mod call_sites;
mod codegen;
mod compiled_code;
mod lazy_compilation_trampoline;
mod reg_alloc;
pub(super) mod rt;
use std::sync::Arc;
use crate::{
compiler::Compiler,
compiler::{
compiled_code::{CompiledCode, Symbol},
graph::{cfg::CFG, BaseOp, Graph, NodeId},
},
};
use super::{reg_alloc::LinearScanRegisterAllocator, Reg, ISA};
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum X64Reg {
RAX,
RCX,
RDX,
RBX,
RSP,
RBP,
RSI,
RDI,
R8,
R9,
R10,
R11,
R12,
R13,
R14,
R15,
XMM0,
XMM1,
XMM2,
XMM3,
XMM4,
XMM5,
XMM6,
XMM7,
XMM8,
XMM9,
XMM10,
XMM11,
XMM12,
XMM13,
XMM14,
XMM15,
}
impl From<usize> for X64Reg {
fn from(v: usize) -> Self {
unsafe { std::mem::transmute(v as u8) }
}
}
impl Into<usize> for X64Reg {
fn into(self) -> usize {
self as _
}
}
impl Reg for X64Reg {
const MAX_COUNT: usize = 32;
const GPRS: &'static [Self] = &[
Self::RAX,
Self::RBX,
Self::RCX,
Self::RDX,
Self::RSI,
Self::RDI,
Self::R8,
Self::R9,
Self::R10,
Self::R11,
Self::R12,
Self::R13,
];
const RESERVED_GPRS: &'static [Self] = &[Self::RBP, Self::RSP, Self::R14, Self::R15];
const FPRS: &'static [Self] = &[
Self::XMM0,
Self::XMM1,
Self::XMM2,
Self::XMM3,
Self::XMM4,
Self::XMM5,
Self::XMM6,
Self::XMM7,
Self::XMM8,
Self::XMM9,
Self::XMM10,
Self::XMM11,
Self::XMM12,
Self::XMM13,
];
const RESERVED_FPRS: &'static [Self] = &[Self::XMM14, Self::XMM15];
}
impl X64Reg {
fn is_callee_saved(&self) -> bool {
[Self::RBX, Self::R12, Self::R13, Self::R14, Self::R15].contains(self)
}
}
pub struct X64;
impl ISA for X64 {
type Reg = X64Reg;
type Op = BaseOp;
fn pre_assign_registers(graph: &mut Graph, node: NodeId) {
reg_alloc::pre_assign_registers(graph, node)
}
fn codegen(
compiler: &Compiler,
symbol: Symbol,
cfg: &mut CFG<Self::Op>,
) -> Arc<dyn CompiledCode> {
let mut lsra = LinearScanRegisterAllocator::<Self>::new(cfg);
lsra.allocate();
let codegen: codegen::CodeGen = codegen::CodeGen::new(compiler, symbol, cfg);
codegen.gen()
}
fn coalesce_live_intervals(g: &Graph, n: NodeId, coalesce: impl FnMut(NodeId, NodeId)) {
reg_alloc::coalesce_live_intervals(g, n, coalesce)
}
fn flush_cache(start: *const u8, bytes: usize) {
unsafe {
for i in (0..bytes).step_by(std::mem::size_of::<usize>()) {
std::arch::x86_64::_mm_clflush(start.add(i));
}
}
}
fn gen_lazy_compilation_trampoline() -> Vec<u8> {
lazy_compilation_trampoline::gen_lazy_compilation_trampoline()
}
}