1 //===-- AMDGPURemoveIncompatibleFunctions.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
10 /// This pass replaces all uses of functions that use GPU features
11 /// incompatible with the current GPU with null then deletes the function.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "AMDGPU.h"
16 #include "GCNSubtarget.h"
17 #include "llvm/Analysis/OptimizationRemarkEmitter.h"
18 #include "llvm/IR/Function.h"
19 #include "llvm/IR/IRBuilder.h"
20 #include "llvm/IR/Module.h"
21 #include "llvm/Pass.h"
22 #include "llvm/Target/TargetMachine.h"
23
24 #define DEBUG_TYPE "amdgpu-remove-incompatible-functions"
25
26 using namespace llvm;
27
28 namespace llvm {
29 extern const SubtargetFeatureKV
30 AMDGPUFeatureKV[AMDGPU::NumSubtargetFeatures - 1];
31 } // namespace llvm
32
33 namespace {
34
35 using Generation = AMDGPUSubtarget::Generation;
36
37 class AMDGPURemoveIncompatibleFunctions : public ModulePass {
38 public:
39 static char ID;
40
AMDGPURemoveIncompatibleFunctions(const TargetMachine * TM=nullptr)41 AMDGPURemoveIncompatibleFunctions(const TargetMachine *TM = nullptr)
42 : ModulePass(ID), TM(TM) {
43 assert(TM && "No TargetMachine!");
44 }
45
getPassName() const46 StringRef getPassName() const override {
47 return "AMDGPU Remove Incompatible Functions";
48 }
49
getAnalysisUsage(AnalysisUsage & AU) const50 void getAnalysisUsage(AnalysisUsage &AU) const override {}
51
52 /// Checks a single function, returns true if the function must be deleted.
53 bool checkFunction(Function &F);
54
runOnModule(Module & M)55 bool runOnModule(Module &M) override {
56 assert(TM->getTargetTriple().isAMDGCN());
57
58 SmallVector<Function *, 4> FnsToDelete;
59 for (Function &F : M) {
60 if (checkFunction(F))
61 FnsToDelete.push_back(&F);
62 }
63
64 for (Function *F : FnsToDelete) {
65 F->replaceAllUsesWith(ConstantPointerNull::get(F->getType()));
66 F->eraseFromParent();
67 }
68 return !FnsToDelete.empty();
69 }
70
71 private:
72 const TargetMachine *TM = nullptr;
73 };
74
getFeatureName(unsigned Feature)75 StringRef getFeatureName(unsigned Feature) {
76 for (const SubtargetFeatureKV &KV : AMDGPUFeatureKV)
77 if (Feature == KV.Value)
78 return KV.Key;
79
80 llvm_unreachable("Unknown Target feature");
81 }
82
getGPUInfo(const GCNSubtarget & ST,StringRef GPUName)83 const SubtargetSubTypeKV *getGPUInfo(const GCNSubtarget &ST,
84 StringRef GPUName) {
85 for (const SubtargetSubTypeKV &KV : ST.getAllProcessorDescriptions())
86 if (StringRef(KV.Key) == GPUName)
87 return &KV;
88
89 return nullptr;
90 }
91
92 constexpr unsigned FeaturesToCheck[] = {AMDGPU::FeatureGFX11Insts,
93 AMDGPU::FeatureGFX10Insts,
94 AMDGPU::FeatureGFX9Insts,
95 AMDGPU::FeatureGFX8Insts,
96 AMDGPU::FeatureDPP,
97 AMDGPU::Feature16BitInsts,
98 AMDGPU::FeatureDot1Insts,
99 AMDGPU::FeatureDot2Insts,
100 AMDGPU::FeatureDot3Insts,
101 AMDGPU::FeatureDot4Insts,
102 AMDGPU::FeatureDot5Insts,
103 AMDGPU::FeatureDot6Insts,
104 AMDGPU::FeatureDot7Insts,
105 AMDGPU::FeatureDot8Insts,
106 AMDGPU::FeatureExtendedImageInsts,
107 AMDGPU::FeatureSMemRealTime,
108 AMDGPU::FeatureSMemTimeInst,
109 AMDGPU::FeatureGWS};
110
expandImpliedFeatures(const FeatureBitset & Features)111 FeatureBitset expandImpliedFeatures(const FeatureBitset &Features) {
112 FeatureBitset Result = Features;
113 for (const SubtargetFeatureKV &FE : AMDGPUFeatureKV) {
114 if (Features.test(FE.Value) && FE.Implies.any())
115 Result |= expandImpliedFeatures(FE.Implies.getAsBitset());
116 }
117 return Result;
118 }
119
reportFunctionRemoved(Function & F,unsigned Feature)120 void reportFunctionRemoved(Function &F, unsigned Feature) {
121 OptimizationRemarkEmitter ORE(&F);
122 ORE.emit([&]() {
123 // Note: we print the function name as part of the diagnostic because if
124 // debug info is not present, users get "<unknown>:0:0" as the debug
125 // loc. If we didn't print the function name there would be no way to
126 // tell which function got removed.
127 return OptimizationRemark(DEBUG_TYPE, "AMDGPUIncompatibleFnRemoved", &F)
128 << "removing function '" << F.getName() << "': +"
129 << getFeatureName(Feature)
130 << " is not supported on the current target";
131 });
132 }
133 } // end anonymous namespace
134
checkFunction(Function & F)135 bool AMDGPURemoveIncompatibleFunctions::checkFunction(Function &F) {
136 if (F.isDeclaration())
137 return false;
138
139 const GCNSubtarget *ST =
140 static_cast<const GCNSubtarget *>(TM->getSubtargetImpl(F));
141
142 // Check the GPU isn't generic or generic-hsa. Generic is used for testing
143 // only and we don't want this pass to interfere with it.
144 StringRef GPUName = ST->getCPU();
145 if (GPUName.empty() || GPUName.starts_with("generic"))
146 return false;
147
148 // Try to fetch the GPU's info. If we can't, it's likely an unknown processor
149 // so just bail out.
150 const SubtargetSubTypeKV *GPUInfo = getGPUInfo(*ST, GPUName);
151 if (!GPUInfo)
152 return false;
153
154 // Get all the features implied by the current GPU, and recursively expand
155 // the features that imply other features.
156 //
157 // e.g. GFX90A implies FeatureGFX9, and FeatureGFX9 implies a whole set of
158 // other features.
159 const FeatureBitset GPUFeatureBits =
160 expandImpliedFeatures(GPUInfo->Implies.getAsBitset());
161
162 // Now that the have a FeatureBitset containing all possible features for
163 // the chosen GPU, check our list of "suspicious" features.
164
165 // Check that the user didn't enable any features that aren't part of that
166 // GPU's feature set. We only check a predetermined set of features.
167 for (unsigned Feature : FeaturesToCheck) {
168 if (ST->hasFeature(Feature) && !GPUFeatureBits.test(Feature)) {
169 reportFunctionRemoved(F, Feature);
170 return true;
171 }
172 }
173
174 // Delete FeatureWavefrontSize32 functions for
175 // gfx9 and below targets that don't support the mode.
176 // gfx10+ is implied to support both wave32 and 64 features.
177 // They are not in the feature set. So, we need a separate check
178 if (ST->getGeneration() < AMDGPUSubtarget::GFX10 &&
179 ST->hasFeature(AMDGPU::FeatureWavefrontSize32)) {
180 reportFunctionRemoved(F, AMDGPU::FeatureWavefrontSize32);
181 return true;
182 }
183 return false;
184 }
185
186 INITIALIZE_PASS(AMDGPURemoveIncompatibleFunctions, DEBUG_TYPE,
187 "AMDGPU Remove Incompatible Functions", false, false)
188
189 char AMDGPURemoveIncompatibleFunctions::ID = 0;
190
191 ModulePass *
createAMDGPURemoveIncompatibleFunctionsPass(const TargetMachine * TM)192 llvm::createAMDGPURemoveIncompatibleFunctionsPass(const TargetMachine *TM) {
193 return new AMDGPURemoveIncompatibleFunctions(TM);
194 }
195