221 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9/// \file10/// This pass replaces all uses of functions that use GPU features11/// 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 26using namespace llvm;27 28namespace llvm {29extern const SubtargetFeatureKV30 AMDGPUFeatureKV[AMDGPU::NumSubtargetFeatures - 1];31} // namespace llvm32 33namespace {34 35using Generation = AMDGPUSubtarget::Generation;36 37class AMDGPURemoveIncompatibleFunctions {38public: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 62private:63 const TargetMachine *TM = nullptr;64};65 66class AMDGPURemoveIncompatibleFunctionsLegacy : public ModulePass {67public: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 84private:85 const TargetMachine *TM = nullptr;86};87 88StringRef 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 96const 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 105constexpr 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 124FeatureBitset 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 133void 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 if137 // debug info is not present, users get "<unknown>:0:0" as the debug138 // loc. If we didn't print the function name there would be no way to139 // 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 namespace147 148PreservedAnalyses149AMDGPURemoveIncompatibleFunctionsPass::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 157bool 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 testing165 // 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 processor171 // 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 expand177 // the features that imply other features.178 //179 // e.g. GFX90A implies FeatureGFX9, and FeatureGFX9 implies a whole set of180 // other features.181 const FeatureBitset GPUFeatureBits =182 expandImpliedFeatures(GPUInfo->Implies.getAsBitset());183 184 // Now that the have a FeatureBitset containing all possible features for185 // 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 that188 // 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 for197 // gfx9 and below targets that don't support the mode.198 // gfx10, gfx11, gfx12 are implied to support both wave32 and 64 features.199 // They are not in the feature set. So, we need a separate check200 if (!ST->supportsWave32() && ST->hasFeature(AMDGPU::FeatureWavefrontSize32)) {201 reportFunctionRemoved(F, AMDGPU::FeatureWavefrontSize32);202 return true;203 }204 // gfx125x only support FeatureWavefrontSize32.205 if (!ST->supportsWave64() && ST->hasFeature(AMDGPU::FeatureWavefrontSize64)) {206 reportFunctionRemoved(F, AMDGPU::FeatureWavefrontSize64);207 return true;208 }209 return false;210}211 212INITIALIZE_PASS(AMDGPURemoveIncompatibleFunctionsLegacy, DEBUG_TYPE,213 "AMDGPU Remove Incompatible Functions", false, false)214 215char AMDGPURemoveIncompatibleFunctionsLegacy::ID = 0;216 217ModulePass *218llvm::createAMDGPURemoveIncompatibleFunctionsPass(const TargetMachine *TM) {219 return new AMDGPURemoveIncompatibleFunctionsLegacy(TM);220}221