LLVM 24.0.0git
AArch64SRLTDefineSuperRegs.cpp
Go to the documentation of this file.
1//===- AArch64SRLTDefineSuperRegs.cpp -------------------------------------===//
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//
9// When SubRegister Liveness Tracking (SRLT) is enabled, this pass adds
10// extra implicit-def's to instructions that define the low N bits of
11// a GPR/FPR register to also define the top bits, because all AArch64
12// instructions that write the low bits of a GPR/FPR also implicitly zero
13// the top bits. For example, 'mov w0, w1' writes zeroes to the top 32-bits of
14// x0, so this pass adds a `implicit-def $x0` after register allocation.
15//
16// These semantics are originally represented in the MIR using `SUBREG_TO_REG`
17// which expresses that the top bits have been defined by the preceding
18// instructions, but during register coalescing this information is lost and in
19// contrast to when SRTL is disabled, when rewriting virtual -> physical
20// registers the implicit-defs are not added to the instruction.
21//
22// There have been several attempts to fix this in the coalescer [1], but each
23// iteration has exposed new bugs and the patch had to be reverted.
24// Additionally, the concept of adding 'implicit-def' of a virtual register is
25// particularly fragile and many places don't expect it (for example in
26// `X86::commuteInstructionImpl` the code only looks at specific operands and
27// does not consider implicit-defs. Similar in `SplitEditor::addDeadDef` where
28// it traverses operand 'defs' rather than 'all_defs').
29//
30// We want a temporary solution that doesn't impact other targets and is simpler
31// and less intrusive than the patch proposed for the register coalescer [1], so
32// that we can enable SRLT for AArch64.
33//
34// The approach here is to just add the 'implicit-def' manually after rewriting
35// virtual regs -> physical regs. This still means that during the register
36// allocation process the dependences are not accurately represented in the MIR
37// and LiveIntervals, but there are several reasons why we believe this isn't a
38// problem in practice:
39// (A) The register allocator only spills entire virtual registers.
40// This is additionally guarded by code in
41// AArch64InstrInfo::storeRegToStackSlot/loadRegFromStackSlot
42// where it checks if a register matches the expected register class.
43// (B) Rematerialization only happens when the instruction writes the full
44// register.
45// (C) The high bits of the AArch64 register cannot be written independently.
46// (D) Instructions that write only part of a register always take that same
47// register as a tied input operand, to indicate it's a merging operation.
48//
49// (A) means that for two virtual registers of regclass GPR32 and GPR64, if the
50// GPR32 register is coalesced into the GPR64 vreg then the full GPR64 would
51// be spilled/filled even if only the low 32-bits would be required for the
52// given liverange. (B) means that the top bits of a GPR64 would never be
53// overwritten by rematerialising a GPR32 sub-register for a given liverange.
54// (C-D) means that we can assume that the MIR as input to the register
55// allocator correctly expresses the instruction behaviour and dependences
56// between values, so unless the register allocator would violate (A) or (B),
57// the MIR is otherwise sound.
58//
59// Alternative approaches have also been considered, such as:
60// (1) Changing the AArch64 instruction definitions to write all bits and
61// extract the low N bits for the result.
62// (2) Disabling coalescing of SUBREG_TO_REG and using regalloc hints to tell
63// the register allocator to favour the same register for the input/output.
64// (3) Adding a new coalescer guard node with a tied-operand constraint, such
65// that when the SUBREG_TO_REG is removed, something still represents that
66// the top bits are defined. The node would get removed before rewriting
67// virtregs.
68// (4) Using an explicit INSERT_SUBREG into a zero value and try to optimize
69// away the INSERT_SUBREG (this is a more explicit variant of (2) and (3))
70// (5) Adding a new MachineOperand flag that represents the top bits would be
71// defined, but are not read nor undef.
72//
73// (1) would be the best approach but would be a significant effort as it
74// requires rewriting most/all instruction definitions and fixing MIR passes
75// that rely on the current definitions, whereas (2-4) result in sub-optimal
76// code that can't really be avoided because the explicit nodes would stop
77// rematerialization. (5) might be a way to mitigate the
78// fragility of implicit-def's of virtual registers if we want to pursue
79// landing [1], but then we'd rather choose approach (1) to avoid using
80// SUBREG_TO_REG entirely.
81//
82// [1] https://github.com/llvm/llvm-project/pull/168353
83//===----------------------------------------------------------------------===//
84
85#include "AArch64.h"
86#include "AArch64InstrInfo.h"
88#include "AArch64Subtarget.h"
90#include "llvm/ADT/BitVector.h"
91#include "llvm/ADT/SmallSet.h"
99#include "llvm/Support/Debug.h"
100
101using namespace llvm;
102
103#define DEBUG_TYPE "aarch64-srlt-define-superregs"
104#define PASS_NAME "AArch64 SRLT Define Super-Regs Pass"
105
106namespace {
107
108class AArch64SRLTDefineSuperRegsImpl {
109private:
110 const AArch64Subtarget *Subtarget = nullptr;
111 const AArch64RegisterInfo *TRI = nullptr;
112
113 Register getWidestSuperReg(Register R, const BitVector &RequiredBaseRegUnits,
114 const BitVector &QHiRegUnits);
115
116public:
117 bool run(MachineFunction &MF);
118};
119
120class AArch64SRLTDefineSuperRegsLegacy : public MachineFunctionPass {
121public:
122 inline static char ID = 0;
123
124 AArch64SRLTDefineSuperRegsLegacy() : MachineFunctionPass(ID) {}
125
126 bool runOnMachineFunction(MachineFunction &MF) override {
127 return AArch64SRLTDefineSuperRegsImpl().run(MF);
128 }
129
130 StringRef getPassName() const override { return PASS_NAME; }
131
132 void getAnalysisUsage(AnalysisUsage &AU) const override {
133 AU.setPreservesCFG();
138 }
139};
140
141} // end anonymous namespace
142
143INITIALIZE_PASS(AArch64SRLTDefineSuperRegsLegacy, DEBUG_TYPE, PASS_NAME, false,
144 false)
145
146// Returns the widest super-reg for a given reg, or NoRegister if no suitable
147// wider super-reg has been found. For example:
148// W0 -> X0
149// B1 -> Q1 (without SVE)
150// -> Z1 (with SVE)
151// W1_W2 -> X1_X2
152// D0_D1 -> Q0_Q1 (without SVE)
153// -> Z0_Z1 (with SVE)
154Register AArch64SRLTDefineSuperRegsImpl::getWidestSuperReg(
155 Register R, const BitVector &RequiredBaseRegUnits,
156 const BitVector &QHiRegUnits) {
157 assert(R.isPhysical() &&
158 "Expected to be run straight after virtregrewriter!");
159
160 BitVector Units(TRI->getNumRegUnits());
161 for (MCRegUnit U : TRI->regunits(R))
162 Units.set((unsigned)U);
163
164 auto IsSuitableSuperReg = [&](Register SR) {
165 for (MCRegUnit U : TRI->regunits(SR)) {
166 // Avoid choosing z1 as super-reg of d1 if SVE is not available.
167 // Q*_HI registers are only set for SVE registers, as those consist
168 // of the Q* register for the low 128 bits and the Q*_HI (artificial)
169 // register for the top (vscale-1) * 128 bits.
170 if (QHiRegUnits.test((unsigned)U) &&
171 !Subtarget->isSVEorStreamingSVEAvailable())
172 return false;
173 // We consider a super-reg as unsuitable if any of its reg units is not
174 // artificial and not shared, as that would imply that U is a unit for a
175 // different register, which means the candidate super-reg is likely
176 // a register tuple.
177 if (!TRI->isArtificialRegUnit(U) &&
178 (!Units.test((unsigned)U) || !RequiredBaseRegUnits.test((unsigned)U)))
179 return false;
180 }
181 return true;
182 };
183
184 Register LargestSuperReg = AArch64::NoRegister;
185 for (Register SR : TRI->superregs(R))
186 if (IsSuitableSuperReg(SR) && (LargestSuperReg == AArch64::NoRegister ||
187 TRI->isSuperRegister(LargestSuperReg, SR)))
188 LargestSuperReg = SR;
189
190 return LargestSuperReg;
191}
192
193bool AArch64SRLTDefineSuperRegsImpl::run(MachineFunction &MF) {
194 Subtarget = &MF.getSubtarget<AArch64Subtarget>();
195 TRI = Subtarget->getRegisterInfo();
196 const MachineRegisterInfo *MRI = &MF.getRegInfo();
197
198 if (!MRI->subRegLivenessEnabled())
199 return false;
200
201 assert(!MRI->isSSA() && "Expected to be run after breaking down SSA form!");
202
203 auto XRegs = seq_inclusive<unsigned>(AArch64::X0, AArch64::X28);
204 auto ZRegs = seq_inclusive<unsigned>(AArch64::Z0, AArch64::Z31);
205 constexpr unsigned FixedRegs[] = {AArch64::FP, AArch64::LR, AArch64::SP};
206
207 BitVector RequiredBaseRegUnits(TRI->getNumRegUnits());
208 for (Register R : concat<unsigned>(XRegs, ZRegs, FixedRegs))
209 for (MCRegUnit U : TRI->regunits(R))
210 RequiredBaseRegUnits.set((unsigned)U);
211
212 BitVector QHiRegUnits(TRI->getNumRegUnits());
213 for (Register R : seq_inclusive<unsigned>(AArch64::Q0_HI, AArch64::Q31_HI))
214 for (MCRegUnit U : TRI->regunits(R))
215 QHiRegUnits.set((unsigned)U);
216
217 bool Changed = false;
218 for (MachineBasicBlock &MBB : MF) {
219 for (MachineInstr &MI : MBB) {
220 // PATCHPOINT may have a 'def' that's not a register, avoid this.
221 if (MI.getOpcode() == TargetOpcode::PATCHPOINT)
222 continue;
223 // For each partial register write, also add an implicit-def for top bits
224 // of the register (e.g. for w0 add a def of x0).
225 SmallSet<Register, 8> SuperRegs;
226 for (const MachineOperand &DefOp : MI.defs())
227 if (Register R = getWidestSuperReg(DefOp.getReg(), RequiredBaseRegUnits,
228 QHiRegUnits);
229 R != AArch64::NoRegister)
230 SuperRegs.insert(R);
231
232 if (!SuperRegs.size())
233 continue;
234
235 LLVM_DEBUG(dbgs() << "Adding implicit-defs to: " << MI);
236 for (Register R : SuperRegs) {
237 LLVM_DEBUG(dbgs() << " " << printReg(R, TRI) << "\n");
238 bool IsRenamable = any_of(MI.defs(), [&](const MachineOperand &MO) {
239 return MO.isRenamable() && TRI->regsOverlap(MO.getReg(), R);
240 });
241 bool IsDead = any_of(MI.defs(), [&](const MachineOperand &MO) {
242 return MO.isDead() && TRI->regsOverlap(MO.getReg(), R);
243 });
244 MachineOperand DefOp = MachineOperand::CreateReg(
245 R, /*isDef=*/true, /*isImp=*/true, /*isKill=*/false,
246 /*isDead=*/IsDead, /*isUndef=*/false, /*isEarlyClobber=*/false,
247 /*SubReg=*/0, /*isDebug=*/false, /*isInternalRead=*/false,
248 /*isRenamable=*/IsRenamable);
249 MI.addOperand(DefOp);
250 }
251 Changed = true;
252 }
253 }
254
255 return Changed;
256}
257
259 return new AArch64SRLTDefineSuperRegsLegacy();
260}
261
265 const bool Changed = AArch64SRLTDefineSuperRegsImpl().run(MF);
266 if (!Changed)
267 return PreservedAnalyses::all();
270 return PA;
271}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
aarch64 promote const
MachineBasicBlock & MBB
This file implements the BitVector class.
#define DEBUG_TYPE
IRTranslator LLVM IR MI
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
bool IsDead
This file defines the SmallSet class.
#define LLVM_DEBUG(...)
Definition Debug.h:119
#define PASS_NAME
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
const AArch64RegisterInfo * getRegisterInfo() const override
Represent the analysis usage information of a pass.
AnalysisUsage & addPreservedID(const void *ID)
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:275
bool test(unsigned Idx) const
Returns true if bit Idx is set.
Definition BitVector.h:482
BitVector & set()
Set all bits in the bitvector.
Definition BitVector.h:366
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
static MachineOperand CreateReg(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isEarlyClobber=false, unsigned SubReg=0, bool isDebug=false, bool isInternalRead=false, bool isRenamable=false)
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
Wrapper class representing virtual and physical registers.
Definition Register.h:20
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
Definition SmallSet.h:184
size_type size() const
Definition SmallSet.h:171
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
Changed
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
constexpr auto seq_inclusive(T Begin, T End)
Iterate over an integral type from Begin to End inclusive.
Definition Sequence.h:361
LLVM_ABI char & MachineDominatorsID
MachineDominators - This pass is a machine dominators analysis pass.
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
detail::concat_range< ValueT, RangeTs... > concat(RangeTs &&...Ranges)
Returns a concatenated range across two or more ranges.
Definition STLExtras.h:1151
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
LLVM_ABI char & MachineLoopInfoID
MachineLoopInfo - This pass is a loop analysis pass.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1746
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
FunctionPass * createAArch64SRLTDefineSuperRegsLegacyPass()
LLVM_ABI Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.