#include "flags.h"
#include "insn-config.h"
#include "recog.h"
+#include "hard-reg-set.h"
#include "basic-block.h"
#include "expr.h"
#include "output.h"
-#include "hard-reg-set.h"
#include "tm_p.h"
#define MAX_CONDITIONAL_EXECUTE (BRANCH_COST + 1)
#endif
-#define EDGE_COMPLEX (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_EH)
-
#define NULL_EDGE ((struct edge_def *)NULL)
#define NULL_BLOCK ((struct basic_block_def *)NULL)
static int count_bb_insns PARAMS ((basic_block));
static rtx first_active_insn PARAMS ((basic_block));
static int last_active_insn_p PARAMS ((basic_block, rtx));
+static int seq_contains_jump PARAMS ((rtx));
static int cond_exec_process_insns PARAMS ((rtx, rtx, rtx, rtx, int));
static rtx cond_exec_get_condition PARAMS ((rtx));
return GET_CODE (insn) == JUMP_INSN;
}
+
+/* It is possible, especially when having dealt with multi-word
+ arithmetic, for the expanders to have emitted jumps. Search
+ through the sequence and return TRUE if a jump exists so that
+ we can abort the conversion. */
+
+static int
+seq_contains_jump (insn)
+ rtx insn;
+{
+ while (insn)
+ {
+ if (GET_CODE (insn) == JUMP_INSN)
+ return 1;
+ insn = NEXT_INSN (insn);
+ }
+ return 0;
+}
\f
/* Go through a bunch of insns, converting them to conditional
execution format if possible. Return TRUE if all of the non-note
{
int must_be_last = FALSE;
rtx insn;
+ rtx pattern;
for (insn = start; ; insn = NEXT_INSN (insn))
{
if (GET_CODE (insn) != INSN && GET_CODE (insn) != CALL_INSN)
abort ();
+ /* Remove USE insns that get in the way. */
+ if (reload_completed && GET_CODE (PATTERN (insn)) == USE)
+ {
+ /* ??? Ug. Actually unlinking the thing is problematic,
+ given what we'd have to coordinate with our callers. */
+ PUT_CODE (insn, NOTE);
+ NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+ NOTE_SOURCE_FILE (insn) = 0;
+ goto insn_done;
+ }
+
/* Last insn wasn't last? */
if (must_be_last)
return FALSE;
}
/* Now build the conditional form of the instruction. */
+ pattern = PATTERN (insn);
+
+ /* If the machine needs to modify the insn being conditionally executed,
+ say for example to force a constant integer operand into a temp
+ register, do so here. */
+#ifdef IFCVT_MODIFY_INSN
+ IFCVT_MODIFY_INSN (pattern, insn);
+ if (! pattern)
+ return FALSE;
+#endif
+
validate_change (insn, &PATTERN (insn),
gen_rtx_COND_EXEC (VOIDmode, copy_rtx (test),
- PATTERN (insn)), 1);
+ pattern), 1);
if (GET_CODE (insn) == CALL_INSN && prob_val)
validate_change (insn, ®_NOTES (insn),
{
rtx test_if, cond;
- if (condjump_p (jump))
- test_if = SET_SRC (PATTERN (jump));
- else if (condjump_in_parallel_p (jump))
- test_if = SET_SRC (XVECEXP (PATTERN (jump), 0, 0));
+ if (any_condjump_p (jump))
+ test_if = SET_SRC (pc_set (jump));
else
return NULL_RTX;
cond = XEXP (test_if, 0);
rtx test_expr; /* expression in IF_THEN_ELSE that is tested */
rtx then_start; /* first insn in THEN block */
rtx then_end; /* last insn + 1 in THEN block */
- rtx else_start; /* first insn in ELSE block or NULL */
- rtx else_end; /* last insn + 1 in ELSE block */
+ rtx else_start = NULL_RTX; /* first insn in ELSE block or NULL */
+ rtx else_end = NULL_RTX; /* last insn + 1 in ELSE block */
int max; /* max # of insns to convert. */
int then_mod_ok; /* whether conditional mods are ok in THEN */
rtx true_expr; /* test for else block insns */
if (! test_expr)
return FALSE;
+ /* If the conditional jump is more than just a conditional jump,
+ then we can not do conditional execution conversion on this block. */
+ if (!onlyjump_p (test_bb->end))
+ return FALSE;
+
/* Collect the bounds of where we're to search. */
then_start = then_bb->head;
then_end = then_bb->end;
+ /* Skip a label heading THEN block. */
+ if (GET_CODE (then_start) == CODE_LABEL)
+ then_start = NEXT_INSN (then_start);
+
/* Skip a (use (const_int 0)) or branch as the final insn. */
if (GET_CODE (then_end) == INSN
&& GET_CODE (PATTERN (then_end)) == USE
GET_MODE (true_expr), XEXP (true_expr, 0),
XEXP (true_expr, 1));
+#ifdef IFCVT_MODIFY_TESTS
+ /* If the machine description needs to modify the tests, such as setting a
+ conditional execution register from a comparison, it can do so here. */
+ IFCVT_MODIFY_TESTS (true_expr, false_expr, test_bb, then_bb, else_bb,
+ join_bb);
+
+ /* See if the conversion failed */
+ if (!true_expr || !false_expr)
+ goto fail;
+#endif
+
true_prob_val = find_reg_note (test_bb->end, REG_BR_PROB, NULL_RTX);
if (true_prob_val)
{
if (! apply_change_group ())
return FALSE;
+#ifdef IFCVT_MODIFY_FINAL
+ /* Do any machine dependent final modifications */
+ IFCVT_MODIFY_FINAL (test_bb, then_bb, else_bb, join_bb);
+#endif
+
/* Conversion succeeded. */
if (rtl_dump_file)
fprintf (rtl_dump_file, "%d insn%s converted to conditional execution.\n",
return TRUE;
fail:
+#ifdef IFCVT_MODIFY_CANCEL
+ /* Cancel any machine dependent changes. */
+ IFCVT_MODIFY_CANCEL (test_bb, then_bb, else_bb, join_bb);
+#endif
+
cancel_changes (0);
return FALSE;
}
seq = get_insns ();
end_sequence ();
+
+ if (seq_contains_jump (seq))
+ return FALSE;
+
emit_insns_before (seq, if_info->cond_earliest);
return TRUE;
seq = get_insns ();
end_sequence ();
+
+ if (seq_contains_jump (seq))
+ return FALSE;
+
emit_insns_before (seq, if_info->cond_earliest);
return TRUE;
seq = get_insns ();
end_sequence ();
+
+ if (seq_contains_jump (seq))
+ return FALSE;
+
emit_insns_before (seq, if_info->cond_earliest);
return TRUE;
rtx *earliest;
{
rtx cond;
+ rtx set;
/* If the condition variable is a register and is MODE_INT, accept it.
Otherwise, fall back on get_condition. */
- if (! condjump_p (jump))
+ if (! any_condjump_p (jump))
return NULL_RTX;
- cond = XEXP (SET_SRC (PATTERN (jump)), 0);
+ set = pc_set (jump);
+
+ cond = XEXP (SET_SRC (set), 0);
if (GET_CODE (XEXP (cond, 0)) == REG
&& GET_MODE_CLASS (GET_MODE (XEXP (cond, 0))) == MODE_INT)
{
/* If this branches to JUMP_LABEL when the condition is false,
reverse the condition. */
- if (GET_CODE (XEXP (SET_SRC (PATTERN (jump)), 2)) == LABEL_REF
- && XEXP (XEXP (SET_SRC (PATTERN (jump)), 2), 0) == JUMP_LABEL (jump))
+ if (GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
+ && XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (jump))
cond = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond)),
GET_MODE (cond), XEXP (cond, 0),
XEXP (cond, 1));
if (! cond)
return FALSE;
+ /* If the conditional jump is more than just a conditional jump,
+ then we can not do if-conversion on this block. */
+ if (! onlyjump_p (jump))
+ return FALSE;
+
/* We must be comparing objects whose modes imply the size. */
if (GET_MODE (XEXP (cond, 0)) == BLKmode)
return FALSE;
/* The JOIN block may have had quite a number of other predecessors too.
Since we've already merged the TEST, THEN and ELSE blocks, we should
have only one remaining edge from our if-then-else diamond. If there
- is more than one remaining edge, it must come from elsewhere. */
- else if (join_bb->pred->pred_next == NULL)
+ is more than one remaining edge, it must come from elsewhere. There
+ may be zero incoming edges if the THEN block didn't actually join
+ back up (as with a call to abort). */
+ else if (join_bb->pred == NULL || join_bb->pred->pred_next == NULL)
{
/* We can merge the JOIN. */
if (combo_bb->global_live_at_end)
if (then_bb->pred->pred_next != NULL_EDGE)
return FALSE;
- /* The THEN block of an IF-THEN combo must have exactly one successor. */
- if (then_succ == NULL_EDGE
- || then_succ->succ_next != NULL_EDGE
- || (then_succ->flags & EDGE_COMPLEX))
+ /* The THEN block of an IF-THEN combo must have zero or one successors. */
+ if (then_succ != NULL_EDGE
+ && (then_succ->succ_next != NULL_EDGE
+ || (then_succ->flags & EDGE_COMPLEX)))
return FALSE;
+ /* If the THEN block has no successors, conditional execution can still
+ make a conditional call. Don't do this unless the ELSE block has
+ only one incoming edge -- the CFG manipulation is too ugly otherwise.
+ Check for the last insn of the THEN block being an indirect jump, which
+ is listed as not having any successors, but confuses the rest of the CE
+ code processing. XXX we should fix this in the future. */
+ if (then_succ == NULL)
+ {
+ if (else_bb->pred->pred_next == NULL_EDGE)
+ {
+ rtx last_insn = then_bb->end;
+
+ while (last_insn
+ && GET_CODE (last_insn) == NOTE
+ && last_insn != then_bb->head)
+ last_insn = PREV_INSN (last_insn);
+
+ if (last_insn
+ && GET_CODE (last_insn) == JUMP_INSN
+ && ! simplejump_p (last_insn))
+ return FALSE;
+
+ join_bb = else_bb;
+ else_bb = NULL_BLOCK;
+ }
+ else
+ return FALSE;
+ }
+
/* If the THEN block's successor is the other edge out of the TEST block,
then we have an IF-THEN combo without an ELSE. */
- if (then_succ->dest == else_bb)
+ else if (then_succ->dest == else_bb)
{
join_bb = else_bb;
else_bb = NULL_BLOCK;
if (else_bb->pred->pred_next != NULL)
return FALSE;
+ /* THEN is not EXIT. */
+ if (then_bb->index < 0)
+ return FALSE;
+
/* ELSE is predicted or SUCC(ELSE) postdominates THEN. */
note = find_reg_note (test_bb->end, REG_BR_PROB, NULL_RTX);
if (note && INTVAL (XEXP (note, 0)) >= REG_BR_PROB_BASE / 2)
;
else if (else_succ->dest->index < 0
- || (then_bb->index >= 0
- && TEST_BIT (post_dominators[ORIG_INDEX (then_bb)],
- ORIG_INDEX (else_succ->dest))))
+ || TEST_BIT (post_dominators[ORIG_INDEX (then_bb)],
+ ORIG_INDEX (else_succ->dest)))
;
else
return FALSE;
end = PREV_INSN (end);
}
+ /* Disable handling dead code by conditional execution if the machine needs
+ to do anything funny with the tests, etc. */
+#ifndef IFCVT_MODIFY_TESTS
if (HAVE_conditional_execution)
{
/* In the conditional execution case, we have things easy. We know
earliest = jump;
}
else
+#endif
{
/* In the non-conditional execution case, we have to verify that there
are no trapping operations, no calls, no references to memory, and
break;
}
- if (! condjump_p (jump))
+ if (! any_condjump_p (jump))
return FALSE;
/* Find the extent of the conditional. */
block_num++;
}
- sbitmap_vector_free (post_dominators);
+ if (post_dominators)
+ sbitmap_vector_free (post_dominators);
if (rtl_dump_file)
fflush (rtl_dump_file);
SET_BIT (update_life_blocks, block_num);
count_or_remove_death_notes (update_life_blocks, 1);
- update_life_info (update_life_blocks, UPDATE_LIFE_LOCAL,
- PROP_DEATH_NOTES);
+ /* ??? See about adding a mode that verifies that the initial
+ set of blocks don't let registers come live. */
+ update_life_info (update_life_blocks, UPDATE_LIFE_GLOBAL,
+ PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE
+ | PROP_KILL_DEAD_CODE);
sbitmap_free (update_life_blocks);
}