96#define DEBUG_TYPE "aarch64-condopt"
98STATISTIC(NumConditionsAdjusted,
"Number of conditions adjusted");
109class AArch64ConditionOptimizerImpl {
113 MachineInstr *CmpMI =
nullptr;
114 MachineInstr *CondMI =
nullptr;
118 unsigned getOpc()
const {
return CmpMI->getOpcode(); }
121 using PairSHT = ScopedHashTable<Register, CmpCondPair>;
123 const AArch64InstrInfo *TII;
124 const TargetRegisterInfo *TRI;
125 MachineDominatorTree *DomTree;
126 const MachineRegisterInfo *MRI;
130 bool run(MachineFunction &MF, MachineDominatorTree &MDT);
133 bool canAdjustCmp(MachineInstr &CmpMI);
134 bool nzcvLivesOut(MachineBasicBlock *
MBB);
136 void updateCmpInstr(MachineInstr *CmpMI,
int NewImm,
unsigned NewOpc);
138 void applyCmpAdjustment(CmpCondPair &Pair,
const CmpInfo &Info);
139 bool commitPendingPair(std::optional<CmpCondPair> &PendingPair);
140 bool tryOptimizePair(CmpCondPair &
First, CmpCondPair &Second);
148 AArch64ConditionOptimizerLegacy() : MachineFunctionPass(ID) {}
150 void getAnalysisUsage(AnalysisUsage &AU)
const override;
151 bool runOnMachineFunction(MachineFunction &MF)
override;
153 StringRef getPassName()
const override {
154 return "AArch64 Condition Optimizer";
160char AArch64ConditionOptimizerLegacy::ID = 0;
163 "AArch64 CondOpt Pass",
false,
false)
169 return new AArch64ConditionOptimizerLegacy();
172void AArch64ConditionOptimizerLegacy::getAnalysisUsage(
181bool AArch64ConditionOptimizerImpl::canAdjustCmp(MachineInstr &CmpMI) {
184 LLVM_DEBUG(
dbgs() <<
"Immediate of cmp is symbolic, " << CmpMI <<
'\n');
187 LLVM_DEBUG(
dbgs() <<
"Immediate of cmp may be out of range, " << CmpMI
191 LLVM_DEBUG(
dbgs() <<
"Destination of cmp is not dead, " << CmpMI <<
'\n');
199bool AArch64ConditionOptimizerImpl::nzcvLivesOut(MachineBasicBlock *
MBB) {
201 if (SuccBB->isLiveIn(AArch64::NZCV)) {
215 case AArch64::SUBSWri:
216 case AArch64::SUBSXri:
218 case AArch64::ADDSWri:
219 case AArch64::ADDSXri:
229 case AArch64::ADDSWri:
return AArch64::SUBSWri;
230 case AArch64::ADDSXri:
return AArch64::SUBSXri;
231 case AArch64::SUBSWri:
return AArch64::ADDSWri;
232 case AArch64::SUBSXri:
return AArch64::ADDSXri;
265AArch64ConditionOptimizerImpl::getAdjustedCmpInfo(MachineInstr *CmpMI,
274 bool Negative = (
Opc == AArch64::ADDSWri ||
Opc == AArch64::ADDSXri);
279 Correction = -Correction;
283 const int NewImm = std::abs(OldImm + Correction);
287 if (OldImm == 0 && Negative)
288 return {OldImm,
Opc,
Cmp};
290 if ((OldImm == 1 && Negative && Correction == -1) ||
291 (OldImm == 0 && Correction == -1)) {
296 return {OldImm,
Opc,
Cmp};
304void AArch64ConditionOptimizerImpl::updateCmpInstr(MachineInstr *CmpMI,
312void AArch64ConditionOptimizerImpl::updateCondInstr(MachineInstr *CondMI,
315 AArch64InstrInfo::findCondCodeUseOperandIdxForBranchOrSelect(*CondMI);
316 assert(CCOpIdx >= 0 &&
"Unsupported conditional instruction");
318 ++NumConditionsAdjusted;
322void AArch64ConditionOptimizerImpl::applyCmpAdjustment(CmpCondPair &Pair,
323 const CmpInfo &Info) {
324 updateCmpInstr(Pair.CmpMI,
Info.Imm,
Info.Opc);
325 updateCondInstr(Pair.CondMI,
Info.CC);
337bool AArch64ConditionOptimizerImpl::tryOptimizePair(CmpCondPair &
First,
338 CmpCondPair &Second) {
343 int FirstImmTrueValue =
First.getImm();
344 int SecondImmTrueValue = Second.getImm();
347 if (
First.getOpc() == AArch64::ADDSWri ||
First.getOpc() == AArch64::ADDSXri)
348 FirstImmTrueValue = -FirstImmTrueValue;
349 if (Second.getOpc() == AArch64::ADDSWri ||
350 Second.getOpc() == AArch64::ADDSXri)
351 SecondImmTrueValue = -SecondImmTrueValue;
353 CmpInfo FirstAdj = getAdjustedCmpInfo(
First.CmpMI,
First.CC);
354 CmpInfo SecondAdj = getAdjustedCmpInfo(Second.CmpMI, Second.CC);
358 std::abs(SecondImmTrueValue - FirstImmTrueValue) == 2) {
371 if (FirstAdj.Imm != SecondAdj.Imm || FirstAdj.Opc != SecondAdj.Opc)
376 <<
First.getImm() <<
", "
378 << Second.getImm() <<
" -> "
380 << FirstAdj.Imm <<
", "
382 << SecondAdj.Imm <<
'\n');
383 applyCmpAdjustment(
First, FirstAdj);
384 applyCmpAdjustment(Second, SecondAdj);
389 std::abs(SecondImmTrueValue - FirstImmTrueValue) == 1) {
402 bool AdjustFirst = (FirstImmTrueValue < SecondImmTrueValue);
404 AdjustFirst = !AdjustFirst;
406 CmpCondPair &
Target = AdjustFirst ? Second :
First;
407 CmpCondPair &ToChange = AdjustFirst ?
First : Second;
408 CmpInfo &Adj = AdjustFirst ? FirstAdj : SecondAdj;
412 if (Adj.Imm !=
Target.getImm() || Adj.Opc !=
Target.getOpc())
417 << ToChange.getImm() <<
" -> "
420 applyCmpAdjustment(ToChange, Adj);
429bool AArch64ConditionOptimizerImpl::commitPendingPair(
430 std::optional<CmpCondPair> &PendingPair) {
434 Register Reg = PendingPair->CmpMI->getOperand(1).getReg();
437 CmpCondPair Prior = BlockPairs.
lookup(
Key);
438 bool Changed = Prior.CmpMI && tryOptimizePair(Prior, *PendingPair);
441 PendingPair = std::nullopt;
465bool AArch64ConditionOptimizerImpl::optimizeBlock(MachineBasicBlock &
MBB) {
466 std::optional<CmpCondPair> PendingPair;
467 MachineInstr *ActiveCmp =
nullptr;
470 for (MachineInstr &
MI :
MBB) {
471 if (
MI.isDebugInstr())
475 Changed |= commitPendingPair(PendingPair);
480 if (
MI.modifiesRegister(AArch64::NZCV,
nullptr)) {
482 Changed |= commitPendingPair(PendingPair);
487 if (AArch64InstrInfo::findCondCodeUseOperandIdxForBranchOrSelect(
MI) >= 0) {
492 PendingPair = std::nullopt;
494 }
else if (ActiveCmp) {
496 AArch64InstrInfo::findCondCodeUseOperandIdxForBranchOrSelect(
MI);
497 assert(CCOpIdx >= 0 &&
"Unsupported conditional instruction");
500 PendingPair = CmpCondPair{ActiveCmp, &
MI, CC};
505 if (
MI.readsRegister(AArch64::NZCV,
nullptr)) {
507 PendingPair = std::nullopt;
514 if (!nzcvLivesOut(&
MBB))
515 Changed |= commitPendingPair(PendingPair);
520bool AArch64ConditionOptimizerLegacy::runOnMachineFunction(
521 MachineFunction &MF) {
524 MachineDominatorTree &MDT =
525 getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
526 return AArch64ConditionOptimizerImpl().run(MF, MDT);
531 ScopedHashTableScope<Register, CmpCondPair>
Scope(BlockPairs);
533 for (
auto *Child :
Node->children())
537bool AArch64ConditionOptimizerImpl::run(MachineFunction &MF,
538 MachineDominatorTree &MDT) {
539 LLVM_DEBUG(
dbgs() <<
"********** AArch64 Conditional Compares **********\n"
540 <<
"********** Function: " << MF.
getName() <<
'\n');
542 TII =
static_cast<const AArch64InstrInfo *
>(MF.
getSubtarget().getInstrInfo());
556 bool Changed = AArch64ConditionOptimizerImpl().run(MF, MDT);
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!")
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)
static bool optimizeBlock(BasicBlock &BB, bool &ModifiedDT, const TargetTransformInfo &TTI, const DataLayout &DL, bool HasBranchDivergence, DomTreeUpdater *DTU)
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.
Represents analyses that only rely on functions' control flow.
DomTreeNodeBase< NodeT > * getRootNode()
getRootNode - This returns the entry node for the CFG of the function.
FunctionPass class - This class is used to implement most global optimizations.
iterator_range< succ_iterator > successors()
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.
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.
void insert(const K &Key, const V &Val)
V lookup(const K &Key) 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.
DXILDebugInfoMap run(Module &M)
Scope
Defines the scope in which this symbol should be visible: Default – Visible in the public interface o...
NodeAddr< NodeBase * > Node
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.
DomTreeNodeBase< MachineBasicBlock > MachineDomTreeNode
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
LLVM_ABI Printable printMBBReference(const MachineBasicBlock &MBB)
Prints a machine basic block reference.