diff options
-rw-r--r-- | gcc/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/calls.c | 32 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/20050713-1.c | 56 |
4 files changed, 95 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 42c8c2e32cd..396314105e9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2005-07-25 Jakub Jelinek <jakub@redhat.com> + + * calls.c (store_one_arg): Check for sibling call MEM arguments + from already clobbered incoming argument area. + 2005-07-24 Kaveh R. Ghazi <ghazi@caip.rutgers.edu> * c-common.c (check_missing_format_attribute): New. diff --git a/gcc/calls.c b/gcc/calls.c index 8e87886de1d..ea6eaeb82f7 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -4076,6 +4076,38 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, stack_arg_under_construction--; } + /* Check for overlap with already clobbered argument area. */ + if ((flags & ECF_SIBCALL) && MEM_P (arg->value)) + { + int i = -1; + unsigned int k; + rtx x = arg->value; + + if (XEXP (x, 0) == current_function_internal_arg_pointer) + i = 0; + else if (GET_CODE (XEXP (x, 0)) == PLUS + && XEXP (XEXP (x, 0), 0) == + current_function_internal_arg_pointer + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT) + i = INTVAL (XEXP (XEXP (x, 0), 1)); + else + i = -1; + + if (i >= 0) + { +#ifdef ARGS_GROW_DOWNWARD + i = -i - arg->locate.size.constant; +#endif + for (k = 0; k < arg->locate.size.constant; k++) + if (i + k < stored_args_map->n_bits + && TEST_BIT (stored_args_map, i + k)) + { + sibcall_failure = 1; + break; + } + } + } + /* Don't allow anything left on stack from computation of argument to alloca. */ if (flags & ECF_MAY_BE_ALLOCA) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 11ec1110cf5..a5d540ca5cb 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,7 @@ 2005-07-25 Jakub Jelinek <jakub@redhat.com> + * gcc.c-torture/execute/20050713-1.c: New test. + PR fortran/20063 * gfortran.fortran-torture/execute/data_4.f90: New test. diff --git a/gcc/testsuite/gcc.c-torture/execute/20050713-1.c b/gcc/testsuite/gcc.c-torture/execute/20050713-1.c new file mode 100644 index 00000000000..4d669cb8e45 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20050713-1.c @@ -0,0 +1,56 @@ +/* Test that sibling call is not used if there is an argument overlap. */ + +extern void abort (void); + +struct S +{ + int a, b, c; +}; + +int +foo2 (struct S x, struct S y) +{ + if (x.a != 3 || x.b != 4 || x.c != 5) + abort (); + if (y.a != 6 || y.b != 7 || y.c != 8) + abort (); + return 0; +} + +int +foo3 (struct S x, struct S y, struct S z) +{ + foo2 (x, y); + if (z.a != 9 || z.b != 10 || z.c != 11) + abort (); + return 0; +} + +int +bar2 (struct S x, struct S y) +{ + return foo2 (y, x); +} + +int +bar3 (struct S x, struct S y, struct S z) +{ + return foo3 (y, x, z); +} + +int +baz3 (struct S x, struct S y, struct S z) +{ + return foo3 (y, z, x); +} + +int +main (void) +{ + struct S a = { 3, 4, 5 }, b = { 6, 7, 8 }, c = { 9, 10, 11 }; + + bar2 (b, a); + bar3 (b, a, c); + baz3 (c, a, b); + return 0; +} |