#endif
static int align_fuzz (rtx, rtx, int, unsigned);
static void collect_fn_hard_reg_usage (void);
+static tree get_call_fndecl (rtx);
\f
/* Initialize data in final at the beginning of a compilation. */
return new pass_clean_state (ctxt);
}
+/* Return true if INSN is a call to the the current function. */
+
+static bool
+self_recursive_call_p (rtx insn)
+{
+ tree fndecl = get_call_fndecl (insn);
+ return (fndecl == current_function_decl
+ && decl_binds_to_current_def_p (fndecl));
+}
+
/* Collect hard register usage for the current function. */
static void
if (!NONDEBUG_INSN_P (insn))
continue;
- if (CALL_P (insn))
+ if (CALL_P (insn)
+ && !self_recursive_call_p (insn))
{
if (!get_call_reg_set_usage (insn, &insn_used_regs,
call_used_reg_set))
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O2 -fuse-caller-save -fomit-frame-pointer -fno-optimize-sibling-calls" } */
+/* { dg-additional-options "-mregparm=1" { target ia32 } } */
+
+/* Test -fuse-caller-save optimization on self-recursive function. */
+
+static int __attribute__((noinline))
+bar (int x)
+{
+ if (x > 4)
+ return bar (x - 3);
+ return 0;
+}
+
+int __attribute__((noinline))
+foo (int y)
+{
+ return y + bar (y);
+}
+
+int
+main (void)
+{
+ return !(foo (5) == 13);
+}
+
+/* Verify that no registers where saved on stack. */
+/* { dg-final { scan-assembler-not "\.cfi_offset" } } */
+
+/* Verify that bar is self-recursive. */
+/* { dg-final { scan-assembler-times "call\tbar" 2 } } */
+