@@ -15,6 +15,7 @@ Author: Daniel Kroening, kroening@kroening.com
1515#include < util/byte_operators.h>
1616#include < util/c_types.h>
1717#include < util/pointer_expr.h>
18+ #include < util/pointer_offset_size.h>
1819#include < util/std_code.h>
1920
2021#include < goto-programs/goto_model.h>
@@ -116,3 +117,65 @@ void rewrite_union(goto_modelt &goto_model)
116117{
117118 rewrite_union (goto_model.goto_functions );
118119}
120+
121+ // / Undo the union access -> byte_extract replacement that rewrite_union did for
122+ // / the purpose of displaying expressions to users.
123+ // / \param expr: expression to inspect and possibly transform
124+ // / \param ns: namespace
125+ // / \return True if, and only if, the expression is unmodified
126+ static bool restore_union_rec (exprt &expr, const namespacet &ns)
127+ {
128+ bool unmodified = true ;
129+
130+ Forall_operands (it, expr)
131+ unmodified &= restore_union_rec (*it, ns);
132+
133+ if (
134+ expr.id () == ID_byte_extract_little_endian ||
135+ expr.id () == ID_byte_extract_big_endian)
136+ {
137+ byte_extract_exprt &be = to_byte_extract_expr (expr);
138+ if (be.op ().type ().id () == ID_union || be.op ().type ().id () == ID_union_tag)
139+ {
140+ const union_typet &union_type = to_union_type (ns.follow (be.op ().type ()));
141+
142+ for (const auto &comp : union_type.components ())
143+ {
144+ if (be.offset ().is_zero () && be.type () == comp.type ())
145+ {
146+ expr = member_exprt{be.op (), comp.get_name (), be.type ()};
147+ return false ;
148+ }
149+ else if (
150+ comp.type ().id () == ID_array || comp.type ().id () == ID_struct ||
151+ comp.type ().id () == ID_struct_tag)
152+ {
153+ optionalt<exprt> result = get_subexpression_at_offset (
154+ member_exprt{be.op (), comp.get_name (), comp.type ()},
155+ be.offset (),
156+ be.type (),
157+ ns);
158+ if (result.has_value ())
159+ {
160+ expr = *result;
161+ return false ;
162+ }
163+ }
164+ }
165+ }
166+ }
167+
168+ return unmodified;
169+ }
170+
171+ // / Undo the union access -> byte_extract replacement that rewrite_union did for
172+ // / the purpose of displaying expressions to users.
173+ // / \param expr: expression to inspect and possibly transform
174+ // / \param ns: namespace
175+ void restore_union (exprt &expr, const namespacet &ns)
176+ {
177+ exprt tmp = expr;
178+
179+ if (!restore_union_rec (tmp, ns))
180+ expr.swap (tmp);
181+ }
0 commit comments