diff options
| author | kkHAIKE <kkhaike@gmail.com> | 2022-09-19 15:39:56 +0800 |
|---|---|---|
| committer | Veikka Tuominen <git@vexu.eu> | 2022-10-13 13:11:13 +0200 |
| commit | d987bf859e6d8511abb49b258c4d764bd32acc8e (patch) | |
| tree | b8a0448ffea6b5a57f3e53bff46971a9ff424977 /src | |
| parent | 3a9344d8fc757e6c771f689fce0db912e39115e9 (diff) | |
| download | zig-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.zig | 66 | ||||
| -rw-r--r-- | src/value.zig | 17 |
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()); |
