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.
This commit is contained in:
38
tccgen.c
38
tccgen.c
@ -3702,12 +3702,16 @@ ST_FUNC void unary(void)
|
|||||||
break;
|
break;
|
||||||
case '+':
|
case '+':
|
||||||
next();
|
next();
|
||||||
/* in order to force cast, we add zero */
|
|
||||||
unary();
|
unary();
|
||||||
if ((vtop->type.t & VT_BTYPE) == VT_PTR)
|
if ((vtop->type.t & VT_BTYPE) == VT_PTR)
|
||||||
tcc_error("pointer not accepted for unary plus");
|
tcc_error("pointer not accepted for unary plus");
|
||||||
vpushi(0);
|
/* In order to force cast, we add zero, except for floating point
|
||||||
gen_op('+');
|
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;
|
break;
|
||||||
case TOK_SIZEOF:
|
case TOK_SIZEOF:
|
||||||
case TOK_ALIGNOF1:
|
case TOK_ALIGNOF1:
|
||||||
@ -3822,20 +3826,20 @@ ST_FUNC void unary(void)
|
|||||||
next();
|
next();
|
||||||
unary();
|
unary();
|
||||||
t = vtop->type.t & VT_BTYPE;
|
t = vtop->type.t & VT_BTYPE;
|
||||||
/* handle (-)0.0 */
|
if (is_float(t)) {
|
||||||
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST &&
|
/* In IEEE negate(x) isn't subtract(0,x), but rather
|
||||||
is_float(t)) {
|
subtract(-0, x). */
|
||||||
if (t == VT_FLOAT)
|
vpush(&vtop->type);
|
||||||
vtop->c.f = -vtop->c.f;
|
if (t == VT_FLOAT)
|
||||||
else if (t == VT_DOUBLE)
|
vtop->c.f = -0.0f;
|
||||||
vtop->c.d = -vtop->c.d;
|
else if (t == VT_DOUBLE)
|
||||||
else
|
vtop->c.d = -0.0;
|
||||||
vtop->c.ld = -vtop->c.ld;
|
else
|
||||||
} else {
|
vtop->c.ld = -0.0;
|
||||||
vpushi(0);
|
} else
|
||||||
vswap();
|
vpushi(0);
|
||||||
gen_op('-');
|
vswap();
|
||||||
}
|
gen_op('-');
|
||||||
break;
|
break;
|
||||||
case TOK_LAND:
|
case TOK_LAND:
|
||||||
if (!gnu_ext)
|
if (!gnu_ext)
|
||||||
|
|||||||
@ -1699,6 +1699,29 @@ void prefix ## call(void)\
|
|||||||
printf("strto%s: %f\n", #prefix, (double)strto ## prefix("1.2", NULL));\
|
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)\
|
void prefix ## test(void)\
|
||||||
{\
|
{\
|
||||||
printf("testing '%s'\n", #typename);\
|
printf("testing '%s'\n", #typename);\
|
||||||
@ -1708,6 +1731,7 @@ void prefix ## test(void)\
|
|||||||
prefix ## fcast(234.6);\
|
prefix ## fcast(234.6);\
|
||||||
prefix ## fcast(-2334.6);\
|
prefix ## fcast(-2334.6);\
|
||||||
prefix ## call();\
|
prefix ## call();\
|
||||||
|
prefix ## signed_zeros();\
|
||||||
}
|
}
|
||||||
|
|
||||||
FTEST(f, float, float, "%f")
|
FTEST(f, float, float, "%f")
|
||||||
|
|||||||
Reference in New Issue
Block a user