66#define DEBUG_TYPE "acc-implicit-routine"
70#define GEN_PASS_DEF_ACCIMPLICITROUTINE
71#include "mlir/Dialect/OpenACC/Transforms/Passes.h.inc"
79class ACCImplicitRoutine
82 unsigned routineCounter = 0;
83 static constexpr llvm::StringRef accRoutinePrefix =
"acc_routine_";
86 void initRoutineCounter(ModuleOp module) {
87 module.walk([&](acc::RoutineOp routineOp) { routineCounter++; });
93 bool isACCRoutineBindDefaultOrDeviceType(acc::RoutineOp op,
94 acc::DeviceType deviceType) {
96 if (!op.getBindIdName() && !op.getBindStrName())
98 return op.getBindNameValue().has_value() ||
99 op.getBindNameValue(deviceType).has_value();
104 FunctionOpInterface &callee) {
105 std::string routineName =
106 (accRoutinePrefix + std::to_string(routineCounter++)).str();
107 auto routineOp = acc::RoutineOp::create(
112 mlir::SymbolRefAttr::get(builder.
getContext(),
129 "function is already associated with a routine");
131 callee->setDiscardableAttr(
133 mlir::acc::RoutineInfoAttr::get(
135 {mlir::SymbolRefAttr::get(builder.getContext(),
136 builder.getStringAttr(routineName))}));
146 op->
walk([&](CallOpInterface callOp) {
149 if (!callOp.getCallableForCallee())
152 auto calleeSymbolRef =
153 dyn_cast<SymbolRefAttr>(callOp.getCallableForCallee());
156 if (!calleeSymbolRef)
159 auto callee = symTab.
lookup<FunctionOpInterface>(
160 calleeSymbolRef.getLeafReference().str());
172 if (callee.isExternal()) {
173 callOp->emitError() <<
"Calls in an acc compute region must be marked "
175 << calleeSymbolRef.getLeafReference();
180 createRoutineOp(builder, callee.getLoc(), callee);
186 LogicalResult implicitRoutineForCallsInRoutine(
193 if (isACCRoutineBindDefaultOrDeviceType(routineOp, targetDeviceType))
196 SymbolTable symTab(routineOp->getParentOfType<ModuleOp>());
197 std::queue<acc::RoutineOp> routineQueue;
198 routineQueue.push(routineOp);
200 while (!routineQueue.empty()) {
201 auto currentRoutine = routineQueue.front();
203 auto func = symTab.
lookup<FunctionOpInterface>(
204 currentRoutine.getFuncName().getLeafReference());
205 func.walk([&](CallOpInterface callOp) {
208 if (!callOp.getCallableForCallee())
211 auto calleeSymbolRef =
212 dyn_cast<SymbolRefAttr>(callOp.getCallableForCallee());
215 if (!calleeSymbolRef)
218 auto callee = symTab.
lookup<FunctionOpInterface>(
219 calleeSymbolRef.getLeafReference().str());
231 if (callee.isExternal()) {
233 <<
"Calls in acc routine must also be marked with acc routine: "
234 << calleeSymbolRef.getLeafReference();
239 auto newRoutineOp = createRoutineOp(builder, callee.getLoc(), callee);
240 routineQueue.push(newRoutineOp);
247 using ACCImplicitRoutineBase<ACCImplicitRoutine>::ACCImplicitRoutineBase;
249 void runOnOperation()
override {
250 auto module = getOperation();
253 initRoutineCounter(module);
260 module.walk([&](Operation *op) {
261 if (isa<ACC_COMPUTE_CONSTRUCT_OPS>(op))
262 if (failed(implicitRoutineForCallsInComputeRegions(op, symTab, builder,
268 acc::DeviceType targetDeviceType = deviceType;
271 module.walk([&](acc::RoutineOp routineOp) {
272 if (failed(implicitRoutineForCallsInRoutine(
273 routineOp, builder, accSupport, targetDeviceType)))
278 return signalPassFailure();
StringAttr getStringAttr(const Twine &bytes)
MLIRContext * getContext() const
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
This class helps build Operations.
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
Operation is the basic unit of execution within MLIR.
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),...
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.
bool isValidSymbolUse(Operation *user, SymbolRefAttr symbol, Operation **definingOpPtr=nullptr)
Check if a symbol use is valid for use in an OpenACC region.
static constexpr StringLiteral getRoutineInfoAttrName()
bool isInOffTargetBranch(mlir::Operation *op, llvm::ArrayRef< int64_t > deviceTypes)
Returns true if op is in a branch that does not execute on the target.
Include the generated interface declarations.