Skip to content

Commit de90391

Browse files
authored
[flang][OpenMP] Lower REDUCTION clause for SECTIONS (#97858)
The tricky bit here is that we need to generate the reduction symbol mapping inside each of the nested SECTION constructs. This is a bit similar to omp.canonical_loop inside of omp.wsloop, except the SECTION constructs come from the PFT. To make this work I moved the lowering of the SECTION constructs inside of the lowering SECTIONS (where reduction information is still available). This subverts the normal control flow for OpenMP lowering a bit. One alternative option I investigated would be to generate the SECTION CONSTRUCTS as normal as though there were no reduction, and then to fix them up after control returns back to genSectionsOp. The problem here is that the code generated for the section body has the wrong symbol mapping for the reduction variable, so all of the nested code has to be patched up. In my prototype version this was even more hacky than what the solution I settled upon.
1 parent 87bf82d commit de90391

File tree

5 files changed

+239
-45
lines changed

5 files changed

+239
-45
lines changed

flang/lib/Lower/OpenMP/ClauseProcessor.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,14 +1044,6 @@ bool ClauseProcessor::processReduction(
10441044
});
10451045
}
10461046

1047-
bool ClauseProcessor::processSectionsReduction(
1048-
mlir::Location currentLocation, mlir::omp::ReductionClauseOps &) const {
1049-
return findRepeatableClause<omp::clause::Reduction>(
1050-
[&](const omp::clause::Reduction &, const parser::CharBlock &) {
1051-
TODO(currentLocation, "OMPC_Reduction");
1052-
});
1053-
}
1054-
10551047
bool ClauseProcessor::processTo(
10561048
llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const {
10571049
return findRepeatableClause<omp::clause::To>(

flang/lib/Lower/OpenMP/ClauseProcessor.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,6 @@ class ClauseProcessor {
125125
llvm::SmallVectorImpl<mlir::Type> *reductionTypes = nullptr,
126126
llvm::SmallVectorImpl<const semantics::Symbol *> *reductionSyms =
127127
nullptr) const;
128-
bool processSectionsReduction(mlir::Location currentLocation,
129-
mlir::omp::ReductionClauseOps &result) const;
130128
bool processTo(llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const;
131129
bool processUseDeviceAddr(
132130
mlir::omp::UseDeviceAddrClauseOps &result,

flang/lib/Lower/OpenMP/OpenMP.cpp

Lines changed: 81 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,14 +1091,16 @@ static void genParallelClauses(
10911091
cp.processReduction(loc, clauseOps, &reductionTypes, &reductionSyms);
10921092
}
10931093

1094-
static void genSectionsClauses(lower::AbstractConverter &converter,
1095-
semantics::SemanticsContext &semaCtx,
1096-
const List<Clause> &clauses, mlir::Location loc,
1097-
mlir::omp::SectionsClauseOps &clauseOps) {
1094+
static void genSectionsClauses(
1095+
lower::AbstractConverter &converter, semantics::SemanticsContext &semaCtx,
1096+
const List<Clause> &clauses, mlir::Location loc,
1097+
mlir::omp::SectionsClauseOps &clauseOps,
1098+
llvm::SmallVectorImpl<mlir::Type> &reductionTypes,
1099+
llvm::SmallVectorImpl<const semantics::Symbol *> &reductionSyms) {
10981100
ClauseProcessor cp(converter, semaCtx, clauses);
10991101
cp.processAllocate(clauseOps);
1100-
cp.processSectionsReduction(loc, clauseOps);
11011102
cp.processNowait(clauseOps);
1103+
cp.processReduction(loc, clauseOps, &reductionTypes, &reductionSyms);
11021104
// TODO Support delayed privatization.
11031105
}
11041106

@@ -1481,27 +1483,20 @@ genParallelOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
14811483
return genOpWithBody<mlir::omp::ParallelOp>(genInfo, queue, item, clauseOps);
14821484
}
14831485

1484-
static mlir::omp::SectionOp
1485-
genSectionOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
1486-
semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval,
1487-
mlir::Location loc, const ConstructQueue &queue,
1488-
ConstructQueue::iterator item) {
1489-
// Currently only private/firstprivate clause is handled, and
1490-
// all privatization is done within `omp.section` operations.
1491-
return genOpWithBody<mlir::omp::SectionOp>(
1492-
OpWithBodyGenInfo(converter, symTable, semaCtx, loc, eval,
1493-
llvm::omp::Directive::OMPD_section)
1494-
.setClauses(&item->clauses),
1495-
queue, item);
1496-
}
1497-
1486+
/// This breaks the normal prototype of the gen*Op functions: adding the
1487+
/// sectionBlocks argument so that the enclosed section constructs can be
1488+
/// lowered here with correct reduction symbol remapping.
14981489
static mlir::omp::SectionsOp
14991490
genSectionsOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
15001491
semantics::SemanticsContext &semaCtx,
15011492
lower::pft::Evaluation &eval, mlir::Location loc,
1502-
const ConstructQueue &queue, ConstructQueue::iterator item) {
1493+
const ConstructQueue &queue, ConstructQueue::iterator item,
1494+
const parser::OmpSectionBlocks &sectionBlocks) {
1495+
llvm::SmallVector<mlir::Type> reductionTypes;
1496+
llvm::SmallVector<const semantics::Symbol *> reductionSyms;
15031497
mlir::omp::SectionsClauseOps clauseOps;
1504-
genSectionsClauses(converter, semaCtx, item->clauses, loc, clauseOps);
1498+
genSectionsClauses(converter, semaCtx, item->clauses, loc, clauseOps,
1499+
reductionTypes, reductionSyms);
15051500

15061501
auto &builder = converter.getFirOpBuilder();
15071502

@@ -1530,11 +1525,46 @@ genSectionsOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
15301525
}
15311526

15321527
// SECTIONS construct.
1533-
mlir::omp::SectionsOp sectionsOp = genOpWithBody<mlir::omp::SectionsOp>(
1534-
OpWithBodyGenInfo(converter, symTable, semaCtx, loc, eval,
1535-
llvm::omp::Directive::OMPD_sections)
1536-
.setClauses(&nonDsaClauses),
1537-
queue, item, clauseOps);
1528+
auto sectionsOp = builder.create<mlir::omp::SectionsOp>(loc, clauseOps);
1529+
1530+
// create entry block with reduction variables as arguments
1531+
llvm::SmallVector<mlir::Location> blockArgLocs(reductionSyms.size(), loc);
1532+
builder.createBlock(&sectionsOp->getRegion(0), {}, reductionTypes,
1533+
blockArgLocs);
1534+
mlir::Operation *terminator =
1535+
lower::genOpenMPTerminator(builder, sectionsOp, loc);
1536+
1537+
auto reductionCallback = [&](mlir::Operation *op) {
1538+
genReductionVars(op, converter, loc, reductionSyms, reductionTypes);
1539+
return reductionSyms;
1540+
};
1541+
1542+
// Generate nested SECTION constructs.
1543+
// This is done here rather than in genOMP([...], OpenMPSectionConstruct )
1544+
// because we need to run genReductionVars on each omp.section so that the
1545+
// reduction variable gets mapped to the private version
1546+
for (auto [construct, nestedEval] :
1547+
llvm::zip(sectionBlocks.v, eval.getNestedEvaluations())) {
1548+
const auto *sectionConstruct =
1549+
std::get_if<parser::OpenMPSectionConstruct>(&construct.u);
1550+
if (!sectionConstruct) {
1551+
assert(false &&
1552+
"unexpected construct nested inside of SECTIONS construct");
1553+
continue;
1554+
}
1555+
1556+
ConstructQueue sectionQueue{buildConstructQueue(
1557+
converter.getFirOpBuilder().getModule(), semaCtx, nestedEval,
1558+
sectionConstruct->source, llvm::omp::Directive::OMPD_section, {})};
1559+
1560+
builder.setInsertionPoint(terminator);
1561+
genOpWithBody<mlir::omp::SectionOp>(
1562+
OpWithBodyGenInfo(converter, symTable, semaCtx, loc, nestedEval,
1563+
llvm::omp::Directive::OMPD_section)
1564+
.setClauses(&sectionQueue.begin()->clauses)
1565+
.setGenRegionEntryCb(reductionCallback),
1566+
sectionQueue, sectionQueue.begin());
1567+
}
15381568

15391569
if (!lastprivates.empty()) {
15401570
mlir::Region &sectionsBody = sectionsOp.getRegion();
@@ -2120,10 +2150,14 @@ static void genOMPDispatch(lower::AbstractConverter &converter,
21202150
genStandaloneParallel(converter, symTable, semaCtx, eval, loc, queue, item);
21212151
break;
21222152
case llvm::omp::Directive::OMPD_section:
2123-
genSectionOp(converter, symTable, semaCtx, eval, loc, queue, item);
2153+
llvm_unreachable("genOMPDispatch: OMPD_section");
2154+
// Lowered in the enclosing genSectionsOp.
21242155
break;
21252156
case llvm::omp::Directive::OMPD_sections:
2126-
genSectionsOp(converter, symTable, semaCtx, eval, loc, queue, item);
2157+
// Called directly from genOMP([...], OpenMPSectionsConstruct) because it
2158+
// has a different prototype.
2159+
// This code path is still taken when iterating through the construct queue
2160+
// in genBodyOfOp
21272161
break;
21282162
case llvm::omp::Directive::OMPD_simd:
21292163
genStandaloneSimd(converter, symTable, semaCtx, eval, loc, queue, item,
@@ -2536,11 +2570,7 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
25362570
semantics::SemanticsContext &semaCtx,
25372571
lower::pft::Evaluation &eval,
25382572
const parser::OpenMPSectionConstruct &sectionConstruct) {
2539-
mlir::Location loc = converter.getCurrentLocation();
2540-
ConstructQueue queue{buildConstructQueue(
2541-
converter.getFirOpBuilder().getModule(), semaCtx, eval,
2542-
sectionConstruct.source, llvm::omp::Directive::OMPD_section, {})};
2543-
genOMPDispatch(converter, symTable, semaCtx, eval, loc, queue, queue.begin());
2573+
// Do nothing here. SECTION is lowered inside of the lowering for Sections
25442574
}
25452575

25462576
static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
@@ -2553,6 +2583,8 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
25532583
std::get<parser::OmpClauseList>(beginSectionsDirective.t), semaCtx);
25542584
const auto &endSectionsDirective =
25552585
std::get<parser::OmpEndSectionsDirective>(sectionsConstruct.t);
2586+
const auto &sectionBlocks =
2587+
std::get<parser::OmpSectionBlocks>(sectionsConstruct.t);
25562588
clauses.append(makeClauses(
25572589
std::get<parser::OmpClauseList>(endSectionsDirective.t), semaCtx));
25582590
mlir::Location currentLocation = converter.getCurrentLocation();
@@ -2564,8 +2596,22 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
25642596
ConstructQueue queue{
25652597
buildConstructQueue(converter.getFirOpBuilder().getModule(), semaCtx,
25662598
eval, source, directive, clauses)};
2567-
genOMPDispatch(converter, symTable, semaCtx, eval, currentLocation, queue,
2568-
queue.begin());
2599+
ConstructQueue::iterator next = queue.begin();
2600+
// Generate constructs that come first e.g. Parallel
2601+
while (next != queue.end() &&
2602+
next->id != llvm::omp::Directive::OMPD_sections) {
2603+
genOMPDispatch(converter, symTable, semaCtx, eval, currentLocation, queue,
2604+
next);
2605+
next = std::next(next);
2606+
}
2607+
2608+
// call genSectionsOp directly (not via genOMPDispatch) so that we can add the
2609+
// sectionBlocks argument
2610+
assert(next != queue.end());
2611+
assert(next->id == llvm::omp::Directive::OMPD_sections);
2612+
genSectionsOp(converter, symTable, semaCtx, eval, currentLocation, queue,
2613+
next, sectionBlocks);
2614+
assert(std::next(next) == queue.end());
25692615
}
25702616

25712617
static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
! RUN: bbc -emit-hlfir -fopenmp %s -o - | FileCheck %s
2+
! RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s
3+
4+
subroutine sectionsReduction(x)
5+
real, dimension(:) :: x
6+
7+
!$omp parallel
8+
!$omp sections reduction(+:x)
9+
x = x + 1
10+
!$omp section
11+
x = x + 2
12+
!$omp end sections
13+
!$omp end parallel
14+
end subroutine
15+
16+
17+
! CHECK-LABEL: omp.declare_reduction @add_reduction_byref_box_Uxf32 : !fir.ref<!fir.box<!fir.array<?xf32>>> init {
18+
! [...]
19+
! CHECK: omp.yield
20+
! CHECK-LABEL: } combiner {
21+
! [...]
22+
! CHECK: omp.yield
23+
! CHECK-LABEL: } cleanup {
24+
! [...]
25+
! CHECK: omp.yield
26+
! CHECK: }
27+
28+
! CHECK-LABEL: func.func @_QPsectionsreduction(
29+
! CHECK-SAME: %[[VAL_0:.*]]: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "x"}) {
30+
! CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
31+
! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {uniq_name = "_QFsectionsreductionEx"} : (!fir.box<!fir.array<?xf32>>, !fir.dscope) -> (!fir.box<!fir.array<?xf32>>, !fir.box<!fir.array<?xf32>>)
32+
! CHECK: omp.parallel {
33+
! CHECK: %[[VAL_3:.*]] = fir.alloca !fir.box<!fir.array<?xf32>>
34+
! CHECK: fir.store %[[VAL_2]]#1 to %[[VAL_3]] : !fir.ref<!fir.box<!fir.array<?xf32>>>
35+
! CHECK: omp.sections reduction(byref @add_reduction_byref_box_Uxf32 -> %[[VAL_3]] : !fir.ref<!fir.box<!fir.array<?xf32>>>) {
36+
! CHECK: ^bb0(%[[VAL_4:.*]]: !fir.ref<!fir.box<!fir.array<?xf32>>>):
37+
! CHECK: omp.section {
38+
! CHECK: ^bb0(%[[VAL_5:.*]]: !fir.ref<!fir.box<!fir.array<?xf32>>>):
39+
! [...]
40+
! CHECK: omp.terminator
41+
! CHECK: }
42+
! CHECK: omp.section {
43+
! CHECK: ^bb0(%[[VAL_23:.*]]: !fir.ref<!fir.box<!fir.array<?xf32>>>):
44+
! [...]
45+
! CHECK: omp.terminator
46+
! CHECK: }
47+
! CHECK: omp.terminator
48+
! CHECK: }
49+
! CHECK: omp.terminator
50+
! CHECK: }
51+
! CHECK: return
52+
! CHECK: }
53+
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
! RUN: bbc -emit-hlfir -fopenmp %s -o - | FileCheck %s
2+
! RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s
3+
4+
subroutine sectionsReduction(x,y)
5+
real :: x, y
6+
7+
!$omp parallel
8+
!$omp sections reduction(+:x,y)
9+
x = x + 1
10+
y = x
11+
!$omp section
12+
x = x + 2
13+
y = x
14+
!$omp end sections
15+
!$omp end parallel
16+
17+
!$omp parallel sections reduction(+:x) reduction(+:y)
18+
x = x + 1
19+
y = x
20+
!$omp section
21+
x = x + 2
22+
y = x
23+
!$omp end parallel sections
24+
end subroutine
25+
26+
! CHECK-LABEL: omp.declare_reduction @add_reduction_f32 : f32 init {
27+
! CHECK: ^bb0(%[[VAL_0:.*]]: f32):
28+
! CHECK: %[[VAL_1:.*]] = arith.constant 0.000000e+00 : f32
29+
! CHECK: omp.yield(%[[VAL_1]] : f32)
30+
! CHECK-LABEL: } combiner {
31+
! CHECK: ^bb0(%[[VAL_0:.*]]: f32, %[[VAL_1:.*]]: f32):
32+
! CHECK: %[[VAL_2:.*]] = arith.addf %[[VAL_0]], %[[VAL_1]] fastmath<contract> : f32
33+
! CHECK: omp.yield(%[[VAL_2]] : f32)
34+
! CHECK: }
35+
36+
! CHECK-LABEL: func.func @_QPsectionsreduction(
37+
! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<f32> {fir.bindc_name = "x"},
38+
! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref<f32> {fir.bindc_name = "y"}) {
39+
! CHECK: %[[VAL_2:.*]] = fir.dummy_scope : !fir.dscope
40+
! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_2]] {uniq_name = "_QFsectionsreductionEx"} : (!fir.ref<f32>, !fir.dscope) -> (!fir.ref<f32>, !fir.ref<f32>)
41+
! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_1]] dummy_scope %[[VAL_2]] {uniq_name = "_QFsectionsreductionEy"} : (!fir.ref<f32>, !fir.dscope) -> (!fir.ref<f32>, !fir.ref<f32>)
42+
! CHECK: omp.parallel {
43+
! CHECK: omp.sections reduction(@add_reduction_f32 -> %[[VAL_3]]#0 : !fir.ref<f32>, @add_reduction_f32 -> %[[VAL_4]]#0 : !fir.ref<f32>) {
44+
! CHECK: ^bb0(%[[VAL_5:.*]]: !fir.ref<f32>, %[[VAL_6:.*]]: !fir.ref<f32>):
45+
! CHECK: omp.section {
46+
! CHECK: ^bb0(%[[VAL_7:.*]]: !fir.ref<f32>, %[[VAL_8:.*]]: !fir.ref<f32>):
47+
! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFsectionsreductionEx"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
48+
! CHECK: %[[VAL_10:.*]]:2 = hlfir.declare %[[VAL_8]] {uniq_name = "_QFsectionsreductionEy"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
49+
! CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_9]]#0 : !fir.ref<f32>
50+
! CHECK: %[[VAL_12:.*]] = arith.constant 1.000000e+00 : f32
51+
! CHECK: %[[VAL_13:.*]] = arith.addf %[[VAL_11]], %[[VAL_12]] fastmath<contract> : f32
52+
! CHECK: hlfir.assign %[[VAL_13]] to %[[VAL_9]]#0 : f32, !fir.ref<f32>
53+
! CHECK: %[[VAL_14:.*]] = fir.load %[[VAL_9]]#0 : !fir.ref<f32>
54+
! CHECK: hlfir.assign %[[VAL_14]] to %[[VAL_10]]#0 : f32, !fir.ref<f32>
55+
! CHECK: omp.terminator
56+
! CHECK: }
57+
! CHECK: omp.section {
58+
! CHECK: ^bb0(%[[VAL_15:.*]]: !fir.ref<f32>, %[[VAL_16:.*]]: !fir.ref<f32>):
59+
! CHECK: %[[VAL_17:.*]]:2 = hlfir.declare %[[VAL_15]] {uniq_name = "_QFsectionsreductionEx"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
60+
! CHECK: %[[VAL_18:.*]]:2 = hlfir.declare %[[VAL_16]] {uniq_name = "_QFsectionsreductionEy"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
61+
! CHECK: %[[VAL_19:.*]] = fir.load %[[VAL_17]]#0 : !fir.ref<f32>
62+
! CHECK: %[[VAL_20:.*]] = arith.constant 2.000000e+00 : f32
63+
! CHECK: %[[VAL_21:.*]] = arith.addf %[[VAL_19]], %[[VAL_20]] fastmath<contract> : f32
64+
! CHECK: hlfir.assign %[[VAL_21]] to %[[VAL_17]]#0 : f32, !fir.ref<f32>
65+
! CHECK: %[[VAL_22:.*]] = fir.load %[[VAL_17]]#0 : !fir.ref<f32>
66+
! CHECK: hlfir.assign %[[VAL_22]] to %[[VAL_18]]#0 : f32, !fir.ref<f32>
67+
! CHECK: omp.terminator
68+
! CHECK: }
69+
! CHECK: omp.terminator
70+
! CHECK: }
71+
! CHECK: omp.terminator
72+
! CHECK: }
73+
! CHECK: omp.parallel {
74+
! CHECK: omp.sections reduction(@add_reduction_f32 -> %[[VAL_3]]#0 : !fir.ref<f32>, @add_reduction_f32 -> %[[VAL_4]]#0 : !fir.ref<f32>) {
75+
! CHECK: ^bb0(%[[VAL_23:.*]]: !fir.ref<f32>, %[[VAL_24:.*]]: !fir.ref<f32>):
76+
! CHECK: omp.section {
77+
! CHECK: ^bb0(%[[VAL_25:.*]]: !fir.ref<f32>, %[[VAL_26:.*]]: !fir.ref<f32>):
78+
! CHECK: %[[VAL_27:.*]]:2 = hlfir.declare %[[VAL_25]] {uniq_name = "_QFsectionsreductionEx"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
79+
! CHECK: %[[VAL_28:.*]]:2 = hlfir.declare %[[VAL_26]] {uniq_name = "_QFsectionsreductionEy"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
80+
! CHECK: %[[VAL_29:.*]] = fir.load %[[VAL_27]]#0 : !fir.ref<f32>
81+
! CHECK: %[[VAL_30:.*]] = arith.constant 1.000000e+00 : f32
82+
! CHECK: %[[VAL_31:.*]] = arith.addf %[[VAL_29]], %[[VAL_30]] fastmath<contract> : f32
83+
! CHECK: hlfir.assign %[[VAL_31]] to %[[VAL_27]]#0 : f32, !fir.ref<f32>
84+
! CHECK: %[[VAL_32:.*]] = fir.load %[[VAL_27]]#0 : !fir.ref<f32>
85+
! CHECK: hlfir.assign %[[VAL_32]] to %[[VAL_28]]#0 : f32, !fir.ref<f32>
86+
! CHECK: omp.terminator
87+
! CHECK: }
88+
! CHECK: omp.section {
89+
! CHECK: ^bb0(%[[VAL_33:.*]]: !fir.ref<f32>, %[[VAL_34:.*]]: !fir.ref<f32>):
90+
! CHECK: %[[VAL_35:.*]]:2 = hlfir.declare %[[VAL_33]] {uniq_name = "_QFsectionsreductionEx"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
91+
! CHECK: %[[VAL_36:.*]]:2 = hlfir.declare %[[VAL_34]] {uniq_name = "_QFsectionsreductionEy"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
92+
! CHECK: %[[VAL_37:.*]] = fir.load %[[VAL_35]]#0 : !fir.ref<f32>
93+
! CHECK: %[[VAL_38:.*]] = arith.constant 2.000000e+00 : f32
94+
! CHECK: %[[VAL_39:.*]] = arith.addf %[[VAL_37]], %[[VAL_38]] fastmath<contract> : f32
95+
! CHECK: hlfir.assign %[[VAL_39]] to %[[VAL_35]]#0 : f32, !fir.ref<f32>
96+
! CHECK: %[[VAL_40:.*]] = fir.load %[[VAL_35]]#0 : !fir.ref<f32>
97+
! CHECK: hlfir.assign %[[VAL_40]] to %[[VAL_36]]#0 : f32, !fir.ref<f32>
98+
! CHECK: omp.terminator
99+
! CHECK: }
100+
! CHECK: omp.terminator
101+
! CHECK: }
102+
! CHECK: omp.terminator
103+
! CHECK: }
104+
! CHECK: return
105+
! CHECK: }

0 commit comments

Comments
 (0)