diff --git a/data/test.lang b/data/test.lang index 9f7fa75..0ee8494 100644 --- a/data/test.lang +++ b/data/test.lang @@ -1,9 +1,11 @@ fn start() { - print("Helld!\n"); - print("Hello World!!!!!\n"); + println("Helld!"); + println("Hello World!!!!!"); thinger(); - print("what\n"); - exit(39); + println("what"); + print(tester()); + arger("a", "b", "c"); + exit(add(35, 4)); } fn thinger() { @@ -14,6 +16,11 @@ fn unused() { print("el unused\n"); } +fn println(msg: slice<8>) { + print(msg); + print("\n"); +} + fn print(msg: slice<8>) { asm (a1 = msg) { ld a2, 8, a1 @@ -24,6 +31,23 @@ fn print(msg: slice<8>) { } } +fn add(a: 64, b: 64) -> 64 { + let c: 64 = 0; + asm (t0 = a, t1 = b, a0 = c) { + ld t0, 0, t0 + ld t1, 0, t1 + add t0, t0, t1 + sd t0, 0, a0 + }; + c +} + +fn arger(a: slice<8>, b: slice<8>, c: slice<8>) { + print(a); + print(b); + println(c); +} + fn exit(status: 64) { asm (a0 = status) { ld a0, 0, a0 @@ -31,3 +55,7 @@ fn exit(status: 64) { ecall }; } + +fn tester() -> slice<8> { + "hola\n" +} diff --git a/src/compiler/arch/riscv64/compile.rs b/src/compiler/arch/riscv64/compile.rs index 9302055..eaa22bc 100644 --- a/src/compiler/arch/riscv64/compile.rs +++ b/src/compiler/arch/riscv64/compile.rs @@ -100,29 +100,38 @@ pub fn compile(program: IRLProgram) -> (Vec, Option) { let mut v = Vec::new(); let mut stack = HashMap::new(); let mut stack_len = 0; - let has_stack = !f.stack.is_empty() || !f.args.is_empty() || f.makes_call; let mut stack_ra = None; + let mut stack_rva = None; + if f.makes_call { + // return addr + stack_ra = Some(stack_len); + stack_len += 8; + } + for (id, s) in &f.stack { + stack.insert(id, stack_len); + stack_len += align(s); + } + for (id, s) in f.args.iter().rev() { + stack.insert(id, stack_len); + stack_len += align(s); + } + if f.ret_size > 0 { + stack_rva = Some(stack_len); + stack_len += align(&f.ret_size); + } + v.push(LI::Addi { + dest: sp, + src: sp, + imm: -stack_len, + }); + let has_stack = stack_len > 0; if has_stack { - if f.makes_call { - // return addr - stack_ra = Some(stack_len); - stack_len += 8; - } - for (id, s) in &f.stack { - stack.insert(id, stack_len); - stack_len += align(s); - } - for (id, s) in f.args.iter().rev() { - stack.insert(id, stack_len); - stack_len += align(s); - } - v.push(LI::Addi { - dest: sp, - src: sp, - imm: -stack_len, - }); if let Some(stack_ra) = stack_ra { - v.push(LI::Sd { src: ra, offset: stack_ra, base: sp }); + v.push(LI::Sd { + src: ra, + offset: stack_ra, + base: sp, + }); } } for i in &f.instructions { @@ -156,6 +165,19 @@ pub fn compile(program: IRLProgram) -> (Vec, Option) { } IRI::Call { dest, f, args } => { let mut offset = 0; + if let Some((dest, s)) = dest { + offset -= align(s); + v.push(LI::Addi { + dest: t0, + src: sp, + imm: stack[&dest], + }); + v.push(LI::Sd { + src: t0, + offset, + base: sp, + }) + } for (arg, s) in args { let bs = align(s); offset -= bs; @@ -191,15 +213,39 @@ pub fn compile(program: IRLProgram) -> (Vec, Option) { offset: offset as i32, base: r(base), }), + AI::Sd { src, base, offset } => v.push(LI::Sd { + src: r(src), + offset: offset as i32, + base: r(base), + }), + AI::Add { dest, src1, src2 } => v.push(LI::Add { + dest: r(dest), + src1: r(src1), + src2: r(src2), + }), } } } - IRI::Ret { src } => todo!(), + IRI::Ret { src } => { + let Some(rva) = stack_rva else { + panic!("no return value address on stack!") + }; + v.push(LI::Ld { + dest: t0, + offset: rva, + base: sp, + }); + mov_mem(&mut v, sp, stack[src], t0, 0, t1, align(&f.ret_size) as u32); + } } } if has_stack { if let Some(stack_ra) = stack_ra { - v.push(LI::Ld { dest: ra, offset: stack_ra, base: sp }); + v.push(LI::Ld { + dest: ra, + offset: stack_ra, + base: sp, + }); } v.push(LI::Addi { dest: sp, @@ -210,5 +256,5 @@ pub fn compile(program: IRLProgram) -> (Vec, Option) { v.push(LI::Ret); fns.push((v, *sym)); } - create_program(fns, data, Some(program.entry())) + create_program(fns, data, Some(program.entry()), &program) } diff --git a/src/compiler/program.rs b/src/compiler/program.rs index 6c0b0ba..546d363 100644 --- a/src/compiler/program.rs +++ b/src/compiler/program.rs @@ -1,11 +1,12 @@ use std::collections::HashMap; -use crate::ir::Symbol; +use crate::ir::{IRLProgram, Symbol}; pub fn create_program( fns: Vec<(Vec, Symbol)>, ro_data: Vec<(Vec, Symbol)>, start: Option, + program: &IRLProgram, ) -> (Vec, Option) { let mut data = Vec::new(); let mut sym_table = SymTable::new(fns.len() + ro_data.len()); @@ -36,6 +37,16 @@ pub fn create_program( } } } + for (s, f) in program.fns() { + println!( + "{}: {:?}", + f.name, + sym_table.get(*s).map(|a| { + let pos = a.0 + 0x1000 + 0x40 + 0x38; + format!("0x{:x}", pos) + }) + ); + } assert!(missing.is_empty()); ( data, diff --git a/src/ir/arch/riscv64.rs b/src/ir/arch/riscv64.rs index b36cfef..cc4dd98 100644 --- a/src/ir/arch/riscv64.rs +++ b/src/ir/arch/riscv64.rs @@ -1,7 +1,4 @@ -use crate::{ - compiler::arch::riscv64::*, - ir::{VarID, VarInst}, -}; +use crate::{compiler::arch::riscv64::*, ir::VarInst}; #[derive(Copy, Clone)] pub enum RV64Instruction { @@ -23,6 +20,16 @@ pub enum RV64Instruction { offset: i64, base: RegRef, }, + Sd { + src: RegRef, + offset: i64, + base: RegRef, + }, + Add { + dest: RegRef, + src1: RegRef, + src2: RegRef, + }, } #[derive(Copy, Clone)] @@ -48,6 +55,8 @@ impl std::fmt::Debug for RV64Instruction { Self::Mv { dest, src } => write!(f, "mv {dest:?}, {src:?}"), Self::La { dest, src } => write!(f, "la {dest:?}, {src:?}"), Self::Ld { dest, offset, base } => write!(f, "ld {dest:?}, {offset}({base:?})"), + Self::Sd { src, offset, base } => write!(f, "sd {src:?}, {offset}({base:?})"), + Self::Add { dest, src1, src2 } => write!(f, "add {dest:?}, {src1:?}, {src2:?}"), } } } diff --git a/src/ir/lower/func.rs b/src/ir/lower/func.rs index a11f997..42ad338 100644 --- a/src/ir/lower/func.rs +++ b/src/ir/lower/func.rs @@ -9,6 +9,7 @@ pub struct IRLFunction { pub instructions: Vec, pub stack: HashMap, pub args: Vec<(VarID, Size)>, + pub ret_size: Size, pub makes_call: bool, } @@ -34,7 +35,7 @@ pub enum IRLInstruction { len: Len, }, Call { - dest: VarID, + dest: Option<(VarID, Size)>, f: Symbol, args: Vec<(VarID, Size)>, }, diff --git a/src/ir/lower/program.rs b/src/ir/lower/program.rs index 06b6360..beefaa3 100644 --- a/src/ir/lower/program.rs +++ b/src/ir/lower/program.rs @@ -106,8 +106,14 @@ impl IRLProgram { makes_call = true; let fid = &p.fn_map[&f.id]; let sym = builder.func(fid); + let ret_size = p.size_of_var(dest.id).expect("unsized type"); + let dest = if ret_size > 0 { + Some((dest.id, ret_size)) + } else { + None + }; instrs.push(IRLInstruction::Call { - dest: dest.id, + dest, f: sym, args: args .iter() @@ -135,6 +141,7 @@ impl IRLProgram { .iter() .map(|a| (*a, p.size_of_var(*a).expect("unsized type"))) .collect(), + ret_size: p.size_of_type(&f.ret).expect("unsized type"), stack, }, ); diff --git a/src/ir/upper/func.rs b/src/ir/upper/func.rs index f5fdbe5..42d1a01 100644 --- a/src/ir/upper/func.rs +++ b/src/ir/upper/func.rs @@ -1,11 +1,12 @@ use std::fmt::Write; -use super::{arch::riscv64::RV64Instruction, inst::VarInst, DataID, FnID, IRUInstrInst, VarID}; +use super::{arch::riscv64::RV64Instruction, inst::VarInst, DataID, FnID, IRUInstrInst, Type, VarID}; use crate::{common::FileSpan, compiler::arch::riscv64::Reg, util::Padder}; pub struct IRUFunction { pub name: String, pub args: Vec, + pub ret: Type, pub instructions: Vec, } @@ -49,9 +50,10 @@ pub struct IRInstructions { } impl IRUFunction { - pub fn new(name: String, args: Vec, instructions: IRInstructions) -> Self { + pub fn new(name: String, args: Vec, ret: Type, instructions: IRInstructions) -> Self { Self { name, + ret, args, instructions: instructions.vec, } diff --git a/src/ir/upper/validate.rs b/src/ir/upper/validate.rs index 407ee6a..c15faae 100644 --- a/src/ir/upper/validate.rs +++ b/src/ir/upper/validate.rs @@ -1,11 +1,11 @@ // TODO: move this into ir, not parser use super::{IRUProgram, Type}; -use crate::common::CompilerOutput; +use crate::common::{CompilerMsg, CompilerOutput}; impl IRUProgram { pub fn validate(&self) -> CompilerOutput { let mut output = CompilerOutput::new(); - for f in self.fns.iter().flatten() { + for (f, fd) in self.fns.iter().flatten().zip(&self.fn_defs) { for i in &f.instructions { match &i.i { super::IRUInstruction::Mv { dest, src } => { @@ -35,6 +35,12 @@ impl IRUProgram { todo!() }; output.check_assign(self, ret, destty, dest.span); + if args.len() != argtys.len() { + output.err(CompilerMsg { + msg: "Wrong number of arguments to function".to_string(), + spans: vec![dest.span], + }); + } for (argv, argt) in args.iter().zip(argtys) { let dest = self.get_var(argv.id); output.check_assign(self, argt, &dest.ty, argv.span); @@ -43,7 +49,10 @@ impl IRUProgram { super::IRUInstruction::AsmBlock { instructions, args } => { // TODO } - super::IRUInstruction::Ret { src } => todo!(), + super::IRUInstruction::Ret { src } => { + let srcty = &self.get_var(src.id).ty; + output.check_assign(self, srcty, &fd.ret, src.span); + }, } } } diff --git a/src/main.rs b/src/main.rs index 9cc250f..4065e5c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -49,8 +49,8 @@ fn run_file(file: &str, gdb: bool) { let output = namespace.validate(); output.write_for(&mut stdout(), file); if output.errs.is_empty() { - let program = IRLProgram::create(&namespace); - let bin = compiler::compile(program.expect("morir")); + let program = IRLProgram::create(&namespace).expect("morir"); + let bin = compiler::compile(program); println!("compiled"); save_run(&bin, gdb); } diff --git a/src/parser/v3/lower/arch/riscv64.rs b/src/parser/v3/lower/arch/riscv64.rs index eb2cc92..07b10a2 100644 --- a/src/parser/v3/lower/arch/riscv64.rs +++ b/src/parser/v3/lower/arch/riscv64.rs @@ -1,4 +1,4 @@ -use super::{PAsmArg, FnLowerCtx, PIdent, Node, PInstruction}; +use super::{FnLowerCtx, Node, PAsmArg, PIdent, PInstruction}; use crate::{ compiler::arch::riscv64::*, ir::{ @@ -40,6 +40,16 @@ impl RV64Instruction { let base = RegRef::from_arg(base, ctx)?; Self::Ld { dest, offset, base } } + "sd" => { + let [src, offset, base] = args else { + ctx.err("sd requires 3 arguments".to_string()); + return None; + }; + let src = RegRef::from_arg(src, ctx)?; + let offset = i64_from_arg(offset, ctx)?; + let base = RegRef::from_arg(base, ctx)?; + Self::Sd { src, offset, base } + } "mv" => { let [dest, src] = args else { ctx.err("la requires 2 arguments".to_string()); @@ -49,6 +59,16 @@ impl RV64Instruction { let src = RegRef::from_arg(src, ctx)?; Self::Mv { dest, src } } + "add" => { + let [dest, src1, src2] = args else { + ctx.err("add requires 3 arguments".to_string()); + return None; + }; + let dest = RegRef::from_arg(dest, ctx)?; + let src1 = RegRef::from_arg(src1, ctx)?; + let src2 = RegRef::from_arg(src2, ctx)?; + Self::Add { dest, src1, src2 } + } w => { ctx.err_at(inst.op.span, format!("Unknown instruction '{}'", w)); return None; diff --git a/src/parser/v3/lower/func.rs b/src/parser/v3/lower/func.rs index e10b12b..ac500e6 100644 --- a/src/parser/v3/lower/func.rs +++ b/src/parser/v3/lower/func.rs @@ -73,7 +73,7 @@ impl PFunction { if let Some(src) = self.body.lower(&mut ctx) { instructions.push(IRUInstruction::Ret { src }, src.span); } - IRUFunction::new(def.name.clone(), args, instructions) + IRUFunction::new(def.name.clone(), args, def.ret, instructions) } }