LLVM 24.0.0git
GenericIteratedDominanceFrontier.h
Go to the documentation of this file.
1//===- IteratedDominanceFrontier.h - Calculate IDF --------------*- C++ -*-===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8/// \file
9/// Compute iterated dominance frontiers using a linear time algorithm.
10///
11/// The algorithm used here is based on:
12///
13/// Sreedhar and Gao. A linear time algorithm for placing phi-nodes.
14/// In Proceedings of the 22nd ACM SIGPLAN-SIGACT Symposium on Principles of
15/// Programming Languages
16/// POPL '95. ACM, New York, NY, 62-73.
17///
18/// It has been modified to not explicitly use the DJ graph data structure and
19/// to directly compute pruned SSA using per-variable liveness information.
20//
21//===----------------------------------------------------------------------===//
22
23#ifndef LLVM_SUPPORT_GENERICITERATEDDOMINANCEFRONTIER_H
24#define LLVM_SUPPORT_GENERICITERATEDDOMINANCEFRONTIER_H
25
30#include <queue>
31
32namespace llvm {
33
34namespace IDFCalculatorDetail {
35
36/// Generic utility class used for getting the children of a basic block.
37/// May be specialized if, for example, one wouldn't like to return nullpointer
38/// successors.
39template <class NodeTy, bool IsPostDom> struct ChildrenGetterTy {
43
44 range get(const NodeRef &N);
45};
46
47} // end of namespace IDFCalculatorDetail
48
49/// Determine the iterated dominance frontier, given a set of defining
50/// blocks, and optionally, a set of live-in blocks.
51///
52/// In turn, the results can be used to place phi nodes.
53///
54/// This algorithm is a linear time computation of Iterated Dominance Frontiers,
55/// pruned using the live-in set.
56/// By default, liveness is not used to prune the IDF computation.
57/// The template parameters should be of a CFG block type.
58template <class NodeTy, bool IsPostDom> class IDFCalculatorBase {
59public:
61 std::conditional_t<IsPostDom, Inverse<NodeTy *>, NodeTy *>;
64
66
68 const ChildrenGetterTy &C)
69 : DT(DT), ChildrenGetter(C) {}
70
71 /// Give the IDF calculator the set of blocks in which the value is
72 /// defined. This is equivalent to the set of starting blocks it should be
73 /// calculating the IDF for (though later gets pruned based on liveness).
74 ///
75 /// Note: This set *must* live for the entire lifetime of the IDF calculator.
77 DefBlocks = &Blocks;
78 }
79
80 /// Give the IDF calculator the set of blocks in which the value is
81 /// live on entry to the block. This is used to prune the IDF calculation to
82 /// not include blocks where any phi insertion would be dead.
83 ///
84 /// Note: This set *must* live for the entire lifetime of the IDF calculator.
86 LiveInBlocks = &Blocks;
87 useLiveIn = true;
88 }
89
90 /// Reset the live-in block set to be empty, and tell the IDF
91 /// calculator to not use liveness anymore.
93 LiveInBlocks = nullptr;
94 useLiveIn = false;
95 }
96
97 /// Calculate iterated dominance frontiers
98 ///
99 /// This uses the linear-time phi algorithm based on DJ-graphs mentioned in
100 /// the file-level comment. It performs DF->IDF pruning using the live-in
101 /// set, to avoid computing the IDF for blocks where an inserted PHI node
102 /// would be dead.
104
105private:
107 ChildrenGetterTy ChildrenGetter;
108 bool useLiveIn = false;
109 const SmallPtrSetImpl<NodeTy *> *LiveInBlocks;
110 const SmallPtrSetImpl<NodeTy *> *DefBlocks;
111};
112
113//===----------------------------------------------------------------------===//
114// Implementation.
115//===----------------------------------------------------------------------===//
116
117namespace IDFCalculatorDetail {
118
119template <class NodeTy, bool IsPostDom>
127
128} // end of namespace IDFCalculatorDetail
129
130template <class NodeTy, bool IsPostDom>
132 SmallVectorImpl<NodeTy *> &IDFBlocks) {
133 // Use a priority queue keyed on dominator tree level so that inserted nodes
134 // are handled from the bottom of the dominator tree upwards. We also augment
135 // the level with a DFS number to ensure that the blocks are ordered in a
136 // deterministic way.
137 using DomTreeNodePair =
138 std::pair<DomTreeNodeBase<NodeTy> *, std::pair<unsigned, unsigned>>;
139 using IDFPriorityQueue =
140 std::priority_queue<DomTreeNodePair, SmallVector<DomTreeNodePair, 32>,
142
143 IDFPriorityQueue PQ;
144
145 DT.updateDFSNumbers();
146
147 // The DFS in-numbers are unique and dense in [0, number of nodes), with the
148 // root's DFS out-number being the number of nodes. Use them to index the
149 // visited sets.
150 const DomTreeNodeBase<NodeTy> *RootNode = DT.getRootNode();
151 unsigned NumNodes = RootNode ? RootNode->getDFSNumOut() : 0;
152
154 SmallVector<bool, 32> VisitedPQ(NumNodes, false);
155 SmallVector<bool, 32> VisitedWorklist(NumNodes, false);
156
157 for (NodeTy *BB : *DefBlocks)
158 if (DomTreeNodeBase<NodeTy> *Node = DT.getNode(BB)) {
159 PQ.push({Node, std::make_pair(Node->getLevel(), Node->getDFSNumIn())});
160 VisitedWorklist[Node->getDFSNumIn()] = true;
161 }
162
163 while (!PQ.empty()) {
164 DomTreeNodePair RootPair = PQ.top();
165 PQ.pop();
166 DomTreeNodeBase<NodeTy> *Root = RootPair.first;
167 unsigned RootLevel = RootPair.second.first;
168
169 // Walk all dominator tree children of Root, inspecting their CFG edges with
170 // targets elsewhere on the dominator tree. Only targets whose level is at
171 // most Root's level are added to the iterated dominance frontier of the
172 // definition set.
173
174 assert(Worklist.empty());
175 Worklist.push_back(Root);
176
177 while (!Worklist.empty()) {
179 NodeTy *BB = Node->getBlock();
180 // Succ is the successor in the direction we are calculating IDF, so it is
181 // successor for IDF, and predecessor for Reverse IDF.
182 auto DoWork = [&](NodeTy *Succ) {
183 DomTreeNodeBase<NodeTy> *SuccNode = DT.getNode(Succ);
184
185 const unsigned SuccLevel = SuccNode->getLevel();
186 if (SuccLevel > RootLevel)
187 return;
188
189 if (std::exchange(VisitedPQ[SuccNode->getDFSNumIn()], true))
190 return;
191
192 NodeTy *SuccBB = SuccNode->getBlock();
193 if (useLiveIn && !LiveInBlocks->count(SuccBB))
194 return;
195
196 IDFBlocks.emplace_back(SuccBB);
197 if (!DefBlocks->count(SuccBB))
198 PQ.push(std::make_pair(
199 SuccNode, std::make_pair(SuccLevel, SuccNode->getDFSNumIn())));
200 };
201
202 for (auto *Succ : ChildrenGetter.get(BB))
203 DoWork(Succ);
204
205 for (auto DomChild : *Node) {
206 if (!std::exchange(VisitedWorklist[DomChild->getDFSNumIn()], true))
207 Worklist.push_back(DomChild);
208 }
209 }
210 }
211}
212
213} // end of namespace llvm
214
215#endif
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
This file defines a set of templates that efficiently compute a dominator tree over a generic graph.
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
Base class for the actual dominator tree node.
unsigned getDFSNumIn() const
getDFSNumIn/getDFSNumOut - These return the DFS visitation order for nodes in the dominator tree.
NodeT * getBlock() const
unsigned getLevel() const
unsigned getDFSNumOut() const
Core dominator tree base class.
IDFCalculatorBase(DominatorTreeBase< NodeTy, IsPostDom > &DT)
void resetLiveInBlocks()
Reset the live-in block set to be empty, and tell the IDF calculator to not use liveness anymore.
void calculate(SmallVectorImpl< NodeTy * > &IDFBlocks)
Calculate iterated dominance frontiers.
void setLiveInBlocks(const SmallPtrSetImpl< NodeTy * > &Blocks)
Give the IDF calculator the set of blocks in which the value is live on entry to the block.
void setDefiningBlocks(const SmallPtrSetImpl< NodeTy * > &Blocks)
Give the IDF calculator the set of blocks in which the value is defined.
IDFCalculatorBase(DominatorTreeBase< NodeTy, IsPostDom > &DT, const ChildrenGetterTy &C)
std::conditional_t< IsPostDom, Inverse< NodeTy * >, NodeTy * > OrderedNodeTy
IDFCalculatorDetail::ChildrenGetterTy< NodeTy, IsPostDom > ChildrenGetterTy
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
A range adaptor for a pair of iterators.
This provides a very simple, boring adaptor for a begin and end iterator into a range type.
This is an optimization pass for GlobalISel generic memory operations.
iterator_range< typename GraphTraits< GraphType >::ChildIteratorType > children(const typename GraphTraits< GraphType >::NodeRef &G)
#define N
typename GraphType::UnknownGraphTypeError NodeRef
Definition GraphTraits.h:95
Generic utility class used for getting the children of a basic block.
typename GraphTraits< NodeTy * >::ChildIteratorType ChildIteratorType
typename GraphTraits< NodeTy * >::NodeRef NodeRef
Function object to check whether the second component of a container supported by std::get (like std:...
Definition STLExtras.h:1464