LLVM 24.0.0git
HexagonAggressiveRDFCopy.cpp
Go to the documentation of this file.
1//===--- HexagonAggressiveRDFCopy.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// RDF-based aggressive copy propagation.
10//
11// This optimization extends the standard RDF copy propagation with support for
12// super-register and sub-register copy propagation. It determines candidates
13// for copy propagation by verifying that both the copy instruction and all
14// reached uses have the same reaching definitions for the source register(s).
15//
16// Key differences:
17// 1. Super-register handling: Can propagate copies involving super-registers
18// and their sub-registers (e.g., double-register pairs on Hexagon).
19// 2. Sub-register coverage: Verifies that all sub-registers of the source
20// register have consistent reaching definitions before propagating.
21// 3. Combine instruction support: Handles A2_combinew instructions that
22// combine two 32-bit registers into a 64-bit register pair.
23//
24// Algorithm:
25// 1. Scan all basic blocks in dominator tree order, maintaining a stack of
26// reaching definitions for each register.
27// 2. For each copy instruction:
28// a. Record the copy and its source/destination register mapping.
29// b. Find the reaching definition for the source register at the copy.
30// c. For each use reached by the copy's destination register:
31// - Check if all sub-registers of the source have the same reaching
32// definition at both the copy and the use.
33// - If yes, mark the use as replaceable.
34// 3. Replace all marked uses with the source register of the copy.
35//
36// Example:
37// BB1:
38// R1 = ... // Def1
39// D0 = A2_combinew R1, R0 // Copy: D0 = {R1, R0}
40// ... = D0 // Use of D0
41//
42// If R1 and R0 have the same reaching definitions at both the copy and the
43// use, the use of D0 can be replaced with the original source registers.
44// D0 is super-register corresponding to R1:0.
45//
46//===----------------------------------------------------------------------===//
47
60#include "llvm/Support/Debug.h"
63
64#include <cassert>
65#include <cstdint>
66#include <utility>
67
68using namespace llvm;
69using namespace rdf;
70
71#ifndef NDEBUG
73static unsigned RDFCpCount = 0;
74#endif
75
76// Record destination and source registers in EqualityMap
77// if this is a copy instruction
79 EqualityMap &EM) {
80 unsigned Opc = MI->getOpcode();
81 switch (Opc) {
82 case TargetOpcode::COPY: {
83 const MachineOperand &Dst = MI->getOperand(0);
84 const MachineOperand &Src = MI->getOperand(1);
85 RegisterRef DstR = DFG.makeRegRef(Dst.getReg(), Dst.getSubReg());
86 RegisterRef SrcR = DFG.makeRegRef(Src.getReg(), Src.getSubReg());
89 if (HRI.isFakeReg(DstR.Id) || HRI.isFakeReg(SrcR.Id))
90 return false;
91 if (TRI.getMinimalPhysRegClass(DstR.Id) !=
92 TRI.getMinimalPhysRegClass(SrcR.Id))
93 return false;
94 if (!DFG.isTracked(SrcR) || !DFG.isTracked(DstR))
95 return false;
96 EM.insert(std::make_pair(DstR, SrcR));
97 return true;
98 }
99 case TargetOpcode::REG_SEQUENCE:
100 llvm_unreachable("Unexpected REG_SEQUENCE");
101 }
102 return false;
103}
104
105// Track instructions determined to be copies along with their uses.
106// The register, sub-register copy pairs are given by EqualityMap
107// Find the reaching def from DefM stack for source (LHS) registers in each
108// copy. ReachedUseToCopyMap stores each reached use (UseNode) of a copy along
109// with the copy DefNode and source register
110void AggressiveCopyPropagation::recordCopy(NodeAddr<StmtNode *> SA,
111 EqualityMap &EM) {
112 if (trace())
113 CopyMap.insert(std::make_pair(SA.Id, EM));
114
115 // Find and store reaching def for each source register
116 // EqualityMap should also contain subregs
117 for (auto I : EM) {
118 if (PRI.equal_to(I.first, I.second))
119 continue;
120 NodeId RDefId = 0;
121 auto FS = DefM.find(I.second.Id);
122 if (FS != DefM.end() && !FS->second.empty()) {
123 auto Def = FS->second.top()->Addr->getRegRef(DFG);
124 // Avoid adding subreg as reaching def for superreg
126 TRI.isSuperRegister(Def.Id, I.second.Id))
127 continue;
128 RDefId = FS->second.top()->Id;
129 }
130 RDefMap[I.second][SA.Id] = RDefId;
131 }
132 for (NodeAddr<DefNode *> DA : SA.Addr->members_if(DFG.IsDef, DFG)) {
133 RegisterRef DR = DA.Addr->getRegRef(DFG);
134 auto FR = EM.find(DR);
135 if (FR == EM.end())
136 continue;
137 // Iterate over DR and its subregisters
138 // if present in EqualityMap, find its reached uses
139 for (MCPhysReg SubDReg : TRI.subregs_inclusive(DR.Id)) {
140 auto SubDR = DFG.makeRegRef(SubDReg, 0);
141 auto FR = EM.find(SubDR);
142 if (FR == EM.end())
143 continue;
144 RegisterRef SR = FR->second;
145 // Redundant copy
146 if (PRI.equal_to(SubDR, SR))
147 continue;
148 for (NodeId N = DA.Addr->getReachedUse(), NextN; N; N = NextN) {
149 auto UA = DFG.addr<UseNode *>(N);
150 NextN = UA.Addr->getSibling();
151 uint16_t F = UA.Addr->getFlags();
152 // Skip phi node uses
153 // Skip shadow uses. When shadow nodes are present, the register has
154 // multiple reaching defs.
155 if ((F & NodeAttrs::PhiRef) || (F & NodeAttrs::Fixed) ||
157 continue;
158 if (!PRI.equal_to(UA.Addr->getRegRef(DFG), SubDR))
159 continue;
160 MachineOperand &Op = UA.Addr->getOp();
161 // Skip operand if def and use of a register happens in same instruction
162 if (Op.isTied())
163 continue;
164 if (ReachedUseToCopyMap.find(UA.Id) != ReachedUseToCopyMap.end())
165 llvm_unreachable("Multiple copy instructions reach this use");
166 ReachedUseToCopyMap.insert(
167 std::make_pair(UA.Id, std::make_pair(DA, SR)));
168 }
169 }
170 }
171}
172
173// Now that we can obtain reaching def for uses from DefM,
174// check that reaching defs for source register and subregisters at the use
175// instruction, are the same as reaching defs for the copy. Uses that satisfy
176// this check can be replaced with the source registers of the copy.
177void AggressiveCopyPropagation::recordReplacableUses(NodeAddr<InstrNode *> IA) {
178 for (NodeAddr<UseNode *> UA : IA.Addr->members_if(DFG.IsUse, DFG)) {
179 // Check if any uses of the instruction are reached by a copy
180 auto CopyUseIt = ReachedUseToCopyMap.find(UA.Id);
181 if (CopyUseIt == ReachedUseToCopyMap.end())
182 continue;
183 [[maybe_unused]] auto UseReg = UA.Addr->getRegRef(DFG);
184 auto DA = CopyUseIt->second.first;
185 auto SR = CopyUseIt->second.second;
186 [[maybe_unused]] auto DefReg = DA.Addr->getRegRef(DFG);
187 assert(PRI.equal_to(DefReg, UseReg));
188 NodeAddr<InstrNode *> DefI = DA.Addr->getOwner(DFG);
189 // Aggr of subregs that have same reaching def (at IA) as DefI
190 RegisterAggr RRs(PRI);
191 // Registers that need to be added as use nodes in updated IA
192 SmallVector<RegisterRef, 4> UseRefs;
193 for (MCPhysReg S : TRI.subregs_inclusive(SR.Id)) {
194 auto SRef = DFG.makeRegRef(S, 0);
195 NodeId RDefId = 0;
196 // If there is no reaching def for SRef at DefI,
197 // do not check if SRef can be propagated
198 auto RDefIt = RDefMap.find(SRef);
199 if (RDefIt == RDefMap.end())
200 continue;
201 auto DefIIt = RDefIt->second.find(DefI.Id);
202 if (DefIIt == RDefIt->second.end())
203 continue;
204 // If we already have reaching def for SRef at IA,
205 // use it instead of searching DefM.
206 auto IAIt = RDefIt->second.find(IA.Id);
207 if (IAIt != RDefIt->second.end()) {
208 RDefId = IAIt->second;
209 } else {
210 auto F = DefM.find(S);
211 if (F != DefM.end() && !F->second.empty()) {
212 auto Def = F->second.top()->Addr->getRegRef(DFG);
213 // Avoid adding subreg as reaching def for superreg
215 TRI.isSuperRegister(Def.Id, S))
216 continue;
217 RDefId = F->second.top()->Id;
218 }
219 }
220 // If reaching def for SRef at DefI is not same as IA,
221 // SRef can not propagated to IA.
222 if (DefIIt->second != RDefId)
223 continue;
224 RRs.insert(SRef);
225 UseRefs.push_back(SRef);
226 RDefIt->second[IA.Id] = RDefId;
227 // If registers or sub-registers that can be propagated cover SR,
228 // the use node is a candidate for copy propagation
229 if (RRs.hasCoverOf(SR))
230 break;
231 }
232 // Use node can be replaced with new use nodes created from UseRefs
233 if (RRs.hasCoverOf(SR))
234 ReplacableUses.push_back(std::make_pair(UA, UseRefs));
235 }
236}
237
238// Recursively process all children in the dominator tree.
239// Find copy instructions and reached uses that are candidates for propagation
240void AggressiveCopyPropagation::scanBlock(MachineBasicBlock *B) {
241 NodeAddr<BlockNode *> BA = DFG.findBlock(B);
242 DFG.markBlock(BA.Id, DefM);
243
244 for (NodeAddr<InstrNode *> IA : BA.Addr->members(DFG)) {
245 if (DFG.IsCode<NodeAttrs::Stmt>(IA)) {
246 NodeAddr<StmtNode *> SA = IA;
247 EqualityMap EM(RegisterRefLess(DFG.getPRI()));
248 if (interpretAsCopy(SA.Addr->getCode(), EM))
249 recordCopy(SA, EM);
250 recordReplacableUses(IA);
251 }
252 DFG.pushAllDefs(IA, DefM);
253 }
254
255 MachineDomTreeNode *N = MDT.getNode(B);
256 for (auto *I : *N)
257 scanBlock(I->getBlock());
258
259 DFG.releaseBlock(BA.Id, DefM);
260 return;
261}
262
264 scanBlock(MDT.getRootNode()->getBlock());
265
266 if (trace()) {
267 dbgs() << "Copies:\n";
268 for (auto &C : CopyMap) {
269 dbgs() << "Instr: " << *DFG.addr<StmtNode *>(C.first).Addr->getCode();
270 dbgs() << " eq: {";
271 for (auto J : C.second)
272 dbgs() << ' ' << Print<RegisterRef>(J.first, DFG) << '='
273 << Print<RegisterRef>(J.second, DFG);
274 dbgs() << " }\n";
275 }
276 dbgs() << "\nCopy def-use:\n";
277 for (auto &U : ReachedUseToCopyMap) {
278 auto DA = U.second.first;
279 auto DefI = DA.Addr->getOwner(DFG);
280 auto UseI = DFG.addr<UseNode *>(U.first).Addr->getOwner(DFG);
281 dbgs() << "Copy def: " << *DFG.addr<StmtNode *>(DefI.Id).Addr->getCode();
282 dbgs() << "Copy use: " << *DFG.addr<StmtNode *>(UseI.Id).Addr->getCode();
283 }
284 dbgs() << "\nRDef map:\n";
285 for (auto R : RDefMap) {
286 dbgs() << Print<RegisterRef>(R.first, DFG) << " -> {";
287 for (auto &M : R.second)
288 dbgs() << ' ' << Print<NodeId>(M.first, DFG) << ':'
289 << Print<NodeId>(M.second, DFG);
290 dbgs() << " }\n";
291 }
292 }
293
294 bool Changed = false;
295#ifndef NDEBUG
296 bool HasLimit = RDFCpLimit.getNumOccurrences() > 0;
297#endif
298
299 auto MinPhysReg = [this](RegisterRef RR) -> unsigned {
300 const TargetRegisterClass &RC = *TRI.getMinimalPhysRegClass(RR.Id);
301 if ((RC.LaneMask & RR.Mask) == RC.LaneMask)
302 return RR.Id;
303 for (MCSubRegIndexIterator S(RR.Id, &TRI); S.isValid(); ++S)
304 if (RR.Mask == TRI.getSubRegIndexLaneMask(S.getSubRegIndex()))
305 return S.getSubReg();
306 llvm_unreachable("Should have found a register");
307 return 0;
308 };
309
310 // Iterate over all candidate uses found and replace with source register of
311 // copy
312 for (auto P : ReplacableUses) {
313#ifndef NDEBUG
314 if (HasLimit && RDFCpCount >= RDFCpLimit)
315 break;
316#endif
317 NodeAddr<UseNode *> UA = P.first;
318 SmallVector<RegisterRef, 4> UseRefs = P.second;
319
320 // UseRefs should never be empty if RRs.hasCoverOf(SR) was true
321 assert(!UseRefs.empty() &&
322 "UseRefs should not be empty for replaceable use");
323
324 auto IA = UA.Addr->getOwner(DFG);
325 auto DR = UA.Addr->getRegRef(DFG);
326 auto SR = ReachedUseToCopyMap[UA.Id].second;
327 if (HRI.isFakeReg(SR.Id))
328 continue;
329
330 if (trace()) {
331 dbgs() << "Can replace " << Print<RegisterRef>(DR, DFG) << " with "
332 << Print<RegisterRef>(SR, DFG) << " in "
333 << *NodeAddr<StmtNode *>(IA).Addr->getCode();
334 }
335
336 // Update existing use node to use the source register
337 MachineOperand &Op = UA.Addr->getOp();
338 unsigned NewReg = MinPhysReg(SR);
339 Op.setReg(NewReg);
340 Op.setSubReg(0);
341 DFG.unlinkUse(UA, false);
342 bool firstUseNode = true;
343
344 for (auto UR : UseRefs) {
345 // If we have more than one use (such as multiple subregs),
346 // add a new shadow use node
347 if (!firstUseNode) {
348 UA.Addr->setFlags(UA.Addr->getFlags() | NodeAttrs::Shadow);
349 UA = DFG.getNextShadow(IA, UA, true);
350 }
351 if (RDefMap[UR][IA.Id] != 0) {
352 UA.Addr->linkToDef(UA.Id, DFG.addr<DefNode *>(RDefMap[UR][IA.Id]));
353 } else {
354 // No reaching def present
355 UA.Addr->setReachingDef(0);
356 UA.Addr->setSibling(0);
357 }
358 firstUseNode = false;
359 }
360
361 Changed = true;
362#ifndef NDEBUG
363 if (HasLimit && RDFCpCount >= RDFCpLimit)
364 break;
365 RDFCpCount++;
366#endif
367
368 } // for (UA in replacable uses)
369
370 return Changed;
371}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
cl::opt< unsigned > RDFCpLimit
static unsigned RDFCpCount
static Register UseReg(const MachineOperand &MO)
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Register const TargetRegisterInfo * TRI
#define P(N)
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:223
iterator end()
Definition DenseMap.h:141
const LaneBitmask LaneMask
Iterator that enumerates the sub-registers of a Reg and the associated sub-register indices.
bool isValid() const
Returns true if this iterator is not yet at the end.
Representation of each machine instruction.
MachineOperand class - Representation of each machine instruction operand.
static constexpr bool isPhysicalRegister(unsigned Reg)
Return true if the specified register number is in the physical register namespace.
Definition Register.h:60
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Changed
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
NodeAddr< DefNode * > Def
Definition RDFGraph.h:384
Print(const T &, const DataFlowGraph &) -> Print< T >
uint32_t NodeId
Definition RDFGraph.h:262
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
DomTreeNodeBase< MachineBasicBlock > MachineDomTreeNode
uint16_t MCPhysReg
An unsigned integer type large enough to represent all physical registers, but not necessarily virtua...
Definition MCRegister.h:21
DWARFExpression::Operation Op
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58
#define N
virtual bool interpretAsCopy(const MachineInstr *MI, EqualityMap &EM)
std::map< NodeId, EqualityMap > CopyMap
Definition RDFCopyBase.h:48
std::map< RegisterRef, std::map< NodeId, NodeId >, RegisterRefLess > RDefMap
Definition RDFCopyBase.h:46
DataFlowGraph::DefStackMap DefM
Definition RDFCopyBase.h:42
std::map< RegisterRef, RegisterRef, RegisterRefLess > EqualityMap
Definition RDFCopyBase.h:37
const MachineDominatorTree & MDT
Definition RDFCopyBase.h:40
LLVM_ABI RegisterRef makeRegRef(unsigned Reg, unsigned Sub) const
Definition RDFGraph.cpp:989
static bool IsDef(const Node BA)
Definition RDFGraph.h:827
NodeAddr< T > addr(NodeId N) const
Definition RDFGraph.h:692
LLVM_ABI bool equal_to(RegisterRef A, RegisterRef B) const
NodeId getSibling() const
Definition RDFGraph.h:569
LLVM_ABI RegisterRef getRegRef(const DataFlowGraph &G) const
Definition RDFGraph.cpp:401
LLVM_ABI Node getOwner(const DataFlowGraph &G)
Definition RDFGraph.cpp:427
MachineInstr * getCode() const
Definition RDFGraph.h:638