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
|
### Incomplete Examples
|
||||||
|
|
||||||
#### comptime_pointers
|
#### comptime_pointers
|
||||||
|
@ -548,6 +525,34 @@ main := fn(): int {
|
||||||
|
|
||||||
### Purely Testing Examples
|
### 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
|
#### comptime_min_reg_leak
|
||||||
```hb
|
```hb
|
||||||
a := @use("math.hb").min(100, 50)
|
a := @use("math.hb").min(100, 50)
|
||||||
|
|
245
lang/src/son.rs
245
lang/src/son.rs
|
@ -7,7 +7,7 @@ use {
|
||||||
parser::{
|
parser::{
|
||||||
self,
|
self,
|
||||||
idfl::{self},
|
idfl::{self},
|
||||||
Expr, ExprRef, FileId, Pos,
|
CtorField, Expr, ExprRef, FileId, Pos,
|
||||||
},
|
},
|
||||||
reg, task,
|
reg, task,
|
||||||
ty::{self, ArrayLen, Tuple},
|
ty::{self, ArrayLen, Tuple},
|
||||||
|
@ -483,6 +483,7 @@ impl Nodes {
|
||||||
Kind::Stre => write!(out, "stre: "),
|
Kind::Stre => write!(out, "stre: "),
|
||||||
Kind::Mem => write!(out, " mem: "),
|
Kind::Mem => write!(out, " mem: "),
|
||||||
Kind::Idk => write!(out, " idk: "),
|
Kind::Idk => write!(out, " idk: "),
|
||||||
|
Kind::Extend => write!(out, " ext: "),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
if self[node].kind != Kind::Loop && self[node].kind != Kind::Region {
|
if self[node].kind != Kind::Loop && self[node].kind != Kind::Region {
|
||||||
|
@ -837,6 +838,8 @@ pub enum Kind {
|
||||||
Phi,
|
Phi,
|
||||||
Arg,
|
Arg,
|
||||||
// [ctrl, oper]
|
// [ctrl, oper]
|
||||||
|
Extend,
|
||||||
|
// [ctrl, oper]
|
||||||
UnOp {
|
UnOp {
|
||||||
op: lexer::TokenKind,
|
op: lexer::TokenKind,
|
||||||
},
|
},
|
||||||
|
@ -1031,9 +1034,9 @@ impl ItemCtx {
|
||||||
let mut nodes = core::mem::take(&mut self.nodes);
|
let mut nodes = core::mem::take(&mut self.nodes);
|
||||||
nodes.visited.clear(nodes.values.len());
|
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
|
let mut ralloc = Regalloc::default(); // TODO: reuse
|
||||||
log::info!("{:?}", func);
|
log::info!("{:?}", fuc);
|
||||||
if self.call_count != 0 {
|
if self.call_count != 0 {
|
||||||
core::mem::swap(
|
core::mem::swap(
|
||||||
&mut ralloc.env.preferred_regs_by_class,
|
&mut ralloc.env.preferred_regs_by_class,
|
||||||
|
@ -1046,7 +1049,7 @@ impl ItemCtx {
|
||||||
validate_ssa: false,
|
validate_ssa: false,
|
||||||
algorithm: regalloc2::Algorithm::Ion,
|
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}"));
|
.unwrap_or_else(|err| panic!("{err}"));
|
||||||
|
|
||||||
if self.call_count != 0 {
|
if self.call_count != 0 {
|
||||||
|
@ -1067,10 +1070,10 @@ impl ItemCtx {
|
||||||
*saved_regs.entry(hvenc).or_insert(would_insert)
|
*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 _);
|
let blk = regalloc2::Block(i as _);
|
||||||
func.nodes[block.nid].offset = self.code.len() as _;
|
fuc.nodes[block.nid].offset = self.code.len() as _;
|
||||||
for instr_or_edit in ralloc.ctx.output.block_insts_and_edits(&func, blk) {
|
for instr_or_edit in ralloc.ctx.output.block_insts_and_edits(&fuc, blk) {
|
||||||
let inst = match instr_or_edit {
|
let inst = match instr_or_edit {
|
||||||
regalloc2::InstOrEdit::Inst(inst) => inst,
|
regalloc2::InstOrEdit::Inst(inst) => inst,
|
||||||
regalloc2::InstOrEdit::Edit(®alloc2::Edit::Move { from, to }) => {
|
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 {
|
if nid == NEVER {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let allocs = ralloc.ctx.output.inst_allocs(inst);
|
let allocs = ralloc.ctx.output.inst_allocs(inst);
|
||||||
let node = &func.nodes[nid];
|
let node = &fuc.nodes[nid];
|
||||||
match node.kind {
|
match node.kind {
|
||||||
Kind::If => {
|
Kind::If => {
|
||||||
let &[_, cond] = node.inputs.as_slice() else { unreachable!() };
|
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 Some((op, swapped)) = op.cond_op(node.ty.is_signed())
|
||||||
{
|
{
|
||||||
let rel = Reloc::new(self.code.len(), 3, 2);
|
let rel = Reloc::new(self.code.len(), 3, 2);
|
||||||
|
@ -1109,13 +1112,19 @@ impl ItemCtx {
|
||||||
Kind::Return => {
|
Kind::Return => {
|
||||||
match tys.size_of(sig.ret) {
|
match tys.size_of(sig.ret) {
|
||||||
0..=8 => {}
|
0..=8 => {}
|
||||||
9..=16 => todo!(),
|
size @ 9..=16 => {
|
||||||
|
self.emit(instrs::ld(reg::RET, atr(allocs[0]), 0, size as _));
|
||||||
|
}
|
||||||
size @ 17.. => {
|
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);
|
let rel = Reloc::new(self.code.len(), 1, 4);
|
||||||
self.ret_relocs.push(rel);
|
self.ret_relocs.push(rel);
|
||||||
self.emit(instrs::jmp(0));
|
self.emit(instrs::jmp(0));
|
||||||
|
@ -1124,6 +1133,22 @@ impl ItemCtx {
|
||||||
Kind::CInt { value } => {
|
Kind::CInt { value } => {
|
||||||
self.emit(instrs::li64(atr(allocs[0]), value as _));
|
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 } => {
|
Kind::UnOp { op } => {
|
||||||
let op = op.unop().expect("TODO: unary operator not supported");
|
let op = op.unop().expect("TODO: unary operator not supported");
|
||||||
let &[dst, oper] = allocs else { unreachable!() };
|
let &[dst, oper] = allocs else { unreachable!() };
|
||||||
|
@ -1132,15 +1157,15 @@ impl ItemCtx {
|
||||||
Kind::BinOp { op } => {
|
Kind::BinOp { op } => {
|
||||||
let &[.., rhs] = node.inputs.as_slice() else { unreachable!() };
|
let &[.., rhs] = node.inputs.as_slice() else { unreachable!() };
|
||||||
|
|
||||||
if let Kind::CInt { value } = func.nodes[rhs].kind
|
if let Kind::CInt { value } = fuc.nodes[rhs].kind
|
||||||
&& func.nodes[rhs].lock_rc != 0
|
&& fuc.nodes[rhs].lock_rc != 0
|
||||||
&& let Some(op) =
|
&& 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!() };
|
let &[dst, lhs] = allocs else { unreachable!() };
|
||||||
self.emit(op(atr(dst), atr(lhs), value as _));
|
self.emit(op(atr(dst), atr(lhs), value as _));
|
||||||
} else if let Some(op) =
|
} 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!() };
|
let &[dst, lhs, rhs] = allocs else { unreachable!() };
|
||||||
self.emit(op(atr(dst), atr(lhs), atr(rhs)));
|
self.emit(op(atr(dst), atr(lhs), atr(rhs)));
|
||||||
|
@ -1155,6 +1180,10 @@ impl ItemCtx {
|
||||||
reloc: Reloc::new(self.code.len(), 3, 4),
|
reloc: Reloc::new(self.code.len(), 3, 4),
|
||||||
});
|
});
|
||||||
self.emit(instrs::jal(reg::RET_ADDR, reg::ZERO, 0));
|
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 } => {
|
Kind::Global { global } => {
|
||||||
let reloc = Reloc::new(self.code.len(), 3, 4);
|
let reloc = Reloc::new(self.code.len(), 3, 4);
|
||||||
|
@ -1166,24 +1195,24 @@ impl ItemCtx {
|
||||||
}
|
}
|
||||||
Kind::Stck => {
|
Kind::Stck => {
|
||||||
let base = reg::STACK_PTR;
|
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 _));
|
self.emit(instrs::addi64(atr(allocs[0]), base, offset as _));
|
||||||
}
|
}
|
||||||
Kind::Idk => {}
|
Kind::Idk => {}
|
||||||
Kind::Load => {
|
Kind::Load => {
|
||||||
let mut region = node.inputs[1];
|
let mut region = node.inputs[1];
|
||||||
let mut offset = 0;
|
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 } =
|
&& 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;
|
offset = value as Offset;
|
||||||
}
|
}
|
||||||
let size = tys.size_of(node.ty);
|
let size = tys.size_of(node.ty);
|
||||||
if size <= 8 {
|
if size <= 8 {
|
||||||
let (base, offset) = match func.nodes[region].kind {
|
let (base, offset) = match fuc.nodes[region].kind {
|
||||||
Kind::Stck => (reg::STACK_PTR, func.nodes[region].offset + offset),
|
Kind::Stck => (reg::STACK_PTR, fuc.nodes[region].offset + offset),
|
||||||
_ => (atr(allocs[1]), offset),
|
_ => (atr(allocs[1]), offset),
|
||||||
};
|
};
|
||||||
self.emit(instrs::ld(atr(allocs[0]), base, offset as _, size as _));
|
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 region = node.inputs[2];
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
let size = u16::try_from(tys.size_of(node.ty)).expect("TODO");
|
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 } =
|
&& let Kind::CInt { value } =
|
||||||
func.nodes[func.nodes[region].inputs[2]].kind
|
fuc.nodes[fuc.nodes[region].inputs[2]].kind
|
||||||
&& size <= 8
|
&& size <= 8
|
||||||
{
|
{
|
||||||
region = func.nodes[region].inputs[1];
|
region = fuc.nodes[region].inputs[1];
|
||||||
offset = value as Offset;
|
offset = value as Offset;
|
||||||
}
|
}
|
||||||
let nd = &func.nodes[region];
|
let nd = &fuc.nodes[region];
|
||||||
let (base, offset, src) = match nd.kind {
|
let (base, offset, src) = match nd.kind {
|
||||||
Kind::Stck if size <= 8 => {
|
Kind::Stck if size <= 8 => {
|
||||||
(reg::STACK_PTR, nd.offset + offset, allocs[0])
|
(reg::STACK_PTR, nd.offset + offset, allocs[0])
|
||||||
|
@ -1215,7 +1244,14 @@ impl ItemCtx {
|
||||||
self.emit(instrs::st(atr(src), base, offset as _, size));
|
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, .. } => {
|
Expr::Ident { id, pos, .. } => {
|
||||||
let decl = self.find_type(pos, self.ci.file, Ok(id), self.files);
|
let decl = self.find_type(pos, self.ci.file, Ok(id), self.files);
|
||||||
match decl.expand() {
|
match decl.expand() {
|
||||||
|
ty::Kind::Builtin(ty::NEVER) => Value::NEVER,
|
||||||
ty::Kind::Global(global) => {
|
ty::Kind::Global(global) => {
|
||||||
let gl = &self.tys.ins.globals[global as usize];
|
let gl = &self.tys.ins.globals[global as usize];
|
||||||
let value = self.ci.nodes.new_node(gl.ty, Kind::Global { global }, [VOID]);
|
let value = self.ci.nodes.new_node(gl.ty, Kind::Global { global }, [VOID]);
|
||||||
Some(Value::ptr(value).ty(gl.ty))
|
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),
|
Expr::Comment { .. } => Some(Value::VOID),
|
||||||
|
@ -1661,12 +1701,15 @@ impl<'a> Codegen<'a> {
|
||||||
Some(Value::new(global).ty(ty))
|
Some(Value::new(global).ty(ty))
|
||||||
}
|
}
|
||||||
Expr::Return { pos, val } => {
|
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 })?
|
self.expr_ctx(val, Ctx { ty: self.ci.ret })?
|
||||||
} else {
|
} else {
|
||||||
Value { ty: ty::Id::VOID, ..Default::default() }
|
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]);
|
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);
|
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() {
|
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[NEVER].inputs.push(self.ci.ctrl);
|
||||||
self.ci.nodes[self.ci.ctrl].outputs.push(NEVER);
|
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
|
None
|
||||||
}
|
}
|
||||||
Expr::Field { target, name, pos } => {
|
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]))
|
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 } => {
|
Expr::BinOp { left, op: TokenKind::Decl, right } => {
|
||||||
let mut value = self.raw_expr(right)?;
|
let right = self.raw_expr(right)?;
|
||||||
self.strip_var(&mut value);
|
self.assign_pattern(left, right);
|
||||||
self.ci.nodes.lock(value.id);
|
|
||||||
self.ci.scope.vars.push(Variable {
|
|
||||||
id,
|
|
||||||
value: value.id,
|
|
||||||
ptr: value.ptr,
|
|
||||||
ty: value.ty,
|
|
||||||
});
|
|
||||||
Some(Value::VOID)
|
Some(Value::VOID)
|
||||||
}
|
}
|
||||||
Expr::BinOp { left, op: TokenKind::Assign, right } => {
|
Expr::BinOp { left, op: TokenKind::Assign, right } => {
|
||||||
let dest = self.raw_expr(left)?;
|
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 {
|
if dest.var {
|
||||||
self.ci.nodes.lock(value.id);
|
self.ci.nodes.lock(value.id);
|
||||||
|
@ -1791,13 +1824,16 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
Some(Value::VOID)
|
Some(Value::VOID)
|
||||||
}
|
}
|
||||||
Expr::BinOp { left, op, right } if op != TokenKind::Assign => {
|
Expr::BinOp { left, op, right }
|
||||||
let lhs = self.expr_ctx(left, ctx)?;
|
if !matches!(op, TokenKind::Assign | TokenKind::Decl) =>
|
||||||
|
{
|
||||||
|
let mut lhs = self.expr_ctx(left, ctx)?;
|
||||||
self.ci.nodes.lock(lhs.id);
|
self.ci.nodes.lock(lhs.id);
|
||||||
let rhs = self.expr_ctx(right, Ctx::default().with_ty(lhs.ty));
|
let rhs = self.expr_ctx(right, Ctx::default().with_ty(lhs.ty));
|
||||||
self.ci.nodes.unlock(lhs.id);
|
self.ci.nodes.unlock(lhs.id);
|
||||||
let ty = self.binop_ty(left.pos(), rhs?.ty, lhs.ty, op);
|
let mut rhs = rhs?;
|
||||||
let inps = [VOID, lhs.id, rhs?.id];
|
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))
|
Some(self.ci.nodes.new_node_lit(ty::bin_ret(ty, op), Kind::BinOp { op }, inps))
|
||||||
}
|
}
|
||||||
Expr::Index { base, index } => {
|
Expr::Index { base, index } => {
|
||||||
|
@ -1886,7 +1922,7 @@ impl<'a> Codegen<'a> {
|
||||||
Expr::Call { func, args, .. } => {
|
Expr::Call { func, args, .. } => {
|
||||||
self.ci.call_count += 1;
|
self.ci.call_count += 1;
|
||||||
let ty = self.ty(func);
|
let ty = self.ty(func);
|
||||||
let ty::Kind::Func(fnc) = ty.expand() else {
|
let ty::Kind::Func(fu) = ty.expand() else {
|
||||||
self.report(
|
self.report(
|
||||||
func.pos(),
|
func.pos(),
|
||||||
fa!("compiler cant (yet) call '{}'", self.ty_display(ty)),
|
fa!("compiler cant (yet) call '{}'", self.ty_display(ty)),
|
||||||
|
@ -1894,9 +1930,9 @@ impl<'a> Codegen<'a> {
|
||||||
return Value::NEVER;
|
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 sig = fuc.sig.expect("TODO: generic functions");
|
||||||
let ast = &self.files[fuc.file as usize];
|
let ast = &self.files[fuc.file as usize];
|
||||||
let &Expr::Closure { args: cargs, .. } = fuc.expr.get(ast).unwrap() else {
|
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 {
|
if self.tys.size_of(ty) == 0 {
|
||||||
continue;
|
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!(self.ci.nodes[value.id].kind, Kind::Stre);
|
||||||
debug_assert_ne!(value.id, 0);
|
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);
|
inps.push(value.id);
|
||||||
}
|
}
|
||||||
|
@ -1945,15 +1981,14 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
let alt_value = match self.tys.size_of(sig.ret) {
|
let alt_value = match self.tys.size_of(sig.ret) {
|
||||||
0..=8 => None,
|
0..=8 => None,
|
||||||
9..=16 => todo!(),
|
9.. => {
|
||||||
17.. => {
|
|
||||||
let stck = self.ci.nodes.new_node_nop(sig.ret, Kind::Stck, [VOID, MEM]);
|
let stck = self.ci.nodes.new_node_nop(sig.ret, Kind::Stck, [VOID, MEM]);
|
||||||
inps.push(stck);
|
inps.push(stck);
|
||||||
Some(Value::ptr(stck).ty(sig.ret))
|
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);
|
self.store_mem(VOID, VOID);
|
||||||
|
|
||||||
|
@ -2028,8 +2063,8 @@ impl<'a> Codegen<'a> {
|
||||||
for (field, offset) in
|
for (field, offset) in
|
||||||
fields.iter().zip((0u32..).step_by(elem_size as usize))
|
fields.iter().zip((0u32..).step_by(elem_size as usize))
|
||||||
{
|
{
|
||||||
let value = self.expr_ctx(field, Ctx::default().with_ty(elem))?;
|
let mut value = self.expr_ctx(field, Ctx::default().with_ty(elem))?;
|
||||||
_ = self.assert_ty(field.pos(), value.ty, elem, "array value");
|
_ = self.assert_ty(field.pos(), &mut value, elem, "array value");
|
||||||
let mem = self.offset(mem, offset);
|
let mem = self.offset(mem, offset);
|
||||||
self.store_mem(mem, value.id);
|
self.store_mem(mem, value.id);
|
||||||
}
|
}
|
||||||
|
@ -2124,8 +2159,8 @@ impl<'a> Codegen<'a> {
|
||||||
let mut ret = Some(Value::VOID);
|
let mut ret = Some(Value::VOID);
|
||||||
for stmt in stmts {
|
for stmt in stmts {
|
||||||
ret = ret.and(self.expr(stmt));
|
ret = ret.and(self.expr(stmt));
|
||||||
if let Some(id) = ret {
|
if let Some(mut id) = ret {
|
||||||
self.assert_ty(stmt.pos(), id.ty, ty::Id::VOID, "statement");
|
self.assert_ty(stmt.pos(), &mut id, ty::Id::VOID, "statement");
|
||||||
} else {
|
} else {
|
||||||
break;
|
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> {
|
fn expr_ctx(&mut self, expr: &Expr, ctx: Ctx) -> Option<Value> {
|
||||||
let mut n = self.raw_expr_ctx(expr, ctx)?;
|
let mut n = self.raw_expr_ctx(expr, ctx)?;
|
||||||
self.strip_var(&mut n);
|
self.strip_var(&mut n);
|
||||||
|
@ -2492,26 +2558,46 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn binop_ty(&self, pos: Pos, lhs: ty::Id, rhs: ty::Id, op: TokenKind) -> ty::Id {
|
fn binop_ty(&mut self, pos: Pos, lhs: &mut Value, rhs: &mut Value, op: TokenKind) -> ty::Id {
|
||||||
if let Some(res) = lhs.try_upcast(rhs, ty::TyCheck::BinOp) {
|
if let Some(upcasted) = lhs.ty.try_upcast(rhs.ty, ty::TyCheck::BinOp) {
|
||||||
res
|
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 {
|
} else {
|
||||||
let ty = self.ty_display(lhs);
|
let ty = self.ty_display(lhs.ty);
|
||||||
let expected = self.ty_display(rhs);
|
let expected = self.ty_display(rhs.ty);
|
||||||
self.report(pos, fa!("'{ty} {op} {expected}' is not supported"));
|
self.report(pos, fa!("'{ty} {op} {expected}' is not supported"));
|
||||||
ty::Id::NEVER
|
ty::Id::NEVER
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn assert_ty(&self, pos: Pos, ty: ty::Id, expected: ty::Id, hint: impl fmt::Display) -> bool {
|
fn assert_ty(
|
||||||
if ty.try_upcast(expected, ty::TyCheck::BinOp) != Some(expected) {
|
&mut self,
|
||||||
let ty = self.ty_display(ty);
|
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);
|
let expected = self.ty_display(expected);
|
||||||
self.report(pos, fa!("expected {hint} to be of type {expected}, got {ty}"));
|
self.report(pos, fa!("expected {hint} to be of type {expected}, got {ty}"));
|
||||||
return false;
|
false
|
||||||
}
|
}
|
||||||
true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
|
@ -2528,7 +2614,7 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn report_unhandled_ast(&self, ast: &Expr, hint: &str) -> ! {
|
fn report_unhandled_ast(&self, ast: &Expr, hint: impl Display) -> ! {
|
||||||
log::info!("{ast:#?}");
|
log::info!("{ast:#?}");
|
||||||
self.fatal_report(ast.pos(), fa!("compiler does not (yet) know how to handle ({hint})"));
|
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),
|
regalloc2::PReg::new(1, regalloc2::RegClass::Int),
|
||||||
)]
|
)]
|
||||||
}
|
}
|
||||||
9..=16 => todo!(),
|
9..=16 => {
|
||||||
|
vec![self.urg(self.nodes[node.inputs[1]].inputs[1])]
|
||||||
|
}
|
||||||
17.. => {
|
17.. => {
|
||||||
vec![self.urg(node.inputs[1])]
|
vec![self.urg(node.inputs[1])]
|
||||||
}
|
}
|
||||||
|
@ -2751,6 +2839,10 @@ impl<'a> Function<'a> {
|
||||||
let ops = vec![self.drg(nid)];
|
let ops = vec![self.drg(nid)];
|
||||||
self.add_instr(nid, ops);
|
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 => {
|
Kind::Entry => {
|
||||||
self.nodes[nid].ralloc_backref = self.add_block(nid);
|
self.nodes[nid].ralloc_backref = self.add_block(nid);
|
||||||
|
|
||||||
|
@ -2863,8 +2955,7 @@ impl<'a> Function<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.tys.size_of(fuc.ret) {
|
match self.tys.size_of(fuc.ret) {
|
||||||
0..=8 => {}
|
0..=16 => {}
|
||||||
9..=16 => todo!(),
|
|
||||||
17.. => {
|
17.. => {
|
||||||
ops.push(regalloc2::Operand::reg_fixed_use(
|
ops.push(regalloc2::Operand::reg_fixed_use(
|
||||||
self.rg(*node.inputs.last().unwrap()),
|
self.rg(*node.inputs.last().unwrap()),
|
||||||
|
@ -3332,11 +3423,10 @@ mod tests {
|
||||||
global_variables;
|
global_variables;
|
||||||
//directives;
|
//directives;
|
||||||
c_strings;
|
c_strings;
|
||||||
//struct_patterns;
|
struct_patterns;
|
||||||
arrays;
|
arrays;
|
||||||
//inline;
|
//inline;
|
||||||
idk;
|
idk;
|
||||||
//wide_ret;
|
|
||||||
|
|
||||||
// Incomplete Examples;
|
// Incomplete Examples;
|
||||||
//comptime_pointers;
|
//comptime_pointers;
|
||||||
|
@ -3345,6 +3435,7 @@ mod tests {
|
||||||
fb_driver;
|
fb_driver;
|
||||||
|
|
||||||
// Purely Testing Examples;
|
// Purely Testing Examples;
|
||||||
|
wide_ret;
|
||||||
comptime_min_reg_leak;
|
comptime_min_reg_leak;
|
||||||
//different_types;
|
//different_types;
|
||||||
//struct_return_from_module_function;
|
//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