diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 223b65ab566..9e2f445e77b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2007-08-28 Nathan Sidwell + + * config/m68k/m68k.c (m68k_get_function_kind): Assert we're never + given a non-function. + (m68k_ok_for_sibcall_p): Only sibcall functions of the same kind. + 2007-08-28 DJ Delorie * config/sh/sh.c (sh_gimplify_va_arg_expr): Fix sh2a support. diff --git a/gcc/config/m68k/m68k.c b/gcc/config/m68k/m68k.c index 2b06b6c01d9..f1f09bc86c1 100644 --- a/gcc/config/m68k/m68k.c +++ b/gcc/config/m68k/m68k.c @@ -639,9 +639,8 @@ m68k_get_function_kind (tree func) { tree a; - if (TREE_CODE (func) != FUNCTION_DECL) - return false; - + gcc_assert (TREE_CODE (func) == FUNCTION_DECL); + a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func)); if (a != NULL_TREE) return m68k_fk_interrupt_handler; @@ -1258,14 +1257,30 @@ flags_in_68881 (void) return cc_status.flags & CC_IN_68881; } -/* Implement TARGET_FUNCTION_OK_FOR_SIBCALL_P. We cannot use sibcalls - for nested functions because we use the static chain register for - indirect calls. */ +/* Implement TARGET_FUNCTION_OK_FOR_SIBCALL_P. */ static bool -m68k_ok_for_sibcall_p (tree decl ATTRIBUTE_UNUSED, tree exp) +m68k_ok_for_sibcall_p (tree decl, tree exp) { - return TREE_OPERAND (exp, 2) == NULL; + enum m68k_function_kind kind; + + /* We cannot use sibcalls for nested functions because we use the + static chain register for indirect calls. */ + if (CALL_EXPR_STATIC_CHAIN (exp)) + return false; + + kind = m68k_get_function_kind (current_function_decl); + if (kind == m68k_fk_normal_function) + /* We can always sibcall from a normal function, because it's + undefined if it is calling an interrupt function. */ + return true; + + /* Otherwise we can only sibcall if the function kind is known to be + the same. */ + if (decl && m68k_get_function_kind (decl) == kind) + return true; + + return false; } /* Convert X to a legitimate function call memory reference and return the diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d9dc83e8b6f..36dd47a953e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2007-08-28 Nathan Sidwell + Kazu Hirata + + * gcc.target/m68k/interrupt-1.c: New. + 2007-08-28 Rask Ingemann Lambertsen * gcc.c-torture/compile/limits-blockid.c: Reduce testcase size to diff --git a/gcc/testsuite/gcc.target/m68k/interrupt-1.c b/gcc/testsuite/gcc.target/m68k/interrupt-1.c new file mode 100644 index 00000000000..443c13b460e --- /dev/null +++ b/gcc/testsuite/gcc.target/m68k/interrupt-1.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { scan-assembler "j(ra|mp)\[ \t\]*interrupt_sibcall" } } */ +/* { dg-final { scan-assembler "j(b|)sr\[ \t\]*interrupt_call" } } */ +/* { dg-final { scan-assembler "j(ra|mp)\[ \t\]*normal_sibcall" } } */ + +void normal_sibcall (void); +void interrupt_call (void); +void __attribute ((interrupt)) interrupt_sibcall (void); + +void normal (void) +{ + normal_sibcall (); +} + +void __attribute ((interrupt)) interrupt (void) +{ + interrupt_call (); +} + +void __attribute ((interrupt)) interrupt_2 (void) +{ + interrupt_sibcall (); +}