xref: /wasmtime-44.0.1/winch/codegen/src/isa/mod.rs (revision 770c5d0f)
1 use crate::TrampolineKind;
2 use anyhow::{anyhow, Result};
3 use core::fmt::Formatter;
4 use cranelift_codegen::isa::{CallConv, IsaBuilder};
5 use cranelift_codegen::settings;
6 use cranelift_codegen::{Final, MachBufferFinalized, TextSectionBuilder};
7 use std::{
8     error,
9     fmt::{self, Debug, Display},
10 };
11 use target_lexicon::{Architecture, Triple};
12 use wasmparser::{FuncValidator, FunctionBody, ValidatorResources};
13 use wasmtime_environ::{ModuleTranslation, WasmFuncType};
14 
15 #[cfg(feature = "x64")]
16 pub(crate) mod x64;
17 
18 #[cfg(feature = "arm64")]
19 pub(crate) mod aarch64;
20 
21 pub(crate) mod reg;
22 
23 macro_rules! isa_builder {
24     ($name: ident, $cfg_terms: tt, $triple: ident) => {{
25         #[cfg $cfg_terms]
26         {
27             Ok($name::isa_builder($triple))
28         }
29         #[cfg(not $cfg_terms)]
30         {
31             Err(anyhow!(LookupError::SupportDisabled))
32         }
33     }};
34 }
35 
36 pub type Builder = IsaBuilder<Result<Box<dyn TargetIsa>>>;
37 
38 /// Look for an ISA builder for the given target triple.
39 pub fn lookup(triple: Triple) -> Result<Builder> {
40     match triple.architecture {
41         Architecture::X86_64 => {
42             isa_builder!(x64, (feature = "x64"), triple)
43         }
44         Architecture::Aarch64 { .. } => {
45             isa_builder!(aarch64, (feature = "arm64"), triple)
46         }
47 
48         _ => Err(anyhow!(LookupError::Unsupported)),
49     }
50 }
51 
52 impl error::Error for LookupError {}
53 impl Display for LookupError {
54     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
55         match self {
56             LookupError::Unsupported => write!(f, "This target is not supported yet"),
57             LookupError::SupportDisabled => write!(f, "Support for this target was disabled"),
58         }
59     }
60 }
61 
62 #[derive(Debug)]
63 pub(crate) enum LookupError {
64     Unsupported,
65     // This directive covers the case in which the consumer
66     // enables the `all-arch` feature; in such case, this variant
67     // will never be used. This is most likely going to change
68     // in the future; this is one of the simplest options for now.
69     #[allow(dead_code)]
70     SupportDisabled,
71 }
72 
73 /// Calling conventions supported by Winch. Winch supports the `Wasmtime*`
74 /// variations of the system's ABI calling conventions and an internal default
75 /// calling convention.
76 ///
77 /// This enum is a reduced subset of the calling conventions defined in
78 /// [cranelift_codegen::isa::CallConv]. Introducing this enum makes it easier
79 /// to enforce the invariant of all the calling conventions supported by Winch.
80 pub enum CallingConvention {
81     /// See [cranelift_codegen::isa::CallConv::WasmtimeSystemV]
82     WasmtimeSystemV,
83     /// See [cranelift_codegen::isa::CallConv::WindowsFastcall]
84     WindowsFastcall,
85     /// See [cranelift_codegen::isa::CallConv::AppleAarch64]
86     AppleAarch64,
87     /// The default calling convention for Winch. It largely follows SystemV
88     /// for parameter and result handling. This calling convention is part of
89     /// Winch's default ABI [crate::abi::ABI].
90     Default,
91 }
92 
93 impl CallingConvention {
94     /// Returns true if the current calling convention is `WasmtimeFastcall`.
95     fn is_fastcall(&self) -> bool {
96         match &self {
97             CallingConvention::WindowsFastcall => true,
98             _ => false,
99         }
100     }
101 
102     /// Returns true if the current calling convention is `WasmtimeSystemV`.
103     fn is_systemv(&self) -> bool {
104         match &self {
105             CallingConvention::WasmtimeSystemV => true,
106             _ => false,
107         }
108     }
109 
110     /// Returns true if the current calling convention is `WasmtimeAppleAarch64`.
111     fn is_apple_aarch64(&self) -> bool {
112         match &self {
113             CallingConvention::AppleAarch64 => true,
114             _ => false,
115         }
116     }
117 
118     /// Returns true if the current calling convention is `Default`.
119     fn is_default(&self) -> bool {
120         match &self {
121             CallingConvention::Default => true,
122             _ => false,
123         }
124     }
125 }
126 
127 /// A trait representing commonalities between the supported
128 /// instruction set architectures.
129 pub trait TargetIsa: Send + Sync {
130     /// Get the name of the ISA.
131     fn name(&self) -> &'static str;
132 
133     /// Get the target triple of the ISA.
134     fn triple(&self) -> &Triple;
135 
136     /// Get the ISA-independent flags that were used to make this trait object.
137     fn flags(&self) -> &settings::Flags;
138 
139     /// Get the ISA-dependent flag values that were used to make this trait object.
140     fn isa_flags(&self) -> Vec<settings::Value>;
141 
142     /// Get a flag indicating whether branch protection is enabled.
143     fn is_branch_protection_enabled(&self) -> bool {
144         false
145     }
146 
147     /// Compile a function.
148     fn compile_function(
149         &self,
150         sig: &WasmFuncType,
151         body: &FunctionBody,
152         translation: &ModuleTranslation,
153         validator: &mut FuncValidator<ValidatorResources>,
154     ) -> Result<MachBufferFinalized<Final>>;
155 
156     /// Get the default calling convention of the underlying target triple.
157     fn default_call_conv(&self) -> CallConv {
158         CallConv::triple_default(&self.triple())
159     }
160 
161     /// Derive Wasmtime's calling convention from the triple's default
162     /// calling convention.
163     fn wasmtime_call_conv(&self) -> CallingConvention {
164         match self.default_call_conv() {
165             CallConv::AppleAarch64 => CallingConvention::AppleAarch64,
166             CallConv::SystemV => CallingConvention::WasmtimeSystemV,
167             CallConv::WindowsFastcall => CallingConvention::WindowsFastcall,
168             cc => unimplemented!("calling convention: {:?}", cc),
169         }
170     }
171 
172     /// Get the endianess of the underlying target triple.
173     fn endianness(&self) -> target_lexicon::Endianness {
174         self.triple().endianness().unwrap()
175     }
176 
177     /// See `cranelift_codegen::isa::TargetIsa::create_systemv_cie`.
178     fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
179         // By default, an ISA cannot create a System V CIE.
180         None
181     }
182 
183     /// See `cranelift_codegen::isa::TargetIsa::text_section_builder`.
184     fn text_section_builder(&self, num_labeled_funcs: usize) -> Box<dyn TextSectionBuilder>;
185 
186     /// See `cranelift_codegen::isa::TargetIsa::function_alignment`.
187     fn function_alignment(&self) -> u32;
188 
189     /// Compile a trampoline kind.
190     ///
191     /// This function, internally dispatches to the right trampoline to emit
192     /// depending on the `kind` paramter.
193     fn compile_trampoline(
194         &self,
195         ty: &WasmFuncType,
196         kind: TrampolineKind,
197     ) -> Result<MachBufferFinalized<Final>>;
198 
199     /// Returns the pointer width of the ISA in bytes.
200     fn pointer_bytes(&self) -> u8 {
201         let width = self.triple().pointer_width().unwrap();
202         width.bytes()
203     }
204 }
205 
206 impl Debug for &dyn TargetIsa {
207     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
208         write!(
209             f,
210             "Target ISA {{ triple: {:?}, calling convention: {:?} }}",
211             self.triple(),
212             self.default_call_conv()
213         )
214     }
215 }
216