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(false), 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 > 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
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.
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:284
Register getReg() const
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
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:262
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition SetVector.h:151
void push_back(const T &Elt)
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:552
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:1739
void erase(Container &C, ValueType V)
Wrapper function to remove a value from a container:
Definition STLExtras.h:2200
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:519
LLVM_ABI RegisterRef makeRegRef(unsigned Reg, unsigned Sub) const
Definition RDFGraph.cpp:987
static bool IsDef(const Node BA)
Definition RDFGraph.h:829
LLVM_ABI NodeList getRelatedRefs(Instr IA, Ref RA) const
const TargetInstrInfo & getTII() const
Definition RDFGraph.h:700
static bool IsCode(const Node BA)
Definition RDFGraph.h:825
const TargetRegisterInfo & getTRI() const
Definition RDFGraph.h:701
NodeAddr< T > addr(NodeId N) const
Definition RDFGraph.h:694