From 69be6ba8eea8e0b64153a0d0676f1b8749df8195 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Mon, 27 Sep 2021 04:58:27 +0200 Subject: [PATCH] Comptime wrapping addition/subtraction --- lib/std/math/big/int.zig | 4 +-- src/value.zig | 57 +++++++++++++++++++++++++--------------- 2 files changed, 38 insertions(+), 23 deletions(-) diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig index 59d59a19d3..86d0e22cb8 100644 --- a/lib/std/math/big/int.zig +++ b/lib/std/math/big/int.zig @@ -444,7 +444,7 @@ pub const Mutable = struct { const b_limbs = b.limbs[0..math.min(req_limbs, b.limbs.len)]; if (a.positive != b.positive) { - if (a.positive) { + if (a.positive) { // (a) - (-b) => a + b r.addWrap(a, b.abs(), signedness, bit_count); } else { @@ -1107,7 +1107,7 @@ pub const Mutable = struct { // Zero-extend the result if (req_limbs > r.len) { - mem.set(Limb, r.limbs[r.len .. req_limbs], 0); + mem.set(Limb, r.limbs[r.len..req_limbs], 0); } // Truncate to required number of limbs. diff --git a/src/value.zig b/src/value.zig index fa11bb6ddb..2894840166 100644 --- a/src/value.zig +++ b/src/value.zig @@ -1660,19 +1660,26 @@ pub const Value = extern union { if (ty.isAnyFloat()) { return floatAdd(lhs, rhs, ty, arena); } - const result = try intAdd(lhs, rhs, arena); - const max = try ty.maxInt(arena, target); - if (compare(result, .gt, max, ty)) { - @panic("TODO comptime wrapping integer addition"); + const info = ty.intInfo(target); + + var lhs_space: Value.BigIntSpace = undefined; + var rhs_space: Value.BigIntSpace = undefined; + const lhs_bigint = lhs.toBigInt(&lhs_space); + const rhs_bigint = rhs.toBigInt(&rhs_space); + const limbs = try arena.alloc( + std.math.big.Limb, + std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1, + ); + var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; + result_bigint.addWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits); + const result_limbs = result_bigint.limbs[0..result_bigint.len]; + + if (result_bigint.positive) { + return Value.Tag.int_big_positive.create(arena, result_limbs); + } else { + return Value.Tag.int_big_negative.create(arena, result_limbs); } - - const min = try ty.minInt(arena, target); - if (compare(result, .lt, min, ty)) { - @panic("TODO comptime wrapping integer addition"); - } - - return result; } /// Supports integers only; asserts neither operand is undefined. @@ -1714,19 +1721,27 @@ pub const Value = extern union { if (ty.isAnyFloat()) { return floatSub(lhs, rhs, ty, arena); } - const result = try intSub(lhs, rhs, arena); - const max = try ty.maxInt(arena, target); - if (compare(result, .gt, max, ty)) { - @panic("TODO comptime wrapping integer subtraction"); + const info = ty.intInfo(target); + + var lhs_space: Value.BigIntSpace = undefined; + var rhs_space: Value.BigIntSpace = undefined; + const lhs_bigint = lhs.toBigInt(&lhs_space); + const rhs_bigint = rhs.toBigInt(&rhs_space); + const limbs = try arena.alloc( + std.math.big.Limb, + std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1, + ); + var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; + result_bigint.subWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits); + const result_limbs = result_bigint.limbs[0..result_bigint.len]; + + if (result_bigint.positive) { + return Value.Tag.int_big_positive.create(arena, result_limbs); + } else { + return Value.Tag.int_big_negative.create(arena, result_limbs); } - const min = try ty.minInt(arena, target); - if (compare(result, .lt, min, ty)) { - @panic("TODO comptime wrapping integer subtraction"); - } - - return result; } /// Supports integers only; asserts neither operand is undefined.