66 #define PASS_KEY "x86-flags-copy-lowering" 67 #define DEBUG_TYPE PASS_KEY 69 STATISTIC(NumCopiesEliminated,
"Number of copies of EFLAGS eliminated");
70 STATISTIC(NumSetCCsInserted,
"Number of setCC instructions inserted");
71 STATISTIC(NumTestsInserted,
"Number of test instructions inserted");
72 STATISTIC(NumAddsInserted,
"Number of adds instructions inserted");
83 using CondRegArray = std::array<unsigned, X86::LAST_VALID_COND + 1>;
91 StringRef getPassName()
const override {
return "X86 EFLAGS copy lowering"; }
112 std::pair<unsigned, bool>
122 CondRegArray &CondRegs);
126 CondRegArray &CondRegs);
139 CondRegArray &CondRegs);
145 "X86 EFLAGS copy lowering",
false,
false)
150 return new X86FlagsCopyLoweringPass();
155 void X86FlagsCopyLoweringPass::getAnalysisUsage(
AnalysisUsage &AU)
const {
180 "by this instruction!");
182 #define LLVM_EXPAND_INSTR_SIZES(MNEMONIC, SUFFIX) \ 183 case X86::MNEMONIC##8##SUFFIX: \ 184 case X86::MNEMONIC##16##SUFFIX: \ 185 case X86::MNEMONIC##32##SUFFIX: \ 186 case X86::MNEMONIC##64##SUFFIX: 188 #define LLVM_EXPAND_ADC_SBB_INSTR(MNEMONIC) \ 189 LLVM_EXPAND_INSTR_SIZES(MNEMONIC, rr) \ 190 LLVM_EXPAND_INSTR_SIZES(MNEMONIC, rr_REV) \ 191 LLVM_EXPAND_INSTR_SIZES(MNEMONIC, rm) \ 192 LLVM_EXPAND_INSTR_SIZES(MNEMONIC, mr) \ 193 case X86::MNEMONIC##8ri: \ 194 case X86::MNEMONIC##16ri8: \ 195 case X86::MNEMONIC##32ri8: \ 196 case X86::MNEMONIC##64ri8: \ 197 case X86::MNEMONIC##16ri: \ 198 case X86::MNEMONIC##32ri: \ 199 case X86::MNEMONIC##64ri32: \ 200 case X86::MNEMONIC##8mi: \ 201 case X86::MNEMONIC##16mi8: \ 202 case X86::MNEMONIC##32mi8: \ 203 case X86::MNEMONIC##64mi8: \ 204 case X86::MNEMONIC##16mi: \ 205 case X86::MNEMONIC##32mi: \ 206 case X86::MNEMONIC##64mi32: \ 207 case X86::MNEMONIC##8i8: \ 208 case X86::MNEMONIC##16i16: \ 209 case X86::MNEMONIC##32i32: \ 210 case X86::MNEMONIC##64i32: 218 #undef LLVM_EXPAND_ADC_SBB_INSTR 223 return FlagArithMnemonic::RCL;
228 return FlagArithMnemonic::RCR;
230 #undef LLVM_EXPAND_INSTR_SIZES 236 return FlagArithMnemonic::ADCX;
242 return FlagArithMnemonic::ADOX;
252 "Split instruction must be in the split block!");
254 "Only designed to split a tail of branch instructions!");
256 "Must split on an actual jCC instruction!");
262 "Must split after an actual jCC instruction!");
264 "Must only have this one terminator prior to the split!");
276 "Should only have spliced terminators!");
279 return MOp.isMBB() && MOp.getMBB() == &UnsplitSucc;
296 if (IsEdgeSplit || *
SI != &UnsplitSucc)
305 if (Succ != &UnsplitSucc)
310 "Failed to make the new block a successor!");
318 for (
int OpIdx = 1, NumOps =
MI.getNumOperands(); OpIdx < NumOps;
322 assert(OpMBB.
isMBB() &&
"Block operand to a PHI is not a block!");
323 if (OpMBB.
getMBB() != &MBB)
327 if (!IsEdgeSplit || Succ != &UnsplitSucc) {
336 MI.addOperand(MF, OpV);
346 bool X86FlagsCopyLoweringPass::runOnMachineFunction(
MachineFunction &MF) {
352 TII = Subtarget->getInstrInfo();
353 TRI = Subtarget->getRegisterInfo();
354 MDT = &getAnalysis<MachineDominatorTree>();
355 PromoteRC = &X86::GR8RegClass;
369 if (
MI.getOpcode() == TargetOpcode::COPY &&
370 MI.getOperand(0).getReg() == X86::EFLAGS)
378 "The input to the copy for EFLAGS should always be a register!");
380 if (CopyDefI.getOpcode() != TargetOpcode::COPY) {
396 dbgs() <<
"ERROR: Encountered unexpected def of an eflags copy: ";
399 "Cannot lower EFLAGS copy unless it is defined in turn by a copy!");
405 CopyI->eraseFromParent();
406 if (MRI->use_empty(CopyDefI.getOperand(0).getReg()))
407 CopyDefI.eraseFromParent();
408 ++NumCopiesEliminated;
412 assert(DOp.isDef() &&
"Expected register def!");
413 assert(DOp.getReg() == X86::EFLAGS &&
"Unexpected copy def register!");
418 auto TestPos = CopyDefI.getIterator();
419 DebugLoc TestLoc = CopyDefI.getDebugLoc();
446 assert(MDT->dominates(BeginMBB, EndMBB) &&
447 "Only support paths down the dominator tree!");
456 if (!Visited.insert(PredMBB).second)
458 if (HasEFLAGSClobber(PredMBB->begin(), PredMBB->end()))
463 }
while (!Worklist.
empty());
468 !HasEFLAGSClobber(TestMBB->
begin(), TestPos)) {
475 return MDT->findNearestCommonDominator(LHS, RHS);
481 if (HasEFLAGSClobberPath(HoistMBB, TestMBB))
499 return MI.findRegisterDefOperand(X86::EFLAGS);
502 dbgs() <<
" Using EFLAGS defined by: ";
505 dbgs() <<
" Using live-in flags for BB:\n";
520 CondRegArray CondRegs = collectCondsInRegs(*TestMBB, TestPos);
533 bool FlagsKilled =
false;
544 for (
auto MII = (&UseMBB == &MBB && !VisitedBlocks.
count(&UseMBB))
545 ? std::next(CopyI->getIterator())
554 if (&MI == CopyI || &MI == &CopyDefI) {
555 assert(&UseMBB == &MBB && VisitedBlocks.
count(&MBB) &&
556 "Should only encounter these on the second pass over the " 594 JmpIs.push_back(&*JmpIt);
604 rewriteCMov(*TestMBB, TestPos, TestLoc, MI, *FlagUse, CondRegs);
607 rewriteSetCC(*TestMBB, TestPos, TestLoc, MI, *FlagUse, CondRegs);
608 }
else if (MI.
getOpcode() == TargetOpcode::COPY) {
609 rewriteCopy(MI, *FlagUse, CopyDefI);
613 "Expected a def of EFLAGS for this instruction!");
630 rewriteSetCarryExtended(*TestMBB, TestPos, TestLoc, MI, *FlagUse,
636 rewriteArithmetic(*TestMBB, TestPos, TestLoc, MI, *FlagUse,
655 if (SuccMBB->isLiveIn(X86::EFLAGS) &&
656 VisitedBlocks.
insert(SuccMBB).second) {
670 if (SuccMBB == TestMBB || !MDT->dominates(TestMBB, SuccMBB)) {
673 <<
"ERROR: Encountered use that is not dominated by our test " 674 "basic block! Rewriting this would require inserting PHI " 675 "nodes to track the flag state across the CFG.\n\nTest " 678 dbgs() <<
"Use block:\n";
682 "Cannot lower EFLAGS copy when original copy def " 683 "does not dominate all uses.");
688 }
while (!Blocks.
empty());
697 if (JmpI->getParent() == LastJmpMBB)
702 rewriteCondJmp(*TestMBB, TestPos, TestLoc, *JmpI, CondRegs);
712 if (
MI.getOpcode() == TargetOpcode::COPY &&
713 (
MI.getOperand(0).getReg() == X86::EFLAGS ||
714 MI.getOperand(1).getReg() == X86::EFLAGS)) {
726 CondRegArray X86FlagsCopyLoweringPass::collectCondsInRegs(
728 CondRegArray CondRegs = {};
735 TRI->isVirtualRegister(
MI.getOperand(0).getReg())) {
737 "A non-storing SETcc should always define a register!");
738 CondRegs[Cond] =
MI.getOperand(0).getReg();
743 if (
MI.findRegisterDefOperand(X86::EFLAGS))
749 unsigned X86FlagsCopyLoweringPass::promoteCondToReg(
752 unsigned Reg =
MRI->createVirtualRegister(PromoteRC);
753 auto SetI =
BuildMI(TestMBB, TestPos, TestLoc,
761 std::pair<unsigned, bool> X86FlagsCopyLoweringPass::getCondOrInverseInReg(
764 unsigned &CondReg = CondRegs[Cond];
766 if (!CondReg && !InvCondReg)
767 CondReg = promoteCondToReg(TestMBB, TestPos, TestLoc, Cond);
770 return {CondReg,
false};
772 return {InvCondReg,
true};
785 void X86FlagsCopyLoweringPass::rewriteArithmetic(
788 CondRegArray &CondRegs) {
798 case FlagArithMnemonic::ADCX:
799 case FlagArithMnemonic::RCL:
800 case FlagArithMnemonic::RCR:
808 case FlagArithMnemonic::ADOX:
819 unsigned &CondReg = CondRegs[Cond];
821 CondReg = promoteCondToReg(TestMBB, TestPos, TestLoc, Cond);
826 unsigned TmpReg =
MRI->createVirtualRegister(PromoteRC);
843 CondRegArray &CondRegs) {
848 std::tie(CondReg, Inverted) =
849 getCondOrInverseInReg(TestMBB, TestPos, TestLoc, Cond, CondRegs);
866 void X86FlagsCopyLoweringPass::rewriteCondJmp(
873 std::tie(CondReg, Inverted) =
874 getCondOrInverseInReg(TestMBB, TestPos, TestLoc, Cond, CondRegs);
885 const int ImplicitEFLAGSOpIdx = 1;
890 void X86FlagsCopyLoweringPass::rewriteCopy(
MachineInstr &MI,
899 void X86FlagsCopyLoweringPass::rewriteSetCarryExtended(
902 CondRegArray &CondRegs) {
911 "Cannot have a non-register defined operand to this variant of SETB!");
916 auto RewriteToReg = [&](
unsigned Reg) {
928 auto AdjustReg = [&](
unsigned Reg) {
929 auto &OrigRC = *
MRI->getRegClass(Reg);
930 if (&OrigRC == &SetBRC)
935 int OrigRegSize =
TRI->getRegSizeInBits(OrigRC) / 8;
936 int TargetRegSize =
TRI->getRegSizeInBits(SetBRC) / 8;
937 assert(OrigRegSize <= 8 &&
"No GPRs larger than 64-bits!");
938 assert(TargetRegSize <= 8 &&
"No GPRs larger than 64-bits!");
939 int SubRegIdx[] = {X86::NoSubRegister, X86::sub_8bit, X86::sub_16bit,
940 X86::NoSubRegister, X86::sub_32bit};
946 if (OrigRegSize < TargetRegSize && OrigRegSize < 4) {
947 NewReg =
MRI->createVirtualRegister(&X86::GR32RegClass);
948 BuildMI(MBB, SetPos, SetLoc,
TII->get(X86::MOVZX32rr8), NewReg)
950 if (&SetBRC == &X86::GR32RegClass)
956 NewReg =
MRI->createVirtualRegister(&SetBRC);
957 if (OrigRegSize < TargetRegSize) {
958 BuildMI(MBB, SetPos, SetLoc,
TII->get(TargetOpcode::SUBREG_TO_REG),
962 .
addImm(SubRegIdx[OrigRegSize]);
963 }
else if (OrigRegSize > TargetRegSize) {
964 if (TargetRegSize == 1 && !Subtarget->is64Bit()) {
966 MRI->constrainRegClass(Reg, &X86::GR32_ABCDRegClass);
969 BuildMI(MBB, SetPos, SetLoc,
TII->get(TargetOpcode::COPY),
971 .addReg(Reg, 0, SubRegIdx[TargetRegSize]);
973 BuildMI(MBB, SetPos, SetLoc,
TII->get(TargetOpcode::COPY), NewReg)
981 CondReg = promoteCondToReg(TestMBB, TestPos, TestLoc,
X86::COND_B);
987 unsigned ExtCondReg = AdjustReg(CondReg);
991 unsigned ZeroReg =
MRI->createVirtualRegister(&X86::GR32RegClass);
992 BuildMI(MBB, SetPos, SetLoc,
TII->get(X86::MOV32r0), ZeroReg);
993 ZeroReg = AdjustReg(ZeroReg);
1001 case X86::SETB_C16r:
1005 case X86::SETB_C32r:
1009 case X86::SETB_C64r:
1016 unsigned ResultReg =
MRI->createVirtualRegister(&SetBRC);
1017 BuildMI(MBB, SetPos, SetLoc,
TII->get(Sub), ResultReg)
1020 return RewriteToReg(ResultReg);
1028 CondRegArray &CondRegs) {
1033 unsigned &CondReg = CondRegs[Cond];
1035 CondReg = promoteCondToReg(TestMBB, TestPos, TestLoc, Cond);
1041 "Cannot have a non-register defined operand to SETcc!");
unsigned GetCondBranchFromCond(CondCode CC)
const MachineInstrBuilder & setMemRefs(ArrayRef< MachineMemOperand *> MMOs) const
const MachineInstrBuilder & add(const MachineOperand &MO) const
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
instr_iterator instr_begin()
instr_iterator instr_end()
MachineBasicBlock * getMBB() const
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
This class represents lattice values for constants.
MachineOperand * findRegisterDefOperand(unsigned Reg, bool isDead=false, const TargetRegisterInfo *TRI=nullptr)
Wrapper for findRegisterDefOperandIdx, it returns a pointer to the MachineOperand rather than an inde...
CondCode getCondFromCMovOpc(unsigned Opc)
Return condition code of a CMov opcode.
void push_back(const T &Elt)
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
unsigned getReg() const
getReg - Returns the register number.
MachineOperand * findRegisterUseOperand(unsigned Reg, bool isKill=false, const TargetRegisterInfo *TRI=nullptr)
Wrapper for findRegisterUseOperandIdx, it returns a pointer to the MachineOperand rather than an inde...
CondCode getCondFromSETOpc(unsigned Opc)
Return condition code of a SET opcode.
AddrNumOperands - Total number of operands in a memory reference.
LLVM_NODISCARD detail::scope_exit< typename std::decay< Callable >::type > make_scope_exit(Callable &&F)
STATISTIC(NumFunctions, "Total number of functions")
unsigned const TargetRegisterInfo * TRI
iterator_range< succ_iterator > successors()
AnalysisUsage & addRequired()
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
const HexagonInstrInfo * TII
MachineBasicBlock * getFallThrough()
Return the fallthrough block if the block can implicitly transfer control to the block after it by fa...
void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
CondCode getCondFromBranchOpc(unsigned Opc)
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
auto reverse(ContainerTy &&C, typename std::enable_if< has_rbegin< ContainerTy >::value >::type *=nullptr) -> decltype(make_range(C.rbegin(), C.rend()))
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *bb=nullptr)
CreateMachineBasicBlock - Allocate a new MachineBasicBlock.
bool isBranch(QueryType Type=AnyInBundle) const
Returns true if this is a conditional, unconditional, or indirect branch.
void normalizeSuccProbs()
Normalize probabilities of all successors so that the sum of them becomes one.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
FlagArithMnemonic
An enumeration of the arithmetic instruction mnemonics which have interesting flag semantics...
MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
bool mayStore(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly modify memory.
unsigned const MachineRegisterInfo * MRI
ArrayRef< MachineMemOperand * > memoperands() const
Access to memory operands of the instruction.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
void setMBB(MachineBasicBlock *MBB)
#define LLVM_EXPAND_ADC_SBB_INSTR(MNEMONIC)
Represent the analysis usage information of a pass.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly...
FunctionPass class - This class is used to implement most global optimizations.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
self_iterator getIterator()
iterator_range< pred_iterator > predecessors()
auto find_if(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range))
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly...
static void r1(uint32_t &A, uint32_t &B, uint32_t &C, uint32_t &D, uint32_t &E, int I, uint32_t *Buf)
succ_iterator succ_begin()
unsigned getSETFromCond(CondCode CC, bool HasMemoryOperand=false)
Return a set opcode for the given condition and whether it has a memory operand.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
pred_iterator pred_begin()
INITIALIZE_PASS_END(RegBankSelect, DEBUG_TYPE, "Assign register bank of generic virtual registers", false, false) RegBankSelect
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
void setIsKill(bool Val=true)
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
Iterator for intrusive lists based on ilist_node.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements...
void setDesc(const MCInstrDesc &tid)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one...
MachineOperand class - Representation of each machine instruction operand.
CondCode GetOppositeBranchCondition(CondCode CC)
GetOppositeBranchCondition - Return the inverse of the specified cond, e.g.
LLVM_NODISCARD T pop_back_val()
FunctionPass * createX86FlagsCopyLoweringPass()
Return a pass that lowers EFLAGS copy pseudo instructions.
INITIALIZE_PASS_BEGIN(X86FlagsCopyLoweringPass, DEBUG_TYPE, "X86 EFLAGS copy lowering", false, false) INITIALIZE_PASS_END(X86FlagsCopyLoweringPass
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isLiveIn(MCPhysReg Reg, LaneBitmask LaneMask=LaneBitmask::getAll()) const
Return true if the specified register is in the live in set.
unsigned getCMovFromCond(CondCode CC, unsigned RegBytes, bool HasMemoryOperand=false)
Return a cmov opcode for the given condition, register size in bytes, and operand type...
void replaceSuccessor(MachineBasicBlock *Old, MachineBasicBlock *New)
Replace successor OLD with NEW and update probability info.
iterator insert(iterator I, T &&Elt)
void copySuccessor(MachineBasicBlock *Orig, succ_iterator I)
Copy a successor (and any probability info) from original block to this block's.
const MachineBasicBlock * getParent() const
MachineRegisterInfo - Keep track of information for virtual and physical registers, including vreg register classes, use/def chains for registers, etc.
Representation of each machine instruction.
static MachineBasicBlock & splitBlock(MachineBasicBlock &MBB, MachineInstr &SplitI, const X86InstrInfo &TII)
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
static MachineOperand CreateMBB(MachineBasicBlock *MBB, unsigned char TargetFlags=0)
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 '...
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
#define LLVM_EXPAND_INSTR_SIZES(MNEMONIC, SUFFIX)
LLVM_NODISCARD bool empty() const
void initializeX86FlagsCopyLoweringPassPass(PassRegistry &)
static FlagArithMnemonic getMnemonicFromOpcode(unsigned Opcode)
const MachineInstrBuilder & addReg(unsigned RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
bool isSuccessor(const MachineBasicBlock *MBB) const
Return true if the specified MBB is a successor of this block.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
bool memoperands_empty() const
Return true if we don't have any memory operands which described the memory access done by this instr...
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
void insert(iterator MBBI, MachineBasicBlock *MBB)
StringRef - Represent a constant reference to a string, i.e.
PassRegistry - This class manages the registration and intitialization of the pass subsystem as appli...
bool isMBB() const
isMBB - Tests if this is a MO_MachineBasicBlock operand.
const MachineOperand & getOperand(unsigned i) const
OutputIt copy(R &&Range, OutputIt Out)
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...