43#define DEBUG_TYPE "aarch64-ccmp"
49 cl::desc(
"Maximum number of instructions per speculated block."));
55STATISTIC(NumConsidered,
"Number of ccmps considered");
56STATISTIC(NumPhiRejs,
"Number of ccmps rejected (PHI)");
57STATISTIC(NumPhysRejs,
"Number of ccmps rejected (Physregs)");
58STATISTIC(NumPhi2Rejs,
"Number of ccmps rejected (PHI2)");
59STATISTIC(NumHeadBranchRejs,
"Number of ccmps rejected (Head branch)");
60STATISTIC(NumCmpBranchRejs,
"Number of ccmps rejected (CmpBB branch)");
61STATISTIC(NumCmpTermRejs,
"Number of ccmps rejected (CmpBB is cbz...)");
62STATISTIC(NumImmRangeRejs,
"Number of ccmps rejected (Imm out of range)");
63STATISTIC(NumLiveDstRejs,
"Number of ccmps rejected (Cmp dest live)");
64STATISTIC(NumMultNZCVUses,
"Number of ccmps rejected (NZCV used)");
65STATISTIC(NumUnknNZCVDefs,
"Number of ccmps rejected (NZCV def unknown)");
67STATISTIC(NumSpeculateRejs,
"Number of ccmps rejected (Can't speculate)");
69STATISTIC(NumConverted,
"Number of ccmp instructions created");
70STATISTIC(NumCompBranches,
"Number of cb/cbz/cbnz branches converted");
173 bool trivialTailPHIs();
176 void updateTailPHIs();
179 bool isDeadDef(
unsigned DstReg);
203 bool canConvert(MachineBasicBlock *
MBB);
207 void convert(SmallVectorImpl<MachineBasicBlock *> &RemovedBlocks);
211 int expectedCodeSizeDelta()
const;
218 MI->getOpcode() == TargetOpcode::COPY) {
219 if (
MI->getOperand(1).getReg().isPhysical())
221 Reg =
MI->getOperand(1).getReg();
228bool SSACCmpConv::trivialTailPHIs() {
229 for (
auto &
I : *Tail) {
232 unsigned HeadReg = 0, CmpBBReg = 0;
234 for (
unsigned oi = 1, oe =
I.getNumOperands(); oi != oe; oi += 2) {
235 MachineBasicBlock *
MBB =
I.getOperand(oi + 1).getMBB();
238 assert((!HeadReg || HeadReg ==
Reg) &&
"Inconsistent PHI operands");
242 assert((!CmpBBReg || CmpBBReg ==
Reg) &&
"Inconsistent PHI operands");
246 if (HeadReg != CmpBBReg)
254void SSACCmpConv::updateTailPHIs() {
255 for (
auto &
I : *Tail) {
259 for (
unsigned oi =
I.getNumOperands(); oi > 2; oi -= 2) {
261 if (
I.getOperand(oi - 1).getMBB() == CmpBB) {
262 I.removeOperand(oi - 1);
263 I.removeOperand(oi - 2);
271bool SSACCmpConv::isDeadDef(
unsigned DstReg) {
273 if (DstReg == AArch64::WZR || DstReg == AArch64::XZR)
275 if (!Register::isVirtualRegister(DstReg))
288 assert(
Cond.size() == 1 &&
"Unknown Cond array format");
300 assert(
Cond.size() == 3 &&
"Unknown Cond array format");
305 assert(
Cond.size() == 3 &&
"Unknown Cond array format");
310 case AArch64::CBWPri:
311 case AArch64::CBXPri:
312 case AArch64::CBWPrr:
313 case AArch64::CBXPrr:
314 assert(
Cond.size() == 5 &&
"Unknown Cond array format");
321MachineInstr *SSACCmpConv::findConvertibleCompare(MachineBasicBlock *
MBB) {
326 if (!
I->readsRegister(AArch64::NZCV,
nullptr)) {
327 switch (
I->getOpcode()) {
334 case AArch64::CBWPrr:
335 case AArch64::CBXPrr:
339 case AArch64::CBWPri:
340 case AArch64::CBXPri:
341 assert(
I->getOperand(2).isImm() &&
"Expected immediate operand");
357 assert(!
I->isTerminator() &&
"Spurious terminator");
358 switch (
I->getOpcode()) {
360 case AArch64::SUBSWri:
361 case AArch64::SUBSXri:
363 case AArch64::ADDSWri:
364 case AArch64::ADDSXri:
367 if (
I->getOperand(3).getImm() || !
isUInt<5>(
I->getOperand(2).getImm())) {
373 case AArch64::SUBSWrr:
374 case AArch64::SUBSXrr:
375 case AArch64::ADDSWrr:
376 case AArch64::ADDSXrr:
377 if (isDeadDef(
I->getOperand(0).getReg()))
379 LLVM_DEBUG(
dbgs() <<
"Can't convert compare with live destination: "
383 case AArch64::FCMPSrr:
384 case AArch64::FCMPDrr:
385 case AArch64::FCMPESrr:
386 case AArch64::FCMPEDrr:
418bool SSACCmpConv::canSpeculateInstrs(MachineBasicBlock *
MBB,
419 const MachineInstr *CmpMI) {
432 if (
I.isDebugInstr())
456 bool DontMoveAcrossStore =
true;
457 if (!
I.isSafeToMove(DontMoveAcrossStore)) {
463 if (&
I != CmpMI &&
I.modifiesRegister(AArch64::NZCV,
TRI)) {
474bool SSACCmpConv::canConvert(MachineBasicBlock *
MBB) {
476 Tail = CmpBB =
nullptr;
480 MachineBasicBlock *Succ0 = Head->
succ_begin()[0];
481 MachineBasicBlock *Succ1 = Head->
succ_begin()[1];
509 if (!trivialTailPHIs()) {
515 if (!
Tail->livein_empty()) {
530 LLVM_DEBUG(
dbgs() <<
"Can't handle live-in physregs in CmpBB.\n");
537 MachineBasicBlock *
TBB =
nullptr, *FBB =
nullptr;
548 dbgs() <<
"analyzeBranch didn't find conditional branch in Head.\n");
575 dbgs() <<
"analyzeBranch didn't find conditional branch in CmpBB.\n");
580 if (!
parseCond(CmpBBCond, CmpBBTailCC)) {
591 <<
", CmpBB->Tail on "
594 CmpMI = findConvertibleCompare(CmpBB);
598 if (!canSpeculateInstrs(CmpBB, CmpMI)) {
605void SSACCmpConv::convert(SmallVectorImpl<MachineBasicBlock *> &RemovedBlocks) {
634 Head2Tail + Head2CmpBB * CmpBB2Tail);
653 if (HeadCond[0].
getImm() == -1) {
655 TII->insertCmpForCondBr(*Head, Head->
end(), TermDL, HeadCond);
663 unsigned FirstOp = 1;
664 bool isZBranch =
false;
668 case AArch64::SUBSWri:
Opc = AArch64::CCMPWi;
break;
669 case AArch64::SUBSWrr:
Opc = AArch64::CCMPWr;
break;
670 case AArch64::SUBSXri:
Opc = AArch64::CCMPXi;
break;
671 case AArch64::SUBSXrr:
Opc = AArch64::CCMPXr;
break;
672 case AArch64::ADDSWri:
Opc = AArch64::CCMNWi;
break;
673 case AArch64::ADDSWrr:
Opc = AArch64::CCMNWr;
break;
674 case AArch64::ADDSXri:
Opc = AArch64::CCMNXi;
break;
675 case AArch64::ADDSXrr:
Opc = AArch64::CCMNXr;
break;
676 case AArch64::FCMPSrr:
Opc = AArch64::FCCMPSrr; FirstOp = 0;
break;
677 case AArch64::FCMPDrr:
Opc = AArch64::FCCMPDrr; FirstOp = 0;
break;
678 case AArch64::FCMPESrr:
Opc = AArch64::FCCMPESrr; FirstOp = 0;
break;
679 case AArch64::FCMPEDrr:
Opc = AArch64::FCCMPEDrr; FirstOp = 0;
break;
682 Opc = AArch64::CCMPWi;
688 Opc = AArch64::CCMPXi;
692 case AArch64::CBWPri:
693 Opc = AArch64::CCMPWi;
696 case AArch64::CBXPri:
697 Opc = AArch64::CCMPXi;
700 case AArch64::CBWPrr:
701 Opc = AArch64::CCMPWr;
704 case AArch64::CBXPrr:
705 Opc = AArch64::CCMPXr;
716 const MCInstrDesc &MCID =
TII->get(
Opc);
718 TII->getRegClass(MCID, 0));
721 TII->getRegClass(MCID, 1));
745 case AArch64::CBWPri:
746 case AArch64::CBXPri:
747 case AArch64::CBWPrr:
748 case AArch64::CBXPrr:
752 MachineBasicBlock *BrTarget =
TII->getBranchDestBlock(*CmpMI);
765int SSACCmpConv::expectedCodeSizeDelta()
const {
770 if (HeadCond[0].
getImm() == -1) {
771 switch (HeadCond[1].
getImm()) {
776 case AArch64::CBWPri:
777 case AArch64::CBXPri:
778 case AArch64::CBWPrr:
779 case AArch64::CBXPrr:
799 case AArch64::CBWPri:
800 case AArch64::CBXPri:
801 case AArch64::CBWPrr:
802 case AArch64::CBXPrr:
813class AArch64ConditionalComparesImpl {
814 const MachineBranchProbabilityInfo *MBPI;
815 const TargetInstrInfo *
TII;
816 const TargetRegisterInfo *
TRI;
817 const TargetSubtargetInfo *STI;
820 MachineRegisterInfo *MRI;
821 MachineDominatorTree *DomTree;
822 MachineLoopInfo *
Loops;
823 MachineTraceMetrics *Traces;
828 AArch64ConditionalComparesImpl(
const MachineBranchProbabilityInfo *MBPI,
829 MachineDominatorTree *DomTree,
830 MachineLoopInfo *
Loops,
831 MachineTraceMetrics *Traces)
832 : MBPI(MBPI), DomTree(DomTree),
Loops(
Loops), Traces(Traces) {}
837 bool tryConvert(MachineBasicBlock *);
840 void invalidateTraces();
844class AArch64ConditionalComparesLegacy :
public MachineFunctionPass {
847 AArch64ConditionalComparesLegacy() : MachineFunctionPass(
ID) {
851 void getAnalysisUsage(AnalysisUsage &AU)
const override;
853 StringRef getPassName()
const override {
854 return "AArch64 Conditional Compares";
859char AArch64ConditionalComparesLegacy::ID = 0;
862 "AArch64 CCMP Pass",
false,
false)
870 return new AArch64ConditionalComparesLegacy();
873void AArch64ConditionalComparesLegacy::getAnalysisUsage(
886void AArch64ConditionalComparesImpl::updateDomTree(
891 for (MachineBasicBlock *RemovedMBB : Removed) {
893 assert(Node != HeadNode &&
"Cannot erase the head node");
894 assert(
Node->getIDom() == HeadNode &&
"CmpBB should be dominated by Head");
895 while (!
Node->isLeaf())
902void AArch64ConditionalComparesImpl::updateLoops(
906 for (MachineBasicBlock *RemovedMBB : Removed)
907 Loops->removeBlock(RemovedMBB);
911void AArch64ConditionalComparesImpl::invalidateTraces() {
919bool AArch64ConditionalComparesImpl::shouldConvert() {
924 MinInstr = Traces->
getEnsemble(MachineTraceStrategy::TS_MinInstrCount);
931 int CodeSizeDelta = CmpConv.expectedCodeSizeDelta();
932 LLVM_DEBUG(
dbgs() <<
"Code size delta: " << CodeSizeDelta <<
'\n');
935 if (CodeSizeDelta < 0)
937 if (CodeSizeDelta > 0) {
938 LLVM_DEBUG(
dbgs() <<
"Code size is increasing, give up on this one.\n");
955 unsigned CmpBBDepth =
958 <<
"\nCmpBB depth: " << CmpBBDepth <<
'\n');
959 if (CmpBBDepth > HeadDepth + DelayLimit) {
960 LLVM_DEBUG(
dbgs() <<
"Branch delay would be larger than " << DelayLimit
973 if (ResDepth > HeadDepth) {
980bool AArch64ConditionalComparesImpl::tryConvert(MachineBasicBlock *
MBB) {
984 SmallVector<MachineBasicBlock *, 4> RemovedBlocks;
985 CmpConv.convert(RemovedBlocks);
987 updateDomTree(RemovedBlocks);
988 updateLoops(RemovedBlocks);
989 for (MachineBasicBlock *
MBB : RemovedBlocks)
996 LLVM_DEBUG(
dbgs() <<
"********** AArch64 Conditional Compares **********\n"
997 <<
"********** Function: " << MF.
getName() <<
'\n');
1007 CmpConv.runOnMachineFunction(MF, MBPI);
1015 if (tryConvert(
I->getBlock()))
1021bool AArch64ConditionalComparesLegacy::runOnMachineFunction(
1026 const MachineBranchProbabilityInfo *MBPI =
1027 &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
1028 MachineDominatorTree *DomTree =
1029 &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
1030 MachineLoopInfo *
Loops = &getAnalysis<MachineLoopInfoWrapperPass>().getLI();
1031 MachineTraceMetrics *Traces =
1032 &getAnalysis<MachineTraceMetricsWrapperPass>().getMTM();
1034 AArch64ConditionalComparesImpl Impl(MBPI, DomTree,
Loops, Traces);
1035 return Impl.run(MF);
1049 AArch64ConditionalComparesImpl Impl(MBPI, DomTree,
Loops, Traces);
static Register lookThroughCopies(Register Reg, MachineRegisterInfo *MRI)
static cl::opt< bool > Stress("aarch64-stress-ccmp", cl::Hidden, cl::desc("Turn all knobs to 11"))
static cl::opt< unsigned > BlockInstrLimit("aarch64-ccmp-limit", cl::init(30), cl::Hidden, cl::desc("Maximum number of instructions per speculated block."))
static bool parseCond(ArrayRef< MachineOperand > Cond, AArch64CC::CondCode &CC)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static unsigned InstrCount
This file builds on the ADT/GraphTraits.h file to build generic depth first graph iterator.
static cl::opt< bool > Stress("stress-early-ifcvt", cl::Hidden, cl::desc("Turn all knobs to 11"))
static cl::opt< unsigned > BlockInstrLimit("early-ifcvt-limit", cl::init(30), cl::Hidden, cl::desc("Maximum number of instructions per speculated block."))
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)
const SmallVectorImpl< MachineOperand > MachineBasicBlock * TBB
const SmallVectorImpl< MachineOperand > & Cond
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
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.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
void changeImmediateDominator(DomTreeNodeBase< NodeT > *N, DomTreeNodeBase< NodeT > *NewIDom)
changeImmediateDominator - This method is used to update the dominator tree information when a node's...
void eraseNode(NodeT *BB)
eraseNode - Removes a node from the dominator tree.
DomTreeNodeBase< NodeT > * getNode(const NodeT *BB) const
getNode - return the (Post)DominatorTree node for the specified basic block.
FunctionPass class - This class is used to implement most global optimizations.
bool hasMinSize() const
Optimize this function for minimum size (-Oz).
unsigned removeBranch(MachineBasicBlock &MBB, int *BytesRemoved=nullptr) const override
Remove the branching code at the end of the specific MBB.
bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, SmallVectorImpl< MachineOperand > &Cond, bool AllowModify) const override
Analyze the branching code at the end of MBB, returning true if it cannot be understood (e....
unsigned pred_size() const
LLVM_ABI void transferSuccessorsAndUpdatePHIs(MachineBasicBlock *FromMBB)
Transfers all the successors, as in transferSuccessors, and update PHI operands in the successor bloc...
LLVM_ABI void updateTerminator(MachineBasicBlock *PreviousLayoutSuccessor)
Update the terminator instructions in block to account for changes to block layout which may have bee...
LLVM_ABI void setSuccProbability(succ_iterator I, BranchProbability Prob)
Set successor probability of a given iterator.
succ_iterator succ_begin()
bool livein_empty() const
LLVM_ABI iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
unsigned succ_size() const
LLVM_ABI void removeSuccessor(MachineBasicBlock *Succ, bool NormalizeSuccProbs=false)
Remove successor from the successors list of this MachineBasicBlock.
bool hasSuccessorProbabilities() const
Return true if any of the successors have probabilities attached to them.
LLVM_ABI void eraseFromParent()
This method unlinks 'this' from the containing function and deletes it.
LLVM_ABI bool isSuccessor(const MachineBasicBlock *MBB) const
Return true if the specified MBB is a successor of this block.
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
LLVM_ABI BranchProbability getEdgeProbability(const MachineBasicBlock *Src, const MachineBasicBlock *Dst) const
Analysis pass which computes a MachineDominatorTree.
Analysis pass which computes a MachineDominatorTree.
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
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.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
bool isTerminator(QueryType Type=AnyInBundle) const
Returns true if this instruction part of the terminator for a basic block.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
Analysis pass that exposes the MachineLoopInfo for a machine function.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
bool use_nodbg_empty(Register RegNo) const
use_nodbg_empty - Return true if there are no non-Debug instructions using the specified register.
LLVM_ABI const TargetRegisterClass * constrainRegClass(Register Reg, const TargetRegisterClass *RC, unsigned MinNumRegs=0)
constrainRegClass - Constrain the register class of the specified virtual register to be a common sub...
LLVM_ABI LLVM_READONLY MachineInstr * getUniqueVRegDef(Register Reg) const
getUniqueVRegDef - Return the unique machine instr that defines the specified virtual register or nul...
Trace getTrace(const MachineBasicBlock *MBB)
Get the trace that passes through MBB.
InstrCycles getInstrCycles(const MachineInstr &MI) const
Return the depth and height of MI.
LLVM_ABI unsigned getResourceDepth(bool Bottom) const
Return the resource depth of the top/bottom of the trace center block.
LLVM_ABI Ensemble * getEnsemble(MachineTraceStrategy)
Get the trace ensemble representing the given trace selection strategy.
LLVM_ABI void invalidate(const MachineBasicBlock *MBB)
Invalidate cached information about MBB.
static LLVM_ABI PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserve()
Mark an analysis as preserved.
Wrapper class representing virtual and physical registers.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual unsigned getMispredictionPenalty() const
Return the number of extra cycles the processor takes to recover from a branch misprediction.
virtual const TargetInstrInfo * getInstrInfo() const
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
static const char * getCondCodeName(CondCode Code)
static CondCode getInvertedCondCode(CondCode Code)
static unsigned getNZCVToSatisfyCondCode(CondCode Code)
Given a condition code, return NZCV flags that would satisfy that condition.
@ Tail
Attemps to make calls as fast as possible while guaranteeing that tail call optimization can always b...
initializer< Ty > init(const Ty &Val)
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
NodeAddr< NodeBase * > Node
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.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
LLVM_ABI PhysRegInfo AnalyzePhysRegInBundle(const MachineInstr &MI, Register Reg, const TargetRegisterInfo *TRI)
AnalyzePhysRegInBundle - Analyze how the current instruction or bundle uses a physical register.
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
FunctionPass * createAArch64ConditionalCompares()
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
DomTreeNodeBase< MachineBasicBlock > MachineDomTreeNode
ArrayRef(const T &OneElt) -> ArrayRef< T >
iterator_range< df_iterator< T > > depth_first(const T &G)
IterT prev_nodbg(IterT It, IterT Begin, bool SkipPseudoOp=true)
Decrement It, then continue decrementing it while it points to a debug instruction.
void initializeAArch64ConditionalComparesLegacyPass(PassRegistry &)
LLVM_ABI Printable printMBBReference(const MachineBasicBlock &MBB)
Prints a machine basic block reference.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
unsigned Depth
Earliest issue cycle as determined by data dependencies and instruction latencies from the beginning ...
bool Read
Reg or one of its aliases is read.
bool Defined
Reg or one of its aliases is defined.
bool Clobbered
There is a regmask operand indicating Reg is clobbered.