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