/* Optimize by combining instructions for GNU compiler.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
/* This module is essentially the "combiner" phase of the U. of Arizona
Portable Optimizer, but redone to work on our list-structured
we install it, delete the earlier insns, and update the data flow
information (LOG_LINKS and REG_NOTES) for what we did.
- There are a few exceptions where the dataflow information created by
- flow.c aren't completely updated:
+ There are a few exceptions where the dataflow information isn't
+ completely updated (however this is only a local issue since it is
+ regenerated before the next pass that uses it):
- reg_live_length is not updated
- reg_n_refs is not adjusted in the rare case when a register is
#include "params.h"
#include "timevar.h"
#include "tree-pass.h"
+#include "df.h"
+#include "cgraph.h"
/* Number of attempts to combine instructions in this function. */
static int total_attempts, total_merges, total_extras, total_successes;
-\f
-/* Vector mapping INSN_UIDs to cuids.
- The cuids are like uids but increase monotonically always.
- Combine always uses cuids so that it can compare them.
- But actually renumbering the uids, which we used to do,
- proves to be a bad idea because it makes it hard to compare
- the dumps produced by earlier passes with those from later passes. */
-
-static int *uid_cuid;
-static int max_uid_cuid;
-
-/* Get the cuid of an insn. */
+/* combine_instructions may try to replace the right hand side of the
+ second instruction with the value of an associated REG_EQUAL note
+ before throwing it at try_combine. That is problematic when there
+ is a REG_DEAD note for a register used in the old right hand side
+ and can cause distribute_notes to do wrong things. This is the
+ second instruction if it has been so modified, null otherwise. */
-#define INSN_CUID(INSN) \
-(INSN_UID (INSN) > max_uid_cuid ? insn_cuid (INSN) : uid_cuid[INSN_UID (INSN)])
+static rtx i2mod;
-/* In case BITS_PER_WORD == HOST_BITS_PER_WIDE_INT, shifting by
- BITS_PER_WORD would invoke undefined behavior. Work around it. */
+/* When I2MOD is nonnull, this is a copy of the old right hand side. */
-#define UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD(val) \
- (((unsigned HOST_WIDE_INT) (val) << (BITS_PER_WORD - 1)) << 1)
+static rtx i2mod_old_rhs;
-/* Maximum register number, which is the size of the tables below. */
+/* When I2MOD is nonnull, this is a copy of the new right hand side. */
-static unsigned int combine_max_regno;
-
-struct reg_stat {
+static rtx i2mod_new_rhs;
+\f
+typedef struct reg_stat_struct {
/* Record last point of death of (hard or pseudo) register n. */
rtx last_death;
(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.
+ to a register. Often just its form is helpful.
Therefore, we maintain the following fields:
truncation if we know that value already contains a truncated
value. */
- ENUM_BITFIELD(machine_mode) truncated_to_mode : 8;
-};
+ ENUM_BITFIELD(machine_mode) truncated_to_mode : 8;
+} reg_stat_type;
-static struct reg_stat *reg_stat;
+DEF_VEC_O(reg_stat_type);
+DEF_VEC_ALLOC_O(reg_stat_type,heap);
-/* Record the cuid of the last insn that invalidated memory
+static VEC(reg_stat_type,heap) *reg_stat;
+
+/* Record the luid of the last insn that invalidated memory
(anything that writes memory, and subroutine calls, but not pushes). */
static int mem_last_set;
-/* Record the cuid of the last CALL_INSN
+/* Record the luid of the last CALL_INSN
so we can tell whether a potential combination crosses any calls. */
-static int last_call_cuid;
+static int last_call_luid;
/* When `subst' is called, this is the insn that is being modified
(by combining in a previous insn). The PATTERN of this insn
static rtx subst_insn;
-/* This is the lowest CUID that `subst' is currently dealing with.
+/* This is the lowest LUID that `subst' is currently dealing with.
get_last_value will not return a value if the register was set at or
- after this CUID. If not for this mechanism, we could get confused if
+ after this LUID. If not for this mechanism, we could get confused if
I2 or I1 in try_combine were an insn that used the old value of a register
to obtain a new value. In that case, we might erroneously get the
new value of the register when we wanted the old one. */
-static int subst_low_cuid;
+static int subst_low_luid;
/* This contains any hard registers that are used in newpat; reg_dead_at_p
must consider all these registers to be always live. */
/* Basic block in which we are performing combines. */
static basic_block this_basic_block;
+static bool optimize_this_for_speed_p;
-/* A bitmap indicating which blocks had registers go dead at entry.
- After combine, we'll need to re-do global life analysis with
- those blocks as starting points. */
-static sbitmap refresh_blocks;
\f
+/* Length of the currently allocated uid_insn_cost array. */
+
+static int max_uid_known;
+
/* The following array records the insn_rtx_cost for every insn
in the instruction stream. */
static int *uid_insn_cost;
-/* Length of the currently allocated uid_insn_cost array. */
+/* The following array records the LOG_LINKS for every insn in the
+ instruction stream as an INSN_LIST rtx. */
-static int last_insn_cost;
+static rtx *uid_log_links;
-/* Incremented for each label. */
+#define INSN_COST(INSN) (uid_insn_cost[INSN_UID (INSN)])
+#define LOG_LINKS(INSN) (uid_log_links[INSN_UID (INSN)])
+
+/* Incremented for each basic block. */
static int label_tick;
+/* Reset to label_tick for each label. */
+
+static int label_tick_ebb_start;
+
/* Mode used to compute significance in reg_stat[].nonzero_bits. It is the
largest integer mode that can fit in HOST_BITS_PER_WIDE_INT. */
/* Record one modification to rtl structure
to be undone by storing old_contents into *where. */
+enum undo_kind { UNDO_RTX, UNDO_INT, UNDO_MODE };
+
struct undo
{
struct undo *next;
- enum { UNDO_RTX, UNDO_INT, UNDO_MODE } kind;
+ enum undo_kind kind;
union { rtx r; int i; enum machine_mode m; } old_contents;
union { rtx *r; int *i; } where;
};
static int n_occurrences;
-static rtx reg_nonzero_bits_for_combine (rtx, enum machine_mode, rtx,
+static rtx reg_nonzero_bits_for_combine (const_rtx, enum machine_mode, const_rtx,
enum machine_mode,
unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT *);
-static rtx reg_num_sign_bit_copies_for_combine (rtx, enum machine_mode, rtx,
+static rtx reg_num_sign_bit_copies_for_combine (const_rtx, enum machine_mode, const_rtx,
enum machine_mode,
unsigned int, unsigned int *);
static void do_SUBST (rtx *, rtx);
static void do_SUBST_INT (int *, int);
static void init_reg_last (void);
-static void setup_incoming_promotions (void);
-static void set_nonzero_bits_and_sign_copies (rtx, rtx, void *);
+static void setup_incoming_promotions (rtx);
+static void set_nonzero_bits_and_sign_copies (rtx, const_rtx, void *);
static int cant_combine_insn_p (rtx);
static int can_combine_p (rtx, rtx, rtx, rtx, rtx *, rtx *);
static int combinable_i3pat (rtx, rtx *, rtx, rtx, int, rtx *);
static rtx simplify_set (rtx);
static rtx simplify_logical (rtx);
static rtx expand_compound_operation (rtx);
-static rtx expand_field_assignment (rtx);
+static const_rtx expand_field_assignment (const_rtx);
static rtx make_extraction (enum machine_mode, rtx, HOST_WIDE_INT,
rtx, unsigned HOST_WIDE_INT, int, int, int);
static rtx extract_left_shift (rtx, int);
static enum rtx_code simplify_comparison (enum rtx_code, rtx *, rtx *);
static void update_table_tick (rtx);
static void record_value_for_reg (rtx, rtx, rtx);
-static void check_conversions (rtx, rtx);
-static void record_dead_and_set_regs_1 (rtx, rtx, void *);
+static void check_promoted_subreg (rtx, rtx);
+static void record_dead_and_set_regs_1 (rtx, const_rtx, void *);
static void record_dead_and_set_regs (rtx);
static int get_last_value_validate (rtx *, rtx, int, int);
-static rtx get_last_value (rtx);
-static int use_crosses_set_p (rtx, int);
-static void reg_dead_at_p_1 (rtx, rtx, void *);
+static rtx get_last_value (const_rtx);
+static int use_crosses_set_p (const_rtx, int);
+static void reg_dead_at_p_1 (rtx, const_rtx, void *);
static int reg_dead_at_p (rtx, rtx);
static void move_deaths (rtx, rtx, int, rtx, rtx *);
static int reg_bitfield_target_p (rtx, rtx);
static void distribute_notes (rtx, rtx, rtx, rtx, rtx, rtx);
static void distribute_links (rtx);
static void mark_used_regs_combine (rtx);
-static int insn_cuid (rtx);
static void record_promoted_value (rtx, rtx);
static int unmentioned_reg_p_1 (rtx *, void *);
static bool unmentioned_reg_p (rtx, rtx);
-static void record_truncated_value (rtx);
-static bool reg_truncated_to_mode (enum machine_mode, rtx);
+static int record_truncated_value (rtx *, void *);
+static void record_truncated_values (rtx *, void *);
+static bool reg_truncated_to_mode (enum machine_mode, const_rtx);
static rtx gen_lowpart_or_truncate (enum machine_mode, rtx);
\f
#undef RTL_HOOKS_REG_NUM_SIGN_BIT_COPIES
#define RTL_HOOKS_REG_NUM_SIGN_BIT_COPIES reg_num_sign_bit_copies_for_combine
+#undef RTL_HOOKS_REG_TRUNCATED_TO_MODE
+#define RTL_HOOKS_REG_TRUNCATED_TO_MODE reg_truncated_to_mode
+
static const struct rtl_hooks combine_rtl_hooks = RTL_HOOKS_INITIALIZER;
\f
+/* Try to split PATTERN found in INSN. This returns NULL_RTX if
+ PATTERN can not be split. Otherwise, it returns an insn sequence.
+ This is a wrapper around split_insns which ensures that the
+ reg_stat vector is made larger if the splitter creates a new
+ register. */
+
+static rtx
+combine_split_insns (rtx pattern, rtx insn)
+{
+ rtx ret;
+ unsigned int nregs;
+
+ ret = split_insns (pattern, insn);
+ nregs = max_reg_num ();
+ if (nregs > VEC_length (reg_stat_type, reg_stat))
+ VEC_safe_grow_cleared (reg_stat_type, heap, reg_stat, nregs);
+ return ret;
+}
+
+/* This is used by find_single_use to locate an rtx in LOC that
+ contains exactly one use of DEST, which is typically either a REG
+ or CC0. It returns a pointer to the innermost rtx expression
+ containing DEST. Appearances of DEST that are being used to
+ totally replace it are not counted. */
+
+static rtx *
+find_single_use_1 (rtx dest, rtx *loc)
+{
+ rtx x = *loc;
+ enum rtx_code code = GET_CODE (x);
+ rtx *result = NULL;
+ rtx *this_result;
+ int i;
+ const char *fmt;
+
+ switch (code)
+ {
+ case CONST_INT:
+ case CONST:
+ case LABEL_REF:
+ case SYMBOL_REF:
+ case CONST_DOUBLE:
+ case CONST_VECTOR:
+ case CLOBBER:
+ return 0;
+
+ case SET:
+ /* If the destination is anything other than CC0, PC, a REG or a SUBREG
+ of a REG that occupies all of the REG, the insn uses DEST if
+ it is mentioned in the destination or the source. Otherwise, we
+ need just check the source. */
+ if (GET_CODE (SET_DEST (x)) != CC0
+ && GET_CODE (SET_DEST (x)) != PC
+ && !REG_P (SET_DEST (x))
+ && ! (GET_CODE (SET_DEST (x)) == SUBREG
+ && REG_P (SUBREG_REG (SET_DEST (x)))
+ && (((GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (x))))
+ + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
+ == ((GET_MODE_SIZE (GET_MODE (SET_DEST (x)))
+ + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))))
+ break;
+
+ return find_single_use_1 (dest, &SET_SRC (x));
+
+ case MEM:
+ case SUBREG:
+ return find_single_use_1 (dest, &XEXP (x, 0));
+
+ default:
+ break;
+ }
+
+ /* If it wasn't one of the common cases above, check each expression and
+ vector of this code. Look for a unique usage of DEST. */
+
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ {
+ if (dest == XEXP (x, i)
+ || (REG_P (dest) && REG_P (XEXP (x, i))
+ && REGNO (dest) == REGNO (XEXP (x, i))))
+ this_result = loc;
+ else
+ this_result = find_single_use_1 (dest, &XEXP (x, i));
+
+ if (result == NULL)
+ result = this_result;
+ else if (this_result)
+ /* Duplicate usage. */
+ return NULL;
+ }
+ else if (fmt[i] == 'E')
+ {
+ int j;
+
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ {
+ if (XVECEXP (x, i, j) == dest
+ || (REG_P (dest)
+ && REG_P (XVECEXP (x, i, j))
+ && REGNO (XVECEXP (x, i, j)) == REGNO (dest)))
+ this_result = loc;
+ else
+ this_result = find_single_use_1 (dest, &XVECEXP (x, i, j));
+
+ if (result == NULL)
+ result = this_result;
+ else if (this_result)
+ return NULL;
+ }
+ }
+ }
+
+ return result;
+}
+
+
+/* See if DEST, produced in INSN, is used only a single time in the
+ sequel. If so, return a pointer to the innermost rtx expression in which
+ it is used.
+
+ If PLOC is nonzero, *PLOC is set to the insn containing the single use.
+
+ If DEST is cc0_rtx, we look only at the next insn. In that case, we don't
+ care about REG_DEAD notes or LOG_LINKS.
+
+ Otherwise, we find the single use by finding an insn that has a
+ LOG_LINKS pointing at INSN and has a REG_DEAD note for DEST. If DEST is
+ only referenced once in that insn, we know that it must be the first
+ and last insn referencing DEST. */
+
+static rtx *
+find_single_use (rtx dest, rtx insn, rtx *ploc)
+{
+ basic_block bb;
+ rtx next;
+ rtx *result;
+ rtx link;
+
+#ifdef HAVE_cc0
+ if (dest == cc0_rtx)
+ {
+ next = NEXT_INSN (insn);
+ if (next == 0
+ || (!NONJUMP_INSN_P (next) && !JUMP_P (next)))
+ return 0;
+
+ result = find_single_use_1 (dest, &PATTERN (next));
+ if (result && ploc)
+ *ploc = next;
+ return result;
+ }
+#endif
+
+ if (!REG_P (dest))
+ return 0;
+
+ bb = BLOCK_FOR_INSN (insn);
+ for (next = NEXT_INSN (insn);
+ next && BLOCK_FOR_INSN (next) == bb;
+ next = NEXT_INSN (next))
+ if (INSN_P (next) && dead_or_set_p (next, dest))
+ {
+ for (link = LOG_LINKS (next); link; link = XEXP (link, 1))
+ if (XEXP (link, 0) == insn)
+ break;
+
+ if (link)
+ {
+ result = find_single_use_1 (dest, &PATTERN (next));
+ if (ploc)
+ *ploc = next;
+ return result;
+ }
+ }
+
+ return 0;
+}
+\f
/* Substitute NEWVAL, an rtx expression, into INTO, a place in some
insn. The substitution can be undone by undo_all. If INTO is already
set to NEWVAL, do not record this change. Because computing NEWVAL might
little gain doing the checks here. Focus on catching invalid
transformations involving integer constants. */
if (GET_MODE_CLASS (GET_MODE (oldval)) == MODE_INT
- && GET_CODE (newval) == CONST_INT)
+ && CONST_INT_P (newval))
{
/* Sanity check that we're replacing oldval with a CONST_INT
that is a valid sign-extension for the original mode. */
perform this test on oldval instead, checking whether an
invalid replacement took place before we got here. */
gcc_assert (!(GET_CODE (oldval) == SUBREG
- && GET_CODE (SUBREG_REG (oldval)) == CONST_INT));
+ && CONST_INT_P (SUBREG_REG (oldval))));
gcc_assert (!(GET_CODE (oldval) == ZERO_EXTEND
- && GET_CODE (XEXP (oldval, 0)) == CONST_INT));
+ && CONST_INT_P (XEXP (oldval, 0))));
}
if (undobuf.frees)
buf->kind = UNDO_MODE;
buf->where.r = into;
buf->old_contents.m = oldval;
- PUT_MODE (*into, newval);
+ adjust_reg_mode (*into, newval);
buf->next = undobuf.undos, undobuf.undos = buf;
}
#define SUBST_MODE(INTO, NEWVAL) do_SUBST_MODE(&(INTO), (NEWVAL))
\f
/* Subroutine of try_combine. Determine whether the combine replacement
- patterns NEWPAT and NEWI2PAT are cheaper according to insn_rtx_cost
- that the original instruction sequence I1, I2 and I3. Note that I1
- and/or NEWI2PAT may be NULL_RTX. This function returns false, if the
- costs of all instructions can be estimated, and the replacements are
- more expensive than the original sequence. */
+ patterns NEWPAT, NEWI2PAT and NEWOTHERPAT are cheaper according to
+ insn_rtx_cost that the original instruction sequence I1, I2, I3 and
+ undobuf.other_insn. Note that I1 and/or NEWI2PAT may be NULL_RTX.
+ NEWOTHERPAT and undobuf.other_insn may also both be NULL_RTX. This
+ function returns false, if the costs of all instructions can be
+ estimated, and the replacements are more expensive than the original
+ sequence. */
static bool
-combine_validate_cost (rtx i1, rtx i2, rtx i3, rtx newpat, rtx newi2pat)
+combine_validate_cost (rtx i1, rtx i2, rtx i3, rtx newpat, rtx newi2pat,
+ rtx newotherpat)
{
int i1_cost, i2_cost, i3_cost;
int new_i2_cost, new_i3_cost;
int old_cost, new_cost;
/* Lookup the original insn_rtx_costs. */
- i2_cost = INSN_UID (i2) <= last_insn_cost
- ? uid_insn_cost[INSN_UID (i2)] : 0;
- i3_cost = INSN_UID (i3) <= last_insn_cost
- ? uid_insn_cost[INSN_UID (i3)] : 0;
+ i2_cost = INSN_COST (i2);
+ i3_cost = INSN_COST (i3);
if (i1)
{
- i1_cost = INSN_UID (i1) <= last_insn_cost
- ? uid_insn_cost[INSN_UID (i1)] : 0;
+ i1_cost = INSN_COST (i1);
old_cost = (i1_cost > 0 && i2_cost > 0 && i3_cost > 0)
? i1_cost + i2_cost + i3_cost : 0;
}
}
/* Calculate the replacement insn_rtx_costs. */
- new_i3_cost = insn_rtx_cost (newpat);
+ new_i3_cost = insn_rtx_cost (newpat, optimize_this_for_speed_p);
if (newi2pat)
{
- new_i2_cost = insn_rtx_cost (newi2pat);
+ new_i2_cost = insn_rtx_cost (newi2pat, optimize_this_for_speed_p);
new_cost = (new_i2_cost > 0 && new_i3_cost > 0)
? new_i2_cost + new_i3_cost : 0;
}
{
int old_other_cost, new_other_cost;
- old_other_cost = (INSN_UID (undobuf.other_insn) <= last_insn_cost
- ? uid_insn_cost[INSN_UID (undobuf.other_insn)] : 0);
- new_other_cost = insn_rtx_cost (PATTERN (undobuf.other_insn));
+ old_other_cost = INSN_COST (undobuf.other_insn);
+ new_other_cost = insn_rtx_cost (newotherpat, optimize_this_for_speed_p);
if (old_other_cost > 0 && new_other_cost > 0)
{
old_cost += old_other_cost;
}
/* Update the uid_insn_cost array with the replacement costs. */
- uid_insn_cost[INSN_UID (i2)] = new_i2_cost;
- uid_insn_cost[INSN_UID (i3)] = new_i3_cost;
+ INSN_COST (i2) = new_i2_cost;
+ INSN_COST (i3) = new_i3_cost;
if (i1)
- uid_insn_cost[INSN_UID (i1)] = 0;
+ INSN_COST (i1) = 0;
return true;
}
+
+
+/* Delete any insns that copy a register to itself. */
+
+static void
+delete_noop_moves (void)
+{
+ rtx insn, next;
+ basic_block bb;
+
+ FOR_EACH_BB (bb)
+ {
+ for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb)); insn = next)
+ {
+ next = NEXT_INSN (insn);
+ if (INSN_P (insn) && noop_move_p (insn))
+ {
+ if (dump_file)
+ fprintf (dump_file, "deleting noop move %d\n", INSN_UID (insn));
+
+ delete_insn_and_edges (insn);
+ }
+ }
+ }
+}
+
+\f
+/* Fill in log links field for all insns. */
+
+static void
+create_log_links (void)
+{
+ basic_block bb;
+ rtx *next_use, insn;
+ df_ref *def_vec, *use_vec;
+
+ next_use = XCNEWVEC (rtx, max_reg_num ());
+
+ /* Pass through each block from the end, recording the uses of each
+ register and establishing log links when def is encountered.
+ Note that we do not clear next_use array in order to save time,
+ so we have to test whether the use is in the same basic block as def.
+
+ There are a few cases below when we do not consider the definition or
+ usage -- these are taken from original flow.c did. Don't ask me why it is
+ done this way; I don't know and if it works, I don't want to know. */
+
+ FOR_EACH_BB (bb)
+ {
+ FOR_BB_INSNS_REVERSE (bb, insn)
+ {
+ if (!INSN_P (insn))
+ continue;
+
+ /* Log links are created only once. */
+ gcc_assert (!LOG_LINKS (insn));
+
+ for (def_vec = DF_INSN_DEFS (insn); *def_vec; def_vec++)
+ {
+ df_ref def = *def_vec;
+ int regno = DF_REF_REGNO (def);
+ rtx use_insn;
+
+ if (!next_use[regno])
+ continue;
+
+ /* Do not consider if it is pre/post modification in MEM. */
+ if (DF_REF_FLAGS (def) & DF_REF_PRE_POST_MODIFY)
+ continue;
+
+ /* Do not make the log link for frame pointer. */
+ if ((regno == FRAME_POINTER_REGNUM
+ && (! reload_completed || frame_pointer_needed))
+#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+ || (regno == HARD_FRAME_POINTER_REGNUM
+ && (! reload_completed || frame_pointer_needed))
+#endif
+#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+ || (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
+#endif
+ )
+ continue;
+
+ use_insn = next_use[regno];
+ if (BLOCK_FOR_INSN (use_insn) == bb)
+ {
+ /* flow.c claimed:
+
+ We don't build a LOG_LINK for hard registers contained
+ in ASM_OPERANDs. If these registers get replaced,
+ we might wind up changing the semantics of the insn,
+ even if reload can make what appear to be valid
+ assignments later. */
+ if (regno >= FIRST_PSEUDO_REGISTER
+ || asm_noperands (PATTERN (use_insn)) < 0)
+ {
+ /* Don't add duplicate links between instructions. */
+ rtx links;
+ for (links = LOG_LINKS (use_insn); links;
+ links = XEXP (links, 1))
+ if (insn == XEXP (links, 0))
+ break;
+
+ if (!links)
+ LOG_LINKS (use_insn) =
+ alloc_INSN_LIST (insn, LOG_LINKS (use_insn));
+ }
+ }
+ next_use[regno] = NULL_RTX;
+ }
+
+ for (use_vec = DF_INSN_USES (insn); *use_vec; use_vec++)
+ {
+ df_ref use = *use_vec;
+ int regno = DF_REF_REGNO (use);
+
+ /* Do not consider the usage of the stack pointer
+ by function call. */
+ if (DF_REF_FLAGS (use) & DF_REF_CALL_STACK_USAGE)
+ continue;
+
+ next_use[regno] = insn;
+ }
+ }
+ }
+
+ free (next_use);
+}
+
+/* Clear LOG_LINKS fields of insns. */
+
+static void
+clear_log_links (void)
+{
+ rtx insn;
+
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (INSN_P (insn))
+ free_INSN_LIST_list (&LOG_LINKS (insn));
+}
+
+
+
\f
/* Main entry point for combiner. F is the first insn of the function.
NREGS is the first unused pseudo-reg number.
#ifdef HAVE_cc0
rtx prev;
#endif
- int i;
- unsigned int j = 0;
rtx links, nextlinks;
- sbitmap_iterator sbi;
+ rtx first;
int new_direct_jump_p = 0;
+ for (first = f; first && !INSN_P (first); )
+ first = NEXT_INSN (first);
+ if (!first)
+ return 0;
+
combine_attempts = 0;
combine_merges = 0;
combine_extras = 0;
combine_successes = 0;
- combine_max_regno = nregs;
-
rtl_hooks = combine_rtl_hooks;
- reg_stat = XCNEWVEC (struct reg_stat, nregs);
+ VEC_safe_grow_cleared (reg_stat_type, heap, reg_stat, nregs);
init_recog_no_volatile ();
- /* Compute maximum uid value so uid_cuid can be allocated. */
-
- for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
- if (INSN_UID (insn) > i)
- i = INSN_UID (insn);
-
- uid_cuid = XNEWVEC (int, i + 1);
- max_uid_cuid = i;
+ /* Allocate array for insn info. */
+ max_uid_known = get_max_uid ();
+ uid_log_links = XCNEWVEC (rtx, max_uid_known + 1);
+ uid_insn_cost = XCNEWVEC (int, max_uid_known + 1);
nonzero_bits_mode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0);
nonzero_sign_valid = 0;
- /* Compute the mapping from uids to cuids.
- Cuids are numbers assigned to insns, like uids,
- except that cuids increase monotonically through the code.
-
- Scan all SETs and see if we can deduce anything about what
+ /* Scan all SETs and see if we can deduce anything about what
bits are known to be zero for some registers and how many copies
of the sign bit are known to exist for those registers.
Also set any known values so that we can use it while searching
for what bits are known to be set. */
- label_tick = 1;
-
- setup_incoming_promotions ();
-
- refresh_blocks = sbitmap_alloc (last_basic_block);
- sbitmap_zero (refresh_blocks);
-
- /* Allocate array of current insn_rtx_costs. */
- uid_insn_cost = XCNEWVEC (int, max_uid_cuid + 1);
- last_insn_cost = max_uid_cuid;
+ setup_incoming_promotions (first);
- for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
+ create_log_links ();
+ label_tick_ebb_start = ENTRY_BLOCK_PTR->index;
+ FOR_EACH_BB (this_basic_block)
{
- uid_cuid[INSN_UID (insn)] = ++i;
- subst_low_cuid = i;
- subst_insn = insn;
+ optimize_this_for_speed_p = optimize_bb_for_speed_p (this_basic_block);
+ last_call_luid = 0;
+ mem_last_set = -1;
+ label_tick = this_basic_block->index;
+ if (!single_pred_p (this_basic_block)
+ || single_pred (this_basic_block)->index != label_tick - 1)
+ label_tick_ebb_start = label_tick;
+ FOR_BB_INSNS (this_basic_block, insn)
+ if (INSN_P (insn) && BLOCK_FOR_INSN (insn))
+ {
+ subst_low_luid = DF_INSN_LUID (insn);
+ subst_insn = insn;
- if (INSN_P (insn))
- {
- note_stores (PATTERN (insn), set_nonzero_bits_and_sign_copies,
- NULL);
- record_dead_and_set_regs (insn);
+ note_stores (PATTERN (insn), set_nonzero_bits_and_sign_copies,
+ insn);
+ record_dead_and_set_regs (insn);
#ifdef AUTO_INC_DEC
- for (links = REG_NOTES (insn); links; links = XEXP (links, 1))
- if (REG_NOTE_KIND (links) == REG_INC)
- set_nonzero_bits_and_sign_copies (XEXP (links, 0), NULL_RTX,
- NULL);
+ for (links = REG_NOTES (insn); links; links = XEXP (links, 1))
+ if (REG_NOTE_KIND (links) == REG_INC)
+ set_nonzero_bits_and_sign_copies (XEXP (links, 0), NULL_RTX,
+ insn);
#endif
- /* Record the current insn_rtx_cost of this instruction. */
- if (NONJUMP_INSN_P (insn))
- uid_insn_cost[INSN_UID (insn)] = insn_rtx_cost (PATTERN (insn));
- if (dump_file)
- fprintf(dump_file, "insn_cost %d: %d\n",
- INSN_UID (insn), uid_insn_cost[INSN_UID (insn)]);
- }
-
- if (LABEL_P (insn))
- label_tick++;
+ /* Record the current insn_rtx_cost of this instruction. */
+ if (NONJUMP_INSN_P (insn))
+ INSN_COST (insn) = insn_rtx_cost (PATTERN (insn),
+ optimize_this_for_speed_p);
+ if (dump_file)
+ fprintf(dump_file, "insn_cost %d: %d\n",
+ INSN_UID (insn), INSN_COST (insn));
+ }
}
nonzero_sign_valid = 1;
/* Now scan all the insns in forward order. */
- label_tick = 1;
- last_call_cuid = 0;
- mem_last_set = 0;
+ label_tick_ebb_start = ENTRY_BLOCK_PTR->index;
init_reg_last ();
- setup_incoming_promotions ();
+ setup_incoming_promotions (first);
FOR_EACH_BB (this_basic_block)
{
+ optimize_this_for_speed_p = optimize_bb_for_speed_p (this_basic_block);
+ last_call_luid = 0;
+ mem_last_set = -1;
+ label_tick = this_basic_block->index;
+ if (!single_pred_p (this_basic_block)
+ || single_pred (this_basic_block)->index != label_tick - 1)
+ label_tick_ebb_start = label_tick;
+ rtl_profile_for_bb (this_basic_block);
for (insn = BB_HEAD (this_basic_block);
- insn != NEXT_INSN (BB_END (this_basic_block));
+ insn != NEXT_INSN (BB_END (this_basic_block));
insn = next ? next : NEXT_INSN (insn))
{
next = 0;
-
- if (LABEL_P (insn))
- label_tick++;
-
- else if (INSN_P (insn))
+ if (INSN_P (insn))
{
/* See if we know about function return values before this
insn based upon SUBREG flags. */
- check_conversions (insn, PATTERN (insn));
+ check_promoted_subreg (insn, PATTERN (insn));
+
+ /* See if we can find hardregs and subreg of pseudos in
+ narrower modes. This could help turning TRUNCATEs
+ into SUBREGs. */
+ note_uses (&PATTERN (insn), record_truncated_values, NULL);
/* Try this insn with each insn it links back to. */
be deleted or recognized by try_combine. */
rtx orig = SET_SRC (set);
SET_SRC (set) = note;
- next = try_combine (insn, temp, NULL_RTX,
+ i2mod = temp;
+ i2mod_old_rhs = copy_rtx (orig);
+ i2mod_new_rhs = copy_rtx (note);
+ next = try_combine (insn, i2mod, NULL_RTX,
&new_direct_jump_p);
+ i2mod = NULL_RTX;
if (next)
goto retry;
SET_SRC (set) = orig;
}
}
}
- clear_bb_flags ();
- EXECUTE_IF_SET_IN_SBITMAP (refresh_blocks, 0, j, sbi)
- BASIC_BLOCK (j)->flags |= BB_DIRTY;
+ default_rtl_profile ();
+ clear_log_links ();
+ clear_bb_flags ();
new_direct_jump_p |= purge_all_dead_edges ();
delete_noop_moves ();
- update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES,
- PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE
- | PROP_KILL_DEAD_CODE);
-
/* Clean up. */
- sbitmap_free (refresh_blocks);
+ free (uid_log_links);
free (uid_insn_cost);
- free (reg_stat);
- free (uid_cuid);
+ VEC_free (reg_stat_type, heap, reg_stat);
{
struct undo *undo, *next;
init_reg_last (void)
{
unsigned int i;
- for (i = 0; i < combine_max_regno; i++)
- memset (reg_stat + i, 0, offsetof (struct reg_stat, sign_bit_copies));
+ reg_stat_type *p;
+
+ for (i = 0; VEC_iterate (reg_stat_type, reg_stat, i, p); ++i)
+ memset (p, 0, offsetof (reg_stat_type, sign_bit_copies));
}
\f
/* Set up any promoted values for incoming argument registers. */
static void
-setup_incoming_promotions (void)
+setup_incoming_promotions (rtx first)
{
- unsigned int regno;
- rtx reg;
- enum machine_mode mode;
- int unsignedp;
- rtx first = get_insns ();
+ tree arg;
+ bool strictly_local = false;
- if (targetm.calls.promote_function_args (TREE_TYPE (cfun->decl)))
+ for (arg = DECL_ARGUMENTS (current_function_decl); arg;
+ arg = TREE_CHAIN (arg))
{
- for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
- /* Check whether this register can hold an incoming pointer
- argument. FUNCTION_ARG_REGNO_P tests outgoing register
- numbers, so translate if necessary due to register windows. */
- if (FUNCTION_ARG_REGNO_P (OUTGOING_REGNO (regno))
- && (reg = promoted_input_arg (regno, &mode, &unsignedp)) != 0)
- {
- record_value_for_reg
- (reg, first, gen_rtx_fmt_e ((unsignedp ? ZERO_EXTEND
- : SIGN_EXTEND),
- GET_MODE (reg),
- gen_rtx_CLOBBER (mode, const0_rtx)));
- }
+ rtx reg = DECL_INCOMING_RTL (arg);
+ int uns1, uns3;
+ enum machine_mode mode1, mode2, mode3, mode4;
+
+ /* Only continue if the incoming argument is in a register. */
+ if (!REG_P (reg))
+ continue;
+
+ /* Determine, if possible, whether all call sites of the current
+ function lie within the current compilation unit. (This does
+ take into account the exporting of a function via taking its
+ address, and so forth.) */
+ strictly_local = cgraph_local_info (current_function_decl)->local;
+
+ /* The mode and signedness of the argument before any promotions happen
+ (equal to the mode of the pseudo holding it at that stage). */
+ mode1 = TYPE_MODE (TREE_TYPE (arg));
+ uns1 = TYPE_UNSIGNED (TREE_TYPE (arg));
+
+ /* The mode and signedness of the argument after any source language and
+ TARGET_PROMOTE_PROTOTYPES-driven promotions. */
+ mode2 = TYPE_MODE (DECL_ARG_TYPE (arg));
+ uns3 = TYPE_UNSIGNED (DECL_ARG_TYPE (arg));
+
+ /* The mode and signedness of the argument as it is actually passed,
+ after any TARGET_PROMOTE_FUNCTION_ARGS-driven ABI promotions. */
+ mode3 = promote_function_mode (DECL_ARG_TYPE (arg), mode2, &uns3,
+ TREE_TYPE (cfun->decl), 0);
+
+ /* The mode of the register in which the argument is being passed. */
+ mode4 = GET_MODE (reg);
+
+ /* Eliminate sign extensions in the callee when possible. Only
+ do this when:
+ (a) a mode promotion has occurred;
+ (b) the mode of the register is the same as the mode of
+ the argument as it is passed; and
+ (c) the signedness does not change across any of the promotions; and
+ (d) when no language-level promotions (which we cannot guarantee
+ will have been done by an external caller) are necessary,
+ unless we know that this function is only ever called from
+ the current compilation unit -- all of whose call sites will
+ do the mode1 --> mode2 promotion. */
+ if (mode1 != mode3
+ && mode3 == mode4
+ && uns1 == uns3
+ && (mode1 == mode2 || strictly_local))
+ {
+ /* Record that the value was promoted from mode1 to mode3,
+ so that any sign extension at the head of the current
+ function may be eliminated. */
+ rtx x;
+ x = gen_rtx_CLOBBER (mode1, const0_rtx);
+ x = gen_rtx_fmt_e ((uns3 ? ZERO_EXTEND : SIGN_EXTEND), mode3, x);
+ record_value_for_reg (reg, first, x);
+ }
}
}
-\f
+
/* Called via note_stores. If X is a pseudo that is narrower than
HOST_BITS_PER_WIDE_INT and is being set, record what bits are known zero.
by any set of X. */
static void
-set_nonzero_bits_and_sign_copies (rtx x, rtx set,
- void *data ATTRIBUTE_UNUSED)
+set_nonzero_bits_and_sign_copies (rtx x, const_rtx set, void *data)
{
+ rtx insn = (rtx) data;
unsigned int num;
if (REG_P (x)
/* If this register is undefined at the start of the file, we can't
say what its contents were. */
&& ! REGNO_REG_SET_P
- (ENTRY_BLOCK_PTR->next_bb->il.rtl->global_live_at_start, REGNO (x))
+ (DF_LR_IN (ENTRY_BLOCK_PTR->next_bb), REGNO (x))
&& GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT)
{
+ reg_stat_type *rsp = VEC_index (reg_stat_type, reg_stat, REGNO (x));
+
if (set == 0 || GET_CODE (set) == CLOBBER)
{
- reg_stat[REGNO (x)].nonzero_bits = GET_MODE_MASK (GET_MODE (x));
- reg_stat[REGNO (x)].sign_bit_copies = 1;
+ rsp->nonzero_bits = GET_MODE_MASK (GET_MODE (x));
+ rsp->sign_bit_copies = 1;
return;
}
+ /* If this register is being initialized using itself, and the
+ register is uninitialized in this basic block, and there are
+ no LOG_LINKS which set the register, then part of the
+ register is uninitialized. In that case we can't assume
+ anything about the number of nonzero bits.
+
+ ??? We could do better if we checked this in
+ reg_{nonzero_bits,num_sign_bit_copies}_for_combine. Then we
+ could avoid making assumptions about the insn which initially
+ sets the register, while still using the information in other
+ insns. We would have to be careful to check every insn
+ involved in the combination. */
+
+ if (insn
+ && reg_referenced_p (x, PATTERN (insn))
+ && !REGNO_REG_SET_P (DF_LR_IN (BLOCK_FOR_INSN (insn)),
+ REGNO (x)))
+ {
+ rtx link;
+
+ for (link = LOG_LINKS (insn); link; link = XEXP (link, 1))
+ {
+ if (dead_or_set_p (XEXP (link, 0), x))
+ break;
+ }
+ if (!link)
+ {
+ rsp->nonzero_bits = GET_MODE_MASK (GET_MODE (x));
+ rsp->sign_bit_copies = 1;
+ return;
+ }
+ }
+
/* If this is a complex assignment, see if we can convert it into a
simple assignment. */
set = expand_field_assignment (set);
instead of this kludge. */
if (GET_MODE_BITSIZE (GET_MODE (x)) < BITS_PER_WORD
- && GET_CODE (src) == CONST_INT
+ && CONST_INT_P (src)
&& INTVAL (src) > 0
&& 0 != (INTVAL (src)
& ((HOST_WIDE_INT) 1
#endif
/* Don't call nonzero_bits if it cannot change anything. */
- if (reg_stat[REGNO (x)].nonzero_bits != ~(unsigned HOST_WIDE_INT) 0)
- reg_stat[REGNO (x)].nonzero_bits
- |= nonzero_bits (src, nonzero_bits_mode);
+ if (rsp->nonzero_bits != ~(unsigned HOST_WIDE_INT) 0)
+ rsp->nonzero_bits |= nonzero_bits (src, nonzero_bits_mode);
num = num_sign_bit_copies (SET_SRC (set), GET_MODE (x));
- if (reg_stat[REGNO (x)].sign_bit_copies == 0
- || reg_stat[REGNO (x)].sign_bit_copies > num)
- reg_stat[REGNO (x)].sign_bit_copies = num;
+ if (rsp->sign_bit_copies == 0
+ || rsp->sign_bit_copies > num)
+ rsp->sign_bit_copies = num;
}
else
{
- reg_stat[REGNO (x)].nonzero_bits = GET_MODE_MASK (GET_MODE (x));
- reg_stat[REGNO (x)].sign_bit_copies = 1;
+ rsp->nonzero_bits = GET_MODE_MASK (GET_MODE (x));
+ rsp->sign_bit_copies = 1;
}
}
}
rtx *pdest, rtx *psrc)
{
int i;
- rtx set = 0, src, dest;
+ const_rtx set = 0;
+ rtx src, dest;
rtx p;
#ifdef AUTO_INC_DEC
rtx link;
/* Don't eliminate a store in the stack pointer. */
if (dest == stack_pointer_rtx
/* Don't combine with an insn that sets a register to itself if it has
- a REG_EQUAL note. This may be part of a REG_NO_CONFLICT sequence. */
+ a REG_EQUAL note. This may be part of a LIBCALL sequence. */
|| (rtx_equal_p (src, dest) && find_reg_note (insn, REG_EQUAL, NULL_RTX))
/* Can't merge an ASM_OPERANDS. */
|| GET_CODE (src) == ASM_OPERANDS
|| (succ && FIND_REG_INC_NOTE (succ, dest))
/* Don't substitute into a non-local goto, this confuses CFG. */
|| (JUMP_P (i3) && find_reg_note (i3, REG_NON_LOCAL_GOTO, NULL_RTX))
-#if 0
- /* Don't combine the end of a libcall into anything. */
- /* ??? This gives worse code, and appears to be unnecessary, since no
- pass after flow uses REG_LIBCALL/REG_RETVAL notes. Local-alloc does
- use REG_RETVAL notes for noconflict blocks, but other code here
- makes sure that those insns don't disappear. */
- || find_reg_note (insn, REG_RETVAL, NULL_RTX)
-#endif
/* Make sure that DEST is not used after SUCC but before I3. */
|| (succ && ! all_adjacent
&& reg_used_between_p (dest, succ, i3))
|| (! all_adjacent
&& (((!MEM_P (src)
|| ! find_reg_note (insn, REG_EQUIV, src))
- && use_crosses_set_p (src, INSN_CUID (insn)))
+ && use_crosses_set_p (src, DF_INSN_LUID (insn)))
|| (GET_CODE (src) == ASM_OPERANDS && MEM_VOLATILE_P (src))
|| GET_CODE (src) == UNSPEC_VOLATILE))
- /* If there is a REG_NO_CONFLICT note for DEST in I3 or SUCC, we get
- better register allocation by not doing the combine. */
- || find_reg_note (i3, REG_NO_CONFLICT, dest)
- || (succ && find_reg_note (succ, REG_NO_CONFLICT, dest))
/* Don't combine across a CALL_INSN, because that would possibly
change whether the life span of some REGs crosses calls or not,
and it is a pain to update that information.
Exception: if source is a constant, moving it later can't hurt.
- Accept that special case, because it helps -fforce-addr a lot. */
- || (INSN_CUID (insn) < last_call_cuid && ! CONSTANT_P (src)))
+ Accept that as a special case. */
+ || (DF_INSN_LUID (insn) < last_call_luid && ! CONSTANT_P (src)))
return 0;
/* DEST must either be a REG or CC0. */
for (i = XVECLEN (PATTERN (i3), 0) - 1; i >= 0; i--)
if (GET_CODE (XVECEXP (PATTERN (i3), 0, i)) == CLOBBER)
{
- /* Don't substitute for a register intended as a clobberable
+ /* Don't substitute for a register intended as a clobberable
operand. */
rtx reg = XEXP (XVECEXP (PATTERN (i3), 0, i), 0);
if (rtx_equal_p (reg, dest))
{
/* Make sure succ doesn't contain a volatile reference. */
if (succ != 0 && volatile_refs_p (PATTERN (succ)))
- return 0;
+ return 0;
for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))
- if (INSN_P (p) && p != succ && volatile_refs_p (PATTERN (p)))
+ if (INSN_P (p) && p != succ && volatile_refs_p (PATTERN (p)))
return 0;
}
Consider:
- (set (reg:DI 101) (reg:DI 100))
+ (set (reg:DI 101) (reg:DI 100))
(set (subreg:SI (reg:DI 101) 0) <foo>)
This is NOT equivalent to:
- (parallel [(set (subreg:SI (reg:DI 100) 0) <foo>)
+ (parallel [(set (subreg:SI (reg:DI 100) 0) <foo>)
(set (reg:DI 101) (reg:DI 100))])
Not only does this modify 100 (in which case it might still be valid
return 1;
case MULT:
- return ! (GET_CODE (XEXP (x, 1)) == CONST_INT
+ return ! (CONST_INT_P (XEXP (x, 1))
&& exact_log2 (INTVAL (XEXP (x, 1))) >= 0);
default:
if (BINARY_P (x))
/* Called via note_stores by likely_spilled_retval_p. Remove from info->mask
hard registers that are known to be written to / clobbered in full. */
static void
-likely_spilled_retval_1 (rtx x, rtx set, void *data)
+likely_spilled_retval_1 (rtx x, const_rtx set, void *data)
{
- struct likely_spilled_retval_info *info = data;
+ struct likely_spilled_retval_info *const info =
+ (struct likely_spilled_retval_info *) data;
unsigned regno, nregs;
unsigned new_mask;
new_mask >>= info->regno - regno;
else
new_mask <<= regno - info->regno;
- info->mask &= new_mask;
+ info->mask &= ~new_mask;
}
/* Return nonzero iff part of the return value is live during INSN, and
info.nregs = nregs;
info.mask = mask;
for (p = PREV_INSN (use); info.mask && p != insn; p = PREV_INSN (p))
- note_stores (PATTERN (insn), likely_spilled_retval_1, &info);
+ if (INSN_P (p))
+ note_stores (PATTERN (p), likely_spilled_retval_1, &info);
mask = info.mask;
/* Check if any of the (probably) live return value registers is
static void
adjust_for_new_dest (rtx insn)
{
- rtx *loc;
-
/* For notes, be conservative and simply remove them. */
- loc = ®_NOTES (insn);
- while (*loc)
- {
- enum reg_note kind = REG_NOTE_KIND (*loc);
- if (kind == REG_EQUAL || kind == REG_EQUIV)
- *loc = XEXP (*loc, 1);
- else
- loc = &XEXP (*loc, 1);
- }
+ remove_reg_equal_equiv_notes (insn);
/* The new insn will have a destination that was previously the destination
of an insn just above it. Call distribute_links to make a LOG_LINK from
the next use of that destination. */
distribute_links (gen_rtx_INSN_LIST (VOIDmode, insn, NULL_RTX));
+
+ df_insn_rescan (insn);
}
/* Return TRUE if combine can reuse reg X in mode MODE.
}
+/* Delete the conditional jump INSN and adjust the CFG correspondingly.
+ Note that the INSN should be deleted *after* removing dead edges, so
+ that the kept edge is the fallthrough edge for a (set (pc) (pc))
+ but not for a (set (pc) (label_ref FOO)). */
+
+static void
+update_cfg_for_uncondjump (rtx insn)
+{
+ basic_block bb = BLOCK_FOR_INSN (insn);
+
+ if (BB_END (bb) == insn)
+ purge_dead_edges (bb);
+
+ delete_insn (insn);
+ if (EDGE_COUNT (bb->succs) == 1)
+ single_succ_edge (bb)->flags |= EDGE_FALLTHRU;
+}
+
+
/* Try to combine the insns I1 and I2 into I3.
Here I1 and I2 appear earlier than I3.
I1 can be zero; then we combine just I2 into I3.
rtx i3dest_killed = 0;
/* SET_DEST and SET_SRC of I2 and I1. */
rtx i2dest, i2src, i1dest = 0, i1src = 0;
- /* PATTERN (I2), or a copy of it in certain cases. */
- rtx i2pat;
+ /* PATTERN (I1) and PATTERN (I2), or a copy of it in certain cases. */
+ rtx i1pat = 0, i2pat = 0;
/* Indicates if I2DEST or I1DEST is in I2SRC or I1_SRC. */
int i2dest_in_i2src = 0, i1dest_in_i1src = 0, i2dest_in_i1src = 0;
int i2dest_killed = 0, i1dest_killed = 0;
/* Notes that I1, I2 or I3 is a MULT operation. */
int have_mult = 0;
int swap_i2i3 = 0;
+ int changed_i3_dest = 0;
int maxreg;
rtx temp;
rtx link;
+ rtx other_pat = 0;
+ rtx new_other_notes;
int i;
/* Exit early if one of the insns involved can't be used for
if (cant_combine_insn_p (i3)
|| cant_combine_insn_p (i2)
|| (i1 && cant_combine_insn_p (i1))
- || likely_spilled_retval_p (i3)
- /* We also can't do anything if I3 has a
- REG_LIBCALL note since we don't want to disrupt the contiguity of a
- libcall. */
-#if 0
- /* ??? This gives worse code, and appears to be unnecessary, since no
- pass after flow uses REG_LIBCALL/REG_RETVAL notes. */
- || find_reg_note (i3, REG_LIBCALL, NULL_RTX)
-#endif
- )
+ || likely_spilled_retval_p (i3))
return 0;
combine_attempts++;
/* Reset the hard register usage information. */
CLEAR_HARD_REG_SET (newpat_used_regs);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ if (i1)
+ fprintf (dump_file, "\nTrying %d, %d -> %d:\n",
+ INSN_UID (i1), INSN_UID (i2), INSN_UID (i3));
+ else
+ fprintf (dump_file, "\nTrying %d -> %d:\n",
+ INSN_UID (i2), INSN_UID (i3));
+ }
+
/* If I1 and I2 both feed I3, they can be in any order. To simplify the
code below, set I1 to be the earlier of the two insns. */
- if (i1 && INSN_CUID (i1) > INSN_CUID (i2))
+ if (i1 && DF_INSN_LUID (i1) > DF_INSN_LUID (i2))
temp = i1, i1 = i2, i2 = temp;
added_links_insn = 0;
combine_merges++;
subst_insn = i3;
- subst_low_cuid = INSN_CUID (i2);
+ subst_low_luid = DF_INSN_LUID (i2);
added_sets_2 = added_sets_1 = 0;
i2dest = SET_SRC (PATTERN (i3));
constant. */
if (i1 == 0
&& (temp = single_set (i2)) != 0
- && (GET_CODE (SET_SRC (temp)) == CONST_INT
+ && (CONST_INT_P (SET_SRC (temp))
|| GET_CODE (SET_SRC (temp)) == CONST_DOUBLE)
&& GET_CODE (PATTERN (i3)) == SET
- && (GET_CODE (SET_SRC (PATTERN (i3))) == CONST_INT
+ && (CONST_INT_P (SET_SRC (PATTERN (i3)))
|| GET_CODE (SET_SRC (PATTERN (i3))) == CONST_DOUBLE)
&& reg_subword_p (SET_DEST (PATTERN (i3)), SET_DEST (temp)))
{
if (GET_CODE (dest) == ZERO_EXTRACT)
{
- if (GET_CODE (XEXP (dest, 1)) == CONST_INT
- && GET_CODE (XEXP (dest, 2)) == CONST_INT)
+ if (CONST_INT_P (XEXP (dest, 1))
+ && CONST_INT_P (XEXP (dest, 2)))
{
width = INTVAL (XEXP (dest, 1));
offset = INTVAL (XEXP (dest, 2));
offset = -1;
}
- if (offset >= 0)
+ if (offset >= 0
+ && (GET_MODE_BITSIZE (GET_MODE (SET_DEST (temp)))
+ <= HOST_BITS_PER_WIDE_INT * 2))
{
HOST_WIDE_INT mhi, ohi, ihi;
HOST_WIDE_INT mlo, olo, ilo;
rtx inner = SET_SRC (PATTERN (i3));
rtx outer = SET_SRC (temp);
- if (GET_CODE (outer) == CONST_INT)
+ if (CONST_INT_P (outer))
{
olo = INTVAL (outer);
ohi = olo < 0 ? -1 : 0;
ohi = CONST_DOUBLE_HIGH (outer);
}
- if (GET_CODE (inner) == CONST_INT)
+ if (CONST_INT_P (inner))
{
ilo = INTVAL (inner);
ihi = ilo < 0 ? -1 : 0;
combine_merges++;
subst_insn = i3;
- subst_low_cuid = INSN_CUID (i2);
+ subst_low_luid = DF_INSN_LUID (i2);
added_sets_2 = added_sets_1 = 0;
i2dest = SET_DEST (temp);
i2dest_killed = dead_or_set_p (i2, i2dest);
make up a dummy I1 that is
(set Y OP)
and change I2 to be
- (set (reg:CC X) (compare:CC Y (const_int 0)))
+ (set (reg:CC X) (compare:CC Y (const_int 0)))
(We can ignore any trailing CLOBBERs.)
if (i == 1)
{
/* We make I1 with the same INSN_UID as I2. This gives it
- the same INSN_CUID for value tracking. Our fake I1 will
+ the same DF_INSN_LUID for value tracking. Our fake I1 will
never appear in the insn stream so giving it the same INSN_UID
as I2 will not cause a problem. */
i1 = gen_rtx_INSN (VOIDmode, INSN_UID (i2), NULL_RTX, i2,
BLOCK_FOR_INSN (i2), INSN_LOCATOR (i2),
- XVECEXP (PATTERN (i2), 0, 1), -1, NULL_RTX,
- NULL_RTX);
+ XVECEXP (PATTERN (i2), 0, 1), -1, NULL_RTX);
SUBST (PATTERN (i2), XVECEXP (PATTERN (i2), 0, 0));
SUBST (XEXP (SET_SRC (PATTERN (i2)), 0),
rtx. If I2 is a PARALLEL, we just need the piece that assigns I2SRC to
I2DEST. */
- i2pat = (GET_CODE (PATTERN (i2)) == PARALLEL
- ? gen_rtx_SET (VOIDmode, i2dest, i2src)
- : PATTERN (i2));
-
if (added_sets_2)
- i2pat = copy_rtx (i2pat);
+ {
+ if (GET_CODE (PATTERN (i2)) == PARALLEL)
+ i2pat = gen_rtx_SET (VOIDmode, i2dest, copy_rtx (i2src));
+ else
+ i2pat = copy_rtx (PATTERN (i2));
+ }
+
+ if (added_sets_1)
+ {
+ if (GET_CODE (PATTERN (i1)) == PARALLEL)
+ i1pat = gen_rtx_SET (VOIDmode, i1dest, copy_rtx (i1src));
+ else
+ i1pat = copy_rtx (PATTERN (i1));
+ }
combine_merges++;
simplifications. */
if (i1)
{
- subst_low_cuid = INSN_CUID (i1);
+ subst_low_luid = DF_INSN_LUID (i1);
i1src = subst (i1src, pc_rtx, pc_rtx, 0, 0);
}
else
{
- subst_low_cuid = INSN_CUID (i2);
+ subst_low_luid = DF_INSN_LUID (i2);
i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0);
}
}
need to make a unique copy of I2SRC each time we substitute it
to avoid self-referential rtl. */
- subst_low_cuid = INSN_CUID (i2);
+ subst_low_luid = DF_INSN_LUID (i2);
newpat = subst (PATTERN (i3), i2dest, i2src, 0,
! i1_feeds_i3 && i1dest_in_i1src);
substed_i2 = 1;
if (i1 && GET_CODE (newpat) != CLOBBER)
{
- /* 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. */
-
- if (! combinable_i3pat (NULL_RTX, &newpat, i1dest, NULL_RTX,
- 0, (rtx*) 0))
+ /* Check that an autoincrement side-effect on I1 has not been lost.
+ This happens if I1DEST is mentioned in I2 and dies there, and
+ has disappeared from the new pattern. */
+ if ((FIND_REG_INC_NOTE (i1, NULL_RTX) != 0
+ && !i1_feeds_i3
+ && dead_or_set_p (i2, i1dest)
+ && !reg_overlap_mentioned_p (i1dest, newpat))
+ /* 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. */
+ || !combinable_i3pat (NULL_RTX, &newpat, i1dest, NULL_RTX, 0, 0))
{
undo_all ();
return 0;
}
n_occurrences = 0;
- subst_low_cuid = INSN_CUID (i1);
+ subst_low_luid = DF_INSN_LUID (i1);
newpat = subst (newpat, i1dest, i1src, 0, 0);
substed_i1 = 1;
}
}
if (added_sets_1)
- XVECEXP (newpat, 0, --total_sets)
- = (GET_CODE (PATTERN (i1)) == PARALLEL
- ? gen_rtx_SET (VOIDmode, i1dest, i1src) : PATTERN (i1));
+ XVECEXP (newpat, 0, --total_sets) = i1pat;
if (added_sets_2)
{
insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
if (insn_code_number >= 0)
- {
- /* If we will be able to accept this, we have made a
- change to the destination of I3. This requires us to
- do a few adjustments. */
-
- PATTERN (i3) = newpat;
- adjust_for_new_dest (i3);
- }
+ changed_i3_dest = 1;
}
}
if (i1 && insn_code_number < 0 && GET_CODE (newpat) == SET
&& asm_noperands (newpat) < 0)
{
- rtx m_split, *split;
+ rtx parallel, m_split, *split;
/* See if the MD file can split NEWPAT. If it can't, see if letting it
use I2DEST as a scratch register will help. In the latter case,
convert I2DEST to the mode of the source of NEWPAT if we can. */
- m_split = split_insns (newpat, i3);
+ m_split = combine_split_insns (newpat, i3);
/* We can only use I2DEST as a scratch reg if it doesn't overlap any
inputs of NEWPAT. */
/* First try to split using the original register as a
scratch register. */
- m_split = split_insns (gen_rtx_PARALLEL
- (VOIDmode,
- gen_rtvec (2, newpat,
- gen_rtx_CLOBBER (VOIDmode,
- i2dest))),
- i3);
+ parallel = gen_rtx_PARALLEL (VOIDmode,
+ gen_rtvec (2, newpat,
+ gen_rtx_CLOBBER (VOIDmode,
+ i2dest)));
+ m_split = combine_split_insns (parallel, i3);
/* If that didn't work, try changing the mode of I2DEST if
we can. */
ni2dest = regno_reg_rtx[REGNO (i2dest)];
}
- m_split = split_insns (gen_rtx_PARALLEL
- (VOIDmode,
- gen_rtvec (2, newpat,
- gen_rtx_CLOBBER (VOIDmode,
- ni2dest))),
- i3);
+ parallel = (gen_rtx_PARALLEL
+ (VOIDmode,
+ gen_rtvec (2, newpat,
+ gen_rtx_CLOBBER (VOIDmode,
+ ni2dest))));
+ m_split = combine_split_insns (parallel, i3);
if (m_split == 0
&& REGNO (i2dest) >= FIRST_PSEUDO_REGISTER)
{
struct undo *buf;
- PUT_MODE (regno_reg_rtx[REGNO (i2dest)], old_mode);
+ adjust_reg_mode (regno_reg_rtx[REGNO (i2dest)], old_mode);
buf = undobuf.undos;
undobuf.undos = buf->next;
buf->next = undobuf.frees;
/* If recog_for_combine has discarded clobbers, try to use them
again for the split. */
if (m_split == 0 && newpat_vec_with_clobbers)
- m_split
- = split_insns (gen_rtx_PARALLEL (VOIDmode,
- newpat_vec_with_clobbers), i3);
+ {
+ parallel = gen_rtx_PARALLEL (VOIDmode, newpat_vec_with_clobbers);
+ m_split = combine_split_insns (parallel, i3);
+ }
if (m_split && NEXT_INSN (m_split) == NULL_RTX)
{
}
else if (m_split && NEXT_INSN (NEXT_INSN (m_split)) == NULL_RTX
&& (next_real_insn (i2) == i3
- || ! use_crosses_set_p (PATTERN (m_split), INSN_CUID (i2))))
+ || ! use_crosses_set_p (PATTERN (m_split), DF_INSN_LUID (i2))))
{
rtx i2set, i3set;
rtx newi3pat = PATTERN (NEXT_INSN (m_split));
if (REG_P (new_i3_dest)
&& REG_P (new_i2_dest)
&& REGNO (new_i3_dest) == REGNO (new_i2_dest))
- REG_N_SETS (REGNO (new_i2_dest))++;
+ INC_REG_N_SETS (REGNO (new_i2_dest), 1);
}
}
|| can_change_dest_mode (i2dest, added_sets_2,
GET_MODE (*split)))
&& (next_real_insn (i2) == i3
- || ! use_crosses_set_p (*split, INSN_CUID (i2)))
+ || ! use_crosses_set_p (*split, DF_INSN_LUID (i2)))
/* We can't overwrite I2DEST if its value is still used by
NEWPAT. */
&& ! reg_referenced_p (i2dest, newpat))
an ASHIFT. This can occur if it was inside a PLUS and hence
appeared to be a memory address. This is a kludge. */
if (split_code == MULT
- && GET_CODE (XEXP (*split, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (*split, 1))
&& INTVAL (XEXP (*split, 1)) > 0
&& (i = exact_log2 (INTVAL (XEXP (*split, 1)))) >= 0)
{
&& rtx_equal_p (SET_SRC (XVECEXP (newpat, 0, 1)),
XEXP (SET_SRC (XVECEXP (newpat, 0, 0)), 0))
&& ! use_crosses_set_p (SET_SRC (XVECEXP (newpat, 0, 1)),
- INSN_CUID (i2))
+ DF_INSN_LUID (i2))
&& GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != ZERO_EXTRACT
&& GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != STRICT_LOW_PART
&& ! (temp = SET_DEST (XVECEXP (newpat, 0, 1)),
(REG_P (temp)
- && reg_stat[REGNO (temp)].nonzero_bits != 0
+ && VEC_index (reg_stat_type, reg_stat,
+ REGNO (temp))->nonzero_bits != 0
&& GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD
&& GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT
- && (reg_stat[REGNO (temp)].nonzero_bits
+ && (VEC_index (reg_stat_type, reg_stat,
+ REGNO (temp))->nonzero_bits
!= GET_MODE_MASK (word_mode))))
&& ! (GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) == SUBREG
&& (temp = SUBREG_REG (SET_DEST (XVECEXP (newpat, 0, 1))),
(REG_P (temp)
- && reg_stat[REGNO (temp)].nonzero_bits != 0
+ && VEC_index (reg_stat_type, reg_stat,
+ REGNO (temp))->nonzero_bits != 0
&& GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD
&& GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT
- && (reg_stat[REGNO (temp)].nonzero_bits
+ && (VEC_index (reg_stat_type, reg_stat,
+ REGNO (temp))->nonzero_bits
!= GET_MODE_MASK (word_mode)))))
&& ! reg_overlap_mentioned_p (SET_DEST (XVECEXP (newpat, 0, 1)),
SET_SRC (XVECEXP (newpat, 0, 1)))
&& GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != ZERO_EXTRACT
&& GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != STRICT_LOW_PART
&& ! use_crosses_set_p (SET_SRC (XVECEXP (newpat, 0, 1)),
- INSN_CUID (i2))
+ DF_INSN_LUID (i2))
&& ! reg_referenced_p (SET_DEST (XVECEXP (newpat, 0, 1)),
XVECEXP (newpat, 0, 0))
&& ! reg_referenced_p (SET_DEST (XVECEXP (newpat, 0, 0)),
XVECEXP (newpat, 0, 1))
&& ! (contains_muldiv (SET_SRC (XVECEXP (newpat, 0, 0)))
- && contains_muldiv (SET_SRC (XVECEXP (newpat, 0, 1)))))
+ && contains_muldiv (SET_SRC (XVECEXP (newpat, 0, 1))))
+#ifdef HAVE_cc0
+ /* We cannot split the parallel into two sets if both sets
+ reference cc0. */
+ && ! (reg_referenced_p (cc0_rtx, XVECEXP (newpat, 0, 0))
+ && reg_referenced_p (cc0_rtx, XVECEXP (newpat, 0, 1)))
+#endif
+ )
{
/* Normally, it doesn't matter which of the two is done first,
but it does if one references cc0. In that case, it has to
/* If we had to change another insn, make sure it is valid also. */
if (undobuf.other_insn)
{
- rtx other_pat = PATTERN (undobuf.other_insn);
- rtx new_other_notes;
- rtx note, next;
-
CLEAR_HARD_REG_SET (newpat_used_regs);
+ other_pat = PATTERN (undobuf.other_insn);
other_code_number = recog_for_combine (&other_pat, undobuf.other_insn,
&new_other_notes);
undo_all ();
return 0;
}
-
- PATTERN (undobuf.other_insn) = other_pat;
-
- /* If any of the notes in OTHER_INSN were REG_UNUSED, ensure that they
- are still valid. Then add any non-duplicate notes added by
- recog_for_combine. */
- for (note = REG_NOTES (undobuf.other_insn); note; note = next)
- {
- next = XEXP (note, 1);
-
- if (REG_NOTE_KIND (note) == REG_UNUSED
- && ! reg_set_p (XEXP (note, 0), PATTERN (undobuf.other_insn)))
- {
- if (REG_P (XEXP (note, 0)))
- REG_N_DEATHS (REGNO (XEXP (note, 0)))--;
-
- remove_note (undobuf.other_insn, note);
- }
- }
-
- for (note = new_other_notes; note; note = XEXP (note, 1))
- if (REG_P (XEXP (note, 0)))
- REG_N_DEATHS (REGNO (XEXP (note, 0)))++;
-
- distribute_notes (new_other_notes, undobuf.other_insn,
- undobuf.other_insn, NULL_RTX, NULL_RTX, NULL_RTX);
}
+
#ifdef HAVE_cc0
/* If I2 is the CC0 setter and I3 is the CC0 user then check whether
they are adjacent to each other or not. */
/* Only allow this combination if insn_rtx_costs reports that the
replacement instructions are cheaper than the originals. */
- if (!combine_validate_cost (i1, i2, i3, newpat, newi2pat))
+ if (!combine_validate_cost (i1, i2, i3, newpat, newi2pat, other_pat))
{
undo_all ();
return 0;
}
+ /* If we will be able to accept this, we have made a
+ change to the destination of I3. This requires us to
+ do a few adjustments. */
+
+ if (changed_i3_dest)
+ {
+ PATTERN (i3) = newpat;
+ adjust_for_new_dest (i3);
+ }
+
/* We now know that we can do this combination. Merge the insns and
update the status of registers and LOG_LINKS. */
+ if (undobuf.other_insn)
+ {
+ rtx note, next;
+
+ PATTERN (undobuf.other_insn) = other_pat;
+
+ /* If any of the notes in OTHER_INSN were REG_UNUSED, ensure that they
+ are still valid. Then add any non-duplicate notes added by
+ recog_for_combine. */
+ for (note = REG_NOTES (undobuf.other_insn); note; note = next)
+ {
+ next = XEXP (note, 1);
+
+ if (REG_NOTE_KIND (note) == REG_UNUSED
+ && ! reg_set_p (XEXP (note, 0), PATTERN (undobuf.other_insn)))
+ remove_note (undobuf.other_insn, note);
+ }
+
+ distribute_notes (new_other_notes, undobuf.other_insn,
+ undobuf.other_insn, NULL_RTX, NULL_RTX, NULL_RTX);
+ }
+
if (swap_i2i3)
{
rtx insn;
rtx ni2dest;
/* I3 now uses what used to be its destination and which is now
- I2's destination. This requires us to do a few adjustments. */
+ I2's destination. This requires us to do a few adjustments. */
PATTERN (i3) = newpat;
adjust_for_new_dest (i3);
/* We need a LOG_LINK from I3 to I2. But we used to have one,
- so we still will.
+ so we still will.
However, some later insn might be using I2's dest and have
a LOG_LINK pointing at I3. We must remove this link.
if (i3_subst_into_i2)
{
for (i = 0; i < XVECLEN (PATTERN (i2), 0); i++)
- if (GET_CODE (XVECEXP (PATTERN (i2), 0, i)) != USE
+ if ((GET_CODE (XVECEXP (PATTERN (i2), 0, i)) == SET
+ || GET_CODE (XVECEXP (PATTERN (i2), 0, i)) == CLOBBER)
&& REG_P (SET_DEST (XVECEXP (PATTERN (i2), 0, i)))
&& SET_DEST (XVECEXP (PATTERN (i2), 0, i)) != i2dest
&& ! find_reg_note (i2, REG_UNUSED,
if (newi2pat)
{
- move_deaths (newi2pat, NULL_RTX, INSN_CUID (i1), i2, &midnotes);
- move_deaths (newpat, newi2pat, INSN_CUID (i1), i3, &midnotes);
+ move_deaths (newi2pat, NULL_RTX, DF_INSN_LUID (i1), i2, &midnotes);
+ move_deaths (newpat, newi2pat, DF_INSN_LUID (i1), i3, &midnotes);
}
else
- move_deaths (newpat, NULL_RTX, i1 ? INSN_CUID (i1) : INSN_CUID (i2),
+ move_deaths (newpat, NULL_RTX, i1 ? DF_INSN_LUID (i1) : DF_INSN_LUID (i2),
i3, &midnotes);
/* Distribute all the LOG_LINKS and REG_NOTES from I1, I2, and I3. */
/* Distribute any notes added to I2 or I3 by recog_for_combine. We
know these are REG_UNUSED and want them to go to the desired insn,
- so we always pass it as i3. We have not counted the notes in
- reg_n_deaths yet, so we need to do so now. */
+ so we always pass it as i3. */
if (newi2pat && new_i2_notes)
- {
- for (temp = new_i2_notes; temp; temp = XEXP (temp, 1))
- if (REG_P (XEXP (temp, 0)))
- REG_N_DEATHS (REGNO (XEXP (temp, 0)))++;
-
- distribute_notes (new_i2_notes, i2, i2, NULL_RTX, NULL_RTX, NULL_RTX);
- }
-
+ distribute_notes (new_i2_notes, i2, i2, NULL_RTX, NULL_RTX, NULL_RTX);
+
if (new_i3_notes)
- {
- for (temp = new_i3_notes; temp; temp = XEXP (temp, 1))
- if (REG_P (XEXP (temp, 0)))
- REG_N_DEATHS (REGNO (XEXP (temp, 0)))++;
-
- distribute_notes (new_i3_notes, i3, i3, NULL_RTX, NULL_RTX, NULL_RTX);
- }
+ distribute_notes (new_i3_notes, i3, i3, NULL_RTX, NULL_RTX, NULL_RTX);
/* If I3DEST was used in I3SRC, it really died in I3. We may need to
put a REG_DEAD note for it somewhere. If NEWI2PAT exists and sets
if (i3dest_killed)
{
- if (REG_P (i3dest_killed))
- REG_N_DEATHS (REGNO (i3dest_killed))++;
-
if (newi2pat && reg_set_p (i3dest_killed, newi2pat))
- distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i3dest_killed,
- NULL_RTX),
+ distribute_notes (alloc_reg_note (REG_DEAD, i3dest_killed,
+ NULL_RTX),
NULL_RTX, i2, NULL_RTX, elim_i2, elim_i1);
else
- distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i3dest_killed,
- NULL_RTX),
+ distribute_notes (alloc_reg_note (REG_DEAD, i3dest_killed,
+ NULL_RTX),
NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
elim_i2, elim_i1);
}
if (i2dest_in_i2src)
{
- if (REG_P (i2dest))
- REG_N_DEATHS (REGNO (i2dest))++;
-
if (newi2pat && reg_set_p (i2dest, newi2pat))
- distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i2dest, NULL_RTX),
+ distribute_notes (alloc_reg_note (REG_DEAD, i2dest, NULL_RTX),
NULL_RTX, i2, NULL_RTX, NULL_RTX, NULL_RTX);
else
- distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i2dest, NULL_RTX),
+ distribute_notes (alloc_reg_note (REG_DEAD, i2dest, NULL_RTX),
NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
NULL_RTX, NULL_RTX);
}
if (i1dest_in_i1src)
{
- if (REG_P (i1dest))
- REG_N_DEATHS (REGNO (i1dest))++;
-
if (newi2pat && reg_set_p (i1dest, newi2pat))
- distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i1dest, NULL_RTX),
+ distribute_notes (alloc_reg_note (REG_DEAD, i1dest, NULL_RTX),
NULL_RTX, i2, NULL_RTX, NULL_RTX, NULL_RTX);
else
- distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i1dest, NULL_RTX),
+ distribute_notes (alloc_reg_note (REG_DEAD, i1dest, NULL_RTX),
NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
NULL_RTX, NULL_RTX);
}
&& ! i2dest_in_i2src)
{
regno = REGNO (i2dest);
- REG_N_SETS (regno)--;
+ INC_REG_N_SETS (regno, -1);
}
}
regno = REGNO (i1dest);
if (! added_sets_1 && ! i1dest_in_i1src)
- REG_N_SETS (regno)--;
+ INC_REG_N_SETS (regno, -1);
}
/* Update reg_stat[].nonzero_bits et al for any changes that may have
if (newi2pat)
note_stores (newi2pat, set_nonzero_bits_and_sign_copies, NULL);
note_stores (newpat, set_nonzero_bits_and_sign_copies, NULL);
+ }
- /* Set new_direct_jump_p if a new return or simple jump instruction
- has been created.
-
- If I3 is now an unconditional jump, ensure that it has a
- BARRIER following it since it may have initially been a
- conditional jump. It may also be the last nonnote insn. */
+ if (undobuf.other_insn != NULL_RTX)
+ {
+ if (dump_file)
+ {
+ fprintf (dump_file, "modifying other_insn ");
+ dump_insn_slim (dump_file, undobuf.other_insn);
+ }
+ df_insn_rescan (undobuf.other_insn);
+ }
- if (returnjump_p (i3) || any_uncondjump_p (i3))
- {
- *new_direct_jump_p = 1;
- mark_jump_label (PATTERN (i3), i3, 0);
+ if (i1 && !(NOTE_P(i1) && (NOTE_KIND (i1) == NOTE_INSN_DELETED)))
+ {
+ if (dump_file)
+ {
+ fprintf (dump_file, "modifying insn i1 ");
+ dump_insn_slim (dump_file, i1);
+ }
+ df_insn_rescan (i1);
+ }
- if ((temp = next_nonnote_insn (i3)) == NULL_RTX
- || !BARRIER_P (temp))
- emit_barrier_after (i3);
- }
+ if (i2 && !(NOTE_P(i2) && (NOTE_KIND (i2) == NOTE_INSN_DELETED)))
+ {
+ if (dump_file)
+ {
+ fprintf (dump_file, "modifying insn i2 ");
+ dump_insn_slim (dump_file, i2);
+ }
+ df_insn_rescan (i2);
+ }
- if (undobuf.other_insn != NULL_RTX
- && (returnjump_p (undobuf.other_insn)
- || any_uncondjump_p (undobuf.other_insn)))
- {
- *new_direct_jump_p = 1;
+ if (i3 && !(NOTE_P(i3) && (NOTE_KIND (i3) == NOTE_INSN_DELETED)))
+ {
+ if (dump_file)
+ {
+ fprintf (dump_file, "modifying insn i3 ");
+ dump_insn_slim (dump_file, i3);
+ }
+ df_insn_rescan (i3);
+ }
+
+ /* Set new_direct_jump_p if a new return or simple jump instruction
+ has been created. Adjust the CFG accordingly. */
- if ((temp = next_nonnote_insn (undobuf.other_insn)) == NULL_RTX
- || !BARRIER_P (temp))
- emit_barrier_after (undobuf.other_insn);
- }
+ if (returnjump_p (i3) || any_uncondjump_p (i3))
+ {
+ *new_direct_jump_p = 1;
+ mark_jump_label (PATTERN (i3), i3, 0);
+ update_cfg_for_uncondjump (i3);
+ }
- /* An NOOP jump does not need barrier, but it does need cleaning up
- of CFG. */
- if (GET_CODE (newpat) == SET
- && SET_SRC (newpat) == pc_rtx
- && SET_DEST (newpat) == pc_rtx)
+ if (undobuf.other_insn != NULL_RTX
+ && (returnjump_p (undobuf.other_insn)
+ || any_uncondjump_p (undobuf.other_insn)))
+ {
*new_direct_jump_p = 1;
- }
+ update_cfg_for_uncondjump (undobuf.other_insn);
+ }
+ /* A noop might also need cleaning up of CFG, if it comes from the
+ simplification of a jump. */
+ if (GET_CODE (newpat) == SET
+ && SET_SRC (newpat) == pc_rtx
+ && SET_DEST (newpat) == pc_rtx)
+ {
+ *new_direct_jump_p = 1;
+ update_cfg_for_uncondjump (i3);
+ }
+
combine_successes++;
undo_commit ();
if (added_links_insn
- && (newi2pat == 0 || INSN_CUID (added_links_insn) < INSN_CUID (i2))
- && INSN_CUID (added_links_insn) < INSN_CUID (i3))
+ && (newi2pat == 0 || DF_INSN_LUID (added_links_insn) < DF_INSN_LUID (i2))
+ && DF_INSN_LUID (added_links_insn) < DF_INSN_LUID (i3))
return added_links_insn;
else
return newi2pat ? i2 : i3;
*undo->where.i = undo->old_contents.i;
break;
case UNDO_MODE:
- PUT_MODE (*undo->where.r, undo->old_contents.m);
+ adjust_reg_mode (*undo->where.r, undo->old_contents.m);
break;
default:
gcc_unreachable ();
}
undobuf.undos = 0;
}
-
\f
/* Find the innermost point within the rtx at LOC, possibly LOC itself,
where we have an arithmetic expression and return that point. LOC will
the first pseudo-reg (one of the virtual regs) as a placeholder;
it will not remain in the result. */
if (GET_CODE (XEXP (x, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+ && CONST_INT_P (XEXP (XEXP (x, 0), 1))
&& ! memory_address_p (GET_MODE (x), XEXP (x, 0)))
{
rtx reg = regno_reg_rtx[FIRST_PSEUDO_REGISTER];
- rtx seq = split_insns (gen_rtx_SET (VOIDmode, reg, XEXP (x, 0)),
- subst_insn);
+ rtx seq = combine_split_insns (gen_rtx_SET (VOIDmode, reg,
+ XEXP (x, 0)),
+ subst_insn);
/* This should have produced two insns, each of which sets our
placeholder. If the source of the second is a valid address,
&& OBJECT_P (SUBREG_REG (XEXP (XEXP (x, 0), 0)))))
return &XEXP (XEXP (x, 0), 0);
}
+
+ /* If we have a PLUS whose first operand is complex, try computing it
+ separately by making a split there. */
+ if (GET_CODE (XEXP (x, 0)) == PLUS
+ && ! memory_address_p (GET_MODE (x), XEXP (x, 0))
+ && ! OBJECT_P (XEXP (XEXP (x, 0), 0))
+ && ! (GET_CODE (XEXP (XEXP (x, 0), 0)) == SUBREG
+ && OBJECT_P (SUBREG_REG (XEXP (XEXP (x, 0), 0)))))
+ return &XEXP (XEXP (x, 0), 0);
break;
case SET:
if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT
&& (GET_MODE_BITSIZE (GET_MODE (XEXP (SET_DEST (x), 0)))
<= HOST_BITS_PER_WIDE_INT)
- && GET_CODE (XEXP (SET_DEST (x), 1)) == CONST_INT
- && GET_CODE (XEXP (SET_DEST (x), 2)) == CONST_INT
- && GET_CODE (SET_SRC (x)) == CONST_INT
+ && CONST_INT_P (XEXP (SET_DEST (x), 1))
+ && CONST_INT_P (XEXP (SET_DEST (x), 2))
+ && CONST_INT_P (SET_SRC (x))
&& ((INTVAL (XEXP (SET_DEST (x), 1))
+ INTVAL (XEXP (SET_DEST (x), 2)))
<= GET_MODE_BITSIZE (GET_MODE (XEXP (SET_DEST (x), 0))))
rtx negmask = gen_int_mode (~(mask << pos), mode);
SUBST (SET_SRC (x),
simplify_gen_binary (IOR, mode,
- simplify_gen_binary (AND, mode,
+ simplify_gen_binary (AND, mode,
dest, negmask),
or_mask));
}
this is no worse, but if it took more than one insn, it will
be better. */
- if (GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT
+ if (CONST_INT_P (XEXP (SET_SRC (x), 1))
&& REG_P (XEXP (SET_SRC (x), 0))
&& (pos = exact_log2 (INTVAL (XEXP (SET_SRC (x), 1)))) >= 7
&& REG_P (SET_DEST (x))
case SIGN_EXTRACT:
case ZERO_EXTRACT:
- if (GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT
- && GET_CODE (XEXP (SET_SRC (x), 2)) == CONST_INT)
+ if (CONST_INT_P (XEXP (SET_SRC (x), 1))
+ && CONST_INT_P (XEXP (SET_SRC (x), 2)))
{
inner = XEXP (SET_SRC (x), 0);
len = INTVAL (XEXP (SET_SRC (x), 1));
enum machine_mode op0_mode = VOIDmode;
const char *fmt;
int len, i;
- rtx new;
+ rtx new_rtx;
/* Two expressions are equal if they are identical copies of a shared
RTX or if they are both registers with the same register number
return (unique_copy && n_occurrences > 1 ? copy_rtx (to) : to);
}
- /* If X and FROM are the same register but different modes, they will
- not have been seen as equal above. However, flow.c will make a
- LOG_LINKS entry for that case. If we do nothing, we will try to
- rerecognize our original insn and, when it succeeds, we will
- delete the feeding insn, which is incorrect.
+ /* If X and FROM are the same register but different modes, they
+ will not have been seen as equal above. However, the log links code
+ will make a LOG_LINKS entry for that case. If we do nothing, we
+ will try to rerecognize our original insn and, when it succeeds,
+ we will delete the feeding insn, which is incorrect.
So force this insn not to match in this (rare) case. */
if (! in_dest && code == REG && REG_P (from)
- && REGNO (x) == REGNO (from))
+ && reg_overlap_mentioned_p (x, from))
return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
/* If this is an object, we are done unless it is a MEM or LO_SUM, both
&& GET_CODE (XVECEXP (x, 0, 0)) == SET
&& GET_CODE (SET_SRC (XVECEXP (x, 0, 0))) == ASM_OPERANDS)
{
- new = subst (XVECEXP (x, 0, 0), from, to, 0, unique_copy);
+ new_rtx = subst (XVECEXP (x, 0, 0), from, to, 0, unique_copy);
/* If this substitution failed, this whole thing fails. */
- if (GET_CODE (new) == CLOBBER
- && XEXP (new, 0) == const0_rtx)
- return new;
+ if (GET_CODE (new_rtx) == CLOBBER
+ && XEXP (new_rtx, 0) == const0_rtx)
+ return new_rtx;
- SUBST (XVECEXP (x, 0, 0), new);
+ SUBST (XVECEXP (x, 0, 0), new_rtx);
for (i = XVECLEN (x, 0) - 1; i >= 1; i--)
{
&& GET_CODE (dest) != CC0
&& GET_CODE (dest) != PC)
{
- new = subst (dest, from, to, 0, unique_copy);
+ new_rtx = subst (dest, from, to, 0, unique_copy);
/* If this substitution failed, this whole thing fails. */
- if (GET_CODE (new) == CLOBBER
- && XEXP (new, 0) == const0_rtx)
- return new;
+ if (GET_CODE (new_rtx) == CLOBBER
+ && XEXP (new_rtx, 0) == const0_rtx)
+ return new_rtx;
- SUBST (SET_DEST (XVECEXP (x, 0, i)), new);
+ SUBST (SET_DEST (XVECEXP (x, 0, i)), new_rtx);
}
}
}
{
if (COMBINE_RTX_EQUAL_P (XVECEXP (x, i, j), from))
{
- new = (unique_copy && n_occurrences
+ new_rtx = (unique_copy && n_occurrences
? copy_rtx (to) : to);
n_occurrences++;
}
else
{
- new = subst (XVECEXP (x, i, j), from, to, 0,
+ new_rtx = subst (XVECEXP (x, i, j), from, to, 0,
unique_copy);
/* If this substitution failed, this whole thing
fails. */
- if (GET_CODE (new) == CLOBBER
- && XEXP (new, 0) == const0_rtx)
- return new;
+ if (GET_CODE (new_rtx) == CLOBBER
+ && XEXP (new_rtx, 0) == const0_rtx)
+ return new_rtx;
}
- SUBST (XVECEXP (x, i, j), new);
+ SUBST (XVECEXP (x, i, j), new_rtx);
}
}
else if (fmt[i] == 'e')
{
/* If this is a register being set, ignore it. */
- new = XEXP (x, i);
+ new_rtx = XEXP (x, i);
if (in_dest
&& i == 0
&& (((code == SUBREG || code == ZERO_EXTRACT)
- && REG_P (new))
+ && REG_P (new_rtx))
|| code == STRICT_LOW_PART))
;
return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
#endif
- new = (unique_copy && n_occurrences ? copy_rtx (to) : to);
+ new_rtx = (unique_copy && n_occurrences ? copy_rtx (to) : to);
n_occurrences++;
}
else
STRICT_LOW_PART, and ZERO_EXTRACT, which are the only
things aside from REG and MEM that should appear in a
SET_DEST. */
- new = subst (XEXP (x, i), from, to,
+ new_rtx = subst (XEXP (x, i), from, to,
(((in_dest
&& (code == SUBREG || code == STRICT_LOW_PART
|| code == ZERO_EXTRACT))
well as prevent accidents where two CLOBBERs are considered
to be equal, thus producing an incorrect simplification. */
- if (GET_CODE (new) == CLOBBER && XEXP (new, 0) == const0_rtx)
- return new;
+ if (GET_CODE (new_rtx) == CLOBBER && XEXP (new_rtx, 0) == const0_rtx)
+ return new_rtx;
if (GET_CODE (x) == SUBREG
- && (GET_CODE (new) == CONST_INT
- || GET_CODE (new) == CONST_DOUBLE))
+ && (CONST_INT_P (new_rtx)
+ || GET_CODE (new_rtx) == CONST_DOUBLE))
{
enum machine_mode mode = GET_MODE (x);
- x = simplify_subreg (GET_MODE (x), new,
+ x = simplify_subreg (GET_MODE (x), new_rtx,
GET_MODE (SUBREG_REG (x)),
SUBREG_BYTE (x));
if (! x)
x = gen_rtx_CLOBBER (mode, const0_rtx);
}
- else if (GET_CODE (new) == CONST_INT
+ else if (CONST_INT_P (new_rtx)
&& GET_CODE (x) == ZERO_EXTEND)
{
x = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
- new, GET_MODE (XEXP (x, 0)));
+ new_rtx, GET_MODE (XEXP (x, 0)));
gcc_assert (x);
}
else
- SUBST (XEXP (x, i), new);
+ SUBST (XEXP (x, i), new_rtx);
}
}
}
+ /* Check if we are loading something from the constant pool via float
+ extension; in this case we would undo compress_float_constant
+ optimization and degenerate constant load to an immediate value. */
+ if (GET_CODE (x) == FLOAT_EXTEND
+ && MEM_P (XEXP (x, 0))
+ && MEM_READONLY_P (XEXP (x, 0)))
+ {
+ rtx tmp = avoid_constant_pool_reference (x);
+ if (x != tmp)
+ return x;
+ }
+
/* Try to simplify X. If the simplification changed the code, it is likely
that further simplification will help, so loop, but limit the number
of repetitions that will be performed. */
&& ! (GET_CODE (XEXP (x, 1)) == SUBREG
&& OBJECT_P (SUBREG_REG (XEXP (x, 1)))))))
|| (UNARY_P (x)
- && (!OBJECT_P (XEXP (x, 0))
+ && (!OBJECT_P (XEXP (x, 0))
&& ! (GET_CODE (XEXP (x, 0)) == SUBREG
&& OBJECT_P (SUBREG_REG (XEXP (x, 0)))))))
{
else if (true_rtx == const0_rtx && false_rtx == const_true_rtx
&& ((reversed = reversed_comparison_code_parts
(cond_code, cond, cop1, NULL))
- != UNKNOWN))
+ != UNKNOWN))
x = simplify_gen_relational (reversed, mode, VOIDmode,
cond, cop1);
/* Likewise, we can make the negate of a comparison operation
if the result values are - STORE_FLAG_VALUE and zero. */
- else if (GET_CODE (true_rtx) == CONST_INT
+ else if (CONST_INT_P (true_rtx)
&& INTVAL (true_rtx) == - STORE_FLAG_VALUE
&& false_rtx == const0_rtx)
x = simplify_gen_unary (NEG, mode,
mode, VOIDmode,
cond, cop1),
mode);
- else if (GET_CODE (false_rtx) == CONST_INT
+ else if (CONST_INT_P (false_rtx)
&& INTVAL (false_rtx) == - STORE_FLAG_VALUE
&& true_rtx == const0_rtx
&& ((reversed = reversed_comparison_code_parts
(cond_code, cond, cop1, NULL))
- != UNKNOWN))
+ != UNKNOWN))
x = simplify_gen_unary (NEG, mode,
simplify_gen_relational (reversed,
mode, VOIDmode,
|| code == AND || code == IOR || code == XOR
|| code == SMAX || code == SMIN || code == UMAX || code == UMIN)
&& ((INTEGRAL_MODE_P (mode) && code != DIV)
- || (flag_unsafe_math_optimizations && FLOAT_MODE_P (mode))))
+ || (flag_associative_math && FLOAT_MODE_P (mode))))
{
if (GET_CODE (XEXP (x, 0)) == code)
{
return gen_lowpart (mode, SUBREG_REG (x));
if (GET_MODE_CLASS (GET_MODE (SUBREG_REG (x))) == MODE_CC)
- break;
+ break;
{
rtx temp;
temp = simplify_subreg (mode, SUBREG_REG (x), op0_mode,
(neg (sign_extract X 1 Y)) to (zero_extract X 1 Y). */
if (GET_CODE (temp) == ASHIFTRT
- && GET_CODE (XEXP (temp, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (temp, 1))
&& INTVAL (XEXP (temp, 1)) == GET_MODE_BITSIZE (mode) - 1)
return simplify_shift_const (NULL_RTX, LSHIFTRT, mode, XEXP (temp, 0),
INTVAL (XEXP (temp, 1)));
if (GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
break;
- if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
- && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
- GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))))
+ 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), 0));
return gen_lowpart (mode, XEXP (x, 0));
break;
-#ifdef HAVE_cc0
- case COMPARE:
- /* Convert (compare FOO (const_int 0)) to FOO unless we aren't
- using cc0, in which case we want to leave it as a COMPARE
- so we can distinguish it from a register-register-copy. */
- if (XEXP (x, 1) == const0_rtx)
- return XEXP (x, 0);
-
- /* x - 0 is the same as x unless x's mode has signed zeros and
- allows rounding towards -infinity. Under those conditions,
- 0 - 0 is -0. */
- if (!(HONOR_SIGNED_ZEROS (GET_MODE (XEXP (x, 0)))
- && HONOR_SIGN_DEPENDENT_ROUNDING (GET_MODE (XEXP (x, 0))))
- && XEXP (x, 1) == CONST0_RTX (GET_MODE (XEXP (x, 0))))
- return XEXP (x, 0);
- break;
-#endif
-
case CONST:
/* (const (const X)) can become (const X). Do it this way rather than
returning the inner CONST since CONST can be shared with a
sign_extract. The `and' may be a zero_extend and the two
<c>, -<c> constants may be reversed. */
if (GET_CODE (XEXP (x, 0)) == XOR
- && GET_CODE (XEXP (x, 1)) == CONST_INT
- && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+ && CONST_INT_P (XEXP (x, 1))
+ && CONST_INT_P (XEXP (XEXP (x, 0), 1))
&& INTVAL (XEXP (x, 1)) == -INTVAL (XEXP (XEXP (x, 0), 1))
&& ((i = exact_log2 (INTVAL (XEXP (XEXP (x, 0), 1)))) >= 0
|| (i = exact_log2 (INTVAL (XEXP (x, 1)))) >= 0)
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& ((GET_CODE (XEXP (XEXP (x, 0), 0)) == AND
- && GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == CONST_INT
+ && CONST_INT_P (XEXP (XEXP (XEXP (x, 0), 0), 1))
&& (INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1))
== ((HOST_WIDE_INT) 1 << (i + 1)) - 1))
|| (GET_CODE (XEXP (XEXP (x, 0), 0)) == ZERO_EXTEND
/* (minus <foo> (and <foo> (const_int -pow2))) becomes
(and <foo> (const_int pow2-1)) */
if (GET_CODE (XEXP (x, 1)) == AND
- && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT
+ && CONST_INT_P (XEXP (XEXP (x, 1), 1))
&& exact_log2 (-INTVAL (XEXP (XEXP (x, 1), 1))) >= 0
&& rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0)))
return simplify_and_const_int (NULL_RTX, mode, XEXP (x, 0),
}
/* Try simplify a*(b/c) as (a*b)/c. */
- if (FLOAT_MODE_P (mode) && flag_unsafe_math_optimizations
+ if (FLOAT_MODE_P (mode) && flag_associative_math
&& GET_CODE (XEXP (x, 0)) == DIV)
{
rtx tem = simplify_binary_operation (MULT, mode,
case UDIV:
/* If this is a divide by a power of two, treat it as a shift if
its first operand is a shift. */
- if (GET_CODE (XEXP (x, 1)) == CONST_INT
+ if (CONST_INT_P (XEXP (x, 1))
&& (i = exact_log2 (INTVAL (XEXP (x, 1)))) >= 0
&& (GET_CODE (XEXP (x, 0)) == ASHIFT
|| GET_CODE (XEXP (x, 0)) == LSHIFTRT
case ROTATE:
case ROTATERT:
/* If this is a shift by a constant amount, simplify it. */
- if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+ if (CONST_INT_P (XEXP (x, 1)))
return simplify_shift_const (x, code, mode, XEXP (x, 0),
INTVAL (XEXP (x, 1)));
if (true_code == EQ && true_val == const0_rtx
&& exact_log2 (nzb = nonzero_bits (from, GET_MODE (from))) >= 0)
- false_code = EQ, false_val = GEN_INT (nzb);
+ {
+ false_code = EQ;
+ false_val = GEN_INT (trunc_int_for_mode (nzb, GET_MODE (from)));
+ }
else if (true_code == EQ && true_val == const0_rtx
&& (num_sign_bit_copies (from, GET_MODE (from))
== GET_MODE_BITSIZE (GET_MODE (from))))
- false_code = EQ, false_val = constm1_rtx;
+ {
+ false_code = EQ;
+ false_val = constm1_rtx;
+ }
/* Now simplify an arm if we know the value of the register in the
branch and it is used in the arm. Be careful due to the potential
&& reversed_comparison_code (cond, NULL) != UNKNOWN
&& (true_rtx == pc_rtx
|| (CONSTANT_P (true_rtx)
- && GET_CODE (false_rtx) != CONST_INT && false_rtx != pc_rtx)
+ && !CONST_INT_P (false_rtx) && false_rtx != pc_rtx)
|| true_rtx == const0_rtx
|| (OBJECT_P (true_rtx) && !OBJECT_P (false_rtx))
|| (GET_CODE (true_rtx) == SUBREG && OBJECT_P (SUBREG_REG (true_rtx))
/* Look for cases where we have (abs x) or (neg (abs X)). */
if (GET_MODE_CLASS (mode) == MODE_INT
+ && comparison_p
+ && XEXP (cond, 1) == const0_rtx
&& GET_CODE (false_rtx) == NEG
&& rtx_equal_p (true_rtx, XEXP (false_rtx, 0))
- && comparison_p
&& rtx_equal_p (true_rtx, XEXP (cond, 0))
&& ! side_effects_p (true_rtx))
switch (true_code)
can actually do this more generally, but it doesn't seem worth it. */
if (true_code == NE && XEXP (cond, 1) == const0_rtx
- && false_rtx == const0_rtx && GET_CODE (true_rtx) == CONST_INT
+ && false_rtx == const0_rtx && CONST_INT_P (true_rtx)
&& ((1 == nonzero_bits (XEXP (cond, 0), mode)
&& (i = exact_log2 (INTVAL (true_rtx))) >= 0)
|| ((num_sign_bit_copies (XEXP (cond, 0), mode)
/* (IF_THEN_ELSE (NE REG 0) (0) (8)) is REG for nonzero_bits (REG) == 8. */
if (true_code == NE && XEXP (cond, 1) == const0_rtx
- && false_rtx == const0_rtx && GET_CODE (true_rtx) == CONST_INT
+ && false_rtx == const0_rtx && CONST_INT_P (true_rtx)
&& GET_MODE (XEXP (cond, 0)) == mode
&& (INTVAL (true_rtx) & GET_MODE_MASK (mode))
== nonzero_bits (XEXP (cond, 0), mode)
tmp = simplify_relational_operation (old_code, compare_mode, VOIDmode,
op0, op1);
if (!tmp)
- new_code = old_code;
+ new_code = old_code;
else if (!CONSTANT_P (tmp))
- {
- new_code = GET_CODE (tmp);
- op0 = XEXP (tmp, 0);
- op1 = XEXP (tmp, 1);
- }
+ {
+ new_code = GET_CODE (tmp);
+ op0 = XEXP (tmp, 0);
+ op1 = XEXP (tmp, 1);
+ }
else
{
rtx pat = PATTERN (other_insn);
/* Attempt to simplify CC user. */
if (GET_CODE (pat) == SET)
{
- rtx new = simplify_rtx (SET_SRC (pat));
- if (new != NULL_RTX)
- SUBST (SET_SRC (pat), new);
+ rtx new_rtx = simplify_rtx (SET_SRC (pat));
+ if (new_rtx != NULL_RTX)
+ SUBST (SET_SRC (pat), new_rtx);
}
/* Convert X into a no-op move. */
{
int other_changed_previously = other_changed;
unsigned HOST_WIDE_INT mask;
+ rtx old_cc_use = *cc_use;
SUBST (*cc_use, gen_rtx_fmt_ee (new_code, GET_MODE (*cc_use),
dest, const0_rtx));
if ((recog_for_combine (&pat, other_insn, ¬e) < 0
&& ! check_asm_operands (pat)))
{
- PUT_CODE (*cc_use, old_code);
+ *cc_use = old_cc_use;
other_changed = 0;
op0 = simplify_gen_binary (XOR, GET_MODE (op0),
if (other_changed)
undobuf.other_insn = other_insn;
-#ifdef HAVE_cc0
- /* If we are now comparing against zero, change our source if
- needed. If we do not use cc0, we always have a COMPARE. */
- if (op1 == const0_rtx && dest == cc0_rtx)
- {
- SUBST (SET_SRC (x), op0);
- src = op0;
- }
- else
-#endif
-
/* Otherwise, if we didn't previously have a COMPARE in the
correct mode, we need one. */
if (GET_CODE (src) != COMPARE || GET_MODE (src) != compare_mode)
}
else if (GET_MODE (op0) == compare_mode && op1 == const0_rtx)
{
- SUBST(SET_SRC (x), op0);
+ SUBST (SET_SRC (x), op0);
src = SET_SRC (x);
- }
- else
+ }
+ /* Otherwise, update the COMPARE if needed. */
+ else if (XEXP (src, 0) != op0 || XEXP (src, 1) != op1)
{
- /* Otherwise, update the COMPARE if needed. */
- SUBST (XEXP (src, 0), op0);
- SUBST (XEXP (src, 1), op1);
+ SUBST (SET_SRC (x), gen_rtx_COMPARE (compare_mode, op0, op1));
+ src = SET_SRC (x);
}
}
else
+ (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))
#ifndef WORD_REGISTER_OPERATIONS
&& (GET_MODE_SIZE (GET_MODE (src))
- < GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))))
+ < GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))))
#endif
#ifdef CANNOT_CHANGE_MODE_CLASS
&& ! (REG_P (dest) && REGNO (dest) < FIRST_PSEUDO_REGISTER
zero_extend to avoid the reload that would otherwise be required. */
if (GET_CODE (src) == SUBREG && subreg_lowpart_p (src)
+ && INTEGRAL_MODE_P (GET_MODE (SUBREG_REG (src)))
&& LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))) != UNKNOWN
&& SUBREG_BYTE (src) == 0
&& (GET_MODE_SIZE (GET_MODE (src))
/* We can call simplify_and_const_int only if we don't lose
any (sign) bits when converting INTVAL (op1) to
"unsigned HOST_WIDE_INT". */
- if (GET_CODE (op1) == CONST_INT
+ if (CONST_INT_P (op1)
&& (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
|| INTVAL (op1) > 0))
{
Even for a mode that is no wider than a const_int,
we can't win, because we need to sign extend one of its bits through
the rest of it, and we don't know which bit. */
- if (GET_CODE (XEXP (x, 0)) == CONST_INT)
+ if (CONST_INT_P (XEXP (x, 0)))
return x;
/* Return if (subreg:MODE FROM 0) is not a safe replacement for
if (GET_CODE (XEXP (x, 0)) == CLOBBER)
return XEXP (x, 0);
- if (GET_CODE (XEXP (x, 1)) != CONST_INT
- || GET_CODE (XEXP (x, 2)) != CONST_INT
+ if (!CONST_INT_P (XEXP (x, 1))
+ || !CONST_INT_P (XEXP (x, 2))
|| GET_MODE (XEXP (x, 0)) == VOIDmode)
return x;
rtx temp2 = expand_compound_operation (temp);
/* Make sure this is a profitable operation. */
- if (rtx_cost (x, SET) > rtx_cost (temp2, SET))
+ if (rtx_cost (x, SET, optimize_this_for_speed_p)
+ > rtx_cost (temp2, SET, optimize_this_for_speed_p))
return temp2;
- else if (rtx_cost (x, SET) > rtx_cost (temp, SET))
+ else if (rtx_cost (x, SET, optimize_this_for_speed_p)
+ > rtx_cost (temp, SET, optimize_this_for_speed_p))
return temp;
else
return x;
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. */
+ 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
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. */
+ 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)
&& COMPARISON_P (XEXP (XEXP (x, 0), 0))
modewidth = GET_MODE_BITSIZE (GET_MODE (x));
if (modewidth + len >= pos)
- tem = simplify_shift_const (NULL_RTX, unsignedp ? LSHIFTRT : ASHIFTRT,
- GET_MODE (x),
- simplify_shift_const (NULL_RTX, ASHIFT,
- GET_MODE (x),
- XEXP (x, 0),
- modewidth - pos - len),
- modewidth - len);
-
+ {
+ enum machine_mode mode = GET_MODE (x);
+ tem = gen_lowpart (mode, XEXP (x, 0));
+ if (!tem || GET_CODE (tem) == CLOBBER)
+ return x;
+ tem = simplify_shift_const (NULL_RTX, ASHIFT, mode,
+ tem, modewidth - pos - len);
+ tem = simplify_shift_const (NULL_RTX, unsignedp ? LSHIFTRT : ASHIFTRT,
+ mode, tem, modewidth - len);
+ }
else if (unsignedp && len < HOST_BITS_PER_WIDE_INT)
tem = simplify_and_const_int (NULL_RTX, GET_MODE (x),
simplify_shift_const (NULL_RTX, LSHIFTRT,
We half-heartedly support variable positions, but do not at all
support variable lengths. */
-static rtx
-expand_field_assignment (rtx x)
+static const_rtx
+expand_field_assignment (const_rtx x)
{
rtx inner;
rtx pos; /* Always counts from low bit. */
pos = GEN_INT (subreg_lsb (XEXP (SET_DEST (x), 0)));
}
else if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT
- && GET_CODE (XEXP (SET_DEST (x), 1)) == CONST_INT)
+ && CONST_INT_P (XEXP (SET_DEST (x), 1)))
{
inner = XEXP (SET_DEST (x), 0);
len = INTVAL (XEXP (SET_DEST (x), 1));
pos = XEXP (SET_DEST (x), 2);
/* A constant position should stay within the width of INNER. */
- if (GET_CODE (pos) == CONST_INT
+ if (CONST_INT_P (pos)
&& INTVAL (pos) + len > GET_MODE_BITSIZE (GET_MODE (inner)))
break;
if (BITS_BIG_ENDIAN)
{
- if (GET_CODE (pos) == CONST_INT)
+ if (CONST_INT_P (pos))
pos = GEN_INT (GET_MODE_BITSIZE (GET_MODE (inner)) - len
- INTVAL (pos));
else if (GET_CODE (pos) == MINUS
- && GET_CODE (XEXP (pos, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (pos, 1))
&& (INTVAL (XEXP (pos, 1))
== GET_MODE_BITSIZE (GET_MODE (inner)) - len))
/* If position is ADJUST - X, new position is X. */
enum machine_mode pos_mode = word_mode;
enum machine_mode extraction_mode = word_mode;
enum machine_mode tmode = mode_for_size (len, MODE_INT, 1);
- rtx new = 0;
+ rtx new_rtx = 0;
rtx orig_pos_rtx = pos_rtx;
HOST_WIDE_INT orig_pos;
inner = SUBREG_REG (inner);
}
else if (GET_CODE (inner) == ASHIFT
- && GET_CODE (XEXP (inner, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (inner, 1))
&& pos_rtx == 0 && pos == 0
&& len > (unsigned HOST_WIDE_INT) INTVAL (XEXP (inner, 1)))
{
(ashift X (const_int C)), where LEN > C. Extract the
least significant (LEN - C) bits of X, giving an rtx
whose mode is MODE, then shift it left C times. */
- new = make_extraction (mode, XEXP (inner, 0),
+ new_rtx = make_extraction (mode, XEXP (inner, 0),
0, 0, len - INTVAL (XEXP (inner, 1)),
unsignedp, in_dest, in_compare);
- if (new != 0)
- return gen_rtx_ASHIFT (mode, new, XEXP (inner, 1));
+ if (new_rtx != 0)
+ return gen_rtx_ASHIFT (mode, new_rtx, XEXP (inner, 1));
}
inner_mode = GET_MODE (inner);
- if (pos_rtx && GET_CODE (pos_rtx) == CONST_INT)
+ if (pos_rtx && CONST_INT_P (pos_rtx))
pos = INTVAL (pos_rtx), pos_rtx = 0;
/* See if this can be done without an extraction. We never can if the
else
offset = pos / BITS_PER_UNIT;
- new = adjust_address_nv (inner, tmode, offset);
+ new_rtx = adjust_address_nv (inner, tmode, offset);
}
else if (REG_P (inner))
{
if (!validate_subreg (tmode, inner_mode, inner, final_word))
return NULL_RTX;
- new = gen_rtx_SUBREG (tmode, inner, final_word);
+ new_rtx = gen_rtx_SUBREG (tmode, inner, final_word);
}
else
- new = gen_lowpart (tmode, inner);
+ new_rtx = gen_lowpart (tmode, inner);
}
else
- new = inner;
+ new_rtx = inner;
}
else
- new = force_to_mode (inner, tmode,
+ new_rtx = force_to_mode (inner, tmode,
len >= HOST_BITS_PER_WIDE_INT
? ~(unsigned HOST_WIDE_INT) 0
: ((unsigned HOST_WIDE_INT) 1 << len) - 1,
make a STRICT_LOW_PART unless we made a MEM. */
if (in_dest)
- return (MEM_P (new) ? new
- : (GET_CODE (new) != SUBREG
+ return (MEM_P (new_rtx) ? new_rtx
+ : (GET_CODE (new_rtx) != SUBREG
? gen_rtx_CLOBBER (tmode, const0_rtx)
- : gen_rtx_STRICT_LOW_PART (VOIDmode, new)));
+ : gen_rtx_STRICT_LOW_PART (VOIDmode, new_rtx)));
if (mode == tmode)
- return new;
+ return new_rtx;
- if (GET_CODE (new) == CONST_INT)
- return gen_int_mode (INTVAL (new), mode);
+ if (CONST_INT_P (new_rtx))
+ return gen_int_mode (INTVAL (new_rtx), mode);
/* If we know that no extraneous bits are set, and that the high
bit is not set, convert the extraction to the cheaper of
sign and zero extension, that are equivalent in these cases. */
if (flag_expensive_optimizations
&& (GET_MODE_BITSIZE (tmode) <= HOST_BITS_PER_WIDE_INT
- && ((nonzero_bits (new, tmode)
+ && ((nonzero_bits (new_rtx, tmode)
& ~(((unsigned HOST_WIDE_INT)
GET_MODE_MASK (tmode))
>> 1))
== 0)))
{
- rtx temp = gen_rtx_ZERO_EXTEND (mode, new);
- rtx temp1 = gen_rtx_SIGN_EXTEND (mode, new);
+ rtx temp = gen_rtx_ZERO_EXTEND (mode, new_rtx);
+ rtx temp1 = gen_rtx_SIGN_EXTEND (mode, new_rtx);
/* Prefer ZERO_EXTENSION, since it gives more information to
backends. */
- if (rtx_cost (temp, SET) <= rtx_cost (temp1, SET))
+ if (rtx_cost (temp, SET, optimize_this_for_speed_p)
+ <= rtx_cost (temp1, SET, optimize_this_for_speed_p))
return temp;
return temp1;
}
proper mode. */
return (gen_rtx_fmt_e (unsignedp ? ZERO_EXTEND : SIGN_EXTEND,
- mode, new));
+ mode, new_rtx));
}
/* Unless this is a COMPARE or we have a funny memory reference,
else
{
/* Be careful not to go beyond the extracted object and maintain the
- natural alignment of the memory. */
+ natural alignment of the memory. */
wanted_inner_mode = smallest_mode_for_size (len, MODE_INT);
while (pos % GET_MODE_BITSIZE (wanted_inner_mode) + len
> GET_MODE_BITSIZE (wanted_inner_mode))
inner = adjust_address_nv (inner, wanted_inner_mode, offset);
}
- /* If INNER is not memory, we can always get it into the proper mode. If we
- are changing its mode, POS must be a constant and smaller than the size
- of the new mode. */
+ /* If INNER is not memory, get it into the proper mode. If we are changing
+ its mode, POS must be a constant and smaller than the size of the new
+ mode. */
else if (!MEM_P (inner))
{
+ /* On the LHS, don't create paradoxical subregs implicitely truncating
+ the register unless TRULY_NOOP_TRUNCATION. */
+ if (in_dest
+ && !TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (GET_MODE (inner)),
+ GET_MODE_BITSIZE (wanted_inner_mode)))
+ return NULL_RTX;
+
if (GET_MODE (inner) != wanted_inner_mode
&& (pos_rtx != 0
|| orig_pos + len > GET_MODE_BITSIZE (wanted_inner_mode)))
- return 0;
+ return NULL_RTX;
+
+ if (orig_pos < 0)
+ return NULL_RTX;
inner = force_to_mode (inner, wanted_inner_mode,
pos_rtx
/* Prefer ZERO_EXTENSION, since it gives more information to
backends. */
- if (rtx_cost (temp1, SET) < rtx_cost (temp, SET))
+ if (rtx_cost (temp1, SET, optimize_this_for_speed_p)
+ < rtx_cost (temp, SET, optimize_this_for_speed_p))
temp = temp1;
}
pos_rtx = temp;
pos_rtx = GEN_INT (pos);
/* Make the required operation. See if we can use existing rtx. */
- new = gen_rtx_fmt_eee (unsignedp ? ZERO_EXTRACT : SIGN_EXTRACT,
+ new_rtx = gen_rtx_fmt_eee (unsignedp ? ZERO_EXTRACT : SIGN_EXTRACT,
extraction_mode, inner, GEN_INT (len), pos_rtx);
if (! in_dest)
- new = gen_lowpart (mode, new);
+ new_rtx = gen_lowpart (mode, new_rtx);
- return new;
+ return new_rtx;
}
\f
/* See if X contains an ASHIFT of COUNT or more bits that can be commuted
/* This is the shift itself. If it is wide enough, we will return
either the value being shifted if the shift count is equal to
COUNT or a shift for the difference. */
- if (GET_CODE (XEXP (x, 1)) == CONST_INT
+ if (CONST_INT_P (XEXP (x, 1))
&& INTVAL (XEXP (x, 1)) >= count)
return simplify_shift_const (NULL_RTX, ASHIFT, mode, XEXP (x, 0),
INTVAL (XEXP (x, 1)) - count);
case PLUS: case IOR: case XOR: case AND:
/* If we can safely shift this constant and we find the inner shift,
make a new operation. */
- if (GET_CODE (XEXP (x, 1)) == CONST_INT
+ if (CONST_INT_P (XEXP (x, 1))
&& (INTVAL (XEXP (x, 1)) & ((((HOST_WIDE_INT) 1 << count)) - 1)) == 0
&& (tem = extract_left_shift (XEXP (x, 0), count)) != 0)
return simplify_gen_binary (code, mode, tem,
int mode_width = GET_MODE_BITSIZE (mode);
rtx rhs, lhs;
enum rtx_code next_code;
- int i;
- rtx new = 0;
+ int i, j;
+ rtx new_rtx = 0;
rtx tem;
const char *fmt;
case ASHIFT:
/* Convert shifts by constants into multiplications if inside
an address. */
- if (in_code == MEM && GET_CODE (XEXP (x, 1)) == CONST_INT
+ if (in_code == MEM && CONST_INT_P (XEXP (x, 1))
&& INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT
&& INTVAL (XEXP (x, 1)) >= 0)
{
- new = make_compound_operation (XEXP (x, 0), next_code);
- new = gen_rtx_MULT (mode, new,
+ new_rtx = make_compound_operation (XEXP (x, 0), next_code);
+ new_rtx = gen_rtx_MULT (mode, new_rtx,
GEN_INT ((HOST_WIDE_INT) 1
<< INTVAL (XEXP (x, 1))));
}
case AND:
/* If the second operand is not a constant, we can't do anything
with it. */
- if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+ if (!CONST_INT_P (XEXP (x, 1)))
break;
/* If the constant is a power of two minus one and the first operand
if (GET_CODE (XEXP (x, 0)) == LSHIFTRT
&& (i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0)
{
- new = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code);
- new = make_extraction (mode, new, 0, XEXP (XEXP (x, 0), 1), i, 1,
+ new_rtx = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code);
+ new_rtx = make_extraction (mode, new_rtx, 0, XEXP (XEXP (x, 0), 1), i, 1,
0, in_code == COMPARE);
}
&& GET_CODE (SUBREG_REG (XEXP (x, 0))) == LSHIFTRT
&& (i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0)
{
- new = make_compound_operation (XEXP (SUBREG_REG (XEXP (x, 0)), 0),
+ new_rtx = make_compound_operation (XEXP (SUBREG_REG (XEXP (x, 0)), 0),
next_code);
- new = make_extraction (GET_MODE (SUBREG_REG (XEXP (x, 0))), new, 0,
+ new_rtx = make_extraction (GET_MODE (SUBREG_REG (XEXP (x, 0))), new_rtx, 0,
XEXP (SUBREG_REG (XEXP (x, 0)), 1), i, 1,
0, in_code == COMPARE);
}
&& (i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0)
{
/* Apply the distributive law, and then try to make extractions. */
- new = gen_rtx_fmt_ee (GET_CODE (XEXP (x, 0)), mode,
+ new_rtx = gen_rtx_fmt_ee (GET_CODE (XEXP (x, 0)), mode,
gen_rtx_AND (mode, XEXP (XEXP (x, 0), 0),
XEXP (x, 1)),
gen_rtx_AND (mode, XEXP (XEXP (x, 0), 1),
XEXP (x, 1)));
- new = make_compound_operation (new, in_code);
+ new_rtx = make_compound_operation (new_rtx, in_code);
}
/* If we are have (and (rotate X C) M) and C is larger than the number
of bits in M, this is an extraction. */
else if (GET_CODE (XEXP (x, 0)) == ROTATE
- && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+ && CONST_INT_P (XEXP (XEXP (x, 0), 1))
&& (i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0
&& i <= INTVAL (XEXP (XEXP (x, 0), 1)))
{
- new = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code);
- new = make_extraction (mode, new,
+ new_rtx = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code);
+ new_rtx = make_extraction (mode, new_rtx,
(GET_MODE_BITSIZE (mode)
- INTVAL (XEXP (XEXP (x, 0), 1))),
NULL_RTX, i, 1, 0, in_code == COMPARE);
else if (GET_CODE (XEXP (x, 0)) == LSHIFTRT
&& !have_insn_for (LSHIFTRT, mode)
&& have_insn_for (ASHIFTRT, mode)
- && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+ && CONST_INT_P (XEXP (XEXP (x, 0), 1))
&& INTVAL (XEXP (XEXP (x, 0), 1)) >= 0
&& INTVAL (XEXP (XEXP (x, 0), 1)) < HOST_BITS_PER_WIDE_INT
&& mode_width <= HOST_BITS_PER_WIDE_INT)
If it doesn't end up being a ZERO_EXTEND, we will ignore it unless
we are in a COMPARE. */
else if ((i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0)
- new = make_extraction (mode,
+ new_rtx = make_extraction (mode,
make_compound_operation (XEXP (x, 0),
next_code),
0, NULL_RTX, i, 1, 0, in_code == COMPARE);
convert this into the appropriate bit extract. */
else if (in_code == COMPARE
&& (i = exact_log2 (INTVAL (XEXP (x, 1)))) >= 0)
- new = make_extraction (mode,
+ new_rtx = make_extraction (mode,
make_compound_operation (XEXP (x, 0),
next_code),
i, NULL_RTX, 1, 1, 0, 1);
&& mode_width <= HOST_BITS_PER_WIDE_INT
&& (nonzero_bits (XEXP (x, 0), mode) & (1 << (mode_width - 1))) == 0)
{
- new = gen_rtx_ASHIFTRT (mode,
+ new_rtx = gen_rtx_ASHIFTRT (mode,
make_compound_operation (XEXP (x, 0),
next_code),
XEXP (x, 1));
/* If we have (ashiftrt (ashift foo C1) C2) with C2 >= C1,
this is a SIGN_EXTRACT. */
- if (GET_CODE (rhs) == CONST_INT
+ if (CONST_INT_P (rhs)
&& GET_CODE (lhs) == ASHIFT
- && GET_CODE (XEXP (lhs, 1)) == CONST_INT
- && INTVAL (rhs) >= INTVAL (XEXP (lhs, 1)))
+ && CONST_INT_P (XEXP (lhs, 1))
+ && INTVAL (rhs) >= INTVAL (XEXP (lhs, 1))
+ && INTVAL (rhs) < mode_width)
{
- new = make_compound_operation (XEXP (lhs, 0), next_code);
- new = make_extraction (mode, new,
+ new_rtx = make_compound_operation (XEXP (lhs, 0), next_code);
+ new_rtx = make_extraction (mode, new_rtx,
INTVAL (rhs) - INTVAL (XEXP (lhs, 1)),
NULL_RTX, mode_width - INTVAL (rhs),
code == LSHIFTRT, 0, in_code == COMPARE);
if (!OBJECT_P (lhs)
&& ! (GET_CODE (lhs) == SUBREG
&& (OBJECT_P (SUBREG_REG (lhs))))
- && GET_CODE (rhs) == CONST_INT
+ && CONST_INT_P (rhs)
&& INTVAL (rhs) < HOST_BITS_PER_WIDE_INT
- && (new = extract_left_shift (lhs, INTVAL (rhs))) != 0)
- new = make_extraction (mode, make_compound_operation (new, next_code),
+ && INTVAL (rhs) < mode_width
+ && (new_rtx = extract_left_shift (lhs, INTVAL (rhs))) != 0)
+ new_rtx = make_extraction (mode, make_compound_operation (new_rtx, next_code),
0, NULL_RTX, mode_width - INTVAL (rhs),
code == LSHIFTRT, 0, in_code == COMPARE);
{
rtx newer = force_to_mode (tem, mode, ~(HOST_WIDE_INT) 0,
0);
-
+
/* If we have something other than a SUBREG, we might have
done an expansion, so rerun ourselves. */
if (GET_CODE (newer) != SUBREG)
newer = make_compound_operation (newer, in_code);
-
+
+ /* force_to_mode can expand compounds. If it just re-expanded the
+ compound use gen_lowpart instead to convert to the desired
+ mode. */
+ if (rtx_equal_p (newer, x))
+ return gen_lowpart (GET_MODE (x), tem);
+
return newer;
}
break;
}
- if (new)
+ if (new_rtx)
{
- x = gen_lowpart (mode, new);
+ x = gen_lowpart (mode, new_rtx);
code = GET_CODE (x);
}
for (i = 0; i < GET_RTX_LENGTH (code); i++)
if (fmt[i] == 'e')
{
- new = make_compound_operation (XEXP (x, i), next_code);
- SUBST (XEXP (x, i), new);
+ new_rtx = make_compound_operation (XEXP (x, i), next_code);
+ SUBST (XEXP (x, i), new_rtx);
}
+ else if (fmt[i] == 'E')
+ for (j = 0; j < XVECLEN (x, i); j++)
+ {
+ new_rtx = make_compound_operation (XVECEXP (x, i, j), next_code);
+ SUBST (XVECEXP (x, i, j), new_rtx);
+ }
/* If this is a commutative operation, the changes to the operands
may have made it noncanonical. */
fmt = GET_RTX_FORMAT (code);
copied = false;
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- if (fmt[i] == 'e')
- {
- rtx op = canon_reg_for_combine (XEXP (x, i), reg);
+ if (fmt[i] == 'e')
+ {
+ rtx op = canon_reg_for_combine (XEXP (x, i), reg);
if (op != XEXP (x, i))
{
if (!copied)
x = copy_rtx (x);
}
XEXP (x, i) = op;
- }
- }
- else if (fmt[i] == 'E')
- {
- int j;
- for (j = 0; j < XVECLEN (x, i); j++)
+ }
+ }
+ else if (fmt[i] == 'E')
+ {
+ int j;
+ for (j = 0; j < XVECLEN (x, i); j++)
{
- rtx op = canon_reg_for_combine (XVECEXP (x, i, j), reg);
- if (op != XVECEXP (x, i, j))
+ rtx op = canon_reg_for_combine (XVECEXP (x, i, j), reg);
+ if (op != XVECEXP (x, i, j))
{
if (!copied)
{
x = copy_rtx (x);
}
XVECEXP (x, i, j) = op;
- }
+ }
}
}
static rtx
gen_lowpart_or_truncate (enum machine_mode mode, rtx x)
{
- if (GET_MODE_SIZE (GET_MODE (x)) <= GET_MODE_SIZE (mode)
- || TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
- GET_MODE_BITSIZE (GET_MODE (x)))
- || (REG_P (x) && reg_truncated_to_mode (mode, x)))
- return gen_lowpart (mode, x);
- else
- return gen_rtx_TRUNCATE (mode, x);
+ if (!CONST_INT_P (x)
+ && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (x))
+ && !TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
+ GET_MODE_BITSIZE (GET_MODE (x)))
+ && !(REG_P (x) && reg_truncated_to_mode (mode, x)))
+ {
+ /* Bit-cast X into an integer mode. */
+ if (!SCALAR_INT_MODE_P (GET_MODE (x)))
+ x = gen_lowpart (int_mode_for_mode (GET_MODE (x)), x);
+ x = simplify_gen_unary (TRUNCATE, int_mode_for_mode (mode),
+ x, GET_MODE (x));
+ }
+
+ return gen_lowpart (mode, x);
}
/* See if X can be simplified knowing that we will only refer to it in
nonzero = nonzero_bits (x, mode);
/* If none of the bits in X are needed, return a zero. */
- if (! just_select && (nonzero & mask) == 0)
+ if (!just_select && (nonzero & mask) == 0 && !side_effects_p (x))
x = const0_rtx;
/* If X is a CONST_INT, return a new one. Do this here since the
test below will fail. */
- if (GET_CODE (x) == CONST_INT)
+ if (CONST_INT_P (x))
{
if (SCALAR_INT_MODE_P (mode))
- return gen_int_mode (INTVAL (x) & mask, mode);
+ return gen_int_mode (INTVAL (x) & mask, mode);
else
{
x = GEN_INT (INTVAL (x) & mask);
&& (GET_MODE_MASK (GET_MODE (x)) & ~mask) == 0)
return gen_lowpart (mode, x);
+ /* We can ignore the effect of a SUBREG if it narrows the mode or
+ if the constant masks to zero all the bits the mode doesn't have. */
+ if (GET_CODE (x) == SUBREG
+ && subreg_lowpart_p (x)
+ && ((GET_MODE_SIZE (GET_MODE (x))
+ < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
+ || (0 == (mask
+ & GET_MODE_MASK (GET_MODE (x))
+ & ~GET_MODE_MASK (GET_MODE (SUBREG_REG (x)))))))
+ return force_to_mode (SUBREG_REG (x), mode, mask, next_select);
+
+ /* The arithmetic simplifications here only work for scalar integer modes. */
+ if (!SCALAR_INT_MODE_P (mode) || !SCALAR_INT_MODE_P (GET_MODE (x)))
+ return gen_lowpart_or_truncate (mode, x);
+
switch (code)
{
case CLOBBER:
return force_to_mode (x, mode, mask, next_select);
break;
- case SUBREG:
- if (subreg_lowpart_p (x)
- /* We can ignore the effect of this SUBREG if it narrows the mode or
- if the constant masks to zero all the bits the mode doesn't
- have. */
- && ((GET_MODE_SIZE (GET_MODE (x))
- < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
- || (0 == (mask
- & GET_MODE_MASK (GET_MODE (x))
- & ~GET_MODE_MASK (GET_MODE (SUBREG_REG (x)))))))
- return force_to_mode (SUBREG_REG (x), mode, mask, next_select);
- break;
+ case TRUNCATE:
+ /* Similarly for a truncate. */
+ return force_to_mode (XEXP (x, 0), mode, mask, next_select);
case AND:
/* If this is an AND with a constant, convert it into an AND
whose constant is the AND of that constant with MASK. If it
remains an AND of MASK, delete it since it is redundant. */
- if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+ if (CONST_INT_P (XEXP (x, 1)))
{
x = simplify_and_const_int (x, op_mode, XEXP (x, 0),
mask & INTVAL (XEXP (x, 1)));
is just some low-order bits. If so, and it is MASK, we don't
need it. */
- if (GET_CODE (x) == AND && GET_CODE (XEXP (x, 1)) == CONST_INT
+ if (GET_CODE (x) == AND && CONST_INT_P (XEXP (x, 1))
&& ((INTVAL (XEXP (x, 1)) & GET_MODE_MASK (GET_MODE (x)))
== mask))
x = XEXP (x, 0);
constant in the AND is wide enough, this might make a
cheaper constant. */
- if (GET_CODE (x) == AND && GET_CODE (XEXP (x, 1)) == CONST_INT
+ if (GET_CODE (x) == AND && CONST_INT_P (XEXP (x, 1))
&& GET_MODE_MASK (GET_MODE (x)) != mask
&& GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT)
{
y = simplify_gen_binary (AND, GET_MODE (x),
XEXP (x, 0), GEN_INT (cval));
- if (rtx_cost (y, SET) < rtx_cost (x, SET))
+ if (rtx_cost (y, SET, optimize_this_for_speed_p)
+ < rtx_cost (x, SET, optimize_this_for_speed_p))
x = y;
}
&& (smask & ((HOST_WIDE_INT) 1 << (width - 1))) != 0)
smask |= (HOST_WIDE_INT) -1 << width;
- if (GET_CODE (XEXP (x, 1)) == CONST_INT
+ if (CONST_INT_P (XEXP (x, 1))
&& exact_log2 (- smask) >= 0
&& (nonzero_bits (XEXP (x, 0), mode) & ~smask) == 0
&& (INTVAL (XEXP (x, 1)) & ~smask) != 0)
case MINUS:
/* If X is (minus C Y) where C's least set bit is larger than any bit
in the mask, then we may replace with (neg Y). */
- if (GET_CODE (XEXP (x, 0)) == CONST_INT
+ if (CONST_INT_P (XEXP (x, 0))
&& (((unsigned HOST_WIDE_INT) (INTVAL (XEXP (x, 0))
& -INTVAL (XEXP (x, 0))))
> mask))
/* Similarly, if C contains every bit in the fuller_mask, then we may
replace with (not Y). */
- if (GET_CODE (XEXP (x, 0)) == CONST_INT
+ if (CONST_INT_P (XEXP (x, 0))
&& ((INTVAL (XEXP (x, 0)) | (HOST_WIDE_INT) fuller_mask)
== INTVAL (XEXP (x, 0))))
{
constant we form is not wider than the mode of X. */
if (GET_CODE (XEXP (x, 0)) == LSHIFTRT
- && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+ && CONST_INT_P (XEXP (XEXP (x, 0), 1))
&& INTVAL (XEXP (XEXP (x, 0), 1)) >= 0
&& INTVAL (XEXP (XEXP (x, 0), 1)) < HOST_BITS_PER_WIDE_INT
- && GET_CODE (XEXP (x, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (x, 1))
&& ((INTVAL (XEXP (XEXP (x, 0), 1))
+ floor_log2 (INTVAL (XEXP (x, 1))))
< GET_MODE_BITSIZE (GET_MODE (x)))
/* For most binary operations, just propagate into the operation and
change the mode if we have an operation of that mode. */
- op0 = gen_lowpart_or_truncate (op_mode,
- force_to_mode (XEXP (x, 0), mode, mask,
- next_select));
- op1 = gen_lowpart_or_truncate (op_mode,
- force_to_mode (XEXP (x, 1), mode, mask,
- next_select));
+ op0 = force_to_mode (XEXP (x, 0), mode, mask, next_select);
+ op1 = force_to_mode (XEXP (x, 1), mode, mask, next_select);
+
+ /* If we ended up truncating both operands, truncate the result of the
+ operation instead. */
+ if (GET_CODE (op0) == TRUNCATE
+ && GET_CODE (op1) == TRUNCATE)
+ {
+ op0 = XEXP (op0, 0);
+ op1 = XEXP (op1, 0);
+ }
+
+ op0 = gen_lowpart_or_truncate (op_mode, op0);
+ op1 = gen_lowpart_or_truncate (op_mode, op1);
if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
x = simplify_gen_binary (code, op_mode, op0, op1);
because such a count will have a different meaning in a
wider mode. */
- if (! (GET_CODE (XEXP (x, 1)) == CONST_INT
+ if (! (CONST_INT_P (XEXP (x, 1))
&& INTVAL (XEXP (x, 1)) >= 0
&& INTVAL (XEXP (x, 1)) < GET_MODE_BITSIZE (mode))
&& ! (GET_MODE (XEXP (x, 1)) != VOIDmode
/* If the shift count is a constant and we can do arithmetic in
the mode of the shift, refine which bits we need. Otherwise, use the
conservative form of the mask. */
- if (GET_CODE (XEXP (x, 1)) == CONST_INT
+ if (CONST_INT_P (XEXP (x, 1))
&& INTVAL (XEXP (x, 1)) >= 0
&& INTVAL (XEXP (x, 1)) < GET_MODE_BITSIZE (op_mode)
&& GET_MODE_BITSIZE (op_mode) <= HOST_BITS_PER_WIDE_INT)
this shift constant is valid for the host, and we can do arithmetic
in OP_MODE. */
- if (GET_CODE (XEXP (x, 1)) == CONST_INT
+ if (CONST_INT_P (XEXP (x, 1))
&& INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT
&& GET_MODE_BITSIZE (op_mode) <= HOST_BITS_PER_WIDE_INT)
{
than a power of two), we can do this with just a shift. */
if (GET_CODE (x) == LSHIFTRT
- && GET_CODE (XEXP (x, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (x, 1))
/* The shift puts one of the sign bit copies in the least significant
bit. */
&& ((INTVAL (XEXP (x, 1))
those bits, we are requesting a copy of the sign bit and hence can
shift the sign bit to the appropriate location. */
- if (GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0
+ if (CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) >= 0
&& INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT)
{
int i;
something that is still a shift. */
if ((GET_CODE (x) == LSHIFTRT || GET_CODE (x) == ASHIFTRT)
- && GET_CODE (XEXP (x, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (x, 1))
&& INTVAL (XEXP (x, 1)) >= 0
&& (INTVAL (XEXP (x, 1))
<= GET_MODE_BITSIZE (GET_MODE (x)) - (floor_log2 (mask) + 1))
in the mode of X, compute where the bits we care about are.
Otherwise, we can't do anything. Don't change the mode of
the shift or propagate MODE into the shift, though. */
- if (GET_CODE (XEXP (x, 1)) == CONST_INT
+ if (CONST_INT_P (XEXP (x, 1))
&& INTVAL (XEXP (x, 1)) >= 0)
{
temp = simplify_binary_operation (code == ROTATE ? ROTATERT : ROTATE,
GET_MODE (x), GEN_INT (mask),
XEXP (x, 1));
- if (temp && GET_CODE (temp) == CONST_INT)
+ if (temp && CONST_INT_P (temp))
SUBST (XEXP (x, 0),
force_to_mode (XEXP (x, 0), GET_MODE (x),
INTVAL (temp), next_select));
wider than the mode of X. */
if (GET_CODE (XEXP (x, 0)) == LSHIFTRT
- && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+ && CONST_INT_P (XEXP (XEXP (x, 0), 1))
&& INTVAL (XEXP (XEXP (x, 0), 1)) >= 0
&& (INTVAL (XEXP (XEXP (x, 0), 1)) + floor_log2 (mask)
< GET_MODE_BITSIZE (GET_MODE (x)))
*ptrue = simplify_gen_relational (code, mode, VOIDmode,
true0, true1);
*pfalse = simplify_gen_relational (code, mode, VOIDmode,
- false0, false1);
+ false0, false1);
}
else
{
else if (code == SUBREG)
{
enum machine_mode inner_mode = GET_MODE (SUBREG_REG (x));
- rtx new, r = known_cond (SUBREG_REG (x), cond, reg, val);
+ rtx new_rtx, r = known_cond (SUBREG_REG (x), cond, reg, val);
if (SUBREG_REG (x) != r)
{
/* We must simplify subreg here, before we lose track of the
original inner_mode. */
- new = simplify_subreg (GET_MODE (x), r,
+ new_rtx = simplify_subreg (GET_MODE (x), r,
inner_mode, SUBREG_BYTE (x));
- if (new)
- return new;
+ if (new_rtx)
+ return new_rtx;
else
SUBST (SUBREG_REG (x), r);
}
else if (code == ZERO_EXTEND)
{
enum machine_mode inner_mode = GET_MODE (XEXP (x, 0));
- rtx new, r = known_cond (XEXP (x, 0), cond, reg, val);
+ rtx new_rtx, r = known_cond (XEXP (x, 0), cond, reg, val);
if (XEXP (x, 0) != r)
{
/* We must simplify the zero_extend here, before we lose
- track of the original inner_mode. */
- new = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
+ track of the original inner_mode. */
+ new_rtx = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
r, inner_mode);
- if (new)
- return new;
+ if (new_rtx)
+ return new_rtx;
else
SUBST (XEXP (x, 0), r);
}
for a SUBREG. */
if (GET_CODE (src) == AND && GET_CODE (XEXP (src, 0)) == ROTATE
- && GET_CODE (XEXP (XEXP (src, 0), 0)) == CONST_INT
+ && CONST_INT_P (XEXP (XEXP (src, 0), 0))
&& INTVAL (XEXP (XEXP (src, 0), 0)) == -2
&& rtx_equal_for_field_assignment_p (dest, XEXP (src, 1)))
{
&& (GET_MODE_SIZE (GET_MODE (XEXP (src, 0)))
< GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (src, 0)))))
&& GET_CODE (SUBREG_REG (XEXP (src, 0))) == ROTATE
- && GET_CODE (XEXP (SUBREG_REG (XEXP (src, 0)), 0)) == CONST_INT
+ && CONST_INT_P (XEXP (SUBREG_REG (XEXP (src, 0)), 0))
&& INTVAL (XEXP (SUBREG_REG (XEXP (src, 0)), 0)) == -2
&& rtx_equal_for_field_assignment_p (dest, XEXP (src, 1)))
{
SRC is an AND with all bits of that field set, then we can discard
the AND. */
if (GET_CODE (dest) == ZERO_EXTRACT
- && GET_CODE (XEXP (dest, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (dest, 1))
&& GET_CODE (src) == AND
- && GET_CODE (XEXP (src, 1)) == CONST_INT)
+ && CONST_INT_P (XEXP (src, 1)))
{
HOST_WIDE_INT width = INTVAL (XEXP (dest, 1));
unsigned HOST_WIDE_INT and_mask = INTVAL (XEXP (src, 1));
lhs = expand_compound_operation (XEXP (src, 1));
if (GET_CODE (rhs) == AND
- && GET_CODE (XEXP (rhs, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (rhs, 1))
&& rtx_equal_for_field_assignment_p (XEXP (rhs, 0), dest))
c1 = INTVAL (XEXP (rhs, 1)), other = lhs;
else if (GET_CODE (lhs) == AND
- && GET_CODE (XEXP (lhs, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (lhs, 1))
&& rtx_equal_for_field_assignment_p (XEXP (lhs, 0), dest))
c1 = INTVAL (XEXP (lhs, 1)), other = rhs;
else
/* If SRC is masked by an AND that does not make a difference in
the value being stored, strip it. */
if (GET_CODE (assign) == ZERO_EXTRACT
- && GET_CODE (XEXP (assign, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (assign, 1))
&& INTVAL (XEXP (assign, 1)) < HOST_BITS_PER_WIDE_INT
&& GET_CODE (src) == AND
- && GET_CODE (XEXP (src, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (src, 1))
&& ((unsigned HOST_WIDE_INT) INTVAL (XEXP (src, 1))
== ((unsigned HOST_WIDE_INT) 1 << INTVAL (XEXP (assign, 1))) - 1))
src = XEXP (src, 0);
expanding a bit field assignment. When we apply the distributive
law to this, we get (ior (and (A (not B))) (and (B (not B)))),
which then simplifies to (and (A (not B))).
-
+
Note that no checks happen on the validity of applying the inverse
distributive law. This is pointless since we can do it in the
few places where this routine is called.
tmp = apply_distributive_law (simplify_gen_binary (inner_code, mode,
new_op0, new_op1));
if (GET_CODE (tmp) != outer_code
- && rtx_cost (tmp, SET) < rtx_cost (x, SET))
+ && rtx_cost (tmp, SET, optimize_this_for_speed_p)
+ < rtx_cost (x, SET, optimize_this_for_speed_p))
return tmp;
return NULL_RTX;
/* If VAROP is a CONST_INT, then we need to apply the mask in CONSTOP
to VAROP and return the new constant. */
- if (GET_CODE (varop) == CONST_INT)
+ if (CONST_INT_P (varop))
return gen_int_mode (INTVAL (varop) & constop, mode);
/* See what bits may be nonzero in VAROP. Unlike the general case of
return NULL_RTX;
/* Otherwise, return an AND. */
- constop = trunc_int_for_mode (constop, mode);
- return simplify_gen_binary (AND, mode, varop, GEN_INT (constop));
+ return simplify_gen_binary (AND, mode, varop, gen_int_mode (constop, mode));
}
return tem;
if (!x)
- x = simplify_gen_binary (AND, GET_MODE (varop), varop, GEN_INT (constop));
+ x = simplify_gen_binary (AND, GET_MODE (varop), varop,
+ gen_int_mode (constop, mode));
if (GET_MODE (x) != mode)
x = gen_lowpart (mode, x);
return x;
a shift, AND, or zero_extract, we can do better. */
static rtx
-reg_nonzero_bits_for_combine (rtx x, enum machine_mode mode,
- rtx known_x ATTRIBUTE_UNUSED,
+reg_nonzero_bits_for_combine (const_rtx x, enum machine_mode mode,
+ const_rtx known_x ATTRIBUTE_UNUSED,
enum machine_mode known_mode ATTRIBUTE_UNUSED,
unsigned HOST_WIDE_INT known_ret ATTRIBUTE_UNUSED,
unsigned HOST_WIDE_INT *nonzero)
{
rtx tem;
+ reg_stat_type *rsp;
/* If X is a register whose nonzero bits value is current, use it.
Otherwise, if X is a register whose value we can find, use that
value. Otherwise, use the previously-computed global nonzero bits
for this register. */
- if (reg_stat[REGNO (x)].last_set_value != 0
- && (reg_stat[REGNO (x)].last_set_mode == mode
- || (GET_MODE_CLASS (reg_stat[REGNO (x)].last_set_mode) == MODE_INT
+ rsp = VEC_index (reg_stat_type, reg_stat, REGNO (x));
+ if (rsp->last_set_value != 0
+ && (rsp->last_set_mode == mode
+ || (GET_MODE_CLASS (rsp->last_set_mode) == MODE_INT
&& GET_MODE_CLASS (mode) == MODE_INT))
- && (reg_stat[REGNO (x)].last_set_label == label_tick
+ && ((rsp->last_set_label >= label_tick_ebb_start
+ && rsp->last_set_label < label_tick)
+ || (rsp->last_set_label == label_tick
+ && DF_INSN_LUID (rsp->last_set) < subst_low_luid)
|| (REGNO (x) >= FIRST_PSEUDO_REGISTER
&& REG_N_SETS (REGNO (x)) == 1
- && ! REGNO_REG_SET_P
- (ENTRY_BLOCK_PTR->next_bb->il.rtl->global_live_at_start,
- REGNO (x))))
- && INSN_CUID (reg_stat[REGNO (x)].last_set) < subst_low_cuid)
+ && !REGNO_REG_SET_P
+ (DF_LR_IN (ENTRY_BLOCK_PTR->next_bb), REGNO (x)))))
{
- *nonzero &= reg_stat[REGNO (x)].last_set_nonzero_bits;
+ *nonzero &= rsp->last_set_nonzero_bits;
return NULL;
}
{
#ifdef SHORT_IMMEDIATES_SIGN_EXTEND
/* If X is narrower than MODE and TEM is a non-negative
- constant that would appear negative in the mode of X,
- sign-extend it for use in reg_nonzero_bits because some
- machines (maybe most) will actually do the sign-extension
- and this is the conservative approach.
+ constant that would appear negative in the mode of X,
+ sign-extend it for use in reg_nonzero_bits because some
+ machines (maybe most) will actually do the sign-extension
+ and this is the conservative approach.
- ??? For 2.5, try to tighten up the MD files in this regard
- instead of this kludge. */
+ ??? For 2.5, try to tighten up the MD files in this regard
+ instead of this kludge. */
if (GET_MODE_BITSIZE (GET_MODE (x)) < GET_MODE_BITSIZE (mode)
- && GET_CODE (tem) == CONST_INT
+ && CONST_INT_P (tem)
&& INTVAL (tem) > 0
&& 0 != (INTVAL (tem)
& ((HOST_WIDE_INT) 1
#endif
return tem;
}
- else if (nonzero_sign_valid && reg_stat[REGNO (x)].nonzero_bits)
+ else if (nonzero_sign_valid && rsp->nonzero_bits)
{
- unsigned HOST_WIDE_INT mask = reg_stat[REGNO (x)].nonzero_bits;
+ unsigned HOST_WIDE_INT mask = rsp->nonzero_bits;
if (GET_MODE_BITSIZE (GET_MODE (x)) < GET_MODE_BITSIZE (mode))
- /* We don't know anything about the upper bits. */
- mask |= GET_MODE_MASK (mode) ^ GET_MODE_MASK (GET_MODE (x));
+ /* We don't know anything about the upper bits. */
+ mask |= GET_MODE_MASK (mode) ^ GET_MODE_MASK (GET_MODE (x));
*nonzero &= mask;
}
be between 1 and the number of bits in MODE. */
static rtx
-reg_num_sign_bit_copies_for_combine (rtx x, enum machine_mode mode,
- rtx known_x ATTRIBUTE_UNUSED,
+reg_num_sign_bit_copies_for_combine (const_rtx x, enum machine_mode mode,
+ const_rtx known_x ATTRIBUTE_UNUSED,
enum machine_mode known_mode
ATTRIBUTE_UNUSED,
unsigned int known_ret ATTRIBUTE_UNUSED,
unsigned int *result)
{
rtx tem;
-
- if (reg_stat[REGNO (x)].last_set_value != 0
- && reg_stat[REGNO (x)].last_set_mode == mode
- && (reg_stat[REGNO (x)].last_set_label == label_tick
- || (REGNO (x) >= FIRST_PSEUDO_REGISTER
+ reg_stat_type *rsp;
+
+ rsp = VEC_index (reg_stat_type, reg_stat, REGNO (x));
+ if (rsp->last_set_value != 0
+ && rsp->last_set_mode == mode
+ && ((rsp->last_set_label >= label_tick_ebb_start
+ && rsp->last_set_label < label_tick)
+ || (rsp->last_set_label == label_tick
+ && DF_INSN_LUID (rsp->last_set) < subst_low_luid)
+ || (REGNO (x) >= FIRST_PSEUDO_REGISTER
&& REG_N_SETS (REGNO (x)) == 1
- && ! REGNO_REG_SET_P
- (ENTRY_BLOCK_PTR->next_bb->il.rtl->global_live_at_start,
- REGNO (x))))
- && INSN_CUID (reg_stat[REGNO (x)].last_set) < subst_low_cuid)
+ && !REGNO_REG_SET_P
+ (DF_LR_IN (ENTRY_BLOCK_PTR->next_bb), REGNO (x)))))
{
- *result = reg_stat[REGNO (x)].last_set_sign_bit_copies;
+ *result = rsp->last_set_sign_bit_copies;
return NULL;
}
if (tem != 0)
return tem;
- if (nonzero_sign_valid && reg_stat[REGNO (x)].sign_bit_copies != 0
+ if (nonzero_sign_valid && rsp->sign_bit_copies != 0
&& GET_MODE_BITSIZE (GET_MODE (x)) == GET_MODE_BITSIZE (mode))
- *result = reg_stat[REGNO (x)].sign_bit_copies;
-
+ *result = rsp->sign_bit_copies;
+
return NULL;
}
\f
implies that it must be called from a define_split. */
unsigned int
-extended_count (rtx x, enum machine_mode mode, int unsignedp)
+extended_count (const_rtx x, enum machine_mode mode, int unsignedp)
{
if (nonzero_sign_valid == 0)
return 0;
&& op0 == AND)
op0 = UNKNOWN;
+ *pop0 = op0;
+
/* ??? Slightly redundant with the above mask, but not entirely.
Moving this above means we'd have to sign-extend the mode mask
for the final test. */
- const0 = trunc_int_for_mode (const0, mode);
-
- *pop0 = op0;
- *pconst0 = const0;
+ if (op0 != UNKNOWN && op0 != NEG)
+ *pconst0 = trunc_int_for_mode (const0, mode);
return 1;
}
\f
+/* A helper to simplify_shift_const_1 to determine the mode we can perform
+ the shift in. The original shift operation CODE is performed on OP in
+ ORIG_MODE. Return the wider mode MODE if we can perform the operation
+ in that mode. Return ORIG_MODE otherwise. We can also assume that the
+ result of the shift is subject to operation OUTER_CODE with operand
+ OUTER_CONST. */
+
+static enum machine_mode
+try_widen_shift_mode (enum rtx_code code, rtx op, int count,
+ enum machine_mode orig_mode, enum machine_mode mode,
+ enum rtx_code outer_code, HOST_WIDE_INT outer_const)
+{
+ if (orig_mode == mode)
+ return mode;
+ gcc_assert (GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (orig_mode));
+
+ /* In general we can't perform in wider mode for right shift and rotate. */
+ switch (code)
+ {
+ case ASHIFTRT:
+ /* We can still widen if the bits brought in from the left are identical
+ to the sign bit of ORIG_MODE. */
+ if (num_sign_bit_copies (op, mode)
+ > (unsigned) (GET_MODE_BITSIZE (mode)
+ - GET_MODE_BITSIZE (orig_mode)))
+ return mode;
+ return orig_mode;
+
+ case LSHIFTRT:
+ /* Similarly here but with zero bits. */
+ if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+ && (nonzero_bits (op, mode) & ~GET_MODE_MASK (orig_mode)) == 0)
+ return mode;
+
+ /* We can also widen if the bits brought in will be masked off. This
+ operation is performed in ORIG_MODE. */
+ if (outer_code == AND)
+ {
+ int care_bits = low_bitmask_len (orig_mode, outer_const);
+
+ if (care_bits >= 0
+ && GET_MODE_BITSIZE (orig_mode) - care_bits >= count)
+ return mode;
+ }
+ /* fall through */
+
+ case ROTATE:
+ return orig_mode;
+
+ case ROTATERT:
+ gcc_unreachable ();
+
+ default:
+ return mode;
+ }
+}
+
/* Simplify a shift of VAROP by COUNT bits. CODE says what kind of shift.
The result of the shift is RESULT_MODE. Return NULL_RTX if we cannot
simplify it. Otherwise, return a simplified value.
enum rtx_code outer_op = UNKNOWN;
HOST_WIDE_INT outer_const = 0;
int complement_p = 0;
- rtx new, x;
+ rtx new_rtx, x;
/* Make sure and truncate the "natural" shift on the way in. We don't
want to do this inside the loop as it makes it more difficult to
if (GET_CODE (varop) == CLOBBER)
return NULL_RTX;
- /* If we discovered we had to complement VAROP, leave. Making a NOT
- here would cause an infinite loop. */
- if (complement_p)
- break;
-
/* Convert ROTATERT to ROTATE. */
if (code == ROTATERT)
{
count = bitsize - count;
}
- /* 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. */
- shift_mode
- = (code == ASHIFTRT || code == LSHIFTRT || code == ROTATE
- ? result_mode : mode);
+ shift_mode = try_widen_shift_mode (code, varop, count, result_mode,
+ mode, outer_op, outer_const);
/* Handle cases where the count is greater than the size of the mode
minus 1. For ASHIFT, use the size minus one as the count (this can
}
}
+ /* If we discovered we had to complement VAROP, leave. Making a NOT
+ here would cause an infinite loop. */
+ if (complement_p)
+ break;
+
/* An arithmetic right shift of a quantity known to be -1 or 0
is a no-op. */
if (code == ASHIFTRT
== 0))
code = LSHIFTRT;
- if (code == LSHIFTRT
- && GET_MODE_BITSIZE (shift_mode) <= HOST_BITS_PER_WIDE_INT
- && !(nonzero_bits (varop, shift_mode) >> count))
- varop = const0_rtx;
- if (code == ASHIFT
- && GET_MODE_BITSIZE (shift_mode) <= HOST_BITS_PER_WIDE_INT
- && !((nonzero_bits (varop, shift_mode) << count)
- & GET_MODE_MASK (shift_mode)))
+ if (((code == LSHIFTRT
+ && GET_MODE_BITSIZE (shift_mode) <= HOST_BITS_PER_WIDE_INT
+ && !(nonzero_bits (varop, shift_mode) >> count))
+ || (code == ASHIFT
+ && GET_MODE_BITSIZE (shift_mode) <= HOST_BITS_PER_WIDE_INT
+ && !((nonzero_bits (varop, shift_mode) << count)
+ & GET_MODE_MASK (shift_mode))))
+ && !side_effects_p (varop))
varop = const0_rtx;
switch (GET_CODE (varop))
case ZERO_EXTEND:
case SIGN_EXTRACT:
case ZERO_EXTRACT:
- new = expand_compound_operation (varop);
- if (new != varop)
+ new_rtx = expand_compound_operation (varop);
+ if (new_rtx != varop)
{
- varop = new;
+ varop = new_rtx;
continue;
}
break;
&& (tmode = mode_for_size (GET_MODE_BITSIZE (mode) - count,
MODE_INT, 1)) != BLKmode)
{
- new = adjust_address_nv (varop, tmode,
+ new_rtx = adjust_address_nv (varop, tmode,
BYTES_BIG_ENDIAN ? 0
: count / BITS_PER_UNIT);
varop = gen_rtx_fmt_e (code == ASHIFTRT ? SIGN_EXTEND
- : ZERO_EXTEND, mode, new);
+ : ZERO_EXTEND, mode, new_rtx);
count = 0;
continue;
}
/* Some machines use MULT instead of ASHIFT because MULT
is cheaper. But it is still better on those machines to
merge two shifts into one. */
- if (GET_CODE (XEXP (varop, 1)) == CONST_INT
+ if (CONST_INT_P (XEXP (varop, 1))
&& exact_log2 (INTVAL (XEXP (varop, 1))) >= 0)
{
varop
case UDIV:
/* Similar, for when divides are cheaper. */
- if (GET_CODE (XEXP (varop, 1)) == CONST_INT
+ if (CONST_INT_P (XEXP (varop, 1))
&& exact_log2 (INTVAL (XEXP (varop, 1))) >= 0)
{
varop
case ROTATE:
/* Here we have two nested shifts. The result is usually the
AND of a new shift with a mask. We compute the result below. */
- if (GET_CODE (XEXP (varop, 1)) == CONST_INT
+ if (CONST_INT_P (XEXP (varop, 1))
&& INTVAL (XEXP (varop, 1)) >= 0
&& INTVAL (XEXP (varop, 1)) < GET_MODE_BITSIZE (GET_MODE (varop))
&& GET_MODE_BITSIZE (result_mode) <= HOST_BITS_PER_WIDE_INT
- && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+ && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+ && !VECTOR_MODE_P (result_mode))
{
enum rtx_code first_code = GET_CODE (varop);
unsigned int first_count = INTVAL (XEXP (varop, 1));
/* Give up if we can't compute an outer operation to use. */
if (mask_rtx == 0
- || GET_CODE (mask_rtx) != CONST_INT
+ || !CONST_INT_P (mask_rtx)
|| ! merge_outer_ops (&outer_op, &outer_const, AND,
INTVAL (mask_rtx),
result_mode, &complement_p))
B is not a constant. */
else if (GET_CODE (varop) == code
- && GET_CODE (XEXP (varop, 0)) == CONST_INT
- && GET_CODE (XEXP (varop, 1)) != CONST_INT)
+ && CONST_INT_P (XEXP (varop, 0))
+ && !CONST_INT_P (XEXP (varop, 1)))
{
- rtx new = simplify_const_binary_operation (code, mode,
+ rtx new_rtx = simplify_const_binary_operation (code, mode,
XEXP (varop, 0),
GEN_INT (count));
- varop = gen_rtx_fmt_ee (code, mode, new, XEXP (varop, 1));
+ varop = gen_rtx_fmt_ee (code, mode, new_rtx, XEXP (varop, 1));
count = 0;
continue;
}
break;
case NOT:
+ if (VECTOR_MODE_P (mode))
+ break;
+
/* Make this fit the case below. */
varop = gen_rtx_XOR (mode, XEXP (varop, 0),
GEN_INT (GET_MODE_MASK (mode)));
what a ZERO_EXTRACT looks like. Also, some machines have
(and (shift)) insns. */
- if (GET_CODE (XEXP (varop, 1)) == CONST_INT
+ if (CONST_INT_P (XEXP (varop, 1))
/* We can't do this if we have (ashiftrt (xor)) and the
constant has its sign bit set in shift_mode. */
&& !(code == ASHIFTRT && GET_CODE (varop) == XOR
&& 0 > trunc_int_for_mode (INTVAL (XEXP (varop, 1)),
shift_mode))
- && (new = simplify_const_binary_operation (code, result_mode,
- XEXP (varop, 1),
- GEN_INT (count))) != 0
- && GET_CODE (new) == CONST_INT
+ && (new_rtx = simplify_const_binary_operation (code, result_mode,
+ XEXP (varop, 1),
+ GEN_INT (count))) != 0
+ && CONST_INT_P (new_rtx)
&& merge_outer_ops (&outer_op, &outer_const, GET_CODE (varop),
- INTVAL (new), result_mode, &complement_p))
+ INTVAL (new_rtx), result_mode, &complement_p))
{
varop = XEXP (varop, 0);
continue;
logical expression, make a new logical expression, and apply
the inverse distributive law. This also can't be done
for some (ashiftrt (xor)). */
- if (GET_CODE (XEXP (varop, 1)) == CONST_INT
+ if (CONST_INT_P (XEXP (varop, 1))
&& !(code == ASHIFTRT && GET_CODE (varop) == XOR
- && 0 > trunc_int_for_mode (INTVAL (XEXP (varop, 1)),
+ && 0 > trunc_int_for_mode (INTVAL (XEXP (varop, 1)),
shift_mode)))
{
rtx lhs = simplify_shift_const (NULL_RTX, code, shift_mode,
varop = apply_distributive_law (varop);
count = 0;
- continue;
+ continue;
}
break;
/* (ashift (plus foo C) N) is (plus (ashift foo N) C'). */
if (code == ASHIFT
- && GET_CODE (XEXP (varop, 1)) == CONST_INT
- && (new = simplify_const_binary_operation (ASHIFT, result_mode,
- XEXP (varop, 1),
- GEN_INT (count))) != 0
- && GET_CODE (new) == CONST_INT
+ && CONST_INT_P (XEXP (varop, 1))
+ && (new_rtx = simplify_const_binary_operation (ASHIFT, result_mode,
+ XEXP (varop, 1),
+ GEN_INT (count))) != 0
+ && CONST_INT_P (new_rtx)
&& merge_outer_ops (&outer_op, &outer_const, PLUS,
- INTVAL (new), result_mode, &complement_p))
+ INTVAL (new_rtx), result_mode, &complement_p))
{
varop = XEXP (varop, 0);
continue;
leg for shift(logical). See details in logical handling above
for reasoning in doing so. */
if (code == LSHIFTRT
- && GET_CODE (XEXP (varop, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (varop, 1))
&& mode_signbit_p (result_mode, XEXP (varop, 1))
- && (new = simplify_const_binary_operation (code, result_mode,
- XEXP (varop, 1),
- GEN_INT (count))) != 0
- && GET_CODE (new) == CONST_INT
+ && (new_rtx = simplify_const_binary_operation (code, result_mode,
+ XEXP (varop, 1),
+ GEN_INT (count))) != 0
+ && CONST_INT_P (new_rtx)
&& merge_outer_ops (&outer_op, &outer_const, XOR,
- INTVAL (new), result_mode, &complement_p))
+ INTVAL (new_rtx), result_mode, &complement_p))
{
varop = XEXP (varop, 0);
continue;
&& GET_CODE (XEXP (varop, 0)) == ASHIFTRT
&& count == (GET_MODE_BITSIZE (GET_MODE (varop)) - 1)
&& (code == LSHIFTRT || code == ASHIFTRT)
- && GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT
+ && CONST_INT_P (XEXP (XEXP (varop, 0), 1))
&& INTVAL (XEXP (XEXP (varop, 0), 1)) == count
&& rtx_equal_p (XEXP (XEXP (varop, 0), 0), XEXP (varop, 1)))
{
if the truncate does not affect the value. */
if (code == LSHIFTRT
&& GET_CODE (XEXP (varop, 0)) == LSHIFTRT
- && GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT
+ && CONST_INT_P (XEXP (XEXP (varop, 0), 1))
&& (INTVAL (XEXP (XEXP (varop, 0), 1))
>= (GET_MODE_BITSIZE (GET_MODE (XEXP (varop, 0)))
- GET_MODE_BITSIZE (GET_MODE (varop)))))
break;
}
- /* We need to determine what mode to do the shift in. If the shift is
- a right shift or 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. The code we care about is that of the shift that will
- actually be done, not the shift that was originally requested. */
- shift_mode
- = (code == ASHIFTRT || code == LSHIFTRT || code == ROTATE
- ? result_mode : mode);
+ shift_mode = try_widen_shift_mode (code, varop, count, result_mode, mode,
+ outer_op, outer_const);
/* We have now finished analyzing the shift. The result should be
a shift of type CODE with SHIFT_MODE shifting VAROP COUNT places. If
GET_MODE_MASK (result_mode) >> orig_count);
/* Do the remainder of the processing in RESULT_MODE. */
- x = gen_lowpart (result_mode, x);
+ x = gen_lowpart_or_truncate (result_mode, x);
/* If COMPLEMENT_P is set, we have to complement X before doing the outer
operation. */
if (outer_op != UNKNOWN)
{
- if (GET_MODE_BITSIZE (result_mode) < HOST_BITS_PER_WIDE_INT)
+ if (GET_RTX_CLASS (outer_op) != RTX_UNARY
+ && GET_MODE_BITSIZE (result_mode) < HOST_BITS_PER_WIDE_INT)
outer_const = trunc_int_for_mode (outer_const, result_mode);
if (outer_op == AND)
x = simplify_and_const_int (NULL_RTX, result_mode, x, outer_const);
else if (outer_op == SET)
- /* This means that we have determined that the result is
- equivalent to a constant. This should be rare. */
- x = GEN_INT (outer_const);
+ {
+ /* This means that we have determined that the result is
+ equivalent to a constant. This should be rare. */
+ if (!side_effects_p (x))
+ x = GEN_INT (outer_const);
+ }
else if (GET_RTX_CLASS (outer_op) == RTX_UNARY)
x = simplify_gen_unary (outer_op, result_mode, x, result_mode);
else
REG_NOTES (insn) = 0;
insn_code_number = recog (pat, insn, &num_clobbers_to_add);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ if (insn_code_number < 0)
+ fputs ("Failed to match this instruction:\n", dump_file);
+ else
+ fputs ("Successfully matched this instruction:\n", dump_file);
+ print_rtl_single (dump_file, pat);
+ }
/* If it isn't, there is the possibility that we previously had an insn
that clobbered some register as a side effect, but the combined
PATTERN (insn) = pat;
insn_code_number = recog (pat, insn, &num_clobbers_to_add);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ if (insn_code_number < 0)
+ fputs ("Failed to match this instruction:\n", dump_file);
+ else
+ fputs ("Successfully matched this instruction:\n", dump_file);
+ print_rtl_single (dump_file, pat);
+ }
}
PATTERN (insn) = old_pat;
REG_NOTES (insn) = old_notes;
if (REG_P (XEXP (XVECEXP (newpat, 0, i), 0))
&& ! reg_dead_at_p (XEXP (XVECEXP (newpat, 0, i), 0), insn))
return -1;
- notes = gen_rtx_EXPR_LIST (REG_UNUSED,
- XEXP (XVECEXP (newpat, 0, i), 0), notes);
+ if (GET_CODE (XEXP (XVECEXP (newpat, 0, i), 0)) != SCRATCH)
+ {
+ gcc_assert (REG_P (XEXP (XVECEXP (newpat, 0, i), 0)));
+ notes = alloc_reg_note (REG_UNUSED,
+ XEXP (XVECEXP (newpat, 0, i), 0), notes);
+ }
}
pat = newpat;
}
constant integer or has a mode the same size. */
if (GET_MODE_SIZE (omode) > UNITS_PER_WORD
&& ! ((imode == VOIDmode
- && (GET_CODE (x) == CONST_INT
+ && (CONST_INT_P (x)
|| GET_CODE (x) == CONST_DOUBLE))
|| isize == osize))
goto fail;
result = gen_lowpart_common (omode, x);
-#ifdef CANNOT_CHANGE_MODE_CLASS
- if (result != 0 && GET_CODE (result) == SUBREG)
- record_subregs_of_mode (result);
-#endif
-
if (result)
return result;
}
fail:
- return gen_rtx_CLOBBER (imode, const0_rtx);
+ return gen_rtx_CLOBBER (omode, const0_rtx);
}
\f
/* Simplify a comparison between *POP0 and *POP1 where CODE is the
&& GET_CODE (XEXP (XEXP (op1, 0), 0)) == SUBREG
&& (GET_MODE (SUBREG_REG (XEXP (XEXP (op0, 0), 0)))
== GET_MODE (SUBREG_REG (XEXP (XEXP (op1, 0), 0))))
- && GET_CODE (XEXP (op0, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (op0, 1))
&& XEXP (op0, 1) == XEXP (op1, 1)
&& XEXP (op0, 1) == XEXP (XEXP (op0, 0), 1)
&& XEXP (op0, 1) == XEXP (XEXP (op1, 0), 1)
|| (GET_CODE (op0) == ASHIFTRT
&& (code != GTU && code != LTU
&& code != GEU && code != LEU)))
- && GET_CODE (XEXP (op0, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (op0, 1))
&& INTVAL (XEXP (op0, 1)) >= 0
&& INTVAL (XEXP (op0, 1)) < HOST_BITS_PER_WIDE_INT
&& XEXP (op0, 1) == XEXP (op1, 1))
present. */
else if (GET_CODE (op0) == AND && GET_CODE (op1) == AND
- && GET_CODE (XEXP (op0, 1)) == CONST_INT
- && GET_CODE (XEXP (op1, 1)) == CONST_INT)
+ && CONST_INT_P (XEXP (op0, 1))
+ && CONST_INT_P (XEXP (op1, 1)))
{
rtx inner_op0 = XEXP (op0, 0);
rtx inner_op1 = XEXP (op1, 0);
but some things may really be comparisons with zero but not start
out looking that way. */
- while (GET_CODE (op1) == CONST_INT)
+ while (CONST_INT_P (op1))
{
enum machine_mode mode = GET_MODE (op0);
unsigned int mode_width = GET_MODE_BITSIZE (mode);
/* Except we can't if SHIFT_COUNT_TRUNCATED is set, since we might
have already reduced the shift count modulo the word size. */
if (!SHIFT_COUNT_TRUNCATED
- && GET_CODE (XEXP (op0, 0)) == CONST_INT
+ && CONST_INT_P (XEXP (op0, 0))
&& XEXP (op0, 1) == const1_rtx
&& equality_comparison_p && const_op == 0
&& (i = exact_log2 (INTVAL (XEXP (op0, 0)))) >= 0)
case ROTATE:
/* If we are testing equality and our count is a constant, we
can perform the inverse operation on our RHS. */
- if (equality_comparison_p && GET_CODE (XEXP (op0, 1)) == CONST_INT
+ if (equality_comparison_p && CONST_INT_P (XEXP (op0, 1))
&& (tem = simplify_binary_operation (ROTATERT, mode,
op1, XEXP (op0, 1))) != 0)
{
a particular bit. Convert it to an AND of a constant of that
bit. This will be converted into a ZERO_EXTRACT. */
if (const_op == 0 && sign_bit_comparison_p
- && GET_CODE (XEXP (op0, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (op0, 1))
&& mode_width <= HOST_BITS_PER_WIDE_INT)
{
op0 = simplify_and_const_int (NULL_RTX, mode, XEXP (op0, 0),
&& ! unsigned_comparison_p
&& (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
&& ((unsigned HOST_WIDE_INT) const_op
- < (((unsigned HOST_WIDE_INT) 1
+ < (((unsigned HOST_WIDE_INT) 1
<< (GET_MODE_BITSIZE (mode) - 1))))
- && cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+ && have_insn_for (COMPARE, mode))
{
op0 = XEXP (op0, 0);
continue;
&& subreg_lowpart_p (op0)
&& GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0))) > mode_width
&& GET_CODE (SUBREG_REG (op0)) == PLUS
- && GET_CODE (XEXP (SUBREG_REG (op0), 1)) == CONST_INT)
+ && CONST_INT_P (XEXP (SUBREG_REG (op0), 1)))
{
enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
rtx a = XEXP (SUBREG_REG (op0), 0);
HOST_WIDE_INT c1 = -INTVAL (XEXP (SUBREG_REG (op0), 1));
if ((c1 > 0
- && (unsigned HOST_WIDE_INT) c1
+ && (unsigned HOST_WIDE_INT) c1
< (unsigned HOST_WIDE_INT) 1 << (mode_width - 1)
&& (equality_comparison_p || unsigned_comparison_p)
/* (A - C1) zero-extends if it is positive and sign-extends
{
op0 = SUBREG_REG (op0);
continue;
- }
+ }
}
/* If the inner mode is narrower and we are extracting the low part,
&& (unsigned_comparison_p || equality_comparison_p)
&& (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
&& ((unsigned HOST_WIDE_INT) const_op < GET_MODE_MASK (mode))
- && cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+ && have_insn_for (COMPARE, mode))
{
op0 = XEXP (op0, 0);
continue;
/* The sign bit of (minus (ashiftrt X C) X), where C is the number
of bits in X minus 1, is one iff X > 0. */
if (sign_bit_comparison_p && GET_CODE (XEXP (op0, 0)) == ASHIFTRT
- && GET_CODE (XEXP (XEXP (op0, 0), 1)) == CONST_INT
+ && CONST_INT_P (XEXP (XEXP (op0, 0), 1))
&& (unsigned HOST_WIDE_INT) INTVAL (XEXP (XEXP (op0, 0), 1))
== mode_width - 1
&& rtx_equal_p (XEXP (XEXP (op0, 0), 0), XEXP (op0, 1)))
case UNEQ: case LTGT:
case LT: case LTU: case UNLT: case LE: case LEU: case UNLE:
case GT: case GTU: case UNGT: case GE: case GEU: case UNGE:
- case UNORDERED: case ORDERED:
+ case UNORDERED: case ORDERED:
/* We can't do anything if OP0 is a condition code value, rather
than an actual data value. */
if (const_op != 0
{
op0 = simplify_and_const_int
(NULL_RTX, mode, gen_rtx_LSHIFTRT (mode,
- XEXP (op0, 1),
- XEXP (XEXP (op0, 0), 1)),
+ XEXP (op0, 1),
+ XEXP (XEXP (op0, 0), 1)),
(HOST_WIDE_INT) 1);
continue;
}
in STORE_FLAG_VALUE, we can compare with X. */
if (const_op == 0 && equality_comparison_p
&& mode_width <= HOST_BITS_PER_WIDE_INT
- && GET_CODE (XEXP (op0, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (op0, 1))
&& GET_CODE (XEXP (op0, 0)) == LSHIFTRT
- && GET_CODE (XEXP (XEXP (op0, 0), 1)) == CONST_INT
+ && CONST_INT_P (XEXP (XEXP (op0, 0), 1))
&& INTVAL (XEXP (XEXP (op0, 0), 1)) >= 0
&& INTVAL (XEXP (XEXP (op0, 0), 1)) < HOST_BITS_PER_WIDE_INT)
{
the underlying value. */
if (equality_comparison_p
&& const_op == 0
- && GET_CODE (XEXP (op0, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (op0, 1))
&& mode_width <= HOST_BITS_PER_WIDE_INT
&& ((INTVAL (XEXP (op0, 1)) & GET_MODE_MASK (mode))
== (unsigned HOST_WIDE_INT) 1 << (mode_width - 1)))
known to hold a value of the required mode the
transformation is invalid. */
if ((equality_comparison_p || unsigned_comparison_p)
- && GET_CODE (XEXP (op0, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (op0, 1))
&& (i = exact_log2 ((INTVAL (XEXP (op0, 1))
& GET_MODE_MASK (mode))
+ 1)) >= 0
#endif
|| (mode_width <= GET_MODE_BITSIZE (tmode)
&& subreg_lowpart_p (XEXP (op0, 0))))
- && GET_CODE (XEXP (op0, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (op0, 1))
&& mode_width <= HOST_BITS_PER_WIDE_INT
&& GET_MODE_BITSIZE (tmode) <= HOST_BITS_PER_WIDE_INT
&& ((c1 = INTVAL (XEXP (op0, 1))) & ~mask) == 0
if (GET_CODE (shift_op) == NOT
|| (GET_CODE (shift_op) == XOR
- && GET_CODE (XEXP (shift_op, 1)) == CONST_INT
- && GET_CODE (shift_count) == CONST_INT
+ && CONST_INT_P (XEXP (shift_op, 1))
+ && CONST_INT_P (shift_count)
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& (INTVAL (XEXP (shift_op, 1))
== (HOST_WIDE_INT) 1 << INTVAL (shift_count))))
are known to be zero, we can do this by comparing FOO with C
shifted right N bits so long as the low-order N bits of C are
zero. */
- if (GET_CODE (XEXP (op0, 1)) == CONST_INT
+ if (CONST_INT_P (XEXP (op0, 1))
&& INTVAL (XEXP (op0, 1)) >= 0
&& ((INTVAL (XEXP (op0, 1)) + ! equality_comparison_p)
< HOST_BITS_PER_WIDE_INT)
/* If we are doing a sign bit comparison, it means we are testing
a particular bit. Convert it to the appropriate AND. */
- if (sign_bit_comparison_p && GET_CODE (XEXP (op0, 1)) == CONST_INT
+ if (sign_bit_comparison_p && CONST_INT_P (XEXP (op0, 1))
&& mode_width <= HOST_BITS_PER_WIDE_INT)
{
op0 = simplify_and_const_int (NULL_RTX, mode, XEXP (op0, 0),
the low bit to the sign bit, we can convert this to an AND of the
low-order bit. */
if (const_op == 0 && equality_comparison_p
- && GET_CODE (XEXP (op0, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (op0, 1))
&& (unsigned HOST_WIDE_INT) INTVAL (XEXP (op0, 1))
== mode_width - 1)
{
/* If this is an equality comparison with zero, we can do this
as a logical shift, which might be much simpler. */
if (equality_comparison_p && const_op == 0
- && GET_CODE (XEXP (op0, 1)) == CONST_INT)
+ && CONST_INT_P (XEXP (op0, 1)))
{
op0 = simplify_shift_const (NULL_RTX, LSHIFTRT, mode,
XEXP (op0, 0),
/* If OP0 is a sign extension and CODE is not an unsigned comparison,
do the comparison in a narrower mode. */
if (! unsigned_comparison_p
- && GET_CODE (XEXP (op0, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (op0, 1))
&& GET_CODE (XEXP (op0, 0)) == ASHIFT
&& XEXP (op0, 1) == XEXP (XEXP (op0, 0), 1)
&& (tmode = mode_for_size (mode_width - INTVAL (XEXP (op0, 1)),
constant, which is usually represented with the PLUS
between the shifts. */
if (! unsigned_comparison_p
- && GET_CODE (XEXP (op0, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (op0, 1))
&& GET_CODE (XEXP (op0, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (op0, 0), 1)) == CONST_INT
+ && CONST_INT_P (XEXP (XEXP (op0, 0), 1))
&& GET_CODE (XEXP (XEXP (op0, 0), 0)) == ASHIFT
&& XEXP (op0, 1) == XEXP (XEXP (XEXP (op0, 0), 0), 1)
&& (tmode = mode_for_size (mode_width - INTVAL (XEXP (op0, 1)),
the low order N bits of FOO are known to be zero, we can do this
by comparing FOO with C shifted left N bits so long as no
overflow occurs. */
- if (GET_CODE (XEXP (op0, 1)) == CONST_INT
+ if (CONST_INT_P (XEXP (op0, 1))
&& INTVAL (XEXP (op0, 1)) >= 0
&& INTVAL (XEXP (op0, 1)) < HOST_BITS_PER_WIDE_INT
&& mode_width <= HOST_BITS_PER_WIDE_INT
can replace this with an LT or GE comparison. */
if (const_op == 0
&& (equality_comparison_p || sign_bit_comparison_p)
- && GET_CODE (XEXP (op0, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (op0, 1))
&& (unsigned HOST_WIDE_INT) INTVAL (XEXP (op0, 1))
== mode_width - 1)
{
{
/* For paradoxical subregs, allow case 1 as above. Case 3 isn't
implemented. */
- if (REG_P (SUBREG_REG (op0)))
+ if (REG_P (SUBREG_REG (op0)))
{
op0 = SUBREG_REG (op0);
op1 = gen_lowpart (GET_MODE (op0), op1);
|| code == LEU || code == LTU)
&& (nonzero_bits (op0, tmode)
& ~GET_MODE_MASK (mode)) == 0
- && ((GET_CODE (op1) == CONST_INT
+ && ((CONST_INT_P (op1)
|| (nonzero_bits (op1, tmode)
& ~GET_MODE_MASK (mode)) == 0)));
XEXP (op0, 1)));
op0 = gen_lowpart (tmode, op0);
- if (zero_extended && GET_CODE (op1) == CONST_INT)
+ if (zero_extended && CONST_INT_P (op1))
op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (mode));
op1 = gen_lowpart (tmode, op1);
break;
{
enum rtx_code code = GET_CODE (x);
const char *fmt;
- int i, ret = 1;
+ int i, j, ret = 1;
if (GET_RTX_CLASS (code) == '2'
|| GET_RTX_CLASS (code) == 'c')
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
if (fmt[i] == 'e')
ret += count_rtxs (XEXP (x, i));
+ else if (fmt[i] == 'E')
+ for (j = 0; j < XVECLEN (x, i); j++)
+ ret += count_rtxs (XVECEXP (x, i, j));
return ret;
}
{
enum rtx_code code = GET_CODE (x);
const char *fmt = GET_RTX_FORMAT (code);
- int i;
+ int i, j;
if (code == REG)
{
unsigned int regno = REGNO (x);
- unsigned int endregno
- = regno + (regno < FIRST_PSEUDO_REGISTER
- ? hard_regno_nregs[regno][GET_MODE (x)] : 1);
+ unsigned int endregno = END_REGNO (x);
unsigned int r;
for (r = regno; r < endregno; r++)
- reg_stat[r].last_set_table_tick = label_tick;
+ {
+ reg_stat_type *rsp = VEC_index (reg_stat_type, reg_stat, r);
+ rsp->last_set_table_tick = label_tick;
+ }
return;
}
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- /* Note that we can't have an "E" in values stored; see
- get_last_value_validate. */
if (fmt[i] == 'e')
{
/* Check for identical subexpressions. If x contains
update_table_tick (XEXP (x, i));
}
+ else if (fmt[i] == 'E')
+ for (j = 0; j < XVECLEN (x, i); j++)
+ update_table_tick (XVECEXP (x, i, j));
}
/* Record that REG is set to VALUE in insn INSN. If VALUE is zero, we
record_value_for_reg (rtx reg, rtx insn, rtx value)
{
unsigned int regno = REGNO (reg);
- unsigned int endregno
- = regno + (regno < FIRST_PSEUDO_REGISTER
- ? hard_regno_nregs[regno][GET_MODE (reg)] : 1);
+ unsigned int endregno = END_REGNO (reg);
unsigned int i;
+ reg_stat_type *rsp;
/* If VALUE contains REG and we have a previous value for REG, substitute
the previous value. */
/* Set things up so get_last_value is allowed to see anything set up to
our insn. */
- subst_low_cuid = INSN_CUID (insn);
+ subst_low_luid = DF_INSN_LUID (insn);
tem = get_last_value (reg);
/* If TEM is simply a binary operation with two CLOBBERs as operands,
register. */
for (i = regno; i < endregno; i++)
{
+ rsp = VEC_index (reg_stat_type, reg_stat, i);
+
if (insn)
- reg_stat[i].last_set = insn;
+ rsp->last_set = insn;
- reg_stat[i].last_set_value = 0;
- reg_stat[i].last_set_mode = 0;
- reg_stat[i].last_set_nonzero_bits = 0;
- reg_stat[i].last_set_sign_bit_copies = 0;
- reg_stat[i].last_death = 0;
- reg_stat[i].truncated_to_mode = 0;
+ rsp->last_set_value = 0;
+ rsp->last_set_mode = VOIDmode;
+ rsp->last_set_nonzero_bits = 0;
+ rsp->last_set_sign_bit_copies = 0;
+ rsp->last_death = 0;
+ rsp->truncated_to_mode = VOIDmode;
}
/* Mark registers that are being referenced in this value. */
for (i = regno; i < endregno; i++)
{
- reg_stat[i].last_set_label = label_tick;
- if (!insn || (value && reg_stat[i].last_set_table_tick == label_tick))
- reg_stat[i].last_set_invalid = 1;
+ rsp = VEC_index (reg_stat_type, reg_stat, i);
+ rsp->last_set_label = label_tick;
+ if (!insn
+ || (value && rsp->last_set_table_tick >= label_tick_ebb_start))
+ rsp->last_set_invalid = 1;
else
- reg_stat[i].last_set_invalid = 0;
+ rsp->last_set_invalid = 0;
}
/* 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. */
+ rsp = VEC_index (reg_stat_type, reg_stat, regno);
if (value && ! get_last_value_validate (&value, insn,
- reg_stat[regno].last_set_label, 0))
+ rsp->last_set_label, 0))
{
value = copy_rtx (value);
if (! get_last_value_validate (&value, insn,
- reg_stat[regno].last_set_label, 1))
+ rsp->last_set_label, 1))
value = 0;
}
/* For the main register being modified, update the value, the mode, the
nonzero bits, and the number of sign bit copies. */
- reg_stat[regno].last_set_value = value;
+ rsp->last_set_value = value;
if (value)
{
enum machine_mode mode = GET_MODE (reg);
- subst_low_cuid = INSN_CUID (insn);
- reg_stat[regno].last_set_mode = mode;
+ subst_low_luid = DF_INSN_LUID (insn);
+ rsp->last_set_mode = mode;
if (GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
mode = nonzero_bits_mode;
- reg_stat[regno].last_set_nonzero_bits = nonzero_bits (value, mode);
- reg_stat[regno].last_set_sign_bit_copies
+ rsp->last_set_nonzero_bits = nonzero_bits (value, mode);
+ rsp->last_set_sign_bit_copies
= num_sign_bit_copies (value, GET_MODE (reg));
}
}
set is occurring. */
static void
-record_dead_and_set_regs_1 (rtx dest, rtx setter, void *data)
+record_dead_and_set_regs_1 (rtx dest, const_rtx setter, void *data)
{
rtx record_dead_insn = (rtx) data;
else if (MEM_P (dest)
/* Ignore pushes, they clobber nothing. */
&& ! push_operand (dest, GET_MODE (dest)))
- mem_last_set = INSN_CUID (record_dead_insn);
+ mem_last_set = DF_INSN_LUID (record_dead_insn);
}
/* Update the records of when each REG was most recently set or killed
We update reg_stat[], in particular fields last_set, last_set_value,
last_set_mode, last_set_nonzero_bits, last_set_sign_bit_copies,
last_death, and also the similar information mem_last_set (which insn
- most recently modified memory) and last_call_cuid (which insn was the
+ most recently modified memory) and last_call_luid (which insn was the
most recent subroutine call). */
static void
&& REG_P (XEXP (link, 0)))
{
unsigned int regno = REGNO (XEXP (link, 0));
- unsigned int endregno
- = regno + (regno < FIRST_PSEUDO_REGISTER
- ? hard_regno_nregs[regno][GET_MODE (XEXP (link, 0))]
- : 1);
+ unsigned int endregno = END_REGNO (XEXP (link, 0));
for (i = regno; i < endregno; i++)
- reg_stat[i].last_death = insn;
+ {
+ reg_stat_type *rsp;
+
+ rsp = VEC_index (reg_stat_type, reg_stat, i);
+ rsp->last_death = insn;
+ }
}
else if (REG_NOTE_KIND (link) == REG_INC)
record_value_for_reg (XEXP (link, 0), insn, NULL_RTX);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
{
- reg_stat[i].last_set_value = 0;
- reg_stat[i].last_set_mode = 0;
- reg_stat[i].last_set_nonzero_bits = 0;
- reg_stat[i].last_set_sign_bit_copies = 0;
- reg_stat[i].last_death = 0;
- reg_stat[i].truncated_to_mode = 0;
+ reg_stat_type *rsp;
+
+ rsp = VEC_index (reg_stat_type, reg_stat, i);
+ rsp->last_set_invalid = 1;
+ rsp->last_set = insn;
+ rsp->last_set_value = 0;
+ rsp->last_set_mode = VOIDmode;
+ rsp->last_set_nonzero_bits = 0;
+ rsp->last_set_sign_bit_copies = 0;
+ rsp->last_death = 0;
+ rsp->truncated_to_mode = VOIDmode;
}
- last_call_cuid = mem_last_set = INSN_CUID (insn);
+ last_call_luid = mem_last_set = DF_INSN_LUID (insn);
/* We can't combine into a call pattern. Remember, though, that
- the return value register is set at this CUID. We could
+ the return value register is set at this LUID. We could
still replace a register with the return value from the
wrong subroutine call! */
note_stores (PATTERN (insn), record_dead_and_set_regs_1, NULL_RTX);
for (links = LOG_LINKS (insn); links;)
{
+ reg_stat_type *rsp;
+
insn = XEXP (links, 0);
set = single_set (insn);
continue;
}
- if (reg_stat[regno].last_set == insn)
+ rsp = VEC_index (reg_stat_type, reg_stat, regno);
+ if (rsp->last_set == insn)
{
if (SUBREG_PROMOTED_UNSIGNED_P (subreg) > 0)
- reg_stat[regno].last_set_nonzero_bits &= GET_MODE_MASK (mode);
+ rsp->last_set_nonzero_bits &= GET_MODE_MASK (mode);
}
if (REG_P (SET_SRC (set)))
an explicit truncation. */
static bool
-reg_truncated_to_mode (enum machine_mode mode, rtx x)
+reg_truncated_to_mode (enum machine_mode mode, const_rtx x)
{
- enum machine_mode truncated = reg_stat[REGNO (x)].truncated_to_mode;
+ reg_stat_type *rsp = VEC_index (reg_stat_type, reg_stat, REGNO (x));
+ enum machine_mode truncated = rsp->truncated_to_mode;
- if (truncated == 0 || reg_stat[REGNO (x)].truncation_label != label_tick)
+ if (truncated == 0
+ || rsp->truncation_label < label_tick_ebb_start)
return false;
if (GET_MODE_SIZE (truncated) <= GET_MODE_SIZE (mode))
return true;
return false;
}
-/* X is a REG or a SUBREG. If X is some sort of a truncation record
- it. For non-TRULY_NOOP_TRUNCATION targets we might be able to turn
- a truncate into a subreg using this information. */
+/* Callback for for_each_rtx. If *P is a hard reg or a subreg record the mode
+ that the register is accessed in. For non-TRULY_NOOP_TRUNCATION targets we
+ might be able to turn a truncate into a subreg using this information.
+ Return -1 if traversing *P is complete or 0 otherwise. */
-static void
-record_truncated_value (rtx x)
+static int
+record_truncated_value (rtx *p, void *data ATTRIBUTE_UNUSED)
{
+ rtx x = *p;
enum machine_mode truncated_mode;
-
+ reg_stat_type *rsp;
+
if (GET_CODE (x) == SUBREG && REG_P (SUBREG_REG (x)))
{
enum machine_mode original_mode = GET_MODE (SUBREG_REG (x));
truncated_mode = GET_MODE (x);
if (GET_MODE_SIZE (original_mode) <= GET_MODE_SIZE (truncated_mode))
- return;
+ return -1;
if (TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (truncated_mode),
GET_MODE_BITSIZE (original_mode)))
- return;
+ return -1;
x = SUBREG_REG (x);
}
- /* ??? For hard-regs we now record everthing. We might be able to
+ /* ??? For hard-regs we now record everything. We might be able to
optimize this using last_set_mode. */
else if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
truncated_mode = GET_MODE (x);
else
- return;
+ return 0;
- if (reg_stat[REGNO (x)].truncated_to_mode == 0
- || reg_stat[REGNO (x)].truncation_label < label_tick
+ rsp = VEC_index (reg_stat_type, reg_stat, REGNO (x));
+ if (rsp->truncated_to_mode == 0
+ || rsp->truncation_label < label_tick_ebb_start
|| (GET_MODE_SIZE (truncated_mode)
- < GET_MODE_SIZE (reg_stat[REGNO (x)].truncated_to_mode)))
+ < GET_MODE_SIZE (rsp->truncated_to_mode)))
{
- reg_stat[REGNO (x)].truncated_to_mode = truncated_mode;
- reg_stat[REGNO (x)].truncation_label = label_tick;
+ rsp->truncated_to_mode = truncated_mode;
+ rsp->truncation_label = label_tick;
}
+
+ return -1;
}
-/* Scan X for promoted SUBREGs and truncated REGs. For each one
- found, note what it implies to the registers used in it. */
+/* Callback for note_uses. Find hardregs and subregs of pseudos and
+ the modes they are used in. This can help truning TRUNCATEs into
+ SUBREGs. */
static void
-check_conversions (rtx insn, rtx x)
+record_truncated_values (rtx *x, void *data ATTRIBUTE_UNUSED)
{
- if (GET_CODE (x) == SUBREG || REG_P (x))
- {
- if (GET_CODE (x) == SUBREG
- && SUBREG_PROMOTED_VAR_P (x)
- && REG_P (SUBREG_REG (x)))
- record_promoted_value (insn, x);
+ for_each_rtx (x, record_truncated_value, NULL);
+}
- record_truncated_value (x);
- }
+/* Scan X for promoted SUBREGs. For each one found,
+ note what it implies to the registers used in it. */
+
+static void
+check_promoted_subreg (rtx insn, rtx x)
+{
+ if (GET_CODE (x) == SUBREG
+ && SUBREG_PROMOTED_VAR_P (x)
+ && REG_P (SUBREG_REG (x)))
+ record_promoted_value (insn, x);
else
{
const char *format = GET_RTX_FORMAT (GET_CODE (x));
switch (format[i])
{
case 'e':
- check_conversions (insn, XEXP (x, i));
+ check_promoted_subreg (insn, XEXP (x, i));
break;
case 'V':
case 'E':
if (XVEC (x, i) != 0)
for (j = 0; j < XVECLEN (x, i); j++)
- check_conversions (insn, XVECEXP (x, i, j));
+ check_promoted_subreg (insn, XVECEXP (x, i, j));
break;
}
}
rtx x = *loc;
const char *fmt = GET_RTX_FORMAT (GET_CODE (x));
int len = GET_RTX_LENGTH (GET_CODE (x));
- int i;
+ int i, j;
if (REG_P (x))
{
unsigned int regno = REGNO (x);
- unsigned int endregno
- = regno + (regno < FIRST_PSEUDO_REGISTER
- ? hard_regno_nregs[regno][GET_MODE (x)] : 1);
+ unsigned int endregno = END_REGNO (x);
unsigned int j;
for (j = regno; j < endregno; j++)
- if (reg_stat[j].last_set_invalid
- /* If this is a pseudo-register that was only set once and not
- live at the beginning of the function, it is always valid. */
- || (! (regno >= FIRST_PSEUDO_REGISTER
- && REG_N_SETS (regno) == 1
- && (! REGNO_REG_SET_P
- (ENTRY_BLOCK_PTR->next_bb->il.rtl->global_live_at_start,
- regno)))
- && reg_stat[j].last_set_label > tick))
+ {
+ reg_stat_type *rsp = VEC_index (reg_stat_type, reg_stat, j);
+ if (rsp->last_set_invalid
+ /* If this is a pseudo-register that was only set once and not
+ live at the beginning of the function, it is always valid. */
+ || (! (regno >= FIRST_PSEUDO_REGISTER
+ && REG_N_SETS (regno) == 1
+ && (!REGNO_REG_SET_P
+ (DF_LR_IN (ENTRY_BLOCK_PTR->next_bb), regno)))
+ && rsp->last_set_label > tick))
{
if (replace)
*loc = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
return replace;
}
+ }
return 1;
}
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 (MEM_P (x) && !MEM_READONLY_P (x)
- && INSN_CUID (insn) <= mem_last_set)
+ && DF_INSN_LUID (insn) <= mem_last_set)
{
if (replace)
*loc = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
replace) == 0)
return 0;
}
- /* Don't bother with these. They shouldn't occur anyway. */
else if (fmt[i] == 'E')
- return 0;
+ for (j = 0; j < XVECLEN (x, i); j++)
+ if (get_last_value_validate (&XVECEXP (x, i, j),
+ insn, tick, replace) == 0)
+ return 0;
}
/* If we haven't found a reason for it to be invalid, it is valid. */
is known longer known reliably. */
static rtx
-get_last_value (rtx x)
+get_last_value (const_rtx x)
{
unsigned int regno;
rtx value;
+ reg_stat_type *rsp;
/* 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,
return 0;
regno = REGNO (x);
- value = reg_stat[regno].last_set_value;
+ rsp = VEC_index (reg_stat_type, reg_stat, regno);
+ value = rsp->last_set_value;
/* 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
block. */
if (value == 0
- || (reg_stat[regno].last_set_label != label_tick
+ || (rsp->last_set_label < label_tick_ebb_start
&& (regno < FIRST_PSEUDO_REGISTER
|| REG_N_SETS (regno) != 1
- || (REGNO_REG_SET_P
- (ENTRY_BLOCK_PTR->next_bb->il.rtl->global_live_at_start,
- regno)))))
+ || REGNO_REG_SET_P
+ (DF_LR_IN (ENTRY_BLOCK_PTR->next_bb), regno))))
return 0;
/* 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. */
- if (INSN_CUID (reg_stat[regno].last_set) >= subst_low_cuid)
+ if (rsp->last_set_label == label_tick
+ && DF_INSN_LUID (rsp->last_set) >= subst_low_luid)
return 0;
/* If the value has all its registers valid, return it. */
- if (get_last_value_validate (&value, reg_stat[regno].last_set,
- reg_stat[regno].last_set_label, 0))
+ if (get_last_value_validate (&value, rsp->last_set,
+ rsp->last_set_label, 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_stat[regno].last_set,
- reg_stat[regno].last_set_label, 1))
+ if (get_last_value_validate (&value, rsp->last_set,
+ rsp->last_set_label, 1))
return value;
return 0;
}
\f
/* Return nonzero if expression X refers to a REG or to memory
- that is set in an instruction more recent than FROM_CUID. */
+ that is set in an instruction more recent than FROM_LUID. */
static int
-use_crosses_set_p (rtx x, int from_cuid)
+use_crosses_set_p (const_rtx x, int from_luid)
{
const char *fmt;
int i;
if (code == REG)
{
unsigned int regno = REGNO (x);
- unsigned endreg = regno + (regno < FIRST_PSEUDO_REGISTER
- ? hard_regno_nregs[regno][GET_MODE (x)] : 1);
+ unsigned endreg = END_REGNO (x);
#ifdef PUSH_ROUNDING
/* Don't allow uses of the stack pointer to be moved,
return 1;
#endif
for (; regno < endreg; regno++)
- if (reg_stat[regno].last_set
- && INSN_CUID (reg_stat[regno].last_set) > from_cuid)
- return 1;
+ {
+ reg_stat_type *rsp = VEC_index (reg_stat_type, reg_stat, regno);
+ if (rsp->last_set
+ && rsp->last_set_label == label_tick
+ && DF_INSN_LUID (rsp->last_set) > from_luid)
+ return 1;
+ }
return 0;
}
- if (code == MEM && mem_last_set > from_cuid)
+ if (code == MEM && mem_last_set > from_luid)
return 1;
fmt = GET_RTX_FORMAT (code);
{
int j;
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- if (use_crosses_set_p (XVECEXP (x, i, j), from_cuid))
+ if (use_crosses_set_p (XVECEXP (x, i, j), from_luid))
return 1;
}
else if (fmt[i] == 'e'
- && use_crosses_set_p (XEXP (x, i), from_cuid))
+ && use_crosses_set_p (XEXP (x, i), from_luid))
return 1;
}
return 0;
reg_dead_flag to 1 if X is a CLOBBER and to -1 it is a SET. */
static void
-reg_dead_at_p_1 (rtx dest, rtx x, void *data ATTRIBUTE_UNUSED)
+reg_dead_at_p_1 (rtx dest, const_rtx x, void *data ATTRIBUTE_UNUSED)
{
unsigned int regno, endregno;
return;
regno = REGNO (dest);
- endregno = regno + (regno < FIRST_PSEUDO_REGISTER
- ? hard_regno_nregs[regno][GET_MODE (dest)] : 1);
-
+ endregno = END_REGNO (dest);
if (reg_dead_endregno > regno && reg_dead_regno < endregno)
reg_dead_flag = (GET_CODE (x) == CLOBBER) ? 1 : -1;
}
/* Set variables for reg_dead_at_p_1. */
reg_dead_regno = REGNO (reg);
- reg_dead_endregno = reg_dead_regno + (reg_dead_regno < FIRST_PSEUDO_REGISTER
- ? hard_regno_nregs[reg_dead_regno]
- [GET_MODE (reg)]
- : 1);
+ reg_dead_endregno = END_REGNO (reg);
reg_dead_flag = 0;
return 0;
}
- /* Scan backwards until we find a REG_DEAD note, SET, CLOBBER, label, or
- beginning of function. */
- for (; insn && !LABEL_P (insn) && !BARRIER_P (insn);
- insn = prev_nonnote_insn (insn))
+ /* Scan backwards until we find a REG_DEAD note, SET, CLOBBER, or
+ beginning of basic block. */
+ block = BLOCK_FOR_INSN (insn);
+ for (;;)
{
- note_stores (PATTERN (insn), reg_dead_at_p_1, NULL);
- if (reg_dead_flag)
- return reg_dead_flag == 1 ? 1 : 0;
+ if (INSN_P (insn))
+ {
+ note_stores (PATTERN (insn), reg_dead_at_p_1, NULL);
+ if (reg_dead_flag)
+ return reg_dead_flag == 1 ? 1 : 0;
- if (find_regno_note (insn, REG_DEAD, reg_dead_regno))
- return 1;
- }
+ if (find_regno_note (insn, REG_DEAD, reg_dead_regno))
+ return 1;
+ }
- /* Get the basic block that we were in. */
- if (insn == 0)
- block = ENTRY_BLOCK_PTR->next_bb;
- else
- {
- FOR_EACH_BB (block)
- if (insn == BB_HEAD (block))
- break;
+ if (insn == BB_HEAD (block))
+ break;
- if (block == EXIT_BLOCK_PTR)
- return 0;
+ insn = PREV_INSN (insn);
}
+ /* Look at live-in sets for the basic block that we were in. */
for (i = reg_dead_regno; i < reg_dead_endregno; i++)
- if (REGNO_REG_SET_P (block->il.rtl->global_live_at_start, i))
+ if (REGNO_REG_SET_P (df_get_live_in (block), i))
return 0;
return 1;
}
\f
-/* Note hard registers in X that are used. This code is similar to
- that in flow.c, but much simpler since we don't care about pseudos. */
+/* Note hard registers in X that are used. */
static void
mark_used_regs_combine (rtx x)
If so, mark all of them just like the first. */
if (regno < FIRST_PSEUDO_REGISTER)
{
- unsigned int endregno, r;
-
/* None of this applies to the stack, frame or arg pointers. */
if (regno == STACK_POINTER_REGNUM
#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
|| regno == FRAME_POINTER_REGNUM)
return;
- endregno = regno + hard_regno_nregs[regno][GET_MODE (x)];
- for (r = regno; r < endregno; r++)
- SET_HARD_REG_BIT (newpat_used_regs, r);
+ add_to_hard_reg_set (&newpat_used_regs, GET_MODE (x), regno);
}
return;
rtx note = find_regno_note (insn, REG_DEAD, regno);
if (note)
- {
- REG_N_DEATHS (regno)--;
- remove_note (insn, note);
- }
+ remove_note (insn, note);
return note;
}
/* For each register (hardware or pseudo) used within expression X, if its
- death is in an instruction with cuid between FROM_CUID (inclusive) and
+ death is in an instruction with luid between FROM_LUID (inclusive) and
TO_INSN (exclusive), put a REG_DEAD note for that register in the
list headed by PNOTES.
notes will then be distributed as needed. */
static void
-move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn,
+move_deaths (rtx x, rtx maybe_kill_insn, int from_luid, rtx to_insn,
rtx *pnotes)
{
const char *fmt;
if (code == REG)
{
unsigned int regno = REGNO (x);
- rtx where_dead = reg_stat[regno].last_death;
- rtx before_dead, after_dead;
+ rtx where_dead = VEC_index (reg_stat_type, reg_stat, regno)->last_death;
/* 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;
- while (before_dead && INSN_UID (before_dead) > max_uid_cuid)
- before_dead = PREV_INSN (before_dead);
-
- after_dead = where_dead;
- while (after_dead && INSN_UID (after_dead) > max_uid_cuid)
- after_dead = NEXT_INSN (after_dead);
-
- if (before_dead && after_dead
- && INSN_CUID (before_dead) >= from_cuid
- && (INSN_CUID (after_dead) < INSN_CUID (to_insn)
- || (where_dead != after_dead
- && INSN_CUID (after_dead) == INSN_CUID (to_insn))))
+ if (where_dead
+ && BLOCK_FOR_INSN (where_dead) == BLOCK_FOR_INSN (to_insn)
+ && DF_INSN_LUID (where_dead) >= from_luid
+ && DF_INSN_LUID (where_dead) < DF_INSN_LUID (to_insn))
{
rtx note = remove_death (regno, where_dead);
> GET_MODE_SIZE (GET_MODE (x))))
{
unsigned int deadregno = REGNO (XEXP (note, 0));
- unsigned int deadend
- = (deadregno + hard_regno_nregs[deadregno]
- [GET_MODE (XEXP (note, 0))]);
- unsigned int ourend
- = regno + hard_regno_nregs[regno][GET_MODE (x)];
+ unsigned int deadend = END_HARD_REGNO (XEXP (note, 0));
+ unsigned int ourend = END_HARD_REGNO (x);
unsigned int i;
for (i = deadregno; i < deadend; i++)
if (i < regno || i >= ourend)
- REG_NOTES (where_dead)
- = gen_rtx_EXPR_LIST (REG_DEAD,
- regno_reg_rtx[i],
- REG_NOTES (where_dead));
+ add_reg_note (where_dead, REG_DEAD, regno_reg_rtx[i]);
}
/* If we didn't find any note, or if we found a REG_DEAD note that
&& regno < FIRST_PSEUDO_REGISTER
&& hard_regno_nregs[regno][GET_MODE (x)] > 1)
{
- unsigned int ourend
- = regno + hard_regno_nregs[regno][GET_MODE (x)];
+ unsigned int ourend = END_HARD_REGNO (x);
unsigned int i, offset;
rtx oldnotes = 0;
for (i = regno + offset; i < ourend; i++)
move_deaths (regno_reg_rtx[i],
- maybe_kill_insn, from_cuid, to_insn, &oldnotes);
+ maybe_kill_insn, from_luid, to_insn, &oldnotes);
}
if (note != 0 && GET_MODE (XEXP (note, 0)) == GET_MODE (x))
*pnotes = note;
}
else
- *pnotes = gen_rtx_EXPR_LIST (REG_DEAD, x, *pnotes);
-
- REG_N_DEATHS (regno)++;
+ *pnotes = alloc_reg_note (REG_DEAD, x, *pnotes);
}
return;
{
rtx dest = SET_DEST (x);
- move_deaths (SET_SRC (x), maybe_kill_insn, from_cuid, to_insn, pnotes);
+ move_deaths (SET_SRC (x), maybe_kill_insn, from_luid, 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, maybe_kill_insn, from_cuid, to_insn, pnotes);
+ move_deaths (dest, maybe_kill_insn, from_luid, to_insn, pnotes);
return;
}
being replaced so the old value is not used in this insn. */
if (MEM_P (dest))
- move_deaths (XEXP (dest, 0), maybe_kill_insn, from_cuid,
+ move_deaths (XEXP (dest, 0), maybe_kill_insn, from_luid,
to_insn, pnotes);
return;
}
{
int j;
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- move_deaths (XVECEXP (x, i, j), maybe_kill_insn, from_cuid,
+ move_deaths (XVECEXP (x, i, j), maybe_kill_insn, from_luid,
to_insn, pnotes);
}
else if (fmt[i] == 'e')
- move_deaths (XEXP (x, i), maybe_kill_insn, from_cuid, to_insn, pnotes);
+ move_deaths (XEXP (x, i), maybe_kill_insn, from_luid, to_insn, pnotes);
}
}
\f
if (tregno >= FIRST_PSEUDO_REGISTER || regno >= FIRST_PSEUDO_REGISTER)
return target == x;
- endtregno = tregno + hard_regno_nregs[tregno][GET_MODE (target)];
- endregno = regno + hard_regno_nregs[regno][GET_MODE (x)];
+ endtregno = end_hard_regno (GET_MODE (target), tregno);
+ endregno = end_hard_regno (GET_MODE (x), regno);
return endregno > tregno && regno < endtregno;
}
break;
case REG_INC:
- case REG_NO_CONFLICT:
/* These notes say something about how a register is used. They must
be present on any use of the register in I2 or I3. */
if (reg_mentioned_p (XEXP (note, 0), PATTERN (i3)))
}
break;
- case REG_LABEL:
+ case REG_LABEL_TARGET:
+ case REG_LABEL_OPERAND:
/* This can show up in several ways -- either directly in the
pattern, or hidden off in the constant pool with (or without?)
a REG_EQUAL note. */
place = i2;
}
- /* Don't attach REG_LABEL note to a JUMP_INSN. Add
- a JUMP_LABEL instead or decrement LABEL_NUSES. */
- if (place && JUMP_P (place))
+ /* For REG_LABEL_TARGET on a JUMP_P, we prefer to put the note
+ as a JUMP_LABEL or decrement LABEL_NUSES if it's already
+ there. */
+ if (place && JUMP_P (place)
+ && REG_NOTE_KIND (note) == REG_LABEL_TARGET
+ && (JUMP_LABEL (place) == NULL
+ || JUMP_LABEL (place) == XEXP (note, 0)))
{
rtx label = JUMP_LABEL (place);
-
+
if (!label)
JUMP_LABEL (place) = XEXP (note, 0);
- else
- {
- gcc_assert (label == XEXP (note, 0));
- if (LABEL_P (label))
- LABEL_NUSES (label)--;
- }
- place = 0;
+ else if (LABEL_P (label))
+ LABEL_NUSES (label)--;
}
- if (place2 && JUMP_P (place2))
+
+ if (place2 && JUMP_P (place2)
+ && REG_NOTE_KIND (note) == REG_LABEL_TARGET
+ && (JUMP_LABEL (place2) == NULL
+ || JUMP_LABEL (place2) == XEXP (note, 0)))
{
rtx label = JUMP_LABEL (place2);
-
+
if (!label)
JUMP_LABEL (place2) = XEXP (note, 0);
- else
- {
- gcc_assert (label == XEXP (note, 0));
- if (LABEL_P (label))
- LABEL_NUSES (label)--;
- }
+ else if (LABEL_P (label))
+ LABEL_NUSES (label)--;
place2 = 0;
}
break;
to simply delete it. */
break;
- case REG_RETVAL:
- /* If the insn previously containing this note still exists,
- put it back where it was. Otherwise move it to the previous
- insn. Adjust the corresponding REG_LIBCALL note. */
- if (!NOTE_P (from_insn))
- place = from_insn;
- else
- {
- tem = find_reg_note (XEXP (note, 0), REG_LIBCALL, NULL_RTX);
- place = prev_real_insn (from_insn);
- if (tem && place)
- XEXP (tem, 0) = place;
- /* If we're deleting the last remaining instruction of a
- libcall sequence, don't add the notes. */
- else if (XEXP (note, 0) == from_insn)
- tem = place = 0;
- /* Don't add the dangling REG_RETVAL note. */
- else if (! tem)
- place = 0;
- }
- break;
-
- case REG_LIBCALL:
- /* This is handled similarly to REG_RETVAL. */
- if (!NOTE_P (from_insn))
- place = from_insn;
- else
- {
- tem = find_reg_note (XEXP (note, 0), REG_RETVAL, NULL_RTX);
- place = next_real_insn (from_insn);
- if (tem && place)
- XEXP (tem, 0) = place;
- /* If we're deleting the last remaining instruction of a
- libcall sequence, don't add the notes. */
- else if (XEXP (note, 0) == from_insn)
- tem = place = 0;
- /* Don't add the dangling REG_LIBCALL note. */
- else if (! tem)
- place = 0;
- }
- break;
-
case REG_DEAD:
- /* If the register is used as an input in I3, it dies there.
+ /* If we replaced the right hand side of FROM_INSN with a
+ REG_EQUAL note, the original use of the dying register
+ will not have been combined into I3 and I2. In such cases,
+ FROM_INSN is guaranteed to be the first of the combined
+ instructions, so we simply need to search back before
+ FROM_INSN for the previous use or set of this register,
+ then alter the notes there appropriately.
+
+ If the register is used as an input in I3, it dies there.
Similarly for I2, if it is nonzero and adjacent to I3.
If the register is not used as an input in either I3 or I2
use of A and put the death note there. */
if (from_insn
- && CALL_P (from_insn)
- && find_reg_fusage (from_insn, USE, XEXP (note, 0)))
- place = from_insn;
- else if (reg_referenced_p (XEXP (note, 0), PATTERN (i3)))
- place = i3;
- else if (i2 != 0 && next_nonnote_insn (i2) == i3
- && reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
- place = i2;
-
- if (place == 0
- && (rtx_equal_p (XEXP (note, 0), elim_i2)
- || rtx_equal_p (XEXP (note, 0), elim_i1)))
- break;
+ && from_insn == i2mod
+ && !reg_overlap_mentioned_p (XEXP (note, 0), i2mod_new_rhs))
+ tem = from_insn;
+ else
+ {
+ if (from_insn
+ && CALL_P (from_insn)
+ && find_reg_fusage (from_insn, USE, XEXP (note, 0)))
+ place = from_insn;
+ else if (reg_referenced_p (XEXP (note, 0), PATTERN (i3)))
+ place = i3;
+ else if (i2 != 0 && next_nonnote_insn (i2) == i3
+ && reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
+ place = i2;
+ else if ((rtx_equal_p (XEXP (note, 0), elim_i2)
+ && !(i2mod
+ && reg_overlap_mentioned_p (XEXP (note, 0),
+ i2mod_old_rhs)))
+ || rtx_equal_p (XEXP (note, 0), elim_i1))
+ break;
+ tem = i3;
+ }
if (place == 0)
{
basic_block bb = this_basic_block;
- /* You might think you could search back from FROM_INSN
- rather than from I3, but combine tries to split invalid
- combined instructions. This can result in the old I2
- or I1 moving later in the insn sequence. */
- for (tem = PREV_INSN (i3); place == 0; tem = PREV_INSN (tem))
+ for (tem = PREV_INSN (tem); place == 0; tem = PREV_INSN (tem))
{
if (! INSN_P (tem))
{
distribute_links (LOG_LINKS (tem));
SET_INSN_DELETED (tem);
+ if (tem == i2)
+ i2 = NULL_RTX;
#ifdef HAVE_cc0
/* Delete the setter too. */
distribute_links (LOG_LINKS (cc0_setter));
SET_INSN_DELETED (cc0_setter);
+ if (cc0_setter == i2)
+ i2 = NULL_RTX;
}
#endif
}
|| (CALL_P (tem)
&& find_reg_fusage (tem, USE, XEXP (note, 0))))
{
- /* This may not be the correct place for the death
- note if FROM_INSN is before TEM, and the reg is
- set between FROM_INSN and TEM. The reg might
- die two or more times. An existing death note
- means we are looking at the wrong live range. */
- if (from_insn
- && INSN_CUID (from_insn) < INSN_CUID (tem)
- && find_regno_note (tem, REG_DEAD,
- REGNO (XEXP (note, 0))))
- {
- tem = from_insn;
- if (tem == BB_HEAD (bb))
- break;
- continue;
- }
-
place = tem;
/* If we are doing a 3->2 combination, and we have a
i2 but does not die in i2, and place is between i2
and i3, then we may need to move a link from place to
i2. */
- if (i2 && INSN_UID (place) <= max_uid_cuid
- && INSN_CUID (place) > INSN_CUID (i2)
+ if (i2 && DF_INSN_LUID (place) > DF_INSN_LUID (i2)
&& from_insn
- && INSN_CUID (from_insn) > INSN_CUID (i2)
+ && DF_INSN_LUID (from_insn) > DF_INSN_LUID (i2)
&& reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
{
rtx links = LOG_LINKS (place);
break;
}
- /* We haven't found an insn for the death note and it
- is still a REG_DEAD note, but we have hit the beginning
- of the block. If the existing life info says the reg
- was dead, there's nothing left to do. Otherwise, we'll
- need to do a global life update after combine. */
- if (REG_NOTE_KIND (note) == REG_DEAD && place == 0
- && REGNO_REG_SET_P (bb->il.rtl->global_live_at_start,
- REGNO (XEXP (note, 0))))
- SET_BIT (refresh_blocks, this_basic_block->index);
}
/* If the register is set or already dead at PLACE, we needn't do
if (place && REG_NOTE_KIND (note) == REG_DEAD)
{
unsigned int regno = REGNO (XEXP (note, 0));
-
- /* Similarly, if the instruction on which we want to place
- the note is a noop, we'll need do a global live update
- after we remove them in delete_noop_moves. */
- if (noop_move_p (place))
- SET_BIT (refresh_blocks, this_basic_block->index);
+ reg_stat_type *rsp = VEC_index (reg_stat_type, reg_stat, regno);
if (dead_or_set_p (place, XEXP (note, 0))
|| reg_bitfield_target_p (XEXP (note, 0), PATTERN (place)))
/* Unless the register previously died in PLACE, clear
last_death. [I no longer understand why this is
being done.] */
- if (reg_stat[regno].last_death != place)
- reg_stat[regno].last_death = 0;
+ if (rsp->last_death != place)
+ rsp->last_death = 0;
place = 0;
}
else
- reg_stat[regno].last_death = place;
+ rsp->last_death = place;
/* If this is a death note for a hard reg that is occupying
multiple registers, ensure that we are still using all
if (place && regno < FIRST_PSEUDO_REGISTER
&& hard_regno_nregs[regno][GET_MODE (XEXP (note, 0))] > 1)
{
- unsigned int endregno
- = regno + hard_regno_nregs[regno]
- [GET_MODE (XEXP (note, 0))];
+ unsigned int endregno = END_HARD_REGNO (XEXP (note, 0));
int all_used = 1;
unsigned int i;
&& ! reg_bitfield_target_p (piece,
PATTERN (place)))
{
- rtx new_note
- = gen_rtx_EXPR_LIST (REG_DEAD, piece, NULL_RTX);
+ rtx new_note = alloc_reg_note (REG_DEAD, piece,
+ NULL_RTX);
distribute_notes (new_note, place, place,
NULL_RTX, NULL_RTX, NULL_RTX);
if (! INSN_P (tem))
{
if (tem == BB_HEAD (bb))
- {
- SET_BIT (refresh_blocks,
- this_basic_block->index);
- break;
- }
+ break;
continue;
}
if (dead_or_set_p (tem, piece)
|| reg_bitfield_target_p (piece,
PATTERN (tem)))
{
- REG_NOTES (tem)
- = gen_rtx_EXPR_LIST (REG_UNUSED, piece,
- REG_NOTES (tem));
+ add_reg_note (tem, REG_UNUSED, piece);
break;
}
}
XEXP (note, 1) = REG_NOTES (place);
REG_NOTES (place) = note;
}
- else if ((REG_NOTE_KIND (note) == REG_DEAD
- || REG_NOTE_KIND (note) == REG_UNUSED)
- && REG_P (XEXP (note, 0)))
- REG_N_DEATHS (REGNO (XEXP (note, 0)))--;
if (place2)
- {
- if ((REG_NOTE_KIND (note) == REG_DEAD
- || REG_NOTE_KIND (note) == REG_UNUSED)
- && REG_P (XEXP (note, 0)))
- REG_N_DEATHS (REGNO (XEXP (note, 0)))++;
-
- REG_NOTES (place2) = gen_rtx_fmt_ee (GET_CODE (note),
- REG_NOTE_KIND (note),
- XEXP (note, 0),
- REG_NOTES (place2));
- }
+ add_reg_note (place2, REG_NOTE_KIND (note), XEXP (note, 0));
}
}
\f
/* Set added_links_insn to the earliest insn we added a
link to. */
if (added_links_insn == 0
- || INSN_CUID (added_links_insn) > INSN_CUID (place))
+ || DF_INSN_LUID (added_links_insn) > DF_INSN_LUID (place))
added_links_insn = place;
}
}
return for_each_rtx (&equiv, unmentioned_reg_p_1, expr);
}
\f
-/* Compute INSN_CUID for INSN, which is an insn made by combine. */
-
-static int
-insn_cuid (rtx insn)
-{
- while (insn != 0 && INSN_UID (insn) > max_uid_cuid
- && NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == USE)
- insn = NEXT_INSN (insn);
-
- gcc_assert (INSN_UID (insn) <= max_uid_cuid);
-
- return INSN_CUID (insn);
-}
-\f
void
dump_combine_stats (FILE *file)
{
total_attempts, total_merges, total_extras, total_successes);
}
\f
-
static bool
gate_handle_combine (void)
{
}
/* Try combining insns through substitution. */
-static void
+static unsigned int
rest_of_handle_combine (void)
{
- int rebuild_jump_labels_after_combine
+ int rebuild_jump_labels_after_combine;
+
+ df_set_flags (DF_LR_RUN_DCE + DF_DEFER_INSN_RESCAN);
+ df_note_add_problem ();
+ df_analyze ();
+
+ regstat_init_n_sets_and_refs ();
+
+ rebuild_jump_labels_after_combine
= combine_instructions (get_insns (), max_reg_num ());
/* Combining insns may have turned an indirect jump into a
{
timevar_push (TV_JUMP);
rebuild_jump_labels (get_insns ());
+ cleanup_cfg (0);
timevar_pop (TV_JUMP);
-
- delete_dead_jumptables ();
- cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE);
}
+
+ regstat_free_n_sets_and_refs ();
+ return 0;
}
-struct tree_opt_pass pass_combine =
+struct rtl_opt_pass pass_combine =
{
+ {
+ RTL_PASS,
"combine", /* name */
gate_handle_combine, /* gate */
rest_of_handle_combine, /* execute */
NULL, /* next */
0, /* static_pass_number */
TV_COMBINE, /* tv_id */
- 0, /* properties_required */
+ PROP_cfglayout, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func |
+ TODO_df_finish | TODO_verify_rtl_sharing |
TODO_ggc_collect, /* todo_flags_finish */
- 'c' /* letter */
+ }
};
-