35#define DEBUG_TYPE "gcn-vopd-utils"
46 const bool IsX = CompIdx == VOPD::X;
49 OpIdx = getNamedOperandIdx(VOPDOpc, IsX ? OpName::src0X : OpName::src0Y);
52 OpIdx = getNamedOperandIdx(VOPDOpc, IsX ? OpName::vsrc1X : OpName::vsrc1Y);
55 OpIdx = getNamedOperandIdx(VOPDOpc, IsX ? OpName::vsrc2X : OpName::vsrc2Y);
57 OpIdx = getNamedOperandIdx(VOPDOpc, IsX ? OpName::src2X : OpName::src2Y);
64 return TII.getRegClass(
TII.get(VOPDOpc), OpIdx);
71 unsigned CompIdx,
unsigned SrcIdx,
78 AMDGPU::OpName Name) {
79 return MI.getOperand(getNamedOperandIdx(
MI.getOpcode(), Name));
90 unsigned Opc =
MI.getOpcode();
91 if (
Opc != AMDGPU::V_DOT2_F32_F16 &&
Opc != AMDGPU::V_DOT2_F32_BF16)
100 int Src0Idx = getNamedOperandIdx(
Opc, AMDGPU::OpName::src0);
101 int Src1Idx = getNamedOperandIdx(
Opc, AMDGPU::OpName::src1);
107 if (!Src0.isReg() || !Src1.isImm() ||
108 !
TII.isLegalToSwap(
MI, Src0Idx, Src1Idx))
137 if (!ST.hasVOPD3F64OPYSrcHazard())
142 AMDGPU::getNamedOperandIdx(MIX.
getOpcode(), AMDGPU::OpName::vdst);
143 assert(VDstIdx != -1 &&
"VOPD3 OPX component must have a vdst");
144 if (
TII.getOpSize(MIX, VDstIdx) != 8)
150 unsigned NumVGPRs =
TRI->getNumUsedPhysRegs(
151 MF.
getRegInfo(), AMDGPU::VGPR_32RegClass,
false);
152 for (AMDGPU::OpName Name :
153 {AMDGPU::OpName::src0, AMDGPU::OpName::src1, AMDGPU::OpName::src2}) {
156 if (!Src || !Src->isReg() ||
157 !AMDGPU::VGPR_32RegClass.contains(Src->getReg()))
159 unsigned Idx =
TRI->getHWRegIndex(Src->getReg());
160 if ((Idx + 1) % Granule == 0 && Idx + 1 >= NumVGPRs)
175 bool IsVOPD3,
bool AllowSameVGPR,
182 if (IsVOPD3 && !ST.hasVOPD3())
188 bool Commute[2] = {
false,
false};
193 if (
TII.isDPP(MIX) ||
TII.isDPP(MIY))
205 for (
auto &
Literal : UniqueLiterals) {
209 UniqueLiterals.push_back(&
Op);
224 for (
auto CompIdx : VOPD::COMPONENTS) {
226 const AMDGPU::OpName Src0Name =
227 Commute[CompIdx] ? AMDGPU::OpName::src1 : AMDGPU::OpName::src0;
228 const AMDGPU::OpName Src1Name =
229 Commute[CompIdx] ? AMDGPU::OpName::src0 : AMDGPU::OpName::src1;
235 if (
TII.regUsesConstantBus(Src0, MRI))
236 UniqueScalarRegs.
insert(Src0.getReg());
237 }
else if (!
TII.isInlineConstant(Src0)) {
248 int OpIdx = getNamedOperandIdx(
MI.getOpcode(), Src0Name);
249 if (
TII.getOpSize(
MI, OpIdx) != 4)
253 &AMDGPU::SGPR_32RegClass);
258 int32_t
Imm =
static_cast<int32_t
>(Src0.getImm());
260 Fixups.push_back({CompIdx,
static_cast<unsigned>(OpIdx),
Imm, SlotRC});
266 if (InstInfo[CompIdx].hasMandatoryLiteral()) {
267 auto CompOprIdx = InstInfo[CompIdx].getMandatoryLiteralCompOperandIndex();
268 AddLiteral(
MI.getOperand(CompOprIdx));
272 if (
MI.getDesc().hasImplicitUseOfPhysReg(AMDGPU::VCC))
273 UniqueScalarRegs.
insert(AMDGPU::VCC_LO);
279 assert(
TRI->isVectorRegister(MRI, Src1->getReg()));
280 }
else if (IsVOPD3) {
287 TII.getNamedOperand(
MI, AMDGPU::OpName::src2)) {
290 if (!Src2->isImm() || Src2->getImm())
297 if (
TII.regUsesConstantBus(*Src2, MRI)) {
298 assert(
MI.getOpcode() == AMDGPU::V_CNDMASK_B32_e64);
299 UniqueScalarRegs.
insert(Src2->getReg());
303 for (
auto OpName : {AMDGPU::OpName::clamp, AMDGPU::OpName::omod,
304 AMDGPU::OpName::op_sel}) {
312 {AMDGPU::OpName::src0_modifiers, AMDGPU::OpName::src1_modifiers,
313 AMDGPU::OpName::src2_modifiers}) {
321 if (UniqueLiterals.
size() > 1)
325 if (MaterializedLiterals.
size() > 1)
327 if ((UniqueLiterals.
size() + MaterializedLiterals.
size() +
328 UniqueScalarRegs.
size()) > 2)
331 auto GetVRegIdx = [&](
unsigned OpcodeIdx,
unsigned OperandIdx) {
333 if (Commute[OpcodeIdx]) {
334 int Src0Idx = getNamedOperandIdx(
MI.getOpcode(), AMDGPU::OpName::src0);
335 int Src1Idx = getNamedOperandIdx(
MI.getOpcode(), AMDGPU::OpName::src1);
336 if ((
int)OperandIdx == Src0Idx)
337 OperandIdx = Src1Idx;
338 else if ((
int)OperandIdx == Src1Idx)
339 OperandIdx = Src0Idx;
342 if (Operand.
isReg() &&
TRI->isVectorRegister(MRI, Operand.
getReg()))
349 bool SkipSrc = (ST.hasGFX11_7Insts() || ST.hasGFX12Insts()) &&
350 MIX.
getOpcode() == AMDGPU::V_MOV_B32_e32 &&
351 MIY.
getOpcode() == AMDGPU::V_MOV_B32_e32;
354 if (InstInfo.hasInvalidOperand(GetVRegIdx, *
TRI, SkipSrc, AllowSameVGPR,
355 IsVOPD3, ST.hasVOPDInterlockHazard()))
359 <<
"\n\tY: " << MIY <<
"\n");
360 LiteralFixups.
assign(Fixups);
361 CommuteXY[VOPD::X] = Commute[VOPD::X];
362 CommuteXY[VOPD::Y] = Commute[VOPD::Y];
368static std::optional<VOPDMatchInfo>
379 if (!(FirstCanBeVOPD.
X && SecondCanBeVOPD.
Y) &&
380 !(FirstCanBeVOPD.
Y && SecondCanBeVOPD.
X))
384 if (
TII.hasRAWDependency(FirstMI, SecondMI))
388 bool AllowSameVGPR = ST.hasGFX12Insts();
393 bool CommuteXY[2] = {
false,
false};
395 if (FirstCanBeVOPD.
X && SecondCanBeVOPD.
Y) {
399 {&FirstMI, &SecondMI},
406 if (FirstCanBeVOPD.
Y && SecondCanBeVOPD.
X) {
409 bool IsAntiDep =
TII.hasRAWDependency(SecondMI, FirstMI);
410 AllowSameVGPR &= !IsAntiDep;
411 if (IsAntiDep && !
TII.isVOPDAntidependencyAllowed(SecondMI))
416 {&FirstMI, &SecondMI},
455 auto CheckCanBeVOPD = [&](
bool VOPD3) {
458 return CanBeVOPD.
Y || CanBeVOPD.
X;
460 return CheckCanBeVOPD(
false) || (ST.hasVOPD3() && CheckCanBeVOPD(
true));
463#ifdef EXPENSIVE_CHECKS
466 MII != FirstMI->
getParent()->instr_end(); ++MII) {
467 if (&*MII == &SecondMI)
471 }() &&
"Expected FirstMI to precede SecondMI");
484 SUnit &Head,
bool Forward,
bool StopAtLoads) {
491 Stack.push_back(&Head);
492 while (!Stack.empty()) {
493 SUnit *SU = Stack.pop_back_val();
495 for (
const SDep &Edge : Deps) {
496 if (StopAtLoads && Edge.getKind() !=
SDep::Data)
498 SUnit *Dep = Edge.getSUnit();
508 Stack.push_back(Dep);
526 if (ILoadSuccs.
empty())
535 if (JLoadPreds.
empty())
538 for (
SUnit *ILoad : ILoadSuccs) {
540 if (!LoadPredsComputed.
test(ILoad->NodeNum)) {
543 LoadPredsComputed.
set(ILoad->NodeNum);
546 for (
SUnit *JLoad : JLoadPreds) {
547 if (ILoad == JLoad) {
549 dbgs() <<
"Will not pair " <<
I <<
" with " << J <<
"\n"
550 <<
" Fusion would introduce a cyclic dependency with "
557 <<
" Fusion may force " << *JLoad
558 <<
" to complete its load before dispatching "
572struct VOPDPairingMutation : ScheduleDAGMutation {
579 void apply(ScheduleDAGInstrs *DAG)
override {
580 const TargetInstrInfo &
TII = *DAG->
TII;
583 LLVM_DEBUG(
dbgs() <<
"Target does not support VOPDPairingMutation\n");
587 BitVector VOPDCapable(DAG->
SUnits.size());
590 for (
auto ISUI = DAG->
SUnits.begin(),
E = DAG->
SUnits.end(); ISUI !=
E;
592 const MachineInstr *IMI = ISUI->getInstr();
595 VOPDCapable[IIdx] =
true;
599 SmallPtrSet<SUnit *, 8> ILoadSuccs;
604 BitVector LoadPredsComputed(DAG->
SUnits.size());
607 BitVector Scratch(DAG->
SUnits.size());
608 for (
auto ISUI = DAG->
SUnits.begin(),
E = DAG->
SUnits.end(); ISUI !=
E;
610 if (!VOPDCapable[IIdx])
612 const MachineInstr *IMI = ISUI->getInstr();
618 unsigned JIdx = IIdx + 1;
619 for (
auto JSUI = ISUI + 1; JSUI !=
E; ++JSUI, ++JIdx) {
620 if (!VOPDCapable[JIdx] || JSUI->isBoundaryNode())
622 const MachineInstr *JMI = JSUI->getInstr();
628 LoadPredsCache, Scratch))
633 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 const MachineOperand & getNamedOp(const MachineInstr &MI, AMDGPU::OpName Name)
static void collectLoads(SmallPtrSet< 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 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 loadsMayOverlap(SUnit &I, const SmallPtrSet< SUnit *, 8 > &ILoadSuccs, SUnit &J, BitVector &LoadPredsComputed, SmallVector< SmallPtrSet< 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 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 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.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
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.