@@ -1009,6 +1009,17 @@ static void deallocateIntentOut(Fortran::lower::AbstractConverter &converter,
1009
1009
}
1010
1010
}
1011
1011
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
+
1012
1023
// / Instantiate a local variable. Precondition: Each variable will be visited
1013
1024
// / such that if its properties depend on other variables, the variables upon
1014
1025
// / which its properties depend will already have been visited.
@@ -1077,6 +1088,17 @@ static void instantiateLocal(Fortran::lower::AbstractConverter &converter,
1077
1088
loc, sym);
1078
1089
});
1079
1090
}
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
+ });
1080
1102
}
1081
1103
}
1082
1104
@@ -1914,10 +1936,13 @@ void Fortran::lower::genDeclareSymbol(
1914
1936
sym.GetUltimate ());
1915
1937
auto name = converter.mangleName (sym);
1916
1938
mlir::Value dummyScope;
1917
- if (converter.isRegisteredDummySymbol (sym))
1939
+ fir::ExtendedValue base = exv;
1940
+ if (converter.isRegisteredDummySymbol (sym)) {
1941
+ base = genPackArray (converter, sym, exv);
1918
1942
dummyScope = converter.dummyArgsScopeValue ();
1943
+ }
1919
1944
hlfir::EntityWithAttributes declare = hlfir::genDeclare (
1920
- loc, builder, exv , name, attributes, dummyScope, dataAttr);
1945
+ loc, builder, base , name, attributes, dummyScope, dataAttr);
1921
1946
symMap.addVariableDefinition (sym, declare.getIfVariableInterface (), force);
1922
1947
return ;
1923
1948
}
@@ -2562,3 +2587,75 @@ mlir::Type Fortran::lower::getCrayPointeeBoxType(mlir::Type fortranType) {
2562
2587
}
2563
2588
return fir::BoxType::get (fir::PointerType::get (baseType));
2564
2589
}
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