@@ -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 " << cur_file << " :" << cur_line << padding_1
712+ << step << t_file << " :" << t_line << padding_2
713+ << " (not " << nt_file << " :" << nt_line << " )"
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" << messaget::reset
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" << messaget::reset
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 " << new_lhs.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