94#define DEBUG_TYPE "aarch64-condopt"
96STATISTIC(NumConditionsAdjusted,
"Number of conditions adjusted");
107class AArch64ConditionOptimizerImpl {
108 const TargetInstrInfo *TII;
109 const TargetRegisterInfo *TRI;
110 MachineDominatorTree *DomTree;
111 const MachineRegisterInfo *MRI;
114 bool run(MachineFunction &MF, MachineDominatorTree &MDT);
117 bool canAdjustCmp(MachineInstr &CmpMI);
118 bool registersMatch(MachineInstr *FirstMI, MachineInstr *SecondMI);
119 bool nzcvLivesOut(MachineBasicBlock *
MBB);
120 MachineInstr *getBccTerminator(MachineBasicBlock *
MBB);
121 MachineInstr *findAdjustableCmp(MachineInstr *CondMI);
123 void updateCmpInstr(MachineInstr *CmpMI,
int NewImm,
unsigned NewOpc);
125 void applyCmpAdjustment(MachineInstr *CmpMI, MachineInstr *CondMI,
126 const CmpInfo &Info);
129 bool optimizeIntraBlock(MachineBasicBlock &
MBB);
130 bool optimizeCrossBlock(MachineBasicBlock &HBB);
136 AArch64ConditionOptimizerLegacy() : MachineFunctionPass(ID) {}
138 void getAnalysisUsage(AnalysisUsage &AU)
const override;
139 bool runOnMachineFunction(MachineFunction &MF)
override;
141 StringRef getPassName()
const override {
142 return "AArch64 Condition Optimizer";
148char AArch64ConditionOptimizerLegacy::ID = 0;
151 "AArch64 CondOpt Pass",
false,
false)
157 return new AArch64ConditionOptimizerLegacy();
160void AArch64ConditionOptimizerLegacy::getAnalysisUsage(
169bool AArch64ConditionOptimizerImpl::canAdjustCmp(MachineInstr &CmpMI) {
172 LLVM_DEBUG(
dbgs() <<
"Immediate of cmp is symbolic, " << CmpMI <<
'\n');
175 LLVM_DEBUG(
dbgs() <<
"Immediate of cmp may be out of range, " << CmpMI
179 LLVM_DEBUG(
dbgs() <<
"Destination of cmp is not dead, " << CmpMI <<
'\n');
187bool AArch64ConditionOptimizerImpl::registersMatch(MachineInstr *FirstMI,
188 MachineInstr *SecondMI) {
192 FirstReg.
isVirtual() ?
TRI->lookThruCopyLike(FirstReg, MRI) : FirstReg;
194 SecondReg.
isVirtual() ?
TRI->lookThruCopyLike(SecondReg, MRI) : SecondReg;
195 if (FirstCmpReg != SecondCmpReg) {
204bool AArch64ConditionOptimizerImpl::nzcvLivesOut(MachineBasicBlock *
MBB) {
206 if (SuccBB->isLiveIn(AArch64::NZCV)) {
220 case AArch64::SUBSWri:
221 case AArch64::SUBSXri:
223 case AArch64::ADDSWri:
224 case AArch64::ADDSXri:
232 return Opc == AArch64::CSINCWr ||
Opc == AArch64::CSINCXr;
237AArch64ConditionOptimizerImpl::getBccTerminator(MachineBasicBlock *
MBB) {
245 if (
Term->getOpcode() != AArch64::Bcc) {
259AArch64ConditionOptimizerImpl::findAdjustableCmp(MachineInstr *CondMI) {
260 assert(CondMI &&
"CondMI cannot be null");
269 MachineInstr &
I = *It;
270 assert(!
I.isTerminator() &&
"Spurious terminator");
272 if (
I.readsRegister(AArch64::NZCV,
nullptr))
276 if (!canAdjustCmp(
I)) {
282 if (
I.modifiesRegister(AArch64::NZCV,
nullptr))
293 case AArch64::ADDSWri:
return AArch64::SUBSWri;
294 case AArch64::ADDSXri:
return AArch64::SUBSXri;
295 case AArch64::SUBSWri:
return AArch64::ADDSWri;
296 case AArch64::SUBSXri:
return AArch64::ADDSXri;
329AArch64ConditionOptimizerImpl::getAdjustedCmpInfo(MachineInstr *CmpMI,
338 bool Negative = (
Opc == AArch64::ADDSWri ||
Opc == AArch64::ADDSXri);
343 Correction = -Correction;
347 const int NewImm = std::abs(OldImm + Correction);
351 if (OldImm == 0 && Negative)
352 return {OldImm,
Opc,
Cmp};
354 if ((OldImm == 1 && Negative && Correction == -1) ||
355 (OldImm == 0 && Correction == -1)) {
360 return {OldImm,
Opc,
Cmp};
368void AArch64ConditionOptimizerImpl::updateCmpInstr(MachineInstr *CmpMI,
376void AArch64ConditionOptimizerImpl::updateCondInstr(MachineInstr *CondMI,
384 case AArch64::CSINCWr:
385 case AArch64::CSINCXr:
392 ++NumConditionsAdjusted;
396void AArch64ConditionOptimizerImpl::applyCmpAdjustment(MachineInstr *CmpMI,
397 MachineInstr *CondMI,
398 const CmpInfo &Info) {
399 updateCmpInstr(CmpMI,
Info.Imm,
Info.Opc);
400 updateCondInstr(CondMI,
Info.CC);
406 assert(!
Cond.empty() &&
"Expected non-empty condition from analyzeBranch");
409 assert(
Cond.size() == 1 &&
"Unknown Cond array format");
419bool AArch64ConditionOptimizerImpl::adjustTo(MachineInstr *CmpMI,
421 MachineInstr *To,
int ToImm) {
422 CmpInfo
Info = getAdjustedCmpInfo(CmpMI, Cmp);
425 applyCmpAdjustment(CmpMI, &BrMI, Info);
456bool AArch64ConditionOptimizerImpl::optimizeIntraBlock(MachineBasicBlock &
MBB) {
457 MachineInstr *FirstCSINC =
nullptr;
458 MachineInstr *SecondCSINC =
nullptr;
461 for (MachineInstr &
MI :
MBB) {
465 }
else if (!SecondCSINC) {
472 if (!FirstCSINC || !SecondCSINC) {
477 if (nzcvLivesOut(&
MBB))
481 MachineInstr *FirstCmpMI = findAdjustableCmp(FirstCSINC);
482 MachineInstr *SecondCmpMI = findAdjustableCmp(SecondCSINC);
483 if (!FirstCmpMI || !SecondCmpMI)
487 if (FirstCmpMI == SecondCmpMI) {
488 LLVM_DEBUG(
dbgs() <<
"Both CSINCs already controlled by same CMP\n");
492 if (!registersMatch(FirstCmpMI, SecondCmpMI))
499 if (&*It != SecondCmpMI &&
500 It->modifiesRegister(AArch64::NZCV,
nullptr)) {
501 LLVM_DEBUG(
dbgs() <<
"Flags modified between CMPs by: " << *It <<
'\n');
509 if (It->readsRegister(AArch64::NZCV,
nullptr)) {
510 LLVM_DEBUG(
dbgs() <<
"Flags read after second CSINC by: " << *It <<
'\n');
527 << SecondImm <<
'\n');
531 if (FirstCond == SecondCond &&
533 std::abs(SecondImm - FirstImm) == 1) {
537 bool adjustFirst = (FirstImm < SecondImm);
539 adjustFirst = !adjustFirst;
542 MachineInstr *CmpToAdjust = adjustFirst ? FirstCmpMI : SecondCmpMI;
543 MachineInstr *CSINCToAdjust = adjustFirst ? FirstCSINC : SecondCSINC;
545 int TargetImm = adjustFirst ? SecondImm : FirstImm;
547 CmpInfo Adj = getAdjustedCmpInfo(CmpToAdjust, CondToAdjust);
549 if (Adj.Imm == TargetImm &&
550 Adj.Opc == (adjustFirst ? SecondCmpMI : FirstCmpMI)->getOpcode()) {
551 LLVM_DEBUG(
dbgs() <<
"Successfully optimizing intra-block CSINC pair\n");
554 applyCmpAdjustment(CmpToAdjust, CSINCToAdjust, Adj);
564bool AArch64ConditionOptimizerImpl::optimizeCrossBlock(MachineBasicBlock &HBB) {
566 MachineBasicBlock *
TBB =
nullptr, *FBB =
nullptr;
572 if (!
TBB ||
TBB == &HBB) {
577 MachineBasicBlock *TBB_TBB =
nullptr, *TBB_FBB =
nullptr;
582 MachineInstr *HeadBrMI = getBccTerminator(&HBB);
583 MachineInstr *TrueBrMI = getBccTerminator(
TBB);
584 if (!HeadBrMI || !TrueBrMI)
588 if (nzcvLivesOut(&HBB) || nzcvLivesOut(
TBB))
591 MachineInstr *HeadCmpMI = findAdjustableCmp(HeadBrMI);
592 MachineInstr *TrueCmpMI = findAdjustableCmp(TrueBrMI);
593 if (!HeadCmpMI || !TrueCmpMI)
596 if (!registersMatch(HeadCmpMI, TrueCmpMI))
601 if (HeadCmp == AArch64CC::CondCode::Invalid ||
602 TrueCmp == AArch64CC::CondCode::Invalid) {
609 int HeadImmTrueValue = HeadImm;
610 int TrueImmTrueValue = TrueImm;
623 if (
Opc == AArch64::ADDSWri ||
Opc == AArch64::ADDSXri)
624 HeadImmTrueValue = -HeadImmTrueValue;
627 if (
Opc == AArch64::ADDSWri ||
Opc == AArch64::ADDSXri)
628 TrueImmTrueValue = -TrueImmTrueValue;
632 std::abs(TrueImmTrueValue - HeadImmTrueValue) == 2) {
643 CmpInfo HeadCmpInfo = getAdjustedCmpInfo(HeadCmpMI, HeadCmp);
644 CmpInfo TrueCmpInfo = getAdjustedCmpInfo(TrueCmpMI, TrueCmp);
645 if (HeadCmpInfo.Imm == TrueCmpInfo.Imm &&
646 HeadCmpInfo.Opc == TrueCmpInfo.Opc) {
647 applyCmpAdjustment(HeadCmpMI, HeadBrMI, HeadCmpInfo);
648 applyCmpAdjustment(TrueCmpMI, TrueBrMI, TrueCmpInfo);
653 std::abs(TrueImmTrueValue - HeadImmTrueValue) == 1) {
666 bool adjustHeadCond = (HeadImmTrueValue < TrueImmTrueValue);
668 adjustHeadCond = !adjustHeadCond;
671 if (adjustHeadCond) {
672 return adjustTo(HeadCmpMI, HeadCmp, TrueCmpMI, TrueImm);
674 return adjustTo(TrueCmpMI, TrueCmp, HeadCmpMI, HeadImm);
683bool AArch64ConditionOptimizerLegacy::runOnMachineFunction(
684 MachineFunction &MF) {
687 MachineDominatorTree &MDT =
688 getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
689 return AArch64ConditionOptimizerImpl().run(MF, MDT);
692bool AArch64ConditionOptimizerImpl::run(MachineFunction &MF,
693 MachineDominatorTree &MDT) {
694 LLVM_DEBUG(
dbgs() <<
"********** AArch64 Conditional Compares **********\n"
695 <<
"********** Function: " << MF.
getName() <<
'\n');
710 MachineBasicBlock *HBB =
I->getBlock();
711 Changed |= optimizeIntraBlock(*HBB);
712 Changed |= optimizeCrossBlock(*HBB);
722 bool Changed = AArch64ConditionOptimizerImpl().run(MF, MDT);
static AArch64CC::CondCode parseCondCode(ArrayRef< MachineOperand > Cond)
static int getComplementOpc(int Opc)
static bool isGreaterThan(AArch64CC::CondCode Cmp)
static AArch64CC::CondCode getAdjustedCmp(AArch64CC::CondCode Cmp)
static bool isCSINCInstruction(unsigned Opc)
static bool isLessThan(AArch64CC::CondCode Cmp)
static bool isCmpInstruction(unsigned Opc)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file builds on the ADT/GraphTraits.h file to build generic depth first graph iterator.
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 SmallVector class.
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.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Represents analyses that only rely on functions' control flow.
FunctionPass class - This class is used to implement most global optimizations.
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....
LLVM_ABI iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
iterator_range< succ_iterator > successors()
MachineInstrBundleIterator< MachineInstr > iterator
Analysis pass which computes a MachineDominatorTree.
Analysis pass which computes a MachineDominatorTree.
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.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
LLVM_ABI void setDesc(const MCInstrDesc &TID)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one.
const MachineOperand & getOperand(unsigned i) const
void setImm(int64_t immVal)
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
Register getReg() const
getReg - Returns the register number.
bool use_nodbg_empty(Register RegNo) const
use_nodbg_empty - Return true if there are no non-Debug instructions using the specified register.
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 & preserveSet()
Mark an analysis set as preserved.
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
virtual const TargetInstrInfo * getInstrInfo() const
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
static const char * getCondCodeName(CondCode Code)
static unsigned getShiftValue(unsigned Imm)
getShiftValue - Extract the shift value.
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
This is an optimization pass for GlobalISel generic memory operations.
FunctionPass * createAArch64ConditionOptimizerLegacyPass()
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
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.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
DomTreeNodeBase< MachineBasicBlock > MachineDomTreeNode
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.
LLVM_ABI Printable printMBBReference(const MachineBasicBlock &MBB)
Prints a machine basic block reference.