pub use crate::isa::call_conv::CallConv;
use crate::flowgraph;
use crate::ir::{self, Function};
#[cfg(feature = "unwind")]
use crate::isa::unwind::systemv::RegisterMappingError;
use crate::machinst::{CompiledCode, CompiledCodeStencil, TextSectionBuilder, UnwindInfoKind};
use crate::settings;
use crate::settings::SetResult;
use crate::CodegenResult;
use alloc::{boxed::Box, vec::Vec};
use core::fmt;
use core::fmt::{Debug, Formatter};
use target_lexicon::{triple, Architecture, OperatingSystem, PointerWidth, Triple};
#[cfg(feature = "x86")]
pub mod x64;
#[cfg(feature = "arm64")]
pub(crate) mod aarch64;
#[cfg(feature = "riscv64")]
pub mod riscv64;
#[cfg(feature = "s390x")]
mod s390x;
pub mod unwind;
mod call_conv;
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),
_ => Err(LookupError::Unsupported),
}
}
pub fn lookup_by_name(name: &str) -> Result<Builder, LookupError> {
use alloc::str::FromStr;
lookup(triple!(name))
}
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum LookupError {
SupportDisabled,
Unsupported,
}
impl std::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")
}
}
}
}
#[derive(Clone)]
pub struct Builder {
triple: Triple,
setup: settings::Builder,
constructor:
fn(Triple, settings::Flags, settings::Builder) -> CodegenResult<Box<dyn TargetIsa>>,
}
impl Builder {
pub fn triple(&self) -> &Triple {
&self.triple
}
pub fn iter(&self) -> impl Iterator<Item = settings::Setting> {
self.setup.iter()
}
pub fn finish(self, shared_flags: settings::Flags) -> CodegenResult<Box<dyn TargetIsa>> {
(self.constructor)(self.triple, shared_flags, self.setup)
}
}
impl settings::Configurable for Builder {
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,
}
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 is_branch_protection_enabled(&self) -> bool {
false
}
fn dynamic_vector_bytes(&self, dynamic_ty: ir::Type) -> u32;
fn compile_function(
&self,
func: &Function,
want_disasm: bool,
) -> CodegenResult<CompiledCodeStencil>;
#[cfg(feature = "unwind")]
fn map_regalloc_reg_to_dwarf(
&self,
_: crate::machinst::Reg,
) -> Result<u16, RegisterMappingError> {
Err(RegisterMappingError::UnsupportedArchitecture)
}
fn unsigned_add_overflow_condition(&self) -> ir::condcodes::IntCC;
#[cfg(feature = "unwind")]
fn emit_unwind_info(
&self,
result: &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: u32) -> Box<dyn TextSectionBuilder>;
fn function_alignment(&self) -> 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 code_section_alignment(&self) -> u64 {
use target_lexicon::*;
match (self.triple().operating_system, self.triple().architecture) {
(
OperatingSystem::MacOSX { .. }
| OperatingSystem::Darwin
| OperatingSystem::Ios
| OperatingSystem::Tvos,
Architecture::Aarch64(..),
) => 0x4000,
(_, Architecture::Aarch64(..)) => 0x10000,
_ => 0x1000,
}
}
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(),
}
}
pub(crate) fn unwind_info_kind(&self) -> UnwindInfoKind {
match self.triple().operating_system {
#[cfg(feature = "unwind")]
OperatingSystem::Windows => UnwindInfoKind::Windows,
#[cfg(feature = "unwind")]
_ => UnwindInfoKind::SystemV,
#[cfg(not(feature = "unwind"))]
_ => UnwindInfoKind::None,
}
}
}
impl Debug for &dyn TargetIsa {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"TargetIsa {{ triple: {:?}, pointer_width: {:?}}}",
self.triple(),
self.pointer_width()
)
}
}