@@ -164,7 +164,7 @@ void update_internal_field(
164
164
165
165
void build_goto_trace (
166
166
const symex_target_equationt &target,
167
- symex_target_equationt::SSA_stepst::const_iterator end_step ,
167
+ ssa_step_predicatet is_last_step_to_keep ,
168
168
const prop_convt &prop_conv,
169
169
const namespacet &ns,
170
170
goto_tracet &goto_trace)
@@ -173,21 +173,27 @@ void build_goto_trace(
173
173
// Furthermore, read-events need to occur before write
174
174
// events with the same clock.
175
175
176
- typedef std::map<mp_integer, goto_tracet::stepst> time_mapt;
176
+ typedef symex_target_equationt::SSA_stepst::const_iterator ssa_step_iteratort;
177
+ typedef std::map<mp_integer, std::vector<ssa_step_iteratort>> time_mapt;
177
178
time_mapt time_map;
178
179
179
180
mp_integer current_time=0 ;
180
181
181
- const goto_trace_stept *end_ptr= nullptr ;
182
- bool end_step_seen= false ;
182
+ ssa_step_iteratort last_step_to_keep = target. SSA_steps . end () ;
183
+ bool last_step_was_kept = false ;
183
184
184
- for (symex_target_equationt::SSA_stepst::const_iterator
185
- it=target.SSA_steps .begin ();
186
- it!=target.SSA_steps .end ();
185
+ // First sort the SSA steps by time, in the process dropping steps
186
+ // we definitely don't want to retain in the final trace:
187
+
188
+ for (ssa_step_iteratort it = target.SSA_steps .begin ();
189
+ it != target.SSA_steps .end ();
187
190
it++)
188
191
{
189
- if (it==end_step)
190
- end_step_seen=true ;
192
+ if (last_step_to_keep == target.SSA_steps .end () &&
193
+ is_last_step_to_keep (it, prop_conv))
194
+ {
195
+ last_step_to_keep = it;
196
+ }
191
197
192
198
const symex_target_equationt::SSA_stept &SSA_step=*it;
193
199
@@ -227,12 +233,21 @@ void build_goto_trace(
227
233
228
234
if (time_before<0 )
229
235
{
230
- time_mapt::iterator entry=
231
- time_map.insert (std::make_pair (
232
- current_time,
233
- goto_tracet::stepst ())).first ;
234
- entry->second .splice (entry->second .end (), time_map[time_before]);
235
- time_map.erase (time_before);
236
+ time_mapt::const_iterator time_before_steps_it =
237
+ time_map.find (time_before);
238
+
239
+ if (time_before_steps_it != time_map.end ())
240
+ {
241
+ std::vector<ssa_step_iteratort> ¤t_time_steps =
242
+ time_map[current_time];
243
+
244
+ current_time_steps.insert (
245
+ current_time_steps.end (),
246
+ time_before_steps_it->second .begin (),
247
+ time_before_steps_it->second .end ());
248
+
249
+ time_map.erase (time_before_steps_it);
250
+ }
236
251
}
237
252
238
253
continue ;
@@ -248,97 +263,133 @@ void build_goto_trace(
248
263
continue ;
249
264
}
250
265
251
- goto_tracet::stepst &steps=time_map[current_time];
252
- steps.push_back (goto_trace_stept ());
253
- goto_trace_stept &goto_trace_step=steps.back ();
254
- if (!end_step_seen)
255
- end_ptr=&goto_trace_step;
256
-
257
- goto_trace_step.thread_nr =SSA_step.source .thread_nr ;
258
- goto_trace_step.pc =SSA_step.source .pc ;
259
- goto_trace_step.comment =SSA_step.comment ;
260
- if (SSA_step.ssa_lhs .is_not_nil ())
261
- goto_trace_step.lhs_object =
262
- ssa_exprt (SSA_step.ssa_lhs .get_original_expr ());
263
- else
264
- goto_trace_step.lhs_object .make_nil ();
265
- goto_trace_step.type =SSA_step.type ;
266
- goto_trace_step.hidden =SSA_step.hidden ;
267
- goto_trace_step.format_string =SSA_step.format_string ;
268
- goto_trace_step.io_id =SSA_step.io_id ;
269
- goto_trace_step.formatted =SSA_step.formatted ;
270
- goto_trace_step.identifier =SSA_step.identifier ;
271
-
272
- // update internal field for specific variables in the counterexample
273
- update_internal_field (SSA_step, goto_trace_step, ns);
274
-
275
- goto_trace_step.assignment_type =
276
- (it->is_assignment ()&&
277
- (SSA_step.assignment_type ==
278
- symex_targett::assignment_typet::VISIBLE_ACTUAL_PARAMETER ||
279
- SSA_step.assignment_type ==
280
- symex_targett::assignment_typet::HIDDEN_ACTUAL_PARAMETER))?
281
- goto_trace_stept::assignment_typet::ACTUAL_PARAMETER:
282
- goto_trace_stept::assignment_typet::STATE;
266
+ if (it == last_step_to_keep)
267
+ {
268
+ last_step_was_kept = true ;
269
+ }
283
270
284
- if (SSA_step.original_full_lhs .is_not_nil ())
285
- goto_trace_step.full_lhs =
286
- build_full_lhs_rec (
287
- prop_conv, ns, SSA_step.original_full_lhs , SSA_step.ssa_full_lhs );
271
+ time_map[current_time].push_back (it);
272
+ }
288
273
289
- if (SSA_step.ssa_lhs .is_not_nil ())
290
- goto_trace_step.lhs_object_value =prop_conv.get (SSA_step.ssa_lhs );
274
+ INVARIANT (
275
+ last_step_to_keep == target.SSA_steps .end () || last_step_was_kept,
276
+ " last step in SSA trace to keep must not be filtered out as a sync "
277
+ " instruction, not-taken branch, PHI node, or similar" );
291
278
292
- if (SSA_step.ssa_full_lhs .is_not_nil ())
293
- {
294
- goto_trace_step.full_lhs_value =prop_conv.get (SSA_step.ssa_full_lhs );
295
- simplify (goto_trace_step.full_lhs_value , ns);
296
- }
279
+ // Now build the GOTO trace, ordered by time, then by SSA trace order.
280
+
281
+ // produce the step numbers
282
+ unsigned step_nr=0 ;
297
283
298
- for (const auto &j : SSA_step.converted_io_args )
284
+ for (const auto &time_and_ssa_steps : time_map)
285
+ {
286
+ for (const auto ssa_step_it : time_and_ssa_steps.second )
299
287
{
300
- if (j.is_constant () ||
301
- j.id ()==ID_string_constant)
302
- goto_trace_step.io_args .push_back (j);
288
+ const auto &SSA_step = *ssa_step_it;
289
+ goto_trace.steps .push_back (goto_trace_stept ());
290
+ goto_trace_stept &goto_trace_step = goto_trace.steps .back ();
291
+
292
+ goto_trace_step.step_nr = ++step_nr;
293
+
294
+ goto_trace_step.thread_nr =SSA_step.source .thread_nr ;
295
+ goto_trace_step.pc =SSA_step.source .pc ;
296
+ goto_trace_step.comment =SSA_step.comment ;
297
+ if (SSA_step.ssa_lhs .is_not_nil ())
298
+ {
299
+ goto_trace_step.lhs_object =
300
+ ssa_exprt (SSA_step.ssa_lhs .get_original_expr ());
301
+ }
303
302
else
304
303
{
305
- exprt tmp=prop_conv.get (j);
306
- goto_trace_step.io_args .push_back (tmp);
304
+ goto_trace_step.lhs_object .make_nil ();
307
305
}
308
- }
306
+ goto_trace_step.type =SSA_step.type ;
307
+ goto_trace_step.hidden =SSA_step.hidden ;
308
+ goto_trace_step.format_string =SSA_step.format_string ;
309
+ goto_trace_step.io_id =SSA_step.io_id ;
310
+ goto_trace_step.formatted =SSA_step.formatted ;
311
+ goto_trace_step.identifier =SSA_step.identifier ;
312
+
313
+ // update internal field for specific variables in the counterexample
314
+ update_internal_field (SSA_step, goto_trace_step, ns);
315
+
316
+ goto_trace_step.assignment_type =
317
+ (SSA_step.is_assignment () &&
318
+ (SSA_step.assignment_type ==
319
+ symex_targett::assignment_typet::VISIBLE_ACTUAL_PARAMETER ||
320
+ SSA_step.assignment_type ==
321
+ symex_targett::assignment_typet::HIDDEN_ACTUAL_PARAMETER))?
322
+ goto_trace_stept::assignment_typet::ACTUAL_PARAMETER:
323
+ goto_trace_stept::assignment_typet::STATE;
309
324
310
- if (SSA_step.is_assert () ||
311
- SSA_step.is_assume () ||
312
- SSA_step.is_goto ())
313
- {
314
- goto_trace_step.cond_expr =SSA_step.cond_expr ;
325
+ if (SSA_step.original_full_lhs .is_not_nil ())
326
+ {
327
+ goto_trace_step.full_lhs =
328
+ build_full_lhs_rec (
329
+ prop_conv, ns, SSA_step.original_full_lhs , SSA_step.ssa_full_lhs );
330
+ }
331
+
332
+ if (SSA_step.ssa_lhs .is_not_nil ())
333
+ goto_trace_step.lhs_object_value =prop_conv.get (SSA_step.ssa_lhs );
334
+
335
+ if (SSA_step.ssa_full_lhs .is_not_nil ())
336
+ {
337
+ goto_trace_step.full_lhs_value =prop_conv.get (SSA_step.ssa_full_lhs );
338
+ simplify (goto_trace_step.full_lhs_value , ns);
339
+ }
340
+
341
+ for (const auto &j : SSA_step.converted_io_args )
342
+ {
343
+ if (j.is_constant () ||
344
+ j.id ()==ID_string_constant)
345
+ {
346
+ goto_trace_step.io_args .push_back (j);
347
+ }
348
+ else
349
+ {
350
+ exprt tmp=prop_conv.get (j);
351
+ goto_trace_step.io_args .push_back (tmp);
352
+ }
353
+ }
354
+
355
+ if (SSA_step.is_assert () ||
356
+ SSA_step.is_assume () ||
357
+ SSA_step.is_goto ())
358
+ {
359
+ goto_trace_step.cond_expr =SSA_step.cond_expr ;
315
360
316
- goto_trace_step.cond_value =
317
- prop_conv.l_get (SSA_step.cond_literal ).is_true ();
361
+ goto_trace_step.cond_value =
362
+ prop_conv.l_get (SSA_step.cond_literal ).is_true ();
363
+ }
364
+
365
+ if (ssa_step_it == last_step_to_keep)
366
+ return ;
318
367
}
319
368
}
369
+ }
320
370
321
- // Now assemble into a single goto_trace.
322
- // This exploits sorted-ness of the map.
323
- for (auto &t_it : time_map)
324
- goto_trace.steps .splice (goto_trace.steps .end (), t_it.second );
325
-
326
- // cut off the trace at the desired end
327
- for (goto_tracet::stepst::iterator
328
- s_it1=goto_trace.steps .begin ();
329
- s_it1!=goto_trace.steps .end ();
330
- ++s_it1)
331
- if (end_step_seen && end_ptr==&(*s_it1))
332
- {
333
- goto_trace.trim_after (s_it1);
334
- break ;
335
- }
371
+ void build_goto_trace (
372
+ const symex_target_equationt &target,
373
+ symex_target_equationt::SSA_stepst::const_iterator last_step_to_keep,
374
+ const prop_convt &prop_conv,
375
+ const namespacet &ns,
376
+ goto_tracet &goto_trace)
377
+ {
378
+ const auto is_last_step_to_keep = [last_step_to_keep](
379
+ symex_target_equationt::SSA_stepst::const_iterator it, const prop_convt &)
380
+ {
381
+ return last_step_to_keep == it;
382
+ };
336
383
337
- // produce the step numbers
338
- unsigned step_nr=0 ;
384
+ return build_goto_trace (
385
+ target, is_last_step_to_keep, prop_conv, ns, goto_trace);
386
+ }
339
387
340
- for (auto &s_it : goto_trace.steps )
341
- s_it.step_nr =++step_nr;
388
+ static bool is_failed_assertion_step (
389
+ symex_target_equationt::SSA_stepst::const_iterator step,
390
+ const prop_convt &prop_conv)
391
+ {
392
+ return step->is_assert () && prop_conv.l_get (step->cond_literal ).is_false ();
342
393
}
343
394
344
395
void build_goto_trace (
@@ -348,16 +399,5 @@ void build_goto_trace(
348
399
goto_tracet &goto_trace)
349
400
{
350
401
build_goto_trace (
351
- target, target.SSA_steps .end (), prop_conv, ns, goto_trace);
352
-
353
- // Now delete anything after first failed assertion
354
- for (goto_tracet::stepst::iterator
355
- s_it1=goto_trace.steps .begin ();
356
- s_it1!=goto_trace.steps .end ();
357
- s_it1++)
358
- if (s_it1->is_assert () && !s_it1->cond_value )
359
- {
360
- goto_trace.trim_after (s_it1);
361
- break ;
362
- }
402
+ target, is_failed_assertion_step, prop_conv, ns, goto_trace);
363
403
}
0 commit comments