@@ -38,21 +38,62 @@ Date: February 2016
38
38
// This is used in the implementation of multidimensional decreases clauses.
39
39
static exprt create_lexicographic_less_than (
40
40
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
+ }
42
49
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)
44
87
{
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);
50
91
}
51
92
52
93
void code_contractst::check_apply_loop_contracts (
53
94
goto_functionst::goto_functiont &goto_function,
54
95
const local_may_aliast &local_may_alias,
55
- const goto_programt::targett loop_head,
96
+ goto_programt::targett loop_head,
56
97
const loopt &loop,
57
98
const irep_idt &mode)
58
99
{
@@ -67,10 +108,11 @@ void code_contractst::check_apply_loop_contracts(
67
108
loop_end = t;
68
109
69
110
// see whether we have an invariant and a decreases clause
70
- exprt invariant = static_cast <const exprt &>(
111
+ auto invariant = static_cast <const exprt &>(
71
112
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 &>(
73
114
loop_end->get_condition ().find (ID_C_spec_decreases));
115
+
74
116
if (invariant.is_nil ())
75
117
{
76
118
if (decreases_clause.is_nil ())
@@ -92,12 +134,12 @@ void code_contractst::check_apply_loop_contracts(
92
134
}
93
135
94
136
// 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 ();
96
138
97
139
// Temporary variables for storing the multidimensional decreases clause
98
140
// 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 ;
101
143
102
144
// change
103
145
// H: loop;
@@ -106,8 +148,8 @@ void code_contractst::check_apply_loop_contracts(
106
148
// H: assert(invariant);
107
149
// havoc;
108
150
// assume(invariant);
109
- // old_decreases_value = decreases_clause(current_environment);
110
151
// if(guard) goto E:
152
+ // old_decreases_value = decreases_clause(current_environment);
111
153
// loop;
112
154
// new_decreases_value = decreases_clause(current_environment);
113
155
// assert(invariant);
@@ -159,34 +201,19 @@ void code_contractst::check_apply_loop_contracts(
159
201
// decreases clause's value before and after the loop
160
202
for (const auto &clause : decreases_clause.operands ())
161
203
{
162
- old_temporary_variables. push_back (
204
+ const auto old_decreases_var =
163
205
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);
179
210
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);
190
217
}
191
218
192
219
// non-deterministically skip the loop if it is a do-while loop
@@ -199,7 +226,23 @@ void code_contractst::check_apply_loop_contracts(
199
226
200
227
// Now havoc at the loop head.
201
228
// 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
+ }
203
246
204
247
// Generate: assert(invariant) just after the loop exits
205
248
// We use a block scope to create a temporary assertion,
@@ -212,23 +255,14 @@ void code_contractst::check_apply_loop_contracts(
212
255
" Check that loop invariant is preserved" );
213
256
}
214
257
258
+ // Generate: assignments to store the multidimensional decreases clause's
259
+ // value after one iteration of the loop
215
260
if (!decreases_clause.is_nil ())
216
261
{
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++)
221
263
{
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]};
232
266
new_decreases_assignment.add_source_location () =
233
267
loop_head->source_location ;
234
268
converter.goto_convert (new_decreases_assignment, havoc_code, mode);
@@ -237,27 +271,25 @@ void code_contractst::check_apply_loop_contracts(
237
271
// Generate: assertion that the multidimensional decreases clause's value
238
272
// after the loop is smaller than the value before the loop.
239
273
// 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 )};
242
276
monotonic_decreasing_assertion.add_source_location () =
243
277
loop_head->source_location ;
244
278
converter.goto_convert (monotonic_decreasing_assertion, havoc_code, mode);
245
279
havoc_code.instructions .back ().source_location .set_comment (
246
280
" Check decreases clause on loop iteration" );
247
281
248
282
// 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++)
250
284
{
251
285
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 ));
253
287
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 ));
255
289
}
256
290
}
257
291
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);
261
293
262
294
// change the back edge into assume(false) or assume(guard)
263
295
loop_end->targets .clear ();
@@ -268,52 +300,6 @@ void code_contractst::check_apply_loop_contracts(
268
300
loop_end->set_condition (boolean_negate (loop_end->get_condition ()));
269
301
}
270
302
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
-
317
303
bool code_contractst::has_contract (const irep_idt fun_name)
318
304
{
319
305
const symbolt &function_symbol = ns.lookup (fun_name);
0 commit comments