Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

reached unreachable code in wasm backend when using packed struct on ABI boundary #18894

Closed
andrewrk opened this issue Feb 11, 2024 · 0 comments · Fixed by #18897
Closed

reached unreachable code in wasm backend when using packed struct on ABI boundary #18894

andrewrk opened this issue Feb 11, 2024 · 0 comments · Fixed by #18897
Labels
arch-wasm 32-bit and 64-bit WebAssembly backend-self-hosted bug Observed behavior contradicts documented or intended behavior
Milestone

Comments

@andrewrk
Copy link
Member

const std = @import("std");
const assert = std.debug.assert;
const expect = std.testing.expect;

const S = packed struct(u16) {
    x: u15 = 0,
    y: u1 = 0,
};

fn foo(s: S) callconv(.C) i32 {
    return s.x;
}

test "example" {
    var s: S = .{};
    s.x += 1;
    try bar(s);
}

fn bar(s: S) !void {
    try expect(foo(s) == 1);
}
[nix-shell:~/dev/zig/build-release]$ stage4/bin/zig version
0.12.0-dev.2701+d18f52197

[nix-shell:~/dev/zig/build-release]$ stage4/bin/zig test test.zig -fno-lld -fno-llvm -target wasm32-wasi
thread 3386116 panic: reached unreachable code
Analyzing test.zig: test.zig:test.example
      %46 = dbg_block_begin()
      %47 = dbg_stmt(2, 5)
      %48 = block_comptime({
        %49 = decl_val("S") token_offset:15:12 to :15:13
        %50 = break(%48, %49)
      }) node_offset:15:12 to :15:13
      %51 = alloc_mut(%48) node_offset:15:5 to :15:19
      %52 = typeof(%51) node_offset:15:16 to :15:19
      %53 = elem_type(%52) node_offset:15:16 to :15:19
      %54 = struct_init_empty_result(%53) node_offset:15:16 to :15:19
      %55 = store_node(%51, %54) node_offset:15:16 to :15:19
      %56 = dbg_var_ptr(%51, "s")
      %57 = dbg_stmt(3, 5)
      %58 = dbg_stmt(3, 6)
      %59 = field_ptr(%51, "x") node_offset:16:5 to :16:8
      %60 = load(%59) node_offset:16:5 to :16:13
      %61 = typeof(%60) node_offset:16:5 to :16:13
      %62 = dbg_stmt(3, 9)
      %63 = add(%60, @one) node_offset:16:5 to :16:13
      %64 = store(%59, %63)
      %65 = dbg_stmt(4, 5)
      %66 = decl_val("bar") token_offset:17:9 to :17:12
      %67 = dbg_stmt(4, 12)
      %68 = call(.auto, %66, [
        {
          %69 = load(%51) node_offset:17:13 to :17:14
          %70 = break_inline(%68, %69)
        },
      ]) node_offset:17:9 to :17:15
    > %71 = try(%68, {
        %72 = err_union_code(%68) node_offset:17:5 to :17:15
        %73 = dbg_stmt(4, 5)
        %74 = ret_node(%72) node_offset:17:5 to :17:15
      }) node_offset:17:5 to :17:15
      %75 = ensure_result_used(%71) node_offset:17:5 to :17:15
      %76 = dbg_block_end()
      %77 = restore_err_ret_index(%45.none)
      %78 = break(%45, @void_value)
    For full context, use the command
      zig ast-check -t test.zig

  in test.zig: test.zig:test.example
    > %45 = block({%46..%78}) node_offset:14:16 to :14:16

/home/andy/dev/zig/src/arch/wasm/CodeGen.zig:292:21: 0x7ee173b in buildOpcode (zig)
            else => unreachable,
                    ^
/home/andy/dev/zig/src/arch/wasm/CodeGen.zig:1440:43: 0x7eebcbf in lowerArg (zig)
                const opcode = buildOpcode(.{
                                          ^
/home/andy/dev/zig/src/arch/wasm/CodeGen.zig:2249:26: 0x7d2102b in airCall (zig)
        try func.lowerArg(mod.typeToFunc(fn_ty).?.cc, arg_ty, arg_val);
                         ^
/home/andy/dev/zig/src/arch/wasm/CodeGen.zig:1933:30: 0x7a9f91e in genInst (zig)
        .call => func.airCall(inst, .auto),
                             ^
/home/andy/dev/zig/src/arch/wasm/CodeGen.zig:2090:25: 0x75c4656 in genBody (zig)
        try func.genInst(inst);
                        ^
/home/andy/dev/zig/src/arch/wasm/CodeGen.zig:1268:21: 0x708c09f in genFunc (zig)
    try func.genBody(func.air.getMainBody());
                    ^
/home/andy/dev/zig/src/arch/wasm/CodeGen.zig:1236:12: 0x6ae42af in generate (zig)
    genFunc(&code_gen) catch |err| switch (err) {
           ^
/home/andy/dev/zig/src/codegen.zig:74:60: 0x65227e6 in generateFunction (zig)
        => return @import("arch/wasm/CodeGen.zig").generate(lf, src_loc, func_index, air, liveness, code, debug_output),
                                                           ^
/home/andy/dev/zig/src/link/Wasm.zig:1505:48: 0x652ca8b in updateFunc (zig)
    const result = try codegen.generateFunction(
                                               ^
/home/andy/dev/zig/src/link.zig:438:76: 0x61b430b in updateFunc (zig)
                return @fieldParentPtr(tag.Type(), "base", base).updateFunc(module, func_index, air, liveness);
                                                                           ^
/home/andy/dev/zig/src/Module.zig:3614:22: 0x5ed04b1 in ensureFuncBodyAnalyzed (zig)
        lf.updateFunc(zcu, func_index, air, liveness) catch |err| switch (err) {
                     ^
/home/andy/dev/zig/src/Sema.zig:32431:31: 0x6c36b1d in ensureFuncBodyAnalyzed (zig)
    mod.ensureFuncBodyAnalyzed(func) catch |err| {
                              ^
/home/andy/dev/zig/src/Sema.zig:36374:40: 0x66de94b in resolveInferredErrorSet (zig)
        try sema.ensureFuncBodyAnalyzed(func_index);
                                       ^
/home/andy/dev/zig/src/Sema.zig:32762:69: 0x66afdd6 in analyzeIsNonErrComptimeOnly (zig)
                const resolved_ty = try sema.resolveInferredErrorSet(block, src, set_ty);
                                                                    ^
/home/andy/dev/zig/src/Sema.zig:19066:60: 0x66aea8d in zirTry (zig)
    const is_non_err = try sema.analyzeIsNonErrComptimeOnly(parent_block, operand_src, err_union);
                                                           ^
/home/andy/dev/zig/src/Sema.zig:1771:67: 0x61ed92a in analyzeBodyInner (zig)
                if (!block.is_comptime) break :blk try sema.zirTry(block, inst);
                                                                  ^
/home/andy/dev/zig/src/Sema.zig:5978:34: 0x6b8e227 in resolveBlockBody (zig)
        if (sema.analyzeBodyInner(child_block, body)) |_| {
                                 ^
/home/andy/dev/zig/src/Sema.zig:5961:33: 0x66b358f in zirBlock (zig)
    return sema.resolveBlockBody(parent_block, src, &child_block, body, inst, &label.merges);
                                ^
/home/andy/dev/zig/src/Sema.zig:1602:49: 0x61ef29b in analyzeBodyInner (zig)
                    break :blk try sema.zirBlock(block, inst, tags[@intFromEnum(inst)] == .block_comptime);
                                                ^
/home/andy/dev/zig/src/Sema.zig:922:30: 0x6508898 in analyzeBody (zig)
    _ = sema.analyzeBodyInner(block, body) catch |err| switch (err) {
                             ^
/home/andy/dev/zig/src/Module.zig:4878:21: 0x61b1ea7 in analyzeFnBody (zig)
    sema.analyzeBody(&inner_block, fn_info.body) catch |err| switch (err) {
                    ^
/home/andy/dev/zig/src/Module.zig:3552:32: 0x5ecfa71 in ensureFuncBodyAnalyzed (zig)
    var air = zcu.analyzeFnBody(func_index, sema_arena) catch |err| switch (err) {
                               ^
/home/andy/dev/zig/src/Compilation.zig:3579:42: 0x5ecdc03 in processOneJob (zig)
            module.ensureFuncBodyAnalyzed(func) catch |err| switch (err) {
                                         ^
/home/andy/dev/zig/src/Compilation.zig:3508:30: 0x5c7813a in performAllTheWork (zig)
            try processOneJob(comp, work_item, main_progress_node);
                             ^
/home/andy/dev/zig/src/Compilation.zig:2191:31: 0x5c73dbb in update (zig)
    try comp.performAllTheWork(main_progress_node);
                              ^
/home/andy/dev/zig/src/main.zig:4500:24: 0x5ca3e3c in updateModule (zig)
        try comp.update(main_progress_node);
                       ^
/home/andy/dev/zig/src/main.zig:3353:17: 0x5cc2247 in buildOutputType (zig)
    updateModule(comp, color) catch |err| switch (err) {
                ^
/home/andy/dev/zig/src/main.zig:283:31: 0x5aacb19 in mainArgs (zig)
        return buildOutputType(gpa, arena, args, .zig_test);
                              ^
/home/andy/dev/zig/src/main.zig:223:20: 0x5aa9965 in main (zig)
    return mainArgs(gpa, arena, args);
                   ^
/home/andy/dev/zig/lib/std/start.zig:511:37: 0x5aa93de in main (zig)
            const result = root.main() catch |err| {
                                    ^
???:?:?: 0x7fd38adf0b0d in ??? (libc.so.6)
Unwind information for `libc.so.6:0x7fd38adf0b0d` was not available, trace may be incomplete

Aborted (core dumped)

The problem seems to be something related to passing bytes where bits are expected, however, this change alone is insufficient to solve the problem.

--- a/src/arch/wasm/CodeGen.zig
+++ b/src/arch/wasm/CodeGen.zig
@@ -1439,7 +1439,7 @@ fn lowerArg(func: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value:
             if (value != .imm32 and value != .imm64) {
                 const opcode = buildOpcode(.{
                     .op = .load,
-                    .width = @as(u8, @intCast(abi_size)),
+                    .width = @as(u8, @intCast(abi_size * 8)),
                     .signedness = if (scalar_type.isSignedInt(mod)) .signed else .unsigned,
                     .valtype1 = typeToValtype(scalar_type, mod),
                 });
@andrewrk andrewrk added bug Observed behavior contradicts documented or intended behavior arch-wasm 32-bit and 64-bit WebAssembly backend-self-hosted labels Feb 11, 2024
@andrewrk andrewrk added this to the 0.12.0 milestone Feb 11, 2024
Luukdegram added a commit to Luukdegram/zig that referenced this issue Feb 11, 2024
When an argument is a 'local', which is the case when it's a parameter,
we should not attempt to load it from memory. Instead, we directly emit
it to the stack. Only when the `WValue` is ensure to live in the linear
data section do we load it from memory onto the stack.

closes ziglang#18894
Luukdegram added a commit that referenced this issue Feb 11, 2024
When an argument is a 'local', which is the case when it's a parameter,
we should not attempt to load it from memory. Instead, we directly emit
it to the stack. Only when the `WValue` is ensure to live in the linear
data section do we load it from memory onto the stack.

closes #18894
Rexicon226 pushed a commit to Rexicon226/zig that referenced this issue Feb 16, 2024
When an argument is a 'local', which is the case when it's a parameter,
we should not attempt to load it from memory. Instead, we directly emit
it to the stack. Only when the `WValue` is ensure to live in the linear
data section do we load it from memory onto the stack.

closes ziglang#18894
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
arch-wasm 32-bit and 64-bit WebAssembly backend-self-hosted bug Observed behavior contradicts documented or intended behavior
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant