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"
16*e823d92fSMatt 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:
30*e823d92fSMatt Arsenault   const TargetMachine *TM;
3199c14524SMatt Arsenault   static bool hasAddrSpaceCast(const Function &F);
3299c14524SMatt Arsenault 
333931948bSMatt Arsenault   void addAttrToCallers(Function *Intrin, StringRef AttrName);
343931948bSMatt Arsenault   bool addAttrsForIntrinsics(Module &M, ArrayRef<StringRef[2]>);
353931948bSMatt Arsenault 
363931948bSMatt Arsenault public:
373931948bSMatt Arsenault   static char ID;
383931948bSMatt Arsenault 
39*e823d92fSMatt Arsenault   AMDGPUAnnotateKernelFeatures(const TargetMachine *TM_ = nullptr) :
40*e823d92fSMatt Arsenault                                ModulePass(ID), TM(TM_) {}
413931948bSMatt Arsenault   bool runOnModule(Module &M) override;
42117296c0SMehdi Amini   StringRef getPassName() const override {
433931948bSMatt Arsenault     return "AMDGPU Annotate Kernel Features";
443931948bSMatt Arsenault   }
453931948bSMatt Arsenault 
463931948bSMatt Arsenault   void getAnalysisUsage(AnalysisUsage &AU) const override {
473931948bSMatt Arsenault     AU.setPreservesAll();
483931948bSMatt Arsenault     ModulePass::getAnalysisUsage(AU);
493931948bSMatt Arsenault   }
503b2e2a59SMatt Arsenault 
513b2e2a59SMatt Arsenault   static bool visitConstantExpr(const ConstantExpr *CE);
523b2e2a59SMatt Arsenault   static bool visitConstantExprsRecursively(
533b2e2a59SMatt Arsenault     const Constant *EntryC,
543b2e2a59SMatt Arsenault     SmallPtrSet<const Constant *, 8> &ConstantExprVisited);
553931948bSMatt Arsenault };
563931948bSMatt Arsenault 
573931948bSMatt Arsenault }
583931948bSMatt Arsenault 
593931948bSMatt Arsenault char AMDGPUAnnotateKernelFeatures::ID = 0;
603931948bSMatt Arsenault 
613931948bSMatt Arsenault char &llvm::AMDGPUAnnotateKernelFeaturesID = AMDGPUAnnotateKernelFeatures::ID;
623931948bSMatt Arsenault 
6399c14524SMatt Arsenault INITIALIZE_PASS(AMDGPUAnnotateKernelFeatures, DEBUG_TYPE,
643931948bSMatt Arsenault                 "Add AMDGPU function attributes", false, false)
653931948bSMatt Arsenault 
6699c14524SMatt Arsenault 
6799c14524SMatt Arsenault // The queue ptr is only needed when casting to flat, not from it.
683b2e2a59SMatt Arsenault static bool castRequiresQueuePtr(unsigned SrcAS) {
6999c14524SMatt Arsenault   return SrcAS == AMDGPUAS::LOCAL_ADDRESS || SrcAS == AMDGPUAS::PRIVATE_ADDRESS;
7099c14524SMatt Arsenault }
7199c14524SMatt Arsenault 
723b2e2a59SMatt Arsenault static bool castRequiresQueuePtr(const AddrSpaceCastInst *ASC) {
733b2e2a59SMatt Arsenault   return castRequiresQueuePtr(ASC->getSrcAddressSpace());
743b2e2a59SMatt Arsenault }
753b2e2a59SMatt Arsenault 
763b2e2a59SMatt Arsenault bool AMDGPUAnnotateKernelFeatures::visitConstantExpr(const ConstantExpr *CE) {
773b2e2a59SMatt Arsenault   if (CE->getOpcode() == Instruction::AddrSpaceCast) {
783b2e2a59SMatt Arsenault     unsigned SrcAS = CE->getOperand(0)->getType()->getPointerAddressSpace();
793b2e2a59SMatt Arsenault     return castRequiresQueuePtr(SrcAS);
803b2e2a59SMatt Arsenault   }
813b2e2a59SMatt Arsenault 
823b2e2a59SMatt Arsenault   return false;
833b2e2a59SMatt Arsenault }
843b2e2a59SMatt Arsenault 
853b2e2a59SMatt Arsenault bool AMDGPUAnnotateKernelFeatures::visitConstantExprsRecursively(
863b2e2a59SMatt Arsenault   const Constant *EntryC,
873b2e2a59SMatt Arsenault   SmallPtrSet<const Constant *, 8> &ConstantExprVisited) {
883b2e2a59SMatt Arsenault 
893b2e2a59SMatt Arsenault   if (!ConstantExprVisited.insert(EntryC).second)
903b2e2a59SMatt Arsenault     return false;
913b2e2a59SMatt Arsenault 
923b2e2a59SMatt Arsenault   SmallVector<const Constant *, 16> Stack;
933b2e2a59SMatt Arsenault   Stack.push_back(EntryC);
943b2e2a59SMatt Arsenault 
953b2e2a59SMatt Arsenault   while (!Stack.empty()) {
963b2e2a59SMatt Arsenault     const Constant *C = Stack.pop_back_val();
973b2e2a59SMatt Arsenault 
983b2e2a59SMatt Arsenault     // Check this constant expression.
993b2e2a59SMatt Arsenault     if (const auto *CE = dyn_cast<ConstantExpr>(C)) {
1003b2e2a59SMatt Arsenault       if (visitConstantExpr(CE))
1013b2e2a59SMatt Arsenault         return true;
1023b2e2a59SMatt Arsenault     }
1033b2e2a59SMatt Arsenault 
1043b2e2a59SMatt Arsenault     // Visit all sub-expressions.
1053b2e2a59SMatt Arsenault     for (const Use &U : C->operands()) {
1063b2e2a59SMatt Arsenault       const auto *OpC = dyn_cast<Constant>(U);
1073b2e2a59SMatt Arsenault       if (!OpC)
1083b2e2a59SMatt Arsenault         continue;
1093b2e2a59SMatt Arsenault 
1103b2e2a59SMatt Arsenault       if (!ConstantExprVisited.insert(OpC).second)
1113b2e2a59SMatt Arsenault         continue;
1123b2e2a59SMatt Arsenault 
1133b2e2a59SMatt Arsenault       Stack.push_back(OpC);
1143b2e2a59SMatt Arsenault     }
1153b2e2a59SMatt Arsenault   }
1163b2e2a59SMatt Arsenault 
1173b2e2a59SMatt Arsenault   return false;
1183b2e2a59SMatt Arsenault }
1193b2e2a59SMatt Arsenault 
12099c14524SMatt Arsenault // Return true if an addrspacecast is used that requires the queue ptr.
12199c14524SMatt Arsenault bool AMDGPUAnnotateKernelFeatures::hasAddrSpaceCast(const Function &F) {
1223b2e2a59SMatt Arsenault   SmallPtrSet<const Constant *, 8> ConstantExprVisited;
1233b2e2a59SMatt Arsenault 
12499c14524SMatt Arsenault   for (const BasicBlock &BB : F) {
12599c14524SMatt Arsenault     for (const Instruction &I : BB) {
12699c14524SMatt Arsenault       if (const AddrSpaceCastInst *ASC = dyn_cast<AddrSpaceCastInst>(&I)) {
12799c14524SMatt Arsenault         if (castRequiresQueuePtr(ASC))
12899c14524SMatt Arsenault           return true;
12999c14524SMatt Arsenault       }
1303b2e2a59SMatt Arsenault 
1313b2e2a59SMatt Arsenault       for (const Use &U : I.operands()) {
1323b2e2a59SMatt Arsenault         const auto *OpC = dyn_cast<Constant>(U);
1333b2e2a59SMatt Arsenault         if (!OpC)
1343b2e2a59SMatt Arsenault           continue;
1353b2e2a59SMatt Arsenault 
1363b2e2a59SMatt Arsenault         if (visitConstantExprsRecursively(OpC, ConstantExprVisited))
1373b2e2a59SMatt Arsenault           return true;
1383b2e2a59SMatt Arsenault       }
13999c14524SMatt Arsenault     }
14099c14524SMatt Arsenault   }
14199c14524SMatt Arsenault 
14299c14524SMatt Arsenault   return false;
14399c14524SMatt Arsenault }
1443931948bSMatt Arsenault 
1453931948bSMatt Arsenault void AMDGPUAnnotateKernelFeatures::addAttrToCallers(Function *Intrin,
1463931948bSMatt Arsenault                                                     StringRef AttrName) {
1473931948bSMatt Arsenault   SmallPtrSet<Function *, 4> SeenFuncs;
1483931948bSMatt Arsenault 
1493931948bSMatt Arsenault   for (User *U : Intrin->users()) {
1503931948bSMatt Arsenault     // CallInst is the only valid user for an intrinsic.
1513931948bSMatt Arsenault     CallInst *CI = cast<CallInst>(U);
1523931948bSMatt Arsenault 
1533931948bSMatt Arsenault     Function *CallingFunction = CI->getParent()->getParent();
1543931948bSMatt Arsenault     if (SeenFuncs.insert(CallingFunction).second)
1553931948bSMatt Arsenault       CallingFunction->addFnAttr(AttrName);
1563931948bSMatt Arsenault   }
1573931948bSMatt Arsenault }
1583931948bSMatt Arsenault 
1593931948bSMatt Arsenault bool AMDGPUAnnotateKernelFeatures::addAttrsForIntrinsics(
1603931948bSMatt Arsenault   Module &M,
1613931948bSMatt Arsenault   ArrayRef<StringRef[2]> IntrinsicToAttr) {
1623931948bSMatt Arsenault   bool Changed = false;
1633931948bSMatt Arsenault 
1643931948bSMatt Arsenault   for (const StringRef *Arr  : IntrinsicToAttr) {
1653931948bSMatt Arsenault     if (Function *Fn = M.getFunction(Arr[0])) {
1663931948bSMatt Arsenault       addAttrToCallers(Fn, Arr[1]);
1673931948bSMatt Arsenault       Changed = true;
1683931948bSMatt Arsenault     }
1693931948bSMatt Arsenault   }
1703931948bSMatt Arsenault 
1713931948bSMatt Arsenault   return Changed;
1723931948bSMatt Arsenault }
1733931948bSMatt Arsenault 
1743931948bSMatt Arsenault bool AMDGPUAnnotateKernelFeatures::runOnModule(Module &M) {
1753931948bSMatt Arsenault   Triple TT(M.getTargetTriple());
1763931948bSMatt Arsenault 
1773931948bSMatt Arsenault   static const StringRef IntrinsicToAttr[][2] = {
1783931948bSMatt Arsenault     // .x omitted
17943976df0SMatt Arsenault     { "llvm.amdgcn.workitem.id.y", "amdgpu-work-item-id-y" },
18043976df0SMatt Arsenault     { "llvm.amdgcn.workitem.id.z", "amdgpu-work-item-id-z" },
18143976df0SMatt Arsenault 
18243976df0SMatt Arsenault     { "llvm.amdgcn.workgroup.id.y", "amdgpu-work-group-id-y" },
18343976df0SMatt Arsenault     { "llvm.amdgcn.workgroup.id.z", "amdgpu-work-group-id-z" },
18443976df0SMatt Arsenault 
1853931948bSMatt Arsenault     { "llvm.r600.read.tgid.y", "amdgpu-work-group-id-y" },
1863931948bSMatt Arsenault     { "llvm.r600.read.tgid.z", "amdgpu-work-group-id-z" },
1873931948bSMatt Arsenault 
1883931948bSMatt Arsenault     // .x omitted
1893931948bSMatt Arsenault     { "llvm.r600.read.tidig.y", "amdgpu-work-item-id-y" },
1903931948bSMatt Arsenault     { "llvm.r600.read.tidig.z", "amdgpu-work-item-id-z" }
1913931948bSMatt Arsenault   };
1923931948bSMatt Arsenault 
1933931948bSMatt Arsenault   static const StringRef HSAIntrinsicToAttr[][2] = {
19448ab526fSMatt Arsenault     { "llvm.amdgcn.dispatch.ptr", "amdgpu-dispatch-ptr" },
1958d718dcfSMatt Arsenault     { "llvm.amdgcn.queue.ptr", "amdgpu-queue-ptr" },
196ee21a36fSWei Ding     { "llvm.amdgcn.dispatch.id", "amdgpu-dispatch-id" },
197205bfdb3SWei Ding     { "llvm.trap", "amdgpu-queue-ptr" },
198205bfdb3SWei Ding     { "llvm.debugtrap", "amdgpu-queue-ptr" }
1993931948bSMatt Arsenault   };
2003931948bSMatt Arsenault 
201d0799df7SMatt Arsenault   // TODO: We should not add the attributes if the known compile time workgroup
202d0799df7SMatt Arsenault   // size is 1 for y/z.
203d0799df7SMatt Arsenault 
2043931948bSMatt Arsenault   // TODO: Intrinsics that require queue ptr.
2053931948bSMatt Arsenault 
2063931948bSMatt Arsenault   // We do not need to note the x workitem or workgroup id because they are
2073931948bSMatt Arsenault   // always initialized.
2083931948bSMatt Arsenault 
2093931948bSMatt Arsenault   bool Changed = addAttrsForIntrinsics(M, IntrinsicToAttr);
2100b76fc4cSTom Stellard   if (TT.getOS() == Triple::AMDHSA || TT.getOS() == Triple::Mesa3D) {
2113931948bSMatt Arsenault     Changed |= addAttrsForIntrinsics(M, HSAIntrinsicToAttr);
2123931948bSMatt Arsenault 
21399c14524SMatt Arsenault     for (Function &F : M) {
21499c14524SMatt Arsenault       if (F.hasFnAttribute("amdgpu-queue-ptr"))
21599c14524SMatt Arsenault         continue;
21699c14524SMatt Arsenault 
217*e823d92fSMatt Arsenault       bool HasApertureRegs =
218*e823d92fSMatt Arsenault         TM && TM->getSubtarget<AMDGPUSubtarget>(F).hasApertureRegs();
219*e823d92fSMatt Arsenault       if (!HasApertureRegs && hasAddrSpaceCast(F))
22099c14524SMatt Arsenault         F.addFnAttr("amdgpu-queue-ptr");
22199c14524SMatt Arsenault     }
22299c14524SMatt Arsenault   }
22399c14524SMatt Arsenault 
2243931948bSMatt Arsenault   return Changed;
2253931948bSMatt Arsenault }
2263931948bSMatt Arsenault 
227*e823d92fSMatt Arsenault ModulePass *llvm::createAMDGPUAnnotateKernelFeaturesPass(const TargetMachine *TM) {
228*e823d92fSMatt Arsenault   return new AMDGPUAnnotateKernelFeatures(TM);
2293931948bSMatt Arsenault }
230