diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2c5edb5d9ed..36b080b04eb 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2007-07-06 Josh Conner + + 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-06 Bernd Schmidt * reload1.c (choose_reload_regs): Set reload_spill_index for regs diff --git a/gcc/calls.c b/gcc/calls.c index aa63755d26d..e6741c83fb3 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -4326,6 +4326,7 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, /* expand_call should ensure this. */ gcc_assert (!arg->locate.offset.var + && arg->locate.size.var == 0 && GET_CODE (size_rtx) == CONST_INT); if (arg->locate.offset.constant > i) @@ -4335,7 +4336,21 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, } 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; } } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e5486e9d177..2e0437d994b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2007-07-06 Josh Conner + + PR middle-end/32602 + * gcc.dg/sibcall-8.c: New test. + +2007-07-06 Josh Conner + + PR middle-end/32603 + * gcc.target/arm/sibcall-1.c: New test. + 2007-07-06 H.J. Lu * gcc.dg/dfp/convert-dfp-round-thread.c: New test. diff --git a/gcc/testsuite/gcc.dg/sibcall-8.c b/gcc/testsuite/gcc.dg/sibcall-8.c new file mode 100644 index 00000000000..767040fd04b --- /dev/null +++ b/gcc/testsuite/gcc.dg/sibcall-8.c @@ -0,0 +1,30 @@ +/* { 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; +} + diff --git a/gcc/testsuite/gcc.target/arm/sibcall-1.c b/gcc/testsuite/gcc.target/arm/sibcall-1.c new file mode 100644 index 00000000000..77c94fdd0f8 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/sibcall-1.c @@ -0,0 +1,34 @@ +/* { 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" } } */ +