xref: /freebsd-src/contrib/llvm-project/llvm/lib/Analysis/DDG.cpp (revision 480093f4440d54b30b3025afeac24b48f2ba7a2e)
18bcb0991SDimitry Andric //===- DDG.cpp - Data Dependence Graph -------------------------------------==//
28bcb0991SDimitry Andric //
38bcb0991SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
48bcb0991SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
58bcb0991SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
68bcb0991SDimitry Andric //
78bcb0991SDimitry Andric //===----------------------------------------------------------------------===//
88bcb0991SDimitry Andric //
98bcb0991SDimitry Andric // The implementation for the data dependence graph.
108bcb0991SDimitry Andric //===----------------------------------------------------------------------===//
118bcb0991SDimitry Andric #include "llvm/Analysis/DDG.h"
12*480093f4SDimitry Andric #include "llvm/ADT/SCCIterator.h"
138bcb0991SDimitry Andric #include "llvm/Analysis/LoopInfo.h"
14*480093f4SDimitry Andric #include "llvm/Analysis/LoopIterator.h"
15*480093f4SDimitry Andric #include "llvm/Support/CommandLine.h"
168bcb0991SDimitry Andric 
178bcb0991SDimitry Andric using namespace llvm;
188bcb0991SDimitry Andric 
19*480093f4SDimitry Andric static cl::opt<bool>
20*480093f4SDimitry Andric     CreatePiBlocks("ddg-pi-blocks", cl::init(true), cl::Hidden, cl::ZeroOrMore,
21*480093f4SDimitry Andric                    cl::desc("Create pi-block nodes."));
22*480093f4SDimitry Andric 
238bcb0991SDimitry Andric #define DEBUG_TYPE "ddg"
248bcb0991SDimitry Andric 
258bcb0991SDimitry Andric template class llvm::DGEdge<DDGNode, DDGEdge>;
268bcb0991SDimitry Andric template class llvm::DGNode<DDGNode, DDGEdge>;
278bcb0991SDimitry Andric template class llvm::DirectedGraph<DDGNode, DDGEdge>;
288bcb0991SDimitry Andric 
298bcb0991SDimitry Andric //===--------------------------------------------------------------------===//
308bcb0991SDimitry Andric // DDGNode implementation
318bcb0991SDimitry Andric //===--------------------------------------------------------------------===//
328bcb0991SDimitry Andric DDGNode::~DDGNode() {}
338bcb0991SDimitry Andric 
348bcb0991SDimitry Andric bool DDGNode::collectInstructions(
358bcb0991SDimitry Andric     llvm::function_ref<bool(Instruction *)> const &Pred,
368bcb0991SDimitry Andric     InstructionListType &IList) const {
378bcb0991SDimitry Andric   assert(IList.empty() && "Expected the IList to be empty on entry.");
388bcb0991SDimitry Andric   if (isa<SimpleDDGNode>(this)) {
39*480093f4SDimitry Andric     for (Instruction *I : cast<const SimpleDDGNode>(this)->getInstructions())
408bcb0991SDimitry Andric       if (Pred(I))
418bcb0991SDimitry Andric         IList.push_back(I);
42*480093f4SDimitry Andric   } else if (isa<PiBlockDDGNode>(this)) {
43*480093f4SDimitry Andric     for (const DDGNode *PN : cast<const PiBlockDDGNode>(this)->getNodes()) {
44*480093f4SDimitry Andric       assert(!isa<PiBlockDDGNode>(PN) && "Nested PiBlocks are not supported.");
45*480093f4SDimitry Andric       SmallVector<Instruction *, 8> TmpIList;
46*480093f4SDimitry Andric       PN->collectInstructions(Pred, TmpIList);
47*480093f4SDimitry Andric       IList.insert(IList.end(), TmpIList.begin(), TmpIList.end());
48*480093f4SDimitry Andric     }
498bcb0991SDimitry Andric   } else
508bcb0991SDimitry Andric     llvm_unreachable("unimplemented type of node");
518bcb0991SDimitry Andric   return !IList.empty();
528bcb0991SDimitry Andric }
538bcb0991SDimitry Andric 
548bcb0991SDimitry Andric raw_ostream &llvm::operator<<(raw_ostream &OS, const DDGNode::NodeKind K) {
558bcb0991SDimitry Andric   const char *Out;
568bcb0991SDimitry Andric   switch (K) {
578bcb0991SDimitry Andric   case DDGNode::NodeKind::SingleInstruction:
588bcb0991SDimitry Andric     Out = "single-instruction";
598bcb0991SDimitry Andric     break;
608bcb0991SDimitry Andric   case DDGNode::NodeKind::MultiInstruction:
618bcb0991SDimitry Andric     Out = "multi-instruction";
628bcb0991SDimitry Andric     break;
63*480093f4SDimitry Andric   case DDGNode::NodeKind::PiBlock:
64*480093f4SDimitry Andric     Out = "pi-block";
65*480093f4SDimitry Andric     break;
668bcb0991SDimitry Andric   case DDGNode::NodeKind::Root:
678bcb0991SDimitry Andric     Out = "root";
688bcb0991SDimitry Andric     break;
698bcb0991SDimitry Andric   case DDGNode::NodeKind::Unknown:
70*480093f4SDimitry Andric     Out = "?? (error)";
718bcb0991SDimitry Andric     break;
728bcb0991SDimitry Andric   }
738bcb0991SDimitry Andric   OS << Out;
748bcb0991SDimitry Andric   return OS;
758bcb0991SDimitry Andric }
768bcb0991SDimitry Andric 
778bcb0991SDimitry Andric raw_ostream &llvm::operator<<(raw_ostream &OS, const DDGNode &N) {
788bcb0991SDimitry Andric   OS << "Node Address:" << &N << ":" << N.getKind() << "\n";
798bcb0991SDimitry Andric   if (isa<SimpleDDGNode>(N)) {
808bcb0991SDimitry Andric     OS << " Instructions:\n";
81*480093f4SDimitry Andric     for (const Instruction *I : cast<const SimpleDDGNode>(N).getInstructions())
828bcb0991SDimitry Andric       OS.indent(2) << *I << "\n";
83*480093f4SDimitry Andric   } else if (isa<PiBlockDDGNode>(&N)) {
84*480093f4SDimitry Andric     OS << "--- start of nodes in pi-block ---\n";
85*480093f4SDimitry Andric     auto &Nodes = cast<const PiBlockDDGNode>(&N)->getNodes();
86*480093f4SDimitry Andric     unsigned Count = 0;
87*480093f4SDimitry Andric     for (const DDGNode *N : Nodes)
88*480093f4SDimitry Andric       OS << *N << (++Count == Nodes.size() ? "" : "\n");
89*480093f4SDimitry Andric     OS << "--- end of nodes in pi-block ---\n";
908bcb0991SDimitry Andric   } else if (!isa<RootDDGNode>(N))
918bcb0991SDimitry Andric     llvm_unreachable("unimplemented type of node");
928bcb0991SDimitry Andric 
938bcb0991SDimitry Andric   OS << (N.getEdges().empty() ? " Edges:none!\n" : " Edges:\n");
948bcb0991SDimitry Andric   for (auto &E : N.getEdges())
958bcb0991SDimitry Andric     OS.indent(2) << *E;
968bcb0991SDimitry Andric   return OS;
978bcb0991SDimitry Andric }
988bcb0991SDimitry Andric 
998bcb0991SDimitry Andric //===--------------------------------------------------------------------===//
1008bcb0991SDimitry Andric // SimpleDDGNode implementation
1018bcb0991SDimitry Andric //===--------------------------------------------------------------------===//
1028bcb0991SDimitry Andric 
1038bcb0991SDimitry Andric SimpleDDGNode::SimpleDDGNode(Instruction &I)
1048bcb0991SDimitry Andric   : DDGNode(NodeKind::SingleInstruction), InstList() {
1058bcb0991SDimitry Andric   assert(InstList.empty() && "Expected empty list.");
1068bcb0991SDimitry Andric   InstList.push_back(&I);
1078bcb0991SDimitry Andric }
1088bcb0991SDimitry Andric 
1098bcb0991SDimitry Andric SimpleDDGNode::SimpleDDGNode(const SimpleDDGNode &N)
1108bcb0991SDimitry Andric     : DDGNode(N), InstList(N.InstList) {
1118bcb0991SDimitry Andric   assert(((getKind() == NodeKind::SingleInstruction && InstList.size() == 1) ||
1128bcb0991SDimitry Andric           (getKind() == NodeKind::MultiInstruction && InstList.size() > 1)) &&
1138bcb0991SDimitry Andric          "constructing from invalid simple node.");
1148bcb0991SDimitry Andric }
1158bcb0991SDimitry Andric 
1168bcb0991SDimitry Andric SimpleDDGNode::SimpleDDGNode(SimpleDDGNode &&N)
1178bcb0991SDimitry Andric     : DDGNode(std::move(N)), InstList(std::move(N.InstList)) {
1188bcb0991SDimitry Andric   assert(((getKind() == NodeKind::SingleInstruction && InstList.size() == 1) ||
1198bcb0991SDimitry Andric           (getKind() == NodeKind::MultiInstruction && InstList.size() > 1)) &&
1208bcb0991SDimitry Andric          "constructing from invalid simple node.");
1218bcb0991SDimitry Andric }
1228bcb0991SDimitry Andric 
1238bcb0991SDimitry Andric SimpleDDGNode::~SimpleDDGNode() { InstList.clear(); }
1248bcb0991SDimitry Andric 
1258bcb0991SDimitry Andric //===--------------------------------------------------------------------===//
126*480093f4SDimitry Andric // PiBlockDDGNode implementation
127*480093f4SDimitry Andric //===--------------------------------------------------------------------===//
128*480093f4SDimitry Andric 
129*480093f4SDimitry Andric PiBlockDDGNode::PiBlockDDGNode(const PiNodeList &List)
130*480093f4SDimitry Andric     : DDGNode(NodeKind::PiBlock), NodeList(List) {
131*480093f4SDimitry Andric   assert(!NodeList.empty() && "pi-block node constructed with an empty list.");
132*480093f4SDimitry Andric }
133*480093f4SDimitry Andric 
134*480093f4SDimitry Andric PiBlockDDGNode::PiBlockDDGNode(const PiBlockDDGNode &N)
135*480093f4SDimitry Andric     : DDGNode(N), NodeList(N.NodeList) {
136*480093f4SDimitry Andric   assert(getKind() == NodeKind::PiBlock && !NodeList.empty() &&
137*480093f4SDimitry Andric          "constructing from invalid pi-block node.");
138*480093f4SDimitry Andric }
139*480093f4SDimitry Andric 
140*480093f4SDimitry Andric PiBlockDDGNode::PiBlockDDGNode(PiBlockDDGNode &&N)
141*480093f4SDimitry Andric     : DDGNode(std::move(N)), NodeList(std::move(N.NodeList)) {
142*480093f4SDimitry Andric   assert(getKind() == NodeKind::PiBlock && !NodeList.empty() &&
143*480093f4SDimitry Andric          "constructing from invalid pi-block node.");
144*480093f4SDimitry Andric }
145*480093f4SDimitry Andric 
146*480093f4SDimitry Andric PiBlockDDGNode::~PiBlockDDGNode() { NodeList.clear(); }
147*480093f4SDimitry Andric 
148*480093f4SDimitry Andric //===--------------------------------------------------------------------===//
1498bcb0991SDimitry Andric // DDGEdge implementation
1508bcb0991SDimitry Andric //===--------------------------------------------------------------------===//
1518bcb0991SDimitry Andric 
1528bcb0991SDimitry Andric raw_ostream &llvm::operator<<(raw_ostream &OS, const DDGEdge::EdgeKind K) {
1538bcb0991SDimitry Andric   const char *Out;
1548bcb0991SDimitry Andric   switch (K) {
1558bcb0991SDimitry Andric   case DDGEdge::EdgeKind::RegisterDefUse:
1568bcb0991SDimitry Andric     Out = "def-use";
1578bcb0991SDimitry Andric     break;
1588bcb0991SDimitry Andric   case DDGEdge::EdgeKind::MemoryDependence:
1598bcb0991SDimitry Andric     Out = "memory";
1608bcb0991SDimitry Andric     break;
1618bcb0991SDimitry Andric   case DDGEdge::EdgeKind::Rooted:
1628bcb0991SDimitry Andric     Out = "rooted";
1638bcb0991SDimitry Andric     break;
1648bcb0991SDimitry Andric   case DDGEdge::EdgeKind::Unknown:
165*480093f4SDimitry Andric     Out = "?? (error)";
1668bcb0991SDimitry Andric     break;
1678bcb0991SDimitry Andric   }
1688bcb0991SDimitry Andric   OS << Out;
1698bcb0991SDimitry Andric   return OS;
1708bcb0991SDimitry Andric }
1718bcb0991SDimitry Andric 
1728bcb0991SDimitry Andric raw_ostream &llvm::operator<<(raw_ostream &OS, const DDGEdge &E) {
1738bcb0991SDimitry Andric   OS << "[" << E.getKind() << "] to " << &E.getTargetNode() << "\n";
1748bcb0991SDimitry Andric   return OS;
1758bcb0991SDimitry Andric }
1768bcb0991SDimitry Andric 
1778bcb0991SDimitry Andric //===--------------------------------------------------------------------===//
1788bcb0991SDimitry Andric // DataDependenceGraph implementation
1798bcb0991SDimitry Andric //===--------------------------------------------------------------------===//
1808bcb0991SDimitry Andric using BasicBlockListType = SmallVector<BasicBlock *, 8>;
1818bcb0991SDimitry Andric 
1828bcb0991SDimitry Andric DataDependenceGraph::DataDependenceGraph(Function &F, DependenceInfo &D)
1838bcb0991SDimitry Andric     : DependenceGraphInfo(F.getName().str(), D) {
184*480093f4SDimitry Andric   // Put the basic blocks in program order for correct dependence
185*480093f4SDimitry Andric   // directions.
1868bcb0991SDimitry Andric   BasicBlockListType BBList;
187*480093f4SDimitry Andric   for (auto &SCC : make_range(scc_begin(&F), scc_end(&F)))
188*480093f4SDimitry Andric     for (BasicBlock * BB : SCC)
189*480093f4SDimitry Andric       BBList.push_back(BB);
190*480093f4SDimitry Andric   std::reverse(BBList.begin(), BBList.end());
1918bcb0991SDimitry Andric   DDGBuilder(*this, D, BBList).populate();
1928bcb0991SDimitry Andric }
1938bcb0991SDimitry Andric 
194*480093f4SDimitry Andric DataDependenceGraph::DataDependenceGraph(Loop &L, LoopInfo &LI,
195*480093f4SDimitry Andric                                          DependenceInfo &D)
1968bcb0991SDimitry Andric     : DependenceGraphInfo(Twine(L.getHeader()->getParent()->getName() + "." +
1978bcb0991SDimitry Andric                                 L.getHeader()->getName())
1988bcb0991SDimitry Andric                               .str(),
1998bcb0991SDimitry Andric                           D) {
200*480093f4SDimitry Andric   // Put the basic blocks in program order for correct dependence
201*480093f4SDimitry Andric   // directions.
202*480093f4SDimitry Andric   LoopBlocksDFS DFS(&L);
203*480093f4SDimitry Andric   DFS.perform(&LI);
2048bcb0991SDimitry Andric   BasicBlockListType BBList;
205*480093f4SDimitry Andric   for (BasicBlock *BB : make_range(DFS.beginRPO(), DFS.endRPO()))
2068bcb0991SDimitry Andric     BBList.push_back(BB);
2078bcb0991SDimitry Andric   DDGBuilder(*this, D, BBList).populate();
2088bcb0991SDimitry Andric }
2098bcb0991SDimitry Andric 
2108bcb0991SDimitry Andric DataDependenceGraph::~DataDependenceGraph() {
2118bcb0991SDimitry Andric   for (auto *N : Nodes) {
2128bcb0991SDimitry Andric     for (auto *E : *N)
2138bcb0991SDimitry Andric       delete E;
2148bcb0991SDimitry Andric     delete N;
2158bcb0991SDimitry Andric   }
2168bcb0991SDimitry Andric }
2178bcb0991SDimitry Andric 
2188bcb0991SDimitry Andric bool DataDependenceGraph::addNode(DDGNode &N) {
2198bcb0991SDimitry Andric   if (!DDGBase::addNode(N))
2208bcb0991SDimitry Andric     return false;
2218bcb0991SDimitry Andric 
2228bcb0991SDimitry Andric   // In general, if the root node is already created and linked, it is not safe
223*480093f4SDimitry Andric   // to add new nodes since they may be unreachable by the root. However,
224*480093f4SDimitry Andric   // pi-block nodes need to be added after the root node is linked, and they are
225*480093f4SDimitry Andric   // always reachable by the root, because they represent components that are
226*480093f4SDimitry Andric   // already reachable by root.
227*480093f4SDimitry Andric   auto *Pi = dyn_cast<PiBlockDDGNode>(&N);
228*480093f4SDimitry Andric   assert((!Root || Pi) &&
229*480093f4SDimitry Andric          "Root node is already added. No more nodes can be added.");
230*480093f4SDimitry Andric 
2318bcb0991SDimitry Andric   if (isa<RootDDGNode>(N))
2328bcb0991SDimitry Andric     Root = &N;
2338bcb0991SDimitry Andric 
234*480093f4SDimitry Andric   if (Pi)
235*480093f4SDimitry Andric     for (DDGNode *NI : Pi->getNodes())
236*480093f4SDimitry Andric       PiBlockMap.insert(std::make_pair(NI, Pi));
237*480093f4SDimitry Andric 
2388bcb0991SDimitry Andric   return true;
2398bcb0991SDimitry Andric }
2408bcb0991SDimitry Andric 
241*480093f4SDimitry Andric const PiBlockDDGNode *DataDependenceGraph::getPiBlock(const NodeType &N) const {
242*480093f4SDimitry Andric   if (PiBlockMap.find(&N) == PiBlockMap.end())
243*480093f4SDimitry Andric     return nullptr;
244*480093f4SDimitry Andric   auto *Pi = PiBlockMap.find(&N)->second;
245*480093f4SDimitry Andric   assert(PiBlockMap.find(Pi) == PiBlockMap.end() &&
246*480093f4SDimitry Andric          "Nested pi-blocks detected.");
247*480093f4SDimitry Andric   return Pi;
248*480093f4SDimitry Andric }
249*480093f4SDimitry Andric 
2508bcb0991SDimitry Andric raw_ostream &llvm::operator<<(raw_ostream &OS, const DataDependenceGraph &G) {
251*480093f4SDimitry Andric   for (DDGNode *Node : G)
252*480093f4SDimitry Andric     // Avoid printing nodes that are part of a pi-block twice. They will get
253*480093f4SDimitry Andric     // printed when the pi-block is printed.
254*480093f4SDimitry Andric     if (!G.getPiBlock(*Node))
2558bcb0991SDimitry Andric       OS << *Node << "\n";
256*480093f4SDimitry Andric   OS << "\n";
2578bcb0991SDimitry Andric   return OS;
2588bcb0991SDimitry Andric }
2598bcb0991SDimitry Andric 
260*480093f4SDimitry Andric bool DDGBuilder::shouldCreatePiBlocks() const {
261*480093f4SDimitry Andric   return CreatePiBlocks;
262*480093f4SDimitry Andric }
263*480093f4SDimitry Andric 
2648bcb0991SDimitry Andric //===--------------------------------------------------------------------===//
2658bcb0991SDimitry Andric // DDG Analysis Passes
2668bcb0991SDimitry Andric //===--------------------------------------------------------------------===//
2678bcb0991SDimitry Andric 
2688bcb0991SDimitry Andric /// DDG as a loop pass.
2698bcb0991SDimitry Andric DDGAnalysis::Result DDGAnalysis::run(Loop &L, LoopAnalysisManager &AM,
2708bcb0991SDimitry Andric                                      LoopStandardAnalysisResults &AR) {
2718bcb0991SDimitry Andric   Function *F = L.getHeader()->getParent();
2728bcb0991SDimitry Andric   DependenceInfo DI(F, &AR.AA, &AR.SE, &AR.LI);
273*480093f4SDimitry Andric   return std::make_unique<DataDependenceGraph>(L, AR.LI, DI);
2748bcb0991SDimitry Andric }
2758bcb0991SDimitry Andric AnalysisKey DDGAnalysis::Key;
2768bcb0991SDimitry Andric 
2778bcb0991SDimitry Andric PreservedAnalyses DDGAnalysisPrinterPass::run(Loop &L, LoopAnalysisManager &AM,
2788bcb0991SDimitry Andric                                               LoopStandardAnalysisResults &AR,
2798bcb0991SDimitry Andric                                               LPMUpdater &U) {
2808bcb0991SDimitry Andric   OS << "'DDG' for loop '" << L.getHeader()->getName() << "':\n";
2818bcb0991SDimitry Andric   OS << *AM.getResult<DDGAnalysis>(L, AR);
2828bcb0991SDimitry Andric   return PreservedAnalyses::all();
2838bcb0991SDimitry Andric }
284