pub use crate::isa::call_conv::CallConv;
pub use crate::isa::constraints::{
BranchRange, ConstraintKind, OperandConstraint, RecipeConstraints,
};
pub use crate::isa::enc_tables::Encodings;
pub use crate::isa::encoding::{base_size, EncInfo, Encoding};
pub use crate::isa::registers::{regs_overlap, RegClass, RegClassIndex, RegInfo, RegUnit};
pub use crate::isa::stack::{StackBase, StackBaseMask, StackRef};
use crate::binemit;
use crate::flowgraph;
use crate::ir;
#[cfg(feature = "unwind")]
use crate::isa::unwind::systemv::RegisterMappingError;
use crate::machinst::{MachBackend, UnwindInfoKind};
use crate::regalloc;
use crate::result::CodegenResult;
use crate::settings;
use crate::settings::SetResult;
use crate::timing;
use alloc::{borrow::Cow, boxed::Box, vec::Vec};
use core::any::Any;
use core::fmt;
use core::fmt::{Debug, Formatter};
use core::hash::Hasher;
use target_lexicon::{triple, Architecture, OperatingSystem, PointerWidth, Triple};
#[cfg(feature = "x86")]
pub mod x64;
#[cfg(feature = "arm32")]
mod arm32;
#[cfg(feature = "arm64")]
pub(crate) mod aarch64;
#[cfg(feature = "s390x")]
mod s390x;
#[cfg(any(feature = "x86", feature = "riscv"))]
mod legacy;
#[cfg(feature = "x86")]
use legacy::x86;
#[cfg(feature = "riscv")]
use legacy::riscv;
pub mod unwind;
mod call_conv;
mod constraints;
mod enc_tables;
mod encoding;
pub mod registers;
mod stack;
#[cfg(test)]
mod test_utils;
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)
}
}};
}
#[derive(Clone, Copy, Debug)]
pub enum BackendVariant {
Any,
Legacy,
MachInst,
}
impl Default for BackendVariant {
fn default() -> Self {
BackendVariant::Any
}
}
pub fn lookup_variant(triple: Triple, variant: BackendVariant) -> Result<Builder, LookupError> {
match (triple.architecture, variant) {
(Architecture::Riscv32 { .. }, _) | (Architecture::Riscv64 { .. }, _) => {
isa_builder!(riscv, (feature = "riscv"), triple)
}
(Architecture::X86_64, BackendVariant::Legacy) => {
isa_builder!(x86, (feature = "x86"), triple)
}
(Architecture::X86_64, BackendVariant::MachInst) => {
isa_builder!(x64, (feature = "x86"), triple)
}
#[cfg(not(feature = "old-x86-backend"))]
(Architecture::X86_64, BackendVariant::Any) => {
isa_builder!(x64, (feature = "x86"), triple)
}
#[cfg(feature = "old-x86-backend")]
(Architecture::X86_64, BackendVariant::Any) => {
isa_builder!(x86, (feature = "x86"), triple)
}
(Architecture::Arm { .. }, _) => isa_builder!(arm32, (feature = "arm32"), triple),
(Architecture::Aarch64 { .. }, _) => isa_builder!(aarch64, (feature = "arm64"), triple),
(Architecture::S390x { .. }, _) => isa_builder!(s390x, (feature = "s390x"), triple),
_ => Err(LookupError::Unsupported),
}
}
pub fn lookup(triple: Triple) -> Result<Builder, LookupError> {
lookup_variant(triple, BackendVariant::Any)
}
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) -> 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) -> 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(u16::from(self.pointer_bits())).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 variant(&self) -> BackendVariant {
BackendVariant::Legacy
}
fn hash_all_flags(&self, hasher: &mut dyn Hasher);
fn default_call_conv(&self) -> CallConv {
CallConv::triple_default(self.triple())
}
fn endianness(&self) -> ir::Endianness {
match self.triple().endianness().unwrap() {
target_lexicon::Endianness::Little => ir::Endianness::Little,
target_lexicon::Endianness::Big => ir::Endianness::Big,
}
}
fn pointer_type(&self) -> ir::Type {
ir::Type::int(u16::from(self.pointer_bits())).unwrap()
}
fn pointer_width(&self) -> PointerWidth {
self.triple().pointer_width().unwrap()
}
fn pointer_bits(&self) -> u8 {
self.pointer_width().bits()
}
fn pointer_bytes(&self) -> u8 {
self.pointer_width().bytes()
}
fn frontend_config(&self) -> TargetFrontendConfig {
TargetFrontendConfig {
default_call_conv: self.default_call_conv(),
pointer_width: self.pointer_width(),
}
}
fn uses_cpu_flags(&self) -> bool {
false
}
fn uses_complex_addresses(&self) -> bool {
false
}
fn register_info(&self) -> RegInfo;
#[cfg(feature = "unwind")]
fn map_dwarf_register(&self, _: RegUnit) -> Result<u16, RegisterMappingError> {
Err(RegisterMappingError::UnsupportedArchitecture)
}
#[cfg(feature = "unwind")]
fn map_regalloc_reg_to_dwarf(&self, _: ::regalloc::Reg) -> Result<u16, RegisterMappingError> {
Err(RegisterMappingError::UnsupportedArchitecture)
}
fn legal_encodings<'a>(
&'a self,
func: &'a ir::Function,
inst: &'a ir::InstructionData,
ctrl_typevar: ir::Type,
) -> Encodings<'a>;
fn encode(
&self,
func: &ir::Function,
inst: &ir::InstructionData,
ctrl_typevar: ir::Type,
) -> Result<Encoding, Legalize> {
let mut iter = self.legal_encodings(func, inst, ctrl_typevar);
iter.next().ok_or_else(|| iter.legalize())
}
fn encoding_info(&self) -> EncInfo;
fn legalize_signature(&self, sig: &mut Cow<ir::Signature>, current: bool);
fn regclass_for_abi_type(&self, ty: ir::Type) -> RegClass;
fn allocatable_registers(&self, func: &ir::Function) -> regalloc::RegisterSet;
fn prologue_epilogue(&self, func: &mut ir::Function) -> CodegenResult<()> {
let _tt = timing::prologue_epilogue();
use crate::ir::stackslot::{StackOffset, StackSize};
use crate::stack_layout::layout_stack;
let word_size = StackSize::from(self.pointer_bytes());
if func.signature.call_conv.extends_baldrdash() {
let bytes = StackSize::from(self.flags().baldrdash_prologue_words()) * word_size;
let mut ss = ir::StackSlotData::new(ir::StackSlotKind::IncomingArg, bytes);
ss.offset = Some(-(bytes as StackOffset));
func.stack_slots.push(ss);
}
let is_leaf = func.is_leaf();
layout_stack(&mut func.stack_slots, is_leaf, word_size)?;
Ok(())
}
#[cfg(feature = "testing_hooks")]
fn emit_inst(
&self,
func: &ir::Function,
inst: ir::Inst,
divert: &mut regalloc::RegDiversions,
sink: &mut dyn binemit::CodeSink,
);
fn emit_function_to_memory(&self, func: &ir::Function, sink: &mut binemit::MemoryCodeSink);
fn unsigned_add_overflow_condition(&self) -> ir::condcodes::IntCC;
fn unsigned_sub_overflow_condition(&self) -> ir::condcodes::IntCC;
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,
}
}
#[cfg(feature = "unwind")]
fn create_unwind_info(
&self,
_func: &ir::Function,
) -> CodegenResult<Option<unwind::UnwindInfo>> {
Ok(None)
}
#[cfg(feature = "unwind")]
fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
None
}
fn get_mach_backend(&self) -> Option<&dyn MachBackend> {
None
}
fn as_any(&self) -> &dyn Any;
}
impl Debug for &dyn TargetIsa {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"TargetIsa {{ triple: {:?}, pointer_width: {:?}}}",
self.triple(),
self.pointer_width()
)
}
}