@@ -563,9 +563,10 @@ fn main() {
563563 None => & mut io:: stdin ( ) ,
564564 } ;
565565 reader. read_to_end ( & mut buf) . unwrap ( ) ;
566- match decode_eval_check ( & buf, & cli_args, Mode :: Assert ) {
566+ match decode_eval_check ( & buf, & cli_args, false ) {
567567 Ok ( ( ) ) => ( ) ,
568- Err ( e) => println ! ( "error: {e} (no panic raised)" ) ,
568+ Err ( Error :: Decode ( e) ) => println ! ( "error: {e} (no panic raised)" ) ,
569+ Err ( Error :: Check ( e) ) => panic ! ( "check error: {e}" ) ,
569570 }
570571 }
571572 Commands :: Decode { files } => run_decode_subcmd ( files, & cli_args) ,
@@ -595,7 +596,7 @@ fn main() {
595596 // FIXME(eddyb) make the first argument (panic hook choice) a CLI toggle.
596597 afl:: fuzz ( true , |buf| {
597598 // Discard decoding errors
598- let _ = decode_eval_check ( & buf, & cli_args, Mode :: Assert ) ;
599+ decode_eval_check ( & buf, & cli_args, false ) . unwrap ( ) ;
599600 } ) ;
600601
601602 return ;
@@ -646,8 +647,36 @@ impl fmt::Display for DecodeError {
646647 }
647648}
648649
650+ /// Context for when a check fails.
651+ #[ derive( Clone , Debug ) ]
652+ struct CheckError ( Box < ( EvalCfg , ResultSummary ) > ) ;
653+
654+ impl fmt:: Display for CheckError {
655+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
656+ write ! ( f, "cfg {:?} results {:?}" , self . 0.0 , self . 0.1 )
657+ }
658+ }
659+
660+ #[ derive( Clone , Debug ) ]
661+ enum Error {
662+ Decode ( DecodeError ) ,
663+ Check ( CheckError ) ,
664+ }
665+
666+ impl From < DecodeError > for Error {
667+ fn from ( value : DecodeError ) -> Self {
668+ Self :: Decode ( value)
669+ }
670+ }
671+
672+ impl From < CheckError > for Error {
673+ fn from ( value : CheckError ) -> Self {
674+ Self :: Check ( value)
675+ }
676+ }
677+
649678/// Configuration for the current operation.
650- #[ derive( Debug ) ]
679+ #[ derive( Debug , Clone ) ]
651680struct EvalCfg {
652681 kind : FpKind ,
653682 op : Op ,
@@ -727,14 +756,6 @@ impl EvalCfg {
727756 }
728757}
729758
730- #[ derive( Clone , Copy , Debug ) ]
731- enum Mode {
732- /// Print the results of checking but don't panic. Used for decoding error results.
733- PrintOnly ,
734- /// Exit on failure, used when actually running the fuzzer.
735- Assert ,
736- }
737-
738759/// Decode and evaluate all passed files without exiting on mismatches.
739760fn run_decode_subcmd ( files : & [ PathBuf ] , cli_args : & Args ) {
740761 let mut buf = Vec :: new ( ) ;
@@ -745,49 +766,50 @@ fn run_decode_subcmd(files: &[PathBuf], cli_args: &Args) {
745766 let mut f = fs:: File :: open ( path) . unwrap ( ) ;
746767 f. read_to_end ( & mut buf) . unwrap ( ) ;
747768
748- match decode_eval_check ( & buf, cli_args, Mode :: PrintOnly ) {
769+ match decode_eval_check ( & buf, cli_args, true ) {
749770 Ok ( ( ) ) => ( ) ,
750- Err ( e) => println ! ( "error decoding file: {e}" ) ,
771+ Err ( Error :: Decode ( e) ) => println ! ( "error decoding file: {e}" ) ,
772+ Err ( Error :: Check ( e) ) => println ! ( "check error: {e:?}" ) ,
751773 }
752774 }
753775}
754776
755777/// Main runner: decode a config, inputs based on that config, and then evaluate the results
756778/// for Rust, LLVM APFloat, and the host.
757- fn decode_eval_check ( data : & [ u8 ] , cli_args : & Args , mode : Mode ) -> Result < ( ) , DecodeError > {
779+ fn decode_eval_check ( data : & [ u8 ] , cli_args : & Args , always_print : bool ) -> Result < ( ) , Error > {
758780 let ( cfg, data) = EvalCfg :: decode ( data, cli_args) ?;
759781 match cfg. kind {
760782 FpKind :: Ieee16 => {
761783 let ( a, b, c, r) = decode_for_ty_eval :: < Ieee16 > ( & cfg, data) ?;
762- r. check_all ( & cfg, a, b, c, mode ) ;
784+ r. check_all ( & cfg, a, b, c, always_print ) ? ;
763785 }
764786 FpKind :: Ieee32 => {
765787 let ( a, b, c, r) = decode_for_ty_eval :: < Ieee32 > ( & cfg, data) ?;
766- r. check_all ( & cfg, a, b, c, mode ) ;
788+ r. check_all ( & cfg, a, b, c, always_print ) ? ;
767789 }
768790 FpKind :: Ieee64 => {
769791 let ( a, b, c, r) = decode_for_ty_eval :: < Ieee64 > ( & cfg, data) ?;
770- r. check_all ( & cfg, a, b, c, mode ) ;
792+ r. check_all ( & cfg, a, b, c, always_print ) ? ;
771793 }
772794 FpKind :: Ieee128 => {
773795 let ( a, b, c, r) = decode_for_ty_eval :: < Ieee128 > ( & cfg, data) ?;
774- r. check_all ( & cfg, a, b, c, mode ) ;
796+ r. check_all ( & cfg, a, b, c, always_print ) ? ;
775797 }
776798 FpKind :: F8E5M2 => {
777799 let ( a, b, c, r) = decode_for_ty_eval :: < F8E5M2 > ( & cfg, data) ?;
778- r. check_all ( & cfg, a, b, c, mode ) ;
800+ r. check_all ( & cfg, a, b, c, always_print ) ? ;
779801 }
780802 FpKind :: F8E4M3FN => {
781803 let ( a, b, c, r) = decode_for_ty_eval :: < F8E4M3FN > ( & cfg, data) ?;
782- r. check_all ( & cfg, a, b, c, mode ) ;
804+ r. check_all ( & cfg, a, b, c, always_print ) ? ;
783805 }
784806 FpKind :: BrainF16 => {
785807 let ( a, b, c, r) = decode_for_ty_eval :: < BrainF16 > ( & cfg, data) ?;
786- r. check_all ( & cfg, a, b, c, mode ) ;
808+ r. check_all ( & cfg, a, b, c, always_print ) ? ;
787809 }
788810 FpKind :: X87_F80 => {
789811 let ( a, b, c, r) = decode_for_ty_eval :: < X87_F80 > ( & cfg, data) ?;
790- r. check_all ( & cfg, a, b, c, mode ) ;
812+ r. check_all ( & cfg, a, b, c, always_print ) ? ;
791813 }
792814 }
793815
@@ -804,9 +826,18 @@ where
804826 Double : FloatConvert < <F as FloatRepr >:: RustcApFloat > ,
805827{
806828 let ( a, b, c) = decode_operands :: < F > ( cfg. op , data) ?;
829+ let r = eval_all ( cfg, a, b, c) ;
830+ Ok ( ( a, b, c, r) )
831+ }
807832
833+ #[ must_use]
834+ fn eval_all < F : FloatRepr > ( cfg : & EvalCfg , a : F , b : F , c : F ) -> FuzzOpEvalOutputs2 < F >
835+ where
836+ Single : FloatConvert < <F as FloatRepr >:: RustcApFloat > ,
837+ Double : FloatConvert < <F as FloatRepr >:: RustcApFloat > ,
838+ {
808839 // Evaluate the APFloat version as well as all possible references.
809- let r = FuzzOpEvalOutputs2 {
840+ FuzzOpEvalOutputs2 {
810841 rs_apf : eval_rust_ap ( cfg. op , cfg. rm , a, b, c) ,
811842 cxx_apf : cfg
812843 . run_cxx
@@ -815,9 +846,7 @@ where
815846 . run_host
816847 . then ( || F :: host_eval_fuzz_op_if_supported2 ( cfg. op , cfg. rm , a, b, c) )
817848 . flatten ( ) ,
818- } ;
819-
820- Ok ( ( a, b, c, r) )
849+ }
821850}
822851
823852/// Given a N-arity opcode, decode N `F`s from `data` and return zero in any remaining
@@ -851,15 +880,29 @@ struct FuzzOpEvalOutputs2<F> {
851880 host : Option < StatusAnd < F > > ,
852881}
853882
854- impl < F : FloatRepr > FuzzOpEvalOutputs2 < F > {
855- /// Validate that outputs are correct. May unconitionally print all values or exit on error
856- /// base on the mode (mismatches always print).
857- fn check_all ( & self , cfg : & EvalCfg , a : F , b : F , c : F , mode : Mode ) {
858- let ( always_print, always_assert) = match mode {
859- Mode :: PrintOnly => ( true , false ) ,
860- Mode :: Assert => ( false , true ) ,
861- } ;
883+ #[ derive( Clone , Debug ) ]
884+ struct ResultSummary {
885+ cxx_error : bool ,
886+ cxx_ignore : Option < & ' static str > ,
887+ cxx_stat_error : bool ,
888+ cxx_stat_ignore : Option < & ' static str > ,
889+ host_error : bool ,
890+ host_ignore : Option < & ' static str > ,
891+ host_stat_error : bool ,
892+ host_stat_ignore : Option < & ' static str > ,
893+ }
862894
895+ impl < F : FloatRepr > FuzzOpEvalOutputs2 < F > {
896+ /// Validate that outputs are correct. Pass `always_print` for decoding use where we want to
897+ /// see the output regardless of whether or not it is a failure.
898+ fn check_all (
899+ & self ,
900+ cfg : & EvalCfg ,
901+ a : F ,
902+ b : F ,
903+ c : F ,
904+ always_print : bool ,
905+ ) -> Result < ( ) , CheckError > {
863906 let print_float = |x : StatusAnd < F > ,
864907 label,
865908 error,
@@ -898,19 +941,7 @@ impl<F: FloatRepr> FuzzOpEvalOutputs2<F> {
898941 println ! ( ) ;
899942 } ;
900943
901- #[ derive( Debug ) ]
902- struct Results {
903- cxx_error : bool ,
904- cxx_ignore : Option < & ' static str > ,
905- cxx_stat_error : bool ,
906- cxx_stat_ignore : Option < & ' static str > ,
907- host_error : bool ,
908- host_ignore : Option < & ' static str > ,
909- host_stat_error : bool ,
910- host_stat_ignore : Option < & ' static str > ,
911- }
912-
913- let mut res = Results {
944+ let mut res = ResultSummary {
914945 cxx_error : false ,
915946 cxx_ignore : cfg. ignore_cxx ,
916947 cxx_stat_error : false ,
@@ -985,8 +1016,10 @@ impl<F: FloatRepr> FuzzOpEvalOutputs2<F> {
9851016 }
9861017 }
9871018
988- if always_assert && failure {
989- panic ! ( "mismatched results: {cfg:#?}\n {res:#?}" ) ;
1019+ if failure {
1020+ Err ( CheckError ( Box :: new ( ( cfg. clone ( ) , res) ) ) )
1021+ } else {
1022+ Ok ( ( ) )
9901023 }
9911024 }
9921025}
0 commit comments