LLVM 20.0.0git
AMDGPUPreloadKernArgProlog.cpp
Go to the documentation of this file.
1//===- AMDGPUPreloadKernArgProlog.cpp - Preload KernArg Prolog ------------===//
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 This pass creates a backward compatibility layer for kernel argument
10/// preloading in situations where code is compiled with kernel argument
11/// preloading enabled but executed on hardware without firmware support for it.
12///
13/// To avoid recompilation, the pass inserts a block at the beginning of the
14/// program that loads the kernel arguments into SGPRs using s_load
15/// instructions. This sets up the registers exactly as they would be on systems
16/// with compatible firmware.
17///
18/// This effectively creates two entry points for the kernel. Firmware that
19/// supports the feature will automatically jump past the first 256 bytes of the
20/// program, skipping the compatibility layer and directly starting execution on
21/// the optimized code path.
22///
23/// This pass should be run as late as possible to prevent any optimizations
24/// that might assume the padding is dead code or that the added prologue is a
25/// true predecessor of the kernel entry block.
26//
27//===----------------------------------------------------------------------===//
28
30#include "AMDGPU.h"
31#include "GCNSubtarget.h"
35
36using namespace llvm;
37
38#define DEBUG_TYPE "amdgpu-preload-kern-arg-prolog"
39
40namespace {
41
42// Used to build s_loads maping user SGPRs to kernel arguments
43struct LoadConfig {
44 unsigned Size;
45 const TargetRegisterClass *RegClass;
46 unsigned Opcode;
47 Register LoadReg = Register();
48};
49
50class AMDGPUPreloadKernArgProlog {
51public:
52 AMDGPUPreloadKernArgProlog(MachineFunction &MF);
53
54 bool run();
55
56private:
58 const GCNSubtarget &ST;
59 const SIMachineFunctionInfo &MFI;
60 const SIInstrInfo &TII;
62
63 // Create a new block before the entry point to the kernel. Firmware that
64 // supports preloading kernel arguments will automatically jump past this
65 // block to the alternative kernel entry point.
66 void createBackCompatBlock(unsigned NumKernArgPreloadSGPRs);
67
68 // Add instructions to load kernel arguments into SGPRs.
69 void addBackCompatLoads(MachineBasicBlock *BackCompatMBB,
70 Register KernArgSegmentPtr,
71 unsigned NumKernArgPreloadSGPRs);
72};
73
74class AMDGPUPreloadKernArgPrologLegacy : public MachineFunctionPass {
75public:
76 static char ID;
77
78 AMDGPUPreloadKernArgPrologLegacy() : MachineFunctionPass(ID) {}
79
80 StringRef getPassName() const override {
81 return "AMDGPU Preload Kernel Arguments Prolog";
82 }
83
84 bool runOnMachineFunction(MachineFunction &MF) override;
85};
86
87} // end anonymous namespace
88
89char AMDGPUPreloadKernArgPrologLegacy::ID = 0;
90
91INITIALIZE_PASS(AMDGPUPreloadKernArgPrologLegacy, DEBUG_TYPE,
92 "AMDGPU Preload Kernel Arguments Prolog", false, false)
93
95 AMDGPUPreloadKernArgPrologLegacy::ID;
96
98 return new AMDGPUPreloadKernArgPrologLegacy();
99}
100
101bool AMDGPUPreloadKernArgPrologLegacy::runOnMachineFunction(
102 MachineFunction &MF) {
103 return AMDGPUPreloadKernArgProlog(MF).run();
104}
105
106AMDGPUPreloadKernArgProlog::AMDGPUPreloadKernArgProlog(MachineFunction &MF)
107 : MF(MF), ST(MF.getSubtarget<GCNSubtarget>()),
108 MFI(*MF.getInfo<SIMachineFunctionInfo>()), TII(*ST.getInstrInfo()),
109 TRI(*ST.getRegisterInfo()) {}
110
111bool AMDGPUPreloadKernArgProlog::run() {
112 if (!ST.hasKernargPreload())
113 return false;
114
115 unsigned NumKernArgPreloadSGPRs = MFI.getNumKernargPreloadedSGPRs();
116 if (!NumKernArgPreloadSGPRs)
117 return false;
118
119 createBackCompatBlock(NumKernArgPreloadSGPRs);
120 return true;
121}
122
123void AMDGPUPreloadKernArgProlog::createBackCompatBlock(
124 unsigned NumKernArgPreloadSGPRs) {
125 auto KernelEntryMBB = MF.begin();
126 MachineBasicBlock *BackCompatMBB = MF.CreateMachineBasicBlock();
127 MF.insert(KernelEntryMBB, BackCompatMBB);
128
129 assert(MFI.getUserSGPRInfo().hasKernargSegmentPtr() &&
130 "Kernel argument segment pointer register not set.");
131 Register KernArgSegmentPtr = MFI.getArgInfo().KernargSegmentPtr.getRegister();
132 BackCompatMBB->addLiveIn(KernArgSegmentPtr);
133
134 // Load kernel arguments to SGPRs
135 addBackCompatLoads(BackCompatMBB, KernArgSegmentPtr, NumKernArgPreloadSGPRs);
136
137 // Wait for loads to complete
139 unsigned Waitcnt =
141 BuildMI(BackCompatMBB, DebugLoc(), TII.get(AMDGPU::S_WAITCNT))
142 .addImm(Waitcnt);
143
144 // Branch to kernel start
145 BuildMI(BackCompatMBB, DebugLoc(), TII.get(AMDGPU::S_BRANCH))
146 .addMBB(&*KernelEntryMBB);
147 BackCompatMBB->addSuccessor(&*KernelEntryMBB);
148
149 // Create a new basic block for padding to 256 bytes
151 MF.insert(++BackCompatMBB->getIterator(), PadMBB);
152 PadMBB->setAlignment(Align(256));
153 PadMBB->addSuccessor(&*KernelEntryMBB);
154}
155
156/// Find the largest possible load size that fits with SGPR alignment
157static LoadConfig getLoadParameters(const TargetRegisterInfo &TRI,
158 Register KernArgPreloadSGPR,
159 unsigned NumKernArgPreloadSGPRs) {
160 static constexpr LoadConfig Configs[] = {
161 {8, &AMDGPU::SReg_256RegClass, AMDGPU::S_LOAD_DWORDX8_IMM},
162 {4, &AMDGPU::SReg_128RegClass, AMDGPU::S_LOAD_DWORDX4_IMM},
163 {2, &AMDGPU::SReg_64RegClass, AMDGPU::S_LOAD_DWORDX2_IMM}};
164
165 for (const auto &Config : Configs) {
166 if (NumKernArgPreloadSGPRs >= Config.Size) {
167 Register LoadReg = TRI.getMatchingSuperReg(KernArgPreloadSGPR,
168 AMDGPU::sub0, Config.RegClass);
169 if (LoadReg) {
170 LoadConfig C(Config);
171 C.LoadReg = LoadReg;
172 return C;
173 }
174 }
175 }
176
177 // Fallback to a single register
178 return LoadConfig{1, &AMDGPU::SReg_32RegClass, AMDGPU::S_LOAD_DWORD_IMM,
179 KernArgPreloadSGPR};
180}
181
182void AMDGPUPreloadKernArgProlog::addBackCompatLoads(
183 MachineBasicBlock *BackCompatMBB, Register KernArgSegmentPtr,
184 unsigned NumKernArgPreloadSGPRs) {
185 Register KernArgPreloadSGPR = MFI.getArgInfo().FirstKernArgPreloadReg;
186 unsigned Offset = 0;
187 // Fill all user SGPRs used for kernarg preloading with sequential data from
188 // the kernarg segment
189 while (NumKernArgPreloadSGPRs > 0) {
190 LoadConfig Config =
191 getLoadParameters(TRI, KernArgPreloadSGPR, NumKernArgPreloadSGPRs);
192
193 BuildMI(BackCompatMBB, DebugLoc(), TII.get(Config.Opcode), Config.LoadReg)
194 .addReg(KernArgSegmentPtr)
195 .addImm(Offset)
196 .addImm(0);
197
198 Offset += 4 * Config.Size;
199 KernArgPreloadSGPR = KernArgPreloadSGPR.asMCReg() + Config.Size;
200 NumKernArgPreloadSGPRs -= Config.Size;
201 }
202}
203
207 if (!AMDGPUPreloadKernArgProlog(MF).run())
208 return PreservedAnalyses::all();
209
211}
static LoadConfig getLoadParameters(const TargetRegisterInfo &TRI, Register KernArgPreloadSGPR, unsigned NumKernArgPreloadSGPRs)
Find the largest possible load size that fits with SGPR alignment.
#define DEBUG_TYPE
RelaxConfig Config
Definition: ELF_riscv.cpp:506
AMD GCN specific subclass of TargetSubtarget.
const HexagonInstrInfo * TII
unsigned const TargetRegisterInfo * TRI
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static const uint32_t IV[8]
Definition: blake3_impl.h:78
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &AM)
A container for analyses that lazily runs them and caches their results.
Definition: PassManager.h:253
A debug info location.
Definition: DebugLoc.h:33
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:310
void setAlignment(Align A)
Set alignment of the basic block.
void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
void addLiveIn(MCRegister PhysReg, LaneBitmask LaneMask=LaneBitmask::getAll())
Adds the specified register as a live in.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineBasicBlock - Allocate a new MachineBasicBlock.
void insert(iterator MBBI, MachineBasicBlock *MBB)
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Definition: Pass.cpp:81
A set of analyses that are preserved following a run of a transformation pass.
Definition: Analysis.h:111
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition: Analysis.h:114
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition: Analysis.h:117
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
MCRegister asMCReg() const
Utility to check-convert this value to a MCRegister.
Definition: Register.h:110
This class keeps track of the SPI_SP_INPUT_ADDR config register, which tells the hardware which inter...
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:51
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
self_iterator getIterator()
Definition: ilist_node.h:132
IsaVersion getIsaVersion(StringRef GPU)
unsigned encodeWaitcnt(const IsaVersion &Version, unsigned Vmcnt, unsigned Expcnt, unsigned Lgkmcnt)
Encodes Vmcnt, Expcnt and Lgkmcnt into Waitcnt for given isa Version.
unsigned getVmcntBitMask(const IsaVersion &Version)
unsigned getExpcntBitMask(const IsaVersion &Version)
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
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.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:480
char & AMDGPUPreloadKernArgPrologLegacyID
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
FunctionPass * createAMDGPUPreloadKernArgPrologLegacyPass()
Instruction set architecture version.
Definition: TargetParser.h:130
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39