aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorkkHAIKE <kkhaike@gmail.com>2022-09-19 15:39:56 +0800
committerVeikka Tuominen <git@vexu.eu>2022-10-13 13:11:13 +0200
commitd987bf859e6d8511abb49b258c4d764bd32acc8e (patch)
treeb8a0448ffea6b5a57f3e53bff46971a9ff424977 /src
parent3a9344d8fc757e6c771f689fce0db912e39115e9 (diff)
downloadzig-d987bf859e6d8511abb49b258c4d764bd32acc8e.tar.gz
zig-d987bf859e6d8511abb49b258c4d764bd32acc8e.zip
Sema: add float128IntPartToBigInt to fix compare comptime float with int
Diffstat (limited to 'src')
-rw-r--r--src/Sema.zig66
-rw-r--r--src/value.zig17
2 files changed, 64 insertions, 19 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index e8a64c6e4f..5a0c30d71c 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -27673,6 +27673,14 @@ fn cmpNumeric(
if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
if (lhs_val.isUndef())
return sema.addConstUndef(Type.bool);
+ if (lhs_val.isNan()) switch (op) {
+ .neq => return Air.Inst.Ref.bool_true,
+ else => return Air.Inst.Ref.bool_false,
+ };
+ if (lhs_val.isInf()) switch (op) {
+ .gt, .neq => return Air.Inst.Ref.bool_true,
+ .lt, .lte, .eq, .gte => return Air.Inst.Ref.bool_false,
+ };
if (!rhs_is_signed) {
switch (lhs_val.orderAgainstZero()) {
.gt => {},
@@ -27688,8 +27696,7 @@ fn cmpNumeric(
}
}
if (lhs_is_float) {
- var bigint_space: Value.BigIntSpace = undefined;
- var bigint = try lhs_val.toBigInt(&bigint_space, target).toManaged(sema.gpa);
+ var bigint = try float128IntPartToBigInt(sema.gpa, lhs_val.toFloat(f128));
defer bigint.deinit();
if (lhs_val.floatHasFraction()) {
switch (op) {
@@ -27719,6 +27726,14 @@ fn cmpNumeric(
if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
if (rhs_val.isUndef())
return sema.addConstUndef(Type.bool);
+ if (rhs_val.isNan()) switch (op) {
+ .neq => return Air.Inst.Ref.bool_true,
+ else => return Air.Inst.Ref.bool_false,
+ };
+ if (rhs_val.isInf()) switch (op) {
+ .lt, .neq => return Air.Inst.Ref.bool_true,
+ .gt, .lte, .eq, .gte => return Air.Inst.Ref.bool_false,
+ };
if (!lhs_is_signed) {
switch (rhs_val.orderAgainstZero()) {
.gt => {},
@@ -27734,8 +27749,7 @@ fn cmpNumeric(
}
}
if (rhs_is_float) {
- var bigint_space: Value.BigIntSpace = undefined;
- var bigint = try rhs_val.toBigInt(&bigint_space, target).toManaged(sema.gpa);
+ var bigint = try float128IntPartToBigInt(sema.gpa, rhs_val.toFloat(f128));
defer bigint.deinit();
if (rhs_val.floatHasFraction()) {
switch (op) {
@@ -31110,6 +31124,31 @@ fn floatToInt(
return sema.floatToIntScalar(block, src, val, float_ty, int_ty);
}
+// float is expected to be finite and non-NaN
+fn float128IntPartToBigInt(
+ arena: Allocator,
+ float: f128,
+) !std.math.big.int.Managed {
+ const is_negative = std.math.signbit(float);
+ const floored = @floor(@fabs(float));
+
+ var rational = try std.math.big.Rational.init(arena);
+ defer rational.q.deinit();
+ rational.setFloat(f128, floored) catch |err| switch (err) {
+ error.NonFiniteFloat => unreachable,
+ error.OutOfMemory => return error.OutOfMemory,
+ };
+
+ // The float is reduced in rational.setFloat, so we assert that denominator is equal to one
+ const big_one = std.math.big.int.Const{ .limbs = &.{1}, .positive = true };
+ assert(rational.q.toConst().eqAbs(big_one));
+
+ if (is_negative) {
+ rational.negate();
+ }
+ return rational.p;
+}
+
fn floatToIntScalar(
sema: *Sema,
block: *Block,
@@ -31132,22 +31171,11 @@ fn floatToIntScalar(
});
}
- const is_negative = std.math.signbit(float);
- const floored = @floor(@fabs(float));
-
- var rational = try std.math.big.Rational.init(sema.arena);
- defer rational.deinit();
- rational.setFloat(f128, floored) catch |err| switch (err) {
- error.NonFiniteFloat => unreachable,
- error.OutOfMemory => return error.OutOfMemory,
- };
-
- // The float is reduced in rational.setFloat, so we assert that denominator is equal to one
- const big_one = std.math.big.int.Const{ .limbs = &.{1}, .positive = true };
- assert(rational.q.toConst().eqAbs(big_one));
+ var big_int = try float128IntPartToBigInt(sema.arena, float);
+ defer big_int.deinit();
- const result_limbs = try sema.arena.dupe(Limb, rational.p.toConst().limbs);
- const result = if (is_negative)
+ const result_limbs = try sema.arena.dupe(Limb, big_int.toConst().limbs);
+ const result = if (!big_int.isPositive())
try Value.Tag.int_big_negative.create(sema.arena, result_limbs)
else
try Value.Tag.int_big_positive.create(sema.arena, result_limbs);
diff --git a/src/value.zig b/src/value.zig
index 01df65a715..7a0636dda0 100644
--- a/src/value.zig
+++ b/src/value.zig
@@ -1999,6 +1999,11 @@ pub const Value = extern union {
}
return true;
},
+ .float_16 => if (std.math.isNan(lhs.castTag(.float_16).?.data)) return op != .neq,
+ .float_32 => if (std.math.isNan(lhs.castTag(.float_32).?.data)) return op != .neq,
+ .float_64 => if (std.math.isNan(lhs.castTag(.float_64).?.data)) return op != .neq,
+ .float_80 => if (std.math.isNan(lhs.castTag(.float_80).?.data)) return op != .neq,
+ .float_128 => if (std.math.isNan(lhs.castTag(.float_128).?.data)) return op != .neq,
else => {},
}
return (try orderAgainstZeroAdvanced(lhs, sema_kit)).compare(op);
@@ -3596,6 +3601,18 @@ pub const Value = extern union {
};
}
+ /// Returns true if the value is a floating point type and is infinite. Returns false otherwise.
+ pub fn isInf(val: Value) bool {
+ return switch (val.tag()) {
+ .float_16 => std.math.isInf(val.castTag(.float_16).?.data),
+ .float_32 => std.math.isInf(val.castTag(.float_32).?.data),
+ .float_64 => std.math.isInf(val.castTag(.float_64).?.data),
+ .float_80 => std.math.isInf(val.castTag(.float_80).?.data),
+ .float_128 => std.math.isInf(val.castTag(.float_128).?.data),
+ else => false,
+ };
+ }
+
pub fn floatRem(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, target: Target) !Value {
if (float_type.zigTypeTag() == .Vector) {
const result_data = try arena.alloc(Value, float_type.vectorLen());