Skip to content

Commit d87b506

Browse files
authored
Merge pull request #8458 from tautschnig/loop-invariants-conjunction-splitting
Contracts/DFCC: split conjunctions in loop invariants
2 parents f68cf8c + eb5466d commit d87b506

File tree

1 file changed

+36
-8
lines changed

1 file changed

+36
-8
lines changed

src/goto-instrument/contracts/dynamic-frames/dfcc_instrument_loop.cpp

+36-8
Original file line numberDiff line numberDiff line change
@@ -425,10 +425,24 @@ dfcc_instrument_loopt::add_step_instructions(
425425
const irep_idt &language_mode =
426426
dfcc_utilst::get_function_symbol(symbol_table, function_id).mode;
427427
{
428-
// Assume the loop invariant after havocing the state.
429-
code_assumet assumption{invariant};
430-
assumption.add_source_location() = loop_head_location;
431-
converter.goto_convert(assumption, step_instrs, language_mode);
428+
// Assume the loop invariant after havocing the state; produce one
429+
// assumption per conjunct to ease analysis of counterexamples, and possibly
430+
// also improve solver performance (observed with Bitwuzla)
431+
if(invariant.id() == ID_and)
432+
{
433+
for(const auto &op : invariant.operands())
434+
{
435+
code_assumet assumption{op};
436+
assumption.add_source_location() = loop_head_location;
437+
converter.goto_convert(assumption, step_instrs, language_mode);
438+
}
439+
}
440+
else
441+
{
442+
code_assumet assumption{invariant};
443+
assumption.add_source_location() = loop_head_location;
444+
converter.goto_convert(assumption, step_instrs, language_mode);
445+
}
432446
}
433447

434448
{
@@ -506,10 +520,24 @@ void dfcc_instrument_loopt::add_body_instructions(
506520
"Check invariant after step for loop " +
507521
id2string(check_location.get_function()) + "." +
508522
std::to_string(cbmc_loop_id));
509-
// Assume the loop invariant after havocing the state.
510-
code_assertt assertion{invariant};
511-
assertion.add_source_location() = check_location;
512-
converter.goto_convert(assertion, pre_loop_latch_instrs, language_mode);
523+
// Assert the loop invariant after havocing the state; produce one assertion
524+
// per conjunct to ease analysis of counterexamples, and possibly also
525+
// improve solver performance (observed with Bitwuzla)
526+
if(invariant.id() == ID_and)
527+
{
528+
for(const auto &op : invariant.operands())
529+
{
530+
code_assertt assertion{op};
531+
assertion.add_source_location() = check_location;
532+
converter.goto_convert(assertion, pre_loop_latch_instrs, language_mode);
533+
}
534+
}
535+
else
536+
{
537+
code_assertt assertion{invariant};
538+
assertion.add_source_location() = check_location;
539+
converter.goto_convert(assertion, pre_loop_latch_instrs, language_mode);
540+
}
513541
}
514542

515543
{

0 commit comments

Comments
 (0)