65#define DEBUG_TYPE "si-lower-control-flow"
73class SILowerControlFlow {
89 bool EnableOptimizeEndCf =
false;
124 while (
I !=
End && !
I->isUnconditionalBranch())
130 void optimizeEndCf();
133 SILowerControlFlow(
const GCNSubtarget *ST, LiveIntervals *LIS,
134 MachineDominatorTree *MDT, MachinePostDominatorTree *PDT)
135 : LIS(LIS), MDT(MDT), PDT(PDT), LMC(AMDGPU::LaneMaskConstants::
get(*
ST)) {
144 SILowerControlFlowLegacy() : MachineFunctionPass(ID) {}
148 StringRef getPassName()
const override {
149 return "SI Lower control flow pseudo instructions";
152 void getAnalysisUsage(AnalysisUsage &AU)
const override {
160 AU.
addPreserved<MachineBlockFrequencyInfoWrapperPass>();
167char SILowerControlFlowLegacy::ID = 0;
181 setImpSCCDefDead(
MI, OrigSCCDef.
isDead());
188 DenseSet<const MachineBasicBlock*> Visited;
189 SmallVector<MachineBasicBlock *, 4> Worklist(Begin->
successors());
191 while (!Worklist.empty()) {
192 MachineBasicBlock *
MBB = Worklist.pop_back_val();
206 Register SaveExecReg =
MI.getOperand(0).getReg();
217void SILowerControlFlow::emitIf(MachineInstr &
MI) {
221 Register SaveExecReg =
MI.getOperand(0).getReg();
222 MachineOperand&
Cond =
MI.getOperand(1);
223 assert(
Cond.getSubReg() == AMDGPU::NoSubRegister);
239 Register CopyReg = SimpleIf ? SaveExecReg
241 MachineInstr *CopyExec =
BuildMI(
MBB,
I,
DL,
TII->get(AMDGPU::COPY), CopyReg)
244 LoweredIf.
insert(CopyReg);
250 setImpSCCDefDead(*
And);
252 MachineInstr *
Xor =
nullptr;
257 copySCCDefDead(*
Xor,
MI.getOperand(4));
262 MachineInstr *SetExec =
267 I = skipToUncondBrOrEnd(
MBB,
I);
271 MachineInstr *NewBr =
BuildMI(
MBB,
I,
DL,
TII->get(AMDGPU::S_CBRANCH_EXECZ))
272 .
add(
MI.getOperand(2));
275 MI.eraseFromParent();
290 MI.eraseFromParent();
295 RecomputeRegs.
insert(SaveExecReg);
301void SILowerControlFlow::emitElse(MachineInstr &
MI) {
313 MachineInstr *OrSaveExec =
315 .
add(
MI.getOperand(1));
316 setImpSCCDefDead(*OrSaveExec,
true);
318 MachineBasicBlock *DestBB =
MI.getOperand(2).getMBB();
327 setImpSCCDefDead(*
And,
true);
333 copySCCDefDead(*
Xor,
MI.getOperand(4));
337 ElsePt = skipToUncondBrOrEnd(
MBB, ElsePt);
344 MI.eraseFromParent();
349 MI.eraseFromParent();
357 RecomputeRegs.
insert(SrcReg);
358 RecomputeRegs.
insert(DstReg);
362void SILowerControlFlow::emitIfBreak(MachineInstr &
MI) {
365 auto Dst =
MI.getOperand(0).getReg();
371 bool SkipAnding =
false;
372 if (
MI.getOperand(1).isReg()) {
374 SkipAnding =
Def->getParent() ==
MI.getParent() &&
381 MachineInstr *
And =
nullptr, *
Or =
nullptr;
387 .
add(
MI.getOperand(1));
388 setImpSCCDefDead(*
And,
true);
391 .
add(
MI.getOperand(2));
394 .
add(
MI.getOperand(1))
395 .
add(
MI.getOperand(2));
398 copySCCDefDead(*
Or,
MI.getOperand(3));
404 RecomputeRegs.
insert(
And->getOperand(2).getReg());
410 MI.eraseFromParent();
413void SILowerControlFlow::emitLoop(MachineInstr &
MI) {
417 MachineInstr *AndN2 =
420 .
add(
MI.getOperand(0));
421 copySCCDefDead(*AndN2,
MI.getOperand(3));
426 .
add(
MI.getOperand(1));
429 RecomputeRegs.
insert(
MI.getOperand(0).getReg());
434 MI.eraseFromParent();
438SILowerControlFlow::skipIgnoreExecInstsTrivialSucc(
441 SmallPtrSet<const MachineBasicBlock *, 4> Visited;
442 MachineBasicBlock *
B = &
MBB;
448 for ( ; It !=
E; ++It) {
449 if (
TII->mayReadEXEC(*MRI, *It))
456 if (
B->succ_size() != 1)
460 MachineBasicBlock *Succ = *
B->succ_begin();
467MachineBasicBlock *SILowerControlFlow::emitEndCf(MachineInstr &
MI) {
476 bool NeedBlockSplit =
false;
480 if (
I->modifiesRegister(DataReg,
TRI)) {
481 NeedBlockSplit =
true;
486 unsigned Opcode = LMC.
OrOpc;
487 MachineBasicBlock *SplitBB = &
MBB;
488 if (NeedBlockSplit) {
490 if (SplitBB != &
MBB && (MDT || PDT)) {
493 for (MachineBasicBlock *Succ : SplitBB->
successors()) {
494 DTUpdates.
push_back({DomTreeT::Insert, SplitBB, Succ});
509 .
add(
MI.getOperand(0));
510 copySCCDefDead(*NewMI,
MI.getOperand(2));
512 LoweredEndCf.
insert(NewMI);
517 MI.eraseFromParent();
526void SILowerControlFlow::findMaskOperands(
527 MachineInstr &
MI,
unsigned OpNo,
528 SmallVectorImpl<MachineOperand *> &Src)
const {
529 MachineOperand &
Op =
MI.getOperand(OpNo);
530 if (!
Op.isReg() || !
Op.getReg().isVirtual()) {
536 if (!Def ||
Def->getParent() !=
MI.getParent() ||
537 !(
Def->isFullCopy() || (
Def->getOpcode() ==
MI.getOpcode())))
543 for (
auto I =
Def->getIterator();
I !=
MI.getIterator(); ++
I)
544 if (
I->modifiesRegister(AMDGPU::EXEC,
TRI) &&
545 !(
I->isCopy() &&
I->getOperand(0).getReg() != LMC.
ExecReg))
548 for (MachineOperand &SrcOp :
Def->explicit_operands())
549 if (SrcOp.isReg() && SrcOp.isUse() &&
550 (SrcOp.getReg().isVirtual() || SrcOp.getReg() == LMC.
ExecReg))
551 Src.push_back(&SrcOp);
558void SILowerControlFlow::combineMasks(MachineInstr &
MI) {
559 assert(
MI.getNumExplicitOperands() == 3);
561 findMaskOperands(
MI, 1, Src1);
562 findMaskOperands(
MI, 2, Src2);
566 unsigned OpToReplace;
567 MachineOperand *Leaf, *NestedLHS, *NestedRHS;
568 if (
Src1.size() == 2 &&
Src2.size() == 1) {
573 }
else if (
Src1.size() == 1 &&
Src2.size() == 2) {
583 MachineOperand *KeepOp;
593 MI.removeOperand(OpToReplace);
594 MI.addOperand(*KeepOp);
599void SILowerControlFlow::optimizeEndCf() {
602 if (!EnableOptimizeEndCf)
605 for (MachineInstr *
MI :
reverse(LoweredEndCf)) {
608 skipIgnoreExecInstsTrivialSucc(
MBB, std::next(
MI->getIterator()));
614 =
TII->getNamedOperand(*
Next, AMDGPU::OpName::src1)->getReg();
618 if (Def && LoweredIf.
count(SavedExec)) {
622 MI->eraseFromParent();
623 removeMBBifRedundant(
MBB);
628MachineBasicBlock *SILowerControlFlow::process(MachineInstr &
MI) {
631 MachineInstr *Prev = (
I !=
MBB.
begin()) ? &*(std::prev(
I)) : nullptr;
633 MachineBasicBlock *SplitBB = &
MBB;
635 switch (
MI.getOpcode()) {
640 case AMDGPU::SI_ELSE:
644 case AMDGPU::SI_IF_BREAK:
648 case AMDGPU::SI_LOOP:
652 case AMDGPU::SI_WATERFALL_LOOP:
653 MI.setDesc(
TII->get(AMDGPU::S_CBRANCH_EXECNZ));
656 case AMDGPU::SI_END_CF:
657 SplitBB = emitEndCf(
MI);
661 assert(
false &&
"Attempt to process unsupported instruction");
668 MachineInstr &MaskMI = *
I;
670 case AMDGPU::S_AND_B64:
671 case AMDGPU::S_OR_B64:
672 case AMDGPU::S_AND_B32:
673 case AMDGPU::S_OR_B32:
675 combineMasks(MaskMI);
686bool SILowerControlFlow::removeMBBifRedundant(MachineBasicBlock &
MBB) {
688 if (!
I.isDebugInstr() && !
I.isUnconditionalBranch())
695 MachineBasicBlock *FallThrough =
nullptr;
702 if (
P->getFallThrough(
false) == &
MBB)
705 DTUpdates.
push_back({DomTreeT::Insert,
P, Succ});
744 MachineInstr *BranchMI =
BuildMI(*FallThrough, FallThrough->
end(),
756 TII =
ST.getInstrInfo();
762 BoolRC =
TRI->getBoolRC();
765 const bool CanDemote =
767 for (
auto &
MBB : MF) {
768 bool IsKillBlock =
false;
770 if (
TII->isKillTerminator(
Term.getOpcode())) {
776 if (CanDemote && !IsKillBlock) {
777 for (
auto &
MI :
MBB) {
778 if (
MI.getOpcode() == AMDGPU::SI_DEMOTE_I1) {
789 BI != MF.end(); BI = NextBB) {
790 NextBB = std::next(BI);
791 MachineBasicBlock *
MBB = &*BI;
797 MachineInstr &
MI = *
I;
798 MachineBasicBlock *SplitMBB =
MBB;
800 switch (
MI.getOpcode()) {
802 case AMDGPU::SI_ELSE:
803 case AMDGPU::SI_IF_BREAK:
804 case AMDGPU::SI_WATERFALL_LOOP:
805 case AMDGPU::SI_LOOP:
806 case AMDGPU::SI_END_CF:
807 SplitMBB = process(
MI);
812 if (SplitMBB !=
MBB) {
831 RecomputeRegs.clear();
832 LoweredEndCf.
clear();
839bool SILowerControlFlowLegacy::runOnMachineFunction(
MachineFunction &MF) {
842 auto *LISWrapper = getAnalysisIfAvailable<LiveIntervalsWrapperPass>();
843 LiveIntervals *LIS = LISWrapper ? &LISWrapper->getLIS() :
nullptr;
844 auto *MDTWrapper = getAnalysisIfAvailable<MachineDominatorTreeWrapperPass>();
845 MachineDominatorTree *MDT = MDTWrapper ? &MDTWrapper->getDomTree() :
nullptr;
847 getAnalysisIfAvailable<MachinePostDominatorTreeWrapperPass>();
848 MachinePostDominatorTree *PDT =
849 PDTWrapper ? &PDTWrapper->getPostDomTree() :
nullptr;
850 return SILowerControlFlow(ST, LIS, MDT, PDT).run(MF);
863 bool Changed = SILowerControlFlow(ST, LIS, MDT, PDT).run(MF);
MachineInstrBuilder & UseMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
AMD GCN specific subclass of TargetSubtarget.
const HexagonInstrInfo * TII
Register const TargetRegisterInfo * TRI
Promote Memory to Register
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
const SmallVectorImpl< MachineOperand > & Cond
static cl::opt< bool > RemoveRedundantEndcf("amdgpu-remove-redundant-endcf", cl::init(true), cl::ReallyHidden)
static bool isSimpleIf(const MachineInstr &MI, const MachineRegisterInfo *MRI)
const unsigned XorTermOpc
const unsigned MovTermOpc
const unsigned OrSaveExecOpc
const unsigned AndN2TermOpc
PassT::Result * getCachedResult(IRUnitT &IR) const
Get the cached result of an analysis pass for a given IR unit.
AnalysisUsage & addUsedIfAvailable()
Add the specified Pass class to the set of analyses used by this pass.
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
Implements a dense probed hash-table based set.
void applyUpdates(ArrayRef< UpdateType > Updates)
Inform the dominator tree about a sequence of CFG edge insertions and deletions and perform a batch u...
void eraseNode(NodeT *BB)
eraseNode - Removes a node from the dominator tree.
DomTreeNodeBase< NodeT > * getNode(const NodeT *BB) const
getNode - return the (Post)DominatorTree node for the specified basic block.
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
const HexagonRegisterInfo & getRegisterInfo() const
void removeAllRegUnitsForPhysReg(MCRegister Reg)
Remove associated live ranges for the register units associated with Reg.
bool hasInterval(Register Reg) const
SlotIndex getMBBStartIdx(const MachineBasicBlock *mbb) const
Return the first index in the given basic block.
SlotIndex InsertMachineInstrInMaps(MachineInstr &MI)
LLVM_ABI void handleMove(MachineInstr &MI, bool UpdateFlags=false)
Call this method to notify LiveIntervals that instruction MI has been moved within a basic block.
SlotIndexes * getSlotIndexes() const
void RemoveMachineInstrFromMaps(MachineInstr &MI)
LiveInterval & getInterval(Register Reg)
void removeInterval(Register Reg)
Interval removal.
LiveInterval & createAndComputeVirtRegInterval(Register Reg)
SlotIndex ReplaceMachineInstrInMaps(MachineInstr &MI, MachineInstr &NewMI)
bool liveAt(SlotIndex index) const
succ_iterator succ_begin()
unsigned succ_size() const
LLVM_ABI void removeSuccessor(MachineBasicBlock *Succ, bool NormalizeSuccProbs=false)
Remove successor from the successors list of this MachineBasicBlock.
pred_iterator pred_begin()
LLVM_ABI void ReplaceUsesOfBlockWith(MachineBasicBlock *Old, MachineBasicBlock *New)
Given a machine basic block that branched to 'Old', change the code and CFG so that it branches to 'N...
LLVM_ABI bool isLayoutSuccessor(const MachineBasicBlock *MBB) const
Return true if the specified MBB will be emitted immediately after this block, such that if this bloc...
LLVM_ABI MachineBasicBlock * splitAt(MachineInstr &SplitInst, bool UpdateLiveIns=true, LiveIntervals *LIS=nullptr)
Split a basic block into 2 pieces at SplitPoint.
LLVM_ABI void eraseFromParent()
This method unlinks 'this' from the containing function and deletes it.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
iterator_range< iterator > terminators()
LLVM_ABI DebugLoc findBranchDebugLoc()
Find and return the merged DebugLoc of the branch instructions of the block.
iterator_range< succ_iterator > successors()
iterator_range< pred_iterator > predecessors()
MachineInstrBundleIterator< MachineInstr > iterator
Analysis pass which computes a MachineDominatorTree.
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
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.
BasicBlockListType::iterator iterator
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
MachineOperand class - Representation of each machine instruction operand.
void setIsDead(bool Val=true)
Register getReg() const
getReg - Returns the register number.
LLVM_ABI bool isIdenticalTo(const MachineOperand &Other) const
Returns true if this operand is identical to the specified operand except for liveness related flags ...
MachinePostDominatorTree - an analysis pass wrapper for DominatorTree used to compute the post-domina...
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
use_instr_nodbg_iterator use_instr_nodbg_begin(Register RegNo) const
unsigned getNumVirtRegs() const
getNumVirtRegs - Return the number of virtual registers created.
bool use_empty(Register RegNo) const
use_empty - Return true if there are no instructions using the specified register.
LLVM_ABI LLVM_READONLY MachineInstr * getUniqueVRegDef(Register Reg) const
getUniqueVRegDef - Return the unique machine instr that defines the specified virtual register or nul...
static use_instr_nodbg_iterator use_instr_nodbg_end()
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.
static bool isVALU(const MachineInstr &MI, bool AllowLDSDMA)
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
A vector that has set insertion semantics.
size_type count(const_arg_type key) const
Count the number of elements of a given key in the SetVector.
void clear()
Completely clear the SetVector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
SlotIndex getPrevSlot() const
Returns the previous slot in the index list.
LLVM_ABI void removeMBBFromMaps(MachineBasicBlock &MBB)
Inverse of insertMBBInMaps: merge MBB's slot range into its layout predecessor and drop it from the m...
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 push_back(const T &Elt)
CodeGenOptLevel getOptLevel() const
Returns the optimization level: None, Less, Default, or Aggressive.
std::pair< iterator, bool > insert(const ValueT &V)
size_type count(const_arg_type_t< ValueT > V) const
Return 1 if the specified key is in the set, 0 otherwise.
self_iterator getIterator()
initializer< Ty > init(const Ty &Val)
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
NodeAddr< DefNode * > Def
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.
char & SILowerControlFlowLegacyID
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
auto reverse(ContainerTy &&C)
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
DominatorTreeBase< T, false > DomTreeBase
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...
@ Or
Bitwise or logical OR of integers.
@ Xor
Bitwise or logical XOR of integers.
@ And
Bitwise or logical AND of integers.
DWARFExpression::Operation Op
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
@ End
Run the machine verifier once, at the end of the pipeline.
MCRegisterClass TargetRegisterClass