@@ -120,6 +120,24 @@ static void create_static_function_call(
120
120
call.arguments ()[0 ].make_typecast (need_type);
121
121
}
122
122
123
+ // / Create a disjunction, or add to an existing one. For example,
124
+ // / `add_to_disjunction(x || y, z)` = `x || y || z` (a ternary operation, not
125
+ // / nested binary operations), but `add_to_disjunction(w, z)` where `w` is not
126
+ // / an or_exprt already = `w || z`.
127
+ // / \param maybe_or_expr: expression to add to (`x || y` or `w` in the examples)
128
+ // / \param new_disjunct: new disjunct, written `z` in the examples.
129
+ static void add_to_disjunction (exprt &maybe_or_expr, const exprt &new_disjunct)
130
+ {
131
+ if (maybe_or_expr.id () != ID_or)
132
+ {
133
+ or_exprt or_expr;
134
+ or_expr.move_to_operands (maybe_or_expr);
135
+ maybe_or_expr.swap (or_expr);
136
+ }
137
+
138
+ maybe_or_expr.copy_to_operands (new_disjunct);
139
+ }
140
+
123
141
void remove_virtual_functionst::remove_virtual_function (
124
142
goto_programt &goto_program,
125
143
goto_programt::targett target,
@@ -178,7 +196,8 @@ void remove_virtual_functionst::remove_virtual_function(
178
196
179
197
// So long as `this` is already not `void*` typed, the second parameter
180
198
// is ignored:
181
- exprt c_id2=get_class_identifier_field (this_expr, symbol_typet (), ns);
199
+ exprt this_class_identifier =
200
+ get_class_identifier_field (this_expr, symbol_typet (), ns);
182
201
183
202
// If instructed, add an ASSUME(FALSE) to handle the case where we don't
184
203
// match any expected type:
@@ -191,16 +210,12 @@ void remove_virtual_functionst::remove_virtual_function(
191
210
192
211
// get initial identifier for grouping
193
212
INVARIANT (!functions.empty (), " Function dispatch table cannot be empty." );
194
- auto last_id = functions.back ().symbol_expr .get_identifier ();
195
- // record class_ids for disjunction
196
- std::set<irep_idt> class_ids;
197
213
198
214
std::map<irep_idt, goto_programt::targett> calls;
199
215
// Note backwards iteration, to get the fallback candidate first.
200
216
for (auto it=functions.crbegin (), itend=functions.crend (); it!=itend; ++it)
201
217
{
202
218
const auto &fun=*it;
203
- class_ids.insert (fun.class_id );
204
219
auto insertit=calls.insert (
205
220
{fun.symbol_expr .get_identifier (), goto_programt::targett ()});
206
221
@@ -232,49 +247,36 @@ void remove_virtual_functionst::remove_virtual_function(
232
247
t3->make_goto (t_final, true_exprt ());
233
248
}
234
249
235
- // Emit target if end of dispatch table is reached or if the next element is
236
- // dispatched to another function call. Assumes entries in the functions
237
- // variable to be sorted for the identifier of the function to be called.
238
- auto l_it = std::next (it);
239
- bool next_emit_target =
240
- (l_it == functions.crend ()) ||
241
- l_it->symbol_expr .get_identifier () != fun.symbol_expr .get_identifier ();
242
-
243
- // The root function call is done via fall-through, so nothing to emit
244
- // explicitly for this.
245
- if (next_emit_target && fun.symbol_expr == last_function_symbol)
250
+ // Fall through to the default callee if possible:
251
+ if (fallback_action ==
252
+ virtual_dispatch_fallback_actiont::CALL_LAST_FUNCTION &&
253
+ fun.symbol_expr == last_function_symbol)
246
254
{
247
- class_ids. clear ();
255
+ // Nothing to do
248
256
}
249
-
250
- // If this calls the fallback function we just fall through.
251
- // Otherwise branch to the right call:
252
- if (fallback_action!=virtual_dispatch_fallback_actiont::CALL_LAST_FUNCTION ||
253
- fun.symbol_expr !=last_function_symbol)
257
+ else
254
258
{
255
- // create a disjunction of class_ids to test
256
- if (next_emit_target && fun.symbol_expr != last_function_symbol)
259
+ const constant_exprt fun_class_identifier (fun.class_id , string_typet ());
260
+ const equal_exprt class_id_test (
261
+ fun_class_identifier, this_class_identifier);
262
+
263
+ // If the previous GOTO goes to the same callee, join it
264
+ // (e.g. turning IF x GOTO y into IF x || z GOTO y)
265
+ if (it != functions.crbegin () &&
266
+ std::prev (it)->symbol_expr == fun.symbol_expr )
257
267
{
258
- exprt::operandst or_ops;
259
- for (const auto &id : class_ids)
260
- {
261
- const constant_exprt c_id1 (id, string_typet ());
262
- const equal_exprt class_id_test (c_id1, c_id2);
263
- or_ops.push_back (class_id_test);
264
- }
265
-
266
- goto_programt::targett t4 = new_code_gotos.add_instruction ();
267
- t4->source_location = vcall_source_loc;
268
- t4->make_goto (insertit.first ->second , disjunction (or_ops));
269
-
270
- last_id = fun.symbol_expr .get_identifier ();
271
- class_ids.clear ();
268
+ INVARIANT (
269
+ !new_code_gotos.empty (),
270
+ " a dispatch table entry has been processed already, "
271
+ " which should have created a GOTO" );
272
+ add_to_disjunction (
273
+ new_code_gotos.instructions .back ().guard , class_id_test);
272
274
}
273
- // record class_id
274
- else if (next_emit_target)
275
+ else
275
276
{
276
- last_id = fun.symbol_expr .get_identifier ();
277
- class_ids.clear ();
277
+ goto_programt::targett new_goto = new_code_gotos.add_instruction ();
278
+ new_goto->source_location = vcall_source_loc;
279
+ new_goto->make_goto (insertit.first ->second , class_id_test);
278
280
}
279
281
}
280
282
}
@@ -555,20 +557,35 @@ void remove_virtual_functions(goto_model_functiont &function)
555
557
}
556
558
557
559
void remove_virtual_function (
558
- goto_modelt &goto_model ,
560
+ symbol_tablet &symbol_table ,
559
561
goto_programt &goto_program,
560
562
goto_programt::targett instruction,
561
563
const dispatch_table_entriest &dispatch_table,
562
564
virtual_dispatch_fallback_actiont fallback_action)
563
565
{
564
566
class_hierarchyt class_hierarchy;
565
- class_hierarchy (goto_model. symbol_table );
566
- remove_virtual_functionst rvf (goto_model. symbol_table , class_hierarchy);
567
+ class_hierarchy (symbol_table);
568
+ remove_virtual_functionst rvf (symbol_table, class_hierarchy);
567
569
568
570
rvf.remove_virtual_function (
569
571
goto_program, instruction, dispatch_table, fallback_action);
570
572
}
571
573
574
+ void remove_virtual_function (
575
+ goto_modelt &goto_model,
576
+ goto_programt &goto_program,
577
+ goto_programt::targett instruction,
578
+ const dispatch_table_entriest &dispatch_table,
579
+ virtual_dispatch_fallback_actiont fallback_action)
580
+ {
581
+ remove_virtual_function (
582
+ goto_model.symbol_table ,
583
+ goto_program,
584
+ instruction,
585
+ dispatch_table,
586
+ fallback_action);
587
+ }
588
+
572
589
void collect_virtual_function_callees (
573
590
const exprt &function,
574
591
const symbol_table_baset &symbol_table,
0 commit comments