mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-12-04 09:14:04 +08:00
Fix IA-64 problems with denorms getting clobbered by type conversions.
PR libgcj/26483 * src/ia64/ffi.c (stf_spill, ldf_fill): Rewrite as macros. (hfa_type_load): Call stf_spill. (hfa_type_store): Call ldf_fill. (ffi_call): Adjust calls to above routines. Add local temps for macro result. From-SVN: r112900
This commit is contained in:
parent
3f1d352611
commit
86066f9bd4
@ -1,3 +1,12 @@
|
|||||||
|
2006-04-12 James E Wilson <wilson@specifix.com>
|
||||||
|
|
||||||
|
PR libgcj/26483
|
||||||
|
* src/ia64/ffi.c (stf_spill, ldf_fill): Rewrite as macros.
|
||||||
|
(hfa_type_load): Call stf_spill.
|
||||||
|
(hfa_type_store): Call ldf_fill.
|
||||||
|
(ffi_call): Adjust calls to above routines. Add local temps for
|
||||||
|
macro result.
|
||||||
|
|
||||||
2006-04-10 Matthias Klose <doko@debian.org>
|
2006-04-10 Matthias Klose <doko@debian.org>
|
||||||
|
|
||||||
* testsuite/lib/libffi-dg.exp (libffi-init): Recognize multilib
|
* testsuite/lib/libffi-dg.exp (libffi-init): Recognize multilib
|
||||||
|
@ -69,24 +69,19 @@ endian_adjust (void *addr, size_t len)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Store VALUE to ADDR in the current cpu implementation's fp spill format. */
|
/* Store VALUE to ADDR in the current cpu implementation's fp spill format.
|
||||||
|
This is a macro instead of a function, so that it works for all 3 floating
|
||||||
|
point types without type conversions. Type conversion to long double breaks
|
||||||
|
the denorm support. */
|
||||||
|
|
||||||
static inline void
|
#define stf_spill(addr, value) \
|
||||||
stf_spill(fpreg *addr, __float80 value)
|
|
||||||
{
|
|
||||||
asm ("stf.spill %0 = %1%P0" : "=m" (*addr) : "f"(value));
|
asm ("stf.spill %0 = %1%P0" : "=m" (*addr) : "f"(value));
|
||||||
}
|
|
||||||
|
|
||||||
/* Load a value from ADDR, which is in the current cpu implementation's
|
/* Load a value from ADDR, which is in the current cpu implementation's
|
||||||
fp spill format. */
|
fp spill format. As above, this must also be a macro. */
|
||||||
|
|
||||||
static inline __float80
|
#define ldf_fill(result, addr) \
|
||||||
ldf_fill(fpreg *addr)
|
asm ("ldf.fill %0 = %1%P1" : "=f"(result) : "m"(*addr));
|
||||||
{
|
|
||||||
__float80 ret;
|
|
||||||
asm ("ldf.fill %0 = %1%P1" : "=f"(ret) : "m"(*addr));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return the size of the C type associated with with TYPE. Which will
|
/* Return the size of the C type associated with with TYPE. Which will
|
||||||
be one of the FFI_IA64_TYPE_HFA_* values. */
|
be one of the FFI_IA64_TYPE_HFA_* values. */
|
||||||
@ -110,17 +105,20 @@ hfa_type_size (int type)
|
|||||||
/* Load from ADDR a value indicated by TYPE. Which will be one of
|
/* Load from ADDR a value indicated by TYPE. Which will be one of
|
||||||
the FFI_IA64_TYPE_HFA_* values. */
|
the FFI_IA64_TYPE_HFA_* values. */
|
||||||
|
|
||||||
static __float80
|
static void
|
||||||
hfa_type_load (int type, void *addr)
|
hfa_type_load (fpreg *fpaddr, int type, void *addr)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case FFI_IA64_TYPE_HFA_FLOAT:
|
case FFI_IA64_TYPE_HFA_FLOAT:
|
||||||
return *(float *) addr;
|
stf_spill (fpaddr, *(float *) addr);
|
||||||
|
return;
|
||||||
case FFI_IA64_TYPE_HFA_DOUBLE:
|
case FFI_IA64_TYPE_HFA_DOUBLE:
|
||||||
return *(double *) addr;
|
stf_spill (fpaddr, *(double *) addr);
|
||||||
|
return;
|
||||||
case FFI_IA64_TYPE_HFA_LDOUBLE:
|
case FFI_IA64_TYPE_HFA_LDOUBLE:
|
||||||
return *(__float80 *) addr;
|
stf_spill (fpaddr, *(__float80 *) addr);
|
||||||
|
return;
|
||||||
default:
|
default:
|
||||||
abort ();
|
abort ();
|
||||||
}
|
}
|
||||||
@ -130,19 +128,31 @@ hfa_type_load (int type, void *addr)
|
|||||||
the FFI_IA64_TYPE_HFA_* values. */
|
the FFI_IA64_TYPE_HFA_* values. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
hfa_type_store (int type, void *addr, __float80 value)
|
hfa_type_store (int type, void *addr, fpreg *fpaddr)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case FFI_IA64_TYPE_HFA_FLOAT:
|
case FFI_IA64_TYPE_HFA_FLOAT:
|
||||||
*(float *) addr = value;
|
{
|
||||||
break;
|
float result;
|
||||||
|
ldf_fill (result, fpaddr);
|
||||||
|
*(float *) addr = result;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case FFI_IA64_TYPE_HFA_DOUBLE:
|
case FFI_IA64_TYPE_HFA_DOUBLE:
|
||||||
*(double *) addr = value;
|
{
|
||||||
break;
|
double result;
|
||||||
|
ldf_fill (result, fpaddr);
|
||||||
|
*(double *) addr = result;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case FFI_IA64_TYPE_HFA_LDOUBLE:
|
case FFI_IA64_TYPE_HFA_LDOUBLE:
|
||||||
*(__float80 *) addr = value;
|
{
|
||||||
break;
|
__float80 result;
|
||||||
|
ldf_fill (result, fpaddr);
|
||||||
|
*(__float80 *) addr = result;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
abort ();
|
abort ();
|
||||||
}
|
}
|
||||||
@ -351,8 +361,8 @@ ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
|
|||||||
&& offset < size
|
&& offset < size
|
||||||
&& gp_offset < 8 * 8)
|
&& gp_offset < 8 * 8)
|
||||||
{
|
{
|
||||||
stf_spill (&stack->fp_regs[fpcount],
|
hfa_type_load (&stack->fp_regs[fpcount], hfa_type,
|
||||||
hfa_type_load (hfa_type, avalue[i] + offset));
|
avalue[i] + offset);
|
||||||
offset += hfa_size;
|
offset += hfa_size;
|
||||||
gp_offset += hfa_size;
|
gp_offset += hfa_size;
|
||||||
fpcount += 1;
|
fpcount += 1;
|
||||||
@ -475,9 +485,11 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
|
|||||||
case FFI_TYPE_FLOAT:
|
case FFI_TYPE_FLOAT:
|
||||||
if (gpcount < 8 && fpcount < 8)
|
if (gpcount < 8 && fpcount < 8)
|
||||||
{
|
{
|
||||||
void *addr = &stack->fp_regs[fpcount++];
|
fpreg *addr = &stack->fp_regs[fpcount++];
|
||||||
|
float result;
|
||||||
avalue[i] = addr;
|
avalue[i] = addr;
|
||||||
*(float *)addr = ldf_fill (addr);
|
ldf_fill (result, addr);
|
||||||
|
*(float *)addr = result;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
avalue[i] = endian_adjust(&stack->gp_regs[gpcount], 4);
|
avalue[i] = endian_adjust(&stack->gp_regs[gpcount], 4);
|
||||||
@ -487,9 +499,11 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
|
|||||||
case FFI_TYPE_DOUBLE:
|
case FFI_TYPE_DOUBLE:
|
||||||
if (gpcount < 8 && fpcount < 8)
|
if (gpcount < 8 && fpcount < 8)
|
||||||
{
|
{
|
||||||
void *addr = &stack->fp_regs[fpcount++];
|
fpreg *addr = &stack->fp_regs[fpcount++];
|
||||||
|
double result;
|
||||||
avalue[i] = addr;
|
avalue[i] = addr;
|
||||||
*(double *)addr = ldf_fill (addr);
|
ldf_fill (result, addr);
|
||||||
|
*(double *)addr = result;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
avalue[i] = &stack->gp_regs[gpcount];
|
avalue[i] = &stack->gp_regs[gpcount];
|
||||||
@ -501,9 +515,11 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
|
|||||||
gpcount++;
|
gpcount++;
|
||||||
if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
|
if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
|
||||||
{
|
{
|
||||||
void *addr = &stack->fp_regs[fpcount++];
|
fpreg *addr = &stack->fp_regs[fpcount++];
|
||||||
|
__float80 result;
|
||||||
avalue[i] = addr;
|
avalue[i] = addr;
|
||||||
*(__float80 *)addr = ldf_fill (addr);
|
ldf_fill (result, addr);
|
||||||
|
*(__float80 *)addr = result;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
avalue[i] = &stack->gp_regs[gpcount];
|
avalue[i] = &stack->gp_regs[gpcount];
|
||||||
@ -533,8 +549,8 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
|
|||||||
&& offset < size
|
&& offset < size
|
||||||
&& gp_offset < 8 * 8)
|
&& gp_offset < 8 * 8)
|
||||||
{
|
{
|
||||||
hfa_type_store (hfa_type, addr + offset,
|
hfa_type_store (hfa_type, addr + offset,
|
||||||
ldf_fill (&stack->fp_regs[fpcount]));
|
&stack->fp_regs[fpcount]);
|
||||||
offset += hfa_size;
|
offset += hfa_size;
|
||||||
gp_offset += hfa_size;
|
gp_offset += hfa_size;
|
||||||
fpcount += 1;
|
fpcount += 1;
|
||||||
|
Loading…
Reference in New Issue
Block a user