wasmtime_cranelift/
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(triple: Option<Triple>, lookup: fn(Triple) -> Result<Builder<T>>) -> Result<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 triple_specified = triple.is_some();
32        let triple = triple.unwrap_or_else(Triple::host);
33        let mut isa_flags = lookup(triple)?;
34        if !triple_specified {
35            cranelift_native::infer_native_flags(&mut isa_flags).unwrap();
36        }
37
38        Ok(Self {
39            shared_flags: flags,
40            inner: isa_flags,
41            lookup,
42        })
43    }
44
45    pub fn triple(&self) -> &target_lexicon::Triple {
46        self.inner.triple()
47    }
48
49    pub fn target(&mut self, target: target_lexicon::Triple) -> Result<()> {
50        self.inner = (self.lookup)(target)?;
51        Ok(())
52    }
53
54    pub fn settings(&self) -> Vec<Setting> {
55        self.inner
56            .iter()
57            .map(|s| Setting {
58                description: s.description,
59                name: s.name,
60                values: s.values,
61                kind: match s.kind {
62                    settings::SettingKind::Preset => SettingKind::Preset,
63                    settings::SettingKind::Enum => SettingKind::Enum,
64                    settings::SettingKind::Num => SettingKind::Num,
65                    settings::SettingKind::Bool => SettingKind::Bool,
66                },
67            })
68            .collect()
69    }
70
71    pub fn set(&mut self, name: &str, value: &str) -> Result<()> {
72        if let Err(err) = self.shared_flags.set(name, value) {
73            match err {
74                SetError::BadName(_) => {
75                    self.inner.set(name, value)?;
76                }
77                _ => return Err(err.into()),
78            }
79        }
80        Ok(())
81    }
82
83    pub fn enable(&mut self, name: &str) -> Result<()> {
84        if let Err(err) = self.shared_flags.enable(name) {
85            match err {
86                SetError::BadName(_) => {
87                    // Try the target-specific flags.
88                    self.inner.enable(name)?;
89                }
90                _ => return Err(err.into()),
91            }
92        }
93        Ok(())
94    }
95
96    pub fn build(&self) -> T {
97        self.inner
98            .finish(settings::Flags::new(self.shared_flags.clone()))
99    }
100
101    pub fn shared_flags(&self) -> Flags {
102        settings::Flags::new(self.shared_flags.clone())
103    }
104}