LLVM 24.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"
18#include "llvm/ADT/STLExtras.h"
19#include "llvm/ADT/SetVector.h"
32#include "llvm/Pass.h"
35#include "llvm/Support/Debug.h"
38#include <cassert>
39#include <limits>
40
41using namespace llvm;
42using namespace rdf;
43
44static unsigned RDFCount = 0;
46
48 RDFLimit("hexagon-rdf-limit",
49 cl::init(std::numeric_limits<unsigned>::max()));
51 "hexagon-aggressive-rdf-copy",
52 cl::desc("Enable aggressive RDF copy propagation with super-register "
53 "support"),
54 cl::init(true), cl::Hidden);
55static cl::opt<bool> RDFDump("hexagon-rdf-dump", cl::Hidden);
56static cl::opt<bool> RDFTrackReserved("hexagon-rdf-track-reserved", cl::Hidden);
57
58namespace {
59
60 class HexagonRDFOpt : public MachineFunctionPass {
61 public:
62 HexagonRDFOpt() : MachineFunctionPass(ID) {}
63
64 void getAnalysisUsage(AnalysisUsage &AU) const override {
65 AU.addRequired<MachineDominatorTreeWrapperPass>();
66 AU.addRequired<MachineDominanceFrontierWrapperPass>();
67 AU.setPreservesAll();
69 }
70
71 StringRef getPassName() const override {
72 return "Hexagon RDF optimizations";
73 }
74
75 bool runOnMachineFunction(MachineFunction &MF) override;
76
77 MachineFunctionProperties getRequiredProperties() const override {
78 return MachineFunctionProperties().setNoVRegs();
79 }
80
81 static char ID;
82
83 private:
84 MachineDominatorTree *MDT;
85 MachineRegisterInfo *MRI;
86 };
87
88struct HexagonCP : public CopyPropagation {
89 HexagonCP(DataFlowGraph &G) : CopyPropagation(G) {}
90
91 bool interpretAsCopy(const MachineInstr *MI, EqualityMap &EM) override;
92};
93
94struct HexagonAggressiveCP : public AggressiveCopyPropagation {
95 HexagonAggressiveCP(DataFlowGraph &G) : AggressiveCopyPropagation(G) {}
96
97 bool interpretAsCopy(const MachineInstr *MI, EqualityMap &EM) override;
98};
99
100struct HexagonDCE : public DeadCodeElimination {
101 HexagonDCE(DataFlowGraph &G, MachineRegisterInfo &MRI)
102 : DeadCodeElimination(G, MRI) {}
103
104 bool rewrite(NodeAddr<InstrNode*> IA, SetVector<NodeId> &Remove);
105 void removeOperand(NodeAddr<InstrNode*> IA, unsigned OpNum);
106
107 bool run();
108};
109
110} // end anonymous namespace
111
112char HexagonRDFOpt::ID = 0;
113
114INITIALIZE_PASS_BEGIN(HexagonRDFOpt, "hexagon-rdf-opt",
115 "Hexagon RDF optimizations", false, false)
118INITIALIZE_PASS_END(HexagonRDFOpt, "hexagon-rdf-opt",
119 "Hexagon RDF optimizations", false, false)
120
121bool HexagonCP::interpretAsCopy(const MachineInstr *MI, EqualityMap &EM) {
122 auto mapRegs = [&EM] (RegisterRef DstR, RegisterRef SrcR) -> void {
123 EM.insert(std::make_pair(DstR, SrcR));
124 };
125
126 DataFlowGraph &DFG = getDFG();
127 unsigned Opc = MI->getOpcode();
128 switch (Opc) {
129 case Hexagon::A2_combinew: {
130 const MachineOperand &DstOp = MI->getOperand(0);
131 const MachineOperand &HiOp = MI->getOperand(1);
132 const MachineOperand &LoOp = MI->getOperand(2);
133 assert(DstOp.getSubReg() == 0 && "Unexpected subregister");
134 mapRegs(DFG.makeRegRef(DstOp.getReg(), Hexagon::isub_hi),
135 DFG.makeRegRef(HiOp.getReg(), HiOp.getSubReg()));
136 mapRegs(DFG.makeRegRef(DstOp.getReg(), Hexagon::isub_lo),
137 DFG.makeRegRef(LoOp.getReg(), LoOp.getSubReg()));
138 return true;
139 }
140 case Hexagon::A2_addi: {
141 const MachineOperand &A = MI->getOperand(2);
142 if (!A.isImm() || A.getImm() != 0)
143 return false;
144 [[fallthrough]];
145 }
146 case Hexagon::A2_tfr: {
147 const MachineOperand &DstOp = MI->getOperand(0);
148 const MachineOperand &SrcOp = MI->getOperand(1);
149 mapRegs(DFG.makeRegRef(DstOp.getReg(), DstOp.getSubReg()),
150 DFG.makeRegRef(SrcOp.getReg(), SrcOp.getSubReg()));
151 return true;
152 }
153 }
154
155 return CopyPropagation::interpretAsCopy(MI, EM);
156}
157
158bool HexagonAggressiveCP::interpretAsCopy(const MachineInstr *MI,
159 EqualityMap &EM) {
160 auto mapRegs = [&EM](RegisterRef DstR, RegisterRef SrcR) -> void {
161 EM.insert(std::make_pair(DstR, SrcR));
162 };
163
164 DataFlowGraph &DFG = getDFG();
165 const TargetRegisterInfo &TRI = DFG.getTRI();
166 unsigned Opc = MI->getOpcode();
167 switch (Opc) {
168 case Hexagon::A2_combinew: {
169 // Combine instruction is equivalent to double reg copy.
170 // Add double reg copy to map.
171 const MachineOperand &DstOp = MI->getOperand(0);
172 const MachineOperand &HiOp = MI->getOperand(1);
173 const MachineOperand &LoOp = MI->getOperand(2);
174 assert(DstOp.getSubReg() == 0 && "Unexpected subregister");
175 unsigned DoubleRegDest = TRI.getMatchingSuperReg(
176 LoOp.getReg(), Hexagon::isub_lo, &Hexagon::DoubleRegsRegClass);
177 if (DoubleRegDest != 0 &&
178 TRI.isSuperRegister(HiOp.getReg(), DoubleRegDest))
179 mapRegs(DFG.makeRegRef(DstOp), DFG.makeRegRef(DoubleRegDest, 0));
180 mapRegs(DFG.makeRegRef(DstOp.getReg(), Hexagon::isub_hi),
181 DFG.makeRegRef(HiOp.getReg(), HiOp.getSubReg()));
182 mapRegs(DFG.makeRegRef(DstOp.getReg(), Hexagon::isub_lo),
183 DFG.makeRegRef(LoOp.getReg(), LoOp.getSubReg()));
184 return true;
185 }
186 case Hexagon::A2_addi: {
187 const MachineOperand &A = MI->getOperand(2);
188 if (!A.isImm() || A.getImm() != 0)
189 return false;
190 [[fallthrough]];
191 }
192 case Hexagon::A2_tfr: {
193 const MachineOperand &DstOp = MI->getOperand(0);
194 const MachineOperand &SrcOp = MI->getOperand(1);
195 mapRegs(DFG.makeRegRef(DstOp.getReg(), DstOp.getSubReg()),
196 DFG.makeRegRef(SrcOp.getReg(), SrcOp.getSubReg()));
197 return true;
198 }
199 }
200
202}
203
204bool HexagonDCE::run() {
205 bool Collected = collect();
206 if (!Collected)
207 return false;
208
209 const SetVector<NodeId> &DeadNodes = getDeadNodes();
210 const SetVector<NodeId> &DeadInstrs = getDeadInstrs();
211
212 using RefToInstrMap = DenseMap<NodeId, NodeId>;
213
214 RefToInstrMap R2I;
215 SetVector<NodeId> PartlyDead;
216 DataFlowGraph &DFG = getDFG();
217
218 for (NodeAddr<BlockNode*> BA : DFG.getFunc().Addr->members(DFG)) {
219 for (auto TA : BA.Addr->members_if(DFG.IsCode<NodeAttrs::Stmt>, DFG)) {
220 NodeAddr<StmtNode*> SA = TA;
221 for (NodeAddr<RefNode*> RA : SA.Addr->members(DFG)) {
222 R2I.insert(std::make_pair(RA.Id, SA.Id));
223 if (DFG.IsDef(RA) && DeadNodes.count(RA.Id))
224 if (!DeadInstrs.count(SA.Id))
225 PartlyDead.insert(SA.Id);
226 }
227 }
228 }
229
230 // Nodes to remove.
231 SetVector<NodeId> Remove = DeadInstrs;
232
233 bool Changed = false;
234 for (NodeId N : PartlyDead) {
235 auto SA = DFG.addr<StmtNode*>(N);
236 if (trace())
237 dbgs() << "Partly dead: " << *SA.Addr->getCode();
238 Changed |= rewrite(SA, Remove);
239 }
240
241 return erase(Remove) || Changed;
242}
243
244void HexagonDCE::removeOperand(NodeAddr<InstrNode*> IA, unsigned OpNum) {
245 MachineInstr *MI = NodeAddr<StmtNode*>(IA).Addr->getCode();
246
247 auto getOpNum = [MI] (MachineOperand &Op) -> unsigned {
248 for (unsigned i = 0, n = MI->getNumOperands(); i != n; ++i)
249 if (&MI->getOperand(i) == &Op)
250 return i;
251 llvm_unreachable("Invalid operand");
252 };
253 DenseMap<NodeId,unsigned> OpMap;
254 DataFlowGraph &DFG = getDFG();
255 NodeList Refs = IA.Addr->members(DFG);
256 for (NodeAddr<RefNode*> RA : Refs)
257 OpMap.insert(std::make_pair(RA.Id, getOpNum(RA.Addr->getOp())));
258
259 MI->removeOperand(OpNum);
260
261 for (NodeAddr<RefNode*> RA : Refs) {
262 unsigned N = OpMap[RA.Id];
263 if (N < OpNum)
264 RA.Addr->setRegRef(&MI->getOperand(N), DFG);
265 else if (N > OpNum)
266 RA.Addr->setRegRef(&MI->getOperand(N-1), DFG);
267 }
268}
269
270bool HexagonDCE::rewrite(NodeAddr<InstrNode*> IA, SetVector<NodeId> &Remove) {
271 if (!getDFG().IsCode<NodeAttrs::Stmt>(IA))
272 return false;
273 DataFlowGraph &DFG = getDFG();
274 MachineInstr &MI = *NodeAddr<StmtNode*>(IA).Addr->getCode();
275 auto &HII = static_cast<const HexagonInstrInfo&>(DFG.getTII());
276 if (HII.getAddrMode(MI) != HexagonII::PostInc)
277 return false;
278 unsigned Opc = MI.getOpcode();
279 unsigned OpNum, NewOpc;
280 switch (Opc) {
281 case Hexagon::L2_loadri_pi:
282 NewOpc = Hexagon::L2_loadri_io;
283 OpNum = 1;
284 break;
285 case Hexagon::L2_loadrd_pi:
286 NewOpc = Hexagon::L2_loadrd_io;
287 OpNum = 1;
288 break;
289 case Hexagon::V6_vL32b_pi:
290 NewOpc = Hexagon::V6_vL32b_ai;
291 OpNum = 1;
292 break;
293 case Hexagon::S2_storeri_pi:
294 NewOpc = Hexagon::S2_storeri_io;
295 OpNum = 0;
296 break;
297 case Hexagon::S2_storerd_pi:
298 NewOpc = Hexagon::S2_storerd_io;
299 OpNum = 0;
300 break;
301 case Hexagon::V6_vS32b_pi:
302 NewOpc = Hexagon::V6_vS32b_ai;
303 OpNum = 0;
304 break;
305 default:
306 return false;
307 }
308 auto IsDead = [this] (NodeAddr<DefNode*> DA) -> bool {
309 return getDeadNodes().count(DA.Id);
310 };
311 NodeList Defs;
312 MachineOperand &Op = MI.getOperand(OpNum);
313 for (NodeAddr<DefNode*> DA : IA.Addr->members_if(DFG.IsDef, DFG)) {
314 if (&DA.Addr->getOp() != &Op)
315 continue;
316 Defs = DFG.getRelatedRefs(IA, DA);
317 if (!llvm::all_of(Defs, IsDead))
318 return false;
319 break;
320 }
321
322 // Mark all nodes in Defs for removal.
323 for (auto D : Defs)
324 Remove.insert(D.Id);
325
326 if (trace())
327 dbgs() << "Rewriting: " << MI;
328 MI.setDesc(HII.get(NewOpc));
329 MI.getOperand(OpNum+2).setImm(0);
330 removeOperand(IA, OpNum);
331 if (trace())
332 dbgs() << " to: " << MI;
333
334 return true;
335}
336
337bool HexagonRDFOpt::runOnMachineFunction(MachineFunction &MF) {
338 if (skipFunction(MF.getFunction()))
339 return false;
340
341 // Perform RDF optimizations only if number of basic blocks in the
342 // function is less than the limit
343 if (MF.size() > RDFFuncBlockLimit) {
344 if (RDFDump)
345 dbgs() << "Skipping " << getPassName() << ": too many basic blocks\n";
346 return false;
347 }
348
349 if (RDFLimit.getPosition()) {
350 if (RDFCount >= RDFLimit)
351 return false;
352 RDFCount++;
353 }
354
355 MDT = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
356 const auto &MDF = getAnalysis<MachineDominanceFrontierWrapperPass>().getMDF();
357 const auto &HII = *MF.getSubtarget<HexagonSubtarget>().getInstrInfo();
358 const auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
359 MRI = &MF.getRegInfo();
360 bool Changed;
361
362 if (RDFDump)
363 MF.print(dbgs() << "Before " << getPassName() << "\n", nullptr);
364
365 DataFlowGraph G(MF, HII, HRI, *MDT, MDF);
366 // Dead phi nodes are necessary for copy propagation: we can add a use
367 // of a register in a block where it would need a phi node, but which
368 // was dead (and removed) during the graph build time.
369 DataFlowGraph::Config Cfg;
373 G.build(Cfg);
374
376 if (RDFDump)
377 dbgs() << "Starting aggressive copy propagation on: " << MF.getName()
378 << '\n'
379 << PrintNode<FuncNode *>(G.getFunc(), G) << '\n';
380 HexagonAggressiveCP CP(G);
381 CP.trace(RDFDump);
382 Changed = CP.run();
383 } else {
384 if (RDFDump)
385 dbgs() << "Starting copy propagation on: " << MF.getName() << '\n'
386 << PrintNode<FuncNode *>(G.getFunc(), G) << '\n';
387 HexagonCP CP(G);
388 CP.trace(RDFDump);
389 Changed = CP.run();
390 }
391
392 if (RDFDump)
393 dbgs() << "Starting dead code elimination on: " << MF.getName() << '\n'
394 << PrintNode<FuncNode*>(G.getFunc(), G) << '\n';
395 HexagonDCE DCE(G, *MRI);
396 DCE.trace(RDFDump);
397 Changed |= DCE.run();
398
399 if (Changed) {
400 if (RDFDump) {
401 dbgs() << "Starting liveness recomputation on: " << MF.getName() << '\n'
402 << PrintNode<FuncNode*>(G.getFunc(), G) << '\n';
403 }
404 Liveness LV(*MRI, G);
405 LV.trace(RDFDump);
406 LV.computeLiveIns();
407
408 // Set entry-block live-ins from the RDF LiveMap: calling-convention
409 // registers may not have direct uses and cannot be recovered by a
410 // backward walk.
411 MachineBasicBlock &EntryMBB = MF.front();
412 {
413 std::vector<MCRegister> Old;
414 for (const MachineBasicBlock::RegisterMaskPair &LI : EntryMBB.liveins())
415 Old.push_back(LI.PhysReg);
416 for (MCRegister R : Old)
417 EntryMBB.removeLiveIn(R);
418 for (RegisterRef R : LV.getLiveMap()[&EntryMBB].refs())
419 EntryMBB.addLiveIn({R.asMCReg(), R.Mask});
420 EntryMBB.sortUniqueLiveIns();
421 }
422
423 // The RDF-based live-in recomputation can leave stale (over-approximate)
424 // physical register live-ins on some blocks, which later confuses passes
425 // like IfConversion into inserting incorrect implicit-use operands. Run a
426 // conventional backward liveness recomputation to correct the live-in
427 // lists. Skip:
428 // - the entry block: handled above from the RDF LiveMap;
429 // - EH pads: exception pointer/selector are runtime-established.
430 //
431 // Recompute live-ins one block at a time, visiting successors before
432 // predecessors (post-order). This way each block already has fresh
433 // live-in info from its successors when it is processed.
435 for (MachineBasicBlock *MBB : post_order(&MF))
436 if (!MBB->isEntryBlock() && !MBB->isEHPad())
437 Candidates.push_back(MBB);
438
439 // One pass is usually enough. If any block's live-ins changed, repeat
440 // because its predecessors may need updating too. Stop after
441 // MaxLiveInSweeps passes to keep compile time bounded.
442 constexpr unsigned MaxLiveInSweeps = 8;
443 for (unsigned Sweep = 0; Sweep != MaxLiveInSweeps; ++Sweep) {
444 bool AnyChanged = false;
445 for (MachineBasicBlock *MBB : Candidates)
446 AnyChanged |= recomputeLiveIns(*MBB);
447 if (!AnyChanged)
448 break;
449 }
450
451 // Recompute kill flags against the updated live-in lists.
452 LV.resetKills();
453 }
454
455 if (RDFDump)
456 MF.print(dbgs() << "After " << getPassName() << "\n", nullptr);
457
458 return false;
459}
460
462 return new HexagonRDFOpt();
463}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
aarch64 promote const
MachineBasicBlock & MBB
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 > EnableAggressiveRDFCopy("hexagon-aggressive-rdf-copy", cl::desc("Enable aggressive RDF copy propagation with super-register " "support"), cl::init(true), cl::Hidden)
static cl::opt< bool > RDFTrackReserved("hexagon-rdf-track-reserved", 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
This file implements the LivePhysRegs utility for tracking liveness of physical registers.
#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
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
MachineRegisterInfo & MRI
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:827
Register getReg() const
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:312
bool isEHPad() const
Returns true if the block is a landing pad.
iterator_range< livein_iterator > liveins() const
LLVM_ABI void removeLiveIn(MCRegister Reg, LaneBitmask LaneMask=LaneBitmask::getAll())
Remove the specified register from the live in set.
LLVM_ABI bool isEntryBlock() const
Returns true if this is the entry block of the function.
LLVM_ABI void sortUniqueLiveIns()
Sorts and uniques the LiveIns vector.
void addLiveIn(MCRegister PhysReg, LaneBitmask LaneMask=LaneBitmask::getAll())
Adds the specified register as a live in.
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.
const MachineBasicBlock & front() const
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:268
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition SetVector.h:157
void push_back(const T &Elt)
Register getReg() const
unsigned getPosition() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
initializer< Ty > init(const Ty &Val)
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the 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:1755
void erase(Container &C, ValueType V)
Wrapper function to remove a value from a container:
Definition STLExtras.h:2216
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
auto post_order(const T &G)
Post-order traversal of a graph.
DWARFExpression::Operation Op
static bool recomputeLiveIns(MachineBasicBlock &MBB)
Convenience function for recomputing live-in's for a MBB.
FunctionPass * createHexagonRDFOpt()
#define N
virtual bool interpretAsCopy(const MachineInstr *MI, EqualityMap &EM)
LLVM_ABI NodeList members(const DataFlowGraph &G) const
Definition RDFGraph.cpp:520
LLVM_ABI RegisterRef makeRegRef(unsigned Reg, unsigned Sub) const
Definition RDFGraph.cpp:989
static bool IsDef(const Node BA)
Definition RDFGraph.h:827
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:823
const TargetRegisterInfo & getTRI() const
Definition RDFGraph.h:699
NodeAddr< T > addr(NodeId N) const
Definition RDFGraph.h:692