aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Wilson <wilson@redhat.com>2001-04-14 03:49:46 +0000
committerJim Wilson <wilson@gcc.gnu.org>2001-04-13 20:49:46 -0700
commit25250265baeee2bdca9b08958620f501b80e760a (patch)
tree8e1730685406e09ce3a77740f3a41246b8a91d3a
parentb215b52e59a5fe300f5327a4fd886c9e1673a4c0 (diff)
downloadgcc-25250265baeee2bdca9b08958620f501b80e760a.zip
gcc-25250265baeee2bdca9b08958620f501b80e760a.tar.gz
gcc-25250265baeee2bdca9b08958620f501b80e760a.tar.bz2
Fix linux kernel -foptimize-sibling-calls miscompilation
Fix linux kernel -foptimize-sibling-calls miscompilation * config/ia64/ia64.c (ia64_expand_epilogue): Emit alloc if sibcall_p. (first_instruction): New static variable. (rtx_needs_barrier): Return 1 for alloc. (init_insn_group_barriers): Set first_instruction. (rws_sum): Delete duplicate definition. (group_barrier_needed_p): Return 0 when first_instruction true. (safe_group_barrier_needed_p): Save and restore first_instruction around group_barrier_needed_p call. From-SVN: r41347
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/config/ia64/ia64.c52
2 files changed, 53 insertions, 10 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index aadb201..9dcb55d 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,14 @@
+2001-04-13 Jim Wilson <wilson@redhat.com>
+
+ * config/ia64/ia64.c (ia64_expand_epilogue): Emit alloc if sibcall_p.
+ (first_instruction): New static variable.
+ (rtx_needs_barrier): Return 1 for alloc.
+ (init_insn_group_barriers): Set first_instruction.
+ (rws_sum): Delete duplicate definition.
+ (group_barrier_needed_p): Return 0 when first_instruction true.
+ (safe_group_barrier_needed_p): Save and restore first_instruction
+ around group_barrier_needed_p call.
+
Fri Apr 13 21:40:28 2001 Loren J. Rittle <ljrittle@acm.org>
* expr.h (enum libfunc_index): Add LTI_memmove.
diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c
index 17f5768..5b6ffba 100644
--- a/gcc/config/ia64/ia64.c
+++ b/gcc/config/ia64/ia64.c
@@ -2399,6 +2399,18 @@ ia64_expand_epilogue (sibcall_p)
if (! sibcall_p)
emit_jump_insn (gen_return_internal (gen_rtx_REG (DImode, BR_REG (0))));
+ else
+ /* We must emit an alloc to force the input registers to become output
+ registers. Otherwise, if the callee tries to pass its parameters
+ through to another call without an intervening alloc, then these
+ values get lost. */
+ /* ??? We don't need to preserve all input registers. We only need to
+ preserve those input registers used as arguments to the sibling call.
+ It is unclear how to compute that number here. */
+ emit_insn (gen_alloc (gen_rtx_REG (DImode, GR_REG (2)),
+ GEN_INT (0), GEN_INT (0),
+ GEN_INT (current_frame_info.n_input_regs),
+ GEN_INT (0)));
}
/* Return 1 if br.ret can do all the work required to return from a
@@ -3818,6 +3830,11 @@ struct reg_write_state rws_sum[NUM_REGS];
stop bit is emitted. */
struct reg_write_state rws_insn[NUM_REGS];
+/* Indicates whether this is the first instruction after a stop bit,
+ in which case we don't need another stop bit. Without this, we hit
+ the abort in ia64_variable_issue when scheduling an alloc. */
+static int first_instruction;
+
/* Misc flags needed to compute RAW/WAW dependencies while we are traversing
RTL for one instruction. */
struct reg_flags
@@ -4379,14 +4396,18 @@ rtx_needs_barrier (x, flags, pred)
switch (XINT (x, 1))
{
case 0: /* alloc */
- /* Alloc must always be the first instruction. Currently, we
- only emit it at the function start, so we don't need to worry
- about emitting a stop bit before it. */
- need_barrier = rws_access_regno (AR_PFS_REGNUM, flags, pred);
+ /* Alloc must always be the first instruction of a group.
+ We force this by always returning true. */
+ /* ??? We might get better scheduling if we explicitly check for
+ input/local/output register dependencies, and modify the
+ scheduler so that alloc is always reordered to the start of
+ the current group. We could then eliminate all of the
+ first_instruction code. */
+ rws_access_regno (AR_PFS_REGNUM, flags, pred);
new_flags.is_write = 1;
- need_barrier |= rws_access_regno (REG_AR_CFM, new_flags, pred);
- return need_barrier;
+ rws_access_regno (REG_AR_CFM, new_flags, pred);
+ return 1;
case 1: /* blockage */
case 2: /* insn group barrier */
@@ -4455,11 +4476,9 @@ static void
init_insn_group_barriers ()
{
memset (rws_sum, 0, sizeof (rws_sum));
+ first_instruction = 1;
}
-/* Cumulative info for the current instruction group. */
-struct reg_write_state rws_sum[NUM_REGS];
-
/* Given the current state, recorded by previous calls to this function,
determine whether a group barrier (a stop bit) is necessary before INSN.
Return nonzero if so. */
@@ -4537,12 +4556,18 @@ group_barrier_needed_p (insn)
asm. */
if (! need_barrier)
need_barrier = rws_access_regno (REG_VOLATILE, flags, 0);
-
break;
default:
abort ();
}
+
+ if (first_instruction)
+ {
+ need_barrier = 0;
+ first_instruction = 0;
+ }
+
return need_barrier;
}
@@ -4553,10 +4578,17 @@ safe_group_barrier_needed_p (insn)
rtx insn;
{
struct reg_write_state rws_saved[NUM_REGS];
+ int saved_first_instruction;
int t;
+
memcpy (rws_saved, rws_sum, NUM_REGS * sizeof *rws_saved);
+ saved_first_instruction = first_instruction;
+
t = group_barrier_needed_p (insn);
+
memcpy (rws_sum, rws_saved, NUM_REGS * sizeof *rws_saved);
+ first_instruction = saved_first_instruction;
+
return t;
}