@@ -143,15 +143,17 @@ static void genNestedEvaluations(Fortran::lower::AbstractConverter &converter,
143
143
// ===----------------------------------------------------------------------===//
144
144
145
145
class DataSharingProcessor {
146
+ using SymbolSet = llvm::SetVector<const Fortran::semantics::Symbol *>;
147
+
146
148
bool hasLastPrivateOp;
147
149
mlir::OpBuilder::InsertPoint lastPrivIP;
148
150
mlir::OpBuilder::InsertPoint insPt;
149
151
mlir::Value loopIV;
150
152
// Symbols in private, firstprivate, and/or lastprivate clauses.
151
- llvm::SetVector< const Fortran::semantics::Symbol *> privatizedSymbols;
152
- llvm::SetVector< const Fortran::semantics::Symbol *> defaultSymbols;
153
- llvm::SetVector< const Fortran::semantics::Symbol *> symbolsInNestedRegions;
154
- llvm::SetVector< const Fortran::semantics::Symbol *> symbolsInParentRegions;
153
+ SymbolSet privatizedSymbols;
154
+ SymbolSet defaultSymbols;
155
+ SymbolSet symbolsInNestedRegions;
156
+ SymbolSet symbolsInParentRegions;
155
157
Fortran::lower::AbstractConverter &converter;
156
158
fir::FirOpBuilder &firOpBuilder;
157
159
const Fortran::parser::OmpClauseList &opClauseList;
@@ -182,35 +184,54 @@ class DataSharingProcessor {
182
184
: hasLastPrivateOp(false ), converter(converter),
183
185
firOpBuilder (converter.getFirOpBuilder()), opClauseList(opClauseList),
184
186
eval(eval) {}
185
- // Privatisation is split into two steps.
186
- // Step1 performs cloning of all privatisation clauses and copying for
187
- // firstprivates. Step1 is performed at the place where process/processStep1
187
+ // Privatisation is split into 3 steps:
188
+ //
189
+ // * Step1: collects all symbols that should be privatized.
190
+ //
191
+ // * Step2: performs cloning of all privatisation clauses and copying for
192
+ // firstprivates. Step2 is performed at the place where process/processStep2
188
193
// is called. This is usually inside the Operation corresponding to the OpenMP
189
- // construct, for looping constructs this is just before the Operation. The
190
- // split into two steps was performed basically to be able to call
191
- // privatisation for looping constructs before the operation is created since
192
- // the bounds of the MLIR OpenMP operation can be privatised.
193
- // Step2 performs the copying for lastprivates and requires knowledge of the
194
- // MLIR operation to insert the last private update. Step2 adds
194
+ // construct, for looping constructs this is just before the Operation.
195
+ //
196
+ // * Step3: performs the copying for lastprivates and requires knowledge of
197
+ // the MLIR operation to insert the last private update. Step3 adds
195
198
// dealocation code as well.
199
+ //
200
+ // The split was performed for the following reasons:
201
+ //
202
+ // 1. Step1 was split so that the `target` op knows which symbols should not
203
+ // be mapped into the target region due to being `private`. The implicit
204
+ // mapping happens before the op body is generated so we need to to collect
205
+ // the private symbols first and then later in the body actually privatize
206
+ // them.
207
+ //
208
+ // 2. Step2 was split in order to call privatisation for looping constructs
209
+ // before the operation is created since the bounds of the MLIR OpenMP
210
+ // operation can be privatised.
196
211
void processStep1 ();
197
- void processStep2 (mlir::Operation *op, bool isLoop);
212
+ void processStep2 ();
213
+ void processStep3 (mlir::Operation *op, bool isLoop);
198
214
199
215
void setLoopIV (mlir::Value iv) {
200
216
assert (!loopIV && " Loop iteration variable already set" );
201
217
loopIV = iv;
202
218
}
219
+
220
+ const SymbolSet &getPrivatizedSymbols () const { return privatizedSymbols; }
203
221
};
204
222
205
223
void DataSharingProcessor::processStep1 () {
206
224
collectSymbolsForPrivatization ();
207
225
collectDefaultSymbols ();
226
+ }
227
+
228
+ void DataSharingProcessor::processStep2 () {
208
229
privatize ();
209
230
defaultPrivatize ();
210
231
insertBarrier ();
211
232
}
212
233
213
- void DataSharingProcessor::processStep2 (mlir::Operation *op, bool isLoop) {
234
+ void DataSharingProcessor::processStep3 (mlir::Operation *op, bool isLoop) {
214
235
insPt = firOpBuilder.saveInsertionPoint ();
215
236
copyLastPrivatize (op);
216
237
firOpBuilder.restoreInsertionPoint (insPt);
@@ -2306,11 +2327,12 @@ static void createBodyOfOp(
2306
2327
if (!dsp) {
2307
2328
DataSharingProcessor proc (converter, *clauses, eval);
2308
2329
proc.processStep1 ();
2309
- proc.processStep2 (op, isLoop);
2330
+ proc.processStep2 ();
2331
+ proc.processStep3 (op, isLoop);
2310
2332
} else {
2311
2333
if (isLoop && args.size () > 0 )
2312
2334
dsp->setLoopIV (converter.getSymbolAddress (*args[0 ]));
2313
- dsp->processStep2 (op, isLoop);
2335
+ dsp->processStep3 (op, isLoop);
2314
2336
}
2315
2337
2316
2338
if (storeOp)
@@ -2648,7 +2670,9 @@ static void genBodyOfTargetOp(
2648
2670
const llvm::SmallVector<mlir::Type> &mapSymTypes,
2649
2671
const llvm::SmallVector<mlir::Location> &mapSymLocs,
2650
2672
const llvm::SmallVector<const Fortran::semantics::Symbol *> &mapSymbols,
2651
- const mlir::Location ¤tLocation) {
2673
+ const mlir::Location ¤tLocation,
2674
+ const Fortran::parser::OmpClauseList &clauseList,
2675
+ DataSharingProcessor &dsp) {
2652
2676
assert (mapSymTypes.size () == mapSymLocs.size ());
2653
2677
2654
2678
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder ();
@@ -2657,6 +2681,8 @@ static void genBodyOfTargetOp(
2657
2681
auto *regionBlock =
2658
2682
firOpBuilder.createBlock (®ion, {}, mapSymTypes, mapSymLocs);
2659
2683
2684
+ dsp.processStep2 ();
2685
+
2660
2686
// Clones the `bounds` placing them inside the target region and returns them.
2661
2687
auto cloneBound = [&](mlir::Value bound) {
2662
2688
if (mlir::isMemoryEffectFree (bound.getDefiningOp ())) {
@@ -2811,8 +2837,7 @@ genTargetOp(Fortran::lower::AbstractConverter &converter,
2811
2837
cp.processNowait (nowaitAttr);
2812
2838
cp.processMap (currentLocation, directive, semanticsContext, stmtCtx,
2813
2839
mapOperands, &mapSymTypes, &mapSymLocs, &mapSymbols);
2814
- cp.processTODO <Fortran::parser::OmpClause::Private,
2815
- Fortran::parser::OmpClause::Depend,
2840
+ cp.processTODO <Fortran::parser::OmpClause::Depend,
2816
2841
Fortran::parser::OmpClause::Firstprivate,
2817
2842
Fortran::parser::OmpClause::IsDevicePtr,
2818
2843
Fortran::parser::OmpClause::HasDeviceAddr,
@@ -2823,11 +2848,19 @@ genTargetOp(Fortran::lower::AbstractConverter &converter,
2823
2848
Fortran::parser::OmpClause::Defaultmap>(
2824
2849
currentLocation, llvm::omp::Directive::OMPD_target);
2825
2850
2851
+ DataSharingProcessor dsp (converter, clauseList, eval);
2852
+ dsp.processStep1 ();
2853
+
2826
2854
// 5.8.1 Implicit Data-Mapping Attribute Rules
2827
2855
// The following code follows the implicit data-mapping rules to map all the
2828
- // symbols used inside the region that have not been explicitly mapped using
2829
- // the map clause.
2856
+ // symbols used inside the region that do not have explicit data-environment
2857
+ // attribute clauses (neither data-sharing; e.g. `private`, nor `map`
2858
+ // clauses).
2830
2859
auto captureImplicitMap = [&](const Fortran::semantics::Symbol &sym) {
2860
+ if (dsp.getPrivatizedSymbols ().contains (&sym)) {
2861
+ return ;
2862
+ }
2863
+
2831
2864
if (llvm::find (mapSymbols, &sym) == mapSymbols.end ()) {
2832
2865
mlir::Value baseOp = converter.getSymbolAddress (sym);
2833
2866
if (!baseOp)
@@ -2893,7 +2926,7 @@ genTargetOp(Fortran::lower::AbstractConverter &converter,
2893
2926
nowaitAttr, mapOperands);
2894
2927
2895
2928
genBodyOfTargetOp (converter, eval, genNested, targetOp, mapSymTypes,
2896
- mapSymLocs, mapSymbols, currentLocation);
2929
+ mapSymLocs, mapSymbols, currentLocation, clauseList, dsp );
2897
2930
2898
2931
return targetOp;
2899
2932
}
@@ -3127,6 +3160,7 @@ createSimdLoop(Fortran::lower::AbstractConverter &converter,
3127
3160
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder ();
3128
3161
DataSharingProcessor dsp (converter, loopOpClauseList, eval);
3129
3162
dsp.processStep1 ();
3163
+ dsp.processStep2 ();
3130
3164
3131
3165
Fortran::lower::StatementContext stmtCtx;
3132
3166
mlir::Value scheduleChunkClauseOperand, ifClauseOperand;
@@ -3179,6 +3213,7 @@ static void createWsLoop(Fortran::lower::AbstractConverter &converter,
3179
3213
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder ();
3180
3214
DataSharingProcessor dsp (converter, beginClauseList, eval);
3181
3215
dsp.processStep1 ();
3216
+ dsp.processStep2 ();
3182
3217
3183
3218
Fortran::lower::StatementContext stmtCtx;
3184
3219
mlir::Value scheduleChunkClauseOperand;
0 commit comments