1f785676fSDimitry Andric //===-- SystemZElimCompare.cpp - Eliminate comparison instructions --------===//
2f785676fSDimitry Andric //
3f785676fSDimitry Andric //                     The LLVM Compiler Infrastructure
4f785676fSDimitry Andric //
5f785676fSDimitry Andric // This file is distributed under the University of Illinois Open Source
6f785676fSDimitry Andric // License. See LICENSE.TXT for details.
7f785676fSDimitry Andric //
8f785676fSDimitry Andric //===----------------------------------------------------------------------===//
9f785676fSDimitry Andric //
10f785676fSDimitry Andric // This pass:
11f785676fSDimitry Andric // (1) tries to remove compares if CC already contains the required information
12f785676fSDimitry Andric // (2) fuses compares and branches into COMPARE AND BRANCH instructions
13f785676fSDimitry Andric //
14f785676fSDimitry Andric //===----------------------------------------------------------------------===//
15f785676fSDimitry Andric 
167a7e6055SDimitry Andric #include "SystemZ.h"
177a7e6055SDimitry Andric #include "SystemZInstrInfo.h"
18f785676fSDimitry Andric #include "SystemZTargetMachine.h"
197a7e6055SDimitry Andric #include "llvm/ADT/SmallVector.h"
20f785676fSDimitry Andric #include "llvm/ADT/Statistic.h"
217a7e6055SDimitry Andric #include "llvm/ADT/StringRef.h"
227a7e6055SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
237a7e6055SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
24f785676fSDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
257a7e6055SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
26f785676fSDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
277a7e6055SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
282cab237bSDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
292cab237bSDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
307a7e6055SDimitry Andric #include "llvm/MC/MCInstrDesc.h"
317a7e6055SDimitry Andric #include <cassert>
327a7e6055SDimitry Andric #include <cstdint>
33f785676fSDimitry Andric 
34f785676fSDimitry Andric using namespace llvm;
35f785676fSDimitry Andric 
3691bc56edSDimitry Andric #define DEBUG_TYPE "systemz-elim-compare"
3791bc56edSDimitry Andric 
38f785676fSDimitry Andric STATISTIC(BranchOnCounts, "Number of branch-on-count instructions");
39d88c1a5aSDimitry Andric STATISTIC(LoadAndTraps, "Number of load-and-trap instructions");
40f785676fSDimitry Andric STATISTIC(EliminatedComparisons, "Number of eliminated comparisons");
41f785676fSDimitry Andric STATISTIC(FusedComparisons, "Number of fused compare-and-branch instructions");
42f785676fSDimitry Andric 
43f785676fSDimitry Andric namespace {
447a7e6055SDimitry Andric 
45f785676fSDimitry Andric // Represents the references to a particular register in one or more
46f785676fSDimitry Andric // instructions.
47f785676fSDimitry Andric struct Reference {
487a7e6055SDimitry Andric   Reference() = default;
49f785676fSDimitry Andric 
operator |=__anon3f2c64a60111::Reference50f785676fSDimitry Andric   Reference &operator|=(const Reference &Other) {
51f785676fSDimitry Andric     Def |= Other.Def;
52f785676fSDimitry Andric     Use |= Other.Use;
53f785676fSDimitry Andric     return *this;
54f785676fSDimitry Andric   }
55f785676fSDimitry Andric 
operator bool__anon3f2c64a60111::Reference56ff0cc061SDimitry Andric   explicit operator bool() const { return Def || Use; }
57f785676fSDimitry Andric 
58f785676fSDimitry Andric   // True if the register is defined or used in some form, either directly or
59f785676fSDimitry Andric   // via a sub- or super-register.
607a7e6055SDimitry Andric   bool Def = false;
617a7e6055SDimitry Andric   bool Use = false;
62f785676fSDimitry Andric };
63f785676fSDimitry Andric 
64f785676fSDimitry Andric class SystemZElimCompare : public MachineFunctionPass {
65f785676fSDimitry Andric public:
66f785676fSDimitry Andric   static char ID;
677a7e6055SDimitry Andric 
SystemZElimCompare(const SystemZTargetMachine & tm)68f785676fSDimitry Andric   SystemZElimCompare(const SystemZTargetMachine &tm)
697a7e6055SDimitry Andric     : MachineFunctionPass(ID) {}
70f785676fSDimitry Andric 
getPassName() const71d88c1a5aSDimitry Andric   StringRef getPassName() const override {
72f785676fSDimitry Andric     return "SystemZ Comparison Elimination";
73f785676fSDimitry Andric   }
74f785676fSDimitry Andric 
7591bc56edSDimitry Andric   bool processBlock(MachineBasicBlock &MBB);
7691bc56edSDimitry Andric   bool runOnMachineFunction(MachineFunction &F) override;
777a7e6055SDimitry Andric 
getRequiredProperties() const783ca95b02SDimitry Andric   MachineFunctionProperties getRequiredProperties() const override {
793ca95b02SDimitry Andric     return MachineFunctionProperties().set(
80d88c1a5aSDimitry Andric         MachineFunctionProperties::Property::NoVRegs);
813ca95b02SDimitry Andric   }
82f785676fSDimitry Andric 
83f785676fSDimitry Andric private:
843ca95b02SDimitry Andric   Reference getRegReferences(MachineInstr &MI, unsigned Reg);
853ca95b02SDimitry Andric   bool convertToBRCT(MachineInstr &MI, MachineInstr &Compare,
86f785676fSDimitry Andric                      SmallVectorImpl<MachineInstr *> &CCUsers);
87d88c1a5aSDimitry Andric   bool convertToLoadAndTrap(MachineInstr &MI, MachineInstr &Compare,
88d88c1a5aSDimitry Andric                             SmallVectorImpl<MachineInstr *> &CCUsers);
894ba319b5SDimitry Andric   bool convertToLoadAndTest(MachineInstr &MI, MachineInstr &Compare,
90f785676fSDimitry Andric                             SmallVectorImpl<MachineInstr *> &CCUsers);
914ba319b5SDimitry Andric   bool adjustCCMasksForInstr(MachineInstr &MI, MachineInstr &Compare,
924ba319b5SDimitry Andric                              SmallVectorImpl<MachineInstr *> &CCUsers,
934ba319b5SDimitry Andric                              unsigned ConvOpc = 0);
943ca95b02SDimitry Andric   bool optimizeCompareZero(MachineInstr &Compare,
95f785676fSDimitry Andric                            SmallVectorImpl<MachineInstr *> &CCUsers);
963ca95b02SDimitry Andric   bool fuseCompareOperations(MachineInstr &Compare,
97f785676fSDimitry Andric                              SmallVectorImpl<MachineInstr *> &CCUsers);
98f785676fSDimitry Andric 
997a7e6055SDimitry Andric   const SystemZInstrInfo *TII = nullptr;
1007a7e6055SDimitry Andric   const TargetRegisterInfo *TRI = nullptr;
101f785676fSDimitry Andric };
102f785676fSDimitry Andric 
103f785676fSDimitry Andric char SystemZElimCompare::ID = 0;
104f785676fSDimitry Andric 
1057a7e6055SDimitry Andric } // end anonymous namespace
106f785676fSDimitry Andric 
107f785676fSDimitry Andric // Return true if CC is live out of MBB.
isCCLiveOut(MachineBasicBlock & MBB)10891bc56edSDimitry Andric static bool isCCLiveOut(MachineBasicBlock &MBB) {
10991bc56edSDimitry Andric   for (auto SI = MBB.succ_begin(), SE = MBB.succ_end(); SI != SE; ++SI)
110f785676fSDimitry Andric     if ((*SI)->isLiveIn(SystemZ::CC))
111f785676fSDimitry Andric       return true;
112f785676fSDimitry Andric   return false;
113f785676fSDimitry Andric }
114f785676fSDimitry Andric 
1152cab237bSDimitry Andric // Returns true if MI is an instruction whose output equals the value in Reg.
preservesValueOf(MachineInstr & MI,unsigned Reg)1162cab237bSDimitry Andric static bool preservesValueOf(MachineInstr &MI, unsigned Reg) {
1173ca95b02SDimitry Andric   switch (MI.getOpcode()) {
118f785676fSDimitry Andric   case SystemZ::LR:
119f785676fSDimitry Andric   case SystemZ::LGR:
120f785676fSDimitry Andric   case SystemZ::LGFR:
121f785676fSDimitry Andric   case SystemZ::LTR:
122f785676fSDimitry Andric   case SystemZ::LTGR:
123f785676fSDimitry Andric   case SystemZ::LTGFR:
124f785676fSDimitry Andric   case SystemZ::LER:
125f785676fSDimitry Andric   case SystemZ::LDR:
126f785676fSDimitry Andric   case SystemZ::LXR:
127f785676fSDimitry Andric   case SystemZ::LTEBR:
128f785676fSDimitry Andric   case SystemZ::LTDBR:
129f785676fSDimitry Andric   case SystemZ::LTXBR:
1303ca95b02SDimitry Andric     if (MI.getOperand(1).getReg() == Reg)
131f785676fSDimitry Andric       return true;
132f785676fSDimitry Andric   }
133f785676fSDimitry Andric 
134f785676fSDimitry Andric   return false;
135f785676fSDimitry Andric }
136f785676fSDimitry Andric 
1372cab237bSDimitry Andric // Return true if any CC result of MI would (perhaps after conversion)
1382cab237bSDimitry Andric // reflect the value of Reg.
resultTests(MachineInstr & MI,unsigned Reg)1392cab237bSDimitry Andric static bool resultTests(MachineInstr &MI, unsigned Reg) {
1402cab237bSDimitry Andric   if (MI.getNumOperands() > 0 && MI.getOperand(0).isReg() &&
1412cab237bSDimitry Andric       MI.getOperand(0).isDef() && MI.getOperand(0).getReg() == Reg)
1422cab237bSDimitry Andric     return true;
1432cab237bSDimitry Andric 
1442cab237bSDimitry Andric   return (preservesValueOf(MI, Reg));
1452cab237bSDimitry Andric }
1462cab237bSDimitry Andric 
1477d523365SDimitry Andric // Describe the references to Reg or any of its aliases in MI.
getRegReferences(MachineInstr & MI,unsigned Reg)1483ca95b02SDimitry Andric Reference SystemZElimCompare::getRegReferences(MachineInstr &MI, unsigned Reg) {
149f785676fSDimitry Andric   Reference Ref;
1503ca95b02SDimitry Andric   for (unsigned I = 0, E = MI.getNumOperands(); I != E; ++I) {
1513ca95b02SDimitry Andric     const MachineOperand &MO = MI.getOperand(I);
152f785676fSDimitry Andric     if (MO.isReg()) {
153f785676fSDimitry Andric       if (unsigned MOReg = MO.getReg()) {
1547d523365SDimitry Andric         if (TRI->regsOverlap(MOReg, Reg)) {
1557d523365SDimitry Andric           if (MO.isUse())
156f785676fSDimitry Andric             Ref.Use = true;
1577d523365SDimitry Andric           else if (MO.isDef())
158f785676fSDimitry Andric             Ref.Def = true;
159f785676fSDimitry Andric         }
160f785676fSDimitry Andric       }
161f785676fSDimitry Andric     }
162f785676fSDimitry Andric   }
163f785676fSDimitry Andric   return Ref;
164f785676fSDimitry Andric }
165f785676fSDimitry Andric 
1667d523365SDimitry Andric // Return true if this is a load and test which can be optimized the
1677d523365SDimitry Andric // same way as compare instruction.
isLoadAndTestAsCmp(MachineInstr & MI)1683ca95b02SDimitry Andric static bool isLoadAndTestAsCmp(MachineInstr &MI) {
1697d523365SDimitry Andric   // If we during isel used a load-and-test as a compare with 0, the
1707d523365SDimitry Andric   // def operand is dead.
1713ca95b02SDimitry Andric   return (MI.getOpcode() == SystemZ::LTEBR ||
1723ca95b02SDimitry Andric           MI.getOpcode() == SystemZ::LTDBR ||
1733ca95b02SDimitry Andric           MI.getOpcode() == SystemZ::LTXBR) &&
1743ca95b02SDimitry Andric          MI.getOperand(0).isDead();
1757d523365SDimitry Andric }
1767d523365SDimitry Andric 
1777d523365SDimitry Andric // Return the source register of Compare, which is the unknown value
1787d523365SDimitry Andric // being tested.
getCompareSourceReg(MachineInstr & Compare)1793ca95b02SDimitry Andric static unsigned getCompareSourceReg(MachineInstr &Compare) {
1807d523365SDimitry Andric   unsigned reg = 0;
1813ca95b02SDimitry Andric   if (Compare.isCompare())
1823ca95b02SDimitry Andric     reg = Compare.getOperand(0).getReg();
1837d523365SDimitry Andric   else if (isLoadAndTestAsCmp(Compare))
1843ca95b02SDimitry Andric     reg = Compare.getOperand(1).getReg();
1857d523365SDimitry Andric   assert(reg);
1867d523365SDimitry Andric 
1877d523365SDimitry Andric   return reg;
1887d523365SDimitry Andric }
1897d523365SDimitry Andric 
190f785676fSDimitry Andric // Compare compares the result of MI against zero.  If MI is an addition
191f785676fSDimitry Andric // of -1 and if CCUsers is a single branch on nonzero, eliminate the addition
192d88c1a5aSDimitry Andric // and convert the branch to a BRCT(G) or BRCTH.  Return true on success.
convertToBRCT(MachineInstr & MI,MachineInstr & Compare,SmallVectorImpl<MachineInstr * > & CCUsers)1933ca95b02SDimitry Andric bool SystemZElimCompare::convertToBRCT(
1943ca95b02SDimitry Andric     MachineInstr &MI, MachineInstr &Compare,
195f785676fSDimitry Andric     SmallVectorImpl<MachineInstr *> &CCUsers) {
196f785676fSDimitry Andric   // Check whether we have an addition of -1.
1973ca95b02SDimitry Andric   unsigned Opcode = MI.getOpcode();
198f785676fSDimitry Andric   unsigned BRCT;
199f785676fSDimitry Andric   if (Opcode == SystemZ::AHI)
200f785676fSDimitry Andric     BRCT = SystemZ::BRCT;
201f785676fSDimitry Andric   else if (Opcode == SystemZ::AGHI)
202f785676fSDimitry Andric     BRCT = SystemZ::BRCTG;
203d88c1a5aSDimitry Andric   else if (Opcode == SystemZ::AIH)
204d88c1a5aSDimitry Andric     BRCT = SystemZ::BRCTH;
205f785676fSDimitry Andric   else
206f785676fSDimitry Andric     return false;
2073ca95b02SDimitry Andric   if (MI.getOperand(2).getImm() != -1)
208f785676fSDimitry Andric     return false;
209f785676fSDimitry Andric 
210f785676fSDimitry Andric   // Check whether we have a single JLH.
211f785676fSDimitry Andric   if (CCUsers.size() != 1)
212f785676fSDimitry Andric     return false;
213f785676fSDimitry Andric   MachineInstr *Branch = CCUsers[0];
214f785676fSDimitry Andric   if (Branch->getOpcode() != SystemZ::BRC ||
215f785676fSDimitry Andric       Branch->getOperand(0).getImm() != SystemZ::CCMASK_ICMP ||
216f785676fSDimitry Andric       Branch->getOperand(1).getImm() != SystemZ::CCMASK_CMP_NE)
217f785676fSDimitry Andric     return false;
218f785676fSDimitry Andric 
219f785676fSDimitry Andric   // We already know that there are no references to the register between
220f785676fSDimitry Andric   // MI and Compare.  Make sure that there are also no references between
221f785676fSDimitry Andric   // Compare and Branch.
2227d523365SDimitry Andric   unsigned SrcReg = getCompareSourceReg(Compare);
223f785676fSDimitry Andric   MachineBasicBlock::iterator MBBI = Compare, MBBE = Branch;
224f785676fSDimitry Andric   for (++MBBI; MBBI != MBBE; ++MBBI)
2253ca95b02SDimitry Andric     if (getRegReferences(*MBBI, SrcReg))
226f785676fSDimitry Andric       return false;
227f785676fSDimitry Andric 
228d88c1a5aSDimitry Andric   // The transformation is OK.  Rebuild Branch as a BRCT(G) or BRCTH.
229f785676fSDimitry Andric   MachineOperand Target(Branch->getOperand(2));
2307d523365SDimitry Andric   while (Branch->getNumOperands())
231f785676fSDimitry Andric     Branch->RemoveOperand(0);
232f785676fSDimitry Andric   Branch->setDesc(TII->get(BRCT));
233d88c1a5aSDimitry Andric   MachineInstrBuilder MIB(*Branch->getParent()->getParent(), Branch);
2347a7e6055SDimitry Andric   MIB.add(MI.getOperand(0)).add(MI.getOperand(1)).add(Target);
235d88c1a5aSDimitry Andric   // Add a CC def to BRCT(G), since we may have to split them again if the
236d88c1a5aSDimitry Andric   // branch displacement overflows.  BRCTH has a 32-bit displacement, so
237d88c1a5aSDimitry Andric   // this is not necessary there.
238d88c1a5aSDimitry Andric   if (BRCT != SystemZ::BRCTH)
239d88c1a5aSDimitry Andric     MIB.addReg(SystemZ::CC, RegState::ImplicitDefine | RegState::Dead);
240d88c1a5aSDimitry Andric   MI.eraseFromParent();
241d88c1a5aSDimitry Andric   return true;
242d88c1a5aSDimitry Andric }
243d88c1a5aSDimitry Andric 
244d88c1a5aSDimitry Andric // Compare compares the result of MI against zero.  If MI is a suitable load
245d88c1a5aSDimitry Andric // instruction and if CCUsers is a single conditional trap on zero, eliminate
246d88c1a5aSDimitry Andric // the load and convert the branch to a load-and-trap.  Return true on success.
convertToLoadAndTrap(MachineInstr & MI,MachineInstr & Compare,SmallVectorImpl<MachineInstr * > & CCUsers)247d88c1a5aSDimitry Andric bool SystemZElimCompare::convertToLoadAndTrap(
248d88c1a5aSDimitry Andric     MachineInstr &MI, MachineInstr &Compare,
249d88c1a5aSDimitry Andric     SmallVectorImpl<MachineInstr *> &CCUsers) {
250d88c1a5aSDimitry Andric   unsigned LATOpcode = TII->getLoadAndTrap(MI.getOpcode());
251d88c1a5aSDimitry Andric   if (!LATOpcode)
252d88c1a5aSDimitry Andric     return false;
253d88c1a5aSDimitry Andric 
254d88c1a5aSDimitry Andric   // Check whether we have a single CondTrap that traps on zero.
255d88c1a5aSDimitry Andric   if (CCUsers.size() != 1)
256d88c1a5aSDimitry Andric     return false;
257d88c1a5aSDimitry Andric   MachineInstr *Branch = CCUsers[0];
258d88c1a5aSDimitry Andric   if (Branch->getOpcode() != SystemZ::CondTrap ||
259d88c1a5aSDimitry Andric       Branch->getOperand(0).getImm() != SystemZ::CCMASK_ICMP ||
260d88c1a5aSDimitry Andric       Branch->getOperand(1).getImm() != SystemZ::CCMASK_CMP_EQ)
261d88c1a5aSDimitry Andric     return false;
262d88c1a5aSDimitry Andric 
263d88c1a5aSDimitry Andric   // We already know that there are no references to the register between
264d88c1a5aSDimitry Andric   // MI and Compare.  Make sure that there are also no references between
265d88c1a5aSDimitry Andric   // Compare and Branch.
266d88c1a5aSDimitry Andric   unsigned SrcReg = getCompareSourceReg(Compare);
267d88c1a5aSDimitry Andric   MachineBasicBlock::iterator MBBI = Compare, MBBE = Branch;
268d88c1a5aSDimitry Andric   for (++MBBI; MBBI != MBBE; ++MBBI)
269d88c1a5aSDimitry Andric     if (getRegReferences(*MBBI, SrcReg))
270d88c1a5aSDimitry Andric       return false;
271d88c1a5aSDimitry Andric 
272d88c1a5aSDimitry Andric   // The transformation is OK.  Rebuild Branch as a load-and-trap.
273d88c1a5aSDimitry Andric   while (Branch->getNumOperands())
274d88c1a5aSDimitry Andric     Branch->RemoveOperand(0);
275d88c1a5aSDimitry Andric   Branch->setDesc(TII->get(LATOpcode));
276f785676fSDimitry Andric   MachineInstrBuilder(*Branch->getParent()->getParent(), Branch)
2777a7e6055SDimitry Andric       .add(MI.getOperand(0))
2787a7e6055SDimitry Andric       .add(MI.getOperand(1))
2797a7e6055SDimitry Andric       .add(MI.getOperand(2))
2807a7e6055SDimitry Andric       .add(MI.getOperand(3));
2813ca95b02SDimitry Andric   MI.eraseFromParent();
282f785676fSDimitry Andric   return true;
283f785676fSDimitry Andric }
284f785676fSDimitry Andric 
285f785676fSDimitry Andric // If MI is a load instruction, try to convert it into a LOAD AND TEST.
286f785676fSDimitry Andric // Return true on success.
convertToLoadAndTest(MachineInstr & MI,MachineInstr & Compare,SmallVectorImpl<MachineInstr * > & CCUsers)2874ba319b5SDimitry Andric bool SystemZElimCompare::convertToLoadAndTest(
2884ba319b5SDimitry Andric     MachineInstr &MI, MachineInstr &Compare,
2894ba319b5SDimitry Andric     SmallVectorImpl<MachineInstr *> &CCUsers) {
2904ba319b5SDimitry Andric 
2914ba319b5SDimitry Andric   // Try to adjust CC masks for the LOAD AND TEST opcode that could replace MI.
2923ca95b02SDimitry Andric   unsigned Opcode = TII->getLoadAndTest(MI.getOpcode());
2934ba319b5SDimitry Andric   if (!Opcode || !adjustCCMasksForInstr(MI, Compare, CCUsers, Opcode))
294f785676fSDimitry Andric     return false;
295f785676fSDimitry Andric 
2964ba319b5SDimitry Andric   // Rebuild to get the CC operand in the right place.
297*b5893f02SDimitry Andric   auto MIB = BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(Opcode));
2984ba319b5SDimitry Andric   for (const auto &MO : MI.operands())
299*b5893f02SDimitry Andric     MIB.add(MO);
300*b5893f02SDimitry Andric   MIB.setMemRefs(MI.memoperands());
3014ba319b5SDimitry Andric   MI.eraseFromParent();
3024ba319b5SDimitry Andric 
303f785676fSDimitry Andric   return true;
304f785676fSDimitry Andric }
305f785676fSDimitry Andric 
306f785676fSDimitry Andric // The CC users in CCUsers are testing the result of a comparison of some
3074ba319b5SDimitry Andric // value X against zero and we know that any CC value produced by MI would
3084ba319b5SDimitry Andric // also reflect the value of X.  ConvOpc may be used to pass the transfomed
3094ba319b5SDimitry Andric // opcode MI will have if this succeeds.  Try to adjust CCUsers so that they
3104ba319b5SDimitry Andric // test the result of MI directly, returning true on success.  Leave
3114ba319b5SDimitry Andric // everything unchanged on failure.
adjustCCMasksForInstr(MachineInstr & MI,MachineInstr & Compare,SmallVectorImpl<MachineInstr * > & CCUsers,unsigned ConvOpc)3123ca95b02SDimitry Andric bool SystemZElimCompare::adjustCCMasksForInstr(
3133ca95b02SDimitry Andric     MachineInstr &MI, MachineInstr &Compare,
3144ba319b5SDimitry Andric     SmallVectorImpl<MachineInstr *> &CCUsers,
3154ba319b5SDimitry Andric     unsigned ConvOpc) {
3164ba319b5SDimitry Andric   int Opcode = (ConvOpc ? ConvOpc : MI.getOpcode());
317f785676fSDimitry Andric   const MCInstrDesc &Desc = TII->get(Opcode);
318f785676fSDimitry Andric   unsigned MIFlags = Desc.TSFlags;
319f785676fSDimitry Andric 
320f785676fSDimitry Andric   // See which compare-style condition codes are available.
321f785676fSDimitry Andric   unsigned ReusableCCMask = SystemZII::getCompareZeroCCMask(MIFlags);
322f785676fSDimitry Andric 
323f785676fSDimitry Andric   // For unsigned comparisons with zero, only equality makes sense.
3243ca95b02SDimitry Andric   unsigned CompareFlags = Compare.getDesc().TSFlags;
325f785676fSDimitry Andric   if (CompareFlags & SystemZII::IsLogical)
326f785676fSDimitry Andric     ReusableCCMask &= SystemZ::CCMASK_CMP_EQ;
327f785676fSDimitry Andric 
328f785676fSDimitry Andric   if (ReusableCCMask == 0)
329f785676fSDimitry Andric     return false;
330f785676fSDimitry Andric 
331f785676fSDimitry Andric   unsigned CCValues = SystemZII::getCCValues(MIFlags);
332f785676fSDimitry Andric   assert((ReusableCCMask & ~CCValues) == 0 && "Invalid CCValues");
333f785676fSDimitry Andric 
3344ba319b5SDimitry Andric   bool MIEquivalentToCmp =
3354ba319b5SDimitry Andric     (ReusableCCMask == CCValues &&
3364ba319b5SDimitry Andric      CCValues == SystemZII::getCCValues(CompareFlags));
3374ba319b5SDimitry Andric 
3384ba319b5SDimitry Andric   if (!MIEquivalentToCmp) {
339f785676fSDimitry Andric     // Now check whether these flags are enough for all users.
340f785676fSDimitry Andric     SmallVector<MachineOperand *, 4> AlterMasks;
341f785676fSDimitry Andric     for (unsigned int I = 0, E = CCUsers.size(); I != E; ++I) {
342f785676fSDimitry Andric       MachineInstr *MI = CCUsers[I];
343f785676fSDimitry Andric 
344f785676fSDimitry Andric       // Fail if this isn't a use of CC that we understand.
345f785676fSDimitry Andric       unsigned Flags = MI->getDesc().TSFlags;
346f785676fSDimitry Andric       unsigned FirstOpNum;
347f785676fSDimitry Andric       if (Flags & SystemZII::CCMaskFirst)
348f785676fSDimitry Andric         FirstOpNum = 0;
349f785676fSDimitry Andric       else if (Flags & SystemZII::CCMaskLast)
350f785676fSDimitry Andric         FirstOpNum = MI->getNumExplicitOperands() - 2;
351f785676fSDimitry Andric       else
352f785676fSDimitry Andric         return false;
353f785676fSDimitry Andric 
354f785676fSDimitry Andric       // Check whether the instruction predicate treats all CC values
355f785676fSDimitry Andric       // outside of ReusableCCMask in the same way.  In that case it
356f785676fSDimitry Andric       // doesn't matter what those CC values mean.
357f785676fSDimitry Andric       unsigned CCValid = MI->getOperand(FirstOpNum).getImm();
358f785676fSDimitry Andric       unsigned CCMask = MI->getOperand(FirstOpNum + 1).getImm();
359f785676fSDimitry Andric       unsigned OutValid = ~ReusableCCMask & CCValid;
360f785676fSDimitry Andric       unsigned OutMask = ~ReusableCCMask & CCMask;
361f785676fSDimitry Andric       if (OutMask != 0 && OutMask != OutValid)
362f785676fSDimitry Andric         return false;
363f785676fSDimitry Andric 
364f785676fSDimitry Andric       AlterMasks.push_back(&MI->getOperand(FirstOpNum));
365f785676fSDimitry Andric       AlterMasks.push_back(&MI->getOperand(FirstOpNum + 1));
366f785676fSDimitry Andric     }
367f785676fSDimitry Andric 
368f785676fSDimitry Andric     // All users are OK.  Adjust the masks for MI.
369f785676fSDimitry Andric     for (unsigned I = 0, E = AlterMasks.size(); I != E; I += 2) {
370f785676fSDimitry Andric       AlterMasks[I]->setImm(CCValues);
371f785676fSDimitry Andric       unsigned CCMask = AlterMasks[I + 1]->getImm();
372f785676fSDimitry Andric       if (CCMask & ~ReusableCCMask)
373f785676fSDimitry Andric         AlterMasks[I + 1]->setImm((CCMask & ReusableCCMask) |
374f785676fSDimitry Andric                                   (CCValues & ~ReusableCCMask));
375f785676fSDimitry Andric     }
3764ba319b5SDimitry Andric   }
377f785676fSDimitry Andric 
378f785676fSDimitry Andric   // CC is now live after MI.
3794ba319b5SDimitry Andric   if (!ConvOpc) {
3803ca95b02SDimitry Andric     int CCDef = MI.findRegisterDefOperandIdx(SystemZ::CC, false, true, TRI);
381f785676fSDimitry Andric     assert(CCDef >= 0 && "Couldn't find CC set");
3823ca95b02SDimitry Andric     MI.getOperand(CCDef).setIsDead(false);
3834ba319b5SDimitry Andric   }
3844ba319b5SDimitry Andric 
3854ba319b5SDimitry Andric   // Check if MI lies before Compare.
3864ba319b5SDimitry Andric   bool BeforeCmp = false;
3874ba319b5SDimitry Andric   MachineBasicBlock::iterator MBBI = MI, MBBE = MI.getParent()->end();
3884ba319b5SDimitry Andric   for (++MBBI; MBBI != MBBE; ++MBBI)
3894ba319b5SDimitry Andric     if (MBBI == Compare) {
3904ba319b5SDimitry Andric       BeforeCmp = true;
3914ba319b5SDimitry Andric       break;
3924ba319b5SDimitry Andric     }
393f785676fSDimitry Andric 
394f785676fSDimitry Andric   // Clear any intervening kills of CC.
3954ba319b5SDimitry Andric   if (BeforeCmp) {
396f785676fSDimitry Andric     MachineBasicBlock::iterator MBBI = MI, MBBE = Compare;
397f785676fSDimitry Andric     for (++MBBI; MBBI != MBBE; ++MBBI)
398f785676fSDimitry Andric       MBBI->clearRegisterKills(SystemZ::CC, TRI);
3994ba319b5SDimitry Andric   }
400f785676fSDimitry Andric 
401f785676fSDimitry Andric   return true;
402f785676fSDimitry Andric }
403f785676fSDimitry Andric 
404f785676fSDimitry Andric // Return true if Compare is a comparison against zero.
isCompareZero(MachineInstr & Compare)4053ca95b02SDimitry Andric static bool isCompareZero(MachineInstr &Compare) {
4063ca95b02SDimitry Andric   switch (Compare.getOpcode()) {
407f785676fSDimitry Andric   case SystemZ::LTEBRCompare:
408f785676fSDimitry Andric   case SystemZ::LTDBRCompare:
409f785676fSDimitry Andric   case SystemZ::LTXBRCompare:
410f785676fSDimitry Andric     return true;
411f785676fSDimitry Andric 
412f785676fSDimitry Andric   default:
4137d523365SDimitry Andric     if (isLoadAndTestAsCmp(Compare))
4147d523365SDimitry Andric       return true;
4153ca95b02SDimitry Andric     return Compare.getNumExplicitOperands() == 2 &&
4163ca95b02SDimitry Andric            Compare.getOperand(1).isImm() && Compare.getOperand(1).getImm() == 0;
417f785676fSDimitry Andric   }
418f785676fSDimitry Andric }
419f785676fSDimitry Andric 
420f785676fSDimitry Andric // Try to optimize cases where comparison instruction Compare is testing
421f785676fSDimitry Andric // a value against zero.  Return true on success and if Compare should be
422f785676fSDimitry Andric // deleted as dead.  CCUsers is the list of instructions that use the CC
423f785676fSDimitry Andric // value produced by Compare.
optimizeCompareZero(MachineInstr & Compare,SmallVectorImpl<MachineInstr * > & CCUsers)4243ca95b02SDimitry Andric bool SystemZElimCompare::optimizeCompareZero(
4253ca95b02SDimitry Andric     MachineInstr &Compare, SmallVectorImpl<MachineInstr *> &CCUsers) {
426f785676fSDimitry Andric   if (!isCompareZero(Compare))
427f785676fSDimitry Andric     return false;
428f785676fSDimitry Andric 
429f785676fSDimitry Andric   // Search back for CC results that are based on the first operand.
4307d523365SDimitry Andric   unsigned SrcReg = getCompareSourceReg(Compare);
4313ca95b02SDimitry Andric   MachineBasicBlock &MBB = *Compare.getParent();
432f785676fSDimitry Andric   Reference CCRefs;
433f785676fSDimitry Andric   Reference SrcRefs;
4344ba319b5SDimitry Andric   for (MachineBasicBlock::reverse_iterator MBBI =
4354ba319b5SDimitry Andric          std::next(MachineBasicBlock::reverse_iterator(&Compare)),
4364ba319b5SDimitry Andric          MBBE = MBB.rend(); MBBI != MBBE;) {
4374ba319b5SDimitry Andric     MachineInstr &MI = *MBBI++;
4387d523365SDimitry Andric     if (resultTests(MI, SrcReg)) {
439f785676fSDimitry Andric       // Try to remove both MI and Compare by converting a branch to BRCT(G).
440d88c1a5aSDimitry Andric       // or a load-and-trap instruction.  We don't care in this case whether
441d88c1a5aSDimitry Andric       // CC is modified between MI and Compare.
442d88c1a5aSDimitry Andric       if (!CCRefs.Use && !SrcRefs) {
443d88c1a5aSDimitry Andric         if (convertToBRCT(MI, Compare, CCUsers)) {
444f785676fSDimitry Andric           BranchOnCounts += 1;
445f785676fSDimitry Andric           return true;
446f785676fSDimitry Andric         }
447d88c1a5aSDimitry Andric         if (convertToLoadAndTrap(MI, Compare, CCUsers)) {
448d88c1a5aSDimitry Andric           LoadAndTraps += 1;
449d88c1a5aSDimitry Andric           return true;
450d88c1a5aSDimitry Andric         }
451d88c1a5aSDimitry Andric       }
452f785676fSDimitry Andric       // Try to eliminate Compare by reusing a CC result from MI.
4534ba319b5SDimitry Andric       if ((!CCRefs && convertToLoadAndTest(MI, Compare, CCUsers)) ||
454f785676fSDimitry Andric           (!CCRefs.Def && adjustCCMasksForInstr(MI, Compare, CCUsers))) {
455f785676fSDimitry Andric         EliminatedComparisons += 1;
456f785676fSDimitry Andric         return true;
457f785676fSDimitry Andric       }
458f785676fSDimitry Andric     }
459f785676fSDimitry Andric     SrcRefs |= getRegReferences(MI, SrcReg);
460f785676fSDimitry Andric     if (SrcRefs.Def)
4612cab237bSDimitry Andric       break;
462f785676fSDimitry Andric     CCRefs |= getRegReferences(MI, SystemZ::CC);
463f785676fSDimitry Andric     if (CCRefs.Use && CCRefs.Def)
4642cab237bSDimitry Andric       break;
4652cab237bSDimitry Andric   }
4662cab237bSDimitry Andric 
4672cab237bSDimitry Andric   // Also do a forward search to handle cases where an instruction after the
4684ba319b5SDimitry Andric   // compare can be converted, like
4694ba319b5SDimitry Andric   // LTEBRCompare %f0s, %f0s; %f2s = LER %f0s  =>  LTEBRCompare %f2s, %f0s
4704ba319b5SDimitry Andric   for (MachineBasicBlock::iterator MBBI =
4714ba319b5SDimitry Andric          std::next(MachineBasicBlock::iterator(&Compare)), MBBE = MBB.end();
4724ba319b5SDimitry Andric        MBBI != MBBE;) {
4734ba319b5SDimitry Andric     MachineInstr &MI = *MBBI++;
4742cab237bSDimitry Andric     if (preservesValueOf(MI, SrcReg)) {
4752cab237bSDimitry Andric       // Try to eliminate Compare by reusing a CC result from MI.
4764ba319b5SDimitry Andric       if (convertToLoadAndTest(MI, Compare, CCUsers)) {
4772cab237bSDimitry Andric         EliminatedComparisons += 1;
4782cab237bSDimitry Andric         return true;
4792cab237bSDimitry Andric       }
4802cab237bSDimitry Andric     }
4812cab237bSDimitry Andric     if (getRegReferences(MI, SrcReg).Def)
4822cab237bSDimitry Andric       return false;
4832cab237bSDimitry Andric     if (getRegReferences(MI, SystemZ::CC))
484f785676fSDimitry Andric       return false;
485f785676fSDimitry Andric   }
4862cab237bSDimitry Andric 
487f785676fSDimitry Andric   return false;
488f785676fSDimitry Andric }
489f785676fSDimitry Andric 
490f785676fSDimitry Andric // Try to fuse comparison instruction Compare into a later branch.
491f785676fSDimitry Andric // Return true on success and if Compare is therefore redundant.
fuseCompareOperations(MachineInstr & Compare,SmallVectorImpl<MachineInstr * > & CCUsers)4923ca95b02SDimitry Andric bool SystemZElimCompare::fuseCompareOperations(
4933ca95b02SDimitry Andric     MachineInstr &Compare, SmallVectorImpl<MachineInstr *> &CCUsers) {
494f785676fSDimitry Andric   // See whether we have a single branch with which to fuse.
495f785676fSDimitry Andric   if (CCUsers.size() != 1)
496f785676fSDimitry Andric     return false;
497f785676fSDimitry Andric   MachineInstr *Branch = CCUsers[0];
4983ca95b02SDimitry Andric   SystemZII::FusedCompareType Type;
4993ca95b02SDimitry Andric   switch (Branch->getOpcode()) {
5003ca95b02SDimitry Andric   case SystemZ::BRC:
5013ca95b02SDimitry Andric     Type = SystemZII::CompareAndBranch;
5023ca95b02SDimitry Andric     break;
5033ca95b02SDimitry Andric   case SystemZ::CondReturn:
5043ca95b02SDimitry Andric     Type = SystemZII::CompareAndReturn;
5053ca95b02SDimitry Andric     break;
5063ca95b02SDimitry Andric   case SystemZ::CallBCR:
5073ca95b02SDimitry Andric     Type = SystemZII::CompareAndSibcall;
5083ca95b02SDimitry Andric     break;
5093ca95b02SDimitry Andric   case SystemZ::CondTrap:
5103ca95b02SDimitry Andric     Type = SystemZII::CompareAndTrap;
5113ca95b02SDimitry Andric     break;
5123ca95b02SDimitry Andric   default:
5133ca95b02SDimitry Andric     return false;
5143ca95b02SDimitry Andric   }
5153ca95b02SDimitry Andric 
5163ca95b02SDimitry Andric   // See whether we have a comparison that can be fused.
5173ca95b02SDimitry Andric   unsigned FusedOpcode =
5183ca95b02SDimitry Andric       TII->getFusedCompare(Compare.getOpcode(), Type, &Compare);
5193ca95b02SDimitry Andric   if (!FusedOpcode)
520f785676fSDimitry Andric     return false;
521f785676fSDimitry Andric 
522f785676fSDimitry Andric   // Make sure that the operands are available at the branch.
523d88c1a5aSDimitry Andric   // SrcReg2 is the register if the source operand is a register,
524d88c1a5aSDimitry Andric   // 0 if the source operand is immediate, and the base register
525d88c1a5aSDimitry Andric   // if the source operand is memory (index is not supported).
5263ca95b02SDimitry Andric   unsigned SrcReg = Compare.getOperand(0).getReg();
5273ca95b02SDimitry Andric   unsigned SrcReg2 =
5283ca95b02SDimitry Andric       Compare.getOperand(1).isReg() ? Compare.getOperand(1).getReg() : 0;
529f785676fSDimitry Andric   MachineBasicBlock::iterator MBBI = Compare, MBBE = Branch;
530f785676fSDimitry Andric   for (++MBBI; MBBI != MBBE; ++MBBI)
531f785676fSDimitry Andric     if (MBBI->modifiesRegister(SrcReg, TRI) ||
532f785676fSDimitry Andric         (SrcReg2 && MBBI->modifiesRegister(SrcReg2, TRI)))
533f785676fSDimitry Andric       return false;
534f785676fSDimitry Andric 
5353ca95b02SDimitry Andric   // Read the branch mask, target (if applicable), regmask (if applicable).
536f785676fSDimitry Andric   MachineOperand CCMask(MBBI->getOperand(1));
537f785676fSDimitry Andric   assert((CCMask.getImm() & ~SystemZ::CCMASK_ICMP) == 0 &&
538f785676fSDimitry Andric          "Invalid condition-code mask for integer comparison");
5393ca95b02SDimitry Andric   // This is only valid for CompareAndBranch.
5403ca95b02SDimitry Andric   MachineOperand Target(MBBI->getOperand(
5413ca95b02SDimitry Andric     Type == SystemZII::CompareAndBranch ? 2 : 0));
5423ca95b02SDimitry Andric   const uint32_t *RegMask;
5433ca95b02SDimitry Andric   if (Type == SystemZII::CompareAndSibcall)
5443ca95b02SDimitry Andric     RegMask = MBBI->getOperand(2).getRegMask();
545f785676fSDimitry Andric 
546f785676fSDimitry Andric   // Clear out all current operands.
547f785676fSDimitry Andric   int CCUse = MBBI->findRegisterUseOperandIdx(SystemZ::CC, false, TRI);
5483ca95b02SDimitry Andric   assert(CCUse >= 0 && "BRC/BCR must use CC");
549f785676fSDimitry Andric   Branch->RemoveOperand(CCUse);
5503ca95b02SDimitry Andric   // Remove target (branch) or regmask (sibcall).
5513ca95b02SDimitry Andric   if (Type == SystemZII::CompareAndBranch ||
5523ca95b02SDimitry Andric       Type == SystemZII::CompareAndSibcall)
553f785676fSDimitry Andric     Branch->RemoveOperand(2);
554f785676fSDimitry Andric   Branch->RemoveOperand(1);
555f785676fSDimitry Andric   Branch->RemoveOperand(0);
556f785676fSDimitry Andric 
557f785676fSDimitry Andric   // Rebuild Branch as a fused compare and branch.
558d88c1a5aSDimitry Andric   // SrcNOps is the number of MI operands of the compare instruction
559d88c1a5aSDimitry Andric   // that we need to copy over.
560d88c1a5aSDimitry Andric   unsigned SrcNOps = 2;
561d88c1a5aSDimitry Andric   if (FusedOpcode == SystemZ::CLT || FusedOpcode == SystemZ::CLGT)
562d88c1a5aSDimitry Andric     SrcNOps = 3;
563f785676fSDimitry Andric   Branch->setDesc(TII->get(FusedOpcode));
5643ca95b02SDimitry Andric   MachineInstrBuilder MIB(*Branch->getParent()->getParent(), Branch);
565d88c1a5aSDimitry Andric   for (unsigned I = 0; I < SrcNOps; I++)
5667a7e6055SDimitry Andric     MIB.add(Compare.getOperand(I));
5677a7e6055SDimitry Andric   MIB.add(CCMask);
5683ca95b02SDimitry Andric 
5693ca95b02SDimitry Andric   if (Type == SystemZII::CompareAndBranch) {
5703ca95b02SDimitry Andric     // Only conditional branches define CC, as they may be converted back
5713ca95b02SDimitry Andric     // to a non-fused branch because of a long displacement.  Conditional
5723ca95b02SDimitry Andric     // returns don't have that problem.
5737a7e6055SDimitry Andric     MIB.add(Target).addReg(SystemZ::CC,
5747a7e6055SDimitry Andric                            RegState::ImplicitDefine | RegState::Dead);
5753ca95b02SDimitry Andric   }
5763ca95b02SDimitry Andric 
5773ca95b02SDimitry Andric   if (Type == SystemZII::CompareAndSibcall)
5783ca95b02SDimitry Andric     MIB.addRegMask(RegMask);
579f785676fSDimitry Andric 
580f785676fSDimitry Andric   // Clear any intervening kills of SrcReg and SrcReg2.
581f785676fSDimitry Andric   MBBI = Compare;
582f785676fSDimitry Andric   for (++MBBI; MBBI != MBBE; ++MBBI) {
583f785676fSDimitry Andric     MBBI->clearRegisterKills(SrcReg, TRI);
584f785676fSDimitry Andric     if (SrcReg2)
585f785676fSDimitry Andric       MBBI->clearRegisterKills(SrcReg2, TRI);
586f785676fSDimitry Andric   }
587f785676fSDimitry Andric   FusedComparisons += 1;
588f785676fSDimitry Andric   return true;
589f785676fSDimitry Andric }
590f785676fSDimitry Andric 
591f785676fSDimitry Andric // Process all comparison instructions in MBB.  Return true if something
592f785676fSDimitry Andric // changed.
processBlock(MachineBasicBlock & MBB)59391bc56edSDimitry Andric bool SystemZElimCompare::processBlock(MachineBasicBlock &MBB) {
594f785676fSDimitry Andric   bool Changed = false;
595f785676fSDimitry Andric 
596f785676fSDimitry Andric   // Walk backwards through the block looking for comparisons, recording
597f785676fSDimitry Andric   // all CC users as we go.  The subroutines can delete Compare and
598f785676fSDimitry Andric   // instructions before it.
599f785676fSDimitry Andric   bool CompleteCCUsers = !isCCLiveOut(MBB);
600f785676fSDimitry Andric   SmallVector<MachineInstr *, 4> CCUsers;
60191bc56edSDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.end();
60291bc56edSDimitry Andric   while (MBBI != MBB.begin()) {
6033ca95b02SDimitry Andric     MachineInstr &MI = *--MBBI;
6043ca95b02SDimitry Andric     if (CompleteCCUsers && (MI.isCompare() || isLoadAndTestAsCmp(MI)) &&
605f785676fSDimitry Andric         (optimizeCompareZero(MI, CCUsers) ||
6063ca95b02SDimitry Andric          fuseCompareOperations(MI, CCUsers))) {
607f785676fSDimitry Andric       ++MBBI;
6083ca95b02SDimitry Andric       MI.eraseFromParent();
609f785676fSDimitry Andric       Changed = true;
610f785676fSDimitry Andric       CCUsers.clear();
611f785676fSDimitry Andric       continue;
612f785676fSDimitry Andric     }
613f785676fSDimitry Andric 
6143ca95b02SDimitry Andric     if (MI.definesRegister(SystemZ::CC)) {
615f785676fSDimitry Andric       CCUsers.clear();
6167d523365SDimitry Andric       CompleteCCUsers = true;
617f785676fSDimitry Andric     }
6183ca95b02SDimitry Andric     if (MI.readsRegister(SystemZ::CC) && CompleteCCUsers)
6193ca95b02SDimitry Andric       CCUsers.push_back(&MI);
620f785676fSDimitry Andric   }
621f785676fSDimitry Andric   return Changed;
622f785676fSDimitry Andric }
623f785676fSDimitry Andric 
runOnMachineFunction(MachineFunction & F)624f785676fSDimitry Andric bool SystemZElimCompare::runOnMachineFunction(MachineFunction &F) {
6252cab237bSDimitry Andric   if (skipFunction(F.getFunction()))
6263ca95b02SDimitry Andric     return false;
6273ca95b02SDimitry Andric 
62839d628a0SDimitry Andric   TII = static_cast<const SystemZInstrInfo *>(F.getSubtarget().getInstrInfo());
629f785676fSDimitry Andric   TRI = &TII->getRegisterInfo();
630f785676fSDimitry Andric 
631f785676fSDimitry Andric   bool Changed = false;
63291bc56edSDimitry Andric   for (auto &MBB : F)
63391bc56edSDimitry Andric     Changed |= processBlock(MBB);
634f785676fSDimitry Andric 
635f785676fSDimitry Andric   return Changed;
636f785676fSDimitry Andric }
6377a7e6055SDimitry Andric 
createSystemZElimComparePass(SystemZTargetMachine & TM)6387a7e6055SDimitry Andric FunctionPass *llvm::createSystemZElimComparePass(SystemZTargetMachine &TM) {
6397a7e6055SDimitry Andric   return new SystemZElimCompare(TM);
6407a7e6055SDimitry Andric }
641