forked from OSchip/llvm-project
585 lines
19 KiB
C++
585 lines
19 KiB
C++
//===---- X86CondBrFolding.cpp - optimize conditional branches ------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
// This file defines a pass that optimizes condition branches on x86 by taking
|
|
// advantage of the three-way conditional code generated by compare
|
|
// instructions.
|
|
// Currently, it tries to hoisting EQ and NE conditional branch to a dominant
|
|
// conditional branch condition where the same EQ/NE conditional code is
|
|
// computed. An example:
|
|
// bb_0:
|
|
// cmp %0, 19
|
|
// jg bb_1
|
|
// jmp bb_2
|
|
// bb_1:
|
|
// cmp %0, 40
|
|
// jg bb_3
|
|
// jmp bb_4
|
|
// bb_4:
|
|
// cmp %0, 20
|
|
// je bb_5
|
|
// jmp bb_6
|
|
// Here we could combine the two compares in bb_0 and bb_4 and have the
|
|
// following code:
|
|
// bb_0:
|
|
// cmp %0, 20
|
|
// jg bb_1
|
|
// jl bb_2
|
|
// jmp bb_5
|
|
// bb_1:
|
|
// cmp %0, 40
|
|
// jg bb_3
|
|
// jmp bb_6
|
|
// For the case of %0 == 20 (bb_5), we eliminate two jumps, and the control
|
|
// height for bb_6 is also reduced. bb_4 is gone after the optimization.
|
|
//
|
|
// There are plenty of this code patterns, especially from the switch case
|
|
// lowing where we generate compare of "pivot-1" for the inner nodes in the
|
|
// binary search tree.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "X86.h"
|
|
#include "X86InstrInfo.h"
|
|
#include "X86Subtarget.h"
|
|
#include "llvm/ADT/Statistic.h"
|
|
#include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
|
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
#include "llvm/Support/BranchProbability.h"
|
|
|
|
using namespace llvm;
|
|
|
|
#define DEBUG_TYPE "x86-condbr-folding"
|
|
|
|
STATISTIC(NumFixedCondBrs, "Number of x86 condbr folded");
|
|
|
|
namespace {
|
|
class X86CondBrFoldingPass : public MachineFunctionPass {
|
|
public:
|
|
X86CondBrFoldingPass() : MachineFunctionPass(ID) {
|
|
initializeX86CondBrFoldingPassPass(*PassRegistry::getPassRegistry());
|
|
}
|
|
StringRef getPassName() const override { return "X86 CondBr Folding"; }
|
|
|
|
bool runOnMachineFunction(MachineFunction &MF) override;
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
MachineFunctionPass::getAnalysisUsage(AU);
|
|
AU.addRequired<MachineBranchProbabilityInfo>();
|
|
}
|
|
|
|
public:
|
|
static char ID;
|
|
};
|
|
} // namespace
|
|
|
|
char X86CondBrFoldingPass::ID = 0;
|
|
INITIALIZE_PASS(X86CondBrFoldingPass, "X86CondBrFolding", "X86CondBrFolding", false, false)
|
|
|
|
FunctionPass *llvm::createX86CondBrFolding() {
|
|
return new X86CondBrFoldingPass();
|
|
}
|
|
|
|
namespace {
|
|
// A class the stores the auxiliary information for each MBB.
|
|
struct TargetMBBInfo {
|
|
MachineBasicBlock *TBB;
|
|
MachineBasicBlock *FBB;
|
|
MachineInstr *BrInstr;
|
|
MachineInstr *CmpInstr;
|
|
X86::CondCode BranchCode;
|
|
unsigned SrcReg;
|
|
int CmpValue;
|
|
bool Modified;
|
|
bool CmpBrOnly;
|
|
};
|
|
|
|
// A class that optimizes the conditional branch by hoisting and merge CondCode.
|
|
class X86CondBrFolding {
|
|
public:
|
|
X86CondBrFolding(const X86InstrInfo *TII,
|
|
const MachineBranchProbabilityInfo *MBPI,
|
|
MachineFunction &MF)
|
|
: TII(TII), MBPI(MBPI), MF(MF) {}
|
|
bool optimize();
|
|
|
|
private:
|
|
const X86InstrInfo *TII;
|
|
const MachineBranchProbabilityInfo *MBPI;
|
|
MachineFunction &MF;
|
|
std::vector<std::unique_ptr<TargetMBBInfo>> MBBInfos;
|
|
SmallVector<MachineBasicBlock *, 4> RemoveList;
|
|
|
|
void optimizeCondBr(MachineBasicBlock &MBB,
|
|
SmallVectorImpl<MachineBasicBlock *> &BranchPath);
|
|
void fixBranchProb(MachineBasicBlock *NextMBB, MachineBasicBlock *RootMBB,
|
|
SmallVectorImpl<MachineBasicBlock *> &BranchPath);
|
|
void replaceBrDest(MachineBasicBlock *MBB, MachineBasicBlock *OrigDest,
|
|
MachineBasicBlock *NewDest);
|
|
void fixupModifiedCond(MachineBasicBlock *MBB);
|
|
std::unique_ptr<TargetMBBInfo> analyzeMBB(MachineBasicBlock &MBB);
|
|
static bool analyzeCompare(const MachineInstr &MI, unsigned &SrcReg,
|
|
int &CmpValue);
|
|
bool findPath(MachineBasicBlock *MBB,
|
|
SmallVectorImpl<MachineBasicBlock *> &BranchPath);
|
|
TargetMBBInfo *getMBBInfo(MachineBasicBlock *MBB) const {
|
|
return MBBInfos[MBB->getNumber()].get();
|
|
}
|
|
};
|
|
} // namespace
|
|
|
|
// Find a valid path that we can reuse the CondCode.
|
|
// The resulted path (if return true) is stored in BranchPath.
|
|
// Return value:
|
|
// false: is no valid path is found.
|
|
// true: a valid path is found and the targetBB can be reached.
|
|
bool X86CondBrFolding::findPath(
|
|
MachineBasicBlock *MBB, SmallVectorImpl<MachineBasicBlock *> &BranchPath) {
|
|
TargetMBBInfo *MBBInfo = getMBBInfo(MBB);
|
|
assert(MBBInfo && "Expecting a candidate MBB");
|
|
int CmpValue = MBBInfo->CmpValue;
|
|
|
|
MachineBasicBlock *PredMBB = *MBB->pred_begin();
|
|
MachineBasicBlock *SaveMBB = MBB;
|
|
while (PredMBB) {
|
|
TargetMBBInfo *PredMBBInfo = getMBBInfo(PredMBB);
|
|
if (!PredMBBInfo || PredMBBInfo->SrcReg != MBBInfo->SrcReg)
|
|
return false;
|
|
|
|
assert(SaveMBB == PredMBBInfo->TBB || SaveMBB == PredMBBInfo->FBB);
|
|
bool IsFalseBranch = (SaveMBB == PredMBBInfo->FBB);
|
|
|
|
X86::CondCode CC = PredMBBInfo->BranchCode;
|
|
assert(CC == X86::COND_L || CC == X86::COND_G || CC == X86::COND_E);
|
|
int PredCmpValue = PredMBBInfo->CmpValue;
|
|
bool ValueCmpTrue = ((CmpValue < PredCmpValue && CC == X86::COND_L) ||
|
|
(CmpValue > PredCmpValue && CC == X86::COND_G) ||
|
|
(CmpValue == PredCmpValue && CC == X86::COND_E));
|
|
// Check if both the result of value compare and the branch target match.
|
|
if (!(ValueCmpTrue ^ IsFalseBranch)) {
|
|
LLVM_DEBUG(dbgs() << "Dead BB detected!\n");
|
|
return false;
|
|
}
|
|
|
|
BranchPath.push_back(PredMBB);
|
|
// These are the conditions on which we could combine the compares.
|
|
if ((CmpValue == PredCmpValue) ||
|
|
(CmpValue == PredCmpValue - 1 && CC == X86::COND_L) ||
|
|
(CmpValue == PredCmpValue + 1 && CC == X86::COND_G))
|
|
return true;
|
|
|
|
// If PredMBB has more than on preds, or not a pure cmp and br, we bailout.
|
|
if (PredMBB->pred_size() != 1 || !PredMBBInfo->CmpBrOnly)
|
|
return false;
|
|
|
|
SaveMBB = PredMBB;
|
|
PredMBB = *PredMBB->pred_begin();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Fix up any PHI node in the successor of MBB.
|
|
static void fixPHIsInSucc(MachineBasicBlock *MBB, MachineBasicBlock *OldMBB,
|
|
MachineBasicBlock *NewMBB) {
|
|
if (NewMBB == OldMBB)
|
|
return;
|
|
for (auto MI = MBB->instr_begin(), ME = MBB->instr_end();
|
|
MI != ME && MI->isPHI(); ++MI)
|
|
for (unsigned i = 2, e = MI->getNumOperands() + 1; i != e; i += 2) {
|
|
MachineOperand &MO = MI->getOperand(i);
|
|
if (MO.getMBB() == OldMBB)
|
|
MO.setMBB(NewMBB);
|
|
}
|
|
}
|
|
|
|
// Utility function to set branch probability for edge MBB->SuccMBB.
|
|
static inline bool setBranchProb(MachineBasicBlock *MBB,
|
|
MachineBasicBlock *SuccMBB,
|
|
BranchProbability Prob) {
|
|
auto MBBI = std::find(MBB->succ_begin(), MBB->succ_end(), SuccMBB);
|
|
if (MBBI == MBB->succ_end())
|
|
return false;
|
|
MBB->setSuccProbability(MBBI, Prob);
|
|
return true;
|
|
}
|
|
|
|
// Utility function to find the unconditional br instruction in MBB.
|
|
static inline MachineBasicBlock::iterator
|
|
findUncondBrI(MachineBasicBlock *MBB) {
|
|
return std::find_if(MBB->begin(), MBB->end(), [](MachineInstr &MI) -> bool {
|
|
return MI.getOpcode() == X86::JMP_1;
|
|
});
|
|
}
|
|
|
|
// Replace MBB's original successor, OrigDest, with NewDest.
|
|
// Also update the MBBInfo for MBB.
|
|
void X86CondBrFolding::replaceBrDest(MachineBasicBlock *MBB,
|
|
MachineBasicBlock *OrigDest,
|
|
MachineBasicBlock *NewDest) {
|
|
TargetMBBInfo *MBBInfo = getMBBInfo(MBB);
|
|
MachineInstr *BrMI;
|
|
if (MBBInfo->TBB == OrigDest) {
|
|
BrMI = MBBInfo->BrInstr;
|
|
unsigned JNCC = GetCondBranchFromCond(MBBInfo->BranchCode);
|
|
MachineInstrBuilder MIB =
|
|
BuildMI(*MBB, BrMI, MBB->findDebugLoc(BrMI), TII->get(JNCC))
|
|
.addMBB(NewDest);
|
|
MBBInfo->TBB = NewDest;
|
|
MBBInfo->BrInstr = MIB.getInstr();
|
|
} else { // Should be the unconditional jump stmt.
|
|
MachineBasicBlock::iterator UncondBrI = findUncondBrI(MBB);
|
|
BuildMI(*MBB, UncondBrI, MBB->findDebugLoc(UncondBrI), TII->get(X86::JMP_1))
|
|
.addMBB(NewDest);
|
|
MBBInfo->FBB = NewDest;
|
|
BrMI = &*UncondBrI;
|
|
}
|
|
fixPHIsInSucc(NewDest, OrigDest, MBB);
|
|
BrMI->eraseFromParent();
|
|
MBB->addSuccessor(NewDest);
|
|
setBranchProb(MBB, NewDest, MBPI->getEdgeProbability(MBB, OrigDest));
|
|
MBB->removeSuccessor(OrigDest);
|
|
}
|
|
|
|
// Change the CondCode and BrInstr according to MBBInfo.
|
|
void X86CondBrFolding::fixupModifiedCond(MachineBasicBlock *MBB) {
|
|
TargetMBBInfo *MBBInfo = getMBBInfo(MBB);
|
|
if (!MBBInfo->Modified)
|
|
return;
|
|
|
|
MachineInstr *BrMI = MBBInfo->BrInstr;
|
|
X86::CondCode CC = MBBInfo->BranchCode;
|
|
MachineInstrBuilder MIB = BuildMI(*MBB, BrMI, MBB->findDebugLoc(BrMI),
|
|
TII->get(GetCondBranchFromCond(CC)))
|
|
.addMBB(MBBInfo->TBB);
|
|
BrMI->eraseFromParent();
|
|
MBBInfo->BrInstr = MIB.getInstr();
|
|
|
|
MachineBasicBlock::iterator UncondBrI = findUncondBrI(MBB);
|
|
BuildMI(*MBB, UncondBrI, MBB->findDebugLoc(UncondBrI), TII->get(X86::JMP_1))
|
|
.addMBB(MBBInfo->FBB);
|
|
MBB->erase(UncondBrI);
|
|
MBBInfo->Modified = false;
|
|
}
|
|
|
|
//
|
|
// Apply the transformation:
|
|
// RootMBB -1-> ... PredMBB -3-> MBB -5-> TargetMBB
|
|
// \-2-> \-4-> \-6-> FalseMBB
|
|
// ==>
|
|
// RootMBB -1-> ... PredMBB -7-> FalseMBB
|
|
// TargetMBB <-8-/ \-2-> \-4->
|
|
//
|
|
// Note that PredMBB and RootMBB could be the same.
|
|
// And in the case of dead TargetMBB, we will not have TargetMBB and edge 8.
|
|
//
|
|
// There are some special handling where the RootMBB is COND_E in which case
|
|
// we directly short-cycle the brinstr.
|
|
//
|
|
void X86CondBrFolding::optimizeCondBr(
|
|
MachineBasicBlock &MBB, SmallVectorImpl<MachineBasicBlock *> &BranchPath) {
|
|
|
|
X86::CondCode CC;
|
|
TargetMBBInfo *MBBInfo = getMBBInfo(&MBB);
|
|
assert(MBBInfo && "Expecting a candidate MBB");
|
|
MachineBasicBlock *TargetMBB = MBBInfo->TBB;
|
|
BranchProbability TargetProb = MBPI->getEdgeProbability(&MBB, MBBInfo->TBB);
|
|
|
|
// Forward the jump from MBB's predecessor to MBB's false target.
|
|
MachineBasicBlock *PredMBB = BranchPath.front();
|
|
TargetMBBInfo *PredMBBInfo = getMBBInfo(PredMBB);
|
|
assert(PredMBBInfo && "Expecting a candidate MBB");
|
|
if (PredMBBInfo->Modified)
|
|
fixupModifiedCond(PredMBB);
|
|
CC = PredMBBInfo->BranchCode;
|
|
// Don't do this if depth of BranchPath is 1 and PredMBB is of COND_E.
|
|
// We will short-cycle directly for this case.
|
|
if (!(CC == X86::COND_E && BranchPath.size() == 1))
|
|
replaceBrDest(PredMBB, &MBB, MBBInfo->FBB);
|
|
|
|
MachineBasicBlock *RootMBB = BranchPath.back();
|
|
TargetMBBInfo *RootMBBInfo = getMBBInfo(RootMBB);
|
|
assert(RootMBBInfo && "Expecting a candidate MBB");
|
|
if (RootMBBInfo->Modified)
|
|
fixupModifiedCond(RootMBB);
|
|
CC = RootMBBInfo->BranchCode;
|
|
|
|
if (CC != X86::COND_E) {
|
|
MachineBasicBlock::iterator UncondBrI = findUncondBrI(RootMBB);
|
|
// RootMBB: Cond jump to the original not-taken MBB.
|
|
X86::CondCode NewCC;
|
|
switch (CC) {
|
|
case X86::COND_L:
|
|
NewCC = X86::COND_G;
|
|
break;
|
|
case X86::COND_G:
|
|
NewCC = X86::COND_L;
|
|
break;
|
|
default:
|
|
llvm_unreachable("unexpected condtional code.");
|
|
}
|
|
BuildMI(*RootMBB, UncondBrI, RootMBB->findDebugLoc(UncondBrI),
|
|
TII->get(GetCondBranchFromCond(NewCC)))
|
|
.addMBB(RootMBBInfo->FBB);
|
|
|
|
// RootMBB: Jump to TargetMBB
|
|
BuildMI(*RootMBB, UncondBrI, RootMBB->findDebugLoc(UncondBrI),
|
|
TII->get(X86::JMP_1))
|
|
.addMBB(TargetMBB);
|
|
RootMBB->addSuccessor(TargetMBB);
|
|
fixPHIsInSucc(TargetMBB, &MBB, RootMBB);
|
|
RootMBB->erase(UncondBrI);
|
|
} else {
|
|
replaceBrDest(RootMBB, RootMBBInfo->TBB, TargetMBB);
|
|
}
|
|
|
|
// Fix RootMBB's CmpValue to MBB's CmpValue to TargetMBB. Don't set Imm
|
|
// directly. Move MBB's stmt to here as the opcode might be different.
|
|
if (RootMBBInfo->CmpValue != MBBInfo->CmpValue) {
|
|
MachineInstr *NewCmp = MBBInfo->CmpInstr;
|
|
NewCmp->removeFromParent();
|
|
RootMBB->insert(RootMBBInfo->CmpInstr, NewCmp);
|
|
RootMBBInfo->CmpInstr->eraseFromParent();
|
|
}
|
|
|
|
// Fix branch Probabilities.
|
|
auto fixBranchProb = [&](MachineBasicBlock *NextMBB) {
|
|
BranchProbability Prob;
|
|
for (auto &I : BranchPath) {
|
|
MachineBasicBlock *ThisMBB = I;
|
|
if (!ThisMBB->hasSuccessorProbabilities() ||
|
|
!ThisMBB->isSuccessor(NextMBB))
|
|
break;
|
|
Prob = MBPI->getEdgeProbability(ThisMBB, NextMBB);
|
|
if (Prob.isUnknown())
|
|
break;
|
|
TargetProb = Prob * TargetProb;
|
|
Prob = Prob - TargetProb;
|
|
setBranchProb(ThisMBB, NextMBB, Prob);
|
|
if (ThisMBB == RootMBB) {
|
|
setBranchProb(ThisMBB, TargetMBB, TargetProb);
|
|
}
|
|
ThisMBB->normalizeSuccProbs();
|
|
if (ThisMBB == RootMBB)
|
|
break;
|
|
NextMBB = ThisMBB;
|
|
}
|
|
return true;
|
|
};
|
|
if (CC != X86::COND_E && !TargetProb.isUnknown())
|
|
fixBranchProb(MBBInfo->FBB);
|
|
|
|
if (CC != X86::COND_E)
|
|
RemoveList.push_back(&MBB);
|
|
|
|
// Invalidate MBBInfo just in case.
|
|
MBBInfos[MBB.getNumber()] = nullptr;
|
|
MBBInfos[RootMBB->getNumber()] = nullptr;
|
|
|
|
LLVM_DEBUG(dbgs() << "After optimization:\nRootMBB is: " << *RootMBB << "\n");
|
|
if (BranchPath.size() > 1)
|
|
LLVM_DEBUG(dbgs() << "PredMBB is: " << *(BranchPath[0]) << "\n");
|
|
}
|
|
|
|
// Driver function for optimization: find the valid candidate and apply
|
|
// the transformation.
|
|
bool X86CondBrFolding::optimize() {
|
|
bool Changed = false;
|
|
LLVM_DEBUG(dbgs() << "***** X86CondBr Folding on Function: " << MF.getName()
|
|
<< " *****\n");
|
|
// Setup data structures.
|
|
MBBInfos.resize(MF.getNumBlockIDs());
|
|
for (auto &MBB : MF)
|
|
MBBInfos[MBB.getNumber()] = analyzeMBB(MBB);
|
|
|
|
for (auto &MBB : MF) {
|
|
TargetMBBInfo *MBBInfo = getMBBInfo(&MBB);
|
|
if (!MBBInfo || !MBBInfo->CmpBrOnly)
|
|
continue;
|
|
if (MBB.pred_size() != 1)
|
|
continue;
|
|
LLVM_DEBUG(dbgs() << "Work on MBB." << MBB.getNumber()
|
|
<< " CmpValue: " << MBBInfo->CmpValue << "\n");
|
|
SmallVector<MachineBasicBlock *, 4> BranchPath;
|
|
if (!findPath(&MBB, BranchPath))
|
|
continue;
|
|
|
|
#ifndef NDEBUG
|
|
LLVM_DEBUG(dbgs() << "Found one path (len=" << BranchPath.size() << "):\n");
|
|
int Index = 1;
|
|
LLVM_DEBUG(dbgs() << "Target MBB is: " << MBB << "\n");
|
|
for (auto I = BranchPath.rbegin(); I != BranchPath.rend(); ++I, ++Index) {
|
|
MachineBasicBlock *PMBB = *I;
|
|
TargetMBBInfo *PMBBInfo = getMBBInfo(PMBB);
|
|
LLVM_DEBUG(dbgs() << "Path MBB (" << Index << " of " << BranchPath.size()
|
|
<< ") is " << *PMBB);
|
|
LLVM_DEBUG(dbgs() << "CC=" << PMBBInfo->BranchCode
|
|
<< " Val=" << PMBBInfo->CmpValue
|
|
<< " CmpBrOnly=" << PMBBInfo->CmpBrOnly << "\n\n");
|
|
}
|
|
#endif
|
|
optimizeCondBr(MBB, BranchPath);
|
|
Changed = true;
|
|
}
|
|
NumFixedCondBrs += RemoveList.size();
|
|
for (auto MBBI : RemoveList) {
|
|
while (!MBBI->succ_empty())
|
|
MBBI->removeSuccessor(MBBI->succ_end() - 1);
|
|
|
|
MBBI->eraseFromParent();
|
|
}
|
|
|
|
return Changed;
|
|
}
|
|
|
|
// Analyze instructions that generate CondCode and extract information.
|
|
bool X86CondBrFolding::analyzeCompare(const MachineInstr &MI, unsigned &SrcReg,
|
|
int &CmpValue) {
|
|
unsigned SrcRegIndex = 0;
|
|
unsigned ValueIndex = 0;
|
|
switch (MI.getOpcode()) {
|
|
// TODO: handle test instructions.
|
|
default:
|
|
return false;
|
|
case X86::CMP64ri32:
|
|
case X86::CMP64ri8:
|
|
case X86::CMP32ri:
|
|
case X86::CMP32ri8:
|
|
case X86::CMP16ri:
|
|
case X86::CMP16ri8:
|
|
case X86::CMP8ri:
|
|
SrcRegIndex = 0;
|
|
ValueIndex = 1;
|
|
break;
|
|
case X86::SUB64ri32:
|
|
case X86::SUB64ri8:
|
|
case X86::SUB32ri:
|
|
case X86::SUB32ri8:
|
|
case X86::SUB16ri:
|
|
case X86::SUB16ri8:
|
|
case X86::SUB8ri:
|
|
SrcRegIndex = 1;
|
|
ValueIndex = 2;
|
|
break;
|
|
}
|
|
SrcReg = MI.getOperand(SrcRegIndex).getReg();
|
|
if (!MI.getOperand(ValueIndex).isImm())
|
|
return false;
|
|
CmpValue = MI.getOperand(ValueIndex).getImm();
|
|
return true;
|
|
}
|
|
|
|
// Analyze a candidate MBB and set the extract all the information needed.
|
|
// The valid candidate will have two successors.
|
|
// It also should have a sequence of
|
|
// Branch_instr,
|
|
// CondBr,
|
|
// UnCondBr.
|
|
// Return TargetMBBInfo if MBB is a valid candidate and nullptr otherwise.
|
|
std::unique_ptr<TargetMBBInfo>
|
|
X86CondBrFolding::analyzeMBB(MachineBasicBlock &MBB) {
|
|
MachineBasicBlock *TBB;
|
|
MachineBasicBlock *FBB;
|
|
MachineInstr *BrInstr;
|
|
MachineInstr *CmpInstr;
|
|
X86::CondCode CC;
|
|
unsigned SrcReg;
|
|
int CmpValue;
|
|
bool Modified;
|
|
bool CmpBrOnly;
|
|
|
|
if (MBB.succ_size() != 2)
|
|
return nullptr;
|
|
|
|
CmpBrOnly = true;
|
|
FBB = TBB = nullptr;
|
|
CmpInstr = nullptr;
|
|
MachineBasicBlock::iterator I = MBB.end();
|
|
while (I != MBB.begin()) {
|
|
--I;
|
|
if (I->isDebugValue())
|
|
continue;
|
|
if (I->getOpcode() == X86::JMP_1) {
|
|
if (FBB)
|
|
return nullptr;
|
|
FBB = I->getOperand(0).getMBB();
|
|
continue;
|
|
}
|
|
if (I->isBranch()) {
|
|
if (TBB)
|
|
return nullptr;
|
|
CC = X86::getCondFromBranchOpc(I->getOpcode());
|
|
switch (CC) {
|
|
default:
|
|
return nullptr;
|
|
case X86::COND_E:
|
|
case X86::COND_L:
|
|
case X86::COND_G:
|
|
case X86::COND_NE:
|
|
case X86::COND_LE:
|
|
case X86::COND_GE:
|
|
break;
|
|
}
|
|
TBB = I->getOperand(0).getMBB();
|
|
BrInstr = &*I;
|
|
continue;
|
|
}
|
|
if (analyzeCompare(*I, SrcReg, CmpValue)) {
|
|
if (CmpInstr)
|
|
return nullptr;
|
|
CmpInstr = &*I;
|
|
continue;
|
|
}
|
|
CmpBrOnly = false;
|
|
break;
|
|
}
|
|
|
|
if (!TBB || !FBB || !CmpInstr)
|
|
return nullptr;
|
|
|
|
// Simplify CondCode. Note this is only to simplify the findPath logic
|
|
// and will not change the instruction here.
|
|
switch (CC) {
|
|
case X86::COND_NE:
|
|
CC = X86::COND_E;
|
|
std::swap(TBB, FBB);
|
|
Modified = true;
|
|
break;
|
|
case X86::COND_LE:
|
|
if (CmpValue == INT_MAX)
|
|
return nullptr;
|
|
CC = X86::COND_L;
|
|
CmpValue += 1;
|
|
Modified = true;
|
|
break;
|
|
case X86::COND_GE:
|
|
if (CmpValue == INT_MIN)
|
|
return nullptr;
|
|
CC = X86::COND_G;
|
|
CmpValue -= 1;
|
|
Modified = true;
|
|
break;
|
|
default:
|
|
Modified = false;
|
|
break;
|
|
}
|
|
return llvm::make_unique<TargetMBBInfo>(TargetMBBInfo{
|
|
TBB, FBB, BrInstr, CmpInstr, CC, SrcReg, CmpValue, Modified, CmpBrOnly});
|
|
}
|
|
|
|
bool X86CondBrFoldingPass::runOnMachineFunction(MachineFunction &MF) {
|
|
const X86Subtarget &ST = MF.getSubtarget<X86Subtarget>();
|
|
if (!ST.threewayBranchProfitable())
|
|
return false;
|
|
const X86InstrInfo *TII = ST.getInstrInfo();
|
|
const MachineBranchProbabilityInfo *MBPI =
|
|
&getAnalysis<MachineBranchProbabilityInfo>();
|
|
|
|
X86CondBrFolding CondBr(TII, MBPI, MF);
|
|
return CondBr.optimize();
|
|
}
|