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" 12480093f4SDimitry Andric #include "llvm/ADT/SCCIterator.h" 138bcb0991SDimitry Andric #include "llvm/Analysis/LoopInfo.h" 14480093f4SDimitry Andric #include "llvm/Analysis/LoopIterator.h" 15480093f4SDimitry Andric #include "llvm/Support/CommandLine.h" 168bcb0991SDimitry Andric 178bcb0991SDimitry Andric using namespace llvm; 188bcb0991SDimitry Andric 195ffd83dbSDimitry Andric static cl::opt<bool> SimplifyDDG( 20*81ad6265SDimitry Andric "ddg-simplify", cl::init(true), cl::Hidden, 215ffd83dbSDimitry Andric cl::desc( 225ffd83dbSDimitry Andric "Simplify DDG by merging nodes that have less interesting edges.")); 235ffd83dbSDimitry Andric 24*81ad6265SDimitry Andric static cl::opt<bool> CreatePiBlocks("ddg-pi-blocks", cl::init(true), cl::Hidden, 25480093f4SDimitry Andric cl::desc("Create pi-block nodes.")); 26480093f4SDimitry Andric 278bcb0991SDimitry Andric #define DEBUG_TYPE "ddg" 288bcb0991SDimitry Andric 298bcb0991SDimitry Andric template class llvm::DGEdge<DDGNode, DDGEdge>; 308bcb0991SDimitry Andric template class llvm::DGNode<DDGNode, DDGEdge>; 318bcb0991SDimitry Andric template class llvm::DirectedGraph<DDGNode, DDGEdge>; 328bcb0991SDimitry Andric 338bcb0991SDimitry Andric //===--------------------------------------------------------------------===// 348bcb0991SDimitry Andric // DDGNode implementation 358bcb0991SDimitry Andric //===--------------------------------------------------------------------===// 36*81ad6265SDimitry Andric DDGNode::~DDGNode() = default; 378bcb0991SDimitry Andric 388bcb0991SDimitry Andric bool DDGNode::collectInstructions( 398bcb0991SDimitry Andric llvm::function_ref<bool(Instruction *)> const &Pred, 408bcb0991SDimitry Andric InstructionListType &IList) const { 418bcb0991SDimitry Andric assert(IList.empty() && "Expected the IList to be empty on entry."); 428bcb0991SDimitry Andric if (isa<SimpleDDGNode>(this)) { 43480093f4SDimitry Andric for (Instruction *I : cast<const SimpleDDGNode>(this)->getInstructions()) 448bcb0991SDimitry Andric if (Pred(I)) 458bcb0991SDimitry Andric IList.push_back(I); 46480093f4SDimitry Andric } else if (isa<PiBlockDDGNode>(this)) { 47480093f4SDimitry Andric for (const DDGNode *PN : cast<const PiBlockDDGNode>(this)->getNodes()) { 48480093f4SDimitry Andric assert(!isa<PiBlockDDGNode>(PN) && "Nested PiBlocks are not supported."); 49480093f4SDimitry Andric SmallVector<Instruction *, 8> TmpIList; 50480093f4SDimitry Andric PN->collectInstructions(Pred, TmpIList); 51e8d8bef9SDimitry Andric llvm::append_range(IList, TmpIList); 52480093f4SDimitry Andric } 538bcb0991SDimitry Andric } else 548bcb0991SDimitry Andric llvm_unreachable("unimplemented type of node"); 558bcb0991SDimitry Andric return !IList.empty(); 568bcb0991SDimitry Andric } 578bcb0991SDimitry Andric 588bcb0991SDimitry Andric raw_ostream &llvm::operator<<(raw_ostream &OS, const DDGNode::NodeKind K) { 598bcb0991SDimitry Andric const char *Out; 608bcb0991SDimitry Andric switch (K) { 618bcb0991SDimitry Andric case DDGNode::NodeKind::SingleInstruction: 628bcb0991SDimitry Andric Out = "single-instruction"; 638bcb0991SDimitry Andric break; 648bcb0991SDimitry Andric case DDGNode::NodeKind::MultiInstruction: 658bcb0991SDimitry Andric Out = "multi-instruction"; 668bcb0991SDimitry Andric break; 67480093f4SDimitry Andric case DDGNode::NodeKind::PiBlock: 68480093f4SDimitry Andric Out = "pi-block"; 69480093f4SDimitry Andric break; 708bcb0991SDimitry Andric case DDGNode::NodeKind::Root: 718bcb0991SDimitry Andric Out = "root"; 728bcb0991SDimitry Andric break; 738bcb0991SDimitry Andric case DDGNode::NodeKind::Unknown: 74480093f4SDimitry Andric Out = "?? (error)"; 758bcb0991SDimitry Andric break; 768bcb0991SDimitry Andric } 778bcb0991SDimitry Andric OS << Out; 788bcb0991SDimitry Andric return OS; 798bcb0991SDimitry Andric } 808bcb0991SDimitry Andric 818bcb0991SDimitry Andric raw_ostream &llvm::operator<<(raw_ostream &OS, const DDGNode &N) { 828bcb0991SDimitry Andric OS << "Node Address:" << &N << ":" << N.getKind() << "\n"; 838bcb0991SDimitry Andric if (isa<SimpleDDGNode>(N)) { 848bcb0991SDimitry Andric OS << " Instructions:\n"; 85480093f4SDimitry Andric for (const Instruction *I : cast<const SimpleDDGNode>(N).getInstructions()) 868bcb0991SDimitry Andric OS.indent(2) << *I << "\n"; 87480093f4SDimitry Andric } else if (isa<PiBlockDDGNode>(&N)) { 88480093f4SDimitry Andric OS << "--- start of nodes in pi-block ---\n"; 89480093f4SDimitry Andric auto &Nodes = cast<const PiBlockDDGNode>(&N)->getNodes(); 90480093f4SDimitry Andric unsigned Count = 0; 91480093f4SDimitry Andric for (const DDGNode *N : Nodes) 92480093f4SDimitry Andric OS << *N << (++Count == Nodes.size() ? "" : "\n"); 93480093f4SDimitry Andric OS << "--- end of nodes in pi-block ---\n"; 948bcb0991SDimitry Andric } else if (!isa<RootDDGNode>(N)) 958bcb0991SDimitry Andric llvm_unreachable("unimplemented type of node"); 968bcb0991SDimitry Andric 978bcb0991SDimitry Andric OS << (N.getEdges().empty() ? " Edges:none!\n" : " Edges:\n"); 988bcb0991SDimitry Andric for (auto &E : N.getEdges()) 998bcb0991SDimitry Andric OS.indent(2) << *E; 1008bcb0991SDimitry Andric return OS; 1018bcb0991SDimitry Andric } 1028bcb0991SDimitry Andric 1038bcb0991SDimitry Andric //===--------------------------------------------------------------------===// 1048bcb0991SDimitry Andric // SimpleDDGNode implementation 1058bcb0991SDimitry Andric //===--------------------------------------------------------------------===// 1068bcb0991SDimitry Andric 1078bcb0991SDimitry Andric SimpleDDGNode::SimpleDDGNode(Instruction &I) 10804eeddc0SDimitry Andric : DDGNode(NodeKind::SingleInstruction) { 1098bcb0991SDimitry Andric assert(InstList.empty() && "Expected empty list."); 1108bcb0991SDimitry Andric InstList.push_back(&I); 1118bcb0991SDimitry Andric } 1128bcb0991SDimitry Andric 1138bcb0991SDimitry Andric SimpleDDGNode::SimpleDDGNode(const SimpleDDGNode &N) 1148bcb0991SDimitry Andric : DDGNode(N), InstList(N.InstList) { 1158bcb0991SDimitry Andric assert(((getKind() == NodeKind::SingleInstruction && InstList.size() == 1) || 1168bcb0991SDimitry Andric (getKind() == NodeKind::MultiInstruction && InstList.size() > 1)) && 1178bcb0991SDimitry Andric "constructing from invalid simple node."); 1188bcb0991SDimitry Andric } 1198bcb0991SDimitry Andric 1208bcb0991SDimitry Andric SimpleDDGNode::SimpleDDGNode(SimpleDDGNode &&N) 1218bcb0991SDimitry Andric : DDGNode(std::move(N)), InstList(std::move(N.InstList)) { 1228bcb0991SDimitry Andric assert(((getKind() == NodeKind::SingleInstruction && InstList.size() == 1) || 1238bcb0991SDimitry Andric (getKind() == NodeKind::MultiInstruction && InstList.size() > 1)) && 1248bcb0991SDimitry Andric "constructing from invalid simple node."); 1258bcb0991SDimitry Andric } 1268bcb0991SDimitry Andric 1278bcb0991SDimitry Andric SimpleDDGNode::~SimpleDDGNode() { InstList.clear(); } 1288bcb0991SDimitry Andric 1298bcb0991SDimitry Andric //===--------------------------------------------------------------------===// 130480093f4SDimitry Andric // PiBlockDDGNode implementation 131480093f4SDimitry Andric //===--------------------------------------------------------------------===// 132480093f4SDimitry Andric 133480093f4SDimitry Andric PiBlockDDGNode::PiBlockDDGNode(const PiNodeList &List) 134480093f4SDimitry Andric : DDGNode(NodeKind::PiBlock), NodeList(List) { 135480093f4SDimitry Andric assert(!NodeList.empty() && "pi-block node constructed with an empty list."); 136480093f4SDimitry Andric } 137480093f4SDimitry Andric 138480093f4SDimitry Andric PiBlockDDGNode::PiBlockDDGNode(const PiBlockDDGNode &N) 139480093f4SDimitry Andric : DDGNode(N), NodeList(N.NodeList) { 140480093f4SDimitry Andric assert(getKind() == NodeKind::PiBlock && !NodeList.empty() && 141480093f4SDimitry Andric "constructing from invalid pi-block node."); 142480093f4SDimitry Andric } 143480093f4SDimitry Andric 144480093f4SDimitry Andric PiBlockDDGNode::PiBlockDDGNode(PiBlockDDGNode &&N) 145480093f4SDimitry Andric : DDGNode(std::move(N)), NodeList(std::move(N.NodeList)) { 146480093f4SDimitry Andric assert(getKind() == NodeKind::PiBlock && !NodeList.empty() && 147480093f4SDimitry Andric "constructing from invalid pi-block node."); 148480093f4SDimitry Andric } 149480093f4SDimitry Andric 150480093f4SDimitry Andric PiBlockDDGNode::~PiBlockDDGNode() { NodeList.clear(); } 151480093f4SDimitry Andric 152480093f4SDimitry Andric //===--------------------------------------------------------------------===// 1538bcb0991SDimitry Andric // DDGEdge implementation 1548bcb0991SDimitry Andric //===--------------------------------------------------------------------===// 1558bcb0991SDimitry Andric 1568bcb0991SDimitry Andric raw_ostream &llvm::operator<<(raw_ostream &OS, const DDGEdge::EdgeKind K) { 1578bcb0991SDimitry Andric const char *Out; 1588bcb0991SDimitry Andric switch (K) { 1598bcb0991SDimitry Andric case DDGEdge::EdgeKind::RegisterDefUse: 1608bcb0991SDimitry Andric Out = "def-use"; 1618bcb0991SDimitry Andric break; 1628bcb0991SDimitry Andric case DDGEdge::EdgeKind::MemoryDependence: 1638bcb0991SDimitry Andric Out = "memory"; 1648bcb0991SDimitry Andric break; 1658bcb0991SDimitry Andric case DDGEdge::EdgeKind::Rooted: 1668bcb0991SDimitry Andric Out = "rooted"; 1678bcb0991SDimitry Andric break; 1688bcb0991SDimitry Andric case DDGEdge::EdgeKind::Unknown: 169480093f4SDimitry Andric Out = "?? (error)"; 1708bcb0991SDimitry Andric break; 1718bcb0991SDimitry Andric } 1728bcb0991SDimitry Andric OS << Out; 1738bcb0991SDimitry Andric return OS; 1748bcb0991SDimitry Andric } 1758bcb0991SDimitry Andric 1768bcb0991SDimitry Andric raw_ostream &llvm::operator<<(raw_ostream &OS, const DDGEdge &E) { 1778bcb0991SDimitry Andric OS << "[" << E.getKind() << "] to " << &E.getTargetNode() << "\n"; 1788bcb0991SDimitry Andric return OS; 1798bcb0991SDimitry Andric } 1808bcb0991SDimitry Andric 1818bcb0991SDimitry Andric //===--------------------------------------------------------------------===// 1828bcb0991SDimitry Andric // DataDependenceGraph implementation 1838bcb0991SDimitry Andric //===--------------------------------------------------------------------===// 1848bcb0991SDimitry Andric using BasicBlockListType = SmallVector<BasicBlock *, 8>; 1858bcb0991SDimitry Andric 1868bcb0991SDimitry Andric DataDependenceGraph::DataDependenceGraph(Function &F, DependenceInfo &D) 1878bcb0991SDimitry Andric : DependenceGraphInfo(F.getName().str(), D) { 188480093f4SDimitry Andric // Put the basic blocks in program order for correct dependence 189480093f4SDimitry Andric // directions. 1908bcb0991SDimitry Andric BasicBlockListType BBList; 191480093f4SDimitry Andric for (auto &SCC : make_range(scc_begin(&F), scc_end(&F))) 192e8d8bef9SDimitry Andric append_range(BBList, SCC); 193480093f4SDimitry Andric std::reverse(BBList.begin(), BBList.end()); 1948bcb0991SDimitry Andric DDGBuilder(*this, D, BBList).populate(); 1958bcb0991SDimitry Andric } 1968bcb0991SDimitry Andric 197480093f4SDimitry Andric DataDependenceGraph::DataDependenceGraph(Loop &L, LoopInfo &LI, 198480093f4SDimitry Andric DependenceInfo &D) 1998bcb0991SDimitry Andric : DependenceGraphInfo(Twine(L.getHeader()->getParent()->getName() + "." + 2008bcb0991SDimitry Andric L.getHeader()->getName()) 2018bcb0991SDimitry Andric .str(), 2028bcb0991SDimitry Andric D) { 203480093f4SDimitry Andric // Put the basic blocks in program order for correct dependence 204480093f4SDimitry Andric // directions. 205480093f4SDimitry Andric LoopBlocksDFS DFS(&L); 206480093f4SDimitry Andric DFS.perform(&LI); 2078bcb0991SDimitry Andric BasicBlockListType BBList; 208e8d8bef9SDimitry Andric append_range(BBList, make_range(DFS.beginRPO(), DFS.endRPO())); 2098bcb0991SDimitry Andric DDGBuilder(*this, D, BBList).populate(); 2108bcb0991SDimitry Andric } 2118bcb0991SDimitry Andric 2128bcb0991SDimitry Andric DataDependenceGraph::~DataDependenceGraph() { 2138bcb0991SDimitry Andric for (auto *N : Nodes) { 2148bcb0991SDimitry Andric for (auto *E : *N) 2158bcb0991SDimitry Andric delete E; 2168bcb0991SDimitry Andric delete N; 2178bcb0991SDimitry Andric } 2188bcb0991SDimitry Andric } 2198bcb0991SDimitry Andric 2208bcb0991SDimitry Andric bool DataDependenceGraph::addNode(DDGNode &N) { 2218bcb0991SDimitry Andric if (!DDGBase::addNode(N)) 2228bcb0991SDimitry Andric return false; 2238bcb0991SDimitry Andric 2248bcb0991SDimitry Andric // In general, if the root node is already created and linked, it is not safe 225480093f4SDimitry Andric // to add new nodes since they may be unreachable by the root. However, 226480093f4SDimitry Andric // pi-block nodes need to be added after the root node is linked, and they are 227480093f4SDimitry Andric // always reachable by the root, because they represent components that are 228480093f4SDimitry Andric // already reachable by root. 229480093f4SDimitry Andric auto *Pi = dyn_cast<PiBlockDDGNode>(&N); 230480093f4SDimitry Andric assert((!Root || Pi) && 231480093f4SDimitry Andric "Root node is already added. No more nodes can be added."); 232480093f4SDimitry Andric 2338bcb0991SDimitry Andric if (isa<RootDDGNode>(N)) 2348bcb0991SDimitry Andric Root = &N; 2358bcb0991SDimitry Andric 236480093f4SDimitry Andric if (Pi) 237480093f4SDimitry Andric for (DDGNode *NI : Pi->getNodes()) 238480093f4SDimitry Andric PiBlockMap.insert(std::make_pair(NI, Pi)); 239480093f4SDimitry Andric 2408bcb0991SDimitry Andric return true; 2418bcb0991SDimitry Andric } 2428bcb0991SDimitry Andric 243480093f4SDimitry Andric const PiBlockDDGNode *DataDependenceGraph::getPiBlock(const NodeType &N) const { 244480093f4SDimitry Andric if (PiBlockMap.find(&N) == PiBlockMap.end()) 245480093f4SDimitry Andric return nullptr; 246480093f4SDimitry Andric auto *Pi = PiBlockMap.find(&N)->second; 247480093f4SDimitry Andric assert(PiBlockMap.find(Pi) == PiBlockMap.end() && 248480093f4SDimitry Andric "Nested pi-blocks detected."); 249480093f4SDimitry Andric return Pi; 250480093f4SDimitry Andric } 251480093f4SDimitry Andric 2528bcb0991SDimitry Andric raw_ostream &llvm::operator<<(raw_ostream &OS, const DataDependenceGraph &G) { 253480093f4SDimitry Andric for (DDGNode *Node : G) 254480093f4SDimitry Andric // Avoid printing nodes that are part of a pi-block twice. They will get 255480093f4SDimitry Andric // printed when the pi-block is printed. 256480093f4SDimitry Andric if (!G.getPiBlock(*Node)) 2578bcb0991SDimitry Andric OS << *Node << "\n"; 258480093f4SDimitry Andric OS << "\n"; 2598bcb0991SDimitry Andric return OS; 2608bcb0991SDimitry Andric } 2618bcb0991SDimitry Andric 2625ffd83dbSDimitry Andric //===--------------------------------------------------------------------===// 2635ffd83dbSDimitry Andric // DDGBuilder implementation 2645ffd83dbSDimitry Andric //===--------------------------------------------------------------------===// 2655ffd83dbSDimitry Andric 2665ffd83dbSDimitry Andric bool DDGBuilder::areNodesMergeable(const DDGNode &Src, 2675ffd83dbSDimitry Andric const DDGNode &Tgt) const { 2685ffd83dbSDimitry Andric // Only merge two nodes if they are both simple nodes and the consecutive 2695ffd83dbSDimitry Andric // instructions after merging belong to the same BB. 2705ffd83dbSDimitry Andric const auto *SimpleSrc = dyn_cast<const SimpleDDGNode>(&Src); 2715ffd83dbSDimitry Andric const auto *SimpleTgt = dyn_cast<const SimpleDDGNode>(&Tgt); 2725ffd83dbSDimitry Andric if (!SimpleSrc || !SimpleTgt) 2735ffd83dbSDimitry Andric return false; 2745ffd83dbSDimitry Andric 2755ffd83dbSDimitry Andric return SimpleSrc->getLastInstruction()->getParent() == 2765ffd83dbSDimitry Andric SimpleTgt->getFirstInstruction()->getParent(); 277480093f4SDimitry Andric } 278480093f4SDimitry Andric 2795ffd83dbSDimitry Andric void DDGBuilder::mergeNodes(DDGNode &A, DDGNode &B) { 2805ffd83dbSDimitry Andric DDGEdge &EdgeToFold = A.back(); 2815ffd83dbSDimitry Andric assert(A.getEdges().size() == 1 && EdgeToFold.getTargetNode() == B && 2825ffd83dbSDimitry Andric "Expected A to have a single edge to B."); 2835ffd83dbSDimitry Andric assert(isa<SimpleDDGNode>(&A) && isa<SimpleDDGNode>(&B) && 2845ffd83dbSDimitry Andric "Expected simple nodes"); 2855ffd83dbSDimitry Andric 2865ffd83dbSDimitry Andric // Copy instructions from B to the end of A. 2875ffd83dbSDimitry Andric cast<SimpleDDGNode>(&A)->appendInstructions(*cast<SimpleDDGNode>(&B)); 2885ffd83dbSDimitry Andric 2895ffd83dbSDimitry Andric // Move to A any outgoing edges from B. 2905ffd83dbSDimitry Andric for (DDGEdge *BE : B) 2915ffd83dbSDimitry Andric Graph.connect(A, BE->getTargetNode(), *BE); 2925ffd83dbSDimitry Andric 2935ffd83dbSDimitry Andric A.removeEdge(EdgeToFold); 2945ffd83dbSDimitry Andric destroyEdge(EdgeToFold); 2955ffd83dbSDimitry Andric Graph.removeNode(B); 2965ffd83dbSDimitry Andric destroyNode(B); 2975ffd83dbSDimitry Andric } 2985ffd83dbSDimitry Andric 2995ffd83dbSDimitry Andric bool DDGBuilder::shouldSimplify() const { return SimplifyDDG; } 3005ffd83dbSDimitry Andric 3015ffd83dbSDimitry Andric bool DDGBuilder::shouldCreatePiBlocks() const { return CreatePiBlocks; } 3025ffd83dbSDimitry Andric 3038bcb0991SDimitry Andric //===--------------------------------------------------------------------===// 3048bcb0991SDimitry Andric // DDG Analysis Passes 3058bcb0991SDimitry Andric //===--------------------------------------------------------------------===// 3068bcb0991SDimitry Andric 3078bcb0991SDimitry Andric /// DDG as a loop pass. 3088bcb0991SDimitry Andric DDGAnalysis::Result DDGAnalysis::run(Loop &L, LoopAnalysisManager &AM, 3098bcb0991SDimitry Andric LoopStandardAnalysisResults &AR) { 3108bcb0991SDimitry Andric Function *F = L.getHeader()->getParent(); 3118bcb0991SDimitry Andric DependenceInfo DI(F, &AR.AA, &AR.SE, &AR.LI); 312480093f4SDimitry Andric return std::make_unique<DataDependenceGraph>(L, AR.LI, DI); 3138bcb0991SDimitry Andric } 3148bcb0991SDimitry Andric AnalysisKey DDGAnalysis::Key; 3158bcb0991SDimitry Andric 3168bcb0991SDimitry Andric PreservedAnalyses DDGAnalysisPrinterPass::run(Loop &L, LoopAnalysisManager &AM, 3178bcb0991SDimitry Andric LoopStandardAnalysisResults &AR, 3188bcb0991SDimitry Andric LPMUpdater &U) { 3198bcb0991SDimitry Andric OS << "'DDG' for loop '" << L.getHeader()->getName() << "':\n"; 3208bcb0991SDimitry Andric OS << *AM.getResult<DDGAnalysis>(L, AR); 3218bcb0991SDimitry Andric return PreservedAnalyses::all(); 3228bcb0991SDimitry Andric } 323