adding different-sized integers
This commit is contained in:
parent
b28baa86f7
commit
7cca9a3683
35
hblang/examples/different_types.hb
Normal file
35
hblang/examples/different_types.hb
Normal file
|
@ -0,0 +1,35 @@
|
|||
|
||||
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,
|
||||
},
|
||||
};
|
||||
|
||||
return pixel.point.x + pixel.point.y + pixel.color.r
|
||||
+ pixel.color.g + pixel.color.b + pixel.color.a;
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
use std::ops::Range;
|
||||
|
||||
use crate::ident::Ident;
|
||||
use crate::ident::{self, Ident};
|
||||
|
||||
use {
|
||||
crate::{
|
||||
|
@ -17,7 +17,7 @@ type Reg = u8;
|
|||
type MaskElem = u64;
|
||||
type Type = u32;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct LinReg(Reg);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
|
@ -63,31 +63,49 @@ impl Ctx {
|
|||
pub mod bt {
|
||||
use super::*;
|
||||
|
||||
const fn builtin_type(id: u32) -> Type {
|
||||
Type::MAX - id
|
||||
}
|
||||
|
||||
macro_rules! builtin_type {
|
||||
($($name:ident;)*) => {$(
|
||||
pub const $name: Type = ${index(0)} << 2;
|
||||
pub const $name: Type = ${index(0)};
|
||||
)*};
|
||||
}
|
||||
|
||||
builtin_type! {
|
||||
VOID;
|
||||
NEVER;
|
||||
INT;
|
||||
I64;
|
||||
I32;
|
||||
I16;
|
||||
I8;
|
||||
UINT;
|
||||
U64;
|
||||
U32;
|
||||
U16;
|
||||
I16;
|
||||
I32;
|
||||
INT;
|
||||
U8;
|
||||
U16;
|
||||
U32;
|
||||
UINT;
|
||||
BOOL;
|
||||
}
|
||||
|
||||
pub fn is_signed(ty: Type) -> bool {
|
||||
ty >= I8 && ty <= INT
|
||||
}
|
||||
|
||||
pub fn is_unsigned(ty: Type) -> bool {
|
||||
ty >= U8 && ty <= UINT
|
||||
}
|
||||
|
||||
pub fn strip_pointer(ty: Type) -> Type {
|
||||
match TypeKind::from_ty(ty) {
|
||||
TypeKind::Pointer(_) => UINT,
|
||||
_ => ty,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_upcast(a: Type, b: Type) -> Option<Type> {
|
||||
Some(match (strip_pointer(a.min(b)), strip_pointer(a.max(b))) {
|
||||
_ if a == b => a,
|
||||
_ if is_signed(a) && is_signed(b) || is_unsigned(a) && is_unsigned(b) => a.max(b),
|
||||
_ if is_unsigned(b) && is_signed(a) && b - U8 < a - I8 => a,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -98,10 +116,14 @@ enum TypeKind {
|
|||
}
|
||||
|
||||
impl TypeKind {
|
||||
const fn from_ty(ty: Type) -> Self {
|
||||
let (flag, index) = (ty & 0b11, ty >> 2);
|
||||
const FLAG_BITS: u32 = 2;
|
||||
const FLAG_OFFSET: u32 = std::mem::size_of::<Type>() as u32 * 8 - Self::FLAG_BITS;
|
||||
const INDEX_MASK: u32 = (1 << (32 - Self::FLAG_BITS)) - 1;
|
||||
|
||||
fn from_ty(ty: Type) -> Self {
|
||||
let (flag, index) = (ty >> Self::FLAG_OFFSET, ty & Self::INDEX_MASK);
|
||||
match flag {
|
||||
0 => Self::Builtin(ty),
|
||||
0 => Self::Builtin(index),
|
||||
1 => Self::Pointer(index),
|
||||
2 => Self::Struct(index),
|
||||
_ => unreachable!(),
|
||||
|
@ -110,11 +132,11 @@ impl TypeKind {
|
|||
|
||||
const fn encode(self) -> Type {
|
||||
let (index, flag) = match self {
|
||||
Self::Builtin(index) => return index,
|
||||
Self::Builtin(index) => (index, 0),
|
||||
Self::Pointer(index) => (index, 1),
|
||||
Self::Struct(index) => (index, 2),
|
||||
};
|
||||
index << 2 | flag
|
||||
(flag << Self::FLAG_OFFSET) | index
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,8 +209,25 @@ impl Func {
|
|||
self.encode(instrs::addi64(STACK_PTR, STACK_PTR, size as _));
|
||||
}
|
||||
|
||||
fn short_cut_bin_op(&mut self, dest: Reg, src: Reg, imm: u64) -> bool {
|
||||
if imm == 0 {
|
||||
if dest != src {
|
||||
self.encode(instrs::cp(dest, src));
|
||||
}
|
||||
}
|
||||
imm != 0
|
||||
}
|
||||
|
||||
fn subi64(&mut self, dest: Reg, src: Reg, imm: u64) {
|
||||
self.encode(instrs::addi64(dest, src, imm.wrapping_neg()));
|
||||
if self.short_cut_bin_op(dest, src, imm) {
|
||||
self.encode(instrs::addi64(dest, src, imm.wrapping_neg()));
|
||||
}
|
||||
}
|
||||
|
||||
fn addi64(&mut self, dest: Reg, src: Reg, imm: u64) {
|
||||
if self.short_cut_bin_op(dest, src, imm) {
|
||||
self.encode(instrs::addi64(dest, src, imm));
|
||||
}
|
||||
}
|
||||
|
||||
fn call(&mut self, func: LabelId) {
|
||||
|
@ -324,12 +363,10 @@ impl<'a> std::fmt::Display for TypeDisplay<'a> {
|
|||
TK::Builtin(bt::VOID) => "void",
|
||||
TK::Builtin(bt::NEVER) => "never",
|
||||
TK::Builtin(bt::INT) => "int",
|
||||
TK::Builtin(bt::I64) => "i64",
|
||||
TK::Builtin(bt::I32) => "i32",
|
||||
TK::Builtin(bt::I16) => "i16",
|
||||
TK::Builtin(bt::I8) => "i8",
|
||||
TK::Builtin(bt::UINT) => "uint",
|
||||
TK::Builtin(bt::U64) => "u64",
|
||||
TK::Builtin(bt::U32) => "u32",
|
||||
TK::Builtin(bt::U16) => "u16",
|
||||
TK::Builtin(bt::U8) => "u8",
|
||||
|
@ -478,7 +515,7 @@ impl<'a> Codegen<'a> {
|
|||
TK::Pointer(_) => 8,
|
||||
TK::Builtin(bt::VOID) => 0,
|
||||
TK::Builtin(bt::NEVER) => unreachable!(),
|
||||
TK::Builtin(bt::INT | bt::I64 | bt::UINT | bt::U64) => 8,
|
||||
TK::Builtin(bt::INT | bt::UINT) => 8,
|
||||
TK::Builtin(bt::I32 | bt::U32) => 4,
|
||||
TK::Builtin(bt::I16 | bt::U16) => 2,
|
||||
TK::Builtin(bt::I8 | bt::U8 | bt::BOOL) => 1,
|
||||
|
@ -521,7 +558,7 @@ impl<'a> Codegen<'a> {
|
|||
self.report(pos, format_args!("field not found: {}", field));
|
||||
}
|
||||
|
||||
fn loc_to_reg(&mut self, loc: Loc) -> LinReg {
|
||||
fn loc_to_reg(&mut self, loc: Loc, size: u64) -> LinReg {
|
||||
match loc {
|
||||
Loc::RegRef(rr) => {
|
||||
let reg = self.gpa.allocate();
|
||||
|
@ -532,13 +569,14 @@ impl<'a> Codegen<'a> {
|
|||
Loc::Reg(reg) => reg,
|
||||
Loc::Deref(dreg, offset) => {
|
||||
let reg = self.gpa.allocate();
|
||||
self.code.encode(instrs::ld(reg.0, dreg.0, offset, 8));
|
||||
self.code
|
||||
.encode(instrs::ld(reg.0, dreg.0, offset, size as _));
|
||||
self.gpa.free(dreg);
|
||||
reg
|
||||
}
|
||||
Loc::DerefRef(dreg, offset) => {
|
||||
let reg = self.gpa.allocate();
|
||||
self.code.encode(instrs::ld(reg.0, dreg, offset, 8));
|
||||
self.code.encode(instrs::ld(reg.0, dreg, offset, size as _));
|
||||
reg
|
||||
}
|
||||
Loc::Imm(imm) => {
|
||||
|
@ -548,16 +586,16 @@ impl<'a> Codegen<'a> {
|
|||
}
|
||||
Loc::Stack(offset) | Loc::StackRef(offset) => {
|
||||
let reg = self.gpa.allocate();
|
||||
self.load_stack(reg.0, offset, 8);
|
||||
self.load_stack(reg.0, offset, size as _);
|
||||
reg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn alloc_stack(&mut self, size: u32) -> u64 {
|
||||
fn alloc_stack(&mut self, size: u64) -> u64 {
|
||||
let offset = self.stack_size;
|
||||
log::dbg!("alloc_stack: {} {}", offset, size);
|
||||
self.stack_size += size as u64;
|
||||
self.stack_size += size;
|
||||
offset
|
||||
}
|
||||
|
||||
|
@ -582,10 +620,7 @@ impl<'a> Codegen<'a> {
|
|||
|
||||
fn ty(&mut self, expr: &parser::Expr<'a>) -> Type {
|
||||
match *expr {
|
||||
E::Ident { name: "int", .. } => bt::INT,
|
||||
E::Ident { name: "bool", .. } => bt::BOOL,
|
||||
E::Ident { name: "void", .. } => bt::VOID,
|
||||
E::Ident { name: "never", .. } => bt::NEVER,
|
||||
E::Ident { id, .. } if ident::is_null(id) => id,
|
||||
E::UnOp {
|
||||
op: T::Star, val, ..
|
||||
} => {
|
||||
|
@ -618,7 +653,7 @@ impl<'a> Codegen<'a> {
|
|||
|
||||
let loc = match ctx {
|
||||
Ctx::Dest(dest) => dest.loc,
|
||||
_ => Loc::Stack(self.alloc_stack(size as u32)),
|
||||
_ => Loc::Stack(self.alloc_stack(size)),
|
||||
};
|
||||
|
||||
for (name, field) in fields {
|
||||
|
@ -663,16 +698,16 @@ impl<'a> Codegen<'a> {
|
|||
let loc = match val.loc {
|
||||
Loc::StackRef(off) => {
|
||||
let reg = self.gpa.allocate();
|
||||
self.code.encode(instrs::addi64(reg.0, STACK_PTR, off));
|
||||
self.code.addi64(reg.0, STACK_PTR, off);
|
||||
Loc::Reg(reg)
|
||||
}
|
||||
Loc::Deref(r, off) => {
|
||||
self.code.encode(instrs::addi64(r.0, r.0, off));
|
||||
self.code.addi64(r.0, r.0, off);
|
||||
Loc::Reg(r)
|
||||
}
|
||||
Loc::DerefRef(r, off) => {
|
||||
let reg = self.gpa.allocate();
|
||||
self.code.encode(instrs::addi64(reg.0, r, off));
|
||||
self.code.addi64(reg.0, r, off);
|
||||
Loc::Reg(reg)
|
||||
}
|
||||
l => self.report(
|
||||
|
@ -691,7 +726,7 @@ impl<'a> Codegen<'a> {
|
|||
pos,
|
||||
} => {
|
||||
let val = self.expr(val)?;
|
||||
let reg = self.loc_to_reg(val.loc);
|
||||
let reg = self.loc_to_reg(val.loc, self.size_of(val.ty));
|
||||
match TypeKind::from_ty(val.ty) {
|
||||
TypeKind::Pointer(ty) => Some(Value {
|
||||
ty: self.pointers[ty as usize],
|
||||
|
@ -726,43 +761,43 @@ impl<'a> Codegen<'a> {
|
|||
let mut parama = 3..12;
|
||||
for (earg, &ty) in args.iter().zip(fn_label.args.iter()) {
|
||||
let arg = self.expr_ctx(earg, Ctx::Inferred(ty))?;
|
||||
self.assert_ty(earg.pos(), ty, arg.ty);
|
||||
_ = self.assert_ty(earg.pos(), ty, arg.ty);
|
||||
self.pass_arg(arg, &mut parama);
|
||||
}
|
||||
|
||||
let size = self.size_of(fn_label.ret);
|
||||
let loc = match size {
|
||||
0 => Loc::Imm(0),
|
||||
8 => Loc::RegRef(1),
|
||||
16 => match ctx {
|
||||
..=8 => Loc::RegRef(1),
|
||||
..=16 => match ctx {
|
||||
Ctx::Dest(dest) => dest.loc,
|
||||
_ => Loc::Stack(self.alloc_stack(size as u32)),
|
||||
_ => Loc::Stack(self.alloc_stack(size)),
|
||||
},
|
||||
24..=u64::MAX => {
|
||||
..=u64::MAX => {
|
||||
let val = match ctx {
|
||||
Ctx::Dest(dest) => dest.loc,
|
||||
_ => Loc::Stack(self.alloc_stack(size as u32)),
|
||||
_ => Loc::Stack(self.alloc_stack(size)),
|
||||
};
|
||||
let (ptr, off) = val.ref_to_ptr(size);
|
||||
self.code.encode(instrs::cp(1, ptr));
|
||||
self.code.encode(instrs::addi64(1, ptr, off));
|
||||
self.code.addi64(1, ptr, off);
|
||||
val
|
||||
}
|
||||
s => todo!("call return size: {}", s),
|
||||
};
|
||||
|
||||
self.code.call(func);
|
||||
|
||||
match size {
|
||||
0 => {}
|
||||
8 => {}
|
||||
16 => {
|
||||
..=8 => {}
|
||||
..=16 => {
|
||||
if let Loc::Stack(stack) = loc {
|
||||
self.store_stack(1, stack, 16);
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
24..=u64::MAX => {}
|
||||
s => todo!("call return size: {}", s),
|
||||
..=u64::MAX => {}
|
||||
}
|
||||
|
||||
return Some(Value {
|
||||
|
@ -782,7 +817,8 @@ impl<'a> Codegen<'a> {
|
|||
E::Return { val, pos } => {
|
||||
if let Some(val) = val {
|
||||
let val = self.expr_ctx(val, Ctx::Inferred(self.ret))?;
|
||||
self.assert_ty(pos, self.ret, val.ty);
|
||||
let ty = self.assert_ty(pos, self.ret, val.ty);
|
||||
let val = self.ensure_sign_extended(val, ty);
|
||||
self.assign(self.ret, Loc::Return, val.loc);
|
||||
}
|
||||
self.ret_relocs.push(RetReloc {
|
||||
|
@ -810,7 +846,7 @@ impl<'a> Codegen<'a> {
|
|||
} => 'b: {
|
||||
log::dbg!("if-cond");
|
||||
let cond = self.expr_ctx(cond, Ctx::Inferred(bt::BOOL))?;
|
||||
let reg = self.loc_to_reg(cond.loc);
|
||||
let reg = self.loc_to_reg(cond.loc, 1);
|
||||
let jump_offset = self.code.code.len() as u32;
|
||||
self.code.encode(instrs::jeq(reg.0, 0, 0));
|
||||
self.gpa.free(reg);
|
||||
|
@ -903,49 +939,86 @@ impl<'a> Codegen<'a> {
|
|||
None
|
||||
}
|
||||
E::BinOp { left, op, right } => {
|
||||
use instrs as i;
|
||||
|
||||
if op == T::Assign {
|
||||
let left = self.expr(left)?;
|
||||
let right = self.expr_ctx(right, Ctx::Inferred(left.ty))?;
|
||||
return self.assign(left.ty, left.loc, right.loc);
|
||||
self.expr_ctx(right, Ctx::Dest(left))?;
|
||||
return Some(Value::VOID);
|
||||
}
|
||||
|
||||
let left = self.expr(left)?;
|
||||
let lhs = self.loc_to_reg(left.loc);
|
||||
let lsize = self.size_of(left.ty);
|
||||
let lhs = self.loc_to_reg(left.loc, lsize);
|
||||
let right = self.expr_ctx(right, Ctx::Inferred(left.ty))?;
|
||||
let rhs = self.loc_to_reg(right.loc);
|
||||
let rsize = self.size_of(right.ty);
|
||||
let rhs = self.loc_to_reg(right.loc, rsize);
|
||||
|
||||
let op = match op {
|
||||
T::Plus => instrs::add64,
|
||||
T::Minus => instrs::sub64,
|
||||
T::Star => instrs::mul64,
|
||||
T::Le => {
|
||||
self.code.encode(instrs::cmpu(lhs.0, lhs.0, rhs.0));
|
||||
let ty = self.assert_ty(expr.pos(), left.ty, right.ty);
|
||||
|
||||
let size = self.size_of(ty);
|
||||
|
||||
let signed = bt::is_signed(ty);
|
||||
let index = size.ilog2() as usize;
|
||||
|
||||
let ops = match op {
|
||||
T::Plus => [i::add8, i::add16, i::add32, i::add64],
|
||||
T::Minus => [i::sub8, i::sub16, i::sub32, i::sub64],
|
||||
T::Star => [i::mul8, i::mul16, i::mul32, i::mul64],
|
||||
T::FSlash if signed => [
|
||||
|a, b, c| i::dirs8(a, ZERO, b, c),
|
||||
|a, b, c| i::dirs16(a, ZERO, b, c),
|
||||
|a, b, c| i::dirs32(a, ZERO, b, c),
|
||||
|a, b, c| i::dirs64(a, ZERO, b, c),
|
||||
],
|
||||
T::FSlash => [
|
||||
|a, b, c| i::diru8(a, ZERO, b, c),
|
||||
|a, b, c| i::diru16(a, ZERO, b, c),
|
||||
|a, b, c| i::diru32(a, ZERO, b, c),
|
||||
|a, b, c| i::diru64(a, ZERO, b, c),
|
||||
],
|
||||
T::Le | T::Ge => {
|
||||
let against = if op == T::Le { 1 } else { (-1i64) as _ };
|
||||
let op = if signed { i::cmps } else { i::cmpu };
|
||||
self.code.encode(op(lhs.0, lhs.0, rhs.0));
|
||||
self.gpa.free(rhs);
|
||||
self.code.encode(instrs::cmpui(lhs.0, lhs.0, 1));
|
||||
self.code.encode(instrs::cmpui(lhs.0, lhs.0, against));
|
||||
return Some(Value {
|
||||
ty: bt::BOOL,
|
||||
loc: Loc::Reg(lhs),
|
||||
});
|
||||
}
|
||||
T::Eq => {
|
||||
self.code.encode(instrs::cmpu(lhs.0, lhs.0, rhs.0));
|
||||
T::Eq | T::Lt | T::Gt => {
|
||||
let against = match op {
|
||||
T::Eq => 0,
|
||||
T::Lt => 1,
|
||||
T::Gt => (-1i64) as _,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let op = if signed { i::cmps } else { i::cmpu };
|
||||
self.code.encode(op(lhs.0, lhs.0, rhs.0));
|
||||
self.gpa.free(rhs);
|
||||
self.code.encode(instrs::cmpui(lhs.0, lhs.0, 0));
|
||||
self.code.encode(instrs::cmpui(lhs.0, lhs.0, against));
|
||||
self.code.encode(instrs::not(lhs.0, lhs.0));
|
||||
return Some(Value {
|
||||
ty: bt::BOOL,
|
||||
loc: Loc::Reg(lhs),
|
||||
});
|
||||
}
|
||||
T::FSlash => |reg0, reg1, reg2| instrs::diru64(reg0, ZERO, reg1, reg2),
|
||||
_ => unimplemented!("{:#?}", op),
|
||||
};
|
||||
|
||||
self.code.encode(op(lhs.0, lhs.0, rhs.0));
|
||||
self.code.encode(ops[index](lhs.0, lhs.0, rhs.0));
|
||||
self.gpa.free(rhs);
|
||||
|
||||
let min_size = lsize.min(rsize);
|
||||
if bt::is_signed(ty) && min_size < size {
|
||||
let op = [i::sxt8, i::sxt16, i::sxt32][min_size.ilog2() as usize];
|
||||
self.code.encode(op(lhs.0, lhs.0));
|
||||
}
|
||||
|
||||
Some(Value {
|
||||
ty: left.ty,
|
||||
ty,
|
||||
loc: Loc::Reg(lhs),
|
||||
})
|
||||
}
|
||||
|
@ -960,45 +1033,68 @@ impl<'a> Codegen<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn ensure_sign_extended(&mut self, val: Value, ty: Type) -> Value {
|
||||
let size = self.size_of(ty);
|
||||
let lsize = self.size_of(val.ty);
|
||||
if lsize < size {
|
||||
let reg = self.loc_to_reg(val.loc, lsize);
|
||||
let op = [instrs::sxt8, instrs::sxt16, instrs::sxt32][lsize.ilog2() as usize];
|
||||
self.code.encode(op(reg.0, reg.0));
|
||||
Value {
|
||||
ty,
|
||||
loc: Loc::Reg(reg),
|
||||
}
|
||||
} else {
|
||||
val
|
||||
}
|
||||
}
|
||||
|
||||
fn assign(&mut self, ty: Type, right: Loc, left: Loc) -> Option<Value> {
|
||||
if left == right {
|
||||
return Some(Value::VOID);
|
||||
}
|
||||
|
||||
let size = self.size_of(ty);
|
||||
|
||||
match size {
|
||||
8 => {
|
||||
let lhs = self.loc_to_reg(left);
|
||||
0 => {}
|
||||
..=8 => {
|
||||
let lhs = self.loc_to_reg(left, size);
|
||||
match right {
|
||||
Loc::RegRef(reg) => self.code.encode(instrs::cp(reg, lhs.0)),
|
||||
Loc::Return => self.code.encode(instrs::cp(1, lhs.0)),
|
||||
Loc::Deref(reg, off) => {
|
||||
self.code.encode(instrs::st(lhs.0, reg.0, off, 8));
|
||||
self.code.encode(instrs::st(lhs.0, reg.0, off, size as _));
|
||||
self.gpa.free(reg);
|
||||
}
|
||||
Loc::RegRef(reg) => self.code.encode(instrs::cp(reg, lhs.0)),
|
||||
Loc::StackRef(offset) | Loc::Stack(offset) => {
|
||||
self.store_stack(lhs.0, offset, 8)
|
||||
Loc::DerefRef(reg, off) => {
|
||||
self.code.encode(instrs::st(lhs.0, reg, off, size as _));
|
||||
}
|
||||
Loc::StackRef(offset) | Loc::Stack(offset) => {
|
||||
self.store_stack(lhs.0, offset, size as _)
|
||||
}
|
||||
Loc::Return => self.code.encode(instrs::cp(1, lhs.0)),
|
||||
l => unimplemented!("{:?}", l),
|
||||
}
|
||||
self.gpa.free(lhs);
|
||||
}
|
||||
16 if matches!(right, Loc::Return) => {
|
||||
..=16 if matches!(right, Loc::Return) => {
|
||||
let (lhs, loff) = left.to_ptr(size);
|
||||
self.code.encode(instrs::st(1, lhs.get(), loff, 16));
|
||||
self.gpa.free_cow(lhs);
|
||||
}
|
||||
16..=u64::MAX => {
|
||||
..=u64::MAX => {
|
||||
let (rhs, roff) = right.to_ptr(size);
|
||||
let (lhs, loff) = left.to_ptr(size);
|
||||
let (rhs, lhs) = (self.to_owned(rhs), self.to_owned(lhs));
|
||||
|
||||
self.code.encode(instrs::addi64(rhs.0, rhs.0, roff));
|
||||
self.code.encode(instrs::addi64(lhs.0, lhs.0, loff));
|
||||
self.code.addi64(rhs.0, rhs.0, roff);
|
||||
self.code.addi64(lhs.0, lhs.0, loff);
|
||||
self.code
|
||||
.encode(instrs::bmc(lhs.0, rhs.0, size.try_into().unwrap()));
|
||||
|
||||
self.gpa.free(rhs);
|
||||
self.gpa.free(lhs);
|
||||
}
|
||||
s => unimplemented!("size: {}", s),
|
||||
}
|
||||
|
||||
Some(Value::VOID)
|
||||
|
@ -1102,7 +1198,7 @@ impl<'a> Codegen<'a> {
|
|||
}
|
||||
Loc::StackRef(off) => {
|
||||
let size = self.size_of(ty);
|
||||
let stack = self.alloc_stack(size as u32);
|
||||
let stack = self.alloc_stack(size);
|
||||
self.assign(ty, Loc::Stack(stack), Loc::StackRef(off));
|
||||
Loc::Stack(stack)
|
||||
}
|
||||
|
@ -1118,7 +1214,7 @@ impl<'a> Codegen<'a> {
|
|||
let (Loc::Stack(stack) | Loc::StackRef(stack)) = value.loc else {
|
||||
todo!("expected stack location, got {:?}", value.loc);
|
||||
};
|
||||
self.code.encode(instrs::addi64(p, STACK_PTR, stack));
|
||||
self.code.addi64(p, STACK_PTR, stack);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1151,24 +1247,24 @@ impl<'a> Codegen<'a> {
|
|||
fn load_arg(&mut self, ty: Type, parama: &mut Range<u8>) -> Loc {
|
||||
let size = self.size_of(ty);
|
||||
match size {
|
||||
8 => {
|
||||
let stack = self.alloc_stack(8);
|
||||
self.store_stack(parama.next().unwrap(), stack, 8);
|
||||
0 => Loc::Imm(0),
|
||||
..=8 => {
|
||||
let stack = self.alloc_stack(size as _);
|
||||
self.store_stack(parama.next().unwrap(), stack, size as _);
|
||||
Loc::Stack(stack)
|
||||
}
|
||||
16 => {
|
||||
let stack = self.alloc_stack(16);
|
||||
self.store_stack(parama.next().unwrap(), stack, 8);
|
||||
self.store_stack(parama.next().unwrap(), stack + 8, 8);
|
||||
..=16 => {
|
||||
let stack = self.alloc_stack(size);
|
||||
self.store_stack(parama.next().unwrap(), stack, size as _);
|
||||
parama.next().unwrap();
|
||||
Loc::Stack(stack)
|
||||
}
|
||||
24..=u64::MAX => {
|
||||
..=u64::MAX => {
|
||||
let ptr = parama.next().unwrap();
|
||||
let stack = self.alloc_stack(size as u32);
|
||||
let stack = self.alloc_stack(size);
|
||||
self.assign(ty, Loc::StackRef(stack), Loc::DerefRef(ptr, 0));
|
||||
Loc::Stack(stack)
|
||||
}
|
||||
blah => todo!("{blah:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1184,8 +1280,11 @@ impl<'a> Codegen<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn assert_ty(&self, pos: parser::Pos, ty: Type, expected: Type) {
|
||||
if ty != expected {
|
||||
#[must_use]
|
||||
fn assert_ty(&self, pos: parser::Pos, ty: Type, expected: Type) -> Type {
|
||||
if let Some(res) = bt::try_upcast(ty, expected) {
|
||||
res
|
||||
} else {
|
||||
let ty = self.display_ty(ty);
|
||||
let expected = self.display_ty(expected);
|
||||
self.report(pos, format_args!("expected {ty}, got {expected}"));
|
||||
|
@ -1211,7 +1310,7 @@ impl Value {
|
|||
};
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
enum Loc {
|
||||
Reg(LinReg),
|
||||
RegRef(Reg),
|
||||
|
@ -1378,5 +1477,6 @@ mod tests {
|
|||
fb_driver => include_str!("../examples/fb_driver.hb");
|
||||
pointers => include_str!("../examples/pointers.hb");
|
||||
structs => include_str!("../examples/structs.hb");
|
||||
different_types => include_str!("../examples/different_types.hb");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,13 +6,17 @@ pub fn len(ident: Ident) -> u32 {
|
|||
ident & ((1 << LEN_BITS) - 1)
|
||||
}
|
||||
|
||||
pub fn is_null(ident: Ident) -> bool {
|
||||
(ident >> LEN_BITS) == 0
|
||||
}
|
||||
|
||||
pub fn pos(ident: Ident) -> u32 {
|
||||
ident >> LEN_BITS
|
||||
(ident >> LEN_BITS).saturating_sub(1)
|
||||
}
|
||||
|
||||
pub fn new(pos: u32, len: u32) -> Ident {
|
||||
debug_assert!(len < (1 << LEN_BITS));
|
||||
(pos << LEN_BITS) | len
|
||||
((pos + 1) << LEN_BITS) | len
|
||||
}
|
||||
|
||||
pub fn range(ident: Ident) -> std::ops::Range<usize> {
|
||||
|
|
|
@ -109,6 +109,9 @@ gen_token_kind! {
|
|||
Assign = "=",
|
||||
#[prec = 21]
|
||||
Le = "<=",
|
||||
Ge = ">=",
|
||||
Lt = "<",
|
||||
Gt = ">",
|
||||
Eq = "==",
|
||||
#[prec = 22]
|
||||
Amp = "&",
|
||||
|
@ -216,6 +219,9 @@ impl<'a> Iterator for Lexer<'a> {
|
|||
b'=' if self.advance_if(b'=') => T::Eq,
|
||||
b'=' => T::Assign,
|
||||
b'<' if self.advance_if(b'=') => T::Le,
|
||||
b'<' => T::Lt,
|
||||
b'>' if self.advance_if(b'=') => T::Ge,
|
||||
b'>' => T::Gt,
|
||||
b'+' => T::Plus,
|
||||
b'-' => T::Minus,
|
||||
b'*' => T::Star,
|
||||
|
|
|
@ -80,7 +80,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
break;
|
||||
};
|
||||
|
||||
if prec < min_prec {
|
||||
if prec <= min_prec {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -100,7 +100,13 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
fn try_resolve_builtin(name: &str) -> Option<Ident> {
|
||||
// FIXME: we actually do this the second time in the codegen
|
||||
Some(match name {
|
||||
"int" => bt::INT,
|
||||
"int" | "i64" => bt::INT,
|
||||
"i8" => bt::I8,
|
||||
"i16" => bt::I16,
|
||||
"i32" => bt::I32,
|
||||
"u8" => bt::U8,
|
||||
"u16" => bt::U16,
|
||||
"uint" | "u32" => bt::U32,
|
||||
"bool" => bt::BOOL,
|
||||
"void" => bt::VOID,
|
||||
"never" => bt::NEVER,
|
||||
|
|
|
@ -12,7 +12,10 @@ pub fn run_test(name: &'static str, input: &'static str, test: fn(&'static str,
|
|||
test(input, &mut output);
|
||||
|
||||
let mut root = PathBuf::from(std::env::var("PT_TEST_ROOT").unwrap_or("tests".to_string()));
|
||||
root.push(name.replace("::", "_"));
|
||||
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();
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
code size: 220
|
||||
code size: 209
|
||||
ret: 1
|
||||
status: Ok(())
|
3
hblang/tests/codegen_tests_different_types.txt
Normal file
3
hblang/tests/codegen_tests_different_types.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
code size: 336
|
||||
ret: 512
|
||||
status: Ok(())
|
|
@ -1,3 +1,3 @@
|
|||
code size: 107
|
||||
code size: 96
|
||||
ret: 1
|
||||
status: Ok(())
|
|
@ -1,3 +1,3 @@
|
|||
code size: 1114
|
||||
code size: 1081
|
||||
ret: 0
|
||||
status: Ok(())
|
|
@ -1,3 +1,3 @@
|
|||
code size: 399
|
||||
code size: 388
|
||||
ret: 33
|
||||
status: Ok(())
|
|
@ -1,3 +1,3 @@
|
|||
code size: 364
|
||||
code size: 353
|
||||
ret: 55
|
||||
status: Ok(())
|
|
@ -1,3 +1,3 @@
|
|||
code size: 469
|
||||
code size: 458
|
||||
ret: 55
|
||||
status: Ok(())
|
|
@ -1,3 +1,3 @@
|
|||
code size: 339
|
||||
code size: 331
|
||||
ret: 0
|
||||
status: Ok(())
|
|
@ -1,3 +1,3 @@
|
|||
code size: 596
|
||||
code size: 544
|
||||
ret: 3
|
||||
status: Ok(())
|
Loading…
Reference in a new issue