Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit c1cac71

Browse files
committedAug 21, 2019
Dominator analysis: analyse on basic-block granularity
Previously this used instruction granularity, which especially combined with a naive dominator set (not a dominator tree) can waste a great deal of time and memory computing and storing the dominator sets. Now that cfg_dominatorst works on a basic-block granularity, natural_loopst does as well.
1 parent 18ba777 commit c1cac71

18 files changed

+691
-223
lines changed
 

‎jbmc/src/java_bytecode/java_local_variable_table.cpp

+24-11
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ Author: Chris Smowton, chris.smowton@diffblue.com
2424
// Specialise the CFG representation to work over Java instead of GOTO programs.
2525
// This must be done at global scope due to template resolution rules.
2626

27+
// Specialise get-key function for cfg_dominators_templatet:
28+
template <>
29+
inline std::size_t key_to_dense_integer(const uint16_t &key)
30+
{
31+
return key;
32+
}
33+
2734
template <class T>
2835
struct procedure_local_cfg_baset<
2936
T,
@@ -85,19 +92,19 @@ struct procedure_local_cfg_baset<
8592
}
8693
}
8794

88-
java_bytecode_convert_methodt::method_offsett
89-
get_first_node(const method_with_amapt &args) const
95+
static java_bytecode_convert_methodt::method_offsett
96+
get_first_node(const method_with_amapt &args)
9097
{
9198
return args.second.begin()->first;
9299
}
93100

94-
java_bytecode_convert_methodt::method_offsett
95-
get_last_node(const method_with_amapt &args) const
101+
static java_bytecode_convert_methodt::method_offsett
102+
get_last_node(const method_with_amapt &args)
96103
{
97104
return (--args.second.end())->first;
98105
}
99106

100-
bool nodes_empty(const method_with_amapt &args) const
107+
static bool nodes_empty(const method_with_amapt &args)
101108
{
102109
return args.second.empty();
103110
}
@@ -442,13 +449,19 @@ static java_bytecode_convert_methodt::method_offsett get_common_dominator(
442449
candidate_dominators;
443450
for(auto v : merge_vars)
444451
{
445-
const auto &dominator_nodeidx=
452+
const auto &var_start_basic_block =
446453
dominator_analysis.cfg.entry_map.at(v->var.start_pc);
447-
const auto &this_var_doms=
448-
dominator_analysis.cfg[dominator_nodeidx].dominators;
449-
for(const auto this_var_dom : this_var_doms)
450-
if(this_var_dom<=first_pc)
451-
candidate_dominators.push_back(this_var_dom);
454+
const auto &this_var_dom_blocks =
455+
dominator_analysis.cfg[var_start_basic_block].dominators;
456+
for(const auto this_var_dom_block_index : this_var_dom_blocks)
457+
{
458+
const auto &this_var_dom_block =
459+
dominator_analysis.cfg[this_var_dom_block_index].block;
460+
// Only consider placing variable declarations at the head of
461+
// a basic block (which conveniently is always a safe choice, even
462+
// for a live range starting midway through a block)
463+
candidate_dominators.push_back(this_var_dom_block.front());
464+
}
452465
}
453466
std::sort(candidate_dominators.begin(), candidate_dominators.end());
454467

‎src/analyses/cfg_dominators.h

+85-17
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,68 @@ template <class P, class T, bool post_dom>
2626
class cfg_dominators_templatet
2727
{
2828
public:
29-
typedef std::set<T> target_sett;
29+
typedef std::set<std::size_t> target_sett;
3030

3131
struct nodet
3232
{
3333
target_sett dominators;
3434
};
3535

36-
typedef procedure_local_cfg_baset<nodet, P, T> cfgt;
36+
typedef cfg_basic_blockst<procedure_local_cfg_baset, nodet, P, T> cfgt;
3737
cfgt cfg;
3838

3939
void operator()(P &program);
4040

4141
T entry_node;
4242

43+
/// Returns true if basic block \p lhs [post]dominates \p rhs
44+
bool basic_block_dominates(std::size_t lhs, std::size_t rhs) const
45+
{
46+
return cfg[rhs].dominators.count(lhs);
47+
}
48+
49+
/// Returns true if program point \p lhs [post]dominates \p rhs
50+
bool dominates_same_block(T lhs, T rhs, std::size_t block) const;
51+
52+
bool dominates(T lhs, T rhs) const
53+
{
54+
const auto lhs_block = cfg.entry_map.at(lhs);
55+
const auto rhs_block = cfg.entry_map.at(rhs);
56+
57+
if(lhs == rhs)
58+
return true;
59+
60+
if(lhs_block != rhs_block)
61+
return basic_block_dominates(lhs_block, rhs_block);
62+
else
63+
return dominates_same_block(lhs, rhs, lhs_block);
64+
}
65+
66+
const target_sett &basic_block_dominators(std::size_t block) const
67+
{
68+
return cfg[block].dominators;
69+
}
70+
71+
const typename cfgt::nodet &get_node(const T &program_point) const
72+
{
73+
return cfg[cfg.entry_map.at(program_point)];
74+
}
75+
76+
typename cfgt::nodet &get_node(const T &program_point)
77+
{
78+
return cfg[cfg.entry_map.at(program_point)];
79+
}
80+
81+
bool basic_block_reachable(std::size_t block) const
82+
{
83+
return !cfg[block].dominators.empty();
84+
}
85+
86+
bool instruction_reachable(T instruction) const
87+
{
88+
return basic_block_reachable(cfg.entry_map.at(instruction));
89+
}
90+
4391
void output(std::ostream &) const;
4492

4593
protected:
@@ -76,32 +124,33 @@ void cfg_dominators_templatet<P, T, post_dom>::initialise(P &program)
76124
template <class P, class T, bool post_dom>
77125
void cfg_dominators_templatet<P, T, post_dom>::fixedpoint(P &program)
78126
{
79-
std::list<T> worklist;
127+
std::list<typename cfgt::node_indext> worklist;
80128

81129
if(cfg.nodes_empty(program))
82130
return;
83131

84132
if(post_dom)
85-
entry_node=cfg.get_last_node(program);
133+
entry_node = cfgt::get_last_node(program);
86134
else
87-
entry_node=cfg.get_first_node(program);
88-
typename cfgt::nodet &n=cfg[cfg.entry_map[entry_node]];
89-
n.dominators.insert(entry_node);
135+
entry_node = cfgt::get_first_node(program);
136+
const auto entry_node_index = cfg.entry_map[entry_node];
137+
typename cfgt::nodet &n = cfg[entry_node_index];
138+
n.dominators.insert(entry_node_index);
90139

91140
for(typename cfgt::edgest::const_iterator
92141
s_it=(post_dom?n.in:n.out).begin();
93142
s_it!=(post_dom?n.in:n.out).end();
94143
++s_it)
95-
worklist.push_back(cfg[s_it->first].PC);
144+
worklist.push_back(s_it->first);
96145

97146
while(!worklist.empty())
98147
{
99148
// get node from worklist
100-
T current=worklist.front();
149+
const auto current = worklist.front();
101150
worklist.pop_front();
102151

103152
bool changed=false;
104-
typename cfgt::nodet &node=cfg[cfg.entry_map[current]];
153+
typename cfgt::nodet &node = cfg[current];
105154
if(node.dominators.empty())
106155
{
107156
for(const auto &edge : (post_dom ? node.out : node.in))
@@ -158,12 +207,33 @@ void cfg_dominators_templatet<P, T, post_dom>::fixedpoint(P &program)
158207
{
159208
for(const auto &edge : (post_dom ? node.in : node.out))
160209
{
161-
worklist.push_back(cfg[edge.first].PC);
210+
worklist.push_back(edge.first);
162211
}
163212
}
164213
}
165214
}
166215

216+
template <class P, class T, bool post_dom>
217+
bool cfg_dominators_templatet<P, T, post_dom>::dominates_same_block(
218+
T lhs,
219+
T rhs,
220+
std::size_t block) const
221+
{
222+
// Special case when the program points belong to the same block: lhs
223+
// dominates rhs iff it is <= rhs in program order (or the reverse if we're
224+
// a postdominator analysis)
225+
226+
for(const auto &instruction : cfg[block].block)
227+
{
228+
if(instruction == lhs)
229+
return !post_dom;
230+
else if(instruction == rhs)
231+
return post_dom;
232+
}
233+
234+
UNREACHABLE; // Entry map is inconsistent with block members?
235+
}
236+
167237
/// Pretty-print a single node in the dominator tree. Supply a specialisation if
168238
/// operator<< is not sufficient.
169239
/// \par parameters: `node` to print and stream `out` to pretty-print it to
@@ -184,22 +254,20 @@ inline void dominators_pretty_print_node(
184254
template <class P, class T, bool post_dom>
185255
void cfg_dominators_templatet<P, T, post_dom>::output(std::ostream &out) const
186256
{
187-
for(const auto &node : cfg.entry_map)
257+
for(typename cfgt::node_indext i = 0; i < cfg.size(); ++i)
188258
{
189-
auto n=node.first;
190-
191-
dominators_pretty_print_node(n, out);
259+
out << "Block " << dominators_pretty_print_node(cfg[i].block.at(0), out);
192260
if(post_dom)
193261
out << " post-dominated by ";
194262
else
195263
out << " dominated by ";
196264
bool first=true;
197-
for(const auto &d : cfg[node.second].dominators)
265+
for(const auto &d : cfg[i].dominators)
198266
{
199267
if(!first)
200268
out << ", ";
201269
first=false;
202-
dominators_pretty_print_node(d, out);
270+
dominators_pretty_print_node(cfg[d].block.at(0), out);
203271
}
204272
out << "\n";
205273
}

‎src/analyses/dependence_graph.cpp

+4-15
Original file line numberDiff line numberDiff line change
@@ -97,22 +97,11 @@ 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];
108-
109-
// successors of M
110-
for(const auto &edge : m.out)
100+
for(const auto &candidate_successor :
101+
goto_programt::get_well_formed_instruction_successors(
102+
control_dep_candidate))
111103
{
112-
const cfg_post_dominatorst::cfgt::nodet &m_s=
113-
pd.cfg[edge.first];
114-
115-
if(m_s.dominators.find(to)!=m_s.dominators.end())
104+
if(pd.dominates(to, candidate_successor))
116105
post_dom_one=true;
117106
else
118107
post_dom_all=false;

0 commit comments

Comments
 (0)
Please sign in to comment.