don't heap allocate in io.printf

This commit is contained in:
2026-03-14 11:44:14 +01:00
parent 4a60c1fc12
commit 3f9df4a32f
3 changed files with 39 additions and 31 deletions

View File

@@ -14,7 +14,15 @@ pub struct Analyzer {
impl Analyzer { impl Analyzer {
pub fn new() -> Analyzer { pub fn new() -> Analyzer {
Analyzer { Analyzer {
functions: HashMap::new(), functions: HashMap::from([
("_builtin_heap_head".into(), -1),
("_builtin_heap_tail".into(), -1),
("_builtin_read64".into(), -1),
("_builtin_set64".into(), -1),
("_builtin_syscall".into(), -1),
("io.printf".into(), -1),
("_builtin_environ".into(), -1),
]),
constants: HashMap::new(), constants: HashMap::new(),
structs: HashMap::new(), structs: HashMap::new(),
} }
@@ -160,22 +168,16 @@ impl Analyzer {
args, args,
} => { } => {
if let Expr::Variable(callee_name) = *callee.clone() { if let Expr::Variable(callee_name) = *callee.clone() {
if callee_name.lexeme.starts_with("_builtin_") if self.functions.contains_key(&callee_name.lexeme) {
|| self.functions.contains_key(&callee_name.lexeme)
{
// its a function (defined/builtin/extern) // its a function (defined/builtin/extern)
if let Some(arity) = self.functions.get(&callee_name.lexeme) { if let Some(arity) = self.functions.get(&callee_name.lexeme) {
if *arity >= 0 if *arity >= 0 && *arity != args.len() as i32 {
&& *arity != args.len() as i32
&& callee_name.lexeme != "io.printf"
// TODO: disgusting hack
{
return error!( return error!(
&paren.loc, &paren.loc,
format!("expected {} arguments, got {}", arity, args.len()) format!("expected {} arguments, got {}", arity, args.len())
); );
} }
} else if !callee_name.lexeme.starts_with("_builtin_") { } else {
return error!( return error!(
&paren.loc, &paren.loc,
format!("undefined function: {}", callee_name.lexeme) format!("undefined function: {}", callee_name.lexeme)

View File

@@ -142,6 +142,21 @@ _builtin_syscall:
mov r9, [rsp+8] mov r9, [rsp+8]
syscall syscall
ret ret
section .text.io.printf
io.printf:
push rbp
mov rbp, rsp
sub rsp, 48
mov [rsp], rsi
mov [rsp + 8], rdx
mov [rsp + 16], rcx
mov [rsp + 24], r8
mov [rsp + 32], r9
lea rsi, [rsp]
call io._printf_impl
leave
ret
" "
); );
@@ -650,9 +665,7 @@ _builtin_environ:
} }
if let Expr::Variable(callee_name) = &**callee { if let Expr::Variable(callee_name) = &**callee {
if callee_name.lexeme.starts_with("_builtin_") if self.analyzer.functions.contains_key(&callee_name.lexeme) {
|| self.analyzer.functions.contains_key(&callee_name.lexeme)
{
// its a function (defined/builtin/extern) // its a function (defined/builtin/extern)
emit!(&mut self.output, " call {}", callee_name.lexeme); emit!(&mut self.output, " call {}", callee_name.lexeme);
} else { } else {

View File

@@ -186,36 +186,29 @@ func mem.write32[x: ptr, d: i64] : void
func mem.write64[x: ptr, d: i64] : void func mem.write64[x: ptr, d: i64] : void
_builtin_set64(x, d) _builtin_set64(x, d)
// TODO: we don't have variadics so we manually skip arity checking in the analyzer func io._printf_impl[s: str, args: ptr] : void
func io.printf[s: str, a1: any, a2: any, a3: any, a4: any, a5: any] : void
// TODO: we really shouldn't heap allocate to print something
let args: Array = [a1, a2, a3, a4, a5]
let arg_idx: i64 = 0
while s[0] while s[0]
if s[0] == '%' if s[0] == '%'
s = s + 1 s = s + 1
if s[0] == 'd' if s[0] == 'd'
io.print_i64(array.nth(args, arg_idx)) io.print_i64(mem.read64(args))
arg_idx = arg_idx + 1 args = args + 8
else if s[0] == 'x' else if s[0] == 'x'
io.print_i64_hex(array.nth(args, arg_idx)) io.print_i64_hex(mem.read64(args))
arg_idx = arg_idx + 1 args = args + 8
else if s[0] == 's' else if s[0] == 's'
io.print(array.nth(args, arg_idx)) io.print(mem.read64(args))
arg_idx = arg_idx + 1 args = args + 8
else if (s[0] == 'c') else if s[0] == 'c'
io.print_char(array.nth(args, arg_idx)) io.print_char(mem.read64(args))
arg_idx = arg_idx + 1 args = args + 8
else if (s[0] == '%') else if s[0] == '%'
io.print_char('%') io.print_char('%')
else else
io.print_char(s[0]) io.print_char(s[0])
s = s + 1 s = s + 1
array.free(args)
func io.print_sized[x: str, size: i64] : void func io.print_sized[x: str, size: i64] : void
_builtin_syscall(SYS_write, 1, x, size) _builtin_syscall(SYS_write, 1, x, size)