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
8787 void weak_test(void);
8888 void global_data_test(void);
8989 void cmp_comparison_test(void);
90+void math_cmp_test(void);
9091
9192 int fib(int n);
9293 void num(int n);
@@ -594,6 +595,7 @@ int main(int argc, char **argv) · 501 unmodified lines
594595 weak_test();
595596 global_data_test();
596597 cmp_comparison_test();
598+ math_cmp_test();
597599 return 0;
598600 }
599601
@@ -2592,3 +2594,67 @@ void cmp_comparison_test(void) · 1992 unmodified lines
25922594 compare_comparisons (&s);
25932595 return 0;
25942596 }
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+}
x86_64-gen.c+31−2
@@ -429,7 +429,18 @@ void load(int r, SValue *sv) · 428 unmodified lines
429429 gen_modrm(r, VT_LOCAL, sv->sym, fc);
430430 } else if (v == VT_CMP) {
431431 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+ }
433444 orex(0,r,0, 0x0f); /* setxx %br */
434445 o(fc);
435446 o(0xc0 + REG_VALUE(r));
@@ -1161,6 +1172,24 @@ int gtst(int inv, int t) · 725 unmodified lines
11611172 v = vtop->r & VT_VALMASK;
11621173 if (v == VT_CMP) {
11631174 /* 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+ }
11641193 g(0x0f);
11651194 t = psym((vtop->c.i - 16) ^ inv, t);
11661195 } else if (v == VT_JMP || v == VT_JMPI) {
@@ -1469,7 +1498,7 @@ void gen_opf(int op) · 302 unmodified lines
14691498
14701499 vtop--;
14711500 vtop->r = VT_CMP;
1472− vtop->c.i = op;
1501+ vtop->c.i = op | 0x100;
14731502 } else {
14741503 /* no memory reference possible for long double operations */
14751504 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