Path: blob/main/contrib/llvm-project/llvm/lib/Analysis/DDG.cpp
35234 views
//===- DDG.cpp - Data Dependence Graph -------------------------------------==//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// The implementation for the data dependence graph.9//===----------------------------------------------------------------------===//10#include "llvm/Analysis/DDG.h"11#include "llvm/ADT/SCCIterator.h"12#include "llvm/Analysis/LoopInfo.h"13#include "llvm/Analysis/LoopIterator.h"14#include "llvm/Support/CommandLine.h"1516using namespace llvm;1718static cl::opt<bool> SimplifyDDG(19"ddg-simplify", cl::init(true), cl::Hidden,20cl::desc(21"Simplify DDG by merging nodes that have less interesting edges."));2223static cl::opt<bool> CreatePiBlocks("ddg-pi-blocks", cl::init(true), cl::Hidden,24cl::desc("Create pi-block nodes."));2526#define DEBUG_TYPE "ddg"2728template class llvm::DGEdge<DDGNode, DDGEdge>;29template class llvm::DGNode<DDGNode, DDGEdge>;30template class llvm::DirectedGraph<DDGNode, DDGEdge>;3132//===--------------------------------------------------------------------===//33// DDGNode implementation34//===--------------------------------------------------------------------===//35DDGNode::~DDGNode() = default;3637bool DDGNode::collectInstructions(38llvm::function_ref<bool(Instruction *)> const &Pred,39InstructionListType &IList) const {40assert(IList.empty() && "Expected the IList to be empty on entry.");41if (isa<SimpleDDGNode>(this)) {42for (Instruction *I : cast<const SimpleDDGNode>(this)->getInstructions())43if (Pred(I))44IList.push_back(I);45} else if (isa<PiBlockDDGNode>(this)) {46for (const DDGNode *PN : cast<const PiBlockDDGNode>(this)->getNodes()) {47assert(!isa<PiBlockDDGNode>(PN) && "Nested PiBlocks are not supported.");48SmallVector<Instruction *, 8> TmpIList;49PN->collectInstructions(Pred, TmpIList);50llvm::append_range(IList, TmpIList);51}52} else53llvm_unreachable("unimplemented type of node");54return !IList.empty();55}5657raw_ostream &llvm::operator<<(raw_ostream &OS, const DDGNode::NodeKind K) {58const char *Out;59switch (K) {60case DDGNode::NodeKind::SingleInstruction:61Out = "single-instruction";62break;63case DDGNode::NodeKind::MultiInstruction:64Out = "multi-instruction";65break;66case DDGNode::NodeKind::PiBlock:67Out = "pi-block";68break;69case DDGNode::NodeKind::Root:70Out = "root";71break;72case DDGNode::NodeKind::Unknown:73Out = "?? (error)";74break;75}76OS << Out;77return OS;78}7980raw_ostream &llvm::operator<<(raw_ostream &OS, const DDGNode &N) {81OS << "Node Address:" << &N << ":" << N.getKind() << "\n";82if (isa<SimpleDDGNode>(N)) {83OS << " Instructions:\n";84for (const Instruction *I : cast<const SimpleDDGNode>(N).getInstructions())85OS.indent(2) << *I << "\n";86} else if (isa<PiBlockDDGNode>(&N)) {87OS << "--- start of nodes in pi-block ---\n";88auto &Nodes = cast<const PiBlockDDGNode>(&N)->getNodes();89unsigned Count = 0;90for (const DDGNode *N : Nodes)91OS << *N << (++Count == Nodes.size() ? "" : "\n");92OS << "--- end of nodes in pi-block ---\n";93} else if (!isa<RootDDGNode>(N))94llvm_unreachable("unimplemented type of node");9596OS << (N.getEdges().empty() ? " Edges:none!\n" : " Edges:\n");97for (const auto &E : N.getEdges())98OS.indent(2) << *E;99return OS;100}101102//===--------------------------------------------------------------------===//103// SimpleDDGNode implementation104//===--------------------------------------------------------------------===//105106SimpleDDGNode::SimpleDDGNode(Instruction &I)107: DDGNode(NodeKind::SingleInstruction) {108assert(InstList.empty() && "Expected empty list.");109InstList.push_back(&I);110}111112SimpleDDGNode::SimpleDDGNode(const SimpleDDGNode &N)113: DDGNode(N), InstList(N.InstList) {114assert(((getKind() == NodeKind::SingleInstruction && InstList.size() == 1) ||115(getKind() == NodeKind::MultiInstruction && InstList.size() > 1)) &&116"constructing from invalid simple node.");117}118119SimpleDDGNode::SimpleDDGNode(SimpleDDGNode &&N)120: DDGNode(std::move(N)), InstList(std::move(N.InstList)) {121assert(((getKind() == NodeKind::SingleInstruction && InstList.size() == 1) ||122(getKind() == NodeKind::MultiInstruction && InstList.size() > 1)) &&123"constructing from invalid simple node.");124}125126SimpleDDGNode::~SimpleDDGNode() { InstList.clear(); }127128//===--------------------------------------------------------------------===//129// PiBlockDDGNode implementation130//===--------------------------------------------------------------------===//131132PiBlockDDGNode::PiBlockDDGNode(const PiNodeList &List)133: DDGNode(NodeKind::PiBlock), NodeList(List) {134assert(!NodeList.empty() && "pi-block node constructed with an empty list.");135}136137PiBlockDDGNode::PiBlockDDGNode(const PiBlockDDGNode &N)138: DDGNode(N), NodeList(N.NodeList) {139assert(getKind() == NodeKind::PiBlock && !NodeList.empty() &&140"constructing from invalid pi-block node.");141}142143PiBlockDDGNode::PiBlockDDGNode(PiBlockDDGNode &&N)144: DDGNode(std::move(N)), NodeList(std::move(N.NodeList)) {145assert(getKind() == NodeKind::PiBlock && !NodeList.empty() &&146"constructing from invalid pi-block node.");147}148149PiBlockDDGNode::~PiBlockDDGNode() { NodeList.clear(); }150151//===--------------------------------------------------------------------===//152// DDGEdge implementation153//===--------------------------------------------------------------------===//154155raw_ostream &llvm::operator<<(raw_ostream &OS, const DDGEdge::EdgeKind K) {156const char *Out;157switch (K) {158case DDGEdge::EdgeKind::RegisterDefUse:159Out = "def-use";160break;161case DDGEdge::EdgeKind::MemoryDependence:162Out = "memory";163break;164case DDGEdge::EdgeKind::Rooted:165Out = "rooted";166break;167case DDGEdge::EdgeKind::Unknown:168Out = "?? (error)";169break;170}171OS << Out;172return OS;173}174175raw_ostream &llvm::operator<<(raw_ostream &OS, const DDGEdge &E) {176OS << "[" << E.getKind() << "] to " << &E.getTargetNode() << "\n";177return OS;178}179180//===--------------------------------------------------------------------===//181// DataDependenceGraph implementation182//===--------------------------------------------------------------------===//183using BasicBlockListType = SmallVector<BasicBlock *, 8>;184185DataDependenceGraph::DataDependenceGraph(Function &F, DependenceInfo &D)186: DependenceGraphInfo(F.getName().str(), D) {187// Put the basic blocks in program order for correct dependence188// directions.189BasicBlockListType BBList;190for (const auto &SCC : make_range(scc_begin(&F), scc_end(&F)))191append_range(BBList, SCC);192std::reverse(BBList.begin(), BBList.end());193DDGBuilder(*this, D, BBList).populate();194}195196DataDependenceGraph::DataDependenceGraph(Loop &L, LoopInfo &LI,197DependenceInfo &D)198: DependenceGraphInfo(Twine(L.getHeader()->getParent()->getName() + "." +199L.getHeader()->getName())200.str(),201D) {202// Put the basic blocks in program order for correct dependence203// directions.204LoopBlocksDFS DFS(&L);205DFS.perform(&LI);206BasicBlockListType BBList;207append_range(BBList, make_range(DFS.beginRPO(), DFS.endRPO()));208DDGBuilder(*this, D, BBList).populate();209}210211DataDependenceGraph::~DataDependenceGraph() {212for (auto *N : Nodes) {213for (auto *E : *N)214delete E;215delete N;216}217}218219bool DataDependenceGraph::addNode(DDGNode &N) {220if (!DDGBase::addNode(N))221return false;222223// In general, if the root node is already created and linked, it is not safe224// to add new nodes since they may be unreachable by the root. However,225// pi-block nodes need to be added after the root node is linked, and they are226// always reachable by the root, because they represent components that are227// already reachable by root.228auto *Pi = dyn_cast<PiBlockDDGNode>(&N);229assert((!Root || Pi) &&230"Root node is already added. No more nodes can be added.");231232if (isa<RootDDGNode>(N))233Root = &N;234235if (Pi)236for (DDGNode *NI : Pi->getNodes())237PiBlockMap.insert(std::make_pair(NI, Pi));238239return true;240}241242const PiBlockDDGNode *DataDependenceGraph::getPiBlock(const NodeType &N) const {243if (!PiBlockMap.contains(&N))244return nullptr;245auto *Pi = PiBlockMap.find(&N)->second;246assert(!PiBlockMap.contains(Pi) && "Nested pi-blocks detected.");247return Pi;248}249250raw_ostream &llvm::operator<<(raw_ostream &OS, const DataDependenceGraph &G) {251for (DDGNode *Node : G)252// Avoid printing nodes that are part of a pi-block twice. They will get253// printed when the pi-block is printed.254if (!G.getPiBlock(*Node))255OS << *Node << "\n";256OS << "\n";257return OS;258}259260//===--------------------------------------------------------------------===//261// DDGBuilder implementation262//===--------------------------------------------------------------------===//263264bool DDGBuilder::areNodesMergeable(const DDGNode &Src,265const DDGNode &Tgt) const {266// Only merge two nodes if they are both simple nodes and the consecutive267// instructions after merging belong to the same BB.268const auto *SimpleSrc = dyn_cast<const SimpleDDGNode>(&Src);269const auto *SimpleTgt = dyn_cast<const SimpleDDGNode>(&Tgt);270if (!SimpleSrc || !SimpleTgt)271return false;272273return SimpleSrc->getLastInstruction()->getParent() ==274SimpleTgt->getFirstInstruction()->getParent();275}276277void DDGBuilder::mergeNodes(DDGNode &A, DDGNode &B) {278DDGEdge &EdgeToFold = A.back();279assert(A.getEdges().size() == 1 && EdgeToFold.getTargetNode() == B &&280"Expected A to have a single edge to B.");281assert(isa<SimpleDDGNode>(&A) && isa<SimpleDDGNode>(&B) &&282"Expected simple nodes");283284// Copy instructions from B to the end of A.285cast<SimpleDDGNode>(&A)->appendInstructions(*cast<SimpleDDGNode>(&B));286287// Move to A any outgoing edges from B.288for (DDGEdge *BE : B)289Graph.connect(A, BE->getTargetNode(), *BE);290291A.removeEdge(EdgeToFold);292destroyEdge(EdgeToFold);293Graph.removeNode(B);294destroyNode(B);295}296297bool DDGBuilder::shouldSimplify() const { return SimplifyDDG; }298299bool DDGBuilder::shouldCreatePiBlocks() const { return CreatePiBlocks; }300301//===--------------------------------------------------------------------===//302// DDG Analysis Passes303//===--------------------------------------------------------------------===//304305/// DDG as a loop pass.306DDGAnalysis::Result DDGAnalysis::run(Loop &L, LoopAnalysisManager &AM,307LoopStandardAnalysisResults &AR) {308Function *F = L.getHeader()->getParent();309DependenceInfo DI(F, &AR.AA, &AR.SE, &AR.LI);310return std::make_unique<DataDependenceGraph>(L, AR.LI, DI);311}312AnalysisKey DDGAnalysis::Key;313314PreservedAnalyses DDGAnalysisPrinterPass::run(Loop &L, LoopAnalysisManager &AM,315LoopStandardAnalysisResults &AR,316LPMUpdater &U) {317OS << "'DDG' for loop '" << L.getHeader()->getName() << "':\n";318OS << *AM.getResult<DDGAnalysis>(L, AR);319return PreservedAnalyses::all();320}321322323