diff options
-rw-r--r-- | gcc/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/calls.c | 47 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/nested-calls-1.c | 42 |
4 files changed, 88 insertions, 12 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8575379..dcd74da 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2005-11-13 Eric Botcazou <ebotcazou@adacore.com> + Ian Lance Taylor <ian@airs.com> + + PR middle-end/24003 + * calls.c (expand_call): If TARGET is a MEM and some part of the + argument area has been saved, force TARGET to a register. + 2005-11-13 Razya Ladelsky <razya@il.ibm.com> * ipa-prop.c (ipa_callsite_compute_param ): Removed obsolete type diff --git a/gcc/calls.c b/gcc/calls.c index 920c8157..2cc15fc 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -2857,6 +2857,8 @@ expand_call (tree exp, rtx target, int ignore) && GET_MODE (target) == TYPE_MODE (TREE_TYPE (exp)) && GET_MODE (target) == GET_MODE (valreg)) { + bool may_overlap = false; + /* We have to copy a return value in a CLASS_LIKELY_SPILLED hard reg to a plain register. */ if (REG_P (valreg) @@ -2865,19 +2867,40 @@ expand_call (tree exp, rtx target, int ignore) && !(REG_P (target) && !HARD_REGISTER_P (target))) valreg = copy_to_reg (valreg); - /* TARGET and VALREG cannot be equal at this point because the - latter would not have REG_FUNCTION_VALUE_P true, while the - former would if it were referring to the same register. - - If they refer to the same register, this move will be a no-op, - except when function inlining is being done. */ - emit_move_insn (target, valreg); + /* If TARGET is a MEM in the argument area, and we have + saved part of the argument area, then we can't store + directly into TARGET as it may get overwritten when we + restore the argument save area below. Don't work too + hard though and simply force TARGET to a register if it + is a MEM; the optimizer is quite likely to sort it out. */ + if (ACCUMULATE_OUTGOING_ARGS && pass && MEM_P (target)) + for (i = 0; i < num_actuals; i++) + if (args[i].save_area) + { + may_overlap = true; + break; + } - /* If we are setting a MEM, this code must be executed. Since it is - emitted after the call insn, sibcall optimization cannot be - performed in that case. */ - if (MEM_P (target)) - sibcall_failure = 1; + if (may_overlap) + target = copy_to_reg (valreg); + else + { + /* TARGET and VALREG cannot be equal at this point + because the latter would not have + REG_FUNCTION_VALUE_P true, while the former would if + it were referring to the same register. + + If they refer to the same register, this move will be + a no-op, except when function inlining is being + done. */ + emit_move_insn (target, valreg); + + /* If we are setting a MEM, this code must be executed. + Since it is emitted after the call insn, sibcall + optimization cannot be performed in that case. */ + if (MEM_P (target)) + sibcall_failure = 1; + } } else if (TYPE_MODE (TREE_TYPE (exp)) == BLKmode) { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ae3265f..e6f9757 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2005-11-13 Eric Botcazou <ebotcazou@adacore.com> + + * gcc.dg/nested-calls-1.c: New test. + 2005-11-13 Francois-Xavier Coudert <coudert@clipper.ens.fr> * gfortran.dg/complex_intrinsic_1.f90: New test. diff --git a/gcc/testsuite/gcc.dg/nested-calls-1.c b/gcc/testsuite/gcc.dg/nested-calls-1.c new file mode 100644 index 0000000..b3f08be --- /dev/null +++ b/gcc/testsuite/gcc.dg/nested-calls-1.c @@ -0,0 +1,42 @@ +/* PR middle-end/24003 */ +/* Contributed by Eric Botcazou <ebotcazou@adacore.com> */ + +/* { dg-do run } */ +/* { dg-options "-std=c99 -O -fno-inline" } */ +/* { dg-options "-std=c99 -O -fno-inline -mtune=i686" { target { i?86-*-* && ilp32 } } } */ + +#include <limits.h> + +typedef unsigned long uns32_t; +typedef unsigned long long uns64_t; + +extern void abort(void); + +uns32_t lo (uns64_t p) +{ + return (uns32_t)p; +} + +uns64_t concat (uns32_t p1, uns32_t p2) +{ +#if LLONG_MAX > 2147483647L + return ((uns64_t)p1 << 32) | p2; +#else + return 0; +#endif +} + +uns64_t lshift32 (uns64_t p1, uns32_t p2) +{ + return concat (lo (p1), p2); +} + +int main(void) +{ +#if LLONG_MAX > 2147483647L + if (lshift32 (0xFFFFFFFF12345678ULL, 0x90ABCDEFUL) != 0x1234567890ABCDEFULL) + abort (); +#endif + + return 0; +} |