diff --git a/doc/langref.html.in b/doc/langref.html.in index 0b914201091b..71331de89f05 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5413,14 +5413,14 @@ pub fn parseU64(buf: []const u8, radix: u8) !u64 { } // x *= radix - if (@mulWithOverflow(u64, x, radix, &x)) { - return error.Overflow; - } + var ov = @mulWithOverflow(x, radix); + if (ov[1] != 0) return error.OverFlow; + // x += digit - if (@addWithOverflow(u64, x, digit, &x)) { - return error.Overflow; - } + ov = @addWithOverflow(ov[0], digit); + if (ov[1] != 0) return error.OverFlow; + x = ov[0]; } return x; @@ -5832,14 +5832,16 @@ test "merge error sets" { {#code_begin|test|inferred_error_sets#} // With an inferred error set pub fn add_inferred(comptime T: type, a: T, b: T) !T { - var answer: T = undefined; - return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer; + const ov = @addWithOverflow(a, b); + if (ov[1] != 0) return error.Overflow; + return ov[0]; } // With an explicit error set pub fn add_explicit(comptime T: type, a: T, b: T) Error!T { - var answer: T = undefined; - return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer; + const ov = @addWithOverflow(a, b); + if (ov[1] != 0) return error.Overflow; + return ov[0]; } const Error = error { @@ -7632,11 +7634,9 @@ test "global assembly" {
{#header_close#} {#header_open|@addWithOverflow#} -{#syntax#}@addWithOverflow(comptime T: type, a: T, b: T, result: *T) bool{#endsyntax#}+
{#syntax#}@addWithOverflow(a: anytype, b: anytype) struct { @TypeOf(a, b), u1 }{#endsyntax#}
- Performs {#syntax#}result.* = a + b{#endsyntax#}. If overflow or underflow occurs, - stores the overflowed bits in {#syntax#}result{#endsyntax#} and returns {#syntax#}true{#endsyntax#}. - If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}. + Performs {#syntax#}a + b{#endsyntax#} and returns a tuple with the result and a possible overflow bit.
{#header_close#} {#header_open|@alignCast#} @@ -8695,11 +8695,9 @@ test "@wasmMemoryGrow" { {#header_close#} {#header_open|@mulWithOverflow#} -{#syntax#}@mulWithOverflow(comptime T: type, a: T, b: T, result: *T) bool{#endsyntax#}+
{#syntax#}@mulWithOverflow(a: anytype, b: anytype) struct { @TypeOf(a, b), u1 }{#endsyntax#}
- Performs {#syntax#}result.* = a * b{#endsyntax#}. If overflow or underflow occurs, - stores the overflowed bits in {#syntax#}result{#endsyntax#} and returns {#syntax#}true{#endsyntax#}. - If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}. + Performs {#syntax#}a * b{#endsyntax#} and returns a tuple with the result and a possible overflow bit.
{#header_close#} @@ -8973,15 +8971,13 @@ test "@setRuntimeSafety" { {#header_close#} {#header_open|@shlWithOverflow#} -{#syntax#}@shlWithOverflow(comptime T: type, a: T, shift_amt: Log2T, result: *T) bool{#endsyntax#}+
{#syntax#}@shlWithOverflow(a: anytype, shift_amt: Log2T) struct { @TypeOf(a), u1 }{#endsyntax#}
- Performs {#syntax#}result.* = a << b{#endsyntax#}. If overflow or underflow occurs, - stores the overflowed bits in {#syntax#}result{#endsyntax#} and returns {#syntax#}true{#endsyntax#}. - If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}. + Performs {#syntax#}a << b{#endsyntax#} and returns a tuple with the result and a possible overflow bit.
- The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(@typeInfo(T).Int.bits){#endsyntax#} bits. - This is because {#syntax#}shift_amt >= @typeInfo(T).Int.bits{#endsyntax#} is undefined behavior. + The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(@typeInfo(@TypeOf(a)).Int.bits){#endsyntax#} bits. + This is because {#syntax#}shift_amt >= @typeInfo(@TypeOf(a)).Int.bits{#endsyntax#} is undefined behavior.
{#see_also|@shlExact|@shrExact#} {#header_close#} @@ -9323,11 +9319,9 @@ fn doTheTest() !void { {#header_close#} {#header_open|@subWithOverflow#} -{#syntax#}@subWithOverflow(comptime T: type, a: T, b: T, result: *T) bool{#endsyntax#}+
{#syntax#}@subWithOverflow(a: anytype, b: anytype) struct { @TypeOf(a, b), u1 }{#endsyntax#}
- Performs {#syntax#}result.* = a - b{#endsyntax#}. If overflow or underflow occurs, - stores the overflowed bits in {#syntax#}result{#endsyntax#} and returns {#syntax#}true{#endsyntax#}. - If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}. + Performs {#syntax#}a - b{#endsyntax#} and returns a tuple with the result and a possible overflow bit.
{#header_close#} @@ -9774,11 +9768,11 @@ const print = @import("std").debug.print; pub fn main() void { var byte: u8 = 255; - var result: u8 = undefined; - if (@addWithOverflow(u8, byte, 10, &result)) { - print("overflowed result: {}\n", .{result}); + const ov = @addWithOverflow(byte, 10); + if (ov[1] != 0) { + print("overflowed result: {}\n", .{ov[0]}); } else { - print("result: {}\n", .{result}); + print("result: {}\n", .{ov[0]}); } } {#code_end#} diff --git a/lib/compiler_rt/trunctfxf2.zig b/lib/compiler_rt/trunctfxf2.zig index 731f58f19205..fece695b65c0 100644 --- a/lib/compiler_rt/trunctfxf2.zig +++ b/lib/compiler_rt/trunctfxf2.zig @@ -49,14 +49,16 @@ pub fn __trunctfxf2(a: f128) callconv(.C) f80 { const round_bits = a_abs & round_mask; if (round_bits > halfway) { // Round to nearest - const carry = @boolToInt(@addWithOverflow(u64, res.fraction, 1, &res.fraction)); - res.exp += carry; - res.fraction |= @as(u64, carry) << 63; // Restore integer bit after carry + const ov = @addWithOverflow(res.fraction, 1); + res.fraction = ov[0]; + res.exp += ov[1]; + res.fraction |= @as(u64, ov[1]) << 63; // Restore integer bit after carry } else if (round_bits == halfway) { // Ties to even - const carry = @boolToInt(@addWithOverflow(u64, res.fraction, res.fraction & 1, &res.fraction)); - res.exp += carry; - res.fraction |= @as(u64, carry) << 63; // Restore integer bit after carry + const ov = @addWithOverflow(res.fraction, res.fraction & 1); + res.fraction = ov[0]; + res.exp += ov[1]; + res.fraction |= @as(u64, ov[1]) << 63; // Restore integer bit after carry } if (res.exp == 0) res.fraction &= ~@as(u64, integer_bit); // Remove integer bit for de-normals } diff --git a/lib/std/compress/deflate/compressor_test.zig b/lib/std/compress/deflate/compressor_test.zig index a02df5526c67..c51f68236da3 100644 --- a/lib/std/compress/deflate/compressor_test.zig +++ b/lib/std/compress/deflate/compressor_test.zig @@ -172,9 +172,7 @@ test "deflate/inflate" { defer testing.allocator.free(large_data_chunk); // fill with random data for (large_data_chunk) |_, i| { - var mul: u8 = @truncate(u8, i); - _ = @mulWithOverflow(u8, mul, mul, &mul); - large_data_chunk[i] = mul; + large_data_chunk[i] = @truncate(u8, i) *% @truncate(u8, i); } try testToFromWithLimit(large_data_chunk, limits); } diff --git a/lib/std/crypto/pcurves/p256/p256_64.zig b/lib/std/crypto/pcurves/p256/p256_64.zig index 4ea8f268f3dc..e8ba37e845e0 100644 --- a/lib/std/crypto/pcurves/p256/p256_64.zig +++ b/lib/std/crypto/pcurves/p256/p256_64.zig @@ -75,10 +75,10 @@ pub const NonMontgomeryDomainFieldElement = [4]u64; inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void { @setRuntimeSafety(mode == .Debug); - var t: u64 = undefined; - const carry1 = @addWithOverflow(u64, arg2, arg3, &t); - const carry2 = @addWithOverflow(u64, t, arg1, out1); - out2.* = @boolToInt(carry1) | @boolToInt(carry2); + const ov1 = @addWithOverflow(arg2, arg3); + const ov2 = @addWithOverflow(ov1[0], arg1); + out1.* = ov2[0]; + out2.* = ov1[1] | ov2[1]; } /// 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 inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void { @setRuntimeSafety(mode == .Debug); - var t: u64 = undefined; - const carry1 = @subWithOverflow(u64, arg2, arg3, &t); - const carry2 = @subWithOverflow(u64, t, arg1, out1); - out2.* = @boolToInt(carry1) | @boolToInt(carry2); + const ov1 = @subWithOverflow(arg2, arg3); + const ov2 = @subWithOverflow(ov1[0], arg1); + out1.* = ov2[0]; + out2.* = ov1[1] | ov2[1]; } /// The function mulxU64 is a multiplication, returning the full double-width result. diff --git a/lib/std/crypto/pcurves/p256/p256_scalar_64.zig b/lib/std/crypto/pcurves/p256/p256_scalar_64.zig index 9c99d18ccfb0..ea102360cf8c 100644 --- a/lib/std/crypto/pcurves/p256/p256_scalar_64.zig +++ b/lib/std/crypto/pcurves/p256/p256_scalar_64.zig @@ -75,10 +75,10 @@ pub const NonMontgomeryDomainFieldElement = [4]u64; inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void { @setRuntimeSafety(mode == .Debug); - var t: u64 = undefined; - const carry1 = @addWithOverflow(u64, arg2, arg3, &t); - const carry2 = @addWithOverflow(u64, t, arg1, out1); - out2.* = @boolToInt(carry1) | @boolToInt(carry2); + const ov1 = @addWithOverflow(arg2, arg3); + const ov2 = @addWithOverflow(ov1[0], arg1); + out1.* = ov2[0]; + out2.* = ov1[1] | ov2[1]; } /// 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 inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void { @setRuntimeSafety(mode == .Debug); - var t: u64 = undefined; - const carry1 = @subWithOverflow(u64, arg2, arg3, &t); - const carry2 = @subWithOverflow(u64, t, arg1, out1); - out2.* = @boolToInt(carry1) | @boolToInt(carry2); + const ov1 = @subWithOverflow(arg2, arg3); + const ov2 = @subWithOverflow(ov1[0], arg1); + out1.* = ov2[0]; + out2.* = ov1[1] | ov2[1]; } /// The function mulxU64 is a multiplication, returning the full double-width result. diff --git a/lib/std/crypto/pcurves/p384/p384_64.zig b/lib/std/crypto/pcurves/p384/p384_64.zig index bd39fc527adf..45c12835b345 100644 --- a/lib/std/crypto/pcurves/p384/p384_64.zig +++ b/lib/std/crypto/pcurves/p384/p384_64.zig @@ -44,10 +44,10 @@ pub const NonMontgomeryDomainFieldElement = [6]u64; inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void { @setRuntimeSafety(mode == .Debug); - var t: u64 = undefined; - const carry1 = @addWithOverflow(u64, arg2, arg3, &t); - const carry2 = @addWithOverflow(u64, t, arg1, out1); - out2.* = @boolToInt(carry1) | @boolToInt(carry2); + const ov1 = @addWithOverflow(arg2, arg3); + const ov2 = @addWithOverflow(ov1[0], arg1); + out1.* = ov2[0]; + out2.* = ov1[1] | ov2[1]; } /// 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 inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void { @setRuntimeSafety(mode == .Debug); - var t: u64 = undefined; - const carry1 = @subWithOverflow(u64, arg2, arg3, &t); - const carry2 = @subWithOverflow(u64, t, arg1, out1); - out2.* = @boolToInt(carry1) | @boolToInt(carry2); + const ov1 = @subWithOverflow(arg2, arg3); + const ov2 = @subWithOverflow(ov1[0], arg1); + out1.* = ov2[0]; + out2.* = ov1[1] | ov2[1]; } /// The function mulxU64 is a multiplication, returning the full double-width result. diff --git a/lib/std/crypto/pcurves/p384/p384_scalar_64.zig b/lib/std/crypto/pcurves/p384/p384_scalar_64.zig index e45e43f98cf3..0ce7727148fc 100644 --- a/lib/std/crypto/pcurves/p384/p384_scalar_64.zig +++ b/lib/std/crypto/pcurves/p384/p384_scalar_64.zig @@ -44,10 +44,10 @@ pub const NonMontgomeryDomainFieldElement = [6]u64; inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void { @setRuntimeSafety(mode == .Debug); - var t: u64 = undefined; - const carry1 = @addWithOverflow(u64, arg2, arg3, &t); - const carry2 = @addWithOverflow(u64, t, arg1, out1); - out2.* = @boolToInt(carry1) | @boolToInt(carry2); + const ov1 = @addWithOverflow(arg2, arg3); + const ov2 = @addWithOverflow(ov1[0], arg1); + out1.* = ov2[0]; + out2.* = ov1[1] | ov2[1]; } /// 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 inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void { @setRuntimeSafety(mode == .Debug); - var t: u64 = undefined; - const carry1 = @subWithOverflow(u64, arg2, arg3, &t); - const carry2 = @subWithOverflow(u64, t, arg1, out1); - out2.* = @boolToInt(carry1) | @boolToInt(carry2); + const ov1 = @subWithOverflow(arg2, arg3); + const ov2 = @subWithOverflow(ov1[0], arg1); + out1.* = ov2[0]; + out2.* = ov1[1] | ov2[1]; } /// The function mulxU64 is a multiplication, returning the full double-width result. diff --git a/lib/std/crypto/pcurves/secp256k1/secp256k1_64.zig b/lib/std/crypto/pcurves/secp256k1/secp256k1_64.zig index 2309b48ac97f..5643ea88d509 100644 --- a/lib/std/crypto/pcurves/secp256k1/secp256k1_64.zig +++ b/lib/std/crypto/pcurves/secp256k1/secp256k1_64.zig @@ -44,10 +44,10 @@ pub const NonMontgomeryDomainFieldElement = [4]u64; inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void { @setRuntimeSafety(mode == .Debug); - var t: u64 = undefined; - const carry1 = @addWithOverflow(u64, arg2, arg3, &t); - const carry2 = @addWithOverflow(u64, t, arg1, out1); - out2.* = @boolToInt(carry1) | @boolToInt(carry2); + const ov1 = @addWithOverflow(arg2, arg3); + const ov2 = @addWithOverflow(ov1[0], arg1); + out1.* = ov2[0]; + out2.* = ov1[1] | ov2[1]; } /// 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 inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void { @setRuntimeSafety(mode == .Debug); - var t: u64 = undefined; - const carry1 = @subWithOverflow(u64, arg2, arg3, &t); - const carry2 = @subWithOverflow(u64, t, arg1, out1); - out2.* = @boolToInt(carry1) | @boolToInt(carry2); + const ov1 = @subWithOverflow(arg2, arg3); + const ov2 = @subWithOverflow(ov1[0], arg1); + out1.* = ov2[0]; + out2.* = ov1[1] | ov2[1]; } /// The function mulxU64 is a multiplication, returning the full double-width result. diff --git a/lib/std/crypto/pcurves/secp256k1/secp256k1_scalar_64.zig b/lib/std/crypto/pcurves/secp256k1/secp256k1_scalar_64.zig index 8e9687f0a1a3..aca1bd3063bb 100644 --- a/lib/std/crypto/pcurves/secp256k1/secp256k1_scalar_64.zig +++ b/lib/std/crypto/pcurves/secp256k1/secp256k1_scalar_64.zig @@ -44,10 +44,10 @@ pub const NonMontgomeryDomainFieldElement = [4]u64; inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void { @setRuntimeSafety(mode == .Debug); - var t: u64 = undefined; - const carry1 = @addWithOverflow(u64, arg2, arg3, &t); - const carry2 = @addWithOverflow(u64, t, arg1, out1); - out2.* = @boolToInt(carry1) | @boolToInt(carry2); + const ov1 = @addWithOverflow(arg2, arg3); + const ov2 = @addWithOverflow(ov1[0], arg1); + out1.* = ov2[0]; + out2.* = ov1[1] | ov2[1]; } /// 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 inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void { @setRuntimeSafety(mode == .Debug); - var t: u64 = undefined; - const carry1 = @subWithOverflow(u64, arg2, arg3, &t); - const carry2 = @subWithOverflow(u64, t, arg1, out1); - out2.* = @boolToInt(carry1) | @boolToInt(carry2); + const ov1 = @subWithOverflow(arg2, arg3); + const ov2 = @subWithOverflow(ov1[0], arg1); + out1.* = ov2[0]; + out2.* = ov1[1] | ov2[1]; } /// The function mulxU64 is a multiplication, returning the full double-width result. diff --git a/lib/std/crypto/salsa20.zig b/lib/std/crypto/salsa20.zig index c4cd86b0e43b..2027403ee228 100644 --- a/lib/std/crypto/salsa20.zig +++ b/lib/std/crypto/salsa20.zig @@ -263,7 +263,9 @@ fn SalsaNonVecImpl(comptime rounds: comptime_int) type { while (j < 64) : (j += 1) { xout[j] ^= buf[j]; } - ctx[9] += @boolToInt(@addWithOverflow(u32, ctx[8], 1, &ctx[8])); + const ov = @addWithOverflow(ctx[8], 1); + ctx[8] = ov[0]; + ctx[9] += ov[1]; } if (i < in.len) { salsaCore(x[0..], ctx, true); diff --git a/lib/std/crypto/utils.zig b/lib/std/crypto/utils.zig index 0a3540d8950a..fd7264e73786 100644 --- a/lib/std/crypto/utils.zig +++ b/lib/std/crypto/utils.zig @@ -87,15 +87,19 @@ pub fn timingSafeAdd(comptime T: type, a: []const T, b: []const T, result: []T, if (endian == .Little) { var i: usize = 0; while (i < len) : (i += 1) { - const tmp = @boolToInt(@addWithOverflow(u8, a[i], b[i], &result[i])); - carry = tmp | @boolToInt(@addWithOverflow(u8, result[i], carry, &result[i])); + const ov1 = @addWithOverflow(a[i], b[i]); + const ov2 = @addWithOverflow(ov1[0], carry); + result[i] = ov2[0]; + carry = ov1[1] | ov2[1]; } } else { var i: usize = len; while (i != 0) { i -= 1; - const tmp = @boolToInt(@addWithOverflow(u8, a[i], b[i], &result[i])); - carry = tmp | @boolToInt(@addWithOverflow(u8, result[i], carry, &result[i])); + const ov1 = @addWithOverflow(a[i], b[i]); + const ov2 = @addWithOverflow(ov1[0], carry); + result[i] = ov2[0]; + carry = ov1[1] | ov2[1]; } } return @bitCast(bool, carry); @@ -110,15 +114,19 @@ pub fn timingSafeSub(comptime T: type, a: []const T, b: []const T, result: []T, if (endian == .Little) { var i: usize = 0; while (i < len) : (i += 1) { - const tmp = @boolToInt(@subWithOverflow(u8, a[i], b[i], &result[i])); - borrow = tmp | @boolToInt(@subWithOverflow(u8, result[i], borrow, &result[i])); + const ov1 = @subWithOverflow(a[i], b[i]); + const ov2 = @subWithOverflow(ov1[0], borrow); + result[i] = ov2[0]; + borrow = ov1[1] | ov2[1]; } } else { var i: usize = len; while (i != 0) { i -= 1; - const tmp = @boolToInt(@subWithOverflow(u8, a[i], b[i], &result[i])); - borrow = tmp | @boolToInt(@subWithOverflow(u8, result[i], borrow, &result[i])); + const ov1 = @subWithOverflow(a[i], b[i]); + const ov2 = @subWithOverflow(ov1[0], borrow); + result[i] = ov2[0]; + borrow = ov1[1] | ov2[1]; } } return @bitCast(bool, borrow); diff --git a/lib/std/heap.zig b/lib/std/heap.zig index ee6525659eae..081e65fa2788 100644 --- a/lib/std/heap.zig +++ b/lib/std/heap.zig @@ -789,7 +789,7 @@ pub fn testAllocatorLargeAlignment(base_allocator: mem.Allocator) !void { const large_align: usize = mem.page_size / 2; var align_mask: usize = undefined; - _ = @shlWithOverflow(usize, ~@as(usize, 0), @as(Allocator.Log2Align, @ctz(large_align)), &align_mask); + align_mask = @shlWithOverflow(~@as(usize, 0), @as(Allocator.Log2Align, @ctz(large_align)))[0]; var slice = try allocator.alignedAlloc(u8, large_align, 500); try testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr)); diff --git a/lib/std/leb128.zig b/lib/std/leb128.zig index f72070d13d84..bc5955d16a6c 100644 --- a/lib/std/leb128.zig +++ b/lib/std/leb128.zig @@ -15,11 +15,11 @@ pub fn readULEB128(comptime T: type, reader: anytype) !T { while (group < max_group) : (group += 1) { const byte = try reader.readByte(); - var temp = @as(U, byte & 0x7f); - if (@shlWithOverflow(U, temp, group * 7, &temp)) return error.Overflow; + const ov = @shlWithOverflow(@as(U, byte & 0x7f), group * 7); + if (ov[1] != 0) return error.Overflow; - value |= temp; + value |= ov[0]; if (byte & 0x80 == 0) break; } else { return error.Overflow; @@ -65,13 +65,13 @@ pub fn readILEB128(comptime T: type, reader: anytype) !T { while (group < max_group) : (group += 1) { const byte = try reader.readByte(); - var temp = @as(U, byte & 0x7f); const shift = group * 7; - if (@shlWithOverflow(U, temp, shift, &temp)) { + const ov = @shlWithOverflow(@as(U, byte & 0x7f), shift); + if (ov[1] != 0) { // Overflow is ok so long as the sign bit is set and this is the last byte if (byte & 0x80 != 0) return error.Overflow; - if (@bitCast(S, temp) >= 0) return error.Overflow; + if (@bitCast(S, ov[0]) >= 0) return error.Overflow; // and all the overflowed bits are 1 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 { } else { // If we don't overflow and this is the last byte and the number being decoded // is negative, check that the remaining bits are 1 - if ((byte & 0x80 == 0) and (@bitCast(S, temp) < 0)) { + if ((byte & 0x80 == 0) and (@bitCast(S, ov[0]) < 0)) { const remaining_shift = @intCast(u3, @typeInfo(U).Int.bits - @as(u16, shift)); const remaining_bits = @bitCast(i8, byte | 0x80) >> remaining_shift; if (remaining_bits != -1) return error.Overflow; } } - value |= temp; + value |= ov[0]; if (byte & 0x80 == 0) { const needs_sign_ext = group + 1 < max_group; if (byte & 0x40 != 0 and needs_sign_ext) { diff --git a/lib/std/math.zig b/lib/std/math.zig index c2e793ca8f3c..d27e4761942c 100644 --- a/lib/std/math.zig +++ b/lib/std/math.zig @@ -468,21 +468,26 @@ test "clamp" { /// Returns the product of a and b. Returns an error on overflow. pub fn mul(comptime T: type, a: T, b: T) (error{Overflow}!T) { - var answer: T = undefined; - return if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer; + if (T == comptime_int) return a * b; + const ov = @mulWithOverflow(a, b); + if (ov[1] != 0) return error.Overflow; + return ov[0]; } /// Returns the sum of a and b. Returns an error on overflow. pub fn add(comptime T: type, a: T, b: T) (error{Overflow}!T) { if (T == comptime_int) return a + b; - var answer: T = undefined; - return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer; + const ov = @addWithOverflow(a, b); + if (ov[1] != 0) return error.Overflow; + return ov[0]; } /// Returns a - b, or an error on overflow. pub fn sub(comptime T: type, a: T, b: T) (error{Overflow}!T) { - var answer: T = undefined; - return if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer; + if (T == comptime_int) return a - b; + const ov = @subWithOverflow(a, b); + if (ov[1] != 0) return error.Overflow; + return ov[0]; } pub fn negate(x: anytype) !@TypeOf(x) { @@ -492,8 +497,10 @@ pub fn negate(x: anytype) !@TypeOf(x) { /// Shifts a left by shift_amt. Returns an error on overflow. shift_amt /// is unsigned. pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T { - var answer: T = undefined; - return if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer; + if (T == comptime_int) return a << shift_amt; + const ov = @shlWithOverflow(a, shift_amt); + if (ov[1] != 0) return error.Overflow; + return ov[0]; } /// Shifts left. Overflowed bits are truncated. diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig index c30187445186..8410e25864ee 100644 --- a/lib/std/math/big/int.zig +++ b/lib/std/math/big/int.zig @@ -74,42 +74,40 @@ pub fn calcTwosCompLimbCount(bit_count: usize) usize { /// a + b * c + *carry, sets carry to the overflow bits pub fn addMulLimbWithCarry(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb { @setRuntimeSafety(debug_safety); - var r1: Limb = undefined; - // r1 = a + *carry - const c1: Limb = @boolToInt(@addWithOverflow(Limb, a, carry.*, &r1)); + // ov1[0] = a + *carry + const ov1 = @addWithOverflow(a, carry.*); // r2 = b * c const bc = @as(DoubleLimb, math.mulWide(Limb, b, c)); const r2 = @truncate(Limb, bc); const c2 = @truncate(Limb, bc >> limb_bits); - // r1 = r1 + r2 - const c3: Limb = @boolToInt(@addWithOverflow(Limb, r1, r2, &r1)); + // ov2[0] = ov1[0] + r2 + const ov2 = @addWithOverflow(ov1[0], r2); // This never overflows, c1, c3 are either 0 or 1 and if both are 1 then // c2 is at least <= maxInt(Limb) - 2. - carry.* = c1 + c2 + c3; + carry.* = ov1[1] + c2 + ov2[1]; - return r1; + return ov2[0]; } /// a - b * c - *carry, sets carry to the overflow bits fn subMulLimbWithBorrow(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb { - // r1 = a - *carry - var r1: Limb = undefined; - const c1: Limb = @boolToInt(@subWithOverflow(Limb, a, carry.*, &r1)); + // ov1[0] = a - *carry + const ov1 = @subWithOverflow(a, carry.*); // r2 = b * c const bc = @as(DoubleLimb, std.math.mulWide(Limb, b, c)); const r2 = @truncate(Limb, bc); const c2 = @truncate(Limb, bc >> limb_bits); - // r1 = r1 - r2 - const c3: Limb = @boolToInt(@subWithOverflow(Limb, r1, r2, &r1)); - carry.* = c1 + c2 + c3; + // ov2[0] = ov1[0] - r2 + const ov2 = @subWithOverflow(ov1[0], r2); + carry.* = ov1[1] + c2 + ov2[1]; - return r1; + return ov2[0]; } /// Used to indicate either limit of a 2s-complement integer. @@ -673,7 +671,9 @@ pub const Mutable = struct { assert(rma.limbs.ptr != b.limbs.ptr); // illegal aliasing if (a.limbs.len == 1 and b.limbs.len == 1) { - if (!@mulWithOverflow(Limb, a.limbs[0], b.limbs[0], &rma.limbs[0])) { + const ov = @mulWithOverflow(a.limbs[0], b.limbs[0]); + rma.limbs[0] = ov[0]; + if (ov[1] == 0) { rma.len = 1; rma.positive = (a.positive == b.positive); return; @@ -1836,7 +1836,11 @@ pub const Mutable = struct { bit_index += @bitSizeOf(Limb); // 2's complement (bitwise not, then add carry bit) - if (!positive) carry = @boolToInt(@addWithOverflow(Limb, ~limb, carry, &limb)); + if (!positive) { + const ov = @addWithOverflow(~limb, carry); + limb = ov[0]; + carry = ov[1]; + } x.limbs[limb_index] = limb; } @@ -1853,7 +1857,11 @@ pub const Mutable = struct { }; // 2's complement (bitwise not, then add carry bit) - if (!positive) assert(!@addWithOverflow(Limb, ~limb, carry, &limb)); + if (!positive) { + const ov = @addWithOverflow(~limb, carry); + assert(ov[1] == 0); + limb = ov[0]; + } x.limbs[limb_index] = limb; limb_index += 1; @@ -2000,7 +2008,9 @@ pub const Const = struct { // All but the most significant limb. for (self.limbs[0 .. self.limbs.len - 1]) |limb| { - carry = @boolToInt(@addWithOverflow(Limb, ~limb, carry, &add_res)); + const ov = @addWithOverflow(~limb, carry); + add_res = ov[0]; + carry = ov[1]; sum += @popCount(add_res); remaining_bits -= limb_bits; // Asserted not to undeflow by fitsInTwosComp } @@ -2294,7 +2304,11 @@ pub const Const = struct { var limb: Limb = if (limb_index < x.limbs.len) x.limbs[limb_index] else 0; // 2's complement (bitwise not, then add carry bit) - if (!x.positive) carry = @boolToInt(@addWithOverflow(Limb, ~limb, carry, &limb)); + if (!x.positive) { + const ov = @addWithOverflow(~limb, carry); + limb = ov[0]; + carry = ov[1]; + } // Write one Limb of bits mem.writePackedInt(Limb, bytes, bit_index + bit_offset, limb, endian); @@ -2306,7 +2320,7 @@ pub const Const = struct { var limb: Limb = if (limb_index < x.limbs.len) x.limbs[limb_index] else 0; // 2's complement (bitwise not, then add carry bit) - if (!x.positive) _ = @addWithOverflow(Limb, ~limb, carry, &limb); + if (!x.positive) limb = ~limb +% carry; // Write all remaining bits 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 { var carry: Limb = 0; while (i < a.len) : (i += 1) { - var c: Limb = 0; - c += @boolToInt(@addWithOverflow(Limb, r[i], a[i], &r[i])); - c += @boolToInt(@addWithOverflow(Limb, r[i], carry, &r[i])); - carry = c; + const ov1 = @addWithOverflow(r[i], a[i]); + r[i] = ov1[0]; + const ov2 = @addWithOverflow(r[i], carry); + r[i] = ov2[0]; + carry = @as(Limb, ov1[1]) + ov2[1]; } while ((carry != 0) and i < r.len) : (i += 1) { - carry = @boolToInt(@addWithOverflow(Limb, r[i], carry, &r[i])); + const ov = @addWithOverflow(r[i], carry); + r[i] = ov[0]; + carry = ov[1]; } } @@ -3435,7 +3452,9 @@ fn llmulLimb(comptime op: AccOp, acc: []Limb, y: []const Limb, xi: Limb) bool { j = 0; while ((carry != 0) and (j < a_hi.len)) : (j += 1) { - carry = @boolToInt(@addWithOverflow(Limb, a_hi[j], carry, &a_hi[j])); + const ov = @addWithOverflow(a_hi[j], carry); + a_hi[j] = ov[0]; + carry = ov[1]; } return carry != 0; @@ -3449,7 +3468,9 @@ fn llmulLimb(comptime op: AccOp, acc: []Limb, y: []const Limb, xi: Limb) bool { j = 0; while ((borrow != 0) and (j < a_hi.len)) : (j += 1) { - borrow = @boolToInt(@subWithOverflow(Limb, a_hi[j], borrow, &a_hi[j])); + const ov = @subWithOverflow(a_hi[j], borrow); + a_hi[j] = ov[0]; + borrow = ov[1]; } return borrow != 0; @@ -3482,14 +3503,17 @@ fn llsubcarry(r: []Limb, a: []const Limb, b: []const Limb) Limb { var borrow: Limb = 0; while (i < b.len) : (i += 1) { - var c: Limb = 0; - c += @boolToInt(@subWithOverflow(Limb, a[i], b[i], &r[i])); - c += @boolToInt(@subWithOverflow(Limb, r[i], borrow, &r[i])); - borrow = c; + const ov1 = @subWithOverflow(a[i], b[i]); + r[i] = ov1[0]; + const ov2 = @subWithOverflow(r[i], borrow); + r[i] = ov2[0]; + borrow = @as(Limb, ov1[1]) + ov2[1]; } while (i < a.len) : (i += 1) { - borrow = @boolToInt(@subWithOverflow(Limb, a[i], borrow, &r[i])); + const ov = @subWithOverflow(a[i], borrow); + r[i] = ov[0]; + borrow = ov[1]; } return borrow; @@ -3512,14 +3536,17 @@ fn lladdcarry(r: []Limb, a: []const Limb, b: []const Limb) Limb { var carry: Limb = 0; while (i < b.len) : (i += 1) { - var c: Limb = 0; - c += @boolToInt(@addWithOverflow(Limb, a[i], b[i], &r[i])); - c += @boolToInt(@addWithOverflow(Limb, r[i], carry, &r[i])); - carry = c; + const ov1 = @addWithOverflow(a[i], b[i]); + r[i] = ov1[0]; + const ov2 = @addWithOverflow(r[i], carry); + r[i] = ov2[0]; + carry = @as(Limb, ov1[1]) + ov2[1]; } while (i < a.len) : (i += 1) { - carry = @boolToInt(@addWithOverflow(Limb, a[i], carry, &r[i])); + const ov = @addWithOverflow(a[i], carry); + r[i] = ov[0]; + carry = ov[1]; } return carry; @@ -3685,11 +3712,11 @@ fn llsignedor(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_p var r_carry: u1 = 1; while (i < b.len) : (i += 1) { - var a_limb: Limb = undefined; - a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &a_limb)); - - r[i] = a_limb & ~b[i]; - r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i])); + const ov1 = @subWithOverflow(a[i], a_borrow); + a_borrow = ov1[1]; + const ov2 = @addWithOverflow(ov1[0] & ~b[i], r_carry); + r[i] = ov2[0]; + r_carry = ov2[1]; } // 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 // Note, if a_borrow is zero we do not need to compute anything for // the higher limbs so we can early return here. while (i < a.len and a_borrow == 1) : (i += 1) { - a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &r[i])); + const ov = @subWithOverflow(a[i], a_borrow); + r[i] = ov[0]; + a_borrow = ov[1]; } 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 var r_carry: u1 = 1; while (i < b.len) : (i += 1) { - var b_limb: Limb = undefined; - b_borrow = @boolToInt(@subWithOverflow(Limb, b[i], b_borrow, &b_limb)); - - r[i] = ~a[i] & b_limb; - r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i])); + const ov1 = @subWithOverflow(b[i], b_borrow); + b_borrow = ov1[1]; + const ov2 = @addWithOverflow(~a[i] & ov1[0], r_carry); + r[i] = ov2[0]; + r_carry = ov2[1]; } // 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 var r_carry: u1 = 1; while (i < b.len) : (i += 1) { - var a_limb: Limb = undefined; - a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &a_limb)); - - var b_limb: Limb = undefined; - b_borrow = @boolToInt(@subWithOverflow(Limb, b[i], b_borrow, &b_limb)); - - r[i] = a_limb & b_limb; - r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i])); + const ov1 = @subWithOverflow(a[i], a_borrow); + a_borrow = ov1[1]; + const ov2 = @subWithOverflow(b[i], b_borrow); + b_borrow = ov2[1]; + const ov3 = @addWithOverflow(ov1[0] & ov2[0], r_carry); + r[i] = ov3[0]; + r_carry = ov3[1]; } // 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_ var a_borrow: u1 = 1; while (i < b.len) : (i += 1) { - var a_limb: Limb = undefined; - a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &a_limb)); - r[i] = ~a_limb & b[i]; + const ov = @subWithOverflow(a[i], a_borrow); + a_borrow = ov[1]; + r[i] = ~ov[0] & b[i]; } // 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_ var b_borrow: u1 = 1; while (i < b.len) : (i += 1) { - var a_limb: Limb = undefined; - b_borrow = @boolToInt(@subWithOverflow(Limb, b[i], b_borrow, &a_limb)); - r[i] = a[i] & ~a_limb; + const ov = @subWithOverflow(b[i], b_borrow); + b_borrow = ov[1]; + r[i] = a[i] & ~ov[0]; } 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_ var r_carry: u1 = 1; while (i < b.len) : (i += 1) { - var a_limb: Limb = undefined; - a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &a_limb)); - - var b_limb: Limb = undefined; - b_borrow = @boolToInt(@subWithOverflow(Limb, b[i], b_borrow, &b_limb)); - - r[i] = a_limb | b_limb; - r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i])); + const ov1 = @subWithOverflow(a[i], a_borrow); + a_borrow = ov1[1]; + const ov2 = @subWithOverflow(b[i], b_borrow); + b_borrow = ov2[1]; + const ov3 = @addWithOverflow(ov1[0] | ov2[0], r_carry); + r[i] = ov3[0]; + r_carry = ov3[1]; } // 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_ // With b = 0 and b_borrow = 0 we get (-a - 1) | (-0 - 0) = (-a - 1) | 0 = -a - 1. while (i < a.len) : (i += 1) { - a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &r[i])); - r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i])); + const ov1 = @subWithOverflow(a[i], a_borrow); + a_borrow = ov1[1]; + const ov2 = @addWithOverflow(ov1[0], r_carry); + r[i] = ov2[0]; + r_carry = ov2[1]; } 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_ var r_carry = @boolToInt(a_positive != b_positive); while (i < b.len) : (i += 1) { - var a_limb: Limb = undefined; - a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &a_limb)); - - var b_limb: Limb = undefined; - b_borrow = @boolToInt(@subWithOverflow(Limb, b[i], b_borrow, &b_limb)); - - r[i] = a_limb ^ b_limb; - r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i])); + const ov1 = @subWithOverflow(a[i], a_borrow); + a_borrow = ov1[1]; + const ov2 = @subWithOverflow(b[i], b_borrow); + b_borrow = ov2[1]; + const ov3 = @addWithOverflow(ov1[0] ^ ov2[0], r_carry); + r[i] = ov3[0]; + r_carry = ov3[1]; } while (i < a.len) : (i += 1) { - a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &r[i])); - r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i])); + const ov1 = @subWithOverflow(a[i], a_borrow); + a_borrow = ov1[1]; + const ov2 = @addWithOverflow(ov1[0], r_carry); + r[i] = ov2[0]; + r_carry = ov2[1]; } // 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 { llsquareBasecase(tmp2, tmp1[0..llnormalize(tmp1)]); mem.swap([]Limb, &tmp1, &tmp2); // Multiply by a - if (@shlWithOverflow(u32, exp, 1, &exp)) { + const ov = @shlWithOverflow(exp, 1); + exp = ov[0]; + if (ov[1] != 0) { mem.set(Limb, tmp2, 0); llmulacc(.add, null, tmp2, tmp1[0..llnormalize(tmp1)], a); mem.swap([]Limb, &tmp1, &tmp2); diff --git a/lib/std/math/powi.zig b/lib/std/math/powi.zig index 2e615de5d54f..d7d07985ebdf 100644 --- a/lib/std/math/powi.zig +++ b/lib/std/math/powi.zig @@ -70,22 +70,22 @@ pub fn powi(comptime T: type, x: T, y: T) (error{ while (exp > 1) { if (exp & 1 == 1) { - if (@mulWithOverflow(T, acc, base, &acc)) { - return error.Overflow; - } + const ov = @mulWithOverflow(acc, base); + if (ov[1] != 0) return error.Overflow; + acc = ov[0]; } exp >>= 1; - if (@mulWithOverflow(T, base, base, &base)) { - return error.Overflow; - } + const ov = @mulWithOverflow(base, base); + if (ov[1] != 0) return error.Overflow; + base = ov[0]; } if (exp == 1) { - if (@mulWithOverflow(T, acc, base, &acc)) { - return error.Overflow; - } + const ov = @mulWithOverflow(acc, base); + if (ov[1] != 0) return error.Overflow; + acc = ov[0]; } return acc; diff --git a/lib/std/mem.zig b/lib/std/mem.zig index a392335a7009..774db2caa474 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -3304,13 +3304,13 @@ pub fn alignPointerOffset(ptr: anytype, align_to: usize) ?usize { // Calculate the aligned base address with an eye out for overflow. const addr = @ptrToInt(ptr); - var new_addr: usize = undefined; - if (@addWithOverflow(usize, addr, align_to - 1, &new_addr)) return null; - new_addr &= ~@as(usize, align_to - 1); + var ov = @addWithOverflow(addr, align_to - 1); + if (ov[1] != 0) return null; + ov[0] &= ~@as(usize, align_to - 1); // The delta is expressed in terms of bytes, turn it into a number of child // type elements. - const delta = new_addr - addr; + const delta = ov[0] - addr; const pointee_size = @sizeOf(info.Pointer.child); if (delta % pointee_size != 0) return null; return delta / pointee_size; diff --git a/lib/std/net.zig b/lib/std/net.zig index 6818b91d5a83..4a0582e7f5ef 100644 --- a/lib/std/net.zig +++ b/lib/std/net.zig @@ -321,11 +321,15 @@ pub const Ip6Address = extern struct { if (scope_id) { if (c >= '0' and c <= '9') { const digit = c - '0'; - if (@mulWithOverflow(u32, result.sa.scope_id, 10, &result.sa.scope_id)) { - return error.Overflow; + { + const ov = @mulWithOverflow(result.sa.scope_id, 10); + if (ov[1] != 0) return error.Overflow; + result.sa.scope_id = ov[0]; } - if (@addWithOverflow(u32, result.sa.scope_id, digit, &result.sa.scope_id)) { - return error.Overflow; + { + const ov = @addWithOverflow(result.sa.scope_id, digit); + if (ov[1] != 0) return error.Overflow; + result.sa.scope_id = ov[0]; } } else { return error.InvalidCharacter; @@ -377,11 +381,15 @@ pub const Ip6Address = extern struct { return result; } else { const digit = try std.fmt.charToDigit(c, 16); - if (@mulWithOverflow(u16, x, 16, &x)) { - return error.Overflow; + { + const ov = @mulWithOverflow(x, 16); + if (ov[1] != 0) return error.Overflow; + x = ov[0]; } - if (@addWithOverflow(u16, x, digit, &x)) { - return error.Overflow; + { + const ov = @addWithOverflow(x, digit); + if (ov[1] != 0) return error.Overflow; + x = ov[0]; } saw_any_digits = true; } @@ -492,11 +500,15 @@ pub const Ip6Address = extern struct { return result; } else { const digit = try std.fmt.charToDigit(c, 16); - if (@mulWithOverflow(u16, x, 16, &x)) { - return error.Overflow; + { + const ov = @mulWithOverflow(x, 16); + if (ov[1] != 0) return error.Overflow; + x = ov[0]; } - if (@addWithOverflow(u16, x, digit, &x)) { - return error.Overflow; + { + const ov = @addWithOverflow(x, digit); + if (ov[1] != 0) return error.Overflow; + x = ov[0]; } saw_any_digits = true; } diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 7f227ffec4a4..ecb8a21d7a6b 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -1244,7 +1244,7 @@ pub fn sendmmsg(fd: i32, msgvec: [*]mmsghdr_const, vlen: u32, flags: u32) usize var size: i32 = 0; const msg_iovlen = @intCast(usize, msg.msg_hdr.msg_iovlen); // kernel side this is treated as unsigned for (msg.msg_hdr.msg_iov[0..msg_iovlen]) |iov| { - if (iov.iov_len > std.math.maxInt(i32) or @addWithOverflow(i32, size, @intCast(i32, iov.iov_len), &size)) { + if (iov.iov_len > std.math.maxInt(i32) or @addWithOverflow(size, @intCast(i32, iov.iov_len))[1] != 0) { // batch-send all messages up to the current message if (next_unsent < i) { const batch_size = i - next_unsent; diff --git a/lib/std/process.zig b/lib/std/process.zig index 23fad9e8c67d..849596ebfa16 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -1023,8 +1023,16 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo { '0'...'9' => byte - '0', else => return error.CorruptPasswordFile, }; - if (@mulWithOverflow(u32, uid, 10, &uid)) return error.CorruptPasswordFile; - if (@addWithOverflow(u32, uid, digit, &uid)) return error.CorruptPasswordFile; + { + const ov = @mulWithOverflow(uid, 10); + if (ov[1] != 0) return error.CorruptPasswordFile; + uid = ov[0]; + } + { + const ov = @addWithOverflow(uid, digit); + if (ov[1] != 0) return error.CorruptPasswordFile; + uid = ov[0]; + } }, }, .ReadGroupId => switch (byte) { @@ -1039,8 +1047,16 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo { '0'...'9' => byte - '0', else => return error.CorruptPasswordFile, }; - if (@mulWithOverflow(u32, gid, 10, &gid)) return error.CorruptPasswordFile; - if (@addWithOverflow(u32, gid, digit, &gid)) return error.CorruptPasswordFile; + { + const ov = @mulWithOverflow(gid, 10); + if (ov[1] != 0) return error.CorruptPasswordFile; + gid = ov[0]; + } + { + const ov = @addWithOverflow(gid, digit); + if (ov[1] != 0) return error.CorruptPasswordFile; + gid = ov[0]; + } }, }, } diff --git a/lib/std/zig/c_builtins.zig b/lib/std/zig/c_builtins.zig index 08a2ec78c4e1..9c28e56e3158 100644 --- a/lib/std/zig/c_builtins.zig +++ b/lib/std/zig/c_builtins.zig @@ -246,7 +246,9 @@ pub inline fn __builtin_constant_p(expr: anytype) c_int { return @boolToInt(false); } pub fn __builtin_mul_overflow(a: anytype, b: anytype, result: *@TypeOf(a, b)) c_int { - return @boolToInt(@mulWithOverflow(@TypeOf(a, b), a, b, result)); + const res = @mulWithOverflow(a, b); + result.* = res[0]; + return res[1]; } // __builtin_alloca_with_align is not currently implemented. diff --git a/lib/std/zig/number_literal.zig b/lib/std/zig/number_literal.zig index 118d16f59e7e..1b41908371f6 100644 --- a/lib/std/zig/number_literal.zig +++ b/lib/std/zig/number_literal.zig @@ -151,12 +151,14 @@ pub fn parseNumberLiteral(bytes: []const u8) Result { special = 0; if (float) continue; - if (x != 0) if (@mulWithOverflow(u64, x, base, &x)) { - overflow = true; - }; - if (@addWithOverflow(u64, x, digit, &x)) { - overflow = true; + if (x != 0) { + const res = @mulWithOverflow(x, base); + if (res[1] != 0) overflow = true; + x = res[0]; } + const res = @addWithOverflow(x, digit); + if (res[1] != 0) overflow = true; + x = res[0]; } if (underscore) return .{ .failure = .{ .trailing_underscore = bytes.len - 1 } }; if (special != 0) return .{ .failure = .{ .trailing_special = bytes.len - 1 } }; diff --git a/src/AstGen.zig b/src/AstGen.zig index 405bc1ccc307..1f8e2dd88115 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -2505,7 +2505,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As .err_union_code, .err_union_code_ptr, .ptr_type, - .overflow_arithmetic_ptr, .enum_literal, .merge_error_sets, .error_union_type, @@ -2543,7 +2542,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As .type_info, .size_of, .bit_size_of, - .log2_int_type, .typeof_log2_int_type, .ptr_to_int, .align_of, @@ -8236,21 +8234,7 @@ fn builtinCall( .add_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .add_with_overflow), .sub_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .sub_with_overflow), .mul_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .mul_with_overflow), - .shl_with_overflow => { - const int_type = try typeExpr(gz, scope, params[0]); - const log2_int_type = try gz.addUnNode(.log2_int_type, int_type, params[0]); - const ptr_type = try gz.addUnNode(.overflow_arithmetic_ptr, int_type, params[0]); - const lhs = try expr(gz, scope, .{ .rl = .{ .ty = int_type } }, params[1]); - const rhs = try expr(gz, scope, .{ .rl = .{ .ty = log2_int_type } }, params[2]); - const ptr = try expr(gz, scope, .{ .rl = .{ .ty = ptr_type } }, params[3]); - const result = try gz.addExtendedPayload(.shl_with_overflow, Zir.Inst.OverflowArithmetic{ - .node = gz.nodeIndexToRelative(node), - .lhs = lhs, - .rhs = rhs, - .ptr = ptr, - }); - return rvalue(gz, ri, result, node); - }, + .shl_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .shl_with_overflow), .atomic_load => { const result = try gz.addPlNode(.atomic_load, node, Zir.Inst.AtomicLoad{ @@ -8691,16 +8675,12 @@ fn overflowArithmetic( params: []const Ast.Node.Index, tag: Zir.Inst.Extended, ) InnerError!Zir.Inst.Ref { - const int_type = try typeExpr(gz, scope, params[0]); - const ptr_type = try gz.addUnNode(.overflow_arithmetic_ptr, int_type, params[0]); - const lhs = try expr(gz, scope, .{ .rl = .{ .ty = int_type } }, params[1]); - const rhs = try expr(gz, scope, .{ .rl = .{ .ty = int_type } }, params[2]); - const ptr = try expr(gz, scope, .{ .rl = .{ .ty = ptr_type } }, params[3]); - const result = try gz.addExtendedPayload(tag, Zir.Inst.OverflowArithmetic{ + const lhs = try expr(gz, scope, .{ .rl = .none }, params[0]); + const rhs = try expr(gz, scope, .{ .rl = .none }, params[1]); + const result = try gz.addExtendedPayload(tag, Zir.Inst.BinNode{ .node = gz.nodeIndexToRelative(node), .lhs = lhs, .rhs = rhs, - .ptr = ptr, }); return rvalue(gz, ri, result, node); } diff --git a/src/Autodoc.zig b/src/Autodoc.zig index 246b97037a75..7664d6cdbf1f 100644 --- a/src/Autodoc.zig +++ b/src/Autodoc.zig @@ -1510,26 +1510,6 @@ fn walkInstruction( // return operand; // }, - .overflow_arithmetic_ptr => { - const un_node = data[inst_index].un_node; - - const elem_type_ref = try self.walkRef(file, parent_scope, parent_src, un_node.operand, false); - const type_slot_index = self.types.items.len; - try self.types.append(self.arena, .{ - .Pointer = .{ - .size = .One, - .child = elem_type_ref.expr, - .is_mutable = true, - .is_volatile = false, - .is_allowzero = false, - }, - }); - - return DocData.WalkResult{ - .typeRef = .{ .type = @enumToInt(Ref.type_type) }, - .expr = .{ .type = type_slot_index }, - }; - }, .ptr_type => { const ptr = data[inst_index].ptr_type; const extra = file.zir.extraData(Zir.Inst.PtrType, ptr.payload_index); diff --git a/src/BuiltinFn.zig b/src/BuiltinFn.zig index 7e23be2a3aa2..b71d96c3dd39 100644 --- a/src/BuiltinFn.zig +++ b/src/BuiltinFn.zig @@ -154,7 +154,7 @@ pub const list = list: { "@addWithOverflow", .{ .tag = .add_with_overflow, - .param_count = 4, + .param_count = 2, }, }, .{ @@ -636,7 +636,7 @@ pub const list = list: { "@mulWithOverflow", .{ .tag = .mul_with_overflow, - .param_count = 4, + .param_count = 2, }, }, .{ @@ -741,7 +741,7 @@ pub const list = list: { "@shlWithOverflow", .{ .tag = .shl_with_overflow, - .param_count = 4, + .param_count = 2, }, }, .{ @@ -889,7 +889,7 @@ pub const list = list: { "@subWithOverflow", .{ .tag = .sub_with_overflow, - .param_count = 4, + .param_count = 2, }, }, .{ diff --git a/src/Sema.zig b/src/Sema.zig index d25f3076d2aa..6546708aaadd 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -971,7 +971,6 @@ fn analyzeBodyInner( .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false), .optional_type => try sema.zirOptionalType(block, inst), .ptr_type => try sema.zirPtrType(block, inst), - .overflow_arithmetic_ptr => try sema.zirOverflowArithmeticPtr(block, inst), .ref => try sema.zirRef(block, inst), .ret_err_value_code => try sema.zirRetErrValueCode(inst), .shr => try sema.zirShr(block, inst, .shr), @@ -993,7 +992,6 @@ fn analyzeBodyInner( .bit_size_of => try sema.zirBitSizeOf(block, inst), .typeof => try sema.zirTypeof(block, inst), .typeof_builtin => try sema.zirTypeofBuiltin(block, inst), - .log2_int_type => try sema.zirLog2IntType(block, inst), .typeof_log2_int_type => try sema.zirTypeofLog2IntType(block, inst), .xor => try sema.zirBitwise(block, inst, .xor), .struct_init_empty => try sema.zirStructInitEmpty(block, inst), @@ -11762,7 +11760,7 @@ fn zirShl( if (scalar_ty.zigTypeTag() == .ComptimeInt) { break :val shifted.wrapped_result; } - if (shifted.overflowed.compareAllWithZero(.eq)) { + if (shifted.overflow_bit.compareAllWithZero(.eq)) { break :val shifted.wrapped_result; } return sema.fail(block, src, "operation caused overflow", .{}); @@ -13783,24 +13781,37 @@ fn zirOverflowArithmetic( const tracy = trace(@src()); defer tracy.end(); - const extra = sema.code.extraData(Zir.Inst.OverflowArithmetic, extended.operand).data; + const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; const src = LazySrcLoc.nodeOffset(extra.node); const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; - const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = extra.node }; - const lhs = try sema.resolveInst(extra.lhs); - const rhs = try sema.resolveInst(extra.rhs); - const ptr = try sema.resolveInst(extra.ptr); + const uncasted_lhs = try sema.resolveInst(extra.lhs); + const uncasted_rhs = try sema.resolveInst(extra.rhs); - const lhs_ty = sema.typeOf(lhs); - const rhs_ty = sema.typeOf(rhs); + const lhs_ty = sema.typeOf(uncasted_lhs); + const rhs_ty = sema.typeOf(uncasted_rhs); const mod = sema.mod; - // Note, the types of lhs/rhs (also for shifting)/ptr are already correct as ensured by astgen. try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); - const dest_ty = lhs_ty; + + const instructions = &[_]Air.Inst.Ref{ uncasted_lhs, uncasted_rhs }; + const dest_ty = if (zir_tag == .shl_with_overflow) + lhs_ty + else + try sema.resolvePeerTypes(block, src, instructions, .{ + .override = &[_]LazySrcLoc{ lhs_src, rhs_src }, + }); + + const rhs_dest_ty = if (zir_tag == .shl_with_overflow) + try sema.log2IntType(block, lhs_ty, src) + else + dest_ty; + + const lhs = try sema.coerce(block, dest_ty, uncasted_lhs, lhs_src); + const rhs = try sema.coerce(block, rhs_dest_ty, uncasted_rhs, rhs_src); + if (dest_ty.scalarType().zigTypeTag() != .Int) { return sema.fail(block, src, "expected vector of integers or integer tag type, found '{}'", .{dest_ty.fmt(mod)}); } @@ -13809,14 +13820,11 @@ fn zirOverflowArithmetic( const maybe_rhs_val = try sema.resolveMaybeUndefVal(rhs); const tuple_ty = try sema.overflowArithmeticTupleType(dest_ty); - // TODO: Remove and use `ov_ty` instead. - // This is a temporary type used until overflow arithmetic properly returns `u1` instead of `bool`. - const overflowed_ty = if (dest_ty.zigTypeTag() == .Vector) try Type.vector(sema.arena, dest_ty.vectorLen(), Type.bool) else Type.bool; - - const result: struct { - /// TODO: Rename to `overflow_bit` and make of type `u1`. - overflowed: Air.Inst.Ref, - wrapped: Air.Inst.Ref, + + var result: struct { + inst: Air.Inst.Ref = .none, + wrapped: Value = Value.initTag(.unreachable_value), + overflow_bit: Value, } = result: { switch (zir_tag) { .add_with_overflow => { @@ -13825,24 +13833,22 @@ fn zirOverflowArithmetic( // Otherwise, if either of the argument is undefined, undefined is returned. if (maybe_lhs_val) |lhs_val| { if (!lhs_val.isUndef() and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { - break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs }; + break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = rhs }; } } if (maybe_rhs_val) |rhs_val| { if (!rhs_val.isUndef() and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) { - break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs }; + break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs }; } } if (maybe_lhs_val) |lhs_val| { if (maybe_rhs_val) |rhs_val| { if (lhs_val.isUndef() or rhs_val.isUndef()) { - break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) }; + break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; } const result = try sema.intAddWithOverflow(lhs_val, rhs_val, dest_ty); - const overflowed = try sema.addConstant(overflowed_ty, result.overflowed); - const wrapped = try sema.addConstant(dest_ty, result.wrapped_result); - break :result .{ .overflowed = overflowed, .wrapped = wrapped }; + break :result .{ .overflow_bit = result.overflow_bit, .wrapped = result.wrapped_result }; } } }, @@ -13851,18 +13857,16 @@ fn zirOverflowArithmetic( // Otherwise, if either result is undefined, both results are undefined. if (maybe_rhs_val) |rhs_val| { if (rhs_val.isUndef()) { - break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) }; + break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; } else if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { - break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs }; + break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs }; } else if (maybe_lhs_val) |lhs_val| { if (lhs_val.isUndef()) { - break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) }; + break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; } const result = try sema.intSubWithOverflow(lhs_val, rhs_val, dest_ty); - const overflowed = try sema.addConstant(overflowed_ty, result.overflowed); - const wrapped = try sema.addConstant(dest_ty, result.wrapped_result); - break :result .{ .overflowed = overflowed, .wrapped = wrapped }; + break :result .{ .overflow_bit = result.overflow_bit, .wrapped = result.wrapped_result }; } } }, @@ -13873,9 +13877,9 @@ fn zirOverflowArithmetic( if (maybe_lhs_val) |lhs_val| { if (!lhs_val.isUndef()) { if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { - break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs }; - } else if (try sema.compareAll(lhs_val, .eq, Value.one, dest_ty)) { - break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs }; + break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs }; + } else if (try sema.compareAll(lhs_val, .eq, try maybeRepeated(sema, dest_ty, Value.one), dest_ty)) { + break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = rhs }; } } } @@ -13883,9 +13887,9 @@ fn zirOverflowArithmetic( if (maybe_rhs_val) |rhs_val| { if (!rhs_val.isUndef()) { if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { - break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs }; - } else if (try sema.compareAll(rhs_val, .eq, Value.one, dest_ty)) { - break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs }; + break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = rhs }; + } else if (try sema.compareAll(rhs_val, .eq, try maybeRepeated(sema, dest_ty, Value.one), dest_ty)) { + break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs }; } } } @@ -13893,13 +13897,11 @@ fn zirOverflowArithmetic( if (maybe_lhs_val) |lhs_val| { if (maybe_rhs_val) |rhs_val| { if (lhs_val.isUndef() or rhs_val.isUndef()) { - break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) }; + break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; } const result = try lhs_val.intMulWithOverflow(rhs_val, dest_ty, sema.arena, mod); - const overflowed = try sema.addConstant(overflowed_ty, result.overflowed); - const wrapped = try sema.addConstant(dest_ty, result.wrapped_result); - break :result .{ .overflowed = overflowed, .wrapped = wrapped }; + break :result .{ .overflow_bit = result.overflow_bit, .wrapped = result.wrapped_result }; } } }, @@ -13909,24 +13911,22 @@ fn zirOverflowArithmetic( // Oterhwise if either of the arguments is undefined, both results are undefined. if (maybe_lhs_val) |lhs_val| { if (!lhs_val.isUndef() and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { - break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs }; + break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs }; } } if (maybe_rhs_val) |rhs_val| { if (!rhs_val.isUndef() and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) { - break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs }; + break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs }; } } if (maybe_lhs_val) |lhs_val| { if (maybe_rhs_val) |rhs_val| { if (lhs_val.isUndef() or rhs_val.isUndef()) { - break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) }; + break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; } const result = try lhs_val.shlWithOverflow(rhs_val, dest_ty, sema.arena, sema.mod); - const overflowed = try sema.addConstant(overflowed_ty, result.overflowed); - const wrapped = try sema.addConstant(dest_ty, result.wrapped_result); - break :result .{ .overflowed = overflowed, .wrapped = wrapped }; + break :result .{ .overflow_bit = result.overflow_bit, .wrapped = result.wrapped_result }; } } }, @@ -13944,7 +13944,7 @@ fn zirOverflowArithmetic( const runtime_src = if (maybe_lhs_val == null) lhs_src else rhs_src; try sema.requireRuntimeBlock(block, src, runtime_src); - const tuple = try block.addInst(.{ + return block.addInst(.{ .tag = air_tag, .data = .{ .ty_pl = .{ .ty = try block.sema.addType(tuple_ty), @@ -13954,16 +13954,32 @@ fn zirOverflowArithmetic( }), } }, }); + }; - const wrapped = try sema.tupleFieldValByIndex(block, src, tuple, 0, tuple_ty); - try sema.storePtr2(block, src, ptr, ptr_src, wrapped, src, .store); + if (result.inst != .none) { + if (try sema.resolveMaybeUndefVal(result.inst)) |some| { + result.wrapped = some; + result.inst = .none; + } + } - const overflow_bit = try sema.tupleFieldValByIndex(block, src, tuple, 1, tuple_ty); - return block.addBitCast(overflowed_ty, overflow_bit); - }; + if (result.inst == .none) { + const values = try sema.arena.alloc(Value, 2); + values[0] = result.wrapped; + values[1] = result.overflow_bit; + const tuple_val = try Value.Tag.aggregate.create(sema.arena, values); + return sema.addConstant(tuple_ty, tuple_val); + } + + const element_refs = try sema.arena.alloc(Air.Inst.Ref, 2); + element_refs[0] = result.inst; + element_refs[1] = try sema.addConstant(tuple_ty.structFieldType(1), result.overflow_bit); + return block.addAggregateInit(tuple_ty, element_refs); +} - try sema.storePtr2(block, src, ptr, ptr_src, result.wrapped, src, .store); - return result.overflowed; +fn maybeRepeated(sema: *Sema, ty: Type, val: Value) !Value { + if (ty.zigTypeTag() != .Vector) return val; + return Value.Tag.repeated.create(sema.arena, val); } fn overflowArithmeticTupleType(sema: *Sema, ty: Type) !Type { @@ -16211,14 +16227,6 @@ fn zirTypeofLog2IntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil return sema.addType(res_ty); } -fn zirLog2IntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const inst_data = sema.code.instructions.items(.data)[inst].un_node; - const src = inst_data.src(); - const operand = try sema.resolveType(block, src, inst_data.operand); - const res_ty = try sema.log2IntType(block, operand, src); - return sema.addType(res_ty); -} - fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) CompileError!Type { switch (operand.zigTypeTag()) { .ComptimeInt => return Type.comptime_int, @@ -17039,24 +17047,6 @@ fn floatOpAllowed(tag: Zir.Inst.Tag) bool { }; } -fn zirOverflowArithmeticPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - - const inst_data = sema.code.instructions.items(.data)[inst].un_node; - const elem_ty_src = inst_data.src(); - const elem_type = try sema.resolveType(block, elem_ty_src, inst_data.operand); - const ty = try Type.ptr(sema.arena, sema.mod, .{ - .pointee_type = elem_type, - .@"addrspace" = .generic, - .mutable = true, - .@"allowzero" = false, - .@"volatile" = false, - .size = .One, - }); - return sema.addType(ty); -} - fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { const tracy = trace(@src()); defer tracy.end(); @@ -32613,11 +32603,11 @@ fn intSubWithOverflow( const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf); const of_math_result = try sema.intSubWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType()); - overflowed_data[i] = of_math_result.overflowed; + overflowed_data[i] = of_math_result.overflow_bit; scalar.* = of_math_result.wrapped_result; } return Value.OverflowArithmeticResult{ - .overflowed = try Value.Tag.aggregate.create(sema.arena, overflowed_data), + .overflow_bit = try Value.Tag.aggregate.create(sema.arena, overflowed_data), .wrapped_result = try Value.Tag.aggregate.create(sema.arena, result_data), }; } @@ -32645,7 +32635,7 @@ fn intSubWithOverflowScalar( const overflowed = result_bigint.subWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits); const wrapped_result = try Value.fromBigInt(sema.arena, result_bigint.toConst()); return Value.OverflowArithmeticResult{ - .overflowed = Value.makeBool(overflowed), + .overflow_bit = Value.boolToInt(overflowed), .wrapped_result = wrapped_result, }; } @@ -32964,11 +32954,11 @@ fn intAddWithOverflow( const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf); const of_math_result = try sema.intAddWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType()); - overflowed_data[i] = of_math_result.overflowed; + overflowed_data[i] = of_math_result.overflow_bit; scalar.* = of_math_result.wrapped_result; } return Value.OverflowArithmeticResult{ - .overflowed = try Value.Tag.aggregate.create(sema.arena, overflowed_data), + .overflow_bit = try Value.Tag.aggregate.create(sema.arena, overflowed_data), .wrapped_result = try Value.Tag.aggregate.create(sema.arena, result_data), }; } @@ -32996,7 +32986,7 @@ fn intAddWithOverflowScalar( const overflowed = result_bigint.addWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits); const result = try Value.fromBigInt(sema.arena, result_bigint.toConst()); return Value.OverflowArithmeticResult{ - .overflowed = Value.makeBool(overflowed), + .overflow_bit = Value.boolToInt(overflowed), .wrapped_result = result, }; } diff --git a/src/TypedValue.zig b/src/TypedValue.zig index 805448d54090..6e096ee90a6b 100644 --- a/src/TypedValue.zig +++ b/src/TypedValue.zig @@ -225,9 +225,7 @@ pub fn print( .one => return writer.writeAll("1"), .void_value => return writer.writeAll("{}"), .unreachable_value => return writer.writeAll("unreachable"), - .the_only_possible_value => { - val = ty.onePossibleValue().?; - }, + .the_only_possible_value => return writer.writeAll("0"), .bool_true => return writer.writeAll("true"), .bool_false => return writer.writeAll("false"), .ty => return val.castTag(.ty).?.data.print(writer, mod), diff --git a/src/Zir.zig b/src/Zir.zig index cb0923eddf2e..ffe1f4c345f2 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -539,9 +539,6 @@ pub const Inst = struct { /// Obtains the return type of the in-scope function. /// Uses the `node` union field. ret_type, - /// Create a pointer type for overflow arithmetic. - /// TODO remove when doing https://github.com/ziglang/zig/issues/10248 - overflow_arithmetic_ptr, /// Create a pointer type which can have a sentinel, alignment, address space, and/or bit range. /// Uses the `ptr_type` union field. ptr_type, @@ -600,9 +597,6 @@ pub const Inst = struct { /// Returns the integer type for the RHS of a shift operation. /// Uses the `un_node` field. typeof_log2_int_type, - /// Given an integer type, returns the integer type for the RHS of a shift operation. - /// Uses the `un_node` field. - log2_int_type, /// Asserts control-flow will not reach this instruction (`unreachable`). /// Uses the `unreachable` union field. @"unreachable", @@ -1121,7 +1115,6 @@ pub const Inst = struct { .err_union_code, .err_union_code_ptr, .ptr_type, - .overflow_arithmetic_ptr, .enum_literal, .merge_error_sets, .error_union_type, @@ -1132,7 +1125,6 @@ pub const Inst = struct { .slice_sentinel, .import, .typeof_log2_int_type, - .log2_int_type, .resolve_inferred_alloc, .set_eval_branch_quota, .switch_capture, @@ -1422,7 +1414,6 @@ pub const Inst = struct { .err_union_code, .err_union_code_ptr, .ptr_type, - .overflow_arithmetic_ptr, .enum_literal, .merge_error_sets, .error_union_type, @@ -1433,7 +1424,6 @@ pub const Inst = struct { .slice_sentinel, .import, .typeof_log2_int_type, - .log2_int_type, .switch_capture, .switch_capture_ref, .switch_capture_multi, @@ -1664,7 +1654,6 @@ pub const Inst = struct { .ret_err_value_code = .str_tok, .ret_ptr = .node, .ret_type = .node, - .overflow_arithmetic_ptr = .un_node, .ptr_type = .ptr_type, .slice_start = .pl_node, .slice_end = .pl_node, @@ -1678,7 +1667,6 @@ pub const Inst = struct { .negate_wrap = .un_node, .typeof = .un_node, .typeof_log2_int_type = .un_node, - .log2_int_type = .un_node, .@"unreachable" = .@"unreachable", .xor = .pl_node, .optional_type = .un_node, @@ -1916,19 +1904,19 @@ pub const Inst = struct { /// The AST node is the builtin call. typeof_peer, /// Implements the `@addWithOverflow` builtin. - /// `operand` is payload index to `OverflowArithmetic`. + /// `operand` is payload index to `BinNode`. /// `small` is unused. add_with_overflow, /// Implements the `@subWithOverflow` builtin. - /// `operand` is payload index to `OverflowArithmetic`. + /// `operand` is payload index to `BinNode`. /// `small` is unused. sub_with_overflow, /// Implements the `@mulWithOverflow` builtin. - /// `operand` is payload index to `OverflowArithmetic`. + /// `operand` is payload index to `BinNode`. /// `small` is unused. mul_with_overflow, /// Implements the `@shlWithOverflow` builtin. - /// `operand` is payload index to `OverflowArithmetic`. + /// `operand` is payload index to `BinNode`. /// `small` is unused. shl_with_overflow, /// `operand` is payload index to `UnNode`. @@ -3430,13 +3418,6 @@ pub const Inst = struct { field_name: Ref, }; - pub const OverflowArithmetic = struct { - node: i32, - lhs: Ref, - rhs: Ref, - ptr: Ref, - }; - pub const Cmpxchg = struct { node: i32, ptr: Ref, diff --git a/src/link/Coff.zig b/src/link/Coff.zig index aa94704c5451..232342dd7f36 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1860,9 +1860,7 @@ fn writeHeader(self: *Coff) !void { } pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { - // TODO https://github.com/ziglang/zig/issues/1284 - return math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch - math.maxInt(@TypeOf(actual_size)); + return actual_size +| (actual_size / ideal_factor); } fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 { diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 6cc3a7d68f81..1b65bbb04b89 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -2445,9 +2445,7 @@ fn makeString(self: *Dwarf, bytes: []const u8) !u32 { } fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { - // TODO https://github.com/ziglang/zig/issues/1284 - return std.math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch - std.math.maxInt(@TypeOf(actual_size)); + return actual_size +| (actual_size / ideal_factor); } pub fn flushModule(self: *Dwarf, module: *Module) !void { diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 30c88fe9b200..466442cd774f 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -3032,9 +3032,7 @@ fn getLDMOption(target: std.Target) ?[]const u8 { } fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { - // TODO https://github.com/ziglang/zig/issues/1284 - return std.math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch - std.math.maxInt(@TypeOf(actual_size)); + return actual_size +| (actual_size / ideal_factor); } // Provide a blueprint of csu (c-runtime startup) objects for supported diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 733f2a6c2abe..852efaf28684 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -3772,9 +3772,7 @@ fn writeHeader(self: *MachO, ncmds: u32, sizeofcmds: u32) !void { } pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { - // TODO https://github.com/ziglang/zig/issues/1284 - return std.math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch - std.math.maxInt(@TypeOf(actual_size)); + return actual_size +| (actual_size / ideal_factor); } fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 { diff --git a/src/print_zir.zig b/src/print_zir.zig index bc4dc84075b3..49c97a5bc7cf 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -185,7 +185,6 @@ const Writer = struct { .size_of, .bit_size_of, .typeof_log2_int_type, - .log2_int_type, .ptr_to_int, .compile_error, .set_eval_branch_quota, @@ -230,7 +229,6 @@ const Writer = struct { .validate_struct_init_ty, .make_ptr_const, .validate_deref, - .overflow_arithmetic_ptr, .check_comptime_control_flow, => try self.writeUnNode(stream, inst), @@ -1153,14 +1151,12 @@ const Writer = struct { } fn writeOverflowArithmetic(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { - const extra = self.code.extraData(Zir.Inst.OverflowArithmetic, extended.operand).data; + const extra = self.code.extraData(Zir.Inst.BinNode, extended.operand).data; const src = LazySrcLoc.nodeOffset(extra.node); try self.writeInstRef(stream, extra.lhs); try stream.writeAll(", "); try self.writeInstRef(stream, extra.rhs); - try stream.writeAll(", "); - try self.writeInstRef(stream, extra.ptr); try stream.writeAll(")) "); try self.writeSrc(stream, src); } diff --git a/src/type.zig b/src/type.zig index 349d7557796e..43a3636ba382 100644 --- a/src/type.zig +++ b/src/type.zig @@ -3123,6 +3123,7 @@ pub const Type = extern union { for (tuple.types) |field_ty, i| { const val = tuple.values[i]; if (val.tag() != .unreachable_value) continue; // comptime field + if (!(field_ty.hasRuntimeBits())) continue; switch (try field_ty.abiAlignmentAdvanced(target, strat)) { .scalar => |field_align| big_align = @max(big_align, field_align), diff --git a/src/value.zig b/src/value.zig index a607a3551e2b..eeb1228ebc04 100644 --- a/src/value.zig +++ b/src/value.zig @@ -1378,6 +1378,7 @@ pub const Value = extern union { var enum_buffer: Payload.U64 = undefined; const int_val = val.enumToInt(ty, &enum_buffer); + if (abi_size == 0) return; if (abi_size <= @sizeOf(u64)) { const int: u64 = switch (int_val.tag()) { .zero => 0, @@ -1571,6 +1572,7 @@ pub const Value = extern union { const abi_size = @intCast(usize, ty.abiSize(target)); const bits = int_info.bits; + if (bits == 0) return Value.zero; if (bits <= 64) switch (int_info.signedness) { // Fast path for integers <= u64 .signed => return Value.Tag.int_i64.create(arena, std.mem.readVarPackedInt(i64, buffer, bit_offset, bits, endian, .signed)), .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 { } pub const OverflowArithmeticResult = struct { - /// TODO: Rename to `overflow_bit` and make of type `u1`. - overflowed: Value, + overflow_bit: Value, wrapped_result: Value, }; @@ -3395,11 +3396,11 @@ pub const Value = extern union { const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); const of_math_result = try intMulWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType(), arena, target); - overflowed_data[i] = of_math_result.overflowed; + overflowed_data[i] = of_math_result.overflow_bit; scalar.* = of_math_result.wrapped_result; } return OverflowArithmeticResult{ - .overflowed = try Value.Tag.aggregate.create(arena, overflowed_data), + .overflow_bit = try Value.Tag.aggregate.create(arena, overflowed_data), .wrapped_result = try Value.Tag.aggregate.create(arena, result_data), }; } @@ -3436,7 +3437,7 @@ pub const Value = extern union { } return OverflowArithmeticResult{ - .overflowed = makeBool(overflowed), + .overflow_bit = boolToInt(overflowed), .wrapped_result = try fromBigInt(arena, result_bigint.toConst()), }; } @@ -4141,11 +4142,11 @@ pub const Value = extern union { const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); const of_math_result = try shlWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType(), allocator, target); - overflowed_data[i] = of_math_result.overflowed; + overflowed_data[i] = of_math_result.overflow_bit; scalar.* = of_math_result.wrapped_result; } return OverflowArithmeticResult{ - .overflowed = try Value.Tag.aggregate.create(allocator, overflowed_data), + .overflow_bit = try Value.Tag.aggregate.create(allocator, overflowed_data), .wrapped_result = try Value.Tag.aggregate.create(allocator, result_data), }; } @@ -4178,7 +4179,7 @@ pub const Value = extern union { result_bigint.truncate(result_bigint.toConst(), info.signedness, info.bits); } return OverflowArithmeticResult{ - .overflowed = makeBool(overflowed), + .overflow_bit = boolToInt(overflowed), .wrapped_result = try fromBigInt(allocator, result_bigint.toConst()), }; } @@ -5492,6 +5493,10 @@ pub const Value = extern union { return if (x) Value.true else Value.false; } + pub fn boolToInt(x: bool) Value { + return if (x) Value.one else Value.zero; + } + pub const RuntimeIndex = enum(u32) { zero = 0, comptime_field_ptr = std.math.maxInt(u32), diff --git a/stage1/zig1.wasm b/stage1/zig1.wasm index 7f19d7ddbc3b..1ce3a0fb9703 100644 Binary files a/stage1/zig1.wasm and b/stage1/zig1.wasm differ diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 0b276deba703..08066edc73bc 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -1505,3 +1505,16 @@ test "implicit cast from [:0]T to [*c]T" { try expect(c.len == a.len); try expect(c.ptr == a.ptr); } + +test "bitcast packed struct with u0" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + + const S = packed struct(u2) { a: u0, b: u2 }; + const s = @bitCast(S, @as(u2, 2)); + try expect(s.a == 0); + try expect(s.b == 2); + const i = @bitCast(u2, s); + try expect(i == 2); +} diff --git a/test/behavior/eval.zig b/test/behavior/eval.zig index 97c3a85bbb89..8c3962e3e492 100644 --- a/test/behavior/eval.zig +++ b/test/behavior/eval.zig @@ -489,18 +489,11 @@ test "comptime bitwise operators" { test "comptime shlWithOverflow" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO - const ct_shifted: u64 = comptime amt: { - var amt = @as(u64, 0); - _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt); - break :amt amt; - }; - - const rt_shifted: u64 = amt: { - var amt = @as(u64, 0); - _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt); - break :amt amt; - }; + const ct_shifted = @shlWithOverflow(~@as(u64, 0), 16)[0]; + var a = ~@as(u64, 0); + const rt_shifted = @shlWithOverflow(a, 16)[0]; try expect(ct_shifted == rt_shifted); } diff --git a/test/behavior/math.zig b/test/behavior/math.zig index 29e0b9ff7942..db032b1983b5 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -533,6 +533,7 @@ fn testUnsignedNegationWrappingEval(x: u16) !void { test "negation wrapping" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO try expectEqual(@as(u1, 1), negateWrap(u1, 1)); @@ -632,42 +633,53 @@ test "128-bit multiplication" { } test "@addWithOverflow" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO { - var result: u8 = undefined; - try expect(@addWithOverflow(u8, 250, 100, &result)); - try expect(result == 94); - try expect(!@addWithOverflow(u8, 100, 150, &result)); - try expect(result == 250); - + var a: u8 = 250; + const ov = @addWithOverflow(a, 100); + try expect(ov[0] == 94); + try expect(ov[1] == 1); + } + { + var a: u8 = 100; + const ov = @addWithOverflow(a, 150); + try expect(ov[0] == 250); + try expect(ov[1] == 0); + } + { var a: u8 = 200; var b: u8 = 99; - try expect(@addWithOverflow(u8, a, b, &result)); - try expect(result == 43); + var ov = @addWithOverflow(a, b); + try expect(ov[0] == 43); + try expect(ov[1] == 1); b = 55; - try expect(!@addWithOverflow(u8, a, b, &result)); - try expect(result == 255); + ov = @addWithOverflow(a, b); + try expect(ov[0] == 255); + try expect(ov[1] == 0); } { var a: usize = 6; var b: usize = 6; - var res: usize = undefined; - try expect(!@addWithOverflow(usize, a, b, &res)); - try expect(res == 12); + const ov = @addWithOverflow(a, b); + try expect(ov[0] == 12); + try expect(ov[1] == 0); } { var a: isize = -6; var b: isize = -6; - var res: isize = undefined; - try expect(!@addWithOverflow(isize, a, b, &res)); - try expect(res == -12); + const ov = @addWithOverflow(a, b); + try expect(ov[0] == -12); + try expect(ov[1] == 0); } } test "small int addition" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO var x: u2 = 0; @@ -682,180 +694,206 @@ test "small int addition" { x += 1; try expect(x == 3); - var result: @TypeOf(x) = 3; - try expect(@addWithOverflow(@TypeOf(x), x, 1, &result)); - - try expect(result == 0); + const ov = @addWithOverflow(x, 1); + try expect(ov[0] == 0); + try expect(ov[1] == 1); } test "basic @mulWithOverflow" { - var result: u8 = undefined; - try expect(@mulWithOverflow(u8, 86, 3, &result)); - try expect(result == 2); - try expect(!@mulWithOverflow(u8, 85, 3, &result)); - try expect(result == 255); + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + + { + var a: u8 = 86; + const ov = @mulWithOverflow(a, 3); + try expect(ov[0] == 2); + try expect(ov[1] == 1); + } + { + var a: u8 = 85; + const ov = @mulWithOverflow(a, 3); + try expect(ov[0] == 255); + try expect(ov[1] == 0); + } var a: u8 = 123; var b: u8 = 2; - try expect(!@mulWithOverflow(u8, a, b, &result)); - try expect(result == 246); + var ov = @mulWithOverflow(a, b); + try expect(ov[0] == 246); + try expect(ov[1] == 0); b = 4; - try expect(@mulWithOverflow(u8, a, b, &result)); - try expect(result == 236); + ov = @mulWithOverflow(a, b); + try expect(ov[0] == 236); + try expect(ov[1] == 1); } -// TODO migrate to this for all backends once they handle more cases test "extensive @mulWithOverflow" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO { var a: u5 = 3; var b: u5 = 10; - var res: u5 = undefined; - try expect(!@mulWithOverflow(u5, a, b, &res)); - try expect(res == 30); + var ov = @mulWithOverflow(a, b); + try expect(ov[0] == 30); + try expect(ov[1] == 0); b = 11; - try expect(@mulWithOverflow(u5, a, b, &res)); - try expect(res == 1); + ov = @mulWithOverflow(a, b); + try expect(ov[0] == 1); + try expect(ov[1] == 1); } { var a: i5 = 3; var b: i5 = -5; - var res: i5 = undefined; - try expect(!@mulWithOverflow(i5, a, b, &res)); - try expect(res == -15); + var ov = @mulWithOverflow(a, b); + try expect(ov[0] == -15); + try expect(ov[1] == 0); b = -6; - try expect(@mulWithOverflow(i5, a, b, &res)); - try expect(res == 14); + ov = @mulWithOverflow(a, b); + try expect(ov[0] == 14); + try expect(ov[1] == 1); } { var a: u8 = 3; var b: u8 = 85; - var res: u8 = undefined; - try expect(!@mulWithOverflow(u8, a, b, &res)); - try expect(res == 255); + var ov = @mulWithOverflow(a, b); + try expect(ov[0] == 255); + try expect(ov[1] == 0); b = 86; - try expect(@mulWithOverflow(u8, a, b, &res)); - try expect(res == 2); + ov = @mulWithOverflow(a, b); + try expect(ov[0] == 2); + try expect(ov[1] == 1); } { var a: i8 = 3; var b: i8 = -42; - var res: i8 = undefined; - try expect(!@mulWithOverflow(i8, a, b, &res)); - try expect(res == -126); + var ov = @mulWithOverflow(a, b); + try expect(ov[0] == -126); + try expect(ov[1] == 0); b = -43; - try expect(@mulWithOverflow(i8, a, b, &res)); - try expect(res == 127); + ov = @mulWithOverflow(a, b); + try expect(ov[0] == 127); + try expect(ov[1] == 1); } { var a: u14 = 3; var b: u14 = 0x1555; - var res: u14 = undefined; - try expect(!@mulWithOverflow(u14, a, b, &res)); - try expect(res == 0x3fff); + var ov = @mulWithOverflow(a, b); + try expect(ov[0] == 0x3fff); + try expect(ov[1] == 0); b = 0x1556; - try expect(@mulWithOverflow(u14, a, b, &res)); - try expect(res == 2); + ov = @mulWithOverflow(a, b); + try expect(ov[0] == 2); + try expect(ov[1] == 1); } { var a: i14 = 3; var b: i14 = -0xaaa; - var res: i14 = undefined; - try expect(!@mulWithOverflow(i14, a, b, &res)); - try expect(res == -0x1ffe); + var ov = @mulWithOverflow(a, b); + try expect(ov[0] == -0x1ffe); + try expect(ov[1] == 0); b = -0xaab; - try expect(@mulWithOverflow(i14, a, b, &res)); - try expect(res == 0x1fff); + ov = @mulWithOverflow(a, b); + try expect(ov[0] == 0x1fff); } { var a: u16 = 3; var b: u16 = 0x5555; - var res: u16 = undefined; - try expect(!@mulWithOverflow(u16, a, b, &res)); - try expect(res == 0xffff); + var ov = @mulWithOverflow(a, b); + try expect(ov[0] == 0xffff); + try expect(ov[1] == 0); b = 0x5556; - try expect(@mulWithOverflow(u16, a, b, &res)); - try expect(res == 2); + ov = @mulWithOverflow(a, b); + try expect(ov[0] == 2); + try expect(ov[1] == 1); } { var a: i16 = 3; var b: i16 = -0x2aaa; - var res: i16 = undefined; - try expect(!@mulWithOverflow(i16, a, b, &res)); - try expect(res == -0x7ffe); + var ov = @mulWithOverflow(a, b); + try expect(ov[0] == -0x7ffe); + try expect(ov[1] == 0); b = -0x2aab; - try expect(@mulWithOverflow(i16, a, b, &res)); - try expect(res == 0x7fff); + ov = @mulWithOverflow(a, b); + try expect(ov[0] == 0x7fff); + try expect(ov[1] == 1); } { var a: u30 = 3; var b: u30 = 0x15555555; - var res: u30 = undefined; - try expect(!@mulWithOverflow(u30, a, b, &res)); - try expect(res == 0x3fffffff); + var ov = @mulWithOverflow(a, b); + try expect(ov[0] == 0x3fffffff); + try expect(ov[1] == 0); b = 0x15555556; - try expect(@mulWithOverflow(u30, a, b, &res)); - try expect(res == 2); + ov = @mulWithOverflow(a, b); + try expect(ov[0] == 2); + try expect(ov[1] == 1); } { var a: i30 = 3; var b: i30 = -0xaaaaaaa; - var res: i30 = undefined; - try expect(!@mulWithOverflow(i30, a, b, &res)); - try expect(res == -0x1ffffffe); + var ov = @mulWithOverflow(a, b); + try expect(ov[0] == -0x1ffffffe); + try expect(ov[1] == 0); b = -0xaaaaaab; - try expect(@mulWithOverflow(i30, a, b, &res)); - try expect(res == 0x1fffffff); + ov = @mulWithOverflow(a, b); + try expect(ov[0] == 0x1fffffff); + try expect(ov[1] == 1); } { var a: u32 = 3; var b: u32 = 0x55555555; - var res: u32 = undefined; - try expect(!@mulWithOverflow(u32, a, b, &res)); - try expect(res == 0xffffffff); + var ov = @mulWithOverflow(a, b); + try expect(ov[0] == 0xffffffff); + try expect(ov[1] == 0); b = 0x55555556; - try expect(@mulWithOverflow(u32, a, b, &res)); - try expect(res == 2); + ov = @mulWithOverflow(a, b); + try expect(ov[0] == 2); + try expect(ov[1] == 1); } { var a: i32 = 3; var b: i32 = -0x2aaaaaaa; - var res: i32 = undefined; - try expect(!@mulWithOverflow(i32, a, b, &res)); - try expect(res == -0x7ffffffe); + var ov = @mulWithOverflow(a, b); + try expect(ov[0] == -0x7ffffffe); + try expect(ov[1] == 0); b = -0x2aaaaaab; - try expect(@mulWithOverflow(i32, a, b, &res)); - try expect(res == 0x7fffffff); + ov = @mulWithOverflow(a, b); + try expect(ov[0] == 0x7fffffff); + try expect(ov[1] == 1); } } test "@mulWithOverflow bitsize > 32" { + // aarch64 fails on a release build of the compiler. + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -863,140 +901,181 @@ test "@mulWithOverflow bitsize > 32" { { var a: u62 = 3; var b: u62 = 0x1555555555555555; - var res: u62 = undefined; - try expect(!@mulWithOverflow(u62, a, b, &res)); - try expect(res == 0x3fffffffffffffff); + var ov = @mulWithOverflow(a, b); + try expect(ov[0] == 0x3fffffffffffffff); + try expect(ov[1] == 0); b = 0x1555555555555556; - try expect(@mulWithOverflow(u62, a, b, &res)); - try expect(res == 2); + ov = @mulWithOverflow(a, b); + try expect(ov[0] == 2); + try expect(ov[1] == 1); } { var a: i62 = 3; var b: i62 = -0xaaaaaaaaaaaaaaa; - var res: i62 = undefined; - try expect(!@mulWithOverflow(i62, a, b, &res)); - try expect(res == -0x1ffffffffffffffe); + var ov = @mulWithOverflow(a, b); + try expect(ov[0] == -0x1ffffffffffffffe); + try expect(ov[1] == 0); b = -0xaaaaaaaaaaaaaab; - try expect(@mulWithOverflow(i62, a, b, &res)); - try expect(res == 0x1fffffffffffffff); + ov = @mulWithOverflow(a, b); + try expect(ov[0] == 0x1fffffffffffffff); + try expect(ov[1] == 1); } { var a: u64 = 3; var b: u64 = 0x5555555555555555; - var res: u64 = undefined; - try expect(!@mulWithOverflow(u64, a, b, &res)); - try expect(res == 0xffffffffffffffff); + var ov = @mulWithOverflow(a, b); + try expect(ov[0] == 0xffffffffffffffff); + try expect(ov[1] == 0); b = 0x5555555555555556; - try expect(@mulWithOverflow(u64, a, b, &res)); - try expect(res == 2); + ov = @mulWithOverflow(a, b); + try expect(ov[0] == 2); + try expect(ov[1] == 1); } { var a: i64 = 3; var b: i64 = -0x2aaaaaaaaaaaaaaa; - var res: i64 = undefined; - try expect(!@mulWithOverflow(i64, a, b, &res)); - try expect(res == -0x7ffffffffffffffe); + var ov = @mulWithOverflow(a, b); + try expect(ov[0] == -0x7ffffffffffffffe); + try expect(ov[1] == 0); b = -0x2aaaaaaaaaaaaaab; - try expect(@mulWithOverflow(i64, a, b, &res)); - try expect(res == 0x7fffffffffffffff); + ov = @mulWithOverflow(a, b); + try expect(ov[0] == 0x7fffffffffffffff); + try expect(ov[1] == 1); } } test "@subWithOverflow" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO { - var result: u8 = undefined; - try expect(@subWithOverflow(u8, 1, 2, &result)); - try expect(result == 255); - try expect(!@subWithOverflow(u8, 1, 1, &result)); - try expect(result == 0); + var a: u8 = 1; + const ov = @subWithOverflow(a, 2); + try expect(ov[0] == 255); + try expect(ov[1] == 1); + } + { + var a: u8 = 1; + const ov = @subWithOverflow(a, 1); + try expect(ov[0] == 0); + try expect(ov[1] == 0); + } + { var a: u8 = 1; var b: u8 = 2; - try expect(@subWithOverflow(u8, a, b, &result)); - try expect(result == 255); + var ov = @subWithOverflow(a, b); + try expect(ov[0] == 255); + try expect(ov[1] == 1); b = 1; - try expect(!@subWithOverflow(u8, a, b, &result)); - try expect(result == 0); + ov = @subWithOverflow(a, b); + try expect(ov[0] == 0); + try expect(ov[1] == 0); } { var a: usize = 6; var b: usize = 6; - var res: usize = undefined; - try expect(!@subWithOverflow(usize, a, b, &res)); - try expect(res == 0); + const ov = @subWithOverflow(a, b); + try expect(ov[0] == 0); + try expect(ov[1] == 0); } { var a: isize = -6; var b: isize = -6; - var res: isize = undefined; - try expect(!@subWithOverflow(isize, a, b, &res)); - try expect(res == 0); + const ov = @subWithOverflow(a, b); + try expect(ov[0] == 0); + try expect(ov[1] == 0); } } test "@shlWithOverflow" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO { - var result: u4 = undefined; var a: u4 = 2; var b: u2 = 1; - try expect(!@shlWithOverflow(u4, a, b, &result)); - try expect(result == 4); + var ov = @shlWithOverflow(a, b); + try expect(ov[0] == 4); + try expect(ov[1] == 0); b = 3; - try expect(@shlWithOverflow(u4, a, b, &result)); - try expect(result == 0); + ov = @shlWithOverflow(a, b); + try expect(ov[0] == 0); + try expect(ov[1] == 1); } { - var result: i9 = undefined; var a: i9 = 127; var b: u4 = 1; - try expect(!@shlWithOverflow(i9, a, b, &result)); - try expect(result == 254); + var ov = @shlWithOverflow(a, b); + try expect(ov[0] == 254); + try expect(ov[1] == 0); b = 2; - try expect(@shlWithOverflow(i9, a, b, &result)); - try expect(result == -4); + ov = @shlWithOverflow(a, b); + try expect(ov[0] == -4); + try expect(ov[1] == 1); } { - var result: u16 = undefined; - try expect(@shlWithOverflow(u16, 0b0010111111111111, 3, &result)); - try expect(result == 0b0111111111111000); - try expect(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result)); - try expect(result == 0b1011111111111100); - + const ov = @shlWithOverflow(@as(u16, 0b0010111111111111), 3); + try expect(ov[0] == 0b0111111111111000); + try expect(ov[1] == 1); + } + { + const ov = @shlWithOverflow(@as(u16, 0b0010111111111111), 2); + try expect(ov[0] == 0b1011111111111100); + try expect(ov[1] == 0); + } + { var a: u16 = 0b0000_0000_0000_0011; var b: u4 = 15; - try expect(@shlWithOverflow(u16, a, b, &result)); - try expect(result == 0b1000_0000_0000_0000); + var ov = @shlWithOverflow(a, b); + try expect(ov[0] == 0b1000_0000_0000_0000); + try expect(ov[1] == 1); b = 14; - try expect(!@shlWithOverflow(u16, a, b, &result)); - try expect(result == 0b1100_0000_0000_0000); + ov = @shlWithOverflow(a, b); + try expect(ov[0] == 0b1100_0000_0000_0000); + try expect(ov[1] == 0); } } test "overflow arithmetic with u0 values" { - var result: u0 = undefined; - try expect(!@addWithOverflow(u0, 0, 0, &result)); - try expect(result == 0); - try expect(!@subWithOverflow(u0, 0, 0, &result)); - try expect(result == 0); - try expect(!@mulWithOverflow(u0, 0, 0, &result)); - try expect(result == 0); - try expect(!@shlWithOverflow(u0, 0, 0, &result)); - try expect(result == 0); + { + var a: u0 = 0; + const ov = @addWithOverflow(a, 0); + try expect(ov[1] == 0); + try expect(ov[1] == 0); + } + { + var a: u0 = 0; + const ov = @subWithOverflow(a, 0); + try expect(ov[1] == 0); + try expect(ov[1] == 0); + } + { + var a: u0 = 0; + const ov = @mulWithOverflow(a, 0); + try expect(ov[1] == 0); + try expect(ov[1] == 0); + } + { + var a: u0 = 0; + const ov = @shlWithOverflow(a, 0); + try expect(ov[1] == 0); + try expect(ov[1] == 0); + } } test "allow signed integer division/remainder when values are comptime-known and positive or exact" { diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig index 7a441a925d42..cf23430f4fed 100644 --- a/test/behavior/vector.zig +++ b/test/behavior/vector.zig @@ -963,35 +963,31 @@ test "@addWithOverflow" { const S = struct { fn doTheTest() !void { { - var result: @Vector(4, u8) = undefined; var lhs = @Vector(4, u8){ 250, 250, 250, 250 }; var rhs = @Vector(4, u8){ 0, 5, 6, 10 }; - var overflow = @addWithOverflow(@Vector(4, u8), lhs, rhs, &result); - var expected: @Vector(4, bool) = .{ false, false, true, true }; + var overflow = @addWithOverflow(lhs, rhs)[1]; + var expected: @Vector(4, u1) = .{ 0, 0, 1, 1 }; try expectEqual(expected, overflow); } { - var result: @Vector(4, i8) = undefined; var lhs = @Vector(4, i8){ -125, -125, 125, 125 }; var rhs = @Vector(4, i8){ -3, -4, 2, 3 }; - var overflow = @addWithOverflow(@Vector(4, i8), lhs, rhs, &result); - var expected: @Vector(4, bool) = .{ false, true, false, true }; + var overflow = @addWithOverflow(lhs, rhs)[1]; + var expected: @Vector(4, u1) = .{ 0, 1, 0, 1 }; try expectEqual(expected, overflow); } { - var result: @Vector(4, u1) = undefined; var lhs = @Vector(4, u1){ 0, 0, 1, 1 }; var rhs = @Vector(4, u1){ 0, 1, 0, 1 }; - var overflow = @addWithOverflow(@Vector(4, u1), lhs, rhs, &result); - var expected: @Vector(4, bool) = .{ false, false, false, true }; + var overflow = @addWithOverflow(lhs, rhs)[1]; + var expected: @Vector(4, u1) = .{ 0, 0, 0, 1 }; try expectEqual(expected, overflow); } { - var result: @Vector(4, u0) = undefined; var lhs = @Vector(4, u0){ 0, 0, 0, 0 }; var rhs = @Vector(4, u0){ 0, 0, 0, 0 }; - var overflow = @addWithOverflow(@Vector(4, u0), lhs, rhs, &result); - var expected: @Vector(4, bool) = .{ false, false, false, false }; + var overflow = @addWithOverflow(lhs, rhs)[1]; + var expected: @Vector(4, u1) = .{ 0, 0, 0, 0 }; try expectEqual(expected, overflow); } } @@ -1010,19 +1006,17 @@ test "@subWithOverflow" { const S = struct { fn doTheTest() !void { { - var result: @Vector(2, u8) = undefined; var lhs = @Vector(2, u8){ 5, 5 }; var rhs = @Vector(2, u8){ 5, 6 }; - var overflow = @subWithOverflow(@Vector(2, u8), lhs, rhs, &result); - var expected: @Vector(2, bool) = .{ false, true }; + var overflow = @subWithOverflow(lhs, rhs)[1]; + var expected: @Vector(2, u1) = .{ 0, 1 }; try expectEqual(expected, overflow); } { - var result: @Vector(4, i8) = undefined; var lhs = @Vector(4, i8){ -120, -120, 120, 120 }; var rhs = @Vector(4, i8){ 8, 9, -7, -8 }; - var overflow = @subWithOverflow(@Vector(4, i8), lhs, rhs, &result); - var expected: @Vector(4, bool) = .{ false, true, false, true }; + var overflow = @subWithOverflow(lhs, rhs)[1]; + var expected: @Vector(4, u1) = .{ 0, 1, 0, 1 }; try expectEqual(expected, overflow); } } @@ -1040,11 +1034,10 @@ test "@mulWithOverflow" { const S = struct { fn doTheTest() !void { - var result: @Vector(4, u8) = undefined; var lhs = @Vector(4, u8){ 10, 10, 10, 10 }; var rhs = @Vector(4, u8){ 25, 26, 0, 30 }; - var overflow = @mulWithOverflow(@Vector(4, u8), lhs, rhs, &result); - var expected: @Vector(4, bool) = .{ false, true, false, true }; + var overflow = @mulWithOverflow(lhs, rhs)[1]; + var expected: @Vector(4, u1) = .{ 0, 1, 0, 1 }; try expectEqual(expected, overflow); } }; @@ -1062,11 +1055,10 @@ test "@shlWithOverflow" { const S = struct { fn doTheTest() !void { - var result: @Vector(4, u8) = undefined; var lhs = @Vector(4, u8){ 0, 1, 8, 255 }; var rhs = @Vector(4, u3){ 7, 7, 7, 7 }; - var overflow = @shlWithOverflow(@Vector(4, u8), lhs, rhs, &result); - var expected: @Vector(4, bool) = .{ false, false, true, true }; + var overflow = @shlWithOverflow(lhs, rhs)[1]; + var expected: @Vector(4, u1) = .{ 0, 0, 1, 1 }; try expectEqual(expected, overflow); } }; @@ -1136,8 +1128,19 @@ test "byte vector initialized in inline function" { } test "byte vector initialized in inline function" { - // TODO https://github.com/ziglang/zig/issues/13279 - if (true) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + + if (comptime builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and + builtin.cpu.features.isEnabled(@enumToInt(std.Target.x86.Feature.avx512f))) + { + // TODO https://github.com/ziglang/zig/issues/13279 + return error.SkipZigTest; + } const S = struct { fn boolx4(e0: bool, e1: bool, e2: bool, e3: bool) @Vector(4, bool) {