Commit c6fb08ad by Paolo Bonzini Committed by Paolo Bonzini

combine.c (combine_simplify_rtx): Adjust call to use simplify_relational_operation.

2004-04-29  Paolo Bonzini  <bonzini@gnu.org>

        * combine.c (combine_simplify_rtx): Adjust call to use
        simplify_relational_operation.  Do not use SELECT_CC_MODE
        when a comparison already has a MODE_CC mode.
        (simplify_set): simplify_relational_operation may now
        return another relational expression.
        * cse.c (fold_rtx): simplify_relational_operation now
        takes of computing the comparison mode.
        * dojump.c (compare_from_rtx): Use simplify_relational_operation,
        remove dead code.
        (do_compare_rtx_and_jump): Likewise.
        * integrate.c (subst_constants): simplify_relational_operation
        may now return another relational expression.
        * simplify-rtx.c (simplify_gen_relational): Move most code to
        the new simplify_relational_operation and
        simplify_relational_operation_1 functions.
        (simplify_relational_operation): Rewritten.
        (simplify_relational_operation_1): New function.
        (simplify_ternary_operation): simplify_relational_operation
        may now return another relational expression.
        (simplify_rtx): Remove unnecessary temp variable.

From-SVN: r81282
parent 6cf1ac42
2004-04-29 Paolo Bonzini <bonzini@gnu.org>
* combine.c (combine_simplify_rtx): Adjust call to use
simplify_relational_operation. Do not use SELECT_CC_MODE
when a comparison already has a MODE_CC mode.
(simplify_set): simplify_relational_operation may now
return another relational expression.
* cse.c (fold_rtx): simplify_relational_operation now
takes of computing the comparison mode.
* dojump.c (compare_from_rtx): Use simplify_relational_operation,
remove dead code.
(do_compare_rtx_and_jump): Likewise.
* integrate.c (subst_constants): simplify_relational_operation
may now return another relational expression.
* simplify-rtx.c (simplify_gen_relational): Move most code to
the new simplify_relational_operation and
simplify_relational_operation_1 functions.
(simplify_relational_operation): Rewritten.
(simplify_relational_operation_1): New function.
(simplify_ternary_operation): simplify_relational_operation
may now return another relational expression.
(simplify_rtx): Remove unnecessary temp variable.
2004-04-29 Uros Bizjak <uros@kss-loka.si> 2004-04-29 Uros Bizjak <uros@kss-loka.si>
* reg-stack.c (swap_to_top): New function. * reg-stack.c (swap_to_top): New function.
......
...@@ -143,13 +143,103 @@ static int max_uid_cuid; ...@@ -143,13 +143,103 @@ static int max_uid_cuid;
static unsigned int combine_max_regno; static unsigned int combine_max_regno;
/* Record last point of death of (hard or pseudo) register n. */ struct reg_stat {
/* Record last point of death of (hard or pseudo) register n. */
rtx last_death;
static rtx *reg_last_death; /* Record last point of modification of (hard or pseudo) register n. */
rtx last_set;
/* Record last point of modification of (hard or pseudo) register n. */ /* The next group of fields allows the recording of the last value assigned
to (hard or pseudo) register n. We use this information to see if an
operation being processed is redundant given a prior operation performed
on the register. For example, an `and' with a constant is redundant if
all the zero bits are already known to be turned off.
static rtx *reg_last_set; We use an approach similar to that used by cse, but change it in the
following ways:
(1) We do not want to reinitialize at each label.
(2) It is useful, but not critical, to know the actual value assigned
to a register. Often just its form is helpful.
Therefore, we maintain the following fields:
last_set_value the last value assigned
last_set_label records the value of label_tick when the
register was assigned
last_set_table_tick records the value of label_tick when a
value using the register is assigned
last_set_invalid set to nonzero when it is not valid
to use the value of this register in some
register's value
To understand the usage of these tables, it is important to understand
the distinction between the value in last_set_value being valid and
the register being validly contained in some other expression in the
table.
(The next two parameters are out of date).
reg_stat[i].last_set_value is valid if it is nonzero, and either
reg_n_sets[i] is 1 or reg_stat[i].last_set_label == label_tick.
Register I may validly appear in any expression returned for the value
of another register if reg_n_sets[i] is 1. It may also appear in the
value for register J if reg_stat[j].last_set_invalid is zero, or
reg_stat[i].last_set_label < reg_stat[j].last_set_label.
If an expression is found in the table containing a register which may
not validly appear in an expression, the register is replaced by
something that won't match, (clobber (const_int 0)). */
/* Record last value assigned to (hard or pseudo) register n. */
rtx last_set_value;
/* Record the value of label_tick when an expression involving register n
is placed in last_set_value. */
int last_set_table_tick;
/* Record the value of label_tick when the value for register n is placed in
last_set_value. */
int last_set_label;
/* These fields are maintained in parallel with last_set_value and are
used to store the mode in which the register was last set, te bits
that were known to be zero when it was last set, and the number of
sign bits copies it was known to have when it was last set. */
unsigned HOST_WIDE_INT last_set_nonzero_bits;
char last_set_sign_bit_copies;
ENUM_BITFIELD(machine_mode) last_set_mode : 8;
/* Set nonzero if references to register n in expressions should not be
used. last_set_invalid is set nonzero when this register is being
assigned to and last_set_table_tick == label_tick. */
char last_set_invalid;
/* Some registers that are set more than once and used in more than one
basic block are nevertheless always set in similar ways. For example,
a QImode register may be loaded from memory in two places on a machine
where byte loads zero extend.
We record in the following fields if a register has some leading bits
that are always equal to the sign bit, and what we know about the
nonzero bits of a register, specifically which bits are known to be
zero.
If an entry is zero, it means that we don't know anything special. */
unsigned char sign_bit_copies;
unsigned HOST_WIDE_INT nonzero_bits;
};
static struct reg_stat *reg_stat;
/* Record the cuid of the last insn that invalidated memory /* Record the cuid of the last insn that invalidated memory
(anything that writes memory, and subroutine calls, but not pushes). */ (anything that writes memory, and subroutine calls, but not pushes). */
...@@ -197,110 +287,23 @@ static basic_block this_basic_block; ...@@ -197,110 +287,23 @@ static basic_block this_basic_block;
those blocks as starting points. */ those blocks as starting points. */
static sbitmap refresh_blocks; static sbitmap refresh_blocks;
/* The next group of arrays allows the recording of the last value assigned
to (hard or pseudo) register n. We use this information to see if an
operation being processed is redundant given a prior operation performed
on the register. For example, an `and' with a constant is redundant if
all the zero bits are already known to be turned off.
We use an approach similar to that used by cse, but change it in the
following ways:
(1) We do not want to reinitialize at each label.
(2) It is useful, but not critical, to know the actual value assigned
to a register. Often just its form is helpful.
Therefore, we maintain the following arrays:
reg_last_set_value the last value assigned
reg_last_set_label records the value of label_tick when the
register was assigned
reg_last_set_table_tick records the value of label_tick when a
value using the register is assigned
reg_last_set_invalid set to nonzero when it is not valid
to use the value of this register in some
register's value
To understand the usage of these tables, it is important to understand
the distinction between the value in reg_last_set_value being valid
and the register being validly contained in some other expression in the
table.
Entry I in reg_last_set_value is valid if it is nonzero, and either
reg_n_sets[i] is 1 or reg_last_set_label[i] == label_tick.
Register I may validly appear in any expression returned for the value
of another register if reg_n_sets[i] is 1. It may also appear in the
value for register J if reg_last_set_label[i] < reg_last_set_label[j] or
reg_last_set_invalid[j] is zero.
If an expression is found in the table containing a register which may
not validly appear in an expression, the register is replaced by
something that won't match, (clobber (const_int 0)).
reg_last_set_invalid[i] is set nonzero when register I is being assigned
to and reg_last_set_table_tick[i] == label_tick. */
/* Record last value assigned to (hard or pseudo) register n. */
static rtx *reg_last_set_value;
/* Record the value of label_tick when the value for register n is placed in
reg_last_set_value[n]. */
static int *reg_last_set_label;
/* Record the value of label_tick when an expression involving register n
is placed in reg_last_set_value. */
static int *reg_last_set_table_tick;
/* Set nonzero if references to register n in expressions should not be
used. */
static char *reg_last_set_invalid;
/* Incremented for each label. */ /* Incremented for each label. */
static int label_tick; static int label_tick;
/* Some registers that are set more than once and used in more than one /* Mode used to compute significance in reg_stat[].nonzero_bits. It is the
basic block are nevertheless always set in similar ways. For example, largest integer mode that can fit in HOST_BITS_PER_WIDE_INT. */
a QImode register may be loaded from memory in two places on a machine
where byte loads zero extend.
We record in the following array what we know about the nonzero
bits of a register, specifically which bits are known to be zero.
If an entry is zero, it means that we don't know anything special. */
static unsigned HOST_WIDE_INT *reg_nonzero_bits;
/* Mode used to compute significance in reg_nonzero_bits. It is the largest
integer mode that can fit in HOST_BITS_PER_WIDE_INT. */
static enum machine_mode nonzero_bits_mode; static enum machine_mode nonzero_bits_mode;
/* Nonzero if we know that a register has some leading bits that are always /* Nonzero when reg_stat[].nonzero_bits and reg_stat[].sign_bit_copies can
equal to the sign bit. */ be safely used. It is zero while computing them and after combine has
completed. This former test prevents propagating values based on
static unsigned char *reg_sign_bit_copies; previously set values, which can be incorrect if a variable is modified
in a loop. */
/* Nonzero when reg_nonzero_bits and reg_sign_bit_copies can be safely used.
It is zero while computing them and after combine has completed. This
former test prevents propagating values based on previously set values,
which can be incorrect if a variable is modified in a loop. */
static int nonzero_sign_valid; static int nonzero_sign_valid;
/* These arrays are maintained in parallel with reg_last_set_value
and are used to store the mode in which the register was last set,
the bits that were known to be zero when it was last set, and the
number of sign bits copies it was known to have when it was last set. */
static enum machine_mode *reg_last_set_mode;
static unsigned HOST_WIDE_INT *reg_last_set_nonzero_bits;
static char *reg_last_set_sign_bit_copies;
/* Record one modification to rtl structure /* Record one modification to rtl structure
to be undone by storing old_contents into *where. to be undone by storing old_contents into *where.
...@@ -336,7 +339,7 @@ static int n_occurrences; ...@@ -336,7 +339,7 @@ static int n_occurrences;
static void do_SUBST (rtx *, rtx); static void do_SUBST (rtx *, rtx);
static void do_SUBST_INT (int *, int); static void do_SUBST_INT (int *, int);
static void init_reg_last_arrays (void); static void init_reg_last (void);
static void setup_incoming_promotions (void); static void setup_incoming_promotions (void);
static void set_nonzero_bits_and_sign_copies (rtx, rtx, void *); static void set_nonzero_bits_and_sign_copies (rtx, rtx, void *);
static int cant_combine_insn_p (rtx); static int cant_combine_insn_p (rtx);
...@@ -523,20 +526,7 @@ combine_instructions (rtx f, unsigned int nregs) ...@@ -523,20 +526,7 @@ combine_instructions (rtx f, unsigned int nregs)
See comments in gen_lowpart_for_combine. */ See comments in gen_lowpart_for_combine. */
gen_lowpart = gen_lowpart_for_combine; gen_lowpart = gen_lowpart_for_combine;
reg_nonzero_bits = xcalloc (nregs, sizeof (unsigned HOST_WIDE_INT)); reg_stat = xcalloc (nregs, sizeof (struct reg_stat));
reg_sign_bit_copies = xcalloc (nregs, sizeof (unsigned char));
reg_last_death = xmalloc (nregs * sizeof (rtx));
reg_last_set = xmalloc (nregs * sizeof (rtx));
reg_last_set_value = xmalloc (nregs * sizeof (rtx));
reg_last_set_table_tick = xmalloc (nregs * sizeof (int));
reg_last_set_label = xmalloc (nregs * sizeof (int));
reg_last_set_invalid = xmalloc (nregs * sizeof (char));
reg_last_set_mode = xmalloc (nregs * sizeof (enum machine_mode));
reg_last_set_nonzero_bits = xmalloc (nregs * sizeof (HOST_WIDE_INT));
reg_last_set_sign_bit_copies = xmalloc (nregs * sizeof (char));
init_reg_last_arrays ();
init_recog_no_volatile (); init_recog_no_volatile ();
...@@ -551,8 +541,8 @@ combine_instructions (rtx f, unsigned int nregs) ...@@ -551,8 +541,8 @@ combine_instructions (rtx f, unsigned int nregs)
nonzero_bits_mode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0); nonzero_bits_mode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0);
/* Don't use reg_nonzero_bits when computing it. This can cause problems /* Don't use reg_stat[].nonzero_bits when computing it. This can cause
when, for example, we have j <<= 1 in a loop. */ problems when, for example, we have j <<= 1 in a loop. */
nonzero_sign_valid = 0; nonzero_sign_valid = 0;
...@@ -605,7 +595,7 @@ combine_instructions (rtx f, unsigned int nregs) ...@@ -605,7 +595,7 @@ combine_instructions (rtx f, unsigned int nregs)
label_tick = 1; label_tick = 1;
last_call_cuid = 0; last_call_cuid = 0;
mem_last_set = 0; mem_last_set = 0;
init_reg_last_arrays (); init_reg_last ();
setup_incoming_promotions (); setup_incoming_promotions ();
FOR_EACH_BB (this_basic_block) FOR_EACH_BB (this_basic_block)
...@@ -768,17 +758,7 @@ combine_instructions (rtx f, unsigned int nregs) ...@@ -768,17 +758,7 @@ combine_instructions (rtx f, unsigned int nregs)
/* Clean up. */ /* Clean up. */
sbitmap_free (refresh_blocks); sbitmap_free (refresh_blocks);
free (reg_nonzero_bits); free (reg_stat);
free (reg_sign_bit_copies);
free (reg_last_death);
free (reg_last_set);
free (reg_last_set_value);
free (reg_last_set_table_tick);
free (reg_last_set_label);
free (reg_last_set_invalid);
free (reg_last_set_mode);
free (reg_last_set_nonzero_bits);
free (reg_last_set_sign_bit_copies);
free (uid_cuid); free (uid_cuid);
{ {
...@@ -805,22 +785,14 @@ combine_instructions (rtx f, unsigned int nregs) ...@@ -805,22 +785,14 @@ combine_instructions (rtx f, unsigned int nregs)
return new_direct_jump_p; return new_direct_jump_p;
} }
/* Wipe the reg_last_xxx arrays in preparation for another pass. */ /* Wipe the last_xxx fields of reg_stat in preparation for another pass. */
static void static void
init_reg_last_arrays (void) init_reg_last (void)
{ {
unsigned int nregs = combine_max_regno; unsigned int i;
for (i = 0; i < combine_max_regno; i++)
memset (reg_last_death, 0, nregs * sizeof (rtx)); memset (reg_stat + i, 0, offsetof (struct reg_stat, sign_bit_copies));
memset (reg_last_set, 0, nregs * sizeof (rtx));
memset (reg_last_set_value, 0, nregs * sizeof (rtx));
memset (reg_last_set_table_tick, 0, nregs * sizeof (int));
memset (reg_last_set_label, 0, nregs * sizeof (int));
memset (reg_last_set_invalid, 0, nregs * sizeof (char));
memset (reg_last_set_mode, 0, nregs * sizeof (enum machine_mode));
memset (reg_last_set_nonzero_bits, 0, nregs * sizeof (HOST_WIDE_INT));
memset (reg_last_set_sign_bit_copies, 0, nregs * sizeof (char));
} }
/* Set up any promoted values for incoming argument registers. */ /* Set up any promoted values for incoming argument registers. */
...@@ -878,8 +850,8 @@ set_nonzero_bits_and_sign_copies (rtx x, rtx set, ...@@ -878,8 +850,8 @@ set_nonzero_bits_and_sign_copies (rtx x, rtx set,
{ {
if (set == 0 || GET_CODE (set) == CLOBBER) if (set == 0 || GET_CODE (set) == CLOBBER)
{ {
reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x)); reg_stat[REGNO (x)].nonzero_bits = GET_MODE_MASK (GET_MODE (x));
reg_sign_bit_copies[REGNO (x)] = 1; reg_stat[REGNO (x)].sign_bit_copies = 1;
return; return;
} }
...@@ -901,7 +873,7 @@ set_nonzero_bits_and_sign_copies (rtx x, rtx set, ...@@ -901,7 +873,7 @@ set_nonzero_bits_and_sign_copies (rtx x, rtx set,
#ifdef SHORT_IMMEDIATES_SIGN_EXTEND #ifdef SHORT_IMMEDIATES_SIGN_EXTEND
/* If X is narrower than a word and SRC is a non-negative /* If X is narrower than a word and SRC is a non-negative
constant that would appear negative in the mode of X, constant that would appear negative in the mode of X,
sign-extend it for use in reg_nonzero_bits because some sign-extend it for use in reg_stat[].nonzero_bits because some
machines (maybe most) will actually do the sign-extension machines (maybe most) will actually do the sign-extension
and this is the conservative approach. and this is the conservative approach.
...@@ -920,18 +892,18 @@ set_nonzero_bits_and_sign_copies (rtx x, rtx set, ...@@ -920,18 +892,18 @@ set_nonzero_bits_and_sign_copies (rtx x, rtx set,
#endif #endif
/* Don't call nonzero_bits if it cannot change anything. */ /* Don't call nonzero_bits if it cannot change anything. */
if (reg_nonzero_bits[REGNO (x)] != ~(unsigned HOST_WIDE_INT) 0) if (reg_stat[REGNO (x)].nonzero_bits != ~(unsigned HOST_WIDE_INT) 0)
reg_nonzero_bits[REGNO (x)] reg_stat[REGNO (x)].nonzero_bits
|= nonzero_bits (src, nonzero_bits_mode); |= nonzero_bits (src, nonzero_bits_mode);
num = num_sign_bit_copies (SET_SRC (set), GET_MODE (x)); num = num_sign_bit_copies (SET_SRC (set), GET_MODE (x));
if (reg_sign_bit_copies[REGNO (x)] == 0 if (reg_stat[REGNO (x)].sign_bit_copies == 0
|| reg_sign_bit_copies[REGNO (x)] > num) || reg_stat[REGNO (x)].sign_bit_copies > num)
reg_sign_bit_copies[REGNO (x)] = num; reg_stat[REGNO (x)].sign_bit_copies = num;
} }
else else
{ {
reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x)); reg_stat[REGNO (x)].nonzero_bits = GET_MODE_MASK (GET_MODE (x));
reg_sign_bit_copies[REGNO (x)] = 1; reg_stat[REGNO (x)].sign_bit_copies = 1;
} }
} }
} }
...@@ -1101,7 +1073,7 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ, ...@@ -1101,7 +1073,7 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
does not use any registers whose values alter in between. However, does not use any registers whose values alter in between. However,
If the insns are adjacent, a use can't cross a set even though we If the insns are adjacent, a use can't cross a set even though we
think it might (this can happen for a sequence of insns each setting think it might (this can happen for a sequence of insns each setting
the same destination; reg_last_set of that register might point to the same destination; last_set of that register might point to
a NOTE). If INSN has a REG_EQUIV note, the register is always a NOTE). If INSN has a REG_EQUIV note, the register is always
equivalent to the memory so the substitution is valid even if there equivalent to the memory so the substitution is valid even if there
are intervening stores. Also, don't move a volatile asm or are intervening stores. Also, don't move a volatile asm or
...@@ -2331,18 +2303,18 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p) ...@@ -2331,18 +2303,18 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
&& GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != STRICT_LOW_PART && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != STRICT_LOW_PART
&& ! (temp = SET_DEST (XVECEXP (newpat, 0, 1)), && ! (temp = SET_DEST (XVECEXP (newpat, 0, 1)),
(GET_CODE (temp) == REG (GET_CODE (temp) == REG
&& reg_nonzero_bits[REGNO (temp)] != 0 && reg_stat[REGNO (temp)].nonzero_bits != 0
&& GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD && GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD
&& GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT && GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT
&& (reg_nonzero_bits[REGNO (temp)] && (reg_stat[REGNO (temp)].nonzero_bits
!= GET_MODE_MASK (word_mode)))) != GET_MODE_MASK (word_mode))))
&& ! (GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) == SUBREG && ! (GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) == SUBREG
&& (temp = SUBREG_REG (SET_DEST (XVECEXP (newpat, 0, 1))), && (temp = SUBREG_REG (SET_DEST (XVECEXP (newpat, 0, 1))),
(GET_CODE (temp) == REG (GET_CODE (temp) == REG
&& reg_nonzero_bits[REGNO (temp)] != 0 && reg_stat[REGNO (temp)].nonzero_bits != 0
&& GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD && GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD
&& GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT && GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT
&& (reg_nonzero_bits[REGNO (temp)] && (reg_stat[REGNO (temp)].nonzero_bits
!= GET_MODE_MASK (word_mode))))) != GET_MODE_MASK (word_mode)))))
&& ! reg_overlap_mentioned_p (SET_DEST (XVECEXP (newpat, 0, 1)), && ! reg_overlap_mentioned_p (SET_DEST (XVECEXP (newpat, 0, 1)),
SET_SRC (XVECEXP (newpat, 0, 1))) SET_SRC (XVECEXP (newpat, 0, 1)))
...@@ -2783,9 +2755,10 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p) ...@@ -2783,9 +2755,10 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
REG_N_SETS (regno)--; REG_N_SETS (regno)--;
} }
/* Update reg_nonzero_bits et al for any changes that may have been made /* Update reg_stat[].nonzero_bits et al for any changes that may have
to this insn. The order of set_nonzero_bits_and_sign_copies() is been made to this insn. The order of
important. Because newi2pat can affect nonzero_bits of newpat */ set_nonzero_bits_and_sign_copies() is important. Because newi2pat
can affect nonzero_bits of newpat */
if (newi2pat) if (newi2pat)
note_stores (newi2pat, set_nonzero_bits_and_sign_copies, NULL); note_stores (newi2pat, set_nonzero_bits_and_sign_copies, NULL);
note_stores (newpat, set_nonzero_bits_and_sign_copies, NULL); note_stores (newpat, set_nonzero_bits_and_sign_copies, NULL);
...@@ -4994,23 +4967,23 @@ simplify_set (rtx x) ...@@ -4994,23 +4967,23 @@ simplify_set (rtx x)
rtx op0, op1, tmp; rtx op0, op1, tmp;
int other_changed = 0; int other_changed = 0;
enum machine_mode compare_mode = GET_MODE (dest); enum machine_mode compare_mode = GET_MODE (dest);
enum machine_mode tmp_mode;
if (GET_CODE (src) == COMPARE) if (GET_CODE (src) == COMPARE)
op0 = XEXP (src, 0), op1 = XEXP (src, 1); op0 = XEXP (src, 0), op1 = XEXP (src, 1);
else else
op0 = src, op1 = const0_rtx; op0 = src, op1 = const0_rtx;
/* Check whether the comparison is known at compile time. */ tmp = simplify_relational_operation (old_code, compare_mode, VOIDmode,
if (GET_MODE (op0) != VOIDmode) op0, op1);
tmp_mode = GET_MODE (op0); if (!tmp)
else if (GET_MODE (op1) != VOIDmode) new_code = old_code;
tmp_mode = GET_MODE (op1); else if (!CONSTANT_P (tmp))
{
new_code = GET_CODE (tmp);
op0 = XEXP (tmp, 0);
op1 = XEXP (tmp, 1);
}
else else
tmp_mode = compare_mode;
tmp = simplify_const_relational_operation (old_code, tmp_mode,
op0, op1);
if (tmp != NULL_RTX)
{ {
rtx pat = PATTERN (other_insn); rtx pat = PATTERN (other_insn);
undobuf.other_insn = other_insn; undobuf.other_insn = other_insn;
...@@ -5031,12 +5004,15 @@ simplify_set (rtx x) ...@@ -5031,12 +5004,15 @@ simplify_set (rtx x)
} }
/* Simplify our comparison, if possible. */ /* Simplify our comparison, if possible. */
new_code = simplify_comparison (old_code, &op0, &op1); new_code = simplify_comparison (new_code, &op0, &op1);
#ifdef SELECT_CC_MODE #ifdef SELECT_CC_MODE
/* If this machine has CC modes other than CCmode, check to see if we /* If this machine has CC modes other than CCmode, check to see if we
need to use a different CC mode here. */ need to use a different CC mode here. */
compare_mode = SELECT_CC_MODE (new_code, op0, op1); if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC)
compare_mode = GET_MODE (op0);
else
compare_mode = SELECT_CC_MODE (new_code, op0, op1);
#ifndef HAVE_cc0 #ifndef HAVE_cc0
/* If the mode changed, we have to change SET_DEST, the mode in the /* If the mode changed, we have to change SET_DEST, the mode in the
...@@ -8168,17 +8144,17 @@ nonzero_bits1 (rtx x, enum machine_mode mode, rtx known_x, ...@@ -8168,17 +8144,17 @@ nonzero_bits1 (rtx x, enum machine_mode mode, rtx known_x,
value. Otherwise, use the previously-computed global nonzero bits value. Otherwise, use the previously-computed global nonzero bits
for this register. */ for this register. */
if (reg_last_set_value[REGNO (x)] != 0 if (reg_stat[REGNO (x)].last_set_value != 0
&& (reg_last_set_mode[REGNO (x)] == mode && (reg_stat[REGNO (x)].last_set_mode == mode
|| (GET_MODE_CLASS (reg_last_set_mode[REGNO (x)]) == MODE_INT || (GET_MODE_CLASS (reg_stat[REGNO (x)].last_set_mode) == MODE_INT
&& GET_MODE_CLASS (mode) == MODE_INT)) && GET_MODE_CLASS (mode) == MODE_INT))
&& (reg_last_set_label[REGNO (x)] == label_tick && (reg_stat[REGNO (x)].last_set_label == label_tick
|| (REGNO (x) >= FIRST_PSEUDO_REGISTER || (REGNO (x) >= FIRST_PSEUDO_REGISTER
&& REG_N_SETS (REGNO (x)) == 1 && REG_N_SETS (REGNO (x)) == 1
&& ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start, && ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start,
REGNO (x)))) REGNO (x))))
&& INSN_CUID (reg_last_set[REGNO (x)]) < subst_low_cuid) && INSN_CUID (reg_stat[REGNO (x)].last_set) < subst_low_cuid)
return reg_last_set_nonzero_bits[REGNO (x)] & nonzero; return reg_stat[REGNO (x)].last_set_nonzero_bits & nonzero;
tem = get_last_value (x); tem = get_last_value (x);
...@@ -8187,8 +8163,8 @@ nonzero_bits1 (rtx x, enum machine_mode mode, rtx known_x, ...@@ -8187,8 +8163,8 @@ nonzero_bits1 (rtx x, enum machine_mode mode, rtx known_x,
#ifdef SHORT_IMMEDIATES_SIGN_EXTEND #ifdef SHORT_IMMEDIATES_SIGN_EXTEND
/* If X is narrower than MODE and TEM is a non-negative /* If X is narrower than MODE and TEM is a non-negative
constant that would appear negative in the mode of X, constant that would appear negative in the mode of X,
sign-extend it for use in reg_nonzero_bits because some sign-extend it for use in reg_stat[].nonzero_bits because
machines (maybe most) will actually do the sign-extension some machines (maybe most) will actually do the sign-extension
and this is the conservative approach. and this is the conservative approach.
??? For 2.5, try to tighten up the MD files in this regard ??? For 2.5, try to tighten up the MD files in this regard
...@@ -8206,9 +8182,9 @@ nonzero_bits1 (rtx x, enum machine_mode mode, rtx known_x, ...@@ -8206,9 +8182,9 @@ nonzero_bits1 (rtx x, enum machine_mode mode, rtx known_x,
#endif #endif
return nonzero_bits_with_known (tem, mode) & nonzero; return nonzero_bits_with_known (tem, mode) & nonzero;
} }
else if (nonzero_sign_valid && reg_nonzero_bits[REGNO (x)]) else if (nonzero_sign_valid && reg_stat[REGNO (x)].nonzero_bits)
{ {
unsigned HOST_WIDE_INT mask = reg_nonzero_bits[REGNO (x)]; unsigned HOST_WIDE_INT mask = reg_stat[REGNO (x)].nonzero_bits;
if (GET_MODE_BITSIZE (GET_MODE (x)) < mode_width) if (GET_MODE_BITSIZE (GET_MODE (x)) < mode_width)
/* We don't know anything about the upper bits. */ /* We don't know anything about the upper bits. */
...@@ -8664,23 +8640,23 @@ num_sign_bit_copies1 (rtx x, enum machine_mode mode, rtx known_x, ...@@ -8664,23 +8640,23 @@ num_sign_bit_copies1 (rtx x, enum machine_mode mode, rtx known_x,
return GET_MODE_BITSIZE (Pmode) - GET_MODE_BITSIZE (ptr_mode) + 1; return GET_MODE_BITSIZE (Pmode) - GET_MODE_BITSIZE (ptr_mode) + 1;
#endif #endif
if (reg_last_set_value[REGNO (x)] != 0 if (reg_stat[REGNO (x)].last_set_value != 0
&& reg_last_set_mode[REGNO (x)] == mode && reg_stat[REGNO (x)].last_set_mode == mode
&& (reg_last_set_label[REGNO (x)] == label_tick && (reg_stat[REGNO (x)].last_set_label == label_tick
|| (REGNO (x) >= FIRST_PSEUDO_REGISTER || (REGNO (x) >= FIRST_PSEUDO_REGISTER
&& REG_N_SETS (REGNO (x)) == 1 && REG_N_SETS (REGNO (x)) == 1
&& ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start, && ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start,
REGNO (x)))) REGNO (x))))
&& INSN_CUID (reg_last_set[REGNO (x)]) < subst_low_cuid) && INSN_CUID (reg_stat[REGNO (x)].last_set) < subst_low_cuid)
return reg_last_set_sign_bit_copies[REGNO (x)]; return reg_stat[REGNO (x)].last_set_sign_bit_copies;
tem = get_last_value (x); tem = get_last_value (x);
if (tem != 0) if (tem != 0)
return num_sign_bit_copies_with_known (tem, mode); return num_sign_bit_copies_with_known (tem, mode);
if (nonzero_sign_valid && reg_sign_bit_copies[REGNO (x)] != 0 if (nonzero_sign_valid && reg_stat[REGNO (x)].sign_bit_copies != 0
&& GET_MODE_BITSIZE (GET_MODE (x)) == bitwidth) && GET_MODE_BITSIZE (GET_MODE (x)) == bitwidth)
return reg_sign_bit_copies[REGNO (x)]; return reg_stat[REGNO (x)].sign_bit_copies;
break; break;
case MEM: case MEM:
...@@ -11364,7 +11340,7 @@ reversed_comparison (rtx exp, enum machine_mode mode, rtx op0, rtx op1) ...@@ -11364,7 +11340,7 @@ reversed_comparison (rtx exp, enum machine_mode mode, rtx op0, rtx op1)
} }
/* Utility function for following routine. Called when X is part of a value /* Utility function for following routine. Called when X is part of a value
being stored into reg_last_set_value. Sets reg_last_set_table_tick being stored into last_set_value. Sets last_set_table_tick
for each register mentioned. Similar to mention_regs in cse.c */ for each register mentioned. Similar to mention_regs in cse.c */
static void static void
...@@ -11383,7 +11359,7 @@ update_table_tick (rtx x) ...@@ -11383,7 +11359,7 @@ update_table_tick (rtx x)
unsigned int r; unsigned int r;
for (r = regno; r < endregno; r++) for (r = regno; r < endregno; r++)
reg_last_set_table_tick[r] = label_tick; reg_stat[r].last_set_table_tick = label_tick;
return; return;
} }
...@@ -11431,8 +11407,9 @@ update_table_tick (rtx x) ...@@ -11431,8 +11407,9 @@ update_table_tick (rtx x)
/* Record that REG is set to VALUE in insn INSN. If VALUE is zero, we /* Record that REG is set to VALUE in insn INSN. If VALUE is zero, we
are saying that the register is clobbered and we no longer know its are saying that the register is clobbered and we no longer know its
value. If INSN is zero, don't update reg_last_set; this is only permitted value. If INSN is zero, don't update reg_stat[].last_set; this is
with VALUE also zero and is used to invalidate the register. */ only permitted with VALUE also zero and is used to invalidate the
register. */
static void static void
record_value_for_reg (rtx reg, rtx insn, rtx value) record_value_for_reg (rtx reg, rtx insn, rtx value)
...@@ -11476,13 +11453,13 @@ record_value_for_reg (rtx reg, rtx insn, rtx value) ...@@ -11476,13 +11453,13 @@ record_value_for_reg (rtx reg, rtx insn, rtx value)
for (i = regno; i < endregno; i++) for (i = regno; i < endregno; i++)
{ {
if (insn) if (insn)
reg_last_set[i] = insn; reg_stat[i].last_set = insn;
reg_last_set_value[i] = 0; reg_stat[i].last_set_value = 0;
reg_last_set_mode[i] = 0; reg_stat[i].last_set_mode = 0;
reg_last_set_nonzero_bits[i] = 0; reg_stat[i].last_set_nonzero_bits = 0;
reg_last_set_sign_bit_copies[i] = 0; reg_stat[i].last_set_sign_bit_copies = 0;
reg_last_death[i] = 0; reg_stat[i].last_death = 0;
} }
/* Mark registers that are being referenced in this value. */ /* Mark registers that are being referenced in this value. */
...@@ -11498,40 +11475,40 @@ record_value_for_reg (rtx reg, rtx insn, rtx value) ...@@ -11498,40 +11475,40 @@ record_value_for_reg (rtx reg, rtx insn, rtx value)
for (i = regno; i < endregno; i++) for (i = regno; i < endregno; i++)
{ {
reg_last_set_label[i] = label_tick; reg_stat[i].last_set_label = label_tick;
if (value && reg_last_set_table_tick[i] == label_tick) if (value && reg_stat[i].last_set_table_tick == label_tick)
reg_last_set_invalid[i] = 1; reg_stat[i].last_set_invalid = 1;
else else
reg_last_set_invalid[i] = 0; reg_stat[i].last_set_invalid = 0;
} }
/* The value being assigned might refer to X (like in "x++;"). In that /* The value being assigned might refer to X (like in "x++;"). In that
case, we must replace it with (clobber (const_int 0)) to prevent case, we must replace it with (clobber (const_int 0)) to prevent
infinite loops. */ infinite loops. */
if (value && ! get_last_value_validate (&value, insn, if (value && ! get_last_value_validate (&value, insn,
reg_last_set_label[regno], 0)) reg_stat[regno].last_set_label, 0))
{ {
value = copy_rtx (value); value = copy_rtx (value);
if (! get_last_value_validate (&value, insn, if (! get_last_value_validate (&value, insn,
reg_last_set_label[regno], 1)) reg_stat[regno].last_set_label, 1))
value = 0; value = 0;
} }
/* For the main register being modified, update the value, the mode, the /* For the main register being modified, update the value, the mode, the
nonzero bits, and the number of sign bit copies. */ nonzero bits, and the number of sign bit copies. */
reg_last_set_value[regno] = value; reg_stat[regno].last_set_value = value;
if (value) if (value)
{ {
enum machine_mode mode = GET_MODE (reg); enum machine_mode mode = GET_MODE (reg);
subst_low_cuid = INSN_CUID (insn); subst_low_cuid = INSN_CUID (insn);
reg_last_set_mode[regno] = mode; reg_stat[regno].last_set_mode = mode;
if (GET_MODE_CLASS (mode) == MODE_INT if (GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT) && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
mode = nonzero_bits_mode; mode = nonzero_bits_mode;
reg_last_set_nonzero_bits[regno] = nonzero_bits (value, mode); reg_stat[regno].last_set_nonzero_bits = nonzero_bits (value, mode);
reg_last_set_sign_bit_copies[regno] reg_stat[regno].last_set_sign_bit_copies
= num_sign_bit_copies (value, GET_MODE (reg)); = num_sign_bit_copies (value, GET_MODE (reg));
} }
} }
...@@ -11576,11 +11553,11 @@ record_dead_and_set_regs_1 (rtx dest, rtx setter, void *data) ...@@ -11576,11 +11553,11 @@ record_dead_and_set_regs_1 (rtx dest, rtx setter, void *data)
for the things done by INSN. This is the last thing done in processing for the things done by INSN. This is the last thing done in processing
INSN in the combiner loop. INSN in the combiner loop.
We update reg_last_set, reg_last_set_value, reg_last_set_mode, We update reg_stat[], in particular fields last_set, last_set_value,
reg_last_set_nonzero_bits, reg_last_set_sign_bit_copies, reg_last_death, last_set_mode, last_set_nonzero_bits, last_set_sign_bit_copies,
and also the similar information mem_last_set (which insn most recently last_death, and also the similar information mem_last_set (which insn
modified memory) and last_call_cuid (which insn was the most recent most recently modified memory) and last_call_cuid (which insn was the
subroutine call). */ most recent subroutine call). */
static void static void
record_dead_and_set_regs (rtx insn) record_dead_and_set_regs (rtx insn)
...@@ -11600,7 +11577,7 @@ record_dead_and_set_regs (rtx insn) ...@@ -11600,7 +11577,7 @@ record_dead_and_set_regs (rtx insn)
: 1); : 1);
for (i = regno; i < endregno; i++) for (i = regno; i < endregno; i++)
reg_last_death[i] = insn; reg_stat[i].last_death = insn;
} }
else if (REG_NOTE_KIND (link) == REG_INC) else if (REG_NOTE_KIND (link) == REG_INC)
record_value_for_reg (XEXP (link, 0), insn, NULL_RTX); record_value_for_reg (XEXP (link, 0), insn, NULL_RTX);
...@@ -11611,11 +11588,11 @@ record_dead_and_set_regs (rtx insn) ...@@ -11611,11 +11588,11 @@ record_dead_and_set_regs (rtx insn)
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i)) if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
{ {
reg_last_set_value[i] = 0; reg_stat[i].last_set_value = 0;
reg_last_set_mode[i] = 0; reg_stat[i].last_set_mode = 0;
reg_last_set_nonzero_bits[i] = 0; reg_stat[i].last_set_nonzero_bits = 0;
reg_last_set_sign_bit_copies[i] = 0; reg_stat[i].last_set_sign_bit_copies = 0;
reg_last_death[i] = 0; reg_stat[i].last_death = 0;
} }
last_call_cuid = mem_last_set = INSN_CUID (insn); last_call_cuid = mem_last_set = INSN_CUID (insn);
...@@ -11663,10 +11640,10 @@ record_promoted_value (rtx insn, rtx subreg) ...@@ -11663,10 +11640,10 @@ record_promoted_value (rtx insn, rtx subreg)
continue; continue;
} }
if (reg_last_set[regno] == insn) if (reg_stat[regno].last_set == insn)
{ {
if (SUBREG_PROMOTED_UNSIGNED_P (subreg) > 0) if (SUBREG_PROMOTED_UNSIGNED_P (subreg) > 0)
reg_last_set_nonzero_bits[regno] &= GET_MODE_MASK (mode); reg_stat[regno].last_set_nonzero_bits &= GET_MODE_MASK (mode);
} }
if (GET_CODE (SET_SRC (set)) == REG) if (GET_CODE (SET_SRC (set)) == REG)
...@@ -11736,14 +11713,14 @@ get_last_value_validate (rtx *loc, rtx insn, int tick, int replace) ...@@ -11736,14 +11713,14 @@ get_last_value_validate (rtx *loc, rtx insn, int tick, int replace)
unsigned int j; unsigned int j;
for (j = regno; j < endregno; j++) for (j = regno; j < endregno; j++)
if (reg_last_set_invalid[j] if (reg_stat[j].last_set_invalid
/* If this is a pseudo-register that was only set once and not /* If this is a pseudo-register that was only set once and not
live at the beginning of the function, it is always valid. */ live at the beginning of the function, it is always valid. */
|| (! (regno >= FIRST_PSEUDO_REGISTER || (! (regno >= FIRST_PSEUDO_REGISTER
&& REG_N_SETS (regno) == 1 && REG_N_SETS (regno) == 1
&& (! REGNO_REG_SET_P && (! REGNO_REG_SET_P
(ENTRY_BLOCK_PTR->next_bb->global_live_at_start, regno))) (ENTRY_BLOCK_PTR->next_bb->global_live_at_start, regno)))
&& reg_last_set_label[j] > tick)) && reg_stat[j].last_set_label > tick))
{ {
if (replace) if (replace)
*loc = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx); *loc = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
...@@ -11835,7 +11812,7 @@ get_last_value (rtx x) ...@@ -11835,7 +11812,7 @@ get_last_value (rtx x)
return 0; return 0;
regno = REGNO (x); regno = REGNO (x);
value = reg_last_set_value[regno]; value = reg_stat[regno].last_set_value;
/* If we don't have a value, or if it isn't for this basic block and /* If we don't have a value, or if it isn't for this basic block and
it's either a hard register, set more than once, or it's a live it's either a hard register, set more than once, or it's a live
...@@ -11848,7 +11825,7 @@ get_last_value (rtx x) ...@@ -11848,7 +11825,7 @@ get_last_value (rtx x)
block. */ block. */
if (value == 0 if (value == 0
|| (reg_last_set_label[regno] != label_tick || (reg_stat[regno].last_set_label != label_tick
&& (regno < FIRST_PSEUDO_REGISTER && (regno < FIRST_PSEUDO_REGISTER
|| REG_N_SETS (regno) != 1 || REG_N_SETS (regno) != 1
|| (REGNO_REG_SET_P || (REGNO_REG_SET_P
...@@ -11857,20 +11834,20 @@ get_last_value (rtx x) ...@@ -11857,20 +11834,20 @@ get_last_value (rtx x)
/* If the value was set in a later insn than the ones we are processing, /* If the value was set in a later insn than the ones we are processing,
we can't use it even if the register was only set once. */ we can't use it even if the register was only set once. */
if (INSN_CUID (reg_last_set[regno]) >= subst_low_cuid) if (INSN_CUID (reg_stat[regno].last_set) >= subst_low_cuid)
return 0; return 0;
/* If the value has all its registers valid, return it. */ /* If the value has all its registers valid, return it. */
if (get_last_value_validate (&value, reg_last_set[regno], if (get_last_value_validate (&value, reg_stat[regno].last_set,
reg_last_set_label[regno], 0)) reg_stat[regno].last_set_label, 0))
return value; return value;
/* Otherwise, make a copy and replace any invalid register with /* Otherwise, make a copy and replace any invalid register with
(clobber (const_int 0)). If that fails for some reason, return 0. */ (clobber (const_int 0)). If that fails for some reason, return 0. */
value = copy_rtx (value); value = copy_rtx (value);
if (get_last_value_validate (&value, reg_last_set[regno], if (get_last_value_validate (&value, reg_stat[regno].last_set,
reg_last_set_label[regno], 1)) reg_stat[regno].last_set_label, 1))
return value; return value;
return 0; return 0;
...@@ -11899,8 +11876,8 @@ use_crosses_set_p (rtx x, int from_cuid) ...@@ -11899,8 +11876,8 @@ use_crosses_set_p (rtx x, int from_cuid)
return 1; return 1;
#endif #endif
for (; regno < endreg; regno++) for (; regno < endreg; regno++)
if (reg_last_set[regno] if (reg_stat[regno].last_set
&& INSN_CUID (reg_last_set[regno]) > from_cuid) && INSN_CUID (reg_stat[regno].last_set) > from_cuid)
return 1; return 1;
return 0; return 0;
} }
...@@ -12160,7 +12137,7 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn, ...@@ -12160,7 +12137,7 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn,
if (code == REG) if (code == REG)
{ {
unsigned int regno = REGNO (x); unsigned int regno = REGNO (x);
rtx where_dead = reg_last_death[regno]; rtx where_dead = reg_stat[regno].last_death;
rtx before_dead, after_dead; rtx before_dead, after_dead;
/* Don't move the register if it gets killed in between from and to. */ /* Don't move the register if it gets killed in between from and to. */
...@@ -12187,7 +12164,7 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn, ...@@ -12187,7 +12164,7 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn,
rtx note = remove_death (regno, where_dead); rtx note = remove_death (regno, where_dead);
/* It is possible for the call above to return 0. This can occur /* It is possible for the call above to return 0. This can occur
when reg_last_death points to I2 or I1 that we combined with. when last_death points to I2 or I1 that we combined with.
In that case make a new note. In that case make a new note.
We must also check for the case where X is a hard register We must also check for the case where X is a hard register
...@@ -12794,14 +12771,14 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2) ...@@ -12794,14 +12771,14 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
|| reg_bitfield_target_p (XEXP (note, 0), PATTERN (place))) || reg_bitfield_target_p (XEXP (note, 0), PATTERN (place)))
{ {
/* Unless the register previously died in PLACE, clear /* Unless the register previously died in PLACE, clear
reg_last_death. [I no longer understand why this is last_death. [I no longer understand why this is
being done.] */ being done.] */
if (reg_last_death[regno] != place) if (reg_stat[regno].last_death != place)
reg_last_death[regno] = 0; reg_stat[regno].last_death = 0;
place = 0; place = 0;
} }
else else
reg_last_death[regno] = place; reg_stat[regno].last_death = place;
/* If this is a death note for a hard reg that is occupying /* If this is a death note for a hard reg that is occupying
multiple registers, ensure that we are still using all multiple registers, ensure that we are still using all
......
...@@ -3924,21 +3924,11 @@ fold_rtx (rtx x, rtx insn) ...@@ -3924,21 +3924,11 @@ fold_rtx (rtx x, rtx insn)
} }
} }
new = simplify_relational_operation (code, mode, {
(mode_arg0 != VOIDmode rtx op0 = const_arg0 ? const_arg0 : folded_arg0;
? mode_arg0 rtx op1 = const_arg1 ? const_arg1 : folded_arg1;
: (GET_MODE (const_arg0 new = simplify_relational_operation (code, mode, mode_arg0, op0, op1);
? const_arg0 }
: folded_arg0)
!= VOIDmode)
? GET_MODE (const_arg0
? const_arg0
: folded_arg0)
: GET_MODE (const_arg1
? const_arg1
: folded_arg1)),
const_arg0 ? const_arg0 : folded_arg0,
const_arg1 ? const_arg1 : folded_arg1);
break; break;
case RTX_BIN_ARITH: case RTX_BIN_ARITH:
......
...@@ -820,7 +820,6 @@ rtx ...@@ -820,7 +820,6 @@ rtx
compare_from_rtx (rtx op0, rtx op1, enum rtx_code code, int unsignedp, compare_from_rtx (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
enum machine_mode mode, rtx size) enum machine_mode mode, rtx size)
{ {
enum rtx_code ucode;
rtx tem; rtx tem;
/* If one operand is constant, make it the second one. Only do this /* If one operand is constant, make it the second one. Only do this
...@@ -842,32 +841,19 @@ compare_from_rtx (rtx op0, rtx op1, enum rtx_code code, int unsignedp, ...@@ -842,32 +841,19 @@ compare_from_rtx (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
do_pending_stack_adjust (); do_pending_stack_adjust ();
ucode = unsignedp ? unsigned_condition (code) : code; code = unsignedp ? unsigned_condition (code) : code;
tem = simplify_const_relational_operation (ucode, mode, op0, op1); if (0 != (tem = simplify_relational_operation (code, mode, VOIDmode,
if (tem != 0) op0, op1)))
return tem;
#if 0
/* There's no need to do this now that combine.c can eliminate lots of
sign extensions. This can be less efficient in certain cases on other
machines. */
/* If this is a signed equality comparison, we can do it as an
unsigned comparison since zero-extension is cheaper than sign
extension and comparisons with zero are done as unsigned. This is
the case even on machines that can do fast sign extension, since
zero-extension is easier to combine with other operations than
sign-extension is. If we are comparing against a constant, we must
convert it to what it would look like unsigned. */
if ((code == EQ || code == NE) && ! unsignedp
&& GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT)
{ {
if (GET_CODE (op1) == CONST_INT if (CONSTANT_P (tem))
&& (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0))) != INTVAL (op1)) return tem;
op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0)));
unsignedp = 1; code = GET_CODE (tem);
mode = GET_MODE (tem);
op0 = XEXP (tem, 0);
op1 = XEXP (tem, 1);
unsignedp = (code == GTU || code == LTU || code == GEU || code == LEU);
} }
#endif
emit_cmp_insn (op0, op1, code, size, mode, unsignedp); emit_cmp_insn (op0, op1, code, size, mode, unsignedp);
...@@ -889,7 +875,6 @@ do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp, ...@@ -889,7 +875,6 @@ do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
enum machine_mode mode, rtx size, rtx if_false_label, enum machine_mode mode, rtx size, rtx if_false_label,
rtx if_true_label) rtx if_true_label)
{ {
enum rtx_code ucode;
rtx tem; rtx tem;
int dummy_true_label = 0; int dummy_true_label = 0;
...@@ -921,44 +906,25 @@ do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp, ...@@ -921,44 +906,25 @@ do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
do_pending_stack_adjust (); do_pending_stack_adjust ();
ucode = unsignedp ? unsigned_condition (code) : code; code = unsignedp ? unsigned_condition (code) : code;
tem = simplify_const_relational_operation (ucode, mode, op0, op1); if (0 != (tem = simplify_relational_operation (code, mode, VOIDmode,
if (tem != 0) op0, op1)))
{ {
if (tem == const_true_rtx) if (CONSTANT_P (tem))
{ {
if (if_true_label) rtx label = (tem == const0_rtx || tem == CONST0_RTX (mode))
emit_jump (if_true_label); ? if_false_label : if_true_label;
} if (label)
else emit_jump (label);
{ return;
if (if_false_label) }
emit_jump (if_false_label);
}
return;
}
#if 0 code = GET_CODE (tem);
/* There's no need to do this now that combine.c can eliminate lots of mode = GET_MODE (tem);
sign extensions. This can be less efficient in certain cases on other op0 = XEXP (tem, 0);
machines. */ op1 = XEXP (tem, 1);
unsignedp = (code == GTU || code == LTU || code == GEU || code == LEU);
/* If this is a signed equality comparison, we can do it as an
unsigned comparison since zero-extension is cheaper than sign
extension and comparisons with zero are done as unsigned. This is
the case even on machines that can do fast sign extension, since
zero-extension is easier to combine with other operations than
sign-extension is. If we are comparing against a constant, we must
convert it to what it would look like unsigned. */
if ((code == EQ || code == NE) && ! unsignedp
&& GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT)
{
if (GET_CODE (op1) == CONST_INT
&& (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0))) != INTVAL (op1))
op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0)));
unsignedp = 1;
} }
#endif
if (! if_true_label) if (! if_true_label)
{ {
......
...@@ -2738,6 +2738,7 @@ subst_constants (rtx *loc, rtx insn, struct inline_remap *map, int memonly) ...@@ -2738,6 +2738,7 @@ subst_constants (rtx *loc, rtx insn, struct inline_remap *map, int memonly)
if (op_mode == VOIDmode) if (op_mode == VOIDmode)
op_mode = GET_MODE (XEXP (x, 1)); op_mode = GET_MODE (XEXP (x, 1));
new = simplify_relational_operation (code, GET_MODE (x), op_mode, new = simplify_relational_operation (code, GET_MODE (x), op_mode,
XEXP (x, 0), XEXP (x, 1)); XEXP (x, 0), XEXP (x, 1));
break; break;
...@@ -2766,15 +2767,18 @@ subst_constants (rtx *loc, rtx insn, struct inline_remap *map, int memonly) ...@@ -2766,15 +2767,18 @@ subst_constants (rtx *loc, rtx insn, struct inline_remap *map, int memonly)
{ {
/* We have compare of two VOIDmode constants for which /* We have compare of two VOIDmode constants for which
we recorded the comparison mode. */ we recorded the comparison mode. */
rtx temp = rtx tem =
simplify_const_relational_operation (GET_CODE (op0), simplify_gen_relational (GET_CODE (op0), GET_MODE (op0),
map->compare_mode, map->compare_mode, XEXP (op0, 0),
XEXP (op0, 0), XEXP (op0, 1));
XEXP (op0, 1));
if (GET_CODE (tem) != CONST_INT)
if (temp == const0_rtx) new = simplify_ternary_operation (code, GET_MODE (x),
op0_mode, tem, XEXP (x, 1),
XEXP (x, 2));
else if (tem == const0_rtx)
new = XEXP (x, 2); new = XEXP (x, 2);
else if (temp == const1_rtx) else
new = XEXP (x, 1); new = XEXP (x, 1);
} }
} }
......
...@@ -58,6 +58,8 @@ static rtx simplify_immed_subreg (enum machine_mode, rtx, enum machine_mode, ...@@ -58,6 +58,8 @@ static rtx simplify_immed_subreg (enum machine_mode, rtx, enum machine_mode,
unsigned int); unsigned int);
static rtx simplify_associative_operation (enum rtx_code, enum machine_mode, static rtx simplify_associative_operation (enum rtx_code, enum machine_mode,
rtx, rtx); rtx, rtx);
static rtx simplify_relational_operation_1 (enum rtx_code, enum machine_mode,
enum machine_mode, rtx, rtx);
/* Negate a CONST_INT rtx, truncating (because a conversion from a /* Negate a CONST_INT rtx, truncating (because a conversion from a
maximally negative number can overflow). */ maximally negative number can overflow). */
...@@ -221,10 +223,9 @@ simplify_gen_ternary (enum rtx_code code, enum machine_mode mode, ...@@ -221,10 +223,9 @@ simplify_gen_ternary (enum rtx_code code, enum machine_mode mode,
return gen_rtx_fmt_eee (code, mode, op0, op1, op2); return gen_rtx_fmt_eee (code, mode, op0, op1, op2);
} }
/* Likewise, for relational operations. /* Likewise, for relational operations.
CMP_MODE specifies mode comparison is done in. CMP_MODE specifies mode comparison is done in. */
*/
rtx rtx
simplify_gen_relational (enum rtx_code code, enum machine_mode mode, simplify_gen_relational (enum rtx_code code, enum machine_mode mode,
...@@ -232,46 +233,9 @@ simplify_gen_relational (enum rtx_code code, enum machine_mode mode, ...@@ -232,46 +233,9 @@ simplify_gen_relational (enum rtx_code code, enum machine_mode mode,
{ {
rtx tem; rtx tem;
if (cmp_mode == VOIDmode) if (0 != (tem = simplify_relational_operation (code, mode, cmp_mode,
cmp_mode = GET_MODE (op0); op0, op1)))
if (cmp_mode == VOIDmode) return tem;
cmp_mode = GET_MODE (op1);
if (cmp_mode != VOIDmode)
{
tem = simplify_relational_operation (code, mode, cmp_mode, op0, op1);
if (tem)
return tem;
}
/* For the following tests, ensure const0_rtx is op1. */
if (swap_commutative_operands_p (op0, op1)
|| (op0 == const0_rtx && op1 != const0_rtx))
tem = op0, op0 = op1, op1 = tem, code = swap_condition (code);
/* If op0 is a compare, extract the comparison arguments from it. */
if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
return simplify_gen_relational (code, mode, VOIDmode,
XEXP (op0, 0), XEXP (op0, 1));
/* If op0 is a comparison, extract the comparison arguments form it. */
if (COMPARISON_P (op0) && op1 == const0_rtx)
{
if (code == NE)
{
if (GET_MODE (op0) == mode)
return op0;
return simplify_gen_relational (GET_CODE (op0), mode, VOIDmode,
XEXP (op0, 0), XEXP (op0, 1));
}
else if (code == EQ)
{
enum rtx_code new = reversed_comparison_code (op0, NULL_RTX);
if (new != UNKNOWN)
return simplify_gen_relational (new, mode, VOIDmode,
XEXP (op0, 0), XEXP (op0, 1));
}
}
return gen_rtx_fmt_ee (code, mode, op0, op1); return gen_rtx_fmt_ee (code, mode, op0, op1);
} }
...@@ -1201,7 +1165,6 @@ simplify_associative_operation (enum rtx_code code, enum machine_mode mode, ...@@ -1201,7 +1165,6 @@ simplify_associative_operation (enum rtx_code code, enum machine_mode mode,
Don't use this for relational operations such as EQ or LT. Don't use this for relational operations such as EQ or LT.
Use simplify_relational_operation instead. */ Use simplify_relational_operation instead. */
rtx rtx
simplify_binary_operation (enum rtx_code code, enum machine_mode mode, simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
rtx op0, rtx op1) rtx op0, rtx op1)
...@@ -2662,10 +2625,102 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0, ...@@ -2662,10 +2625,102 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0,
} }
/* Like simplify_binary_operation except used for relational operators. /* Like simplify_binary_operation except used for relational operators.
MODE is the mode of the operands, not that of the result. If MODE MODE is the mode of the result. If MODE is VOIDmode, both operands must
is VOIDmode, both operands must also be VOIDmode and we compare the also be VOIDmode.
operands in "infinite precision".
CMP_MODE specifies in which mode the comparison is done in, so it is
the mode of the operands. If CMP_MODE is VOIDmode, it is taken from
the operands or, if both are VOIDmode, the operands are compared in
"infinite precision". */
rtx
simplify_relational_operation (enum rtx_code code, enum machine_mode mode,
enum machine_mode cmp_mode, rtx op0, rtx op1)
{
rtx tem, trueop0, trueop1;
if (cmp_mode == VOIDmode)
cmp_mode = GET_MODE (op0);
if (cmp_mode == VOIDmode)
cmp_mode = GET_MODE (op1);
tem = simplify_const_relational_operation (code, cmp_mode, op0, op1);
if (tem)
{
#ifdef FLOAT_STORE_FLAG_VALUE
if (GET_MODE_CLASS (mode) == MODE_FLOAT)
{
if (tem == const0_rtx)
return CONST0_RTX (mode);
else if (GET_MODE_CLASS (mode) == MODE_FLOAT)
{
REAL_VALUE_TYPE val;
val = FLOAT_STORE_FLAG_VALUE (mode);
return CONST_DOUBLE_FROM_REAL_VALUE (val, mode);
}
}
#endif
return tem;
}
/* For the following tests, ensure const0_rtx is op1. */
if (swap_commutative_operands_p (op0, op1)
|| (op0 == const0_rtx && op1 != const0_rtx))
tem = op0, op0 = op1, op1 = tem, code = swap_condition (code);
/* If op0 is a compare, extract the comparison arguments from it. */
if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
return simplify_relational_operation (code, mode, VOIDmode,
XEXP (op0, 0), XEXP (op0, 1));
if (mode == VOIDmode
|| GET_MODE_CLASS (cmp_mode) == MODE_CC
|| CC0_P (op0))
return NULL_RTX;
trueop0 = avoid_constant_pool_reference (op0);
trueop1 = avoid_constant_pool_reference (op1);
return simplify_relational_operation_1 (code, mode, cmp_mode,
trueop0, trueop1);
}
/* This part of simplify_relational_operation is only used when CMP_MODE
is not in class MODE_CC (i.e. it is a real comparison).
MODE is the mode of the result, while CMP_MODE specifies in which
mode the comparison is done in, so it is the mode of the operands. */
rtx
simplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode,
enum machine_mode cmp_mode, rtx op0, rtx op1)
{
if (GET_CODE (op1) == CONST_INT)
{
if (INTVAL (op1) == 0 && COMPARISON_P (op0))
{
/* If op0 is a comparison, extract the comparison arguments form it. */
if (code == NE)
{
if (GET_MODE (op0) == cmp_mode)
return simplify_rtx (op0);
else
return simplify_gen_relational (GET_CODE (op0), mode, VOIDmode,
XEXP (op0, 0), XEXP (op0, 1));
}
else if (code == EQ)
{
enum rtx_code new = reversed_comparison_code (op0, NULL_RTX);
if (new != UNKNOWN)
return simplify_gen_relational (new, mode, VOIDmode,
XEXP (op0, 0), XEXP (op0, 1));
}
}
}
return NULL_RTX;
}
/* Check if the given comparison (done in the given MODE) is actually a
tautology or a contradiction.
If no simplification is possible, this function returns zero. If no simplification is possible, this function returns zero.
Otherwise, it returns either const_true_rtx or const0_rtx. */ Otherwise, it returns either const_true_rtx or const0_rtx. */
...@@ -2954,36 +3009,6 @@ simplify_const_relational_operation (enum rtx_code code, ...@@ -2954,36 +3009,6 @@ simplify_const_relational_operation (enum rtx_code code,
abort (); abort ();
} }
} }
/* Like simplify_binary_operation except used for relational operators.
MODE is the mode of the result, and CMP_MODE is the mode of the operands.
If CMP_MODE is VOIDmode, both operands must also be VOIDmode and we
compare the operands in "infinite precision". */
rtx
simplify_relational_operation (enum rtx_code code,
enum machine_mode mode ATTRIBUTE_UNUSED,
enum machine_mode cmp_mode, rtx op0, rtx op1)
{
rtx tmp;
tmp = simplify_const_relational_operation (code, cmp_mode, op0, op1);
if (tmp)
{
#ifdef FLOAT_STORE_FLAG_VALUE
if (GET_MODE_CLASS (mode) == MODE_FLOAT)
{
if (tmp == const0_rtx)
return CONST0_RTX (mode);
return CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE (mode),
mode);
}
#endif
return tmp;
}
return NULL_RTX;
}
/* Simplify CODE, an operation with result mode MODE and three operands, /* Simplify CODE, an operation with result mode MODE and three operands,
OP0, OP1, and OP2. OP0_MODE was the mode of OP0 before it became OP0, OP1, and OP2. OP0_MODE was the mode of OP0 before it became
...@@ -3078,20 +3103,6 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode, ...@@ -3078,20 +3103,6 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
? GET_MODE (XEXP (op0, 1)) ? GET_MODE (XEXP (op0, 1))
: GET_MODE (XEXP (op0, 0))); : GET_MODE (XEXP (op0, 0)));
rtx temp; rtx temp;
if (cmp_mode == VOIDmode)
cmp_mode = op0_mode;
temp = simplify_const_relational_operation (GET_CODE (op0),
cmp_mode,
XEXP (op0, 0),
XEXP (op0, 1));
/* See if any simplifications were possible. */
if (temp == const0_rtx)
return op2;
else if (temp == const_true_rtx)
return op1;
else if (temp)
abort ();
/* Look for happy constants in op1 and op2. */ /* Look for happy constants in op1 and op2. */
if (GET_CODE (op1) == CONST_INT && GET_CODE (op2) == CONST_INT) if (GET_CODE (op1) == CONST_INT && GET_CODE (op2) == CONST_INT)
...@@ -3112,7 +3123,23 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode, ...@@ -3112,7 +3123,23 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
else else
break; break;
return gen_rtx_fmt_ee (code, mode, XEXP (op0, 0), XEXP (op0, 1)); return simplify_gen_relational (code, op0_mode, cmp_mode,
XEXP (op0, 0), XEXP (op0, 1));
}
if (cmp_mode == VOIDmode)
cmp_mode = op0_mode;
temp = simplify_relational_operation (GET_CODE (op0), op0_mode,
cmp_mode, XEXP (op0, 0),
XEXP (op0, 1));
/* See if any simplifications were possible. */
if (temp)
{
if (GET_CODE (temp) == CONST_INT)
return temp == const0_rtx ? op2 : op1;
else if (temp)
return gen_rtx_IF_THEN_ELSE (mode, temp, op1, op2);
} }
} }
break; break;
...@@ -3721,7 +3748,6 @@ simplify_rtx (rtx x) ...@@ -3721,7 +3748,6 @@ simplify_rtx (rtx x)
{ {
enum rtx_code code = GET_CODE (x); enum rtx_code code = GET_CODE (x);
enum machine_mode mode = GET_MODE (x); enum machine_mode mode = GET_MODE (x);
rtx temp;
switch (GET_RTX_CLASS (code)) switch (GET_RTX_CLASS (code))
{ {
...@@ -3745,13 +3771,13 @@ simplify_rtx (rtx x) ...@@ -3745,13 +3771,13 @@ simplify_rtx (rtx x)
case RTX_COMPARE: case RTX_COMPARE:
case RTX_COMM_COMPARE: case RTX_COMM_COMPARE:
temp = simplify_relational_operation (code, mode, return simplify_relational_operation (code, mode,
((GET_MODE (XEXP (x, 0)) ((GET_MODE (XEXP (x, 0))
!= VOIDmode) != VOIDmode)
? GET_MODE (XEXP (x, 0)) ? GET_MODE (XEXP (x, 0))
: GET_MODE (XEXP (x, 1))), : GET_MODE (XEXP (x, 1))),
XEXP (x, 0), XEXP (x, 1)); XEXP (x, 0),
return temp; XEXP (x, 1));
case RTX_EXTRA: case RTX_EXTRA:
if (code == SUBREG) if (code == SUBREG)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment