1 use anyhow::{anyhow, Result}; 2 use core::fmt::Formatter; 3 use cranelift_codegen::isa::{CallConv, IsaBuilder}; 4 use cranelift_codegen::settings; 5 use cranelift_codegen::{Final, MachBufferFinalized, TextSectionBuilder}; 6 use std::{ 7 error, 8 fmt::{self, Debug, Display}, 9 }; 10 use target_lexicon::{Architecture, Triple}; 11 use wasmparser::{FuncType, FuncValidator, FunctionBody, ValidatorResources}; 12 13 #[cfg(feature = "x64")] 14 pub(crate) mod x64; 15 16 #[cfg(feature = "arm64")] 17 pub(crate) mod aarch64; 18 19 pub(crate) mod reg; 20 21 macro_rules! isa_builder { 22 ($name: ident, $cfg_terms: tt, $triple: ident) => {{ 23 #[cfg $cfg_terms] 24 { 25 Ok($name::isa_builder($triple)) 26 } 27 #[cfg(not $cfg_terms)] 28 { 29 Err(anyhow!(LookupError::SupportDisabled)) 30 } 31 }}; 32 } 33 34 pub type Builder = IsaBuilder<Result<Box<dyn TargetIsa>>>; 35 36 /// Look for an ISA builder for the given target triple. 37 pub fn lookup(triple: Triple) -> Result<Builder> { 38 match triple.architecture { 39 Architecture::X86_64 => { 40 isa_builder!(x64, (feature = "x64"), triple) 41 } 42 Architecture::Aarch64 { .. } => { 43 isa_builder!(aarch64, (feature = "arm64"), triple) 44 } 45 46 _ => Err(anyhow!(LookupError::Unsupported)), 47 } 48 } 49 50 impl error::Error for LookupError {} 51 impl Display for LookupError { 52 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 53 match self { 54 LookupError::Unsupported => write!(f, "This target is not supported yet"), 55 LookupError::SupportDisabled => write!(f, "Support for this target was disabled"), 56 } 57 } 58 } 59 60 #[derive(Debug)] 61 pub(crate) enum LookupError { 62 Unsupported, 63 // This directive covers the case in which the consumer 64 // enables the `all-arch` feature; in such case, this variant 65 // will never be used. This is most likely going to change 66 // in the future; this is one of the simplest options for now. 67 #[allow(dead_code)] 68 SupportDisabled, 69 } 70 71 /// A trait representing commonalities between the supported 72 /// instruction set architectures. 73 pub trait TargetIsa: Send + Sync { 74 /// Get the name of the ISA. 75 fn name(&self) -> &'static str; 76 77 /// Get the target triple of the ISA. 78 fn triple(&self) -> &Triple; 79 80 /// Get the ISA-independent flags that were used to make this trait object. 81 fn flags(&self) -> &settings::Flags; 82 83 /// Get the ISA-dependent flag values that were used to make this trait object. 84 fn isa_flags(&self) -> Vec<settings::Value>; 85 86 /// Get a flag indicating whether branch protection is enabled. 87 fn is_branch_protection_enabled(&self) -> bool { 88 false 89 } 90 91 fn compile_function( 92 &self, 93 sig: &FuncType, 94 body: &FunctionBody, 95 validator: FuncValidator<ValidatorResources>, 96 ) -> Result<MachBufferFinalized<Final>>; 97 98 /// Get the default calling convention of the underlying target triple. 99 fn call_conv(&self) -> CallConv { 100 CallConv::triple_default(&self.triple()) 101 } 102 103 /// Get the endianess of the underlying target triple. 104 fn endianness(&self) -> target_lexicon::Endianness { 105 self.triple().endianness().unwrap() 106 } 107 108 /// See `cranelift_codegen::isa::TargetIsa::create_systemv_cie`. 109 fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> { 110 // By default, an ISA cannot create a System V CIE. 111 None 112 } 113 114 /// See `cranelift_codegen::isa::TargetIsa::text_section_builder`. 115 fn text_section_builder(&self, num_labeled_funcs: usize) -> Box<dyn TextSectionBuilder>; 116 117 /// See `cranelift_codegen::isa::TargetIsa::function_alignment`. 118 fn function_alignment(&self) -> u32; 119 } 120 121 impl Debug for &dyn TargetIsa { 122 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 123 write!( 124 f, 125 "Target ISA {{ triple: {:?}, calling convention: {:?} }}", 126 self.triple(), 127 self.call_conv() 128 ) 129 } 130 } 131