LLVM  9.0.0svn
AArch64DeadRegisterDefinitionsPass.cpp
Go to the documentation of this file.
1 //==-- AArch64DeadRegisterDefinitions.cpp - Replace dead defs w/ zero reg --==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 /// \file When allowed by the instruction, replace a dead definition of a GPR
9 /// with the zero register. This makes the code a bit friendlier towards the
10 /// hardware's register renamer.
11 //===----------------------------------------------------------------------===//
12 
13 #include "AArch64.h"
14 #include "AArch64RegisterInfo.h"
15 #include "AArch64Subtarget.h"
16 #include "llvm/ADT/Statistic.h"
24 #include "llvm/Support/Debug.h"
26 using namespace llvm;
27 
28 #define DEBUG_TYPE "aarch64-dead-defs"
29 
30 STATISTIC(NumDeadDefsReplaced, "Number of dead definitions replaced");
31 
32 #define AARCH64_DEAD_REG_DEF_NAME "AArch64 Dead register definitions"
33 
34 namespace {
35 class AArch64DeadRegisterDefinitions : public MachineFunctionPass {
36 private:
37  const TargetRegisterInfo *TRI;
38  const MachineRegisterInfo *MRI;
39  const TargetInstrInfo *TII;
40  bool Changed;
41  void processMachineBasicBlock(MachineBasicBlock &MBB);
42 public:
43  static char ID; // Pass identification, replacement for typeid.
44  AArch64DeadRegisterDefinitions() : MachineFunctionPass(ID) {
47  }
48 
49  bool runOnMachineFunction(MachineFunction &F) override;
50 
51  StringRef getPassName() const override { return AARCH64_DEAD_REG_DEF_NAME; }
52 
53  void getAnalysisUsage(AnalysisUsage &AU) const override {
54  AU.setPreservesCFG();
56  }
57 };
59 } // end anonymous namespace
60 
61 INITIALIZE_PASS(AArch64DeadRegisterDefinitions, "aarch64-dead-defs",
62  AARCH64_DEAD_REG_DEF_NAME, false, false)
63 
64 static bool usesFrameIndex(const MachineInstr &MI) {
65  for (const MachineOperand &MO : MI.uses())
66  if (MO.isFI())
67  return true;
68  return false;
69 }
70 
71 // Instructions that lose their 'read' operation for a subesquent fence acquire
72 // (DMB LD) once the zero register is used.
73 //
74 // WARNING: The aquire variants of the instructions are also affected, but they
75 // are split out into `atomicBarrierDroppedOnZero()` to support annotations on
76 // assembly.
77 static bool atomicReadDroppedOnZero(unsigned Opcode) {
78  switch (Opcode) {
79  case AArch64::LDADDB: case AArch64::LDADDH:
80  case AArch64::LDADDW: case AArch64::LDADDX:
81  case AArch64::LDADDLB: case AArch64::LDADDLH:
82  case AArch64::LDADDLW: case AArch64::LDADDLX:
83  case AArch64::LDCLRB: case AArch64::LDCLRH:
84  case AArch64::LDCLRW: case AArch64::LDCLRX:
85  case AArch64::LDCLRLB: case AArch64::LDCLRLH:
86  case AArch64::LDCLRLW: case AArch64::LDCLRLX:
87  case AArch64::LDEORB: case AArch64::LDEORH:
88  case AArch64::LDEORW: case AArch64::LDEORX:
89  case AArch64::LDEORLB: case AArch64::LDEORLH:
90  case AArch64::LDEORLW: case AArch64::LDEORLX:
91  case AArch64::LDSETB: case AArch64::LDSETH:
92  case AArch64::LDSETW: case AArch64::LDSETX:
93  case AArch64::LDSETLB: case AArch64::LDSETLH:
94  case AArch64::LDSETLW: case AArch64::LDSETLX:
95  case AArch64::LDSMAXB: case AArch64::LDSMAXH:
96  case AArch64::LDSMAXW: case AArch64::LDSMAXX:
97  case AArch64::LDSMAXLB: case AArch64::LDSMAXLH:
98  case AArch64::LDSMAXLW: case AArch64::LDSMAXLX:
99  case AArch64::LDSMINB: case AArch64::LDSMINH:
100  case AArch64::LDSMINW: case AArch64::LDSMINX:
101  case AArch64::LDSMINLB: case AArch64::LDSMINLH:
102  case AArch64::LDSMINLW: case AArch64::LDSMINLX:
103  case AArch64::LDUMAXB: case AArch64::LDUMAXH:
104  case AArch64::LDUMAXW: case AArch64::LDUMAXX:
105  case AArch64::LDUMAXLB: case AArch64::LDUMAXLH:
106  case AArch64::LDUMAXLW: case AArch64::LDUMAXLX:
107  case AArch64::LDUMINB: case AArch64::LDUMINH:
108  case AArch64::LDUMINW: case AArch64::LDUMINX:
109  case AArch64::LDUMINLB: case AArch64::LDUMINLH:
110  case AArch64::LDUMINLW: case AArch64::LDUMINLX:
111  return true;
112  }
113  return false;
114 }
115 
116 void AArch64DeadRegisterDefinitions::processMachineBasicBlock(
117  MachineBasicBlock &MBB) {
118  const MachineFunction &MF = *MBB.getParent();
119  for (MachineInstr &MI : MBB) {
120  if (usesFrameIndex(MI)) {
121  // We need to skip this instruction because while it appears to have a
122  // dead def it uses a frame index which might expand into a multi
123  // instruction sequence during EPI.
124  LLVM_DEBUG(dbgs() << " Ignoring, operand is frame index\n");
125  continue;
126  }
127  if (MI.definesRegister(AArch64::XZR) || MI.definesRegister(AArch64::WZR)) {
128  // It is not allowed to write to the same register (not even the zero
129  // register) twice in a single instruction.
130  LLVM_DEBUG(
131  dbgs()
132  << " Ignoring, XZR or WZR already used by the instruction\n");
133  continue;
134  }
135 
136  if (atomicBarrierDroppedOnZero(MI.getOpcode()) || atomicReadDroppedOnZero(MI.getOpcode())) {
137  LLVM_DEBUG(dbgs() << " Ignoring, semantics change with xzr/wzr.\n");
138  continue;
139  }
140 
141  const MCInstrDesc &Desc = MI.getDesc();
142  for (int I = 0, E = Desc.getNumDefs(); I != E; ++I) {
143  MachineOperand &MO = MI.getOperand(I);
144  if (!MO.isReg() || !MO.isDef())
145  continue;
146  // We should not have any relevant physreg defs that are replacable by
147  // zero before register allocation. So we just check for dead vreg defs.
148  unsigned Reg = MO.getReg();
150  (!MO.isDead() && !MRI->use_nodbg_empty(Reg)))
151  continue;
152  assert(!MO.isImplicit() && "Unexpected implicit def!");
153  LLVM_DEBUG(dbgs() << " Dead def operand #" << I << " in:\n ";
154  MI.print(dbgs()));
155  // Be careful not to change the register if it's a tied operand.
156  if (MI.isRegTiedToUseOperand(I)) {
157  LLVM_DEBUG(dbgs() << " Ignoring, def is tied operand.\n");
158  continue;
159  }
160  const TargetRegisterClass *RC = TII->getRegClass(Desc, I, TRI, MF);
161  unsigned NewReg;
162  if (RC == nullptr) {
163  LLVM_DEBUG(dbgs() << " Ignoring, register is not a GPR.\n");
164  continue;
165  } else if (RC->contains(AArch64::WZR))
166  NewReg = AArch64::WZR;
167  else if (RC->contains(AArch64::XZR))
168  NewReg = AArch64::XZR;
169  else {
170  LLVM_DEBUG(dbgs() << " Ignoring, register is not a GPR.\n");
171  continue;
172  }
173  LLVM_DEBUG(dbgs() << " Replacing with zero register. New:\n ");
174  MO.setReg(NewReg);
175  MO.setIsDead();
176  LLVM_DEBUG(MI.print(dbgs()));
177  ++NumDeadDefsReplaced;
178  Changed = true;
179  // Only replace one dead register, see check for zero register above.
180  break;
181  }
182  }
183 }
184 
185 // Scan the function for instructions that have a dead definition of a
186 // register. Replace that register with the zero register when possible.
187 bool AArch64DeadRegisterDefinitions::runOnMachineFunction(MachineFunction &MF) {
188  if (skipFunction(MF.getFunction()))
189  return false;
190 
192  TII = MF.getSubtarget().getInstrInfo();
193  MRI = &MF.getRegInfo();
194  LLVM_DEBUG(dbgs() << "***** AArch64DeadRegisterDefinitions *****\n");
195  Changed = false;
196  for (auto &MBB : MF)
197  processMachineBasicBlock(MBB);
198  return Changed;
199 }
200 
202  return new AArch64DeadRegisterDefinitions();
203 }
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
bool contains(unsigned Reg) const
Return true if the specified register is included in this register class.
This class represents lattice values for constants.
Definition: AllocatorList.h:23
virtual const TargetRegisterInfo * getRegisterInfo() const
getRegisterInfo - If register information is available, return it.
Describe properties that are true of each instruction in the target description file.
Definition: MCInstrDesc.h:164
unsigned getReg() const
getReg - Returns the register number.
static bool isVirtualRegister(unsigned Reg)
Return true if the specified register number is in the virtual register namespace.
unsigned Reg
STATISTIC(NumFunctions, "Total number of functions")
unsigned const TargetRegisterInfo * TRI
void setIsDead(bool Val=true)
F(f)
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
const HexagonInstrInfo * TII
static bool atomicBarrierDroppedOnZero(unsigned Opcode)
virtual const TargetInstrInfo * getInstrInfo() const
TargetInstrInfo - Interface to description of machine instruction set.
unsigned const MachineRegisterInfo * MRI
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Represent the analysis usage information of a pass.
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:284
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
static bool atomicReadDroppedOnZero(unsigned Opcode)
MachineOperand class - Representation of each machine instruction operand.
unsigned getNumDefs() const
Return the number of MachineOperands that are register definitions.
Definition: MCInstrDesc.h:226
void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition: Pass.cpp:301
const Function & getFunction() const
Return the LLVM function that this machine code represents.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:132
#define AARCH64_DEAD_REG_DEF_NAME
MachineRegisterInfo - Keep track of information for virtual and physical registers, including vreg register classes, use/def chains for registers, etc.
Representation of each machine instruction.
Definition: MachineInstr.h:63
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
INITIALIZE_PASS(AArch64DeadRegisterDefinitions, "aarch64-dead-defs", AARCH64_DEAD_REG_DEF_NAME, false, false) static bool usesFrameIndex(const MachineInstr &MI)
void setReg(unsigned Reg)
Change the register this operand corresponds to.
#define I(x, y, z)
Definition: MD5.cpp:58
virtual void print(raw_ostream &OS, const Module *M) const
print - Print out the internal state of the pass.
Definition: Pass.cpp:128
bool isReg() const
isReg - Tests if this is a MO_Register operand.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
aarch64 promote const
void initializeAArch64DeadRegisterDefinitionsPass(PassRegistry &)
IRTranslator LLVM IR MI
FunctionPass * createAArch64DeadRegisterDefinitions()
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
#define LLVM_DEBUG(X)
Definition: Debug.h:122
bool isImplicit() const