@@ -32,6 +32,7 @@ dfcc_instrument_loopt::dfcc_instrument_loopt(
32
32
dfcc_spec_functionst &spec_functions,
33
33
dfcc_contract_clauses_codegent &contract_clauses_codegen)
34
34
: goto_model(goto_model),
35
+ message_handler(message_handler),
35
36
log(message_handler),
36
37
utils(utils),
37
38
library(library),
@@ -88,7 +89,7 @@ void dfcc_instrument_loopt::operator()(
88
89
.symbol_expr ();
89
90
90
91
// Temporary variables for storing the multidimensional decreases clause
91
- // at the start of and end of a loop body.
92
+ // at the start of and end of a loop body
92
93
exprt::operandst decreases_clauses = loop.decreases ;
93
94
std::vector<symbol_exprt> old_decreases_vars, new_decreases_vars;
94
95
for (const auto &clause : decreases_clauses)
@@ -105,10 +106,10 @@ void dfcc_instrument_loopt::operator()(
105
106
new_decreases_vars.push_back (new_decreases_var);
106
107
}
107
108
108
- // Convert the assigns clause to the required type.
109
+ // convert the assigns clause to the required type
109
110
exprt::operandst assigns (loop.assigns .begin (), loop.assigns .end ());
110
111
111
- // Add local statics to the assigns clause.
112
+ // add local statics to the assigns clause
112
113
for (auto &local_static : local_statics)
113
114
{
114
115
assigns.push_back (local_static);
@@ -128,24 +129,26 @@ void dfcc_instrument_loopt::operator()(
128
129
contract_clauses_codegen.gen_spec_assigns_instructions (
129
130
language_mode, assigns, assigns_instrs);
130
131
132
+ const symbol_exprt &addr_of_loop_write_set = loop.addr_of_write_set_var ;
131
133
spec_functions.generate_havoc_instructions (
132
134
function_id,
133
135
language_mode,
134
136
symbol_table.get_writeable_ref (function_id).module ,
135
137
assigns_instrs,
136
- loop. addr_of_write_set_var ,
138
+ addr_of_loop_write_set ,
137
139
havoc_instrs,
138
140
nof_targets);
139
141
spec_functions.to_spec_assigns_instructions (
140
- loop. addr_of_write_set_var , language_mode, assigns_instrs, nof_targets);
142
+ addr_of_loop_write_set , language_mode, assigns_instrs, nof_targets);
141
143
write_set_populate_instrs.copy_from (assigns_instrs);
142
144
143
- // Replace bound variables by fresh instances in quantified formulas.
145
+ // replace bound variables by fresh instances in quantified formulas
144
146
exprt invariant = loop.invariant ;
145
147
if (has_subexpr (invariant, ID_exists) || has_subexpr (invariant, ID_forall))
146
148
add_quantified_variable (symbol_table, invariant, language_mode);
147
149
148
150
// ---------- Add instrumented instructions ----------
151
+ const symbol_exprt &loop_write_set = loop.write_set_var ;
149
152
goto_programt::targett loop_latch =
150
153
loop.find_latch (goto_function.body ).value ();
151
154
@@ -158,8 +161,8 @@ void dfcc_instrument_loopt::operator()(
158
161
write_set_populate_instrs,
159
162
invariant,
160
163
assigns,
161
- loop. write_set_var ,
162
- loop. addr_of_write_set_var ,
164
+ loop_write_set ,
165
+ addr_of_loop_write_set ,
163
166
entered_loop,
164
167
initial_invariant,
165
168
in_base_case,
@@ -176,7 +179,7 @@ void dfcc_instrument_loopt::operator()(
176
179
havoc_instrs,
177
180
invariant,
178
181
decreases_clauses,
179
- loop. addr_of_write_set_var ,
182
+ addr_of_loop_write_set ,
180
183
outer_write_set,
181
184
initial_invariant,
182
185
in_base_case,
@@ -204,8 +207,9 @@ void dfcc_instrument_loopt::operator()(
204
207
cbmc_loop_id,
205
208
goto_function,
206
209
head,
207
- loop.write_set_var ,
208
- loop.addr_of_write_set_var ,
210
+ decreases_clauses,
211
+ loop_write_set,
212
+ addr_of_loop_write_set,
209
213
history_var_map,
210
214
entered_loop,
211
215
initial_invariant,
@@ -234,6 +238,7 @@ std::map<exprt, exprt> dfcc_instrument_loopt::add_prehead_instructions(
234
238
{
235
239
auto loop_head_location (loop_head->source_location ());
236
240
dfcc_remove_loop_tags (loop_head_location);
241
+ goto_convertt converter (symbol_table, message_handler);
237
242
238
243
// ```
239
244
// ... preamble ...
@@ -278,7 +283,6 @@ std::map<exprt, exprt> dfcc_instrument_loopt::add_prehead_instructions(
278
283
279
284
// initial_invariant = <loop_invariant>;
280
285
{
281
- goto_convertt converter (symbol_table, log .get_message_handler ());
282
286
// Create a snapshot of the invariant so that we can check the base case,
283
287
// if the loop is not vacuous and must be abstracted with contracts.
284
288
pre_loop_head_instrs.add (
@@ -304,7 +308,7 @@ std::map<exprt, exprt> dfcc_instrument_loopt::add_prehead_instructions(
304
308
}
305
309
306
310
{
307
- // Create and populate the write set.
311
+ // create and populate the write set
308
312
// DECL loop_write_set
309
313
// DECL addr_of_loop_write_set
310
314
// ASSIGN write_set_ptr := address_of(write_set)
@@ -367,6 +371,7 @@ dfcc_instrument_loopt::add_step_instructions(
367
371
{
368
372
auto loop_head_location (loop_head->source_location ());
369
373
dfcc_remove_loop_tags (loop_head_location);
374
+ goto_convertt converter (symbol_table, message_handler);
370
375
371
376
// ```
372
377
// STEP: // Loop step block: havoc the loop state
@@ -393,20 +398,21 @@ dfcc_instrument_loopt::add_step_instructions(
393
398
394
399
{
395
400
// If we jump here, then the loop runs at least once,
396
- // so add the base case assertion: `assert(initial_invariant)`.
401
+ // so add the base case assertion: `assert(initial_invariant)`
397
402
source_locationt check_location (loop_head_location);
398
403
check_location.set_property_class (" loop_invariant_base" );
399
404
check_location.set_comment (
400
405
" Check invariant before entry for loop " +
401
406
id2string (check_location.get_function ()) + " ." +
402
407
std::to_string (cbmc_loop_id));
403
- step_instrs.add (
404
- goto_programt::make_assertion (initial_invariant, check_location));
408
+ code_assertt assertion{initial_invariant};
409
+ assertion.add_source_location () = check_location;
410
+ converter.goto_convert (assertion, step_instrs, language_mode);
405
411
}
406
412
407
413
{
408
- // Check assigns clause inclusion with parent write set
409
- // skip the check when if w_parent is NULL.
414
+ // check assigns clause inclusion with parent write set
415
+ // skip the check when if w_parent is NULL
410
416
auto goto_instruction = step_instrs.add (goto_programt::make_incomplete_goto (
411
417
equal_exprt (
412
418
outer_write_set,
@@ -462,24 +468,26 @@ dfcc_instrument_loopt::add_step_instructions(
462
468
goto_programt::make_assignment (in_loop_havoc_block, false_exprt{}));
463
469
}
464
470
465
- goto_convertt converter (symbol_table, log .get_message_handler ());
466
471
{
467
- // Assume the loop invariant after havocing the state.
472
+ // Assume the loop invariant after havocing the state
468
473
code_assumet assumption{invariant};
469
474
assumption.add_source_location () = loop_head_location;
470
475
converter.goto_convert (assumption, step_instrs, language_mode);
471
476
}
472
477
473
478
{
474
479
// Generate assignments to store the multidimensional decreases clause's
475
- // value just before the loop_head.
476
- for ( size_t i = 0 ; i < old_decreases_vars. size (); i++ )
480
+ // value just before the loop_head
481
+ if (!decreases_clauses. empty () )
477
482
{
478
- code_assignt old_decreases_assignment{
479
- old_decreases_vars[i], decreases_clauses[i]};
480
- old_decreases_assignment.add_source_location () = loop_head_location;
481
- converter.goto_convert (
482
- old_decreases_assignment, step_instrs, language_mode);
483
+ for (size_t i = 0 ; i < old_decreases_vars.size (); i++)
484
+ {
485
+ code_assignt old_decreases_assignment{
486
+ old_decreases_vars[i], decreases_clauses[i]};
487
+ old_decreases_assignment.add_source_location () = loop_head_location;
488
+ converter.goto_convert (
489
+ old_decreases_assignment, step_instrs, language_mode);
490
+ }
483
491
}
484
492
}
485
493
@@ -506,6 +514,7 @@ void dfcc_instrument_loopt::add_body_instructions(
506
514
{
507
515
auto loop_head_location (loop_head->source_location ());
508
516
dfcc_remove_loop_tags (loop_head_location);
517
+ goto_convertt converter (symbol_table, message_handler);
509
518
510
519
// HEAD: // Loop body block
511
520
// ... eval guard ...
@@ -523,7 +532,7 @@ void dfcc_instrument_loopt::add_body_instructions(
523
532
goto_programt pre_loop_latch_instrs;
524
533
525
534
{
526
- // Record that we entered the loop with `entered_loop = true`.
535
+ // Record that we entered the loop with `entered_loop = true`
527
536
pre_loop_latch_instrs.add (
528
537
goto_programt::make_assignment (entered_loop, true_exprt{}));
529
538
}
@@ -535,7 +544,6 @@ void dfcc_instrument_loopt::add_body_instructions(
535
544
step_case_target, in_base_case, loop_head_location));
536
545
}
537
546
538
- goto_convertt converter (symbol_table, log .get_message_handler ());
539
547
{
540
548
// Because of the unconditional jump above the following code is only
541
549
// reachable in the step case. Generate the inductive invariant check
@@ -553,7 +561,7 @@ void dfcc_instrument_loopt::add_body_instructions(
553
561
554
562
{
555
563
// Generate assignments to store the multidimensional decreases clause's
556
- // value after one iteration of the loop.
564
+ // value after one iteration of the loop
557
565
if (!decreases_clauses.empty ())
558
566
{
559
567
for (size_t i = 0 ; i < new_decreases_vars.size (); i++)
@@ -573,12 +581,14 @@ void dfcc_instrument_loopt::add_body_instructions(
573
581
" Check variant decreases after step for loop " +
574
582
id2string (check_location.get_function ()) + " ." +
575
583
std::to_string (cbmc_loop_id));
576
- pre_loop_latch_instrs. add ( goto_programt::make_assertion (
584
+ code_assertt monotonic_decreasing_assertion{
577
585
generate_lexicographic_less_than_check (
578
- new_decreases_vars, old_decreases_vars),
579
- check_location));
586
+ new_decreases_vars, old_decreases_vars)};
587
+ monotonic_decreasing_assertion.add_source_location () = check_location;
588
+ converter.goto_convert (
589
+ monotonic_decreasing_assertion, pre_loop_latch_instrs, language_mode);
580
590
581
- // Discard the temporary variables that store decreases clause's value.
591
+ // Discard the temporary variables that store decreases clause's value
582
592
for (size_t i = 0 ; i < old_decreases_vars.size (); i++)
583
593
{
584
594
pre_loop_latch_instrs.add (
@@ -593,7 +603,7 @@ void dfcc_instrument_loopt::add_body_instructions(
593
603
goto_function.body , loop_latch, pre_loop_latch_instrs);
594
604
595
605
{
596
- // Change the back edge into assume(false) or assume(!guard).
606
+ // change the back edge into assume(false) or assume(!guard)
597
607
loop_latch->turn_into_assume ();
598
608
loop_latch->condition_nonconst () = boolean_negate (loop_latch->condition ());
599
609
}
@@ -604,6 +614,7 @@ void dfcc_instrument_loopt::add_exit_instructions(
604
614
const std::size_t cbmc_loop_id,
605
615
goto_functionst::goto_functiont &goto_function,
606
616
goto_programt::targett loop_head,
617
+ const exprt::operandst &decreases_clauses,
607
618
const symbol_exprt &loop_write_set,
608
619
const symbol_exprt &addr_of_loop_write_set,
609
620
const std::map<exprt, exprt> &history_var_map,
@@ -613,7 +624,7 @@ void dfcc_instrument_loopt::add_exit_instructions(
613
624
const std::vector<symbol_exprt> &old_decreases_vars,
614
625
const std::vector<symbol_exprt> &new_decreases_vars)
615
626
{
616
- // Collect all exit targets of the loop.
627
+ // collect all exit targets of the loop
617
628
std::set<goto_programt::targett> exit_targets;
618
629
619
630
for (goto_programt::instructiont::targett target =
@@ -632,7 +643,7 @@ void dfcc_instrument_loopt::add_exit_instructions(
632
643
exit_targets.insert (exit_target);
633
644
}
634
645
635
- // For each exit target of the loop, insert a code block:
646
+ // For each exit target of the loop, insert a code block :
636
647
// ```
637
648
// EXIT:
638
649
// // check that step case was checked if loop can run once
@@ -648,8 +659,8 @@ void dfcc_instrument_loopt::add_exit_instructions(
648
659
{
649
660
goto_programt loop_exit_program;
650
661
651
- // Use the head location for this check as well so that all checks related
652
- // to a given loop are presented as coming from the loop head.
662
+ // use the head location for this check as well so that all checks related
663
+ // to a given loop are presented as coming from the loop head
653
664
source_locationt check_location = loop_head->source_location ();
654
665
check_location.set_property_class (" loop_step_unwinding" );
655
666
check_location.set_comment (
@@ -660,7 +671,7 @@ void dfcc_instrument_loopt::add_exit_instructions(
660
671
or_exprt{not_exprt{entered_loop}, not_exprt{in_base_case}},
661
672
check_location));
662
673
663
- // Mark instrumentation variables as going out of scope .
674
+ // Kill instrumentation variables.
664
675
source_locationt exit_location = exit_target->source_location ();
665
676
loop_exit_program.add (
666
677
goto_programt::make_dead (in_base_case, exit_location));
@@ -669,31 +680,34 @@ void dfcc_instrument_loopt::add_exit_instructions(
669
680
loop_exit_program.add (
670
681
goto_programt::make_dead (initial_invariant, exit_location));
671
682
672
- // Release the write set resources.
683
+ // Release the write set resources
673
684
loop_exit_program.add (goto_programt::make_function_call (
674
685
library.write_set_release_call (addr_of_loop_write_set, exit_location),
675
686
exit_location));
676
687
677
- // Mark write set as going out of scope.
688
+ // Kill write set
678
689
loop_exit_program.add (
679
690
goto_programt::make_dead (to_symbol_expr (loop_write_set), exit_location));
680
691
loop_exit_program.add (goto_programt::make_dead (
681
692
to_symbol_expr (addr_of_loop_write_set), exit_location));
682
693
683
- // Mark history variables as going out of scope.
694
+ // Kill history variables
684
695
for (const auto &v : history_var_map)
685
696
{
686
697
loop_exit_program.add (
687
698
goto_programt::make_dead (to_symbol_expr (v.second ), exit_location));
688
699
}
689
700
690
- // Mark decreases clause snapshots as gong out of scope.
691
- for (size_t i = 0 ; i < old_decreases_vars.size (); i++)
701
+ if (!decreases_clauses.empty ())
692
702
{
693
- loop_exit_program.add (
694
- goto_programt::make_dead (old_decreases_vars[i], exit_location));
695
- loop_exit_program.add (
696
- goto_programt::make_dead (new_decreases_vars[i], exit_location));
703
+ // Kill decreases clause snapshots
704
+ for (size_t i = 0 ; i < old_decreases_vars.size (); i++)
705
+ {
706
+ loop_exit_program.add (
707
+ goto_programt::make_dead (old_decreases_vars[i], exit_location));
708
+ loop_exit_program.add (
709
+ goto_programt::make_dead (new_decreases_vars[i], exit_location));
710
+ }
697
711
}
698
712
699
713
// Insert the exit block, preserving the loop end target.
0 commit comments