re PR middle-end/35616 (Incorrect code while O2 compling)
authorMichael Matz <matz@suse.de>
Wed, 19 Mar 2008 19:15:03 +0000 (19:15 +0000)
committerMichael Matz <matz@gcc.gnu.org>
Wed, 19 Mar 2008 19:15:03 +0000 (19:15 +0000)
        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

gcc/ChangeLog
gcc/calls.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/pr35616.c [new file with mode: 0644]

index 21135c054c6992a2525823defd3e63b5e52d1249..19b81c429633366cada5169c541a31b545365953 100644 (file)
@@ -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
index 657439a60eb6c44e492e7aa51eefcd54397e6927..2d68f7507a50450d520792c8586762d32290d163 100644 (file)
@@ -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
index 6557c0cafb1695dfe7a394db22b1ecc0aef98ce6..9902a74134b2e83e7d31e848f3d54eb84a109cb9 100644 (file)
@@ -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 (file)
index 0000000..ad2c9e9
--- /dev/null
@@ -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;
+}