Skip to content

Commit e33cd96

Browse files
authored
[flang][fir] Basic PFT to MLIR lowering for do concurrent locality specifiers (#138534)
Extends support for `fir.do_concurrent` locality specifiers to the PFT to MLIR level. This adds code-gen for generating the newly added `fir.local` ops and referencing these ops from `fir.do_concurrent.loop` ops that have locality specifiers attached to them. This reuses the `DataSharingProcessor` component and generalizes it a bit more to allow for handling `omp.private` ops and `fir.local` ops as well. PR stack: - #137928 - #138505 - #138506 - #138512 - #138534 (this PR) - #138816
1 parent 57f3151 commit e33cd96

File tree

7 files changed

+213
-40
lines changed

7 files changed

+213
-40
lines changed

flang/include/flang/Lower/AbstractConverter.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,10 @@ class AbstractConverter {
348348
virtual Fortran::lower::SymbolBox
349349
lookupOneLevelUpSymbol(const Fortran::semantics::Symbol &sym) = 0;
350350

351+
/// Find the symbol in the inner-most level of the local map or return null.
352+
virtual Fortran::lower::SymbolBox
353+
shallowLookupSymbol(const Fortran::semantics::Symbol &sym) = 0;
354+
351355
/// Return the mlir::SymbolTable associated to the ModuleOp.
352356
/// Look-ups are faster using it than using module.lookup<>,
353357
/// but the module op should be queried in case of failure

flang/include/flang/Optimizer/Dialect/FIROps.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ class CoordinateIndicesAdaptor {
147147
mlir::ValueRange values;
148148
};
149149

150+
struct LocalitySpecifierOperands {
151+
llvm::SmallVector<::mlir::Value> privateVars;
152+
llvm::SmallVector<::mlir::Attribute> privateSyms;
153+
};
150154
} // namespace fir
151155

152156
#endif // FORTRAN_OPTIMIZER_DIALECT_FIROPS_H

flang/include/flang/Optimizer/Dialect/FIROps.td

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3605,6 +3605,21 @@ def fir_LocalitySpecifierOp : fir_Op<"local", [IsolatedFromAbove]> {
36053605
];
36063606

36073607
let extraClassDeclaration = [{
3608+
mlir::BlockArgument getInitMoldArg() {
3609+
auto &region = getInitRegion();
3610+
return region.empty() ? nullptr : region.getArgument(0);
3611+
}
3612+
mlir::BlockArgument getInitPrivateArg() {
3613+
auto &region = getInitRegion();
3614+
return region.empty() ? nullptr : region.getArgument(1);
3615+
}
3616+
3617+
/// Returns true if the init region might read from the mold argument
3618+
bool initReadsFromMold() {
3619+
mlir::BlockArgument moldArg = getInitMoldArg();
3620+
return moldArg && !moldArg.use_empty();
3621+
}
3622+
36083623
/// Get the type for arguments to nested regions. This should
36093624
/// generally be either the same as getType() or some pointer
36103625
/// type (pointing to the type allocated by this op).

flang/lib/Lower/Bridge.cpp

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
#include "flang/Lower/Bridge.h"
1414

15+
#include "OpenMP/DataSharingProcessor.h"
16+
#include "OpenMP/Utils.h"
1517
#include "flang/Lower/Allocatable.h"
1618
#include "flang/Lower/CallInterface.h"
1719
#include "flang/Lower/Coarray.h"
@@ -1142,6 +1144,14 @@ class FirConverter : public Fortran::lower::AbstractConverter {
11421144
return name;
11431145
}
11441146

1147+
/// Find the symbol in the inner-most level of the local map or return null.
1148+
Fortran::lower::SymbolBox
1149+
shallowLookupSymbol(const Fortran::semantics::Symbol &sym) override {
1150+
if (Fortran::lower::SymbolBox v = localSymbols.shallowLookupSymbol(sym))
1151+
return v;
1152+
return {};
1153+
}
1154+
11451155
private:
11461156
FirConverter() = delete;
11471157
FirConverter(const FirConverter &) = delete;
@@ -1216,14 +1226,6 @@ class FirConverter : public Fortran::lower::AbstractConverter {
12161226
return {};
12171227
}
12181228

1219-
/// Find the symbol in the inner-most level of the local map or return null.
1220-
Fortran::lower::SymbolBox
1221-
shallowLookupSymbol(const Fortran::semantics::Symbol &sym) {
1222-
if (Fortran::lower::SymbolBox v = localSymbols.shallowLookupSymbol(sym))
1223-
return v;
1224-
return {};
1225-
}
1226-
12271229
/// Find the symbol in one level up of symbol map such as for host-association
12281230
/// in OpenMP code or return null.
12291231
Fortran::lower::SymbolBox
@@ -2027,9 +2029,34 @@ class FirConverter : public Fortran::lower::AbstractConverter {
20272029
void handleLocalitySpecs(const IncrementLoopInfo &info) {
20282030
Fortran::semantics::SemanticsContext &semanticsContext =
20292031
bridge.getSemanticsContext();
2030-
for (const Fortran::semantics::Symbol *sym : info.localSymList)
2032+
// TODO Extract `DataSharingProcessor` from omp to a more general location.
2033+
Fortran::lower::omp::DataSharingProcessor dsp(
2034+
*this, semanticsContext, getEval(),
2035+
/*useDelayedPrivatization=*/true, localSymbols);
2036+
fir::LocalitySpecifierOperands privateClauseOps;
2037+
auto doConcurrentLoopOp =
2038+
mlir::dyn_cast_if_present<fir::DoConcurrentLoopOp>(info.loopOp);
2039+
// TODO Promote to using `enableDelayedPrivatization` (which is enabled by
2040+
// default unlike the staging flag) once the implementation of this is more
2041+
// complete.
2042+
bool useDelayedPriv =
2043+
enableDelayedPrivatizationStaging && doConcurrentLoopOp;
2044+
2045+
for (const Fortran::semantics::Symbol *sym : info.localSymList) {
2046+
if (useDelayedPriv) {
2047+
dsp.privatizeSymbol<fir::LocalitySpecifierOp>(sym, &privateClauseOps);
2048+
continue;
2049+
}
2050+
20312051
createHostAssociateVarClone(*sym, /*skipDefaultInit=*/false);
2052+
}
2053+
20322054
for (const Fortran::semantics::Symbol *sym : info.localInitSymList) {
2055+
if (useDelayedPriv) {
2056+
dsp.privatizeSymbol<fir::LocalitySpecifierOp>(sym, &privateClauseOps);
2057+
continue;
2058+
}
2059+
20332060
createHostAssociateVarClone(*sym, /*skipDefaultInit=*/true);
20342061
const auto *hostDetails =
20352062
sym->detailsIf<Fortran::semantics::HostAssocDetails>();
@@ -2048,6 +2075,24 @@ class FirConverter : public Fortran::lower::AbstractConverter {
20482075
sym->detailsIf<Fortran::semantics::HostAssocDetails>();
20492076
copySymbolBinding(hostDetails->symbol(), *sym);
20502077
}
2078+
2079+
if (useDelayedPriv) {
2080+
doConcurrentLoopOp.getLocalVarsMutable().assign(
2081+
privateClauseOps.privateVars);
2082+
doConcurrentLoopOp.setLocalSymsAttr(
2083+
builder->getArrayAttr(privateClauseOps.privateSyms));
2084+
2085+
for (auto [sym, privateVar] : llvm::zip_equal(
2086+
dsp.getAllSymbolsToPrivatize(), privateClauseOps.privateVars)) {
2087+
auto arg = doConcurrentLoopOp.getRegion().begin()->addArgument(
2088+
privateVar.getType(), doConcurrentLoopOp.getLoc());
2089+
bindSymbol(*sym, hlfir::translateToExtendedValue(
2090+
privateVar.getLoc(), *builder, hlfir::Entity{arg},
2091+
/*contiguousHint=*/true)
2092+
.first);
2093+
}
2094+
}
2095+
20512096
// Note that allocatable, types with ultimate components, and type
20522097
// requiring finalization are forbidden in LOCAL/LOCAL_INIT (F2023 C1130),
20532098
// so no clean-up needs to be generated for these entities.

flang/lib/Lower/OpenMP/DataSharingProcessor.cpp

Lines changed: 77 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "flang/Optimizer/Builder/BoxValue.h"
2121
#include "flang/Optimizer/Builder/HLFIRTools.h"
2222
#include "flang/Optimizer/Builder/Todo.h"
23+
#include "flang/Optimizer/Dialect/FIROps.h"
2324
#include "flang/Optimizer/HLFIR/HLFIRDialect.h"
2425
#include "flang/Optimizer/HLFIR/HLFIROps.h"
2526
#include "flang/Semantics/attr.h"
@@ -53,6 +54,15 @@ DataSharingProcessor::DataSharingProcessor(
5354
});
5455
}
5556

57+
DataSharingProcessor::DataSharingProcessor(lower::AbstractConverter &converter,
58+
semantics::SemanticsContext &semaCtx,
59+
lower::pft::Evaluation &eval,
60+
bool useDelayedPrivatization,
61+
lower::SymMap &symTable)
62+
: DataSharingProcessor(converter, semaCtx, {}, eval,
63+
/*shouldCollectPreDeterminedSymols=*/false,
64+
useDelayedPrivatization, symTable) {}
65+
5666
void DataSharingProcessor::processStep1(
5767
mlir::omp::PrivateClauseOps *clauseOps) {
5868
collectSymbolsForPrivatization();
@@ -174,7 +184,8 @@ void DataSharingProcessor::cloneSymbol(const semantics::Symbol *sym) {
174184

175185
void DataSharingProcessor::copyFirstPrivateSymbol(
176186
const semantics::Symbol *sym, mlir::OpBuilder::InsertPoint *copyAssignIP) {
177-
if (sym->test(semantics::Symbol::Flag::OmpFirstPrivate))
187+
if (sym->test(semantics::Symbol::Flag::OmpFirstPrivate) ||
188+
sym->test(semantics::Symbol::Flag::LocalityLocalInit))
178189
converter.copyHostAssociateVar(*sym, copyAssignIP);
179190
}
180191

@@ -497,9 +508,9 @@ void DataSharingProcessor::privatize(mlir::omp::PrivateClauseOps *clauseOps) {
497508
if (const auto *commonDet =
498509
sym->detailsIf<semantics::CommonBlockDetails>()) {
499510
for (const auto &mem : commonDet->objects())
500-
doPrivatize(&*mem, clauseOps);
511+
privatizeSymbol(&*mem, clauseOps);
501512
} else
502-
doPrivatize(sym, clauseOps);
513+
privatizeSymbol(sym, clauseOps);
503514
}
504515
}
505516

@@ -516,22 +527,30 @@ void DataSharingProcessor::copyLastPrivatize(mlir::Operation *op) {
516527
}
517528
}
518529

519-
void DataSharingProcessor::doPrivatize(const semantics::Symbol *sym,
520-
mlir::omp::PrivateClauseOps *clauseOps) {
530+
template <typename OpType, typename OperandsStructType>
531+
void DataSharingProcessor::privatizeSymbol(
532+
const semantics::Symbol *symToPrivatize, OperandsStructType *clauseOps) {
521533
if (!useDelayedPrivatization) {
522-
cloneSymbol(sym);
523-
copyFirstPrivateSymbol(sym);
534+
cloneSymbol(symToPrivatize);
535+
copyFirstPrivateSymbol(symToPrivatize);
524536
return;
525537
}
526538

527-
lower::SymbolBox hsb = converter.lookupOneLevelUpSymbol(*sym);
539+
const semantics::Symbol *sym = symToPrivatize->HasLocalLocality()
540+
? &symToPrivatize->GetUltimate()
541+
: symToPrivatize;
542+
lower::SymbolBox hsb = symToPrivatize->HasLocalLocality()
543+
? converter.shallowLookupSymbol(*sym)
544+
: converter.lookupOneLevelUpSymbol(*sym);
528545
assert(hsb && "Host symbol box not found");
529546
hlfir::Entity entity{hsb.getAddr()};
530547
bool cannotHaveNonDefaultLowerBounds = !entity.mayHaveNonDefaultLowerBounds();
531548

532549
mlir::Location symLoc = hsb.getAddr().getLoc();
533550
std::string privatizerName = sym->name().ToString() + ".privatizer";
534-
bool isFirstPrivate = sym->test(semantics::Symbol::Flag::OmpFirstPrivate);
551+
bool isFirstPrivate =
552+
symToPrivatize->test(semantics::Symbol::Flag::OmpFirstPrivate) ||
553+
symToPrivatize->test(semantics::Symbol::Flag::LocalityLocalInit);
535554

536555
mlir::Value privVal = hsb.getAddr();
537556
mlir::Type allocType = privVal.getType();
@@ -565,24 +584,33 @@ void DataSharingProcessor::doPrivatize(const semantics::Symbol *sym,
565584

566585
mlir::Type argType = privVal.getType();
567586

568-
mlir::omp::PrivateClauseOp privatizerOp = [&]() {
587+
OpType privatizerOp = [&]() {
569588
auto moduleOp = firOpBuilder.getModule();
570589
auto uniquePrivatizerName = fir::getTypeAsString(
571590
allocType, converter.getKindMap(),
572591
converter.mangleName(*sym) +
573592
(isFirstPrivate ? "_firstprivate" : "_private"));
574593

575594
if (auto existingPrivatizer =
576-
moduleOp.lookupSymbol<mlir::omp::PrivateClauseOp>(
577-
uniquePrivatizerName))
595+
moduleOp.lookupSymbol<OpType>(uniquePrivatizerName))
578596
return existingPrivatizer;
579597

580598
mlir::OpBuilder::InsertionGuard guard(firOpBuilder);
581599
firOpBuilder.setInsertionPointToStart(moduleOp.getBody());
582-
auto result = firOpBuilder.create<mlir::omp::PrivateClauseOp>(
583-
symLoc, uniquePrivatizerName, allocType,
584-
isFirstPrivate ? mlir::omp::DataSharingClauseType::FirstPrivate
585-
: mlir::omp::DataSharingClauseType::Private);
600+
OpType result;
601+
602+
if constexpr (std::is_same_v<OpType, mlir::omp::PrivateClauseOp>) {
603+
result = firOpBuilder.create<OpType>(
604+
symLoc, uniquePrivatizerName, allocType,
605+
isFirstPrivate ? mlir::omp::DataSharingClauseType::FirstPrivate
606+
: mlir::omp::DataSharingClauseType::Private);
607+
} else {
608+
result = firOpBuilder.create<OpType>(
609+
symLoc, uniquePrivatizerName, allocType,
610+
isFirstPrivate ? fir::LocalitySpecifierType::LocalInit
611+
: fir::LocalitySpecifierType::Local);
612+
}
613+
586614
fir::ExtendedValue symExV = converter.getSymbolExtendedValue(*sym);
587615
lower::SymMapScope outerScope(symTable);
588616

@@ -625,27 +653,36 @@ void DataSharingProcessor::doPrivatize(const semantics::Symbol *sym,
625653
&copyRegion, /*insertPt=*/{}, {argType, argType}, {symLoc, symLoc});
626654
firOpBuilder.setInsertionPointToEnd(copyEntryBlock);
627655

628-
auto addSymbol = [&](unsigned argIdx, bool force = false) {
656+
auto addSymbol = [&](unsigned argIdx, const semantics::Symbol *symToMap,
657+
bool force = false) {
629658
symExV.match(
630659
[&](const fir::MutableBoxValue &box) {
631660
symTable.addSymbol(
632-
*sym, fir::substBase(box, copyRegion.getArgument(argIdx)),
633-
force);
661+
*symToMap,
662+
fir::substBase(box, copyRegion.getArgument(argIdx)), force);
634663
},
635664
[&](const auto &box) {
636-
symTable.addSymbol(*sym, copyRegion.getArgument(argIdx), force);
665+
symTable.addSymbol(*symToMap, copyRegion.getArgument(argIdx),
666+
force);
637667
});
638668
};
639669

640-
addSymbol(0, true);
670+
addSymbol(0, sym, true);
641671
lower::SymMapScope innerScope(symTable);
642-
addSymbol(1);
672+
addSymbol(1, symToPrivatize);
643673

644674
auto ip = firOpBuilder.saveInsertionPoint();
645-
copyFirstPrivateSymbol(sym, &ip);
646-
647-
firOpBuilder.create<mlir::omp::YieldOp>(
648-
hsb.getAddr().getLoc(), symTable.shallowLookupSymbol(*sym).getAddr());
675+
copyFirstPrivateSymbol(symToPrivatize, &ip);
676+
677+
if constexpr (std::is_same_v<OpType, mlir::omp::PrivateClauseOp>) {
678+
firOpBuilder.create<mlir::omp::YieldOp>(
679+
hsb.getAddr().getLoc(),
680+
symTable.shallowLookupSymbol(*symToPrivatize).getAddr());
681+
} else {
682+
firOpBuilder.create<fir::YieldOp>(
683+
hsb.getAddr().getLoc(),
684+
symTable.shallowLookupSymbol(*symToPrivatize).getAddr());
685+
}
649686
}
650687

651688
return result;
@@ -656,9 +693,22 @@ void DataSharingProcessor::doPrivatize(const semantics::Symbol *sym,
656693
clauseOps->privateVars.push_back(privVal);
657694
}
658695

659-
symToPrivatizer[sym] = privatizerOp;
696+
if (symToPrivatize->HasLocalLocality())
697+
allPrivatizedSymbols.insert(symToPrivatize);
660698
}
661699

700+
template void
701+
DataSharingProcessor::privatizeSymbol<mlir::omp::PrivateClauseOp,
702+
mlir::omp::PrivateClauseOps>(
703+
const semantics::Symbol *symToPrivatize,
704+
mlir::omp::PrivateClauseOps *clauseOps);
705+
706+
template void
707+
DataSharingProcessor::privatizeSymbol<fir::LocalitySpecifierOp,
708+
fir::LocalitySpecifierOperands>(
709+
const semantics::Symbol *symToPrivatize,
710+
fir::LocalitySpecifierOperands *clauseOps);
711+
662712
} // namespace omp
663713
} // namespace lower
664714
} // namespace Fortran

flang/lib/Lower/OpenMP/DataSharingProcessor.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,6 @@ class DataSharingProcessor {
7777
llvm::SetVector<const semantics::Symbol *> preDeterminedSymbols;
7878
llvm::SetVector<const semantics::Symbol *> allPrivatizedSymbols;
7979

80-
llvm::DenseMap<const semantics::Symbol *, mlir::omp::PrivateClauseOp>
81-
symToPrivatizer;
8280
lower::AbstractConverter &converter;
8381
semantics::SemanticsContext &semaCtx;
8482
fir::FirOpBuilder &firOpBuilder;
@@ -105,8 +103,6 @@ class DataSharingProcessor {
105103
void collectImplicitSymbols();
106104
void collectPreDeterminedSymbols();
107105
void privatize(mlir::omp::PrivateClauseOps *clauseOps);
108-
void doPrivatize(const semantics::Symbol *sym,
109-
mlir::omp::PrivateClauseOps *clauseOps);
110106
void copyLastPrivatize(mlir::Operation *op);
111107
void insertLastPrivateCompare(mlir::Operation *op);
112108
void cloneSymbol(const semantics::Symbol *sym);
@@ -125,6 +121,11 @@ class DataSharingProcessor {
125121
bool shouldCollectPreDeterminedSymbols,
126122
bool useDelayedPrivatization, lower::SymMap &symTable);
127123

124+
DataSharingProcessor(lower::AbstractConverter &converter,
125+
semantics::SemanticsContext &semaCtx,
126+
lower::pft::Evaluation &eval,
127+
bool useDelayedPrivatization, lower::SymMap &symTable);
128+
128129
// Privatisation is split into two steps.
129130
// Step1 performs cloning of all privatisation clauses and copying for
130131
// firstprivates. Step1 is performed at the place where process/processStep1
@@ -151,6 +152,11 @@ class DataSharingProcessor {
151152
? allPrivatizedSymbols.getArrayRef()
152153
: llvm::ArrayRef<const semantics::Symbol *>();
153154
}
155+
156+
template <typename OpType = mlir::omp::PrivateClauseOp,
157+
typename OperandsStructType = mlir::omp::PrivateClauseOps>
158+
void privatizeSymbol(const semantics::Symbol *symToPrivatize,
159+
OperandsStructType *clauseOps);
154160
};
155161

156162
} // namespace omp

0 commit comments

Comments
 (0)