Skip to content

Commit f1d4b2f

Browse files
committed
remove repeated inclusion checks in nested loops
1 parent 1a472f2 commit f1d4b2f

File tree

4 files changed

+68
-8
lines changed

4 files changed

+68
-8
lines changed

src/goto-instrument/contracts/assigns.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ assigns_clauset::conditional_address_ranget::generate_snapshot_instructions()
117117
location));
118118

119119
instructions.destructive_append(skip_program);
120+
121+
add_pragma_disable_assigns_check(instructions);
120122
return instructions;
121123
}
122124

src/goto-instrument/contracts/contracts.cpp

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,6 @@ void code_contractst::check_apply_loop_contracts(
140140
generated_code,
141141
ID_loop_entry);
142142

143-
// Create 'loop_entry' history variables
144-
insert_before_swap_and_advance(goto_function.body, loop_head, generated_code);
145-
146143
// Generate: assert(invariant) just before the loop
147144
// We use a block scope to create a temporary assertion,
148145
// and immediately convert it to goto instructions.
@@ -154,6 +151,14 @@ void code_contractst::check_apply_loop_contracts(
154151
"Check loop invariant before entry");
155152
}
156153

154+
// Add 'loop_entry' history variables and base case assertion.
155+
// These variables are local and thus
156+
// need not be checked against the enclosing scope's write set.
157+
insert_before_swap_and_advance(
158+
goto_function.body,
159+
loop_head,
160+
add_pragma_disable_assigns_check(generated_code));
161+
157162
// havoc the variables that may be modified
158163
modifiest modifies;
159164
if(assigns.is_nil())
@@ -176,7 +181,8 @@ void code_contractst::check_apply_loop_contracts(
176181
for(const auto &target : assigns.operands())
177182
modifies.insert(target);
178183

179-
// create snapshots of the CARs -- must be done before havocing
184+
// Create snapshots of write set CARs.
185+
// This must be done before havocing the write set.
180186
for(const auto &car : loop_assigns.get_write_set())
181187
{
182188
auto snapshot_instructions = car.generate_snapshot_instructions();
@@ -188,7 +194,17 @@ void code_contractst::check_apply_loop_contracts(
188194
havoc_assigns_targetst havoc_gen(modifies, ns);
189195
havoc_gen.append_full_havoc_code(
190196
loop_head->source_location(), generated_code);
191-
insert_before_swap_and_advance(goto_function.body, loop_head, generated_code);
197+
198+
// Add the havocing code, but only check against the enclosing scope's
199+
// write set if it was manually specified.
200+
if(assigns.is_nil())
201+
insert_before_swap_and_advance(
202+
goto_function.body,
203+
loop_head,
204+
add_pragma_disable_assigns_check(generated_code));
205+
else
206+
insert_before_swap_and_advance(
207+
goto_function.body, loop_head, generated_code);
192208

193209
// Generate: assume(invariant) just after havocing
194210
// We use a block scope to create a temporary assumption,
@@ -726,7 +742,6 @@ void code_contractst::instrument_assign_statement(
726742
instruction_it->is_assign(),
727743
"The first instruction of instrument_assign_statement should always be"
728744
" an assignment");
729-
730745
add_inclusion_check(
731746
program, assigns_clause, instruction_it, instruction_it->assign_lhs());
732747
}
@@ -816,7 +831,9 @@ void code_contractst::instrument_call_statement(
816831

817832
alias_checking_instructions.destructive_append(skip_program);
818833
insert_before_swap_and_advance(
819-
body, instruction_it, alias_checking_instructions);
834+
body,
835+
instruction_it,
836+
add_pragma_disable_assigns_check(alias_checking_instructions));
820837

821838
// move past the call and then insert the invalidation instructions
822839
instruction_it++;
@@ -848,7 +865,9 @@ void code_contractst::instrument_call_statement(
848865

849866
invalidation_instructions.destructive_append(skip_program);
850867
insert_before_swap_and_advance(
851-
body, instruction_it, invalidation_instructions);
868+
body,
869+
instruction_it,
870+
add_pragma_disable_assigns_check(invalidation_instructions));
852871

853872
instruction_it--;
854873
}
@@ -985,6 +1004,14 @@ void code_contractst::check_frame_conditions(
9851004

9861005
for(; instruction_it != instruction_end; ++instruction_it)
9871006
{
1007+
const auto &pragmas = instruction_it->source_location().get_pragmas();
1008+
if(pragmas.find(CONTRACT_PRAGMA_DISABLE_ASSIGNS_CHECK) != pragmas.end())
1009+
continue;
1010+
1011+
// do not instrument this instruction again in the future,
1012+
// since we are going to instrument it now below.
1013+
add_pragma_disable_assigns_check(*instruction_it);
1014+
9881015
if(instruction_it->is_decl())
9891016
{
9901017
// grab the declared symbol

src/goto-instrument/contracts/utils.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,21 @@ Date: September 2021
1414
#include <util/pointer_expr.h>
1515
#include <util/pointer_predicates.h>
1616

17+
goto_programt::instructiont &
18+
add_pragma_disable_assigns_check(goto_programt::instructiont &instr)
19+
{
20+
instr.source_location_nonconst().add_pragma(
21+
CONTRACT_PRAGMA_DISABLE_ASSIGNS_CHECK);
22+
return instr;
23+
}
24+
25+
goto_programt &add_pragma_disable_assigns_check(goto_programt &prog)
26+
{
27+
Forall_goto_program_instructions(it, prog)
28+
add_pragma_disable_assigns_check(*it);
29+
return prog;
30+
}
31+
1732
static void append_safe_havoc_code_for_expr(
1833
const source_locationt location,
1934
const namespacet &ns,

src/goto-instrument/contracts/utils.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ Date: September 2021
1717

1818
#include <goto-programs/goto_model.h>
1919

20+
#define CONTRACT_PRAGMA_DISABLE_ASSIGNS_CHECK "contracts:disable:assigns-check"
21+
2022
/// \brief A class that overrides the low-level havocing functions in the base
2123
/// utility class, to havoc only when expressions point to valid memory,
2224
/// i.e. if all dereferences within an expression are valid
@@ -42,6 +44,20 @@ class havoc_if_validt : public havoc_utilst
4244
const namespacet &ns;
4345
};
4446

47+
/// \brief Adds a pragma on a GOTO instruction to disable inclusion checking.
48+
///
49+
/// \param instr: A mutable reference to the GOTO instruction.
50+
/// \return The same reference after mutation (i.e., adding the pragma).
51+
goto_programt::instructiont &
52+
add_pragma_disable_assigns_check(goto_programt::instructiont &instr);
53+
54+
/// \brief Adds pragmas on all instructions in a GOTO program
55+
/// to disable inclusion checking on them.
56+
///
57+
/// \param prog: A mutable reference to the GOTO program.
58+
/// \return The same reference after mutation (i.e., adding the pragmas).
59+
goto_programt &add_pragma_disable_assigns_check(goto_programt &prog);
60+
4561
/// \brief Generate a validity check over all dereferences in an expression
4662
///
4763
/// This function generates a formula:

0 commit comments

Comments
 (0)