#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, int));
+static int cond_exec_process_insns PARAMS ((rtx, rtx, rtx, rtx, int));
static rtx cond_exec_get_condition PARAMS ((rtx));
static int cond_exec_process_if_block PARAMS ((basic_block, basic_block,
basic_block, basic_block));
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
insns were processed. */
static int
-cond_exec_process_insns (start, end, test, mod_ok)
+cond_exec_process_insns (start, end, test, prob_val, mod_ok)
rtx start; /* first insn to look at */
rtx end; /* last insn to look at */
rtx test; /* conditional execution test */
+ rtx prob_val; /* probability of branch taken. */
int mod_ok; /* true if modifications ok last insn. */
{
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),
+ alloc_EXPR_LIST (REG_BR_PROB, prob_val,
+ REG_NOTES (insn)), 1);
insn_done:
if (insn == end)
{
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 */
rtx false_expr; /* test for then block insns */
+ rtx true_prob_val; /* probability of else block */
+ rtx false_prob_val; /* probability of then block */
int n_insns;
/* Find the conditional jump to the ELSE or JOIN part, and isolate
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)
+ {
+ true_prob_val = XEXP (true_prob_val, 0);
+ false_prob_val = GEN_INT (REG_BR_PROB_BASE - INTVAL (true_prob_val));
+ }
+ else
+ false_prob_val = NULL_RTX;
+
/* For IF-THEN-ELSE blocks, we don't allow modifications of the test
on then THEN block. */
then_mod_ok = (else_bb == NULL_BLOCK);
if (then_end
&& ! cond_exec_process_insns (then_start, then_end,
- false_expr, then_mod_ok))
+ false_expr, false_prob_val, then_mod_ok))
goto fail;
if (else_bb
&& ! cond_exec_process_insns (else_start, else_end,
- true_expr, TRUE))
+ true_expr, true_prob_val, TRUE))
goto fail;
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;
|| GET_CODE (insn_b) != INSN
|| (set_b = single_set (insn_b)) == NULL_RTX
|| ! rtx_equal_p (x, SET_DEST (set_b))
- || reg_mentioned_p (x, cond))
+ || reg_mentioned_p (x, cond)
+ || reg_mentioned_p (x, a)
+ || reg_mentioned_p (x, SET_SRC (set_b)))
insn_b = set_b = NULL_RTX;
}
b = (set_b ? SET_SRC (set_b) : x);
else_bb->end = PREV_INSN (insn_b);
reorder_insns (insn_b, insn_b, PREV_INSN (if_info.cond_earliest));
insn_b = NULL_RTX;
- x = orig_x;
}
+ x = orig_x;
goto success;
}
get their addresses taken. */
if (else_bb)
{
- if (LABEL_NUSES (else_bb->head) == 0
- && ! LABEL_PRESERVE_P (else_bb->head)
- && ! LABEL_NAME (else_bb->head))
- {
- /* We can merge the ELSE. */
- merge_blocks_nomove (combo_bb, else_bb);
- num_removed_blocks++;
- }
- else
- {
- /* We cannot merge the ELSE. */
-
- /* Properly rewire the edge out of the now combined
- TEST-THEN block to point here. */
- remove_edge (combo_bb->succ);
- if (combo_bb->succ || else_bb->pred)
- abort ();
- make_edge (NULL, combo_bb, else_bb, EDGE_FALLTHRU);
-
- /* Remove the jump and cruft from the end of the TEST-THEN block. */
- tidy_fallthru_edge (combo_bb->succ, combo_bb, else_bb);
-
- /* Make sure we update life info properly. */
- SET_UPDATE_LIFE(combo_bb);
- if (else_bb->global_live_at_end)
- COPY_REG_SET (else_bb->global_live_at_start,
- else_bb->global_live_at_end);
-
- /* The ELSE is the new combo block. */
- combo_bb = else_bb;
- }
+ merge_blocks_nomove (combo_bb, else_bb);
+ num_removed_blocks++;
}
/* If there was no join block reported, that means it was not adjacent
abort ();
}
- /* The JOIN block had a label. It may have had quite a number
- of other predecessors too, but probably not. See if we can
- merge this with the others. */
- else if (LABEL_NUSES (join_bb->head) == 0
- && ! LABEL_PRESERVE_P (join_bb->head)
- && ! LABEL_NAME (join_bb->head))
+ /* 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. 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;
- /* The THEN block may not start with a label, as might happen with an
- unused user label that has had its address taken. */
- if (GET_CODE (then_bb->head) == CODE_LABEL)
- 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 (then_bb->pred->pred_next != NULL)
return FALSE;
- /* THEN has no label. */
- if (GET_CODE (then_bb->head) == CODE_LABEL)
- return FALSE;
-
/* ELSE follows THEN. (??? could be moved) */
if (else_bb->index != then_bb->index + 1)
return FALSE;
if (else_bb->pred->pred_next != NULL)
return FALSE;
- /* ELSE has a label we can delete. */
- if (LABEL_NUSES (else_bb->head) > 1
- || LABEL_PRESERVE_P (else_bb->head)
- || LABEL_NAME (else_bb->head))
+ /* THEN is not EXIT. */
+ if (then_bb->index < 0)
return FALSE;
/* ELSE is predicted or SUCC(ELSE) postdominates THEN. */
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
All that's left is making sure the insns involved can actually
be predicated. */
- rtx cond;
+ rtx cond, prob_val;
cond = cond_exec_get_condition (jump);
+
+ prob_val = find_reg_note (jump, REG_BR_PROB, NULL_RTX);
+ if (prob_val)
+ prob_val = XEXP (prob_val, 0);
+
if (reversep)
- cond = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond)),
- GET_MODE (cond), XEXP (cond, 0),
- XEXP (cond, 1));
+ {
+ cond = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond)),
+ GET_MODE (cond), XEXP (cond, 0),
+ XEXP (cond, 1));
+ if (prob_val)
+ prob_val = GEN_INT (REG_BR_PROB_BASE - INTVAL (prob_val));
+ }
- if (! cond_exec_process_insns (head, end, cond, 0))
+ if (! cond_exec_process_insns (head, end, cond, prob_val, 0))
goto cancel;
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);
}