Jun Bum Lim | b389d9b | 2016-02-16 20:02:39 +0000 | [diff] [blame] | 1 | //=- AArch64RedundantCopyElimination.cpp - Remove useless copy for AArch64 -=// |
| 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 | // This pass removes unnecessary zero copies in BBs that are targets of |
| 9 | // cbz/cbnz instructions. For instance, the copy instruction in the code below |
| 10 | // can be removed because the CBZW jumps to BB#2 when W0 is zero. |
| 11 | // BB#1: |
| 12 | // CBZW %W0, <BB#2> |
| 13 | // BB#2: |
| 14 | // %W0 = COPY %WZR |
| 15 | // This pass should be run after register allocation. |
| 16 | // |
| 17 | // FIXME: This should be extended to handle any constant other than zero. E.g., |
| 18 | // cmp w0, #1 |
| 19 | // b.eq .BB1 |
| 20 | // BB1: |
| 21 | // mov w0, #1 |
| 22 | // |
| 23 | // FIXME: This could also be extended to check the whole dominance subtree below |
| 24 | // the comparison if the compile time regression is acceptable. |
| 25 | // |
| 26 | //===----------------------------------------------------------------------===// |
| 27 | |
| 28 | #include "AArch64.h" |
| 29 | #include "llvm/ADT/SetVector.h" |
| 30 | #include "llvm/ADT/Statistic.h" |
| 31 | #include "llvm/ADT/iterator_range.h" |
| 32 | #include "llvm/CodeGen/MachineFunctionPass.h" |
| 33 | #include "llvm/CodeGen/MachineRegisterInfo.h" |
| 34 | #include "llvm/Support/Debug.h" |
| 35 | |
| 36 | using namespace llvm; |
| 37 | |
| 38 | #define DEBUG_TYPE "aarch64-copyelim" |
| 39 | |
| 40 | STATISTIC(NumCopiesRemoved, "Number of copies removed."); |
| 41 | |
Jun Bum Lim | b389d9b | 2016-02-16 20:02:39 +0000 | [diff] [blame] | 42 | namespace { |
| 43 | class AArch64RedundantCopyElimination : public MachineFunctionPass { |
| 44 | const MachineRegisterInfo *MRI; |
| 45 | const TargetRegisterInfo *TRI; |
| 46 | |
| 47 | public: |
| 48 | static char ID; |
Diana Picus | 850043b | 2016-08-01 05:56:57 +0000 | [diff] [blame] | 49 | AArch64RedundantCopyElimination() : MachineFunctionPass(ID) { |
| 50 | initializeAArch64RedundantCopyEliminationPass( |
| 51 | *PassRegistry::getPassRegistry()); |
| 52 | } |
Jun Bum Lim | b389d9b | 2016-02-16 20:02:39 +0000 | [diff] [blame] | 53 | bool optimizeCopy(MachineBasicBlock *MBB); |
| 54 | bool runOnMachineFunction(MachineFunction &MF) override; |
Derek Schuff | 1dbf7a5 | 2016-04-04 17:09:25 +0000 | [diff] [blame] | 55 | MachineFunctionProperties getRequiredProperties() const override { |
| 56 | return MachineFunctionProperties().set( |
Matthias Braun | 1eb4736 | 2016-08-25 01:27:13 +0000 | [diff] [blame] | 57 | MachineFunctionProperties::Property::NoVRegs); |
Derek Schuff | 1dbf7a5 | 2016-04-04 17:09:25 +0000 | [diff] [blame] | 58 | } |
Jun Bum Lim | b389d9b | 2016-02-16 20:02:39 +0000 | [diff] [blame] | 59 | const char *getPassName() const override { |
| 60 | return "AArch64 Redundant Copy Elimination"; |
| 61 | } |
| 62 | }; |
| 63 | char AArch64RedundantCopyElimination::ID = 0; |
| 64 | } |
| 65 | |
| 66 | INITIALIZE_PASS(AArch64RedundantCopyElimination, "aarch64-copyelim", |
| 67 | "AArch64 redundant copy elimination pass", false, false) |
| 68 | |
Duncan P. N. Exon Smith | 1f6624a | 2016-02-27 19:12:54 +0000 | [diff] [blame] | 69 | static bool guaranteesZeroRegInBlock(MachineInstr &MI, MachineBasicBlock *MBB) { |
| 70 | unsigned Opc = MI.getOpcode(); |
Tim Northover | 3f22856 | 2016-02-17 21:16:53 +0000 | [diff] [blame] | 71 | // Check if the current basic block is the target block to which the |
| 72 | // CBZ/CBNZ instruction jumps when its Wt/Xt is zero. |
| 73 | if ((Opc == AArch64::CBZW || Opc == AArch64::CBZX) && |
Duncan P. N. Exon Smith | 1f6624a | 2016-02-27 19:12:54 +0000 | [diff] [blame] | 74 | MBB == MI.getOperand(1).getMBB()) |
Tim Northover | 3f22856 | 2016-02-17 21:16:53 +0000 | [diff] [blame] | 75 | return true; |
| 76 | else if ((Opc == AArch64::CBNZW || Opc == AArch64::CBNZX) && |
Duncan P. N. Exon Smith | 1f6624a | 2016-02-27 19:12:54 +0000 | [diff] [blame] | 77 | MBB != MI.getOperand(1).getMBB()) |
Tim Northover | 3f22856 | 2016-02-17 21:16:53 +0000 | [diff] [blame] | 78 | return true; |
| 79 | |
| 80 | return false; |
| 81 | } |
| 82 | |
Jun Bum Lim | b389d9b | 2016-02-16 20:02:39 +0000 | [diff] [blame] | 83 | bool AArch64RedundantCopyElimination::optimizeCopy(MachineBasicBlock *MBB) { |
| 84 | // Check if the current basic block has a single predecessor. |
| 85 | if (MBB->pred_size() != 1) |
| 86 | return false; |
| 87 | |
| 88 | MachineBasicBlock *PredMBB = *MBB->pred_begin(); |
| 89 | MachineBasicBlock::iterator CompBr = PredMBB->getLastNonDebugInstr(); |
| 90 | if (CompBr == PredMBB->end() || PredMBB->succ_size() != 2) |
| 91 | return false; |
| 92 | |
Tim Northover | 3f22856 | 2016-02-17 21:16:53 +0000 | [diff] [blame] | 93 | ++CompBr; |
| 94 | do { |
| 95 | --CompBr; |
Duncan P. N. Exon Smith | 1f6624a | 2016-02-27 19:12:54 +0000 | [diff] [blame] | 96 | if (guaranteesZeroRegInBlock(*CompBr, MBB)) |
Tim Northover | 3f22856 | 2016-02-17 21:16:53 +0000 | [diff] [blame] | 97 | break; |
| 98 | } while (CompBr != PredMBB->begin() && CompBr->isTerminator()); |
| 99 | |
| 100 | // We've not found a CBZ/CBNZ, time to bail out. |
Duncan P. N. Exon Smith | 1f6624a | 2016-02-27 19:12:54 +0000 | [diff] [blame] | 101 | if (!guaranteesZeroRegInBlock(*CompBr, MBB)) |
Jun Bum Lim | b389d9b | 2016-02-16 20:02:39 +0000 | [diff] [blame] | 102 | return false; |
Jun Bum Lim | b389d9b | 2016-02-16 20:02:39 +0000 | [diff] [blame] | 103 | |
| 104 | unsigned TargetReg = CompBr->getOperand(0).getReg(); |
| 105 | if (!TargetReg) |
| 106 | return false; |
| 107 | assert(TargetRegisterInfo::isPhysicalRegister(TargetReg) && |
| 108 | "Expect physical register"); |
| 109 | |
| 110 | // Remember all registers aliasing with TargetReg. |
| 111 | SmallSetVector<unsigned, 8> TargetRegs; |
| 112 | for (MCRegAliasIterator AI(TargetReg, TRI, true); AI.isValid(); ++AI) |
| 113 | TargetRegs.insert(*AI); |
| 114 | |
| 115 | bool Changed = false; |
Tim Northover | 3f22856 | 2016-02-17 21:16:53 +0000 | [diff] [blame] | 116 | MachineBasicBlock::iterator LastChange = MBB->begin(); |
| 117 | unsigned SmallestDef = TargetReg; |
Jun Bum Lim | b389d9b | 2016-02-16 20:02:39 +0000 | [diff] [blame] | 118 | // Remove redundant Copy instructions unless TargetReg is modified. |
| 119 | for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end(); I != E;) { |
| 120 | MachineInstr *MI = &*I; |
| 121 | ++I; |
| 122 | if (MI->isCopy() && MI->getOperand(0).isReg() && |
| 123 | MI->getOperand(1).isReg()) { |
| 124 | |
| 125 | unsigned DefReg = MI->getOperand(0).getReg(); |
| 126 | unsigned SrcReg = MI->getOperand(1).getReg(); |
| 127 | |
| 128 | if ((SrcReg == AArch64::XZR || SrcReg == AArch64::WZR) && |
| 129 | !MRI->isReserved(DefReg) && |
| 130 | (TargetReg == DefReg || TRI->isSuperRegister(DefReg, TargetReg))) { |
Jun Bum Lim | b389d9b | 2016-02-16 20:02:39 +0000 | [diff] [blame] | 131 | DEBUG(dbgs() << "Remove redundant Copy : "); |
| 132 | DEBUG((MI)->print(dbgs())); |
| 133 | |
| 134 | MI->eraseFromParent(); |
| 135 | Changed = true; |
Tim Northover | 3f22856 | 2016-02-17 21:16:53 +0000 | [diff] [blame] | 136 | LastChange = I; |
Jun Bum Lim | b389d9b | 2016-02-16 20:02:39 +0000 | [diff] [blame] | 137 | NumCopiesRemoved++; |
Tim Northover | 3f22856 | 2016-02-17 21:16:53 +0000 | [diff] [blame] | 138 | SmallestDef = |
| 139 | TRI->isSubRegister(SmallestDef, DefReg) ? DefReg : SmallestDef; |
Jun Bum Lim | b389d9b | 2016-02-16 20:02:39 +0000 | [diff] [blame] | 140 | continue; |
| 141 | } |
| 142 | } |
| 143 | |
Tim Northover | 3f22856 | 2016-02-17 21:16:53 +0000 | [diff] [blame] | 144 | if (MI->modifiesRegister(TargetReg, TRI)) |
| 145 | break; |
Jun Bum Lim | b389d9b | 2016-02-16 20:02:39 +0000 | [diff] [blame] | 146 | } |
Tim Northover | 3f22856 | 2016-02-17 21:16:53 +0000 | [diff] [blame] | 147 | |
| 148 | if (!Changed) |
| 149 | return false; |
| 150 | |
| 151 | // Otherwise, we have to fixup the use-def chain, starting with the |
| 152 | // CBZ/CBNZ. Conservatively mark as much as we can live. |
| 153 | CompBr->clearRegisterKills(SmallestDef, TRI); |
| 154 | |
David Majnemer | 91a02f5 | 2016-08-12 04:32:45 +0000 | [diff] [blame] | 155 | if (none_of(TargetRegs, [&](unsigned Reg) { return MBB->isLiveIn(Reg); })) |
Tim Northover | 3f22856 | 2016-02-17 21:16:53 +0000 | [diff] [blame] | 156 | MBB->addLiveIn(TargetReg); |
| 157 | |
Tim Northover | 7687bce | 2016-02-17 23:07:04 +0000 | [diff] [blame] | 158 | // Clear any kills of TargetReg between CompBr and the last removed COPY. |
Duncan P. N. Exon Smith | 84c2da4 | 2016-08-18 17:58:09 +0000 | [diff] [blame] | 159 | for (MachineInstr &MMI : make_range(MBB->begin(), LastChange)) |
Tim Northover | 7687bce | 2016-02-17 23:07:04 +0000 | [diff] [blame] | 160 | MMI.clearRegisterKills(SmallestDef, TRI); |
| 161 | |
Tim Northover | 3f22856 | 2016-02-17 21:16:53 +0000 | [diff] [blame] | 162 | return true; |
Jun Bum Lim | b389d9b | 2016-02-16 20:02:39 +0000 | [diff] [blame] | 163 | } |
| 164 | |
| 165 | bool AArch64RedundantCopyElimination::runOnMachineFunction( |
| 166 | MachineFunction &MF) { |
Andrew Kaylor | 1ac98bb | 2016-04-25 21:58:52 +0000 | [diff] [blame] | 167 | if (skipFunction(*MF.getFunction())) |
| 168 | return false; |
Jun Bum Lim | b389d9b | 2016-02-16 20:02:39 +0000 | [diff] [blame] | 169 | TRI = MF.getSubtarget().getRegisterInfo(); |
| 170 | MRI = &MF.getRegInfo(); |
| 171 | bool Changed = false; |
| 172 | for (MachineBasicBlock &MBB : MF) |
| 173 | Changed |= optimizeCopy(&MBB); |
| 174 | return Changed; |
| 175 | } |
| 176 | |
| 177 | FunctionPass *llvm::createAArch64RedundantCopyEliminationPass() { |
| 178 | return new AArch64RedundantCopyElimination(); |
| 179 | } |