History

x86_64: Fix compares with NaNs.

Comparisons with unordered doubles was broken, NaNs always compare unequal (and unordered) to everything, including to itself.

Michael Matz committed 14 years ago

Commit 2daae0d1 parent 0394caf2 files · +97 −2Browse files

Unified · Split

2 files
  1. tests/tcctest.c +66 −0
  2. x86_64-gen.c +31 −2
tests/tcctest.c+66−0
@@ -87,6 +87,7 @@ void builtin_test(void); · 86 unmodified lines
87void weak_test(void);87void weak_test(void);
88void global_data_test(void);88void global_data_test(void);
89void cmp_comparison_test(void);89void cmp_comparison_test(void);
90void math_cmp_test(void);
90 91
91int fib(int n);92int fib(int n);
92void num(int n);93void num(int n);
@@ -594,6 +595,7 @@ int main(int argc, char **argv) · 501 unmodified lines
594 weak_test();595 weak_test();
595 global_data_test();596 global_data_test();
596 cmp_comparison_test();597 cmp_comparison_test();
598 math_cmp_test();
597 return 0; 599 return 0;
598}600}
599 601
@@ -2592,3 +2594,67 @@ void cmp_comparison_test(void) · 1992 unmodified lines
2592 compare_comparisons (&s);2594 compare_comparisons (&s);
2593 return 0;2595 return 0;
2594}2596}
2597
2598int fcompare (double a, double b, int code)
2599{
2600 switch (code) {
2601 case 0: return a == b;
2602 case 1: return a != b;
2603 case 2: return a < b;
2604 case 3: return a >= b;
2605 case 4: return a > b;
2606 case 5: return a <= b;
2607 }
2608}
2609
2610void math_cmp_test(void)
2611{
2612 double nan = 0.0/0.0;
2613 double one = 1.0;
2614 double two = 2.0;
2615 int comp = 0;
2616#define bug(a,b,op,iop,part) printf("Test broken: %s %s %s %s %d\n", #a, #b, #op, #iop, part)
2617
2618 /* This asserts that "a op b" is _not_ true, but "a iop b" is true.
2619 And it does this in various ways so that all code generation paths
2620 are checked (generating inverted tests, or non-inverted tests, or
2621 producing a 0/1 value without jumps (that's done in the fcompare
2622 function). */
2623#define FCMP(a,b,op,iop,code) \
2624 if (fcompare (a,b,code)) \
2625 bug (a,b,op,iop,1); \
2626 if (a op b) \
2627 bug (a,b,op,iop,2); \
2628 if (a iop b) \
2629 ; \
2630 else \
2631 bug (a,b,op,iop,3); \
2632 if ((a op b) || comp) \
2633 bug (a,b,op,iop,4); \
2634 if ((a iop b) || comp) \
2635 ; \
2636 else \
2637 bug (a,b,op,iop,5);
2638
2639 /* Equality tests. */
2640 FCMP(nan, nan, ==, !=, 0);
2641 FCMP(one, two, ==, !=, 0);
2642 FCMP(one, one, !=, ==, 1);
2643 /* Non-equality is a bit special. */
2644 if (!fcompare (nan, nan, 1))
2645 bug (nan, nan, !=, ==, 6);
2646
2647 /* Relational tests on numbers. */
2648 FCMP(two, one, <, >=, 2);
2649 FCMP(one, two, >=, <, 3);
2650 FCMP(one, two, >, <=, 4);
2651 FCMP(two, one, <=, >, 5);
2652
2653 /* Relational tests on NaNs. Note that the inverse op here is
2654 always !=, there's no operator in C that is equivalent to !(a < b),
2655 when NaNs are involved, same for the other relational ops. */
2656 FCMP(nan, nan, <, !=, 2);
2657 FCMP(nan, nan, >=, !=, 3);
2658 FCMP(nan, nan, >, !=, 4);
2659 FCMP(nan, nan, <=, !=, 5);
2660}
x86_64-gen.c+31−2
@@ -429,7 +429,18 @@ void load(int r, SValue *sv) · 428 unmodified lines
429 gen_modrm(r, VT_LOCAL, sv->sym, fc);429 gen_modrm(r, VT_LOCAL, sv->sym, fc);
430 } else if (v == VT_CMP) {430 } else if (v == VT_CMP) {
431 orex(0,r,0,0);431 orex(0,r,0,0);
432 oad(0xb8 + REG_VALUE(r), 0); /* mov $0, r */432 if ((fc & ~0x100) != TOK_NE)
433 oad(0xb8 + REG_VALUE(r), 0); /* mov $0, r */
434 else
435 oad(0xb8 + REG_VALUE(r), 1); /* mov $1, r */
436 if (fc & 0x100)
437 {
438 /* This was a float compare. If the parity bit is
439 set the result was unordered, meaning false for everything
440 except TOK_NE, and true for TOK_NE. */
441 fc &= ~0x100;
442 o(0x037a + (REX_BASE(r) << 8));
443 }
433 orex(0,r,0, 0x0f); /* setxx %br */444 orex(0,r,0, 0x0f); /* setxx %br */
434 o(fc);445 o(fc);
435 o(0xc0 + REG_VALUE(r));446 o(0xc0 + REG_VALUE(r));
@@ -1161,6 +1172,24 @@ int gtst(int inv, int t) · 725 unmodified lines
1161 v = vtop->r & VT_VALMASK;1172 v = vtop->r & VT_VALMASK;
1162 if (v == VT_CMP) {1173 if (v == VT_CMP) {
1163 /* fast case : can jump directly since flags are set */1174 /* fast case : can jump directly since flags are set */
1175 if (vtop->c.i & 0x100)
1176 {
1177 /* This was a float compare. If the parity flag is set
1178 the result was unordered. For anything except != this
1179 means false and we don't jump (anding both conditions).
1180 For != this means true (oring both).
1181 Take care about inverting the test. We need to jump
1182 to our target if the result was unordered and test wasn't NE,
1183 otherwise if unordered we don't want to jump. */
1184 vtop->c.i &= ~0x100;
1185 if (!inv == (vtop->c.i != TOK_NE))
1186 o(0x067a); /* jp +6 */
1187 else
1188 {
1189 g(0x0f);
1190 t = psym(0x8a, t); /* jp t */
1191 }
1192 }
1164 g(0x0f);1193 g(0x0f);
1165 t = psym((vtop->c.i - 16) ^ inv, t);1194 t = psym((vtop->c.i - 16) ^ inv, t);
1166 } else if (v == VT_JMP || v == VT_JMPI) {1195 } else if (v == VT_JMP || v == VT_JMPI) {
@@ -1469,7 +1498,7 @@ void gen_opf(int op) · 302 unmodified lines
1469 1498
1470 vtop--;1499 vtop--;
1471 vtop->r = VT_CMP;1500 vtop->r = VT_CMP;
1472 vtop->c.i = op;1501 vtop->c.i = op | 0x100;
1473 } else {1502 } else {
1474 /* no memory reference possible for long double operations */1503 /* no memory reference possible for long double operations */
1475 if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {1504 if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {

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