13931948bSMatt Arsenault //===-- AMDGPUAnnotateKernelFeaturesPass.cpp ------------------------------===//
23931948bSMatt Arsenault //
33931948bSMatt Arsenault //                     The LLVM Compiler Infrastructure
43931948bSMatt Arsenault //
53931948bSMatt Arsenault // This file is distributed under the University of Illinois Open Source
63931948bSMatt Arsenault // License. See LICENSE.TXT for details.
73931948bSMatt Arsenault //
83931948bSMatt Arsenault //===----------------------------------------------------------------------===//
93931948bSMatt Arsenault //
103931948bSMatt Arsenault /// \file This pass adds target attributes to functions which use intrinsics
113931948bSMatt Arsenault /// which will impact calling convention lowering.
123931948bSMatt Arsenault //
133931948bSMatt Arsenault //===----------------------------------------------------------------------===//
143931948bSMatt Arsenault 
153931948bSMatt Arsenault #include "AMDGPU.h"
16e823d92fSMatt Arsenault #include "AMDGPUSubtarget.h"
172ffe8fd2SMatt Arsenault #include "llvm/ADT/Triple.h"
183b2e2a59SMatt Arsenault #include "llvm/IR/Constants.h"
193931948bSMatt Arsenault #include "llvm/IR/Instructions.h"
203931948bSMatt Arsenault #include "llvm/IR/Module.h"
213931948bSMatt Arsenault 
223931948bSMatt Arsenault #define DEBUG_TYPE "amdgpu-annotate-kernel-features"
233931948bSMatt Arsenault 
243931948bSMatt Arsenault using namespace llvm;
253931948bSMatt Arsenault 
263931948bSMatt Arsenault namespace {
273931948bSMatt Arsenault 
283931948bSMatt Arsenault class AMDGPUAnnotateKernelFeatures : public ModulePass {
293931948bSMatt Arsenault private:
30e823d92fSMatt Arsenault   const TargetMachine *TM;
31*1a14bfa0SYaxun Liu   AMDGPUAS AS;
32*1a14bfa0SYaxun Liu   static bool hasAddrSpaceCast(const Function &F, AMDGPUAS AS);
3399c14524SMatt Arsenault 
343931948bSMatt Arsenault   void addAttrToCallers(Function *Intrin, StringRef AttrName);
353931948bSMatt Arsenault   bool addAttrsForIntrinsics(Module &M, ArrayRef<StringRef[2]>);
363931948bSMatt Arsenault 
373931948bSMatt Arsenault public:
383931948bSMatt Arsenault   static char ID;
393931948bSMatt Arsenault 
40e823d92fSMatt Arsenault   AMDGPUAnnotateKernelFeatures(const TargetMachine *TM_ = nullptr) :
41e823d92fSMatt Arsenault                                ModulePass(ID), TM(TM_) {}
423931948bSMatt Arsenault   bool runOnModule(Module &M) override;
43117296c0SMehdi Amini   StringRef getPassName() const override {
443931948bSMatt Arsenault     return "AMDGPU Annotate Kernel Features";
453931948bSMatt Arsenault   }
463931948bSMatt Arsenault 
473931948bSMatt Arsenault   void getAnalysisUsage(AnalysisUsage &AU) const override {
483931948bSMatt Arsenault     AU.setPreservesAll();
493931948bSMatt Arsenault     ModulePass::getAnalysisUsage(AU);
503931948bSMatt Arsenault   }
513b2e2a59SMatt Arsenault 
52*1a14bfa0SYaxun Liu   static bool visitConstantExpr(const ConstantExpr *CE, AMDGPUAS AS);
533b2e2a59SMatt Arsenault   static bool visitConstantExprsRecursively(
543b2e2a59SMatt Arsenault     const Constant *EntryC,
55*1a14bfa0SYaxun Liu     SmallPtrSet<const Constant *, 8> &ConstantExprVisited,
56*1a14bfa0SYaxun Liu     AMDGPUAS AS);
573931948bSMatt Arsenault };
583931948bSMatt Arsenault 
593931948bSMatt Arsenault }
603931948bSMatt Arsenault 
613931948bSMatt Arsenault char AMDGPUAnnotateKernelFeatures::ID = 0;
623931948bSMatt Arsenault 
633931948bSMatt Arsenault char &llvm::AMDGPUAnnotateKernelFeaturesID = AMDGPUAnnotateKernelFeatures::ID;
643931948bSMatt Arsenault 
6599c14524SMatt Arsenault INITIALIZE_PASS(AMDGPUAnnotateKernelFeatures, DEBUG_TYPE,
663931948bSMatt Arsenault                 "Add AMDGPU function attributes", false, false)
673931948bSMatt Arsenault 
6899c14524SMatt Arsenault 
6999c14524SMatt Arsenault // The queue ptr is only needed when casting to flat, not from it.
70*1a14bfa0SYaxun Liu static bool castRequiresQueuePtr(unsigned SrcAS, const AMDGPUAS &AS) {
71*1a14bfa0SYaxun Liu   return SrcAS == AS.LOCAL_ADDRESS || SrcAS == AS.PRIVATE_ADDRESS;
7299c14524SMatt Arsenault }
7399c14524SMatt Arsenault 
74*1a14bfa0SYaxun Liu static bool castRequiresQueuePtr(const AddrSpaceCastInst *ASC,
75*1a14bfa0SYaxun Liu     const AMDGPUAS &AS) {
76*1a14bfa0SYaxun Liu   return castRequiresQueuePtr(ASC->getSrcAddressSpace(), AS);
773b2e2a59SMatt Arsenault }
783b2e2a59SMatt Arsenault 
79*1a14bfa0SYaxun Liu bool AMDGPUAnnotateKernelFeatures::visitConstantExpr(const ConstantExpr *CE,
80*1a14bfa0SYaxun Liu     AMDGPUAS AS) {
813b2e2a59SMatt Arsenault   if (CE->getOpcode() == Instruction::AddrSpaceCast) {
823b2e2a59SMatt Arsenault     unsigned SrcAS = CE->getOperand(0)->getType()->getPointerAddressSpace();
83*1a14bfa0SYaxun Liu     return castRequiresQueuePtr(SrcAS, AS);
843b2e2a59SMatt Arsenault   }
853b2e2a59SMatt Arsenault 
863b2e2a59SMatt Arsenault   return false;
873b2e2a59SMatt Arsenault }
883b2e2a59SMatt Arsenault 
893b2e2a59SMatt Arsenault bool AMDGPUAnnotateKernelFeatures::visitConstantExprsRecursively(
903b2e2a59SMatt Arsenault   const Constant *EntryC,
91*1a14bfa0SYaxun Liu   SmallPtrSet<const Constant *, 8> &ConstantExprVisited,
92*1a14bfa0SYaxun Liu   AMDGPUAS AS) {
933b2e2a59SMatt Arsenault 
943b2e2a59SMatt Arsenault   if (!ConstantExprVisited.insert(EntryC).second)
953b2e2a59SMatt Arsenault     return false;
963b2e2a59SMatt Arsenault 
973b2e2a59SMatt Arsenault   SmallVector<const Constant *, 16> Stack;
983b2e2a59SMatt Arsenault   Stack.push_back(EntryC);
993b2e2a59SMatt Arsenault 
1003b2e2a59SMatt Arsenault   while (!Stack.empty()) {
1013b2e2a59SMatt Arsenault     const Constant *C = Stack.pop_back_val();
1023b2e2a59SMatt Arsenault 
1033b2e2a59SMatt Arsenault     // Check this constant expression.
1043b2e2a59SMatt Arsenault     if (const auto *CE = dyn_cast<ConstantExpr>(C)) {
105*1a14bfa0SYaxun Liu       if (visitConstantExpr(CE, AS))
1063b2e2a59SMatt Arsenault         return true;
1073b2e2a59SMatt Arsenault     }
1083b2e2a59SMatt Arsenault 
1093b2e2a59SMatt Arsenault     // Visit all sub-expressions.
1103b2e2a59SMatt Arsenault     for (const Use &U : C->operands()) {
1113b2e2a59SMatt Arsenault       const auto *OpC = dyn_cast<Constant>(U);
1123b2e2a59SMatt Arsenault       if (!OpC)
1133b2e2a59SMatt Arsenault         continue;
1143b2e2a59SMatt Arsenault 
1153b2e2a59SMatt Arsenault       if (!ConstantExprVisited.insert(OpC).second)
1163b2e2a59SMatt Arsenault         continue;
1173b2e2a59SMatt Arsenault 
1183b2e2a59SMatt Arsenault       Stack.push_back(OpC);
1193b2e2a59SMatt Arsenault     }
1203b2e2a59SMatt Arsenault   }
1213b2e2a59SMatt Arsenault 
1223b2e2a59SMatt Arsenault   return false;
1233b2e2a59SMatt Arsenault }
1243b2e2a59SMatt Arsenault 
12599c14524SMatt Arsenault // Return true if an addrspacecast is used that requires the queue ptr.
126*1a14bfa0SYaxun Liu bool AMDGPUAnnotateKernelFeatures::hasAddrSpaceCast(const Function &F,
127*1a14bfa0SYaxun Liu     AMDGPUAS AS) {
1283b2e2a59SMatt Arsenault   SmallPtrSet<const Constant *, 8> ConstantExprVisited;
1293b2e2a59SMatt Arsenault 
13099c14524SMatt Arsenault   for (const BasicBlock &BB : F) {
13199c14524SMatt Arsenault     for (const Instruction &I : BB) {
13299c14524SMatt Arsenault       if (const AddrSpaceCastInst *ASC = dyn_cast<AddrSpaceCastInst>(&I)) {
133*1a14bfa0SYaxun Liu         if (castRequiresQueuePtr(ASC, AS))
13499c14524SMatt Arsenault           return true;
13599c14524SMatt Arsenault       }
1363b2e2a59SMatt Arsenault 
1373b2e2a59SMatt Arsenault       for (const Use &U : I.operands()) {
1383b2e2a59SMatt Arsenault         const auto *OpC = dyn_cast<Constant>(U);
1393b2e2a59SMatt Arsenault         if (!OpC)
1403b2e2a59SMatt Arsenault           continue;
1413b2e2a59SMatt Arsenault 
142*1a14bfa0SYaxun Liu         if (visitConstantExprsRecursively(OpC, ConstantExprVisited, AS))
1433b2e2a59SMatt Arsenault           return true;
1443b2e2a59SMatt Arsenault       }
14599c14524SMatt Arsenault     }
14699c14524SMatt Arsenault   }
14799c14524SMatt Arsenault 
14899c14524SMatt Arsenault   return false;
14999c14524SMatt Arsenault }
1503931948bSMatt Arsenault 
1513931948bSMatt Arsenault void AMDGPUAnnotateKernelFeatures::addAttrToCallers(Function *Intrin,
1523931948bSMatt Arsenault                                                     StringRef AttrName) {
1533931948bSMatt Arsenault   SmallPtrSet<Function *, 4> SeenFuncs;
1543931948bSMatt Arsenault 
1553931948bSMatt Arsenault   for (User *U : Intrin->users()) {
1563931948bSMatt Arsenault     // CallInst is the only valid user for an intrinsic.
1573931948bSMatt Arsenault     CallInst *CI = cast<CallInst>(U);
1583931948bSMatt Arsenault 
1593931948bSMatt Arsenault     Function *CallingFunction = CI->getParent()->getParent();
1603931948bSMatt Arsenault     if (SeenFuncs.insert(CallingFunction).second)
1613931948bSMatt Arsenault       CallingFunction->addFnAttr(AttrName);
1623931948bSMatt Arsenault   }
1633931948bSMatt Arsenault }
1643931948bSMatt Arsenault 
1653931948bSMatt Arsenault bool AMDGPUAnnotateKernelFeatures::addAttrsForIntrinsics(
1663931948bSMatt Arsenault   Module &M,
1673931948bSMatt Arsenault   ArrayRef<StringRef[2]> IntrinsicToAttr) {
1683931948bSMatt Arsenault   bool Changed = false;
1693931948bSMatt Arsenault 
1703931948bSMatt Arsenault   for (const StringRef *Arr  : IntrinsicToAttr) {
1713931948bSMatt Arsenault     if (Function *Fn = M.getFunction(Arr[0])) {
1723931948bSMatt Arsenault       addAttrToCallers(Fn, Arr[1]);
1733931948bSMatt Arsenault       Changed = true;
1743931948bSMatt Arsenault     }
1753931948bSMatt Arsenault   }
1763931948bSMatt Arsenault 
1773931948bSMatt Arsenault   return Changed;
1783931948bSMatt Arsenault }
1793931948bSMatt Arsenault 
1803931948bSMatt Arsenault bool AMDGPUAnnotateKernelFeatures::runOnModule(Module &M) {
1813931948bSMatt Arsenault   Triple TT(M.getTargetTriple());
182*1a14bfa0SYaxun Liu   AS = AMDGPU::getAMDGPUAS(M);
1833931948bSMatt Arsenault 
1843931948bSMatt Arsenault   static const StringRef IntrinsicToAttr[][2] = {
1853931948bSMatt Arsenault     // .x omitted
18643976df0SMatt Arsenault     { "llvm.amdgcn.workitem.id.y", "amdgpu-work-item-id-y" },
18743976df0SMatt Arsenault     { "llvm.amdgcn.workitem.id.z", "amdgpu-work-item-id-z" },
18843976df0SMatt Arsenault 
18943976df0SMatt Arsenault     { "llvm.amdgcn.workgroup.id.y", "amdgpu-work-group-id-y" },
19043976df0SMatt Arsenault     { "llvm.amdgcn.workgroup.id.z", "amdgpu-work-group-id-z" },
19143976df0SMatt Arsenault 
1923931948bSMatt Arsenault     { "llvm.r600.read.tgid.y", "amdgpu-work-group-id-y" },
1933931948bSMatt Arsenault     { "llvm.r600.read.tgid.z", "amdgpu-work-group-id-z" },
1943931948bSMatt Arsenault 
1953931948bSMatt Arsenault     // .x omitted
1963931948bSMatt Arsenault     { "llvm.r600.read.tidig.y", "amdgpu-work-item-id-y" },
1973931948bSMatt Arsenault     { "llvm.r600.read.tidig.z", "amdgpu-work-item-id-z" }
1983931948bSMatt Arsenault   };
1993931948bSMatt Arsenault 
2003931948bSMatt Arsenault   static const StringRef HSAIntrinsicToAttr[][2] = {
20148ab526fSMatt Arsenault     { "llvm.amdgcn.dispatch.ptr", "amdgpu-dispatch-ptr" },
2028d718dcfSMatt Arsenault     { "llvm.amdgcn.queue.ptr", "amdgpu-queue-ptr" },
203ee21a36fSWei Ding     { "llvm.amdgcn.dispatch.id", "amdgpu-dispatch-id" },
204205bfdb3SWei Ding     { "llvm.trap", "amdgpu-queue-ptr" },
205205bfdb3SWei Ding     { "llvm.debugtrap", "amdgpu-queue-ptr" }
2063931948bSMatt Arsenault   };
2073931948bSMatt Arsenault 
208d0799df7SMatt Arsenault   // TODO: We should not add the attributes if the known compile time workgroup
209d0799df7SMatt Arsenault   // size is 1 for y/z.
210d0799df7SMatt Arsenault 
2113931948bSMatt Arsenault   // TODO: Intrinsics that require queue ptr.
2123931948bSMatt Arsenault 
2133931948bSMatt Arsenault   // We do not need to note the x workitem or workgroup id because they are
2143931948bSMatt Arsenault   // always initialized.
2153931948bSMatt Arsenault 
2163931948bSMatt Arsenault   bool Changed = addAttrsForIntrinsics(M, IntrinsicToAttr);
2170b76fc4cSTom Stellard   if (TT.getOS() == Triple::AMDHSA || TT.getOS() == Triple::Mesa3D) {
2183931948bSMatt Arsenault     Changed |= addAttrsForIntrinsics(M, HSAIntrinsicToAttr);
2193931948bSMatt Arsenault 
22099c14524SMatt Arsenault     for (Function &F : M) {
22199c14524SMatt Arsenault       if (F.hasFnAttribute("amdgpu-queue-ptr"))
22299c14524SMatt Arsenault         continue;
22399c14524SMatt Arsenault 
224e823d92fSMatt Arsenault       bool HasApertureRegs =
225e823d92fSMatt Arsenault         TM && TM->getSubtarget<AMDGPUSubtarget>(F).hasApertureRegs();
226*1a14bfa0SYaxun Liu       if (!HasApertureRegs && hasAddrSpaceCast(F, AS))
22799c14524SMatt Arsenault         F.addFnAttr("amdgpu-queue-ptr");
22899c14524SMatt Arsenault     }
22999c14524SMatt Arsenault   }
23099c14524SMatt Arsenault 
2313931948bSMatt Arsenault   return Changed;
2323931948bSMatt Arsenault }
2333931948bSMatt Arsenault 
234e823d92fSMatt Arsenault ModulePass *llvm::createAMDGPUAnnotateKernelFeaturesPass(const TargetMachine *TM) {
235e823d92fSMatt Arsenault   return new AMDGPUAnnotateKernelFeatures(TM);
2363931948bSMatt Arsenault }
237