]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Fix IA-64 problems with denorms getting clobbered by type conversions.
authorJames E Wilson <wilson@specifixinc.com>
Wed, 12 Apr 2006 22:10:49 +0000 (15:10 -0700)
committerJim Wilson <wilson@gcc.gnu.org>
Wed, 12 Apr 2006 22:10:49 +0000 (15:10 -0700)
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

libffi/ChangeLog
libffi/src/ia64/ffi.c

index cf733efe4c0b084620e41c23082152c1d85651eb..baa57145be7442692f848e27dc350ad66351412b 100644 (file)
@@ -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>
 
        * testsuite/lib/libffi-dg.exp (libffi-init): Recognize multilib
index e810827a81de13249e4fed7bab9fee031cfe9703..77dec567284a01f2c049abed468d60426c019d3d 100644 (file)
@@ -69,24 +69,19 @@ endian_adjust (void *addr, size_t len)
 #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
-stf_spill(fpreg *addr, __float80 value)
-{
+#define stf_spill(addr, value) \
   asm ("stf.spill %0 = %1%P0" : "=m" (*addr) : "f"(value));
-}
 
 /* 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
-ldf_fill(fpreg *addr)
-{
-  __float80 ret;
-  asm ("ldf.fill %0 = %1%P1" : "=f"(ret) : "m"(*addr));
-  return ret;
-}
+#define ldf_fill(result, addr) \
+  asm ("ldf.fill %0 = %1%P1" : "=f"(result) : "m"(*addr));
 
 /* Return the size of the C type associated with with TYPE.  Which will
    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
    the FFI_IA64_TYPE_HFA_* values.  */
 
-static __float80
-hfa_type_load (int type, void *addr)
+static void
+hfa_type_load (fpreg *fpaddr, int type, void *addr)
 {
   switch (type)
     {
     case FFI_IA64_TYPE_HFA_FLOAT:
-      return *(float *) addr;
+      stf_spill (fpaddr, *(float *) addr);
+      return;
     case FFI_IA64_TYPE_HFA_DOUBLE:
-      return *(double *) addr;
+      stf_spill (fpaddr, *(double *) addr);
+      return;
     case FFI_IA64_TYPE_HFA_LDOUBLE:
-      return *(__float80 *) addr;
+      stf_spill (fpaddr, *(__float80 *) addr);
+      return;
     default:
       abort ();
     }
@@ -130,19 +128,31 @@ hfa_type_load (int type, void *addr)
    the FFI_IA64_TYPE_HFA_* values.  */
 
 static void
-hfa_type_store (int type, void *addr, __float80 value)
+hfa_type_store (int type, void *addr, fpreg *fpaddr)
 {
   switch (type)
     {
     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:
-      *(double *) addr = value;
-      break;
+      {
+       double result;
+       ldf_fill (result, fpaddr);
+       *(double *) addr = result;
+       break;
+      }
     case FFI_IA64_TYPE_HFA_LDOUBLE:
-      *(__float80 *) addr = value;
-      break;
+      {
+       __float80 result;
+       ldf_fill (result, fpaddr);
+       *(__float80 *) addr = result;
+       break;
+      }
     default:
       abort ();
     }
@@ -351,8 +361,8 @@ ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
                       && offset < size
                       && gp_offset < 8 * 8)
                  {
-                   stf_spill (&stack->fp_regs[fpcount],
-                              hfa_type_load (hfa_type, avalue[i] + offset));
+                   hfa_type_load (&stack->fp_regs[fpcount], hfa_type,
+                                  avalue[i] + offset);
                    offset += hfa_size;
                    gp_offset += hfa_size;
                    fpcount += 1;
@@ -475,9 +485,11 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
        case FFI_TYPE_FLOAT:
          if (gpcount < 8 && fpcount < 8)
            {
-             void *addr = &stack->fp_regs[fpcount++];
+             fpreg *addr = &stack->fp_regs[fpcount++];
+             float result;
              avalue[i] = addr;
-             *(float *)addr = ldf_fill (addr);
+             ldf_fill (result, addr);
+             *(float *)addr = result;
            }
          else
            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:
          if (gpcount < 8 && fpcount < 8)
            {
-             void *addr = &stack->fp_regs[fpcount++];
+             fpreg *addr = &stack->fp_regs[fpcount++];
+             double result;
              avalue[i] = addr;
-             *(double *)addr = ldf_fill (addr);
+             ldf_fill (result, addr);
+             *(double *)addr = result;
            }
          else
            avalue[i] = &stack->gp_regs[gpcount];
@@ -501,9 +515,11 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
            gpcount++;
          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;
-             *(__float80 *)addr = ldf_fill (addr);
+             ldf_fill (result, addr);
+             *(__float80 *)addr = result;
            }
          else
            avalue[i] = &stack->gp_regs[gpcount];
@@ -533,8 +549,8 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
                       && offset < size
                       && gp_offset < 8 * 8)
                  {
-                   hfa_type_store (hfa_type, addr + offset, 
-                                   ldf_fill (&stack->fp_regs[fpcount]));
+                   hfa_type_store (hfa_type, addr + offset,
+                                   &stack->fp_regs[fpcount]);
                    offset += hfa_size;
                    gp_offset += hfa_size;
                    fpcount += 1;