LLVM 23.0.0git
AMDGPURemoveIncompatibleFunctions.cpp
Go to the documentation of this file.
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
16#include "AMDGPU.h"
17#include "GCNSubtarget.h"
19#include "llvm/IR/Function.h"
20#include "llvm/IR/Module.h"
21#include "llvm/Pass.h"
23
24#define DEBUG_TYPE "amdgpu-remove-incompatible-functions"
25
26using namespace llvm;
27
28namespace {
29
30using Generation = AMDGPUSubtarget::Generation;
31
32class AMDGPURemoveIncompatibleFunctions {
33public:
34 AMDGPURemoveIncompatibleFunctions(const TargetMachine *TM = nullptr)
35 : TM(TM) {
36 assert(TM && "No TargetMachine!");
37 }
38 /// Checks a single function, returns true if the function must be deleted.
39 bool checkFunction(Function &F);
40
41 bool run(Module &M) {
42 assert(TM->getTargetTriple().isAMDGCN());
43
45 for (Function &F : M) {
46 if (checkFunction(F))
47 FnsToDelete.push_back(&F);
48 }
49
50 for (Function *F : FnsToDelete) {
51 F->replaceAllUsesWith(ConstantPointerNull::get(F->getType()));
52 F->eraseFromParent();
53 }
54 return !FnsToDelete.empty();
55 }
56
57private:
58 const TargetMachine *TM = nullptr;
59};
60
61class AMDGPURemoveIncompatibleFunctionsLegacy : public ModulePass {
62public:
63 static char ID;
64
65 AMDGPURemoveIncompatibleFunctionsLegacy(const TargetMachine *TM)
66 : ModulePass(ID), TM(TM) {}
67
68 bool runOnModule(Module &M) override {
69 AMDGPURemoveIncompatibleFunctions Pass(TM);
70 return Pass.run(M);
71 }
72
73 StringRef getPassName() const override {
74 return "AMDGPU Remove Incompatible Functions";
75 }
76
77 void getAnalysisUsage(AnalysisUsage &AU) const override {}
78
79private:
80 const TargetMachine *TM = nullptr;
81};
82
83StringRef getFeatureName(const GCNSubtarget &ST, unsigned Feature) {
84 for (const SubtargetFeatureKV &KV : ST.getAllProcessorFeatures())
85 if (Feature == KV.Value)
86 return KV.key();
87
88 llvm_unreachable("Unknown Target feature");
89}
90
91const SubtargetSubTypeKV *getGPUInfo(const GCNSubtarget &ST,
92 StringRef GPUName) {
93 for (const SubtargetSubTypeKV &KV : ST.getAllProcessorDescriptions())
94 if (StringRef(KV.key()) == GPUName)
95 return &KV;
96
97 return nullptr;
98}
99
100constexpr unsigned FeaturesToCheck[] = {AMDGPU::FeatureGFX11Insts,
101 AMDGPU::FeatureGFX10Insts,
102 AMDGPU::FeatureGFX9Insts,
103 AMDGPU::FeatureGFX8Insts,
104 AMDGPU::FeatureDPP,
105 AMDGPU::FeatureDPPWavefrontShifts,
106 AMDGPU::FeatureDPPBroadcasts,
107 AMDGPU::Feature16BitInsts,
108 AMDGPU::FeatureDot1Insts,
109 AMDGPU::FeatureDot2Insts,
110 AMDGPU::FeatureDot3Insts,
111 AMDGPU::FeatureDot4Insts,
112 AMDGPU::FeatureDot5Insts,
113 AMDGPU::FeatureDot6Insts,
114 AMDGPU::FeatureDot7Insts,
115 AMDGPU::FeatureDot8Insts,
116 AMDGPU::FeatureExtendedImageInsts,
117 AMDGPU::FeatureSMemRealTime,
118 AMDGPU::FeatureSMemTimeInst,
119 AMDGPU::FeatureGWS};
120
121FeatureBitset expandImpliedFeatures(const GCNSubtarget &ST,
122 const FeatureBitset &Features) {
123 FeatureBitset Result = Features;
124 for (const SubtargetFeatureKV &FE : ST.getAllProcessorFeatures()) {
125 if (Features.test(FE.Value) && FE.Implies.any())
126 Result |= expandImpliedFeatures(ST, FE.Implies.getAsBitset());
127 }
128 return Result;
129}
130
131void reportFunctionRemoved(Function &F, const GCNSubtarget &ST,
132 unsigned Feature) {
134 ORE.emit([&]() {
135 // Note: we print the function name as part of the diagnostic because if
136 // debug info is not present, users get "<unknown>:0:0" as the debug
137 // loc. If we didn't print the function name there would be no way to
138 // tell which function got removed.
139 return OptimizationRemark(DEBUG_TYPE, "AMDGPUIncompatibleFnRemoved", &F)
140 << "removing function '" << F.getName() << "': +"
141 << getFeatureName(ST, Feature)
142 << " is not supported on the current target";
143 });
144}
145} // end anonymous namespace
146
150 AMDGPURemoveIncompatibleFunctions Impl(TM);
151 if (Impl.run(M))
153 return PreservedAnalyses::all();
154}
155
156bool AMDGPURemoveIncompatibleFunctions::checkFunction(Function &F) {
157 if (F.isDeclaration())
158 return false;
159
160 const GCNSubtarget *ST =
161 static_cast<const GCNSubtarget *>(TM->getSubtargetImpl(F));
162
163 // Check the GPU isn't generic or generic-hsa. Generic is used for testing
164 // only and we don't want this pass to interfere with it.
165 StringRef GPUName = ST->getCPU();
166 if (GPUName.empty() || GPUName.starts_with("generic"))
167 return false;
168
169 // Try to fetch the GPU's info. If we can't, it's likely an unknown processor
170 // so just bail out.
171 const SubtargetSubTypeKV *GPUInfo = getGPUInfo(*ST, GPUName);
172 if (!GPUInfo)
173 return false;
174
175 // Get all the features implied by the current GPU, and recursively expand
176 // the features that imply other features.
177 //
178 // e.g. GFX90A implies FeatureGFX9, and FeatureGFX9 implies a whole set of
179 // other features.
180 const FeatureBitset GPUFeatureBits =
181 expandImpliedFeatures(*ST, GPUInfo->Implies.getAsBitset());
182
183 // Now that the have a FeatureBitset containing all possible features for
184 // the chosen GPU, check our list of "suspicious" features.
185
186 // Check that the user didn't enable any features that aren't part of that
187 // GPU's feature set. We only check a predetermined set of features.
188 for (unsigned Feature : FeaturesToCheck) {
189 if (ST->hasFeature(Feature) && !GPUFeatureBits.test(Feature)) {
190 reportFunctionRemoved(F, *ST, Feature);
191 return true;
192 }
193 }
194
195 // Delete FeatureWavefrontSize32 functions for
196 // gfx9 and below targets that don't support the mode.
197 // gfx10, gfx11, gfx12 are implied to support both wave32 and 64 features.
198 // They are not in the feature set. So, we need a separate check
199 if (!ST->supportsWave32() && ST->hasFeature(AMDGPU::FeatureWavefrontSize32)) {
200 reportFunctionRemoved(F, *ST, AMDGPU::FeatureWavefrontSize32);
201 return true;
202 }
203 // gfx125x only support FeatureWavefrontSize32.
204 if (!ST->supportsWave64() && ST->hasFeature(AMDGPU::FeatureWavefrontSize64)) {
205 reportFunctionRemoved(F, *ST, AMDGPU::FeatureWavefrontSize64);
206 return true;
207 }
208 return false;
209}
210
211INITIALIZE_PASS(AMDGPURemoveIncompatibleFunctionsLegacy, DEBUG_TYPE,
212 "AMDGPU Remove Incompatible Functions", false, false)
213
214char AMDGPURemoveIncompatibleFunctionsLegacy::ID = 0;
215
218 return new AMDGPURemoveIncompatibleFunctionsLegacy(TM);
219}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
aarch64 promote const
AMD GCN specific subclass of TargetSubtarget.
#define DEBUG_TYPE
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:54
print mir2vec MIR2Vec Vocabulary Printer Pass
Definition MIR2Vec.cpp:598
ModuleAnalysisManager MAM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
Represent the analysis usage information of a pass.
static LLVM_ABI ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
const FeatureBitset & getAsBitset() const
Container class for subtarget features.
constexpr bool test(unsigned I) const
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition Pass.h:255
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
The optimization diagnostic interface.
LLVM_ABI void emit(DiagnosticInfoOptimizationBase &OptDiag)
Output the remark via the diagnostic handler and to the optimization record file.
Diagnostic information for applied optimization remarks.
Pass interface - Implemented by all 'passes'.
Definition Pass.h:99
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition StringRef.h:258
constexpr bool empty() const
Check if the string is empty.
Definition StringRef.h:141
Primary interface to the complete machine description for the target machine.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
ModulePass * createAMDGPURemoveIncompatibleFunctionsPass(const TargetMachine *)
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
Used to provide key value pairs for feature and CPU bit flags.
Used to provide key value pairs for feature and CPU bit flags.
FeatureBitArray Implies
K-V bit mask.