@@ -38,21 +38,62 @@ Date: February 2016
3838// This is used in the implementation of multidimensional decreases clauses.
3939static exprt create_lexicographic_less_than (
4040 const std::vector<symbol_exprt> &lhs,
41- const std::vector<symbol_exprt> &rhs);
41+ const std::vector<symbol_exprt> &rhs)
42+ {
43+ PRECONDITION (lhs.size () == rhs.size ());
44+
45+ if (lhs.empty ())
46+ {
47+ return false_exprt ();
48+ }
4249
43- exprt get_size (const typet &type, const namespacet &ns, messaget &log)
50+ // Store conjunctions of equalities.
51+ // For example, suppose that the two input vectors are <s1, s2, s3> and <l1,
52+ // l2, l3>.
53+ // Then this vector stores <s1 == l1, s1 == l1 && s2 == l2,
54+ // s1 == l1 && s2 == l2 && s3 == l3>.
55+ // In fact, the last element is unnecessary, so we do not create it.
56+ exprt::operandst equality_conjunctions (lhs.size ());
57+ equality_conjunctions[0 ] = binary_relation_exprt (lhs[0 ], ID_equal, rhs[0 ]);
58+ for (size_t i = 1 ; i < equality_conjunctions.size () - 1 ; i++)
59+ {
60+ binary_relation_exprt component_i_equality{lhs[i], ID_equal, rhs[i]};
61+ equality_conjunctions[i] =
62+ and_exprt (equality_conjunctions[i - 1 ], component_i_equality);
63+ }
64+
65+ // Store inequalities between the i-th components of the input vectors
66+ // (i.e. lhs and rhs).
67+ // For example, suppose that the two input vectors are <s1, s2, s3> and <l1,
68+ // l2, l3>.
69+ // Then this vector stores <s1 < l1, s1 == l1 && s2 < l2, s1 == l1 &&
70+ // s2 == l2 && s3 < l3>.
71+ exprt::operandst lexicographic_individual_comparisons (lhs.size ());
72+ lexicographic_individual_comparisons[0 ] =
73+ binary_relation_exprt (lhs[0 ], ID_lt, rhs[0 ]);
74+ for (size_t i = 1 ; i < lexicographic_individual_comparisons.size (); i++)
75+ {
76+ binary_relation_exprt component_i_less_than{lhs[i], ID_lt, rhs[i]};
77+ lexicographic_individual_comparisons[i] =
78+ and_exprt (equality_conjunctions[i - 1 ], component_i_less_than);
79+ }
80+ return disjunction (lexicographic_individual_comparisons);
81+ }
82+
83+ static void insert_before_swap_and_advance (
84+ goto_programt &program,
85+ goto_programt::targett &target,
86+ goto_programt &payload)
4487{
45- auto size_of_opt = size_of_expr (type, ns);
46- CHECK_RETURN (size_of_opt.has_value ());
47- exprt result = size_of_opt.value ();
48- result.add (ID_C_c_sizeof_type) = type;
49- return result;
88+ const auto offset = payload.instructions .size ();
89+ program.insert_before_swap (target, payload);
90+ std::advance (target, offset);
5091}
5192
5293void code_contractst::check_apply_loop_contracts (
5394 goto_functionst::goto_functiont &goto_function,
5495 const local_may_aliast &local_may_alias,
55- const goto_programt::targett loop_head,
96+ goto_programt::targett loop_head,
5697 const loopt &loop,
5798 const irep_idt &mode)
5899{
@@ -67,10 +108,11 @@ void code_contractst::check_apply_loop_contracts(
67108 loop_end = t;
68109
69110 // see whether we have an invariant and a decreases clause
70- exprt invariant = static_cast <const exprt &>(
111+ auto invariant = static_cast <const exprt &>(
71112 loop_end->get_condition ().find (ID_C_spec_loop_invariant));
72- exprt decreases_clause = static_cast <const exprt &>(
113+ auto decreases_clause = static_cast <const exprt &>(
73114 loop_end->get_condition ().find (ID_C_spec_decreases));
115+
74116 if (invariant.is_nil ())
75117 {
76118 if (decreases_clause.is_nil ())
@@ -92,12 +134,12 @@ void code_contractst::check_apply_loop_contracts(
92134 }
93135
94136 // Vector representing a (possibly multidimensional) decreases clause
95- const auto decreases_clause_vector = decreases_clause.operands ();
137+ const auto &decreases_clause_exprs = decreases_clause.operands ();
96138
97139 // Temporary variables for storing the multidimensional decreases clause
98140 // at the start of and end of a loop body
99- std::vector<symbol_exprt> old_temporary_variables ;
100- std::vector<symbol_exprt> new_temporary_variables ;
141+ std::vector<symbol_exprt> old_decreases_vars ;
142+ std::vector<symbol_exprt> new_decreases_vars ;
101143
102144 // change
103145 // H: loop;
@@ -106,8 +148,8 @@ void code_contractst::check_apply_loop_contracts(
106148 // H: assert(invariant);
107149 // havoc;
108150 // assume(invariant);
109- // old_decreases_value = decreases_clause(current_environment);
110151 // if(guard) goto E:
152+ // old_decreases_value = decreases_clause(current_environment);
111153 // loop;
112154 // new_decreases_value = decreases_clause(current_environment);
113155 // assert(invariant);
@@ -159,34 +201,19 @@ void code_contractst::check_apply_loop_contracts(
159201 // decreases clause's value before and after the loop
160202 for (const auto &clause : decreases_clause.operands ())
161203 {
162- old_temporary_variables. push_back (
204+ const auto old_decreases_var =
163205 new_tmp_symbol (clause.type (), loop_head->source_location , mode)
164- .symbol_expr ());
165- new_temporary_variables.push_back (
166- new_tmp_symbol (clause.type (), loop_head->source_location , mode)
167- .symbol_expr ());
168- }
169-
170- if (!decreases_clause.is_nil ())
171- {
172- // Generate: declarations of the temporary variables that stores the
173- // multidimensional decreases clause's value before the loop
174- for (const auto &old_temp_var : old_temporary_variables)
175- {
176- havoc_code.add (
177- goto_programt::make_decl (old_temp_var, loop_head->source_location ));
178- }
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);
179210
180- // Generate: assignments to store the multidimensional decreases clause's
181- // value before the loop
182- for (size_t i = 0 ; i < old_temporary_variables.size (); i++)
183- {
184- code_assignt old_decreases_assignment{old_temporary_variables[i],
185- decreases_clause_vector[i]};
186- old_decreases_assignment.add_source_location () =
187- loop_head->source_location ;
188- converter.goto_convert (old_decreases_assignment, havoc_code, mode);
189- }
211+ const auto new_decreases_var =
212+ new_tmp_symbol (clause.type (), loop_head->source_location , mode)
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);
190217 }
191218
192219 // non-deterministically skip the loop if it is a do-while loop
@@ -199,7 +226,23 @@ void code_contractst::check_apply_loop_contracts(
199226
200227 // Now havoc at the loop head.
201228 // Use insert_before_swap to preserve jumps to loop head.
202- goto_function.body .insert_before_swap (loop_head, havoc_code);
229+ insert_before_swap_and_advance (goto_function.body , loop_head, havoc_code);
230+
231+ // Generate: assignments to store the multidimensional decreases clause's
232+ // value before the loop
233+ if (!decreases_clause.is_nil ())
234+ {
235+ for (size_t i = 0 ; i < old_decreases_vars.size (); i++)
236+ {
237+ code_assignt old_decreases_assignment{old_decreases_vars[i],
238+ decreases_clause_exprs[i]};
239+ old_decreases_assignment.add_source_location () =
240+ loop_head->source_location ;
241+ converter.goto_convert (old_decreases_assignment, havoc_code, mode);
242+ }
243+
244+ goto_function.body .destructive_insert (std::next (loop_head), havoc_code);
245+ }
203246
204247 // Generate: assert(invariant) just after the loop exits
205248 // We use a block scope to create a temporary assertion,
@@ -212,23 +255,14 @@ void code_contractst::check_apply_loop_contracts(
212255 " Check that loop invariant is preserved" );
213256 }
214257
258+ // Generate: assignments to store the multidimensional decreases clause's
259+ // value after one iteration of the loop
215260 if (!decreases_clause.is_nil ())
216261 {
217- // Generate: declarations of temporary variables that stores the
218- // multidimensional decreases clause's value after one arbitrary iteration
219- // of the loop
220- for (const auto &new_temp_var : new_temporary_variables)
262+ for (size_t i = 0 ; i < new_decreases_vars.size (); i++)
221263 {
222- havoc_code.add (
223- goto_programt::make_decl (new_temp_var, loop_head->source_location ));
224- }
225-
226- // Generate: assignments to store the multidimensional decreases clause's
227- // value after one iteration of the loop
228- for (size_t i = 0 ; i < new_temporary_variables.size (); i++)
229- {
230- code_assignt new_decreases_assignment{new_temporary_variables[i],
231- decreases_clause_vector[i]};
264+ code_assignt new_decreases_assignment{new_decreases_vars[i],
265+ decreases_clause_exprs[i]};
232266 new_decreases_assignment.add_source_location () =
233267 loop_head->source_location ;
234268 converter.goto_convert (new_decreases_assignment, havoc_code, mode);
@@ -237,27 +271,25 @@ void code_contractst::check_apply_loop_contracts(
237271 // Generate: assertion that the multidimensional decreases clause's value
238272 // after the loop is smaller than the value before the loop.
239273 // Here, we use the lexicographic order.
240- code_assertt monotonic_decreasing_assertion{create_lexicographic_less_than (
241- new_temporary_variables, old_temporary_variables )};
274+ code_assertt monotonic_decreasing_assertion{
275+ create_lexicographic_less_than (new_decreases_vars, old_decreases_vars )};
242276 monotonic_decreasing_assertion.add_source_location () =
243277 loop_head->source_location ;
244278 converter.goto_convert (monotonic_decreasing_assertion, havoc_code, mode);
245279 havoc_code.instructions .back ().source_location .set_comment (
246280 " Check decreases clause on loop iteration" );
247281
248282 // Discard the temporary variables that store decreases clause's value
249- for (size_t i = 0 ; i < old_temporary_variables .size (); i++)
283+ for (size_t i = 0 ; i < old_decreases_vars .size (); i++)
250284 {
251285 havoc_code.add (goto_programt::make_dead (
252- old_temporary_variables [i], loop_head->source_location ));
286+ old_decreases_vars [i], loop_head->source_location ));
253287 havoc_code.add (goto_programt::make_dead (
254- new_temporary_variables [i], loop_head->source_location ));
288+ new_decreases_vars [i], loop_head->source_location ));
255289 }
256290 }
257291
258- auto offset = havoc_code.instructions .size ();
259- goto_function.body .insert_before_swap (loop_end, havoc_code);
260- std::advance (loop_end, offset);
292+ insert_before_swap_and_advance (goto_function.body , loop_end, havoc_code);
261293
262294 // change the back edge into assume(false) or assume(guard)
263295 loop_end->targets .clear ();
@@ -268,52 +300,6 @@ void code_contractst::check_apply_loop_contracts(
268300 loop_end->set_condition (boolean_negate (loop_end->get_condition ()));
269301}
270302
271- // Create a lexicographic less-than relation between two tuples of variables.
272- // This is used in the implementation of multidimensional decreases clauses.
273- static exprt create_lexicographic_less_than (
274- const std::vector<symbol_exprt> &lhs,
275- const std::vector<symbol_exprt> &rhs)
276- {
277- PRECONDITION (lhs.size () == rhs.size ());
278-
279- if (lhs.empty ())
280- {
281- return false_exprt ();
282- }
283-
284- // Store conjunctions of equalities.
285- // For example, suppose that the two input vectors are <s1, s2, s3> and <l1,
286- // l2, l3>.
287- // Then this vector stores <s1 == l1, s1 == l1 && s2 == l2,
288- // s1 == l1 && s2 == l2 && s3 == l3>.
289- // In fact, the last element is unnecessary, so we do not create it.
290- exprt::operandst equality_conjunctions (lhs.size ());
291- equality_conjunctions[0 ] = binary_relation_exprt (lhs[0 ], ID_equal, rhs[0 ]);
292- for (unsigned int i = 1 ; i < equality_conjunctions.size () - 1 ; i++)
293- {
294- binary_relation_exprt component_i_equality{lhs[i], ID_equal, rhs[i]};
295- equality_conjunctions[i] =
296- and_exprt (equality_conjunctions[i - 1 ], component_i_equality);
297- }
298-
299- // Store inequalities between the i-th components of the input vectors
300- // (i.e. lhs and rhs).
301- // For example, suppose that the two input vectors are <s1, s2, s3> and <l1,
302- // l2, l3>.
303- // Then this vector stores <s1 < l1, s1 == l1 && s2 < l2, s1 == l1 &&
304- // s2 == l2 && s3 < l3>.
305- exprt::operandst lexicographic_individual_comparisons (lhs.size ());
306- lexicographic_individual_comparisons[0 ] =
307- binary_relation_exprt (lhs[0 ], ID_lt, rhs[0 ]);
308- for (unsigned int i = 1 ; i < lexicographic_individual_comparisons.size (); i++)
309- {
310- binary_relation_exprt component_i_less_than{lhs[i], ID_lt, rhs[i]};
311- lexicographic_individual_comparisons[i] =
312- and_exprt (equality_conjunctions[i - 1 ], component_i_less_than);
313- }
314- return disjunction (lexicographic_individual_comparisons);
315- }
316-
317303bool code_contractst::has_contract (const irep_idt fun_name)
318304{
319305 const symbolt &function_symbol = ns.lookup (fun_name);
0 commit comments