@@ -138,9 +138,7 @@ void goto_convertt::finish_gotos(goto_programt &dest, const irep_idt &mode)
138
138
throw 0 ;
139
139
}
140
140
141
- i.type =GOTO;
142
- i.targets .clear ();
143
- i.targets .push_back (l_it->second .first );
141
+ i.complete_goto (l_it->second .first );
144
142
145
143
// If the goto recorded a destructor stack, execute as much as is
146
144
// appropriate for however many automatic variables leave scope.
@@ -234,45 +232,42 @@ void goto_convertt::finish_computed_gotos(goto_programt &goto_program)
234
232
targets.computed_gotos .clear ();
235
233
}
236
234
237
- // / For each if(x) goto z; goto y; z: emitted, see if any destructor statements
238
- // / were inserted between goto z and z, and if not, simplify into if(!x) goto y;
235
+ // / Rewrite " if(x) goto z; goto y; z:" into "if(!x) goto y;"
236
+ // / This only works if the "goto y" is not a branch target.
239
237
// / \par parameters: Destination goto program
240
- void goto_convertt::finish_guarded_gotos (goto_programt &dest)
238
+ void goto_convertt::optimize_guarded_gotos (goto_programt &dest)
241
239
{
242
- for (auto &gg : guarded_gotos)
240
+ // collect targets
241
+ std::set<goto_programt::const_targett> targets;
242
+
243
+ for (const auto &i : dest.instructions )
244
+ for (const auto &t : i.targets )
245
+ targets.insert (t);
246
+
247
+ for (auto it = dest.instructions .begin (); it != dest.instructions .end (); it++)
243
248
{
244
- // Check if any destructor code has been inserted:
245
- bool destructor_present=false ;
246
- for (auto it=gg.ifiter ;
247
- it!=gg.gotoiter && !destructor_present;
248
- ++it)
249
- {
250
- if (!(it->is_goto () || it->is_skip ()))
251
- destructor_present=true ;
252
- }
249
+ if (!it->is_goto ())
250
+ continue ;
253
251
254
- // If so, can't simplify.
255
- if (destructor_present)
252
+ auto it_goto_y = std::next (it);
253
+
254
+ if (
255
+ it_goto_y == dest.instructions .end () || !it_goto_y->is_goto () ||
256
+ !it_goto_y->guard .is_true () || targets.find (it_goto_y) != targets.end ())
256
257
continue ;
257
258
258
- // Simplify: remove whatever code was generated for the condition
259
- // and attach the original guard to the goto instruction.
260
- gg.gotoiter ->guard =gg.guard ;
261
- // inherit the source location (otherwise the guarded goto will
262
- // have the source location of the else branch)
263
- gg.gotoiter ->source_location =gg.ifiter ->source_location ;
264
- // goto_programt doesn't provide an erase operation,
265
- // perhaps for a good reason, so let's be cautious and just
266
- // flatten the unneeded instructions into skips.
267
- for (auto it=gg.ifiter , itend=gg.gotoiter ; it!=itend; ++it)
268
- it->make_skip ();
269
- }
259
+ auto it_z = std::next (it_goto_y);
270
260
271
- // Must clear this, as future functions may be converted
272
- // using the same instance of goto_convertt, typically via
273
- // goto_convert_functions.
261
+ if (it_z == dest.instructions .end ())
262
+ continue ;
274
263
275
- guarded_gotos.clear ();
264
+ if (it->get_target () == it_z)
265
+ {
266
+ it->set_target (it_goto_y->get_target ());
267
+ it->guard = boolean_negate (it->guard );
268
+ it_goto_y->make_skip ();
269
+ }
270
+ }
276
271
}
277
272
278
273
void goto_convertt::goto_convert (
@@ -288,14 +283,11 @@ void goto_convertt::goto_convert_rec(
288
283
goto_programt &dest,
289
284
const irep_idt &mode)
290
285
{
291
- // Check that guarded_gotos was cleared after any previous use of this
292
- // converter instance:
293
- PRECONDITION (guarded_gotos.empty ());
294
286
convert (code, dest, mode);
295
287
296
288
finish_gotos (dest, mode);
297
289
finish_computed_gotos (dest);
298
- finish_guarded_gotos (dest);
290
+ optimize_guarded_gotos (dest);
299
291
finish_catch_push_targets (dest);
300
292
}
301
293
@@ -493,13 +485,11 @@ void goto_convertt::convert(
493
485
else if (statement==ID_continue)
494
486
convert_continue (to_code_continue (code), dest, mode);
495
487
else if (statement==ID_goto)
496
- convert_goto (code, dest);
488
+ convert_goto (to_code_goto ( code) , dest);
497
489
else if (statement==ID_gcc_computed_goto)
498
490
convert_gcc_computed_goto (code, dest);
499
491
else if (statement==ID_skip)
500
492
convert_skip (code, dest);
501
- else if (statement==" non-deterministic-goto" )
502
- convert_non_deterministic_goto (code, dest);
503
493
else if (statement==ID_ifthenelse)
504
494
convert_ifthenelse (to_code_ifthenelse (code), dest, mode);
505
495
else if (statement==ID_start_thread)
@@ -1456,16 +1446,12 @@ void goto_convertt::convert_continue(
1456
1446
t->source_location =code.source_location ();
1457
1447
}
1458
1448
1459
- void goto_convertt::convert_goto (
1460
- const codet &code,
1461
- goto_programt &dest)
1449
+ void goto_convertt::convert_goto (const code_gotot &code, goto_programt &dest)
1462
1450
{
1463
1451
// this instruction will be completed during post-processing
1464
- // it is required to mark this as GOTO in order to enable
1465
- // simplifications in generate_ifthenelse
1466
- goto_programt::targett t = dest.add_instruction (GOTO);
1452
+ goto_programt::targett t = dest.add_instruction ();
1453
+ t->make_incomplete_goto (code);
1467
1454
t->source_location =code.source_location ();
1468
- t->code =code;
1469
1455
1470
1456
// remember it to do the target later
1471
1457
targets.gotos .push_back (std::make_pair (t, targets.destructor_stack ));
@@ -1484,13 +1470,6 @@ void goto_convertt::convert_gcc_computed_goto(
1484
1470
targets.computed_gotos .push_back (t);
1485
1471
}
1486
1472
1487
- void goto_convertt::convert_non_deterministic_goto (
1488
- const codet &code,
1489
- goto_programt &dest)
1490
- {
1491
- convert_goto (code, dest);
1492
- }
1493
-
1494
1473
void goto_convertt::convert_start_thread (
1495
1474
const codet &code,
1496
1475
goto_programt &dest)
@@ -1649,24 +1628,7 @@ void goto_convertt::generate_ifthenelse(
1649
1628
return ;
1650
1629
}
1651
1630
1652
- bool is_guarded_goto=false ;
1653
-
1654
- // do guarded gotos directly
1655
- if (is_empty (false_case) &&
1656
- is_size_one (true_case) &&
1657
- true_case.instructions .back ().is_goto () &&
1658
- true_case.instructions .back ().guard .is_true () &&
1659
- true_case.instructions .back ().labels .empty ())
1660
- {
1661
- // The above conjunction deliberately excludes the instance
1662
- // if(some) { label: goto somewhere; }
1663
- // Don't perform the transformation here, as code might get inserted into
1664
- // the true case to perform destructors.
1665
- // This will be attempted in finish_guarded_gotos.
1666
- is_guarded_goto=true ;
1667
- }
1668
-
1669
- // similarly, do guarded assertions directly
1631
+ // do guarded assertions directly
1670
1632
if (is_size_one (true_case) &&
1671
1633
true_case.instructions .back ().is_assert () &&
1672
1634
true_case.instructions .back ().guard .is_false () &&
@@ -1779,13 +1741,6 @@ void goto_convertt::generate_ifthenelse(
1779
1741
assert (!tmp_w.instructions .empty ());
1780
1742
x->source_location =tmp_w.instructions .back ().source_location ;
1781
1743
1782
- // See if we can simplify this guarded goto later.
1783
- // Note this depends on the fact that `instructions` is a std::list
1784
- // and so goto-program-destructive-append preserves iterator validity.
1785
- if (is_guarded_goto)
1786
- guarded_gotos.push_back (
1787
- {tmp_v.instructions .begin (), tmp_w.instructions .begin (), guard});
1788
-
1789
1744
dest.destructive_append (tmp_v);
1790
1745
dest.destructive_append (tmp_w);
1791
1746
0 commit comments