diff options
author | Jim Wilson <wilson@redhat.com> | 2001-04-14 03:49:46 +0000 |
---|---|---|
committer | Jim Wilson <wilson@gcc.gnu.org> | 2001-04-13 20:49:46 -0700 |
commit | 25250265baeee2bdca9b08958620f501b80e760a (patch) | |
tree | 8e1730685406e09ce3a77740f3a41246b8a91d3a | |
parent | b215b52e59a5fe300f5327a4fd886c9e1673a4c0 (diff) | |
download | gcc-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/ChangeLog | 11 | ||||
-rw-r--r-- | gcc/config/ia64/ia64.c | 52 |
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; } |