@@ -55,7 +55,7 @@ static exprt create_lexicographic_less_than(
5555 // In fact, the last element is unnecessary, so we do not create it.
5656 exprt::operandst equality_conjunctions (lhs.size ());
5757 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++)
5959 {
6060 binary_relation_exprt component_i_equality{lhs[i], ID_equal, rhs[i]};
6161 equality_conjunctions[i] =
@@ -71,7 +71,7 @@ static exprt create_lexicographic_less_than(
7171 exprt::operandst lexicographic_individual_comparisons (lhs.size ());
7272 lexicographic_individual_comparisons[0 ] =
7373 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++)
7575 {
7676 binary_relation_exprt component_i_less_than{lhs[i], ID_lt, rhs[i]};
7777 lexicographic_individual_comparisons[i] =
@@ -80,10 +80,20 @@ static exprt create_lexicographic_less_than(
8080 return disjunction (lexicographic_individual_comparisons);
8181}
8282
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+
8393void code_contractst::check_apply_loop_contracts (
8494 goto_functionst::goto_functiont &goto_function,
8595 const local_may_aliast &local_may_alias,
86- const goto_programt::targett loop_head,
96+ goto_programt::targett loop_head,
8797 const loopt &loop,
8898 const irep_idt &mode)
8999{
@@ -138,8 +148,8 @@ void code_contractst::check_apply_loop_contracts(
138148 // H: assert(invariant);
139149 // havoc;
140150 // assume(invariant);
141- // old_decreases_value = decreases_clause(current_environment);
142151 // if(guard) goto E:
152+ // old_decreases_value = decreases_clause(current_environment);
143153 // loop;
144154 // new_decreases_value = decreases_clause(current_environment);
145155 // assert(invariant);
@@ -191,26 +201,37 @@ void code_contractst::check_apply_loop_contracts(
191201 // decreases clause's value before and after the loop
192202 for (const auto &clause : decreases_clause.operands ())
193203 {
194- old_decreases_vars. push_back (
204+ const auto old_decreases_var =
195205 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 =
198212 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);
200217 }
201218
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 ())
203221 {
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);
211230
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+ {
214235 for (size_t i = 0 ; i < old_decreases_vars.size (); i++)
215236 {
216237 code_assignt old_decreases_assignment{old_decreases_vars[i],
@@ -219,20 +240,10 @@ void code_contractst::check_apply_loop_contracts(
219240 loop_head->source_location ;
220241 converter.goto_convert (old_decreases_assignment, havoc_code, mode);
221242 }
222- }
223243
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);
230245 }
231246
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-
236247 // Generate: assert(invariant) just after the loop exits
237248 // We use a block scope to create a temporary assertion,
238249 // and immediately convert it to goto instructions.
@@ -244,19 +255,10 @@ void code_contractst::check_apply_loop_contracts(
244255 " Check that loop invariant is preserved" );
245256 }
246257
258+ // Generate: assignments to store the multidimensional decreases clause's
259+ // value after one iteration of the loop
247260 if (!decreases_clause.is_nil ())
248261 {
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
260262 for (size_t i = 0 ; i < new_decreases_vars.size (); i++)
261263 {
262264 code_assignt new_decreases_assignment{new_decreases_vars[i],
@@ -269,8 +271,8 @@ void code_contractst::check_apply_loop_contracts(
269271 // Generate: assertion that the multidimensional decreases clause's value
270272 // after the loop is smaller than the value before the loop.
271273 // 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)};
274276 monotonic_decreasing_assertion.add_source_location () =
275277 loop_head->source_location ;
276278 converter.goto_convert (monotonic_decreasing_assertion, havoc_code, mode);
@@ -287,9 +289,7 @@ void code_contractst::check_apply_loop_contracts(
287289 }
288290 }
289291
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);
293293
294294 // change the back edge into assume(false) or assume(guard)
295295 loop_end->targets .clear ();
0 commit comments