Fix int<->floating point conversion routines
authorMichael Meissner <meissner@gcc.gnu.org>
Sat, 29 Jun 1996 11:28:52 +0000 (11:28 +0000)
committerMichael Meissner <meissner@gcc.gnu.org>
Sat, 29 Jun 1996 11:28:52 +0000 (11:28 +0000)
From-SVN: r12379

gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.h
gcc/config/rs6000/rs6000.md

index 5a097d6944923f431ebbf5280a08a97a77f2d2ac..ea35f4c59fec816b47085b319631d722caf72907 100644 (file)
@@ -36,6 +36,7 @@ Boston, MA 02111-1307, USA.  */
 #include "expr.h"
 #include "obstack.h"
 #include "tree.h"
+#include "function.h"
 
 #ifndef TARGET_NO_PROTOTYPE
 #define TARGET_NO_PROTOTYPE 0
@@ -2083,6 +2084,66 @@ rs6000_finalize_pic ()
     }
 }
 
+\f
+/* Define the structure for the machine field in struct function.  */
+struct machine_function
+{
+  int sysv_varargs_p;
+  int save_toc_p;
+  int fpmem_size;
+  int fpmem_offset;
+};
+
+/* Functions to save and restore rs6000_fpmem_size.
+   These will be called, via pointer variables,
+   from push_function_context and pop_function_context.  */
+
+void
+rs6000_save_machine_status (p)
+     struct function *p;
+{
+  struct machine_function *machine =
+    (struct machine_function *) xmalloc (sizeof (struct machine_function));
+
+  p->machine = machine;
+  machine->sysv_varargs_p = rs6000_sysv_varargs_p;
+  machine->save_toc_p     = rs6000_save_toc_p;
+  machine->fpmem_size     = rs6000_fpmem_size;
+  machine->fpmem_offset   = rs6000_fpmem_offset;
+}
+
+void
+rs6000_restore_machine_status (p)
+     struct function *p;
+{
+  struct machine_function *machine = p->machine;
+
+  rs6000_sysv_varargs_p = machine->sysv_varargs_p;
+  rs6000_save_toc_p     = machine->save_toc_p;
+  rs6000_fpmem_size     = machine->fpmem_size;
+  rs6000_fpmem_offset   = machine->fpmem_offset;
+
+  free (machine);
+  p->machine = (struct machine_function *)0;
+}
+
+/* Do anything needed before RTL is emitted for each function.  */
+
+void
+rs6000_init_expanders ()
+{
+  /* Reset varargs and save TOC indicator */
+  rs6000_sysv_varargs_p = 0;
+  rs6000_save_toc_p = 0;
+  rs6000_fpmem_size = 0;
+  rs6000_fpmem_offset = 0;
+  pic_offset_table_rtx = (rtx)0;
+
+  /* Arrange to save and restore machine status around nested functions.  */
+  save_machine_status = rs6000_save_machine_status;
+  restore_machine_status = rs6000_restore_machine_status;
+}
+
 \f
 /* Print an operand.  Recognize special options, documented below.  */
 
@@ -2720,15 +2781,15 @@ rs6000_makes_calls ()
                +---------------------------------------+
                | Parameter save area (P)               | 24
                +---------------------------------------+
-               | Float/int conversion temporary (X)    | 24+P
+               | Alloca space (A)                      | 24+P
                +---------------------------------------+
-               | Alloca space (A)                      | 24+P+X
+               | Local variable space (L)              | 24+P+A
                +---------------------------------------+
-               | Local variable space (L)              | 24+P+X+A
+               | Float/int conversion temporary (X)    | 24+P+A+L
                +---------------------------------------+
-               | Save area for GP registers (G)        | 24+P+X+A+L
+               | Save area for GP registers (G)        | 24+P+A+X+L
                +---------------------------------------+
-               | Save area for FP registers (F)        | 24+P+X+A+L+G
+               | Save area for FP registers (F)        | 24+P+A+X+L+G
                +---------------------------------------+
        old SP->| back chain to caller's caller         |
                +---------------------------------------+
@@ -2742,19 +2803,19 @@ rs6000_makes_calls ()
                +---------------------------------------+
                | Parameter save area (P)               | 8
                +---------------------------------------+
-               | Float/int conversion temporary (X)    | 8+P
-               +---------------------------------------+
-               | Alloca space (A)                      | 8+P+X
-               +---------------------------------------+
-               | Varargs save area (V)                 | 8+P+X+A
-               +---------------------------------------+
-               | Local variable space (L)              | 8+P+X+A+V
+               | Alloca space (A)                      | 8+P
+               +---------------------------------------+    
+               | Varargs save area (V)                 | 8+P+A
+               +---------------------------------------+    
+               | Local variable space (L)              | 8+P+A+V
+               +---------------------------------------+    
+               | Float/int conversion temporary (X)    | 8+P+A+V+L
                +---------------------------------------+
-               | saved CR (C)                          | 8+P+X+A+V+L
-               +---------------------------------------+
-               | Save area for GP registers (G)        | 8+P+X+A+V+L+C
-               +---------------------------------------+
-               | Save area for FP registers (F)        | 8+P+X+A+V+L+C+G
+               | saved CR (C)                          | 8+P+A+V+L+X
+               +---------------------------------------+    
+               | Save area for GP registers (G)        | 8+P+A+V+L+X+C
+               +---------------------------------------+    
+               | Save area for FP registers (F)        | 8+P+A+V+L+X+C+G
                +---------------------------------------+
        old SP->| back chain to caller's caller         |
                +---------------------------------------+
@@ -2777,23 +2838,23 @@ rs6000_makes_calls ()
                +---------------------------------------+
                | Parameter save area (P)               | 24
                +---------------------------------------+
-               | Float/int conversion temporary (X)    | 24+P
-               +---------------------------------------+
-               | Alloca space (A)                      | 24+P+X
-               +---------------------------------------+
-               | Local variable space (L)              | 24+P+X+A
-               +---------------------------------------+
-               | Save area for FP registers (F)        | 24+P+X+A+L
-               +---------------------------------------+
-               | Possible alignment area (X)           | 24+P+X+A+L+F
+               | Alloca space (A)                      | 24+P
+               +---------------------------------------+     
+               | Local variable space (L)              | 24+P+A
+               +---------------------------------------+     
+               | Float/int conversion temporary (X)    | 24+P+A+L
                +---------------------------------------+
-               | Save area for GP registers (G)        | 24+P+X+A+L+F+X
-               +---------------------------------------+
-               | Save area for CR (C)                  | 24+P+X+A+L+F+X+G
-               +---------------------------------------+
-               | Save area for TOC (T)                 | 24+P+X+A+L+F+X+G+C
-               +---------------------------------------+
-               | Save area for LR (R)                  | 24+P+X+A+L+F+X+G+C+T
+               | Save area for FP registers (F)        | 24+P+A+L+X
+               +---------------------------------------+     
+               | Possible alignment area (Y)           | 24+P+A+L+X+F
+               +---------------------------------------+     
+               | Save area for GP registers (G)        | 24+P+A+L+X+F+Y
+               +---------------------------------------+     
+               | Save area for CR (C)                  | 24+P+A+L+X+F+Y+G
+               +---------------------------------------+     
+               | Save area for TOC (T)                 | 24+P+A+L+X+F+Y+G+C
+               +---------------------------------------+     
+               | Save area for LR (R)                  | 24+P+A+L+X+F+Y+G+C+T
                +---------------------------------------+
        old SP->| back chain to caller's caller         |
                +---------------------------------------+
@@ -2941,7 +3002,6 @@ rs6000_stack_info ()
                        || info_ptr->total_size > 220);
 
   /* Calculate the offsets */
-  info_ptr->fpmem_offset = info_ptr->total_size - info_ptr->parm_size;
   switch (abi)
     {
     case ABI_NONE:
@@ -2961,9 +3021,9 @@ rs6000_stack_info ()
     case ABI_SOLARIS:
       info_ptr->fp_save_offset   = - info_ptr->fp_size;
       info_ptr->gp_save_offset   = info_ptr->fp_save_offset - info_ptr->gp_size;
-      info_ptr->cr_save_offset   = info_ptr->gp_save_offset - reg_size;
-      info_ptr->toc_save_offset  = info_ptr->cr_save_offset - info_ptr->cr_size;
-      info_ptr->main_save_offset = info_ptr->toc_save_offset - info_ptr->toc_size;
+      info_ptr->cr_save_offset   = info_ptr->gp_save_offset - info_ptr->cr_size;
+      info_ptr->toc_save_offset  = info_ptr->cr_save_offset - info_ptr->toc_size;
+      info_ptr->main_save_offset = info_ptr->toc_save_offset - info_ptr->main_size;
       info_ptr->lr_save_offset   = reg_size;
       break;
 
@@ -2980,6 +3040,9 @@ rs6000_stack_info ()
       break;
     }
 
+  if (info_ptr->fpmem_p)
+    info_ptr->fpmem_offset = STARTING_FRAME_OFFSET - info_ptr->total_size + info_ptr->vars_size;
+
   /* Zero offsets if we're not saving those registers */
   if (!info_ptr->fp_size)
     info_ptr->fp_save_offset = 0;
@@ -3004,9 +3067,7 @@ rs6000_stack_info ()
   else
     {
       rs6000_fpmem_size   = info_ptr->fpmem_size;
-      rs6000_fpmem_offset = STACK_DYNAMIC_OFFSET (current_function_decl) - info_ptr->fpmem_size;
-      if (rs6000_fpmem_offset > 32767)
-       abort ();
+      rs6000_fpmem_offset = info_ptr->total_size + info_ptr->fpmem_offset;
     }
 
   return info_ptr;
@@ -3792,13 +3853,6 @@ output_epilog (file, size)
        fputs ("\t.byte 31\n", file);
     }
 
-  /* Reset varargs and save TOC indicator */
-  rs6000_sysv_varargs_p = 0;
-  rs6000_save_toc_p = 0;
-  rs6000_fpmem_size = 0;
-  rs6000_fpmem_offset = 0;
-  pic_offset_table_rtx = (rtx)0;
-
   if (DEFAULT_ABI == ABI_NT)
     {
       RS6000_OUTPUT_BASENAME (file, XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0));
index f157f0ec01bf53bd540c74139e1a5332d016b9ea..7626eff03c5ac0caa11c90bf53a3f120ae862255 100644 (file)
@@ -1190,6 +1190,10 @@ extern int rs6000_sysv_varargs_p;
 /* Align an address */
 #define ALIGN(n,a) (((n) + (a) - 1) & ~((a) - 1))
 
+/* Initialize data used by insn expanders.  This is called from
+   init_emit, once for each function, before code is generated. */
+#define INIT_EXPANDERS rs6000_init_expanders ()
+
 /* Size of V.4 varargs area in bytes */
 #define RS6000_VARARGS_SIZE \
   ((GP_ARG_NUM_REG * (TARGET_32BIT ? 4 : 8)) + (FP_ARG_NUM_REG * 8) + 8)
@@ -1197,7 +1201,6 @@ extern int rs6000_sysv_varargs_p;
 /* Offset of V.4 varargs area */
 #define RS6000_VARARGS_OFFSET                                          \
   (ALIGN (current_function_outgoing_args_size, 8)                      \
-   + ALIGN (rs6000_fpmem_size, 8)                                      \
    + RS6000_SAVE_AREA)
 
 /* Offset within stack frame to start allocating local variables at.
@@ -1211,7 +1214,6 @@ extern int rs6000_sysv_varargs_p;
 
 #define STARTING_FRAME_OFFSET                                          \
   (ALIGN (current_function_outgoing_args_size, 8)                      \
-   + ALIGN (rs6000_fpmem_size, 8)                                      \
    + RS6000_VARARGS_AREA                                               \
    + RS6000_SAVE_AREA)
 
@@ -1223,7 +1225,6 @@ extern int rs6000_sysv_varargs_p;
    machines.  See `function.c' for details.  */
 #define STACK_DYNAMIC_OFFSET(FUNDECL)                                  \
   (ALIGN (current_function_outgoing_args_size, 8)                      \
-   + ALIGN (rs6000_fpmem_size, 8)                                      \
    + (STACK_POINTER_OFFSET))
 
 /* If we generate an insn to push BYTES bytes,
@@ -3009,6 +3010,7 @@ do {                                                                      \
 extern int flag_pic;
 extern int optimize;
 extern int flag_expensive_optimizations;
+extern int frame_pointer_needed;
 
 /* Declare functions in rs6000.c */
 extern void output_options ();
@@ -3071,6 +3073,9 @@ extern int addrs_ok_for_quad_peep ();
 extern enum reg_class secondary_reload_class ();
 extern int ccr_bit ();
 extern void rs6000_finalize_pic ();
+extern void rs6000_save_machine_status ();
+extern void rs6000_restore_machine_status ();
+extern void rs6000_init_expanders ();
 extern void print_operand ();
 extern void print_operand_address ();
 extern int first_reg_to_save ();
index be5c4f354c4a05f092dedd22d68f14f036ad4b00..c015c3dfcf76e01a0632e2d315e4238cff10bf74 100644 (file)
              (use (match_dup 2))
              (use (match_dup 3))
              (clobber (match_dup 4))
+             (clobber (match_dup 5))
              (clobber (reg:DF 76))])]
   "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
   "
   operands[2] = force_reg (SImode, GEN_INT (0x43300000));
   operands[3] = force_reg (DFmode, rs6000_float_const (\"4503601774854144\", DFmode));
   operands[4] = gen_reg_rtx (SImode);
+  operands[5] = gen_reg_rtx (Pmode);
 }")
 
 (define_insn "*floatsidf2_internal"
    (use (match_operand:SI 2 "gpc_reg_operand" "r"))
    (use (match_operand:DF 3 "gpc_reg_operand" "f"))
    (clobber (match_operand:SI 4 "gpc_reg_operand" "=r"))
+   (clobber (match_operand:SI 5 "gpc_reg_operand" "=b"))
    (clobber (reg:DF 76))]
   "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
   "#"
-  [(set_attr "length" "20")])
+  [(set_attr "length" "24")])
 
 (define_split
   [(set (match_operand:DF 0 "gpc_reg_operand" "")
    (use (match_operand:SI 2 "gpc_reg_operand" ""))
    (use (match_operand:DF 3 "gpc_reg_operand" ""))
    (clobber (match_operand:SI 4 "gpc_reg_operand" ""))
+   (clobber (match_operand:SI 5 "gpc_reg_operand" ""))
    (clobber (reg:DF 76))]
   "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
   [(set (match_dup 4)
        (xor:SI (match_dup 1)
-               (match_dup 5)))
-   (set (match_dup 6)
-       (unspec [(match_dup 4)          ;; low word
-                (reg:SI 1)] 11))
-   (set (match_dup 6)
-       (unspec [(match_dup 2)          ;; high word
-                (reg:SI 1)
-                (match_dup 6)] 12))
+               (match_dup 6)))
+   (set (match_dup 5)
+       (unspec [(const_int 0)] 11))
+   (set (match_dup 7)
+       (unspec [(match_dup 4)
+                (match_dup 5)] 12))    ;; low word
+   (set (match_dup 7)
+       (unspec [(match_dup 2)
+                (match_dup 5)
+                (match_dup 7)] 13))    ;; high word
    (set (match_dup 0)
-       (unspec [(match_dup 6)
-                (reg:SI 1)] 13))
+       (unspec [(match_dup 7)
+                (match_dup 5)] 14))
    (set (match_dup 0)
        (minus:DF (match_dup 0)
                  (match_dup 3)))]
   "
 {
-  operands[5] = GEN_INT (0x80000000);
-  operands[6] = gen_rtx (REG, DFmode, FPMEM_REGNUM);
+  operands[6] = GEN_INT (0x80000000);
+  operands[7] = gen_rtx (REG, DFmode, FPMEM_REGNUM);
 }")
 
 (define_expand "floatunssidf2"
                   (unsigned_float:DF (match_operand:SI 1 "gpc_reg_operand" "")))
              (use (match_dup 2))
              (use (match_dup 3))
+             (clobber (match_dup 4))
              (clobber (reg:DF 76))])]
   "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
   "
 {
   operands[2] = force_reg (SImode, GEN_INT (0x43300000));
   operands[3] = force_reg (DFmode, rs6000_float_const (\"4503599627370496\", DFmode));
+  operands[4] = gen_reg_rtx (Pmode);
 }")
 
 (define_insn "*floatunssidf2_internal"
        (unsigned_float:DF (match_operand:SI 1 "gpc_reg_operand" "r")))
    (use (match_operand:SI 2 "gpc_reg_operand" "r"))
    (use (match_operand:DF 3 "gpc_reg_operand" "f"))
+   (clobber (match_operand:SI 4 "gpc_reg_operand" "=b"))
    (clobber (reg:DF 76))]
   "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
   "#"
-  [(set_attr "length" "16")])
+  [(set_attr "length" "20")])
 
 (define_split
   [(set (match_operand:DF 0 "gpc_reg_operand" "")
        (unsigned_float:DF (match_operand:SI 1 "gpc_reg_operand" "")))
    (use (match_operand:SI 2 "gpc_reg_operand" ""))
    (use (match_operand:DF 3 "gpc_reg_operand" ""))
+   (clobber (match_operand:SI 4 "gpc_reg_operand" "=b"))
    (clobber (reg:DF 76))]
   "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
   [(set (match_dup 4)
-       (unspec [(match_dup 1)          ;; low word
-                (reg:SI 1)] 11))
-   (set (match_dup 4)
-       (unspec [(match_dup 2)          ;; high word
-                (reg:SI 1)
-                (reg:DF 76)] 12))
+       (unspec [(const_int 0)] 11))
+   (set (match_dup 5)
+       (unspec [(match_dup 1)
+                (match_dup 4)] 12))    ;; low word
+   (set (match_dup 5)
+       (unspec [(match_dup 2)
+                (match_dup 4)
+                (match_dup 5)] 13))    ;; high word
    (set (match_dup 0)
-       (unspec [(match_dup 4)
-                (reg:SI 1)] 13))
+       (unspec [(match_dup 5)
+                (reg:SI 1)] 14))
    (set (match_dup 0)
        (minus:DF (match_dup 0)
                  (match_dup 3)))]
-  "operands[4] = gen_rtx (REG, DFmode, FPMEM_REGNUM);")
+  "operands[5] = gen_rtx (REG, DFmode, FPMEM_REGNUM);")
+
+;; Load up scratch register with base address + offset if needed
+(define_insn "*floatsidf2_loadaddr"
+  [(set (match_operand:SI 0 "gpc_reg_operand" "=b")
+       (unspec [(const_int 0)] 11))]
+  "TARGET_HARD_FLOAT"
+  "*
+{
+  if (rs6000_fpmem_offset > 32760)
+    {
+      rtx xop[3];
 
-;; Note, we list r1 in the unspec, so that the optimizer is not tempted to optimize
-;; around an alloca call (the memory address is constructed directly from r1).
+      xop[0] = operands[0];
+      xop[1] = (frame_pointer_needed) ? frame_pointer_rtx : stack_pointer_rtx;
+      xop[2] = GEN_INT ((rs6000_fpmem_offset >> 16) & 0xffff);
+      output_asm_insn (\"{cau %0,%2(%1)|addis %0,%1,%2}\", xop);
+    }
+  else if (rs6000_fpmem_offset < 0)
+    abort ();
+
+  return \"\";
+}"
+  [(set_attr "length" "4")])
 
 (define_insn "*floatsidf2_store1"
   [(set (reg:DF 76)
        (unspec [(match_operand:SI 0 "gpc_reg_operand" "r")
-                (reg:SI 1)] 11))]
+                (match_operand:SI 1 "gpc_reg_operand" "r")] 12))]
   "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
   "*
 {
-  operands[1] = gen_rtx (MEM, SImode,
+  rtx indx;
+
+  if (rs6000_fpmem_offset > 32760)
+    indx = operands[1];
+  else if (frame_pointer_needed)
+    indx = frame_pointer_rtx;
+  else
+    indx = stack_pointer_rtx;
+
+  operands[2] = gen_rtx (MEM, SImode,
                         gen_rtx (PLUS, Pmode,
-                                 stack_pointer_rtx,
-                                 GEN_INT (rs6000_fpmem_offset
+                                 indx,
+                                 GEN_INT ((rs6000_fpmem_offset & 0xffff)
                                           + ((WORDS_BIG_ENDIAN != 0) * 4))));
 
-  return \"{st|stw} %0,%1\";
+  return \"{st|stw} %0,%2\";
 }"
   [(set_attr "type" "store")])
 
 (define_insn "*floatsidf2_store2"
   [(set (reg:DF 76)
        (unspec [(match_operand:SI 0 "gpc_reg_operand" "r")
-                (reg:SI 1)
-                (reg:DF 76)] 12))]
+                (match_operand:SI 1 "gpc_reg_operand" "r")
+                (reg:DF 76)] 13))]
   "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
   "*
 {
-  operands[1] = gen_rtx (MEM, SImode,
+  rtx indx;
+
+  if (rs6000_fpmem_offset > 32760)
+    indx = operands[1];
+  else if (frame_pointer_needed)
+    indx = frame_pointer_rtx;
+  else
+    indx = stack_pointer_rtx;
+
+  operands[2] = gen_rtx (MEM, SImode,
                         gen_rtx (PLUS, Pmode,
-                                 stack_pointer_rtx,
-                                 GEN_INT (rs6000_fpmem_offset
+                                 indx,
+                                 GEN_INT ((rs6000_fpmem_offset & 0xffff)
                                           + ((WORDS_BIG_ENDIAN == 0) * 4))));
 
-  return \"{st|stw} %0,%1\";
+  return \"{st|stw} %0,%2\";
 }"
   [(set_attr "type" "store")])
 
 (define_insn "*floatsidf2_load"
   [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
        (unspec [(reg:DF 76)
-                (reg:SI 1)] 13))]
+                (match_operand:SI 1 "gpc_reg_operand" "b")] 14))]
   "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
   "*
 {
-  operands[1] = gen_rtx (MEM, SImode,
+  rtx indx;
+
+  if (rs6000_fpmem_offset > 32760)
+    indx = operands[1];
+  else if (frame_pointer_needed)
+    indx = frame_pointer_rtx;
+  else
+    indx = stack_pointer_rtx;
+
+  operands[2] = gen_rtx (MEM, SImode,
                         gen_rtx (PLUS, Pmode,
-                                 stack_pointer_rtx,
+                                 indx,
                                  GEN_INT (rs6000_fpmem_offset)));
 
-  return \"lfd %0,%1\";
+  return \"lfd %0,%2\";
 }"
   [(set_attr "type" "fpload")])
 
   [(parallel [(set (match_operand:SI 0 "gpc_reg_operand" "")
                   (fix:SI (match_operand:DF 1 "gpc_reg_operand" "")))
              (clobber (match_dup 2))
-             (clobber (match_dup 3))])]
+             (clobber (match_dup 3))
+             (clobber (match_dup 4))])]
   "TARGET_HARD_FLOAT"
   "
 {
     }
 
   operands[2] = gen_reg_rtx (DImode);
-  operands[3] = gen_rtx (REG, DImode, FPMEM_REGNUM);
+  operands[3] = gen_reg_rtx (Pmode);
+  operands[4] = gen_rtx (REG, DImode, FPMEM_REGNUM);
 }")
 
 (define_insn "*fix_truncdfsi2_internal"
   [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
        (fix:SI (match_operand:DF 1 "gpc_reg_operand" "f")))
    (clobber (match_operand:DI 2 "gpc_reg_operand" "=f"))
+   (clobber (match_operand:SI 3 "gpc_reg_operand" "=b"))
    (clobber (reg:DI 76))]
   "TARGET_HARD_FLOAT"
   "#"
   [(set (match_operand:SI 0 "gpc_reg_operand" "")
        (fix:SI (match_operand:DF 1 "gpc_reg_operand" "f")))
    (clobber (match_operand:DI 2 "gpc_reg_operand" ""))
+   (clobber (match_operand:SI 3 "gpc_reg_operand" ""))
    (clobber (reg:DI 76))]
   "TARGET_HARD_FLOAT"
   [(set (match_dup 2)
        (sign_extend:DI (fix:SI (match_operand:DF 1 "gpc_reg_operand" ""))))
    (set (match_dup 3)
+       (unspec [(const_int 0)] 11))
+   (set (match_dup 4)
        (unspec [(match_dup 2)
-                (reg:SI 1)] 14))
+                (match_dup 3)] 15))
    (set (match_operand:SI 0 "gpc_reg_operand" "")
-       (unspec [(match_dup 3)
-                (reg:SI 1)] 15))]
-  "operands[3] = gen_rtx (REG, DImode, FPMEM_REGNUM);")
+       (unspec [(match_dup 4)
+                (match_dup 3)] 16))]
+  "operands[4] = gen_rtx (REG, DImode, FPMEM_REGNUM);")
 
 (define_insn "*fctiwz"
   [(set (match_operand:DI 0 "gpc_reg_operand" "=f")
 (define_insn "*fix_truncdfsi2_store"
   [(set (reg:DI 76)
        (unspec [(match_operand:DI 0 "gpc_reg_operand" "f")
-                (reg:SI 1)] 14))]
+                (match_operand:SI 1 "gpc_reg_operand" "b")] 15))]
   "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT"
   "*
 {
-  operands[1] = gen_rtx (MEM, DFmode,
+  rtx indx;
+
+  if (rs6000_fpmem_offset > 32760)
+    indx = operands[1];
+  else if (frame_pointer_needed)
+    indx = frame_pointer_rtx;
+  else
+    indx = stack_pointer_rtx;
+
+  operands[2] = gen_rtx (MEM, DFmode,
                         gen_rtx (PLUS, Pmode,
-                                 stack_pointer_rtx,
-                                 GEN_INT (rs6000_fpmem_offset)));
+                                 indx,
+                                 GEN_INT ((rs6000_fpmem_offset & 0xffff))));
 
-  return \"stfd %0,%1\";
+  return \"stfd %0,%2\";
 }"
   [(set_attr "type" "fpstore")])
 
 (define_insn "*fix_truncdfsi2_load"
   [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
        (unspec [(reg:DI 76)
-                (reg:SI 1)] 15))]
+                (match_operand:SI 1 "gpc_reg_operand" "b")] 16))]
   "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT"
   "*
 {
-  operands[1] = gen_rtx (MEM, DFmode,
+  rtx indx;
+
+  if (rs6000_fpmem_offset > 32760)
+    indx = operands[1];
+  else if (frame_pointer_needed)
+    indx = frame_pointer_rtx;
+  else
+    indx = stack_pointer_rtx;
+
+  operands[2] = gen_rtx (MEM, DFmode,
                         gen_rtx (PLUS, Pmode,
-                                 stack_pointer_rtx,
-                                 GEN_INT (rs6000_fpmem_offset + ((WORDS_BIG_ENDIAN) ? 4 : 0))));
+                                 indx,
+                                 GEN_INT ((rs6000_fpmem_offset & 0xffff)
+                                          + ((WORDS_BIG_ENDIAN) ? 4 : 0))));
 
-  return \"{l|lwz} %0,%1\";
+  return \"{l|lwz} %0,%2\";
 }"
   [(set_attr "type" "load")])