authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-12-27 16:59:26-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-12-27 16:59:26-07:00
log886df772f06377df95f867e8b18ee47bbd0fcd8b
treed8224b85c2b1691abf4ce669fce4b0aa0fc9e933
parent3abe464b06ab7d75954abda18dc41bf7af4a3839

stage2: LLVM backend: fix const packed structs

When doing LLVM const bit shifting we must make sure the integer bit sizes are wide enough or else LLVM gives us a poison result.

5 files changed, 55 insertions(+), 62 deletions(-)

src/codegen/llvm.zig+6-4
...@@ -1361,10 +1361,12 @@ pub const DeclGen = struct {...@@ -1361,10 +1361,12 @@ pub const DeclGen = struct {
1361 .val = field_val,1361 .val = field_val,
1362 });1362 });
1363 const ty_bit_size = @intCast(u16, field.ty.bitSize(target));1363 const ty_bit_size = @intCast(u16, field.ty.bitSize(target));
1364 const llvm_int_ty = dg.context.intType(ty_bit_size);1364 const small_int_ty = dg.context.intType(ty_bit_size);
1365 const int_val = non_int_val.constBitCast(llvm_int_ty);1365 const small_int_val = non_int_val.constBitCast(small_int_ty);
1366 const shift_rhs = llvm_int_ty.constInt(running_bits, .False);1366 const big_int_ty = running_int.typeOf();
1367 const shifted = int_val.constShl(shift_rhs);1367 const shift_rhs = big_int_ty.constInt(running_bits, .False);
1368 const extended_int_val = small_int_val.constZExt(big_int_ty);
1369 const shifted = extended_int_val.constShl(shift_rhs);
1368 running_int = running_int.constOr(shifted);1370 running_int = running_int.constOr(shifted);
1369 running_bits += ty_bit_size;1371 running_bits += ty_bit_size;
1370 } else {1372 } else {
src/codegen/llvm/bindings.zig+5
...@@ -201,6 +201,11 @@ pub const Value = opaque {...@@ -201,6 +201,11 @@ pub const Value = opaque {
201201
202 pub const addCase = LLVMAddCase;202 pub const addCase = LLVMAddCase;
203 extern fn LLVMAddCase(Switch: *const Value, OnVal: *const Value, Dest: *const BasicBlock) void;203 extern fn LLVMAddCase(Switch: *const Value, OnVal: *const Value, Dest: *const BasicBlock) void;
204
205 pub inline fn isPoison(Val: *const Value) bool {
206 return LLVMIsPoison(Val).toBool();
207 }
208 extern fn LLVMIsPoison(Val: *const Value) Bool;
204};209};
205210
206pub const Type = opaque {211pub const Type = opaque {
test/behavior.zig+1-1
...@@ -21,7 +21,7 @@ test {...@@ -21,7 +21,7 @@ test {
21 _ = @import("behavior/usingnamespace.zig");21 _ = @import("behavior/usingnamespace.zig");
2222
23 // Tests that pass for stage1, stage2 and the C backend, but not for the wasm backend23 // Tests that pass for stage1, stage2 and the C backend, but not for the wasm backend
24 if (!builtin.zig_is_stage2 or (builtin.zig_is_stage2 and builtin.stage2_arch != .wasm32)) {24 if (!builtin.zig_is_stage2 or builtin.stage2_arch != .wasm32) {
25 _ = @import("behavior/align.zig");25 _ = @import("behavior/align.zig");
26 _ = @import("behavior/bool.zig");26 _ = @import("behavior/bool.zig");
27 _ = @import("behavior/bugs/704.zig");27 _ = @import("behavior/bugs/704.zig");
test/behavior/enum_llvm.zig+43
...@@ -47,3 +47,46 @@ test "enum literal casting to optional" {...@@ -47,3 +47,46 @@ test "enum literal casting to optional" {
4747
48 try expect(bar.? == Bar.B);48 try expect(bar.? == Bar.B);
49}49}
50
51const A = enum(u3) { One, Two, Three, Four, One2, Two2, Three2, Four2 };
52const B = enum(u3) { One3, Two3, Three3, Four3, One23, Two23, Three23, Four23 };
53const C = enum(u2) { One4, Two4, Three4, Four4 };
54
55const BitFieldOfEnums = packed struct {
56 a: A,
57 b: B,
58 c: C,
59};
60
61const bit_field_1 = BitFieldOfEnums{
62 .a = A.Two,
63 .b = B.Three3,
64 .c = C.Four4,
65};
66
67test "bit field access with enum fields" {
68 var data = bit_field_1;
69 try expect(getA(&data) == A.Two);
70 try expect(getB(&data) == B.Three3);
71 try expect(getC(&data) == C.Four4);
72 comptime try expect(@sizeOf(BitFieldOfEnums) == 1);
73
74 data.b = B.Four3;
75 try expect(data.b == B.Four3);
76
77 data.a = A.Three;
78 try expect(data.a == A.Three);
79 try expect(data.b == B.Four3);
80}
81
82fn getA(data: *const BitFieldOfEnums) A {
83 return data.a;
84}
85
86fn getB(data: *const BitFieldOfEnums) B {
87 return data.b;
88}
89
90fn getC(data: *const BitFieldOfEnums) C {
91 return data.c;
92}
test/behavior/enum_stage1.zig-57
...@@ -2,63 +2,6 @@ const expect = @import("std").testing.expect;...@@ -2,63 +2,6 @@ const expect = @import("std").testing.expect;
2const mem = @import("std").mem;2const mem = @import("std").mem;
3const Tag = @import("std").meta.Tag;3const Tag = @import("std").meta.Tag;
44
5const Small2 = enum(u2) { One, Two };
6
7const A = enum(u3) { One, Two, Three, Four, One2, Two2, Three2, Four2 };
8const B = enum(u3) { One3, Two3, Three3, Four3, One23, Two23, Three23, Four23 };
9const C = enum(u2) { One4, Two4, Three4, Four4 };
10
11const BitFieldOfEnums = packed struct {
12 a: A,
13 b: B,
14 c: C,
15};
16
17const bit_field_1 = BitFieldOfEnums{
18 .a = A.Two,
19 .b = B.Three3,
20 .c = C.Four4,
21};
22
23test "bit field access with enum fields" {
24 var data = bit_field_1;
25 try expect(getA(&data) == A.Two);
26 try expect(getB(&data) == B.Three3);
27 try expect(getC(&data) == C.Four4);
28 comptime try expect(@sizeOf(BitFieldOfEnums) == 1);
29
30 data.b = B.Four3;
31 try expect(data.b == B.Four3);
32
33 data.a = A.Three;
34 try expect(data.a == A.Three);
35 try expect(data.b == B.Four3);
36}
37
38fn getA(data: *const BitFieldOfEnums) A {
39 return data.a;
40}
41
42fn getB(data: *const BitFieldOfEnums) B {
43 return data.b;
44}
45
46fn getC(data: *const BitFieldOfEnums) C {
47 return data.c;
48}
49
50const MultipleChoice2 = enum(u32) {
51 Unspecified1,
52 A = 20,
53 Unspecified2,
54 B = 40,
55 Unspecified3,
56 C = 60,
57 Unspecified4,
58 D = 1000,
59 Unspecified5,
60};
61
62const EnumWithOneMember = enum { Eof };5const EnumWithOneMember = enum { Eof };
636
64fn doALoopThing(id: EnumWithOneMember) void {7fn doALoopThing(id: EnumWithOneMember) void {