pub use crate::isa::call_conv::CallConv;
pub use crate::isa::constraints::{
BranchRange, ConstraintKind, OperandConstraint, RecipeConstraints,
};
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;
use crate::isa::enc_tables::Encodings;
use crate::regalloc;
use crate::result::CodegenResult;
use crate::settings;
use crate::settings::SetResult;
use crate::timing;
use alloc::borrow::Cow;
use alloc::boxed::Box;
use core::fmt;
use target_lexicon::{triple, Architecture, PointerWidth, Triple};
use thiserror::Error;
#[cfg(feature = "riscv")]
mod riscv;
#[cfg(feature = "x86")]
mod x86;
#[cfg(feature = "arm32")]
mod arm32;
#[cfg(feature = "arm64")]
mod arm64;
mod call_conv;
mod constraints;
mod enc_tables;
mod encoding;
pub mod registers;
mod stack;
macro_rules! isa_builder {
($name: ident, $feature: tt, $triple: ident) => {{
#[cfg(feature = $feature)]
{
Ok($name::isa_builder($triple))
}
#[cfg(not(feature = $feature))]
{
Err(LookupError::SupportDisabled)
}
}};
}
pub fn lookup(triple: Triple) -> Result<Builder, LookupError> {
match triple.architecture {
Architecture::Riscv32 | Architecture::Riscv64 => isa_builder!(riscv, "riscv", triple),
Architecture::I386 | Architecture::I586 | Architecture::I686 | Architecture::X86_64 => {
isa_builder!(x86, "x86", triple)
}
Architecture::Arm { .. } => isa_builder!(arm32, "arm32", triple),
Architecture::Aarch64 { .. } => isa_builder!(arm64, "arm64", triple),
_ => Err(LookupError::Unsupported),
}
}
pub fn lookup_by_name(name: &str) -> Result<Builder, LookupError> {
use alloc::str::FromStr;
lookup(triple!(name))
}
#[derive(Error, PartialEq, Eq, Copy, Clone, Debug)]
pub enum LookupError {
#[error("Support for this target is disabled")]
SupportDisabled,
#[error("Support for this target has not been implemented yet")]
Unsupported,
}
pub struct Builder {
triple: Triple,
setup: settings::Builder,
constructor: fn(Triple, settings::Flags, settings::Builder) -> Box<dyn TargetIsa>,
}
impl Builder {
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)]
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 default_call_conv(&self) -> CallConv {
CallConv::triple_default(self.triple())
}
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;
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 emit_unwind_info(
&self,
_func: &ir::Function,
_kind: binemit::FrameUnwindKind,
_sink: &mut dyn binemit::FrameUnwindSink,
) {
}
}