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