mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
update uses of overflow arithmetic builtins
This commit is contained in:
parent
54160e7f6a
commit
622311fb9a
29 changed files with 568 additions and 435 deletions
|
|
@ -5413,14 +5413,14 @@ pub fn parseU64(buf: []const u8, radix: u8) !u64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// x *= radix
|
// x *= radix
|
||||||
if (@mulWithOverflow(u64, x, radix, &x)) {
|
var ov = @mulWithOverflow(x, radix);
|
||||||
return error.Overflow;
|
if (ov[1] != 0) return error.OverFlow;
|
||||||
}
|
|
||||||
|
|
||||||
// x += digit
|
// x += digit
|
||||||
if (@addWithOverflow(u64, x, digit, &x)) {
|
ov = @addWithOverflow(ov[0], digit);
|
||||||
return error.Overflow;
|
if (ov[1] != 0) return error.OverFlow;
|
||||||
}
|
x = ov[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
return x;
|
return x;
|
||||||
|
|
@ -5832,14 +5832,16 @@ test "merge error sets" {
|
||||||
{#code_begin|test|inferred_error_sets#}
|
{#code_begin|test|inferred_error_sets#}
|
||||||
// With an inferred error set
|
// With an inferred error set
|
||||||
pub fn add_inferred(comptime T: type, a: T, b: T) !T {
|
pub fn add_inferred(comptime T: type, a: T, b: T) !T {
|
||||||
var answer: T = undefined;
|
const ov = @addWithOverflow(a, b);
|
||||||
return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
|
if (ov[1] != 0) return error.Overflow;
|
||||||
|
return ov[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// With an explicit error set
|
// With an explicit error set
|
||||||
pub fn add_explicit(comptime T: type, a: T, b: T) Error!T {
|
pub fn add_explicit(comptime T: type, a: T, b: T) Error!T {
|
||||||
var answer: T = undefined;
|
const ov = @addWithOverflow(a, b);
|
||||||
return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
|
if (ov[1] != 0) return error.Overflow;
|
||||||
|
return ov[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
const Error = error {
|
const Error = error {
|
||||||
|
|
@ -7632,11 +7634,9 @@ test "global assembly" {
|
||||||
</p>
|
</p>
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
{#header_open|@addWithOverflow#}
|
{#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>
|
<p>
|
||||||
Performs {#syntax#}result.* = a + b{#endsyntax#}. If overflow or underflow occurs,
|
Performs {#syntax#}a + b{#endsyntax#} and returns a tuple with the result and a possible overflow bit.
|
||||||
stores the overflowed bits in {#syntax#}result{#endsyntax#} and returns {#syntax#}true{#endsyntax#}.
|
|
||||||
If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.
|
|
||||||
</p>
|
</p>
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
{#header_open|@alignCast#}
|
{#header_open|@alignCast#}
|
||||||
|
|
@ -8695,11 +8695,9 @@ test "@wasmMemoryGrow" {
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|
||||||
{#header_open|@mulWithOverflow#}
|
{#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>
|
<p>
|
||||||
Performs {#syntax#}result.* = a * b{#endsyntax#}. If overflow or underflow occurs,
|
Performs {#syntax#}a * b{#endsyntax#} and returns a tuple with the result and a possible overflow bit.
|
||||||
stores the overflowed bits in {#syntax#}result{#endsyntax#} and returns {#syntax#}true{#endsyntax#}.
|
|
||||||
If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.
|
|
||||||
</p>
|
</p>
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|
||||||
|
|
@ -8973,15 +8971,13 @@ test "@setRuntimeSafety" {
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|
||||||
{#header_open|@shlWithOverflow#}
|
{#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>
|
<p>
|
||||||
Performs {#syntax#}result.* = a << b{#endsyntax#}. If overflow or underflow occurs,
|
Performs {#syntax#}a << b{#endsyntax#} and returns a tuple with the result and a possible overflow bit.
|
||||||
stores the overflowed bits in {#syntax#}result{#endsyntax#} and returns {#syntax#}true{#endsyntax#}.
|
|
||||||
If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(@typeInfo(T).Int.bits){#endsyntax#} bits.
|
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(T).Int.bits{#endsyntax#} is undefined behavior.
|
This is because {#syntax#}shift_amt >= @typeInfo(@TypeOf(a)).Int.bits{#endsyntax#} is undefined behavior.
|
||||||
</p>
|
</p>
|
||||||
{#see_also|@shlExact|@shrExact#}
|
{#see_also|@shlExact|@shrExact#}
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|
@ -9323,11 +9319,9 @@ fn doTheTest() !void {
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|
||||||
{#header_open|@subWithOverflow#}
|
{#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>
|
<p>
|
||||||
Performs {#syntax#}result.* = a - b{#endsyntax#}. If overflow or underflow occurs,
|
Performs {#syntax#}a - b{#endsyntax#} and returns a tuple with the result and a possible overflow bit.
|
||||||
stores the overflowed bits in {#syntax#}result{#endsyntax#} and returns {#syntax#}true{#endsyntax#}.
|
|
||||||
If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.
|
|
||||||
</p>
|
</p>
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|
||||||
|
|
@ -9774,11 +9768,11 @@ const print = @import("std").debug.print;
|
||||||
pub fn main() void {
|
pub fn main() void {
|
||||||
var byte: u8 = 255;
|
var byte: u8 = 255;
|
||||||
|
|
||||||
var result: u8 = undefined;
|
const ov = @addWithOverflow(byte, 10);
|
||||||
if (@addWithOverflow(u8, byte, 10, &result)) {
|
if (ov[1] != 0) {
|
||||||
print("overflowed result: {}\n", .{result});
|
print("overflowed result: {}\n", .{ov[0]});
|
||||||
} else {
|
} else {
|
||||||
print("result: {}\n", .{result});
|
print("result: {}\n", .{ov[0]});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{#code_end#}
|
{#code_end#}
|
||||||
|
|
|
||||||
|
|
@ -49,14 +49,16 @@ pub fn __trunctfxf2(a: f128) callconv(.C) f80 {
|
||||||
const round_bits = a_abs & round_mask;
|
const round_bits = a_abs & round_mask;
|
||||||
if (round_bits > halfway) {
|
if (round_bits > halfway) {
|
||||||
// Round to nearest
|
// Round to nearest
|
||||||
const carry = @boolToInt(@addWithOverflow(u64, res.fraction, 1, &res.fraction));
|
const ov = @addWithOverflow(res.fraction, 1);
|
||||||
res.exp += carry;
|
res.fraction = ov[0];
|
||||||
res.fraction |= @as(u64, carry) << 63; // Restore integer bit after carry
|
res.exp += ov[1];
|
||||||
|
res.fraction |= @as(u64, ov[1]) << 63; // Restore integer bit after carry
|
||||||
} else if (round_bits == halfway) {
|
} else if (round_bits == halfway) {
|
||||||
// Ties to even
|
// Ties to even
|
||||||
const carry = @boolToInt(@addWithOverflow(u64, res.fraction, res.fraction & 1, &res.fraction));
|
const ov = @addWithOverflow(res.fraction, res.fraction & 1);
|
||||||
res.exp += carry;
|
res.fraction = ov[0];
|
||||||
res.fraction |= @as(u64, carry) << 63; // Restore integer bit after carry
|
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
|
if (res.exp == 0) res.fraction &= ~@as(u64, integer_bit); // Remove integer bit for de-normals
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -172,9 +172,7 @@ test "deflate/inflate" {
|
||||||
defer testing.allocator.free(large_data_chunk);
|
defer testing.allocator.free(large_data_chunk);
|
||||||
// fill with random data
|
// fill with random data
|
||||||
for (large_data_chunk) |_, i| {
|
for (large_data_chunk) |_, i| {
|
||||||
var mul: u8 = @truncate(u8, i);
|
large_data_chunk[i] = @truncate(u8, i) *% @truncate(u8, i);
|
||||||
_ = @mulWithOverflow(u8, mul, mul, &mul);
|
|
||||||
large_data_chunk[i] = mul;
|
|
||||||
}
|
}
|
||||||
try testToFromWithLimit(large_data_chunk, limits);
|
try testToFromWithLimit(large_data_chunk, limits);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,10 +75,10 @@ pub const NonMontgomeryDomainFieldElement = [4]u64;
|
||||||
inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
|
inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
|
||||||
@setRuntimeSafety(mode == .Debug);
|
@setRuntimeSafety(mode == .Debug);
|
||||||
|
|
||||||
var t: u64 = undefined;
|
const ov1 = @addWithOverflow(arg2, arg3);
|
||||||
const carry1 = @addWithOverflow(u64, arg2, arg3, &t);
|
const ov2 = @addWithOverflow(ov1[0], arg1);
|
||||||
const carry2 = @addWithOverflow(u64, t, arg1, out1);
|
out1.* = ov2[0];
|
||||||
out2.* = @boolToInt(carry1) | @boolToInt(carry2);
|
out2.* = ov1[1] | ov2[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The function subborrowxU64 is a subtraction with borrow.
|
/// 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 {
|
inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
|
||||||
@setRuntimeSafety(mode == .Debug);
|
@setRuntimeSafety(mode == .Debug);
|
||||||
|
|
||||||
var t: u64 = undefined;
|
const ov1 = @subWithOverflow(arg2, arg3);
|
||||||
const carry1 = @subWithOverflow(u64, arg2, arg3, &t);
|
const ov2 = @subWithOverflow(ov1[0], arg1);
|
||||||
const carry2 = @subWithOverflow(u64, t, arg1, out1);
|
out1.* = ov2[0];
|
||||||
out2.* = @boolToInt(carry1) | @boolToInt(carry2);
|
out2.* = ov1[1] | ov2[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The function mulxU64 is a multiplication, returning the full double-width result.
|
/// The function mulxU64 is a multiplication, returning the full double-width result.
|
||||||
|
|
|
||||||
|
|
@ -75,10 +75,10 @@ pub const NonMontgomeryDomainFieldElement = [4]u64;
|
||||||
inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
|
inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
|
||||||
@setRuntimeSafety(mode == .Debug);
|
@setRuntimeSafety(mode == .Debug);
|
||||||
|
|
||||||
var t: u64 = undefined;
|
const ov1 = @addWithOverflow(arg2, arg3);
|
||||||
const carry1 = @addWithOverflow(u64, arg2, arg3, &t);
|
const ov2 = @addWithOverflow(ov1[0], arg1);
|
||||||
const carry2 = @addWithOverflow(u64, t, arg1, out1);
|
out1.* = ov2[0];
|
||||||
out2.* = @boolToInt(carry1) | @boolToInt(carry2);
|
out2.* = ov1[1] | ov2[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The function subborrowxU64 is a subtraction with borrow.
|
/// 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 {
|
inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
|
||||||
@setRuntimeSafety(mode == .Debug);
|
@setRuntimeSafety(mode == .Debug);
|
||||||
|
|
||||||
var t: u64 = undefined;
|
const ov1 = @subWithOverflow(arg2, arg3);
|
||||||
const carry1 = @subWithOverflow(u64, arg2, arg3, &t);
|
const ov2 = @subWithOverflow(ov1[0], arg1);
|
||||||
const carry2 = @subWithOverflow(u64, t, arg1, out1);
|
out1.* = ov2[0];
|
||||||
out2.* = @boolToInt(carry1) | @boolToInt(carry2);
|
out2.* = ov1[1] | ov2[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The function mulxU64 is a multiplication, returning the full double-width result.
|
/// The function mulxU64 is a multiplication, returning the full double-width result.
|
||||||
|
|
|
||||||
|
|
@ -44,10 +44,10 @@ pub const NonMontgomeryDomainFieldElement = [6]u64;
|
||||||
inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
|
inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
|
||||||
@setRuntimeSafety(mode == .Debug);
|
@setRuntimeSafety(mode == .Debug);
|
||||||
|
|
||||||
var t: u64 = undefined;
|
const ov1 = @addWithOverflow(arg2, arg3);
|
||||||
const carry1 = @addWithOverflow(u64, arg2, arg3, &t);
|
const ov2 = @addWithOverflow(ov1[0], arg1);
|
||||||
const carry2 = @addWithOverflow(u64, t, arg1, out1);
|
out1.* = ov2[0];
|
||||||
out2.* = @boolToInt(carry1) | @boolToInt(carry2);
|
out2.* = ov1[1] | ov2[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The function subborrowxU64 is a subtraction with borrow.
|
/// 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 {
|
inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
|
||||||
@setRuntimeSafety(mode == .Debug);
|
@setRuntimeSafety(mode == .Debug);
|
||||||
|
|
||||||
var t: u64 = undefined;
|
const ov1 = @subWithOverflow(arg2, arg3);
|
||||||
const carry1 = @subWithOverflow(u64, arg2, arg3, &t);
|
const ov2 = @subWithOverflow(ov1[0], arg1);
|
||||||
const carry2 = @subWithOverflow(u64, t, arg1, out1);
|
out1.* = ov2[0];
|
||||||
out2.* = @boolToInt(carry1) | @boolToInt(carry2);
|
out2.* = ov1[1] | ov2[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The function mulxU64 is a multiplication, returning the full double-width result.
|
/// The function mulxU64 is a multiplication, returning the full double-width result.
|
||||||
|
|
|
||||||
|
|
@ -44,10 +44,10 @@ pub const NonMontgomeryDomainFieldElement = [6]u64;
|
||||||
inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
|
inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
|
||||||
@setRuntimeSafety(mode == .Debug);
|
@setRuntimeSafety(mode == .Debug);
|
||||||
|
|
||||||
var t: u64 = undefined;
|
const ov1 = @addWithOverflow(arg2, arg3);
|
||||||
const carry1 = @addWithOverflow(u64, arg2, arg3, &t);
|
const ov2 = @addWithOverflow(ov1[0], arg1);
|
||||||
const carry2 = @addWithOverflow(u64, t, arg1, out1);
|
out1.* = ov2[0];
|
||||||
out2.* = @boolToInt(carry1) | @boolToInt(carry2);
|
out2.* = ov1[1] | ov2[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The function subborrowxU64 is a subtraction with borrow.
|
/// 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 {
|
inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
|
||||||
@setRuntimeSafety(mode == .Debug);
|
@setRuntimeSafety(mode == .Debug);
|
||||||
|
|
||||||
var t: u64 = undefined;
|
const ov1 = @subWithOverflow(arg2, arg3);
|
||||||
const carry1 = @subWithOverflow(u64, arg2, arg3, &t);
|
const ov2 = @subWithOverflow(ov1[0], arg1);
|
||||||
const carry2 = @subWithOverflow(u64, t, arg1, out1);
|
out1.* = ov2[0];
|
||||||
out2.* = @boolToInt(carry1) | @boolToInt(carry2);
|
out2.* = ov1[1] | ov2[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The function mulxU64 is a multiplication, returning the full double-width result.
|
/// The function mulxU64 is a multiplication, returning the full double-width result.
|
||||||
|
|
|
||||||
|
|
@ -44,10 +44,10 @@ pub const NonMontgomeryDomainFieldElement = [4]u64;
|
||||||
inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
|
inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
|
||||||
@setRuntimeSafety(mode == .Debug);
|
@setRuntimeSafety(mode == .Debug);
|
||||||
|
|
||||||
var t: u64 = undefined;
|
const ov1 = @addWithOverflow(arg2, arg3);
|
||||||
const carry1 = @addWithOverflow(u64, arg2, arg3, &t);
|
const ov2 = @addWithOverflow(ov1[0], arg1);
|
||||||
const carry2 = @addWithOverflow(u64, t, arg1, out1);
|
out1.* = ov2[0];
|
||||||
out2.* = @boolToInt(carry1) | @boolToInt(carry2);
|
out2.* = ov1[1] | ov2[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The function subborrowxU64 is a subtraction with borrow.
|
/// 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 {
|
inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
|
||||||
@setRuntimeSafety(mode == .Debug);
|
@setRuntimeSafety(mode == .Debug);
|
||||||
|
|
||||||
var t: u64 = undefined;
|
const ov1 = @subWithOverflow(arg2, arg3);
|
||||||
const carry1 = @subWithOverflow(u64, arg2, arg3, &t);
|
const ov2 = @subWithOverflow(ov1[0], arg1);
|
||||||
const carry2 = @subWithOverflow(u64, t, arg1, out1);
|
out1.* = ov2[0];
|
||||||
out2.* = @boolToInt(carry1) | @boolToInt(carry2);
|
out2.* = ov1[1] | ov2[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The function mulxU64 is a multiplication, returning the full double-width result.
|
/// The function mulxU64 is a multiplication, returning the full double-width result.
|
||||||
|
|
|
||||||
|
|
@ -44,10 +44,10 @@ pub const NonMontgomeryDomainFieldElement = [4]u64;
|
||||||
inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
|
inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
|
||||||
@setRuntimeSafety(mode == .Debug);
|
@setRuntimeSafety(mode == .Debug);
|
||||||
|
|
||||||
var t: u64 = undefined;
|
const ov1 = @addWithOverflow(arg2, arg3);
|
||||||
const carry1 = @addWithOverflow(u64, arg2, arg3, &t);
|
const ov2 = @addWithOverflow(ov1[0], arg1);
|
||||||
const carry2 = @addWithOverflow(u64, t, arg1, out1);
|
out1.* = ov2[0];
|
||||||
out2.* = @boolToInt(carry1) | @boolToInt(carry2);
|
out2.* = ov1[1] | ov2[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The function subborrowxU64 is a subtraction with borrow.
|
/// 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 {
|
inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
|
||||||
@setRuntimeSafety(mode == .Debug);
|
@setRuntimeSafety(mode == .Debug);
|
||||||
|
|
||||||
var t: u64 = undefined;
|
const ov1 = @subWithOverflow(arg2, arg3);
|
||||||
const carry1 = @subWithOverflow(u64, arg2, arg3, &t);
|
const ov2 = @subWithOverflow(ov1[0], arg1);
|
||||||
const carry2 = @subWithOverflow(u64, t, arg1, out1);
|
out1.* = ov2[0];
|
||||||
out2.* = @boolToInt(carry1) | @boolToInt(carry2);
|
out2.* = ov1[1] | ov2[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The function mulxU64 is a multiplication, returning the full double-width result.
|
/// The function mulxU64 is a multiplication, returning the full double-width result.
|
||||||
|
|
|
||||||
|
|
@ -263,7 +263,9 @@ fn SalsaNonVecImpl(comptime rounds: comptime_int) type {
|
||||||
while (j < 64) : (j += 1) {
|
while (j < 64) : (j += 1) {
|
||||||
xout[j] ^= buf[j];
|
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) {
|
if (i < in.len) {
|
||||||
salsaCore(x[0..], ctx, true);
|
salsaCore(x[0..], ctx, true);
|
||||||
|
|
|
||||||
|
|
@ -87,15 +87,19 @@ pub fn timingSafeAdd(comptime T: type, a: []const T, b: []const T, result: []T,
|
||||||
if (endian == .Little) {
|
if (endian == .Little) {
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (i < len) : (i += 1) {
|
while (i < len) : (i += 1) {
|
||||||
const tmp = @boolToInt(@addWithOverflow(u8, a[i], b[i], &result[i]));
|
const ov1 = @addWithOverflow(a[i], b[i]);
|
||||||
carry = tmp | @boolToInt(@addWithOverflow(u8, result[i], carry, &result[i]));
|
const ov2 = @addWithOverflow(ov1[0], carry);
|
||||||
|
result[i] = ov2[0];
|
||||||
|
carry = ov1[1] | ov2[1];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var i: usize = len;
|
var i: usize = len;
|
||||||
while (i != 0) {
|
while (i != 0) {
|
||||||
i -= 1;
|
i -= 1;
|
||||||
const tmp = @boolToInt(@addWithOverflow(u8, a[i], b[i], &result[i]));
|
const ov1 = @addWithOverflow(a[i], b[i]);
|
||||||
carry = tmp | @boolToInt(@addWithOverflow(u8, result[i], carry, &result[i]));
|
const ov2 = @addWithOverflow(ov1[0], carry);
|
||||||
|
result[i] = ov2[0];
|
||||||
|
carry = ov1[1] | ov2[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return @bitCast(bool, carry);
|
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) {
|
if (endian == .Little) {
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (i < len) : (i += 1) {
|
while (i < len) : (i += 1) {
|
||||||
const tmp = @boolToInt(@subWithOverflow(u8, a[i], b[i], &result[i]));
|
const ov1 = @subWithOverflow(a[i], b[i]);
|
||||||
borrow = tmp | @boolToInt(@subWithOverflow(u8, result[i], borrow, &result[i]));
|
const ov2 = @subWithOverflow(ov1[0], borrow);
|
||||||
|
result[i] = ov2[0];
|
||||||
|
borrow = ov1[1] | ov2[1];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var i: usize = len;
|
var i: usize = len;
|
||||||
while (i != 0) {
|
while (i != 0) {
|
||||||
i -= 1;
|
i -= 1;
|
||||||
const tmp = @boolToInt(@subWithOverflow(u8, a[i], b[i], &result[i]));
|
const ov1 = @subWithOverflow(a[i], b[i]);
|
||||||
borrow = tmp | @boolToInt(@subWithOverflow(u8, result[i], borrow, &result[i]));
|
const ov2 = @subWithOverflow(ov1[0], borrow);
|
||||||
|
result[i] = ov2[0];
|
||||||
|
borrow = ov1[1] | ov2[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return @bitCast(bool, borrow);
|
return @bitCast(bool, borrow);
|
||||||
|
|
|
||||||
|
|
@ -789,7 +789,7 @@ pub fn testAllocatorLargeAlignment(base_allocator: mem.Allocator) !void {
|
||||||
const large_align: usize = mem.page_size / 2;
|
const large_align: usize = mem.page_size / 2;
|
||||||
|
|
||||||
var align_mask: usize = undefined;
|
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);
|
var slice = try allocator.alignedAlloc(u8, large_align, 500);
|
||||||
try testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
|
try testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,11 @@ pub fn readULEB128(comptime T: type, reader: anytype) !T {
|
||||||
|
|
||||||
while (group < max_group) : (group += 1) {
|
while (group < max_group) : (group += 1) {
|
||||||
const byte = try reader.readByte();
|
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;
|
if (byte & 0x80 == 0) break;
|
||||||
} else {
|
} else {
|
||||||
return error.Overflow;
|
return error.Overflow;
|
||||||
|
|
@ -65,13 +65,13 @@ pub fn readILEB128(comptime T: type, reader: anytype) !T {
|
||||||
|
|
||||||
while (group < max_group) : (group += 1) {
|
while (group < max_group) : (group += 1) {
|
||||||
const byte = try reader.readByte();
|
const byte = try reader.readByte();
|
||||||
var temp = @as(U, byte & 0x7f);
|
|
||||||
|
|
||||||
const shift = group * 7;
|
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
|
// 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 (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
|
// and all the overflowed bits are 1
|
||||||
const remaining_shift = @intCast(u3, @typeInfo(U).Int.bits - @as(u16, shift));
|
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 {
|
} else {
|
||||||
// If we don't overflow and this is the last byte and the number being decoded
|
// 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
|
// 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_shift = @intCast(u3, @typeInfo(U).Int.bits - @as(u16, shift));
|
||||||
const remaining_bits = @bitCast(i8, byte | 0x80) >> remaining_shift;
|
const remaining_bits = @bitCast(i8, byte | 0x80) >> remaining_shift;
|
||||||
if (remaining_bits != -1) return error.Overflow;
|
if (remaining_bits != -1) return error.Overflow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
value |= temp;
|
value |= ov[0];
|
||||||
if (byte & 0x80 == 0) {
|
if (byte & 0x80 == 0) {
|
||||||
const needs_sign_ext = group + 1 < max_group;
|
const needs_sign_ext = group + 1 < max_group;
|
||||||
if (byte & 0x40 != 0 and needs_sign_ext) {
|
if (byte & 0x40 != 0 and needs_sign_ext) {
|
||||||
|
|
|
||||||
|
|
@ -468,21 +468,26 @@ test "clamp" {
|
||||||
|
|
||||||
/// Returns the product of a and b. Returns an error on overflow.
|
/// 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) {
|
pub fn mul(comptime T: type, a: T, b: T) (error{Overflow}!T) {
|
||||||
var answer: T = undefined;
|
if (T == comptime_int) return a * b;
|
||||||
return if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer;
|
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.
|
/// 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) {
|
pub fn add(comptime T: type, a: T, b: T) (error{Overflow}!T) {
|
||||||
if (T == comptime_int) return a + b;
|
if (T == comptime_int) return a + b;
|
||||||
var answer: T = undefined;
|
const ov = @addWithOverflow(a, b);
|
||||||
return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
|
if (ov[1] != 0) return error.Overflow;
|
||||||
|
return ov[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a - b, or an error on overflow.
|
/// Returns a - b, or an error on overflow.
|
||||||
pub fn sub(comptime T: type, a: T, b: T) (error{Overflow}!T) {
|
pub fn sub(comptime T: type, a: T, b: T) (error{Overflow}!T) {
|
||||||
var answer: T = undefined;
|
if (T == comptime_int) return a - b;
|
||||||
return if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer;
|
const ov = @subWithOverflow(a, b);
|
||||||
|
if (ov[1] != 0) return error.Overflow;
|
||||||
|
return ov[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn negate(x: anytype) !@TypeOf(x) {
|
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
|
/// Shifts a left by shift_amt. Returns an error on overflow. shift_amt
|
||||||
/// is unsigned.
|
/// is unsigned.
|
||||||
pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T {
|
pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T {
|
||||||
var answer: T = undefined;
|
if (T == comptime_int) return a << shift_amt;
|
||||||
return if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer;
|
const ov = @shlWithOverflow(a, shift_amt);
|
||||||
|
if (ov[1] != 0) return error.Overflow;
|
||||||
|
return ov[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shifts left. Overflowed bits are truncated.
|
/// Shifts left. Overflowed bits are truncated.
|
||||||
|
|
|
||||||
|
|
@ -74,42 +74,40 @@ pub fn calcTwosCompLimbCount(bit_count: usize) usize {
|
||||||
/// a + b * c + *carry, sets carry to the overflow bits
|
/// a + b * c + *carry, sets carry to the overflow bits
|
||||||
pub fn addMulLimbWithCarry(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb {
|
pub fn addMulLimbWithCarry(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb {
|
||||||
@setRuntimeSafety(debug_safety);
|
@setRuntimeSafety(debug_safety);
|
||||||
var r1: Limb = undefined;
|
|
||||||
|
|
||||||
// r1 = a + *carry
|
// ov1[0] = a + *carry
|
||||||
const c1: Limb = @boolToInt(@addWithOverflow(Limb, a, carry.*, &r1));
|
const ov1 = @addWithOverflow(a, carry.*);
|
||||||
|
|
||||||
// r2 = b * c
|
// r2 = b * c
|
||||||
const bc = @as(DoubleLimb, math.mulWide(Limb, b, c));
|
const bc = @as(DoubleLimb, math.mulWide(Limb, b, c));
|
||||||
const r2 = @truncate(Limb, bc);
|
const r2 = @truncate(Limb, bc);
|
||||||
const c2 = @truncate(Limb, bc >> limb_bits);
|
const c2 = @truncate(Limb, bc >> limb_bits);
|
||||||
|
|
||||||
// r1 = r1 + r2
|
// ov2[0] = ov1[0] + r2
|
||||||
const c3: Limb = @boolToInt(@addWithOverflow(Limb, r1, r2, &r1));
|
const ov2 = @addWithOverflow(ov1[0], r2);
|
||||||
|
|
||||||
// This never overflows, c1, c3 are either 0 or 1 and if both are 1 then
|
// This never overflows, c1, c3 are either 0 or 1 and if both are 1 then
|
||||||
// c2 is at least <= maxInt(Limb) - 2.
|
// 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
|
/// a - b * c - *carry, sets carry to the overflow bits
|
||||||
fn subMulLimbWithBorrow(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb {
|
fn subMulLimbWithBorrow(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb {
|
||||||
// r1 = a - *carry
|
// ov1[0] = a - *carry
|
||||||
var r1: Limb = undefined;
|
const ov1 = @subWithOverflow(a, carry.*);
|
||||||
const c1: Limb = @boolToInt(@subWithOverflow(Limb, a, carry.*, &r1));
|
|
||||||
|
|
||||||
// r2 = b * c
|
// r2 = b * c
|
||||||
const bc = @as(DoubleLimb, std.math.mulWide(Limb, b, c));
|
const bc = @as(DoubleLimb, std.math.mulWide(Limb, b, c));
|
||||||
const r2 = @truncate(Limb, bc);
|
const r2 = @truncate(Limb, bc);
|
||||||
const c2 = @truncate(Limb, bc >> limb_bits);
|
const c2 = @truncate(Limb, bc >> limb_bits);
|
||||||
|
|
||||||
// r1 = r1 - r2
|
// ov2[0] = ov1[0] - r2
|
||||||
const c3: Limb = @boolToInt(@subWithOverflow(Limb, r1, r2, &r1));
|
const ov2 = @subWithOverflow(ov1[0], r2);
|
||||||
carry.* = c1 + c2 + c3;
|
carry.* = ov1[1] + c2 + ov2[1];
|
||||||
|
|
||||||
return r1;
|
return ov2[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used to indicate either limit of a 2s-complement integer.
|
/// 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
|
assert(rma.limbs.ptr != b.limbs.ptr); // illegal aliasing
|
||||||
|
|
||||||
if (a.limbs.len == 1 and b.limbs.len == 1) {
|
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.len = 1;
|
||||||
rma.positive = (a.positive == b.positive);
|
rma.positive = (a.positive == b.positive);
|
||||||
return;
|
return;
|
||||||
|
|
@ -1836,7 +1836,11 @@ pub const Mutable = struct {
|
||||||
bit_index += @bitSizeOf(Limb);
|
bit_index += @bitSizeOf(Limb);
|
||||||
|
|
||||||
// 2's complement (bitwise not, then add carry bit)
|
// 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;
|
x.limbs[limb_index] = limb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1853,7 +1857,11 @@ pub const Mutable = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
// 2's complement (bitwise not, then add carry bit)
|
// 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;
|
x.limbs[limb_index] = limb;
|
||||||
|
|
||||||
limb_index += 1;
|
limb_index += 1;
|
||||||
|
|
@ -2000,7 +2008,9 @@ pub const Const = struct {
|
||||||
|
|
||||||
// All but the most significant limb.
|
// All but the most significant limb.
|
||||||
for (self.limbs[0 .. self.limbs.len - 1]) |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);
|
sum += @popCount(add_res);
|
||||||
remaining_bits -= limb_bits; // Asserted not to undeflow by fitsInTwosComp
|
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;
|
var limb: Limb = if (limb_index < x.limbs.len) x.limbs[limb_index] else 0;
|
||||||
|
|
||||||
// 2's complement (bitwise not, then add carry bit)
|
// 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
|
// Write one Limb of bits
|
||||||
mem.writePackedInt(Limb, bytes, bit_index + bit_offset, limb, endian);
|
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;
|
var limb: Limb = if (limb_index < x.limbs.len) x.limbs[limb_index] else 0;
|
||||||
|
|
||||||
// 2's complement (bitwise not, then add carry bit)
|
// 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
|
// Write all remaining bits
|
||||||
mem.writeVarPackedInt(bytes, bit_index + bit_offset, bit_count - bit_index, limb, endian);
|
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;
|
var carry: Limb = 0;
|
||||||
|
|
||||||
while (i < a.len) : (i += 1) {
|
while (i < a.len) : (i += 1) {
|
||||||
var c: Limb = 0;
|
const ov1 = @addWithOverflow(r[i], a[i]);
|
||||||
c += @boolToInt(@addWithOverflow(Limb, r[i], a[i], &r[i]));
|
r[i] = ov1[0];
|
||||||
c += @boolToInt(@addWithOverflow(Limb, r[i], carry, &r[i]));
|
const ov2 = @addWithOverflow(r[i], carry);
|
||||||
carry = c;
|
r[i] = ov2[0];
|
||||||
|
carry = @as(Limb, ov1[1]) + ov2[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((carry != 0) and i < r.len) : (i += 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;
|
j = 0;
|
||||||
while ((carry != 0) and (j < a_hi.len)) : (j += 1) {
|
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;
|
return carry != 0;
|
||||||
|
|
@ -3449,7 +3468,9 @@ fn llmulLimb(comptime op: AccOp, acc: []Limb, y: []const Limb, xi: Limb) bool {
|
||||||
|
|
||||||
j = 0;
|
j = 0;
|
||||||
while ((borrow != 0) and (j < a_hi.len)) : (j += 1) {
|
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;
|
return borrow != 0;
|
||||||
|
|
@ -3482,14 +3503,17 @@ fn llsubcarry(r: []Limb, a: []const Limb, b: []const Limb) Limb {
|
||||||
var borrow: Limb = 0;
|
var borrow: Limb = 0;
|
||||||
|
|
||||||
while (i < b.len) : (i += 1) {
|
while (i < b.len) : (i += 1) {
|
||||||
var c: Limb = 0;
|
const ov1 = @subWithOverflow(a[i], b[i]);
|
||||||
c += @boolToInt(@subWithOverflow(Limb, a[i], b[i], &r[i]));
|
r[i] = ov1[0];
|
||||||
c += @boolToInt(@subWithOverflow(Limb, r[i], borrow, &r[i]));
|
const ov2 = @subWithOverflow(r[i], borrow);
|
||||||
borrow = c;
|
r[i] = ov2[0];
|
||||||
|
borrow = @as(Limb, ov1[1]) + ov2[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
while (i < a.len) : (i += 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;
|
return borrow;
|
||||||
|
|
@ -3512,14 +3536,17 @@ fn lladdcarry(r: []Limb, a: []const Limb, b: []const Limb) Limb {
|
||||||
var carry: Limb = 0;
|
var carry: Limb = 0;
|
||||||
|
|
||||||
while (i < b.len) : (i += 1) {
|
while (i < b.len) : (i += 1) {
|
||||||
var c: Limb = 0;
|
const ov1 = @addWithOverflow(a[i], b[i]);
|
||||||
c += @boolToInt(@addWithOverflow(Limb, a[i], b[i], &r[i]));
|
r[i] = ov1[0];
|
||||||
c += @boolToInt(@addWithOverflow(Limb, r[i], carry, &r[i]));
|
const ov2 = @addWithOverflow(r[i], carry);
|
||||||
carry = c;
|
r[i] = ov2[0];
|
||||||
|
carry = @as(Limb, ov1[1]) + ov2[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
while (i < a.len) : (i += 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;
|
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;
|
var r_carry: u1 = 1;
|
||||||
|
|
||||||
while (i < b.len) : (i += 1) {
|
while (i < b.len) : (i += 1) {
|
||||||
var a_limb: Limb = undefined;
|
const ov1 = @subWithOverflow(a[i], a_borrow);
|
||||||
a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &a_limb));
|
a_borrow = ov1[1];
|
||||||
|
const ov2 = @addWithOverflow(ov1[0] & ~b[i], r_carry);
|
||||||
r[i] = a_limb & ~b[i];
|
r[i] = ov2[0];
|
||||||
r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i]));
|
r_carry = ov2[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
// In order for r_carry to be nonzero at this point, ~b[i] would need to be
|
// 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
|
// Note, if a_borrow is zero we do not need to compute anything for
|
||||||
// the higher limbs so we can early return here.
|
// the higher limbs so we can early return here.
|
||||||
while (i < a.len and a_borrow == 1) : (i += 1) {
|
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.
|
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;
|
var r_carry: u1 = 1;
|
||||||
|
|
||||||
while (i < b.len) : (i += 1) {
|
while (i < b.len) : (i += 1) {
|
||||||
var b_limb: Limb = undefined;
|
const ov1 = @subWithOverflow(b[i], b_borrow);
|
||||||
b_borrow = @boolToInt(@subWithOverflow(Limb, b[i], b_borrow, &b_limb));
|
b_borrow = ov1[1];
|
||||||
|
const ov2 = @addWithOverflow(~a[i] & ov1[0], r_carry);
|
||||||
r[i] = ~a[i] & b_limb;
|
r[i] = ov2[0];
|
||||||
r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i]));
|
r_carry = ov2[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
// b is at least 1, so this should never underflow.
|
// 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;
|
var r_carry: u1 = 1;
|
||||||
|
|
||||||
while (i < b.len) : (i += 1) {
|
while (i < b.len) : (i += 1) {
|
||||||
var a_limb: Limb = undefined;
|
const ov1 = @subWithOverflow(a[i], a_borrow);
|
||||||
a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &a_limb));
|
a_borrow = ov1[1];
|
||||||
|
const ov2 = @subWithOverflow(b[i], b_borrow);
|
||||||
var b_limb: Limb = undefined;
|
b_borrow = ov2[1];
|
||||||
b_borrow = @boolToInt(@subWithOverflow(Limb, b[i], b_borrow, &b_limb));
|
const ov3 = @addWithOverflow(ov1[0] & ov2[0], r_carry);
|
||||||
|
r[i] = ov3[0];
|
||||||
r[i] = a_limb & b_limb;
|
r_carry = ov3[1];
|
||||||
r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// b is at least 1, so this should never underflow.
|
// 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;
|
var a_borrow: u1 = 1;
|
||||||
|
|
||||||
while (i < b.len) : (i += 1) {
|
while (i < b.len) : (i += 1) {
|
||||||
var a_limb: Limb = undefined;
|
const ov = @subWithOverflow(a[i], a_borrow);
|
||||||
a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &a_limb));
|
a_borrow = ov[1];
|
||||||
r[i] = ~a_limb & b[i];
|
r[i] = ~ov[0] & b[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
// With b = 0 we have ~(a - 1) & 0 = 0, so the upper bytes are zero.
|
// 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;
|
var b_borrow: u1 = 1;
|
||||||
|
|
||||||
while (i < b.len) : (i += 1) {
|
while (i < b.len) : (i += 1) {
|
||||||
var a_limb: Limb = undefined;
|
const ov = @subWithOverflow(b[i], b_borrow);
|
||||||
b_borrow = @boolToInt(@subWithOverflow(Limb, b[i], b_borrow, &a_limb));
|
b_borrow = ov[1];
|
||||||
r[i] = a[i] & ~a_limb;
|
r[i] = a[i] & ~ov[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(b_borrow == 0); // b was 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;
|
var r_carry: u1 = 1;
|
||||||
|
|
||||||
while (i < b.len) : (i += 1) {
|
while (i < b.len) : (i += 1) {
|
||||||
var a_limb: Limb = undefined;
|
const ov1 = @subWithOverflow(a[i], a_borrow);
|
||||||
a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &a_limb));
|
a_borrow = ov1[1];
|
||||||
|
const ov2 = @subWithOverflow(b[i], b_borrow);
|
||||||
var b_limb: Limb = undefined;
|
b_borrow = ov2[1];
|
||||||
b_borrow = @boolToInt(@subWithOverflow(Limb, b[i], b_borrow, &b_limb));
|
const ov3 = @addWithOverflow(ov1[0] | ov2[0], r_carry);
|
||||||
|
r[i] = ov3[0];
|
||||||
r[i] = a_limb | b_limb;
|
r_carry = ov3[1];
|
||||||
r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// b is at least 1, so this should never underflow.
|
// 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.
|
// With b = 0 and b_borrow = 0 we get (-a - 1) | (-0 - 0) = (-a - 1) | 0 = -a - 1.
|
||||||
while (i < a.len) : (i += 1) {
|
while (i < a.len) : (i += 1) {
|
||||||
a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &r[i]));
|
const ov1 = @subWithOverflow(a[i], a_borrow);
|
||||||
r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i]));
|
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.
|
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);
|
var r_carry = @boolToInt(a_positive != b_positive);
|
||||||
|
|
||||||
while (i < b.len) : (i += 1) {
|
while (i < b.len) : (i += 1) {
|
||||||
var a_limb: Limb = undefined;
|
const ov1 = @subWithOverflow(a[i], a_borrow);
|
||||||
a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &a_limb));
|
a_borrow = ov1[1];
|
||||||
|
const ov2 = @subWithOverflow(b[i], b_borrow);
|
||||||
var b_limb: Limb = undefined;
|
b_borrow = ov2[1];
|
||||||
b_borrow = @boolToInt(@subWithOverflow(Limb, b[i], b_borrow, &b_limb));
|
const ov3 = @addWithOverflow(ov1[0] ^ ov2[0], r_carry);
|
||||||
|
r[i] = ov3[0];
|
||||||
r[i] = a_limb ^ b_limb;
|
r_carry = ov3[1];
|
||||||
r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (i < a.len) : (i += 1) {
|
while (i < a.len) : (i += 1) {
|
||||||
a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &r[i]));
|
const ov1 = @subWithOverflow(a[i], a_borrow);
|
||||||
r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i]));
|
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.
|
// 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)]);
|
llsquareBasecase(tmp2, tmp1[0..llnormalize(tmp1)]);
|
||||||
mem.swap([]Limb, &tmp1, &tmp2);
|
mem.swap([]Limb, &tmp1, &tmp2);
|
||||||
// Multiply by a
|
// 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);
|
mem.set(Limb, tmp2, 0);
|
||||||
llmulacc(.add, null, tmp2, tmp1[0..llnormalize(tmp1)], a);
|
llmulacc(.add, null, tmp2, tmp1[0..llnormalize(tmp1)], a);
|
||||||
mem.swap([]Limb, &tmp1, &tmp2);
|
mem.swap([]Limb, &tmp1, &tmp2);
|
||||||
|
|
|
||||||
|
|
@ -70,22 +70,22 @@ pub fn powi(comptime T: type, x: T, y: T) (error{
|
||||||
|
|
||||||
while (exp > 1) {
|
while (exp > 1) {
|
||||||
if (exp & 1 == 1) {
|
if (exp & 1 == 1) {
|
||||||
if (@mulWithOverflow(T, acc, base, &acc)) {
|
const ov = @mulWithOverflow(acc, base);
|
||||||
return error.Overflow;
|
if (ov[1] != 0) return error.Overflow;
|
||||||
}
|
acc = ov[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
exp >>= 1;
|
exp >>= 1;
|
||||||
|
|
||||||
if (@mulWithOverflow(T, base, base, &base)) {
|
const ov = @mulWithOverflow(base, base);
|
||||||
return error.Overflow;
|
if (ov[1] != 0) return error.Overflow;
|
||||||
}
|
base = ov[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exp == 1) {
|
if (exp == 1) {
|
||||||
if (@mulWithOverflow(T, acc, base, &acc)) {
|
const ov = @mulWithOverflow(acc, base);
|
||||||
return error.Overflow;
|
if (ov[1] != 0) return error.Overflow;
|
||||||
}
|
acc = ov[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
|
|
|
||||||
|
|
@ -3304,13 +3304,13 @@ pub fn alignPointerOffset(ptr: anytype, align_to: usize) ?usize {
|
||||||
|
|
||||||
// Calculate the aligned base address with an eye out for overflow.
|
// Calculate the aligned base address with an eye out for overflow.
|
||||||
const addr = @ptrToInt(ptr);
|
const addr = @ptrToInt(ptr);
|
||||||
var new_addr: usize = undefined;
|
var ov = @addWithOverflow(addr, align_to - 1);
|
||||||
if (@addWithOverflow(usize, addr, align_to - 1, &new_addr)) return null;
|
if (ov[1] != 0) return null;
|
||||||
new_addr &= ~@as(usize, align_to - 1);
|
ov[0] &= ~@as(usize, align_to - 1);
|
||||||
|
|
||||||
// The delta is expressed in terms of bytes, turn it into a number of child
|
// The delta is expressed in terms of bytes, turn it into a number of child
|
||||||
// type elements.
|
// type elements.
|
||||||
const delta = new_addr - addr;
|
const delta = ov[0] - addr;
|
||||||
const pointee_size = @sizeOf(info.Pointer.child);
|
const pointee_size = @sizeOf(info.Pointer.child);
|
||||||
if (delta % pointee_size != 0) return null;
|
if (delta % pointee_size != 0) return null;
|
||||||
return delta / pointee_size;
|
return delta / pointee_size;
|
||||||
|
|
|
||||||
|
|
@ -321,11 +321,15 @@ pub const Ip6Address = extern struct {
|
||||||
if (scope_id) {
|
if (scope_id) {
|
||||||
if (c >= '0' and c <= '9') {
|
if (c >= '0' and c <= '9') {
|
||||||
const digit = c - '0';
|
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 {
|
} else {
|
||||||
return error.InvalidCharacter;
|
return error.InvalidCharacter;
|
||||||
|
|
@ -377,11 +381,15 @@ pub const Ip6Address = extern struct {
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
const digit = try std.fmt.charToDigit(c, 16);
|
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;
|
saw_any_digits = true;
|
||||||
}
|
}
|
||||||
|
|
@ -492,11 +500,15 @@ pub const Ip6Address = extern struct {
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
const digit = try std.fmt.charToDigit(c, 16);
|
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;
|
saw_any_digits = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1244,7 +1244,7 @@ pub fn sendmmsg(fd: i32, msgvec: [*]mmsghdr_const, vlen: u32, flags: u32) usize
|
||||||
var size: i32 = 0;
|
var size: i32 = 0;
|
||||||
const msg_iovlen = @intCast(usize, msg.msg_hdr.msg_iovlen); // kernel side this is treated as unsigned
|
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| {
|
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
|
// batch-send all messages up to the current message
|
||||||
if (next_unsent < i) {
|
if (next_unsent < i) {
|
||||||
const batch_size = i - next_unsent;
|
const batch_size = i - next_unsent;
|
||||||
|
|
|
||||||
|
|
@ -1023,8 +1023,16 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {
|
||||||
'0'...'9' => byte - '0',
|
'0'...'9' => byte - '0',
|
||||||
else => return error.CorruptPasswordFile,
|
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) {
|
.ReadGroupId => switch (byte) {
|
||||||
|
|
@ -1039,8 +1047,16 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {
|
||||||
'0'...'9' => byte - '0',
|
'0'...'9' => byte - '0',
|
||||||
else => return error.CorruptPasswordFile,
|
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];
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -246,7 +246,9 @@ pub inline fn __builtin_constant_p(expr: anytype) c_int {
|
||||||
return @boolToInt(false);
|
return @boolToInt(false);
|
||||||
}
|
}
|
||||||
pub fn __builtin_mul_overflow(a: anytype, b: anytype, result: *@TypeOf(a, b)) c_int {
|
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.
|
// __builtin_alloca_with_align is not currently implemented.
|
||||||
|
|
|
||||||
|
|
@ -151,12 +151,14 @@ pub fn parseNumberLiteral(bytes: []const u8) Result {
|
||||||
special = 0;
|
special = 0;
|
||||||
|
|
||||||
if (float) continue;
|
if (float) continue;
|
||||||
if (x != 0) if (@mulWithOverflow(u64, x, base, &x)) {
|
if (x != 0) {
|
||||||
overflow = true;
|
const res = @mulWithOverflow(x, base);
|
||||||
};
|
if (res[1] != 0) overflow = true;
|
||||||
if (@addWithOverflow(u64, x, digit, &x)) {
|
x = res[0];
|
||||||
overflow = true;
|
|
||||||
}
|
}
|
||||||
|
const res = @addWithOverflow(x, digit);
|
||||||
|
if (res[1] != 0) overflow = true;
|
||||||
|
x = res[0];
|
||||||
}
|
}
|
||||||
if (underscore) return .{ .failure = .{ .trailing_underscore = bytes.len - 1 } };
|
if (underscore) return .{ .failure = .{ .trailing_underscore = bytes.len - 1 } };
|
||||||
if (special != 0) return .{ .failure = .{ .trailing_special = bytes.len - 1 } };
|
if (special != 0) return .{ .failure = .{ .trailing_special = bytes.len - 1 } };
|
||||||
|
|
|
||||||
|
|
@ -1860,9 +1860,7 @@ fn writeHeader(self: *Coff) !void {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
|
pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
|
||||||
// TODO https://github.com/ziglang/zig/issues/1284
|
return actual_size +| (actual_size / ideal_factor);
|
||||||
return math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch
|
|
||||||
math.maxInt(@TypeOf(actual_size));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 {
|
fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 {
|
||||||
|
|
|
||||||
|
|
@ -2445,9 +2445,7 @@ fn makeString(self: *Dwarf, bytes: []const u8) !u32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
|
fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
|
||||||
// TODO https://github.com/ziglang/zig/issues/1284
|
return actual_size +| (actual_size / ideal_factor);
|
||||||
return std.math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch
|
|
||||||
std.math.maxInt(@TypeOf(actual_size));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn flushModule(self: *Dwarf, module: *Module) !void {
|
pub fn flushModule(self: *Dwarf, module: *Module) !void {
|
||||||
|
|
|
||||||
|
|
@ -3032,9 +3032,7 @@ fn getLDMOption(target: std.Target) ?[]const u8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
|
fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
|
||||||
// TODO https://github.com/ziglang/zig/issues/1284
|
return actual_size +| (actual_size / ideal_factor);
|
||||||
return std.math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch
|
|
||||||
std.math.maxInt(@TypeOf(actual_size));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provide a blueprint of csu (c-runtime startup) objects for supported
|
// Provide a blueprint of csu (c-runtime startup) objects for supported
|
||||||
|
|
|
||||||
|
|
@ -3772,9 +3772,7 @@ fn writeHeader(self: *MachO, ncmds: u32, sizeofcmds: u32) !void {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
|
pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
|
||||||
// TODO https://github.com/ziglang/zig/issues/1284
|
return actual_size +| (actual_size / ideal_factor);
|
||||||
return std.math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch
|
|
||||||
std.math.maxInt(@TypeOf(actual_size));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 {
|
fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 {
|
||||||
|
|
|
||||||
|
|
@ -489,18 +489,11 @@ test "comptime bitwise operators" {
|
||||||
|
|
||||||
test "comptime shlWithOverflow" {
|
test "comptime shlWithOverflow" {
|
||||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
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: {
|
const ct_shifted = @shlWithOverflow(~@as(u64, 0), 16)[0];
|
||||||
var amt = @as(u64, 0);
|
var a = ~@as(u64, 0);
|
||||||
_ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt);
|
const rt_shifted = @shlWithOverflow(a, 16)[0];
|
||||||
break :amt amt;
|
|
||||||
};
|
|
||||||
|
|
||||||
const rt_shifted: u64 = amt: {
|
|
||||||
var amt = @as(u64, 0);
|
|
||||||
_ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt);
|
|
||||||
break :amt amt;
|
|
||||||
};
|
|
||||||
|
|
||||||
try expect(ct_shifted == rt_shifted);
|
try expect(ct_shifted == rt_shifted);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -534,6 +534,7 @@ fn testUnsignedNegationWrappingEval(x: u16) !void {
|
||||||
|
|
||||||
test "negation wrapping" {
|
test "negation wrapping" {
|
||||||
if (builtin.zig_backend == .stage2_aarch64) 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_x86_64) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||||
|
|
||||||
try expectEqual(@as(u1, 1), negateWrap(u1, 1));
|
try expectEqual(@as(u1, 1), negateWrap(u1, 1));
|
||||||
|
|
@ -634,42 +635,53 @@ test "128-bit multiplication" {
|
||||||
}
|
}
|
||||||
|
|
||||||
test "@addWithOverflow" {
|
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
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||||
|
|
||||||
{
|
{
|
||||||
var result: u8 = undefined;
|
var a: u8 = 250;
|
||||||
try expect(@addWithOverflow(u8, 250, 100, &result));
|
const ov = @addWithOverflow(a, 100);
|
||||||
try expect(result == 94);
|
try expect(ov[0] == 94);
|
||||||
try expect(!@addWithOverflow(u8, 100, 150, &result));
|
try expect(ov[1] == 1);
|
||||||
try expect(result == 250);
|
}
|
||||||
|
{
|
||||||
|
var a: u8 = 100;
|
||||||
|
const ov = @addWithOverflow(a, 150);
|
||||||
|
try expect(ov[0] == 250);
|
||||||
|
try expect(ov[1] == 0);
|
||||||
|
}
|
||||||
|
{
|
||||||
var a: u8 = 200;
|
var a: u8 = 200;
|
||||||
var b: u8 = 99;
|
var b: u8 = 99;
|
||||||
try expect(@addWithOverflow(u8, a, b, &result));
|
var ov = @addWithOverflow(a, b);
|
||||||
try expect(result == 43);
|
try expect(ov[0] == 43);
|
||||||
|
try expect(ov[1] == 1);
|
||||||
b = 55;
|
b = 55;
|
||||||
try expect(!@addWithOverflow(u8, a, b, &result));
|
ov = @addWithOverflow(a, b);
|
||||||
try expect(result == 255);
|
try expect(ov[0] == 255);
|
||||||
|
try expect(ov[1] == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var a: usize = 6;
|
var a: usize = 6;
|
||||||
var b: usize = 6;
|
var b: usize = 6;
|
||||||
var res: usize = undefined;
|
const ov = @addWithOverflow(a, b);
|
||||||
try expect(!@addWithOverflow(usize, a, b, &res));
|
try expect(ov[0] == 12);
|
||||||
try expect(res == 12);
|
try expect(ov[1] == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var a: isize = -6;
|
var a: isize = -6;
|
||||||
var b: isize = -6;
|
var b: isize = -6;
|
||||||
var res: isize = undefined;
|
const ov = @addWithOverflow(a, b);
|
||||||
try expect(!@addWithOverflow(isize, a, b, &res));
|
try expect(ov[0] == -12);
|
||||||
try expect(res == -12);
|
try expect(ov[1] == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "small int addition" {
|
test "small int addition" {
|
||||||
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||||
|
|
||||||
var x: u2 = 0;
|
var x: u2 = 0;
|
||||||
|
|
@ -684,180 +696,206 @@ test "small int addition" {
|
||||||
x += 1;
|
x += 1;
|
||||||
try expect(x == 3);
|
try expect(x == 3);
|
||||||
|
|
||||||
var result: @TypeOf(x) = 3;
|
const ov = @addWithOverflow(x, 1);
|
||||||
try expect(@addWithOverflow(@TypeOf(x), x, 1, &result));
|
try expect(ov[0] == 0);
|
||||||
|
try expect(ov[1] == 1);
|
||||||
try expect(result == 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test "basic @mulWithOverflow" {
|
test "basic @mulWithOverflow" {
|
||||||
var result: u8 = undefined;
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||||
try expect(@mulWithOverflow(u8, 86, 3, &result));
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||||
try expect(result == 2);
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||||
try expect(!@mulWithOverflow(u8, 85, 3, &result));
|
|
||||||
try expect(result == 255);
|
{
|
||||||
|
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 a: u8 = 123;
|
||||||
var b: u8 = 2;
|
var b: u8 = 2;
|
||||||
try expect(!@mulWithOverflow(u8, a, b, &result));
|
var ov = @mulWithOverflow(a, b);
|
||||||
try expect(result == 246);
|
try expect(ov[0] == 246);
|
||||||
|
try expect(ov[1] == 0);
|
||||||
|
|
||||||
b = 4;
|
b = 4;
|
||||||
try expect(@mulWithOverflow(u8, a, b, &result));
|
ov = @mulWithOverflow(a, b);
|
||||||
try expect(result == 236);
|
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" {
|
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_arm) return error.SkipZigTest; // TODO
|
||||||
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||||
|
|
||||||
{
|
{
|
||||||
var a: u5 = 3;
|
var a: u5 = 3;
|
||||||
var b: u5 = 10;
|
var b: u5 = 10;
|
||||||
var res: u5 = undefined;
|
var ov = @mulWithOverflow(a, b);
|
||||||
try expect(!@mulWithOverflow(u5, a, b, &res));
|
try expect(ov[0] == 30);
|
||||||
try expect(res == 30);
|
try expect(ov[1] == 0);
|
||||||
|
|
||||||
b = 11;
|
b = 11;
|
||||||
try expect(@mulWithOverflow(u5, a, b, &res));
|
ov = @mulWithOverflow(a, b);
|
||||||
try expect(res == 1);
|
try expect(ov[0] == 1);
|
||||||
|
try expect(ov[1] == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var a: i5 = 3;
|
var a: i5 = 3;
|
||||||
var b: i5 = -5;
|
var b: i5 = -5;
|
||||||
var res: i5 = undefined;
|
var ov = @mulWithOverflow(a, b);
|
||||||
try expect(!@mulWithOverflow(i5, a, b, &res));
|
try expect(ov[0] == -15);
|
||||||
try expect(res == -15);
|
try expect(ov[1] == 0);
|
||||||
|
|
||||||
b = -6;
|
b = -6;
|
||||||
try expect(@mulWithOverflow(i5, a, b, &res));
|
ov = @mulWithOverflow(a, b);
|
||||||
try expect(res == 14);
|
try expect(ov[0] == 14);
|
||||||
|
try expect(ov[1] == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var a: u8 = 3;
|
var a: u8 = 3;
|
||||||
var b: u8 = 85;
|
var b: u8 = 85;
|
||||||
var res: u8 = undefined;
|
|
||||||
|
|
||||||
try expect(!@mulWithOverflow(u8, a, b, &res));
|
var ov = @mulWithOverflow(a, b);
|
||||||
try expect(res == 255);
|
try expect(ov[0] == 255);
|
||||||
|
try expect(ov[1] == 0);
|
||||||
|
|
||||||
b = 86;
|
b = 86;
|
||||||
try expect(@mulWithOverflow(u8, a, b, &res));
|
ov = @mulWithOverflow(a, b);
|
||||||
try expect(res == 2);
|
try expect(ov[0] == 2);
|
||||||
|
try expect(ov[1] == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var a: i8 = 3;
|
var a: i8 = 3;
|
||||||
var b: i8 = -42;
|
var b: i8 = -42;
|
||||||
var res: i8 = undefined;
|
var ov = @mulWithOverflow(a, b);
|
||||||
try expect(!@mulWithOverflow(i8, a, b, &res));
|
try expect(ov[0] == -126);
|
||||||
try expect(res == -126);
|
try expect(ov[1] == 0);
|
||||||
|
|
||||||
b = -43;
|
b = -43;
|
||||||
try expect(@mulWithOverflow(i8, a, b, &res));
|
ov = @mulWithOverflow(a, b);
|
||||||
try expect(res == 127);
|
try expect(ov[0] == 127);
|
||||||
|
try expect(ov[1] == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var a: u14 = 3;
|
var a: u14 = 3;
|
||||||
var b: u14 = 0x1555;
|
var b: u14 = 0x1555;
|
||||||
var res: u14 = undefined;
|
var ov = @mulWithOverflow(a, b);
|
||||||
try expect(!@mulWithOverflow(u14, a, b, &res));
|
try expect(ov[0] == 0x3fff);
|
||||||
try expect(res == 0x3fff);
|
try expect(ov[1] == 0);
|
||||||
|
|
||||||
b = 0x1556;
|
b = 0x1556;
|
||||||
try expect(@mulWithOverflow(u14, a, b, &res));
|
ov = @mulWithOverflow(a, b);
|
||||||
try expect(res == 2);
|
try expect(ov[0] == 2);
|
||||||
|
try expect(ov[1] == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var a: i14 = 3;
|
var a: i14 = 3;
|
||||||
var b: i14 = -0xaaa;
|
var b: i14 = -0xaaa;
|
||||||
var res: i14 = undefined;
|
var ov = @mulWithOverflow(a, b);
|
||||||
try expect(!@mulWithOverflow(i14, a, b, &res));
|
try expect(ov[0] == -0x1ffe);
|
||||||
try expect(res == -0x1ffe);
|
try expect(ov[1] == 0);
|
||||||
|
|
||||||
b = -0xaab;
|
b = -0xaab;
|
||||||
try expect(@mulWithOverflow(i14, a, b, &res));
|
ov = @mulWithOverflow(a, b);
|
||||||
try expect(res == 0x1fff);
|
try expect(ov[0] == 0x1fff);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var a: u16 = 3;
|
var a: u16 = 3;
|
||||||
var b: u16 = 0x5555;
|
var b: u16 = 0x5555;
|
||||||
var res: u16 = undefined;
|
var ov = @mulWithOverflow(a, b);
|
||||||
try expect(!@mulWithOverflow(u16, a, b, &res));
|
try expect(ov[0] == 0xffff);
|
||||||
try expect(res == 0xffff);
|
try expect(ov[1] == 0);
|
||||||
|
|
||||||
b = 0x5556;
|
b = 0x5556;
|
||||||
try expect(@mulWithOverflow(u16, a, b, &res));
|
ov = @mulWithOverflow(a, b);
|
||||||
try expect(res == 2);
|
try expect(ov[0] == 2);
|
||||||
|
try expect(ov[1] == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var a: i16 = 3;
|
var a: i16 = 3;
|
||||||
var b: i16 = -0x2aaa;
|
var b: i16 = -0x2aaa;
|
||||||
var res: i16 = undefined;
|
var ov = @mulWithOverflow(a, b);
|
||||||
try expect(!@mulWithOverflow(i16, a, b, &res));
|
try expect(ov[0] == -0x7ffe);
|
||||||
try expect(res == -0x7ffe);
|
try expect(ov[1] == 0);
|
||||||
|
|
||||||
b = -0x2aab;
|
b = -0x2aab;
|
||||||
try expect(@mulWithOverflow(i16, a, b, &res));
|
ov = @mulWithOverflow(a, b);
|
||||||
try expect(res == 0x7fff);
|
try expect(ov[0] == 0x7fff);
|
||||||
|
try expect(ov[1] == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var a: u30 = 3;
|
var a: u30 = 3;
|
||||||
var b: u30 = 0x15555555;
|
var b: u30 = 0x15555555;
|
||||||
var res: u30 = undefined;
|
var ov = @mulWithOverflow(a, b);
|
||||||
try expect(!@mulWithOverflow(u30, a, b, &res));
|
try expect(ov[0] == 0x3fffffff);
|
||||||
try expect(res == 0x3fffffff);
|
try expect(ov[1] == 0);
|
||||||
|
|
||||||
b = 0x15555556;
|
b = 0x15555556;
|
||||||
try expect(@mulWithOverflow(u30, a, b, &res));
|
ov = @mulWithOverflow(a, b);
|
||||||
try expect(res == 2);
|
try expect(ov[0] == 2);
|
||||||
|
try expect(ov[1] == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var a: i30 = 3;
|
var a: i30 = 3;
|
||||||
var b: i30 = -0xaaaaaaa;
|
var b: i30 = -0xaaaaaaa;
|
||||||
var res: i30 = undefined;
|
var ov = @mulWithOverflow(a, b);
|
||||||
try expect(!@mulWithOverflow(i30, a, b, &res));
|
try expect(ov[0] == -0x1ffffffe);
|
||||||
try expect(res == -0x1ffffffe);
|
try expect(ov[1] == 0);
|
||||||
|
|
||||||
b = -0xaaaaaab;
|
b = -0xaaaaaab;
|
||||||
try expect(@mulWithOverflow(i30, a, b, &res));
|
ov = @mulWithOverflow(a, b);
|
||||||
try expect(res == 0x1fffffff);
|
try expect(ov[0] == 0x1fffffff);
|
||||||
|
try expect(ov[1] == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var a: u32 = 3;
|
var a: u32 = 3;
|
||||||
var b: u32 = 0x55555555;
|
var b: u32 = 0x55555555;
|
||||||
var res: u32 = undefined;
|
var ov = @mulWithOverflow(a, b);
|
||||||
try expect(!@mulWithOverflow(u32, a, b, &res));
|
try expect(ov[0] == 0xffffffff);
|
||||||
try expect(res == 0xffffffff);
|
try expect(ov[1] == 0);
|
||||||
|
|
||||||
b = 0x55555556;
|
b = 0x55555556;
|
||||||
try expect(@mulWithOverflow(u32, a, b, &res));
|
ov = @mulWithOverflow(a, b);
|
||||||
try expect(res == 2);
|
try expect(ov[0] == 2);
|
||||||
|
try expect(ov[1] == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var a: i32 = 3;
|
var a: i32 = 3;
|
||||||
var b: i32 = -0x2aaaaaaa;
|
var b: i32 = -0x2aaaaaaa;
|
||||||
var res: i32 = undefined;
|
var ov = @mulWithOverflow(a, b);
|
||||||
try expect(!@mulWithOverflow(i32, a, b, &res));
|
try expect(ov[0] == -0x7ffffffe);
|
||||||
try expect(res == -0x7ffffffe);
|
try expect(ov[1] == 0);
|
||||||
|
|
||||||
b = -0x2aaaaaab;
|
b = -0x2aaaaaab;
|
||||||
try expect(@mulWithOverflow(i32, a, b, &res));
|
ov = @mulWithOverflow(a, b);
|
||||||
try expect(res == 0x7fffffff);
|
try expect(ov[0] == 0x7fffffff);
|
||||||
|
try expect(ov[1] == 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "@mulWithOverflow bitsize > 32" {
|
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_arm) return error.SkipZigTest; // TODO
|
||||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||||
if (builtin.zig_backend == .stage2_sparc64) 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 a: u62 = 3;
|
||||||
var b: u62 = 0x1555555555555555;
|
var b: u62 = 0x1555555555555555;
|
||||||
var res: u62 = undefined;
|
var ov = @mulWithOverflow(a, b);
|
||||||
try expect(!@mulWithOverflow(u62, a, b, &res));
|
try expect(ov[0] == 0x3fffffffffffffff);
|
||||||
try expect(res == 0x3fffffffffffffff);
|
try expect(ov[1] == 0);
|
||||||
|
|
||||||
b = 0x1555555555555556;
|
b = 0x1555555555555556;
|
||||||
try expect(@mulWithOverflow(u62, a, b, &res));
|
ov = @mulWithOverflow(a, b);
|
||||||
try expect(res == 2);
|
try expect(ov[0] == 2);
|
||||||
|
try expect(ov[1] == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var a: i62 = 3;
|
var a: i62 = 3;
|
||||||
var b: i62 = -0xaaaaaaaaaaaaaaa;
|
var b: i62 = -0xaaaaaaaaaaaaaaa;
|
||||||
var res: i62 = undefined;
|
var ov = @mulWithOverflow(a, b);
|
||||||
try expect(!@mulWithOverflow(i62, a, b, &res));
|
try expect(ov[0] == -0x1ffffffffffffffe);
|
||||||
try expect(res == -0x1ffffffffffffffe);
|
try expect(ov[1] == 0);
|
||||||
|
|
||||||
b = -0xaaaaaaaaaaaaaab;
|
b = -0xaaaaaaaaaaaaaab;
|
||||||
try expect(@mulWithOverflow(i62, a, b, &res));
|
ov = @mulWithOverflow(a, b);
|
||||||
try expect(res == 0x1fffffffffffffff);
|
try expect(ov[0] == 0x1fffffffffffffff);
|
||||||
|
try expect(ov[1] == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var a: u64 = 3;
|
var a: u64 = 3;
|
||||||
var b: u64 = 0x5555555555555555;
|
var b: u64 = 0x5555555555555555;
|
||||||
var res: u64 = undefined;
|
var ov = @mulWithOverflow(a, b);
|
||||||
try expect(!@mulWithOverflow(u64, a, b, &res));
|
try expect(ov[0] == 0xffffffffffffffff);
|
||||||
try expect(res == 0xffffffffffffffff);
|
try expect(ov[1] == 0);
|
||||||
|
|
||||||
b = 0x5555555555555556;
|
b = 0x5555555555555556;
|
||||||
try expect(@mulWithOverflow(u64, a, b, &res));
|
ov = @mulWithOverflow(a, b);
|
||||||
try expect(res == 2);
|
try expect(ov[0] == 2);
|
||||||
|
try expect(ov[1] == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var a: i64 = 3;
|
var a: i64 = 3;
|
||||||
var b: i64 = -0x2aaaaaaaaaaaaaaa;
|
var b: i64 = -0x2aaaaaaaaaaaaaaa;
|
||||||
var res: i64 = undefined;
|
var ov = @mulWithOverflow(a, b);
|
||||||
try expect(!@mulWithOverflow(i64, a, b, &res));
|
try expect(ov[0] == -0x7ffffffffffffffe);
|
||||||
try expect(res == -0x7ffffffffffffffe);
|
try expect(ov[1] == 0);
|
||||||
|
|
||||||
b = -0x2aaaaaaaaaaaaaab;
|
b = -0x2aaaaaaaaaaaaaab;
|
||||||
try expect(@mulWithOverflow(i64, a, b, &res));
|
ov = @mulWithOverflow(a, b);
|
||||||
try expect(res == 0x7fffffffffffffff);
|
try expect(ov[0] == 0x7fffffffffffffff);
|
||||||
|
try expect(ov[1] == 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "@subWithOverflow" {
|
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
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||||
|
|
||||||
{
|
{
|
||||||
var result: u8 = undefined;
|
var a: u8 = 1;
|
||||||
try expect(@subWithOverflow(u8, 1, 2, &result));
|
const ov = @subWithOverflow(a, 2);
|
||||||
try expect(result == 255);
|
try expect(ov[0] == 255);
|
||||||
try expect(!@subWithOverflow(u8, 1, 1, &result));
|
try expect(ov[1] == 1);
|
||||||
try expect(result == 0);
|
}
|
||||||
|
{
|
||||||
|
var a: u8 = 1;
|
||||||
|
const ov = @subWithOverflow(a, 1);
|
||||||
|
try expect(ov[0] == 0);
|
||||||
|
try expect(ov[1] == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
var a: u8 = 1;
|
var a: u8 = 1;
|
||||||
var b: u8 = 2;
|
var b: u8 = 2;
|
||||||
try expect(@subWithOverflow(u8, a, b, &result));
|
var ov = @subWithOverflow(a, b);
|
||||||
try expect(result == 255);
|
try expect(ov[0] == 255);
|
||||||
|
try expect(ov[1] == 1);
|
||||||
b = 1;
|
b = 1;
|
||||||
try expect(!@subWithOverflow(u8, a, b, &result));
|
ov = @subWithOverflow(a, b);
|
||||||
try expect(result == 0);
|
try expect(ov[0] == 0);
|
||||||
|
try expect(ov[1] == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var a: usize = 6;
|
var a: usize = 6;
|
||||||
var b: usize = 6;
|
var b: usize = 6;
|
||||||
var res: usize = undefined;
|
const ov = @subWithOverflow(a, b);
|
||||||
try expect(!@subWithOverflow(usize, a, b, &res));
|
try expect(ov[0] == 0);
|
||||||
try expect(res == 0);
|
try expect(ov[1] == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var a: isize = -6;
|
var a: isize = -6;
|
||||||
var b: isize = -6;
|
var b: isize = -6;
|
||||||
var res: isize = undefined;
|
const ov = @subWithOverflow(a, b);
|
||||||
try expect(!@subWithOverflow(isize, a, b, &res));
|
try expect(ov[0] == 0);
|
||||||
try expect(res == 0);
|
try expect(ov[1] == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "@shlWithOverflow" {
|
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 a: u4 = 2;
|
||||||
var b: u2 = 1;
|
var b: u2 = 1;
|
||||||
try expect(!@shlWithOverflow(u4, a, b, &result));
|
var ov = @shlWithOverflow(a, b);
|
||||||
try expect(result == 4);
|
try expect(ov[0] == 4);
|
||||||
|
try expect(ov[1] == 0);
|
||||||
|
|
||||||
b = 3;
|
b = 3;
|
||||||
try expect(@shlWithOverflow(u4, a, b, &result));
|
ov = @shlWithOverflow(a, b);
|
||||||
try expect(result == 0);
|
try expect(ov[0] == 0);
|
||||||
|
try expect(ov[1] == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var result: i9 = undefined;
|
|
||||||
var a: i9 = 127;
|
var a: i9 = 127;
|
||||||
var b: u4 = 1;
|
var b: u4 = 1;
|
||||||
try expect(!@shlWithOverflow(i9, a, b, &result));
|
var ov = @shlWithOverflow(a, b);
|
||||||
try expect(result == 254);
|
try expect(ov[0] == 254);
|
||||||
|
try expect(ov[1] == 0);
|
||||||
|
|
||||||
b = 2;
|
b = 2;
|
||||||
try expect(@shlWithOverflow(i9, a, b, &result));
|
ov = @shlWithOverflow(a, b);
|
||||||
try expect(result == -4);
|
try expect(ov[0] == -4);
|
||||||
|
try expect(ov[1] == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var result: u16 = undefined;
|
const ov = @shlWithOverflow(@as(u16, 0b0010111111111111), 3);
|
||||||
try expect(@shlWithOverflow(u16, 0b0010111111111111, 3, &result));
|
try expect(ov[0] == 0b0111111111111000);
|
||||||
try expect(result == 0b0111111111111000);
|
try expect(ov[1] == 1);
|
||||||
try expect(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result));
|
}
|
||||||
try expect(result == 0b1011111111111100);
|
{
|
||||||
|
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 a: u16 = 0b0000_0000_0000_0011;
|
||||||
var b: u4 = 15;
|
var b: u4 = 15;
|
||||||
try expect(@shlWithOverflow(u16, a, b, &result));
|
var ov = @shlWithOverflow(a, b);
|
||||||
try expect(result == 0b1000_0000_0000_0000);
|
try expect(ov[0] == 0b1000_0000_0000_0000);
|
||||||
|
try expect(ov[1] == 1);
|
||||||
b = 14;
|
b = 14;
|
||||||
try expect(!@shlWithOverflow(u16, a, b, &result));
|
ov = @shlWithOverflow(a, b);
|
||||||
try expect(result == 0b1100_0000_0000_0000);
|
try expect(ov[0] == 0b1100_0000_0000_0000);
|
||||||
|
try expect(ov[1] == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "overflow arithmetic with u0 values" {
|
test "overflow arithmetic with u0 values" {
|
||||||
var result: u0 = undefined;
|
{
|
||||||
try expect(!@addWithOverflow(u0, 0, 0, &result));
|
var a: u0 = 0;
|
||||||
try expect(result == 0);
|
const ov = @addWithOverflow(a, 0);
|
||||||
try expect(!@subWithOverflow(u0, 0, 0, &result));
|
try expect(ov[1] == 0);
|
||||||
try expect(result == 0);
|
try expect(ov[1] == 0);
|
||||||
try expect(!@mulWithOverflow(u0, 0, 0, &result));
|
}
|
||||||
try expect(result == 0);
|
{
|
||||||
try expect(!@shlWithOverflow(u0, 0, 0, &result));
|
var a: u0 = 0;
|
||||||
try expect(result == 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" {
|
test "allow signed integer division/remainder when values are comptime-known and positive or exact" {
|
||||||
|
|
|
||||||
|
|
@ -963,35 +963,31 @@ test "@addWithOverflow" {
|
||||||
const S = struct {
|
const S = struct {
|
||||||
fn doTheTest() !void {
|
fn doTheTest() !void {
|
||||||
{
|
{
|
||||||
var result: @Vector(4, u8) = undefined;
|
|
||||||
var lhs = @Vector(4, u8){ 250, 250, 250, 250 };
|
var lhs = @Vector(4, u8){ 250, 250, 250, 250 };
|
||||||
var rhs = @Vector(4, u8){ 0, 5, 6, 10 };
|
var rhs = @Vector(4, u8){ 0, 5, 6, 10 };
|
||||||
var overflow = @addWithOverflow(@Vector(4, u8), lhs, rhs, &result);
|
var overflow = @addWithOverflow(lhs, rhs)[1];
|
||||||
var expected: @Vector(4, bool) = .{ false, false, true, true };
|
var expected: @Vector(4, u1) = .{ 0, 0, 1, 1 };
|
||||||
try expectEqual(expected, overflow);
|
try expectEqual(expected, overflow);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
var result: @Vector(4, i8) = undefined;
|
|
||||||
var lhs = @Vector(4, i8){ -125, -125, 125, 125 };
|
var lhs = @Vector(4, i8){ -125, -125, 125, 125 };
|
||||||
var rhs = @Vector(4, i8){ -3, -4, 2, 3 };
|
var rhs = @Vector(4, i8){ -3, -4, 2, 3 };
|
||||||
var overflow = @addWithOverflow(@Vector(4, i8), lhs, rhs, &result);
|
var overflow = @addWithOverflow(lhs, rhs)[1];
|
||||||
var expected: @Vector(4, bool) = .{ false, true, false, true };
|
var expected: @Vector(4, u1) = .{ 0, 1, 0, 1 };
|
||||||
try expectEqual(expected, overflow);
|
try expectEqual(expected, overflow);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
var result: @Vector(4, u1) = undefined;
|
|
||||||
var lhs = @Vector(4, u1){ 0, 0, 1, 1 };
|
var lhs = @Vector(4, u1){ 0, 0, 1, 1 };
|
||||||
var rhs = @Vector(4, u1){ 0, 1, 0, 1 };
|
var rhs = @Vector(4, u1){ 0, 1, 0, 1 };
|
||||||
var overflow = @addWithOverflow(@Vector(4, u1), lhs, rhs, &result);
|
var overflow = @addWithOverflow(lhs, rhs)[1];
|
||||||
var expected: @Vector(4, bool) = .{ false, false, false, true };
|
var expected: @Vector(4, u1) = .{ 0, 0, 0, 1 };
|
||||||
try expectEqual(expected, overflow);
|
try expectEqual(expected, overflow);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
var result: @Vector(4, u0) = undefined;
|
|
||||||
var lhs = @Vector(4, u0){ 0, 0, 0, 0 };
|
var lhs = @Vector(4, u0){ 0, 0, 0, 0 };
|
||||||
var rhs = @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 overflow = @addWithOverflow(lhs, rhs)[1];
|
||||||
var expected: @Vector(4, bool) = .{ false, false, false, false };
|
var expected: @Vector(4, u1) = .{ 0, 0, 0, 0 };
|
||||||
try expectEqual(expected, overflow);
|
try expectEqual(expected, overflow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1010,19 +1006,17 @@ test "@subWithOverflow" {
|
||||||
const S = struct {
|
const S = struct {
|
||||||
fn doTheTest() !void {
|
fn doTheTest() !void {
|
||||||
{
|
{
|
||||||
var result: @Vector(2, u8) = undefined;
|
|
||||||
var lhs = @Vector(2, u8){ 5, 5 };
|
var lhs = @Vector(2, u8){ 5, 5 };
|
||||||
var rhs = @Vector(2, u8){ 5, 6 };
|
var rhs = @Vector(2, u8){ 5, 6 };
|
||||||
var overflow = @subWithOverflow(@Vector(2, u8), lhs, rhs, &result);
|
var overflow = @subWithOverflow(lhs, rhs)[1];
|
||||||
var expected: @Vector(2, bool) = .{ false, true };
|
var expected: @Vector(2, u1) = .{ 0, 1 };
|
||||||
try expectEqual(expected, overflow);
|
try expectEqual(expected, overflow);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
var result: @Vector(4, i8) = undefined;
|
|
||||||
var lhs = @Vector(4, i8){ -120, -120, 120, 120 };
|
var lhs = @Vector(4, i8){ -120, -120, 120, 120 };
|
||||||
var rhs = @Vector(4, i8){ 8, 9, -7, -8 };
|
var rhs = @Vector(4, i8){ 8, 9, -7, -8 };
|
||||||
var overflow = @subWithOverflow(@Vector(4, i8), lhs, rhs, &result);
|
var overflow = @subWithOverflow(lhs, rhs)[1];
|
||||||
var expected: @Vector(4, bool) = .{ false, true, false, true };
|
var expected: @Vector(4, u1) = .{ 0, 1, 0, 1 };
|
||||||
try expectEqual(expected, overflow);
|
try expectEqual(expected, overflow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1040,11 +1034,10 @@ test "@mulWithOverflow" {
|
||||||
|
|
||||||
const S = struct {
|
const S = struct {
|
||||||
fn doTheTest() !void {
|
fn doTheTest() !void {
|
||||||
var result: @Vector(4, u8) = undefined;
|
|
||||||
var lhs = @Vector(4, u8){ 10, 10, 10, 10 };
|
var lhs = @Vector(4, u8){ 10, 10, 10, 10 };
|
||||||
var rhs = @Vector(4, u8){ 25, 26, 0, 30 };
|
var rhs = @Vector(4, u8){ 25, 26, 0, 30 };
|
||||||
var overflow = @mulWithOverflow(@Vector(4, u8), lhs, rhs, &result);
|
var overflow = @mulWithOverflow(lhs, rhs)[1];
|
||||||
var expected: @Vector(4, bool) = .{ false, true, false, true };
|
var expected: @Vector(4, u1) = .{ 0, 1, 0, 1 };
|
||||||
try expectEqual(expected, overflow);
|
try expectEqual(expected, overflow);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -1062,11 +1055,10 @@ test "@shlWithOverflow" {
|
||||||
|
|
||||||
const S = struct {
|
const S = struct {
|
||||||
fn doTheTest() !void {
|
fn doTheTest() !void {
|
||||||
var result: @Vector(4, u8) = undefined;
|
|
||||||
var lhs = @Vector(4, u8){ 0, 1, 8, 255 };
|
var lhs = @Vector(4, u8){ 0, 1, 8, 255 };
|
||||||
var rhs = @Vector(4, u3){ 7, 7, 7, 7 };
|
var rhs = @Vector(4, u3){ 7, 7, 7, 7 };
|
||||||
var overflow = @shlWithOverflow(@Vector(4, u8), lhs, rhs, &result);
|
var overflow = @shlWithOverflow(lhs, rhs)[1];
|
||||||
var expected: @Vector(4, bool) = .{ false, false, true, true };
|
var expected: @Vector(4, u1) = .{ 0, 0, 1, 1 };
|
||||||
try expectEqual(expected, overflow);
|
try expectEqual(expected, overflow);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue