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