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