34#define DEBUG_TYPE "gcn-vopd-utils"
45 const bool IsX = CompIdx == VOPD::X;
48 OpIdx = getNamedOperandIdx(VOPDOpc, IsX ? OpName::src0X : OpName::src0Y);
51 OpIdx = getNamedOperandIdx(VOPDOpc, IsX ? OpName::vsrc1X : OpName::vsrc1Y);
54 OpIdx = getNamedOperandIdx(VOPDOpc, IsX ? OpName::vsrc2X : OpName::vsrc2Y);
56 OpIdx = getNamedOperandIdx(VOPDOpc, IsX ? OpName::src2X : OpName::src2Y);
63 return TII.getRegClass(
TII.get(VOPDOpc), OpIdx);
70 unsigned CompIdx,
unsigned SrcIdx,
77 AMDGPU::OpName Name) {
78 return MI.getOperand(getNamedOperandIdx(
MI.getOpcode(), Name));
85 unsigned Opc =
MI.getOpcode();
86 if (
Opc != AMDGPU::V_DOT2_F32_F16 &&
Opc != AMDGPU::V_DOT2_F32_BF16)
125 if (IsVOPD3 && !ST.hasVOPD3())
130 if (
TII.isDPP(MIX) ||
TII.isDPP(MIY))
142 for (
auto &
Literal : UniqueLiterals) {
146 UniqueLiterals.push_back(&
Op);
161 for (
auto CompIdx : VOPD::COMPONENTS) {
168 if (
TII.regUsesConstantBus(Src0, MRI))
170 }
else if (!
TII.isInlineConstant(Src0)) {
181 int OpIdx = getNamedOperandIdx(
MI.getOpcode(), AMDGPU::OpName::src0);
182 if (
TII.getOpSize(
MI, OpIdx) != 4)
186 &AMDGPU::SGPR_32RegClass);
191 int32_t
Imm =
static_cast<int32_t
>(Src0.
getImm());
193 Fixups.push_back({CompIdx,
static_cast<unsigned>(OpIdx),
Imm, SlotRC});
199 if (InstInfo[CompIdx].hasMandatoryLiteral()) {
200 auto CompOprIdx = InstInfo[CompIdx].getMandatoryLiteralCompOperandIndex();
201 AddLiteral(
MI.getOperand(CompOprIdx));
205 if (
MI.getDesc().hasImplicitUseOfPhysReg(AMDGPU::VCC))
206 UniqueScalarRegs.
insert(AMDGPU::VCC_LO);
209 TII.getNamedOperand(
MI, AMDGPU::OpName::src1)) {
213 assert(
TRI->isVectorRegister(MRI, Src1->getReg()));
214 }
else if (IsVOPD3) {
221 TII.getNamedOperand(
MI, AMDGPU::OpName::src2)) {
224 if (!Src2->isImm() || Src2->getImm())
231 if (
TII.regUsesConstantBus(*Src2, MRI)) {
232 assert(
MI.getOpcode() == AMDGPU::V_CNDMASK_B32_e64);
233 UniqueScalarRegs.
insert(Src2->getReg());
237 for (
auto OpName : {AMDGPU::OpName::clamp, AMDGPU::OpName::omod,
238 AMDGPU::OpName::op_sel}) {
246 {AMDGPU::OpName::src0_modifiers, AMDGPU::OpName::src1_modifiers,
247 AMDGPU::OpName::src2_modifiers}) {
255 if (UniqueLiterals.
size() > 1)
259 if (MaterializedLiterals.
size() > 1)
261 if ((UniqueLiterals.
size() + MaterializedLiterals.
size() +
262 UniqueScalarRegs.
size()) > 2)
265 auto GetVRegIdx = [&](
unsigned OpcodeIdx,
unsigned OperandIdx) {
268 if (Operand.
isReg() &&
TRI->isVectorRegister(MRI, Operand.
getReg()))
275 bool SkipSrc = (ST.hasGFX11_7Insts() || ST.hasGFX12Insts()) &&
276 MIX.
getOpcode() == AMDGPU::V_MOV_B32_e32 &&
277 MIY.
getOpcode() == AMDGPU::V_MOV_B32_e32;
280 if (InstInfo.hasInvalidOperand(GetVRegIdx, *
TRI, SkipSrc, AllowSameVGPR,
281 IsVOPD3, ST.hasGFX11VOPDInterlockHazard()))
285 <<
"\n\tY: " << MIY <<
"\n");
286 LiteralFixups.
assign(Fixups);
292static std::optional<VOPDMatchInfo>
303 if (!(FirstCanBeVOPD.
X && SecondCanBeVOPD.
Y) &&
304 !(FirstCanBeVOPD.
Y && SecondCanBeVOPD.
X))
308 if (
TII.hasRAWDependency(FirstMI, SecondMI))
312 bool AllowSameVGPR = ST.hasGFX12Insts();
318 if (FirstCanBeVOPD.
X && SecondCanBeVOPD.
Y) {
322 {&FirstMI, &SecondMI}, 0, IsVOPD3, std::move(Fixups)};
325 if (FirstCanBeVOPD.
Y && SecondCanBeVOPD.
X) {
328 bool IsAntiDep =
TII.hasRAWDependency(SecondMI, FirstMI);
329 AllowSameVGPR &= !IsAntiDep;
330 if (IsAntiDep && !
TII.isVOPDAntidependencyAllowed(SecondMI))
335 {&FirstMI, &SecondMI}, 1, IsVOPD3, std::move(Fixups)};
370 auto CheckCanBeVOPD = [&](
bool VOPD3) {
373 return CanBeVOPD.
Y || CanBeVOPD.
X;
375 return CheckCanBeVOPD(
false) || (ST.hasVOPD3() && CheckCanBeVOPD(
true));
378#ifdef EXPENSIVE_CHECKS
381 MII != FirstMI->
getParent()->instr_end(); ++MII) {
382 if (&*MII == &SecondMI)
386 }() &&
"Expected FirstMI to precede SecondMI");
399 SUnit &Head,
bool Forward,
bool StopAtLoads) {
406 Stack.push_back(&Head);
407 while (!Stack.empty()) {
408 SUnit *SU = Stack.pop_back_val();
410 for (
const SDep &Edge : Deps) {
411 if (StopAtLoads && Edge.getKind() !=
SDep::Data)
413 SUnit *Dep = Edge.getSUnit();
423 Stack.push_back(Dep);
441 if (ILoadSuccs.
empty())
450 if (JLoadPreds.
empty())
453 for (
SUnit *ILoad : ILoadSuccs) {
455 if (!LoadPredsComputed.
test(ILoad->NodeNum)) {
458 LoadPredsComputed.
set(ILoad->NodeNum);
461 for (
SUnit *JLoad : JLoadPreds) {
462 if (ILoad == JLoad) {
464 dbgs() <<
"Will not pair SU(" <<
I.NodeNum <<
") with SU("
466 <<
" Fusion would introduce a cyclic dependency with SU("
467 << ILoad->NodeNum <<
")\n");
474 <<
" Fusion may force SU(" << JLoad->NodeNum
475 <<
") to complete its load before dispatching SU("
476 << ILoad->NodeNum <<
")\n");
489struct VOPDPairingMutation : ScheduleDAGMutation {
496 void apply(ScheduleDAGInstrs *DAG)
override {
497 const TargetInstrInfo &
TII = *DAG->
TII;
500 LLVM_DEBUG(
dbgs() <<
"Target does not support VOPDPairingMutation\n");
504 BitVector VOPDCapable(DAG->
SUnits.size());
507 for (
auto ISUI = DAG->
SUnits.begin(),
E = DAG->
SUnits.end(); ISUI !=
E;
509 const MachineInstr *IMI = ISUI->getInstr();
512 VOPDCapable[IIdx] =
true;
516 SmallPtrSet<SUnit *, 8> ILoadSuccs;
521 BitVector LoadPredsComputed(DAG->
SUnits.size());
524 BitVector Scratch(DAG->
SUnits.size());
525 for (
auto ISUI = DAG->
SUnits.begin(),
E = DAG->
SUnits.end(); ISUI !=
E;
527 if (!VOPDCapable[IIdx])
529 const MachineInstr *IMI = ISUI->getInstr();
535 unsigned JIdx = IIdx + 1;
536 for (
auto JSUI = ISUI + 1; JSUI !=
E; ++JSUI, ++JIdx) {
537 if (!VOPDCapable[JIdx] || JSUI->isBoundaryNode())
539 const MachineInstr *JMI = JSUI->getInstr();
545 LoadPredsCache, Scratch))
550 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 const TargetRegisterClass * getVOPDSrcRegClass(const SIInstrInfo &TII, int VOPDOpc, unsigned CompIdx, unsigned SrcIdx)
static bool checkVOPDRegConstraints(const SIInstrInfo &TII, const MachineInstr &MIX, const MachineInstr &MIY, bool IsVOPD3, bool AllowSameVGPR, SmallVectorImpl< VOPDLiteralFixup > &LiteralFixups)
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.
bool isImm() const
isImm - Tests if this is a MO_Immediate 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)
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.
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.