22#define GEN_PASS_DEF_HOSTOPFILTERINGPASS
23#include "mlir/Dialect/OpenMP/Transforms/Passes.h.inc"
49 for (
Value member : mapOp.getMembers())
50 collectRewrite(cast<omp::MapInfoOp>(member.getDefiningOp()), rewrites);
52 rewrites.insert(mapOp);
62 if ((isa<BlockArgument>(value) &&
63 isa<FunctionOpInterface>(
64 cast<BlockArgument>(value).getOwner()->getParentOp())) ||
65 rewrites.contains(value))
73 rewrites.insert(value);
78static std::optional<omp::DeclareTargetDeviceType>
80 auto declareTargetOp = dyn_cast<omp::DeclareTargetInterface>(op);
81 if (declareTargetOp && declareTargetOp.isDeclareTarget())
82 return declareTargetOp.getDeclareTargetDeviceType();
87class HostOpFilteringPass
88 :
public omp::impl::HostOpFilteringPassBase<HostOpFilteringPass> {
90 HostOpFilteringPass() =
default;
92 void runOnOperation()
override {
93 auto op = dyn_cast<omp::OffloadModuleInterface>(getOperation());
94 if (!op || !op.getIsTargetDevice())
97 op->walk<WalkOrder::PreOrder>([&](LLVM::LLVMFuncOp funcOp) {
98 omp::DeclareTargetDeviceType declareType =
100 .value_or(omp::DeclareTargetDeviceType::host);
103 if (funcOp.isExternal() ||
104 declareType != omp::DeclareTargetDeviceType::host)
107 if (
failed(rewriteHostFunction(funcOp))) {
108 funcOp.emitOpError() <<
"could not filter host-only operations";
118 op->walk([&](LLVM::GlobalOp globalOp) {
120 globalOp.setLinkage(LLVM::Linkage::Internal);
153 LogicalResult rewriteHostFunction(LLVM::LLVMFuncOp funcOp) {
154 Region ®ion = funcOp.getFunctionBody();
155 LLVM::LLVMFunctionType functionType = funcOp.getFunctionType();
158 llvm::SmallVector<omp::TargetOp> targetOps;
159 region.
walk<WalkOrder::PreOrder>([&](Operation *op) {
161 if (
auto targetOp = dyn_cast<omp::TargetOp>(op)) {
162 targetOps.push_back(targetOp);
170 if (
auto targetDataOp = dyn_cast<omp::TargetDataOp>(op)) {
171 llvm::SmallVector<std::pair<Value, BlockArgument>> argPairs;
172 cast<omp::BlockArgOpenMPOpInterface>(*targetDataOp)
173 .getBlockArgsPairs(argPairs);
174 for (
auto [operand, blockArg] : argPairs) {
175 auto mapInfo = cast<omp::MapInfoOp>(operand.getDefiningOp());
176 blockArg.replaceAllUsesWith(mapInfo.getVarPtr());
187 builder.setInsertionPointAfter(funcOp);
188 Operation *newFuncOp = builder.cloneWithoutRegions(funcOp);
191 llvm::SmallVector<Location> locs;
193 llvm::transform(region.
getArguments(), std::back_inserter(locs),
194 [](
const BlockArgument &arg) { return arg.getLoc(); });
197 for (
auto [oldArg, newArg] :
199 oldArg.replaceAllUsesWith(newArg);
205 llvm::SetVector<Value> rewriteValues;
206 llvm::SetVector<omp::MapInfoOp> mapInfos;
207 for (omp::TargetOp targetOp : targetOps) {
208 assert(targetOp.getHostEvalVars().empty() &&
209 "unexpected host_eval in target device module");
212 targetOp.getDependVarsMutable().clear();
213 targetOp.setDependKindsAttr(
nullptr);
214 targetOp.getDependIteratedMutable().clear();
215 targetOp.setDependIteratedKindsAttr(
nullptr);
216 targetOp.getDeviceMutable().clear();
217 targetOp.getDynGroupprivateSizeMutable().clear();
218 targetOp.getIfExprMutable().clear();
219 targetOp.getInReductionVarsMutable().clear();
220 targetOp.setInReductionByrefAttr(
nullptr);
221 targetOp.setInReductionSymsAttr(
nullptr);
226 for (Value allocVar : targetOp.getAllocateVars())
228 for (Value allocVar : targetOp.getAllocatorVars())
230 for (Value isDevPtr : targetOp.getIsDevicePtrVars())
232 for (Value mapVar : targetOp.getHasDeviceAddrVars())
233 collectRewrite(cast<omp::MapInfoOp>(mapVar.getDefiningOp()), mapInfos);
234 for (Value mapVar : targetOp.getMapVars())
235 collectRewrite(cast<omp::MapInfoOp>(mapVar.getDefiningOp()), mapInfos);
236 for (Value privateVar : targetOp.getPrivateVars())
238 for (Value threadLimit : targetOp.getThreadLimitVars())
243 for (omp::MapInfoOp mapOp : mapInfos) {
246 if (Value varPtrPtr = mapOp.getVarPtrPtr())
250 mapOp.getBoundsMutable().clear();
251 mapOp->moveBefore(&block, block.
end());
254 builder.setInsertionPointToStart(&block);
259 llvm::SmallVector<Type> newFnArgTypes(functionType.getParams());
260 for (Value value : rewriteValues) {
262 Operation *definingOp = value.getDefiningOp();
264 rewriteValue = builder.clone(*value.getDefiningOp())->getResult(0);
266 rewriteValue = block.
addArgument(value.getType(), value.getLoc());
267 newFnArgTypes.push_back(rewriteValue.
getType());
269 value.replaceAllUsesWith(rewriteValue);
273 for (omp::TargetOp targetOp : targetOps)
274 targetOp->moveBefore(&block, block.
end());
277 builder.setInsertionPointToEnd(&block);
278 LLVM::ReturnOp::create(builder, funcOp.getLoc(),
ValueRange());
286 funcOp.setType(LLVM::LLVMFunctionType::get(
287 LLVM::LLVMVoidType::get(&
getContext()), newFnArgTypes));
static std::optional< omp::DeclareTargetDeviceType > getDeclareTargetDevice(Operation &op)
Provide the device_type of an omp.declare_target attribute, if defined.
static bool keepHostOpInDevice(Operation &op)
Some host operations, like llvm.mlir.addressof and constants, must remain in the device module becaus...
static void collectRewrite(omp::MapInfoOp mapOp, llvm::SetVector< omp::MapInfoOp > &rewrites)
Add an omp.map.info operation and all its members recursively to the output set to be later rewritten...
iterator_range< args_iterator > addArguments(TypeRange types, ArrayRef< Location > locs)
Add one argument to the argument list for each type specified in the list.
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
BlockArgListType getArguments()
Dialect * getLoadedDialect(StringRef name)
Get a registered IR dialect with the given namespace.
Operation is the basic unit of execution within MLIR.
Dialect * getDialect()
Return the dialect this operation is associated with, or nullptr if the associated dialect is not loa...
Region & getRegion(unsigned index)
Returns the region held by this operation at position 'index'.
operand_range getOperands()
Returns an iterator on the underlying Value's.
MLIRContext * getContext()
Return the context this operation is associated with.
void erase()
Remove this operation from its parent block and delete it.
BlockArgListType getArguments()
unsigned getNumArguments()
ValueTypeRange< BlockArgListType > getArgumentTypes()
Returns the argument types of the first block within the region.
void takeBody(Region &other)
Takes body of another region (that region will have no body after this operation completes).
RetT walk(FnT &&callback)
Walk all nested operations, blocks or regions (including this region), depending on the type of callb...
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
static WalkResult advance()
static WalkResult interrupt()
Include the generated interface declarations.
bool isPure(Operation *op)
Returns true if the given operation is pure, i.e., is speculatable that does not touch memory.