aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Wilson <wilson@redhat.com>2000-11-17 22:18:25 +0000
committerJim Wilson <wilson@gcc.gnu.org>2000-11-17 14:18:25 -0800
commit95c8e04b098394262e6883b8ef5e713d080f92e5 (patch)
treec8bc91dc4827b16086b98c856986594bf4c3b47b
parent4f21aedbf4c7661626f49e7ca74ecc2a80892262 (diff)
downloadgcc-95c8e04b098394262e6883b8ef5e713d080f92e5.zip
gcc-95c8e04b098394262e6883b8ef5e713d080f92e5.tar.gz
gcc-95c8e04b098394262e6883b8ef5e713d080f92e5.tar.bz2
Fix miscompilation of linux kernel ia64_do_signal routine.
* config/ia64/ia64.c (emit_insn_group_barriers, case CALL_INSN): Don't clear need_barrier is next_insn is a CALL_INSN, or has instruction type B or UNKNOWN. From-SVN: r37528
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/config/ia64/ia64.c25
2 files changed, 29 insertions, 2 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 2d200c0..bd36ead 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2000-11-17 Jim Wilson <wilson@redhat.com>
+
+ * config/ia64/ia64.c (emit_insn_group_barriers, case CALL_INSN):
+ Don't clear need_barrier is next_insn is a CALL_INSN, or has
+ instruction type B or UNKNOWN.
+
2000-11-17 Neil Booth <neilb@earthling.net>
* cpperror.c (print_file_and_line): Don't display line number
diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c
index e318dbb..e523eef 100644
--- a/gcc/config/ia64/ia64.c
+++ b/gcc/config/ia64/ia64.c
@@ -4460,24 +4460,45 @@ emit_insn_group_barriers (insns)
memcpy (rws_sum, rws_insn, sizeof (rws_sum));
}
- /* A call must end a group, otherwise the assembler might pack
+ /* A call must end a bundle, otherwise the assembler might pack
it in with a following branch and then the function return
goes to the wrong place. Do this unconditionally for
unconditional calls, simply because it (1) looks nicer and
(2) keeps the data structures more accurate for the insns
following the call. */
+ /* ??? A call doesn't have to end a bundle if it is followed by
+ a mutex call or branch. Two mutex calls/branches can be put in
+ the same bundle. */
need_barrier = 1;
if (GET_CODE (PATTERN (insn)) == COND_EXEC)
{
rtx next_insn = insn;
+ enum attr_type type = TYPE_A;
+
do
next_insn = next_nonnote_insn (next_insn);
while (next_insn
&& GET_CODE (next_insn) == INSN
&& (GET_CODE (PATTERN (next_insn)) == USE
|| GET_CODE (PATTERN (next_insn)) == CLOBBER));
- if (next_insn && GET_CODE (next_insn) != JUMP_INSN)
+
+ /* A call ends a bundle if there is a stop bit after it,
+ or if it is followed by a non-B-type instruction.
+ In the later case, we can elide the stop bit, and get faster
+ code when the predicate is false. */
+ /* ??? The proper solution for this problem is to make gcc
+ explicitly bundle instructions. Then we don't need to
+ emit stop bits to force the assembler to start a new
+ bundle. */
+
+ /* Check the instruction type if it is not a branch or call. */
+ if (next_insn && GET_CODE (next_insn) == INSN)
+ type = get_attr_type (next_insn);
+
+ if (next_insn && GET_CODE (next_insn) != JUMP_INSN
+ && GET_CODE (next_insn) != CALL_INSN
+ && type != TYPE_B && type != TYPE_UNKNOWN)
need_barrier = 0;
}
if (need_barrier)