Skip to content

Commit 71aec16

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 699d8d2 commit 71aec16

File tree

2 files changed

+95
-34
lines changed

2 files changed

+95
-34
lines changed

src/goto-symex/goto_symex_state.cpp

Lines changed: 93 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -282,13 +282,27 @@ goto_symex_statet::rename_ssa<L1>(ssa_exprt ssa, const namespacet &ns);
282282

283283
template <levelt level>
284284
exprt goto_symex_statet::rename(exprt expr, const namespacet &ns)
285+
{
286+
if(auto renamed = rename_expr<level>(expr, ns))
287+
return *renamed;
288+
else
289+
return expr;
290+
}
291+
292+
// explicitly instantiate templates
293+
template exprt goto_symex_statet::rename<L1>(exprt expr, const namespacet &ns);
294+
template exprt goto_symex_statet::rename<L2>(exprt expr, const namespacet &ns);
295+
296+
template <levelt level>
297+
optionalt<exprt>
298+
goto_symex_statet::rename_expr(const exprt &expr, const namespacet &ns)
285299
{
286300
// rename all the symbols with their last known value
287301

288302
if(expr.id()==ID_symbol &&
289303
expr.get_bool(ID_C_SSA_symbol))
290304
{
291-
ssa_exprt &ssa=to_ssa_expr(expr);
305+
ssa_exprt ssa = to_ssa_expr(expr);
292306

293307
if(level == L0)
294308
{
@@ -324,11 +338,13 @@ exprt goto_symex_statet::rename(exprt expr, const namespacet &ns)
324338
auto p_it = propagation.find(ssa.get_identifier());
325339

326340
if(p_it != propagation.end())
327-
expr=p_it->second; // already L2
341+
return p_it->second; // already L2
328342
else
329343
ssa = set_indices<L2>(std::move(ssa), ns).get();
330344
}
331345
}
346+
347+
return std::move(ssa);
332348
}
333349
else if(expr.id()==ID_symbol)
334350
{
@@ -341,40 +357,83 @@ exprt goto_symex_statet::rename(exprt expr, const namespacet &ns)
341357
auto renamed_type = rename_type<level>(
342358
expr.type(), to_symbol_expr(expr).get_identifier(), ns))
343359
{
344-
expr.type() = std::move(*renamed_type);
360+
exprt result = expr;
361+
result.type() = std::move(*renamed_type);
362+
return std::move(result);
345363
}
364+
else
365+
return {};
346366
}
367+
368+
ssa_exprt ssa{expr};
369+
if(auto renamed = rename_expr<level>(ssa, ns))
370+
return renamed;
347371
else
348-
expr = rename<level>(ssa_exprt{expr}, ns);
372+
return std::move(ssa);
349373
}
350374
else if(expr.id()==ID_address_of)
351375
{
352376
auto &address_of_expr = to_address_of_expr(expr);
353377
auto renamed_object = rename_address<level>(address_of_expr.object(), ns);
354378

355379
if(renamed_object.has_value())
356-
expr = address_of_exprt{std::move(*renamed_object)};
380+
return address_of_exprt{std::move(*renamed_object)};
381+
else
382+
return {};
357383
}
358384
else
359385
{
386+
optionalt<exprt> result;
387+
360388
if(auto renamed_type = rename_type<level>(expr.type(), irep_idt(), ns))
361389
{
362-
expr.type() = std::move(*renamed_type);
390+
result = expr;
391+
result->type() = std::move(*renamed_type);
363392
}
364393

365394
// do this recursively
366-
Forall_operands(it, expr)
367-
*it = rename<level>(std::move(*it), ns);
368-
369-
const exprt &c_expr = as_const(expr);
370-
INVARIANT(
371-
(expr.id() != ID_with ||
372-
c_expr.type() == to_with_expr(c_expr).old().type()) &&
373-
(expr.id() != ID_if ||
374-
(c_expr.type() == to_if_expr(c_expr).true_case().type() &&
375-
c_expr.type() == to_if_expr(c_expr).false_case().type())),
376-
"Type of renamed expr should be the same as operands for with_exprt and "
377-
"if_exprt");
395+
optionalt<exprt::operandst> result_operands;
396+
std::size_t op_index = 0;
397+
398+
for(auto &op : expr.operands())
399+
{
400+
if(auto renamed_op = rename_expr<level>(op, ns))
401+
{
402+
if(!result_operands.has_value())
403+
result_operands = expr.operands();
404+
405+
(*result_operands)[op_index] = std::move(*renamed_op);
406+
}
407+
++op_index;
408+
}
409+
410+
if(result_operands.has_value())
411+
{
412+
if(!result.has_value())
413+
result = expr;
414+
415+
result->operands() = std::move(*result_operands);
416+
}
417+
418+
if(result.has_value())
419+
{
420+
const exprt &c_expr = as_const(*result);
421+
if(expr.id() == ID_with)
422+
{
423+
INVARIANT(
424+
c_expr.type() == to_with_expr(c_expr).old().type(),
425+
"type of renamed expr should be the same as operands for with_exprt");
426+
}
427+
else if(expr.id() == ID_if)
428+
{
429+
INVARIANT(
430+
c_expr.type() == to_if_expr(c_expr).true_case().type() &&
431+
c_expr.type() == to_if_expr(c_expr).false_case().type(),
432+
"type of renamed expr should be the same as operands for if_exprt");
433+
}
434+
}
435+
436+
return result;
378437
}
379438
return expr;
380439
}
@@ -588,9 +647,9 @@ goto_symex_statet::rename_address(const exprt &expr, const namespacet &ns)
588647
auto renamed_array = rename_address<level>(index_expr.array(), ns);
589648

590649
// the index is not an address
591-
auto renamed_index = rename<level>(index_expr.index(), ns);
650+
auto renamed_index = rename_expr<level>(index_expr.index(), ns);
592651

593-
if(renamed_array.has_value() || renamed_index != index_expr.index())
652+
if(renamed_array.has_value() || renamed_index.has_value())
594653
{
595654
index_exprt result = index_expr;
596655

@@ -600,8 +659,8 @@ goto_symex_statet::rename_address(const exprt &expr, const namespacet &ns)
600659
result.type() = to_array_type(result.array().type()).subtype();
601660
}
602661

603-
if(renamed_index != index_expr.index())
604-
result.index() = std::move(renamed_index);
662+
if(renamed_index.has_value())
663+
result.index() = std::move(*renamed_index);
605664

606665
return std::move(result);
607666
}
@@ -612,18 +671,18 @@ goto_symex_statet::rename_address(const exprt &expr, const namespacet &ns)
612671
{
613672
// the condition is not an address
614673
const if_exprt &if_expr = to_if_expr(expr);
615-
auto renamed_cond = rename<level>(if_expr.cond(), ns);
674+
auto renamed_cond = rename_expr<level>(if_expr.cond(), ns);
616675
auto renamed_true = rename_address<level>(if_expr.true_case(), ns);
617676
auto renamed_false = rename_address<level>(if_expr.false_case(), ns);
618677

619678
if(
620-
renamed_cond != if_expr.cond() || renamed_true.has_value() ||
679+
renamed_cond.has_value() || renamed_true.has_value() ||
621680
renamed_false.has_value())
622681
{
623682
if_exprt result = if_expr;
624683

625-
if(renamed_cond != if_expr.cond())
626-
result.cond() = std::move(renamed_cond);
684+
if(renamed_cond.has_value())
685+
result.cond() = std::move(*renamed_cond);
627686

628687
if(renamed_true.has_value())
629688
{
@@ -773,17 +832,17 @@ optionalt<typet> goto_symex_statet::rename_type(
773832
auto &array_type = to_array_type(type);
774833
auto renamed_subtype =
775834
rename_type<level>(array_type.subtype(), irep_idt(), ns);
776-
auto renamed_size = rename<level>(array_type.size(), ns);
835+
auto renamed_size = rename_expr<level>(array_type.size(), ns);
777836

778-
if(renamed_subtype.has_value() || renamed_size != array_type.size())
837+
if(renamed_subtype.has_value() || renamed_size.has_value())
779838
{
780839
array_typet result_type = array_type;
781840

782841
if(renamed_subtype.has_value())
783842
result_type.subtype() = std::move(*renamed_subtype);
784843

785-
if(renamed_size != array_type.size())
786-
result_type.size() = std::move(renamed_size);
844+
if(renamed_size.has_value())
845+
result_type.size() = std::move(*renamed_size);
787846

788847
result = std::move(result_type);
789848
}
@@ -800,11 +859,11 @@ optionalt<typet> goto_symex_statet::rename_type(
800859
// be careful, or it might get cyclic
801860
if(component.type().id() == ID_array)
802861
{
803-
auto &array_type = to_array_type(component.type());
804-
auto renamed_expr = rename<level>(array_type.size(), ns);
805-
if(renamed_expr != array_type.size())
862+
if(
863+
auto renamed_expr =
864+
rename_expr<level>(to_array_type(component.type()).size(), ns))
806865
{
807-
to_array_type(comp_it->type()).size() = std::move(renamed_expr);
866+
to_array_type(comp_it->type()).size() = std::move(*renamed_expr);
808867
modified = true;
809868
}
810869
}

src/goto-symex/goto_symex_state.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ class goto_symex_statet final : public goto_statet
115115
template <levelt>
116116
optionalt<exprt> rename_address(const exprt &expr, const namespacet &ns);
117117
template <levelt>
118+
optionalt<exprt> rename_expr(const exprt &expr, const namespacet &ns);
119+
template <levelt>
118120
optionalt<typet> rename_type(
119121
const typet &type,
120122
const irep_idt &l1_identifier,

0 commit comments

Comments
 (0)