Skip to main content

compiletest/runtest/
mir_opt.rs

1use std::fs;
2
3use camino::{Utf8Path, Utf8PathBuf};
4use glob::glob;
5use miropt_test_tools::{MiroptTest, MiroptTestFile, files_for_miropt_test};
6use tracing::debug;
7
8use super::{Emit, TestCx, WillExecute};
9use crate::runtest::compute_diff::write_diff;
10
11impl TestCx<'_> {
12    pub(super) fn run_mir_opt_test(&self) {
13        let mut test_info = files_for_miropt_test(
14            &self.testpaths.file.as_std_path(),
15            self.config.get_pointer_width(),
16            self.config.target_cfg().panic.for_miropt_test_tools(),
17        );
18
19        let passes = std::mem::take(&mut test_info.passes);
20
21        let proc_res = self.compile_test_general(WillExecute::No, Emit::Mir, passes);
22        if !proc_res.status.success() {
23            self.fatal_proc_rec("compilation failed!", &proc_res);
24        }
25        self.check_mir_dump(test_info);
26    }
27
28    fn check_mir_dump(&self, test_info: MiroptTest) {
29        let test_dir = self.testpaths.file.parent().unwrap();
30        let test_crate = self.testpaths.file.file_stem().unwrap().replace('-', "_");
31
32        let MiroptTest { suffix, files, passes: _ } = test_info;
33
34        if self.config.bless {
35            for e in glob(&format!("{}/{}.*{}.mir", test_dir, test_crate, suffix)).unwrap() {
36                fs::remove_file(e.unwrap()).unwrap();
37            }
38            for e in glob(&format!("{}/{}.*{}.diff", test_dir, test_crate, suffix)).unwrap() {
39                fs::remove_file(e.unwrap()).unwrap();
40            }
41        }
42
43        for MiroptTestFile { from_file, to_file, expected_file } in files {
44            let dumped_string = if let Some(after) = to_file {
45                self.diff_mir_files(from_file.into(), after.into())
46            } else {
47                let mut output_file = Utf8PathBuf::new();
48                output_file.push(self.output_base_dir());
49                output_file.push(&from_file);
50                debug!("comparing the contents of: {} with {:?}", output_file, expected_file);
51                if !output_file.exists() {
52                    panic!(
53                        "Output file `{}` from test does not exist, available files are in `{}`",
54                        output_file,
55                        output_file.parent().unwrap()
56                    );
57                }
58                self.check_mir_test_timestamp(&from_file, &output_file);
59                let dumped_string = fs::read_to_string(&output_file).unwrap();
60                self.normalize_output(&dumped_string, &[])
61            };
62
63            if self.config.bless {
64                let _ = fs::remove_file(&expected_file);
65                fs::write(expected_file, dumped_string.as_bytes()).unwrap();
66            } else {
67                if !expected_file.exists() {
68                    panic!("Output file `{}` from test does not exist", expected_file.display());
69                }
70                let expected_string = fs::read_to_string(&expected_file).unwrap();
71                if dumped_string != expected_string {
72                    write!(self.stdout, "{}", write_diff(&expected_string, &dumped_string, 3));
73                    panic!(
74                        "Actual MIR output differs from expected MIR output {}",
75                        expected_file.display()
76                    );
77                }
78            }
79        }
80
81        if !self.props.skip_filecheck {
82            let output_path = self.output_base_name().with_extension("mir");
83            let proc_res = self.verify_with_filecheck(&output_path);
84            if !proc_res.status.success() {
85                self.fatal_proc_rec("verification with 'FileCheck' failed", &proc_res);
86            }
87        }
88    }
89
90    fn diff_mir_files(&self, before: Utf8PathBuf, after: Utf8PathBuf) -> String {
91        let to_full_path = |path: Utf8PathBuf| {
92            let full = self.output_base_dir().join(&path);
93            if !full.exists() {
94                panic!(
95                    "the mir dump file for {} does not exist (requested in {})",
96                    path, self.testpaths.file,
97                );
98            }
99            full
100        };
101        let before = to_full_path(before);
102        let after = to_full_path(after);
103        debug!("comparing the contents of: {} with {}", before, after);
104        let before = fs::read_to_string(before).unwrap();
105        let after = fs::read_to_string(after).unwrap();
106        let before = self.normalize_output(&before, &[]);
107        let after = self.normalize_output(&after, &[]);
108        let mut dumped_string = String::new();
109        for result in diff::lines(&before, &after) {
110            use std::fmt::Write;
111            match result {
112                diff::Result::Left(s) => writeln!(dumped_string, "- {}", s).unwrap(),
113                diff::Result::Right(s) => writeln!(dumped_string, "+ {}", s).unwrap(),
114                diff::Result::Both(s, _) => writeln!(dumped_string, "  {}", s).unwrap(),
115            }
116        }
117        dumped_string
118    }
119
120    fn check_mir_test_timestamp(&self, test_name: &str, output_file: &Utf8Path) {
121        let t = |file: &Utf8Path| fs::metadata(file.as_std_path()).unwrap().modified().unwrap();
122        let source_file = &self.testpaths.file;
123        let output_time = t(output_file);
124        let source_time = t(source_file);
125        if source_time > output_time {
126            debug!("source file time: {:?} output file time: {:?}", source_time, output_time);
127            panic!(
128                "test source file `{}` is newer than potentially stale output file `{}`.",
129                source_file, test_name
130            );
131        }
132    }
133}