From 05c9b76131e9d0a2e1b011eeb70ad7897efc9084 Mon Sep 17 00:00:00 2001 From: Michael Matz Date: Sun, 12 Jan 2014 04:44:27 +0100 Subject: [PATCH] Fix floating point unary minus and plus negate(x) is subtract(-0,x), not subtract(+0,x), which makes a difference with signed zeros. Also +x was expressed as x+0, in order for the integer promotions to happen, but also mangles signed zeros, so just don't do that with floating types. --- tccgen.c | 38 +++++++++++++++++++++----------------- tests/tcctest.c | 24 ++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/tccgen.c b/tccgen.c index 4d7e1fbd..6a5ba03b 100644 --- a/tccgen.c +++ b/tccgen.c @@ -3702,12 +3702,16 @@ ST_FUNC void unary(void) break; case '+': next(); - /* in order to force cast, we add zero */ unary(); if ((vtop->type.t & VT_BTYPE) == VT_PTR) tcc_error("pointer not accepted for unary plus"); - vpushi(0); - gen_op('+'); + /* In order to force cast, we add zero, except for floating point + where we really need an noop (otherwise -0.0 will be transformed + into +0.0). */ + if (!is_float(vtop->type.t)) { + vpushi(0); + gen_op('+'); + } break; case TOK_SIZEOF: case TOK_ALIGNOF1: @@ -3822,20 +3826,20 @@ ST_FUNC void unary(void) next(); unary(); t = vtop->type.t & VT_BTYPE; - /* handle (-)0.0 */ - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST && - is_float(t)) { - if (t == VT_FLOAT) - vtop->c.f = -vtop->c.f; - else if (t == VT_DOUBLE) - vtop->c.d = -vtop->c.d; - else - vtop->c.ld = -vtop->c.ld; - } else { - vpushi(0); - vswap(); - gen_op('-'); - } + if (is_float(t)) { + /* In IEEE negate(x) isn't subtract(0,x), but rather + subtract(-0, x). */ + vpush(&vtop->type); + if (t == VT_FLOAT) + vtop->c.f = -0.0f; + else if (t == VT_DOUBLE) + vtop->c.d = -0.0; + else + vtop->c.ld = -0.0; + } else + vpushi(0); + vswap(); + gen_op('-'); break; case TOK_LAND: if (!gnu_ext) diff --git a/tests/tcctest.c b/tests/tcctest.c index eb284f02..d96c5a1e 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -1699,6 +1699,29 @@ void prefix ## call(void)\ printf("strto%s: %f\n", #prefix, (double)strto ## prefix("1.2", NULL));\ }\ \ +void prefix ## signed_zeros(void) \ +{\ + type x = 0.0, y = -0.0, n, p;\ + if (x == y)\ + printf ("Test 1.0 / x != 1.0 / y returns %d (should be 1).\n",\ + 1.0 / x != 1.0 / y);\ + else\ + printf ("x != y; this is wrong!\n");\ +\ + n = -x;\ + if (x == n)\ + printf ("Test 1.0 / x != 1.0 / -x returns %d (should be 1).\n",\ + 1.0 / x != 1.0 / n);\ + else\ + printf ("x != -x; this is wrong!\n");\ +\ + p = +y;\ + if (x == p)\ + printf ("Test 1.0 / x != 1.0 / +y returns %d (should be 1).\n",\ + 1.0 / x != 1.0 / p);\ + else\ + printf ("x != +y; this is wrong!\n");\ +}\ void prefix ## test(void)\ {\ printf("testing '%s'\n", #typename);\ @@ -1708,6 +1731,7 @@ void prefix ## test(void)\ prefix ## fcast(234.6);\ prefix ## fcast(-2334.6);\ prefix ## call();\ + prefix ## signed_zeros();\ } FTEST(f, float, float, "%f")