1 //===- AMDGPUAnnotateKernelFeaturesPass.cpp -------------------------------===//
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 /// \file This pass propagates the uniform-work-group-size attribute from
10 /// kernels to leaf functions when possible. It also adds additional attributes
11 /// to hint ABI lowering optimizations later.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "AMDGPU.h"
16 #include "GCNSubtarget.h"
17 #include "llvm/Analysis/CallGraph.h"
18 #include "llvm/Analysis/CallGraphSCCPass.h"
19 #include "llvm/CodeGen/TargetPassConfig.h"
20 #include "llvm/IR/IntrinsicsAMDGPU.h"
21 #include "llvm/IR/IntrinsicsR600.h"
22 #include "llvm/Target/TargetMachine.h"
23 
24 #define DEBUG_TYPE "amdgpu-annotate-kernel-features"
25 
26 using namespace llvm;
27 
28 namespace {
29 class AMDGPUAnnotateKernelFeatures : public CallGraphSCCPass {
30 private:
31   const TargetMachine *TM = nullptr;
32 
33   bool addFeatureAttributes(Function &F);
34 
35 public:
36   static char ID;
37 
38   AMDGPUAnnotateKernelFeatures() : CallGraphSCCPass(ID) {}
39 
40   bool doInitialization(CallGraph &CG) override;
41   bool runOnSCC(CallGraphSCC &SCC) override;
42 
43   StringRef getPassName() const override {
44     return "AMDGPU Annotate Kernel Features";
45   }
46 
47   void getAnalysisUsage(AnalysisUsage &AU) const override {
48     AU.setPreservesAll();
49     CallGraphSCCPass::getAnalysisUsage(AU);
50   }
51 };
52 
53 } // end anonymous namespace
54 
55 char AMDGPUAnnotateKernelFeatures::ID = 0;
56 
57 char &llvm::AMDGPUAnnotateKernelFeaturesID = AMDGPUAnnotateKernelFeatures::ID;
58 
59 INITIALIZE_PASS(AMDGPUAnnotateKernelFeatures, DEBUG_TYPE,
60                 "Add AMDGPU function attributes", false, false)
61 
62 bool AMDGPUAnnotateKernelFeatures::addFeatureAttributes(Function &F) {
63   bool HaveStackObjects = false;
64   bool Changed = false;
65   bool HaveCall = false;
66   bool IsFunc = !AMDGPU::isEntryFunctionCC(F.getCallingConv());
67 
68   for (BasicBlock &BB : F) {
69     for (Instruction &I : BB) {
70       if (isa<AllocaInst>(I)) {
71         HaveStackObjects = true;
72         continue;
73       }
74 
75       if (auto *CB = dyn_cast<CallBase>(&I)) {
76         const Function *Callee =
77             dyn_cast<Function>(CB->getCalledOperand()->stripPointerCasts());
78 
79         // Note the occurrence of indirect call.
80         if (!Callee) {
81           if (!CB->isInlineAsm())
82             HaveCall = true;
83 
84           continue;
85         }
86 
87         Intrinsic::ID IID = Callee->getIntrinsicID();
88         if (IID == Intrinsic::not_intrinsic) {
89           HaveCall = true;
90           Changed = true;
91         }
92       }
93     }
94   }
95 
96   // TODO: We could refine this to captured pointers that could possibly be
97   // accessed by flat instructions. For now this is mostly a poor way of
98   // estimating whether there are calls before argument lowering.
99   if (!IsFunc && HaveCall) {
100     F.addFnAttr("amdgpu-calls");
101     Changed = true;
102   }
103 
104   if (HaveStackObjects) {
105     F.addFnAttr("amdgpu-stack-objects");
106     Changed = true;
107   }
108 
109   return Changed;
110 }
111 
112 bool AMDGPUAnnotateKernelFeatures::runOnSCC(CallGraphSCC &SCC) {
113   bool Changed = false;
114 
115   for (CallGraphNode *I : SCC) {
116     Function *F = I->getFunction();
117     // Ignore functions with graphics calling conventions, these are currently
118     // not allowed to have kernel arguments.
119     if (!F || F->isDeclaration() || AMDGPU::isGraphics(F->getCallingConv()))
120       continue;
121     // Add feature attributes
122     Changed |= addFeatureAttributes(*F);
123   }
124 
125   return Changed;
126 }
127 
128 bool AMDGPUAnnotateKernelFeatures::doInitialization(CallGraph &CG) {
129   auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
130   if (!TPC)
131     report_fatal_error("TargetMachine is required");
132 
133   TM = &TPC->getTM<TargetMachine>();
134   return false;
135 }
136 
137 Pass *llvm::createAMDGPUAnnotateKernelFeaturesPass() {
138   return new AMDGPUAnnotateKernelFeatures();
139 }
140