1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 11:13:28 +01:00
llvm-mirror/lib/Analysis/DDG.cpp
Bardia Mahjour 948b602c7f [DDG] Data Dependence Graph - Topological Sort (Memory Leak Fix)
Summary:
This fixes the memory leak in bec37c3fc766a7b97f8c52c181c325fd47b75259
and re-delivers the reverted patch.
In this patch the DDG DAG is sorted topologically to put the
nodes in the graph in the order that would satisfy all
dependencies. This helps transformations that would like to
generate code based on the DDG. Since the DDG is a DAG a
reverse-post-order traversal would give us the topological
ordering. This patch also sorts the basic blocks passed to
the builder based on program order to ensure that the
dependencies are computed in the correct direction.

Authored By: bmahjour

Reviewer: Meinersbur, fhahn, myhsu, xtian, dmgreen, kbarton, jdoerfert

Reviewed By: Meinersbur

Subscribers: ychen, arphaman, simoll, a.elovikov, mgorny, hiraditya, jfb, wuzish, llvm-commits, jsji, Whitney, etiotto, ppc-slack

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D70609
2019-12-03 10:08:25 -05:00

284 lines
9.7 KiB
C++

//===- DDG.cpp - Data Dependence Graph -------------------------------------==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// The implementation for the data dependence graph.
//===----------------------------------------------------------------------===//
#include "llvm/Analysis/DDG.h"
#include "llvm/ADT/SCCIterator.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/LoopIterator.h"
#include "llvm/Support/CommandLine.h"
using namespace llvm;
static cl::opt<bool>
CreatePiBlocks("ddg-pi-blocks", cl::init(true), cl::Hidden, cl::ZeroOrMore,
cl::desc("Create pi-block nodes."));
#define DEBUG_TYPE "ddg"
template class llvm::DGEdge<DDGNode, DDGEdge>;
template class llvm::DGNode<DDGNode, DDGEdge>;
template class llvm::DirectedGraph<DDGNode, DDGEdge>;
//===--------------------------------------------------------------------===//
// DDGNode implementation
//===--------------------------------------------------------------------===//
DDGNode::~DDGNode() {}
bool DDGNode::collectInstructions(
llvm::function_ref<bool(Instruction *)> const &Pred,
InstructionListType &IList) const {
assert(IList.empty() && "Expected the IList to be empty on entry.");
if (isa<SimpleDDGNode>(this)) {
for (Instruction *I : cast<const SimpleDDGNode>(this)->getInstructions())
if (Pred(I))
IList.push_back(I);
} else if (isa<PiBlockDDGNode>(this)) {
for (const DDGNode *PN : cast<const PiBlockDDGNode>(this)->getNodes()) {
assert(!isa<PiBlockDDGNode>(PN) && "Nested PiBlocks are not supported.");
SmallVector<Instruction *, 8> TmpIList;
PN->collectInstructions(Pred, TmpIList);
IList.insert(IList.end(), TmpIList.begin(), TmpIList.end());
}
} else
llvm_unreachable("unimplemented type of node");
return !IList.empty();
}
raw_ostream &llvm::operator<<(raw_ostream &OS, const DDGNode::NodeKind K) {
const char *Out;
switch (K) {
case DDGNode::NodeKind::SingleInstruction:
Out = "single-instruction";
break;
case DDGNode::NodeKind::MultiInstruction:
Out = "multi-instruction";
break;
case DDGNode::NodeKind::PiBlock:
Out = "pi-block";
break;
case DDGNode::NodeKind::Root:
Out = "root";
break;
case DDGNode::NodeKind::Unknown:
Out = "?? (error)";
break;
}
OS << Out;
return OS;
}
raw_ostream &llvm::operator<<(raw_ostream &OS, const DDGNode &N) {
OS << "Node Address:" << &N << ":" << N.getKind() << "\n";
if (isa<SimpleDDGNode>(N)) {
OS << " Instructions:\n";
for (const Instruction *I : cast<const SimpleDDGNode>(N).getInstructions())
OS.indent(2) << *I << "\n";
} else if (isa<PiBlockDDGNode>(&N)) {
OS << "--- start of nodes in pi-block ---\n";
auto &Nodes = cast<const PiBlockDDGNode>(&N)->getNodes();
unsigned Count = 0;
for (const DDGNode *N : Nodes)
OS << *N << (++Count == Nodes.size() ? "" : "\n");
OS << "--- end of nodes in pi-block ---\n";
} else if (!isa<RootDDGNode>(N))
llvm_unreachable("unimplemented type of node");
OS << (N.getEdges().empty() ? " Edges:none!\n" : " Edges:\n");
for (auto &E : N.getEdges())
OS.indent(2) << *E;
return OS;
}
//===--------------------------------------------------------------------===//
// SimpleDDGNode implementation
//===--------------------------------------------------------------------===//
SimpleDDGNode::SimpleDDGNode(Instruction &I)
: DDGNode(NodeKind::SingleInstruction), InstList() {
assert(InstList.empty() && "Expected empty list.");
InstList.push_back(&I);
}
SimpleDDGNode::SimpleDDGNode(const SimpleDDGNode &N)
: DDGNode(N), InstList(N.InstList) {
assert(((getKind() == NodeKind::SingleInstruction && InstList.size() == 1) ||
(getKind() == NodeKind::MultiInstruction && InstList.size() > 1)) &&
"constructing from invalid simple node.");
}
SimpleDDGNode::SimpleDDGNode(SimpleDDGNode &&N)
: DDGNode(std::move(N)), InstList(std::move(N.InstList)) {
assert(((getKind() == NodeKind::SingleInstruction && InstList.size() == 1) ||
(getKind() == NodeKind::MultiInstruction && InstList.size() > 1)) &&
"constructing from invalid simple node.");
}
SimpleDDGNode::~SimpleDDGNode() { InstList.clear(); }
//===--------------------------------------------------------------------===//
// PiBlockDDGNode implementation
//===--------------------------------------------------------------------===//
PiBlockDDGNode::PiBlockDDGNode(const PiNodeList &List)
: DDGNode(NodeKind::PiBlock), NodeList(List) {
assert(!NodeList.empty() && "pi-block node constructed with an empty list.");
}
PiBlockDDGNode::PiBlockDDGNode(const PiBlockDDGNode &N)
: DDGNode(N), NodeList(N.NodeList) {
assert(getKind() == NodeKind::PiBlock && !NodeList.empty() &&
"constructing from invalid pi-block node.");
}
PiBlockDDGNode::PiBlockDDGNode(PiBlockDDGNode &&N)
: DDGNode(std::move(N)), NodeList(std::move(N.NodeList)) {
assert(getKind() == NodeKind::PiBlock && !NodeList.empty() &&
"constructing from invalid pi-block node.");
}
PiBlockDDGNode::~PiBlockDDGNode() { NodeList.clear(); }
//===--------------------------------------------------------------------===//
// DDGEdge implementation
//===--------------------------------------------------------------------===//
raw_ostream &llvm::operator<<(raw_ostream &OS, const DDGEdge::EdgeKind K) {
const char *Out;
switch (K) {
case DDGEdge::EdgeKind::RegisterDefUse:
Out = "def-use";
break;
case DDGEdge::EdgeKind::MemoryDependence:
Out = "memory";
break;
case DDGEdge::EdgeKind::Rooted:
Out = "rooted";
break;
case DDGEdge::EdgeKind::Unknown:
Out = "?? (error)";
break;
}
OS << Out;
return OS;
}
raw_ostream &llvm::operator<<(raw_ostream &OS, const DDGEdge &E) {
OS << "[" << E.getKind() << "] to " << &E.getTargetNode() << "\n";
return OS;
}
//===--------------------------------------------------------------------===//
// DataDependenceGraph implementation
//===--------------------------------------------------------------------===//
using BasicBlockListType = SmallVector<BasicBlock *, 8>;
DataDependenceGraph::DataDependenceGraph(Function &F, DependenceInfo &D)
: DependenceGraphInfo(F.getName().str(), D) {
// Put the basic blocks in program order for correct dependence
// directions.
BasicBlockListType BBList;
for (auto &SCC : make_range(scc_begin(&F), scc_end(&F)))
for (BasicBlock * BB : SCC)
BBList.push_back(BB);
std::reverse(BBList.begin(), BBList.end());
DDGBuilder(*this, D, BBList).populate();
}
DataDependenceGraph::DataDependenceGraph(Loop &L, LoopInfo &LI,
DependenceInfo &D)
: DependenceGraphInfo(Twine(L.getHeader()->getParent()->getName() + "." +
L.getHeader()->getName())
.str(),
D) {
// Put the basic blocks in program order for correct dependence
// directions.
LoopBlocksDFS DFS(&L);
DFS.perform(&LI);
BasicBlockListType BBList;
for (BasicBlock *BB : make_range(DFS.beginRPO(), DFS.endRPO()))
BBList.push_back(BB);
DDGBuilder(*this, D, BBList).populate();
}
DataDependenceGraph::~DataDependenceGraph() {
for (auto *N : Nodes) {
for (auto *E : *N)
delete E;
delete N;
}
}
bool DataDependenceGraph::addNode(DDGNode &N) {
if (!DDGBase::addNode(N))
return false;
// In general, if the root node is already created and linked, it is not safe
// to add new nodes since they may be unreachable by the root. However,
// pi-block nodes need to be added after the root node is linked, and they are
// always reachable by the root, because they represent components that are
// already reachable by root.
auto *Pi = dyn_cast<PiBlockDDGNode>(&N);
assert((!Root || Pi) &&
"Root node is already added. No more nodes can be added.");
if (isa<RootDDGNode>(N))
Root = &N;
if (Pi)
for (DDGNode *NI : Pi->getNodes())
PiBlockMap.insert(std::make_pair(NI, Pi));
return true;
}
const PiBlockDDGNode *DataDependenceGraph::getPiBlock(const NodeType &N) const {
if (PiBlockMap.find(&N) == PiBlockMap.end())
return nullptr;
auto *Pi = PiBlockMap.find(&N)->second;
assert(PiBlockMap.find(Pi) == PiBlockMap.end() &&
"Nested pi-blocks detected.");
return Pi;
}
raw_ostream &llvm::operator<<(raw_ostream &OS, const DataDependenceGraph &G) {
for (DDGNode *Node : G)
// Avoid printing nodes that are part of a pi-block twice. They will get
// printed when the pi-block is printed.
if (!G.getPiBlock(*Node))
OS << *Node << "\n";
OS << "\n";
return OS;
}
bool DDGBuilder::shouldCreatePiBlocks() const {
return CreatePiBlocks;
}
//===--------------------------------------------------------------------===//
// DDG Analysis Passes
//===--------------------------------------------------------------------===//
/// DDG as a loop pass.
DDGAnalysis::Result DDGAnalysis::run(Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR) {
Function *F = L.getHeader()->getParent();
DependenceInfo DI(F, &AR.AA, &AR.SE, &AR.LI);
return std::make_unique<DataDependenceGraph>(L, AR.LI, DI);
}
AnalysisKey DDGAnalysis::Key;
PreservedAnalyses DDGAnalysisPrinterPass::run(Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR,
LPMUpdater &U) {
OS << "'DDG' for loop '" << L.getHeader()->getName() << "':\n";
OS << *AM.getResult<DDGAnalysis>(L, AR);
return PreservedAnalyses::all();
}