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]

fix PR 16819


This bug is caused by a bad interaction between the i386 code that
defines argument passing conventions and the generic function call
handling.  Given a testcase like this (from the bug report):

double d=0;

struct A {} a;

void foo(struct A x)
{
  d=0;
}

void bar()
{
  if (d) foo(a);
}

I was at first surprised because the size of type struct A was zero,
at least as far as calling conventions were concerned.  I suppose this
might be fine for C; I know it isn't for C++, which I'm more familiar
with.  Anyhow...

The problem is that i386.c:function_arg() falls through from the
BLKmode case to the [QHSD]Imode case, which is intentional, but then
ends up passing the words <= cum->nregs test, because both sides are
zero.  So we end up returning (reg:BLK 0).

This wouldn't be much of a problem, because given the zero size, we
don't store anything in eax, and we don't advance the used-register
count nor the stack use, which is according to the ABI.

The only fallout is that we end up adding a (use (reg:SI 0)) to the
call instruction, which life analysis ends up propagating up as a live
eax all the way up to the beginning of the function or a previous
function call.

I see two possible solutions for this problem.  One would be to modify
the i386-specific code to break out of the case statement when words
is zero (and perhaps when nregs is also zero), such that the generic
code arranges for the zero-sized argument to be passed on the stack.
This would fix the problem and apparently wouldn't introduce any ABI
incompatibility, since the zero-sized argument doesn't actually take
up any stack slots.

Looking further, I couldn't think of any reason for the explicit use
of the register that is not set before the call.  There's no reason to
force it live if we're not setting it nor passing anything in it; we
might as well leave it available for other purposes.  This is the
approach taken by the patch below.  Can anyone foresee any ill effects
this change might have?  If not, ok to install?  I'm testing it on
i686-pc-linux-gnu.

Index: gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	PR target/16819
	* calls.c (load_register_parameters): Don't call use_regs when
	nregs is zero.

Index: gcc/calls.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/calls.c,v
retrieving revision 1.373
diff -u -p -r1.373 calls.c
--- gcc/calls.c 24 Nov 2004 18:50:21 -0000 1.373
+++ gcc/calls.c 22 Dec 2004 05:21:24 -0000
@@ -1554,8 +1554,8 @@ load_register_parameters (struct arg_dat
 	    use_group_regs (call_fusage, reg);
 	  else if (nregs == -1)
 	    use_reg (call_fusage, reg);
-	  else
-	    use_regs (call_fusage, REGNO (reg), nregs == 0 ? 1 : nregs);
+	  else if (nregs > 0)
+	    use_regs (call_fusage, REGNO (reg), nregs);
 	}
     }
 }
-- 
Alexandre Oliva             http://www.ic.unicamp.br/~oliva/
Red Hat Compiler Engineer   aoliva@{redhat.com, gcc.gnu.org}
Free Software Evangelist  oliva@{lsd.ic.unicamp.br, gnu.org}

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