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;
121 DelayInfo() =
default;
123 DelayInfo(DelayType
Type,
unsigned Cycles) {
128 VALUCycles =
static_cast<uint8_t>(Cycles);
132 TRANSCycles =
static_cast<uint8_t>(Cycles);
139 SALUCycles =
static_cast<uint8_t>(std::min(Cycles, SALU_CYCLES_MAX));
145 return VALUCycles ==
RHS.VALUCycles && VALUNum ==
RHS.VALUNum &&
146 TRANSCycles ==
RHS.TRANSCycles && TRANSNum ==
RHS.TRANSNum &&
147 TRANSNumVALU ==
RHS.TRANSNumVALU && SALUCycles ==
RHS.SALUCycles;
155 VALUCycles = std::max(VALUCycles,
RHS.VALUCycles);
156 VALUNum = std::min(VALUNum,
RHS.VALUNum);
157 TRANSCycles = std::max(TRANSCycles,
RHS.TRANSCycles);
158 TRANSNum = std::min(TRANSNum,
RHS.TRANSNum);
159 TRANSNumVALU = std::min(TRANSNumVALU,
RHS.TRANSNumVALU);
160 SALUCycles = std::max(SALUCycles,
RHS.SALUCycles);
166 bool advance(DelayType
Type,
unsigned Cycles) {
169 VALUNum += (
Type == VALU);
170 if (VALUNum >= VALU_MAX || VALUCycles <= Cycles) {
176 VALUCycles -=
static_cast<uint8_t>(Cycles);
180 TRANSNum += (
Type == TRANS);
181 TRANSNumVALU += (
Type == VALU);
182 if (TRANSNum >= TRANS_MAX || TRANSCycles <= Cycles) {
185 TRANSNum = TRANS_MAX;
186 TRANSNumVALU = VALU_MAX;
189 TRANSCycles -=
static_cast<uint8_t>(Cycles);
193 if (SALUCycles <= Cycles) {
198 SALUCycles -=
static_cast<uint8_t>(Cycles);
205#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
208 dbgs() <<
" VALUCycles=" << (int)VALUCycles;
209 if (VALUNum < VALU_MAX)
210 dbgs() <<
" VALUNum=" << (int)VALUNum;
212 dbgs() <<
" TRANSCycles=" << (int)TRANSCycles;
213 if (TRANSNum < TRANS_MAX)
214 dbgs() <<
" TRANSNum=" << (int)TRANSNum;
215 if (TRANSNumVALU < VALU_MAX)
216 dbgs() <<
" TRANSNumVALU=" << (int)TRANSNumVALU;
218 dbgs() <<
" SALUCycles=" << (int)SALUCycles;
224 struct DelayState :
DenseMap<MCRegUnit, DelayInfo> {
228 for (
const auto &KV :
RHS) {
231 std::tie(It, Inserted) = insert(KV);
233 It->second.merge(KV.second);
239 void advance(DelayType
Type,
unsigned Cycles) {
243 void advanceByVALUNum(
unsigned VALUNum) {
245 return P.second.VALUNum >= VALUNum &&
P.second.VALUCycles > 0;
249#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
252 dbgs() <<
" empty\n";
262 return A->first <
B->first;
282 if (Delay.TRANSNum < DelayInfo::TRANS_MAX)
283 Imm |= 4 + Delay.TRANSNum;
287 if (Delay.VALUNum < DelayInfo::VALU_MAX &&
288 Delay.VALUNum <= Delay.TRANSNumVALU) {
290 Imm |= Delay.VALUNum << 7;
292 Imm |= Delay.VALUNum;
296 if (Delay.SALUCycles) {
297 assert(Delay.SALUCycles < DelayInfo::SALU_CYCLES_MAX);
301 }
else if (
Imm & 0xf) {
302 Imm |= (Delay.SALUCycles + 8) << 7;
304 Imm |= Delay.SALUCycles + 8;
314 if (!(
Imm & 0x780) && LastDelayAlu) {
319 if (
I->getOpcode() == AMDGPU::S_SET_VGPR_MSB) {
326 if (!
I->isBundle() && !
I->isMetaInstruction())
331 unsigned LastImm =
static_cast<unsigned>(
Op.getImm());
332 assert((LastImm & ~0xf) == 0 &&
333 "Remembered an s_delay_alu with no room for another delay!");
334 LastImm |=
Imm << 7 | Skip << 4;
340 auto &
MBB = *
MI.getParent();
345 return (
Imm & 0x780) ? nullptr : DelayAlu;
350 for (
auto *Pred :
MBB.predecessors())
351 State.merge(BlockState[Pred]);
361 MCRegUnit LastSGPRFromVALU =
static_cast<MCRegUnit
>(0);
368 for (
auto &
MI :
MBB.instrs()) {
369 if (
MI.isBundle() ||
MI.isMetaInstruction())
373 switch (
MI.getOpcode()) {
374 case AMDGPU::SI_RETURN_TO_EPILOG:
381 DelayType ProducerType = getDelayType(
MI,
false);
382 DelayType ConsumerType = getDelayType(
MI,
true);
384 if (instructionWaitsForSGPRWrites(
MI)) {
385 auto It = State.find(LastSGPRFromVALU);
386 if (It != State.end()) {
387 DelayInfo Info = It->getSecond();
388 State.advanceByVALUNum(Info.VALUNum);
390 LastSGPRFromVALU =
static_cast<MCRegUnit
>(0);
394 if (instructionWaitsForVALU(
MI)) {
397 State = DelayState();
398 }
else if (ConsumerType != OTHER) {
406 for (
const auto &
Op :
MI.explicit_uses()) {
411 if (
MI.getOpcode() == AMDGPU::V_WRITELANE_B32 &&
Op.isTied())
414 if (IsWMMACReuse &&
Op.isTied() &&
Op.getReg() == PrevWMMAVDst)
416 for (MCRegUnit Unit :
TRI->regunits(
Op.getReg())) {
417 auto It = State.find(Unit);
418 if (It != State.end()) {
419 Delay.merge(It->second);
426 if (ProducerType == VALU) {
427 for (
const auto &
Op :
MI.defs()) {
430 LastSGPRFromVALU = *
TRI->regunits(
Reg).begin();
436 if (Emit && !
MI.isBundledWithPred()) {
439 LastDelayAlu = emitDelayAlu(
MI, Delay, LastDelayAlu);
443 if (ProducerType != OTHER) {
445 for (
const auto &
Op :
MI.defs()) {
447 &
MI,
Op.getOperandNo(),
nullptr, 0);
448 for (MCRegUnit Unit :
TRI->regunits(
Op.getReg()))
449 State[Unit] = DelayInfo(ProducerType,
Latency);
460 State.advance(ProducerType, Cycles);
476 "Basic block state should not have changed on final pass!");
477 }
else if (DelayState &BS = BlockState[&
MBB]; State != BS) {
478 BS = std::move(State);
489 if (!ST->hasDelayAlu())
497 SII = ST->getInstrInfo();
498 TRI = ST->getRegisterInfo();
506 while (!WorkList.
empty()) {
508 bool Changed = runOnMachineBasicBlock(
MBB,
false);
538 AMDGPUInsertDelayAlu Impl;
547 if (!AMDGPUInsertDelayAlu().
run(MF))
554char AMDGPUInsertDelayAluLegacy::ID = 0;
559 "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)