@@ -164,7 +164,7 @@ void update_internal_field(
164164
165165void build_goto_trace (
166166 const symex_target_equationt &target,
167- symex_target_equationt::SSA_stepst::const_iterator end_step ,
167+ ssa_step_predicatet is_last_step_to_keep ,
168168 const prop_convt &prop_conv,
169169 const namespacet &ns,
170170 goto_tracet &goto_trace)
@@ -173,21 +173,27 @@ void build_goto_trace(
173173 // Furthermore, read-events need to occur before write
174174 // events with the same clock.
175175
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;
177178 time_mapt time_map;
178179
179180 mp_integer current_time=0 ;
180181
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 ;
183184
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 ();
187190 it++)
188191 {
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+ }
191197
192198 const symex_target_equationt::SSA_stept &SSA_step=*it;
193199
@@ -227,12 +233,21 @@ void build_goto_trace(
227233
228234 if (time_before<0 )
229235 {
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+ }
236251 }
237252
238253 continue ;
@@ -248,97 +263,133 @@ void build_goto_trace(
248263 continue ;
249264 }
250265
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+ }
283270
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+ }
288273
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" );
291278
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 ;
297283
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 )
299287 {
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+ }
303302 else
304303 {
305- exprt tmp=prop_conv.get (j);
306- goto_trace_step.io_args .push_back (tmp);
304+ goto_trace_step.lhs_object .make_nil ();
307305 }
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;
309324
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 ;
315360
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 ;
318367 }
319368 }
369+ }
320370
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+ };
336383
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+ }
339387
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 ();
342393}
343394
344395void build_goto_trace (
@@ -348,16 +399,5 @@ void build_goto_trace(
348399 goto_tracet &goto_trace)
349400{
350401 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);
363403}
0 commit comments