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)
MachineRegisterInfo & MRI
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 TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
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...
LLVM_ABI CGPassBuilderOption getCGPassBuilderOption(const TargetMachine &TM)
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
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
bool DisableSelectOptimize