use crate::BuiltinFunctions;
use anyhow::{anyhow, Result};
use core::fmt::Formatter;
use cranelift_codegen::isa::unwind::{UnwindInfo, UnwindInfoKind};
use cranelift_codegen::isa::{CallConv, IsaBuilder};
use cranelift_codegen::settings;
use cranelift_codegen::{Final, MachBufferFinalized, TextSectionBuilder};
use std::{
error,
fmt::{self, Debug, Display},
};
use target_lexicon::{Architecture, Triple};
use wasmparser::{FuncValidator, FunctionBody, ValidatorResources};
use wasmtime_cranelift::CompiledFunction;
use wasmtime_environ::{ModuleTranslation, ModuleTypesBuilder, WasmFuncType};
#[cfg(feature = "x64")]
pub(crate) mod x64;
#[cfg(feature = "arm64")]
pub(crate) mod aarch64;
pub(crate) mod reg;
macro_rules! isa_builder {
($name: ident, $cfg_terms: tt, $triple: ident) => {{
#[cfg $cfg_terms]
{
Ok($name::isa_builder($triple))
}
#[cfg(not $cfg_terms)]
{
Err(anyhow!(LookupError::SupportDisabled))
}
}};
}
pub type Builder = IsaBuilder<Result<Box<dyn TargetIsa>>>;
pub fn lookup(triple: Triple) -> Result<Builder> {
match triple.architecture {
Architecture::X86_64 => {
isa_builder!(x64, (feature = "x64"), triple)
}
Architecture::Aarch64 { .. } => {
isa_builder!(aarch64, (feature = "arm64"), triple)
}
_ => Err(anyhow!(LookupError::Unsupported)),
}
}
impl error::Error for LookupError {}
impl Display for LookupError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
LookupError::Unsupported => write!(f, "This target is not supported yet"),
LookupError::SupportDisabled => write!(f, "Support for this target was disabled"),
}
}
}
#[derive(Debug)]
pub(crate) enum LookupError {
Unsupported,
#[allow(dead_code)]
SupportDisabled,
}
#[derive(Copy, Clone, Debug)]
pub enum CallingConvention {
SystemV,
WindowsFastcall,
AppleAarch64,
Default,
}
impl CallingConvention {
fn is_fastcall(&self) -> bool {
match &self {
CallingConvention::WindowsFastcall => true,
_ => false,
}
}
fn is_systemv(&self) -> bool {
match &self {
CallingConvention::SystemV => true,
_ => false,
}
}
fn is_apple_aarch64(&self) -> bool {
match &self {
CallingConvention::AppleAarch64 => true,
_ => false,
}
}
pub fn is_default(&self) -> bool {
match &self {
CallingConvention::Default => true,
_ => false,
}
}
}
pub trait TargetIsa: Send + Sync {
fn name(&self) -> &'static str;
fn triple(&self) -> &Triple;
fn flags(&self) -> &settings::Flags;
fn isa_flags(&self) -> Vec<settings::Value>;
fn is_branch_protection_enabled(&self) -> bool {
false
}
fn compile_function(
&self,
sig: &WasmFuncType,
body: &FunctionBody,
translation: &ModuleTranslation,
types: &ModuleTypesBuilder,
builtins: &mut BuiltinFunctions,
validator: &mut FuncValidator<ValidatorResources>,
) -> Result<CompiledFunction>;
fn default_call_conv(&self) -> CallConv {
CallConv::triple_default(&self.triple())
}
fn wasmtime_call_conv(&self) -> CallingConvention {
match self.default_call_conv() {
CallConv::AppleAarch64 => CallingConvention::AppleAarch64,
CallConv::SystemV => CallingConvention::SystemV,
CallConv::WindowsFastcall => CallingConvention::WindowsFastcall,
cc => unimplemented!("calling convention: {:?}", cc),
}
}
fn endianness(&self) -> target_lexicon::Endianness {
self.triple().endianness().unwrap()
}
fn emit_unwind_info(
&self,
_result: &MachBufferFinalized<Final>,
_kind: UnwindInfoKind,
) -> Result<Option<UnwindInfo>>;
fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
None
}
fn text_section_builder(&self, num_labeled_funcs: usize) -> Box<dyn TextSectionBuilder>;
fn function_alignment(&self) -> u32;
fn pointer_bytes(&self) -> u8 {
let width = self.triple().pointer_width().unwrap();
width.bytes()
}
}
impl Debug for &dyn TargetIsa {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"Target ISA {{ triple: {:?}, calling convention: {:?} }}",
self.triple(),
self.default_call_conv()
)
}
}