Skip to content

Commit 8cc34fa

Browse files
authored
[flang][OpenMP] Support reduction of allocatable variables (llvm#88392)
Both arrays and trivial scalars are supported. Both cases must use by-ref reductions because both are boxed. My understanding of the standards are that OpenMP says that this should follow the rules of the intrinsic reduction operators in fortran, and fortran says that unallocated allocatable variables can only be referenced to allocate them or test if they are already allocated. Therefore we do not need a null pointer check in the combiner region.
1 parent a68ea36 commit 8cc34fa

11 files changed

+327
-44
lines changed

flang/lib/Lower/OpenMP/ReductionProcessor.cpp

Lines changed: 113 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -301,17 +301,35 @@ static void genBoxCombiner(fir::FirOpBuilder &builder, mlir::Location loc,
301301
ReductionProcessor::ReductionIdentifier redId,
302302
fir::BaseBoxType boxTy, mlir::Value lhs,
303303
mlir::Value rhs) {
304-
fir::SequenceType seqTy =
305-
mlir::dyn_cast_or_null<fir::SequenceType>(boxTy.getEleTy());
306-
// TODO: support allocatable arrays: !fir.box<!fir.heap<!fir.array<...>>>
307-
if (!seqTy || seqTy.hasUnknownShape())
304+
fir::SequenceType seqTy = mlir::dyn_cast_or_null<fir::SequenceType>(
305+
fir::unwrapRefType(boxTy.getEleTy()));
306+
fir::HeapType heapTy =
307+
mlir::dyn_cast_or_null<fir::HeapType>(boxTy.getEleTy());
308+
if ((!seqTy || seqTy.hasUnknownShape()) && !heapTy)
308309
TODO(loc, "Unsupported boxed type in OpenMP reduction");
309310

310311
// load fir.ref<fir.box<...>>
311312
mlir::Value lhsAddr = lhs;
312313
lhs = builder.create<fir::LoadOp>(loc, lhs);
313314
rhs = builder.create<fir::LoadOp>(loc, rhs);
314315

316+
if (heapTy && !seqTy) {
317+
// get box contents (heap pointers)
318+
lhs = builder.create<fir::BoxAddrOp>(loc, lhs);
319+
rhs = builder.create<fir::BoxAddrOp>(loc, rhs);
320+
mlir::Value lhsValAddr = lhs;
321+
322+
// load heap pointers
323+
lhs = builder.create<fir::LoadOp>(loc, lhs);
324+
rhs = builder.create<fir::LoadOp>(loc, rhs);
325+
326+
mlir::Value result = ReductionProcessor::createScalarCombiner(
327+
builder, loc, redId, heapTy.getEleTy(), lhs, rhs);
328+
builder.create<fir::StoreOp>(loc, result, lhsValAddr);
329+
builder.create<mlir::omp::YieldOp>(loc, lhsAddr);
330+
return;
331+
}
332+
315333
const unsigned rank = seqTy.getDimension();
316334
llvm::SmallVector<mlir::Value> extents;
317335
extents.reserve(rank);
@@ -338,6 +356,10 @@ static void genBoxCombiner(fir::FirOpBuilder &builder, mlir::Location loc,
338356

339357
// Iterate over array elements, applying the equivalent scalar reduction:
340358

359+
// F2018 5.4.10.2: Unallocated allocatable variables may not be referenced
360+
// and so no null check is needed here before indexing into the (possibly
361+
// allocatable) arrays.
362+
341363
// A hlfir::elemental here gets inlined with a temporary so create the
342364
// loop nest directly.
343365
// This function already controls all of the code in this region so we
@@ -412,9 +434,11 @@ createReductionCleanupRegion(fir::FirOpBuilder &builder, mlir::Location loc,
412434

413435
mlir::Type valTy = fir::unwrapRefType(redTy);
414436
if (auto boxTy = mlir::dyn_cast_or_null<fir::BaseBoxType>(valTy)) {
415-
mlir::Type innerTy = fir::extractSequenceType(boxTy);
416-
if (!mlir::isa<fir::SequenceType>(innerTy))
417-
typeError();
437+
if (!mlir::isa<fir::HeapType>(boxTy.getEleTy())) {
438+
mlir::Type innerTy = fir::extractSequenceType(boxTy);
439+
if (!mlir::isa<fir::SequenceType>(innerTy))
440+
typeError();
441+
}
418442

419443
mlir::Value arg = block->getArgument(0);
420444
arg = builder.loadIfRef(loc, arg);
@@ -443,14 +467,27 @@ createReductionCleanupRegion(fir::FirOpBuilder &builder, mlir::Location loc,
443467
typeError();
444468
}
445469

470+
// like fir::unwrapSeqOrBoxedSeqType except it also works for non-sequence boxes
471+
static mlir::Type unwrapSeqOrBoxedType(mlir::Type ty) {
472+
if (auto seqTy = ty.dyn_cast<fir::SequenceType>())
473+
return seqTy.getEleTy();
474+
if (auto boxTy = ty.dyn_cast<fir::BaseBoxType>()) {
475+
auto eleTy = fir::unwrapRefType(boxTy.getEleTy());
476+
if (auto seqTy = eleTy.dyn_cast<fir::SequenceType>())
477+
return seqTy.getEleTy();
478+
return eleTy;
479+
}
480+
return ty;
481+
}
482+
446483
static mlir::Value
447484
createReductionInitRegion(fir::FirOpBuilder &builder, mlir::Location loc,
448485
mlir::omp::DeclareReductionOp &reductionDecl,
449486
const ReductionProcessor::ReductionIdentifier redId,
450487
mlir::Type type, bool isByRef) {
451488
mlir::Type ty = fir::unwrapRefType(type);
452489
mlir::Value initValue = ReductionProcessor::getReductionInitValue(
453-
loc, fir::unwrapSeqOrBoxedSeqType(ty), redId, builder);
490+
loc, unwrapSeqOrBoxedType(ty), redId, builder);
454491

455492
if (fir::isa_trivial(ty)) {
456493
if (isByRef) {
@@ -462,39 +499,99 @@ createReductionInitRegion(fir::FirOpBuilder &builder, mlir::Location loc,
462499
return initValue;
463500
}
464501

502+
// check if an allocatable box is unallocated. If so, initialize the boxAlloca
503+
// to be unallocated e.g.
504+
// %box_alloca = fir.alloca !fir.box<!fir.heap<...>>
505+
// %addr = fir.box_addr %box
506+
// if (%addr == 0) {
507+
// %nullbox = fir.embox %addr
508+
// fir.store %nullbox to %box_alloca
509+
// } else {
510+
// // ...
511+
// fir.store %something to %box_alloca
512+
// }
513+
// omp.yield %box_alloca
514+
mlir::Value blockArg =
515+
builder.loadIfRef(loc, builder.getBlock()->getArgument(0));
516+
auto handleNullAllocatable = [&](mlir::Value boxAlloca) -> fir::IfOp {
517+
mlir::Value addr = builder.create<fir::BoxAddrOp>(loc, blockArg);
518+
mlir::Value isNotAllocated = builder.genIsNullAddr(loc, addr);
519+
fir::IfOp ifOp = builder.create<fir::IfOp>(loc, isNotAllocated,
520+
/*withElseRegion=*/true);
521+
builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
522+
// just embox the null address and return
523+
mlir::Value nullBox = builder.create<fir::EmboxOp>(loc, ty, addr);
524+
builder.create<fir::StoreOp>(loc, nullBox, boxAlloca);
525+
return ifOp;
526+
};
527+
465528
// all arrays are boxed
466529
if (auto boxTy = mlir::dyn_cast_or_null<fir::BaseBoxType>(ty)) {
467-
assert(isByRef && "passing arrays by value is unsupported");
468-
// TODO: support allocatable arrays: !fir.box<!fir.heap<!fir.array<...>>>
469-
mlir::Type innerTy = fir::extractSequenceType(boxTy);
530+
assert(isByRef && "passing boxes by value is unsupported");
531+
bool isAllocatable = mlir::isa<fir::HeapType>(boxTy.getEleTy());
532+
mlir::Value boxAlloca = builder.create<fir::AllocaOp>(loc, ty);
533+
mlir::Type innerTy = fir::unwrapRefType(boxTy.getEleTy());
534+
if (fir::isa_trivial(innerTy)) {
535+
// boxed non-sequence value e.g. !fir.box<!fir.heap<i32>>
536+
if (!isAllocatable)
537+
TODO(loc, "Reduction of non-allocatable trivial typed box");
538+
539+
fir::IfOp ifUnallocated = handleNullAllocatable(boxAlloca);
540+
541+
builder.setInsertionPointToStart(&ifUnallocated.getElseRegion().front());
542+
mlir::Value valAlloc = builder.create<fir::AllocMemOp>(loc, innerTy);
543+
builder.createStoreWithConvert(loc, initValue, valAlloc);
544+
mlir::Value box = builder.create<fir::EmboxOp>(loc, ty, valAlloc);
545+
builder.create<fir::StoreOp>(loc, box, boxAlloca);
546+
547+
auto insPt = builder.saveInsertionPoint();
548+
createReductionCleanupRegion(builder, loc, reductionDecl);
549+
builder.restoreInsertionPoint(insPt);
550+
builder.setInsertionPointAfter(ifUnallocated);
551+
return boxAlloca;
552+
}
553+
innerTy = fir::extractSequenceType(boxTy);
470554
if (!mlir::isa<fir::SequenceType>(innerTy))
471555
TODO(loc, "Unsupported boxed type for reduction");
556+
557+
fir::IfOp ifUnallocated{nullptr};
558+
if (isAllocatable) {
559+
ifUnallocated = handleNullAllocatable(boxAlloca);
560+
builder.setInsertionPointToStart(&ifUnallocated.getElseRegion().front());
561+
}
562+
472563
// Create the private copy from the initial fir.box:
473-
hlfir::Entity source = hlfir::Entity{builder.getBlock()->getArgument(0)};
564+
hlfir::Entity source = hlfir::Entity{blockArg};
474565

475566
// Allocating on the heap in case the whole reduction is nested inside of a
476567
// loop
477568
// TODO: compare performance here to using allocas - this could be made to
478569
// work by inserting stacksave/stackrestore around the reduction in
479570
// openmpirbuilder
480571
auto [temp, needsDealloc] = createTempFromMold(loc, builder, source);
481-
// if needsDealloc isn't statically false, add cleanup region. TODO: always
572+
// if needsDealloc isn't statically false, add cleanup region. Always
482573
// do this for allocatable boxes because they might have been re-allocated
483574
// in the body of the loop/parallel region
575+
484576
std::optional<int64_t> cstNeedsDealloc =
485577
fir::getIntIfConstant(needsDealloc);
486578
assert(cstNeedsDealloc.has_value() &&
487579
"createTempFromMold decides this statically");
488580
if (cstNeedsDealloc.has_value() && *cstNeedsDealloc != false) {
489581
mlir::OpBuilder::InsertionGuard guard(builder);
490582
createReductionCleanupRegion(builder, loc, reductionDecl);
583+
} else {
584+
assert(!isAllocatable && "Allocatable arrays must be heap allocated");
491585
}
492586

493587
// Put the temporary inside of a box:
494588
hlfir::Entity box = hlfir::genVariableBox(loc, builder, temp);
495-
builder.create<hlfir::AssignOp>(loc, initValue, box);
496-
mlir::Value boxAlloca = builder.create<fir::AllocaOp>(loc, ty);
497-
builder.create<fir::StoreOp>(loc, box, boxAlloca);
589+
// hlfir::genVariableBox removes fir.heap<> around the element type
590+
mlir::Value convertedBox = builder.createConvert(loc, ty, box.getBase());
591+
builder.create<hlfir::AssignOp>(loc, initValue, convertedBox);
592+
builder.create<fir::StoreOp>(loc, convertedBox, boxAlloca);
593+
if (ifUnallocated)
594+
builder.setInsertionPointAfter(ifUnallocated);
498595
return boxAlloca;
499596
}
500597

flang/lib/Optimizer/Builder/FIRBuilder.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ mlir::Block *fir::FirOpBuilder::getAllocaBlock() {
250250
.getParentOfType<mlir::omp::OutlineableOpenMPOpInterface>()) {
251251
return ompOutlineableIface.getAllocaBlock();
252252
}
253-
if (mlir::isa<mlir::omp::DeclareReductionOp>(getRegion().getParentOp()))
253+
if (getRegion().getParentOfType<mlir::omp::DeclareReductionOp>())
254254
return &getRegion().front();
255255
if (auto accRecipeIface =
256256
getRegion().getParentOfType<mlir::acc::RecipeInterface>()) {

flang/test/Lower/OpenMP/Todo/reduction-allocatable.f90

Lines changed: 0 additions & 21 deletions
This file was deleted.
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
! RUN: bbc -emit-hlfir -fopenmp -o - %s | FileCheck %s
2+
! RUN: %flang_fc1 -emit-hlfir -fopenmp -o - %s | FileCheck %s
3+
4+
program reduce
5+
integer :: i = 0
6+
integer, dimension(:), allocatable :: r
7+
8+
allocate(r(2))
9+
10+
!$omp parallel do reduction(+:r)
11+
do i=0,10
12+
r(1) = i
13+
r(2) = -i
14+
enddo
15+
!$omp end parallel do
16+
17+
print *,r
18+
19+
end program
20+
21+
! CHECK-LABEL: omp.declare_reduction @add_reduction_byref_box_heap_Uxi32 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> init {
22+
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>):
23+
! CHECK: %[[VAL_1:.*]] = arith.constant 0 : i32
24+
! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
25+
! CHECK: %[[VAL_10:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>>
26+
! CHECK: %[[ADDR:.*]] = fir.box_addr %[[VAL_2]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
27+
! CHECK: %[[ADDRI:.*]] = fir.convert %[[ADDR]] : (!fir.heap<!fir.array<?xi32>>) -> i64
28+
! CHECK: %[[C0_I64:.*]] = arith.constant 0 : i64
29+
! CHECK: %[[IS_NULL:.*]] = arith.cmpi eq, %[[ADDRI]], %[[C0_I64]] : i64
30+
! CHECK: fir.if %[[IS_NULL]] {
31+
! CHECK: %[[NULL_BOX:.*]] = fir.embox %[[ADDR]] : (!fir.heap<!fir.array<?xi32>>) -> !fir.box<!fir.heap<!fir.array<?xi32>>>
32+
! CHECK: fir.store %[[NULL_BOX]] to %[[VAL_10]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
33+
! CHECK: } else {
34+
! CHECK: %[[VAL_3:.*]] = arith.constant 0 : index
35+
! CHECK: %[[VAL_4:.*]]:3 = fir.box_dims %[[VAL_2]], %[[VAL_3]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
36+
! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_4]]#1 : (index) -> !fir.shape<1>
37+
! CHECK: %[[VAL_6:.*]] = fir.allocmem !fir.array<?xi32>, %[[VAL_4]]#1 {bindc_name = ".tmp", uniq_name = ""}
38+
! CHECK: %[[VAL_7:.*]] = arith.constant true
39+
! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_6]](%[[VAL_5]]) {uniq_name = ".tmp"} : (!fir.heap<!fir.array<?xi32>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xi32>>, !fir.heap<!fir.array<?xi32>>)
40+
! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]]#0 : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.heap<!fir.array<?xi32>>>
41+
! CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_9]] : i32, !fir.box<!fir.heap<!fir.array<?xi32>>>
42+
! CHECK: fir.store %[[VAL_9]] to %[[VAL_10]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
43+
! CHECK: }
44+
! CHECK: omp.yield(%[[VAL_10]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)
45+
! CHECK: } combiner {
46+
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, %[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>):
47+
! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
48+
! CHECK: %[[VAL_3:.*]] = fir.load %[[VAL_1]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
49+
! CHECK: %[[VAL_4:.*]] = arith.constant 0 : index
50+
! CHECK: %[[VAL_5:.*]]:3 = fir.box_dims %[[VAL_2]], %[[VAL_4]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
51+
! CHECK: %[[VAL_6:.*]] = fir.shape_shift %[[VAL_5]]#0, %[[VAL_5]]#1 : (index, index) -> !fir.shapeshift<1>
52+
! CHECK: %[[VAL_7:.*]] = arith.constant 1 : index
53+
! CHECK: fir.do_loop %[[VAL_8:.*]] = %[[VAL_7]] to %[[VAL_5]]#1 step %[[VAL_7]] unordered {
54+
! CHECK: %[[VAL_9:.*]] = fir.array_coor %[[VAL_2]](%[[VAL_6]]) %[[VAL_8]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>, !fir.shapeshift<1>, index) -> !fir.ref<i32>
55+
! CHECK: %[[VAL_10:.*]] = fir.array_coor %[[VAL_3]](%[[VAL_6]]) %[[VAL_8]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>, !fir.shapeshift<1>, index) -> !fir.ref<i32>
56+
! CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_9]] : !fir.ref<i32>
57+
! CHECK: %[[VAL_12:.*]] = fir.load %[[VAL_10]] : !fir.ref<i32>
58+
! CHECK: %[[VAL_13:.*]] = arith.addi %[[VAL_11]], %[[VAL_12]] : i32
59+
! CHECK: fir.store %[[VAL_13]] to %[[VAL_9]] : !fir.ref<i32>
60+
! CHECK: }
61+
! CHECK: omp.yield(%[[VAL_0]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)
62+
! CHECK: } cleanup {
63+
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>):
64+
! CHECK: %[[VAL_1:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
65+
! CHECK: %[[VAL_2:.*]] = fir.box_addr %[[VAL_1]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
66+
! CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (!fir.heap<!fir.array<?xi32>>) -> i64
67+
! CHECK: %[[VAL_4:.*]] = arith.constant 0 : i64
68+
! CHECK: %[[VAL_5:.*]] = arith.cmpi ne, %[[VAL_3]], %[[VAL_4]] : i64
69+
! CHECK: fir.if %[[VAL_5]] {
70+
! CHECK: fir.freemem %[[VAL_2]] : !fir.heap<!fir.array<?xi32>>
71+
! CHECK: }
72+
! CHECK: omp.yield
73+
! CHECK: }
74+
75+
! CHECK-LABEL: func.func @_QQmain() attributes {fir.bindc_name = "reduce"} {
76+
! CHECK: %[[VAL_0:.*]] = fir.address_of(@_QFEi) : !fir.ref<i32>
77+
! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
78+
! CHECK: %[[VAL_2:.*]] = fir.address_of(@_QFEr) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
79+
! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {fortran_attrs = {{.*}}<allocatable>, uniq_name = "_QFEr"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)
80+
! CHECK: %[[VAL_4:.*]] = arith.constant 2 : i32
81+
! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (i32) -> index
82+
! CHECK: %[[VAL_6:.*]] = arith.constant 0 : index
83+
! CHECK: %[[VAL_7:.*]] = arith.cmpi sgt, %[[VAL_5]], %[[VAL_6]] : index
84+
! CHECK: %[[VAL_8:.*]] = arith.select %[[VAL_7]], %[[VAL_5]], %[[VAL_6]] : index
85+
! CHECK: %[[VAL_9:.*]] = fir.allocmem !fir.array<?xi32>, %[[VAL_8]] {fir.must_be_heap = true, uniq_name = "_QFEr.alloc"}
86+
! CHECK: %[[VAL_10:.*]] = fir.shape %[[VAL_8]] : (index) -> !fir.shape<1>
87+
! CHECK: %[[VAL_11:.*]] = fir.embox %[[VAL_9]](%[[VAL_10]]) : (!fir.heap<!fir.array<?xi32>>, !fir.shape<1>) -> !fir.box<!fir.heap<!fir.array<?xi32>>>
88+
! CHECK: fir.store %[[VAL_11]] to %[[VAL_3]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
89+
! CHECK: omp.parallel {
90+
! CHECK: %[[VAL_12:.*]] = fir.alloca i32 {adapt.valuebyref, pinned}
91+
! CHECK: %[[VAL_13:.*]]:2 = hlfir.declare %[[VAL_12]] {uniq_name = "_QFEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
92+
! CHECK: %[[VAL_14:.*]] = arith.constant 0 : i32
93+
! CHECK: %[[VAL_15:.*]] = arith.constant 10 : i32
94+
! CHECK: %[[VAL_16:.*]] = arith.constant 1 : i32
95+
! CHECK: omp.wsloop byref reduction(@add_reduction_byref_box_heap_Uxi32 %[[VAL_3]]#0 -> %[[VAL_17:.*]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) for (%[[VAL_18:.*]]) : i32 = (%[[VAL_14]]) to (%[[VAL_15]]) inclusive step (%[[VAL_16]]) {
96+
! CHECK: fir.store %[[VAL_18]] to %[[VAL_13]]#1 : !fir.ref<i32>
97+
! CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_17]] {fortran_attrs = {{.*}}<allocatable>, uniq_name = "_QFEr"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)
98+
! CHECK: %[[VAL_20:.*]] = fir.load %[[VAL_13]]#0 : !fir.ref<i32>
99+
! CHECK: %[[VAL_21:.*]] = fir.load %[[VAL_19]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
100+
! CHECK: %[[VAL_22:.*]] = arith.constant 1 : index
101+
! CHECK: %[[VAL_23:.*]] = hlfir.designate %[[VAL_21]] (%[[VAL_22]]) : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> !fir.ref<i32>
102+
! CHECK: hlfir.assign %[[VAL_20]] to %[[VAL_23]] : i32, !fir.ref<i32>
103+
! CHECK: %[[VAL_24:.*]] = fir.load %[[VAL_13]]#0 : !fir.ref<i32>
104+
! CHECK: %[[VAL_25:.*]] = arith.constant 0 : i32
105+
! CHECK: %[[VAL_26:.*]] = arith.subi %[[VAL_25]], %[[VAL_24]] : i32
106+
! CHECK: %[[VAL_27:.*]] = fir.load %[[VAL_19]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
107+
! CHECK: %[[VAL_28:.*]] = arith.constant 2 : index
108+
! CHECK: %[[VAL_29:.*]] = hlfir.designate %[[VAL_27]] (%[[VAL_28]]) : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> !fir.ref<i32>
109+
! CHECK: hlfir.assign %[[VAL_26]] to %[[VAL_29]] : i32, !fir.ref<i32>
110+
! CHECK: omp.yield
111+
! CHECK: }
112+
! CHECK: omp.terminator
113+
! CHECK: }

flang/test/Lower/OpenMP/parallel-reduction-array.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ program reduce
1717
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.array<3xi32>>>):
1818
! CHECK: %[[VAL_2:.*]] = arith.constant 0 : i32
1919
! CHECK: %[[VAL_3:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.array<3xi32>>>
20+
! CHECK: %[[VAL_8:.*]] = fir.alloca !fir.box<!fir.array<3xi32>>
2021
! CHECK: %[[VAL_4:.*]] = arith.constant 3 : index
2122
! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_4]] : (index) -> !fir.shape<1>
2223
! CHECK: %[[VAL_1:.*]] = fir.allocmem !fir.array<3xi32> {bindc_name = ".tmp", uniq_name = ""}
@@ -25,7 +26,6 @@ program reduce
2526
!fir.shape<1>) -> (!fir.heap<!fir.array<3xi32>>, !fir.heap<!fir.array<3xi32>>)
2627
! CHECK: %[[VAL_7:.*]] = fir.embox %[[VAL_6]]#0(%[[VAL_5]]) : (!fir.heap<!fir.array<3xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<3xi32>>
2728
! CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_7]] : i32, !fir.box<!fir.array<3xi32>>
28-
! CHECK: %[[VAL_8:.*]] = fir.alloca !fir.box<!fir.array<3xi32>>
2929
! CHECK: fir.store %[[VAL_7]] to %[[VAL_8]] : !fir.ref<!fir.box<!fir.array<3xi32>>>
3030
! CHECK: omp.yield(%[[VAL_8]] : !fir.ref<!fir.box<!fir.array<3xi32>>>)
3131
! CHECK: } combiner {

0 commit comments

Comments
 (0)