|
20 | 20 | #include "flang/Optimizer/Builder/Todo.h"
|
21 | 21 | #include "flang/Optimizer/HLFIR/HLFIROps.h"
|
22 | 22 |
|
| 23 | +namespace { |
| 24 | +/// Check if we are inside a WHERE construct's masked expression region. |
| 25 | +/// Array constructors inside WHERE statements must be evaluated exactly once |
| 26 | +/// without mask control, similar to non-elemental function calls. |
| 27 | + |
| 28 | +static bool isInWhereMaskedExpression(fir::FirOpBuilder &builder) { |
| 29 | + mlir::Operation *op = builder.getRegion().getParentOp(); |
| 30 | + return op && op->getParentOfType<hlfir::WhereOp>(); |
| 31 | +} |
| 32 | + |
| 33 | +} // namespace |
| 34 | + |
23 | 35 | // Array constructors are lowered with three different strategies.
|
24 | 36 | // All strategies are not possible with all array constructors.
|
25 | 37 | //
|
@@ -780,6 +792,41 @@ hlfir::EntityWithAttributes Fortran::lower::ArrayConstructorBuilder<T>::gen(
|
780 | 792 | const Fortran::evaluate::ArrayConstructor<T> &arrayCtorExpr,
|
781 | 793 | Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx) {
|
782 | 794 | fir::FirOpBuilder &builder = converter.getFirOpBuilder();
|
| 795 | + |
| 796 | + // Array constructors inside a where-assignment-stmt must be executed |
| 797 | + // exactly once without mask control, per Fortran 2023 section 10.2.3.2. |
| 798 | + // Lower them in a special region so that this can be enforced when |
| 799 | + // scheduling forall/where expression evaluations. |
| 800 | + if (isInWhereMaskedExpression(builder) && |
| 801 | + !builder.getRegion().getParentOfType<hlfir::ExactlyOnceOp>()) { |
| 802 | + Fortran::lower::StatementContext localStmtCtx; |
| 803 | + mlir::Type bogusType = builder.getIndexType(); |
| 804 | + auto exactlyOnce = hlfir::ExactlyOnceOp::create(builder, loc, bogusType); |
| 805 | + mlir::Block *block = builder.createBlock(&exactlyOnce.getBody()); |
| 806 | + builder.setInsertionPointToStart(block); |
| 807 | + |
| 808 | + // Recursively generate the array constructor inside the exactly_once region |
| 809 | + hlfir::EntityWithAttributes res = ArrayConstructorBuilder<T>::gen( |
| 810 | + loc, converter, arrayCtorExpr, symMap, localStmtCtx); |
| 811 | + |
| 812 | + auto yield = hlfir::YieldOp::create(builder, loc, res); |
| 813 | + Fortran::lower::genCleanUpInRegionIfAny(loc, builder, yield.getCleanup(), |
| 814 | + localStmtCtx); |
| 815 | + builder.setInsertionPointAfter(exactlyOnce); |
| 816 | + exactlyOnce->getResult(0).setType(res.getType()); |
| 817 | + |
| 818 | + if (hlfir::isFortranValue(exactlyOnce.getResult())) |
| 819 | + return hlfir::EntityWithAttributes{exactlyOnce.getResult()}; |
| 820 | + |
| 821 | + // Create hlfir.declare for the result to satisfy |
| 822 | + // hlfir::EntityWithAttributes requirements. |
| 823 | + auto [exv, cleanup] = hlfir::translateToExtendedValue( |
| 824 | + loc, builder, hlfir::Entity{exactlyOnce}); |
| 825 | + assert(!cleanup && "result is a variable"); |
| 826 | + return hlfir::genDeclare(loc, builder, exv, ".arrayctor.result", |
| 827 | + fir::FortranVariableFlagsAttr{}); |
| 828 | + } |
| 829 | + |
783 | 830 | // Select the lowering strategy given the array constructor.
|
784 | 831 | auto arrayBuilder = selectArrayCtorLoweringStrategy(
|
785 | 832 | loc, converter, arrayCtorExpr, symMap, stmtCtx);
|
|
0 commit comments