aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog8
-rw-r--r--gcc/config/rs6000/rs6000-protos.h1
-rw-r--r--gcc/config/rs6000/rs6000.c69
-rw-r--r--gcc/config/rs6000/rs6000.h4
-rw-r--r--gcc/config/rs6000/rs6000.md241
5 files changed, 317 insertions, 6 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index aa73454..a8b9a19 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index 42563d3..4209211 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -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));
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index ad99417..28a0a75 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -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;
}
/* Add a REG_MAYBE_DEAD note to the insn. */
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index 17a3015..42aa929 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -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. */
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index dd1cad7..4a441e2 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -10710,6 +10710,247 @@
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.