@@ -99,6 +99,36 @@ static json_objectt value_set_dereference_stats_to_json(
9999 return json_result;
100100}
101101
102+ optionalt<exprt> value_set_dereferencet::try_add_offset_to_indices (
103+ const exprt &expr,
104+ const exprt &offset_elements)
105+ {
106+ if (const auto *index_expr = expr_try_dynamic_cast<index_exprt>(expr))
107+ {
108+ return index_exprt{
109+ index_expr->array (),
110+ plus_exprt{index_expr->index (),
111+ typecast_exprt::conditional_cast (
112+ offset_elements, index_expr->index ().type ())}};
113+ }
114+ else if (const auto *if_expr = expr_try_dynamic_cast<if_exprt>(expr))
115+ {
116+ const auto true_case =
117+ try_add_offset_to_indices (if_expr->true_case (), offset_elements);
118+ if (!true_case)
119+ return {};
120+ const auto false_case =
121+ try_add_offset_to_indices (if_expr->false_case (), offset_elements);
122+ if (!false_case)
123+ return {};
124+ return if_exprt{if_expr->cond (), *true_case, *false_case};
125+ }
126+ else
127+ {
128+ return {};
129+ }
130+ }
131+
102132exprt value_set_dereferencet::dereference (
103133 const exprt &pointer,
104134 bool display_points_to_sets)
@@ -140,6 +170,33 @@ exprt value_set_dereferencet::dereference(
140170 display_points_to_sets));
141171 }
142172 }
173+ else if (pointer.id () == ID_plus && pointer.operands ().size () == 2 )
174+ {
175+ // Try to improve results for *(p + i) where p points to known offsets but
176+ // i is non-constant-- if `p` points to known positions in arrays or array-members
177+ // of structs then we can add the non-constant expression `i` to the index
178+ // instead of using a byte-extract expression.
179+
180+ exprt pointer_expr = to_plus_expr (pointer).op0 ();
181+ exprt offset_expr = to_plus_expr (pointer).op1 ();
182+
183+ if (can_cast_type<pointer_typet>(offset_expr.type ()))
184+ std::swap (pointer_expr, offset_expr);
185+
186+ if (
187+ can_cast_type<pointer_typet>(pointer_expr.type ()) &&
188+ !can_cast_type<pointer_typet>(offset_expr.type ()) &&
189+ !can_cast_expr<constant_exprt>(offset_expr))
190+ {
191+ exprt derefd_pointer = dereference (pointer_expr);
192+ if (
193+ auto derefd_with_offset =
194+ try_add_offset_to_indices (derefd_pointer, offset_expr))
195+ return *derefd_with_offset;
196+
197+ // If any of this fails, fall through to use the normal byte-extract path.
198+ }
199+ }
143200
144201 return handle_dereference_base_case (pointer, display_points_to_sets);
145202}
0 commit comments