diff options
| author | Peter Maydell | 2020-05-15 20:51:16 +0200 |
|---|---|---|
| committer | Peter Maydell | 2020-05-15 20:51:16 +0200 |
| commit | debe78ce14bf8f8940c2bdf3ef387505e9e035a9 (patch) | |
| tree | b51a6862e2ea9ddeaf179d2526de717ffa336c66 /tests | |
| parent | Merge remote-tracking branch 'remotes/stsquad/tags/pull-testing-tcg-plugins-1... (diff) | |
| parent | softfloat: fix floatx80 pseudo-denormal round to integer (diff) | |
| download | qemu-debe78ce14bf8f8940c2bdf3ef387505e9e035a9.tar.gz qemu-debe78ce14bf8f8940c2bdf3ef387505e9e035a9.tar.xz qemu-debe78ce14bf8f8940c2bdf3ef387505e9e035a9.zip | |
Merge remote-tracking branch 'remotes/rth/tags/pull-fpu-20200515' into staging
floatx80 x87 pseudo-denormal fixes
# gpg: Signature made Fri 15 May 2020 19:10:27 BST
# gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F
# gpg: issuer "richard.henderson@linaro.org"
# gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [full]
# Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A 05C0 64DF 38E8 AF7E 215F
* remotes/rth/tags/pull-fpu-20200515:
softfloat: fix floatx80 pseudo-denormal round to integer
softfloat: fix floatx80 pseudo-denormal comparisons
softfloat: fix floatx80 pseudo-denormal addition / subtraction
softfloat: silence sNaN for conversions to/from floatx80
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/tcg/i386/test-i386-pseudo-denormal.c | 38 | ||||
| -rw-r--r-- | tests/tcg/i386/test-i386-snan-convert.c | 63 |
2 files changed, 101 insertions, 0 deletions
diff --git a/tests/tcg/i386/test-i386-pseudo-denormal.c b/tests/tcg/i386/test-i386-pseudo-denormal.c new file mode 100644 index 0000000000..00d510cf4a --- /dev/null +++ b/tests/tcg/i386/test-i386-pseudo-denormal.c @@ -0,0 +1,38 @@ +/* Test pseudo-denormal operations. */ + +#include <stdint.h> +#include <stdio.h> + +union u { + struct { uint64_t sig; uint16_t sign_exp; } s; + long double ld; +}; + +volatile union u ld_pseudo_m16382 = { .s = { UINT64_C(1) << 63, 0 } }; + +volatile long double ld_res; + +int main(void) +{ + short cw; + int ret = 0; + ld_res = ld_pseudo_m16382.ld + ld_pseudo_m16382.ld; + if (ld_res != 0x1p-16381L) { + printf("FAIL: pseudo-denormal add\n"); + ret = 1; + } + if (ld_pseudo_m16382.ld != 0x1p-16382L) { + printf("FAIL: pseudo-denormal compare\n"); + ret = 1; + } + /* Set round-upward. */ + __asm__ volatile ("fnstcw %0" : "=m" (cw)); + cw = (cw & ~0xc00) | 0x800; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ ("frndint" : "=t" (ld_res) : "0" (ld_pseudo_m16382.ld)); + if (ld_res != 1.0L) { + printf("FAIL: pseudo-denormal round-to-integer\n"); + ret = 1; + } + return ret; +} diff --git a/tests/tcg/i386/test-i386-snan-convert.c b/tests/tcg/i386/test-i386-snan-convert.c new file mode 100644 index 0000000000..ed6d535ce2 --- /dev/null +++ b/tests/tcg/i386/test-i386-snan-convert.c @@ -0,0 +1,63 @@ +/* Test conversions of signaling NaNs to and from long double. */ + +#include <stdint.h> +#include <stdio.h> + +volatile float f_res; +volatile double d_res; +volatile long double ld_res; + +volatile float f_snan = __builtin_nansf(""); +volatile double d_snan = __builtin_nans(""); +volatile long double ld_snan = __builtin_nansl(""); + +int issignaling_f(float x) +{ + union { float f; uint32_t u; } u = { .f = x }; + return (u.u & 0x7fffffff) > 0x7f800000 && (u.u & 0x400000) == 0; +} + +int issignaling_d(double x) +{ + union { double d; uint64_t u; } u = { .d = x }; + return (((u.u & UINT64_C(0x7fffffffffffffff)) > + UINT64_C(0x7ff0000000000000)) && + (u.u & UINT64_C(0x8000000000000)) == 0); +} + +int issignaling_ld(long double x) +{ + union { + long double ld; + struct { uint64_t sig; uint16_t sign_exp; } s; + } u = { .ld = x }; + return ((u.s.sign_exp & 0x7fff) == 0x7fff && + (u.s.sig >> 63) != 0 && + (u.s.sig & UINT64_C(0x4000000000000000)) == 0); +} + +int main(void) +{ + int ret = 0; + ld_res = f_snan; + if (issignaling_ld(ld_res)) { + printf("FAIL: float -> long double\n"); + ret = 1; + } + ld_res = d_snan; + if (issignaling_ld(ld_res)) { + printf("FAIL: double -> long double\n"); + ret = 1; + } + f_res = ld_snan; + if (issignaling_d(f_res)) { + printf("FAIL: long double -> float\n"); + ret = 1; + } + d_res = ld_snan; + if (issignaling_d(d_res)) { + printf("FAIL: long double -> double\n"); + ret = 1; + } + return ret; +} |
