LLVM  16.0.0git
GCNVOPDUtils.cpp
Go to the documentation of this file.
1 //===- GCNVOPDUtils.cpp - GCN VOPD Utils ------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 /// \file This file contains the AMDGPU DAG scheduling
10 /// mutation to pair VOPD instructions back to back. It also contains
11 // subroutines useful in the creation of VOPD instructions
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "GCNVOPDUtils.h"
16 #include "AMDGPUSubtarget.h"
17 #include "GCNSubtarget.h"
19 #include "SIInstrInfo.h"
20 #include "Utils/AMDGPUBaseInfo.h"
21 #include "llvm/ADT/STLExtras.h"
22 #include "llvm/ADT/SmallVector.h"
31 #include "llvm/MC/MCInst.h"
32 
33 using namespace llvm;
34 
35 #define DEBUG_TYPE "gcn-vopd-utils"
36 
38  const MachineInstr &FirstMI,
39  const MachineInstr &SecondMI) {
40  namespace VOPD = AMDGPU::VOPD;
41 
42  const MachineFunction *MF = FirstMI.getMF();
43  const GCNSubtarget &ST = MF->getSubtarget<GCNSubtarget>();
44  const SIRegisterInfo *TRI = dyn_cast<SIRegisterInfo>(ST.getRegisterInfo());
45  const MachineRegisterInfo &MRI = MF->getRegInfo();
46  // Literals also count against scalar bus limit
48  auto addLiteral = [&](const MachineOperand &Op) {
49  for (auto &Literal : UniqueLiterals) {
50  if (Literal->isIdenticalTo(Op))
51  return;
52  }
53  UniqueLiterals.push_back(&Op);
54  };
55  SmallVector<Register> UniqueScalarRegs;
56  assert([&]() -> bool {
57  for (auto MII = MachineBasicBlock::const_iterator(&FirstMI);
58  MII != FirstMI.getParent()->instr_end(); ++MII) {
59  if (&*MII == &SecondMI)
60  return true;
61  }
62  return false;
63  }() && "Expected FirstMI to precede SecondMI");
64  // Cannot pair dependent instructions
65  for (const auto &Use : SecondMI.uses())
66  if (Use.isReg() && FirstMI.modifiesRegister(Use.getReg()))
67  return false;
68 
69  auto getVRegIdx = [&](unsigned OpcodeIdx, unsigned OperandIdx) {
70  const MachineInstr &MI = (OpcodeIdx == VOPD::X) ? FirstMI : SecondMI;
71  const MachineOperand &Operand = MI.getOperand(OperandIdx);
72  if (Operand.isReg() && TRI->isVectorRegister(MRI, Operand.getReg()))
73  return Operand.getReg();
74  return Register();
75  };
76 
77  auto InstInfo =
78  AMDGPU::getVOPDInstInfo(FirstMI.getDesc(), SecondMI.getDesc());
79 
80  for (auto CompIdx : VOPD::COMPONENTS) {
81  const MachineInstr &MI = (CompIdx == VOPD::X) ? FirstMI : SecondMI;
82 
83  const MachineOperand &Src0 = MI.getOperand(VOPD::Component::SRC0);
84  if (Src0.isReg()) {
85  if (!TRI->isVectorRegister(MRI, Src0.getReg())) {
86  if (!is_contained(UniqueScalarRegs, Src0.getReg()))
87  UniqueScalarRegs.push_back(Src0.getReg());
88  }
89  } else {
90  if (!TII.isInlineConstant(MI, VOPD::Component::SRC0))
91  addLiteral(Src0);
92  }
93 
94  if (InstInfo[CompIdx].hasMandatoryLiteral()) {
95  auto CompOprIdx = InstInfo[CompIdx].getMandatoryLiteralCompOperandIndex();
96  addLiteral(MI.getOperand(CompOprIdx));
97  }
98  if (MI.getDesc().hasImplicitUseOfPhysReg(AMDGPU::VCC))
99  UniqueScalarRegs.push_back(AMDGPU::VCC_LO);
100  }
101 
102  if (UniqueLiterals.size() > 1)
103  return false;
104  if ((UniqueLiterals.size() + UniqueScalarRegs.size()) > 2)
105  return false;
106  if (InstInfo.hasInvalidOperand(getVRegIdx))
107  return false;
108 
109  LLVM_DEBUG(dbgs() << "VOPD Reg Constraints Passed\n\tX: " << FirstMI
110  << "\n\tY: " << SecondMI << "\n");
111  return true;
112 }
113 
114 /// Check if the instr pair, FirstMI and SecondMI, should be scheduled
115 /// together. Given SecondMI, when FirstMI is unspecified, then check if
116 /// SecondMI may be part of a fused pair at all.
118  const TargetSubtargetInfo &TSI,
119  const MachineInstr *FirstMI,
120  const MachineInstr &SecondMI) {
121  const SIInstrInfo &STII = static_cast<const SIInstrInfo &>(TII);
122  unsigned Opc2 = SecondMI.getOpcode();
123  auto SecondCanBeVOPD = AMDGPU::getCanBeVOPD(Opc2);
124 
125  // One instruction case
126  if (!FirstMI)
127  return SecondCanBeVOPD.Y;
128 
129  unsigned Opc = FirstMI->getOpcode();
130  auto FirstCanBeVOPD = AMDGPU::getCanBeVOPD(Opc);
131 
132  if (!((FirstCanBeVOPD.X && SecondCanBeVOPD.Y) ||
133  (FirstCanBeVOPD.Y && SecondCanBeVOPD.X)))
134  return false;
135 
136  return checkVOPDRegConstraints(STII, *FirstMI, SecondMI);
137 }
138 
139 /// Adapts design from MacroFusion
140 /// Puts valid candidate instructions back-to-back so they can easily
141 /// be turned into VOPD instructions
142 /// Greedily pairs instruction candidates. O(n^2) algorithm.
144  ShouldSchedulePredTy shouldScheduleAdjacent; // NOLINT: function pointer
145 
147  ShouldSchedulePredTy shouldScheduleAdjacent) // NOLINT: function pointer
149 
150  void apply(ScheduleDAGInstrs *DAG) override {
151  const TargetInstrInfo &TII = *DAG->TII;
152  const GCNSubtarget &ST = DAG->MF.getSubtarget<GCNSubtarget>();
153  if (!AMDGPU::hasVOPD(ST) || !ST.isWave32()) {
154  LLVM_DEBUG(dbgs() << "Target does not support VOPDPairingMutation\n");
155  return;
156  }
157 
158  std::vector<SUnit>::iterator ISUI, JSUI;
159  for (ISUI = DAG->SUnits.begin(); ISUI != DAG->SUnits.end(); ++ISUI) {
160  const MachineInstr *IMI = ISUI->getInstr();
161  if (!shouldScheduleAdjacent(TII, ST, nullptr, *IMI))
162  continue;
163  if (!hasLessThanNumFused(*ISUI, 2))
164  continue;
165 
166  for (JSUI = ISUI + 1; JSUI != DAG->SUnits.end(); ++JSUI) {
167  if (JSUI->isBoundaryNode())
168  continue;
169  const MachineInstr *JMI = JSUI->getInstr();
170  if (!hasLessThanNumFused(*JSUI, 2) ||
171  !shouldScheduleAdjacent(TII, ST, IMI, *JMI))
172  continue;
173  if (fuseInstructionPair(*DAG, *ISUI, *JSUI))
174  break;
175  }
176  }
177  LLVM_DEBUG(dbgs() << "Completed VOPDPairingMutation\n");
178  }
179 };
180 
181 std::unique_ptr<ScheduleDAGMutation> llvm::createVOPDPairingMutation() {
182  return std::make_unique<VOPDPairingMutation>(shouldScheduleVOPDAdjacent);
183 }
ScheduleDAG.h
llvm::MachineInstr::uses
iterator_range< mop_iterator > uses()
Returns a range that includes all operands that are register uses.
Definition: MachineInstr.h:689
MI
IRTranslator LLVM IR MI
Definition: IRTranslator.cpp:108
MachineInstr.h
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
llvm::AMDGPU::hasVOPD
bool hasVOPD(const MCSubtargetInfo &STI)
Definition: AMDGPUBaseInfo.cpp:1950
llvm::MachineRegisterInfo
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Definition: MachineRegisterInfo.h:50
llvm::SmallVector
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1199
llvm::checkVOPDRegConstraints
bool checkVOPDRegConstraints(const SIInstrInfo &TII, const MachineInstr &FirstMI, const MachineInstr &SecondMI)
Definition: GCNVOPDUtils.cpp:37
MachineBasicBlock.h
GCNVOPDUtils.h
llvm::MachineInstr::getDesc
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
Definition: MachineInstr.h:513
TargetInstrInfo.h
llvm::MachineInstr::getMF
const MachineFunction * getMF() const
Return the function that contains the basic block that this instruction belongs to.
Definition: MachineInstr.cpp:678
llvm::GCNSubtarget
Definition: GCNSubtarget.h:31
STLExtras.h
TRI
unsigned const TargetRegisterInfo * TRI
Definition: MachineSink.cpp:1628
LLVM_DEBUG
#define LLVM_DEBUG(X)
Definition: Debug.h:101
MachineRegisterInfo.h
llvm::dbgs
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
llvm::MachineFunction::getRegInfo
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Definition: MachineFunction.h:667
llvm::TargetInstrInfo
TargetInstrInfo - Interface to description of machine instruction set.
Definition: TargetInstrInfo.h:98
GCNSubtarget.h
VOPDPairingMutation::apply
void apply(ScheduleDAGInstrs *DAG) override
Definition: GCNVOPDUtils.cpp:150
AMDGPUSubtarget.h
MCInst.h
TII
const HexagonInstrInfo * TII
Definition: HexagonCopyToCombine.cpp:125
llvm::AMDGPU::getVOPDInstInfo
VOPD::InstInfo getVOPDInstInfo(const MCInstrDesc &OpX, const MCInstrDesc &OpY)
Definition: AMDGPUBaseInfo.cpp:557
llvm::MachineOperand
MachineOperand class - Representation of each machine instruction operand.
Definition: MachineOperand.h:48
llvm::fuseInstructionPair
bool fuseInstructionPair(ScheduleDAGInstrs &DAG, SUnit &FirstSU, SUnit &SecondSU)
Create an artificial edge between FirstSU and SecondSU.
Definition: MacroFusion.cpp:53
llvm::SIRegisterInfo
Definition: SIRegisterInfo.h:30
shouldScheduleVOPDAdjacent
static bool shouldScheduleVOPDAdjacent(const TargetInstrInfo &TII, const TargetSubtargetInfo &TSI, const MachineInstr *FirstMI, const MachineInstr &SecondMI)
Check if the instr pair, FirstMI and SecondMI, should be scheduled together.
Definition: GCNVOPDUtils.cpp:117
Register
Promote Memory to Register
Definition: Mem2Reg.cpp:110
X
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
llvm::shouldScheduleAdjacent
static bool shouldScheduleAdjacent(const TargetInstrInfo &TII, const TargetSubtargetInfo &TSI, const MachineInstr *FirstMI, const MachineInstr &SecondMI)
Check if the instr pair, FirstMI and SecondMI, should be fused together.
Definition: ARMMacroFusion.cpp:51
llvm::MachineFunction::getSubtarget
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Definition: MachineFunction.h:657
AMDGPUMCTargetDesc.h
llvm::MachineOperand::isReg
bool isReg() const
isReg - Tests if this is a MO_Register operand.
Definition: MachineOperand.h:320
llvm::MachineInstr
Representation of each machine instruction.
Definition: MachineInstr.h:66
MacroFusion.h
llvm::ARM_MB::ST
@ ST
Definition: ARMBaseInfo.h:73
llvm::is_contained
bool is_contained(R &&Range, const E &Element)
Wrapper function around std::find to detect if an element exists in a container.
Definition: STLExtras.h:1843
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::MachineOperand::getReg
Register getReg() const
getReg - Returns the register number.
Definition: MachineOperand.h:359
SIInstrInfo.h
llvm::MachineFunction
Definition: MachineFunction.h:257
VOPDPairingMutation::shouldScheduleAdjacent
ShouldSchedulePredTy shouldScheduleAdjacent
Definition: GCNVOPDUtils.cpp:144
ScheduleDAGMutation.h
llvm::MachineInstr::getOpcode
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
Definition: MachineInstr.h:516
llvm::ScheduleDAG::MF
MachineFunction & MF
Machine function.
Definition: ScheduleDAG.h:559
llvm::createVOPDPairingMutation
std::unique_ptr< ScheduleDAGMutation > createVOPDPairingMutation()
Definition: GCNVOPDUtils.cpp:181
llvm::MachineInstr::getParent
const MachineBasicBlock * getParent() const
Definition: MachineInstr.h:313
llvm::TargetSubtargetInfo
TargetSubtargetInfo - Generic base class for all target subtargets.
Definition: TargetSubtargetInfo.h:62
llvm::AMDGPU::VOPD::COMPONENTS
constexpr unsigned COMPONENTS[]
Definition: AMDGPUBaseInfo.h:529
MRI
unsigned const MachineRegisterInfo * MRI
Definition: AArch64AdvSIMDScalarPass.cpp:105
llvm::MachineInstr::modifiesRegister
bool modifiesRegister(Register Reg, const TargetRegisterInfo *TRI=nullptr) const
Return true if the MachineInstr modifies (fully define or partially define) the specified register.
Definition: MachineInstr.h:1428
llvm::hasLessThanNumFused
bool hasLessThanNumFused(const SUnit &SU, unsigned FuseLimit)
Checks if the number of cluster edges between SU and its predecessors is less than FuseLimit.
Definition: MacroFusion.cpp:46
llvm::ScheduleDAG::SUnits
std::vector< SUnit > SUnits
The scheduling units.
Definition: ScheduleDAG.h:561
llvm::AMDGPU::VOPD::SRC0
@ SRC0
Definition: AMDGPUBaseInfo.h:516
llvm::AMDGPU::SendMsg::Op
Op
Definition: SIDefines.h:348
llvm::ScheduleDAG::TII
const TargetInstrInfo * TII
Target instruction information.
Definition: ScheduleDAG.h:557
VOPDPairingMutation
Adapts design from MacroFusion Puts valid candidate instructions back-to-back so they can easily be t...
Definition: GCNVOPDUtils.cpp:143
llvm::SIInstrInfo
Definition: SIInstrInfo.h:44
SmallVector.h
llvm::ScheduleDAGMutation
Mutate the DAG as a postpass after normal DAG building.
Definition: ScheduleDAGMutation.h:22
llvm::AMDGPU::getCanBeVOPD
CanBeVOPD getCanBeVOPD(unsigned Opc)
Definition: AMDGPUBaseInfo.cpp:420
MachineOperand.h
llvm::ScheduleDAGInstrs
A ScheduleDAG for scheduling lists of MachineInstr.
Definition: ScheduleDAGInstrs.h:120
VOPDPairingMutation::VOPDPairingMutation
VOPDPairingMutation(ShouldSchedulePredTy shouldScheduleAdjacent)
Definition: GCNVOPDUtils.cpp:146
llvm::MachineInstrBundleIterator< const MachineInstr >
llvm::Use
A Use represents the edge between a Value definition and its users.
Definition: Use.h:43
AMDGPUBaseInfo.h
llvm::ShouldSchedulePredTy
std::function< bool(const TargetInstrInfo &TII, const TargetSubtargetInfo &TSI, const MachineInstr *FirstMI, const MachineInstr &SecondMI)> ShouldSchedulePredTy
Check if the instr pair, FirstMI and SecondMI, should be fused together.
Definition: MacroFusion.h:35