40#include "llvm/Support/Debug.h"
44#define GEN_PASS_DEF_ACCBINDROUTINE
45#define GEN_PASS_DEF_ACCMATERIALIZEROUTINEBINDTARGETS
46#include "mlir/Dialect/OpenACC/Transforms/Passes.h.inc"
50#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());
79class ACCMaterializeRoutineBindTargets
81 ACCMaterializeRoutineBindTargets> {
83 ACCMaterializeRoutineBindTargets>;
92 "root operation must have the SymbolTable trait");
97 ModuleOp mod = dyn_cast<ModuleOp>(symbolTableOp);
102 "root operation must be a builtin.module or nested in one");
115 auto callOp = dyn_cast<CallOpInterface>(op);
116 if (!callOp || !callOp.getCallableForCallee())
118 if (!callOp->getParentOfType<OffloadRegionOpInterface>() &&
119 !callOp->getParentOfType<gpu::GPUFuncOp>())
122 auto calleeSymbolRef =
123 dyn_cast<SymbolRefAttr>(callOp.getCallableForCallee());
124 if (!calleeSymbolRef)
126 FunctionOpInterface callee =
128 callOp, calleeSymbolRef);
130 callee = outerSymTab.lookup<FunctionOpInterface>(
131 calleeSymbolRef.getLeafReference());
135 if (
auto routineInfo = callee->getDiscardableAttrOfType<RoutineInfoAttr>(
137 if (routineInfo.getAccRoutines().size() > 1)
140 RoutineOp routine = getFirstAccRoutineOp(callee, outerSymTab);
144 auto bindNameOpt = routine.getEffectiveBindName(this->deviceType);
145 if (!bindNameOpt || !std::holds_alternative<StringAttr>(*bindNameOpt))
148 StringRef bindName = std::get<StringAttr>(*bindNameOpt).getValue();
149 if (insertSymTab.lookup(bindName))
153 builder.setInsertionPointToEnd(insertBlock);
154 auto funcType = cast<FunctionType>(callee.getFunctionType());
155 func::FuncOp bindFunc =
156 func::FuncOp::create(builder, callee.getLoc(), bindName, funcType);
157 bindFunc.setPrivate();
158 insertSymTab.insert(bindFunc);
166 using acc::impl::ACCBindRoutineBase<ACCBindRoutine>::ACCBindRoutineBase;
168 void getDependentDialects(DialectRegistry ®istry)
const override {
174 void runOnOperation()
override {
175 FunctionOpInterface func = getOperation();
176 ModuleOp module = func->getParentOfType<ModuleOp>();
180 auto cachedAnalysis =
181 getCachedParentAnalysis<OpenACCSupport>(func->getParentOp());
182 OpenACCSupport &accSupport =
183 cachedAnalysis ? cachedAnalysis->get() : getAnalysis<OpenACCSupport>();
184 SymbolTable outerSymTab(module);
187 func.walk([&](CallOpInterface callOp) {
188 if (!callOp.getCallableForCallee())
190 if (!callOp->getParentOfType<OffloadRegionOpInterface>() &&
191 !callOp->getParentOfType<gpu::GPUFuncOp>())
193 SymbolRefAttr calleeSymbolRef =
194 dyn_cast<SymbolRefAttr>(callOp.getCallableForCallee());
195 if (!calleeSymbolRef)
197 FunctionOpInterface callee =
199 callOp, calleeSymbolRef);
201 callee = outerSymTab.lookup<FunctionOpInterface>(
202 calleeSymbolRef.getLeafReference());
209 if (
auto routineInfo = callee->getDiscardableAttrOfType<RoutineInfoAttr>(
211 if (routineInfo.getAccRoutines().size() > 1) {
212 (void)accSupport.
emitNYI(callOp.getLoc(),
"multiple `acc routine`s");
218 RoutineOp routine = getFirstAccRoutineOp(callee, outerSymTab);
222 auto bindNameOpt = routine.getEffectiveBindName(this->deviceType);
225 SymbolRefAttr calleeRef;
226 if (
auto *symRef = std::get_if<SymbolRefAttr>(&*bindNameOpt)) {
229 StringRef bindName = std::get<StringAttr>(*bindNameOpt).getValue();
230 auto gpuMod = func->getParentOfType<gpu::GPUModuleOp>();
231 Operation *symbolTableOp =
232 gpuMod ? gpuMod.getOperation() :
module.getOperation();
233 SymbolTable symbolTable(symbolTableOp);
234 if (!symbolTable.lookup(bindName)) {
236 "string-bound ACC routine target was not materialized");
242 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.
void getDependentDialects(::mlir::DialectRegistry ®istry) const override
Return the dialect that must be loaded in the context before this pass.
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()
void registerAllExtensions(DialectRegistry ®istry)
Register the standard OpenACC models for GPU, LLVM and MemRef IR.
Include the generated interface declarations.