Skip to content

@Vector(.., u1) memory layout confusion #11891

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
xxxbxxx opened this issue Jun 19, 2022 · 7 comments
Closed

@Vector(.., u1) memory layout confusion #11891

xxxbxxx opened this issue Jun 19, 2022 · 7 comments
Labels
backend-llvm The LLVM backend outputs an LLVM IR Module. bug Observed behavior contradicts documented or intended behavior frontend Tokenization, parsing, AstGen, Sema, and Liveness. miscompilation The compiler reports success but produces semantically incorrect code.
Milestone

Comments

@xxxbxxx
Copy link
Contributor

xxxbxxx commented Jun 19, 2022

Zig Version

0.10.0-dev.2588+b753cbe56 (stage1+stage2)

Steps to Reproduce

pub fn main() anyerror!void {
    var xxxxx = @splat(8, @as(u1, 1));
    if (xxxxx[5] != 1) unreachable;

    var yyyyy = [_]@Vector(8, u1){@splat(8, @as(u1, 1))};
    if (yyyyy[0][5] != 1) unreachable;  // crash!
}

Expected Behavior

xxxx works fine.
(immediate 0xFF get loaded into a register, and bit 5 gets tested)

Actual Behavior

yyyy points to some memory with bytes 0x01, 0x01, 0x01, ....
first byte 0x01 gets loaded, bit 5 get tested -> wrong value!

exact same behaviour with stage2.

@xxxbxxx xxxbxxx added the bug Observed behavior contradicts documented or intended behavior label Jun 19, 2022
@xxxbxxx
Copy link
Contributor Author

xxxbxxx commented Jun 19, 2022

maybe related to #11856

@xxxbxxx
Copy link
Contributor Author

xxxbxxx commented Jun 19, 2022

stage2 llvm ir:

@1 = private unnamed_addr constant [1 x <8 x i1>] [<8 x i1> <i1 true, i1 true, i1 true, i1 true, i1 true, i1 true, i1 true, i1 true>], align 16

define internal fastcc i16 @vec.main() unnamed_addr #0 {
Entry:
  %0 = alloca [1 x <8 x i1>], align 16
  %1 = alloca <8 x i1>, align 16
  store <8 x i1> <i1 true, i1 true, i1 true, i1 true, i1 true, i1 true, i1 true, i1 true>, <8 x i1>* %1, align 16
  %2 = load <8 x i1>, <8 x i1>* %1, align 16
  %3 = extractelement <8 x i1> %2, i64 5
  %4 = icmp ne i1 %3, true
  br i1 %4, label %Then, label %Else

Then:                                             ; preds = %Entry
  call fastcc void @builtin.default_panic(i8* getelementptr inbounds ([24 x i8], [24 x i8]* @vec.main__anon_3590, i32 0, i32 0), i64 24, %builtin.StackTrace* null)
  unreachable

Else:                                             ; preds = %Entry
  br label %Block

Block:                                            ; preds = %Else
  %5 = bitcast [1 x <8 x i1>]* %0 to i8*
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 %5, i8* align 16 bitcast ([1 x <8 x i1>]* @1 to i8*), i64 8, i1 false)
  %6 = getelementptr inbounds [1 x <8 x i1>], [1 x <8 x i1>]* %0, i32 0, i64 0
  %7 = load <8 x i1>, <8 x i1>* %6, align 8
  %8 = extractelement <8 x i1> %7, i64 5
  %9 = icmp ne i1 %8, true
  br i1 %9, label %Then1, label %Else2

Then1:                                            ; preds = %Block
  call fastcc void @builtin.default_panic(i8* getelementptr inbounds ([24 x i8], [24 x i8]* @vec.main__anon_3591, i32 0, i32 0), i64 24, %builtin.StackTrace* null)
  unreachable

Else2:                                            ; preds = %Block
  br label %Block3

Block3:                                           ; preds = %Else2
  ret i16 0
}

@xxxbxxx
Copy link
Contributor Author

xxxbxxx commented Jun 19, 2022

my guess would be that
%66 = constant([1]@Vector(8, u1), .{ .{ 1, 1, 1, 1, 1, 1, 1, 1 } })
doesn't get the correct memory layout?
or maybe it's more complicated and 'correct' depends on the context?

stage2 air:

# Begin Function AIR: vec.main:
# Total AIR+Liveness bytes: 1.552734375KiB
# AIR Instructions:         98 (882B)
# AIR Extra Data:           38 (152B)
# AIR Values Bytes:         42 (336B)
# Liveness tomb_bits:       56B
# Liveness Extra Data:      9 (36B)
# Liveness special table:   2 (16B)
  %0 = const_ty((inferred_alloc_mut))
  %2 = constant(comptime_int, 8)
  %3 = constant(u1, 1)
  %4 = constant(u32, 8)
  %5 = const_ty(@Vector(8, u1))
  %6 = constant(@Vector(8, u1), .{ 1, 1, 1, 1, 1, 1, 1, 1 })
  %7 = const_ty(*@Vector(8, u1))
  %9 = const_ty(@Vector(8, u1))
  %11 = const_ty(@Vector(8, u1))
  %13 = const_ty(@Vector(8, u1))
  %15 = constant(comptime_int, 5)
  %16 = constant(usize, 5)
  %18 = const_ty(u1)
  %19 = constant(u1, 1)
  %21 = const_ty(*const [24]u8)
  %22 = constant(*const [24]u8, "reached unreachable code")
  %23 = constant([]const u8, .{ 114, 101, 97, 99, 104, 101, 100, 32, 117, 110, 114, 101, 97, 99, 104, 97, 98, 108, 101, 32, 99, 111, 100, 101 })
  %24 = const_ty(*const type)
  %25 = constant(*const type, builtin.builtin)
  %26 = constant(type, builtin.builtin)
  %27 = const_ty(*const fn([]const u8, ?*builtin.StackTrace) noreturn)
  %28 = constant(*const fn([]const u8, ?*builtin.StackTrace) noreturn, (function 'default_panic'))
  %29 = const_ty(fn([]const u8, ?*builtin.StackTrace) noreturn)
  %30 = constant(fn([]const u8, ?*builtin.StackTrace) noreturn, (function 'default_panic'))
  %31 = const_ty(*const type)
  %32 = constant(*const type, builtin.builtin)
  %33 = constant(type, builtin.builtin)
  %34 = const_ty(*const type)
  %35 = constant(*const type, builtin.StackTrace)
  %36 = constant(type, builtin.StackTrace)
  %37 = const_ty(builtin.StackTrace)
  %38 = const_ty(?*builtin.StackTrace)
  %39 = constant(?*builtin.StackTrace, null)
  %43 = const_ty((inferred_alloc_mut))
  %45 = constant(comptime_int, 1)
  %46 = constant(comptime_int, 8)
  %47 = constant(u32, 8)
  %48 = const_ty(@Vector(8, u1))
  %49 = constant(usize, 1)
  %50 = const_ty([1]@Vector(8, u1))
  %51 = const_ty([1]@Vector(8, u1))
  %53 = const_ty(*[1]@Vector(8, u1))
  %55 = constant(usize, 0)
  %56 = const_ty(*@Vector(8, u1))
  %58 = constant(comptime_int, 8)
  %59 = constant(u1, 1)
  %60 = constant(u32, 8)
  %61 = const_ty(@Vector(8, u1))
  %62 = constant(@Vector(8, u1), .{ 1, 1, 1, 1, 1, 1, 1, 1 })
  %63 = const_ty(@Vector(8, u1))
  %65 = const_ty([1]@Vector(8, u1))
  %66 = constant([1]@Vector(8, u1), .{ .{ 1, 1, 1, 1, 1, 1, 1, 1 } })
  %67 = const_ty([1]@Vector(8, u1))
  %69 = const_ty([1]@Vector(8, u1))
  %71 = const_ty([1]@Vector(8, u1))
  %73 = constant(usize, 0)
  %75 = constant(comptime_int, 5)
  %76 = constant(usize, 5)
  %78 = const_ty(u1)
  %79 = constant(u1, 1)
  %81 = const_ty(*const [24]u8)
  %82 = constant(*const [24]u8, "reached unreachable code")
  %83 = constant([]const u8, .{ 114, 101, 97, 99, 104, 101, 100, 32, 117, 110, 114, 101, 97, 99, 104, 97, 98, 108, 101, 32, 99, 111, 100, 101 })
  %84 = const_ty(*const type)
  %85 = constant(*const type, builtin.builtin)
  %86 = constant(type, builtin.builtin)
  %87 = const_ty(*const type)
  %88 = constant(*const type, builtin.builtin)
  %89 = constant(type, builtin.builtin)
  %90 = const_ty(builtin.StackTrace)
  %91 = const_ty(?*builtin.StackTrace)
  %92 = constant(?*builtin.StackTrace, null)
  %96 = constant(anyerror!void, {})

  %1 = alloc(*@Vector(8, u1))
  %8!= bitcast(*@Vector(8, u1), %1)
  %10!= store(%1, %6!)
  %12!= block(void, {
    %14 = load(@Vector(8, u1), %1!)
    %17 = array_elem_val(%14!, %16!)
    %20 = cmp_neq(%17!, %19!)
    %42!= cond_br(%20!, {
      %40!= call(%30, [%23!, %39!])
    }, {
      %23! %39!
      %41!= br(%12, @Zir.Inst.Ref.void_value)
    })
  })
  %44 = alloc(*[1]@Vector(8, u1))
  %54 = bitcast(*[1]@Vector(8, u1), %44)
  %68!= store(%54!, %66!)
  %70!= block(void, {
    %72 = load([1]@Vector(8, u1), %44!)
    %74 = array_elem_val(%72!, %73!)
    %77 = array_elem_val(%74!, %76!)
    %80 = cmp_neq(%77!, %79!)
    %95!= cond_br(%80!, {
      %93!= call(%30!, [%83!, %92!])
    }, {
      %30! %92! %83!
      %94!= br(%70, @Zir.Inst.Ref.void_value)
    })
  })
  %97!= ret(%96!)
# End Function AIR: vec.main

@xxxbxxx
Copy link
Contributor Author

xxxbxxx commented Jun 19, 2022

simplification:

var ggg : @Vector(8, u1) = @splat(8, @as(u1, 1));
pub fn main() anyerror!void {
    if (ggg[5] != 1) unreachable;
}
@vec.ggg = internal unnamed_addr global <8 x i1> <i1 true, i1 true, i1 true, i1 true, i1 true, i1 true, i1 true, i1 true>, align 16

; Function Attrs: nounwind
define internal fastcc i16 @vec.main() unnamed_addr #0 {
Entry:
  %0 = load <8 x i1>, <8 x i1>* @vec.ggg, align 16
  %1 = extractelement <8 x i1> %0, i64 5
  %2 = icmp ne i1 %1, true
  br i1 %2, label %Then, label %Else

Then:                                             ; preds = %Entry
  call fastcc void @builtin.default_panic(i8* getelementptr inbounds ([24 x i8], [24 x i8]* @vec.main__anon_3591, i32 0, i32 0), i64 24, %builtin.StackTrace* null)
  unreachable

Else:                                             ; preds = %Entry
  br label %Block

Block:                                            ; preds = %Else
  ret i16 0
}

is this an unexpected llvm behaviour? looks like the memory layout is not as documented here:
https://llvm.org/docs/LangRef.html#vector-type

@andrewrk andrewrk added this to the 0.10.0 milestone Jun 28, 2022
@andrewrk andrewrk added frontend Tokenization, parsing, AstGen, Sema, and Liveness. backend-llvm The LLVM backend outputs an LLVM IR Module. miscompilation The compiler reports success but produces semantically incorrect code. labels Jun 28, 2022
@andrewrk andrewrk modified the milestones: 0.10.0, 0.10.1 Aug 23, 2022
@andrewrk
Copy link
Member

andrewrk commented Aug 23, 2022

This is what I get locally for the original test case:

[nix-shell:~/dev/zig/build-release]$ stage2/bin/zig build-exe test.zig 
LLD Link... ld.lld: error: test.o:(function _start: .text+0x2aa): relocation R_X86_64_32S out of range: 4297392128 is not in [-2147483648, 2147483647]
>>> referenced by start.zig:266 (/home/andy/dev/zig/lib/std/start.zig:266)

ld.lld: error: test.o:(function start.posixCallMainAndExit: .text+0x2fb): relocation R_X86_64_32S out of range: 4297392128 is not in [-2147483648, 2147483647]
>>> referenced by start.zig:365 (/home/andy/dev/zig/lib/std/start.zig:365)

ld.lld: error: test.o:(function start.posixCallMainAndExit: .text+0x30e): relocation R_X86_64_32S out of range: 4297392128 is not in [-2147483648, 2147483647]
>>> referenced by start.zig:366 (/home/andy/dev/zig/lib/std/start.zig:366)

ld.lld: error: test.o:(function start.posixCallMainAndExit: .text+0x566): relocation R_X86_64_32S out of range: 4297392136 is not in [-2147483648, 2147483647]
>>> referenced by start.zig:376 (/home/andy/dev/zig/lib/std/start.zig:376)

ld.lld: error: test.o:(function start.posixCallMainAndExit: .text+0x908): relocation R_X86_64_PC32 out of range: -4295014916 is not in [-2147483648, 2147483647]
>>> referenced by start.zig:575 (/home/andy/dev/zig/lib/std/start.zig:575)

ld.lld: error: test.o:(function debug.panicImpl: .text+0xaf2): relocation R_X86_64_32 out of range: 4297392180 is not in [0, 4294967295]
>>> referenced by debug.zig:345 (/home/andy/dev/zig/lib/std/debug.zig:345)

ld.lld: error: test.o:(function os.linux.tls.initStaticTLS: .text+0xbc8): relocation R_X86_64_32S out of range: 4297392208 is not in [-2147483648, 2147483647]
>>> referenced by tls.zig:315 (/home/andy/dev/zig/lib/std/os/linux/tls.zig:315)

... and a whole lot more...

@xxxbxxx
Copy link
Contributor Author

xxxbxxx commented Oct 8, 2022

fixed in master, both stage1 & stage2. (probably from llvm15)

@xxxbxxx xxxbxxx closed this as completed Oct 8, 2022
@nektro
Copy link
Contributor

nektro commented Oct 9, 2022

should be left open unless you're aware of regression test coverage for this

xxxbxxx added a commit to xxxbxxx/zig that referenced this issue Oct 9, 2022
@andrewrk andrewrk modified the milestones: 0.10.1, 0.10.0 Oct 12, 2022
xxxbxxx added a commit to xxxbxxx/zig that referenced this issue Oct 15, 2022
xxxbxxx added a commit to xxxbxxx/zig that referenced this issue Oct 16, 2022
xxxbxxx added a commit to xxxbxxx/zig that referenced this issue Oct 16, 2022
xxxbxxx added a commit to xxxbxxx/zig that referenced this issue Oct 16, 2022
xxxbxxx added a commit to xxxbxxx/zig that referenced this issue Oct 20, 2022
xxxbxxx added a commit to xxxbxxx/zig that referenced this issue Mar 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend-llvm The LLVM backend outputs an LLVM IR Module. bug Observed behavior contradicts documented or intended behavior frontend Tokenization, parsing, AstGen, Sema, and Liveness. miscompilation The compiler reports success but produces semantically incorrect code.
Projects
None yet
Development

No branches or pull requests

3 participants