Skip to content

Commit ce3e340

Browse files
committed
Do not unnecessarily break sharing during SSA renaming (part 1: types)
Instead of editing the object in place, return an optional<typet> that is set if, and only if, a modification took place.
1 parent 31a06e8 commit ce3e340

File tree

2 files changed

+117
-28
lines changed

2 files changed

+117
-28
lines changed

src/goto-symex/goto_symex_state.cpp

Lines changed: 110 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ ssa_exprt goto_symex_statet::rename_ssa(ssa_exprt ssa, const namespacet &ns)
274274
return ssa;
275275
}
276276

277-
/// Ensure `rename_ssa` gets compiled for L0
277+
// explicitly instantiate templates
278278
template ssa_exprt
279279
goto_symex_statet::rename_ssa<L0>(ssa_exprt ssa, const namespacet &ns);
280280
template ssa_exprt
@@ -301,8 +301,13 @@ exprt goto_symex_statet::rename(exprt expr, const namespacet &ns)
301301
else if(level==L2)
302302
{
303303
ssa = set_indices<L1>(std::move(ssa), ns).get();
304-
rename<level>(expr.type(), ssa.get_identifier(), ns);
305-
ssa.update_type();
304+
if(
305+
auto renamed_type =
306+
rename_type<level>(expr.type(), ssa.get_identifier(), ns))
307+
{
308+
ssa.type() = std::move(*renamed_type);
309+
ssa.update_type();
310+
}
306311

307312
if(l2_thread_read_encoding(ssa, ns))
308313
{
@@ -327,11 +332,18 @@ exprt goto_symex_statet::rename(exprt expr, const namespacet &ns)
327332
}
328333
else if(expr.id()==ID_symbol)
329334
{
330-
const auto &type = as_const(expr).type();
331-
332335
// we never rename function symbols
333-
if(type.id() == ID_code || type.id() == ID_mathematical_function)
334-
rename<level>(expr.type(), to_symbol_expr(expr).get_identifier(), ns);
336+
if(
337+
expr.type().id() == ID_code ||
338+
expr.type().id() == ID_mathematical_function)
339+
{
340+
if(
341+
auto renamed_type = rename_type<level>(
342+
expr.type(), to_symbol_expr(expr).get_identifier(), ns))
343+
{
344+
expr.type() = std::move(*renamed_type);
345+
}
346+
}
335347
else
336348
expr = rename<level>(ssa_exprt{expr}, ns);
337349
}
@@ -344,7 +356,10 @@ exprt goto_symex_statet::rename(exprt expr, const namespacet &ns)
344356
}
345357
else
346358
{
347-
rename<level>(expr.type(), irep_idt(), ns);
359+
if(auto renamed_type = rename_type<level>(expr.type(), irep_idt(), ns))
360+
{
361+
expr.type() = std::move(*renamed_type);
362+
}
348363

349364
// do this recursively
350365
Forall_operands(it, expr)
@@ -363,8 +378,6 @@ exprt goto_symex_statet::rename(exprt expr, const namespacet &ns)
363378
return expr;
364379
}
365380

366-
template exprt goto_symex_statet::rename<L1>(exprt expr, const namespacet &ns);
367-
368381
/// thread encoding
369382
bool goto_symex_statet::l2_thread_read_encoding(
370383
ssa_exprt &expr,
@@ -548,8 +561,13 @@ void goto_symex_statet::rename_address(exprt &expr, const namespacet &ns)
548561
// only do L1!
549562
ssa = set_indices<L1>(std::move(ssa), ns).get();
550563

551-
rename<level>(expr.type(), ssa.get_identifier(), ns);
552-
ssa.update_type();
564+
if(
565+
auto renamed_type =
566+
rename_type<level>(expr.type(), ssa.get_identifier(), ns))
567+
{
568+
ssa.type() = std::move(*renamed_type);
569+
ssa.update_type();
570+
}
553571
}
554572
else if(expr.id()==ID_symbol)
555573
{
@@ -667,11 +685,29 @@ void goto_symex_statet::rename(
667685
typet &type,
668686
const irep_idt &l1_identifier,
669687
const namespacet &ns)
688+
{
689+
if(auto renamed = rename_type<level>(type, l1_identifier, ns))
690+
type = std::move(*renamed);
691+
}
692+
693+
// explicitly instantiate templates
694+
/// \cond
695+
template void goto_symex_statet::rename<L2>(
696+
typet &type,
697+
const irep_idt &l1_identifier,
698+
const namespacet &ns);
699+
/// \endcond
700+
701+
template <levelt level>
702+
optionalt<typet> goto_symex_statet::rename_type(
703+
const typet &type,
704+
const irep_idt &l1_identifier,
705+
const namespacet &ns)
670706
{
671707
// check whether there are symbol expressions in the type; if not, there
672708
// is no need to expand the struct/union tags in the type
673709
if(!requires_renaming(type, ns))
674-
return; // no action
710+
return {};
675711

676712
// rename all the symbols with their last known value
677713
// to the given level
@@ -693,46 +729,92 @@ void goto_symex_statet::rename(
693729
to_array_type(type).is_incomplete() ||
694730
to_array_type(type_prev).is_complete())
695731
{
696-
type=l1_type_entry.first->second;
697-
return;
732+
return l1_type_entry.first->second;
698733
}
699734
}
700735
}
701736

702-
// expand struct and union tag types
703-
type = ns.follow(type);
737+
optionalt<typet> result;
704738

705739
if(type.id()==ID_array)
706740
{
707741
auto &array_type = to_array_type(type);
708-
rename<level>(array_type.subtype(), irep_idt(), ns);
709-
array_type.size() = rename<level>(std::move(array_type.size()), ns);
742+
auto renamed_subtype =
743+
rename_type<level>(array_type.subtype(), irep_idt(), ns);
744+
auto renamed_size = rename<level>(array_type.size(), ns);
745+
746+
if(renamed_subtype.has_value() || renamed_size != array_type.size())
747+
{
748+
array_typet result_type = array_type;
749+
750+
if(renamed_subtype.has_value())
751+
result_type.subtype() = std::move(*renamed_subtype);
752+
753+
if(renamed_size != array_type.size())
754+
result_type.size() = std::move(renamed_size);
755+
756+
result = std::move(result_type);
757+
}
710758
}
711759
else if(type.id() == ID_struct || type.id() == ID_union)
712760
{
713-
struct_union_typet &s_u_type=to_struct_union_type(type);
714-
struct_union_typet::componentst &components=s_u_type.components();
761+
struct_union_typet s_u_type = to_struct_union_type(type);
762+
bool modified = false;
715763

716-
for(auto &component : components)
764+
struct_union_typet::componentst::iterator comp_it =
765+
s_u_type.components().begin();
766+
for(auto &component : to_struct_union_type(type).components())
717767
{
718768
// be careful, or it might get cyclic
719769
if(component.type().id() == ID_array)
720770
{
721771
auto &array_type = to_array_type(component.type());
722-
array_type.size() = rename<level>(std::move(array_type.size()), ns);
772+
auto renamed_expr = rename<level>(array_type.size(), ns);
773+
if(renamed_expr != array_type.size())
774+
{
775+
to_array_type(comp_it->type()).size() = std::move(renamed_expr);
776+
modified = true;
777+
}
723778
}
724779
else if(component.type().id() != ID_pointer)
725-
rename<level>(component.type(), irep_idt(), ns);
780+
{
781+
if(
782+
auto renamed_type =
783+
rename_type<level>(component.type(), irep_idt(), ns))
784+
{
785+
comp_it->type() = std::move(*renamed_type);
786+
modified = true;
787+
}
788+
}
789+
790+
++comp_it;
726791
}
792+
793+
if(modified)
794+
result = std::move(s_u_type);
727795
}
728796
else if(type.id()==ID_pointer)
729797
{
730-
rename<level>(to_pointer_type(type).subtype(), irep_idt(), ns);
798+
auto renamed_subtype =
799+
rename_type<level>(to_pointer_type(type).subtype(), irep_idt(), ns);
800+
if(renamed_subtype.has_value())
801+
{
802+
result = pointer_typet{std::move(*renamed_subtype),
803+
to_pointer_type(type).get_width()};
804+
}
805+
}
806+
else if(type.id() == ID_struct_tag || type.id() == ID_union_tag)
807+
{
808+
const typet &followed_type = ns.follow(type);
809+
result = rename_type<level>(followed_type, l1_identifier, ns);
810+
if(!result.has_value())
811+
result = followed_type;
731812
}
732813

733-
if(level==L2 &&
734-
!l1_identifier.empty())
735-
l1_type_entry.first->second=type;
814+
if(level == L2 && !l1_identifier.empty() && result.has_value())
815+
l1_type_entry.first->second = *result;
816+
817+
return result;
736818
}
737819

738820
static void get_l1_name(exprt &expr)

src/goto-symex/goto_symex_state.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ class goto_symex_statet final : public goto_statet
9898
template <levelt level>
9999
ssa_exprt rename_ssa(ssa_exprt ssa, const namespacet &ns);
100100

101+
/// Perform renaming of expressions contained in types, which is necessary for
102+
/// arrays of non-constant size.
101103
template <levelt level = L2>
102104
void rename(typet &type, const irep_idt &l1_identifier, const namespacet &ns);
103105

@@ -112,6 +114,11 @@ class goto_symex_statet final : public goto_statet
112114
protected:
113115
template <levelt>
114116
void rename_address(exprt &expr, const namespacet &ns);
117+
template <levelt>
118+
optionalt<typet> rename_type(
119+
const typet &type,
120+
const irep_idt &l1_identifier,
121+
const namespacet &ns);
115122

116123
/// Update values up to \c level.
117124
template <levelt level>

0 commit comments

Comments
 (0)