Skip to main content

cranelift_codegen_meta/
isle.rs

1use std::io::Result;
2
3/// A list of compilations (transformations from ISLE source to
4/// generated Rust source) that exist in the repository.
5///
6/// This list is used either to regenerate the Rust source in-tree (if
7/// the `rebuild-isle` feature is enabled), or to verify that the ISLE
8/// source in-tree corresponds to the ISLE source that was last used
9/// to rebuild the Rust source (if the `rebuild-isle` feature is not
10/// enabled).
11#[derive(Clone, Debug)]
12pub struct IsleCompilations {
13    pub items: Vec<IsleCompilation>,
14}
15
16impl IsleCompilations {
17    pub fn lookup(&self, name: &str) -> Option<&IsleCompilation> {
18        for compilation in &self.items {
19            if compilation.name == name {
20                return Some(compilation);
21            }
22        }
23        None
24    }
25}
26
27#[derive(Clone, Debug)]
28pub struct IsleCompilation {
29    pub name: String,
30    pub output: std::path::PathBuf,
31    pub tracked_inputs: Vec<std::path::PathBuf>,
32    pub untracked_inputs: Vec<std::path::PathBuf>,
33}
34
35impl IsleCompilation {
36    /// All inputs to the computation, tracked or untracked. May contain directories.
37    pub fn inputs(&self) -> Vec<std::path::PathBuf> {
38        self.tracked_inputs
39            .iter()
40            .chain(self.untracked_inputs.iter())
41            .cloned()
42            .collect()
43    }
44
45    /// All path inputs to the compilation. Directory inputs are expanded to the
46    /// list of all ISLE files in the directory.
47    pub fn paths(&self) -> Result<Vec<std::path::PathBuf>> {
48        let mut paths = Vec::new();
49        for input in self.inputs() {
50            paths.extend(Self::expand_paths(&input)?);
51        }
52        Ok(paths)
53    }
54
55    fn expand_paths(input: &std::path::PathBuf) -> Result<Vec<std::path::PathBuf>> {
56        if input.is_file() {
57            return Ok(vec![input.clone()]);
58        }
59
60        if !input.exists() {
61            return Err(std::io::Error::new(
62                std::io::ErrorKind::NotFound,
63                format!("ISLE input does not exist: {}", input.display()),
64            ));
65        }
66
67        let mut paths = Vec::new();
68        for entry in std::fs::read_dir(input).map_err(|e| {
69            std::io::Error::new(
70                e.kind(),
71                format!(
72                    "failed to read ISLE input directory {}: {e}",
73                    input.display()
74                ),
75            )
76        })? {
77            let path = entry?.path();
78            if let Some(ext) = path.extension() {
79                if ext == "isle" {
80                    paths.push(path);
81                }
82            }
83        }
84        Ok(paths)
85    }
86}
87
88pub fn shared_isle_lower_paths(codegen_crate_dir: &std::path::Path) -> Vec<std::path::PathBuf> {
89    let inst_specs_isle = codegen_crate_dir.join("src").join("inst_specs.isle");
90    let prelude_isle = codegen_crate_dir.join("src").join("prelude.isle");
91    let prelude_lower_isle = codegen_crate_dir.join("src").join("prelude_lower.isle");
92    // The shared instruction selector logic.
93    vec![
94        inst_specs_isle.clone(),
95        prelude_isle.clone(),
96        prelude_lower_isle.clone(),
97    ]
98}
99
100/// Construct the list of compilations (transformations from ISLE
101/// source to generated Rust source) that exist in the repository.
102pub fn get_isle_compilations(
103    codegen_crate_dir: &std::path::Path,
104    gen_dir: &std::path::Path,
105) -> IsleCompilations {
106    // Preludes.
107    let numerics_isle = gen_dir.join("numerics.isle");
108    let clif_lower_isle = gen_dir.join("clif_lower.isle");
109    let clif_opt_isle = gen_dir.join("clif_opt.isle");
110    let prelude_isle = codegen_crate_dir.join("src").join("prelude.isle");
111    let prelude_opt_isle = codegen_crate_dir.join("src").join("prelude_opt.isle");
112    let prelude_lower_isle = codegen_crate_dir.join("src").join("prelude_lower.isle");
113    #[cfg(feature = "pulley")]
114    let pulley_gen = gen_dir.join("pulley_gen.isle");
115
116    // Verification spec source files. These define the instruction
117    // semantics consumed by the ISLE verifier and are only needed
118    // when building the verifier tooling (the `spec` feature). They
119    // are excluded from normal codegen builds.
120    let spec_inputs = |extra: &[&str]| -> Vec<std::path::PathBuf> {
121        if !cfg!(feature = "spec") {
122            return vec![];
123        }
124        let spec_dir = codegen_crate_dir.join("src").join("spec");
125        let mut inputs = vec![
126            spec_dir.join("prelude_spec.isle"),
127            spec_dir.join("inst_specs.isle"),
128            spec_dir.join("inst_tags.isle"),
129        ];
130        inputs.extend(extra.iter().map(|f| spec_dir.join(f)));
131        inputs
132    };
133
134    // Directory for mid-end optimizations.
135    let src_opts = codegen_crate_dir.join("src").join("opts");
136
137    // Directories for lowering backends.
138    let src_isa_x64 = codegen_crate_dir.join("src").join("isa").join("x64");
139    let src_isa_aarch64 = codegen_crate_dir.join("src").join("isa").join("aarch64");
140    let src_isa_s390x = codegen_crate_dir.join("src").join("isa").join("s390x");
141    let src_isa_risc_v = codegen_crate_dir.join("src").join("isa").join("riscv64");
142    #[cfg(feature = "pulley")]
143    let src_isa_pulley_shared = codegen_crate_dir
144        .join("src")
145        .join("isa")
146        .join("pulley_shared");
147
148    // This is a set of ISLE compilation units.
149    //
150    // The format of each entry is:
151    //
152    //     (output Rust code file, input ISLE source files)
153    //
154    // There should be one entry for each backend that uses ISLE for lowering,
155    // and if/when we replace our peephole optimization passes with ISLE, there
156    // should be an entry for each of those as well.
157    //
158    // N.B.: add any new compilation outputs to
159    // `scripts/force-rebuild-isle.sh` if they do not fit the pattern
160    // `cranelift/codegen/src/isa/*/lower/isle/generated_code.rs`!
161    IsleCompilations {
162        items: vec![
163            // The mid-end optimization rules.
164            IsleCompilation {
165                name: "opt".to_string(),
166                output: gen_dir.join("isle_opt.rs"),
167                tracked_inputs: [
168                    vec![prelude_isle.clone(), prelude_opt_isle],
169                    spec_inputs(&[]),
170                    vec![
171                        src_opts.join("arithmetic.isle"),
172                        src_opts.join("bitops.isle"),
173                        src_opts.join("cprop.isle"),
174                        src_opts.join("extends.isle"),
175                        src_opts.join("icmp.isle"),
176                        src_opts.join("remat.isle"),
177                        src_opts.join("selects.isle"),
178                        src_opts.join("shifts.isle"),
179                        src_opts.join("skeleton.isle"),
180                        src_opts.join("spaceship.isle"),
181                        src_opts.join("spectre.isle"),
182                        src_opts.join("vector.isle"),
183                    ],
184                ]
185                .concat(),
186                untracked_inputs: vec![numerics_isle.clone(), clif_opt_isle],
187            },
188            // The x86-64 instruction selector.
189            IsleCompilation {
190                name: "x64".to_string(),
191                output: gen_dir.join("isle_x64.rs"),
192                tracked_inputs: [
193                    vec![prelude_isle.clone(), prelude_lower_isle.clone()],
194                    spec_inputs(&["state.isle"]),
195                    vec![
196                        src_isa_x64.join("inst.isle"),
197                        src_isa_x64.join("lower.isle"),
198                    ],
199                ]
200                .concat(),
201                untracked_inputs: vec![
202                    numerics_isle.clone(),
203                    clif_lower_isle.clone(),
204                    gen_dir.join("assembler.isle"),
205                ],
206            },
207            // The aarch64 instruction selector.
208            IsleCompilation {
209                name: "aarch64".to_string(),
210                output: gen_dir.join("isle_aarch64.rs"),
211                tracked_inputs: [
212                    vec![prelude_isle.clone(), prelude_lower_isle.clone()],
213                    spec_inputs(&["fpconst.isle", "state.isle"]),
214                    vec![
215                        src_isa_aarch64.join("inst.isle"),
216                        src_isa_aarch64.join("inst_neon.isle"),
217                    ],
218                    // The aarch64-specific spec directory is also verification-only.
219                    if cfg!(feature = "spec") {
220                        vec![src_isa_aarch64.join("spec")]
221                    } else {
222                        vec![]
223                    },
224                    vec![
225                        src_isa_aarch64.join("lower.isle"),
226                        src_isa_aarch64.join("lower_dynamic_neon.isle"),
227                    ],
228                ]
229                .concat(),
230                untracked_inputs: vec![numerics_isle.clone(), clif_lower_isle.clone()],
231            },
232            // The s390x instruction selector.
233            IsleCompilation {
234                name: "s390x".to_string(),
235                output: gen_dir.join("isle_s390x.rs"),
236                tracked_inputs: [
237                    vec![prelude_isle.clone(), prelude_lower_isle.clone()],
238                    spec_inputs(&[]),
239                    vec![
240                        src_isa_s390x.join("inst.isle"),
241                        src_isa_s390x.join("lower.isle"),
242                    ],
243                ]
244                .concat(),
245                untracked_inputs: vec![numerics_isle.clone(), clif_lower_isle.clone()],
246            },
247            // The risc-v instruction selector.
248            IsleCompilation {
249                name: "riscv64".to_string(),
250                output: gen_dir.join("isle_riscv64.rs"),
251                tracked_inputs: [
252                    vec![prelude_isle.clone(), prelude_lower_isle.clone()],
253                    spec_inputs(&[]),
254                    vec![
255                        src_isa_risc_v.join("inst.isle"),
256                        src_isa_risc_v.join("inst_vector.isle"),
257                        src_isa_risc_v.join("lower.isle"),
258                    ],
259                ]
260                .concat(),
261                untracked_inputs: vec![numerics_isle.clone(), clif_lower_isle.clone()],
262            },
263            // The Pulley instruction selector.
264            #[cfg(feature = "pulley")]
265            IsleCompilation {
266                name: "pulley".to_string(),
267                output: gen_dir.join("isle_pulley_shared.rs"),
268                tracked_inputs: vec![
269                    prelude_isle.clone(),
270                    prelude_lower_isle.clone(),
271                    src_isa_pulley_shared.join("inst.isle"),
272                    src_isa_pulley_shared.join("lower.isle"),
273                ],
274                untracked_inputs: vec![
275                    numerics_isle.clone(),
276                    pulley_gen.clone(),
277                    clif_lower_isle.clone(),
278                ],
279            },
280        ],
281    }
282}