Skip to content

Commit 5bff566

Browse files
committed
Simplify selected ID_if operands in preorder traversal
This avoids repeatedly visiting already-simplified operands. On the example from #7357 this reduces symex time from 1172 seconds to 922 seconds.
1 parent ad53d2f commit 5bff566

5 files changed

+178
-75
lines changed

src/util/simplify_expr.cpp

+84-28
Original file line numberDiff line numberDiff line change
@@ -1376,23 +1376,6 @@ simplify_exprt::simplify_dereference(const dereference_exprt &expr)
13761376
if(pointer.type().id()!=ID_pointer)
13771377
return unchanged(expr);
13781378

1379-
if(pointer.id()==ID_if && pointer.operands().size()==3)
1380-
{
1381-
const if_exprt &if_expr=to_if_expr(pointer);
1382-
1383-
auto tmp_op1 = expr;
1384-
tmp_op1.op() = if_expr.true_case();
1385-
exprt tmp_op1_result = simplify_dereference(tmp_op1);
1386-
1387-
auto tmp_op2 = expr;
1388-
tmp_op2.op() = if_expr.false_case();
1389-
exprt tmp_op2_result = simplify_dereference(tmp_op2);
1390-
1391-
if_exprt tmp{if_expr.cond(), tmp_op1_result, tmp_op2_result};
1392-
1393-
return changed(simplify_if(tmp));
1394-
}
1395-
13961379
if(pointer.id()==ID_address_of)
13971380
{
13981381
exprt tmp=to_address_of_expr(pointer).object();
@@ -1426,6 +1409,30 @@ simplify_exprt::simplify_dereference(const dereference_exprt &expr)
14261409
return unchanged(expr);
14271410
}
14281411

1412+
simplify_exprt::resultt<>
1413+
simplify_exprt::simplify_dereference_preorder(const dereference_exprt &expr)
1414+
{
1415+
const exprt &pointer = expr.pointer();
1416+
1417+
if(pointer.id() == ID_if)
1418+
{
1419+
if_exprt if_expr = lift_if(expr, 0);
1420+
return changed(simplify_if_preorder(if_expr));
1421+
}
1422+
else
1423+
{
1424+
auto r_it = simplify_rec(pointer); // recursive call
1425+
if(r_it.has_changed())
1426+
{
1427+
auto tmp = expr;
1428+
tmp.pointer() = r_it.expr;
1429+
return tmp;
1430+
}
1431+
}
1432+
1433+
return unchanged(expr);
1434+
}
1435+
14291436
simplify_exprt::resultt<>
14301437
simplify_exprt::simplify_lambda(const lambda_exprt &expr)
14311438
{
@@ -1642,17 +1649,6 @@ simplify_exprt::resultt<> simplify_exprt::simplify_object(const exprt &expr)
16421649
simplify_exprt::resultt<>
16431650
simplify_exprt::simplify_byte_extract(const byte_extract_exprt &expr)
16441651
{
1645-
// lift up any ID_if on the object
1646-
if(expr.op().id()==ID_if)
1647-
{
1648-
if_exprt if_expr=lift_if(expr, 0);
1649-
if_expr.true_case() =
1650-
simplify_byte_extract(to_byte_extract_expr(if_expr.true_case()));
1651-
if_expr.false_case() =
1652-
simplify_byte_extract(to_byte_extract_expr(if_expr.false_case()));
1653-
return changed(simplify_if(if_expr));
1654-
}
1655-
16561652
const auto el_size = pointer_offset_bits(expr.type(), ns);
16571653
if(el_size.has_value() && *el_size < 0)
16581654
return unchanged(expr);
@@ -1995,6 +1991,41 @@ simplify_exprt::simplify_byte_extract(const byte_extract_exprt &expr)
19951991
return unchanged(expr);
19961992
}
19971993

1994+
simplify_exprt::resultt<>
1995+
simplify_exprt::simplify_byte_extract_preorder(const byte_extract_exprt &expr)
1996+
{
1997+
// lift up any ID_if on the object
1998+
if(expr.op().id() == ID_if)
1999+
{
2000+
if_exprt if_expr = lift_if(expr, 0);
2001+
return changed(simplify_if_preorder(if_expr));
2002+
}
2003+
else
2004+
{
2005+
optionalt<exprt::operandst> new_operands;
2006+
2007+
for(std::size_t i = 0; i < expr.operands().size(); ++i)
2008+
{
2009+
auto r_it = simplify_rec(expr.operands()[i]); // recursive call
2010+
if(r_it.has_changed())
2011+
{
2012+
if(!new_operands.has_value())
2013+
new_operands = expr.operands();
2014+
(*new_operands)[i] = std::move(r_it.expr);
2015+
}
2016+
}
2017+
2018+
if(new_operands.has_value())
2019+
{
2020+
exprt result = expr;
2021+
std::swap(result.operands(), *new_operands);
2022+
return result;
2023+
}
2024+
}
2025+
2026+
return unchanged(expr);
2027+
}
2028+
19982029
simplify_exprt::resultt<>
19992030
simplify_exprt::simplify_byte_update(const byte_update_exprt &expr)
20002031
{
@@ -2724,6 +2755,31 @@ simplify_exprt::simplify_node_preorder(const exprt &expr)
27242755
{
27252756
result = simplify_typecast_preorder(to_typecast_expr(expr));
27262757
}
2758+
else if(
2759+
expr.id() == ID_byte_extract_little_endian ||
2760+
expr.id() == ID_byte_extract_big_endian)
2761+
{
2762+
result = simplify_byte_extract_preorder(to_byte_extract_expr(expr));
2763+
}
2764+
else if(expr.id() == ID_dereference)
2765+
{
2766+
result = simplify_dereference_preorder(to_dereference_expr(expr));
2767+
}
2768+
else if(expr.id() == ID_index)
2769+
{
2770+
result = simplify_index_preorder(to_index_expr(expr));
2771+
}
2772+
else if(expr.id() == ID_member)
2773+
{
2774+
result = simplify_member_preorder(to_member_expr(expr));
2775+
}
2776+
else if(
2777+
expr.id() == ID_is_dynamic_object || expr.id() == ID_is_invalid_pointer ||
2778+
expr.id() == ID_object_size || expr.id() == ID_pointer_object ||
2779+
expr.id() == ID_pointer_offset)
2780+
{
2781+
result = simplify_unary_pointer_predicate_preorder(to_unary_expr(expr));
2782+
}
27272783
else if(expr.has_operands())
27282784
{
27292785
optionalt<exprt::operandst> new_operands;

src/util/simplify_expr_array.cpp

+36-13
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Author: Daniel Kroening, [email protected]
1010

1111
#include "arith_tools.h"
1212
#include "byte_operators.h"
13+
#include "expr_util.h"
1314
#include "pointer_offset_size.h"
1415
#include "replace_expr.h"
1516
#include "std_expr.h"
@@ -196,22 +197,44 @@ simplify_exprt::simplify_index(const index_exprt &expr)
196197
return changed(simplify_byte_extract(result_expr));
197198
}
198199
}
199-
else if(array.id()==ID_if)
200-
{
201-
const if_exprt &if_expr=to_if_expr(array);
202-
exprt cond=if_expr.cond();
203-
204-
index_exprt idx_false=to_index_expr(expr);
205-
idx_false.array()=if_expr.false_case();
206-
207-
new_expr.array() = if_expr.true_case();
208-
209-
exprt result = if_exprt(cond, new_expr, idx_false, expr.type());
210-
return changed(simplify_rec(result));
211-
}
212200

213201
if(no_change)
214202
return unchanged(expr);
215203
else
216204
return std::move(new_expr);
217205
}
206+
207+
simplify_exprt::resultt<>
208+
simplify_exprt::simplify_index_preorder(const index_exprt &expr)
209+
{
210+
// lift up any ID_if on the array
211+
if(expr.array().id() == ID_if)
212+
{
213+
if_exprt if_expr = lift_if(expr, 0);
214+
return changed(simplify_if_preorder(if_expr));
215+
}
216+
else
217+
{
218+
optionalt<exprt::operandst> new_operands;
219+
220+
for(std::size_t i = 0; i < expr.operands().size(); ++i)
221+
{
222+
auto r_it = simplify_rec(expr.operands()[i]); // recursive call
223+
if(r_it.has_changed())
224+
{
225+
if(!new_operands.has_value())
226+
new_operands = expr.operands();
227+
(*new_operands)[i] = std::move(r_it.expr);
228+
}
229+
}
230+
231+
if(new_operands.has_value())
232+
{
233+
exprt result = expr;
234+
std::swap(result.operands(), *new_operands);
235+
return result;
236+
}
237+
}
238+
239+
return unchanged(expr);
240+
}

src/util/simplify_expr_class.h

+7
Original file line numberDiff line numberDiff line change
@@ -175,17 +175,24 @@ class simplify_exprt
175175
NODISCARD resultt<> simplify_with(const with_exprt &);
176176
NODISCARD resultt<> simplify_update(const update_exprt &);
177177
NODISCARD resultt<> simplify_index(const index_exprt &);
178+
NODISCARD resultt<> simplify_index_preorder(const index_exprt &);
178179
NODISCARD resultt<> simplify_member(const member_exprt &);
180+
NODISCARD resultt<> simplify_member_preorder(const member_exprt &);
179181
NODISCARD resultt<> simplify_byte_update(const byte_update_exprt &);
180182
NODISCARD resultt<> simplify_byte_extract(const byte_extract_exprt &);
183+
NODISCARD resultt<>
184+
simplify_byte_extract_preorder(const byte_extract_exprt &);
181185
NODISCARD resultt<> simplify_pointer_object(const pointer_object_exprt &);
186+
NODISCARD resultt<>
187+
simplify_unary_pointer_predicate_preorder(const unary_exprt &);
182188
NODISCARD resultt<> simplify_object_size(const object_size_exprt &);
183189
NODISCARD resultt<> simplify_is_dynamic_object(const unary_exprt &);
184190
NODISCARD resultt<> simplify_is_invalid_pointer(const unary_exprt &);
185191
NODISCARD resultt<> simplify_object(const exprt &);
186192
NODISCARD resultt<> simplify_unary_minus(const unary_minus_exprt &);
187193
NODISCARD resultt<> simplify_unary_plus(const unary_plus_exprt &);
188194
NODISCARD resultt<> simplify_dereference(const dereference_exprt &);
195+
NODISCARD resultt<> simplify_dereference_preorder(const dereference_exprt &);
189196
NODISCARD resultt<> simplify_address_of(const address_of_exprt &);
190197
NODISCARD resultt<> simplify_pointer_offset(const pointer_offset_exprt &);
191198
NODISCARD resultt<> simplify_bswap(const bswap_exprt &);

src/util/simplify_expr_pointer.cpp

+26-20
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,32 @@ static bool is_dereference_integer_object(
5353
return false;
5454
}
5555

56+
simplify_exprt::resultt<>
57+
simplify_exprt::simplify_unary_pointer_predicate_preorder(
58+
const unary_exprt &expr)
59+
{
60+
const exprt &pointer = expr.op();
61+
PRECONDITION(pointer.type().id() == ID_pointer);
62+
63+
if(pointer.id() == ID_if)
64+
{
65+
if_exprt if_expr = lift_if(expr, 0);
66+
return changed(simplify_if_preorder(if_expr));
67+
}
68+
else
69+
{
70+
auto r_it = simplify_rec(pointer); // recursive call
71+
if(r_it.has_changed())
72+
{
73+
auto tmp = expr;
74+
tmp.op() = r_it.expr;
75+
return tmp;
76+
}
77+
}
78+
79+
return unchanged(expr);
80+
}
81+
5682
simplify_exprt::resultt<>
5783
simplify_exprt::simplify_address_of_arg(const exprt &expr)
5884
{
@@ -249,16 +275,6 @@ simplify_exprt::simplify_pointer_offset(const pointer_offset_exprt &expr)
249275
{
250276
const exprt &ptr = expr.pointer();
251277

252-
if(ptr.id()==ID_if && ptr.operands().size()==3)
253-
{
254-
if_exprt if_expr=lift_if(expr, 0);
255-
if_expr.true_case() =
256-
simplify_pointer_offset(to_pointer_offset_expr(if_expr.true_case()));
257-
if_expr.false_case() =
258-
simplify_pointer_offset(to_pointer_offset_expr(if_expr.false_case()));
259-
return changed(simplify_if(if_expr));
260-
}
261-
262278
if(ptr.type().id()!=ID_pointer)
263279
return unchanged(expr);
264280

@@ -559,16 +575,6 @@ simplify_exprt::simplify_is_dynamic_object(const unary_exprt &expr)
559575
auto new_expr = expr;
560576
exprt &op = new_expr.op();
561577

562-
if(op.id()==ID_if && op.operands().size()==3)
563-
{
564-
if_exprt if_expr=lift_if(expr, 0);
565-
if_expr.true_case() =
566-
simplify_is_dynamic_object(to_unary_expr(if_expr.true_case()));
567-
if_expr.false_case() =
568-
simplify_is_dynamic_object(to_unary_expr(if_expr.false_case()));
569-
return changed(simplify_if(if_expr));
570-
}
571-
572578
bool no_change = true;
573579

574580
auto op_result = simplify_object(op);

src/util/simplify_expr_struct.cpp

+25-14
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Author: Daniel Kroening, [email protected]
1212
#include "byte_operators.h"
1313
#include "c_types.h"
1414
#include "config.h"
15+
#include "expr_util.h"
1516
#include "invariant.h"
1617
#include "namespace.h"
1718
#include "pointer_offset_size.h"
@@ -240,20 +241,6 @@ simplify_exprt::simplify_member(const member_exprt &expr)
240241
}
241242
}
242243
}
243-
else if(op.id()==ID_if)
244-
{
245-
const if_exprt &if_expr=to_if_expr(op);
246-
exprt cond=if_expr.cond();
247-
248-
member_exprt member_false=to_member_expr(expr);
249-
member_false.compound()=if_expr.false_case();
250-
251-
member_exprt member_true = to_member_expr(expr);
252-
member_true.compound() = if_expr.true_case();
253-
254-
auto tmp = if_exprt(cond, member_true, member_false, expr.type());
255-
return changed(simplify_rec(tmp));
256-
}
257244
else if(op.id() == ID_let)
258245
{
259246
// Push a member operator inside a let binding, to avoid the let bisecting
@@ -271,3 +258,27 @@ simplify_exprt::simplify_member(const member_exprt &expr)
271258

272259
return unchanged(expr);
273260
}
261+
262+
simplify_exprt::resultt<>
263+
simplify_exprt::simplify_member_preorder(const member_exprt &expr)
264+
{
265+
const exprt &compound = expr.compound();
266+
267+
if(compound.id() == ID_if)
268+
{
269+
if_exprt if_expr = lift_if(expr, 0);
270+
return changed(simplify_if_preorder(if_expr));
271+
}
272+
else
273+
{
274+
auto r_it = simplify_rec(compound); // recursive call
275+
if(r_it.has_changed())
276+
{
277+
auto tmp = expr;
278+
tmp.compound() = r_it.expr;
279+
return tmp;
280+
}
281+
}
282+
283+
return unchanged(expr);
284+
}

0 commit comments

Comments
 (0)