10b57cec5SDimitry Andric //=- AArch64ConditionOptimizer.cpp - Remove useless comparisons for AArch64 -=// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This pass tries to make consecutive compares of values use same operands to 100b57cec5SDimitry Andric // allow CSE pass to remove duplicated instructions. For this it analyzes 110b57cec5SDimitry Andric // branches and adjusts comparisons with immediate values by converting: 120b57cec5SDimitry Andric // * GE -> GT 130b57cec5SDimitry Andric // * GT -> GE 140b57cec5SDimitry Andric // * LT -> LE 150b57cec5SDimitry Andric // * LE -> LT 160b57cec5SDimitry Andric // and adjusting immediate values appropriately. It basically corrects two 170b57cec5SDimitry Andric // immediate values towards each other to make them equal. 180b57cec5SDimitry Andric // 190b57cec5SDimitry Andric // Consider the following example in C: 200b57cec5SDimitry Andric // 210b57cec5SDimitry Andric // if ((a < 5 && ...) || (a > 5 && ...)) { 220b57cec5SDimitry Andric // ~~~~~ ~~~~~ 230b57cec5SDimitry Andric // ^ ^ 240b57cec5SDimitry Andric // x y 250b57cec5SDimitry Andric // 260b57cec5SDimitry Andric // Here both "x" and "y" expressions compare "a" with "5". When "x" evaluates 270b57cec5SDimitry Andric // to "false", "y" can just check flags set by the first comparison. As a 280b57cec5SDimitry Andric // result of the canonicalization employed by 290b57cec5SDimitry Andric // SelectionDAGBuilder::visitSwitchCase, DAGCombine, and other target-specific 300b57cec5SDimitry Andric // code, assembly ends up in the form that is not CSE friendly: 310b57cec5SDimitry Andric // 320b57cec5SDimitry Andric // ... 330b57cec5SDimitry Andric // cmp w8, #4 340b57cec5SDimitry Andric // b.gt .LBB0_3 350b57cec5SDimitry Andric // ... 360b57cec5SDimitry Andric // .LBB0_3: 370b57cec5SDimitry Andric // cmp w8, #6 380b57cec5SDimitry Andric // b.lt .LBB0_6 390b57cec5SDimitry Andric // ... 400b57cec5SDimitry Andric // 410b57cec5SDimitry Andric // Same assembly after the pass: 420b57cec5SDimitry Andric // 430b57cec5SDimitry Andric // ... 440b57cec5SDimitry Andric // cmp w8, #5 450b57cec5SDimitry Andric // b.ge .LBB0_3 460b57cec5SDimitry Andric // ... 470b57cec5SDimitry Andric // .LBB0_3: 480b57cec5SDimitry Andric // cmp w8, #5 // <-- CSE pass removes this instruction 490b57cec5SDimitry Andric // b.le .LBB0_6 500b57cec5SDimitry Andric // ... 510b57cec5SDimitry Andric // 520b57cec5SDimitry Andric // Currently only SUBS and ADDS followed by b.?? are supported. 530b57cec5SDimitry Andric // 540b57cec5SDimitry Andric // TODO: maybe handle TBNZ/TBZ the same way as CMP when used instead for "a < 0" 550b57cec5SDimitry Andric // TODO: handle other conditional instructions (e.g. CSET) 560b57cec5SDimitry Andric // TODO: allow second branching to be anything if it doesn't require adjusting 570b57cec5SDimitry Andric // 580b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric #include "AArch64.h" 610b57cec5SDimitry Andric #include "MCTargetDesc/AArch64AddressingModes.h" 620b57cec5SDimitry Andric #include "Utils/AArch64BaseInfo.h" 630b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h" 640b57cec5SDimitry Andric #include "llvm/ADT/DepthFirstIterator.h" 650b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 660b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h" 670b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 680b57cec5SDimitry Andric #include "llvm/CodeGen/MachineDominators.h" 690b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 700b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 710b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 720b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 730b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 740b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 750b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h" 760b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h" 77480093f4SDimitry Andric #include "llvm/InitializePasses.h" 780b57cec5SDimitry Andric #include "llvm/Pass.h" 790b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 800b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 810b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 820b57cec5SDimitry Andric #include <cassert> 830b57cec5SDimitry Andric #include <cstdlib> 840b57cec5SDimitry Andric #include <tuple> 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric using namespace llvm; 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric #define DEBUG_TYPE "aarch64-condopt" 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric STATISTIC(NumConditionsAdjusted, "Number of conditions adjusted"); 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric namespace { 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric class AArch64ConditionOptimizer : public MachineFunctionPass { 950b57cec5SDimitry Andric const TargetInstrInfo *TII; 960b57cec5SDimitry Andric MachineDominatorTree *DomTree; 970b57cec5SDimitry Andric const MachineRegisterInfo *MRI; 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric public: 1000b57cec5SDimitry Andric // Stores immediate, compare instruction opcode and branch condition (in this 1010b57cec5SDimitry Andric // order) of adjusted comparison. 1020b57cec5SDimitry Andric using CmpInfo = std::tuple<int, unsigned, AArch64CC::CondCode>; 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric static char ID; 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric AArch64ConditionOptimizer() : MachineFunctionPass(ID) { 1070b57cec5SDimitry Andric initializeAArch64ConditionOptimizerPass(*PassRegistry::getPassRegistry()); 1080b57cec5SDimitry Andric } 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override; 1110b57cec5SDimitry Andric MachineInstr *findSuitableCompare(MachineBasicBlock *MBB); 1120b57cec5SDimitry Andric CmpInfo adjustCmp(MachineInstr *CmpMI, AArch64CC::CondCode Cmp); 1130b57cec5SDimitry Andric void modifyCmp(MachineInstr *CmpMI, const CmpInfo &Info); 1140b57cec5SDimitry Andric bool adjustTo(MachineInstr *CmpMI, AArch64CC::CondCode Cmp, MachineInstr *To, 1150b57cec5SDimitry Andric int ToImm); 1160b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric StringRef getPassName() const override { 1190b57cec5SDimitry Andric return "AArch64 Condition Optimizer"; 1200b57cec5SDimitry Andric } 1210b57cec5SDimitry Andric }; 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric } // end anonymous namespace 1240b57cec5SDimitry Andric 1250b57cec5SDimitry Andric char AArch64ConditionOptimizer::ID = 0; 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(AArch64ConditionOptimizer, "aarch64-condopt", 1280b57cec5SDimitry Andric "AArch64 CondOpt Pass", false, false) 129*0fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass) 1300b57cec5SDimitry Andric INITIALIZE_PASS_END(AArch64ConditionOptimizer, "aarch64-condopt", 1310b57cec5SDimitry Andric "AArch64 CondOpt Pass", false, false) 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric FunctionPass *llvm::createAArch64ConditionOptimizerPass() { 1340b57cec5SDimitry Andric return new AArch64ConditionOptimizer(); 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric void AArch64ConditionOptimizer::getAnalysisUsage(AnalysisUsage &AU) const { 138*0fca6ea1SDimitry Andric AU.addRequired<MachineDominatorTreeWrapperPass>(); 139*0fca6ea1SDimitry Andric AU.addPreserved<MachineDominatorTreeWrapperPass>(); 1400b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 1410b57cec5SDimitry Andric } 1420b57cec5SDimitry Andric 1430b57cec5SDimitry Andric // Finds compare instruction that corresponds to supported types of branching. 1440b57cec5SDimitry Andric // Returns the instruction or nullptr on failures or detecting unsupported 1450b57cec5SDimitry Andric // instructions. 1460b57cec5SDimitry Andric MachineInstr *AArch64ConditionOptimizer::findSuitableCompare( 1470b57cec5SDimitry Andric MachineBasicBlock *MBB) { 1485ffd83dbSDimitry Andric MachineBasicBlock::iterator Term = MBB->getFirstTerminator(); 1495ffd83dbSDimitry Andric if (Term == MBB->end()) 1500b57cec5SDimitry Andric return nullptr; 1510b57cec5SDimitry Andric 1525ffd83dbSDimitry Andric if (Term->getOpcode() != AArch64::Bcc) 1530b57cec5SDimitry Andric return nullptr; 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric // Since we may modify cmp of this MBB, make sure NZCV does not live out. 156bdd1243dSDimitry Andric for (auto *SuccBB : MBB->successors()) 1570b57cec5SDimitry Andric if (SuccBB->isLiveIn(AArch64::NZCV)) 1580b57cec5SDimitry Andric return nullptr; 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric // Now find the instruction controlling the terminator. 1615ffd83dbSDimitry Andric for (MachineBasicBlock::iterator B = MBB->begin(), It = Term; It != B;) { 1625ffd83dbSDimitry Andric It = prev_nodbg(It, B); 1635ffd83dbSDimitry Andric MachineInstr &I = *It; 1645ffd83dbSDimitry Andric assert(!I.isTerminator() && "Spurious terminator"); 1650b57cec5SDimitry Andric // Check if there is any use of NZCV between CMP and Bcc. 166*0fca6ea1SDimitry Andric if (I.readsRegister(AArch64::NZCV, /*TRI=*/nullptr)) 1670b57cec5SDimitry Andric return nullptr; 1685ffd83dbSDimitry Andric switch (I.getOpcode()) { 1690b57cec5SDimitry Andric // cmp is an alias for subs with a dead destination register. 1700b57cec5SDimitry Andric case AArch64::SUBSWri: 1710b57cec5SDimitry Andric case AArch64::SUBSXri: 1720b57cec5SDimitry Andric // cmn is an alias for adds with a dead destination register. 1730b57cec5SDimitry Andric case AArch64::ADDSWri: 1740b57cec5SDimitry Andric case AArch64::ADDSXri: { 1755ffd83dbSDimitry Andric unsigned ShiftAmt = AArch64_AM::getShiftValue(I.getOperand(3).getImm()); 1765ffd83dbSDimitry Andric if (!I.getOperand(2).isImm()) { 1775ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Immediate of cmp is symbolic, " << I << '\n'); 1780b57cec5SDimitry Andric return nullptr; 1795ffd83dbSDimitry Andric } else if (I.getOperand(2).getImm() << ShiftAmt >= 0xfff) { 1805ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Immediate of cmp may be out of range, " << I 1810b57cec5SDimitry Andric << '\n'); 1820b57cec5SDimitry Andric return nullptr; 1835ffd83dbSDimitry Andric } else if (!MRI->use_nodbg_empty(I.getOperand(0).getReg())) { 1845ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Destination of cmp is not dead, " << I << '\n'); 1850b57cec5SDimitry Andric return nullptr; 1860b57cec5SDimitry Andric } 1875ffd83dbSDimitry Andric return &I; 1880b57cec5SDimitry Andric } 1890b57cec5SDimitry Andric // Prevent false positive case like: 1900b57cec5SDimitry Andric // cmp w19, #0 1910b57cec5SDimitry Andric // cinc w0, w19, gt 1920b57cec5SDimitry Andric // ... 1930b57cec5SDimitry Andric // fcmp d8, #0.0 1940b57cec5SDimitry Andric // b.gt .LBB0_5 1950b57cec5SDimitry Andric case AArch64::FCMPDri: 1960b57cec5SDimitry Andric case AArch64::FCMPSri: 1970b57cec5SDimitry Andric case AArch64::FCMPESri: 1980b57cec5SDimitry Andric case AArch64::FCMPEDri: 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric case AArch64::SUBSWrr: 2010b57cec5SDimitry Andric case AArch64::SUBSXrr: 2020b57cec5SDimitry Andric case AArch64::ADDSWrr: 2030b57cec5SDimitry Andric case AArch64::ADDSXrr: 2040b57cec5SDimitry Andric case AArch64::FCMPSrr: 2050b57cec5SDimitry Andric case AArch64::FCMPDrr: 2060b57cec5SDimitry Andric case AArch64::FCMPESrr: 2070b57cec5SDimitry Andric case AArch64::FCMPEDrr: 2080b57cec5SDimitry Andric // Skip comparison instructions without immediate operands. 2090b57cec5SDimitry Andric return nullptr; 2100b57cec5SDimitry Andric } 2110b57cec5SDimitry Andric } 2120b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Flags not defined in " << printMBBReference(*MBB) 2130b57cec5SDimitry Andric << '\n'); 2140b57cec5SDimitry Andric return nullptr; 2150b57cec5SDimitry Andric } 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric // Changes opcode adds <-> subs considering register operand width. 2180b57cec5SDimitry Andric static int getComplementOpc(int Opc) { 2190b57cec5SDimitry Andric switch (Opc) { 2200b57cec5SDimitry Andric case AArch64::ADDSWri: return AArch64::SUBSWri; 2210b57cec5SDimitry Andric case AArch64::ADDSXri: return AArch64::SUBSXri; 2220b57cec5SDimitry Andric case AArch64::SUBSWri: return AArch64::ADDSWri; 2230b57cec5SDimitry Andric case AArch64::SUBSXri: return AArch64::ADDSXri; 2240b57cec5SDimitry Andric default: 2250b57cec5SDimitry Andric llvm_unreachable("Unexpected opcode"); 2260b57cec5SDimitry Andric } 2270b57cec5SDimitry Andric } 2280b57cec5SDimitry Andric 2290b57cec5SDimitry Andric // Changes form of comparison inclusive <-> exclusive. 2300b57cec5SDimitry Andric static AArch64CC::CondCode getAdjustedCmp(AArch64CC::CondCode Cmp) { 2310b57cec5SDimitry Andric switch (Cmp) { 2320b57cec5SDimitry Andric case AArch64CC::GT: return AArch64CC::GE; 2330b57cec5SDimitry Andric case AArch64CC::GE: return AArch64CC::GT; 2340b57cec5SDimitry Andric case AArch64CC::LT: return AArch64CC::LE; 2350b57cec5SDimitry Andric case AArch64CC::LE: return AArch64CC::LT; 2360b57cec5SDimitry Andric default: 2370b57cec5SDimitry Andric llvm_unreachable("Unexpected condition code"); 2380b57cec5SDimitry Andric } 2390b57cec5SDimitry Andric } 2400b57cec5SDimitry Andric 2410b57cec5SDimitry Andric // Transforms GT -> GE, GE -> GT, LT -> LE, LE -> LT by updating comparison 2420b57cec5SDimitry Andric // operator and condition code. 2430b57cec5SDimitry Andric AArch64ConditionOptimizer::CmpInfo AArch64ConditionOptimizer::adjustCmp( 2440b57cec5SDimitry Andric MachineInstr *CmpMI, AArch64CC::CondCode Cmp) { 2450b57cec5SDimitry Andric unsigned Opc = CmpMI->getOpcode(); 2460b57cec5SDimitry Andric 2470b57cec5SDimitry Andric // CMN (compare with negative immediate) is an alias to ADDS (as 2480b57cec5SDimitry Andric // "operand - negative" == "operand + positive") 2490b57cec5SDimitry Andric bool Negative = (Opc == AArch64::ADDSWri || Opc == AArch64::ADDSXri); 2500b57cec5SDimitry Andric 2510b57cec5SDimitry Andric int Correction = (Cmp == AArch64CC::GT) ? 1 : -1; 2520b57cec5SDimitry Andric // Negate Correction value for comparison with negative immediate (CMN). 2530b57cec5SDimitry Andric if (Negative) { 2540b57cec5SDimitry Andric Correction = -Correction; 2550b57cec5SDimitry Andric } 2560b57cec5SDimitry Andric 2570b57cec5SDimitry Andric const int OldImm = (int)CmpMI->getOperand(2).getImm(); 2580b57cec5SDimitry Andric const int NewImm = std::abs(OldImm + Correction); 2590b57cec5SDimitry Andric 2600b57cec5SDimitry Andric // Handle +0 -> -1 and -0 -> +1 (CMN with 0 immediate) transitions by 2610b57cec5SDimitry Andric // adjusting compare instruction opcode. 2620b57cec5SDimitry Andric if (OldImm == 0 && ((Negative && Correction == 1) || 2630b57cec5SDimitry Andric (!Negative && Correction == -1))) { 2640b57cec5SDimitry Andric Opc = getComplementOpc(Opc); 2650b57cec5SDimitry Andric } 2660b57cec5SDimitry Andric 2670b57cec5SDimitry Andric return CmpInfo(NewImm, Opc, getAdjustedCmp(Cmp)); 2680b57cec5SDimitry Andric } 2690b57cec5SDimitry Andric 2700b57cec5SDimitry Andric // Applies changes to comparison instruction suggested by adjustCmp(). 2710b57cec5SDimitry Andric void AArch64ConditionOptimizer::modifyCmp(MachineInstr *CmpMI, 2720b57cec5SDimitry Andric const CmpInfo &Info) { 2730b57cec5SDimitry Andric int Imm; 2740b57cec5SDimitry Andric unsigned Opc; 2750b57cec5SDimitry Andric AArch64CC::CondCode Cmp; 2760b57cec5SDimitry Andric std::tie(Imm, Opc, Cmp) = Info; 2770b57cec5SDimitry Andric 2780b57cec5SDimitry Andric MachineBasicBlock *const MBB = CmpMI->getParent(); 2790b57cec5SDimitry Andric 2800b57cec5SDimitry Andric // Change immediate in comparison instruction (ADDS or SUBS). 2810b57cec5SDimitry Andric BuildMI(*MBB, CmpMI, CmpMI->getDebugLoc(), TII->get(Opc)) 2820b57cec5SDimitry Andric .add(CmpMI->getOperand(0)) 2830b57cec5SDimitry Andric .add(CmpMI->getOperand(1)) 2840b57cec5SDimitry Andric .addImm(Imm) 2850b57cec5SDimitry Andric .add(CmpMI->getOperand(3)); 2860b57cec5SDimitry Andric CmpMI->eraseFromParent(); 2870b57cec5SDimitry Andric 2880b57cec5SDimitry Andric // The fact that this comparison was picked ensures that it's related to the 2890b57cec5SDimitry Andric // first terminator instruction. 2900b57cec5SDimitry Andric MachineInstr &BrMI = *MBB->getFirstTerminator(); 2910b57cec5SDimitry Andric 2920b57cec5SDimitry Andric // Change condition in branch instruction. 2930b57cec5SDimitry Andric BuildMI(*MBB, BrMI, BrMI.getDebugLoc(), TII->get(AArch64::Bcc)) 2940b57cec5SDimitry Andric .addImm(Cmp) 2950b57cec5SDimitry Andric .add(BrMI.getOperand(1)); 2960b57cec5SDimitry Andric BrMI.eraseFromParent(); 2970b57cec5SDimitry Andric 2980b57cec5SDimitry Andric ++NumConditionsAdjusted; 2990b57cec5SDimitry Andric } 3000b57cec5SDimitry Andric 3015ffd83dbSDimitry Andric // Parse a condition code returned by analyzeBranch, and compute the CondCode 3020b57cec5SDimitry Andric // corresponding to TBB. 3030b57cec5SDimitry Andric // Returns true if parsing was successful, otherwise false is returned. 3040b57cec5SDimitry Andric static bool parseCond(ArrayRef<MachineOperand> Cond, AArch64CC::CondCode &CC) { 3050b57cec5SDimitry Andric // A normal br.cond simply has the condition code. 3060b57cec5SDimitry Andric if (Cond[0].getImm() != -1) { 3070b57cec5SDimitry Andric assert(Cond.size() == 1 && "Unknown Cond array format"); 3080b57cec5SDimitry Andric CC = (AArch64CC::CondCode)(int)Cond[0].getImm(); 3090b57cec5SDimitry Andric return true; 3100b57cec5SDimitry Andric } 3110b57cec5SDimitry Andric return false; 3120b57cec5SDimitry Andric } 3130b57cec5SDimitry Andric 3140b57cec5SDimitry Andric // Adjusts one cmp instruction to another one if result of adjustment will allow 3150b57cec5SDimitry Andric // CSE. Returns true if compare instruction was changed, otherwise false is 3160b57cec5SDimitry Andric // returned. 3170b57cec5SDimitry Andric bool AArch64ConditionOptimizer::adjustTo(MachineInstr *CmpMI, 3180b57cec5SDimitry Andric AArch64CC::CondCode Cmp, MachineInstr *To, int ToImm) 3190b57cec5SDimitry Andric { 3200b57cec5SDimitry Andric CmpInfo Info = adjustCmp(CmpMI, Cmp); 3210b57cec5SDimitry Andric if (std::get<0>(Info) == ToImm && std::get<1>(Info) == To->getOpcode()) { 3220b57cec5SDimitry Andric modifyCmp(CmpMI, Info); 3230b57cec5SDimitry Andric return true; 3240b57cec5SDimitry Andric } 3250b57cec5SDimitry Andric return false; 3260b57cec5SDimitry Andric } 3270b57cec5SDimitry Andric 3280b57cec5SDimitry Andric bool AArch64ConditionOptimizer::runOnMachineFunction(MachineFunction &MF) { 3290b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "********** AArch64 Conditional Compares **********\n" 3300b57cec5SDimitry Andric << "********** Function: " << MF.getName() << '\n'); 3310b57cec5SDimitry Andric if (skipFunction(MF.getFunction())) 3320b57cec5SDimitry Andric return false; 3330b57cec5SDimitry Andric 3340b57cec5SDimitry Andric TII = MF.getSubtarget().getInstrInfo(); 335*0fca6ea1SDimitry Andric DomTree = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree(); 3360b57cec5SDimitry Andric MRI = &MF.getRegInfo(); 3370b57cec5SDimitry Andric 3380b57cec5SDimitry Andric bool Changed = false; 3390b57cec5SDimitry Andric 3400b57cec5SDimitry Andric // Visit blocks in dominator tree pre-order. The pre-order enables multiple 3410b57cec5SDimitry Andric // cmp-conversions from the same head block. 3420b57cec5SDimitry Andric // Note that updateDomTree() modifies the children of the DomTree node 3430b57cec5SDimitry Andric // currently being visited. The df_iterator supports that; it doesn't look at 3440b57cec5SDimitry Andric // child_begin() / child_end() until after a node has been visited. 3450b57cec5SDimitry Andric for (MachineDomTreeNode *I : depth_first(DomTree)) { 3460b57cec5SDimitry Andric MachineBasicBlock *HBB = I->getBlock(); 3470b57cec5SDimitry Andric 3480b57cec5SDimitry Andric SmallVector<MachineOperand, 4> HeadCond; 3490b57cec5SDimitry Andric MachineBasicBlock *TBB = nullptr, *FBB = nullptr; 3500b57cec5SDimitry Andric if (TII->analyzeBranch(*HBB, TBB, FBB, HeadCond)) { 3510b57cec5SDimitry Andric continue; 3520b57cec5SDimitry Andric } 3530b57cec5SDimitry Andric 3540b57cec5SDimitry Andric // Equivalence check is to skip loops. 3550b57cec5SDimitry Andric if (!TBB || TBB == HBB) { 3560b57cec5SDimitry Andric continue; 3570b57cec5SDimitry Andric } 3580b57cec5SDimitry Andric 3590b57cec5SDimitry Andric SmallVector<MachineOperand, 4> TrueCond; 3600b57cec5SDimitry Andric MachineBasicBlock *TBB_TBB = nullptr, *TBB_FBB = nullptr; 3610b57cec5SDimitry Andric if (TII->analyzeBranch(*TBB, TBB_TBB, TBB_FBB, TrueCond)) { 3620b57cec5SDimitry Andric continue; 3630b57cec5SDimitry Andric } 3640b57cec5SDimitry Andric 3650b57cec5SDimitry Andric MachineInstr *HeadCmpMI = findSuitableCompare(HBB); 3660b57cec5SDimitry Andric if (!HeadCmpMI) { 3670b57cec5SDimitry Andric continue; 3680b57cec5SDimitry Andric } 3690b57cec5SDimitry Andric 3700b57cec5SDimitry Andric MachineInstr *TrueCmpMI = findSuitableCompare(TBB); 3710b57cec5SDimitry Andric if (!TrueCmpMI) { 3720b57cec5SDimitry Andric continue; 3730b57cec5SDimitry Andric } 3740b57cec5SDimitry Andric 3750b57cec5SDimitry Andric AArch64CC::CondCode HeadCmp; 3760b57cec5SDimitry Andric if (HeadCond.empty() || !parseCond(HeadCond, HeadCmp)) { 3770b57cec5SDimitry Andric continue; 3780b57cec5SDimitry Andric } 3790b57cec5SDimitry Andric 3800b57cec5SDimitry Andric AArch64CC::CondCode TrueCmp; 3810b57cec5SDimitry Andric if (TrueCond.empty() || !parseCond(TrueCond, TrueCmp)) { 3820b57cec5SDimitry Andric continue; 3830b57cec5SDimitry Andric } 3840b57cec5SDimitry Andric 3850b57cec5SDimitry Andric const int HeadImm = (int)HeadCmpMI->getOperand(2).getImm(); 3860b57cec5SDimitry Andric const int TrueImm = (int)TrueCmpMI->getOperand(2).getImm(); 3870b57cec5SDimitry Andric 3880b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Head branch:\n"); 3890b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\tcondition: " << AArch64CC::getCondCodeName(HeadCmp) 3900b57cec5SDimitry Andric << '\n'); 3910b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\timmediate: " << HeadImm << '\n'); 3920b57cec5SDimitry Andric 3930b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "True branch:\n"); 3940b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\tcondition: " << AArch64CC::getCondCodeName(TrueCmp) 3950b57cec5SDimitry Andric << '\n'); 3960b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\timmediate: " << TrueImm << '\n'); 3970b57cec5SDimitry Andric 3980b57cec5SDimitry Andric if (((HeadCmp == AArch64CC::GT && TrueCmp == AArch64CC::LT) || 3990b57cec5SDimitry Andric (HeadCmp == AArch64CC::LT && TrueCmp == AArch64CC::GT)) && 4000b57cec5SDimitry Andric std::abs(TrueImm - HeadImm) == 2) { 4010b57cec5SDimitry Andric // This branch transforms machine instructions that correspond to 4020b57cec5SDimitry Andric // 4030b57cec5SDimitry Andric // 1) (a > {TrueImm} && ...) || (a < {HeadImm} && ...) 4040b57cec5SDimitry Andric // 2) (a < {TrueImm} && ...) || (a > {HeadImm} && ...) 4050b57cec5SDimitry Andric // 4060b57cec5SDimitry Andric // into 4070b57cec5SDimitry Andric // 4080b57cec5SDimitry Andric // 1) (a >= {NewImm} && ...) || (a <= {NewImm} && ...) 4090b57cec5SDimitry Andric // 2) (a <= {NewImm} && ...) || (a >= {NewImm} && ...) 4100b57cec5SDimitry Andric 4110b57cec5SDimitry Andric CmpInfo HeadCmpInfo = adjustCmp(HeadCmpMI, HeadCmp); 4120b57cec5SDimitry Andric CmpInfo TrueCmpInfo = adjustCmp(TrueCmpMI, TrueCmp); 4130b57cec5SDimitry Andric if (std::get<0>(HeadCmpInfo) == std::get<0>(TrueCmpInfo) && 4140b57cec5SDimitry Andric std::get<1>(HeadCmpInfo) == std::get<1>(TrueCmpInfo)) { 4150b57cec5SDimitry Andric modifyCmp(HeadCmpMI, HeadCmpInfo); 4160b57cec5SDimitry Andric modifyCmp(TrueCmpMI, TrueCmpInfo); 4170b57cec5SDimitry Andric Changed = true; 4180b57cec5SDimitry Andric } 4190b57cec5SDimitry Andric } else if (((HeadCmp == AArch64CC::GT && TrueCmp == AArch64CC::GT) || 4200b57cec5SDimitry Andric (HeadCmp == AArch64CC::LT && TrueCmp == AArch64CC::LT)) && 4210b57cec5SDimitry Andric std::abs(TrueImm - HeadImm) == 1) { 4220b57cec5SDimitry Andric // This branch transforms machine instructions that correspond to 4230b57cec5SDimitry Andric // 4240b57cec5SDimitry Andric // 1) (a > {TrueImm} && ...) || (a > {HeadImm} && ...) 4250b57cec5SDimitry Andric // 2) (a < {TrueImm} && ...) || (a < {HeadImm} && ...) 4260b57cec5SDimitry Andric // 4270b57cec5SDimitry Andric // into 4280b57cec5SDimitry Andric // 4290b57cec5SDimitry Andric // 1) (a <= {NewImm} && ...) || (a > {NewImm} && ...) 4300b57cec5SDimitry Andric // 2) (a < {NewImm} && ...) || (a >= {NewImm} && ...) 4310b57cec5SDimitry Andric 4320b57cec5SDimitry Andric // GT -> GE transformation increases immediate value, so picking the 4330b57cec5SDimitry Andric // smaller one; LT -> LE decreases immediate value so invert the choice. 4340b57cec5SDimitry Andric bool adjustHeadCond = (HeadImm < TrueImm); 4350b57cec5SDimitry Andric if (HeadCmp == AArch64CC::LT) { 4360b57cec5SDimitry Andric adjustHeadCond = !adjustHeadCond; 4370b57cec5SDimitry Andric } 4380b57cec5SDimitry Andric 4390b57cec5SDimitry Andric if (adjustHeadCond) { 4400b57cec5SDimitry Andric Changed |= adjustTo(HeadCmpMI, HeadCmp, TrueCmpMI, TrueImm); 4410b57cec5SDimitry Andric } else { 4420b57cec5SDimitry Andric Changed |= adjustTo(TrueCmpMI, TrueCmp, HeadCmpMI, HeadImm); 4430b57cec5SDimitry Andric } 4440b57cec5SDimitry Andric } 4450b57cec5SDimitry Andric // Other transformation cases almost never occur due to generation of < or > 4460b57cec5SDimitry Andric // comparisons instead of <= and >=. 4470b57cec5SDimitry Andric } 4480b57cec5SDimitry Andric 4490b57cec5SDimitry Andric return Changed; 4500b57cec5SDimitry Andric } 451