97#define DEBUG_TYPE "aarch64-condopt"
99STATISTIC(NumConditionsAdjusted,
"Number of conditions adjusted");
110class AArch64ConditionOptimizerImpl {
115 MachineInstr *CondMI;
119 unsigned getOpc()
const {
return CmpMI->getOpcode(); }
122 const AArch64InstrInfo *TII;
123 const TargetRegisterInfo *TRI;
124 MachineDominatorTree *DomTree;
125 const MachineRegisterInfo *MRI;
131 bool canAdjustCmp(MachineInstr &CmpMI);
132 bool registersMatch(MachineInstr *FirstMI, MachineInstr *SecondMI);
133 bool nzcvLivesOut(MachineBasicBlock *
MBB);
134 MachineInstr *getBccTerminator(MachineBasicBlock *
MBB);
135 MachineInstr *findAdjustableCmp(MachineInstr *CondMI);
137 void updateCmpInstr(MachineInstr *CmpMI,
int NewImm,
unsigned NewOpc);
139 void applyCmpAdjustment(CmpCondPair &Pair,
const CmpInfo &Info);
140 bool commitPendingPair(std::optional<CmpCondPair> &PendingPair,
141 SmallDenseMap<Register, CmpCondPair> &PairsByReg);
142 bool tryOptimizePair(CmpCondPair &
First, CmpCondPair &Second);
143 bool optimizeIntraBlock(MachineBasicBlock &
MBB);
144 bool optimizeCrossBlock(MachineBasicBlock &HBB);
145 std::pair<MachineInstr *, AArch64CC::CondCode>
146 findCondConsumer(MachineBasicBlock *
MBB);
152 AArch64ConditionOptimizerLegacy() : MachineFunctionPass(ID) {}
154 void getAnalysisUsage(AnalysisUsage &AU)
const override;
157 StringRef getPassName()
const override {
158 return "AArch64 Condition Optimizer";
164char AArch64ConditionOptimizerLegacy::ID = 0;
167 "AArch64 CondOpt Pass",
false,
false)
173 return new AArch64ConditionOptimizerLegacy();
176void AArch64ConditionOptimizerLegacy::getAnalysisUsage(
185bool AArch64ConditionOptimizerImpl::canAdjustCmp(MachineInstr &CmpMI) {
188 LLVM_DEBUG(
dbgs() <<
"Immediate of cmp is symbolic, " << CmpMI <<
'\n');
191 LLVM_DEBUG(
dbgs() <<
"Immediate of cmp may be out of range, " << CmpMI
195 LLVM_DEBUG(
dbgs() <<
"Destination of cmp is not dead, " << CmpMI <<
'\n');
203bool AArch64ConditionOptimizerImpl::registersMatch(MachineInstr *FirstMI,
204 MachineInstr *SecondMI) {
208 FirstReg.
isVirtual() ?
TRI->lookThruCopyLike(FirstReg, MRI) : FirstReg;
210 SecondReg.
isVirtual() ?
TRI->lookThruCopyLike(SecondReg, MRI) : SecondReg;
211 if (FirstCmpReg != SecondCmpReg) {
220bool AArch64ConditionOptimizerImpl::nzcvLivesOut(MachineBasicBlock *
MBB) {
222 if (SuccBB->isLiveIn(AArch64::NZCV)) {
236 case AArch64::SUBSWri:
237 case AArch64::SUBSXri:
239 case AArch64::ADDSWri:
240 case AArch64::ADDSXri:
249AArch64ConditionOptimizerImpl::getBccTerminator(MachineBasicBlock *
MBB) {
257 if (
Term->getOpcode() != AArch64::Bcc) {
271AArch64ConditionOptimizerImpl::findAdjustableCmp(MachineInstr *CondMI) {
272 assert(CondMI &&
"CondMI cannot be null");
281 MachineInstr &
I = *It;
282 assert(!
I.isTerminator() &&
"Spurious terminator");
284 if (
I.readsRegister(AArch64::NZCV,
nullptr))
288 if (!canAdjustCmp(
I)) {
294 if (
I.modifiesRegister(AArch64::NZCV,
nullptr))
305 case AArch64::ADDSWri:
return AArch64::SUBSWri;
306 case AArch64::ADDSXri:
return AArch64::SUBSXri;
307 case AArch64::SUBSWri:
return AArch64::ADDSWri;
308 case AArch64::SUBSXri:
return AArch64::ADDSXri;
341AArch64ConditionOptimizerImpl::getAdjustedCmpInfo(MachineInstr *CmpMI,
350 bool Negative = (
Opc == AArch64::ADDSWri ||
Opc == AArch64::ADDSXri);
355 Correction = -Correction;
359 const int NewImm = std::abs(OldImm + Correction);
363 if (OldImm == 0 && Negative)
364 return {OldImm,
Opc,
Cmp};
366 if ((OldImm == 1 && Negative && Correction == -1) ||
367 (OldImm == 0 && Correction == -1)) {
372 return {OldImm,
Opc,
Cmp};
380void AArch64ConditionOptimizerImpl::updateCmpInstr(MachineInstr *CmpMI,
388void AArch64ConditionOptimizerImpl::updateCondInstr(MachineInstr *CondMI,
391 AArch64InstrInfo::findCondCodeUseOperandIdxForBranchOrSelect(*CondMI);
392 assert(CCOpIdx >= 0 &&
"Unsupported conditional instruction");
394 ++NumConditionsAdjusted;
398void AArch64ConditionOptimizerImpl::applyCmpAdjustment(CmpCondPair &Pair,
399 const CmpInfo &Info) {
400 updateCmpInstr(Pair.CmpMI,
Info.Imm,
Info.Opc);
401 updateCondInstr(Pair.CondMI,
Info.CC);
408 assert(!
Cond.empty() &&
"Expected non-empty condition from analyzeBranch");
411 assert(
Cond.size() == 1 &&
"Unknown Cond array format");
425bool AArch64ConditionOptimizerImpl::tryOptimizePair(CmpCondPair &
First,
426 CmpCondPair &Second) {
431 int FirstImmTrueValue =
First.getImm();
432 int SecondImmTrueValue = Second.getImm();
435 if (
First.getOpc() == AArch64::ADDSWri ||
First.getOpc() == AArch64::ADDSXri)
436 FirstImmTrueValue = -FirstImmTrueValue;
437 if (Second.getOpc() == AArch64::ADDSWri ||
438 Second.getOpc() == AArch64::ADDSXri)
439 SecondImmTrueValue = -SecondImmTrueValue;
441 CmpInfo FirstAdj = getAdjustedCmpInfo(
First.CmpMI,
First.CC);
442 CmpInfo SecondAdj = getAdjustedCmpInfo(Second.CmpMI, Second.CC);
446 std::abs(SecondImmTrueValue - FirstImmTrueValue) == 2) {
459 if (FirstAdj.Imm != SecondAdj.Imm || FirstAdj.Opc != SecondAdj.Opc)
464 <<
First.getImm() <<
", "
466 << Second.getImm() <<
" -> "
468 << FirstAdj.Imm <<
", "
470 << SecondAdj.Imm <<
'\n');
471 applyCmpAdjustment(
First, FirstAdj);
472 applyCmpAdjustment(Second, SecondAdj);
477 std::abs(SecondImmTrueValue - FirstImmTrueValue) == 1) {
490 bool AdjustFirst = (FirstImmTrueValue < SecondImmTrueValue);
492 AdjustFirst = !AdjustFirst;
494 CmpCondPair &
Target = AdjustFirst ? Second :
First;
495 CmpCondPair &ToChange = AdjustFirst ?
First : Second;
496 CmpInfo &Adj = AdjustFirst ? FirstAdj : SecondAdj;
500 if (Adj.Imm !=
Target.getImm() || Adj.Opc !=
Target.getOpc())
505 << ToChange.getImm() <<
" -> "
508 applyCmpAdjustment(ToChange, Adj);
517bool AArch64ConditionOptimizerImpl::commitPendingPair(
518 std::optional<CmpCondPair> &PendingPair,
519 SmallDenseMap<Register, CmpCondPair> &PairsByReg) {
523 Register Reg = PendingPair->CmpMI->getOperand(1).getReg();
526 auto MatchingPair = PairsByReg.
find(
Key);
527 bool Changed = MatchingPair != PairsByReg.
end() &&
528 tryOptimizePair(MatchingPair->second, *PendingPair);
530 PairsByReg[
Key] = *PendingPair;
531 PendingPair = std::nullopt;
555bool AArch64ConditionOptimizerImpl::optimizeIntraBlock(MachineBasicBlock &
MBB) {
556 SmallDenseMap<Register, CmpCondPair> PairsByReg;
557 std::optional<CmpCondPair> PendingPair;
558 MachineInstr *ActiveCmp =
nullptr;
561 for (MachineInstr &
MI :
MBB) {
562 if (
MI.isDebugInstr())
566 Changed |= commitPendingPair(PendingPair, PairsByReg);
571 if (
MI.modifiesRegister(AArch64::NZCV,
nullptr)) {
574 Changed |= commitPendingPair(PendingPair, PairsByReg);
580 if (AArch64InstrInfo::findCondCodeUseOperandIdxForBranchOrSelect(
MI) >= 0 &&
586 PendingPair = std::nullopt;
588 }
else if (ActiveCmp) {
590 AArch64InstrInfo::findCondCodeUseOperandIdxForBranchOrSelect(
MI);
591 assert(CCOpIdx >= 0 &&
"Unsupported conditional instruction");
594 PendingPair = CmpCondPair{ActiveCmp, &
MI, CC};
599 if (
MI.readsRegister(AArch64::NZCV,
nullptr)) {
601 PendingPair = std::nullopt;
608 if (!nzcvLivesOut(&
MBB))
609 Changed |= commitPendingPair(PendingPair, PairsByReg);
627std::pair<MachineInstr *, AArch64CC::CondCode>
628AArch64ConditionOptimizerImpl::findCondConsumer(MachineBasicBlock *
MBB) {
630 if (MachineInstr *BrMI = getBccTerminator(
MBB)) {
632 MachineBasicBlock *TBBDest =
nullptr, *FBBDest =
nullptr;
643 MachineInstr *Found =
nullptr;
649 if (
MI.isTerminator() ||
MI.isDebugInstr())
657 if (
MI.modifiesRegister(AArch64::NZCV,
nullptr))
666 AArch64InstrInfo::findCondCodeUseOperandIdxForBranchOrSelect(
MI);
667 if (CCOpIdx >= 0 && !
MI.isBranch()) {
675 if (
MI.readsRegister(AArch64::NZCV,
nullptr))
682 if (
MI.readsRegister(AArch64::NZCV,
nullptr))
685 if (
MI.modifiesRegister(AArch64::NZCV,
nullptr)) {
696 return {Found, FoundCC};
702bool AArch64ConditionOptimizerImpl::optimizeCrossBlock(MachineBasicBlock &HBB) {
704 MachineBasicBlock *
TBB =
nullptr, *FBB =
nullptr;
710 if (!
TBB ||
TBB == &HBB) {
716 auto [HeadCondMI, HeadCondCode] = findCondConsumer(&HBB);
720 auto [TrueCondMI, TrueCondCode] = findCondConsumer(
TBB);
725 if (nzcvLivesOut(&HBB) || nzcvLivesOut(
TBB))
729 MachineInstr *HeadCmpMI = findAdjustableCmp(HeadCondMI);
730 MachineInstr *TrueCmpMI = findAdjustableCmp(TrueCondMI);
731 if (!HeadCmpMI || !TrueCmpMI)
734 if (!registersMatch(HeadCmpMI, TrueCmpMI))
743 CmpCondPair Head{HeadCmpMI, HeadCondMI, HeadCondCode};
744 CmpCondPair True{TrueCmpMI, TrueCondMI, TrueCondCode};
746 return tryOptimizePair(Head, True);
749bool AArch64ConditionOptimizerLegacy::runOnMachineFunction(
753 MachineDominatorTree &MDT =
754 getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
755 return AArch64ConditionOptimizerImpl().run(MF, MDT);
759 MachineDominatorTree &MDT) {
760 LLVM_DEBUG(
dbgs() <<
"********** AArch64 Conditional Compares **********\n"
761 <<
"********** Function: " << MF.
getName() <<
'\n');
763 TII =
static_cast<const AArch64InstrInfo *
>(MF.
getSubtarget().getInstrInfo());
776 MachineBasicBlock *HBB =
I->getBlock();
777 Changed |= optimizeIntraBlock(*HBB);
778 Changed |= optimizeCrossBlock(*HBB);
788 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 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.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Represents analyses that only rely on functions' control flow.
iterator find(const_arg_type_t< KeyT > Val)
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 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.
DXILDebugInfoMap run(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.
auto reverse(ContainerTy &&C)
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
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
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.