rs6000.h (FIXED_SCRATCH): Use r0 as a scratch register on SPE targets.
authorNathan Froyd <froydnj@codesourcery.com>
Tue, 5 Jun 2007 19:46:23 +0000 (19:46 +0000)
committerNathan Froyd <froydnj@gcc.gnu.org>
Tue, 5 Jun 2007 19:46:23 +0000 (19:46 +0000)
* config/rs6000/rs6000.h (FIXED_SCRATCH): Use r0 as a scratch
register on SPE targets.  Change documentation to reflect
reality.
* config/rs6000/rs6000.c (rs6000_conditional_register_usage):
Change FIXED_SCRATCH to 14 and document why we're keeping r14
out of the register allocation pool.
(rs6000_reg_live_or_pic_offset_p): New function.
(rs6000_emit_prologue): Move the actual saving of LR up to free
r0 for holding r11.  Split saving of SPE 64-bit registers into
its own case.  Ensure that offsets will always be in-range for
'evstdd' by using r11 as a scratch register to point at the start
of the SPE save area.  Save r11 if necessary, as it is the static
chain register.
(rs6000_emit_epilogue): Split restoring of SPE 64-bit registers
into its own case.  Ensure that offsets will always be in-range
for 'evldd' by using r11 as a scratch register to point at the
start of the SPE save area.  Also adjust r11 when restoring
the stack pointer to compensate for pre-loading r11.

From-SVN: r125340

gcc/ChangeLog
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.h

index f43122a077ab89eb097d904a05c93bb640e5b238..bf664a8e64d960b4efe9ba20e745a04433824e9a 100644 (file)
@@ -1,3 +1,24 @@
+2007-06-06  Nathan Froyd  <froydnj@codesourcery.com>
+
+       * config/rs6000/rs6000.h (FIXED_SCRATCH): Use r0 as a scratch
+       register on SPE targets.  Change documentation to reflect
+       reality.
+       * config/rs6000/rs6000.c (rs6000_conditional_register_usage):
+       Change FIXED_SCRATCH to 14 and document why we're keeping r14
+       out of the register allocation pool.
+       (rs6000_reg_live_or_pic_offset_p): New function.
+       (rs6000_emit_prologue): Move the actual saving of LR up to free
+       r0 for holding r11.  Split saving of SPE 64-bit registers into
+       its own case.  Ensure that offsets will always be in-range for
+       'evstdd' by using r11 as a scratch register to point at the start
+       of the SPE save area.  Save r11 if necessary, as it is the static
+       chain register.
+       (rs6000_emit_epilogue): Split restoring of SPE 64-bit registers
+       into its own case.  Ensure that offsets will always be in-range
+       for 'evldd' by using r11 as a scratch register to point at the
+       start of the SPE save area.  Also adjust r11 when restoring
+       the stack pointer to compensate for pre-loading r11.
+
 2007-06-05  Thomas Neumann  <tneumann@users.sourceforge.net>
 
        * cfg.c (init_flow): Use type safe memory macros.
index f7d76ea125531d801e5cdfe0bf55bb15273396db..67b7c86cda9b00e33a2ca198f9b675d265aa268d 100644 (file)
@@ -648,6 +648,7 @@ static void rs6000_eliminate_indexed_memrefs (rtx operands[2]);
 static const char *rs6000_mangle_fundamental_type (tree);
 extern const struct attribute_spec rs6000_attribute_table[];
 static void rs6000_set_default_type_attributes (tree);
+static bool rs6000_reg_live_or_pic_offset_p (int);
 static void rs6000_output_function_prologue (FILE *, HOST_WIDE_INT);
 static void rs6000_output_function_epilogue (FILE *, HOST_WIDE_INT);
 static void rs6000_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT,
@@ -3991,9 +3992,15 @@ rs6000_conditional_register_usage (void)
   if (TARGET_SPE)
     {
       global_regs[SPEFSCR_REGNO] = 1;
-      fixed_regs[FIXED_SCRATCH]
-       = call_used_regs[FIXED_SCRATCH]
-       = call_really_used_regs[FIXED_SCRATCH] = 1;
+      /* We used to use r14 as FIXED_SCRATCH to address SPE 64-bit
+         registers in prologues and epilogues.  We no longer use r14
+         for FIXED_SCRATCH, but we're keeping r14 out of the allocation
+         pool for link-compatibility with older versions of GCC.  Once
+         "old" code has died out, we can return r14 to the allocation
+         pool.  */
+      fixed_regs[14]
+       = call_used_regs[14]
+       = call_really_used_regs[14] = 1;
     }
 
   if (! TARGET_ALTIVEC)
@@ -14629,6 +14636,20 @@ no_global_regs_above (int first_greg)
 #define TARGET_FIX_AND_CONTINUE 0
 #endif
 
+/* Determine whether the gp REG is really used.  */
+
+static bool
+rs6000_reg_live_or_pic_offset_p (int reg)
+{
+  return ((regs_ever_live[reg]
+           && (!call_used_regs[reg]
+               || (reg == RS6000_PIC_OFFSET_TABLE_REGNUM
+                   && TARGET_TOC && TARGET_MINIMAL_TOC)))
+          || (reg == RS6000_PIC_OFFSET_TABLE_REGNUM
+              && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
+                  || (DEFAULT_ABI == ABI_DARWIN && flag_pic))));
+}
+
 /* Emit function prologue as insns.  */
 
 void
@@ -14815,9 +14836,22 @@ rs6000_emit_prologue (void)
   /* If we use the link register, get it into r0.  */
   if (!WORLD_SAVE_P (info) && info->lr_save_p)
     {
+      rtx addr, reg, mem;
+
       insn = emit_move_insn (gen_rtx_REG (Pmode, 0),
                             gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
       RTX_FRAME_RELATED_P (insn) = 1;
+
+      addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                              GEN_INT (info->lr_save_offset + sp_offset));
+      reg = gen_rtx_REG (Pmode, 0);
+      mem = gen_rtx_MEM (Pmode, addr);
+      /* This should not be of rs6000_sr_alias_set, because of
+        __builtin_return_address.  */
+
+      insn = emit_move_insn (mem, reg);
+      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+                           NULL_RTX, NULL_RTX);
     }
 
   /* If we need to save CR, put it into r12.  */
@@ -14910,59 +14944,99 @@ rs6000_emit_prologue (void)
       rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
                            NULL_RTX, NULL_RTX);
     }
+   else if (!WORLD_SAVE_P (info)
+            && TARGET_SPE_ABI
+            && info->spe_64bit_regs_used != 0
+            && info->first_gp_reg_save != 32)
+     {
+       int i;
+       rtx spe_save_area_ptr;
+       int using_static_chain_p = (cfun->static_chain_decl != NULL_TREE
+                                   && regs_ever_live[STATIC_CHAIN_REGNUM]
+                                   && !call_used_regs[STATIC_CHAIN_REGNUM]);
+       /* Determine whether we can address all of the registers that need
+          to be saved with an offset from the stack pointer that fits in
+          the small const field for SPE memory instructions.  */
+       int spe_regs_addressable_via_sp
+         = SPE_CONST_OFFSET_OK(info->spe_gp_save_offset + sp_offset
+                               + (32 - info->first_gp_reg_save - 1) * reg_size);
+       int spe_offset;
+       if (spe_regs_addressable_via_sp)
+         {
+           spe_save_area_ptr = sp_reg_rtx;
+           spe_offset = info->spe_gp_save_offset + sp_offset;
+         }
+       else
+         {
+           /* Make r11 point to the start of the SPE save area.  We need
+              to be careful here if r11 is holding the static chain.  If
+              it is, then temporarily save it in r0.  We would use r0 as
+              our base register here, but using r0 as a base register in
+              loads and stores means something different from what we
+              would like.  */
+           if (using_static_chain_p)
+             {
+               rtx r0 = gen_rtx_REG (Pmode, 0);
+               gcc_assert (info->first_gp_reg_save > 11);
+               emit_move_insn (r0, gen_rtx_REG (Pmode, 11));
+             }
+           spe_save_area_ptr = gen_rtx_REG (Pmode, 11);
+           emit_insn (gen_addsi3 (spe_save_area_ptr, sp_reg_rtx,
+                                  GEN_INT (info->spe_gp_save_offset + sp_offset)));
+           spe_offset = 0;
+         }
+       for (i = 0; i < 32 - info->first_gp_reg_save; i++)
+         if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i))
+           {
+             rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
+             rtx offset, addr, mem;
+             /* We're doing all this to ensure that the offset fits into
+                the immediate offset of 'evstdd'.  */
+             gcc_assert (SPE_CONST_OFFSET_OK (reg_size * i + spe_offset));
+             offset = GEN_INT (reg_size * i + spe_offset);
+             addr = gen_rtx_PLUS (Pmode, spe_save_area_ptr, offset);
+             mem = gen_rtx_MEM (V2SImode, addr);
+             insn = emit_move_insn (mem, reg);
+           
+             rs6000_frame_related (insn, spe_save_area_ptr,
+                                   info->spe_gp_save_offset
+                                   + sp_offset + reg_size * i,
+                                   offset, const0_rtx);
+           }
+       /* Move the static chain pointer back.  */
+       if (using_static_chain_p && !spe_regs_addressable_via_sp)
+         emit_move_insn (gen_rtx_REG (Pmode, 11), gen_rtx_REG (Pmode, 0));
+     }
   else if (!WORLD_SAVE_P (info))
     {
       int i;
       for (i = 0; i < 32 - info->first_gp_reg_save; i++)
-       if ((regs_ever_live[info->first_gp_reg_save + i]
-            && (!call_used_regs[info->first_gp_reg_save + i]
-                || (i + info->first_gp_reg_save
-                    == RS6000_PIC_OFFSET_TABLE_REGNUM
-                    && TARGET_TOC && TARGET_MINIMAL_TOC)))
-           || (i + info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
-               && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
-                   || (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
-         {
-           rtx addr, reg, mem;
-           reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
+       if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i))
+          {
+            rtx addr, reg, mem;
+            reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
 
-           if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
-             {
-               int offset = info->spe_gp_save_offset + sp_offset + 8 * i;
-               rtx b;
+            addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                 GEN_INT (info->gp_save_offset
+                                          + sp_offset
+                                          + reg_size * i));
+            mem = gen_frame_mem (reg_mode, addr);
 
-               if (!SPE_CONST_OFFSET_OK (offset))
-                 {
-                   b = gen_rtx_REG (Pmode, FIXED_SCRATCH);
-                   emit_move_insn (b, GEN_INT (offset));
-                 }
-               else
-                 b = GEN_INT (offset);
-
-               addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, b);
-               mem = gen_frame_mem (V2SImode, addr);
-               insn = emit_move_insn (mem, reg);
-
-               if (GET_CODE (b) == CONST_INT)
-                 rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
-                                       NULL_RTX, NULL_RTX);
-               else
-                 rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
-                                       b, GEN_INT (offset));
-             }
-           else
-             {
-               addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                    GEN_INT (info->gp_save_offset
-                                             + sp_offset
-                                             + reg_size * i));
-               mem = gen_frame_mem (reg_mode, addr);
-
-               insn = emit_move_insn (mem, reg);
-               rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
-                                     NULL_RTX, NULL_RTX);
-             }
-         }
+            insn = emit_move_insn (mem, reg);
+            rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+                                  NULL_RTX, NULL_RTX);
+          }
     }
 
   /* ??? There's no need to emit actual instructions here, but it's the
@@ -15000,21 +15074,6 @@ rs6000_emit_prologue (void)
        }
     }
 
-  /* Save lr if we used it.  */
-  if (!WORLD_SAVE_P (info) && info->lr_save_p)
-    {
-      rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                              GEN_INT (info->lr_save_offset + sp_offset));
-      rtx reg = gen_rtx_REG (Pmode, 0);
-      rtx mem = gen_rtx_MEM (Pmode, addr);
-      /* This should not be of frame_alias_set, because of
-        __builtin_return_address.  */
-
-      insn = emit_move_insn (mem, reg);
-      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
-                           NULL_RTX, NULL_RTX);
-    }
-
   /* Save CR if we use any that must be preserved.  */
   if (!WORLD_SAVE_P (info) && info->cr_save_p)
     {
@@ -15548,15 +15607,58 @@ rs6000_emit_epilogue (int sibcall)
        }
       emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
     }
+  else if (TARGET_SPE_ABI
+           && info->spe_64bit_regs_used != 0
+           && info->first_gp_reg_save != 32)
+    {
+      rtx spe_save_area_ptr;
+      /* Determine whether we can address all of the registers that need
+         to be saved with an offset from the stack pointer that fits in
+         the small const field for SPE memory instructions.  */
+      int spe_regs_addressable_via_sp
+        = SPE_CONST_OFFSET_OK(info->spe_gp_save_offset + sp_offset
+                              + (32 - info->first_gp_reg_save - 1) * reg_size);
+      int spe_offset;
+
+      if (spe_regs_addressable_via_sp)
+        {
+          spe_save_area_ptr = frame_reg_rtx;
+          spe_offset = info->spe_gp_save_offset + sp_offset;
+        }
+      else
+        {
+          /* Make r11 point to the start of the SPE save area.  We worried about
+             not clobbering it when we were saving registers in the prolgoue.
+             There's no need to worry here because the static chain is passed
+             anew to every function.  */
+          spe_save_area_ptr = gen_rtx_REG (Pmode, 11);
+
+          emit_insn (gen_addsi3 (spe_save_area_ptr, frame_reg_rtx,
+                                 GEN_INT (info->spe_gp_save_offset + sp_offset)));
+
+          spe_offset = 0;
+        }
+
+      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
+        if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i))
+          {
+            rtx offset, addr, mem;
+
+            /* We're doing all this to ensure that the immediate offset
+               fits into the immediate field of 'evldd'.  */
+            gcc_assert (SPE_CONST_OFFSET_OK (spe_offset + reg_size * i));
+
+            offset = GEN_INT (spe_offset + reg_size * i);
+            addr = gen_rtx_PLUS (Pmode, spe_save_area_ptr, offset);
+            mem = gen_rtx_MEM (V2SImode, addr);
+
+            emit_move_insn (gen_rtx_REG (reg_mode, info->first_gp_reg_save + i),
+                            mem);
+          }
+    }
   else
     for (i = 0; i < 32 - info->first_gp_reg_save; i++)
-      if ((regs_ever_live[info->first_gp_reg_save + i]
-          && (!call_used_regs[info->first_gp_reg_save + i]
-              || (i + info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
-                  && TARGET_TOC && TARGET_MINIMAL_TOC)))
-         || (i + info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
-             && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
-                 || (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
+      if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i))
        {
          rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
                                   GEN_INT (info->gp_save_offset
@@ -15564,24 +15666,6 @@ rs6000_emit_epilogue (int sibcall)
                                            + reg_size * i));
          rtx mem = gen_frame_mem (reg_mode, addr);
 
-         /* Restore 64-bit quantities for SPE.  */
-         if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
-           {
-             int offset = info->spe_gp_save_offset + sp_offset + 8 * i;
-             rtx b;
-
-             if (!SPE_CONST_OFFSET_OK (offset))
-               {
-                 b = gen_rtx_REG (Pmode, FIXED_SCRATCH);
-                 emit_move_insn (b, GEN_INT (offset));
-               }
-             else
-               b = GEN_INT (offset);
-
-             addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, b);
-             mem = gen_frame_mem (V2SImode, addr);
-           }
-
          emit_move_insn (gen_rtx_REG (reg_mode,
                                       info->first_gp_reg_save + i), mem);
        }
@@ -15657,7 +15741,13 @@ rs6000_emit_epilogue (int sibcall)
       /* This blockage is needed so that sched doesn't decide to move
         the sp change before the register restores.  */
       rs6000_emit_stack_tie ();
-      emit_move_insn (sp_reg_rtx, frame_reg_rtx);
+      if (TARGET_SPE_ABI
+          && info->spe_64bit_regs_used != 0
+          && info->first_gp_reg_save != 32)
+        emit_insn (gen_addsi3 (sp_reg_rtx, gen_rtx_REG (Pmode, 11),
+                               GEN_INT (-(info->spe_gp_save_offset + sp_offset))));
+      else
+        emit_move_insn (sp_reg_rtx, frame_reg_rtx);
     }
   else if (sp_offset != 0)
     emit_insn (TARGET_32BIT
index 57cd68dc2155a896e592e935d92698dd37f325d3..509cd6efb107a55927bd0d3585868357744ead6a 100644 (file)
@@ -913,18 +913,12 @@ extern enum rs6000_nop_insertion rs6000_sched_insert_nops;
 
 #define LOGICAL_OP_NON_SHORT_CIRCUIT 0
 
-/* A fixed register used at prologue and epilogue generation to fix
-   addressing modes.  The SPE needs heavy addressing fixes at the last
-   minute, and it's best to save a register for it.
+/* A fixed register used at epilogue generation to address SPE registers
+   with negative offsets.  The 64-bit load/store instructions on the SPE
+   only take positive offsets (and small ones at that), so we need to
+   reserve a register for consing up negative offsets.  */
 
-   AltiVec also needs fixes, but we've gotten around using r11, which
-   is actually wrong because when use_backchain_to_restore_sp is true,
-   we end up clobbering r11.
-
-   The AltiVec case needs to be fixed.  Dunno if we should break ABI
-   compatibility and reserve a register for it as well..  */
-
-#define FIXED_SCRATCH (TARGET_SPE ? 14 : 11)
+#define FIXED_SCRATCH 0
 
 /* Define this macro to change register usage conditional on target
    flags.  */