| author | |
| committer | |
| log | 886df772f06377df95f867e8b18ee47bbd0fcd8b |
| tree | d8224b85c2b1691abf4ce669fce4b0aa0fc9e933 |
| parent | 3abe464b06ab7d75954abda18dc41bf7af4a3839 |
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 { |
| 201 | 201 | ||
| 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 | }; |
| 205 | 210 | ||
| 206 | pub const Type = opaque { | 211 | pub 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"); |
| 22 | 22 | ||
| 23 | // Tests that pass for stage1, stage2 and the C backend, but not for the wasm backend | 23 | // 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" { |
| 47 | 47 | ||
| 48 | try expect(bar.? == Bar.B); | 48 | try expect(bar.? == Bar.B); |
| 49 | } | 49 | } |
| 50 | |||
| 51 | const A = enum(u3) { One, Two, Three, Four, One2, Two2, Three2, Four2 }; | ||
| 52 | const B = enum(u3) { One3, Two3, Three3, Four3, One23, Two23, Three23, Four23 }; | ||
| 53 | const C = enum(u2) { One4, Two4, Three4, Four4 }; | ||
| 54 | |||
| 55 | const BitFieldOfEnums = packed struct { | ||
| 56 | a: A, | ||
| 57 | b: B, | ||
| 58 | c: C, | ||
| 59 | }; | ||
| 60 | |||
| 61 | const bit_field_1 = BitFieldOfEnums{ | ||
| 62 | .a = A.Two, | ||
| 63 | .b = B.Three3, | ||
| 64 | .c = C.Four4, | ||
| 65 | }; | ||
| 66 | |||
| 67 | test "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 | |||
| 82 | fn getA(data: *const BitFieldOfEnums) A { | ||
| 83 | return data.a; | ||
| 84 | } | ||
| 85 | |||
| 86 | fn getB(data: *const BitFieldOfEnums) B { | ||
| 87 | return data.b; | ||
| 88 | } | ||
| 89 | |||
| 90 | fn 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; |
| 2 | const mem = @import("std").mem; | 2 | const mem = @import("std").mem; |
| 3 | const Tag = @import("std").meta.Tag; | 3 | const Tag = @import("std").meta.Tag; |
| 4 | 4 | ||
| 5 | const Small2 = enum(u2) { One, Two }; | ||
| 6 | |||
| 7 | const A = enum(u3) { One, Two, Three, Four, One2, Two2, Three2, Four2 }; | ||
| 8 | const B = enum(u3) { One3, Two3, Three3, Four3, One23, Two23, Three23, Four23 }; | ||
| 9 | const C = enum(u2) { One4, Two4, Three4, Four4 }; | ||
| 10 | |||
| 11 | const BitFieldOfEnums = packed struct { | ||
| 12 | a: A, | ||
| 13 | b: B, | ||
| 14 | c: C, | ||
| 15 | }; | ||
| 16 | |||
| 17 | const bit_field_1 = BitFieldOfEnums{ | ||
| 18 | .a = A.Two, | ||
| 19 | .b = B.Three3, | ||
| 20 | .c = C.Four4, | ||
| 21 | }; | ||
| 22 | |||
| 23 | test "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 | |||
| 38 | fn getA(data: *const BitFieldOfEnums) A { | ||
| 39 | return data.a; | ||
| 40 | } | ||
| 41 | |||
| 42 | fn getB(data: *const BitFieldOfEnums) B { | ||
| 43 | return data.b; | ||
| 44 | } | ||
| 45 | |||
| 46 | fn getC(data: *const BitFieldOfEnums) C { | ||
| 47 | return data.c; | ||
| 48 | } | ||
| 49 | |||
| 50 | const 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 | |||
| 62 | const EnumWithOneMember = enum { Eof }; | 5 | const EnumWithOneMember = enum { Eof }; |
| 63 | 6 | ||
| 64 | fn doALoopThing(id: EnumWithOneMember) void { | 7 | fn doALoopThing(id: EnumWithOneMember) void { |