aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/calls.c47
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.dg/nested-calls-1.c42
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;
+}