1*9880d681SAndroid Build Coastguard Worker //===-- AMDGPUAnnotateKernelFeaturesPass.cpp ------------------------------===//
2*9880d681SAndroid Build Coastguard Worker //
3*9880d681SAndroid Build Coastguard Worker // The LLVM Compiler Infrastructure
4*9880d681SAndroid Build Coastguard Worker //
5*9880d681SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*9880d681SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*9880d681SAndroid Build Coastguard Worker //
8*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*9880d681SAndroid Build Coastguard Worker //
10*9880d681SAndroid Build Coastguard Worker /// \file This pass adds target attributes to functions which use intrinsics
11*9880d681SAndroid Build Coastguard Worker /// which will impact calling convention lowering.
12*9880d681SAndroid Build Coastguard Worker //
13*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
14*9880d681SAndroid Build Coastguard Worker
15*9880d681SAndroid Build Coastguard Worker #include "AMDGPU.h"
16*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/Constants.h"
17*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/Instructions.h"
18*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/Module.h"
19*9880d681SAndroid Build Coastguard Worker
20*9880d681SAndroid Build Coastguard Worker #define DEBUG_TYPE "amdgpu-annotate-kernel-features"
21*9880d681SAndroid Build Coastguard Worker
22*9880d681SAndroid Build Coastguard Worker using namespace llvm;
23*9880d681SAndroid Build Coastguard Worker
24*9880d681SAndroid Build Coastguard Worker namespace {
25*9880d681SAndroid Build Coastguard Worker
26*9880d681SAndroid Build Coastguard Worker class AMDGPUAnnotateKernelFeatures : public ModulePass {
27*9880d681SAndroid Build Coastguard Worker private:
28*9880d681SAndroid Build Coastguard Worker static bool hasAddrSpaceCast(const Function &F);
29*9880d681SAndroid Build Coastguard Worker
30*9880d681SAndroid Build Coastguard Worker void addAttrToCallers(Function *Intrin, StringRef AttrName);
31*9880d681SAndroid Build Coastguard Worker bool addAttrsForIntrinsics(Module &M, ArrayRef<StringRef[2]>);
32*9880d681SAndroid Build Coastguard Worker
33*9880d681SAndroid Build Coastguard Worker public:
34*9880d681SAndroid Build Coastguard Worker static char ID;
35*9880d681SAndroid Build Coastguard Worker
AMDGPUAnnotateKernelFeatures()36*9880d681SAndroid Build Coastguard Worker AMDGPUAnnotateKernelFeatures() : ModulePass(ID) { }
37*9880d681SAndroid Build Coastguard Worker bool runOnModule(Module &M) override;
getPassName() const38*9880d681SAndroid Build Coastguard Worker const char *getPassName() const override {
39*9880d681SAndroid Build Coastguard Worker return "AMDGPU Annotate Kernel Features";
40*9880d681SAndroid Build Coastguard Worker }
41*9880d681SAndroid Build Coastguard Worker
getAnalysisUsage(AnalysisUsage & AU) const42*9880d681SAndroid Build Coastguard Worker void getAnalysisUsage(AnalysisUsage &AU) const override {
43*9880d681SAndroid Build Coastguard Worker AU.setPreservesAll();
44*9880d681SAndroid Build Coastguard Worker ModulePass::getAnalysisUsage(AU);
45*9880d681SAndroid Build Coastguard Worker }
46*9880d681SAndroid Build Coastguard Worker
47*9880d681SAndroid Build Coastguard Worker static bool visitConstantExpr(const ConstantExpr *CE);
48*9880d681SAndroid Build Coastguard Worker static bool visitConstantExprsRecursively(
49*9880d681SAndroid Build Coastguard Worker const Constant *EntryC,
50*9880d681SAndroid Build Coastguard Worker SmallPtrSet<const Constant *, 8> &ConstantExprVisited);
51*9880d681SAndroid Build Coastguard Worker };
52*9880d681SAndroid Build Coastguard Worker
53*9880d681SAndroid Build Coastguard Worker }
54*9880d681SAndroid Build Coastguard Worker
55*9880d681SAndroid Build Coastguard Worker char AMDGPUAnnotateKernelFeatures::ID = 0;
56*9880d681SAndroid Build Coastguard Worker
57*9880d681SAndroid Build Coastguard Worker char &llvm::AMDGPUAnnotateKernelFeaturesID = AMDGPUAnnotateKernelFeatures::ID;
58*9880d681SAndroid Build Coastguard Worker
59*9880d681SAndroid Build Coastguard Worker INITIALIZE_PASS(AMDGPUAnnotateKernelFeatures, DEBUG_TYPE,
60*9880d681SAndroid Build Coastguard Worker "Add AMDGPU function attributes", false, false)
61*9880d681SAndroid Build Coastguard Worker
62*9880d681SAndroid Build Coastguard Worker
63*9880d681SAndroid Build Coastguard Worker // The queue ptr is only needed when casting to flat, not from it.
castRequiresQueuePtr(unsigned SrcAS)64*9880d681SAndroid Build Coastguard Worker static bool castRequiresQueuePtr(unsigned SrcAS) {
65*9880d681SAndroid Build Coastguard Worker return SrcAS == AMDGPUAS::LOCAL_ADDRESS || SrcAS == AMDGPUAS::PRIVATE_ADDRESS;
66*9880d681SAndroid Build Coastguard Worker }
67*9880d681SAndroid Build Coastguard Worker
castRequiresQueuePtr(const AddrSpaceCastInst * ASC)68*9880d681SAndroid Build Coastguard Worker static bool castRequiresQueuePtr(const AddrSpaceCastInst *ASC) {
69*9880d681SAndroid Build Coastguard Worker return castRequiresQueuePtr(ASC->getSrcAddressSpace());
70*9880d681SAndroid Build Coastguard Worker }
71*9880d681SAndroid Build Coastguard Worker
visitConstantExpr(const ConstantExpr * CE)72*9880d681SAndroid Build Coastguard Worker bool AMDGPUAnnotateKernelFeatures::visitConstantExpr(const ConstantExpr *CE) {
73*9880d681SAndroid Build Coastguard Worker if (CE->getOpcode() == Instruction::AddrSpaceCast) {
74*9880d681SAndroid Build Coastguard Worker unsigned SrcAS = CE->getOperand(0)->getType()->getPointerAddressSpace();
75*9880d681SAndroid Build Coastguard Worker return castRequiresQueuePtr(SrcAS);
76*9880d681SAndroid Build Coastguard Worker }
77*9880d681SAndroid Build Coastguard Worker
78*9880d681SAndroid Build Coastguard Worker return false;
79*9880d681SAndroid Build Coastguard Worker }
80*9880d681SAndroid Build Coastguard Worker
visitConstantExprsRecursively(const Constant * EntryC,SmallPtrSet<const Constant *,8> & ConstantExprVisited)81*9880d681SAndroid Build Coastguard Worker bool AMDGPUAnnotateKernelFeatures::visitConstantExprsRecursively(
82*9880d681SAndroid Build Coastguard Worker const Constant *EntryC,
83*9880d681SAndroid Build Coastguard Worker SmallPtrSet<const Constant *, 8> &ConstantExprVisited) {
84*9880d681SAndroid Build Coastguard Worker
85*9880d681SAndroid Build Coastguard Worker if (!ConstantExprVisited.insert(EntryC).second)
86*9880d681SAndroid Build Coastguard Worker return false;
87*9880d681SAndroid Build Coastguard Worker
88*9880d681SAndroid Build Coastguard Worker SmallVector<const Constant *, 16> Stack;
89*9880d681SAndroid Build Coastguard Worker Stack.push_back(EntryC);
90*9880d681SAndroid Build Coastguard Worker
91*9880d681SAndroid Build Coastguard Worker while (!Stack.empty()) {
92*9880d681SAndroid Build Coastguard Worker const Constant *C = Stack.pop_back_val();
93*9880d681SAndroid Build Coastguard Worker
94*9880d681SAndroid Build Coastguard Worker // Check this constant expression.
95*9880d681SAndroid Build Coastguard Worker if (const auto *CE = dyn_cast<ConstantExpr>(C)) {
96*9880d681SAndroid Build Coastguard Worker if (visitConstantExpr(CE))
97*9880d681SAndroid Build Coastguard Worker return true;
98*9880d681SAndroid Build Coastguard Worker }
99*9880d681SAndroid Build Coastguard Worker
100*9880d681SAndroid Build Coastguard Worker // Visit all sub-expressions.
101*9880d681SAndroid Build Coastguard Worker for (const Use &U : C->operands()) {
102*9880d681SAndroid Build Coastguard Worker const auto *OpC = dyn_cast<Constant>(U);
103*9880d681SAndroid Build Coastguard Worker if (!OpC)
104*9880d681SAndroid Build Coastguard Worker continue;
105*9880d681SAndroid Build Coastguard Worker
106*9880d681SAndroid Build Coastguard Worker if (!ConstantExprVisited.insert(OpC).second)
107*9880d681SAndroid Build Coastguard Worker continue;
108*9880d681SAndroid Build Coastguard Worker
109*9880d681SAndroid Build Coastguard Worker Stack.push_back(OpC);
110*9880d681SAndroid Build Coastguard Worker }
111*9880d681SAndroid Build Coastguard Worker }
112*9880d681SAndroid Build Coastguard Worker
113*9880d681SAndroid Build Coastguard Worker return false;
114*9880d681SAndroid Build Coastguard Worker }
115*9880d681SAndroid Build Coastguard Worker
116*9880d681SAndroid Build Coastguard Worker // Return true if an addrspacecast is used that requires the queue ptr.
hasAddrSpaceCast(const Function & F)117*9880d681SAndroid Build Coastguard Worker bool AMDGPUAnnotateKernelFeatures::hasAddrSpaceCast(const Function &F) {
118*9880d681SAndroid Build Coastguard Worker SmallPtrSet<const Constant *, 8> ConstantExprVisited;
119*9880d681SAndroid Build Coastguard Worker
120*9880d681SAndroid Build Coastguard Worker for (const BasicBlock &BB : F) {
121*9880d681SAndroid Build Coastguard Worker for (const Instruction &I : BB) {
122*9880d681SAndroid Build Coastguard Worker if (const AddrSpaceCastInst *ASC = dyn_cast<AddrSpaceCastInst>(&I)) {
123*9880d681SAndroid Build Coastguard Worker if (castRequiresQueuePtr(ASC))
124*9880d681SAndroid Build Coastguard Worker return true;
125*9880d681SAndroid Build Coastguard Worker }
126*9880d681SAndroid Build Coastguard Worker
127*9880d681SAndroid Build Coastguard Worker for (const Use &U : I.operands()) {
128*9880d681SAndroid Build Coastguard Worker const auto *OpC = dyn_cast<Constant>(U);
129*9880d681SAndroid Build Coastguard Worker if (!OpC)
130*9880d681SAndroid Build Coastguard Worker continue;
131*9880d681SAndroid Build Coastguard Worker
132*9880d681SAndroid Build Coastguard Worker if (visitConstantExprsRecursively(OpC, ConstantExprVisited))
133*9880d681SAndroid Build Coastguard Worker return true;
134*9880d681SAndroid Build Coastguard Worker }
135*9880d681SAndroid Build Coastguard Worker }
136*9880d681SAndroid Build Coastguard Worker }
137*9880d681SAndroid Build Coastguard Worker
138*9880d681SAndroid Build Coastguard Worker return false;
139*9880d681SAndroid Build Coastguard Worker }
140*9880d681SAndroid Build Coastguard Worker
addAttrToCallers(Function * Intrin,StringRef AttrName)141*9880d681SAndroid Build Coastguard Worker void AMDGPUAnnotateKernelFeatures::addAttrToCallers(Function *Intrin,
142*9880d681SAndroid Build Coastguard Worker StringRef AttrName) {
143*9880d681SAndroid Build Coastguard Worker SmallPtrSet<Function *, 4> SeenFuncs;
144*9880d681SAndroid Build Coastguard Worker
145*9880d681SAndroid Build Coastguard Worker for (User *U : Intrin->users()) {
146*9880d681SAndroid Build Coastguard Worker // CallInst is the only valid user for an intrinsic.
147*9880d681SAndroid Build Coastguard Worker CallInst *CI = cast<CallInst>(U);
148*9880d681SAndroid Build Coastguard Worker
149*9880d681SAndroid Build Coastguard Worker Function *CallingFunction = CI->getParent()->getParent();
150*9880d681SAndroid Build Coastguard Worker if (SeenFuncs.insert(CallingFunction).second)
151*9880d681SAndroid Build Coastguard Worker CallingFunction->addFnAttr(AttrName);
152*9880d681SAndroid Build Coastguard Worker }
153*9880d681SAndroid Build Coastguard Worker }
154*9880d681SAndroid Build Coastguard Worker
addAttrsForIntrinsics(Module & M,ArrayRef<StringRef[2]> IntrinsicToAttr)155*9880d681SAndroid Build Coastguard Worker bool AMDGPUAnnotateKernelFeatures::addAttrsForIntrinsics(
156*9880d681SAndroid Build Coastguard Worker Module &M,
157*9880d681SAndroid Build Coastguard Worker ArrayRef<StringRef[2]> IntrinsicToAttr) {
158*9880d681SAndroid Build Coastguard Worker bool Changed = false;
159*9880d681SAndroid Build Coastguard Worker
160*9880d681SAndroid Build Coastguard Worker for (const StringRef *Arr : IntrinsicToAttr) {
161*9880d681SAndroid Build Coastguard Worker if (Function *Fn = M.getFunction(Arr[0])) {
162*9880d681SAndroid Build Coastguard Worker addAttrToCallers(Fn, Arr[1]);
163*9880d681SAndroid Build Coastguard Worker Changed = true;
164*9880d681SAndroid Build Coastguard Worker }
165*9880d681SAndroid Build Coastguard Worker }
166*9880d681SAndroid Build Coastguard Worker
167*9880d681SAndroid Build Coastguard Worker return Changed;
168*9880d681SAndroid Build Coastguard Worker }
169*9880d681SAndroid Build Coastguard Worker
runOnModule(Module & M)170*9880d681SAndroid Build Coastguard Worker bool AMDGPUAnnotateKernelFeatures::runOnModule(Module &M) {
171*9880d681SAndroid Build Coastguard Worker Triple TT(M.getTargetTriple());
172*9880d681SAndroid Build Coastguard Worker
173*9880d681SAndroid Build Coastguard Worker static const StringRef IntrinsicToAttr[][2] = {
174*9880d681SAndroid Build Coastguard Worker // .x omitted
175*9880d681SAndroid Build Coastguard Worker { "llvm.amdgcn.workitem.id.y", "amdgpu-work-item-id-y" },
176*9880d681SAndroid Build Coastguard Worker { "llvm.amdgcn.workitem.id.z", "amdgpu-work-item-id-z" },
177*9880d681SAndroid Build Coastguard Worker
178*9880d681SAndroid Build Coastguard Worker { "llvm.amdgcn.workgroup.id.y", "amdgpu-work-group-id-y" },
179*9880d681SAndroid Build Coastguard Worker { "llvm.amdgcn.workgroup.id.z", "amdgpu-work-group-id-z" },
180*9880d681SAndroid Build Coastguard Worker
181*9880d681SAndroid Build Coastguard Worker { "llvm.r600.read.tgid.y", "amdgpu-work-group-id-y" },
182*9880d681SAndroid Build Coastguard Worker { "llvm.r600.read.tgid.z", "amdgpu-work-group-id-z" },
183*9880d681SAndroid Build Coastguard Worker
184*9880d681SAndroid Build Coastguard Worker // .x omitted
185*9880d681SAndroid Build Coastguard Worker { "llvm.r600.read.tidig.y", "amdgpu-work-item-id-y" },
186*9880d681SAndroid Build Coastguard Worker { "llvm.r600.read.tidig.z", "amdgpu-work-item-id-z" }
187*9880d681SAndroid Build Coastguard Worker };
188*9880d681SAndroid Build Coastguard Worker
189*9880d681SAndroid Build Coastguard Worker static const StringRef HSAIntrinsicToAttr[][2] = {
190*9880d681SAndroid Build Coastguard Worker { "llvm.amdgcn.dispatch.ptr", "amdgpu-dispatch-ptr" },
191*9880d681SAndroid Build Coastguard Worker { "llvm.amdgcn.queue.ptr", "amdgpu-queue-ptr" }
192*9880d681SAndroid Build Coastguard Worker };
193*9880d681SAndroid Build Coastguard Worker
194*9880d681SAndroid Build Coastguard Worker // TODO: We should not add the attributes if the known compile time workgroup
195*9880d681SAndroid Build Coastguard Worker // size is 1 for y/z.
196*9880d681SAndroid Build Coastguard Worker
197*9880d681SAndroid Build Coastguard Worker // TODO: Intrinsics that require queue ptr.
198*9880d681SAndroid Build Coastguard Worker
199*9880d681SAndroid Build Coastguard Worker // We do not need to note the x workitem or workgroup id because they are
200*9880d681SAndroid Build Coastguard Worker // always initialized.
201*9880d681SAndroid Build Coastguard Worker
202*9880d681SAndroid Build Coastguard Worker bool Changed = addAttrsForIntrinsics(M, IntrinsicToAttr);
203*9880d681SAndroid Build Coastguard Worker if (TT.getOS() == Triple::AMDHSA) {
204*9880d681SAndroid Build Coastguard Worker Changed |= addAttrsForIntrinsics(M, HSAIntrinsicToAttr);
205*9880d681SAndroid Build Coastguard Worker
206*9880d681SAndroid Build Coastguard Worker for (Function &F : M) {
207*9880d681SAndroid Build Coastguard Worker if (F.hasFnAttribute("amdgpu-queue-ptr"))
208*9880d681SAndroid Build Coastguard Worker continue;
209*9880d681SAndroid Build Coastguard Worker
210*9880d681SAndroid Build Coastguard Worker if (hasAddrSpaceCast(F))
211*9880d681SAndroid Build Coastguard Worker F.addFnAttr("amdgpu-queue-ptr");
212*9880d681SAndroid Build Coastguard Worker }
213*9880d681SAndroid Build Coastguard Worker }
214*9880d681SAndroid Build Coastguard Worker
215*9880d681SAndroid Build Coastguard Worker return Changed;
216*9880d681SAndroid Build Coastguard Worker }
217*9880d681SAndroid Build Coastguard Worker
createAMDGPUAnnotateKernelFeaturesPass()218*9880d681SAndroid Build Coastguard Worker ModulePass *llvm::createAMDGPUAnnotateKernelFeaturesPass() {
219*9880d681SAndroid Build Coastguard Worker return new AMDGPUAnnotateKernelFeatures();
220*9880d681SAndroid Build Coastguard Worker }
221