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