Merge branch 'LemonBoy-fix-4259'

This commit is contained in:
Andrew Kelley 2020-01-29 17:21:29 -05:00
commit 7ebc624a15
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
2 changed files with 107 additions and 34 deletions

View File

@ -11161,6 +11161,38 @@ void float_read_ieee597(ZigValue *val, uint8_t *buf, bool is_big_endian) {
}
}
static void value_to_bigfloat(BigFloat *out, ZigValue *val) {
switch (val->type->id) {
case ZigTypeIdInt:
case ZigTypeIdComptimeInt:
bigfloat_init_bigint(out, &val->data.x_bigint);
return;
case ZigTypeIdComptimeFloat:
*out = val->data.x_bigfloat;
return;
case ZigTypeIdFloat: switch (val->type->data.floating.bit_count) {
case 16:
bigfloat_init_16(out, val->data.x_f16);
return;
case 32:
bigfloat_init_32(out, val->data.x_f32);
return;
case 64:
bigfloat_init_64(out, val->data.x_f64);
return;
case 80:
zig_panic("TODO");
case 128:
bigfloat_init_128(out, val->data.x_f128);
return;
default:
zig_unreachable();
}
default:
zig_unreachable();
}
}
static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstGen *instruction, ZigType *other_type,
bool explicit_cast)
{
@ -15815,33 +15847,44 @@ never_mind_just_calculate_it_normally:
bool op1_is_int = op1_val->type->id == ZigTypeIdInt || op1_val->type->id == ZigTypeIdComptimeInt;
bool op2_is_int = op2_val->type->id == ZigTypeIdInt || op2_val->type->id == ZigTypeIdComptimeInt;
BigInt *op1_bigint;
BigInt *op2_bigint;
bool need_to_free_op1_bigint = false;
bool need_to_free_op2_bigint = false;
if (op1_is_float) {
op1_bigint = allocate<BigInt>(1, "BigInt");
need_to_free_op1_bigint = true;
float_init_bigint(op1_bigint, op1_val);
} else {
assert(op1_is_int);
op1_bigint = &op1_val->data.x_bigint;
}
if (op2_is_float) {
op2_bigint = allocate<BigInt>(1, "BigInt");
need_to_free_op2_bigint = true;
float_init_bigint(op2_bigint, op2_val);
} else {
assert(op2_is_int);
op2_bigint = &op2_val->data.x_bigint;
}
Cmp cmp_result = bigint_cmp(op1_bigint, op2_bigint);
if (op1_is_int && op2_is_int) {
Cmp cmp_result = bigint_cmp(&op1_val->data.x_bigint, &op2_val->data.x_bigint);
out_val->special = ConstValSpecialStatic;
out_val->data.x_bool = resolve_cmp_op_id(op_id, cmp_result);
return nullptr;
}
// Handle the case where one of the two operands is a fp value and the other
// is an integer value
ZigValue *float_val;
if (op1_is_int && op2_is_float) {
float_val = op2_val;
} else if (op1_is_float && op2_is_int) {
float_val = op1_val;
} else {
zig_unreachable();
}
// They can never be equal if the fp value has a non-zero decimal part
if (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq) {
if (float_has_fraction(float_val)) {
out_val->special = ConstValSpecialStatic;
out_val->data.x_bool = op_id == IrBinOpCmpNotEq;
return nullptr;
}
}
// Cast the integer operand into a fp value to perform the comparison
BigFloat op1_bigfloat;
BigFloat op2_bigfloat;
value_to_bigfloat(&op1_bigfloat, op1_val);
value_to_bigfloat(&op2_bigfloat, op2_val);
Cmp cmp_result = bigfloat_cmp(&op1_bigfloat, &op2_bigfloat);
out_val->special = ConstValSpecialStatic;
out_val->data.x_bool = resolve_cmp_op_id(op_id, cmp_result);
if (need_to_free_op1_bigint) destroy(op1_bigint, "BigInt");
if (need_to_free_op2_bigint) destroy(op2_bigint, "BigInt");
return nullptr;
}

View File

@ -403,6 +403,36 @@ fn testTrunc() void {
}
}
test "floating point comparisons" {
testFloatComparisons();
comptime testFloatComparisons();
}
fn testFloatComparisons() void {
inline for ([_]type{ f16, f32, f64, f128 }) |ty| {
// No decimal part
{
const x: ty = 1.0;
expect(x == 1);
expect(x != 0);
expect(x > 0);
expect(x < 2);
expect(x >= 1);
expect(x <= 1);
}
// Non-zero decimal part
{
const x: ty = 1.5;
expect(x != 1);
expect(x != 2);
expect(x > 1);
expect(x < 2);
expect(x >= 1);
expect(x <= 2);
}
}
}
// TODO This is waiting on library support for the Windows build (not sure why the other's don't need it)
//test "@nearbyint" {
// comptime testNearbyInt();