16f4000e7SKrzysztof Parzyszek //===--- RDFDeadCode.cpp --------------------------------------------------===//
26f4000e7SKrzysztof Parzyszek //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66f4000e7SKrzysztof Parzyszek //
76f4000e7SKrzysztof Parzyszek //===----------------------------------------------------------------------===//
86f4000e7SKrzysztof Parzyszek //
96f4000e7SKrzysztof Parzyszek // RDF-based generic dead code elimination.
106f4000e7SKrzysztof Parzyszek 
116bda14b3SChandler Carruth #include "RDFDeadCode.h"
126f4000e7SKrzysztof Parzyszek 
136f4000e7SKrzysztof Parzyszek #include "llvm/ADT/SetVector.h"
146f4000e7SKrzysztof Parzyszek #include "llvm/CodeGen/MachineBasicBlock.h"
156f4000e7SKrzysztof Parzyszek #include "llvm/CodeGen/MachineFunction.h"
166f4000e7SKrzysztof Parzyszek #include "llvm/CodeGen/MachineRegisterInfo.h"
17080dd10fSScott Constable #include "llvm/CodeGen/RDFGraph.h"
18080dd10fSScott Constable #include "llvm/CodeGen/RDFLiveness.h"
191d7b4136SReid Kleckner #include "llvm/Support/Debug.h"
206f4000e7SKrzysztof Parzyszek 
21e6b06620SKrzysztof Parzyszek #include <queue>
22e6b06620SKrzysztof Parzyszek 
236f4000e7SKrzysztof Parzyszek using namespace llvm;
246f4000e7SKrzysztof Parzyszek using namespace rdf;
256f4000e7SKrzysztof Parzyszek 
26e6b06620SKrzysztof Parzyszek // This drastically improves execution time in "collect" over using
27e6b06620SKrzysztof Parzyszek // SetVector as a work queue, and popping the first element from it.
28e6b06620SKrzysztof Parzyszek template<typename T> struct DeadCodeElimination::SetQueue {
SetQueueDeadCodeElimination::SetQueue29e6b06620SKrzysztof Parzyszek   SetQueue() : Set(), Queue() {}
30e6b06620SKrzysztof Parzyszek 
emptyDeadCodeElimination::SetQueue31e6b06620SKrzysztof Parzyszek   bool empty() const {
32e6b06620SKrzysztof Parzyszek     return Queue.empty();
33e6b06620SKrzysztof Parzyszek   }
pop_frontDeadCodeElimination::SetQueue34e6b06620SKrzysztof Parzyszek   T pop_front() {
35e6b06620SKrzysztof Parzyszek     T V = Queue.front();
36e6b06620SKrzysztof Parzyszek     Queue.pop();
37e6b06620SKrzysztof Parzyszek     Set.erase(V);
38e6b06620SKrzysztof Parzyszek     return V;
39e6b06620SKrzysztof Parzyszek   }
push_backDeadCodeElimination::SetQueue40e6b06620SKrzysztof Parzyszek   void push_back(T V) {
41e6b06620SKrzysztof Parzyszek     if (Set.count(V))
42e6b06620SKrzysztof Parzyszek       return;
43e6b06620SKrzysztof Parzyszek     Queue.push(V);
44e6b06620SKrzysztof Parzyszek     Set.insert(V);
45e6b06620SKrzysztof Parzyszek   }
46e6b06620SKrzysztof Parzyszek 
47e6b06620SKrzysztof Parzyszek private:
48e6b06620SKrzysztof Parzyszek   DenseSet<T> Set;
49e6b06620SKrzysztof Parzyszek   std::queue<T> Queue;
50e6b06620SKrzysztof Parzyszek };
51e6b06620SKrzysztof Parzyszek 
52e6b06620SKrzysztof Parzyszek 
536f4000e7SKrzysztof Parzyszek // Check if the given instruction has observable side-effects, i.e. if
546f4000e7SKrzysztof Parzyszek // it should be considered "live". It is safe for this function to be
556f4000e7SKrzysztof Parzyszek // overly conservative (i.e. return "true" for all instructions), but it
566f4000e7SKrzysztof Parzyszek // is not safe to return "false" for an instruction that should not be
576f4000e7SKrzysztof Parzyszek // considered removable.
isLiveInstr(const MachineInstr * MI) const586f4000e7SKrzysztof Parzyszek bool DeadCodeElimination::isLiveInstr(const MachineInstr *MI) const {
596f4000e7SKrzysztof Parzyszek   if (MI->mayStore() || MI->isBranch() || MI->isCall() || MI->isReturn())
606f4000e7SKrzysztof Parzyszek     return true;
61fc0a1812SKrzysztof Parzyszek   if (MI->hasOrderedMemoryRef() || MI->hasUnmodeledSideEffects() ||
62fc0a1812SKrzysztof Parzyszek       MI->isPosition())
636f4000e7SKrzysztof Parzyszek     return true;
646f4000e7SKrzysztof Parzyszek   if (MI->isPHI())
656f4000e7SKrzysztof Parzyszek     return false;
661aaf41afSKrzysztof Parzyszek   for (auto &Op : MI->operands()) {
676f4000e7SKrzysztof Parzyszek     if (Op.isReg() && MRI.isReserved(Op.getReg()))
686f4000e7SKrzysztof Parzyszek       return true;
691aaf41afSKrzysztof Parzyszek     if (Op.isRegMask()) {
701aaf41afSKrzysztof Parzyszek       const uint32_t *BM = Op.getRegMask();
711aaf41afSKrzysztof Parzyszek       for (unsigned R = 0, RN = DFG.getTRI().getNumRegs(); R != RN; ++R) {
721aaf41afSKrzysztof Parzyszek         if (BM[R/32] & (1u << (R%32)))
731aaf41afSKrzysztof Parzyszek           continue;
741aaf41afSKrzysztof Parzyszek         if (MRI.isReserved(R))
751aaf41afSKrzysztof Parzyszek           return true;
761aaf41afSKrzysztof Parzyszek       }
771aaf41afSKrzysztof Parzyszek     }
781aaf41afSKrzysztof Parzyszek   }
796f4000e7SKrzysztof Parzyszek   return false;
806f4000e7SKrzysztof Parzyszek }
816f4000e7SKrzysztof Parzyszek 
scanInstr(NodeAddr<InstrNode * > IA,SetQueue<NodeId> & WorkQ)826f4000e7SKrzysztof Parzyszek void DeadCodeElimination::scanInstr(NodeAddr<InstrNode*> IA,
83e6b06620SKrzysztof Parzyszek       SetQueue<NodeId> &WorkQ) {
846f4000e7SKrzysztof Parzyszek   if (!DFG.IsCode<NodeAttrs::Stmt>(IA))
856f4000e7SKrzysztof Parzyszek     return;
866f4000e7SKrzysztof Parzyszek   if (!isLiveInstr(NodeAddr<StmtNode*>(IA).Addr->getCode()))
876f4000e7SKrzysztof Parzyszek     return;
886f4000e7SKrzysztof Parzyszek   for (NodeAddr<RefNode*> RA : IA.Addr->members(DFG)) {
896f4000e7SKrzysztof Parzyszek     if (!LiveNodes.count(RA.Id))
90e6b06620SKrzysztof Parzyszek       WorkQ.push_back(RA.Id);
916f4000e7SKrzysztof Parzyszek   }
926f4000e7SKrzysztof Parzyszek }
936f4000e7SKrzysztof Parzyszek 
processDef(NodeAddr<DefNode * > DA,SetQueue<NodeId> & WorkQ)946f4000e7SKrzysztof Parzyszek void DeadCodeElimination::processDef(NodeAddr<DefNode*> DA,
95e6b06620SKrzysztof Parzyszek       SetQueue<NodeId> &WorkQ) {
966f4000e7SKrzysztof Parzyszek   NodeAddr<InstrNode*> IA = DA.Addr->getOwner(DFG);
976f4000e7SKrzysztof Parzyszek   for (NodeAddr<UseNode*> UA : IA.Addr->members_if(DFG.IsUse, DFG)) {
986f4000e7SKrzysztof Parzyszek     if (!LiveNodes.count(UA.Id))
99e6b06620SKrzysztof Parzyszek       WorkQ.push_back(UA.Id);
1006f4000e7SKrzysztof Parzyszek   }
1016f4000e7SKrzysztof Parzyszek   for (NodeAddr<DefNode*> TA : DFG.getRelatedRefs(IA, DA))
1026f4000e7SKrzysztof Parzyszek     LiveNodes.insert(TA.Id);
1036f4000e7SKrzysztof Parzyszek }
1046f4000e7SKrzysztof Parzyszek 
processUse(NodeAddr<UseNode * > UA,SetQueue<NodeId> & WorkQ)1056f4000e7SKrzysztof Parzyszek void DeadCodeElimination::processUse(NodeAddr<UseNode*> UA,
106e6b06620SKrzysztof Parzyszek       SetQueue<NodeId> &WorkQ) {
1076f4000e7SKrzysztof Parzyszek   for (NodeAddr<DefNode*> DA : LV.getAllReachingDefs(UA)) {
1086f4000e7SKrzysztof Parzyszek     if (!LiveNodes.count(DA.Id))
109e6b06620SKrzysztof Parzyszek       WorkQ.push_back(DA.Id);
1106f4000e7SKrzysztof Parzyszek   }
1116f4000e7SKrzysztof Parzyszek }
1126f4000e7SKrzysztof Parzyszek 
1136f4000e7SKrzysztof Parzyszek // Traverse the DFG and collect the set dead RefNodes and the set of
1146f4000e7SKrzysztof Parzyszek // dead instructions. Return "true" if any of these sets is non-empty,
1156f4000e7SKrzysztof Parzyszek // "false" otherwise.
collect()1166f4000e7SKrzysztof Parzyszek bool DeadCodeElimination::collect() {
1176f4000e7SKrzysztof Parzyszek   // This function works by first finding all live nodes. The dead nodes
1186f4000e7SKrzysztof Parzyszek   // are then the complement of the set of live nodes.
1196f4000e7SKrzysztof Parzyszek   //
1206f4000e7SKrzysztof Parzyszek   // Assume that all nodes are dead. Identify instructions which must be
1216f4000e7SKrzysztof Parzyszek   // considered live, i.e. instructions with observable side-effects, such
1226f4000e7SKrzysztof Parzyszek   // as calls and stores. All arguments of such instructions are considered
1236f4000e7SKrzysztof Parzyszek   // live. For each live def, all operands used in the corresponding
1246f4000e7SKrzysztof Parzyszek   // instruction are considered live. For each live use, all its reaching
1256f4000e7SKrzysztof Parzyszek   // defs are considered live.
1266f4000e7SKrzysztof Parzyszek   LiveNodes.clear();
127e6b06620SKrzysztof Parzyszek   SetQueue<NodeId> WorkQ;
1286f4000e7SKrzysztof Parzyszek   for (NodeAddr<BlockNode*> BA : DFG.getFunc().Addr->members(DFG))
1296f4000e7SKrzysztof Parzyszek     for (NodeAddr<InstrNode*> IA : BA.Addr->members(DFG))
1306f4000e7SKrzysztof Parzyszek       scanInstr(IA, WorkQ);
1316f4000e7SKrzysztof Parzyszek 
1326f4000e7SKrzysztof Parzyszek   while (!WorkQ.empty()) {
133e6b06620SKrzysztof Parzyszek     NodeId N = WorkQ.pop_front();
1346f4000e7SKrzysztof Parzyszek     LiveNodes.insert(N);
1356f4000e7SKrzysztof Parzyszek     auto RA = DFG.addr<RefNode*>(N);
1366f4000e7SKrzysztof Parzyszek     if (DFG.IsDef(RA))
1376f4000e7SKrzysztof Parzyszek       processDef(RA, WorkQ);
1386f4000e7SKrzysztof Parzyszek     else
1396f4000e7SKrzysztof Parzyszek       processUse(RA, WorkQ);
1406f4000e7SKrzysztof Parzyszek   }
1416f4000e7SKrzysztof Parzyszek 
1426f4000e7SKrzysztof Parzyszek   if (trace()) {
1436f4000e7SKrzysztof Parzyszek     dbgs() << "Live nodes:\n";
1446f4000e7SKrzysztof Parzyszek     for (NodeId N : LiveNodes) {
1456f4000e7SKrzysztof Parzyszek       auto RA = DFG.addr<RefNode*>(N);
1466f4000e7SKrzysztof Parzyszek       dbgs() << PrintNode<RefNode*>(RA, DFG) << "\n";
1476f4000e7SKrzysztof Parzyszek     }
1486f4000e7SKrzysztof Parzyszek   }
1496f4000e7SKrzysztof Parzyszek 
1506f4000e7SKrzysztof Parzyszek   auto IsDead = [this] (NodeAddr<InstrNode*> IA) -> bool {
1516f4000e7SKrzysztof Parzyszek     for (NodeAddr<DefNode*> DA : IA.Addr->members_if(DFG.IsDef, DFG))
1526f4000e7SKrzysztof Parzyszek       if (LiveNodes.count(DA.Id))
1536f4000e7SKrzysztof Parzyszek         return false;
1546f4000e7SKrzysztof Parzyszek     return true;
1556f4000e7SKrzysztof Parzyszek   };
1566f4000e7SKrzysztof Parzyszek 
1576f4000e7SKrzysztof Parzyszek   for (NodeAddr<BlockNode*> BA : DFG.getFunc().Addr->members(DFG)) {
1586f4000e7SKrzysztof Parzyszek     for (NodeAddr<InstrNode*> IA : BA.Addr->members(DFG)) {
1596f4000e7SKrzysztof Parzyszek       for (NodeAddr<RefNode*> RA : IA.Addr->members(DFG))
1606f4000e7SKrzysztof Parzyszek         if (!LiveNodes.count(RA.Id))
1616f4000e7SKrzysztof Parzyszek           DeadNodes.insert(RA.Id);
1626f4000e7SKrzysztof Parzyszek       if (DFG.IsCode<NodeAttrs::Stmt>(IA))
1636f4000e7SKrzysztof Parzyszek         if (isLiveInstr(NodeAddr<StmtNode*>(IA).Addr->getCode()))
1646f4000e7SKrzysztof Parzyszek           continue;
1656f4000e7SKrzysztof Parzyszek       if (IsDead(IA)) {
1666f4000e7SKrzysztof Parzyszek         DeadInstrs.insert(IA.Id);
1676f4000e7SKrzysztof Parzyszek         if (trace())
1686f4000e7SKrzysztof Parzyszek           dbgs() << "Dead instr: " << PrintNode<InstrNode*>(IA, DFG) << "\n";
1696f4000e7SKrzysztof Parzyszek       }
1706f4000e7SKrzysztof Parzyszek     }
1716f4000e7SKrzysztof Parzyszek   }
1726f4000e7SKrzysztof Parzyszek 
1736f4000e7SKrzysztof Parzyszek   return !DeadNodes.empty();
1746f4000e7SKrzysztof Parzyszek }
1756f4000e7SKrzysztof Parzyszek 
1766f4000e7SKrzysztof Parzyszek // Erase the nodes given in the Nodes set from DFG. In addition to removing
1776f4000e7SKrzysztof Parzyszek // them from the DFG, if a node corresponds to a statement, the corresponding
1786f4000e7SKrzysztof Parzyszek // machine instruction is erased from the function.
erase(const SetVector<NodeId> & Nodes)1796f4000e7SKrzysztof Parzyszek bool DeadCodeElimination::erase(const SetVector<NodeId> &Nodes) {
1806f4000e7SKrzysztof Parzyszek   if (Nodes.empty())
1816f4000e7SKrzysztof Parzyszek     return false;
1826f4000e7SKrzysztof Parzyszek 
1836f4000e7SKrzysztof Parzyszek   // Prepare the actual set of ref nodes to remove: ref nodes from Nodes
1846f4000e7SKrzysztof Parzyszek   // are included directly, for each InstrNode in Nodes, include the set
1856f4000e7SKrzysztof Parzyszek   // of all RefNodes from it.
1866f4000e7SKrzysztof Parzyszek   NodeList DRNs, DINs;
1876f4000e7SKrzysztof Parzyszek   for (auto I : Nodes) {
1886f4000e7SKrzysztof Parzyszek     auto BA = DFG.addr<NodeBase*>(I);
1896f4000e7SKrzysztof Parzyszek     uint16_t Type = BA.Addr->getType();
1906f4000e7SKrzysztof Parzyszek     if (Type == NodeAttrs::Ref) {
1916f4000e7SKrzysztof Parzyszek       DRNs.push_back(DFG.addr<RefNode*>(I));
1926f4000e7SKrzysztof Parzyszek       continue;
1936f4000e7SKrzysztof Parzyszek     }
1946f4000e7SKrzysztof Parzyszek 
1956f4000e7SKrzysztof Parzyszek     // If it's a code node, add all ref nodes from it.
1966f4000e7SKrzysztof Parzyszek     uint16_t Kind = BA.Addr->getKind();
1976f4000e7SKrzysztof Parzyszek     if (Kind == NodeAttrs::Stmt || Kind == NodeAttrs::Phi) {
198*05444417SKazu Hirata       append_range(DRNs, NodeAddr<CodeNode*>(BA).Addr->members(DFG));
1996f4000e7SKrzysztof Parzyszek       DINs.push_back(DFG.addr<InstrNode*>(I));
2006f4000e7SKrzysztof Parzyszek     } else {
2016f4000e7SKrzysztof Parzyszek       llvm_unreachable("Unexpected code node");
2026f4000e7SKrzysztof Parzyszek       return false;
2036f4000e7SKrzysztof Parzyszek     }
2046f4000e7SKrzysztof Parzyszek   }
2056f4000e7SKrzysztof Parzyszek 
2066f4000e7SKrzysztof Parzyszek   // Sort the list so that use nodes are removed first. This makes the
2076f4000e7SKrzysztof Parzyszek   // "unlink" functions a bit faster.
2086f4000e7SKrzysztof Parzyszek   auto UsesFirst = [] (NodeAddr<RefNode*> A, NodeAddr<RefNode*> B) -> bool {
2096f4000e7SKrzysztof Parzyszek     uint16_t KindA = A.Addr->getKind(), KindB = B.Addr->getKind();
2106f4000e7SKrzysztof Parzyszek     if (KindA == NodeAttrs::Use && KindB == NodeAttrs::Def)
2116f4000e7SKrzysztof Parzyszek       return true;
2126f4000e7SKrzysztof Parzyszek     if (KindA == NodeAttrs::Def && KindB == NodeAttrs::Use)
2136f4000e7SKrzysztof Parzyszek       return false;
2146f4000e7SKrzysztof Parzyszek     return A.Id < B.Id;
2156f4000e7SKrzysztof Parzyszek   };
2160cac726aSFangrui Song   llvm::sort(DRNs, UsesFirst);
2176f4000e7SKrzysztof Parzyszek 
2186f4000e7SKrzysztof Parzyszek   if (trace())
2196f4000e7SKrzysztof Parzyszek     dbgs() << "Removing dead ref nodes:\n";
2206f4000e7SKrzysztof Parzyszek   for (NodeAddr<RefNode*> RA : DRNs) {
2216f4000e7SKrzysztof Parzyszek     if (trace())
2226f4000e7SKrzysztof Parzyszek       dbgs() << "  " << PrintNode<RefNode*>(RA, DFG) << '\n';
2236f4000e7SKrzysztof Parzyszek     if (DFG.IsUse(RA))
22469e670d5SKrzysztof Parzyszek       DFG.unlinkUse(RA, true);
2256f4000e7SKrzysztof Parzyszek     else if (DFG.IsDef(RA))
22669e670d5SKrzysztof Parzyszek       DFG.unlinkDef(RA, true);
2276f4000e7SKrzysztof Parzyszek   }
2286f4000e7SKrzysztof Parzyszek 
2296f4000e7SKrzysztof Parzyszek   // Now, remove all dead instruction nodes.
2306f4000e7SKrzysztof Parzyszek   for (NodeAddr<InstrNode*> IA : DINs) {
2316f4000e7SKrzysztof Parzyszek     NodeAddr<BlockNode*> BA = IA.Addr->getOwner(DFG);
2326f4000e7SKrzysztof Parzyszek     BA.Addr->removeMember(IA, DFG);
2336f4000e7SKrzysztof Parzyszek     if (!DFG.IsCode<NodeAttrs::Stmt>(IA))
2346f4000e7SKrzysztof Parzyszek       continue;
2356f4000e7SKrzysztof Parzyszek 
2366f4000e7SKrzysztof Parzyszek     MachineInstr *MI = NodeAddr<StmtNode*>(IA).Addr->getCode();
2376f4000e7SKrzysztof Parzyszek     if (trace())
2386f4000e7SKrzysztof Parzyszek       dbgs() << "erasing: " << *MI;
2396f4000e7SKrzysztof Parzyszek     MI->eraseFromParent();
2406f4000e7SKrzysztof Parzyszek   }
2416f4000e7SKrzysztof Parzyszek   return true;
2426f4000e7SKrzysztof Parzyszek }
243