authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-12-21 16:40:30+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-12-27 15:13:14+02:00
log622311fb9ac7ee6d93dcb8cda4b608751f7e092a
treeef54a9f6bc53919a4ef4f01aae2d9e3573aad871
parent54160e7f6aecb4628df633ceaef4c6d956429a3d

update uses of overflow arithmetic builtins


29 files changed, 568 insertions(+), 435 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/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 {
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
......@@ -534,6 +534,7 @@ fn testUnsignedNegationWrappingEval(x: u16) !void {
534534
535535test "negation wrapping" {
536536 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
537 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
537538 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
538539
539540 try expectEqual(@as(u1, 1), negateWrap(u1, 1));
......@@ -634,42 +635,53 @@ test "128-bit multiplication" {
634635}
635636
636637test "@addWithOverflow" {
638 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
639 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
637640 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
638641
639642 {
640 var result: u8 = undefined;
641 try expect(@addWithOverflow(u8, 250, 100, &result));
642 try expect(result == 94);
643 try expect(!@addWithOverflow(u8, 100, 150, &result));
644 try expect(result == 250);
645
643 var a: u8 = 250;
644 const ov = @addWithOverflow(a, 100);
645 try expect(ov[0] == 94);
646 try expect(ov[1] == 1);
647 }
648 {
649 var a: u8 = 100;
650 const ov = @addWithOverflow(a, 150);
651 try expect(ov[0] == 250);
652 try expect(ov[1] == 0);
653 }
654 {
646655 var a: u8 = 200;
647656 var b: u8 = 99;
648 try expect(@addWithOverflow(u8, a, b, &result));
649 try expect(result == 43);
657 var ov = @addWithOverflow(a, b);
658 try expect(ov[0] == 43);
659 try expect(ov[1] == 1);
650660 b = 55;
651 try expect(!@addWithOverflow(u8, a, b, &result));
652 try expect(result == 255);
661 ov = @addWithOverflow(a, b);
662 try expect(ov[0] == 255);
663 try expect(ov[1] == 0);
653664 }
654665
655666 {
656667 var a: usize = 6;
657668 var b: usize = 6;
658 var res: usize = undefined;
659 try expect(!@addWithOverflow(usize, a, b, &res));
660 try expect(res == 12);
669 const ov = @addWithOverflow(a, b);
670 try expect(ov[0] == 12);
671 try expect(ov[1] == 0);
661672 }
662673
663674 {
664675 var a: isize = -6;
665676 var b: isize = -6;
666 var res: isize = undefined;
667 try expect(!@addWithOverflow(isize, a, b, &res));
668 try expect(res == -12);
677 const ov = @addWithOverflow(a, b);
678 try expect(ov[0] == -12);
679 try expect(ov[1] == 0);
669680 }
670681}
671682
672683test "small int addition" {
684 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
673685 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
674686
675687 var x: u2 = 0;
......@@ -684,180 +696,206 @@ test "small int addition" {
684696 x += 1;
685697 try expect(x == 3);
686698
687 var result: @TypeOf(x) = 3;
688 try expect(@addWithOverflow(@TypeOf(x), x, 1, &result));
689
690 try expect(result == 0);
699 const ov = @addWithOverflow(x, 1);
700 try expect(ov[0] == 0);
701 try expect(ov[1] == 1);
691702}
692703
693704test "basic @mulWithOverflow" {
694 var result: u8 = undefined;
695 try expect(@mulWithOverflow(u8, 86, 3, &result));
696 try expect(result == 2);
697 try expect(!@mulWithOverflow(u8, 85, 3, &result));
698 try expect(result == 255);
705 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
706 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
707 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
708
709 {
710 var a: u8 = 86;
711 const ov = @mulWithOverflow(a, 3);
712 try expect(ov[0] == 2);
713 try expect(ov[1] == 1);
714 }
715 {
716 var a: u8 = 85;
717 const ov = @mulWithOverflow(a, 3);
718 try expect(ov[0] == 255);
719 try expect(ov[1] == 0);
720 }
699721
700722 var a: u8 = 123;
701723 var b: u8 = 2;
702 try expect(!@mulWithOverflow(u8, a, b, &result));
703 try expect(result == 246);
724 var ov = @mulWithOverflow(a, b);
725 try expect(ov[0] == 246);
726 try expect(ov[1] == 0);
704727
705728 b = 4;
706 try expect(@mulWithOverflow(u8, a, b, &result));
707 try expect(result == 236);
729 ov = @mulWithOverflow(a, b);
730 try expect(ov[0] == 236);
731 try expect(ov[1] == 1);
708732}
709733
710// TODO migrate to this for all backends once they handle more cases
711734test "extensive @mulWithOverflow" {
735 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
712736 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
737 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
713738
714739 {
715740 var a: u5 = 3;
716741 var b: u5 = 10;
717 var res: u5 = undefined;
718 try expect(!@mulWithOverflow(u5, a, b, &res));
719 try expect(res == 30);
742 var ov = @mulWithOverflow(a, b);
743 try expect(ov[0] == 30);
744 try expect(ov[1] == 0);
720745
721746 b = 11;
722 try expect(@mulWithOverflow(u5, a, b, &res));
723 try expect(res == 1);
747 ov = @mulWithOverflow(a, b);
748 try expect(ov[0] == 1);
749 try expect(ov[1] == 1);
724750 }
725751
726752 {
727753 var a: i5 = 3;
728754 var b: i5 = -5;
729 var res: i5 = undefined;
730 try expect(!@mulWithOverflow(i5, a, b, &res));
731 try expect(res == -15);
755 var ov = @mulWithOverflow(a, b);
756 try expect(ov[0] == -15);
757 try expect(ov[1] == 0);
732758
733759 b = -6;
734 try expect(@mulWithOverflow(i5, a, b, &res));
735 try expect(res == 14);
760 ov = @mulWithOverflow(a, b);
761 try expect(ov[0] == 14);
762 try expect(ov[1] == 1);
736763 }
737764
738765 {
739766 var a: u8 = 3;
740767 var b: u8 = 85;
741 var res: u8 = undefined;
742768
743 try expect(!@mulWithOverflow(u8, a, b, &res));
744 try expect(res == 255);
769 var ov = @mulWithOverflow(a, b);
770 try expect(ov[0] == 255);
771 try expect(ov[1] == 0);
745772
746773 b = 86;
747 try expect(@mulWithOverflow(u8, a, b, &res));
748 try expect(res == 2);
774 ov = @mulWithOverflow(a, b);
775 try expect(ov[0] == 2);
776 try expect(ov[1] == 1);
749777 }
750778
751779 {
752780 var a: i8 = 3;
753781 var b: i8 = -42;
754 var res: i8 = undefined;
755 try expect(!@mulWithOverflow(i8, a, b, &res));
756 try expect(res == -126);
782 var ov = @mulWithOverflow(a, b);
783 try expect(ov[0] == -126);
784 try expect(ov[1] == 0);
757785
758786 b = -43;
759 try expect(@mulWithOverflow(i8, a, b, &res));
760 try expect(res == 127);
787 ov = @mulWithOverflow(a, b);
788 try expect(ov[0] == 127);
789 try expect(ov[1] == 1);
761790 }
762791
763792 {
764793 var a: u14 = 3;
765794 var b: u14 = 0x1555;
766 var res: u14 = undefined;
767 try expect(!@mulWithOverflow(u14, a, b, &res));
768 try expect(res == 0x3fff);
795 var ov = @mulWithOverflow(a, b);
796 try expect(ov[0] == 0x3fff);
797 try expect(ov[1] == 0);
769798
770799 b = 0x1556;
771 try expect(@mulWithOverflow(u14, a, b, &res));
772 try expect(res == 2);
800 ov = @mulWithOverflow(a, b);
801 try expect(ov[0] == 2);
802 try expect(ov[1] == 1);
773803 }
774804
775805 {
776806 var a: i14 = 3;
777807 var b: i14 = -0xaaa;
778 var res: i14 = undefined;
779 try expect(!@mulWithOverflow(i14, a, b, &res));
780 try expect(res == -0x1ffe);
808 var ov = @mulWithOverflow(a, b);
809 try expect(ov[0] == -0x1ffe);
810 try expect(ov[1] == 0);
781811
782812 b = -0xaab;
783 try expect(@mulWithOverflow(i14, a, b, &res));
784 try expect(res == 0x1fff);
813 ov = @mulWithOverflow(a, b);
814 try expect(ov[0] == 0x1fff);
785815 }
786816
787817 {
788818 var a: u16 = 3;
789819 var b: u16 = 0x5555;
790 var res: u16 = undefined;
791 try expect(!@mulWithOverflow(u16, a, b, &res));
792 try expect(res == 0xffff);
820 var ov = @mulWithOverflow(a, b);
821 try expect(ov[0] == 0xffff);
822 try expect(ov[1] == 0);
793823
794824 b = 0x5556;
795 try expect(@mulWithOverflow(u16, a, b, &res));
796 try expect(res == 2);
825 ov = @mulWithOverflow(a, b);
826 try expect(ov[0] == 2);
827 try expect(ov[1] == 1);
797828 }
798829
799830 {
800831 var a: i16 = 3;
801832 var b: i16 = -0x2aaa;
802 var res: i16 = undefined;
803 try expect(!@mulWithOverflow(i16, a, b, &res));
804 try expect(res == -0x7ffe);
833 var ov = @mulWithOverflow(a, b);
834 try expect(ov[0] == -0x7ffe);
835 try expect(ov[1] == 0);
805836
806837 b = -0x2aab;
807 try expect(@mulWithOverflow(i16, a, b, &res));
808 try expect(res == 0x7fff);
838 ov = @mulWithOverflow(a, b);
839 try expect(ov[0] == 0x7fff);
840 try expect(ov[1] == 1);
809841 }
810842
811843 {
812844 var a: u30 = 3;
813845 var b: u30 = 0x15555555;
814 var res: u30 = undefined;
815 try expect(!@mulWithOverflow(u30, a, b, &res));
816 try expect(res == 0x3fffffff);
846 var ov = @mulWithOverflow(a, b);
847 try expect(ov[0] == 0x3fffffff);
848 try expect(ov[1] == 0);
817849
818850 b = 0x15555556;
819 try expect(@mulWithOverflow(u30, a, b, &res));
820 try expect(res == 2);
851 ov = @mulWithOverflow(a, b);
852 try expect(ov[0] == 2);
853 try expect(ov[1] == 1);
821854 }
822855
823856 {
824857 var a: i30 = 3;
825858 var b: i30 = -0xaaaaaaa;
826 var res: i30 = undefined;
827 try expect(!@mulWithOverflow(i30, a, b, &res));
828 try expect(res == -0x1ffffffe);
859 var ov = @mulWithOverflow(a, b);
860 try expect(ov[0] == -0x1ffffffe);
861 try expect(ov[1] == 0);
829862
830863 b = -0xaaaaaab;
831 try expect(@mulWithOverflow(i30, a, b, &res));
832 try expect(res == 0x1fffffff);
864 ov = @mulWithOverflow(a, b);
865 try expect(ov[0] == 0x1fffffff);
866 try expect(ov[1] == 1);
833867 }
834868
835869 {
836870 var a: u32 = 3;
837871 var b: u32 = 0x55555555;
838 var res: u32 = undefined;
839 try expect(!@mulWithOverflow(u32, a, b, &res));
840 try expect(res == 0xffffffff);
872 var ov = @mulWithOverflow(a, b);
873 try expect(ov[0] == 0xffffffff);
874 try expect(ov[1] == 0);
841875
842876 b = 0x55555556;
843 try expect(@mulWithOverflow(u32, a, b, &res));
844 try expect(res == 2);
877 ov = @mulWithOverflow(a, b);
878 try expect(ov[0] == 2);
879 try expect(ov[1] == 1);
845880 }
846881
847882 {
848883 var a: i32 = 3;
849884 var b: i32 = -0x2aaaaaaa;
850 var res: i32 = undefined;
851 try expect(!@mulWithOverflow(i32, a, b, &res));
852 try expect(res == -0x7ffffffe);
885 var ov = @mulWithOverflow(a, b);
886 try expect(ov[0] == -0x7ffffffe);
887 try expect(ov[1] == 0);
853888
854889 b = -0x2aaaaaab;
855 try expect(@mulWithOverflow(i32, a, b, &res));
856 try expect(res == 0x7fffffff);
890 ov = @mulWithOverflow(a, b);
891 try expect(ov[0] == 0x7fffffff);
892 try expect(ov[1] == 1);
857893 }
858894}
859895
860896test "@mulWithOverflow bitsize > 32" {
897 // aarch64 fails on a release build of the compiler.
898 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
861899 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
862900 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
863901 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -865,140 +903,181 @@ test "@mulWithOverflow bitsize > 32" {
865903 {
866904 var a: u62 = 3;
867905 var b: u62 = 0x1555555555555555;
868 var res: u62 = undefined;
869 try expect(!@mulWithOverflow(u62, a, b, &res));
870 try expect(res == 0x3fffffffffffffff);
906 var ov = @mulWithOverflow(a, b);
907 try expect(ov[0] == 0x3fffffffffffffff);
908 try expect(ov[1] == 0);
871909
872910 b = 0x1555555555555556;
873 try expect(@mulWithOverflow(u62, a, b, &res));
874 try expect(res == 2);
911 ov = @mulWithOverflow(a, b);
912 try expect(ov[0] == 2);
913 try expect(ov[1] == 1);
875914 }
876915
877916 {
878917 var a: i62 = 3;
879918 var b: i62 = -0xaaaaaaaaaaaaaaa;
880 var res: i62 = undefined;
881 try expect(!@mulWithOverflow(i62, a, b, &res));
882 try expect(res == -0x1ffffffffffffffe);
919 var ov = @mulWithOverflow(a, b);
920 try expect(ov[0] == -0x1ffffffffffffffe);
921 try expect(ov[1] == 0);
883922
884923 b = -0xaaaaaaaaaaaaaab;
885 try expect(@mulWithOverflow(i62, a, b, &res));
886 try expect(res == 0x1fffffffffffffff);
924 ov = @mulWithOverflow(a, b);
925 try expect(ov[0] == 0x1fffffffffffffff);
926 try expect(ov[1] == 1);
887927 }
888928
889929 {
890930 var a: u64 = 3;
891931 var b: u64 = 0x5555555555555555;
892 var res: u64 = undefined;
893 try expect(!@mulWithOverflow(u64, a, b, &res));
894 try expect(res == 0xffffffffffffffff);
932 var ov = @mulWithOverflow(a, b);
933 try expect(ov[0] == 0xffffffffffffffff);
934 try expect(ov[1] == 0);
895935
896936 b = 0x5555555555555556;
897 try expect(@mulWithOverflow(u64, a, b, &res));
898 try expect(res == 2);
937 ov = @mulWithOverflow(a, b);
938 try expect(ov[0] == 2);
939 try expect(ov[1] == 1);
899940 }
900941
901942 {
902943 var a: i64 = 3;
903944 var b: i64 = -0x2aaaaaaaaaaaaaaa;
904 var res: i64 = undefined;
905 try expect(!@mulWithOverflow(i64, a, b, &res));
906 try expect(res == -0x7ffffffffffffffe);
945 var ov = @mulWithOverflow(a, b);
946 try expect(ov[0] == -0x7ffffffffffffffe);
947 try expect(ov[1] == 0);
907948
908949 b = -0x2aaaaaaaaaaaaaab;
909 try expect(@mulWithOverflow(i64, a, b, &res));
910 try expect(res == 0x7fffffffffffffff);
950 ov = @mulWithOverflow(a, b);
951 try expect(ov[0] == 0x7fffffffffffffff);
952 try expect(ov[1] == 1);
911953 }
912954}
913955
914956test "@subWithOverflow" {
957 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
958 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
915959 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
916960
917961 {
918 var result: u8 = undefined;
919 try expect(@subWithOverflow(u8, 1, 2, &result));
920 try expect(result == 255);
921 try expect(!@subWithOverflow(u8, 1, 1, &result));
922 try expect(result == 0);
962 var a: u8 = 1;
963 const ov = @subWithOverflow(a, 2);
964 try expect(ov[0] == 255);
965 try expect(ov[1] == 1);
966 }
967 {
968 var a: u8 = 1;
969 const ov = @subWithOverflow(a, 1);
970 try expect(ov[0] == 0);
971 try expect(ov[1] == 0);
972 }
923973
974 {
924975 var a: u8 = 1;
925976 var b: u8 = 2;
926 try expect(@subWithOverflow(u8, a, b, &result));
927 try expect(result == 255);
977 var ov = @subWithOverflow(a, b);
978 try expect(ov[0] == 255);
979 try expect(ov[1] == 1);
928980 b = 1;
929 try expect(!@subWithOverflow(u8, a, b, &result));
930 try expect(result == 0);
981 ov = @subWithOverflow(a, b);
982 try expect(ov[0] == 0);
983 try expect(ov[1] == 0);
931984 }
932985
933986 {
934987 var a: usize = 6;
935988 var b: usize = 6;
936 var res: usize = undefined;
937 try expect(!@subWithOverflow(usize, a, b, &res));
938 try expect(res == 0);
989 const ov = @subWithOverflow(a, b);
990 try expect(ov[0] == 0);
991 try expect(ov[1] == 0);
939992 }
940993
941994 {
942995 var a: isize = -6;
943996 var b: isize = -6;
944 var res: isize = undefined;
945 try expect(!@subWithOverflow(isize, a, b, &res));
946 try expect(res == 0);
997 const ov = @subWithOverflow(a, b);
998 try expect(ov[0] == 0);
999 try expect(ov[1] == 0);
9471000 }
9481001}
9491002
9501003test "@shlWithOverflow" {
1004 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1005 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1006 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
9511007 {
952 var result: u4 = undefined;
9531008 var a: u4 = 2;
9541009 var b: u2 = 1;
955 try expect(!@shlWithOverflow(u4, a, b, &result));
956 try expect(result == 4);
1010 var ov = @shlWithOverflow(a, b);
1011 try expect(ov[0] == 4);
1012 try expect(ov[1] == 0);
9571013
9581014 b = 3;
959 try expect(@shlWithOverflow(u4, a, b, &result));
960 try expect(result == 0);
1015 ov = @shlWithOverflow(a, b);
1016 try expect(ov[0] == 0);
1017 try expect(ov[1] == 1);
9611018 }
9621019
9631020 {
964 var result: i9 = undefined;
9651021 var a: i9 = 127;
9661022 var b: u4 = 1;
967 try expect(!@shlWithOverflow(i9, a, b, &result));
968 try expect(result == 254);
1023 var ov = @shlWithOverflow(a, b);
1024 try expect(ov[0] == 254);
1025 try expect(ov[1] == 0);
9691026
9701027 b = 2;
971 try expect(@shlWithOverflow(i9, a, b, &result));
972 try expect(result == -4);
1028 ov = @shlWithOverflow(a, b);
1029 try expect(ov[0] == -4);
1030 try expect(ov[1] == 1);
9731031 }
9741032
9751033 {
976 var result: u16 = undefined;
977 try expect(@shlWithOverflow(u16, 0b0010111111111111, 3, &result));
978 try expect(result == 0b0111111111111000);
979 try expect(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result));
980 try expect(result == 0b1011111111111100);
981
1034 const ov = @shlWithOverflow(@as(u16, 0b0010111111111111), 3);
1035 try expect(ov[0] == 0b0111111111111000);
1036 try expect(ov[1] == 1);
1037 }
1038 {
1039 const ov = @shlWithOverflow(@as(u16, 0b0010111111111111), 2);
1040 try expect(ov[0] == 0b1011111111111100);
1041 try expect(ov[1] == 0);
1042 }
1043 {
9821044 var a: u16 = 0b0000_0000_0000_0011;
9831045 var b: u4 = 15;
984 try expect(@shlWithOverflow(u16, a, b, &result));
985 try expect(result == 0b1000_0000_0000_0000);
1046 var ov = @shlWithOverflow(a, b);
1047 try expect(ov[0] == 0b1000_0000_0000_0000);
1048 try expect(ov[1] == 1);
9861049 b = 14;
987 try expect(!@shlWithOverflow(u16, a, b, &result));
988 try expect(result == 0b1100_0000_0000_0000);
1050 ov = @shlWithOverflow(a, b);
1051 try expect(ov[0] == 0b1100_0000_0000_0000);
1052 try expect(ov[1] == 0);
9891053 }
9901054}
9911055
9921056test "overflow arithmetic with u0 values" {
993 var result: u0 = undefined;
994 try expect(!@addWithOverflow(u0, 0, 0, &result));
995 try expect(result == 0);
996 try expect(!@subWithOverflow(u0, 0, 0, &result));
997 try expect(result == 0);
998 try expect(!@mulWithOverflow(u0, 0, 0, &result));
999 try expect(result == 0);
1000 try expect(!@shlWithOverflow(u0, 0, 0, &result));
1001 try expect(result == 0);
1057 {
1058 var a: u0 = 0;
1059 const ov = @addWithOverflow(a, 0);
1060 try expect(ov[1] == 0);
1061 try expect(ov[1] == 0);
1062 }
1063 {
1064 var a: u0 = 0;
1065 const ov = @subWithOverflow(a, 0);
1066 try expect(ov[1] == 0);
1067 try expect(ov[1] == 0);
1068 }
1069 {
1070 var a: u0 = 0;
1071 const ov = @mulWithOverflow(a, 0);
1072 try expect(ov[1] == 0);
1073 try expect(ov[1] == 0);
1074 }
1075 {
1076 var a: u0 = 0;
1077 const ov = @shlWithOverflow(a, 0);
1078 try expect(ov[1] == 0);
1079 try expect(ov[1] == 0);
1080 }
10021081}
10031082
10041083test "allow signed integer division/remainder when values are comptime-known and positive or exact" {
test/behavior/vector.zig+16-24
......@@ -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 };