diff options
author | Richard Henderson <rth@cygnus.com> | 1999-01-19 13:30:48 -0800 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 1999-01-19 13:30:48 -0800 |
commit | d804ed43d00126b959d19621d7c546463d990e1a (patch) | |
tree | 0b661dbf1b43ed00d7384a2ae1d1e8726d2c4dfb /gcc | |
parent | c14c652997970714f0b92df466ccebdf1e5cddfa (diff) | |
download | gcc-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/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/expr.c | 71 | ||||
-rw-r--r-- | gcc/jump.c | 26 | ||||
-rw-r--r-- | gcc/rtl.h | 1 |
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 @@ -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); } } @@ -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 @@ -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)); |