/* Optimize by combining instructions for GNU compiler.
- Copyright (C) 1987, 88, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 92-96, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
static rtx added_links_insn;
-/* This is the value of undobuf.num_undo when we started processing this
- substitution. This will prevent gen_rtx_combine from re-used a piece
- from the previous expression. Doing so can produce circular rtl
- structures. */
-
-static int previous_num_undos;
-
/* Basic block number of the block in which we are performing combines. */
static int this_basic_block;
\f
reg_last_set_invalid[i] is set non-zero 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. */
+/* Record last value assigned to (hard or pseudo) register n. */
static rtx *reg_last_set_value;
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. */
+ is placed in reg_last_set_value. */
static int *reg_last_set_table_tick;
static char *reg_last_set_invalid;
-/* Incremented for each label. */
+/* Incremented for each label. */
static int label_tick;
struct undo
{
+ struct undo *next;
int is_int;
union {rtx r; int i;} old_contents;
union {rtx *r; int *i;} where;
The value of storage is what to pass to obfree.
other_insn is nonzero if we have modified some other insn in the process
- of working on subst_insn. It must be verified too. */
+ of working on subst_insn. It must be verified too.
-#define MAX_UNDO 50
+ previous_undos is the value of undobuf.undos when we started processing
+ this substitution. This will prevent gen_rtx_combine from re-used a piece
+ from the previous expression. Doing so can produce circular rtl
+ structures. */
struct undobuf
{
- int num_undo;
char *storage;
- struct undo undo[MAX_UNDO];
+ struct undo *undos;
+ struct undo *frees;
+ struct undo *previous_undos;
rtx other_insn;
};
the undo table. */
#define SUBST(INTO, NEWVAL) \
- do { rtx _new = (NEWVAL); \
- if (undobuf.num_undo < MAX_UNDO) \
- { \
- undobuf.undo[undobuf.num_undo].is_int = 0; \
- undobuf.undo[undobuf.num_undo].where.r = &INTO; \
- undobuf.undo[undobuf.num_undo].old_contents.r = INTO; \
- INTO = _new; \
- if (undobuf.undo[undobuf.num_undo].old_contents.r != INTO) \
- undobuf.num_undo++; \
- } \
+ do { rtx _new = (NEWVAL); \
+ struct undo *_buf; \
+ \
+ if (undobuf.frees) \
+ _buf = undobuf.frees, undobuf.frees = _buf->next; \
+ else \
+ _buf = (struct undo *) xmalloc (sizeof (struct undo)); \
+ \
+ _buf->is_int = 0; \
+ _buf->where.r = &INTO; \
+ _buf->old_contents.r = INTO; \
+ INTO = _new; \
+ if (_buf->old_contents.r == INTO) \
+ _buf->next = undobuf.frees, undobuf.frees = _buf; \
+ else \
+ _buf->next = undobuf.undos, undobuf.undos = _buf; \
} while (0)
-/* Similar to SUBST, but NEWVAL is an int. INTO will normally be an XINT
- expression.
- Note that substitution for the value of a CONST_INT is not safe. */
+/* Similar to SUBST, but NEWVAL is an int expression. Note that substitution
+ for the value of a HOST_WIDE_INT value (including CONST_INT) is
+ not safe. */
#define SUBST_INT(INTO, NEWVAL) \
- do { if (undobuf.num_undo < MAX_UNDO) \
-{ \
- undobuf.undo[undobuf.num_undo].is_int = 1; \
- undobuf.undo[undobuf.num_undo].where.i = (int *) &INTO; \
- undobuf.undo[undobuf.num_undo].old_contents.i = INTO; \
- INTO = NEWVAL; \
- if (undobuf.undo[undobuf.num_undo].old_contents.i != INTO) \
- undobuf.num_undo++; \
- } \
+ do { struct undo *_buf; \
+ \
+ if (undobuf.frees) \
+ _buf = undobuf.frees, undobuf.frees = _buf->next; \
+ else \
+ _buf = (struct undo *) xmalloc (sizeof (struct undo)); \
+ \
+ _buf->is_int = 1; \
+ _buf->where.i = (int *) &INTO; \
+ _buf->old_contents.i = INTO; \
+ INTO = NEWVAL; \
+ if (_buf->old_contents.i == INTO) \
+ _buf->next = undobuf.frees, undobuf.frees = _buf; \
+ else \
+ _buf->next = undobuf.undos, undobuf.undos = _buf; \
} while (0)
/* Number of times the pseudo being substituted for
static void record_value_for_reg PROTO((rtx, rtx, rtx));
static void record_dead_and_set_regs_1 PROTO((rtx, rtx));
static void record_dead_and_set_regs PROTO((rtx));
-static int get_last_value_validate PROTO((rtx *, int, int));
+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));
static int reg_dead_at_p PROTO((rtx, rtx));
-static void move_deaths PROTO((rtx, int, 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));
combine_merges = 0;
combine_extras = 0;
combine_successes = 0;
- undobuf.num_undo = previous_num_undos = 0;
+ undobuf.undos = undobuf.previous_undos = 0;
combine_max_regno = nregs;
insns. Eliminate this problem by not combining with such an insn.
Also, on some machines we don't want to extend the life of a hard
- register. */
+ register.
+
+ This is the same test done in can_combine except that we don't test
+ if SRC is a CALL operation to permit a hard register with
+ SMALL_REGISTER_CLASSES, and that we have to take all_adjacent
+ into account. */
if (GET_CODE (src) == REG
&& ((REGNO (dest) < FIRST_PSEUDO_REGISTER
/* Don't extend the life of a hard register unless it is
user variable (if we have few registers) or it can't
fit into the desired register (meaning something special
- is going on). */
+ is going on).
+ Also avoid substituting a return register into I3, because
+ reload can't handle a conflict with constraints of other
+ inputs. */
|| (REGNO (src) < FIRST_PSEUDO_REGISTER
&& (! HARD_REGNO_MODE_OK (REGNO (src), GET_MODE (src))
#ifdef SMALL_REGISTER_CLASSES
- || ! REG_USERVAR_P (src)
+ || (SMALL_REGISTER_CLASSES
+ && ((! all_adjacent && ! REG_USERVAR_P (src))
+ || (FUNCTION_VALUE_REGNO_P (REGNO (src))
+ && ! REG_USERVAR_P (src))))
#endif
))))
return 0;
|| (i1dest && reg_overlap_mentioned_p (i1dest, inner_dest))))
/* This is the same test done in can_combine_p except that we
allow a hard register with SMALL_REGISTER_CLASSES if SRC is a
- CALL operation. */
+ CALL operation.
+ Moreover, we can't test all_adjacent; we don't have to, since
+ this instruction will stay in place, thus we are not considering
+ to increase the lifetime of INNER_DEST. */
|| (GET_CODE (inner_dest) == REG
&& REGNO (inner_dest) < FIRST_PSEUDO_REGISTER
&& (! HARD_REGNO_MODE_OK (REGNO (inner_dest),
GET_MODE (inner_dest))
#ifdef SMALL_REGISTER_CLASSES
- || (GET_CODE (src) != CALL && ! REG_USERVAR_P (inner_dest))
+ || (SMALL_REGISTER_CLASSES
+ && GET_CODE (src) != CALL && ! REG_USERVAR_P (inner_dest)
+ && FUNCTION_VALUE_REGNO_P (REGNO (inner_dest)))
#endif
))
|| (i1_not_in_src && reg_overlap_mentioned_p (i1dest, src)))
combine_attempts++;
- undobuf.num_undo = previous_num_undos = 0;
+ undobuf.undos = undobuf.previous_undos = 0;
undobuf.other_insn = 0;
/* Save the current high-water-mark so we can free storage if we didn't
&& GET_CODE (SET_SRC (PATTERN (i3))) == REG
&& REGNO (SET_SRC (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER
#ifdef SMALL_REGISTER_CLASSES
- && (GET_CODE (SET_DEST (PATTERN (i3))) != REG
+ && (! SMALL_REGISTER_CLASSES
+ || GET_CODE (SET_DEST (PATTERN (i3))) != REG
|| REGNO (SET_DEST (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER
|| REG_USERVAR_P (SET_DEST (PATTERN (i3))))
#endif
i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0);
}
- previous_num_undos = undobuf.num_undo;
+ undobuf.previous_undos = undobuf.undos;
}
#ifndef HAVE_cc0
subst_low_cuid = INSN_CUID (i2);
newpat = subst (PATTERN (i3), i2dest, i2src, 0,
! i1_feeds_i3 && i1dest_in_i1src);
- previous_num_undos = undobuf.num_undo;
+ undobuf.previous_undos = undobuf.undos;
/* Record whether i2's body now appears within i3's body. */
i2_is_used = n_occurrences;
{
/* Before we can do this substitution, we must redo the test done
above (see detailed comments there) that ensures that I1DEST
- isn't mentioned in any SETs in NEWPAT that are field assignments. */
+ isn't mentioned in any SETs in NEWPAT that are field assignments. */
if (! combinable_i3pat (NULL_RTX, &newpat, i1dest, NULL_RTX,
0, NULL_PTR))
n_occurrences = 0;
subst_low_cuid = INSN_CUID (i1);
newpat = subst (newpat, i1dest, i1src, 0, 0);
- previous_num_undos = undobuf.num_undo;
+ undobuf.previous_undos = undobuf.undos;
}
/* Fail if an autoincrement side-effect has been duplicated. Be careful
rtvec old = XVEC (newpat, 0);
total_sets = XVECLEN (newpat, 0) + added_sets_1 + added_sets_2;
newpat = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (total_sets));
- bcopy ((char *) &old->elem[0], (char *) &XVECEXP (newpat, 0, 0),
+ bcopy ((char *) &old->elem[0], (char *) XVEC (newpat, 0)->elem,
sizeof (old->elem[0]) * old->num_elem);
}
else
|| GET_CODE (new_i3_dest) == SUBREG)
new_i3_dest = XEXP (new_i3_dest, 0);
+ while (GET_CODE (new_i2_dest) == ZERO_EXTRACT
+ || GET_CODE (new_i2_dest) == STRICT_LOW_PART
+ || GET_CODE (new_i2_dest) == SUBREG)
+ new_i2_dest = XEXP (new_i2_dest, 0);
+
if (GET_CODE (new_i3_dest) == REG
&& GET_CODE (new_i2_dest) == REG
&& REGNO (new_i3_dest) == REGNO (new_i2_dest))
- reg_n_sets[REGNO (SET_DEST (i2set))]++;
+ reg_n_sets[REGNO (new_i2_dest)]++;
}
}
}
/* Get death notes for everything that is now used in either I3 or
- I2 and used to die in a previous insn. */
+ I2 and used to die in a previous insn. If we built two new
+ patterns, move from I1 to I2 then I2 to I3 so that we get the
+ proper movement on registers that I2 modifies. */
- move_deaths (newpat, i1 ? INSN_CUID (i1) : INSN_CUID (i2), i3, &midnotes);
if (newi2pat)
- move_deaths (newi2pat, INSN_CUID (i1), i2, &midnotes);
+ {
+ move_deaths (newi2pat, NULL_RTX, INSN_CUID (i1), i2, &midnotes);
+ move_deaths (newpat, newi2pat, INSN_CUID (i1), i3, &midnotes);
+ }
+ else
+ move_deaths (newpat, NULL_RTX, i1 ? INSN_CUID (i1) : INSN_CUID (i2),
+ i3, &midnotes);
/* Distribute all the LOG_LINKS and REG_NOTES from I1, I2, and I3. */
if (i3notes)
/* If the reg formerly set in I2 died only once and that was in I3,
zero its use count so it won't make `reload' do any work. */
- if (! added_sets_2 && newi2pat == 0 && ! i2dest_in_i2src)
+ if (! added_sets_2
+ && (newi2pat == 0 || ! reg_mentioned_p (i2dest, newi2pat))
+ && ! i2dest_in_i2src)
{
regno = REGNO (i2dest);
reg_n_sets[regno]--;
static void
undo_all ()
{
- register int i;
- if (undobuf.num_undo > MAX_UNDO)
- undobuf.num_undo = MAX_UNDO;
- for (i = undobuf.num_undo - 1; i >= 0; i--)
+ struct undo *undo, *next;
+
+ for (undo = undobuf.undos; undo; undo = next)
{
- if (undobuf.undo[i].is_int)
- *undobuf.undo[i].where.i = undobuf.undo[i].old_contents.i;
+ next = undo->next;
+ if (undo->is_int)
+ *undo->where.i = undo->old_contents.i;
else
- *undobuf.undo[i].where.r = undobuf.undo[i].old_contents.r;
-
+ *undo->where.r = undo->old_contents.r;
+
+ undo->next = undobuf.frees;
+ undobuf.frees = undo;
}
obfree (undobuf.storage);
- undobuf.num_undo = 0;
+ undobuf.undos = undobuf.previous_undos = 0;
/* Clear this here, so that subsequent get_last_value calls are not
affected. */
}
break;
+ case NE:
+ /* if STORE_FLAG_VALUE is -1, this is (NE X 0) and only one bit of X
+ is known to be on, this can be converted into a NEG of a shift. */
+ if (STORE_FLAG_VALUE == -1 && XEXP (SET_SRC (x), 1) == const0_rtx
+ && GET_MODE (SET_SRC (x)) == GET_MODE (XEXP (SET_SRC (x), 0))
+ && 1 <= (pos = exact_log2
+ (nonzero_bits (XEXP (SET_SRC (x), 0),
+ GET_MODE (XEXP (SET_SRC (x), 0))))))
+ {
+ enum machine_mode mode = GET_MODE (XEXP (SET_SRC (x), 0));
+
+ SUBST (SET_SRC (x),
+ gen_rtx_combine (NEG, mode,
+ gen_rtx_combine (LSHIFTRT, mode,
+ XEXP (SET_SRC (x), 0),
+ GEN_INT (pos))));
+
+ split = find_split_point (&SET_SRC (x), insn);
+ if (split && split != &SET_SRC (x))
+ return split;
+ }
+ break;
+
case SIGN_EXTEND:
inner = XEXP (SET_SRC (x), 0);
+
+ /* We can't optimize if either mode is a partial integer
+ mode as we don't know how many bits are significant
+ in those modes. */
+ if (GET_MODE_CLASS (GET_MODE (inner)) == MODE_PARTIAL_INT
+ || GET_MODE_CLASS (GET_MODE (SET_SRC (x))) == MODE_PARTIAL_INT)
+ break;
+
pos = 0;
len = GET_MODE_BITSIZE (GET_MODE (inner));
unsignedp = 0;
split = find_split_point (&XEXP (x, 2), insn);
if (split)
return split;
- /* ... fall through ... */
+ /* ... fall through ... */
case '2':
case 'c':
case '<':
split = find_split_point (&XEXP (x, 1), insn);
if (split)
return split;
- /* ... fall through ... */
+ /* ... fall through ... */
case '1':
/* Some machines have (and (shift ...) ...) insns. If X is not
an AND, but XEXP (X, 0) is, use it as our split point. */
|| GET_CODE (SET_DEST (x)) == PC))
fmt = "ie";
- /* Get the mode of operand 0 in case X is now a SIGN_EXTEND of a constant. */
+ /* Get the mode of operand 0 in case X is now a SIGN_EXTEND of a
+ constant. */
if (fmt[0] == 'e')
op0_mode = GET_MODE (XEXP (x, 0));
rtx cond, true, false;
cond = if_then_else_cond (x, &true, &false);
- if (cond != 0)
+ if (cond != 0
+ /* If everything is a comparison, what we have is highly unlikely
+ to be simpler, so don't use it. */
+ && ! (GET_RTX_CLASS (code) == '<'
+ && (GET_RTX_CLASS (GET_CODE (true)) == '<'
+ || GET_RTX_CLASS (GET_CODE (false)) == '<')))
{
rtx cop1 = const0_rtx;
enum rtx_code cond_code = simplify_comparison (NE, &cond, &cop1);
if (CONSTANT_P (SUBREG_REG (x)) && op0_mode != VOIDmode
&& GET_MODE_SIZE (mode) == UNITS_PER_WORD
- && GET_MODE_SIZE (op0_mode) < UNITS_PER_WORD
+ && GET_MODE_SIZE (op0_mode) > UNITS_PER_WORD
&& GET_MODE_CLASS (mode) == MODE_INT)
{
temp = operand_subword (SUBREG_REG (x), SUBREG_WORD (x),
/* If we want a subreg of a constant, at offset 0,
take the low bits. On a little-endian machine, that's
always valid. On a big-endian machine, it's valid
- only if the constant's mode fits in one word. */
- if (CONSTANT_P (SUBREG_REG (x)) && subreg_lowpart_p (x)
+ only if the constant's mode fits in one word. Note that we
+ cannot use subreg_lowpart_p since SUBREG_REG may be VOIDmode. */
+ if (CONSTANT_P (SUBREG_REG (x))
+ && ((GET_MODE_SIZE (op0_mode) <= UNITS_PER_WORD
+ || ! WORDS_BIG_ENDIAN)
+ ? SUBREG_WORD (x) == 0
+ : (SUBREG_WORD (x)
+ == ((GET_MODE_SIZE (op0_mode)
+ - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
+ / UNITS_PER_WORD)))
&& GET_MODE_SIZE (mode) <= GET_MODE_SIZE (op0_mode)
&& (! WORDS_BIG_ENDIAN
|| GET_MODE_BITSIZE (op0_mode) <= BITS_PER_WORD))
return gen_lowpart_for_combine (mode, x);
}
-#if STORE_FLAG_VALUE == -1
- /* (not (comparison foo bar)) can be done by reversing the comparison
- code if valid. */
- if (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
+ /* If STORE_FLAG_VALUE is -1, (not (comparison foo bar)) can be done by
+ reversing the comparison code if valid. */
+ if (STORE_FLAG_VALUE == -1
+ && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
&& reversible_comparison_p (XEXP (x, 0)))
return gen_rtx_combine (reverse_condition (GET_CODE (XEXP (x, 0))),
mode, XEXP (XEXP (x, 0), 0),
XEXP (XEXP (x, 0), 1));
/* (ashiftrt foo C) where C is the number of bits in FOO minus 1
- is (lt foo (const_int 0)), so we can perform the above
- simplification. */
+ is (lt foo (const_int 0)) if STORE_FLAG_VALUE is -1, so we can
+ perform the above simplification. */
- if (XEXP (x, 1) == const1_rtx
+ if (STORE_FLAG_VALUE == -1
+ && XEXP (x, 1) == const1_rtx
&& GET_CODE (XEXP (x, 0)) == ASHIFTRT
&& 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);
-#endif
/* Apply De Morgan's laws to reduce number of patterns for machines
with negating logical insns (and-not, nand, etc.). If result has
/* (neg (minus X Y)) can become (minus Y X). */
if (GET_CODE (XEXP (x, 0)) == MINUS
&& (! FLOAT_MODE_P (mode)
- /* x-y != -(y-x) with IEEE floating point. */
+ /* x-y != -(y-x) with IEEE floating point. */
|| TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
|| flag_fast_math))
return gen_binary (MINUS, mode, XEXP (XEXP (x, 0), 1),
XEXP (XEXP (x, 0), 0));
- /* (neg (xor A 1)) is (plus A -1) if A is known to be either 0 or 1. */
+ /* (neg (xor A 1)) is (plus A -1) if A is known to be either 0 or 1. */
if (GET_CODE (XEXP (x, 0)) == XOR && XEXP (XEXP (x, 0), 1) == const1_rtx
&& nonzero_bits (XEXP (XEXP (x, 0), 0), mode) == 1)
return gen_binary (PLUS, mode, XEXP (XEXP (x, 0), 0), constm1_rtx);
break;
case TRUNCATE:
+ /* We can't handle truncation to a partial integer mode here
+ because we don't know the real bitsize of the partial
+ integer mode. */
+ if (GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
+ break;
+
if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
SUBST (XEXP (x, 0),
force_to_mode (XEXP (x, 0), GET_MODE (XEXP (x, 0)),
GET_MODE_MASK (mode), NULL_RTX, 0));
+
+ /* (truncate:SI ({sign,zero}_extend:DI foo:SI)) == foo:SI. */
+ if ((GET_CODE (XEXP (x, 0)) == SIGN_EXTEND
+ || GET_CODE (XEXP (x, 0)) == ZERO_EXTEND)
+ && GET_MODE (XEXP (XEXP (x, 0), 0)) == mode)
+ return XEXP (XEXP (x, 0), 0);
+
+ /* (truncate:SI (OP:DI ({sign,zero}_extend:DI foo:SI))) is
+ (OP:SI foo:SI) if OP is NEG or ABS. */
+ if ((GET_CODE (XEXP (x, 0)) == ABS
+ || GET_CODE (XEXP (x, 0)) == NEG)
+ && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SIGN_EXTEND
+ || GET_CODE (XEXP (XEXP (x, 0), 0)) == ZERO_EXTEND)
+ && GET_MODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == mode)
+ return gen_unary (GET_CODE (XEXP (x, 0)), mode, mode,
+ XEXP (XEXP (XEXP (x, 0), 0), 0));
+
+ /* (truncate:SI (subreg:DI (truncate:SI X) 0)) is
+ (truncate:SI x). */
+ if (GET_CODE (XEXP (x, 0)) == SUBREG
+ && GET_CODE (SUBREG_REG (XEXP (x, 0))) == TRUNCATE
+ && subreg_lowpart_p (XEXP (x, 0)))
+ return SUBREG_REG (XEXP (x, 0));
+
+ /* If we know that the value is already truncated, we can
+ replace the TRUNCATE with a SUBREG. */
+ if (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) <= HOST_BITS_PER_WIDE_INT
+ && (nonzero_bits (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
+ &~ GET_MODE_MASK (mode)) == 0)
+ return gen_lowpart_for_combine (mode, XEXP (x, 0));
+
+ /* A truncate of a comparison can be replaced with a subreg if
+ STORE_FLAG_VALUE permits. This is like the previous test,
+ but it works even if the comparison is done in a mode larger
+ than HOST_BITS_PER_WIDE_INT. */
+ if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+ && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
+ && ((HOST_WIDE_INT) STORE_FLAG_VALUE &~ GET_MODE_MASK (mode)) == 0)
+ return gen_lowpart_for_combine (mode, XEXP (x, 0));
+
+ /* Similarly, a truncate of a register whose value is a
+ comparison can be replaced with a subreg if STORE_FLAG_VALUE
+ permits. */
+ if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+ && ((HOST_WIDE_INT) STORE_FLAG_VALUE &~ GET_MODE_MASK (mode)) == 0
+ && (temp = get_last_value (XEXP (x, 0)))
+ && GET_RTX_CLASS (GET_CODE (temp)) == '<')
+ return gen_lowpart_for_combine (mode, XEXP (x, 0));
+
break;
case FLOAT_TRUNCATE:
break;
case MINUS:
-#if STORE_FLAG_VALUE == 1
- /* (minus 1 (comparison foo bar)) can be done by reversing the comparison
- code if valid. */
- if (XEXP (x, 0) == const1_rtx
+ /* If STORE_FLAG_VALUE is 1, (minus 1 (comparison foo bar)) can be done
+ by reversing the comparison code if valid. */
+ if (STORE_FLAG_VALUE == 1
+ && XEXP (x, 0) == const1_rtx
&& GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<'
&& reversible_comparison_p (XEXP (x, 1)))
return gen_binary (reverse_condition (GET_CODE (XEXP (x, 1))),
mode, XEXP (XEXP (x, 1), 0),
XEXP (XEXP (x, 1), 1));
-#endif
/* (minus <foo> (and <foo> (const_int -pow2))) becomes
(and <foo> (const_int pow2-1)) */
/* Simplify our comparison, if possible. */
new_code = simplify_comparison (code, &op0, &op1);
-#if STORE_FLAG_VALUE == 1
/* If STORE_FLAG_VALUE is 1, we can convert (ne x 0) to simply X
if only the low-order bit is possibly nonzero in X (such as when
X is a ZERO_EXTRACT of one bit). Similarly, we can convert EQ to
ZERO_EXTRACT is indeed appropriate, it will be placed back by
the call to make_compound_operation in the SET case. */
- if (new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
- && op1 == const0_rtx
- && nonzero_bits (op0, mode) == 1)
+ if (STORE_FLAG_VALUE == 1
+ && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
+ && op1 == const0_rtx && nonzero_bits (op0, mode) == 1)
return gen_lowpart_for_combine (mode,
expand_compound_operation (op0));
- else if (new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
+ else if (STORE_FLAG_VALUE == 1
+ && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& (num_sign_bit_copies (op0, mode)
== GET_MODE_BITSIZE (mode)))
gen_lowpart_for_combine (mode, op0));
}
- else if (new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
+ else if (STORE_FLAG_VALUE == 1
+ && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& nonzero_bits (op0, mode) == 1)
{
const1_rtx);
}
- else if (new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
+ else if (STORE_FLAG_VALUE == 1
+ && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& (num_sign_bit_copies (op0, mode)
== GET_MODE_BITSIZE (mode)))
op0 = expand_compound_operation (op0);
return plus_constant (gen_lowpart_for_combine (mode, op0), 1);
}
-#endif
-#if STORE_FLAG_VALUE == -1
/* If STORE_FLAG_VALUE is -1, we have cases similar to
those above. */
- if (new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
+ if (STORE_FLAG_VALUE == -1
+ && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& (num_sign_bit_copies (op0, mode)
== GET_MODE_BITSIZE (mode)))
return gen_lowpart_for_combine (mode,
expand_compound_operation (op0));
- else if (new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
+ else if (STORE_FLAG_VALUE == -1
+ && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& nonzero_bits (op0, mode) == 1)
{
gen_lowpart_for_combine (mode, op0));
}
- else if (new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
+ else if (STORE_FLAG_VALUE == -1
+ && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& (num_sign_bit_copies (op0, mode)
== GET_MODE_BITSIZE (mode)))
}
/* If X is 0/1, (eq X 0) is X-1. */
- else if (new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
+ else if (STORE_FLAG_VALUE == -1
+ && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& nonzero_bits (op0, mode) == 1)
{
op0 = expand_compound_operation (op0);
return plus_constant (gen_lowpart_for_combine (mode, op0), -1);
}
-#endif
/* If STORE_FLAG_VALUE says to just test the sign bit and X has just
one bit that might be nonzero, we can convert (ne x 0) to
going to test the sign bit. */
if (new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
- && (STORE_FLAG_VALUE
+ && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
== (HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))
&& op1 == const0_rtx
&& mode == GET_MODE (op0)
case SIGN_EXTRACT:
case ZERO_EXTEND:
case SIGN_EXTEND:
- /* If we are processing SET_DEST, we are done. */
+ /* If we are processing SET_DEST, we are done. */
if (in_dest)
return x;
rtx temp;
int i;
- /* Simplify storing of the truth value. */
+ /* Simplify storing of the truth value. */
if (comparison_p && true == const_true_rtx && false == const0_rtx)
return gen_binary (true_code, mode, XEXP (cond, 0), XEXP (cond, 1));
- /* Also when the truth value has to be reversed. */
+ /* Also when the truth value has to be reversed. */
if (comparison_p && reversible_comparison_p (cond)
&& true == const0_rtx && false == const_true_rtx)
return gen_binary (reverse_condition (true_code),
temp = true, true = false, false = temp, cond = XEXP (x, 0);
- /* It is possible that the conditional has been simplified out. */
+ /* It is possible that the conditional has been simplified out. */
true_code = GET_CODE (cond);
comparison_p = GET_RTX_CLASS (true_code) == '<';
}
return gen_binary (UMIN, mode, true, false);
}
-#if STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1
-
/* If we have (if_then_else COND (OP Z C1) Z) and OP is an identity when its
second operand is zero, this can be done as (OP Z (mult COND C2)) where
C2 = C1 * STORE_FLAG_VALUE. Similarly if OP has an outer ZERO_EXTEND or
SIGN_EXTEND as long as Z is already extended (so we don't destroy it).
We can do this kind of thing in some cases when STORE_FLAG_VALUE is
- neither of the above, but it isn't worth checking for. */
+ neither 1 or -1, but it isn't worth checking for. */
- if (comparison_p && mode != VOIDmode && ! side_effects_p (x))
+ if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
+ && comparison_p && mode != VOIDmode && ! side_effects_p (x))
{
rtx t = make_compound_operation (true, SET);
rtx f = make_compound_operation (false, SET);
c1 = XEXP (t, 1), op = GET_CODE (t), z = f;
/* If an identity-zero op is commutative, check whether there
- would be a match if we swapped the operands. */
+ would be a match if we swapped the operands. */
else if ((GET_CODE (t) == PLUS || GET_CODE (t) == IOR
|| GET_CODE (t) == XOR)
&& rtx_equal_p (XEXP (t, 1), f))
return temp;
}
}
-#endif
/* If we have (if_then_else (ne A 0) C1 0) and either A is known to be 0 or
1 and C1 is a single bit or A is known to be 0 or -1 and C1 is the
#ifdef LOAD_EXTEND_OP
/* If we have (set FOO (subreg:M (mem:N BAR) 0)) with M wider than N, this
would require a paradoxical subreg. Replace the subreg with a
- zero_extend to avoid the reload that would otherwise be required. */
+ zero_extend to avoid the reload that would otherwise be required. */
if (GET_CODE (src) == SUBREG && subreg_lowpart_p (src)
&& LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))) != NIL
/* If we have (ior (and (X C1) C2)) and the next restart would be
the last, simplify this by making C1 as small as possible
- and then exit. */
+ and then exit. */
if (last
&& GET_CODE (x) == IOR && GET_CODE (op0) == AND
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
gen_unary (NOT, mode, mode, XEXP (op0, 1)),
op1);
-#if STORE_FLAG_VALUE == 1
/* (xor (comparison foo bar) (const_int 1)) can become the reversed
- comparison. */
- if (op1 == const1_rtx
+ comparison if STORE_FLAG_VALUE is 1. */
+ if (STORE_FLAG_VALUE == 1
+ && op1 == const1_rtx
&& GET_RTX_CLASS (GET_CODE (op0)) == '<'
&& reversible_comparison_p (op0))
return gen_rtx_combine (reverse_condition (GET_CODE (op0)),
/* (lshiftrt foo C) where C is the number of bits in FOO minus 1
is (lt foo (const_int 0)), so we can perform the above
- simplification. */
+ simplification if STORE_FLAG_VALUE is 1. */
- if (op1 == const1_rtx
+ if (STORE_FLAG_VALUE == 1
+ && op1 == const1_rtx
&& GET_CODE (op0) == LSHIFTRT
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
&& INTVAL (XEXP (op0, 1)) == GET_MODE_BITSIZE (mode) - 1)
return gen_rtx_combine (GE, mode, XEXP (op0, 0), const0_rtx);
-#endif
/* (xor (comparison foo bar) (const_int sign-bit))
when STORE_FLAG_VALUE is the sign bit. */
if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
- && (STORE_FLAG_VALUE
+ && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
== (HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))
&& op1 == const_true_rtx
&& GET_RTX_CLASS (GET_CODE (op0)) == '<'
return x;
}
+ /* We can optimize some special cases of ZERO_EXTEND. */
+ if (GET_CODE (x) == ZERO_EXTEND)
+ {
+ /* (zero_extend:DI (truncate:SI foo:DI)) is just foo:DI if we
+ know that the last value didn't have any inappropriate bits
+ set. */
+ if (GET_CODE (XEXP (x, 0)) == TRUNCATE
+ && GET_MODE (XEXP (XEXP (x, 0), 0)) == GET_MODE (x)
+ && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
+ && (nonzero_bits (XEXP (XEXP (x, 0), 0), GET_MODE (x))
+ & ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
+ return XEXP (XEXP (x, 0), 0);
+
+ /* Likewise for (zero_extend:DI (subreg:SI foo:DI 0)). */
+ if (GET_CODE (XEXP (x, 0)) == SUBREG
+ && GET_MODE (SUBREG_REG (XEXP (x, 0))) == GET_MODE (x)
+ && subreg_lowpart_p (XEXP (x, 0))
+ && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
+ && (nonzero_bits (SUBREG_REG (XEXP (x, 0)), GET_MODE (x))
+ & ~ GET_MODE_MASK (GET_MODE (SUBREG_REG (x)))) == 0)
+ return SUBREG_REG (XEXP (x, 0));
+
+ /* (zero_extend:DI (truncate:SI foo:DI)) is just foo:DI when foo
+ is a comparison and STORE_FLAG_VALUE permits. This is like
+ the first case, but it works even when GET_MODE (x) is larger
+ than HOST_WIDE_INT. */
+ if (GET_CODE (XEXP (x, 0)) == TRUNCATE
+ && GET_MODE (XEXP (XEXP (x, 0), 0)) == GET_MODE (x)
+ && GET_RTX_CLASS (GET_CODE (XEXP (XEXP (x, 0), 0))) == '<'
+ && (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
+ <= HOST_BITS_PER_WIDE_INT)
+ && ((HOST_WIDE_INT) STORE_FLAG_VALUE
+ & ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
+ return XEXP (XEXP (x, 0), 0);
+
+ /* Likewise for (zero_extend:DI (subreg:SI foo:DI 0)). */
+ if (GET_CODE (XEXP (x, 0)) == SUBREG
+ && GET_MODE (SUBREG_REG (XEXP (x, 0))) == GET_MODE (x)
+ && subreg_lowpart_p (XEXP (x, 0))
+ && GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 0)))) == '<'
+ && (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
+ <= HOST_BITS_PER_WIDE_INT)
+ && ((HOST_WIDE_INT) STORE_FLAG_VALUE
+ & ~ 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
shift is a left shift of BITSIZE - POS - LEN bits. The outer
shift is a right shift of BITSIZE - LEN bits. It is arithmetic or
rtx x;
{
rtx inner;
- rtx pos; /* Always counts from low bit. */
+ rtx pos; /* Always counts from low bit. */
int len;
rtx mask;
enum machine_mode compute_mode;
If it is mixed, we must adjust. */
/* If bytes are big endian and we had a paradoxical SUBREG, we must
- adjust OFFSET to compensate. */
+ adjust OFFSET to compensate. */
if (BYTES_BIG_ENDIAN
&& ! spans_byte
&& GET_MODE_SIZE (inner_mode) < GET_MODE_SIZE (is_mode))
/* Make POS_RTX unless we already have it and it is correct. If we don't
have a POS_RTX but we do have an ORIG_POS_RTX, the latter must
- be a CONST_INT. */
+ be a CONST_INT. */
if (pos_rtx == 0 && orig_pos_rtx != 0 && INTVAL (orig_pos_rtx) == pos)
pos_rtx = orig_pos_rtx;
break;
}
- /* ... fall through ... */
+ /* ... fall through ... */
case ASHIFTRT:
lhs = XEXP (x, 0);
{
case CLOBBER:
/* If X is a (clobber (const_int)), return it since we know we are
- generating something that won't match. */
+ generating something that won't match. */
return x;
case USE:
mode, mask, reg, next_select);
}
- /* ... fall through ... */
+ /* ... fall through ... */
case MINUS:
case MULT:
if (GET_MODE_BITSIZE (GET_MODE (x)) > HOST_BITS_PER_WIDE_INT)
{
- nonzero = ~(HOST_WIDE_INT)0;
+ nonzero = ~ (HOST_WIDE_INT) 0;
/* GET_MODE_BITSIZE (GET_MODE (x)) - INTVAL (XEXP (x, 1))
is the number of bits a full-width mask would have set.
case NE:
/* (and (ne FOO 0) CONST) can be (and FOO CONST) if CONST is included
- in STORE_FLAG_VALUE and FOO has no bits that might be nonzero not
- in CONST. */
- if ((mask & ~ STORE_FLAG_VALUE) == 0 && XEXP (x, 0) == const0_rtx
- && (nonzero_bits (XEXP (x, 0), mode) & ~ mask) == 0)
+ in STORE_FLAG_VALUE and FOO has a single bit that might be nonzero,
+ which is equal to STORE_FLAG_VALUE. */
+ if ((mask & ~ STORE_FLAG_VALUE) == 0 && XEXP (x, 1) == const0_rtx
+ && exact_log2 (nonzero_bits (XEXP (x, 0), mode)) >= 0
+ && nonzero_bits (XEXP (x, 0), mode) == STORE_FLAG_VALUE)
return force_to_mode (XEXP (x, 0), mode, mask, reg, next_select);
break;
if ((cond0 != 0 || cond1 != 0)
&& ! (cond0 != 0 && cond1 != 0 && ! rtx_equal_p (cond0, cond1)))
{
+ /* If if_then_else_cond returned zero, then true/false are the
+ same rtl. We must copy one of them to prevent invalid rtl
+ sharing. */
+ if (cond0 == 0)
+ true0 = copy_rtx (true0);
+ else if (cond1 == 0)
+ true1 = copy_rtx (true1);
+
*ptrue = gen_binary (code, mode, true0, true1);
*pfalse = gen_binary (code, mode, false0, false1);
return cond0 ? cond0 : cond1;
}
-#if STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1
-
/* See if we have PLUS, IOR, XOR, MINUS or UMAX, where one of the
- operands is zero when the other is non-zero, and vice-versa. */
+ operands is zero when the other is non-zero, and vice-versa,
+ and STORE_FLAG_VALUE is 1 or -1. */
- if ((code == PLUS || code == IOR || code == XOR || code == MINUS
+ if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
+ && (code == PLUS || code == IOR || code == XOR || code == MINUS
|| code == UMAX)
&& GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (x, 1)) == MULT)
{
/* Similarly for MULT, AND and UMIN, execpt that for these the result
is always zero. */
- if ((code == MULT || code == AND || code == UMIN)
+ if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
+ && (code == MULT || code == AND || code == UMIN)
&& GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (x, 1)) == MULT)
{
cond0 = XEXP (XEXP (x, 0), 0);
return cond0;
}
}
-#endif
}
else if (code == IF_THEN_ELSE)
last_x = get_last_value (x);
last_y = get_last_value (y);
- return ((last_x != 0 && rtx_equal_for_field_assignment_p (last_x, y))
- || (last_y != 0 && rtx_equal_for_field_assignment_p (x, last_y))
+ return ((last_x != 0
+ && GET_CODE (last_x) != CLOBBER
+ && rtx_equal_for_field_assignment_p (last_x, y))
+ || (last_y != 0
+ && GET_CODE (last_y) != CLOBBER
+ && rtx_equal_for_field_assignment_p (x, last_y))
|| (last_x != 0 && last_y != 0
+ && GET_CODE (last_x) != CLOBBER
+ && GET_CODE (last_y) != CLOBBER
&& rtx_equal_for_field_assignment_p (last_x, last_y)));
}
\f
lhs = XEXP (x, 0), rhs = XEXP (x, 1);
- /* If either operand is a primitive we can't do anything, so get out fast. */
+ /* If either operand is a primitive we can't do anything, so get out
+ fast. */
if (GET_RTX_CLASS (GET_CODE (lhs)) == 'o'
|| GET_RTX_CLASS (GET_CODE (rhs)) == 'o')
return x;
else
varop = gen_lowpart_for_combine (mode, varop);
- /* If we can't make the SUBREG, try to return what we were given. */
+ /* If we can't make the SUBREG, try to return what we were given. */
if (GET_CODE (varop) == CLOBBER)
return x ? x : varop;
return x;
}
\f
+/* We let num_sign_bit_copies recur into nonzero_bits as that is useful.
+ We don't let nonzero_bits recur into num_sign_bit_copies, because that
+ is less useful. We can't allow both, because that results in exponential
+ run time recusion. There is a nullstone testcase that triggered
+ this. This macro avoids accidental uses of num_sign_bit_copies. */
+#define num_sign_bit_copies()
+
/* Given an expression, X, compute which bits in X can be non-zero.
We don't care about bits outside of those defined in MODE.
break;
case NEG:
+#if 0
+ /* Disabled to avoid exponential mutual recursion between nonzero_bits
+ and num_sign_bit_copies. */
if (num_sign_bit_copies (XEXP (x, 0), GET_MODE (x))
== GET_MODE_BITSIZE (GET_MODE (x)))
nonzero = 1;
+#endif
if (GET_MODE_SIZE (GET_MODE (x)) < mode_width)
nonzero |= (GET_MODE_MASK (mode) & ~ GET_MODE_MASK (GET_MODE (x)));
break;
case ABS:
+#if 0
+ /* Disabled to avoid exponential mutual recursion between nonzero_bits
+ and num_sign_bit_copies. */
if (num_sign_bit_copies (XEXP (x, 0), GET_MODE (x))
== GET_MODE_BITSIZE (GET_MODE (x)))
nonzero = 1;
+#endif
break;
case TRUNCATE:
return nonzero;
}
+
+/* See the macro definition above. */
+#undef num_sign_bit_copies
\f
/* Return the number of bits at the high-order end of X that are known to
be equal to the sign bit. X will be used in mode MODE; if MODE is
bitwidth = GET_MODE_BITSIZE (mode);
- /* For a smaller object, just ignore the high bits. */
+ /* For a smaller object, just ignore the high bits. */
if (bitwidth < GET_MODE_BITSIZE (GET_MODE (x)))
return MAX (1, (num_sign_bit_copies (x, GET_MODE (x))
- (GET_MODE_BITSIZE (GET_MODE (x)) - bitwidth)));
return MAX (bitwidth - GET_MODE_BITSIZE (GET_MODE (x)) + 1,
num_sign_bit_copies (SUBREG_REG (x), mode));
- /* For a smaller object, just ignore the high bits. */
+ /* For a smaller object, just ignore the high bits. */
if (bitwidth <= GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))))
{
num0 = num_sign_bit_copies (SUBREG_REG (x), VOIDmode);
+ num_sign_bit_copies (XEXP (x, 0), VOIDmode));
case TRUNCATE:
- /* For a smaller object, just ignore the high bits. */
+ /* For a smaller object, just ignore the high bits. */
num0 = num_sign_bit_copies (XEXP (x, 0), VOIDmode);
return MAX (1, (num0 - (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
- bitwidth)));
num1 = num_sign_bit_copies (XEXP (x, 2), mode);
return MIN (num0, num1);
-#if STORE_FLAG_VALUE == -1
case EQ: case NE: case GE: case GT: case LE: case LT:
case GEU: case GTU: case LEU: case LTU:
- return bitwidth;
-#endif
+ if (STORE_FLAG_VALUE == -1)
+ return bitwidth;
}
/* If we haven't been able to figure it out by one of the above rules,
/* We need to determine what mode we will do the shift in. If the
shift is a right shift or a ROTATE, we must always do it in the mode
it was originally done in. Otherwise, we can do it in MODE, the
- widest mode encountered. */
+ widest mode encountered. */
shift_mode
= (code == ASHIFTRT || code == LSHIFTRT || code == ROTATE
? result_mode : mode);
/* Negative counts are invalid and should not have been made (a
programmer-specified negative count should have been handled
- above). */
+ above). */
else if (count < 0)
abort ();
continue;
}
- /* ... fall through ... */
+ /* ... fall through ... */
case LSHIFTRT:
case ASHIFT:
STORE_FLAG_VALUE of 1 or logical with STORE_FLAG_VALUE == -1,
we have a (neg (gt X 0)) operation. */
- if (GET_CODE (XEXP (varop, 0)) == ASHIFTRT
+ if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
+ && GET_CODE (XEXP (varop, 0)) == ASHIFTRT
&& count == GET_MODE_BITSIZE (GET_MODE (varop)) - 1
- && (STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
&& (code == LSHIFTRT || code == ASHIFTRT)
&& GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT
&& INTVAL (XEXP (XEXP (varop, 0), 1)) == count
else if (GET_MODE (varop) != shift_mode)
varop = gen_lowpart_for_combine (shift_mode, varop);
- /* If we can't make the SUBREG, try to return what we were given. */
+ /* If we can't make the SUBREG, try to return what we were given. */
if (GET_CODE (varop) == CLOBBER)
return x ? x : varop;
int i, j;
char *fmt;
rtx rt;
+ struct undo *undo;
VA_START (p, mode);
/* See if this is in undobuf. Be sure we don't use objects that came
from another insn; this could produce circular rtl structures. */
- for (i = previous_num_undos; i < undobuf.num_undo; i++)
- if (!undobuf.undo[i].is_int
- && GET_CODE (undobuf.undo[i].old_contents.r) == code
- && GET_MODE (undobuf.undo[i].old_contents.r) == mode)
+ for (undo = undobuf.undos; undo != undobuf.previous_undos; undo = undo->next)
+ if (!undo->is_int
+ && GET_CODE (undo->old_contents.r) == code
+ && GET_MODE (undo->old_contents.r) == mode)
{
for (j = 0; j < n_args; j++)
- if (XEXP (undobuf.undo[i].old_contents.r, j) != args[j])
+ if (XEXP (undo->old_contents.r, j) != args[j])
break;
if (j == n_args)
- return undobuf.undo[i].old_contents.r;
+ return undo->old_contents.r;
}
/* Otherwise make a new rtx. We know we have 1, 2, or 3 args.
enum machine_mode op_mode = GET_MODE (op0);
/* Strip the COMPARE from (REL_OP (compare X Y) 0) to get
- just (REL_OP X Y). */
+ just (REL_OP X Y). */
if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
{
op1 = XEXP (op0, 1);
op1 = SUBREG_REG (inner_op1);
/* The resulting comparison is always unsigned since we masked
- off the original sign bit. */
+ off the original sign bit. */
code = unsigned_condition (code);
changed = 1;
}
/* If the first operand is a constant, swap the operands and adjust the
- comparison code appropriately. */
- if (CONSTANT_P (op0))
+ comparison code appropriately, but don't do this if the second operand
+ is already a constant integer. */
+ if (CONSTANT_P (op0) && GET_CODE (op1) != CONST_INT)
{
tem = op0, op0 = op1, op1 = tem;
code = swap_condition (code);
break;
case GE:
- /* >= C is equivalent to > (C - 1). */
+ /* >= C is equivalent to > (C - 1). */
if (const_op > 0)
{
const_op -= 1;
const_op -= 1;
op1 = GEN_INT (const_op);
code = LEU;
- /* ... fall through ... */
+ /* ... fall through ... */
}
/* (unsigned) < 0x80000000 is equivalent to >= 0. */
- else if (const_op == (HOST_WIDE_INT) 1 << (mode_width - 1))
+ else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
+ && (const_op == (HOST_WIDE_INT) 1 << (mode_width - 1)))
{
const_op = 0, op1 = const0_rtx;
code = GE;
if (const_op == 0)
code = EQ;
- /* (unsigned) <= 0x7fffffff is equivalent to >= 0. */
- else if (const_op == ((HOST_WIDE_INT) 1 << (mode_width - 1)) - 1)
+ /* (unsigned) <= 0x7fffffff is equivalent to >= 0. */
+ else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
+ && (const_op == ((HOST_WIDE_INT) 1 << (mode_width - 1)) - 1))
{
const_op = 0, op1 = const0_rtx;
code = GE;
const_op -= 1;
op1 = GEN_INT (const_op);
code = GTU;
- /* ... fall through ... */
+ /* ... fall through ... */
}
/* (unsigned) >= 0x80000000 is equivalent to < 0. */
- else if (const_op == (HOST_WIDE_INT) 1 << (mode_width - 1))
+ else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
+ && (const_op == (HOST_WIDE_INT) 1 << (mode_width - 1)))
{
const_op = 0, op1 = const0_rtx;
code = LT;
code = NE;
/* (unsigned) > 0x7fffffff is equivalent to < 0. */
- else if (const_op == ((HOST_WIDE_INT) 1 << (mode_width - 1)) - 1)
+ else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
+ && (const_op == ((HOST_WIDE_INT) 1 << (mode_width - 1)) - 1))
{
const_op = 0, op1 = const0_rtx;
code = LT;
continue;
}
- /* ... fall through ... */
+ /* ... fall through ... */
case SIGN_EXTRACT:
tem = expand_compound_operation (op0);
}
/* If we have NEG of something whose two high-order bits are the
- same, we know that "(-a) < 0" is equivalent to "a > 0". */
+ same, we know that "(-a) < 0" is equivalent to "a > 0". */
if (num_sign_bit_copies (op0, mode) >= 2)
{
op0 = XEXP (op0, 0);
continue;
}
- /* ... fall through ... */
+ /* ... fall through ... */
case ABS:
/* ABS is ignorable inside an equality comparison with zero. */
else
break;
- /* ... fall through ... */
+ /* ... fall through ... */
case ZERO_EXTEND:
if ((unsigned_comparison_p || equality_comparison_p)
continue;
}
- /* ... fall through ... */
+ /* ... fall through ... */
case LSHIFTRT:
/* If we have (compare (xshiftrt FOO N) (const_int C)) and
the low order N bits of FOO are known to be zero, we can do this
/* 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
infinite loops. */
- if (value && ! get_last_value_validate (&value,
+ if (value && ! get_last_value_validate (&value, insn,
reg_last_set_label[regno], 0))
{
value = copy_rtx (value);
- if (! get_last_value_validate (&value, reg_last_set_label[regno], 1))
+ if (! get_last_value_validate (&value, insn,
+ reg_last_set_label[regno], 1))
value = 0;
}
we don't know exactly what registers it was produced from. */
static int
-get_last_value_validate (loc, tick, replace)
+get_last_value_validate (loc, insn, tick, replace)
rtx *loc;
+ rtx insn;
int tick;
int replace;
{
return 1;
}
+ /* If this is a memory reference, make sure that there were
+ no stores after it that might have clobbered the value. We don't
+ have alias info, so we assume any store invalidates it. */
+ else if (GET_CODE (x) == MEM && ! RTX_UNCHANGING_P (x)
+ && INSN_CUID (insn) <= mem_last_set)
+ {
+ if (replace)
+ *loc = gen_rtx (CLOBBER, GET_MODE (x), const0_rtx);
+ return replace;
+ }
for (i = 0; i < len; i++)
if ((fmt[i] == 'e'
- && get_last_value_validate (&XEXP (x, i), tick, replace) == 0)
+ && get_last_value_validate (&XEXP (x, i), insn, tick, replace) == 0)
/* Don't bother with these. They shouldn't occur anyway. */
|| fmt[i] == 'E')
return 0;
/* If this is a non-paradoxical SUBREG, get the value of its operand and
then convert it to the desired mode. If this is a paradoxical SUBREG,
- we cannot predict what values the "extra" bits might have. */
+ we cannot predict what values the "extra" bits might have. */
if (GET_CODE (x) == SUBREG
&& subreg_lowpart_p (x)
&& (GET_MODE_SIZE (GET_MODE (x))
regno = REGNO (x);
value = reg_last_set_value[regno];
- /* If we don't have a value or if it isn't for this basic block, return 0. */
+ /* If we don't have a value or if it isn't for this basic block,
+ return 0. */
if (value == 0
|| (reg_n_sets[regno] != 1
}
/* If the value has all its registers valid, return it. */
- if (get_last_value_validate (&value, reg_last_set_label[regno], 0))
+ if (get_last_value_validate (&value, reg_last_set[regno],
+ reg_last_set_label[regno], 0))
return value;
/* Otherwise, make a copy and replace any invalid register with
(clobber (const_int 0)). If that fails for some reason, return 0. */
value = copy_rtx (value);
- if (get_last_value_validate (&value, reg_last_set_label[regno], 1))
+ if (get_last_value_validate (&value, reg_last_set[regno],
+ reg_last_set_label[regno], 1))
return value;
return 0;
TO_INSN (exclusive), put a REG_DEAD note for that register in the
list headed by PNOTES.
+ That said, don't move registers killed by maybe_kill_insn.
+
This is done when X is being merged by combination into TO_INSN. These
notes will then be distributed as needed. */
static void
-move_deaths (x, from_cuid, to_insn, pnotes)
+move_deaths (x, maybe_kill_insn, from_cuid, to_insn, pnotes)
rtx x;
+ rtx maybe_kill_insn;
int from_cuid;
rtx to_insn;
rtx *pnotes;
register rtx where_dead = reg_last_death[regno];
register rtx before_dead, after_dead;
+ /* Don't move the register if it gets killed in between from and to */
+ if (maybe_kill_insn && reg_set_p (x, maybe_kill_insn)
+ && !reg_referenced_p (x, maybe_kill_insn))
+ return;
+
/* WHERE_DEAD could be a USE insn made by combine, so first we
make sure that we have insns with valid INSN_CUID values. */
before_dead = where_dead;
if (note != 0 && regno < FIRST_PSEUDO_REGISTER
&& (GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
- != GET_MODE_SIZE (GET_MODE (x))))
+ > GET_MODE_SIZE (GET_MODE (x))))
{
int deadregno = REGNO (XEXP (note, 0));
int deadend
gen_rtx (REG, reg_raw_mode[i], i),
REG_NOTES (where_dead));
}
- /* If we didn't find any note, and we have a multi-reg hard
+ /* If we didn't find any note, or if we found a REG_DEAD note that
+ covers only part of the given reg, and we have a multi-reg hard
register, then to be safe we must check for REG_DEAD notes
for each register other than the first. They could have
their own REG_DEAD notes lying around. */
- else if (note == 0 && regno < FIRST_PSEUDO_REGISTER
+ else if ((note == 0
+ || (note != 0
+ && (GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
+ < GET_MODE_SIZE (GET_MODE (x)))))
+ && regno < FIRST_PSEUDO_REGISTER
&& HARD_REGNO_NREGS (regno, GET_MODE (x)) > 1)
{
int ourend = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
- int i;
+ int i, offset;
rtx oldnotes = 0;
- for (i = regno + 1; i < ourend; i++)
+ if (note)
+ offset = HARD_REGNO_NREGS (regno, GET_MODE (XEXP (note, 0)));
+ else
+ offset = 1;
+
+ for (i = regno + offset; i < ourend; i++)
move_deaths (gen_rtx (REG, reg_raw_mode[i], i),
- from_cuid, to_insn, &oldnotes);
+ maybe_kill_insn, from_cuid, to_insn, &oldnotes);
}
if (note != 0 && GET_MODE (XEXP (note, 0)) == GET_MODE (x))
{
rtx dest = SET_DEST (x);
- move_deaths (SET_SRC (x), from_cuid, to_insn, pnotes);
+ move_deaths (SET_SRC (x), maybe_kill_insn, from_cuid, to_insn, pnotes);
/* In the case of a ZERO_EXTRACT, a STRICT_LOW_PART, or a SUBREG
that accesses one word of a multi-word item, some
== ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest)))
+ UNITS_PER_WORD - 1) / UNITS_PER_WORD))))
{
- move_deaths (dest, from_cuid, to_insn, pnotes);
+ move_deaths (dest, maybe_kill_insn, from_cuid, to_insn, pnotes);
return;
}
being replaced so the old value is not used in this insn. */
if (GET_CODE (dest) == MEM)
- move_deaths (XEXP (dest, 0), from_cuid, to_insn, pnotes);
+ move_deaths (XEXP (dest, 0), maybe_kill_insn, from_cuid,
+ to_insn, pnotes);
return;
}
{
register int j;
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- move_deaths (XVECEXP (x, i, j), from_cuid, to_insn, pnotes);
+ move_deaths (XVECEXP (x, i, j), maybe_kill_insn, from_cuid,
+ to_insn, pnotes);
}
else if (fmt[i] == 'e')
- move_deaths (XEXP (x, i), from_cuid, to_insn, pnotes);
+ move_deaths (XEXP (x, i), maybe_kill_insn, from_cuid, to_insn, pnotes);
}
}
\f
next_note = XEXP (note, 1);
switch (REG_NOTE_KIND (note))
{
+ case REG_BR_PROB:
+ case REG_EXEC_COUNT:
+ /* Doesn't matter much where we put this, as long as it's somewhere.
+ It is preferable to keep these notes on branches, which is most
+ likely to be i3. */
+ place = i3;
+ break;
+
case REG_UNUSED:
/* Any clobbers for i3 may still exist, and so we must process
REG_UNUSED notes from that insn.