diff --git a/lang/README.md b/lang/README.md index 1fb8821..bf2062b 100644 --- a/lang/README.md +++ b/lang/README.md @@ -593,6 +593,59 @@ main := fn(): uint { ### Purely Testing Examples +#### inlining_issues +```hb +main := fn(): void { + @use("main.hb").put_filled_rect(.(&.(0), 100, 100), .(0, 0), .(0, 0), .(1)) +} + +// in module: memory.hb + +SetMsg := packed struct {a: u8, count: u32, size: u32, src: ^u8, dest: ^u8} +set := fn($Expr: type, src: ^Expr, dest: ^Expr, count: uint): void { + return @eca(8, 2, &SetMsg.(5, @intcast(count), @intcast(@sizeof(Expr)), @bitcast(src), @bitcast(dest)), @sizeof(SetMsg)) +} + +// in module: main.hb + +Color := struct {r: u8} + +Vec2 := fn($Ty: type): type return struct {x: Ty, y: Ty} + +memory := @use("memory.hb") + +Surface := struct { + buf: ^Color, + width: uint, + height: uint, +} + +indexptr := fn(surface: Surface, x: uint, y: uint): ^Color { + return surface.buf + y * surface.width + x +} + +put_filled_rect := fn(surface: Surface, pos: Vec2(uint), tr: Vec2(uint), color: Color): void { + top_start_idx := @inline(indexptr, surface, pos.x, pos.y) + bottom_start_idx := @inline(indexptr, surface, pos.x, pos.y + tr.y - 1) + rows_to_fill := tr.y + + loop if rows_to_fill <= 1 break else { + @inline(memory.set, Color, &color, top_start_idx, @bitcast(tr.x)) + @inline(memory.set, Color, &color, bottom_start_idx, @bitcast(tr.x)) + + top_start_idx += surface.width + bottom_start_idx -= surface.width + rows_to_fill -= 2 + } + + if rows_to_fill == 1 { + @inline(memory.set, Color, &color, top_start_idx, @bitcast(tr.x)) + } + + return +} +``` + #### only_break_loop ```hb memory := @use("memory.hb") diff --git a/lang/src/son.rs b/lang/src/son.rs index c48dc5f..ea05930 100644 --- a/lang/src/son.rs +++ b/lang/src/son.rs @@ -39,7 +39,7 @@ const GLOBAL_ACLASS: usize = 1; pub mod hbvm; type Nid = u16; -type AClassId = u16; +type AClassId = i16; type Lookup = crate::ctx_map::CtxMap; @@ -410,6 +410,7 @@ impl Nodes { } fn bind(&mut self, from: Nid, to: Nid) { + debug_assert_ne!(to, 0); self[from].outputs.push(to); self[to].inputs.push(from); } @@ -512,17 +513,16 @@ impl Nodes { if node.ty != ty::Id::VOID { writeln!( out, - " node{i}[label=\"{i} {} {} {} {}\" color={color}]", + " node{i}[label=\"{i} {} {} {}\" color={color}]", node.kind, ty::Display::new(tys, files, node.ty), node.aclass, - node.mem, )?; } else { writeln!( out, - " node{i}[label=\"{i} {} {} {}\" color={color}]", - node.kind, node.aclass, node.mem, + " node{i}[label=\"{i} {} {}\" color={color}]", + node.kind, node.aclass, )?; } @@ -763,7 +763,21 @@ impl Nodes { } pub fn aclass_index(&self, region: Nid) -> (usize, Nid) { - (self[region].aclass as _, self[region].mem) + if self[region].aclass >= 0 { + (self[region].aclass as _, region) + } else { + ( + self[self[region].aclass.unsigned_abs() - 1].aclass as _, + self[region].aclass.unsigned_abs() - 1, + ) + } + } + + fn pass_aclass(&mut self, from: Nid, to: Nid) { + debug_assert!(self[from].aclass >= 0); + if from != to { + self[to].aclass = -(from as AClassId + 1); + } } fn peephole(&mut self, target: Nid) -> Option { @@ -1335,7 +1349,7 @@ impl Nodes { write!(out, " {node:>2}-c{:>2}: ", self[node].ralloc_backref)?; } match self[node].kind { - Kind::Assert { .. } | Kind::Start => unreachable!(), + Kind::Assert { .. } | Kind::Start => unreachable!("{} {out}", self[node].kind), Kind::End => return Ok(()), Kind::If => write!(out, " if: "), Kind::Region | Kind::Loop => writeln!(out, " goto: {node}"), @@ -1499,6 +1513,10 @@ impl Nodes { log::error!("is unreachable but still present {id} {:?}", node.kind); failed = true; } + if node.outputs.contains(&id) && !matches!(node.kind, Kind::Loop | Kind::End) { + log::error!("node depends on it self and its not a loop {id} {:?}", node); + failed = true; + } } if failed { @@ -1522,8 +1540,8 @@ impl Nodes { let lvalue = lvar.value(); let inps = [node, lvalue, VOID]; lvar.set_value(self.new_node_nop(lvar.ty, Kind::Phi, inps), self); - self[lvar.value()].aclass = self[lvalue].aclass; - self[lvar.value()].mem = self[lvalue].mem; + + self.pass_aclass(self.aclass_index(lvalue).1, lvar.value()); } var.set_value(lvar.value(), self); } @@ -1728,7 +1746,6 @@ pub struct Node { lock_rc: LockRc, loop_depth: LoopDepth, aclass: AClassId, - mem: Nid, antidep: Nid, } @@ -2254,7 +2271,6 @@ impl<'a> Codegen<'a> { fn new_stack(&mut self, ty: ty::Id) -> Nid { let stck = self.ci.nodes.new_node_nop(ty, Kind::Stck, [VOID, MEM]); self.ci.nodes[stck].aclass = self.ci.scope.aclasses.len() as _; - self.ci.nodes[stck].mem = stck; self.ci.scope.aclasses.push(AClass::new(&mut self.ci.nodes)); stck } @@ -2271,25 +2287,46 @@ impl<'a> Codegen<'a> { let (value_index, value_region) = self.ci.nodes.aclass_index(value); if value_index != 0 { - // simply switch the class to the default one - let aclass = &mut self.ci.scope.aclasses[value_index]; - self.ci.nodes.load_loop_aclass(value_index, aclass, &mut self.ci.loops); - let last_store = aclass.last_store.get(); - let mut cursor = last_store; - let mut first_store = cursor; - while cursor != MEM { - first_store = cursor; - cursor = self.ci.nodes[cursor].inputs[3]; - } + self.ci.nodes[value_region].aclass = 0; + //// simply switch the class to the default one + //let aclass = &mut self.ci.scope.aclasses[value_index]; + //self.ci.nodes.load_loop_aclass(value_index, aclass, &mut self.ci.loops); + //let last_store = aclass.last_store.get(); + //let mut cursor = last_store; + //let mut first_store = cursor; + //while cursor != MEM { + // first_store = cursor; + // debug_assert_matches!( + // self.ci.nodes[cursor].kind, + // Kind::Stre, + // "{:?}", + // self.ci.nodes[cursor] + // ); + // cursor = self.ci.nodes[cursor].inputs[3]; + //} + //if last_store != MEM { + // let base_class = self.ci.scope.aclasses[0].last_store.get(); + // if base_class != MEM { + // self.ci.nodes.modify_input(first_store, 3, base_class); + // } + // self.ci.scope.aclasses[0].last_store.set(last_store, &mut self.ci.nodes); + //} + + self.ci.nodes.load_loop_aclass(0, &mut self.ci.scope.aclasses[0], &mut self.ci.loops); + self.ci.nodes.load_loop_aclass( + value_index, + &mut self.ci.scope.aclasses[value_index], + &mut self.ci.loops, + ); + let base_class = self.ci.scope.aclasses[0].last_store.get(); + let last_store = self.ci.scope.aclasses[value_index].last_store.get(); + if base_class != MEM && last_store != MEM { + self.ci.nodes.bind(base_class, last_store); + } if last_store != MEM { - let base_class = self.ci.scope.aclasses[0].last_store.get(); - if base_class != MEM { - self.ci.nodes.modify_input(first_store, 3, base_class); - } self.ci.scope.aclasses[0].last_store.set(last_store, &mut self.ci.nodes); } - self.ci.nodes[value_region].aclass = 0; } let (index, _) = self.ci.nodes.aclass_index(region); @@ -2485,7 +2522,9 @@ impl<'a> Codegen<'a> { let mut inps = Vc::from([self.ci.ctrl.get(), value.id]); for (i, aclass) in self.ci.scope.aclasses.iter_mut().enumerate() { self.ci.nodes.load_loop_aclass(i, aclass, &mut self.ci.loops); - inps.push(aclass.last_store.get()); + if aclass.last_store.get() != MEM { + inps.push(aclass.last_store.get()); + } } self.ci.ctrl.set( @@ -2729,12 +2768,11 @@ impl<'a> Codegen<'a> { let mut rhs = rhs?; self.strip_var(&mut rhs); self.unwrap_opt(right.pos(), &mut rhs); - let (ty, aclass, mem) = self.binop_ty(pos, &mut lhs, &mut rhs, op); + let (ty, aclass) = self.binop_ty(pos, &mut lhs, &mut rhs, op); let inps = [VOID, lhs.id, rhs.id]; let bop = self.ci.nodes.new_node_lit(ty.bin_ret(op), Kind::BinOp { op }, inps); - self.ci.nodes[bop.id].aclass = aclass as _; - self.ci.nodes[bop.id].mem = mem; + self.ci.nodes.pass_aclass(aclass, bop.id); Some(bop) } ty::Kind::Struct(s) if op.is_homogenous() => { @@ -2784,12 +2822,11 @@ impl<'a> Codegen<'a> { let inps = [VOID, idx.id, size]; let offset = self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Mul }, inps); - let (aclass, mem) = self.ci.nodes.aclass_index(bs.id); + let aclass = self.ci.nodes.aclass_index(bs.id).1; let inps = [VOID, bs.id, offset]; let ptr = self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Add }, inps); - self.ci.nodes[ptr].aclass = aclass as _; - self.ci.nodes[ptr].mem = mem; + self.ci.nodes.pass_aclass(aclass, ptr); Some(Value::ptr(ptr).ty(elem)) } @@ -3896,11 +3933,10 @@ impl<'a> Codegen<'a> { } let off = self.ci.nodes.new_const(ty::Id::INT, off); - let (aclass, mem) = self.ci.nodes.aclass_index(val); + let aclass = self.ci.nodes.aclass_index(val).1; let inps = [VOID, val, off]; let seted = self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Add }, inps); - self.ci.nodes[seted].aclass = aclass as _; - self.ci.nodes[seted].mem = mem; + self.ci.nodes.pass_aclass(aclass, seted); seted } @@ -4089,7 +4125,7 @@ impl<'a> Codegen<'a> { lhs: &mut Value, rhs: &mut Value, op: TokenKind, - ) -> (ty::Id, usize, Nid) { + ) -> (ty::Id, Nid) { if let Some(upcasted) = lhs.ty.try_upcast(rhs.ty) { let to_correct = if lhs.ty != upcasted { Some((lhs, rhs)) @@ -4111,20 +4147,16 @@ impl<'a> Codegen<'a> { self.ci.nodes.new_node(upcasted, Kind::BinOp { op: TokenKind::Mul }, [ VOID, oper.id, cnst, ]); - return ( - upcasted, - self.ci.nodes[other.id].aclass as _, - self.ci.nodes[other.id].mem, - ); + return (upcasted, self.ci.nodes.aclass_index(other.id).1); } } - (upcasted, DEFAULT_ACLASS, VOID) + (upcasted, VOID) } else { 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, DEFAULT_ACLASS, VOID) + (ty::Id::NEVER, VOID) } } @@ -4448,6 +4480,7 @@ mod tests { fb_driver; // Purely Testing Examples; + inlining_issues; null_check_test; only_break_loop; reading_idk; diff --git a/lang/src/son/hbvm.rs b/lang/src/son/hbvm.rs index ddfce3f..38aa166 100644 --- a/lang/src/son/hbvm.rs +++ b/lang/src/son/hbvm.rs @@ -395,6 +395,9 @@ impl ItemCtx { PLoc::WideReg(rg, size) => (rg, size), PLoc::Ref(..) | PLoc::Reg(..) => continue, }; + if size > 8 { + allocs.next().unwrap(); + } self.emit(instrs::ld(rg, atr(arg), 0, size)); } @@ -946,7 +949,7 @@ impl<'a> Function<'a> { regalloc2::PReg::new(r as _, regalloc2::RegClass::Int), )); } - PLoc::WideReg(..) | PLoc::Reg(..) => { + PLoc::WideReg(r, size) | PLoc::Reg(r, size) => { loop { match self.nodes[i].kind { Kind::Stre { .. } => i = self.nodes[i].inputs[2], @@ -956,7 +959,16 @@ impl<'a> Function<'a> { debug_assert_ne!(i, 0); } debug_assert!(i != 0); - ops.push(self.urg(i)); + ops.push(regalloc2::Operand::reg_fixed_use( + self.rg(i), + regalloc2::PReg::new(r as _, regalloc2::RegClass::Int), + )); + if size > 8 { + ops.push(regalloc2::Operand::reg_fixed_use( + self.rg(i), + regalloc2::PReg::new((r + 1) as _, regalloc2::RegClass::Int), + )); + } } PLoc::Ref(r, _) => { loop { @@ -1044,6 +1056,7 @@ impl<'a> Function<'a> { } Kind::Stre if node.inputs[1] == VOID => self.nodes.lock(nid), Kind::Stre => { + debug_assert_ne!(self.tys.size_of(node.ty), 0); let mut region = node.inputs[2]; if self.nodes[region].kind == (Kind::BinOp { op: TokenKind::Add }) && self.nodes.is_const(self.nodes[region].inputs[2]) @@ -1597,6 +1610,7 @@ pub fn test_run_vm(out: &[u8], output: &mut String) { unsafe { alloc::alloc::dealloc(ptr as *mut u8, layout) }; } 3 => vm.write_reg(1, 42), + 8 => {} unknown => unreachable!("unknown ecall: {unknown:?}"), }, Ok(hbvm::VmRunOk::Timer) => { diff --git a/lang/tests/son_tests_directives.txt b/lang/tests/son_tests_directives.txt index be46acd..9c25941 100644 --- a/lang/tests/son_tests_directives.txt +++ b/lang/tests/son_tests_directives.txt @@ -8,12 +8,13 @@ main: LI64 r6, 6d LI64 r5, 5d LI64 r2, 1d - LD r3, r4, 0a, 16h + CP r3, r4 + LD r3, r3, 0a, 16h ECA LI64 r1, 0d ADDI64 r254, r254, 16d JALA r0, r31, 0a ev: Ecall -code size: 152 +code size: 155 ret: 0 status: Ok(()) diff --git a/lang/tests/son_tests_inline_test.txt b/lang/tests/son_tests_inline_test.txt index a427d1b..77d182b 100644 --- a/lang/tests/son_tests_inline_test.txt +++ b/lang/tests/son_tests_inline_test.txt @@ -24,14 +24,14 @@ scalar_values: structs: ADDI64 r254, r254, -32d LI64 r1, 5d - ST r1, r254, 0a, 8h - ST r1, r254, 8a, 8h - LD r5, r254, 0a, 8h + ST r1, r254, 16a, 8h + ST r1, r254, 24a, 8h + LD r5, r254, 16a, 8h ADDI64 r7, r5, 15d - ST r7, r254, 16a, 8h + ST r7, r254, 0a, 8h LI64 r10, 20d - ST r10, r254, 24a, 8h - LD r1, r254, 16a, 8h + ST r10, r254, 8a, 8h + LD r1, r254, 0a, 8h SUB64 r1, r1, r10 ADDI64 r254, r254, 32d JALA r0, r31, 0a diff --git a/lang/tests/son_tests_inlining_issues.txt b/lang/tests/son_tests_inlining_issues.txt new file mode 100644 index 0000000..318c5a1 --- /dev/null +++ b/lang/tests/son_tests_inlining_issues.txt @@ -0,0 +1,109 @@ +main: + ADDI64 r254, r254, -66d + ST r31, r254, 58a, 8h + ADDI64 r3, r254, 33d + ADDI64 r2, r254, 34d + ADDI64 r6, r254, 1d + LI64 r9, 0d + ADDI64 r4, r254, 17d + ST r3, r254, 34a, 8h + LI64 r10, 100d + ADDI64 r7, r254, 0d + LI8 r5, 1b + ST r9, r254, 1a, 8h + ST r9, r254, 17a, 8h + ST r10, r254, 42a, 8h + LI8 r3, 0b + ST r5, r254, 0a, 1h + ST r9, r254, 9a, 8h + ST r9, r254, 25a, 8h + ST r10, r254, 50a, 8h + ST r3, r254, 33a, 1h + CP r3, r4 + CP r5, r6 + LD r3, r3, 0a, 16h + LD r5, r5, 0a, 16h + LD r7, r7, 0a, 1h + JAL r31, r0, :put_filled_rect + LD r31, r254, 58a, 8h + ADDI64 r254, r254, 66d + JALA r0, r31, 0a +put_filled_rect: + ADDI64 r254, r254, -212d + ST r32, r254, 108a, 104h + ST r3, r254, 92a, 16h + ADDI64 r3, r254, 92d + ST r5, r254, 76a, 16h + ADDI64 r5, r254, 76d + ST r7, r254, 75a, 1h + ADDI64 r7, r254, 75d + LI64 r8, 25d + LI64 r32, 2d + LI64 r6, 8d + ADDI64 r33, r254, 25d + ADDI64 r34, r254, 50d + LI8 r35, 5b + ST r35, r254, 25a, 1h + LD r36, r5, 0a, 8h + ST r36, r254, 26a, 4h + LI64 r37, 1d + ST r37, r254, 30a, 4h + ST r7, r254, 34a, 8h + ST r35, r254, 50a, 1h + ST r36, r254, 51a, 4h + ST r37, r254, 55a, 4h + ST r7, r254, 59a, 8h + CP r38, r7 + LD r7, r3, 8a, 8h + LD r39, r5, 8a, 8h + ADD64 r11, r39, r7 + SUB64 r4, r11, r37 + LD r40, r2, 8a, 8h + MUL64 r5, r40, r4 + LD r9, r2, 0a, 8h + ADD64 r10, r9, r5 + LD r2, r3, 0a, 8h + ADD64 r41, r2, r10 + MUL64 r3, r40, r7 + ADD64 r4, r9, r3 + ADD64 r42, r2, r4 + 3: JGTU r39, r37, :0 + JNE r39, r37, :1 + ADDI64 r4, r254, 0d + ST r35, r254, 0a, 1h + ST r36, r254, 1a, 4h + ST r37, r254, 5a, 4h + ST r38, r254, 9a, 8h + ST r42, r254, 17a, 8h + CP r2, r6 + CP r3, r32 + CP r5, r8 + ECA + JMP :1 + 1: JMP :2 + 0: CP r3, r32 + CP r43, r6 + CP r44, r8 + ST r42, r254, 67a, 8h + CP r2, r43 + CP r4, r34 + CP r5, r44 + ECA + ST r41, r254, 42a, 8h + CP r2, r43 + CP r3, r32 + CP r4, r33 + CP r5, r44 + ECA + ADD64 r42, r40, r42 + SUB64 r41, r41, r40 + SUB64 r39, r39, r32 + CP r6, r43 + CP r8, r44 + JMP :3 + 2: LD r32, r254, 108a, 104h + ADDI64 r254, r254, 212d + JALA r0, r31, 0a +code size: 917 +ret: 0 +status: Ok(()) diff --git a/lang/tests/son_tests_nullable_types.txt b/lang/tests/son_tests_nullable_types.txt index 273bcc1..11c7aa9 100644 --- a/lang/tests/son_tests_nullable_types.txt +++ b/lang/tests/son_tests_nullable_types.txt @@ -20,12 +20,12 @@ main: LI8 r35, 1b ANDI r1, r1, 255d JNE r1, r0, :4 - ST r35, r254, 56a, 1h + ST r35, r254, 40a, 1h LD r9, r33, 0a, 8h - ST r9, r254, 64a, 8h + ST r9, r254, 48a, 8h JMP :5 - 4: ST r34, r254, 56a, 1h - 5: LD r6, r254, 56a, 1h + 4: ST r34, r254, 40a, 1h + 5: LD r6, r254, 40a, 1h ANDI r6, r6, 255d ANDI r34, r34, 255d JEQ r6, r34, :6 @@ -48,34 +48,34 @@ main: LI64 r37, 1d ANDI r1, r1, 255d JNE r1, r0, :10 - ST r3, r254, 16a, 8h + ST r3, r254, 0a, 8h JMP :11 -10: ST r32, r254, 16a, 8h - ST r37, r254, 24a, 8h +10: ST r32, r254, 0a, 8h + ST r37, r254, 8a, 8h ST r37, r254, 72a, 8h -11: LD r2, r254, 16a, 8h +11: LD r2, r254, 0a, 8h JNE r2, r3, :12 LI64 r1, 34d JMP :3 12: JAL r31, r0, :decide - ADDI64 r10, r254, 32d + ADDI64 r10, r254, 16d ANDI r1, r1, 255d JNE r1, r0, :13 - ADDI64 r11, r254, 0d - ST r32, r254, 0a, 8h - ST r37, r254, 8a, 8h - ST r35, r254, 32a, 1h + ADDI64 r11, r254, 56d + ST r32, r254, 56a, 8h + ST r37, r254, 64a, 8h + ST r35, r254, 16a, 1h ADDI64 r12, r10, 8d BMC r11, r12, 16h JMP :14 -13: ST r34, r254, 32a, 1h -14: LD r11, r254, 32a, 1h +13: ST r34, r254, 16a, 1h +14: LD r11, r254, 16a, 1h ANDI r11, r11, 255d ANDI r34, r34, 255d JEQ r11, r34, :15 LI64 r1, 420d JMP :3 -15: LD r5, r254, 16a, 8h +15: LD r5, r254, 0a, 8h LD r7, r5, 0a, 8h ANDI r9, r36, 65535d SUB64 r1, r9, r7 diff --git a/lang/tests/son_tests_structs.txt b/lang/tests/son_tests_structs.txt index baa5202..c630e38 100644 --- a/lang/tests/son_tests_structs.txt +++ b/lang/tests/son_tests_structs.txt @@ -1,13 +1,14 @@ main: ADDI64 r254, r254, -56d ST r31, r254, 32a, 24h - LI64 r3, 4d - ADDI64 r2, r254, 16d - ST r3, r254, 16a, 8h + LI64 r2, 4d + ADDI64 r4, r254, 16d + ST r2, r254, 16a, 8h LI64 r32, 3d ST r32, r254, 24a, 8h ADDI64 r33, r254, 0d - LD r3, r2, 0a, 16h + CP r3, r4 + LD r3, r3, 0a, 16h JAL r31, r0, :odher_pass ST r1, r254, 0a, 16h LD r2, r254, 8a, 8h @@ -29,6 +30,6 @@ odher_pass: pass: LD r1, r2, 0a, 8h JALA r0, r31, 0a -code size: 305 +code size: 308 ret: 4 status: Ok(())