62#define PASS_KEY "x86-flags-copy-lowering"
63#define DEBUG_TYPE PASS_KEY
65STATISTIC(NumCopiesEliminated,
"Number of copies of EFLAGS eliminated");
66STATISTIC(NumSetCCsInserted,
"Number of setCC instructions inserted");
67STATISTIC(NumTestsInserted,
"Number of test instructions inserted");
68STATISTIC(NumAddsInserted,
"Number of adds instructions inserted");
69STATISTIC(NumNFsConvertedTo,
"Number of NF instructions converted to");
74using CondRegArray = std::array<unsigned, X86::LAST_VALID_COND + 1>;
101 std::pair<unsigned, bool> getCondOrInverseInReg(
109 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;
190 if (IsEdgeSplit || *SI != &UnsplitSucc)
199 if (Succ != &UnsplitSucc)
204 "Failed to make the new block a successor!");
212 for (
int OpIdx = 1, NumOps =
MI.getNumOperands(); OpIdx < NumOps;
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);
253bool X86FlagsCopyLoweringPass::runOnMachineFunction(
MachineFunction &MF) {
259 TII = Subtarget->getInstrInfo();
260 TRI = Subtarget->getRegisterInfo();
261 PromoteRC = &X86::GR8RegClass;
268 return MI.getOpcode() == TargetOpcode::COPY;
277 auto MDTWrapper = getAnalysisIfAvailable<MachineDominatorTreeWrapperPass>();
278 std::unique_ptr<MachineDominatorTree> OwnedMDT;
280 MDT = &MDTWrapper->getDomTree();
282 OwnedMDT = std::make_unique<MachineDominatorTree>();
283 OwnedMDT->getBase().recalculate(MF);
284 MDT = OwnedMDT.get();
295 if (
MI.getOpcode() == TargetOpcode::COPY &&
296 MI.getOperand(0).getReg() == X86::EFLAGS)
311 if (Subtarget->hasNF()) {
315 while (CopyIIt != CopyIEnd) {
316 auto NCopyIIt = std::next(CopyIIt);
331 for (
auto I = (
MBB != CopyDefIMBB)
343 goto ProcessNextCopyI;
350 RemovedCopies.
insert(CopyI);
353 RemovedCopies.
insert(CopyDefI);
356 ++NumCopiesEliminated;
357 for (
auto *Clobber : EvitableClobbers) {
359 assert(NewOpc &&
"evitable clobber must have a NF variant");
360 Clobber->setDesc(
TII->get(NewOpc));
361 Clobber->removeOperand(
362 Clobber->findRegisterDefOperand(X86::EFLAGS,
nullptr)
369 if (*BI != CopyDefIMBB)
370 BI->addLiveIn(X86::EFLAGS);
374 Copies.set_subtract(RemovedCopies);
397 "The input to the copy for EFLAGS should always be a register!");
399 if (CopyDefI.
getOpcode() != TargetOpcode::COPY) {
415 dbgs() <<
"ERROR: Encountered unexpected def of an eflags copy: ";
418 "Cannot lower EFLAGS copy unless it is defined in turn by a copy!");
427 ++NumCopiesEliminated;
431 assert(DOp.isDef() &&
"Expected register def!");
432 assert(DOp.getReg() == X86::EFLAGS &&
"Unexpected copy def register!");
460 return &
MI != CopyI &&
461 MI.findRegisterDefOperand(X86::EFLAGS,
nullptr);
466 assert(MDT->dominates(BeginMBB, EndMBB) &&
467 "Only support paths down the dominator tree!");
476 if (!Visited.
insert(PredMBB).second)
478 if (HasEFLAGSClobber(PredMBB->begin(), PredMBB->end()))
483 }
while (!Worklist.
empty());
488 !HasEFLAGSClobber(TestMBB->
begin(), TestPos)) {
495 return MDT->findNearestCommonDominator(LHS, RHS);
501 if (HasEFLAGSClobberPath(HoistMBB, TestMBB))
519 return MI.findRegisterDefOperand(X86::EFLAGS, nullptr);
522 dbgs() <<
" Using EFLAGS defined by: ";
525 dbgs() <<
" Using live-in flags for BB:\n";
540 CondRegArray CondRegs = collectCondsInRegs(*TestMBB, TestPos);
553 bool FlagsKilled =
false;
564 for (
auto MII = (&UseMBB == &
MBB && !VisitedBlocks.
count(&UseMBB))
574 if (&
MI == CopyI || &
MI == &CopyDefI) {
576 "Should only encounter these on the second pass over the "
582 MI.findRegisterUseOperand(X86::EFLAGS,
nullptr);
583 FlagsKilled =
MI.modifiesRegister(X86::EFLAGS,
TRI);
585 if (!FlagUse && FlagsKilled)
605 auto JmpIt =
MI.getIterator();
607 JmpIs.push_back(&*JmpIt);
615 unsigned Opc =
MI.getOpcode();
616 if (Opc == TargetOpcode::COPY) {
618 MRI->replaceRegWith(
MI.getOperand(0).getReg(),
620 MI.eraseFromParent();
621 }
else if (X86::isSETCC(Opc)) {
622 rewriteSetCC(*TestMBB, TestPos, TestLoc,
MI, CondRegs);
624 rewriteArithmetic(*TestMBB, TestPos, TestLoc,
MI, CondRegs);
626 rewriteMI(*TestMBB, TestPos, TestLoc,
MI, CondRegs);
641 if (SuccMBB->isLiveIn(X86::EFLAGS) &&
642 VisitedBlocks.
insert(SuccMBB).second) {
656 if (SuccMBB == TestMBB || !MDT->dominates(TestMBB, SuccMBB)) {
659 <<
"ERROR: Encountered use that is not dominated by our test "
660 "basic block! Rewriting this would require inserting PHI "
661 "nodes to track the flag state across the CFG.\n\nTest "
664 dbgs() <<
"Use block:\n";
668 "Cannot lower EFLAGS copy when original copy def "
669 "does not dominate all uses.");
672 Blocks.push_back(SuccMBB);
675 SuccMBB->removeLiveIn(X86::EFLAGS);
677 }
while (!
Blocks.empty());
686 if (JmpI->getParent() == LastJmpMBB)
691 rewriteMI(*TestMBB, TestPos, TestLoc, *JmpI, CondRegs);
701 if (
MI.getOpcode() == TargetOpcode::COPY &&
702 (
MI.getOperand(0).getReg() == X86::EFLAGS ||
703 MI.getOperand(1).getReg() == X86::EFLAGS)) {
715CondRegArray X86FlagsCopyLoweringPass::collectCondsInRegs(
717 CondRegArray CondRegs = {};
724 MI.getOperand(0).isReg() &&
MI.getOperand(0).getReg().isVirtual()) {
726 "A non-storing SETcc should always define a register!");
727 CondRegs[
Cond] =
MI.getOperand(0).getReg();
732 if (
MI.findRegisterDefOperand(X86::EFLAGS,
nullptr))
738Register X86FlagsCopyLoweringPass::promoteCondToReg(
742 auto SetI =
BuildMI(TestMBB, TestPos, TestLoc,
TII->get(X86::SETCCr), Reg)
750std::pair<unsigned, bool> X86FlagsCopyLoweringPass::getCondOrInverseInReg(
753 unsigned &CondReg = CondRegs[
Cond];
755 if (!CondReg && !InvCondReg)
756 CondReg = promoteCondToReg(TestMBB, TestPos, TestLoc,
Cond);
759 return {CondReg,
false};
761 return {InvCondReg,
true};
766 const DebugLoc &Loc,
unsigned Reg) {
778 CondRegArray &CondRegs) {
783 unsigned &CondReg = CondRegs[
Cond];
785 CondReg = promoteCondToReg(
MBB, Pos, Loc,
Cond);
789 if (!
MI.mayStore()) {
791 "Cannot have a non-register defined operand to SETcc!");
795 MRI->clearKillFlags(OldReg);
796 MRI->replaceRegWith(OldReg, CondReg);
797 MI.eraseFromParent();
802 auto MIB =
BuildMI(*
MI.getParent(),
MI.getIterator(),
MI.getDebugLoc(),
803 TII->get(X86::MOV8mr));
806 MIB.add(
MI.getOperand(i));
809 MIB.setMemRefs(
MI.memoperands());
810 MI.eraseFromParent();
813void X86FlagsCopyLoweringPass::rewriteArithmetic(
826 unsigned &CondReg = CondRegs[
Cond];
828 CondReg = promoteCondToReg(
MBB, Pos, Loc,
Cond);
831 Register TmpReg =
MRI->createVirtualRegister(PromoteRC);
834 TII->get(Subtarget->hasNDD() ? X86::ADD8ri_ND : X86::ADD8ri))
841 MI.findRegisterUseOperand(X86::EFLAGS,
nullptr)->setIsKill(
true);
845#define FROM_TO(A, B) \
846 case X86::CMOV##A##_Fp32: \
847 case X86::CMOV##A##_Fp64: \
848 case X86::CMOV##A##_Fp80: \
849 return X86::COND_##B;
869 case X86::CMOVB_##A: \
870 case X86::CMOVE_##A: \
871 case X86::CMOVP_##A: \
872 case X86::CMOVBE_##A: \
873 case X86::CMOVNB_##A: \
874 case X86::CMOVNE_##A: \
875 case X86::CMOVNP_##A: \
876 case X86::CMOVNBE_##A: \
877 return (CC == X86::COND_E) ? X86::CMOVE_##A : X86::CMOVNE_##A;
891 CondRegArray &CondRegs) {
893 bool IsImplicitCC =
false;
902 std::tie(CondReg, Inverted) =
903 getCondOrInverseInReg(
MBB, Pos, Loc,
CC, CondRegs);
906 insertTest(*
MI.getParent(),
MI.getIterator(),
MI.getDebugLoc(), CondReg);
914 MI.getOperand(
MI.getDesc().getNumOperands() - 1).setImm(NewCC);
916 MI.findRegisterUseOperand(X86::EFLAGS,
nullptr)->setIsKill(
true);
unsigned const MachineRegisterInfo * MRI
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
This file builds on the ADT/GraphTraits.h file to build generic depth first graph iterator.
DenseMap< Block *, BlockRelaxAux > Blocks
static const HTTPClientCleanup Cleanup
const HexagonInstrInfo * TII
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
unsigned const TargetRegisterInfo * TRI
#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
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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)
static X86::CondCode getImplicitCondFromMI(unsigned Opc)
static MachineBasicBlock & splitBlock(MachineBasicBlock &MBB, MachineInstr &SplitI, const X86InstrInfo &TII)
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()
void replaceSuccessor(MachineBasicBlock *Old, MachineBasicBlock *New)
Replace successor OLD with NEW and update probability info.
MachineBasicBlock * getFallThrough(bool JumpToFallThrough=true)
Return the fallthrough block if the block can implicitly transfer control to the block after it by fa...
instr_iterator insert(instr_iterator I, MachineInstr *M)
Insert MI into the instruction list before I, possibly inside a bundle.
bool isLiveIn(MCPhysReg Reg, LaneBitmask LaneMask=LaneBitmask::getAll()) const
Return true if the specified register is in the live in set.
succ_iterator succ_begin()
iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
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()
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 '...
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.
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
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.
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.
void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
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.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Wrapper class representing virtual and physical registers.
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.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
A SetVector that performs no allocations if smaller than a certain size.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
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.
Reg
All possible values of the reg field in the ModR/M byte.
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)
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.
detail::scope_exit< std::decay_t< Callable > > make_scope_exit(Callable &&F)
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)
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.
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
idf_iterator< T > idf_end(const T &G)
OutputIt copy(R &&Range, OutputIt Out)
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.