1 //===- DDG.cpp - Data Dependence Graph -------------------------------------==//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // The implementation for the data dependence graph.
10 //===----------------------------------------------------------------------===//
11 #include "llvm/Analysis/DDG.h"
12 #include "llvm/ADT/SCCIterator.h"
13 #include "llvm/Analysis/LoopInfo.h"
14 #include "llvm/Analysis/LoopIterator.h"
15 #include "llvm/Support/CommandLine.h"
19 static cl::opt
<bool> SimplifyDDG(
20 "ddg-simplify", cl::init(true), cl::Hidden
, cl::ZeroOrMore
,
22 "Simplify DDG by merging nodes that have less interesting edges."));
25 CreatePiBlocks("ddg-pi-blocks", cl::init(true), cl::Hidden
, cl::ZeroOrMore
,
26 cl::desc("Create pi-block nodes."));
28 #define DEBUG_TYPE "ddg"
30 template class llvm::DGEdge
<DDGNode
, DDGEdge
>;
31 template class llvm::DGNode
<DDGNode
, DDGEdge
>;
32 template class llvm::DirectedGraph
<DDGNode
, DDGEdge
>;
34 //===--------------------------------------------------------------------===//
35 // DDGNode implementation
36 //===--------------------------------------------------------------------===//
37 DDGNode::~DDGNode() {}
39 bool DDGNode::collectInstructions(
40 llvm::function_ref
<bool(Instruction
*)> const &Pred
,
41 InstructionListType
&IList
) const {
42 assert(IList
.empty() && "Expected the IList to be empty on entry.");
43 if (isa
<SimpleDDGNode
>(this)) {
44 for (Instruction
*I
: cast
<const SimpleDDGNode
>(this)->getInstructions())
47 } else if (isa
<PiBlockDDGNode
>(this)) {
48 for (const DDGNode
*PN
: cast
<const PiBlockDDGNode
>(this)->getNodes()) {
49 assert(!isa
<PiBlockDDGNode
>(PN
) && "Nested PiBlocks are not supported.");
50 SmallVector
<Instruction
*, 8> TmpIList
;
51 PN
->collectInstructions(Pred
, TmpIList
);
52 llvm::append_range(IList
, TmpIList
);
55 llvm_unreachable("unimplemented type of node");
56 return !IList
.empty();
59 raw_ostream
&llvm::operator<<(raw_ostream
&OS
, const DDGNode::NodeKind K
) {
62 case DDGNode::NodeKind::SingleInstruction
:
63 Out
= "single-instruction";
65 case DDGNode::NodeKind::MultiInstruction
:
66 Out
= "multi-instruction";
68 case DDGNode::NodeKind::PiBlock
:
71 case DDGNode::NodeKind::Root
:
74 case DDGNode::NodeKind::Unknown
:
82 raw_ostream
&llvm::operator<<(raw_ostream
&OS
, const DDGNode
&N
) {
83 OS
<< "Node Address:" << &N
<< ":" << N
.getKind() << "\n";
84 if (isa
<SimpleDDGNode
>(N
)) {
85 OS
<< " Instructions:\n";
86 for (const Instruction
*I
: cast
<const SimpleDDGNode
>(N
).getInstructions())
87 OS
.indent(2) << *I
<< "\n";
88 } else if (isa
<PiBlockDDGNode
>(&N
)) {
89 OS
<< "--- start of nodes in pi-block ---\n";
90 auto &Nodes
= cast
<const PiBlockDDGNode
>(&N
)->getNodes();
92 for (const DDGNode
*N
: Nodes
)
93 OS
<< *N
<< (++Count
== Nodes
.size() ? "" : "\n");
94 OS
<< "--- end of nodes in pi-block ---\n";
95 } else if (!isa
<RootDDGNode
>(N
))
96 llvm_unreachable("unimplemented type of node");
98 OS
<< (N
.getEdges().empty() ? " Edges:none!\n" : " Edges:\n");
99 for (auto &E
: N
.getEdges())
104 //===--------------------------------------------------------------------===//
105 // SimpleDDGNode implementation
106 //===--------------------------------------------------------------------===//
108 SimpleDDGNode::SimpleDDGNode(Instruction
&I
)
109 : DDGNode(NodeKind::SingleInstruction
), InstList() {
110 assert(InstList
.empty() && "Expected empty list.");
111 InstList
.push_back(&I
);
114 SimpleDDGNode::SimpleDDGNode(const SimpleDDGNode
&N
)
115 : DDGNode(N
), InstList(N
.InstList
) {
116 assert(((getKind() == NodeKind::SingleInstruction
&& InstList
.size() == 1) ||
117 (getKind() == NodeKind::MultiInstruction
&& InstList
.size() > 1)) &&
118 "constructing from invalid simple node.");
121 SimpleDDGNode::SimpleDDGNode(SimpleDDGNode
&&N
)
122 : DDGNode(std::move(N
)), InstList(std::move(N
.InstList
)) {
123 assert(((getKind() == NodeKind::SingleInstruction
&& InstList
.size() == 1) ||
124 (getKind() == NodeKind::MultiInstruction
&& InstList
.size() > 1)) &&
125 "constructing from invalid simple node.");
128 SimpleDDGNode::~SimpleDDGNode() { InstList
.clear(); }
130 //===--------------------------------------------------------------------===//
131 // PiBlockDDGNode implementation
132 //===--------------------------------------------------------------------===//
134 PiBlockDDGNode::PiBlockDDGNode(const PiNodeList
&List
)
135 : DDGNode(NodeKind::PiBlock
), NodeList(List
) {
136 assert(!NodeList
.empty() && "pi-block node constructed with an empty list.");
139 PiBlockDDGNode::PiBlockDDGNode(const PiBlockDDGNode
&N
)
140 : DDGNode(N
), NodeList(N
.NodeList
) {
141 assert(getKind() == NodeKind::PiBlock
&& !NodeList
.empty() &&
142 "constructing from invalid pi-block node.");
145 PiBlockDDGNode::PiBlockDDGNode(PiBlockDDGNode
&&N
)
146 : DDGNode(std::move(N
)), NodeList(std::move(N
.NodeList
)) {
147 assert(getKind() == NodeKind::PiBlock
&& !NodeList
.empty() &&
148 "constructing from invalid pi-block node.");
151 PiBlockDDGNode::~PiBlockDDGNode() { NodeList
.clear(); }
153 //===--------------------------------------------------------------------===//
154 // DDGEdge implementation
155 //===--------------------------------------------------------------------===//
157 raw_ostream
&llvm::operator<<(raw_ostream
&OS
, const DDGEdge::EdgeKind K
) {
160 case DDGEdge::EdgeKind::RegisterDefUse
:
163 case DDGEdge::EdgeKind::MemoryDependence
:
166 case DDGEdge::EdgeKind::Rooted
:
169 case DDGEdge::EdgeKind::Unknown
:
177 raw_ostream
&llvm::operator<<(raw_ostream
&OS
, const DDGEdge
&E
) {
178 OS
<< "[" << E
.getKind() << "] to " << &E
.getTargetNode() << "\n";
182 //===--------------------------------------------------------------------===//
183 // DataDependenceGraph implementation
184 //===--------------------------------------------------------------------===//
185 using BasicBlockListType
= SmallVector
<BasicBlock
*, 8>;
187 DataDependenceGraph::DataDependenceGraph(Function
&F
, DependenceInfo
&D
)
188 : DependenceGraphInfo(F
.getName().str(), D
) {
189 // Put the basic blocks in program order for correct dependence
191 BasicBlockListType BBList
;
192 for (auto &SCC
: make_range(scc_begin(&F
), scc_end(&F
)))
193 append_range(BBList
, SCC
);
194 std::reverse(BBList
.begin(), BBList
.end());
195 DDGBuilder(*this, D
, BBList
).populate();
198 DataDependenceGraph::DataDependenceGraph(Loop
&L
, LoopInfo
&LI
,
200 : DependenceGraphInfo(Twine(L
.getHeader()->getParent()->getName() + "." +
201 L
.getHeader()->getName())
204 // Put the basic blocks in program order for correct dependence
206 LoopBlocksDFS
DFS(&L
);
208 BasicBlockListType BBList
;
209 append_range(BBList
, make_range(DFS
.beginRPO(), DFS
.endRPO()));
210 DDGBuilder(*this, D
, BBList
).populate();
213 DataDependenceGraph::~DataDependenceGraph() {
214 for (auto *N
: Nodes
) {
221 bool DataDependenceGraph::addNode(DDGNode
&N
) {
222 if (!DDGBase::addNode(N
))
225 // In general, if the root node is already created and linked, it is not safe
226 // to add new nodes since they may be unreachable by the root. However,
227 // pi-block nodes need to be added after the root node is linked, and they are
228 // always reachable by the root, because they represent components that are
229 // already reachable by root.
230 auto *Pi
= dyn_cast
<PiBlockDDGNode
>(&N
);
231 assert((!Root
|| Pi
) &&
232 "Root node is already added. No more nodes can be added.");
234 if (isa
<RootDDGNode
>(N
))
238 for (DDGNode
*NI
: Pi
->getNodes())
239 PiBlockMap
.insert(std::make_pair(NI
, Pi
));
244 const PiBlockDDGNode
*DataDependenceGraph::getPiBlock(const NodeType
&N
) const {
245 if (PiBlockMap
.find(&N
) == PiBlockMap
.end())
247 auto *Pi
= PiBlockMap
.find(&N
)->second
;
248 assert(PiBlockMap
.find(Pi
) == PiBlockMap
.end() &&
249 "Nested pi-blocks detected.");
253 raw_ostream
&llvm::operator<<(raw_ostream
&OS
, const DataDependenceGraph
&G
) {
254 for (DDGNode
*Node
: G
)
255 // Avoid printing nodes that are part of a pi-block twice. They will get
256 // printed when the pi-block is printed.
257 if (!G
.getPiBlock(*Node
))
263 //===--------------------------------------------------------------------===//
264 // DDGBuilder implementation
265 //===--------------------------------------------------------------------===//
267 bool DDGBuilder::areNodesMergeable(const DDGNode
&Src
,
268 const DDGNode
&Tgt
) const {
269 // Only merge two nodes if they are both simple nodes and the consecutive
270 // instructions after merging belong to the same BB.
271 const auto *SimpleSrc
= dyn_cast
<const SimpleDDGNode
>(&Src
);
272 const auto *SimpleTgt
= dyn_cast
<const SimpleDDGNode
>(&Tgt
);
273 if (!SimpleSrc
|| !SimpleTgt
)
276 return SimpleSrc
->getLastInstruction()->getParent() ==
277 SimpleTgt
->getFirstInstruction()->getParent();
280 void DDGBuilder::mergeNodes(DDGNode
&A
, DDGNode
&B
) {
281 DDGEdge
&EdgeToFold
= A
.back();
282 assert(A
.getEdges().size() == 1 && EdgeToFold
.getTargetNode() == B
&&
283 "Expected A to have a single edge to B.");
284 assert(isa
<SimpleDDGNode
>(&A
) && isa
<SimpleDDGNode
>(&B
) &&
285 "Expected simple nodes");
287 // Copy instructions from B to the end of A.
288 cast
<SimpleDDGNode
>(&A
)->appendInstructions(*cast
<SimpleDDGNode
>(&B
));
290 // Move to A any outgoing edges from B.
291 for (DDGEdge
*BE
: B
)
292 Graph
.connect(A
, BE
->getTargetNode(), *BE
);
294 A
.removeEdge(EdgeToFold
);
295 destroyEdge(EdgeToFold
);
300 bool DDGBuilder::shouldSimplify() const { return SimplifyDDG
; }
302 bool DDGBuilder::shouldCreatePiBlocks() const { return CreatePiBlocks
; }
304 //===--------------------------------------------------------------------===//
305 // DDG Analysis Passes
306 //===--------------------------------------------------------------------===//
308 /// DDG as a loop pass.
309 DDGAnalysis::Result
DDGAnalysis::run(Loop
&L
, LoopAnalysisManager
&AM
,
310 LoopStandardAnalysisResults
&AR
) {
311 Function
*F
= L
.getHeader()->getParent();
312 DependenceInfo
DI(F
, &AR
.AA
, &AR
.SE
, &AR
.LI
);
313 return std::make_unique
<DataDependenceGraph
>(L
, AR
.LI
, DI
);
315 AnalysisKey
DDGAnalysis::Key
;
317 PreservedAnalyses
DDGAnalysisPrinterPass::run(Loop
&L
, LoopAnalysisManager
&AM
,
318 LoopStandardAnalysisResults
&AR
,
320 OS
<< "'DDG' for loop '" << L
.getHeader()->getName() << "':\n";
321 OS
<< *AM
.getResult
<DDGAnalysis
>(L
, AR
);
322 return PreservedAnalyses::all();