pub use isa::call_conv::CallConv;
pub use isa::constraints::{BranchRange, ConstraintKind, OperandConstraint, RecipeConstraints};
pub use isa::encoding::{base_size, EncInfo, Encoding};
pub use isa::registers::{regs_overlap, RegClass, RegClassIndex, RegInfo, RegUnit};
pub use isa::stack::{StackBase, StackBaseMask, StackRef};
use binemit;
use flowgraph;
use ir;
use isa::enc_tables::Encodings;
use regalloc;
use result::CodegenResult;
use settings;
use settings::SetResult;
use std::boxed::Box;
use std::fmt;
use target_lexicon::{Architecture, PointerWidth, Triple};
use timing;
#[cfg(build_riscv)]
mod riscv;
#[cfg(build_x86)]
mod x86;
#[cfg(build_arm32)]
mod arm32;
#[cfg(build_arm64)]
mod arm64;
mod call_conv;
mod constraints;
mod enc_tables;
mod encoding;
pub mod registers;
mod stack;
macro_rules! isa_builder {
($module:ident, $name:ident) => {{
#[cfg($name)]
fn $name(triple: Triple) -> Result<Builder, LookupError> {
Ok($module::isa_builder(triple))
};
#[cfg(not($name))]
fn $name(_triple: Triple) -> Result<Builder, LookupError> {
Err(LookupError::Unsupported)
}
$name
}};
}
pub fn lookup(triple: Triple) -> Result<Builder, LookupError> {
match triple.architecture {
Architecture::Riscv32 | Architecture::Riscv64 => isa_builder!(riscv, build_riscv)(triple),
Architecture::I386 | Architecture::I586 | Architecture::I686 | Architecture::X86_64 => {
isa_builder!(x86, build_x86)(triple)
}
Architecture::Thumbv6m
| Architecture::Thumbv7em
| Architecture::Thumbv7m
| Architecture::Arm
| Architecture::Armv4t
| Architecture::Armv5te
| Architecture::Armv7
| Architecture::Armv7s => isa_builder!(arm32, build_arm32)(triple),
Architecture::Aarch64 => isa_builder!(arm64, build_arm64)(triple),
_ => Err(LookupError::Unsupported),
}
}
#[derive(Fail, PartialEq, Eq, Copy, Clone, Debug)]
pub enum LookupError {
#[fail(display = "Support for this target is disabled")]
SupportDisabled,
#[fail(display = "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<TargetIsa>,
}
impl Builder {
pub fn finish(self, shared_flags: settings::Flags) -> Box<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, &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 {
fn name(&self) -> &'static str;
fn triple(&self) -> &Triple;
fn flags(&self) -> &settings::Flags;
fn default_call_conv(&self) -> CallConv {
CallConv::default_for_triple(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 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 ir::stackslot::{StackOffset, StackSize};
use stack_layout::layout_stack;
let word_size = StackSize::from(self.pointer_bytes());
if func.signature.call_conv == CallConv::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);
}
layout_stack(&mut func.stack_slots, word_size)?;
Ok(())
}
#[cfg(feature = "testing_hooks")]
fn emit_inst(
&self,
func: &ir::Function,
inst: ir::Inst,
divert: &mut regalloc::RegDiversions,
sink: &mut binemit::CodeSink,
);
fn emit_function_to_memory(&self, func: &ir::Function, sink: &mut binemit::MemoryCodeSink);
}