authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-12-27 13:57:49-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-12-27 13:57:49-05:00
log19056cb6821dd03612628e9220595576878aafe7
treeb0e4bc3588abf86e55d343843f77bb891bc816da
parent55c3efcb58cc153fc3109a61c6949e470b57b81e
parenta777373bb8d6fd94b54d63f124b7346163b39045
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #14024 from Vexu/overflow-arithmetic

Make overflow arithmetic builtins return tuples

40 files changed, 700 insertions(+), 612 deletions(-)

doc/langref.html.in+26-32
......@@ -5413,14 +5413,14 @@ pub fn parseU64(buf: []const u8, radix: u8) !u64 {
54135413 }
54145414
54155415 // x *= radix
5416 if (@mulWithOverflow(u64, x, radix, &x)) {
5417 return error.Overflow;
5418 }
5416 var ov = @mulWithOverflow(x, radix);
5417 if (ov[1] != 0) return error.OverFlow;
5418
54195419
54205420 // x += digit
5421 if (@addWithOverflow(u64, x, digit, &x)) {
5422 return error.Overflow;
5423 }
5421 ov = @addWithOverflow(ov[0], digit);
5422 if (ov[1] != 0) return error.OverFlow;
5423 x = ov[0];
54245424 }
54255425
54265426 return x;
......@@ -5832,14 +5832,16 @@ test "merge error sets" {
58325832{#code_begin|test|inferred_error_sets#}
58335833// With an inferred error set
58345834pub fn add_inferred(comptime T: type, a: T, b: T) !T {
5835 var answer: T = undefined;
5836 return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
5835 const ov = @addWithOverflow(a, b);
5836 if (ov[1] != 0) return error.Overflow;
5837 return ov[0];
58375838}
58385839
58395840// With an explicit error set
58405841pub fn add_explicit(comptime T: type, a: T, b: T) Error!T {
5841 var answer: T = undefined;
5842 return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
5842 const ov = @addWithOverflow(a, b);
5843 if (ov[1] != 0) return error.Overflow;
5844 return ov[0];
58435845}
58445846
58455847const Error = error {
......@@ -7632,11 +7634,9 @@ test "global assembly" {
76327634 </p>
76337635 {#header_close#}
76347636 {#header_open|@addWithOverflow#}
7635 <pre>{#syntax#}@addWithOverflow(comptime T: type, a: T, b: T, result: *T) bool{#endsyntax#}</pre>
7637 <pre>{#syntax#}@addWithOverflow(a: anytype, b: anytype) struct { @TypeOf(a, b), u1 }{#endsyntax#}</pre>
76367638 <p>
7637 Performs {#syntax#}result.* = a + b{#endsyntax#}. If overflow or underflow occurs,
7638 stores the overflowed bits in {#syntax#}result{#endsyntax#} and returns {#syntax#}true{#endsyntax#}.
7639 If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.
7639 Performs {#syntax#}a + b{#endsyntax#} and returns a tuple with the result and a possible overflow bit.
76407640 </p>
76417641 {#header_close#}
76427642 {#header_open|@alignCast#}
......@@ -8695,11 +8695,9 @@ test "@wasmMemoryGrow" {
86958695 {#header_close#}
86968696
86978697 {#header_open|@mulWithOverflow#}
8698 <pre>{#syntax#}@mulWithOverflow(comptime T: type, a: T, b: T, result: *T) bool{#endsyntax#}</pre>
8698 <pre>{#syntax#}@mulWithOverflow(a: anytype, b: anytype) struct { @TypeOf(a, b), u1 }{#endsyntax#}</pre>
86998699 <p>
8700 Performs {#syntax#}result.* = a * b{#endsyntax#}. If overflow or underflow occurs,
8701 stores the overflowed bits in {#syntax#}result{#endsyntax#} and returns {#syntax#}true{#endsyntax#}.
8702 If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.
8700 Performs {#syntax#}a * b{#endsyntax#} and returns a tuple with the result and a possible overflow bit.
87038701 </p>
87048702 {#header_close#}
87058703
......@@ -8973,15 +8971,13 @@ test "@setRuntimeSafety" {
89738971 {#header_close#}
89748972
89758973 {#header_open|@shlWithOverflow#}
8976 <pre>{#syntax#}@shlWithOverflow(comptime T: type, a: T, shift_amt: Log2T, result: *T) bool{#endsyntax#}</pre>
8974 <pre>{#syntax#}@shlWithOverflow(a: anytype, shift_amt: Log2T) struct { @TypeOf(a), u1 }{#endsyntax#}</pre>
89778975 <p>
8978 Performs {#syntax#}result.* = a << b{#endsyntax#}. If overflow or underflow occurs,
8979 stores the overflowed bits in {#syntax#}result{#endsyntax#} and returns {#syntax#}true{#endsyntax#}.
8980 If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.
8976 Performs {#syntax#}a << b{#endsyntax#} and returns a tuple with the result and a possible overflow bit.
89818977 </p>
89828978 <p>
8983 The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(@typeInfo(T).Int.bits){#endsyntax#} bits.
8984 This is because {#syntax#}shift_amt >= @typeInfo(T).Int.bits{#endsyntax#} is undefined behavior.
8979 The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(@typeInfo(@TypeOf(a)).Int.bits){#endsyntax#} bits.
8980 This is because {#syntax#}shift_amt >= @typeInfo(@TypeOf(a)).Int.bits{#endsyntax#} is undefined behavior.
89858981 </p>
89868982 {#see_also|@shlExact|@shrExact#}
89878983 {#header_close#}
......@@ -9323,11 +9319,9 @@ fn doTheTest() !void {
93239319 {#header_close#}
93249320
93259321 {#header_open|@subWithOverflow#}
9326 <pre>{#syntax#}@subWithOverflow(comptime T: type, a: T, b: T, result: *T) bool{#endsyntax#}</pre>
9322 <pre>{#syntax#}@subWithOverflow(a: anytype, b: anytype) struct { @TypeOf(a, b), u1 }{#endsyntax#}</pre>
93279323 <p>
9328 Performs {#syntax#}result.* = a - b{#endsyntax#}. If overflow or underflow occurs,
9329 stores the overflowed bits in {#syntax#}result{#endsyntax#} and returns {#syntax#}true{#endsyntax#}.
9330 If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.
9324 Performs {#syntax#}a - b{#endsyntax#} and returns a tuple with the result and a possible overflow bit.
93319325 </p>
93329326 {#header_close#}
93339327
......@@ -9774,11 +9768,11 @@ const print = @import("std").debug.print;
97749768pub fn main() void {
97759769 var byte: u8 = 255;
97769770
9777 var result: u8 = undefined;
9778 if (@addWithOverflow(u8, byte, 10, &result)) {
9779 print("overflowed result: {}\n", .{result});
9771 const ov = @addWithOverflow(byte, 10);
9772 if (ov[1] != 0) {
9773 print("overflowed result: {}\n", .{ov[0]});
97809774 } else {
9781 print("result: {}\n", .{result});
9775 print("result: {}\n", .{ov[0]});
97829776 }
97839777}
97849778 {#code_end#}
lib/compiler_rt/trunctfxf2.zig+8-6
......@@ -49,14 +49,16 @@ pub fn __trunctfxf2(a: f128) callconv(.C) f80 {
4949 const round_bits = a_abs & round_mask;
5050 if (round_bits > halfway) {
5151 // Round to nearest
52 const carry = @boolToInt(@addWithOverflow(u64, res.fraction, 1, &res.fraction));
53 res.exp += carry;
54 res.fraction |= @as(u64, carry) << 63; // Restore integer bit after carry
52 const ov = @addWithOverflow(res.fraction, 1);
53 res.fraction = ov[0];
54 res.exp += ov[1];
55 res.fraction |= @as(u64, ov[1]) << 63; // Restore integer bit after carry
5556 } else if (round_bits == halfway) {
5657 // Ties to even
57 const carry = @boolToInt(@addWithOverflow(u64, res.fraction, res.fraction & 1, &res.fraction));
58 res.exp += carry;
59 res.fraction |= @as(u64, carry) << 63; // Restore integer bit after carry
58 const ov = @addWithOverflow(res.fraction, res.fraction & 1);
59 res.fraction = ov[0];
60 res.exp += ov[1];
61 res.fraction |= @as(u64, ov[1]) << 63; // Restore integer bit after carry
6062 }
6163 if (res.exp == 0) res.fraction &= ~@as(u64, integer_bit); // Remove integer bit for de-normals
6264 }
lib/std/compress/deflate/compressor_test.zig+1-3
......@@ -172,9 +172,7 @@ test "deflate/inflate" {
172172 defer testing.allocator.free(large_data_chunk);
173173 // fill with random data
174174 for (large_data_chunk) |_, i| {
175 var mul: u8 = @truncate(u8, i);
176 _ = @mulWithOverflow(u8, mul, mul, &mul);
177 large_data_chunk[i] = mul;
175 large_data_chunk[i] = @truncate(u8, i) *% @truncate(u8, i);
178176 }
179177 try testToFromWithLimit(large_data_chunk, limits);
180178}
lib/std/crypto/pcurves/p256/p256_64.zig+8-8
......@@ -75,10 +75,10 @@ pub const NonMontgomeryDomainFieldElement = [4]u64;
7575inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
7676 @setRuntimeSafety(mode == .Debug);
7777
78 var t: u64 = undefined;
79 const carry1 = @addWithOverflow(u64, arg2, arg3, &t);
80 const carry2 = @addWithOverflow(u64, t, arg1, out1);
81 out2.* = @boolToInt(carry1) | @boolToInt(carry2);
78 const ov1 = @addWithOverflow(arg2, arg3);
79 const ov2 = @addWithOverflow(ov1[0], arg1);
80 out1.* = ov2[0];
81 out2.* = ov1[1] | ov2[1];
8282}
8383
8484/// The function subborrowxU64 is a subtraction with borrow.
......@@ -97,10 +97,10 @@ inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) vo
9797inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
9898 @setRuntimeSafety(mode == .Debug);
9999
100 var t: u64 = undefined;
101 const carry1 = @subWithOverflow(u64, arg2, arg3, &t);
102 const carry2 = @subWithOverflow(u64, t, arg1, out1);
103 out2.* = @boolToInt(carry1) | @boolToInt(carry2);
100 const ov1 = @subWithOverflow(arg2, arg3);
101 const ov2 = @subWithOverflow(ov1[0], arg1);
102 out1.* = ov2[0];
103 out2.* = ov1[1] | ov2[1];
104104}
105105
106106/// The function mulxU64 is a multiplication, returning the full double-width result.
lib/std/crypto/pcurves/p256/p256_scalar_64.zig+8-8
......@@ -75,10 +75,10 @@ pub const NonMontgomeryDomainFieldElement = [4]u64;
7575inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
7676 @setRuntimeSafety(mode == .Debug);
7777
78 var t: u64 = undefined;
79 const carry1 = @addWithOverflow(u64, arg2, arg3, &t);
80 const carry2 = @addWithOverflow(u64, t, arg1, out1);
81 out2.* = @boolToInt(carry1) | @boolToInt(carry2);
78 const ov1 = @addWithOverflow(arg2, arg3);
79 const ov2 = @addWithOverflow(ov1[0], arg1);
80 out1.* = ov2[0];
81 out2.* = ov1[1] | ov2[1];
8282}
8383
8484/// The function subborrowxU64 is a subtraction with borrow.
......@@ -97,10 +97,10 @@ inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) vo
9797inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
9898 @setRuntimeSafety(mode == .Debug);
9999
100 var t: u64 = undefined;
101 const carry1 = @subWithOverflow(u64, arg2, arg3, &t);
102 const carry2 = @subWithOverflow(u64, t, arg1, out1);
103 out2.* = @boolToInt(carry1) | @boolToInt(carry2);
100 const ov1 = @subWithOverflow(arg2, arg3);
101 const ov2 = @subWithOverflow(ov1[0], arg1);
102 out1.* = ov2[0];
103 out2.* = ov1[1] | ov2[1];
104104}
105105
106106/// The function mulxU64 is a multiplication, returning the full double-width result.
lib/std/crypto/pcurves/p384/p384_64.zig+8-8
......@@ -44,10 +44,10 @@ pub const NonMontgomeryDomainFieldElement = [6]u64;
4444inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
4545 @setRuntimeSafety(mode == .Debug);
4646
47 var t: u64 = undefined;
48 const carry1 = @addWithOverflow(u64, arg2, arg3, &t);
49 const carry2 = @addWithOverflow(u64, t, arg1, out1);
50 out2.* = @boolToInt(carry1) | @boolToInt(carry2);
47 const ov1 = @addWithOverflow(arg2, arg3);
48 const ov2 = @addWithOverflow(ov1[0], arg1);
49 out1.* = ov2[0];
50 out2.* = ov1[1] | ov2[1];
5151}
5252
5353/// The function subborrowxU64 is a subtraction with borrow.
......@@ -66,10 +66,10 @@ inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) vo
6666inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
6767 @setRuntimeSafety(mode == .Debug);
6868
69 var t: u64 = undefined;
70 const carry1 = @subWithOverflow(u64, arg2, arg3, &t);
71 const carry2 = @subWithOverflow(u64, t, arg1, out1);
72 out2.* = @boolToInt(carry1) | @boolToInt(carry2);
69 const ov1 = @subWithOverflow(arg2, arg3);
70 const ov2 = @subWithOverflow(ov1[0], arg1);
71 out1.* = ov2[0];
72 out2.* = ov1[1] | ov2[1];
7373}
7474
7575/// The function mulxU64 is a multiplication, returning the full double-width result.
lib/std/crypto/pcurves/p384/p384_scalar_64.zig+8-8
......@@ -44,10 +44,10 @@ pub const NonMontgomeryDomainFieldElement = [6]u64;
4444inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
4545 @setRuntimeSafety(mode == .Debug);
4646
47 var t: u64 = undefined;
48 const carry1 = @addWithOverflow(u64, arg2, arg3, &t);
49 const carry2 = @addWithOverflow(u64, t, arg1, out1);
50 out2.* = @boolToInt(carry1) | @boolToInt(carry2);
47 const ov1 = @addWithOverflow(arg2, arg3);
48 const ov2 = @addWithOverflow(ov1[0], arg1);
49 out1.* = ov2[0];
50 out2.* = ov1[1] | ov2[1];
5151}
5252
5353/// The function subborrowxU64 is a subtraction with borrow.
......@@ -66,10 +66,10 @@ inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) vo
6666inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
6767 @setRuntimeSafety(mode == .Debug);
6868
69 var t: u64 = undefined;
70 const carry1 = @subWithOverflow(u64, arg2, arg3, &t);
71 const carry2 = @subWithOverflow(u64, t, arg1, out1);
72 out2.* = @boolToInt(carry1) | @boolToInt(carry2);
69 const ov1 = @subWithOverflow(arg2, arg3);
70 const ov2 = @subWithOverflow(ov1[0], arg1);
71 out1.* = ov2[0];
72 out2.* = ov1[1] | ov2[1];
7373}
7474
7575/// The function mulxU64 is a multiplication, returning the full double-width result.
lib/std/crypto/pcurves/secp256k1/secp256k1_64.zig+8-8
......@@ -44,10 +44,10 @@ pub const NonMontgomeryDomainFieldElement = [4]u64;
4444inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
4545 @setRuntimeSafety(mode == .Debug);
4646
47 var t: u64 = undefined;
48 const carry1 = @addWithOverflow(u64, arg2, arg3, &t);
49 const carry2 = @addWithOverflow(u64, t, arg1, out1);
50 out2.* = @boolToInt(carry1) | @boolToInt(carry2);
47 const ov1 = @addWithOverflow(arg2, arg3);
48 const ov2 = @addWithOverflow(ov1[0], arg1);
49 out1.* = ov2[0];
50 out2.* = ov1[1] | ov2[1];
5151}
5252
5353/// The function subborrowxU64 is a subtraction with borrow.
......@@ -66,10 +66,10 @@ inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) vo
6666inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
6767 @setRuntimeSafety(mode == .Debug);
6868
69 var t: u64 = undefined;
70 const carry1 = @subWithOverflow(u64, arg2, arg3, &t);
71 const carry2 = @subWithOverflow(u64, t, arg1, out1);
72 out2.* = @boolToInt(carry1) | @boolToInt(carry2);
69 const ov1 = @subWithOverflow(arg2, arg3);
70 const ov2 = @subWithOverflow(ov1[0], arg1);
71 out1.* = ov2[0];
72 out2.* = ov1[1] | ov2[1];
7373}
7474
7575/// The function mulxU64 is a multiplication, returning the full double-width result.
lib/std/crypto/pcurves/secp256k1/secp256k1_scalar_64.zig+8-8
......@@ -44,10 +44,10 @@ pub const NonMontgomeryDomainFieldElement = [4]u64;
4444inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
4545 @setRuntimeSafety(mode == .Debug);
4646
47 var t: u64 = undefined;
48 const carry1 = @addWithOverflow(u64, arg2, arg3, &t);
49 const carry2 = @addWithOverflow(u64, t, arg1, out1);
50 out2.* = @boolToInt(carry1) | @boolToInt(carry2);
47 const ov1 = @addWithOverflow(arg2, arg3);
48 const ov2 = @addWithOverflow(ov1[0], arg1);
49 out1.* = ov2[0];
50 out2.* = ov1[1] | ov2[1];
5151}
5252
5353/// The function subborrowxU64 is a subtraction with borrow.
......@@ -66,10 +66,10 @@ inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) vo
6666inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
6767 @setRuntimeSafety(mode == .Debug);
6868
69 var t: u64 = undefined;
70 const carry1 = @subWithOverflow(u64, arg2, arg3, &t);
71 const carry2 = @subWithOverflow(u64, t, arg1, out1);
72 out2.* = @boolToInt(carry1) | @boolToInt(carry2);
69 const ov1 = @subWithOverflow(arg2, arg3);
70 const ov2 = @subWithOverflow(ov1[0], arg1);
71 out1.* = ov2[0];
72 out2.* = ov1[1] | ov2[1];
7373}
7474
7575/// The function mulxU64 is a multiplication, returning the full double-width result.
lib/std/crypto/salsa20.zig+3-1
......@@ -263,7 +263,9 @@ fn SalsaNonVecImpl(comptime rounds: comptime_int) type {
263263 while (j < 64) : (j += 1) {
264264 xout[j] ^= buf[j];
265265 }
266 ctx[9] += @boolToInt(@addWithOverflow(u32, ctx[8], 1, &ctx[8]));
266 const ov = @addWithOverflow(ctx[8], 1);
267 ctx[8] = ov[0];
268 ctx[9] += ov[1];
267269 }
268270 if (i < in.len) {
269271 salsaCore(x[0..], ctx, true);
lib/std/crypto/utils.zig+16-8
......@@ -87,15 +87,19 @@ pub fn timingSafeAdd(comptime T: type, a: []const T, b: []const T, result: []T,
8787 if (endian == .Little) {
8888 var i: usize = 0;
8989 while (i < len) : (i += 1) {
90 const tmp = @boolToInt(@addWithOverflow(u8, a[i], b[i], &result[i]));
91 carry = tmp | @boolToInt(@addWithOverflow(u8, result[i], carry, &result[i]));
90 const ov1 = @addWithOverflow(a[i], b[i]);
91 const ov2 = @addWithOverflow(ov1[0], carry);
92 result[i] = ov2[0];
93 carry = ov1[1] | ov2[1];
9294 }
9395 } else {
9496 var i: usize = len;
9597 while (i != 0) {
9698 i -= 1;
97 const tmp = @boolToInt(@addWithOverflow(u8, a[i], b[i], &result[i]));
98 carry = tmp | @boolToInt(@addWithOverflow(u8, result[i], carry, &result[i]));
99 const ov1 = @addWithOverflow(a[i], b[i]);
100 const ov2 = @addWithOverflow(ov1[0], carry);
101 result[i] = ov2[0];
102 carry = ov1[1] | ov2[1];
99103 }
100104 }
101105 return @bitCast(bool, carry);
......@@ -110,15 +114,19 @@ pub fn timingSafeSub(comptime T: type, a: []const T, b: []const T, result: []T,
110114 if (endian == .Little) {
111115 var i: usize = 0;
112116 while (i < len) : (i += 1) {
113 const tmp = @boolToInt(@subWithOverflow(u8, a[i], b[i], &result[i]));
114 borrow = tmp | @boolToInt(@subWithOverflow(u8, result[i], borrow, &result[i]));
117 const ov1 = @subWithOverflow(a[i], b[i]);
118 const ov2 = @subWithOverflow(ov1[0], borrow);
119 result[i] = ov2[0];
120 borrow = ov1[1] | ov2[1];
115121 }
116122 } else {
117123 var i: usize = len;
118124 while (i != 0) {
119125 i -= 1;
120 const tmp = @boolToInt(@subWithOverflow(u8, a[i], b[i], &result[i]));
121 borrow = tmp | @boolToInt(@subWithOverflow(u8, result[i], borrow, &result[i]));
126 const ov1 = @subWithOverflow(a[i], b[i]);
127 const ov2 = @subWithOverflow(ov1[0], borrow);
128 result[i] = ov2[0];
129 borrow = ov1[1] | ov2[1];
122130 }
123131 }
124132 return @bitCast(bool, borrow);
lib/std/heap.zig+1-1
......@@ -789,7 +789,7 @@ pub fn testAllocatorLargeAlignment(base_allocator: mem.Allocator) !void {
789789 const large_align: usize = mem.page_size / 2;
790790
791791 var align_mask: usize = undefined;
792 _ = @shlWithOverflow(usize, ~@as(usize, 0), @as(Allocator.Log2Align, @ctz(large_align)), &align_mask);
792 align_mask = @shlWithOverflow(~@as(usize, 0), @as(Allocator.Log2Align, @ctz(large_align)))[0];
793793
794794 var slice = try allocator.alignedAlloc(u8, large_align, 500);
795795 try testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
lib/std/leb128.zig+8-8
......@@ -15,11 +15,11 @@ pub fn readULEB128(comptime T: type, reader: anytype) !T {
1515
1616 while (group < max_group) : (group += 1) {
1717 const byte = try reader.readByte();
18 var temp = @as(U, byte & 0x7f);
1918
20 if (@shlWithOverflow(U, temp, group * 7, &temp)) return error.Overflow;
19 const ov = @shlWithOverflow(@as(U, byte & 0x7f), group * 7);
20 if (ov[1] != 0) return error.Overflow;
2121
22 value |= temp;
22 value |= ov[0];
2323 if (byte & 0x80 == 0) break;
2424 } else {
2525 return error.Overflow;
......@@ -65,13 +65,13 @@ pub fn readILEB128(comptime T: type, reader: anytype) !T {
6565
6666 while (group < max_group) : (group += 1) {
6767 const byte = try reader.readByte();
68 var temp = @as(U, byte & 0x7f);
6968
7069 const shift = group * 7;
71 if (@shlWithOverflow(U, temp, shift, &temp)) {
70 const ov = @shlWithOverflow(@as(U, byte & 0x7f), shift);
71 if (ov[1] != 0) {
7272 // Overflow is ok so long as the sign bit is set and this is the last byte
7373 if (byte & 0x80 != 0) return error.Overflow;
74 if (@bitCast(S, temp) >= 0) return error.Overflow;
74 if (@bitCast(S, ov[0]) >= 0) return error.Overflow;
7575
7676 // and all the overflowed bits are 1
7777 const remaining_shift = @intCast(u3, @typeInfo(U).Int.bits - @as(u16, shift));
......@@ -80,14 +80,14 @@ pub fn readILEB128(comptime T: type, reader: anytype) !T {
8080 } else {
8181 // If we don't overflow and this is the last byte and the number being decoded
8282 // is negative, check that the remaining bits are 1
83 if ((byte & 0x80 == 0) and (@bitCast(S, temp) < 0)) {
83 if ((byte & 0x80 == 0) and (@bitCast(S, ov[0]) < 0)) {
8484 const remaining_shift = @intCast(u3, @typeInfo(U).Int.bits - @as(u16, shift));
8585 const remaining_bits = @bitCast(i8, byte | 0x80) >> remaining_shift;
8686 if (remaining_bits != -1) return error.Overflow;
8787 }
8888 }
8989
90 value |= temp;
90 value |= ov[0];
9191 if (byte & 0x80 == 0) {
9292 const needs_sign_ext = group + 1 < max_group;
9393 if (byte & 0x40 != 0 and needs_sign_ext) {
lib/std/math.zig+15-8
......@@ -468,21 +468,26 @@ test "clamp" {
468468
469469/// Returns the product of a and b. Returns an error on overflow.
470470pub fn mul(comptime T: type, a: T, b: T) (error{Overflow}!T) {
471 var answer: T = undefined;
472 return if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer;
471 if (T == comptime_int) return a * b;
472 const ov = @mulWithOverflow(a, b);
473 if (ov[1] != 0) return error.Overflow;
474 return ov[0];
473475}
474476
475477/// Returns the sum of a and b. Returns an error on overflow.
476478pub fn add(comptime T: type, a: T, b: T) (error{Overflow}!T) {
477479 if (T == comptime_int) return a + b;
478 var answer: T = undefined;
479 return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
480 const ov = @addWithOverflow(a, b);
481 if (ov[1] != 0) return error.Overflow;
482 return ov[0];
480483}
481484
482485/// Returns a - b, or an error on overflow.
483486pub fn sub(comptime T: type, a: T, b: T) (error{Overflow}!T) {
484 var answer: T = undefined;
485 return if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer;
487 if (T == comptime_int) return a - b;
488 const ov = @subWithOverflow(a, b);
489 if (ov[1] != 0) return error.Overflow;
490 return ov[0];
486491}
487492
488493pub fn negate(x: anytype) !@TypeOf(x) {
......@@ -492,8 +497,10 @@ pub fn negate(x: anytype) !@TypeOf(x) {
492497/// Shifts a left by shift_amt. Returns an error on overflow. shift_amt
493498/// is unsigned.
494499pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T {
495 var answer: T = undefined;
496 return if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer;
500 if (T == comptime_int) return a << shift_amt;
501 const ov = @shlWithOverflow(a, shift_amt);
502 if (ov[1] != 0) return error.Overflow;
503 return ov[0];
497504}
498505
499506/// Shifts left. Overflowed bits are truncated.
lib/std/math/big/int.zig+117-83
......@@ -74,42 +74,40 @@ pub fn calcTwosCompLimbCount(bit_count: usize) usize {
7474/// a + b * c + *carry, sets carry to the overflow bits
7575pub fn addMulLimbWithCarry(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb {
7676 @setRuntimeSafety(debug_safety);
77 var r1: Limb = undefined;
7877
79 // r1 = a + *carry
80 const c1: Limb = @boolToInt(@addWithOverflow(Limb, a, carry.*, &r1));
78 // ov1[0] = a + *carry
79 const ov1 = @addWithOverflow(a, carry.*);
8180
8281 // r2 = b * c
8382 const bc = @as(DoubleLimb, math.mulWide(Limb, b, c));
8483 const r2 = @truncate(Limb, bc);
8584 const c2 = @truncate(Limb, bc >> limb_bits);
8685
87 // r1 = r1 + r2
88 const c3: Limb = @boolToInt(@addWithOverflow(Limb, r1, r2, &r1));
86 // ov2[0] = ov1[0] + r2
87 const ov2 = @addWithOverflow(ov1[0], r2);
8988
9089 // This never overflows, c1, c3 are either 0 or 1 and if both are 1 then
9190 // c2 is at least <= maxInt(Limb) - 2.
92 carry.* = c1 + c2 + c3;
91 carry.* = ov1[1] + c2 + ov2[1];
9392
94 return r1;
93 return ov2[0];
9594}
9695
9796/// a - b * c - *carry, sets carry to the overflow bits
9897fn subMulLimbWithBorrow(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb {
99 // r1 = a - *carry
100 var r1: Limb = undefined;
101 const c1: Limb = @boolToInt(@subWithOverflow(Limb, a, carry.*, &r1));
98 // ov1[0] = a - *carry
99 const ov1 = @subWithOverflow(a, carry.*);
102100
103101 // r2 = b * c
104102 const bc = @as(DoubleLimb, std.math.mulWide(Limb, b, c));
105103 const r2 = @truncate(Limb, bc);
106104 const c2 = @truncate(Limb, bc >> limb_bits);
107105
108 // r1 = r1 - r2
109 const c3: Limb = @boolToInt(@subWithOverflow(Limb, r1, r2, &r1));
110 carry.* = c1 + c2 + c3;
106 // ov2[0] = ov1[0] - r2
107 const ov2 = @subWithOverflow(ov1[0], r2);
108 carry.* = ov1[1] + c2 + ov2[1];
111109
112 return r1;
110 return ov2[0];
113111}
114112
115113/// Used to indicate either limit of a 2s-complement integer.
......@@ -673,7 +671,9 @@ pub const Mutable = struct {
673671 assert(rma.limbs.ptr != b.limbs.ptr); // illegal aliasing
674672
675673 if (a.limbs.len == 1 and b.limbs.len == 1) {
676 if (!@mulWithOverflow(Limb, a.limbs[0], b.limbs[0], &rma.limbs[0])) {
674 const ov = @mulWithOverflow(a.limbs[0], b.limbs[0]);
675 rma.limbs[0] = ov[0];
676 if (ov[1] == 0) {
677677 rma.len = 1;
678678 rma.positive = (a.positive == b.positive);
679679 return;
......@@ -1836,7 +1836,11 @@ pub const Mutable = struct {
18361836 bit_index += @bitSizeOf(Limb);
18371837
18381838 // 2's complement (bitwise not, then add carry bit)
1839 if (!positive) carry = @boolToInt(@addWithOverflow(Limb, ~limb, carry, &limb));
1839 if (!positive) {
1840 const ov = @addWithOverflow(~limb, carry);
1841 limb = ov[0];
1842 carry = ov[1];
1843 }
18401844 x.limbs[limb_index] = limb;
18411845 }
18421846
......@@ -1853,7 +1857,11 @@ pub const Mutable = struct {
18531857 };
18541858
18551859 // 2's complement (bitwise not, then add carry bit)
1856 if (!positive) assert(!@addWithOverflow(Limb, ~limb, carry, &limb));
1860 if (!positive) {
1861 const ov = @addWithOverflow(~limb, carry);
1862 assert(ov[1] == 0);
1863 limb = ov[0];
1864 }
18571865 x.limbs[limb_index] = limb;
18581866
18591867 limb_index += 1;
......@@ -2000,7 +2008,9 @@ pub const Const = struct {
20002008
20012009 // All but the most significant limb.
20022010 for (self.limbs[0 .. self.limbs.len - 1]) |limb| {
2003 carry = @boolToInt(@addWithOverflow(Limb, ~limb, carry, &add_res));
2011 const ov = @addWithOverflow(~limb, carry);
2012 add_res = ov[0];
2013 carry = ov[1];
20042014 sum += @popCount(add_res);
20052015 remaining_bits -= limb_bits; // Asserted not to undeflow by fitsInTwosComp
20062016 }
......@@ -2294,7 +2304,11 @@ pub const Const = struct {
22942304 var limb: Limb = if (limb_index < x.limbs.len) x.limbs[limb_index] else 0;
22952305
22962306 // 2's complement (bitwise not, then add carry bit)
2297 if (!x.positive) carry = @boolToInt(@addWithOverflow(Limb, ~limb, carry, &limb));
2307 if (!x.positive) {
2308 const ov = @addWithOverflow(~limb, carry);
2309 limb = ov[0];
2310 carry = ov[1];
2311 }
22982312
22992313 // Write one Limb of bits
23002314 mem.writePackedInt(Limb, bytes, bit_index + bit_offset, limb, endian);
......@@ -2306,7 +2320,7 @@ pub const Const = struct {
23062320 var limb: Limb = if (limb_index < x.limbs.len) x.limbs[limb_index] else 0;
23072321
23082322 // 2's complement (bitwise not, then add carry bit)
2309 if (!x.positive) _ = @addWithOverflow(Limb, ~limb, carry, &limb);
2323 if (!x.positive) limb = ~limb +% carry;
23102324
23112325 // Write all remaining bits
23122326 mem.writeVarPackedInt(bytes, bit_index + bit_offset, bit_count - bit_index, limb, endian);
......@@ -3360,14 +3374,17 @@ fn llaccum(comptime op: AccOp, r: []Limb, a: []const Limb) void {
33603374 var carry: Limb = 0;
33613375
33623376 while (i < a.len) : (i += 1) {
3363 var c: Limb = 0;
3364 c += @boolToInt(@addWithOverflow(Limb, r[i], a[i], &r[i]));
3365 c += @boolToInt(@addWithOverflow(Limb, r[i], carry, &r[i]));
3366 carry = c;
3377 const ov1 = @addWithOverflow(r[i], a[i]);
3378 r[i] = ov1[0];
3379 const ov2 = @addWithOverflow(r[i], carry);
3380 r[i] = ov2[0];
3381 carry = @as(Limb, ov1[1]) + ov2[1];
33673382 }
33683383
33693384 while ((carry != 0) and i < r.len) : (i += 1) {
3370 carry = @boolToInt(@addWithOverflow(Limb, r[i], carry, &r[i]));
3385 const ov = @addWithOverflow(r[i], carry);
3386 r[i] = ov[0];
3387 carry = ov[1];
33713388 }
33723389}
33733390
......@@ -3435,7 +3452,9 @@ fn llmulLimb(comptime op: AccOp, acc: []Limb, y: []const Limb, xi: Limb) bool {
34353452
34363453 j = 0;
34373454 while ((carry != 0) and (j < a_hi.len)) : (j += 1) {
3438 carry = @boolToInt(@addWithOverflow(Limb, a_hi[j], carry, &a_hi[j]));
3455 const ov = @addWithOverflow(a_hi[j], carry);
3456 a_hi[j] = ov[0];
3457 carry = ov[1];
34393458 }
34403459
34413460 return carry != 0;
......@@ -3449,7 +3468,9 @@ fn llmulLimb(comptime op: AccOp, acc: []Limb, y: []const Limb, xi: Limb) bool {
34493468
34503469 j = 0;
34513470 while ((borrow != 0) and (j < a_hi.len)) : (j += 1) {
3452 borrow = @boolToInt(@subWithOverflow(Limb, a_hi[j], borrow, &a_hi[j]));
3471 const ov = @subWithOverflow(a_hi[j], borrow);
3472 a_hi[j] = ov[0];
3473 borrow = ov[1];
34533474 }
34543475
34553476 return borrow != 0;
......@@ -3482,14 +3503,17 @@ fn llsubcarry(r: []Limb, a: []const Limb, b: []const Limb) Limb {
34823503 var borrow: Limb = 0;
34833504
34843505 while (i < b.len) : (i += 1) {
3485 var c: Limb = 0;
3486 c += @boolToInt(@subWithOverflow(Limb, a[i], b[i], &r[i]));
3487 c += @boolToInt(@subWithOverflow(Limb, r[i], borrow, &r[i]));
3488 borrow = c;
3506 const ov1 = @subWithOverflow(a[i], b[i]);
3507 r[i] = ov1[0];
3508 const ov2 = @subWithOverflow(r[i], borrow);
3509 r[i] = ov2[0];
3510 borrow = @as(Limb, ov1[1]) + ov2[1];
34893511 }
34903512
34913513 while (i < a.len) : (i += 1) {
3492 borrow = @boolToInt(@subWithOverflow(Limb, a[i], borrow, &r[i]));
3514 const ov = @subWithOverflow(a[i], borrow);
3515 r[i] = ov[0];
3516 borrow = ov[1];
34933517 }
34943518
34953519 return borrow;
......@@ -3512,14 +3536,17 @@ fn lladdcarry(r: []Limb, a: []const Limb, b: []const Limb) Limb {
35123536 var carry: Limb = 0;
35133537
35143538 while (i < b.len) : (i += 1) {
3515 var c: Limb = 0;
3516 c += @boolToInt(@addWithOverflow(Limb, a[i], b[i], &r[i]));
3517 c += @boolToInt(@addWithOverflow(Limb, r[i], carry, &r[i]));
3518 carry = c;
3539 const ov1 = @addWithOverflow(a[i], b[i]);
3540 r[i] = ov1[0];
3541 const ov2 = @addWithOverflow(r[i], carry);
3542 r[i] = ov2[0];
3543 carry = @as(Limb, ov1[1]) + ov2[1];
35193544 }
35203545
35213546 while (i < a.len) : (i += 1) {
3522 carry = @boolToInt(@addWithOverflow(Limb, a[i], carry, &r[i]));
3547 const ov = @addWithOverflow(a[i], carry);
3548 r[i] = ov[0];
3549 carry = ov[1];
35233550 }
35243551
35253552 return carry;
......@@ -3685,11 +3712,11 @@ fn llsignedor(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_p
36853712 var r_carry: u1 = 1;
36863713
36873714 while (i < b.len) : (i += 1) {
3688 var a_limb: Limb = undefined;
3689 a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &a_limb));
3690
3691 r[i] = a_limb & ~b[i];
3692 r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i]));
3715 const ov1 = @subWithOverflow(a[i], a_borrow);
3716 a_borrow = ov1[1];
3717 const ov2 = @addWithOverflow(ov1[0] & ~b[i], r_carry);
3718 r[i] = ov2[0];
3719 r_carry = ov2[1];
36933720 }
36943721
36953722 // In order for r_carry to be nonzero at this point, ~b[i] would need to be
......@@ -3702,7 +3729,9 @@ fn llsignedor(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_p
37023729 // Note, if a_borrow is zero we do not need to compute anything for
37033730 // the higher limbs so we can early return here.
37043731 while (i < a.len and a_borrow == 1) : (i += 1) {
3705 a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &r[i]));
3732 const ov = @subWithOverflow(a[i], a_borrow);
3733 r[i] = ov[0];
3734 a_borrow = ov[1];
37063735 }
37073736
37083737 assert(a_borrow == 0); // a was 0.
......@@ -3721,11 +3750,11 @@ fn llsignedor(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_p
37213750 var r_carry: u1 = 1;
37223751
37233752 while (i < b.len) : (i += 1) {
3724 var b_limb: Limb = undefined;
3725 b_borrow = @boolToInt(@subWithOverflow(Limb, b[i], b_borrow, &b_limb));
3726
3727 r[i] = ~a[i] & b_limb;
3728 r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i]));
3753 const ov1 = @subWithOverflow(b[i], b_borrow);
3754 b_borrow = ov1[1];
3755 const ov2 = @addWithOverflow(~a[i] & ov1[0], r_carry);
3756 r[i] = ov2[0];
3757 r_carry = ov2[1];
37293758 }
37303759
37313760 // b is at least 1, so this should never underflow.
......@@ -3752,14 +3781,13 @@ fn llsignedor(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_p
37523781 var r_carry: u1 = 1;
37533782
37543783 while (i < b.len) : (i += 1) {
3755 var a_limb: Limb = undefined;
3756 a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &a_limb));
3757
3758 var b_limb: Limb = undefined;
3759 b_borrow = @boolToInt(@subWithOverflow(Limb, b[i], b_borrow, &b_limb));
3760
3761 r[i] = a_limb & b_limb;
3762 r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i]));
3784 const ov1 = @subWithOverflow(a[i], a_borrow);
3785 a_borrow = ov1[1];
3786 const ov2 = @subWithOverflow(b[i], b_borrow);
3787 b_borrow = ov2[1];
3788 const ov3 = @addWithOverflow(ov1[0] & ov2[0], r_carry);
3789 r[i] = ov3[0];
3790 r_carry = ov3[1];
37633791 }
37643792
37653793 // b is at least 1, so this should never underflow.
......@@ -3811,9 +3839,9 @@ fn llsignedand(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_
38113839 var a_borrow: u1 = 1;
38123840
38133841 while (i < b.len) : (i += 1) {
3814 var a_limb: Limb = undefined;
3815 a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &a_limb));
3816 r[i] = ~a_limb & b[i];
3842 const ov = @subWithOverflow(a[i], a_borrow);
3843 a_borrow = ov[1];
3844 r[i] = ~ov[0] & b[i];
38173845 }
38183846
38193847 // With b = 0 we have ~(a - 1) & 0 = 0, so the upper bytes are zero.
......@@ -3830,9 +3858,9 @@ fn llsignedand(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_
38303858 var b_borrow: u1 = 1;
38313859
38323860 while (i < b.len) : (i += 1) {
3833 var a_limb: Limb = undefined;
3834 b_borrow = @boolToInt(@subWithOverflow(Limb, b[i], b_borrow, &a_limb));
3835 r[i] = a[i] & ~a_limb;
3861 const ov = @subWithOverflow(b[i], b_borrow);
3862 b_borrow = ov[1];
3863 r[i] = a[i] & ~ov[0];
38363864 }
38373865
38383866 assert(b_borrow == 0); // b was 0
......@@ -3855,14 +3883,13 @@ fn llsignedand(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_
38553883 var r_carry: u1 = 1;
38563884
38573885 while (i < b.len) : (i += 1) {
3858 var a_limb: Limb = undefined;
3859 a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &a_limb));
3860
3861 var b_limb: Limb = undefined;
3862 b_borrow = @boolToInt(@subWithOverflow(Limb, b[i], b_borrow, &b_limb));
3863
3864 r[i] = a_limb | b_limb;
3865 r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i]));
3886 const ov1 = @subWithOverflow(a[i], a_borrow);
3887 a_borrow = ov1[1];
3888 const ov2 = @subWithOverflow(b[i], b_borrow);
3889 b_borrow = ov2[1];
3890 const ov3 = @addWithOverflow(ov1[0] | ov2[0], r_carry);
3891 r[i] = ov3[0];
3892 r_carry = ov3[1];
38663893 }
38673894
38683895 // b is at least 1, so this should never underflow.
......@@ -3870,8 +3897,11 @@ fn llsignedand(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_
38703897
38713898 // With b = 0 and b_borrow = 0 we get (-a - 1) | (-0 - 0) = (-a - 1) | 0 = -a - 1.
38723899 while (i < a.len) : (i += 1) {
3873 a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &r[i]));
3874 r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i]));
3900 const ov1 = @subWithOverflow(a[i], a_borrow);
3901 a_borrow = ov1[1];
3902 const ov2 = @addWithOverflow(ov1[0], r_carry);
3903 r[i] = ov2[0];
3904 r_carry = ov2[1];
38753905 }
38763906
38773907 assert(a_borrow == 0); // a was 0.
......@@ -3917,19 +3947,21 @@ fn llsignedxor(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_
39173947 var r_carry = @boolToInt(a_positive != b_positive);
39183948
39193949 while (i < b.len) : (i += 1) {
3920 var a_limb: Limb = undefined;
3921 a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &a_limb));
3922
3923 var b_limb: Limb = undefined;
3924 b_borrow = @boolToInt(@subWithOverflow(Limb, b[i], b_borrow, &b_limb));
3925
3926 r[i] = a_limb ^ b_limb;
3927 r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i]));
3950 const ov1 = @subWithOverflow(a[i], a_borrow);
3951 a_borrow = ov1[1];
3952 const ov2 = @subWithOverflow(b[i], b_borrow);
3953 b_borrow = ov2[1];
3954 const ov3 = @addWithOverflow(ov1[0] ^ ov2[0], r_carry);
3955 r[i] = ov3[0];
3956 r_carry = ov3[1];
39283957 }
39293958
39303959 while (i < a.len) : (i += 1) {
3931 a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &r[i]));
3932 r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i]));
3960 const ov1 = @subWithOverflow(a[i], a_borrow);
3961 a_borrow = ov1[1];
3962 const ov2 = @addWithOverflow(ov1[0], r_carry);
3963 r[i] = ov2[0];
3964 r_carry = ov2[1];
39333965 }
39343966
39353967 // If both inputs don't share the same sign, an extra limb is required.
......@@ -4021,7 +4053,9 @@ fn llpow(r: []Limb, a: []const Limb, b: u32, tmp_limbs: []Limb) void {
40214053 llsquareBasecase(tmp2, tmp1[0..llnormalize(tmp1)]);
40224054 mem.swap([]Limb, &tmp1, &tmp2);
40234055 // Multiply by a
4024 if (@shlWithOverflow(u32, exp, 1, &exp)) {
4056 const ov = @shlWithOverflow(exp, 1);
4057 exp = ov[0];
4058 if (ov[1] != 0) {
40254059 mem.set(Limb, tmp2, 0);
40264060 llmulacc(.add, null, tmp2, tmp1[0..llnormalize(tmp1)], a);
40274061 mem.swap([]Limb, &tmp1, &tmp2);
lib/std/math/powi.zig+9-9
......@@ -70,22 +70,22 @@ pub fn powi(comptime T: type, x: T, y: T) (error{
7070
7171 while (exp > 1) {
7272 if (exp & 1 == 1) {
73 if (@mulWithOverflow(T, acc, base, &acc)) {
74 return error.Overflow;
75 }
73 const ov = @mulWithOverflow(acc, base);
74 if (ov[1] != 0) return error.Overflow;
75 acc = ov[0];
7676 }
7777
7878 exp >>= 1;
7979
80 if (@mulWithOverflow(T, base, base, &base)) {
81 return error.Overflow;
82 }
80 const ov = @mulWithOverflow(base, base);
81 if (ov[1] != 0) return error.Overflow;
82 base = ov[0];
8383 }
8484
8585 if (exp == 1) {
86 if (@mulWithOverflow(T, acc, base, &acc)) {
87 return error.Overflow;
88 }
86 const ov = @mulWithOverflow(acc, base);
87 if (ov[1] != 0) return error.Overflow;
88 acc = ov[0];
8989 }
9090
9191 return acc;
lib/std/mem.zig+4-4
......@@ -3304,13 +3304,13 @@ pub fn alignPointerOffset(ptr: anytype, align_to: usize) ?usize {
33043304
33053305 // Calculate the aligned base address with an eye out for overflow.
33063306 const addr = @ptrToInt(ptr);
3307 var new_addr: usize = undefined;
3308 if (@addWithOverflow(usize, addr, align_to - 1, &new_addr)) return null;
3309 new_addr &= ~@as(usize, align_to - 1);
3307 var ov = @addWithOverflow(addr, align_to - 1);
3308 if (ov[1] != 0) return null;
3309 ov[0] &= ~@as(usize, align_to - 1);
33103310
33113311 // The delta is expressed in terms of bytes, turn it into a number of child
33123312 // type elements.
3313 const delta = new_addr - addr;
3313 const delta = ov[0] - addr;
33143314 const pointee_size = @sizeOf(info.Pointer.child);
33153315 if (delta % pointee_size != 0) return null;
33163316 return delta / pointee_size;
lib/std/net.zig+24-12
......@@ -321,11 +321,15 @@ pub const Ip6Address = extern struct {
321321 if (scope_id) {
322322 if (c >= '0' and c <= '9') {
323323 const digit = c - '0';
324 if (@mulWithOverflow(u32, result.sa.scope_id, 10, &result.sa.scope_id)) {
325 return error.Overflow;
324 {
325 const ov = @mulWithOverflow(result.sa.scope_id, 10);
326 if (ov[1] != 0) return error.Overflow;
327 result.sa.scope_id = ov[0];
326328 }
327 if (@addWithOverflow(u32, result.sa.scope_id, digit, &result.sa.scope_id)) {
328 return error.Overflow;
329 {
330 const ov = @addWithOverflow(result.sa.scope_id, digit);
331 if (ov[1] != 0) return error.Overflow;
332 result.sa.scope_id = ov[0];
329333 }
330334 } else {
331335 return error.InvalidCharacter;
......@@ -377,11 +381,15 @@ pub const Ip6Address = extern struct {
377381 return result;
378382 } else {
379383 const digit = try std.fmt.charToDigit(c, 16);
380 if (@mulWithOverflow(u16, x, 16, &x)) {
381 return error.Overflow;
384 {
385 const ov = @mulWithOverflow(x, 16);
386 if (ov[1] != 0) return error.Overflow;
387 x = ov[0];
382388 }
383 if (@addWithOverflow(u16, x, digit, &x)) {
384 return error.Overflow;
389 {
390 const ov = @addWithOverflow(x, digit);
391 if (ov[1] != 0) return error.Overflow;
392 x = ov[0];
385393 }
386394 saw_any_digits = true;
387395 }
......@@ -492,11 +500,15 @@ pub const Ip6Address = extern struct {
492500 return result;
493501 } else {
494502 const digit = try std.fmt.charToDigit(c, 16);
495 if (@mulWithOverflow(u16, x, 16, &x)) {
496 return error.Overflow;
503 {
504 const ov = @mulWithOverflow(x, 16);
505 if (ov[1] != 0) return error.Overflow;
506 x = ov[0];
497507 }
498 if (@addWithOverflow(u16, x, digit, &x)) {
499 return error.Overflow;
508 {
509 const ov = @addWithOverflow(x, digit);
510 if (ov[1] != 0) return error.Overflow;
511 x = ov[0];
500512 }
501513 saw_any_digits = true;
502514 }
lib/std/os/linux.zig+1-1
......@@ -1244,7 +1244,7 @@ pub fn sendmmsg(fd: i32, msgvec: [*]mmsghdr_const, vlen: u32, flags: u32) usize
12441244 var size: i32 = 0;
12451245 const msg_iovlen = @intCast(usize, msg.msg_hdr.msg_iovlen); // kernel side this is treated as unsigned
12461246 for (msg.msg_hdr.msg_iov[0..msg_iovlen]) |iov| {
1247 if (iov.iov_len > std.math.maxInt(i32) or @addWithOverflow(i32, size, @intCast(i32, iov.iov_len), &size)) {
1247 if (iov.iov_len > std.math.maxInt(i32) or @addWithOverflow(size, @intCast(i32, iov.iov_len))[1] != 0) {
12481248 // batch-send all messages up to the current message
12491249 if (next_unsent < i) {
12501250 const batch_size = i - next_unsent;
lib/std/process.zig+20-4
......@@ -1023,8 +1023,16 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {
10231023 '0'...'9' => byte - '0',
10241024 else => return error.CorruptPasswordFile,
10251025 };
1026 if (@mulWithOverflow(u32, uid, 10, &uid)) return error.CorruptPasswordFile;
1027 if (@addWithOverflow(u32, uid, digit, &uid)) return error.CorruptPasswordFile;
1026 {
1027 const ov = @mulWithOverflow(uid, 10);
1028 if (ov[1] != 0) return error.CorruptPasswordFile;
1029 uid = ov[0];
1030 }
1031 {
1032 const ov = @addWithOverflow(uid, digit);
1033 if (ov[1] != 0) return error.CorruptPasswordFile;
1034 uid = ov[0];
1035 }
10281036 },
10291037 },
10301038 .ReadGroupId => switch (byte) {
......@@ -1039,8 +1047,16 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {
10391047 '0'...'9' => byte - '0',
10401048 else => return error.CorruptPasswordFile,
10411049 };
1042 if (@mulWithOverflow(u32, gid, 10, &gid)) return error.CorruptPasswordFile;
1043 if (@addWithOverflow(u32, gid, digit, &gid)) return error.CorruptPasswordFile;
1050 {
1051 const ov = @mulWithOverflow(gid, 10);
1052 if (ov[1] != 0) return error.CorruptPasswordFile;
1053 gid = ov[0];
1054 }
1055 {
1056 const ov = @addWithOverflow(gid, digit);
1057 if (ov[1] != 0) return error.CorruptPasswordFile;
1058 gid = ov[0];
1059 }
10441060 },
10451061 },
10461062 }
lib/std/zig/c_builtins.zig+3-1
......@@ -246,7 +246,9 @@ pub inline fn __builtin_constant_p(expr: anytype) c_int {
246246 return @boolToInt(false);
247247}
248248pub fn __builtin_mul_overflow(a: anytype, b: anytype, result: *@TypeOf(a, b)) c_int {
249 return @boolToInt(@mulWithOverflow(@TypeOf(a, b), a, b, result));
249 const res = @mulWithOverflow(a, b);
250 result.* = res[0];
251 return res[1];
250252}
251253
252254// __builtin_alloca_with_align is not currently implemented.
lib/std/zig/number_literal.zig+7-5
......@@ -151,12 +151,14 @@ pub fn parseNumberLiteral(bytes: []const u8) Result {
151151 special = 0;
152152
153153 if (float) continue;
154 if (x != 0) if (@mulWithOverflow(u64, x, base, &x)) {
155 overflow = true;
156 };
157 if (@addWithOverflow(u64, x, digit, &x)) {
158 overflow = true;
154 if (x != 0) {
155 const res = @mulWithOverflow(x, base);
156 if (res[1] != 0) overflow = true;
157 x = res[0];
159158 }
159 const res = @addWithOverflow(x, digit);
160 if (res[1] != 0) overflow = true;
161 x = res[0];
160162 }
161163 if (underscore) return .{ .failure = .{ .trailing_underscore = bytes.len - 1 } };
162164 if (special != 0) return .{ .failure = .{ .trailing_special = bytes.len - 1 } };
src/AstGen.zig+4-24
......@@ -2505,7 +2505,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
25052505 .err_union_code,
25062506 .err_union_code_ptr,
25072507 .ptr_type,
2508 .overflow_arithmetic_ptr,
25092508 .enum_literal,
25102509 .merge_error_sets,
25112510 .error_union_type,
......@@ -2543,7 +2542,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
25432542 .type_info,
25442543 .size_of,
25452544 .bit_size_of,
2546 .log2_int_type,
25472545 .typeof_log2_int_type,
25482546 .ptr_to_int,
25492547 .align_of,
......@@ -8236,21 +8234,7 @@ fn builtinCall(
82368234 .add_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .add_with_overflow),
82378235 .sub_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .sub_with_overflow),
82388236 .mul_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .mul_with_overflow),
8239 .shl_with_overflow => {
8240 const int_type = try typeExpr(gz, scope, params[0]);
8241 const log2_int_type = try gz.addUnNode(.log2_int_type, int_type, params[0]);
8242 const ptr_type = try gz.addUnNode(.overflow_arithmetic_ptr, int_type, params[0]);
8243 const lhs = try expr(gz, scope, .{ .rl = .{ .ty = int_type } }, params[1]);
8244 const rhs = try expr(gz, scope, .{ .rl = .{ .ty = log2_int_type } }, params[2]);
8245 const ptr = try expr(gz, scope, .{ .rl = .{ .ty = ptr_type } }, params[3]);
8246 const result = try gz.addExtendedPayload(.shl_with_overflow, Zir.Inst.OverflowArithmetic{
8247 .node = gz.nodeIndexToRelative(node),
8248 .lhs = lhs,
8249 .rhs = rhs,
8250 .ptr = ptr,
8251 });
8252 return rvalue(gz, ri, result, node);
8253 },
8237 .shl_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .shl_with_overflow),
82548238
82558239 .atomic_load => {
82568240 const result = try gz.addPlNode(.atomic_load, node, Zir.Inst.AtomicLoad{
......@@ -8691,16 +8675,12 @@ fn overflowArithmetic(
86918675 params: []const Ast.Node.Index,
86928676 tag: Zir.Inst.Extended,
86938677) InnerError!Zir.Inst.Ref {
8694 const int_type = try typeExpr(gz, scope, params[0]);
8695 const ptr_type = try gz.addUnNode(.overflow_arithmetic_ptr, int_type, params[0]);
8696 const lhs = try expr(gz, scope, .{ .rl = .{ .ty = int_type } }, params[1]);
8697 const rhs = try expr(gz, scope, .{ .rl = .{ .ty = int_type } }, params[2]);
8698 const ptr = try expr(gz, scope, .{ .rl = .{ .ty = ptr_type } }, params[3]);
8699 const result = try gz.addExtendedPayload(tag, Zir.Inst.OverflowArithmetic{
8678 const lhs = try expr(gz, scope, .{ .rl = .none }, params[0]);
8679 const rhs = try expr(gz, scope, .{ .rl = .none }, params[1]);
8680 const result = try gz.addExtendedPayload(tag, Zir.Inst.BinNode{
87008681 .node = gz.nodeIndexToRelative(node),
87018682 .lhs = lhs,
87028683 .rhs = rhs,
8703 .ptr = ptr,
87048684 });
87058685 return rvalue(gz, ri, result, node);
87068686}
src/Autodoc.zig-20
......@@ -1510,26 +1510,6 @@ fn walkInstruction(
15101510
15111511 // return operand;
15121512 // },
1513 .overflow_arithmetic_ptr => {
1514 const un_node = data[inst_index].un_node;
1515
1516 const elem_type_ref = try self.walkRef(file, parent_scope, parent_src, un_node.operand, false);
1517 const type_slot_index = self.types.items.len;
1518 try self.types.append(self.arena, .{
1519 .Pointer = .{
1520 .size = .One,
1521 .child = elem_type_ref.expr,
1522 .is_mutable = true,
1523 .is_volatile = false,
1524 .is_allowzero = false,
1525 },
1526 });
1527
1528 return DocData.WalkResult{
1529 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
1530 .expr = .{ .type = type_slot_index },
1531 };
1532 },
15331513 .ptr_type => {
15341514 const ptr = data[inst_index].ptr_type;
15351515 const extra = file.zir.extraData(Zir.Inst.PtrType, ptr.payload_index);
src/BuiltinFn.zig+4-4
......@@ -154,7 +154,7 @@ pub const list = list: {
154154 "@addWithOverflow",
155155 .{
156156 .tag = .add_with_overflow,
157 .param_count = 4,
157 .param_count = 2,
158158 },
159159 },
160160 .{
......@@ -636,7 +636,7 @@ pub const list = list: {
636636 "@mulWithOverflow",
637637 .{
638638 .tag = .mul_with_overflow,
639 .param_count = 4,
639 .param_count = 2,
640640 },
641641 },
642642 .{
......@@ -741,7 +741,7 @@ pub const list = list: {
741741 "@shlWithOverflow",
742742 .{
743743 .tag = .shl_with_overflow,
744 .param_count = 4,
744 .param_count = 2,
745745 },
746746 },
747747 .{
......@@ -889,7 +889,7 @@ pub const list = list: {
889889 "@subWithOverflow",
890890 .{
891891 .tag = .sub_with_overflow,
892 .param_count = 4,
892 .param_count = 2,
893893 },
894894 },
895895 .{
src/Sema.zig+78-88
......@@ -971,7 +971,6 @@ fn analyzeBodyInner(
971971 .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false),
972972 .optional_type => try sema.zirOptionalType(block, inst),
973973 .ptr_type => try sema.zirPtrType(block, inst),
974 .overflow_arithmetic_ptr => try sema.zirOverflowArithmeticPtr(block, inst),
975974 .ref => try sema.zirRef(block, inst),
976975 .ret_err_value_code => try sema.zirRetErrValueCode(inst),
977976 .shr => try sema.zirShr(block, inst, .shr),
......@@ -993,7 +992,6 @@ fn analyzeBodyInner(
993992 .bit_size_of => try sema.zirBitSizeOf(block, inst),
994993 .typeof => try sema.zirTypeof(block, inst),
995994 .typeof_builtin => try sema.zirTypeofBuiltin(block, inst),
996 .log2_int_type => try sema.zirLog2IntType(block, inst),
997995 .typeof_log2_int_type => try sema.zirTypeofLog2IntType(block, inst),
998996 .xor => try sema.zirBitwise(block, inst, .xor),
999997 .struct_init_empty => try sema.zirStructInitEmpty(block, inst),
......@@ -11762,7 +11760,7 @@ fn zirShl(
1176211760 if (scalar_ty.zigTypeTag() == .ComptimeInt) {
1176311761 break :val shifted.wrapped_result;
1176411762 }
11765 if (shifted.overflowed.compareAllWithZero(.eq)) {
11763 if (shifted.overflow_bit.compareAllWithZero(.eq)) {
1176611764 break :val shifted.wrapped_result;
1176711765 }
1176811766 return sema.fail(block, src, "operation caused overflow", .{});
......@@ -13783,24 +13781,37 @@ fn zirOverflowArithmetic(
1378313781 const tracy = trace(@src());
1378413782 defer tracy.end();
1378513783
13786 const extra = sema.code.extraData(Zir.Inst.OverflowArithmetic, extended.operand).data;
13784 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
1378713785 const src = LazySrcLoc.nodeOffset(extra.node);
1378813786
1378913787 const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
1379013788 const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
13791 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = extra.node };
1379213789
13793 const lhs = try sema.resolveInst(extra.lhs);
13794 const rhs = try sema.resolveInst(extra.rhs);
13795 const ptr = try sema.resolveInst(extra.ptr);
13790 const uncasted_lhs = try sema.resolveInst(extra.lhs);
13791 const uncasted_rhs = try sema.resolveInst(extra.rhs);
1379613792
13797 const lhs_ty = sema.typeOf(lhs);
13798 const rhs_ty = sema.typeOf(rhs);
13793 const lhs_ty = sema.typeOf(uncasted_lhs);
13794 const rhs_ty = sema.typeOf(uncasted_rhs);
1379913795 const mod = sema.mod;
1380013796
13801 // Note, the types of lhs/rhs (also for shifting)/ptr are already correct as ensured by astgen.
1380213797 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
13803 const dest_ty = lhs_ty;
13798
13799 const instructions = &[_]Air.Inst.Ref{ uncasted_lhs, uncasted_rhs };
13800 const dest_ty = if (zir_tag == .shl_with_overflow)
13801 lhs_ty
13802 else
13803 try sema.resolvePeerTypes(block, src, instructions, .{
13804 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
13805 });
13806
13807 const rhs_dest_ty = if (zir_tag == .shl_with_overflow)
13808 try sema.log2IntType(block, lhs_ty, src)
13809 else
13810 dest_ty;
13811
13812 const lhs = try sema.coerce(block, dest_ty, uncasted_lhs, lhs_src);
13813 const rhs = try sema.coerce(block, rhs_dest_ty, uncasted_rhs, rhs_src);
13814
1380413815 if (dest_ty.scalarType().zigTypeTag() != .Int) {
1380513816 return sema.fail(block, src, "expected vector of integers or integer tag type, found '{}'", .{dest_ty.fmt(mod)});
1380613817 }
......@@ -13809,14 +13820,11 @@ fn zirOverflowArithmetic(
1380913820 const maybe_rhs_val = try sema.resolveMaybeUndefVal(rhs);
1381013821
1381113822 const tuple_ty = try sema.overflowArithmeticTupleType(dest_ty);
13812 // TODO: Remove and use `ov_ty` instead.
13813 // This is a temporary type used until overflow arithmetic properly returns `u1` instead of `bool`.
13814 const overflowed_ty = if (dest_ty.zigTypeTag() == .Vector) try Type.vector(sema.arena, dest_ty.vectorLen(), Type.bool) else Type.bool;
13815
13816 const result: struct {
13817 /// TODO: Rename to `overflow_bit` and make of type `u1`.
13818 overflowed: Air.Inst.Ref,
13819 wrapped: Air.Inst.Ref,
13823
13824 var result: struct {
13825 inst: Air.Inst.Ref = .none,
13826 wrapped: Value = Value.initTag(.unreachable_value),
13827 overflow_bit: Value,
1382013828 } = result: {
1382113829 switch (zir_tag) {
1382213830 .add_with_overflow => {
......@@ -13825,24 +13833,22 @@ fn zirOverflowArithmetic(
1382513833 // Otherwise, if either of the argument is undefined, undefined is returned.
1382613834 if (maybe_lhs_val) |lhs_val| {
1382713835 if (!lhs_val.isUndef() and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
13828 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs };
13836 break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = rhs };
1382913837 }
1383013838 }
1383113839 if (maybe_rhs_val) |rhs_val| {
1383213840 if (!rhs_val.isUndef() and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
13833 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
13841 break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs };
1383413842 }
1383513843 }
1383613844 if (maybe_lhs_val) |lhs_val| {
1383713845 if (maybe_rhs_val) |rhs_val| {
1383813846 if (lhs_val.isUndef() or rhs_val.isUndef()) {
13839 break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) };
13847 break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef };
1384013848 }
1384113849
1384213850 const result = try sema.intAddWithOverflow(lhs_val, rhs_val, dest_ty);
13843 const overflowed = try sema.addConstant(overflowed_ty, result.overflowed);
13844 const wrapped = try sema.addConstant(dest_ty, result.wrapped_result);
13845 break :result .{ .overflowed = overflowed, .wrapped = wrapped };
13851 break :result .{ .overflow_bit = result.overflow_bit, .wrapped = result.wrapped_result };
1384613852 }
1384713853 }
1384813854 },
......@@ -13851,18 +13857,16 @@ fn zirOverflowArithmetic(
1385113857 // Otherwise, if either result is undefined, both results are undefined.
1385213858 if (maybe_rhs_val) |rhs_val| {
1385313859 if (rhs_val.isUndef()) {
13854 break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) };
13860 break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef };
1385513861 } else if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
13856 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
13862 break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs };
1385713863 } else if (maybe_lhs_val) |lhs_val| {
1385813864 if (lhs_val.isUndef()) {
13859 break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) };
13865 break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef };
1386013866 }
1386113867
1386213868 const result = try sema.intSubWithOverflow(lhs_val, rhs_val, dest_ty);
13863 const overflowed = try sema.addConstant(overflowed_ty, result.overflowed);
13864 const wrapped = try sema.addConstant(dest_ty, result.wrapped_result);
13865 break :result .{ .overflowed = overflowed, .wrapped = wrapped };
13869 break :result .{ .overflow_bit = result.overflow_bit, .wrapped = result.wrapped_result };
1386613870 }
1386713871 }
1386813872 },
......@@ -13873,9 +13877,9 @@ fn zirOverflowArithmetic(
1387313877 if (maybe_lhs_val) |lhs_val| {
1387413878 if (!lhs_val.isUndef()) {
1387513879 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
13876 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
13877 } else if (try sema.compareAll(lhs_val, .eq, Value.one, dest_ty)) {
13878 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs };
13880 break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs };
13881 } else if (try sema.compareAll(lhs_val, .eq, try maybeRepeated(sema, dest_ty, Value.one), dest_ty)) {
13882 break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = rhs };
1387913883 }
1388013884 }
1388113885 }
......@@ -13883,9 +13887,9 @@ fn zirOverflowArithmetic(
1388313887 if (maybe_rhs_val) |rhs_val| {
1388413888 if (!rhs_val.isUndef()) {
1388513889 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
13886 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs };
13887 } else if (try sema.compareAll(rhs_val, .eq, Value.one, dest_ty)) {
13888 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
13890 break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = rhs };
13891 } else if (try sema.compareAll(rhs_val, .eq, try maybeRepeated(sema, dest_ty, Value.one), dest_ty)) {
13892 break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs };
1388913893 }
1389013894 }
1389113895 }
......@@ -13893,13 +13897,11 @@ fn zirOverflowArithmetic(
1389313897 if (maybe_lhs_val) |lhs_val| {
1389413898 if (maybe_rhs_val) |rhs_val| {
1389513899 if (lhs_val.isUndef() or rhs_val.isUndef()) {
13896 break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) };
13900 break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef };
1389713901 }
1389813902
1389913903 const result = try lhs_val.intMulWithOverflow(rhs_val, dest_ty, sema.arena, mod);
13900 const overflowed = try sema.addConstant(overflowed_ty, result.overflowed);
13901 const wrapped = try sema.addConstant(dest_ty, result.wrapped_result);
13902 break :result .{ .overflowed = overflowed, .wrapped = wrapped };
13904 break :result .{ .overflow_bit = result.overflow_bit, .wrapped = result.wrapped_result };
1390313905 }
1390413906 }
1390513907 },
......@@ -13909,24 +13911,22 @@ fn zirOverflowArithmetic(
1390913911 // Oterhwise if either of the arguments is undefined, both results are undefined.
1391013912 if (maybe_lhs_val) |lhs_val| {
1391113913 if (!lhs_val.isUndef() and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
13912 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
13914 break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs };
1391313915 }
1391413916 }
1391513917 if (maybe_rhs_val) |rhs_val| {
1391613918 if (!rhs_val.isUndef() and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
13917 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
13919 break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs };
1391813920 }
1391913921 }
1392013922 if (maybe_lhs_val) |lhs_val| {
1392113923 if (maybe_rhs_val) |rhs_val| {
1392213924 if (lhs_val.isUndef() or rhs_val.isUndef()) {
13923 break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) };
13925 break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef };
1392413926 }
1392513927
1392613928 const result = try lhs_val.shlWithOverflow(rhs_val, dest_ty, sema.arena, sema.mod);
13927 const overflowed = try sema.addConstant(overflowed_ty, result.overflowed);
13928 const wrapped = try sema.addConstant(dest_ty, result.wrapped_result);
13929 break :result .{ .overflowed = overflowed, .wrapped = wrapped };
13929 break :result .{ .overflow_bit = result.overflow_bit, .wrapped = result.wrapped_result };
1393013930 }
1393113931 }
1393213932 },
......@@ -13944,7 +13944,7 @@ fn zirOverflowArithmetic(
1394413944 const runtime_src = if (maybe_lhs_val == null) lhs_src else rhs_src;
1394513945 try sema.requireRuntimeBlock(block, src, runtime_src);
1394613946
13947 const tuple = try block.addInst(.{
13947 return block.addInst(.{
1394813948 .tag = air_tag,
1394913949 .data = .{ .ty_pl = .{
1395013950 .ty = try block.sema.addType(tuple_ty),
......@@ -13954,16 +13954,32 @@ fn zirOverflowArithmetic(
1395413954 }),
1395513955 } },
1395613956 });
13957 };
1395713958
13958 const wrapped = try sema.tupleFieldValByIndex(block, src, tuple, 0, tuple_ty);
13959 try sema.storePtr2(block, src, ptr, ptr_src, wrapped, src, .store);
13959 if (result.inst != .none) {
13960 if (try sema.resolveMaybeUndefVal(result.inst)) |some| {
13961 result.wrapped = some;
13962 result.inst = .none;
13963 }
13964 }
1396013965
13961 const overflow_bit = try sema.tupleFieldValByIndex(block, src, tuple, 1, tuple_ty);
13962 return block.addBitCast(overflowed_ty, overflow_bit);
13963 };
13966 if (result.inst == .none) {
13967 const values = try sema.arena.alloc(Value, 2);
13968 values[0] = result.wrapped;
13969 values[1] = result.overflow_bit;
13970 const tuple_val = try Value.Tag.aggregate.create(sema.arena, values);
13971 return sema.addConstant(tuple_ty, tuple_val);
13972 }
13973
13974 const element_refs = try sema.arena.alloc(Air.Inst.Ref, 2);
13975 element_refs[0] = result.inst;
13976 element_refs[1] = try sema.addConstant(tuple_ty.structFieldType(1), result.overflow_bit);
13977 return block.addAggregateInit(tuple_ty, element_refs);
13978}
1396413979
13965 try sema.storePtr2(block, src, ptr, ptr_src, result.wrapped, src, .store);
13966 return result.overflowed;
13980fn maybeRepeated(sema: *Sema, ty: Type, val: Value) !Value {
13981 if (ty.zigTypeTag() != .Vector) return val;
13982 return Value.Tag.repeated.create(sema.arena, val);
1396713983}
1396813984
1396913985fn overflowArithmeticTupleType(sema: *Sema, ty: Type) !Type {
......@@ -16211,14 +16227,6 @@ fn zirTypeofLog2IntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil
1621116227 return sema.addType(res_ty);
1621216228}
1621316229
16214fn zirLog2IntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
16215 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
16216 const src = inst_data.src();
16217 const operand = try sema.resolveType(block, src, inst_data.operand);
16218 const res_ty = try sema.log2IntType(block, operand, src);
16219 return sema.addType(res_ty);
16220}
16221
1622216230fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) CompileError!Type {
1622316231 switch (operand.zigTypeTag()) {
1622416232 .ComptimeInt => return Type.comptime_int,
......@@ -17039,24 +17047,6 @@ fn floatOpAllowed(tag: Zir.Inst.Tag) bool {
1703917047 };
1704017048}
1704117049
17042fn zirOverflowArithmeticPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
17043 const tracy = trace(@src());
17044 defer tracy.end();
17045
17046 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
17047 const elem_ty_src = inst_data.src();
17048 const elem_type = try sema.resolveType(block, elem_ty_src, inst_data.operand);
17049 const ty = try Type.ptr(sema.arena, sema.mod, .{
17050 .pointee_type = elem_type,
17051 .@"addrspace" = .generic,
17052 .mutable = true,
17053 .@"allowzero" = false,
17054 .@"volatile" = false,
17055 .size = .One,
17056 });
17057 return sema.addType(ty);
17058}
17059
1706017050fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
1706117051 const tracy = trace(@src());
1706217052 defer tracy.end();
......@@ -32613,11 +32603,11 @@ fn intSubWithOverflow(
3261332603 const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf);
3261432604 const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf);
3261532605 const of_math_result = try sema.intSubWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType());
32616 overflowed_data[i] = of_math_result.overflowed;
32606 overflowed_data[i] = of_math_result.overflow_bit;
3261732607 scalar.* = of_math_result.wrapped_result;
3261832608 }
3261932609 return Value.OverflowArithmeticResult{
32620 .overflowed = try Value.Tag.aggregate.create(sema.arena, overflowed_data),
32610 .overflow_bit = try Value.Tag.aggregate.create(sema.arena, overflowed_data),
3262132611 .wrapped_result = try Value.Tag.aggregate.create(sema.arena, result_data),
3262232612 };
3262332613 }
......@@ -32645,7 +32635,7 @@ fn intSubWithOverflowScalar(
3264532635 const overflowed = result_bigint.subWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);
3264632636 const wrapped_result = try Value.fromBigInt(sema.arena, result_bigint.toConst());
3264732637 return Value.OverflowArithmeticResult{
32648 .overflowed = Value.makeBool(overflowed),
32638 .overflow_bit = Value.boolToInt(overflowed),
3264932639 .wrapped_result = wrapped_result,
3265032640 };
3265132641}
......@@ -32964,11 +32954,11 @@ fn intAddWithOverflow(
3296432954 const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf);
3296532955 const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf);
3296632956 const of_math_result = try sema.intAddWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType());
32967 overflowed_data[i] = of_math_result.overflowed;
32957 overflowed_data[i] = of_math_result.overflow_bit;
3296832958 scalar.* = of_math_result.wrapped_result;
3296932959 }
3297032960 return Value.OverflowArithmeticResult{
32971 .overflowed = try Value.Tag.aggregate.create(sema.arena, overflowed_data),
32961 .overflow_bit = try Value.Tag.aggregate.create(sema.arena, overflowed_data),
3297232962 .wrapped_result = try Value.Tag.aggregate.create(sema.arena, result_data),
3297332963 };
3297432964 }
......@@ -32996,7 +32986,7 @@ fn intAddWithOverflowScalar(
3299632986 const overflowed = result_bigint.addWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);
3299732987 const result = try Value.fromBigInt(sema.arena, result_bigint.toConst());
3299832988 return Value.OverflowArithmeticResult{
32999 .overflowed = Value.makeBool(overflowed),
32989 .overflow_bit = Value.boolToInt(overflowed),
3300032990 .wrapped_result = result,
3300132991 };
3300232992}
src/TypedValue.zig+1-3
......@@ -225,9 +225,7 @@ pub fn print(
225225 .one => return writer.writeAll("1"),
226226 .void_value => return writer.writeAll("{}"),
227227 .unreachable_value => return writer.writeAll("unreachable"),
228 .the_only_possible_value => {
229 val = ty.onePossibleValue().?;
230 },
228 .the_only_possible_value => return writer.writeAll("0"),
231229 .bool_true => return writer.writeAll("true"),
232230 .bool_false => return writer.writeAll("false"),
233231 .ty => return val.castTag(.ty).?.data.print(writer, mod),
src/Zir.zig+4-23
......@@ -539,9 +539,6 @@ pub const Inst = struct {
539539 /// Obtains the return type of the in-scope function.
540540 /// Uses the `node` union field.
541541 ret_type,
542 /// Create a pointer type for overflow arithmetic.
543 /// TODO remove when doing https://github.com/ziglang/zig/issues/10248
544 overflow_arithmetic_ptr,
545542 /// Create a pointer type which can have a sentinel, alignment, address space, and/or bit range.
546543 /// Uses the `ptr_type` union field.
547544 ptr_type,
......@@ -600,9 +597,6 @@ pub const Inst = struct {
600597 /// Returns the integer type for the RHS of a shift operation.
601598 /// Uses the `un_node` field.
602599 typeof_log2_int_type,
603 /// Given an integer type, returns the integer type for the RHS of a shift operation.
604 /// Uses the `un_node` field.
605 log2_int_type,
606600 /// Asserts control-flow will not reach this instruction (`unreachable`).
607601 /// Uses the `unreachable` union field.
608602 @"unreachable",
......@@ -1121,7 +1115,6 @@ pub const Inst = struct {
11211115 .err_union_code,
11221116 .err_union_code_ptr,
11231117 .ptr_type,
1124 .overflow_arithmetic_ptr,
11251118 .enum_literal,
11261119 .merge_error_sets,
11271120 .error_union_type,
......@@ -1132,7 +1125,6 @@ pub const Inst = struct {
11321125 .slice_sentinel,
11331126 .import,
11341127 .typeof_log2_int_type,
1135 .log2_int_type,
11361128 .resolve_inferred_alloc,
11371129 .set_eval_branch_quota,
11381130 .switch_capture,
......@@ -1422,7 +1414,6 @@ pub const Inst = struct {
14221414 .err_union_code,
14231415 .err_union_code_ptr,
14241416 .ptr_type,
1425 .overflow_arithmetic_ptr,
14261417 .enum_literal,
14271418 .merge_error_sets,
14281419 .error_union_type,
......@@ -1433,7 +1424,6 @@ pub const Inst = struct {
14331424 .slice_sentinel,
14341425 .import,
14351426 .typeof_log2_int_type,
1436 .log2_int_type,
14371427 .switch_capture,
14381428 .switch_capture_ref,
14391429 .switch_capture_multi,
......@@ -1664,7 +1654,6 @@ pub const Inst = struct {
16641654 .ret_err_value_code = .str_tok,
16651655 .ret_ptr = .node,
16661656 .ret_type = .node,
1667 .overflow_arithmetic_ptr = .un_node,
16681657 .ptr_type = .ptr_type,
16691658 .slice_start = .pl_node,
16701659 .slice_end = .pl_node,
......@@ -1678,7 +1667,6 @@ pub const Inst = struct {
16781667 .negate_wrap = .un_node,
16791668 .typeof = .un_node,
16801669 .typeof_log2_int_type = .un_node,
1681 .log2_int_type = .un_node,
16821670 .@"unreachable" = .@"unreachable",
16831671 .xor = .pl_node,
16841672 .optional_type = .un_node,
......@@ -1916,19 +1904,19 @@ pub const Inst = struct {
19161904 /// The AST node is the builtin call.
19171905 typeof_peer,
19181906 /// Implements the `@addWithOverflow` builtin.
1919 /// `operand` is payload index to `OverflowArithmetic`.
1907 /// `operand` is payload index to `BinNode`.
19201908 /// `small` is unused.
19211909 add_with_overflow,
19221910 /// Implements the `@subWithOverflow` builtin.
1923 /// `operand` is payload index to `OverflowArithmetic`.
1911 /// `operand` is payload index to `BinNode`.
19241912 /// `small` is unused.
19251913 sub_with_overflow,
19261914 /// Implements the `@mulWithOverflow` builtin.
1927 /// `operand` is payload index to `OverflowArithmetic`.
1915 /// `operand` is payload index to `BinNode`.
19281916 /// `small` is unused.
19291917 mul_with_overflow,
19301918 /// Implements the `@shlWithOverflow` builtin.
1931 /// `operand` is payload index to `OverflowArithmetic`.
1919 /// `operand` is payload index to `BinNode`.
19321920 /// `small` is unused.
19331921 shl_with_overflow,
19341922 /// `operand` is payload index to `UnNode`.
......@@ -3430,13 +3418,6 @@ pub const Inst = struct {
34303418 field_name: Ref,
34313419 };
34323420
3433 pub const OverflowArithmetic = struct {
3434 node: i32,
3435 lhs: Ref,
3436 rhs: Ref,
3437 ptr: Ref,
3438 };
3439
34403421 pub const Cmpxchg = struct {
34413422 node: i32,
34423423 ptr: Ref,
src/link/Coff.zig+1-3
......@@ -1860,9 +1860,7 @@ fn writeHeader(self: *Coff) !void {
18601860}
18611861
18621862pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
1863 // TODO https://github.com/ziglang/zig/issues/1284
1864 return math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch
1865 math.maxInt(@TypeOf(actual_size));
1863 return actual_size +| (actual_size / ideal_factor);
18661864}
18671865
18681866fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 {
src/link/Dwarf.zig+1-3
......@@ -2445,9 +2445,7 @@ fn makeString(self: *Dwarf, bytes: []const u8) !u32 {
24452445}
24462446
24472447fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
2448 // TODO https://github.com/ziglang/zig/issues/1284
2449 return std.math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch
2450 std.math.maxInt(@TypeOf(actual_size));
2448 return actual_size +| (actual_size / ideal_factor);
24512449}
24522450
24532451pub fn flushModule(self: *Dwarf, module: *Module) !void {
src/link/Elf.zig+1-3
......@@ -3032,9 +3032,7 @@ fn getLDMOption(target: std.Target) ?[]const u8 {
30323032}
30333033
30343034fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
3035 // TODO https://github.com/ziglang/zig/issues/1284
3036 return std.math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch
3037 std.math.maxInt(@TypeOf(actual_size));
3035 return actual_size +| (actual_size / ideal_factor);
30383036}
30393037
30403038// Provide a blueprint of csu (c-runtime startup) objects for supported
src/link/MachO.zig+1-3
......@@ -3772,9 +3772,7 @@ fn writeHeader(self: *MachO, ncmds: u32, sizeofcmds: u32) !void {
37723772}
37733773
37743774pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
3775 // TODO https://github.com/ziglang/zig/issues/1284
3776 return std.math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch
3777 std.math.maxInt(@TypeOf(actual_size));
3775 return actual_size +| (actual_size / ideal_factor);
37783776}
37793777
37803778fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 {
src/print_zir.zig+1-5
......@@ -185,7 +185,6 @@ const Writer = struct {
185185 .size_of,
186186 .bit_size_of,
187187 .typeof_log2_int_type,
188 .log2_int_type,
189188 .ptr_to_int,
190189 .compile_error,
191190 .set_eval_branch_quota,
......@@ -230,7 +229,6 @@ const Writer = struct {
230229 .validate_struct_init_ty,
231230 .make_ptr_const,
232231 .validate_deref,
233 .overflow_arithmetic_ptr,
234232 .check_comptime_control_flow,
235233 => try self.writeUnNode(stream, inst),
236234
......@@ -1153,14 +1151,12 @@ const Writer = struct {
11531151 }
11541152
11551153 fn writeOverflowArithmetic(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
1156 const extra = self.code.extraData(Zir.Inst.OverflowArithmetic, extended.operand).data;
1154 const extra = self.code.extraData(Zir.Inst.BinNode, extended.operand).data;
11571155 const src = LazySrcLoc.nodeOffset(extra.node);
11581156
11591157 try self.writeInstRef(stream, extra.lhs);
11601158 try stream.writeAll(", ");
11611159 try self.writeInstRef(stream, extra.rhs);
1162 try stream.writeAll(", ");
1163 try self.writeInstRef(stream, extra.ptr);
11641160 try stream.writeAll(")) ");
11651161 try self.writeSrc(stream, src);
11661162 }
src/type.zig+1
......@@ -3123,6 +3123,7 @@ pub const Type = extern union {
31233123 for (tuple.types) |field_ty, i| {
31243124 const val = tuple.values[i];
31253125 if (val.tag() != .unreachable_value) continue; // comptime field
3126 if (!(field_ty.hasRuntimeBits())) continue;
31263127
31273128 switch (try field_ty.abiAlignmentAdvanced(target, strat)) {
31283129 .scalar => |field_align| big_align = @max(big_align, field_align),
src/value.zig+13-8
......@@ -1378,6 +1378,7 @@ pub const Value = extern union {
13781378 var enum_buffer: Payload.U64 = undefined;
13791379 const int_val = val.enumToInt(ty, &enum_buffer);
13801380
1381 if (abi_size == 0) return;
13811382 if (abi_size <= @sizeOf(u64)) {
13821383 const int: u64 = switch (int_val.tag()) {
13831384 .zero => 0,
......@@ -1571,6 +1572,7 @@ pub const Value = extern union {
15711572 const abi_size = @intCast(usize, ty.abiSize(target));
15721573
15731574 const bits = int_info.bits;
1575 if (bits == 0) return Value.zero;
15741576 if (bits <= 64) switch (int_info.signedness) { // Fast path for integers <= u64
15751577 .signed => return Value.Tag.int_i64.create(arena, std.mem.readVarPackedInt(i64, buffer, bit_offset, bits, endian, .signed)),
15761578 .unsigned => return Value.Tag.int_u64.create(arena, std.mem.readVarPackedInt(u64, buffer, bit_offset, bits, endian, .unsigned)),
......@@ -3259,8 +3261,7 @@ pub const Value = extern union {
32593261 }
32603262
32613263 pub const OverflowArithmeticResult = struct {
3262 /// TODO: Rename to `overflow_bit` and make of type `u1`.
3263 overflowed: Value,
3264 overflow_bit: Value,
32643265 wrapped_result: Value,
32653266 };
32663267
......@@ -3395,11 +3396,11 @@ pub const Value = extern union {
33953396 const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf);
33963397 const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf);
33973398 const of_math_result = try intMulWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType(), arena, target);
3398 overflowed_data[i] = of_math_result.overflowed;
3399 overflowed_data[i] = of_math_result.overflow_bit;
33993400 scalar.* = of_math_result.wrapped_result;
34003401 }
34013402 return OverflowArithmeticResult{
3402 .overflowed = try Value.Tag.aggregate.create(arena, overflowed_data),
3403 .overflow_bit = try Value.Tag.aggregate.create(arena, overflowed_data),
34033404 .wrapped_result = try Value.Tag.aggregate.create(arena, result_data),
34043405 };
34053406 }
......@@ -3436,7 +3437,7 @@ pub const Value = extern union {
34363437 }
34373438
34383439 return OverflowArithmeticResult{
3439 .overflowed = makeBool(overflowed),
3440 .overflow_bit = boolToInt(overflowed),
34403441 .wrapped_result = try fromBigInt(arena, result_bigint.toConst()),
34413442 };
34423443 }
......@@ -4141,11 +4142,11 @@ pub const Value = extern union {
41414142 const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf);
41424143 const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf);
41434144 const of_math_result = try shlWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType(), allocator, target);
4144 overflowed_data[i] = of_math_result.overflowed;
4145 overflowed_data[i] = of_math_result.overflow_bit;
41454146 scalar.* = of_math_result.wrapped_result;
41464147 }
41474148 return OverflowArithmeticResult{
4148 .overflowed = try Value.Tag.aggregate.create(allocator, overflowed_data),
4149 .overflow_bit = try Value.Tag.aggregate.create(allocator, overflowed_data),
41494150 .wrapped_result = try Value.Tag.aggregate.create(allocator, result_data),
41504151 };
41514152 }
......@@ -4178,7 +4179,7 @@ pub const Value = extern union {
41784179 result_bigint.truncate(result_bigint.toConst(), info.signedness, info.bits);
41794180 }
41804181 return OverflowArithmeticResult{
4181 .overflowed = makeBool(overflowed),
4182 .overflow_bit = boolToInt(overflowed),
41824183 .wrapped_result = try fromBigInt(allocator, result_bigint.toConst()),
41834184 };
41844185 }
......@@ -5492,6 +5493,10 @@ pub const Value = extern union {
54925493 return if (x) Value.true else Value.false;
54935494 }
54945495
5496 pub fn boolToInt(x: bool) Value {
5497 return if (x) Value.one else Value.zero;
5498 }
5499
54955500 pub const RuntimeIndex = enum(u32) {
54965501 zero = 0,
54975502 comptime_field_ptr = std.math.maxInt(u32),
stage1/zig1.wasm
Binary files a/stage1/zig1.wasm and b/stage1/zig1.wasm differ
test/behavior/cast.zig+13
......@@ -1505,3 +1505,16 @@ test "implicit cast from [:0]T to [*c]T" {
15051505 try expect(c.len == a.len);
15061506 try expect(c.ptr == a.ptr);
15071507}
1508
1509test "bitcast packed struct with u0" {
1510 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1511 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1512 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1513
1514 const S = packed struct(u2) { a: u0, b: u2 };
1515 const s = @bitCast(S, @as(u2, 2));
1516 try expect(s.a == 0);
1517 try expect(s.b == 2);
1518 const i = @bitCast(u2, s);
1519 try expect(i == 2);
1520}
test/behavior/eval.zig+4-11
......@@ -489,18 +489,11 @@ test "comptime bitwise operators" {
489489
490490test "comptime shlWithOverflow" {
491491 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
492 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
492493
493 const ct_shifted: u64 = comptime amt: {
494 var amt = @as(u64, 0);
495 _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt);
496 break :amt amt;
497 };
498
499 const rt_shifted: u64 = amt: {
500 var amt = @as(u64, 0);
501 _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt);
502 break :amt amt;
503 };
494 const ct_shifted = @shlWithOverflow(~@as(u64, 0), 16)[0];
495 var a = ~@as(u64, 0);
496 const rt_shifted = @shlWithOverflow(a, 16)[0];
504497
505498 try expect(ct_shifted == rt_shifted);
506499}
test/behavior/math.zig+233-154
......@@ -533,6 +533,7 @@ fn testUnsignedNegationWrappingEval(x: u16) !void {
533533
534534test "negation wrapping" {
535535 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
536 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
536537 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
537538
538539 try expectEqual(@as(u1, 1), negateWrap(u1, 1));
......@@ -632,42 +633,53 @@ test "128-bit multiplication" {
632633}
633634
634635test "@addWithOverflow" {
636 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
637 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
635638 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
636639
637640 {
638 var result: u8 = undefined;
639 try expect(@addWithOverflow(u8, 250, 100, &result));
640 try expect(result == 94);
641 try expect(!@addWithOverflow(u8, 100, 150, &result));
642 try expect(result == 250);
643
641 var a: u8 = 250;
642 const ov = @addWithOverflow(a, 100);
643 try expect(ov[0] == 94);
644 try expect(ov[1] == 1);
645 }
646 {
647 var a: u8 = 100;
648 const ov = @addWithOverflow(a, 150);
649 try expect(ov[0] == 250);
650 try expect(ov[1] == 0);
651 }
652 {
644653 var a: u8 = 200;
645654 var b: u8 = 99;
646 try expect(@addWithOverflow(u8, a, b, &result));
647 try expect(result == 43);
655 var ov = @addWithOverflow(a, b);
656 try expect(ov[0] == 43);
657 try expect(ov[1] == 1);
648658 b = 55;
649 try expect(!@addWithOverflow(u8, a, b, &result));
650 try expect(result == 255);
659 ov = @addWithOverflow(a, b);
660 try expect(ov[0] == 255);
661 try expect(ov[1] == 0);
651662 }
652663
653664 {
654665 var a: usize = 6;
655666 var b: usize = 6;
656 var res: usize = undefined;
657 try expect(!@addWithOverflow(usize, a, b, &res));
658 try expect(res == 12);
667 const ov = @addWithOverflow(a, b);
668 try expect(ov[0] == 12);
669 try expect(ov[1] == 0);
659670 }
660671
661672 {
662673 var a: isize = -6;
663674 var b: isize = -6;
664 var res: isize = undefined;
665 try expect(!@addWithOverflow(isize, a, b, &res));
666 try expect(res == -12);
675 const ov = @addWithOverflow(a, b);
676 try expect(ov[0] == -12);
677 try expect(ov[1] == 0);
667678 }
668679}
669680
670681test "small int addition" {
682 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
671683 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
672684
673685 var x: u2 = 0;
......@@ -682,180 +694,206 @@ test "small int addition" {
682694 x += 1;
683695 try expect(x == 3);
684696
685 var result: @TypeOf(x) = 3;
686 try expect(@addWithOverflow(@TypeOf(x), x, 1, &result));
687
688 try expect(result == 0);
697 const ov = @addWithOverflow(x, 1);
698 try expect(ov[0] == 0);
699 try expect(ov[1] == 1);
689700}
690701
691702test "basic @mulWithOverflow" {
692 var result: u8 = undefined;
693 try expect(@mulWithOverflow(u8, 86, 3, &result));
694 try expect(result == 2);
695 try expect(!@mulWithOverflow(u8, 85, 3, &result));
696 try expect(result == 255);
703 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
704 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
705 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
706
707 {
708 var a: u8 = 86;
709 const ov = @mulWithOverflow(a, 3);
710 try expect(ov[0] == 2);
711 try expect(ov[1] == 1);
712 }
713 {
714 var a: u8 = 85;
715 const ov = @mulWithOverflow(a, 3);
716 try expect(ov[0] == 255);
717 try expect(ov[1] == 0);
718 }
697719
698720 var a: u8 = 123;
699721 var b: u8 = 2;
700 try expect(!@mulWithOverflow(u8, a, b, &result));
701 try expect(result == 246);
722 var ov = @mulWithOverflow(a, b);
723 try expect(ov[0] == 246);
724 try expect(ov[1] == 0);
702725
703726 b = 4;
704 try expect(@mulWithOverflow(u8, a, b, &result));
705 try expect(result == 236);
727 ov = @mulWithOverflow(a, b);
728 try expect(ov[0] == 236);
729 try expect(ov[1] == 1);
706730}
707731
708// TODO migrate to this for all backends once they handle more cases
709732test "extensive @mulWithOverflow" {
733 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
710734 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
735 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
711736
712737 {
713738 var a: u5 = 3;
714739 var b: u5 = 10;
715 var res: u5 = undefined;
716 try expect(!@mulWithOverflow(u5, a, b, &res));
717 try expect(res == 30);
740 var ov = @mulWithOverflow(a, b);
741 try expect(ov[0] == 30);
742 try expect(ov[1] == 0);
718743
719744 b = 11;
720 try expect(@mulWithOverflow(u5, a, b, &res));
721 try expect(res == 1);
745 ov = @mulWithOverflow(a, b);
746 try expect(ov[0] == 1);
747 try expect(ov[1] == 1);
722748 }
723749
724750 {
725751 var a: i5 = 3;
726752 var b: i5 = -5;
727 var res: i5 = undefined;
728 try expect(!@mulWithOverflow(i5, a, b, &res));
729 try expect(res == -15);
753 var ov = @mulWithOverflow(a, b);
754 try expect(ov[0] == -15);
755 try expect(ov[1] == 0);
730756
731757 b = -6;
732 try expect(@mulWithOverflow(i5, a, b, &res));
733 try expect(res == 14);
758 ov = @mulWithOverflow(a, b);
759 try expect(ov[0] == 14);
760 try expect(ov[1] == 1);
734761 }
735762
736763 {
737764 var a: u8 = 3;
738765 var b: u8 = 85;
739 var res: u8 = undefined;
740766
741 try expect(!@mulWithOverflow(u8, a, b, &res));
742 try expect(res == 255);
767 var ov = @mulWithOverflow(a, b);
768 try expect(ov[0] == 255);
769 try expect(ov[1] == 0);
743770
744771 b = 86;
745 try expect(@mulWithOverflow(u8, a, b, &res));
746 try expect(res == 2);
772 ov = @mulWithOverflow(a, b);
773 try expect(ov[0] == 2);
774 try expect(ov[1] == 1);
747775 }
748776
749777 {
750778 var a: i8 = 3;
751779 var b: i8 = -42;
752 var res: i8 = undefined;
753 try expect(!@mulWithOverflow(i8, a, b, &res));
754 try expect(res == -126);
780 var ov = @mulWithOverflow(a, b);
781 try expect(ov[0] == -126);
782 try expect(ov[1] == 0);
755783
756784 b = -43;
757 try expect(@mulWithOverflow(i8, a, b, &res));
758 try expect(res == 127);
785 ov = @mulWithOverflow(a, b);
786 try expect(ov[0] == 127);
787 try expect(ov[1] == 1);
759788 }
760789
761790 {
762791 var a: u14 = 3;
763792 var b: u14 = 0x1555;
764 var res: u14 = undefined;
765 try expect(!@mulWithOverflow(u14, a, b, &res));
766 try expect(res == 0x3fff);
793 var ov = @mulWithOverflow(a, b);
794 try expect(ov[0] == 0x3fff);
795 try expect(ov[1] == 0);
767796
768797 b = 0x1556;
769 try expect(@mulWithOverflow(u14, a, b, &res));
770 try expect(res == 2);
798 ov = @mulWithOverflow(a, b);
799 try expect(ov[0] == 2);
800 try expect(ov[1] == 1);
771801 }
772802
773803 {
774804 var a: i14 = 3;
775805 var b: i14 = -0xaaa;
776 var res: i14 = undefined;
777 try expect(!@mulWithOverflow(i14, a, b, &res));
778 try expect(res == -0x1ffe);
806 var ov = @mulWithOverflow(a, b);
807 try expect(ov[0] == -0x1ffe);
808 try expect(ov[1] == 0);
779809
780810 b = -0xaab;
781 try expect(@mulWithOverflow(i14, a, b, &res));
782 try expect(res == 0x1fff);
811 ov = @mulWithOverflow(a, b);
812 try expect(ov[0] == 0x1fff);
783813 }
784814
785815 {
786816 var a: u16 = 3;
787817 var b: u16 = 0x5555;
788 var res: u16 = undefined;
789 try expect(!@mulWithOverflow(u16, a, b, &res));
790 try expect(res == 0xffff);
818 var ov = @mulWithOverflow(a, b);
819 try expect(ov[0] == 0xffff);
820 try expect(ov[1] == 0);
791821
792822 b = 0x5556;
793 try expect(@mulWithOverflow(u16, a, b, &res));
794 try expect(res == 2);
823 ov = @mulWithOverflow(a, b);
824 try expect(ov[0] == 2);
825 try expect(ov[1] == 1);
795826 }
796827
797828 {
798829 var a: i16 = 3;
799830 var b: i16 = -0x2aaa;
800 var res: i16 = undefined;
801 try expect(!@mulWithOverflow(i16, a, b, &res));
802 try expect(res == -0x7ffe);
831 var ov = @mulWithOverflow(a, b);
832 try expect(ov[0] == -0x7ffe);
833 try expect(ov[1] == 0);
803834
804835 b = -0x2aab;
805 try expect(@mulWithOverflow(i16, a, b, &res));
806 try expect(res == 0x7fff);
836 ov = @mulWithOverflow(a, b);
837 try expect(ov[0] == 0x7fff);
838 try expect(ov[1] == 1);
807839 }
808840
809841 {
810842 var a: u30 = 3;
811843 var b: u30 = 0x15555555;
812 var res: u30 = undefined;
813 try expect(!@mulWithOverflow(u30, a, b, &res));
814 try expect(res == 0x3fffffff);
844 var ov = @mulWithOverflow(a, b);
845 try expect(ov[0] == 0x3fffffff);
846 try expect(ov[1] == 0);
815847
816848 b = 0x15555556;
817 try expect(@mulWithOverflow(u30, a, b, &res));
818 try expect(res == 2);
849 ov = @mulWithOverflow(a, b);
850 try expect(ov[0] == 2);
851 try expect(ov[1] == 1);
819852 }
820853
821854 {
822855 var a: i30 = 3;
823856 var b: i30 = -0xaaaaaaa;
824 var res: i30 = undefined;
825 try expect(!@mulWithOverflow(i30, a, b, &res));
826 try expect(res == -0x1ffffffe);
857 var ov = @mulWithOverflow(a, b);
858 try expect(ov[0] == -0x1ffffffe);
859 try expect(ov[1] == 0);
827860
828861 b = -0xaaaaaab;
829 try expect(@mulWithOverflow(i30, a, b, &res));
830 try expect(res == 0x1fffffff);
862 ov = @mulWithOverflow(a, b);
863 try expect(ov[0] == 0x1fffffff);
864 try expect(ov[1] == 1);
831865 }
832866
833867 {
834868 var a: u32 = 3;
835869 var b: u32 = 0x55555555;
836 var res: u32 = undefined;
837 try expect(!@mulWithOverflow(u32, a, b, &res));
838 try expect(res == 0xffffffff);
870 var ov = @mulWithOverflow(a, b);
871 try expect(ov[0] == 0xffffffff);
872 try expect(ov[1] == 0);
839873
840874 b = 0x55555556;
841 try expect(@mulWithOverflow(u32, a, b, &res));
842 try expect(res == 2);
875 ov = @mulWithOverflow(a, b);
876 try expect(ov[0] == 2);
877 try expect(ov[1] == 1);
843878 }
844879
845880 {
846881 var a: i32 = 3;
847882 var b: i32 = -0x2aaaaaaa;
848 var res: i32 = undefined;
849 try expect(!@mulWithOverflow(i32, a, b, &res));
850 try expect(res == -0x7ffffffe);
883 var ov = @mulWithOverflow(a, b);
884 try expect(ov[0] == -0x7ffffffe);
885 try expect(ov[1] == 0);
851886
852887 b = -0x2aaaaaab;
853 try expect(@mulWithOverflow(i32, a, b, &res));
854 try expect(res == 0x7fffffff);
888 ov = @mulWithOverflow(a, b);
889 try expect(ov[0] == 0x7fffffff);
890 try expect(ov[1] == 1);
855891 }
856892}
857893
858894test "@mulWithOverflow bitsize > 32" {
895 // aarch64 fails on a release build of the compiler.
896 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
859897 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
860898 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
861899 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -863,140 +901,181 @@ test "@mulWithOverflow bitsize > 32" {
863901 {
864902 var a: u62 = 3;
865903 var b: u62 = 0x1555555555555555;
866 var res: u62 = undefined;
867 try expect(!@mulWithOverflow(u62, a, b, &res));
868 try expect(res == 0x3fffffffffffffff);
904 var ov = @mulWithOverflow(a, b);
905 try expect(ov[0] == 0x3fffffffffffffff);
906 try expect(ov[1] == 0);
869907
870908 b = 0x1555555555555556;
871 try expect(@mulWithOverflow(u62, a, b, &res));
872 try expect(res == 2);
909 ov = @mulWithOverflow(a, b);
910 try expect(ov[0] == 2);
911 try expect(ov[1] == 1);
873912 }
874913
875914 {
876915 var a: i62 = 3;
877916 var b: i62 = -0xaaaaaaaaaaaaaaa;
878 var res: i62 = undefined;
879 try expect(!@mulWithOverflow(i62, a, b, &res));
880 try expect(res == -0x1ffffffffffffffe);
917 var ov = @mulWithOverflow(a, b);
918 try expect(ov[0] == -0x1ffffffffffffffe);
919 try expect(ov[1] == 0);
881920
882921 b = -0xaaaaaaaaaaaaaab;
883 try expect(@mulWithOverflow(i62, a, b, &res));
884 try expect(res == 0x1fffffffffffffff);
922 ov = @mulWithOverflow(a, b);
923 try expect(ov[0] == 0x1fffffffffffffff);
924 try expect(ov[1] == 1);
885925 }
886926
887927 {
888928 var a: u64 = 3;
889929 var b: u64 = 0x5555555555555555;
890 var res: u64 = undefined;
891 try expect(!@mulWithOverflow(u64, a, b, &res));
892 try expect(res == 0xffffffffffffffff);
930 var ov = @mulWithOverflow(a, b);
931 try expect(ov[0] == 0xffffffffffffffff);
932 try expect(ov[1] == 0);
893933
894934 b = 0x5555555555555556;
895 try expect(@mulWithOverflow(u64, a, b, &res));
896 try expect(res == 2);
935 ov = @mulWithOverflow(a, b);
936 try expect(ov[0] == 2);
937 try expect(ov[1] == 1);
897938 }
898939
899940 {
900941 var a: i64 = 3;
901942 var b: i64 = -0x2aaaaaaaaaaaaaaa;
902 var res: i64 = undefined;
903 try expect(!@mulWithOverflow(i64, a, b, &res));
904 try expect(res == -0x7ffffffffffffffe);
943 var ov = @mulWithOverflow(a, b);
944 try expect(ov[0] == -0x7ffffffffffffffe);
945 try expect(ov[1] == 0);
905946
906947 b = -0x2aaaaaaaaaaaaaab;
907 try expect(@mulWithOverflow(i64, a, b, &res));
908 try expect(res == 0x7fffffffffffffff);
948 ov = @mulWithOverflow(a, b);
949 try expect(ov[0] == 0x7fffffffffffffff);
950 try expect(ov[1] == 1);
909951 }
910952}
911953
912954test "@subWithOverflow" {
955 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
956 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
913957 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
914958
915959 {
916 var result: u8 = undefined;
917 try expect(@subWithOverflow(u8, 1, 2, &result));
918 try expect(result == 255);
919 try expect(!@subWithOverflow(u8, 1, 1, &result));
920 try expect(result == 0);
960 var a: u8 = 1;
961 const ov = @subWithOverflow(a, 2);
962 try expect(ov[0] == 255);
963 try expect(ov[1] == 1);
964 }
965 {
966 var a: u8 = 1;
967 const ov = @subWithOverflow(a, 1);
968 try expect(ov[0] == 0);
969 try expect(ov[1] == 0);
970 }
921971
972 {
922973 var a: u8 = 1;
923974 var b: u8 = 2;
924 try expect(@subWithOverflow(u8, a, b, &result));
925 try expect(result == 255);
975 var ov = @subWithOverflow(a, b);
976 try expect(ov[0] == 255);
977 try expect(ov[1] == 1);
926978 b = 1;
927 try expect(!@subWithOverflow(u8, a, b, &result));
928 try expect(result == 0);
979 ov = @subWithOverflow(a, b);
980 try expect(ov[0] == 0);
981 try expect(ov[1] == 0);
929982 }
930983
931984 {
932985 var a: usize = 6;
933986 var b: usize = 6;
934 var res: usize = undefined;
935 try expect(!@subWithOverflow(usize, a, b, &res));
936 try expect(res == 0);
987 const ov = @subWithOverflow(a, b);
988 try expect(ov[0] == 0);
989 try expect(ov[1] == 0);
937990 }
938991
939992 {
940993 var a: isize = -6;
941994 var b: isize = -6;
942 var res: isize = undefined;
943 try expect(!@subWithOverflow(isize, a, b, &res));
944 try expect(res == 0);
995 const ov = @subWithOverflow(a, b);
996 try expect(ov[0] == 0);
997 try expect(ov[1] == 0);
945998 }
946999}
9471000
9481001test "@shlWithOverflow" {
1002 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1003 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1004 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
9491005 {
950 var result: u4 = undefined;
9511006 var a: u4 = 2;
9521007 var b: u2 = 1;
953 try expect(!@shlWithOverflow(u4, a, b, &result));
954 try expect(result == 4);
1008 var ov = @shlWithOverflow(a, b);
1009 try expect(ov[0] == 4);
1010 try expect(ov[1] == 0);
9551011
9561012 b = 3;
957 try expect(@shlWithOverflow(u4, a, b, &result));
958 try expect(result == 0);
1013 ov = @shlWithOverflow(a, b);
1014 try expect(ov[0] == 0);
1015 try expect(ov[1] == 1);
9591016 }
9601017
9611018 {
962 var result: i9 = undefined;
9631019 var a: i9 = 127;
9641020 var b: u4 = 1;
965 try expect(!@shlWithOverflow(i9, a, b, &result));
966 try expect(result == 254);
1021 var ov = @shlWithOverflow(a, b);
1022 try expect(ov[0] == 254);
1023 try expect(ov[1] == 0);
9671024
9681025 b = 2;
969 try expect(@shlWithOverflow(i9, a, b, &result));
970 try expect(result == -4);
1026 ov = @shlWithOverflow(a, b);
1027 try expect(ov[0] == -4);
1028 try expect(ov[1] == 1);
9711029 }
9721030
9731031 {
974 var result: u16 = undefined;
975 try expect(@shlWithOverflow(u16, 0b0010111111111111, 3, &result));
976 try expect(result == 0b0111111111111000);
977 try expect(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result));
978 try expect(result == 0b1011111111111100);
979
1032 const ov = @shlWithOverflow(@as(u16, 0b0010111111111111), 3);
1033 try expect(ov[0] == 0b0111111111111000);
1034 try expect(ov[1] == 1);
1035 }
1036 {
1037 const ov = @shlWithOverflow(@as(u16, 0b0010111111111111), 2);
1038 try expect(ov[0] == 0b1011111111111100);
1039 try expect(ov[1] == 0);
1040 }
1041 {
9801042 var a: u16 = 0b0000_0000_0000_0011;
9811043 var b: u4 = 15;
982 try expect(@shlWithOverflow(u16, a, b, &result));
983 try expect(result == 0b1000_0000_0000_0000);
1044 var ov = @shlWithOverflow(a, b);
1045 try expect(ov[0] == 0b1000_0000_0000_0000);
1046 try expect(ov[1] == 1);
9841047 b = 14;
985 try expect(!@shlWithOverflow(u16, a, b, &result));
986 try expect(result == 0b1100_0000_0000_0000);
1048 ov = @shlWithOverflow(a, b);
1049 try expect(ov[0] == 0b1100_0000_0000_0000);
1050 try expect(ov[1] == 0);
9871051 }
9881052}
9891053
9901054test "overflow arithmetic with u0 values" {
991 var result: u0 = undefined;
992 try expect(!@addWithOverflow(u0, 0, 0, &result));
993 try expect(result == 0);
994 try expect(!@subWithOverflow(u0, 0, 0, &result));
995 try expect(result == 0);
996 try expect(!@mulWithOverflow(u0, 0, 0, &result));
997 try expect(result == 0);
998 try expect(!@shlWithOverflow(u0, 0, 0, &result));
999 try expect(result == 0);
1055 {
1056 var a: u0 = 0;
1057 const ov = @addWithOverflow(a, 0);
1058 try expect(ov[1] == 0);
1059 try expect(ov[1] == 0);
1060 }
1061 {
1062 var a: u0 = 0;
1063 const ov = @subWithOverflow(a, 0);
1064 try expect(ov[1] == 0);
1065 try expect(ov[1] == 0);
1066 }
1067 {
1068 var a: u0 = 0;
1069 const ov = @mulWithOverflow(a, 0);
1070 try expect(ov[1] == 0);
1071 try expect(ov[1] == 0);
1072 }
1073 {
1074 var a: u0 = 0;
1075 const ov = @shlWithOverflow(a, 0);
1076 try expect(ov[1] == 0);
1077 try expect(ov[1] == 0);
1078 }
10001079}
10011080
10021081test "allow signed integer division/remainder when values are comptime-known and positive or exact" {
test/behavior/vector.zig+29-26
......@@ -963,35 +963,31 @@ test "@addWithOverflow" {
963963 const S = struct {
964964 fn doTheTest() !void {
965965 {
966 var result: @Vector(4, u8) = undefined;
967966 var lhs = @Vector(4, u8){ 250, 250, 250, 250 };
968967 var rhs = @Vector(4, u8){ 0, 5, 6, 10 };
969 var overflow = @addWithOverflow(@Vector(4, u8), lhs, rhs, &result);
970 var expected: @Vector(4, bool) = .{ false, false, true, true };
968 var overflow = @addWithOverflow(lhs, rhs)[1];
969 var expected: @Vector(4, u1) = .{ 0, 0, 1, 1 };
971970 try expectEqual(expected, overflow);
972971 }
973972 {
974 var result: @Vector(4, i8) = undefined;
975973 var lhs = @Vector(4, i8){ -125, -125, 125, 125 };
976974 var rhs = @Vector(4, i8){ -3, -4, 2, 3 };
977 var overflow = @addWithOverflow(@Vector(4, i8), lhs, rhs, &result);
978 var expected: @Vector(4, bool) = .{ false, true, false, true };
975 var overflow = @addWithOverflow(lhs, rhs)[1];
976 var expected: @Vector(4, u1) = .{ 0, 1, 0, 1 };
979977 try expectEqual(expected, overflow);
980978 }
981979 {
982 var result: @Vector(4, u1) = undefined;
983980 var lhs = @Vector(4, u1){ 0, 0, 1, 1 };
984981 var rhs = @Vector(4, u1){ 0, 1, 0, 1 };
985 var overflow = @addWithOverflow(@Vector(4, u1), lhs, rhs, &result);
986 var expected: @Vector(4, bool) = .{ false, false, false, true };
982 var overflow = @addWithOverflow(lhs, rhs)[1];
983 var expected: @Vector(4, u1) = .{ 0, 0, 0, 1 };
987984 try expectEqual(expected, overflow);
988985 }
989986 {
990 var result: @Vector(4, u0) = undefined;
991987 var lhs = @Vector(4, u0){ 0, 0, 0, 0 };
992988 var rhs = @Vector(4, u0){ 0, 0, 0, 0 };
993 var overflow = @addWithOverflow(@Vector(4, u0), lhs, rhs, &result);
994 var expected: @Vector(4, bool) = .{ false, false, false, false };
989 var overflow = @addWithOverflow(lhs, rhs)[1];
990 var expected: @Vector(4, u1) = .{ 0, 0, 0, 0 };
995991 try expectEqual(expected, overflow);
996992 }
997993 }
......@@ -1010,19 +1006,17 @@ test "@subWithOverflow" {
10101006 const S = struct {
10111007 fn doTheTest() !void {
10121008 {
1013 var result: @Vector(2, u8) = undefined;
10141009 var lhs = @Vector(2, u8){ 5, 5 };
10151010 var rhs = @Vector(2, u8){ 5, 6 };
1016 var overflow = @subWithOverflow(@Vector(2, u8), lhs, rhs, &result);
1017 var expected: @Vector(2, bool) = .{ false, true };
1011 var overflow = @subWithOverflow(lhs, rhs)[1];
1012 var expected: @Vector(2, u1) = .{ 0, 1 };
10181013 try expectEqual(expected, overflow);
10191014 }
10201015 {
1021 var result: @Vector(4, i8) = undefined;
10221016 var lhs = @Vector(4, i8){ -120, -120, 120, 120 };
10231017 var rhs = @Vector(4, i8){ 8, 9, -7, -8 };
1024 var overflow = @subWithOverflow(@Vector(4, i8), lhs, rhs, &result);
1025 var expected: @Vector(4, bool) = .{ false, true, false, true };
1018 var overflow = @subWithOverflow(lhs, rhs)[1];
1019 var expected: @Vector(4, u1) = .{ 0, 1, 0, 1 };
10261020 try expectEqual(expected, overflow);
10271021 }
10281022 }
......@@ -1040,11 +1034,10 @@ test "@mulWithOverflow" {
10401034
10411035 const S = struct {
10421036 fn doTheTest() !void {
1043 var result: @Vector(4, u8) = undefined;
10441037 var lhs = @Vector(4, u8){ 10, 10, 10, 10 };
10451038 var rhs = @Vector(4, u8){ 25, 26, 0, 30 };
1046 var overflow = @mulWithOverflow(@Vector(4, u8), lhs, rhs, &result);
1047 var expected: @Vector(4, bool) = .{ false, true, false, true };
1039 var overflow = @mulWithOverflow(lhs, rhs)[1];
1040 var expected: @Vector(4, u1) = .{ 0, 1, 0, 1 };
10481041 try expectEqual(expected, overflow);
10491042 }
10501043 };
......@@ -1062,11 +1055,10 @@ test "@shlWithOverflow" {
10621055
10631056 const S = struct {
10641057 fn doTheTest() !void {
1065 var result: @Vector(4, u8) = undefined;
10661058 var lhs = @Vector(4, u8){ 0, 1, 8, 255 };
10671059 var rhs = @Vector(4, u3){ 7, 7, 7, 7 };
1068 var overflow = @shlWithOverflow(@Vector(4, u8), lhs, rhs, &result);
1069 var expected: @Vector(4, bool) = .{ false, false, true, true };
1060 var overflow = @shlWithOverflow(lhs, rhs)[1];
1061 var expected: @Vector(4, u1) = .{ 0, 0, 1, 1 };
10701062 try expectEqual(expected, overflow);
10711063 }
10721064 };
......@@ -1136,8 +1128,19 @@ test "byte vector initialized in inline function" {
11361128}
11371129
11381130test "byte vector initialized in inline function" {
1139 // TODO https://github.com/ziglang/zig/issues/13279
1140 if (true) return error.SkipZigTest;
1131 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1132 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1133 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1134 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1135 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1136 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1137
1138 if (comptime builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and
1139 builtin.cpu.features.isEnabled(@enumToInt(std.Target.x86.Feature.avx512f)))
1140 {
1141 // TODO https://github.com/ziglang/zig/issues/13279
1142 return error.SkipZigTest;
1143 }
11411144
11421145 const S = struct {
11431146 fn boolx4(e0: bool, e1: bool, e2: bool, e3: bool) @Vector(4, bool) {