From d5de30d9e7b2b23027e92287bd067a6503a9a770 Mon Sep 17 00:00:00 2001 From: janis Date: Fri, 31 Oct 2025 15:49:10 +0100 Subject: [PATCH] initial codegen --- lang/src/codegen.asm | 112 ++++++++++++++++++++++++++++++++++++++ lang/tests/codegen.rs | 74 +++++++++++++++++++++++++ lang/tests/shared/defs.rs | 9 ++- 3 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 lang/src/codegen.asm create mode 100644 lang/tests/codegen.rs diff --git a/lang/src/codegen.asm b/lang/src/codegen.asm new file mode 100644 index 0000000..c16c005 --- /dev/null +++ b/lang/src/codegen.asm @@ -0,0 +1,112 @@ +default rel + +%include "ast.inc" + +extern panic +extern vec_extend +extern vec_get + +section .rdata + SECTION_TEXT db "section .text\n" + SECTION_TEXT_LEN equ $ - SECTION_TEXT + GLOBAL_ db "global " + GLOBAL_LEN equ $ - GLOBAL_ + COLON_NL db ":", 10 + COLON_NL_LEN equ $ - COLON_NL + RET_NL db "ret", 10 + RET_NL_LEN equ $ - RET_NL + +section .text +;; start-structs +;; struct CodegenCtx { +;; ast: *const Ast, +;; text: Vec, +;; } +;; end-structs + +;; rdi: *Ctx +;; rsi: function index +;; define-fn: fn codegen_function(ast: *const CodegenCtx, func_idx: usize) -> () +codegen_function: + push rbp + mov rbp, rsp + push rbx + + ; register-bitset [72..88] [a,b,c,d,di,si,sp,bp,8,9,10,11,12,13,14,15] + ; stack-vars: Vec<(index, offset)> [32..72] + ; current_stack_size: [24..32] + ; func_idx [16..24] + ; ast [8..16] + ; ctx [0..8] + sub rsp, 88 + mov [rsp], rdi ; ctx + mov rax, [rdi] + mov [rsp + 8], rax ; ast + mov [rsp + 16], rsi ; func_idx + + bts [rsp + 72], 7 ; mark rbp as used + bts [rsp + 72], 6 ; mark rsp as used + + ; push "section .text\n" + mov rdi, [rsp] ; ctx + lea rdi, [rsp + 8] ; &ctx.text + lea rsi, [rel SECTION_TEXT] + mov rdx, SECTION_TEXT_LEN + call vec_extend + + mov rdi, [rsp + 8] ; ast + mov rsi, [rsp + 16] ; func_idx + call vec_get + cmp [rax + 0], AST_FUNCTION ; AstNode.kind + mov rbx, [rax + 8] ; AstNode.data + jne .panic + + ; push "global {function_name}\n" + mov rdi, [rsp] ; ctx + lea rdi, [rdi] ; &ctx.text + lea rsi, [rel GLOBAL_] + mov rdx, GLOBAL_LEN + call vec_extend + ; get function name + mov rdi, [rsp] ; ctx + lea rdi, [rdi] ; &ctx.text + mov rsi, [rbx + 0] ; AstFunction.name + mov rdx, [rbx + 8] ; AstFunction.name_len + call vec_extend + ; push "\n" + mov rdi, [rsp] ; ctx + lea rdi, [rdi] ; &ctx.text + lea rsi, [rel COLON_NL] + inc rsi + mov rdx, 1 + call vec_extend + ; push "{function_name}:\n" + mov rdi, [rsp] ; ctx + lea rdi, [rdi] ; &ctx.text + mov rsi, [rbx + 0] ; AstFunction.name + mov rdx, [rbx + 8] ; AstFunction.name_len + call vec_extend + ; push ":\n" + mov rdi, [rsp] ; ctx + lea rdi, [rdi] ; &ctx.text + lea rsi, [rel COLON_NL] + mov rdx, 2 + call vec_extend + + + ; TODO: generate function body + + ; push "ret\n" + mov rdi, [rsp] ; ctx + lea rdi, [rdi] ; &ctx.text + lea rsi, [rel RET_NL] + mov rdx, RET_NL_LEN + call vec_extend + + pop rbx + add rsp, 88 + pop rbp + ret + +.panic: + call panic diff --git a/lang/tests/codegen.rs b/lang/tests/codegen.rs new file mode 100644 index 0000000..d786539 --- /dev/null +++ b/lang/tests/codegen.rs @@ -0,0 +1,74 @@ +#![feature(debug_closure_helpers)] + +#[path = "shared/shared.rs"] +mod util; + +#[path = "shared/ast_debug.rs"] +mod ast_debug; + +use util::defs::{parse_func, Ast, AstNode}; + +unsafe extern "C" { + unsafe fn bump_init(); + + unsafe fn tokeniser_init_buf(bytes: *const u8, len: usize) -> (); +} + +fn main() { + unsafe { + bump_init(); + } + println!("Bump allocator initialized."); + + let src = b"3 + 4"; + + fn print_ast(src: &[u8], parser: impl FnOnce(&mut Ast) -> u64) { + unsafe { + tokeniser_init_buf(src.as_ptr(), src.len()); + let mut ast = Ast { + nodes: util::vec::Vec::new(), + }; + let expr_id = parser(&mut ast); + eprintln!("Parsed expression ID: {}", expr_id); + println!("{:#}", &ast); + + // unsafe extern "C" fn visit_node( + // _this: *mut (), + // ast: *mut Ast, + // node_id: u64, + // scope: u64, + // ) { + // let ast = unsafe { &*ast }; + // let node = ast.nodes.get(node_id as usize).unwrap(); + // eprintln!("{scope}: Visiting node {node_id}: {node}"); + // } + + // util::defs::ast_walk_for_each(&mut ast, expr_id, core::ptr::null_mut(), visit_node); + + let mut symtable = core::mem::MaybeUninit::::uninit(); + util::defs::ast_build_symtable(&mut ast, expr_id, &mut symtable); + let mut symtable = symtable.assume_init(); + use util::DisplayedSliceExt; + println!( + "Symbol Table: {:#?}", + symtable.symtable.as_slice().displayed() + ); + + util::defs::ast_resolve_var_refs(&mut ast, &mut symtable, expr_id); + + println!("{:#}", &ast); + }; + } + + print_ast( + b"fn main(a: u32) -> void { +let y: u32 = a + 4; +{ + let y: u32 = 10; +} +let y: *u32 = &y; +return *y; +}", + |ast| unsafe { parse_func(ast) }, + ); +} diff --git a/lang/tests/shared/defs.rs b/lang/tests/shared/defs.rs index bddda5b..838b5c3 100644 --- a/lang/tests/shared/defs.rs +++ b/lang/tests/shared/defs.rs @@ -17,7 +17,7 @@ unsafe extern "C" { pub unsafe fn ast_build_symtable(ast: *mut Ast, root_index: u64, symtable: *mut core::mem::MaybeUninit); pub unsafe fn ast_walk_for_each(ast: *mut Ast, start_index: u64, ctx: *mut (), for_each: unsafe extern "C" fn(ctx: *mut (), *mut Ast, node_index: u64, scope: u64)); pub unsafe fn ast_resolve_var_refs(ast: *mut Ast, ctx: *mut SymbolTable, root_index: u64); - pub unsafe fn codegen_function(ast: *const Ast, func_idx: usize) -> (); + pub unsafe fn codegen_function(ast: *const CodegenCtx, func_idx: usize) -> (); pub unsafe fn vec_extend(vec: *mut BlobVec, elements: *const u8, count: usize) -> (); } @@ -192,6 +192,13 @@ pub struct SymEntry { pub extra: u64, } +#[repr(C)] +#[derive(Debug)] +pub struct CodegenCtx { + pub ast: *const Ast, + pub text: Vec, +} + #[repr(C)] #[derive(Debug)] pub struct BlobVec {