aboutsummaryrefslogtreecommitdiff
path: root/src/value.zig
diff options
context:
space:
mode:
authorRobin Voetter <robin@voetter.nl>2021-12-20 02:06:09 +0100
committerRobin Voetter <robin@voetter.nl>2021-12-21 01:41:51 +0100
commitc47ed0c912d2f445710fe4486fa071dd63601989 (patch)
tree3272549828e1ca5fbb65b43a6cad1ea6e200cbd4 /src/value.zig
parentddd2ef822f99979d3ea61583a91ab236942e6367 (diff)
downloadzig-c47ed0c912d2f445710fe4486fa071dd63601989.tar.gz
zig-c47ed0c912d2f445710fe4486fa071dd63601989.zip
stage2: @mulWithOverflow
Diffstat (limited to 'src/value.zig')
-rw-r--r--src/value.zig48
1 files changed, 33 insertions, 15 deletions
diff --git a/src/value.zig b/src/value.zig
index 085883f7af..19546ed8b9 100644
--- a/src/value.zig
+++ b/src/value.zig
@@ -2130,20 +2130,13 @@ pub const Value = extern union {
return fromBigInt(arena, result_bigint.toConst());
}
- /// Supports both floats and ints; handles undefined.
- pub fn numberMulWrap(
+ pub fn intMulWithOverflow(
lhs: Value,
rhs: Value,
ty: Type,
arena: Allocator,
target: Target,
- ) !Value {
- if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
-
- if (ty.isAnyFloat()) {
- return floatMul(lhs, rhs, ty, arena);
- }
-
+ ) !OverflowArithmeticResult {
const info = ty.intInfo(target);
var lhs_space: Value.BigIntSpace = undefined;
@@ -2152,16 +2145,42 @@ pub const Value = extern union {
const rhs_bigint = rhs.toBigInt(&rhs_space);
const limbs = try arena.alloc(
std.math.big.Limb,
- std.math.big.int.calcTwosCompLimbCount(info.bits),
+ lhs_bigint.limbs.len + rhs_bigint.limbs.len,
);
var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
var limbs_buffer = try arena.alloc(
std.math.big.Limb,
- std.math.big.int.calcMulWrapLimbsBufferLen(info.bits, lhs_bigint.limbs.len, rhs_bigint.limbs.len, 1),
+ std.math.big.int.calcMulLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len, 1),
);
- defer arena.free(limbs_buffer);
- result_bigint.mulWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits, limbs_buffer, arena);
- return fromBigInt(arena, result_bigint.toConst());
+ result_bigint.mul(lhs_bigint, rhs_bigint, limbs_buffer, arena);
+
+ const overflowed = !result_bigint.toConst().fitsInTwosComp(info.signedness, info.bits);
+ if (overflowed) {
+ result_bigint.truncate(result_bigint.toConst(), info.signedness, info.bits);
+ }
+
+ return OverflowArithmeticResult{
+ .overflowed = overflowed,
+ .wrapped_result = try fromBigInt(arena, result_bigint.toConst()),
+ };
+ }
+
+ /// Supports both floats and ints; handles undefined.
+ pub fn numberMulWrap(
+ lhs: Value,
+ rhs: Value,
+ ty: Type,
+ arena: Allocator,
+ target: Target,
+ ) !Value {
+ if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
+
+ if (ty.isAnyFloat()) {
+ return floatMul(lhs, rhs, ty, arena);
+ }
+
+ const overflow_result = try intMulWithOverflow(lhs, rhs, ty, arena, target);
+ return overflow_result.wrapped_result;
}
/// Supports integers only; asserts neither operand is undefined.
@@ -2194,7 +2213,6 @@ pub const Value = extern union {
std.math.big.Limb,
std.math.big.int.calcMulLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len, 1),
);
- defer arena.free(limbs_buffer);
result_bigint.mul(lhs_bigint, rhs_bigint, limbs_buffer, arena);
result_bigint.saturate(result_bigint.toConst(), info.signedness, info.bits);
return fromBigInt(arena, result_bigint.toConst());