[PATCH] Fix sibcall miscompilation on i?86

Jakub Jelinek jakub@redhat.com
Wed Jul 13 18:38:00 GMT 2005


Hi!

The attached testcase is miscompiled on i?86, e.g. with
-m32 -O2 -march=i386 or -m32 -Os -march=i386 -mtune=i686
(a regression from GCC 3.4.4).
The problem is that check_sibcall_argument_overlap is very simplistic
and detects only cases when a MEM (with non-BLKmode) is used to
read/write with virtual-incoming-args or virtuan-incoming-args PLUS
const_int as address.  But on the testcase below, with -march=i386
we have there:
(insn 8 6 9 1 (parallel [
            (set (reg:SI 60)
                (plus:SI (reg/f:SI 53 virtual-incoming-args)
                    (const_int 12 [0xc])))
            (clobber (reg:CC 17 flags))
        ]) -1 (nil)
    (nil))

(insn 9 8 10 1 (set (reg:SI 61)
        (reg/f:SI 53 virtual-incoming-args)) -1 (nil)
    (nil))
...
(insn 11 10 12 1 (parallel [
            (set (mem:SI (reg:SI 60) [0 S4 A32])
                (mem/s:SI (reg:SI 61) [2 x+0 S4 A32]))
            (set (reg:SI 60)
                (plus:SI (reg:SI 60)
                    (const_int 4 [0x4])))
            (set (reg:SI 61)
                (plus:SI (reg:SI 61)
                    (const_int 4 [0x4])))
            (use (reg:SI 19 dirflag))
        ]) -1 (nil)
    (nil))
...
(but very well could have a :BLK mem rep;movsb etc.) and
with -Os there are memcpy function calls.
Doing address propagation and handling function calls etc.
in check_sibcall_argument_overlap sounds difficult and there is still
the question what to do about :BLK mems, so I'm just
checking the arg->value before it is copied using emit_push_insn.

Ok to commit if bootstrap/regtesting succeeds?

2005-07-13  Jakub Jelinek  <jakub@redhat.com>

	* calls.c (store_one_arg): Check for sibling call MEM arguments
	from already clobbered incoming argument area.

	* gcc.c-torture/execute/20050713-1.c: New test.

--- gcc/calls.c.jj	2005-07-02 02:27:09.000000000 +0200
+++ gcc/calls.c	2005-07-13 20:05:36.000000000 +0200
@@ -4062,6 +4062,38 @@ store_one_arg (struct arg_data *arg, rtx
 	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)
--- gcc/testsuite/gcc.c-torture/execute/20050713-1.c.jj	2005-07-13 20:23:42.000000000 +0200
+++ gcc/testsuite/gcc.c-torture/execute/20050713-1.c	2005-07-13 20:23:27.000000000 +0200
@@ -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;
+}

	Jakub



More information about the Gcc-patches mailing list