@@ -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,28 @@ 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 (
193
+ last_step_to_keep == target.SSA_steps .end () &&
194
+ is_last_step_to_keep (it, prop_conv))
195
+ {
196
+ last_step_to_keep = it;
197
+ }
191
198
192
199
const symex_target_equationt::SSA_stept &SSA_step=*it;
193
200
@@ -227,12 +234,21 @@ void build_goto_trace(
227
234
228
235
if (time_before<0 )
229
236
{
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);
237
+ time_mapt::const_iterator time_before_steps_it =
238
+ time_map.find (time_before);
239
+
240
+ if (time_before_steps_it != time_map.end ())
241
+ {
242
+ std::vector<ssa_step_iteratort> ¤t_time_steps =
243
+ time_map[current_time];
244
+
245
+ current_time_steps.insert (
246
+ current_time_steps.end (),
247
+ time_before_steps_it->second .begin (),
248
+ time_before_steps_it->second .end ());
249
+
250
+ time_map.erase (time_before_steps_it);
251
+ }
236
252
}
237
253
238
254
continue ;
@@ -248,97 +264,128 @@ void build_goto_trace(
248
264
continue ;
249
265
}
250
266
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;
267
+ if (it == last_step_to_keep)
268
+ {
269
+ last_step_was_kept = true ;
270
+ }
283
271
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 );
272
+ time_map[current_time].push_back (it);
273
+ }
288
274
289
- if (SSA_step.ssa_lhs .is_not_nil ())
290
- goto_trace_step.lhs_object_value =prop_conv.get (SSA_step.ssa_lhs );
275
+ INVARIANT (
276
+ last_step_to_keep == target.SSA_steps .end () || last_step_was_kept,
277
+ " last step in SSA trace to keep must not be filtered out as a sync "
278
+ " instruction, not-taken branch, PHI node, or similar" );
291
279
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
- }
280
+ // Now build the GOTO trace, ordered by time, then by SSA trace order.
281
+
282
+ // produce the step numbers
283
+ unsigned step_nr = 0 ;
297
284
298
- for (const auto &j : SSA_step.converted_io_args )
285
+ for (const auto &time_and_ssa_steps : time_map)
286
+ {
287
+ for (const auto ssa_step_it : time_and_ssa_steps.second )
299
288
{
300
- if (j.is_constant () ||
301
- j.id ()==ID_string_constant)
302
- goto_trace_step.io_args .push_back (j);
289
+ const auto &SSA_step = *ssa_step_it;
290
+ goto_trace.steps .push_back (goto_trace_stept ());
291
+ goto_trace_stept &goto_trace_step = goto_trace.steps .back ();
292
+
293
+ goto_trace_step.step_nr = ++step_nr;
294
+
295
+ goto_trace_step.thread_nr = SSA_step.source .thread_nr ;
296
+ goto_trace_step.pc = SSA_step.source .pc ;
297
+ goto_trace_step.comment = SSA_step.comment ;
298
+ if (SSA_step.ssa_lhs .is_not_nil ())
299
+ {
300
+ goto_trace_step.lhs_object =
301
+ ssa_exprt (SSA_step.ssa_lhs .get_original_expr ());
302
+ }
303
303
else
304
304
{
305
- exprt tmp=prop_conv.get (j);
306
- goto_trace_step.io_args .push_back (tmp);
305
+ goto_trace_step.lhs_object .make_nil ();
306
+ }
307
+ goto_trace_step.type = SSA_step.type ;
308
+ goto_trace_step.hidden = SSA_step.hidden ;
309
+ goto_trace_step.format_string = SSA_step.format_string ;
310
+ goto_trace_step.io_id = SSA_step.io_id ;
311
+ goto_trace_step.formatted = SSA_step.formatted ;
312
+ goto_trace_step.identifier = SSA_step.identifier ;
313
+
314
+ // update internal field for specific variables in the counterexample
315
+ update_internal_field (SSA_step, goto_trace_step, ns);
316
+
317
+ goto_trace_step.assignment_type =
318
+ (SSA_step.is_assignment () &&
319
+ (SSA_step.assignment_type ==
320
+ symex_targett::assignment_typet::VISIBLE_ACTUAL_PARAMETER ||
321
+ SSA_step.assignment_type ==
322
+ symex_targett::assignment_typet::HIDDEN_ACTUAL_PARAMETER))
323
+ ? goto_trace_stept::assignment_typet::ACTUAL_PARAMETER
324
+ : goto_trace_stept::assignment_typet::STATE;
325
+
326
+ if (SSA_step.original_full_lhs .is_not_nil ())
327
+ {
328
+ goto_trace_step.full_lhs = build_full_lhs_rec (
329
+ prop_conv, ns, SSA_step.original_full_lhs , SSA_step.ssa_full_lhs );
307
330
}
308
- }
309
331
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 ;
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 () || j.id () == ID_string_constant)
344
+ {
345
+ goto_trace_step.io_args .push_back (j);
346
+ }
347
+ else
348
+ {
349
+ exprt tmp = prop_conv.get (j);
350
+ goto_trace_step.io_args .push_back (tmp);
351
+ }
352
+ }
315
353
316
- goto_trace_step.cond_value =
317
- prop_conv.l_get (SSA_step.cond_literal ).is_true ();
354
+ if (SSA_step.is_assert () || SSA_step.is_assume () || SSA_step.is_goto ())
355
+ {
356
+ goto_trace_step.cond_expr = SSA_step.cond_expr ;
357
+
358
+ goto_trace_step.cond_value =
359
+ prop_conv.l_get (SSA_step.cond_literal ).is_true ();
360
+ }
361
+
362
+ if (ssa_step_it == last_step_to_keep)
363
+ return ;
318
364
}
319
365
}
366
+ }
320
367
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
- }
368
+ void build_goto_trace (
369
+ const symex_target_equationt &target,
370
+ symex_target_equationt::SSA_stepst::const_iterator last_step_to_keep,
371
+ const prop_convt &prop_conv,
372
+ const namespacet &ns,
373
+ goto_tracet &goto_trace)
374
+ {
375
+ const auto is_last_step_to_keep = [last_step_to_keep](
376
+ symex_target_equationt::SSA_stepst::const_iterator it, const prop_convt &) {
377
+ return last_step_to_keep == it;
378
+ };
336
379
337
- // produce the step numbers
338
- unsigned step_nr=0 ;
380
+ return build_goto_trace (
381
+ target, is_last_step_to_keep, prop_conv, ns, goto_trace);
382
+ }
339
383
340
- for (auto &s_it : goto_trace.steps )
341
- s_it.step_nr =++step_nr;
384
+ static bool is_failed_assertion_step (
385
+ symex_target_equationt::SSA_stepst::const_iterator step,
386
+ const prop_convt &prop_conv)
387
+ {
388
+ return step->is_assert () && prop_conv.l_get (step->cond_literal ).is_false ();
342
389
}
343
390
344
391
void build_goto_trace (
@@ -347,17 +394,5 @@ void build_goto_trace(
347
394
const namespacet &ns,
348
395
goto_tracet &goto_trace)
349
396
{
350
- 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
- }
397
+ build_goto_trace (target, is_failed_assertion_step, prop_conv, ns, goto_trace);
363
398
}
0 commit comments