60#define PASS_KEY "x86-flags-copy-lowering"
61#define DEBUG_TYPE PASS_KEY
63STATISTIC(NumCopiesEliminated,
"Number of copies of EFLAGS eliminated");
64STATISTIC(NumSetCCsInserted,
"Number of setCC instructions inserted");
65STATISTIC(NumTestsInserted,
"Number of test instructions inserted");
66STATISTIC(NumAddsInserted,
"Number of adds instructions inserted");
67STATISTIC(NumNFsConvertedTo,
"Number of NF instructions converted to");
74using CondRegArray = std::array<Register, X86::LAST_VALID_COND + 1>;
80 StringRef getPassName()
const override {
return "X86 EFLAGS copy lowering"; }
81 bool runOnMachineFunction(MachineFunction &MF)
override;
82 void getAnalysisUsage(AnalysisUsage &AU)
const override;
88 MachineRegisterInfo *MRI =
nullptr;
89 const X86Subtarget *Subtarget =
nullptr;
90 const X86InstrInfo *TII =
nullptr;
91 const TargetRegisterInfo *TRI =
nullptr;
92 const TargetRegisterClass *PromoteRC =
nullptr;
93 MachineDominatorTree *MDT =
nullptr;
95 CondRegArray collectCondsInRegs(MachineBasicBlock &
MBB,
101 std::pair<Register, bool> getCondOrInverseInReg(
109 CondRegArray &CondRegs);
110 void rewriteArithmetic(MachineBasicBlock &
MBB,
112 MachineInstr &
MI, CondRegArray &CondRegs);
114 const DebugLoc &Loc, MachineInstr &
MI, CondRegArray &CondRegs);
120 "X86 EFLAGS copy lowering",
false,
false)
125 return new X86FlagsCopyLoweringPass();
128char X86FlagsCopyLoweringPass::ID = 0;
130void X86FlagsCopyLoweringPass::getAnalysisUsage(
AnalysisUsage &AU)
const {
136 return X86::isADC(
Opc) || X86::isSBB(
Opc) || X86::isRCL(
Opc) ||
137 X86::isRCR(
Opc) || (
Opc == X86::SETB_C32r ||
Opc == X86::SETB_C64r);
146 "Split instruction must be in the split block!");
148 "Only designed to split a tail of branch instructions!");
150 "Must split on an actual jCC instruction!");
156 "Must split after an actual jCC instruction!");
158 "Must only have this one terminator prior to the split!");
169 assert(MI.isTerminator() &&
170 "Should only have spliced terminators!");
172 MI.operands(), [&](MachineOperand &MOp) {
173 return MOp.isMBB() && MOp.getMBB() == &UnsplitSucc;
178 MachineBasicBlock &NewMBB = *MF.CreateMachineBasicBlock();
190 if (IsEdgeSplit || *SI != &UnsplitSucc)
198 for (MachineBasicBlock *Succ : NewMBB.
successors())
199 if (Succ != &UnsplitSucc)
200 MBB.replaceSuccessor(Succ, &NewMBB);
204 "Failed to make the new block a successor!");
207 for (MachineBasicBlock *Succ : NewMBB.
successors()) {
208 for (MachineInstr &
MI : *Succ) {
214 MachineOperand &OpV =
MI.getOperand(
OpIdx);
215 MachineOperand &OpMBB =
MI.getOperand(
OpIdx + 1);
216 assert(OpMBB.
isMBB() &&
"Block operand to a PHI is not a block!");
221 if (!IsEdgeSplit || Succ != &UnsplitSucc) {
230 MI.addOperand(MF, OpV);
244 MI.findRegisterDefOperand(X86::EFLAGS,
nullptr);
261bool X86FlagsCopyLoweringPass::runOnMachineFunction(MachineFunction &MF) {
269 PromoteRC = &X86::GR8RegClass;
275 if (
none_of(
MRI->def_instructions(X86::EFLAGS), [](
const MachineInstr &
MI) {
276 return MI.getOpcode() == TargetOpcode::COPY;
285 auto MDTWrapper = getAnalysisIfAvailable<MachineDominatorTreeWrapperPass>();
286 std::unique_ptr<MachineDominatorTree> OwnedMDT;
288 MDT = &MDTWrapper->getDomTree();
290 OwnedMDT = std::make_unique<MachineDominatorTree>(MF);
291 MDT = OwnedMDT.get();
298 SmallSetVector<MachineInstr *, 4>
Copies;
299 ReversePostOrderTraversal<MachineFunction *> RPOT(&MF);
300 for (MachineBasicBlock *
MBB : RPOT)
301 for (MachineInstr &
MI : *
MBB)
302 if (
MI.getOpcode() == TargetOpcode::COPY &&
303 MI.getOperand(0).getReg() == X86::EFLAGS)
318 if (Subtarget->hasNF()) {
319 SmallSetVector<MachineInstr *, 4> RemovedCopies;
322 while (CopyIIt != CopyIEnd) {
323 auto NCopyIIt = std::next(CopyIIt);
324 SmallSetVector<MachineInstr *, 4> EvitableClobbers;
325 MachineInstr *CopyI = *CopyIIt;
327 MachineInstr *CopyDefI =
MRI->getVRegDef(VOp.
getReg());
328 MachineBasicBlock *CopyIMBB = CopyI->
getParent();
329 MachineBasicBlock *CopyDefIMBB = CopyDefI->
getParent();
337 MachineBasicBlock *
MBB = *BI;
338 for (
auto I = (
MBB != CopyDefIMBB)
344 MachineInstr &
MI = *
I;
350 goto ProcessNextCopyI;
357 RemovedCopies.
insert(CopyI);
360 RemovedCopies.
insert(CopyDefI);
363 ++NumCopiesEliminated;
364 for (
auto *Clobber : EvitableClobbers) {
366 assert(NewOpc &&
"evitable clobber must have a NF variant");
367 Clobber->setDesc(
TII->get(NewOpc));
368 Clobber->removeOperand(
369 Clobber->findRegisterDefOperand(X86::EFLAGS,
nullptr)
376 if (*BI != CopyDefIMBB)
377 BI->addLiveIn(X86::EFLAGS);
381 Copies.set_subtract(RemovedCopies);
399 for (MachineInstr *CopyI :
Copies) {
404 "The input to the copy for EFLAGS should always be a register!");
405 MachineInstr &CopyDefI = *
MRI->getVRegDef(VOp.
getReg());
406 if (CopyDefI.
getOpcode() != TargetOpcode::COPY) {
422 dbgs() <<
"ERROR: Encountered unexpected def of an eflags copy: ";
425 "Cannot lower EFLAGS copy unless it is defined in turn by a copy!");
434 ++NumCopiesEliminated;
438 assert(DOp.isDef() &&
"Expected register def!");
439 assert(DOp.getReg() == X86::EFLAGS &&
"Unexpected copy def register!");
443 MachineBasicBlock *TestMBB = CopyDefI.
getParent();
467 return &
MI != CopyI &&
468 MI.findRegisterDefOperand(X86::EFLAGS,
nullptr);
471 auto HasEFLAGSClobberPath = [&](MachineBasicBlock *BeginMBB,
472 MachineBasicBlock *EndMBB) {
474 "Only support paths down the dominator tree!");
475 SmallPtrSet<MachineBasicBlock *, 4> Visited;
476 SmallVector<MachineBasicBlock *, 4> Worklist;
483 if (!Visited.
insert(PredMBB).second)
485 if (HasEFLAGSClobber(PredMBB->begin(), PredMBB->end()))
490 }
while (!Worklist.
empty());
495 !HasEFLAGSClobber(TestMBB->
begin(), TestPos)) {
498 MachineBasicBlock *HoistMBB =
501 [&](MachineBasicBlock *
LHS, MachineBasicBlock *
RHS) {
502 return MDT->findNearestCommonDominator(LHS, RHS);
508 if (HasEFLAGSClobberPath(HoistMBB, TestMBB))
525 [&](MachineInstr &
MI) {
526 return MI.findRegisterDefOperand(X86::EFLAGS, nullptr);
529 dbgs() <<
" Using EFLAGS defined by: ";
532 dbgs() <<
" Using live-in flags for BB:\n";
540 SmallVector<MachineInstr *, 4> JmpIs;
547 CondRegArray CondRegs = collectCondsInRegs(*TestMBB, TestPos);
553 SmallPtrSet<MachineBasicBlock *, 2> VisitedBlocks;
560 bool FlagsKilled =
false;
571 for (
auto MII = (&UseMBB == &
MBB && !VisitedBlocks.
count(&UseMBB))
576 MachineInstr &
MI = *MII++;
581 if (&
MI == CopyI || &
MI == &CopyDefI) {
583 "Should only encounter these on the second pass over the "
588 MachineOperand *FlagUse =
589 MI.findRegisterUseOperand(X86::EFLAGS,
nullptr);
590 FlagsKilled =
MI.modifiesRegister(X86::EFLAGS,
TRI);
592 if (!FlagUse && FlagsKilled)
612 auto JmpIt =
MI.getIterator();
614 JmpIs.push_back(&*JmpIt);
622 unsigned Opc =
MI.getOpcode();
623 if (
Opc == TargetOpcode::COPY) {
625 MRI->replaceRegWith(
MI.getOperand(0).getReg(),
627 MI.eraseFromParent();
628 }
else if (X86::isSETCC(
Opc) || X86::isSETZUCC(
Opc)) {
629 rewriteSetCC(*TestMBB, TestPos, TestLoc,
MI, CondRegs);
631 rewriteArithmetic(*TestMBB, TestPos, TestLoc,
MI, CondRegs);
633 rewriteMI(*TestMBB, TestPos, TestLoc,
MI, CondRegs);
647 for (MachineBasicBlock *SuccMBB : UseMBB.
successors())
648 if (SuccMBB->isLiveIn(X86::EFLAGS) &&
649 VisitedBlocks.
insert(SuccMBB).second) {
663 if (SuccMBB == TestMBB || !MDT->
dominates(TestMBB, SuccMBB)) {
666 <<
"ERROR: Encountered use that is not dominated by our test "
667 "basic block! Rewriting this would require inserting PHI "
668 "nodes to track the flag state across the CFG.\n\nTest "
671 dbgs() <<
"Use block:\n";
675 "Cannot lower EFLAGS copy when original copy def "
676 "does not dominate all uses.");
682 SuccMBB->removeLiveIn(X86::EFLAGS);
684 }
while (!Blocks.
empty());
689 MachineBasicBlock *LastJmpMBB =
nullptr;
690 for (MachineInstr *JmpI : JmpIs) {
693 if (JmpI->getParent() == LastJmpMBB)
698 rewriteMI(*TestMBB, TestPos, TestLoc, *JmpI, CondRegs);
706 for (MachineBasicBlock &
MBB : MF)
707 for (MachineInstr &
MI :
MBB)
708 if (
MI.getOpcode() == TargetOpcode::COPY &&
709 (
MI.getOperand(0).getReg() == X86::EFLAGS ||
710 MI.getOperand(1).getReg() == X86::EFLAGS)) {
722CondRegArray X86FlagsCopyLoweringPass::collectCondsInRegs(
724 CondRegArray CondRegs = {};
727 for (MachineInstr &
MI :
731 MI.getOperand(0).isReg() &&
MI.getOperand(0).getReg().isVirtual()) {
733 "A non-storing SETcc should always define a register!");
734 CondRegs[
Cond] =
MI.getOperand(0).getReg();
739 if (
MI.findRegisterDefOperand(X86::EFLAGS,
nullptr))
745Register X86FlagsCopyLoweringPass::promoteCondToReg(
749 auto SetI =
BuildMI(TestMBB, TestPos, TestLoc,
TII->get(X86::SETCCr),
Reg)
757std::pair<Register, bool> X86FlagsCopyLoweringPass::getCondOrInverseInReg(
762 if (!CondReg && !InvCondReg)
763 CondReg = promoteCondToReg(TestMBB, TestPos, TestLoc,
Cond);
766 return {CondReg,
false};
768 return {InvCondReg,
true};
771void X86FlagsCopyLoweringPass::insertTest(MachineBasicBlock &
MBB,
781void X86FlagsCopyLoweringPass::rewriteSetCC(MachineBasicBlock &
MBB,
785 CondRegArray &CondRegs) {
792 CondReg = promoteCondToReg(
MBB, Pos, Loc,
Cond);
794 if (X86::isSETZUCC(
MI.getOpcode())) {
796 assert(!
MI.mayStore() &&
"Cannot handle memory variants");
798 "Cannot have a non-register defined operand to SETZUcc!");
802 MRI->clearKillFlags(OldReg);
803 for (
auto &Use :
MRI->use_instructions(OldReg)) {
804 assert(
Use.getOpcode() == X86::INSERT_SUBREG &&
805 "SETZUCC should be only used by INSERT_SUBREG");
806 Use.getOperand(2).setReg(CondReg);
808 Register ZeroReg =
MRI->createVirtualRegister(&X86::GR32RegClass);
811 Use.getOperand(1).setReg(ZeroReg);
813 MI.eraseFromParent();
819 if (!
MI.mayStore()) {
821 "Cannot have a non-register defined operand to SETcc!");
825 MRI->clearKillFlags(OldReg);
826 MRI->replaceRegWith(OldReg, CondReg);
827 MI.eraseFromParent();
832 auto MIB =
BuildMI(*
MI.getParent(),
MI.getIterator(),
MI.getDebugLoc(),
833 TII->get(X86::MOV8mr));
836 MIB.add(
MI.getOperand(i));
839 MIB.setMemRefs(
MI.memoperands());
840 MI.eraseFromParent();
843void X86FlagsCopyLoweringPass::rewriteArithmetic(
845 const DebugLoc &Loc, MachineInstr &
MI, CondRegArray &CondRegs) {
858 CondReg = promoteCondToReg(
MBB, Pos, Loc,
Cond);
861 Register TmpReg =
MRI->createVirtualRegister(PromoteRC);
864 TII->get(Subtarget->hasNDD() ? X86::ADD8ri_ND : X86::ADD8ri))
871 MI.findRegisterUseOperand(X86::EFLAGS,
nullptr)->setIsKill(
true);
875#define FROM_TO(A, B) \
876 case X86::CMOV##A##_Fp32: \
877 case X86::CMOV##A##_Fp64: \
878 case X86::CMOV##A##_Fp80: \
879 return X86::COND_##B;
899 case X86::CMOVB_##A: \
900 case X86::CMOVE_##A: \
901 case X86::CMOVP_##A: \
902 case X86::CMOVBE_##A: \
903 case X86::CMOVNB_##A: \
904 case X86::CMOVNE_##A: \
905 case X86::CMOVNP_##A: \
906 case X86::CMOVNBE_##A: \
907 return (CC == X86::COND_E) ? X86::CMOVE_##A : X86::CMOVNE_##A;
918void X86FlagsCopyLoweringPass::rewriteMI(MachineBasicBlock &
MBB,
921 CondRegArray &CondRegs) {
923 bool IsImplicitCC =
false;
932 std::tie(CondReg, Inverted) =
933 getCondOrInverseInReg(
MBB, Pos, Loc, CC, CondRegs);
936 insertTest(*
MI.getParent(),
MI.getIterator(),
MI.getDebugLoc(), CondReg);
944 MI.getOperand(
MI.getDesc().getNumOperands() - 1).setImm(NewCC);
946 MI.findRegisterUseOperand(X86::EFLAGS,
nullptr)->setIsKill(
true);
unsigned const MachineRegisterInfo * MRI
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")
This file builds on the ADT/GraphTraits.h file to build generic depth first graph iterator.
static const 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)
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)
cl::opt< bool > X86EnableAPXForRelocation
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)
Represent the analysis usage information of a pass.
AnalysisUsage & addUsedIfAvailable()
Add the specified Pass class to the set of analyses used 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.
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 & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, 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 eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
LLVM_ABI void dump() const
const MachineOperand & getOperand(unsigned i) const
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.
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)
const X86InstrInfo * getInstrInfo() const override
const X86RegisterInfo * getRegisterInfo() const override
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
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 getNFVariant(unsigned Opc)
NodeAddr< UseNode * > Use
This is an optimization pass for GlobalISel generic memory operations.
static bool isAddMemInstrWithRelocation(const MachineInstr &MI)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
detail::scope_exit< std::decay_t< Callable > > make_scope_exit(Callable &&F)
auto successors(const MachineBasicBlock *BB)
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
FunctionPass * createX86FlagsCopyLoweringPass()
Return a pass that lowers EFLAGS copy pseudo instructions.
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...
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.