11use super :: cli:: FailureReason ;
2+ use itertools:: Itertools ;
23use rayon:: prelude:: * ;
3- use std:: process:: Command ;
4+ use std:: { collections :: HashMap , process:: Command } ;
45
56fn runner_command ( runner : & str ) -> Command {
67 let mut it = runner. split_whitespace ( ) ;
@@ -11,85 +12,83 @@ fn runner_command(runner: &str) -> Command {
1112}
1213
1314pub fn compare_outputs ( intrinsic_name_list : & Vec < String > , runner : & str , target : & str ) -> bool {
14- let intrinsics = intrinsic_name_list
15- . par_iter ( )
16- . filter_map ( |intrinsic_name| {
17- let c = runner_command ( runner)
18- . arg ( "./intrinsic-test-programs" )
19- . arg ( intrinsic_name)
20- . current_dir ( "c_programs" )
21- . output ( ) ;
22-
23- let rust = runner_command ( runner)
24- . arg ( format ! ( "./target/{target}/release/intrinsic-test-programs" ) )
25- . arg ( intrinsic_name)
26- . current_dir ( "rust_programs" )
27- . output ( ) ;
28-
29- let ( c, rust) = match ( c, rust) {
30- ( Ok ( c) , Ok ( rust) ) => ( c, rust) ,
31- a => panic ! ( "{a:#?}" ) ,
32- } ;
33-
34- if !c. status . success ( ) {
35- error ! (
36- "Failed to run C program for intrinsic `{intrinsic_name}`\n stdout: {stdout}\n stderr: {stderr}" ,
37- stdout = std:: str :: from_utf8( & c. stdout) . unwrap_or( "" ) ,
38- stderr = std:: str :: from_utf8( & c. stderr) . unwrap_or( "" ) ,
39- ) ;
40- return Some ( FailureReason :: RunC ( intrinsic_name. clone ( ) ) ) ;
41- }
42-
43- if !rust. status . success ( ) {
44- error ! (
45- "Failed to run Rust program for intrinsic `{intrinsic_name}`\n stdout: {stdout}\n stderr: {stderr}" ,
46- stdout = std:: str :: from_utf8( & rust. stdout) . unwrap_or( "" ) ,
47- stderr = std:: str :: from_utf8( & rust. stderr) . unwrap_or( "" ) ,
48- ) ;
49- return Some ( FailureReason :: RunRust ( intrinsic_name. clone ( ) ) ) ;
50- }
15+ let c = runner_command ( runner)
16+ . arg ( "./intrinsic-test-programs" )
17+ . current_dir ( "c_programs" )
18+ . output ( ) ;
5119
52- info ! ( "Comparing intrinsic: {intrinsic_name}" ) ;
20+ let rust = runner_command ( runner)
21+ . arg ( format ! ( "./target/{target}/release/intrinsic-test-programs" ) )
22+ . current_dir ( "rust_programs" )
23+ . output ( ) ;
24+
25+ let ( c, rust) = match ( c, rust) {
26+ ( Ok ( c) , Ok ( rust) ) => ( c, rust) ,
27+ a => panic ! ( "{a:#?}" ) ,
28+ } ;
29+
30+ if !c. status . success ( ) {
31+ error ! (
32+ "Failed to run C program.\n stdout: {stdout}\n stderr: {stderr}" ,
33+ stdout = std:: str :: from_utf8( & c. stdout) . unwrap_or( "" ) ,
34+ stderr = std:: str :: from_utf8( & c. stderr) . unwrap_or( "" ) ,
35+ ) ;
36+ }
37+
38+ if !rust. status . success ( ) {
39+ error ! (
40+ "Failed to run Rust program.\n stdout: {stdout}\n stderr: {stderr}" ,
41+ stdout = std:: str :: from_utf8( & rust. stdout) . unwrap_or( "" ) ,
42+ stderr = std:: str :: from_utf8( & rust. stderr) . unwrap_or( "" ) ,
43+ ) ;
44+ }
5345
54- let c = std:: str:: from_utf8 ( & c. stdout )
55- . unwrap ( )
56- . to_lowercase ( )
57- . replace ( "-nan" , "nan" ) ;
58- let rust = std:: str:: from_utf8 ( & rust. stdout )
59- . unwrap ( )
60- . to_lowercase ( )
61- . replace ( "-nan" , "nan" ) ;
46+ let c = std:: str:: from_utf8 ( & c. stdout )
47+ . unwrap ( )
48+ . to_lowercase ( )
49+ . replace ( "-nan" , "nan" ) ;
50+ let rust = std:: str:: from_utf8 ( & rust. stdout )
51+ . unwrap ( )
52+ . to_lowercase ( )
53+ . replace ( "-nan" , "nan" ) ;
54+
55+ let c_output_map = c. split ( "############" )
56+ . filter_map ( |output| output. trim ( ) . split_once ( "\n " ) )
57+ . collect :: < HashMap < & str , & str > > ( ) ;
58+ let rust_output_map = rust. split ( "############" )
59+ . filter_map ( |output| output. trim ( ) . split_once ( "\n " ) )
60+ . collect :: < HashMap < & str , & str > > ( ) ;
6261
63- if c == rust {
64- None
65- } else {
66- Some ( FailureReason :: Difference ( intrinsic_name. clone ( ) , c, rust) )
67- }
68- } )
69- . collect :: < Vec < _ > > ( ) ;
70-
71- intrinsics. iter ( ) . for_each ( |reason| match reason {
72- FailureReason :: Difference ( intrinsic, c, rust) => {
62+ let intrinsics = c_output_map. keys ( ) . chain ( rust_output_map. keys ( ) ) . unique ( ) . collect_vec ( ) ;
63+ let intrinsics_diff_count = intrinsics
64+ . par_iter ( )
65+ . filter_map ( |& & intrinsic| {
7366 println ! ( "Difference for intrinsic: {intrinsic}" ) ;
74- let diff = diff:: lines ( c, rust) ;
75- diff. iter ( ) . for_each ( |diff| match diff {
76- diff:: Result :: Left ( c) => println ! ( "C: {c}" ) ,
77- diff:: Result :: Right ( rust) => println ! ( "Rust: {rust}" ) ,
78- diff:: Result :: Both ( _, _) => ( ) ,
79- } ) ;
67+ let c_output = c_output_map. get ( intrinsic) . unwrap ( ) ;
68+ let rust_output = rust_output_map. get ( intrinsic) . unwrap ( ) ;
69+ let diff = diff:: lines ( c_output, rust_output) ;
70+ let diff_count = diff. into_iter ( ) . filter_map ( |diff| match diff {
71+ diff:: Result :: Left ( c) => {
72+ println ! ( "C: {c}" ) ;
73+ Some ( c)
74+ }
75+ diff:: Result :: Right ( rust) => {
76+ println ! ( "Rust: {rust}" ) ;
77+ Some ( rust)
78+ }
79+ diff:: Result :: Both ( _, _) => None ,
80+ } ) . count ( ) ;
8081 println ! ( "****************************************************************" ) ;
81- }
82- FailureReason :: RunC ( intrinsic) => {
83- println ! ( "Failed to run C program for intrinsic {intrinsic}" )
84- }
85- FailureReason :: RunRust ( intrinsic) => {
86- println ! ( "Failed to run rust program for intrinsic {intrinsic}" )
87- }
88- } ) ;
82+ if diff_count > 0 {
83+ Some ( intrinsic)
84+ } else { None }
85+ } ) . count ( ) ;
86+
8987 println ! (
9088 "{} differences found (tested {} intrinsics)" ,
91- intrinsics . len ( ) ,
89+ intrinsics_diff_count ,
9290 intrinsic_name_list. len( )
9391 ) ;
94- intrinsics. is_empty ( )
92+
93+ intrinsics_diff_count == 0
9594}
0 commit comments