Line data Source code
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/CodeGen/TargetInstrInfo.h"
24 : #include "llvm/CodeGen/TargetSubtargetInfo.h"
25 : #include "llvm/Support/Debug.h"
26 : #include "llvm/Support/raw_ostream.h"
27 : using namespace llvm;
28 :
29 : #define DEBUG_TYPE "aarch64-dead-defs"
30 :
31 : STATISTIC(NumDeadDefsReplaced, "Number of dead definitions replaced");
32 :
33 : #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 1119 : AArch64DeadRegisterDefinitions() : MachineFunctionPass(ID) {
46 1119 : initializeAArch64DeadRegisterDefinitionsPass(
47 1119 : *PassRegistry::getPassRegistry());
48 1119 : }
49 :
50 : bool runOnMachineFunction(MachineFunction &F) override;
51 :
52 1111 : StringRef getPassName() const override { return AARCH64_DEAD_REG_DEF_NAME; }
53 :
54 1104 : void getAnalysisUsage(AnalysisUsage &AU) const override {
55 1104 : AU.setPreservesCFG();
56 1104 : MachineFunctionPass::getAnalysisUsage(AU);
57 1104 : }
58 :
59 : bool shouldSkip(const MachineInstr &MI, const MachineFunction &MF) const;
60 : };
61 : char AArch64DeadRegisterDefinitions::ID = 0;
62 : } // end anonymous namespace
63 :
64 200151 : INITIALIZE_PASS(AArch64DeadRegisterDefinitions, "aarch64-dead-defs",
65 : AARCH64_DEAD_REG_DEF_NAME, false, false)
66 :
67 118326 : static bool usesFrameIndex(const MachineInstr &MI) {
68 323721 : for (const MachineOperand &MO : MI.uses())
69 206731 : if (MO.isFI())
70 : return true;
71 : return false;
72 : }
73 :
74 : bool
75 0 : AArch64DeadRegisterDefinitions::shouldSkip(const MachineInstr &MI,
76 : const MachineFunction &MF) const {
77 0 : if (!MF.getSubtarget<AArch64Subtarget>().hasLSE())
78 0 : return false;
79 :
80 : #define CASE_AARCH64_ATOMIC_(PREFIX) \
81 : case AArch64::PREFIX##X: \
82 : case AArch64::PREFIX##W: \
83 : case AArch64::PREFIX##H: \
84 : case AArch64::PREFIX##B
85 :
86 0 : for (const MachineMemOperand *MMO : MI.memoperands()) {
87 0 : if (MMO->isAtomic()) {
88 0 : unsigned Opcode = MI.getOpcode();
89 0 : switch (Opcode) {
90 0 : default:
91 0 : return false;
92 : break;
93 :
94 0 : CASE_AARCH64_ATOMIC_(LDADDA):
95 : CASE_AARCH64_ATOMIC_(LDADDAL):
96 :
97 : CASE_AARCH64_ATOMIC_(LDCLRA):
98 : CASE_AARCH64_ATOMIC_(LDCLRAL):
99 :
100 : CASE_AARCH64_ATOMIC_(LDEORA):
101 : CASE_AARCH64_ATOMIC_(LDEORAL):
102 :
103 : CASE_AARCH64_ATOMIC_(LDSETA):
104 : CASE_AARCH64_ATOMIC_(LDSETAL):
105 :
106 : CASE_AARCH64_ATOMIC_(LDSMAXA):
107 : CASE_AARCH64_ATOMIC_(LDSMAXAL):
108 :
109 : CASE_AARCH64_ATOMIC_(LDSMINA):
110 : CASE_AARCH64_ATOMIC_(LDSMINAL):
111 :
112 : CASE_AARCH64_ATOMIC_(LDUMAXA):
113 : CASE_AARCH64_ATOMIC_(LDUMAXAL):
114 :
115 : CASE_AARCH64_ATOMIC_(LDUMINA):
116 : CASE_AARCH64_ATOMIC_(LDUMINAL):
117 :
118 : CASE_AARCH64_ATOMIC_(SWPA):
119 : CASE_AARCH64_ATOMIC_(SWPAL):
120 0 : return true;
121 : break;
122 : }
123 : }
124 : }
125 :
126 : #undef CASE_AARCH64_ATOMIC_
127 :
128 : return false;
129 : }
130 :
131 16335 : void AArch64DeadRegisterDefinitions::processMachineBasicBlock(
132 : MachineBasicBlock &MBB) {
133 16335 : const MachineFunction &MF = *MBB.getParent();
134 134661 : for (MachineInstr &MI : MBB) {
135 118326 : if (usesFrameIndex(MI)) {
136 : // We need to skip this instruction because while it appears to have a
137 : // dead def it uses a frame index which might expand into a multi
138 : // instruction sequence during EPI.
139 : LLVM_DEBUG(dbgs() << " Ignoring, operand is frame index\n");
140 : continue;
141 : }
142 233955 : if (MI.definesRegister(AArch64::XZR) || MI.definesRegister(AArch64::WZR)) {
143 : // It is not allowed to write to the same register (not even the zero
144 : // register) twice in a single instruction.
145 : LLVM_DEBUG(
146 : dbgs()
147 : << " Ignoring, XZR or WZR already used by the instruction\n");
148 76 : continue;
149 : }
150 :
151 116914 : if (shouldSkip(MI, MF)) {
152 : LLVM_DEBUG(dbgs() << " Ignoring, Atomic instruction with acquire "
153 : "semantics using WZR/XZR\n");
154 : continue;
155 : }
156 :
157 115890 : const MCInstrDesc &Desc = MI.getDesc();
158 203904 : for (int I = 0, E = Desc.getNumDefs(); I != E; ++I) {
159 89096 : MachineOperand &MO = MI.getOperand(I);
160 89096 : if (!MO.isReg() || !MO.isDef())
161 : continue;
162 : // We should not have any relevant physreg defs that are replacable by
163 : // zero before register allocation. So we just check for dead vreg defs.
164 89057 : unsigned Reg = MO.getReg();
165 89057 : if (!TargetRegisterInfo::isVirtualRegister(Reg) ||
166 73492 : (!MO.isDead() && !MRI->use_nodbg_empty(Reg)))
167 87975 : continue;
168 : assert(!MO.isImplicit() && "Unexpected implicit def!");
169 : LLVM_DEBUG(dbgs() << " Dead def operand #" << I << " in:\n ";
170 : MI.print(dbgs()));
171 : // Be careful not to change the register if it's a tied operand.
172 1082 : if (MI.isRegTiedToUseOperand(I)) {
173 : LLVM_DEBUG(dbgs() << " Ignoring, def is tied operand.\n");
174 : continue;
175 : }
176 1082 : const TargetRegisterClass *RC = TII->getRegClass(Desc, I, TRI, MF);
177 : unsigned NewReg;
178 1082 : if (RC == nullptr) {
179 : LLVM_DEBUG(dbgs() << " Ignoring, register is not a GPR.\n");
180 : continue;
181 1082 : } else if (RC->contains(AArch64::WZR))
182 : NewReg = AArch64::WZR;
183 395 : else if (RC->contains(AArch64::XZR))
184 : NewReg = AArch64::XZR;
185 : else {
186 : LLVM_DEBUG(dbgs() << " Ignoring, register is not a GPR.\n");
187 : continue;
188 : }
189 : LLVM_DEBUG(dbgs() << " Replacing with zero register. New:\n ");
190 1082 : MO.setReg(NewReg);
191 : MO.setIsDead();
192 : LLVM_DEBUG(MI.print(dbgs()));
193 : ++NumDeadDefsReplaced;
194 1082 : Changed = true;
195 : // Only replace one dead register, see check for zero register above.
196 1082 : break;
197 : }
198 : }
199 16335 : }
200 :
201 : // Scan the function for instructions that have a dead definition of a
202 : // register. Replace that register with the zero register when possible.
203 14086 : bool AArch64DeadRegisterDefinitions::runOnMachineFunction(MachineFunction &MF) {
204 14086 : if (skipFunction(MF.getFunction()))
205 : return false;
206 :
207 14080 : TRI = MF.getSubtarget().getRegisterInfo();
208 14080 : TII = MF.getSubtarget().getInstrInfo();
209 14080 : MRI = &MF.getRegInfo();
210 : LLVM_DEBUG(dbgs() << "***** AArch64DeadRegisterDefinitions *****\n");
211 14080 : Changed = false;
212 30415 : for (auto &MBB : MF)
213 16335 : processMachineBasicBlock(MBB);
214 14080 : return Changed;
215 : }
216 :
217 1119 : FunctionPass *llvm::createAArch64DeadRegisterDefinitions() {
218 1119 : return new AArch64DeadRegisterDefinitions();
219 : }
|