SystemZElimCompare.cpp revision 9b05c709c65ba05645853ca49bc2a1ea8b554f37
1//===-- SystemZElimCompare.cpp - Eliminate comparison instructions --------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This pass:
11// (1) tries to remove compares if CC already contains the required information
12// (2) fuses compares and branches into COMPARE AND BRANCH instructions
13//
14//===----------------------------------------------------------------------===//
15
16#define DEBUG_TYPE "systemz-elim-compare"
17
18#include "SystemZTargetMachine.h"
19#include "llvm/ADT/Statistic.h"
20#include "llvm/CodeGen/MachineFunctionPass.h"
21#include "llvm/CodeGen/MachineInstrBuilder.h"
22#include "llvm/IR/Function.h"
23#include "llvm/Support/CommandLine.h"
24#include "llvm/Support/MathExtras.h"
25#include "llvm/Target/TargetInstrInfo.h"
26#include "llvm/Target/TargetMachine.h"
27#include "llvm/Target/TargetRegisterInfo.h"
28
29using namespace llvm;
30
31STATISTIC(EliminatedComparisons, "Number of eliminated comparisons");
32STATISTIC(FusedComparisons, "Number of fused compare-and-branch instructions");
33
34namespace {
35  class SystemZElimCompare : public MachineFunctionPass {
36  public:
37    static char ID;
38    SystemZElimCompare(const SystemZTargetMachine &tm)
39      : MachineFunctionPass(ID), TII(0), TRI(0) {}
40
41    virtual const char *getPassName() const {
42      return "SystemZ Comparison Elimination";
43    }
44
45    bool processBlock(MachineBasicBlock *MBB);
46    bool runOnMachineFunction(MachineFunction &F);
47
48  private:
49    bool convertToLoadAndTest(MachineInstr *MI);
50    bool adjustCCMasksForInstr(MachineInstr *MI, MachineInstr *Compare,
51                               SmallVectorImpl<MachineInstr *> &CCUsers);
52    bool optimizeCompareZero(MachineInstr *Compare,
53                             SmallVectorImpl<MachineInstr *> &CCUsers);
54    bool fuseCompareAndBranch(MachineInstr *Compare,
55                              SmallVectorImpl<MachineInstr *> &CCUsers);
56
57    const SystemZInstrInfo *TII;
58    const TargetRegisterInfo *TRI;
59  };
60
61  char SystemZElimCompare::ID = 0;
62} // end of anonymous namespace
63
64FunctionPass *llvm::createSystemZElimComparePass(SystemZTargetMachine &TM) {
65  return new SystemZElimCompare(TM);
66}
67
68// Return true if CC is live out of MBB.
69static bool isCCLiveOut(MachineBasicBlock *MBB) {
70  for (MachineBasicBlock::succ_iterator SI = MBB->succ_begin(),
71         SE = MBB->succ_end(); SI != SE; ++SI)
72    if ((*SI)->isLiveIn(SystemZ::CC))
73      return true;
74  return false;
75}
76
77// Return true if any CC result of MI would reflect the value of subreg
78// SubReg of Reg.
79static bool resultTests(MachineInstr *MI, unsigned Reg, unsigned SubReg) {
80  if (MI->getNumOperands() > 0 &&
81      MI->getOperand(0).isReg() &&
82      MI->getOperand(0).isDef() &&
83      MI->getOperand(0).getReg() == Reg &&
84      MI->getOperand(0).getSubReg() == SubReg)
85    return true;
86
87  switch (MI->getOpcode()) {
88  case SystemZ::LR:
89  case SystemZ::LGR:
90  case SystemZ::LGFR:
91  case SystemZ::LTR:
92  case SystemZ::LTGR:
93  case SystemZ::LTGFR:
94    if (MI->getOperand(1).getReg() == Reg &&
95        MI->getOperand(1).getSubReg() == SubReg)
96      return true;
97  }
98
99  return false;
100}
101
102// If MI is a load instruction, try to convert it into a LOAD AND TEST.
103// Return true on success.
104bool SystemZElimCompare::convertToLoadAndTest(MachineInstr *MI) {
105  unsigned Opcode = TII->getLoadAndTest(MI->getOpcode());
106  if (!Opcode)
107    return false;
108
109  MI->setDesc(TII->get(Opcode));
110  MachineInstrBuilder(*MI->getParent()->getParent(), MI)
111    .addReg(SystemZ::CC, RegState::ImplicitDefine);
112  return true;
113}
114
115// The CC users in CCUsers are testing the result of a comparison of some
116// value X against zero and we know that any CC value produced by MI
117// would also reflect the value of X.  Try to adjust CCUsers so that
118// they test the result of MI directly, returning true on success.
119// Leave everything unchanged on failure.
120bool SystemZElimCompare::
121adjustCCMasksForInstr(MachineInstr *MI, MachineInstr *Compare,
122                      SmallVectorImpl<MachineInstr *> &CCUsers) {
123  int Opcode = MI->getOpcode();
124  const MCInstrDesc &Desc = TII->get(Opcode);
125  unsigned MIFlags = Desc.TSFlags;
126
127  // See which compare-style condition codes are available.
128  unsigned ReusableCCMask = 0;
129  if (MIFlags & SystemZII::CCHasZero)
130    ReusableCCMask |= SystemZ::CCMASK_CMP_EQ;
131
132  // For unsigned comparisons with zero, only equality makes sense.
133  unsigned CompareFlags = Compare->getDesc().TSFlags;
134  if (!(CompareFlags & SystemZII::IsLogical) &&
135      (MIFlags & SystemZII::CCHasOrder))
136    ReusableCCMask |= SystemZ::CCMASK_CMP_LT | SystemZ::CCMASK_CMP_GT;
137
138  if (ReusableCCMask == 0)
139    return false;
140
141  unsigned CCValues = SystemZII::getCCValues(MIFlags);
142  assert((ReusableCCMask & ~CCValues) == 0 && "Invalid CCValues");
143
144  // Now check whether these flags are enough for all users.
145  SmallVector<MachineOperand *, 4> AlterMasks;
146  for (unsigned int I = 0, E = CCUsers.size(); I != E; ++I) {
147    MachineInstr *MI = CCUsers[I];
148
149    // Fail if this isn't a use of CC that we understand.
150    unsigned Flags = MI->getDesc().TSFlags;
151    unsigned FirstOpNum;
152    if (Flags & SystemZII::CCMaskFirst)
153      FirstOpNum = 0;
154    else if (Flags & SystemZII::CCMaskLast)
155      FirstOpNum = MI->getNumExplicitOperands() - 2;
156    else
157      return false;
158
159    // Check whether the instruction predicate treats all CC values
160    // outside of ReusableCCMask in the same way.  In that case it
161    // doesn't matter what those CC values mean.
162    unsigned CCValid = MI->getOperand(FirstOpNum).getImm();
163    unsigned CCMask = MI->getOperand(FirstOpNum + 1).getImm();
164    unsigned OutValid = ~ReusableCCMask & CCValid;
165    unsigned OutMask = ~ReusableCCMask & CCMask;
166    if (OutMask != 0 && OutMask != OutValid)
167      return false;
168
169    AlterMasks.push_back(&MI->getOperand(FirstOpNum));
170    AlterMasks.push_back(&MI->getOperand(FirstOpNum + 1));
171  }
172
173  // All users are OK.  Adjust the masks for MI.
174  for (unsigned I = 0, E = AlterMasks.size(); I != E; I += 2) {
175    AlterMasks[I]->setImm(CCValues);
176    unsigned CCMask = AlterMasks[I + 1]->getImm();
177    if (CCMask & ~ReusableCCMask)
178      AlterMasks[I + 1]->setImm((CCMask & ReusableCCMask) |
179                                (CCValues & ~ReusableCCMask));
180  }
181
182  // CC is now live after MI.
183  int CCDef = MI->findRegisterDefOperandIdx(SystemZ::CC, false, true, TRI);
184  assert(CCDef >= 0 && "Couldn't find CC set");
185  MI->getOperand(CCDef).setIsDead(false);
186
187  // Clear any intervening kills of CC.
188  MachineBasicBlock::iterator MBBI = MI, MBBE = Compare;
189  for (++MBBI; MBBI != MBBE; ++MBBI)
190    MBBI->clearRegisterKills(SystemZ::CC, TRI);
191
192  return true;
193}
194
195// Try to optimize cases where comparison instruction Compare is testing
196// a value against zero.  Return true on success and if Compare should be
197// deleted as dead.  CCUsers is the list of instructions that use the CC
198// value produced by Compare.
199bool SystemZElimCompare::
200optimizeCompareZero(MachineInstr *Compare,
201                    SmallVectorImpl<MachineInstr *> &CCUsers) {
202  // Check whether this is a comparison against zero.
203  if (Compare->getNumExplicitOperands() != 2 ||
204      !Compare->getOperand(1).isImm() ||
205      Compare->getOperand(1).getImm() != 0)
206    return false;
207
208  // Search back for CC results that are based on the first operand.
209  unsigned SrcReg = Compare->getOperand(0).getReg();
210  unsigned SrcSubReg = Compare->getOperand(0).getSubReg();
211  MachineBasicBlock *MBB = Compare->getParent();
212  MachineBasicBlock::iterator MBBI = Compare, MBBE = MBB->begin();
213  bool SeenUseOfCC = false;
214  while (MBBI != MBBE) {
215    --MBBI;
216    MachineInstr *MI = MBBI;
217    if (resultTests(MI, SrcReg, SrcSubReg) &&
218        ((!SeenUseOfCC && convertToLoadAndTest(MI)) ||
219         adjustCCMasksForInstr(MI, Compare, CCUsers))) {
220      EliminatedComparisons += 1;
221      return true;
222    }
223    if (MI->modifiesRegister(SrcReg, TRI) ||
224        MI->modifiesRegister(SystemZ::CC, TRI))
225      return false;
226    if (MI->readsRegister(SystemZ::CC, TRI))
227      SeenUseOfCC = true;
228  }
229  return false;
230}
231
232// Try to fuse comparison instruction Compare into a later branch.
233// Return true on success and if Compare is therefore redundant.
234bool SystemZElimCompare::
235fuseCompareAndBranch(MachineInstr *Compare,
236                     SmallVectorImpl<MachineInstr *> &CCUsers) {
237  // See whether we have a comparison that can be fused.
238  unsigned FusedOpcode = TII->getCompareAndBranch(Compare->getOpcode(),
239                                                  Compare);
240  if (!FusedOpcode)
241    return false;
242
243  // See whether we have a single branch with which to fuse.
244  if (CCUsers.size() != 1)
245    return false;
246  MachineInstr *Branch = CCUsers[0];
247  if (Branch->getOpcode() != SystemZ::BRC)
248    return false;
249
250  // Make sure that the operands are available at the branch.
251  unsigned SrcReg = Compare->getOperand(0).getReg();
252  unsigned SrcReg2 = (Compare->getOperand(1).isReg() ?
253                      Compare->getOperand(1).getReg() : 0);
254  MachineBasicBlock::iterator MBBI = Compare, MBBE = Branch;
255  for (++MBBI; MBBI != MBBE; ++MBBI)
256    if (MBBI->modifiesRegister(SrcReg, TRI) ||
257        (SrcReg2 && MBBI->modifiesRegister(SrcReg2, TRI)))
258      return false;
259
260  // Read the branch mask and target.
261  MachineOperand CCMask(MBBI->getOperand(1));
262  MachineOperand Target(MBBI->getOperand(2));
263  assert((CCMask.getImm() & ~SystemZ::CCMASK_ICMP) == 0 &&
264         "Invalid condition-code mask for integer comparison");
265
266  // Clear out all current operands.
267  int CCUse = MBBI->findRegisterUseOperandIdx(SystemZ::CC, false, TRI);
268  assert(CCUse >= 0 && "BRC must use CC");
269  Branch->RemoveOperand(CCUse);
270  Branch->RemoveOperand(2);
271  Branch->RemoveOperand(1);
272  Branch->RemoveOperand(0);
273
274  // Rebuild Branch as a fused compare and branch.
275  Branch->setDesc(TII->get(FusedOpcode));
276  MachineInstrBuilder(*Branch->getParent()->getParent(), Branch)
277    .addOperand(Compare->getOperand(0))
278    .addOperand(Compare->getOperand(1))
279    .addOperand(CCMask)
280    .addOperand(Target)
281    .addReg(SystemZ::CC, RegState::ImplicitDefine);
282
283  // Clear any intervening kills of SrcReg and SrcReg2.
284  MBBI = Compare;
285  for (++MBBI; MBBI != MBBE; ++MBBI) {
286    MBBI->clearRegisterKills(SrcReg, TRI);
287    if (SrcReg2)
288      MBBI->clearRegisterKills(SrcReg2, TRI);
289  }
290  FusedComparisons += 1;
291  return true;
292}
293
294// Process all comparison instructions in MBB.  Return true if something
295// changed.
296bool SystemZElimCompare::processBlock(MachineBasicBlock *MBB) {
297  bool Changed = false;
298
299  // Walk backwards through the block looking for comparisons, recording
300  // all CC users as we go.  The subroutines can delete Compare and
301  // instructions before it.
302  bool CompleteCCUsers = !isCCLiveOut(MBB);
303  SmallVector<MachineInstr *, 4> CCUsers;
304  MachineBasicBlock::iterator MBBI = MBB->end();
305  while (MBBI != MBB->begin()) {
306    MachineInstr *MI = --MBBI;
307    if (CompleteCCUsers &&
308        MI->isCompare() &&
309        (optimizeCompareZero(MI, CCUsers) ||
310         fuseCompareAndBranch(MI, CCUsers))) {
311      ++MBBI;
312      MI->removeFromParent();
313      Changed = true;
314      CCUsers.clear();
315      CompleteCCUsers = true;
316      continue;
317    }
318
319    if (MI->definesRegister(SystemZ::CC, TRI)) {
320      CCUsers.clear();
321      CompleteCCUsers = true;
322    } else if (MI->modifiesRegister(SystemZ::CC, TRI))
323      CompleteCCUsers = false;
324
325    if (CompleteCCUsers && MI->readsRegister(SystemZ::CC, TRI))
326      CCUsers.push_back(MI);
327  }
328  return Changed;
329}
330
331bool SystemZElimCompare::runOnMachineFunction(MachineFunction &F) {
332  TII = static_cast<const SystemZInstrInfo *>(F.getTarget().getInstrInfo());
333  TRI = &TII->getRegisterInfo();
334
335  bool Changed = false;
336  for (MachineFunction::iterator MFI = F.begin(), MFE = F.end();
337       MFI != MFE; ++MFI)
338    Changed |= processBlock(MFI);
339
340  return Changed;
341}
342