@@ -260,8 +260,7 @@ void goto_symext::symex_goto(statet &state)
260
260
DATA_INVARIANT (
261
261
instruction.targets .size () == 1 , " no support for non-deterministic gotos" );
262
262
263
- goto_programt::const_targett goto_target=
264
- instruction.get_target ();
263
+ goto_programt::const_targett goto_target = instruction.get_target ();
265
264
266
265
const bool backward = instruction.is_backwards_goto ();
267
266
@@ -614,6 +613,197 @@ void goto_symext::symex_unreachable_goto(statet &state)
614
613
symex_transition (state);
615
614
}
616
615
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
+
617
807
bool goto_symext::check_break (const irep_idt &loop_id, unsigned unwind)
618
808
{
619
809
// dummy implementation
0 commit comments