From 6bafe32ce08498b428255217a0f0bf3f13cafe95 Mon Sep 17 00:00:00 2001 From: Cassie Jones Date: Mon, 2 Mar 2020 20:02:49 +0100 Subject: [PATCH] Add support for some arithmetic built-ins This adds support for addition, subtraction, and comparisons. All of these built-ins are written as definitions in assembly. Currently the true and false functions are included unconditionally in compilation, and have their numbers hard-coded. --- ivy-examples/print-n.vy | 9 ++++++ ivy-examples/program.vy | 9 ++++-- src/main.rs | 4 ++- src/trans/x64.rs | 70 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 ivy-examples/print-n.vy diff --git a/ivy-examples/print-n.vy b/ivy-examples/print-n.vy new file mode 100644 index 0000000..c79d5d5 --- /dev/null +++ b/ivy-examples/print-n.vy @@ -0,0 +1,9 @@ +(let ( + [fix (lam (f) + (let ([t (lam (x) (f (lam (v) (x x v))))]) + (t t)))] + [printn [fix (lam (recur n) + (((<= n 0) + (lam () 0) + (lam () (recur (- (debug n) 1))))))]] +) (printn 13)) diff --git a/ivy-examples/program.vy b/ivy-examples/program.vy index 9a10f88..2a9fe0e 100644 --- a/ivy-examples/program.vy +++ b/ivy-examples/program.vy @@ -1,9 +1,12 @@ (let ([nil (lam (c n) (n))] [cons (lam (x y) (lam (c n) (c x y)))] - [fix (lam (f) (f f))] + [head true] + [fix (lam (f) + (let ([t (lam (x) (f (lam (v) (x x v))))]) + (t t)))] [if (lam (c t f) ((c t f)))]) ([fix (lam (recur a b l n) (if (<= n 0) [lam () l] - [lam () (recur b (+ a b) (cons a l) (- n 1))]))] - 0 1 nil 20)) + [lam () (recur b (+ (debug a) b) (cons a l) (- n 1))]))] + 0 1 nil 30)) diff --git a/src/main.rs b/src/main.rs index b2eebd2..e40b16a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -69,13 +69,15 @@ fn main() -> io::Result<()> { } return Ok(()); } - let code = match translate(&ast) { + let mut code = match translate(&ast) { Ok(code) => code, Err(err) => { println!("{}", err); std::process::exit(1); } }; + code.globals.insert(1); // builtins true + code.globals.insert(2); // builtins false builtins.retain(|_, v| code.globals.contains(&v.global_number().unwrap())); if opt.assembly { match opt.output { diff --git a/src/trans/x64.rs b/src/trans/x64.rs index 473db2a..aa165a2 100644 --- a/src/trans/x64.rs +++ b/src/trans/x64.rs @@ -55,6 +55,11 @@ pub enum Reg { R15, } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Cond { + Le, +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Cfi { Def(Reg, i32), @@ -72,8 +77,13 @@ pub enum Inst { Lea(Reg, Addr), Call(Label), Jmp(Label), + Add(Reg, Reg), + Sub(Reg, Reg), AddI(Reg, u32), SubI(Reg, u32), + Cmp(Reg, Reg), + CLoad(Cond, Reg, Addr), + CMov(Cond, Reg, Reg), Ret, } @@ -349,6 +359,14 @@ impl fmt::Display for Addr { } } +impl fmt::Display for Cond { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match self { + Cond::Le => write!(fmt, "le"), + } + } +} + impl fmt::Display for Cfi { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { @@ -370,8 +388,13 @@ impl fmt::Display for Inst { Inst::Lea(r, a) => write!(fmt, "lea {}, {}", r, a), Inst::Call(l) => write!(fmt, "call {}", l), Inst::Jmp(l) => write!(fmt, "jmp {}", l), + Inst::Add(d, s) => write!(fmt, "add {}, {}", d, s), + Inst::Sub(d, s) => write!(fmt, "sub {}, {}", d, s), Inst::AddI(r, x) => write!(fmt, "add {}, {}", r, x), Inst::SubI(r, x) => write!(fmt, "sub {}, {}", r, x), + Inst::Cmp(a, b) => write!(fmt, "cmp {}, {}", a, b), + Inst::CLoad(c, r, a) => write!(fmt, "cmov{} {}, {}", c, r, a), + Inst::CMov(c, d, s) => write!(fmt, "cmov{} {}, {}", c, d, s), Inst::Ret => write!(fmt, "ret"), } } @@ -387,6 +410,53 @@ fn builtin(name: &str) -> (u16, &'static str, &'static [Inst]) { Inst::Jmp(extern_label!("ivy_debug")), ], ), + "+" => ( + 2, + "add", + &[ + Inst::Load(Reg::Rax, Addr::Off(Reg::Rdi, 0x18)), + Inst::Load(Reg::Rdi, Addr::Off(Reg::Rdi, 0x18 + 8)), + Inst::Add(Reg::Rax, Reg::Rdi), + Inst::SubI(Reg::Rax, 1), + Inst::Ret, + ], + ), + "-" => ( + 2, + "sub", + &[ + Inst::Load(Reg::Rax, Addr::Off(Reg::Rdi, 0x18)), + Inst::Load(Reg::Rdi, Addr::Off(Reg::Rdi, 0x18 + 8)), + Inst::Sub(Reg::Rax, Reg::Rdi), + Inst::AddI(Reg::Rax, 1), + Inst::Ret, + ], + ), + "<=" => ( + 2, + "leq", + &[ + Inst::Load(Reg::Rax, Addr::Off(Reg::Rdi, 0x18)), + Inst::Load(Reg::Rdi, Addr::Off(Reg::Rdi, 0x18 + 8)), + Inst::Cmp(Reg::Rax, Reg::Rdi), + Inst::Load(Reg::Rax, Addr::Rip(Label::Global(2))), // false + Inst::CLoad(Cond::Le, Reg::Rax, Addr::Rip(Label::Global(1))), // true + Inst::Ret, + ], + ), + "true" => ( + 2, + "true", + &[Inst::Load(Reg::Rax, Addr::Off(Reg::Rdi, 0x18)), Inst::Ret], + ), + "false" => ( + 2, + "false", + &[ + Inst::Load(Reg::Rax, Addr::Off(Reg::Rdi, 0x18 + 8)), + Inst::Ret, + ], + ), name => panic!("Unsupported builtin '{}' for x64", name), } } -- 2.43.2