#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "rtl.h"
#include "regs.h"
static rtx noce_emit_store_flag PARAMS ((struct noce_if_info *,
rtx, int, int));
static int noce_try_store_flag PARAMS ((struct noce_if_info *));
-static int noce_try_store_flag_inc PARAMS ((struct noce_if_info *));
+static int noce_try_addcc PARAMS ((struct noce_if_info *));
static int noce_try_store_flag_constants PARAMS ((struct noce_if_info *));
static int noce_try_store_flag_mask PARAMS ((struct noce_if_info *));
static rtx noce_emit_cmove PARAMS ((struct noce_if_info *,
end_sequence ();
}
- /* Don't even try if the comparison operands are weird. */
- if (cond_complex)
+ /* Don't even try if the comparison operands or the mode of X are weird. */
+ if (cond_complex || !SCALAR_INT_MODE_P (GET_MODE (x)))
return NULL_RTX;
return emit_store_flag (x, code, XEXP (cond, 0),
similarly for "foo--". */
static int
-noce_try_store_flag_inc (if_info)
+noce_try_addcc (if_info)
struct noce_if_info *if_info;
{
rtx target, seq;
int subtract, normalize;
if (! no_new_pseudos
- && (BRANCH_COST >= 2
- || HAVE_incscc
- || HAVE_decscc)
/* Should be no `else' case to worry about. */
&& if_info->b == if_info->x
&& GET_CODE (if_info->a) == PLUS
- && (XEXP (if_info->a, 1) == const1_rtx
- || XEXP (if_info->a, 1) == constm1_rtx)
&& rtx_equal_p (XEXP (if_info->a, 0), if_info->x)
&& (reversed_comparison_code (if_info->cond, if_info->jump)
!= UNKNOWN))
{
- if (STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1)))
- subtract = 0, normalize = 0;
- else if (-STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1)))
- subtract = 1, normalize = 0;
- else
- subtract = 0, normalize = INTVAL (XEXP (if_info->a, 1));
-
- start_sequence ();
+ rtx cond = if_info->cond;
+ enum rtx_code code = reversed_comparison_code (cond, if_info->jump);
- target = noce_emit_store_flag (if_info,
- gen_reg_rtx (GET_MODE (if_info->x)),
- 1, normalize);
-
- if (target)
- target = expand_simple_binop (GET_MODE (if_info->x),
- subtract ? MINUS : PLUS,
- if_info->x, target, if_info->x,
- 0, OPTAB_WIDEN);
- if (target)
+ /* First try to use addcc pattern. */
+ if (general_operand (XEXP (cond, 0), VOIDmode)
+ && general_operand (XEXP (cond, 1), VOIDmode))
{
- if (target != if_info->x)
- noce_emit_move_insn (if_info->x, target);
-
- seq = get_insns ();
+ start_sequence ();
+ target = emit_conditional_add (if_info->x, code,
+ XEXP (cond, 0), XEXP (cond, 1),
+ VOIDmode,
+ if_info->b, XEXP (if_info->a, 1),
+ GET_MODE (if_info->x),
+ (code == LTU || code == GEU
+ || code == LEU || code == GTU));
+ if (target)
+ {
+ if (target != if_info->x)
+ noce_emit_move_insn (if_info->x, target);
+
+ seq = get_insns ();
+ end_sequence ();
+ emit_insn_before_scope (seq, if_info->jump,
+ INSN_SCOPE (if_info->insn_a));
+ return TRUE;
+ }
end_sequence ();
+ }
+
+ /* If that fails, construct conditional increment or decrement using
+ setcc. */
+ if (BRANCH_COST >= 2
+ && (XEXP (if_info->a, 1) == const1_rtx
+ || XEXP (if_info->a, 1) == constm1_rtx))
+ {
+ start_sequence ();
+ if (STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1)))
+ subtract = 0, normalize = 0;
+ else if (-STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1)))
+ subtract = 1, normalize = 0;
+ else
+ subtract = 0, normalize = INTVAL (XEXP (if_info->a, 1));
- if (seq_contains_jump (seq))
- return FALSE;
- emit_insn_before_scope (seq, if_info->jump,
- INSN_SCOPE (if_info->insn_a));
+ target = noce_emit_store_flag (if_info,
+ gen_reg_rtx (GET_MODE (if_info->x)),
+ 1, normalize);
- return TRUE;
- }
+ if (target)
+ target = expand_simple_binop (GET_MODE (if_info->x),
+ subtract ? MINUS : PLUS,
+ if_info->x, target, if_info->x,
+ 0, OPTAB_WIDEN);
+ if (target)
+ {
+ if (target != if_info->x)
+ noce_emit_move_insn (if_info->x, target);
- end_sequence ();
+ seq = get_insns ();
+ end_sequence ();
+
+ if (seq_contains_jump (seq))
+ return FALSE;
+
+ emit_insn_before_scope (seq, if_info->jump,
+ INSN_SCOPE (if_info->insn_a));
+
+ return TRUE;
+ }
+ end_sequence ();
+ }
}
return FALSE;
rtx insn_a, insn_b;
rtx set_a, set_b;
rtx orig_x, x, a, b;
- rtx jump, cond, insn;
+ rtx jump, cond;
/* We're looking for patterns of the form
else
{
insn_b = prev_nonnote_insn (if_info.cond_earliest);
+ /* We're going to be moving the evaluation of B down from above
+ COND_EARLIEST to JUMP. Make sure the relevant data is still
+ intact. */
if (! insn_b
|| GET_CODE (insn_b) != INSN
|| (set_b = single_set (insn_b)) == NULL_RTX
|| ! rtx_equal_p (x, SET_DEST (set_b))
+ || reg_overlap_mentioned_p (x, SET_SRC (set_b))
+ || modified_between_p (SET_SRC (set_b),
+ PREV_INSN (if_info.cond_earliest), jump)
+ /* Likewise with X. In particular this can happen when
+ noce_get_condition looks farther back in the instruction
+ stream than one might expect. */
|| reg_overlap_mentioned_p (x, cond)
|| reg_overlap_mentioned_p (x, a)
- || reg_overlap_mentioned_p (x, SET_SRC (set_b)))
+ || modified_between_p (x, PREV_INSN (if_info.cond_earliest), jump))
insn_b = set_b = NULL_RTX;
}
b = (set_b ? SET_SRC (set_b) : x);
- /* X may not be mentioned in the range (cond_earliest, jump].
- Note the use of reg_overlap_mentioned_p, which handles memories
- properly, as opposed to reg_mentioned_p, which doesn't. */
- for (insn = jump; insn != if_info.cond_earliest; insn = PREV_INSN (insn))
- if (INSN_P (insn) && reg_overlap_mentioned_p (x, PATTERN (insn)))
- return FALSE;
-
- /* A and B may not be modified in the range [cond_earliest, jump). */
- for (insn = if_info.cond_earliest; insn != jump; insn = NEXT_INSN (insn))
- if (INSN_P (insn)
- && (modified_in_p (a, insn) || modified_in_p (b, insn)))
- return FALSE;
-
/* Only operate on register destinations, and even then avoid extending
the lifetime of hard registers on small register class machines. */
orig_x = x;
if (else_bb && insn_b == else_bb->end)
else_bb->end = PREV_INSN (insn_b);
- reorder_insns (insn_b, insn_b, PREV_INSN (if_info.cond_earliest));
+ reorder_insns (insn_b, insn_b, PREV_INSN (jump));
/* If there was a REG_EQUAL note, delete it since it may have been
true due to this insn being after a jump. */
{
if (noce_try_store_flag_constants (&if_info))
goto success;
- if (noce_try_store_flag_inc (&if_info))
+ if (noce_try_addcc (&if_info))
goto success;
if (noce_try_store_flag_mask (&if_info))
goto success;
if (insn_b && else_bb)
delete_insn (insn_b);
- /* The new insns will have been inserted before cond_earliest. We should
- be able to remove the jump with impunity, but the condition itself may
- have been modified by gcse to be shared across basic blocks. */
+ /* The new insns will have been inserted immediately before the jump. We
+ should be able to remove the jump with impunity, but the condition itself
+ may have been modified by gcse to be shared across basic blocks. */
delete_insn (jump);
/* If we used a temporary, fix it up now. */
int max_insns = MAX_CONDITIONAL_EXECUTE;
int n_insns;
- /* Determine if the preceeding block is an && or || block. */
+ /* Determine if the preceding block is an && or || block. */
if ((n_insns = block_jumps_and_fallthru_p (bb, else_bb)) >= 0)
{
ce_info->and_and_p = TRUE;
if (HAVE_conditional_execution)
{
/* In the conditional execution case, we have things easy. We know
- the condition is reversable. We don't have to check life info,
+ the condition is reversible. We don't have to check life info,
becase we're going to conditionally execute the code anyway.
All that's left is making sure the insns involved can actually
be predicated. */
FOR_EACH_BB (bb)
{
- basic_block new_bb = find_if_header (bb, pass);
- if (new_bb)
+ basic_block new_bb;
+ while ((new_bb = find_if_header (bb, pass)))
bb = new_bb;
}