79#define DEBUG_TYPE "x86-cmov-conversion"
81STATISTIC(NumOfSkippedCmovGroups,
"Number of unsupported CMOV-groups");
82STATISTIC(NumOfCmovGroupCandidate,
"Number of CMOV-group candidates");
83STATISTIC(NumOfLoopCandidate,
"Number of CMOV-conversion profitable loops");
84STATISTIC(NumOfOptimizedCmovGroups,
"Number of optimized CMOV-groups");
89class X86CmovConversionImpl {
96 MachineRegisterInfo *MRI =
nullptr;
97 const TargetInstrInfo *TII =
nullptr;
98 const TargetRegisterInfo *TRI =
nullptr;
99 const X86Subtarget *STI =
nullptr;
100 MachineLoopInfo *MLI =
nullptr;
101 TargetSchedModel TSchedModel;
104 using CmovGroup = SmallVector<MachineInstr *, 2>;
105 using CmovGroups = SmallVector<CmovGroup, 2>;
114 CmovGroups &CmovInstGroups,
115 bool IncludeLoads =
false);
124 CmovGroups &CmovInstGroups);
129 void convertCmovInstsToBranches(SmallVectorImpl<MachineInstr *> &Group)
const;
134 X86CmovConversionLegacy() : MachineFunctionPass(ID) {}
136 StringRef getPassName()
const override {
return "X86 cmov Conversion"; }
138 void getAnalysisUsage(AnalysisUsage &AU)
const override;
146char X86CmovConversionLegacy::ID = 0;
148void X86CmovConversionLegacy::getAnalysisUsage(
AnalysisUsage &AU)
const {
156 const X86Options &CLOpts = STI->
getCLOpts();
157 if (!CLOpts.cmov_converter)
171 TSchedModel.
init(STI);
179 if (CLOpts.cmov_converter_force_mem_operand ||
180 CLOpts.cmov_converter_force_all) {
181 CmovGroups AllCmovGroups;
183 if (collectCmovCandidates(Blocks, AllCmovGroups,
true)) {
184 for (
auto &Group : AllCmovGroups) {
186 if (CLOpts.cmov_converter_force_mem_operand &&
187 !CLOpts.cmov_converter_force_all &&
188 llvm::none_of(Group, [&](MachineInstr *
I) { return I->mayLoad(); }))
195 convertCmovInstsToBranches(Group);
199 if (CLOpts.cmov_converter_force_all)
230 for (
int i = 0; i < (int)
Loops.size(); ++i)
233 for (MachineLoop *CurrLoop :
Loops) {
235 if (!CurrLoop->getSubLoops().empty())
239 CmovGroups CmovInstGroups;
241 if (!collectCmovCandidates(CurrLoop->getBlocks(), CmovInstGroups))
244 if (!checkForProfitableCmovCandidates(CurrLoop->getBlocks(),
249 for (
auto &Group : CmovInstGroups)
250 convertCmovInstsToBranches(Group);
256bool X86CmovConversionImpl::collectCmovCandidates(
280 for (
auto *
MBB : Blocks) {
287 bool FoundNonCMOVInst =
false;
289 bool SkipGroup =
false;
291 for (
auto &
I : *
MBB) {
293 if (
I.isDebugInstr())
300 !
I.getFlag(MachineInstr::MIFlag::Unpredictable) &&
301 (IncludeLoads || !
I.mayLoad()) && !
I.hasOrderedMemoryRef()) {
308 FoundNonCMOVInst =
false;
314 if (FoundNonCMOVInst || (CC != FirstCC && CC != FirstOppCC))
321 else if (CC != MemOpCC)
329 [&](MachineInstr &UseI) {
330 return UseI.getOpcode() == X86::SUBREG_TO_REG;
342 FoundNonCMOVInst =
true;
345 if (
I.definesRegister(X86::EFLAGS,
nullptr)) {
349 CmovInstGroups.push_back(Group);
351 ++NumOfSkippedCmovGroups;
360 CmovInstGroups.push_back(Group);
362 ++NumOfSkippedCmovGroups;
365 NumOfCmovGroupCandidate += CmovInstGroups.
size();
366 return !CmovInstGroups.empty();
378 divideCeil(TrueOpDepth * 3 + FalseOpDepth, 4),
379 divideCeil(FalseOpDepth * 3 + TrueOpDepth, 4));
382bool X86CmovConversionImpl::checkForProfitableCmovCandidates(
391 static const unsigned LoopIterations = 2;
392 DenseMap<MachineInstr *, DepthInfo> DepthMap;
393 DepthInfo LoopDepth[LoopIterations] = {{0, 0}, {0, 0}};
394 enum { PhyRegType = 0, VirRegType = 1, RegTypeNum = 2 };
396 DenseMap<Register, MachineInstr *> RegDefMaps[RegTypeNum];
399 DenseMap<MachineOperand *, MachineInstr *> OperandToDefMap;
402 DepthMap[
nullptr] = {0, 0};
404 SmallPtrSet<MachineInstr *, 4> CmovInstructions;
405 for (
auto &Group : CmovInstGroups)
431 for (DepthInfo &MaxDepth : LoopDepth) {
432 for (
auto *
MBB : Blocks) {
434 RegDefMaps[PhyRegType].
clear();
435 for (MachineInstr &
MI : *
MBB) {
437 if (
MI.isDebugInstr())
439 unsigned MIDepth = 0;
440 unsigned MIDepthOpt = 0;
441 bool IsCMOV = CmovInstructions.
count(&
MI);
442 for (
auto &MO :
MI.uses()) {
444 if (!MO.isReg() || !MO.isUse())
448 if (MachineInstr *
DefMI = RDM.lookup(
Reg)) {
449 OperandToDefMap[&MO] =
DefMI;
451 MIDepth = std::max(MIDepth,
Info.Depth);
453 MIDepthOpt = std::max(MIDepthOpt,
Info.OptDepth);
459 DepthMap[OperandToDefMap.
lookup(&
MI.getOperand(1))].OptDepth,
460 DepthMap[OperandToDefMap.
lookup(&
MI.getOperand(2))].OptDepth);
463 for (
auto &MO :
MI.operands()) {
464 if (!MO.isReg() || !MO.isDef())
470 unsigned Latency = TSchedModel.computeInstrLatency(&
MI);
472 MaxDepth.Depth = std::max(MaxDepth.Depth, MIDepth);
473 MaxDepth.OptDepth = std::max(MaxDepth.OptDepth, MIDepthOpt);
478 unsigned Diff[LoopIterations] = {LoopDepth[0].Depth - LoopDepth[0].OptDepth,
479 LoopDepth[1].Depth - LoopDepth[1].OptDepth};
509 if (Diff[1] < STI->
getCLOpts().cmov_converter_threshold)
512 bool WorthOptLoop =
false;
513 if (Diff[1] == Diff[0])
514 WorthOptLoop = Diff[0] * 8 >= LoopDepth[0].Depth;
515 else if (Diff[1] > Diff[0])
517 (Diff[1] - Diff[0]) * 2 >= (LoopDepth[1].
Depth - LoopDepth[0].
Depth) &&
518 (Diff[1] * 8 >= LoopDepth[1].Depth);
523 ++NumOfLoopCandidate;
536 unsigned MispredictPenalty = STI->getMispredictionPenalty();
537 CmovGroups TempGroups;
539 for (
auto &Group : TempGroups) {
540 bool WorthOpGroup =
true;
541 for (
auto *
MI : Group) {
547 unsigned Op = UIs.begin()->getOpcode();
548 if (
Op == X86::MOV64rm ||
Op == X86::MOV32rm) {
549 WorthOpGroup =
false;
555 DepthMap[OperandToDefMap.
lookup(&
MI->getOperand(4))].Depth;
557 DepthMap[OperandToDefMap.
lookup(&
MI->getOperand(1))].Depth,
558 DepthMap[OperandToDefMap.
lookup(&
MI->getOperand(2))].Depth);
559 if (ValCost > CondCost || (CondCost - ValCost) * 4 < MispredictPenalty) {
560 WorthOpGroup =
false;
566 CmovInstGroups.push_back(Group);
569 return !CmovInstGroups.empty();
573 if (
MI->killsRegister(X86::EFLAGS,
nullptr))
582 for (
auto I = std::next(ItrMI),
E = BB->
end();
I !=
E; ++
I) {
583 if (
I->readsRegister(X86::EFLAGS,
nullptr))
585 if (
I->definesRegister(X86::EFLAGS,
nullptr))
591 if (Succ->isLiveIn(X86::EFLAGS))
603 "Last instruction in a CMOV group must be a CMOV instruction");
606 for (
auto I =
First->getIterator(),
E =
Last->getIterator();
I !=
E;
I++) {
607 if (
I->isDebugInstr())
613 for (
auto *
MI : DBGInstructions)
614 MBB->insertAfter(
Last,
MI->removeFromParent());
617void X86CmovConversionImpl::convertCmovInstsToBranches(
618 SmallVectorImpl<MachineInstr *> &Group)
const {
619 assert(!Group.
empty() &&
"No CMOV instructions to convert");
620 ++NumOfOptimizedCmovGroups;
656 MachineInstr &
MI = *Group.
front();
657 MachineInstr *LastCMOV = Group.
back();
676 MachineBasicBlock *FalseMBB =
F->CreateMachineBasicBlock(BB);
677 MachineBasicBlock *SinkMBB =
F->CreateMachineBasicBlock(BB);
678 F->insert(It, FalseMBB);
679 F->insert(It, SinkMBB);
703 MachineInstrBuilder MIB;
714 DenseMap<Register, Register> FalseBBRegRewriteTable;
724 auto FRIt = FalseBBRegRewriteTable.
find(FalseReg);
725 if (FRIt == FalseBBRegRewriteTable.
end())
727 FalseReg = FRIt->second;
729 FalseBBRegRewriteTable[
MI.getOperand(0).getReg()] = FalseReg;
737 "Can only handle memory-operand cmov instructions with a condition "
738 "opposite to the selected branch direction.");
766 unsigned OldDebugInstrNum =
MI.peekDebugInstrNum();
767 SmallVector<MachineInstr *, 4> NewMIs;
772 assert(Unfolded &&
"Should never fail to unfold a loading cmov!");
778 "Last new instruction isn't the expected CMOV!");
781 if (&*MIItBegin == &
MI)
784 if (OldDebugInstrNum)
785 NewCMOV->setDebugInstrNum(OldDebugInstrNum);
789 for (
auto *NewMI : NewMIs) {
791 FalseMBB->
insert(FalseInsertionPoint, NewMI);
793 for (
auto &MOp : NewMI->uses()) {
796 auto It = FalseBBRegRewriteTable.
find(MOp.getReg());
797 if (It == FalseBBRegRewriteTable.
end())
800 MOp.setReg(It->second);
806 MOp.setIsKill(
false);
812 FalseBBRegRewriteTable[NewCMOV->getOperand(0).getReg()] = TmpReg;
821 DenseMap<Register, std::pair<Register, Register>> RegRewriteTable;
824 Register DestReg = MIIt->getOperand(0).getReg();
825 Register Op1Reg = MIIt->getOperand(1).getReg();
826 Register Op2Reg = MIIt->getOperand(2).getReg();
834 auto Op1Itr = RegRewriteTable.
find(Op1Reg);
835 if (Op1Itr != RegRewriteTable.
end())
836 Op1Reg = Op1Itr->second.first;
838 auto Op2Itr = RegRewriteTable.
find(Op2Reg);
839 if (Op2Itr != RegRewriteTable.
end())
840 Op2Reg = Op2Itr->second.second;
845 MIB =
BuildMI(*SinkMBB, SinkInsertionPoint,
DL,
TII->get(X86::PHI), DestReg)
856 if (
unsigned InstrNum = MIIt->peekDebugInstrNum())
860 RegRewriteTable[DestReg] = std::make_pair(Op1Reg, Op2Reg);
865 if (MIItBegin != MIItEnd)
866 F->getProperties().resetNoPHIs();
873 L->addBasicBlockToLoop(FalseMBB, *MLI);
874 L->addBasicBlockToLoop(SinkMBB, *MLI);
879 "X86 cmov Conversion",
false,
false)
885 return new X86CmovConversionLegacy();
888bool X86CmovConversionLegacy::runOnMachineFunction(
MachineFunction &MF) {
891 MachineLoopInfo *MLI = &getAnalysis<MachineLoopInfoWrapperPass>().getLI();
892 X86CmovConversionImpl Impl(MLI);
893 return Impl.runOnMachineFunction(MF);
900 X86CmovConversionImpl Impl(MLI);
901 bool Changed = Impl.runOnMachineFunction(MF);
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file defines the DenseMap class.
const HexagonInstrInfo * TII
Register const TargetRegisterInfo * TRI
Promote Memory to Register
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
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 bool checkEFLAGSLive(MachineInstr *MI)
static unsigned getDepthOfOptCmov(unsigned TrueOpDepth, unsigned FalseOpDepth)
static void packCmovGroup(MachineInstr *First, MachineInstr *Last)
Given /p First CMOV instruction and /p Last CMOV instruction representing a group of CMOV instruction...
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
iterator find(const_arg_type_t< KeyT > Val)
ValueT lookup(const_arg_type_t< KeyT > Val) const
Return the entry for the specified key, or a default constructed value if no such entry exists.
FunctionPass class - This class is used to implement most global optimizations.
LoopT * getLoopFor(const BlockT *BB) const
Return the inner most loop that BB lives in.
LLVM_ABI void transferSuccessorsAndUpdatePHIs(MachineBasicBlock *FromMBB)
Transfers all the successors, as in transferSuccessors, and update PHI operands in the successor bloc...
LLVM_ABI instr_iterator insert(instr_iterator I, MachineInstr *M)
Insert MI into the instruction list before I, possibly inside a bundle.
const BasicBlock * getBasicBlock() const
Return the LLVM basic block that this instance corresponded to originally.
LLVM_ABI void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
void addLiveIn(MCRegister PhysReg, LaneBitmask LaneMask=LaneBitmask::getAll())
Adds the specified register as a live in.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
LLVM_ABI instr_iterator erase(instr_iterator I)
Remove an instruction from the instruction list and delete it.
iterator_range< succ_iterator > successors()
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
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.
Function & getFunction()
Return the LLVM function that this machine code represents.
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 & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
void setDebugInstrNum(unsigned Num)
Set instruction number of this MachineInstr.
LLVM_ABI void dump() const
Analysis pass that exposes the MachineLoopInfo for a machine function.
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
iterator_range< use_instr_iterator > use_instructions(Register Reg) const
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
void insert_range(Range &&R)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
LLVM_ABI void init(const TargetSubtargetInfo *TSInfo, bool EnableSModel=true, bool EnableSItins=true)
Initialize the machine model for instruction scheduling.
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
const X86InstrInfo * getInstrInfo() const override
const X86RegisterInfo * getRegisterInfo() const override
const X86Options & getCLOpts() const
self_iterator getIterator()
@ BasicBlock
Various leaf nodes.
CondCode GetOppositeBranchCondition(CondCode CC)
GetOppositeBranchCondition - Return the inverse of the specified cond, e.g.
CondCode getCondFromCMov(const MachineInstr &MI)
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.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
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.
FunctionPass * createX86CmovConversionLegacyPass()
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.
bool hasSingleElement(ContainerTy &&C)
Returns true if the given container only contains a single element.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
constexpr T divideCeil(U Numerator, V Denominator)
Returns the integer ceil(Numerator / Denominator).
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
MCRegisterClass TargetRegisterClass
LLVM_ABI CGPassBuilderOption getCGPassBuilderOption()
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.