Skip to content

Commit 037a32a

Browse files
authored
[flang][OpenMP] Convert DataSharingProcessor to omp::Clause (#81629)
[Clause representation 6/6]
1 parent d8f97c0 commit 037a32a

File tree

4 files changed

+156
-163
lines changed

4 files changed

+156
-163
lines changed

flang/lib/Lower/OpenMP/Clauses.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,12 @@ getBaseObject(const Object &object,
108108
Fortran::semantics::SemanticsContext &semaCtx);
109109

110110
namespace clause {
111+
using DefinedOperator = tomp::clause::DefinedOperatorT<SymIdent, SymReference>;
112+
using ProcedureDesignator =
113+
tomp::clause::ProcedureDesignatorT<SymIdent, SymReference>;
114+
using ReductionOperator =
115+
tomp::clause::ReductionOperatorT<SymIdent, SymReference>;
116+
111117
#ifdef EMPTY_CLASS
112118
#undef EMPTY_CLASS
113119
#endif
@@ -124,12 +130,6 @@ namespace clause {
124130
#undef EMPTY_CLASS
125131
#undef WRAPPER_CLASS
126132

127-
using DefinedOperator = tomp::clause::DefinedOperatorT<SymIdent, SymReference>;
128-
using ProcedureDesignator =
129-
tomp::clause::ProcedureDesignatorT<SymIdent, SymReference>;
130-
using ReductionOperator =
131-
tomp::clause::ReductionOperatorT<SymIdent, SymReference>;
132-
133133
// "Requires" clauses are handled early on, and the aggregated information
134134
// is stored in the Symbol details of modules, programs, and subprograms.
135135
// These clauses are still handled here to cover all alternatives in the

flang/lib/Lower/OpenMP/DataSharingProcessor.cpp

Lines changed: 139 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -81,30 +81,26 @@ void DataSharingProcessor::copyLastPrivateSymbol(
8181
}
8282

8383
void DataSharingProcessor::collectOmpObjectListSymbol(
84-
const Fortran::parser::OmpObjectList &ompObjectList,
84+
const omp::ObjectList &objects,
8585
llvm::SetVector<const Fortran::semantics::Symbol *> &symbolSet) {
86-
for (const Fortran::parser::OmpObject &ompObject : ompObjectList.v) {
87-
Fortran::semantics::Symbol *sym = getOmpObjectSymbol(ompObject);
88-
symbolSet.insert(sym);
89-
}
86+
for (const omp::Object &object : objects)
87+
symbolSet.insert(object.id());
9088
}
9189

9290
void DataSharingProcessor::collectSymbolsForPrivatization() {
9391
bool hasCollapse = false;
94-
for (const Fortran::parser::OmpClause &clause : opClauseList.v) {
92+
for (const omp::Clause &clause : clauses) {
9593
if (const auto &privateClause =
96-
std::get_if<Fortran::parser::OmpClause::Private>(&clause.u)) {
94+
std::get_if<omp::clause::Private>(&clause.u)) {
9795
collectOmpObjectListSymbol(privateClause->v, privatizedSymbols);
9896
} else if (const auto &firstPrivateClause =
99-
std::get_if<Fortran::parser::OmpClause::Firstprivate>(
100-
&clause.u)) {
97+
std::get_if<omp::clause::Firstprivate>(&clause.u)) {
10198
collectOmpObjectListSymbol(firstPrivateClause->v, privatizedSymbols);
10299
} else if (const auto &lastPrivateClause =
103-
std::get_if<Fortran::parser::OmpClause::Lastprivate>(
104-
&clause.u)) {
100+
std::get_if<omp::clause::Lastprivate>(&clause.u)) {
105101
collectOmpObjectListSymbol(lastPrivateClause->v, privatizedSymbols);
106102
hasLastPrivateOp = true;
107-
} else if (std::get_if<Fortran::parser::OmpClause::Collapse>(&clause.u)) {
103+
} else if (std::get_if<omp::clause::Collapse>(&clause.u)) {
108104
hasCollapse = true;
109105
}
110106
}
@@ -137,138 +133,135 @@ void DataSharingProcessor::insertBarrier() {
137133
void DataSharingProcessor::insertLastPrivateCompare(mlir::Operation *op) {
138134
bool cmpCreated = false;
139135
mlir::OpBuilder::InsertPoint localInsPt = firOpBuilder.saveInsertionPoint();
140-
for (const Fortran::parser::OmpClause &clause : opClauseList.v) {
141-
if (std::get_if<Fortran::parser::OmpClause::Lastprivate>(&clause.u)) {
142-
// TODO: Add lastprivate support for simd construct
143-
if (mlir::isa<mlir::omp::SectionOp>(op)) {
144-
if (&eval == &eval.parentConstruct->getLastNestedEvaluation()) {
145-
// For `omp.sections`, lastprivatized variables occur in
146-
// lexically final `omp.section` operation. The following FIR
147-
// shall be generated for the same:
148-
//
149-
// omp.sections lastprivate(...) {
150-
// omp.section {...}
151-
// omp.section {...}
152-
// omp.section {
153-
// fir.allocate for `private`/`firstprivate`
154-
// <More operations here>
155-
// fir.if %true {
156-
// ^%lpv_update_blk
157-
// }
158-
// }
159-
// }
160-
//
161-
// To keep code consistency while handling privatization
162-
// through this control flow, add a `fir.if` operation
163-
// that always evaluates to true, in order to create
164-
// a dedicated sub-region in `omp.section` where
165-
// lastprivate FIR can reside. Later canonicalizations
166-
// will optimize away this operation.
167-
if (!eval.lowerAsUnstructured()) {
168-
auto ifOp = firOpBuilder.create<fir::IfOp>(
169-
op->getLoc(),
170-
firOpBuilder.createIntegerConstant(
171-
op->getLoc(), firOpBuilder.getIntegerType(1), 0x1),
172-
/*else*/ false);
173-
firOpBuilder.setInsertionPointToStart(
174-
&ifOp.getThenRegion().front());
175-
176-
const Fortran::parser::OpenMPConstruct *parentOmpConstruct =
177-
eval.parentConstruct->getIf<Fortran::parser::OpenMPConstruct>();
178-
assert(parentOmpConstruct &&
179-
"Expected a valid enclosing OpenMP construct");
180-
const Fortran::parser::OpenMPSectionsConstruct *sectionsConstruct =
181-
std::get_if<Fortran::parser::OpenMPSectionsConstruct>(
182-
&parentOmpConstruct->u);
183-
assert(sectionsConstruct &&
184-
"Expected an enclosing omp.sections construct");
185-
const Fortran::parser::OmpClauseList &sectionsEndClauseList =
186-
std::get<Fortran::parser::OmpClauseList>(
187-
std::get<Fortran::parser::OmpEndSectionsDirective>(
188-
sectionsConstruct->t)
189-
.t);
190-
for (const Fortran::parser::OmpClause &otherClause :
191-
sectionsEndClauseList.v)
192-
if (std::get_if<Fortran::parser::OmpClause::Nowait>(
193-
&otherClause.u))
194-
// Emit implicit barrier to synchronize threads and avoid data
195-
// races on post-update of lastprivate variables when `nowait`
196-
// clause is present.
197-
firOpBuilder.create<mlir::omp::BarrierOp>(
198-
converter.getCurrentLocation());
199-
firOpBuilder.setInsertionPointToStart(
200-
&ifOp.getThenRegion().front());
201-
lastPrivIP = firOpBuilder.saveInsertionPoint();
202-
firOpBuilder.setInsertionPoint(ifOp);
203-
insPt = firOpBuilder.saveInsertionPoint();
204-
} else {
205-
// Lastprivate operation is inserted at the end
206-
// of the lexically last section in the sections
207-
// construct
208-
mlir::OpBuilder::InsertPoint unstructuredSectionsIP =
209-
firOpBuilder.saveInsertionPoint();
210-
mlir::Operation *lastOper = op->getRegion(0).back().getTerminator();
211-
firOpBuilder.setInsertionPoint(lastOper);
212-
lastPrivIP = firOpBuilder.saveInsertionPoint();
213-
firOpBuilder.restoreInsertionPoint(unstructuredSectionsIP);
214-
}
215-
}
216-
} else if (mlir::isa<mlir::omp::WsLoopOp>(op)) {
217-
// Update the original variable just before exiting the worksharing
218-
// loop. Conversion as follows:
136+
for (const omp::Clause &clause : clauses) {
137+
if (clause.id != llvm::omp::OMPC_lastprivate)
138+
continue;
139+
// TODO: Add lastprivate support for simd construct
140+
if (mlir::isa<mlir::omp::SectionOp>(op)) {
141+
if (&eval == &eval.parentConstruct->getLastNestedEvaluation()) {
142+
// For `omp.sections`, lastprivatized variables occur in
143+
// lexically final `omp.section` operation. The following FIR
144+
// shall be generated for the same:
219145
//
220-
// omp.wsloop {
221-
// omp.wsloop { ...
222-
// ... store
223-
// store ===> %v = arith.addi %iv, %step
224-
// omp.yield %cmp = %step < 0 ? %v < %ub : %v > %ub
225-
// } fir.if %cmp {
226-
// fir.store %v to %loopIV
227-
// ^%lpv_update_blk:
228-
// }
229-
// omp.yield
230-
// }
146+
// omp.sections lastprivate(...) {
147+
// omp.section {...}
148+
// omp.section {...}
149+
// omp.section {
150+
// fir.allocate for `private`/`firstprivate`
151+
// <More operations here>
152+
// fir.if %true {
153+
// ^%lpv_update_blk
154+
// }
155+
// }
156+
// }
231157
//
232-
233-
// Only generate the compare once in presence of multiple LastPrivate
234-
// clauses.
235-
if (cmpCreated)
236-
continue;
237-
cmpCreated = true;
238-
239-
mlir::Location loc = op->getLoc();
240-
mlir::Operation *lastOper = op->getRegion(0).back().getTerminator();
241-
firOpBuilder.setInsertionPoint(lastOper);
242-
243-
mlir::Value iv = op->getRegion(0).front().getArguments()[0];
244-
mlir::Value ub =
245-
mlir::dyn_cast<mlir::omp::WsLoopOp>(op).getUpperBound()[0];
246-
mlir::Value step = mlir::dyn_cast<mlir::omp::WsLoopOp>(op).getStep()[0];
247-
248-
// v = iv + step
249-
// cmp = step < 0 ? v < ub : v > ub
250-
mlir::Value v = firOpBuilder.create<mlir::arith::AddIOp>(loc, iv, step);
251-
mlir::Value zero =
252-
firOpBuilder.createIntegerConstant(loc, step.getType(), 0);
253-
mlir::Value negativeStep = firOpBuilder.create<mlir::arith::CmpIOp>(
254-
loc, mlir::arith::CmpIPredicate::slt, step, zero);
255-
mlir::Value vLT = firOpBuilder.create<mlir::arith::CmpIOp>(
256-
loc, mlir::arith::CmpIPredicate::slt, v, ub);
257-
mlir::Value vGT = firOpBuilder.create<mlir::arith::CmpIOp>(
258-
loc, mlir::arith::CmpIPredicate::sgt, v, ub);
259-
mlir::Value cmpOp = firOpBuilder.create<mlir::arith::SelectOp>(
260-
loc, negativeStep, vLT, vGT);
261-
262-
auto ifOp = firOpBuilder.create<fir::IfOp>(loc, cmpOp, /*else*/ false);
263-
firOpBuilder.setInsertionPointToStart(&ifOp.getThenRegion().front());
264-
assert(loopIV && "loopIV was not set");
265-
firOpBuilder.create<fir::StoreOp>(op->getLoc(), v, loopIV);
266-
lastPrivIP = firOpBuilder.saveInsertionPoint();
267-
} else {
268-
TODO(converter.getCurrentLocation(),
269-
"lastprivate clause in constructs other than "
270-
"simd/worksharing-loop");
158+
// To keep code consistency while handling privatization
159+
// through this control flow, add a `fir.if` operation
160+
// that always evaluates to true, in order to create
161+
// a dedicated sub-region in `omp.section` where
162+
// lastprivate FIR can reside. Later canonicalizations
163+
// will optimize away this operation.
164+
if (!eval.lowerAsUnstructured()) {
165+
auto ifOp = firOpBuilder.create<fir::IfOp>(
166+
op->getLoc(),
167+
firOpBuilder.createIntegerConstant(
168+
op->getLoc(), firOpBuilder.getIntegerType(1), 0x1),
169+
/*else*/ false);
170+
firOpBuilder.setInsertionPointToStart(&ifOp.getThenRegion().front());
171+
172+
const Fortran::parser::OpenMPConstruct *parentOmpConstruct =
173+
eval.parentConstruct->getIf<Fortran::parser::OpenMPConstruct>();
174+
assert(parentOmpConstruct &&
175+
"Expected a valid enclosing OpenMP construct");
176+
const Fortran::parser::OpenMPSectionsConstruct *sectionsConstruct =
177+
std::get_if<Fortran::parser::OpenMPSectionsConstruct>(
178+
&parentOmpConstruct->u);
179+
assert(sectionsConstruct &&
180+
"Expected an enclosing omp.sections construct");
181+
const Fortran::parser::OmpClauseList &sectionsEndClauseList =
182+
std::get<Fortran::parser::OmpClauseList>(
183+
std::get<Fortran::parser::OmpEndSectionsDirective>(
184+
sectionsConstruct->t)
185+
.t);
186+
for (const Fortran::parser::OmpClause &otherClause :
187+
sectionsEndClauseList.v)
188+
if (std::get_if<Fortran::parser::OmpClause::Nowait>(&otherClause.u))
189+
// Emit implicit barrier to synchronize threads and avoid data
190+
// races on post-update of lastprivate variables when `nowait`
191+
// clause is present.
192+
firOpBuilder.create<mlir::omp::BarrierOp>(
193+
converter.getCurrentLocation());
194+
firOpBuilder.setInsertionPointToStart(&ifOp.getThenRegion().front());
195+
lastPrivIP = firOpBuilder.saveInsertionPoint();
196+
firOpBuilder.setInsertionPoint(ifOp);
197+
insPt = firOpBuilder.saveInsertionPoint();
198+
} else {
199+
// Lastprivate operation is inserted at the end
200+
// of the lexically last section in the sections
201+
// construct
202+
mlir::OpBuilder::InsertPoint unstructuredSectionsIP =
203+
firOpBuilder.saveInsertionPoint();
204+
mlir::Operation *lastOper = op->getRegion(0).back().getTerminator();
205+
firOpBuilder.setInsertionPoint(lastOper);
206+
lastPrivIP = firOpBuilder.saveInsertionPoint();
207+
firOpBuilder.restoreInsertionPoint(unstructuredSectionsIP);
208+
}
271209
}
210+
} else if (mlir::isa<mlir::omp::WsLoopOp>(op)) {
211+
// Update the original variable just before exiting the worksharing
212+
// loop. Conversion as follows:
213+
//
214+
// omp.wsloop {
215+
// omp.wsloop { ...
216+
// ... store
217+
// store ===> %v = arith.addi %iv, %step
218+
// omp.yield %cmp = %step < 0 ? %v < %ub : %v > %ub
219+
// } fir.if %cmp {
220+
// fir.store %v to %loopIV
221+
// ^%lpv_update_blk:
222+
// }
223+
// omp.yield
224+
// }
225+
//
226+
227+
// Only generate the compare once in presence of multiple LastPrivate
228+
// clauses.
229+
if (cmpCreated)
230+
continue;
231+
cmpCreated = true;
232+
233+
mlir::Location loc = op->getLoc();
234+
mlir::Operation *lastOper = op->getRegion(0).back().getTerminator();
235+
firOpBuilder.setInsertionPoint(lastOper);
236+
237+
mlir::Value iv = op->getRegion(0).front().getArguments()[0];
238+
mlir::Value ub =
239+
mlir::dyn_cast<mlir::omp::WsLoopOp>(op).getUpperBound()[0];
240+
mlir::Value step = mlir::dyn_cast<mlir::omp::WsLoopOp>(op).getStep()[0];
241+
242+
// v = iv + step
243+
// cmp = step < 0 ? v < ub : v > ub
244+
mlir::Value v = firOpBuilder.create<mlir::arith::AddIOp>(loc, iv, step);
245+
mlir::Value zero =
246+
firOpBuilder.createIntegerConstant(loc, step.getType(), 0);
247+
mlir::Value negativeStep = firOpBuilder.create<mlir::arith::CmpIOp>(
248+
loc, mlir::arith::CmpIPredicate::slt, step, zero);
249+
mlir::Value vLT = firOpBuilder.create<mlir::arith::CmpIOp>(
250+
loc, mlir::arith::CmpIPredicate::slt, v, ub);
251+
mlir::Value vGT = firOpBuilder.create<mlir::arith::CmpIOp>(
252+
loc, mlir::arith::CmpIPredicate::sgt, v, ub);
253+
mlir::Value cmpOp = firOpBuilder.create<mlir::arith::SelectOp>(
254+
loc, negativeStep, vLT, vGT);
255+
256+
auto ifOp = firOpBuilder.create<fir::IfOp>(loc, cmpOp, /*else*/ false);
257+
firOpBuilder.setInsertionPointToStart(&ifOp.getThenRegion().front());
258+
assert(loopIV && "loopIV was not set");
259+
firOpBuilder.create<fir::StoreOp>(op->getLoc(), v, loopIV);
260+
lastPrivIP = firOpBuilder.saveInsertionPoint();
261+
} else {
262+
TODO(converter.getCurrentLocation(),
263+
"lastprivate clause in constructs other than "
264+
"simd/worksharing-loop");
272265
}
273266
}
274267
firOpBuilder.restoreInsertionPoint(localInsPt);
@@ -292,14 +285,12 @@ void DataSharingProcessor::collectSymbols(
292285
}
293286

294287
void DataSharingProcessor::collectDefaultSymbols() {
295-
for (const Fortran::parser::OmpClause &clause : opClauseList.v) {
296-
if (const auto &defaultClause =
297-
std::get_if<Fortran::parser::OmpClause::Default>(&clause.u)) {
298-
if (defaultClause->v.v ==
299-
Fortran::parser::OmpDefaultClause::Type::Private)
288+
for (const omp::Clause &clause : clauses) {
289+
if (const auto *defaultClause =
290+
std::get_if<omp::clause::Default>(&clause.u)) {
291+
if (defaultClause->v == omp::clause::Default::Type::Private)
300292
collectSymbols(Fortran::semantics::Symbol::Flag::OmpPrivate);
301-
else if (defaultClause->v.v ==
302-
Fortran::parser::OmpDefaultClause::Type::Firstprivate)
293+
else if (defaultClause->v == omp::clause::Default::Type::Firstprivate)
303294
collectSymbols(Fortran::semantics::Symbol::Flag::OmpFirstPrivate);
304295
}
305296
}

flang/lib/Lower/OpenMP/DataSharingProcessor.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#ifndef FORTRAN_LOWER_DATASHARINGPROCESSOR_H
1313
#define FORTRAN_LOWER_DATASHARINGPROCESSOR_H
1414

15+
#include "Clauses.h"
1516
#include "flang/Lower/AbstractConverter.h"
1617
#include "flang/Lower/OpenMP.h"
1718
#include "flang/Optimizer/Builder/FIRBuilder.h"
@@ -52,7 +53,7 @@ class DataSharingProcessor {
5253
llvm::SetVector<const Fortran::semantics::Symbol *> symbolsInParentRegions;
5354
Fortran::lower::AbstractConverter &converter;
5455
fir::FirOpBuilder &firOpBuilder;
55-
const Fortran::parser::OmpClauseList &opClauseList;
56+
omp::List<omp::Clause> clauses;
5657
Fortran::lower::pft::Evaluation &eval;
5758
bool useDelayedPrivatization;
5859
Fortran::lower::SymMap *symTable;
@@ -61,7 +62,7 @@ class DataSharingProcessor {
6162
bool needBarrier();
6263
void collectSymbols(Fortran::semantics::Symbol::Flag flag);
6364
void collectOmpObjectListSymbol(
64-
const Fortran::parser::OmpObjectList &ompObjectList,
65+
const omp::ObjectList &objects,
6566
llvm::SetVector<const Fortran::semantics::Symbol *> &symbolSet);
6667
void collectSymbolsForPrivatization();
6768
void insertBarrier();
@@ -81,14 +82,15 @@ class DataSharingProcessor {
8182

8283
public:
8384
DataSharingProcessor(Fortran::lower::AbstractConverter &converter,
85+
Fortran::semantics::SemanticsContext &semaCtx,
8486
const Fortran::parser::OmpClauseList &opClauseList,
8587
Fortran::lower::pft::Evaluation &eval,
8688
bool useDelayedPrivatization = false,
8789
Fortran::lower::SymMap *symTable = nullptr)
8890
: hasLastPrivateOp(false), converter(converter),
89-
firOpBuilder(converter.getFirOpBuilder()), opClauseList(opClauseList),
90-
eval(eval), useDelayedPrivatization(useDelayedPrivatization),
91-
symTable(symTable) {}
91+
firOpBuilder(converter.getFirOpBuilder()),
92+
clauses(omp::makeList(opClauseList, semaCtx)), eval(eval),
93+
useDelayedPrivatization(useDelayedPrivatization), symTable(symTable) {}
9294

9395
// Privatisation is split into two steps.
9496
// Step1 performs cloning of all privatisation clauses and copying for

0 commit comments

Comments
 (0)