//=- AArch64ConditionOptimizer.cpp - Remove useless comparisons for AArch64 -=// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This pass tries to make consecutive compares of values use same operands to // allow CSE pass to remove duplicated instructions. For this it analyzes // branches and adjusts comparisons with immediate values by converting: // * GE -> GT // * GT -> GE // * LT -> LE // * LE -> LT // and adjusting immediate values appropriately. It basically corrects two // immediate values towards each other to make them equal. // // Consider the following example in C: // // if ((a < 5 && ...) || (a > 5 && ...)) { // ~~~~~ ~~~~~ // ^ ^ // x y // // Here both "x" and "y" expressions compare "a" with "5". When "x" evaluates // to "false", "y" can just check flags set by the first comparison. As a // result of the canonicalization employed by // SelectionDAGBuilder::visitSwitchCase, DAGCombine, and other target-specific // code, assembly ends up in the form that is not CSE friendly: // // ... // cmp w8, #4 // b.gt .LBB0_3 // ... // .LBB0_3: // cmp w8, #6 // b.lt .LBB0_6 // ... // // Same assembly after the pass: // // ... // cmp w8, #5 // b.ge .LBB0_3 // ... // .LBB0_3: // cmp w8, #5 // <-- CSE pass removes this instruction // b.le .LBB0_6 // ... // // Currently only SUBS and ADDS followed by b.?? are supported. // // TODO: maybe handle TBNZ/TBZ the same way as CMP when used instead for "a < 0" // TODO: handle other conditional instructions (e.g. CSET) // TODO: allow second branching to be anything if it doesn't require adjusting // //===----------------------------------------------------------------------===// #include "AArch64.h" #include "MCTargetDesc/AArch64AddressingModes.h" #include "Utils/AArch64BaseInfo.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include <cassert> #include <cstdlib> #include <tuple> usingnamespacellvm; #define DEBUG_TYPE … STATISTIC(NumConditionsAdjusted, "Number of conditions adjusted"); namespace { class AArch64ConditionOptimizer : public MachineFunctionPass { … }; } // end anonymous namespace char AArch64ConditionOptimizer::ID = …; INITIALIZE_PASS_BEGIN(AArch64ConditionOptimizer, "aarch64-condopt", "AArch64 CondOpt Pass", false, false) INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass) INITIALIZE_PASS_END(AArch64ConditionOptimizer, "aarch64-condopt", "AArch64 CondOpt Pass", false, false) FunctionPass *llvm::createAArch64ConditionOptimizerPass() { … } void AArch64ConditionOptimizer::getAnalysisUsage(AnalysisUsage &AU) const { … } // Finds compare instruction that corresponds to supported types of branching. // Returns the instruction or nullptr on failures or detecting unsupported // instructions. MachineInstr *AArch64ConditionOptimizer::findSuitableCompare( MachineBasicBlock *MBB) { … } // Changes opcode adds <-> subs considering register operand width. static int getComplementOpc(int Opc) { … } // Changes form of comparison inclusive <-> exclusive. static AArch64CC::CondCode getAdjustedCmp(AArch64CC::CondCode Cmp) { … } // Transforms GT -> GE, GE -> GT, LT -> LE, LE -> LT by updating comparison // operator and condition code. AArch64ConditionOptimizer::CmpInfo AArch64ConditionOptimizer::adjustCmp( MachineInstr *CmpMI, AArch64CC::CondCode Cmp) { … } // Applies changes to comparison instruction suggested by adjustCmp(). void AArch64ConditionOptimizer::modifyCmp(MachineInstr *CmpMI, const CmpInfo &Info) { … } // Parse a condition code returned by analyzeBranch, and compute the CondCode // corresponding to TBB. // Returns true if parsing was successful, otherwise false is returned. static bool parseCond(ArrayRef<MachineOperand> Cond, AArch64CC::CondCode &CC) { … } // Adjusts one cmp instruction to another one if result of adjustment will allow // CSE. Returns true if compare instruction was changed, otherwise false is // returned. bool AArch64ConditionOptimizer::adjustTo(MachineInstr *CmpMI, AArch64CC::CondCode Cmp, MachineInstr *To, int ToImm) { … } bool AArch64ConditionOptimizer::runOnMachineFunction(MachineFunction &MF) { … }