| author | |
| committer | |
| log | 1dc6751721a2fe9990ea8fab4eadc95a29f53304 |
| tree | fb85f1874651709f419567327241e94748d63bb8 |
| parent | 8e6ff8d615820f7f732724a5db1639ae5f12fb4e |
| signature |
This was broken both in comptime code and in runtime code.
closes #11746 files changed, 54 insertions(+), 1 deletions(-)
CMakeLists.txt+1| ... | @@ -302,6 +302,7 @@ set(EMBEDDED_SOFTFLOAT_SOURCES | ... | @@ -302,6 +302,7 @@ set(EMBEDDED_SOFTFLOAT_SOURCES |
| 302 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_add.c" | 302 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_add.c" |
| 303 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_div.c" | 303 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_div.c" |
| 304 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_eq.c" | 304 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_eq.c" |
| 305 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_isSignalingNaN.c" | ||
| 305 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_lt.c" | 306 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_lt.c" |
| 306 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_mul.c" | 307 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_mul.c" |
| 307 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_rem.c" | 308 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_rem.c" |
src/bigfloat.cpp+4| ... | @@ -190,3 +190,7 @@ bool bigfloat_has_fraction(const BigFloat *bigfloat) { | ... | @@ -190,3 +190,7 @@ bool bigfloat_has_fraction(const BigFloat *bigfloat) { |
| 190 | void bigfloat_sqrt(BigFloat *dest, const BigFloat *op) { | 190 | void bigfloat_sqrt(BigFloat *dest, const BigFloat *op) { |
| 191 | f128M_sqrt(&op->value, &dest->value); | 191 | f128M_sqrt(&op->value, &dest->value); |
| 192 | } | 192 | } |
| 193 | |||
| 194 | bool bigfloat_is_nan(const BigFloat *op) { | ||
| 195 | return f128M_isSignalingNaN(&op->value); | ||
| 196 | } |
src/bigfloat.hpp+1| ... | @@ -48,6 +48,7 @@ void bigfloat_sqrt(BigFloat *dest, const BigFloat *op); | ... | @@ -48,6 +48,7 @@ void bigfloat_sqrt(BigFloat *dest, const BigFloat *op); |
| 48 | void bigfloat_append_buf(Buf *buf, const BigFloat *op); | 48 | void bigfloat_append_buf(Buf *buf, const BigFloat *op); |
| 49 | Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2); | 49 | Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2); |
| 50 | 50 | ||
| 51 | bool bigfloat_is_nan(const BigFloat *op); | ||
| 51 | 52 | ||
| 52 | // convenience functions | 53 | // convenience functions |
| 53 | Cmp bigfloat_cmp_zero(const BigFloat *bigfloat); | 54 | Cmp bigfloat_cmp_zero(const BigFloat *bigfloat); |
src/codegen.cpp+1-1| ... | @@ -1852,7 +1852,7 @@ static LLVMRealPredicate cmp_op_to_real_predicate(IrBinOp cmp_op) { | ... | @@ -1852,7 +1852,7 @@ static LLVMRealPredicate cmp_op_to_real_predicate(IrBinOp cmp_op) { |
| 1852 | case IrBinOpCmpEq: | 1852 | case IrBinOpCmpEq: |
| 1853 | return LLVMRealOEQ; | 1853 | return LLVMRealOEQ; |
| 1854 | case IrBinOpCmpNotEq: | 1854 | case IrBinOpCmpNotEq: |
| 1855 | return LLVMRealONE; | 1855 | return LLVMRealUNE; |
| 1856 | case IrBinOpCmpLessThan: | 1856 | case IrBinOpCmpLessThan: |
| 1857 | return LLVMRealOLT; | 1857 | return LLVMRealOLT; |
| 1858 | case IrBinOpCmpGreaterThan: | 1858 | case IrBinOpCmpGreaterThan: |
src/ir.cpp+25| ... | @@ -17,6 +17,7 @@ | ... | @@ -17,6 +17,7 @@ |
| 17 | #include "util.hpp" | 17 | #include "util.hpp" |
| 18 | 18 | ||
| 19 | #include <errno.h> | 19 | #include <errno.h> |
| 20 | #include <math.h> | ||
| 20 | 21 | ||
| 21 | struct IrExecContext { | 22 | struct IrExecContext { |
| 22 | ZigList<ConstExprValue *> mem_slot_list; | 23 | ZigList<ConstExprValue *> mem_slot_list; |
| ... | @@ -8242,6 +8243,27 @@ static void float_init_float(ConstExprValue *dest_val, ConstExprValue *src_val) | ... | @@ -8242,6 +8243,27 @@ static void float_init_float(ConstExprValue *dest_val, ConstExprValue *src_val) |
| 8242 | } | 8243 | } |
| 8243 | } | 8244 | } |
| 8244 | 8245 | ||
| 8246 | static bool float_is_nan(ConstExprValue *op) { | ||
| 8247 | if (op->type->id == ZigTypeIdComptimeFloat) { | ||
| 8248 | return bigfloat_is_nan(&op->data.x_bigfloat); | ||
| 8249 | } else if (op->type->id == ZigTypeIdFloat) { | ||
| 8250 | switch (op->type->data.floating.bit_count) { | ||
| 8251 | case 16: | ||
| 8252 | return f16_isSignalingNaN(op->data.x_f16); | ||
| 8253 | case 32: | ||
| 8254 | return isnan(op->data.x_f32); | ||
| 8255 | case 64: | ||
| 8256 | return isnan(op->data.x_f64); | ||
| 8257 | case 128: | ||
| 8258 | return f128M_isSignalingNaN(&op->data.x_f128); | ||
| 8259 | default: | ||
| 8260 | zig_unreachable(); | ||
| 8261 | } | ||
| 8262 | } else { | ||
| 8263 | zig_unreachable(); | ||
| 8264 | } | ||
| 8265 | } | ||
| 8266 | |||
| 8245 | static Cmp float_cmp(ConstExprValue *op1, ConstExprValue *op2) { | 8267 | static Cmp float_cmp(ConstExprValue *op1, ConstExprValue *op2) { |
| 8246 | assert(op1->type == op2->type); | 8268 | assert(op1->type == op2->type); |
| 8247 | if (op1->type->id == ZigTypeIdComptimeFloat) { | 8269 | if (op1->type->id == ZigTypeIdComptimeFloat) { |
| ... | @@ -12378,6 +12400,9 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * | ... | @@ -12378,6 +12400,9 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * |
| 12378 | return ira->codegen->invalid_instruction; | 12400 | return ira->codegen->invalid_instruction; |
| 12379 | 12401 | ||
| 12380 | if (resolved_type->id == ZigTypeIdComptimeFloat || resolved_type->id == ZigTypeIdFloat) { | 12402 | if (resolved_type->id == ZigTypeIdComptimeFloat || resolved_type->id == ZigTypeIdFloat) { |
| 12403 | if (float_is_nan(op1_val) || float_is_nan(op2_val)) { | ||
| 12404 | return ir_const_bool(ira, &bin_op_instruction->base, op_id == IrBinOpCmpNotEq); | ||
| 12405 | } | ||
| 12381 | Cmp cmp_result = float_cmp(op1_val, op2_val); | 12406 | Cmp cmp_result = float_cmp(op1_val, op2_val); |
| 12382 | bool answer = resolve_cmp_op_id(op_id, cmp_result); | 12407 | bool answer = resolve_cmp_op_id(op_id, cmp_result); |
| 12383 | return ir_const_bool(ira, &bin_op_instruction->base, answer); | 12408 | return ir_const_bool(ira, &bin_op_instruction->base, answer); |
test/stage1/behavior/math.zig+22| ... | @@ -610,3 +610,25 @@ test "vector integer addition" { | ... | @@ -610,3 +610,25 @@ test "vector integer addition" { |
| 610 | S.doTheTest(); | 610 | S.doTheTest(); |
| 611 | comptime S.doTheTest(); | 611 | comptime S.doTheTest(); |
| 612 | } | 612 | } |
| 613 | |||
| 614 | test "NaN comparison" { | ||
| 615 | testNanEqNan(f16); | ||
| 616 | testNanEqNan(f32); | ||
| 617 | testNanEqNan(f64); | ||
| 618 | testNanEqNan(f128); | ||
| 619 | comptime testNanEqNan(f16); | ||
| 620 | comptime testNanEqNan(f32); | ||
| 621 | comptime testNanEqNan(f64); | ||
| 622 | comptime testNanEqNan(f128); | ||
| 623 | } | ||
| 624 | |||
| 625 | fn testNanEqNan(comptime F: type) void { | ||
| 626 | var nan1 = std.math.nan(F); | ||
| 627 | var nan2 = std.math.nan(F); | ||
| 628 | expect(nan1 != nan2); | ||
| 629 | expect(!(nan1 == nan2)); | ||
| 630 | expect(!(nan1 > nan2)); | ||
| 631 | expect(!(nan1 >= nan2)); | ||
| 632 | expect(!(nan1 < nan2)); | ||
| 633 | expect(!(nan1 <= nan2)); | ||
| 634 | } |