fixing very sneaky bug

This commit is contained in:
Jakub Doka 2024-11-04 12:38:47 +01:00
parent e8f1d2af8c
commit 2e36f32ae0
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
8 changed files with 286 additions and 75 deletions

View file

@ -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")

View file

@ -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<Nid>;
@ -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<Nid> {
@ -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;

View file

@ -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) => {

View file

@ -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(())

View file

@ -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

View file

@ -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(())

View file

@ -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

View file

@ -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(())