#include "AArch64.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/MachineTraceMetrics.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/InitializePasses.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
#define DEBUG_TYPE "aarch64-ccmp"
static cl::opt<unsigned> BlockInstrLimit(
"aarch64-ccmp-limit", cl::init(30), cl::Hidden,
cl::desc("Maximum number of instructions per speculated block."));
static cl::opt<bool> Stress("aarch64-stress-ccmp", cl::Hidden,
cl::desc("Turn all knobs to 11"));
STATISTIC(NumConsidered, "Number of ccmps considered");
STATISTIC(NumPhiRejs, "Number of ccmps rejected (PHI)");
STATISTIC(NumPhysRejs, "Number of ccmps rejected (Physregs)");
STATISTIC(NumPhi2Rejs, "Number of ccmps rejected (PHI2)");
STATISTIC(NumHeadBranchRejs, "Number of ccmps rejected (Head branch)");
STATISTIC(NumCmpBranchRejs, "Number of ccmps rejected (CmpBB branch)");
STATISTIC(NumCmpTermRejs, "Number of ccmps rejected (CmpBB is cbz...)");
STATISTIC(NumImmRangeRejs, "Number of ccmps rejected (Imm out of range)");
STATISTIC(NumLiveDstRejs, "Number of ccmps rejected (Cmp dest live)");
STATISTIC(NumMultNZCVUses, "Number of ccmps rejected (NZCV used)");
STATISTIC(NumUnknNZCVDefs, "Number of ccmps rejected (NZCV def unknown)");
STATISTIC(NumSpeculateRejs, "Number of ccmps rejected (Can't speculate)");
STATISTIC(NumConverted, "Number of ccmp instructions created");
STATISTIC(NumCompBranches, "Number of cbz/cbnz branches converted");
namespace {
class SSACCmpConv {
MachineFunction *MF;
const TargetInstrInfo *TII;
const TargetRegisterInfo *TRI;
MachineRegisterInfo *MRI;
const MachineBranchProbabilityInfo *MBPI;
public:
MachineBasicBlock *Head;
MachineBasicBlock *CmpBB;
MachineBasicBlock *Tail;
MachineInstr *CmpMI;
private:
SmallVector<MachineOperand, 4> HeadCond;
AArch64CC::CondCode HeadCmpBBCC;
SmallVector<MachineOperand, 4> CmpBBCond;
AArch64CC::CondCode CmpBBTailCC;
bool trivialTailPHIs();
void updateTailPHIs();
bool isDeadDef(unsigned DstReg);
MachineInstr *findConvertibleCompare(MachineBasicBlock *MBB);
bool canSpeculateInstrs(MachineBasicBlock *MBB, const MachineInstr *CmpMI);
public:
void runOnMachineFunction(MachineFunction &MF,
const MachineBranchProbabilityInfo *MBPI) {
this->MF = &MF;
this->MBPI = MBPI;
TII = MF.getSubtarget().getInstrInfo();
TRI = MF.getSubtarget().getRegisterInfo();
MRI = &MF.getRegInfo();
}
bool canConvert(MachineBasicBlock *MBB);
void convert(SmallVectorImpl<MachineBasicBlock *> &RemovedBlocks);
int expectedCodeSizeDelta() const;
};
}
bool SSACCmpConv::trivialTailPHIs() {
for (auto &I : *Tail) {
if (!I.isPHI())
break;
unsigned HeadReg = 0, CmpBBReg = 0;
for (unsigned oi = 1, oe = I.getNumOperands(); oi != oe; oi += 2) {
MachineBasicBlock *MBB = I.getOperand(oi + 1).getMBB();
Register Reg = I.getOperand(oi).getReg();
if (MBB == Head) {
assert((!HeadReg || HeadReg == Reg) && "Inconsistent PHI operands");
HeadReg = Reg;
}
if (MBB == CmpBB) {
assert((!CmpBBReg || CmpBBReg == Reg) && "Inconsistent PHI operands");
CmpBBReg = Reg;
}
}
if (HeadReg != CmpBBReg)
return false;
}
return true;
}
void SSACCmpConv::updateTailPHIs() {
for (auto &I : *Tail) {
if (!I.isPHI())
break;
for (unsigned oi = I.getNumOperands(); oi > 2; oi -= 2) {
if (I.getOperand(oi - 1).getMBB() == CmpBB) {
I.removeOperand(oi - 1);
I.removeOperand(oi - 2);
}
}
}
}
bool SSACCmpConv::isDeadDef(unsigned DstReg) {
if (DstReg == AArch64::WZR || DstReg == AArch64::XZR)
return true;
if (!Register::isVirtualRegister(DstReg))
return false;
return MRI->use_nodbg_empty(DstReg);
}
static bool parseCond(ArrayRef<MachineOperand> Cond, AArch64CC::CondCode &CC) {
if (Cond[0].getImm() != -1) {
assert(Cond.size() == 1 && "Unknown Cond array format");
CC = (AArch64CC::CondCode)(int)Cond[0].getImm();
return true;
}
switch (Cond[1].getImm()) {
default:
return false;
case AArch64::CBZW:
case AArch64::CBZX:
assert(Cond.size() == 3 && "Unknown Cond array format");
CC = AArch64CC::EQ;
return true;
case AArch64::CBNZW:
case AArch64::CBNZX:
assert(Cond.size() == 3 && "Unknown Cond array format");
CC = AArch64CC::NE;
return true;
}
}
MachineInstr *SSACCmpConv::findConvertibleCompare(MachineBasicBlock *MBB) {
MachineBasicBlock::iterator I = MBB->getFirstTerminator();
if (I == MBB->end())
return nullptr;
if (!I->readsRegister(AArch64::NZCV)) {
switch (I->getOpcode()) {
case AArch64::CBZW:
case AArch64::CBZX:
case AArch64::CBNZW:
case AArch64::CBNZX:
return &*I;
}
++NumCmpTermRejs;
LLVM_DEBUG(dbgs() << "Flags not used by terminator: " << *I);
return nullptr;
}
for (MachineBasicBlock::iterator B = MBB->begin(); I != B;) {
I = prev_nodbg(I, MBB->begin());
assert(!I->isTerminator() && "Spurious terminator");
switch (I->getOpcode()) {
case AArch64::SUBSWri:
case AArch64::SUBSXri:
case AArch64::ADDSWri:
case AArch64::ADDSXri:
if (I->getOperand(3).getImm() || !isUInt<5>(I->getOperand(2).getImm())) {
LLVM_DEBUG(dbgs() << "Immediate out of range for ccmp: " << *I);
++NumImmRangeRejs;
return nullptr;
}
LLVM_FALLTHROUGH;
case AArch64::SUBSWrr:
case AArch64::SUBSXrr:
case AArch64::ADDSWrr:
case AArch64::ADDSXrr:
if (isDeadDef(I->getOperand(0).getReg()))
return &*I;
LLVM_DEBUG(dbgs() << "Can't convert compare with live destination: "
<< *I);
++NumLiveDstRejs;
return nullptr;
case AArch64::FCMPSrr:
case AArch64::FCMPDrr:
case AArch64::FCMPESrr:
case AArch64::FCMPEDrr:
return &*I;
}
PhysRegInfo PRI = AnalyzePhysRegInBundle(*I, AArch64::NZCV, TRI);
if (PRI.Read) {
LLVM_DEBUG(dbgs() << "Can't create ccmp with multiple uses: " << *I);
++NumMultNZCVUses;
return nullptr;
}
if (PRI.Defined || PRI.Clobbered) {
LLVM_DEBUG(dbgs() << "Not convertible compare: " << *I);
++NumUnknNZCVDefs;
return nullptr;
}
}
LLVM_DEBUG(dbgs() << "Flags not defined in " << printMBBReference(*MBB)
<< '\n');
return nullptr;
}
bool SSACCmpConv::canSpeculateInstrs(MachineBasicBlock *MBB,
const MachineInstr *CmpMI) {
if (!MBB->livein_empty()) {
LLVM_DEBUG(dbgs() << printMBBReference(*MBB) << " has live-ins.\n");
return false;
}
unsigned InstrCount = 0;
for (auto &I : make_range(MBB->begin(), MBB->getFirstTerminator())) {
if (I.isDebugInstr())
continue;
if (++InstrCount > BlockInstrLimit && !Stress) {
LLVM_DEBUG(dbgs() << printMBBReference(*MBB) << " has more than "
<< BlockInstrLimit << " instructions.\n");
return false;
}
if (I.isPHI()) {
LLVM_DEBUG(dbgs() << "Can't hoist: " << I);
return false;
}
if (I.mayLoad()) {
LLVM_DEBUG(dbgs() << "Won't speculate load: " << I);
return false;
}
bool DontMoveAcrossStore = true;
if (!I.isSafeToMove(nullptr, DontMoveAcrossStore)) {
LLVM_DEBUG(dbgs() << "Can't speculate: " << I);
return false;
}
if (&I != CmpMI && I.modifiesRegister(AArch64::NZCV, TRI)) {
LLVM_DEBUG(dbgs() << "Clobbers flags: " << I);
return false;
}
}
return true;
}
bool SSACCmpConv::canConvert(MachineBasicBlock *MBB) {
Head = MBB;
Tail = CmpBB = nullptr;
if (Head->succ_size() != 2)
return false;
MachineBasicBlock *Succ0 = Head->succ_begin()[0];
MachineBasicBlock *Succ1 = Head->succ_begin()[1];
if (Succ0->pred_size() != 1)
std::swap(Succ0, Succ1);
if (Succ0->pred_size() != 1 || Succ0->succ_size() != 2)
return false;
CmpBB = Succ0;
Tail = Succ1;
if (!CmpBB->isSuccessor(Tail))
return false;
LLVM_DEBUG(dbgs() << "\nTriangle: " << printMBBReference(*Head) << " -> "
<< printMBBReference(*CmpBB) << " -> "
<< printMBBReference(*Tail) << '\n');
++NumConsidered;
if (!trivialTailPHIs()) {
LLVM_DEBUG(dbgs() << "Can't handle phis in Tail.\n");
++NumPhiRejs;
return false;
}
if (!Tail->livein_empty()) {
LLVM_DEBUG(dbgs() << "Can't handle live-in physregs in Tail.\n");
++NumPhysRejs;
return false;
}
if (!CmpBB->empty() && CmpBB->front().isPHI()) {
LLVM_DEBUG(dbgs() << "Can't handle phis in CmpBB.\n");
++NumPhi2Rejs;
return false;
}
if (!CmpBB->livein_empty()) {
LLVM_DEBUG(dbgs() << "Can't handle live-in physregs in CmpBB.\n");
++NumPhysRejs;
return false;
}
HeadCond.clear();
MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
if (TII->analyzeBranch(*Head, TBB, FBB, HeadCond)) {
LLVM_DEBUG(dbgs() << "Head branch not analyzable.\n");
++NumHeadBranchRejs;
return false;
}
if (!TBB || HeadCond.empty()) {
LLVM_DEBUG(
dbgs() << "analyzeBranch didn't find conditional branch in Head.\n");
++NumHeadBranchRejs;
return false;
}
if (!parseCond(HeadCond, HeadCmpBBCC)) {
LLVM_DEBUG(dbgs() << "Unsupported branch type on Head\n");
++NumHeadBranchRejs;
return false;
}
if (TBB != CmpBB) {
assert(TBB == Tail && "Unexpected TBB");
HeadCmpBBCC = AArch64CC::getInvertedCondCode(HeadCmpBBCC);
}
CmpBBCond.clear();
TBB = FBB = nullptr;
if (TII->analyzeBranch(*CmpBB, TBB, FBB, CmpBBCond)) {
LLVM_DEBUG(dbgs() << "CmpBB branch not analyzable.\n");
++NumCmpBranchRejs;
return false;
}
if (!TBB || CmpBBCond.empty()) {
LLVM_DEBUG(
dbgs() << "analyzeBranch didn't find conditional branch in CmpBB.\n");
++NumCmpBranchRejs;
return false;
}
if (!parseCond(CmpBBCond, CmpBBTailCC)) {
LLVM_DEBUG(dbgs() << "Unsupported branch type on CmpBB\n");
++NumCmpBranchRejs;
return false;
}
if (TBB != Tail)
CmpBBTailCC = AArch64CC::getInvertedCondCode(CmpBBTailCC);
LLVM_DEBUG(dbgs() << "Head->CmpBB on "
<< AArch64CC::getCondCodeName(HeadCmpBBCC)
<< ", CmpBB->Tail on "
<< AArch64CC::getCondCodeName(CmpBBTailCC) << '\n');
CmpMI = findConvertibleCompare(CmpBB);
if (!CmpMI)
return false;
if (!canSpeculateInstrs(CmpBB, CmpMI)) {
++NumSpeculateRejs;
return false;
}
return true;
}
void SSACCmpConv::convert(SmallVectorImpl<MachineBasicBlock *> &RemovedBlocks) {
LLVM_DEBUG(dbgs() << "Merging " << printMBBReference(*CmpBB) << " into "
<< printMBBReference(*Head) << ":\n"
<< *CmpBB);
updateTailPHIs();
BranchProbability Head2CmpBB = MBPI->getEdgeProbability(Head, CmpBB);
BranchProbability CmpBB2Tail = MBPI->getEdgeProbability(CmpBB, Tail);
Head->removeSuccessor(CmpBB);
CmpBB->removeSuccessor(Tail);
if (Head->hasSuccessorProbabilities() && CmpBB->hasSuccessorProbabilities()) {
assert(*Head->succ_begin() == Tail && "Head successor is not Tail");
BranchProbability Head2Tail = MBPI->getEdgeProbability(Head, Tail);
Head->setSuccProbability(Head->succ_begin(),
Head2Tail + Head2CmpBB * CmpBB2Tail);
for (auto I = CmpBB->succ_begin(), E = CmpBB->succ_end(); I != E; ++I) {
BranchProbability CmpBB2I = MBPI->getEdgeProbability(CmpBB, *I);
CmpBB->setSuccProbability(I, Head2CmpBB * CmpBB2I);
}
}
Head->transferSuccessorsAndUpdatePHIs(CmpBB);
DebugLoc TermDL = Head->getFirstTerminator()->getDebugLoc();
TII->removeBranch(*Head);
if (HeadCond[0].getImm() == -1) {
++NumCompBranches;
unsigned Opc = 0;
switch (HeadCond[1].getImm()) {
case AArch64::CBZW:
case AArch64::CBNZW:
Opc = AArch64::SUBSWri;
break;
case AArch64::CBZX:
case AArch64::CBNZX:
Opc = AArch64::SUBSXri;
break;
default:
llvm_unreachable("Cannot convert Head branch");
}
const MCInstrDesc &MCID = TII->get(Opc);
Register DestReg =
MRI->createVirtualRegister(TII->getRegClass(MCID, 0, TRI, *MF));
BuildMI(*Head, Head->end(), TermDL, MCID)
.addReg(DestReg, RegState::Define | RegState::Dead)
.add(HeadCond[2])
.addImm(0)
.addImm(0);
MRI->constrainRegClass(HeadCond[2].getReg(),
TII->getRegClass(MCID, 1, TRI, *MF));
}
Head->splice(Head->end(), CmpBB, CmpBB->begin(), CmpBB->end());
unsigned Opc = 0;
unsigned FirstOp = 1; bool isZBranch = false; switch (CmpMI->getOpcode()) {
default:
llvm_unreachable("Unknown compare opcode");
case AArch64::SUBSWri: Opc = AArch64::CCMPWi; break;
case AArch64::SUBSWrr: Opc = AArch64::CCMPWr; break;
case AArch64::SUBSXri: Opc = AArch64::CCMPXi; break;
case AArch64::SUBSXrr: Opc = AArch64::CCMPXr; break;
case AArch64::ADDSWri: Opc = AArch64::CCMNWi; break;
case AArch64::ADDSWrr: Opc = AArch64::CCMNWr; break;
case AArch64::ADDSXri: Opc = AArch64::CCMNXi; break;
case AArch64::ADDSXrr: Opc = AArch64::CCMNXr; break;
case AArch64::FCMPSrr: Opc = AArch64::FCCMPSrr; FirstOp = 0; break;
case AArch64::FCMPDrr: Opc = AArch64::FCCMPDrr; FirstOp = 0; break;
case AArch64::FCMPESrr: Opc = AArch64::FCCMPESrr; FirstOp = 0; break;
case AArch64::FCMPEDrr: Opc = AArch64::FCCMPEDrr; FirstOp = 0; break;
case AArch64::CBZW:
case AArch64::CBNZW:
Opc = AArch64::CCMPWi;
FirstOp = 0;
isZBranch = true;
break;
case AArch64::CBZX:
case AArch64::CBNZX:
Opc = AArch64::CCMPXi;
FirstOp = 0;
isZBranch = true;
break;
}
unsigned NZCV = AArch64CC::getNZCVToSatisfyCondCode(CmpBBTailCC);
const MCInstrDesc &MCID = TII->get(Opc);
MRI->constrainRegClass(CmpMI->getOperand(FirstOp).getReg(),
TII->getRegClass(MCID, 0, TRI, *MF));
if (CmpMI->getOperand(FirstOp + 1).isReg())
MRI->constrainRegClass(CmpMI->getOperand(FirstOp + 1).getReg(),
TII->getRegClass(MCID, 1, TRI, *MF));
MachineInstrBuilder MIB = BuildMI(*Head, CmpMI, CmpMI->getDebugLoc(), MCID)
.add(CmpMI->getOperand(FirstOp)); if (isZBranch)
MIB.addImm(0); else
MIB.add(CmpMI->getOperand(FirstOp + 1)); MIB.addImm(NZCV).addImm(HeadCmpBBCC);
if (isZBranch) {
bool isNZ = CmpMI->getOpcode() == AArch64::CBNZW ||
CmpMI->getOpcode() == AArch64::CBNZX;
BuildMI(*Head, CmpMI, CmpMI->getDebugLoc(), TII->get(AArch64::Bcc))
.addImm(isNZ ? AArch64CC::NE : AArch64CC::EQ)
.add(CmpMI->getOperand(1)); }
CmpMI->eraseFromParent();
Head->updateTerminator(CmpBB->getNextNode());
RemovedBlocks.push_back(CmpBB);
CmpBB->eraseFromParent();
LLVM_DEBUG(dbgs() << "Result:\n" << *Head);
++NumConverted;
}
int SSACCmpConv::expectedCodeSizeDelta() const {
int delta = 0;
if (HeadCond[0].getImm() == -1) {
switch (HeadCond[1].getImm()) {
case AArch64::CBZW:
case AArch64::CBNZW:
case AArch64::CBZX:
case AArch64::CBNZX:
delta = 1;
break;
default:
llvm_unreachable("Cannot convert Head branch");
}
}
switch (CmpMI->getOpcode()) {
default:
--delta;
break;
case AArch64::CBZW:
case AArch64::CBNZW:
case AArch64::CBZX:
case AArch64::CBNZX:
break;
}
return delta;
}
namespace {
class AArch64ConditionalCompares : public MachineFunctionPass {
const MachineBranchProbabilityInfo *MBPI;
const TargetInstrInfo *TII;
const TargetRegisterInfo *TRI;
MCSchedModel SchedModel;
bool MinSize;
MachineRegisterInfo *MRI;
MachineDominatorTree *DomTree;
MachineLoopInfo *Loops;
MachineTraceMetrics *Traces;
MachineTraceMetrics::Ensemble *MinInstr;
SSACCmpConv CmpConv;
public:
static char ID;
AArch64ConditionalCompares() : MachineFunctionPass(ID) {
initializeAArch64ConditionalComparesPass(*PassRegistry::getPassRegistry());
}
void getAnalysisUsage(AnalysisUsage &AU) const override;
bool runOnMachineFunction(MachineFunction &MF) override;
StringRef getPassName() const override {
return "AArch64 Conditional Compares";
}
private:
bool tryConvert(MachineBasicBlock *);
void updateDomTree(ArrayRef<MachineBasicBlock *> Removed);
void updateLoops(ArrayRef<MachineBasicBlock *> Removed);
void invalidateTraces();
bool shouldConvert();
};
}
char AArch64ConditionalCompares::ID = 0;
INITIALIZE_PASS_BEGIN(AArch64ConditionalCompares, "aarch64-ccmp",
"AArch64 CCMP Pass", false, false)
INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
INITIALIZE_PASS_DEPENDENCY(MachineTraceMetrics)
INITIALIZE_PASS_END(AArch64ConditionalCompares, "aarch64-ccmp",
"AArch64 CCMP Pass", false, false)
FunctionPass *llvm::createAArch64ConditionalCompares() {
return new AArch64ConditionalCompares();
}
void AArch64ConditionalCompares::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<MachineBranchProbabilityInfo>();
AU.addRequired<MachineDominatorTree>();
AU.addPreserved<MachineDominatorTree>();
AU.addRequired<MachineLoopInfo>();
AU.addPreserved<MachineLoopInfo>();
AU.addRequired<MachineTraceMetrics>();
AU.addPreserved<MachineTraceMetrics>();
MachineFunctionPass::getAnalysisUsage(AU);
}
void AArch64ConditionalCompares::updateDomTree(
ArrayRef<MachineBasicBlock *> Removed) {
MachineDomTreeNode *HeadNode = DomTree->getNode(CmpConv.Head);
for (MachineBasicBlock *RemovedMBB : Removed) {
MachineDomTreeNode *Node = DomTree->getNode(RemovedMBB);
assert(Node != HeadNode && "Cannot erase the head node");
assert(Node->getIDom() == HeadNode && "CmpBB should be dominated by Head");
while (Node->getNumChildren())
DomTree->changeImmediateDominator(Node->back(), HeadNode);
DomTree->eraseNode(RemovedMBB);
}
}
void
AArch64ConditionalCompares::updateLoops(ArrayRef<MachineBasicBlock *> Removed) {
if (!Loops)
return;
for (MachineBasicBlock *RemovedMBB : Removed)
Loops->removeBlock(RemovedMBB);
}
void AArch64ConditionalCompares::invalidateTraces() {
Traces->invalidate(CmpConv.Head);
Traces->invalidate(CmpConv.CmpBB);
}
bool AArch64ConditionalCompares::shouldConvert() {
if (Stress)
return true;
if (!MinInstr)
MinInstr = Traces->getEnsemble(MachineTraceMetrics::TS_MinInstrCount);
MachineTraceMetrics::Trace Trace = MinInstr->getTrace(CmpConv.CmpBB);
if (MinSize) {
int CodeSizeDelta = CmpConv.expectedCodeSizeDelta();
LLVM_DEBUG(dbgs() << "Code size delta: " << CodeSizeDelta << '\n');
if (CodeSizeDelta < 0)
return true;
if (CodeSizeDelta > 0) {
LLVM_DEBUG(dbgs() << "Code size is increasing, give up on this one.\n");
return false;
}
}
unsigned DelayLimit = SchedModel.MispredictPenalty * 3 / 4;
unsigned HeadDepth =
Trace.getInstrCycles(*CmpConv.Head->getFirstTerminator()).Depth;
unsigned CmpBBDepth =
Trace.getInstrCycles(*CmpConv.CmpBB->getFirstTerminator()).Depth;
LLVM_DEBUG(dbgs() << "Head depth: " << HeadDepth
<< "\nCmpBB depth: " << CmpBBDepth << '\n');
if (CmpBBDepth > HeadDepth + DelayLimit) {
LLVM_DEBUG(dbgs() << "Branch delay would be larger than " << DelayLimit
<< " cycles.\n");
return false;
}
unsigned ResDepth = Trace.getResourceDepth(true);
LLVM_DEBUG(dbgs() << "Resources: " << ResDepth << '\n');
if (ResDepth > HeadDepth) {
LLVM_DEBUG(dbgs() << "Too many instructions to speculate.\n");
return false;
}
return true;
}
bool AArch64ConditionalCompares::tryConvert(MachineBasicBlock *MBB) {
bool Changed = false;
while (CmpConv.canConvert(MBB) && shouldConvert()) {
invalidateTraces();
SmallVector<MachineBasicBlock *, 4> RemovedBlocks;
CmpConv.convert(RemovedBlocks);
Changed = true;
updateDomTree(RemovedBlocks);
updateLoops(RemovedBlocks);
}
return Changed;
}
bool AArch64ConditionalCompares::runOnMachineFunction(MachineFunction &MF) {
LLVM_DEBUG(dbgs() << "********** AArch64 Conditional Compares **********\n"
<< "********** Function: " << MF.getName() << '\n');
if (skipFunction(MF.getFunction()))
return false;
TII = MF.getSubtarget().getInstrInfo();
TRI = MF.getSubtarget().getRegisterInfo();
SchedModel = MF.getSubtarget().getSchedModel();
MRI = &MF.getRegInfo();
DomTree = &getAnalysis<MachineDominatorTree>();
Loops = getAnalysisIfAvailable<MachineLoopInfo>();
MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
Traces = &getAnalysis<MachineTraceMetrics>();
MinInstr = nullptr;
MinSize = MF.getFunction().hasMinSize();
bool Changed = false;
CmpConv.runOnMachineFunction(MF, MBPI);
for (auto *I : depth_first(DomTree))
if (tryConvert(I->getBlock()))
Changed = true;
return Changed;
}