1use crate::BuiltinFunctions;
2use anyhow::{anyhow, Result};
3use core::fmt::Formatter;
4use cranelift_codegen::isa::unwind::{UnwindInfo, UnwindInfoKind};
5use cranelift_codegen::isa::{CallConv, IsaBuilder};
6use cranelift_codegen::settings;
7use cranelift_codegen::{Final, MachBufferFinalized, TextSectionBuilder};
8use std::{
9 error,
10 fmt::{self, Debug, Display},
11};
12use target_lexicon::{Architecture, Triple};
13use wasmparser::{FuncValidator, FunctionBody, ValidatorResources};
14use wasmtime_cranelift::CompiledFunction;
15use wasmtime_environ::{ModuleTranslation, ModuleTypesBuilder, WasmFuncType};
16
17#[cfg(feature = "x64")]
18pub(crate) mod x64;
19
20#[cfg(feature = "arm64")]
21pub(crate) mod aarch64;
22
23pub(crate) mod reg;
24
25macro_rules! isa_builder {
26 ($name: ident, $cfg_terms: tt, $triple: ident) => {{
27 #[cfg $cfg_terms]
28 {
29 Ok($name::isa_builder($triple))
30 }
31 #[cfg(not $cfg_terms)]
32 {
33 Err(anyhow!(LookupError::SupportDisabled))
34 }
35 }};
36}
37
38pub type Builder = IsaBuilder<Result<Box<dyn TargetIsa>>>;
39
40pub fn lookup(triple: Triple) -> Result<Builder> {
42 match triple.architecture {
43 Architecture::X86_64 => {
44 isa_builder!(x64, (feature = "x64"), triple)
45 }
46 Architecture::Aarch64 { .. } => {
47 isa_builder!(aarch64, (feature = "arm64"), triple)
48 }
49
50 _ => Err(anyhow!(LookupError::Unsupported)),
51 }
52}
53
54impl error::Error for LookupError {}
55impl Display for LookupError {
56 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
57 match self {
58 LookupError::Unsupported => write!(f, "This target is not supported yet"),
59 LookupError::SupportDisabled => write!(f, "Support for this target was disabled"),
60 }
61 }
62}
63
64#[derive(Debug)]
65pub(crate) enum LookupError {
66 Unsupported,
67 #[allow(dead_code)]
72 SupportDisabled,
73}
74
75#[derive(Copy, Clone, Debug)]
90pub enum CallingConvention {
91 SystemV,
93 WindowsFastcall,
95 AppleAarch64,
97 Default,
101}
102
103impl CallingConvention {
104 fn is_fastcall(&self) -> bool {
106 match &self {
107 CallingConvention::WindowsFastcall => true,
108 _ => false,
109 }
110 }
111
112 fn is_systemv(&self) -> bool {
114 match &self {
115 CallingConvention::SystemV => true,
116 _ => false,
117 }
118 }
119
120 fn is_apple_aarch64(&self) -> bool {
122 match &self {
123 CallingConvention::AppleAarch64 => true,
124 _ => false,
125 }
126 }
127
128 pub fn is_default(&self) -> bool {
130 match &self {
131 CallingConvention::Default => true,
132 _ => false,
133 }
134 }
135}
136
137pub trait TargetIsa: Send + Sync {
140 fn name(&self) -> &'static str;
142
143 fn triple(&self) -> &Triple;
145
146 fn flags(&self) -> &settings::Flags;
148
149 fn isa_flags(&self) -> Vec<settings::Value>;
151
152 fn is_branch_protection_enabled(&self) -> bool {
154 false
155 }
156
157 fn compile_function(
159 &self,
160 sig: &WasmFuncType,
161 body: &FunctionBody,
162 translation: &ModuleTranslation,
163 types: &ModuleTypesBuilder,
164 builtins: &mut BuiltinFunctions,
165 validator: &mut FuncValidator<ValidatorResources>,
166 ) -> Result<CompiledFunction>;
167
168 fn default_call_conv(&self) -> CallConv {
170 CallConv::triple_default(&self.triple())
171 }
172
173 fn wasmtime_call_conv(&self) -> CallingConvention {
176 match self.default_call_conv() {
177 CallConv::AppleAarch64 => CallingConvention::AppleAarch64,
178 CallConv::SystemV => CallingConvention::SystemV,
179 CallConv::WindowsFastcall => CallingConvention::WindowsFastcall,
180 cc => unimplemented!("calling convention: {:?}", cc),
181 }
182 }
183
184 fn endianness(&self) -> target_lexicon::Endianness {
186 self.triple().endianness().unwrap()
187 }
188
189 fn emit_unwind_info(
190 &self,
191 _result: &MachBufferFinalized<Final>,
192 _kind: UnwindInfoKind,
193 ) -> Result<Option<UnwindInfo>>;
194
195 fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
197 None
199 }
200
201 fn text_section_builder(&self, num_labeled_funcs: usize) -> Box<dyn TextSectionBuilder>;
203
204 fn function_alignment(&self) -> u32;
206
207 fn pointer_bytes(&self) -> u8 {
209 let width = self.triple().pointer_width().unwrap();
210 width.bytes()
211 }
212}
213
214impl Debug for &dyn TargetIsa {
215 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
216 write!(
217 f,
218 "Target ISA {{ triple: {:?}, calling convention: {:?} }}",
219 self.triple(),
220 self.default_call_conv()
221 )
222 }
223}