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