25#define DEBUG_TYPE "si-optimize-exec-masking-pre-ra"
29class SIOptimizeExecMaskingPreRA {
61 return "SI optimize exec mask operations pre-RA";
74 "SI optimize exec mask operations pre-RA",
false,
false)
79char SIOptimizeExecMaskingPreRALegacy::ID = 0;
84 return new SIOptimizeExecMaskingPreRALegacy();
105 for (MCRegUnit Unit :
TRI.regunits(
Reg.asMCReg())) {
131 unsigned Opc = MI.getOpcode();
132 return Opc == AMDGPU::S_CBRANCH_VCCZ ||
133 Opc == AMDGPU::S_CBRANCH_VCCNZ; });
138 TRI->findReachingDef(CondReg, AMDGPU::NoSubRegister, *
I, *MRI, LIS);
139 if (!
And ||
And->getOpcode() != LMC.
AndOpc || !
And->getOperand(1).isReg() ||
140 !
And->getOperand(2).isReg())
143 MachineOperand *AndCC = &
And->getOperand(1);
147 AndCC = &
And->getOperand(2);
150 }
else if (
And->getOperand(2).getReg() !=
Register(ExecReg)) {
154 auto *
Cmp =
TRI->findReachingDef(CmpReg, CmpSubReg, *
And, *MRI, LIS);
155 if (!Cmp || !(
Cmp->getOpcode() == AMDGPU::V_CMP_NE_U32_e32 ||
156 Cmp->getOpcode() == AMDGPU::V_CMP_NE_U32_e64) ||
157 Cmp->getParent() !=
And->getParent())
160 MachineOperand *Op1 =
TII->getNamedOperand(*Cmp, AMDGPU::OpName::src0);
161 MachineOperand *Op2 =
TII->getNamedOperand(*Cmp, AMDGPU::OpName::src1);
171 auto *Sel =
TRI->findReachingDef(SelReg, Op1->
getSubReg(), *Cmp, *MRI, LIS);
172 if (!Sel || Sel->getOpcode() != AMDGPU::V_CNDMASK_B32_e64)
175 if (
TII->hasModifiersSet(*Sel, AMDGPU::OpName::src0_modifiers) ||
176 TII->hasModifiersSet(*Sel, AMDGPU::OpName::src1_modifiers))
179 Op1 =
TII->getNamedOperand(*Sel, AMDGPU::OpName::src0);
180 Op2 =
TII->getNamedOperand(*Sel, AMDGPU::OpName::src1);
181 MachineOperand *CC =
TII->getNamedOperand(*Sel, AMDGPU::OpName::src2);
198 [](
const VNInfo *VNI) {
199 return VNI->isPHIDef();
204 LLVM_DEBUG(
dbgs() <<
"Folding sequence:\n\t" << *Sel <<
'\t' << *Cmp <<
'\t'
207 MachineInstr *Andn2 =
209 And->getOperand(0).getReg())
214 MachineOperand &Andn2SCC = Andn2->
getOperand(3);
219 And->eraseFromParent();
242 [&](
const MachineInstr &
MI) {
243 return MI.readsRegister(CondReg, TRI);
249 Cmp->eraseFromParent();
261 bool ShrinkSel = Sel->getOperand(0).readsReg();
262 Sel->eraseFromParent();
288bool SIOptimizeExecMaskingPreRA::optimizeElseBranch(MachineBasicBlock &
MBB) {
294 MachineInstr &SaveExecMI = *
First;
299 return MI.getOpcode() == LMC.XorTermOpc;
304 MachineInstr &XorTermMI = *
I;
312 MachineInstr *AndExecMI =
nullptr;
314 while (
I !=
First && !AndExecMI) {
315 if (
I->getOpcode() == LMC.
AndOpc &&
I->getOperand(0).getReg() == DstReg &&
316 I->getOperand(1).getReg() ==
Register(ExecReg))
329 for (MCRegUnit Unit :
TRI->regunits(ExecReg)) {
331 if (RegUnit.
find(StartIdx) != std::prev(RegUnit.
find(EndIdx)))
353 SIOptimizeExecMaskingPreRA(MF, &LIS).
run(MF);
357bool SIOptimizeExecMaskingPreRALegacy::runOnMachineFunction(
362 auto *LIS = &getAnalysis<LiveIntervalsWrapperPass>().getLIS();
363 return SIOptimizeExecMaskingPreRA(MF, LIS).run(MF);
373 for (MachineBasicBlock &
MBB : MF) {
375 if (optimizeElseBranch(
MBB)) {
376 RecalcRegs.insert(AMDGPU::SCC);
380 if (optimizeVcndVcmpPair(
MBB)) {
381 RecalcRegs.insert(AMDGPU::VCC_LO);
382 RecalcRegs.insert(AMDGPU::VCC_HI);
383 RecalcRegs.insert(AMDGPU::SCC);
397 if (
Term.getOpcode() != AMDGPU::S_ENDPGM ||
Term.getNumOperands() != 1)
400 SmallVector<MachineBasicBlock*, 4> Blocks({&
MBB});
402 while (!Blocks.empty()) {
403 auto *CurBB = Blocks.pop_back_val();
404 auto I = CurBB->rbegin(),
E = CurBB->rend();
406 if (
I->isUnconditionalBranch() ||
I->getOpcode() == AMDGPU::S_ENDPGM)
408 else if (
I->isBranch())
413 if (
I->isDebugInstr()) {
418 if (
I->mayStore() ||
I->isBarrier() ||
I->isCall() ||
419 I->hasUnmodeledSideEffects() ||
I->hasOrderedMemoryRef())
423 <<
"Removing no effect instruction: " << *
I <<
'\n');
425 for (
auto &
Op :
I->operands()) {
427 RecalcRegs.insert(
Op.getReg());
430 auto Next = std::next(
I);
432 I->eraseFromParent();
442 for (
auto *Pred : CurBB->predecessors()) {
443 if (Pred->succ_size() == 1)
444 Blocks.push_back(Pred);
457 unsigned ScanThreshold = 10;
459 && ScanThreshold--; ++
I) {
461 if (!(
I->isFullCopy() &&
I->getOperand(1).getReg() ==
Register(ExecReg)))
464 Register SavedExec =
I->getOperand(0).getReg();
472 static_cast<unsigned>(Idx) <
474 TII->isOperandLegal(*SingleExecUser, Idx, &
I->getOperand(1))) {
477 I->eraseFromParent();
488 for (
auto Reg : RecalcRegs) {
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
AMD GCN specific subclass of TargetSubtarget.
const HexagonInstrInfo * TII
Register const TargetRegisterInfo * TRI
Promote Memory to Register
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
static bool isDefBetween(Register Reg, SlotIndex First, SlotIndex Last, const MachineRegisterInfo *MRI, const LiveIntervals *LIS)
static bool isDefBetween(const LiveRange &LR, SlotIndex AndIdx, SlotIndex SelIdx)
SI Optimize VGPR LiveRange
static const LaneMaskConstants & get(const GCNSubtarget &ST)
const unsigned OrSaveExecOpc
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
void setPreservesAll()
Set by analyses that do not transform their input at all.
Implements a dense probed hash-table based set.
FunctionPass class - This class is used to implement most global optimizations.
LLVM_ABI Result run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
void removeAllRegUnitsForPhysReg(MCRegister Reg)
Remove associated live ranges for the register units associated with Reg.
SlotIndex getInstructionIndex(const MachineInstr &Instr) const
Returns the base index of the given instruction.
void RemoveMachineInstrFromMaps(MachineInstr &MI)
LiveInterval & getInterval(Register Reg)
void removeInterval(Register Reg)
Interval removal.
LiveRange & getRegUnit(MCRegUnit Unit)
Return the live range for register unit Unit.
LLVM_ABI void removeVRegDefAt(LiveInterval &LI, SlotIndex Pos)
Remove value number and related live segments of LI and its subranges that start at position Pos.
LLVM_ABI bool shrinkToUses(LiveInterval *li, SmallVectorImpl< MachineInstr * > *dead=nullptr)
After removing some uses of a register, shrink its live range to just the remaining uses.
LiveInterval & createAndComputeVirtRegInterval(Register Reg)
SlotIndex ReplaceMachineInstrInMaps(MachineInstr &MI, MachineInstr &NewMI)
Result of a LiveRange query.
bool isDeadDef() const
Return true if this instruction has a dead def.
VNInfo * valueIn() const
Return the value that is live-in to the instruction.
VNInfo * valueOut() const
Return the value leaving the instruction, if any.
bool isKill() const
Return true if the live-in value is killed by this instruction.
This class represents the liveness of a register, stack slot, etc.
iterator_range< vni_iterator > vnis()
LiveQueryResult Query(SlotIndex Idx) const
Query Liveness at Idx.
LLVM_ABI iterator find(SlotIndex Pos)
find - Return an iterator pointing to the first segment that ends after Pos, or end().
unsigned getNumOperands() const
Return the number of declared MachineOperands for this MachineInstruction.
Wrapper class representing physical registers. Should be passed by value.
static MCRegister from(unsigned Val)
Check the provided unsigned value is a valid MCRegister.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
iterator_range< iterator > terminators()
reverse_iterator rbegin()
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
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 MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
LLVM_ABI int findRegisterUseOperandIdx(Register Reg, const TargetRegisterInfo *TRI, bool isKill=false) const
Returns the operand index that is a use of the specific register or -1 if it is not found.
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
unsigned getSubReg() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
void setIsDead(bool Val=true)
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
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,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
bool use_nodbg_empty(Register RegNo) const
use_nodbg_empty - Return true if there are no non-Debug instructions using the specified register.
use_instr_nodbg_iterator use_instr_nodbg_begin(Register RegNo) const
bool reg_empty(Register RegNo) const
reg_empty - Return true if there are no instructions using or defining the specified register (it may...
LLVM_ABI void replaceRegWith(Register FromReg, Register ToReg)
replaceRegWith - Replace all instances of FromReg with ToReg in the machine function.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Wrapper class representing virtual and physical registers.
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
SlotIndex - An opaque wrapper around machine indexes.
SlotIndex getRegSlot(bool EC=false) const
Returns the register use/def slot in the current instruction for a normal or early-clobber def.
Represent a constant reference to a string, i.e.
self_iterator getIterator()
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
char & SIOptimizeExecMaskingPreRAID
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
@ And
Bitwise or logical AND of integers.
DWARFExpression::Operation Op
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
FunctionPass * createSIOptimizeExecMaskingPreRAPass()
constexpr RegState getUndefRegState(bool B)
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.