@@ -29,18 +29,112 @@ class OMPEarlyOutliningPass
29
29
return std::string (parentName) + " _omp_outline_" + std::to_string (count);
30
30
}
31
31
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
+
32
115
mlir::func::FuncOp outlineTargetOp (mlir::OpBuilder &builder,
33
116
mlir::omp::TargetOp &targetOp,
34
117
mlir::func::FuncOp &parentFunc,
35
118
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.
36
124
// Collect inputs
37
125
llvm::SetVector<mlir::Value> inputs;
38
- for (auto operand : targetOp.getOperation ()->getOperands ())
39
- inputs.insert (operand);
40
-
41
126
mlir::Region &targetRegion = targetOp.getRegion ();
42
127
mlir::getUsedValuesDefinedAbove (targetRegion, inputs);
43
128
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
+
44
138
// Create new function and initialize
45
139
mlir::FunctionType funcType = builder.getFunctionType (
46
140
mlir::TypeRange (inputs.getArrayRef ()), mlir::TypeRange ());
@@ -51,7 +145,7 @@ class OMPEarlyOutliningPass
51
145
mlir::func::FuncOp::create (loc, funcName, funcType);
52
146
mlir::Block *entryBlock = newFunc.addEntryBlock ();
53
147
builder.setInsertionPointToStart (entryBlock);
54
- mlir::ValueRange newInputs = entryBlock->getArguments ();
148
+ mlir::Block::BlockArgListType newInputs = entryBlock->getArguments ();
55
149
56
150
// Set the declare target information, the outlined function
57
151
// is always a host function.
@@ -68,10 +162,47 @@ class OMPEarlyOutliningPass
68
162
newFunc.getOperation ()))
69
163
earlyOutlineOp.setParentName (parentName);
70
164
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.
72
167
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));
75
206
76
207
// Clone the target op into the new function
77
208
builder.clone (*(targetOp.getOperation ()), valueMap);
0 commit comments