aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Henderson <rth@cygnus.com>1999-01-19 13:30:48 -0800
committerRichard Henderson <rth@gcc.gnu.org>1999-01-19 13:30:48 -0800
commitd804ed43d00126b959d19621d7c546463d990e1a (patch)
tree0b661dbf1b43ed00d7384a2ae1d1e8726d2c4dfb /gcc
parentc14c652997970714f0b92df466ccebdf1e5cddfa (diff)
downloadgcc-d804ed43d00126b959d19621d7c546463d990e1a.zip
gcc-d804ed43d00126b959d19621d7c546463d990e1a.tar.gz
gcc-d804ed43d00126b959d19621d7c546463d990e1a.tar.bz2
expr.c (do_jump_for_compare): Handle conditional branch expanders emitting multiple jump instructions.
* expr.c (do_jump_for_compare): Handle conditional branch expanders emitting multiple jump instructions. * jump.c (condjump_label): New function. * rtl.h (condjump_label): Declare it. From-SVN: r24773
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/expr.c71
-rw-r--r--gcc/jump.c26
-rw-r--r--gcc/rtl.h1
4 files changed, 84 insertions, 21 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index bfd8a0b..572ce6c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+Tue Jan 19 21:20:52 1999 Richard Henderson <rth@cygnus.com>
+
+ * expr.c (do_jump_for_compare): Handle conditional branch expanders
+ emitting multiple jump instructions.
+ * jump.c (condjump_label): New function.
+ * rtl.h (condjump_label): Declare it.
+
Tue Jan 19 21:08:20 1999 Richard Henderson <rth@cygnus.com>
* expr.c (emit_move_insn_1): Revert 17 Dec change. Don't emit
diff --git a/gcc/expr.c b/gcc/expr.c
index 88ce156..591c826 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -11008,7 +11008,8 @@ do_jump_for_compare (comparison, if_false_label, if_true_label)
if (if_true_label)
{
if (bcc_gen_fctn[(int) GET_CODE (comparison)] != 0)
- emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (comparison)]) (if_true_label));
+ emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (comparison)])
+ (if_true_label));
else
abort ();
@@ -11017,52 +11018,80 @@ do_jump_for_compare (comparison, if_false_label, if_true_label)
}
else if (if_false_label)
{
- rtx insn;
- rtx prev = get_last_insn ();
- rtx branch = 0;
+ rtx first = get_last_insn (), insn, branch;
+ int br_count;
/* Output the branch with the opposite condition. Then try to invert
what is generated. If more than one insn is a branch, or if the
branch is not the last insn written, abort. If we can't invert
the branch, emit make a true label, redirect this jump to that,
emit a jump to the false label and define the true label. */
+ /* ??? Note that we wouldn't have to do any of this nonsense if
+ we passed both labels into a combined compare-and-branch.
+ Ah well, jump threading does a good job of repairing the damage. */
if (bcc_gen_fctn[(int) GET_CODE (comparison)] != 0)
- emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (comparison)])(if_false_label));
+ emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (comparison)])
+ (if_false_label));
else
abort ();
- /* Here we get the first insn that was just emitted. It used to be the
+ /* Here we get the first insn that was just emitted. It used to be the
case that, on some machines, emitting the branch would discard
the previous compare insn and emit a replacement. This isn't
done anymore, but abort if we see that PREV is deleted. */
- if (prev == 0)
- insn = get_insns ();
- else if (INSN_DELETED_P (prev))
+ if (first == 0)
+ first = get_insns ();
+ else if (INSN_DELETED_P (first))
abort ();
else
- insn = NEXT_INSN (prev);
+ first = NEXT_INSN (first);
- for (; insn; insn = NEXT_INSN (insn))
+ /* Look for multiple branches in this sequence, as might be generated
+ for a multi-word integer comparison. */
+
+ br_count = 0;
+ branch = NULL_RTX;
+ for (insn = first; insn ; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == JUMP_INSN)
{
- if (branch)
- abort ();
branch = insn;
+ br_count += 1;
}
- if (branch != get_last_insn ())
- abort ();
+ /* If we've got one branch at the end of the sequence,
+ we can try to reverse it. */
- JUMP_LABEL (branch) = if_false_label;
- if (! invert_jump (branch, if_false_label))
+ if (br_count == 1 && NEXT_INSN (branch) == NULL_RTX)
{
- if_true_label = gen_label_rtx ();
- redirect_jump (branch, if_true_label);
- emit_jump (if_false_label);
- emit_label (if_true_label);
+ rtx insn_label;
+ insn_label = XEXP (condjump_label (branch), 0);
+ JUMP_LABEL (branch) = insn_label;
+
+ if (insn_label != if_false_label)
+ abort ();
+
+ if (invert_jump (branch, if_false_label))
+ return;
}
+
+ /* Multiple branches, or reversion failed. Convert to branches
+ around an unconditional jump. */
+
+ if_true_label = gen_label_rtx ();
+ for (insn = first; insn; insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) == JUMP_INSN)
+ {
+ rtx insn_label;
+ insn_label = XEXP (condjump_label (insn), 0);
+ JUMP_LABEL (insn) = insn_label;
+
+ if (insn_label == if_false_label)
+ redirect_jump (insn, if_true_label);
+ }
+ emit_jump (if_false_label);
+ emit_label (if_true_label);
}
}
diff --git a/gcc/jump.c b/gcc/jump.c
index d5af17c..47f5fd4 100644
--- a/gcc/jump.c
+++ b/gcc/jump.c
@@ -3402,6 +3402,32 @@ condjump_in_parallel_p (insn)
return 0;
}
+/* Return the label of a conditional jump. */
+
+rtx
+condjump_label (insn)
+ rtx insn;
+{
+ register rtx x = PATTERN (insn);
+
+ if (GET_CODE (x) == PARALLEL)
+ x = XVECEXP (x, 0, 0);
+ if (GET_CODE (x) != SET)
+ return NULL_RTX;
+ if (GET_CODE (SET_DEST (x)) != PC)
+ return NULL_RTX;
+ x = SET_SRC (x);
+ if (GET_CODE (x) == LABEL_REF)
+ return x;
+ if (GET_CODE (x) != IF_THEN_ELSE)
+ return NULL_RTX;
+ if (XEXP (x, 2) == pc_rtx && GET_CODE (XEXP (x, 1)) == LABEL_REF)
+ return XEXP (x, 1);
+ if (XEXP (x, 1) == pc_rtx && GET_CODE (XEXP (x, 2)) == LABEL_REF)
+ return XEXP (x, 2);
+ return NULL_RTX;
+}
+
#ifdef HAVE_cc0
/* Return 1 if X is an RTX that does nothing but set the condition codes
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 0fef1a7..76fc6e1 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1289,6 +1289,7 @@ extern void cse_end_of_basic_block PROTO ((rtx,
/* In jump.c */
extern int comparison_dominates_p PROTO ((enum rtx_code, enum rtx_code));
extern int condjump_p PROTO ((rtx));
+extern rtx condjump_label PROTO ((rtx));
extern int simplejump_p PROTO ((rtx));
extern int sets_cc0_p PROTO ((rtx));
extern int invert_jump PROTO ((rtx, rtx));