Skip to content

Commit 7cf4875

Browse files
committed
Do not unnecessarily break sharing during renaming (part 3: expressions)
Not all subexpressions (or types) change during renaming. Only actually write to the result when there was a change. This preserves sharing. Performance results for this and parts 1 and 2 of the renaming combined: On SV-COMP's ReachSafety-ECA benchmarks the time spent in goto_symex_state::rename(exprt &, ...) is now 1944 seconds, when previously it was 2326 seconds. On the other hand, the time spent in merge_ireps did not improve, the number of recursive operator== calls in fact was higher (6930718243 rising to from 5710509892). The time spent in goto_symex_statet::rename(typet &, ...) increases from 530 seconds to 568 seconds, which suggests there is room for improvement.
1 parent c5a948c commit 7cf4875

File tree

2 files changed

+78
-29
lines changed

2 files changed

+78
-29
lines changed

src/goto-symex/goto_symex_state.cpp

Lines changed: 76 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ Author: Daniel Kroening, [email protected]
1414
#include <cstdlib>
1515
#include <iostream>
1616

17-
#include <util/as_const.h>
1817
#include <util/base_exceptions.h>
1918
#include <util/exception_utils.h>
2019
#include <util/expr_util.h>
@@ -291,13 +290,31 @@ template ssa_exprt goto_symex_statet::rename_ssa<goto_symex_statet::L1>(
291290

292291
template <goto_symex_statet::levelt level>
293292
exprt goto_symex_statet::rename(exprt expr, const namespacet &ns)
293+
{
294+
if(auto renamed = rename_expr<level>(expr, ns))
295+
return *renamed;
296+
else
297+
return expr;
298+
}
299+
300+
// explicitly instantiate templates
301+
template exprt goto_symex_statet::rename<goto_symex_statet::L1>(
302+
exprt expr,
303+
const namespacet &ns);
304+
template exprt goto_symex_statet::rename<goto_symex_statet::L2>(
305+
exprt expr,
306+
const namespacet &ns);
307+
308+
template <goto_symex_statet::levelt level>
309+
optionalt<exprt>
310+
goto_symex_statet::rename_expr(const exprt &expr, const namespacet &ns)
294311
{
295312
// rename all the symbols with their last known value
296313

297314
if(expr.id()==ID_symbol &&
298315
expr.get_bool(ID_C_SSA_symbol))
299316
{
300-
ssa_exprt &ssa=to_ssa_expr(expr);
317+
ssa_exprt ssa = to_ssa_expr(expr);
301318

302319
if(level == L0)
303320
{
@@ -326,7 +343,7 @@ exprt goto_symex_statet::rename(exprt expr, const namespacet &ns)
326343
auto p_it = propagation.find(ssa.get_identifier());
327344

328345
if(p_it != propagation.end())
329-
expr=p_it->second; // already L2
346+
return p_it->second; // already L2
330347
else
331348
{
332349
if(
@@ -340,6 +357,8 @@ exprt goto_symex_statet::rename(exprt expr, const namespacet &ns)
340357
set_l2_indices(ssa, ns);
341358
}
342359
}
360+
361+
return std::move(ssa);
343362
}
344363

345364
if(
@@ -349,6 +368,8 @@ exprt goto_symex_statet::rename(exprt expr, const namespacet &ns)
349368
ssa.type() = std::move(*renamed_type);
350369
ssa.update_type();
351370
}
371+
372+
return std::move(ssa);
352373
}
353374
else if(expr.id()==ID_symbol)
354375
{
@@ -359,11 +380,19 @@ exprt goto_symex_statet::rename(exprt expr, const namespacet &ns)
359380
auto renamed_type = rename_type<level>(
360381
expr.type(), to_symbol_expr(expr).get_identifier(), ns))
361382
{
362-
expr.type() = std::move(*renamed_type);
383+
exprt result = expr;
384+
result.type() = std::move(*renamed_type);
385+
return std::move(result);
363386
}
387+
else
388+
return {};
364389
}
390+
391+
ssa_exprt ssa(expr);
392+
if(auto renamed = rename_expr<level>(ssa, ns))
393+
return renamed;
365394
else
366-
expr = rename<level>(ssa_exprt{expr}, ns);
395+
return std::move(ssa);
367396
}
368397
else if(expr.id()==ID_address_of)
369398
{
@@ -375,29 +404,47 @@ exprt goto_symex_statet::rename(exprt expr, const namespacet &ns)
375404
address_of_exprt result = address_of_expr;
376405
result.object() = std::move(*renamed_object);
377406
to_pointer_type(result.type()).subtype() = result.object().type();
378-
expr = std::move(result);
407+
return std::move(result);
379408
}
409+
else
410+
return {};
380411
}
381412
else
382413
{
414+
exprt result = expr;
415+
bool modified = false;
416+
383417
if(auto renamed_type = rename_type<level>(expr.type(), irep_idt(), ns))
384418
{
385-
expr.type() = std::move(*renamed_type);
419+
result.type() = std::move(*renamed_type);
420+
modified = true;
386421
}
387422

388423
// do this recursively
389-
Forall_operands(it, expr)
390-
*it = rename<level>(std::move(*it), ns);
424+
exprt::operandst::iterator op_it = result.operands().begin();
425+
forall_operands(it, expr)
426+
{
427+
if(auto renamed_op = rename_expr<level>(*it, ns))
428+
{
429+
*op_it = std::move(*renamed_op);
430+
modified = true;
431+
}
432+
++op_it;
433+
}
391434

392-
const exprt &c_expr = as_const(expr);
393435
INVARIANT(
394436
(expr.id() != ID_with ||
395-
c_expr.type() == to_with_expr(c_expr).old().type()) &&
437+
expr.type() == to_with_expr(expr).old().type()) &&
396438
(expr.id() != ID_if ||
397-
(c_expr.type() == to_if_expr(c_expr).true_case().type() &&
398-
c_expr.type() == to_if_expr(c_expr).false_case().type())),
439+
(expr.type() == to_if_expr(expr).true_case().type() &&
440+
expr.type() == to_if_expr(expr).false_case().type())),
399441
"Type of renamed expr should be the same as operands for with_exprt and "
400442
"if_exprt");
443+
444+
if(modified)
445+
return std::move(result);
446+
else
447+
return {};
401448
}
402449
return expr;
403450
}
@@ -616,9 +663,9 @@ goto_symex_statet::rename_address(const exprt &expr, const namespacet &ns)
616663
auto renamed_array = rename_address<level>(index_expr.array(), ns);
617664

618665
// the index is not an address
619-
auto renamed_index = rename<level>(index_expr.index(), ns);
666+
auto renamed_index = rename_expr<level>(index_expr.index(), ns);
620667

621-
if(renamed_array.has_value() || renamed_index != index_expr.index())
668+
if(renamed_array.has_value() || renamed_index.has_value())
622669
{
623670
index_exprt result = index_expr;
624671

@@ -628,8 +675,8 @@ goto_symex_statet::rename_address(const exprt &expr, const namespacet &ns)
628675
result.type() = to_array_type(result.array().type()).subtype();
629676
}
630677

631-
if(renamed_index != index_expr.index())
632-
result.index() = std::move(renamed_index);
678+
if(renamed_index.has_value())
679+
result.index() = std::move(*renamed_index);
633680

634681
return std::move(result);
635682
}
@@ -640,18 +687,18 @@ goto_symex_statet::rename_address(const exprt &expr, const namespacet &ns)
640687
{
641688
// the condition is not an address
642689
const if_exprt &if_expr = to_if_expr(expr);
643-
auto renamed_cond = rename<level>(if_expr.cond(), ns);
690+
auto renamed_cond = rename_expr<level>(if_expr.cond(), ns);
644691
auto renamed_true = rename_address<level>(if_expr.true_case(), ns);
645692
auto renamed_false = rename_address<level>(if_expr.false_case(), ns);
646693

647694
if(
648-
renamed_cond != if_expr.cond() || renamed_true.has_value() ||
695+
renamed_cond.has_value() || renamed_true.has_value() ||
649696
renamed_false.has_value())
650697
{
651698
if_exprt result = if_expr;
652699

653-
if(renamed_cond != if_expr.cond())
654-
result.cond() = std::move(renamed_cond);
700+
if(renamed_cond.has_value())
701+
result.cond() = std::move(*renamed_cond);
655702

656703
if(renamed_true.has_value())
657704
{
@@ -851,17 +898,17 @@ optionalt<typet> goto_symex_statet::rename_type(
851898
auto &array_type = to_array_type(type);
852899
auto renamed_subtype =
853900
rename_type<level>(array_type.subtype(), irep_idt(), ns);
854-
auto renamed_size = rename<level>(array_type.size(), ns);
901+
auto renamed_size = rename_expr<level>(array_type.size(), ns);
855902

856-
if(renamed_subtype.has_value() || renamed_size != array_type.size())
903+
if(renamed_subtype.has_value() || renamed_size.has_value())
857904
{
858905
array_typet result_type = array_type;
859906

860907
if(renamed_subtype.has_value())
861908
result_type.subtype() = std::move(*renamed_subtype);
862909

863-
if(renamed_size != array_type.size())
864-
result_type.size() = std::move(renamed_size);
910+
if(renamed_size.has_value())
911+
result_type.size() = std::move(*renamed_size);
865912

866913
result = std::move(result_type);
867914
}
@@ -878,11 +925,11 @@ optionalt<typet> goto_symex_statet::rename_type(
878925
// be careful, or it might get cyclic
879926
if(component.type().id() == ID_array)
880927
{
881-
auto &array_type = to_array_type(component.type());
882-
auto renamed_expr = rename<level>(array_type.size(), ns);
883-
if(renamed_expr != array_type.size())
928+
if(
929+
auto renamed_expr =
930+
rename_expr<level>(to_array_type(component.type()).size(), ns))
884931
{
885-
to_array_type(comp_it->type()).size() = std::move(renamed_expr);
932+
to_array_type(comp_it->type()).size() = std::move(*renamed_expr);
886933
modified = true;
887934
}
888935
}

src/goto-symex/goto_symex_state.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ class goto_symex_statet final : public goto_statet
202202
template <levelt>
203203
optionalt<exprt> rename_address(const exprt &expr, const namespacet &ns);
204204
template <levelt>
205+
optionalt<exprt> rename_expr(const exprt &expr, const namespacet &ns);
206+
template <levelt>
205207
optionalt<typet> rename_type(
206208
const typet &type,
207209
const irep_idt &l1_identifier,

0 commit comments

Comments
 (0)