#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)
{
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 and CLOBBER insns that get in the way. */
- if (reload_completed
- && (GET_CODE (PATTERN (insn)) == USE
- || GET_CODE (PATTERN (insn)) == CLOBBER))
+ /* 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. */
}
/* 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_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;
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;
}
build the store_flag insn directly. */
if (cond_complex)
- cond = XEXP (SET_SRC (PATTERN (if_info->jump)), 0);
+ cond = XEXP (SET_SRC (pc_set (if_info->jump)), 0);
if ((if_info->cond_earliest == if_info->jump || cond_complex)
&& (normalize == 0 || STORE_FLAG_VALUE == normalize))
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;
reorder_insns (insn_b, insn_b, PREV_INSN (if_info.cond_earliest));
insn_b = NULL_RTX;
}
+ /* If we have "x = b; if (...) x = a;", and x has side-effects, then
+ x must be executed twice. */
+ else if (insn_b && side_effects_p (orig_x))
+ return FALSE;
+
x = orig_x;
goto success;
}
/* 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;
{
rtx head, end, jump, earliest, old_dest;
+ /* No code movement can occur if we'd be scrogging EH regions.
+ Within MERGE_BB, ensure that we've not got stray EH_BEG or EH_END
+ notes within the block. Between the blocks, checking that the end
+ region numbers match ensures that we won't disrupt the nesting
+ between regions. */
+ if (merge_bb->eh_beg != merge_bb->eh_end
+ || merge_bb->eh_end != test_bb->eh_end)
+ return FALSE;
+
jump = test_bb->end;
/* Find the extent of the real code in the merge block. */
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
/* ??? bb->local_set is only valid during calculate_global_regs_live,
so we must recompute usage for MERGE_BB. Not so bad, I suppose,
since we've already asserted that MERGE_BB is small. */
- propagate_block (merge_bb, tmp, merge_set, 0);
+ propagate_block (merge_bb, tmp, merge_set, merge_set, 0);
/* For small register class machines, don't lengthen lifetimes of
hard registers before reload. */
Moreover, we're interested in the insns live from OTHER_BB. */
COPY_REG_SET (test_live, other_bb->global_live_at_start);
- pbi = init_propagate_block_info (test_bb, test_live, test_set, 0);
+ pbi = init_propagate_block_info (test_bb, test_live, test_set, test_set,
+ 0);
for (insn = jump; ; insn = prev)
{
if (HAVE_conditional_execution || life_data_ok)
{
post_dominators = sbitmap_vector_alloc (n_basic_blocks, n_basic_blocks);
- compute_flow_dominators (NULL, post_dominators);
+ calculate_dominance_info (NULL, post_dominators, CDI_POST_DOMINATORS);
}
/* Record initial block numbers. */