Skip to content

Commit 1b20868

Browse files
author
Daniel Kroening
committed
introduce INCOMPLETE_GOTO and turn guarded goto into a stateless pass
1 parent 360fabe commit 1b20868

File tree

9 files changed

+75
-91
lines changed

9 files changed

+75
-91
lines changed

regression/cbmc/goto5/main.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include <assert.h>
2+
3+
int main(void)
4+
{
5+
int r = 0;
6+
7+
if ( r == 0 )
8+
{
9+
goto l1;
10+
r = 1;
11+
}
12+
13+
l1:
14+
assert(r != 0); // expected to fail
15+
}

regression/cbmc/goto5/test.desc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
--
8+
^warning: ignoring

src/analyses/goto_rw.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,7 @@ void goto_rw(goto_programt::const_targett target,
719719
switch(target->type)
720720
{
721721
case NO_INSTRUCTION_TYPE:
722+
case INCOMPLETE_GOTO:
722723
UNREACHABLE;
723724
break;
724725

src/goto-instrument/goto_program2code.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ goto_programt::const_targett goto_program2codet::convert_instruction(
245245
return convert_catch(target, upper_bound, dest);
246246

247247
case NO_INSTRUCTION_TYPE:
248+
case INCOMPLETE_GOTO:
248249
UNREACHABLE;
249250
}
250251

src/goto-programs/cfg.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ void cfg_baset<T, P, I>::compute_edges(
418418
break;
419419

420420
case NO_INSTRUCTION_TYPE:
421+
case INCOMPLETE_GOTO:
421422
UNREACHABLE;
422423
break;
423424
}

src/goto-programs/goto_convert.cpp

Lines changed: 29 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -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,36 @@ 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();
240+
it!=dest.instructions.end();
241+
it++)
243242
{
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-
}
243+
if(!it->is_goto())
244+
continue;
253245

254-
// If so, can't simplify.
255-
if(destructor_present)
246+
auto it_goto_y=std::next(it);
247+
248+
if(it_goto_y==dest.instructions.end() ||
249+
!it_goto_y->is_goto() ||
250+
!it_goto_y->guard.is_true())
256251
continue;
257252

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-
}
253+
auto it_z=std::next(it_goto_y);
270254

271-
// Must clear this, as future functions may be converted
272-
// using the same instance of goto_convertt, typically via
273-
// goto_convert_functions.
255+
if(it_z==dest.instructions.end())
256+
continue;
274257

275-
guarded_gotos.clear();
258+
if(it->get_target()==it_z)
259+
{
260+
it->set_target(it_goto_y->get_target());
261+
it->guard=boolean_negate(it->guard);
262+
it_goto_y->make_skip();
263+
}
264+
}
276265
}
277266

278267
void goto_convertt::goto_convert(
@@ -288,14 +277,11 @@ void goto_convertt::goto_convert_rec(
288277
goto_programt &dest,
289278
const irep_idt &mode)
290279
{
291-
// Check that guarded_gotos was cleared after any previous use of this
292-
// converter instance:
293-
PRECONDITION(guarded_gotos.empty());
294280
convert(code, dest, mode);
295281

296282
finish_gotos(dest, mode);
297283
finish_computed_gotos(dest);
298-
finish_guarded_gotos(dest);
284+
optimize_guarded_gotos(dest);
299285
finish_catch_push_targets(dest);
300286
}
301287

@@ -493,13 +479,11 @@ void goto_convertt::convert(
493479
else if(statement==ID_continue)
494480
convert_continue(to_code_continue(code), dest, mode);
495481
else if(statement==ID_goto)
496-
convert_goto(code, dest);
482+
convert_goto(to_code_goto(code), dest);
497483
else if(statement==ID_gcc_computed_goto)
498484
convert_gcc_computed_goto(code, dest);
499485
else if(statement==ID_skip)
500486
convert_skip(code, dest);
501-
else if(statement=="non-deterministic-goto")
502-
convert_non_deterministic_goto(code, dest);
503487
else if(statement==ID_ifthenelse)
504488
convert_ifthenelse(to_code_ifthenelse(code), dest, mode);
505489
else if(statement==ID_start_thread)
@@ -1457,15 +1441,13 @@ void goto_convertt::convert_continue(
14571441
}
14581442

14591443
void goto_convertt::convert_goto(
1460-
const codet &code,
1444+
const code_gotot &code,
14611445
goto_programt &dest)
14621446
{
14631447
// 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);
1448+
goto_programt::targett t = dest.add_instruction();
1449+
t->make_incomplete_goto(code);
14671450
t->source_location=code.source_location();
1468-
t->code=code;
14691451

14701452
// remember it to do the target later
14711453
targets.gotos.push_back(std::make_pair(t, targets.destructor_stack));
@@ -1484,13 +1466,6 @@ void goto_convertt::convert_gcc_computed_goto(
14841466
targets.computed_gotos.push_back(t);
14851467
}
14861468

1487-
void goto_convertt::convert_non_deterministic_goto(
1488-
const codet &code,
1489-
goto_programt &dest)
1490-
{
1491-
convert_goto(code, dest);
1492-
}
1493-
14941469
void goto_convertt::convert_start_thread(
14951470
const codet &code,
14961471
goto_programt &dest)
@@ -1649,24 +1624,7 @@ void goto_convertt::generate_ifthenelse(
16491624
return;
16501625
}
16511626

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
1627+
// do guarded assertions directly
16701628
if(is_size_one(true_case) &&
16711629
true_case.instructions.back().is_assert() &&
16721630
true_case.instructions.back().guard.is_false() &&
@@ -1779,13 +1737,6 @@ void goto_convertt::generate_ifthenelse(
17791737
assert(!tmp_w.instructions.empty());
17801738
x->source_location=tmp_w.instructions.back().source_location;
17811739

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-
17891740
dest.destructive_append(tmp_v);
17901741
dest.destructive_append(tmp_w);
17911742

src/goto-programs/goto_convert_class.h

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -268,10 +268,9 @@ class goto_convertt:public messaget
268268
const irep_idt &mode);
269269
void
270270
convert_init(const codet &code, goto_programt &dest, const irep_idt &mode);
271-
void convert_goto(const codet &code, goto_programt &dest);
271+
void convert_goto(const code_gotot &code, goto_programt &dest);
272272
void convert_gcc_computed_goto(const codet &code, goto_programt &dest);
273273
void convert_skip(const codet &code, goto_programt &dest);
274-
void convert_non_deterministic_goto(const codet &code, goto_programt &dest);
275274
void convert_label(
276275
const code_labelt &code,
277276
goto_programt &dest,
@@ -355,7 +354,7 @@ class goto_convertt:public messaget
355354

356355
void finish_gotos(goto_programt &dest, const irep_idt &mode);
357356
void finish_computed_gotos(goto_programt &dest);
358-
void finish_guarded_gotos(goto_programt &dest);
357+
void optimize_guarded_gotos(goto_programt &dest);
359358

360359
typedef std::map<irep_idt,
361360
std::pair<goto_programt::targett, destructor_stackt>>
@@ -545,15 +544,6 @@ class goto_convertt:public messaget
545544
std::size_t leave_stack_size;
546545
};
547546

548-
struct guarded_gotot
549-
{
550-
goto_programt::targett ifiter;
551-
goto_programt::targett gotoiter;
552-
exprt guard;
553-
};
554-
typedef std::list<guarded_gotot> guarded_gotost;
555-
guarded_gotost guarded_gotos;
556-
557547
exprt case_guard(
558548
const exprt &value,
559549
const caset &case_op);

src/goto-programs/goto_program.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ enum goto_program_instruction_typet
4646
DEAD=15, // marks the end-of-live of a local variable
4747
FUNCTION_CALL=16, // call a function
4848
THROW=17, // throw an exception
49-
CATCH=18 // push, pop or enter an exception handler
49+
CATCH=18, // push, pop or enter an exception handler
50+
INCOMPLETE_GOTO=19 // goto where target is yet to be determined
5051
};
5152

5253
std::ostream &operator<<(std::ostream &, goto_program_instruction_typet);
@@ -253,6 +254,12 @@ class goto_programt
253254
void make_atomic_end() { clear(ATOMIC_END); }
254255
void make_end_function() { clear(END_FUNCTION); }
255256

257+
void make_incomplete_goto(const code_gotot &_code)
258+
{
259+
clear(INCOMPLETE_GOTO);
260+
code=_code;
261+
}
262+
256263
void make_goto(targett _target)
257264
{
258265
clear(GOTO);
@@ -265,6 +272,13 @@ class goto_programt
265272
guard=g;
266273
}
267274

275+
void complete_goto(targett _target)
276+
{
277+
PRECONDITION(type==INCOMPLETE_GOTO);
278+
targets.push_back(_target);
279+
type=GOTO;
280+
}
281+
268282
void make_assignment(const codet &_code)
269283
{
270284
clear(ASSIGN);
@@ -301,6 +315,7 @@ class goto_programt
301315
bool is_start_thread () const { return type==START_THREAD; }
302316
bool is_end_thread () const { return type==END_THREAD; }
303317
bool is_end_function () const { return type==END_FUNCTION; }
318+
bool is_incomplete_goto() const { return type==INCOMPLETE_GOTO; }
304319

305320
instructiont():
306321
instructiont(NO_INSTRUCTION_TYPE) // NOLINT(runtime/explicit)

src/goto-programs/string_abstraction.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,8 @@ goto_programt::targett string_abstractiont::abstract(
490490
case OTHER:
491491
case LOCATION:
492492
break;
493+
494+
case INCOMPLETE_GOTO:
493495
case NO_INSTRUCTION_TYPE:
494496
UNREACHABLE;
495497
break;

0 commit comments

Comments
 (0)