Skip to content

Commit fd0e20a

Browse files
authored
[flang] Generate fir.pack/unpack_array in Lowering. (llvm#131704)
Basic generation of array repacking operations in Lowering.
1 parent b3a4bf9 commit fd0e20a

File tree

5 files changed

+403
-2
lines changed

5 files changed

+403
-2
lines changed

flang/include/flang/Lower/ConvertVariable.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,22 @@ void genDeclareSymbol(Fortran::lower::AbstractConverter &converter,
182182
/// track the cray pointee as Fortran pointer.
183183
mlir::Type getCrayPointeeBoxType(mlir::Type);
184184

185+
/// If the given array symbol must be repacked into contiguous
186+
/// memory, generate fir.pack_array for the given box array value.
187+
/// The returned extended value is a box with the same properties
188+
/// as the original.
189+
fir::ExtendedValue genPackArray(Fortran::lower::AbstractConverter &converter,
190+
const Fortran::semantics::Symbol &sym,
191+
fir::ExtendedValue exv);
192+
193+
/// Given an operation defining the variable corresponding
194+
/// to the given symbol, generate fir.unpack_array operation
195+
/// that reverts the effect of fir.pack_array.
196+
/// \p def is expected to be hlfir.declare operation.
197+
void genUnpackArray(fir::FirOpBuilder &builder, mlir::Location loc,
198+
fir::FortranVariableOpInterface def,
199+
const Fortran::semantics::Symbol &sym);
200+
185201
} // namespace lower
186202
} // namespace Fortran
187203
#endif // FORTRAN_LOWER_CONVERT_VARIABLE_H

flang/include/flang/Lower/LoweringOptions.def

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,20 @@ ENUM_LOWERINGOPT(ReallocateLHS, unsigned, 1, 1)
4747
/// If true, initialize globals without initialization to zero.
4848
/// On by default.
4949
ENUM_LOWERINGOPT(InitGlobalZero, unsigned, 1, 1)
50+
51+
/// If true, the arrays of unknown size and array temporaries
52+
/// are requested to be allocated in stack memory.
53+
ENUM_LOWERINGOPT(StackArrays, unsigned, 1, 0)
54+
55+
/// If true, the dummy assumed shape arrays are conditionally
56+
/// packed into contiguous memory.
57+
ENUM_LOWERINGOPT(RepackArrays, unsigned, 1, 0)
58+
59+
/// If true, the repacking (RepackArrays option above)
60+
/// will be done for arrays non-contiguous in any dimension,
61+
/// otherwise, it will be done only for arrays non-contiguous
62+
/// in the leading dimension.
63+
ENUM_LOWERINGOPT(RepackArraysWhole, unsigned, 1, 0)
64+
5065
#undef LOWERINGOPT
5166
#undef ENUM_LOWERINGOPT

flang/lib/Lower/ConvertVariable.cpp

Lines changed: 99 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,6 +1009,17 @@ static void deallocateIntentOut(Fortran::lower::AbstractConverter &converter,
10091009
}
10101010
}
10111011

1012+
static bool needsRepack(Fortran::lower::AbstractConverter &converter,
1013+
const Fortran::semantics::Symbol &sym) {
1014+
if (!converter.getLoweringOptions().getRepackArrays() ||
1015+
!converter.isRegisteredDummySymbol(sym) ||
1016+
!Fortran::semantics::IsAssumedShape(sym) ||
1017+
Fortran::evaluate::IsSimplyContiguous(sym, converter.getFoldingContext()))
1018+
return false;
1019+
1020+
return true;
1021+
}
1022+
10121023
/// Instantiate a local variable. Precondition: Each variable will be visited
10131024
/// such that if its properties depend on other variables, the variables upon
10141025
/// which its properties depend will already have been visited.
@@ -1077,6 +1088,17 @@ static void instantiateLocal(Fortran::lower::AbstractConverter &converter,
10771088
loc, sym);
10781089
});
10791090
}
1091+
} else if (var.hasSymbol() && needsRepack(converter, var.getSymbol())) {
1092+
auto *builder = &converter.getFirOpBuilder();
1093+
mlir::Location loc = converter.getCurrentLocation();
1094+
auto *sym = &var.getSymbol();
1095+
std::optional<fir::FortranVariableOpInterface> varDef =
1096+
symMap.lookupVariableDefinition(*sym);
1097+
assert(varDef && "cannot find defining operation for an array that needs "
1098+
"to be repacked");
1099+
converter.getFctCtx().attachCleanup([builder, loc, varDef, sym]() {
1100+
Fortran::lower::genUnpackArray(*builder, loc, *varDef, *sym);
1101+
});
10801102
}
10811103
}
10821104

@@ -1914,10 +1936,13 @@ void Fortran::lower::genDeclareSymbol(
19141936
sym.GetUltimate());
19151937
auto name = converter.mangleName(sym);
19161938
mlir::Value dummyScope;
1917-
if (converter.isRegisteredDummySymbol(sym))
1939+
fir::ExtendedValue base = exv;
1940+
if (converter.isRegisteredDummySymbol(sym)) {
1941+
base = genPackArray(converter, sym, exv);
19181942
dummyScope = converter.dummyArgsScopeValue();
1943+
}
19191944
hlfir::EntityWithAttributes declare = hlfir::genDeclare(
1920-
loc, builder, exv, name, attributes, dummyScope, dataAttr);
1945+
loc, builder, base, name, attributes, dummyScope, dataAttr);
19211946
symMap.addVariableDefinition(sym, declare.getIfVariableInterface(), force);
19221947
return;
19231948
}
@@ -2562,3 +2587,75 @@ mlir::Type Fortran::lower::getCrayPointeeBoxType(mlir::Type fortranType) {
25622587
}
25632588
return fir::BoxType::get(fir::PointerType::get(baseType));
25642589
}
2590+
2591+
fir::ExtendedValue
2592+
Fortran::lower::genPackArray(Fortran::lower::AbstractConverter &converter,
2593+
const Fortran::semantics::Symbol &sym,
2594+
fir::ExtendedValue exv) {
2595+
if (!needsRepack(converter, sym))
2596+
return exv;
2597+
2598+
auto &opts = converter.getLoweringOptions();
2599+
llvm::SmallVector<mlir::Value> lenParams;
2600+
exv.match(
2601+
[&](const fir::CharArrayBoxValue &box) {
2602+
lenParams.emplace_back(box.getLen());
2603+
},
2604+
[&](const fir::BoxValue &box) {
2605+
lenParams.append(box.getExplicitParameters().begin(),
2606+
box.getExplicitParameters().end());
2607+
},
2608+
[](const auto &) {
2609+
llvm_unreachable("unexpected lowering for assumed-shape dummy");
2610+
});
2611+
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
2612+
const mlir::Location loc = genLocation(converter, sym);
2613+
bool stackAlloc = opts.getStackArrays();
2614+
// 1D arrays must always use 'whole' mode.
2615+
bool isInnermostMode = !opts.getRepackArraysWhole() && sym.Rank() > 1;
2616+
// Avoid copy-in for 'intent(out)' variables.
2617+
bool noCopy = Fortran::semantics::IsIntentOut(sym);
2618+
auto boxType = mlir::cast<fir::BaseBoxType>(fir::getBase(exv).getType());
2619+
mlir::Type elementType = boxType.unwrapInnerType();
2620+
llvm::SmallVector<mlir::Value> elidedLenParams =
2621+
fir::factory::elideLengthsAlreadyInType(elementType, lenParams);
2622+
auto packOp = builder.create<fir::PackArrayOp>(
2623+
loc, fir::getBase(exv), stackAlloc, isInnermostMode, noCopy,
2624+
/*max_size=*/mlir::IntegerAttr{},
2625+
/*max_element_size=*/mlir::IntegerAttr{},
2626+
/*min_stride=*/mlir::IntegerAttr{}, fir::PackArrayHeuristics::None,
2627+
elidedLenParams);
2628+
2629+
mlir::Value newBase = packOp.getResult();
2630+
return exv.match(
2631+
[&](const fir::CharArrayBoxValue &box) -> fir::ExtendedValue {
2632+
return box.clone(newBase);
2633+
},
2634+
[&](const fir::BoxValue &box) -> fir::ExtendedValue {
2635+
return box.clone(newBase);
2636+
},
2637+
[](const auto &) -> fir::ExtendedValue {
2638+
llvm_unreachable("unexpected lowering for assumed-shape dummy");
2639+
});
2640+
}
2641+
2642+
void Fortran::lower::genUnpackArray(fir::FirOpBuilder &builder,
2643+
mlir::Location loc,
2644+
fir::FortranVariableOpInterface def,
2645+
const Fortran::semantics::Symbol &sym) {
2646+
// Subtle: rely on the fact that the memref of the defining
2647+
// hlfir.declare is a result of fir.pack_array.
2648+
// Alternatively, we can track the pack operation for a symbol
2649+
// via SymMap.
2650+
auto declareOp = mlir::dyn_cast<hlfir::DeclareOp>(def.getOperation());
2651+
assert(declareOp &&
2652+
"cannot find hlfir.declare for an array that needs to be repacked");
2653+
auto packOp = declareOp.getMemref().getDefiningOp<fir::PackArrayOp>();
2654+
assert(packOp && "cannot find fir.pack_array");
2655+
mlir::Value temp = packOp.getResult();
2656+
mlir::Value original = packOp.getArray();
2657+
bool stackAlloc = packOp.getStack();
2658+
// Avoid copy-out for 'intent(in)' variables.
2659+
bool noCopy = Fortran::semantics::IsIntentIn(sym);
2660+
builder.create<fir::UnpackArrayOp>(loc, temp, original, stackAlloc, noCopy);
2661+
}

0 commit comments

Comments
 (0)