Comparisons with unordered doubles was broken, NaNs always compare unequal (and unordered) to everything, including to itself.
Unified · Split
| @@ -87,6 +87,7 @@ void builtin_test(void); · 86 unmodified lines | |||
| 87 | void weak_test(void); | 87 | void weak_test(void); |
| 88 | void global_data_test(void); | 88 | void global_data_test(void); |
| 89 | void cmp_comparison_test(void); | 89 | void cmp_comparison_test(void); |
| 90 | void math_cmp_test(void); | ||
| 90 | 91 | ||
| 91 | int fib(int n); | 92 | int fib(int n); |
| 92 | void num(int n); | 93 | void 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 | |||
| 2598 | int 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 | |||
| 2610 | void 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 | } | ||
| @@ -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) { |