Skip to content

Commit 6e9e655

Browse files
authored
Merge pull request #2520 from smowton/smowton/feature/constant-propagator-selectivity
Constant propagator: add callback to filter tracked values
2 parents 9013779 + 56a487e commit 6e9e655

File tree

4 files changed

+166
-14
lines changed

4 files changed

+166
-14
lines changed

src/analyses/constant_propagator.cpp

+12-7
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,15 @@ void constant_propagator_domaint::assign_rec(
3131
valuest &values,
3232
const exprt &lhs,
3333
const exprt &rhs,
34-
const namespacet &ns)
34+
const namespacet &ns,
35+
const constant_propagator_ait *cp)
3536
{
3637
if(lhs.id()!=ID_symbol)
3738
return;
3839

40+
if(cp && !cp->should_track_value(lhs, ns))
41+
return;
42+
3943
const symbol_exprt &s=to_symbol_expr(lhs);
4044

4145
exprt tmp=rhs;
@@ -89,11 +93,11 @@ void constant_propagator_domaint::transform(
8993
const code_assignt &assignment=to_code_assign(from->code);
9094
const exprt &lhs=assignment.lhs();
9195
const exprt &rhs=assignment.rhs();
92-
assign_rec(values, lhs, rhs, ns);
96+
assign_rec(values, lhs, rhs, ns, cp);
9397
}
9498
else if(from->is_assume())
9599
{
96-
two_way_propagate_rec(from->guard, ns);
100+
two_way_propagate_rec(from->guard, ns, cp);
97101
}
98102
else if(from->is_goto())
99103
{
@@ -110,7 +114,7 @@ void constant_propagator_domaint::transform(
110114
values.set_to_bottom();
111115
else
112116
{
113-
two_way_propagate_rec(g, ns);
117+
two_way_propagate_rec(g, ns, cp);
114118
// If two way propagate is enabled then it may be possible to detect
115119
// that the branch condition is infeasible and thus the domain should
116120
// be set to bottom. Without it the domain will only be set to bottom
@@ -175,7 +179,7 @@ void constant_propagator_domaint::transform(
175179
break;
176180

177181
const symbol_exprt parameter_expr(p_it->get_identifier(), arg.type());
178-
assign_rec(values, parameter_expr, arg, ns);
182+
assign_rec(values, parameter_expr, arg, ns, cp);
179183

180184
++p_it;
181185
}
@@ -220,7 +224,8 @@ void constant_propagator_domaint::transform(
220224
/// handles equalities and conjunctions containing equalities
221225
bool constant_propagator_domaint::two_way_propagate_rec(
222226
const exprt &expr,
223-
const namespacet &ns)
227+
const namespacet &ns,
228+
const constant_propagator_ait *cp)
224229
{
225230
#ifdef DEBUG
226231
std::cout << "two_way_propagate_rec: " << format(expr) << '\n';
@@ -238,7 +243,7 @@ bool constant_propagator_domaint::two_way_propagate_rec(
238243
change = false;
239244

240245
forall_operands(it, expr)
241-
if(two_way_propagate_rec(*it, ns))
246+
if(two_way_propagate_rec(*it, ns, cp))
242247
change=true;
243248
}
244249
while(change);

src/analyses/constant_propagator.h

+39-7
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ Author: Peter Schrammel
1818
#include "ai.h"
1919
#include "dirty.h"
2020

21+
class constant_propagator_ait;
22+
2123
class constant_propagator_domaint:public ai_domain_baset
2224
{
2325
public:
@@ -143,12 +145,15 @@ class constant_propagator_domaint:public ai_domain_baset
143145
protected:
144146
void assign_rec(
145147
valuest &values,
146-
const exprt &lhs, const exprt &rhs,
147-
const namespacet &ns);
148+
const exprt &lhs,
149+
const exprt &rhs,
150+
const namespacet &ns,
151+
const constant_propagator_ait *cp);
148152

149153
bool two_way_propagate_rec(
150154
const exprt &expr,
151-
const namespacet &ns);
155+
const namespacet &ns,
156+
const constant_propagator_ait *cp);
152157

153158
bool partial_evaluate_with_all_rounding_modes(
154159
exprt &expr,
@@ -160,13 +165,35 @@ class constant_propagator_domaint:public ai_domain_baset
160165
class constant_propagator_ait:public ait<constant_propagator_domaint>
161166
{
162167
public:
163-
explicit constant_propagator_ait(const goto_functionst &goto_functions):
164-
dirty(goto_functions)
168+
typedef std::function<bool(const exprt &, const namespacet &)>
169+
should_track_valuet;
170+
171+
static bool track_all_values(const exprt &, const namespacet &)
172+
{
173+
return true;
174+
}
175+
176+
explicit constant_propagator_ait(
177+
const goto_functionst &goto_functions,
178+
should_track_valuet should_track_value = track_all_values):
179+
dirty(goto_functions),
180+
should_track_value(should_track_value)
181+
{
182+
}
183+
184+
explicit constant_propagator_ait(
185+
const goto_functiont &goto_function,
186+
should_track_valuet should_track_value = track_all_values):
187+
dirty(goto_function),
188+
should_track_value(should_track_value)
165189
{
166190
}
167191

168192
constant_propagator_ait(
169-
goto_modelt &goto_model):dirty(goto_model.goto_functions)
193+
goto_modelt &goto_model,
194+
should_track_valuet should_track_value = track_all_values):
195+
dirty(goto_model.goto_functions),
196+
should_track_value(should_track_value)
170197
{
171198
const namespacet ns(goto_model.symbol_table);
172199
operator()(goto_model.goto_functions, ns);
@@ -175,7 +202,10 @@ class constant_propagator_ait:public ait<constant_propagator_domaint>
175202

176203
constant_propagator_ait(
177204
goto_functionst::goto_functiont &goto_function,
178-
const namespacet &ns):dirty(goto_function)
205+
const namespacet &ns,
206+
should_track_valuet should_track_value = track_all_values):
207+
dirty(goto_function),
208+
should_track_value(should_track_value)
179209
{
180210
operator()(goto_function, ns);
181211
replace(goto_function, ns);
@@ -197,6 +227,8 @@ class constant_propagator_ait:public ait<constant_propagator_domaint>
197227
void replace_types_rec(
198228
const replace_symbolt &replace_const,
199229
exprt &expr);
230+
231+
should_track_valuet should_track_value;
200232
};
201233

202234
#endif // CPROVER_ANALYSES_CONSTANT_PROPAGATOR_H

unit/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ SRC = unit_tests.cpp \
99
SRC += unit_tests.cpp \
1010
analyses/ai/ai_simplify_lhs.cpp \
1111
analyses/call_graph.cpp \
12+
analyses/constant_propagator.cpp \
1213
analyses/disconnect_unreachable_nodes_in_graph.cpp \
1314
analyses/does_remove_const/does_expr_lose_const.cpp \
1415
analyses/does_remove_const/does_type_preserve_const_correctness.cpp \

unit/analyses/constant_propagator.cpp

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*******************************************************************\
2+
3+
Module: Unit test for constant propagation
4+
5+
Author: Diffblue Ltd
6+
7+
\*******************************************************************/
8+
9+
#include <testing-utils/catch.hpp>
10+
11+
#include <analyses/constant_propagator.h>
12+
13+
#include <ansi-c/ansi_c_language.h>
14+
15+
#include <goto-programs/goto_convert_functions.h>
16+
17+
#include <util/message.h>
18+
19+
static bool starts_with_x(const exprt &e, const namespacet &)
20+
{
21+
if(e.id() != ID_symbol)
22+
return false;
23+
return has_prefix(id2string(to_symbol_expr(e).get_identifier()), "x");
24+
}
25+
26+
SCENARIO("constant_propagator", "[core][analyses][constant_propagator]")
27+
{
28+
GIVEN("A simple GOTO program")
29+
{
30+
null_message_handlert null_out;
31+
32+
goto_modelt goto_model;
33+
namespacet ns(goto_model.symbol_table);
34+
35+
// Create the program:
36+
// int x = 1;
37+
// int y = 2;
38+
39+
symbolt local_x;
40+
symbolt local_y;
41+
local_x.name = "x";
42+
local_x.type = integer_typet();
43+
local_x.mode = ID_C;
44+
local_y.name = "y";
45+
local_y.type = integer_typet();
46+
local_y.mode = ID_C;
47+
48+
code_blockt code;
49+
code.copy_to_operands(code_declt(local_x.symbol_expr()));
50+
code.copy_to_operands(code_declt(local_y.symbol_expr()));
51+
code.copy_to_operands(
52+
code_assignt(
53+
local_x.symbol_expr(), constant_exprt("1", integer_typet())));
54+
code.copy_to_operands(
55+
code_assignt(
56+
local_y.symbol_expr(), constant_exprt("2", integer_typet())));
57+
58+
symbolt main_function_symbol;
59+
main_function_symbol.name = "main";
60+
main_function_symbol.type = code_typet();
61+
main_function_symbol.value = code;
62+
main_function_symbol.mode = ID_C;
63+
64+
goto_model.symbol_table.add(local_x);
65+
goto_model.symbol_table.add(local_y);
66+
goto_model.symbol_table.add(main_function_symbol);
67+
68+
goto_convert(goto_model, null_out);
69+
70+
const goto_functiont &main_function = goto_model.get_goto_function("main");
71+
72+
// Find the instruction after "y = 2;"
73+
goto_programt::const_targett test_instruction =
74+
main_function.body.instructions.begin();
75+
while(
76+
test_instruction != main_function.body.instructions.end() &&
77+
(!test_instruction->is_assign() ||
78+
to_code_assign(test_instruction->code).lhs() != local_y.symbol_expr()))
79+
{
80+
++test_instruction;
81+
}
82+
83+
REQUIRE(test_instruction != main_function.body.instructions.end());
84+
++test_instruction;
85+
86+
WHEN("We apply conventional constant propagation")
87+
{
88+
constant_propagator_ait constant_propagator(main_function);
89+
constant_propagator(main_function, ns);
90+
91+
THEN("The propagator should discover values for both 'x' and 'y'")
92+
{
93+
const auto &final_domain = constant_propagator[test_instruction];
94+
95+
REQUIRE(final_domain.values.is_constant(local_x.symbol_expr()));
96+
REQUIRE(final_domain.values.is_constant(local_y.symbol_expr()));
97+
}
98+
}
99+
100+
WHEN("We apply constant propagation for symbols beginning with 'x'")
101+
{
102+
constant_propagator_ait constant_propagator(main_function, starts_with_x);
103+
constant_propagator(main_function, ns);
104+
105+
THEN("The propagator should discover a value for 'x' but not 'y'")
106+
{
107+
const auto &final_domain = constant_propagator[test_instruction];
108+
109+
REQUIRE(final_domain.values.is_constant(local_x.symbol_expr()));
110+
REQUIRE(!final_domain.values.is_constant(local_y.symbol_expr()));
111+
}
112+
}
113+
}
114+
}

0 commit comments

Comments
 (0)