use anyhow::{anyhow, Result};
use core::fmt::Formatter;
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::{FuncType, FuncValidator, FunctionBody, ValidatorResources};
use crate::FuncEnv;
#[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,
}
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: &FuncType,
body: &FunctionBody,
env: &dyn FuncEnv,
validator: FuncValidator<ValidatorResources>,
) -> Result<MachBufferFinalized<Final>>;
fn call_conv(&self) -> CallConv {
CallConv::triple_default(&self.triple())
}
fn endianness(&self) -> target_lexicon::Endianness {
self.triple().endianness().unwrap()
}
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;
}
impl Debug for &dyn TargetIsa {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"Target ISA {{ triple: {:?}, calling convention: {:?} }}",
self.triple(),
self.call_conv()
)
}
}