33#define DEBUG_TYPE "gcn-vopd-utils"
39 unsigned CompIdx,
unsigned SrcIdx,
43 const bool IsX = CompIdx == VOPD::X;
46 OpIdx = getNamedOperandIdx(VOPDOpc, IsX ? OpName::src0X : OpName::src0Y);
49 OpIdx = getNamedOperandIdx(VOPDOpc, IsX ? OpName::vsrc1X : OpName::vsrc1Y);
52 OpIdx = getNamedOperandIdx(VOPDOpc, IsX ? OpName::vsrc2X : OpName::vsrc2Y);
54 OpIdx = getNamedOperandIdx(VOPDOpc, IsX ? OpName::src2X : OpName::src2Y);
61 return TII.getRegClass(
TII.get(VOPDOpc), OpIdx)->contains(PhysSrcReg);
65 AMDGPU::OpName Name) {
66 return MI.getOperand(getNamedOperandIdx(
MI.getOpcode(), Name));
73 unsigned Opc =
MI.getOpcode();
74 if (
Opc != AMDGPU::V_DOT2_F32_F16 &&
Opc != AMDGPU::V_DOT2_F32_BF16)
105 if (IsVOPD3 && !ST.hasVOPD3())
110 if (
TII.isDPP(MIX) ||
TII.isDPP(MIY))
118 for (
auto &
Literal : UniqueLiterals) {
122 UniqueLiterals.push_back(&
Op);
134 for (
auto CompIdx : VOPD::COMPONENTS) {
141 if (!
TRI->isVectorRegister(MRI, Src0.
getReg()))
143 }
else if (!
TII.isInlineConstant(Src0)) {
151 if (InstInfo[CompIdx].hasMandatoryLiteral()) {
152 auto CompOprIdx = InstInfo[CompIdx].getMandatoryLiteralCompOperandIndex();
153 addLiteral(
MI.getOperand(CompOprIdx));
157 if (
MI.getDesc().hasImplicitUseOfPhysReg(AMDGPU::VCC))
158 UniqueScalarRegs.
insert(AMDGPU::VCC_LO);
161 TII.getNamedOperand(
MI, AMDGPU::OpName::src1)) {
165 assert(
TRI->isVectorRegister(MRI, Src1->getReg()));
166 }
else if (IsVOPD3) {
173 TII.getNamedOperand(
MI, AMDGPU::OpName::src2)) {
176 if (!Src2->isImm() || Src2->getImm())
183 if (!
TRI->isVectorRegister(MRI, Src2->getReg())) {
184 assert(
MI.getOpcode() == AMDGPU::V_CNDMASK_B32_e64);
185 UniqueScalarRegs.
insert(Src2->getReg());
189 for (
auto OpName : {AMDGPU::OpName::clamp, AMDGPU::OpName::omod,
190 AMDGPU::OpName::op_sel}) {
198 {AMDGPU::OpName::src0_modifiers, AMDGPU::OpName::src1_modifiers,
199 AMDGPU::OpName::src2_modifiers}) {
207 if (UniqueLiterals.
size() > 1)
209 if ((UniqueLiterals.
size() + UniqueScalarRegs.
size()) > 2)
212 auto getVRegIdx = [&](
unsigned OpcodeIdx,
unsigned OperandIdx) {
215 if (Operand.
isReg() &&
TRI->isVectorRegister(MRI, Operand.
getReg()))
222 bool SkipSrc = (ST.hasGFX11_7Insts() || ST.hasGFX12Insts()) &&
223 MIX.
getOpcode() == AMDGPU::V_MOV_B32_e32 &&
224 MIY.
getOpcode() == AMDGPU::V_MOV_B32_e32;
227 if (InstInfo.hasInvalidOperand(getVRegIdx, *
TRI, SkipSrc, AllowSameVGPR,
232 <<
"\n\tY: " << MIY <<
"\n");
238static std::optional<VOPDMatchInfo>
249 if (!(FirstCanBeVOPD.
X && SecondCanBeVOPD.
Y) &&
250 !(FirstCanBeVOPD.
Y && SecondCanBeVOPD.
X))
254 if (
TII.hasRAWDependency(FirstMI, SecondMI))
258 bool AllowSameVGPR = ST.hasGFX12Insts();
260 if (FirstCanBeVOPD.
X && SecondCanBeVOPD.
Y) {
265 if (FirstCanBeVOPD.
Y && SecondCanBeVOPD.
X) {
268 bool IsAntiDep =
TII.hasRAWDependency(SecondMI, FirstMI);
269 AllowSameVGPR &= !IsAntiDep;
270 if (IsAntiDep && !
TII.isVOPDAntidependencyAllowed(SecondMI))
308 auto checkCanBeVOPD = [&](
bool VOPD3) {
311 return CanBeVOPD.
Y || CanBeVOPD.
X;
313 return checkCanBeVOPD(
false) || (ST.hasVOPD3() && checkCanBeVOPD(
true));
316#ifdef EXPENSIVE_CHECKS
319 MII != FirstMI->
getParent()->instr_end(); ++MII) {
320 if (&*MII == &SecondMI)
324 }() &&
"Expected FirstMI to precede SecondMI");
337 SUnit &Head,
bool Forward,
bool StopAtLoads) {
344 Stack.push_back(&Head);
345 while (!Stack.empty()) {
346 SUnit *SU = Stack.pop_back_val();
348 for (
const SDep &Edge : Deps) {
349 if (StopAtLoads && Edge.getKind() !=
SDep::Data)
351 SUnit *Dep = Edge.getSUnit();
361 Stack.push_back(Dep);
379 if (ILoadSuccs.
empty())
388 if (JLoadPreds.
empty())
391 for (
SUnit *ILoad : ILoadSuccs) {
393 if (!LoadPredsComputed.
test(ILoad->NodeNum)) {
396 LoadPredsComputed.
set(ILoad->NodeNum);
399 for (
SUnit *JLoad : JLoadPreds) {
400 if (ILoad == JLoad) {
402 dbgs() <<
"Will not pair SU(" <<
I.NodeNum <<
") with SU("
404 <<
" Fusion would introduce a cyclic dependency with SU("
405 << ILoad->NodeNum <<
")\n");
412 <<
" Fusion may force SU(" << JLoad->NodeNum
413 <<
") to complete its load before dispatching SU("
414 << ILoad->NodeNum <<
")\n");
427struct VOPDPairingMutation : ScheduleDAGMutation {
434 void apply(ScheduleDAGInstrs *DAG)
override {
435 const TargetInstrInfo &
TII = *DAG->
TII;
438 LLVM_DEBUG(
dbgs() <<
"Target does not support VOPDPairingMutation\n");
442 BitVector VOPDCapable(DAG->
SUnits.size());
445 for (
auto ISUI = DAG->
SUnits.begin(),
E = DAG->
SUnits.end(); ISUI !=
E;
447 const MachineInstr *IMI = ISUI->getInstr();
450 VOPDCapable[IIdx] =
true;
454 SmallPtrSet<SUnit *, 8> ILoadSuccs;
459 BitVector LoadPredsComputed(DAG->
SUnits.size());
462 BitVector Scratch(DAG->
SUnits.size());
463 for (
auto ISUI = DAG->
SUnits.begin(),
E = DAG->
SUnits.end(); ISUI !=
E;
465 if (!VOPDCapable[IIdx])
467 const MachineInstr *IMI = ISUI->getInstr();
473 unsigned JIdx = IIdx + 1;
474 for (
auto JSUI = ISUI + 1; JSUI !=
E; ++JSUI, ++JIdx) {
475 if (!VOPDCapable[JIdx] || JSUI->isBoundaryNode())
477 const MachineInstr *JMI = JSUI->getInstr();
483 LoadPredsCache, Scratch))
488 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 canMapVOP3PToVOPD(const MachineInstr &MI)
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.
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.
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 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)
LLVM_READONLY bool hasNamedOperand(uint64_t Opcode, OpName NamedIdx)
unsigned getVOPDEncodingFamily(const MCSubtargetInfo &ST)
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.
bool checkVOPDRegConstraints(const SIInstrInfo &TII, const MachineInstr &FirstMI, const MachineInstr &SecondMI, bool IsVOPD3, bool AllowSameVGPR)
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.
Describes a matched VOPD pair: which instruction is the X component and which is the Y component,...