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

Merge pull request #14024 from Vexu/overflow-arithmetic

Make overflow arithmetic builtins return tuples

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

doc/langref.html.in+26-32
...@@ -5413,14 +5413,14 @@ pub fn parseU64(buf: []const u8, radix: u8) !u64 {...@@ -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/AstGen.zig+4-24
...@@ -2505,7 +2505,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2505,7 +2505,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2505 .err_union_code,2505 .err_union_code,
2506 .err_union_code_ptr,2506 .err_union_code_ptr,
2507 .ptr_type,2507 .ptr_type,
2508 .overflow_arithmetic_ptr,
2509 .enum_literal,2508 .enum_literal,
2510 .merge_error_sets,2509 .merge_error_sets,
2511 .error_union_type,2510 .error_union_type,
...@@ -2543,7 +2542,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2543,7 +2542,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2543 .type_info,2542 .type_info,
2544 .size_of,2543 .size_of,
2545 .bit_size_of,2544 .bit_size_of,
2546 .log2_int_type,
2547 .typeof_log2_int_type,2545 .typeof_log2_int_type,
2548 .ptr_to_int,2546 .ptr_to_int,
2549 .align_of,2547 .align_of,
...@@ -8236,21 +8234,7 @@ fn builtinCall(...@@ -8236,21 +8234,7 @@ fn builtinCall(
8236 .add_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .add_with_overflow),8234 .add_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .add_with_overflow),
8237 .sub_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .sub_with_overflow),8235 .sub_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .sub_with_overflow),
8238 .mul_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .mul_with_overflow),8236 .mul_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .mul_with_overflow),
8239 .shl_with_overflow => {8237 .shl_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .shl_with_overflow),
8240 const int_type = try typeExpr(gz, scope, params[0]);
8241 const log2_int_type = try gz.addUnNode(.log2_int_type, int_type, params[0]);
8242 const ptr_type = try gz.addUnNode(.overflow_arithmetic_ptr, int_type, params[0]);
8243 const lhs = try expr(gz, scope, .{ .rl = .{ .ty = int_type } }, params[1]);
8244 const rhs = try expr(gz, scope, .{ .rl = .{ .ty = log2_int_type } }, params[2]);
8245 const ptr = try expr(gz, scope, .{ .rl = .{ .ty = ptr_type } }, params[3]);
8246 const result = try gz.addExtendedPayload(.shl_with_overflow, Zir.Inst.OverflowArithmetic{
8247 .node = gz.nodeIndexToRelative(node),
8248 .lhs = lhs,
8249 .rhs = rhs,
8250 .ptr = ptr,
8251 });
8252 return rvalue(gz, ri, result, node);
8253 },
82548238
8255 .atomic_load => {8239 .atomic_load => {
8256 const result = try gz.addPlNode(.atomic_load, node, Zir.Inst.AtomicLoad{8240 const result = try gz.addPlNode(.atomic_load, node, Zir.Inst.AtomicLoad{
...@@ -8691,16 +8675,12 @@ fn overflowArithmetic(...@@ -8691,16 +8675,12 @@ fn overflowArithmetic(
8691 params: []const Ast.Node.Index,8675 params: []const Ast.Node.Index,
8692 tag: Zir.Inst.Extended,8676 tag: Zir.Inst.Extended,
8693) InnerError!Zir.Inst.Ref {8677) InnerError!Zir.Inst.Ref {
8694 const int_type = try typeExpr(gz, scope, params[0]);8678 const lhs = try expr(gz, scope, .{ .rl = .none }, params[0]);
8695 const ptr_type = try gz.addUnNode(.overflow_arithmetic_ptr, int_type, params[0]);8679 const rhs = try expr(gz, scope, .{ .rl = .none }, params[1]);
8696 const lhs = try expr(gz, scope, .{ .rl = .{ .ty = int_type } }, params[1]);8680 const result = try gz.addExtendedPayload(tag, Zir.Inst.BinNode{
8697 const rhs = try expr(gz, scope, .{ .rl = .{ .ty = int_type } }, params[2]);
8698 const ptr = try expr(gz, scope, .{ .rl = .{ .ty = ptr_type } }, params[3]);
8699 const result = try gz.addExtendedPayload(tag, Zir.Inst.OverflowArithmetic{
8700 .node = gz.nodeIndexToRelative(node),8681 .node = gz.nodeIndexToRelative(node),
8701 .lhs = lhs,8682 .lhs = lhs,
8702 .rhs = rhs,8683 .rhs = rhs,
8703 .ptr = ptr,
8704 });8684 });
8705 return rvalue(gz, ri, result, node);8685 return rvalue(gz, ri, result, node);
8706}8686}
src/Autodoc.zig-20
...@@ -1510,26 +1510,6 @@ fn walkInstruction(...@@ -1510,26 +1510,6 @@ fn walkInstruction(
15101510
1511 // return operand;1511 // return operand;
1512 // },1512 // },
1513 .overflow_arithmetic_ptr => {
1514 const un_node = data[inst_index].un_node;
1515
1516 const elem_type_ref = try self.walkRef(file, parent_scope, parent_src, un_node.operand, false);
1517 const type_slot_index = self.types.items.len;
1518 try self.types.append(self.arena, .{
1519 .Pointer = .{
1520 .size = .One,
1521 .child = elem_type_ref.expr,
1522 .is_mutable = true,
1523 .is_volatile = false,
1524 .is_allowzero = false,
1525 },
1526 });
1527
1528 return DocData.WalkResult{
1529 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
1530 .expr = .{ .type = type_slot_index },
1531 };
1532 },
1533 .ptr_type => {1513 .ptr_type => {
1534 const ptr = data[inst_index].ptr_type;1514 const ptr = data[inst_index].ptr_type;
1535 const extra = file.zir.extraData(Zir.Inst.PtrType, ptr.payload_index);1515 const extra = file.zir.extraData(Zir.Inst.PtrType, ptr.payload_index);
src/BuiltinFn.zig+4-4
...@@ -154,7 +154,7 @@ pub const list = list: {...@@ -154,7 +154,7 @@ pub const list = list: {
154 "@addWithOverflow",154 "@addWithOverflow",
155 .{155 .{
156 .tag = .add_with_overflow,156 .tag = .add_with_overflow,
157 .param_count = 4,157 .param_count = 2,
158 },158 },
159 },159 },
160 .{160 .{
...@@ -636,7 +636,7 @@ pub const list = list: {...@@ -636,7 +636,7 @@ pub const list = list: {
636 "@mulWithOverflow",636 "@mulWithOverflow",
637 .{637 .{
638 .tag = .mul_with_overflow,638 .tag = .mul_with_overflow,
639 .param_count = 4,639 .param_count = 2,
640 },640 },
641 },641 },
642 .{642 .{
...@@ -741,7 +741,7 @@ pub const list = list: {...@@ -741,7 +741,7 @@ pub const list = list: {
741 "@shlWithOverflow",741 "@shlWithOverflow",
742 .{742 .{
743 .tag = .shl_with_overflow,743 .tag = .shl_with_overflow,
744 .param_count = 4,744 .param_count = 2,
745 },745 },
746 },746 },
747 .{747 .{
...@@ -889,7 +889,7 @@ pub const list = list: {...@@ -889,7 +889,7 @@ pub const list = list: {
889 "@subWithOverflow",889 "@subWithOverflow",
890 .{890 .{
891 .tag = .sub_with_overflow,891 .tag = .sub_with_overflow,
892 .param_count = 4,892 .param_count = 2,
893 },893 },
894 },894 },
895 .{895 .{
src/Sema.zig+78-88
...@@ -971,7 +971,6 @@ fn analyzeBodyInner(...@@ -971,7 +971,6 @@ fn analyzeBodyInner(
971 .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false),971 .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false),
972 .optional_type => try sema.zirOptionalType(block, inst),972 .optional_type => try sema.zirOptionalType(block, inst),
973 .ptr_type => try sema.zirPtrType(block, inst),973 .ptr_type => try sema.zirPtrType(block, inst),
974 .overflow_arithmetic_ptr => try sema.zirOverflowArithmeticPtr(block, inst),
975 .ref => try sema.zirRef(block, inst),974 .ref => try sema.zirRef(block, inst),
976 .ret_err_value_code => try sema.zirRetErrValueCode(inst),975 .ret_err_value_code => try sema.zirRetErrValueCode(inst),
977 .shr => try sema.zirShr(block, inst, .shr),976 .shr => try sema.zirShr(block, inst, .shr),
...@@ -993,7 +992,6 @@ fn analyzeBodyInner(...@@ -993,7 +992,6 @@ fn analyzeBodyInner(
993 .bit_size_of => try sema.zirBitSizeOf(block, inst),992 .bit_size_of => try sema.zirBitSizeOf(block, inst),
994 .typeof => try sema.zirTypeof(block, inst),993 .typeof => try sema.zirTypeof(block, inst),
995 .typeof_builtin => try sema.zirTypeofBuiltin(block, inst),994 .typeof_builtin => try sema.zirTypeofBuiltin(block, inst),
996 .log2_int_type => try sema.zirLog2IntType(block, inst),
997 .typeof_log2_int_type => try sema.zirTypeofLog2IntType(block, inst),995 .typeof_log2_int_type => try sema.zirTypeofLog2IntType(block, inst),
998 .xor => try sema.zirBitwise(block, inst, .xor),996 .xor => try sema.zirBitwise(block, inst, .xor),
999 .struct_init_empty => try sema.zirStructInitEmpty(block, inst),997 .struct_init_empty => try sema.zirStructInitEmpty(block, inst),
...@@ -11762,7 +11760,7 @@ fn zirShl(...@@ -11762,7 +11760,7 @@ fn zirShl(
11762 if (scalar_ty.zigTypeTag() == .ComptimeInt) {11760 if (scalar_ty.zigTypeTag() == .ComptimeInt) {
11763 break :val shifted.wrapped_result;11761 break :val shifted.wrapped_result;
11764 }11762 }
11765 if (shifted.overflowed.compareAllWithZero(.eq)) {11763 if (shifted.overflow_bit.compareAllWithZero(.eq)) {
11766 break :val shifted.wrapped_result;11764 break :val shifted.wrapped_result;
11767 }11765 }
11768 return sema.fail(block, src, "operation caused overflow", .{});11766 return sema.fail(block, src, "operation caused overflow", .{});
...@@ -13783,24 +13781,37 @@ fn zirOverflowArithmetic(...@@ -13783,24 +13781,37 @@ fn zirOverflowArithmetic(
13783 const tracy = trace(@src());13781 const tracy = trace(@src());
13784 defer tracy.end();13782 defer tracy.end();
1378513783
13786 const extra = sema.code.extraData(Zir.Inst.OverflowArithmetic, extended.operand).data;13784 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
13787 const src = LazySrcLoc.nodeOffset(extra.node);13785 const src = LazySrcLoc.nodeOffset(extra.node);
1378813786
13789 const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };13787 const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
13790 const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };13788 const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
13791 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = extra.node };
1379213789
13793 const lhs = try sema.resolveInst(extra.lhs);13790 const uncasted_lhs = try sema.resolveInst(extra.lhs);
13794 const rhs = try sema.resolveInst(extra.rhs);13791 const uncasted_rhs = try sema.resolveInst(extra.rhs);
13795 const ptr = try sema.resolveInst(extra.ptr);
1379613792
13797 const lhs_ty = sema.typeOf(lhs);13793 const lhs_ty = sema.typeOf(uncasted_lhs);
13798 const rhs_ty = sema.typeOf(rhs);13794 const rhs_ty = sema.typeOf(uncasted_rhs);
13799 const mod = sema.mod;13795 const mod = sema.mod;
1380013796
13801 // Note, the types of lhs/rhs (also for shifting)/ptr are already correct as ensured by astgen.
13802 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);13797 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
13803 const dest_ty = lhs_ty;13798
13799 const instructions = &[_]Air.Inst.Ref{ uncasted_lhs, uncasted_rhs };
13800 const dest_ty = if (zir_tag == .shl_with_overflow)
13801 lhs_ty
13802 else
13803 try sema.resolvePeerTypes(block, src, instructions, .{
13804 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
13805 });
13806
13807 const rhs_dest_ty = if (zir_tag == .shl_with_overflow)
13808 try sema.log2IntType(block, lhs_ty, src)
13809 else
13810 dest_ty;
13811
13812 const lhs = try sema.coerce(block, dest_ty, uncasted_lhs, lhs_src);
13813 const rhs = try sema.coerce(block, rhs_dest_ty, uncasted_rhs, rhs_src);
13814
13804 if (dest_ty.scalarType().zigTypeTag() != .Int) {13815 if (dest_ty.scalarType().zigTypeTag() != .Int) {
13805 return sema.fail(block, src, "expected vector of integers or integer tag type, found '{}'", .{dest_ty.fmt(mod)});13816 return sema.fail(block, src, "expected vector of integers or integer tag type, found '{}'", .{dest_ty.fmt(mod)});
13806 }13817 }
...@@ -13809,14 +13820,11 @@ fn zirOverflowArithmetic(...@@ -13809,14 +13820,11 @@ fn zirOverflowArithmetic(
13809 const maybe_rhs_val = try sema.resolveMaybeUndefVal(rhs);13820 const maybe_rhs_val = try sema.resolveMaybeUndefVal(rhs);
1381013821
13811 const tuple_ty = try sema.overflowArithmeticTupleType(dest_ty);13822 const tuple_ty = try sema.overflowArithmeticTupleType(dest_ty);
13812 // TODO: Remove and use `ov_ty` instead.13823
13813 // This is a temporary type used until overflow arithmetic properly returns `u1` instead of `bool`.13824 var result: struct {
13814 const overflowed_ty = if (dest_ty.zigTypeTag() == .Vector) try Type.vector(sema.arena, dest_ty.vectorLen(), Type.bool) else Type.bool;13825 inst: Air.Inst.Ref = .none,
1381513826 wrapped: Value = Value.initTag(.unreachable_value),
13816 const result: struct {13827 overflow_bit: Value,
13817 /// TODO: Rename to `overflow_bit` and make of type `u1`.
13818 overflowed: Air.Inst.Ref,
13819 wrapped: Air.Inst.Ref,
13820 } = result: {13828 } = result: {
13821 switch (zir_tag) {13829 switch (zir_tag) {
13822 .add_with_overflow => {13830 .add_with_overflow => {
...@@ -13825,24 +13833,22 @@ fn zirOverflowArithmetic(...@@ -13825,24 +13833,22 @@ fn zirOverflowArithmetic(
13825 // Otherwise, if either of the argument is undefined, undefined is returned.13833 // Otherwise, if either of the argument is undefined, undefined is returned.
13826 if (maybe_lhs_val) |lhs_val| {13834 if (maybe_lhs_val) |lhs_val| {
13827 if (!lhs_val.isUndef() and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {13835 if (!lhs_val.isUndef() and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
13828 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs };13836 break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = rhs };
13829 }13837 }
13830 }13838 }
13831 if (maybe_rhs_val) |rhs_val| {13839 if (maybe_rhs_val) |rhs_val| {
13832 if (!rhs_val.isUndef() and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) {13840 if (!rhs_val.isUndef() and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
13833 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };13841 break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs };
13834 }13842 }
13835 }13843 }
13836 if (maybe_lhs_val) |lhs_val| {13844 if (maybe_lhs_val) |lhs_val| {
13837 if (maybe_rhs_val) |rhs_val| {13845 if (maybe_rhs_val) |rhs_val| {
13838 if (lhs_val.isUndef() or rhs_val.isUndef()) {13846 if (lhs_val.isUndef() or rhs_val.isUndef()) {
13839 break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) };13847 break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef };
13840 }13848 }
1384113849
13842 const result = try sema.intAddWithOverflow(lhs_val, rhs_val, dest_ty);13850 const result = try sema.intAddWithOverflow(lhs_val, rhs_val, dest_ty);
13843 const overflowed = try sema.addConstant(overflowed_ty, result.overflowed);13851 break :result .{ .overflow_bit = result.overflow_bit, .wrapped = result.wrapped_result };
13844 const wrapped = try sema.addConstant(dest_ty, result.wrapped_result);
13845 break :result .{ .overflowed = overflowed, .wrapped = wrapped };
13846 }13852 }
13847 }13853 }
13848 },13854 },
...@@ -13851,18 +13857,16 @@ fn zirOverflowArithmetic(...@@ -13851,18 +13857,16 @@ fn zirOverflowArithmetic(
13851 // Otherwise, if either result is undefined, both results are undefined.13857 // Otherwise, if either result is undefined, both results are undefined.
13852 if (maybe_rhs_val) |rhs_val| {13858 if (maybe_rhs_val) |rhs_val| {
13853 if (rhs_val.isUndef()) {13859 if (rhs_val.isUndef()) {
13854 break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) };13860 break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef };
13855 } else if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {13861 } else if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
13856 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };13862 break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs };
13857 } else if (maybe_lhs_val) |lhs_val| {13863 } else if (maybe_lhs_val) |lhs_val| {
13858 if (lhs_val.isUndef()) {13864 if (lhs_val.isUndef()) {
13859 break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) };13865 break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef };
13860 }13866 }
1386113867
13862 const result = try sema.intSubWithOverflow(lhs_val, rhs_val, dest_ty);13868 const result = try sema.intSubWithOverflow(lhs_val, rhs_val, dest_ty);
13863 const overflowed = try sema.addConstant(overflowed_ty, result.overflowed);13869 break :result .{ .overflow_bit = result.overflow_bit, .wrapped = result.wrapped_result };
13864 const wrapped = try sema.addConstant(dest_ty, result.wrapped_result);
13865 break :result .{ .overflowed = overflowed, .wrapped = wrapped };
13866 }13870 }
13867 }13871 }
13868 },13872 },
...@@ -13873,9 +13877,9 @@ fn zirOverflowArithmetic(...@@ -13873,9 +13877,9 @@ fn zirOverflowArithmetic(
13873 if (maybe_lhs_val) |lhs_val| {13877 if (maybe_lhs_val) |lhs_val| {
13874 if (!lhs_val.isUndef()) {13878 if (!lhs_val.isUndef()) {
13875 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {13879 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
13876 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };13880 break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs };
13877 } else if (try sema.compareAll(lhs_val, .eq, Value.one, dest_ty)) {13881 } else if (try sema.compareAll(lhs_val, .eq, try maybeRepeated(sema, dest_ty, Value.one), dest_ty)) {
13878 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs };13882 break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = rhs };
13879 }13883 }
13880 }13884 }
13881 }13885 }
...@@ -13883,9 +13887,9 @@ fn zirOverflowArithmetic(...@@ -13883,9 +13887,9 @@ fn zirOverflowArithmetic(
13883 if (maybe_rhs_val) |rhs_val| {13887 if (maybe_rhs_val) |rhs_val| {
13884 if (!rhs_val.isUndef()) {13888 if (!rhs_val.isUndef()) {
13885 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {13889 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
13886 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs };13890 break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = rhs };
13887 } else if (try sema.compareAll(rhs_val, .eq, Value.one, dest_ty)) {13891 } else if (try sema.compareAll(rhs_val, .eq, try maybeRepeated(sema, dest_ty, Value.one), dest_ty)) {
13888 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };13892 break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs };
13889 }13893 }
13890 }13894 }
13891 }13895 }
...@@ -13893,13 +13897,11 @@ fn zirOverflowArithmetic(...@@ -13893,13 +13897,11 @@ fn zirOverflowArithmetic(
13893 if (maybe_lhs_val) |lhs_val| {13897 if (maybe_lhs_val) |lhs_val| {
13894 if (maybe_rhs_val) |rhs_val| {13898 if (maybe_rhs_val) |rhs_val| {
13895 if (lhs_val.isUndef() or rhs_val.isUndef()) {13899 if (lhs_val.isUndef() or rhs_val.isUndef()) {
13896 break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) };13900 break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef };
13897 }13901 }
1389813902
13899 const result = try lhs_val.intMulWithOverflow(rhs_val, dest_ty, sema.arena, mod);13903 const result = try lhs_val.intMulWithOverflow(rhs_val, dest_ty, sema.arena, mod);
13900 const overflowed = try sema.addConstant(overflowed_ty, result.overflowed);13904 break :result .{ .overflow_bit = result.overflow_bit, .wrapped = result.wrapped_result };
13901 const wrapped = try sema.addConstant(dest_ty, result.wrapped_result);
13902 break :result .{ .overflowed = overflowed, .wrapped = wrapped };
13903 }13905 }
13904 }13906 }
13905 },13907 },
...@@ -13909,24 +13911,22 @@ fn zirOverflowArithmetic(...@@ -13909,24 +13911,22 @@ fn zirOverflowArithmetic(
13909 // Oterhwise if either of the arguments is undefined, both results are undefined.13911 // Oterhwise if either of the arguments is undefined, both results are undefined.
13910 if (maybe_lhs_val) |lhs_val| {13912 if (maybe_lhs_val) |lhs_val| {
13911 if (!lhs_val.isUndef() and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {13913 if (!lhs_val.isUndef() and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
13912 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };13914 break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs };
13913 }13915 }
13914 }13916 }
13915 if (maybe_rhs_val) |rhs_val| {13917 if (maybe_rhs_val) |rhs_val| {
13916 if (!rhs_val.isUndef() and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) {13918 if (!rhs_val.isUndef() and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
13917 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };13919 break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs };
13918 }13920 }
13919 }13921 }
13920 if (maybe_lhs_val) |lhs_val| {13922 if (maybe_lhs_val) |lhs_val| {
13921 if (maybe_rhs_val) |rhs_val| {13923 if (maybe_rhs_val) |rhs_val| {
13922 if (lhs_val.isUndef() or rhs_val.isUndef()) {13924 if (lhs_val.isUndef() or rhs_val.isUndef()) {
13923 break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) };13925 break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef };
13924 }13926 }
1392513927
13926 const result = try lhs_val.shlWithOverflow(rhs_val, dest_ty, sema.arena, sema.mod);13928 const result = try lhs_val.shlWithOverflow(rhs_val, dest_ty, sema.arena, sema.mod);
13927 const overflowed = try sema.addConstant(overflowed_ty, result.overflowed);13929 break :result .{ .overflow_bit = result.overflow_bit, .wrapped = result.wrapped_result };
13928 const wrapped = try sema.addConstant(dest_ty, result.wrapped_result);
13929 break :result .{ .overflowed = overflowed, .wrapped = wrapped };
13930 }13930 }
13931 }13931 }
13932 },13932 },
...@@ -13944,7 +13944,7 @@ fn zirOverflowArithmetic(...@@ -13944,7 +13944,7 @@ fn zirOverflowArithmetic(
13944 const runtime_src = if (maybe_lhs_val == null) lhs_src else rhs_src;13944 const runtime_src = if (maybe_lhs_val == null) lhs_src else rhs_src;
13945 try sema.requireRuntimeBlock(block, src, runtime_src);13945 try sema.requireRuntimeBlock(block, src, runtime_src);
1394613946
13947 const tuple = try block.addInst(.{13947 return block.addInst(.{
13948 .tag = air_tag,13948 .tag = air_tag,
13949 .data = .{ .ty_pl = .{13949 .data = .{ .ty_pl = .{
13950 .ty = try block.sema.addType(tuple_ty),13950 .ty = try block.sema.addType(tuple_ty),
...@@ -13954,16 +13954,32 @@ fn zirOverflowArithmetic(...@@ -13954,16 +13954,32 @@ fn zirOverflowArithmetic(
13954 }),13954 }),
13955 } },13955 } },
13956 });13956 });
13957 };
1395713958
13958 const wrapped = try sema.tupleFieldValByIndex(block, src, tuple, 0, tuple_ty);13959 if (result.inst != .none) {
13959 try sema.storePtr2(block, src, ptr, ptr_src, wrapped, src, .store);13960 if (try sema.resolveMaybeUndefVal(result.inst)) |some| {
13961 result.wrapped = some;
13962 result.inst = .none;
13963 }
13964 }
1396013965
13961 const overflow_bit = try sema.tupleFieldValByIndex(block, src, tuple, 1, tuple_ty);13966 if (result.inst == .none) {
13962 return block.addBitCast(overflowed_ty, overflow_bit);13967 const values = try sema.arena.alloc(Value, 2);
13963 };13968 values[0] = result.wrapped;
13969 values[1] = result.overflow_bit;
13970 const tuple_val = try Value.Tag.aggregate.create(sema.arena, values);
13971 return sema.addConstant(tuple_ty, tuple_val);
13972 }
13973
13974 const element_refs = try sema.arena.alloc(Air.Inst.Ref, 2);
13975 element_refs[0] = result.inst;
13976 element_refs[1] = try sema.addConstant(tuple_ty.structFieldType(1), result.overflow_bit);
13977 return block.addAggregateInit(tuple_ty, element_refs);
13978}
1396413979
13965 try sema.storePtr2(block, src, ptr, ptr_src, result.wrapped, src, .store);13980fn maybeRepeated(sema: *Sema, ty: Type, val: Value) !Value {
13966 return result.overflowed;13981 if (ty.zigTypeTag() != .Vector) return val;
13982 return Value.Tag.repeated.create(sema.arena, val);
13967}13983}
1396813984
13969fn overflowArithmeticTupleType(sema: *Sema, ty: Type) !Type {13985fn overflowArithmeticTupleType(sema: *Sema, ty: Type) !Type {
...@@ -16211,14 +16227,6 @@ fn zirTypeofLog2IntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil...@@ -16211,14 +16227,6 @@ fn zirTypeofLog2IntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil
16211 return sema.addType(res_ty);16227 return sema.addType(res_ty);
16212}16228}
1621316229
16214fn zirLog2IntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
16215 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
16216 const src = inst_data.src();
16217 const operand = try sema.resolveType(block, src, inst_data.operand);
16218 const res_ty = try sema.log2IntType(block, operand, src);
16219 return sema.addType(res_ty);
16220}
16221
16222fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) CompileError!Type {16230fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) CompileError!Type {
16223 switch (operand.zigTypeTag()) {16231 switch (operand.zigTypeTag()) {
16224 .ComptimeInt => return Type.comptime_int,16232 .ComptimeInt => return Type.comptime_int,
...@@ -17039,24 +17047,6 @@ fn floatOpAllowed(tag: Zir.Inst.Tag) bool {...@@ -17039,24 +17047,6 @@ fn floatOpAllowed(tag: Zir.Inst.Tag) bool {
17039 };17047 };
17040}17048}
1704117049
17042fn zirOverflowArithmeticPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
17043 const tracy = trace(@src());
17044 defer tracy.end();
17045
17046 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
17047 const elem_ty_src = inst_data.src();
17048 const elem_type = try sema.resolveType(block, elem_ty_src, inst_data.operand);
17049 const ty = try Type.ptr(sema.arena, sema.mod, .{
17050 .pointee_type = elem_type,
17051 .@"addrspace" = .generic,
17052 .mutable = true,
17053 .@"allowzero" = false,
17054 .@"volatile" = false,
17055 .size = .One,
17056 });
17057 return sema.addType(ty);
17058}
17059
17060fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {17050fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
17061 const tracy = trace(@src());17051 const tracy = trace(@src());
17062 defer tracy.end();17052 defer tracy.end();
...@@ -32613,11 +32603,11 @@ fn intSubWithOverflow(...@@ -32613,11 +32603,11 @@ fn intSubWithOverflow(
32613 const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf);32603 const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf);
32614 const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf);32604 const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf);
32615 const of_math_result = try sema.intSubWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType());32605 const of_math_result = try sema.intSubWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType());
32616 overflowed_data[i] = of_math_result.overflowed;32606 overflowed_data[i] = of_math_result.overflow_bit;
32617 scalar.* = of_math_result.wrapped_result;32607 scalar.* = of_math_result.wrapped_result;
32618 }32608 }
32619 return Value.OverflowArithmeticResult{32609 return Value.OverflowArithmeticResult{
32620 .overflowed = try Value.Tag.aggregate.create(sema.arena, overflowed_data),32610 .overflow_bit = try Value.Tag.aggregate.create(sema.arena, overflowed_data),
32621 .wrapped_result = try Value.Tag.aggregate.create(sema.arena, result_data),32611 .wrapped_result = try Value.Tag.aggregate.create(sema.arena, result_data),
32622 };32612 };
32623 }32613 }
...@@ -32645,7 +32635,7 @@ fn intSubWithOverflowScalar(...@@ -32645,7 +32635,7 @@ fn intSubWithOverflowScalar(
32645 const overflowed = result_bigint.subWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);32635 const overflowed = result_bigint.subWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);
32646 const wrapped_result = try Value.fromBigInt(sema.arena, result_bigint.toConst());32636 const wrapped_result = try Value.fromBigInt(sema.arena, result_bigint.toConst());
32647 return Value.OverflowArithmeticResult{32637 return Value.OverflowArithmeticResult{
32648 .overflowed = Value.makeBool(overflowed),32638 .overflow_bit = Value.boolToInt(overflowed),
32649 .wrapped_result = wrapped_result,32639 .wrapped_result = wrapped_result,
32650 };32640 };
32651}32641}
...@@ -32964,11 +32954,11 @@ fn intAddWithOverflow(...@@ -32964,11 +32954,11 @@ fn intAddWithOverflow(
32964 const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf);32954 const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf);
32965 const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf);32955 const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf);
32966 const of_math_result = try sema.intAddWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType());32956 const of_math_result = try sema.intAddWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType());
32967 overflowed_data[i] = of_math_result.overflowed;32957 overflowed_data[i] = of_math_result.overflow_bit;
32968 scalar.* = of_math_result.wrapped_result;32958 scalar.* = of_math_result.wrapped_result;
32969 }32959 }
32970 return Value.OverflowArithmeticResult{32960 return Value.OverflowArithmeticResult{
32971 .overflowed = try Value.Tag.aggregate.create(sema.arena, overflowed_data),32961 .overflow_bit = try Value.Tag.aggregate.create(sema.arena, overflowed_data),
32972 .wrapped_result = try Value.Tag.aggregate.create(sema.arena, result_data),32962 .wrapped_result = try Value.Tag.aggregate.create(sema.arena, result_data),
32973 };32963 };
32974 }32964 }
...@@ -32996,7 +32986,7 @@ fn intAddWithOverflowScalar(...@@ -32996,7 +32986,7 @@ fn intAddWithOverflowScalar(
32996 const overflowed = result_bigint.addWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);32986 const overflowed = result_bigint.addWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);
32997 const result = try Value.fromBigInt(sema.arena, result_bigint.toConst());32987 const result = try Value.fromBigInt(sema.arena, result_bigint.toConst());
32998 return Value.OverflowArithmeticResult{32988 return Value.OverflowArithmeticResult{
32999 .overflowed = Value.makeBool(overflowed),32989 .overflow_bit = Value.boolToInt(overflowed),
33000 .wrapped_result = result,32990 .wrapped_result = result,
33001 };32991 };
33002}32992}
src/TypedValue.zig+1-3
...@@ -225,9 +225,7 @@ pub fn print(...@@ -225,9 +225,7 @@ pub fn print(
225 .one => return writer.writeAll("1"),225 .one => return writer.writeAll("1"),
226 .void_value => return writer.writeAll("{}"),226 .void_value => return writer.writeAll("{}"),
227 .unreachable_value => return writer.writeAll("unreachable"),227 .unreachable_value => return writer.writeAll("unreachable"),
228 .the_only_possible_value => {228 .the_only_possible_value => return writer.writeAll("0"),
229 val = ty.onePossibleValue().?;
230 },
231 .bool_true => return writer.writeAll("true"),229 .bool_true => return writer.writeAll("true"),
232 .bool_false => return writer.writeAll("false"),230 .bool_false => return writer.writeAll("false"),
233 .ty => return val.castTag(.ty).?.data.print(writer, mod),231 .ty => return val.castTag(.ty).?.data.print(writer, mod),
src/Zir.zig+4-23
...@@ -539,9 +539,6 @@ pub const Inst = struct {...@@ -539,9 +539,6 @@ pub const Inst = struct {
539 /// Obtains the return type of the in-scope function.539 /// Obtains the return type of the in-scope function.
540 /// Uses the `node` union field.540 /// Uses the `node` union field.
541 ret_type,541 ret_type,
542 /// Create a pointer type for overflow arithmetic.
543 /// TODO remove when doing https://github.com/ziglang/zig/issues/10248
544 overflow_arithmetic_ptr,
545 /// Create a pointer type which can have a sentinel, alignment, address space, and/or bit range.542 /// Create a pointer type which can have a sentinel, alignment, address space, and/or bit range.
546 /// Uses the `ptr_type` union field.543 /// Uses the `ptr_type` union field.
547 ptr_type,544 ptr_type,
...@@ -600,9 +597,6 @@ pub const Inst = struct {...@@ -600,9 +597,6 @@ pub const Inst = struct {
600 /// Returns the integer type for the RHS of a shift operation.597 /// Returns the integer type for the RHS of a shift operation.
601 /// Uses the `un_node` field.598 /// Uses the `un_node` field.
602 typeof_log2_int_type,599 typeof_log2_int_type,
603 /// Given an integer type, returns the integer type for the RHS of a shift operation.
604 /// Uses the `un_node` field.
605 log2_int_type,
606 /// Asserts control-flow will not reach this instruction (`unreachable`).600 /// Asserts control-flow will not reach this instruction (`unreachable`).
607 /// Uses the `unreachable` union field.601 /// Uses the `unreachable` union field.
608 @"unreachable",602 @"unreachable",
...@@ -1121,7 +1115,6 @@ pub const Inst = struct {...@@ -1121,7 +1115,6 @@ pub const Inst = struct {
1121 .err_union_code,1115 .err_union_code,
1122 .err_union_code_ptr,1116 .err_union_code_ptr,
1123 .ptr_type,1117 .ptr_type,
1124 .overflow_arithmetic_ptr,
1125 .enum_literal,1118 .enum_literal,
1126 .merge_error_sets,1119 .merge_error_sets,
1127 .error_union_type,1120 .error_union_type,
...@@ -1132,7 +1125,6 @@ pub const Inst = struct {...@@ -1132,7 +1125,6 @@ pub const Inst = struct {
1132 .slice_sentinel,1125 .slice_sentinel,
1133 .import,1126 .import,
1134 .typeof_log2_int_type,1127 .typeof_log2_int_type,
1135 .log2_int_type,
1136 .resolve_inferred_alloc,1128 .resolve_inferred_alloc,
1137 .set_eval_branch_quota,1129 .set_eval_branch_quota,
1138 .switch_capture,1130 .switch_capture,
...@@ -1422,7 +1414,6 @@ pub const Inst = struct {...@@ -1422,7 +1414,6 @@ pub const Inst = struct {
1422 .err_union_code,1414 .err_union_code,
1423 .err_union_code_ptr,1415 .err_union_code_ptr,
1424 .ptr_type,1416 .ptr_type,
1425 .overflow_arithmetic_ptr,
1426 .enum_literal,1417 .enum_literal,
1427 .merge_error_sets,1418 .merge_error_sets,
1428 .error_union_type,1419 .error_union_type,
...@@ -1433,7 +1424,6 @@ pub const Inst = struct {...@@ -1433,7 +1424,6 @@ pub const Inst = struct {
1433 .slice_sentinel,1424 .slice_sentinel,
1434 .import,1425 .import,
1435 .typeof_log2_int_type,1426 .typeof_log2_int_type,
1436 .log2_int_type,
1437 .switch_capture,1427 .switch_capture,
1438 .switch_capture_ref,1428 .switch_capture_ref,
1439 .switch_capture_multi,1429 .switch_capture_multi,
...@@ -1664,7 +1654,6 @@ pub const Inst = struct {...@@ -1664,7 +1654,6 @@ pub const Inst = struct {
1664 .ret_err_value_code = .str_tok,1654 .ret_err_value_code = .str_tok,
1665 .ret_ptr = .node,1655 .ret_ptr = .node,
1666 .ret_type = .node,1656 .ret_type = .node,
1667 .overflow_arithmetic_ptr = .un_node,
1668 .ptr_type = .ptr_type,1657 .ptr_type = .ptr_type,
1669 .slice_start = .pl_node,1658 .slice_start = .pl_node,
1670 .slice_end = .pl_node,1659 .slice_end = .pl_node,
...@@ -1678,7 +1667,6 @@ pub const Inst = struct {...@@ -1678,7 +1667,6 @@ pub const Inst = struct {
1678 .negate_wrap = .un_node,1667 .negate_wrap = .un_node,
1679 .typeof = .un_node,1668 .typeof = .un_node,
1680 .typeof_log2_int_type = .un_node,1669 .typeof_log2_int_type = .un_node,
1681 .log2_int_type = .un_node,
1682 .@"unreachable" = .@"unreachable",1670 .@"unreachable" = .@"unreachable",
1683 .xor = .pl_node,1671 .xor = .pl_node,
1684 .optional_type = .un_node,1672 .optional_type = .un_node,
...@@ -1916,19 +1904,19 @@ pub const Inst = struct {...@@ -1916,19 +1904,19 @@ pub const Inst = struct {
1916 /// The AST node is the builtin call.1904 /// The AST node is the builtin call.
1917 typeof_peer,1905 typeof_peer,
1918 /// Implements the `@addWithOverflow` builtin.1906 /// Implements the `@addWithOverflow` builtin.
1919 /// `operand` is payload index to `OverflowArithmetic`.1907 /// `operand` is payload index to `BinNode`.
1920 /// `small` is unused.1908 /// `small` is unused.
1921 add_with_overflow,1909 add_with_overflow,
1922 /// Implements the `@subWithOverflow` builtin.1910 /// Implements the `@subWithOverflow` builtin.
1923 /// `operand` is payload index to `OverflowArithmetic`.1911 /// `operand` is payload index to `BinNode`.
1924 /// `small` is unused.1912 /// `small` is unused.
1925 sub_with_overflow,1913 sub_with_overflow,
1926 /// Implements the `@mulWithOverflow` builtin.1914 /// Implements the `@mulWithOverflow` builtin.
1927 /// `operand` is payload index to `OverflowArithmetic`.1915 /// `operand` is payload index to `BinNode`.
1928 /// `small` is unused.1916 /// `small` is unused.
1929 mul_with_overflow,1917 mul_with_overflow,
1930 /// Implements the `@shlWithOverflow` builtin.1918 /// Implements the `@shlWithOverflow` builtin.
1931 /// `operand` is payload index to `OverflowArithmetic`.1919 /// `operand` is payload index to `BinNode`.
1932 /// `small` is unused.1920 /// `small` is unused.
1933 shl_with_overflow,1921 shl_with_overflow,
1934 /// `operand` is payload index to `UnNode`.1922 /// `operand` is payload index to `UnNode`.
...@@ -3430,13 +3418,6 @@ pub const Inst = struct {...@@ -3430,13 +3418,6 @@ pub const Inst = struct {
3430 field_name: Ref,3418 field_name: Ref,
3431 };3419 };
34323420
3433 pub const OverflowArithmetic = struct {
3434 node: i32,
3435 lhs: Ref,
3436 rhs: Ref,
3437 ptr: Ref,
3438 };
3439
3440 pub const Cmpxchg = struct {3421 pub const Cmpxchg = struct {
3441 node: i32,3422 node: i32,
3442 ptr: Ref,3423 ptr: Ref,
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 {
src/print_zir.zig+1-5
...@@ -185,7 +185,6 @@ const Writer = struct {...@@ -185,7 +185,6 @@ const Writer = struct {
185 .size_of,185 .size_of,
186 .bit_size_of,186 .bit_size_of,
187 .typeof_log2_int_type,187 .typeof_log2_int_type,
188 .log2_int_type,
189 .ptr_to_int,188 .ptr_to_int,
190 .compile_error,189 .compile_error,
191 .set_eval_branch_quota,190 .set_eval_branch_quota,
...@@ -230,7 +229,6 @@ const Writer = struct {...@@ -230,7 +229,6 @@ const Writer = struct {
230 .validate_struct_init_ty,229 .validate_struct_init_ty,
231 .make_ptr_const,230 .make_ptr_const,
232 .validate_deref,231 .validate_deref,
233 .overflow_arithmetic_ptr,
234 .check_comptime_control_flow,232 .check_comptime_control_flow,
235 => try self.writeUnNode(stream, inst),233 => try self.writeUnNode(stream, inst),
236234
...@@ -1153,14 +1151,12 @@ const Writer = struct {...@@ -1153,14 +1151,12 @@ const Writer = struct {
1153 }1151 }
11541152
1155 fn writeOverflowArithmetic(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {1153 fn writeOverflowArithmetic(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
1156 const extra = self.code.extraData(Zir.Inst.OverflowArithmetic, extended.operand).data;1154 const extra = self.code.extraData(Zir.Inst.BinNode, extended.operand).data;
1157 const src = LazySrcLoc.nodeOffset(extra.node);1155 const src = LazySrcLoc.nodeOffset(extra.node);
11581156
1159 try self.writeInstRef(stream, extra.lhs);1157 try self.writeInstRef(stream, extra.lhs);
1160 try stream.writeAll(", ");1158 try stream.writeAll(", ");
1161 try self.writeInstRef(stream, extra.rhs);1159 try self.writeInstRef(stream, extra.rhs);
1162 try stream.writeAll(", ");
1163 try self.writeInstRef(stream, extra.ptr);
1164 try stream.writeAll(")) ");1160 try stream.writeAll(")) ");
1165 try self.writeSrc(stream, src);1161 try self.writeSrc(stream, src);
1166 }1162 }
src/type.zig+1
...@@ -3123,6 +3123,7 @@ pub const Type = extern union {...@@ -3123,6 +3123,7 @@ pub const Type = extern union {
3123 for (tuple.types) |field_ty, i| {3123 for (tuple.types) |field_ty, i| {
3124 const val = tuple.values[i];3124 const val = tuple.values[i];
3125 if (val.tag() != .unreachable_value) continue; // comptime field3125 if (val.tag() != .unreachable_value) continue; // comptime field
3126 if (!(field_ty.hasRuntimeBits())) continue;
31263127
3127 switch (try field_ty.abiAlignmentAdvanced(target, strat)) {3128 switch (try field_ty.abiAlignmentAdvanced(target, strat)) {
3128 .scalar => |field_align| big_align = @max(big_align, field_align),3129 .scalar => |field_align| big_align = @max(big_align, field_align),
src/value.zig+13-8
...@@ -1378,6 +1378,7 @@ pub const Value = extern union {...@@ -1378,6 +1378,7 @@ pub const Value = extern union {
1378 var enum_buffer: Payload.U64 = undefined;1378 var enum_buffer: Payload.U64 = undefined;
1379 const int_val = val.enumToInt(ty, &enum_buffer);1379 const int_val = val.enumToInt(ty, &enum_buffer);
13801380
1381 if (abi_size == 0) return;
1381 if (abi_size <= @sizeOf(u64)) {1382 if (abi_size <= @sizeOf(u64)) {
1382 const int: u64 = switch (int_val.tag()) {1383 const int: u64 = switch (int_val.tag()) {
1383 .zero => 0,1384 .zero => 0,
...@@ -1571,6 +1572,7 @@ pub const Value = extern union {...@@ -1571,6 +1572,7 @@ pub const Value = extern union {
1571 const abi_size = @intCast(usize, ty.abiSize(target));1572 const abi_size = @intCast(usize, ty.abiSize(target));
15721573
1573 const bits = int_info.bits;1574 const bits = int_info.bits;
1575 if (bits == 0) return Value.zero;
1574 if (bits <= 64) switch (int_info.signedness) { // Fast path for integers <= u641576 if (bits <= 64) switch (int_info.signedness) { // Fast path for integers <= u64
1575 .signed => return Value.Tag.int_i64.create(arena, std.mem.readVarPackedInt(i64, buffer, bit_offset, bits, endian, .signed)),1577 .signed => return Value.Tag.int_i64.create(arena, std.mem.readVarPackedInt(i64, buffer, bit_offset, bits, endian, .signed)),
1576 .unsigned => return Value.Tag.int_u64.create(arena, std.mem.readVarPackedInt(u64, buffer, bit_offset, bits, endian, .unsigned)),1578 .unsigned => return Value.Tag.int_u64.create(arena, std.mem.readVarPackedInt(u64, buffer, bit_offset, bits, endian, .unsigned)),
...@@ -3259,8 +3261,7 @@ pub const Value = extern union {...@@ -3259,8 +3261,7 @@ pub const Value = extern union {
3259 }3261 }
32603262
3261 pub const OverflowArithmeticResult = struct {3263 pub const OverflowArithmeticResult = struct {
3262 /// TODO: Rename to `overflow_bit` and make of type `u1`.3264 overflow_bit: Value,
3263 overflowed: Value,
3264 wrapped_result: Value,3265 wrapped_result: Value,
3265 };3266 };
32663267
...@@ -3395,11 +3396,11 @@ pub const Value = extern union {...@@ -3395,11 +3396,11 @@ pub const Value = extern union {
3395 const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf);3396 const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf);
3396 const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf);3397 const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf);
3397 const of_math_result = try intMulWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType(), arena, target);3398 const of_math_result = try intMulWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType(), arena, target);
3398 overflowed_data[i] = of_math_result.overflowed;3399 overflowed_data[i] = of_math_result.overflow_bit;
3399 scalar.* = of_math_result.wrapped_result;3400 scalar.* = of_math_result.wrapped_result;
3400 }3401 }
3401 return OverflowArithmeticResult{3402 return OverflowArithmeticResult{
3402 .overflowed = try Value.Tag.aggregate.create(arena, overflowed_data),3403 .overflow_bit = try Value.Tag.aggregate.create(arena, overflowed_data),
3403 .wrapped_result = try Value.Tag.aggregate.create(arena, result_data),3404 .wrapped_result = try Value.Tag.aggregate.create(arena, result_data),
3404 };3405 };
3405 }3406 }
...@@ -3436,7 +3437,7 @@ pub const Value = extern union {...@@ -3436,7 +3437,7 @@ pub const Value = extern union {
3436 }3437 }
34373438
3438 return OverflowArithmeticResult{3439 return OverflowArithmeticResult{
3439 .overflowed = makeBool(overflowed),3440 .overflow_bit = boolToInt(overflowed),
3440 .wrapped_result = try fromBigInt(arena, result_bigint.toConst()),3441 .wrapped_result = try fromBigInt(arena, result_bigint.toConst()),
3441 };3442 };
3442 }3443 }
...@@ -4141,11 +4142,11 @@ pub const Value = extern union {...@@ -4141,11 +4142,11 @@ pub const Value = extern union {
4141 const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf);4142 const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf);
4142 const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf);4143 const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf);
4143 const of_math_result = try shlWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType(), allocator, target);4144 const of_math_result = try shlWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType(), allocator, target);
4144 overflowed_data[i] = of_math_result.overflowed;4145 overflowed_data[i] = of_math_result.overflow_bit;
4145 scalar.* = of_math_result.wrapped_result;4146 scalar.* = of_math_result.wrapped_result;
4146 }4147 }
4147 return OverflowArithmeticResult{4148 return OverflowArithmeticResult{
4148 .overflowed = try Value.Tag.aggregate.create(allocator, overflowed_data),4149 .overflow_bit = try Value.Tag.aggregate.create(allocator, overflowed_data),
4149 .wrapped_result = try Value.Tag.aggregate.create(allocator, result_data),4150 .wrapped_result = try Value.Tag.aggregate.create(allocator, result_data),
4150 };4151 };
4151 }4152 }
...@@ -4178,7 +4179,7 @@ pub const Value = extern union {...@@ -4178,7 +4179,7 @@ pub const Value = extern union {
4178 result_bigint.truncate(result_bigint.toConst(), info.signedness, info.bits);4179 result_bigint.truncate(result_bigint.toConst(), info.signedness, info.bits);
4179 }4180 }
4180 return OverflowArithmeticResult{4181 return OverflowArithmeticResult{
4181 .overflowed = makeBool(overflowed),4182 .overflow_bit = boolToInt(overflowed),
4182 .wrapped_result = try fromBigInt(allocator, result_bigint.toConst()),4183 .wrapped_result = try fromBigInt(allocator, result_bigint.toConst()),
4183 };4184 };
4184 }4185 }
...@@ -5492,6 +5493,10 @@ pub const Value = extern union {...@@ -5492,6 +5493,10 @@ pub const Value = extern union {
5492 return if (x) Value.true else Value.false;5493 return if (x) Value.true else Value.false;
5493 }5494 }
54945495
5496 pub fn boolToInt(x: bool) Value {
5497 return if (x) Value.one else Value.zero;
5498 }
5499
5495 pub const RuntimeIndex = enum(u32) {5500 pub const RuntimeIndex = enum(u32) {
5496 zero = 0,5501 zero = 0,
5497 comptime_field_ptr = std.math.maxInt(u32),5502 comptime_field_ptr = std.math.maxInt(u32),
stage1/zig1.wasm
Binary files a/stage1/zig1.wasm and b/stage1/zig1.wasm differ
test/behavior/cast.zig+13
...@@ -1505,3 +1505,16 @@ test "implicit cast from [:0]T to [*c]T" {...@@ -1505,3 +1505,16 @@ test "implicit cast from [:0]T to [*c]T" {
1505 try expect(c.len == a.len);1505 try expect(c.len == a.len);
1506 try expect(c.ptr == a.ptr);1506 try expect(c.ptr == a.ptr);
1507}1507}
1508
1509test "bitcast packed struct with u0" {
1510 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1511 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1512 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1513
1514 const S = packed struct(u2) { a: u0, b: u2 };
1515 const s = @bitCast(S, @as(u2, 2));
1516 try expect(s.a == 0);
1517 try expect(s.b == 2);
1518 const i = @bitCast(u2, s);
1519 try expect(i == 2);
1520}
test/behavior/eval.zig+4-11
...@@ -489,18 +489,11 @@ test "comptime bitwise operators" {...@@ -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
...@@ -533,6 +533,7 @@ fn testUnsignedNegationWrappingEval(x: u16) !void {...@@ -533,6 +533,7 @@ fn testUnsignedNegationWrappingEval(x: u16) !void {
533533
534test "negation wrapping" {534test "negation wrapping" {
535 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO535 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
536 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
536 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO537 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
537538
538 try expectEqual(@as(u1, 1), negateWrap(u1, 1));539 try expectEqual(@as(u1, 1), negateWrap(u1, 1));
...@@ -632,42 +633,53 @@ test "128-bit multiplication" {...@@ -632,42 +633,53 @@ test "128-bit multiplication" {
632}633}
633634
634test "@addWithOverflow" {635test "@addWithOverflow" {
636 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
637 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
635 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO638 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
636639
637 {640 {
638 var result: u8 = undefined;641 var a: u8 = 250;
639 try expect(@addWithOverflow(u8, 250, 100, &result));642 const ov = @addWithOverflow(a, 100);
640 try expect(result == 94);643 try expect(ov[0] == 94);
641 try expect(!@addWithOverflow(u8, 100, 150, &result));644 try expect(ov[1] == 1);
642 try expect(result == 250);645 }
643646 {
647 var a: u8 = 100;
648 const ov = @addWithOverflow(a, 150);
649 try expect(ov[0] == 250);
650 try expect(ov[1] == 0);
651 }
652 {
644 var a: u8 = 200;653 var a: u8 = 200;
645 var b: u8 = 99;654 var b: u8 = 99;
646 try expect(@addWithOverflow(u8, a, b, &result));655 var ov = @addWithOverflow(a, b);
647 try expect(result == 43);656 try expect(ov[0] == 43);
657 try expect(ov[1] == 1);
648 b = 55;658 b = 55;
649 try expect(!@addWithOverflow(u8, a, b, &result));659 ov = @addWithOverflow(a, b);
650 try expect(result == 255);660 try expect(ov[0] == 255);
661 try expect(ov[1] == 0);
651 }662 }
652663
653 {664 {
654 var a: usize = 6;665 var a: usize = 6;
655 var b: usize = 6;666 var b: usize = 6;
656 var res: usize = undefined;667 const ov = @addWithOverflow(a, b);
657 try expect(!@addWithOverflow(usize, a, b, &res));668 try expect(ov[0] == 12);
658 try expect(res == 12);669 try expect(ov[1] == 0);
659 }670 }
660671
661 {672 {
662 var a: isize = -6;673 var a: isize = -6;
663 var b: isize = -6;674 var b: isize = -6;
664 var res: isize = undefined;675 const ov = @addWithOverflow(a, b);
665 try expect(!@addWithOverflow(isize, a, b, &res));676 try expect(ov[0] == -12);
666 try expect(res == -12);677 try expect(ov[1] == 0);
667 }678 }
668}679}
669680
670test "small int addition" {681test "small int addition" {
682 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
671 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO683 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
672684
673 var x: u2 = 0;685 var x: u2 = 0;
...@@ -682,180 +694,206 @@ test "small int addition" {...@@ -682,180 +694,206 @@ test "small int addition" {
682 x += 1;694 x += 1;
683 try expect(x == 3);695 try expect(x == 3);
684696
685 var result: @TypeOf(x) = 3;697 const ov = @addWithOverflow(x, 1);
686 try expect(@addWithOverflow(@TypeOf(x), x, 1, &result));698 try expect(ov[0] == 0);
687699 try expect(ov[1] == 1);
688 try expect(result == 0);
689}700}
690701
691test "basic @mulWithOverflow" {702test "basic @mulWithOverflow" {
692 var result: u8 = undefined;703 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
693 try expect(@mulWithOverflow(u8, 86, 3, &result));704 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
694 try expect(result == 2);705 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
695 try expect(!@mulWithOverflow(u8, 85, 3, &result));706
696 try expect(result == 255);707 {
708 var a: u8 = 86;
709 const ov = @mulWithOverflow(a, 3);
710 try expect(ov[0] == 2);
711 try expect(ov[1] == 1);
712 }
713 {
714 var a: u8 = 85;
715 const ov = @mulWithOverflow(a, 3);
716 try expect(ov[0] == 255);
717 try expect(ov[1] == 0);
718 }
697719
698 var a: u8 = 123;720 var a: u8 = 123;
699 var b: u8 = 2;721 var b: u8 = 2;
700 try expect(!@mulWithOverflow(u8, a, b, &result));722 var ov = @mulWithOverflow(a, b);
701 try expect(result == 246);723 try expect(ov[0] == 246);
724 try expect(ov[1] == 0);
702725
703 b = 4;726 b = 4;
704 try expect(@mulWithOverflow(u8, a, b, &result));727 ov = @mulWithOverflow(a, b);
705 try expect(result == 236);728 try expect(ov[0] == 236);
729 try expect(ov[1] == 1);
706}730}
707731
708// TODO migrate to this for all backends once they handle more cases
709test "extensive @mulWithOverflow" {732test "extensive @mulWithOverflow" {
733 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
710 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO734 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
735 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
711736
712 {737 {
713 var a: u5 = 3;738 var a: u5 = 3;
714 var b: u5 = 10;739 var b: u5 = 10;
715 var res: u5 = undefined;740 var ov = @mulWithOverflow(a, b);
716 try expect(!@mulWithOverflow(u5, a, b, &res));741 try expect(ov[0] == 30);
717 try expect(res == 30);742 try expect(ov[1] == 0);
718743
719 b = 11;744 b = 11;
720 try expect(@mulWithOverflow(u5, a, b, &res));745 ov = @mulWithOverflow(a, b);
721 try expect(res == 1);746 try expect(ov[0] == 1);
747 try expect(ov[1] == 1);
722 }748 }
723749
724 {750 {
725 var a: i5 = 3;751 var a: i5 = 3;
726 var b: i5 = -5;752 var b: i5 = -5;
727 var res: i5 = undefined;753 var ov = @mulWithOverflow(a, b);
728 try expect(!@mulWithOverflow(i5, a, b, &res));754 try expect(ov[0] == -15);
729 try expect(res == -15);755 try expect(ov[1] == 0);
730756
731 b = -6;757 b = -6;
732 try expect(@mulWithOverflow(i5, a, b, &res));758 ov = @mulWithOverflow(a, b);
733 try expect(res == 14);759 try expect(ov[0] == 14);
760 try expect(ov[1] == 1);
734 }761 }
735762
736 {763 {
737 var a: u8 = 3;764 var a: u8 = 3;
738 var b: u8 = 85;765 var b: u8 = 85;
739 var res: u8 = undefined;
740766
741 try expect(!@mulWithOverflow(u8, a, b, &res));767 var ov = @mulWithOverflow(a, b);
742 try expect(res == 255);768 try expect(ov[0] == 255);
769 try expect(ov[1] == 0);
743770
744 b = 86;771 b = 86;
745 try expect(@mulWithOverflow(u8, a, b, &res));772 ov = @mulWithOverflow(a, b);
746 try expect(res == 2);773 try expect(ov[0] == 2);
774 try expect(ov[1] == 1);
747 }775 }
748776
749 {777 {
750 var a: i8 = 3;778 var a: i8 = 3;
751 var b: i8 = -42;779 var b: i8 = -42;
752 var res: i8 = undefined;780 var ov = @mulWithOverflow(a, b);
753 try expect(!@mulWithOverflow(i8, a, b, &res));781 try expect(ov[0] == -126);
754 try expect(res == -126);782 try expect(ov[1] == 0);
755783
756 b = -43;784 b = -43;
757 try expect(@mulWithOverflow(i8, a, b, &res));785 ov = @mulWithOverflow(a, b);
758 try expect(res == 127);786 try expect(ov[0] == 127);
787 try expect(ov[1] == 1);
759 }788 }
760789
761 {790 {
762 var a: u14 = 3;791 var a: u14 = 3;
763 var b: u14 = 0x1555;792 var b: u14 = 0x1555;
764 var res: u14 = undefined;793 var ov = @mulWithOverflow(a, b);
765 try expect(!@mulWithOverflow(u14, a, b, &res));794 try expect(ov[0] == 0x3fff);
766 try expect(res == 0x3fff);795 try expect(ov[1] == 0);
767796
768 b = 0x1556;797 b = 0x1556;
769 try expect(@mulWithOverflow(u14, a, b, &res));798 ov = @mulWithOverflow(a, b);
770 try expect(res == 2);799 try expect(ov[0] == 2);
800 try expect(ov[1] == 1);
771 }801 }
772802
773 {803 {
774 var a: i14 = 3;804 var a: i14 = 3;
775 var b: i14 = -0xaaa;805 var b: i14 = -0xaaa;
776 var res: i14 = undefined;806 var ov = @mulWithOverflow(a, b);
777 try expect(!@mulWithOverflow(i14, a, b, &res));807 try expect(ov[0] == -0x1ffe);
778 try expect(res == -0x1ffe);808 try expect(ov[1] == 0);
779809
780 b = -0xaab;810 b = -0xaab;
781 try expect(@mulWithOverflow(i14, a, b, &res));811 ov = @mulWithOverflow(a, b);
782 try expect(res == 0x1fff);812 try expect(ov[0] == 0x1fff);
783 }813 }
784814
785 {815 {
786 var a: u16 = 3;816 var a: u16 = 3;
787 var b: u16 = 0x5555;817 var b: u16 = 0x5555;
788 var res: u16 = undefined;818 var ov = @mulWithOverflow(a, b);
789 try expect(!@mulWithOverflow(u16, a, b, &res));819 try expect(ov[0] == 0xffff);
790 try expect(res == 0xffff);820 try expect(ov[1] == 0);
791821
792 b = 0x5556;822 b = 0x5556;
793 try expect(@mulWithOverflow(u16, a, b, &res));823 ov = @mulWithOverflow(a, b);
794 try expect(res == 2);824 try expect(ov[0] == 2);
825 try expect(ov[1] == 1);
795 }826 }
796827
797 {828 {
798 var a: i16 = 3;829 var a: i16 = 3;
799 var b: i16 = -0x2aaa;830 var b: i16 = -0x2aaa;
800 var res: i16 = undefined;831 var ov = @mulWithOverflow(a, b);
801 try expect(!@mulWithOverflow(i16, a, b, &res));832 try expect(ov[0] == -0x7ffe);
802 try expect(res == -0x7ffe);833 try expect(ov[1] == 0);
803834
804 b = -0x2aab;835 b = -0x2aab;
805 try expect(@mulWithOverflow(i16, a, b, &res));836 ov = @mulWithOverflow(a, b);
806 try expect(res == 0x7fff);837 try expect(ov[0] == 0x7fff);
838 try expect(ov[1] == 1);
807 }839 }
808840
809 {841 {
810 var a: u30 = 3;842 var a: u30 = 3;
811 var b: u30 = 0x15555555;843 var b: u30 = 0x15555555;
812 var res: u30 = undefined;844 var ov = @mulWithOverflow(a, b);
813 try expect(!@mulWithOverflow(u30, a, b, &res));845 try expect(ov[0] == 0x3fffffff);
814 try expect(res == 0x3fffffff);846 try expect(ov[1] == 0);
815847
816 b = 0x15555556;848 b = 0x15555556;
817 try expect(@mulWithOverflow(u30, a, b, &res));849 ov = @mulWithOverflow(a, b);
818 try expect(res == 2);850 try expect(ov[0] == 2);
851 try expect(ov[1] == 1);
819 }852 }
820853
821 {854 {
822 var a: i30 = 3;855 var a: i30 = 3;
823 var b: i30 = -0xaaaaaaa;856 var b: i30 = -0xaaaaaaa;
824 var res: i30 = undefined;857 var ov = @mulWithOverflow(a, b);
825 try expect(!@mulWithOverflow(i30, a, b, &res));858 try expect(ov[0] == -0x1ffffffe);
826 try expect(res == -0x1ffffffe);859 try expect(ov[1] == 0);
827860
828 b = -0xaaaaaab;861 b = -0xaaaaaab;
829 try expect(@mulWithOverflow(i30, a, b, &res));862 ov = @mulWithOverflow(a, b);
830 try expect(res == 0x1fffffff);863 try expect(ov[0] == 0x1fffffff);
864 try expect(ov[1] == 1);
831 }865 }
832866
833 {867 {
834 var a: u32 = 3;868 var a: u32 = 3;
835 var b: u32 = 0x55555555;869 var b: u32 = 0x55555555;
836 var res: u32 = undefined;870 var ov = @mulWithOverflow(a, b);
837 try expect(!@mulWithOverflow(u32, a, b, &res));871 try expect(ov[0] == 0xffffffff);
838 try expect(res == 0xffffffff);872 try expect(ov[1] == 0);
839873
840 b = 0x55555556;874 b = 0x55555556;
841 try expect(@mulWithOverflow(u32, a, b, &res));875 ov = @mulWithOverflow(a, b);
842 try expect(res == 2);876 try expect(ov[0] == 2);
877 try expect(ov[1] == 1);
843 }878 }
844879
845 {880 {
846 var a: i32 = 3;881 var a: i32 = 3;
847 var b: i32 = -0x2aaaaaaa;882 var b: i32 = -0x2aaaaaaa;
848 var res: i32 = undefined;883 var ov = @mulWithOverflow(a, b);
849 try expect(!@mulWithOverflow(i32, a, b, &res));884 try expect(ov[0] == -0x7ffffffe);
850 try expect(res == -0x7ffffffe);885 try expect(ov[1] == 0);
851886
852 b = -0x2aaaaaab;887 b = -0x2aaaaaab;
853 try expect(@mulWithOverflow(i32, a, b, &res));888 ov = @mulWithOverflow(a, b);
854 try expect(res == 0x7fffffff);889 try expect(ov[0] == 0x7fffffff);
890 try expect(ov[1] == 1);
855 }891 }
856}892}
857893
858test "@mulWithOverflow bitsize > 32" {894test "@mulWithOverflow bitsize > 32" {
895 // aarch64 fails on a release build of the compiler.
896 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
859 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO897 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
860 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO898 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
861 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO899 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -863,140 +901,181 @@ test "@mulWithOverflow bitsize > 32" {...@@ -863,140 +901,181 @@ test "@mulWithOverflow bitsize > 32" {
863 {901 {
864 var a: u62 = 3;902 var a: u62 = 3;
865 var b: u62 = 0x1555555555555555;903 var b: u62 = 0x1555555555555555;
866 var res: u62 = undefined;904 var ov = @mulWithOverflow(a, b);
867 try expect(!@mulWithOverflow(u62, a, b, &res));905 try expect(ov[0] == 0x3fffffffffffffff);
868 try expect(res == 0x3fffffffffffffff);906 try expect(ov[1] == 0);
869907
870 b = 0x1555555555555556;908 b = 0x1555555555555556;
871 try expect(@mulWithOverflow(u62, a, b, &res));909 ov = @mulWithOverflow(a, b);
872 try expect(res == 2);910 try expect(ov[0] == 2);
911 try expect(ov[1] == 1);
873 }912 }
874913
875 {914 {
876 var a: i62 = 3;915 var a: i62 = 3;
877 var b: i62 = -0xaaaaaaaaaaaaaaa;916 var b: i62 = -0xaaaaaaaaaaaaaaa;
878 var res: i62 = undefined;917 var ov = @mulWithOverflow(a, b);
879 try expect(!@mulWithOverflow(i62, a, b, &res));918 try expect(ov[0] == -0x1ffffffffffffffe);
880 try expect(res == -0x1ffffffffffffffe);919 try expect(ov[1] == 0);
881920
882 b = -0xaaaaaaaaaaaaaab;921 b = -0xaaaaaaaaaaaaaab;
883 try expect(@mulWithOverflow(i62, a, b, &res));922 ov = @mulWithOverflow(a, b);
884 try expect(res == 0x1fffffffffffffff);923 try expect(ov[0] == 0x1fffffffffffffff);
924 try expect(ov[1] == 1);
885 }925 }
886926
887 {927 {
888 var a: u64 = 3;928 var a: u64 = 3;
889 var b: u64 = 0x5555555555555555;929 var b: u64 = 0x5555555555555555;
890 var res: u64 = undefined;930 var ov = @mulWithOverflow(a, b);
891 try expect(!@mulWithOverflow(u64, a, b, &res));931 try expect(ov[0] == 0xffffffffffffffff);
892 try expect(res == 0xffffffffffffffff);932 try expect(ov[1] == 0);
893933
894 b = 0x5555555555555556;934 b = 0x5555555555555556;
895 try expect(@mulWithOverflow(u64, a, b, &res));935 ov = @mulWithOverflow(a, b);
896 try expect(res == 2);936 try expect(ov[0] == 2);
937 try expect(ov[1] == 1);
897 }938 }
898939
899 {940 {
900 var a: i64 = 3;941 var a: i64 = 3;
901 var b: i64 = -0x2aaaaaaaaaaaaaaa;942 var b: i64 = -0x2aaaaaaaaaaaaaaa;
902 var res: i64 = undefined;943 var ov = @mulWithOverflow(a, b);
903 try expect(!@mulWithOverflow(i64, a, b, &res));944 try expect(ov[0] == -0x7ffffffffffffffe);
904 try expect(res == -0x7ffffffffffffffe);945 try expect(ov[1] == 0);
905946
906 b = -0x2aaaaaaaaaaaaaab;947 b = -0x2aaaaaaaaaaaaaab;
907 try expect(@mulWithOverflow(i64, a, b, &res));948 ov = @mulWithOverflow(a, b);
908 try expect(res == 0x7fffffffffffffff);949 try expect(ov[0] == 0x7fffffffffffffff);
950 try expect(ov[1] == 1);
909 }951 }
910}952}
911953
912test "@subWithOverflow" {954test "@subWithOverflow" {
955 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
956 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
913 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO957 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
914958
915 {959 {
916 var result: u8 = undefined;960 var a: u8 = 1;
917 try expect(@subWithOverflow(u8, 1, 2, &result));961 const ov = @subWithOverflow(a, 2);
918 try expect(result == 255);962 try expect(ov[0] == 255);
919 try expect(!@subWithOverflow(u8, 1, 1, &result));963 try expect(ov[1] == 1);
920 try expect(result == 0);964 }
965 {
966 var a: u8 = 1;
967 const ov = @subWithOverflow(a, 1);
968 try expect(ov[0] == 0);
969 try expect(ov[1] == 0);
970 }
921971
972 {
922 var a: u8 = 1;973 var a: u8 = 1;
923 var b: u8 = 2;974 var b: u8 = 2;
924 try expect(@subWithOverflow(u8, a, b, &result));975 var ov = @subWithOverflow(a, b);
925 try expect(result == 255);976 try expect(ov[0] == 255);
977 try expect(ov[1] == 1);
926 b = 1;978 b = 1;
927 try expect(!@subWithOverflow(u8, a, b, &result));979 ov = @subWithOverflow(a, b);
928 try expect(result == 0);980 try expect(ov[0] == 0);
981 try expect(ov[1] == 0);
929 }982 }
930983
931 {984 {
932 var a: usize = 6;985 var a: usize = 6;
933 var b: usize = 6;986 var b: usize = 6;
934 var res: usize = undefined;987 const ov = @subWithOverflow(a, b);
935 try expect(!@subWithOverflow(usize, a, b, &res));988 try expect(ov[0] == 0);
936 try expect(res == 0);989 try expect(ov[1] == 0);
937 }990 }
938991
939 {992 {
940 var a: isize = -6;993 var a: isize = -6;
941 var b: isize = -6;994 var b: isize = -6;
942 var res: isize = undefined;995 const ov = @subWithOverflow(a, b);
943 try expect(!@subWithOverflow(isize, a, b, &res));996 try expect(ov[0] == 0);
944 try expect(res == 0);997 try expect(ov[1] == 0);
945 }998 }
946}999}
9471000
948test "@shlWithOverflow" {1001test "@shlWithOverflow" {
1002 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1003 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1004 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
949 {1005 {
950 var result: u4 = undefined;
951 var a: u4 = 2;1006 var a: u4 = 2;
952 var b: u2 = 1;1007 var b: u2 = 1;
953 try expect(!@shlWithOverflow(u4, a, b, &result));1008 var ov = @shlWithOverflow(a, b);
954 try expect(result == 4);1009 try expect(ov[0] == 4);
1010 try expect(ov[1] == 0);
9551011
956 b = 3;1012 b = 3;
957 try expect(@shlWithOverflow(u4, a, b, &result));1013 ov = @shlWithOverflow(a, b);
958 try expect(result == 0);1014 try expect(ov[0] == 0);
1015 try expect(ov[1] == 1);
959 }1016 }
9601017
961 {1018 {
962 var result: i9 = undefined;
963 var a: i9 = 127;1019 var a: i9 = 127;
964 var b: u4 = 1;1020 var b: u4 = 1;
965 try expect(!@shlWithOverflow(i9, a, b, &result));1021 var ov = @shlWithOverflow(a, b);
966 try expect(result == 254);1022 try expect(ov[0] == 254);
1023 try expect(ov[1] == 0);
9671024
968 b = 2;1025 b = 2;
969 try expect(@shlWithOverflow(i9, a, b, &result));1026 ov = @shlWithOverflow(a, b);
970 try expect(result == -4);1027 try expect(ov[0] == -4);
1028 try expect(ov[1] == 1);
971 }1029 }
9721030
973 {1031 {
974 var result: u16 = undefined;1032 const ov = @shlWithOverflow(@as(u16, 0b0010111111111111), 3);
975 try expect(@shlWithOverflow(u16, 0b0010111111111111, 3, &result));1033 try expect(ov[0] == 0b0111111111111000);
976 try expect(result == 0b0111111111111000);1034 try expect(ov[1] == 1);
977 try expect(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result));1035 }
978 try expect(result == 0b1011111111111100);1036 {
9791037 const ov = @shlWithOverflow(@as(u16, 0b0010111111111111), 2);
1038 try expect(ov[0] == 0b1011111111111100);
1039 try expect(ov[1] == 0);
1040 }
1041 {
980 var a: u16 = 0b0000_0000_0000_0011;1042 var a: u16 = 0b0000_0000_0000_0011;
981 var b: u4 = 15;1043 var b: u4 = 15;
982 try expect(@shlWithOverflow(u16, a, b, &result));1044 var ov = @shlWithOverflow(a, b);
983 try expect(result == 0b1000_0000_0000_0000);1045 try expect(ov[0] == 0b1000_0000_0000_0000);
1046 try expect(ov[1] == 1);
984 b = 14;1047 b = 14;
985 try expect(!@shlWithOverflow(u16, a, b, &result));1048 ov = @shlWithOverflow(a, b);
986 try expect(result == 0b1100_0000_0000_0000);1049 try expect(ov[0] == 0b1100_0000_0000_0000);
1050 try expect(ov[1] == 0);
987 }1051 }
988}1052}
9891053
990test "overflow arithmetic with u0 values" {1054test "overflow arithmetic with u0 values" {
991 var result: u0 = undefined;1055 {
992 try expect(!@addWithOverflow(u0, 0, 0, &result));1056 var a: u0 = 0;
993 try expect(result == 0);1057 const ov = @addWithOverflow(a, 0);
994 try expect(!@subWithOverflow(u0, 0, 0, &result));1058 try expect(ov[1] == 0);
995 try expect(result == 0);1059 try expect(ov[1] == 0);
996 try expect(!@mulWithOverflow(u0, 0, 0, &result));1060 }
997 try expect(result == 0);1061 {
998 try expect(!@shlWithOverflow(u0, 0, 0, &result));1062 var a: u0 = 0;
999 try expect(result == 0);1063 const ov = @subWithOverflow(a, 0);
1064 try expect(ov[1] == 0);
1065 try expect(ov[1] == 0);
1066 }
1067 {
1068 var a: u0 = 0;
1069 const ov = @mulWithOverflow(a, 0);
1070 try expect(ov[1] == 0);
1071 try expect(ov[1] == 0);
1072 }
1073 {
1074 var a: u0 = 0;
1075 const ov = @shlWithOverflow(a, 0);
1076 try expect(ov[1] == 0);
1077 try expect(ov[1] == 0);
1078 }
1000}1079}
10011080
1002test "allow signed integer division/remainder when values are comptime-known and positive or exact" {1081test "allow signed integer division/remainder when values are comptime-known and positive or exact" {
test/behavior/vector.zig+29-26
...@@ -963,35 +963,31 @@ test "@addWithOverflow" {...@@ -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 };
...@@ -1136,8 +1128,19 @@ test "byte vector initialized in inline function" {...@@ -1136,8 +1128,19 @@ test "byte vector initialized in inline function" {
1136}1128}
11371129
1138test "byte vector initialized in inline function" {1130test "byte vector initialized in inline function" {
1139 // TODO https://github.com/ziglang/zig/issues/132791131 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1140 if (true) return error.SkipZigTest;1132 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1133 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1134 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1135 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1136 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1137
1138 if (comptime builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and
1139 builtin.cpu.features.isEnabled(@enumToInt(std.Target.x86.Feature.avx512f)))
1140 {
1141 // TODO https://github.com/ziglang/zig/issues/13279
1142 return error.SkipZigTest;
1143 }
11411144
1142 const S = struct {1145 const S = struct {
1143 fn boolx4(e0: bool, e1: bool, e2: bool, e3: bool) @Vector(4, bool) {1146 fn boolx4(e0: bool, e1: bool, e2: bool, e3: bool) @Vector(4, bool) {