Skip to content

Commit bc2bb54

Browse files
committed
CFG dominator algorithm change to more closely resemble Coopers
Main change is to make it so that cfg nodes only hold their immediate dominators index, where previously it used to hold on to all dominators up the tree. More compact (and faster) but if you need the full dominator list then you have to walk back up dominator nodes.
1 parent cd54630 commit bc2bb54

File tree

1 file changed

+60
-42
lines changed

1 file changed

+60
-42
lines changed

src/analyses/cfg_dominators.h

+60-42
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,9 @@ template <class P, class T, bool post_dom>
3737
class cfg_dominators_templatet
3838
{
3939
public:
40-
typedef std::set<T> target_sett;
41-
4240
struct nodet
4341
{
44-
target_sett dominators;
42+
optionalt<std::size_t> dominator;
4543
};
4644

4745
typedef procedure_local_cfg_baset<nodet, P, T> cfgt;
@@ -76,7 +74,45 @@ class cfg_dominators_templatet
7674
/// Note by definition all program points dominate themselves.
7775
bool dominates(T lhs, const nodet &rhs_node) const
7876
{
79-
return rhs_node.dominators.count(lhs);
77+
if (!rhs_node.dominator)
78+
return false;
79+
80+
auto target_index = cfg.get_node_index(lhs);
81+
auto current_index = rhs_node.dominator;
82+
while (current_index.has_value())
83+
{
84+
if (*current_index == target_index)
85+
return true;
86+
87+
// As the root dominates itself, we will cancel if we get here and we're
88+
// not compared.
89+
if (*current_index == 0)
90+
return false;
91+
92+
current_index = cfg[*current_index].dominator;
93+
}
94+
95+
return false;
96+
}
97+
98+
/// Returns a set of T that are the dominators of start_node.
99+
std::set<T> dominated_by(T start_node) const
100+
{
101+
auto current_index = cfg.get_node_index(start_node);
102+
std::set<T> results;
103+
while (current_index.has_value())
104+
{
105+
// As the root dominates itself, we will cancel if we get here and we're
106+
// not compared.
107+
if (*current_index == 0)
108+
return false;
109+
110+
auto &current_node = cfg[*current_index];
111+
results.emplace(current_node.PC);
112+
current_index = current_node.dominator;
113+
}
114+
115+
return results;
80116
}
81117

82118
/// Returns true if program point \p lhs dominates \p rhs.
@@ -94,7 +130,7 @@ class cfg_dominators_templatet
94130
// Dominator analysis walks from the entry point, so a side-effect is to
95131
// identify unreachable program points (those which don't dominate even
96132
// themselves).
97-
return !program_point_node.dominators.empty();
133+
return program_point_node.dominator.has_value();
98134
}
99135

100136
/// Returns true if the program point for \p program_point_node is reachable
@@ -156,7 +192,7 @@ void cfg_dominators_templatet<P, T, post_dom>::fixedpoint(P &program)
156192
else
157193
entry_node = cfgt::get_first_node(program);
158194
typename cfgt::nodet &n = cfg.get_node(entry_node);
159-
n.dominators.insert(entry_node);
195+
n.dominator = cfg.get_node_index(entry_node);
160196

161197
for(typename cfgt::edgest::const_iterator
162198
s_it=(post_dom?n.in:n.out).begin();
@@ -172,58 +208,40 @@ void cfg_dominators_templatet<P, T, post_dom>::fixedpoint(P &program)
172208

173209
bool changed=false;
174210
typename cfgt::nodet &node = cfg.get_node(current);
175-
if(node.dominators.empty())
176-
{
177-
for(const auto &edge : (post_dom ? node.out : node.in))
178-
if(!cfg[edge.first].dominators.empty())
179-
{
180-
node.dominators=cfg[edge.first].dominators;
181-
node.dominators.insert(current);
182-
changed=true;
183-
}
184-
}
211+
212+
auto potential_dominator = node.dominator;
185213

186214
// compute intersection of predecessors
187215
for(const auto &edge : (post_dom ? node.out : node.in))
188216
{
189-
const target_sett &other=cfg[edge.first].dominators;
190-
if(other.empty())
217+
const typename cfgt::nodet &other = cfg[edge.first];
218+
if(!other.dominator)
191219
continue;
192220

193-
typename target_sett::const_iterator n_it=node.dominators.begin();
194-
typename target_sett::const_iterator o_it=other.begin();
221+
if (!potential_dominator)
222+
potential_dominator = other.dominator;
195223

196-
// in-place intersection. not safe to use set_intersect
197-
while(n_it!=node.dominators.end() && o_it!=other.end())
224+
auto edge_index = *other.dominator;
225+
while(potential_dominator != edge_index)
198226
{
199-
if(*n_it==current)
200-
++n_it;
201-
else if(*n_it<*o_it)
202-
{
203-
changed=true;
204-
node.dominators.erase(n_it++);
205-
}
206-
else if(*o_it<*n_it)
207-
++o_it;
208-
else
227+
while(potential_dominator > edge_index)
209228
{
210-
++n_it;
211-
++o_it;
229+
potential_dominator = cfg[*potential_dominator].dominator;
212230
}
213-
}
214231

215-
while(n_it!=node.dominators.end())
216-
{
217-
if(*n_it==current)
218-
++n_it;
219-
else
232+
while(edge_index < potential_dominator)
220233
{
221-
changed=true;
222-
node.dominators.erase(n_it++);
234+
edge_index = *cfg[edge_index].dominator;
223235
}
224236
}
225237
}
226238

239+
if (!node.dominator || *potential_dominator != *node.dominator)
240+
{
241+
node.dominator = potential_dominator;
242+
changed = true;
243+
}
244+
227245
if(changed) // fixed point for node reached?
228246
{
229247
for(const auto &edge : (post_dom ? node.in : node.out))

0 commit comments

Comments
 (0)