From 8ad69be5aa91e1c64ac769d783d0c2cf10309d6c Mon Sep 17 00:00:00 2001 From: Toni Date: Fri, 26 Jun 2026 16:30:04 +0200 Subject: [PATCH] switched to gnu assembler for 5x speed up --- src/codegen_x86_64.rs | 150 +++++++++++++++++++++++------------------ src/main.rs | 2 +- src/symbol_table.rs | 2 - src/tokenizer.rs | 8 +-- std/linux_constants.zr | 4 +- std/std.zr | 13 +++- 6 files changed, 101 insertions(+), 78 deletions(-) diff --git a/src/codegen_x86_64.rs b/src/codegen_x86_64.rs index b34a1e2..e0b4306 100644 --- a/src/codegen_x86_64.rs +++ b/src/codegen_x86_64.rs @@ -103,58 +103,60 @@ impl<'a> CodegenX86_64<'a> { } pub fn get_output(&self) -> String { - format!("section .data\n{}{}", self.data_section, self.output) + format!(".section .data\n{}{}", self.data_section, self.output) } pub fn emit_prologue(&mut self, use_crt: bool) -> Result<(), ZernError> { emit!( &mut self.output, - "section .note.GNU-stack - db 0 + ".intel_syntax noprefix -section .bss - _heap_head: resq 1 - _heap_tail: resq 1 - _environ: resq 1 +.section .note.GNU-stack + .byte 0 -section .text._builtin_heap_head +.section .bss + _heap_head: .zero 8 + _heap_tail: .zero 8 + _environ: .zero 8 + +.section .text._builtin_heap_head _builtin_heap_head: - lea rax, [rel _heap_head] + lea rax, [rip + _heap_head] ret -section .text._builtin_heap_tail +.section .text._builtin_heap_tail _builtin_heap_tail: - lea rax, [rel _heap_tail] + lea rax, [rip + _heap_tail] ret -section .text._builtin_read64 +.section .text._builtin_read64 _builtin_read64: - mov rax, QWORD [rdi] + mov rax, QWORD PTR [rdi] ret -section .text._builtin_set64 +.section .text._builtin_set64 _builtin_set64: mov [rdi], rsi ret -section .text._builtin_cvtsi2sd +.section .text._builtin_cvtsi2sd _builtin_cvtsi2sd: cvtsi2sd xmm0, rdi movq rax, xmm0 ret -section .text._builtin_cvttsd2si +.section .text._builtin_cvttsd2si _builtin_cvttsd2si: cvttsd2si rax, xmm0 ret -section .text._builtin_f64_to_float +.section .text._builtin_f64_to_float _builtin_f64_to_float: cvtsd2ss xmm0, xmm0 movd eax, xmm0 ret -section .text._builtin_syscall +.section .text._builtin_syscall _builtin_syscall: mov rax, rdi mov rdi, rsi @@ -172,26 +174,26 @@ _builtin_syscall: emit!( &mut self.output, " -section .text._builtin_environ +.section .text._builtin_environ _builtin_environ: - lea rax, [rel _environ] + lea rax, [rip + _environ] mov rax, [rax] ret -global _start -section .text +.globl _start +.section .text _start: xor rbp, rbp - ; setup args + // setup args pop rdi mov rsi, rsp - ; save environ + // save environ lea rdx, [rsi + rdi*8 + 8] - lea rax, [rel _environ] + lea rax, [rip + _environ] mov [rax], rdx - ; align stack + // align stack and rsp, -16 - ; exit(main()) + // exit(main()) call main mov rdi, rax mov rax, 60 @@ -202,10 +204,10 @@ _start: emit!( &mut self.output, " -section .text._builtin_environ +.section .text._builtin_environ _builtin_environ: - extern environ - mov rax, [rel environ] + .extern environ + mov rax, [rip + environ] ret " ); @@ -239,7 +241,7 @@ _builtin_environ: self.compile_expr(env, initializer)?; let offset = env.define_var(name.lexeme.clone(), var_type); - emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset); + emit!(&mut self.output, " mov QWORD PTR [rbp-{}], rax", offset); } Stmt::Assign { left, op, value } => { self.compile_expr(env, value)?; @@ -250,7 +252,7 @@ _builtin_environ: let var = env.get_var(&name.lexeme).unwrap(); emit!( &mut self.output, - " mov QWORD [rbp-{}], rax", + " mov QWORD PTR [rbp-{}], rax", var.stack_offset, ); } @@ -266,7 +268,7 @@ _builtin_environ: emit!(&mut self.output, " pop rbx"); emit!(&mut self.output, " add rbx, rax"); emit!(&mut self.output, " pop rax"); - emit!(&mut self.output, " mov BYTE [rbx], al"); + emit!(&mut self.output, " mov BYTE PTR [rbx], al"); } ExprKind::MemberAccess { left, field } => { emit!(&mut self.output, " push rax"); @@ -275,7 +277,7 @@ _builtin_environ: self.compile_expr(env, left)?; emit!(&mut self.output, " pop rbx"); - emit!(&mut self.output, " mov QWORD [rax+{}], rbx", offset); + emit!(&mut self.output, " mov QWORD PTR [rax+{}], rbx", offset); } _ => return error!(&op.loc, "invalid assignment target"), }; @@ -302,7 +304,12 @@ _builtin_environ: env.define_var(target.lexeme.clone(), types[i].to_string()) } }; - emit!(&mut self.output, " mov QWORD [rbp-{}], {}", offset, reg); + emit!( + &mut self.output, + " mov QWORD PTR [rbp-{}], {}", + offset, + reg + ); } } Stmt::Const { .. } => { @@ -366,13 +373,10 @@ _builtin_environ: } => { let name = &name.lexeme; if self.emit_debug || *exported || name == "main" { - emit!( - &mut self.output, - "global {0}:function ({0}.end - {0})", - name - ); + emit!(&mut self.output, ".globl {0}", name); + emit!(&mut self.output, ".type {0}, @function", name); } - emit!(&mut self.output, "section .text.{}", name); + emit!(&mut self.output, ".section .text.{}", name); emit!(&mut self.output, "{}:", name); emit!(&mut self.output, " push rbp"); emit!(&mut self.output, " mov rbp, rsp"); @@ -388,15 +392,20 @@ _builtin_environ: param.var_type.lexeme.clone(), ); if let Some(reg) = REGISTERS.get(i) { - emit!(&mut self.output, " mov QWORD [rbp-{}], {}", offset, reg); + emit!( + &mut self.output, + " mov QWORD PTR [rbp-{}], {}", + offset, + reg + ); } else { let stack_offset = 16 + 8 * (i - REGISTERS.len()); emit!( &mut self.output, - " mov rax, QWORD [rbp+{}]", + " mov rax, QWORD PTR [rbp+{}]", stack_offset ); - emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset); + emit!(&mut self.output, " mov QWORD PTR [rbp-{}], rax", offset); } } } @@ -423,7 +432,7 @@ _builtin_environ: emit!(&mut self.output, " ret"); } - emit!(&mut self.output, ".end:"); + emit!(&mut self.output, ".size {0}, . - {0}", name); // patch the stack size after we know how much we actually need let patch = format!(" sub rsp, {:<10}", (env.next_offset + 15) & !15); @@ -465,21 +474,29 @@ _builtin_environ: let offset = env.define_var(var.lexeme.clone(), "i64".into()); self.compile_expr(env, start)?; - emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset); + emit!(&mut self.output, " mov QWORD PTR [rbp-{}], rax", offset); self.compile_expr(env, end)?; let end_offset = env.next_offset; env.next_offset += 8; - emit!(&mut self.output, " mov QWORD [rbp-{}], rax", end_offset); + emit!( + &mut self.output, + " mov QWORD PTR [rbp-{}], rax", + end_offset + ); emit!(&mut self.output, "{}:", env.loop_begin_label); - emit!(&mut self.output, " mov rax, QWORD [rbp-{}]", offset); - emit!(&mut self.output, " mov rcx, QWORD [rbp-{}]", end_offset); + emit!(&mut self.output, " mov rax, QWORD PTR [rbp-{}]", offset); + emit!( + &mut self.output, + " mov rcx, QWORD PTR [rbp-{}]", + end_offset + ); emit!(&mut self.output, " cmp rax, rcx"); emit!(&mut self.output, " jge {}", env.loop_end_label); self.compile_stmt(env, body)?; emit!(&mut self.output, "{}:", env.loop_continue_label); - emit!(&mut self.output, " mov rax, QWORD [rbp-{}]", offset); + emit!(&mut self.output, " mov rax, QWORD PTR [rbp-{}]", offset); emit!(&mut self.output, " add rax, 1"); - emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset); + emit!(&mut self.output, " mov QWORD PTR [rbp-{}], rax", offset); emit!(&mut self.output, " jmp {}", env.loop_begin_label); emit!(&mut self.output, "{}:", env.loop_end_label); env.pop_scope(); @@ -495,7 +512,7 @@ _builtin_environ: emit!(&mut self.output, " jmp {}", env.loop_continue_label); } Stmt::Extern(name) => { - emit!(&mut self.output, "extern {}", name.lexeme); + emit!(&mut self.output, ".extern {}", name.lexeme); } Stmt::Struct { .. } => { // handled in SymbolTable @@ -610,11 +627,8 @@ _builtin_environ: emit!(&mut self.output, " mov rax, {}", token.lexeme); } TokenType::FloatLiteral => { - emit!( - &mut self.output, - " mov rax, __float64__({})", - token.lexeme - ); + let value: f64 = token.lexeme.parse().unwrap(); + emit!(&mut self.output, " mov rax, {}", value.to_bits()); } TokenType::CharLiteral => { emit!( @@ -635,10 +649,10 @@ _builtin_environ: .chain(std::iter::once("0".into())) .collect::>() .join(","); - emit!(&mut self.data_section, " {} db {}", label, charcodes); + emit!(&mut self.data_section, " {}: .byte {}", label, charcodes); self.data_counter += 1; - emit!(&mut self.output, " mov rax, {}", label); + emit!(&mut self.output, " lea rax, [rip + {}]", label); } TokenType::True => { emit!(&mut self.output, " mov rax, 1"); @@ -679,7 +693,7 @@ _builtin_environ: let var = env.get_var(&name.lexeme).unwrap(); emit!( &mut self.output, - " mov rax, QWORD [rbp-{}]", + " mov rax, QWORD PTR [rbp-{}]", var.stack_offset, ); } @@ -767,12 +781,12 @@ _builtin_environ: self.compile_expr(env, index)?; emit!(&mut self.output, " pop rbx"); emit!(&mut self.output, " add rax, rbx"); - emit!(&mut self.output, " movzx rax, BYTE [rax]"); + emit!(&mut self.output, " movzx rax, BYTE PTR [rax]"); } ExprKind::AddrOf { op, expr } => match &expr.kind { ExprKind::Variable(name) => { if self.symbol_table.functions.contains_key(&name.lexeme) { - emit!(&mut self.output, " mov rax, {}", name.lexeme); + emit!(&mut self.output, " lea rax, [rip + {}]", name.lexeme); } else { let var = match env.get_var(&name.lexeme) { Some(x) => x, @@ -785,7 +799,7 @@ _builtin_environ: }; emit!( &mut self.output, - " lea rax, QWORD [rbp-{}]", + " lea rax, QWORD PTR [rbp-{}]", var.stack_offset, ); } @@ -821,7 +835,7 @@ _builtin_environ: ExprKind::MemberAccess { left, field } => { let offset = self.get_field_offset(left, field)?; self.compile_expr(env, left)?; - emit!(&mut self.output, " mov rax, QWORD [rax+{}]", offset); + emit!(&mut self.output, " mov rax, QWORD PTR [rax+{}]", offset); } ExprKind::Cast { expr, type_name: _ } => { self.compile_expr(env, expr)?; @@ -857,7 +871,11 @@ _builtin_environ: let mut int_idx = 0; for (i, arg_type) in arg_types.iter().enumerate().take(to_register) { let offset = 8 * (arg_count - 1 - i); - emit!(&mut self.output, " mov rax, QWORD [rsp + {}]", offset); + emit!( + &mut self.output, + " mov rax, QWORD PTR [rsp + {}]", + offset + ); if arg_type == "f64" { emit!(&mut self.output, " movq xmm{}, rax", fp_idx); fp_idx += 1; @@ -875,7 +893,7 @@ _builtin_environ: let offset = 8 * (arg_count - 1 - arg_idx); emit!( &mut self.output, - " mov rax, QWORD [rsp + {}]", + " mov rax, QWORD PTR [rsp + {}]", offset + 8 * i ); emit!(&mut self.output, " push rax"); diff --git a/src/main.rs b/src/main.rs index 125b484..0d82bd0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -50,7 +50,7 @@ fn compile_file(args: Args) -> Result<(), ZernError> { fs::write(format!("{out}.s"), codegen.get_output()).unwrap(); - run_command(format!("nasm -f elf64 -o {out}.o {out}.s")); + run_command(format!("as --64 -o {out}.o {out}.s")); if args.use_crt { run_command(format!( diff --git a/src/symbol_table.rs b/src/symbol_table.rs index 26b9456..6cd2876 100644 --- a/src/symbol_table.rs +++ b/src/symbol_table.rs @@ -75,8 +75,6 @@ impl SymbolTable { } let mut value = if value.lexeme.starts_with("0x") { u64::from_str_radix(&value.lexeme[2..], 16).unwrap() - } else if value.lexeme.starts_with("0o") { - u64::from_str_radix(&value.lexeme[2..], 8).unwrap() } else { value.lexeme.parse().unwrap() } as i64; diff --git a/src/tokenizer.rs b/src/tokenizer.rs index c91f413..0641cf2 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -345,10 +345,6 @@ impl Tokenizer { while self.peek().is_ascii_hexdigit() { self.advance(); } - } else if self.match_char('o') { - while matches!(self.peek(), '0'..='7') { - self.advance(); - } } else { while self.peek().is_ascii_digit() { self.advance(); @@ -412,7 +408,7 @@ impl Tokenizer { } if self.peek() != '"' { - return error!(self.loc, "expected '#' after 'include '"); + return error!(self.loc, "expected '\"' after 'include '"); } self.advance(); @@ -422,7 +418,7 @@ impl Tokenizer { } if self.eof() { - return error!(self.loc, "unterminated string after 'include'"); + return error!(self.loc, "unterminated string after 'include '"); } let path: String = self.source[path_start..self.current].iter().collect(); diff --git a/std/linux_constants.zr b/std/linux_constants.zr index 3513e42..6d41487 100644 --- a/std/linux_constants.zr +++ b/std/linux_constants.zr @@ -5,8 +5,8 @@ const SIGABRT = 6 const AT_FDCWD = -100 -const S_IFDIR = 0o040000 -const S_IFMT = 0o170000 +const S_IFDIR = 16384 +const S_IFMT = 61440 const PROT_READ = 1 const PROT_WRITE = 2 diff --git a/std/std.zr b/std/std.zr index a7ba1c5..92112ef 100644 --- a/std/std.zr +++ b/std/std.zr @@ -438,7 +438,7 @@ func io.write_file[path: str, content: str] : bool return io.write_binary_file(path, content as ptr, content->len()) func io.write_binary_file[path: str, content: ptr, size: i64] : bool - fd := _builtin_syscall(SYS_openat, AT_FDCWD, path, O_WRONLY|O_CREAT|O_TRUNC, 0o644) + fd := _builtin_syscall(SYS_openat, AT_FDCWD, path, O_WRONLY|O_CREAT|O_TRUNC, math.octal_to_decimal(644)) if fd < 0 return false @@ -901,6 +901,17 @@ func math.pow[b: i64, e: i64] : i64 func math.lcm[a: i64, b: i64] : i64 return (a / math.gcd(a, b)) * b +func math.octal_to_decimal[octal: i64] : i64 + decimal := 0 + base := 1 + + while octal > 0 + digit := octal % 10 + decimal += digit * base + base = base * 8 + octal = octal / 10 + return decimal + struct Blob data: ptr size: i64