LLVM 23.0.0git
HexagonRDFOpt.cpp
Go to the documentation of this file.
1//===- HexagonRDFOpt.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#include "Hexagon.h"
11#include "HexagonInstrInfo.h"
12#include "HexagonSubtarget.h"
14#include "RDFCopy.h"
15#include "RDFDeadCode.h"
16#include "llvm/ADT/DenseMap.h"
17#include "llvm/ADT/STLExtras.h"
18#include "llvm/ADT/SetVector.h"
30#include "llvm/Pass.h"
33#include "llvm/Support/Debug.h"
36#include <cassert>
37#include <limits>
38
39using namespace llvm;
40using namespace rdf;
41
42static unsigned RDFCount = 0;
44
46 RDFLimit("hexagon-rdf-limit",
47 cl::init(std::numeric_limits<unsigned>::max()));
49 "hexagon-aggressive-rdf-copy",
50 cl::desc("Enable aggressive RDF copy propagation with super-register "
51 "support"),
52 cl::init(false), cl::Hidden);
53static cl::opt<bool> RDFDump("hexagon-rdf-dump", cl::Hidden);
54static cl::opt<bool> RDFTrackReserved("hexagon-rdf-track-reserved", cl::Hidden);
55
56namespace {
57
58 class HexagonRDFOpt : public MachineFunctionPass {
59 public:
60 HexagonRDFOpt() : MachineFunctionPass(ID) {}
61
62 void getAnalysisUsage(AnalysisUsage &AU) const override {
63 AU.addRequired<MachineDominatorTreeWrapperPass>();
64 AU.addRequired<MachineDominanceFrontierWrapperPass>();
65 AU.setPreservesAll();
67 }
68
69 StringRef getPassName() const override {
70 return "Hexagon RDF optimizations";
71 }
72
73 bool runOnMachineFunction(MachineFunction &MF) override;
74
75 MachineFunctionProperties getRequiredProperties() const override {
76 return MachineFunctionProperties().setNoVRegs();
77 }
78
79 static char ID;
80
81 private:
82 MachineDominatorTree *MDT;
83 MachineRegisterInfo *MRI;
84 };
85
86struct HexagonCP : public CopyPropagation {
87 HexagonCP(DataFlowGraph &G) : CopyPropagation(G) {}
88
89 bool interpretAsCopy(const MachineInstr *MI, EqualityMap &EM) override;
90};
91
92struct HexagonAggressiveCP : public AggressiveCopyPropagation {
93 HexagonAggressiveCP(DataFlowGraph &G) : AggressiveCopyPropagation(G) {}
94
95 bool interpretAsCopy(const MachineInstr *MI, EqualityMap &EM) override;
96};
97
98struct HexagonDCE : public DeadCodeElimination {
99 HexagonDCE(DataFlowGraph &G, MachineRegisterInfo &MRI)
100 : DeadCodeElimination(G, MRI) {}
101
102 bool rewrite(NodeAddr<InstrNode*> IA, SetVector<NodeId> &Remove);
103 void removeOperand(NodeAddr<InstrNode*> IA, unsigned OpNum);
104
105 bool run();
106};
107
108} // end anonymous namespace
109
110char HexagonRDFOpt::ID = 0;
111
112INITIALIZE_PASS_BEGIN(HexagonRDFOpt, "hexagon-rdf-opt",
113 "Hexagon RDF optimizations", false, false)
116INITIALIZE_PASS_END(HexagonRDFOpt, "hexagon-rdf-opt",
117 "Hexagon RDF optimizations", false, false)
118
119bool HexagonCP::interpretAsCopy(const MachineInstr *MI, EqualityMap &EM) {
120 auto mapRegs = [&EM] (RegisterRef DstR, RegisterRef SrcR) -> void {
121 EM.insert(std::make_pair(DstR, SrcR));
122 };
123
124 DataFlowGraph &DFG = getDFG();
125 unsigned Opc = MI->getOpcode();
126 switch (Opc) {
127 case Hexagon::A2_combinew: {
128 const MachineOperand &DstOp = MI->getOperand(0);
129 const MachineOperand &HiOp = MI->getOperand(1);
130 const MachineOperand &LoOp = MI->getOperand(2);
131 assert(DstOp.getSubReg() == 0 && "Unexpected subregister");
132 mapRegs(DFG.makeRegRef(DstOp.getReg(), Hexagon::isub_hi),
133 DFG.makeRegRef(HiOp.getReg(), HiOp.getSubReg()));
134 mapRegs(DFG.makeRegRef(DstOp.getReg(), Hexagon::isub_lo),
135 DFG.makeRegRef(LoOp.getReg(), LoOp.getSubReg()));
136 return true;
137 }
138 case Hexagon::A2_addi: {
139 const MachineOperand &A = MI->getOperand(2);
140 if (!A.isImm() || A.getImm() != 0)
141 return false;
142 [[fallthrough]];
143 }
144 case Hexagon::A2_tfr: {
145 const MachineOperand &DstOp = MI->getOperand(0);
146 const MachineOperand &SrcOp = MI->getOperand(1);
147 mapRegs(DFG.makeRegRef(DstOp.getReg(), DstOp.getSubReg()),
148 DFG.makeRegRef(SrcOp.getReg(), SrcOp.getSubReg()));
149 return true;
150 }
151 }
152
153 return CopyPropagation::interpretAsCopy(MI, EM);
154}
155
156bool HexagonAggressiveCP::interpretAsCopy(const MachineInstr *MI,
157 EqualityMap &EM) {
158 auto mapRegs = [&EM](RegisterRef DstR, RegisterRef SrcR) -> void {
159 EM.insert(std::make_pair(DstR, SrcR));
160 };
161
162 DataFlowGraph &DFG = getDFG();
163 const TargetRegisterInfo &TRI = DFG.getTRI();
164 unsigned Opc = MI->getOpcode();
165 switch (Opc) {
166 case Hexagon::A2_combinew: {
167 // Combine instruction is equivalent to double reg copy.
168 // Add double reg copy to map.
169 const MachineOperand &DstOp = MI->getOperand(0);
170 const MachineOperand &HiOp = MI->getOperand(1);
171 const MachineOperand &LoOp = MI->getOperand(2);
172 assert(DstOp.getSubReg() == 0 && "Unexpected subregister");
173 unsigned DoubleRegDest = TRI.getMatchingSuperReg(
174 LoOp.getReg(), Hexagon::isub_lo, &Hexagon::DoubleRegsRegClass);
175 if (DoubleRegDest != 0 &&
176 TRI.isSuperRegister(HiOp.getReg(), DoubleRegDest))
177 mapRegs(DFG.makeRegRef(DstOp), DFG.makeRegRef(DoubleRegDest, 0));
178 mapRegs(DFG.makeRegRef(DstOp.getReg(), Hexagon::isub_hi),
179 DFG.makeRegRef(HiOp.getReg(), HiOp.getSubReg()));
180 mapRegs(DFG.makeRegRef(DstOp.getReg(), Hexagon::isub_lo),
181 DFG.makeRegRef(LoOp.getReg(), LoOp.getSubReg()));
182 return true;
183 }
184 case Hexagon::A2_addi: {
185 const MachineOperand &A = MI->getOperand(2);
186 if (!A.isImm() || A.getImm() != 0)
187 return false;
188 [[fallthrough]];
189 }
190 case Hexagon::A2_tfr: {
191 const MachineOperand &DstOp = MI->getOperand(0);
192 const MachineOperand &SrcOp = MI->getOperand(1);
193 mapRegs(DFG.makeRegRef(DstOp.getReg(), DstOp.getSubReg()),
194 DFG.makeRegRef(SrcOp.getReg(), SrcOp.getSubReg()));
195 return true;
196 }
197 }
198
200}
201
202bool HexagonDCE::run() {
203 bool Collected = collect();
204 if (!Collected)
205 return false;
206
207 const SetVector<NodeId> &DeadNodes = getDeadNodes();
208 const SetVector<NodeId> &DeadInstrs = getDeadInstrs();
209
210 using RefToInstrMap = DenseMap<NodeId, NodeId>;
211
212 RefToInstrMap R2I;
213 SetVector<NodeId> PartlyDead;
214 DataFlowGraph &DFG = getDFG();
215
216 for (NodeAddr<BlockNode*> BA : DFG.getFunc().Addr->members(DFG)) {
217 for (auto TA : BA.Addr->members_if(DFG.IsCode<NodeAttrs::Stmt>, DFG)) {
218 NodeAddr<StmtNode*> SA = TA;
219 for (NodeAddr<RefNode*> RA : SA.Addr->members(DFG)) {
220 R2I.insert(std::make_pair(RA.Id, SA.Id));
221 if (DFG.IsDef(RA) && DeadNodes.count(RA.Id))
222 if (!DeadInstrs.count(SA.Id))
223 PartlyDead.insert(SA.Id);
224 }
225 }
226 }
227
228 // Nodes to remove.
229 SetVector<NodeId> Remove = DeadInstrs;
230
231 bool Changed = false;
232 for (NodeId N : PartlyDead) {
233 auto SA = DFG.addr<StmtNode*>(N);
234 if (trace())
235 dbgs() << "Partly dead: " << *SA.Addr->getCode();
236 Changed |= rewrite(SA, Remove);
237 }
238
239 return erase(Remove) || Changed;
240}
241
242void HexagonDCE::removeOperand(NodeAddr<InstrNode*> IA, unsigned OpNum) {
243 MachineInstr *MI = NodeAddr<StmtNode*>(IA).Addr->getCode();
244
245 auto getOpNum = [MI] (MachineOperand &Op) -> unsigned {
246 for (unsigned i = 0, n = MI->getNumOperands(); i != n; ++i)
247 if (&MI->getOperand(i) == &Op)
248 return i;
249 llvm_unreachable("Invalid operand");
250 };
251 DenseMap<NodeId,unsigned> OpMap;
252 DataFlowGraph &DFG = getDFG();
253 NodeList Refs = IA.Addr->members(DFG);
254 for (NodeAddr<RefNode*> RA : Refs)
255 OpMap.insert(std::make_pair(RA.Id, getOpNum(RA.Addr->getOp())));
256
257 MI->removeOperand(OpNum);
258
259 for (NodeAddr<RefNode*> RA : Refs) {
260 unsigned N = OpMap[RA.Id];
261 if (N < OpNum)
262 RA.Addr->setRegRef(&MI->getOperand(N), DFG);
263 else if (N > OpNum)
264 RA.Addr->setRegRef(&MI->getOperand(N-1), DFG);
265 }
266}
267
268bool HexagonDCE::rewrite(NodeAddr<InstrNode*> IA, SetVector<NodeId> &Remove) {
269 if (!getDFG().IsCode<NodeAttrs::Stmt>(IA))
270 return false;
271 DataFlowGraph &DFG = getDFG();
272 MachineInstr &MI = *NodeAddr<StmtNode*>(IA).Addr->getCode();
273 auto &HII = static_cast<const HexagonInstrInfo&>(DFG.getTII());
274 if (HII.getAddrMode(MI) != HexagonII::PostInc)
275 return false;
276 unsigned Opc = MI.getOpcode();
277 unsigned OpNum, NewOpc;
278 switch (Opc) {
279 case Hexagon::L2_loadri_pi:
280 NewOpc = Hexagon::L2_loadri_io;
281 OpNum = 1;
282 break;
283 case Hexagon::L2_loadrd_pi:
284 NewOpc = Hexagon::L2_loadrd_io;
285 OpNum = 1;
286 break;
287 case Hexagon::V6_vL32b_pi:
288 NewOpc = Hexagon::V6_vL32b_ai;
289 OpNum = 1;
290 break;
291 case Hexagon::S2_storeri_pi:
292 NewOpc = Hexagon::S2_storeri_io;
293 OpNum = 0;
294 break;
295 case Hexagon::S2_storerd_pi:
296 NewOpc = Hexagon::S2_storerd_io;
297 OpNum = 0;
298 break;
299 case Hexagon::V6_vS32b_pi:
300 NewOpc = Hexagon::V6_vS32b_ai;
301 OpNum = 0;
302 break;
303 default:
304 return false;
305 }
306 auto IsDead = [this] (NodeAddr<DefNode*> DA) -> bool {
307 return getDeadNodes().count(DA.Id);
308 };
309 NodeList Defs;
310 MachineOperand &Op = MI.getOperand(OpNum);
311 for (NodeAddr<DefNode*> DA : IA.Addr->members_if(DFG.IsDef, DFG)) {
312 if (&DA.Addr->getOp() != &Op)
313 continue;
314 Defs = DFG.getRelatedRefs(IA, DA);
315 if (!llvm::all_of(Defs, IsDead))
316 return false;
317 break;
318 }
319
320 // Mark all nodes in Defs for removal.
321 for (auto D : Defs)
322 Remove.insert(D.Id);
323
324 if (trace())
325 dbgs() << "Rewriting: " << MI;
326 MI.setDesc(HII.get(NewOpc));
327 MI.getOperand(OpNum+2).setImm(0);
328 removeOperand(IA, OpNum);
329 if (trace())
330 dbgs() << " to: " << MI;
331
332 return true;
333}
334
335bool HexagonRDFOpt::runOnMachineFunction(MachineFunction &MF) {
336 if (skipFunction(MF.getFunction()))
337 return false;
338
339 // Perform RDF optimizations only if number of basic blocks in the
340 // function is less than the limit
341 if (MF.size() > RDFFuncBlockLimit) {
342 if (RDFDump)
343 dbgs() << "Skipping " << getPassName() << ": too many basic blocks\n";
344 return false;
345 }
346
347 if (RDFLimit.getPosition()) {
348 if (RDFCount >= RDFLimit)
349 return false;
350 RDFCount++;
351 }
352
353 MDT = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
354 const auto &MDF = getAnalysis<MachineDominanceFrontierWrapperPass>().getMDF();
355 const auto &HII = *MF.getSubtarget<HexagonSubtarget>().getInstrInfo();
356 const auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
357 MRI = &MF.getRegInfo();
358 bool Changed;
359
360 if (RDFDump)
361 MF.print(dbgs() << "Before " << getPassName() << "\n", nullptr);
362
363 DataFlowGraph G(MF, HII, HRI, *MDT, MDF);
364 // Dead phi nodes are necessary for copy propagation: we can add a use
365 // of a register in a block where it would need a phi node, but which
366 // was dead (and removed) during the graph build time.
367 DataFlowGraph::Config Cfg;
371 G.build(Cfg);
372
374 if (RDFDump)
375 dbgs() << "Starting aggressive copy propagation on: " << MF.getName()
376 << '\n'
377 << PrintNode<FuncNode *>(G.getFunc(), G) << '\n';
378 HexagonAggressiveCP CP(G);
379 CP.trace(RDFDump);
380 Changed = CP.run();
381 } else {
382 if (RDFDump)
383 dbgs() << "Starting copy propagation on: " << MF.getName() << '\n'
384 << PrintNode<FuncNode *>(G.getFunc(), G) << '\n';
385 HexagonCP CP(G);
386 CP.trace(RDFDump);
387 Changed = CP.run();
388 }
389
390 if (RDFDump)
391 dbgs() << "Starting dead code elimination on: " << MF.getName() << '\n'
392 << PrintNode<FuncNode*>(G.getFunc(), G) << '\n';
393 HexagonDCE DCE(G, *MRI);
394 DCE.trace(RDFDump);
395 Changed |= DCE.run();
396
397 if (Changed) {
398 if (RDFDump) {
399 dbgs() << "Starting liveness recomputation on: " << MF.getName() << '\n'
400 << PrintNode<FuncNode*>(G.getFunc(), G) << '\n';
401 }
402 Liveness LV(*MRI, G);
403 LV.trace(RDFDump);
404 LV.computeLiveIns();
405 LV.resetLiveIns();
406 LV.resetKills();
407 }
408
409 if (RDFDump)
410 MF.print(dbgs() << "After " << getPassName() << "\n", nullptr);
411
412 return false;
413}
414
416 return new HexagonRDFOpt();
417}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
aarch64 promote const
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
This file defines the DenseMap class.
cl::opt< unsigned > RDFFuncBlockLimit
static cl::opt< bool > RDFTrackReserved("hexagon-rdf-track-reserved", cl::Hidden)
static cl::opt< bool > EnableAggressiveRDFCopy("hexagon-aggressive-rdf-copy", cl::desc("Enable aggressive RDF copy propagation with super-register " "support"), cl::init(false), cl::Hidden)
static cl::opt< unsigned > RDFLimit("hexagon-rdf-limit", cl::init(std::numeric_limits< unsigned >::max()))
static unsigned RDFCount
static cl::opt< bool > RDFDump("hexagon-rdf-dump", cl::Hidden)
IRTranslator LLVM IR MI
#define G(x, y, z)
Definition MD5.cpp:55
Register const TargetRegisterInfo * TRI
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
bool IsDead
SI optimize exec mask operations pre RA
This file contains some templates that are useful if you are working with the STL at all.
This file implements a set that has insertion order iteration characteristics.
AnalysisUsage & addRequired()
void setPreservesAll()
Set by analyses that do not transform their input at all.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition DenseMap.h:239
Register getReg() const
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
Analysis pass which computes a MachineDominatorTree.
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.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
void print(raw_ostream &OS, const SlotIndexes *=nullptr) const
print - Print out the MachineFunction in a format suitable for debugging to the specified stream.
Representation of each machine instruction.
MachineOperand class - Representation of each machine instruction operand.
unsigned getSubReg() const
Register getReg() const
getReg - Returns the register number.
size_type count(const_arg_type key) const
Count the number of elements of a given key in the SetVector.
Definition SetVector.h:262
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition SetVector.h:151
Register getReg() const
Changed
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
initializer< Ty > init(const Ty &Val)
DXILDebugInfoMap run(Module &M)
uint32_t NodeId
Definition RDFGraph.h:262
SmallVector< Node, 4 > NodeList
Definition RDFGraph.h:550
This is an optimization pass for GlobalISel generic memory operations.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1738
void erase(Container &C, ValueType V)
Wrapper function to remove a value from a container:
Definition STLExtras.h:2199
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
DWARFExpression::Operation Op
FunctionPass * createHexagonRDFOpt()
#define N
virtual bool interpretAsCopy(const MachineInstr *MI, EqualityMap &EM)
LLVM_ABI NodeList members(const DataFlowGraph &G) const
Definition RDFGraph.cpp:519
LLVM_ABI RegisterRef makeRegRef(unsigned Reg, unsigned Sub) const
Definition RDFGraph.cpp:987
static bool IsDef(const Node BA)
Definition RDFGraph.h:828
LLVM_ABI NodeList getRelatedRefs(Instr IA, Ref RA) const
const TargetInstrInfo & getTII() const
Definition RDFGraph.h:698
static bool IsCode(const Node BA)
Definition RDFGraph.h:824
const TargetRegisterInfo & getTRI() const
Definition RDFGraph.h:699
NodeAddr< T > addr(NodeId N) const
Definition RDFGraph.h:692