Skip to content

Compiler bug with ranged nested switch #3988

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

Closed
LiterallyVoid opened this issue Dec 28, 2019 · 1 comment
Closed

Compiler bug with ranged nested switch #3988

LiterallyVoid opened this issue Dec 28, 2019 · 1 comment
Labels
bug Observed behavior contradicts documented or intended behavior stage1 The process of building from source via WebAssembly and the C backend.
Milestone

Comments

@LiterallyVoid
Copy link
Contributor

LiterallyVoid commented Dec 28, 2019

Zig version: 0.5.0+25e71216c

Code:

pub fn main() void {
    var zds: u2 = 0;
    zds = switch(zds) {
        0 => switch(zds) {
            0...0 => zds, // two ranges make it break, making either not a range or removing either range will make it work again
            1...1 => zds,
            2 => zds,
            // changing `else` to `3` will make it work
            // returning, breaking out of a loop, or breaking out of a labeled block will make it break
            else => return,
        },
        else => zds,
    };
}

Compiler output:

Code Generation [280/474] std.fmt.format...broken LLVM module found: PHINode should have one entry for each predecessor of its parent basic block!
  %7 = phi i2 [ %5, %SwitchRangeYes ], [ %6, %SwitchRangeYes2 ], !dbg !12435

This is a bug in the Zig compiler.

LLVM ir:

; Function Attrs: nobuiltin nounwind
define internal fastcc void @main() unnamed_addr #1 !dbg !12427 {
Entry:
  %zds = alloca i2, align 1
  store i2 0, i2* %zds, align 1, !dbg !12432
  call void @llvm.dbg.declare(metadata i2* %zds, metadata !12430, metadata !DIExpression()), !dbg !12432
  %0 = load i2, i2* %zds, align 1, !dbg !12433
  switch i2 %0, label %SwitchElse [
    i2 0, label %SwitchProng
  ], !dbg !12433

SwitchElse:                                       ; preds = %Entry
  %1 = load i2, i2* %zds, align 1, !dbg !12434
  store i2 %1, i2* %zds, align 1, !dbg !12434
  br label %SwitchEnd3, !dbg !12433

SwitchProng:                                      ; preds = %Entry
  %2 = load i2, i2* %zds, align 1, !dbg !12435
  %3 = icmp ule i2 %2, 0, !dbg !12436
  %4 = and i1 true, %3, !dbg !12436
  br i1 %4, label %SwitchRangeYes, label %SwitchRangeNo, !dbg !12436

SwitchElse1:                                      ; preds = %SwitchRangeNo4
  ret void, !dbg !12437

SwitchRangeYes:                                   ; preds = %SwitchProng
  %5 = load i2, i2* %zds, align 1, !dbg !12438
  store i2 %5, i2* %zds, align 1, !dbg !12438
  br label %SwitchEnd, !dbg !12435

SwitchRangeYes2:                                  ; preds = %SwitchRangeNo
  %6 = load i2, i2* %zds, align 1, !dbg !12439
  store i2 %6, i2* %zds, align 1, !dbg !12439
  br label %SwitchEnd, !dbg !12435

SwitchEnd:                                        ; preds = %SwitchProng5, %SwitchRangeYes2, %SwitchRangeYes
  %7 = phi i2 [ %5, %SwitchRangeYes ], [ %6, %SwitchRangeYes2 ], !dbg !12435
  store i2 %7, i2* %zds, align 1, !dbg !12435
  br label %SwitchEnd3, !dbg !12433

SwitchEnd3:                                       ; preds = %SwitchEnd, %SwitchElse
  ret void, !dbg !12440

SwitchRangeNo:                                    ; preds = %SwitchProng
  %8 = icmp uge i2 %2, 1, !dbg !12441
  %9 = icmp ule i2 %2, 1, !dbg !12441
  %10 = and i1 %8, %9, !dbg !12441
  br i1 %10, label %SwitchRangeYes2, label %SwitchRangeNo4, !dbg !12441

SwitchRangeNo4:                                   ; preds = %SwitchRangeNo
  switch i2 %2, label %SwitchElse1 [
    i2 -2, label %SwitchProng5
  ], !dbg !12435

SwitchProng5:                                     ; preds = %SwitchRangeNo4
  %11 = load i2, i2* %zds, align 1, !dbg !12442
  store i2 %11, i2* %zds, align 1, !dbg !12442
  br label %SwitchEnd, !dbg !12435
}

Backtrace:

#0  0x00007ffff0190f25 in raise () from /usr/lib/libc.so.6
#1  0x00007ffff017a897 in abort () from /usr/lib/libc.so.6
#2  0x0000555555b82389 in std.os.abort () at zig/lib/std/os.zig:206
#3  0x0000555555b7aac5 in std.debug.panicExtra (trace=0x0, first_trace_addr=..., args=...) at zig/lib/std/debug.zig:252
#4  0x0000555555b79883 in std.builtin.default_panic (msg=..., error_return_trace=0x0) at zig/lib/std/builtin.zig:455
#5  0x0000555555be7fe5 in std.debug.StackIterator.next (self=0x7fffffffd8a0) at zig/lib/std/debug.zig:317
#6  0x0000555555b9a4a6 in std.debug.writeCurrentStackTrace (out_stream=0x5555566c5440 <stderr_file_out_stream+8>, debug_info=0x5555566c5448 <self_debug_info>, tty_color=false, start_addr=...) at zig/lib/std/debug.zig:327
#7  0x0000555555b82842 in std.debug.dumpCurrentStackTrace (start_addr=...) at zig/lib/std/debug.zig:102
#8  0x0000555555b7aab9 in std.debug.panicExtra (trace=0x0, first_trace_addr=..., args=...) at zig/lib/std/debug.zig:240
#9  0x0000555555b79883 in std.builtin.default_panic (msg=..., error_return_trace=0x0) at zig/lib/std/builtin.zig:455
#10 0x0000555555b7ab5d in stage2_panic (ptr=0x5555562d8144 "", len=0) at stage1.zig:33
#11 0x0000555555b39742 in zig_panic (format=0x5555562b2e58 "broken LLVM module found: %s\nThis is a bug in the Zig compiler.") at zig/src/util.cpp:20
#12 0x0000555555a6ee23 in do_code_gen (g=0x5555567277c0) at zig/src/codegen.cpp:7821
#13 0x0000555555a790f5 in codegen_build_and_link (g=0x5555567277c0) at zig/src/codegen.cpp:10341
#14 0x0000555555a4bf25 in main (argc=3, argv=0x7fffffffe898) at zig/src/main.cpp:1295
@daurnimator daurnimator added bug Observed behavior contradicts documented or intended behavior stage1 The process of building from source via WebAssembly and the C backend. labels Dec 28, 2019
@andrewrk andrewrk added this to the 0.6.0 milestone Dec 31, 2019
@h57624paen
Copy link
Contributor

pub fn boom2(a: u8, b: u8) u8 {
    return switch (a) {
        0x07 => switch (b) {
            0x1...0x13 => @as(u8, 1),
            0x1f => 0xff,
            else => {
                unreachable;
            },
        },
        else => unreachable,
    };
}

test "bad_switch" {
    var v: u8 = undefined;
    v = boom2(0x07, 0x1f);
    assert(v == 0xff);
}

This is definitely a related situation, but I think its slightly more nefarious since it will compile fine, but the result of the switch is statement ends up being the value from the ranged case rather than the correct value :)

@andrewrk andrewrk modified the milestones: 0.6.0, 0.7.0 Mar 4, 2020
@andrewrk andrewrk modified the milestones: 0.7.0, 0.8.0 Aug 13, 2020
@andrewrk andrewrk modified the milestones: 0.8.0, 0.9.0 Nov 6, 2020
@andrewrk andrewrk modified the milestones: 0.9.0, 0.10.0 May 19, 2021
Vexu added a commit to Vexu/zig that referenced this issue Dec 28, 2022
Vexu added a commit to Vexu/zig that referenced this issue Dec 28, 2022
Vexu added a commit to Vexu/zig that referenced this issue Dec 28, 2022
Vexu added a commit to Vexu/zig that referenced this issue Dec 28, 2022
Vexu added a commit to Vexu/zig that referenced this issue Dec 28, 2022
Vexu added a commit to Vexu/zig that referenced this issue Dec 29, 2022
@andrewrk andrewrk modified the milestones: 0.12.0, 0.11.0 Dec 29, 2022
TUSF pushed a commit to TUSF/zig that referenced this issue May 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Observed behavior contradicts documented or intended behavior stage1 The process of building from source via WebAssembly and the C backend.
Projects
None yet
Development

No branches or pull requests

4 participants