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