39#include "llvm/Support/Debug.h"
43#define GEN_PASS_DEF_ACCBINDROUTINE
44#define GEN_PASS_DEF_ACCMATERIALIZEROUTINEBINDTARGETS
45#include "mlir/Dialect/OpenACC/Transforms/Passes.h.inc"
49#define DEBUG_TYPE "acc-bind-routine"
56static RoutineOp getFirstAccRoutineOp(FunctionOpInterface funcOp,
58 SymbolRefAttr routineRef;
60 auto attr = funcOp->getDiscardableAttrOfType<SpecializedRoutineAttr>(
62 routineRef = attr.getRoutine();
64 auto routineInfo = funcOp->getDiscardableAttrOfType<RoutineInfoAttr>(
66 assert(routineInfo &&
"expected acc.routine_info for acc routine function");
67 auto accRoutines = routineInfo.getAccRoutines();
68 assert(!accRoutines.empty() &&
"expected at least one acc routine");
69 routineRef = accRoutines[0];
76 return fallbackSymTab.
lookup<RoutineOp>(routineRef.getLeafReference());
79static bool isACCRoutineBindDefaultOrDeviceType(RoutineOp op,
81 if (!op.getBindIdName() && !op.getBindStrName())
83 return op.getBindNameValue().has_value() ||
87class ACCMaterializeRoutineBindTargets
89 ACCMaterializeRoutineBindTargets> {
91 ACCMaterializeRoutineBindTargets>;
100 "root operation must have the SymbolTable trait");
105 ModuleOp mod = dyn_cast<ModuleOp>(symbolTableOp);
110 "root operation must be a builtin.module or nested in one");
123 auto callOp = dyn_cast<CallOpInterface>(op);
124 if (!callOp || !callOp.getCallableForCallee())
126 if (!callOp->getParentOfType<OffloadRegionOpInterface>() &&
127 !callOp->getParentOfType<gpu::GPUFuncOp>())
130 auto calleeSymbolRef =
131 dyn_cast<SymbolRefAttr>(callOp.getCallableForCallee());
132 if (!calleeSymbolRef)
134 FunctionOpInterface callee =
136 callOp, calleeSymbolRef);
138 callee = outerSymTab.lookup<FunctionOpInterface>(
139 calleeSymbolRef.getLeafReference());
143 if (
auto routineInfo = callee->getDiscardableAttrOfType<RoutineInfoAttr>(
145 if (routineInfo.getAccRoutines().size() > 1)
148 RoutineOp routine = getFirstAccRoutineOp(callee, outerSymTab);
150 !isACCRoutineBindDefaultOrDeviceType(routine, this->deviceType))
153 auto bindNameOpt = routine.getBindNameValue(this->deviceType);
155 bindNameOpt = routine.getBindNameValue();
156 if (!bindNameOpt || !std::holds_alternative<StringAttr>(*bindNameOpt))
159 StringRef bindName = std::get<StringAttr>(*bindNameOpt).getValue();
160 if (insertSymTab.lookup(bindName))
164 builder.setInsertionPointToEnd(insertBlock);
165 auto funcType = cast<FunctionType>(callee.getFunctionType());
166 func::FuncOp bindFunc =
167 func::FuncOp::create(builder, callee.getLoc(), bindName, funcType);
168 bindFunc.setPrivate();
169 insertSymTab.insert(bindFunc);
177 using acc::impl::ACCBindRoutineBase<ACCBindRoutine>::ACCBindRoutineBase;
179 void runOnOperation()
override {
180 FunctionOpInterface func = getOperation();
181 ModuleOp module = func->getParentOfType<ModuleOp>();
185 auto cachedAnalysis =
186 getCachedParentAnalysis<OpenACCSupport>(func->getParentOp());
187 OpenACCSupport &accSupport =
188 cachedAnalysis ? cachedAnalysis->get() : getAnalysis<OpenACCSupport>();
189 SymbolTable outerSymTab(module);
192 func.walk([&](CallOpInterface callOp) {
193 if (!callOp.getCallableForCallee())
195 if (!callOp->getParentOfType<OffloadRegionOpInterface>() &&
196 !callOp->getParentOfType<gpu::GPUFuncOp>())
198 SymbolRefAttr calleeSymbolRef =
199 dyn_cast<SymbolRefAttr>(callOp.getCallableForCallee());
200 if (!calleeSymbolRef)
202 FunctionOpInterface callee =
204 callOp, calleeSymbolRef);
206 callee = outerSymTab.lookup<FunctionOpInterface>(
207 calleeSymbolRef.getLeafReference());
214 if (
auto routineInfo = callee->getDiscardableAttrOfType<RoutineInfoAttr>(
216 if (routineInfo.getAccRoutines().size() > 1) {
217 (void)accSupport.
emitNYI(callOp.getLoc(),
"multiple `acc routine`s");
223 RoutineOp routine = getFirstAccRoutineOp(callee, outerSymTab);
225 !isACCRoutineBindDefaultOrDeviceType(routine, this->deviceType))
228 auto bindNameOpt = routine.getBindNameValue(this->deviceType);
230 bindNameOpt = routine.getBindNameValue();
233 SymbolRefAttr calleeRef;
234 if (
auto *symRef = std::get_if<SymbolRefAttr>(&*bindNameOpt)) {
237 StringRef bindName = std::get<StringAttr>(*bindNameOpt).getValue();
238 auto gpuMod = func->getParentOfType<gpu::GPUModuleOp>();
239 Operation *symbolTableOp =
240 gpuMod ? gpuMod.getOperation() :
module.getOperation();
241 SymbolTable symbolTable(symbolTableOp);
242 if (!symbolTable.lookup(bindName)) {
244 "string-bound ACC routine target was not materialized");
250 callOp.setCalleeFromCallable(calleeRef);
Block represents an ordered list of Operations.
static FlatSymbolRefAttr get(StringAttr value)
Construct a symbol reference for the given value name.
mlir::FunctionOpInterface getOperation()
This class helps build Operations.
A trait used to provide symbol table functionalities to a region operation.
Operation is the basic unit of execution within MLIR.
Region & getRegion(unsigned index)
Returns the region held by this operation at position 'index'.
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
std::enable_if_t< llvm::function_traits< std::decay_t< FnT > >::num_args==1, RetT > walk(FnT &&callback)
Walk the operation by calling the callback for each nested operation (including this one),...
virtual void runOnOperation()=0
The polymorphic API that runs the pass over the currently held operation.
void signalPassFailure()
Signal that some invariant was broken when running.
This class allows for representing and managing the symbol table used by operations with the 'SymbolT...
Operation * lookup(StringRef name) const
Look up a symbol with the specified name, returning null if no such name exists.
static Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
static WalkResult advance()
InFlightDiagnostic emitNYI(Location loc, const Twine &message)
Report a case that is not yet supported by the implementation.
::mlir::Pass::Option< mlir::acc::DeviceType > deviceType
bool isAccRoutine(mlir::Operation *op)
Used to check whether the current operation is marked with acc routine.
static constexpr StringLiteral getSpecializedRoutineAttrName()
bool isSpecializedAccRoutine(mlir::Operation *op)
Used to check whether this is a specialized accelerator version of acc routine function.
static constexpr StringLiteral getRoutineInfoAttrName()
Include the generated interface declarations.