| //===- 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(); | |
| } |