5656// strategy.pushValue(ac-value);
5757// } else if (ac-value is implied-do) {
5858// strategy.startImpliedDo(lower, upper, stride);
59+ // strategy.startImpliedDoScope();
5960// // lower nested values
61+ // ...
62+ // strategy.endImpliedDoScope();
6063// }
6164// result = strategy.finishArrayCtorLowering();
6265// ```
6366
6467// ===----------------------------------------------------------------------===//
6568// Definition of the lowering strategies. Each lowering strategy is defined
66- // as a class that implements "pushValue", "startImpliedDo", and
67- // "finishArrayCtorLowering".
69+ // as a class that implements "pushValue", "startImpliedDo" and
70+ // "finishArrayCtorLowering". A strategy may optionally override
71+ // "startImpliedDoScope" and "endImpliedDoScope" virtual methods
72+ // of its base class StrategyBase.
6873// ===----------------------------------------------------------------------===//
6974
7075namespace {
76+ // / Class provides common implementation of scope push/pop methods
77+ // / that update StatementContext scopes and SymMap bindings.
78+ // / They might be overridden by the lowering strategies, e.g.
79+ // / see AsElementalStrategy.
80+ class StrategyBase {
81+ public:
82+ StrategyBase (Fortran::lower::StatementContext &stmtCtx,
83+ Fortran::lower::SymMap &symMap)
84+ : stmtCtx{stmtCtx}, symMap{symMap} {};
85+ virtual ~StrategyBase () = default ;
86+
87+ virtual void startImpliedDoScope (llvm::StringRef doName,
88+ mlir::Value indexValue) {
89+ symMap.pushImpliedDoBinding (doName, indexValue);
90+ stmtCtx.pushScope ();
91+ }
92+
93+ virtual void endImpliedDoScope () {
94+ stmtCtx.finalizeAndPop ();
95+ symMap.popImpliedDoBinding ();
96+ }
97+
98+ protected:
99+ Fortran::lower::StatementContext &stmtCtx;
100+ Fortran::lower::SymMap &symMap;
101+ };
102+
71103// / Class that implements the "inlined temp strategy" to lower array
72104// / constructors. It must be further provided a CounterType class to specify how
73105// / the current ac-value insertion position is tracked.
74106template <typename CounterType>
75- class InlinedTempStrategyImpl {
107+ class InlinedTempStrategyImpl : public StrategyBase {
76108 // / Name that will be given to the temporary allocation and hlfir.declare in
77109 // / the IR.
78110 static constexpr char tempName[] = " .tmp.arrayctor" ;
@@ -81,9 +113,12 @@ class InlinedTempStrategyImpl {
81113 // / Start lowering an array constructor according to the inline strategy.
82114 // / The temporary is created right away.
83115 InlinedTempStrategyImpl (mlir::Location loc, fir::FirOpBuilder &builder,
116+ Fortran::lower::StatementContext &stmtCtx,
117+ Fortran::lower::SymMap &symMap,
84118 fir::SequenceType declaredType, mlir::Value extent,
85119 llvm::ArrayRef<mlir::Value> lengths)
86- : one{builder.createIntegerConstant (loc, builder.getIndexType (), 1 )},
120+ : StrategyBase{stmtCtx, symMap},
121+ one{builder.createIntegerConstant (loc, builder.getIndexType (), 1 )},
87122 counter{loc, builder, one} {
88123 // Allocate the temporary storage.
89124 llvm::SmallVector<mlir::Value, 1 > extents{extent};
@@ -224,15 +259,17 @@ using InlinedTempStrategy = InlinedTempStrategyImpl<InMemoryCounter>;
224259// / implied-do nest and wrapped in an hlfir.reshape to a rank 1 array. But this
225260// / op does not exist yet, so this is left for the future if it appears
226261// / profitable.
227- class AsElementalStrategy {
262+ class AsElementalStrategy : public StrategyBase {
228263public:
229264 // / The constructor only gathers the operands to create the hlfir.elemental.
230265 AsElementalStrategy (mlir::Location loc, fir::FirOpBuilder &builder,
266+ Fortran::lower::StatementContext &stmtCtx,
267+ Fortran::lower::SymMap &symMap,
231268 fir::SequenceType declaredType, mlir::Value extent,
232269 llvm::ArrayRef<mlir::Value> lengths)
233- : shape{builder.genShape (loc, {extent})},
234- lengthParams{lengths.begin (), lengths.end ()}, exprType{ getExprType (
235- declaredType)} {}
270+ : StrategyBase{stmtCtx, symMap}, shape{builder.genShape (loc, {extent})},
271+ lengthParams{lengths.begin (), lengths.end ()},
272+ exprType{ getExprType ( declaredType)} {}
236273
237274 static hlfir::ExprType getExprType (fir::SequenceType declaredType) {
238275 // Note: 7.8 point 4: the dynamic type of an array constructor is its static
@@ -271,9 +308,19 @@ class AsElementalStrategy {
271308 if (fir::isa_trivial (elementResult.getType ()))
272309 elementResult =
273310 builder.createConvert (loc, exprType.getElementType (), elementResult);
311+
312+ // The clean-ups associated with the implied-do body operations
313+ // must be initiated before the YieldElementOp, so we have to pop the scope
314+ // right now.
315+ stmtCtx.finalizeAndPop ();
316+
274317 builder.create <hlfir::YieldElementOp>(loc, elementResult);
275318 }
276319
320+ // Override the default, because the context scope must be popped in
321+ // pushValue().
322+ virtual void endImpliedDoScope () override { symMap.popImpliedDoBinding (); }
323+
277324 // / Return the created hlfir.elemental.
278325 hlfir::Entity finishArrayCtorLowering (mlir::Location loc,
279326 fir::FirOpBuilder &builder) {
@@ -289,7 +336,7 @@ class AsElementalStrategy {
289336
290337// / Class that implements the "runtime temp strategy" to lower array
291338// / constructors.
292- class RuntimeTempStrategy {
339+ class RuntimeTempStrategy : public StrategyBase {
293340 // / Name that will be given to the temporary allocation and hlfir.declare in
294341 // / the IR.
295342 static constexpr char tempName[] = " .tmp.arrayctor" ;
@@ -305,11 +352,14 @@ class RuntimeTempStrategy {
305352 // / constructor, if they could be precomputed. \p missingLengthParameters is
306353 // / set to true if the length parameters could not be precomputed.
307354 RuntimeTempStrategy (mlir::Location loc, fir::FirOpBuilder &builder,
355+ Fortran::lower::StatementContext &stmtCtx,
356+ Fortran::lower::SymMap &symMap,
308357 fir::SequenceType declaredType,
309358 std::optional<mlir::Value> extent,
310359 llvm::ArrayRef<mlir::Value> lengths,
311360 bool missingLengthParameters)
312- : arrayConstructorElementType{declaredType.getEleTy ()} {
361+ : StrategyBase{stmtCtx, symMap},
362+ arrayConstructorElementType{declaredType.getEleTy ()} {
313363 mlir::Type heapType = fir::HeapType::get (declaredType);
314364 mlir::Type boxType = fir::BoxType::get (heapType);
315365 allocatableTemp = builder.createTemporary (loc, boxType, tempName);
@@ -463,6 +513,19 @@ class ArrayCtorLoweringStrategy {
463513 implVariant);
464514 }
465515
516+ void startImpliedDoScope (llvm::StringRef doName, mlir::Value indexValue) {
517+ std::visit (
518+ [&](auto &impl) {
519+ return impl.startImpliedDoScope (doName, indexValue);
520+ },
521+ implVariant);
522+ }
523+
524+ void endImpliedDoScope () {
525+ std::visit ([&](auto &impl) { return impl.endImpliedDoScope (); },
526+ implVariant);
527+ }
528+
466529private:
467530 std::variant<InlinedTempStrategy, LooplessInlinedTempStrategy,
468531 AsElementalStrategy, RuntimeTempStrategy>
@@ -694,20 +757,22 @@ static ArrayCtorLoweringStrategy selectArrayCtorLoweringStrategy(
694757 if (!extent || needToEvaluateOneExprToGetLengthParameters ||
695758 analysis.anyArrayExpr || declaredType.getEleTy ().isa <fir::RecordType>())
696759 return RuntimeTempStrategy (
697- loc, builder, declaredType,
760+ loc, builder, stmtCtx, symMap, declaredType,
698761 extent ? std::optional<mlir::Value>(extent) : std::nullopt , lengths,
699762 needToEvaluateOneExprToGetLengthParameters);
700763 // Note: array constructors containing impure ac-value expr are currently not
701764 // rewritten to hlfir.elemental because impure expressions should be evaluated
702765 // in order, and hlfir.elemental currently misses a way to indicate that.
703766 if (analysis.isSingleImpliedDoWithOneScalarPureExpr ())
704- return AsElementalStrategy (loc, builder, declaredType, extent, lengths);
767+ return AsElementalStrategy (loc, builder, stmtCtx, symMap, declaredType,
768+ extent, lengths);
705769
706770 if (analysis.anyImpliedDo )
707- return InlinedTempStrategy (loc, builder, declaredType, extent, lengths);
771+ return InlinedTempStrategy (loc, builder, stmtCtx, symMap, declaredType,
772+ extent, lengths);
708773
709- return LooplessInlinedTempStrategy (loc, builder, declaredType, extent ,
710- lengths);
774+ return LooplessInlinedTempStrategy (loc, builder, stmtCtx, symMap ,
775+ declaredType, extent, lengths);
711776}
712777
713778// / Lower an ac-value expression \p expr and forward it to the selected
@@ -747,9 +812,8 @@ static void genAcValue(mlir::Location loc,
747812 mlir::OpBuilder::InsertPoint insertPt = builder.saveInsertionPoint ();
748813 mlir::Value impliedDoIndexValue =
749814 arrayBuilder.startImpliedDo (loc, builder, lower, upper, stride);
750- symMap.pushImpliedDoBinding (toStringRef (impledDo.name ()),
751- impliedDoIndexValue);
752- stmtCtx.pushScope ();
815+ arrayBuilder.startImpliedDoScope (toStringRef (impledDo.name ()),
816+ impliedDoIndexValue);
753817
754818 for (const auto &acValue : impledDo.values ())
755819 std::visit (
@@ -758,8 +822,7 @@ static void genAcValue(mlir::Location loc,
758822 },
759823 acValue.u );
760824
761- stmtCtx.finalizeAndPop ();
762- symMap.popImpliedDoBinding ();
825+ arrayBuilder.endImpliedDoScope ();
763826 builder.restoreInsertionPoint (insertPt);
764827}
765828
0 commit comments