mips.h (GLOBAL_POINTER_REGNUM): New macro.
authorRichard Sandiford <rsandifo@redhat.com>
Mon, 9 Jun 2003 07:19:14 +0000 (07:19 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Mon, 9 Jun 2003 07:19:14 +0000 (07:19 +0000)
* config/mips/mips.h (GLOBAL_POINTER_REGNUM): New macro.
(PIC_OFFSET_TABLE_REGNUM): Look at pic_offset_table_rtx after reload.
(STARTING_FRAME_OFFSET): Don't allocate a cprestore slot for
n32/64 PIC.
(MUST_SAVE_REGISTERS): Delete.
* config/mips/mips.c (mips_frame_info): Remove extra_size field.
(machine_function): Add global_pointer field.
(mips_classify_constant): Check for (const $gp) using pointer equality
with pic_offset_table_rtx.
(mips_classify_constant): Handle RELOC_LOADGP_HI and RELOC_LOADGP_LO.
(mips_restore_gp): Use current_function_outgoing_args_size.
(print_operand): Use PIC_OFFSET_TABLE_REGNUM instead of
GP_REG_FIRST + 28.  Handle relocation strings that have
more than one '('.
(mips_reloc_string): Handle RELOC_LOADGP_HI and RELOC_LOADGP_LO.
(mips_global_pointer): New function.
(mips_save_reg_p): New function, mostly split out from...
(compute_frame_size): ...here.  Remove handling of extra_size.
Reclaim args_size if no variables depend on it.  Don't treat gp
as a special case: handle it in the main GPR loop.
(mips_initial_elimination_offset): Fix comment.
(save_restore_insns): Save every register in the GPR mask,
removing distinction between mask and real_mask.
(mips_output_function_prologue): Update .frame psuedo-op after
the removal of extra_size.  Move the SVR4 PIC stack allocation
and cprestore instructions to mips_expand_prologue.
(mips_gp_insn): New function.
(mips_expand_prologue): Set REGNO (pic_offset_table_rtx) to
the chosen global pointer.  Handle SVR4 PIC stack allocation
in the same way as other ABIs.  Adjust varargs code accordingly.
Emit a cprestore insn after allocating the stack.  Use mips_gp_insn
to emit the loadgp sequence.  Follow it with a loadgp_blockage
if not using explicit relocs.
(mips_output_function_epilogue): Reinstate the default gp register.
(mips16_gp_pseudo_reg): Use pic_offset_table_rtx.
(mips16_optimize_gp): Likewise.
* config/mips/mips.md (UNSPEC_LOADGP): Remove.
(UNSPEC_SETJMP, UNSPEC_LONGJMP): Remove.
(UNSPEC_CPRESTORE, RELOC_LOADGP_HI, RELOC_LOADGP_LO): New.
(loadgp): Remove.
(loadgp_blockage, cprestore): New instructions.
(builtin_setjmp_setup): Implement using emit_move_insn.  Use
pic_offset_table_rtx.
(builtin_setjmp_setup_32, builtin_setjmp_setup_64): Remove.
(builtin_longjmp): Use gen_raw_REG to force use of $28.

Co-Authored-By: Alexandre Oliva <aoliva@redhat.com>
From-SVN: r67656

gcc/ChangeLog
gcc/config/mips/mips.c
gcc/config/mips/mips.h
gcc/config/mips/mips.md

index 452a23243ee34ee1af84d2ce36f1ccefa0715000..21222323898b62981dd19575d720aa392e2e8f6f 100644 (file)
@@ -1,3 +1,52 @@
+2003-06-09  Richard Sandiford  <rsandifo@redhat.com>
+           Alexandre Oliva  <aoliva@redhat.com>
+
+       * config/mips/mips.h (GLOBAL_POINTER_REGNUM): New macro.
+       (PIC_OFFSET_TABLE_REGNUM): Look at pic_offset_table_rtx after reload.
+       (STARTING_FRAME_OFFSET): Don't allocate a cprestore slot for
+       n32/64 PIC.
+       (MUST_SAVE_REGISTERS): Delete.
+       * config/mips/mips.c (mips_frame_info): Remove extra_size field.
+       (machine_function): Add global_pointer field.
+       (mips_classify_constant): Check for (const $gp) using pointer equality
+       with pic_offset_table_rtx.
+       (mips_classify_constant): Handle RELOC_LOADGP_HI and RELOC_LOADGP_LO.
+       (mips_restore_gp): Use current_function_outgoing_args_size.
+       (print_operand): Use PIC_OFFSET_TABLE_REGNUM instead of
+       GP_REG_FIRST + 28.  Handle relocation strings that have
+       more than one '('.
+       (mips_reloc_string): Handle RELOC_LOADGP_HI and RELOC_LOADGP_LO.
+       (mips_global_pointer): New function.
+       (mips_save_reg_p): New function, mostly split out from...
+       (compute_frame_size): ...here.  Remove handling of extra_size.
+       Reclaim args_size if no variables depend on it.  Don't treat gp
+       as a special case: handle it in the main GPR loop.
+       (mips_initial_elimination_offset): Fix comment.
+       (save_restore_insns): Save every register in the GPR mask,
+       removing distinction between mask and real_mask.
+       (mips_output_function_prologue): Update .frame psuedo-op after
+       the removal of extra_size.  Move the SVR4 PIC stack allocation
+       and cprestore instructions to mips_expand_prologue.
+       (mips_gp_insn): New function.
+       (mips_expand_prologue): Set REGNO (pic_offset_table_rtx) to
+       the chosen global pointer.  Handle SVR4 PIC stack allocation
+       in the same way as other ABIs.  Adjust varargs code accordingly.
+       Emit a cprestore insn after allocating the stack.  Use mips_gp_insn
+       to emit the loadgp sequence.  Follow it with a loadgp_blockage
+       if not using explicit relocs.
+       (mips_output_function_epilogue): Reinstate the default gp register.
+       (mips16_gp_pseudo_reg): Use pic_offset_table_rtx.
+       (mips16_optimize_gp): Likewise.
+       * config/mips/mips.md (UNSPEC_LOADGP): Remove.
+       (UNSPEC_SETJMP, UNSPEC_LONGJMP): Remove.
+       (UNSPEC_CPRESTORE, RELOC_LOADGP_HI, RELOC_LOADGP_LO): New.
+       (loadgp): Remove.
+       (loadgp_blockage, cprestore): New instructions.
+       (builtin_setjmp_setup): Implement using emit_move_insn.  Use
+       pic_offset_table_rtx.
+       (builtin_setjmp_setup_32, builtin_setjmp_setup_64): Remove.
+       (builtin_longjmp): Use gen_raw_REG to force use of $28.
+
 2003-06-09  Richard Sandiford  <rsandifo@redhat.com>
 
        * config/mips/mips-protos.h (mips_output_division): Declare.
index 2604d49a02ae2723576c9305855638b54d31ab8a..47f3edde76f0302ba66fc721b9fdaf77bb30ccbd 100644 (file)
@@ -231,12 +231,15 @@ static void mips_arg_info         PARAMS ((const CUMULATIVE_ARGS *,
                                                 struct mips_arg_info *));
 static bool mips_get_unaligned_mem             PARAMS ((rtx *, unsigned int,
                                                         int, rtx *, rtx *));
+static unsigned int mips_global_pointer                PARAMS ((void));
+static bool mips_save_reg_p                    PARAMS ((unsigned int));
 static rtx mips_add_large_offset_to_sp         PARAMS ((HOST_WIDE_INT));
 static void mips_set_frame_expr                        PARAMS ((rtx));
 static rtx mips_frame_set                      PARAMS ((rtx, int));
 static void mips_emit_frame_related_store      PARAMS ((rtx, rtx,
                                                         HOST_WIDE_INT));
 static void save_restore_insns                 PARAMS ((int, rtx, long));
+static void mips_gp_insn                       PARAMS ((rtx, rtx));
 static void mips16_fp_args                     PARAMS ((FILE *, int, int));
 static void build_mips16_function_stub         PARAMS ((FILE *));
 static void mips16_optimize_gp                 PARAMS ((rtx));
@@ -298,7 +301,6 @@ struct mips_frame_info GTY(())
   long total_size;             /* # bytes that the entire frame takes up */
   long var_size;               /* # bytes that variables take up */
   long args_size;              /* # bytes that outgoing arguments take up */
-  long extra_size;             /* # bytes of extra gunk */
   int  gp_reg_size;            /* # bytes needed to store gp regs */
   int  fp_reg_size;            /* # bytes needed to store fp regs */
   long mask;                   /* mask of saved gp registers */
@@ -327,6 +329,9 @@ struct machine_function GTY(()) {
 
   /* Length of instructions in function; mips16 only.  */
   long insns_len;
+
+  /* The register to use as the global pointer within this function.  */
+  unsigned int global_pointer;
 };
 
 /* Information about a single argument.  */
@@ -890,7 +895,7 @@ mips_classify_constant (info, x)
     {
       x = XEXP (x, 0);
 
-      if (GET_CODE (x) == REG && REGNO (x) == GP_REG_FIRST + 28)
+      if (x == pic_offset_table_rtx)
        return CONSTANT_GP;
 
       while (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
@@ -913,6 +918,8 @@ mips_classify_constant (info, x)
          case RELOC_CALL16:
          case RELOC_CALL_HI:
          case RELOC_CALL_LO:
+         case RELOC_LOADGP_HI:
+         case RELOC_LOADGP_LO:
            /* These relocations should be applied to bare symbols only.  */
            return (info->offset == 0 ? CONSTANT_RELOC : CONSTANT_NONE);
          }
@@ -3033,7 +3040,7 @@ mips_restore_gp (operands)
     loc = hard_frame_pointer_rtx;
   else
     loc = stack_pointer_rtx;
-  loc = plus_constant (loc, cfun->machine->frame.args_size);
+  loc = plus_constant (loc, current_function_outgoing_args_size);
   operands[1] = gen_rtx_MEM (ptr_mode, loc);
 
   return mips_output_move (operands[0], operands[1]);
@@ -5861,7 +5868,7 @@ mips_debugger_offset (addr, offset)
    '.' Print the name of the register with a hard-wired zero (zero or $0).
    '^' Print the name of the pic call-through register (t9 or $25).
    '$' Print the name of the stack pointer register (sp or $29).
-   '+' Print the name of the gp register (gp or $28).
+   '+' Print the name of the gp register (usually gp or $28).
    '~' Output a branch alignment to LABEL_ALIGN(NULL).  */
 
 void
@@ -5872,6 +5879,7 @@ print_operand (file, op, letter)
 {
   register enum rtx_code code;
   struct mips_constant_info c;
+  const char *reloc;
 
   if (PRINT_OPERAND_PUNCT_VALID_P (letter))
     {
@@ -5899,7 +5907,7 @@ print_operand (file, op, letter)
          break;
 
        case '+':
-         fputs (reg_names[GP_REG_FIRST + 28], file);
+         fputs (reg_names[PIC_OFFSET_TABLE_REGNUM], file);
          break;
 
        case '&':
@@ -6159,15 +6167,17 @@ print_operand (file, op, letter)
        break;
 
       case CONSTANT_GP:
-       fputs (reg_names[GP_REG_FIRST + 28], file);
+       fputs (reg_names[PIC_OFFSET_TABLE_REGNUM], file);
        break;
 
       case CONSTANT_RELOC:
-       fputs (mips_reloc_string (XINT (c.symbol, 1)), file);
+       reloc = mips_reloc_string (XINT (c.symbol, 1));
+       fputs (reloc, file);
        output_addr_const (file, plus_constant (XVECEXP (c.symbol, 0, 0),
                                                c.offset));
-       fputc (')', file);
-       break;
+       while (*reloc != 0)
+         if (*reloc++ == '(')
+           fputc (')', file);
       }
 }
 \f
@@ -6187,6 +6197,8 @@ mips_reloc_string (reloc)
     case RELOC_CALL16:   return "%call16(";
     case RELOC_CALL_HI:          return "%call_hi(";
     case RELOC_CALL_LO:          return "%call_lo(";
+    case RELOC_LOADGP_HI: return "%hi(%neg(%gp_rel(";
+    case RELOC_LOADGP_LO: return "%lo(%neg(%gp_rel(";
     }
   abort ();
 }
@@ -6615,6 +6627,117 @@ mips_declare_object (stream, name, init_string, final_string, size)
     }
 }
 \f
+/* Return the register that should be used as the global pointer
+   within this function.  Return 0 if the function doesn't need
+   a global pointer.  */
+
+static unsigned int
+mips_global_pointer ()
+{
+  unsigned int regno;
+
+  /* $gp is always available in non-abicalls code.  */
+  if (!TARGET_ABICALLS)
+    return GLOBAL_POINTER_REGNUM;
+
+  /* We must always provide $gp when it is used implicitly.  */
+  if (!TARGET_EXPLICIT_RELOCS)
+    return GLOBAL_POINTER_REGNUM;
+
+  /* FUNCTION_PROFILER includes a jal macro, so we need to give it
+     a valid gp.  */
+  if (current_function_profile)
+    return GLOBAL_POINTER_REGNUM;
+
+  /* If the gp is never referenced, there's no need to initialize it.
+     Note that reload can sometimes introduce constant pool references
+     into a function that otherwise didn't need them.  For example,
+     suppose we have an instruction like:
+
+         (set (reg:DF R1) (float:DF (reg:SI R2)))
+
+     If R2 turns out to be constant such as 1, the instruction may have a
+     REG_EQUAL note saying that R1 == 1.0.  Reload then has the option of
+     using this constant if R2 doesn't get allocated to a register.
+
+     In cases like these, reload will have added the constant to the pool
+     but no instruction will yet refer to it.  */
+  if (!regs_ever_live[GLOBAL_POINTER_REGNUM]
+      && !current_function_uses_const_pool)
+    return 0;
+
+  /* We need a global pointer, but perhaps we can use a call-clobbered
+     register instead of $gp.  */
+  if (TARGET_NEWABI && current_function_is_leaf)
+    for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
+      if (!regs_ever_live[regno]
+         && call_used_regs[regno]
+         && !fixed_regs[regno])
+       return regno;
+
+  return GLOBAL_POINTER_REGNUM;
+}
+
+
+/* Return true if the current function must save REGNO.  */
+
+static bool
+mips_save_reg_p (regno)
+     unsigned int regno;
+{
+  /* We only need to save $gp for NewABI PIC.  */
+  if (regno == GLOBAL_POINTER_REGNUM)
+    return (TARGET_ABICALLS && TARGET_NEWABI
+           && cfun->machine->global_pointer == regno);
+
+  /* Check call-saved registers.  */
+  if (regs_ever_live[regno] && !call_used_regs[regno])
+    return true;
+
+  /* We need to save the old frame pointer before setting up a new one.  */
+  if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
+    return true;
+
+  /* We need to save the incoming return address if it is ever clobbered
+     within the function.  */
+  if (regno == GP_REG_FIRST + 31 && regs_ever_live[regno])
+    return true;
+
+  if (TARGET_MIPS16)
+    {
+      tree return_type;
+
+      return_type = DECL_RESULT (current_function_decl);
+
+      /* $18 is a special case in mips16 code.  It may be used to call
+        a function which returns a floating point value, but it is
+        marked in call_used_regs.  */
+      if (regno == GP_REG_FIRST + 18 && regs_ever_live[regno])
+       return true;
+
+      /* $31 is also a special case.  When not using -mentry, it will be
+        used to copy a return value into the floating point registers if
+        the return value is floating point.  */
+      if (regno == GP_REG_FIRST + 31
+         && mips16_hard_float
+         && !mips_entry
+         && !aggregate_value_p (return_type)
+         && GET_MODE_CLASS (DECL_MODE (return_type)) == MODE_FLOAT
+         && GET_MODE_SIZE (DECL_MODE (return_type)) <= UNITS_PER_FPVALUE)
+       return true;
+
+      /* The entry and exit pseudo instructions can not save $17
+        without also saving $16.  */
+      if (mips_entry
+         && regno == GP_REG_FIRST + 16
+         && mips_save_reg_p (GP_REG_FIRST + 17))
+       return true;
+    }
+
+  return false;
+}
+
+
 /* Return the bytes needed to compute the frame pointer from the current
    stack pointer.
 
@@ -6676,21 +6799,26 @@ compute_frame_size (size)
   HOST_WIDE_INT total_size;    /* # bytes that the entire frame takes up */
   HOST_WIDE_INT var_size;      /* # bytes that variables take up */
   HOST_WIDE_INT args_size;     /* # bytes that outgoing arguments take up */
-  HOST_WIDE_INT extra_size;    /* # extra bytes */
   HOST_WIDE_INT gp_reg_rounded;        /* # bytes needed to store gp after rounding */
   HOST_WIDE_INT gp_reg_size;   /* # bytes needed to store gp regs */
   HOST_WIDE_INT fp_reg_size;   /* # bytes needed to store fp regs */
   long mask;                   /* mask of saved gp registers */
   long fmask;                  /* mask of saved fp registers */
-  tree return_type;
+
+  cfun->machine->global_pointer = mips_global_pointer ();
 
   gp_reg_size = 0;
   fp_reg_size = 0;
   mask = 0;
   fmask        = 0;
-  extra_size = MIPS_STACK_ALIGN (((TARGET_ABICALLS) ? UNITS_PER_WORD : 0));
   var_size = MIPS_STACK_ALIGN (size);
-  args_size = MIPS_STACK_ALIGN (current_function_outgoing_args_size);
+  args_size = MIPS_STACK_ALIGN (STARTING_FRAME_OFFSET);
+
+  /* The space set aside by STARTING_FRAME_OFFSET isn't needed in leaf
+     functions.  If the function has local variables, we're committed
+     to allocating it anyway.  Otherwise reclaim it here.  */
+  if (var_size == 0 && current_function_is_leaf)
+    args_size = 0;
 
   /* The MIPS 3.0 linker does not like functions that dynamically
      allocate the stack and have 0 for STACK_DYNAMIC_OFFSET, since it
@@ -6700,44 +6828,15 @@ compute_frame_size (size)
   if (args_size == 0 && current_function_calls_alloca)
     args_size = 4 * UNITS_PER_WORD;
 
-  total_size = var_size + args_size + extra_size;
-  return_type = DECL_RESULT (current_function_decl);
+  total_size = var_size + args_size;
 
   /* Calculate space needed for gp registers.  */
   for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
-    {
-      /* $18 is a special case on the mips16.  It may be used to call
-         a function which returns a floating point value, but it is
-         marked in call_used_regs.  $31 is also a special case.  When
-         not using -mentry, it will be used to copy a return value
-         into the floating point registers if the return value is
-         floating point.  */
-      if (MUST_SAVE_REGISTER (regno)
-         || (TARGET_MIPS16
-             && regno == GP_REG_FIRST + 18
-             && regs_ever_live[regno])
-         || (TARGET_MIPS16
-             && regno == GP_REG_FIRST + 31
-             && mips16_hard_float
-             && ! mips_entry
-             && ! aggregate_value_p (return_type)
-             && GET_MODE_CLASS (DECL_MODE (return_type)) == MODE_FLOAT
-             && GET_MODE_SIZE (DECL_MODE (return_type)) <= UNITS_PER_FPVALUE))
-       {
-         gp_reg_size += GET_MODE_SIZE (gpr_mode);
-         mask |= 1L << (regno - GP_REG_FIRST);
-
-         /* The entry and exit pseudo instructions can not save $17
-            without also saving $16.  */
-         if (mips_entry
-             && regno == GP_REG_FIRST + 17
-             && ! MUST_SAVE_REGISTER (GP_REG_FIRST + 16))
-           {
-             gp_reg_size += UNITS_PER_WORD;
-             mask |= 1L << 16;
-           }
-       }
-    }
+    if (mips_save_reg_p (regno))
+      {
+       gp_reg_size += GET_MODE_SIZE (gpr_mode);
+       mask |= 1L << (regno - GP_REG_FIRST);
+      }
 
   /* We need to restore these for the handler.  */
   if (current_function_calls_eh_return)
@@ -6759,7 +6858,7 @@ compute_frame_size (size)
        regno >= FP_REG_FIRST;
        regno -= FP_INC)
     {
-      if (regs_ever_live[regno] && !call_used_regs[regno])
+      if (mips_save_reg_p (regno))
        {
          fp_reg_size += FP_INC * UNITS_PER_FPREG;
          fmask |= ((1 << FP_INC) - 1) << (regno - FP_REG_FIRST);
@@ -6769,25 +6868,6 @@ compute_frame_size (size)
   gp_reg_rounded = MIPS_STACK_ALIGN (gp_reg_size);
   total_size += gp_reg_rounded + MIPS_STACK_ALIGN (fp_reg_size);
 
-  /* The gp reg is caller saved in the 32 bit ABI, so there is no need
-     for leaf routines (total_size == extra_size) to save the gp reg.
-     The gp reg is callee saved in the 64 bit ABI, so all routines must
-     save the gp reg.  This is not a leaf routine if -p, because of the
-     call to mcount.  */
-  if (total_size == extra_size
-      && (mips_abi == ABI_32 || mips_abi == ABI_O64 || mips_abi == ABI_EABI)
-      && ! current_function_profile)
-    total_size = extra_size = 0;
-  else if (TARGET_ABICALLS)
-    {
-      /* Add the context-pointer to the saved registers.  */
-      gp_reg_size += UNITS_PER_WORD;
-      mask |= 1L << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST);
-      total_size -= gp_reg_rounded;
-      gp_reg_rounded = MIPS_STACK_ALIGN (gp_reg_size);
-      total_size += gp_reg_rounded;
-    }
-
   /* Add in space reserved on the stack by the callee for storing arguments
      passed in registers.  */
   if (mips_abi != ABI_32 && mips_abi != ABI_O64)
@@ -6801,7 +6881,6 @@ compute_frame_size (size)
   cfun->machine->frame.total_size = total_size;
   cfun->machine->frame.var_size = var_size;
   cfun->machine->frame.args_size = args_size;
-  cfun->machine->frame.extra_size = extra_size;
   cfun->machine->frame.gp_reg_size = gp_reg_size;
   cfun->machine->frame.fp_reg_size = fp_reg_size;
   cfun->machine->frame.mask = mask;
@@ -6817,8 +6896,7 @@ compute_frame_size (size)
       /* When using mips_entry, the registers are always saved at the
          top of the stack.  */
       if (! mips_entry)
-       offset = (args_size + extra_size + var_size
-                 + gp_reg_size - GET_MODE_SIZE (gpr_mode));
+       offset = args_size + var_size + gp_reg_size - GET_MODE_SIZE (gpr_mode);
       else
        offset = total_size - GET_MODE_SIZE (gpr_mode);
 
@@ -6833,7 +6911,7 @@ compute_frame_size (size)
 
   if (fmask)
     {
-      unsigned long offset = (args_size + extra_size + var_size
+      unsigned long offset = (args_size + var_size
                              + gp_reg_rounded + fp_reg_size
                              - FP_INC * UNITS_PER_FPREG);
       cfun->machine->frame.fp_sp_offset = offset;
@@ -6850,8 +6928,8 @@ compute_frame_size (size)
 }
 \f
 /* Implement INITIAL_ELIMINATION_OFFSET.  FROM is either the frame
-   pointer, argument pointer, or return address pointer.  TO is either
-   the stack pointer or hard frame pointer.  */
+   pointer or argument pointer.  TO is either the stack pointer or
+   hard frame pointer.  */
 
 int
 mips_initial_elimination_offset (from, to)
@@ -6995,7 +7073,6 @@ save_restore_insns (store_p, large_reg, large_offset)
 {
   long mask = cfun->machine->frame.mask;
   long fmask = cfun->machine->frame.fmask;
-  long real_mask = mask;
   int regno;
   rtx base_reg_rtx;
   HOST_WIDE_INT base_offset;
@@ -7007,12 +7084,6 @@ save_restore_insns (store_p, large_reg, large_offset)
       && ! BITSET_P (mask, HARD_FRAME_POINTER_REGNUM - GP_REG_FIRST))
     abort ();
 
-  /* Do not restore GP under certain conditions.  */
-  if (! store_p
-      && TARGET_ABICALLS
-      && (mips_abi == ABI_32 || mips_abi == ABI_O64))
-    mask &= ~(1L << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST));
-
   if (mask == 0 && fmask == 0)
     return;
 
@@ -7124,11 +7195,8 @@ save_restore_insns (store_p, large_reg, large_offset)
                    emit_move_insn (gen_rtx (REG, gpr_mode, regno),
                                    reg_rtx);
                }
+             gp_offset -= GET_MODE_SIZE (gpr_mode);
            }
-         /* If the restore is being supressed, still take into account
-            the offset at which it is stored.  */
-         if (BITSET_P (real_mask, regno - GP_REG_FIRST))
-           gp_offset -= GET_MODE_SIZE (gpr_mode);
        }
     }
   else
@@ -7252,7 +7320,7 @@ mips_output_function_prologue (file, size)
     {
       /* .frame FRAMEREG, FRAMESIZE, RETREG */
       fprintf (file,
-              "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d/%d, args= %d, extra= %ld\n",
+              "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d/%d, args= %d, gp= %ld\n",
               (reg_names[(frame_pointer_needed)
                          ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
               ((frame_pointer_needed && TARGET_MIPS16)
@@ -7263,7 +7331,8 @@ mips_output_function_prologue (file, size)
               cfun->machine->frame.num_gp,
               cfun->machine->frame.num_fp,
               current_function_outgoing_args_size,
-              cfun->machine->frame.extra_size);
+              cfun->machine->frame.args_size
+              - current_function_outgoing_args_size);
 
       /* .mask MASK, GPOFFSET; .fmask FPOFFSET */
       fprintf (file, "\t.mask\t0x%08lx,%ld\n\t.fmask\t0x%08lx,%ld\n",
@@ -7392,25 +7461,33 @@ mips_output_function_prologue (file, size)
       fprintf (file, "\n");
     }
 
-  if (TARGET_ABICALLS && (mips_abi == ABI_32 || mips_abi == ABI_O64))
-    {
-      const char *const sp_str = reg_names[STACK_POINTER_REGNUM];
+  /* Handle the initialization of $gp for SVR4 PIC.  */
+  if (TARGET_ABICALLS && !TARGET_NEWABI && cfun->machine->global_pointer > 0)
+    fprintf (file, "\t.set\tnoreorder\n\t.cpload\t%s\n\t.set\treorder\n",
+            reg_names[PIC_FUNCTION_ADDR_REGNUM]);
+}
+\f
+/* Emit an instruction to move SRC into DEST.  When generating
+   explicit reloc code, mark the instruction as potentially dead.  */
 
-      fprintf (file, "\t.set\tnoreorder\n\t.cpload\t%s\n\t.set\treorder\n",
-              reg_names[PIC_FUNCTION_ADDR_REGNUM]);
-      if (tsize > 0)
-       {
-         fprintf (file, "\t%s\t%s,%s,%ld\n",
-                  (ptr_mode == DImode ? "dsubu" : "subu"),
-                  sp_str, sp_str, (long) tsize);
-         fprintf (file, "\t.cprestore %ld\n", cfun->machine->frame.args_size);
-       }
+static void
+mips_gp_insn (dest, src)
+     rtx dest, src;
+{
+  rtx insn;
 
-      if (dwarf2out_do_frame ())
-       dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, tsize);
+  insn = emit_insn (gen_rtx_SET (VOIDmode, dest, src));
+  if (TARGET_EXPLICIT_RELOCS)
+    {
+      /* compute_frame_size assumes that any function which uses the
+        constant pool will need a gp.  However, all constant
+        pool references could be eliminated, in which case
+        it is OK for flow to delete the gp load as well.  */
+      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
+                                           REG_NOTES (insn));
     }
 }
-\f
+
 /* Expand the prologue into a bunch of separate insns.  */
 
 void
@@ -7432,6 +7509,9 @@ mips_expand_prologue ()
   int store_args_on_stack = (mips_abi == ABI_32 || mips_abi == ABI_O64)
                             && (! mips_entry || mips_can_use_return_insn ());
 
+  if (cfun->machine->global_pointer > 0)
+    REGNO (pic_offset_table_rtx) = cfun->machine->global_pointer;
+
   /* If struct value address is treated as the first argument, make it so.  */
   if (aggregate_value_p (DECL_RESULT (fndecl))
       && ! current_function_returns_pcc_struct
@@ -7558,10 +7638,6 @@ mips_expand_prologue ()
       int offset = (regno - GP_ARG_FIRST) * UNITS_PER_WORD;
       rtx ptr = stack_pointer_rtx;
 
-      /* If we are doing svr4-abi, sp has already been decremented by tsize.  */
-      if (TARGET_ABICALLS)
-       offset += tsize;
-
       for (; regno <= GP_ARG_LAST; regno++)
        {
          if (offset != 0)
@@ -7657,8 +7733,7 @@ mips_expand_prologue ()
       /* If we are doing svr4-abi, sp move is done by
          function_prologue.  In mips16 mode with a large frame, we
          save the registers before adjusting the stack.  */
-      if ((!TARGET_ABICALLS || (mips_abi != ABI_32 && mips_abi != ABI_O64))
-         && (!TARGET_MIPS16 || tsize <= 32767))
+      if (!TARGET_MIPS16 || tsize <= 32767)
        {
          rtx adjustment_rtx;
 
@@ -7687,9 +7762,11 @@ mips_expand_prologue ()
       else if (reg_18_save != NULL_RTX)
        emit_insn (reg_18_save);
 
-      if ((!TARGET_ABICALLS || (mips_abi != ABI_32 && mips_abi != ABI_O64))
-         && TARGET_MIPS16
-         && tsize > 32767)
+      if (TARGET_ABICALLS && !TARGET_NEWABI && !current_function_is_leaf)
+       emit_insn (gen_cprestore
+                  (GEN_INT (current_function_outgoing_args_size)));
+
+      if (TARGET_MIPS16 && tsize > 32767)
        {
          rtx reg_rtx;
 
@@ -7718,9 +7795,7 @@ mips_expand_prologue ()
              instructions when using the frame pointer by pointing the
              frame pointer ahead of the argument space allocated on
              the stack.  */
-         if ((! TARGET_ABICALLS || (mips_abi != ABI_32 && mips_abi != ABI_O64))
-             && TARGET_MIPS16
-             && tsize > 32767)
+         if (TARGET_MIPS16 && tsize > 32767)
            {
              /* In this case, we have already copied the stack
                  pointer into the frame pointer, above.  We need only
@@ -7760,10 +7835,24 @@ mips_expand_prologue ()
          if (insn)
            RTX_FRAME_RELATED_P (insn) = 1;
        }
+    }
+
+  if (TARGET_ABICALLS && TARGET_NEWABI && cfun->machine->global_pointer > 0)
+    {
+      rtx temp, fnsymbol, fnaddr;
 
-      if (TARGET_ABICALLS && (mips_abi != ABI_32 && mips_abi != ABI_O64))
-       emit_insn (gen_loadgp (XEXP (DECL_RTL (current_function_decl), 0),
-                              gen_rtx_REG (DImode, 25)));
+      temp = gen_rtx_REG (Pmode, MIPS_TEMP1_REGNUM);
+      fnsymbol = XEXP (DECL_RTL (current_function_decl), 0);
+      fnaddr = gen_rtx_REG (Pmode, PIC_FUNCTION_ADDR_REGNUM);
+
+      mips_gp_insn (temp, mips_lui_reloc (fnsymbol, RELOC_LOADGP_HI));
+      mips_gp_insn (temp, gen_rtx_PLUS (Pmode, temp, fnaddr));
+      mips_gp_insn (pic_offset_table_rtx,
+                   gen_rtx_PLUS (Pmode, temp,
+                                 mips_reloc (fnsymbol, RELOC_LOADGP_LO)));
+
+      if (!TARGET_EXPLICIT_RELOCS)
+       emit_insn (gen_loadgp_blockage ());
     }
 
   /* If we are profiling, make sure no instructions are scheduled before
@@ -7824,6 +7913,9 @@ mips_output_function_epilogue (file, size)
   for (string = mips16_strings; string != 0; string = XEXP (string, 1))
     SYMBOL_REF_FLAG (XEXP (string, 0)) = 0;
   free_EXPR_LIST_list (&mips16_strings);
+
+  /* Reinstate the normal $gp.  */
+  REGNO (pic_offset_table_rtx) = GLOBAL_POINTER_REGNUM;
 }
 \f
 /* Expand the epilogue into a bunch of separate insns.  SIBCALL_P is true
@@ -8680,9 +8772,7 @@ mips16_gp_pseudo_reg ()
 
       /* We want to initialize this to a value which gcc will believe
          is constant.  */
-      const_gp = gen_rtx (CONST, Pmode,
-                         gen_rtx (REG, Pmode, GP_REG_FIRST + 28));
-
+      const_gp = gen_rtx_CONST (Pmode, pic_offset_table_rtx);
       start_sequence ();
       emit_move_insn (cfun->machine->mips16_gp_pseudo_rtx,
                      const_gp);
@@ -9223,8 +9313,7 @@ mips16_optimize_gp (first)
 
       if (gpcopy == NULL_RTX
          && GET_CODE (SET_SRC (set)) == CONST
-         && GET_CODE (XEXP (SET_SRC (set), 0)) == REG
-         && REGNO (XEXP (SET_SRC (set), 0)) == GP_REG_FIRST + 28
+         && XEXP (SET_SRC (set), 0) == pic_offset_table_rtx
          && GET_CODE (SET_DEST (set)) == REG)
        gpcopy = SET_DEST (set);
       else if (slot == NULL_RTX
@@ -9249,9 +9338,7 @@ mips16_optimize_gp (first)
               && (GET_CODE (SET_DEST (set)) != REG
                   || REGNO (SET_DEST (set)) != REGNO (gpcopy)
                   || ((GET_CODE (SET_SRC (set)) != CONST
-                       || GET_CODE (XEXP (SET_SRC (set), 0)) != REG
-                       || (REGNO (XEXP (SET_SRC (set), 0))
-                           != GP_REG_FIRST + 28))
+                       || XEXP (SET_SRC (set), 0) != pic_offset_table_rtx)
                       && ! rtx_equal_p (SET_SRC (set), slot))))
        break;
       else if (slot != NULL_RTX
@@ -9324,8 +9411,7 @@ mips16_optimize_gp (first)
 
          if (GET_CODE (SET_DEST (set1)) == REG
              && GET_CODE (SET_SRC (set1)) == CONST
-             && GET_CODE (XEXP (SET_SRC (set1), 0)) == REG
-             && REGNO (XEXP (SET_SRC (set1), 0)) == GP_REG_FIRST + 28
+             && XEXP (SET_SRC (set1), 0) == pic_offset_table_rtx
              && rtx_equal_p (SET_DEST (set1), SET_DEST (set2))
              && GET_CODE (SET_SRC (set2)) == PLUS
              && rtx_equal_p (SET_DEST (set1), XEXP (SET_SRC (set2), 0))
@@ -9387,13 +9473,11 @@ mips16_optimize_gp (first)
               && rtx_equal_p (SET_SRC (set), slot))
        {
          enum machine_mode mode;
+         rtx src;
 
          mode = GET_MODE (SET_DEST (set));
-         emit_insn_after (gen_rtx (SET, VOIDmode, SET_DEST (set),
-                                   gen_rtx (CONST, mode,
-                                            gen_rtx (REG, mode,
-                                                     GP_REG_FIRST + 28))),
-                          insn);
+         src = gen_rtx_CONST (mode, pic_offset_table_rtx);
+         emit_insn_after (gen_rtx_SET (VOIDmode, SET_DEST (set), src), insn);
          PUT_CODE (insn, NOTE);
          NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
          NOTE_SOURCE_FILE (insn) = 0;
index b40abc8245d6ab46718978a5242c03e3ec7ed2ea..1481d512b551100185f15732a345a891054ae65f 100644 (file)
@@ -1945,14 +1945,20 @@ extern char mips_hard_regno_mode_ok[][FIRST_PSEUDO_REGISTER];
    kept in a register.  */
 #define NO_RECURSIVE_FUNCTION_CSE 1
 
-/* The register number of the register used to address a table of
-   static data addresses in memory.  In some cases this register is
-   defined by a processor's "application binary interface" (ABI).
-   When this macro is defined, RTL is generated for this register
-   once, as with the stack pointer and frame pointer registers.  If
-   this macro is not defined, it is up to the machine-dependent
-   files to allocate such a register (if necessary).  */
-#define PIC_OFFSET_TABLE_REGNUM (GP_REG_FIRST + 28)
+/* The ABI-defined global pointer.  Sometimes we use a different
+   register in leaf functions: see PIC_OFFSET_TABLE_REGNUM.  */
+#define GLOBAL_POINTER_REGNUM (GP_REG_FIRST + 28)
+
+/* We normally use $28 as the global pointer.  However, when generating
+   n32/64 PIC, it is better for leaf functions to use a call-clobbered
+   register instead.  They can then avoid saving and restoring $28
+   and perhaps avoid using a frame at all.
+
+   When a leaf function uses something other than $28, mips_expand_prologue
+   will modify pic_offset_table_rtx in place.  Take the register number
+   from there after reload.  */
+#define PIC_OFFSET_TABLE_REGNUM \
+  (reload_completed ? REGNO (pic_offset_table_rtx) : GLOBAL_POINTER_REGNUM)
 
 #define PIC_FUNCTION_ADDR_REGNUM (GP_REG_FIRST + 25)
 \f
@@ -2353,23 +2359,14 @@ extern enum reg_class mips_char_to_class[256];
 \f
 /* Stack layout; function entry, exit and calling.  */
 
-/* Define this if pushing a word on the stack
-   makes the stack pointer a smaller address.  */
 #define STACK_GROWS_DOWNWARD
 
-/* Define this if the nominal address of the stack frame
-   is at the high-address end of the local variables;
-   that is, each additional local variable allocated
-   goes at a more negative offset in the frame.  */
-/* #define FRAME_GROWS_DOWNWARD */
-
-/* Offset within stack frame to start allocating local variables at.
-   If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
-   first local allocated.  Otherwise, it is the offset to the BEGINNING
-   of the first local allocated.  */
+/* The offset of the first local variable from the beginning of the frame.
+   See compute_frame_size for details about the frame layout.  */
 #define STARTING_FRAME_OFFSET                                          \
   (current_function_outgoing_args_size                                 \
-   + (TARGET_ABICALLS ? MIPS_STACK_ALIGN (UNITS_PER_WORD) : 0))
+   + (TARGET_ABICALLS && !TARGET_NEWABI                                        \
+      ? MIPS_STACK_ALIGN (UNITS_PER_WORD) : 0))
 
 /* Offset from the stack pointer register to an item dynamically
    allocated on the stack, e.g., by `alloca'.
@@ -2837,13 +2834,6 @@ typedef struct mips_args {
        (mips_abi == ABI_EABI && UNITS_PER_FPVALUE >= UNITS_PER_DOUBLE)
 
 \f
-/* Tell prologue and epilogue if register REGNO should be saved / restored.  */
-
-#define MUST_SAVE_REGISTER(regno) \
- ((regs_ever_live[regno] && !call_used_regs[regno])                    \
-  || (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)      \
-  || (regno == (GP_REG_FIRST + 31) && regs_ever_live[GP_REG_FIRST + 31]))
-
 /* Say that the epilogue uses the return address register.  Note that
    in the case of sibcalls, the values "used by the epilogue" are
    considered live at the start of the called function.  */
index 85e9b2d1700a7d9ba6a9209c743f339f79b666fd..3bc3f85a03661893ddf26ce68e2fae9de47506ca 100644 (file)
@@ -32,9 +32,7 @@
    (UNSPEC_STORE_DF_HIGH        2)
    (UNSPEC_GET_FNADDR           4)
    (UNSPEC_BLOCKAGE             6)
-   (UNSPEC_LOADGP               7)
-   (UNSPEC_SETJMP               8)
-   (UNSPEC_LONGJMP              9)
+   (UNSPEC_CPRESTORE            8)
    (UNSPEC_EH_RECEIVER         10)
    (UNSPEC_EH_RETURN           11)
    (UNSPEC_CONSTTABLE_QI       12)
@@ -67,7 +65,9 @@
    (RELOC_GOT_DISP             104)
    (RELOC_CALL16               105)
    (RELOC_CALL_HI              106)
-   (RELOC_CALL_LO              107)])
+   (RELOC_CALL_LO              107)
+   (RELOC_LOADGP_HI            108)
+   (RELOC_LOADGP_LO            109)])
 \f
 
 ;; ....................
@@ -5428,21 +5428,28 @@ move\\t%0,%z4\\n\\
    (set_attr "mode"    "SF")
    (set_attr "length"  "4")])
 
-;; Instructions to load the global pointer register.
-;; This is volatile to make sure that the scheduler won't move any symbol_ref
-;; uses in front of it.  All symbol_refs implicitly use the gp reg.
+;; The use of gp is hidden when not using explicit relocations.
+;; This blockage instruction prevents the gp load from being
+;; scheduled after an implicit use of gp.  It also prevents
+;; the load from being deleted as dead.
+(define_insn "loadgp_blockage"
+  [(unspec_volatile [(reg:DI 28)] UNSPEC_BLOCKAGE)]
+  ""
+  ""
+  [(set_attr "type"    "unknown")
+   (set_attr "mode"    "none")
+   (set_attr "length"  "0")])
 
-(define_insn "loadgp"
-  [(set (reg:DI 28)
-       (unspec_volatile:DI [(match_operand 0 "immediate_operand" "")
-                            (match_operand:DI 1 "register_operand" "")]
-                           UNSPEC_LOADGP))
-   (clobber (reg:DI 1))]
+;; Emit a .cprestore directive, which expands to a single store instruction.
+;; Note that we continue to use .cprestore for explicit reloc code so that
+;; jals inside inlines asms will work correctly.
+(define_insn "cprestore"
+  [(unspec_volatile [(match_operand 0 "const_int_operand" "")]
+                   UNSPEC_CPRESTORE)]
   ""
-  "%[lui\\t$1,%%hi(%%neg(%%gp_rel(%0)))\\n\\taddiu\\t$1,$1,%%lo(%%neg(%%gp_rel(%0)))\\n\\tdaddu\\t$gp,$1,%1%]"
-  [(set_attr "type"    "move")
-   (set_attr "mode"    "DI")
-   (set_attr "length"  "12")])
+  ".cprestore\t%0"
+  [(set_attr "type" "store")
+   (set_attr "length" "4")])
 \f
 ;; Block moves, see mips.c for more details.
 ;; Argument 0 is the destination
@@ -8776,55 +8783,45 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
    (set_attr "mode"    "none")
    (set_attr "length"  "24")])
 
-;; For o32/n32/n64, we save the gp in the jmp_buf as well.  While it is
-;; possible to either pull it off the stack (in the o32 case) or recalculate
-;; it given t9 and our target label, it takes 3 or 4 insns to do so, and
-;; this is easy.
+;; For TARGET_ABICALLS, we save the gp in the jmp_buf as well.
+;; While it is possible to either pull it off the stack (in the
+;; o32 case) or recalculate it given t9 and our target label,
+;; it takes 3 or 4 insns to do so.
 
 (define_expand "builtin_setjmp_setup"
-  [(unspec [(match_operand 0 "register_operand" "r")] UNSPEC_SETJMP)]
+  [(use (match_operand 0 "register_operand" ""))]
   "TARGET_ABICALLS"
-  "
-{
-  if (Pmode == DImode)
-    emit_insn (gen_builtin_setjmp_setup_64 (operands[0]));
-  else
-    emit_insn (gen_builtin_setjmp_setup_32 (operands[0]));
-  DONE;
-}")
-
-(define_expand "builtin_setjmp_setup_32"
-  [(set (mem:SI (plus:SI (match_operand:SI 0 "register_operand" "r")
-                  (const_int 12)))
-      (reg:SI 28))]
-  "TARGET_ABICALLS && ! (Pmode == DImode)"
-  "")
+  {
+    rtx addr;
 
-(define_expand "builtin_setjmp_setup_64"
-  [(set (mem:DI (plus:DI (match_operand:DI 0 "register_operand" "r")
-                  (const_int 24)))
-      (reg:DI 28))]
-  "TARGET_ABICALLS && Pmode == DImode"
-  "")
+    addr = plus_constant (operands[0], GET_MODE_SIZE (Pmode) * 3);
+    emit_move_insn (gen_rtx_MEM (Pmode, addr), pic_offset_table_rtx);
+    DONE;
+  })
 
-;; For o32/n32/n64, we need to arrange for longjmp to put the
-;; target address in t9 so that we can use it for loading $gp.
+;; Restore the gp that we saved above.  Despite the comment, it seems that
+;; older code did recalculate the gp from $25.  Continue to jump through
+;; $25 for compatibility (we lose nothing by doing so).
 
 (define_expand "builtin_longjmp"
-  [(unspec_volatile [(match_operand 0 "register_operand" "r")] UNSPEC_LONGJMP)]
+  [(use (match_operand 0 "register_operand" "r"))]
   "TARGET_ABICALLS"
   "
 {
   /* The elements of the buffer are, in order:  */
-  int W = (Pmode == DImode ? 8 : 4);
+  int W = GET_MODE_SIZE (Pmode);
   rtx fp = gen_rtx_MEM (Pmode, operands[0]);
   rtx lab = gen_rtx_MEM (Pmode, plus_constant (operands[0], 1*W));
   rtx stack = gen_rtx_MEM (Pmode, plus_constant (operands[0], 2*W));
   rtx gpv = gen_rtx_MEM (Pmode, plus_constant (operands[0], 3*W));
-  rtx pv = gen_rtx_REG (Pmode, 25);
-  rtx gp = gen_rtx_REG (Pmode, 28);
-
-  /* This bit is the same as expand_builtin_longjmp.  */
+  rtx pv = gen_rtx_REG (Pmode, PIC_FUNCTION_ADDR_REGNUM);
+  /* Use gen_raw_REG to avoid being given pic_offset_table_rtx.
+     The target is bound to be using $28 as the global pointer
+     but the current function might not be.  */
+  rtx gp = gen_raw_REG (Pmode, GLOBAL_POINTER_REGNUM);
+
+  /* This bit is similar to expand_builtin_longjmp except that it
+     restores $gp as well.  */
   emit_move_insn (hard_frame_pointer_rtx, fp);
   emit_move_insn (pv, lab);
   emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX);