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 &&
45 static_cast<unsigned>(
MI.getOperand(0).getImm())) == 0)
50 static bool instructionWaitsForSGPRWrites(
const MachineInstr &
MI) {
56 for (
auto &
Op :
MI.operands()) {
65 enum DelayType { VALU, TRANS, SALU, OTHER };
90 static constexpr unsigned VALU_MAX = 5;
94 static constexpr unsigned TRANS_MAX = 4;
98 static constexpr unsigned SALU_CYCLES_MAX = 4;
115 uint8_t TRANSNumVALU = VALU_MAX;
122 bool IsFFProducer =
false;
124 DelayInfo() =
default;
126 DelayInfo(DelayType
Type,
unsigned Cycles,
bool IsFFProducer =
false)
127 : IsFFProducer(IsFFProducer) {
132 VALUCycles =
static_cast<uint8_t>(Cycles);
136 TRANSCycles =
static_cast<uint8_t>(Cycles);
143 SALUCycles =
static_cast<uint8_t>(std::min(Cycles, SALU_CYCLES_MAX));
149 return VALUCycles ==
RHS.VALUCycles && VALUNum ==
RHS.VALUNum &&
150 TRANSCycles ==
RHS.TRANSCycles && TRANSNum ==
RHS.TRANSNum &&
151 TRANSNumVALU ==
RHS.TRANSNumVALU && SALUCycles ==
RHS.SALUCycles &&
152 IsFFProducer ==
RHS.IsFFProducer;
160 VALUCycles = std::max(VALUCycles,
RHS.VALUCycles);
161 VALUNum = std::min(VALUNum,
RHS.VALUNum);
162 TRANSCycles = std::max(TRANSCycles,
RHS.TRANSCycles);
163 TRANSNum = std::min(TRANSNum,
RHS.TRANSNum);
164 TRANSNumVALU = std::min(TRANSNumVALU,
RHS.TRANSNumVALU);
165 SALUCycles = std::max(SALUCycles,
RHS.SALUCycles);
166 IsFFProducer = IsFFProducer &&
RHS.IsFFProducer;
172 bool advance(DelayType
Type,
unsigned Cycles) {
175 VALUNum += (
Type == VALU);
176 if (VALUNum >= VALU_MAX || VALUCycles <= Cycles) {
182 VALUCycles -=
static_cast<uint8_t>(Cycles);
186 TRANSNum += (
Type == TRANS);
187 TRANSNumVALU += (
Type == VALU);
188 if (TRANSNum >= TRANS_MAX || TRANSCycles <= Cycles) {
191 TRANSNum = TRANS_MAX;
192 TRANSNumVALU = VALU_MAX;
195 TRANSCycles -=
static_cast<uint8_t>(Cycles);
199 if (SALUCycles <= Cycles) {
204 SALUCycles -=
static_cast<uint8_t>(Cycles);
211#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
214 dbgs() <<
" VALUCycles=" << (int)VALUCycles;
215 if (VALUNum < VALU_MAX)
216 dbgs() <<
" VALUNum=" << (int)VALUNum;
218 dbgs() <<
" TRANSCycles=" << (int)TRANSCycles;
219 if (TRANSNum < TRANS_MAX)
220 dbgs() <<
" TRANSNum=" << (int)TRANSNum;
221 if (TRANSNumVALU < VALU_MAX)
222 dbgs() <<
" TRANSNumVALU=" << (int)TRANSNumVALU;
224 dbgs() <<
" SALUCycles=" << (int)SALUCycles;
230 struct DelayState :
DenseMap<MCRegUnit, DelayInfo> {
234 for (
const auto &KV :
RHS) {
237 std::tie(It, Inserted) = insert(KV);
239 It->second.merge(KV.second);
245 void advance(DelayType
Type,
unsigned Cycles) {
249 void advanceByVALUNum(
unsigned VALUNum) {
251 return P.second.VALUNum >= VALUNum &&
P.second.VALUCycles > 0;
255#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
258 dbgs() <<
" empty\n";
268 return A->first <
B->first;
288 if (Delay.TRANSNum < DelayInfo::TRANS_MAX)
289 Imm |= 4 + Delay.TRANSNum;
293 if (Delay.VALUNum < DelayInfo::VALU_MAX &&
294 Delay.VALUNum <= Delay.TRANSNumVALU) {
296 Imm |= Delay.VALUNum << 7;
298 Imm |= Delay.VALUNum;
302 if (Delay.SALUCycles) {
303 assert(Delay.SALUCycles < DelayInfo::SALU_CYCLES_MAX);
307 }
else if (
Imm & 0xf) {
308 Imm |= (Delay.SALUCycles + 8) << 7;
310 Imm |= Delay.SALUCycles + 8;
320 if (!(
Imm & 0x780) && LastDelayAlu) {
325 if (
I->getOpcode() == AMDGPU::S_SET_VGPR_MSB) {
332 if (!
I->isBundle() && !
I->isMetaInstruction())
337 unsigned LastImm =
static_cast<unsigned>(
Op.getImm());
338 assert((LastImm & ~0xf) == 0 &&
339 "Remembered an s_delay_alu with no room for another delay!");
340 LastImm |=
Imm << 7 | Skip << 4;
346 auto &
MBB = *
MI.getParent();
351 return (
Imm & 0x780) ? nullptr : DelayAlu;
365 switch (
MI.getOpcode()) {
367 case AMDGPU::V_ADD_CO_U32_e64:
368 case AMDGPU::V_SUB_CO_U32_e64:
369 case AMDGPU::V_SUBREV_CO_U32_e64:
370 case AMDGPU::V_ADDC_U32_e64:
371 case AMDGPU::V_SUBB_U32_e64:
372 case AMDGPU::V_SUBBREV_U32_e64:
394 unsigned MIOpCode =
MI.getOpcode();
399 case AMDGPU::V_ADDC_U32_e64:
400 case AMDGPU::V_SUBB_U32_e64:
401 case AMDGPU::V_SUBBREV_U32_e64:
402 case AMDGPU::V_CNDMASK_B32_e64:
403 case AMDGPU::V_CNDMASK_B16_fake16_e64:
404 case AMDGPU::V_CNDMASK_B16_t16_e64:
406 AMDGPU::getNamedOperandIdx(MIOpCode, AMDGPU::OpName::src2);
407 assert(Src2Idx >= 0 &&
"Unexpected source index");
408 return OpNo ==
static_cast<unsigned>(Src2Idx);
416 for (
auto *
Pred :
MBB.predecessors())
417 State.merge(BlockState[
Pred]);
427 MCRegUnit LastSGPRFromVALU =
static_cast<MCRegUnit
>(0);
434 for (
auto &
MI :
MBB.instrs()) {
435 if (
MI.isBundle() ||
MI.isMetaInstruction())
439 switch (
MI.getOpcode()) {
440 case AMDGPU::SI_RETURN_TO_EPILOG:
447 DelayType ProducerType = getDelayType(
MI,
false);
448 DelayType ConsumerType = getDelayType(
MI,
true);
450 if (instructionWaitsForSGPRWrites(
MI)) {
451 auto It = State.find(LastSGPRFromVALU);
452 if (It != State.end()) {
453 DelayInfo Info = It->getSecond();
454 State.advanceByVALUNum(Info.VALUNum);
456 LastSGPRFromVALU =
static_cast<MCRegUnit
>(0);
460 if (instructionWaitsForVALU(
MI)) {
463 State = DelayState();
464 }
else if (ConsumerType != OTHER) {
472 for (
const auto &
Op :
MI.explicit_uses()) {
477 if (
MI.getOpcode() == AMDGPU::V_WRITELANE_B32 &&
Op.isTied())
480 if (IsWMMACReuse &&
Op.isTied() &&
Op.getReg() == PrevWMMAVDst)
484 unsigned OperandNo =
MI.getOperandNo(&
Op);
488 if (isFastForwardConsumer(
MI,
Op, OperandNo) &&
490 auto It = State.find(Unit);
491 if (It != State.end())
492 return It->second.IsFFProducer;
498 for (MCRegUnit Unit :
TRI->regunits(
Op.getReg())) {
499 auto It = State.find(Unit);
500 if (It != State.end()) {
501 Delay.merge(It->second);
508 if (ProducerType == VALU) {
509 for (
const auto &
Op :
MI.defs()) {
512 LastSGPRFromVALU = *
TRI->regunits(
Reg).begin();
518 if (Emit && !
MI.isBundledWithPred()) {
521 LastDelayAlu = emitDelayAlu(
MI, Delay, LastDelayAlu);
525 if (ProducerType != OTHER) {
527 for (
const auto &
Op :
MI.defs()) {
529 &
MI,
Op.getOperandNo(),
nullptr, 0);
530 for (MCRegUnit Unit :
TRI->regunits(
Op.getReg()))
532 DelayInfo{ProducerType,
Latency, isFastForwardProducer(
MI,
Op)};
543 State.advance(ProducerType, Cycles);
559 "Basic block state should not have changed on final pass!");
560 }
else if (DelayState &BS = BlockState[&
MBB]; State != BS) {
561 BS = std::move(State);
572 if (!ST->hasDelayAlu())
580 SII = ST->getInstrInfo();
581 TRI = ST->getRegisterInfo();
589 while (!WorkList.
empty()) {
621 AMDGPUInsertDelayAlu Impl;
630 if (!AMDGPUInsertDelayAlu().
run(MF))
637char AMDGPUInsertDelayAluLegacy::ID = 0;
642 "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
static bool runOnMachineBasicBlock(MachineBasicBlock &MBB, MachineInstr *FirstNextMBBInstr, function_ref< MachineBranchProbabilityInfo &()> GetMBPI)
runOnMachineBasicBlock - Fill in delay slots for the given basic block.
#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.
bool isReg() const
isReg - Tests if this is a MO_Register 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)
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
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)