@@ -55,7 +55,7 @@ static exprt create_lexicographic_less_than(
55
55
// In fact, the last element is unnecessary, so we do not create it.
56
56
exprt::operandst equality_conjunctions (lhs.size ());
57
57
equality_conjunctions[0 ] = binary_relation_exprt (lhs[0 ], ID_equal, rhs[0 ]);
58
- for (unsigned int i = 1 ; i < equality_conjunctions.size () - 1 ; i++)
58
+ for (size_t i = 1 ; i < equality_conjunctions.size () - 1 ; i++)
59
59
{
60
60
binary_relation_exprt component_i_equality{lhs[i], ID_equal, rhs[i]};
61
61
equality_conjunctions[i] =
@@ -71,7 +71,7 @@ static exprt create_lexicographic_less_than(
71
71
exprt::operandst lexicographic_individual_comparisons (lhs.size ());
72
72
lexicographic_individual_comparisons[0 ] =
73
73
binary_relation_exprt (lhs[0 ], ID_lt, rhs[0 ]);
74
- for (unsigned int i = 1 ; i < lexicographic_individual_comparisons.size (); i++)
74
+ for (size_t i = 1 ; i < lexicographic_individual_comparisons.size (); i++)
75
75
{
76
76
binary_relation_exprt component_i_less_than{lhs[i], ID_lt, rhs[i]};
77
77
lexicographic_individual_comparisons[i] =
@@ -80,10 +80,20 @@ static exprt create_lexicographic_less_than(
80
80
return disjunction (lexicographic_individual_comparisons);
81
81
}
82
82
83
+ static void insert_before_swap_and_advance (
84
+ goto_programt &program,
85
+ goto_programt::targett &target,
86
+ goto_programt &payload)
87
+ {
88
+ const auto offset = payload.instructions .size ();
89
+ program.insert_before_swap (target, payload);
90
+ std::advance (target, offset);
91
+ }
92
+
83
93
void code_contractst::check_apply_loop_contracts (
84
94
goto_functionst::goto_functiont &goto_function,
85
95
const local_may_aliast &local_may_alias,
86
- const goto_programt::targett loop_head,
96
+ goto_programt::targett loop_head,
87
97
const loopt &loop,
88
98
const irep_idt &mode)
89
99
{
@@ -138,8 +148,8 @@ void code_contractst::check_apply_loop_contracts(
138
148
// H: assert(invariant);
139
149
// havoc;
140
150
// assume(invariant);
141
- // old_decreases_value = decreases_clause(current_environment);
142
151
// if(guard) goto E:
152
+ // old_decreases_value = decreases_clause(current_environment);
143
153
// loop;
144
154
// new_decreases_value = decreases_clause(current_environment);
145
155
// assert(invariant);
@@ -191,26 +201,37 @@ void code_contractst::check_apply_loop_contracts(
191
201
// decreases clause's value before and after the loop
192
202
for (const auto &clause : decreases_clause.operands ())
193
203
{
194
- old_decreases_vars. push_back (
204
+ const auto old_decreases_var =
195
205
new_tmp_symbol (clause.type (), loop_head->source_location , mode)
196
- .symbol_expr ());
197
- new_decreases_vars.push_back (
206
+ .symbol_expr ();
207
+ havoc_code.add (
208
+ goto_programt::make_decl (old_decreases_var, loop_head->source_location ));
209
+ old_decreases_vars.push_back (old_decreases_var);
210
+
211
+ const auto new_decreases_var =
198
212
new_tmp_symbol (clause.type (), loop_head->source_location , mode)
199
- .symbol_expr ());
213
+ .symbol_expr ();
214
+ havoc_code.add (
215
+ goto_programt::make_decl (new_decreases_var, loop_head->source_location ));
216
+ new_decreases_vars.push_back (new_decreases_var);
200
217
}
201
218
202
- if (!decreases_clause.is_nil ())
219
+ // non-deterministically skip the loop if it is a do-while loop
220
+ if (!loop_head->is_goto ())
203
221
{
204
- // Generate: declarations of the temporary variables that stores the
205
- // multidimensional decreases clause's value before the loop
206
- for (const auto &old_temp_var : old_decreases_vars)
207
- {
208
- havoc_code.add (
209
- goto_programt::make_decl (old_temp_var, loop_head->source_location ));
210
- }
222
+ havoc_code.add (goto_programt::make_goto (
223
+ loop_end,
224
+ side_effect_expr_nondett (bool_typet (), loop_head->source_location )));
225
+ }
226
+
227
+ // Now havoc at the loop head.
228
+ // Use insert_before_swap to preserve jumps to loop head.
229
+ insert_before_swap_and_advance (goto_function.body , loop_head, havoc_code);
211
230
212
- // Generate: assignments to store the multidimensional decreases clause's
213
- // value before the loop
231
+ // Generate: assignments to store the multidimensional decreases clause's
232
+ // value before the loop
233
+ if (!decreases_clause.is_nil ())
234
+ {
214
235
for (size_t i = 0 ; i < old_decreases_vars.size (); i++)
215
236
{
216
237
code_assignt old_decreases_assignment{old_decreases_vars[i],
@@ -219,20 +240,10 @@ void code_contractst::check_apply_loop_contracts(
219
240
loop_head->source_location ;
220
241
converter.goto_convert (old_decreases_assignment, havoc_code, mode);
221
242
}
222
- }
223
243
224
- // non-deterministically skip the loop if it is a do-while loop
225
- if (!loop_head->is_goto ())
226
- {
227
- havoc_code.add (goto_programt::make_goto (
228
- loop_end,
229
- side_effect_expr_nondett (bool_typet (), loop_head->source_location )));
244
+ goto_function.body .destructive_insert (std::next (loop_head), havoc_code);
230
245
}
231
246
232
- // Now havoc at the loop head.
233
- // Use insert_before_swap to preserve jumps to loop head.
234
- goto_function.body .insert_before_swap (loop_head, havoc_code);
235
-
236
247
// Generate: assert(invariant) just after the loop exits
237
248
// We use a block scope to create a temporary assertion,
238
249
// and immediately convert it to goto instructions.
@@ -244,19 +255,10 @@ void code_contractst::check_apply_loop_contracts(
244
255
" Check that loop invariant is preserved" );
245
256
}
246
257
258
+ // Generate: assignments to store the multidimensional decreases clause's
259
+ // value after one iteration of the loop
247
260
if (!decreases_clause.is_nil ())
248
261
{
249
- // Generate: declarations of temporary variables that stores the
250
- // multidimensional decreases clause's value after one arbitrary iteration
251
- // of the loop
252
- for (const auto &new_temp_var : new_decreases_vars)
253
- {
254
- havoc_code.add (
255
- goto_programt::make_decl (new_temp_var, loop_head->source_location ));
256
- }
257
-
258
- // Generate: assignments to store the multidimensional decreases clause's
259
- // value after one iteration of the loop
260
262
for (size_t i = 0 ; i < new_decreases_vars.size (); i++)
261
263
{
262
264
code_assignt new_decreases_assignment{new_decreases_vars[i],
@@ -269,8 +271,8 @@ void code_contractst::check_apply_loop_contracts(
269
271
// Generate: assertion that the multidimensional decreases clause's value
270
272
// after the loop is smaller than the value before the loop.
271
273
// Here, we use the lexicographic order.
272
- code_assertt monotonic_decreasing_assertion{create_lexicographic_less_than (
273
- new_decreases_vars, old_decreases_vars)};
274
+ code_assertt monotonic_decreasing_assertion{
275
+ create_lexicographic_less_than ( new_decreases_vars, old_decreases_vars)};
274
276
monotonic_decreasing_assertion.add_source_location () =
275
277
loop_head->source_location ;
276
278
converter.goto_convert (monotonic_decreasing_assertion, havoc_code, mode);
@@ -287,9 +289,7 @@ void code_contractst::check_apply_loop_contracts(
287
289
}
288
290
}
289
291
290
- auto offset = havoc_code.instructions .size ();
291
- goto_function.body .insert_before_swap (loop_end, havoc_code);
292
- std::advance (loop_end, offset);
292
+ insert_before_swap_and_advance (goto_function.body , loop_end, havoc_code);
293
293
294
294
// change the back edge into assume(false) or assume(guard)
295
295
loop_end->targets .clear ();
0 commit comments