1*0b57cec5SDimitry Andric //===-- SystemZElimCompare.cpp - Eliminate comparison instructions --------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This pass: 10*0b57cec5SDimitry Andric // (1) tries to remove compares if CC already contains the required information 11*0b57cec5SDimitry Andric // (2) fuses compares and branches into COMPARE AND BRANCH instructions 12*0b57cec5SDimitry Andric // 13*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 14*0b57cec5SDimitry Andric 15*0b57cec5SDimitry Andric #include "SystemZ.h" 16*0b57cec5SDimitry Andric #include "SystemZInstrInfo.h" 17*0b57cec5SDimitry Andric #include "SystemZTargetMachine.h" 18*0b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 19*0b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h" 20*0b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 21*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 22*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 23*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 24*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 25*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 26*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 27*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 28*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h" 29*0b57cec5SDimitry Andric #include "llvm/MC/MCInstrDesc.h" 30*0b57cec5SDimitry Andric #include <cassert> 31*0b57cec5SDimitry Andric #include <cstdint> 32*0b57cec5SDimitry Andric 33*0b57cec5SDimitry Andric using namespace llvm; 34*0b57cec5SDimitry Andric 35*0b57cec5SDimitry Andric #define DEBUG_TYPE "systemz-elim-compare" 36*0b57cec5SDimitry Andric 37*0b57cec5SDimitry Andric STATISTIC(BranchOnCounts, "Number of branch-on-count instructions"); 38*0b57cec5SDimitry Andric STATISTIC(LoadAndTraps, "Number of load-and-trap instructions"); 39*0b57cec5SDimitry Andric STATISTIC(EliminatedComparisons, "Number of eliminated comparisons"); 40*0b57cec5SDimitry Andric STATISTIC(FusedComparisons, "Number of fused compare-and-branch instructions"); 41*0b57cec5SDimitry Andric 42*0b57cec5SDimitry Andric namespace { 43*0b57cec5SDimitry Andric 44*0b57cec5SDimitry Andric // Represents the references to a particular register in one or more 45*0b57cec5SDimitry Andric // instructions. 46*0b57cec5SDimitry Andric struct Reference { 47*0b57cec5SDimitry Andric Reference() = default; 48*0b57cec5SDimitry Andric 49*0b57cec5SDimitry Andric Reference &operator|=(const Reference &Other) { 50*0b57cec5SDimitry Andric Def |= Other.Def; 51*0b57cec5SDimitry Andric Use |= Other.Use; 52*0b57cec5SDimitry Andric return *this; 53*0b57cec5SDimitry Andric } 54*0b57cec5SDimitry Andric 55*0b57cec5SDimitry Andric explicit operator bool() const { return Def || Use; } 56*0b57cec5SDimitry Andric 57*0b57cec5SDimitry Andric // True if the register is defined or used in some form, either directly or 58*0b57cec5SDimitry Andric // via a sub- or super-register. 59*0b57cec5SDimitry Andric bool Def = false; 60*0b57cec5SDimitry Andric bool Use = false; 61*0b57cec5SDimitry Andric }; 62*0b57cec5SDimitry Andric 63*0b57cec5SDimitry Andric class SystemZElimCompare : public MachineFunctionPass { 64*0b57cec5SDimitry Andric public: 65*0b57cec5SDimitry Andric static char ID; 66*0b57cec5SDimitry Andric 67*0b57cec5SDimitry Andric SystemZElimCompare(const SystemZTargetMachine &tm) 68*0b57cec5SDimitry Andric : MachineFunctionPass(ID) {} 69*0b57cec5SDimitry Andric 70*0b57cec5SDimitry Andric StringRef getPassName() const override { 71*0b57cec5SDimitry Andric return "SystemZ Comparison Elimination"; 72*0b57cec5SDimitry Andric } 73*0b57cec5SDimitry Andric 74*0b57cec5SDimitry Andric bool processBlock(MachineBasicBlock &MBB); 75*0b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &F) override; 76*0b57cec5SDimitry Andric 77*0b57cec5SDimitry Andric MachineFunctionProperties getRequiredProperties() const override { 78*0b57cec5SDimitry Andric return MachineFunctionProperties().set( 79*0b57cec5SDimitry Andric MachineFunctionProperties::Property::NoVRegs); 80*0b57cec5SDimitry Andric } 81*0b57cec5SDimitry Andric 82*0b57cec5SDimitry Andric private: 83*0b57cec5SDimitry Andric Reference getRegReferences(MachineInstr &MI, unsigned Reg); 84*0b57cec5SDimitry Andric bool convertToBRCT(MachineInstr &MI, MachineInstr &Compare, 85*0b57cec5SDimitry Andric SmallVectorImpl<MachineInstr *> &CCUsers); 86*0b57cec5SDimitry Andric bool convertToLoadAndTrap(MachineInstr &MI, MachineInstr &Compare, 87*0b57cec5SDimitry Andric SmallVectorImpl<MachineInstr *> &CCUsers); 88*0b57cec5SDimitry Andric bool convertToLoadAndTest(MachineInstr &MI, MachineInstr &Compare, 89*0b57cec5SDimitry Andric SmallVectorImpl<MachineInstr *> &CCUsers); 90*0b57cec5SDimitry Andric bool adjustCCMasksForInstr(MachineInstr &MI, MachineInstr &Compare, 91*0b57cec5SDimitry Andric SmallVectorImpl<MachineInstr *> &CCUsers, 92*0b57cec5SDimitry Andric unsigned ConvOpc = 0); 93*0b57cec5SDimitry Andric bool optimizeCompareZero(MachineInstr &Compare, 94*0b57cec5SDimitry Andric SmallVectorImpl<MachineInstr *> &CCUsers); 95*0b57cec5SDimitry Andric bool fuseCompareOperations(MachineInstr &Compare, 96*0b57cec5SDimitry Andric SmallVectorImpl<MachineInstr *> &CCUsers); 97*0b57cec5SDimitry Andric 98*0b57cec5SDimitry Andric const SystemZInstrInfo *TII = nullptr; 99*0b57cec5SDimitry Andric const TargetRegisterInfo *TRI = nullptr; 100*0b57cec5SDimitry Andric }; 101*0b57cec5SDimitry Andric 102*0b57cec5SDimitry Andric char SystemZElimCompare::ID = 0; 103*0b57cec5SDimitry Andric 104*0b57cec5SDimitry Andric } // end anonymous namespace 105*0b57cec5SDimitry Andric 106*0b57cec5SDimitry Andric // Return true if CC is live out of MBB. 107*0b57cec5SDimitry Andric static bool isCCLiveOut(MachineBasicBlock &MBB) { 108*0b57cec5SDimitry Andric for (auto SI = MBB.succ_begin(), SE = MBB.succ_end(); SI != SE; ++SI) 109*0b57cec5SDimitry Andric if ((*SI)->isLiveIn(SystemZ::CC)) 110*0b57cec5SDimitry Andric return true; 111*0b57cec5SDimitry Andric return false; 112*0b57cec5SDimitry Andric } 113*0b57cec5SDimitry Andric 114*0b57cec5SDimitry Andric // Returns true if MI is an instruction whose output equals the value in Reg. 115*0b57cec5SDimitry Andric static bool preservesValueOf(MachineInstr &MI, unsigned Reg) { 116*0b57cec5SDimitry Andric switch (MI.getOpcode()) { 117*0b57cec5SDimitry Andric case SystemZ::LR: 118*0b57cec5SDimitry Andric case SystemZ::LGR: 119*0b57cec5SDimitry Andric case SystemZ::LGFR: 120*0b57cec5SDimitry Andric case SystemZ::LTR: 121*0b57cec5SDimitry Andric case SystemZ::LTGR: 122*0b57cec5SDimitry Andric case SystemZ::LTGFR: 123*0b57cec5SDimitry Andric case SystemZ::LER: 124*0b57cec5SDimitry Andric case SystemZ::LDR: 125*0b57cec5SDimitry Andric case SystemZ::LXR: 126*0b57cec5SDimitry Andric case SystemZ::LTEBR: 127*0b57cec5SDimitry Andric case SystemZ::LTDBR: 128*0b57cec5SDimitry Andric case SystemZ::LTXBR: 129*0b57cec5SDimitry Andric if (MI.getOperand(1).getReg() == Reg) 130*0b57cec5SDimitry Andric return true; 131*0b57cec5SDimitry Andric } 132*0b57cec5SDimitry Andric 133*0b57cec5SDimitry Andric return false; 134*0b57cec5SDimitry Andric } 135*0b57cec5SDimitry Andric 136*0b57cec5SDimitry Andric // Return true if any CC result of MI would (perhaps after conversion) 137*0b57cec5SDimitry Andric // reflect the value of Reg. 138*0b57cec5SDimitry Andric static bool resultTests(MachineInstr &MI, unsigned Reg) { 139*0b57cec5SDimitry Andric if (MI.getNumOperands() > 0 && MI.getOperand(0).isReg() && 140*0b57cec5SDimitry Andric MI.getOperand(0).isDef() && MI.getOperand(0).getReg() == Reg) 141*0b57cec5SDimitry Andric return true; 142*0b57cec5SDimitry Andric 143*0b57cec5SDimitry Andric return (preservesValueOf(MI, Reg)); 144*0b57cec5SDimitry Andric } 145*0b57cec5SDimitry Andric 146*0b57cec5SDimitry Andric // Describe the references to Reg or any of its aliases in MI. 147*0b57cec5SDimitry Andric Reference SystemZElimCompare::getRegReferences(MachineInstr &MI, unsigned Reg) { 148*0b57cec5SDimitry Andric Reference Ref; 149*0b57cec5SDimitry Andric if (MI.isDebugInstr()) 150*0b57cec5SDimitry Andric return Ref; 151*0b57cec5SDimitry Andric 152*0b57cec5SDimitry Andric for (unsigned I = 0, E = MI.getNumOperands(); I != E; ++I) { 153*0b57cec5SDimitry Andric const MachineOperand &MO = MI.getOperand(I); 154*0b57cec5SDimitry Andric if (MO.isReg()) { 155*0b57cec5SDimitry Andric if (unsigned MOReg = MO.getReg()) { 156*0b57cec5SDimitry Andric if (TRI->regsOverlap(MOReg, Reg)) { 157*0b57cec5SDimitry Andric if (MO.isUse()) 158*0b57cec5SDimitry Andric Ref.Use = true; 159*0b57cec5SDimitry Andric else if (MO.isDef()) 160*0b57cec5SDimitry Andric Ref.Def = true; 161*0b57cec5SDimitry Andric } 162*0b57cec5SDimitry Andric } 163*0b57cec5SDimitry Andric } 164*0b57cec5SDimitry Andric } 165*0b57cec5SDimitry Andric return Ref; 166*0b57cec5SDimitry Andric } 167*0b57cec5SDimitry Andric 168*0b57cec5SDimitry Andric // Return true if this is a load and test which can be optimized the 169*0b57cec5SDimitry Andric // same way as compare instruction. 170*0b57cec5SDimitry Andric static bool isLoadAndTestAsCmp(MachineInstr &MI) { 171*0b57cec5SDimitry Andric // If we during isel used a load-and-test as a compare with 0, the 172*0b57cec5SDimitry Andric // def operand is dead. 173*0b57cec5SDimitry Andric return (MI.getOpcode() == SystemZ::LTEBR || 174*0b57cec5SDimitry Andric MI.getOpcode() == SystemZ::LTDBR || 175*0b57cec5SDimitry Andric MI.getOpcode() == SystemZ::LTXBR) && 176*0b57cec5SDimitry Andric MI.getOperand(0).isDead(); 177*0b57cec5SDimitry Andric } 178*0b57cec5SDimitry Andric 179*0b57cec5SDimitry Andric // Return the source register of Compare, which is the unknown value 180*0b57cec5SDimitry Andric // being tested. 181*0b57cec5SDimitry Andric static unsigned getCompareSourceReg(MachineInstr &Compare) { 182*0b57cec5SDimitry Andric unsigned reg = 0; 183*0b57cec5SDimitry Andric if (Compare.isCompare()) 184*0b57cec5SDimitry Andric reg = Compare.getOperand(0).getReg(); 185*0b57cec5SDimitry Andric else if (isLoadAndTestAsCmp(Compare)) 186*0b57cec5SDimitry Andric reg = Compare.getOperand(1).getReg(); 187*0b57cec5SDimitry Andric assert(reg); 188*0b57cec5SDimitry Andric 189*0b57cec5SDimitry Andric return reg; 190*0b57cec5SDimitry Andric } 191*0b57cec5SDimitry Andric 192*0b57cec5SDimitry Andric // Compare compares the result of MI against zero. If MI is an addition 193*0b57cec5SDimitry Andric // of -1 and if CCUsers is a single branch on nonzero, eliminate the addition 194*0b57cec5SDimitry Andric // and convert the branch to a BRCT(G) or BRCTH. Return true on success. 195*0b57cec5SDimitry Andric bool SystemZElimCompare::convertToBRCT( 196*0b57cec5SDimitry Andric MachineInstr &MI, MachineInstr &Compare, 197*0b57cec5SDimitry Andric SmallVectorImpl<MachineInstr *> &CCUsers) { 198*0b57cec5SDimitry Andric // Check whether we have an addition of -1. 199*0b57cec5SDimitry Andric unsigned Opcode = MI.getOpcode(); 200*0b57cec5SDimitry Andric unsigned BRCT; 201*0b57cec5SDimitry Andric if (Opcode == SystemZ::AHI) 202*0b57cec5SDimitry Andric BRCT = SystemZ::BRCT; 203*0b57cec5SDimitry Andric else if (Opcode == SystemZ::AGHI) 204*0b57cec5SDimitry Andric BRCT = SystemZ::BRCTG; 205*0b57cec5SDimitry Andric else if (Opcode == SystemZ::AIH) 206*0b57cec5SDimitry Andric BRCT = SystemZ::BRCTH; 207*0b57cec5SDimitry Andric else 208*0b57cec5SDimitry Andric return false; 209*0b57cec5SDimitry Andric if (MI.getOperand(2).getImm() != -1) 210*0b57cec5SDimitry Andric return false; 211*0b57cec5SDimitry Andric 212*0b57cec5SDimitry Andric // Check whether we have a single JLH. 213*0b57cec5SDimitry Andric if (CCUsers.size() != 1) 214*0b57cec5SDimitry Andric return false; 215*0b57cec5SDimitry Andric MachineInstr *Branch = CCUsers[0]; 216*0b57cec5SDimitry Andric if (Branch->getOpcode() != SystemZ::BRC || 217*0b57cec5SDimitry Andric Branch->getOperand(0).getImm() != SystemZ::CCMASK_ICMP || 218*0b57cec5SDimitry Andric Branch->getOperand(1).getImm() != SystemZ::CCMASK_CMP_NE) 219*0b57cec5SDimitry Andric return false; 220*0b57cec5SDimitry Andric 221*0b57cec5SDimitry Andric // We already know that there are no references to the register between 222*0b57cec5SDimitry Andric // MI and Compare. Make sure that there are also no references between 223*0b57cec5SDimitry Andric // Compare and Branch. 224*0b57cec5SDimitry Andric unsigned SrcReg = getCompareSourceReg(Compare); 225*0b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI = Compare, MBBE = Branch; 226*0b57cec5SDimitry Andric for (++MBBI; MBBI != MBBE; ++MBBI) 227*0b57cec5SDimitry Andric if (getRegReferences(*MBBI, SrcReg)) 228*0b57cec5SDimitry Andric return false; 229*0b57cec5SDimitry Andric 230*0b57cec5SDimitry Andric // The transformation is OK. Rebuild Branch as a BRCT(G) or BRCTH. 231*0b57cec5SDimitry Andric MachineOperand Target(Branch->getOperand(2)); 232*0b57cec5SDimitry Andric while (Branch->getNumOperands()) 233*0b57cec5SDimitry Andric Branch->RemoveOperand(0); 234*0b57cec5SDimitry Andric Branch->setDesc(TII->get(BRCT)); 235*0b57cec5SDimitry Andric MachineInstrBuilder MIB(*Branch->getParent()->getParent(), Branch); 236*0b57cec5SDimitry Andric MIB.add(MI.getOperand(0)).add(MI.getOperand(1)).add(Target); 237*0b57cec5SDimitry Andric // Add a CC def to BRCT(G), since we may have to split them again if the 238*0b57cec5SDimitry Andric // branch displacement overflows. BRCTH has a 32-bit displacement, so 239*0b57cec5SDimitry Andric // this is not necessary there. 240*0b57cec5SDimitry Andric if (BRCT != SystemZ::BRCTH) 241*0b57cec5SDimitry Andric MIB.addReg(SystemZ::CC, RegState::ImplicitDefine | RegState::Dead); 242*0b57cec5SDimitry Andric MI.eraseFromParent(); 243*0b57cec5SDimitry Andric return true; 244*0b57cec5SDimitry Andric } 245*0b57cec5SDimitry Andric 246*0b57cec5SDimitry Andric // Compare compares the result of MI against zero. If MI is a suitable load 247*0b57cec5SDimitry Andric // instruction and if CCUsers is a single conditional trap on zero, eliminate 248*0b57cec5SDimitry Andric // the load and convert the branch to a load-and-trap. Return true on success. 249*0b57cec5SDimitry Andric bool SystemZElimCompare::convertToLoadAndTrap( 250*0b57cec5SDimitry Andric MachineInstr &MI, MachineInstr &Compare, 251*0b57cec5SDimitry Andric SmallVectorImpl<MachineInstr *> &CCUsers) { 252*0b57cec5SDimitry Andric unsigned LATOpcode = TII->getLoadAndTrap(MI.getOpcode()); 253*0b57cec5SDimitry Andric if (!LATOpcode) 254*0b57cec5SDimitry Andric return false; 255*0b57cec5SDimitry Andric 256*0b57cec5SDimitry Andric // Check whether we have a single CondTrap that traps on zero. 257*0b57cec5SDimitry Andric if (CCUsers.size() != 1) 258*0b57cec5SDimitry Andric return false; 259*0b57cec5SDimitry Andric MachineInstr *Branch = CCUsers[0]; 260*0b57cec5SDimitry Andric if (Branch->getOpcode() != SystemZ::CondTrap || 261*0b57cec5SDimitry Andric Branch->getOperand(0).getImm() != SystemZ::CCMASK_ICMP || 262*0b57cec5SDimitry Andric Branch->getOperand(1).getImm() != SystemZ::CCMASK_CMP_EQ) 263*0b57cec5SDimitry Andric return false; 264*0b57cec5SDimitry Andric 265*0b57cec5SDimitry Andric // We already know that there are no references to the register between 266*0b57cec5SDimitry Andric // MI and Compare. Make sure that there are also no references between 267*0b57cec5SDimitry Andric // Compare and Branch. 268*0b57cec5SDimitry Andric unsigned SrcReg = getCompareSourceReg(Compare); 269*0b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI = Compare, MBBE = Branch; 270*0b57cec5SDimitry Andric for (++MBBI; MBBI != MBBE; ++MBBI) 271*0b57cec5SDimitry Andric if (getRegReferences(*MBBI, SrcReg)) 272*0b57cec5SDimitry Andric return false; 273*0b57cec5SDimitry Andric 274*0b57cec5SDimitry Andric // The transformation is OK. Rebuild Branch as a load-and-trap. 275*0b57cec5SDimitry Andric while (Branch->getNumOperands()) 276*0b57cec5SDimitry Andric Branch->RemoveOperand(0); 277*0b57cec5SDimitry Andric Branch->setDesc(TII->get(LATOpcode)); 278*0b57cec5SDimitry Andric MachineInstrBuilder(*Branch->getParent()->getParent(), Branch) 279*0b57cec5SDimitry Andric .add(MI.getOperand(0)) 280*0b57cec5SDimitry Andric .add(MI.getOperand(1)) 281*0b57cec5SDimitry Andric .add(MI.getOperand(2)) 282*0b57cec5SDimitry Andric .add(MI.getOperand(3)); 283*0b57cec5SDimitry Andric MI.eraseFromParent(); 284*0b57cec5SDimitry Andric return true; 285*0b57cec5SDimitry Andric } 286*0b57cec5SDimitry Andric 287*0b57cec5SDimitry Andric // If MI is a load instruction, try to convert it into a LOAD AND TEST. 288*0b57cec5SDimitry Andric // Return true on success. 289*0b57cec5SDimitry Andric bool SystemZElimCompare::convertToLoadAndTest( 290*0b57cec5SDimitry Andric MachineInstr &MI, MachineInstr &Compare, 291*0b57cec5SDimitry Andric SmallVectorImpl<MachineInstr *> &CCUsers) { 292*0b57cec5SDimitry Andric 293*0b57cec5SDimitry Andric // Try to adjust CC masks for the LOAD AND TEST opcode that could replace MI. 294*0b57cec5SDimitry Andric unsigned Opcode = TII->getLoadAndTest(MI.getOpcode()); 295*0b57cec5SDimitry Andric if (!Opcode || !adjustCCMasksForInstr(MI, Compare, CCUsers, Opcode)) 296*0b57cec5SDimitry Andric return false; 297*0b57cec5SDimitry Andric 298*0b57cec5SDimitry Andric // Rebuild to get the CC operand in the right place. 299*0b57cec5SDimitry Andric auto MIB = BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(Opcode)); 300*0b57cec5SDimitry Andric for (const auto &MO : MI.operands()) 301*0b57cec5SDimitry Andric MIB.add(MO); 302*0b57cec5SDimitry Andric MIB.setMemRefs(MI.memoperands()); 303*0b57cec5SDimitry Andric MI.eraseFromParent(); 304*0b57cec5SDimitry Andric 305*0b57cec5SDimitry Andric return true; 306*0b57cec5SDimitry Andric } 307*0b57cec5SDimitry Andric 308*0b57cec5SDimitry Andric // The CC users in CCUsers are testing the result of a comparison of some 309*0b57cec5SDimitry Andric // value X against zero and we know that any CC value produced by MI would 310*0b57cec5SDimitry Andric // also reflect the value of X. ConvOpc may be used to pass the transfomed 311*0b57cec5SDimitry Andric // opcode MI will have if this succeeds. Try to adjust CCUsers so that they 312*0b57cec5SDimitry Andric // test the result of MI directly, returning true on success. Leave 313*0b57cec5SDimitry Andric // everything unchanged on failure. 314*0b57cec5SDimitry Andric bool SystemZElimCompare::adjustCCMasksForInstr( 315*0b57cec5SDimitry Andric MachineInstr &MI, MachineInstr &Compare, 316*0b57cec5SDimitry Andric SmallVectorImpl<MachineInstr *> &CCUsers, 317*0b57cec5SDimitry Andric unsigned ConvOpc) { 318*0b57cec5SDimitry Andric int Opcode = (ConvOpc ? ConvOpc : MI.getOpcode()); 319*0b57cec5SDimitry Andric const MCInstrDesc &Desc = TII->get(Opcode); 320*0b57cec5SDimitry Andric unsigned MIFlags = Desc.TSFlags; 321*0b57cec5SDimitry Andric 322*0b57cec5SDimitry Andric // See which compare-style condition codes are available. 323*0b57cec5SDimitry Andric unsigned ReusableCCMask = SystemZII::getCompareZeroCCMask(MIFlags); 324*0b57cec5SDimitry Andric 325*0b57cec5SDimitry Andric // For unsigned comparisons with zero, only equality makes sense. 326*0b57cec5SDimitry Andric unsigned CompareFlags = Compare.getDesc().TSFlags; 327*0b57cec5SDimitry Andric if (CompareFlags & SystemZII::IsLogical) 328*0b57cec5SDimitry Andric ReusableCCMask &= SystemZ::CCMASK_CMP_EQ; 329*0b57cec5SDimitry Andric 330*0b57cec5SDimitry Andric if (ReusableCCMask == 0) 331*0b57cec5SDimitry Andric return false; 332*0b57cec5SDimitry Andric 333*0b57cec5SDimitry Andric unsigned CCValues = SystemZII::getCCValues(MIFlags); 334*0b57cec5SDimitry Andric assert((ReusableCCMask & ~CCValues) == 0 && "Invalid CCValues"); 335*0b57cec5SDimitry Andric 336*0b57cec5SDimitry Andric bool MIEquivalentToCmp = 337*0b57cec5SDimitry Andric (ReusableCCMask == CCValues && 338*0b57cec5SDimitry Andric CCValues == SystemZII::getCCValues(CompareFlags)); 339*0b57cec5SDimitry Andric 340*0b57cec5SDimitry Andric if (!MIEquivalentToCmp) { 341*0b57cec5SDimitry Andric // Now check whether these flags are enough for all users. 342*0b57cec5SDimitry Andric SmallVector<MachineOperand *, 4> AlterMasks; 343*0b57cec5SDimitry Andric for (unsigned int I = 0, E = CCUsers.size(); I != E; ++I) { 344*0b57cec5SDimitry Andric MachineInstr *MI = CCUsers[I]; 345*0b57cec5SDimitry Andric 346*0b57cec5SDimitry Andric // Fail if this isn't a use of CC that we understand. 347*0b57cec5SDimitry Andric unsigned Flags = MI->getDesc().TSFlags; 348*0b57cec5SDimitry Andric unsigned FirstOpNum; 349*0b57cec5SDimitry Andric if (Flags & SystemZII::CCMaskFirst) 350*0b57cec5SDimitry Andric FirstOpNum = 0; 351*0b57cec5SDimitry Andric else if (Flags & SystemZII::CCMaskLast) 352*0b57cec5SDimitry Andric FirstOpNum = MI->getNumExplicitOperands() - 2; 353*0b57cec5SDimitry Andric else 354*0b57cec5SDimitry Andric return false; 355*0b57cec5SDimitry Andric 356*0b57cec5SDimitry Andric // Check whether the instruction predicate treats all CC values 357*0b57cec5SDimitry Andric // outside of ReusableCCMask in the same way. In that case it 358*0b57cec5SDimitry Andric // doesn't matter what those CC values mean. 359*0b57cec5SDimitry Andric unsigned CCValid = MI->getOperand(FirstOpNum).getImm(); 360*0b57cec5SDimitry Andric unsigned CCMask = MI->getOperand(FirstOpNum + 1).getImm(); 361*0b57cec5SDimitry Andric unsigned OutValid = ~ReusableCCMask & CCValid; 362*0b57cec5SDimitry Andric unsigned OutMask = ~ReusableCCMask & CCMask; 363*0b57cec5SDimitry Andric if (OutMask != 0 && OutMask != OutValid) 364*0b57cec5SDimitry Andric return false; 365*0b57cec5SDimitry Andric 366*0b57cec5SDimitry Andric AlterMasks.push_back(&MI->getOperand(FirstOpNum)); 367*0b57cec5SDimitry Andric AlterMasks.push_back(&MI->getOperand(FirstOpNum + 1)); 368*0b57cec5SDimitry Andric } 369*0b57cec5SDimitry Andric 370*0b57cec5SDimitry Andric // All users are OK. Adjust the masks for MI. 371*0b57cec5SDimitry Andric for (unsigned I = 0, E = AlterMasks.size(); I != E; I += 2) { 372*0b57cec5SDimitry Andric AlterMasks[I]->setImm(CCValues); 373*0b57cec5SDimitry Andric unsigned CCMask = AlterMasks[I + 1]->getImm(); 374*0b57cec5SDimitry Andric if (CCMask & ~ReusableCCMask) 375*0b57cec5SDimitry Andric AlterMasks[I + 1]->setImm((CCMask & ReusableCCMask) | 376*0b57cec5SDimitry Andric (CCValues & ~ReusableCCMask)); 377*0b57cec5SDimitry Andric } 378*0b57cec5SDimitry Andric } 379*0b57cec5SDimitry Andric 380*0b57cec5SDimitry Andric // CC is now live after MI. 381*0b57cec5SDimitry Andric if (!ConvOpc) { 382*0b57cec5SDimitry Andric int CCDef = MI.findRegisterDefOperandIdx(SystemZ::CC, false, true, TRI); 383*0b57cec5SDimitry Andric assert(CCDef >= 0 && "Couldn't find CC set"); 384*0b57cec5SDimitry Andric MI.getOperand(CCDef).setIsDead(false); 385*0b57cec5SDimitry Andric } 386*0b57cec5SDimitry Andric 387*0b57cec5SDimitry Andric // Check if MI lies before Compare. 388*0b57cec5SDimitry Andric bool BeforeCmp = false; 389*0b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI = MI, MBBE = MI.getParent()->end(); 390*0b57cec5SDimitry Andric for (++MBBI; MBBI != MBBE; ++MBBI) 391*0b57cec5SDimitry Andric if (MBBI == Compare) { 392*0b57cec5SDimitry Andric BeforeCmp = true; 393*0b57cec5SDimitry Andric break; 394*0b57cec5SDimitry Andric } 395*0b57cec5SDimitry Andric 396*0b57cec5SDimitry Andric // Clear any intervening kills of CC. 397*0b57cec5SDimitry Andric if (BeforeCmp) { 398*0b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI = MI, MBBE = Compare; 399*0b57cec5SDimitry Andric for (++MBBI; MBBI != MBBE; ++MBBI) 400*0b57cec5SDimitry Andric MBBI->clearRegisterKills(SystemZ::CC, TRI); 401*0b57cec5SDimitry Andric } 402*0b57cec5SDimitry Andric 403*0b57cec5SDimitry Andric return true; 404*0b57cec5SDimitry Andric } 405*0b57cec5SDimitry Andric 406*0b57cec5SDimitry Andric // Return true if Compare is a comparison against zero. 407*0b57cec5SDimitry Andric static bool isCompareZero(MachineInstr &Compare) { 408*0b57cec5SDimitry Andric switch (Compare.getOpcode()) { 409*0b57cec5SDimitry Andric case SystemZ::LTEBRCompare: 410*0b57cec5SDimitry Andric case SystemZ::LTDBRCompare: 411*0b57cec5SDimitry Andric case SystemZ::LTXBRCompare: 412*0b57cec5SDimitry Andric return true; 413*0b57cec5SDimitry Andric 414*0b57cec5SDimitry Andric default: 415*0b57cec5SDimitry Andric if (isLoadAndTestAsCmp(Compare)) 416*0b57cec5SDimitry Andric return true; 417*0b57cec5SDimitry Andric return Compare.getNumExplicitOperands() == 2 && 418*0b57cec5SDimitry Andric Compare.getOperand(1).isImm() && Compare.getOperand(1).getImm() == 0; 419*0b57cec5SDimitry Andric } 420*0b57cec5SDimitry Andric } 421*0b57cec5SDimitry Andric 422*0b57cec5SDimitry Andric // Try to optimize cases where comparison instruction Compare is testing 423*0b57cec5SDimitry Andric // a value against zero. Return true on success and if Compare should be 424*0b57cec5SDimitry Andric // deleted as dead. CCUsers is the list of instructions that use the CC 425*0b57cec5SDimitry Andric // value produced by Compare. 426*0b57cec5SDimitry Andric bool SystemZElimCompare::optimizeCompareZero( 427*0b57cec5SDimitry Andric MachineInstr &Compare, SmallVectorImpl<MachineInstr *> &CCUsers) { 428*0b57cec5SDimitry Andric if (!isCompareZero(Compare)) 429*0b57cec5SDimitry Andric return false; 430*0b57cec5SDimitry Andric 431*0b57cec5SDimitry Andric // Search back for CC results that are based on the first operand. 432*0b57cec5SDimitry Andric unsigned SrcReg = getCompareSourceReg(Compare); 433*0b57cec5SDimitry Andric MachineBasicBlock &MBB = *Compare.getParent(); 434*0b57cec5SDimitry Andric Reference CCRefs; 435*0b57cec5SDimitry Andric Reference SrcRefs; 436*0b57cec5SDimitry Andric for (MachineBasicBlock::reverse_iterator MBBI = 437*0b57cec5SDimitry Andric std::next(MachineBasicBlock::reverse_iterator(&Compare)), 438*0b57cec5SDimitry Andric MBBE = MBB.rend(); MBBI != MBBE;) { 439*0b57cec5SDimitry Andric MachineInstr &MI = *MBBI++; 440*0b57cec5SDimitry Andric if (resultTests(MI, SrcReg)) { 441*0b57cec5SDimitry Andric // Try to remove both MI and Compare by converting a branch to BRCT(G). 442*0b57cec5SDimitry Andric // or a load-and-trap instruction. We don't care in this case whether 443*0b57cec5SDimitry Andric // CC is modified between MI and Compare. 444*0b57cec5SDimitry Andric if (!CCRefs.Use && !SrcRefs) { 445*0b57cec5SDimitry Andric if (convertToBRCT(MI, Compare, CCUsers)) { 446*0b57cec5SDimitry Andric BranchOnCounts += 1; 447*0b57cec5SDimitry Andric return true; 448*0b57cec5SDimitry Andric } 449*0b57cec5SDimitry Andric if (convertToLoadAndTrap(MI, Compare, CCUsers)) { 450*0b57cec5SDimitry Andric LoadAndTraps += 1; 451*0b57cec5SDimitry Andric return true; 452*0b57cec5SDimitry Andric } 453*0b57cec5SDimitry Andric } 454*0b57cec5SDimitry Andric // Try to eliminate Compare by reusing a CC result from MI. 455*0b57cec5SDimitry Andric if ((!CCRefs && convertToLoadAndTest(MI, Compare, CCUsers)) || 456*0b57cec5SDimitry Andric (!CCRefs.Def && adjustCCMasksForInstr(MI, Compare, CCUsers))) { 457*0b57cec5SDimitry Andric EliminatedComparisons += 1; 458*0b57cec5SDimitry Andric return true; 459*0b57cec5SDimitry Andric } 460*0b57cec5SDimitry Andric } 461*0b57cec5SDimitry Andric SrcRefs |= getRegReferences(MI, SrcReg); 462*0b57cec5SDimitry Andric if (SrcRefs.Def) 463*0b57cec5SDimitry Andric break; 464*0b57cec5SDimitry Andric CCRefs |= getRegReferences(MI, SystemZ::CC); 465*0b57cec5SDimitry Andric if (CCRefs.Use && CCRefs.Def) 466*0b57cec5SDimitry Andric break; 467*0b57cec5SDimitry Andric } 468*0b57cec5SDimitry Andric 469*0b57cec5SDimitry Andric // Also do a forward search to handle cases where an instruction after the 470*0b57cec5SDimitry Andric // compare can be converted, like 471*0b57cec5SDimitry Andric // LTEBRCompare %f0s, %f0s; %f2s = LER %f0s => LTEBRCompare %f2s, %f0s 472*0b57cec5SDimitry Andric for (MachineBasicBlock::iterator MBBI = 473*0b57cec5SDimitry Andric std::next(MachineBasicBlock::iterator(&Compare)), MBBE = MBB.end(); 474*0b57cec5SDimitry Andric MBBI != MBBE;) { 475*0b57cec5SDimitry Andric MachineInstr &MI = *MBBI++; 476*0b57cec5SDimitry Andric if (preservesValueOf(MI, SrcReg)) { 477*0b57cec5SDimitry Andric // Try to eliminate Compare by reusing a CC result from MI. 478*0b57cec5SDimitry Andric if (convertToLoadAndTest(MI, Compare, CCUsers)) { 479*0b57cec5SDimitry Andric EliminatedComparisons += 1; 480*0b57cec5SDimitry Andric return true; 481*0b57cec5SDimitry Andric } 482*0b57cec5SDimitry Andric } 483*0b57cec5SDimitry Andric if (getRegReferences(MI, SrcReg).Def) 484*0b57cec5SDimitry Andric return false; 485*0b57cec5SDimitry Andric if (getRegReferences(MI, SystemZ::CC)) 486*0b57cec5SDimitry Andric return false; 487*0b57cec5SDimitry Andric } 488*0b57cec5SDimitry Andric 489*0b57cec5SDimitry Andric return false; 490*0b57cec5SDimitry Andric } 491*0b57cec5SDimitry Andric 492*0b57cec5SDimitry Andric // Try to fuse comparison instruction Compare into a later branch. 493*0b57cec5SDimitry Andric // Return true on success and if Compare is therefore redundant. 494*0b57cec5SDimitry Andric bool SystemZElimCompare::fuseCompareOperations( 495*0b57cec5SDimitry Andric MachineInstr &Compare, SmallVectorImpl<MachineInstr *> &CCUsers) { 496*0b57cec5SDimitry Andric // See whether we have a single branch with which to fuse. 497*0b57cec5SDimitry Andric if (CCUsers.size() != 1) 498*0b57cec5SDimitry Andric return false; 499*0b57cec5SDimitry Andric MachineInstr *Branch = CCUsers[0]; 500*0b57cec5SDimitry Andric SystemZII::FusedCompareType Type; 501*0b57cec5SDimitry Andric switch (Branch->getOpcode()) { 502*0b57cec5SDimitry Andric case SystemZ::BRC: 503*0b57cec5SDimitry Andric Type = SystemZII::CompareAndBranch; 504*0b57cec5SDimitry Andric break; 505*0b57cec5SDimitry Andric case SystemZ::CondReturn: 506*0b57cec5SDimitry Andric Type = SystemZII::CompareAndReturn; 507*0b57cec5SDimitry Andric break; 508*0b57cec5SDimitry Andric case SystemZ::CallBCR: 509*0b57cec5SDimitry Andric Type = SystemZII::CompareAndSibcall; 510*0b57cec5SDimitry Andric break; 511*0b57cec5SDimitry Andric case SystemZ::CondTrap: 512*0b57cec5SDimitry Andric Type = SystemZII::CompareAndTrap; 513*0b57cec5SDimitry Andric break; 514*0b57cec5SDimitry Andric default: 515*0b57cec5SDimitry Andric return false; 516*0b57cec5SDimitry Andric } 517*0b57cec5SDimitry Andric 518*0b57cec5SDimitry Andric // See whether we have a comparison that can be fused. 519*0b57cec5SDimitry Andric unsigned FusedOpcode = 520*0b57cec5SDimitry Andric TII->getFusedCompare(Compare.getOpcode(), Type, &Compare); 521*0b57cec5SDimitry Andric if (!FusedOpcode) 522*0b57cec5SDimitry Andric return false; 523*0b57cec5SDimitry Andric 524*0b57cec5SDimitry Andric // Make sure that the operands are available at the branch. 525*0b57cec5SDimitry Andric // SrcReg2 is the register if the source operand is a register, 526*0b57cec5SDimitry Andric // 0 if the source operand is immediate, and the base register 527*0b57cec5SDimitry Andric // if the source operand is memory (index is not supported). 528*0b57cec5SDimitry Andric Register SrcReg = Compare.getOperand(0).getReg(); 529*0b57cec5SDimitry Andric Register SrcReg2 = 530*0b57cec5SDimitry Andric Compare.getOperand(1).isReg() ? Compare.getOperand(1).getReg() : Register(); 531*0b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI = Compare, MBBE = Branch; 532*0b57cec5SDimitry Andric for (++MBBI; MBBI != MBBE; ++MBBI) 533*0b57cec5SDimitry Andric if (MBBI->modifiesRegister(SrcReg, TRI) || 534*0b57cec5SDimitry Andric (SrcReg2 && MBBI->modifiesRegister(SrcReg2, TRI))) 535*0b57cec5SDimitry Andric return false; 536*0b57cec5SDimitry Andric 537*0b57cec5SDimitry Andric // Read the branch mask, target (if applicable), regmask (if applicable). 538*0b57cec5SDimitry Andric MachineOperand CCMask(MBBI->getOperand(1)); 539*0b57cec5SDimitry Andric assert((CCMask.getImm() & ~SystemZ::CCMASK_ICMP) == 0 && 540*0b57cec5SDimitry Andric "Invalid condition-code mask for integer comparison"); 541*0b57cec5SDimitry Andric // This is only valid for CompareAndBranch. 542*0b57cec5SDimitry Andric MachineOperand Target(MBBI->getOperand( 543*0b57cec5SDimitry Andric Type == SystemZII::CompareAndBranch ? 2 : 0)); 544*0b57cec5SDimitry Andric const uint32_t *RegMask; 545*0b57cec5SDimitry Andric if (Type == SystemZII::CompareAndSibcall) 546*0b57cec5SDimitry Andric RegMask = MBBI->getOperand(2).getRegMask(); 547*0b57cec5SDimitry Andric 548*0b57cec5SDimitry Andric // Clear out all current operands. 549*0b57cec5SDimitry Andric int CCUse = MBBI->findRegisterUseOperandIdx(SystemZ::CC, false, TRI); 550*0b57cec5SDimitry Andric assert(CCUse >= 0 && "BRC/BCR must use CC"); 551*0b57cec5SDimitry Andric Branch->RemoveOperand(CCUse); 552*0b57cec5SDimitry Andric // Remove target (branch) or regmask (sibcall). 553*0b57cec5SDimitry Andric if (Type == SystemZII::CompareAndBranch || 554*0b57cec5SDimitry Andric Type == SystemZII::CompareAndSibcall) 555*0b57cec5SDimitry Andric Branch->RemoveOperand(2); 556*0b57cec5SDimitry Andric Branch->RemoveOperand(1); 557*0b57cec5SDimitry Andric Branch->RemoveOperand(0); 558*0b57cec5SDimitry Andric 559*0b57cec5SDimitry Andric // Rebuild Branch as a fused compare and branch. 560*0b57cec5SDimitry Andric // SrcNOps is the number of MI operands of the compare instruction 561*0b57cec5SDimitry Andric // that we need to copy over. 562*0b57cec5SDimitry Andric unsigned SrcNOps = 2; 563*0b57cec5SDimitry Andric if (FusedOpcode == SystemZ::CLT || FusedOpcode == SystemZ::CLGT) 564*0b57cec5SDimitry Andric SrcNOps = 3; 565*0b57cec5SDimitry Andric Branch->setDesc(TII->get(FusedOpcode)); 566*0b57cec5SDimitry Andric MachineInstrBuilder MIB(*Branch->getParent()->getParent(), Branch); 567*0b57cec5SDimitry Andric for (unsigned I = 0; I < SrcNOps; I++) 568*0b57cec5SDimitry Andric MIB.add(Compare.getOperand(I)); 569*0b57cec5SDimitry Andric MIB.add(CCMask); 570*0b57cec5SDimitry Andric 571*0b57cec5SDimitry Andric if (Type == SystemZII::CompareAndBranch) { 572*0b57cec5SDimitry Andric // Only conditional branches define CC, as they may be converted back 573*0b57cec5SDimitry Andric // to a non-fused branch because of a long displacement. Conditional 574*0b57cec5SDimitry Andric // returns don't have that problem. 575*0b57cec5SDimitry Andric MIB.add(Target).addReg(SystemZ::CC, 576*0b57cec5SDimitry Andric RegState::ImplicitDefine | RegState::Dead); 577*0b57cec5SDimitry Andric } 578*0b57cec5SDimitry Andric 579*0b57cec5SDimitry Andric if (Type == SystemZII::CompareAndSibcall) 580*0b57cec5SDimitry Andric MIB.addRegMask(RegMask); 581*0b57cec5SDimitry Andric 582*0b57cec5SDimitry Andric // Clear any intervening kills of SrcReg and SrcReg2. 583*0b57cec5SDimitry Andric MBBI = Compare; 584*0b57cec5SDimitry Andric for (++MBBI; MBBI != MBBE; ++MBBI) { 585*0b57cec5SDimitry Andric MBBI->clearRegisterKills(SrcReg, TRI); 586*0b57cec5SDimitry Andric if (SrcReg2) 587*0b57cec5SDimitry Andric MBBI->clearRegisterKills(SrcReg2, TRI); 588*0b57cec5SDimitry Andric } 589*0b57cec5SDimitry Andric FusedComparisons += 1; 590*0b57cec5SDimitry Andric return true; 591*0b57cec5SDimitry Andric } 592*0b57cec5SDimitry Andric 593*0b57cec5SDimitry Andric // Process all comparison instructions in MBB. Return true if something 594*0b57cec5SDimitry Andric // changed. 595*0b57cec5SDimitry Andric bool SystemZElimCompare::processBlock(MachineBasicBlock &MBB) { 596*0b57cec5SDimitry Andric bool Changed = false; 597*0b57cec5SDimitry Andric 598*0b57cec5SDimitry Andric // Walk backwards through the block looking for comparisons, recording 599*0b57cec5SDimitry Andric // all CC users as we go. The subroutines can delete Compare and 600*0b57cec5SDimitry Andric // instructions before it. 601*0b57cec5SDimitry Andric bool CompleteCCUsers = !isCCLiveOut(MBB); 602*0b57cec5SDimitry Andric SmallVector<MachineInstr *, 4> CCUsers; 603*0b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.end(); 604*0b57cec5SDimitry Andric while (MBBI != MBB.begin()) { 605*0b57cec5SDimitry Andric MachineInstr &MI = *--MBBI; 606*0b57cec5SDimitry Andric if (CompleteCCUsers && (MI.isCompare() || isLoadAndTestAsCmp(MI)) && 607*0b57cec5SDimitry Andric (optimizeCompareZero(MI, CCUsers) || 608*0b57cec5SDimitry Andric fuseCompareOperations(MI, CCUsers))) { 609*0b57cec5SDimitry Andric ++MBBI; 610*0b57cec5SDimitry Andric MI.eraseFromParent(); 611*0b57cec5SDimitry Andric Changed = true; 612*0b57cec5SDimitry Andric CCUsers.clear(); 613*0b57cec5SDimitry Andric continue; 614*0b57cec5SDimitry Andric } 615*0b57cec5SDimitry Andric 616*0b57cec5SDimitry Andric if (MI.definesRegister(SystemZ::CC)) { 617*0b57cec5SDimitry Andric CCUsers.clear(); 618*0b57cec5SDimitry Andric CompleteCCUsers = true; 619*0b57cec5SDimitry Andric } 620*0b57cec5SDimitry Andric if (MI.readsRegister(SystemZ::CC) && CompleteCCUsers) 621*0b57cec5SDimitry Andric CCUsers.push_back(&MI); 622*0b57cec5SDimitry Andric } 623*0b57cec5SDimitry Andric return Changed; 624*0b57cec5SDimitry Andric } 625*0b57cec5SDimitry Andric 626*0b57cec5SDimitry Andric bool SystemZElimCompare::runOnMachineFunction(MachineFunction &F) { 627*0b57cec5SDimitry Andric if (skipFunction(F.getFunction())) 628*0b57cec5SDimitry Andric return false; 629*0b57cec5SDimitry Andric 630*0b57cec5SDimitry Andric TII = static_cast<const SystemZInstrInfo *>(F.getSubtarget().getInstrInfo()); 631*0b57cec5SDimitry Andric TRI = &TII->getRegisterInfo(); 632*0b57cec5SDimitry Andric 633*0b57cec5SDimitry Andric bool Changed = false; 634*0b57cec5SDimitry Andric for (auto &MBB : F) 635*0b57cec5SDimitry Andric Changed |= processBlock(MBB); 636*0b57cec5SDimitry Andric 637*0b57cec5SDimitry Andric return Changed; 638*0b57cec5SDimitry Andric } 639*0b57cec5SDimitry Andric 640*0b57cec5SDimitry Andric FunctionPass *llvm::createSystemZElimComparePass(SystemZTargetMachine &TM) { 641*0b57cec5SDimitry Andric return new SystemZElimCompare(TM); 642*0b57cec5SDimitry Andric } 643