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 {...@@ -5413,14 +5413,14 @@ pub fn parseU64(buf: []const u8, radix: u8) !u64 {
5413 }5413 }
54145414
5415 // x *= radix5415 // x *= radix
5416 if (@mulWithOverflow(u64, x, radix, &x)) {5416 var ov = @mulWithOverflow(x, radix);
5417 return error.Overflow;5417 if (ov[1] != 0) return error.OverFlow;
5418 }5418
54195419
5420 // x += digit5420 // x += digit
5421 if (@addWithOverflow(u64, x, digit, &x)) {5421 ov = @addWithOverflow(ov[0], digit);
5422 return error.Overflow;5422 if (ov[1] != 0) return error.OverFlow;
5423 }5423 x = ov[0];
5424 }5424 }
54255425
5426 return x;5426 return x;
...@@ -5832,14 +5832,16 @@ test "merge error sets" {...@@ -5832,14 +5832,16 @@ test "merge error sets" {
5832{#code_begin|test|inferred_error_sets#}5832{#code_begin|test|inferred_error_sets#}
5833// With an inferred error set5833// With an inferred error set
5834pub fn add_inferred(comptime T: type, a: T, b: T) !T {5834pub fn add_inferred(comptime T: type, a: T, b: T) !T {
5835 var answer: T = undefined;5835 const ov = @addWithOverflow(a, b);
5836 return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;5836 if (ov[1] != 0) return error.Overflow;
5837 return ov[0];
5837}5838}
58385839
5839// With an explicit error set5840// With an explicit error set
5840pub fn add_explicit(comptime T: type, a: T, b: T) Error!T {5841pub fn add_explicit(comptime T: type, a: T, b: T) Error!T {
5841 var answer: T = undefined;5842 const ov = @addWithOverflow(a, b);
5842 return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;5843 if (ov[1] != 0) return error.Overflow;
5844 return ov[0];
5843}5845}
58445846
5845const Error = error {5847const Error = error {
...@@ -7632,11 +7634,9 @@ test "global assembly" {...@@ -7632,11 +7634,9 @@ test "global assembly" {
7632 </p>7634 </p>
7633 {#header_close#}7635 {#header_close#}
7634 {#header_open|@addWithOverflow#}7636 {#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>
7636 <p>7638 <p>
7637 Performs {#syntax#}result.* = a + b{#endsyntax#}. If overflow or underflow occurs,7639 Performs {#syntax#}a + b{#endsyntax#} and returns a tuple with the result and a possible overflow bit.
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#}.
7640 </p>7640 </p>
7641 {#header_close#}7641 {#header_close#}
7642 {#header_open|@alignCast#}7642 {#header_open|@alignCast#}
...@@ -8695,11 +8695,9 @@ test "@wasmMemoryGrow" {...@@ -8695,11 +8695,9 @@ test "@wasmMemoryGrow" {
8695 {#header_close#}8695 {#header_close#}
86968696
8697 {#header_open|@mulWithOverflow#}8697 {#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>
8699 <p>8699 <p>
8700 Performs {#syntax#}result.* = a * b{#endsyntax#}. If overflow or underflow occurs,8700 Performs {#syntax#}a * b{#endsyntax#} and returns a tuple with the result and a possible overflow bit.
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#}.
8703 </p>8701 </p>
8704 {#header_close#}8702 {#header_close#}
87058703
...@@ -8973,15 +8971,13 @@ test "@setRuntimeSafety" {...@@ -8973,15 +8971,13 @@ test "@setRuntimeSafety" {
8973 {#header_close#}8971 {#header_close#}
89748972
8975 {#header_open|@shlWithOverflow#}8973 {#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>
8977 <p>8975 <p>
8978 Performs {#syntax#}result.* = a << b{#endsyntax#}. If overflow or underflow occurs,8976 Performs {#syntax#}a << b{#endsyntax#} and returns a tuple with the result and a possible overflow bit.
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#}.
8981 </p>8977 </p>
8982 <p>8978 <p>
8983 The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(@typeInfo(T).Int.bits){#endsyntax#} bits.8979 The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(@typeInfo(@TypeOf(a)).Int.bits){#endsyntax#} bits.
8984 This is because {#syntax#}shift_amt >= @typeInfo(T).Int.bits{#endsyntax#} is undefined behavior.8980 This is because {#syntax#}shift_amt >= @typeInfo(@TypeOf(a)).Int.bits{#endsyntax#} is undefined behavior.
8985 </p>8981 </p>
8986 {#see_also|@shlExact|@shrExact#}8982 {#see_also|@shlExact|@shrExact#}
8987 {#header_close#}8983 {#header_close#}
...@@ -9323,11 +9319,9 @@ fn doTheTest() !void {...@@ -9323,11 +9319,9 @@ fn doTheTest() !void {
9323 {#header_close#}9319 {#header_close#}
93249320
9325 {#header_open|@subWithOverflow#}9321 {#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>
9327 <p>9323 <p>
9328 Performs {#syntax#}result.* = a - b{#endsyntax#}. If overflow or underflow occurs,9324 Performs {#syntax#}a - b{#endsyntax#} and returns a tuple with the result and a possible overflow bit.
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#}.
9331 </p>9325 </p>
9332 {#header_close#}9326 {#header_close#}
93339327
...@@ -9774,11 +9768,11 @@ const print = @import("std").debug.print;...@@ -9774,11 +9768,11 @@ const print = @import("std").debug.print;
9774pub fn main() void {9768pub fn main() void {
9775 var byte: u8 = 255;9769 var byte: u8 = 255;
97769770
9777 var result: u8 = undefined;9771 const ov = @addWithOverflow(byte, 10);
9778 if (@addWithOverflow(u8, byte, 10, &result)) {9772 if (ov[1] != 0) {
9779 print("overflowed result: {}\n", .{result});9773 print("overflowed result: {}\n", .{ov[0]});
9780 } else {9774 } else {
9781 print("result: {}\n", .{result});9775 print("result: {}\n", .{ov[0]});
9782 }9776 }
9783}9777}
9784 {#code_end#}9778 {#code_end#}
lib/compiler_rt/trunctfxf2.zig+8-6
...@@ -49,14 +49,16 @@ pub fn __trunctfxf2(a: f128) callconv(.C) f80 {...@@ -49,14 +49,16 @@ pub fn __trunctfxf2(a: f128) callconv(.C) f80 {
49 const round_bits = a_abs & round_mask;49 const round_bits = a_abs & round_mask;
50 if (round_bits > halfway) {50 if (round_bits > halfway) {
51 // Round to nearest51 // Round to nearest
52 const carry = @boolToInt(@addWithOverflow(u64, res.fraction, 1, &res.fraction));52 const ov = @addWithOverflow(res.fraction, 1);
53 res.exp += carry;53 res.fraction = ov[0];
54 res.fraction |= @as(u64, carry) << 63; // Restore integer bit after carry54 res.exp += ov[1];
55 res.fraction |= @as(u64, ov[1]) << 63; // Restore integer bit after carry
55 } else if (round_bits == halfway) {56 } else if (round_bits == halfway) {
56 // Ties to even57 // Ties to even
57 const carry = @boolToInt(@addWithOverflow(u64, res.fraction, res.fraction & 1, &res.fraction));58 const ov = @addWithOverflow(res.fraction, res.fraction & 1);
58 res.exp += carry;59 res.fraction = ov[0];
59 res.fraction |= @as(u64, carry) << 63; // Restore integer bit after carry60 res.exp += ov[1];
61 res.fraction |= @as(u64, ov[1]) << 63; // Restore integer bit after carry
60 }62 }
61 if (res.exp == 0) res.fraction &= ~@as(u64, integer_bit); // Remove integer bit for de-normals63 if (res.exp == 0) res.fraction &= ~@as(u64, integer_bit); // Remove integer bit for de-normals
62 }64 }
lib/std/compress/deflate/compressor_test.zig+1-3
...@@ -172,9 +172,7 @@ test "deflate/inflate" {...@@ -172,9 +172,7 @@ test "deflate/inflate" {
172 defer testing.allocator.free(large_data_chunk);172 defer testing.allocator.free(large_data_chunk);
173 // fill with random data173 // fill with random data
174 for (large_data_chunk) |_, i| {174 for (large_data_chunk) |_, i| {
175 var mul: u8 = @truncate(u8, i);175 large_data_chunk[i] = @truncate(u8, i) *% @truncate(u8, i);
176 _ = @mulWithOverflow(u8, mul, mul, &mul);
177 large_data_chunk[i] = mul;
178 }176 }
179 try testToFromWithLimit(large_data_chunk, limits);177 try testToFromWithLimit(large_data_chunk, limits);
180}178}
lib/std/crypto/pcurves/p256/p256_64.zig+8-8
...@@ -75,10 +75,10 @@ pub const NonMontgomeryDomainFieldElement = [4]u64;...@@ -75,10 +75,10 @@ pub const NonMontgomeryDomainFieldElement = [4]u64;
75inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {75inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
76 @setRuntimeSafety(mode == .Debug);76 @setRuntimeSafety(mode == .Debug);
7777
78 var t: u64 = undefined;78 const ov1 = @addWithOverflow(arg2, arg3);
79 const carry1 = @addWithOverflow(u64, arg2, arg3, &t);79 const ov2 = @addWithOverflow(ov1[0], arg1);
80 const carry2 = @addWithOverflow(u64, t, arg1, out1);80 out1.* = ov2[0];
81 out2.* = @boolToInt(carry1) | @boolToInt(carry2);81 out2.* = ov1[1] | ov2[1];
82}82}
8383
84/// The function subborrowxU64 is a subtraction with borrow.84/// 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...@@ -97,10 +97,10 @@ inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) vo
97inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {97inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
98 @setRuntimeSafety(mode == .Debug);98 @setRuntimeSafety(mode == .Debug);
9999
100 var t: u64 = undefined;100 const ov1 = @subWithOverflow(arg2, arg3);
101 const carry1 = @subWithOverflow(u64, arg2, arg3, &t);101 const ov2 = @subWithOverflow(ov1[0], arg1);
102 const carry2 = @subWithOverflow(u64, t, arg1, out1);102 out1.* = ov2[0];
103 out2.* = @boolToInt(carry1) | @boolToInt(carry2);103 out2.* = ov1[1] | ov2[1];
104}104}
105105
106/// The function mulxU64 is a multiplication, returning the full double-width result.106/// 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;...@@ -75,10 +75,10 @@ pub const NonMontgomeryDomainFieldElement = [4]u64;
75inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {75inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
76 @setRuntimeSafety(mode == .Debug);76 @setRuntimeSafety(mode == .Debug);
7777
78 var t: u64 = undefined;78 const ov1 = @addWithOverflow(arg2, arg3);
79 const carry1 = @addWithOverflow(u64, arg2, arg3, &t);79 const ov2 = @addWithOverflow(ov1[0], arg1);
80 const carry2 = @addWithOverflow(u64, t, arg1, out1);80 out1.* = ov2[0];
81 out2.* = @boolToInt(carry1) | @boolToInt(carry2);81 out2.* = ov1[1] | ov2[1];
82}82}
8383
84/// The function subborrowxU64 is a subtraction with borrow.84/// 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...@@ -97,10 +97,10 @@ inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) vo
97inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {97inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
98 @setRuntimeSafety(mode == .Debug);98 @setRuntimeSafety(mode == .Debug);
9999
100 var t: u64 = undefined;100 const ov1 = @subWithOverflow(arg2, arg3);
101 const carry1 = @subWithOverflow(u64, arg2, arg3, &t);101 const ov2 = @subWithOverflow(ov1[0], arg1);
102 const carry2 = @subWithOverflow(u64, t, arg1, out1);102 out1.* = ov2[0];
103 out2.* = @boolToInt(carry1) | @boolToInt(carry2);103 out2.* = ov1[1] | ov2[1];
104}104}
105105
106/// The function mulxU64 is a multiplication, returning the full double-width result.106/// 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;...@@ -44,10 +44,10 @@ pub const NonMontgomeryDomainFieldElement = [6]u64;
44inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {44inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
45 @setRuntimeSafety(mode == .Debug);45 @setRuntimeSafety(mode == .Debug);
4646
47 var t: u64 = undefined;47 const ov1 = @addWithOverflow(arg2, arg3);
48 const carry1 = @addWithOverflow(u64, arg2, arg3, &t);48 const ov2 = @addWithOverflow(ov1[0], arg1);
49 const carry2 = @addWithOverflow(u64, t, arg1, out1);49 out1.* = ov2[0];
50 out2.* = @boolToInt(carry1) | @boolToInt(carry2);50 out2.* = ov1[1] | ov2[1];
51}51}
5252
53/// The function subborrowxU64 is a subtraction with borrow.53/// 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...@@ -66,10 +66,10 @@ inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) vo
66inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {66inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
67 @setRuntimeSafety(mode == .Debug);67 @setRuntimeSafety(mode == .Debug);
6868
69 var t: u64 = undefined;69 const ov1 = @subWithOverflow(arg2, arg3);
70 const carry1 = @subWithOverflow(u64, arg2, arg3, &t);70 const ov2 = @subWithOverflow(ov1[0], arg1);
71 const carry2 = @subWithOverflow(u64, t, arg1, out1);71 out1.* = ov2[0];
72 out2.* = @boolToInt(carry1) | @boolToInt(carry2);72 out2.* = ov1[1] | ov2[1];
73}73}
7474
75/// The function mulxU64 is a multiplication, returning the full double-width result.75/// 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;...@@ -44,10 +44,10 @@ pub const NonMontgomeryDomainFieldElement = [6]u64;
44inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {44inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
45 @setRuntimeSafety(mode == .Debug);45 @setRuntimeSafety(mode == .Debug);
4646
47 var t: u64 = undefined;47 const ov1 = @addWithOverflow(arg2, arg3);
48 const carry1 = @addWithOverflow(u64, arg2, arg3, &t);48 const ov2 = @addWithOverflow(ov1[0], arg1);
49 const carry2 = @addWithOverflow(u64, t, arg1, out1);49 out1.* = ov2[0];
50 out2.* = @boolToInt(carry1) | @boolToInt(carry2);50 out2.* = ov1[1] | ov2[1];
51}51}
5252
53/// The function subborrowxU64 is a subtraction with borrow.53/// 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...@@ -66,10 +66,10 @@ inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) vo
66inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {66inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
67 @setRuntimeSafety(mode == .Debug);67 @setRuntimeSafety(mode == .Debug);
6868
69 var t: u64 = undefined;69 const ov1 = @subWithOverflow(arg2, arg3);
70 const carry1 = @subWithOverflow(u64, arg2, arg3, &t);70 const ov2 = @subWithOverflow(ov1[0], arg1);
71 const carry2 = @subWithOverflow(u64, t, arg1, out1);71 out1.* = ov2[0];
72 out2.* = @boolToInt(carry1) | @boolToInt(carry2);72 out2.* = ov1[1] | ov2[1];
73}73}
7474
75/// The function mulxU64 is a multiplication, returning the full double-width result.75/// 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;...@@ -44,10 +44,10 @@ pub const NonMontgomeryDomainFieldElement = [4]u64;
44inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {44inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
45 @setRuntimeSafety(mode == .Debug);45 @setRuntimeSafety(mode == .Debug);
4646
47 var t: u64 = undefined;47 const ov1 = @addWithOverflow(arg2, arg3);
48 const carry1 = @addWithOverflow(u64, arg2, arg3, &t);48 const ov2 = @addWithOverflow(ov1[0], arg1);
49 const carry2 = @addWithOverflow(u64, t, arg1, out1);49 out1.* = ov2[0];
50 out2.* = @boolToInt(carry1) | @boolToInt(carry2);50 out2.* = ov1[1] | ov2[1];
51}51}
5252
53/// The function subborrowxU64 is a subtraction with borrow.53/// 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...@@ -66,10 +66,10 @@ inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) vo
66inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {66inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
67 @setRuntimeSafety(mode == .Debug);67 @setRuntimeSafety(mode == .Debug);
6868
69 var t: u64 = undefined;69 const ov1 = @subWithOverflow(arg2, arg3);
70 const carry1 = @subWithOverflow(u64, arg2, arg3, &t);70 const ov2 = @subWithOverflow(ov1[0], arg1);
71 const carry2 = @subWithOverflow(u64, t, arg1, out1);71 out1.* = ov2[0];
72 out2.* = @boolToInt(carry1) | @boolToInt(carry2);72 out2.* = ov1[1] | ov2[1];
73}73}
7474
75/// The function mulxU64 is a multiplication, returning the full double-width result.75/// 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;...@@ -44,10 +44,10 @@ pub const NonMontgomeryDomainFieldElement = [4]u64;
44inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {44inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
45 @setRuntimeSafety(mode == .Debug);45 @setRuntimeSafety(mode == .Debug);
4646
47 var t: u64 = undefined;47 const ov1 = @addWithOverflow(arg2, arg3);
48 const carry1 = @addWithOverflow(u64, arg2, arg3, &t);48 const ov2 = @addWithOverflow(ov1[0], arg1);
49 const carry2 = @addWithOverflow(u64, t, arg1, out1);49 out1.* = ov2[0];
50 out2.* = @boolToInt(carry1) | @boolToInt(carry2);50 out2.* = ov1[1] | ov2[1];
51}51}
5252
53/// The function subborrowxU64 is a subtraction with borrow.53/// 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...@@ -66,10 +66,10 @@ inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) vo
66inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {66inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
67 @setRuntimeSafety(mode == .Debug);67 @setRuntimeSafety(mode == .Debug);
6868
69 var t: u64 = undefined;69 const ov1 = @subWithOverflow(arg2, arg3);
70 const carry1 = @subWithOverflow(u64, arg2, arg3, &t);70 const ov2 = @subWithOverflow(ov1[0], arg1);
71 const carry2 = @subWithOverflow(u64, t, arg1, out1);71 out1.* = ov2[0];
72 out2.* = @boolToInt(carry1) | @boolToInt(carry2);72 out2.* = ov1[1] | ov2[1];
73}73}
7474
75/// The function mulxU64 is a multiplication, returning the full double-width result.75/// 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 {...@@ -263,7 +263,9 @@ fn SalsaNonVecImpl(comptime rounds: comptime_int) type {
263 while (j < 64) : (j += 1) {263 while (j < 64) : (j += 1) {
264 xout[j] ^= buf[j];264 xout[j] ^= buf[j];
265 }265 }
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];
267 }269 }
268 if (i < in.len) {270 if (i < in.len) {
269 salsaCore(x[0..], ctx, true);271 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,...@@ -87,15 +87,19 @@ pub fn timingSafeAdd(comptime T: type, a: []const T, b: []const T, result: []T,
87 if (endian == .Little) {87 if (endian == .Little) {
88 var i: usize = 0;88 var i: usize = 0;
89 while (i < len) : (i += 1) {89 while (i < len) : (i += 1) {
90 const tmp = @boolToInt(@addWithOverflow(u8, a[i], b[i], &result[i]));90 const ov1 = @addWithOverflow(a[i], b[i]);
91 carry = tmp | @boolToInt(@addWithOverflow(u8, result[i], carry, &result[i]));91 const ov2 = @addWithOverflow(ov1[0], carry);
92 result[i] = ov2[0];
93 carry = ov1[1] | ov2[1];
92 }94 }
93 } else {95 } else {
94 var i: usize = len;96 var i: usize = len;
95 while (i != 0) {97 while (i != 0) {
96 i -= 1;98 i -= 1;
97 const tmp = @boolToInt(@addWithOverflow(u8, a[i], b[i], &result[i]));99 const ov1 = @addWithOverflow(a[i], b[i]);
98 carry = tmp | @boolToInt(@addWithOverflow(u8, result[i], carry, &result[i]));100 const ov2 = @addWithOverflow(ov1[0], carry);
101 result[i] = ov2[0];
102 carry = ov1[1] | ov2[1];
99 }103 }
100 }104 }
101 return @bitCast(bool, carry);105 return @bitCast(bool, carry);
...@@ -110,15 +114,19 @@ pub fn timingSafeSub(comptime T: type, a: []const T, b: []const T, result: []T,...@@ -110,15 +114,19 @@ pub fn timingSafeSub(comptime T: type, a: []const T, b: []const T, result: []T,
110 if (endian == .Little) {114 if (endian == .Little) {
111 var i: usize = 0;115 var i: usize = 0;
112 while (i < len) : (i += 1) {116 while (i < len) : (i += 1) {
113 const tmp = @boolToInt(@subWithOverflow(u8, a[i], b[i], &result[i]));117 const ov1 = @subWithOverflow(a[i], b[i]);
114 borrow = tmp | @boolToInt(@subWithOverflow(u8, result[i], borrow, &result[i]));118 const ov2 = @subWithOverflow(ov1[0], borrow);
119 result[i] = ov2[0];
120 borrow = ov1[1] | ov2[1];
115 }121 }
116 } else {122 } else {
117 var i: usize = len;123 var i: usize = len;
118 while (i != 0) {124 while (i != 0) {
119 i -= 1;125 i -= 1;
120 const tmp = @boolToInt(@subWithOverflow(u8, a[i], b[i], &result[i]));126 const ov1 = @subWithOverflow(a[i], b[i]);
121 borrow = tmp | @boolToInt(@subWithOverflow(u8, result[i], borrow, &result[i]));127 const ov2 = @subWithOverflow(ov1[0], borrow);
128 result[i] = ov2[0];
129 borrow = ov1[1] | ov2[1];
122 }130 }
123 }131 }
124 return @bitCast(bool, borrow);132 return @bitCast(bool, borrow);
lib/std/heap.zig+1-1
...@@ -789,7 +789,7 @@ pub fn testAllocatorLargeAlignment(base_allocator: mem.Allocator) !void {...@@ -789,7 +789,7 @@ pub fn testAllocatorLargeAlignment(base_allocator: mem.Allocator) !void {
789 const large_align: usize = mem.page_size / 2;789 const large_align: usize = mem.page_size / 2;
790790
791 var align_mask: usize = undefined;791 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
794 var slice = try allocator.alignedAlloc(u8, large_align, 500);794 var slice = try allocator.alignedAlloc(u8, large_align, 500);
795 try testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));795 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 {...@@ -15,11 +15,11 @@ pub fn readULEB128(comptime T: type, reader: anytype) !T {
1515
16 while (group < max_group) : (group += 1) {16 while (group < max_group) : (group += 1) {
17 const byte = try reader.readByte();17 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];
23 if (byte & 0x80 == 0) break;23 if (byte & 0x80 == 0) break;
24 } else {24 } else {
25 return error.Overflow;25 return error.Overflow;
...@@ -65,13 +65,13 @@ pub fn readILEB128(comptime T: type, reader: anytype) !T {...@@ -65,13 +65,13 @@ pub fn readILEB128(comptime T: type, reader: anytype) !T {
6565
66 while (group < max_group) : (group += 1) {66 while (group < max_group) : (group += 1) {
67 const byte = try reader.readByte();67 const byte = try reader.readByte();
68 var temp = @as(U, byte & 0x7f);
6968
70 const shift = group * 7;69 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) {
72 // Overflow is ok so long as the sign bit is set and this is the last byte72 // Overflow is ok so long as the sign bit is set and this is the last byte
73 if (byte & 0x80 != 0) return error.Overflow;73 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
76 // and all the overflowed bits are 176 // and all the overflowed bits are 1
77 const remaining_shift = @intCast(u3, @typeInfo(U).Int.bits - @as(u16, shift));77 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 {...@@ -80,14 +80,14 @@ pub fn readILEB128(comptime T: type, reader: anytype) !T {
80 } else {80 } else {
81 // If we don't overflow and this is the last byte and the number being decoded81 // If we don't overflow and this is the last byte and the number being decoded
82 // is negative, check that the remaining bits are 182 // 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)) {
84 const remaining_shift = @intCast(u3, @typeInfo(U).Int.bits - @as(u16, shift));84 const remaining_shift = @intCast(u3, @typeInfo(U).Int.bits - @as(u16, shift));
85 const remaining_bits = @bitCast(i8, byte | 0x80) >> remaining_shift;85 const remaining_bits = @bitCast(i8, byte | 0x80) >> remaining_shift;
86 if (remaining_bits != -1) return error.Overflow;86 if (remaining_bits != -1) return error.Overflow;
87 }87 }
88 }88 }
8989
90 value |= temp;90 value |= ov[0];
91 if (byte & 0x80 == 0) {91 if (byte & 0x80 == 0) {
92 const needs_sign_ext = group + 1 < max_group;92 const needs_sign_ext = group + 1 < max_group;
93 if (byte & 0x40 != 0 and needs_sign_ext) {93 if (byte & 0x40 != 0 and needs_sign_ext) {
lib/std/math.zig+15-8
...@@ -468,21 +468,26 @@ test "clamp" {...@@ -468,21 +468,26 @@ test "clamp" {
468468
469/// Returns the product of a and b. Returns an error on overflow.469/// Returns the product of a and b. Returns an error on overflow.
470pub fn mul(comptime T: type, a: T, b: T) (error{Overflow}!T) {470pub fn mul(comptime T: type, a: T, b: T) (error{Overflow}!T) {
471 var answer: T = undefined;471 if (T == comptime_int) return a * b;
472 return if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer;472 const ov = @mulWithOverflow(a, b);
473 if (ov[1] != 0) return error.Overflow;
474 return ov[0];
473}475}
474476
475/// Returns the sum of a and b. Returns an error on overflow.477/// Returns the sum of a and b. Returns an error on overflow.
476pub fn add(comptime T: type, a: T, b: T) (error{Overflow}!T) {478pub fn add(comptime T: type, a: T, b: T) (error{Overflow}!T) {
477 if (T == comptime_int) return a + b;479 if (T == comptime_int) return a + b;
478 var answer: T = undefined;480 const ov = @addWithOverflow(a, b);
479 return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;481 if (ov[1] != 0) return error.Overflow;
482 return ov[0];
480}483}
481484
482/// Returns a - b, or an error on overflow.485/// Returns a - b, or an error on overflow.
483pub fn sub(comptime T: type, a: T, b: T) (error{Overflow}!T) {486pub fn sub(comptime T: type, a: T, b: T) (error{Overflow}!T) {
484 var answer: T = undefined;487 if (T == comptime_int) return a - b;
485 return if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer;488 const ov = @subWithOverflow(a, b);
489 if (ov[1] != 0) return error.Overflow;
490 return ov[0];
486}491}
487492
488pub fn negate(x: anytype) !@TypeOf(x) {493pub fn negate(x: anytype) !@TypeOf(x) {
...@@ -492,8 +497,10 @@ pub fn negate(x: anytype) !@TypeOf(x) {...@@ -492,8 +497,10 @@ pub fn negate(x: anytype) !@TypeOf(x) {
492/// Shifts a left by shift_amt. Returns an error on overflow. shift_amt497/// Shifts a left by shift_amt. Returns an error on overflow. shift_amt
493/// is unsigned.498/// is unsigned.
494pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T {499pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T {
495 var answer: T = undefined;500 if (T == comptime_int) return a << shift_amt;
496 return if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer;501 const ov = @shlWithOverflow(a, shift_amt);
502 if (ov[1] != 0) return error.Overflow;
503 return ov[0];
497}504}
498505
499/// Shifts left. Overflowed bits are truncated.506/// 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 {...@@ -74,42 +74,40 @@ pub fn calcTwosCompLimbCount(bit_count: usize) usize {
74/// a + b * c + *carry, sets carry to the overflow bits74/// a + b * c + *carry, sets carry to the overflow bits
75pub fn addMulLimbWithCarry(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb {75pub fn addMulLimbWithCarry(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb {
76 @setRuntimeSafety(debug_safety);76 @setRuntimeSafety(debug_safety);
77 var r1: Limb = undefined;
7877
79 // r1 = a + *carry78 // ov1[0] = a + *carry
80 const c1: Limb = @boolToInt(@addWithOverflow(Limb, a, carry.*, &r1));79 const ov1 = @addWithOverflow(a, carry.*);
8180
82 // r2 = b * c81 // r2 = b * c
83 const bc = @as(DoubleLimb, math.mulWide(Limb, b, c));82 const bc = @as(DoubleLimb, math.mulWide(Limb, b, c));
84 const r2 = @truncate(Limb, bc);83 const r2 = @truncate(Limb, bc);
85 const c2 = @truncate(Limb, bc >> limb_bits);84 const c2 = @truncate(Limb, bc >> limb_bits);
8685
87 // r1 = r1 + r286 // ov2[0] = ov1[0] + r2
88 const c3: Limb = @boolToInt(@addWithOverflow(Limb, r1, r2, &r1));87 const ov2 = @addWithOverflow(ov1[0], r2);
8988
90 // This never overflows, c1, c3 are either 0 or 1 and if both are 1 then89 // This never overflows, c1, c3 are either 0 or 1 and if both are 1 then
91 // c2 is at least <= maxInt(Limb) - 2.90 // 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];
95}94}
9695
97/// a - b * c - *carry, sets carry to the overflow bits96/// a - b * c - *carry, sets carry to the overflow bits
98fn subMulLimbWithBorrow(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb {97fn subMulLimbWithBorrow(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb {
99 // r1 = a - *carry98 // ov1[0] = a - *carry
100 var r1: Limb = undefined;99 const ov1 = @subWithOverflow(a, carry.*);
101 const c1: Limb = @boolToInt(@subWithOverflow(Limb, a, carry.*, &r1));
102100
103 // r2 = b * c101 // r2 = b * c
104 const bc = @as(DoubleLimb, std.math.mulWide(Limb, b, c));102 const bc = @as(DoubleLimb, std.math.mulWide(Limb, b, c));
105 const r2 = @truncate(Limb, bc);103 const r2 = @truncate(Limb, bc);
106 const c2 = @truncate(Limb, bc >> limb_bits);104 const c2 = @truncate(Limb, bc >> limb_bits);
107105
108 // r1 = r1 - r2106 // ov2[0] = ov1[0] - r2
109 const c3: Limb = @boolToInt(@subWithOverflow(Limb, r1, r2, &r1));107 const ov2 = @subWithOverflow(ov1[0], r2);
110 carry.* = c1 + c2 + c3;108 carry.* = ov1[1] + c2 + ov2[1];
111109
112 return r1;110 return ov2[0];
113}111}
114112
115/// Used to indicate either limit of a 2s-complement integer.113/// Used to indicate either limit of a 2s-complement integer.
...@@ -673,7 +671,9 @@ pub const Mutable = struct {...@@ -673,7 +671,9 @@ pub const Mutable = struct {
673 assert(rma.limbs.ptr != b.limbs.ptr); // illegal aliasing671 assert(rma.limbs.ptr != b.limbs.ptr); // illegal aliasing
674672
675 if (a.limbs.len == 1 and b.limbs.len == 1) {673 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) {
677 rma.len = 1;677 rma.len = 1;
678 rma.positive = (a.positive == b.positive);678 rma.positive = (a.positive == b.positive);
679 return;679 return;
...@@ -1836,7 +1836,11 @@ pub const Mutable = struct {...@@ -1836,7 +1836,11 @@ pub const Mutable = struct {
1836 bit_index += @bitSizeOf(Limb);1836 bit_index += @bitSizeOf(Limb);
18371837
1838 // 2's complement (bitwise not, then add carry bit)1838 // 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 }
1840 x.limbs[limb_index] = limb;1844 x.limbs[limb_index] = limb;
1841 }1845 }
18421846
...@@ -1853,7 +1857,11 @@ pub const Mutable = struct {...@@ -1853,7 +1857,11 @@ pub const Mutable = struct {
1853 };1857 };
18541858
1855 // 2's complement (bitwise not, then add carry bit)1859 // 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 }
1857 x.limbs[limb_index] = limb;1865 x.limbs[limb_index] = limb;
18581866
1859 limb_index += 1;1867 limb_index += 1;
...@@ -2000,7 +2008,9 @@ pub const Const = struct {...@@ -2000,7 +2008,9 @@ pub const Const = struct {
20002008
2001 // All but the most significant limb.2009 // All but the most significant limb.
2002 for (self.limbs[0 .. self.limbs.len - 1]) |limb| {2010 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];
2004 sum += @popCount(add_res);2014 sum += @popCount(add_res);
2005 remaining_bits -= limb_bits; // Asserted not to undeflow by fitsInTwosComp2015 remaining_bits -= limb_bits; // Asserted not to undeflow by fitsInTwosComp
2006 }2016 }
...@@ -2294,7 +2304,11 @@ pub const Const = struct {...@@ -2294,7 +2304,11 @@ pub const Const = struct {
2294 var limb: Limb = if (limb_index < x.limbs.len) x.limbs[limb_index] else 0;2304 var limb: Limb = if (limb_index < x.limbs.len) x.limbs[limb_index] else 0;
22952305
2296 // 2's complement (bitwise not, then add carry bit)2306 // 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
2299 // Write one Limb of bits2313 // Write one Limb of bits
2300 mem.writePackedInt(Limb, bytes, bit_index + bit_offset, limb, endian);2314 mem.writePackedInt(Limb, bytes, bit_index + bit_offset, limb, endian);
...@@ -2306,7 +2320,7 @@ pub const Const = struct {...@@ -2306,7 +2320,7 @@ pub const Const = struct {
2306 var limb: Limb = if (limb_index < x.limbs.len) x.limbs[limb_index] else 0;2320 var limb: Limb = if (limb_index < x.limbs.len) x.limbs[limb_index] else 0;
23072321
2308 // 2's complement (bitwise not, then add carry bit)2322 // 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
2311 // Write all remaining bits2325 // Write all remaining bits
2312 mem.writeVarPackedInt(bytes, bit_index + bit_offset, bit_count - bit_index, limb, endian);2326 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 {...@@ -3360,14 +3374,17 @@ fn llaccum(comptime op: AccOp, r: []Limb, a: []const Limb) void {
3360 var carry: Limb = 0;3374 var carry: Limb = 0;
33613375
3362 while (i < a.len) : (i += 1) {3376 while (i < a.len) : (i += 1) {
3363 var c: Limb = 0;3377 const ov1 = @addWithOverflow(r[i], a[i]);
3364 c += @boolToInt(@addWithOverflow(Limb, r[i], a[i], &r[i]));3378 r[i] = ov1[0];
3365 c += @boolToInt(@addWithOverflow(Limb, r[i], carry, &r[i]));3379 const ov2 = @addWithOverflow(r[i], carry);
3366 carry = c;3380 r[i] = ov2[0];
3381 carry = @as(Limb, ov1[1]) + ov2[1];
3367 }3382 }
33683383
3369 while ((carry != 0) and i < r.len) : (i += 1) {3384 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];
3371 }3388 }
3372}3389}
33733390
...@@ -3435,7 +3452,9 @@ fn llmulLimb(comptime op: AccOp, acc: []Limb, y: []const Limb, xi: Limb) bool {...@@ -3435,7 +3452,9 @@ fn llmulLimb(comptime op: AccOp, acc: []Limb, y: []const Limb, xi: Limb) bool {
34353452
3436 j = 0;3453 j = 0;
3437 while ((carry != 0) and (j < a_hi.len)) : (j += 1) {3454 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];
3439 }3458 }
34403459
3441 return carry != 0;3460 return carry != 0;
...@@ -3449,7 +3468,9 @@ fn llmulLimb(comptime op: AccOp, acc: []Limb, y: []const Limb, xi: Limb) bool {...@@ -3449,7 +3468,9 @@ fn llmulLimb(comptime op: AccOp, acc: []Limb, y: []const Limb, xi: Limb) bool {
34493468
3450 j = 0;3469 j = 0;
3451 while ((borrow != 0) and (j < a_hi.len)) : (j += 1) {3470 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];
3453 }3474 }
34543475
3455 return borrow != 0;3476 return borrow != 0;
...@@ -3482,14 +3503,17 @@ fn llsubcarry(r: []Limb, a: []const Limb, b: []const Limb) Limb {...@@ -3482,14 +3503,17 @@ fn llsubcarry(r: []Limb, a: []const Limb, b: []const Limb) Limb {
3482 var borrow: Limb = 0;3503 var borrow: Limb = 0;
34833504
3484 while (i < b.len) : (i += 1) {3505 while (i < b.len) : (i += 1) {
3485 var c: Limb = 0;3506 const ov1 = @subWithOverflow(a[i], b[i]);
3486 c += @boolToInt(@subWithOverflow(Limb, a[i], b[i], &r[i]));3507 r[i] = ov1[0];
3487 c += @boolToInt(@subWithOverflow(Limb, r[i], borrow, &r[i]));3508 const ov2 = @subWithOverflow(r[i], borrow);
3488 borrow = c;3509 r[i] = ov2[0];
3510 borrow = @as(Limb, ov1[1]) + ov2[1];
3489 }3511 }
34903512
3491 while (i < a.len) : (i += 1) {3513 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];
3493 }3517 }
34943518
3495 return borrow;3519 return borrow;
...@@ -3512,14 +3536,17 @@ fn lladdcarry(r: []Limb, a: []const Limb, b: []const Limb) Limb {...@@ -3512,14 +3536,17 @@ fn lladdcarry(r: []Limb, a: []const Limb, b: []const Limb) Limb {
3512 var carry: Limb = 0;3536 var carry: Limb = 0;
35133537
3514 while (i < b.len) : (i += 1) {3538 while (i < b.len) : (i += 1) {
3515 var c: Limb = 0;3539 const ov1 = @addWithOverflow(a[i], b[i]);
3516 c += @boolToInt(@addWithOverflow(Limb, a[i], b[i], &r[i]));3540 r[i] = ov1[0];
3517 c += @boolToInt(@addWithOverflow(Limb, r[i], carry, &r[i]));3541 const ov2 = @addWithOverflow(r[i], carry);
3518 carry = c;3542 r[i] = ov2[0];
3543 carry = @as(Limb, ov1[1]) + ov2[1];
3519 }3544 }
35203545
3521 while (i < a.len) : (i += 1) {3546 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];
3523 }3550 }
35243551
3525 return carry;3552 return carry;
...@@ -3685,11 +3712,11 @@ fn llsignedor(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_p...@@ -3685,11 +3712,11 @@ fn llsignedor(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_p
3685 var r_carry: u1 = 1;3712 var r_carry: u1 = 1;
36863713
3687 while (i < b.len) : (i += 1) {3714 while (i < b.len) : (i += 1) {
3688 var a_limb: Limb = undefined;3715 const ov1 = @subWithOverflow(a[i], a_borrow);
3689 a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &a_limb));3716 a_borrow = ov1[1];
36903717 const ov2 = @addWithOverflow(ov1[0] & ~b[i], r_carry);
3691 r[i] = a_limb & ~b[i];3718 r[i] = ov2[0];
3692 r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i]));3719 r_carry = ov2[1];
3693 }3720 }
36943721
3695 // In order for r_carry to be nonzero at this point, ~b[i] would need to be3722 // 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...@@ -3702,7 +3729,9 @@ fn llsignedor(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_p
3702 // Note, if a_borrow is zero we do not need to compute anything for3729 // Note, if a_borrow is zero we do not need to compute anything for
3703 // the higher limbs so we can early return here.3730 // the higher limbs so we can early return here.
3704 while (i < a.len and a_borrow == 1) : (i += 1) {3731 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];
3706 }3735 }
37073736
3708 assert(a_borrow == 0); // a was 0.3737 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...@@ -3721,11 +3750,11 @@ fn llsignedor(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_p
3721 var r_carry: u1 = 1;3750 var r_carry: u1 = 1;
37223751
3723 while (i < b.len) : (i += 1) {3752 while (i < b.len) : (i += 1) {
3724 var b_limb: Limb = undefined;3753 const ov1 = @subWithOverflow(b[i], b_borrow);
3725 b_borrow = @boolToInt(@subWithOverflow(Limb, b[i], b_borrow, &b_limb));3754 b_borrow = ov1[1];
37263755 const ov2 = @addWithOverflow(~a[i] & ov1[0], r_carry);
3727 r[i] = ~a[i] & b_limb;3756 r[i] = ov2[0];
3728 r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i]));3757 r_carry = ov2[1];
3729 }3758 }
37303759
3731 // b is at least 1, so this should never underflow.3760 // 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...@@ -3752,14 +3781,13 @@ fn llsignedor(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_p
3752 var r_carry: u1 = 1;3781 var r_carry: u1 = 1;
37533782
3754 while (i < b.len) : (i += 1) {3783 while (i < b.len) : (i += 1) {
3755 var a_limb: Limb = undefined;3784 const ov1 = @subWithOverflow(a[i], a_borrow);
3756 a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &a_limb));3785 a_borrow = ov1[1];
37573786 const ov2 = @subWithOverflow(b[i], b_borrow);
3758 var b_limb: Limb = undefined;3787 b_borrow = ov2[1];
3759 b_borrow = @boolToInt(@subWithOverflow(Limb, b[i], b_borrow, &b_limb));3788 const ov3 = @addWithOverflow(ov1[0] & ov2[0], r_carry);
37603789 r[i] = ov3[0];
3761 r[i] = a_limb & b_limb;3790 r_carry = ov3[1];
3762 r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i]));
3763 }3791 }
37643792
3765 // b is at least 1, so this should never underflow.3793 // 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_...@@ -3811,9 +3839,9 @@ fn llsignedand(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_
3811 var a_borrow: u1 = 1;3839 var a_borrow: u1 = 1;
38123840
3813 while (i < b.len) : (i += 1) {3841 while (i < b.len) : (i += 1) {
3814 var a_limb: Limb = undefined;3842 const ov = @subWithOverflow(a[i], a_borrow);
3815 a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &a_limb));3843 a_borrow = ov[1];
3816 r[i] = ~a_limb & b[i];3844 r[i] = ~ov[0] & b[i];
3817 }3845 }
38183846
3819 // With b = 0 we have ~(a - 1) & 0 = 0, so the upper bytes are zero.3847 // 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_...@@ -3830,9 +3858,9 @@ fn llsignedand(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_
3830 var b_borrow: u1 = 1;3858 var b_borrow: u1 = 1;
38313859
3832 while (i < b.len) : (i += 1) {3860 while (i < b.len) : (i += 1) {
3833 var a_limb: Limb = undefined;3861 const ov = @subWithOverflow(b[i], b_borrow);
3834 b_borrow = @boolToInt(@subWithOverflow(Limb, b[i], b_borrow, &a_limb));3862 b_borrow = ov[1];
3835 r[i] = a[i] & ~a_limb;3863 r[i] = a[i] & ~ov[0];
3836 }3864 }
38373865
3838 assert(b_borrow == 0); // b was 03866 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_...@@ -3855,14 +3883,13 @@ fn llsignedand(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_
3855 var r_carry: u1 = 1;3883 var r_carry: u1 = 1;
38563884
3857 while (i < b.len) : (i += 1) {3885 while (i < b.len) : (i += 1) {
3858 var a_limb: Limb = undefined;3886 const ov1 = @subWithOverflow(a[i], a_borrow);
3859 a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &a_limb));3887 a_borrow = ov1[1];
38603888 const ov2 = @subWithOverflow(b[i], b_borrow);
3861 var b_limb: Limb = undefined;3889 b_borrow = ov2[1];
3862 b_borrow = @boolToInt(@subWithOverflow(Limb, b[i], b_borrow, &b_limb));3890 const ov3 = @addWithOverflow(ov1[0] | ov2[0], r_carry);
38633891 r[i] = ov3[0];
3864 r[i] = a_limb | b_limb;3892 r_carry = ov3[1];
3865 r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i]));
3866 }3893 }
38673894
3868 // b is at least 1, so this should never underflow.3895 // 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_...@@ -3870,8 +3897,11 @@ fn llsignedand(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_
38703897
3871 // With b = 0 and b_borrow = 0 we get (-a - 1) | (-0 - 0) = (-a - 1) | 0 = -a - 1.3898 // With b = 0 and b_borrow = 0 we get (-a - 1) | (-0 - 0) = (-a - 1) | 0 = -a - 1.
3872 while (i < a.len) : (i += 1) {3899 while (i < a.len) : (i += 1) {
3873 a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &r[i]));3900 const ov1 = @subWithOverflow(a[i], a_borrow);
3874 r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i]));3901 a_borrow = ov1[1];
3902 const ov2 = @addWithOverflow(ov1[0], r_carry);
3903 r[i] = ov2[0];
3904 r_carry = ov2[1];
3875 }3905 }
38763906
3877 assert(a_borrow == 0); // a was 0.3907 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_...@@ -3917,19 +3947,21 @@ fn llsignedxor(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_
3917 var r_carry = @boolToInt(a_positive != b_positive);3947 var r_carry = @boolToInt(a_positive != b_positive);
39183948
3919 while (i < b.len) : (i += 1) {3949 while (i < b.len) : (i += 1) {
3920 var a_limb: Limb = undefined;3950 const ov1 = @subWithOverflow(a[i], a_borrow);
3921 a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &a_limb));3951 a_borrow = ov1[1];
39223952 const ov2 = @subWithOverflow(b[i], b_borrow);
3923 var b_limb: Limb = undefined;3953 b_borrow = ov2[1];
3924 b_borrow = @boolToInt(@subWithOverflow(Limb, b[i], b_borrow, &b_limb));3954 const ov3 = @addWithOverflow(ov1[0] ^ ov2[0], r_carry);
39253955 r[i] = ov3[0];
3926 r[i] = a_limb ^ b_limb;3956 r_carry = ov3[1];
3927 r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i]));
3928 }3957 }
39293958
3930 while (i < a.len) : (i += 1) {3959 while (i < a.len) : (i += 1) {
3931 a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &r[i]));3960 const ov1 = @subWithOverflow(a[i], a_borrow);
3932 r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i]));3961 a_borrow = ov1[1];
3962 const ov2 = @addWithOverflow(ov1[0], r_carry);
3963 r[i] = ov2[0];
3964 r_carry = ov2[1];
3933 }3965 }
39343966
3935 // If both inputs don't share the same sign, an extra limb is required.3967 // 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 {...@@ -4021,7 +4053,9 @@ fn llpow(r: []Limb, a: []const Limb, b: u32, tmp_limbs: []Limb) void {
4021 llsquareBasecase(tmp2, tmp1[0..llnormalize(tmp1)]);4053 llsquareBasecase(tmp2, tmp1[0..llnormalize(tmp1)]);
4022 mem.swap([]Limb, &tmp1, &tmp2);4054 mem.swap([]Limb, &tmp1, &tmp2);
4023 // Multiply by a4055 // 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) {
4025 mem.set(Limb, tmp2, 0);4059 mem.set(Limb, tmp2, 0);
4026 llmulacc(.add, null, tmp2, tmp1[0..llnormalize(tmp1)], a);4060 llmulacc(.add, null, tmp2, tmp1[0..llnormalize(tmp1)], a);
4027 mem.swap([]Limb, &tmp1, &tmp2);4061 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{...@@ -70,22 +70,22 @@ pub fn powi(comptime T: type, x: T, y: T) (error{
7070
71 while (exp > 1) {71 while (exp > 1) {
72 if (exp & 1 == 1) {72 if (exp & 1 == 1) {
73 if (@mulWithOverflow(T, acc, base, &acc)) {73 const ov = @mulWithOverflow(acc, base);
74 return error.Overflow;74 if (ov[1] != 0) return error.Overflow;
75 }75 acc = ov[0];
76 }76 }
7777
78 exp >>= 1;78 exp >>= 1;
7979
80 if (@mulWithOverflow(T, base, base, &base)) {80 const ov = @mulWithOverflow(base, base);
81 return error.Overflow;81 if (ov[1] != 0) return error.Overflow;
82 }82 base = ov[0];
83 }83 }
8484
85 if (exp == 1) {85 if (exp == 1) {
86 if (@mulWithOverflow(T, acc, base, &acc)) {86 const ov = @mulWithOverflow(acc, base);
87 return error.Overflow;87 if (ov[1] != 0) return error.Overflow;
88 }88 acc = ov[0];
89 }89 }
9090
91 return acc;91 return acc;
lib/std/mem.zig+4-4
...@@ -3304,13 +3304,13 @@ pub fn alignPointerOffset(ptr: anytype, align_to: usize) ?usize {...@@ -3304,13 +3304,13 @@ pub fn alignPointerOffset(ptr: anytype, align_to: usize) ?usize {
33043304
3305 // Calculate the aligned base address with an eye out for overflow.3305 // Calculate the aligned base address with an eye out for overflow.
3306 const addr = @ptrToInt(ptr);3306 const addr = @ptrToInt(ptr);
3307 var new_addr: usize = undefined;3307 var ov = @addWithOverflow(addr, align_to - 1);
3308 if (@addWithOverflow(usize, addr, align_to - 1, &new_addr)) return null;3308 if (ov[1] != 0) return null;
3309 new_addr &= ~@as(usize, align_to - 1);3309 ov[0] &= ~@as(usize, align_to - 1);
33103310
3311 // The delta is expressed in terms of bytes, turn it into a number of child3311 // The delta is expressed in terms of bytes, turn it into a number of child
3312 // type elements.3312 // type elements.
3313 const delta = new_addr - addr;3313 const delta = ov[0] - addr;
3314 const pointee_size = @sizeOf(info.Pointer.child);3314 const pointee_size = @sizeOf(info.Pointer.child);
3315 if (delta % pointee_size != 0) return null;3315 if (delta % pointee_size != 0) return null;
3316 return delta / pointee_size;3316 return delta / pointee_size;
lib/std/net.zig+24-12
...@@ -321,11 +321,15 @@ pub const Ip6Address = extern struct {...@@ -321,11 +321,15 @@ pub const Ip6Address = extern struct {
321 if (scope_id) {321 if (scope_id) {
322 if (c >= '0' and c <= '9') {322 if (c >= '0' and c <= '9') {
323 const digit = c - '0';323 const digit = c - '0';
324 if (@mulWithOverflow(u32, result.sa.scope_id, 10, &result.sa.scope_id)) {324 {
325 return error.Overflow;325 const ov = @mulWithOverflow(result.sa.scope_id, 10);
326 if (ov[1] != 0) return error.Overflow;
327 result.sa.scope_id = ov[0];
326 }328 }
327 if (@addWithOverflow(u32, result.sa.scope_id, digit, &result.sa.scope_id)) {329 {
328 return error.Overflow;330 const ov = @addWithOverflow(result.sa.scope_id, digit);
331 if (ov[1] != 0) return error.Overflow;
332 result.sa.scope_id = ov[0];
329 }333 }
330 } else {334 } else {
331 return error.InvalidCharacter;335 return error.InvalidCharacter;
...@@ -377,11 +381,15 @@ pub const Ip6Address = extern struct {...@@ -377,11 +381,15 @@ pub const Ip6Address = extern struct {
377 return result;381 return result;
378 } else {382 } else {
379 const digit = try std.fmt.charToDigit(c, 16);383 const digit = try std.fmt.charToDigit(c, 16);
380 if (@mulWithOverflow(u16, x, 16, &x)) {384 {
381 return error.Overflow;385 const ov = @mulWithOverflow(x, 16);
386 if (ov[1] != 0) return error.Overflow;
387 x = ov[0];
382 }388 }
383 if (@addWithOverflow(u16, x, digit, &x)) {389 {
384 return error.Overflow;390 const ov = @addWithOverflow(x, digit);
391 if (ov[1] != 0) return error.Overflow;
392 x = ov[0];
385 }393 }
386 saw_any_digits = true;394 saw_any_digits = true;
387 }395 }
...@@ -492,11 +500,15 @@ pub const Ip6Address = extern struct {...@@ -492,11 +500,15 @@ pub const Ip6Address = extern struct {
492 return result;500 return result;
493 } else {501 } else {
494 const digit = try std.fmt.charToDigit(c, 16);502 const digit = try std.fmt.charToDigit(c, 16);
495 if (@mulWithOverflow(u16, x, 16, &x)) {503 {
496 return error.Overflow;504 const ov = @mulWithOverflow(x, 16);
505 if (ov[1] != 0) return error.Overflow;
506 x = ov[0];
497 }507 }
498 if (@addWithOverflow(u16, x, digit, &x)) {508 {
499 return error.Overflow;509 const ov = @addWithOverflow(x, digit);
510 if (ov[1] != 0) return error.Overflow;
511 x = ov[0];
500 }512 }
501 saw_any_digits = true;513 saw_any_digits = true;
502 }514 }
lib/std/os/linux.zig+1-1
...@@ -1244,7 +1244,7 @@ pub fn sendmmsg(fd: i32, msgvec: [*]mmsghdr_const, vlen: u32, flags: u32) usize...@@ -1244,7 +1244,7 @@ pub fn sendmmsg(fd: i32, msgvec: [*]mmsghdr_const, vlen: u32, flags: u32) usize
1244 var size: i32 = 0;1244 var size: i32 = 0;
1245 const msg_iovlen = @intCast(usize, msg.msg_hdr.msg_iovlen); // kernel side this is treated as unsigned1245 const msg_iovlen = @intCast(usize, msg.msg_hdr.msg_iovlen); // kernel side this is treated as unsigned
1246 for (msg.msg_hdr.msg_iov[0..msg_iovlen]) |iov| {1246 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) {
1248 // batch-send all messages up to the current message1248 // batch-send all messages up to the current message
1249 if (next_unsent < i) {1249 if (next_unsent < i) {
1250 const batch_size = i - next_unsent;1250 const batch_size = i - next_unsent;
lib/std/process.zig+20-4
...@@ -1023,8 +1023,16 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {...@@ -1023,8 +1023,16 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {
1023 '0'...'9' => byte - '0',1023 '0'...'9' => byte - '0',
1024 else => return error.CorruptPasswordFile,1024 else => return error.CorruptPasswordFile,
1025 };1025 };
1026 if (@mulWithOverflow(u32, uid, 10, &uid)) return error.CorruptPasswordFile;1026 {
1027 if (@addWithOverflow(u32, uid, digit, &uid)) return error.CorruptPasswordFile;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 }
1028 },1036 },
1029 },1037 },
1030 .ReadGroupId => switch (byte) {1038 .ReadGroupId => switch (byte) {
...@@ -1039,8 +1047,16 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {...@@ -1039,8 +1047,16 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {
1039 '0'...'9' => byte - '0',1047 '0'...'9' => byte - '0',
1040 else => return error.CorruptPasswordFile,1048 else => return error.CorruptPasswordFile,
1041 };1049 };
1042 if (@mulWithOverflow(u32, gid, 10, &gid)) return error.CorruptPasswordFile;1050 {
1043 if (@addWithOverflow(u32, gid, digit, &gid)) return error.CorruptPasswordFile;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 }
1044 },1060 },
1045 },1061 },
1046 }1062 }
lib/std/zig/c_builtins.zig+3-1
...@@ -246,7 +246,9 @@ pub inline fn __builtin_constant_p(expr: anytype) c_int {...@@ -246,7 +246,9 @@ pub inline fn __builtin_constant_p(expr: anytype) c_int {
246 return @boolToInt(false);246 return @boolToInt(false);
247}247}
248pub fn __builtin_mul_overflow(a: anytype, b: anytype, result: *@TypeOf(a, b)) c_int {248pub 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];
250}252}
251253
252// __builtin_alloca_with_align is not currently implemented.254// __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 {...@@ -151,12 +151,14 @@ pub fn parseNumberLiteral(bytes: []const u8) Result {
151 special = 0;151 special = 0;
152152
153 if (float) continue;153 if (float) continue;
154 if (x != 0) if (@mulWithOverflow(u64, x, base, &x)) {154 if (x != 0) {
155 overflow = true;155 const res = @mulWithOverflow(x, base);
156 };156 if (res[1] != 0) overflow = true;
157 if (@addWithOverflow(u64, x, digit, &x)) {157 x = res[0];
158 overflow = true;
159 }158 }
159 const res = @addWithOverflow(x, digit);
160 if (res[1] != 0) overflow = true;
161 x = res[0];
160 }162 }
161 if (underscore) return .{ .failure = .{ .trailing_underscore = bytes.len - 1 } };163 if (underscore) return .{ .failure = .{ .trailing_underscore = bytes.len - 1 } };
162 if (special != 0) return .{ .failure = .{ .trailing_special = bytes.len - 1 } };164 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 {...@@ -1860,9 +1860,7 @@ fn writeHeader(self: *Coff) !void {
1860}1860}
18611861
1862pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {1862pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
1863 // TODO https://github.com/ziglang/zig/issues/12841863 return actual_size +| (actual_size / ideal_factor);
1864 return math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch
1865 math.maxInt(@TypeOf(actual_size));
1866}1864}
18671865
1868fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 {1866fn 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 {...@@ -2445,9 +2445,7 @@ fn makeString(self: *Dwarf, bytes: []const u8) !u32 {
2445}2445}
24462446
2447fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {2447fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
2448 // TODO https://github.com/ziglang/zig/issues/12842448 return actual_size +| (actual_size / ideal_factor);
2449 return std.math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch
2450 std.math.maxInt(@TypeOf(actual_size));
2451}2449}
24522450
2453pub fn flushModule(self: *Dwarf, module: *Module) !void {2451pub fn flushModule(self: *Dwarf, module: *Module) !void {
src/link/Elf.zig+1-3
...@@ -3032,9 +3032,7 @@ fn getLDMOption(target: std.Target) ?[]const u8 {...@@ -3032,9 +3032,7 @@ fn getLDMOption(target: std.Target) ?[]const u8 {
3032}3032}
30333033
3034fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {3034fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
3035 // TODO https://github.com/ziglang/zig/issues/12843035 return actual_size +| (actual_size / ideal_factor);
3036 return std.math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch
3037 std.math.maxInt(@TypeOf(actual_size));
3038}3036}
30393037
3040// Provide a blueprint of csu (c-runtime startup) objects for supported3038// 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 {...@@ -3772,9 +3772,7 @@ fn writeHeader(self: *MachO, ncmds: u32, sizeofcmds: u32) !void {
3772}3772}
37733773
3774pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {3774pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
3775 // TODO https://github.com/ziglang/zig/issues/12843775 return actual_size +| (actual_size / ideal_factor);
3776 return std.math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch
3777 std.math.maxInt(@TypeOf(actual_size));
3778}3776}
37793777
3780fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 {3778fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 {
test/behavior/eval.zig+4-11
...@@ -489,18 +489,11 @@ test "comptime bitwise operators" {...@@ -489,18 +489,11 @@ test "comptime bitwise operators" {
489489
490test "comptime shlWithOverflow" {490test "comptime shlWithOverflow" {
491 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO491 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 const ct_shifted = @shlWithOverflow(~@as(u64, 0), 16)[0];
494 var amt = @as(u64, 0);495 var a = ~@as(u64, 0);
495 _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt);496 const rt_shifted = @shlWithOverflow(a, 16)[0];
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 };
504497
505 try expect(ct_shifted == rt_shifted);498 try expect(ct_shifted == rt_shifted);
506}499}
test/behavior/math.zig+233-154
...@@ -534,6 +534,7 @@ fn testUnsignedNegationWrappingEval(x: u16) !void {...@@ -534,6 +534,7 @@ fn testUnsignedNegationWrappingEval(x: u16) !void {
534534
535test "negation wrapping" {535test "negation wrapping" {
536 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO536 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
537 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
537 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO538 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
538539
539 try expectEqual(@as(u1, 1), negateWrap(u1, 1));540 try expectEqual(@as(u1, 1), negateWrap(u1, 1));
...@@ -634,42 +635,53 @@ test "128-bit multiplication" {...@@ -634,42 +635,53 @@ test "128-bit multiplication" {
634}635}
635636
636test "@addWithOverflow" {637test "@addWithOverflow" {
638 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
639 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
637 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO640 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
638641
639 {642 {
640 var result: u8 = undefined;643 var a: u8 = 250;
641 try expect(@addWithOverflow(u8, 250, 100, &result));644 const ov = @addWithOverflow(a, 100);
642 try expect(result == 94);645 try expect(ov[0] == 94);
643 try expect(!@addWithOverflow(u8, 100, 150, &result));646 try expect(ov[1] == 1);
644 try expect(result == 250);647 }
645648 {
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 {
646 var a: u8 = 200;655 var a: u8 = 200;
647 var b: u8 = 99;656 var b: u8 = 99;
648 try expect(@addWithOverflow(u8, a, b, &result));657 var ov = @addWithOverflow(a, b);
649 try expect(result == 43);658 try expect(ov[0] == 43);
659 try expect(ov[1] == 1);
650 b = 55;660 b = 55;
651 try expect(!@addWithOverflow(u8, a, b, &result));661 ov = @addWithOverflow(a, b);
652 try expect(result == 255);662 try expect(ov[0] == 255);
663 try expect(ov[1] == 0);
653 }664 }
654665
655 {666 {
656 var a: usize = 6;667 var a: usize = 6;
657 var b: usize = 6;668 var b: usize = 6;
658 var res: usize = undefined;669 const ov = @addWithOverflow(a, b);
659 try expect(!@addWithOverflow(usize, a, b, &res));670 try expect(ov[0] == 12);
660 try expect(res == 12);671 try expect(ov[1] == 0);
661 }672 }
662673
663 {674 {
664 var a: isize = -6;675 var a: isize = -6;
665 var b: isize = -6;676 var b: isize = -6;
666 var res: isize = undefined;677 const ov = @addWithOverflow(a, b);
667 try expect(!@addWithOverflow(isize, a, b, &res));678 try expect(ov[0] == -12);
668 try expect(res == -12);679 try expect(ov[1] == 0);
669 }680 }
670}681}
671682
672test "small int addition" {683test "small int addition" {
684 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
673 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO685 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
674686
675 var x: u2 = 0;687 var x: u2 = 0;
...@@ -684,180 +696,206 @@ test "small int addition" {...@@ -684,180 +696,206 @@ test "small int addition" {
684 x += 1;696 x += 1;
685 try expect(x == 3);697 try expect(x == 3);
686698
687 var result: @TypeOf(x) = 3;699 const ov = @addWithOverflow(x, 1);
688 try expect(@addWithOverflow(@TypeOf(x), x, 1, &result));700 try expect(ov[0] == 0);
689701 try expect(ov[1] == 1);
690 try expect(result == 0);
691}702}
692703
693test "basic @mulWithOverflow" {704test "basic @mulWithOverflow" {
694 var result: u8 = undefined;705 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
695 try expect(@mulWithOverflow(u8, 86, 3, &result));706 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
696 try expect(result == 2);707 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
697 try expect(!@mulWithOverflow(u8, 85, 3, &result));708
698 try expect(result == 255);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
700 var a: u8 = 123;722 var a: u8 = 123;
701 var b: u8 = 2;723 var b: u8 = 2;
702 try expect(!@mulWithOverflow(u8, a, b, &result));724 var ov = @mulWithOverflow(a, b);
703 try expect(result == 246);725 try expect(ov[0] == 246);
726 try expect(ov[1] == 0);
704727
705 b = 4;728 b = 4;
706 try expect(@mulWithOverflow(u8, a, b, &result));729 ov = @mulWithOverflow(a, b);
707 try expect(result == 236);730 try expect(ov[0] == 236);
731 try expect(ov[1] == 1);
708}732}
709733
710// TODO migrate to this for all backends once they handle more cases
711test "extensive @mulWithOverflow" {734test "extensive @mulWithOverflow" {
735 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
712 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO736 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
737 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
713738
714 {739 {
715 var a: u5 = 3;740 var a: u5 = 3;
716 var b: u5 = 10;741 var b: u5 = 10;
717 var res: u5 = undefined;742 var ov = @mulWithOverflow(a, b);
718 try expect(!@mulWithOverflow(u5, a, b, &res));743 try expect(ov[0] == 30);
719 try expect(res == 30);744 try expect(ov[1] == 0);
720745
721 b = 11;746 b = 11;
722 try expect(@mulWithOverflow(u5, a, b, &res));747 ov = @mulWithOverflow(a, b);
723 try expect(res == 1);748 try expect(ov[0] == 1);
749 try expect(ov[1] == 1);
724 }750 }
725751
726 {752 {
727 var a: i5 = 3;753 var a: i5 = 3;
728 var b: i5 = -5;754 var b: i5 = -5;
729 var res: i5 = undefined;755 var ov = @mulWithOverflow(a, b);
730 try expect(!@mulWithOverflow(i5, a, b, &res));756 try expect(ov[0] == -15);
731 try expect(res == -15);757 try expect(ov[1] == 0);
732758
733 b = -6;759 b = -6;
734 try expect(@mulWithOverflow(i5, a, b, &res));760 ov = @mulWithOverflow(a, b);
735 try expect(res == 14);761 try expect(ov[0] == 14);
762 try expect(ov[1] == 1);
736 }763 }
737764
738 {765 {
739 var a: u8 = 3;766 var a: u8 = 3;
740 var b: u8 = 85;767 var b: u8 = 85;
741 var res: u8 = undefined;
742768
743 try expect(!@mulWithOverflow(u8, a, b, &res));769 var ov = @mulWithOverflow(a, b);
744 try expect(res == 255);770 try expect(ov[0] == 255);
771 try expect(ov[1] == 0);
745772
746 b = 86;773 b = 86;
747 try expect(@mulWithOverflow(u8, a, b, &res));774 ov = @mulWithOverflow(a, b);
748 try expect(res == 2);775 try expect(ov[0] == 2);
776 try expect(ov[1] == 1);
749 }777 }
750778
751 {779 {
752 var a: i8 = 3;780 var a: i8 = 3;
753 var b: i8 = -42;781 var b: i8 = -42;
754 var res: i8 = undefined;782 var ov = @mulWithOverflow(a, b);
755 try expect(!@mulWithOverflow(i8, a, b, &res));783 try expect(ov[0] == -126);
756 try expect(res == -126);784 try expect(ov[1] == 0);
757785
758 b = -43;786 b = -43;
759 try expect(@mulWithOverflow(i8, a, b, &res));787 ov = @mulWithOverflow(a, b);
760 try expect(res == 127);788 try expect(ov[0] == 127);
789 try expect(ov[1] == 1);
761 }790 }
762791
763 {792 {
764 var a: u14 = 3;793 var a: u14 = 3;
765 var b: u14 = 0x1555;794 var b: u14 = 0x1555;
766 var res: u14 = undefined;795 var ov = @mulWithOverflow(a, b);
767 try expect(!@mulWithOverflow(u14, a, b, &res));796 try expect(ov[0] == 0x3fff);
768 try expect(res == 0x3fff);797 try expect(ov[1] == 0);
769798
770 b = 0x1556;799 b = 0x1556;
771 try expect(@mulWithOverflow(u14, a, b, &res));800 ov = @mulWithOverflow(a, b);
772 try expect(res == 2);801 try expect(ov[0] == 2);
802 try expect(ov[1] == 1);
773 }803 }
774804
775 {805 {
776 var a: i14 = 3;806 var a: i14 = 3;
777 var b: i14 = -0xaaa;807 var b: i14 = -0xaaa;
778 var res: i14 = undefined;808 var ov = @mulWithOverflow(a, b);
779 try expect(!@mulWithOverflow(i14, a, b, &res));809 try expect(ov[0] == -0x1ffe);
780 try expect(res == -0x1ffe);810 try expect(ov[1] == 0);
781811
782 b = -0xaab;812 b = -0xaab;
783 try expect(@mulWithOverflow(i14, a, b, &res));813 ov = @mulWithOverflow(a, b);
784 try expect(res == 0x1fff);814 try expect(ov[0] == 0x1fff);
785 }815 }
786816
787 {817 {
788 var a: u16 = 3;818 var a: u16 = 3;
789 var b: u16 = 0x5555;819 var b: u16 = 0x5555;
790 var res: u16 = undefined;820 var ov = @mulWithOverflow(a, b);
791 try expect(!@mulWithOverflow(u16, a, b, &res));821 try expect(ov[0] == 0xffff);
792 try expect(res == 0xffff);822 try expect(ov[1] == 0);
793823
794 b = 0x5556;824 b = 0x5556;
795 try expect(@mulWithOverflow(u16, a, b, &res));825 ov = @mulWithOverflow(a, b);
796 try expect(res == 2);826 try expect(ov[0] == 2);
827 try expect(ov[1] == 1);
797 }828 }
798829
799 {830 {
800 var a: i16 = 3;831 var a: i16 = 3;
801 var b: i16 = -0x2aaa;832 var b: i16 = -0x2aaa;
802 var res: i16 = undefined;833 var ov = @mulWithOverflow(a, b);
803 try expect(!@mulWithOverflow(i16, a, b, &res));834 try expect(ov[0] == -0x7ffe);
804 try expect(res == -0x7ffe);835 try expect(ov[1] == 0);
805836
806 b = -0x2aab;837 b = -0x2aab;
807 try expect(@mulWithOverflow(i16, a, b, &res));838 ov = @mulWithOverflow(a, b);
808 try expect(res == 0x7fff);839 try expect(ov[0] == 0x7fff);
840 try expect(ov[1] == 1);
809 }841 }
810842
811 {843 {
812 var a: u30 = 3;844 var a: u30 = 3;
813 var b: u30 = 0x15555555;845 var b: u30 = 0x15555555;
814 var res: u30 = undefined;846 var ov = @mulWithOverflow(a, b);
815 try expect(!@mulWithOverflow(u30, a, b, &res));847 try expect(ov[0] == 0x3fffffff);
816 try expect(res == 0x3fffffff);848 try expect(ov[1] == 0);
817849
818 b = 0x15555556;850 b = 0x15555556;
819 try expect(@mulWithOverflow(u30, a, b, &res));851 ov = @mulWithOverflow(a, b);
820 try expect(res == 2);852 try expect(ov[0] == 2);
853 try expect(ov[1] == 1);
821 }854 }
822855
823 {856 {
824 var a: i30 = 3;857 var a: i30 = 3;
825 var b: i30 = -0xaaaaaaa;858 var b: i30 = -0xaaaaaaa;
826 var res: i30 = undefined;859 var ov = @mulWithOverflow(a, b);
827 try expect(!@mulWithOverflow(i30, a, b, &res));860 try expect(ov[0] == -0x1ffffffe);
828 try expect(res == -0x1ffffffe);861 try expect(ov[1] == 0);
829862
830 b = -0xaaaaaab;863 b = -0xaaaaaab;
831 try expect(@mulWithOverflow(i30, a, b, &res));864 ov = @mulWithOverflow(a, b);
832 try expect(res == 0x1fffffff);865 try expect(ov[0] == 0x1fffffff);
866 try expect(ov[1] == 1);
833 }867 }
834868
835 {869 {
836 var a: u32 = 3;870 var a: u32 = 3;
837 var b: u32 = 0x55555555;871 var b: u32 = 0x55555555;
838 var res: u32 = undefined;872 var ov = @mulWithOverflow(a, b);
839 try expect(!@mulWithOverflow(u32, a, b, &res));873 try expect(ov[0] == 0xffffffff);
840 try expect(res == 0xffffffff);874 try expect(ov[1] == 0);
841875
842 b = 0x55555556;876 b = 0x55555556;
843 try expect(@mulWithOverflow(u32, a, b, &res));877 ov = @mulWithOverflow(a, b);
844 try expect(res == 2);878 try expect(ov[0] == 2);
879 try expect(ov[1] == 1);
845 }880 }
846881
847 {882 {
848 var a: i32 = 3;883 var a: i32 = 3;
849 var b: i32 = -0x2aaaaaaa;884 var b: i32 = -0x2aaaaaaa;
850 var res: i32 = undefined;885 var ov = @mulWithOverflow(a, b);
851 try expect(!@mulWithOverflow(i32, a, b, &res));886 try expect(ov[0] == -0x7ffffffe);
852 try expect(res == -0x7ffffffe);887 try expect(ov[1] == 0);
853888
854 b = -0x2aaaaaab;889 b = -0x2aaaaaab;
855 try expect(@mulWithOverflow(i32, a, b, &res));890 ov = @mulWithOverflow(a, b);
856 try expect(res == 0x7fffffff);891 try expect(ov[0] == 0x7fffffff);
892 try expect(ov[1] == 1);
857 }893 }
858}894}
859895
860test "@mulWithOverflow bitsize > 32" {896test "@mulWithOverflow bitsize > 32" {
897 // aarch64 fails on a release build of the compiler.
898 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
861 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO899 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
862 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO900 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
863 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO901 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -865,140 +903,181 @@ test "@mulWithOverflow bitsize > 32" {...@@ -865,140 +903,181 @@ test "@mulWithOverflow bitsize > 32" {
865 {903 {
866 var a: u62 = 3;904 var a: u62 = 3;
867 var b: u62 = 0x1555555555555555;905 var b: u62 = 0x1555555555555555;
868 var res: u62 = undefined;906 var ov = @mulWithOverflow(a, b);
869 try expect(!@mulWithOverflow(u62, a, b, &res));907 try expect(ov[0] == 0x3fffffffffffffff);
870 try expect(res == 0x3fffffffffffffff);908 try expect(ov[1] == 0);
871909
872 b = 0x1555555555555556;910 b = 0x1555555555555556;
873 try expect(@mulWithOverflow(u62, a, b, &res));911 ov = @mulWithOverflow(a, b);
874 try expect(res == 2);912 try expect(ov[0] == 2);
913 try expect(ov[1] == 1);
875 }914 }
876915
877 {916 {
878 var a: i62 = 3;917 var a: i62 = 3;
879 var b: i62 = -0xaaaaaaaaaaaaaaa;918 var b: i62 = -0xaaaaaaaaaaaaaaa;
880 var res: i62 = undefined;919 var ov = @mulWithOverflow(a, b);
881 try expect(!@mulWithOverflow(i62, a, b, &res));920 try expect(ov[0] == -0x1ffffffffffffffe);
882 try expect(res == -0x1ffffffffffffffe);921 try expect(ov[1] == 0);
883922
884 b = -0xaaaaaaaaaaaaaab;923 b = -0xaaaaaaaaaaaaaab;
885 try expect(@mulWithOverflow(i62, a, b, &res));924 ov = @mulWithOverflow(a, b);
886 try expect(res == 0x1fffffffffffffff);925 try expect(ov[0] == 0x1fffffffffffffff);
926 try expect(ov[1] == 1);
887 }927 }
888928
889 {929 {
890 var a: u64 = 3;930 var a: u64 = 3;
891 var b: u64 = 0x5555555555555555;931 var b: u64 = 0x5555555555555555;
892 var res: u64 = undefined;932 var ov = @mulWithOverflow(a, b);
893 try expect(!@mulWithOverflow(u64, a, b, &res));933 try expect(ov[0] == 0xffffffffffffffff);
894 try expect(res == 0xffffffffffffffff);934 try expect(ov[1] == 0);
895935
896 b = 0x5555555555555556;936 b = 0x5555555555555556;
897 try expect(@mulWithOverflow(u64, a, b, &res));937 ov = @mulWithOverflow(a, b);
898 try expect(res == 2);938 try expect(ov[0] == 2);
939 try expect(ov[1] == 1);
899 }940 }
900941
901 {942 {
902 var a: i64 = 3;943 var a: i64 = 3;
903 var b: i64 = -0x2aaaaaaaaaaaaaaa;944 var b: i64 = -0x2aaaaaaaaaaaaaaa;
904 var res: i64 = undefined;945 var ov = @mulWithOverflow(a, b);
905 try expect(!@mulWithOverflow(i64, a, b, &res));946 try expect(ov[0] == -0x7ffffffffffffffe);
906 try expect(res == -0x7ffffffffffffffe);947 try expect(ov[1] == 0);
907948
908 b = -0x2aaaaaaaaaaaaaab;949 b = -0x2aaaaaaaaaaaaaab;
909 try expect(@mulWithOverflow(i64, a, b, &res));950 ov = @mulWithOverflow(a, b);
910 try expect(res == 0x7fffffffffffffff);951 try expect(ov[0] == 0x7fffffffffffffff);
952 try expect(ov[1] == 1);
911 }953 }
912}954}
913955
914test "@subWithOverflow" {956test "@subWithOverflow" {
957 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
958 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
915 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO959 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
916960
917 {961 {
918 var result: u8 = undefined;962 var a: u8 = 1;
919 try expect(@subWithOverflow(u8, 1, 2, &result));963 const ov = @subWithOverflow(a, 2);
920 try expect(result == 255);964 try expect(ov[0] == 255);
921 try expect(!@subWithOverflow(u8, 1, 1, &result));965 try expect(ov[1] == 1);
922 try expect(result == 0);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 {
924 var a: u8 = 1;975 var a: u8 = 1;
925 var b: u8 = 2;976 var b: u8 = 2;
926 try expect(@subWithOverflow(u8, a, b, &result));977 var ov = @subWithOverflow(a, b);
927 try expect(result == 255);978 try expect(ov[0] == 255);
979 try expect(ov[1] == 1);
928 b = 1;980 b = 1;
929 try expect(!@subWithOverflow(u8, a, b, &result));981 ov = @subWithOverflow(a, b);
930 try expect(result == 0);982 try expect(ov[0] == 0);
983 try expect(ov[1] == 0);
931 }984 }
932985
933 {986 {
934 var a: usize = 6;987 var a: usize = 6;
935 var b: usize = 6;988 var b: usize = 6;
936 var res: usize = undefined;989 const ov = @subWithOverflow(a, b);
937 try expect(!@subWithOverflow(usize, a, b, &res));990 try expect(ov[0] == 0);
938 try expect(res == 0);991 try expect(ov[1] == 0);
939 }992 }
940993
941 {994 {
942 var a: isize = -6;995 var a: isize = -6;
943 var b: isize = -6;996 var b: isize = -6;
944 var res: isize = undefined;997 const ov = @subWithOverflow(a, b);
945 try expect(!@subWithOverflow(isize, a, b, &res));998 try expect(ov[0] == 0);
946 try expect(res == 0);999 try expect(ov[1] == 0);
947 }1000 }
948}1001}
9491002
950test "@shlWithOverflow" {1003test "@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
951 {1007 {
952 var result: u4 = undefined;
953 var a: u4 = 2;1008 var a: u4 = 2;
954 var b: u2 = 1;1009 var b: u2 = 1;
955 try expect(!@shlWithOverflow(u4, a, b, &result));1010 var ov = @shlWithOverflow(a, b);
956 try expect(result == 4);1011 try expect(ov[0] == 4);
1012 try expect(ov[1] == 0);
9571013
958 b = 3;1014 b = 3;
959 try expect(@shlWithOverflow(u4, a, b, &result));1015 ov = @shlWithOverflow(a, b);
960 try expect(result == 0);1016 try expect(ov[0] == 0);
1017 try expect(ov[1] == 1);
961 }1018 }
9621019
963 {1020 {
964 var result: i9 = undefined;
965 var a: i9 = 127;1021 var a: i9 = 127;
966 var b: u4 = 1;1022 var b: u4 = 1;
967 try expect(!@shlWithOverflow(i9, a, b, &result));1023 var ov = @shlWithOverflow(a, b);
968 try expect(result == 254);1024 try expect(ov[0] == 254);
1025 try expect(ov[1] == 0);
9691026
970 b = 2;1027 b = 2;
971 try expect(@shlWithOverflow(i9, a, b, &result));1028 ov = @shlWithOverflow(a, b);
972 try expect(result == -4);1029 try expect(ov[0] == -4);
1030 try expect(ov[1] == 1);
973 }1031 }
9741032
975 {1033 {
976 var result: u16 = undefined;1034 const ov = @shlWithOverflow(@as(u16, 0b0010111111111111), 3);
977 try expect(@shlWithOverflow(u16, 0b0010111111111111, 3, &result));1035 try expect(ov[0] == 0b0111111111111000);
978 try expect(result == 0b0111111111111000);1036 try expect(ov[1] == 1);
979 try expect(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result));1037 }
980 try expect(result == 0b1011111111111100);1038 {
9811039 const ov = @shlWithOverflow(@as(u16, 0b0010111111111111), 2);
1040 try expect(ov[0] == 0b1011111111111100);
1041 try expect(ov[1] == 0);
1042 }
1043 {
982 var a: u16 = 0b0000_0000_0000_0011;1044 var a: u16 = 0b0000_0000_0000_0011;
983 var b: u4 = 15;1045 var b: u4 = 15;
984 try expect(@shlWithOverflow(u16, a, b, &result));1046 var ov = @shlWithOverflow(a, b);
985 try expect(result == 0b1000_0000_0000_0000);1047 try expect(ov[0] == 0b1000_0000_0000_0000);
1048 try expect(ov[1] == 1);
986 b = 14;1049 b = 14;
987 try expect(!@shlWithOverflow(u16, a, b, &result));1050 ov = @shlWithOverflow(a, b);
988 try expect(result == 0b1100_0000_0000_0000);1051 try expect(ov[0] == 0b1100_0000_0000_0000);
1052 try expect(ov[1] == 0);
989 }1053 }
990}1054}
9911055
992test "overflow arithmetic with u0 values" {1056test "overflow arithmetic with u0 values" {
993 var result: u0 = undefined;1057 {
994 try expect(!@addWithOverflow(u0, 0, 0, &result));1058 var a: u0 = 0;
995 try expect(result == 0);1059 const ov = @addWithOverflow(a, 0);
996 try expect(!@subWithOverflow(u0, 0, 0, &result));1060 try expect(ov[1] == 0);
997 try expect(result == 0);1061 try expect(ov[1] == 0);
998 try expect(!@mulWithOverflow(u0, 0, 0, &result));1062 }
999 try expect(result == 0);1063 {
1000 try expect(!@shlWithOverflow(u0, 0, 0, &result));1064 var a: u0 = 0;
1001 try expect(result == 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 }
1002}1081}
10031082
1004test "allow signed integer division/remainder when values are comptime-known and positive or exact" {1083test "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" {...@@ -963,35 +963,31 @@ test "@addWithOverflow" {
963 const S = struct {963 const S = struct {
964 fn doTheTest() !void {964 fn doTheTest() !void {
965 {965 {
966 var result: @Vector(4, u8) = undefined;
967 var lhs = @Vector(4, u8){ 250, 250, 250, 250 };966 var lhs = @Vector(4, u8){ 250, 250, 250, 250 };
968 var rhs = @Vector(4, u8){ 0, 5, 6, 10 };967 var rhs = @Vector(4, u8){ 0, 5, 6, 10 };
969 var overflow = @addWithOverflow(@Vector(4, u8), lhs, rhs, &result);968 var overflow = @addWithOverflow(lhs, rhs)[1];
970 var expected: @Vector(4, bool) = .{ false, false, true, true };969 var expected: @Vector(4, u1) = .{ 0, 0, 1, 1 };
971 try expectEqual(expected, overflow);970 try expectEqual(expected, overflow);
972 }971 }
973 {972 {
974 var result: @Vector(4, i8) = undefined;
975 var lhs = @Vector(4, i8){ -125, -125, 125, 125 };973 var lhs = @Vector(4, i8){ -125, -125, 125, 125 };
976 var rhs = @Vector(4, i8){ -3, -4, 2, 3 };974 var rhs = @Vector(4, i8){ -3, -4, 2, 3 };
977 var overflow = @addWithOverflow(@Vector(4, i8), lhs, rhs, &result);975 var overflow = @addWithOverflow(lhs, rhs)[1];
978 var expected: @Vector(4, bool) = .{ false, true, false, true };976 var expected: @Vector(4, u1) = .{ 0, 1, 0, 1 };
979 try expectEqual(expected, overflow);977 try expectEqual(expected, overflow);
980 }978 }
981 {979 {
982 var result: @Vector(4, u1) = undefined;
983 var lhs = @Vector(4, u1){ 0, 0, 1, 1 };980 var lhs = @Vector(4, u1){ 0, 0, 1, 1 };
984 var rhs = @Vector(4, u1){ 0, 1, 0, 1 };981 var rhs = @Vector(4, u1){ 0, 1, 0, 1 };
985 var overflow = @addWithOverflow(@Vector(4, u1), lhs, rhs, &result);982 var overflow = @addWithOverflow(lhs, rhs)[1];
986 var expected: @Vector(4, bool) = .{ false, false, false, true };983 var expected: @Vector(4, u1) = .{ 0, 0, 0, 1 };
987 try expectEqual(expected, overflow);984 try expectEqual(expected, overflow);
988 }985 }
989 {986 {
990 var result: @Vector(4, u0) = undefined;
991 var lhs = @Vector(4, u0){ 0, 0, 0, 0 };987 var lhs = @Vector(4, u0){ 0, 0, 0, 0 };
992 var rhs = @Vector(4, u0){ 0, 0, 0, 0 };988 var rhs = @Vector(4, u0){ 0, 0, 0, 0 };
993 var overflow = @addWithOverflow(@Vector(4, u0), lhs, rhs, &result);989 var overflow = @addWithOverflow(lhs, rhs)[1];
994 var expected: @Vector(4, bool) = .{ false, false, false, false };990 var expected: @Vector(4, u1) = .{ 0, 0, 0, 0 };
995 try expectEqual(expected, overflow);991 try expectEqual(expected, overflow);
996 }992 }
997 }993 }
...@@ -1010,19 +1006,17 @@ test "@subWithOverflow" {...@@ -1010,19 +1006,17 @@ test "@subWithOverflow" {
1010 const S = struct {1006 const S = struct {
1011 fn doTheTest() !void {1007 fn doTheTest() !void {
1012 {1008 {
1013 var result: @Vector(2, u8) = undefined;
1014 var lhs = @Vector(2, u8){ 5, 5 };1009 var lhs = @Vector(2, u8){ 5, 5 };
1015 var rhs = @Vector(2, u8){ 5, 6 };1010 var rhs = @Vector(2, u8){ 5, 6 };
1016 var overflow = @subWithOverflow(@Vector(2, u8), lhs, rhs, &result);1011 var overflow = @subWithOverflow(lhs, rhs)[1];
1017 var expected: @Vector(2, bool) = .{ false, true };1012 var expected: @Vector(2, u1) = .{ 0, 1 };
1018 try expectEqual(expected, overflow);1013 try expectEqual(expected, overflow);
1019 }1014 }
1020 {1015 {
1021 var result: @Vector(4, i8) = undefined;
1022 var lhs = @Vector(4, i8){ -120, -120, 120, 120 };1016 var lhs = @Vector(4, i8){ -120, -120, 120, 120 };
1023 var rhs = @Vector(4, i8){ 8, 9, -7, -8 };1017 var rhs = @Vector(4, i8){ 8, 9, -7, -8 };
1024 var overflow = @subWithOverflow(@Vector(4, i8), lhs, rhs, &result);1018 var overflow = @subWithOverflow(lhs, rhs)[1];
1025 var expected: @Vector(4, bool) = .{ false, true, false, true };1019 var expected: @Vector(4, u1) = .{ 0, 1, 0, 1 };
1026 try expectEqual(expected, overflow);1020 try expectEqual(expected, overflow);
1027 }1021 }
1028 }1022 }
...@@ -1040,11 +1034,10 @@ test "@mulWithOverflow" {...@@ -1040,11 +1034,10 @@ test "@mulWithOverflow" {
10401034
1041 const S = struct {1035 const S = struct {
1042 fn doTheTest() !void {1036 fn doTheTest() !void {
1043 var result: @Vector(4, u8) = undefined;
1044 var lhs = @Vector(4, u8){ 10, 10, 10, 10 };1037 var lhs = @Vector(4, u8){ 10, 10, 10, 10 };
1045 var rhs = @Vector(4, u8){ 25, 26, 0, 30 };1038 var rhs = @Vector(4, u8){ 25, 26, 0, 30 };
1046 var overflow = @mulWithOverflow(@Vector(4, u8), lhs, rhs, &result);1039 var overflow = @mulWithOverflow(lhs, rhs)[1];
1047 var expected: @Vector(4, bool) = .{ false, true, false, true };1040 var expected: @Vector(4, u1) = .{ 0, 1, 0, 1 };
1048 try expectEqual(expected, overflow);1041 try expectEqual(expected, overflow);
1049 }1042 }
1050 };1043 };
...@@ -1062,11 +1055,10 @@ test "@shlWithOverflow" {...@@ -1062,11 +1055,10 @@ test "@shlWithOverflow" {
10621055
1063 const S = struct {1056 const S = struct {
1064 fn doTheTest() !void {1057 fn doTheTest() !void {
1065 var result: @Vector(4, u8) = undefined;
1066 var lhs = @Vector(4, u8){ 0, 1, 8, 255 };1058 var lhs = @Vector(4, u8){ 0, 1, 8, 255 };
1067 var rhs = @Vector(4, u3){ 7, 7, 7, 7 };1059 var rhs = @Vector(4, u3){ 7, 7, 7, 7 };
1068 var overflow = @shlWithOverflow(@Vector(4, u8), lhs, rhs, &result);1060 var overflow = @shlWithOverflow(lhs, rhs)[1];
1069 var expected: @Vector(4, bool) = .{ false, false, true, true };1061 var expected: @Vector(4, u1) = .{ 0, 0, 1, 1 };
1070 try expectEqual(expected, overflow);1062 try expectEqual(expected, overflow);
1071 }1063 }
1072 };1064 };