Skip to content

Commit b417161

Browse files
authored
[Flang] Wrap array constructors within a hlfir.exactly_once op (#159442)
When inside a WHERE construct, the array constructor should be generated within an hlfir.exactly_once region. Fixes #130532
1 parent adaf5ba commit b417161

File tree

2 files changed

+67
-0
lines changed

2 files changed

+67
-0
lines changed

flang/lib/Lower/ConvertArrayConstructor.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,18 @@
2020
#include "flang/Optimizer/Builder/Todo.h"
2121
#include "flang/Optimizer/HLFIR/HLFIROps.h"
2222

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+
2335
// Array constructors are lowered with three different strategies.
2436
// All strategies are not possible with all array constructors.
2537
//
@@ -780,6 +792,41 @@ hlfir::EntityWithAttributes Fortran::lower::ArrayConstructorBuilder<T>::gen(
780792
const Fortran::evaluate::ArrayConstructor<T> &arrayCtorExpr,
781793
Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx) {
782794
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+
783830
// Select the lowering strategy given the array constructor.
784831
auto arrayBuilder = selectArrayCtorLoweringStrategy(
785832
loc, converter, arrayCtorExpr, symMap, stmtCtx);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
! RUN: flang -fc1 -emit-hlfir %s -o - | FileCheck %s
2+
3+
program main
4+
call test06()
5+
print *,'pass'
6+
end program main
7+
8+
subroutine test06()
9+
type ty1
10+
integer ,allocatable :: a(:,:,:)
11+
end type ty1
12+
type(ty1) :: str(1)
13+
integer ,allocatable :: b(:,:,:)
14+
allocate(str(1)%a(1,1,1),b(1,1,1))
15+
b=1
16+
write(6,*) "b = ", b
17+
write(6,*) "reshape((/(b,jj=1,1)/),(/1,1,1/)) = ", reshape((/(b,jj=1,1)/),(/1,1,1/))
18+
where ((/.true./)) str=(/(ty1(reshape((/(b,jj=1,1)/),(/1,1,1/))),ii=1,1)/)
19+
! CHECK: hlfir.exactly_once : !hlfir.expr<1x!fir.type<_QFtest06Tty1{a:!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>}>>
20+
end subroutine test06

0 commit comments

Comments
 (0)