This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix PR target/5755


Hi!

The following testcase is miscompiled with -fomit-frame-pointer (and
shouldn't be hard to come up with a testcase that is miscompiled without
-fomit-frame-pointer too).
The problem is that RETURN_POPS_ARGS() returns sizeof(void*) even if the
hidden structure return argument was passed in %eax.
ix86_expand_epilogue does emits the return_pop sequence only if:
  if (current_function_pops_args && current_function_args_size)
where in this case the first is 4, the latter 0, so the
function doesn't pop up any arguments.
But the caller (handled in calls.c) just counts with that being poped
up all the time, so it gets %esp 4 bytes from what it really should be.
Functions which were broken this way are all returning
structures where all arguments are passed in registers (callee did not pop
anything up, caller expected that), so this apparently never worked.
E.g.
struct A __attribute__((regparm(2))) foo (int, int);
used to work (popped in callee and expected that in the caller), but
it certainly is quite illogical (and this patch changes it
to not pop and not expect that), since it used to be popping
up a different argument than the fake return structure pointer.
Other solution (if the strange ABI of functions which used to work needs to
be preserved) would be to check if size > 0 in ix86_return_pops_args.

Bootstrapped on i386-redhat-linux, no regressions.

2002-02-24  Jakub Jelinek  <jakub@redhat.com>

	PR target/5755
	* config/i386/i386.c (ix86_return_pops_args): Only pop
	fake structure return argument if it was passed on the stack.

	* gcc.dg/20020224-1.c: New test.

--- gcc/config/i386/i386.c.jj	Fri Feb 22 11:32:12 2002
+++ gcc/config/i386/i386.c	Sun Feb 24 21:15:39 2002
@@ -1466,12 +1466,25 @@ ix86_return_pops_args (fundecl, funtype,
       return size;
   }
 
-  /* Lose any fake structure return argument.  */
+  /* Lose any fake structure return argument if it is passed on the stack.  */
   if (aggregate_value_p (TREE_TYPE (funtype))
       && !TARGET_64BIT)
-    return GET_MODE_SIZE (Pmode);
+    {
+      int nregs = ix86_regparm;
 
-    return 0;
+      if (funtype)
+	{
+	  tree attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (funtype));
+
+	  if (attr)
+	    nregs = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr)));
+	}
+
+      if (!nregs)
+	return GET_MODE_SIZE (Pmode);
+    }
+
+  return 0;
 }
 
 /* Argument support functions.  */
--- gcc/testsuite/gcc.dg/20020224-1.c.jj	Sun Feb 24 21:43:47 2002
+++ gcc/testsuite/gcc.dg/20020224-1.c	Sun Feb 24 21:49:30 2002
@@ -0,0 +1,41 @@
+/* PR target/5755
+   This testcase failed because the caller of a function returning struct
+   expected the callee to pop up the hidden return structure pointer,
+   while callee was actually not poping it up (as the hidden argument
+   was passed in register).  */
+/* { dg-do run { target i?86-*-* } } */
+/* { dg-options "-O2 -fomit-frame-pointer" } */
+
+extern void abort (void);
+extern void exit (int);
+
+typedef struct {
+   int a1, a2;
+} A;
+
+A a;
+
+A __attribute__ ((regparm (2)))
+foo (int x)
+{
+  return a;
+}
+
+int __attribute__ ((regparm (2)))
+bar (int x)
+{
+  int r = foo(0).a2;
+  return r;
+}
+
+int
+main ()
+{
+  int f;
+  a.a1 = 530;
+  a.a2 = 980;
+  f = bar (0);
+  if (f != 980)
+    abort ();
+  exit (0);
+}

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]