Skip to content

Commit 9ca8c49

Browse files
committed
[WIP] Delayed privatization.
This is a PoC for delayed privatization in OpenMP. Instead of directly emitting privatization code in the frontend, we add a new op to outline the privatization logic for a symbol and call-like mapping that maps from the host symbol to a block argument in the OpenMP region. Example: ``` !$omp target private(x) !$end omp target ``` Would be code-generated by flang as: ``` func.func @foo() { omp.target x.privatizer %x -> %argx: !fir.ref<i32> { bb0(%argx: !fir.ref<i32>): // ... use %argx .... } } "omp.private"() <{function_type = (!fir.ref<i32>) -> !fir.ref<i32>, sym_name = "x.privatizer"}> ({ ^bb0(%arg0: !fir.ref<i32>): %0 = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFprivate_clause_allocatableEx"} %1 = fir.load %arg0 : !fir.ref<i32> fir.store %1 to %0 : !fir.ref<i32> omp.yield(%0 : !fir.ref<i32>) }) : () -> () ``` Later, we would inline the delayed privatizer function-like op in the OpenMP region to basically get the same code generated directly by the fronend at the moment. So far this PoC implements the following: - Adds the delayed privatization op: `omp.private`. - For simple symbols, emits the op. Still TODO: - Extend the `omp.target` op to somehow model the oulined privatization logic. - Inline the outlined privatizer before emitting LLVM IR. - Support more complex symbols like allocatables.
1 parent ce72f78 commit 9ca8c49

File tree

8 files changed

+206
-46
lines changed

8 files changed

+206
-46
lines changed

flang/include/flang/Lower/AbstractConverter.h

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "flang/Common/Fortran.h"
1717
#include "flang/Lower/LoweringOptions.h"
1818
#include "flang/Lower/PFTDefs.h"
19+
#include "flang/Lower/SymbolMap.h"
1920
#include "flang/Optimizer/Builder/BoxValue.h"
2021
#include "flang/Semantics/symbol.h"
2122
#include "mlir/IR/Builders.h"
@@ -92,7 +93,8 @@ class AbstractConverter {
9293

9394
/// Binds the symbol to an fir extended value. The symbol binding will be
9495
/// added or replaced at the inner-most level of the local symbol map.
95-
virtual void bindSymbol(SymbolRef sym, const fir::ExtendedValue &exval) = 0;
96+
virtual void bindSymbol(SymbolRef sym, const fir::ExtendedValue &exval,
97+
Fortran::lower::SymMap *symMap = nullptr) = 0;
9698

9799
/// Override lowering of expression with pre-lowered values.
98100
/// Associate mlir::Value to evaluate::Expr. All subsequent call to
@@ -111,14 +113,16 @@ class AbstractConverter {
111113
/// For a given symbol which is host-associated, create a clone using
112114
/// parameters from the host-associated symbol.
113115
virtual bool
114-
createHostAssociateVarClone(const Fortran::semantics::Symbol &sym) = 0;
116+
createHostAssociateVarClone(const Fortran::semantics::Symbol &sym,
117+
Fortran::lower::SymMap *symMap = nullptr) = 0;
115118

116119
virtual void
117120
createHostAssociateVarCloneDealloc(const Fortran::semantics::Symbol &sym) = 0;
118121

119-
virtual void copyHostAssociateVar(
120-
const Fortran::semantics::Symbol &sym,
121-
mlir::OpBuilder::InsertPoint *copyAssignIP = nullptr) = 0;
122+
virtual void
123+
copyHostAssociateVar(const Fortran::semantics::Symbol &sym,
124+
mlir::OpBuilder::InsertPoint *copyAssignIP = nullptr,
125+
Fortran::lower::SymMap *symMap = nullptr) = 0;
122126

123127
/// For a given symbol, check if it is present in the inner-most
124128
/// level of the symbol map.
@@ -295,6 +299,10 @@ class AbstractConverter {
295299
return loweringOptions;
296300
}
297301

302+
virtual Fortran::lower::SymbolBox
303+
lookupOneLevelUpSymbol(const Fortran::semantics::Symbol &sym,
304+
Fortran::lower::SymMap *symMap = nullptr) = 0;
305+
298306
private:
299307
/// Options controlling lowering behavior.
300308
const Fortran::lower::LoweringOptions &loweringOptions;

flang/include/flang/Lower/SymbolMap.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ struct SymbolBox : public fir::details::matcher<SymbolBox> {
101101
[](const fir::FortranVariableOpInterface &x) {
102102
return fir::FortranVariableOpInterface(x).getBase();
103103
},
104+
[](const fir::MutableBoxValue &x) {
105+
return x.getAddr();
106+
},
104107
[](const auto &x) { return x.getAddr(); });
105108
}
106109

flang/lib/Lower/Bridge.cpp

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -498,16 +498,18 @@ class FirConverter : public Fortran::lower::AbstractConverter {
498498
/// Add the symbol binding to the inner-most level of the symbol map and
499499
/// return true if it is not already present. Otherwise, return false.
500500
bool bindIfNewSymbol(Fortran::lower::SymbolRef sym,
501-
const fir::ExtendedValue &exval) {
502-
if (shallowLookupSymbol(sym))
501+
const fir::ExtendedValue &exval,
502+
Fortran::lower::SymMap *symMap = nullptr) {
503+
if (shallowLookupSymbol(sym, symMap))
503504
return false;
504-
bindSymbol(sym, exval);
505+
bindSymbol(sym, exval, symMap);
505506
return true;
506507
}
507508

508509
void bindSymbol(Fortran::lower::SymbolRef sym,
509-
const fir::ExtendedValue &exval) override final {
510-
addSymbol(sym, exval, /*forced=*/true);
510+
const fir::ExtendedValue &exval,
511+
Fortran::lower::SymMap *symMap = nullptr) override final {
512+
addSymbol(sym, exval, /*forced=*/true, symMap);
511513
}
512514

513515
void
@@ -610,14 +612,15 @@ class FirConverter : public Fortran::lower::AbstractConverter {
610612
}
611613

612614
bool createHostAssociateVarClone(
613-
const Fortran::semantics::Symbol &sym) override final {
615+
const Fortran::semantics::Symbol &sym,
616+
Fortran::lower::SymMap *symMap = nullptr) override final {
614617
mlir::Location loc = genLocation(sym.name());
615618
mlir::Type symType = genType(sym);
616619
const auto *details = sym.detailsIf<Fortran::semantics::HostAssocDetails>();
617620
assert(details && "No host-association found");
618621
const Fortran::semantics::Symbol &hsym = details->symbol();
619622
mlir::Type hSymType = genType(hsym);
620-
Fortran::lower::SymbolBox hsb = lookupSymbol(hsym);
623+
Fortran::lower::SymbolBox hsb = lookupSymbol(hsym, symMap);
621624

622625
auto allocate = [&](llvm::ArrayRef<mlir::Value> shape,
623626
llvm::ArrayRef<mlir::Value> typeParams) -> mlir::Value {
@@ -720,7 +723,7 @@ class FirConverter : public Fortran::lower::AbstractConverter {
720723
// Do nothing
721724
});
722725

723-
return bindIfNewSymbol(sym, exv);
726+
return bindIfNewSymbol(sym, exv, symMap);
724727
}
725728

726729
void createHostAssociateVarCloneDealloc(
@@ -745,16 +748,17 @@ class FirConverter : public Fortran::lower::AbstractConverter {
745748

746749
void copyHostAssociateVar(
747750
const Fortran::semantics::Symbol &sym,
748-
mlir::OpBuilder::InsertPoint *copyAssignIP = nullptr) override final {
751+
mlir::OpBuilder::InsertPoint *copyAssignIP = nullptr,
752+
Fortran::lower::SymMap *symMap = nullptr) override final {
749753
// 1) Fetch the original copy of the variable.
750754
assert(sym.has<Fortran::semantics::HostAssocDetails>() &&
751755
"No host-association found");
752756
const Fortran::semantics::Symbol &hsym = sym.GetUltimate();
753-
Fortran::lower::SymbolBox hsb = lookupOneLevelUpSymbol(hsym);
757+
Fortran::lower::SymbolBox hsb = lookupOneLevelUpSymbol(hsym, symMap);
754758
assert(hsb && "Host symbol box not found");
755759

756760
// 2) Fetch the copied one that will mask the original.
757-
Fortran::lower::SymbolBox sb = shallowLookupSymbol(sym);
761+
Fortran::lower::SymbolBox sb = shallowLookupSymbol(sym, symMap);
758762
assert(sb && "Host-associated symbol box not found");
759763
assert(hsb.getAddr() != sb.getAddr() &&
760764
"Host and associated symbol boxes are the same");
@@ -763,8 +767,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
763767
mlir::OpBuilder::InsertPoint insPt = builder->saveInsertionPoint();
764768
if (copyAssignIP && copyAssignIP->isSet())
765769
builder->restoreInsertionPoint(*copyAssignIP);
766-
else
770+
else {
767771
builder->setInsertionPointAfter(sb.getAddr().getDefiningOp());
772+
}
768773

769774
Fortran::lower::SymbolBox *lhs_sb, *rhs_sb;
770775
if (copyAssignIP && copyAssignIP->isSet() &&
@@ -1060,17 +1065,21 @@ class FirConverter : public Fortran::lower::AbstractConverter {
10601065

10611066
/// Find the symbol in the inner-most level of the local map or return null.
10621067
Fortran::lower::SymbolBox
1063-
shallowLookupSymbol(const Fortran::semantics::Symbol &sym) {
1064-
if (Fortran::lower::SymbolBox v = localSymbols.shallowLookupSymbol(sym))
1068+
shallowLookupSymbol(const Fortran::semantics::Symbol &sym,
1069+
Fortran::lower::SymMap *symMap = nullptr) {
1070+
auto &map = (symMap == nullptr ? localSymbols : *symMap);
1071+
if (Fortran::lower::SymbolBox v = map.shallowLookupSymbol(sym))
10651072
return v;
10661073
return {};
10671074
}
10681075

10691076
/// Find the symbol in one level up of symbol map such as for host-association
10701077
/// in OpenMP code or return null.
10711078
Fortran::lower::SymbolBox
1072-
lookupOneLevelUpSymbol(const Fortran::semantics::Symbol &sym) {
1073-
if (Fortran::lower::SymbolBox v = localSymbols.lookupOneLevelUpSymbol(sym))
1079+
lookupOneLevelUpSymbol(const Fortran::semantics::Symbol &sym,
1080+
Fortran::lower::SymMap *symMap = nullptr) override {
1081+
auto &map = (symMap == nullptr ? localSymbols : *symMap);
1082+
if (Fortran::lower::SymbolBox v = map.lookupOneLevelUpSymbol(sym))
10741083
return v;
10751084
return {};
10761085
}
@@ -1079,15 +1088,16 @@ class FirConverter : public Fortran::lower::AbstractConverter {
10791088
/// already in the map and \p forced is `false`, the map is not updated.
10801089
/// Instead the value `false` is returned.
10811090
bool addSymbol(const Fortran::semantics::SymbolRef sym,
1082-
fir::ExtendedValue val, bool forced = false) {
1083-
if (!forced && lookupSymbol(sym))
1091+
fir::ExtendedValue val, bool forced = false,
1092+
Fortran::lower::SymMap *symMap = nullptr) {
1093+
auto &map = (symMap == nullptr ? localSymbols : *symMap);
1094+
if (!forced && lookupSymbol(sym, &map))
10841095
return false;
10851096
if (lowerToHighLevelFIR()) {
1086-
Fortran::lower::genDeclareSymbol(*this, localSymbols, sym, val,
1087-
fir::FortranVariableFlagsEnum::None,
1088-
forced);
1097+
Fortran::lower::genDeclareSymbol(
1098+
*this, map, sym, val, fir::FortranVariableFlagsEnum::None, forced);
10891099
} else {
1090-
localSymbols.addSymbol(sym, val, forced);
1100+
map.addSymbol(sym, val, forced);
10911101
}
10921102
return true;
10931103
}

flang/lib/Lower/OpenMP.cpp

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -169,12 +169,15 @@ class DataSharingProcessor {
169169
void collectSymbolsForPrivatization();
170170
void insertBarrier();
171171
void collectDefaultSymbols();
172-
void privatize();
172+
void
173+
privatize(llvm::SetVector<mlir::omp::PrivateClauseOp> *privateInitializers);
173174
void defaultPrivatize();
174175
void copyLastPrivatize(mlir::Operation *op);
175176
void insertLastPrivateCompare(mlir::Operation *op);
176-
void cloneSymbol(const Fortran::semantics::Symbol *sym);
177-
void copyFirstPrivateSymbol(const Fortran::semantics::Symbol *sym);
177+
void cloneSymbol(const Fortran::semantics::Symbol *sym,
178+
Fortran::lower::SymMap *symMap = nullptr);
179+
void copyFirstPrivateSymbol(const Fortran::semantics::Symbol *sym,
180+
Fortran::lower::SymMap *symMap);
178181
void copyLastPrivateSymbol(const Fortran::semantics::Symbol *sym,
179182
mlir::OpBuilder::InsertPoint *lastPrivIP);
180183
void insertDeallocs();
@@ -197,7 +200,8 @@ class DataSharingProcessor {
197200
// Step2 performs the copying for lastprivates and requires knowledge of the
198201
// MLIR operation to insert the last private update. Step2 adds
199202
// dealocation code as well.
200-
void processStep1();
203+
void processStep1(llvm::SetVector<mlir::omp::PrivateClauseOp>
204+
*privateInitializers = nullptr);
201205
void processStep2(mlir::Operation *op, bool isLoop);
202206

203207
void setLoopIV(mlir::Value iv) {
@@ -206,10 +210,11 @@ class DataSharingProcessor {
206210
}
207211
};
208212

209-
void DataSharingProcessor::processStep1() {
213+
void DataSharingProcessor::processStep1(
214+
llvm::SetVector<mlir::omp::PrivateClauseOp> *privateInitializers) {
210215
collectSymbolsForPrivatization();
211216
collectDefaultSymbols();
212-
privatize();
217+
privatize(privateInitializers);
213218
defaultPrivatize();
214219
insertBarrier();
215220
}
@@ -239,20 +244,23 @@ void DataSharingProcessor::insertDeallocs() {
239244
}
240245
}
241246

242-
void DataSharingProcessor::cloneSymbol(const Fortran::semantics::Symbol *sym) {
247+
void DataSharingProcessor::cloneSymbol(const Fortran::semantics::Symbol *sym,
248+
Fortran::lower::SymMap *symMap) {
243249
// Privatization for symbols which are pre-determined (like loop index
244250
// variables) happen separately, for everything else privatize here.
245251
if (sym->test(Fortran::semantics::Symbol::Flag::OmpPreDetermined))
246252
return;
247-
bool success = converter.createHostAssociateVarClone(*sym);
253+
bool success = converter.createHostAssociateVarClone(*sym, symMap);
248254
(void)success;
249255
assert(success && "Privatization failed due to existing binding");
250256
}
251257

252258
void DataSharingProcessor::copyFirstPrivateSymbol(
253-
const Fortran::semantics::Symbol *sym) {
254-
if (sym->test(Fortran::semantics::Symbol::Flag::OmpFirstPrivate))
255-
converter.copyHostAssociateVar(*sym);
259+
const Fortran::semantics::Symbol *sym,
260+
Fortran::lower::SymMap *symMap = nullptr) {
261+
if (sym->test(Fortran::semantics::Symbol::Flag::OmpFirstPrivate)) {
262+
converter.copyHostAssociateVar(*sym, nullptr, symMap);
263+
}
256264
}
257265

258266
void DataSharingProcessor::copyLastPrivateSymbol(
@@ -487,15 +495,54 @@ void DataSharingProcessor::collectDefaultSymbols() {
487495
}
488496
}
489497

490-
void DataSharingProcessor::privatize() {
498+
void DataSharingProcessor::privatize(
499+
llvm::SetVector<mlir::omp::PrivateClauseOp> *privateInitializers) {
500+
491501
for (const Fortran::semantics::Symbol *sym : privatizedSymbols) {
502+
492503
if (const auto *commonDet =
493504
sym->detailsIf<Fortran::semantics::CommonBlockDetails>()) {
494505
for (const auto &mem : commonDet->objects()) {
495506
cloneSymbol(&*mem);
496507
copyFirstPrivateSymbol(&*mem);
497508
}
498509
} else {
510+
if (privateInitializers != nullptr) {
511+
auto ip = firOpBuilder.saveInsertionPoint();
512+
513+
auto moduleOp = firOpBuilder.getInsertionBlock()
514+
->getParentOp()
515+
->getParentOfType<mlir::ModuleOp>();
516+
517+
firOpBuilder.setInsertionPoint(&moduleOp.getBodyRegion().front(),
518+
moduleOp.getBodyRegion().front().end());
519+
520+
Fortran::lower::SymbolBox hsb = converter.lookupOneLevelUpSymbol(*sym);
521+
assert(hsb && "Host symbol box not found");
522+
523+
auto privatizerOp = firOpBuilder.create<mlir::omp::PrivateClauseOp>(
524+
hsb.getAddr().getLoc(), hsb.getAddr().getType(),
525+
sym->name().ToString());
526+
firOpBuilder.setInsertionPointToEnd(&privatizerOp.getBody().front());
527+
528+
Fortran::semantics::Symbol cp = *sym;
529+
Fortran::lower::SymMap privatizerSymbolMap;
530+
privatizerSymbolMap.addSymbol(cp, privatizerOp.getArgument(0));
531+
privatizerSymbolMap.pushScope();
532+
533+
cloneSymbol(&cp, &privatizerSymbolMap);
534+
copyFirstPrivateSymbol(&cp, &privatizerSymbolMap);
535+
536+
firOpBuilder.create<mlir::omp::YieldOp>(
537+
hsb.getAddr().getLoc(),
538+
privatizerSymbolMap.shallowLookupSymbol(cp).getAddr());
539+
540+
firOpBuilder.restoreInsertionPoint(ip);
541+
}
542+
543+
// TODO: This will eventually be an else to the `if` above it. For now, I
544+
// emit both the outlined privatizer AND directly emitted cloning and
545+
// copying ops while I am testing.
499546
cloneSymbol(sym);
500547
copyFirstPrivateSymbol(sym);
501548
}
@@ -2272,6 +2319,7 @@ static void createBodyOfOp(
22722319
llvm::SmallVector<mlir::Type> tiv(args.size(), loopVarType);
22732320
llvm::SmallVector<mlir::Location> locs(args.size(), loc);
22742321
firOpBuilder.createBlock(&op.getRegion(), {}, tiv, locs);
2322+
22752323
// The argument is not currently in memory, so make a temporary for the
22762324
// argument, and store it there, then bind that location to the argument.
22772325
mlir::Operation *storeOp = nullptr;
@@ -2291,10 +2339,11 @@ static void createBodyOfOp(
22912339

22922340
// If it is an unstructured region and is not the outer region of a combined
22932341
// construct, create empty blocks for all evaluations.
2294-
if (eval.lowerAsUnstructured() && !outerCombined)
2342+
if (eval.lowerAsUnstructured() && !outerCombined) {
22952343
Fortran::lower::createEmptyRegionBlocks<mlir::omp::TerminatorOp,
22962344
mlir::omp::YieldOp>(
22972345
firOpBuilder, eval.getNestedEvaluations());
2346+
}
22982347

22992348
// Start with privatization, so that the lowering of the nested
23002349
// code will use the right symbols.
@@ -2307,12 +2356,14 @@ static void createBodyOfOp(
23072356
if (privatize) {
23082357
if (!dsp) {
23092358
tempDsp.emplace(converter, *clauses, eval);
2310-
tempDsp->processStep1();
2359+
llvm::SetVector<mlir::omp::PrivateClauseOp> privateInitializers;
2360+
tempDsp->processStep1(&privateInitializers);
23112361
}
23122362
}
23132363

23142364
if constexpr (std::is_same_v<Op, mlir::omp::ParallelOp>) {
23152365
threadPrivatizeVars(converter, eval);
2366+
23162367
if (clauses) {
23172368
firOpBuilder.setInsertionPoint(marker);
23182369
ClauseProcessor(converter, *clauses).processCopyin();
@@ -2361,6 +2412,7 @@ static void createBodyOfOp(
23612412
if (exits.size() == 1)
23622413
return exits[0];
23632414
mlir::Block *exit = firOpBuilder.createBlock(&region);
2415+
23642416
for (mlir::Block *b : exits) {
23652417
firOpBuilder.setInsertionPointToEnd(b);
23662418
firOpBuilder.create<mlir::cf::BranchOp>(loc, exit);
@@ -2382,8 +2434,9 @@ static void createBodyOfOp(
23822434
assert(tempDsp.has_value());
23832435
tempDsp->processStep2(op, isLoop);
23842436
} else {
2385-
if (isLoop && args.size() > 0)
2437+
if (isLoop && args.size() > 0) {
23862438
dsp->setLoopIV(converter.getSymbolAddress(*args[0]));
2439+
}
23872440
dsp->processStep2(op, isLoop);
23882441
}
23892442
}

0 commit comments

Comments
 (0)