target/i386: fix floating-point load-constant rounding
The implementations of the fldl2t, fldl2e, fldpi, fldlg2 and fldln2 instructions load fixed constants independent of the rounding mode. Fix them to load a value correctly rounded for the current rounding mode (but always rounded to 64-bit precision independent of the precision control, and without setting "inexact") as specified. Signed-off-by: Joseph Myers <joseph@codesourcery.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <alpine.DEB.2.21.2005132348310.11687@digraph.polyomino.org.uk> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
5579b524b0
commit
80b4008c80
|
@ -59,8 +59,13 @@
|
||||||
#define FPUC_EM 0x3f
|
#define FPUC_EM 0x3f
|
||||||
|
|
||||||
#define floatx80_lg2 make_floatx80(0x3ffd, 0x9a209a84fbcff799LL)
|
#define floatx80_lg2 make_floatx80(0x3ffd, 0x9a209a84fbcff799LL)
|
||||||
|
#define floatx80_lg2_d make_floatx80(0x3ffd, 0x9a209a84fbcff798LL)
|
||||||
#define floatx80_l2e make_floatx80(0x3fff, 0xb8aa3b295c17f0bcLL)
|
#define floatx80_l2e make_floatx80(0x3fff, 0xb8aa3b295c17f0bcLL)
|
||||||
|
#define floatx80_l2e_d make_floatx80(0x3fff, 0xb8aa3b295c17f0bbLL)
|
||||||
#define floatx80_l2t make_floatx80(0x4000, 0xd49a784bcd1b8afeLL)
|
#define floatx80_l2t make_floatx80(0x4000, 0xd49a784bcd1b8afeLL)
|
||||||
|
#define floatx80_l2t_u make_floatx80(0x4000, 0xd49a784bcd1b8affLL)
|
||||||
|
#define floatx80_ln2_d make_floatx80(0x3ffe, 0xb17217f7d1cf79abLL)
|
||||||
|
#define floatx80_pi_d make_floatx80(0x4000, 0xc90fdaa22168c234LL)
|
||||||
|
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
static qemu_irq ferr_irq;
|
static qemu_irq ferr_irq;
|
||||||
|
@ -544,27 +549,66 @@ void helper_fld1_ST0(CPUX86State *env)
|
||||||
|
|
||||||
void helper_fldl2t_ST0(CPUX86State *env)
|
void helper_fldl2t_ST0(CPUX86State *env)
|
||||||
{
|
{
|
||||||
|
switch (env->fpuc & FPU_RC_MASK) {
|
||||||
|
case FPU_RC_UP:
|
||||||
|
ST0 = floatx80_l2t_u;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
ST0 = floatx80_l2t;
|
ST0 = floatx80_l2t;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_fldl2e_ST0(CPUX86State *env)
|
void helper_fldl2e_ST0(CPUX86State *env)
|
||||||
{
|
{
|
||||||
|
switch (env->fpuc & FPU_RC_MASK) {
|
||||||
|
case FPU_RC_DOWN:
|
||||||
|
case FPU_RC_CHOP:
|
||||||
|
ST0 = floatx80_l2e_d;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
ST0 = floatx80_l2e;
|
ST0 = floatx80_l2e;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_fldpi_ST0(CPUX86State *env)
|
void helper_fldpi_ST0(CPUX86State *env)
|
||||||
{
|
{
|
||||||
|
switch (env->fpuc & FPU_RC_MASK) {
|
||||||
|
case FPU_RC_DOWN:
|
||||||
|
case FPU_RC_CHOP:
|
||||||
|
ST0 = floatx80_pi_d;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
ST0 = floatx80_pi;
|
ST0 = floatx80_pi;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_fldlg2_ST0(CPUX86State *env)
|
void helper_fldlg2_ST0(CPUX86State *env)
|
||||||
{
|
{
|
||||||
|
switch (env->fpuc & FPU_RC_MASK) {
|
||||||
|
case FPU_RC_DOWN:
|
||||||
|
case FPU_RC_CHOP:
|
||||||
|
ST0 = floatx80_lg2_d;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
ST0 = floatx80_lg2;
|
ST0 = floatx80_lg2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_fldln2_ST0(CPUX86State *env)
|
void helper_fldln2_ST0(CPUX86State *env)
|
||||||
{
|
{
|
||||||
|
switch (env->fpuc & FPU_RC_MASK) {
|
||||||
|
case FPU_RC_DOWN:
|
||||||
|
case FPU_RC_CHOP:
|
||||||
|
ST0 = floatx80_ln2_d;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
ST0 = floatx80_ln2;
|
ST0 = floatx80_ln2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_fldz_ST0(CPUX86State *env)
|
void helper_fldz_ST0(CPUX86State *env)
|
||||||
|
|
199
tests/tcg/i386/test-i386-fldcst.c
Normal file
199
tests/tcg/i386/test-i386-fldcst.c
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
/* Test instructions loading floating-point constants. */
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
volatile long double ld_res;
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
short cw;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
/* Round to nearest. */
|
||||||
|
__asm__ volatile ("fnstcw %0" : "=m" (cw));
|
||||||
|
cw = (cw & ~0xc00) | 0x000;
|
||||||
|
__asm__ volatile ("fldcw %0" : : "m" (cw));
|
||||||
|
__asm__ volatile ("fldl2t" : "=t" (ld_res));
|
||||||
|
if (ld_res != 0x3.5269e12f346e2bf8p+0L) {
|
||||||
|
printf("FAIL: fldl2t N\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
/* Round downward. */
|
||||||
|
__asm__ volatile ("fnstcw %0" : "=m" (cw));
|
||||||
|
cw = (cw & ~0xc00) | 0x400;
|
||||||
|
__asm__ volatile ("fldcw %0" : : "m" (cw));
|
||||||
|
__asm__ volatile ("fldl2t" : "=t" (ld_res));
|
||||||
|
if (ld_res != 0x3.5269e12f346e2bf8p+0L) {
|
||||||
|
printf("FAIL: fldl2t D\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
/* Round toward zero. */
|
||||||
|
__asm__ volatile ("fnstcw %0" : "=m" (cw));
|
||||||
|
cw = (cw & ~0xc00) | 0xc00;
|
||||||
|
__asm__ volatile ("fldcw %0" : : "m" (cw));
|
||||||
|
__asm__ volatile ("fldl2t" : "=t" (ld_res));
|
||||||
|
if (ld_res != 0x3.5269e12f346e2bf8p+0L) {
|
||||||
|
printf("FAIL: fldl2t Z\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
/* Round upward. */
|
||||||
|
__asm__ volatile ("fnstcw %0" : "=m" (cw));
|
||||||
|
cw = (cw & ~0xc00) | 0x800;
|
||||||
|
__asm__ volatile ("fldcw %0" : : "m" (cw));
|
||||||
|
__asm__ volatile ("fldl2t" : "=t" (ld_res));
|
||||||
|
if (ld_res != 0x3.5269e12f346e2bfcp+0L) {
|
||||||
|
printf("FAIL: fldl2t U\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Round to nearest. */
|
||||||
|
__asm__ volatile ("fnstcw %0" : "=m" (cw));
|
||||||
|
cw = (cw & ~0xc00) | 0x000;
|
||||||
|
__asm__ volatile ("fldcw %0" : : "m" (cw));
|
||||||
|
__asm__ volatile ("fldl2e" : "=t" (ld_res));
|
||||||
|
if (ld_res != 0x1.71547652b82fe178p+0L) {
|
||||||
|
printf("FAIL: fldl2e N\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
/* Round downward. */
|
||||||
|
__asm__ volatile ("fnstcw %0" : "=m" (cw));
|
||||||
|
cw = (cw & ~0xc00) | 0x400;
|
||||||
|
__asm__ volatile ("fldcw %0" : : "m" (cw));
|
||||||
|
__asm__ volatile ("fldl2e" : "=t" (ld_res));
|
||||||
|
if (ld_res != 0x1.71547652b82fe176p+0L) {
|
||||||
|
printf("FAIL: fldl2e D\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
/* Round toward zero. */
|
||||||
|
__asm__ volatile ("fnstcw %0" : "=m" (cw));
|
||||||
|
cw = (cw & ~0xc00) | 0xc00;
|
||||||
|
__asm__ volatile ("fldcw %0" : : "m" (cw));
|
||||||
|
__asm__ volatile ("fldl2e" : "=t" (ld_res));
|
||||||
|
if (ld_res != 0x1.71547652b82fe176p+0L) {
|
||||||
|
printf("FAIL: fldl2e Z\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
/* Round upward. */
|
||||||
|
__asm__ volatile ("fnstcw %0" : "=m" (cw));
|
||||||
|
cw = (cw & ~0xc00) | 0x800;
|
||||||
|
__asm__ volatile ("fldcw %0" : : "m" (cw));
|
||||||
|
__asm__ volatile ("fldl2e" : "=t" (ld_res));
|
||||||
|
if (ld_res != 0x1.71547652b82fe178p+0L) {
|
||||||
|
printf("FAIL: fldl2e U\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Round to nearest. */
|
||||||
|
__asm__ volatile ("fnstcw %0" : "=m" (cw));
|
||||||
|
cw = (cw & ~0xc00) | 0x000;
|
||||||
|
__asm__ volatile ("fldcw %0" : : "m" (cw));
|
||||||
|
__asm__ volatile ("fldpi" : "=t" (ld_res));
|
||||||
|
if (ld_res != 0x3.243f6a8885a308d4p+0L) {
|
||||||
|
printf("FAIL: fldpi N\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
/* Round downward. */
|
||||||
|
__asm__ volatile ("fnstcw %0" : "=m" (cw));
|
||||||
|
cw = (cw & ~0xc00) | 0x400;
|
||||||
|
__asm__ volatile ("fldcw %0" : : "m" (cw));
|
||||||
|
__asm__ volatile ("fldpi" : "=t" (ld_res));
|
||||||
|
if (ld_res != 0x3.243f6a8885a308dp+0L) {
|
||||||
|
printf("FAIL: fldpi D\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
/* Round toward zero. */
|
||||||
|
__asm__ volatile ("fnstcw %0" : "=m" (cw));
|
||||||
|
cw = (cw & ~0xc00) | 0xc00;
|
||||||
|
__asm__ volatile ("fldcw %0" : : "m" (cw));
|
||||||
|
__asm__ volatile ("fldpi" : "=t" (ld_res));
|
||||||
|
if (ld_res != 0x3.243f6a8885a308dp+0L) {
|
||||||
|
printf("FAIL: fldpi Z\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
/* Round upward. */
|
||||||
|
__asm__ volatile ("fnstcw %0" : "=m" (cw));
|
||||||
|
cw = (cw & ~0xc00) | 0x800;
|
||||||
|
__asm__ volatile ("fldcw %0" : : "m" (cw));
|
||||||
|
__asm__ volatile ("fldpi" : "=t" (ld_res));
|
||||||
|
if (ld_res != 0x3.243f6a8885a308d4p+0L) {
|
||||||
|
printf("FAIL: fldpi U\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Round to nearest. */
|
||||||
|
__asm__ volatile ("fnstcw %0" : "=m" (cw));
|
||||||
|
cw = (cw & ~0xc00) | 0x000;
|
||||||
|
__asm__ volatile ("fldcw %0" : : "m" (cw));
|
||||||
|
__asm__ volatile ("fldlg2" : "=t" (ld_res));
|
||||||
|
if (ld_res != 0x4.d104d427de7fbcc8p-4L) {
|
||||||
|
printf("FAIL: fldlg2 N\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
/* Round downward. */
|
||||||
|
__asm__ volatile ("fnstcw %0" : "=m" (cw));
|
||||||
|
cw = (cw & ~0xc00) | 0x400;
|
||||||
|
__asm__ volatile ("fldcw %0" : : "m" (cw));
|
||||||
|
__asm__ volatile ("fldlg2" : "=t" (ld_res));
|
||||||
|
if (ld_res != 0x4.d104d427de7fbccp-4L) {
|
||||||
|
printf("FAIL: fldlg2 D\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
/* Round toward zero. */
|
||||||
|
__asm__ volatile ("fnstcw %0" : "=m" (cw));
|
||||||
|
cw = (cw & ~0xc00) | 0xc00;
|
||||||
|
__asm__ volatile ("fldcw %0" : : "m" (cw));
|
||||||
|
__asm__ volatile ("fldlg2" : "=t" (ld_res));
|
||||||
|
if (ld_res != 0x4.d104d427de7fbccp-4L) {
|
||||||
|
printf("FAIL: fldlg2 Z\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
/* Round upward. */
|
||||||
|
__asm__ volatile ("fnstcw %0" : "=m" (cw));
|
||||||
|
cw = (cw & ~0xc00) | 0x800;
|
||||||
|
__asm__ volatile ("fldcw %0" : : "m" (cw));
|
||||||
|
__asm__ volatile ("fldlg2" : "=t" (ld_res));
|
||||||
|
if (ld_res != 0x4.d104d427de7fbcc8p-4L) {
|
||||||
|
printf("FAIL: fldlg2 U\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Round to nearest. */
|
||||||
|
__asm__ volatile ("fnstcw %0" : "=m" (cw));
|
||||||
|
cw = (cw & ~0xc00) | 0x000;
|
||||||
|
__asm__ volatile ("fldcw %0" : : "m" (cw));
|
||||||
|
__asm__ volatile ("fldln2" : "=t" (ld_res));
|
||||||
|
if (ld_res != 0xb.17217f7d1cf79acp-4L) {
|
||||||
|
printf("FAIL: fldln2 N\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
/* Round downward. */
|
||||||
|
__asm__ volatile ("fnstcw %0" : "=m" (cw));
|
||||||
|
cw = (cw & ~0xc00) | 0x400;
|
||||||
|
__asm__ volatile ("fldcw %0" : : "m" (cw));
|
||||||
|
__asm__ volatile ("fldln2" : "=t" (ld_res));
|
||||||
|
if (ld_res != 0xb.17217f7d1cf79abp-4L) {
|
||||||
|
printf("FAIL: fldln2 D\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
/* Round toward zero. */
|
||||||
|
__asm__ volatile ("fnstcw %0" : "=m" (cw));
|
||||||
|
cw = (cw & ~0xc00) | 0xc00;
|
||||||
|
__asm__ volatile ("fldcw %0" : : "m" (cw));
|
||||||
|
__asm__ volatile ("fldln2" : "=t" (ld_res));
|
||||||
|
if (ld_res != 0xb.17217f7d1cf79abp-4L) {
|
||||||
|
printf("FAIL: fldln2 Z\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
/* Round upward. */
|
||||||
|
__asm__ volatile ("fnstcw %0" : "=m" (cw));
|
||||||
|
cw = (cw & ~0xc00) | 0x800;
|
||||||
|
__asm__ volatile ("fldcw %0" : : "m" (cw));
|
||||||
|
__asm__ volatile ("fldln2" : "=t" (ld_res));
|
||||||
|
if (ld_res != 0xb.17217f7d1cf79acp-4L) {
|
||||||
|
printf("FAIL: fldln2 U\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
Loading…
Reference in a new issue