Skip to content

Commit eaa0d28

Browse files
committed
[Flang][MLIR][OpenMP] Update OMPEarlyOutlining to support Bounds, MapEntry and declare target globals
This patch is a required change for the device side IR to maintain apporpiate links for declare target variables to their global variables for later lowering. It is also a requirement to clone over map bounds and entry operations to maintain the correct information for later lowering of the IR. It simply tries to clone over the relevant information maintaining the appropriate links they would have maintained prior to the pass, rather than redirecting them to new function arguments which causes a loss of information in the case of Declare Target and map information. Depends on D158734 reviewers: TIFitis, razvanlupusoru Differential Revision: https://reviews.llvm.org/D158735
1 parent 8fde6f4 commit eaa0d28

File tree

1 file changed

+138
-7
lines changed

1 file changed

+138
-7
lines changed

flang/lib/Optimizer/Transforms/OMPEarlyOutlining.cpp

Lines changed: 138 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,112 @@ class OMPEarlyOutliningPass
2929
return std::string(parentName) + "_omp_outline_" + std::to_string(count);
3030
}
3131

32+
// Given a value this function will iterate over an operators results
33+
// and return the relevant index for the result the value corresponds to.
34+
// There may be a simpler way to do this however.
35+
unsigned getResultIndex(mlir::Value value, mlir::Operation *op) {
36+
for (unsigned i = 0; i < op->getNumResults(); ++i) {
37+
if (op->getResult(i) == value)
38+
return i;
39+
}
40+
return 0;
41+
}
42+
43+
bool isDeclareTargetOp(mlir::Operation *op) {
44+
if (fir::AddrOfOp addressOfOp = mlir::dyn_cast<fir::AddrOfOp>(op))
45+
if (fir::GlobalOp gOp = mlir::dyn_cast<fir::GlobalOp>(
46+
addressOfOp->getParentOfType<mlir::ModuleOp>().lookupSymbol(
47+
addressOfOp.getSymbol())))
48+
if (auto declareTargetGlobal =
49+
llvm::dyn_cast<mlir::omp::DeclareTargetInterface>(
50+
gOp.getOperation()))
51+
if (declareTargetGlobal.isDeclareTarget())
52+
return true;
53+
return false;
54+
}
55+
56+
// Currently used for cloning arguments that are nested. Should be
57+
// extendable where required, perhaps via operation
58+
// specialisation/overloading, if something needs specialised handling.
59+
// NOTE: Results in duplication of some values that would otherwise be
60+
// a single SSA value shared between operations, this is tidied up on
61+
// lowering to some extent.
62+
mlir::Operation *
63+
cloneArgAndChildren(mlir::OpBuilder &builder, mlir::Operation *op,
64+
llvm::SetVector<mlir::Value> &inputs,
65+
mlir::Block::BlockArgListType &newInputs) {
66+
mlir::IRMapping valueMap;
67+
for (auto opValue : op->getOperands()) {
68+
if (opValue.getDefiningOp()) {
69+
auto resIdx = getResultIndex(opValue, opValue.getDefiningOp());
70+
valueMap.map(opValue,
71+
cloneArgAndChildren(builder, opValue.getDefiningOp(),
72+
inputs, newInputs)
73+
->getResult(resIdx));
74+
} else {
75+
for (auto inArg : llvm::zip(inputs, newInputs)) {
76+
if (opValue == std::get<0>(inArg))
77+
valueMap.map(opValue, std::get<1>(inArg));
78+
}
79+
}
80+
}
81+
82+
return builder.clone(*op, valueMap);
83+
}
84+
85+
void cloneMapOpVariables(mlir::OpBuilder &builder, mlir::IRMapping &valueMap,
86+
mlir::IRMapping &mapInfoMap,
87+
llvm::SetVector<mlir::Value> &inputs,
88+
mlir::Block::BlockArgListType &newInputs,
89+
mlir::Value varPtr) {
90+
if (fir::BoxAddrOp boxAddrOp =
91+
mlir::dyn_cast_if_present<fir::BoxAddrOp>(varPtr.getDefiningOp())) {
92+
mlir::Value newV =
93+
cloneArgAndChildren(builder, boxAddrOp, inputs, newInputs)
94+
->getResult(0);
95+
mapInfoMap.map(varPtr, newV);
96+
valueMap.map(boxAddrOp, newV);
97+
return;
98+
}
99+
100+
if (varPtr.getDefiningOp() && isDeclareTargetOp(varPtr.getDefiningOp())) {
101+
fir::AddrOfOp addrOp =
102+
mlir::dyn_cast<fir::AddrOfOp>(varPtr.getDefiningOp());
103+
mlir::Value newV = builder.clone(*addrOp)->getResult(0);
104+
mapInfoMap.map(varPtr, newV);
105+
valueMap.map(addrOp, newV);
106+
return;
107+
}
108+
109+
for (auto inArg : llvm::zip(inputs, newInputs)) {
110+
if (varPtr == std::get<0>(inArg))
111+
mapInfoMap.map(varPtr, std::get<1>(inArg));
112+
}
113+
}
114+
32115
mlir::func::FuncOp outlineTargetOp(mlir::OpBuilder &builder,
33116
mlir::omp::TargetOp &targetOp,
34117
mlir::func::FuncOp &parentFunc,
35118
unsigned count) {
119+
// NOTE: once implicit captures are handled appropriately in the initial
120+
// PFT lowering if it is possible, we can remove the usage of
121+
// getUsedValuesDefinedAbove and instead just iterate over the target op's
122+
// operands (or just the map arguments) and perhaps refactor this function
123+
// a little.
36124
// Collect inputs
37125
llvm::SetVector<mlir::Value> inputs;
38-
for (auto operand : targetOp.getOperation()->getOperands())
39-
inputs.insert(operand);
40-
41126
mlir::Region &targetRegion = targetOp.getRegion();
42127
mlir::getUsedValuesDefinedAbove(targetRegion, inputs);
43128

129+
// filter out declareTarget and map entries which are specially handled
130+
// at the moment, so we do not wish these to end up as function arguments
131+
// which would just be more noise in the IR.
132+
for (auto value : inputs)
133+
if (value.getDefiningOp())
134+
if (mlir::isa<mlir::omp::MapInfoOp>(value.getDefiningOp()) ||
135+
isDeclareTargetOp(value.getDefiningOp()))
136+
inputs.remove(value);
137+
44138
// Create new function and initialize
45139
mlir::FunctionType funcType = builder.getFunctionType(
46140
mlir::TypeRange(inputs.getArrayRef()), mlir::TypeRange());
@@ -51,7 +145,7 @@ class OMPEarlyOutliningPass
51145
mlir::func::FuncOp::create(loc, funcName, funcType);
52146
mlir::Block *entryBlock = newFunc.addEntryBlock();
53147
builder.setInsertionPointToStart(entryBlock);
54-
mlir::ValueRange newInputs = entryBlock->getArguments();
148+
mlir::Block::BlockArgListType newInputs = entryBlock->getArguments();
55149

56150
// Set the declare target information, the outlined function
57151
// is always a host function.
@@ -68,10 +162,47 @@ class OMPEarlyOutliningPass
68162
newFunc.getOperation()))
69163
earlyOutlineOp.setParentName(parentName);
70164

71-
// Create input map from inputs to function parameters.
165+
// The value map for the newly generated Target Operation, we must
166+
// remap most of the input.
72167
mlir::IRMapping valueMap;
73-
for (auto InArg : llvm::zip(inputs, newInputs))
74-
valueMap.map(std::get<0>(InArg), std::get<1>(InArg));
168+
169+
// Special handling for map, declare target and regular map variables
170+
// are handled slightly differently for the moment, declare target has
171+
// its addressOfOp cloned over, whereas we skip it for the regular map
172+
// variables. We need knowledge of which global is linked to the map
173+
// operation for declare target, whereas we aren't bothered for the
174+
// regular map variables for the moment. We could treat both the same,
175+
// however, cloning across the minimum for the moment to avoid
176+
// optimisations breaking segments of the lowering seems prudent as this
177+
// was the original intent of the pass.
178+
for (auto oper : targetOp.getOperation()->getOperands()) {
179+
if (auto mapEntry =
180+
mlir::dyn_cast<mlir::omp::MapInfoOp>(oper.getDefiningOp())) {
181+
mlir::IRMapping mapInfoMap;
182+
for (auto bound : mapEntry.getBounds()) {
183+
if (auto mapEntryBound = mlir::dyn_cast<mlir::omp::DataBoundsOp>(
184+
bound.getDefiningOp())) {
185+
mapInfoMap.map(bound, cloneArgAndChildren(builder, mapEntryBound,
186+
inputs, newInputs)
187+
->getResult(0));
188+
}
189+
}
190+
191+
cloneMapOpVariables(builder, valueMap, mapInfoMap, inputs, newInputs,
192+
mapEntry.getVarPtr());
193+
194+
if (mapEntry.getVarPtrPtr())
195+
cloneMapOpVariables(builder, valueMap, mapInfoMap, inputs, newInputs,
196+
mapEntry.getVarPtrPtr());
197+
198+
valueMap.map(
199+
mapEntry,
200+
builder.clone(*mapEntry.getOperation(), mapInfoMap)->getResult(0));
201+
}
202+
}
203+
204+
for (auto inArg : llvm::zip(inputs, newInputs))
205+
valueMap.map(std::get<0>(inArg), std::get<1>(inArg));
75206

76207
// Clone the target op into the new function
77208
builder.clone(*(targetOp.getOperation()), valueMap);

0 commit comments

Comments
 (0)