From d928eca5337ec50e30f6c6020d0b2074106b9d88 Mon Sep 17 00:00:00 2001 From: Cassie Jones Date: Sat, 29 Feb 2020 17:56:45 +0100 Subject: [PATCH] Add skeleton of x64 compilation code We compile the globals and functions in the program into a list of global labels and definitions. Add a bunch of instruction and etc. types here for formatting. Then, assemble all of this together in the program. The program realigns the stack (probably overkill?) and then calls into the entry point symbol, then exits. I added ivy_exit so that I wouldn't have to refer to any platform-specific symbols in the assembly that's emitted, all of that can be handled by the runtime. Unfortunately there will still be platform specific behavior because of different calling conventions. --- rt/src/lib.rs | 5 ++ src/main.rs | 3 +- src/trans.rs | 2 + src/trans/x64.rs | 175 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 src/trans/x64.rs diff --git a/rt/src/lib.rs b/rt/src/lib.rs index 7250dad..6dfd5bd 100644 --- a/rt/src/lib.rs +++ b/rt/src/lib.rs @@ -75,6 +75,11 @@ pub unsafe extern "C" fn ivy_abort(msg: *const u8, len: usize) -> ! { sys::exit(1); } +#[no_mangle] +pub unsafe extern "C" fn ivy_exit(code: i32) -> ! { + sys::exit(code) +} + #[no_mangle] pub unsafe extern "C" fn ivy_check_int(obj: Obj) { if !obj.is_int() { diff --git a/src/main.rs b/src/main.rs index 65164d8..19d9392 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,6 +44,7 @@ fn main() -> io::Result<()> { std::process::exit(1); } }; - println!("{:#?}", code); + let stdout = std::io::stdout(); + trans::x64::write_compile(&mut stdout.lock(), &code)?; Ok(()) } diff --git a/src/trans.rs b/src/trans.rs index 234229f..5ded82e 100644 --- a/src/trans.rs +++ b/src/trans.rs @@ -4,6 +4,8 @@ use std::{ fmt, }; +pub mod x64; + #[derive(Hash, PartialEq, Eq, Clone, Copy)] pub struct FnName(u32); diff --git a/src/trans/x64.rs b/src/trans/x64.rs new file mode 100644 index 0000000..6cfa161 --- /dev/null +++ b/src/trans/x64.rs @@ -0,0 +1,175 @@ +use crate::trans::{FnName, Func, Program}; +use std::{ + fmt, + io::{self, Write}, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Label { + Global(u32), + Function(FnName), +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Addr { + Rip(Label), + Off(Reg, u32), +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Reg { + Rax, + Rbx, + Rcx, + Rdx, + Rsi, + Rdi, + Rbp, + Rsp, + R8, + R9, + R10, + R11, + R12, + R13, + R14, + R15, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Inst { + Push(Reg), + Load(Reg, Addr), + Store(Addr, Reg), + Mov(Reg, Reg), + Pop(Reg), + Ret, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Definition { + name: Label, + body: Vec, +} + +pub struct Global { + name: Label, + value: i64, +} + +pub fn write_compile(out: &mut impl Write, prog: &Program) -> io::Result<()> { + let (entry, globals, defns) = compile(&prog); + writeln!(out, ".data")?; + for global in globals { + writeln!(out, "{}", global)?; + } + writeln!(out)?; + writeln!( + out, + r#".text +.global _start +_start: + sub rsp, 15 + and spl, 0xF0 + call {} + mov rdi, 0 + call _ivy_exit +"#, + entry + )?; + for defn in defns { + writeln!(out, "{}", defn)?; + } + Ok(()) +} + +pub fn compile(prog: &Program) -> (Label, Vec, Vec) { + let globals = prog + .globals + .iter() + .map(|&global| Global { + name: Label::Global(global), + value: 0, + }) + .collect(); + let defns = prog + .functions + .values() + .map(|func| compile_func(prog, func)) + .collect(); + (Label::Function(prog.top), globals, defns) +} + +fn compile_func(prog: &Program, func: &Func) -> Definition { + let mut body = Vec::new(); + body.push(Inst::Ret); + Definition { + name: Label::Function(func.name), + body, + } +} + +impl fmt::Display for Definition { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match self.body.len() { + 0 => write!(fmt, "{}:", self.name), + 1 => write!(fmt, "{}: {}", self.name, self.body[0]), + len => { + writeln!(fmt, "{}:", self.name)?; + for inst in &self.body[..len - 1] { + writeln!(fmt, " {}", inst)?; + } + write!(fmt, " {}", self.body.last().unwrap()) + } + } + } +} + +impl fmt::Display for Global { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{}: .quad {}", self.name, self.value) + } +} + +impl fmt::Display for Label { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match self { + Label::Global(g) => write!(fmt, "IVY_GLOBAL${}", g), + Label::Function(f) => write!(fmt, "ivy_fn${}", f.0), + } + } +} + +impl fmt::Display for Reg { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match self { + Reg::Rax => write!(fmt, "rax"), + Reg::Rbx => write!(fmt, "rbx"), + Reg::Rcx => write!(fmt, "rcx"), + Reg::Rdx => write!(fmt, "rdx"), + Reg::Rsi => write!(fmt, "rsi"), + Reg::Rdi => write!(fmt, "rdi"), + Reg::Rbp => write!(fmt, "rbp"), + Reg::Rsp => write!(fmt, "rsp"), + Reg::R8 => write!(fmt, "r8"), + Reg::R9 => write!(fmt, "r9"), + Reg::R10 => write!(fmt, "r10"), + Reg::R11 => write!(fmt, "r11"), + Reg::R12 => write!(fmt, "r12"), + Reg::R13 => write!(fmt, "r13"), + Reg::R14 => write!(fmt, "r14"), + Reg::R15 => write!(fmt, "r15"), + } + } +} + +impl fmt::Display for Inst { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match self { + Inst::Push(r) => write!(fmt, "push {}", r), + Inst::Pop(r) => write!(fmt, "pop {}", r), + Inst::Ret => write!(fmt, "ret"), + inst => write!(fmt, "{:?}", inst), + } + } +} -- 2.43.2