xref: /aosp_15_r20/external/llvm/lib/Target/Hexagon/RDFDeadCode.cpp (revision 9880d6810fe72a1726cb53787c6711e909410d58)
1*9880d681SAndroid Build Coastguard Worker //===--- RDFDeadCode.cpp --------------------------------------------------===//
2*9880d681SAndroid Build Coastguard Worker //
3*9880d681SAndroid Build Coastguard Worker //                     The LLVM Compiler Infrastructure
4*9880d681SAndroid Build Coastguard Worker //
5*9880d681SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*9880d681SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*9880d681SAndroid Build Coastguard Worker //
8*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*9880d681SAndroid Build Coastguard Worker //
10*9880d681SAndroid Build Coastguard Worker // RDF-based generic dead code elimination.
11*9880d681SAndroid Build Coastguard Worker 
12*9880d681SAndroid Build Coastguard Worker #include "RDFGraph.h"
13*9880d681SAndroid Build Coastguard Worker #include "RDFLiveness.h"
14*9880d681SAndroid Build Coastguard Worker #include "RDFDeadCode.h"
15*9880d681SAndroid Build Coastguard Worker 
16*9880d681SAndroid Build Coastguard Worker #include "llvm/ADT/SetVector.h"
17*9880d681SAndroid Build Coastguard Worker #include "llvm/CodeGen/MachineBasicBlock.h"
18*9880d681SAndroid Build Coastguard Worker #include "llvm/CodeGen/MachineFunction.h"
19*9880d681SAndroid Build Coastguard Worker #include "llvm/CodeGen/MachineRegisterInfo.h"
20*9880d681SAndroid Build Coastguard Worker 
21*9880d681SAndroid Build Coastguard Worker #include <queue>
22*9880d681SAndroid Build Coastguard Worker 
23*9880d681SAndroid Build Coastguard Worker using namespace llvm;
24*9880d681SAndroid Build Coastguard Worker using namespace rdf;
25*9880d681SAndroid Build Coastguard Worker 
26*9880d681SAndroid Build Coastguard Worker // This drastically improves execution time in "collect" over using
27*9880d681SAndroid Build Coastguard Worker // SetVector as a work queue, and popping the first element from it.
28*9880d681SAndroid Build Coastguard Worker template<typename T> struct DeadCodeElimination::SetQueue {
SetQueueDeadCodeElimination::SetQueue29*9880d681SAndroid Build Coastguard Worker   SetQueue() : Set(), Queue() {}
30*9880d681SAndroid Build Coastguard Worker 
emptyDeadCodeElimination::SetQueue31*9880d681SAndroid Build Coastguard Worker   bool empty() const {
32*9880d681SAndroid Build Coastguard Worker     return Queue.empty();
33*9880d681SAndroid Build Coastguard Worker   }
pop_frontDeadCodeElimination::SetQueue34*9880d681SAndroid Build Coastguard Worker   T pop_front() {
35*9880d681SAndroid Build Coastguard Worker     T V = Queue.front();
36*9880d681SAndroid Build Coastguard Worker     Queue.pop();
37*9880d681SAndroid Build Coastguard Worker     Set.erase(V);
38*9880d681SAndroid Build Coastguard Worker     return V;
39*9880d681SAndroid Build Coastguard Worker   }
push_backDeadCodeElimination::SetQueue40*9880d681SAndroid Build Coastguard Worker   void push_back(T V) {
41*9880d681SAndroid Build Coastguard Worker     if (Set.count(V))
42*9880d681SAndroid Build Coastguard Worker       return;
43*9880d681SAndroid Build Coastguard Worker     Queue.push(V);
44*9880d681SAndroid Build Coastguard Worker     Set.insert(V);
45*9880d681SAndroid Build Coastguard Worker   }
46*9880d681SAndroid Build Coastguard Worker 
47*9880d681SAndroid Build Coastguard Worker private:
48*9880d681SAndroid Build Coastguard Worker   DenseSet<T> Set;
49*9880d681SAndroid Build Coastguard Worker   std::queue<T> Queue;
50*9880d681SAndroid Build Coastguard Worker };
51*9880d681SAndroid Build Coastguard Worker 
52*9880d681SAndroid Build Coastguard Worker 
53*9880d681SAndroid Build Coastguard Worker // Check if the given instruction has observable side-effects, i.e. if
54*9880d681SAndroid Build Coastguard Worker // it should be considered "live". It is safe for this function to be
55*9880d681SAndroid Build Coastguard Worker // overly conservative (i.e. return "true" for all instructions), but it
56*9880d681SAndroid Build Coastguard Worker // is not safe to return "false" for an instruction that should not be
57*9880d681SAndroid Build Coastguard Worker // considered removable.
isLiveInstr(const MachineInstr * MI) const58*9880d681SAndroid Build Coastguard Worker bool DeadCodeElimination::isLiveInstr(const MachineInstr *MI) const {
59*9880d681SAndroid Build Coastguard Worker   if (MI->mayStore() || MI->isBranch() || MI->isCall() || MI->isReturn())
60*9880d681SAndroid Build Coastguard Worker     return true;
61*9880d681SAndroid Build Coastguard Worker   if (MI->hasOrderedMemoryRef() || MI->hasUnmodeledSideEffects())
62*9880d681SAndroid Build Coastguard Worker     return true;
63*9880d681SAndroid Build Coastguard Worker   if (MI->isPHI())
64*9880d681SAndroid Build Coastguard Worker     return false;
65*9880d681SAndroid Build Coastguard Worker   for (auto &Op : MI->operands())
66*9880d681SAndroid Build Coastguard Worker     if (Op.isReg() && MRI.isReserved(Op.getReg()))
67*9880d681SAndroid Build Coastguard Worker       return true;
68*9880d681SAndroid Build Coastguard Worker   return false;
69*9880d681SAndroid Build Coastguard Worker }
70*9880d681SAndroid Build Coastguard Worker 
scanInstr(NodeAddr<InstrNode * > IA,SetQueue<NodeId> & WorkQ)71*9880d681SAndroid Build Coastguard Worker void DeadCodeElimination::scanInstr(NodeAddr<InstrNode*> IA,
72*9880d681SAndroid Build Coastguard Worker       SetQueue<NodeId> &WorkQ) {
73*9880d681SAndroid Build Coastguard Worker   if (!DFG.IsCode<NodeAttrs::Stmt>(IA))
74*9880d681SAndroid Build Coastguard Worker     return;
75*9880d681SAndroid Build Coastguard Worker   if (!isLiveInstr(NodeAddr<StmtNode*>(IA).Addr->getCode()))
76*9880d681SAndroid Build Coastguard Worker     return;
77*9880d681SAndroid Build Coastguard Worker   for (NodeAddr<RefNode*> RA : IA.Addr->members(DFG)) {
78*9880d681SAndroid Build Coastguard Worker     if (!LiveNodes.count(RA.Id))
79*9880d681SAndroid Build Coastguard Worker       WorkQ.push_back(RA.Id);
80*9880d681SAndroid Build Coastguard Worker   }
81*9880d681SAndroid Build Coastguard Worker }
82*9880d681SAndroid Build Coastguard Worker 
processDef(NodeAddr<DefNode * > DA,SetQueue<NodeId> & WorkQ)83*9880d681SAndroid Build Coastguard Worker void DeadCodeElimination::processDef(NodeAddr<DefNode*> DA,
84*9880d681SAndroid Build Coastguard Worker       SetQueue<NodeId> &WorkQ) {
85*9880d681SAndroid Build Coastguard Worker   NodeAddr<InstrNode*> IA = DA.Addr->getOwner(DFG);
86*9880d681SAndroid Build Coastguard Worker   for (NodeAddr<UseNode*> UA : IA.Addr->members_if(DFG.IsUse, DFG)) {
87*9880d681SAndroid Build Coastguard Worker     if (!LiveNodes.count(UA.Id))
88*9880d681SAndroid Build Coastguard Worker       WorkQ.push_back(UA.Id);
89*9880d681SAndroid Build Coastguard Worker   }
90*9880d681SAndroid Build Coastguard Worker   for (NodeAddr<DefNode*> TA : DFG.getRelatedRefs(IA, DA))
91*9880d681SAndroid Build Coastguard Worker     LiveNodes.insert(TA.Id);
92*9880d681SAndroid Build Coastguard Worker }
93*9880d681SAndroid Build Coastguard Worker 
processUse(NodeAddr<UseNode * > UA,SetQueue<NodeId> & WorkQ)94*9880d681SAndroid Build Coastguard Worker void DeadCodeElimination::processUse(NodeAddr<UseNode*> UA,
95*9880d681SAndroid Build Coastguard Worker       SetQueue<NodeId> &WorkQ) {
96*9880d681SAndroid Build Coastguard Worker   for (NodeAddr<DefNode*> DA : LV.getAllReachingDefs(UA)) {
97*9880d681SAndroid Build Coastguard Worker     if (!LiveNodes.count(DA.Id))
98*9880d681SAndroid Build Coastguard Worker       WorkQ.push_back(DA.Id);
99*9880d681SAndroid Build Coastguard Worker   }
100*9880d681SAndroid Build Coastguard Worker }
101*9880d681SAndroid Build Coastguard Worker 
102*9880d681SAndroid Build Coastguard Worker // Traverse the DFG and collect the set dead RefNodes and the set of
103*9880d681SAndroid Build Coastguard Worker // dead instructions. Return "true" if any of these sets is non-empty,
104*9880d681SAndroid Build Coastguard Worker // "false" otherwise.
collect()105*9880d681SAndroid Build Coastguard Worker bool DeadCodeElimination::collect() {
106*9880d681SAndroid Build Coastguard Worker   // This function works by first finding all live nodes. The dead nodes
107*9880d681SAndroid Build Coastguard Worker   // are then the complement of the set of live nodes.
108*9880d681SAndroid Build Coastguard Worker   //
109*9880d681SAndroid Build Coastguard Worker   // Assume that all nodes are dead. Identify instructions which must be
110*9880d681SAndroid Build Coastguard Worker   // considered live, i.e. instructions with observable side-effects, such
111*9880d681SAndroid Build Coastguard Worker   // as calls and stores. All arguments of such instructions are considered
112*9880d681SAndroid Build Coastguard Worker   // live. For each live def, all operands used in the corresponding
113*9880d681SAndroid Build Coastguard Worker   // instruction are considered live. For each live use, all its reaching
114*9880d681SAndroid Build Coastguard Worker   // defs are considered live.
115*9880d681SAndroid Build Coastguard Worker   LiveNodes.clear();
116*9880d681SAndroid Build Coastguard Worker   SetQueue<NodeId> WorkQ;
117*9880d681SAndroid Build Coastguard Worker   for (NodeAddr<BlockNode*> BA : DFG.getFunc().Addr->members(DFG))
118*9880d681SAndroid Build Coastguard Worker     for (NodeAddr<InstrNode*> IA : BA.Addr->members(DFG))
119*9880d681SAndroid Build Coastguard Worker       scanInstr(IA, WorkQ);
120*9880d681SAndroid Build Coastguard Worker 
121*9880d681SAndroid Build Coastguard Worker   while (!WorkQ.empty()) {
122*9880d681SAndroid Build Coastguard Worker     NodeId N = WorkQ.pop_front();
123*9880d681SAndroid Build Coastguard Worker     LiveNodes.insert(N);
124*9880d681SAndroid Build Coastguard Worker     auto RA = DFG.addr<RefNode*>(N);
125*9880d681SAndroid Build Coastguard Worker     if (DFG.IsDef(RA))
126*9880d681SAndroid Build Coastguard Worker       processDef(RA, WorkQ);
127*9880d681SAndroid Build Coastguard Worker     else
128*9880d681SAndroid Build Coastguard Worker       processUse(RA, WorkQ);
129*9880d681SAndroid Build Coastguard Worker   }
130*9880d681SAndroid Build Coastguard Worker 
131*9880d681SAndroid Build Coastguard Worker   if (trace()) {
132*9880d681SAndroid Build Coastguard Worker     dbgs() << "Live nodes:\n";
133*9880d681SAndroid Build Coastguard Worker     for (NodeId N : LiveNodes) {
134*9880d681SAndroid Build Coastguard Worker       auto RA = DFG.addr<RefNode*>(N);
135*9880d681SAndroid Build Coastguard Worker       dbgs() << PrintNode<RefNode*>(RA, DFG) << "\n";
136*9880d681SAndroid Build Coastguard Worker     }
137*9880d681SAndroid Build Coastguard Worker   }
138*9880d681SAndroid Build Coastguard Worker 
139*9880d681SAndroid Build Coastguard Worker   auto IsDead = [this] (NodeAddr<InstrNode*> IA) -> bool {
140*9880d681SAndroid Build Coastguard Worker     for (NodeAddr<DefNode*> DA : IA.Addr->members_if(DFG.IsDef, DFG))
141*9880d681SAndroid Build Coastguard Worker       if (LiveNodes.count(DA.Id))
142*9880d681SAndroid Build Coastguard Worker         return false;
143*9880d681SAndroid Build Coastguard Worker     return true;
144*9880d681SAndroid Build Coastguard Worker   };
145*9880d681SAndroid Build Coastguard Worker 
146*9880d681SAndroid Build Coastguard Worker   for (NodeAddr<BlockNode*> BA : DFG.getFunc().Addr->members(DFG)) {
147*9880d681SAndroid Build Coastguard Worker     for (NodeAddr<InstrNode*> IA : BA.Addr->members(DFG)) {
148*9880d681SAndroid Build Coastguard Worker       for (NodeAddr<RefNode*> RA : IA.Addr->members(DFG))
149*9880d681SAndroid Build Coastguard Worker         if (!LiveNodes.count(RA.Id))
150*9880d681SAndroid Build Coastguard Worker           DeadNodes.insert(RA.Id);
151*9880d681SAndroid Build Coastguard Worker       if (DFG.IsCode<NodeAttrs::Stmt>(IA))
152*9880d681SAndroid Build Coastguard Worker         if (isLiveInstr(NodeAddr<StmtNode*>(IA).Addr->getCode()))
153*9880d681SAndroid Build Coastguard Worker           continue;
154*9880d681SAndroid Build Coastguard Worker       if (IsDead(IA)) {
155*9880d681SAndroid Build Coastguard Worker         DeadInstrs.insert(IA.Id);
156*9880d681SAndroid Build Coastguard Worker         if (trace())
157*9880d681SAndroid Build Coastguard Worker           dbgs() << "Dead instr: " << PrintNode<InstrNode*>(IA, DFG) << "\n";
158*9880d681SAndroid Build Coastguard Worker       }
159*9880d681SAndroid Build Coastguard Worker     }
160*9880d681SAndroid Build Coastguard Worker   }
161*9880d681SAndroid Build Coastguard Worker 
162*9880d681SAndroid Build Coastguard Worker   return !DeadNodes.empty();
163*9880d681SAndroid Build Coastguard Worker }
164*9880d681SAndroid Build Coastguard Worker 
165*9880d681SAndroid Build Coastguard Worker // Erase the nodes given in the Nodes set from DFG. In addition to removing
166*9880d681SAndroid Build Coastguard Worker // them from the DFG, if a node corresponds to a statement, the corresponding
167*9880d681SAndroid Build Coastguard Worker // machine instruction is erased from the function.
erase(const SetVector<NodeId> & Nodes)168*9880d681SAndroid Build Coastguard Worker bool DeadCodeElimination::erase(const SetVector<NodeId> &Nodes) {
169*9880d681SAndroid Build Coastguard Worker   if (Nodes.empty())
170*9880d681SAndroid Build Coastguard Worker     return false;
171*9880d681SAndroid Build Coastguard Worker 
172*9880d681SAndroid Build Coastguard Worker   // Prepare the actual set of ref nodes to remove: ref nodes from Nodes
173*9880d681SAndroid Build Coastguard Worker   // are included directly, for each InstrNode in Nodes, include the set
174*9880d681SAndroid Build Coastguard Worker   // of all RefNodes from it.
175*9880d681SAndroid Build Coastguard Worker   NodeList DRNs, DINs;
176*9880d681SAndroid Build Coastguard Worker   for (auto I : Nodes) {
177*9880d681SAndroid Build Coastguard Worker     auto BA = DFG.addr<NodeBase*>(I);
178*9880d681SAndroid Build Coastguard Worker     uint16_t Type = BA.Addr->getType();
179*9880d681SAndroid Build Coastguard Worker     if (Type == NodeAttrs::Ref) {
180*9880d681SAndroid Build Coastguard Worker       DRNs.push_back(DFG.addr<RefNode*>(I));
181*9880d681SAndroid Build Coastguard Worker       continue;
182*9880d681SAndroid Build Coastguard Worker     }
183*9880d681SAndroid Build Coastguard Worker 
184*9880d681SAndroid Build Coastguard Worker     // If it's a code node, add all ref nodes from it.
185*9880d681SAndroid Build Coastguard Worker     uint16_t Kind = BA.Addr->getKind();
186*9880d681SAndroid Build Coastguard Worker     if (Kind == NodeAttrs::Stmt || Kind == NodeAttrs::Phi) {
187*9880d681SAndroid Build Coastguard Worker       for (auto N : NodeAddr<CodeNode*>(BA).Addr->members(DFG))
188*9880d681SAndroid Build Coastguard Worker         DRNs.push_back(N);
189*9880d681SAndroid Build Coastguard Worker       DINs.push_back(DFG.addr<InstrNode*>(I));
190*9880d681SAndroid Build Coastguard Worker     } else {
191*9880d681SAndroid Build Coastguard Worker       llvm_unreachable("Unexpected code node");
192*9880d681SAndroid Build Coastguard Worker       return false;
193*9880d681SAndroid Build Coastguard Worker     }
194*9880d681SAndroid Build Coastguard Worker   }
195*9880d681SAndroid Build Coastguard Worker 
196*9880d681SAndroid Build Coastguard Worker   // Sort the list so that use nodes are removed first. This makes the
197*9880d681SAndroid Build Coastguard Worker   // "unlink" functions a bit faster.
198*9880d681SAndroid Build Coastguard Worker   auto UsesFirst = [] (NodeAddr<RefNode*> A, NodeAddr<RefNode*> B) -> bool {
199*9880d681SAndroid Build Coastguard Worker     uint16_t KindA = A.Addr->getKind(), KindB = B.Addr->getKind();
200*9880d681SAndroid Build Coastguard Worker     if (KindA == NodeAttrs::Use && KindB == NodeAttrs::Def)
201*9880d681SAndroid Build Coastguard Worker       return true;
202*9880d681SAndroid Build Coastguard Worker     if (KindA == NodeAttrs::Def && KindB == NodeAttrs::Use)
203*9880d681SAndroid Build Coastguard Worker       return false;
204*9880d681SAndroid Build Coastguard Worker     return A.Id < B.Id;
205*9880d681SAndroid Build Coastguard Worker   };
206*9880d681SAndroid Build Coastguard Worker   std::sort(DRNs.begin(), DRNs.end(), UsesFirst);
207*9880d681SAndroid Build Coastguard Worker 
208*9880d681SAndroid Build Coastguard Worker   if (trace())
209*9880d681SAndroid Build Coastguard Worker     dbgs() << "Removing dead ref nodes:\n";
210*9880d681SAndroid Build Coastguard Worker   for (NodeAddr<RefNode*> RA : DRNs) {
211*9880d681SAndroid Build Coastguard Worker     if (trace())
212*9880d681SAndroid Build Coastguard Worker       dbgs() << "  " << PrintNode<RefNode*>(RA, DFG) << '\n';
213*9880d681SAndroid Build Coastguard Worker     if (DFG.IsUse(RA))
214*9880d681SAndroid Build Coastguard Worker       DFG.unlinkUse(RA, true);
215*9880d681SAndroid Build Coastguard Worker     else if (DFG.IsDef(RA))
216*9880d681SAndroid Build Coastguard Worker       DFG.unlinkDef(RA, true);
217*9880d681SAndroid Build Coastguard Worker   }
218*9880d681SAndroid Build Coastguard Worker 
219*9880d681SAndroid Build Coastguard Worker   // Now, remove all dead instruction nodes.
220*9880d681SAndroid Build Coastguard Worker   for (NodeAddr<InstrNode*> IA : DINs) {
221*9880d681SAndroid Build Coastguard Worker     NodeAddr<BlockNode*> BA = IA.Addr->getOwner(DFG);
222*9880d681SAndroid Build Coastguard Worker     BA.Addr->removeMember(IA, DFG);
223*9880d681SAndroid Build Coastguard Worker     if (!DFG.IsCode<NodeAttrs::Stmt>(IA))
224*9880d681SAndroid Build Coastguard Worker       continue;
225*9880d681SAndroid Build Coastguard Worker 
226*9880d681SAndroid Build Coastguard Worker     MachineInstr *MI = NodeAddr<StmtNode*>(IA).Addr->getCode();
227*9880d681SAndroid Build Coastguard Worker     if (trace())
228*9880d681SAndroid Build Coastguard Worker       dbgs() << "erasing: " << *MI;
229*9880d681SAndroid Build Coastguard Worker     MI->eraseFromParent();
230*9880d681SAndroid Build Coastguard Worker   }
231*9880d681SAndroid Build Coastguard Worker   return true;
232*9880d681SAndroid Build Coastguard Worker }
233