Commit f9481402f0

LemonBoy <thatlemon@gmail.com>
2021-04-15 18:12:11
stage1: Fix negation for zero floating point values
Toggling the sign by computing 0-x doesn't really work for zero values.
1 parent c59241b
src/stage1/bigfloat.cpp
@@ -9,6 +9,7 @@
 #include "bigint.hpp"
 #include "buffer.hpp"
 #include "softfloat.hpp"
+#include "softfloat_ext.hpp"
 #include "parse_f128.h"
 #include <stdio.h>
 #include <math.h>
@@ -60,9 +61,7 @@ void bigfloat_init_bigint(BigFloat *dest, const BigInt *op) {
 
         if (i == 0) {
             if (op->is_negative) {
-                float128_t zero_f128;
-                ui32_to_f128M(0, &zero_f128);
-                f128M_sub(&zero_f128, &dest->value, &dest->value);
+                f128M_neg(&dest->value, &dest->value);
             }
             return;
         }
@@ -89,9 +88,7 @@ void bigfloat_add(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
 }
 
 void bigfloat_negate(BigFloat *dest, const BigFloat *op) {
-    float128_t zero_f128;
-    ui32_to_f128M(0, &zero_f128);
-    f128M_sub(&zero_f128, &op->value, &dest->value);
+    f128M_neg(&op->value, &dest->value);
 }
 
 void bigfloat_sub(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
src/stage1/ir.cpp
@@ -11363,11 +11363,8 @@ static void float_negate(ZigValue *out_val, ZigValue *op) {
     } else if (op->type->id == ZigTypeIdFloat) {
         switch (op->type->data.floating.bit_count) {
             case 16:
-                {
-                    const float16_t zero = zig_double_to_f16(0);
-                    out_val->data.x_f16 = f16_sub(zero, op->data.x_f16);
-                    return;
-                }
+                out_val->data.x_f16 = f16_neg(op->data.x_f16);
+                return;
             case 32:
                 out_val->data.x_f32 = -op->data.x_f32;
                 return;
@@ -11375,9 +11372,7 @@ static void float_negate(ZigValue *out_val, ZigValue *op) {
                 out_val->data.x_f64 = -op->data.x_f64;
                 return;
             case 128:
-                float128_t zero_f128;
-                ui32_to_f128M(0, &zero_f128);
-                f128M_sub(&zero_f128, &op->data.x_f128, &out_val->data.x_f128);
+                f128M_neg(&op->data.x_f128, &out_val->data.x_f128);
                 return;
             default:
                 zig_unreachable();
src/stage1/softfloat_ext.cpp
@@ -1,6 +1,8 @@
 #include "softfloat_ext.hpp"
 
 extern "C" {
+    #include "platform.h"
+    #include "internals.h"
     #include "softfloat.h"
 }
 
@@ -22,4 +24,15 @@ void f128M_trunc(const float128_t *aPtr, float128_t *zPtr) {
     } else {
         f128M_roundToInt(aPtr, softfloat_round_min, false, zPtr);
     } 
+}
+
+float16_t f16_neg(const float16_t a) {
+    union ui16_f16 uZ;
+    uZ.ui = a.v ^ (UINT16_C(1) << 15);
+    return uZ.f;
+}
+
+void f128M_neg(const float128_t *aPtr, float128_t *zPtr) {
+    zPtr->v[indexWord(2,1)] = aPtr->v[indexWord(2,1)] ^ (UINT64_C(1) << 63);
+    zPtr->v[indexWord(2,0)] = aPtr->v[indexWord(2,0)];
 }
\ No newline at end of file
src/stage1/softfloat_ext.hpp
@@ -5,5 +5,8 @@
 
 void f128M_abs(const float128_t *aPtr, float128_t *zPtr);
 void f128M_trunc(const float128_t *aPtr, float128_t *zPtr);
+void f128M_neg(const float128_t *aPtr, float128_t *zPtr);
+
+float16_t f16_neg(const float16_t a);
 
 #endif
\ No newline at end of file