authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-04-04 22:07:15-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-04-04 22:07:15-04:00
log1dc6751721a2fe9990ea8fab4eadc95a29f53304
treefb85f1874651709f419567327241e94748d63bb8
parent8e6ff8d615820f7f732724a5db1639ae5f12fb4e
signaturelock-open Commit is signed but in an unrecognized format.

fix NaN comparing equal to itself

This was broken both in comptime code and in runtime code. closes #1174

6 files changed, 54 insertions(+), 1 deletions(-)

CMakeLists.txt+1
......@@ -302,6 +302,7 @@ set(EMBEDDED_SOFTFLOAT_SOURCES
302302 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_add.c"
303303 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_div.c"
304304 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_eq.c"
305 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_isSignalingNaN.c"
305306 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_lt.c"
306307 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_mul.c"
307308 "${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) {
190190void bigfloat_sqrt(BigFloat *dest, const BigFloat *op) {
191191 f128M_sqrt(&op->value, &dest->value);
192192}
193
194bool 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);
4848void bigfloat_append_buf(Buf *buf, const BigFloat *op);
4949Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2);
5050
51bool bigfloat_is_nan(const BigFloat *op);
5152
5253// convenience functions
5354Cmp 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) {
18521852 case IrBinOpCmpEq:
18531853 return LLVMRealOEQ;
18541854 case IrBinOpCmpNotEq:
1855 return LLVMRealONE;
1855 return LLVMRealUNE;
18561856 case IrBinOpCmpLessThan:
18571857 return LLVMRealOLT;
18581858 case IrBinOpCmpGreaterThan:
src/ir.cpp+25
......@@ -17,6 +17,7 @@
1717#include "util.hpp"
1818
1919#include <errno.h>
20#include <math.h>
2021
2122struct IrExecContext {
2223 ZigList<ConstExprValue *> mem_slot_list;
......@@ -8242,6 +8243,27 @@ static void float_init_float(ConstExprValue *dest_val, ConstExprValue *src_val)
82428243 }
82438244}
82448245
8246static 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
82458267static Cmp float_cmp(ConstExprValue *op1, ConstExprValue *op2) {
82468268 assert(op1->type == op2->type);
82478269 if (op1->type->id == ZigTypeIdComptimeFloat) {
......@@ -12378,6 +12400,9 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
1237812400 return ira->codegen->invalid_instruction;
1237912401
1238012402 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 }
1238112406 Cmp cmp_result = float_cmp(op1_val, op2_val);
1238212407 bool answer = resolve_cmp_op_id(op_id, cmp_result);
1238312408 return ir_const_bool(ira, &bin_op_instruction->base, answer);
test/stage1/behavior/math.zig+22
......@@ -610,3 +610,25 @@ test "vector integer addition" {
610610 S.doTheTest();
611611 comptime S.doTheTest();
612612}
613
614test "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
625fn 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}