| ... | ... | @@ -27673,6 +27673,14 @@ fn cmpNumeric( |
| 27673 | 27673 | if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| { |
| 27674 | 27674 | if (lhs_val.isUndef()) |
| 27675 | 27675 | return sema.addConstUndef(Type.bool); |
| 27676 | if (lhs_val.isNan()) switch (op) { |
| 27677 | .neq => return Air.Inst.Ref.bool_true, |
| 27678 | else => return Air.Inst.Ref.bool_false, |
| 27679 | }; |
| 27680 | if (lhs_val.isInf()) switch (op) { |
| 27681 | .gt, .neq => return Air.Inst.Ref.bool_true, |
| 27682 | .lt, .lte, .eq, .gte => return Air.Inst.Ref.bool_false, |
| 27683 | }; |
| 27676 | 27684 | if (!rhs_is_signed) { |
| 27677 | 27685 | switch (lhs_val.orderAgainstZero()) { |
| 27678 | 27686 | .gt => {}, |
| ... | ... | @@ -27688,8 +27696,7 @@ fn cmpNumeric( |
| 27688 | 27696 | } |
| 27689 | 27697 | } |
| 27690 | 27698 | if (lhs_is_float) { |
| 27691 | | var bigint_space: Value.BigIntSpace = undefined; |
| 27692 | | var bigint = try lhs_val.toBigInt(&bigint_space, target).toManaged(sema.gpa); |
| 27699 | var bigint = try float128IntPartToBigInt(sema.gpa, lhs_val.toFloat(f128)); |
| 27693 | 27700 | defer bigint.deinit(); |
| 27694 | 27701 | if (lhs_val.floatHasFraction()) { |
| 27695 | 27702 | switch (op) { |
| ... | ... | @@ -27719,6 +27726,14 @@ fn cmpNumeric( |
| 27719 | 27726 | if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| { |
| 27720 | 27727 | if (rhs_val.isUndef()) |
| 27721 | 27728 | return sema.addConstUndef(Type.bool); |
| 27729 | if (rhs_val.isNan()) switch (op) { |
| 27730 | .neq => return Air.Inst.Ref.bool_true, |
| 27731 | else => return Air.Inst.Ref.bool_false, |
| 27732 | }; |
| 27733 | if (rhs_val.isInf()) switch (op) { |
| 27734 | .lt, .neq => return Air.Inst.Ref.bool_true, |
| 27735 | .gt, .lte, .eq, .gte => return Air.Inst.Ref.bool_false, |
| 27736 | }; |
| 27722 | 27737 | if (!lhs_is_signed) { |
| 27723 | 27738 | switch (rhs_val.orderAgainstZero()) { |
| 27724 | 27739 | .gt => {}, |
| ... | ... | @@ -27734,8 +27749,7 @@ fn cmpNumeric( |
| 27734 | 27749 | } |
| 27735 | 27750 | } |
| 27736 | 27751 | if (rhs_is_float) { |
| 27737 | | var bigint_space: Value.BigIntSpace = undefined; |
| 27738 | | var bigint = try rhs_val.toBigInt(&bigint_space, target).toManaged(sema.gpa); |
| 27752 | var bigint = try float128IntPartToBigInt(sema.gpa, rhs_val.toFloat(f128)); |
| 27739 | 27753 | defer bigint.deinit(); |
| 27740 | 27754 | if (rhs_val.floatHasFraction()) { |
| 27741 | 27755 | switch (op) { |
| ... | ... | @@ -31110,6 +31124,31 @@ fn floatToInt( |
| 31110 | 31124 | return sema.floatToIntScalar(block, src, val, float_ty, int_ty); |
| 31111 | 31125 | } |
| 31112 | 31126 | |
| 31127 | // float is expected to be finite and non-NaN |
| 31128 | fn float128IntPartToBigInt( |
| 31129 | arena: Allocator, |
| 31130 | float: f128, |
| 31131 | ) !std.math.big.int.Managed { |
| 31132 | const is_negative = std.math.signbit(float); |
| 31133 | const floored = @floor(@fabs(float)); |
| 31134 | |
| 31135 | var rational = try std.math.big.Rational.init(arena); |
| 31136 | defer rational.q.deinit(); |
| 31137 | rational.setFloat(f128, floored) catch |err| switch (err) { |
| 31138 | error.NonFiniteFloat => unreachable, |
| 31139 | error.OutOfMemory => return error.OutOfMemory, |
| 31140 | }; |
| 31141 | |
| 31142 | // The float is reduced in rational.setFloat, so we assert that denominator is equal to one |
| 31143 | const big_one = std.math.big.int.Const{ .limbs = &.{1}, .positive = true }; |
| 31144 | assert(rational.q.toConst().eqAbs(big_one)); |
| 31145 | |
| 31146 | if (is_negative) { |
| 31147 | rational.negate(); |
| 31148 | } |
| 31149 | return rational.p; |
| 31150 | } |
| 31151 | |
| 31113 | 31152 | fn floatToIntScalar( |
| 31114 | 31153 | sema: *Sema, |
| 31115 | 31154 | block: *Block, |
| ... | ... | @@ -31132,22 +31171,11 @@ fn floatToIntScalar( |
| 31132 | 31171 | }); |
| 31133 | 31172 | } |
| 31134 | 31173 | |
| 31135 | | const is_negative = std.math.signbit(float); |
| 31136 | | const floored = @floor(@fabs(float)); |
| 31137 | | |
| 31138 | | var rational = try std.math.big.Rational.init(sema.arena); |
| 31139 | | defer rational.deinit(); |
| 31140 | | rational.setFloat(f128, floored) catch |err| switch (err) { |
| 31141 | | error.NonFiniteFloat => unreachable, |
| 31142 | | error.OutOfMemory => return error.OutOfMemory, |
| 31143 | | }; |
| 31144 | | |
| 31145 | | // The float is reduced in rational.setFloat, so we assert that denominator is equal to one |
| 31146 | | const big_one = std.math.big.int.Const{ .limbs = &.{1}, .positive = true }; |
| 31147 | | assert(rational.q.toConst().eqAbs(big_one)); |
| 31174 | var big_int = try float128IntPartToBigInt(sema.arena, float); |
| 31175 | defer big_int.deinit(); |
| 31148 | 31176 | |
| 31149 | | const result_limbs = try sema.arena.dupe(Limb, rational.p.toConst().limbs); |
| 31150 | | const result = if (is_negative) |
| 31177 | const result_limbs = try sema.arena.dupe(Limb, big_int.toConst().limbs); |
| 31178 | const result = if (!big_int.isPositive()) |
| 31151 | 31179 | try Value.Tag.int_big_negative.create(sema.arena, result_limbs) |
| 31152 | 31180 | else |
| 31153 | 31181 | try Value.Tag.int_big_positive.create(sema.arena, result_limbs); |