| //===- AMDGPUAnnotateKernelFeaturesPass.cpp -------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| /// \file This pass propagates the uniform-work-group-size attribute from |
| /// kernels to leaf functions when possible. It also adds additional attributes |
| /// to hint ABI lowering optimizations later. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "AMDGPU.h" |
| #include "GCNSubtarget.h" |
| #include "llvm/Analysis/CallGraph.h" |
| #include "llvm/Analysis/CallGraphSCCPass.h" |
| #include "llvm/CodeGen/TargetPassConfig.h" |
| #include "llvm/IR/IntrinsicsAMDGPU.h" |
| #include "llvm/IR/IntrinsicsR600.h" |
| #include "llvm/Target/TargetMachine.h" |
| |
| #define DEBUG_TYPE "amdgpu-annotate-kernel-features" |
| |
| using namespace llvm; |
| |
| namespace { |
| class AMDGPUAnnotateKernelFeatures : public CallGraphSCCPass { |
| private: |
| const TargetMachine *TM = nullptr; |
| |
| bool addFeatureAttributes(Function &F); |
| |
| public: |
| static char ID; |
| |
| AMDGPUAnnotateKernelFeatures() : CallGraphSCCPass(ID) {} |
| |
| bool doInitialization(CallGraph &CG) override; |
| bool runOnSCC(CallGraphSCC &SCC) override; |
| |
| StringRef getPassName() const override { |
| return "AMDGPU Annotate Kernel Features"; |
| } |
| |
| void getAnalysisUsage(AnalysisUsage &AU) const override { |
| AU.setPreservesAll(); |
| CallGraphSCCPass::getAnalysisUsage(AU); |
| } |
| }; |
| |
| } // end anonymous namespace |
| |
| char AMDGPUAnnotateKernelFeatures::ID = 0; |
| |
| char &llvm::AMDGPUAnnotateKernelFeaturesID = AMDGPUAnnotateKernelFeatures::ID; |
| |
| INITIALIZE_PASS(AMDGPUAnnotateKernelFeatures, DEBUG_TYPE, |
| "Add AMDGPU function attributes", false, false) |
| |
| bool AMDGPUAnnotateKernelFeatures::addFeatureAttributes(Function &F) { |
| bool HaveStackObjects = false; |
| bool Changed = false; |
| bool HaveCall = false; |
| bool IsFunc = !AMDGPU::isEntryFunctionCC(F.getCallingConv()); |
| |
| for (BasicBlock &BB : F) { |
| for (Instruction &I : BB) { |
| if (isa<AllocaInst>(I)) { |
| HaveStackObjects = true; |
| continue; |
| } |
| |
| if (auto *CB = dyn_cast<CallBase>(&I)) { |
| const Function *Callee = |
| dyn_cast<Function>(CB->getCalledOperand()->stripPointerCasts()); |
| |
| // Note the occurrence of indirect call. |
| if (!Callee) { |
| if (!CB->isInlineAsm()) |
| HaveCall = true; |
| |
| continue; |
| } |
| |
| Intrinsic::ID IID = Callee->getIntrinsicID(); |
| if (IID == Intrinsic::not_intrinsic) { |
| HaveCall = true; |
| Changed = true; |
| } |
| } |
| } |
| } |
| |
| // TODO: We could refine this to captured pointers that could possibly be |
| // accessed by flat instructions. For now this is mostly a poor way of |
| // estimating whether there are calls before argument lowering. |
| if (!IsFunc && HaveCall) { |
| F.addFnAttr("amdgpu-calls"); |
| Changed = true; |
| } |
| |
| if (HaveStackObjects) { |
| F.addFnAttr("amdgpu-stack-objects"); |
| Changed = true; |
| } |
| |
| return Changed; |
| } |
| |
| bool AMDGPUAnnotateKernelFeatures::runOnSCC(CallGraphSCC &SCC) { |
| bool Changed = false; |
| |
| for (CallGraphNode *I : SCC) { |
| Function *F = I->getFunction(); |
| // Ignore functions with graphics calling conventions, these are currently |
| // not allowed to have kernel arguments. |
| if (!F || F->isDeclaration() || AMDGPU::isGraphics(F->getCallingConv())) |
| continue; |
| // Add feature attributes |
| Changed |= addFeatureAttributes(*F); |
| } |
| |
| return Changed; |
| } |
| |
| bool AMDGPUAnnotateKernelFeatures::doInitialization(CallGraph &CG) { |
| auto *TPC = getAnalysisIfAvailable<TargetPassConfig>(); |
| if (!TPC) |
| report_fatal_error("TargetMachine is required"); |
| |
| TM = &TPC->getTM<TargetMachine>(); |
| return false; |
| } |
| |
| Pass *llvm::createAMDGPUAnnotateKernelFeaturesPass() { |
| return new AMDGPUAnnotateKernelFeatures(); |
| } |