14
14
#include < util/arith_tools.h>
15
15
#include < util/c_types.h>
16
16
#include < util/config.h>
17
+ #include < util/expr_iterator.h>
17
18
#include < util/expr_util.h>
18
19
#include < util/fixedbv.h>
19
20
#include < util/format_expr.h>
@@ -612,24 +613,6 @@ void smt2_convt::convert_address_of_rec(
612
613
expr.id_string ());
613
614
}
614
615
615
- void smt2_convt::convert_byte_extract (const byte_extract_exprt &expr)
616
- {
617
- // we just run the flattener
618
- exprt flattened_expr = lower_byte_extract (expr, ns);
619
- unflatten (wheret::BEGIN, expr.type ());
620
- convert_expr (flattened_expr);
621
- unflatten (wheret::END, expr.type ());
622
- }
623
-
624
- void smt2_convt::convert_byte_update (const byte_update_exprt &expr)
625
- {
626
- // we just run the flattener
627
- exprt flattened_expr = lower_byte_update (expr, ns);
628
- unflatten (wheret::BEGIN, expr.type ());
629
- convert_expr (flattened_expr);
630
- unflatten (wheret::END, expr.type ());
631
- }
632
-
633
616
literalt smt2_convt::convert (const exprt &expr)
634
617
{
635
618
PRECONDITION (expr.type ().id () == ID_bool);
@@ -647,7 +630,7 @@ literalt smt2_convt::convert(const exprt &expr)
647
630
648
631
out << " \n " ;
649
632
650
- find_symbols (expr);
633
+ exprt prepared_expr = prepare_expr (expr);
651
634
652
635
literalt l (no_boolean_variables, false );
653
636
no_boolean_variables++;
@@ -656,7 +639,7 @@ literalt smt2_convt::convert(const exprt &expr)
656
639
out << " (define-fun " ;
657
640
convert_literal (l);
658
641
out << " () Bool " ;
659
- convert_expr (expr );
642
+ convert_expr (prepared_expr );
660
643
out << " )" << " \n " ;
661
644
662
645
return l;
@@ -1431,12 +1414,12 @@ void smt2_convt::convert_expr(const exprt &expr)
1431
1414
else if (expr.id ()==ID_byte_extract_little_endian ||
1432
1415
expr.id ()==ID_byte_extract_big_endian)
1433
1416
{
1434
- convert_byte_extract ( to_byte_extract_expr (expr) );
1417
+ INVARIANT ( false , " byte_extract ops should be lowered in prepare_expr " );
1435
1418
}
1436
1419
else if (expr.id ()==ID_byte_update_little_endian ||
1437
1420
expr.id ()==ID_byte_update_big_endian)
1438
1421
{
1439
- convert_byte_update ( to_byte_update_expr (expr) );
1422
+ INVARIANT ( false , " byte_update ops should be lowered in prepare_expr " );
1440
1423
}
1441
1424
else if (expr.id ()==ID_width)
1442
1425
{
@@ -4058,7 +4041,7 @@ void smt2_convt::set_to(const exprt &expr, bool value)
4058
4041
4059
4042
id.type =equal_expr.lhs ().type ();
4060
4043
find_symbols (id.type );
4061
- find_symbols (equal_expr.rhs ());
4044
+ exprt prepared_rhs = prepare_expr (equal_expr.rhs ());
4062
4045
4063
4046
std::string smt2_identifier=convert_identifier (identifier);
4064
4047
smt2_identifiers.insert (smt2_identifier);
@@ -4068,38 +4051,98 @@ void smt2_convt::set_to(const exprt &expr, bool value)
4068
4051
4069
4052
convert_type (equal_expr.lhs ().type ());
4070
4053
out << " " ;
4071
- convert_expr (equal_expr. rhs () );
4054
+ convert_expr (prepared_rhs );
4072
4055
4073
4056
out << " )" << " \n " ;
4074
4057
return ; // done
4075
4058
}
4076
4059
}
4077
4060
}
4078
4061
4079
- find_symbols (expr);
4062
+ exprt prepared_expr = prepare_expr (expr);
4080
4063
4081
- #if 0
4064
+ #if 0
4082
4065
out << "; CONV: "
4083
4066
<< format(expr) << "\n";
4084
- #endif
4067
+ #endif
4085
4068
4086
4069
out << " ; set_to " << (value?" true" :" false" ) << " \n "
4087
4070
<< " (assert " ;
4088
4071
4089
4072
if (!value)
4090
4073
{
4091
4074
out << " (not " ;
4092
- convert_expr (expr );
4075
+ convert_expr (prepared_expr );
4093
4076
out << " )" ;
4094
4077
}
4095
4078
else
4096
- convert_expr (expr );
4079
+ convert_expr (prepared_expr );
4097
4080
4098
4081
out << " )" << " \n " ; // assert
4099
4082
4100
4083
return ;
4101
4084
}
4102
4085
4086
+ // / Lower byte_update and byte_extract operations within \p expr. Return an
4087
+ // / equivalent expression that doesn't use byte operators.
4088
+ // / Note this replaces operators post-order (compare \ref lower_byte_operators,
4089
+ // / which uses a pre-order walk, replacing in child expressions before the
4090
+ // / parent). Pre-order replacement currently fails regression tests: see
4091
+ // / https://github.com/diffblue/cbmc/issues/4380
4092
+ exprt smt2_convt::lower_byte_operators_rec (const exprt &expr)
4093
+ {
4094
+ exprt lowered_expr = expr;
4095
+
4096
+ for (auto it = lowered_expr.depth_begin (), itend = lowered_expr.depth_end ();
4097
+ it != itend;
4098
+ /* No ++it */ )
4099
+ {
4100
+ if (
4101
+ it->id () == ID_byte_extract_little_endian ||
4102
+ it->id () == ID_byte_extract_big_endian)
4103
+ {
4104
+ // Note we must recurse to get a fresh iterator because depth_iteratort
4105
+ // currently crashes if we try to recurse into an expression we've
4106
+ // altered.
4107
+ it.mutate () = lower_byte_operators_rec (
4108
+ lower_byte_extract (to_byte_extract_expr (*it), ns));
4109
+ it.next_sibling_or_parent ();
4110
+ }
4111
+ else if (
4112
+ it->id () == ID_byte_update_little_endian ||
4113
+ it->id () == ID_byte_update_big_endian)
4114
+ {
4115
+ // Note we must recurse to get a fresh iterator because depth_iteratort
4116
+ // currently crashes if we try to recurse into an expression we've
4117
+ // altered.
4118
+ it.mutate () = lower_byte_operators_rec (
4119
+ lower_byte_update (to_byte_update_expr (*it), ns));
4120
+ it.next_sibling_or_parent ();
4121
+ }
4122
+ else
4123
+ {
4124
+ ++it;
4125
+ }
4126
+ }
4127
+
4128
+ return lowered_expr;
4129
+ }
4130
+
4131
+ exprt smt2_convt::prepare_expr (const exprt &expr)
4132
+ {
4133
+ // First, replace byte operators, because they may introduce new array
4134
+ // expressions that must be seen by find_symbols:
4135
+ exprt lowered_expr = lower_byte_operators_rec (expr);
4136
+ INVARIANT (
4137
+ !has_byte_operator (lowered_expr),
4138
+ " lower_byte_operators_rec should remove all byte operators" );
4139
+
4140
+ // Now create symbols for all composite expressions present in lowered_expr:
4141
+ find_symbols (lowered_expr);
4142
+
4143
+ return lowered_expr;
4144
+ }
4145
+
4103
4146
void smt2_convt::find_symbols (const exprt &expr)
4104
4147
{
4105
4148
// recursive call on type
0 commit comments