wasmtime_cranelift_shared/
isa_builder.rs

1use anyhow::Result;
2use cranelift_codegen::isa::IsaBuilder as Builder;
3use cranelift_codegen::settings::{self, Configurable, Flags, SetError};
4use target_lexicon::Triple;
5use wasmtime_environ::{Setting, SettingKind};
6
7/// A helper to build an Isa for a compiler implementation.
8/// Compiler builders can wrap this to provide better flexibility when setting flags.
9///
10/// Most methods are mirrored from the `wasmtime_environ::CompilerBuilder` trait, so look there for more
11/// information.
12pub struct IsaBuilder<T> {
13    /// The shared flags that all targets share.
14    shared_flags: settings::Builder,
15    /// The internal ISA builder for the current target.
16    inner: Builder<T>,
17    /// A callback to lookup a new ISA builder for a target.
18    pub lookup: fn(Triple) -> Result<Builder<T>>,
19}
20
21impl<T> IsaBuilder<T> {
22    /// Create a new ISA builder with the given lookup function.
23    pub fn new(lookup: fn(Triple) -> Result<Builder<T>>) -> Self {
24        let mut flags = settings::builder();
25
26        // We don't use probestack as a stack limit mechanism
27        flags
28            .set("enable_probestack", "false")
29            .expect("should be valid flag");
30
31        let mut isa_flags = lookup(Triple::host()).expect("host machine is not a supported target");
32        cranelift_native::infer_native_flags(&mut isa_flags).unwrap();
33
34        Self {
35            shared_flags: flags,
36            inner: isa_flags,
37            lookup,
38        }
39    }
40
41    pub fn triple(&self) -> &target_lexicon::Triple {
42        self.inner.triple()
43    }
44
45    pub fn target(&mut self, target: target_lexicon::Triple) -> Result<()> {
46        self.inner = (self.lookup)(target)?;
47        Ok(())
48    }
49
50    pub fn settings(&self) -> Vec<Setting> {
51        self.inner
52            .iter()
53            .map(|s| Setting {
54                description: s.description,
55                name: s.name,
56                values: s.values,
57                kind: match s.kind {
58                    settings::SettingKind::Preset => SettingKind::Preset,
59                    settings::SettingKind::Enum => SettingKind::Enum,
60                    settings::SettingKind::Num => SettingKind::Num,
61                    settings::SettingKind::Bool => SettingKind::Bool,
62                },
63            })
64            .collect()
65    }
66
67    pub fn set(&mut self, name: &str, value: &str) -> Result<()> {
68        if let Err(err) = self.shared_flags.set(name, value) {
69            match err {
70                SetError::BadName(_) => {
71                    self.inner.set(name, value)?;
72                }
73                _ => return Err(err.into()),
74            }
75        }
76        Ok(())
77    }
78
79    pub fn enable(&mut self, name: &str) -> Result<()> {
80        if let Err(err) = self.shared_flags.enable(name) {
81            match err {
82                SetError::BadName(_) => {
83                    // Try the target-specific flags.
84                    self.inner.enable(name)?;
85                }
86                _ => return Err(err.into()),
87            }
88        }
89        Ok(())
90    }
91
92    pub fn build(&self) -> T {
93        self.inner
94            .finish(settings::Flags::new(self.shared_flags.clone()))
95    }
96
97    pub fn shared_flags(&self) -> Flags {
98        settings::Flags::new(self.shared_flags.clone())
99    }
100}