Skip to content

Commit 21e44f7

Browse files
Remi Delmasqinheping
Remi Delmas
authored andcommitted
CONTRACTS: class that applies loop contract transformations
1 parent c94189f commit 21e44f7

File tree

1 file changed

+53
-41
lines changed

1 file changed

+53
-41
lines changed

src/goto-instrument/contracts/dynamic-frames/dfcc_instrument_loop.cpp

Lines changed: 53 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ dfcc_instrument_loopt::dfcc_instrument_loopt(
3232
dfcc_spec_functionst &spec_functions,
3333
dfcc_contract_clauses_codegent &contract_clauses_codegen)
3434
: goto_model(goto_model),
35+
message_handler(message_handler),
3536
log(message_handler),
3637
utils(utils),
3738
library(library),
@@ -94,7 +95,7 @@ void dfcc_instrument_loopt::operator()(
9495
.symbol_expr();
9596

9697
// Temporary variables for storing the multidimensional decreases clause
97-
// at the start of and end of a loop body.
98+
// at the start of and end of a loop body
9899
exprt::operandst decreases_clauses = loop.decreases;
99100
std::vector<symbol_exprt> old_decreases_vars, new_decreases_vars;
100101
for(const auto &clause : decreases_clauses)
@@ -121,10 +122,10 @@ void dfcc_instrument_loopt::operator()(
121122
new_decreases_vars.push_back(new_decreases_var);
122123
}
123124

124-
// Convert the assigns clause to the required type.
125+
// convert the assigns clause to the required type
125126
exprt::operandst assigns(loop.assigns.begin(), loop.assigns.end());
126127

127-
// Add local statics to the assigns clause.
128+
// add local statics to the assigns clause
128129
for(auto &local_static : local_statics)
129130
{
130131
assigns.push_back(local_static);
@@ -146,24 +147,26 @@ void dfcc_instrument_loopt::operator()(
146147
contract_clauses_codegen.gen_spec_assigns_instructions(
147148
language_mode, assigns, assigns_instrs);
148149

150+
const symbol_exprt &addr_of_loop_write_set = loop.addr_of_write_set_var;
149151
spec_functions.generate_havoc_instructions(
150152
function_id,
151153
language_mode,
152154
symbol_table.get_writeable_ref(function_id).module,
153155
assigns_instrs,
154-
loop.addr_of_write_set_var,
156+
addr_of_loop_write_set,
155157
havoc_instrs,
156158
nof_targets);
157159
spec_functions.to_spec_assigns_instructions(
158-
loop.addr_of_write_set_var, language_mode, assigns_instrs, nof_targets);
160+
addr_of_loop_write_set, language_mode, assigns_instrs, nof_targets);
159161
write_set_populate_instrs.copy_from(assigns_instrs);
160162

161-
// Replace bound variables by fresh instances in quantified formulas.
163+
// replace bound variables by fresh instances in quantified formulas
162164
exprt invariant = loop.invariant;
163165
if(has_subexpr(invariant, ID_exists) || has_subexpr(invariant, ID_forall))
164166
add_quantified_variable(symbol_table, invariant, language_mode);
165167

166168
// ---------- Add instrumented instructions ----------
169+
const symbol_exprt &loop_write_set = loop.write_set_var;
167170
goto_programt::targett loop_latch =
168171
loop.find_latch(goto_function.body).value();
169172

@@ -176,8 +179,8 @@ void dfcc_instrument_loopt::operator()(
176179
write_set_populate_instrs,
177180
invariant,
178181
assigns,
179-
loop.write_set_var,
180-
loop.addr_of_write_set_var,
182+
loop_write_set,
183+
addr_of_loop_write_set,
181184
entered_loop,
182185
initial_invariant,
183186
in_base_case,
@@ -194,7 +197,7 @@ void dfcc_instrument_loopt::operator()(
194197
havoc_instrs,
195198
invariant,
196199
decreases_clauses,
197-
loop.addr_of_write_set_var,
200+
addr_of_loop_write_set,
198201
outer_write_set,
199202
initial_invariant,
200203
in_base_case,
@@ -222,8 +225,9 @@ void dfcc_instrument_loopt::operator()(
222225
cbmc_loop_id,
223226
goto_function,
224227
head,
225-
loop.write_set_var,
226-
loop.addr_of_write_set_var,
228+
decreases_clauses,
229+
loop_write_set,
230+
addr_of_loop_write_set,
227231
history_var_map,
228232
entered_loop,
229233
initial_invariant,
@@ -252,6 +256,7 @@ std::map<exprt, exprt> dfcc_instrument_loopt::add_prehead_instructions(
252256
{
253257
auto loop_head_location(loop_head->source_location());
254258
dfcc_remove_loop_tags(loop_head_location);
259+
goto_convertt converter(symbol_table, message_handler);
255260

256261
// ```
257262
// ... preamble ...
@@ -322,7 +327,7 @@ std::map<exprt, exprt> dfcc_instrument_loopt::add_prehead_instructions(
322327
}
323328

324329
{
325-
// Create and populate the write set.
330+
// create and populate the write set
326331
// DECL loop_write_set
327332
// DECL addr_of_loop_write_set
328333
// ASSIGN write_set_ptr := address_of(write_set)
@@ -378,6 +383,7 @@ dfcc_instrument_loopt::add_step_instructions(
378383
{
379384
auto loop_head_location(loop_head->source_location());
380385
dfcc_remove_loop_tags(loop_head_location);
386+
goto_convertt converter(symbol_table, message_handler);
381387

382388
// ```
383389
// STEP: // Loop step block: havoc the loop state
@@ -402,20 +408,21 @@ dfcc_instrument_loopt::add_step_instructions(
402408

403409
{
404410
// If we jump here, then the loop runs at least once,
405-
// so add the base case assertion: `assert(initial_invariant)`.
411+
// so add the base case assertion: `assert(initial_invariant)`
406412
source_locationt check_location(loop_head_location);
407413
check_location.set_property_class("loop_invariant_base");
408414
check_location.set_comment(
409415
"Check invariant before entry for loop " +
410416
id2string(check_location.get_function()) + "." +
411417
std::to_string(cbmc_loop_id));
412-
step_instrs.add(
413-
goto_programt::make_assertion(initial_invariant, check_location));
418+
code_assertt assertion{initial_invariant};
419+
assertion.add_source_location() = check_location;
420+
converter.goto_convert(assertion, step_instrs, language_mode);
414421
}
415422

416423
{
417-
// Check assigns clause inclusion with parent write set
418-
// skip the check when if w_parent is NULL.
424+
// check assigns clause inclusion with parent write set
425+
// skip the check when if w_parent is NULL
419426
auto goto_instruction = step_instrs.add(goto_programt::make_incomplete_goto(
420427
equal_exprt(
421428
outer_write_set,
@@ -472,17 +479,16 @@ dfcc_instrument_loopt::add_step_instructions(
472479
goto_programt::make_assignment(in_loop_havoc_block, false_exprt{}));
473480
}
474481

475-
goto_convertt converter(symbol_table, log.get_message_handler());
476482
{
477-
// Assume the loop invariant after havocing the state.
483+
// Assume the loop invariant after havocing the state
478484
code_assumet assumption{invariant};
479485
assumption.add_source_location() = loop_head_location;
480486
converter.goto_convert(assumption, step_instrs, language_mode);
481487
}
482488

483489
{
484490
// Generate assignments to store the multidimensional decreases clause's
485-
// value just before the loop_head.
491+
// value just before the loop_head
486492
for(size_t i = 0; i < old_decreases_vars.size(); i++)
487493
{
488494
code_frontend_assignt old_decreases_assignment{
@@ -515,6 +521,7 @@ void dfcc_instrument_loopt::add_body_instructions(
515521
{
516522
auto loop_head_location(loop_head->source_location());
517523
dfcc_remove_loop_tags(loop_head_location);
524+
goto_convertt converter(symbol_table, message_handler);
518525

519526
// HEAD: // Loop body block
520527
// ... eval guard ...
@@ -532,7 +539,7 @@ void dfcc_instrument_loopt::add_body_instructions(
532539
goto_programt pre_loop_latch_instrs;
533540

534541
{
535-
// Record that we entered the loop with `entered_loop = true`.
542+
// Record that we entered the loop with `entered_loop = true`
536543
pre_loop_latch_instrs.add(
537544
goto_programt::make_assignment(entered_loop, true_exprt{}));
538545
}
@@ -544,7 +551,6 @@ void dfcc_instrument_loopt::add_body_instructions(
544551
step_case_target, in_base_case, loop_head_location));
545552
}
546553

547-
goto_convertt converter(symbol_table, log.get_message_handler());
548554
{
549555
// Because of the unconditional jump above the following code is only
550556
// reachable in the step case. Generate the inductive invariant check
@@ -562,7 +568,7 @@ void dfcc_instrument_loopt::add_body_instructions(
562568

563569
{
564570
// Generate assignments to store the multidimensional decreases clause's
565-
// value after one iteration of the loop.
571+
// value after one iteration of the loop
566572
if(!decreases_clauses.empty())
567573
{
568574
for(size_t i = 0; i < new_decreases_vars.size(); i++)
@@ -581,12 +587,14 @@ void dfcc_instrument_loopt::add_body_instructions(
581587
"Check variant decreases after step for loop " +
582588
id2string(check_location.get_function()) + "." +
583589
std::to_string(cbmc_loop_id));
584-
pre_loop_latch_instrs.add(goto_programt::make_assertion(
590+
code_assertt monotonic_decreasing_assertion{
585591
generate_lexicographic_less_than_check(
586-
new_decreases_vars, old_decreases_vars),
587-
check_location));
592+
new_decreases_vars, old_decreases_vars)};
593+
monotonic_decreasing_assertion.add_source_location() = check_location;
594+
converter.goto_convert(
595+
monotonic_decreasing_assertion, pre_loop_latch_instrs, language_mode);
588596

589-
// Discard the temporary variables that store decreases clause's value.
597+
// Discard the temporary variables that store decreases clause's value
590598
for(size_t i = 0; i < old_decreases_vars.size(); i++)
591599
{
592600
pre_loop_latch_instrs.add(
@@ -601,7 +609,7 @@ void dfcc_instrument_loopt::add_body_instructions(
601609
goto_function.body, loop_latch, pre_loop_latch_instrs);
602610

603611
{
604-
// Change the back edge into assume(false) or assume(!guard).
612+
// change the back edge into assume(false) or assume(!guard)
605613
loop_latch->turn_into_assume();
606614
loop_latch->condition_nonconst() = boolean_negate(loop_latch->condition());
607615
}
@@ -612,6 +620,7 @@ void dfcc_instrument_loopt::add_exit_instructions(
612620
const std::size_t cbmc_loop_id,
613621
goto_functionst::goto_functiont &goto_function,
614622
goto_programt::targett loop_head,
623+
const exprt::operandst &decreases_clauses,
615624
const symbol_exprt &loop_write_set,
616625
const symbol_exprt &addr_of_loop_write_set,
617626
const std::map<exprt, exprt> &history_var_map,
@@ -621,7 +630,7 @@ void dfcc_instrument_loopt::add_exit_instructions(
621630
const std::vector<symbol_exprt> &old_decreases_vars,
622631
const std::vector<symbol_exprt> &new_decreases_vars)
623632
{
624-
// Collect all exit targets of the loop.
633+
// collect all exit targets of the loop
625634
std::set<goto_programt::targett> exit_targets;
626635

627636
for(goto_programt::instructiont::targett target =
@@ -640,7 +649,7 @@ void dfcc_instrument_loopt::add_exit_instructions(
640649
exit_targets.insert(exit_target);
641650
}
642651

643-
// For each exit target of the loop, insert a code block:
652+
// For each exit target of the loop, insert a code block :
644653
// ```
645654
// EXIT:
646655
// // check that step case was checked if loop can run once
@@ -656,8 +665,8 @@ void dfcc_instrument_loopt::add_exit_instructions(
656665
{
657666
goto_programt loop_exit_program;
658667

659-
// Use the head location for this check as well so that all checks related
660-
// to a given loop are presented as coming from the loop head.
668+
// use the head location for this check as well so that all checks related
669+
// to a given loop are presented as coming from the loop head
661670
source_locationt check_location = loop_head->source_location();
662671
check_location.set_property_class("loop_step_unwinding");
663672
check_location.set_comment(
@@ -677,31 +686,34 @@ void dfcc_instrument_loopt::add_exit_instructions(
677686
loop_exit_program.add(
678687
goto_programt::make_dead(initial_invariant, exit_location));
679688

680-
// Release the write set resources.
689+
// Release the write set resources
681690
loop_exit_program.add(goto_programt::make_function_call(
682691
library.write_set_release_call(addr_of_loop_write_set, exit_location),
683692
exit_location));
684693

685-
// Mark write set as going out of scope.
694+
// Kill write set
686695
loop_exit_program.add(
687696
goto_programt::make_dead(to_symbol_expr(loop_write_set), exit_location));
688697
loop_exit_program.add(goto_programt::make_dead(
689698
to_symbol_expr(addr_of_loop_write_set), exit_location));
690699

691-
// Mark history variables as going out of scope.
700+
// Kill history variables
692701
for(const auto &v : history_var_map)
693702
{
694703
loop_exit_program.add(
695704
goto_programt::make_dead(to_symbol_expr(v.second), exit_location));
696705
}
697706

698-
// Mark decreases clause snapshots as gong out of scope.
699-
for(size_t i = 0; i < old_decreases_vars.size(); i++)
707+
if(!decreases_clauses.empty())
700708
{
701-
loop_exit_program.add(
702-
goto_programt::make_dead(old_decreases_vars[i], exit_location));
703-
loop_exit_program.add(
704-
goto_programt::make_dead(new_decreases_vars[i], exit_location));
709+
// Kill decreases clause snapshots
710+
for(size_t i = 0; i < old_decreases_vars.size(); i++)
711+
{
712+
loop_exit_program.add(
713+
goto_programt::make_dead(old_decreases_vars[i], exit_location));
714+
loop_exit_program.add(
715+
goto_programt::make_dead(new_decreases_vars[i], exit_location));
716+
}
705717
}
706718

707719
// Insert the exit block, preserving the loop end target.

0 commit comments

Comments
 (0)