diff options
Diffstat (limited to 'lib/Target/X86/X86CmovConversion.cpp')
| -rw-r--r-- | lib/Target/X86/X86CmovConversion.cpp | 359 |
1 files changed, 308 insertions, 51 deletions
diff --git a/lib/Target/X86/X86CmovConversion.cpp b/lib/Target/X86/X86CmovConversion.cpp index bfc834435de5..489d9d86e254 100644 --- a/lib/Target/X86/X86CmovConversion.cpp +++ b/lib/Target/X86/X86CmovConversion.cpp @@ -1,4 +1,4 @@ -//====-- X86CmovConversion.cpp - Convert Cmov to Branch -------------------===// +//====- X86CmovConversion.cpp - Convert Cmov to Branch --------------------===// // // The LLVM Compiler Infrastructure // @@ -6,104 +6,146 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// +// /// \file -/// This file implements a pass that converts X86 cmov instructions into branch -/// when profitable. This pass is conservative, i.e., it applies transformation -/// if and only if it can gaurantee a gain with high confidence. +/// This file implements a pass that converts X86 cmov instructions into +/// branches when profitable. This pass is conservative. It transforms if and +/// only if it can guarantee a gain with high confidence. /// /// Thus, the optimization applies under the following conditions: -/// 1. Consider as a candidate only CMOV in most inner loop, assuming that -/// most hotspots are represented by these loops. -/// 2. Given a group of CMOV instructions, that are using same EFLAGS def +/// 1. Consider as candidates only CMOVs in innermost loops (assume that +/// most hotspots are represented by these loops). +/// 2. Given a group of CMOV instructions that are using the same EFLAGS def /// instruction: -/// a. Consider them as candidates only if all have same code condition or -/// opposite one, to prevent generating more than one conditional jump -/// per EFLAGS def instruction. +/// a. Consider them as candidates only if all have the same code condition +/// or the opposite one to prevent generating more than one conditional +/// jump per EFLAGS def instruction. /// b. Consider them as candidates only if all are profitable to be -/// converted, assuming that one bad conversion may casue a degradation. -/// 3. Apply conversion only for loop that are found profitable and only for +/// converted (assume that one bad conversion may cause a degradation). +/// 3. Apply conversion only for loops that are found profitable and only for /// CMOV candidates that were found profitable. -/// a. Loop is considered profitable only if conversion will reduce its -/// depth cost by some thrishold. +/// a. A loop is considered profitable only if conversion will reduce its +/// depth cost by some threshold. /// b. CMOV is considered profitable if the cost of its condition is higher /// than the average cost of its true-value and false-value by 25% of -/// branch-misprediction-penalty, this to assure no degredassion even -/// with 25% branch misprediction. +/// branch-misprediction-penalty. This assures no degradation even with +/// 25% branch misprediction. /// /// Note: This pass is assumed to run on SSA machine code. +// //===----------------------------------------------------------------------===// // // External interfaces: // FunctionPass *llvm::createX86CmovConverterPass(); // bool X86CmovConverterPass::runOnMachineFunction(MachineFunction &MF); // +//===----------------------------------------------------------------------===// #include "X86.h" #include "X86InstrInfo.h" -#include "X86Subtarget.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineLoopInfo.h" +#include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" -#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/TargetInstrInfo.h" +#include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSchedule.h" -#include "llvm/IR/InstIterator.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/IR/DebugLoc.h" +#include "llvm/MC/MCSchedule.h" +#include "llvm/Pass.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <iterator> +#include <utility> + using namespace llvm; -#define DEBUG_TYPE "x86-cmov-converter" +#define DEBUG_TYPE "x86-cmov-conversion" STATISTIC(NumOfSkippedCmovGroups, "Number of unsupported CMOV-groups"); STATISTIC(NumOfCmovGroupCandidate, "Number of CMOV-group candidates"); STATISTIC(NumOfLoopCandidate, "Number of CMOV-conversion profitable loops"); STATISTIC(NumOfOptimizedCmovGroups, "Number of optimized CMOV-groups"); -namespace { +namespace llvm { + +void initializeX86CmovConverterPassPass(PassRegistry &); + +} // end namespace llvm + // This internal switch can be used to turn off the cmov/branch optimization. static cl::opt<bool> EnableCmovConverter("x86-cmov-converter", cl::desc("Enable the X86 cmov-to-branch optimization."), cl::init(true), cl::Hidden); +static cl::opt<unsigned> + GainCycleThreshold("x86-cmov-converter-threshold", + cl::desc("Minimum gain per loop (in cycles) threshold."), + cl::init(4), cl::Hidden); + +static cl::opt<bool> ForceMemOperand( + "x86-cmov-converter-force-mem-operand", + cl::desc("Convert cmovs to branches whenever they have memory operands."), + cl::init(true), cl::Hidden); + +namespace { + /// Converts X86 cmov instructions into branches when profitable. class X86CmovConverterPass : public MachineFunctionPass { public: - X86CmovConverterPass() : MachineFunctionPass(ID) {} - ~X86CmovConverterPass() {} + X86CmovConverterPass() : MachineFunctionPass(ID) { + initializeX86CmovConverterPassPass(*PassRegistry::getPassRegistry()); + } StringRef getPassName() const override { return "X86 cmov Conversion"; } bool runOnMachineFunction(MachineFunction &MF) override; void getAnalysisUsage(AnalysisUsage &AU) const override; -private: /// Pass identification, replacement for typeid. static char ID; - const MachineRegisterInfo *MRI; +private: + MachineRegisterInfo *MRI; const TargetInstrInfo *TII; + const TargetRegisterInfo *TRI; TargetSchedModel TSchedModel; /// List of consecutive CMOV instructions. - typedef SmallVector<MachineInstr *, 2> CmovGroup; - typedef SmallVector<CmovGroup, 2> CmovGroups; + using CmovGroup = SmallVector<MachineInstr *, 2>; + using CmovGroups = SmallVector<CmovGroup, 2>; /// Collect all CMOV-group-candidates in \p CurrLoop and update \p /// CmovInstGroups accordingly. /// - /// \param CurrLoop Loop being processed. + /// \param Blocks List of blocks to process. /// \param CmovInstGroups List of consecutive CMOV instructions in CurrLoop. /// \returns true iff it found any CMOV-group-candidate. - bool collectCmovCandidates(MachineLoop *CurrLoop, CmovGroups &CmovInstGroups); + bool collectCmovCandidates(ArrayRef<MachineBasicBlock *> Blocks, + CmovGroups &CmovInstGroups, + bool IncludeLoads = false); /// Check if it is profitable to transform each CMOV-group-candidates into /// branch. Remove all groups that are not profitable from \p CmovInstGroups. /// - /// \param CurrLoop Loop being processed. + /// \param Blocks List of blocks to process. /// \param CmovInstGroups List of consecutive CMOV instructions in CurrLoop. /// \returns true iff any CMOV-group-candidate remain. - bool checkForProfitableCmovCandidates(MachineLoop *CurrLoop, + bool checkForProfitableCmovCandidates(ArrayRef<MachineBasicBlock *> Blocks, CmovGroups &CmovInstGroups); /// Convert the given list of consecutive CMOV instructions into a branch. @@ -112,6 +154,8 @@ private: void convertCmovInstsToBranches(SmallVectorImpl<MachineInstr *> &Group) const; }; +} // end anonymous namespace + char X86CmovConverterPass::ID = 0; void X86CmovConverterPass::getAnalysisUsage(AnalysisUsage &AU) const { @@ -120,7 +164,7 @@ void X86CmovConverterPass::getAnalysisUsage(AnalysisUsage &AU) const { } bool X86CmovConverterPass::runOnMachineFunction(MachineFunction &MF) { - if (skipFunction(*MF.getFunction())) + if (skipFunction(MF.getFunction())) return false; if (!EnableCmovConverter) return false; @@ -133,10 +177,36 @@ bool X86CmovConverterPass::runOnMachineFunction(MachineFunction &MF) { const TargetSubtargetInfo &STI = MF.getSubtarget(); MRI = &MF.getRegInfo(); TII = STI.getInstrInfo(); + TRI = STI.getRegisterInfo(); TSchedModel.init(STI.getSchedModel(), &STI, TII); + // Before we handle the more subtle cases of register-register CMOVs inside + // of potentially hot loops, we want to quickly remove all CMOVs with + // a memory operand. The CMOV will risk a stall waiting for the load to + // complete that speculative execution behind a branch is better suited to + // handle on modern x86 chips. + if (ForceMemOperand) { + CmovGroups AllCmovGroups; + SmallVector<MachineBasicBlock *, 4> Blocks; + for (auto &MBB : MF) + Blocks.push_back(&MBB); + if (collectCmovCandidates(Blocks, AllCmovGroups, /*IncludeLoads*/ true)) { + for (auto &Group : AllCmovGroups) { + // Skip any group that doesn't do at least one memory operand cmov. + if (!llvm::any_of(Group, [&](MachineInstr *I) { return I->mayLoad(); })) + continue; + + // For CMOV groups which we can rewrite and which contain a memory load, + // always rewrite them. On x86, a CMOV will dramatically amplify any + // memory latency by blocking speculative execution. + Changed = true; + convertCmovInstsToBranches(Group); + } + } + } + //===--------------------------------------------------------------------===// - // Algorithm + // Register-operand Conversion Algorithm // --------- // For each inner most loop // collectCmovCandidates() { @@ -157,32 +227,41 @@ bool X86CmovConverterPass::runOnMachineFunction(MachineFunction &MF) { // // Note: For more details, see each function description. //===--------------------------------------------------------------------===// - for (MachineBasicBlock &MBB : MF) { - MachineLoop *CurrLoop = MLI.getLoopFor(&MBB); + // Build up the loops in pre-order. + SmallVector<MachineLoop *, 4> Loops(MLI.begin(), MLI.end()); + // Note that we need to check size on each iteration as we accumulate child + // loops. + for (int i = 0; i < (int)Loops.size(); ++i) + for (MachineLoop *Child : Loops[i]->getSubLoops()) + Loops.push_back(Child); + + for (MachineLoop *CurrLoop : Loops) { // Optimize only inner most loops. - if (!CurrLoop || CurrLoop->getHeader() != &MBB || - !CurrLoop->getSubLoops().empty()) + if (!CurrLoop->getSubLoops().empty()) continue; // List of consecutive CMOV instructions to be processed. CmovGroups CmovInstGroups; - if (!collectCmovCandidates(CurrLoop, CmovInstGroups)) + if (!collectCmovCandidates(CurrLoop->getBlocks(), CmovInstGroups)) continue; - if (!checkForProfitableCmovCandidates(CurrLoop, CmovInstGroups)) + if (!checkForProfitableCmovCandidates(CurrLoop->getBlocks(), + CmovInstGroups)) continue; Changed = true; for (auto &Group : CmovInstGroups) convertCmovInstsToBranches(Group); } + return Changed; } -bool X86CmovConverterPass::collectCmovCandidates(MachineLoop *CurrLoop, - CmovGroups &CmovInstGroups) { +bool X86CmovConverterPass::collectCmovCandidates( + ArrayRef<MachineBasicBlock *> Blocks, CmovGroups &CmovInstGroups, + bool IncludeLoads) { //===--------------------------------------------------------------------===// // Collect all CMOV-group-candidates and add them into CmovInstGroups. // @@ -204,24 +283,29 @@ bool X86CmovConverterPass::collectCmovCandidates(MachineLoop *CurrLoop, // Current processed CMOV-Group. CmovGroup Group; - for (auto *MBB : CurrLoop->getBlocks()) { + for (auto *MBB : Blocks) { Group.clear(); // Condition code of first CMOV instruction current processed range and its // opposite condition code. - X86::CondCode FirstCC, FirstOppCC; + X86::CondCode FirstCC, FirstOppCC, MemOpCC; // Indicator of a non CMOVrr instruction in the current processed range. bool FoundNonCMOVInst = false; // Indicator for current processed CMOV-group if it should be skipped. bool SkipGroup = false; for (auto &I : *MBB) { + // Skip debug instructions. + if (I.isDebugValue()) + continue; X86::CondCode CC = X86::getCondFromCMovOpc(I.getOpcode()); // Check if we found a X86::CMOVrr instruction. - if (CC != X86::COND_INVALID && !I.mayLoad()) { + if (CC != X86::COND_INVALID && (IncludeLoads || !I.mayLoad())) { if (Group.empty()) { // We found first CMOV in the range, reset flags. FirstCC = CC; FirstOppCC = X86::GetOppositeBranchCondition(CC); + // Clear out the prior group's memory operand CC. + MemOpCC = X86::COND_INVALID; FoundNonCMOVInst = false; SkipGroup = false; } @@ -231,6 +315,24 @@ bool X86CmovConverterPass::collectCmovCandidates(MachineLoop *CurrLoop, if (FoundNonCMOVInst || (CC != FirstCC && CC != FirstOppCC)) // Mark the SKipGroup indicator to skip current processed CMOV-Group. SkipGroup = true; + if (I.mayLoad()) { + if (MemOpCC == X86::COND_INVALID) + // The first memory operand CMOV. + MemOpCC = CC; + else if (CC != MemOpCC) + // Can't handle mixed conditions with memory operands. + SkipGroup = true; + } + // Check if we were relying on zero-extending behavior of the CMOV. + if (!SkipGroup && + llvm::any_of( + MRI->use_nodbg_instructions(I.defs().begin()->getReg()), + [&](MachineInstr &UseI) { + return UseI.getOpcode() == X86::SUBREG_TO_REG; + })) + // FIXME: We should model the cost of using an explicit MOV to handle + // the zero-extension rather than just refusing to handle this. + SkipGroup = true; continue; } // If Group is empty, keep looking for first CMOV in the range. @@ -278,7 +380,7 @@ static unsigned getDepthOfOptCmov(unsigned TrueOpDepth, unsigned FalseOpDepth) { } bool X86CmovConverterPass::checkForProfitableCmovCandidates( - MachineLoop *CurrLoop, CmovGroups &CmovInstGroups) { + ArrayRef<MachineBasicBlock *> Blocks, CmovGroups &CmovInstGroups) { struct DepthInfo { /// Depth of original loop. unsigned Depth; @@ -328,10 +430,13 @@ bool X86CmovConverterPass::checkForProfitableCmovCandidates( //===--------------------------------------------------------------------===// for (unsigned I = 0; I < LoopIterations; ++I) { DepthInfo &MaxDepth = LoopDepth[I]; - for (auto *MBB : CurrLoop->getBlocks()) { + for (auto *MBB : Blocks) { // Clear physical registers Def map. RegDefMaps[PhyRegType].clear(); for (MachineInstr &MI : *MBB) { + // Skip debug instructions. + if (MI.isDebugValue()) + continue; unsigned MIDepth = 0; unsigned MIDepthOpt = 0; bool IsCMOV = CmovInstructions.count(&MI); @@ -389,19 +494,28 @@ bool X86CmovConverterPass::checkForProfitableCmovCandidates( // Critical-path is iteration dependent - there is dependency of // critical-path instructions on critical-path instructions of // previous iteration. - // Thus, it is required to check the gradient of the gain - the - // change in Depth-Diff compared to the change in Loop-Depth between - // 1st and 2nd iterations. + // Thus, check the gain percent of the 2nd iteration (similar to the + // previous case), but it is also required to check the gradient of + // the gain - the change in Depth-Diff compared to the change in + // Loop-Depth between 1st and 2nd iterations. // To be conservative, the gradient need to be at least 50%. // + // In addition, In order not to optimize loops with very small gain, the + // gain (in cycles) after 2nd iteration should not be less than a given + // threshold. Thus, the check (Diff[1] >= GainCycleThreshold) must apply. + // // If loop is not worth optimizing, remove all CMOV-group-candidates. //===--------------------------------------------------------------------===// + if (Diff[1] < GainCycleThreshold) + return false; + bool WorthOptLoop = false; if (Diff[1] == Diff[0]) WorthOptLoop = Diff[0] * 8 >= LoopDepth[0].Depth; else if (Diff[1] > Diff[0]) WorthOptLoop = - (Diff[1] - Diff[0]) * 2 >= (LoopDepth[1].Depth - LoopDepth[0].Depth); + (Diff[1] - Diff[0]) * 2 >= (LoopDepth[1].Depth - LoopDepth[0].Depth) && + (Diff[1] * 8 >= LoopDepth[1].Depth); if (!WorthOptLoop) return false; @@ -481,11 +595,36 @@ static bool checkEFLAGSLive(MachineInstr *MI) { return false; } +/// Given /p First CMOV instruction and /p Last CMOV instruction representing a +/// group of CMOV instructions, which may contain debug instructions in between, +/// move all debug instructions to after the last CMOV instruction, making the +/// CMOV group consecutive. +static void packCmovGroup(MachineInstr *First, MachineInstr *Last) { + assert(X86::getCondFromCMovOpc(Last->getOpcode()) != X86::COND_INVALID && + "Last instruction in a CMOV group must be a CMOV instruction"); + + SmallVector<MachineInstr *, 2> DBGInstructions; + for (auto I = First->getIterator(), E = Last->getIterator(); I != E; I++) { + if (I->isDebugValue()) + DBGInstructions.push_back(&*I); + } + + // Splice the debug instruction after the cmov group. + MachineBasicBlock *MBB = First->getParent(); + for (auto *MI : DBGInstructions) + MBB->insertAfter(Last, MI->removeFromParent()); +} + void X86CmovConverterPass::convertCmovInstsToBranches( SmallVectorImpl<MachineInstr *> &Group) const { assert(!Group.empty() && "No CMOV instructions to convert"); ++NumOfOptimizedCmovGroups; + // If the CMOV group is not packed, e.g., there are debug instructions between + // first CMOV and last CMOV, then pack the group and make the CMOV instruction + // consecutive by moving the debug instructions to after the last CMOV. + packCmovGroup(Group.front(), Group.back()); + // To convert a CMOVcc instruction, we actually have to insert the diamond // control-flow pattern. The incoming instruction knows the destination vreg // to set, the condition code register to branch on, the true/false values to @@ -518,8 +657,18 @@ void X86CmovConverterPass::convertCmovInstsToBranches( MachineInstr &MI = *Group.front(); MachineInstr *LastCMOV = Group.back(); DebugLoc DL = MI.getDebugLoc(); + X86::CondCode CC = X86::CondCode(X86::getCondFromCMovOpc(MI.getOpcode())); X86::CondCode OppCC = X86::GetOppositeBranchCondition(CC); + // Potentially swap the condition codes so that any memory operand to a CMOV + // is in the *false* position instead of the *true* position. We can invert + // any non-memory operand CMOV instructions to cope with this and we ensure + // memory operand CMOVs are only included with a single condition code. + if (llvm::any_of(Group, [&](MachineInstr *I) { + return I->mayLoad() && X86::getCondFromCMovOpc(I->getOpcode()) == CC; + })) + std::swap(CC, OppCC); + MachineBasicBlock *MBB = MI.getParent(); MachineFunction::iterator It = ++MBB->getIterator(); MachineFunction *F = MBB->getParent(); @@ -556,7 +705,111 @@ void X86CmovConverterPass::convertCmovInstsToBranches( MachineBasicBlock::iterator MIItBegin = MachineBasicBlock::iterator(MI); MachineBasicBlock::iterator MIItEnd = std::next(MachineBasicBlock::iterator(LastCMOV)); + MachineBasicBlock::iterator FalseInsertionPoint = FalseMBB->begin(); MachineBasicBlock::iterator SinkInsertionPoint = SinkMBB->begin(); + + // First we need to insert an explicit load on the false path for any memory + // operand. We also need to potentially do register rewriting here, but it is + // simpler as the memory operands are always on the false path so we can + // simply take that input, whatever it is. + DenseMap<unsigned, unsigned> FalseBBRegRewriteTable; + for (MachineBasicBlock::iterator MIIt = MIItBegin; MIIt != MIItEnd;) { + auto &MI = *MIIt++; + // Skip any CMOVs in this group which don't load from memory. + if (!MI.mayLoad()) { + // Remember the false-side register input. + unsigned FalseReg = + MI.getOperand(X86::getCondFromCMovOpc(MI.getOpcode()) == CC ? 1 : 2) + .getReg(); + // Walk back through any intermediate cmovs referenced. + while (true) { + auto FRIt = FalseBBRegRewriteTable.find(FalseReg); + if (FRIt == FalseBBRegRewriteTable.end()) + break; + FalseReg = FRIt->second; + } + FalseBBRegRewriteTable[MI.getOperand(0).getReg()] = FalseReg; + continue; + } + + // The condition must be the *opposite* of the one we've decided to branch + // on as the branch will go *around* the load and the load should happen + // when the CMOV condition is false. + assert(X86::getCondFromCMovOpc(MI.getOpcode()) == OppCC && + "Can only handle memory-operand cmov instructions with a condition " + "opposite to the selected branch direction."); + + // The goal is to rewrite the cmov from: + // + // MBB: + // %A = CMOVcc %B (tied), (mem) + // + // to + // + // MBB: + // %A = CMOVcc %B (tied), %C + // FalseMBB: + // %C = MOV (mem) + // + // Which will allow the next loop to rewrite the CMOV in terms of a PHI: + // + // MBB: + // JMP!cc SinkMBB + // FalseMBB: + // %C = MOV (mem) + // SinkMBB: + // %A = PHI [ %C, FalseMBB ], [ %B, MBB] + + // Get a fresh register to use as the destination of the MOV. + const TargetRegisterClass *RC = MRI->getRegClass(MI.getOperand(0).getReg()); + unsigned TmpReg = MRI->createVirtualRegister(RC); + + SmallVector<MachineInstr *, 4> NewMIs; + bool Unfolded = TII->unfoldMemoryOperand(*MBB->getParent(), MI, TmpReg, + /*UnfoldLoad*/ true, + /*UnfoldStore*/ false, NewMIs); + (void)Unfolded; + assert(Unfolded && "Should never fail to unfold a loading cmov!"); + + // Move the new CMOV to just before the old one and reset any impacted + // iterator. + auto *NewCMOV = NewMIs.pop_back_val(); + assert(X86::getCondFromCMovOpc(NewCMOV->getOpcode()) == OppCC && + "Last new instruction isn't the expected CMOV!"); + DEBUG(dbgs() << "\tRewritten cmov: "; NewCMOV->dump()); + MBB->insert(MachineBasicBlock::iterator(MI), NewCMOV); + if (&*MIItBegin == &MI) + MIItBegin = MachineBasicBlock::iterator(NewCMOV); + + // Sink whatever instructions were needed to produce the unfolded operand + // into the false block. + for (auto *NewMI : NewMIs) { + DEBUG(dbgs() << "\tRewritten load instr: "; NewMI->dump()); + FalseMBB->insert(FalseInsertionPoint, NewMI); + // Re-map any operands that are from other cmovs to the inputs for this block. + for (auto &MOp : NewMI->uses()) { + if (!MOp.isReg()) + continue; + auto It = FalseBBRegRewriteTable.find(MOp.getReg()); + if (It == FalseBBRegRewriteTable.end()) + continue; + + MOp.setReg(It->second); + // This might have been a kill when it referenced the cmov result, but + // it won't necessarily be once rewritten. + // FIXME: We could potentially improve this by tracking whether the + // operand to the cmov was also a kill, and then skipping the PHI node + // construction below. + MOp.setIsKill(false); + } + } + MBB->erase(MachineBasicBlock::iterator(MI), + std::next(MachineBasicBlock::iterator(MI))); + + // Add this PHI to the rewrite table. + FalseBBRegRewriteTable[NewCMOV->getOperand(0).getReg()] = TmpReg; + } + // As we are creating the PHIs, we have to be careful if there is more than // one. Later CMOVs may reference the results of earlier CMOVs, but later // PHIs have to reference the individual true/false inputs from earlier PHIs. @@ -604,7 +857,11 @@ void X86CmovConverterPass::convertCmovInstsToBranches( MBB->erase(MIItBegin, MIItEnd); } -} // End anonymous namespace. +INITIALIZE_PASS_BEGIN(X86CmovConverterPass, DEBUG_TYPE, "X86 cmov Conversion", + false, false) +INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo) +INITIALIZE_PASS_END(X86CmovConverterPass, DEBUG_TYPE, "X86 cmov Conversion", + false, false) FunctionPass *llvm::createX86CmovConverterPass() { return new X86CmovConverterPass(); |
