* arm.c (arm_function_ok_for_sibcall): New function.
* arm.h (FUNCTION_OK_FOR_SIBCALL): Define.
* arm.md (call expanders): Don't check here for calls that can't
be sibling calls.
From-SVN: r35708
+2000-08-15 Richard Earnshaw <rearnsha@arm.com>
+
+ * arm.c (arm_function_ok_for_sibcall): New function.
+ * arm.h (FUNCTION_OK_FOR_SIBCALL): Define.
+ * arm.md (call expanders): Don't check here for calls that can't
+ be sibling calls.
+
2000-08-15 Richard Earnshaw <rearnsha@arm.com>
* arm.md (splits generating cond_exec): Disable.
|| ENCODED_LONG_CALL_ATTR_P (XSTR (sym_ref, 0))
|| TARGET_LONG_CALLS;
}
+
+/* Return non-zero if it is ok to make a tail-call to DECL. */
+int
+arm_function_ok_for_sibcall (decl)
+ tree decl;
+{
+ int call_type = TARGET_LONG_CALLS ? CALL_LONG : CALL_NORMAL;
+
+ /* Never tailcall something for which we have no decl, or if we
+ are in Thumb mode. */
+ if (decl == NULL || TARGET_THUMB)
+ return 0;
+
+ /* Get the calling method. */
+ if (lookup_attribute ("short_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
+ call_type = CALL_SHORT;
+ else if (lookup_attribute ("long_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
+ call_type = CALL_LONG;
+
+ /* Cannot tail-call to long calls, since these are out of range of
+ a branch instruction. However, if not compiling PIC, we know
+ we can reach the symbol if it is in this compilation unit. */
+ if (call_type == CALL_LONG && (flag_pic || ! TREE_ASM_WRITTEN (decl)))
+ return 0;
+
+ /* If we are interworking and the function is not declared static
+ then we can't tail-call it unless we know that it exists in this
+ compilation unit (since it might be a Thumb routine). */
+ if (TARGET_INTERWORK && TREE_PUBLIC (decl) && ! TREE_ASM_WRITTEN (decl))
+ return 0;
+
+ /* Everything else is ok. */
+ return 1;
+}
+
\f
int
legitimate_pic_operand_p (x)
#define FUNCTION_ARG_REGNO_P(REGNO) \
((REGNO) >= 0 && (REGNO) <= 3)
+\f
+/* Tail calling. */
+
+/* A C expression that evaluates to true if it is ok to perform a sibling
+ call to DECL. */
+#define FUNCTION_OK_FOR_SIBCALL(DECL) arm_function_ok_for_sibcall ((DECL))
+
/* Perform any actions needed for a function that is receiving a variable
number of arguments. CUM is as above. MODE and TYPE are the mode and type
of the current parameter. PRETEND_SIZE is a variable that should be set to
{
if (operands[2] == NULL_RTX)
operands[2] = const0_rtx;
-
- /* If we need to emit a long-call, we can't do it as a sibling call,
- so fail over to a normal call. */
- if (arm_is_longcall_p (operands[0], INTVAL (operands[2]), 0))
- {
- emit_call_insn (gen_call (operands[0], operands[1], operands[2]));
- DONE;
- }
}"
)
{
if (operands[3] == NULL_RTX)
operands[3] = const0_rtx;
-
- /* If we need to emit a long-call, we can't do it as a sibling call,
- so fail over to a normal call. */
- if (arm_is_longcall_p (operands[1], INTVAL (operands[3]), 0))
- {
- emit_call_insn (gen_call_value (operands[0], operands[1], operands[2],
- operands[3]));
- DONE;
- }
}"
)