diff options
| author | Michael Matz <matz@suse.de> | 2012-05-13 02:21:51 +0200 |
|---|---|---|
| committer | Michael Matz <matz@suse.de> | 2012-05-13 02:21:51 +0200 |
| commit | 2daae0dc99c05a0da9485a67d21a3e47814551a8 (patch) | |
| tree | 4f0cbbb164142023f351cf46cfcc6e67c9596c05 /x86_64-gen.c | |
| parent | 0394caf784124f867d9294dab700e6005e99cea4 (diff) | |
| download | tinycc-2daae0dc99c05a0da9485a67d21a3e47814551a8.tar.gz tinycc-2daae0dc99c05a0da9485a67d21a3e47814551a8.tar.bz2 | |
x86_64: Fix compares with NaNs.
Comparisons with unordered doubles was broken, NaNs always
compare unequal (and unordered) to everything, including
to itself.
Diffstat (limited to 'x86_64-gen.c')
| -rw-r--r-- | x86_64-gen.c | 33 |
1 files changed, 31 insertions, 2 deletions
diff --git a/x86_64-gen.c b/x86_64-gen.c index 0f86b3a..6dfe1e4 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -429,7 +429,18 @@ void load(int r, SValue *sv) gen_modrm(r, VT_LOCAL, sv->sym, fc); } else if (v == VT_CMP) { orex(0,r,0,0); - oad(0xb8 + REG_VALUE(r), 0); /* mov $0, r */ + if ((fc & ~0x100) != TOK_NE) + oad(0xb8 + REG_VALUE(r), 0); /* mov $0, r */ + else + oad(0xb8 + REG_VALUE(r), 1); /* mov $1, r */ + if (fc & 0x100) + { + /* This was a float compare. If the parity bit is + set the result was unordered, meaning false for everything + except TOK_NE, and true for TOK_NE. */ + fc &= ~0x100; + o(0x037a + (REX_BASE(r) << 8)); + } orex(0,r,0, 0x0f); /* setxx %br */ o(fc); o(0xc0 + REG_VALUE(r)); @@ -1161,6 +1172,24 @@ int gtst(int inv, int t) v = vtop->r & VT_VALMASK; if (v == VT_CMP) { /* fast case : can jump directly since flags are set */ + if (vtop->c.i & 0x100) + { + /* This was a float compare. If the parity flag is set + the result was unordered. For anything except != this + means false and we don't jump (anding both conditions). + For != this means true (oring both). + Take care about inverting the test. We need to jump + to our target if the result was unordered and test wasn't NE, + otherwise if unordered we don't want to jump. */ + vtop->c.i &= ~0x100; + if (!inv == (vtop->c.i != TOK_NE)) + o(0x067a); /* jp +6 */ + else + { + g(0x0f); + t = psym(0x8a, t); /* jp t */ + } + } g(0x0f); t = psym((vtop->c.i - 16) ^ inv, t); } else if (v == VT_JMP || v == VT_JMPI) { @@ -1469,7 +1498,7 @@ void gen_opf(int op) vtop--; vtop->r = VT_CMP; - vtop->c.i = op; + vtop->c.i = op | 0x100; } else { /* no memory reference possible for long double operations */ if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { |
