Skip to content

Commit 9c310b0

Browse files
Hannes SteffenhagenTGWDB
Hannes Steffenhagen
authored andcommitted
Add --symex-cache-dereferences flag
This makes the dereference caching behaviour configurable
1 parent 249de05 commit 9c310b0

17 files changed

+78
-33
lines changed

jbmc/src/jbmc/jbmc_parse_options.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,9 @@ void jbmc_parse_optionst::get_command_line_options(optionst &options)
425425
options.set_option("validate-goto-model", true);
426426
}
427427

428+
options.set_option(
429+
"symex-cache-dereferences", cmdline.isset("symex-cache-dereferences"));
430+
428431
PARSE_OPTIONS_GOTO_TRACE(cmdline, options);
429432

430433
if(cmdline.isset("no-lazy-methods"))

regression/cbmc/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,4 @@ tests.log: ../test.pl test
3434
clean:
3535
find . -name '*.out' -execdir $(RM) '{}' \;
3636
find . -name '*.smt2' -execdir $(RM) '{}' \;
37-
$(RM) tests*.log
37+
$(RM) tests*.log tests-paths-lifo.log tests-cprover-smt2.log
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
CORE
2+
test.c
3+
--show-vcc
4+
\(main::1::p!0@1#2 = address_of
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
--
9+
This is just checking that the --symex-cache-dereferences flag actually turns
10+
dereference caching on and off.
11+
12+
I would like to match the expression more precisely, but the order of
13+
comparisons for address of depends on platform-specific logic (unordered_xxx),
14+
and the corresponding regex would look ridiculous.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
test.c
3+
--show-vcc --symex-cache-dereferences
4+
symex::dereference_cache!0#1 = 0
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
--
9+
This is just checking that the --symex-cache-dereferences flag actually
10+
turns dereference caching on.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#include <assert.h>
2+
3+
int main(void)
4+
{
5+
int cond, x, y, *p = cond ? &x : &y;
6+
assert(*p == 0);
7+
}

regression/cbmc/double_deref/README

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,3 @@ double_deref_with_cast.desc -- a double-deref with an intervening cast (*(int*)*
2525
double_deref_with_member.desc -- a double-deref with an intervening member expression (p->field1->field2), should use a let-expression
2626
double_deref_with_pointer_arithmetic.desc -- a double-deref with intervening pointer arithmetic (p[idx1][idx2]), should use a let-expression
2727
*_single_alias.desc -- variants of the above where the first dereference points to a single possible object, so no let-expression is necessary
28-
29-
Why no-dereference-cache?
30-
-------------------------
31-
32-
Because these tests test for specific VCCs to do with multiple nested complex
33-
dereferences and the dereference caching rewrites these.

regression/cbmc/double_deref/double_deref.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE no-dereference-cache
1+
CORE
22
double_deref.c
33
--show-vcc
44
\{1\} \(main::1::pptr!0@1#2 = address_of\(main::1::ptr[12]!0@1\) \? main::argc!0@1#1 = [12] : main::argc!0@1#1 = [12]\)

regression/cbmc/double_deref/double_deref_with_cast.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE no-dereference-cache
1+
CORE
22
double_deref_with_cast.c
33
--show-vcc
44
\{1\} \(cast\(main::1::pptr!0@1#2, signedbv\[32\]\*\*\) = address_of\(main::1::ptr2!0@1\) \? main::argc!0@1#1 = 2 \: main::argc!0@1#1 = 1\)

regression/cbmc/double_deref/double_deref_with_member.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE no-dereference-cache
1+
CORE
22
double_deref_with_member.c
33
--show-vcc
44
^\{1\} \(main::1::cptr!0@1#2 = address_of\(main::1::container2!0@1\) \? main::argc!0@1#1 = 2 : main::argc!0@1#1 = 1\)

regression/cbmc/double_deref/double_deref_with_pointer_arithmetic.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE no-dereference-cache
1+
CORE
22
double_deref_with_pointer_arithmetic.c
33
--show-vcc
44
^\{-[0-9]+\} derefd_pointer::derefd_pointer!0#1 = \{ symex_dynamic::dynamic_object1#3\[\[0\]\], symex_dynamic::dynamic_object1#3\[\[1\]\] \}\[cast\(mod #source_location=""\(main::argc!0@1#1, 2\), signedbv\[64\]\)\]

regression/cbmc/double_deref/double_deref_with_pointer_arithmetic_single_alias.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE no-dereference-cache
1+
CORE
22
double_deref_with_pointer_arithmetic_single_alias.c
33
--show-vcc
44
\{1\} \(derefd_pointer::derefd_pointer!0#1 = address_of\(symex_dynamic::dynamic_object2\) \? main::argc!0@1#1 = 1 : symex::invalid_object!0#0 = main::argc!0@1#1\)

src/cbmc/cbmc_parse_options.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,9 @@ void cbmc_parse_optionst::get_command_line_options(optionst &options)
342342
"max-node-refinement",
343343
cmdline.get_value("max-node-refinement"));
344344

345+
options.set_option(
346+
"symex-cache-dereferences", cmdline.isset("symex-cache-dereferences"));
347+
345348
if(cmdline.isset("incremental-loop"))
346349
{
347350
options.set_option(

src/goto-checker/bmc_util.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,8 @@ void run_property_decider(
197197
"(incremental-loop):" \
198198
"(unwind-min):" \
199199
"(unwind-max):" \
200-
"(ignore-properties-before-unwind-min)"
200+
"(ignore-properties-before-unwind-min)" \
201+
"(symex-cache-dereferences)" \
201202

202203
#define HELP_BMC \
203204
" --paths [strategy] explore paths one at a time\n" \
@@ -251,7 +252,8 @@ void run_property_decider(
251252
" iteration are allowed to fail due to\n" \
252253
" complexity violations before the loop\n" \
253254
" gets blacklisted\n" \
254-
" --graphml-witness filename write the witness in GraphML format to filename\n" // NOLINT(*)
255+
" --graphml-witness filename write the witness in GraphML format to filename\n" /* NOLINT(*) */ \
256+
" --symex-cache-dereferences enable caching of repeated dereferences" \
255257
// clang-format on
256258

257259
#endif // CPROVER_GOTO_CHECKER_BMC_UTIL_H

src/goto-symex/goto_state.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ Author: Romain Brenguier, [email protected]
1212
#ifndef CPROVER_GOTO_SYMEX_GOTO_STATE_H
1313
#define CPROVER_GOTO_SYMEX_GOTO_STATE_H
1414

15-
#include <unordered_map>
1615
#include <util/sharing_map.h>
1716

1817
#include <analyses/guard.h>

src/goto-symex/symex_config.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ struct symex_configt final
5555
/// enables certain analyses that otherwise aren't run.
5656
bool complexity_limits_active;
5757

58+
/// \brief Whether or not to replace multiple occurrences of the same
59+
/// dereference with a single symbol that contains the result of that
60+
/// dereference. Can sometimes lead to a significant performance
61+
/// improvement, but sometimes also makes things worse.
62+
/// See https://github.com/diffblue/cbmc/pull/5964 for performance data.
63+
/// Used in goto_symext::dereference_rec
64+
bool cache_dereferences;
65+
5866
/// \brief Construct a symex_configt using options specified in an
5967
/// \ref optionst
6068
explicit symex_configt(const optionst &options);

src/goto-symex/symex_dereference.cpp

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ goto_symext::cache_dereference(exprt &dereference_result, statet &state)
221221
"symex",
222222
"dereference_cache",
223223
dereference_result.source_location(),
224-
ID_C,
224+
language_mode,
225225
ns,
226226
state.symbol_table);
227227

@@ -230,25 +230,29 @@ goto_symext::cache_dereference(exprt &dereference_result, statet &state)
230230
auto cache_value = cache_key;
231231
lift_lets(state, cache_value);
232232

233-
exprt::operandst guard{};
234233
auto assign = symex_assignt{
235234
state, symex_targett::assignment_typet::STATE, ns, symex_config, target};
236235

236+
auto cache_symbol_expr = cache_symbol.symbol_expr();
237237
assign.assign_symbol(
238-
to_ssa_expr(state.rename<L1>(cache_symbol.symbol_expr(), ns).get()),
238+
to_ssa_expr(state.rename<L1>(cache_symbol_expr, ns).get()),
239239
expr_skeletont{},
240240
cache_value,
241-
guard);
241+
{});
242242

243-
state.dereference_cache.insert(cache_key, cache_symbol.symbol_expr());
244-
return cache_symbol.symbol_expr();
243+
state.dereference_cache.insert(cache_key, cache_symbol_expr);
244+
return cache_symbol_expr;
245245
}
246246

247247
/// If \p expr is a \ref dereference_exprt, replace it with explicit references
248248
/// to the objects it may point to. Otherwise recursively apply this function to
249249
/// \p expr's operands, with special cases for address-of (handled by \ref
250250
/// goto_symext::address_arithmetic) and certain common expression patterns
251251
/// such as `&struct.flexible_array[0]` (see inline comments in code).
252+
/// Note that \p write is used to alter behaviour when this function is
253+
/// operating on the LHS of an assignment. Similarly \p is_in_quantifier
254+
/// indicates when the dereference is inside a quantifier (related to scoping
255+
/// when dereference caching is enabled).
252256
/// For full details of this method's pointer replacement and potential side-
253257
/// effects see \ref goto_symext::dereference
254258
void goto_symext::dereference_rec(
@@ -332,24 +336,24 @@ void goto_symext::dereference_rec(
332336
// this may yield a new auto-object
333337
trigger_auto_object(tmp2, state);
334338

335-
// If the dereference result is not a complicated expression
336-
// (i.e. of the form
337-
// [let p = <expr> in ]
338-
// (p == &something ? something : ...))
339-
// we should just return it unchanged.
340-
// also if we are on the lhs of an assignment we should also not attempt to
341-
// go to the cache we cannot do this for quantified expressions because this
342-
// would result in us referencing quantifier variables outside the scope of
343-
// the quantifier.
339+
// Check various conditions for when we should try to cache the expression.
340+
// 1. Caching dereferences must be enabled.
341+
// 2. Do not cache inside LHS of writes.
342+
// 3. Do not cache inside quantifiers (references variables outside their
343+
// scope).
344+
// 4. Only cache "complicated" expressions, i.e. of the form
345+
// [let p = <expr> in ]
346+
// (p == &something ? something : ...))
347+
// Otherwise we should just return it unchanged.
344348
if(
345-
!write && !is_in_quantifier &&
349+
symex_config.cache_dereferences && !write && !is_in_quantifier &&
346350
(tmp2.id() == ID_if || tmp2.id() == ID_let))
347351
{
348352
expr = cache_dereference(tmp2, state);
349353
}
350354
else
351355
{
352-
expr = tmp2;
356+
expr = std::move(tmp2);
353357
}
354358
}
355359
else if(

src/goto-symex/symex_main.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ symex_configt::symex_configt(const optionst &options)
5656
"max-field-sensitivity-array-size")
5757
: DEFAULT_MAX_FIELD_SENSITIVITY_ARRAY_SIZE),
5858
complexity_limits_active(
59-
options.get_signed_int_option("symex-complexity-limit") > 0)
59+
options.get_signed_int_option("symex-complexity-limit") > 0),
60+
cache_dereferences{options.get_bool_option("symex-cache-dereferences")}
6061
{
6162
}
6263

0 commit comments

Comments
 (0)