1bdbb8af7SRichard Sandiford //===-- SystemZElimCompare.cpp - Eliminate comparison instructions --------===//
2bdbb8af7SRichard Sandiford //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bdbb8af7SRichard Sandiford //
7bdbb8af7SRichard Sandiford //===----------------------------------------------------------------------===//
8bdbb8af7SRichard Sandiford //
9bdbb8af7SRichard Sandiford // This pass:
10bdbb8af7SRichard Sandiford // (1) tries to remove compares if CC already contains the required information
11bdbb8af7SRichard Sandiford // (2) fuses compares and branches into COMPARE AND BRANCH instructions
12bdbb8af7SRichard Sandiford //
13bdbb8af7SRichard Sandiford //===----------------------------------------------------------------------===//
14bdbb8af7SRichard Sandiford 
153943d2b0SEugene Zelenko #include "SystemZ.h"
163943d2b0SEugene Zelenko #include "SystemZInstrInfo.h"
17bdbb8af7SRichard Sandiford #include "SystemZTargetMachine.h"
183943d2b0SEugene Zelenko #include "llvm/ADT/SmallVector.h"
19bdbb8af7SRichard Sandiford #include "llvm/ADT/Statistic.h"
203943d2b0SEugene Zelenko #include "llvm/ADT/StringRef.h"
21bf6744dfSJonas Paulsson #include "llvm/CodeGen/LivePhysRegs.h"
223943d2b0SEugene Zelenko #include "llvm/CodeGen/MachineBasicBlock.h"
233943d2b0SEugene Zelenko #include "llvm/CodeGen/MachineFunction.h"
24bdbb8af7SRichard Sandiford #include "llvm/CodeGen/MachineFunctionPass.h"
253943d2b0SEugene Zelenko #include "llvm/CodeGen/MachineInstr.h"
26bdbb8af7SRichard Sandiford #include "llvm/CodeGen/MachineInstrBuilder.h"
273943d2b0SEugene Zelenko #include "llvm/CodeGen/MachineOperand.h"
28b3bde2eaSDavid Blaikie #include "llvm/CodeGen/TargetRegisterInfo.h"
29b3bde2eaSDavid Blaikie #include "llvm/CodeGen/TargetSubtargetInfo.h"
303943d2b0SEugene Zelenko #include "llvm/MC/MCInstrDesc.h"
313943d2b0SEugene Zelenko #include <cassert>
323943d2b0SEugene Zelenko #include <cstdint>
33bdbb8af7SRichard Sandiford 
34bdbb8af7SRichard Sandiford using namespace llvm;
35bdbb8af7SRichard Sandiford 
3684e68b29SChandler Carruth #define DEBUG_TYPE "systemz-elim-compare"
3784e68b29SChandler Carruth 
38c212125dSRichard Sandiford STATISTIC(BranchOnCounts, "Number of branch-on-count instructions");
392d9e3d9dSUlrich Weigand STATISTIC(LoadAndTraps, "Number of load-and-trap instructions");
40bdbb8af7SRichard Sandiford STATISTIC(EliminatedComparisons, "Number of eliminated comparisons");
41bdbb8af7SRichard Sandiford STATISTIC(FusedComparisons, "Number of fused compare-and-branch instructions");
42bdbb8af7SRichard Sandiford 
43bdbb8af7SRichard Sandiford namespace {
443943d2b0SEugene Zelenko 
45c212125dSRichard Sandiford // Represents the references to a particular register in one or more
46c212125dSRichard Sandiford // instructions.
47c212125dSRichard Sandiford struct Reference {
483943d2b0SEugene Zelenko   Reference() = default;
49c212125dSRichard Sandiford 
operator |=__anonb09c29110111::Reference50c212125dSRichard Sandiford   Reference &operator|=(const Reference &Other) {
51c212125dSRichard Sandiford     Def |= Other.Def;
52c212125dSRichard Sandiford     Use |= Other.Use;
53c212125dSRichard Sandiford     return *this;
54c212125dSRichard Sandiford   }
55c212125dSRichard Sandiford 
operator bool__anonb09c29110111::Reference56b46962feSAaron Ballman   explicit operator bool() const { return Def || Use; }
57c212125dSRichard Sandiford 
58c212125dSRichard Sandiford   // True if the register is defined or used in some form, either directly or
59c212125dSRichard Sandiford   // via a sub- or super-register.
603943d2b0SEugene Zelenko   bool Def = false;
613943d2b0SEugene Zelenko   bool Use = false;
62c212125dSRichard Sandiford };
63c212125dSRichard Sandiford 
64bdbb8af7SRichard Sandiford class SystemZElimCompare : public MachineFunctionPass {
65bdbb8af7SRichard Sandiford public:
66bdbb8af7SRichard Sandiford   static char ID;
673943d2b0SEugene Zelenko 
SystemZElimCompare()68d5ae039eSKai Nacke   SystemZElimCompare() : MachineFunctionPass(ID) {
69d5ae039eSKai Nacke     initializeSystemZElimComparePass(*PassRegistry::getPassRegistry());
70bdbb8af7SRichard Sandiford   }
71bdbb8af7SRichard Sandiford 
7228c111ecSRichard Sandiford   bool processBlock(MachineBasicBlock &MBB);
739d74a5a5SCraig Topper   bool runOnMachineFunction(MachineFunction &F) override;
743943d2b0SEugene Zelenko 
getRequiredProperties() const751dbf7a57SDerek Schuff   MachineFunctionProperties getRequiredProperties() const override {
761dbf7a57SDerek Schuff     return MachineFunctionProperties().set(
771eb47368SMatthias Braun         MachineFunctionProperties::Property::NoVRegs);
781dbf7a57SDerek Schuff   }
79bdbb8af7SRichard Sandiford 
80bdbb8af7SRichard Sandiford private:
814565ec0cSDuncan P. N. Exon Smith   Reference getRegReferences(MachineInstr &MI, unsigned Reg);
824565ec0cSDuncan P. N. Exon Smith   bool convertToBRCT(MachineInstr &MI, MachineInstr &Compare,
83c212125dSRichard Sandiford                      SmallVectorImpl<MachineInstr *> &CCUsers);
842d9e3d9dSUlrich Weigand   bool convertToLoadAndTrap(MachineInstr &MI, MachineInstr &Compare,
852d9e3d9dSUlrich Weigand                             SmallVectorImpl<MachineInstr *> &CCUsers);
86776a81a4SJonas Paulsson   bool convertToLoadAndTest(MachineInstr &MI, MachineInstr &Compare,
871a76f3a2SJonas Paulsson                             SmallVectorImpl<MachineInstr *> &CCUsers);
883174683eSJonas Paulsson   bool convertToLogical(MachineInstr &MI, MachineInstr &Compare,
893174683eSJonas Paulsson                         SmallVectorImpl<MachineInstr *> &CCUsers);
90776a81a4SJonas Paulsson   bool adjustCCMasksForInstr(MachineInstr &MI, MachineInstr &Compare,
91776a81a4SJonas Paulsson                              SmallVectorImpl<MachineInstr *> &CCUsers,
92776a81a4SJonas Paulsson                              unsigned ConvOpc = 0);
934565ec0cSDuncan P. N. Exon Smith   bool optimizeCompareZero(MachineInstr &Compare,
94bdbb8af7SRichard Sandiford                            SmallVectorImpl<MachineInstr *> &CCUsers);
954565ec0cSDuncan P. N. Exon Smith   bool fuseCompareOperations(MachineInstr &Compare,
96bdbb8af7SRichard Sandiford                              SmallVectorImpl<MachineInstr *> &CCUsers);
97bdbb8af7SRichard Sandiford 
983943d2b0SEugene Zelenko   const SystemZInstrInfo *TII = nullptr;
993943d2b0SEugene Zelenko   const TargetRegisterInfo *TRI = nullptr;
100bdbb8af7SRichard Sandiford };
101bdbb8af7SRichard Sandiford 
102bdbb8af7SRichard Sandiford char SystemZElimCompare::ID = 0;
103bdbb8af7SRichard Sandiford 
1043943d2b0SEugene Zelenko } // end anonymous namespace
105bdbb8af7SRichard Sandiford 
106d5ae039eSKai Nacke INITIALIZE_PASS(SystemZElimCompare, DEBUG_TYPE,
107d5ae039eSKai Nacke                 "SystemZ Comparison Elimination", false, false)
108d5ae039eSKai Nacke 
109b0e8a2e6SJonas Paulsson // Returns true if MI is an instruction whose output equals the value in Reg.
preservesValueOf(MachineInstr & MI,unsigned Reg)110b0e8a2e6SJonas Paulsson static bool preservesValueOf(MachineInstr &MI, unsigned Reg) {
1114565ec0cSDuncan P. N. Exon Smith   switch (MI.getOpcode()) {
112b49a3ab2SRichard Sandiford   case SystemZ::LR:
113b49a3ab2SRichard Sandiford   case SystemZ::LGR:
114b49a3ab2SRichard Sandiford   case SystemZ::LGFR:
115b49a3ab2SRichard Sandiford   case SystemZ::LTR:
116b49a3ab2SRichard Sandiford   case SystemZ::LTGR:
117b49a3ab2SRichard Sandiford   case SystemZ::LTGFR:
1180897fce2SRichard Sandiford   case SystemZ::LER:
1190897fce2SRichard Sandiford   case SystemZ::LDR:
1200897fce2SRichard Sandiford   case SystemZ::LXR:
1210897fce2SRichard Sandiford   case SystemZ::LTEBR:
1220897fce2SRichard Sandiford   case SystemZ::LTDBR:
1230897fce2SRichard Sandiford   case SystemZ::LTXBR:
1244565ec0cSDuncan P. N. Exon Smith     if (MI.getOperand(1).getReg() == Reg)
125b49a3ab2SRichard Sandiford       return true;
126b49a3ab2SRichard Sandiford   }
127b49a3ab2SRichard Sandiford 
128bdbb8af7SRichard Sandiford   return false;
129bdbb8af7SRichard Sandiford }
130bdbb8af7SRichard Sandiford 
131b0e8a2e6SJonas Paulsson // Return true if any CC result of MI would (perhaps after conversion)
132b0e8a2e6SJonas Paulsson // reflect the value of Reg.
resultTests(MachineInstr & MI,unsigned Reg)133b0e8a2e6SJonas Paulsson static bool resultTests(MachineInstr &MI, unsigned Reg) {
134b0e8a2e6SJonas Paulsson   if (MI.getNumOperands() > 0 && MI.getOperand(0).isReg() &&
135b0e8a2e6SJonas Paulsson       MI.getOperand(0).isDef() && MI.getOperand(0).getReg() == Reg)
136b0e8a2e6SJonas Paulsson     return true;
137b0e8a2e6SJonas Paulsson 
138b0e8a2e6SJonas Paulsson   return (preservesValueOf(MI, Reg));
139b0e8a2e6SJonas Paulsson }
140b0e8a2e6SJonas Paulsson 
141ee3685fdSJonas Paulsson // Describe the references to Reg or any of its aliases in MI.
getRegReferences(MachineInstr & MI,unsigned Reg)1424565ec0cSDuncan P. N. Exon Smith Reference SystemZElimCompare::getRegReferences(MachineInstr &MI, unsigned Reg) {
143c212125dSRichard Sandiford   Reference Ref;
144961c47ecSJonas Paulsson   if (MI.isDebugInstr())
145961c47ecSJonas Paulsson     return Ref;
146961c47ecSJonas Paulsson 
147ff649e08SKazu Hirata   for (const MachineOperand &MO : MI.operands()) {
148c212125dSRichard Sandiford     if (MO.isReg()) {
1490c476111SDaniel Sanders       if (Register MOReg = MO.getReg()) {
150ee3685fdSJonas Paulsson         if (TRI->regsOverlap(MOReg, Reg)) {
151ee3685fdSJonas Paulsson           if (MO.isUse())
152c212125dSRichard Sandiford             Ref.Use = true;
153ee3685fdSJonas Paulsson           else if (MO.isDef())
154c212125dSRichard Sandiford             Ref.Def = true;
155c212125dSRichard Sandiford         }
156c212125dSRichard Sandiford       }
157c212125dSRichard Sandiford     }
158c212125dSRichard Sandiford   }
159c212125dSRichard Sandiford   return Ref;
160c212125dSRichard Sandiford }
161c212125dSRichard Sandiford 
1625d3fbd37SJonas Paulsson // Return true if this is a load and test which can be optimized the
1635d3fbd37SJonas Paulsson // same way as compare instruction.
isLoadAndTestAsCmp(MachineInstr & MI)1644565ec0cSDuncan P. N. Exon Smith static bool isLoadAndTestAsCmp(MachineInstr &MI) {
1655d3fbd37SJonas Paulsson   // If we during isel used a load-and-test as a compare with 0, the
1665d3fbd37SJonas Paulsson   // def operand is dead.
1674565ec0cSDuncan P. N. Exon Smith   return (MI.getOpcode() == SystemZ::LTEBR ||
1684565ec0cSDuncan P. N. Exon Smith           MI.getOpcode() == SystemZ::LTDBR ||
1694565ec0cSDuncan P. N. Exon Smith           MI.getOpcode() == SystemZ::LTXBR) &&
1704565ec0cSDuncan P. N. Exon Smith          MI.getOperand(0).isDead();
1715d3fbd37SJonas Paulsson }
1725d3fbd37SJonas Paulsson 
1735d3fbd37SJonas Paulsson // Return the source register of Compare, which is the unknown value
1745d3fbd37SJonas Paulsson // being tested.
getCompareSourceReg(MachineInstr & Compare)1754565ec0cSDuncan P. N. Exon Smith static unsigned getCompareSourceReg(MachineInstr &Compare) {
1765d3fbd37SJonas Paulsson   unsigned reg = 0;
1774565ec0cSDuncan P. N. Exon Smith   if (Compare.isCompare())
1784565ec0cSDuncan P. N. Exon Smith     reg = Compare.getOperand(0).getReg();
1795d3fbd37SJonas Paulsson   else if (isLoadAndTestAsCmp(Compare))
1804565ec0cSDuncan P. N. Exon Smith     reg = Compare.getOperand(1).getReg();
1815d3fbd37SJonas Paulsson   assert(reg);
1825d3fbd37SJonas Paulsson 
1835d3fbd37SJonas Paulsson   return reg;
1845d3fbd37SJonas Paulsson }
1855d3fbd37SJonas Paulsson 
186c212125dSRichard Sandiford // Compare compares the result of MI against zero.  If MI is an addition
187c212125dSRichard Sandiford // of -1 and if CCUsers is a single branch on nonzero, eliminate the addition
18875839913SUlrich Weigand // and convert the branch to a BRCT(G) or BRCTH.  Return true on success.
convertToBRCT(MachineInstr & MI,MachineInstr & Compare,SmallVectorImpl<MachineInstr * > & CCUsers)1894565ec0cSDuncan P. N. Exon Smith bool SystemZElimCompare::convertToBRCT(
1904565ec0cSDuncan P. N. Exon Smith     MachineInstr &MI, MachineInstr &Compare,
191c212125dSRichard Sandiford     SmallVectorImpl<MachineInstr *> &CCUsers) {
192c212125dSRichard Sandiford   // Check whether we have an addition of -1.
1934565ec0cSDuncan P. N. Exon Smith   unsigned Opcode = MI.getOpcode();
194c212125dSRichard Sandiford   unsigned BRCT;
195c212125dSRichard Sandiford   if (Opcode == SystemZ::AHI)
196c212125dSRichard Sandiford     BRCT = SystemZ::BRCT;
197c212125dSRichard Sandiford   else if (Opcode == SystemZ::AGHI)
198c212125dSRichard Sandiford     BRCT = SystemZ::BRCTG;
19975839913SUlrich Weigand   else if (Opcode == SystemZ::AIH)
20075839913SUlrich Weigand     BRCT = SystemZ::BRCTH;
201c212125dSRichard Sandiford   else
202c212125dSRichard Sandiford     return false;
2034565ec0cSDuncan P. N. Exon Smith   if (MI.getOperand(2).getImm() != -1)
204c212125dSRichard Sandiford     return false;
205c212125dSRichard Sandiford 
206c212125dSRichard Sandiford   // Check whether we have a single JLH.
207c212125dSRichard Sandiford   if (CCUsers.size() != 1)
208c212125dSRichard Sandiford     return false;
209c212125dSRichard Sandiford   MachineInstr *Branch = CCUsers[0];
210c212125dSRichard Sandiford   if (Branch->getOpcode() != SystemZ::BRC ||
211c212125dSRichard Sandiford       Branch->getOperand(0).getImm() != SystemZ::CCMASK_ICMP ||
212c212125dSRichard Sandiford       Branch->getOperand(1).getImm() != SystemZ::CCMASK_CMP_NE)
213c212125dSRichard Sandiford     return false;
214c212125dSRichard Sandiford 
215c212125dSRichard Sandiford   // We already know that there are no references to the register between
216c212125dSRichard Sandiford   // MI and Compare.  Make sure that there are also no references between
217c212125dSRichard Sandiford   // Compare and Branch.
2185d3fbd37SJonas Paulsson   unsigned SrcReg = getCompareSourceReg(Compare);
219c212125dSRichard Sandiford   MachineBasicBlock::iterator MBBI = Compare, MBBE = Branch;
220c212125dSRichard Sandiford   for (++MBBI; MBBI != MBBE; ++MBBI)
2214565ec0cSDuncan P. N. Exon Smith     if (getRegReferences(*MBBI, SrcReg))
222c212125dSRichard Sandiford       return false;
223c212125dSRichard Sandiford 
22475839913SUlrich Weigand   // The transformation is OK.  Rebuild Branch as a BRCT(G) or BRCTH.
225c212125dSRichard Sandiford   MachineOperand Target(Branch->getOperand(2));
22663a2b686SJonas Paulsson   while (Branch->getNumOperands())
22737b37838SShengchen Kan     Branch->removeOperand(0);
228c212125dSRichard Sandiford   Branch->setDesc(TII->get(BRCT));
22975839913SUlrich Weigand   MachineInstrBuilder MIB(*Branch->getParent()->getParent(), Branch);
230116bbab4SDiana Picus   MIB.add(MI.getOperand(0)).add(MI.getOperand(1)).add(Target);
23175839913SUlrich Weigand   // Add a CC def to BRCT(G), since we may have to split them again if the
23275839913SUlrich Weigand   // branch displacement overflows.  BRCTH has a 32-bit displacement, so
23375839913SUlrich Weigand   // this is not necessary there.
23475839913SUlrich Weigand   if (BRCT != SystemZ::BRCTH)
23575839913SUlrich Weigand     MIB.addReg(SystemZ::CC, RegState::ImplicitDefine | RegState::Dead);
2364565ec0cSDuncan P. N. Exon Smith   MI.eraseFromParent();
237c212125dSRichard Sandiford   return true;
238c212125dSRichard Sandiford }
239c212125dSRichard Sandiford 
2402d9e3d9dSUlrich Weigand // Compare compares the result of MI against zero.  If MI is a suitable load
2412d9e3d9dSUlrich Weigand // instruction and if CCUsers is a single conditional trap on zero, eliminate
2422d9e3d9dSUlrich Weigand // the load and convert the branch to a load-and-trap.  Return true on success.
convertToLoadAndTrap(MachineInstr & MI,MachineInstr & Compare,SmallVectorImpl<MachineInstr * > & CCUsers)2432d9e3d9dSUlrich Weigand bool SystemZElimCompare::convertToLoadAndTrap(
2442d9e3d9dSUlrich Weigand     MachineInstr &MI, MachineInstr &Compare,
2452d9e3d9dSUlrich Weigand     SmallVectorImpl<MachineInstr *> &CCUsers) {
2462d9e3d9dSUlrich Weigand   unsigned LATOpcode = TII->getLoadAndTrap(MI.getOpcode());
2472d9e3d9dSUlrich Weigand   if (!LATOpcode)
2482d9e3d9dSUlrich Weigand     return false;
2492d9e3d9dSUlrich Weigand 
2502d9e3d9dSUlrich Weigand   // Check whether we have a single CondTrap that traps on zero.
2512d9e3d9dSUlrich Weigand   if (CCUsers.size() != 1)
2522d9e3d9dSUlrich Weigand     return false;
2532d9e3d9dSUlrich Weigand   MachineInstr *Branch = CCUsers[0];
2542d9e3d9dSUlrich Weigand   if (Branch->getOpcode() != SystemZ::CondTrap ||
2552d9e3d9dSUlrich Weigand       Branch->getOperand(0).getImm() != SystemZ::CCMASK_ICMP ||
2562d9e3d9dSUlrich Weigand       Branch->getOperand(1).getImm() != SystemZ::CCMASK_CMP_EQ)
2572d9e3d9dSUlrich Weigand     return false;
2582d9e3d9dSUlrich Weigand 
2592d9e3d9dSUlrich Weigand   // We already know that there are no references to the register between
2602d9e3d9dSUlrich Weigand   // MI and Compare.  Make sure that there are also no references between
2612d9e3d9dSUlrich Weigand   // Compare and Branch.
2622d9e3d9dSUlrich Weigand   unsigned SrcReg = getCompareSourceReg(Compare);
2632d9e3d9dSUlrich Weigand   MachineBasicBlock::iterator MBBI = Compare, MBBE = Branch;
2642d9e3d9dSUlrich Weigand   for (++MBBI; MBBI != MBBE; ++MBBI)
2652d9e3d9dSUlrich Weigand     if (getRegReferences(*MBBI, SrcReg))
2662d9e3d9dSUlrich Weigand       return false;
2672d9e3d9dSUlrich Weigand 
2682d9e3d9dSUlrich Weigand   // The transformation is OK.  Rebuild Branch as a load-and-trap.
2692d9e3d9dSUlrich Weigand   while (Branch->getNumOperands())
27037b37838SShengchen Kan     Branch->removeOperand(0);
2712d9e3d9dSUlrich Weigand   Branch->setDesc(TII->get(LATOpcode));
2722d9e3d9dSUlrich Weigand   MachineInstrBuilder(*Branch->getParent()->getParent(), Branch)
273116bbab4SDiana Picus       .add(MI.getOperand(0))
274116bbab4SDiana Picus       .add(MI.getOperand(1))
275116bbab4SDiana Picus       .add(MI.getOperand(2))
276116bbab4SDiana Picus       .add(MI.getOperand(3));
2772d9e3d9dSUlrich Weigand   MI.eraseFromParent();
2782d9e3d9dSUlrich Weigand   return true;
2792d9e3d9dSUlrich Weigand }
2802d9e3d9dSUlrich Weigand 
281b49a3ab2SRichard Sandiford // If MI is a load instruction, try to convert it into a LOAD AND TEST.
282b49a3ab2SRichard Sandiford // Return true on success.
convertToLoadAndTest(MachineInstr & MI,MachineInstr & Compare,SmallVectorImpl<MachineInstr * > & CCUsers)283776a81a4SJonas Paulsson bool SystemZElimCompare::convertToLoadAndTest(
284776a81a4SJonas Paulsson     MachineInstr &MI, MachineInstr &Compare,
285776a81a4SJonas Paulsson     SmallVectorImpl<MachineInstr *> &CCUsers) {
286776a81a4SJonas Paulsson 
287776a81a4SJonas Paulsson   // Try to adjust CC masks for the LOAD AND TEST opcode that could replace MI.
2884565ec0cSDuncan P. N. Exon Smith   unsigned Opcode = TII->getLoadAndTest(MI.getOpcode());
289776a81a4SJonas Paulsson   if (!Opcode || !adjustCCMasksForInstr(MI, Compare, CCUsers, Opcode))
290b49a3ab2SRichard Sandiford     return false;
291b49a3ab2SRichard Sandiford 
292e80d4057SJonas Paulsson   // Rebuild to get the CC operand in the right place.
293c73c0307SChandler Carruth   auto MIB = BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(Opcode));
294e80d4057SJonas Paulsson   for (const auto &MO : MI.operands())
295c73c0307SChandler Carruth     MIB.add(MO);
296c73c0307SChandler Carruth   MIB.setMemRefs(MI.memoperands());
297e80d4057SJonas Paulsson   MI.eraseFromParent();
298e80d4057SJonas Paulsson 
299f0fd11dfSUlrich Weigand   // Mark instruction as not raising an FP exception if applicable.  We already
3009db13b5aSUlrich Weigand   // verified earlier that this move is valid.
301f0fd11dfSUlrich Weigand   if (!Compare.mayRaiseFPException())
302f0fd11dfSUlrich Weigand     MIB.setMIFlag(MachineInstr::MIFlag::NoFPExcept);
3039db13b5aSUlrich Weigand 
304b49a3ab2SRichard Sandiford   return true;
305b49a3ab2SRichard Sandiford }
306b49a3ab2SRichard Sandiford 
3073174683eSJonas Paulsson // See if MI is an instruction with an equivalent "logical" opcode that can
3083174683eSJonas Paulsson // be used and replace MI. This is useful for EQ/NE comparisons where the
3093174683eSJonas Paulsson // "nsw" flag is missing since the "logical" opcode always sets CC to reflect
3103174683eSJonas Paulsson // the result being zero or non-zero.
convertToLogical(MachineInstr & MI,MachineInstr & Compare,SmallVectorImpl<MachineInstr * > & CCUsers)3113174683eSJonas Paulsson bool SystemZElimCompare::convertToLogical(
3123174683eSJonas Paulsson     MachineInstr &MI, MachineInstr &Compare,
3133174683eSJonas Paulsson     SmallVectorImpl<MachineInstr *> &CCUsers) {
3143174683eSJonas Paulsson 
3153174683eSJonas Paulsson   unsigned ConvOpc = 0;
3163174683eSJonas Paulsson   switch (MI.getOpcode()) {
3173174683eSJonas Paulsson   case SystemZ::AR:   ConvOpc = SystemZ::ALR;   break;
3183174683eSJonas Paulsson   case SystemZ::ARK:  ConvOpc = SystemZ::ALRK;  break;
3193174683eSJonas Paulsson   case SystemZ::AGR:  ConvOpc = SystemZ::ALGR;  break;
3203174683eSJonas Paulsson   case SystemZ::AGRK: ConvOpc = SystemZ::ALGRK; break;
3213174683eSJonas Paulsson   case SystemZ::A:    ConvOpc = SystemZ::AL;    break;
3223174683eSJonas Paulsson   case SystemZ::AY:   ConvOpc = SystemZ::ALY;   break;
3233174683eSJonas Paulsson   case SystemZ::AG:   ConvOpc = SystemZ::ALG;   break;
3243174683eSJonas Paulsson   default: break;
3253174683eSJonas Paulsson   }
3263174683eSJonas Paulsson   if (!ConvOpc || !adjustCCMasksForInstr(MI, Compare, CCUsers, ConvOpc))
3273174683eSJonas Paulsson     return false;
3283174683eSJonas Paulsson 
3293174683eSJonas Paulsson   // Operands should be identical, so just change the opcode and remove the
3303174683eSJonas Paulsson   // dead flag on CC.
3313174683eSJonas Paulsson   MI.setDesc(TII->get(ConvOpc));
3323174683eSJonas Paulsson   MI.clearRegisterDeads(SystemZ::CC);
3333174683eSJonas Paulsson   return true;
3343174683eSJonas Paulsson }
3353174683eSJonas Paulsson 
3363174683eSJonas Paulsson #ifndef NDEBUG
isAddWithImmediate(unsigned Opcode)3373174683eSJonas Paulsson static bool isAddWithImmediate(unsigned Opcode) {
3383174683eSJonas Paulsson   switch(Opcode) {
3393174683eSJonas Paulsson   case SystemZ::AHI:
3403174683eSJonas Paulsson   case SystemZ::AHIK:
3413174683eSJonas Paulsson   case SystemZ::AGHI:
3423174683eSJonas Paulsson   case SystemZ::AGHIK:
3433174683eSJonas Paulsson   case SystemZ::AFI:
3443174683eSJonas Paulsson   case SystemZ::AIH:
3453174683eSJonas Paulsson   case SystemZ::AGFI:
3463174683eSJonas Paulsson     return true;
3473174683eSJonas Paulsson   default: break;
3483174683eSJonas Paulsson   }
3493174683eSJonas Paulsson   return false;
3503174683eSJonas Paulsson }
3513174683eSJonas Paulsson #endif
3523174683eSJonas Paulsson 
353bdbb8af7SRichard Sandiford // The CC users in CCUsers are testing the result of a comparison of some
354776a81a4SJonas Paulsson // value X against zero and we know that any CC value produced by MI would
355776a81a4SJonas Paulsson // also reflect the value of X.  ConvOpc may be used to pass the transfomed
356776a81a4SJonas Paulsson // opcode MI will have if this succeeds.  Try to adjust CCUsers so that they
357776a81a4SJonas Paulsson // test the result of MI directly, returning true on success.  Leave
358776a81a4SJonas Paulsson // everything unchanged on failure.
adjustCCMasksForInstr(MachineInstr & MI,MachineInstr & Compare,SmallVectorImpl<MachineInstr * > & CCUsers,unsigned ConvOpc)3594565ec0cSDuncan P. N. Exon Smith bool SystemZElimCompare::adjustCCMasksForInstr(
3604565ec0cSDuncan P. N. Exon Smith     MachineInstr &MI, MachineInstr &Compare,
361776a81a4SJonas Paulsson     SmallVectorImpl<MachineInstr *> &CCUsers,
362776a81a4SJonas Paulsson     unsigned ConvOpc) {
3633174683eSJonas Paulsson   unsigned CompareFlags = Compare.getDesc().TSFlags;
3643174683eSJonas Paulsson   unsigned CompareCCValues = SystemZII::getCCValues(CompareFlags);
365776a81a4SJonas Paulsson   int Opcode = (ConvOpc ? ConvOpc : MI.getOpcode());
366bdbb8af7SRichard Sandiford   const MCInstrDesc &Desc = TII->get(Opcode);
367bdbb8af7SRichard Sandiford   unsigned MIFlags = Desc.TSFlags;
368bdbb8af7SRichard Sandiford 
3699db13b5aSUlrich Weigand   // If Compare may raise an FP exception, we can only eliminate it
3709db13b5aSUlrich Weigand   // if MI itself would have already raised the exception.
3719db13b5aSUlrich Weigand   if (Compare.mayRaiseFPException()) {
3729db13b5aSUlrich Weigand     // If the caller will change MI to use ConvOpc, only test whether
3739db13b5aSUlrich Weigand     // ConvOpc is suitable; it is on the caller to set the MI flag.
3749db13b5aSUlrich Weigand     if (ConvOpc && !Desc.mayRaiseFPException())
3759db13b5aSUlrich Weigand       return false;
3769db13b5aSUlrich Weigand     // If the caller will not change MI, we test the MI flag here.
3779db13b5aSUlrich Weigand     if (!ConvOpc && !MI.mayRaiseFPException())
3789db13b5aSUlrich Weigand       return false;
3799db13b5aSUlrich Weigand   }
3809db13b5aSUlrich Weigand 
381bdbb8af7SRichard Sandiford   // See which compare-style condition codes are available.
3823174683eSJonas Paulsson   unsigned CCValues = SystemZII::getCCValues(MIFlags);
3833174683eSJonas Paulsson   unsigned ReusableCCMask = CCValues;
384bdbb8af7SRichard Sandiford   // For unsigned comparisons with zero, only equality makes sense.
3850897fce2SRichard Sandiford   if (CompareFlags & SystemZII::IsLogical)
3860897fce2SRichard Sandiford     ReusableCCMask &= SystemZ::CCMASK_CMP_EQ;
3873174683eSJonas Paulsson   unsigned OFImplies = 0;
3883174683eSJonas Paulsson   bool LogicalMI = false;
3893174683eSJonas Paulsson   bool MIEquivalentToCmp = false;
3903174683eSJonas Paulsson   if (MI.getFlag(MachineInstr::NoSWrap) &&
3913174683eSJonas Paulsson       (MIFlags & SystemZII::CCIfNoSignedWrap)) {
3923174683eSJonas Paulsson     // If MI has the NSW flag set in combination with the
3933174683eSJonas Paulsson     // SystemZII::CCIfNoSignedWrap flag, all CCValues are valid.
3943174683eSJonas Paulsson   }
3953174683eSJonas Paulsson   else if ((MIFlags & SystemZII::CCIfNoSignedWrap) &&
3963174683eSJonas Paulsson            MI.getOperand(2).isImm()) {
3973174683eSJonas Paulsson     // Signed addition of immediate. If adding a positive immediate
3983174683eSJonas Paulsson     // overflows, the result must be less than zero. If adding a negative
3993174683eSJonas Paulsson     // immediate overflows, the result must be larger than zero (except in
4003174683eSJonas Paulsson     // the special case of adding the minimum value of the result range, in
4013174683eSJonas Paulsson     // which case we cannot predict whether the result is larger than or
4023174683eSJonas Paulsson     // equal to zero).
4033174683eSJonas Paulsson     assert(isAddWithImmediate(Opcode) && "Expected an add with immediate.");
4043174683eSJonas Paulsson     assert(!MI.mayLoadOrStore() && "Expected an immediate term.");
4053174683eSJonas Paulsson     int64_t RHS = MI.getOperand(2).getImm();
4063174683eSJonas Paulsson     if (SystemZ::GRX32BitRegClass.contains(MI.getOperand(0).getReg()) &&
4073174683eSJonas Paulsson         RHS == INT32_MIN)
4083174683eSJonas Paulsson       return false;
4093174683eSJonas Paulsson     OFImplies = (RHS > 0 ? SystemZ::CCMASK_CMP_LT : SystemZ::CCMASK_CMP_GT);
4103174683eSJonas Paulsson   }
4113174683eSJonas Paulsson   else if ((MIFlags & SystemZII::IsLogical) && CCValues) {
4123174683eSJonas Paulsson     // Use CCMASK_CMP_EQ to match with CCUsers. On success CCMask:s will be
4133174683eSJonas Paulsson     // converted to CCMASK_LOGICAL_ZERO or CCMASK_LOGICAL_NONZERO.
4143174683eSJonas Paulsson     LogicalMI = true;
4153174683eSJonas Paulsson     ReusableCCMask = SystemZ::CCMASK_CMP_EQ;
4163174683eSJonas Paulsson   }
4173174683eSJonas Paulsson   else {
4183174683eSJonas Paulsson     ReusableCCMask &= SystemZII::getCompareZeroCCMask(MIFlags);
4193174683eSJonas Paulsson     assert((ReusableCCMask & ~CCValues) == 0 && "Invalid CCValues");
4203174683eSJonas Paulsson     MIEquivalentToCmp =
4213174683eSJonas Paulsson       ReusableCCMask == CCValues && CCValues == CompareCCValues;
4223174683eSJonas Paulsson   }
423bdbb8af7SRichard Sandiford   if (ReusableCCMask == 0)
424bdbb8af7SRichard Sandiford     return false;
425bdbb8af7SRichard Sandiford 
426776a81a4SJonas Paulsson   if (!MIEquivalentToCmp) {
427bdbb8af7SRichard Sandiford     // Now check whether these flags are enough for all users.
428bdbb8af7SRichard Sandiford     SmallVector<MachineOperand *, 4> AlterMasks;
429bdbb8af7SRichard Sandiford     for (unsigned int I = 0, E = CCUsers.size(); I != E; ++I) {
4303174683eSJonas Paulsson       MachineInstr *CCUserMI = CCUsers[I];
431bdbb8af7SRichard Sandiford 
432bdbb8af7SRichard Sandiford       // Fail if this isn't a use of CC that we understand.
4333174683eSJonas Paulsson       unsigned Flags = CCUserMI->getDesc().TSFlags;
434bdbb8af7SRichard Sandiford       unsigned FirstOpNum;
435bdbb8af7SRichard Sandiford       if (Flags & SystemZII::CCMaskFirst)
436bdbb8af7SRichard Sandiford         FirstOpNum = 0;
437bdbb8af7SRichard Sandiford       else if (Flags & SystemZII::CCMaskLast)
4383174683eSJonas Paulsson         FirstOpNum = CCUserMI->getNumExplicitOperands() - 2;
439bdbb8af7SRichard Sandiford       else
440bdbb8af7SRichard Sandiford         return false;
441bdbb8af7SRichard Sandiford 
442bdbb8af7SRichard Sandiford       // Check whether the instruction predicate treats all CC values
443bdbb8af7SRichard Sandiford       // outside of ReusableCCMask in the same way.  In that case it
444bdbb8af7SRichard Sandiford       // doesn't matter what those CC values mean.
4453174683eSJonas Paulsson       unsigned CCValid = CCUserMI->getOperand(FirstOpNum).getImm();
4463174683eSJonas Paulsson       unsigned CCMask = CCUserMI->getOperand(FirstOpNum + 1).getImm();
4473174683eSJonas Paulsson       assert(CCValid == CompareCCValues && (CCMask & ~CCValid) == 0 &&
4483174683eSJonas Paulsson              "Corrupt CC operands of CCUser.");
449bdbb8af7SRichard Sandiford       unsigned OutValid = ~ReusableCCMask & CCValid;
450bdbb8af7SRichard Sandiford       unsigned OutMask = ~ReusableCCMask & CCMask;
451bdbb8af7SRichard Sandiford       if (OutMask != 0 && OutMask != OutValid)
452bdbb8af7SRichard Sandiford         return false;
453bdbb8af7SRichard Sandiford 
4543174683eSJonas Paulsson       AlterMasks.push_back(&CCUserMI->getOperand(FirstOpNum));
4553174683eSJonas Paulsson       AlterMasks.push_back(&CCUserMI->getOperand(FirstOpNum + 1));
456bdbb8af7SRichard Sandiford     }
457bdbb8af7SRichard Sandiford 
458bdbb8af7SRichard Sandiford     // All users are OK.  Adjust the masks for MI.
459bdbb8af7SRichard Sandiford     for (unsigned I = 0, E = AlterMasks.size(); I != E; I += 2) {
460bdbb8af7SRichard Sandiford       AlterMasks[I]->setImm(CCValues);
461bdbb8af7SRichard Sandiford       unsigned CCMask = AlterMasks[I + 1]->getImm();
4623174683eSJonas Paulsson       if (LogicalMI) {
4633174683eSJonas Paulsson         // Translate the CCMask into its "logical" value.
4643174683eSJonas Paulsson         CCMask = (CCMask == SystemZ::CCMASK_CMP_EQ ?
4653174683eSJonas Paulsson                   SystemZ::CCMASK_LOGICAL_ZERO : SystemZ::CCMASK_LOGICAL_NONZERO);
4663174683eSJonas Paulsson         CCMask &= CCValues; // Logical subtracts never set CC=0.
4673174683eSJonas Paulsson       } else {
468bdbb8af7SRichard Sandiford         if (CCMask & ~ReusableCCMask)
4693174683eSJonas Paulsson           CCMask = (CCMask & ReusableCCMask) | (CCValues & ~ReusableCCMask);
4703174683eSJonas Paulsson         CCMask |= (CCMask & OFImplies) ? SystemZ::CCMASK_ARITH_OVERFLOW : 0;
4713174683eSJonas Paulsson       }
4723174683eSJonas Paulsson       AlterMasks[I + 1]->setImm(CCMask);
473bdbb8af7SRichard Sandiford     }
474776a81a4SJonas Paulsson   }
475bdbb8af7SRichard Sandiford 
476bdbb8af7SRichard Sandiford   // CC is now live after MI.
477ca6f4522SJonas Paulsson   if (!ConvOpc)
478ca6f4522SJonas Paulsson     MI.clearRegisterDeads(SystemZ::CC);
479776a81a4SJonas Paulsson 
480776a81a4SJonas Paulsson   // Check if MI lies before Compare.
481776a81a4SJonas Paulsson   bool BeforeCmp = false;
482776a81a4SJonas Paulsson   MachineBasicBlock::iterator MBBI = MI, MBBE = MI.getParent()->end();
483776a81a4SJonas Paulsson   for (++MBBI; MBBI != MBBE; ++MBBI)
484776a81a4SJonas Paulsson     if (MBBI == Compare) {
485776a81a4SJonas Paulsson       BeforeCmp = true;
486776a81a4SJonas Paulsson       break;
487776a81a4SJonas Paulsson     }
488bdbb8af7SRichard Sandiford 
489bdbb8af7SRichard Sandiford   // Clear any intervening kills of CC.
490776a81a4SJonas Paulsson   if (BeforeCmp) {
491bdbb8af7SRichard Sandiford     MachineBasicBlock::iterator MBBI = MI, MBBE = Compare;
492bdbb8af7SRichard Sandiford     for (++MBBI; MBBI != MBBE; ++MBBI)
493bdbb8af7SRichard Sandiford       MBBI->clearRegisterKills(SystemZ::CC, TRI);
494776a81a4SJonas Paulsson   }
495bdbb8af7SRichard Sandiford 
496bdbb8af7SRichard Sandiford   return true;
497bdbb8af7SRichard Sandiford }
498bdbb8af7SRichard Sandiford 
4990897fce2SRichard Sandiford // Return true if Compare is a comparison against zero.
isCompareZero(MachineInstr & Compare)5004565ec0cSDuncan P. N. Exon Smith static bool isCompareZero(MachineInstr &Compare) {
5014565ec0cSDuncan P. N. Exon Smith   switch (Compare.getOpcode()) {
5020897fce2SRichard Sandiford   case SystemZ::LTEBRCompare:
5030897fce2SRichard Sandiford   case SystemZ::LTDBRCompare:
5040897fce2SRichard Sandiford   case SystemZ::LTXBRCompare:
5050897fce2SRichard Sandiford     return true;
5060897fce2SRichard Sandiford 
5070897fce2SRichard Sandiford   default:
5085d3fbd37SJonas Paulsson     if (isLoadAndTestAsCmp(Compare))
5095d3fbd37SJonas Paulsson       return true;
5104565ec0cSDuncan P. N. Exon Smith     return Compare.getNumExplicitOperands() == 2 &&
5114565ec0cSDuncan P. N. Exon Smith            Compare.getOperand(1).isImm() && Compare.getOperand(1).getImm() == 0;
5120897fce2SRichard Sandiford   }
5130897fce2SRichard Sandiford }
5140897fce2SRichard Sandiford 
515bdbb8af7SRichard Sandiford // Try to optimize cases where comparison instruction Compare is testing
516bdbb8af7SRichard Sandiford // a value against zero.  Return true on success and if Compare should be
517bdbb8af7SRichard Sandiford // deleted as dead.  CCUsers is the list of instructions that use the CC
518bdbb8af7SRichard Sandiford // value produced by Compare.
optimizeCompareZero(MachineInstr & Compare,SmallVectorImpl<MachineInstr * > & CCUsers)5194565ec0cSDuncan P. N. Exon Smith bool SystemZElimCompare::optimizeCompareZero(
5204565ec0cSDuncan P. N. Exon Smith     MachineInstr &Compare, SmallVectorImpl<MachineInstr *> &CCUsers) {
5210897fce2SRichard Sandiford   if (!isCompareZero(Compare))
522bdbb8af7SRichard Sandiford     return false;
523bdbb8af7SRichard Sandiford 
524bdbb8af7SRichard Sandiford   // Search back for CC results that are based on the first operand.
5255d3fbd37SJonas Paulsson   unsigned SrcReg = getCompareSourceReg(Compare);
5264565ec0cSDuncan P. N. Exon Smith   MachineBasicBlock &MBB = *Compare.getParent();
527c212125dSRichard Sandiford   Reference CCRefs;
528c212125dSRichard Sandiford   Reference SrcRefs;
529e80d4057SJonas Paulsson   for (MachineBasicBlock::reverse_iterator MBBI =
530e80d4057SJonas Paulsson          std::next(MachineBasicBlock::reverse_iterator(&Compare)),
531e80d4057SJonas Paulsson          MBBE = MBB.rend(); MBBI != MBBE;) {
532e80d4057SJonas Paulsson     MachineInstr &MI = *MBBI++;
5332c96dd64SJonas Paulsson     if (resultTests(MI, SrcReg)) {
534c212125dSRichard Sandiford       // Try to remove both MI and Compare by converting a branch to BRCT(G).
5352d9e3d9dSUlrich Weigand       // or a load-and-trap instruction.  We don't care in this case whether
5362d9e3d9dSUlrich Weigand       // CC is modified between MI and Compare.
5372d9e3d9dSUlrich Weigand       if (!CCRefs.Use && !SrcRefs) {
5382d9e3d9dSUlrich Weigand         if (convertToBRCT(MI, Compare, CCUsers)) {
539c212125dSRichard Sandiford           BranchOnCounts += 1;
540c212125dSRichard Sandiford           return true;
541c212125dSRichard Sandiford         }
5422d9e3d9dSUlrich Weigand         if (convertToLoadAndTrap(MI, Compare, CCUsers)) {
5432d9e3d9dSUlrich Weigand           LoadAndTraps += 1;
5442d9e3d9dSUlrich Weigand           return true;
5452d9e3d9dSUlrich Weigand         }
5462d9e3d9dSUlrich Weigand       }
547c212125dSRichard Sandiford       // Try to eliminate Compare by reusing a CC result from MI.
548776a81a4SJonas Paulsson       if ((!CCRefs && convertToLoadAndTest(MI, Compare, CCUsers)) ||
5493174683eSJonas Paulsson           (!CCRefs.Def &&
5503174683eSJonas Paulsson            (adjustCCMasksForInstr(MI, Compare, CCUsers) ||
5513174683eSJonas Paulsson             convertToLogical(MI, Compare, CCUsers)))) {
552bdbb8af7SRichard Sandiford         EliminatedComparisons += 1;
553bdbb8af7SRichard Sandiford         return true;
554bdbb8af7SRichard Sandiford       }
555c212125dSRichard Sandiford     }
556c212125dSRichard Sandiford     SrcRefs |= getRegReferences(MI, SrcReg);
557c212125dSRichard Sandiford     if (SrcRefs.Def)
558b0e8a2e6SJonas Paulsson       break;
559c212125dSRichard Sandiford     CCRefs |= getRegReferences(MI, SystemZ::CC);
560c212125dSRichard Sandiford     if (CCRefs.Use && CCRefs.Def)
561b0e8a2e6SJonas Paulsson       break;
5629db13b5aSUlrich Weigand     // Eliminating a Compare that may raise an FP exception will move
5639db13b5aSUlrich Weigand     // raising the exception to some earlier MI.  We cannot do this if
5649db13b5aSUlrich Weigand     // there is anything in between that might change exception flags.
5659db13b5aSUlrich Weigand     if (Compare.mayRaiseFPException() &&
5669db13b5aSUlrich Weigand         (MI.isCall() || MI.hasUnmodeledSideEffects()))
5679db13b5aSUlrich Weigand       break;
568b0e8a2e6SJonas Paulsson   }
569b0e8a2e6SJonas Paulsson 
570b0e8a2e6SJonas Paulsson   // Also do a forward search to handle cases where an instruction after the
57122f208f0SJonas Paulsson   // compare can be converted, like
57222f208f0SJonas Paulsson   // LTEBRCompare %f0s, %f0s; %f2s = LER %f0s  =>  LTEBRCompare %f2s, %f0s
5737f00806aSKazu Hirata   auto MIRange = llvm::make_range(
5747f00806aSKazu Hirata       std::next(MachineBasicBlock::iterator(&Compare)), MBB.end());
5757f00806aSKazu Hirata   for (MachineInstr &MI : llvm::make_early_inc_range(MIRange)) {
576b0e8a2e6SJonas Paulsson     if (preservesValueOf(MI, SrcReg)) {
577b0e8a2e6SJonas Paulsson       // Try to eliminate Compare by reusing a CC result from MI.
578776a81a4SJonas Paulsson       if (convertToLoadAndTest(MI, Compare, CCUsers)) {
579b0e8a2e6SJonas Paulsson         EliminatedComparisons += 1;
580b0e8a2e6SJonas Paulsson         return true;
581b0e8a2e6SJonas Paulsson       }
582b0e8a2e6SJonas Paulsson     }
583b0e8a2e6SJonas Paulsson     if (getRegReferences(MI, SrcReg).Def)
584b0e8a2e6SJonas Paulsson       return false;
585b0e8a2e6SJonas Paulsson     if (getRegReferences(MI, SystemZ::CC))
586c212125dSRichard Sandiford       return false;
587bdbb8af7SRichard Sandiford   }
588b0e8a2e6SJonas Paulsson 
589bdbb8af7SRichard Sandiford   return false;
590bdbb8af7SRichard Sandiford }
591bdbb8af7SRichard Sandiford 
592bdbb8af7SRichard Sandiford // Try to fuse comparison instruction Compare into a later branch.
593bdbb8af7SRichard Sandiford // Return true on success and if Compare is therefore redundant.
fuseCompareOperations(MachineInstr & Compare,SmallVectorImpl<MachineInstr * > & CCUsers)5944565ec0cSDuncan P. N. Exon Smith bool SystemZElimCompare::fuseCompareOperations(
5954565ec0cSDuncan P. N. Exon Smith     MachineInstr &Compare, SmallVectorImpl<MachineInstr *> &CCUsers) {
596bdbb8af7SRichard Sandiford   // See whether we have a single branch with which to fuse.
597bdbb8af7SRichard Sandiford   if (CCUsers.size() != 1)
598bdbb8af7SRichard Sandiford     return false;
599bdbb8af7SRichard Sandiford   MachineInstr *Branch = CCUsers[0];
600ab42cbceSZhan Jun Liau   SystemZII::FusedCompareType Type;
6012eb027d2SUlrich Weigand   switch (Branch->getOpcode()) {
6022eb027d2SUlrich Weigand   case SystemZ::BRC:
6032eb027d2SUlrich Weigand     Type = SystemZII::CompareAndBranch;
6042eb027d2SUlrich Weigand     break;
6052eb027d2SUlrich Weigand   case SystemZ::CondReturn:
6062eb027d2SUlrich Weigand     Type = SystemZII::CompareAndReturn;
6072eb027d2SUlrich Weigand     break;
608848a513dSUlrich Weigand   case SystemZ::CallBCR:
609848a513dSUlrich Weigand     Type = SystemZII::CompareAndSibcall;
610848a513dSUlrich Weigand     break;
611ab42cbceSZhan Jun Liau   case SystemZ::CondTrap:
612ab42cbceSZhan Jun Liau     Type = SystemZII::CompareAndTrap;
613ab42cbceSZhan Jun Liau     break;
6142eb027d2SUlrich Weigand   default:
6152eb027d2SUlrich Weigand     return false;
6162eb027d2SUlrich Weigand   }
6172eb027d2SUlrich Weigand 
6182eb027d2SUlrich Weigand   // See whether we have a comparison that can be fused.
6194565ec0cSDuncan P. N. Exon Smith   unsigned FusedOpcode =
6204565ec0cSDuncan P. N. Exon Smith       TII->getFusedCompare(Compare.getOpcode(), Type, &Compare);
6212eb027d2SUlrich Weigand   if (!FusedOpcode)
622bdbb8af7SRichard Sandiford     return false;
623bdbb8af7SRichard Sandiford 
624bdbb8af7SRichard Sandiford   // Make sure that the operands are available at the branch.
625a0e73250SUlrich Weigand   // SrcReg2 is the register if the source operand is a register,
626a0e73250SUlrich Weigand   // 0 if the source operand is immediate, and the base register
627a0e73250SUlrich Weigand   // if the source operand is memory (index is not supported).
628e3a676e9SMatt Arsenault   Register SrcReg = Compare.getOperand(0).getReg();
629e3a676e9SMatt Arsenault   Register SrcReg2 =
630e3a676e9SMatt Arsenault     Compare.getOperand(1).isReg() ? Compare.getOperand(1).getReg() : Register();
631bdbb8af7SRichard Sandiford   MachineBasicBlock::iterator MBBI = Compare, MBBE = Branch;
632bdbb8af7SRichard Sandiford   for (++MBBI; MBBI != MBBE; ++MBBI)
633bdbb8af7SRichard Sandiford     if (MBBI->modifiesRegister(SrcReg, TRI) ||
634bdbb8af7SRichard Sandiford         (SrcReg2 && MBBI->modifiesRegister(SrcReg2, TRI)))
635bdbb8af7SRichard Sandiford       return false;
636bdbb8af7SRichard Sandiford 
637848a513dSUlrich Weigand   // Read the branch mask, target (if applicable), regmask (if applicable).
638bdbb8af7SRichard Sandiford   MachineOperand CCMask(MBBI->getOperand(1));
639bdbb8af7SRichard Sandiford   assert((CCMask.getImm() & ~SystemZ::CCMASK_ICMP) == 0 &&
640bdbb8af7SRichard Sandiford          "Invalid condition-code mask for integer comparison");
641ebef9216SUlrich Weigand   // This is only valid for CompareAndBranch and CompareAndSibcall.
6422eb027d2SUlrich Weigand   MachineOperand Target(MBBI->getOperand(
643ebef9216SUlrich Weigand     (Type == SystemZII::CompareAndBranch ||
644ebef9216SUlrich Weigand      Type == SystemZII::CompareAndSibcall) ? 2 : 0));
645848a513dSUlrich Weigand   const uint32_t *RegMask;
646848a513dSUlrich Weigand   if (Type == SystemZII::CompareAndSibcall)
647ebef9216SUlrich Weigand     RegMask = MBBI->getOperand(3).getRegMask();
648bdbb8af7SRichard Sandiford 
649bdbb8af7SRichard Sandiford   // Clear out all current operands.
650bdbb8af7SRichard Sandiford   int CCUse = MBBI->findRegisterUseOperandIdx(SystemZ::CC, false, TRI);
6512eb027d2SUlrich Weigand   assert(CCUse >= 0 && "BRC/BCR must use CC");
65237b37838SShengchen Kan   Branch->removeOperand(CCUse);
653ebef9216SUlrich Weigand   // Remove regmask (sibcall).
654ebef9216SUlrich Weigand   if (Type == SystemZII::CompareAndSibcall)
65537b37838SShengchen Kan     Branch->removeOperand(3);
656ebef9216SUlrich Weigand   // Remove target (branch or sibcall).
657848a513dSUlrich Weigand   if (Type == SystemZII::CompareAndBranch ||
658848a513dSUlrich Weigand       Type == SystemZII::CompareAndSibcall)
65937b37838SShengchen Kan     Branch->removeOperand(2);
66037b37838SShengchen Kan   Branch->removeOperand(1);
66137b37838SShengchen Kan   Branch->removeOperand(0);
662bdbb8af7SRichard Sandiford 
663bdbb8af7SRichard Sandiford   // Rebuild Branch as a fused compare and branch.
664a0e73250SUlrich Weigand   // SrcNOps is the number of MI operands of the compare instruction
665a0e73250SUlrich Weigand   // that we need to copy over.
666a0e73250SUlrich Weigand   unsigned SrcNOps = 2;
667a0e73250SUlrich Weigand   if (FusedOpcode == SystemZ::CLT || FusedOpcode == SystemZ::CLGT)
668a0e73250SUlrich Weigand     SrcNOps = 3;
669bdbb8af7SRichard Sandiford   Branch->setDesc(TII->get(FusedOpcode));
6702eb027d2SUlrich Weigand   MachineInstrBuilder MIB(*Branch->getParent()->getParent(), Branch);
671a0e73250SUlrich Weigand   for (unsigned I = 0; I < SrcNOps; I++)
672116bbab4SDiana Picus     MIB.add(Compare.getOperand(I));
673116bbab4SDiana Picus   MIB.add(CCMask);
6742eb027d2SUlrich Weigand 
6752eb027d2SUlrich Weigand   if (Type == SystemZII::CompareAndBranch) {
6762eb027d2SUlrich Weigand     // Only conditional branches define CC, as they may be converted back
6772eb027d2SUlrich Weigand     // to a non-fused branch because of a long displacement.  Conditional
6782eb027d2SUlrich Weigand     // returns don't have that problem.
679116bbab4SDiana Picus     MIB.add(Target).addReg(SystemZ::CC,
680116bbab4SDiana Picus                            RegState::ImplicitDefine | RegState::Dead);
6812eb027d2SUlrich Weigand   }
682bdbb8af7SRichard Sandiford 
683ebef9216SUlrich Weigand   if (Type == SystemZII::CompareAndSibcall) {
684ebef9216SUlrich Weigand     MIB.add(Target);
685848a513dSUlrich Weigand     MIB.addRegMask(RegMask);
686ebef9216SUlrich Weigand   }
687848a513dSUlrich Weigand 
688bdbb8af7SRichard Sandiford   // Clear any intervening kills of SrcReg and SrcReg2.
689bdbb8af7SRichard Sandiford   MBBI = Compare;
690bdbb8af7SRichard Sandiford   for (++MBBI; MBBI != MBBE; ++MBBI) {
691bdbb8af7SRichard Sandiford     MBBI->clearRegisterKills(SrcReg, TRI);
692bdbb8af7SRichard Sandiford     if (SrcReg2)
693bdbb8af7SRichard Sandiford       MBBI->clearRegisterKills(SrcReg2, TRI);
694bdbb8af7SRichard Sandiford   }
695bdbb8af7SRichard Sandiford   FusedComparisons += 1;
696bdbb8af7SRichard Sandiford   return true;
697bdbb8af7SRichard Sandiford }
698bdbb8af7SRichard Sandiford 
699bdbb8af7SRichard Sandiford // Process all comparison instructions in MBB.  Return true if something
700bdbb8af7SRichard Sandiford // changed.
processBlock(MachineBasicBlock & MBB)70128c111ecSRichard Sandiford bool SystemZElimCompare::processBlock(MachineBasicBlock &MBB) {
702bdbb8af7SRichard Sandiford   bool Changed = false;
703bdbb8af7SRichard Sandiford 
704bdbb8af7SRichard Sandiford   // Walk backwards through the block looking for comparisons, recording
705bdbb8af7SRichard Sandiford   // all CC users as we go.  The subroutines can delete Compare and
706bdbb8af7SRichard Sandiford   // instructions before it.
707bf6744dfSJonas Paulsson   LivePhysRegs LiveRegs(*TRI);
708bf6744dfSJonas Paulsson   LiveRegs.addLiveOuts(MBB);
709bf6744dfSJonas Paulsson   bool CompleteCCUsers = !LiveRegs.contains(SystemZ::CC);
710bdbb8af7SRichard Sandiford   SmallVector<MachineInstr *, 4> CCUsers;
71128c111ecSRichard Sandiford   MachineBasicBlock::iterator MBBI = MBB.end();
71228c111ecSRichard Sandiford   while (MBBI != MBB.begin()) {
7134565ec0cSDuncan P. N. Exon Smith     MachineInstr &MI = *--MBBI;
7144565ec0cSDuncan P. N. Exon Smith     if (CompleteCCUsers && (MI.isCompare() || isLoadAndTestAsCmp(MI)) &&
715bdbb8af7SRichard Sandiford         (optimizeCompareZero(MI, CCUsers) ||
716ab42cbceSZhan Jun Liau          fuseCompareOperations(MI, CCUsers))) {
717bdbb8af7SRichard Sandiford       ++MBBI;
7184565ec0cSDuncan P. N. Exon Smith       MI.eraseFromParent();
719bdbb8af7SRichard Sandiford       Changed = true;
720bdbb8af7SRichard Sandiford       CCUsers.clear();
721bdbb8af7SRichard Sandiford       continue;
722bdbb8af7SRichard Sandiford     }
723bdbb8af7SRichard Sandiford 
7244565ec0cSDuncan P. N. Exon Smith     if (MI.definesRegister(SystemZ::CC)) {
725bdbb8af7SRichard Sandiford       CCUsers.clear();
7269e1f3bd1SJonas Paulsson       CompleteCCUsers = true;
727c212125dSRichard Sandiford     }
7284565ec0cSDuncan P. N. Exon Smith     if (MI.readsRegister(SystemZ::CC) && CompleteCCUsers)
7294565ec0cSDuncan P. N. Exon Smith       CCUsers.push_back(&MI);
730bdbb8af7SRichard Sandiford   }
731bdbb8af7SRichard Sandiford   return Changed;
732bdbb8af7SRichard Sandiford }
733bdbb8af7SRichard Sandiford 
runOnMachineFunction(MachineFunction & F)734bdbb8af7SRichard Sandiford bool SystemZElimCompare::runOnMachineFunction(MachineFunction &F) {
735f1caa283SMatthias Braun   if (skipFunction(F.getFunction()))
736d9974cc9SAndrew Kaylor     return false;
737d9974cc9SAndrew Kaylor 
738*3432d40cSJonas Paulsson   TII = F.getSubtarget<SystemZSubtarget>().getInstrInfo();
739bdbb8af7SRichard Sandiford   TRI = &TII->getRegisterInfo();
740bdbb8af7SRichard Sandiford 
741bdbb8af7SRichard Sandiford   bool Changed = false;
74228c111ecSRichard Sandiford   for (auto &MBB : F)
74328c111ecSRichard Sandiford     Changed |= processBlock(MBB);
744bdbb8af7SRichard Sandiford 
745bdbb8af7SRichard Sandiford   return Changed;
746bdbb8af7SRichard Sandiford }
7473943d2b0SEugene Zelenko 
createSystemZElimComparePass(SystemZTargetMachine & TM)7483943d2b0SEugene Zelenko FunctionPass *llvm::createSystemZElimComparePass(SystemZTargetMachine &TM) {
749d5ae039eSKai Nacke   return new SystemZElimCompare();
7503943d2b0SEugene Zelenko }
751