update uses of overflow arithmetic builtins

This commit is contained in:
Veikka Tuominen 2022-12-21 16:40:30 +02:00
parent 54160e7f6a
commit 622311fb9a
29 changed files with 568 additions and 435 deletions

View file

@ -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" {
</p>
{#header_close#}
{#header_open|@addWithOverflow#}
<pre>{#syntax#}@addWithOverflow(comptime T: type, a: T, b: T, result: *T) bool{#endsyntax#}</pre>
<pre>{#syntax#}@addWithOverflow(a: anytype, b: anytype) struct { @TypeOf(a, b), u1 }{#endsyntax#}</pre>
<p>
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.
</p>
{#header_close#}
{#header_open|@alignCast#}
@ -8695,11 +8695,9 @@ test "@wasmMemoryGrow" {
{#header_close#}
{#header_open|@mulWithOverflow#}
<pre>{#syntax#}@mulWithOverflow(comptime T: type, a: T, b: T, result: *T) bool{#endsyntax#}</pre>
<pre>{#syntax#}@mulWithOverflow(a: anytype, b: anytype) struct { @TypeOf(a, b), u1 }{#endsyntax#}</pre>
<p>
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.
</p>
{#header_close#}
@ -8973,15 +8971,13 @@ test "@setRuntimeSafety" {
{#header_close#}
{#header_open|@shlWithOverflow#}
<pre>{#syntax#}@shlWithOverflow(comptime T: type, a: T, shift_amt: Log2T, result: *T) bool{#endsyntax#}</pre>
<pre>{#syntax#}@shlWithOverflow(a: anytype, shift_amt: Log2T) struct { @TypeOf(a), u1 }{#endsyntax#}</pre>
<p>
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.
</p>
<p>
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.
</p>
{#see_also|@shlExact|@shrExact#}
{#header_close#}
@ -9323,11 +9319,9 @@ fn doTheTest() !void {
{#header_close#}
{#header_open|@subWithOverflow#}
<pre>{#syntax#}@subWithOverflow(comptime T: type, a: T, b: T, result: *T) bool{#endsyntax#}</pre>
<pre>{#syntax#}@subWithOverflow(a: anytype, b: anytype) struct { @TypeOf(a, b), u1 }{#endsyntax#}</pre>
<p>
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.
</p>
{#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#}

View file

@ -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
}

View file

@ -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);
}

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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);

View file

@ -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);

View file

@ -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));

View file

@ -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) {

View file

@ -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.

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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;

View file

@ -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];
}
},
},
}

View file

@ -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.

View file

@ -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 } };

View file

@ -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 {

View file

@ -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 {

View file

@ -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

View file

@ -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 {

View file

@ -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);
}

View file

@ -534,6 +534,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));
@ -634,42 +635,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;
@ -684,180 +696,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
@ -865,140 +903,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" {

View file

@ -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);
}
};