Skip to content

Commit a1822ef

Browse files
authored
Merge pull request #7717 from tautschnig/feature/constant-pointer-ops
Change is_constantt logic to enumerate not-constant expressions
2 parents 12c8f62 + 3aa0eee commit a1822ef

15 files changed

+141
-69
lines changed

regression/cbmc/Array_UF22/main.c

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
int main()
22
{
3-
int a[2] = {0};
4-
int b[2] = {0};
3+
int x;
4+
int a[2] = {x};
5+
int b[2] = {x};
56
__CPROVER_assert(__CPROVER_array_equal(a, b), "equal");
67
}

src/analyses/constant_propagator.cpp

+7-6
Original file line numberDiff line numberDiff line change
@@ -416,13 +416,13 @@ bool constant_propagator_domaint::ai_simplify(
416416
return partial_evaluate(values, condition, ns);
417417
}
418418

419-
class constant_propagator_is_constantt : public is_constantt
419+
class constant_propagator_can_forward_propagatet : public can_forward_propagatet
420420
{
421421
public:
422-
constant_propagator_is_constantt(
422+
constant_propagator_can_forward_propagatet(
423423
const replace_symbolt &replace_const,
424424
const namespacet &ns)
425-
: is_constantt(ns), replace_const(replace_const)
425+
: can_forward_propagatet(ns), replace_const(replace_const)
426426
{
427427
}
428428

@@ -437,7 +437,7 @@ class constant_propagator_is_constantt : public is_constantt
437437
if(expr.id() == ID_symbol)
438438
return is_constant(to_symbol_expr(expr).get_identifier());
439439

440-
return is_constantt::is_constant(expr);
440+
return can_forward_propagatet::is_constant(expr);
441441
}
442442

443443
const replace_symbolt &replace_const;
@@ -447,14 +447,15 @@ bool constant_propagator_domaint::valuest::is_constant(
447447
const exprt &expr,
448448
const namespacet &ns) const
449449
{
450-
return constant_propagator_is_constantt(replace_const, ns)(expr);
450+
return constant_propagator_can_forward_propagatet(replace_const, ns)(expr);
451451
}
452452

453453
bool constant_propagator_domaint::valuest::is_constant(
454454
const irep_idt &id,
455455
const namespacet &ns) const
456456
{
457-
return constant_propagator_is_constantt(replace_const, ns).is_constant(id);
457+
return constant_propagator_can_forward_propagatet(replace_const, ns)
458+
.is_constant(id);
458459
}
459460

460461
/// Do not call this when iterating over replace_const.expr_map!

src/ansi-c/c_typecheck_expr.cpp

+64-8
Original file line numberDiff line numberDiff line change
@@ -4495,23 +4495,60 @@ void c_typecheck_baset::typecheck_side_effect_assignment(
44954495
throw 0;
44964496
}
44974497

4498-
class is_compile_time_constantt : public is_constantt
4498+
/// Architecturally similar to \ref can_forward_propagatet, but specialized for
4499+
/// what is a constexpr, i.e., an expression that can be fully evaluated at
4500+
/// compile time.
4501+
class is_compile_time_constantt
44994502
{
45004503
public:
4501-
explicit is_compile_time_constantt(const namespacet &ns) : is_constantt(ns)
4504+
explicit is_compile_time_constantt(const namespacet &ns) : ns(ns)
45024505
{
45034506
}
45044507

4508+
/// returns true iff the expression can be considered constant
4509+
bool operator()(const exprt &e) const
4510+
{
4511+
return is_constant(e);
4512+
}
4513+
45054514
protected:
4506-
bool is_constant(const exprt &e) const override
4515+
const namespacet &ns;
4516+
4517+
/// This function determines what expressions are to be propagated as
4518+
/// "constants"
4519+
bool is_constant(const exprt &e) const
45074520
{
45084521
if(e.id() == ID_infinity)
45094522
return true;
4510-
else
4511-
return is_constantt::is_constant(e);
4523+
4524+
if(e.is_constant())
4525+
return true;
4526+
4527+
if(e.id() == ID_address_of)
4528+
{
4529+
return is_constant_address_of(to_address_of_expr(e).object());
4530+
}
4531+
else if(
4532+
e.id() == ID_typecast || e.id() == ID_array_of || e.id() == ID_plus ||
4533+
e.id() == ID_mult || e.id() == ID_array || e.id() == ID_with ||
4534+
e.id() == ID_struct || e.id() == ID_union || e.id() == ID_empty_union ||
4535+
e.id() == ID_equal || e.id() == ID_notequal || e.id() == ID_lt ||
4536+
e.id() == ID_le || e.id() == ID_gt || e.id() == ID_ge ||
4537+
e.id() == ID_if || e.id() == ID_not || e.id() == ID_and ||
4538+
e.id() == ID_or || e.id() == ID_bitnot || e.id() == ID_bitand ||
4539+
e.id() == ID_bitor || e.id() == ID_bitxor)
4540+
{
4541+
return std::all_of(
4542+
e.operands().begin(), e.operands().end(), [this](const exprt &op) {
4543+
return is_constant(op);
4544+
});
4545+
}
4546+
4547+
return false;
45124548
}
45134549

4514-
bool is_constant_address_of(const exprt &e) const override
4550+
/// this function determines which reference-typed expressions are constant
4551+
bool is_constant_address_of(const exprt &e) const
45154552
{
45164553
if(e.id() == ID_symbol)
45174554
{
@@ -4522,8 +4559,27 @@ class is_compile_time_constantt : public is_constantt
45224559
return true;
45234560
else if(e.id() == ID_label)
45244561
return true;
4525-
else
4526-
return is_constantt::is_constant_address_of(e);
4562+
else if(e.id() == ID_index)
4563+
{
4564+
const index_exprt &index_expr = to_index_expr(e);
4565+
4566+
return is_constant_address_of(index_expr.array()) &&
4567+
is_constant(index_expr.index());
4568+
}
4569+
else if(e.id() == ID_member)
4570+
{
4571+
return is_constant_address_of(to_member_expr(e).compound());
4572+
}
4573+
else if(e.id() == ID_dereference)
4574+
{
4575+
const dereference_exprt &deref = to_dereference_expr(e);
4576+
4577+
return is_constant(deref.pointer());
4578+
}
4579+
else if(e.id() == ID_string_constant)
4580+
return true;
4581+
4582+
return false;
45274583
}
45284584
};
45294585

src/goto-instrument/contracts/dynamic-frames/dfcc_infer_loop_assigns.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ assignst dfcc_infer_loop_assigns(
6666
// widen or drop targets that depend on loop-locals or are non-constant,
6767
// ie. depend on other locations assigned by the loop.
6868
// e.g: if the loop assigns {i, a[i]}, then a[i] is non-constant.
69-
havoc_utils_is_constantt is_constant(assigns, ns);
69+
havoc_utils_can_forward_propagatet is_constant(assigns, ns);
7070
assignst result;
7171
for(const auto &expr : assigns)
7272
{

src/goto-instrument/contracts/utils.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ void widen_assigns(assignst &assigns, const namespacet &ns)
342342
{
343343
assignst result;
344344

345-
havoc_utils_is_constantt is_constant(assigns, ns);
345+
havoc_utils_can_forward_propagatet is_constant(assigns, ns);
346346

347347
for(const auto &e : assigns)
348348
{

src/goto-instrument/havoc_utils.h

+10-7
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,25 @@ class goto_programt;
2424
typedef std::set<exprt> assignst;
2525

2626
/// \brief A class containing utility functions for havocing expressions.
27-
class havoc_utils_is_constantt : public is_constantt
27+
class havoc_utils_can_forward_propagatet : public can_forward_propagatet
2828
{
2929
public:
30-
explicit havoc_utils_is_constantt(const assignst &mod, const namespacet &ns)
31-
: is_constantt(ns), assigns(mod)
30+
explicit havoc_utils_can_forward_propagatet(
31+
const assignst &mod,
32+
const namespacet &ns)
33+
: can_forward_propagatet(ns), assigns(mod)
3234
{
3335
}
3436

3537
bool is_constant(const exprt &expr) const override
3638
{
37-
// Besides the "usual" constants (checked in is_constantt::is_constant),
38-
// we also treat unmodified symbols as constants
39+
// Besides the "usual" constants (checked in
40+
// can_forward_propagatet::is_constant), we also treat unmodified symbols as
41+
// constants
3942
if(expr.id() == ID_symbol && assigns.find(expr) == assigns.end())
4043
return true;
4144

42-
return is_constantt::is_constant(expr);
45+
return can_forward_propagatet::is_constant(expr);
4346
}
4447

4548
protected:
@@ -102,7 +105,7 @@ class havoc_utilst
102105

103106
protected:
104107
const assignst &assigns;
105-
const havoc_utils_is_constantt is_constant;
108+
const havoc_utils_can_forward_propagatet is_constant;
106109
};
107110

108111
#endif // CPROVER_GOTO_INSTRUMENT_HAVOC_UTILS_H

src/goto-symex/goto_state.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ Author: Romain Brenguier, [email protected]
77
\*******************************************************************/
88

99
#include "goto_state.h"
10-
#include "goto_symex_is_constant.h"
11-
#include "goto_symex_state.h"
1210

1311
#include <util/format_expr.h>
1412

13+
#include "goto_symex_can_forward_propagate.h"
14+
#include "goto_symex_state.h"
15+
1516
/// Print the constant propagation map in a human-friendly format.
1617
/// This is primarily for use from the debugger; please don't delete me just
1718
/// because there aren't any current callers.
@@ -91,7 +92,7 @@ void goto_statet::apply_condition(
9192
if(is_ssa_expr(rhs))
9293
std::swap(lhs, rhs);
9394

94-
if(is_ssa_expr(lhs) && goto_symex_is_constantt(ns)(rhs))
95+
if(is_ssa_expr(lhs) && goto_symex_can_forward_propagatet(ns)(rhs))
9596
{
9697
const ssa_exprt &ssa_lhs = to_ssa_expr(lhs);
9798
INVARIANT(
@@ -141,7 +142,7 @@ void goto_statet::apply_condition(
141142
if(is_ssa_expr(rhs))
142143
std::swap(lhs, rhs);
143144

144-
if(!is_ssa_expr(lhs) || !goto_symex_is_constantt(ns)(rhs))
145+
if(!is_ssa_expr(lhs) || !goto_symex_can_forward_propagatet(ns)(rhs))
145146
return;
146147

147148
if(rhs.is_true())

src/goto-symex/goto_symex_is_constant.h renamed to src/goto-symex/goto_symex_can_forward_propagate.h

+7-6
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,17 @@ Author: Michael Tautschig, [email protected]
99
/// \file
1010
/// GOTO Symex constant propagation
1111

12-
#ifndef CPROVER_GOTO_SYMEX_GOTO_SYMEX_IS_CONSTANT_H
13-
#define CPROVER_GOTO_SYMEX_GOTO_SYMEX_IS_CONSTANT_H
12+
#ifndef CPROVER_GOTO_SYMEX_GOTO_SYMEX_CAN_FORWARD_PROPAGATE_H
13+
#define CPROVER_GOTO_SYMEX_GOTO_SYMEX_CAN_FORWARD_PROPAGATE_H
1414

1515
#include <util/expr.h>
1616
#include <util/expr_util.h>
1717

18-
class goto_symex_is_constantt : public is_constantt
18+
class goto_symex_can_forward_propagatet : public can_forward_propagatet
1919
{
2020
public:
21-
explicit goto_symex_is_constantt(const namespacet &ns) : is_constantt(ns)
21+
explicit goto_symex_can_forward_propagatet(const namespacet &ns)
22+
: can_forward_propagatet(ns)
2223
{
2324
}
2425

@@ -56,8 +57,8 @@ class goto_symex_is_constantt : public is_constantt
5657
#endif
5758
}
5859

59-
return is_constantt::is_constant(expr);
60+
return can_forward_propagatet::is_constant(expr);
6061
}
6162
};
6263

63-
#endif // CPROVER_GOTO_SYMEX_GOTO_SYMEX_IS_CONSTANT_H
64+
#endif // CPROVER_GOTO_SYMEX_GOTO_SYMEX_CAN_FORWARD_PROPAGATE_H

src/goto-symex/goto_symex_state.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Author: Daniel Kroening, [email protected]
2323
#include <analyses/dirty.h>
2424
#include <pointer-analysis/add_failed_symbols.h>
2525

26-
#include "goto_symex_is_constant.h"
26+
#include "goto_symex_can_forward_propagate.h"
2727
#include "symex_target_equation.h"
2828

2929
static void get_l1_name(exprt &expr);
@@ -112,7 +112,7 @@ renamedt<ssa_exprt, L2> goto_symex_statet::assignment(
112112
"pointer handling for concurrency is unsound");
113113

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

src/goto-symex/symex_goto.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Author: Daniel Kroening, [email protected]
2222
#include <pointer-analysis/value_set_dereference.h>
2323

2424
#include "goto_symex.h"
25-
#include "goto_symex_is_constant.h"
25+
#include "goto_symex_can_forward_propagate.h"
2626
#include "path_storage.h"
2727

2828
#include <algorithm>
@@ -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(ns)(rhs))
207+
if(!goto_symex_can_forward_propagatet(ns)(rhs))
208208
return {};
209209

210210
return try_evaluate_pointer_comparison(

src/goto-synthesizer/enumerative_loop_contracts_synthesizer.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ void enumerative_loop_contracts_synthesizert::synthesize_assigns(
179179
if(new_assign.id() == ID_index || new_assign.id() == ID_dereference)
180180
{
181181
address_of_exprt address_of_new_assigns(new_assign);
182-
havoc_utils_is_constantt is_constant(assigns_map[loop_id], ns);
182+
havoc_utils_can_forward_propagatet is_constant(assigns_map[loop_id], ns);
183183
if(!is_constant(address_of_new_assigns))
184184
{
185185
new_assign = pointer_object(address_of_new_assigns);

0 commit comments

Comments
 (0)