This commit is contained in:
mlokr 2024-06-23 13:55:48 +02:00
parent b04d9e517e
commit 66c3f7b0d4
No known key found for this signature in database
GPG key ID: DEA147DDEE644993
27 changed files with 165 additions and 527 deletions

View file

@ -1,46 +0,0 @@
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 544
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 3200
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 1032
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 224
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 3240
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 1144
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 1352
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 1400
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 1128
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 1632
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 1528
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 2496
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 2440
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 600
Dbg: deallocating full chunk
test parser::tests::arithmetic ... Dbg: dropping chunk of size: 544
Dbg: deallocating full chunk
test parser::tests::example ... Dbg: dropping chunk of size: 224
Dbg: deallocating full chunk

View file

@ -1,46 +0,0 @@
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 936
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 4040
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 1112
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 296
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 4328
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 1464
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 1616
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 1864
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 1504
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 2160
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 2000
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 3048
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 2960
Dbg: deallocating full chunk
Dbg: dropping chunk of size: 0
Dbg: dropping chunk of size: 848
Dbg: deallocating full chunk
test parser::tests::arithmetic ... Dbg: dropping chunk of size: 936
Dbg: deallocating full chunk
test parser::tests::example ... Dbg: dropping chunk of size: 296
Dbg: deallocating full chunk

View file

@ -1,3 +0,0 @@
main := fn(): int {
return 10 - 20 / 2 + 4 * (2 + 2) - 4 * 4 + 1;
}

View file

@ -1,43 +0,0 @@
Color := struct {
r: u8,
g: u8,
b: u8,
a: u8,
}
Point := struct {
x: u32,
y: u32,
}
Pixel := struct {
color: Color,
point: Point,
}
main := fn(): int {
pixel := Pixel.{
color: Color.{
r: 255,
g: 0,
b: 0,
a: 255,
},
point: Point.{
x: 0,
y: 2,
},
};
if *(&pixel.point.x + 1) != 2 {
return 0;
}
if *(&pixel.point.y - 1) != 0 {
return 64;
}
return pixel.point.x + pixel.point.y + pixel.color.r
+ pixel.color.g + pixel.color.b + pixel.color.a;
}

View file

@ -1,16 +0,0 @@
Type := struct {
brah: int,
blah: int,
}
main := fn(): int {
byte := @as(u8, 10);
same_type_as_byte := @as(@TypeOf(byte), 30);
wide_uint := @as(u32, 40);
truncated_uint := @as(u8, @intcast(wide_uint));
size_of_Type_in_bytes := @sizeof(Type);
align_of_Type_in_bytes := @alignof(Type);
hardcoded_pointer := @as(^u8, @bitcast(10));
ecall_that_returns_int := @eca(int, 1, Type.(10, 20), 5, 6);
return 0;
}

View file

@ -1,36 +0,0 @@
arm_fb_ptr := fn(): int return 100;
x86_fb_ptr := fn(): int return 100;
check_platform := fn(): int {
return x86_fb_ptr();
}
set_pixel := fn(x: int, y: int, width: int): int {
pix_offset := y * width + x;
return 0;
}
main := fn(): int {
fb_ptr := check_platform();
width := 100;
height := 30;
x:= 0;
y:= 0;
loop {
if x <= height + 1 {
set_pixel(x,y,width);
x = x + 1;
} else {
set_pixel(x,y,width);
x = 0;
y = y + 1;
}
if y == width {
break;
}
}
return 0;
}

View file

@ -1,14 +0,0 @@
main := fn(): int {
return add_one(10) + add_two(20);
}
add_two := fn(x: int): int {
return x + 2;
}
add_one := fn(x: int): int {
return x + 1;
}

View file

@ -1,17 +0,0 @@
Vec := fn($Elem: type): type {
return struct {
data: ^Elem,
len: uint,
cap: uint,
};
}
main := fn(): int {
i := 69;
vec := Vec(int).{
data: &i,
len: 1,
cap: 1,
};
return *vec.data;
}

View file

@ -1,15 +0,0 @@
global_var := 10;
complex_global_var := fib(global_var) - 5;
fib := fn(n: int): int {
if 2 > n {
return n;
}
return fib(n - 1) + fib(n - 2);
}
main := fn(): int {
return complex_global_var;
}

View file

@ -1,12 +0,0 @@
main := fn(): int {
return fib(10);
}
fib := fn(x: int): int {
if x <= 2 {
return 1;
} else {
return fib(x - 1) + fib(x - 2);
}
}

View file

@ -1,22 +0,0 @@
main := fn(): int {
return fib(10);
}
fib := fn(n: int): int {
a := 0;
b := 1;
loop {
if n == 0 {
break;
}
c := a + b;
a = b;
b = c;
n -= 1;
stack_reclamation_edge_case := 0;
continue;
}
return a;
}

View file

@ -1,3 +0,0 @@
main := fn(): int {
return 1;
}

View file

@ -1,17 +0,0 @@
main := fn(): int {
a := 1;
b := &a;
modify(b);
drop(a);
stack_reclamation_edge_case := 0;
return *b - 2;
}
modify := fn(a: ^int): void {
*a = 2;
return;
}
drop := fn(a: int): void {
return;
}

View file

@ -1,21 +0,0 @@
Point := struct {
x: int,
y: int,
}
Rect := struct {
a: Point,
b: Point,
}
main := fn(): int {
a := Point.(1, 2);
b := Point.(3, 4);
d := Rect.(a + b, b - a);
d2 := Rect.(Point.(0, 0) - b, a);
d2 = d2 + d;
c := d2.a + d2.b;
return c.x + c.y;
}

View file

@ -1,26 +0,0 @@
Ty := struct {
a: int,
b: int,
}
Ty2 := struct {
ty: Ty,
c: int,
}
main := fn(): int {
finst := Ty2.{ ty: Ty.{ a: 4, b: 1 }, c: 3 };
inst := odher_pass(finst);
if inst.c == 3 {
return pass(&inst.ty);
}
return 0;
}
pass := fn(t: ^Ty): int {
return t.a - t.b;
}
odher_pass := fn(t: Ty2): Ty2 {
return t;
}

View file

@ -1,6 +0,0 @@
main := fn(): int {
a := 1;
b := 2;
a = a + 1;
return a - b;
}

View file

@ -956,11 +956,7 @@ struct Output {
}
impl Output {
fn emit_addi(&mut self, op: &reg::Id, delta: u64) {
self.emit_addi_low(op.get(), op.get(), delta)
}
fn emit_addi_low(&mut self, dest: u8, op: u8, delta: u64) {
fn emit_addi(&mut self, dest: u8, op: u8, delta: u64) {
if delta == 0 {
if dest != op {
self.emit(cp(dest, op));
@ -968,13 +964,7 @@ impl Output {
return;
}
#[allow(overflowing_literals)]
self.emit(match delta as i64 {
// -0x80..=0x7F => addi8(dest, op, delta as _),
// -0x8000..=0x7FFF => addi16(dest, op, delta as _),
// -0x80000000..=0x7FFFFFFF => addi32(dest, op, delta as _),
0x8000000000000000..=0x7FFFFFFFFFFFFFFF => addi64(dest, op, delta),
});
self.emit(addi64(dest, op, delta));
}
fn emit(&mut self, (len, instr): (usize, [u8; instrs::MAX_SIZE])) {
@ -1269,7 +1259,7 @@ impl Codegen {
ptr = ptr.offset(size);
}
self.stack_offset_low(2, STACK_PTR, Some(&stack), 0);
self.stack_offset(2, STACK_PTR, Some(&stack), 0);
let val = self.eca(
Trap::MakeStruct {
file: self.ci.file,
@ -1508,10 +1498,10 @@ impl Codegen {
let offset = std::mem::take(offset) as _;
if reg.is_ref() {
let new_reg = self.ci.regs.allocate();
self.stack_offset_low(new_reg.get(), reg.get(), stack.as_ref(), offset);
self.stack_offset(new_reg.get(), reg.get(), stack.as_ref(), offset);
*reg = new_reg;
} else {
self.stack_offset_low(reg.get(), reg.get(), stack.as_ref(), offset);
self.stack_offset(reg.get(), reg.get(), stack.as_ref(), offset);
}
// FIXME: we might be able to track this but it will be pain
@ -1657,10 +1647,10 @@ impl Codegen {
} => 'b: {
log::dbg!("if-cond");
let cond = self.expr_ctx(cond, Ctx::default().with_ty(ty::BOOL))?;
let reg = self.loc_to_reg(cond.loc, 1);
let reg = self.loc_to_reg(&cond.loc, 1);
let jump_offset = self.output.code.len() as u32;
self.output.emit(jeq(reg.get(), 0, 0));
self.ci.regs.free(reg);
self.ci.free_loc(cond.loc);
log::dbg!("if-then");
let then_unreachable = self.expr(then).is_none();
@ -1794,11 +1784,7 @@ impl Codegen {
let lsize = self.tys.size_of(left.ty);
let lhs = if left.loc.is_ref() && matches!(right, E::Number { .. }) {
self.loc_to_reg(&left.loc, lsize)
} else {
self.loc_to_reg(left.loc, lsize)
};
let lhs = self.loc_to_reg(left.loc, lsize);
let right = self.expr_ctx(right, Ctx::default().with_ty(left.ty))?;
let rsize = self.tys.size_of(right.ty);
@ -2201,7 +2187,7 @@ impl Codegen {
9..=16 => Loc::stack(self.ci.stack.allocate(size)),
_ => {
let stack = self.ci.stack.allocate(size);
self.stack_offset_low(1, STACK_PTR, Some(&stack), 0);
self.stack_offset(1, STACK_PTR, Some(&stack), 0);
Loc::stack(stack)
}
}
@ -2234,16 +2220,11 @@ impl Codegen {
assert_eq!(offset, 0, "TODO");
reg.as_ref()
}
loc @ (LocCow::Ref(Loc::Rt { .. }) | LocCow::Owned(Loc::Rt { .. })) => {
loc => {
let reg = self.ci.regs.allocate();
self.store_sized(loc, Loc::reg(reg.as_ref()), size);
reg
}
LocCow::Ref(&Loc::Ct { value }) | LocCow::Owned(Loc::Ct { value }) => {
let reg = self.ci.regs.allocate();
self.output.emit(li64(reg.get(), u64::from_ne_bytes(value)));
reg
}
}
}
@ -2266,7 +2247,7 @@ impl Codegen {
else {
unreachable!()
};
self.stack_offset_low(parama.next(), reg.get(), stack.as_ref(), *offset as _);
self.stack_offset(parama.next(), reg.get(), stack.as_ref(), *offset as _);
return;
}
@ -2312,8 +2293,8 @@ impl Codegen {
// TODO: some oportuinies to ellit more optimal code
let src_off = self.ci.regs.allocate();
let dst_off = self.ci.regs.allocate();
self.stack_offset_low(src_off.get(), src.get(), ssta.as_ref(), soff);
self.stack_offset_low(dst_off.get(), dst.get(), dsta.as_ref(), doff);
self.stack_offset(src_off.get(), src.get(), ssta.as_ref(), soff);
self.stack_offset(dst_off.get(), dst.get(), dsta.as_ref(), doff);
self.output
.emit(bmc(src_off.get(), dst_off.get(), size as _));
self.ci.regs.free(src_off);
@ -2342,9 +2323,9 @@ impl Codegen {
self.ci.free_loc(dst);
}
fn stack_offset_low(&mut self, dst: u8, op: u8, stack: Option<&stack::Id>, off: Offset) {
fn stack_offset(&mut self, dst: u8, op: u8, stack: Option<&stack::Id>, off: Offset) {
let Some(stack) = stack else {
self.output.emit_addi_low(dst, op, off as _);
self.output.emit_addi(dst, op, off as _);
return;
};

View file

@ -1,2 +0,0 @@

View file

@ -1,25 +0,0 @@
pub type Ident = u32;
const LEN_BITS: u32 = 6;
pub fn len(ident: u32) -> u32 {
ident & ((1 << LEN_BITS) - 1)
}
pub fn is_null(ident: u32) -> bool {
(ident >> LEN_BITS) == 0
}
pub fn pos(ident: u32) -> u32 {
(ident >> LEN_BITS).saturating_sub(1)
}
pub fn new(pos: u32, len: u32) -> u32 {
debug_assert!(len < (1 << LEN_BITS));
((pos + 1) << LEN_BITS) | len
}
pub fn range(ident: u32) -> std::ops::Range<usize> {
let (len, pos) = (len(ident) as usize, pos(ident) as usize);
pos..pos + len
}

View file

@ -29,20 +29,95 @@ macro_rules! run_tests {
($runner:path: $($name:ident => $input:expr;)*) => {$(
#[test]
fn $name() {
$crate::tests::run_test(std::any::type_name_of_val(&$name), stringify!($name), $input, $runner);
$crate::run_test(std::any::type_name_of_val(&$name), stringify!($name), $input, $runner);
}
)*};
}
pub mod codegen;
pub mod codegen2;
mod ident;
pub mod parser;
mod instrs;
mod lexer;
mod log;
pub mod parser;
mod tests;
mod typechk;
mod ident {
pub type Ident = u32;
const LEN_BITS: u32 = 6;
pub fn len(ident: u32) -> u32 {
ident & ((1 << LEN_BITS) - 1)
}
pub fn is_null(ident: u32) -> bool {
(ident >> LEN_BITS) == 0
}
pub fn pos(ident: u32) -> u32 {
(ident >> LEN_BITS).saturating_sub(1)
}
pub fn new(pos: u32, len: u32) -> u32 {
debug_assert!(len < (1 << LEN_BITS));
((pos + 1) << LEN_BITS) | len
}
pub fn range(ident: u32) -> std::ops::Range<usize> {
let (len, pos) = (len(ident) as usize, pos(ident) as usize);
pos..pos + len
}
}
mod log {
#![allow(unused_macros)]
#[derive(PartialOrd, PartialEq, Ord, Eq, Debug)]
pub enum Level {
Err,
Wrn,
Inf,
Dbg,
}
pub const LOG_LEVEL: Level = match option_env!("LOG_LEVEL") {
Some(val) => match val.as_bytes()[0] {
b'e' => Level::Err,
b'w' => Level::Wrn,
b'i' => Level::Inf,
b'd' => Level::Dbg,
_ => panic!("Invalid log level."),
},
None => {
if cfg!(debug_assertions) {
Level::Dbg
} else {
Level::Err
}
}
};
macro_rules! log {
($level:expr, $fmt:literal $($expr:tt)*) => {
if $level <= $crate::log::LOG_LEVEL {
eprintln!("{:?}: {}", $level, format_args!($fmt $($expr)*));
}
};
($level:expr, $($arg:expr),*) => {
if $level <= $crate::log::LOG_LEVEL {
$(eprintln!("[{}{}{}][{:?}]: {} = {:?}", line!(), column!(), file!(), $level, stringify!($arg), $arg);)*
}
};
}
macro_rules! err { ($($arg:tt)*) => { $crate::log::log!($crate::log::Level::Err, $($arg)*) }; }
macro_rules! wrn { ($($arg:tt)*) => { $crate::log::log!($crate::log::Level::Wrn, $($arg)*) }; }
macro_rules! inf { ($($arg:tt)*) => { $crate::log::log!($crate::log::Level::Inf, $($arg)*) }; }
macro_rules! dbg { ($($arg:tt)*) => { $crate::log::log!($crate::log::Level::Dbg, $($arg)*) }; }
#[allow(unused_imports)]
pub(crate) use {dbg, err, inf, log, wrn};
}
#[inline]
unsafe fn encode<T>(instr: T) -> (usize, [u8; instrs::MAX_SIZE]) {
@ -424,6 +499,70 @@ impl Default for FnvHasher {
}
}
#[cfg(test)]
pub fn run_test(
name: &'static str,
ident: &'static str,
input: &'static str,
test: fn(&'static str, &'static str, &mut String),
) {
use std::{io::Write, path::PathBuf};
let filter = std::env::var("PT_FILTER").unwrap_or_default();
if !filter.is_empty() && !name.contains(&filter) {
return;
}
let mut output = String::new();
test(ident, input, &mut output);
let mut root = PathBuf::from(
std::env::var("PT_TEST_ROOT")
.unwrap_or(concat!(env!("CARGO_MANIFEST_DIR"), "/tests").to_string()),
);
root.push(
name.replace("::", "_")
.replace(concat!(env!("CARGO_PKG_NAME"), "_"), ""),
);
root.set_extension("txt");
let expected = std::fs::read_to_string(&root).unwrap_or_default();
if output == expected {
return;
}
if std::env::var("PT_UPDATE").is_ok() {
std::fs::write(&root, output).unwrap();
return;
}
if !root.exists() {
std::fs::create_dir_all(root.parent().unwrap()).unwrap();
std::fs::write(&root, vec![]).unwrap();
}
let mut proc = std::process::Command::new("diff")
.arg("-u")
.arg("--color")
.arg(&root)
.arg("-")
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::inherit())
.spawn()
.unwrap();
proc.stdin
.as_mut()
.unwrap()
.write_all(output.as_bytes())
.unwrap();
proc.wait().unwrap();
panic!("test failed");
}
#[cfg(test)]
mod test {
use std::sync::Arc;

View file

@ -1,48 +0,0 @@
#![allow(unused_macros)]
#[derive(PartialOrd, PartialEq, Ord, Eq, Debug)]
pub enum Level {
Err,
Wrn,
Inf,
Dbg,
}
pub const LOG_LEVEL: Level = match option_env!("LOG_LEVEL") {
Some(val) => match val.as_bytes()[0] {
b'e' => Level::Err,
b'w' => Level::Wrn,
b'i' => Level::Inf,
b'd' => Level::Dbg,
_ => panic!("Invalid log level."),
},
None => {
if cfg!(debug_assertions) {
Level::Dbg
} else {
Level::Err
}
}
};
macro_rules! log {
($level:expr, $fmt:literal $($expr:tt)*) => {
if $level <= $crate::log::LOG_LEVEL {
println!("{:?}: {}", $level, format_args!($fmt $($expr)*));
}
};
($level:expr, $($arg:expr),*) => {
if $level <= $crate::log::LOG_LEVEL {
$(println!("[{}{}{}][{:?}]: {} = {:?}", line!(), column!(), file!(), $level, stringify!($arg), $arg);)*
}
};
}
macro_rules! err { ($($arg:tt)*) => { $crate::log::log!($crate::log::Level::Err, $($arg)*) }; }
macro_rules! wrn { ($($arg:tt)*) => { $crate::log::log!($crate::log::Level::Wrn, $($arg)*) }; }
macro_rules! inf { ($($arg:tt)*) => { $crate::log::log!($crate::log::Level::Inf, $($arg)*) }; }
macro_rules! dbg { ($($arg:tt)*) => { $crate::log::log!($crate::log::Level::Dbg, $($arg)*) }; }
#[allow(unused_imports)]
pub(crate) use {dbg, err, inf, log, wrn};

View file

@ -1,64 +0,0 @@
#![cfg(test)]
pub fn run_test(
name: &'static str,
ident: &'static str,
input: &'static str,
test: fn(&'static str, &'static str, &mut String),
) {
use std::{io::Write, path::PathBuf};
let filter = std::env::var("PT_FILTER").unwrap_or_default();
if !filter.is_empty() && !name.contains(&filter) {
return;
}
let mut output = String::new();
test(ident, input, &mut output);
let mut root = PathBuf::from(
std::env::var("PT_TEST_ROOT")
.unwrap_or(concat!(env!("CARGO_MANIFEST_DIR"), "/tests").to_string()),
);
root.push(
name.replace("::", "_")
.replace(concat!(env!("CARGO_PKG_NAME"), "_"), ""),
);
root.set_extension("txt");
let expected = std::fs::read_to_string(&root).unwrap_or_default();
if output == expected {
return;
}
if std::env::var("PT_UPDATE").is_ok() {
std::fs::write(&root, output).unwrap();
return;
}
if !root.exists() {
std::fs::create_dir_all(root.parent().unwrap()).unwrap();
std::fs::write(&root, vec![]).unwrap();
}
let mut proc = std::process::Command::new("diff")
.arg("-u")
.arg("--color")
.arg(&root)
.arg("-")
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::inherit())
.spawn()
.unwrap();
proc.stdin
.as_mut()
.unwrap()
.write_all(output.as_bytes())
.unwrap();
proc.wait().unwrap();
panic!();
}

View file

View file

@ -1,3 +1,3 @@
code size: 513
code size: 525
ret: 0
status: Ok(())

View file

@ -1,3 +1,3 @@
code size: 262
code size: 268
ret: 55
status: Ok(())

View file

@ -1,3 +1,3 @@
code size: 110
code size: 116
ret: 0
status: Ok(())

View file

@ -10,7 +10,7 @@
// - Instructions have to be valid as specified (values and sizes)
// - Mapped pages should be at least 4 KiB
//#![no_std]
#![no_std]
#![cfg_attr(feature = "nightly", feature(fn_align))]
#![deny(unsafe_op_in_unsafe_fn)]