@@ -11,6 +11,8 @@ Author: Diffblue Ltd.
11
11
12
12
#include " ensure_one_backedge_per_target.h"
13
13
14
+ #include < analyses/natural_loops.h>
15
+
14
16
#include " goto_model.h"
15
17
16
18
#include < algorithm>
@@ -84,9 +86,89 @@ bool ensure_one_backedge_per_target(
84
86
return true ;
85
87
}
86
88
89
+ struct instruction_location_numbert : public goto_programt ::targett
90
+ {
91
+ // Implicit conversion from a goto_programt::targett is permitted.
92
+ // NOLINTNEXTLINE(runtime/explicit)
93
+ instruction_location_numbert (goto_programt::targett target)
94
+ : goto_programt::targett(target)
95
+ {
96
+ }
97
+
98
+ instruction_location_numbert () = default ;
99
+ };
100
+
101
+ inline bool operator <(
102
+ const instruction_location_numbert &i1,
103
+ const instruction_location_numbert &i2)
104
+ {
105
+ return i1->location_number < i2->location_number ;
106
+ }
107
+
87
108
bool ensure_one_backedge_per_target (goto_programt &goto_program)
88
109
{
89
- bool any_change = false ;
110
+ natural_loops_templatet<goto_programt, instruction_location_numbert>
111
+ natural_loops{goto_program};
112
+ std::set<instruction_location_numbert> modified_loops;
113
+
114
+ for (auto it1 = natural_loops.loop_map .begin ();
115
+ it1 != natural_loops.loop_map .end ();
116
+ ++it1)
117
+ {
118
+ DATA_INVARIANT (!it1->second .empty (), " loops cannot have no instructions" );
119
+ // skip over lexical loops
120
+ if (
121
+ (*std::prev (it1->second .end ()))->is_goto () &&
122
+ (*std::prev (it1->second .end ()))->get_target () == it1->first )
123
+ continue ;
124
+ if (modified_loops.find (it1->first ) != modified_loops.end ())
125
+ continue ;
126
+ // it1 refers to a loop that isn't a lexical loop, now see whether any other
127
+ // loop is nested within it1
128
+ for (auto it2 = natural_loops.loop_map .begin ();
129
+ it2 != natural_loops.loop_map .end ();
130
+ ++it2)
131
+ {
132
+ if (it1 == it2)
133
+ continue ;
134
+
135
+ if (std::includes (
136
+ it1->second .begin (),
137
+ it1->second .end (),
138
+ it2->second .begin (),
139
+ it2->second .end ()))
140
+ {
141
+ // make sure that loops with overlapping body are properly nested by a
142
+ // back edge; this will be a disconnected edge, which
143
+ // ensure_one_backedge_per_target connects
144
+ if (
145
+ modified_loops.find (it2->first ) == modified_loops.end () &&
146
+ (!(*std::prev (it2->second .end ()))->is_goto () ||
147
+ (*std::prev (it2->second .end ()))->get_target () != it2->first ))
148
+ {
149
+ auto new_goto = goto_program.insert_after (
150
+ *std::prev (it2->second .end ()),
151
+ goto_programt::make_goto (
152
+ it2->first , (*std::prev (it2->second .end ()))->source_location ()));
153
+ it2->second .insert_instruction (new_goto);
154
+ it1->second .insert_instruction (new_goto);
155
+ modified_loops.insert (it2->first );
156
+ }
157
+
158
+ goto_program.insert_after (
159
+ *std::prev (it1->second .end ()),
160
+ goto_programt::make_goto (
161
+ it1->first , (*std::prev (it1->second .end ()))->source_location ()));
162
+ modified_loops.insert (it1->first );
163
+ break ;
164
+ }
165
+ }
166
+ }
167
+
168
+ if (!modified_loops.empty ())
169
+ goto_program.update ();
170
+
171
+ bool any_change = !modified_loops.empty ();
90
172
91
173
for (auto it = goto_program.instructions .begin ();
92
174
it != goto_program.instructions .end ();
0 commit comments