Skip to content

Commit 9620ae6

Browse files
committed
cfg_dominatorst: introduce a public interface
This eliminates most use of cfg_dominatorst::cfg, hiding the implementation behind a clean interface.
1 parent adf685f commit 9620ae6

File tree

6 files changed

+97
-79
lines changed

6 files changed

+97
-79
lines changed

src/analyses/cfg_dominators.h

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,17 @@ Author: Georg Weissenbacher, [email protected]
2222
#include <goto-programs/goto_program.h>
2323
#include <goto-programs/cfg.h>
2424

25+
/// Dominator graph. This computes a control-flow graph (see \ref cfgt) and
26+
/// decorates it with dominator sets per program point, following
27+
/// "A Simple, Fast Dominance Algorithm" by Cooper et al.
28+
/// Templated over the program type (P) and program point type (T), which need
29+
/// to be supported by \ref cfgt. Can compute either dominators or
30+
/// postdominators depending on template parameter `post_dom`.
31+
/// Use \ref cfg_dominators_templatet::dominates to directly query dominance,
32+
/// or \ref cfg_dominators_templatet::get_node to get the \ref cfgt graph node
33+
/// corresponding to a program point, including the in- and out-edges provided
34+
/// by \ref cfgt as well as the dominator set computed by this class.
35+
/// See also https://en.wikipedia.org/wiki/Dominator_(graph_theory)
2536
template <class P, class T, bool post_dom>
2637
class cfg_dominators_templatet
2738
{
@@ -38,6 +49,59 @@ class cfg_dominators_templatet
3849

3950
void operator()(P &program);
4051

52+
/// Get the graph node (which gives dominators, predecessors and successors)
53+
/// for \p program_point
54+
const typename cfgt::nodet &get_node(const T &program_point) const
55+
{
56+
return cfg[cfg.entry_map.at(program_point)];
57+
}
58+
59+
/// Get the graph node (which gives dominators, predecessors and successors)
60+
/// for \p program_point
61+
typename cfgt::nodet &get_node(const T &program_point)
62+
{
63+
return cfg[cfg.entry_map.at(program_point)];
64+
}
65+
66+
/// Returns true if the program point corresponding to \p rhs_node is
67+
/// dominated by program point \p lhs. Saves node lookup compared to the
68+
/// dominates overload that takes two program points, so this version is
69+
/// preferable if you intend to check more than one potential dominator.
70+
/// Note by definition all program points dominate themselves.
71+
bool dominates(T lhs, const nodet &rhs_node) const
72+
{
73+
return rhs_node.dominators.count(lhs);
74+
}
75+
76+
/// Returns true if program point \p lhs dominates \p rhs.
77+
/// Note by definition all program points dominate themselves.
78+
bool dominates(T lhs, T rhs) const
79+
{
80+
return dominates(lhs, get_node(rhs));
81+
}
82+
83+
/// Returns true if the program point for \p program_point_node is reachable
84+
/// from the entry point. Saves a lookup compared to the overload taking a
85+
/// program point, so use this overload if you already have the node.
86+
bool program_point_reachable(const nodet &program_point_node) const
87+
{
88+
// Dominator analysis walks from the entry point, so a side-effect is to
89+
// identify unreachable program points (those which don't dominate even
90+
// themselves).
91+
return !program_point_node.dominators.empty();
92+
}
93+
94+
/// Returns true if the program point for \p program_point_node is reachable
95+
/// from the entry point. Saves a lookup compared to the overload taking a
96+
/// program point, so use this overload if you already have the node.
97+
bool program_point_reachable(T program_point) const
98+
{
99+
// Dominator analysis walks from the entry point, so a side-effect is to
100+
// identify unreachable program points (those which don't dominate even
101+
// themselves).
102+
return program_point_reachable(get_node(program_point));
103+
}
104+
41105
T entry_node;
42106

43107
void output(std::ostream &) const;

src/analyses/dependence_graph.cpp

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -97,18 +97,15 @@ void dep_graph_domaint::control_dependencies(
9797

9898
// we could hard-code assume and goto handling here to improve
9999
// performance
100-
cfg_post_dominatorst::cfgt::entry_mapt::const_iterator e =
101-
pd.cfg.entry_map.find(control_dep_candidate);
102-
103-
INVARIANT(
104-
e != pd.cfg.entry_map.end(), "cfg must have an entry for every location");
105-
106-
const cfg_post_dominatorst::cfgt::nodet &m=
107-
pd.cfg[e->second];
100+
const cfg_post_dominatorst::cfgt::nodet &m =
101+
pd.get_node(control_dep_candidate);
108102

109103
// successors of M
110104
for(const auto &edge : m.out)
111105
{
106+
// Could use pd.dominates(to, control_dep_candidate) but this would impose
107+
// another dominator node lookup per call to this function, which is too
108+
// expensive.
112109
const cfg_post_dominatorst::cfgt::nodet &m_s=
113110
pd.cfg[edge.first];
114111

src/analyses/natural_loops.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,16 +122,13 @@ void natural_loops_templatet<P, T>::compute(P &program)
122122

123123
if(target->location_number<=m_it->location_number)
124124
{
125-
const nodet &node=
126-
cfg_dominators.cfg[cfg_dominators.cfg.entry_map[m_it]];
127-
128125
#ifdef DEBUG
129126
std::cout << "Computing loop for "
130127
<< m_it->location_number << " -> "
131128
<< target->location_number << "\n";
132129
#endif
133130

134-
if(node.dominators.find(target)!=node.dominators.end())
131+
if(cfg_dominators.dominates(target, m_it))
135132
compute_natural_loop(m_it, target);
136133
}
137134
}
@@ -159,8 +156,7 @@ void natural_loops_templatet<P, T>::compute_natural_loop(T m, T n)
159156
T p=stack.top();
160157
stack.pop();
161158

162-
const nodet &node=
163-
cfg_dominators.cfg[cfg_dominators.cfg.entry_map[p]];
159+
const nodet &node = cfg_dominators.get_node(p);
164160

165161
for(const auto &edge : node.in)
166162
{

src/goto-instrument/full_slicer.cpp

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -151,16 +151,10 @@ void full_slicert::add_jumps(
151151
const irep_idt &id = j.function_id;
152152
const cfg_post_dominatorst &pd=post_dominators.at(id);
153153

154-
cfg_post_dominatorst::cfgt::entry_mapt::const_iterator e=
155-
pd.cfg.entry_map.find(j.PC);
156-
157-
assert(e!=pd.cfg.entry_map.end());
158-
159-
const cfg_post_dominatorst::cfgt::nodet &n=
160-
pd.cfg[e->second];
154+
const auto &j_PC_node = pd.get_node(j.PC);
161155

162156
// find the nearest post-dominator in slice
163-
if(n.dominators.find(lex_succ)==n.dominators.end())
157+
if(!pd.dominates(lex_succ, j_PC_node))
164158
{
165159
add_to_queue(queue, *it, lex_succ);
166160
jumps.erase(it);
@@ -171,9 +165,9 @@ void full_slicert::add_jumps(
171165
// lex_succ
172166
goto_programt::const_targett nearest=lex_succ;
173167
std::size_t post_dom_size=0;
174-
for(cfg_dominatorst::target_sett::const_iterator
175-
d_it=n.dominators.begin();
176-
d_it!=n.dominators.end();
168+
for(cfg_dominatorst::target_sett::const_iterator d_it =
169+
j_PC_node.dominators.begin();
170+
d_it != j_PC_node.dominators.end();
177171
++d_it)
178172
{
179173
cfgt::entry_mapt::const_iterator entry=
@@ -186,18 +180,12 @@ void full_slicert::add_jumps(
186180
INVARIANT(id==id2,
187181
"goto/jump expected to be within a single function");
188182

189-
cfg_post_dominatorst::cfgt::entry_mapt::const_iterator e2=
190-
pd.cfg.entry_map.find(*d_it);
191-
192-
assert(e2!=pd.cfg.entry_map.end());
193-
194-
const cfg_post_dominatorst::cfgt::nodet &n2=
195-
pd.cfg[e2->second];
183+
const auto &postdom_node = pd.get_node(*d_it);
196184

197-
if(n2.dominators.size()>post_dom_size)
185+
if(postdom_node.dominators.size() > post_dom_size)
198186
{
199187
nearest=*d_it;
200-
post_dom_size=n2.dominators.size();
188+
post_dom_size = postdom_node.dominators.size();
201189
}
202190
}
203191
}

src/goto-instrument/goto_program2code.cpp

Lines changed: 9 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -763,14 +763,10 @@ bool goto_program2codet::set_block_end_points(
763763
case_end!=upper_bound;
764764
++case_end)
765765
{
766-
cfg_dominatorst::cfgt::entry_mapt::const_iterator i_entry=
767-
dominators.cfg.entry_map.find(case_end);
768-
assert(i_entry!=dominators.cfg.entry_map.end());
769-
const cfg_dominatorst::cfgt::nodet &n=
770-
dominators.cfg[i_entry->second];
766+
const auto &case_end_node = dominators.get_node(case_end);
771767

772768
// ignore dead instructions for the following checks
773-
if(n.dominators.empty())
769+
if(!dominators.program_point_reachable(case_end_node))
774770
{
775771
// simplification may have figured out that a case is unreachable
776772
// this is possibly getting too weird, abort to be safe
@@ -781,7 +777,7 @@ bool goto_program2codet::set_block_end_points(
781777
}
782778

783779
// find the last instruction dominated by the case start
784-
if(n.dominators.find(it->case_start)==n.dominators.end())
780+
if(!dominators.dominates(it->case_start, case_end_node))
785781
break;
786782

787783
if(!processed_locations.insert(case_end->location_number).second)
@@ -818,13 +814,7 @@ bool goto_program2codet::remove_default(
818814
next_case!=goto_program.instructions.end();
819815
++next_case)
820816
{
821-
cfg_dominatorst::cfgt::entry_mapt::const_iterator i_entry=
822-
dominators.cfg.entry_map.find(next_case);
823-
assert(i_entry!=dominators.cfg.entry_map.end());
824-
const cfg_dominatorst::cfgt::nodet &n=
825-
dominators.cfg[i_entry->second];
826-
827-
if(!n.dominators.empty())
817+
if(dominators.program_point_reachable(next_case))
828818
break;
829819
}
830820

@@ -876,10 +866,7 @@ goto_programt::const_targett goto_program2codet::convert_goto_switch(
876866

877867
// always use convert_goto_if for dead code as the construction below relies
878868
// on effective dominator information
879-
cfg_dominatorst::cfgt::entry_mapt::const_iterator t_entry=
880-
dominators.cfg.entry_map.find(target);
881-
assert(t_entry!=dominators.cfg.entry_map.end());
882-
if(dominators.cfg[t_entry->second].dominators.empty())
869+
if(!dominators.program_point_reachable(target))
883870
return convert_goto_if(target, upper_bound, dest);
884871

885872
// maybe, let's try some more
@@ -1019,13 +1006,7 @@ goto_programt::const_targett goto_program2codet::convert_goto_switch(
10191006
if(processed_locations.find(it->location_number)==
10201007
processed_locations.end())
10211008
{
1022-
cfg_dominatorst::cfgt::entry_mapt::const_iterator it_entry=
1023-
dominators.cfg.entry_map.find(it);
1024-
assert(it_entry!=dominators.cfg.entry_map.end());
1025-
const cfg_dominatorst::cfgt::nodet &n=
1026-
dominators.cfg[it_entry->second];
1027-
1028-
if(!n.dominators.empty())
1009+
if(dominators.program_point_reachable(it))
10291010
{
10301011
toplevel_block.swap(toplevel_block_bak);
10311012
return convert_goto_if(orig_target, upper_bound, dest);
@@ -1128,13 +1109,7 @@ goto_programt::const_targett goto_program2codet::convert_goto_break_continue(
11281109
next!=upper_bound && next!=goto_program.instructions.end();
11291110
++next)
11301111
{
1131-
cfg_dominatorst::cfgt::entry_mapt::const_iterator i_entry=
1132-
dominators.cfg.entry_map.find(next);
1133-
assert(i_entry!=dominators.cfg.entry_map.end());
1134-
const cfg_dominatorst::cfgt::nodet &n=
1135-
dominators.cfg[i_entry->second];
1136-
1137-
if(!n.dominators.empty())
1112+
if(dominators.program_point_reachable(next))
11381113
break;
11391114
}
11401115

@@ -1168,13 +1143,7 @@ goto_programt::const_targett goto_program2codet::convert_goto_break_continue(
11681143
after_loop!=goto_program.instructions.end();
11691144
++after_loop)
11701145
{
1171-
cfg_dominatorst::cfgt::entry_mapt::const_iterator i_entry=
1172-
dominators.cfg.entry_map.find(after_loop);
1173-
assert(i_entry!=dominators.cfg.entry_map.end());
1174-
const cfg_dominatorst::cfgt::nodet &n=
1175-
dominators.cfg[i_entry->second];
1176-
1177-
if(!n.dominators.empty())
1146+
if(dominators.program_point_reachable(after_loop))
11781147
break;
11791148
}
11801149

@@ -1207,15 +1176,10 @@ goto_programt::const_targett goto_program2codet::convert_goto_goto(
12071176
return target;
12081177

12091178
const cfg_dominatorst &dominators=loops.get_dominator_info();
1210-
cfg_dominatorst::cfgt::entry_mapt::const_iterator it_entry=
1211-
dominators.cfg.entry_map.find(target);
1212-
assert(it_entry!=dominators.cfg.entry_map.end());
1213-
const cfg_dominatorst::cfgt::nodet &n=
1214-
dominators.cfg[it_entry->second];
12151179

12161180
// skip dead goto L as the label might be skipped if it is dead
12171181
// as well and at the end of a case block
1218-
if(n.dominators.empty())
1182+
if(!dominators.program_point_reachable(target))
12191183
return target;
12201184

12211185
std::stringstream label;

src/goto-programs/cfg.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,15 @@ class cfg_baset:public grapht< cfg_base_nodet<T, I> >
102102

103103
return e.first->second;
104104
}
105+
106+
entryt &at(const goto_programt::const_targett &t)
107+
{
108+
return data.at(t);
109+
}
110+
const entryt &at(const goto_programt::const_targett &t) const
111+
{
112+
return data.at(t);
113+
}
105114
};
106115
entry_mapt entry_map;
107116

0 commit comments

Comments
 (0)