|
22 | 22 | #include <util/c_types.h>
|
23 | 23 | #include <util/config.h>
|
24 | 24 | #include <util/cprover_prefix.h>
|
| 25 | +#include <util/expr_iterator.h> |
25 | 26 | #include <util/format_type.h>
|
26 | 27 | #include <util/fresh_symbol.h>
|
27 | 28 | #include <util/options.h>
|
|
30 | 31 | #include <util/simplify_expr.h>
|
31 | 32 | #include <util/ssa_expr.h>
|
32 | 33 |
|
| 34 | +/// Returns true if \p expr is complicated enough that a local definition (using |
| 35 | +/// a let expression) is preferable to repeating it, potentially many times. |
| 36 | +/// Of course this is just a heuristic -- currently we allow any expression that |
| 37 | +/// only involves one symbol, such as "x", "(type*)x", "x[0]" (but not "x[y]"). |
| 38 | +/// Particularly we want to make sure to insist on a local definition of \p expr |
| 39 | +/// is a large if-expression, such as `p == &o1 ? o1 : p == &o2 ? o2 : ...`, as |
| 40 | +/// can result from dereferencing a subexpression. |
| 41 | +static bool should_use_local_definition_for(const exprt &expr) |
| 42 | +{ |
| 43 | + bool seen_symbol = false; |
| 44 | + for(auto it = expr.depth_begin(), itend = expr.depth_end(); it != itend; ++it) |
| 45 | + { |
| 46 | + if(it->id() == ID_symbol) |
| 47 | + { |
| 48 | + if(seen_symbol) |
| 49 | + return true; |
| 50 | + else |
| 51 | + seen_symbol = true; |
| 52 | + } |
| 53 | + } |
| 54 | + |
| 55 | + return false; |
| 56 | +} |
| 57 | + |
33 | 58 | exprt value_set_dereferencet::dereference(const exprt &pointer)
|
34 | 59 | {
|
35 | 60 | if(pointer.type().id()!=ID_pointer)
|
@@ -78,7 +103,7 @@ exprt value_set_dereferencet::dereference(const exprt &pointer)
|
78 | 103 |
|
79 | 104 | exprt compare_against_pointer = pointer;
|
80 | 105 |
|
81 |
| - if(pointer.id() != ID_symbol && retained_values.size() >= 2) |
| 106 | + if(retained_values.size() >= 2 && should_use_local_definition_for(pointer)) |
82 | 107 | {
|
83 | 108 | symbolt fresh_binder = get_fresh_aux_symbol(
|
84 | 109 | pointer.type(),
|
|
0 commit comments