39#include "llvm/Support/Debug.h"
43#define GEN_PASS_DEF_ACCBINDROUTINE
44#include "mlir/Dialect/OpenACC/Transforms/Passes.h.inc"
48#define DEBUG_TYPE "acc-bind-routine"
55static RoutineOp getFirstAccRoutineOp(FunctionOpInterface funcOp,
58 auto attr = funcOp->getAttrOfType<SpecializedRoutineAttr>(
60 return symTab.
lookup<RoutineOp>(attr.getRoutine().getLeafReference());
64 assert(routineInfo &&
"expected acc.routine_info for acc routine function");
65 auto accRoutines = routineInfo.getAccRoutines();
66 assert(!accRoutines.empty() &&
"expected at least one acc routine");
67 return symTab.
lookup<RoutineOp>(accRoutines[0].getLeafReference());
70static bool isACCRoutineBindDefaultOrDeviceType(RoutineOp op,
72 if (!op.getBindIdName() && !op.getBindStrName())
74 return op.getBindNameValue().has_value() ||
84 ModuleOp module =
func->getParentOfType<ModuleOp>();
96 func.walk([&](CallOpInterface callOp) {
97 if (!callOp.getCallableForCallee())
99 if (!callOp->getParentOfType<OffloadRegionOpInterface>() &&
100 !callOp->getParentOfType<gpu::GPUFuncOp>())
102 SymbolRefAttr calleeSymbolRef =
103 dyn_cast<SymbolRefAttr>(callOp.getCallableForCallee());
104 if (!calleeSymbolRef)
106 FunctionOpInterface callee = symTab.
lookup<FunctionOpInterface>(
107 calleeSymbolRef.getLeafReference());
114 if (
auto routineInfo = callee->getAttrOfType<RoutineInfoAttr>(
116 if (routineInfo.getAccRoutines().size() > 1) {
117 (
void)accSupport.
emitNYI(callOp.getLoc(),
"multiple `acc routine`s");
123 RoutineOp routine = getFirstAccRoutineOp(callee, symTab);
124 if (!isACCRoutineBindDefaultOrDeviceType(routine, this->deviceType))
127 auto bindNameOpt = routine.getBindNameValue(this->deviceType);
129 bindNameOpt = routine.getBindNameValue();
132 SymbolRefAttr calleeRef;
133 if (
auto *symRef = std::get_if<SymbolRefAttr>(&*bindNameOpt)) {
136 StringRef bindName = std::get<StringAttr>(*bindNameOpt).getValue();
137 auto gpuMod =
func->getParentOfType<gpu::GPUModuleOp>();
139 gpuMod ? gpuMod.getOperation() :
module.getOperation();
141 if (!insertSymTab.lookup(bindName)) {
143 Block *insertBlock = gpuMod ? gpuMod.getBody() :
module.getBody();
144 builder.setInsertionPointToEnd(insertBlock);
145 auto funcType = cast<FunctionType>(callee.getFunctionType());
146 func::FuncOp bindFunc = func::FuncOp::create(builder, callee.getLoc(),
148 bindFunc.setPrivate();
149 insertSymTab.insert(bindFunc);
153 callOp.setCalleeFromCallable(calleeRef);
Block represents an ordered list of Operations.
static FlatSymbolRefAttr get(StringAttr value)
Construct a symbol reference for the given value name.
AnalysisT & getAnalysis()
mlir::FunctionOpInterface getOperation()
This class helps build Operations.
Operation is the basic unit of execution within MLIR.
std::optional< std::reference_wrapper< AnalysisT > > getCachedParentAnalysis(Operation *parent)
Returns the analysis for the given parent operation if it exists.
virtual void runOnOperation()=0
The polymorphic API that runs the pass over the currently held operation.
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.
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.