@@ -59,6 +59,7 @@ void code_contractst::check_apply_loop_contracts(
59
59
const irep_idt &mode)
60
60
{
61
61
const auto loop_head_location = loop_head->source_location ();
62
+ const auto loop_number = loop_end->loop_number ;
62
63
63
64
// Vector representing a (possibly multidimensional) decreases clause
64
65
const auto &decreases_clause_exprs = decreases_clause.operands ();
@@ -95,10 +96,12 @@ void code_contractst::check_apply_loop_contracts(
95
96
// | STEP:
96
97
// --. | assert (initial_invariant_val);
97
98
// loop assigns check | | in_base_case = false;
98
- // - not applicable >======= havoc (assigns_set);
99
- // func assigns check | | assume (invariant_expr);
100
- // + deferred | `- old_variant_val = decreases_clause_expr;
101
- // --' * HEAD:
99
+ // - not applicable >======= in_loop_havoc_block = true;
100
+ // func assigns check | | havoc (assigns_set);
101
+ // + deferred | | in_loop_havoc_block = false;
102
+ // --' | assume (invariant_expr);
103
+ // `- old_variant_val = decreases_clause_expr;
104
+ // * HEAD:
102
105
// loop assigns check ,- ... eval guard ...
103
106
// + assertions added | if (!guard)
104
107
// func assigns check | goto EXIT;
@@ -142,7 +145,11 @@ void code_contractst::check_apply_loop_contracts(
142
145
// i.e., the loop guard was satisfied.
143
146
const auto entered_loop =
144
147
new_tmp_symbol (
145
- bool_typet (), loop_head_location, mode, symbol_table, " __entered_loop" )
148
+ bool_typet (),
149
+ loop_head_location,
150
+ mode,
151
+ symbol_table,
152
+ std::string (ENTERED_LOOP) + " __" + std::to_string (loop_number))
146
153
.symbol_expr ();
147
154
pre_loop_head_instrs.add (
148
155
goto_programt::make_decl (entered_loop, loop_head_location));
@@ -153,7 +160,7 @@ void code_contractst::check_apply_loop_contracts(
153
160
// if the loop is not vacuous and must be abstracted with contracts.
154
161
const auto initial_invariant_val =
155
162
new_tmp_symbol (
156
- bool_typet (), loop_head_location, mode, symbol_table, " __init_invariant " )
163
+ bool_typet (), loop_head_location, mode, symbol_table, INIT_INVARIANT )
157
164
.symbol_expr ();
158
165
pre_loop_head_instrs.add (
159
166
goto_programt::make_decl (initial_invariant_val, loop_head_location));
@@ -292,8 +299,25 @@ void code_contractst::check_apply_loop_contracts(
292
299
loop_head, add_pragma_disable_assigns_check (pre_loop_head_instrs));
293
300
294
301
// Generate havocing code for assignment targets.
302
+ // ASSIGN in_loop_havoc_block = true;
303
+ // havoc (assigns_set);
304
+ // ASSIGN in_loop_havoc_block = false;
305
+ const auto in_loop_havoc_block =
306
+ new_tmp_symbol (
307
+ bool_typet (),
308
+ loop_head_location,
309
+ mode,
310
+ symbol_table,
311
+ std::string (IN_LOOP_HAVOC_BLOCK) + +" __" + std::to_string (loop_number))
312
+ .symbol_expr ();
313
+ pre_loop_head_instrs.add (
314
+ goto_programt::make_decl (in_loop_havoc_block, loop_head_location));
315
+ pre_loop_head_instrs.add (
316
+ goto_programt::make_assignment (in_loop_havoc_block, true_exprt{}));
295
317
havoc_assigns_targetst havoc_gen (to_havoc, ns);
296
318
havoc_gen.append_full_havoc_code (loop_head_location, pre_loop_head_instrs);
319
+ pre_loop_head_instrs.add (
320
+ goto_programt::make_assignment (in_loop_havoc_block, false_exprt{}));
297
321
298
322
// Insert the second block of pre_loop_head_instrs: the havocing code.
299
323
// We do not `add_pragma_disable_assigns_check`,
@@ -1414,6 +1438,66 @@ void code_contractst::apply_loop_contracts(
1414
1438
unwindset.parse_unwindset (loop_names, log .get_message_handler ());
1415
1439
goto_unwindt goto_unwind;
1416
1440
goto_unwind (goto_model, unwindset, goto_unwindt::unwind_strategyt::ASSUME);
1441
+
1442
+ remove_skip (goto_model);
1443
+
1444
+ // Record original loop number for some instrumented instructions.
1445
+ for (auto &goto_function_entry : goto_functions.function_map )
1446
+ {
1447
+ auto &goto_function = goto_function_entry.second ;
1448
+ bool is_in_loop_havoc_block = false ;
1449
+
1450
+ unsigned loop_number_of_loop_havoc = 0 ;
1451
+ for (goto_programt::const_targett it_instr =
1452
+ goto_function.body .instructions .begin ();
1453
+ it_instr != goto_function.body .instructions .end ();
1454
+ it_instr++)
1455
+ {
1456
+ // Don't override original loop numbers.
1457
+ if (original_loop_number_map.count (it_instr) != 0 )
1458
+ continue ;
1459
+
1460
+ // Store loop number for
1461
+ // ASSIGN ENTERED_LOOP = TRUE
1462
+ if (
1463
+ is_assignment_to_instrumented_variable (it_instr, ENTERED_LOOP) &&
1464
+ it_instr->assign_rhs () == true_exprt ())
1465
+ {
1466
+ const auto &assign_lhs =
1467
+ expr_try_dynamic_cast<symbol_exprt>(it_instr->assign_lhs ());
1468
+ original_loop_number_map[it_instr] = get_suffix_unsigned (
1469
+ id2string (assign_lhs->get_identifier ()),
1470
+ std::string (ENTERED_LOOP) + " __" );
1471
+ continue ;
1472
+ }
1473
+
1474
+ // Loop havocs are assignments between
1475
+ // ASSIGN IN_LOOP_HAVOC_BLOCK = true
1476
+ // and
1477
+ // ASSIGN IN_LOOP_HAVOC_BLOCK = false
1478
+
1479
+ // Entering the loop-havoc block.
1480
+ if (is_assignment_to_instrumented_variable (it_instr, IN_LOOP_HAVOC_BLOCK))
1481
+ {
1482
+ is_in_loop_havoc_block = it_instr->assign_rhs () == true_exprt ();
1483
+ const auto &assign_lhs =
1484
+ expr_try_dynamic_cast<symbol_exprt>(it_instr->assign_lhs ());
1485
+ loop_number_of_loop_havoc = get_suffix_unsigned (
1486
+ id2string (assign_lhs->get_identifier ()),
1487
+ std::string (IN_LOOP_HAVOC_BLOCK) + " __" );
1488
+ continue ;
1489
+ }
1490
+
1491
+ // Assignments in loop-havoc block are loop havocs.
1492
+ if (is_in_loop_havoc_block && it_instr->is_assign ())
1493
+ {
1494
+ loop_havoc_set.emplace (it_instr);
1495
+
1496
+ // Store loop number for loop havoc.
1497
+ original_loop_number_map[it_instr] = loop_number_of_loop_havoc;
1498
+ }
1499
+ }
1500
+ }
1417
1501
}
1418
1502
1419
1503
void code_contractst::enforce_contracts (
0 commit comments