10
10
// / Program Transformation
11
11
12
12
#include " goto_convert.h"
13
+ #include " goto_convert_class.h"
13
14
14
15
#include < util/arith_tools.h>
15
16
#include < util/c_types.h>
24
25
#include < util/string_constant.h>
25
26
#include < util/symbol_table_builder.h>
26
27
27
- #include " goto_convert_class.h"
28
28
#include " destructor.h"
29
29
#include " remove_skip.h"
30
30
31
+ #include < iostream>
32
+ #define WATCHVAR (var ) \
33
+ std::cerr << " DBG: " << __FILE__ << " (" << __LINE__ << " ) " << #var \
34
+ << " = [" << (var) << " ]" << std::endl
35
+
31
36
static bool is_empty (const goto_programt &goto_program)
32
37
{
33
38
forall_goto_program_instructions (it, goto_program)
@@ -134,6 +139,136 @@ goto_programt goto_convertt::build_declaration_stack(
134
139
return declarations;
135
140
}
136
141
142
+ struct build_declaration_hops_inputst
143
+ {
144
+ irep_idt mode;
145
+ irep_idt label;
146
+ goto_programt::targett goto_instruction;
147
+ goto_programt::targett label_instruction;
148
+ node_indext label_scope_index = 0 ;
149
+ node_indext end_scope_index = 0 ;
150
+ };
151
+
152
+ void goto_convertt::build_declaration_hops (
153
+ goto_programt &program,
154
+ std::unordered_map<irep_idt, symbolt, irep_id_hash> &label_flags,
155
+ const build_declaration_hops_inputst &inputs)
156
+ {
157
+ // In the case of a goto jumping into a scope, the declarations (but not the
158
+ // initialisations) need to be executed. This function performs a
159
+ // transformation from code that looks like -
160
+ // {
161
+ // statement_block_a();
162
+ // if(...)
163
+ // goto label;
164
+ // statement_block_b();
165
+ // user_label:
166
+ // x_label:
167
+ // int x;
168
+ // x = 0;
169
+ // statement_block_c();
170
+ // int y;
171
+ // y = 0;
172
+ // statement_block_d();
173
+ // label:
174
+ // statement_block_e();
175
+ // }
176
+ // to code which looks like -
177
+ // {
178
+ // __CPROVER_bool going_to_label;
179
+ // going_to_label = false;
180
+ // statement_block_a();
181
+ // if(...)
182
+ // going_to_label = true;
183
+ // goto scope_x_label;
184
+ // statement_block_b();
185
+ // scope_x_label:
186
+ // int x;
187
+ // if going_to_label goto scope_y_label:
188
+ // x = 0;
189
+ // statement_block_c();
190
+ // scope_y_label:
191
+ // int y;
192
+ // if going_to_label goto label:
193
+ // y = 0;
194
+ // statement_block_d();
195
+ // label:
196
+ // going_to_label = false;
197
+ // statement_block_e();
198
+ // }
199
+
200
+ PRECONDITION (inputs.label_scope_index != inputs.end_scope_index );
201
+
202
+ source_locationt hidden{};
203
+ hidden.set_hide ();
204
+ const auto flag = [&]() -> symbolt {
205
+ const auto existing_flag = label_flags.find (inputs.label );
206
+ if (existing_flag != label_flags.end ())
207
+ return existing_flag->second ;
208
+ const symbolt &new_flag = get_fresh_aux_symbol (
209
+ bool_typet{},
210
+ id2string (inputs.label ),
211
+ " going_to" ,
212
+ hidden,
213
+ inputs.mode ,
214
+ symbol_table);
215
+ label_flags.emplace (inputs.label , new_flag);
216
+
217
+ // Create and initialise flag.
218
+ goto_programt flag_creation;
219
+ flag_creation.instructions .push_back (
220
+ goto_programt::make_decl (new_flag.symbol_expr (), hidden));
221
+ const auto make_clear_flag = [&]() -> goto_programt::instructiont {
222
+ return goto_programt::make_assignment (
223
+ new_flag.symbol_expr (), false_exprt{}, hidden);
224
+ };
225
+ flag_creation.instructions .push_back (make_clear_flag ());
226
+ program.destructive_insert (program.instructions .begin (), flag_creation);
227
+
228
+ // Clear flag on arrival at label.
229
+ auto clear_on_arrival = make_clear_flag ();
230
+ program.insert_before_swap (inputs.label_instruction , clear_on_arrival);
231
+ return new_flag;
232
+ }();
233
+
234
+ {
235
+ // Set flag before the goto.
236
+ auto set_flag =
237
+ goto_programt::make_assignment (flag.symbol_expr (), true_exprt{}, hidden);
238
+ program.insert_before_swap (inputs.goto_instruction , set_flag);
239
+ }
240
+
241
+ auto target = inputs.label_instruction ;
242
+ targets.scope_stack .set_current_node (inputs.label_scope_index );
243
+ while (targets.scope_stack .get_current_node () > inputs.end_scope_index )
244
+ {
245
+ node_indext current_node = targets.scope_stack .get_current_node ();
246
+ auto &declaration = targets.scope_stack .get_declaration (current_node);
247
+ targets.scope_stack .descend_tree ();
248
+ if (!declaration)
249
+ continue ;
250
+
251
+ // TODO - TYPE CHECK FOR VAR ARRAYS!
252
+
253
+ WATCHVAR (declaration->instruction ->to_string ());
254
+ bool add_if = declaration->if_conditions_added .find (flag.name ) ==
255
+ declaration->if_conditions_added .end ();
256
+ if (add_if)
257
+ {
258
+ auto if_goto =
259
+ goto_programt::make_goto (target, flag.symbol_expr (), hidden);
260
+ program.instructions .insert (
261
+ std::next (declaration->instruction ), std::move (if_goto));
262
+ declaration->if_conditions_added .insert (flag.name );
263
+ }
264
+ target = declaration->instruction ;
265
+ }
266
+
267
+ // We need to look at the list node after goto_instruction because this
268
+ // iterator now refers to the flag assignment.
269
+ std::next (inputs.goto_instruction )->set_target (target);
270
+ }
271
+
137
272
/* ****************************************************************** \
138
273
139
274
Function: goto_convertt::finish_gotos
@@ -148,6 +283,8 @@ Function: goto_convertt::finish_gotos
148
283
149
284
void goto_convertt::finish_gotos (goto_programt &dest, const irep_idt &mode)
150
285
{
286
+ std::unordered_map<irep_idt, symbolt, irep_id_hash> label_flags;
287
+
151
288
for (const auto &g_it : targets.gotos )
152
289
{
153
290
goto_programt::instructiont &i=*(g_it.first );
@@ -179,6 +316,7 @@ void goto_convertt::finish_gotos(goto_programt &dest, const irep_idt &mode)
179
316
}
180
317
181
318
i.complete_goto (l_it->second .first );
319
+ WATCHVAR (i.get_target ()->to_string ());
182
320
183
321
node_indext label_target = l_it->second .second ;
184
322
node_indext goto_target = g_it.second ;
@@ -222,9 +360,15 @@ void goto_convertt::finish_gotos(goto_programt &dest, const irep_idt &mode)
222
360
debug () << " adding declaration code on jump to '" << goto_label << " '"
223
361
<< eom;
224
362
225
- auto declaration_code = build_declaration_stack (
226
- mode, label_target, intersection_result.common_ancestor );
227
- dest.destructive_insert (g_it.first , declaration_code);
363
+ build_declaration_hops_inputst inputs;
364
+ inputs.mode = mode;
365
+ inputs.label = l_it->first ;
366
+ inputs.goto_instruction = g_it.first ;
367
+ inputs.label_instruction = l_it->second .first ;
368
+ inputs.label_scope_index = label_target;
369
+ inputs.end_scope_index = intersection_result.common_ancestor ;
370
+ build_declaration_hops (dest, label_flags, inputs);
371
+ // WATCHVAR(i.get_target()->to_string());
228
372
}
229
373
}
230
374
else
@@ -660,7 +804,7 @@ void goto_convertt::convert_frontend_decl(
660
804
if (code.operands ().size () == 1 )
661
805
{
662
806
copy (code, DECL, dest);
663
- return dest.instructions .end ()-- ;
807
+ return std::prev ( dest.instructions .end ()) ;
664
808
}
665
809
666
810
exprt initializer = code.op1 ();
@@ -673,7 +817,7 @@ void goto_convertt::convert_frontend_decl(
673
817
// Break up into decl and assignment.
674
818
// Decl must be visible before initializer.
675
819
copy (tmp, DECL, dest);
676
- const auto declaration_iterator = dest.instructions .end ()-- ;
820
+ const auto declaration_iterator = std::prev ( dest.instructions .end ()) ;
677
821
678
822
auto initializer_location = initializer.find_source_location ();
679
823
clean_expr (initializer, dest, mode);
@@ -696,7 +840,6 @@ void goto_convertt::convert_frontend_decl(
696
840
697
841
{
698
842
code_deadt code_dead (symbol_expr);
699
-
700
843
targets.scope_stack .add (code_dead, {declaration_iterator});
701
844
}
702
845
0 commit comments