| ... | @@ -27673,6 +27673,14 @@ fn cmpNumeric( | ... | @@ -27673,6 +27673,14 @@ fn cmpNumeric( |
| 27673 | if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| { | 27673 | if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| { |
| 27674 | if (lhs_val.isUndef()) | 27674 | if (lhs_val.isUndef()) |
| 27675 | return sema.addConstUndef(Type.bool); | 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 | if (!rhs_is_signed) { | 27684 | if (!rhs_is_signed) { |
| 27677 | switch (lhs_val.orderAgainstZero()) { | 27685 | switch (lhs_val.orderAgainstZero()) { |
| 27678 | .gt => {}, | 27686 | .gt => {}, |
| ... | @@ -27688,8 +27696,7 @@ fn cmpNumeric( | ... | @@ -27688,8 +27696,7 @@ fn cmpNumeric( |
| 27688 | } | 27696 | } |
| 27689 | } | 27697 | } |
| 27690 | if (lhs_is_float) { | 27698 | if (lhs_is_float) { |
| 27691 | var bigint_space: Value.BigIntSpace = undefined; | 27699 | var bigint = try float128IntPartToBigInt(sema.gpa, lhs_val.toFloat(f128)); |
| 27692 | var bigint = try lhs_val.toBigInt(&bigint_space, target).toManaged(sema.gpa); | | |
| 27693 | defer bigint.deinit(); | 27700 | defer bigint.deinit(); |
| 27694 | if (lhs_val.floatHasFraction()) { | 27701 | if (lhs_val.floatHasFraction()) { |
| 27695 | switch (op) { | 27702 | switch (op) { |
| ... | @@ -27719,6 +27726,14 @@ fn cmpNumeric( | ... | @@ -27719,6 +27726,14 @@ fn cmpNumeric( |
| 27719 | if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| { | 27726 | if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| { |
| 27720 | if (rhs_val.isUndef()) | 27727 | if (rhs_val.isUndef()) |
| 27721 | return sema.addConstUndef(Type.bool); | 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 | if (!lhs_is_signed) { | 27737 | if (!lhs_is_signed) { |
| 27723 | switch (rhs_val.orderAgainstZero()) { | 27738 | switch (rhs_val.orderAgainstZero()) { |
| 27724 | .gt => {}, | 27739 | .gt => {}, |
| ... | @@ -27734,8 +27749,7 @@ fn cmpNumeric( | ... | @@ -27734,8 +27749,7 @@ fn cmpNumeric( |
| 27734 | } | 27749 | } |
| 27735 | } | 27750 | } |
| 27736 | if (rhs_is_float) { | 27751 | if (rhs_is_float) { |
| 27737 | var bigint_space: Value.BigIntSpace = undefined; | 27752 | var bigint = try float128IntPartToBigInt(sema.gpa, rhs_val.toFloat(f128)); |
| 27738 | var bigint = try rhs_val.toBigInt(&bigint_space, target).toManaged(sema.gpa); | | |
| 27739 | defer bigint.deinit(); | 27753 | defer bigint.deinit(); |
| 27740 | if (rhs_val.floatHasFraction()) { | 27754 | if (rhs_val.floatHasFraction()) { |
| 27741 | switch (op) { | 27755 | switch (op) { |
| ... | @@ -31110,6 +31124,31 @@ fn floatToInt( | ... | @@ -31110,6 +31124,31 @@ fn floatToInt( |
| 31110 | return sema.floatToIntScalar(block, src, val, float_ty, int_ty); | 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 | fn floatToIntScalar( | 31152 | fn floatToIntScalar( |
| 31114 | sema: *Sema, | 31153 | sema: *Sema, |
| 31115 | block: *Block, | 31154 | block: *Block, |
| ... | @@ -31132,22 +31171,11 @@ fn floatToIntScalar( | ... | @@ -31132,22 +31171,11 @@ fn floatToIntScalar( |
| 31132 | }); | 31171 | }); |
| 31133 | } | 31172 | } |
| 31134 | | 31173 | |
| 31135 | const is_negative = std.math.signbit(float); | 31174 | var big_int = try float128IntPartToBigInt(sema.arena, float); |
| 31136 | const floored = @floor(@fabs(float)); | 31175 | defer big_int.deinit(); |
| 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)); | | |
| 31148 | | 31176 | |
| 31149 | const result_limbs = try sema.arena.dupe(Limb, rational.p.toConst().limbs); | 31177 | const result_limbs = try sema.arena.dupe(Limb, big_int.toConst().limbs); |
| 31150 | const result = if (is_negative) | 31178 | const result = if (!big_int.isPositive()) |
| 31151 | try Value.Tag.int_big_negative.create(sema.arena, result_limbs) | 31179 | try Value.Tag.int_big_negative.create(sema.arena, result_limbs) |
| 31152 | else | 31180 | else |
| 31153 | try Value.Tag.int_big_positive.create(sema.arena, result_limbs); | 31181 | try Value.Tag.int_big_positive.create(sema.arena, result_limbs); |