xref: /wasmtime-44.0.1/winch/codegen/src/isa/mod.rs (revision 25bf8e0e)
1 use anyhow::{anyhow, Result};
2 use core::fmt::Formatter;
3 use cranelift_codegen::isa::CallConv;
4 use std::{
5     error,
6     fmt::{self, Debug, Display},
7 };
8 use target_lexicon::{Architecture, Triple};
9 use wasmparser::{FuncType, FuncValidator, FunctionBody, ValidatorResources};
10 
11 #[cfg(feature = "x64")]
12 pub(crate) mod x64;
13 
14 #[cfg(feature = "arm64")]
15 pub(crate) mod aarch64;
16 
17 pub(crate) mod reg;
18 
19 macro_rules! isa {
20     ($name: ident, $cfg_terms: tt, $triple: ident) => {{
21         #[cfg $cfg_terms]
22         {
23             Ok(Box::new($name::isa_from($triple)))
24         }
25         #[cfg(not $cfg_terms)]
26         {
27             Err(anyhow!(LookupError::SupportDisabled))
28         }
29     }};
30 }
31 
32 /// Look for an ISA for the given target triple.
33 //
34 // The ISA, as it's currently implemented in Cranelift
35 // needs a builder since it adds settings
36 // depending on those available in the host architecture.
37 // I'm intentionally skipping the builder for now.
38 // The lookup method will return the ISA directly.
39 //
40 // Once features like SIMD are supported, returning a builder
41 // will make more sense.
42 pub fn lookup(triple: Triple) -> Result<Box<dyn TargetIsa>> {
43     match triple.architecture {
44         Architecture::X86_64 => {
45             isa!(x64, (feature = "x64"), triple)
46         }
47         Architecture::Aarch64 { .. } => {
48             isa!(aarch64, (feature = "arm64"), triple)
49         }
50 
51         _ => Err(anyhow!(LookupError::Unsupported)),
52     }
53 }
54 
55 impl error::Error for LookupError {}
56 impl Display for LookupError {
57     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
58         match self {
59             LookupError::Unsupported => write!(f, "This target is not supported yet"),
60             LookupError::SupportDisabled => write!(f, "Support for this target was disabled"),
61         }
62     }
63 }
64 
65 #[derive(Debug)]
66 pub(crate) enum LookupError {
67     Unsupported,
68     // This directive covers the case in which the consumer
69     // enables the `all-arch` feature; in such case, this variant
70     // will never be used. This is most likely going to change
71     // in the future; this is one of the simplest options for now.
72     #[allow(dead_code)]
73     SupportDisabled,
74 }
75 
76 /// A trait representing commonalities between the supported
77 /// instruction set architectures.
78 pub trait TargetIsa: Send + Sync {
79     /// Get the name of the ISA.
80     fn name(&self) -> &'static str;
81 
82     /// Get the target triple of the ISA.
83     fn triple(&self) -> &Triple;
84 
85     fn compile_function(
86         &self,
87         sig: &FuncType,
88         body: &FunctionBody,
89         validator: FuncValidator<ValidatorResources>,
90     ) -> Result<Vec<String>>;
91 
92     /// Get the default calling convention of the underlying target triple.
93     fn call_conv(&self) -> CallConv {
94         CallConv::triple_default(&self.triple())
95     }
96 
97     /// Get the endianess of the underlying target triple.
98     fn endianness(&self) -> target_lexicon::Endianness {
99         self.triple().endianness().unwrap()
100     }
101 }
102 
103 impl Debug for &dyn TargetIsa {
104     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
105         write!(
106             f,
107             "Target ISA {{ triple: {:?}, calling convention: {:?} }}",
108             self.triple(),
109             self.call_conv()
110         )
111     }
112 }
113