| 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 | 1361 | .val = field_val, |
| 1362 | 1362 | }); |
| 1363 | 1363 | const ty_bit_size = @intCast(u16, field.ty.bitSize(target)); |
| 1364 | const llvm_int_ty = dg.context.intType(ty_bit_size); | |
| 1365 | const int_val = non_int_val.constBitCast(llvm_int_ty); | |
| 1366 | const shift_rhs = llvm_int_ty.constInt(running_bits, .False); | |
| 1367 | const shifted = int_val.constShl(shift_rhs); | |
| 1364 | const small_int_ty = dg.context.intType(ty_bit_size); | |
| 1365 | const small_int_val = non_int_val.constBitCast(small_int_ty); | |
| 1366 | const big_int_ty = running_int.typeOf(); | |
| 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 | 1370 | running_int = running_int.constOr(shifted); |
| 1369 | 1371 | running_bits += ty_bit_size; |
| 1370 | 1372 | } else { |
src/codegen/llvm/bindings.zig+5| ... | ... | @@ -201,6 +201,11 @@ pub const Value = opaque { |
| 201 | 201 | |
| 202 | 202 | pub const addCase = LLVMAddCase; |
| 203 | 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 | 211 | pub const Type = opaque { |
test/behavior.zig+1-1| ... | ... | @@ -21,7 +21,7 @@ test { |
| 21 | 21 | _ = @import("behavior/usingnamespace.zig"); |
| 22 | 22 | |
| 23 | 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 | 25 | _ = @import("behavior/align.zig"); |
| 26 | 26 | _ = @import("behavior/bool.zig"); |
| 27 | 27 | _ = @import("behavior/bugs/704.zig"); |
test/behavior/enum_llvm.zig+43| ... | ... | @@ -47,3 +47,46 @@ test "enum literal casting to optional" { |
| 47 | 47 | |
| 48 | 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 | 2 | const mem = @import("std").mem; |
| 3 | 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 | 5 | const EnumWithOneMember = enum { Eof }; |
| 63 | 6 | |
| 64 | 7 | fn doALoopThing(id: EnumWithOneMember) void { |