diff --git a/flang/include/flang/Lower/ConvertVariable.h b/flang/include/flang/Lower/ConvertVariable.h index b9d7f891380322..293ffa010d14a3 100644 --- a/flang/include/flang/Lower/ConvertVariable.h +++ b/flang/include/flang/Lower/ConvertVariable.h @@ -182,6 +182,22 @@ void genDeclareSymbol(Fortran::lower::AbstractConverter &converter, /// track the cray pointee as Fortran pointer. mlir::Type getCrayPointeeBoxType(mlir::Type); +/// If the given array symbol must be repacked into contiguous +/// memory, generate fir.pack_array for the given box array value. +/// The returned extended value is a box with the same properties +/// as the original. +fir::ExtendedValue genPackArray(Fortran::lower::AbstractConverter &converter, + const Fortran::semantics::Symbol &sym, + fir::ExtendedValue exv); + +/// Given an operation defining the variable corresponding +/// to the given symbol, generate fir.unpack_array operation +/// that reverts the effect of fir.pack_array. +/// \p def is expected to be hlfir.declare operation. +void genUnpackArray(fir::FirOpBuilder &builder, mlir::Location loc, + fir::FortranVariableOpInterface def, + const Fortran::semantics::Symbol &sym); + } // namespace lower } // namespace Fortran #endif // FORTRAN_LOWER_CONVERT_VARIABLE_H diff --git a/flang/include/flang/Lower/LoweringOptions.def b/flang/include/flang/Lower/LoweringOptions.def index 396c91948be36b..6735bea5514144 100644 --- a/flang/include/flang/Lower/LoweringOptions.def +++ b/flang/include/flang/Lower/LoweringOptions.def @@ -47,5 +47,20 @@ ENUM_LOWERINGOPT(ReallocateLHS, unsigned, 1, 1) /// If true, initialize globals without initialization to zero. /// On by default. ENUM_LOWERINGOPT(InitGlobalZero, unsigned, 1, 1) + +/// If true, the arrays of unknown size and array temporaries +/// are requested to be allocated in stack memory. +ENUM_LOWERINGOPT(StackArrays, unsigned, 1, 0) + +/// If true, the dummy assumed shape arrays are conditionally +/// packed into contiguous memory. +ENUM_LOWERINGOPT(RepackArrays, unsigned, 1, 0) + +/// If true, the repacking (RepackArrays option above) +/// will be done for arrays non-contiguous in any dimension, +/// otherwise, it will be done only for arrays non-contiguous +/// in the leading dimension. +ENUM_LOWERINGOPT(RepackArraysWhole, unsigned, 1, 0) + #undef LOWERINGOPT #undef ENUM_LOWERINGOPT diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp index 05256fec672412..52e3578ae21f08 100644 --- a/flang/lib/Lower/ConvertVariable.cpp +++ b/flang/lib/Lower/ConvertVariable.cpp @@ -1009,6 +1009,17 @@ static void deallocateIntentOut(Fortran::lower::AbstractConverter &converter, } } +static bool needsRepack(Fortran::lower::AbstractConverter &converter, + const Fortran::semantics::Symbol &sym) { + if (!converter.getLoweringOptions().getRepackArrays() || + !converter.isRegisteredDummySymbol(sym) || + !Fortran::semantics::IsAssumedShape(sym) || + Fortran::evaluate::IsSimplyContiguous(sym, converter.getFoldingContext())) + return false; + + return true; +} + /// Instantiate a local variable. Precondition: Each variable will be visited /// such that if its properties depend on other variables, the variables upon /// which its properties depend will already have been visited. @@ -1077,6 +1088,17 @@ static void instantiateLocal(Fortran::lower::AbstractConverter &converter, loc, sym); }); } + } else if (var.hasSymbol() && needsRepack(converter, var.getSymbol())) { + auto *builder = &converter.getFirOpBuilder(); + mlir::Location loc = converter.getCurrentLocation(); + auto *sym = &var.getSymbol(); + std::optional varDef = + symMap.lookupVariableDefinition(*sym); + assert(varDef && "cannot find defining operation for an array that needs " + "to be repacked"); + converter.getFctCtx().attachCleanup([builder, loc, varDef, sym]() { + Fortran::lower::genUnpackArray(*builder, loc, *varDef, *sym); + }); } } @@ -1914,10 +1936,13 @@ void Fortran::lower::genDeclareSymbol( sym.GetUltimate()); auto name = converter.mangleName(sym); mlir::Value dummyScope; - if (converter.isRegisteredDummySymbol(sym)) + fir::ExtendedValue base = exv; + if (converter.isRegisteredDummySymbol(sym)) { + base = genPackArray(converter, sym, exv); dummyScope = converter.dummyArgsScopeValue(); + } hlfir::EntityWithAttributes declare = hlfir::genDeclare( - loc, builder, exv, name, attributes, dummyScope, dataAttr); + loc, builder, base, name, attributes, dummyScope, dataAttr); symMap.addVariableDefinition(sym, declare.getIfVariableInterface(), force); return; } @@ -2562,3 +2587,75 @@ mlir::Type Fortran::lower::getCrayPointeeBoxType(mlir::Type fortranType) { } return fir::BoxType::get(fir::PointerType::get(baseType)); } + +fir::ExtendedValue +Fortran::lower::genPackArray(Fortran::lower::AbstractConverter &converter, + const Fortran::semantics::Symbol &sym, + fir::ExtendedValue exv) { + if (!needsRepack(converter, sym)) + return exv; + + auto &opts = converter.getLoweringOptions(); + llvm::SmallVector lenParams; + exv.match( + [&](const fir::CharArrayBoxValue &box) { + lenParams.emplace_back(box.getLen()); + }, + [&](const fir::BoxValue &box) { + lenParams.append(box.getExplicitParameters().begin(), + box.getExplicitParameters().end()); + }, + [](const auto &) { + llvm_unreachable("unexpected lowering for assumed-shape dummy"); + }); + fir::FirOpBuilder &builder = converter.getFirOpBuilder(); + const mlir::Location loc = genLocation(converter, sym); + bool stackAlloc = opts.getStackArrays(); + // 1D arrays must always use 'whole' mode. + bool isInnermostMode = !opts.getRepackArraysWhole() && sym.Rank() > 1; + // Avoid copy-in for 'intent(out)' variables. + bool noCopy = Fortran::semantics::IsIntentOut(sym); + auto boxType = mlir::cast(fir::getBase(exv).getType()); + mlir::Type elementType = boxType.unwrapInnerType(); + llvm::SmallVector elidedLenParams = + fir::factory::elideLengthsAlreadyInType(elementType, lenParams); + auto packOp = builder.create( + loc, fir::getBase(exv), stackAlloc, isInnermostMode, noCopy, + /*max_size=*/mlir::IntegerAttr{}, + /*max_element_size=*/mlir::IntegerAttr{}, + /*min_stride=*/mlir::IntegerAttr{}, fir::PackArrayHeuristics::None, + elidedLenParams); + + mlir::Value newBase = packOp.getResult(); + return exv.match( + [&](const fir::CharArrayBoxValue &box) -> fir::ExtendedValue { + return box.clone(newBase); + }, + [&](const fir::BoxValue &box) -> fir::ExtendedValue { + return box.clone(newBase); + }, + [](const auto &) -> fir::ExtendedValue { + llvm_unreachable("unexpected lowering for assumed-shape dummy"); + }); +} + +void Fortran::lower::genUnpackArray(fir::FirOpBuilder &builder, + mlir::Location loc, + fir::FortranVariableOpInterface def, + const Fortran::semantics::Symbol &sym) { + // Subtle: rely on the fact that the memref of the defining + // hlfir.declare is a result of fir.pack_array. + // Alternatively, we can track the pack operation for a symbol + // via SymMap. + auto declareOp = mlir::dyn_cast(def.getOperation()); + assert(declareOp && + "cannot find hlfir.declare for an array that needs to be repacked"); + auto packOp = declareOp.getMemref().getDefiningOp(); + assert(packOp && "cannot find fir.pack_array"); + mlir::Value temp = packOp.getResult(); + mlir::Value original = packOp.getArray(); + bool stackAlloc = packOp.getStack(); + // Avoid copy-out for 'intent(in)' variables. + bool noCopy = Fortran::semantics::IsIntentIn(sym); + builder.create(loc, temp, original, stackAlloc, noCopy); +} diff --git a/flang/test/Lower/repack-arrays.f90 b/flang/test/Lower/repack-arrays.f90 new file mode 100644 index 00000000000000..19ea93a3521a35 --- /dev/null +++ b/flang/test/Lower/repack-arrays.f90 @@ -0,0 +1,247 @@ +! RUN: bbc -emit-hlfir -frepack-arrays -fstack-arrays -frepack-arrays-continuity-whole %s -o - -I nowhere | FileCheck --check-prefixes=ALL,STACK,WHOLE %s +! RUN: bbc -emit-hlfir -frepack-arrays -fstack-arrays=false -frepack-arrays-continuity-whole %s -o - -I nowhere | FileCheck --check-prefixes=ALL,HEAP,WHOLE %s +! RUN: bbc -emit-hlfir -frepack-arrays -fstack-arrays -frepack-arrays-continuity-whole=false %s -o - -I nowhere | FileCheck --check-prefixes=ALL,STACK,INNER %s +! RUN: bbc -emit-hlfir -frepack-arrays -fstack-arrays=false -frepack-arrays-continuity-whole=false %s -o - -I nowhere | FileCheck --check-prefixes=ALL,HEAP,INNER %s + +! ALL-LABEL: func.func @_QPtest1( +! ALL-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box> {fir.bindc_name = "x"}) { +subroutine test1(x) + real :: x(:) +! ALL: %[[VAL_2:.*]] = fir.pack_array %[[VAL_0]] +! STACK-SAME: stack +! HEAP-SAME: heap +! WHOLE-SAME: whole +! ALL-NOT: no_copy +! ALL-SAME : (!fir.box>) -> !fir.box> +! ALL: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] dummy_scope %{{.*}} {uniq_name = "_QFtest1Ex"} : (!fir.box>, !fir.dscope) -> (!fir.box>, !fir.box>) +! ALL: fir.unpack_array %[[VAL_2]] to %[[VAL_0]] +! STACK-SAME: stack +! HEAP-SAME: heap +! ALL-NOT: no_copy +! ALL-SAME: : !fir.box> +end subroutine test1 + +! ALL-LABEL: func.func @_QPtest2( +! ALL-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref {fir.bindc_name = "n"}, +! ALL-SAME: %[[VAL_1:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box>> {fir.bindc_name = "x"}) { +subroutine test2(n, x) + integer :: n + character(n) :: x(:,:) +! ALL: %[[VAL_8:.*]] = fir.pack_array %[[VAL_1]] +! STACK-SAME: stack +! HEAP-SAME: heap +! WHOLE-SAME: whole +! INNER-SAME: innermost +! ALL-NOT: no_copy +! ALL-SAME: typeparams %[[VAL_7:.*]] : (!fir.box>>, i32) -> !fir.box>> +! ALL: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]] typeparams %[[VAL_7]] dummy_scope %{{.*}} {uniq_name = "_QFtest2Ex"} : (!fir.box>>, i32, !fir.dscope) -> (!fir.box>>, !fir.box>>) +! ALL: fir.unpack_array %[[VAL_8]] to %[[VAL_1]] +! STACK-SAME: stack +! HEAP-SAME: heap +! ALL-NOT: no_copy +! ALL-SAME: : !fir.box>> +end subroutine test2 + +! ALL-LABEL: func.func @_QPtest3( +! ALL-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box>> {fir.bindc_name = "x"}) { +subroutine test3(x) + type t + end type t + type(t) :: x(:,:) +! ALL: %[[VAL_2:.*]] = fir.pack_array %[[VAL_0]] +! STACK-SAME: stack +! HEAP-SAME: heap +! WHOLE-SAME: whole +! INNER-SAME: innermost +! ALL-NOT: no_copy +! ALL-SAME: : (!fir.box>>) -> !fir.box>> +! ALL: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] dummy_scope %{{.*}} {uniq_name = "_QFtest3Ex"} : (!fir.box>>, !fir.dscope) -> (!fir.box>>, !fir.box>>) +! ALL: fir.unpack_array %[[VAL_2]] to %[[VAL_0]] +! STACK-SAME: stack +! HEAP-SAME: heap +! ALL-NOT: no_copy +! ALL-SAME: : !fir.box>> +end subroutine test3 + +! ALL-LABEL: func.func @_QPtest4( +! ALL-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box> {fir.bindc_name = "x"}) { +subroutine test4(x) + real, intent(inout) :: x(:) +! ALL: %[[VAL_2:.*]] = fir.pack_array %[[VAL_0]] +! STACK-SAME: stack +! HEAP-SAME: heap +! WHOLE-SAME: whole +! ALL-NOT: no_copy +! ALL-SAME : (!fir.box>) -> !fir.box> +! ALL: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] dummy_scope %{{.*}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest4Ex"} : (!fir.box>, !fir.dscope) -> (!fir.box>, !fir.box>) +! ALL: fir.unpack_array %[[VAL_2]] to %[[VAL_0]] +! STACK-SAME: stack +! HEAP-SAME: heap +! ALL-NOT: no_copy +! ALL-SAME : !fir.box> +end subroutine test4 + +! ALL-LABEL: func.func @_QPtest5( +! ALL-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box> {fir.bindc_name = "x"}) { +subroutine test5(x) + real, intent(in) :: x(:) +! ALL: %[[VAL_2:.*]] = fir.pack_array %[[VAL_0]] +! STACK-SAME: stack +! HEAP-SAME: heap +! WHOLE-SAME: whole +! ALL-NOT: no_copy +! ALL-SAME: (!fir.box>) -> !fir.box> +! ALL: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] dummy_scope %{{.*}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest5Ex"} : (!fir.box>, !fir.dscope) -> (!fir.box>, !fir.box>) +! ALL: fir.unpack_array %[[VAL_2]] to %[[VAL_0]] +! STACK-SAME: stack +! HEAP-SAME: heap +! ALL-SAME no_copy : !fir.box> +end subroutine test5 + +! ALL-LABEL: func.func @_QPtest6( +! ALL-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box> {fir.bindc_name = "x"}) { +subroutine test6(x) + real, intent(out) :: x(:) +! ALL: %[[VAL_2:.*]] = fir.pack_array %[[VAL_0]] +! STACK-SAME: stack +! HEAP-SAME: heap +! WHOLE-SAME: whole +! ALL-SAME no_copy : (!fir.box>) -> !fir.box> +! ALL: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] dummy_scope %{{.*}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest6Ex"} : (!fir.box>, !fir.dscope) -> (!fir.box>, !fir.box>) +! ALL: fir.unpack_array %[[VAL_2]] to %[[VAL_0]] +! STACK-SAME: stack +! HEAP-SAME: heap +! ALL-NOT: no_copy +! ALL-SAME : !fir.box> +end subroutine test6 + +! ALL-LABEL: func.func @_QPtest7( +! ALL-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.class>> {fir.bindc_name = "x"}) { +subroutine test7(x) + type t + end type t + class(t) :: x(:) +! ALL: %[[VAL_2:.*]] = fir.pack_array %[[VAL_0]] +! STACK-SAME: stack +! HEAP-SAME: heap +! WHOLE-SAME: whole +! ALL-NOT: no_copy +! ALL-SAME : (!fir.class>>) -> !fir.class>> +! ALL: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] dummy_scope %{{.*}} {uniq_name = "_QFtest7Ex"} : (!fir.class>>, !fir.dscope) -> (!fir.class>>, !fir.class>>) +! ALL: fir.unpack_array %[[VAL_2]] to %[[VAL_0]] +! STACK-SAME: stack +! HEAP-SAME: heap +! ALL-NOT: no_copy +! ALL-SAME : !fir.class>> +end subroutine test7 + +! ALL-LABEL: func.func @_QPtest8( +! ALL-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box> {fir.bindc_name = "x"}) { +subroutine test8(x) + real :: x(:) +! ALL: %[[VAL_2:.*]] = fir.pack_array %[[VAL_0]] +! STACK-SAME: stack +! HEAP-SAME: heap +! WHOLE-SAME: whole +! ALL-NOT: no_copy +! ALL-SAME : (!fir.box>) -> !fir.box> +! ALL: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] dummy_scope %{{.*}} {uniq_name = "_QFtest8Ex"} : (!fir.box>, !fir.dscope) -> (!fir.box>, !fir.box>) + call inner(x(1)) +! ALL: fir.call @_QFtest8Pinner +! ALL: fir.unpack_array %[[VAL_2]] to %[[VAL_0]] +! STACK-SAME: stack +! HEAP-SAME: heap +! ALL-NOT: no_copy +! ALL-SAME : !fir.box> +contains +! ALL-LABEL: func.func private @_QFtest8Pinner( + subroutine inner(y) +! ALL-NOT: fir.pack_array +! ALL-NOT: fir.unpack_array + real :: y + y = 1.0 + end subroutine inner +end subroutine test8 + +! ALL-LABEL: func.func @_QPtest9( +! ALL-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box> {fir.bindc_name = "x"}) -> f32 { +real function test9(x) + real :: x(:) +! ALL: %[[VAL_6:.*]] = fir.pack_array %[[VAL_0]] +! STACK-SAME: stack +! HEAP-SAME: heap +! WHOLE-SAME: whole +! ALL-NOT: no_copy +! ALL-SAME : (!fir.box>) -> !fir.box> +! ALL: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]] dummy_scope %{{.*}} {uniq_name = "_QFtest9Ex"} : (!fir.box>, !fir.dscope) -> (!fir.box>, !fir.box>) + real :: y(10) + test9 = x(1) +! ALL: fir.unpack_array %[[VAL_6]] to %[[VAL_0]] +! STACK-SAME: stack +! HEAP-SAME: heap +! ALL-NOT: no_copy +! ALL-SAME : !fir.box> +! ALL-NEXT: return + return + +! ALL-LABEL: func.func @_QPtest9_alt( + entry test9_alt(y) +! ALL-NOT: fir.pack_array +! ALL-NOT: fir.unpack_array + rest9_ = y(1) +end function test9 + +! ALL-LABEL: func.func @_QPtest10( +! ALL-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box> {fir.bindc_name = "x", fir.optional}) { +subroutine test10(x) + real, optional :: x(:,:) +! ALL: %[[VAL_2:.*]] = fir.pack_array %[[VAL_0]] +! STACK-SAME: stack +! HEAP-SAME: heap +! WHOLE-SAME: whole +! INNER-SAME: innermost +! ALL-NOT: no_copy +! ALL-SAME: : (!fir.box>) -> !fir.box> +! ALL: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] dummy_scope %{{.*}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest10Ex"} : (!fir.box>, !fir.dscope) -> (!fir.box>, !fir.box>) +! ALL: fir.unpack_array %[[VAL_2]] to %[[VAL_0]] +! STACK-SAME: stack +! HEAP-SAME: heap +! ALL-NOT: no_copy +! ALL-SAME: : !fir.box> +end subroutine test10 + +! ALL-LABEL: func.func @_QPtest11( +! ALL-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box>> {fir.bindc_name = "x"}) { +subroutine test11(x) + character(10) :: x(:) +! ALL: %[[VAL_3:.*]] = fir.pack_array %[[VAL_0]] +! STACK-SAME: stack +! HEAP-SAME: heap +! WHOLE-SAME: whole +! INNER-SAME: whole +! ALL-NOT: no_copy +! ALL-SAME: : (!fir.box>>) -> !fir.box>> +! ALL: fir.unpack_array %[[VAL_3]] to %[[VAL_0]] +! STACK-SAME: stack +! HEAP-SAME: heap +! ALL-NOT: no_copy +! ALL-SAME: : !fir.box>> +end subroutine test11 + +! ALL-LABEL: func.func @_QPtest12( +! ALL-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box>> {fir.bindc_name = "x"}) { +subroutine test12(x) + character(*) :: x(:) +! ALL: %[[VAL_2:.*]] = fir.pack_array %[[VAL_0]] +! STACK-SAME: stack +! HEAP-SAME: heap +! WHOLE-SAME: whole +! INNER-SAME: whole +! ALL-NOT: no_copy +! ALL-SAME: : (!fir.box>>) -> !fir.box>> +! ALL: fir.unpack_array %[[VAL_2]] to %[[VAL_0]] +! STACK-SAME: stack +! HEAP-SAME: heap +! ALL-NOT: no_copy +! ALL-SAME: : !fir.box>> +end subroutine test12 diff --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp index efaeb0c0a3891f..2cc75b7aa4e877 100644 --- a/flang/tools/bbc/bbc.cpp +++ b/flang/tools/bbc/bbc.cpp @@ -245,6 +245,29 @@ static llvm::cl::opt "the LHS of the intrinsic assignment"), llvm::cl::init(true)); +// TODO: -fstack-arrays is currently only used for fir.pack_array, +// but it should probably be used for deciding how arrays/temporaries +// are allocated during lowering. +static llvm::cl::opt + stackArrays("fstack-arrays", + llvm::cl::desc("Allocate all arrays of unknown size and " + "temporary arrays in stack memory"), + llvm::cl::init(false)); + +static llvm::cl::opt + repackArrays("frepack-arrays", + llvm::cl::desc("Pack non-contiguous assummed shape arrays " + "into contiguous memory"), + llvm::cl::init(false)); + +static llvm::cl::opt + repackArraysWhole("frepack-arrays-continuity-whole", + llvm::cl::desc("Repack arrays that are non-contiguous " + "in any dimension. If set to false, " + "only the arrays non-contiguous in the " + "leading dimension will be repacked"), + llvm::cl::init(true)); + #define FLANG_EXCLUDE_CODEGEN #include "flang/Optimizer/Passes/CommandLineOpts.h" #include "flang/Optimizer/Passes/Pipelines.h" @@ -388,6 +411,9 @@ static llvm::LogicalResult convertFortranSourceToMLIR( loweringOptions.setIntegerWrapAround(integerWrapAround); loweringOptions.setInitGlobalZero(initGlobalZero); loweringOptions.setReallocateLHS(reallocateLHS); + loweringOptions.setStackArrays(stackArrays); + loweringOptions.setRepackArrays(repackArrays); + loweringOptions.setRepackArraysWhole(repackArraysWhole); std::vector envDefaults = {}; Fortran::frontend::TargetOptions targetOpts; Fortran::frontend::CodeGenOptions cgOpts;