Add sibcall handling for rs6000 target.
authorDale Johannesen <dalej@apple.com>
Fri, 9 Aug 2002 17:52:50 +0000 (17:52 +0000)
committerDale Johannesen <dalej@gcc.gnu.org>
Fri, 9 Aug 2002 17:52:50 +0000 (17:52 +0000)
From-SVN: r56166

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

index aa73454452125a9a2a36241ed11db7a9ac8830bc..a8b9a1901fa790aedd8f4042e45f83ffc241e4f5 100644 (file)
@@ -1,3 +1,11 @@
+2002-08-09  Dale Johannesen  <dalej@apple.com>
+       * config/rs6000/rs6000.md: Add sibcall patterns.
+       * config/rs6000/rs6000.h (FUNCTION_OK_FOR_SIBCALL):  Define.
+       * config/rs6000/rs6000.c (rs6000_ra_ever_killed):
+       Rewritten to handle sibcalls.
+       * config/rs6000/rs6000.c (function_ok_for_sibcall):  New.
+       * config/rs6000/rs6000-protos.h (function_ok_for_sibcall):  New.
+
 2002-08-08  Nathan Sidwell  <nathan@codesourcery.com>
 
        * profile.c (da_file_name): New static var.
index 42563d30378cb8b43d5bdd4723b564835b97e3ee..42092118f60078706b2e85df392232fc1504793e 100644 (file)
@@ -151,6 +151,7 @@ extern void setup_incoming_varargs PARAMS ((CUMULATIVE_ARGS *,
                                            int *, int));
 extern struct rtx_def *rs6000_va_arg PARAMS ((tree, tree));
 extern void output_mi_thunk PARAMS ((FILE *, tree, int, tree));
+extern int function_ok_for_sibcall PARAMS ((tree));
 #ifdef ARGS_SIZE_RTX
 /* expr.h defines ARGS_SIZE_RTX and `enum direction' */
 extern enum direction function_arg_padding PARAMS ((enum machine_mode, tree));
index ad99417d978a2a972c7c70ad5d57f01645f1e436..28a0a7583b445cc756f07731e7839db454050d96 100644 (file)
@@ -9412,25 +9412,82 @@ rs6000_return_addr (count, frame)
   return get_hard_reg_initial_val (Pmode, LINK_REGISTER_REGNUM);
 }
 
+/* Say whether a function is a candidate for sibcall handling or not.
+   We do not allow indirect calls to be optimized into sibling calls.
+   Also, we can't do it if there are any vector parameters; there's
+   nowhere to put the VRsave code so it works; note that functions with
+   vector parameters are required to have a prototype, so the argument
+   type info must be available here.  (The tail recursion case can work
+   with vector parameters, but there's no way to distinguish here.) */
+int
+function_ok_for_sibcall (fndecl)
+    tree fndecl;
+{
+  tree type;
+  if (fndecl)
+    {
+      if (TARGET_ALTIVEC_VRSAVE)
+        {
+         for (type = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
+              type; type = TREE_CHAIN (type))
+           {
+             if (TREE_CODE (TREE_VALUE (type)) == VECTOR_TYPE )
+               return 0;
+           }
+        }
+      if (DEFAULT_ABI == ABI_DARWIN
+            || (TREE_ASM_WRITTEN (fndecl) && !flag_pic) || !TREE_PUBLIC (fndecl))
+        return 1;
+    }
+  return 0;
+}
+
+/* function rewritten to handle sibcalls */
 static int
 rs6000_ra_ever_killed ()
 {
   rtx top;
+  rtx reg;
+  rtx insn;
 
 #ifdef ASM_OUTPUT_MI_THUNK
   if (current_function_is_thunk)
     return 0;
 #endif
-  if (!has_hard_reg_initial_val (Pmode, LINK_REGISTER_REGNUM)
-      || cfun->machine->ra_needs_full_frame)
-    return regs_ever_live[LINK_REGISTER_REGNUM];
-
+  /* regs_ever_live has LR marked as used if any sibcalls
+     are present.  Which it is, but this should not force
+     saving and restoring in the prologue/epilog.  Likewise,
+     reg_set_between_p thinks a sibcall clobbers LR, so
+     that is inappropriate. */
+  /* Also, the prologue can generate a store into LR that
+     doesn't really count, like this:
+        move LR->R0
+        bcl to set PIC register
+        move LR->R31
+        move R0->LR
+     When we're called from the epilog, we need to avoid counting
+     this as a store; thus we ignore any insns with a REG_MAYBE_DEAD note. */
+         
   push_topmost_sequence ();
   top = get_insns ();
   pop_topmost_sequence ();
+  reg = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
 
-  return reg_set_between_p (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM), 
-                           top, NULL_RTX);
+  for (insn = NEXT_INSN (top); insn != NULL_RTX; insn = NEXT_INSN (insn))
+    {
+      if (INSN_P (insn))
+       {
+         if (FIND_REG_INC_NOTE (insn, reg))
+           return 1;
+         else if (GET_CODE (insn) == CALL_INSN 
+                   && !SIBLING_CALL_P (insn))
+           return 1;
+         else if (set_of (reg, insn) != NULL_RTX 
+                   && find_reg_note (insn, REG_MAYBE_DEAD, NULL_RTX) == 0)
+           return 1;
+       }
+    }
+  return 0;
 }
 \f
 /* Add a REG_MAYBE_DEAD note to the insn.  */
index 17a3015e3fbcc94a08948a6c860c0793cb38e8cc..42aa929b855bd889e7e021a1eabbb8f37738058a 100644 (file)
@@ -1798,6 +1798,10 @@ typedef struct rs6000_args
    argument is passed depends on whether or not it is a named argument.  */
 #define STRICT_ARGUMENT_NAMING 1
 
+/* We do not allow indirect calls to be optimized into sibling calls, nor
+   do we allow calls with vector parameters.  */
+#define FUNCTION_OK_FOR_SIBCALL(DECL) function_ok_for_sibcall ((DECL))
+
 /* Output assembler code to FILE to increment profiler label # LABELNO
    for profiling a function entry.  */
 
index dd1cad7353bd0e17579fc7912434d9fa9285d481..4a441e224477e7d1f4388a7571c1fdb4cc9cd7d9 100644 (file)
   DONE;
 }")
 
+;; sibling call patterns
+(define_expand "sibcall"
+  [(parallel [(call (mem:SI (match_operand 0 "address_operand" ""))
+                   (match_operand 1 "" ""))
+             (use (match_operand 2 "" ""))
+             (use (scratch:SI))
+             (return)])]
+  ""
+  "
+{
+#if TARGET_MACHO
+  if (flag_pic)
+    operands[0] = machopic_indirect_call_target (operands[0]);
+#endif
+
+  if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != CONST_INT)
+    abort ();
+
+  operands[0] = XEXP (operands[0], 0);
+
+}")
+
+;; this and similar patterns must be marked as using LR, otherwise
+;; dataflow will try to delete the store into it.  This is true
+;; even when the actual reg to jump to is in CTR, when LR was
+;; saved and restored around the PIC-setting BCL.
+(define_insn "*sibcall_local32"
+  [(call (mem:SI (match_operand:SI 0 "current_file_function_operand" "s,s"))
+        (match_operand 1 "" "g,g"))
+   (use (match_operand:SI 2 "immediate_operand" "O,n"))
+   (use (match_scratch:SI 3 "=l,l"))
+   (return)]
+  "(INTVAL (operands[2]) & CALL_LONG) == 0"
+  "*
+{
+  if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS)
+    output_asm_insn (\"crxor 6,6,6\", operands);
+
+  else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
+    output_asm_insn (\"creqv 6,6,6\", operands);
+
+  return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"b %z0@local\" : \"b %z0\";
+}"
+  [(set_attr "type" "branch")
+   (set_attr "length" "4,8")])
+
+(define_insn "*sibcall_local64"
+  [(call (mem:SI (match_operand:DI 0 "current_file_function_operand" "s,s"))
+        (match_operand 1 "" "g,g"))
+   (use (match_operand:SI 2 "immediate_operand" "O,n"))
+   (use (match_scratch:SI 3 "=l,l"))
+   (return)]
+  "TARGET_64BIT && (INTVAL (operands[2]) & CALL_LONG) == 0"
+  "*
+{
+  if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS)
+    output_asm_insn (\"crxor 6,6,6\", operands);
+
+  else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
+    output_asm_insn (\"creqv 6,6,6\", operands);
+
+  return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"b %z0@local\" : \"b %z0\";
+}"
+  [(set_attr "type" "branch")
+   (set_attr "length" "4,8")])
+
+(define_insn "*sibcall_value_local32"
+  [(set (match_operand 0 "" "")
+       (call (mem:SI (match_operand:SI 1 "current_file_function_operand" "s,s"))
+             (match_operand 2 "" "g,g")))
+   (use (match_operand:SI 3 "immediate_operand" "O,n"))
+   (use (match_scratch:SI 4 "=l,l"))
+   (return)]
+  "(INTVAL (operands[3]) & CALL_LONG) == 0"
+  "*
+{
+  if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
+    output_asm_insn (\"crxor 6,6,6\", operands);
+
+  else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
+    output_asm_insn (\"creqv 6,6,6\", operands);
+
+  return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"b %z1@local\" : \"b %z1\";
+}"
+  [(set_attr "type" "branch")
+   (set_attr "length" "4,8")])
+
+
+(define_insn "*sibcall_value_local64"
+  [(set (match_operand 0 "" "")
+       (call (mem:SI (match_operand:DI 1 "current_file_function_operand" "s,s"))
+             (match_operand 2 "" "g,g")))
+   (use (match_operand:SI 3 "immediate_operand" "O,n"))
+   (use (match_scratch:SI 4 "=l,l"))
+   (return)]
+  "TARGET_64BIT && (INTVAL (operands[3]) & CALL_LONG) == 0"
+  "*
+{
+  if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
+    output_asm_insn (\"crxor 6,6,6\", operands);
+
+  else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
+    output_asm_insn (\"creqv 6,6,6\", operands);
+
+  return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"b %z1@local\" : \"b %z1\";
+}"
+  [(set_attr "type" "branch")
+   (set_attr "length" "4,8")])
+
+(define_insn "*sibcall_nonlocal_aix32"
+  [(call (mem:SI (match_operand:SI 0 "symbol_ref_operand" "s"))
+        (match_operand 1 "" "g"))
+   (use (match_operand:SI 2 "immediate_operand" "O"))
+   (use (match_scratch:SI 3 "=l"))
+   (return)]
+  "TARGET_32BIT
+   && DEFAULT_ABI == ABI_AIX
+   && (INTVAL (operands[2]) & CALL_LONG) == 0"
+  "b %z0"
+  [(set_attr "type" "branch")
+   (set_attr "length" "4")])
+
+(define_insn "*sibcall_nonlocal_aix64"
+  [(call (mem:SI (match_operand:DI 0 "symbol_ref_operand" "s"))
+        (match_operand 1 "" "g"))
+   (use (match_operand:SI 2 "immediate_operand" "O"))
+   (use (match_scratch:SI 3 "=l"))
+   (return)]
+  "TARGET_64BIT 
+   && DEFAULT_ABI == ABI_AIX
+   && (INTVAL (operands[2]) & CALL_LONG) == 0"
+  "b %z0"
+  [(set_attr "type" "branch")
+   (set_attr "length" "4")])
+
+(define_insn "*sibcall_value_nonlocal_aix32"
+  [(set (match_operand 0 "" "")
+       (call (mem:SI (match_operand:SI 1 "symbol_ref_operand" "s"))
+             (match_operand 2 "" "g")))
+   (use (match_operand:SI 3 "immediate_operand" "O"))
+   (use (match_scratch:SI 4 "=l"))
+   (return)]
+  "TARGET_32BIT
+   && DEFAULT_ABI == ABI_AIX
+   && (INTVAL (operands[3]) & CALL_LONG) == 0"
+  "b %z1"
+  [(set_attr "type" "branch")
+   (set_attr "length" "4")])
+
+(define_insn "*sibcall_value_nonlocal_aix64"
+  [(set (match_operand 0 "" "")
+       (call (mem:SI (match_operand:DI 1 "symbol_ref_operand" "s"))
+             (match_operand 2 "" "g")))
+   (use (match_operand:SI 3 "immediate_operand" "O"))
+   (use (match_scratch:SI 4 "=l"))
+   (return)]
+  "TARGET_64BIT 
+   && DEFAULT_ABI == ABI_AIX
+   && (INTVAL (operands[3]) & CALL_LONG) == 0"
+  "b %z1"
+  [(set_attr "type" "branch")
+   (set_attr "length" "4")])
+
+(define_insn "*sibcall_nonlocal_sysv"
+  [(call (mem:SI (match_operand:SI 0 "symbol_ref_operand" "s,s"))
+        (match_operand 1 "" ""))
+   (use (match_operand 2 "immediate_operand" "O,n"))
+   (use (match_scratch:SI 3 "=l,l"))
+   (return)]
+  "(DEFAULT_ABI == ABI_DARWIN
+     || DEFAULT_ABI == ABI_V4
+     || DEFAULT_ABI == ABI_AIX_NODESC)
+   && (INTVAL (operands[2]) & CALL_LONG) == 0"
+  "*
+{
+  if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS)
+    output_asm_insn (\"crxor 6,6,6\", operands);
+
+  else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
+    output_asm_insn (\"creqv 6,6,6\", operands);
+
+  return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"b %z0@plt\" : \"b %z0\";
+}"
+  [(set_attr "type" "branch,branch")
+   (set_attr "length" "4,8")])
+
+(define_expand "sibcall_value"
+  [(parallel [(set (match_operand 0 "register_operand" "")
+               (call (mem:SI (match_operand 1 "address_operand" ""))
+                     (match_operand 2 "" "")))
+             (use (match_operand 3 "" ""))
+             (use (scratch:SI))
+             (return)])]
+  ""
+  "
+{
+#if TARGET_MACHO
+  if (flag_pic)
+    operands[1] = machopic_indirect_call_target (operands[1]);
+#endif
+
+  if (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != CONST_INT)
+    abort ();
+
+  operands[1] = XEXP (operands[1], 0);
+
+}")
+
+(define_insn "*sibcall_value_nonlocal_sysv"
+  [(set (match_operand 0 "" "")
+       (call (mem:SI (match_operand:SI 1 "symbol_ref_operand" "s,s"))
+             (match_operand 2 "" "")))
+   (use (match_operand:SI 3 "immediate_operand" "O,n"))
+   (use (match_scratch:SI 4 "=l,l"))
+   (return)]
+  "(DEFAULT_ABI == ABI_DARWIN
+       || DEFAULT_ABI == ABI_V4
+       || DEFAULT_ABI == ABI_AIX_NODESC)
+   && (INTVAL (operands[3]) & CALL_LONG) == 0"
+  "*
+{
+  if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS)
+    output_asm_insn (\"crxor 6,6,6\", operands);
+
+  else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
+    output_asm_insn (\"creqv 6,6,6\", operands);
+
+  return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"b %z1@plt\" : \"b %z1\";
+}"
+  [(set_attr "type" "branch,branch")
+   (set_attr "length" "4,8")])
+
+(define_expand "sibcall_epilogue"
+  [(use (const_int 0))]
+  "TARGET_SCHED_PROLOG"
+  "
+{
+      rs6000_emit_epilogue (TRUE);
+      DONE;
+}")
+
 ;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
 ;; all of memory.  This blocks insns from being moved across this point.