63#define PASS_KEY "x86-flags-copy-lowering"
64#define DEBUG_TYPE PASS_KEY
66STATISTIC(NumCopiesEliminated,
"Number of copies of EFLAGS eliminated");
67STATISTIC(NumSetCCsInserted,
"Number of setCC instructions inserted");
68STATISTIC(NumTestsInserted,
"Number of test instructions inserted");
69STATISTIC(NumAddsInserted,
"Number of adds instructions inserted");
70STATISTIC(NumNFsConvertedTo,
"Number of NF instructions converted to");
75using CondRegArray = std::array<Register, X86::LAST_VALID_COND + 1>;
77class X86FlagsCopyLoweringImpl {
81 bool runOnMachineFunction(MachineFunction &MF);
84 MachineRegisterInfo *MRI =
nullptr;
85 const X86Subtarget *Subtarget =
nullptr;
86 const X86InstrInfo *TII =
nullptr;
87 const TargetRegisterInfo *TRI =
nullptr;
89 MachineDominatorTree *MDT =
nullptr;
91 CondRegArray collectCondsInRegs(MachineBasicBlock &
MBB,
97 std::pair<Register, bool> getCondOrInverseInReg(
105 CondRegArray &CondRegs);
106 void rewriteArithmetic(MachineBasicBlock &
MBB,
108 MachineInstr &
MI, CondRegArray &CondRegs);
110 const DebugLoc &Loc, MachineInstr &
MI, CondRegArray &CondRegs);
115 X86FlagsCopyLoweringLegacy() : MachineFunctionPass(ID) {}
117 StringRef getPassName()
const override {
return "X86 EFLAGS copy lowering"; }
118 bool runOnMachineFunction(MachineFunction &MF)
override;
119 void getAnalysisUsage(AnalysisUsage &AU)
const override;
128 "X86 EFLAGS copy lowering",
false,
false)
133 return new X86FlagsCopyLoweringLegacy();
136char X86FlagsCopyLoweringLegacy::ID = 0;
138void X86FlagsCopyLoweringLegacy::getAnalysisUsage(
AnalysisUsage &AU)
const {
145 return X86::isADC(
Opc) || X86::isSBB(
Opc) || X86::isRCL(
Opc) ||
146 X86::isRCR(
Opc) || (
Opc == X86::SETB_C32r ||
Opc == X86::SETB_C64r);
155 "Split instruction must be in the split block!");
157 "Only designed to split a tail of branch instructions!");
159 "Must split on an actual jCC instruction!");
165 "Must split after an actual jCC instruction!");
167 "Must only have this one terminator prior to the split!");
178 assert(MI.isTerminator() &&
179 "Should only have spliced terminators!");
181 MI.operands(), [&](MachineOperand &MOp) {
182 return MOp.isMBB() && MOp.getMBB() == &UnsplitSucc;
187 MachineBasicBlock &NewMBB = *MF.CreateMachineBasicBlock();
199 if (IsEdgeSplit || *SI != &UnsplitSucc)
207 for (MachineBasicBlock *Succ : NewMBB.
successors())
208 if (Succ != &UnsplitSucc)
209 MBB.replaceSuccessor(Succ, &NewMBB);
213 "Failed to make the new block a successor!");
216 for (MachineBasicBlock *Succ : NewMBB.
successors()) {
217 for (MachineInstr &
MI : *Succ) {
223 MachineOperand &OpV =
MI.getOperand(
OpIdx);
224 MachineOperand &OpMBB =
MI.getOperand(
OpIdx + 1);
225 assert(OpMBB.
isMBB() &&
"Block operand to a PHI is not a block!");
230 if (!IsEdgeSplit || Succ != &UnsplitSucc) {
239 MI.addOperand(MF, OpV);
253 MI.findRegisterDefOperand(X86::EFLAGS,
nullptr);
263bool X86FlagsCopyLoweringImpl::runOnMachineFunction(MachineFunction &MF) {
271 PromoteRC = &X86::GR8RegClass;
277 if (
none_of(MRI->def_instructions(X86::EFLAGS), [](
const MachineInstr &
MI) {
278 return MI.getOpcode() == TargetOpcode::COPY;
286 std::unique_ptr<MachineDominatorTree> OwnedMDT;
288 OwnedMDT = std::make_unique<MachineDominatorTree>(MF);
289 MDT = OwnedMDT.get();
296 SmallSetVector<MachineInstr *, 4>
Copies;
297 ReversePostOrderTraversal<MachineFunction *> RPOT(&MF);
298 for (MachineBasicBlock *
MBB : RPOT)
299 for (MachineInstr &
MI : *
MBB)
300 if (
MI.getOpcode() == TargetOpcode::COPY &&
301 MI.getOperand(0).getReg() == X86::EFLAGS)
316 if (Subtarget->hasNF()) {
317 SmallSetVector<MachineInstr *, 4> RemovedCopies;
320 while (CopyIIt != CopyIEnd) {
321 auto NCopyIIt = std::next(CopyIIt);
322 SmallSetVector<MachineInstr *, 4> EvitableClobbers;
323 MachineInstr *CopyI = *CopyIIt;
325 MachineInstr *CopyDefI = MRI->getVRegDef(VOp.
getReg());
326 MachineBasicBlock *CopyIMBB = CopyI->
getParent();
327 MachineBasicBlock *CopyDefIMBB = CopyDefI->
getParent();
335 MachineBasicBlock *
MBB = *BI;
336 for (
auto I = (
MBB != CopyDefIMBB)
342 MachineInstr &
MI = *
I;
348 goto ProcessNextCopyI;
355 RemovedCopies.
insert(CopyI);
358 RemovedCopies.
insert(CopyDefI);
361 ++NumCopiesEliminated;
362 for (
auto *Clobber : EvitableClobbers) {
364 assert(NewOpc &&
"evitable clobber must have a NF variant");
365 Clobber->setDesc(
TII->get(NewOpc));
366 Clobber->removeOperand(
367 Clobber->findRegisterDefOperand(X86::EFLAGS,
nullptr)
374 if (*BI != CopyDefIMBB)
375 BI->addLiveIn(X86::EFLAGS);
379 Copies.set_subtract(RemovedCopies);
397 for (MachineInstr *CopyI :
Copies) {
402 "The input to the copy for EFLAGS should always be a register!");
403 MachineInstr &CopyDefI = *MRI->getVRegDef(VOp.
getReg());
404 if (CopyDefI.
getOpcode() != TargetOpcode::COPY) {
420 dbgs() <<
"ERROR: Encountered unexpected def of an eflags copy: ";
423 "Cannot lower EFLAGS copy unless it is defined in turn by a copy!");
432 ++NumCopiesEliminated;
436 assert(DOp.isDef() &&
"Expected register def!");
437 assert(DOp.getReg() == X86::EFLAGS &&
"Unexpected copy def register!");
441 MachineBasicBlock *TestMBB = CopyDefI.
getParent();
465 return &
MI != CopyI &&
466 MI.findRegisterDefOperand(X86::EFLAGS,
nullptr);
469 auto HasEFLAGSClobberPath = [&](MachineBasicBlock *BeginMBB,
470 MachineBasicBlock *EndMBB) {
472 "Only support paths down the dominator tree!");
473 SmallPtrSet<MachineBasicBlock *, 4> Visited;
474 SmallVector<MachineBasicBlock *, 4> Worklist;
481 if (!Visited.
insert(PredMBB).second)
483 if (HasEFLAGSClobber(PredMBB->begin(), PredMBB->end()))
488 }
while (!Worklist.
empty());
493 !HasEFLAGSClobber(TestMBB->
begin(), TestPos)) {
496 MachineBasicBlock *HoistMBB =
499 [&](MachineBasicBlock *
LHS, MachineBasicBlock *
RHS) {
500 return MDT->findNearestCommonDominator(LHS, RHS);
506 if (HasEFLAGSClobberPath(HoistMBB, TestMBB))
523 [&](MachineInstr &
MI) {
524 return MI.findRegisterDefOperand(X86::EFLAGS, nullptr);
527 dbgs() <<
" Using EFLAGS defined by: ";
530 dbgs() <<
" Using live-in flags for BB:\n";
538 SmallVector<MachineInstr *, 4> JmpIs;
545 CondRegArray CondRegs = collectCondsInRegs(*TestMBB, TestPos);
558 bool FlagsKilled =
false;
574 MachineInstr &
MI = *MII++;
579 if (&
MI == CopyI || &
MI == &CopyDefI) {
581 "Should only encounter these on the second pass over the "
586 MachineOperand *FlagUse =
587 MI.findRegisterUseOperand(X86::EFLAGS,
nullptr);
588 FlagsKilled =
MI.modifiesRegister(X86::EFLAGS,
TRI);
590 if (!FlagUse && FlagsKilled)
610 auto JmpIt =
MI.getIterator();
612 JmpIs.push_back(&*JmpIt);
620 unsigned Opc =
MI.getOpcode();
621 if (
Opc == TargetOpcode::COPY) {
623 MRI->replaceRegWith(
MI.getOperand(0).getReg(),
625 MI.eraseFromParent();
626 }
else if (X86::isSETCC(
Opc) || X86::isSETZUCC(
Opc)) {
627 rewriteSetCC(*TestMBB, TestPos, TestLoc,
MI, CondRegs);
629 rewriteArithmetic(*TestMBB, TestPos, TestLoc,
MI, CondRegs);
631 rewriteMI(*TestMBB, TestPos, TestLoc,
MI, CondRegs);
645 for (MachineBasicBlock *SuccMBB : UseMBB.
successors())
646 if (SuccMBB->isLiveIn(X86::EFLAGS) &&
661 if (SuccMBB == TestMBB || !MDT->
dominates(TestMBB, SuccMBB)) {
664 <<
"ERROR: Encountered use that is not dominated by our test "
665 "basic block! Rewriting this would require inserting PHI "
666 "nodes to track the flag state across the CFG.\n\nTest "
669 dbgs() <<
"Use block:\n";
673 "Cannot lower EFLAGS copy when original copy def "
674 "does not dominate all uses.");
680 SuccMBB->removeLiveIn(X86::EFLAGS);
682 }
while (!Blocks.
empty());
687 MachineBasicBlock *LastJmpMBB =
nullptr;
688 for (MachineInstr *JmpI : JmpIs) {
691 if (JmpI->getParent() == LastJmpMBB)
696 rewriteMI(*TestMBB, TestPos, TestLoc, *JmpI, CondRegs);
706 for (MachineInstr &
MI : *
MBB)
707 if (
MI.getOpcode() == TargetOpcode::COPY &&
708 (
MI.getOperand(0).getReg() == X86::EFLAGS ||
709 MI.getOperand(1).getReg() == X86::EFLAGS)) {
721CondRegArray X86FlagsCopyLoweringImpl::collectCondsInRegs(
723 CondRegArray CondRegs = {};
726 for (MachineInstr &
MI :
730 MI.getOperand(0).isReg() &&
MI.getOperand(0).getReg().isVirtual()) {
732 "A non-storing SETcc should always define a register!");
733 CondRegs[
Cond] =
MI.getOperand(0).getReg();
738 if (
MI.findRegisterDefOperand(X86::EFLAGS,
nullptr))
744Register X86FlagsCopyLoweringImpl::promoteCondToReg(
747 Register Reg = MRI->createVirtualRegister(PromoteRC);
749 BuildMI(TestMBB, TestPos, TestLoc,
750 TII->get((!Subtarget->hasZU() || Subtarget->preferLegacySetCC())
761std::pair<Register, bool> X86FlagsCopyLoweringImpl::getCondOrInverseInReg(
766 if (!CondReg && !InvCondReg)
767 CondReg = promoteCondToReg(TestMBB, TestPos, TestLoc,
Cond);
770 return {CondReg,
false};
772 return {InvCondReg,
true};
775void X86FlagsCopyLoweringImpl::insertTest(MachineBasicBlock &
MBB,
785void X86FlagsCopyLoweringImpl::rewriteSetCC(MachineBasicBlock &
MBB,
789 CondRegArray &CondRegs) {
796 CondReg = promoteCondToReg(
MBB, Pos, Loc,
Cond);
800 if (!
MI.mayStore()) {
802 "Cannot have a non-register defined operand to SETcc!");
806 MRI->clearKillFlags(OldReg);
807 MRI->replaceRegWith(OldReg, CondReg);
808 MI.eraseFromParent();
813 auto MIB =
BuildMI(*
MI.getParent(),
MI.getIterator(),
MI.getDebugLoc(),
814 TII->get(X86::MOV8mr));
817 MIB.add(
MI.getOperand(i));
820 MIB.setMemRefs(
MI.memoperands());
821 MI.eraseFromParent();
824void X86FlagsCopyLoweringImpl::rewriteArithmetic(
826 const DebugLoc &Loc, MachineInstr &
MI, CondRegArray &CondRegs) {
839 CondReg = promoteCondToReg(
MBB, Pos, Loc,
Cond);
842 Register TmpReg = MRI->createVirtualRegister(PromoteRC);
845 TII->get(Subtarget->hasNDD() ? X86::ADD8ri_ND : X86::ADD8ri))
846 .
addDef(TmpReg, RegState::Dead)
852 MI.findRegisterUseOperand(X86::EFLAGS,
nullptr)->setIsKill(
true);
856#define FROM_TO(A, B) \
857 case X86::CMOV##A##_Fp32: \
858 case X86::CMOV##A##_Fp64: \
859 case X86::CMOV##A##_Fp80: \
860 return X86::COND_##B;
880 case X86::CMOVB_##A: \
881 case X86::CMOVE_##A: \
882 case X86::CMOVP_##A: \
883 case X86::CMOVBE_##A: \
884 case X86::CMOVNB_##A: \
885 case X86::CMOVNE_##A: \
886 case X86::CMOVNP_##A: \
887 case X86::CMOVNBE_##A: \
888 return (CC == X86::COND_E) ? X86::CMOVE_##A : X86::CMOVNE_##A;
899void X86FlagsCopyLoweringImpl::rewriteMI(MachineBasicBlock &
MBB,
902 CondRegArray &CondRegs) {
904 bool IsImplicitCC =
false;
913 std::tie(CondReg, Inverted) =
914 getCondOrInverseInReg(
MBB, Pos, Loc, CC, CondRegs);
917 insertTest(*
MI.getParent(),
MI.getIterator(),
MI.getDebugLoc(), CondReg);
925 MI.getOperand(
MI.getDesc().getNumOperands() - 1).setImm(NewCC);
927 MI.findRegisterUseOperand(X86::EFLAGS,
nullptr)->setIsKill(
true);
931bool X86FlagsCopyLoweringLegacy::runOnMachineFunction(MachineFunction &MF) {
932 auto *MDTWrapper = getAnalysisIfAvailable<MachineDominatorTreeWrapperPass>();
933 MachineDominatorTree *MDT = MDTWrapper ? &MDTWrapper->getDomTree() :
nullptr;
934 return X86FlagsCopyLoweringImpl(MDT).runOnMachineFunction(MF);
942 bool Changed = X86FlagsCopyLoweringImpl(MDT).runOnMachineFunction(MF);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define CASE(ATTRNAME, AANAME,...)
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
SmallPtrSet< const BasicBlock *, 8 > VisitedBlocks
This file builds on the ADT/GraphTraits.h file to build generic depth first graph iterator.
ManagedStatic< HTTPClientCleanup > Cleanup
const HexagonInstrInfo * TII
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
Register const TargetRegisterInfo * TRI
Promote Memory to Register
MachineInstr unsigned OpIdx
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
const SmallVectorImpl< MachineOperand > & Cond
static void splitBlock(MachineBasicBlock &MBB, MachineInstr &MI, MachineDominatorTree *MDT, MachineLoopInfo *MLI)
This file defines the make_scope_exit function, which executes user-defined cleanup logic at scope ex...
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
#define FROM_TO(FROM, TO)
static X86::CondCode getImplicitCondFromMI(unsigned Opc)
static unsigned getOpcodeWithCC(unsigned Opc, X86::CondCode CC)
static bool isArithmeticOp(unsigned Opc)
static EFLAGSClobber getClobberType(const MachineInstr &MI)
PassT::Result * getCachedResult(IRUnitT &IR) const
Get the cached result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
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.
FunctionPass class - This class is used to implement most global optimizations.
void normalizeSuccProbs()
Normalize probabilities of all successors so that the sum of them becomes one.
instr_iterator instr_begin()
LLVM_ABI MachineBasicBlock * getFallThrough(bool JumpToFallThrough=true)
Return the fallthrough block if the block can implicitly transfer control to the block after it by fa...
LLVM_ABI instr_iterator insert(instr_iterator I, MachineInstr *M)
Insert MI into the instruction list before I, possibly inside a bundle.
succ_iterator succ_begin()
LLVM_ABI iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
LLVM_ABI void dump() const
LLVM_ABI void copySuccessor(const MachineBasicBlock *Orig, succ_iterator I)
Copy a successor (and any probability info) from original block to this block's.
pred_iterator pred_begin()
instr_iterator instr_end()
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
iterator_range< succ_iterator > successors()
LLVM_ABI bool isSuccessor(const MachineBasicBlock *MBB) const
Return true if the specified MBB is a successor of this block.
iterator_range< pred_iterator > predecessors()
void splice(iterator Where, MachineBasicBlock *Other, iterator From)
Take an instruction from MBB 'Other' at the position From, and insert it into this MBB right before '...
MachineInstrBundleIterator< MachineInstr > iterator
LLVM_ABI bool isLiveIn(MCRegister Reg, LaneBitmask LaneMask=LaneBitmask::getAll()) const
Return true if the specified register is in the live in set.
Analysis pass which computes a MachineDominatorTree.
Analysis pass which computes a MachineDominatorTree.
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
bool dominates(const MachineInstr *A, const MachineInstr *B) const
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.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
BasicBlockListType::iterator iterator
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
bool isBranch(QueryType Type=AnyInBundle) const
Returns true if this is a conditional, unconditional, or indirect branch.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
LLVM_ABI void dump() const
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
MachineOperand class - Representation of each machine instruction operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineBasicBlock * getMBB() const
void setMBB(MachineBasicBlock *MBB)
Register getReg() const
getReg - Returns the register number.
static MachineOperand CreateMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0)
bool isMBB() const
isMBB - Tests if this is a MO_MachineBasicBlock operand.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
bool insert(const value_type &X)
Insert a new element into the SetVector.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
void push_back(const T &Elt)
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
const X86InstrInfo * getInstrInfo() const override
const X86RegisterInfo * getRegisterInfo() const override
self_iterator getIterator()
Pass manager infrastructure for declaring and invalidating analyses.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
CondCode getCondFromBranch(const MachineInstr &MI)
CondCode getCondFromMI(const MachineInstr &MI)
Return the condition code of the instruction.
CondCode GetOppositeBranchCondition(CondCode CC)
GetOppositeBranchCondition - Return the inverse of the specified cond, e.g.
CondCode getCondFromSETCC(const MachineInstr &MI)
unsigned getNFVariantIfClobberRemovable(const MachineInstr &MI, const TargetRegisterInfo *TRI=nullptr)
unsigned getNFVariant(unsigned Opc)
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.
auto successors(const MachineBasicBlock *BB)
scope_exit(Callable) -> scope_exit< Callable >
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
auto reverse(ContainerTy &&C)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
idf_iterator< T > idf_end(const T &G)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
FunctionPass * createX86FlagsCopyLoweringLegacyPass()
idf_iterator< T > idf_begin(const T &G)
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
iterator_range< df_iterator< T > > depth_first(const T &G)
MCRegisterClass TargetRegisterClass