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