aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMichael Matz <matz@suse.de>2008-03-19 19:15:03 +0000
committerMichael Matz <matz@gcc.gnu.org>2008-03-19 19:15:03 +0000
commit05e6ee933ee2acec2477fedb6b22a08ffc2431bf (patch)
treeafbd7145d766cc18a51d78c2499ef49900a49553 /gcc
parentac05557cc7402b73c098179049cad48da07c52dc (diff)
downloadgcc-05e6ee933ee2acec2477fedb6b22a08ffc2431bf.zip
gcc-05e6ee933ee2acec2477fedb6b22a08ffc2431bf.tar.gz
gcc-05e6ee933ee2acec2477fedb6b22a08ffc2431bf.tar.bz2
re PR middle-end/35616 (Incorrect code while O2 compling)
PR middle-end/35616 * calls.c (expand_call): Check overlap of arguments with call address for sibcalls. * gcc.dg/pr35616.c: New test. From-SVN: r133348
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/calls.c10
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/pr35616.c43
4 files changed, 63 insertions, 1 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 21135c0..19b81c4 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2008-03-19 Michael Matz <matz@suse.de>
+
+ PR middle-end/35616
+ * calls.c (expand_call): Check overlap of arguments with call
+ address for sibcalls.
+
2008-03-19 Uros Bizjak <ubizjak@gmail.com>
PR target/35496
diff --git a/gcc/calls.c b/gcc/calls.c
index 657439a..2d68f75 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -2326,7 +2326,7 @@ expand_call (tree exp, rtx target, int ignore)
int save_pending_stack_adjust = 0;
int save_stack_pointer_delta = 0;
rtx insns;
- rtx before_call, next_arg_reg;
+ rtx before_call, next_arg_reg, after_args;
if (pass == 0)
{
@@ -2756,6 +2756,7 @@ expand_call (tree exp, rtx target, int ignore)
use_reg (&call_fusage, struct_value);
}
+ after_args = get_last_insn ();
funexp = prepare_call_address (funexp, static_chain_value,
&call_fusage, reg_parm_seen, pass == 0);
@@ -2790,6 +2791,13 @@ expand_call (tree exp, rtx target, int ignore)
next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage,
flags, & args_so_far);
+ /* If the call setup or the call itself overlaps with anything
+ of the argument setup we probably clobbered our call address.
+ In that case we can't do sibcalls. */
+ if (pass == 0
+ && check_sibcall_argument_overlap (after_args, 0, 0))
+ sibcall_failure = 1;
+
/* If a non-BLKmode value is returned at the most significant end
of a register, shift the register right by the appropriate amount
and update VALREG accordingly. BLKmode values are handled by the
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 6557c0c..9902a74 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2008-03-19 Michael Matz <matz@suse.de>
+
+ PR middle-end/35616
+ * gcc.dg/pr35616.c: New test.
+
2008-03-19 Daniel Franke <franke.daniel@gmail.com>
PR fortran/35152
diff --git a/gcc/testsuite/gcc.dg/pr35616.c b/gcc/testsuite/gcc.dg/pr35616.c
new file mode 100644
index 0000000..ad2c9e9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr35616.c
@@ -0,0 +1,43 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+typedef void (*listener_fun)(
+ int a,
+ int b,
+ int c);
+
+struct data_t
+{
+ int a;
+
+ listener_fun listener;
+
+ int b;
+ int c;
+ int d;
+};
+
+extern void abort(void);
+void function_calling_listener (struct data_t data);
+
+void function_calling_listener (struct data_t data)
+{
+ data.listener(data.a, data.c, data.d);
+}
+
+void my_listener(int a, int b, int c)
+{
+ if (a != 42 || b != 44 || c != 45)
+ abort ();
+}
+
+int main()
+{
+ struct data_t d;
+ d.a = 42;
+ d.b = 43;
+ d.c = 44;
+ d.d = 45;
+ d.listener = my_listener;
+ function_calling_listener (d);
+ return 0;
+}