Compare commits

..

No commits in common. "ae2cf5f9d3de3c0c056ba614d74eb039b2a23821" and "a90a01bc28b2ad4c99150f7699ba0b77e841f98d" have entirely different histories.

22 changed files with 128 additions and 1695 deletions

2
.gitignore vendored
View file

@ -1,4 +1,2 @@
/.direnv/ /.direnv/
lang/target lang/target
lang/libcompiler/target
/target/

39
Cargo.lock generated
View file

@ -1,39 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "cc"
version = "1.2.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3"
dependencies = [
"find-msvc-tools",
"shlex",
]
[[package]]
name = "find-msvc-tools"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127"
[[package]]
name = "libcompiler"
version = "0.1.0"
dependencies = [
"cc",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "typeck"
version = "0.1.0"
dependencies = [
"libcompiler",
]

View file

@ -1,7 +0,0 @@
[workspace]
resolver = "3"
members = [
"lang/libcompiler",
"lang/typeck",
]

View file

@ -1,9 +0,0 @@
[package]
name = "libcompiler"
version = "0.1.0"
edition = "2024"
[dependencies]
[build-dependencies]
cc = "1.0"

View file

@ -1,70 +0,0 @@
use std::path::Path;
fn main() {
let out_dir = std::env::var_os("OUT_DIR").unwrap();
let out_dir = Path::new(&out_dir);
let manifest_dir = std::env::var_os("CARGO_MANIFEST_DIR").unwrap();
let manifest_dir = Path::new(&manifest_dir);
let assembly_files = [
"src/alloc.asm",
"src/ast.asm",
"src/codegen.asm",
"src/vec.asm",
"src/tokeniser.asm",
"src/lib.asm",
"src/int_to_str.asm",
"src/file.asm",
];
let include_files = ["src/tokeniser.inc", "src/ast.inc"];
println!("cargo:rerun-if-changed=build.rs");
for file in assembly_files.iter().chain(include_files.iter()) {
println!(
"cargo:rerun-if-changed={}/{}",
manifest_dir.parent().unwrap().display(),
file
);
}
println!("cargo:rustc-link-search=native={}", out_dir.display());
let working_dir = manifest_dir.parent().unwrap();
for file in assembly_files.iter().map(|f| Path::new(f)) {
let path = working_dir.join(file);
let obj = file.with_extension("o").file_name().unwrap().to_owned();
let lib = format!("lib{}.a", file.file_stem().unwrap().to_str().unwrap());
std::process::Command::new("nasm")
.current_dir(working_dir)
.arg(path)
.arg("-g")
.arg("-f")
.arg("elf64")
.arg("-o")
.arg(out_dir.join(&obj))
.status()
.expect("Failed to assemble assembly files");
std::process::Command::new("ar")
.current_dir(working_dir)
.arg("crs")
.arg(out_dir.join(lib))
.arg(out_dir.join(obj))
.status()
.expect("Failed to create static library from object files");
println!(
"cargo:rustc-link-lib=static={}",
file.file_stem().unwrap().to_str().unwrap()
);
}
std::process::Command::new("../tools/asm2rust")
.current_dir(working_dir)
.args(&assembly_files)
.args(&include_files)
.arg("-o")
.arg(out_dir
.join("bindings.rs")
)
.status().expect("Failed to generate Rust bindings from assembly files");
}

View file

@ -1,612 +0,0 @@
#![feature(debug_closure_helpers)]
pub mod ffi {
#![allow(
non_camel_case_types,
dead_code,
non_upper_case_globals,
improper_ctypes
)]
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}
#[repr(C)]
#[derive(Debug, PartialEq, Eq)]
pub struct FFISlice {
pub ptr: *const u8,
pub len: usize,
}
#[repr(transparent)]
#[derive(Debug, PartialEq, Eq)]
pub struct MaybeFFISlice {
inner: FFISlice,
}
impl MaybeFFISlice {
pub fn is_none(&self) -> bool {
self.inner.ptr.is_null()
}
pub fn into_option(self) -> Option<FFISlice> {
if self.is_none() {
None
} else {
Some(self.inner)
}
}
}
impl FFISlice {
/// # Safety
/// The caller must ensure that the slice is valid for type T.
pub unsafe fn as_slice<T: Sized>(&self) -> &[T] {
// SAFETY: The caller ensures that the FFISlice is valid for type T.
unsafe { core::slice::from_raw_parts(self.ptr.cast(), self.len) }
}
pub fn as_bytes(&self) -> &[u8] {
// SAFETY: The FFISlice is guaranteed to be a valid byte slice.
unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
}
/// # Safety
/// The caller must ensure that the slice is a valid utf8 string.
pub unsafe fn as_str(&self) -> &str {
// SAFETY: The caller ensures that the FFISlice is a valid utf8 string.
unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
}
}
pub mod vec {
#![allow(dead_code)]
impl Default for BlobVec {
fn default() -> Self {
Self {
data: core::ptr::null_mut(),
len: 0,
cap: 0,
elem_size: 0,
drop: None,
}
}
}
unsafe impl Send for BlobVec {}
unsafe impl Sync for BlobVec {}
use super::ffi::*;
#[repr(transparent)]
#[derive(Debug)]
pub struct Vec<T> {
pub vec: BlobVec,
_marker: core::marker::PhantomData<T>,
}
impl<T> Default for Vec<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> Drop for Vec<T> {
fn drop(&mut self) {
// SAFETY: The vec is valid and owned by self.
unsafe {
vec_drop(&mut self.vec);
}
}
}
impl<T> Vec<T> {
pub fn new() -> Self {
Self::new_with(32)
}
pub fn new_with(capacity: usize) -> Self {
let mut vec = BlobVec {
data: core::ptr::null_mut(),
len: 0,
cap: 0,
elem_size: 0,
drop: None,
};
unsafe extern "C" fn drop_fn<T>(ptr: *mut ()) {
unsafe {
core::ptr::drop_in_place::<T>(ptr as *mut T);
}
}
unsafe {
vec_init_with(
&mut vec,
core::mem::size_of::<T>(),
Some(drop_fn::<T>),
capacity,
);
}
Self {
vec,
_marker: core::marker::PhantomData,
}
}
pub fn as_slice(&self) -> &[T] {
assert_eq!(self.vec.elem_size, core::mem::size_of::<T>());
unsafe { core::slice::from_raw_parts(self.vec.data as *const T, self.vec.len) }
}
pub fn as_slice_mut(&mut self) -> &mut [T] {
assert_eq!(self.vec.elem_size, core::mem::size_of::<T>());
unsafe { core::slice::from_raw_parts_mut(self.vec.data as *mut T, self.vec.len) }
}
pub fn extend(&mut self, elements: Box<[T]>) {
unsafe {
let elements =
core::mem::transmute::<Box<[T]>, Box<[core::mem::ManuallyDrop<T>]>>(elements);
vec_extend(&mut self.vec, elements.as_ptr() as *const _, elements.len());
}
}
pub fn push(&mut self, value: T) {
let value = core::mem::ManuallyDrop::new(value);
unsafe {
vec_push(&mut self.vec, &raw const value as *const T as *const _);
}
}
pub fn insert(&mut self, value: T, index: usize) {
if index > self.vec.len {
return;
}
let value = core::mem::ManuallyDrop::new(value);
unsafe {
vec_insert(
&mut self.vec,
index,
&raw const value as *const T as *const _,
);
}
}
pub fn insert_many(&mut self, index: usize, elements: Box<[T]>) {
unsafe {
let elements =
core::mem::transmute::<Box<[T]>, Box<[core::mem::ManuallyDrop<T>]>>(elements);
vec_insert_many(
&mut self.vec,
index,
elements.as_ptr() as *const _,
elements.len(),
);
}
}
pub fn pop(&mut self) -> Option<T> {
if self.vec.len == 0 {
return None;
}
unsafe {
let ptr = vec_get(&mut self.vec, self.vec.len - 1) as *mut T;
let value = ptr.read();
vec_pop(&mut self.vec);
Some(value)
}
}
pub fn get(&self, index: usize) -> Option<&T> {
if index >= self.vec.len {
return None;
}
unsafe {
let ptr = vec_get(&raw const self.vec as *mut _, index) as *mut T;
Some(&*ptr)
}
}
pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
if index >= self.vec.len {
return None;
}
unsafe {
let ptr = vec_get(&raw mut self.vec, index) as *mut T;
Some(&mut *ptr)
}
}
pub fn remove(&mut self, index: usize) {
if index >= self.vec.len {
return;
}
unsafe {
vec_remove(&mut self.vec, index);
}
}
pub fn len(&self) -> usize {
self.vec.len
}
pub fn is_empty(&self) -> bool {
self.vec.len == 0
}
pub fn position<F>(&self, elem: &T, mut cmp: F) -> Option<usize>
where
F: FnMut(&T, &T) -> bool,
{
extern "C" fn cmp_trampoline<T, F: FnMut(&T, &T) -> bool>(
f: *const (),
a: *const (),
b: *const (),
) -> bool {
let f = unsafe { &mut *(f as *mut F) };
let a = unsafe { &*(a as *const T) };
let b = unsafe { &*(b as *const T) };
f(a, b)
}
unsafe {
let index = vec_find(
&raw const self.vec as *mut _,
elem as *const T as *const _,
cmp_trampoline::<T, F>,
&raw mut cmp as *mut (),
);
if index == usize::MAX {
None
} else {
Some(index)
}
}
}
pub fn binary_search_by<F>(&self, elem: &T, mut cmp: F) -> Result<usize, usize>
where
F: FnMut(&T, &T) -> i32,
{
extern "C" fn cmp_trampoline<T, F: FnMut(&T, &T) -> i32>(
f: *const (),
a: *const (),
b: *const (),
) -> i32 {
let f = unsafe { &mut *(f as *mut F) };
let a = unsafe { &*(a as *const T) };
let b = unsafe { &*(b as *const T) };
f(a, b)
}
unsafe {
let (index, vacant) = vec_binary_search_by(
&raw const self.vec as *mut _,
elem as *const T as *const _,
cmp_trampoline::<T, F>,
&raw mut cmp as *mut (),
);
if vacant { Err(index) } else { Ok(index) }
}
}
pub fn insert_sorted<F>(&mut self, elem: T, mut cmp: F) -> Result<usize, usize>
where
F: FnMut(&T, &T) -> i32,
{
extern "C" fn cmp_trampoline<T, F: FnMut(&T, &T) -> i32>(
f: *const (),
a: *const (),
b: *const (),
) -> i32 {
let f = unsafe { &mut *(f as *mut F) };
let a = unsafe { &*(a as *const T) };
let b = unsafe { &*(b as *const T) };
f(a, b)
}
let mut elem = core::mem::ManuallyDrop::new(elem);
unsafe {
let (index, _inserted) = vec_insert_sorted(
&raw const self.vec as *mut _,
&raw mut elem as *const _,
cmp_trampoline::<T, F>,
&raw mut cmp as *mut (),
);
Ok(index)
}
}
}
}
mod display {
use super::ffi::{self, Ast, AstNode};
impl core::fmt::Display for AstNode {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
use crate::ffi::{
AST_ADDRESS_OF, AST_ARG, AST_AS, AST_ASSIGNMENT, AST_BINARY_OP, AST_BLOCK,
AST_CALL, AST_DEREF, AST_FUNCTION, AST_IF, AST_NUMBER, AST_PLACE_TO_VALUE,
AST_RETURN_STATEMENT, AST_VALUE_TO_PLACE, AST_VAR_DECL, AST_VAR_REF, BinaryExpr,
};
match self.kind {
AST_NUMBER => {
write!(f, "Number({})", self.data as usize)
}
AST_DEREF => {
write!(f, "Deref(expr: {})", self.data as usize)
}
AST_ADDRESS_OF => {
write!(f, "AddressOf(expr: {})", self.data as usize)
}
AST_CALL => {
let call = unsafe { self.data.cast::<crate::ffi::AstCallExpr>().read() };
write!(f, "Call(callee: {}, params: {:?})", call.callee, unsafe {
std::slice::from_raw_parts(call.params.cast::<u64>(), call.params_len)
},)
}
AST_AS => {
let as_expr = unsafe { self.data.cast::<crate::ffi::AstAsExpr>().read() };
write!(f, "As(expr: {}, target_type: {})", as_expr.expr, as_expr.ty)
}
AST_ARG => {
let arg = unsafe { self.data.cast::<crate::ffi::AstArgument>().read() };
write!(
f,
"Arg(name: {:?}, arg_type: {})",
unsafe {
std::str::from_utf8(std::slice::from_raw_parts(arg.name, arg.name_len))
},
arg.arg_type,
)
}
AST_VAR_REF => {
let var_ref = unsafe { self.data.cast::<crate::ffi::AstVarRef>().read() };
if var_ref.resolved != u64::MAX {
write!(f, "VarRef({})", var_ref.resolved)
} else {
write!(f, "VarRef(name: {:?})", unsafe {
std::str::from_utf8(std::slice::from_raw_parts(
var_ref.name,
var_ref.name_len,
))
},)
}
}
AST_VAR_DECL => {
let var_decl = unsafe { self.data.cast::<crate::ffi::AstVarDecl>().read() };
write!(
f,
"VarDecl(name: {:?}, var_type: {})",
unsafe {
std::str::from_utf8(std::slice::from_raw_parts(
var_decl.name,
var_decl.name_len,
))
},
var_decl.var_type,
)
}
AST_ASSIGNMENT => {
write!(
f,
"Assignment(dest: {}, src: {})",
self.data as usize, self.extra
)
}
AST_BINARY_OP => {
let BinaryExpr {
left,
operator,
right,
} = unsafe { self.data.cast::<crate::ffi::BinaryExpr>().read() };
write!(
f,
"BinaryOp(op: {}, left: {}, right: {})",
operator, left, right
)
}
AST_RETURN_STATEMENT => {
let return_expr_id = self.data as usize;
write!(f, "ReturnStatement(expr: {})", return_expr_id)
}
AST_FUNCTION => {
let func = unsafe { self.data.cast::<crate::ffi::AstFunction>().read() };
write!(
f,
"Function(name: {:?}, args: {:?}, return_type: {}, body: {})",
unsafe {
std::str::from_utf8(std::slice::from_raw_parts(
func.name,
func.name_len,
))
},
unsafe {
std::slice::from_raw_parts(func.args.cast::<u64>(), func.args_len)
},
func.return_type,
func.body
)
}
AST_BLOCK => {
write!(f, "Block(statements: {:?})", unsafe {
std::slice::from_raw_parts(self.data.cast::<u64>(), self.extra)
})
}
AST_IF => {
let if_node = unsafe { self.data.cast::<crate::ffi::AstIfExpr>().read() };
write!(
f,
"If(cond: {}, then_branch: {}, else_branch: {:?})",
if_node.condition,
if_node.then,
match if_node.else_ {
u64::MAX => None,
v => Some(v),
}
)
}
AST_PLACE_TO_VALUE => {
write!(f, "PlaceToValue(place: {})", self.data as usize)
}
AST_VALUE_TO_PLACE => {
write!(f, "ValueToPlace(value: {})", self.data as usize)
}
kind => write!(f, "UnknownNode(kind: {kind})"),
}
}
}
impl core::fmt::Display for Ast {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
writeln!(f, "[")?;
for (i, item) in self.nodes.as_slice().iter().enumerate() {
if i > 0 {
writeln!(f, ", ")?;
}
write!(f, "\t{i}: {}", item)?;
}
write!(f, "\n]")
}
}
impl core::fmt::Display for ffi::SymEntry {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("SymEntry")
.field_with("key", |f| {
f.debug_struct("Key")
.field_with("kind", |f| {
f.write_str(match self.key.kind {
ffi::SYM_KEY_SCOPE => "Scope",
ffi::SYM_KEY_SCOPE_NAME => "ScopeName",
ffi::SYM_KEY_PARENT_SCOPE => "ParentScope",
ffi::SYM_KEY_ARG => "Argument",
ffi::SYM_KEY_VAR => "Variable",
ffi::SYM_KEY_FUNCTION => "Function",
_ => "Unknown",
})
})
.field("scope", &self.key.scope_index)
.field("span", &self.key.span)
.field_with("ident", |f| {
f.write_str(unsafe {
core::str::from_utf8_unchecked(core::slice::from_raw_parts(
self.key.ident,
self.key.ident_len,
))
})
})
.finish()
})
.field_with("value", |f| {
let stct = &mut f.debug_struct("Value");
if self.extra == 0 {
stct.field("ast_index", &self.index).finish()
} else if self.index != 0 {
stct.field_with("ident", |f| {
f.write_str(unsafe {
core::str::from_utf8_unchecked(core::slice::from_raw_parts(
self.index as *const u8,
self.extra as usize,
))
})
})
.finish()
} else {
stct.field("index", &self.index)
.field("extra", &self.extra)
.finish()
}
})
.finish()
}
}
impl core::fmt::Display for ffi::Type {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
use ffi::{
TYPE_BOOL, TYPE_F32, TYPE_F64, TYPE_I8, TYPE_I16, TYPE_I32, TYPE_I64, TYPE_ISIZE,
TYPE_POINTER, TYPE_STR, TYPE_U8, TYPE_U16, TYPE_U32, TYPE_U64, TYPE_USIZE,
TYPE_VOID,
};
match self.kind {
TYPE_VOID => {
write!(f, "void")
}
TYPE_BOOL => {
write!(f, "bool")
}
TYPE_I32 => {
write!(f, "i32")
}
TYPE_U32 => {
write!(f, "u32")
}
TYPE_STR => {
write!(f, "str")
}
TYPE_POINTER => {
let pointee = unsafe { (self.data as *const ffi::Type).read() };
write!(f, "*{pointee}",)
}
TYPE_I8 => {
write!(f, "i8")
}
TYPE_U8 => {
write!(f, "u8")
}
TYPE_I16 => {
write!(f, "i16")
}
TYPE_U16 => {
write!(f, "u16")
}
TYPE_I64 => {
write!(f, "i64")
}
TYPE_U64 => {
write!(f, "u64")
}
TYPE_F32 => {
write!(f, "f32")
}
TYPE_F64 => {
write!(f, "f64")
}
TYPE_USIZE => {
write!(f, "usize")
}
TYPE_ISIZE => {
write!(f, "isize")
}
_ => {
write!(f, "UnknownType")
}
}
}
}
#[repr(transparent)]
pub struct Displayed<T: core::fmt::Display>(pub T);
impl<T: core::fmt::Display> core::fmt::Debug for Displayed<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.0)
}
}
pub trait DisplayedSliceExt {
type Displayed: core::fmt::Debug;
fn displayed(self) -> Self::Displayed;
}
impl<'a, T: core::fmt::Display> DisplayedSliceExt for &'a [T] {
type Displayed = &'a [Displayed<T>];
fn displayed(self) -> Self::Displayed {
unsafe { core::mem::transmute(self) }
}
}
}
pub use display::{Displayed, DisplayedSliceExt};

View file

@ -15,7 +15,6 @@ extern allocate
extern vec_init extern vec_init
extern vec_push extern vec_push
extern vec_get extern vec_get
extern vec_try_grow_with
global bump_init global bump_init
@ -30,21 +29,14 @@ mmap_alloc:
pop rbp pop rbp
ret ret
;; define-fn: fn bump_init()
bump_init: bump_init:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
mov rdi, 0x1000 lea rdi, [rel free_list]
call mmap_alloc mov rsi, 16
lea rdx, [rel free_list] mov rdx, 0
mov [rdx], rax call vec_init
mov qword [rdx + 8], 0 ; size 0
mov rax, 0x1000
shr rax, 4 ; capacity in blocks of 16 bytes
mov qword [rdx + 16], rax ; capacity
mov qword [rdx + 24], 16 ; elem_size = 16
mov qword [rdx + 32], 0 ; drop = None
pop rbp pop rbp
ret ret
@ -58,20 +50,6 @@ bump_new_block:
ja .mmap ja .mmap
mov rdi, 4096 mov rdi, 4096
.mmap: .mmap:
push rdi
lea rdi, [rel free_list]
mov rsi, [rdi + 8]
mov rax, rsi
shr rax, 1
add rax, 1
add rsi, rax
mov rdx, mmap_alloc
call vec_try_grow_with
pop rdi
; next power of 2 ; next power of 2
lea rax, [rdi - 1] lea rax, [rdi - 1]
lzcnt rax, rax lzcnt rax, rax
@ -97,38 +75,8 @@ bump_new_block:
pop rbp pop rbp
ret ret
;; rdi: num
;; rsi: multiple
next_multiple_of:
test rsi, rsi
je .l1
mov rax, rdi
or rax, rsi
shr rax, 32
je .l2
mov rax, rdi
xor edx, edx
div rsi
jmp .l3
.l2:
mov eax, edi
xor edx, edx
div esi
.l3:
sub rsi, rdx
test rdx, rdx
cmove rsi, rdx
add rsi, rdi
mov rax, rsi
ret
.l1:
mov rax, rdi
ret
;; rdi: number of bytes to allocate ;; rdi: number of bytes to allocate
;; rsi: alignment ;; rsi: alignment
;; define-fn: fn bump_alloc(size: usize, alignment: usize) -> *mut u8
bump_alloc: bump_alloc:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
@ -156,21 +104,25 @@ bump_alloc:
; check for space ; check for space
; block_ptr.next_multiple_of(alignment) + size <= block_ptr + block_size ; block_ptr.next_multiple_of(alignment) + size <= block_ptr + block_size
mov rdi, rdx mov rcx, [rsp + 8] ; alignment
mov rsi, [rsp + 8] ; alignment ; let ptr = block_ptr | alignment
call next_multiple_of or rax, rcx ; align up
; rax = aligned_ptr xor rdx, rdx ; clear high qword
; let rem = ptr % alignment
mov rdx, rax div rcx
add rdx, qword [rsp] ; ptr + size ; let diff = alignment - rem
; rdx = new_end sub rcx, rdx
mov rax, [rsp + 16] ; block+ptr
mov rcx, [rsp + 16] ; block_ptr ; let aligned_ptr = block_ptr + diff
add rcx, [rsp + 24] ; block_size add rax, rcx
; let aligned_end = aligned_ptr + size
cmp rdx, rcx add rax, [rsp] ; size
; let block_end = block_ptr + block_size
mov rdx, [rsp + 16] ; block_ptr
add rdx, [rsp + 24] ; block_ptr + block_size
; if aligned_end <= block_end
cmp rax, rdx
jle .found_space jle .found_space
; else try next block ; else try next block
inc r13 inc r13
jmp .alloc_loop jmp .alloc_loop
@ -184,17 +136,13 @@ bump_alloc:
dec r13 dec r13
jmp .alloc_loop jmp .alloc_loop
.found_space: .found_space:
mov r12, [rsp + 32] ; block entry ptr sub rdx, rax ; remaining size in block
mov rcx, [r12] ; block_ptr mov r13, [rsp + 32] ; block entry ptr
mov [r12], rdx ; update block_ptr mov [r13], rax
mov rax, [rsp + 24] ; block_size
; new_end - old_ptr sub rax, rdx
sub rdx, rcx mov [r13 + 8], rax
mov rax, [r13]
mov rcx, [r12 + 8] ; block_size
sub rcx, rdx
mov [r12 + 8], rcx
add rsp, 0x28 add rsp, 0x28
pop r13 pop r13
pop r12 pop r12

View file

@ -48,7 +48,6 @@ global parse_expr
global parse_binary_expr global parse_binary_expr
global parse_primary_expr global parse_primary_expr
global parse_if_expr global parse_if_expr
global parse_postfix_expr
global parse_statement global parse_statement
global parse_block global parse_block
global ast_build_symtable global ast_build_symtable
@ -315,191 +314,6 @@ parse_number:
.panic: .panic:
call panic call panic
;; rdi: *mut Ast
;; define-fn: fn parse_as_expr(ast: *mut Ast) -> (u64, bool)
parse_as_expr:
push rbp
mov rbp, rsp
; start-structs
; struct AstAsExpr {
; expr: u64,
; ty: Type,
; }
; end-structs
; Type [32..48]
; prefix_expr [16..32]
; span [8..16]
; ast [0..8]
sub rsp, 48
mov [rsp], rdi ; Ast
call parse_prefix_expr
mov [rsp + 16], rax ; prefix_expr
mov [rsp + 24], rdx ; placeness
call tokeniser_get_cursor
mov [rsp + 8], rax ; span
mov dil, TOKEN_AS
call expect_token
test rax, rax
jz .done
; convert prefix_expr to value
.as_expr:
mov rdi, [rsp] ; Ast
mov rsi, [rsp + 16] ; prefix_expr
mov dl, [rsp + 24] ; placeness
call ast_place_to_value
mov [rsp + 24], rax ; AstAsExpr.expr
; parse type
mov rdi, [rsp] ; Ast
call parse_type
mov [rsp + 32], rax ; AstAsExpr.Type.kind
mov [rsp + 40], rdx ; AstAsExpr.Type.data
mov rdi, 16 ; size_of::<AstAsExpr>
mov rsi, 8 ; align_of::<AstAsExpr>
call bump_alloc
mov rdi, rax ; dst
lea rsi, [rsp + 24] ; &AstAsExpr
mov rdx, 16 ; size_of::<AstAsExpr>
call memcpy
mov qword [rsp + 16], AST_AS ; AstNode.kind
mov [rsp + 24], rdi ; AstNode.data
mov qword [rsp + 32], 0 ; AstNode.extra
mov rdi, [rsp + 8] ; span
mov [rsp + 40], rdi ; AstNode.span
mov rdi, [rsp] ; Ast
lea rsi, [rsp + 16] ; &AstNode
call vec_push
; rax = index of pushed node
mov rdx, 0 ; placeness = false
jmp .epilogue
.done:
mov rax, [rsp + 16] ; prefix_expr
mov rdx, [rsp + 24] ; placeness
.epilogue:
add rsp, 48
pop rbp
ret
;; rdi: *mut Ast
;; define-fn: fn parse_postfix_expr(ast: *mut Ast) -> (u64, bool)
parse_postfix_expr:
push rbp
mov rbp, rsp
push rbx
; scratch [64..80]
; params: Vec [24..64]
; expr [16..24]
; span: u64 [8..16]
; ast [0..8]
sub rsp, 80
mov [rsp], rdi ; Ast
call parse_primary_expr
mov [rsp + 16], rax ; expr
mov [rsp + 24], rdx ; placeness
call tokeniser_get_cursor
mov [rsp + 8], rax ; span
mov dil, TOKEN_LPARENS
call expect_token
test rax, rax
jnz .call_expr
mov rax, [rsp + 16] ; expr
mov rdx, [rsp + 24] ; placeness
jmp .epilogue
.call_expr:
; start-structs
; struct AstCallExpr {
; callee: u64,
; params: *const u64,
; params_len: usize,
; }
; end-structs
; scratch [64..80]
; params: Vec [24..64]
mov rdi, [rsp] ; Ast
mov rsi, [rsp + 16] ; callee
mov rdx, [rsp + 24] ; placeness
call ast_place_to_value
mov [rsp + 16], rax ; callee
lea rdi, [rsp + 24] ; params
mov rsi, 8 ; size of u64
mov rdx, 0 ; drop = None
mov rcx, 16 ; capacity
call vec_init_with
.params_loop:
mov dil, TOKEN_RPARENS
call expect_token
test rax, rax
jnz .params_done
mov rdi, [rsp] ; Ast
call parse_expr
mov rdi, [rsp] ; Ast
mov rsi, rax ; expr
call ast_place_to_value
mov [rsp + 64], rax ; value
lea rdi, [rsp + 24] ; params
lea rsi, [rsp + 64] ; &value
call vec_push
mov dil, TOKEN_COMMA
call expect_token
test rax, rax
jz .close_parens
jmp .params_loop
.close_parens:
mov dil, TOKEN_RPARENS
call unwrap_token
.params_done:
mov rdi, 24 ; size_of::<AstCallExpr>
mov rsi, 8 ; align_of::<AstCallExpr>
call bump_alloc
mov rdi, rax ; dst
lea rsi, [rsp + 16] ; &callee
mov rdx, 24 ; size_of::<AstCallExpr>
call memcpy
mov [rsp + 16], rdi ; AstNode.data = *AstCallExpr
mov qword [rsp + 24], 0 ; AstNode.extra = 0
mov rax, [rsp + 8] ; span
mov [rsp + 32], rax ; AstNode.span
mov qword [rsp + 8], AST_CALL ; AstNode.kind
mov rdi, [rsp] ; Ast
lea rsi, [rsp + 8] ; &AstNode
call vec_push
mov rdi, [rsp] ; Ast
mov rax, [rdi + 8] ; return Ast.nodes.len()
dec rax
mov rdx, 0 ; placeness = false
.epilogue:
add rsp, 80
pop rbx
pop rbp
ret
;; rdi: *mut Ast ;; rdi: *mut Ast
;; define-fn: fn parse_primary_expr(ast: *mut Ast) -> (u64, bool) ;; define-fn: fn parse_primary_expr(ast: *mut Ast) -> (u64, bool)
parse_primary_expr: parse_primary_expr:
@ -625,7 +439,7 @@ parse_binary_expr:
call tokeniser_get_cursor call tokeniser_get_cursor
mov [rsp + 56], rax ; span mov [rsp + 56], rax ; span
call parse_as_expr call parse_prefix_expr
mov [rsp + 8], rax ; left mov [rsp + 8], rax ; left
mov [rsp + 19], dl ; left_placeness mov [rsp + 19], dl ; left_placeness
@ -649,11 +463,11 @@ parse_binary_expr:
cmove bx, word [rel PRECEDENCE_EQ] cmove bx, word [rel PRECEDENCE_EQ]
cmp al, TOKEN_LT cmp al, TOKEN_LT
cmove bx, word [rel PRECEDENCE_CMP] cmove bx, word [rel PRECEDENCE_CMP]
cmp al, TOKEN_LEQ cmp al, TOKEN_LTEQ
cmove bx, word [rel PRECEDENCE_CMP] cmove bx, word [rel PRECEDENCE_CMP]
cmp al, TOKEN_GT cmp al, TOKEN_GT
cmove bx, word [rel PRECEDENCE_CMP] cmove bx, word [rel PRECEDENCE_CMP]
cmp al, TOKEN_GEQ cmp al, TOKEN_GTEQ
cmove bx, word [rel PRECEDENCE_CMP] cmove bx, word [rel PRECEDENCE_CMP]
cmp bx, -1 cmp bx, -1
je .done je .done
@ -908,62 +722,12 @@ parse_type:
je .bool_type je .bool_type
cmp al, TOKEN_STAR cmp al, TOKEN_STAR
je .pointer_type je .pointer_type
cmp al, TOKEN_U8
je .u8_type
cmp al, TOKEN_I8
je .i8_type
cmp al, TOKEN_U16
je .u16_type
cmp al, TOKEN_I16
je .i16_type
cmp al, TOKEN_U64
je .u64_type
cmp al, TOKEN_I64
je .i64_type
cmp al, TOKEN_F32
je .f32_type
cmp al, TOKEN_F64
je .f64_type
cmp al, TOKEN_USIZE
je .usize_type
cmp al, TOKEN_ISIZE
je .isize_type
jmp .panic jmp .panic
.u8_type:
mov rax, TYPE_U8
jmp .epilogue
.i8_type:
mov rax, TYPE_I8
jmp .epilogue
.u16_type:
mov rax, TYPE_U16
jmp .epilogue
.i16_type:
mov rax, TYPE_I16
jmp .epilogue
.u32_type:
mov rax, TYPE_U32
jmp .epilogue
.i32_type: .i32_type:
mov rax, TYPE_I32 mov rax, TYPE_I32
jmp .epilogue jmp .epilogue
.u64_type: .u32_type:
mov rax, TYPE_U64 mov rax, TYPE_U32
jmp .epilogue
.i64_type:
mov rax, TYPE_I64
jmp .epilogue
.usize_type:
mov rax, TYPE_USIZE
jmp .epilogue
.isize_type:
mov rax, TYPE_ISIZE
jmp .epilogue
.f32_type:
mov rax, TYPE_F32
jmp .epilogue
.f64_type:
mov rax, TYPE_F64
jmp .epilogue jmp .epilogue
.void_type: .void_type:
mov rax, TYPE_VOID mov rax, TYPE_VOID
@ -1018,7 +782,7 @@ parse_prefix_expr:
jnz .address_of jnz .address_of
mov rdi, [rsp] ; Ast mov rdi, [rsp] ; Ast
call parse_postfix_expr call parse_primary_expr
jmp .done jmp .done
.dereference: .dereference:
mov rdi, [rsp] ; Ast mov rdi, [rsp] ; Ast
@ -1429,11 +1193,11 @@ symkey_cmp:
mov [rsp], rsi mov [rsp], rsi
mov [rsp + 8], rdx mov [rsp + 8], rdx
; mov al, byte [rsi] ; a.kind mov al, byte [rsi] ; a.kind
; mov bl, byte [rdx] ; b.kind mov bl, byte [rdx] ; b.kind
; cmp al, bl cmp al, bl
; jl .a_less jl .a_less
; jg .a_greater jg .a_greater
mov rax, [rsi + 8] ; a.scope_index mov rax, [rsi + 8] ; a.scope_index
mov rbx, [rdx + 8] ; b.scope_index mov rbx, [rdx + 8] ; b.scope_index
@ -1452,12 +1216,6 @@ symkey_cmp:
mov rsi, [rsp] mov rsi, [rsp]
mov rdx, [rsp + 8] mov rdx, [rsp + 8]
mov al, byte [rsi] ; a.kind
mov bl, byte [rdx] ; b.kind
cmp al, bl
jl .a_less
jg .a_greater
mov rax, [rsi + 16] ; a.span mov rax, [rsi + 16] ; a.span
mov rbx, [rdx + 16] ; b.span mov rbx, [rdx + 16] ; b.span
cmp rax, rbx cmp rax, rbx
@ -1483,10 +1241,9 @@ section .rdata
SYM_KEY_SCOPE_NAME equ 2 ; :u8 SYM_KEY_SCOPE_NAME equ 2 ; :u8
SYM_KEY_PARENT_SCOPE equ 3 ; :u8 SYM_KEY_PARENT_SCOPE equ 3 ; :u8
SYM_KEY_START_LOCALS equ 4 ; :u8 SYM_KEY_START_LOCALS equ 4 ; :u8
SYM_KEY_FUNCTION equ 5 ; :u8 SYM_KEY_ARG equ 5 ; :u8
SYM_KEY_ARG equ 6 ; :u8 SYM_KEY_VAR equ 6 ; :u8
SYM_KEY_VAR equ 7 ; :u8 SYM_KEY_END_LOCALS equ 7 ; :u8
SYM_KEY_END_LOCALS equ 8 ; :u8
;; end-consts ;; end-consts
section .text section .text
@ -1638,29 +1395,9 @@ ast_build_symtable_for_each:
jmp .insert_scope jmp .insert_scope
.func: .func:
mov rbx, [rax + 8] ; AstNode.data
; insert function symbol
mov byte [rsp + 32], SYM_KEY_FUNCTION ; SymKey.kind
mov rdx, [rsp + 88] ; index
mov qword [rsp + 40], rdx ; SymKey.scope_index
mov rdx, [rax + 24] ; AstNode.span
mov qword [rsp + 48], rdx ; SymKey.span
mov rdx, [rbx + 0] ; Func.name
mov rcx, [rbx + 8] ; Func.name_len
mov [rsp + 56], rdx ; SymKey.ident
mov [rsp + 64], rcx ; SymKey.ident_len
mov rdx, [rsp + 16] ; index
mov [rsp + 72], rdx ; SymEntry.index
mov qword [rsp + 80], 0 ; SymEntry.extra
mov rdi, [rsp + 8] ; Ctx.symtable
lea rsi, [rsp + 32] ; &SymEntry
mov rcx, 0 ; cmp_ctx
mov rdx, symkey_cmp ; cmp
call vec_insert_sorted
; use function name as scope name ; use function name as scope name
mov rbx, [rax + 8] ; AstNode.data
mov rdx, [rbx + 0] ; Func.name mov rdx, [rbx + 0] ; Func.name
mov rcx, [rbx + 8] ; Func.name_len mov rcx, [rbx + 8] ; Func.name_len
@ -1670,13 +1407,12 @@ ast_build_symtable_for_each:
.insert_scope: .insert_scope:
; insert scope entry ; insert scope entry
mov byte [rsp + 32], SYM_KEY_SCOPE ; SymKey.kind mov byte [rsp + 32], SYM_KEY_SCOPE ; SymKey.kind
mov rdx, [rsp + 16] ; index mov rdx, [rsp + 16] ; index
mov qword [rsp + 40], rdx ; SymKey.scope_index mov qword [rsp + 40], rdx ; SymKey.scope_index
mov rax, [rsp + 24] ; *AstNode mov rdx, [rax + 24] ; AstNode.span
mov rdx, [rax + 24] ; AstNode.span mov qword [rsp + 48], rdx ; SymKey.span
mov qword [rsp + 48], rdx ; SymKey.span mov qword [rsp + 56], 1 ; SymKey.ident
mov qword [rsp + 56], 1 ; SymKey.ident mov qword [rsp + 64], 0 ; SymKey.ident_len
mov qword [rsp + 64], 0 ; SymKey.ident_len
mov rdi, [rsp + 8] ; Ctx.symtable mov rdi, [rsp + 8] ; Ctx.symtable
lea rsi, [rsp + 32] ; &SymEntry lea rsi, [rsp + 32] ; &SymEntry
@ -1851,35 +1587,6 @@ ast_walk_for_each:
je .return_statement je .return_statement
cmp bl, AST_IF cmp bl, AST_IF
je .if_expr je .if_expr
cmp bl, AST_CALL
je .call
cmp bl, AST_AS
je .as_expr
jmp .check_scope
.as_expr:
mov rbx, [rax + 8] ; AstNode.data = *AstAsExpr
mov rax, [rbx + 0] ; AstCallExpr.expr
push rax ; push expr index
jmp .check_scope
.call:
mov rbx, [rax + 8] ; AstNode.data = *AstCallExpr
mov rax, [rbx + 0] ; AstCallExpr.callee
push rax ; push callee index
mov r15, [rbx + 16] ; AstCallExpr.args_len
xor r14, r14 ; index
.call_params:
cmp r14, r15
jge .call_params_done
mov rdx, [rbx + 8] ; AstCallExpr.args
lea rdx, [rdx + r14*8]
mov rax, [rdx] ; arg index
push rax ; push arg index
inc r14
jmp .call_params
.call_params_done:
jmp .check_scope jmp .check_scope
.func: .func:
@ -2079,11 +1786,6 @@ ast_resolve_var_refs_for_each:
call vec_get call vec_get
mov rbx, rax ; *SymEntry mov rbx, rax ; *SymEntry
; check symbol entry kind
mov al, byte [rbx + 0] ; SymEntry.key.kind
cmp al, SYM_KEY_START_LOCALS
jb .parent
; compare symbol ident with var_ref ident ; compare symbol ident with var_ref ident
mov rdi, [rbx + 24] ; SymEntry.key.ident mov rdi, [rbx + 24] ; SymEntry.key.ident
mov rsi, [rbx + 32] ; SymEntry.key.ident_len mov rsi, [rbx + 32] ; SymEntry.key.ident_len
@ -2139,7 +1841,6 @@ ast_resolve_var_refs_for_each:
ret ret
.panic: .panic:
call panic call panic
;; } ast_resolve_var_refs_for_each
;; rdi: Ast ;; rdi: Ast
;; rsi: *mut SymbolTable ;; rsi: *mut SymbolTable

View file

@ -18,22 +18,11 @@ section .rdata
AST_IF equ 16 ; :u8 AST_IF equ 16 ; :u8
AST_ELSE equ 17 ; :u8 AST_ELSE equ 17 ; :u8
AST_CALL equ 18 ; :u8 AST_CALL equ 18 ; :u8
AST_AS equ 19 ; :u8
TYPE_VOID equ 1 ; :u8 TYPE_VOID equ 1 ; :u8
TYPE_BOOL equ 2 ; :u8 TYPE_BOOL equ 2 ; :u8
TYPE_U8 equ 3 ; :u8 TYPE_I32 equ 3 ; :u8
TYPE_U16 equ 4 ; :u8 TYPE_U32 equ 4 ; :u8
TYPE_U32 equ 5 ; :u8 TYPE_STR equ 5 ; :u8
TYPE_U64 equ 6 ; :u8 TYPE_POINTER equ 6 ; :u8
TYPE_USIZE equ 7 ; :u8
TYPE_I8 equ 8 ; :u8
TYPE_I16 equ 9 ; :u8
TYPE_I32 equ 10 ; :u8
TYPE_I64 equ 11 ; :u8
TYPE_ISIZE equ 12 ; :u8
TYPE_STR equ 13 ; :u8
TYPE_POINTER equ 14 ; :u8
TYPE_F32 equ 15 ; :u8
TYPE_F64 equ 16 ; :u8
;; end-consts ;; end-consts

View file

@ -376,7 +376,7 @@ codegen_allocate_stack_value:
mov rsi, 0xF mov rsi, 0xF
not rsi not rsi
and rax, rsi ; clear kind to make it a value and rax, rsi ; clear kind to make it a value
or rax, OPERAND_RBP_VALUE ; Operand.kind = OPERAND_RBP_VALUE and rax, OPERAND_RBP_VALUE ; Operand.kind = OPERAND_RBP_VALUE
pop rbp pop rbp
ret ret
@ -971,243 +971,6 @@ codegen_block:
pop rbp pop rbp
ret ret
;; rdi: ctx
;; rsi: &function_ctx
;; rdx: *AstCallExpr
;; define-fn: fn codegen_call_expr(ctx: *const CodegenCtx, function_ctx: &FunctionCtx, call_expr: *const AstCallExpr) -> (u64, bool)
codegen_call_expr:
push rbp
mov rbp, rsp
push rbx
push r15
push r14
; scratch [80..112]
; callee_operand [64..80]
; param_operands [24..64]
; *AstCallExpr [16..24]
; function_ctx [8..16]
; ctx [0..8]
sub rsp, 112
mov [rsp], rdi ; ctx
mov [rsp + 8], rsi ; &function_ctx
mov [rsp + 16], rdx ; *AstCallExpr
mov rbx, rdx ; copy of *AstCallExpr
; initialize param_operands
lea rdi, [rsp + 24] ; param_operands
mov rsi, 16 ; size_of::<Operand>
mov rdx, 0 ; drop = None
mov rcx, 16 ; initial capacity
call vec_init_with
; codegen callee
mov rdx, [rbx + 0] ; AstCallExpr.callee
mov rdi, [rsp] ; ctx
mov rsi, [rsp + 8] ; &function_ctx
call codegen_expr
mov [rsp + 64], rax ; callee operand
mov [rsp + 72], rdx
; If callee is in a param-register, move to stack
cmp al, OPERAND_REGISTER
jne .arg_loop_init
mov rdx, 0b00000011_00111100
movzx rcx, byte [rsp + 64 + 1] ; callee register
bt rdx, rcx
jnc .arg_loop_init
; allocate stack slot
mov rdi, [rsp + 8] ; &function_ctx
movzx rsi, word [rsp + 64 + 2] ; Operand.width
call codegen_allocate_stack_value
mov [rsp + 80], rax ; new stack operand
mov [rsp + 88], rdx
; move from register to stack
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rsp + 80] ; dst
lea rdx, [rsp + 64] ; src
call codegen_move_dst_src
; free original callee operand
mov rdi, [rsp + 8] ; &function_ctx
lea rsi, [rsp + 64] ; callee operand
call codegen_free_operand
mov rax, [rsp + 80] ; callee operand = new stack operand
mov rdx, [rsp + 88]
mov [rsp + 64], rax
mov [rsp + 72], rdx
.arg_loop_init:
mov r15, [rbx + 16] ; AstCallExpr.args_len
xor r14, r14 ; arg index
.arg_loop:
cmp r14, r15
jge .arg_loop_done
mov rdx, [rbx + 8] ; AstCallExpr.args
lea rsi, [rdx + r14 * 8]
mov rdx, [rsi] ; arg ast index
mov rdi, [rsp] ; ctx
mov rsi, [rsp + 8] ; &function_ctx
call codegen_expr
mov [rsp + 80], rax ; param operand
mov [rsp + 88], rdx
; store param operand
; if the operand is in a register, move it to the stack
; we know already that these are values
cmp byte [rsp + 80], OPERAND_REGISTER
jne .store_param
; allocate stack slot
mov rdi, [rsp + 8] ; &function_ctx
movzx rsi, word [rsp + 80 + 2] ; Operand.width
call codegen_allocate_stack_value
mov [rsp + 96], rax ; new stack operand
mov [rsp + 104], rdx
; move from register to stack
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rsp + 96] ; dst
lea rdx, [rsp + 80] ; src
call codegen_move_dst_src
; free original param operand
mov rdi, [rsp + 8] ; &function_ctx
lea rsi, [rsp + 80] ; param operand
call codegen_free_operand
mov rax, [rsp + 96] ; param operand = new stack operand
mov rdx, [rsp + 104]
mov [rsp + 80], rax
mov [rsp + 88], rdx
.store_param:
; push param operand to param_operands
lea rdi, [rsp + 24] ; param_operands
lea rsi, [rsp + 80] ; &param operand
call vec_push
inc r14
jmp .arg_loop
.arg_loop_done:
; push volatile registers
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rsp + 8] ; &function_ctx
mov rdx, 0 ; pop = false
call codegen_push_pop_used_registers
; move params to appropriate registers/stack slots
; reverse order to allow freeing the allocated stack slots
mov r15, [rbx + 16] ; AstCallExpr.args_len
cmp r15, 6
jg .panic ; more than 6 params not supported yet
.param_move_loop:
dec r15
cmp r15, 0
jl .param_move_done
mov rdi, r15 ; param index
call codegen_arg_to_operand
mov [rsp + 80], rax ; target operand
mov [rsp + 88], rdx
lea rdi, [rsp + 24] ; param_operands
mov rsi, r15
call vec_get
mov r14, rax ; source operand
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rsp + 80] ; dst
mov rdx, r14 ; src
call codegen_move_dst_src
; free param operand
mov rdi, [rsp + 8] ; &function_ctx
mov rdx, r14 ; param operand
call codegen_free_operand
jmp .param_move_loop
.param_move_done:
; align stack
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rel ALIGN_STACK]
mov rdx, ALIGN_STACK_LEN
call vec_extend
; mov rax, rsp
; sub rsp, 8
; and rsp, -16
; mov [rsp], rax
; call callee
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rel CALL_]
mov rdx, CALL_LEN
call vec_extend
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rsp + 64] ; callee operand
call codegen_write_operand
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rel NEWLINE]
call vec_push
; de-align stack
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rel RESTORE_STACK]
mov rdx, RESTORE_STACK_LEN
call vec_extend
; free callee operand
mov rdi, [rsp + 8] ; &function_ctx
lea rsi, [rsp + 64] ; callee operand
call codegen_free_operand
; pop volatile registers
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rsp + 8] ; &function_ctx
mov rdx, 1 ; pop = true
call codegen_push_pop_used_registers
; allocate return value operand
mov rdi, [rsp + 8] ; &function_ctx
mov rsi, 8 ; size_of::<u64>
call codegen_allocate_value
mov [rsp + 80], rax ; return value operand
mov [rsp + 88], rdx
; mov dst, rax
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rsp + 80] ; dst
lea rdx, [rel OPERAND_RAX] ; src
call codegen_move_dst_src
; return return value operand
mov rax, [rsp + 80]
mov rdx, [rsp + 88]
add rsp, 112
pop r14
pop r15
pop rbx
pop rbp
ret
.panic:
call panic
;; rdi: ctx ;; rdi: ctx
;; rsi: &function_ctx ;; rsi: &function_ctx
;; rdx: expr index ;; rdx: expr index
@ -1259,17 +1022,8 @@ codegen_expr:
je .address_of je .address_of
cmp bl, AST_IF cmp bl, AST_IF
je .if_expr je .if_expr
cmp bl, AST_CALL
je .call_expr
jmp .panic jmp .panic
.call_expr:
mov rdx, [rax + 8] ; AstNode.data = *AstCallExpr
mov rdi, [rsp] ; ctx
mov rsi, [rsp + 8] ; &function_ctx
call codegen_call_expr
jmp .done
.if_expr: .if_expr:
mov rbx, [rax + 8] ; AstNode.data = *AstIfExpr mov rbx, [rax + 8] ; AstNode.data = *AstIfExpr
mov [rsp + 16], rax ; scratch = AstNode mov [rsp + 16], rax ; scratch = AstNode
@ -1860,29 +1614,9 @@ codegen_expr:
jmp .done jmp .done
.var_ref: .var_ref:
mov rbx, [rax + 8] ; AstNode.data mov rax, [rax + 8] ; AstNode.data
mov rax, [rbx] ; variable index mov rax, [rax] ; variable index
; check if we're trying to get a reference to a function
mov rdi, [rsp] ; ctx
mov rdi, [rdi] ; ast
mov rsi, rax ; variable index
call vec_get
cmp byte [rax], AST_FUNCTION
jne .var_ref_var
mov rax, [rax + 8] ; *AstFunction
; create label operand for function
mov rcx, [rel OPERAND_LABEL0]
movzx rdx, word [rax + 8] ; AstFunction.name_len
shl rdx, 32
or rcx, rdx
mov rdx, [rax + 0] ; AstFunction.name
mov rax, rcx
jmp .done
.var_ref_var:
mov rax, [rbx]
mov [rsp + 16], rax mov [rsp + 16], rax
mov qword [rsp + 24], 0 mov qword [rsp + 24], 0
; lookup variable in stack_vars ; lookup variable in stack_vars
@ -1922,9 +1656,6 @@ codegen_expr:
je .ptv_register_place je .ptv_register_place
cmp al, OPERAND_RBP_PLACE cmp al, OPERAND_RBP_PLACE
je .ptv_rbp_place je .ptv_rbp_place
cmp al, OPERAND_LABEL
je .done
jmp .panic
.ptv_rbp_offset: .ptv_rbp_offset:
mov byte [rsp + 16], OPERAND_RBP_PVALUE mov byte [rsp + 16], OPERAND_RBP_PVALUE
@ -2099,12 +1830,10 @@ codegen_expr:
;; register: u8, ;; register: u8,
;; width: u16, ;; width: u16,
;; len: u16, ;; len: u16,
;; align: u8,
;; bitset: u8,
;; value: u64, ;; value: u64,
;; } ;; }
;; end-structs ;; end-structs
;; bitset[0]: signed ;; or: register: u4, width: u4
section .rdata section .rdata
;; start-consts ;; start-consts
; Register containing a Value ; Register containing a Value
@ -2158,8 +1887,6 @@ section .rdata
OPERAND_RBP_P dq 0x0008_0009, 0 OPERAND_RBP_P dq 0x0008_0009, 0
align 8 align 8
OPERAND_ZERO dq 0x0001_000b, 0 OPERAND_ZERO dq 0x0001_000b, 0
align 8
OPERAND_LABEL0 dq 0x0008_000d, 0
section .text section .text
@ -2304,7 +2031,8 @@ codegen_write_operand:
mov rax, [rsp + 8] ; op mov rax, [rsp + 8] ; op
mov rdi, [rsp] ; *text mov rdi, [rsp] ; *text
mov rsi, [rax + 8] ; Operand.value mov rsi, [rax + 8] ; Operand.value
movzx rdx, word [rax + 4] ; Operand.len mov rdx, [rax + 4] ; Operand.len
mov dx, dx ; low 16 bits
call vec_extend call vec_extend
mov byte [rsp + 16], ']' mov byte [rsp + 16], ']'
@ -2332,18 +2060,13 @@ codegen_write_operand:
mov rax, [rsp + 8] ; op mov rax, [rsp + 8] ; op
mov rdi, [rsp] ; *text mov rdi, [rsp] ; *text
mov rsi, [rax + 8] ; op.value mov rsi, [rax + 8] ; op.value
movzx rdx, word [rax + 4] ; Operand.len mov rdx, [rax + 2] ; op.len
mov dx, dx ; low 16 bits
call vec_extend call vec_extend
jmp .epilogue jmp .epilogue
.label: .label:
; write address name jmp .panic
mov rax, [rsp + 8] ; op
mov rdi, [rsp] ; *text
mov rsi, [rax + 8] ; Operand.value
movzx rdx, word [rax + 4] ; Operand.len
call vec_extend
jmp .epilogue
.epilogue: .epilogue:
add rsp, 40 add rsp, 40
@ -2713,10 +2436,7 @@ codegen_move_dst_src:
mov cx, word [rsi + 2] ; dst.width mov cx, word [rsi + 2] ; dst.width
mov bx, word [rdx + 2] ; src.width mov bx, word [rdx + 2] ; src.width
cmp cx, bx cmp cx, bx
jb .panic ; dst.width < src.width jne .panic ; mismatched widths
je .width_ok
mov qword [rsp + 24], 'movzx '
.width_ok:
; ; if dst.width == 8 && src.kind == OPERAND_ADDRESS ; ; if dst.width == 8 && src.kind == OPERAND_ADDRESS
; xor rbx, rbx ; xor rbx, rbx
@ -2825,14 +2545,4 @@ section .rdata
JE_B_len equ $ - JE_B JE_B_len equ $ - JE_B
JMP_PHI dq "jmp .PHI" JMP_PHI dq "jmp .PHI"
JMP_PHI_len equ $ - JMP_PHI JMP_PHI_len equ $ - JMP_PHI
ALIGN_STACK db "mov rax, rsp", 10, "sub rsp, 8", 10, "and rsp, -16", 10, "mov [rsp], rax", 10
ALIGN_STACK_LEN equ $ - ALIGN_STACK
RESTORE_STACK db "pop rsp", 10
RESTORE_STACK_LEN equ $ - RESTORE_STACK
CALL_ dq "call "
CALL_LEN equ $ - CALL_
NEWLINE db 10
align 8
MOVZX_ dq "movzx "

View file

@ -62,7 +62,6 @@ section .text
;; rdi: pointer to buffer ;; rdi: pointer to buffer
;; rsi: length of buffer ;; rsi: length of buffer
;; define-fn: fn tokeniser_init_buf(buf: *const u8, buf_len: usize)
tokeniser_init_buf: tokeniser_init_buf:
push rbp push rbp
mov rbp, rsp mov rbp, rsp

View file

@ -8,7 +8,7 @@ extern memswap
extern oom extern oom
extern panic extern panic
extern eprint_str extern eprint_str
extern bump_alloc extern allocate
global vec_init global vec_init
global vec_init_with global vec_init_with
@ -26,8 +26,6 @@ global vec_insert
global vec_insert_many global vec_insert_many
global vec_insert_sorted global vec_insert_sorted
global vec_binary_search_by global vec_binary_search_by
global vec_try_grow
global vec_try_grow_with
global vec_tests global vec_tests
@ -35,11 +33,11 @@ global vec_tests
;; Byte vector structure ;; Byte vector structure
;; start-structs ;; start-structs
;; struct BlobVec { ;; struct BlobVec {
;; data: *mut (), ;; data: *mut u8,
;; len: usize, ;; len: usize,
;; cap: usize, ;; cap: usize,
;; elem_size: usize, ;; elem_size: usize,
;; drop: Option<unsafe extern "C" fn(*mut ())>, ;; drop: Option<extern "C" fn(*mut u8)>,
;; } ;; }
;; end-structs ;; end-structs
;; size: 40 bytes ;; size: 40 bytes
@ -50,7 +48,7 @@ global vec_tests
;; rdi: pointer to Vec struct ;; rdi: pointer to Vec struct
;; rsi: item_size ;; rsi: item_size
;; rdx: drop function pointer ;; rdx: drop function pointer
;; define-fn: fn vec_init(vec: *mut BlobVec, item_size: usize, drop: Option<unsafe extern "C" fn(*mut ())>) ;; fn vec_init(vec: *mut Vec, item_size: usize, drop: Option<fn(*mut u8)>)
vec_init: vec_init:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
@ -59,8 +57,7 @@ vec_init:
push rdi push rdi
; (*vec).data = allocate(INIT_CAPACITY); ; (*vec).data = allocate(INIT_CAPACITY);
mov rdi, INIT_CAPACITY mov rdi, INIT_CAPACITY
mov rsi, 8 call allocate
call bump_alloc
pop r15 pop r15
mov [r15], rax mov [r15], rax
; (*vec).len = 0; ; (*vec).len = 0;
@ -82,7 +79,7 @@ vec_init:
;; rsi: item_size ;; rsi: item_size
;; rdx: drop function pointer ;; rdx: drop function pointer
;; rcx: capacity ;; rcx: capacity
;; define-fn: fn vec_init_with(vec: *mut BlobVec, item_size: usize, drop: Option<unsafe extern "C" fn(*mut ())>, capacity: usize) ;; fn vec_init_with(vec: *mut Vec, item_size: usize, drop: Option<fn(*mut u8)>, capacity: usize)
vec_init_with: vec_init_with:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
@ -97,8 +94,7 @@ vec_init_with:
mov rax, rcx mov rax, rcx
mul rsi ; capacity * item_size mul rsi ; capacity * item_size
mov rdi, rax mov rdi, rax
mov rsi, 8 call allocate
call bump_alloc
pop r15 pop r15
mov [r15], rax mov [r15], rax
; (*vec).len = 0; ; (*vec).len = 0;
@ -116,7 +112,7 @@ vec_init_with:
;; rdi: pointer to Vec struct ;; rdi: pointer to Vec struct
;; rsi: index ;; rsi: index
;; rdx: pointer to default value ;; rdx: pointer to default value
;; define-fn: fn vec_get_or(vec: *mut BlobVec, index: usize, default: *mut ()) -> *mut () ;; fn vec_get(vec: *mut Vec, index: usize, default: *mut u8) -> *mut u8
vec_get_or: vec_get_or:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
@ -138,7 +134,7 @@ vec_get_or:
;; rdi: pointer to Vec struct ;; rdi: pointer to Vec struct
;; rsi: index ;; rsi: index
;; define-fn: fn vec_get(vec: *mut BlobVec, index: usize) -> *mut () ;; fn vec_get(vec: *mut Vec, index: usize) -> *mut u8
vec_get: vec_get:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
@ -161,8 +157,7 @@ vec_get:
;; rdi: pointer to Vec struct ;; rdi: pointer to Vec struct
;; rsi: pointer to data to push ;; rsi: pointer to data to push
;; returns the index at which the item was pushed (the old length of the vector) ;; fn vec_push(vec: *mut Vec, data: &[u8])
;; define-fn: fn vec_push(vec: *mut BlobVec, data: *const ()) -> usize
vec_push: vec_push:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
@ -187,16 +182,15 @@ vec_push:
mov rdx, [rax + 24] ; item_size mov rdx, [rax + 24] ; item_size
call memcpy call memcpy
; vec.len += 1; ; vec.len += 1;
mov rdx, [rsp] ; vec mov rax, [rsp] ; vec
mov rax, [rdx + 8] add qword [rax + 8], 1
add qword [rdx + 8], 1
add rsp, 24 add rsp, 24
pop rbp pop rbp
ret ret
;; rdi: pointer to Vec struct ;; rdi: pointer to Vec struct
;; define-fn: fn vec_pop(vec: *mut BlobVec) ;; fn vec_pop(vec: *mut Vec)
vec_pop: vec_pop:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
@ -216,7 +210,7 @@ vec_pop:
ret ret
;; rdi: pointer to Vec struct ;; rdi: pointer to Vec struct
;; define-fn: fn vec_drop_last(vec: *mut BlobVec) ;; fn vec_pop(vec: *mut Vec)
vec_drop_last: vec_drop_last:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
@ -250,7 +244,7 @@ vec_drop_last:
;; rdi: pointer to Vec struct ;; rdi: pointer to Vec struct
;; rsi: index a ;; rsi: index a
;; rdx: index b ;; rdx: index b
;; define-fn: fn vec_swap(vec: *mut BlobVec, a: usize, b: usize) ;; fn vec_swap(vec: *mut Vec, a: usize, b: usize)
vec_swap: vec_swap:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
@ -297,7 +291,7 @@ vec_swap:
;; rdi: pointer to Vec struct ;; rdi: pointer to Vec struct
;; rsi: index ;; rsi: index
;; define-fn: fn vec_remove(vec: *mut BlobVec, index: usize) ;; fn vec_remove(vec: *mut Vec, index: usize)
vec_remove: vec_remove:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
@ -343,18 +337,8 @@ vec_remove:
;; essentially a reserve() function ;; essentially a reserve() function
;; rdi: pointer to Vec struct ;; rdi: pointer to Vec struct
;; rsi: desired size ;; rsi: desired size
;; define-fn: fn vec_try_grow(vec: *mut BlobVec, new_size: usize) -> bool ;; fn vec_try_grow(vec: *mut Vec, new_size: usize) -> bool
vec_try_grow: vec_try_grow:
mov rdx, bump_alloc
call vec_try_grow_with
ret
;; essentially a reserve() function
;; rdi: pointer to Vec struct
;; rsi: desired size
;; rdx: allocate function pointer
;; define-fn: fn vec_try_grow_with(vec: *mut BlobVec, new_size: usize, alloc: unsafe extern "C" fn(usize, usize) -> *const ()) -> bool
vec_try_grow_with:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
push rbx push rbx
@ -382,8 +366,7 @@ vec_try_grow_with:
mul qword [rdi + 24] ; new_capacity * item_size mul qword [rdi + 24] ; new_capacity * item_size
; new_data = allocate(new_capacity); ; new_data = allocate(new_capacity);
mov rdi, rax mov rdi, rax
mov rsi, 8 call allocate
call rdx
mov [rsp + 16], rax mov [rsp + 16], rax
mov rdi, [rsp] mov rdi, [rsp]
; memcpy(new_data, old_data, len * vec.item_size); ; memcpy(new_data, old_data, len * vec.item_size);
@ -407,7 +390,6 @@ vec_try_grow_with:
ret ret
;; rdi: pointer to Vec struct ;; rdi: pointer to Vec struct
;; define-fn: fn vec_drop(vec: *mut BlobVec)
vec_drop: vec_drop:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
@ -450,7 +432,6 @@ vec_drop:
;; rsi: poiter to object to find ;; rsi: poiter to object to find
;; rdx: compare function fn(ctx: *const (), a: *const T, b: *const T) -> bool ;; rdx: compare function fn(ctx: *const (), a: *const T, b: *const T) -> bool
;; rcx: compare_fn context ;; rcx: compare_fn context
;; define-fn: fn vec_find(vec: *mut BlobVec, object: *const (), compare: unsafe extern "C" fn(ctx: *const (), a: *const (), b: *const ()) -> bool, ctx: *const ()) -> usize
vec_find: vec_find:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
@ -502,7 +483,7 @@ vec_find:
;; rdi: pointer to Vec struct ;; rdi: pointer to Vec struct
;; rsi : index ;; rsi : index
;; rdx: pointer to data to insert ;; rdx: pointer to data to insert
;; define-fn: fn vec_insert(vec: *mut BlobVec, index: usize, data: *const ()) ;; fn vec_insert(vec: *mut Vec, index: usize, data: *const T)
vec_insert: vec_insert:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
@ -554,7 +535,7 @@ vec_insert:
;; rsi : index ;; rsi : index
;; rdx: pointer to data to insert ;; rdx: pointer to data to insert
;; rcx: count ;; rcx: count
;; define-fn: fn vec_insert_many(vec: *mut BlobVec, index: usize, data: *const (), count: usize) ;; define-fn: fn vec_insert_many(vec: *mut BlobVec, index: usize, data: *const u8, count: usize)
vec_insert_many: vec_insert_many:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
@ -614,7 +595,7 @@ vec_insert_many:
;; rsi: pointer to key ;; rsi: pointer to key
;; rdx: compare function fn(ctx: *const (), a: *const T, b: *const T) -> i32 ;; rdx: compare function fn(ctx: *const (), a: *const T, b: *const T) -> i32
;; rcx: compare_fn context ;; rcx: compare_fn context
;; define-fn: fn vec_binary_search_by(vec: *mut BlobVec, key: *const (), compare: unsafe extern "C" fn(ctx: *const (), a: *const (), b: *const ()) -> i32, ctx: *const ()) -> (usize, bool) ;;fn vec_binary_search_by(vec: *mut Vec, key: *const T, compare: fn(ctx: *const (), a: *const T, b: *const T) -> i32, ctx: *const ()) -> (usize, bool)
vec_binary_search_by: vec_binary_search_by:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
@ -686,7 +667,7 @@ vec_binary_search_by:
;; rsi: pointer to key ;; rsi: pointer to key
;; rdx: compare function fn(ctx: *const (), a: *const T, b: *const T) -> i32 ;; rdx: compare function fn(ctx: *const (), a: *const T, b: *const T) -> i32
;; rcx: compare_fn context ;; rcx: compare_fn context
;;define-fn: fn vec_insert_sorted(vec: *mut BlobVec, key: *const (), compare: unsafe extern "C" fn(ctx: *const (), a: *const (), b: *const ()) -> i32, ctx: *const ()) -> (usize, bool) ;;fn vec_insert_sorted(vec: *mut Vec, key: *const T, compare: fn(ctx: *const (), a: *const T, b: *const T) -> i32, ctx: *const ()) -> (usize, bool)
vec_insert_sorted: vec_insert_sorted:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
@ -713,9 +694,9 @@ vec_insert_sorted:
ret ret
;; rdi: *Vec ;; rdi: *Vec
;; rsi: *const () ;; rsi: *const u8
;; rdx: number of elements ;; rdx: number of elements
;; define-fn: fn vec_extend(vec: *mut BlobVec, elements: *const (), count: usize) -> () ;; define-fn: fn vec_extend(vec: *mut BlobVec, elements: *const u8, count: usize) -> ()
vec_extend: vec_extend:
push rbp push rbp
mov rbp, rsp mov rbp, rsp

View file

@ -231,7 +231,7 @@ def parse_file(path: Path) -> Dict[str, Any]:
def render_rust(function_sigs: List[str], consts: List[Tuple[str, str, str]], def render_rust(function_sigs: List[str], consts: List[Tuple[str, str, str]],
structs: List[Tuple[str, List[str]]], rust_blocks: List[List[str]]) -> str: structs: List[Tuple[str, List[str]]], rust_blocks: List[List[str]]) -> str:
parts: List[str] = [] parts: List[str] = []
# parts.append('#![allow(non_camel_case_types, dead_code, non_upper_case_globals, improper_ctypes)]') parts.append('#![allow(non_camel_case_types, dead_code, non_upper_case_globals, improper_ctypes)]')
parts.append('// Auto-generated Rust bindings from assembly source\n') parts.append('// Auto-generated Rust bindings from assembly source\n')
# Functions: wrap in single extern "C" block if any # Functions: wrap in single extern "C" block if any

View file

@ -86,54 +86,39 @@ fn main() {
b"fn main(a: u32) -> void { let x: u32 = a + 4; }", b"fn main(a: u32) -> void { let x: u32 = a + 4; }",
|ast| unsafe { parse_func(ast) }, |ast| unsafe { parse_func(ast) },
); );
print_ast(
b"fn main(a: u32) -> void {
let y: u32 = a + 4;
let y: *u32 = &y;
return *y;
}",
|ast| unsafe { parse_func(ast) },
);
print_ast( print_ast(
b"fn main(a: u32) -> void { b"fn main(a: u32) -> void {
let y: u32 = a + 4; let y: u32 = a + 4;
{
let y: u32 = 10;
}
let y: *u32 = &y; let y: *u32 = &y;
return *y; return *y;
}", }",
|ast| unsafe { parse_func(ast) }, |ast| unsafe { parse_func(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) },
);
print_ast( print_ast(
b"fn main(a: *u32, b: u32) -> void { b"fn main(a: *u32, b: u32) -> void {
*a = b; *a = b;
a = &b; a = &b;
}",
|ast| unsafe { parse_func(ast) },
);
print_ast(
b"fn main(a: u32) -> void {
if (a == 0) {
return 1;
} else {
return 0;
}
}",
|ast| unsafe { parse_func(ast) },
);
print_ast(
b"fn main(a: u32) -> void {
return main(1);
}", }",
|ast| unsafe { parse_func(ast) }, |ast| unsafe { parse_func(ast) },
); );
print_ast( print_ast(
b"fn main(a: u32) -> void { b"fn main(a: u32) -> void {
return a as u8; if (a == 0) {
return 1;
} else {
return 0;
}
}", }",
|ast| unsafe { parse_func(ast) }, |ast| unsafe { parse_func(ast) },
); );

View file

@ -99,26 +99,15 @@ fn main() {
// |ast| unsafe { parse_func(ast) }, // |ast| unsafe { parse_func(ast) },
// ); // );
// print_ast(
// b"fn main(a: u32) -> void {
// let x: u32 = 10;
// if (a == 42) {
// x = 7;
// } else {
// x = 8;
// }
// return x;
// }",
// |ast| unsafe { parse_func(ast) },
// );
print_ast( print_ast(
b"fn main(a: u32) -> void { b"fn main(a: u32) -> void {
let x: u32 = 10;
if (a == 42) { if (a == 42) {
return main(7); x = 7;
} else { } else {
return a; x = 8;
} }
return x;
}", }",
|ast| unsafe { parse_func(ast) }, |ast| unsafe { parse_func(ast) },
); );

View file

@ -3,9 +3,9 @@ use super::util;
impl core::fmt::Display for util::defs::AstNode { impl core::fmt::Display for util::defs::AstNode {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
use util::defs::{ use util::defs::{
BinaryExpr, AST_ADDRESS_OF, AST_ARG, AST_AS, AST_ASSIGNMENT, AST_BINARY_OP, AST_BLOCK, BinaryExpr, AST_ADDRESS_OF, AST_ARG, AST_ASSIGNMENT, AST_BINARY_OP, AST_BLOCK,
AST_CALL, AST_DEREF, AST_FUNCTION, AST_IF, AST_NUMBER, AST_PLACE_TO_VALUE, AST_DEREF, AST_FUNCTION, AST_IF, AST_NUMBER, AST_PLACE_TO_VALUE, AST_RETURN_STATEMENT,
AST_RETURN_STATEMENT, AST_VALUE_TO_PLACE, AST_VAR_DECL, AST_VAR_REF, AST_VALUE_TO_PLACE, AST_VAR_DECL, AST_VAR_REF,
}; };
match self.kind { match self.kind {
AST_NUMBER => { AST_NUMBER => {
@ -17,16 +17,6 @@ impl core::fmt::Display for util::defs::AstNode {
AST_ADDRESS_OF => { AST_ADDRESS_OF => {
write!(f, "AddressOf(expr: {})", self.data as usize) write!(f, "AddressOf(expr: {})", self.data as usize)
} }
AST_CALL => {
let call = unsafe { self.data.cast::<util::defs::AstCallExpr>().read() };
write!(f, "Call(callee: {}, params: {:?})", call.callee, unsafe {
std::slice::from_raw_parts(call.params.cast::<u64>(), call.params_len as usize)
},)
}
AST_AS => {
let as_expr = unsafe { self.data.cast::<util::defs::AstAsExpr>().read() };
write!(f, "As(expr: {}, target_type: {})", as_expr.expr, as_expr.ty)
}
AST_ARG => { AST_ARG => {
let arg = unsafe { self.data.cast::<util::defs::AstArgument>().read() }; let arg = unsafe { self.data.cast::<util::defs::AstArgument>().read() };
write!( write!(
@ -157,7 +147,6 @@ impl core::fmt::Display for util::defs::SymEntry {
util::defs::SYM_KEY_PARENT_SCOPE => "ParentScope", util::defs::SYM_KEY_PARENT_SCOPE => "ParentScope",
util::defs::SYM_KEY_ARG => "Argument", util::defs::SYM_KEY_ARG => "Argument",
util::defs::SYM_KEY_VAR => "Variable", util::defs::SYM_KEY_VAR => "Variable",
util::defs::SYM_KEY_FUNCTION => "Function",
_ => "Unknown", _ => "Unknown",
}) })
}) })

View file

@ -2,12 +2,8 @@
// Auto-generated Rust bindings from assembly source // Auto-generated Rust bindings from assembly source
unsafe extern "C" { unsafe extern "C" {
pub unsafe fn bump_init();
pub unsafe fn bump_alloc(size: usize, alignment: usize) -> *mut u8;
pub unsafe fn parse_func(ast: *mut Ast) -> u64; pub unsafe fn parse_func(ast: *mut Ast) -> u64;
pub unsafe fn parse_args(ast: *mut Ast) -> (*const u64, usize); pub unsafe fn parse_args(ast: *mut Ast) -> (*const u64, usize);
pub unsafe fn parse_as_expr(ast: *mut Ast) -> (u64, bool);
pub unsafe fn parse_postfix_expr(ast: *mut Ast) -> (u64, bool);
pub unsafe fn parse_primary_expr(ast: *mut Ast) -> (u64, bool); pub unsafe fn parse_primary_expr(ast: *mut Ast) -> (u64, bool);
pub unsafe fn parse_binary_expr(ast: *mut Ast, precedence: u8) -> (u64, bool); pub unsafe fn parse_binary_expr(ast: *mut Ast, precedence: u8) -> (u64, bool);
pub unsafe fn parse_expr(ast: *mut Ast) -> u64; pub unsafe fn parse_expr(ast: *mut Ast) -> u64;
@ -32,7 +28,6 @@ unsafe extern "C" {
pub unsafe fn codegen_free_operand(ctx: *mut FunctionCtx, operand: *const Operand) -> (); pub unsafe fn codegen_free_operand(ctx: *mut FunctionCtx, operand: *const Operand) -> ();
pub unsafe fn codegen_function(ast: *const CodegenCtx, func_idx: u64) -> (); pub unsafe fn codegen_function(ast: *const CodegenCtx, func_idx: u64) -> ();
pub unsafe fn codegen_push_pop_used_registers(text: *mut Vec<u8>, function_ctx: &FunctionCtx, pop: bool) -> u8; pub unsafe fn codegen_push_pop_used_registers(text: *mut Vec<u8>, function_ctx: &FunctionCtx, pop: bool) -> u8;
pub unsafe fn codegen_call_expr(ctx: *const CodegenCtx, function_ctx: &FunctionCtx, call_expr: *const AstCallExpr) -> (u64, bool);
pub unsafe fn codegen_expr(ctx: *const CodegenCtx, function_ctx: &FunctionCtx, expr_idx: u64) -> (u64, bool); pub unsafe fn codegen_expr(ctx: *const CodegenCtx, function_ctx: &FunctionCtx, expr_idx: u64) -> (u64, bool);
pub unsafe fn codegen_binary_op_rm64_rm64(function_ctx: *mut FunctionCtx, text: *mut BlobVec, lhs: *const Operand, rhs: *const Operand, op: [u8; 8], discard_result: bool) -> *const Operand; pub unsafe fn codegen_binary_op_rm64_rm64(function_ctx: *mut FunctionCtx, text: *mut BlobVec, lhs: *const Operand, rhs: *const Operand, op: [u8; 8], discard_result: bool) -> *const Operand;
pub unsafe fn vec_insert_many(vec: *mut BlobVec, index: usize, data: *const u8, count: usize); pub unsafe fn vec_insert_many(vec: *mut BlobVec, index: usize, data: *const u8, count: usize);
@ -43,10 +38,9 @@ pub const SYM_KEY_SCOPE: u8 = 1;
pub const SYM_KEY_SCOPE_NAME: u8 = 2; pub const SYM_KEY_SCOPE_NAME: u8 = 2;
pub const SYM_KEY_PARENT_SCOPE: u8 = 3; pub const SYM_KEY_PARENT_SCOPE: u8 = 3;
pub const SYM_KEY_START_LOCALS: u8 = 4; pub const SYM_KEY_START_LOCALS: u8 = 4;
pub const SYM_KEY_FUNCTION: u8 = 5; pub const SYM_KEY_ARG: u8 = 5;
pub const SYM_KEY_ARG: u8 = 6; pub const SYM_KEY_VAR: u8 = 6;
pub const SYM_KEY_VAR: u8 = 7; pub const SYM_KEY_END_LOCALS: u8 = 7;
pub const SYM_KEY_END_LOCALS: u8 = 8;
pub const AST_FUNCTION: u8 = 1; pub const AST_FUNCTION: u8 = 1;
pub const AST_BLOCK: u8 = 2; pub const AST_BLOCK: u8 = 2;
pub const AST_VARIABLE: u8 = 3; pub const AST_VARIABLE: u8 = 3;
@ -65,23 +59,12 @@ pub const AST_SWITCH: u8 = 15;
pub const AST_IF: u8 = 16; pub const AST_IF: u8 = 16;
pub const AST_ELSE: u8 = 17; pub const AST_ELSE: u8 = 17;
pub const AST_CALL: u8 = 18; pub const AST_CALL: u8 = 18;
pub const AST_AS: u8 = 19;
pub const TYPE_VOID: u8 = 1; pub const TYPE_VOID: u8 = 1;
pub const TYPE_BOOL: u8 = 2; pub const TYPE_BOOL: u8 = 2;
pub const TYPE_U8: u8 = 3; pub const TYPE_I32: u8 = 3;
pub const TYPE_U16: u8 = 4; pub const TYPE_U32: u8 = 4;
pub const TYPE_U32: u8 = 5; pub const TYPE_STR: u8 = 5;
pub const TYPE_U64: u8 = 6; pub const TYPE_POINTER: u8 = 6;
pub const TYPE_USIZE: u8 = 7;
pub const TYPE_I8: u8 = 8;
pub const TYPE_I16: u8 = 9;
pub const TYPE_I32: u8 = 10;
pub const TYPE_I64: u8 = 11;
pub const TYPE_ISIZE: u8 = 12;
pub const TYPE_STR: u8 = 13;
pub const TYPE_POINTER: u8 = 14;
pub const TYPE_F32: u8 = 15;
pub const TYPE_F64: u8 = 16;
pub const OPERAND_REGISTER: u32 = 1; pub const OPERAND_REGISTER: u32 = 1;
pub const OPERAND_RBP_VALUE: u32 = 2; pub const OPERAND_RBP_VALUE: u32 = 2;
pub const OPERAND_RBP_PVALUE: u32 = 3; pub const OPERAND_RBP_PVALUE: u32 = 3;
@ -207,21 +190,6 @@ pub struct AstFunction {
pub body: u64, pub body: u64,
} }
#[repr(C)]
#[derive(Debug)]
pub struct AstAsExpr {
pub expr: u64,
pub ty: Type,
}
#[repr(C)]
#[derive(Debug)]
pub struct AstCallExpr {
pub callee: u64,
pub params: *const u64,
pub params_len: usize,
}
#[repr(C)] #[repr(C)]
#[derive(Debug)] #[derive(Debug)]
pub struct AstVarRef { pub struct AstVarRef {
@ -324,8 +292,6 @@ pub struct Operand {
pub register: u8, pub register: u8,
pub width: u16, pub width: u16,
pub len: u16, pub len: u16,
pub align: u8,
pub bitset: u8,
pub value: u64, pub value: u64,
} }

View file

@ -373,60 +373,26 @@ impl<'a, T: core::fmt::Display> core::fmt::Display for DisplaySlice<'a, T> {
impl core::fmt::Display for defs::Type { impl core::fmt::Display for defs::Type {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
use defs::{
TYPE_BOOL, TYPE_F32, TYPE_F64, TYPE_I16, TYPE_I32, TYPE_I64, TYPE_I8, TYPE_ISIZE,
TYPE_POINTER, TYPE_STR, TYPE_U16, TYPE_U32, TYPE_U64, TYPE_U8, TYPE_USIZE, TYPE_VOID,
};
match self.kind { match self.kind {
TYPE_VOID => { defs::TYPE_VOID => {
write!(f, "void") write!(f, "void")
} }
TYPE_BOOL => { defs::TYPE_BOOL => {
write!(f, "bool") write!(f, "bool")
} }
TYPE_I32 => { defs::TYPE_I32 => {
write!(f, "i32") write!(f, "i32")
} }
TYPE_U32 => { defs::TYPE_U32 => {
write!(f, "u32") write!(f, "u32")
} }
TYPE_STR => { defs::TYPE_STR => {
write!(f, "str") write!(f, "str")
} }
TYPE_POINTER => { defs::TYPE_POINTER => {
let pointee = unsafe { (self.data as *const defs::Type).read() }; let pointee = unsafe { (self.data as *const defs::Type).read() };
write!(f, "*{pointee}",) write!(f, "*{pointee}",)
} }
TYPE_I8 => {
write!(f, "i8")
}
TYPE_U8 => {
write!(f, "u8")
}
TYPE_I16 => {
write!(f, "i16")
}
TYPE_U16 => {
write!(f, "u16")
}
TYPE_I64 => {
write!(f, "i64")
}
TYPE_U64 => {
write!(f, "u64")
}
TYPE_F32 => {
write!(f, "f32")
}
TYPE_F64 => {
write!(f, "f64")
}
TYPE_USIZE => {
write!(f, "usize")
}
TYPE_ISIZE => {
write!(f, "isize")
}
_ => { _ => {
write!(f, "UnknownType") write!(f, "UnknownType")
} }

View file

@ -4,9 +4,6 @@ mod util;
use util::{ffi::*, vec::Vec, BlobVec}; use util::{ffi::*, vec::Vec, BlobVec};
fn main() { fn main() {
unsafe {
util::defs::bump_init();
}
static mut DROPS: usize = 1; static mut DROPS: usize = 1;
fn get_drops() -> usize { fn get_drops() -> usize {
unsafe { (&raw const DROPS).read() } unsafe { (&raw const DROPS).read() }

View file

@ -1,7 +0,0 @@
[package]
name = "typeck"
version = "0.1.0"
edition = "2024"
[dependencies]
libcompiler = { path = "../libcompiler" }

View file

@ -1,40 +0,0 @@
fn init() {
unsafe {
libcompiler::ffi::bump_init();
}
}
#[cfg(test)]
mod tests {
use libcompiler::ffi::Ast;
use crate::init;
#[test]
fn type_graph() {
init();
let src = b"fn my-fun(a: u32, b: u32) -> void {
let x: i64 = a as i64 + b as i64;
}";
unsafe {
libcompiler::ffi::tokeniser_init_buf(src.as_ptr(), src.len());
let mut ast = Ast {
nodes: libcompiler::vec::Vec::default(),
};
let func_id = libcompiler::ffi::parse_func(&mut ast);
let mut symtable = core::mem::MaybeUninit::<libcompiler::ffi::SymbolTable>::uninit();
libcompiler::ffi::ast_build_symtable(&mut ast, func_id, &mut symtable);
let mut symtable = symtable.assume_init();
use libcompiler::DisplayedSliceExt;
println!(
"Symbol Table: {:#?}",
symtable.symtable.as_slice().displayed()
);
libcompiler::ffi::ast_resolve_var_refs(&mut ast, &mut symtable, func_id);
}
}
}

View file

@ -1 +0,0 @@
../lang/tests/asm_to_rust.py