@@ -888,18 +888,24 @@ void code_contractst::apply_loop_contract(
888
888
889
889
std::list<size_t > to_check_contracts_on_children;
890
890
891
+ std::map<
892
+ goto_programt::targett,
893
+ std::pair<goto_programt::targett, natural_loops_mutablet::loopt>,
894
+ goto_programt::target_less_than>
895
+ loop_head_ends;
896
+
891
897
for (const auto &loop_head_and_content : natural_loops.loop_map)
892
898
{
893
- const auto &loop_content = loop_head_and_content.second ;
899
+ const auto &loop_body = loop_head_and_content.second ;
894
900
// Skip empty loops and self-looped node.
895
- if (loop_content .size () <= 1 )
901
+ if (loop_body .size () <= 1 )
896
902
continue ;
897
903
898
904
auto loop_head = loop_head_and_content.first ;
899
905
auto loop_end = loop_head;
900
906
901
907
// Find the last back edge to `loop_head`
902
- for (const auto &t : loop_content )
908
+ for (const auto &t : loop_body )
903
909
{
904
910
if (
905
911
t->is_goto () && t->get_target () == loop_head &&
@@ -914,6 +920,41 @@ void code_contractst::apply_loop_contract(
914
920
throw 0 ;
915
921
}
916
922
923
+ // By definition the `loop_body` is a set of instructions computed
924
+ // by `natural_loops` based on the CFG.
925
+ // Since we perform assigns clause instrumentation by sequentially
926
+ // traversing instructions from `loop_head` to `loop_end`,
927
+ // here we ensure that all instructions in `loop_body` belong within
928
+ // the [loop_head, loop_end] target range.
929
+
930
+ // Check 1. (i \in loop_body) ==> loop_head <= i <= loop_end
931
+ for (const auto &i : loop_body)
932
+ {
933
+ if (
934
+ loop_head->location_number > i->location_number ||
935
+ i->location_number > loop_end->location_number )
936
+ {
937
+ log .conditional_output (
938
+ log .error (), [&i, &loop_head](messaget::mstreamt &mstream) {
939
+ mstream << " Computed loop at " << loop_head->source_location ()
940
+ << " contains an instruction beyond [loop_head, loop_end]:"
941
+ << messaget::eom;
942
+ i->output (mstream);
943
+ mstream << messaget::eom;
944
+ });
945
+ throw 0 ;
946
+ }
947
+ }
948
+
949
+ if (!loop_head_ends.emplace (loop_head, std::make_pair (loop_end, loop_body))
950
+ .second )
951
+ UNREACHABLE;
952
+ }
953
+
954
+ for (auto &loop_head_end : loop_head_ends)
955
+ {
956
+ auto loop_head = loop_head_end.first ;
957
+ auto loop_end = loop_head_end.second .first ;
917
958
// After loop-contract instrumentation, jumps to the `loop_head` will skip
918
959
// some instrumented instructions. So we want to make sure that there is
919
960
// only one jump targeting `loop_head` from `loop_end` before loop-contract
@@ -961,7 +1002,7 @@ void code_contractst::apply_loop_contract(
961
1002
}
962
1003
963
1004
const auto idx = loop_nesting_graph.add_node (
964
- loop_content ,
1005
+ loop_head_end. second . second ,
965
1006
loop_head,
966
1007
loop_end,
967
1008
assigns_clause,
@@ -974,30 +1015,6 @@ void code_contractst::apply_loop_contract(
974
1015
continue ;
975
1016
976
1017
to_check_contracts_on_children.push_back (idx);
977
-
978
- // By definition the `loop_content` is a set of instructions computed
979
- // by `natural_loops` based on the CFG.
980
- // Since we perform assigns clause instrumentation by sequentially
981
- // traversing instructions from `loop_head` to `loop_end`,
982
- // here we ensure that all instructions in `loop_content` belong within
983
- // the [loop_head, loop_end] target range
984
-
985
- // Check 1. (i \in loop_content) ==> loop_head <= i <= loop_end
986
- for (const auto &i : loop_content)
987
- {
988
- if (std::distance (loop_head, i) < 0 || std::distance (i, loop_end) < 0 )
989
- {
990
- log .conditional_output (
991
- log .error (), [&i, &loop_head](messaget::mstreamt &mstream) {
992
- mstream << " Computed loop at " << loop_head->source_location ()
993
- << " contains an instruction beyond [loop_head, loop_end]:"
994
- << messaget::eom;
995
- i->output (mstream);
996
- mstream << messaget::eom;
997
- });
998
- throw 0 ;
999
- }
1000
- }
1001
1018
}
1002
1019
1003
1020
for (size_t outer = 0 ; outer < loop_nesting_graph.size(); ++outer)
0 commit comments