summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog5
-rw-r--r--gcc/calls.c32
-rw-r--r--gcc/testsuite/ChangeLog2
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/20050713-1.c56
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;
+}