95#define DEBUG_TYPE "aarch64-condopt"
97STATISTIC(NumConditionsAdjusted,
"Number of conditions adjusted");
109 using CmpInfo = std::tuple<int, unsigned, AArch64CC::CondCode>;
115 void getAnalysisUsage(AnalysisUsage &AU)
const override;
116 MachineInstr *findSuitableCompare(MachineBasicBlock *
MBB);
118 void modifyCmp(MachineInstr *CmpMI,
const CmpInfo &
Info);
121 bool isPureCmp(MachineInstr &CmpMI);
122 bool optimizeIntraBlock(MachineBasicBlock &
MBB);
123 bool optimizeCrossBlock(MachineBasicBlock &HBB);
124 bool runOnMachineFunction(MachineFunction &MF)
override;
126 StringRef getPassName()
const override {
127 return "AArch64 Condition Optimizer";
133char AArch64ConditionOptimizer::ID = 0;
136 "AArch64 CondOpt Pass",
false,
false)
142 return new AArch64ConditionOptimizer();
145void AArch64ConditionOptimizer::getAnalysisUsage(
AnalysisUsage &AU)
const {
154MachineInstr *AArch64ConditionOptimizer::findSuitableCompare(
155 MachineBasicBlock *
MBB) {
160 if (
Term->getOpcode() != AArch64::Bcc)
165 if (SuccBB->isLiveIn(AArch64::NZCV))
171 MachineInstr &
I = *It;
172 assert(!
I.isTerminator() &&
"Spurious terminator");
174 if (
I.readsRegister(AArch64::NZCV,
nullptr))
176 switch (
I.getOpcode()) {
178 case AArch64::SUBSWri:
179 case AArch64::SUBSXri:
181 case AArch64::ADDSWri:
182 case AArch64::ADDSXri: {
184 if (!
I.getOperand(2).isImm()) {
187 }
else if (
I.getOperand(2).getImm() << ShiftAmt >= 0xfff) {
191 }
else if (!
MRI->use_nodbg_empty(
I.getOperand(0).getReg())) {
203 case AArch64::FCMPDri:
204 case AArch64::FCMPSri:
205 case AArch64::FCMPESri:
206 case AArch64::FCMPEDri:
208 case AArch64::SUBSWrr:
209 case AArch64::SUBSXrr:
210 case AArch64::ADDSWrr:
211 case AArch64::ADDSXrr:
212 case AArch64::FCMPSrr:
213 case AArch64::FCMPDrr:
214 case AArch64::FCMPESrr:
215 case AArch64::FCMPEDrr:
228 case AArch64::ADDSWri:
return AArch64::SUBSWri;
229 case AArch64::ADDSXri:
return AArch64::SUBSXri;
230 case AArch64::SUBSWri:
return AArch64::ADDSWri;
231 case AArch64::SUBSXri:
return AArch64::ADDSXri;
251AArch64ConditionOptimizer::CmpInfo AArch64ConditionOptimizer::adjustCmp(
257 bool Negative = (
Opc == AArch64::ADDSWri ||
Opc == AArch64::ADDSXri);
262 Correction = -Correction;
266 const int NewImm = std::abs(OldImm + Correction);
270 if (OldImm == 0 && ((Negative && Correction == 1) ||
271 (!Negative && Correction == -1))) {
279void AArch64ConditionOptimizer::modifyCmp(MachineInstr *CmpMI,
280 const CmpInfo &
Info) {
284 std::tie(Imm,
Opc, Cmp) =
Info;
306 ++NumConditionsAdjusted;
315 assert(
Cond.size() == 1 &&
"Unknown Cond array format");
325bool AArch64ConditionOptimizer::adjustTo(MachineInstr *CmpMI,
328 CmpInfo
Info = adjustCmp(CmpMI, Cmp);
330 modifyCmp(CmpMI,
Info);
336bool AArch64ConditionOptimizer::isPureCmp(MachineInstr &CmpMI) {
339 LLVM_DEBUG(
dbgs() <<
"Immediate of cmp is symbolic, " << CmpMI <<
'\n');
342 LLVM_DEBUG(
dbgs() <<
"Immediate of cmp may be out of range, " << CmpMI
346 LLVM_DEBUG(
dbgs() <<
"Destination of cmp is not dead, " << CmpMI <<
'\n');
370bool AArch64ConditionOptimizer::optimizeIntraBlock(MachineBasicBlock &
MBB) {
371 MachineInstr *FirstCmp =
nullptr;
372 MachineInstr *FirstCSINC =
nullptr;
373 MachineInstr *SecondCmp =
nullptr;
374 MachineInstr *SecondCSINC =
nullptr;
377 for (MachineInstr &
MI :
MBB) {
378 switch (
MI.getOpcode()) {
380 case AArch64::SUBSWri:
381 case AArch64::SUBSXri:
383 case AArch64::ADDSWri:
384 case AArch64::ADDSXri: {
387 }
else if (FirstCSINC && !SecondCmp) {
393 case AArch64::CSINCWr:
394 case AArch64::CSINCXr: {
396 if (FirstCmp && !FirstCSINC) {
398 }
else if (SecondCmp && !SecondCSINC) {
409 if (!SecondCmp || !SecondCSINC) {
419 if (!isPureCmp(*FirstCmp) || !isPureCmp(*SecondCmp)) {
428 if (&*It != SecondCmp &&
429 It->modifiesRegister(AArch64::NZCV,
nullptr)) {
430 LLVM_DEBUG(
dbgs() <<
"Flags modified between CMPs by: " << *It <<
'\n');
438 if (It->readsRegister(AArch64::NZCV,
nullptr)) {
439 LLVM_DEBUG(
dbgs() <<
"Flags read after second CSINC by: " << *It <<
'\n');
446 if (SuccBB->isLiveIn(AArch64::NZCV))
461 << SecondImm <<
'\n');
466 std::abs(SecondImm - FirstImm) == 1) {
470 bool adjustFirst = (FirstImm < SecondImm);
472 adjustFirst = !adjustFirst;
475 MachineInstr *CmpToAdjust = adjustFirst ? FirstCmp : SecondCmp;
476 MachineInstr *CSINCToAdjust = adjustFirst ? FirstCSINC : SecondCSINC;
478 int TargetImm = adjustFirst ? SecondImm : FirstImm;
480 CmpInfo AdjustedInfo = adjustCmp(CmpToAdjust, CondToAdjust);
482 if (std::get<0>(AdjustedInfo) == TargetImm &&
483 std::get<1>(AdjustedInfo) ==
484 (adjustFirst ? SecondCmp : FirstCmp)->
getOpcode()) {
485 LLVM_DEBUG(
dbgs() <<
"Successfully optimizing intra-block CSINC pair\n");
489 CmpToAdjust->
setDesc(
TII->get(std::get<1>(AdjustedInfo)));
500bool AArch64ConditionOptimizer::optimizeCrossBlock(MachineBasicBlock &HBB) {
502 MachineBasicBlock *
TBB =
nullptr, *FBB =
nullptr;
508 if (!
TBB ||
TBB == &HBB) {
513 MachineBasicBlock *TBB_TBB =
nullptr, *TBB_FBB =
nullptr;
518 MachineInstr *HeadCmpMI = findSuitableCompare(&HBB);
523 MachineInstr *TrueCmpMI = findSuitableCompare(
TBB);
553 std::abs(TrueImm - HeadImm) == 2) {
564 CmpInfo HeadCmpInfo = adjustCmp(HeadCmpMI, HeadCmp);
565 CmpInfo TrueCmpInfo = adjustCmp(TrueCmpMI, TrueCmp);
566 if (std::get<0>(HeadCmpInfo) == std::get<0>(TrueCmpInfo) &&
567 std::get<1>(HeadCmpInfo) == std::get<1>(TrueCmpInfo)) {
568 modifyCmp(HeadCmpMI, HeadCmpInfo);
569 modifyCmp(TrueCmpMI, TrueCmpInfo);
574 std::abs(TrueImm - HeadImm) == 1) {
587 bool adjustHeadCond = (HeadImm < TrueImm);
589 adjustHeadCond = !adjustHeadCond;
592 if (adjustHeadCond) {
593 return adjustTo(HeadCmpMI, HeadCmp, TrueCmpMI, TrueImm);
595 return adjustTo(TrueCmpMI, TrueCmp, HeadCmpMI, HeadImm);
604bool AArch64ConditionOptimizer::runOnMachineFunction(MachineFunction &MF) {
605 LLVM_DEBUG(
dbgs() <<
"********** AArch64 Conditional Compares **********\n"
606 <<
"********** Function: " << MF.
getName() <<
'\n');
611 DomTree = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
622 MachineBasicBlock *HBB =
I->getBlock();
623 Changed |= optimizeIntraBlock(*HBB);
624 Changed |= optimizeCrossBlock(*HBB);
unsigned const MachineRegisterInfo * MRI
static int getComplementOpc(int Opc)
static AArch64CC::CondCode getAdjustedCmp(AArch64CC::CondCode Cmp)
static bool parseCond(ArrayRef< MachineOperand > Cond, AArch64CC::CondCode &CC)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Analysis containing CSE Info
This file builds on the ADT/GraphTraits.h file to build generic depth first graph iterator.
const HexagonInstrInfo * TII
#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)
static std::optional< unsigned > getOpcode(ArrayRef< VPValue * > Values)
Returns the opcode of Values or ~0 if they do not all agree.
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),...
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.
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
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.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
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 DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
LLVM_ABI void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
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.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
TargetInstrInfo - Interface to description of machine instruction set.
virtual const TargetInstrInfo * getInstrInfo() const
#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.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
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.
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.
FunctionPass * createAArch64ConditionOptimizerPass()
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.