forked from AbleOS/holey-bytes
implementing wide returns and adding integer upcast ops
This commit is contained in:
parent
d5c90b95a7
commit
11c8755b18
|
@ -395,29 +395,6 @@ main := fn(): int {
|
|||
}
|
||||
```
|
||||
|
||||
#### wide_ret
|
||||
```hb
|
||||
OemIdent := struct {
|
||||
dos_version: [u8; 8],
|
||||
dos_version_name: [u8; 8],
|
||||
}
|
||||
|
||||
Stru := struct {
|
||||
a: u16,
|
||||
b: u16,
|
||||
}
|
||||
|
||||
small_struct := fn(): Stru {
|
||||
return .{a: 0, b: 0}
|
||||
}
|
||||
|
||||
main := fn(major: int, minor: int): OemIdent {
|
||||
small_struct()
|
||||
ver := [u8].(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
return OemIdent.(ver, ver)
|
||||
}
|
||||
```
|
||||
|
||||
### Incomplete Examples
|
||||
|
||||
#### comptime_pointers
|
||||
|
@ -548,6 +525,34 @@ main := fn(): int {
|
|||
|
||||
### Purely Testing Examples
|
||||
|
||||
#### wide_ret
|
||||
```hb
|
||||
OemIdent := struct {
|
||||
dos_version: [u8; 8],
|
||||
dos_version_name: [u8; 8],
|
||||
}
|
||||
|
||||
Stru := struct {
|
||||
a: u16,
|
||||
b: u16,
|
||||
}
|
||||
|
||||
small_struct := fn(): Stru {
|
||||
return .{a: 0, b: 0}
|
||||
}
|
||||
|
||||
maina := fn(major: int, minor: int): OemIdent {
|
||||
_f := small_struct()
|
||||
ver := [u8].(0, 0, 0, 3, 1, 0, 0, 0)
|
||||
return OemIdent.(ver, ver)
|
||||
}
|
||||
|
||||
main := fn(): int {
|
||||
m := maina(0, 0)
|
||||
return m.dos_version[3] - m.dos_version_name[4]
|
||||
}
|
||||
```
|
||||
|
||||
#### comptime_min_reg_leak
|
||||
```hb
|
||||
a := @use("math.hb").min(100, 50)
|
||||
|
|
245
lang/src/son.rs
245
lang/src/son.rs
|
@ -7,7 +7,7 @@ use {
|
|||
parser::{
|
||||
self,
|
||||
idfl::{self},
|
||||
Expr, ExprRef, FileId, Pos,
|
||||
CtorField, Expr, ExprRef, FileId, Pos,
|
||||
},
|
||||
reg, task,
|
||||
ty::{self, ArrayLen, Tuple},
|
||||
|
@ -483,6 +483,7 @@ impl Nodes {
|
|||
Kind::Stre => write!(out, "stre: "),
|
||||
Kind::Mem => write!(out, " mem: "),
|
||||
Kind::Idk => write!(out, " idk: "),
|
||||
Kind::Extend => write!(out, " ext: "),
|
||||
}?;
|
||||
|
||||
if self[node].kind != Kind::Loop && self[node].kind != Kind::Region {
|
||||
|
@ -837,6 +838,8 @@ pub enum Kind {
|
|||
Phi,
|
||||
Arg,
|
||||
// [ctrl, oper]
|
||||
Extend,
|
||||
// [ctrl, oper]
|
||||
UnOp {
|
||||
op: lexer::TokenKind,
|
||||
},
|
||||
|
@ -1031,9 +1034,9 @@ impl ItemCtx {
|
|||
let mut nodes = core::mem::take(&mut self.nodes);
|
||||
nodes.visited.clear(nodes.values.len());
|
||||
|
||||
let func = Function::new(&mut nodes, tys, sig);
|
||||
let fuc = Function::new(&mut nodes, tys, sig);
|
||||
let mut ralloc = Regalloc::default(); // TODO: reuse
|
||||
log::info!("{:?}", func);
|
||||
log::info!("{:?}", fuc);
|
||||
if self.call_count != 0 {
|
||||
core::mem::swap(
|
||||
&mut ralloc.env.preferred_regs_by_class,
|
||||
|
@ -1046,7 +1049,7 @@ impl ItemCtx {
|
|||
validate_ssa: false,
|
||||
algorithm: regalloc2::Algorithm::Ion,
|
||||
};
|
||||
regalloc2::run_with_ctx(&func, &ralloc.env, &options, &mut ralloc.ctx)
|
||||
regalloc2::run_with_ctx(&fuc, &ralloc.env, &options, &mut ralloc.ctx)
|
||||
.unwrap_or_else(|err| panic!("{err}"));
|
||||
|
||||
if self.call_count != 0 {
|
||||
|
@ -1067,10 +1070,10 @@ impl ItemCtx {
|
|||
*saved_regs.entry(hvenc).or_insert(would_insert)
|
||||
};
|
||||
|
||||
for (i, block) in func.blocks.iter().enumerate() {
|
||||
for (i, block) in fuc.blocks.iter().enumerate() {
|
||||
let blk = regalloc2::Block(i as _);
|
||||
func.nodes[block.nid].offset = self.code.len() as _;
|
||||
for instr_or_edit in ralloc.ctx.output.block_insts_and_edits(&func, blk) {
|
||||
fuc.nodes[block.nid].offset = self.code.len() as _;
|
||||
for instr_or_edit in ralloc.ctx.output.block_insts_and_edits(&fuc, blk) {
|
||||
let inst = match instr_or_edit {
|
||||
regalloc2::InstOrEdit::Inst(inst) => inst,
|
||||
regalloc2::InstOrEdit::Edit(®alloc2::Edit::Move { from, to }) => {
|
||||
|
@ -1079,16 +1082,16 @@ impl ItemCtx {
|
|||
}
|
||||
};
|
||||
|
||||
let nid = func.instrs[inst.index()].nid;
|
||||
let nid = fuc.instrs[inst.index()].nid;
|
||||
if nid == NEVER {
|
||||
continue;
|
||||
};
|
||||
let allocs = ralloc.ctx.output.inst_allocs(inst);
|
||||
let node = &func.nodes[nid];
|
||||
let node = &fuc.nodes[nid];
|
||||
match node.kind {
|
||||
Kind::If => {
|
||||
let &[_, cond] = node.inputs.as_slice() else { unreachable!() };
|
||||
if let Kind::BinOp { op } = func.nodes[cond].kind
|
||||
if let Kind::BinOp { op } = fuc.nodes[cond].kind
|
||||
&& let Some((op, swapped)) = op.cond_op(node.ty.is_signed())
|
||||
{
|
||||
let rel = Reloc::new(self.code.len(), 3, 2);
|
||||
|
@ -1109,13 +1112,19 @@ impl ItemCtx {
|
|||
Kind::Return => {
|
||||
match tys.size_of(sig.ret) {
|
||||
0..=8 => {}
|
||||
9..=16 => todo!(),
|
||||
size @ 9..=16 => {
|
||||
self.emit(instrs::ld(reg::RET, atr(allocs[0]), 0, size as _));
|
||||
}
|
||||
size @ 17.. => {
|
||||
self.emit(instrs::bmc(atr(allocs[0]), 1, size.try_into().unwrap()));
|
||||
self.emit(instrs::bmc(
|
||||
atr(allocs[0]),
|
||||
reg::RET,
|
||||
size.try_into().unwrap(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if i != func.blocks.len() - 1 {
|
||||
if i != fuc.blocks.len() - 1 {
|
||||
let rel = Reloc::new(self.code.len(), 1, 4);
|
||||
self.ret_relocs.push(rel);
|
||||
self.emit(instrs::jmp(0));
|
||||
|
@ -1124,6 +1133,22 @@ impl ItemCtx {
|
|||
Kind::CInt { value } => {
|
||||
self.emit(instrs::li64(atr(allocs[0]), value as _));
|
||||
}
|
||||
Kind::Extend => {
|
||||
let base = fuc.nodes[node.inputs[1]].ty;
|
||||
let dest = node.ty;
|
||||
|
||||
match (base.is_signed(), dest.is_signed()) {
|
||||
(true, true) => {
|
||||
let op = [instrs::sxt8, instrs::sxt16, instrs::sxt32]
|
||||
[tys.size_of(base).ilog2() as usize];
|
||||
self.emit(op(atr(allocs[0]), atr(allocs[1])))
|
||||
}
|
||||
_ => {
|
||||
let mask = (1u64 << (tys.size_of(base) * 8)) - 1;
|
||||
self.emit(instrs::andi(atr(allocs[0]), atr(allocs[1]), mask));
|
||||
}
|
||||
}
|
||||
}
|
||||
Kind::UnOp { op } => {
|
||||
let op = op.unop().expect("TODO: unary operator not supported");
|
||||
let &[dst, oper] = allocs else { unreachable!() };
|
||||
|
@ -1132,15 +1157,15 @@ impl ItemCtx {
|
|||
Kind::BinOp { op } => {
|
||||
let &[.., rhs] = node.inputs.as_slice() else { unreachable!() };
|
||||
|
||||
if let Kind::CInt { value } = func.nodes[rhs].kind
|
||||
&& func.nodes[rhs].lock_rc != 0
|
||||
if let Kind::CInt { value } = fuc.nodes[rhs].kind
|
||||
&& fuc.nodes[rhs].lock_rc != 0
|
||||
&& let Some(op) =
|
||||
op.imm_binop(node.ty.is_signed(), func.tys.size_of(node.ty))
|
||||
op.imm_binop(node.ty.is_signed(), fuc.tys.size_of(node.ty))
|
||||
{
|
||||
let &[dst, lhs] = allocs else { unreachable!() };
|
||||
self.emit(op(atr(dst), atr(lhs), value as _));
|
||||
} else if let Some(op) =
|
||||
op.binop(node.ty.is_signed(), func.tys.size_of(node.ty))
|
||||
op.binop(node.ty.is_signed(), fuc.tys.size_of(node.ty))
|
||||
{
|
||||
let &[dst, lhs, rhs] = allocs else { unreachable!() };
|
||||
self.emit(op(atr(dst), atr(lhs), atr(rhs)));
|
||||
|
@ -1155,6 +1180,10 @@ impl ItemCtx {
|
|||
reloc: Reloc::new(self.code.len(), 3, 4),
|
||||
});
|
||||
self.emit(instrs::jal(reg::RET_ADDR, reg::ZERO, 0));
|
||||
if let size @ 9..=16 = tys.size_of(node.ty) {
|
||||
let stck = fuc.nodes[*node.inputs.last().unwrap()].offset;
|
||||
self.emit(instrs::st(reg::RET, reg::STACK_PTR, stck as _, size as _));
|
||||
}
|
||||
}
|
||||
Kind::Global { global } => {
|
||||
let reloc = Reloc::new(self.code.len(), 3, 4);
|
||||
|
@ -1166,24 +1195,24 @@ impl ItemCtx {
|
|||
}
|
||||
Kind::Stck => {
|
||||
let base = reg::STACK_PTR;
|
||||
let offset = func.nodes[nid].offset;
|
||||
let offset = fuc.nodes[nid].offset;
|
||||
self.emit(instrs::addi64(atr(allocs[0]), base, offset as _));
|
||||
}
|
||||
Kind::Idk => {}
|
||||
Kind::Load => {
|
||||
let mut region = node.inputs[1];
|
||||
let mut offset = 0;
|
||||
if func.nodes[region].kind == (Kind::BinOp { op: TokenKind::Add })
|
||||
if fuc.nodes[region].kind == (Kind::BinOp { op: TokenKind::Add })
|
||||
&& let Kind::CInt { value } =
|
||||
func.nodes[func.nodes[region].inputs[2]].kind
|
||||
fuc.nodes[fuc.nodes[region].inputs[2]].kind
|
||||
{
|
||||
region = func.nodes[region].inputs[1];
|
||||
region = fuc.nodes[region].inputs[1];
|
||||
offset = value as Offset;
|
||||
}
|
||||
let size = tys.size_of(node.ty);
|
||||
if size <= 8 {
|
||||
let (base, offset) = match func.nodes[region].kind {
|
||||
Kind::Stck => (reg::STACK_PTR, func.nodes[region].offset + offset),
|
||||
let (base, offset) = match fuc.nodes[region].kind {
|
||||
Kind::Stck => (reg::STACK_PTR, fuc.nodes[region].offset + offset),
|
||||
_ => (atr(allocs[1]), offset),
|
||||
};
|
||||
self.emit(instrs::ld(atr(allocs[0]), base, offset as _, size as _));
|
||||
|
@ -1194,15 +1223,15 @@ impl ItemCtx {
|
|||
let mut region = node.inputs[2];
|
||||
let mut offset = 0;
|
||||
let size = u16::try_from(tys.size_of(node.ty)).expect("TODO");
|
||||
if func.nodes[region].kind == (Kind::BinOp { op: TokenKind::Add })
|
||||
if fuc.nodes[region].kind == (Kind::BinOp { op: TokenKind::Add })
|
||||
&& let Kind::CInt { value } =
|
||||
func.nodes[func.nodes[region].inputs[2]].kind
|
||||
fuc.nodes[fuc.nodes[region].inputs[2]].kind
|
||||
&& size <= 8
|
||||
{
|
||||
region = func.nodes[region].inputs[1];
|
||||
region = fuc.nodes[region].inputs[1];
|
||||
offset = value as Offset;
|
||||
}
|
||||
let nd = &func.nodes[region];
|
||||
let nd = &fuc.nodes[region];
|
||||
let (base, offset, src) = match nd.kind {
|
||||
Kind::Stck if size <= 8 => {
|
||||
(reg::STACK_PTR, nd.offset + offset, allocs[0])
|
||||
|
@ -1215,7 +1244,14 @@ impl ItemCtx {
|
|||
self.emit(instrs::st(atr(src), base, offset as _, size));
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
Kind::Start
|
||||
| Kind::Entry
|
||||
| Kind::Mem
|
||||
| Kind::End
|
||||
| Kind::Then
|
||||
| Kind::Else
|
||||
| Kind::Phi
|
||||
| Kind::Arg => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1635,12 +1671,16 @@ impl<'a> Codegen<'a> {
|
|||
Expr::Ident { id, pos, .. } => {
|
||||
let decl = self.find_type(pos, self.ci.file, Ok(id), self.files);
|
||||
match decl.expand() {
|
||||
ty::Kind::Builtin(ty::NEVER) => Value::NEVER,
|
||||
ty::Kind::Global(global) => {
|
||||
let gl = &self.tys.ins.globals[global as usize];
|
||||
let value = self.ci.nodes.new_node(gl.ty, Kind::Global { global }, [VOID]);
|
||||
Some(Value::ptr(value).ty(gl.ty))
|
||||
}
|
||||
_ => todo!("{decl:?}"),
|
||||
_ => self.report_unhandled_ast(
|
||||
expr,
|
||||
format_args!("identifier evaluated to '{}'", self.ty_display(decl)),
|
||||
),
|
||||
}
|
||||
}
|
||||
Expr::Comment { .. } => Some(Value::VOID),
|
||||
|
@ -1661,12 +1701,15 @@ impl<'a> Codegen<'a> {
|
|||
Some(Value::new(global).ty(ty))
|
||||
}
|
||||
Expr::Return { pos, val } => {
|
||||
let value = if let Some(val) = val {
|
||||
let mut value = if let Some(val) = val {
|
||||
self.expr_ctx(val, Ctx { ty: self.ci.ret })?
|
||||
} else {
|
||||
Value { ty: ty::Id::VOID, ..Default::default() }
|
||||
};
|
||||
|
||||
let expected = *self.ci.ret.get_or_insert(value.ty);
|
||||
self.assert_ty(pos, &mut value, expected, "return value");
|
||||
|
||||
let mut inps = Vc::from([self.ci.ctrl, value.id]);
|
||||
self.ci.nodes.load_loop_store(&mut self.ci.scope.store, &mut self.ci.loops);
|
||||
if let Some(str) = self.ci.scope.store.to_store() {
|
||||
|
@ -1678,9 +1721,6 @@ impl<'a> Codegen<'a> {
|
|||
self.ci.nodes[NEVER].inputs.push(self.ci.ctrl);
|
||||
self.ci.nodes[self.ci.ctrl].outputs.push(NEVER);
|
||||
|
||||
let expected = *self.ci.ret.get_or_insert(value.ty);
|
||||
self.assert_ty(pos, value.ty, expected, "return value");
|
||||
|
||||
None
|
||||
}
|
||||
Expr::Field { target, name, pos } => {
|
||||
|
@ -1760,23 +1800,16 @@ impl<'a> Codegen<'a> {
|
|||
}
|
||||
Some(self.ci.nodes.new_node_lit(val.ty, Kind::UnOp { op }, [VOID, val.id]))
|
||||
}
|
||||
Expr::BinOp { left: &Expr::Ident { id, .. }, op: TokenKind::Decl, right } => {
|
||||
let mut value = self.raw_expr(right)?;
|
||||
self.strip_var(&mut value);
|
||||
self.ci.nodes.lock(value.id);
|
||||
self.ci.scope.vars.push(Variable {
|
||||
id,
|
||||
value: value.id,
|
||||
ptr: value.ptr,
|
||||
ty: value.ty,
|
||||
});
|
||||
Expr::BinOp { left, op: TokenKind::Decl, right } => {
|
||||
let right = self.raw_expr(right)?;
|
||||
self.assign_pattern(left, right);
|
||||
Some(Value::VOID)
|
||||
}
|
||||
Expr::BinOp { left, op: TokenKind::Assign, right } => {
|
||||
let dest = self.raw_expr(left)?;
|
||||
let value = self.expr_ctx(right, Ctx::default().with_ty(dest.ty))?;
|
||||
let mut value = self.expr_ctx(right, Ctx::default().with_ty(dest.ty))?;
|
||||
|
||||
self.assert_ty(left.pos(), value.ty, dest.ty, "assignment source");
|
||||
self.assert_ty(left.pos(), &mut value, dest.ty, "assignment source");
|
||||
|
||||
if dest.var {
|
||||
self.ci.nodes.lock(value.id);
|
||||
|
@ -1791,13 +1824,16 @@ impl<'a> Codegen<'a> {
|
|||
|
||||
Some(Value::VOID)
|
||||
}
|
||||
Expr::BinOp { left, op, right } if op != TokenKind::Assign => {
|
||||
let lhs = self.expr_ctx(left, ctx)?;
|
||||
Expr::BinOp { left, op, right }
|
||||
if !matches!(op, TokenKind::Assign | TokenKind::Decl) =>
|
||||
{
|
||||
let mut lhs = self.expr_ctx(left, ctx)?;
|
||||
self.ci.nodes.lock(lhs.id);
|
||||
let rhs = self.expr_ctx(right, Ctx::default().with_ty(lhs.ty));
|
||||
self.ci.nodes.unlock(lhs.id);
|
||||
let ty = self.binop_ty(left.pos(), rhs?.ty, lhs.ty, op);
|
||||
let inps = [VOID, lhs.id, rhs?.id];
|
||||
let mut rhs = rhs?;
|
||||
let ty = self.binop_ty(left.pos(), &mut rhs, &mut lhs, op);
|
||||
let inps = [VOID, lhs.id, rhs.id];
|
||||
Some(self.ci.nodes.new_node_lit(ty::bin_ret(ty, op), Kind::BinOp { op }, inps))
|
||||
}
|
||||
Expr::Index { base, index } => {
|
||||
|
@ -1886,7 +1922,7 @@ impl<'a> Codegen<'a> {
|
|||
Expr::Call { func, args, .. } => {
|
||||
self.ci.call_count += 1;
|
||||
let ty = self.ty(func);
|
||||
let ty::Kind::Func(fnc) = ty.expand() else {
|
||||
let ty::Kind::Func(fu) = ty.expand() else {
|
||||
self.report(
|
||||
func.pos(),
|
||||
fa!("compiler cant (yet) call '{}'", self.ty_display(ty)),
|
||||
|
@ -1894,9 +1930,9 @@ impl<'a> Codegen<'a> {
|
|||
return Value::NEVER;
|
||||
};
|
||||
|
||||
self.make_func_reachable(fnc);
|
||||
self.make_func_reachable(fu);
|
||||
|
||||
let fuc = &self.tys.ins.funcs[fnc as usize];
|
||||
let fuc = &self.tys.ins.funcs[fu as usize];
|
||||
let sig = fuc.sig.expect("TODO: generic functions");
|
||||
let ast = &self.files[fuc.file as usize];
|
||||
let &Expr::Closure { args: cargs, .. } = fuc.expr.get(ast).unwrap() else {
|
||||
|
@ -1920,10 +1956,10 @@ impl<'a> Codegen<'a> {
|
|||
if self.tys.size_of(ty) == 0 {
|
||||
continue;
|
||||
}
|
||||
let value = self.expr_ctx(arg, Ctx::default().with_ty(ty))?;
|
||||
let mut value = self.expr_ctx(arg, Ctx::default().with_ty(ty))?;
|
||||
debug_assert_ne!(self.ci.nodes[value.id].kind, Kind::Stre);
|
||||
debug_assert_ne!(value.id, 0);
|
||||
self.assert_ty(arg.pos(), value.ty, ty, fa!("argument {}", carg.name));
|
||||
self.assert_ty(arg.pos(), &mut value, ty, fa!("argument {}", carg.name));
|
||||
|
||||
inps.push(value.id);
|
||||
}
|
||||
|
@ -1945,15 +1981,14 @@ impl<'a> Codegen<'a> {
|
|||
|
||||
let alt_value = match self.tys.size_of(sig.ret) {
|
||||
0..=8 => None,
|
||||
9..=16 => todo!(),
|
||||
17.. => {
|
||||
9.. => {
|
||||
let stck = self.ci.nodes.new_node_nop(sig.ret, Kind::Stck, [VOID, MEM]);
|
||||
inps.push(stck);
|
||||
Some(Value::ptr(stck).ty(sig.ret))
|
||||
}
|
||||
};
|
||||
|
||||
self.ci.ctrl = self.ci.nodes.new_node(sig.ret, Kind::Call { func: fnc }, inps);
|
||||
self.ci.ctrl = self.ci.nodes.new_node(sig.ret, Kind::Call { func: fu }, inps);
|
||||
|
||||
self.store_mem(VOID, VOID);
|
||||
|
||||
|
@ -2028,8 +2063,8 @@ impl<'a> Codegen<'a> {
|
|||
for (field, offset) in
|
||||
fields.iter().zip((0u32..).step_by(elem_size as usize))
|
||||
{
|
||||
let value = self.expr_ctx(field, Ctx::default().with_ty(elem))?;
|
||||
_ = self.assert_ty(field.pos(), value.ty, elem, "array value");
|
||||
let mut value = self.expr_ctx(field, Ctx::default().with_ty(elem))?;
|
||||
_ = self.assert_ty(field.pos(), &mut value, elem, "array value");
|
||||
let mem = self.offset(mem, offset);
|
||||
self.store_mem(mem, value.id);
|
||||
}
|
||||
|
@ -2124,8 +2159,8 @@ impl<'a> Codegen<'a> {
|
|||
let mut ret = Some(Value::VOID);
|
||||
for stmt in stmts {
|
||||
ret = ret.and(self.expr(stmt));
|
||||
if let Some(id) = ret {
|
||||
self.assert_ty(stmt.pos(), id.ty, ty::Id::VOID, "statement");
|
||||
if let Some(mut id) = ret {
|
||||
self.assert_ty(stmt.pos(), &mut id, ty::Id::VOID, "statement");
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
@ -2320,6 +2355,37 @@ impl<'a> Codegen<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn assign_pattern(&mut self, pat: &Expr, mut right: Value) {
|
||||
match *pat {
|
||||
Expr::Ident { id, .. } => {
|
||||
self.strip_var(&mut right);
|
||||
self.ci.nodes.lock(right.id);
|
||||
self.ci.scope.vars.push(Variable {
|
||||
id,
|
||||
value: right.id,
|
||||
ptr: right.ptr,
|
||||
ty: right.ty,
|
||||
});
|
||||
}
|
||||
Expr::Ctor { pos, fields, .. } => {
|
||||
let ty::Kind::Struct(idx) = right.ty.expand() else {
|
||||
self.report(pos, "can't use struct destruct on non struct value (TODO: shold work with modules)");
|
||||
return;
|
||||
};
|
||||
|
||||
for &CtorField { pos, name, ref value } in fields {
|
||||
let Some((offset, ty)) = OffsetIter::offset_of(&self.tys, idx, name) else {
|
||||
self.report(pos, format_args!("field not found: {name:?}"));
|
||||
continue;
|
||||
};
|
||||
let off = self.offset(right.id, offset);
|
||||
self.assign_pattern(value, Value::ptr(off).ty(ty));
|
||||
}
|
||||
}
|
||||
ref pat => self.report_unhandled_ast(pat, "pattern"),
|
||||
}
|
||||
}
|
||||
|
||||
fn expr_ctx(&mut self, expr: &Expr, ctx: Ctx) -> Option<Value> {
|
||||
let mut n = self.raw_expr_ctx(expr, ctx)?;
|
||||
self.strip_var(&mut n);
|
||||
|
@ -2492,26 +2558,46 @@ impl<'a> Codegen<'a> {
|
|||
|
||||
#[must_use]
|
||||
#[track_caller]
|
||||
fn binop_ty(&self, pos: Pos, lhs: ty::Id, rhs: ty::Id, op: TokenKind) -> ty::Id {
|
||||
if let Some(res) = lhs.try_upcast(rhs, ty::TyCheck::BinOp) {
|
||||
res
|
||||
fn binop_ty(&mut self, pos: Pos, lhs: &mut Value, rhs: &mut Value, op: TokenKind) -> ty::Id {
|
||||
if let Some(upcasted) = lhs.ty.try_upcast(rhs.ty, ty::TyCheck::BinOp) {
|
||||
if lhs.ty != upcasted {
|
||||
lhs.ty = upcasted;
|
||||
lhs.id = self.ci.nodes.new_node(upcasted, Kind::Extend, [VOID, lhs.id]);
|
||||
} else if rhs.ty != upcasted {
|
||||
rhs.ty = upcasted;
|
||||
rhs.id = self.ci.nodes.new_node(upcasted, Kind::Extend, [VOID, rhs.id]);
|
||||
}
|
||||
upcasted
|
||||
} else {
|
||||
let ty = self.ty_display(lhs);
|
||||
let expected = self.ty_display(rhs);
|
||||
let ty = self.ty_display(lhs.ty);
|
||||
let expected = self.ty_display(rhs.ty);
|
||||
self.report(pos, fa!("'{ty} {op} {expected}' is not supported"));
|
||||
ty::Id::NEVER
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn assert_ty(&self, pos: Pos, ty: ty::Id, expected: ty::Id, hint: impl fmt::Display) -> bool {
|
||||
if ty.try_upcast(expected, ty::TyCheck::BinOp) != Some(expected) {
|
||||
let ty = self.ty_display(ty);
|
||||
fn assert_ty(
|
||||
&mut self,
|
||||
pos: Pos,
|
||||
src: &mut Value,
|
||||
expected: ty::Id,
|
||||
hint: impl fmt::Display,
|
||||
) -> bool {
|
||||
if let Some(upcasted) = src.ty.try_upcast(expected, ty::TyCheck::BinOp)
|
||||
&& upcasted == expected
|
||||
{
|
||||
if src.ty != upcasted {
|
||||
src.ty = upcasted;
|
||||
src.id = self.ci.nodes.new_node(upcasted, Kind::Extend, [VOID, src.id]);
|
||||
}
|
||||
true
|
||||
} else {
|
||||
let ty = self.ty_display(src.ty);
|
||||
let expected = self.ty_display(expected);
|
||||
self.report(pos, fa!("expected {hint} to be of type {expected}, got {ty}"));
|
||||
return false;
|
||||
false
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
|
@ -2528,7 +2614,7 @@ impl<'a> Codegen<'a> {
|
|||
}
|
||||
|
||||
#[track_caller]
|
||||
fn report_unhandled_ast(&self, ast: &Expr, hint: &str) -> ! {
|
||||
fn report_unhandled_ast(&self, ast: &Expr, hint: impl Display) -> ! {
|
||||
log::info!("{ast:#?}");
|
||||
self.fatal_report(ast.pos(), fa!("compiler does not (yet) know how to handle ({hint})"));
|
||||
}
|
||||
|
@ -2727,7 +2813,9 @@ impl<'a> Function<'a> {
|
|||
regalloc2::PReg::new(1, regalloc2::RegClass::Int),
|
||||
)]
|
||||
}
|
||||
9..=16 => todo!(),
|
||||
9..=16 => {
|
||||
vec![self.urg(self.nodes[node.inputs[1]].inputs[1])]
|
||||
}
|
||||
17.. => {
|
||||
vec![self.urg(node.inputs[1])]
|
||||
}
|
||||
|
@ -2751,6 +2839,10 @@ impl<'a> Function<'a> {
|
|||
let ops = vec![self.drg(nid)];
|
||||
self.add_instr(nid, ops);
|
||||
}
|
||||
Kind::Extend => {
|
||||
let ops = vec![self.drg(nid), self.urg(node.inputs[1])];
|
||||
self.add_instr(nid, ops);
|
||||
}
|
||||
Kind::Entry => {
|
||||
self.nodes[nid].ralloc_backref = self.add_block(nid);
|
||||
|
||||
|
@ -2863,8 +2955,7 @@ impl<'a> Function<'a> {
|
|||
}
|
||||
|
||||
match self.tys.size_of(fuc.ret) {
|
||||
0..=8 => {}
|
||||
9..=16 => todo!(),
|
||||
0..=16 => {}
|
||||
17.. => {
|
||||
ops.push(regalloc2::Operand::reg_fixed_use(
|
||||
self.rg(*node.inputs.last().unwrap()),
|
||||
|
@ -3332,11 +3423,10 @@ mod tests {
|
|||
global_variables;
|
||||
//directives;
|
||||
c_strings;
|
||||
//struct_patterns;
|
||||
struct_patterns;
|
||||
arrays;
|
||||
//inline;
|
||||
idk;
|
||||
//wide_ret;
|
||||
|
||||
// Incomplete Examples;
|
||||
//comptime_pointers;
|
||||
|
@ -3345,6 +3435,7 @@ mod tests {
|
|||
fb_driver;
|
||||
|
||||
// Purely Testing Examples;
|
||||
wide_ret;
|
||||
comptime_min_reg_leak;
|
||||
//different_types;
|
||||
//struct_return_from_module_function;
|
||||
|
|
51
lang/tests/son_tests_struct_patterns.txt
Normal file
51
lang/tests/son_tests_struct_patterns.txt
Normal file
|
@ -0,0 +1,51 @@
|
|||
fib:
|
||||
ADDI64 r254, r254, -32d
|
||||
ST r31, r254, 0a, 32h
|
||||
CP r32, r2
|
||||
LI64 r33, 2d
|
||||
JLTU r2, r33, :0
|
||||
CP r34, r32
|
||||
ADDI64 r2, r34, -1d
|
||||
JAL r31, r0, :fib
|
||||
CP r2, r32
|
||||
CP r34, r1
|
||||
SUB64 r2, r2, r33
|
||||
JAL r31, r0, :fib
|
||||
ADD64 r1, r1, r34
|
||||
JMP :1
|
||||
0: CP r1, r32
|
||||
1: LD r31, r254, 0a, 32h
|
||||
ADDI64 r254, r254, 32d
|
||||
JALA r0, r31, 0a
|
||||
fib_iter:
|
||||
LI64 r4, 1d
|
||||
LI64 r5, 0d
|
||||
CP r1, r5
|
||||
CP r10, r4
|
||||
2: JNE r2, r5, :0
|
||||
JMP :1
|
||||
0: ADD64 r3, r10, r1
|
||||
SUB64 r2, r2, r4
|
||||
CP r1, r10
|
||||
CP r10, r3
|
||||
JMP :2
|
||||
1: JALA r0, r31, 0a
|
||||
main:
|
||||
ADDI64 r254, r254, -34d
|
||||
ST r31, r254, 2a, 32h
|
||||
LI64 r32, 10d
|
||||
ADDI64 r33, r254, 0d
|
||||
ST r32, r254, 0a, 1h
|
||||
ST r32, r254, 1a, 1h
|
||||
LD r2, r254, 0a, 1h
|
||||
JAL r31, r0, :fib
|
||||
CP r34, r1
|
||||
LD r2, r254, 1a, 1h
|
||||
JAL r31, r0, :fib_iter
|
||||
SUB64 r1, r34, r1
|
||||
LD r31, r254, 2a, 32h
|
||||
ADDI64 r254, r254, 34d
|
||||
JALA r0, r31, 0a
|
||||
code size: 354
|
||||
ret: 0
|
||||
status: Ok(())
|
52
lang/tests/son_tests_wide_ret.txt
Normal file
52
lang/tests/son_tests_wide_ret.txt
Normal file
|
@ -0,0 +1,52 @@
|
|||
main:
|
||||
ADDI64 r254, r254, -56d
|
||||
ST r31, r254, 16a, 40h
|
||||
LI64 r4, 0d
|
||||
ADDI64 r32, r254, 0d
|
||||
CP r3, r4
|
||||
JAL r31, r0, :maina
|
||||
ST r1, r254, 0a, 16h
|
||||
LD r33, r254, 12a, 1h
|
||||
LD r34, r254, 3a, 1h
|
||||
SUB8 r35, r34, r33
|
||||
ANDI r1, r35, 255d
|
||||
LD r31, r254, 16a, 40h
|
||||
ADDI64 r254, r254, 56d
|
||||
JALA r0, r31, 0a
|
||||
maina:
|
||||
ADDI64 r254, r254, -88d
|
||||
ST r31, r254, 24a, 64h
|
||||
JAL r31, r0, :small_struct
|
||||
LI64 r32, 1d
|
||||
LI64 r33, 3d
|
||||
LI64 r34, 0d
|
||||
ADDI64 r35, r254, 0d
|
||||
ADDI64 r36, r254, 16d
|
||||
ST r34, r254, 16a, 1h
|
||||
ST r34, r254, 17a, 1h
|
||||
ST r34, r254, 18a, 1h
|
||||
ST r33, r254, 19a, 1h
|
||||
ST r32, r254, 20a, 1h
|
||||
ST r34, r254, 21a, 1h
|
||||
ST r34, r254, 22a, 1h
|
||||
ST r34, r254, 23a, 1h
|
||||
LD r37, r254, 16a, 8h
|
||||
ST r37, r254, 0a, 8h
|
||||
LD r38, r254, 16a, 8h
|
||||
ST r38, r254, 8a, 8h
|
||||
LD r1, r35, 0a, 16h
|
||||
LD r31, r254, 24a, 64h
|
||||
ADDI64 r254, r254, 88d
|
||||
JALA r0, r31, 0a
|
||||
small_struct:
|
||||
ADDI64 r254, r254, -4d
|
||||
LI64 r2, 0d
|
||||
ADDI64 r3, r254, 0d
|
||||
ST r2, r254, 0a, 2h
|
||||
ST r2, r254, 2a, 2h
|
||||
LD r1, r254, 0a, 4h
|
||||
ADDI64 r254, r254, 4d
|
||||
JALA r0, r31, 0a
|
||||
code size: 532
|
||||
ret: 2
|
||||
status: Ok(())
|
Loading…
Reference in a new issue