/* Optimize by combining instructions for GNU compiler.
- Copyright (C) 1987, 88, 92-98, 1999 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 92-98, 1999, 2000 Free Software Foundation, Inc.
This file is part of GNU CC.
static int n_occurrences;
-static void do_SUBST PROTO((rtx *, rtx));
-static void do_SUBST_INT PROTO((int *, int));
-static void init_reg_last_arrays PROTO((void));
-static void setup_incoming_promotions PROTO((void));
-static void set_nonzero_bits_and_sign_copies PROTO((rtx, rtx, void *));
-static int can_combine_p PROTO((rtx, rtx, rtx, rtx, rtx *, rtx *));
-static int sets_function_arg_p PROTO((rtx));
-static int combinable_i3pat PROTO((rtx, rtx *, rtx, rtx, int, rtx *));
-static int contains_muldiv PROTO((rtx));
-static rtx try_combine PROTO((rtx, rtx, rtx));
-static void undo_all PROTO((void));
-static void undo_commit PROTO((void));
-static rtx *find_split_point PROTO((rtx *, rtx));
-static rtx subst PROTO((rtx, rtx, rtx, int, int));
-static rtx combine_simplify_rtx PROTO((rtx, enum machine_mode, int, int));
-static rtx simplify_if_then_else PROTO((rtx));
-static rtx simplify_set PROTO((rtx));
-static rtx simplify_logical PROTO((rtx, int));
-static rtx expand_compound_operation PROTO((rtx));
-static rtx expand_field_assignment PROTO((rtx));
-static rtx make_extraction PROTO((enum machine_mode, rtx, int, rtx, int,
- int, int, int));
-static rtx extract_left_shift PROTO((rtx, int));
-static rtx make_compound_operation PROTO((rtx, enum rtx_code));
-static int get_pos_from_mask PROTO((unsigned HOST_WIDE_INT, int *));
-static rtx force_to_mode PROTO((rtx, enum machine_mode,
- unsigned HOST_WIDE_INT, rtx, int));
-static rtx if_then_else_cond PROTO((rtx, rtx *, rtx *));
-static rtx known_cond PROTO((rtx, enum rtx_code, rtx, rtx));
-static int rtx_equal_for_field_assignment_p PROTO((rtx, rtx));
-static rtx make_field_assignment PROTO((rtx));
-static rtx apply_distributive_law PROTO((rtx));
-static rtx simplify_and_const_int PROTO((rtx, enum machine_mode, rtx,
- unsigned HOST_WIDE_INT));
-static unsigned HOST_WIDE_INT nonzero_bits PROTO((rtx, enum machine_mode));
-static int num_sign_bit_copies PROTO((rtx, enum machine_mode));
-static int merge_outer_ops PROTO((enum rtx_code *, HOST_WIDE_INT *,
- enum rtx_code, HOST_WIDE_INT,
- enum machine_mode, int *));
-static rtx simplify_shift_const PROTO((rtx, enum rtx_code, enum machine_mode,
- rtx, int));
-static int recog_for_combine PROTO((rtx *, rtx, rtx *));
-static rtx gen_lowpart_for_combine PROTO((enum machine_mode, rtx));
-static rtx gen_rtx_combine PVPROTO((enum rtx_code code, enum machine_mode mode,
- ...));
-static rtx gen_binary PROTO((enum rtx_code, enum machine_mode,
- rtx, rtx));
-static rtx gen_unary PROTO((enum rtx_code, enum machine_mode,
- enum machine_mode, rtx));
-static enum rtx_code simplify_comparison PROTO((enum rtx_code, rtx *, rtx *));
-static int reversible_comparison_p PROTO((rtx));
-static void update_table_tick PROTO((rtx));
-static void record_value_for_reg PROTO((rtx, rtx, rtx));
-static void record_dead_and_set_regs_1 PROTO((rtx, rtx, void *));
-static void record_dead_and_set_regs PROTO((rtx));
-static int get_last_value_validate PROTO((rtx *, rtx, int, int));
-static rtx get_last_value PROTO((rtx));
-static int use_crosses_set_p PROTO((rtx, int));
-static void reg_dead_at_p_1 PROTO((rtx, rtx, void *));
-static int reg_dead_at_p PROTO((rtx, rtx));
-static void move_deaths PROTO((rtx, rtx, int, rtx, rtx *));
-static int reg_bitfield_target_p PROTO((rtx, rtx));
-static void distribute_notes PROTO((rtx, rtx, rtx, rtx, rtx, rtx));
-static void distribute_links PROTO((rtx));
-static void mark_used_regs_combine PROTO((rtx));
-static int insn_cuid PROTO((rtx));
+static void do_SUBST PARAMS ((rtx *, rtx));
+static void do_SUBST_INT PARAMS ((int *, int));
+static void init_reg_last_arrays PARAMS ((void));
+static void setup_incoming_promotions PARAMS ((void));
+static void set_nonzero_bits_and_sign_copies PARAMS ((rtx, rtx, void *));
+static int can_combine_p PARAMS ((rtx, rtx, rtx, rtx, rtx *, rtx *));
+static int sets_function_arg_p PARAMS ((rtx));
+static int combinable_i3pat PARAMS ((rtx, rtx *, rtx, rtx, int, rtx *));
+static int contains_muldiv PARAMS ((rtx));
+static rtx try_combine PARAMS ((rtx, rtx, rtx));
+static void undo_all PARAMS ((void));
+static void undo_commit PARAMS ((void));
+static rtx *find_split_point PARAMS ((rtx *, rtx));
+static rtx subst PARAMS ((rtx, rtx, rtx, int, int));
+static rtx combine_simplify_rtx PARAMS ((rtx, enum machine_mode, int, int));
+static rtx simplify_if_then_else PARAMS ((rtx));
+static rtx simplify_set PARAMS ((rtx));
+static rtx simplify_logical PARAMS ((rtx, int));
+static rtx expand_compound_operation PARAMS ((rtx));
+static rtx expand_field_assignment PARAMS ((rtx));
+static rtx make_extraction PARAMS ((enum machine_mode, rtx, int, rtx, int,
+ int, int, int));
+static rtx extract_left_shift PARAMS ((rtx, int));
+static rtx make_compound_operation PARAMS ((rtx, enum rtx_code));
+static int get_pos_from_mask PARAMS ((unsigned HOST_WIDE_INT, int *));
+static rtx force_to_mode PARAMS ((rtx, enum machine_mode,
+ unsigned HOST_WIDE_INT, rtx, int));
+static rtx if_then_else_cond PARAMS ((rtx, rtx *, rtx *));
+static rtx known_cond PARAMS ((rtx, enum rtx_code, rtx, rtx));
+static int rtx_equal_for_field_assignment_p PARAMS ((rtx, rtx));
+static rtx make_field_assignment PARAMS ((rtx));
+static rtx apply_distributive_law PARAMS ((rtx));
+static rtx simplify_and_const_int PARAMS ((rtx, enum machine_mode, rtx,
+ unsigned HOST_WIDE_INT));
+static unsigned HOST_WIDE_INT nonzero_bits PARAMS ((rtx, enum machine_mode));
+static int num_sign_bit_copies PARAMS ((rtx, enum machine_mode));
+static int merge_outer_ops PARAMS ((enum rtx_code *, HOST_WIDE_INT *,
+ enum rtx_code, HOST_WIDE_INT,
+ enum machine_mode, int *));
+static rtx simplify_shift_const PARAMS ((rtx, enum rtx_code, enum machine_mode,
+ rtx, int));
+static int recog_for_combine PARAMS ((rtx *, rtx, rtx *));
+static rtx gen_lowpart_for_combine PARAMS ((enum machine_mode, rtx));
+static rtx gen_rtx_combine PARAMS ((enum rtx_code code, enum machine_mode mode,
+ ...));
+static rtx gen_binary PARAMS ((enum rtx_code, enum machine_mode,
+ rtx, rtx));
+static rtx gen_unary PARAMS ((enum rtx_code, enum machine_mode,
+ enum machine_mode, rtx));
+static enum rtx_code simplify_comparison PARAMS ((enum rtx_code, rtx *, rtx *));
+static int reversible_comparison_p PARAMS ((rtx));
+static void update_table_tick PARAMS ((rtx));
+static void record_value_for_reg PARAMS ((rtx, rtx, rtx));
+static void check_promoted_subreg PARAMS ((rtx, rtx));
+static void record_dead_and_set_regs_1 PARAMS ((rtx, rtx, void *));
+static void record_dead_and_set_regs PARAMS ((rtx));
+static int get_last_value_validate PARAMS ((rtx *, rtx, int, int));
+static rtx get_last_value PARAMS ((rtx));
+static int use_crosses_set_p PARAMS ((rtx, int));
+static void reg_dead_at_p_1 PARAMS ((rtx, rtx, void *));
+static int reg_dead_at_p PARAMS ((rtx, rtx));
+static void move_deaths PARAMS ((rtx, rtx, int, rtx, rtx *));
+static int reg_bitfield_target_p PARAMS ((rtx, rtx));
+static void distribute_notes PARAMS ((rtx, rtx, rtx, rtx, rtx, rtx));
+static void distribute_links PARAMS ((rtx));
+static void mark_used_regs_combine PARAMS ((rtx));
+static int insn_cuid PARAMS ((rtx));
+static void record_promoted_value PARAMS ((rtx, rtx));
\f
/* Substitute NEWVAL, an rtx expression, into INTO, a place in some
insn. The substitution can be undone by undo_all. If INTO is already
else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
+ /* See if we know about function return values before this
+ insn based upon SUBREG flags. */
+ check_promoted_subreg (insn, PATTERN (insn));
+
/* Try this insn with each insn it links back to. */
for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
distribute_notes (new_other_notes, undobuf.other_insn,
undobuf.other_insn, NULL_RTX, NULL_RTX, NULL_RTX);
}
+#ifdef HAVE_cc0
+ /* If I2 is the setter CC0 and I3 is the user CC0 then check whether
+ they are adjacent to each other or not. */
+ {
+ rtx p = prev_nonnote_insn (i3);
+ if (p && p != i2 && GET_CODE (p) == INSN && newi2pat && sets_cc0_p (newi2pat))
+ {
+ undo_all ();
+ return 0;
+ }
+ }
+#endif
/* We now know that we can do this combination. Merge the insns and
update the status of registers and LOG_LINKS. */
if (i3_subst_into_i2)
{
- for (i = 0; i < XVECLEN (PATTERN (i2), 0); i++)
- if (GET_CODE (SET_DEST (XVECEXP (PATTERN (i2), 0, i))) == REG
- && SET_DEST (XVECEXP (PATTERN (i2), 0, i)) != i2dest
- && ! find_reg_note (i2, REG_UNUSED,
- SET_DEST (XVECEXP (PATTERN (i2), 0, i))))
- for (temp = NEXT_INSN (i2);
- temp && (this_basic_block == n_basic_blocks - 1
- || BLOCK_HEAD (this_basic_block) != temp);
- temp = NEXT_INSN (temp))
- if (temp != i3 && GET_RTX_CLASS (GET_CODE (temp)) == 'i')
- for (link = LOG_LINKS (temp); link; link = XEXP (link, 1))
- if (XEXP (link, 0) == i2)
- XEXP (link, 0) = i3;
+ if (GET_CODE (PATTERN (i2)) == PARALLEL)
+ {
+ for (i = 0; i < XVECLEN (PATTERN (i2), 0); i++)
+ if (GET_CODE (SET_DEST (XVECEXP (PATTERN (i2), 0, i))) == REG
+ && SET_DEST (XVECEXP (PATTERN (i2), 0, i)) != i2dest
+ && ! find_reg_note (i2, REG_UNUSED,
+ SET_DEST (XVECEXP (PATTERN (i2), 0, i))))
+ for (temp = NEXT_INSN (i2);
+ temp && (this_basic_block == n_basic_blocks - 1
+ || BLOCK_HEAD (this_basic_block) != temp);
+ temp = NEXT_INSN (temp))
+ if (temp != i3 && GET_RTX_CLASS (GET_CODE (temp)) == 'i')
+ for (link = LOG_LINKS (temp); link; link = XEXP (link, 1))
+ if (XEXP (link, 0) == i2)
+ XEXP (link, 0) = i3;
+ }
if (i3notes)
{
{
regno = REGNO (i2dest);
REG_N_SETS (regno)--;
- if (REG_N_SETS (regno) == 0
- && ! REGNO_REG_SET_P (BASIC_BLOCK (0)->global_live_at_start,
- regno))
- REG_N_REFS (regno) = 0;
}
}
if (! added_sets_1 && ! i1dest_in_i1src)
{
REG_N_SETS (regno)--;
- if (REG_N_SETS (regno) == 0
- && ! REGNO_REG_SET_P (BASIC_BLOCK (0)->global_live_at_start,
- regno))
- REG_N_REFS (regno) = 0;
}
}
temp = simplify_relational_operation (code, op0_mode,
XEXP (x, 0), XEXP (x, 1));
#ifdef FLOAT_STORE_FLAG_VALUE
- if (temp != 0 && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
- temp = ((temp == const0_rtx) ? CONST0_RTX (GET_MODE (x))
- : immed_real_const_1 (FLOAT_STORE_FLAG_VALUE, GET_MODE (x)));
+ if (temp != 0 && GET_MODE_CLASS (mode) == MODE_FLOAT)
+ {
+ if (temp == const0_rtx)
+ temp = CONST0_RTX (mode);
+ else
+ temp = immed_real_const_1 (FLOAT_STORE_FLAG_VALUE (mode), mode);
+ }
#endif
break;
case 'c':
perform the above simplification. */
if (STORE_FLAG_VALUE == -1
- && XEXP (x, 1) == const1_rtx
&& GET_CODE (XEXP (x, 0)) == ASHIFTRT
+ && XEXP (x, 1) == const1_rtx
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
&& INTVAL (XEXP (XEXP (x, 0), 1)) == GET_MODE_BITSIZE (mode) - 1)
return gen_rtx_combine (GE, mode, XEXP (XEXP (x, 0), 0), const0_rtx);
gen_binary (MULT, mode,
XEXP (XEXP (x, 0), 0), XEXP (x, 1)),
gen_binary (MULT, mode,
- XEXP (XEXP (x, 0), 1), XEXP (x, 1))));
+ XEXP (XEXP (x, 0), 1),
+ copy_rtx (XEXP (x, 1)))));
if (GET_CODE (x) != MULT)
return x;
x = apply_distributive_law
(gen_binary (GET_CODE (op0), mode,
gen_binary (AND, mode, XEXP (op0, 0), op1),
- gen_binary (AND, mode, XEXP (op0, 1), op1)));
+ gen_binary (AND, mode, XEXP (op0, 1),
+ copy_rtx (op1))));
if (GET_CODE (x) != AND)
return x;
}
return apply_distributive_law
(gen_binary (GET_CODE (op1), mode,
gen_binary (AND, mode, XEXP (op1, 0), op0),
- gen_binary (AND, mode, XEXP (op1, 1), op0)));
+ gen_binary (AND, mode, XEXP (op1, 1),
+ copy_rtx (op0))));
/* Similarly, taking advantage of the fact that
(and (not A) (xor B C)) == (xor (ior A B) (ior A C)) */
return apply_distributive_law
(gen_binary (XOR, mode,
gen_binary (IOR, mode, XEXP (op0, 0), XEXP (op1, 0)),
- gen_binary (IOR, mode, XEXP (op0, 0), XEXP (op1, 1))));
+ gen_binary (IOR, mode, copy_rtx (XEXP (op0, 0)),
+ XEXP (op1, 1))));
else if (GET_CODE (op1) == NOT && GET_CODE (op0) == XOR)
return apply_distributive_law
(gen_binary (XOR, mode,
gen_binary (IOR, mode, XEXP (op1, 0), XEXP (op0, 0)),
- gen_binary (IOR, mode, XEXP (op1, 0), XEXP (op0, 1))));
+ gen_binary (IOR, mode, copy_rtx (XEXP (op1, 0)), XEXP (op0, 1))));
break;
case IOR:
x = apply_distributive_law
(gen_binary (AND, mode,
gen_binary (IOR, mode, XEXP (op0, 0), op1),
- gen_binary (IOR, mode, XEXP (op0, 1), op1)));
+ gen_binary (IOR, mode, XEXP (op0, 1),
+ copy_rtx (op1))));
if (GET_CODE (x) != IOR)
return x;
x = apply_distributive_law
(gen_binary (AND, mode,
gen_binary (IOR, mode, XEXP (op1, 0), op0),
- gen_binary (IOR, mode, XEXP (op1, 1), op0)));
+ gen_binary (IOR, mode, XEXP (op1, 1),
+ copy_rtx (op0))));
if (GET_CODE (x) != IOR)
return x;
default:
return x;
}
+ /* Convert sign extension to zero extension, if we know that the high
+ bit is not set, as this is easier to optimize. It will be converted
+ back to cheaper alternative in make_extraction. */
+ if (GET_CODE (x) == SIGN_EXTEND
+ && (GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
+ && ((nonzero_bits (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
+ & ~ (((unsigned HOST_WIDE_INT)
+ GET_MODE_MASK (GET_MODE (XEXP (x, 0))))
+ >> 1))
+ == 0)))
+ {
+ rtx temp = gen_rtx_ZERO_EXTEND (GET_MODE (x), XEXP (x, 0));
+ return expand_compound_operation (temp);
+ }
/* We can optimize some special cases of ZERO_EXTEND. */
if (GET_CODE (x) == ZERO_EXTEND)
& ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
return SUBREG_REG (XEXP (x, 0));
- /* If sign extension is cheaper than zero extension, then use it
- if we know that no extraneous bits are set, and that the high
- bit is not set. */
- if (flag_expensive_optimizations
- && ((GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
- && ((nonzero_bits (XEXP (x, 0), GET_MODE (x))
- & ~ (((unsigned HOST_WIDE_INT)
- GET_MODE_MASK (GET_MODE (XEXP (x, 0))))
- >> 1))
- == 0))
- || (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
- && (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
- <= HOST_BITS_PER_WIDE_INT)
- && (((HOST_WIDE_INT) STORE_FLAG_VALUE
- & ~ (((unsigned HOST_WIDE_INT)
- GET_MODE_MASK (GET_MODE (XEXP (x, 0))))
- >> 1))
- == 0))))
- {
- rtx temp = gen_rtx_SIGN_EXTEND (GET_MODE (x), XEXP (x, 0));
-
- if (rtx_cost (temp, SET) < rtx_cost (x, SET))
- return expand_compound_operation (temp);
- }
}
/* If we reach here, we want to return a pair of shifts. The inner
/* A SUBREG between two modes that occupy the same numbers of words
can be done by moving the SUBREG to the source. */
else if (GET_CODE (SET_DEST (x)) == SUBREG
+ /* We need SUBREGs to compute nonzero_bits properly. */
+ && nonzero_sign_valid
&& (((GET_MODE_SIZE (GET_MODE (SET_DEST (x)))
+ (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
== ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (x))))
new = force_to_mode (inner, tmode,
len >= HOST_BITS_PER_WIDE_INT
? GET_MODE_MASK (tmode)
- : ((HOST_WIDE_INT) 1 << len) - 1,
+ : ((unsigned HOST_WIDE_INT) 1 << len) - 1,
NULL_RTX, 0);
/* If this extraction is going into the destination of a SET,
? gen_rtx_CLOBBER (tmode, const0_rtx)
: gen_rtx_combine (STRICT_LOW_PART, VOIDmode, new)));
+ if (mode == tmode)
+ return new;
+
+ /* If we know that no extraneous bits are set, and that the high
+ bit is not set, convert the extraction to the cheaper of
+ sign and zero extension, that are equivalent in these cases. */
+ if (flag_expensive_optimizations
+ && (GET_MODE_BITSIZE (tmode) <= HOST_BITS_PER_WIDE_INT
+ && ((nonzero_bits (new, tmode)
+ & ~ (((unsigned HOST_WIDE_INT)
+ GET_MODE_MASK (tmode))
+ >> 1))
+ == 0)))
+ {
+ rtx temp = gen_rtx_ZERO_EXTEND (mode, new);
+ rtx temp1 = gen_rtx_SIGN_EXTEND (mode, new);
+
+ /* Prefer ZERO_EXTENSION, since it gives more information to
+ backends. */
+ if (rtx_cost (temp, SET) < rtx_cost (temp1, SET))
+ return temp;
+ return temp1;
+ }
+
/* Otherwise, sign- or zero-extend unless we already are in the
proper mode. */
- return (mode == tmode ? new
- : gen_rtx_combine (unsignedp ? ZERO_EXTEND : SIGN_EXTEND,
- mode, new));
+ return (gen_rtx_combine (unsignedp ? ZERO_EXTEND : SIGN_EXTEND,
+ mode, new));
}
/* Unless this is a COMPARE or we have a funny memory reference,
pos_rtx
|| len + orig_pos >= HOST_BITS_PER_WIDE_INT
? GET_MODE_MASK (wanted_inner_mode)
- : (((HOST_WIDE_INT) 1 << len) - 1) << orig_pos,
+ : ((((unsigned HOST_WIDE_INT) 1 << len) - 1)
+ << orig_pos),
NULL_RTX, 0);
}
have to zero extend. Otherwise, we can just use a SUBREG. */
if (pos_rtx != 0
&& GET_MODE_SIZE (pos_mode) > GET_MODE_SIZE (GET_MODE (pos_rtx)))
- pos_rtx = gen_rtx_combine (ZERO_EXTEND, pos_mode, pos_rtx);
+ {
+ rtx temp = gen_rtx_combine (ZERO_EXTEND, pos_mode, pos_rtx);
+
+ /* If we know that no extraneous bits are set, and that the high
+ bit is not set, convert extraction to cheaper one - eighter
+ SIGN_EXTENSION or ZERO_EXTENSION, that are equivalent in these
+ cases. */
+ if (flag_expensive_optimizations
+ && (GET_MODE_BITSIZE (GET_MODE (pos_rtx)) <= HOST_BITS_PER_WIDE_INT
+ && ((nonzero_bits (pos_rtx, GET_MODE (pos_rtx))
+ & ~ (((unsigned HOST_WIDE_INT)
+ GET_MODE_MASK (GET_MODE (pos_rtx)))
+ >> 1))
+ == 0)))
+ {
+ rtx temp1 = gen_rtx_SIGN_EXTEND (pos_mode, pos_rtx);
+
+ /* Preffer ZERO_EXTENSION, since it gives more information to
+ backends. */
+ if (rtx_cost (temp1, SET) < rtx_cost (temp, SET))
+ temp = temp1;
+ }
+ pos_rtx = temp;
+ }
else if (pos_rtx != 0
&& GET_MODE_SIZE (pos_mode) < GET_MODE_SIZE (GET_MODE (pos_rtx)))
pos_rtx = gen_lowpart_for_combine (pos_mode, pos_rtx);
if (op_mode)
fuller_mask = (GET_MODE_BITSIZE (op_mode) >= HOST_BITS_PER_WIDE_INT
? GET_MODE_MASK (op_mode)
- : ((HOST_WIDE_INT) 1 << (floor_log2 (mask) + 1)) - 1);
+ : (((unsigned HOST_WIDE_INT) 1 << (floor_log2 (mask) + 1))
+ - 1));
else
fuller_mask = ~ (HOST_WIDE_INT) 0;
&& GET_MODE_BITSIZE (op_mode) <= HOST_BITS_PER_WIDE_INT)
{
rtx inner = XEXP (x, 0);
+ unsigned HOST_WIDE_INT inner_mask;
/* Select the mask of the bits we need for the shift operand. */
- mask <<= INTVAL (XEXP (x, 1));
+ inner_mask = mask << INTVAL (XEXP (x, 1));
/* We can only change the mode of the shift if we can do arithmetic
- in the mode of the shift and MASK is no wider than the width of
- OP_MODE. */
+ in the mode of the shift and INNER_MASK is no wider than the
+ width of OP_MODE. */
if (GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT
- || (mask & ~ GET_MODE_MASK (op_mode)) != 0)
+ || (inner_mask & ~ GET_MODE_MASK (op_mode)) != 0)
op_mode = GET_MODE (x);
- inner = force_to_mode (inner, op_mode, mask, reg, next_select);
+ inner = force_to_mode (inner, op_mode, inner_mask, reg, next_select);
if (GET_MODE (x) != op_mode || inner != XEXP (x, 0))
x = gen_binary (LSHIFTRT, op_mode, inner, XEXP (x, 1));
&& 0 != (cond0 = if_then_else_cond (SUBREG_REG (x),
&true0, &false0)))
{
- if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) > UNITS_PER_WORD
+ if ((GET_CODE (SUBREG_REG (x)) == REG
+ || GET_CODE (SUBREG_REG (x)) == MEM
+ || CONSTANT_P (SUBREG_REG (x)))
+ && GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) > UNITS_PER_WORD
&& (WORDS_BIG_ENDIAN || SUBREG_WORD (x) != 0))
{
true0 = operand_subword (true0, SUBREG_WORD (x), 0, mode);
if (rtx_equal_p (XEXP (x, 0), reg) && rtx_equal_p (XEXP (x, 1), val))
{
if (GET_RTX_CLASS (code) == '<')
- return (comparison_dominates_p (cond, code) ? const_true_rtx
- : (comparison_dominates_p (cond,
- reverse_condition (code))
- ? const0_rtx : x));
+ {
+ if (comparison_dominates_p (cond, code))
+ return const_true_rtx;
+ code = reverse_condition (code);
+ if (code != UNKNOWN
+ && comparison_dominates_p (cond, code))
+ return const0_rtx;
+ else
+ return x;
+ }
else if (code == SMAX || code == SMIN
|| code == UMIN || code == UMAX)
{
mode,
GET_MODE_BITSIZE (mode) >= HOST_BITS_PER_WIDE_INT
? GET_MODE_MASK (mode)
- : ((HOST_WIDE_INT) 1 << len) - 1,
+ : ((unsigned HOST_WIDE_INT) 1 << len) - 1,
dest, 0);
return gen_rtx_combine (SET, VOIDmode, assign, src);
/* If this is a typical RISC machine, we only have to worry
about the way loads are extended. */
if (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) == SIGN_EXTEND
- ? (nonzero
- & (1L << (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) - 1)))
+ ? (((nonzero
+ & (((unsigned HOST_WIDE_INT) 1
+ << (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) - 1))))
+ != 0))
: LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) != ZERO_EXTEND)
#endif
{
/*VARARGS2*/
static rtx
-gen_rtx_combine VPROTO((enum rtx_code code, enum machine_mode mode, ...))
+gen_rtx_combine VPARAMS ((enum rtx_code code, enum machine_mode mode, ...))
{
#ifndef ANSI_PROTOTYPES
enum rtx_code code;
break;
case MINUS:
+ /* (op (minus A B) 0) -> (op A B) */
+ if (op1 == const0_rtx)
+ {
+ op1 = XEXP (op0, 1);
+ op0 = XEXP (op0, 0);
+ continue;
+ }
+
/* (eq (minus A B) C) -> (eq A (plus B C)) or
(eq B (minus A C)), whichever simplifies. We can only do
this for equality comparisons due to pathological cases involving
{
if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
|| flag_fast_math
- || GET_CODE (x) == NE || GET_CODE (x) == EQ)
+ || GET_CODE (x) == NE || GET_CODE (x) == EQ
+ || GET_CODE (x) == UNORDERED || GET_CODE (x) == ORDERED)
return 1;
switch (GET_MODE_CLASS (GET_MODE (XEXP (x, 0))))
note_stores (PATTERN (insn), record_dead_and_set_regs_1, insn);
}
+
+/* If a SUBREG has the promoted bit set, it is in fact a property of the
+ register present in the SUBREG, so for each such SUBREG go back and
+ adjust nonzero and sign bit information of the registers that are
+ known to have some zero/sign bits set.
+
+ This is needed because when combine blows the SUBREGs away, the
+ information on zero/sign bits is lost and further combines can be
+ missed because of that. */
+
+static void
+record_promoted_value (insn, subreg)
+ rtx insn;
+ rtx subreg;
+{
+ rtx links, set;
+ int regno = REGNO (SUBREG_REG (subreg));
+ enum machine_mode mode = GET_MODE (subreg);
+
+ if (GET_MODE_BITSIZE (mode) >= HOST_BITS_PER_WIDE_INT)
+ return;
+
+ for (links = LOG_LINKS (insn); links; )
+ {
+ insn = XEXP (links, 0);
+ set = single_set (insn);
+
+ if (! set || GET_CODE (SET_DEST (set)) != REG
+ || REGNO (SET_DEST (set)) != regno
+ || GET_MODE (SET_DEST (set)) != GET_MODE (SUBREG_REG (subreg)))
+ {
+ links = XEXP (links, 1);
+ continue;
+ }
+
+ if (reg_last_set [regno] == insn)
+ {
+ if (SUBREG_PROMOTED_UNSIGNED_P (subreg))
+ reg_last_set_nonzero_bits [regno] &= GET_MODE_MASK (mode);
+ }
+
+ if (GET_CODE (SET_SRC (set)) == REG)
+ {
+ regno = REGNO (SET_SRC (set));
+ links = LOG_LINKS (insn);
+ }
+ else
+ break;
+ }
+}
+
+/* Scan X for promoted SUBREGs. For each one found,
+ note what it implies to the registers used in it. */
+
+static void
+check_promoted_subreg (insn, x)
+ rtx insn;
+ rtx x;
+{
+ if (GET_CODE (x) == SUBREG && SUBREG_PROMOTED_VAR_P (x)
+ && GET_CODE (SUBREG_REG (x)) == REG)
+ record_promoted_value (insn, x);
+ else
+ {
+ const char *format = GET_RTX_FORMAT (GET_CODE (x));
+ int i, j;
+
+ for (i = 0; i < GET_RTX_LENGTH (GET_CODE (x)); i++)
+ switch (format [i])
+ {
+ case 'e':
+ check_promoted_subreg (insn, XEXP (x, i));
+ break;
+ case 'V':
+ case 'E':
+ if (XVEC (x, i) != 0)
+ for (j = 0; j < XVECLEN (x, i); j++)
+ check_promoted_subreg (insn, XVECEXP (x, i, j));
+ break;
+ }
+ }
+}
\f
/* Utility routine for the following function. Verify that all the registers
mentioned in *LOC are valid when *LOC was part of a value set when
if (XEXP (note, 0) == elim_i2 || XEXP (note, 0) == elim_i1)
break;
- /* If the register is used in both I2 and I3 and it dies in I3,
- we might have added another reference to it. If reg_n_refs
- was 2, bump it to 3. This has to be correct since the
- register must have been set somewhere. The reason this is
- done is because local-alloc.c treats 2 references as a
- special case. */
-
- if (place == i3 && i2 != 0 && GET_CODE (XEXP (note, 0)) == REG
- && REG_N_REFS (REGNO (XEXP (note, 0)))== 2
- && reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
- REG_N_REFS (REGNO (XEXP (note, 0))) = 3;
-
if (place == 0)
{
basic_block bb = BASIC_BLOCK (this_basic_block);