From 1da900461c94257ac7d0d8b85ac0f64ff0339e5d Mon Sep 17 00:00:00 2001 From: Jakub Doka Date: Sun, 20 Oct 2024 18:49:41 +0200 Subject: [PATCH] fixing struct return and copy miscompilation --- lang/README.md | 2 +- lang/src/codegen.rs | 4 - lang/src/lib.rs | 4 + lang/src/son.rs | 148 ++++++++++++------ .../codegen_tests_sort_something_viredly.txt | 41 ++++- .../codegen_tests_writing_into_string.txt | 11 +- lang/tests/son_tests_idk.txt | 19 +++ .../son_tests_sort_something_viredly.txt | 4 +- 8 files changed, 165 insertions(+), 68 deletions(-) create mode 100644 lang/tests/son_tests_idk.txt diff --git a/lang/README.md b/lang/README.md index 771bf54..e2e43e2 100644 --- a/lang/README.md +++ b/lang/README.md @@ -634,7 +634,7 @@ Foo := struct {x: int, y: u32, z: u32} #### sort_something_viredly ```hb main := fn(): int { - return sqrt(1) + return sqrt(100) } sqrt := fn(x: int): int { diff --git a/lang/src/codegen.rs b/lang/src/codegen.rs index 48d18eb..432b8a7 100644 --- a/lang/src/codegen.rs +++ b/lang/src/codegen.rs @@ -1159,10 +1159,6 @@ impl Codegen { E::String { pos, literal } => { let literal = &literal[1..literal.len() - 1]; - if !literal.ends_with("\\0") { - self.report(pos, "string literal must end with null byte (for now)"); - } - let report = |bytes: &core::str::Bytes, message: &str| { self.report(pos + (literal.len() - bytes.len()) as u32 - 1, message) }; diff --git a/lang/src/lib.rs b/lang/src/lib.rs index 5234b1f..4d9d98b 100644 --- a/lang/src/lib.rs +++ b/lang/src/lib.rs @@ -1762,6 +1762,10 @@ fn endoce_string( str.push(b); } + if str.last() != Some(&0) { + report(&bytes, "string literal must end with null byte (for now)"); + } + Some(()) } diff --git a/lang/src/son.rs b/lang/src/son.rs index fd07095..b1dae55 100644 --- a/lang/src/son.rs +++ b/lang/src/son.rs @@ -140,7 +140,7 @@ impl Nodes { Node { ralloc_backref: u16::MAX, inputs: inps.into(), kind, ty, ..Default::default() }; let mut lookup_meta = None; - if !node.is_gvnd() { + if !node.is_not_gvnd() { let (raw_entry, hash) = self.lookup.entry(node.key(), &self.values); let entry = match raw_entry { @@ -170,7 +170,7 @@ impl Nodes { } fn remove_node_lookup(&mut self, target: Nid) { - if !self[target].is_gvnd() { + if !self[target].is_not_gvnd() { self.lookup.remove(&target, &self.values).unwrap(); } } @@ -482,6 +482,7 @@ impl Nodes { Kind::Load => write!(out, "load: "), Kind::Stre => write!(out, "stre: "), Kind::Mem => write!(out, " mem: "), + Kind::Idk => write!(out, " idk: "), }?; if self[node].kind != Kind::Loop && self[node].kind != Kind::Region { @@ -774,9 +775,7 @@ impl Nodes { } fn lock_scope(&mut self, scope: &Scope) { - if let Some(str) = scope.store.to_store() { - self.lock(str); - } + self.lock(scope.store); for &load in &scope.loads { self.lock(load); } @@ -786,9 +785,7 @@ impl Nodes { } fn unlock_remove_scope(&mut self, scope: &Scope) { - if let Some(str) = scope.store.to_store() { - self.unlock_remove(str); - } + self.unlock_remove(scope.store); for &load in &scope.loads { self.unlock_remove(load); } @@ -856,6 +853,8 @@ pub enum Kind { func: ty::Func, }, // [ctrl] + Idk, + // [ctrl] Stck, // [ctrl, memory] Load, @@ -930,8 +929,8 @@ impl Node { self.kind == Kind::Phi && self.inputs[2] == 0 } - fn is_gvnd(&self) -> bool { - self.is_lazy_phi() || matches!(self.kind, Kind::Arg) + fn is_not_gvnd(&self) -> bool { + self.is_lazy_phi() || matches!(self.kind, Kind::Arg | Kind::Stck) } } @@ -1019,7 +1018,6 @@ impl ItemCtx { } fn finalize(&mut self) { - self.nodes.unlock(ENTRY); self.nodes.unlock(NEVER); self.nodes.unlock_remove_scope(&core::mem::take(&mut self.scope)); self.nodes.unlock(MEM); @@ -1109,6 +1107,14 @@ impl ItemCtx { } } Kind::Return => { + match tys.size_of(sig.ret) { + 0..=8 => {} + 9..=16 => todo!(), + size @ 17.. => { + self.emit(instrs::bmc(atr(allocs[0]), 1, size.try_into().unwrap())); + } + } + if i != func.blocks.len() - 1 { let rel = Reloc::new(self.code.len(), 1, 4); self.ret_relocs.push(rel); @@ -1163,6 +1169,7 @@ impl ItemCtx { let offset = func.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; @@ -1186,21 +1193,24 @@ impl ItemCtx { Kind::Stre => { 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 }) && let Kind::CInt { value } = func.nodes[func.nodes[region].inputs[2]].kind + && size <= 8 { region = func.nodes[region].inputs[1]; offset = value as Offset; } - let size = u16::try_from(tys.size_of(node.ty)).expect("TODO"); let nd = &func.nodes[region]; let (base, offset, src) = match nd.kind { - Kind::Stck => (reg::STACK_PTR, nd.offset + offset, allocs[0]), + Kind::Stck if size <= 8 => { + (reg::STACK_PTR, nd.offset + offset, allocs[0]) + } _ => (atr(allocs[0]), offset, allocs[1]), }; if size > 8 { - self.emit(instrs::bmc(base, atr(src), size)); + self.emit(instrs::bmc(atr(src), base, size)); } else { self.emit(instrs::st(atr(src), base, offset as _, size)); } @@ -1539,8 +1549,8 @@ impl<'a> Codegen<'a> { let mut vc = Vc::from([VOID, value, region]); self.ci.nodes.load_loop_store(&mut self.ci.scope.store, &mut self.ci.loops); + self.ci.nodes.unlock(self.ci.scope.store); if let Some(str) = self.ci.scope.store.to_store() { - self.ci.nodes.unlock(str); vc.push(str); } for load in self.ci.scope.loads.drain(..) { @@ -1592,6 +1602,23 @@ impl<'a> Codegen<'a> { fn raw_expr_ctx(&mut self, expr: &Expr, ctx: Ctx) -> Option { // ordered by complexity of the expression match *expr { + Expr::Idk { pos } => { + let Some(ty) = ctx.ty else { + self.report( + pos, + "resulting value cannot be inferred from context, \ + consider using `@as(, idk)` to hint the type", + ); + return Value::NEVER; + }; + + if matches!(ty.expand(), ty::Kind::Struct(_) | ty::Kind::Slice(_)) { + let stck = self.ci.nodes.new_node(ty, Kind::Stck, [VOID, MEM]); + Some(Value::ptr(stck).ty(ty)) + } else { + Some(self.ci.nodes.new_node_lit(ty, Kind::Idk, [VOID])) + } + } Expr::Number { value, .. } => Some(self.ci.nodes.new_node_lit( ctx.ty.filter(|ty| ty.is_integer() || ty.is_pointer()).unwrap_or(ty::Id::INT), Kind::CInt { value }, @@ -1620,10 +1647,6 @@ impl<'a> Codegen<'a> { Expr::String { pos, literal } => { let literal = &literal[1..literal.len() - 1]; - if !literal.ends_with("\\0") { - self.report(pos, "string literal must end with null byte (for now)"); - } - let report = |bytes: &core::str::Bytes, message: &str| { self.report(pos + (literal.len() - bytes.len()) as u32 - 1, message) }; @@ -1696,7 +1719,7 @@ impl<'a> Codegen<'a> { return Value::NEVER; }; - Some(Value::ptr(self.offset(vtarget.id, ty, offset)).ty(ty)) + Some(Value::ptr(self.offset(vtarget.id, offset)).ty(ty)) } Expr::UnOp { op: TokenKind::Band, val, .. } => { let ctx = Ctx { ty: ctx.ty.and_then(|ty| self.tys.base_of(ty)) }; @@ -1751,9 +1774,9 @@ impl<'a> Codegen<'a> { } Expr::BinOp { left, op: TokenKind::Assign, right } => { let dest = self.raw_expr(left)?; - let value = self.expr(right)?; + let value = self.expr_ctx(right, Ctx::default().with_ty(dest.ty))?; - self.assert_ty(left.pos(), value.ty, dest.ty, "assignment dest"); + self.assert_ty(left.pos(), value.ty, dest.ty, "assignment source"); if dest.var { self.ci.nodes.lock(value.id); @@ -1805,7 +1828,8 @@ impl<'a> Codegen<'a> { let offset = self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Mul }, inps); let inps = [VOID, bs.id, offset]; - let ptr = self.ci.nodes.new_node(elem, Kind::BinOp { op: TokenKind::Add }, inps); + let ptr = + self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Add }, inps); Some(Value::ptr(ptr).ty(elem)) } Expr::Directive { name: "sizeof", args: [ty], .. } => { @@ -1857,7 +1881,7 @@ impl<'a> Codegen<'a> { } Expr::Directive { name: "as", args: [ty, expr], .. } => { let ctx = Ctx::default().with_ty(self.ty(ty)); - self.expr_ctx(expr, ctx) + self.raw_expr_ctx(expr, ctx) } Expr::Call { func, args, .. } => { self.ci.call_count += 1; @@ -1918,11 +1942,22 @@ impl<'a> Codegen<'a> { false }); + + let alt_value = match self.tys.size_of(sig.ret) { + 0..=8 => None, + 9..=16 => todo!(), + 17.. => { + 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.store_mem(VOID, VOID); - Some(Value::new(self.ci.ctrl).ty(sig.ret)) + alt_value.or(Some(Value::new(self.ci.ctrl).ty(sig.ret))) } Expr::Tupl { pos, ty, fields, .. } => { let Some(sty) = ty.map(|ty| self.ty(ty)).or(ctx.ty) else { @@ -1948,7 +1983,7 @@ impl<'a> Codegen<'a> { }; let value = self.expr_ctx(field, Ctx::default().with_ty(ty))?; - let mem = self.offset(mem, ty, offset); + let mem = self.offset(mem, offset); self.store_mem(mem, value.id); } @@ -1995,7 +2030,7 @@ impl<'a> Codegen<'a> { { let value = self.expr_ctx(field, Ctx::default().with_ty(elem))?; _ = self.assert_ty(field.pos(), value.ty, elem, "array value"); - let mem = self.offset(mem, elem, offset); + let mem = self.offset(mem, offset); self.store_mem(mem, value.id); } @@ -2063,7 +2098,7 @@ impl<'a> Codegen<'a> { } let value = self.expr_ctx(&field.value, Ctx::default().with_ty(ty))?; - let mem = self.offset(mem, ty, offset); + let mem = self.offset(mem, offset); self.store_mem(mem, value.id); } @@ -2238,9 +2273,7 @@ impl<'a> Codegen<'a> { self.ci.nodes.load_loop_store(&mut self.ci.scope.store, &mut self.ci.loops); let orig_store = self.ci.scope.store; - if let Some(str) = orig_store.to_store() { - self.ci.nodes.lock(str); - } + self.ci.nodes.lock(orig_store); let else_scope = self.ci.scope.clone(); self.ci.nodes.lock_scope(&else_scope); @@ -2255,9 +2288,7 @@ impl<'a> Codegen<'a> { self.ci.ctrl }; - if let Some(str) = orig_store.to_store() { - self.ci.nodes.unlock_remove(str); - } + self.ci.nodes.unlock_remove(orig_store); if lcntrl == Nid::MAX && rcntrl == Nid::MAX { self.ci.nodes.unlock_remove_scope(&then_scope); @@ -2298,14 +2329,14 @@ impl<'a> Codegen<'a> { Some(n) } - fn offset(&mut self, val: Nid, ty: ty::Id, off: Offset) -> Nid { + fn offset(&mut self, val: Nid, off: Offset) -> Nid { if off == 0 { return val; } let off = self.ci.nodes.new_node_nop(ty::Id::INT, Kind::CInt { value: off as i64 }, [VOID]); let inps = [VOID, val, off]; - self.ci.nodes.new_node(ty, Kind::BinOp { op: TokenKind::Add }, inps) + self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Add }, inps) } fn strip_var(&mut self, n: &mut Value) { @@ -2688,14 +2719,20 @@ impl<'a> Function<'a> { } } Kind::Return => { - let ops = if node.inputs[1] != VOID { - vec![regalloc2::Operand::reg_fixed_use( - self.rg(node.inputs[1]), - regalloc2::PReg::new(1, regalloc2::RegClass::Int), - )] - } else { - vec![] + let ops = match self.tys.size_of(self.sig.ret) { + 0 => vec![], + 1..=8 => { + vec![regalloc2::Operand::reg_fixed_use( + self.rg(node.inputs[1]), + regalloc2::PReg::new(1, regalloc2::RegClass::Int), + )] + } + 9..=16 => todo!(), + 17.. => { + vec![self.urg(node.inputs[1])] + } }; + self.add_instr(nid, ops); self.emit_node(node.outputs[0], nid); } @@ -2755,10 +2792,10 @@ impl<'a> Function<'a> { } Kind::BinOp { op: TokenKind::Add } if self.nodes.is_const(node.inputs[2]) - && node - .outputs - .iter() - .all(|&n| matches!(self.nodes[n].kind, Kind::Stre | Kind::Load)) => + && node.outputs.iter().all(|&n| { + matches!(self.nodes[n].kind, Kind::Stre | Kind::Load) + && self.tys.size_of(self.nodes[n].ty) <= 8 + }) => { self.nodes.lock(nid) } @@ -2825,6 +2862,17 @@ impl<'a> Function<'a> { } } + match self.tys.size_of(fuc.ret) { + 0..=8 => {} + 9..=16 => todo!(), + 17.. => { + ops.push(regalloc2::Operand::reg_fixed_use( + self.rg(*node.inputs.last().unwrap()), + regalloc2::PReg::new(1, regalloc2::RegClass::Int), + )); + } + } + self.add_instr(nid, ops); for o in node.outputs.into_iter().rev() { @@ -2851,6 +2899,10 @@ impl<'a> Function<'a> { let ops = vec![self.drg(nid)]; self.add_instr(nid, ops); } + Kind::Idk => { + let ops = vec![self.drg(nid)]; + self.add_instr(nid, ops); + } Kind::Phi | Kind::Arg | Kind::Mem => {} Kind::Load { .. } => { let mut region = node.inputs[1]; @@ -3283,7 +3335,7 @@ mod tests { //struct_patterns; arrays; //inline; - //idk; + idk; //wide_ret; // Incomplete Examples; diff --git a/lang/tests/codegen_tests_sort_something_viredly.txt b/lang/tests/codegen_tests_sort_something_viredly.txt index 9a14185..f89ca54 100644 --- a/lang/tests/codegen_tests_sort_something_viredly.txt +++ b/lang/tests/codegen_tests_sort_something_viredly.txt @@ -1,11 +1,36 @@ main: - ADDI64 r254, r254, -16d - ST r31, r254, 0a, 16h - LI64 r32, 1610612737d - LI64 r1, 0d - LD r31, r254, 0a, 16h - ADDI64 r254, r254, 16d + ADDI64 r254, r254, -8d + ST r31, r254, 0a, 8h + LI64 r2, 1d + JAL r31, r0, :sqrt + LD r31, r254, 0a, 8h + ADDI64 r254, r254, 8d JALA r0, r31, 0a -code size: 87 -ret: 0 +sqrt: + ADDI64 r254, r254, -56d + ST r31, r254, 0a, 56h + CP r32, r2 + LI64 r33, 0d + LI64 r34, 0d + LI64 r35, 32768d + LI64 r36, 15d + 3: LI64 r37, 0d + JNE r35, r37, :0 + JMP :1 + 0: ADDI64 r36, r36, -1d + CP r37, r34 + SLUI64 r37, r37, 1b + ADD64 r33, r35, r37 + SLU64 r33, r33, r36 + JLTS r32, r33, :2 + ADD64 r34, r34, r35 + SUB64 r32, r32, r33 + 2: SRUI64 r35, r35, 1b + JMP :3 + 1: CP r1, r34 + LD r31, r254, 0a, 56h + ADDI64 r254, r254, 56d + JALA r0, r31, 0a +code size: 257 +ret: 1 status: Ok(()) diff --git a/lang/tests/codegen_tests_writing_into_string.txt b/lang/tests/codegen_tests_writing_into_string.txt index 44d026c..f0c3b4e 100644 --- a/lang/tests/codegen_tests_writing_into_string.txt +++ b/lang/tests/codegen_tests_writing_into_string.txt @@ -14,12 +14,13 @@ main: ADDI64 r254, r254, 8d JALA r0, r31, 0a outl: - ADDI64 r254, r254, -16d - ST r31, r254, 0a, 16h + ADDI64 r254, r254, -24d + ST r31, r254, 0a, 24h LRA r32, r0, :"whahaha\0" - LD r31, r254, 0a, 16h - ADDI64 r254, r254, 16d + LI64 r33, 0d + LD r31, r254, 0a, 24h + ADDI64 r254, r254, 24d JALA r0, r31, 0a -code size: 229 +code size: 239 ret: 0 status: Ok(()) diff --git a/lang/tests/son_tests_idk.txt b/lang/tests/son_tests_idk.txt new file mode 100644 index 0000000..333fa7b --- /dev/null +++ b/lang/tests/son_tests_idk.txt @@ -0,0 +1,19 @@ +main: + ADDI64 r254, r254, -128d + LI64 r6, 69d + LI64 r5, 128d + LI64 r7, 0d + ADDI64 r4, r254, 0d + 2: JLTU r7, r5, :0 + LD r1, r254, 42a, 1h + JMP :1 + 0: ADDI64 r3, r7, 1d + ADD64 r2, r7, r4 + ST r6, r2, 0a, 1h + CP r7, r3 + JMP :2 + 1: ADDI64 r254, r254, 128d + JALA r0, r31, 0a +code size: 141 +ret: 69 +status: Ok(()) diff --git a/lang/tests/son_tests_sort_something_viredly.txt b/lang/tests/son_tests_sort_something_viredly.txt index 0212f2f..536fb47 100644 --- a/lang/tests/son_tests_sort_something_viredly.txt +++ b/lang/tests/son_tests_sort_something_viredly.txt @@ -1,7 +1,7 @@ main: ADDI64 r254, r254, -8d ST r31, r254, 0a, 8h - LI64 r2, 1d + LI64 r2, 100d JAL r31, r0, :sqrt LD r31, r254, 0a, 8h ADDI64 r254, r254, 8d @@ -25,5 +25,5 @@ sqrt: JMP :3 1: JALA r0, r31, 0a code size: 188 -ret: 0 +ret: 14 status: Ok(())