OSDN Git Service

PR target/16532
authorebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 28 Sep 2004 06:26:08 +0000 (06:26 +0000)
committerebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 28 Sep 2004 06:26:08 +0000 (06:26 +0000)
* config/sparc/sparc.c (struct machine_function): New field
'leaf_function_p' and 'prologue_data_valid_p'.
(sparc_leaf_function_p, sparc_prologue_data_valid_p): New macro
to conveniently access the above fields.
(TARGET_LATE_RTL_PROLOGUE_EPILOGUE): Delete.
(eligible_for_return_delay): Use 'sparc_leaf_function_p' instead
of the generic flavor 'current_function_uses_only_leaf_regs'.
(eligible_for_sibcall_delay): Likewise.
(sparc_expand_prologue): Compute 'sparc_leaf_function_p' and set
'sparc_prologue_data_valid_p'.  Use 'sparc_leaf_function_p'.
(sparc_asm_function_prologue): Add sanity check for the assumption
made in 'sparc_expand_prologue'.  Use 'sparc_leaf_function_p'.
(sparc_can_use_return_insn_p): New function.
(sparc_expand_epilogue): Use 'sparc_leaf_function_p'.
(output_restore): Likewise.
(output_sibcall): Likewise.
(sparc_output_mi_thunk): Likewise.
* config/sparc/sparc-protos.h (sparc_can_use_return_insn_p): Declare.
* config/sparc/sparc.md (return): New expander.

* config/sparc/sparc.h (INITIAL_ELIMINATION_OFFSET): Minor tweak.

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

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

index d7fb97a..678c005 100644 (file)
@@ -1,3 +1,28 @@
+2004-09-28  Eric Botcazou  <ebotcazou@libertysurf.fr>
+
+       PR target/16532
+       * config/sparc/sparc.c (struct machine_function): New field
+       'leaf_function_p' and 'prologue_data_valid_p'.
+       (sparc_leaf_function_p, sparc_prologue_data_valid_p): New macro
+       to conveniently access the above fields.
+       (TARGET_LATE_RTL_PROLOGUE_EPILOGUE): Delete.
+       (eligible_for_return_delay): Use 'sparc_leaf_function_p' instead
+       of the generic flavor 'current_function_uses_only_leaf_regs'.
+       (eligible_for_sibcall_delay): Likewise.
+       (sparc_expand_prologue): Compute 'sparc_leaf_function_p' and set
+       'sparc_prologue_data_valid_p'.  Use 'sparc_leaf_function_p'.
+       (sparc_asm_function_prologue): Add sanity check for the assumption
+       made in 'sparc_expand_prologue'.  Use 'sparc_leaf_function_p'.
+       (sparc_can_use_return_insn_p): New function.
+       (sparc_expand_epilogue): Use 'sparc_leaf_function_p'.
+       (output_restore): Likewise.
+       (output_sibcall): Likewise.
+       (sparc_output_mi_thunk): Likewise.
+       * config/sparc/sparc-protos.h (sparc_can_use_return_insn_p): Declare.
+       * config/sparc/sparc.md (return): New expander.
+
+       * config/sparc/sparc.h (INITIAL_ELIMINATION_OFFSET): Minor tweak.
+
 2004-09-27  Mark Mitchell  <mark@codesourcery.com>
 
        PR c++/17642
 2004-09-27  Mark Mitchell  <mark@codesourcery.com>
 
        PR c++/17642
index 71599c9..e181f8f 100644 (file)
@@ -47,6 +47,7 @@ extern void order_regs_for_local_alloc (void);
 extern HOST_WIDE_INT sparc_compute_frame_size (HOST_WIDE_INT, int);
 extern void sparc_expand_prologue (void);
 extern void sparc_expand_epilogue (void);
 extern HOST_WIDE_INT sparc_compute_frame_size (HOST_WIDE_INT, int);
 extern void sparc_expand_prologue (void);
 extern void sparc_expand_epilogue (void);
+extern bool sparc_can_use_return_insn_p (void);
 extern int check_pic (int);
 extern int short_branch (int, int);
 extern void sparc_profile_hook (int);
 extern int check_pic (int);
 extern int short_branch (int, int);
 extern void sparc_profile_hook (int);
index 63d3f01..aa1fa09 100644 (file)
@@ -270,8 +270,20 @@ struct machine_function GTY(())
 {
   /* Some local-dynamic TLS symbol name.  */
   const char *some_ld_name;
 {
   /* Some local-dynamic TLS symbol name.  */
   const char *some_ld_name;
+
+  /* True if the current function is leaf and uses only leaf regs,
+     so that the SPARC leaf function optimization can be applied.
+     Private version of current_function_uses_only_leaf_regs, see
+     sparc_expand_prologue for the rationale.  */
+  int leaf_function_p;
+
+  /* True if the data calculated by sparc_expand_prologue are valid.  */
+  bool prologue_data_valid_p;
 };
 
 };
 
+#define sparc_leaf_function_p  cfun->machine->leaf_function_p
+#define sparc_prologue_data_valid_p  cfun->machine->prologue_data_valid_p
+
 /* Register we pretend to think the frame pointer is allocated to.
    Normally, this is %fp, but if we are in a leaf procedure, this
    is %sp+"something".  We record "something" separately as it may
 /* Register we pretend to think the frame pointer is allocated to.
    Normally, this is %fp, but if we are in a leaf procedure, this
    is %sp+"something".  We record "something" separately as it may
@@ -452,9 +464,6 @@ enum processor_type sparc_cpu;
 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
 #define TARGET_GIMPLIFY_VA_ARG_EXPR sparc_gimplify_va_arg
 
 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
 #define TARGET_GIMPLIFY_VA_ARG_EXPR sparc_gimplify_va_arg
 
-#undef TARGET_LATE_RTL_PROLOGUE_EPILOGUE
-#define TARGET_LATE_RTL_PROLOGUE_EPILOGUE true
-
 #ifdef SUBTARGET_INSERT_ATTRIBUTES
 #undef TARGET_INSERT_ATTRIBUTES
 #define TARGET_INSERT_ATTRIBUTES SUBTARGET_INSERT_ATTRIBUTES
 #ifdef SUBTARGET_INSERT_ATTRIBUTES
 #undef TARGET_INSERT_ATTRIBUTES
 #define TARGET_INSERT_ATTRIBUTES SUBTARGET_INSERT_ATTRIBUTES
@@ -3154,7 +3163,6 @@ eligible_for_restore_insn (rtx trial, bool return_p)
 int
 eligible_for_return_delay (rtx trial)
 {
 int
 eligible_for_return_delay (rtx trial)
 {
-  int leaf_function_p = current_function_uses_only_leaf_regs;
   rtx pat;
 
   if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET)
   rtx pat;
 
   if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET)
@@ -3174,7 +3182,7 @@ eligible_for_return_delay (rtx trial)
     return 0;
 
   /* In the case of a true leaf function, anything can go into the slot.  */
     return 0;
 
   /* In the case of a true leaf function, anything can go into the slot.  */
-  if (leaf_function_p)
+  if (sparc_leaf_function_p)
     return get_attr_in_uncond_branch_delay (trial)
           == IN_UNCOND_BRANCH_DELAY_TRUE;
 
     return get_attr_in_uncond_branch_delay (trial)
           == IN_UNCOND_BRANCH_DELAY_TRUE;
 
@@ -3204,7 +3212,6 @@ eligible_for_return_delay (rtx trial)
 int
 eligible_for_sibcall_delay (rtx trial)
 {
 int
 eligible_for_sibcall_delay (rtx trial)
 {
-  int leaf_function_p = current_function_uses_only_leaf_regs;
   rtx pat;
 
   if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET)
   rtx pat;
 
   if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET)
@@ -3215,7 +3222,7 @@ eligible_for_sibcall_delay (rtx trial)
 
   pat = PATTERN (trial);
 
 
   pat = PATTERN (trial);
 
-  if (leaf_function_p)
+  if (sparc_leaf_function_p)
     {
       /* If the tail call is done using the call instruction,
         we have to restore %o7 in the delay slot.  */
     {
       /* If the tail call is done using the call instruction,
         we have to restore %o7 in the delay slot.  */
@@ -4469,13 +4476,40 @@ emit_stack_pointer_decrement (rtx decrement)
 void
 sparc_expand_prologue (void)
 {
 void
 sparc_expand_prologue (void)
 {
-  int leaf_function_p = current_function_uses_only_leaf_regs;
+  /* Compute a snapshot of current_function_uses_only_leaf_regs.  Relying
+     on the final value of the flag means deferring the prologue/epilogue
+     expansion until just before the second scheduling pass, which is too
+     late to emit multiple epilogues or return insns.
+
+     Of course we are making the assumption that the value of the flag
+     will not change between now and its final value.  Of the three parts
+     of the formula, only the last one can reasonably vary.  Let's take a
+     closer look, after assuming that the first two ones are set to true
+     (otherwise the last value is effectively silenced).
+
+     If only_leaf_regs_used returns false, the global predicate will also
+     be false so the actual frame size calculated below will be positive.
+     As a consequence, the save_register_window insn will be emitted in
+     the instruction stream; now this insn explicitly references %fp
+     which is not a leaf register so only_leaf_regs_used will always
+     return false subsequently.
+
+     If only_leaf_regs_used returns true, we hope that the subsequent
+     optimization passes won't cause non-leaf registers to pop up.  For
+     example, the regrename pass has special provisions to not rename to
+     non-leaf registers in a leaf function.  */
+  sparc_leaf_function_p
+    = optimize > 0 && leaf_function_p () && only_leaf_regs_used ();
 
   /* Need to use actual_fsize, since we are also allocating
      space for our callee (and our own register save area).  */
 
   /* Need to use actual_fsize, since we are also allocating
      space for our callee (and our own register save area).  */
-  actual_fsize = sparc_compute_frame_size (get_frame_size(), leaf_function_p);
+  actual_fsize
+    = sparc_compute_frame_size (get_frame_size(), sparc_leaf_function_p);
+
+  /* Advertise that the data calculated just above are now valid.  */
+  sparc_prologue_data_valid_p = true;
 
 
-  if (leaf_function_p)
+  if (sparc_leaf_function_p)
     {
       frame_base_reg = stack_pointer_rtx;
       frame_base_offset = actual_fsize + SPARC_STACK_BIAS;
     {
       frame_base_reg = stack_pointer_rtx;
       frame_base_offset = actual_fsize + SPARC_STACK_BIAS;
@@ -4488,7 +4522,7 @@ sparc_expand_prologue (void)
 
   if (actual_fsize == 0)
     /* do nothing.  */ ;
 
   if (actual_fsize == 0)
     /* do nothing.  */ ;
-  else if (leaf_function_p)
+  else if (sparc_leaf_function_p)
     {
       if (actual_fsize <= 4096)
        emit_stack_pointer_increment (GEN_INT (- actual_fsize));
     {
       if (actual_fsize <= 4096)
        emit_stack_pointer_increment (GEN_INT (- actual_fsize));
@@ -4542,7 +4576,9 @@ sparc_expand_prologue (void)
 static void
 sparc_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 {
 static void
 sparc_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 {
-  int leaf_function_p = current_function_uses_only_leaf_regs;
+  /* Check that the assumption we made in sparc_expand_prologue is valid.  */
+  if (sparc_leaf_function_p != current_function_uses_only_leaf_regs)
+    abort();
 
   sparc_output_scratch_registers (file);
 
 
   sparc_output_scratch_registers (file);
 
@@ -4552,12 +4588,12 @@ sparc_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 
       /* The canonical frame address refers to the top of the frame.  */
       dwarf2out_def_cfa (label,
 
       /* The canonical frame address refers to the top of the frame.  */
       dwarf2out_def_cfa (label,
-                        leaf_function_p
+                        sparc_leaf_function_p
                         ? STACK_POINTER_REGNUM
                         : HARD_FRAME_POINTER_REGNUM,
                         frame_base_offset);
 
                         ? STACK_POINTER_REGNUM
                         : HARD_FRAME_POINTER_REGNUM,
                         frame_base_offset);
 
-      if (! leaf_function_p)
+      if (! sparc_leaf_function_p)
        {
          /* Note the register window save.  This tells the unwinder that
             it needs to restore the window registers from the previous
        {
          /* Note the register window save.  This tells the unwinder that
             it needs to restore the window registers from the previous
@@ -4576,14 +4612,12 @@ sparc_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 void
 sparc_expand_epilogue (void)
 {
 void
 sparc_expand_epilogue (void)
 {
-  int leaf_function_p = current_function_uses_only_leaf_regs;
-
   if (num_gfregs)
     emit_restore_regs ();
 
   if (actual_fsize == 0)
     /* do nothing.  */ ;
   if (num_gfregs)
     emit_restore_regs ();
 
   if (actual_fsize == 0)
     /* do nothing.  */ ;
-  else if (leaf_function_p)
+  else if (sparc_leaf_function_p)
     {
       if (actual_fsize <= 4096)
        emit_stack_pointer_decrement (GEN_INT (- actual_fsize));
     {
       if (actual_fsize <= 4096)
        emit_stack_pointer_decrement (GEN_INT (- actual_fsize));
@@ -4600,6 +4634,16 @@ sparc_expand_epilogue (void)
        }
     }
 }
        }
     }
 }
+
+/* Return true if it is appropriate to emit `return' instructions in the
+   body of a function.  */
+
+bool
+sparc_can_use_return_insn_p (void)
+{
+  return sparc_prologue_data_valid_p
+        && (actual_fsize == 0 || !sparc_leaf_function_p);
+}
   
 /* This function generates the assembly code for function exit.  */
   
   
 /* This function generates the assembly code for function exit.  */
   
@@ -4677,7 +4721,7 @@ output_restore (rtx pat)
 const char *
 output_return (rtx insn)
 {
 const char *
 output_return (rtx insn)
 {
-  if (current_function_uses_only_leaf_regs)
+  if (sparc_leaf_function_p)
     {
       /* This is a leaf function so we don't have to bother restoring the
         register window, which frees us from dealing with the convoluted
     {
       /* This is a leaf function so we don't have to bother restoring the
         register window, which frees us from dealing with the convoluted
@@ -4766,7 +4810,7 @@ output_sibcall (rtx insn, rtx call_operand)
 
   operands[0] = call_operand;
 
 
   operands[0] = call_operand;
 
-  if (current_function_uses_only_leaf_regs)
+  if (sparc_leaf_function_p)
     {
       /* This is a leaf function so we don't have to bother restoring the
         register window.  We simply output the jump to the function and
     {
       /* This is a leaf function so we don't have to bother restoring the
         register window.  We simply output the jump to the function and
@@ -8499,7 +8543,7 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
     {
       /* We will emit a regular sibcall below, so we need to instruct
         output_sibcall that we are in a leaf function.  */
     {
       /* We will emit a regular sibcall below, so we need to instruct
         output_sibcall that we are in a leaf function.  */
-      current_function_uses_only_leaf_regs = 1;
+      sparc_leaf_function_p = 1;
 
       /* This will cause final.c to invoke leaf_renumber_regs so we
         must behave as if we were in a not-yet-leafified function.  */
 
       /* This will cause final.c to invoke leaf_renumber_regs so we
         must behave as if we were in a not-yet-leafified function.  */
@@ -8509,7 +8553,7 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
     {
       /* We will emit the sibcall manually below, so we will need to
         manually spill non-leaf registers.  */
     {
       /* We will emit the sibcall manually below, so we will need to
         manually spill non-leaf registers.  */
-      current_function_uses_only_leaf_regs = 0;
+      sparc_leaf_function_p = 0;
 
       /* We really are in a leaf function.  */
       int_arg_first = SPARC_OUTGOING_INT_ARG_FIRST;
 
       /* We really are in a leaf function.  */
       int_arg_first = SPARC_OUTGOING_INT_ARG_FIRST;
index 5cf5201..d1b93ec 100644 (file)
@@ -1121,8 +1121,7 @@ extern int sparc_mode_class[];
 /* Value should be nonzero if functions must have frame pointers.
    Zero means the frame pointer need not be set up (and parms
    may be accessed via the stack pointer) in functions that seem suitable.
 /* Value should be nonzero if functions must have frame pointers.
    Zero means the frame pointer need not be set up (and parms
    may be accessed via the stack pointer) in functions that seem suitable.
-   This is computed in `reload', in reload1.c.
-   Used in flow.c, global.c, and reload1.c.  */
+   Used in flow.c, global.c, ra.c and reload1.c.  */
 #define FRAME_POINTER_REQUIRED \
   (! (leaf_function_p () && only_leaf_regs_used ()))
 
 #define FRAME_POINTER_REQUIRED \
   (! (leaf_function_p () && only_leaf_regs_used ()))
 
@@ -1594,9 +1593,10 @@ extern char leaf_reg_remap[];
    is a leaf function, we guessed right!  */
 #define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET)                   \
   do {                                                                 \
    is a leaf function, we guessed right!  */
 #define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET)                   \
   do {                                                                 \
-    (OFFSET) = 0;                                                      \
     if ((TO) == STACK_POINTER_REGNUM)                                  \
       (OFFSET) = sparc_compute_frame_size (get_frame_size (), 1);      \
     if ((TO) == STACK_POINTER_REGNUM)                                  \
       (OFFSET) = sparc_compute_frame_size (get_frame_size (), 1);      \
+    else                                                               \
+      (OFFSET) = 0;                                                    \
     (OFFSET) += SPARC_STACK_BIAS;                                      \
   } while (0)
 
     (OFFSET) += SPARC_STACK_BIAS;                                      \
   } while (0)
 
index a077f8c..d91e51d 100644 (file)
   sparc_expand_epilogue ();
 })
 
   sparc_expand_epilogue ();
 })
 
+(define_expand "return"
+  [(return)]
+  "sparc_can_use_return_insn_p ()"
+  "")
+
 (define_insn "*return_internal"
   [(return)]
   ""
 (define_insn "*return_internal"
   [(return)]
   ""