@@ -260,8 +260,7 @@ void goto_symext::symex_goto(statet &state)
260260  DATA_INVARIANT (
261261    instruction.targets .size () == 1 , " no support for non-deterministic gotos" 
262262
263-   goto_programt::const_targett goto_target=
264-     instruction.get_target ();
263+   goto_programt::const_targett goto_target = instruction.get_target ();
265264
266265  const  bool  backward = instruction.is_backwards_goto ();
267266
@@ -614,6 +613,197 @@ void goto_symext::symex_unreachable_goto(statet &state)
614613  symex_transition (state);
615614}
616615
616+ void  goto_symext::symex_goto_retrace (statet &state)
617+ {
618+   //  get guard, targets as in symex_goto()
619+   const  goto_programt::instructiont &instruction = *state.source .pc ;
620+ 
621+   exprt new_guard = clean_expr (instruction.condition (), state, false );
622+ 
623+   renamedt<exprt, L2> renamed_guard = state.rename (std::move (new_guard), ns);
624+   renamed_guard = try_evaluate_pointer_comparisons (
625+     std::move (renamed_guard), state.value_set , language_mode, ns);
626+   if (symex_config.simplify_opt )
627+     renamed_guard.simplify (ns);
628+   new_guard = renamed_guard.get ();
629+ 
630+   target.goto_instruction (state.guard .as_expr (), renamed_guard, state.source );
631+ 
632+   DATA_INVARIANT (
633+     !instruction.targets .empty (), " goto should have at least one target" 
634+ 
635+   //  we only do deterministic gotos for now
636+   DATA_INVARIANT (
637+     instruction.targets .size () == 1 , " no support for non-deterministic gotos" 
638+ 
639+   goto_programt::const_targett goto_target = instruction.get_target ();
640+ 
641+   const  bool  backward = instruction.is_backwards_goto ();
642+ 
643+   goto_programt::const_targett next_instruction = state.source .pc ;
644+   next_instruction++;
645+ 
646+   //  goto or next depends on input trace from user
647+   bool  choose_goto;
648+   static  size_t  retrace_index = 0 ;
649+   if (retrace_index < symex_config.retrace_input .size ())
650+   {
651+     choose_goto = symex_config.retrace_input [retrace_index] == ' 1' 
652+   }
653+   else 
654+   {
655+     choose_goto = false ;
656+   }
657+   retrace_index++;
658+ 
659+   //  print goto choice
660+   log.conditional_output (
661+     log.status (),
662+     [this , &state, &goto_target, &next_instruction, choose_goto](
663+       messaget::mstreamt &mstream)
664+     {
665+       source_locationt cur = state.source .pc ->source_location ();
666+       source_locationt goto_dest = goto_target->source_location ();
667+       source_locationt next_dest = next_instruction->source_location ();
668+       source_locationt t_dest = choose_goto ? goto_dest : next_dest;
669+       source_locationt nt_dest = choose_goto ? next_dest : goto_dest;
670+ 
671+       auto  cur_file = cur.get_file ();
672+       if (cur_file.empty ())
673+         cur_file = " <unknown>" 
674+       auto  t_file = t_dest.get_file ();
675+       if (t_file.empty ())
676+         t_file = " <unknown>" 
677+       auto  nt_file = nt_dest.get_file ();
678+       if (nt_file.empty ())
679+         nt_file = " <unknown>" 
680+ 
681+       //  print nothing when files are the same
682+       if (cur_file == t_file)
683+         t_file = " " 
684+       if (cur_file == nt_file)
685+         nt_file = " " 
686+ 
687+       auto  cur_line = cur.get_line ();
688+       if (cur_line.empty ())
689+         cur_line = " ?" 
690+       auto  t_line = t_dest.get_line ();
691+       if (t_line.empty ())
692+         t_line = " ?" 
693+       auto  nt_line = nt_dest.get_line ();
694+       if (nt_line.empty ())
695+         nt_line = " ?" 
696+ 
697+       std::string head = symex_config.retrace_input ;
698+       //  add 0s in case input trace was shorter
699+       head.resize (retrace_index - 1 , ' 0' 
700+       std::string decision = choose_goto ? " 1" " 0" 
701+ 
702+       std::string step = choose_goto ? "  goto " "  next " 
703+ 
704+       std::string padding_1 =
705+         cur_line.size () < 3  ? std::string (3  - cur_line.size (), '  ' " " 
706+       std::string padding_2 =
707+         t_line.size () < 3  ? std::string (3  - t_line.size (), '  ' " " 
708+ 
709+       mstream << " Retrace " 
710+               << head << messaget::bold << decision << messaget::reset
711+               << "  at " " :" 
712+               << step << t_file << " :" 
713+               << "  (not " " :" " )" 
714+               << messaget::eom;
715+     });
716+ 
717+   //  warn when not following unconditional goto
718+   if (new_guard.is_true () && !choose_goto)
719+   {
720+     log.result () << " Retrace input " 
721+                  << messaget::red << " inconsistent" 
722+                  << " : 0/next although guard is true!" 
723+                  << log.eom ;
724+   }
725+   else  if (new_guard.is_false () && choose_goto)
726+   {
727+     log.result () << " Retrace input " 
728+                  << messaget::red << " inconsistent" 
729+                  << " : 1/goto although guard is false!" 
730+                  << log.eom ;
731+   }
732+ 
733+   symex_targett::sourcet original_source = state.source ;
734+   goto_programt::const_targett new_state_pc;
735+ 
736+   if (choose_goto)
737+   {
738+     //  Jump to the jump target if the input is '1'
739+     new_state_pc = goto_target;
740+     symex_transition (state, new_state_pc, backward);
741+   }
742+   else 
743+   {
744+     //  Jump to the next instruction
745+     new_state_pc = state.source .pc ;
746+     new_state_pc++;
747+     symex_transition (state);
748+   }
749+ 
750+   //  produce new guard symbol
751+   exprt guard_expr;
752+ 
753+   if (
754+     new_guard.id () == ID_symbol ||
755+     (new_guard.id () == ID_not && to_not_expr (new_guard).op ().id () == ID_symbol))
756+   {
757+     guard_expr = new_guard;
758+   }
759+   else 
760+   {
761+     symbol_exprt guard_symbol_expr =
762+       symbol_exprt (statet::guard_identifier (), bool_typet ());
763+     exprt new_rhs = boolean_negate (new_guard);
764+ 
765+     ssa_exprt new_lhs =
766+       state.rename_ssa <L1>(ssa_exprt{guard_symbol_expr}, ns).get ();
767+     new_lhs =
768+       state.assignment (std::move (new_lhs), new_rhs, ns, true , false ).get ();
769+ 
770+     guardt guard{true_exprt{}, guard_manager};
771+ 
772+     log.conditional_output (
773+       log.debug (),
774+       [this , &new_lhs](messaget::mstreamt &mstream)
775+       {
776+         mstream << " Assignment to " get_identifier ()
777+                 << "  [" pointer_offset_bits (new_lhs.type (), ns).value_or (0 )
778+                 << "  bits]" 
779+                 << messaget::eom;
780+       });
781+ 
782+     target.assignment (
783+       guard.as_expr (),
784+       new_lhs,
785+       new_lhs,
786+       guard_symbol_expr,
787+       new_rhs,
788+       original_source,
789+       symex_targett::assignment_typet::GUARD);
790+ 
791+     guard_expr = state.rename (boolean_negate (guard_symbol_expr), ns).get ();
792+   }
793+ 
794+   if (choose_goto)
795+   {
796+     symex_assume_l2 (state, guard_expr);
797+     state.guard .add (guard_expr);
798+   }
799+   else 
800+   {
801+     symex_assume_l2 (state, boolean_negate (guard_expr));
802+     state.guard .add (boolean_negate (guard_expr));
803+   }
804+   return ;
805+ }
806+ 
617807bool  goto_symext::check_break (const  irep_idt &loop_id, unsigned  unwind)
618808{
619809  //  dummy implementation
0 commit comments