36#define DEBUG_TYPE "gcn-vopd-utils"
47 const bool IsX = CompIdx == VOPD::X;
50 OpIdx = getNamedOperandIdx(VOPDOpc, IsX ? OpName::src0X : OpName::src0Y);
53 OpIdx = getNamedOperandIdx(VOPDOpc, IsX ? OpName::vsrc1X : OpName::vsrc1Y);
56 OpIdx = getNamedOperandIdx(VOPDOpc, IsX ? OpName::vsrc2X : OpName::vsrc2Y);
58 OpIdx = getNamedOperandIdx(VOPDOpc, IsX ? OpName::src2X : OpName::src2Y);
65 return TII.getRegClass(
TII.get(VOPDOpc), OpIdx);
72 unsigned CompIdx,
unsigned SrcIdx,
79 AMDGPU::OpName Name) {
80 return MI.getOperand(getNamedOperandIdx(
MI.getOpcode(), Name));
91 unsigned Opc =
MI.getOpcode();
92 if (
Opc != AMDGPU::V_DOT2_F32_F16 &&
Opc != AMDGPU::V_DOT2_F32_BF16)
101 int Src0Idx = getNamedOperandIdx(
Opc, AMDGPU::OpName::src0);
102 int Src1Idx = getNamedOperandIdx(
Opc, AMDGPU::OpName::src1);
108 if (!Src0.isReg() || !Src1.isImm() ||
109 !
TII.isLegalToSwap(
MI, Src0Idx, Src1Idx))
138 if (!ST.hasVOPD3F64OPYSrcHazard())
143 AMDGPU::getNamedOperandIdx(MIX.
getOpcode(), AMDGPU::OpName::vdst);
144 assert(VDstIdx != -1 &&
"VOPD3 OPX component must have a vdst");
145 if (
TII.getOpSize(MIX, VDstIdx) != 8)
151 unsigned NumVGPRs =
TRI->getNumUsedPhysRegs(
152 MF.
getRegInfo(), AMDGPU::VGPR_32RegClass,
false);
153 for (AMDGPU::OpName Name :
154 {AMDGPU::OpName::src0, AMDGPU::OpName::src1, AMDGPU::OpName::src2}) {
157 if (!Src || !Src->isReg() ||
158 !AMDGPU::VGPR_32RegClass.contains(Src->getReg()))
160 unsigned Idx =
TRI->getHWRegIndex(Src->getReg());
161 if ((Idx + 1) % Granule == 0 && Idx + 1 >= NumVGPRs)
176 bool IsVOPD3,
bool AllowSameVGPR,
183 if (IsVOPD3 && !ST.hasVOPD3())
189 bool Commute[2] = {
false,
false};
194 if (
TII.isDPP(MIX) ||
TII.isDPP(MIY))
206 for (
auto &
Literal : UniqueLiterals) {
210 UniqueLiterals.push_back(&
Op);
225 for (
auto CompIdx : VOPD::COMPONENTS) {
227 const AMDGPU::OpName Src0Name =
228 Commute[CompIdx] ? AMDGPU::OpName::src1 : AMDGPU::OpName::src0;
229 const AMDGPU::OpName Src1Name =
230 Commute[CompIdx] ? AMDGPU::OpName::src0 : AMDGPU::OpName::src1;
236 if (
TII.regUsesConstantBus(Src0, MRI))
237 UniqueScalarRegs.
insert(Src0.getReg());
238 }
else if (!
TII.isInlineConstant(Src0)) {
249 int OpIdx = getNamedOperandIdx(
MI.getOpcode(), Src0Name);
250 if (
TII.getOpSize(
MI, OpIdx) != 4)
254 &AMDGPU::SGPR_32RegClass);
259 int32_t
Imm =
static_cast<int32_t
>(Src0.getImm());
261 Fixups.push_back({CompIdx,
static_cast<unsigned>(OpIdx),
Imm, SlotRC});
267 if (InstInfo[CompIdx].hasMandatoryLiteral()) {
268 auto CompOprIdx = InstInfo[CompIdx].getMandatoryLiteralCompOperandIndex();
269 AddLiteral(
MI.getOperand(CompOprIdx));
273 if (
MI.getDesc().hasImplicitUseOfPhysReg(AMDGPU::VCC))
274 UniqueScalarRegs.
insert(AMDGPU::VCC_LO);
280 assert(
TRI->isVectorRegister(MRI, Src1->getReg()));
281 }
else if (IsVOPD3) {
288 TII.getNamedOperand(
MI, AMDGPU::OpName::src2)) {
291 if (!Src2->isImm() || Src2->getImm())
298 if (
TII.regUsesConstantBus(*Src2, MRI)) {
299 assert(
MI.getOpcode() == AMDGPU::V_CNDMASK_B32_e64);
300 UniqueScalarRegs.
insert(Src2->getReg());
304 for (
auto OpName : {AMDGPU::OpName::clamp, AMDGPU::OpName::omod,
305 AMDGPU::OpName::op_sel}) {
313 {AMDGPU::OpName::src0_modifiers, AMDGPU::OpName::src1_modifiers,
314 AMDGPU::OpName::src2_modifiers}) {
322 if (UniqueLiterals.
size() > 1)
326 if (MaterializedLiterals.
size() > 1)
328 if ((UniqueLiterals.
size() + MaterializedLiterals.
size() +
329 UniqueScalarRegs.
size()) > 2)
332 auto GetVRegIdx = [&](
unsigned OpcodeIdx,
unsigned OperandIdx) {
334 if (Commute[OpcodeIdx]) {
335 int Src0Idx = getNamedOperandIdx(
MI.getOpcode(), AMDGPU::OpName::src0);
336 int Src1Idx = getNamedOperandIdx(
MI.getOpcode(), AMDGPU::OpName::src1);
337 if ((
int)OperandIdx == Src0Idx)
338 OperandIdx = Src1Idx;
339 else if ((
int)OperandIdx == Src1Idx)
340 OperandIdx = Src0Idx;
343 if (Operand.
isReg() &&
TRI->isVectorRegister(MRI, Operand.
getReg()))
350 bool SkipSrc = (ST.hasGFX11_7Insts() || ST.hasGFX12Insts()) &&
351 MIX.
getOpcode() == AMDGPU::V_MOV_B32_e32 &&
352 MIY.
getOpcode() == AMDGPU::V_MOV_B32_e32;
355 if (InstInfo.hasInvalidOperand(GetVRegIdx, *
TRI, SkipSrc, AllowSameVGPR,
356 IsVOPD3, ST.hasVOPDInterlockHazard()))
360 <<
"\n\tY: " << MIY <<
"\n");
361 LiteralFixups.
assign(Fixups);
362 CommuteXY[VOPD::X] = Commute[VOPD::X];
363 CommuteXY[VOPD::Y] = Commute[VOPD::Y];
369static std::optional<VOPDMatchInfo>
380 if (!(FirstCanBeVOPD.
X && SecondCanBeVOPD.
Y) &&
381 !(FirstCanBeVOPD.
Y && SecondCanBeVOPD.
X))
385 if (
TII.hasRAWDependency(FirstMI, SecondMI))
389 bool AllowSameVGPR = ST.hasGFX12Insts();
394 bool CommuteXY[2] = {
false,
false};
396 if (FirstCanBeVOPD.
X && SecondCanBeVOPD.
Y) {
400 {&FirstMI, &SecondMI},
407 if (FirstCanBeVOPD.
Y && SecondCanBeVOPD.
X) {
410 bool IsAntiDep =
TII.hasRAWDependency(SecondMI, FirstMI);
411 AllowSameVGPR &= !IsAntiDep;
412 if (IsAntiDep && !
TII.isVOPDAntidependencyAllowed(SecondMI))
417 {&FirstMI, &SecondMI},
456 auto CheckCanBeVOPD = [&](
bool VOPD3) {
459 return CanBeVOPD.
Y || CanBeVOPD.
X;
461 return CheckCanBeVOPD(
false) || (ST.hasVOPD3() && CheckCanBeVOPD(
true));
464#ifdef EXPENSIVE_CHECKS
467 MII != FirstMI->
getParent()->instr_end(); ++MII) {
468 if (&*MII == &SecondMI)
472 }() &&
"Expected FirstMI to precede SecondMI");
485 SUnit &Head,
bool Forward,
bool StopAtLoads) {
492 Stack.push_back(&Head);
493 while (!Stack.empty()) {
494 SUnit *SU = Stack.pop_back_val();
496 for (
const SDep &Edge : Deps) {
497 if (StopAtLoads && Edge.getKind() !=
SDep::Data)
499 SUnit *Dep = Edge.getSUnit();
509 Stack.push_back(Dep);
529 if (ILoadSuccs.
empty())
538 if (JLoadPreds.
empty())
541 for (
SUnit *ILoad : ILoadSuccs) {
543 if (!LoadPredsComputed.
test(ILoad->NodeNum)) {
546 LoadPredsComputed.
set(ILoad->NodeNum);
549 for (
SUnit *JLoad : JLoadPreds) {
550 if (ILoad == JLoad) {
552 dbgs() <<
"Will not pair " <<
I <<
" with " << J <<
"\n"
553 <<
" Fusion would introduce a cyclic dependency with "
560 <<
" Fusion may force " << *JLoad
561 <<
" to complete its load before dispatching "
575struct VOPDPairingMutation : ScheduleDAGMutation {
582 void apply(ScheduleDAGInstrs *DAG)
override {
583 const TargetInstrInfo &
TII = *DAG->
TII;
586 LLVM_DEBUG(
dbgs() <<
"Target does not support VOPDPairingMutation\n");
590 BitVector VOPDCapable(DAG->
SUnits.size());
593 for (
auto ISUI = DAG->
SUnits.begin(),
E = DAG->
SUnits.end(); ISUI !=
E;
595 const MachineInstr *IMI = ISUI->getInstr();
598 VOPDCapable[IIdx] =
true;
602 SmallSetVector<SUnit *, 8> ILoadSuccs;
607 BitVector LoadPredsComputed(DAG->
SUnits.size());
610 BitVector Scratch(DAG->
SUnits.size());
611 for (
auto ISUI = DAG->
SUnits.begin(),
E = DAG->
SUnits.end(); ISUI !=
E;
613 if (!VOPDCapable[IIdx])
615 const MachineInstr *IMI = ISUI->getInstr();
621 unsigned JIdx = IIdx + 1;
622 for (
auto JSUI = ISUI + 1; JSUI !=
E; ++JSUI, ++JIdx) {
623 if (!VOPDCapable[JIdx] || JSUI->isBoundaryNode())
625 const MachineInstr *JMI = JSUI->getInstr();
631 LoadPredsCache, Scratch))
636 VOPDCapable[JIdx] =
false;
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static bool shouldScheduleAdjacent(const TargetInstrInfo &TII, const TargetSubtargetInfo &TSI, const MachineInstr *FirstMI, const MachineInstr &SecondMI, const SDep *Dep)
Check if the instr pair, FirstMI and SecondMI, should be fused together.
Base class for AMDGPU specific classes of TargetSubtarget.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
AMD GCN specific subclass of TargetSubtarget.
static void collectLoads(SmallSetVector< SUnit *, 8 > &Loads, BitVector &Visited, SUnit &Head, bool Forward, bool StopAtLoads)
Collect all load (dependents if Forward else dependencies) that connect to the Head SU.
static const MachineOperand & getNamedOp(const MachineInstr &MI, AMDGPU::OpName Name)
static bool loadsMayOverlap(SUnit &I, const SmallSetVector< SUnit *, 8 > &ILoadSuccs, SUnit &J, BitVector &LoadPredsComputed, SmallVector< SmallSetVector< SUnit *, 8 > > &LoadPredsCache, BitVector &Scratch)
Checks whether fusing SU I with SU J would force the loads preceding J to complete before loads depen...
static bool checkVOPDRegConstraints(const SIInstrInfo &TII, const MachineInstr &MIX, const MachineInstr &MIY, bool IsVOPD3, bool AllowSameVGPR, SmallVectorImpl< VOPDLiteralFixup > &LiteralFixups, bool(&CommuteXY)[2])
static bool canMapVOP3PToVOPD(const SIInstrInfo &TII, const MachineInstr &MI, bool &Commute)
static const TargetRegisterClass * getVOPDSrcRegClass(const SIInstrInfo &TII, int VOPDOpc, unsigned CompIdx, unsigned SrcIdx)
static bool isVOPD3F64OPYSrcHazard(const SIInstrInfo &TII, const MachineInstr &MIX, const MachineInstr &MIY)
static bool canMaterializeVOPDLiterals(const MachineFunction &MF)
static std::optional< VOPDMatchInfo > tryMatchVOPDPairVariant(const SIInstrInfo &TII, unsigned EncodingFamily, MachineInstr &FirstMI, MachineInstr &SecondMI, bool IsVOPD3)
Core pair-eligibility check for a single VOPD encoding variant (VOPD or VOPD3).
static bool shouldScheduleVOPDAdjacent(const TargetInstrInfo &TII, const TargetSubtargetInfo &TSI, const MachineInstr *FirstMI, const MachineInstr &SecondMI, const SDep *)
Check if the instr pair, FirstMI and SecondMI, should be scheduled together.
static bool isValidVOPDSrc(const SIInstrInfo &TII, int VOPDOpc, unsigned CompIdx, unsigned SrcIdx, Register PhysSrcReg)
const HexagonInstrInfo * TII
Register const TargetRegisterInfo * TRI
Promote Memory to Register
static bool isReg(const MCInst &MI, unsigned OpNo)
Interface definition for SIInstrInfo.
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallVector class.
bool test(unsigned Idx) const
Returns true if bit Idx is set.
BitVector & reset()
Reset all bits in the bitvector.
BitVector & set()
Set all bits in the bitvector.
bool hasOptSize() const
Optimize this function for size (-Os) or minimum size (-Oz).
bool contains(MCRegister Reg) const
contains - Return true if the specified register is included in this register class.
MachineInstrBundleIterator< const MachineInstr > const_iterator
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineFunctionProperties & getProperties() const
Get the function properties.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
bool mayLoad(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read memory.
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
LLVM_ABI const MachineFunction * getMF() const
Return the function that contains the basic block that this instruction belongs to.
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.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Wrapper class representing virtual and physical registers.
@ Data
Regular data dependence (aka true-dependence).
const GCNSubtarget & getSubtarget() const
Scheduling unit. This is a node in the scheduling DAG.
bool isInstr() const
Returns true if this SUnit refers to a machine instruction as opposed to an SDNode.
unsigned NodeNum
Entry # of node in the node vector.
bool isBoundaryNode() const
Boundary nodes are placeholders for the boundary of the scheduling region.
SmallVector< SDep, 4 > Succs
All sunit successors.
SmallVector< SDep, 4 > Preds
All sunit predecessors.
MachineInstr * getInstr() const
Returns the representative MachineInstr for this SUnit.
const TargetInstrInfo * TII
Target instruction information.
std::vector< SUnit > SUnits
The scheduling units.
MachineFunction & MF
Machine function.
bool contains(const_arg_type key) const
Check if the SetVector contains the given key.
void clear()
Completely clear the SetVector.
bool empty() const
Determine if the SetVector is empty or not.
bool insert(const value_type &X)
Insert a new element into the SetVector.
A SetVector that performs no allocations if smaller than a certain size.
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void assign(size_type NumElts, ValueParamT Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
TargetInstrInfo - Interface to description of machine instruction set.
TargetSubtargetInfo - Generic base class for all target subtargets.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned getVOPDOpcode(unsigned Opc, bool VOPD3)
CanBeVOPD getCanBeVOPD(unsigned Opc, unsigned EncodingFamily, bool VOPD3)
unsigned getVOPDEncodingFamily(const MCSubtargetInfo &ST)
LLVM_READONLY bool hasNamedOperand(uint32_t Opcode, OpName NamedIdx)
LLVM_ABI unsigned getVGPRAllocGranule(GPUKind AK, bool IsWave32)
VOPD::InstInfo getVOPDInstInfo(const MCInstrDesc &OpX, const MCInstrDesc &OpY)
bool hasVOPD(const MCSubtargetInfo &STI)
int getVOPDFull(unsigned OpX, unsigned OpY, unsigned EncodingFamily, bool VOPD3)
void apply(Opt *O, const Mod &M, const Mods &... Ms)
This is an optimization pass for GlobalISel generic memory operations.
std::unique_ptr< ScheduleDAGMutation > createVOPDPairingMutation()
LLVM_ABI bool fuseInstructionPair(ScheduleDAGInstrs &DAG, SUnit &FirstSU, SUnit &SecondSU)
Create an artificial edge between FirstSU and SecondSU.
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
DWARFExpression::Operation Op
std::optional< VOPDMatchInfo > tryMatchVOPDPair(const SIInstrInfo &TII, MachineInstr &FirstMI, MachineInstr &SecondMI)
Check whether FirstMI and SecondMI can be combined into a VOPD instruction.
bool(*)(const TargetInstrInfo &TII, const TargetSubtargetInfo &STI, const MachineInstr *FirstMI, const MachineInstr &SecondMI, const SDep *Dep) MacroFusionPredTy
Check if the instr pair, FirstMI and SecondMI, should be fused together, based on the dependency betw...
LLVM_ABI bool hasLessThanNumFused(const SUnit &SU, unsigned FuseLimit)
Checks if the number of cluster edges between SU and its predecessors is less than FuseLimit.
MCRegisterClass TargetRegisterClass
Describes a matched VOPD pair.