33#define DEBUG_TYPE "amdgpu-perf-hint"
35STATISTIC(NumMemBound,
"Number of functions marked as memory bound");
36STATISTIC(NumLimitWave,
"Number of functions marked as needing limit wave");
40struct AMDGPUPerfHint {
44 AMDGPUPerfHint(
const AMDGPUOptions &CLOpts,
47 : CLOpts(CLOpts), FIM(FIM_),
TLI(TLI_) {}
52 struct MemAccessInfo {
53 const Value *V =
nullptr;
54 const Value *Base =
nullptr;
56 MemAccessInfo() =
default;
57 bool isLargeStride(MemAccessInfo &Reference,
58 unsigned LargeStrideThresh)
const;
59#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
60 Printable
print()
const {
61 return Printable([
this](raw_ostream &OS) {
62 OS <<
"Value: " << *V <<
'\n'
63 <<
"Base: " << *Base <<
" Offset: " << Offset <<
'\n';
69 MemAccessInfo makeMemAccessInfo(Instruction *)
const;
71 const AMDGPUOptions &CLOpts;
73 MemAccessInfo LastAccess;
77 const DataLayout *DL =
nullptr;
79 const SITargetLowering *TLI;
82 static bool isMemBound(
const AMDGPUOptions &CLOpts,
83 const AMDGPUPerfHintAnalysis::FuncInfo &
F);
84 static bool needLimitWave(
const AMDGPUOptions &CLOpts,
85 const AMDGPUPerfHintAnalysis::FuncInfo &
F);
87 bool isIndirectAccess(
const Instruction *Inst)
const;
96 bool isLargeStride(
const Instruction *Inst);
98 bool isGlobalAddr(
const Value *
V)
const;
99 bool isLocalAddr(
const Value *
V)
const;
100 bool isGlobalLoadUsedInBB(
const Instruction &)
const;
103static std::pair<const Value *, const Type *> getMemoryInstrPtrAndType(
106 return {LI->getPointerOperand(), LI->getType()};
108 return {
SI->getPointerOperand(),
SI->getValueOperand()->getType()};
110 return {AI->getPointerOperand(), AI->getCompareOperand()->getType()};
112 return {AI->getPointerOperand(), AI->getValOperand()->getType()};
116 return {
nullptr,
nullptr};
119bool AMDGPUPerfHint::isIndirectAccess(
const Instruction *Inst)
const {
121 SmallPtrSet<const Value *, 32> WorkSet;
122 SmallPtrSet<const Value *, 32> Visited;
123 if (
const Value *MO = getMemoryInstrPtrAndType(Inst).first) {
124 if (isGlobalAddr(MO))
128 while (!WorkSet.
empty()) {
136 const auto *
M =
LD->getPointerOperand();
137 if (isGlobalAddr(M)) {
145 const auto *
P =
GEP->getPointerOperand();
147 for (
unsigned I = 1,
E =
GEP->getNumIndices() + 1;
I !=
E; ++
I)
153 WorkSet.
insert(
U->getOperand(0));
158 WorkSet.
insert(BO->getOperand(0));
159 WorkSet.
insert(BO->getOperand(1));
164 WorkSet.
insert(S->getFalseValue());
165 WorkSet.
insert(S->getTrueValue());
170 WorkSet.
insert(
E->getVectorOperand());
182bool AMDGPUPerfHint::isGlobalLoadUsedInBB(
const Instruction &
I)
const {
186 if (!isGlobalAddr(Ld->getPointerOperand()))
189 for (
const User *Usr : Ld->users()) {
191 if (UsrInst->getParent() ==
I.getParent())
199AMDGPUPerfHintAnalysis::FuncInfo *AMDGPUPerfHint::visit(
const Function &
F) {
200 AMDGPUPerfHintAnalysis::FuncInfo &FI = FIM[&
F];
202 LLVM_DEBUG(
dbgs() <<
"[AMDGPUPerfHint] process " <<
F.getName() <<
'\n');
205 LastAccess = MemAccessInfo();
208 if (
const Type *Ty = getMemoryInstrPtrAndType(&
I).second) {
212 if (isGlobalLoadUsedInBB(
I))
213 UsedGlobalLoadsInBB +=
Size;
214 if (isIndirectAccess(&
I))
216 if (isLargeStride(&
I))
224 if (!Callee ||
Callee->isDeclaration()) {
231 auto Loc = FIM.
find(Callee);
232 if (Loc == FIM.
end())
236 FI.
InstCost += Loc->second.InstCost;
240 TargetLoweringBase::AddrMode AM;
245 GEP->getPointerAddressSpace()))
255 uint64_t GlobalMemAccPercentage = UsedGlobalLoadsInBB * 100 /
B.size();
256 if (GlobalMemAccPercentage > 50) {
258 <<
B.getName() <<
" has " << GlobalMemAccPercentage
259 <<
"% global memory access\n");
268bool AMDGPUPerfHint::runOnFunction(
Function &
F) {
270 DL = &
M.getDataLayout();
272 if (
F.hasFnAttribute(
"amdgpu-wave-limiter") &&
273 F.hasFnAttribute(
"amdgpu-memory-bound"))
276 const AMDGPUPerfHintAnalysis::FuncInfo *
Info =
visit(
F);
280 <<
" IAMInst cost: " <<
Info->IAMInstCost <<
'\n'
281 <<
" LSMInst cost: " <<
Info->LSMInstCost <<
'\n'
282 <<
" TotalInst cost: " <<
Info->InstCost <<
'\n');
286 if (isMemBound(CLOpts, *Info)) {
289 F.addFnAttr(
"amdgpu-memory-bound",
"true");
294 needLimitWave(CLOpts, *Info)) {
297 F.addFnAttr(
"amdgpu-wave-limiter",
"true");
304bool AMDGPUPerfHint::isMemBound(
const AMDGPUOptions &CLOpts,
305 const AMDGPUPerfHintAnalysis::FuncInfo &FI) {
314bool AMDGPUPerfHint::needLimitWave(
const AMDGPUOptions &CLOpts,
315 const AMDGPUPerfHintAnalysis::FuncInfo &FI) {
318 100 / FI.
InstCost) > CLOpts.limit_wave_threshold;
321bool AMDGPUPerfHint::isGlobalAddr(
const Value *
V)
const {
323 unsigned As = PT->getAddressSpace();
330bool AMDGPUPerfHint::isLocalAddr(
const Value *
V)
const {
336bool AMDGPUPerfHint::isLargeStride(
const Instruction *Inst) {
339 MemAccessInfo MAI = makeMemAccessInfo(
const_cast<Instruction *
>(Inst));
341 MAI.isLargeStride(LastAccess, CLOpts.large_stride_threshold);
343 LastAccess = std::move(MAI);
345 return IsLargeStride;
348AMDGPUPerfHint::MemAccessInfo
349AMDGPUPerfHint::makeMemAccessInfo(Instruction *Inst)
const {
351 const Value *MO = getMemoryInstrPtrAndType(Inst).first;
363bool AMDGPUPerfHint::MemAccessInfo::isLargeStride(
364 MemAccessInfo &Reference,
unsigned LargeStrideThresh)
const {
371 bool Result = Diff > LargeStrideThresh;
373 <<
print() <<
"<=>\n"
374 <<
Reference.print() <<
"Result:" << Result <<
'\n');
378class AMDGPUPerfHintAnalysisLegacy :
public CallGraphSCCPass {
381 AMDGPUPerfHintAnalysis Impl;
386 AMDGPUPerfHintAnalysisLegacy() : CallGraphSCCPass(
ID) {}
388 bool runOnSCC(CallGraphSCC &SCC)
override;
390 void getAnalysisUsage(AnalysisUsage &AU)
const override {
398 auto FI = FIM.find(
F);
402 return AMDGPUPerfHint::isMemBound(
403 F->getContext().getLibraryOptions().get<AMDGPUOptions>(), FI->second);
407 auto FI = FIM.find(
F);
411 return AMDGPUPerfHint::needLimitWave(
412 F->getContext().getLibraryOptions().get<AMDGPUOptions>(), FI->second);
420 if (!
F ||
F->isDeclaration())
424 AMDGPUPerfHint Analyzer(TM.
getCLOpts(), FIM, ST.getTargetLowering());
426 if (Analyzer.runOnFunction(*
F))
443 Function &
F = SCC.begin()->getFunction();
445 if (
F.isDeclaration())
449 AMDGPUPerfHint Analyzer(TM.
getCLOpts(), FIM, ST.getTargetLowering());
450 if (Analyzer.runOnFunction(
F))
458char AMDGPUPerfHintAnalysisLegacy::ID = 0;
462 "Analysis if a function is memory bound",
true,
true)
465 auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
470 return Impl.runOnSCC(TM, SCC);
const TargetLowering & TLI
Analyzes if a function potentially memory bound and if a kernel kernel may benefit from limiting numb...
The AMDGPU TargetMachine interface definition for hw codegen targets.
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val)
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file provides interfaces used to build and manipulate a call graph, which is a very useful tool ...
static bool runOnFunction(Function &F, bool PostInlining)
Implements a lazy call graph analysis and related passes for the new pass manager.
Machine Check Debug Module
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
static void visit(BasicBlock &Start, std::function< bool(BasicBlock *)> op)
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
This file describes how to lower LLVM code to machine code.
Target-Independent Code Generator Pass Configuration Options pass.
bool isMemoryBound(const Function *F) const
bool needsWaveLimiter(const Function *F) const
bool run(const GCNTargetMachine &TM, LazyCallGraph &CG)
bool runOnSCC(const GCNTargetMachine &TM, CallGraphSCC &SCC)
ValueMap< const Function *, FuncInfo > FuncInfoMap
const AMDGPUOptions & getCLOpts() const
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
void setPreservesAll()
Set by analyses that do not transform their input at all.
A node in the call graph for a module.
CallGraphSCC - This is a single SCC that a CallGraphSCCPass is run on.
An analysis pass which computes the call graph for a module.
A RefSCC of the call graph.
An SCC of the call graph.
A lazily constructed view of the call graph of a module.
LLVM_ABI void buildRefSCCs()
iterator_range< postorder_ref_scc_iterator > postorder_ref_sccs()
A Module instance is used to store all the information related to an LLVM module.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserve()
Mark an analysis as preserved.
bool erase(PtrType Ptr)
Remove pointer from the set.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
virtual bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty, unsigned AddrSpace, Instruction *I=nullptr) const
Return true if the addressing mode represented by AM is legal for this target, for a load/store of th...
const STC & getSubtarget(const Function &F) const
This method returns a pointer to the specified type of TargetSubtargetInfo.
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
iterator find(const KeyT &Val)
@ LOCAL_ADDRESS
Address space for local memory.
@ FLAT_ADDRESS
Address space for flat memory.
@ GLOBAL_ADDRESS
Address space for global memory (RAT0, VTX0).
LLVM_READNONE constexpr bool isEntryFunctionCC(CallingConv::ID CC)
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr, unsigned DynamicVGPRBlockSize=0)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Value * GetPointerBaseWithConstantOffset(Value *Ptr, int64_t &Offset, const DataLayout &DL, bool AllowNonInbounds=true)
Analyze the specified pointer to see if it can be expressed as a base pointer plus a constant offset.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
auto dyn_cast_or_null(const Y &Val)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
constexpr T divideCeil(U Numerator, V Denominator)
Returns the integer ceil(Numerator / Denominator).
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
char & AMDGPUPerfHintAnalysisLegacyID
std::unique_ptr< AMDGPUPerfHintAnalysis > Impl
const GCNTargetMachine & TM
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
bool HasDenseGlobalMemAcc