/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/lib/Target/AArch64/AArch64DeadRegisterDefinitionsPass.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //==-- AArch64DeadRegisterDefinitions.cpp - Replace dead defs w/ zero reg --==// |
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 | | /// \file When allowed by the instruction, replace a dead definition of a GPR |
10 | | /// with the zero register. This makes the code a bit friendlier towards the |
11 | | /// hardware's register renamer. |
12 | | //===----------------------------------------------------------------------===// |
13 | | |
14 | | #include "AArch64.h" |
15 | | #include "AArch64RegisterInfo.h" |
16 | | #include "AArch64Subtarget.h" |
17 | | #include "llvm/ADT/Statistic.h" |
18 | | #include "llvm/CodeGen/ISDOpcodes.h" |
19 | | #include "llvm/CodeGen/MachineFunction.h" |
20 | | #include "llvm/CodeGen/MachineFunctionPass.h" |
21 | | #include "llvm/CodeGen/MachineInstr.h" |
22 | | #include "llvm/CodeGen/MachineRegisterInfo.h" |
23 | | #include "llvm/Support/Debug.h" |
24 | | #include "llvm/Support/raw_ostream.h" |
25 | | #include "llvm/Target/TargetInstrInfo.h" |
26 | | #include "llvm/Target/TargetSubtargetInfo.h" |
27 | | using namespace llvm; |
28 | | |
29 | | #define DEBUG_TYPE "aarch64-dead-defs" |
30 | | |
31 | | STATISTIC(NumDeadDefsReplaced, "Number of dead definitions replaced"); |
32 | | |
33 | 13.7k | #define AARCH64_DEAD_REG_DEF_NAME "AArch64 Dead register definitions" |
34 | | |
35 | | namespace { |
36 | | class AArch64DeadRegisterDefinitions : public MachineFunctionPass { |
37 | | private: |
38 | | const TargetRegisterInfo *TRI; |
39 | | const MachineRegisterInfo *MRI; |
40 | | const TargetInstrInfo *TII; |
41 | | bool Changed; |
42 | | void processMachineBasicBlock(MachineBasicBlock &MBB); |
43 | | public: |
44 | | static char ID; // Pass identification, replacement for typeid. |
45 | 13.8k | AArch64DeadRegisterDefinitions() : MachineFunctionPass(ID) { |
46 | 13.8k | initializeAArch64DeadRegisterDefinitionsPass( |
47 | 13.8k | *PassRegistry::getPassRegistry()); |
48 | 13.8k | } |
49 | | |
50 | | bool runOnMachineFunction(MachineFunction &F) override; |
51 | | |
52 | 13.7k | StringRef getPassName() const override { return 13.7k AARCH64_DEAD_REG_DEF_NAME13.7k ; } |
53 | | |
54 | 13.7k | void getAnalysisUsage(AnalysisUsage &AU) const override { |
55 | 13.7k | AU.setPreservesCFG(); |
56 | 13.7k | MachineFunctionPass::getAnalysisUsage(AU); |
57 | 13.7k | } |
58 | | |
59 | | bool shouldSkip(const MachineInstr &MI, const MachineFunction &MF) const; |
60 | | }; |
61 | | char AArch64DeadRegisterDefinitions::ID = 0; |
62 | | } // end anonymous namespace |
63 | | |
64 | | INITIALIZE_PASS(AArch64DeadRegisterDefinitions, "aarch64-dead-defs", |
65 | | AARCH64_DEAD_REG_DEF_NAME, false, false) |
66 | | |
67 | 34.0M | static bool usesFrameIndex(const MachineInstr &MI) { |
68 | 34.0M | for (const MachineOperand &MO : MI.uses()) |
69 | 82.9M | if (82.9M MO.isFI()82.9M ) |
70 | 534k | return true; |
71 | 33.4M | return false; |
72 | 33.4M | } |
73 | | |
74 | | bool |
75 | | AArch64DeadRegisterDefinitions::shouldSkip(const MachineInstr &MI, |
76 | 33.3M | const MachineFunction &MF) const { |
77 | 33.3M | if (!MF.getSubtarget<AArch64Subtarget>().hasLSE()) |
78 | 33.3M | return false; |
79 | 6.52k | |
80 | 6.52k | #define CASE_AARCH64_ATOMIC_(PREFIX) \ |
81 | 12.9k | case AArch64::PREFIX##X: \ |
82 | 12.9k | case AArch64::PREFIX##W: \ |
83 | 12.9k | case AArch64::PREFIX##H: \ |
84 | 12.9k | case AArch64::PREFIX##B |
85 | 6.52k | |
86 | 6.52k | for (const MachineMemOperand *MMO : MI.memoperands()) 6.52k { |
87 | 1.13k | if (MMO->isAtomic()1.13k ) { |
88 | 1.12k | unsigned Opcode = MI.getOpcode(); |
89 | 1.12k | switch (Opcode) { |
90 | 408 | default: |
91 | 408 | return false; |
92 | 0 | break; |
93 | 1.12k | |
94 | 720 | CASE_AARCH64_ATOMIC_720 (LDADDA): |
95 | 720 | CASE_AARCH64_ATOMIC_720 (LDADDAL): |
96 | 2.88k | |
97 | 720 | CASE_AARCH64_ATOMIC_720 (LDCLRA): |
98 | 720 | CASE_AARCH64_ATOMIC_720 (LDCLRAL): |
99 | 2.88k | |
100 | 720 | CASE_AARCH64_ATOMIC_720 (LDEORA): |
101 | 720 | CASE_AARCH64_ATOMIC_720 (LDEORAL): |
102 | 2.88k | |
103 | 720 | CASE_AARCH64_ATOMIC_720 (LDSETA): |
104 | 720 | CASE_AARCH64_ATOMIC_720 (LDSETAL): |
105 | 2.88k | |
106 | 720 | CASE_AARCH64_ATOMIC_720 (LDSMAXA): |
107 | 720 | CASE_AARCH64_ATOMIC_720 (LDSMAXAL): |
108 | 2.88k | |
109 | 720 | CASE_AARCH64_ATOMIC_720 (LDSMINA): |
110 | 720 | CASE_AARCH64_ATOMIC_720 (LDSMINAL): |
111 | 2.88k | |
112 | 720 | CASE_AARCH64_ATOMIC_720 (LDUMAXA): |
113 | 720 | CASE_AARCH64_ATOMIC_720 (LDUMAXAL): |
114 | 2.88k | |
115 | 720 | CASE_AARCH64_ATOMIC_720 (LDUMINA): |
116 | 720 | CASE_AARCH64_ATOMIC_720 (LDUMINAL): |
117 | 2.88k | |
118 | 720 | CASE_AARCH64_ATOMIC_720 (SWPA): |
119 | 720 | CASE_AARCH64_ATOMIC_720 (SWPAL): |
120 | 720 | return true; |
121 | 0 | break; |
122 | 5.39k | } |
123 | 5.39k | } |
124 | 1.13k | } |
125 | 5.39k | |
126 | 5.39k | #undef CASE_AARCH64_ATOMIC_ |
127 | 5.39k | |
128 | 5.39k | return false; |
129 | 5.39k | } |
130 | | |
131 | | void AArch64DeadRegisterDefinitions::processMachineBasicBlock( |
132 | 3.82M | MachineBasicBlock &MBB) { |
133 | 3.82M | const MachineFunction &MF = *MBB.getParent(); |
134 | 34.0M | for (MachineInstr &MI : MBB) { |
135 | 34.0M | if (usesFrameIndex(MI)34.0M ) { |
136 | 534k | // We need to skip this instruction because while it appears to have a |
137 | 534k | // dead def it uses a frame index which might expand into a multi |
138 | 534k | // instruction sequence during EPI. |
139 | 534k | DEBUG(dbgs() << " Ignoring, operand is frame index\n"); |
140 | 534k | continue; |
141 | 534k | } |
142 | 33.4M | if (33.4M MI.definesRegister(AArch64::XZR) || 33.4M MI.definesRegister(AArch64::WZR)33.4M ) { |
143 | 155k | // It is not allowed to write to the same register (not even the zero |
144 | 155k | // register) twice in a single instruction. |
145 | 155k | DEBUG(dbgs() << " Ignoring, XZR or WZR already used by the instruction\n"); |
146 | 155k | continue; |
147 | 155k | } |
148 | 33.3M | |
149 | 33.3M | if (33.3M shouldSkip(MI, MF)33.3M ) { |
150 | 720 | DEBUG(dbgs() << " Ignoring, Atomic instruction with acquire semantics using WZR/XZR\n"); |
151 | 720 | continue; |
152 | 720 | } |
153 | 33.3M | |
154 | 33.3M | const MCInstrDesc &Desc = MI.getDesc(); |
155 | 53.4M | for (int I = 0, E = Desc.getNumDefs(); I != E53.4M ; ++I20.1M ) { |
156 | 21.0M | MachineOperand &MO = MI.getOperand(I); |
157 | 21.0M | if (!MO.isReg() || 21.0M !MO.isDef()21.0M ) |
158 | 39 | continue; |
159 | 21.0M | // We should not have any relevant physreg defs that are replacable by |
160 | 21.0M | // zero before register allocation. So we just check for dead vreg defs. |
161 | 21.0M | unsigned Reg = MO.getReg(); |
162 | 21.0M | if (!TargetRegisterInfo::isVirtualRegister(Reg) || |
163 | 15.5M | (!MO.isDead() && 15.5M !MRI->use_nodbg_empty(Reg)15.5M )) |
164 | 20.1M | continue; |
165 | 21.0M | assert(!MO.isImplicit() && "Unexpected implicit def!"); |
166 | 876k | DEBUG(dbgs() << " Dead def operand #" << I << " in:\n "; |
167 | 876k | MI.print(dbgs())); |
168 | 876k | // Be careful not to change the register if it's a tied operand. |
169 | 876k | if (MI.isRegTiedToUseOperand(I)876k ) { |
170 | 0 | DEBUG(dbgs() << " Ignoring, def is tied operand.\n"); |
171 | 0 | continue; |
172 | 0 | } |
173 | 876k | const TargetRegisterClass *RC = TII->getRegClass(Desc, I, TRI, MF); |
174 | 876k | unsigned NewReg; |
175 | 876k | if (RC == nullptr876k ) { |
176 | 12 | DEBUG(dbgs() << " Ignoring, register is not a GPR.\n"); |
177 | 12 | continue; |
178 | 876k | } else if (876k RC->contains(AArch64::WZR)876k ) |
179 | 541k | NewReg = AArch64::WZR; |
180 | 335k | else if (335k RC->contains(AArch64::XZR)335k ) |
181 | 335k | NewReg = AArch64::XZR; |
182 | 1 | else { |
183 | 1 | DEBUG(dbgs() << " Ignoring, register is not a GPR.\n"); |
184 | 876k | continue; |
185 | 876k | } |
186 | 876k | DEBUG876k (dbgs() << " Replacing with zero register. New:\n "); |
187 | 876k | MO.setReg(NewReg); |
188 | 876k | MO.setIsDead(); |
189 | 876k | DEBUG(MI.print(dbgs())); |
190 | 21.0M | ++NumDeadDefsReplaced; |
191 | 21.0M | Changed = true; |
192 | 21.0M | // Only replace one dead register, see check for zero register above. |
193 | 21.0M | break; |
194 | 21.0M | } |
195 | 34.0M | } |
196 | 3.82M | } |
197 | | |
198 | | // Scan the function for instructions that have a dead definition of a |
199 | | // register. Replace that register with the zero register when possible. |
200 | 456k | bool AArch64DeadRegisterDefinitions::runOnMachineFunction(MachineFunction &MF) { |
201 | 456k | if (skipFunction(*MF.getFunction())) |
202 | 1 | return false; |
203 | 456k | |
204 | 456k | TRI = MF.getSubtarget().getRegisterInfo(); |
205 | 456k | TII = MF.getSubtarget().getInstrInfo(); |
206 | 456k | MRI = &MF.getRegInfo(); |
207 | 456k | DEBUG(dbgs() << "***** AArch64DeadRegisterDefinitions *****\n"); |
208 | 456k | Changed = false; |
209 | 456k | for (auto &MBB : MF) |
210 | 3.82M | processMachineBasicBlock(MBB); |
211 | 456k | return Changed; |
212 | 456k | } |
213 | | |
214 | 13.8k | FunctionPass *llvm::createAArch64DeadRegisterDefinitions() { |
215 | 13.8k | return new AArch64DeadRegisterDefinitions(); |
216 | 13.8k | } |