OSDN Git Service

Jakub Jelinek <jakub@redhat.com>
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 30 Nov 1999 22:18:21 +0000 (22:18 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 30 Nov 1999 22:18:21 +0000 (22:18 +0000)
        * config/sparc/sparc.h (FIXED_REGISTERS, CONDITIONAL_REGISTER_USAGE):
        Allow the user to override call-used/fixed state of %g2-5
        registers from the command line (with the exception of %g4 for
        embedded model).
        (REG_LEAF_ALLOC_ORDER): Move %g1 and %g4-7 registers to front, so that
        there is a higher chance of having a leaf function.
        (MACHINE_STATE_SAVE, MACHINE_STATE_RESTORE): Provide separate macros
        for ARCH64 which has %ccr register.
        * config/sparc/sparc.md (return_losum_si, return_losum_di): New
        patterns.
        * config/sparc/sparc.c (eligible_for_epilogue_delay): For the return
        insn accept into delay slot any insn which does not use %[ol]
        registers.  Accept some LO_SUM and shift left by 1 for the normal
        restore case.
        (output_function_epilogue): Likewise.
        (epilogue_renumber): Added argument which inhibits any renumbering
        and just tests if the rtx does not use any %[ol] registers.
        (output_return): Reflect above change.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@30727 138bc75d-0d04-0410-961f-82ee72b054a4

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

index 861774f..6210e8a 100644 (file)
@@ -1,5 +1,26 @@
 1999-11-30  Jakub Jelinek  <jakub@redhat.com>
 
+       * config/sparc/sparc.h (FIXED_REGISTERS, CONDITIONAL_REGISTER_USAGE):
+       Allow the user to override call-used/fixed state of %g2-5
+       registers from the command line (with the exception of %g4 for
+       embedded model).
+       (REG_LEAF_ALLOC_ORDER): Move %g1 and %g4-7 registers to front, so that
+       there is a higher chance of having a leaf function.
+       (MACHINE_STATE_SAVE, MACHINE_STATE_RESTORE): Provide separate macros
+       for ARCH64 which has %ccr register.
+       * config/sparc/sparc.md (return_losum_si, return_losum_di): New
+       patterns.
+       * config/sparc/sparc.c (eligible_for_epilogue_delay): For the return
+       insn accept into delay slot any insn which does not use %[ol]
+       registers.  Accept some LO_SUM and shift left by 1 for the normal
+       restore case.
+       (output_function_epilogue): Likewise.
+       (epilogue_renumber): Added argument which inhibits any renumbering
+       and just tests if the rtx does not use any %[ol] registers.
+       (output_return): Reflect above change.
+
+1999-11-30  Jakub Jelinek  <jakub@redhat.com>
+
        * config/sparc/sparc.c (sparc_va_arg): Fix sparc64 va_arg
        aggregate passing for sizes <= 16 bytes.
 
index 54c0230..22c0fbf 100644 (file)
@@ -63,6 +63,10 @@ Boston, MA 02111-1307, USA.  */
 static int apparent_fsize;
 static int actual_fsize;
 
+/* Number of live general or floating point registers needed to be saved
+   (as 4-byte quantities).  This is only done if TARGET_EPILOGUE.  */
+static int num_gfregs;
+
 /* Save the operands last given to a compare for use when we
    generate a scc or bcc insn.  */
 
@@ -124,7 +128,7 @@ static void sparc_output_deferred_case_vectors PROTO((void));
 static void sparc_add_gc_roots    PROTO ((void));
 static void mark_ultrasparc_pipeline_state PROTO ((void *));
 static int check_return_regs PROTO ((rtx));
-static void epilogue_renumber PROTO ((rtx *));
+static int epilogue_renumber PROTO ((rtx *, int));
 static int ultra_cmove_results_ready_p PROTO ((rtx));
 static int ultra_fpmode_conflict_exists PROTO ((enum machine_mode));
 static rtx *ultra_find_type PROTO ((int, rtx *, int));
@@ -2208,6 +2212,11 @@ eligible_for_epilogue_delay (trial, slot)
      optimize things as necessary.  */
   if (TARGET_LIVE_G0)
     return 0;
+    
+  /* If there are any call-saved registers, we should scan TRIAL if it
+     does not reference them.  For now just make it easy.  */
+  if (num_gfregs)
+    return 0;
 
   /* In the case of a true leaf function, anything can go into the delay slot.
      A delay slot only exists however if the frame size is zero, otherwise
@@ -2228,7 +2237,7 @@ eligible_for_epilogue_delay (trial, slot)
   pat = PATTERN (trial);
 
   /* Otherwise, only operations which can be done in tandem with
-     a `restore' insn can go into the delay slot.  */
+     a `restore' or `return' insn can go into the delay slot.  */
   if (GET_CODE (SET_DEST (pat)) != REG
       || REGNO (SET_DEST (pat)) >= 32
       || REGNO (SET_DEST (pat)) < 24)
@@ -2247,7 +2256,7 @@ eligible_for_epilogue_delay (trial, slot)
       else
         return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (SImode);
     }
-    
+
   /* This matches "*return_di".  */
   else if (arith_double_operand (src, GET_MODE (src)))
     return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode);
@@ -2257,6 +2266,12 @@ eligible_for_epilogue_delay (trial, slot)
           && register_operand (src, SFmode))
     return 1;
 
+  /* If we have return instruction, anything that does not use
+     local or output registers and can go into a delay slot wins.  */
+  else if (TARGET_V9 && ! epilogue_renumber (&pat, 1)
+          && (get_attr_in_uncond_branch_delay (trial) == IN_BRANCH_DELAY_TRUE))
+    return 1;
+
   /* This matches "*return_addsi".  */
   else if (GET_CODE (src) == PLUS
           && arith_operand (XEXP (src, 0), SImode)
@@ -2273,6 +2288,25 @@ eligible_for_epilogue_delay (trial, slot)
               || register_operand (XEXP (src, 1), DImode)))
     return 1;
 
+  /* This can match "*return_losum_[sd]i".
+     Catch only some cases, so that return_losum* don't have
+     to be too big.  */
+  else if (GET_CODE (src) == LO_SUM
+          && ! TARGET_CM_MEDMID
+          && ((register_operand (XEXP (src, 0), SImode)
+               && immediate_operand (XEXP (src, 1), SImode))
+              || (TARGET_ARCH64
+                  && register_operand (XEXP (src, 0), DImode)
+                  && immediate_operand (XEXP (src, 1), DImode))))
+    return 1;
+
+  /* sll{,x} reg,1,reg2 is add reg,reg,reg2 as well.  */
+  else if (GET_CODE (src) == ASHIFT
+          && (register_operand (XEXP (src, 0), SImode)
+              || register_operand (XEXP (src, 0), DImode))
+          && XEXP (src, 1) == const1_rtx)
+    return 1;
+
   return 0;
 }
 
@@ -2979,12 +3013,6 @@ restore_regs (file, low, high, base, offset, n_regs)
   return n_regs;
 }
 
-/* Static variables we want to share between prologue and epilogue.  */
-
-/* Number of live general or floating point registers needed to be saved
-   (as 4-byte quantities).  This is only done if TARGET_EPILOGUE.  */
-static int num_gfregs;
-
 /* Compute the frame size required by the function.  This function is called
    during the reload pass and also by output_function_prologue().  */
 
@@ -3283,7 +3311,7 @@ output_function_epilogue (file, size, leaf_function)
 #endif
 
   else if (current_function_epilogue_delay_list == 0)
-    {                                                
+    {
       /* If code does not drop into the epilogue, we need
         do nothing except output pending case vectors.  */
       rtx insn = get_last_insn ();                               
@@ -3339,13 +3367,38 @@ output_function_epilogue (file, size, leaf_function)
          /* If we wound up with things in our delay slot, flush them here.  */
          if (current_function_epilogue_delay_list)
            {
-             rtx insn = emit_jump_insn_after (gen_rtx_RETURN (VOIDmode),
-                                              get_last_insn ());
-             PATTERN (insn) = gen_rtx_PARALLEL (VOIDmode,
-                                       gen_rtvec (2,
-                                                  PATTERN (XEXP (current_function_epilogue_delay_list, 0)),
-                                                  PATTERN (insn)));
-             final_scan_insn (insn, file, 1, 0, 1);
+             rtx delay = PATTERN (XEXP (current_function_epilogue_delay_list, 0));
+
+             if (TARGET_V9 && ! epilogue_renumber (&delay, 1))
+               {
+                 epilogue_renumber (&delay, 0);
+                 fputs (SKIP_CALLERS_UNIMP_P
+                        ? "\treturn\t%i7+12\n"
+                        : "\treturn\t%i7+8\n", file);
+                 final_scan_insn (XEXP (current_function_epilogue_delay_list, 0), file, 1, 0, 0);
+               }
+             else
+               {
+                 rtx insn = emit_jump_insn_after (gen_rtx_RETURN (VOIDmode),
+                                                  get_last_insn ());
+                 rtx src;
+
+                 if (GET_CODE (delay) != SET)
+                   abort();
+
+                 src = SET_SRC (delay);
+                 if (GET_CODE (src) == ASHIFT)
+                   {
+                     if (XEXP (src, 1) != const1_rtx)
+                       abort();
+                     SET_SRC (delay) = gen_rtx_PLUS (GET_MODE (src), XEXP (src, 0),
+                                                     XEXP (src, 0));
+                   }
+
+                 PATTERN (insn) = gen_rtx_PARALLEL (VOIDmode,
+                                       gen_rtvec (2, delay, PATTERN (insn)));
+                 final_scan_insn (insn, file, 1, 0, 1);
+               }
            }
          else if (TARGET_V9 && ! SKIP_CALLERS_UNIMP_P)
            fputs ("\treturn\t%i7+8\n\tnop\n", file);
@@ -4726,56 +4779,56 @@ output_v9branch (op, reg, label, reversed, annul, noop, insn)
   return string;
 }
 
-/* Renumber registers in delay slot.  Replace registers instead of
-   renumbering because they may be shared.
-
  This does not handle instructions other than move.  */
+/* Return 1, if any of the registers of the instruction are %l[0-7] or %o[0-7].
+   Such instructions cannot be used in the delay slot of return insn on v9.
+   If TEST is 0, also rename all %i[0-7] registers to their %o[0-7] counterparts.
+ */
 
-static void
-epilogue_renumber (where)
-     rtx *where;
+static int
+epilogue_renumber (where, test)
+     register rtx *where;
+     int test;
 {
-  rtx x = *where;
-  enum rtx_code code = GET_CODE (x);
+  register const char *fmt;
+  register int i;
+  register enum rtx_code code;
+
+  if (*where == 0)
+    return 0;
+
+  code = GET_CODE (*where);
 
   switch (code)
     {
-    case MEM:
-      *where = x = copy_rtx (x);
-      epilogue_renumber (&XEXP (x, 0));
-      return;
-
     case REG:
-      {
-       int regno = REGNO (x);
-       if (regno > 8 && regno < 24)
-         abort ();
-       if (regno >= 24 && regno < 32)
-         *where = gen_rtx_REG (GET_MODE (x), regno - 16);
-       return;
-      }
+      if (REGNO (*where) >= 8 && REGNO (*where) < 24)      /* oX or lX */
+       return 1;
+      if (! test && REGNO (*where) >= 24 && REGNO (*where) < 32)
+       *where = gen_rtx (REG, GET_MODE (*where), OUTGOING_REGNO (REGNO(*where)));
+    case SCRATCH:
+    case CC0:
+    case PC:
     case CONST_INT:
     case CONST_DOUBLE:
-    case CONST:
-    case SYMBOL_REF:
-    case LABEL_REF:
-      return;
+      return 0;
+    }
 
-    case IOR:
-    case AND:
-    case XOR:
-    case PLUS:
-    case MINUS:
-      epilogue_renumber (&XEXP (x, 1));
-    case NEG:
-    case NOT:
-      epilogue_renumber (&XEXP (x, 0));
-      return;
+  fmt = GET_RTX_FORMAT (code);
 
-    default:
-      debug_rtx (*where);
-      abort ();
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'E')
+       {
+         register int j;
+         for (j = XVECLEN (*where, i) - 1; j >= 0; j--)
+           if (epilogue_renumber (&(XVECEXP (*where, i, j)), test))
+             return 1;
+       }
+      else if (fmt[i] == 'e'
+              && epilogue_renumber (&(XEXP (*where, i)), test))
+       return 1;
     }
+  return 0;
 }
 
 /* Output assembler code to return from a function.  */
@@ -4840,8 +4893,8 @@ output_return (operands)
     {
       if (delay)
        {
-         epilogue_renumber (&SET_DEST (PATTERN (delay)));
-         epilogue_renumber (&SET_SRC (PATTERN (delay)));
+         epilogue_renumber (&SET_DEST (PATTERN (delay)), 0);
+         epilogue_renumber (&SET_SRC (PATTERN (delay)), 0);
        }
       if (SKIP_CALLERS_UNIMP_P)
        return "return\t%%i7+12%#";
index 7d02de3..f402b83 100644 (file)
@@ -962,7 +962,7 @@ if (TARGET_ARCH64                           \
 */
 
 #define FIXED_REGISTERS  \
- {1, 0, 0, 0, 0, 0, 1, 1,      \
+ {1, 0, 2, 2, 2, 2, 1, 1,      \
   0, 0, 0, 0, 0, 0, 1, 0,      \
   0, 0, 0, 0, 0, 0, 0, 0,      \
   0, 0, 0, 0, 0, 0, 1, 1,      \
@@ -1015,10 +1015,12 @@ do                                                              \
        fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;                \
        call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;            \
       }                                                                \
-    if (TARGET_ARCH32)                                         \
-      {                                                                \
-       fixed_regs[5] = 1;                                      \
-      }                                                                \
+    /* If the user has passed -f{fixed,call-{used,saved}}-g5 */        \
+    /* then honour it.  */                                     \
+    if (TARGET_ARCH32 && fixed_regs[5])                                \
+      fixed_regs[5] = 1;                                       \
+    else if (TARGET_ARCH64 && fixed_regs[5] == 2)              \
+      fixed_regs[5] = 0;                                       \
     if (TARGET_LIVE_G0)                                                \
       fixed_regs[0] = 0;                                       \
     if (! TARGET_V9)                                           \
@@ -1040,10 +1042,18 @@ do                                                              \
        for (regno = 32; regno < SPARC_LAST_V9_FCC_REG; regno++) \
          fixed_regs[regno] = 1;                                \
       }                                                                \
-    /* Don't unfix g2-g4 if they were fixed with -ffixed-.  */ \
-    fixed_regs[2] |= ! TARGET_APP_REGS;                                \
-    fixed_regs[3] |= ! TARGET_APP_REGS;                                \
-    fixed_regs[4] |= ! TARGET_APP_REGS || TARGET_CM_EMBMEDANY; \
+    /* If the user has passed -f{fixed,call-{used,saved}}-g2 */        \
+    /* then honour it.  Likewise with g3 and g4.  */           \
+    if (fixed_regs[2] == 2)                                    \
+      fixed_regs[2] = ! TARGET_APP_REGS;                       \
+    if (fixed_regs[3] == 2)                                    \
+      fixed_regs[3] = ! TARGET_APP_REGS;                       \
+    if (TARGET_ARCH32 && fixed_regs[4] == 2)                   \
+      fixed_regs[4] = ! TARGET_APP_REGS;                       \
+    else if (TARGET_CM_EMBMEDANY)                              \
+      fixed_regs[4] = 1;                                       \
+    else if (fixed_regs[4] == 2)                               \
+      fixed_regs[4] = 0;                                       \
     if (TARGET_FLAT)                                           \
       {                                                                \
        /* Let the compiler believe the frame pointer is still  \
@@ -1335,11 +1345,12 @@ extern enum reg_class sparc_regno_reg_class[];
   1, 4, 5, 6, 7, 0, 14, 30}
 
 /* This is the order in which to allocate registers for
-   leaf functions.  If all registers can fit in the "i" registers,
+   leaf functions.  If all registers can fit in the "gi" registers,
    then we have the possibility of having a leaf function.  */
 
 #define REG_LEAF_ALLOC_ORDER \
 { 2, 3, 24, 25, 26, 27, 28, 29,                \
+  4, 5, 6, 7, 1,                       \
   15, 8, 9, 10, 11, 12, 13,            \
   16, 17, 18, 19, 20, 21, 22, 23,      \
   34, 35, 36, 37, 38, 39,              \
@@ -1352,8 +1363,8 @@ extern enum reg_class sparc_regno_reg_class[];
   88, 89, 90, 91, 92, 93, 94, 95,      \
   32, 33,                              \
   96, 97, 98, 99, 100,                 \
-  1, 4, 5, 6, 7, 0, 14, 30, 31}
-
+  0, 14, 30, 31}
+  
 #define ORDER_REGS_FOR_LOCAL_ALLOC order_regs_for_local_alloc ()
 
 /* ??? %g7 is not a leaf register to effectively #undef LEAF_REGISTERS when
@@ -1889,6 +1900,8 @@ do {                                                                      \
 #define FUNCTION_BLOCK_PROFILER_EXIT(FILE) \
   sparc_function_block_profiler_exit(FILE)
 
+#ifdef IN_LIBGCC2
+
 /* The function `__bb_trace_func' is called in every basic block
    and is not allowed to change the machine state. Saving (restoring)
    the state can either be done in the BLOCK_PROFILER macro,
@@ -1908,12 +1921,18 @@ do {                                                                    \
    On sparc it is sufficient to save the psw register to memory.
    Unfortunately the psw register can be read in supervisor mode only,
    so we read only the condition codes by using branch instructions
-   and hope that this is enough. */
+   and hope that this is enough.
+   
+   On V9, life is much sweater:  there is a user accessible %ccr
+   register, but we use it for 64bit libraries only.  */
+
+#if TARGET_ARCH32
 
 #define MACHINE_STATE_SAVE(ID)                 \
   int ms_flags, ms_saveret;                    \
   asm volatile(                                        \
-       "mov %%g0,%0\n\
+       "mov %%g2,%1\n\
+       mov %%g0,%0\n\
        be,a LFLGNZ"ID"\n\
        or %0,4,%0\n\
 LFLGNZ"ID":\n\
@@ -1925,10 +1944,20 @@ LFLGNC"ID":\n\
 LFLGNV"ID":\n\
        bneg,a LFLGNN"ID"\n\
        or %0,8,%0\n\
-LFLGNN"ID":\n\
-       mov %%g2,%1"                            \
+LFLGNN"ID":"                                   \
+       : "=r"(ms_flags), "=r"(ms_saveret));
+
+#else
+
+#define MACHINE_STATE_SAVE(ID)                 \
+  unsigned long ms_flags, ms_saveret;          \
+  asm volatile(                                        \
+       "mov %%g2,%1\n\                         \
+       rd %%ccr,%0"                            \
        : "=r"(ms_flags), "=r"(ms_saveret));
 
+#endif
+
 /* On sparc MACHINE_STATE_RESTORE restores the psw register from memory.
    The psw register can be written in supervisor mode only,
    which is true even for simple condition codes.
@@ -1937,6 +1966,8 @@ LFLGNN"ID":\n\
    be generated in this way. If this happens an unimplemented
    instruction will be executed to abort the program. */
 
+#if TARGET_ARCH32
+
 #define MACHINE_STATE_RESTORE(ID)                              \
 { extern char flgtab[] __asm__("LFLGTAB"ID);                   \
   int scratch;                                                 \
@@ -1995,7 +2026,20 @@ LFLGRET"ID":\n\
        : "=r"(scratch)                                         \
        : "r"(ms_flags*8), "r"(flgtab), "r"(-1),                \
          "r"(0x80000000), "r"(ms_saveret)                      \
-       : "cc", "%g2"); }
+       : "cc", "g2"); }
+
+#else
+
+#define MACHINE_STATE_RESTORE(ID)                              \
+  asm volatile (                                               \
+       "wr %0,0,%%ccr\n\
+       mov %1,%%g2"                                            \
+       : : "r"(ms_flags), "r"(ms_saveret)                      \
+       : "cc", "g2");
+
+#endif
+
+#endif /* IN_LIBGCC2 */
 \f
 /* EXIT_IGNORE_STACK should be nonzero if, when returning from a function,
    the stack pointer does not matter.  The value is tested only in
index 90d8641..95c6868 100644 (file)
 }"
   [(set_attr "type" "multi")])
 
+(define_insn "*return_losum_si"
+  [(set (match_operand:SI 0 "restore_operand" "")
+       (lo_sum:SI (match_operand:SI 1 "register_operand" "r")
+                  (match_operand:SI 2 "immediate_operand" "in")))
+   (return)]
+  "! TARGET_EPILOGUE && ! TARGET_LIVE_G0 && ! TARGET_CM_MEDMID"
+  "*
+{
+  if (! TARGET_ARCH64 && current_function_returns_struct)
+    return \"jmp\\t%%i7+12\\n\\trestore %r1, %%lo(%a2), %Y0\";
+  /* If operands are global or in registers, can use return */
+  else if (TARGET_V9 && IN_OR_GLOBAL_P (operands[1]))
+    return \"return\\t%%i7+8\\n\\tor\\t%Y1, %%lo(%a2), %Y0\";
+  else
+    return \"ret\;restore %r1, %%lo(%a2), %Y0\";
+}"
+  [(set_attr "type" "multi")])
+
 (define_insn "*return_di"
   [(set (match_operand:DI 0 "restore_operand" "")
        (match_operand:DI 1 "arith_double_operand" "rHI"))
   "ret\;restore %r1, %2, %Y0"
   [(set_attr "type" "multi")])
 
+(define_insn "*return_losum_di"
+  [(set (match_operand:DI 0 "restore_operand" "")
+       (lo_sum:DI (match_operand:DI 1 "arith_operand" "%r")
+                  (match_operand:DI 2 "immediate_operand" "in")))
+   (return)]
+  "TARGET_ARCH64 && ! TARGET_EPILOGUE && ! TARGET_CM_MEDMID"
+  "ret\;restore %r1, %%lo(a2), %Y0"
+  [(set_attr "type" "multi")])
+
 ;; The following pattern is only generated by delayed-branch scheduling,
 ;; when the insn winds up in the epilogue.
 (define_insn "*return_sf"