Skip to content

Commit 1f37a9f

Browse files
authored
[NFC][flang][OpenMP] Add utils for mapping or cloning region outsiders and mapping temporary values to target (llvm#2034)
Cherry-picks changes introduced by: - https://github.com/AMD-Lightning-Internal/llvm-project/pull/1994 - https://github.com/AMD-Lightning-Internal/llvm-project/pull/1995
2 parents 7a2d074 + dd29614 commit 1f37a9f

File tree

4 files changed

+131
-187
lines changed

4 files changed

+131
-187
lines changed

flang/include/flang/Support/OpenMP-utils.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ mlir::omp::MapInfoOp createMapInfoOp(mlir::OpBuilder &builder,
8383
uint64_t mapType, mlir::omp::VariableCaptureKind mapCaptureType,
8484
mlir::Type retTy, bool partialMap = false,
8585
mlir::FlatSymbolRefAttr mapperId = mlir::FlatSymbolRefAttr());
86+
87+
mlir::Value mapTemporaryValue(fir::FirOpBuilder &firOpBuilder,
88+
mlir::omp::TargetOp targetOp, mlir::Value val, llvm::StringRef name);
89+
90+
void cloneOrMapRegionOutsiders(
91+
fir::FirOpBuilder &firOpBuilder, mlir::omp::TargetOp targetOp);
8692
} // namespace Fortran::common::openmp
8793

8894
#endif // FORTRAN_SUPPORT_OPENMP_UTILS_H_

flang/lib/Lower/OpenMP/OpenMP.cpp

Lines changed: 2 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,9 +1333,7 @@ static void genBodyOfTargetOp(
13331333
ConstructQueue::const_iterator item, DataSharingProcessor &dsp) {
13341334
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
13351335
auto argIface = llvm::cast<mlir::omp::BlockArgOpenMPOpInterface>(*targetOp);
1336-
1337-
mlir::Region &region = targetOp.getRegion();
1338-
mlir::Block *entryBlock = genEntryBlock(firOpBuilder, args, region);
1336+
genEntryBlock(firOpBuilder, args, targetOp.getRegion());
13391337

13401338
if (!enableDelayedPrivatizationStaging)
13411339
dsp.processStep2();
@@ -1348,99 +1346,7 @@ static void genBodyOfTargetOp(
13481346
// If so, then either clone them as well if they are MemoryEffectFree, or else
13491347
// copy them to a new temporary and add them to the map and block_argument
13501348
// lists and replace their uses with the new temporary.
1351-
llvm::SetVector<mlir::Value> valuesDefinedAbove;
1352-
mlir::getUsedValuesDefinedAbove(region, valuesDefinedAbove);
1353-
while (!valuesDefinedAbove.empty()) {
1354-
for (mlir::Value val : valuesDefinedAbove) {
1355-
mlir::Operation *valOp = val.getDefiningOp();
1356-
assert(valOp != nullptr);
1357-
1358-
// NOTE: We skip BoxDimsOp's as the lesser of two evils is to map the
1359-
// indices separately, as the alternative is to eventually map the Box,
1360-
// which comes with a fairly large overhead comparatively. We could be
1361-
// more robust about this and check using a BackwardsSlice to see if we
1362-
// run the risk of mapping a box.
1363-
if (mlir::isMemoryEffectFree(valOp) &&
1364-
!mlir::isa<fir::BoxDimsOp>(valOp)) {
1365-
mlir::Operation *clonedOp = valOp->clone();
1366-
entryBlock->push_front(clonedOp);
1367-
1368-
auto replace = [entryBlock](mlir::OpOperand &use) {
1369-
return use.getOwner()->getBlock() == entryBlock;
1370-
};
1371-
1372-
valOp->getResults().replaceUsesWithIf(clonedOp->getResults(), replace);
1373-
valOp->replaceUsesWithIf(clonedOp, replace);
1374-
} else {
1375-
auto savedIP = firOpBuilder.getInsertionPoint();
1376-
firOpBuilder.setInsertionPointAfter(valOp);
1377-
auto copyVal =
1378-
firOpBuilder.createTemporary(val.getLoc(), val.getType());
1379-
firOpBuilder.createStoreWithConvert(copyVal.getLoc(), val, copyVal);
1380-
1381-
fir::factory::AddrAndBoundsInfo info =
1382-
fir::factory::getDataOperandBaseAddr(
1383-
firOpBuilder, val, /*isOptional=*/false, val.getLoc());
1384-
llvm::SmallVector<mlir::Value> bounds =
1385-
fir::factory::genImplicitBoundsOps<mlir::omp::MapBoundsOp,
1386-
mlir::omp::MapBoundsType>(
1387-
firOpBuilder, info,
1388-
hlfir::translateToExtendedValue(val.getLoc(), firOpBuilder,
1389-
hlfir::Entity{val})
1390-
.first,
1391-
/*dataExvIsAssumedSize=*/false, val.getLoc());
1392-
1393-
std::stringstream name;
1394-
firOpBuilder.setInsertionPoint(targetOp);
1395-
1396-
llvm::omp::OpenMPOffloadMappingFlags mapFlag =
1397-
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT;
1398-
mlir::omp::VariableCaptureKind captureKind =
1399-
mlir::omp::VariableCaptureKind::ByRef;
1400-
1401-
mlir::Type eleType = copyVal.getType();
1402-
if (auto refType =
1403-
mlir::dyn_cast<fir::ReferenceType>(copyVal.getType()))
1404-
eleType = refType.getElementType();
1405-
1406-
if (fir::isa_trivial(eleType) || fir::isa_char(eleType)) {
1407-
captureKind = mlir::omp::VariableCaptureKind::ByCopy;
1408-
} else if (!fir::isa_builtin_cptr_type(eleType)) {
1409-
mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO;
1410-
}
1411-
1412-
mlir::Value mapOp = Fortran::common::openmp::createMapInfoOp(
1413-
firOpBuilder, copyVal.getLoc(), copyVal,
1414-
/*varPtrPtr=*/mlir::Value{}, name.str(), bounds,
1415-
/*members=*/llvm::SmallVector<mlir::Value>{},
1416-
/*membersIndex=*/mlir::ArrayAttr{},
1417-
static_cast<
1418-
std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(
1419-
mapFlag),
1420-
captureKind, copyVal.getType());
1421-
1422-
// Get the index of the first non-map argument before modifying mapVars,
1423-
// then append an element to mapVars and an associated entry block
1424-
// argument at that index.
1425-
unsigned insertIndex =
1426-
argIface.getMapBlockArgsStart() + argIface.numMapBlockArgs();
1427-
targetOp.getMapVarsMutable().append(mapOp);
1428-
mlir::Value clonedValArg = region.insertArgument(
1429-
insertIndex, copyVal.getType(), copyVal.getLoc());
1430-
1431-
firOpBuilder.setInsertionPointToStart(entryBlock);
1432-
auto loadOp = firOpBuilder.create<fir::LoadOp>(clonedValArg.getLoc(),
1433-
clonedValArg);
1434-
val.replaceUsesWithIf(loadOp->getResult(0),
1435-
[entryBlock](mlir::OpOperand &use) {
1436-
return use.getOwner()->getBlock() == entryBlock;
1437-
});
1438-
firOpBuilder.setInsertionPoint(entryBlock, savedIP);
1439-
}
1440-
}
1441-
valuesDefinedAbove.clear();
1442-
mlir::getUsedValuesDefinedAbove(region, valuesDefinedAbove);
1443-
}
1349+
Fortran::common::openmp::cloneOrMapRegionOutsiders(firOpBuilder, targetOp);
14441350

14451351
// Insert dummy instruction to remember the insertion position. The
14461352
// marker will be deleted since there are not uses.

flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp

Lines changed: 11 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -39,90 +39,6 @@ namespace flangomp {
3939
#define DEBUG_TYPE "do-concurrent-conversion"
4040
#define DBGS() (llvm::dbgs() << "[" DEBUG_TYPE << "]: ")
4141

42-
namespace Fortran {
43-
namespace lower {
44-
namespace omp {
45-
namespace internal {
46-
mlir::Value mapTemporaryValue(fir::FirOpBuilder &builder,
47-
mlir::omp::TargetOp targetOp, mlir::Value val,
48-
llvm::StringRef name) {
49-
mlir::OpBuilder::InsertionGuard guard(builder);
50-
builder.setInsertionPointAfterValue(val);
51-
auto copyVal = builder.createTemporary(val.getLoc(), val.getType());
52-
builder.createStoreWithConvert(copyVal.getLoc(), val, copyVal);
53-
54-
llvm::SmallVector<mlir::Value> bounds;
55-
builder.setInsertionPoint(targetOp);
56-
mlir::Value mapOp = Fortran::common::openmp::createMapInfoOp(
57-
builder, copyVal.getLoc(), copyVal,
58-
/*varPtrPtr=*/mlir::Value{}, name.str(), bounds,
59-
/*members=*/llvm::SmallVector<mlir::Value>{},
60-
/*membersIndex=*/mlir::ArrayAttr{},
61-
static_cast<std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(
62-
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT),
63-
mlir::omp::VariableCaptureKind::ByCopy, copyVal.getType());
64-
65-
mlir::Region &targetRegion = targetOp.getRegion();
66-
67-
auto argIface = llvm::cast<mlir::omp::BlockArgOpenMPOpInterface>(*targetOp);
68-
unsigned insertIndex =
69-
argIface.getMapBlockArgsStart() + argIface.numMapBlockArgs();
70-
targetOp.getMapVarsMutable().append(mlir::ValueRange{mapOp});
71-
mlir::Value clonedValArg =
72-
targetRegion.insertArgument(insertIndex, mapOp.getType(), mapOp.getLoc());
73-
74-
mlir::Block *targetEntryBlock = &targetRegion.getBlocks().front();
75-
builder.setInsertionPointToStart(targetEntryBlock);
76-
auto loadOp =
77-
builder.create<fir::LoadOp>(clonedValArg.getLoc(), clonedValArg);
78-
return loadOp.getResult();
79-
}
80-
81-
/// Check if cloning the bounds introduced any dependency on the outer region.
82-
/// If so, then either clone them as well if they are MemoryEffectFree, or else
83-
/// copy them to a new temporary and add them to the map and block_argument
84-
/// lists and replace their uses with the new temporary.
85-
///
86-
/// TODO: similar to the above functions, this is copied from OpenMP lowering
87-
/// (in this case, from `genBodyOfTargetOp`). Once we move to a common lib for
88-
/// these utils this will move as well.
89-
void cloneOrMapRegionOutsiders(fir::FirOpBuilder &builder,
90-
mlir::omp::TargetOp targetOp) {
91-
mlir::Region &targetRegion = targetOp.getRegion();
92-
mlir::Block *targetEntryBlock = &targetRegion.getBlocks().front();
93-
llvm::SetVector<mlir::Value> valuesDefinedAbove;
94-
mlir::getUsedValuesDefinedAbove(targetRegion, valuesDefinedAbove);
95-
96-
while (!valuesDefinedAbove.empty()) {
97-
for (mlir::Value val : valuesDefinedAbove) {
98-
mlir::Operation *valOp = val.getDefiningOp();
99-
assert(valOp != nullptr);
100-
if (mlir::isMemoryEffectFree(valOp)) {
101-
mlir::Operation *clonedOp = valOp->clone();
102-
targetEntryBlock->push_front(clonedOp);
103-
assert(clonedOp->getNumResults() == 1);
104-
val.replaceUsesWithIf(
105-
clonedOp->getResult(0), [targetEntryBlock](mlir::OpOperand &use) {
106-
return use.getOwner()->getBlock() == targetEntryBlock;
107-
});
108-
} else {
109-
mlir::Value mappedTemp = mapTemporaryValue(builder, targetOp, val,
110-
/*name=*/llvm::StringRef{});
111-
val.replaceUsesWithIf(
112-
mappedTemp, [targetEntryBlock](mlir::OpOperand &use) {
113-
return use.getOwner()->getBlock() == targetEntryBlock;
114-
});
115-
}
116-
}
117-
valuesDefinedAbove.clear();
118-
mlir::getUsedValuesDefinedAbove(targetRegion, valuesDefinedAbove);
119-
}
120-
}
121-
} // namespace internal
122-
} // namespace omp
123-
} // namespace lower
124-
} // namespace Fortran
125-
12642
namespace {
12743
namespace looputils {
12844
/// Stores info needed about the induction/iteration variable for each `do
@@ -699,7 +615,12 @@ class DoConcurrentConversion
699615
mapper.lookup(loopNestClauseOps.loopSteps[i]);
700616
}
701617

702-
Fortran::lower::omp::internal::cloneOrMapRegionOutsiders(builder, targetOp);
618+
// Check if cloning the bounds introduced any dependency on the outer
619+
// region. If so, then either clone them as well if they are
620+
// MemoryEffectFree, or else copy them to a new temporary and add them to
621+
// the map and block_argument lists and replace their uses with the new
622+
// temporary.
623+
Fortran::common::openmp::cloneOrMapRegionOutsiders(builder, targetOp);
703624
rewriter.setInsertionPoint(
704625
rewriter.create<mlir::omp::TerminatorOp>(targetOp.getLoc()));
705626

@@ -732,11 +653,11 @@ class DoConcurrentConversion
732653
llvm::zip_equal(targetShapeCreationInfo.startIndices,
733654
targetShapeCreationInfo.extents)) {
734655
shapeShiftOperands.push_back(
735-
Fortran::lower::omp::internal::mapTemporaryValue(
656+
Fortran::common::openmp::mapTemporaryValue(
736657
builder, targetOp, startIndex,
737658
liveInName + ".start_idx.dim" + std::to_string(shapeIdx)));
738659
shapeShiftOperands.push_back(
739-
Fortran::lower::omp::internal::mapTemporaryValue(
660+
Fortran::common::openmp::mapTemporaryValue(
740661
builder, targetOp, extent,
741662
liveInName + ".extent.dim" + std::to_string(shapeIdx)));
742663
++shapeIdx;
@@ -751,10 +672,9 @@ class DoConcurrentConversion
751672
llvm::SmallVector<mlir::Value> shapeOperands;
752673
size_t shapeIdx = 0;
753674
for (auto extent : targetShapeCreationInfo.extents) {
754-
shapeOperands.push_back(
755-
Fortran::lower::omp::internal::mapTemporaryValue(
756-
builder, targetOp, extent,
757-
liveInName + ".extent.dim" + std::to_string(shapeIdx)));
675+
shapeOperands.push_back(Fortran::common::openmp::mapTemporaryValue(
676+
builder, targetOp, extent,
677+
liveInName + ".extent.dim" + std::to_string(shapeIdx)));
758678
++shapeIdx;
759679
}
760680

flang/lib/Support/OpenMP-utils.cpp

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,15 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "flang/Support/OpenMP-utils.h"
10+
#include "flang/Optimizer/Builder/DirectivesCommon.h"
11+
#include "flang/Optimizer/Builder/FIRBuilder.h"
12+
#include "flang/Optimizer/Builder/HLFIRTools.h"
1013

1114
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
1215
#include "mlir/IR/OpDefinition.h"
16+
#include "mlir/Transforms/RegionUtils.h"
17+
18+
#include "llvm/Frontend/OpenMP/OMPConstants.h"
1319

1420
namespace Fortran::common::openmp {
1521
mlir::Block *genEntryBlock(mlir::OpBuilder &builder, const EntryBlockArgs &args,
@@ -79,4 +85,110 @@ mlir::omp::MapInfoOp createMapInfoOp(mlir::OpBuilder &builder,
7985
builder.getStringAttr(name), builder.getBoolAttr(partialMap));
8086
return op;
8187
}
88+
89+
mlir::Value mapTemporaryValue(fir::FirOpBuilder &firOpBuilder,
90+
mlir::omp::TargetOp targetOp, mlir::Value val, llvm::StringRef name) {
91+
mlir::OpBuilder::InsertionGuard guard(firOpBuilder);
92+
93+
firOpBuilder.setInsertionPointAfterValue(val);
94+
auto copyVal = firOpBuilder.createTemporary(val.getLoc(), val.getType());
95+
firOpBuilder.createStoreWithConvert(copyVal.getLoc(), val, copyVal);
96+
97+
fir::factory::AddrAndBoundsInfo info = fir::factory::getDataOperandBaseAddr(
98+
firOpBuilder, val, /*isOptional=*/false, val.getLoc());
99+
llvm::SmallVector<mlir::Value> bounds =
100+
fir::factory::genImplicitBoundsOps<mlir::omp::MapBoundsOp,
101+
mlir::omp::MapBoundsType>(firOpBuilder, info,
102+
hlfir::translateToExtendedValue(
103+
val.getLoc(), firOpBuilder, hlfir::Entity{val})
104+
.first,
105+
/*dataExvIsAssumedSize=*/false, val.getLoc());
106+
107+
firOpBuilder.setInsertionPoint(targetOp);
108+
109+
llvm::omp::OpenMPOffloadMappingFlags mapFlag =
110+
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT;
111+
mlir::omp::VariableCaptureKind captureKind =
112+
mlir::omp::VariableCaptureKind::ByRef;
113+
114+
mlir::Type eleType = copyVal.getType();
115+
if (auto refType = mlir::dyn_cast<fir::ReferenceType>(copyVal.getType())) {
116+
eleType = refType.getElementType();
117+
}
118+
119+
if (fir::isa_trivial(eleType) || fir::isa_char(eleType)) {
120+
captureKind = mlir::omp::VariableCaptureKind::ByCopy;
121+
} else if (!fir::isa_builtin_cptr_type(eleType)) {
122+
mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO;
123+
}
124+
125+
mlir::Value mapOp = Fortran::common::openmp::createMapInfoOp(firOpBuilder,
126+
copyVal.getLoc(), copyVal,
127+
/*varPtrPtr=*/mlir::Value{}, name.str(), bounds,
128+
/*members=*/llvm::SmallVector<mlir::Value>{},
129+
/*membersIndex=*/mlir::ArrayAttr{},
130+
static_cast<std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(
131+
mapFlag),
132+
captureKind, copyVal.getType());
133+
134+
auto argIface = llvm::cast<mlir::omp::BlockArgOpenMPOpInterface>(*targetOp);
135+
mlir::Region &region = targetOp.getRegion();
136+
137+
// Get the index of the first non-map argument before modifying mapVars,
138+
// then append an element to mapVars and an associated entry block
139+
// argument at that index.
140+
unsigned insertIndex =
141+
argIface.getMapBlockArgsStart() + argIface.numMapBlockArgs();
142+
targetOp.getMapVarsMutable().append(mapOp);
143+
mlir::Value clonedValArg =
144+
region.insertArgument(insertIndex, copyVal.getType(), copyVal.getLoc());
145+
146+
mlir::Block *entryBlock = &region.getBlocks().front();
147+
firOpBuilder.setInsertionPointToStart(entryBlock);
148+
auto loadOp =
149+
firOpBuilder.create<fir::LoadOp>(clonedValArg.getLoc(), clonedValArg);
150+
return loadOp.getResult();
151+
}
152+
153+
void cloneOrMapRegionOutsiders(fir::FirOpBuilder &firOpBuilder,
154+
mlir::omp::TargetOp targetOp) {
155+
mlir::Region &region = targetOp.getRegion();
156+
mlir::Block *entryBlock = &region.getBlocks().front();
157+
158+
llvm::SetVector<mlir::Value> valuesDefinedAbove;
159+
mlir::getUsedValuesDefinedAbove(region, valuesDefinedAbove);
160+
while (!valuesDefinedAbove.empty()) {
161+
for (mlir::Value val : valuesDefinedAbove) {
162+
mlir::Operation *valOp = val.getDefiningOp();
163+
assert(valOp != nullptr);
164+
165+
// NOTE: We skip BoxDimsOp's as the lesser of two evils is to map the
166+
// indices separately, as the alternative is to eventually map the Box,
167+
// which comes with a fairly large overhead comparatively. We could be
168+
// more robust about this and check using a BackwardsSlice to see if we
169+
// run the risk of mapping a box.
170+
if (mlir::isMemoryEffectFree(valOp) &&
171+
!mlir::isa<fir::BoxDimsOp>(valOp)) {
172+
mlir::Operation *clonedOp = valOp->clone();
173+
entryBlock->push_front(clonedOp);
174+
175+
auto replace = [entryBlock](mlir::OpOperand &use) {
176+
return use.getOwner()->getBlock() == entryBlock;
177+
};
178+
179+
valOp->getResults().replaceUsesWithIf(clonedOp->getResults(), replace);
180+
valOp->replaceUsesWithIf(clonedOp, replace);
181+
} else {
182+
mlir::Value mappedTemp = Fortran::common::openmp::mapTemporaryValue(
183+
firOpBuilder, targetOp, val,
184+
/*name=*/{});
185+
val.replaceUsesWithIf(mappedTemp, [entryBlock](mlir::OpOperand &use) {
186+
return use.getOwner()->getBlock() == entryBlock;
187+
});
188+
}
189+
}
190+
valuesDefinedAbove.clear();
191+
mlir::getUsedValuesDefinedAbove(region, valuesDefinedAbove);
192+
}
193+
}
82194
} // namespace Fortran::common::openmp

0 commit comments

Comments
 (0)