History

Implement proper floating point negation

Using "-0.0 - x" still isn't enough if x is a NaN, so bite the bullet and implement sign-bit flipping via memory. (It's usually not too bad, the -0.0-x method also uses memory for the floating point constant). This way is at least shorter than implementing a new top-level operation for all backends (a negate) that would be unary.

Michael Matz committed 5 years ago

Commit 29d88711 parent 4c951692 files · +48 −13Browse files

Unified · Split

2 files
  1. tccgen.c +41 −13
  2. tests/tcctest.c +7 −0
tccgen.c+41−13
@@ -5880,19 +5880,47 @@ ST_FUNC void unary(void) · 5879 unmodified lines
58805880 unary();
58815881 t = vtop->type.t & VT_BTYPE;
58825882 if (is_float(t)) {
5883− /* In IEEE negate(x) isn't subtract(0,x), but rather
5884− subtract(-0, x). */
5885− vpush(&vtop->type);
5886− if (t == VT_FLOAT)
5887− vtop->c.f = -1.0 * 0.0;
5888− else if (t == VT_DOUBLE)
5889− vtop->c.d = -1.0 * 0.0;
5890− else
5891− vtop->c.ld = -1.0 * 0.0;
5892− } else
5893− vpushi(0);
5894− vswap();
5895− gen_op('-');
5883+ if ((vtop->r & VT_VALMASK) == VT_CONST) {
5884+ /* This is what gen_opif would do if we had a NEG operation. */
5885+ if (t == VT_FLOAT)
5886+ vtop->c.f = -vtop->c.f;
5887+ else if (t == VT_DOUBLE)
5888+ vtop->c.d = -vtop->c.d;
5889+ else
5890+ vtop->c.ld = -vtop->c.ld;
5891+ } else {
5892+ /* In IEEE negate(x) isn't subtract(0,x). Without NaNs it's
5893+ subtract(-0, x), but with them it's really a sign flip
5894+ operation. We implement this with bit manipulation and have
5895+ to do some type reinterpretation for this, which TCC can do
5896+ only via memory. */
5897+ int align, size = type_size(&vtop->type, &align);
5898+ save_reg(gv(RC_TYPE(t)));
5899+ vdup();
5900+ gaddrof();
5901+ vtop->type = char_pointer_type;
5902+ /* Byte of sign bit. For big endian, this would have to
5903+ add zero always. */
5904+#if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_I386)
5905+ /* sizeof long double is 12 or 16 here, but it's
5906+ really the 80bit extended float format. */
5907+ if (t == VT_LDOUBLE)
5908+ size = 10;
5909+#endif
5910+ vpushi(size - 1);
5911+ gen_op('+');
5912+ indir();
5913+ vdup();
5914+ vpushi(0x80); /* flip sign */
5915+ gen_op('^');
5916+ vstore();
5917+ vpop();
5918+ }
5919+ } else {
5920+ vpushi(0);
5921+ vswap();
5922+ gen_op('-');
5923+ }
58965924 break;
58975925 case TOK_LAND:
58985926 if (!gnu_ext)
tests/tcctest.c+7−0
@@ -2227,6 +2227,12 @@ void prefix ## signed_zeros(void) \ · 2226 unmodified lines
22272227 else\
22282228 printf ("x != -y; this is wrong!\n");\
22292229 }\
2230+void prefix ## nan(void)\
2231+{\
2232+ type nan = 0.0/0.0;\
2233+ type nnan = -nan; \
2234+ printf("nantest: " fmt " " fmt "\n", nan, nnan);\
2235+}\
22302236 void prefix ## test(void)\
22312237 {\
22322238 printf("testing '%s'\n", #typename);\
@@ -2237,6 +2243,7 @@ void prefix ## test(void)\ · 4 unmodified lines
22372243 prefix ## fcast(-2334.6);\
22382244 prefix ## call();\
22392245 prefix ## signed_zeros();\
2246+ prefix ## nan();\
22402247 }
22412248
22422249 FTEST(f, float, float, "%f")

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t