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
,
22 "Simplify DDG by merging nodes that have less interesting edges."));
24 static cl::opt
<bool> CreatePiBlocks("ddg-pi-blocks", cl::init(true), cl::Hidden
,
25 cl::desc("Create pi-block nodes."));
27 #define DEBUG_TYPE "ddg"
29 template class llvm::DGEdge
<DDGNode
, DDGEdge
>;
30 template class llvm::DGNode
<DDGNode
, DDGEdge
>;
31 template class llvm::DirectedGraph
<DDGNode
, DDGEdge
>;
33 //===--------------------------------------------------------------------===//
34 // DDGNode implementation
35 //===--------------------------------------------------------------------===//
36 DDGNode::~DDGNode() = default;
38 bool DDGNode::collectInstructions(
39 llvm::function_ref
<bool(Instruction
*)> const &Pred
,
40 InstructionListType
&IList
) const {
41 assert(IList
.empty() && "Expected the IList to be empty on entry.");
42 if (isa
<SimpleDDGNode
>(this)) {
43 for (Instruction
*I
: cast
<const SimpleDDGNode
>(this)->getInstructions())
46 } else if (isa
<PiBlockDDGNode
>(this)) {
47 for (const DDGNode
*PN
: cast
<const PiBlockDDGNode
>(this)->getNodes()) {
48 assert(!isa
<PiBlockDDGNode
>(PN
) && "Nested PiBlocks are not supported.");
49 SmallVector
<Instruction
*, 8> TmpIList
;
50 PN
->collectInstructions(Pred
, TmpIList
);
51 llvm::append_range(IList
, TmpIList
);
54 llvm_unreachable("unimplemented type of node");
55 return !IList
.empty();
58 raw_ostream
&llvm::operator<<(raw_ostream
&OS
, const DDGNode::NodeKind K
) {
61 case DDGNode::NodeKind::SingleInstruction
:
62 Out
= "single-instruction";
64 case DDGNode::NodeKind::MultiInstruction
:
65 Out
= "multi-instruction";
67 case DDGNode::NodeKind::PiBlock
:
70 case DDGNode::NodeKind::Root
:
73 case DDGNode::NodeKind::Unknown
:
81 raw_ostream
&llvm::operator<<(raw_ostream
&OS
, const DDGNode
&N
) {
82 OS
<< "Node Address:" << &N
<< ":" << N
.getKind() << "\n";
83 if (isa
<SimpleDDGNode
>(N
)) {
84 OS
<< " Instructions:\n";
85 for (const Instruction
*I
: cast
<const SimpleDDGNode
>(N
).getInstructions())
86 OS
.indent(2) << *I
<< "\n";
87 } else if (isa
<PiBlockDDGNode
>(&N
)) {
88 OS
<< "--- start of nodes in pi-block ---\n";
89 auto &Nodes
= cast
<const PiBlockDDGNode
>(&N
)->getNodes();
91 for (const DDGNode
*N
: Nodes
)
92 OS
<< *N
<< (++Count
== Nodes
.size() ? "" : "\n");
93 OS
<< "--- end of nodes in pi-block ---\n";
94 } else if (!isa
<RootDDGNode
>(N
))
95 llvm_unreachable("unimplemented type of node");
97 OS
<< (N
.getEdges().empty() ? " Edges:none!\n" : " Edges:\n");
98 for (const auto &E
: N
.getEdges())
103 //===--------------------------------------------------------------------===//
104 // SimpleDDGNode implementation
105 //===--------------------------------------------------------------------===//
107 SimpleDDGNode::SimpleDDGNode(Instruction
&I
)
108 : DDGNode(NodeKind::SingleInstruction
) {
109 assert(InstList
.empty() && "Expected empty list.");
110 InstList
.push_back(&I
);
113 SimpleDDGNode::SimpleDDGNode(const SimpleDDGNode
&N
)
114 : DDGNode(N
), InstList(N
.InstList
) {
115 assert(((getKind() == NodeKind::SingleInstruction
&& InstList
.size() == 1) ||
116 (getKind() == NodeKind::MultiInstruction
&& InstList
.size() > 1)) &&
117 "constructing from invalid simple node.");
120 SimpleDDGNode::SimpleDDGNode(SimpleDDGNode
&&N
)
121 : DDGNode(std::move(N
)), InstList(std::move(N
.InstList
)) {
122 assert(((getKind() == NodeKind::SingleInstruction
&& InstList
.size() == 1) ||
123 (getKind() == NodeKind::MultiInstruction
&& InstList
.size() > 1)) &&
124 "constructing from invalid simple node.");
127 SimpleDDGNode::~SimpleDDGNode() { InstList
.clear(); }
129 //===--------------------------------------------------------------------===//
130 // PiBlockDDGNode implementation
131 //===--------------------------------------------------------------------===//
133 PiBlockDDGNode::PiBlockDDGNode(const PiNodeList
&List
)
134 : DDGNode(NodeKind::PiBlock
), NodeList(List
) {
135 assert(!NodeList
.empty() && "pi-block node constructed with an empty list.");
138 PiBlockDDGNode::PiBlockDDGNode(const PiBlockDDGNode
&N
)
139 : DDGNode(N
), NodeList(N
.NodeList
) {
140 assert(getKind() == NodeKind::PiBlock
&& !NodeList
.empty() &&
141 "constructing from invalid pi-block node.");
144 PiBlockDDGNode::PiBlockDDGNode(PiBlockDDGNode
&&N
)
145 : DDGNode(std::move(N
)), NodeList(std::move(N
.NodeList
)) {
146 assert(getKind() == NodeKind::PiBlock
&& !NodeList
.empty() &&
147 "constructing from invalid pi-block node.");
150 PiBlockDDGNode::~PiBlockDDGNode() { NodeList
.clear(); }
152 //===--------------------------------------------------------------------===//
153 // DDGEdge implementation
154 //===--------------------------------------------------------------------===//
156 raw_ostream
&llvm::operator<<(raw_ostream
&OS
, const DDGEdge::EdgeKind K
) {
159 case DDGEdge::EdgeKind::RegisterDefUse
:
162 case DDGEdge::EdgeKind::MemoryDependence
:
165 case DDGEdge::EdgeKind::Rooted
:
168 case DDGEdge::EdgeKind::Unknown
:
176 raw_ostream
&llvm::operator<<(raw_ostream
&OS
, const DDGEdge
&E
) {
177 OS
<< "[" << E
.getKind() << "] to " << &E
.getTargetNode() << "\n";
181 //===--------------------------------------------------------------------===//
182 // DataDependenceGraph implementation
183 //===--------------------------------------------------------------------===//
184 using BasicBlockListType
= SmallVector
<BasicBlock
*, 8>;
186 DataDependenceGraph::DataDependenceGraph(Function
&F
, DependenceInfo
&D
)
187 : DependenceGraphInfo(F
.getName().str(), D
) {
188 // Put the basic blocks in program order for correct dependence
190 BasicBlockListType BBList
;
191 for (const auto &SCC
: make_range(scc_begin(&F
), scc_end(&F
)))
192 append_range(BBList
, SCC
);
193 std::reverse(BBList
.begin(), BBList
.end());
194 DDGBuilder(*this, D
, BBList
).populate();
197 DataDependenceGraph::DataDependenceGraph(Loop
&L
, LoopInfo
&LI
,
199 : DependenceGraphInfo(Twine(L
.getHeader()->getParent()->getName() + "." +
200 L
.getHeader()->getName())
203 // Put the basic blocks in program order for correct dependence
205 LoopBlocksDFS
DFS(&L
);
207 BasicBlockListType BBList
;
208 append_range(BBList
, make_range(DFS
.beginRPO(), DFS
.endRPO()));
209 DDGBuilder(*this, D
, BBList
).populate();
212 DataDependenceGraph::~DataDependenceGraph() {
213 for (auto *N
: Nodes
) {
220 bool DataDependenceGraph::addNode(DDGNode
&N
) {
221 if (!DDGBase::addNode(N
))
224 // In general, if the root node is already created and linked, it is not safe
225 // to add new nodes since they may be unreachable by the root. However,
226 // pi-block nodes need to be added after the root node is linked, and they are
227 // always reachable by the root, because they represent components that are
228 // already reachable by root.
229 auto *Pi
= dyn_cast
<PiBlockDDGNode
>(&N
);
230 assert((!Root
|| Pi
) &&
231 "Root node is already added. No more nodes can be added.");
233 if (isa
<RootDDGNode
>(N
))
237 for (DDGNode
*NI
: Pi
->getNodes())
238 PiBlockMap
.insert(std::make_pair(NI
, Pi
));
243 const PiBlockDDGNode
*DataDependenceGraph::getPiBlock(const NodeType
&N
) const {
244 if (!PiBlockMap
.contains(&N
))
246 auto *Pi
= PiBlockMap
.find(&N
)->second
;
247 assert(!PiBlockMap
.contains(Pi
) && "Nested pi-blocks detected.");
251 raw_ostream
&llvm::operator<<(raw_ostream
&OS
, const DataDependenceGraph
&G
) {
252 for (DDGNode
*Node
: G
)
253 // Avoid printing nodes that are part of a pi-block twice. They will get
254 // printed when the pi-block is printed.
255 if (!G
.getPiBlock(*Node
))
261 //===--------------------------------------------------------------------===//
262 // DDGBuilder implementation
263 //===--------------------------------------------------------------------===//
265 bool DDGBuilder::areNodesMergeable(const DDGNode
&Src
,
266 const DDGNode
&Tgt
) const {
267 // Only merge two nodes if they are both simple nodes and the consecutive
268 // instructions after merging belong to the same BB.
269 const auto *SimpleSrc
= dyn_cast
<const SimpleDDGNode
>(&Src
);
270 const auto *SimpleTgt
= dyn_cast
<const SimpleDDGNode
>(&Tgt
);
271 if (!SimpleSrc
|| !SimpleTgt
)
274 return SimpleSrc
->getLastInstruction()->getParent() ==
275 SimpleTgt
->getFirstInstruction()->getParent();
278 void DDGBuilder::mergeNodes(DDGNode
&A
, DDGNode
&B
) {
279 DDGEdge
&EdgeToFold
= A
.back();
280 assert(A
.getEdges().size() == 1 && EdgeToFold
.getTargetNode() == B
&&
281 "Expected A to have a single edge to B.");
282 assert(isa
<SimpleDDGNode
>(&A
) && isa
<SimpleDDGNode
>(&B
) &&
283 "Expected simple nodes");
285 // Copy instructions from B to the end of A.
286 cast
<SimpleDDGNode
>(&A
)->appendInstructions(*cast
<SimpleDDGNode
>(&B
));
288 // Move to A any outgoing edges from B.
289 for (DDGEdge
*BE
: B
)
290 Graph
.connect(A
, BE
->getTargetNode(), *BE
);
292 A
.removeEdge(EdgeToFold
);
293 destroyEdge(EdgeToFold
);
298 bool DDGBuilder::shouldSimplify() const { return SimplifyDDG
; }
300 bool DDGBuilder::shouldCreatePiBlocks() const { return CreatePiBlocks
; }
302 //===--------------------------------------------------------------------===//
303 // DDG Analysis Passes
304 //===--------------------------------------------------------------------===//
306 /// DDG as a loop pass.
307 DDGAnalysis::Result
DDGAnalysis::run(Loop
&L
, LoopAnalysisManager
&AM
,
308 LoopStandardAnalysisResults
&AR
) {
309 Function
*F
= L
.getHeader()->getParent();
310 DependenceInfo
DI(F
, &AR
.AA
, &AR
.SE
, &AR
.LI
);
311 return std::make_unique
<DataDependenceGraph
>(L
, AR
.LI
, DI
);
313 AnalysisKey
DDGAnalysis::Key
;
315 PreservedAnalyses
DDGAnalysisPrinterPass::run(Loop
&L
, LoopAnalysisManager
&AM
,
316 LoopStandardAnalysisResults
&AR
,
318 OS
<< "'DDG' for loop '" << L
.getHeader()->getName() << "':\n";
319 OS
<< *AM
.getResult
<DDGAnalysis
>(L
, AR
);
320 return PreservedAnalyses::all();