From ee6de69bf02df77aaf29df8b135aba5dcebad5a7 Mon Sep 17 00:00:00 2001
From: Jakub Doka <jakub.doka2@gmail.com>
Date: Sat, 15 Mar 2025 12:28:36 +0100
Subject: [PATCH] fixed some bugs

Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
---
 README.md                   | 23 ++++++++++++
 src/backend/Builder.zig     |  2 +-
 src/backend/Mach.zig        |  3 ++
 src/backend/graph.zig       | 10 +++---
 src/backend/static_anal.zig |  4 +--
 src/hbc.zig                 |  5 +++
 src/hbvm/HbvmGen.zig        |  4 +++
 src/test_util.zig           |  8 -----
 src/tests.zig               |  3 +-
 tests/slices 4.txt          | 72 +++++++++++++++++++++++++++++++++++++
 vendored-tests/lily         |  2 +-
 11 files changed, 118 insertions(+), 18 deletions(-)
 create mode 100644 tests/slices 4.txt

diff --git a/README.md b/README.md
index aa30957..ba4c023 100644
--- a/README.md
+++ b/README.md
@@ -1640,6 +1640,29 @@ main := fn(): uint {
 }
 ```
 
+#### slices 4
+```hb
+equals := fn(lhs: []u8, rhs: []u8): bool {
+    if lhs.len != rhs.len return false
+    if lhs.ptr == rhs.ptr return true
+    i := 0
+    loop if i == lhs.len break else {
+        if lhs[i] != rhs[i] return false
+        i += 1
+    }
+    return true
+}
+
+main := fn(): uint {
+    abc := "abc"
+    a_b_c := u8.['a', 'b', 'c'][..]
+    if !equals(abc, abc) return 1
+    if !equals(a_b_c, abc) return 1
+
+    return 0
+}
+```
+
 #### nullable types 1
 ```hb
 expectations := .{
diff --git a/src/backend/Builder.zig b/src/backend/Builder.zig
index 25bbc47..e5fa3b6 100644
--- a/src/backend/Builder.zig
+++ b/src/backend/Builder.zig
@@ -57,7 +57,7 @@ pub fn addParam(self: *Builder, idx: usize) SpecificNode(.Arg) {
 }
 
 pub fn end(self: *Builder, _: BuildToken) void {
-    if (self.func.end.inputs()[0] == null and !self.isUnreachable()) self.addReturn(&.{});
+    if (!self.isUnreachable()) self.addReturn(&.{});
 }
 
 // #MEM ========================================================================
diff --git a/src/backend/Mach.zig b/src/backend/Mach.zig
index cf2b31e..36507ec 100644
--- a/src/backend/Mach.zig
+++ b/src/backend/Mach.zig
@@ -86,6 +86,7 @@ pub const EmitOptions = struct {
     name: []const u8 = &.{},
     entry: bool = false,
     optimizations: struct {
+        verbose: bool = false,
         dead_code_fuel: usize = 1000,
         mem2reg: bool = true,
         peephole_fuel: usize = 1000,
@@ -120,6 +121,8 @@ pub const EmitOptions = struct {
                 func.gcm.buildCfg();
             }
 
+            if (self.verbose) func.fmtScheduled(std.io.getStdErr().writer().any(), .escape_codes);
+
             if (self.error_buf) |eb| {
                 func.static_anal.analize(self.arena.?, eb);
             }
diff --git a/src/backend/graph.zig b/src/backend/graph.zig
index 8346abf..9f33590 100644
--- a/src/backend/graph.zig
+++ b/src/backend/graph.zig
@@ -1207,13 +1207,13 @@ pub fn Func(comptime MachNode: type) type {
 
                 if (base.kind == .Local) eliminate_stack: {
                     for (base.outputs()) |o| {
-                        _ = knownStore(o) orelse {
+                        _ = knownStore(o, base) orelse {
                             break :eliminate_stack;
                         };
                     }
 
-                    for (base.outputs()) |o| if (knownStore(o).? != node) {
-                        worklist.add(knownStore(o).?);
+                    for (base.outputs()) |o| if (knownStore(o, base).? != node) {
+                        worklist.add(knownStore(o, base).?);
                     };
 
                     return node.mem();
@@ -1287,8 +1287,8 @@ pub fn Func(comptime MachNode: type) type {
             return if (comptime optApi("idealize", @TypeOf(idealize))) MachNode.idealize(self, node, worklist) else null;
         }
 
-        pub fn knownStore(base: *Node) ?*Node {
-            if (base.isStore() and !base.isSub(MemCpy)) return base;
+        pub fn knownStore(base: *Node, root: *Node) ?*Node {
+            if (base.isStore() and !base.isSub(MemCpy) and base.base() == root) return base;
             if (base.kind == .BinOp and base.outputs().len == 1 and base.outputs()[0].isStore() and !base.isSub(MemCpy) and base.outputs()[0].base() == base) {
                 return base.outputs()[0];
             }
diff --git a/src/backend/static_anal.zig b/src/backend/static_anal.zig
index fb9d759..b2b0482 100644
--- a/src/backend/static_anal.zig
+++ b/src/backend/static_anal.zig
@@ -95,7 +95,7 @@ pub fn StaticAnalMixin(comptime Mach: type) type {
                 for (arg.outputs()) |ao| {
                     // TODO: we skip MemCpy, this will miss a class of problesm,
                     // but memcpy elimination might help and effort here would be redundant
-                    const store = Func.knownStore(ao) orelse continue;
+                    const store = Func.knownStore(ao, arg) orelse continue;
 
                     if (store.value().kind == .Local) {
                         local_stores.append(tmp.arena.allocator(), store) catch unreachable;
@@ -106,7 +106,7 @@ pub fn StaticAnalMixin(comptime Mach: type) type {
 
                 // filter out the stores that are overriden
                 for (arg.outputs()) |unmarked| {
-                    const store = Func.knownStore(unmarked) orelse continue;
+                    const store = Func.knownStore(unmarked, arg) orelse continue;
 
                     if (store.value().kind == .Local) continue;
 
diff --git a/src/hbc.zig b/src/hbc.zig
index b885540..540846e 100644
--- a/src/hbc.zig
+++ b/src/hbc.zig
@@ -184,6 +184,11 @@ pub fn compile(opts: CompileOptions) anyerror!struct {
             var tmp = Arena.scrath(null);
             defer tmp.deinit();
 
+            //var out_fmt = std.ArrayList(u8).init(tmp.arena.allocator());
+            //defer out_fmt.deinit();
+            //try asts[@intFromEnum(func.key.file)].fmtExpr(&out_fmt, func.key.ast);
+            //try std.io.getStdErr().writeAll(out_fmt.items);
+
             var errors = std.ArrayListUnmanaged(static_anal.Error){};
 
             backend.emitFunc(&codegen.bl.func, .{
diff --git a/src/hbvm/HbvmGen.zig b/src/hbvm/HbvmGen.zig
index f35ba74..07cb259 100644
--- a/src/hbvm/HbvmGen.zig
+++ b/src/hbvm/HbvmGen.zig
@@ -285,9 +285,11 @@ pub fn finalize(self: *HbvmGen) std.ArrayListUnmanaged(u8) {
 pub fn makeSymMap(self: *HbvmGen, offset: u32, arena: std.mem.Allocator) std.AutoHashMapUnmanaged(u32, []const u8) {
     var map = std.AutoHashMap(u32, []const u8).init(arena);
     for (self.funcs.items) |gf| {
+        if (gf.offset < offset) continue;
         map.put(gf.offset - offset, gf.name) catch unreachable;
     }
     for (self.globals.items) |gf| {
+        if (gf.offset < offset) continue;
         map.put(gf.offset - offset, gf.name) catch unreachable;
     }
     return map.unmanaged;
@@ -797,6 +799,8 @@ pub fn idealizeMach(func: *Func, node: *Func.Node, work: *Func.WorkList) ?*Func.
     }
 
     if (node.kind == .If) {
+        //if (node.outputs().len != 2) utils.panic("{} {} {}\n", .{ node, node.outputs()[0], node.data_type });
+
         if (inps[1].?.kind == .BinOp) b: {
             work.add(inps[1].?);
             const op = inps[1].?.extra(.BinOp).*;
diff --git a/src/test_util.zig b/src/test_util.zig
index 7ba4f59..16ba88b 100644
--- a/src/test_util.zig
+++ b/src/test_util.zig
@@ -139,14 +139,6 @@ pub fn testBuilder(
                 cg.bl.func.reset();
             }
 
-            if (verbose) {
-                if (verbose) try header("SOURCE", output, colors);
-                var out_fmt = std.ArrayList(u8).init(gpa);
-                defer out_fmt.deinit();
-                try asts[@intFromEnum(func.key.file)].fmtExpr(&out_fmt, func.key.ast);
-                try output.writeAll(out_fmt.items);
-            }
-
             if (verbose) try header("UNSCHEDULED SON", output, colors);
             cg.build(func) catch {
                 errored = true;
diff --git a/src/tests.zig b/src/tests.zig
index c1e77b3..87b1932 100644
--- a/src/tests.zig
+++ b/src/tests.zig
@@ -54,7 +54,8 @@ pub fn runFuzzFindingTest(name: []const u8, code: []const u8) !void {
 }
 
 pub fn runVendoredTest(path: []const u8) !void {
-    if (std.mem.count(u8, path, "lily") == 2) return;
+    if (std.mem.endsWith(u8, path, "arena-crash.hb")) return;
+    if (std.mem.endsWith(u8, path, "fmt.hb")) return;
     utils.Arena.initScratch(1024 * 1024);
     defer utils.Arena.deinitScratch();
     try test_util.runVendoredTest(std.testing.allocator, path);
diff --git a/tests/slices 4.txt b/tests/slices 4.txt
new file mode 100644
index 0000000..e014e05
--- /dev/null
+++ b/tests/slices 4.txt	
@@ -0,0 +1,72 @@
+main:
+         st $31, $254, -56, 56
+     addi64 $254, $254, -91
+     addi64 $32, $254, 0
+        lra $33, $0, :main.abc
+         st $33, $254, 0, 8
+       li64 $34, 3
+         st $34, $254, 8, 8
+     addi64 $35, $254, 16
+     addi64 $36, $254, 32
+        li8 $37, 97
+         st $37, $254, 32, 1
+        li8 $37, 98
+         st $37, $254, 33, 1
+        li8 $37, 99
+         st $37, $254, 34, 1
+         st $36, $254, 16, 8
+         st $34, $254, 24, 8
+         cp $1, $33
+         cp $2, $34
+         cp $3, $33
+         cp $4, $34
+        jal $31, $0, :equals
+         cp $33, $1
+       andi $33, $33, 255
+        not $33, $33
+       andi $33, $33, 255
+         ld $34, $254, 8, 8
+         ld $36, $254, 16, 8
+         ld $35, $254, 24, 8
+         ld $32, $254, 0, 8
+        jeq $33, $0, :2
+        jmp :3
+2:       cp $1, $36
+         cp $2, $35
+         cp $3, $32
+         cp $4, $34
+        jal $31, $0, :equals
+       andi $1, $1, 255
+        not $1, $1
+       andi $1, $1, 255
+        jeq $1, $0, :4
+3:     li64 $1, 1
+        jmp :5
+4:     li64 $1, 0
+5:   addi64 $254, $254, 91
+         ld $31, $254, -56, 56
+         tx
+equals:
+       li64 $5, 0
+        jeq $2, $4, :6
+         cp $1, $5
+        jmp :7
+6:     li64 $4, 1
+        jne $1, $3, :8
+         cp $1, $4
+7:      jmp :9
+8:       cp $6, $5
+c:      jne $6, $2, :a
+         cp $1, $4
+        jmp :9
+a:    add64 $7, $1, $6
+      add64 $8, $3, $6
+         ld $7, $7, 0, 1
+         ld $8, $8, 0, 1
+       andi $7, $7, 255
+       andi $8, $8, 255
+        jeq $7, $8, :b
+         cp $1, $5
+9:     jala $0, $31, 0
+b:   addi64 $6, $6, 1
+        jmp :c
\ No newline at end of file
diff --git a/vendored-tests/lily b/vendored-tests/lily
index 8465a14..cbc2872 160000
--- a/vendored-tests/lily
+++ b/vendored-tests/lily
@@ -1 +1 @@
-Subproject commit 8465a141b79aec2f5ca07ff899613f85833ae592
+Subproject commit cbc28723a29da52ffe5fa89c4b022f8f0d8c5637