This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix PR middle-end/32602 and middle-end/32603
- From: Josh Conner <jconner at apple dot com>
- To: gcc-patches <gcc-patches at gcc dot gnu dot org>
- Cc: Roger Sayle <roger at eyesopen dot com>, Ian Lance Taylor <iant at google dot com>, Diego Novillo <dnovillo at google dot com>
- Date: Tue, 03 Jul 2007 10:16:47 -0700
- Subject: [PATCH] Fix PR middle-end/32602 and middle-end/32603
In store_one_arg, we attempt to detect if the value to be copied to a
function call's outgoing parameter overlaps it on the stack. If so, we
disallow sibcalls by setting the "sibcall_failure" flag.
Here's the code that attempts to detect that condition:
if (arg->locate.offset.constant > i)
{
if (arg->locate.offset.constant < i + INTVAL (size_rtx))
sibcall_failure = 1;
}
else if (arg->locate.offset.constant < i)
{
if (i < arg->locate.offset.constant + INTVAL (size_rtx))
sibcall_failure = 1;
}
Unfortunately, there are a couple of problems with this code. The first
is that we assume if arg->locate.offset.constant == i, then the value is
already where it needs to be and so a sibcall is acceptable. However,
if the argument is split between the stack and registers it is possible
that both the incoming value and the outgoing argument will have the
same stack offset but will be misaligned with each other. An example of
this is given in pr32602. To address this, we can verify that the total
size of the incoming value is the same as the stack usage of the
outgoing argument.
The second problem is this code:
if (arg->locate.offset.constant < i + INTVAL (size_rtx))
uses "size_rtx" to determine the size of the argument on the stack.
However, this indicates the entire size of the object -- which can be
incorrect if the variable is split between registers and the stack. The
size which is actually on the stack can be found as
"arg->locate.size.constant". Since the size on the stack is always less
than or equal to the total size of the object, this wasn't causing bad
codegen, but could result in missed sibcall opportunities, as shown in
pr32603.
The attached patch has been regtested against arm-none-elf, bootstrapped
and regtested against ppc-apple-darwin9 and i686-linux-pc-gnu.
OK for mainline?
Thanks -
Josh
2007-07-03 Josh Conner <jconner@apple.com>
PR middle-end/32602
PR middle-end/32603
* calls.c (store_one_arg): Handle arguments which are partially
on the stack when detecting argument overlap.
2007-07-03 Josh Conner <jconner@apple.com>
PR middle-end/32602
* gcc.dg/sibcall-8.c: New test.
2007-07-03 Josh Conner <jconner@apple.com>
PR middle-end/32603
* gcc.target/arm/sibcall-1.c: New test.
Index: gcc/calls.c
===================================================================
--- gcc/calls.c (revision 125651)
+++ gcc/calls.c (working copy)
@@ -4323,7 +4323,21 @@ store_one_arg (struct arg_data *arg, rtx
}
else if (arg->locate.offset.constant < i)
{
- if (i < arg->locate.offset.constant + INTVAL (size_rtx))
+ /* Use arg->locate.size.constant instead of size_rtx
+ because we only care about the part of the argument
+ on the stack. */
+ if (i < (arg->locate.offset.constant
+ + arg->locate.size.constant))
+ sibcall_failure = 1;
+ }
+ else
+ {
+ /* Even though they appear to be at the same location,
+ if part of the outgoing argument is in registers,
+ they aren't really at the same location. Check for
+ this by making sure that the incoming size is the
+ same as the outgoing size. */
+ if (arg->locate.size.constant != INTVAL (size_rtx))
sibcall_failure = 1;
}
}
/* { dg-do compile { target { arm32 } } } */
/* { dg-options "-O2" } */
#define noinline __attribute__((noinline))
typedef struct {
int data[4];
} arr16_t;
int result = 0;
void noinline func2 (int i, int j, arr16_t arr)
{
result = (arr.data[0] != 1
|| arr.data[1] != 2
|| arr.data[2] != 3
|| arr.data[3] != 4);
}
void func1 (int i, int j, int k, int l, int m, int n, arr16_t a)
{
func2(i, j, a);
}
int main(int argc, const char *argv[])
{
arr16_t arr = {{1, 2, 3, 4}};
func1(0, 0, 0, 0, 0, 0, arr);
return result;
}
/* { dg-final { scan-assembler "\tb\tfunc2\n" } } */
/* { dg-do run } */
/* { dg-options "-O2 -foptimize-sibling-calls" } */
typedef struct {
int data[4];
} arr16_t;
int result = 0;
void func2(int i, int j, arr16_t arr)
{
result = (arr.data[0] != 1
|| arr.data[1] != 2
|| arr.data[2] != 3
|| arr.data[3] != 4);
}
void func1(int i, int j, int k, arr16_t a)
{
func2(i, j, a);
}
int main(int argc, const char *argv[])
{
arr16_t arr = {{1, 2, 3, 4}};
func1(0, 0, 0, arr);
return result;
}