MLIR 24.0.0git
ACCBindRoutine.cpp
Go to the documentation of this file.
1//===- ACCBindRoutine.cpp - OpenACC bind routine transform ---------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// The OpenACC `routine` directive may specify a `bind(name)` clause to
10// associate the routine with a different symbol for device code. This pass
11// finds calls inside offload regions that target such routines and rewrites the
12// callee to the bound symbol.
13//
14// Overview:
15// ---------
16// For the current function, walk call operations inside offload regions, or
17// gpu.func). If the callee is a function with an acc routine that has
18// bind(name), replace the call to use the bound symbol.
19//
20// Requirements:
21// -------------
22// - OffloadRegionOpInterface: the pass walks operations implementing this
23// interface to discover offload regions (e.g. acc.compute_region) and
24// rewrites calls inside their getOffloadRegion().
25// - CallOpInterface with working setCalleeFromCallable: call operations
26// must implement CallOpInterface and setCalleeFromCallable so the pass
27// can rewrite the callee to the symbol without invalidating the call.
28//
29//===----------------------------------------------------------------------===//
30
32
37#include "mlir/IR/SymbolTable.h"
39#include "llvm/Support/Debug.h"
40
41namespace mlir {
42namespace acc {
43#define GEN_PASS_DEF_ACCBINDROUTINE
44#include "mlir/Dialect/OpenACC/Transforms/Passes.h.inc"
45} // namespace acc
46} // namespace mlir
47
48#define DEBUG_TYPE "acc-bind-routine"
49
50using namespace mlir;
51using namespace mlir::acc;
53namespace {
55static RoutineOp getFirstAccRoutineOp(FunctionOpInterface funcOp,
56 const SymbolTable &symTab) {
58 auto attr = funcOp->getAttrOfType<SpecializedRoutineAttr>(
60 return symTab.lookup<RoutineOp>(attr.getRoutine().getLeafReference());
61 }
62 auto routineInfo =
63 funcOp->getAttrOfType<RoutineInfoAttr>(getRoutineInfoAttrName());
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());
68}
70static bool isACCRoutineBindDefaultOrDeviceType(RoutineOp op,
71 DeviceType deviceType) {
72 if (!op.getBindIdName() && !op.getBindStrName())
73 return false;
74 return op.getBindNameValue().has_value() ||
75 op.getBindNameValue(deviceType).has_value();
76}
77
78class ACCBindRoutine : public acc::impl::ACCBindRoutineBase<ACCBindRoutine> {
79public:
81
82 void runOnOperation() override {
83 FunctionOpInterface func = getOperation();
84 ModuleOp module = func->getParentOfType<ModuleOp>();
85 if (!module)
86 return;
87
88 auto cachedAnalysis =
90 OpenACCSupport &accSupport =
91 cachedAnalysis ? cachedAnalysis->get() : getAnalysis<OpenACCSupport>();
92 SymbolTable symTab(module);
93
94 bool failed = false;
95
96 func.walk([&](CallOpInterface callOp) {
97 if (!callOp.getCallableForCallee())
98 return;
99 if (!callOp->getParentOfType<OffloadRegionOpInterface>() &&
100 !callOp->getParentOfType<gpu::GPUFuncOp>())
101 return;
102 SymbolRefAttr calleeSymbolRef =
103 dyn_cast<SymbolRefAttr>(callOp.getCallableForCallee());
104 if (!calleeSymbolRef)
105 return;
106 FunctionOpInterface callee = symTab.lookup<FunctionOpInterface>(
107 calleeSymbolRef.getLeafReference());
108 if (!callee)
109 return;
111 if (!(isAccRoutine(callee) || isSpecializedAccRoutine(callee)))
112 return;
113
114 if (auto routineInfo = callee->getAttrOfType<RoutineInfoAttr>(
116 if (routineInfo.getAccRoutines().size() > 1) {
117 (void)accSupport.emitNYI(callOp.getLoc(), "multiple `acc routine`s");
118 failed = true;
119 return;
121 }
122
123 RoutineOp routine = getFirstAccRoutineOp(callee, symTab);
124 if (!isACCRoutineBindDefaultOrDeviceType(routine, this->deviceType))
125 return;
126
127 auto bindNameOpt = routine.getBindNameValue(this->deviceType);
128 if (!bindNameOpt)
129 bindNameOpt = routine.getBindNameValue();
130 if (!bindNameOpt)
131 return;
132 SymbolRefAttr calleeRef;
133 if (auto *symRef = std::get_if<SymbolRefAttr>(&*bindNameOpt)) {
134 calleeRef = *symRef;
135 } else {
136 StringRef bindName = std::get<StringAttr>(*bindNameOpt).getValue();
137 auto gpuMod = func->getParentOfType<gpu::GPUModuleOp>();
138 Operation *symbolTableOp =
139 gpuMod ? gpuMod.getOperation() : module.getOperation();
140 SymbolTable insertSymTab(symbolTableOp);
141 if (!insertSymTab.lookup(bindName)) {
142 OpBuilder builder(module.getContext());
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(),
147 bindName, funcType);
148 bindFunc.setPrivate();
149 insertSymTab.insert(bindFunc);
150 }
151 calleeRef = FlatSymbolRefAttr::get(callOp.getContext(), bindName);
152 }
153 callOp.setCalleeFromCallable(calleeRef);
154 });
155
156 if (failed)
157 signalPassFailure();
158 }
159};
160
161} // namespace
Block represents an ordered list of Operations.
Definition Block.h:33
static FlatSymbolRefAttr get(StringAttr value)
Construct a symbol reference for the given value name.
mlir::FunctionOpInterface getOperation()
Definition Pass.h:456
This class helps build Operations.
Definition Builders.h:209
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
std::optional< std::reference_wrapper< AnalysisT > > getCachedParentAnalysis(Operation *parent)
Returns the analysis for the given parent operation if it exists.
Definition Pass.h:265
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...
Definition SymbolTable.h:24
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.
Definition OpenACC.h:195
static constexpr StringLiteral getSpecializedRoutineAttrName()
Definition OpenACC.h:189
bool isSpecializedAccRoutine(mlir::Operation *op)
Used to check whether this is a specialized accelerator version of acc routine function.
Definition OpenACC.h:201
static constexpr StringLiteral getRoutineInfoAttrName()
Definition OpenACC.h:185
Include the generated interface declarations.