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