21#define DEBUG_TYPE "amdgpu-insert-delay-alu"
25class AMDGPUInsertDelayAlu {
40 if (
MI.getOpcode() == AMDGPU::S_SENDMSG_RTN_B32 ||
41 MI.getOpcode() == AMDGPU::S_SENDMSG_RTN_B64)
43 if (
MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
49 static bool instructionWaitsForSGPRWrites(
const MachineInstr &
MI) {
55 for (
auto &
Op :
MI.operands()) {
64 enum DelayType { VALU, TRANS, SALU, OTHER };
89 static constexpr unsigned VALU_MAX = 5;
93 static constexpr unsigned TRANS_MAX = 4;
97 static constexpr unsigned SALU_CYCLES_MAX = 4;
114 uint8_t TRANSNumVALU = VALU_MAX;
120 DelayInfo() =
default;
122 DelayInfo(DelayType
Type,
unsigned Cycles) {
131 TRANSCycles = Cycles;
138 SALUCycles = std::min(Cycles, SALU_CYCLES_MAX);
144 return VALUCycles ==
RHS.VALUCycles && VALUNum ==
RHS.VALUNum &&
145 TRANSCycles ==
RHS.TRANSCycles && TRANSNum ==
RHS.TRANSNum &&
146 TRANSNumVALU ==
RHS.TRANSNumVALU && SALUCycles ==
RHS.SALUCycles;
154 VALUCycles = std::max(VALUCycles,
RHS.VALUCycles);
155 VALUNum = std::min(VALUNum,
RHS.VALUNum);
156 TRANSCycles = std::max(TRANSCycles,
RHS.TRANSCycles);
157 TRANSNum = std::min(TRANSNum,
RHS.TRANSNum);
158 TRANSNumVALU = std::min(TRANSNumVALU,
RHS.TRANSNumVALU);
159 SALUCycles = std::max(SALUCycles,
RHS.SALUCycles);
165 bool advance(DelayType
Type,
unsigned Cycles) {
168 VALUNum += (
Type == VALU);
169 if (VALUNum >= VALU_MAX || VALUCycles <= Cycles) {
175 VALUCycles -= Cycles;
179 TRANSNum += (
Type == TRANS);
180 TRANSNumVALU += (
Type == VALU);
181 if (TRANSNum >= TRANS_MAX || TRANSCycles <= Cycles) {
184 TRANSNum = TRANS_MAX;
185 TRANSNumVALU = VALU_MAX;
188 TRANSCycles -= Cycles;
192 if (SALUCycles <= Cycles) {
197 SALUCycles -= Cycles;
204#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
207 dbgs() <<
" VALUCycles=" << (int)VALUCycles;
208 if (VALUNum < VALU_MAX)
209 dbgs() <<
" VALUNum=" << (int)VALUNum;
211 dbgs() <<
" TRANSCycles=" << (int)TRANSCycles;
212 if (TRANSNum < TRANS_MAX)
213 dbgs() <<
" TRANSNum=" << (int)TRANSNum;
214 if (TRANSNumVALU < VALU_MAX)
215 dbgs() <<
" TRANSNumVALU=" << (int)TRANSNumVALU;
217 dbgs() <<
" SALUCycles=" << (int)SALUCycles;
223 struct DelayState :
DenseMap<MCRegUnit, DelayInfo> {
227 for (
const auto &KV :
RHS) {
230 std::tie(It, Inserted) = insert(KV);
232 It->second.merge(KV.second);
238 void advance(DelayType
Type,
unsigned Cycles) {
242 void advanceByVALUNum(
unsigned VALUNum) {
244 return P.second.VALUNum >= VALUNum &&
P.second.VALUCycles > 0;
248#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
251 dbgs() <<
" empty\n";
261 return A->first <
B->first;
281 if (Delay.TRANSNum < DelayInfo::TRANS_MAX)
282 Imm |= 4 + Delay.TRANSNum;
286 if (Delay.VALUNum < DelayInfo::VALU_MAX &&
287 Delay.VALUNum <= Delay.TRANSNumVALU) {
289 Imm |= Delay.VALUNum << 7;
291 Imm |= Delay.VALUNum;
295 if (Delay.SALUCycles) {
296 assert(Delay.SALUCycles < DelayInfo::SALU_CYCLES_MAX);
300 }
else if (
Imm & 0xf) {
301 Imm |= (Delay.SALUCycles + 8) << 7;
303 Imm |= Delay.SALUCycles + 8;
313 if (!(
Imm & 0x780) && LastDelayAlu) {
318 if (
I->getOpcode() == AMDGPU::S_SET_VGPR_MSB) {
325 if (!
I->isBundle() && !
I->isMetaInstruction())
330 unsigned LastImm =
Op.getImm();
331 assert((LastImm & ~0xf) == 0 &&
332 "Remembered an s_delay_alu with no room for another delay!");
333 LastImm |=
Imm << 7 | Skip << 4;
339 auto &
MBB = *
MI.getParent();
344 return (
Imm & 0x780) ? nullptr : DelayAlu;
349 for (
auto *Pred :
MBB.predecessors())
350 State.merge(BlockState[Pred]);
360 MCRegUnit LastSGPRFromVALU =
static_cast<MCRegUnit
>(0);
367 for (
auto &
MI :
MBB.instrs()) {
368 if (
MI.isBundle() ||
MI.isMetaInstruction())
372 switch (
MI.getOpcode()) {
373 case AMDGPU::SI_RETURN_TO_EPILOG:
377 DelayType
Type = getDelayType(
MI);
379 if (instructionWaitsForSGPRWrites(
MI)) {
380 auto It = State.find(LastSGPRFromVALU);
381 if (It != State.end()) {
382 DelayInfo Info = It->getSecond();
383 State.advanceByVALUNum(Info.VALUNum);
385 LastSGPRFromVALU =
static_cast<MCRegUnit
>(0);
389 if (instructionWaitsForVALU(
MI)) {
392 State = DelayState();
393 }
else if (
Type != OTHER) {
401 for (
const auto &
Op :
MI.explicit_uses()) {
406 if (
MI.getOpcode() == AMDGPU::V_WRITELANE_B32 &&
Op.isTied())
409 if (IsWMMACReuse &&
Op.isTied() &&
Op.getReg() == PrevWMMAVDst)
411 for (MCRegUnit Unit :
TRI->regunits(
Op.getReg())) {
412 auto It = State.find(Unit);
413 if (It != State.end()) {
414 Delay.merge(It->second);
421 if (SII->
isVALU(
MI.getOpcode(),
true)) {
422 for (
const auto &
Op :
MI.defs()) {
425 LastSGPRFromVALU = *
TRI->regunits(
Reg).begin();
431 if (Emit && !
MI.isBundledWithPred()) {
434 LastDelayAlu = emitDelayAlu(
MI, Delay, LastDelayAlu);
440 for (
const auto &
Op :
MI.defs()) {
442 &
MI,
Op.getOperandNo(),
nullptr, 0);
443 for (MCRegUnit Unit :
TRI->regunits(
Op.getReg()))
455 State.advance(
Type, Cycles);
471 "Basic block state should not have changed on final pass!");
472 }
else if (DelayState &BS = BlockState[&
MBB]; State != BS) {
473 BS = std::move(State);
484 if (!ST->hasDelayAlu())
492 SII = ST->getInstrInfo();
493 TRI = ST->getRegisterInfo();
501 while (!WorkList.
empty()) {
503 bool Changed = runOnMachineBasicBlock(
MBB,
false);
533 AMDGPUInsertDelayAlu Impl;
542 if (!AMDGPUInsertDelayAlu().
run(MF))
549char AMDGPUInsertDelayAluLegacy::ID = 0;
554 "AMDGPU Insert Delay ALU",
false,
false)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
AMD GCN specific subclass of TargetSubtarget.
static LoopDeletionResult merge(LoopDeletionResult A, LoopDeletionResult B)
Register const TargetRegisterInfo * TRI
Promote Memory to Register
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Interface definition for SIInstrInfo.
Represent the analysis usage information of a pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Represents analyses that only rely on functions' control flow.
Instructions::iterator instr_iterator
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
Representation of each machine instruction.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
Register getReg() const
getReg - Returns the register number.
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.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
bool isXDLWMMA(const MachineInstr &MI) const
static bool isSALU(const MachineInstr &MI)
static bool isSWMMAC(const MachineInstr &MI)
const TargetSchedModel & getSchedModel() const
static bool isVALU(const MachineInstr &MI, bool AllowLDSDMA)
static bool isTRANS(const MachineInstr &MI)
static unsigned getNumWaitStates(const MachineInstr &MI)
Return the number of wait states that result from executing this instruction.
static bool isWMMA(const MachineInstr &MI)
LLVM_READONLY MachineOperand * getNamedOperand(MachineInstr &MI, AMDGPU::OpName OperandName) const
Returns the operand named Op.
This class keeps track of the SPI_SP_INPUT_ADDR config register, which tells the hardware which inter...
unsigned getMaxWavesPerEU() const
A vector that has set insertion semantics.
void insert_range(Range &&R)
bool empty() const
Determine if the SetVector is empty or not.
bool insert(const value_type &X)
Insert a new element into the SetVector.
value_type pop_back_val()
void reserve(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
Provide an instruction scheduling machine model to CodeGen passes.
LLVM_ABI unsigned computeOperandLatency(const MachineInstr *DefMI, unsigned DefOperIdx, const MachineInstr *UseMI, unsigned UseOperIdx) const
Compute operand latency based on the available machine model.
The instances of the Type class are immutable: once they are created, they are never changed.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned decodeFieldVaVdst(unsigned Encoded)
bool isSGPR(MCRegister Reg, const MCRegisterInfo *TRI)
Is Reg - scalar register.
bool isDPMACCInstruction(unsigned Opc)
constexpr bool isFLAT(const T &...O)
constexpr bool isBuffer(const T &...O)
constexpr bool isSMRD(const T &...O)
constexpr bool isMIMG(const T &...O)
constexpr bool isEXP(const T &...O)
constexpr bool isDS(const T &...O)
constexpr bool isSALU(const T &...O)
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
bool operator!=(uint64_t V1, const APInt &V2)
LLVM_ABI Printable printRegUnit(MCRegUnit Unit, const TargetRegisterInfo *TRI)
Create Printable object to print register units on a raw_ostream.
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
auto reverse(ContainerTy &&C)
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
char & AMDGPUInsertDelayAluID
auto remove_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::remove_if which take ranges instead of having to pass begin/end explicitly.
DWARFExpression::Operation Op
LLVM_ABI Printable printMBBReference(const MachineBasicBlock &MBB)
Prints a machine basic block reference.
PreservedAnalyses run(MachineFunction &F, MachineFunctionAnalysisManager &MFAM)