Skip to content

Commit ec85415

Browse files
authored
Merge pull request #7331 from tautschnig/feature/extract-constant
Byte extract and extract bits can be constant
2 parents c3b72e4 + 2ba7118 commit ec85415

File tree

18 files changed

+137
-49
lines changed

18 files changed

+137
-49
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--show-vcc
4+
main::1::m!0@1#1 = .*byte_extract_(big|little)_endian\(cast\(44, signedbv\[\d+\]\*\), 0, signedbv\[\d+\]\).*
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
^warning: ignoring

src/analyses/constant_propagator.cpp

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ void constant_propagator_domaint::assign_rec(
100100
exprt tmp = rhs;
101101
partial_evaluate(dest_values, tmp, ns);
102102

103-
if(dest_values.is_constant(tmp))
103+
if(dest_values.is_constant(tmp, ns))
104104
{
105105
DATA_INVARIANT(
106106
ns.lookup(s).type == tmp.type(),
@@ -393,7 +393,7 @@ bool constant_propagator_domaint::two_way_propagate_rec(
393393
// two-way propagation
394394
valuest copy_values=values;
395395
assign_rec(copy_values, lhs, rhs, ns, cp, false);
396-
if(!values.is_constant(rhs) || values.is_constant(lhs))
396+
if(!values.is_constant(rhs, ns) || values.is_constant(lhs, ns))
397397
assign_rec(values, rhs, lhs, ns, cp, false);
398398
change = values.meet(copy_values, ns);
399399
}
@@ -419,9 +419,10 @@ bool constant_propagator_domaint::ai_simplify(
419419
class constant_propagator_is_constantt : public is_constantt
420420
{
421421
public:
422-
explicit constant_propagator_is_constantt(
423-
const replace_symbolt &replace_const)
424-
: replace_const(replace_const)
422+
constant_propagator_is_constantt(
423+
const replace_symbolt &replace_const,
424+
const namespacet &ns)
425+
: is_constantt(ns), replace_const(replace_const)
425426
{
426427
}
427428

@@ -442,14 +443,18 @@ class constant_propagator_is_constantt : public is_constantt
442443
const replace_symbolt &replace_const;
443444
};
444445

445-
bool constant_propagator_domaint::valuest::is_constant(const exprt &expr) const
446+
bool constant_propagator_domaint::valuest::is_constant(
447+
const exprt &expr,
448+
const namespacet &ns) const
446449
{
447-
return constant_propagator_is_constantt(replace_const)(expr);
450+
return constant_propagator_is_constantt(replace_const, ns)(expr);
448451
}
449452

450-
bool constant_propagator_domaint::valuest::is_constant(const irep_idt &id) const
453+
bool constant_propagator_domaint::valuest::is_constant(
454+
const irep_idt &id,
455+
const namespacet &ns) const
451456
{
452-
return constant_propagator_is_constantt(replace_const).is_constant(id);
457+
return constant_propagator_is_constantt(replace_const, ns).is_constant(id);
453458
}
454459

455460
/// Do not call this when iterating over replace_const.expr_map!
@@ -657,7 +662,7 @@ bool constant_propagator_domaint::partial_evaluate(
657662
// if the current rounding mode is top we can
658663
// still get a non-top result by trying all rounding
659664
// modes and checking if the results are all the same
660-
if(!known_values.is_constant(rounding_mode_identifier()))
665+
if(!known_values.is_constant(rounding_mode_identifier(), ns))
661666
return partial_evaluate_with_all_rounding_modes(known_values, expr, ns);
662667

663668
return replace_constants_and_simplify(known_values, expr, ns);

src/analyses/constant_propagator.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,9 @@ class constant_propagator_domaint:public ai_domain_baset
123123

124124
void set_dirty_to_top(const dirtyt &dirty, const namespacet &ns);
125125

126-
bool is_constant(const exprt &expr) const;
126+
bool is_constant(const exprt &expr, const namespacet &ns) const;
127127

128-
bool is_constant(const irep_idt &id) const;
128+
bool is_constant(const irep_idt &id, const namespacet &ns) const;
129129

130130
bool is_empty() const
131131
{

src/ansi-c/c_typecheck_expr.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4467,13 +4467,11 @@ void c_typecheck_baset::typecheck_side_effect_assignment(
44674467
class is_compile_time_constantt : public is_constantt
44684468
{
44694469
public:
4470-
explicit is_compile_time_constantt(const namespacet &ns) : ns(ns)
4470+
explicit is_compile_time_constantt(const namespacet &ns) : is_constantt(ns)
44714471
{
44724472
}
44734473

44744474
protected:
4475-
const namespacet &ns;
4476-
44774475
bool is_constant(const exprt &e) const override
44784476
{
44794477
if(e.id() == ID_infinity)

src/goto-instrument/contracts/contracts.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ void code_contractst::check_apply_loop_contracts(
213213

214214
// If the set contains pairs (i, a[i]),
215215
// we widen them to (i, __CPROVER_POINTER_OBJECT(a))
216-
widen_assigns(to_havoc);
216+
widen_assigns(to_havoc, ns);
217217

218218
log.debug() << "No loop assigns clause provided. Inferred targets: {";
219219
// Add inferred targets to the loop assigns clause.

src/goto-instrument/contracts/utils.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,11 +247,11 @@ bool is_assigns_clause_replacement_tracking_comment(const irep_idt &comment)
247247
std::string::npos;
248248
}
249249

250-
void widen_assigns(assignst &assigns)
250+
void widen_assigns(assignst &assigns, const namespacet &ns)
251251
{
252252
assignst result;
253253

254-
havoc_utils_is_constantt is_constant(assigns);
254+
havoc_utils_is_constantt is_constant(assigns, ns);
255255

256256
for(const auto &e : assigns)
257257
{

src/goto-instrument/contracts/utils.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class havoc_if_validt : public havoc_utilst
2424
{
2525
public:
2626
havoc_if_validt(const assignst &mod, const namespacet &ns)
27-
: havoc_utilst(mod), ns(ns)
27+
: havoc_utilst(mod, ns), ns(ns)
2828
{
2929
}
3030

@@ -175,7 +175,7 @@ bool is_assigns_clause_replacement_tracking_comment(const irep_idt &comment);
175175
/// with a non-constant offset, e.g. a[i] or *(b+i) with a non-constant `i`,
176176
/// then replace it by the entire underlying object. Otherwise, e.g. for a[i] or
177177
/// *(b+i) when `i` is a known constant, keep the expression in the result.
178-
void widen_assigns(assignst &assigns);
178+
void widen_assigns(assignst &assigns, const namespacet &ns);
179179

180180
/// This function recursively searches \p expression to find nested or
181181
/// non-nested quantified expressions. When a quantified expression is found,

src/goto-instrument/havoc_loops.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,13 @@ class havoc_loopst
2727

2828
havoc_loopst(
2929
function_assignst &_function_assigns,
30-
goto_functiont &_goto_function)
30+
goto_functiont &_goto_function,
31+
const namespacet &ns)
3132
: goto_function(_goto_function),
3233
local_may_alias(_goto_function),
3334
function_assigns(_function_assigns),
34-
natural_loops(_goto_function.body)
35+
natural_loops(_goto_function.body),
36+
ns(ns)
3537
{
3638
havoc_loops();
3739
}
@@ -41,6 +43,7 @@ class havoc_loopst
4143
local_may_aliast local_may_alias;
4244
function_assignst &function_assigns;
4345
natural_loops_mutablet natural_loops;
46+
const namespacet &ns;
4447

4548
typedef std::set<exprt> assignst;
4649
typedef const natural_loops_mutablet::natural_loopt loopt;
@@ -66,7 +69,7 @@ void havoc_loopst::havoc_loop(
6669

6770
// build the havocking code
6871
goto_programt havoc_code;
69-
havoc_utilst havoc_gen(assigns);
72+
havoc_utilst havoc_gen(assigns, ns);
7073
havoc_gen.append_full_havoc_code(loop_head->source_location(), havoc_code);
7174

7275
// Now havoc at the loop head. Use insert_swap to
@@ -118,5 +121,8 @@ void havoc_loops(goto_modelt &goto_model)
118121
function_assignst function_assigns(goto_model.goto_functions);
119122

120123
for(auto &gf_entry : goto_model.goto_functions.function_map)
121-
havoc_loopst(function_assigns, gf_entry.second);
124+
{
125+
havoc_loopst(
126+
function_assigns, gf_entry.second, namespacet{goto_model.symbol_table});
127+
}
122128
}

src/goto-instrument/havoc_utils.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ typedef std::set<exprt> assignst;
2727
class havoc_utils_is_constantt : public is_constantt
2828
{
2929
public:
30-
explicit havoc_utils_is_constantt(const assignst &mod) : assigns(mod)
30+
explicit havoc_utils_is_constantt(const assignst &mod, const namespacet &ns)
31+
: is_constantt(ns), assigns(mod)
3132
{
3233
}
3334

@@ -48,7 +49,8 @@ class havoc_utils_is_constantt : public is_constantt
4849
class havoc_utilst
4950
{
5051
public:
51-
explicit havoc_utilst(const assignst &mod) : assigns(mod), is_constant(mod)
52+
explicit havoc_utilst(const assignst &mod, const namespacet &ns)
53+
: assigns(mod), is_constant(mod, ns)
5254
{
5355
}
5456

src/goto-instrument/k_induction.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,16 @@ class k_inductiont
2828
goto_functiont &_goto_function,
2929
bool _base_case,
3030
bool _step_case,
31-
unsigned _k)
31+
unsigned _k,
32+
const namespacet &ns)
3233
: function_id(_function_id),
3334
goto_function(_goto_function),
3435
local_may_alias(_goto_function),
3536
natural_loops(_goto_function.body),
3637
base_case(_base_case),
3738
step_case(_step_case),
38-
k(_k)
39+
k(_k),
40+
ns(ns)
3941
{
4042
k_induction();
4143
}
@@ -49,6 +51,8 @@ class k_inductiont
4951
const bool base_case, step_case;
5052
const unsigned k;
5153

54+
const namespacet &ns;
55+
5256
void k_induction();
5357

5458
void process_loop(
@@ -97,7 +101,7 @@ void k_inductiont::process_loop(
97101

98102
// build the havocking code
99103
goto_programt havoc_code;
100-
havoc_utilst havoc_gen(assigns);
104+
havoc_utilst havoc_gen(assigns, ns);
101105
havoc_gen.append_full_havoc_code(loop_head->source_location(), havoc_code);
102106

103107
// unwind to get k+1 copies
@@ -165,5 +169,13 @@ void k_induction(
165169
unsigned k)
166170
{
167171
for(auto &gf_entry : goto_model.goto_functions.function_map)
168-
k_inductiont(gf_entry.first, gf_entry.second, base_case, step_case, k);
172+
{
173+
k_inductiont(
174+
gf_entry.first,
175+
gf_entry.second,
176+
base_case,
177+
step_case,
178+
k,
179+
namespacet{goto_model.symbol_table});
180+
}
169181
}

src/goto-symex/goto_state.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ void goto_statet::apply_condition(
9191
if(is_ssa_expr(rhs))
9292
std::swap(lhs, rhs);
9393

94-
if(is_ssa_expr(lhs) && goto_symex_is_constantt()(rhs))
94+
if(is_ssa_expr(lhs) && goto_symex_is_constantt(ns)(rhs))
9595
{
9696
const ssa_exprt &ssa_lhs = to_ssa_expr(lhs);
9797
INVARIANT(
@@ -141,7 +141,7 @@ void goto_statet::apply_condition(
141141
if(is_ssa_expr(rhs))
142142
std::swap(lhs, rhs);
143143

144-
if(!is_ssa_expr(lhs) || !goto_symex_is_constantt()(rhs))
144+
if(!is_ssa_expr(lhs) || !goto_symex_is_constantt(ns)(rhs))
145145
return;
146146

147147
if(rhs.is_true())

src/goto-symex/goto_symex_is_constant.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ Author: Michael Tautschig, [email protected]
1717

1818
class goto_symex_is_constantt : public is_constantt
1919
{
20+
public:
21+
explicit goto_symex_is_constantt(const namespacet &ns) : is_constantt(ns)
22+
{
23+
}
24+
2025
protected:
2126
bool is_constant(const exprt &expr) const override
2227
{

src/goto-symex/goto_symex_state.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ renamedt<ssa_exprt, L2> goto_symex_statet::assignment(
110110
"pointer handling for concurrency is unsound");
111111

112112
// Update constant propagation map -- the RHS is L2
113-
if(!is_shared && record_value && goto_symex_is_constantt()(rhs))
113+
if(!is_shared && record_value && goto_symex_is_constantt(ns)(rhs))
114114
{
115115
const auto propagation_entry = propagation.find(l1_identifier);
116116
if(!propagation_entry.has_value())

src/goto-symex/symex_goto.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ static optionalt<renamedt<exprt, L2>> try_evaluate_pointer_comparison(
204204
if(!symbol_expr_lhs)
205205
return {};
206206

207-
if(!goto_symex_is_constantt()(rhs))
207+
if(!goto_symex_is_constantt(ns)(rhs))
208208
return {};
209209

210210
return try_evaluate_pointer_comparison(

src/util/expr_util.cpp

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ Author: Daniel Kroening, [email protected]
99
#include "expr_util.h"
1010

1111
#include "arith_tools.h"
12+
#include "bitvector_expr.h"
13+
#include "byte_operators.h"
1214
#include "c_types.h"
1315
#include "config.h"
1416
#include "expr_iterator.h"
1517
#include "namespace.h"
1618
#include "pointer_expr.h"
17-
#include "std_expr.h"
19+
#include "pointer_offset_size.h"
1820

1921
#include <algorithm>
2022
#include <unordered_set>
@@ -238,7 +240,6 @@ bool is_constantt::is_constant(const exprt &expr) const
238240
expr.id() == ID_plus || expr.id() == ID_mult || expr.id() == ID_array ||
239241
expr.id() == ID_with || expr.id() == ID_struct || expr.id() == ID_union ||
240242
expr.id() == ID_empty_union ||
241-
// byte_update works, byte_extract may be out-of-bounds
242243
expr.id() == ID_byte_update_big_endian ||
243244
expr.id() == ID_byte_update_little_endian)
244245
{
@@ -247,6 +248,46 @@ bool is_constantt::is_constant(const exprt &expr) const
247248
return is_constant(e);
248249
});
249250
}
251+
else if(auto be = expr_try_dynamic_cast<byte_extract_exprt>(expr))
252+
{
253+
if(!is_constant(be->op()) || !be->offset().is_constant())
254+
return false;
255+
256+
const auto op_bits = pointer_offset_bits(be->op().type(), ns);
257+
if(!op_bits.has_value())
258+
return false;
259+
260+
const auto extract_bits = pointer_offset_bits(be->type(), ns);
261+
if(!extract_bits.has_value())
262+
return false;
263+
264+
const mp_integer offset_bits =
265+
numeric_cast_v<mp_integer>(to_constant_expr(be->offset())) *
266+
be->get_bits_per_byte();
267+
268+
return offset_bits + *extract_bits <= *op_bits;
269+
}
270+
else if(auto eb = expr_try_dynamic_cast<extractbits_exprt>(expr))
271+
{
272+
if(
273+
!is_constant(eb->src()) || !eb->lower().is_constant() ||
274+
!eb->upper().is_constant())
275+
{
276+
return false;
277+
}
278+
279+
const auto src_bits = pointer_offset_bits(eb->src().type(), ns);
280+
if(!src_bits.has_value())
281+
return false;
282+
283+
const mp_integer lower_bound =
284+
numeric_cast_v<mp_integer>(to_constant_expr(eb->lower()));
285+
const mp_integer upper_bound =
286+
numeric_cast_v<mp_integer>(to_constant_expr(eb->upper()));
287+
288+
return lower_bound >= 0 && lower_bound <= upper_bound &&
289+
upper_bound < src_bits;
290+
}
250291

251292
return false;
252293
}

src/util/expr_util.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,19 @@ const exprt &skip_typecast(const exprt &expr);
8888
class is_constantt
8989
{
9090
public:
91+
explicit is_constantt(const namespacet &ns) : ns(ns)
92+
{
93+
}
94+
9195
/// returns true iff the expression can be considered constant
9296
bool operator()(const exprt &e) const
9397
{
9498
return is_constant(e);
9599
}
96100

97101
protected:
102+
const namespacet &ns;
103+
98104
virtual bool is_constant(const exprt &) const;
99105
virtual bool is_constant_address_of(const exprt &) const;
100106
};

0 commit comments

Comments
 (0)