@@ -138,9 +138,7 @@ void goto_convertt::finish_gotos(goto_programt &dest, const irep_idt &mode)
138138 throw 0 ;
139139 }
140140
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 );
144142
145143 // If the goto recorded a destructor stack, execute as much as is
146144 // appropriate for however many automatic variables leave scope.
@@ -234,45 +232,34 @@ void goto_convertt::finish_computed_gotos(goto_programt &goto_program)
234232 targets.computed_gotos .clear ();
235233}
236234
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;"
239236// / \par parameters: Destination goto program
240- void goto_convertt::finish_guarded_gotos (goto_programt &dest)
237+ void goto_convertt::optimize_guarded_gotos (goto_programt &dest)
241238{
242- for (auto &gg : guarded_gotos )
239+ for (auto it = dest. instructions . begin (); it != dest. instructions . end (); it++ )
243240 {
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- }
241+ if (!it->is_goto ())
242+ continue ;
253243
254- // If so, can't simplify.
255- if (destructor_present)
244+ auto it_goto_y = std::next (it);
245+
246+ if (
247+ it_goto_y == dest.instructions .end () || !it_goto_y->is_goto () ||
248+ !it_goto_y->guard .is_true ())
256249 continue ;
257250
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- }
251+ auto it_z = std::next (it_goto_y);
270252
271- // Must clear this, as future functions may be converted
272- // using the same instance of goto_convertt, typically via
273- // goto_convert_functions.
253+ if (it_z == dest.instructions .end ())
254+ continue ;
274255
275- guarded_gotos.clear ();
256+ if (it->get_target () == it_z)
257+ {
258+ it->set_target (it_goto_y->get_target ());
259+ it->guard = boolean_negate (it->guard );
260+ it_goto_y->make_skip ();
261+ }
262+ }
276263}
277264
278265void goto_convertt::goto_convert (
@@ -288,14 +275,11 @@ void goto_convertt::goto_convert_rec(
288275 goto_programt &dest,
289276 const irep_idt &mode)
290277{
291- // Check that guarded_gotos was cleared after any previous use of this
292- // converter instance:
293- PRECONDITION (guarded_gotos.empty ());
294278 convert (code, dest, mode);
295279
296280 finish_gotos (dest, mode);
297281 finish_computed_gotos (dest);
298- finish_guarded_gotos (dest);
282+ optimize_guarded_gotos (dest);
299283 finish_catch_push_targets (dest);
300284}
301285
@@ -493,13 +477,11 @@ void goto_convertt::convert(
493477 else if (statement==ID_continue)
494478 convert_continue (to_code_continue (code), dest, mode);
495479 else if (statement==ID_goto)
496- convert_goto (code, dest);
480+ convert_goto (to_code_goto ( code) , dest);
497481 else if (statement==ID_gcc_computed_goto)
498482 convert_gcc_computed_goto (code, dest);
499483 else if (statement==ID_skip)
500484 convert_skip (code, dest);
501- else if (statement==" non-deterministic-goto" )
502- convert_non_deterministic_goto (code, dest);
503485 else if (statement==ID_ifthenelse)
504486 convert_ifthenelse (to_code_ifthenelse (code), dest, mode);
505487 else if (statement==ID_start_thread)
@@ -1456,16 +1438,12 @@ void goto_convertt::convert_continue(
14561438 t->source_location =code.source_location ();
14571439}
14581440
1459- void goto_convertt::convert_goto (
1460- const codet &code,
1461- goto_programt &dest)
1441+ void goto_convertt::convert_goto (const code_gotot &code, goto_programt &dest)
14621442{
14631443 // 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);
1444+ goto_programt::targett t = dest.add_instruction ();
1445+ t->make_incomplete_goto (code);
14671446 t->source_location =code.source_location ();
1468- t->code =code;
14691447
14701448 // remember it to do the target later
14711449 targets.gotos .push_back (std::make_pair (t, targets.destructor_stack ));
@@ -1484,13 +1462,6 @@ void goto_convertt::convert_gcc_computed_goto(
14841462 targets.computed_gotos .push_back (t);
14851463}
14861464
1487- void goto_convertt::convert_non_deterministic_goto (
1488- const codet &code,
1489- goto_programt &dest)
1490- {
1491- convert_goto (code, dest);
1492- }
1493-
14941465void goto_convertt::convert_start_thread (
14951466 const codet &code,
14961467 goto_programt &dest)
@@ -1649,24 +1620,7 @@ void goto_convertt::generate_ifthenelse(
16491620 return ;
16501621 }
16511622
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
1623+ // do guarded assertions directly
16701624 if (is_size_one (true_case) &&
16711625 true_case.instructions .back ().is_assert () &&
16721626 true_case.instructions .back ().guard .is_false () &&
@@ -1779,13 +1733,6 @@ void goto_convertt::generate_ifthenelse(
17791733 assert (!tmp_w.instructions .empty ());
17801734 x->source_location =tmp_w.instructions .back ().source_location ;
17811735
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-
17891736 dest.destructive_append (tmp_v);
17901737 dest.destructive_append (tmp_w);
17911738
0 commit comments