use crate::dominator_tree::DominatorTree;
pub use crate::isa::call_conv::CallConv;
use crate::CodegenResult;
use crate::ir::{self, Function, Type};
#[cfg(feature = "unwind")]
use crate::isa::unwind::{UnwindInfoKind, systemv::RegisterMappingError};
use crate::machinst::{CompiledCodeStencil, TextSectionBuilder};
use crate::settings;
use crate::settings::Configurable;
use crate::settings::SetResult;
use crate::{Reg, flowgraph};
use alloc::string::String;
use alloc::{boxed::Box, sync::Arc, vec::Vec};
use core::fmt;
use core::fmt::{Debug, Formatter};
use cranelift_control::ControlPlane;
use target_lexicon::{Architecture, PointerWidth, Triple, triple};
#[cfg(feature = "x86")]
pub mod x64;
#[cfg(feature = "arm64")]
pub mod aarch64;
#[cfg(feature = "riscv64")]
pub mod riscv64;
#[cfg(feature = "s390x")]
mod s390x;
#[cfg(feature = "pulley")]
mod pulley32;
#[cfg(feature = "pulley")]
mod pulley64;
#[cfg(feature = "pulley")]
mod pulley_shared;
pub mod unwind;
mod call_conv;
mod winch;
macro_rules! isa_builder {
($name: ident, $cfg_terms: tt, $triple: ident) => {{
#[cfg $cfg_terms]
{
Ok($name::isa_builder($triple))
}
#[cfg(not $cfg_terms)]
{
Err(LookupError::SupportDisabled)
}
}};
}
pub fn lookup(triple: Triple) -> Result<Builder, LookupError> {
match triple.architecture {
Architecture::X86_64 => {
isa_builder!(x64, (feature = "x86"), triple)
}
Architecture::Aarch64 { .. } => isa_builder!(aarch64, (feature = "arm64"), triple),
Architecture::S390x { .. } => isa_builder!(s390x, (feature = "s390x"), triple),
Architecture::Riscv64 { .. } => isa_builder!(riscv64, (feature = "riscv64"), triple),
Architecture::Pulley32 | Architecture::Pulley32be => {
isa_builder!(pulley32, (feature = "pulley"), triple)
}
Architecture::Pulley64 | Architecture::Pulley64be => {
isa_builder!(pulley64, (feature = "pulley"), triple)
}
_ => Err(LookupError::Unsupported),
}
}
pub const ALL_ARCHITECTURES: &[&str] = &["x86_64", "aarch64", "s390x", "riscv64"];
pub fn lookup_by_name(name: &str) -> Result<Builder, LookupError> {
lookup(triple!(name))
}
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum LookupError {
SupportDisabled,
Unsupported,
}
impl core::error::Error for LookupError {}
impl fmt::Display for LookupError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
LookupError::SupportDisabled => write!(f, "Support for this target is disabled"),
LookupError::Unsupported => {
write!(f, "Support for this target has not been implemented yet")
}
}
}
}
pub type OwnedTargetIsa = Arc<dyn TargetIsa>;
pub type Builder = IsaBuilder<CodegenResult<OwnedTargetIsa>>;
#[derive(Clone)]
pub struct IsaBuilder<T> {
triple: Triple,
setup: settings::Builder,
constructor: fn(Triple, settings::Flags, &settings::Builder) -> T,
}
impl<T> IsaBuilder<T> {
pub fn new(
triple: Triple,
setup: settings::Builder,
constructor: fn(Triple, settings::Flags, &settings::Builder) -> T,
) -> Self {
IsaBuilder {
triple,
setup,
constructor,
}
}
pub fn from_target_isa(target_isa: &dyn TargetIsa) -> Builder {
let triple = target_isa.triple().clone();
let mut builder = self::lookup(triple).expect("Could not find triple for target ISA");
for flag in target_isa.isa_flags() {
builder.set(&flag.name, &flag.value_string()).unwrap();
}
builder
}
pub fn triple(&self) -> &Triple {
&self.triple
}
pub fn iter(&self) -> impl Iterator<Item = settings::Setting> + use<T> {
self.setup.iter()
}
pub fn finish(&self, shared_flags: settings::Flags) -> T {
(self.constructor)(self.triple.clone(), shared_flags, &self.setup)
}
}
impl<T> settings::Configurable for IsaBuilder<T> {
fn set(&mut self, name: &str, value: &str) -> SetResult<()> {
self.setup.set(name, value)
}
fn enable(&mut self, name: &str) -> SetResult<()> {
self.setup.enable(name)
}
}
pub type Legalize =
fn(ir::Inst, &mut ir::Function, &mut flowgraph::ControlFlowGraph, &dyn TargetIsa) -> bool;
#[derive(Clone, Copy, Hash)]
pub struct TargetFrontendConfig {
pub default_call_conv: CallConv,
pub pointer_width: PointerWidth,
pub page_size_align_log2: u8,
}
impl TargetFrontendConfig {
pub fn pointer_type(self) -> ir::Type {
ir::Type::int(self.pointer_bits() as u16).unwrap()
}
pub fn pointer_bits(self) -> u8 {
self.pointer_width.bits()
}
pub fn pointer_bytes(self) -> u8 {
self.pointer_width.bytes()
}
}
pub trait TargetIsa: fmt::Display + Send + Sync {
fn name(&self) -> &'static str;
fn triple(&self) -> &Triple;
fn flags(&self) -> &settings::Flags;
fn isa_flags(&self) -> Vec<settings::Value>;
fn isa_flags_hash_key(&self) -> IsaFlagsHashKey<'_>;
fn is_branch_protection_enabled(&self) -> bool {
false
}
fn dynamic_vector_bytes(&self, dynamic_ty: ir::Type) -> u32;
fn compile_function(
&self,
func: &Function,
domtree: &DominatorTree,
want_disasm: bool,
ctrl_plane: &mut ControlPlane,
) -> CodegenResult<CompiledCodeStencil>;
#[cfg(feature = "unwind")]
fn map_regalloc_reg_to_dwarf(
&self,
_: crate::machinst::Reg,
) -> Result<u16, RegisterMappingError> {
Err(RegisterMappingError::UnsupportedArchitecture)
}
#[cfg(feature = "unwind")]
fn emit_unwind_info(
&self,
result: &crate::machinst::CompiledCode,
kind: UnwindInfoKind,
) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>>;
#[cfg(feature = "unwind")]
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) -> FunctionAlignment;
fn page_size_align_log2(&self) -> u8;
fn wrapped(self) -> OwnedTargetIsa
where
Self: Sized + 'static,
{
Arc::new(self)
}
#[cfg(feature = "disas")]
fn to_capstone(&self) -> Result<capstone::Capstone, capstone::Error> {
Err(capstone::Error::UnsupportedArch)
}
fn pretty_print_reg(&self, reg: Reg, size: u8) -> String;
fn has_native_fma(&self) -> bool;
fn has_round(&self) -> bool;
fn has_blendv_lowering(&self, ty: Type) -> bool;
fn has_x86_pshufb_lowering(&self) -> bool;
fn has_x86_pmulhrsw_lowering(&self) -> bool;
fn has_x86_pmaddubsw_lowering(&self) -> bool;
fn default_argument_extension(&self) -> ir::ArgumentExtension;
}
#[derive(Hash)]
pub struct IsaFlagsHashKey<'a>(&'a [u8]);
#[derive(Copy, Clone)]
pub struct FunctionAlignment {
pub minimum: u32,
pub preferred: u32,
}
impl<'a> dyn TargetIsa + 'a {
pub fn default_call_conv(&self) -> CallConv {
CallConv::triple_default(self.triple())
}
pub fn endianness(&self) -> ir::Endianness {
match self.triple().endianness().unwrap() {
target_lexicon::Endianness::Little => ir::Endianness::Little,
target_lexicon::Endianness::Big => ir::Endianness::Big,
}
}
pub fn symbol_alignment(&self) -> u64 {
match self.triple().architecture {
Architecture::S390x => 2,
_ => 1,
}
}
pub fn pointer_type(&self) -> ir::Type {
ir::Type::int(self.pointer_bits() as u16).unwrap()
}
pub(crate) fn pointer_width(&self) -> PointerWidth {
self.triple().pointer_width().unwrap()
}
pub fn pointer_bits(&self) -> u8 {
self.pointer_width().bits()
}
pub fn pointer_bytes(&self) -> u8 {
self.pointer_width().bytes()
}
pub fn frontend_config(&self) -> TargetFrontendConfig {
TargetFrontendConfig {
default_call_conv: self.default_call_conv(),
pointer_width: self.pointer_width(),
page_size_align_log2: self.page_size_align_log2(),
}
}
}
impl Debug for &dyn TargetIsa {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"TargetIsa {{ triple: {:?}, pointer_width: {:?}}}",
self.triple(),
self.pointer_width()
)
}
}