Skip to content

Commit 0d26292

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

5 files changed

+178
-75
lines changed

src/util/simplify_expr.cpp

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

1375-
if(pointer.id()==ID_if && pointer.operands().size()==3)
1376-
{
1377-
const if_exprt &if_expr=to_if_expr(pointer);
1378-
1379-
auto tmp_op1 = expr;
1380-
tmp_op1.op() = if_expr.true_case();
1381-
exprt tmp_op1_result = simplify_dereference(tmp_op1);
1382-
1383-
auto tmp_op2 = expr;
1384-
tmp_op2.op() = if_expr.false_case();
1385-
exprt tmp_op2_result = simplify_dereference(tmp_op2);
1386-
1387-
if_exprt tmp{if_expr.cond(), tmp_op1_result, tmp_op2_result};
1388-
1389-
return changed(simplify_if(tmp));
1390-
}
1391-
13921375
if(pointer.id()==ID_address_of)
13931376
{
13941377
exprt tmp=to_address_of_expr(pointer).object();
@@ -1422,6 +1405,30 @@ simplify_exprt::simplify_dereference(const dereference_exprt &expr)
14221405
return unchanged(expr);
14231406
}
14241407

1408+
simplify_exprt::resultt<>
1409+
simplify_exprt::simplify_dereference_preorder(const dereference_exprt &expr)
1410+
{
1411+
const exprt &pointer = expr.pointer();
1412+
1413+
if(pointer.id() == ID_if)
1414+
{
1415+
if_exprt if_expr = lift_if(expr, 0);
1416+
return changed(simplify_if_preorder(if_expr));
1417+
}
1418+
else
1419+
{
1420+
auto r_it = simplify_rec(pointer); // recursive call
1421+
if(r_it.has_changed())
1422+
{
1423+
auto tmp = expr;
1424+
tmp.pointer() = r_it.expr;
1425+
return tmp;
1426+
}
1427+
}
1428+
1429+
return unchanged(expr);
1430+
}
1431+
14251432
simplify_exprt::resultt<>
14261433
simplify_exprt::simplify_lambda(const lambda_exprt &expr)
14271434
{
@@ -1638,17 +1645,6 @@ simplify_exprt::resultt<> simplify_exprt::simplify_object(const exprt &expr)
16381645
simplify_exprt::resultt<>
16391646
simplify_exprt::simplify_byte_extract(const byte_extract_exprt &expr)
16401647
{
1641-
// lift up any ID_if on the object
1642-
if(expr.op().id()==ID_if)
1643-
{
1644-
if_exprt if_expr=lift_if(expr, 0);
1645-
if_expr.true_case() =
1646-
simplify_byte_extract(to_byte_extract_expr(if_expr.true_case()));
1647-
if_expr.false_case() =
1648-
simplify_byte_extract(to_byte_extract_expr(if_expr.false_case()));
1649-
return changed(simplify_if(if_expr));
1650-
}
1651-
16521648
const auto el_size = pointer_offset_bits(expr.type(), ns);
16531649
if(el_size.has_value() && *el_size < 0)
16541650
return unchanged(expr);
@@ -1989,6 +1985,41 @@ simplify_exprt::simplify_byte_extract(const byte_extract_exprt &expr)
19891985
return unchanged(expr);
19901986
}
19911987

1988+
simplify_exprt::resultt<>
1989+
simplify_exprt::simplify_byte_extract_preorder(const byte_extract_exprt &expr)
1990+
{
1991+
// lift up any ID_if on the object
1992+
if(expr.op().id() == ID_if)
1993+
{
1994+
if_exprt if_expr = lift_if(expr, 0);
1995+
return changed(simplify_if_preorder(if_expr));
1996+
}
1997+
else
1998+
{
1999+
optionalt<exprt::operandst> new_operands;
2000+
2001+
for(std::size_t i = 0; i < expr.operands().size(); ++i)
2002+
{
2003+
auto r_it = simplify_rec(expr.operands()[i]); // recursive call
2004+
if(r_it.has_changed())
2005+
{
2006+
if(!new_operands.has_value())
2007+
new_operands = expr.operands();
2008+
(*new_operands)[i] = std::move(r_it.expr);
2009+
}
2010+
}
2011+
2012+
if(new_operands.has_value())
2013+
{
2014+
exprt result = expr;
2015+
std::swap(result.operands(), *new_operands);
2016+
return result;
2017+
}
2018+
}
2019+
2020+
return unchanged(expr);
2021+
}
2022+
19922023
simplify_exprt::resultt<>
19932024
simplify_exprt::simplify_byte_update(const byte_update_exprt &expr)
19942025
{
@@ -2718,6 +2749,31 @@ simplify_exprt::simplify_node_preorder(const exprt &expr)
27182749
{
27192750
result = simplify_typecast_preorder(to_typecast_expr(expr));
27202751
}
2752+
else if(
2753+
expr.id() == ID_byte_extract_little_endian ||
2754+
expr.id() == ID_byte_extract_big_endian)
2755+
{
2756+
result = simplify_byte_extract_preorder(to_byte_extract_expr(expr));
2757+
}
2758+
else if(expr.id() == ID_dereference)
2759+
{
2760+
result = simplify_dereference_preorder(to_dereference_expr(expr));
2761+
}
2762+
else if(expr.id() == ID_index)
2763+
{
2764+
result = simplify_index_preorder(to_index_expr(expr));
2765+
}
2766+
else if(expr.id() == ID_member)
2767+
{
2768+
result = simplify_member_preorder(to_member_expr(expr));
2769+
}
2770+
else if(
2771+
expr.id() == ID_is_dynamic_object || expr.id() == ID_is_invalid_pointer ||
2772+
expr.id() == ID_object_size || expr.id() == ID_pointer_object ||
2773+
expr.id() == ID_pointer_offset)
2774+
{
2775+
result = simplify_unary_pointer_predicate_preorder(to_unary_expr(expr));
2776+
}
27212777
else if(expr.has_operands())
27222778
{
27232779
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
@@ -173,17 +173,24 @@ class simplify_exprt
173173
NODISCARD resultt<> simplify_with(const with_exprt &);
174174
NODISCARD resultt<> simplify_update(const update_exprt &);
175175
NODISCARD resultt<> simplify_index(const index_exprt &);
176+
NODISCARD resultt<> simplify_index_preorder(const index_exprt &);
176177
NODISCARD resultt<> simplify_member(const member_exprt &);
178+
NODISCARD resultt<> simplify_member_preorder(const member_exprt &);
177179
NODISCARD resultt<> simplify_byte_update(const byte_update_exprt &);
178180
NODISCARD resultt<> simplify_byte_extract(const byte_extract_exprt &);
181+
NODISCARD resultt<>
182+
simplify_byte_extract_preorder(const byte_extract_exprt &);
179183
NODISCARD resultt<> simplify_pointer_object(const pointer_object_exprt &);
184+
NODISCARD resultt<>
185+
simplify_unary_pointer_predicate_preorder(const unary_exprt &);
180186
NODISCARD resultt<> simplify_object_size(const object_size_exprt &);
181187
NODISCARD resultt<> simplify_is_dynamic_object(const unary_exprt &);
182188
NODISCARD resultt<> simplify_is_invalid_pointer(const unary_exprt &);
183189
NODISCARD resultt<> simplify_object(const exprt &);
184190
NODISCARD resultt<> simplify_unary_minus(const unary_minus_exprt &);
185191
NODISCARD resultt<> simplify_unary_plus(const unary_plus_exprt &);
186192
NODISCARD resultt<> simplify_dereference(const dereference_exprt &);
193+
NODISCARD resultt<> simplify_dereference_preorder(const dereference_exprt &);
187194
NODISCARD resultt<> simplify_address_of(const address_of_exprt &);
188195
NODISCARD resultt<> simplify_pointer_offset(const pointer_offset_exprt &);
189196
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)