/* Optimize by combining instructions for GNU compiler.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of GCC.
flow.c aren't completely updated:
- reg_live_length is not updated
- - reg_n_refs is not adjusted in the rare case when a register is
- no longer required in a computation
- - there are extremely rare cases (see distribute_regnotes) when a
- REG_DEAD note is lost
- a LOG_LINKS entry that refers to an insn with multiple SETs may be
removed because there is no way to know which register it was
linking
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "rtl.h"
+#include "tree.h"
#include "tm_p.h"
#include "flags.h"
#include "regs.h"
#include "recog.h"
#include "real.h"
#include "toplev.h"
-
-/* It is not safe to use ordinary gen_lowpart in combine.
- Use gen_lowpart_for_combine instead. See comments there. */
-#define gen_lowpart dont_use_gen_lowpart_you_dummy
+#include "target.h"
/* Number of attempts to combine instructions in this function. */
#define UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD(val) \
(((unsigned HOST_WIDE_INT) (val) << (BITS_PER_WORD - 1)) << 1)
+#define nonzero_bits(X, M) \
+ cached_nonzero_bits (X, M, NULL_RTX, VOIDmode, 0)
+
+#define num_sign_bit_copies(X, M) \
+ cached_num_sign_bit_copies (X, M, NULL_RTX, VOIDmode, 0)
+
/* Maximum register number, which is the size of the tables below. */
static unsigned int combine_max_regno;
static rtx subst_insn;
-/* This is an insn that belongs before subst_insn, but is not currently
- on the insn chain. */
-
-static rtx subst_prev_insn;
-
/* This is the lowest CUID 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
static rtx added_links_insn;
-/* Basic block number of the block in which we are performing combines. */
-static int this_basic_block;
+/* Basic block in which we are performing combines. */
+static basic_block this_basic_block;
/* 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;
-static int need_refresh;
\f
/* The next group of arrays allows the recording of the last value assigned
- to (hard or pseudo) register n. We use this information to see if a
+ to (hard or pseudo) register n. We use this information to see if an
operation being processed is redundant given a prior operation performed
on the register. For example, an `and' with a constant is redundant if
all the zero bits are already known to be turned off.
register was assigned
reg_last_set_table_tick records the value of label_tick when a
value using the register is assigned
- reg_last_set_invalid set to non-zero when it is not valid
+ reg_last_set_invalid set to nonzero when it is not valid
to use the value of this register in some
register's value
and the register being validly contained in some other expression in the
table.
- Entry I in reg_last_set_value is valid if it is non-zero, and either
+ Entry I in reg_last_set_value is valid if it is nonzero, and either
reg_n_sets[i] is 1 or reg_last_set_label[i] == label_tick.
Register I may validly appear in any expression returned for the value
not validly appear in an expression, the register is replaced by
something that won't match, (clobber (const_int 0)).
- reg_last_set_invalid[i] is set non-zero when register I is being assigned
+ reg_last_set_invalid[i] is set nonzero when register I is being assigned
to and reg_last_set_table_tick[i] == label_tick. */
/* Record last value assigned to (hard or pseudo) register n. */
static int *reg_last_set_table_tick;
-/* Set non-zero if references to register n in expressions should not be
+/* Set nonzero if references to register n in expressions should not be
used. */
static char *reg_last_set_invalid;
{
struct undo *next;
int is_int;
- union {rtx r; unsigned int i;} old_contents;
- union {rtx *r; unsigned int *i;} where;
+ union {rtx r; int i;} old_contents;
+ union {rtx *r; int *i;} where;
};
/* Record a bunch of changes to be undone, up to MAX_UNDO of them.
static int n_occurrences;
-static void do_SUBST PARAMS ((rtx *, rtx));
-static void do_SUBST_INT PARAMS ((unsigned int *,
- unsigned int));
-static void init_reg_last_arrays PARAMS ((void));
-static void setup_incoming_promotions PARAMS ((void));
-static void set_nonzero_bits_and_sign_copies PARAMS ((rtx, rtx, void *));
-static int cant_combine_insn_p PARAMS ((rtx));
-static int can_combine_p PARAMS ((rtx, rtx, rtx, rtx, rtx *, rtx *));
-static int sets_function_arg_p PARAMS ((rtx));
-static int combinable_i3pat PARAMS ((rtx, rtx *, rtx, rtx, int, rtx *));
-static int contains_muldiv PARAMS ((rtx));
-static rtx try_combine PARAMS ((rtx, rtx, rtx, int *));
-static void undo_all PARAMS ((void));
-static void undo_commit PARAMS ((void));
-static rtx *find_split_point PARAMS ((rtx *, rtx));
-static rtx subst PARAMS ((rtx, rtx, rtx, int, int));
-static rtx combine_simplify_rtx PARAMS ((rtx, enum machine_mode, int, int));
-static rtx simplify_if_then_else PARAMS ((rtx));
-static rtx simplify_set PARAMS ((rtx));
-static rtx simplify_logical PARAMS ((rtx, int));
-static rtx expand_compound_operation PARAMS ((rtx));
-static rtx expand_field_assignment PARAMS ((rtx));
-static rtx make_extraction PARAMS ((enum machine_mode, rtx, HOST_WIDE_INT,
- rtx, unsigned HOST_WIDE_INT, int,
- int, int));
-static rtx extract_left_shift PARAMS ((rtx, int));
-static rtx make_compound_operation PARAMS ((rtx, enum rtx_code));
-static int get_pos_from_mask PARAMS ((unsigned HOST_WIDE_INT,
- unsigned HOST_WIDE_INT *));
-static rtx force_to_mode PARAMS ((rtx, enum machine_mode,
- unsigned HOST_WIDE_INT, rtx, int));
-static rtx if_then_else_cond PARAMS ((rtx, rtx *, rtx *));
-static rtx known_cond PARAMS ((rtx, enum rtx_code, rtx, rtx));
-static int rtx_equal_for_field_assignment_p PARAMS ((rtx, rtx));
-static rtx make_field_assignment PARAMS ((rtx));
-static rtx apply_distributive_law PARAMS ((rtx));
-static rtx simplify_and_const_int PARAMS ((rtx, enum machine_mode, rtx,
- unsigned HOST_WIDE_INT));
-static unsigned HOST_WIDE_INT nonzero_bits PARAMS ((rtx, enum machine_mode));
-static unsigned int num_sign_bit_copies PARAMS ((rtx, enum machine_mode));
-static int merge_outer_ops PARAMS ((enum rtx_code *, HOST_WIDE_INT *,
- enum rtx_code, HOST_WIDE_INT,
- enum machine_mode, int *));
-static rtx simplify_shift_const PARAMS ((rtx, enum rtx_code, enum machine_mode,
- rtx, int));
-static int recog_for_combine PARAMS ((rtx *, rtx, rtx *));
-static rtx gen_lowpart_for_combine PARAMS ((enum machine_mode, rtx));
-static rtx gen_binary PARAMS ((enum rtx_code, enum machine_mode,
- rtx, rtx));
-static enum rtx_code simplify_comparison PARAMS ((enum rtx_code, rtx *, rtx *));
-static void update_table_tick PARAMS ((rtx));
-static void record_value_for_reg PARAMS ((rtx, rtx, rtx));
-static void check_promoted_subreg PARAMS ((rtx, rtx));
-static void record_dead_and_set_regs_1 PARAMS ((rtx, rtx, void *));
-static void record_dead_and_set_regs PARAMS ((rtx));
-static int get_last_value_validate PARAMS ((rtx *, rtx, int, int));
-static rtx get_last_value PARAMS ((rtx));
-static int use_crosses_set_p PARAMS ((rtx, int));
-static void reg_dead_at_p_1 PARAMS ((rtx, rtx, void *));
-static int reg_dead_at_p PARAMS ((rtx, rtx));
-static void move_deaths PARAMS ((rtx, rtx, int, rtx, rtx *));
-static int reg_bitfield_target_p PARAMS ((rtx, rtx));
-static void distribute_notes PARAMS ((rtx, rtx, rtx, rtx, rtx, rtx));
-static void distribute_links PARAMS ((rtx));
-static void mark_used_regs_combine PARAMS ((rtx));
-static int insn_cuid PARAMS ((rtx));
-static void record_promoted_value PARAMS ((rtx, rtx));
-static rtx reversed_comparison PARAMS ((rtx, enum machine_mode, rtx, rtx));
-static enum rtx_code combine_reversed_comparison_code PARAMS ((rtx));
+static void do_SUBST (rtx *, rtx);
+static void do_SUBST_INT (int *, int);
+static void init_reg_last_arrays (void);
+static void setup_incoming_promotions (void);
+static void set_nonzero_bits_and_sign_copies (rtx, 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 int contains_muldiv (rtx);
+static rtx try_combine (rtx, rtx, rtx, int *);
+static void undo_all (void);
+static void undo_commit (void);
+static rtx *find_split_point (rtx *, rtx);
+static rtx subst (rtx, rtx, rtx, int, int);
+static rtx combine_simplify_rtx (rtx, enum machine_mode, int);
+static rtx simplify_if_then_else (rtx);
+static rtx simplify_set (rtx);
+static rtx simplify_logical (rtx);
+static rtx expand_compound_operation (rtx);
+static rtx expand_field_assignment (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 rtx make_compound_operation (rtx, enum rtx_code);
+static int get_pos_from_mask (unsigned HOST_WIDE_INT,
+ unsigned HOST_WIDE_INT *);
+static rtx force_to_mode (rtx, enum machine_mode,
+ unsigned HOST_WIDE_INT, rtx, int);
+static rtx if_then_else_cond (rtx, rtx *, rtx *);
+static rtx known_cond (rtx, enum rtx_code, rtx, rtx);
+static int rtx_equal_for_field_assignment_p (rtx, rtx);
+static rtx make_field_assignment (rtx);
+static rtx apply_distributive_law (rtx);
+static rtx simplify_and_const_int (rtx, enum machine_mode, rtx,
+ unsigned HOST_WIDE_INT);
+static unsigned HOST_WIDE_INT cached_nonzero_bits (rtx, enum machine_mode,
+ rtx, enum machine_mode,
+ unsigned HOST_WIDE_INT);
+static unsigned HOST_WIDE_INT nonzero_bits1 (rtx, enum machine_mode, rtx,
+ enum machine_mode,
+ unsigned HOST_WIDE_INT);
+static unsigned int cached_num_sign_bit_copies (rtx, enum machine_mode, rtx,
+ enum machine_mode,
+ unsigned int);
+static unsigned int num_sign_bit_copies1 (rtx, enum machine_mode, rtx,
+ enum machine_mode, unsigned int);
+static int merge_outer_ops (enum rtx_code *, HOST_WIDE_INT *, enum rtx_code,
+ HOST_WIDE_INT, enum machine_mode, int *);
+static rtx simplify_shift_const (rtx, enum rtx_code, enum machine_mode, rtx,
+ int);
+static int recog_for_combine (rtx *, rtx, rtx *);
+static rtx gen_lowpart_for_combine (enum machine_mode, rtx);
+static rtx gen_binary (enum rtx_code, enum machine_mode, rtx, rtx);
+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_promoted_subreg (rtx, rtx);
+static void record_dead_and_set_regs_1 (rtx, 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 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);
+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 rtx reversed_comparison (rtx, enum machine_mode, rtx, rtx);
+static enum rtx_code combine_reversed_comparison_code (rtx);
+static int unmentioned_reg_p_1 (rtx *, void *);
+static bool unmentioned_reg_p (rtx, rtx);
\f
/* Substitute NEWVAL, an rtx expression, into INTO, a place in some
insn. The substitution can be undone by undo_all. If INTO is already
the undo table. */
static void
-do_SUBST (into, newval)
- rtx *into, newval;
+do_SUBST (rtx *into, rtx newval)
{
struct undo *buf;
rtx oldval = *into;
|| (GET_CODE (oldval) == ZERO_EXTEND
&& GET_CODE (XEXP (oldval, 0)) == CONST_INT))
abort ();
- }
+ }
if (undobuf.frees)
buf = undobuf.frees, undobuf.frees = buf->next;
else
- buf = (struct undo *) xmalloc (sizeof (struct undo));
+ buf = xmalloc (sizeof (struct undo));
buf->is_int = 0;
buf->where.r = into;
not safe. */
static void
-do_SUBST_INT (into, newval)
- unsigned int *into, newval;
+do_SUBST_INT (int *into, int newval)
{
struct undo *buf;
- unsigned int oldval = *into;
+ int oldval = *into;
if (oldval == newval)
return;
if (undobuf.frees)
buf = undobuf.frees, undobuf.frees = buf->next;
else
- buf = (struct undo *) xmalloc (sizeof (struct undo));
+ buf = xmalloc (sizeof (struct undo));
buf->is_int = 1;
buf->where.i = into;
/* Main entry point for combiner. F is the first insn of the function.
NREGS is the first unused pseudo-reg number.
- Return non-zero if the combiner has turned an indirect jump
+ Return nonzero if the combiner has turned an indirect jump
instruction into a direct jump. */
int
-combine_instructions (f, nregs)
- rtx f;
- unsigned int nregs;
+combine_instructions (rtx f, unsigned int nregs)
{
rtx insn, next;
#ifdef HAVE_cc0
combine_max_regno = nregs;
- reg_nonzero_bits = ((unsigned HOST_WIDE_INT *)
- xcalloc (nregs, sizeof (unsigned HOST_WIDE_INT)));
- reg_sign_bit_copies
- = (unsigned char *) xcalloc (nregs, sizeof (unsigned char));
-
- reg_last_death = (rtx *) xmalloc (nregs * sizeof (rtx));
- reg_last_set = (rtx *) xmalloc (nregs * sizeof (rtx));
- reg_last_set_value = (rtx *) xmalloc (nregs * sizeof (rtx));
- reg_last_set_table_tick = (int *) xmalloc (nregs * sizeof (int));
- reg_last_set_label = (int *) xmalloc (nregs * sizeof (int));
- reg_last_set_invalid = (char *) xmalloc (nregs * sizeof (char));
- reg_last_set_mode
- = (enum machine_mode *) xmalloc (nregs * sizeof (enum machine_mode));
- reg_last_set_nonzero_bits
- = (unsigned HOST_WIDE_INT *) xmalloc (nregs * sizeof (HOST_WIDE_INT));
- reg_last_set_sign_bit_copies
- = (char *) xmalloc (nregs * sizeof (char));
+ /* It is not safe to use ordinary gen_lowpart in combine.
+ See comments in gen_lowpart_for_combine. */
+ gen_lowpart = gen_lowpart_for_combine;
+
+ reg_nonzero_bits = xcalloc (nregs, sizeof (unsigned HOST_WIDE_INT));
+ reg_sign_bit_copies = xcalloc (nregs, sizeof (unsigned char));
+
+ reg_last_death = xmalloc (nregs * sizeof (rtx));
+ reg_last_set = xmalloc (nregs * sizeof (rtx));
+ reg_last_set_value = xmalloc (nregs * sizeof (rtx));
+ reg_last_set_table_tick = xmalloc (nregs * sizeof (int));
+ reg_last_set_label = xmalloc (nregs * sizeof (int));
+ reg_last_set_invalid = xmalloc (nregs * sizeof (char));
+ reg_last_set_mode = xmalloc (nregs * sizeof (enum machine_mode));
+ reg_last_set_nonzero_bits = xmalloc (nregs * sizeof (HOST_WIDE_INT));
+ reg_last_set_sign_bit_copies = xmalloc (nregs * sizeof (char));
init_reg_last_arrays ();
if (INSN_UID (insn) > i)
i = INSN_UID (insn);
- uid_cuid = (int *) xmalloc ((i + 1) * sizeof (int));
+ uid_cuid = xmalloc ((i + 1) * sizeof (int));
max_uid_cuid = i;
nonzero_bits_mode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0);
label_tick = 1;
- /* We need to initialize it here, because record_dead_and_set_regs may call
- get_last_value. */
- subst_prev_insn = NULL_RTX;
-
setup_incoming_promotions ();
- refresh_blocks = sbitmap_alloc (n_basic_blocks);
+ refresh_blocks = sbitmap_alloc (last_basic_block);
sbitmap_zero (refresh_blocks);
- need_refresh = 0;
for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
{
/* Now scan all the insns in forward order. */
- this_basic_block = -1;
label_tick = 1;
last_call_cuid = 0;
mem_last_set = 0;
init_reg_last_arrays ();
setup_incoming_promotions ();
- for (insn = f; insn; insn = next ? next : NEXT_INSN (insn))
+ FOR_EACH_BB (this_basic_block)
{
- next = 0;
-
- /* If INSN starts a new basic block, update our basic block number. */
- if (this_basic_block + 1 < n_basic_blocks
- && BLOCK_HEAD (this_basic_block + 1) == insn)
- this_basic_block++;
-
- if (GET_CODE (insn) == CODE_LABEL)
- label_tick++;
-
- else if (INSN_P (insn))
+ for (insn = BB_HEAD (this_basic_block);
+ insn != NEXT_INSN (BB_END (this_basic_block));
+ insn = next ? next : NEXT_INSN (insn))
{
- /* See if we know about function return values before this
- insn based upon SUBREG flags. */
- check_promoted_subreg (insn, PATTERN (insn));
-
- /* Try this insn with each insn it links back to. */
+ next = 0;
- for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
- if ((next = try_combine (insn, XEXP (links, 0),
- NULL_RTX, &new_direct_jump_p)) != 0)
- goto retry;
+ if (GET_CODE (insn) == CODE_LABEL)
+ label_tick++;
- /* Try each sequence of three linked insns ending with this one. */
-
- for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
+ else if (INSN_P (insn))
{
- rtx link = XEXP (links, 0);
+ /* See if we know about function return values before this
+ insn based upon SUBREG flags. */
+ check_promoted_subreg (insn, PATTERN (insn));
- /* If the linked insn has been replaced by a note, then there
- is no point in pursuing this chain any further. */
- if (GET_CODE (link) == NOTE)
- continue;
+ /* Try this insn with each insn it links back to. */
- for (nextlinks = LOG_LINKS (link);
- nextlinks;
- nextlinks = XEXP (nextlinks, 1))
- if ((next = try_combine (insn, link,
- XEXP (nextlinks, 0),
- &new_direct_jump_p)) != 0)
+ for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
+ if ((next = try_combine (insn, XEXP (links, 0),
+ NULL_RTX, &new_direct_jump_p)) != 0)
goto retry;
- }
+
+ /* Try each sequence of three linked insns ending with this one. */
+
+ for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
+ {
+ rtx link = XEXP (links, 0);
+
+ /* If the linked insn has been replaced by a note, then there
+ is no point in pursuing this chain any further. */
+ if (GET_CODE (link) == NOTE)
+ continue;
+
+ for (nextlinks = LOG_LINKS (link);
+ nextlinks;
+ nextlinks = XEXP (nextlinks, 1))
+ if ((next = try_combine (insn, link,
+ XEXP (nextlinks, 0),
+ &new_direct_jump_p)) != 0)
+ goto retry;
+ }
#ifdef HAVE_cc0
- /* Try to combine a jump insn that uses CC0
- with a preceding insn that sets CC0, and maybe with its
- logical predecessor as well.
- This is how we make decrement-and-branch insns.
- We need this special code because data flow connections
- via CC0 do not get entered in LOG_LINKS. */
-
- if (GET_CODE (insn) == JUMP_INSN
- && (prev = prev_nonnote_insn (insn)) != 0
- && GET_CODE (prev) == INSN
- && sets_cc0_p (PATTERN (prev)))
- {
- if ((next = try_combine (insn, prev,
- NULL_RTX, &new_direct_jump_p)) != 0)
- goto retry;
-
- for (nextlinks = LOG_LINKS (prev); nextlinks;
- nextlinks = XEXP (nextlinks, 1))
- if ((next = try_combine (insn, prev,
- XEXP (nextlinks, 0),
- &new_direct_jump_p)) != 0)
- goto retry;
- }
+ /* Try to combine a jump insn that uses CC0
+ with a preceding insn that sets CC0, and maybe with its
+ logical predecessor as well.
+ This is how we make decrement-and-branch insns.
+ We need this special code because data flow connections
+ via CC0 do not get entered in LOG_LINKS. */
+
+ if (GET_CODE (insn) == JUMP_INSN
+ && (prev = prev_nonnote_insn (insn)) != 0
+ && GET_CODE (prev) == INSN
+ && sets_cc0_p (PATTERN (prev)))
+ {
+ if ((next = try_combine (insn, prev,
+ NULL_RTX, &new_direct_jump_p)) != 0)
+ goto retry;
+
+ for (nextlinks = LOG_LINKS (prev); nextlinks;
+ nextlinks = XEXP (nextlinks, 1))
+ if ((next = try_combine (insn, prev,
+ XEXP (nextlinks, 0),
+ &new_direct_jump_p)) != 0)
+ goto retry;
+ }
- /* Do the same for an insn that explicitly references CC0. */
- if (GET_CODE (insn) == INSN
- && (prev = prev_nonnote_insn (insn)) != 0
- && GET_CODE (prev) == INSN
- && sets_cc0_p (PATTERN (prev))
- && GET_CODE (PATTERN (insn)) == SET
- && reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (insn))))
- {
- if ((next = try_combine (insn, prev,
- NULL_RTX, &new_direct_jump_p)) != 0)
- goto retry;
+ /* Do the same for an insn that explicitly references CC0. */
+ if (GET_CODE (insn) == INSN
+ && (prev = prev_nonnote_insn (insn)) != 0
+ && GET_CODE (prev) == INSN
+ && sets_cc0_p (PATTERN (prev))
+ && GET_CODE (PATTERN (insn)) == SET
+ && reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (insn))))
+ {
+ if ((next = try_combine (insn, prev,
+ NULL_RTX, &new_direct_jump_p)) != 0)
+ goto retry;
+
+ for (nextlinks = LOG_LINKS (prev); nextlinks;
+ nextlinks = XEXP (nextlinks, 1))
+ if ((next = try_combine (insn, prev,
+ XEXP (nextlinks, 0),
+ &new_direct_jump_p)) != 0)
+ goto retry;
+ }
- for (nextlinks = LOG_LINKS (prev); nextlinks;
- nextlinks = XEXP (nextlinks, 1))
- if ((next = try_combine (insn, prev,
- XEXP (nextlinks, 0),
- &new_direct_jump_p)) != 0)
+ /* Finally, see if any of the insns that this insn links to
+ explicitly references CC0. If so, try this insn, that insn,
+ and its predecessor if it sets CC0. */
+ for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
+ if (GET_CODE (XEXP (links, 0)) == INSN
+ && GET_CODE (PATTERN (XEXP (links, 0))) == SET
+ && reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (XEXP (links, 0))))
+ && (prev = prev_nonnote_insn (XEXP (links, 0))) != 0
+ && GET_CODE (prev) == INSN
+ && sets_cc0_p (PATTERN (prev))
+ && (next = try_combine (insn, XEXP (links, 0),
+ prev, &new_direct_jump_p)) != 0)
goto retry;
- }
-
- /* Finally, see if any of the insns that this insn links to
- explicitly references CC0. If so, try this insn, that insn,
- and its predecessor if it sets CC0. */
- for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
- if (GET_CODE (XEXP (links, 0)) == INSN
- && GET_CODE (PATTERN (XEXP (links, 0))) == SET
- && reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (XEXP (links, 0))))
- && (prev = prev_nonnote_insn (XEXP (links, 0))) != 0
- && GET_CODE (prev) == INSN
- && sets_cc0_p (PATTERN (prev))
- && (next = try_combine (insn, XEXP (links, 0),
- prev, &new_direct_jump_p)) != 0)
- goto retry;
#endif
- /* Try combining an insn with two different insns whose results it
- uses. */
- for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
- for (nextlinks = XEXP (links, 1); nextlinks;
- nextlinks = XEXP (nextlinks, 1))
- if ((next = try_combine (insn, XEXP (links, 0),
- XEXP (nextlinks, 0),
- &new_direct_jump_p)) != 0)
- goto retry;
+ /* Try combining an insn with two different insns whose results it
+ uses. */
+ for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
+ for (nextlinks = XEXP (links, 1); nextlinks;
+ nextlinks = XEXP (nextlinks, 1))
+ if ((next = try_combine (insn, XEXP (links, 0),
+ XEXP (nextlinks, 0),
+ &new_direct_jump_p)) != 0)
+ goto retry;
+
+ /* Try this insn with each REG_EQUAL note it links back to. */
+ for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
+ {
+ rtx set, note;
+ rtx temp = XEXP (links, 0);
+ if ((set = single_set (temp)) != 0
+ && (note = find_reg_equal_equiv_note (temp)) != 0
+ && GET_CODE (XEXP (note, 0)) != EXPR_LIST
+ /* Avoid using a register that may already been marked
+ dead by an earlier instruction. */
+ && ! unmentioned_reg_p (XEXP (note, 0), SET_SRC (set)))
+ {
+ /* Temporarily replace the set's source with the
+ contents of the REG_EQUAL note. The insn will
+ be deleted or recognized by try_combine. */
+ rtx orig = SET_SRC (set);
+ SET_SRC (set) = XEXP (note, 0);
+ next = try_combine (insn, temp, NULL_RTX,
+ &new_direct_jump_p);
+ if (next)
+ goto retry;
+ SET_SRC (set) = orig;
+ }
+ }
- if (GET_CODE (insn) != NOTE)
- record_dead_and_set_regs (insn);
+ if (GET_CODE (insn) != NOTE)
+ record_dead_and_set_regs (insn);
- retry:
- ;
+ retry:
+ ;
+ }
}
}
clear_bb_flags ();
- EXECUTE_IF_SET_IN_SBITMAP (refresh_blocks, 0, this_basic_block,
- BASIC_BLOCK (this_basic_block)->flags |= BB_DIRTY);
+ EXECUTE_IF_SET_IN_SBITMAP (refresh_blocks, 0, i,
+ BASIC_BLOCK (i)->flags |= BB_DIRTY);
new_direct_jump_p |= purge_all_dead_edges (0);
delete_noop_moves (f);
total_successes += combine_successes;
nonzero_sign_valid = 0;
+ gen_lowpart = gen_lowpart_general;
/* Make recognizer allow volatile MEMs again. */
init_recog ();
/* Wipe the reg_last_xxx arrays in preparation for another pass. */
static void
-init_reg_last_arrays ()
+init_reg_last_arrays (void)
{
unsigned int nregs = combine_max_regno;
- memset ((char *) reg_last_death, 0, nregs * sizeof (rtx));
- memset ((char *) reg_last_set, 0, nregs * sizeof (rtx));
- memset ((char *) reg_last_set_value, 0, nregs * sizeof (rtx));
- memset ((char *) reg_last_set_table_tick, 0, nregs * sizeof (int));
- memset ((char *) reg_last_set_label, 0, nregs * sizeof (int));
+ memset (reg_last_death, 0, nregs * sizeof (rtx));
+ memset (reg_last_set, 0, nregs * sizeof (rtx));
+ memset (reg_last_set_value, 0, nregs * sizeof (rtx));
+ memset (reg_last_set_table_tick, 0, nregs * sizeof (int));
+ memset (reg_last_set_label, 0, nregs * sizeof (int));
memset (reg_last_set_invalid, 0, nregs * sizeof (char));
- memset ((char *) reg_last_set_mode, 0, nregs * sizeof (enum machine_mode));
- memset ((char *) reg_last_set_nonzero_bits, 0, nregs * sizeof (HOST_WIDE_INT));
+ memset (reg_last_set_mode, 0, nregs * sizeof (enum machine_mode));
+ memset (reg_last_set_nonzero_bits, 0, nregs * sizeof (HOST_WIDE_INT));
memset (reg_last_set_sign_bit_copies, 0, nregs * sizeof (char));
}
\f
/* Set up any promoted values for incoming argument registers. */
static void
-setup_incoming_promotions ()
+setup_incoming_promotions (void)
{
-#ifdef PROMOTE_FUNCTION_ARGS
unsigned int regno;
rtx reg;
enum machine_mode mode;
int unsignedp;
rtx first = get_insns ();
-#ifndef OUTGOING_REGNO
-#define OUTGOING_REGNO(N) N
-#endif
- 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)));
- }
-#endif
+ if (targetm.calls.promote_function_args (TREE_TYPE (cfun->decl)))
+ {
+ 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)));
+ }
+ }
}
\f
/* Called via note_stores. If X is a pseudo that is narrower than
by any set of X. */
static void
-set_nonzero_bits_and_sign_copies (x, set, data)
- rtx x;
- rtx set;
- void *data ATTRIBUTE_UNUSED;
+set_nonzero_bits_and_sign_copies (rtx x, rtx set,
+ void *data ATTRIBUTE_UNUSED)
{
unsigned int num;
&& REGNO (x) >= FIRST_PSEUDO_REGISTER
/* If this register is undefined at the start of the file, we can't
say what its contents were. */
- && ! REGNO_REG_SET_P (BASIC_BLOCK (0)->global_live_at_start, REGNO (x))
+ && ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start, REGNO (x))
&& GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT)
{
if (set == 0 || GET_CODE (set) == CLOBBER)
<< GET_MODE_BITSIZE (GET_MODE (x))));
#endif
- reg_nonzero_bits[REGNO (x)]
- |= nonzero_bits (src, nonzero_bits_mode);
+ /* Don't call nonzero_bits if it cannot change anything. */
+ if (reg_nonzero_bits[REGNO (x)] != ~(unsigned HOST_WIDE_INT) 0)
+ reg_nonzero_bits[REGNO (x)]
+ |= nonzero_bits (src, nonzero_bits_mode);
num = num_sign_bit_copies (SET_SRC (set), GET_MODE (x));
if (reg_sign_bit_copies[REGNO (x)] == 0
|| reg_sign_bit_copies[REGNO (x)] > num)
will return 1. */
static int
-can_combine_p (insn, i3, pred, succ, pdest, psrc)
- rtx insn;
- rtx i3;
- rtx pred ATTRIBUTE_UNUSED;
- rtx succ;
- rtx *pdest, *psrc;
+can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
+ rtx *pdest, rtx *psrc)
{
int i;
rtx set = 0, src, dest;
for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
{
rtx elt = XVECEXP (PATTERN (insn), 0, i);
+ rtx note;
switch (GET_CODE (elt))
{
/* Ignore SETs whose result isn't used but not those that
have side-effects. */
if (find_reg_note (insn, REG_UNUSED, SET_DEST (elt))
+ && (!(note = find_reg_note (insn, REG_EH_REGION, NULL_RTX))
+ || INTVAL (XEXP (note, 0)) <= 0)
&& ! side_effects_p (elt))
break;
/* Don't eliminate a store in the stack pointer. */
if (dest == stack_pointer_rtx
- /* If we couldn't eliminate a field assignment, we can't combine. */
- || GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == STRICT_LOW_PART
/* 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. */
|| (rtx_equal_p (src, dest) && find_reg_note (insn, REG_EQUAL, NULL_RTX))
return 1;
}
\f
-/* Check if PAT is an insn - or a part of it - used to set up an
- argument for a function in a hard register. */
-
-static int
-sets_function_arg_p (pat)
- rtx pat;
-{
- int i;
- rtx inner_dest;
-
- switch (GET_CODE (pat))
- {
- case INSN:
- return sets_function_arg_p (PATTERN (pat));
-
- case PARALLEL:
- for (i = XVECLEN (pat, 0); --i >= 0;)
- if (sets_function_arg_p (XVECEXP (pat, 0, i)))
- return 1;
-
- break;
-
- case SET:
- inner_dest = SET_DEST (pat);
- while (GET_CODE (inner_dest) == STRICT_LOW_PART
- || GET_CODE (inner_dest) == SUBREG
- || GET_CODE (inner_dest) == ZERO_EXTRACT)
- inner_dest = XEXP (inner_dest, 0);
-
- return (GET_CODE (inner_dest) == REG
- && REGNO (inner_dest) < FIRST_PSEUDO_REGISTER
- && FUNCTION_ARG_REGNO_P (REGNO (inner_dest)));
-
- default:
- break;
- }
-
- return 0;
-}
-
/* LOC is the location within I3 that contains its pattern or the component
of a PARALLEL of the pattern. We validate that it is valid for combining.
case, we would be getting the wrong value of I2DEST into I3, so we
must reject the combination. This case occurs when I2 and I1 both
feed into I3, rather than when I1 feeds into I2, which feeds into I3.
- If I1_NOT_IN_SRC is non-zero, it means that finding I1 in the source
+ If I1_NOT_IN_SRC is nonzero, it means that finding I1 in the source
of a SET must prevent combination from occurring.
Before doing the above check, we first try to expand a field assignment
into a set of logical operations.
- If PI3_DEST_KILLED is non-zero, it is a pointer to a location in which
+ If PI3_DEST_KILLED is nonzero, it is a pointer to a location in which
we place a register that is both set and used within I3. If more than one
such register is detected, we fail.
Return 1 if the combination is valid, zero otherwise. */
static int
-combinable_i3pat (i3, loc, i2dest, i1dest, i1_not_in_src, pi3dest_killed)
- rtx i3;
- rtx *loc;
- rtx i2dest;
- rtx i1dest;
- int i1_not_in_src;
- rtx *pi3dest_killed;
+combinable_i3pat (rtx i3, rtx *loc, rtx i2dest, rtx i1dest,
+ int i1_not_in_src, rtx *pi3dest_killed)
{
rtx x = *loc;
if (GET_CODE (x) == SET)
{
- rtx set = expand_field_assignment (x);
+ rtx set = x ;
rtx dest = SET_DEST (set);
rtx src = SET_SRC (set);
rtx inner_dest = dest;
-#if 0
- rtx inner_src = src;
-#endif
-
- SUBST (*loc, set);
-
while (GET_CODE (inner_dest) == STRICT_LOW_PART
|| GET_CODE (inner_dest) == SUBREG
|| GET_CODE (inner_dest) == ZERO_EXTRACT)
inner_dest = XEXP (inner_dest, 0);
- /* We probably don't need this any more now that LIMIT_RELOAD_CLASS
- was added. */
-#if 0
- while (GET_CODE (inner_src) == STRICT_LOW_PART
- || GET_CODE (inner_src) == SUBREG
- || GET_CODE (inner_src) == ZERO_EXTRACT)
- inner_src = XEXP (inner_src, 0);
-
- /* If it is better that two different modes keep two different pseudos,
- avoid combining them. This avoids producing the following pattern
- on a 386:
- (set (subreg:SI (reg/v:QI 21) 0)
- (lshiftrt:SI (reg/v:SI 20)
- (const_int 24)))
- If that were made, reload could not handle the pair of
- reg 20/21, since it would try to get any GENERAL_REGS
- but some of them don't handle QImode. */
-
- if (rtx_equal_p (inner_src, i2dest)
- && GET_CODE (inner_dest) == REG
- && ! MODES_TIEABLE_P (GET_MODE (i2dest), GET_MODE (inner_dest)))
- return 0;
-#endif
-
- /* Check for the case where I3 modifies its output, as
- discussed above. */
- if ((inner_dest != dest
+ /* Check for the case where I3 modifies its output, as discussed
+ above. We don't want to prevent pseudos from being combined
+ into the address of a MEM, so only prevent the combination if
+ i1 or i2 set the same MEM. */
+ if ((inner_dest != dest &&
+ (GET_CODE (inner_dest) != MEM
+ || rtx_equal_p (i2dest, inner_dest)
+ || (i1dest && rtx_equal_p (i1dest, inner_dest)))
&& (reg_overlap_mentioned_p (i2dest, inner_dest)
|| (i1dest && reg_overlap_mentioned_p (i1dest, inner_dest))))
and division. We don't count multiplications by powers of two here. */
static int
-contains_muldiv (x)
- rtx x;
+contains_muldiv (rtx x)
{
switch (GET_CODE (x))
{
return ! (GET_CODE (XEXP (x, 1)) == CONST_INT
&& exact_log2 (INTVAL (XEXP (x, 1))) >= 0);
default:
- switch (GET_RTX_CLASS (GET_CODE (x)))
- {
- case 'c': case '<': case '2':
- return contains_muldiv (XEXP (x, 0))
+ if (BINARY_P (x))
+ return contains_muldiv (XEXP (x, 0))
|| contains_muldiv (XEXP (x, 1));
- case '1':
- return contains_muldiv (XEXP (x, 0));
+ if (UNARY_P (x))
+ return contains_muldiv (XEXP (x, 0));
- default:
- return 0;
- }
+ return 0;
}
}
\f
can't perform combinations. */
static int
-cant_combine_insn_p (insn)
- rtx insn;
+cant_combine_insn_p (rtx insn)
{
rtx set;
rtx src, dest;
if (! INSN_P (insn))
return 1;
- /* Never combine loads and stores involving hard regs. The register
- allocator can usually handle such reg-reg moves by tying. If we allow
- the combiner to make substitutions of hard regs, we risk aborting in
- reload on machines that have SMALL_REGISTER_CLASSES.
+ /* Never combine loads and stores involving hard regs that are likely
+ to be spilled. The register allocator can usually handle such
+ reg-reg moves by tying. If we allow the combiner to make
+ substitutions of likely-spilled regs, we may abort in reload.
As an exception, we allow combinations involving fixed regs; these are
not available to the register allocator so there's no risk involved. */
dest = SUBREG_REG (dest);
if (REG_P (src) && REG_P (dest)
&& ((REGNO (src) < FIRST_PSEUDO_REGISTER
- && ! fixed_regs[REGNO (src)])
+ && ! fixed_regs[REGNO (src)]
+ && CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (REGNO (src))))
|| (REGNO (dest) < FIRST_PSEUDO_REGISTER
- && ! fixed_regs[REGNO (dest)])))
+ && ! fixed_regs[REGNO (dest)]
+ && CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (REGNO (dest))))))
return 1;
return 0;
}
+/* Adjust INSN after we made a change to its destination.
+
+ Changing the destination can invalidate notes that say something about
+ the results of the insn and a LOG_LINK pointing to the insn. */
+
+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);
+ }
+
+ /* 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));
+}
+
/* 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.
If we did the combination, return the insn at which combine should
resume scanning.
- Set NEW_DIRECT_JUMP_P to a non-zero value if try_combine creates a
+ Set NEW_DIRECT_JUMP_P to a nonzero value if try_combine creates a
new direct jump instruction. */
static rtx
-try_combine (i3, i2, i1, new_direct_jump_p)
- rtx i3, i2, i1;
- int *new_direct_jump_p;
+try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
{
/* New patterns for I3 and I2, respectively. */
rtx newpat, newi2pat = 0;
int added_sets_1, added_sets_2;
/* Total number of SETs to put into I3. */
int total_sets;
- /* Nonzero is I2's body now appears in I3. */
+ /* Nonzero if I2's body now appears in I3. */
int i2_is_used;
/* INSN_CODEs for new I3, new I2, and user of condition code. */
int insn_code_number, i2_code_number = 0, other_code_number = 0;
abort ();
lo &= ~(UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD (1) - 1);
- lo |= (INTVAL (SET_SRC (PATTERN (i3)))
+ lo |= (INTVAL (SET_SRC (PATTERN (i3)))
& (UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD (1) - 1));
}
else if (HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)
never appear in the insn stream so giving it the same INSN_UID
as I2 will not cause a problem. */
- subst_prev_insn = i1
- = gen_rtx_INSN (VOIDmode, INSN_UID (i2), NULL_RTX, i2,
- XVECEXP (PATTERN (i2), 0, 1), -1, NULL_RTX,
- NULL_RTX);
+ 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);
SUBST (PATTERN (i2), XVECEXP (PATTERN (i2), 0, 0));
SUBST (XEXP (SET_SRC (PATTERN (i2)), 0),
if (flag_expensive_optimizations)
{
- /* Pass pc_rtx so no substitutions are done, just simplifications.
- The cases that we are interested in here do not involve the few
- cases were is_replaced is checked. */
+ /* Pass pc_rtx so no substitutions are done, just simplifications. */
if (i1)
{
subst_low_cuid = INSN_CUID (i1);
&& XEXP (SET_SRC (PATTERN (i3)), 1) == const0_rtx
&& rtx_equal_p (XEXP (SET_SRC (PATTERN (i3)), 0), i2dest))
{
-#ifdef EXTRA_CC_MODES
+#ifdef SELECT_CC_MODE
rtx *cc_use;
enum machine_mode compare_mode;
#endif
i2_is_used = 1;
-#ifdef EXTRA_CC_MODES
+#ifdef SELECT_CC_MODE
/* See if a COMPARE with the operand we substituted in should be done
with the mode that is currently being used. If not, do the same
processing we do in `subst' for a SET; namely, if the destination
insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
/* If the result isn't valid, see if it is a PARALLEL of two SETs where
- the second SET's destination is a register that is unused. In that case,
+ the second SET's destination is a register that is unused and isn't
+ marked as an instruction that might trap in an EH region. In that case,
we just need the first SET. This can occur when simplifying a divmod
insn. We *must* test for this case here because the code below that
splits two independent SETs doesn't handle this case correctly when it
- updates the register status. Also check the case where the first
- SET's destination is unused. That would not cause incorrect code, but
- does cause an unneeded insn to remain. */
+ updates the register status.
+
+ It's pointless doing this if we originally had two sets, one from
+ i3, and one from i2. Combining then splitting the parallel results
+ in the original i2 again plus an invalid insn (which we delete).
+ The net effect is only to move instructions around, which makes
+ debug info less accurate.
- if (insn_code_number < 0 && GET_CODE (newpat) == PARALLEL
+ Also check the case where the first SET's destination is unused.
+ That would not cause incorrect code, but does cause an unneeded
+ insn to remain. */
+
+ if (insn_code_number < 0
+ && !(added_sets_2 && i1 == 0)
+ && GET_CODE (newpat) == PARALLEL
&& XVECLEN (newpat, 0) == 2
&& GET_CODE (XVECEXP (newpat, 0, 0)) == SET
&& GET_CODE (XVECEXP (newpat, 0, 1)) == SET
- && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) == REG
- && find_reg_note (i3, REG_UNUSED, SET_DEST (XVECEXP (newpat, 0, 1)))
- && ! side_effects_p (SET_SRC (XVECEXP (newpat, 0, 1)))
&& asm_noperands (newpat) < 0)
{
- newpat = XVECEXP (newpat, 0, 0);
- insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
- }
+ rtx set0 = XVECEXP (newpat, 0, 0);
+ rtx set1 = XVECEXP (newpat, 0, 1);
+ rtx note;
- else if (insn_code_number < 0 && GET_CODE (newpat) == PARALLEL
- && XVECLEN (newpat, 0) == 2
- && GET_CODE (XVECEXP (newpat, 0, 0)) == SET
- && GET_CODE (XVECEXP (newpat, 0, 1)) == SET
- && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 0))) == REG
- && find_reg_note (i3, REG_UNUSED, SET_DEST (XVECEXP (newpat, 0, 0)))
- && ! side_effects_p (SET_SRC (XVECEXP (newpat, 0, 0)))
- && asm_noperands (newpat) < 0)
- {
- newpat = XVECEXP (newpat, 0, 1);
- insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+ if (((GET_CODE (SET_DEST (set1)) == REG
+ && find_reg_note (i3, REG_UNUSED, SET_DEST (set1)))
+ || (GET_CODE (SET_DEST (set1)) == SUBREG
+ && find_reg_note (i3, REG_UNUSED, SUBREG_REG (SET_DEST (set1)))))
+ && (!(note = find_reg_note (i3, REG_EH_REGION, NULL_RTX))
+ || INTVAL (XEXP (note, 0)) <= 0)
+ && ! side_effects_p (SET_SRC (set1)))
+ {
+ newpat = set0;
+ insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+ }
+
+ else if (((GET_CODE (SET_DEST (set0)) == REG
+ && find_reg_note (i3, REG_UNUSED, SET_DEST (set0)))
+ || (GET_CODE (SET_DEST (set0)) == SUBREG
+ && find_reg_note (i3, REG_UNUSED,
+ SUBREG_REG (SET_DEST (set0)))))
+ && (!(note = find_reg_note (i3, REG_EH_REGION, NULL_RTX))
+ || INTVAL (XEXP (note, 0)) <= 0)
+ && ! side_effects_p (SET_SRC (set0)))
+ {
+ newpat = set1;
+ 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);
+ }
+ }
}
/* If we were combining three insns and the result is a simple SET
}
}
- /* If we've split a jump pattern, we'll wind up with a sequence even
- with one instruction. We can handle that below, so extract it. */
- if (m_split && GET_CODE (m_split) == SEQUENCE
- && XVECLEN (m_split, 0) == 1)
- m_split = PATTERN (XVECEXP (m_split, 0, 0));
-
- if (m_split && GET_CODE (m_split) != SEQUENCE)
+ if (m_split && NEXT_INSN (m_split) == NULL_RTX)
{
+ m_split = PATTERN (m_split);
insn_code_number = recog_for_combine (&m_split, i3, &new_i3_notes);
if (insn_code_number >= 0)
newpat = m_split;
}
- else if (m_split && GET_CODE (m_split) == SEQUENCE
- && XVECLEN (m_split, 0) == 2
+ else if (m_split && NEXT_INSN (NEXT_INSN (m_split)) == NULL_RTX
&& (next_real_insn (i2) == i3
- || ! use_crosses_set_p (PATTERN (XVECEXP (m_split, 0, 0)),
- INSN_CUID (i2))))
+ || ! use_crosses_set_p (PATTERN (m_split), INSN_CUID (i2))))
{
rtx i2set, i3set;
- rtx newi3pat = PATTERN (XVECEXP (m_split, 0, 1));
- newi2pat = PATTERN (XVECEXP (m_split, 0, 0));
+ rtx newi3pat = PATTERN (NEXT_INSN (m_split));
+ newi2pat = PATTERN (m_split);
- i3set = single_set (XVECEXP (m_split, 0, 1));
- i2set = single_set (XVECEXP (m_split, 0, 0));
+ i3set = single_set (NEXT_INSN (m_split));
+ i2set = single_set (m_split);
/* In case we changed the mode of I2DEST, replace it in the
pseudo-register table here. We can't do it above in case this
/* If *SPLIT is a paradoxical SUBREG, when we split it, it should
be written as a ZERO_EXTEND. */
if (split_code == SUBREG && GET_CODE (SUBREG_REG (*split)) == MEM)
- SUBST (*split, gen_rtx_ZERO_EXTEND (split_mode,
- SUBREG_REG (*split)));
+ {
+#ifdef LOAD_EXTEND_OP
+ /* Or as a SIGN_EXTEND if LOAD_EXTEND_OP says that that's
+ what it really is. */
+ if (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (*split)))
+ == SIGN_EXTEND)
+ SUBST (*split, gen_rtx_SIGN_EXTEND (split_mode,
+ SUBREG_REG (*split)));
+ else
+#endif
+ SUBST (*split, gen_rtx_ZERO_EXTEND (split_mode,
+ SUBREG_REG (*split)));
+ }
#endif
newi2pat = gen_rtx_SET (VOIDmode, newdest, *split);
copy. This saves at least one insn, more if register allocation can
eliminate the copy.
+ We cannot do this if the destination of the first assignment is a
+ condition code register or cc0. We eliminate this case by making sure
+ the SET_DEST and SET_SRC have the same mode.
+
We cannot do this if the destination of the second assignment is
a register that we have already assumed is zero-extended. Similarly
for a SUBREG of such a register. */
&& XVECLEN (newpat, 0) == 2
&& GET_CODE (XVECEXP (newpat, 0, 0)) == SET
&& GET_CODE (SET_SRC (XVECEXP (newpat, 0, 0))) == SIGN_EXTEND
+ && (GET_MODE (SET_DEST (XVECEXP (newpat, 0, 0)))
+ == GET_MODE (SET_SRC (XVECEXP (newpat, 0, 0))))
&& GET_CODE (XVECEXP (newpat, 0, 1)) == SET
&& rtx_equal_p (SET_SRC (XVECEXP (newpat, 0, 1)),
XEXP (SET_SRC (XVECEXP (newpat, 0, 0)), 0))
ni2dest = SET_DEST (XVECEXP (newpat, 0, 0));
newpat = XVECEXP (newpat, 0, 1);
SUBST (SET_SRC (newpat),
- gen_lowpart_for_combine (GET_MODE (SET_SRC (newpat)), ni2dest));
+ gen_lowpart (GET_MODE (SET_SRC (newpat)), ni2dest));
i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
if (i2_code_number >= 0)
rtx link;
/* If we will be able to accept this, we have made a change to the
- destination of I3. This can invalidate a LOG_LINKS pointing
- to I3. No other part of combine.c makes such a transformation.
-
- The new I3 will have a destination that was previously the
- destination of I1 or I2 and which was used in i2 or I3. Call
- distribute_links to make a LOG_LINK from the next use of
- that destination. */
-
+ destination of I3. This requires us to do a few adjustments. */
PATTERN (i3) = newpat;
- distribute_links (gen_rtx_INSN_LIST (VOIDmode, i3, NULL_RTX));
+ adjust_for_new_dest (i3);
/* I3 now uses what used to be its destination and which is
now I2's destination. That means we need a LOG_LINK from
which we know will be a NOTE. */
for (insn = NEXT_INSN (i3);
- insn && (this_basic_block == n_basic_blocks - 1
- || insn != BLOCK_HEAD (this_basic_block + 1));
+ insn && (this_basic_block->next_bb == EXIT_BLOCK_PTR
+ || insn != BB_HEAD (this_basic_block->next_bb));
insn = NEXT_INSN (insn))
{
if (INSN_P (insn) && reg_referenced_p (ni2dest, PATTERN (insn)))
REG_N_DEATHS (REGNO (XEXP (note, 0)))++;
distribute_notes (new_other_notes, undobuf.other_insn,
- undobuf.other_insn, NULL_RTX, NULL_RTX, NULL_RTX);
+ undobuf.other_insn, NULL_RTX);
}
#ifdef HAVE_cc0
- /* If I2 is the setter CC0 and I3 is the user CC0 then check whether
+ /* If I2 is the CC0 setter and I3 is the CC0 user then check whether
they are adjacent to each other or not. */
{
rtx p = prev_nonnote_insn (i3);
rtx i3links, i2links, i1links = 0;
rtx midnotes = 0;
unsigned int regno;
- /* Compute which registers we expect to eliminate. newi2pat may be setting
- either i3dest or i2dest, so we must check it. Also, i1dest may be the
- same as i3dest, in which case newi2pat may be setting i1dest. */
- rtx elim_i2 = ((newi2pat && reg_set_p (i2dest, newi2pat))
- || i2dest_in_i2src || i2dest_in_i1src
- ? 0 : i2dest);
- rtx elim_i1 = (i1 == 0 || i1dest_in_i1src
- || (newi2pat && reg_set_p (i1dest, newi2pat))
- ? 0 : i1dest);
/* Get the old REG_NOTES and LOG_LINKS from all our insns and
clear them. */
&& ! find_reg_note (i2, REG_UNUSED,
SET_DEST (XVECEXP (PATTERN (i2), 0, i))))
for (temp = NEXT_INSN (i2);
- temp && (this_basic_block == n_basic_blocks - 1
- || BLOCK_HEAD (this_basic_block) != temp);
+ temp && (this_basic_block->next_bb == EXIT_BLOCK_PTR
+ || BB_HEAD (this_basic_block) != temp);
temp = NEXT_INSN (temp))
if (temp != i3 && INSN_P (temp))
for (link = LOG_LINKS (temp); link; link = XEXP (link, 1))
/* Distribute all the LOG_LINKS and REG_NOTES from I1, I2, and I3. */
if (i3notes)
- distribute_notes (i3notes, i3, i3, newi2pat ? i2 : NULL_RTX,
- elim_i2, elim_i1);
+ distribute_notes (i3notes, i3, i3, newi2pat ? i2 : NULL_RTX);
if (i2notes)
- distribute_notes (i2notes, i2, i3, newi2pat ? i2 : NULL_RTX,
- elim_i2, elim_i1);
+ distribute_notes (i2notes, i2, i3, newi2pat ? i2 : NULL_RTX);
if (i1notes)
- distribute_notes (i1notes, i1, i3, newi2pat ? i2 : NULL_RTX,
- elim_i2, elim_i1);
+ distribute_notes (i1notes, i1, i3, newi2pat ? i2 : NULL_RTX);
if (midnotes)
- distribute_notes (midnotes, NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
- elim_i2, elim_i1);
+ distribute_notes (midnotes, NULL_RTX, i3, newi2pat ? i2 : NULL_RTX);
/* 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,
if (GET_CODE (XEXP (temp, 0)) == REG)
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);
}
if (new_i3_notes)
if (GET_CODE (XEXP (temp, 0)) == REG)
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);
}
/* If I3DEST was used in I3SRC, it really died in I3. We may need to
if (newi2pat && reg_set_p (i3dest_killed, newi2pat))
distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i3dest_killed,
NULL_RTX),
- NULL_RTX, i2, NULL_RTX, elim_i2, elim_i1);
+ NULL_RTX, i2, NULL_RTX);
else
distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i3dest_killed,
NULL_RTX),
- NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
- elim_i2, elim_i1);
+ NULL_RTX, i3, newi2pat ? i2 : NULL_RTX);
}
if (i2dest_in_i2src)
if (newi2pat && reg_set_p (i2dest, newi2pat))
distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i2dest, NULL_RTX),
- NULL_RTX, i2, NULL_RTX, NULL_RTX, NULL_RTX);
+ NULL_RTX, i2, NULL_RTX);
else
distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i2dest, NULL_RTX),
- NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
- NULL_RTX, NULL_RTX);
+ NULL_RTX, i3, newi2pat ? i2 : NULL_RTX);
}
if (i1dest_in_i1src)
if (newi2pat && reg_set_p (i1dest, newi2pat))
distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i1dest, NULL_RTX),
- NULL_RTX, i2, NULL_RTX, NULL_RTX, NULL_RTX);
+ NULL_RTX, i2, NULL_RTX);
else
distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i1dest, NULL_RTX),
- NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
- NULL_RTX, NULL_RTX);
+ NULL_RTX, i3, newi2pat ? i2 : NULL_RTX);
}
distribute_links (i3links);
BARRIER following it since it may have initially been a
conditional jump. It may also be the last nonnote insn. */
- if (GET_CODE (newpat) == RETURN || any_uncondjump_p (i3))
+ if (returnjump_p (i3) || any_uncondjump_p (i3))
{
*new_direct_jump_p = 1;
+ mark_jump_label (PATTERN (i3), i3, 0);
if ((temp = next_nonnote_insn (i3)) == NULL_RTX
|| GET_CODE (temp) != BARRIER)
emit_barrier_after (i3);
}
+
+ if (undobuf.other_insn != NULL_RTX
+ && (returnjump_p (undobuf.other_insn)
+ || any_uncondjump_p (undobuf.other_insn)))
+ {
+ *new_direct_jump_p = 1;
+
+ if ((temp = next_nonnote_insn (undobuf.other_insn)) == NULL_RTX
+ || GET_CODE (temp) != BARRIER)
+ emit_barrier_after (undobuf.other_insn);
+ }
+
/* An NOOP jump does not need barrier, but it does need cleaning up
of CFG. */
if (GET_CODE (newpat) == SET
combine_successes++;
undo_commit ();
- /* Clear this here, so that subsequent get_last_value calls are not
- affected. */
- subst_prev_insn = NULL_RTX;
-
if (added_links_insn
&& (newi2pat == 0 || INSN_CUID (added_links_insn) < INSN_CUID (i2))
&& INSN_CUID (added_links_insn) < INSN_CUID (i3))
/* Undo all the modifications recorded in undobuf. */
static void
-undo_all ()
+undo_all (void)
{
struct undo *undo, *next;
}
undobuf.undos = 0;
-
- /* Clear this here, so that subsequent get_last_value calls are not
- affected. */
- subst_prev_insn = NULL_RTX;
}
/* We've committed to accepting the changes we made. Move all
of the undos to the free list. */
static void
-undo_commit ()
+undo_commit (void)
{
struct undo *undo, *next;
two insns. */
static rtx *
-find_split_point (loc, insn)
- rtx *loc;
- rtx insn;
+find_split_point (rtx *loc, rtx insn)
{
rtx x = *loc;
enum rtx_code code = GET_CODE (x);
we can make put both sources together and make a split point
in the middle. */
- if (seq && XVECLEN (seq, 0) == 2
- && GET_CODE (XVECEXP (seq, 0, 0)) == INSN
- && GET_CODE (PATTERN (XVECEXP (seq, 0, 0))) == SET
- && SET_DEST (PATTERN (XVECEXP (seq, 0, 0))) == reg
+ if (seq
+ && NEXT_INSN (seq) != NULL_RTX
+ && NEXT_INSN (NEXT_INSN (seq)) == NULL_RTX
+ && GET_CODE (seq) == INSN
+ && GET_CODE (PATTERN (seq)) == SET
+ && SET_DEST (PATTERN (seq)) == reg
&& ! reg_mentioned_p (reg,
- SET_SRC (PATTERN (XVECEXP (seq, 0, 0))))
- && GET_CODE (XVECEXP (seq, 0, 1)) == INSN
- && GET_CODE (PATTERN (XVECEXP (seq, 0, 1))) == SET
- && SET_DEST (PATTERN (XVECEXP (seq, 0, 1))) == reg
+ SET_SRC (PATTERN (seq)))
+ && GET_CODE (NEXT_INSN (seq)) == INSN
+ && GET_CODE (PATTERN (NEXT_INSN (seq))) == SET
+ && SET_DEST (PATTERN (NEXT_INSN (seq))) == reg
&& memory_address_p (GET_MODE (x),
- SET_SRC (PATTERN (XVECEXP (seq, 0, 1)))))
+ SET_SRC (PATTERN (NEXT_INSN (seq)))))
{
- rtx src1 = SET_SRC (PATTERN (XVECEXP (seq, 0, 0)));
- rtx src2 = SET_SRC (PATTERN (XVECEXP (seq, 0, 1)));
+ rtx src1 = SET_SRC (PATTERN (seq));
+ rtx src2 = SET_SRC (PATTERN (NEXT_INSN (seq)));
/* Replace the placeholder in SRC2 with SRC1. If we can
find where in SRC2 it was placed, that can become our
This will occur on machines that just support REG + CONST
and have a constant moved through some previous computation. */
- else if (GET_RTX_CLASS (GET_CODE (XEXP (XEXP (x, 0), 0))) != 'o'
+ else if (!OBJECT_P (XEXP (XEXP (x, 0), 0))
&& ! (GET_CODE (XEXP (XEXP (x, 0), 0)) == SUBREG
- && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (XEXP (x, 0), 0))))
- == 'o')))
+ && OBJECT_P (SUBREG_REG (XEXP (XEXP (x, 0), 0)))))
return &XEXP (XEXP (x, 0), 0);
}
break;
if (SET_DEST (x) == cc0_rtx
&& GET_CODE (SET_SRC (x)) != COMPARE
&& GET_CODE (SET_SRC (x)) != ZERO_EXTRACT
- && GET_RTX_CLASS (GET_CODE (SET_SRC (x))) != 'o'
+ && !OBJECT_P (SET_SRC (x))
&& ! (GET_CODE (SET_SRC (x)) == SUBREG
- && GET_RTX_CLASS (GET_CODE (SUBREG_REG (SET_SRC (x)))) == 'o'))
+ && OBJECT_P (SUBREG_REG (SET_SRC (x)))))
return &SET_SRC (x);
#endif
SUBST (SET_SRC (x),
gen_binary (IOR, mode,
gen_binary (AND, mode, dest,
- GEN_INT (~(mask << pos)
- & GET_MODE_MASK (mode))),
+ gen_int_mode (~(mask << pos),
+ mode)),
GEN_INT (src << pos)));
SUBST (SET_DEST (x), dest);
case AND:
/* If we are AND'ing with a large constant that is only a single
bit and the result is only being used in a context where we
- need to know if it is zero or non-zero, replace it with a bit
+ need to know if it is zero or nonzero, replace it with a bit
extraction. This will avoid the large constant, which might
have taken more than one insn to make. If the constant were
not a valid argument to the AND but took only one insn to make,
break;
case NE:
- /* if STORE_FLAG_VALUE is -1, this is (NE X 0) and only one bit of X
+ /* If STORE_FLAG_VALUE is -1, this is (NE X 0) and only one bit of X
is known to be on, this can be converted into a NEG of a shift. */
if (STORE_FLAG_VALUE == -1 && XEXP (SET_SRC (x), 1) == const0_rtx
&& GET_MODE (SET_SRC (x)) == GET_MODE (XEXP (SET_SRC (x), 0))
SUBST (SET_SRC (x),
gen_rtx_AND (mode,
gen_rtx_LSHIFTRT
- (mode, gen_lowpart_for_combine (mode, inner),
+ (mode, gen_lowpart (mode, inner),
GEN_INT (pos)),
GEN_INT (((HOST_WIDE_INT) 1 << len) - 1)));
gen_rtx_fmt_ee
(unsignedp ? LSHIFTRT : ASHIFTRT, mode,
gen_rtx_ASHIFT (mode,
- gen_lowpart_for_combine (mode, inner),
+ gen_lowpart (mode, inner),
GEN_INT (GET_MODE_BITSIZE (mode)
- len - pos)),
GEN_INT (GET_MODE_BITSIZE (mode) - len)));
/* See if this is a simple operation with a constant as the second
operand. It might be that this constant is out of range and hence
could be used as a split point. */
- if ((GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '2'
- || GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == 'c'
- || GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '<')
+ if (BINARY_P (SET_SRC (x))
&& CONSTANT_P (XEXP (SET_SRC (x), 1))
- && (GET_RTX_CLASS (GET_CODE (XEXP (SET_SRC (x), 0))) == 'o'
+ && (OBJECT_P (XEXP (SET_SRC (x), 0))
|| (GET_CODE (XEXP (SET_SRC (x), 0)) == SUBREG
- && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (SET_SRC (x), 0))))
- == 'o'))))
+ && OBJECT_P (SUBREG_REG (XEXP (SET_SRC (x), 0))))))
return &XEXP (SET_SRC (x), 1);
/* Finally, see if this is a simple operation with its first operand
register, so return it as a split point. We can always do this
because if the first operand were another operation, we would have
already found it as a split point. */
- if ((GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '2'
- || GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == 'c'
- || GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '<'
- || GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '1')
+ if ((BINARY_P (SET_SRC (x)) || UNARY_P (SET_SRC (x)))
&& ! register_operand (XEXP (SET_SRC (x), 0), VOIDmode))
return &XEXP (SET_SRC (x), 0);
/* Otherwise, select our actions depending on our rtx class. */
switch (GET_RTX_CLASS (code))
{
- case 'b': /* This is ZERO_EXTRACT and SIGN_EXTRACT. */
- case '3':
+ case RTX_BITFIELD_OPS: /* This is ZERO_EXTRACT and SIGN_EXTRACT. */
+ case RTX_TERNARY:
split = find_split_point (&XEXP (x, 2), insn);
if (split)
return split;
/* ... fall through ... */
- case '2':
- case 'c':
- case '<':
+ case RTX_BIN_ARITH:
+ case RTX_COMM_ARITH:
+ case RTX_COMPARE:
+ case RTX_COMM_COMPARE:
split = find_split_point (&XEXP (x, 1), insn);
if (split)
return split;
/* ... fall through ... */
- case '1':
+ case RTX_UNARY:
/* Some machines have (and (shift ...) ...) insns. If X is not
an AND, but XEXP (X, 0) is, use it as our split point. */
if (GET_CODE (x) != AND && GET_CODE (XEXP (x, 0)) == AND)
if (split)
return split;
return loc;
- }
- /* Otherwise, we don't have a split point. */
- return 0;
+ default:
+ /* Otherwise, we don't have a split point. */
+ return 0;
+ }
}
\f
/* Throughout X, replace FROM with TO, and return the result.
`n_occurrences' is incremented each time FROM is replaced.
- IN_DEST is non-zero if we are processing the SET_DEST of a SET.
+ IN_DEST is nonzero if we are processing the SET_DEST of a SET.
- UNIQUE_COPY is non-zero if each substitution must be unique. We do this
- by copying if `n_occurrences' is non-zero. */
+ UNIQUE_COPY is nonzero if each substitution must be unique. We do this
+ by copying if `n_occurrences' is nonzero. */
static rtx
-subst (x, from, to, in_dest, unique_copy)
- rtx x, from, to;
- int in_dest;
- int unique_copy;
+subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
{
enum rtx_code code = GET_CODE (x);
enum machine_mode op0_mode = VOIDmode;
/* If this is an object, we are done unless it is a MEM or LO_SUM, both
of which may contain things that can be combined. */
- if (code != MEM && code != LO_SUM && GET_RTX_CLASS (code) == 'o')
+ if (code != MEM && code != LO_SUM && OBJECT_P (x))
return x;
/* It is possible to have a subexpression appear twice in the insn.
)
return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
-#ifdef CLASS_CANNOT_CHANGE_MODE
+#ifdef CANNOT_CHANGE_MODE_CLASS
if (code == SUBREG
&& GET_CODE (to) == REG
&& REGNO (to) < FIRST_PSEUDO_REGISTER
- && (TEST_HARD_REG_BIT
- (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE],
- REGNO (to)))
- && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (to),
- GET_MODE (x)))
+ && REG_CANNOT_CHANGE_MODE_P (REGNO (to),
+ GET_MODE (to),
+ GET_MODE (x)))
return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
#endif
if (GET_CODE (new) == CLOBBER && XEXP (new, 0) == const0_rtx)
return new;
- if (GET_CODE (new) == CONST_INT && GET_CODE (x) == SUBREG)
+ if (GET_CODE (x) == SUBREG
+ && (GET_CODE (new) == CONST_INT
+ || GET_CODE (new) == CONST_DOUBLE))
{
+ enum machine_mode mode = GET_MODE (x);
+
x = simplify_subreg (GET_MODE (x), new,
GET_MODE (SUBREG_REG (x)),
SUBREG_BYTE (x));
if (! x)
- abort ();
+ x = gen_rtx_CLOBBER (mode, const0_rtx);
}
else if (GET_CODE (new) == CONST_INT
&& GET_CODE (x) == ZERO_EXTEND)
/* If X is sufficiently simple, don't bother trying to do anything
with it. */
if (code != CONST_INT && code != REG && code != CLOBBER)
- x = combine_simplify_rtx (x, op0_mode, i == 3, in_dest);
+ x = combine_simplify_rtx (x, op0_mode, in_dest);
if (GET_CODE (x) == code)
break;
outer level; call `subst' to simplify recursively. Return the new
expression.
- OP0_MODE is the original mode of XEXP (x, 0); LAST is nonzero if this
- will be the iteration even if an expression with a code different from
- X is returned; IN_DEST is nonzero if we are inside a SET_DEST. */
+ OP0_MODE is the original mode of XEXP (x, 0). IN_DEST is nonzero
+ if we are inside a SET_DEST. */
static rtx
-combine_simplify_rtx (x, op0_mode, last, in_dest)
- rtx x;
- enum machine_mode op0_mode;
- int last;
- int in_dest;
+combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
{
enum rtx_code code = GET_CODE (x);
enum machine_mode mode = GET_MODE (x);
/* If this is a commutative operation, put a constant last and a complex
expression first. We don't need to do this for comparisons here. */
- if (GET_RTX_CLASS (code) == 'c'
+ if (COMMUTATIVE_ARITH_P (x)
&& swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
{
temp = XEXP (x, 0);
Don't do anything if all operands are very simple. */
- if (((GET_RTX_CLASS (code) == '2' || GET_RTX_CLASS (code) == 'c'
- || GET_RTX_CLASS (code) == '<')
- && ((GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) != 'o'
+ if ((BINARY_P (x)
+ && ((!OBJECT_P (XEXP (x, 0))
&& ! (GET_CODE (XEXP (x, 0)) == SUBREG
- && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 0))))
- == 'o')))
- || (GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) != 'o'
+ && OBJECT_P (SUBREG_REG (XEXP (x, 0)))))
+ || (!OBJECT_P (XEXP (x, 1))
&& ! (GET_CODE (XEXP (x, 1)) == SUBREG
- && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 1))))
- == 'o')))))
- || (GET_RTX_CLASS (code) == '1'
- && ((GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) != 'o'
+ && OBJECT_P (SUBREG_REG (XEXP (x, 1)))))))
+ || (UNARY_P (x)
+ && (!OBJECT_P (XEXP (x, 0))
&& ! (GET_CODE (XEXP (x, 0)) == SUBREG
- && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 0))))
- == 'o'))))))
+ && OBJECT_P (SUBREG_REG (XEXP (x, 0)))))))
{
rtx cond, true_rtx, false_rtx;
if (cond != 0
/* If everything is a comparison, what we have is highly unlikely
to be simpler, so don't use it. */
- && ! (GET_RTX_CLASS (code) == '<'
- && (GET_RTX_CLASS (GET_CODE (true_rtx)) == '<'
- || GET_RTX_CLASS (GET_CODE (false_rtx)) == '<')))
+ && ! (COMPARISON_P (x)
+ && (COMPARISON_P (true_rtx) || COMPARISON_P (false_rtx))))
{
rtx cop1 = const0_rtx;
enum rtx_code cond_code = simplify_comparison (NE, &cond, &cop1);
- if (cond_code == NE && GET_RTX_CLASS (GET_CODE (cond)) == '<')
+ if (cond_code == NE && COMPARISON_P (cond))
return x;
/* Simplify the alternative arms; this may collapse the true and
- false arms to store-flag values. */
- true_rtx = subst (true_rtx, pc_rtx, pc_rtx, 0, 0);
- false_rtx = subst (false_rtx, pc_rtx, pc_rtx, 0, 0);
+ false arms to store-flag values. Be careful to use copy_rtx
+ here since true_rtx or false_rtx might share RTL with x as a
+ result of the if_then_else_cond call above. */
+ true_rtx = subst (copy_rtx (true_rtx), pc_rtx, pc_rtx, 0, 0);
+ false_rtx = subst (copy_rtx (false_rtx), pc_rtx, pc_rtx, 0, 0);
/* If true_rtx and false_rtx are not general_operands, an if_then_else
is unlikely to be simpler. */
if (general_operand (true_rtx, VOIDmode)
&& general_operand (false_rtx, VOIDmode))
{
+ enum rtx_code reversed;
+
/* Restarting if we generate a store-flag expression will cause
us to loop. Just drop through in this case. */
if (true_rtx == const_true_rtx && false_rtx == const0_rtx)
x = gen_binary (cond_code, mode, cond, cop1);
else if (true_rtx == const0_rtx && false_rtx == const_true_rtx
- && reverse_condition (cond_code) != UNKNOWN)
- x = gen_binary (reverse_condition (cond_code),
- mode, cond, cop1);
+ && ((reversed = reversed_comparison_code_parts
+ (cond_code, cond, cop1, NULL))
+ != UNKNOWN))
+ x = gen_binary (reversed, mode, cond, cop1);
/* Likewise, we can make the negate of a comparison operation
if the result values are - STORE_FLAG_VALUE and zero. */
mode);
else if (GET_CODE (false_rtx) == CONST_INT
&& INTVAL (false_rtx) == - STORE_FLAG_VALUE
- && true_rtx == const0_rtx)
+ && true_rtx == const0_rtx
+ && ((reversed = reversed_comparison_code_parts
+ (cond_code, cond, cop1, NULL))
+ != UNKNOWN))
x = simplify_gen_unary (NEG, mode,
- gen_binary (reverse_condition
- (cond_code),
- mode, cond, cop1),
+ gen_binary (reversed, mode,
+ cond, cop1),
mode);
else
return gen_rtx_IF_THEN_ELSE (mode,
temp = 0;
switch (GET_RTX_CLASS (code))
{
- case '1':
+ case RTX_UNARY:
+ if (op0_mode == VOIDmode)
+ op0_mode = GET_MODE (XEXP (x, 0));
temp = simplify_unary_operation (code, mode, XEXP (x, 0), op0_mode);
break;
- case '<':
+ case RTX_COMPARE:
+ case RTX_COMM_COMPARE:
{
enum machine_mode cmp_mode = GET_MODE (XEXP (x, 0));
if (cmp_mode == VOIDmode)
if (cmp_mode == VOIDmode)
cmp_mode = op0_mode;
}
- temp = simplify_relational_operation (code, cmp_mode,
+ temp = simplify_relational_operation (code, mode, cmp_mode,
XEXP (x, 0), XEXP (x, 1));
}
-#ifdef FLOAT_STORE_FLAG_VALUE
- if (temp != 0 && GET_MODE_CLASS (mode) == MODE_FLOAT)
- {
- if (temp == const0_rtx)
- temp = CONST0_RTX (mode);
- else
- temp = immed_real_const_1 (FLOAT_STORE_FLAG_VALUE (mode), mode);
- }
-#endif
break;
- case 'c':
- case '2':
+ case RTX_COMM_ARITH:
+ case RTX_BIN_ARITH:
temp = simplify_binary_operation (code, mode, XEXP (x, 0), XEXP (x, 1));
break;
- case 'b':
- case '3':
+ case RTX_BITFIELD_OPS:
+ case RTX_TERNARY:
temp = simplify_ternary_operation (code, mode, op0_mode, XEXP (x, 0),
XEXP (x, 1), XEXP (x, 2));
break;
+ default:
+ break;
}
if (temp)
/* Make sure we pass the constant operand if any as the second
one if this is a commutative operation. */
- if (CONSTANT_P (inner_op0) && GET_RTX_CLASS (code) == 'c')
+ if (CONSTANT_P (inner_op0) && COMMUTATIVE_ARITH_P (x))
{
rtx tem = inner_op0;
inner_op0 = inner_op1;
/* For commutative operations, try the other pair if that one
didn't simplify. */
- if (inner == 0 && GET_RTX_CLASS (code) == 'c')
+ if (inner == 0 && COMMUTATIVE_ARITH_P (x))
{
other = XEXP (XEXP (x, 0), 1);
inner = simplify_binary_operation (code, mode,
if (op0_mode == VOIDmode)
op0_mode = GET_MODE (SUBREG_REG (x));
- /* simplify_subreg can't use gen_lowpart_for_combine. */
+ /* See if this can be moved to simplify_subreg. */
if (CONSTANT_P (SUBREG_REG (x))
- && subreg_lowpart_offset (mode, op0_mode) == SUBREG_BYTE (x))
- return gen_lowpart_for_combine (mode, SUBREG_REG (x));
+ && subreg_lowpart_offset (mode, op0_mode) == SUBREG_BYTE (x)
+ /* Don't call gen_lowpart if the inner mode
+ is VOIDmode and we cannot simplify it, as SUBREG without
+ inner mode is invalid. */
+ && (GET_MODE (SUBREG_REG (x)) != VOIDmode
+ || gen_lowpart_common (mode, SUBREG_REG (x))))
+ return gen_lowpart (mode, SUBREG_REG (x));
if (GET_MODE_CLASS (GET_MODE (SUBREG_REG (x))) == MODE_CC)
break;
return temp;
}
+ /* Don't change the mode of the MEM if that would change the meaning
+ of the address. */
+ if (GET_CODE (SUBREG_REG (x)) == MEM
+ && (MEM_VOLATILE_P (SUBREG_REG (x))
+ || mode_dependent_address_p (XEXP (SUBREG_REG (x), 0))))
+ return gen_rtx_CLOBBER (mode, const0_rtx);
+
/* Note that we cannot do any narrowing for non-constants since
we might have been counting on using the fact that some bits were
zero. We now do this in the SET. */
break;
case NOT:
- /* (not (plus X -1)) can become (neg X). */
- if (GET_CODE (XEXP (x, 0)) == PLUS
- && XEXP (XEXP (x, 0), 1) == constm1_rtx)
- return gen_rtx_NEG (mode, XEXP (XEXP (x, 0), 0));
-
- /* Similarly, (not (neg X)) is (plus X -1). */
- if (GET_CODE (XEXP (x, 0)) == NEG)
- return gen_rtx_PLUS (mode, XEXP (XEXP (x, 0), 0), constm1_rtx);
-
- /* (not (xor X C)) for C constant is (xor X D) with D = ~C. */
- if (GET_CODE (XEXP (x, 0)) == XOR
- && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
- && (temp = simplify_unary_operation (NOT, mode,
- XEXP (XEXP (x, 0), 1),
- mode)) != 0)
- return gen_binary (XOR, mode, XEXP (XEXP (x, 0), 0), temp);
-
- /* (not (ashift 1 X)) is (rotate ~1 X). We used to do this for operands
- other than 1, but that is not valid. We could do a similar
- simplification for (not (lshiftrt C X)) where C is just the sign bit,
- but this doesn't seem common enough to bother with. */
- if (GET_CODE (XEXP (x, 0)) == ASHIFT
- && XEXP (XEXP (x, 0), 0) == const1_rtx)
- return gen_rtx_ROTATE (mode, simplify_gen_unary (NOT, mode,
- const1_rtx, mode),
- XEXP (XEXP (x, 0), 1));
-
if (GET_CODE (XEXP (x, 0)) == SUBREG
&& subreg_lowpart_p (XEXP (x, 0))
&& (GET_MODE_SIZE (GET_MODE (XEXP (x, 0)))
simplify_gen_unary (NOT, inner_mode, const1_rtx,
inner_mode),
XEXP (SUBREG_REG (XEXP (x, 0)), 1));
- return gen_lowpart_for_combine (mode, x);
+ return gen_lowpart (mode, x);
}
- /* If STORE_FLAG_VALUE is -1, (not (comparison foo bar)) can be done by
- reversing the comparison code if valid. */
- if (STORE_FLAG_VALUE == -1
- && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
- && (reversed = reversed_comparison (x, mode, XEXP (XEXP (x, 0), 0),
- XEXP (XEXP (x, 0), 1))))
- return reversed;
-
- /* (not (ashiftrt foo C)) where C is the number of bits in FOO minus 1
- is (ge foo (const_int 0)) if STORE_FLAG_VALUE is -1, so we can
- perform the above simplification. */
-
- if (STORE_FLAG_VALUE == -1
- && GET_CODE (XEXP (x, 0)) == ASHIFTRT
- && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
- && INTVAL (XEXP (XEXP (x, 0), 1)) == GET_MODE_BITSIZE (mode) - 1)
- return gen_rtx_GE (mode, XEXP (XEXP (x, 0), 0), const0_rtx);
-
/* Apply De Morgan's laws to reduce number of patterns for machines
with negating logical insns (and-not, nand, etc.). If result has
only one NOT, put it first, since that is how the patterns are
break;
case NEG:
- /* (neg (plus X 1)) can become (not X). */
- if (GET_CODE (XEXP (x, 0)) == PLUS
- && XEXP (XEXP (x, 0), 1) == const1_rtx)
- return gen_rtx_NOT (mode, XEXP (XEXP (x, 0), 0));
-
- /* Similarly, (neg (not X)) is (plus X 1). */
- if (GET_CODE (XEXP (x, 0)) == NOT)
- return plus_constant (XEXP (XEXP (x, 0), 0), 1);
-
- /* (neg (minus X Y)) can become (minus Y X). This transformation
- isn't safe for modes with signed zeros, since if X and Y are
- both +0, (minus Y X) is the same as (minus X Y). If the rounding
- mode is towards +infinity (or -infinity) then the two expressions
- will be rounded differently. */
- if (GET_CODE (XEXP (x, 0)) == MINUS
- && !HONOR_SIGNED_ZEROS (mode)
- && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
- return gen_binary (MINUS, mode, XEXP (XEXP (x, 0), 1),
- XEXP (XEXP (x, 0), 0));
-
/* (neg (xor A 1)) is (plus A -1) if A is known to be either 0 or 1. */
- if (GET_CODE (XEXP (x, 0)) == XOR && XEXP (XEXP (x, 0), 1) == const1_rtx
+ if (GET_CODE (XEXP (x, 0)) == XOR
+ && XEXP (XEXP (x, 0), 1) == const1_rtx
&& nonzero_bits (XEXP (XEXP (x, 0), 0), mode) == 1)
return gen_binary (PLUS, mode, XEXP (XEXP (x, 0), 0), constm1_rtx);
- /* NEG commutes with ASHIFT since it is multiplication. Only do this
- if we can then eliminate the NEG (e.g.,
- if the operand is a constant). */
-
- if (GET_CODE (XEXP (x, 0)) == ASHIFT)
- {
- temp = simplify_unary_operation (NEG, mode,
- XEXP (XEXP (x, 0), 0), mode);
- if (temp)
- return gen_binary (ASHIFT, mode, temp, XEXP (XEXP (x, 0), 1));
- }
-
temp = expand_compound_operation (XEXP (x, 0));
/* For C equal to the width of MODE minus 1, (neg (ashiftrt X C)) can be
if (TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))))
&& num_sign_bit_copies (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
- >= GET_MODE_BITSIZE (mode) + 1
+ >= (unsigned int) (GET_MODE_BITSIZE (mode) + 1)
&& ! (GET_CODE (XEXP (x, 0)) == LSHIFTRT
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT))
- return gen_lowpart_for_combine (mode, XEXP (x, 0));
+ return gen_lowpart (mode, XEXP (x, 0));
/* A truncate of a comparison can be replaced with a subreg if
STORE_FLAG_VALUE permits. This is like the previous test,
but it works even if the comparison is done in a mode larger
than HOST_BITS_PER_WIDE_INT. */
if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
- && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
+ && COMPARISON_P (XEXP (x, 0))
&& ((HOST_WIDE_INT) STORE_FLAG_VALUE & ~GET_MODE_MASK (mode)) == 0)
- return gen_lowpart_for_combine (mode, XEXP (x, 0));
+ return gen_lowpart (mode, XEXP (x, 0));
/* Similarly, a truncate of a register whose value is a
comparison can be replaced with a subreg if STORE_FLAG_VALUE
if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& ((HOST_WIDE_INT) STORE_FLAG_VALUE & ~GET_MODE_MASK (mode)) == 0
&& (temp = get_last_value (XEXP (x, 0)))
- && GET_RTX_CLASS (GET_CODE (temp)) == '<')
- return gen_lowpart_for_combine (mode, XEXP (x, 0));
+ && COMPARISON_P (temp))
+ return gen_lowpart (mode, XEXP (x, 0));
break;
&& GET_MODE (XEXP (XEXP (x, 0), 0)) == mode)
return XEXP (XEXP (x, 0), 0);
+ /* (float_truncate:SF (float_truncate:DF foo:XF))
+ = (float_truncate:SF foo:XF).
+ This may eliminate double rounding, so it is unsafe.
+
+ (float_truncate:SF (float_extend:XF foo:DF))
+ = (float_truncate:SF foo:DF).
+
+ (float_truncate:DF (float_extend:XF foo:SF))
+ = (float_extend:SF foo:DF). */
+ if ((GET_CODE (XEXP (x, 0)) == FLOAT_TRUNCATE
+ && flag_unsafe_math_optimizations)
+ || GET_CODE (XEXP (x, 0)) == FLOAT_EXTEND)
+ return simplify_gen_unary (GET_MODE_SIZE (GET_MODE (XEXP (XEXP (x, 0),
+ 0)))
+ > GET_MODE_SIZE (mode)
+ ? FLOAT_TRUNCATE : FLOAT_EXTEND,
+ mode,
+ XEXP (XEXP (x, 0), 0), mode);
+
+ /* (float_truncate (float x)) is (float x) */
+ if (GET_CODE (XEXP (x, 0)) == FLOAT
+ && (flag_unsafe_math_optimizations
+ || ((unsigned)significand_size (GET_MODE (XEXP (x, 0)))
+ >= (GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (x, 0), 0)))
+ - num_sign_bit_copies (XEXP (XEXP (x, 0), 0),
+ GET_MODE (XEXP (XEXP (x, 0), 0)))))))
+ return simplify_gen_unary (FLOAT, mode,
+ XEXP (XEXP (x, 0), 0),
+ GET_MODE (XEXP (XEXP (x, 0), 0)));
+
/* (float_truncate:SF (OP:DF (float_extend:DF foo:sf))) is
(OP:SF foo:SF) if OP is NEG or ABS. */
if ((GET_CODE (XEXP (x, 0)) == ABS
&& GET_CODE (SUBREG_REG (XEXP (x, 0))) == FLOAT_TRUNCATE)
return SUBREG_REG (XEXP (x, 0));
break;
+ case FLOAT_EXTEND:
+ /* (float_extend (float_extend x)) is (float_extend x)
+
+ (float_extend (float x)) is (float x) assuming that double
+ rounding can't happen.
+ */
+ if (GET_CODE (XEXP (x, 0)) == FLOAT_EXTEND
+ || (GET_CODE (XEXP (x, 0)) == FLOAT
+ && ((unsigned)significand_size (GET_MODE (XEXP (x, 0)))
+ >= (GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (x, 0), 0)))
+ - num_sign_bit_copies (XEXP (XEXP (x, 0), 0),
+ GET_MODE (XEXP (XEXP (x, 0), 0)))))))
+ return simplify_gen_unary (GET_CODE (XEXP (x, 0)), mode,
+ XEXP (XEXP (x, 0), 0),
+ GET_MODE (XEXP (XEXP (x, 0), 0)));
+ break;
#ifdef HAVE_cc0
case COMPARE:
/* Convert (compare FOO (const_int 0)) to FOO unless we aren't
#endif
case PLUS:
+ /* Canonicalize (plus (mult (neg B) C) A) to (minus A (mult B C)).
+ */
+ if (GET_CODE (XEXP (x, 0)) == MULT
+ && GET_CODE (XEXP (XEXP (x, 0), 0)) == NEG)
+ {
+ rtx in1, in2;
+
+ in1 = XEXP (XEXP (XEXP (x, 0), 0), 0);
+ in2 = XEXP (XEXP (x, 0), 1);
+ return gen_binary (MINUS, mode, XEXP (x, 1),
+ gen_binary (MULT, mode, in1, in2));
+ }
+
/* If we have (plus (plus (A const) B)), associate it so that CONST is
outermost. That's because that's the way indexed addresses are
supposed to appear. This code used to check many more cases, but
C is 1 and STORE_FLAG_VALUE is -1 or if C is -1 and STORE_FLAG_VALUE
is 1. This produces better code than the alternative immediately
below. */
- if (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
+ if (COMPARISON_P (XEXP (x, 0))
&& ((STORE_FLAG_VALUE == -1 && XEXP (x, 1) == const1_rtx)
|| (STORE_FLAG_VALUE == 1 && XEXP (x, 1) == constm1_rtx))
&& (reversed = reversed_comparison (XEXP (x, 0), mode,
"a = (b & 8) == 0;" */
if (XEXP (x, 1) == constm1_rtx
&& GET_CODE (XEXP (x, 0)) != REG
- && ! (GET_CODE (XEXP (x,0)) == SUBREG
+ && ! (GET_CODE (XEXP (x, 0)) == SUBREG
&& GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG)
&& nonzero_bits (XEXP (x, 0), mode) == 1)
return simplify_shift_const (NULL_RTX, ASHIFTRT, mode,
{
/* Try to simplify the expression further. */
rtx tor = gen_binary (IOR, mode, XEXP (x, 0), XEXP (x, 1));
- temp = combine_simplify_rtx (tor, mode, last, in_dest);
+ temp = combine_simplify_rtx (tor, mode, in_dest);
/* If we could, great. If not, do not go ahead with the IOR
replacement, since PLUS appears in many special purpose
by reversing the comparison code if valid. */
if (STORE_FLAG_VALUE == 1
&& XEXP (x, 0) == const1_rtx
- && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<'
+ && COMPARISON_P (XEXP (x, 1))
&& (reversed = reversed_comparison (XEXP (x, 1), mode,
XEXP (XEXP (x, 1), 0),
XEXP (XEXP (x, 1), 1))))
return simplify_and_const_int (NULL_RTX, mode, XEXP (x, 0),
-INTVAL (XEXP (XEXP (x, 1), 1)) - 1);
+ /* Canonicalize (minus A (mult (neg B) C)) to (plus (mult B C) A).
+ */
+ if (GET_CODE (XEXP (x, 1)) == MULT
+ && GET_CODE (XEXP (XEXP (x, 1), 0)) == NEG)
+ {
+ rtx in1, in2;
+
+ in1 = XEXP (XEXP (XEXP (x, 1), 0), 0);
+ in2 = XEXP (XEXP (x, 1), 1);
+ return gen_binary (PLUS, mode, gen_binary (MULT, mode, in1, in2),
+ XEXP (x, 0));
+ }
+
+ /* Canonicalize (minus (neg A) (mult B C)) to
+ (minus (mult (neg B) C) A). */
+ if (GET_CODE (XEXP (x, 1)) == MULT
+ && GET_CODE (XEXP (x, 0)) == NEG)
+ {
+ rtx in1, in2;
+
+ in1 = simplify_gen_unary (NEG, mode, XEXP (XEXP (x, 1), 0), mode);
+ in2 = XEXP (XEXP (x, 1), 1);
+ return gen_binary (MINUS, mode, gen_binary (MULT, mode, in1, in2),
+ XEXP (XEXP (x, 0), 0));
+ }
+
/* Canonicalize (minus A (plus B C)) to (minus (minus A B) C) for
integers. */
if (GET_CODE (XEXP (x, 1)) == PLUS && INTEGRAL_MODE_P (mode))
with it. */
if (GET_CODE (XEXP (x, 0)) == COMPARE
|| (GET_MODE_CLASS (GET_MODE (XEXP (x, 0))) != MODE_CC
-#ifdef HAVE_cc0
- && XEXP (x, 0) != cc0_rtx
-#endif
- ))
+ && ! CC0_P (XEXP (x, 0))))
{
rtx op0 = XEXP (x, 0);
rtx op1 = XEXP (x, 1);
&& op1 == const0_rtx
&& mode == GET_MODE (op0)
&& nonzero_bits (op0, mode) == 1)
- return gen_lowpart_for_combine (mode,
- expand_compound_operation (op0));
+ return gen_lowpart (mode,
+ expand_compound_operation (op0));
else if (STORE_FLAG_VALUE == 1
&& new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
{
op0 = expand_compound_operation (op0);
return simplify_gen_unary (NEG, mode,
- gen_lowpart_for_combine (mode, op0),
+ gen_lowpart (mode, op0),
mode);
}
{
op0 = expand_compound_operation (op0);
return gen_binary (XOR, mode,
- gen_lowpart_for_combine (mode, op0),
+ gen_lowpart (mode, op0),
const1_rtx);
}
== GET_MODE_BITSIZE (mode)))
{
op0 = expand_compound_operation (op0);
- return plus_constant (gen_lowpart_for_combine (mode, op0), 1);
+ return plus_constant (gen_lowpart (mode, op0), 1);
}
/* If STORE_FLAG_VALUE is -1, we have cases similar to
&& op1 == const0_rtx
&& (num_sign_bit_copies (op0, mode)
== GET_MODE_BITSIZE (mode)))
- return gen_lowpart_for_combine (mode,
- expand_compound_operation (op0));
+ return gen_lowpart (mode,
+ expand_compound_operation (op0));
else if (STORE_FLAG_VALUE == -1
&& new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
{
op0 = expand_compound_operation (op0);
return simplify_gen_unary (NEG, mode,
- gen_lowpart_for_combine (mode, op0),
+ gen_lowpart (mode, op0),
mode);
}
{
op0 = expand_compound_operation (op0);
return simplify_gen_unary (NOT, mode,
- gen_lowpart_for_combine (mode, op0),
+ gen_lowpart (mode, op0),
mode);
}
&& nonzero_bits (op0, mode) == 1)
{
op0 = expand_compound_operation (op0);
- return plus_constant (gen_lowpart_for_combine (mode, op0), -1);
+ return plus_constant (gen_lowpart (mode, op0), -1);
}
/* If STORE_FLAG_VALUE says to just test the sign bit and X has just
if (new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
- == (unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE(mode)-1))
+ == (unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))
&& op1 == const0_rtx
&& mode == GET_MODE (op0)
&& (i = exact_log2 (nonzero_bits (op0, mode))) >= 0)
case AND:
case IOR:
case XOR:
- return simplify_logical (x, last);
+ return simplify_logical (x);
case ABS:
/* (abs (neg <foo>)) -> (abs <foo>) */
SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
break;
+ case POPCOUNT:
+ case PARITY:
+ /* (pop* (zero_extend <X>)) = (pop* <X>) */
+ if (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND)
+ SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
+ break;
+
case FLOAT:
/* (float (sign_extend <X>)) = (float <X>). */
if (GET_CODE (XEXP (x, 0)) == SIGN_EXTEND)
return simplify_shift_const (x, code, mode, XEXP (x, 0),
INTVAL (XEXP (x, 1)));
-#ifdef SHIFT_COUNT_TRUNCATED
else if (SHIFT_COUNT_TRUNCATED && GET_CODE (XEXP (x, 1)) != REG)
SUBST (XEXP (x, 1),
- force_to_mode (XEXP (x, 1), GET_MODE (x),
+ force_to_mode (XEXP (x, 1), GET_MODE (XEXP (x, 1)),
((HOST_WIDE_INT) 1
<< exact_log2 (GET_MODE_BITSIZE (GET_MODE (x))))
- 1,
NULL_RTX, 0));
-#endif
-
break;
case VEC_SELECT:
/* Simplify X, an IF_THEN_ELSE expression. Return the new expression. */
static rtx
-simplify_if_then_else (x)
- rtx x;
+simplify_if_then_else (rtx x)
{
enum machine_mode mode = GET_MODE (x);
rtx cond = XEXP (x, 0);
rtx true_rtx = XEXP (x, 1);
rtx false_rtx = XEXP (x, 2);
enum rtx_code true_code = GET_CODE (cond);
- int comparison_p = GET_RTX_CLASS (true_code) == '<';
+ int comparison_p = COMPARISON_P (cond);
rtx temp;
int i;
enum rtx_code false_code;
|| (CONSTANT_P (true_rtx)
&& GET_CODE (false_rtx) != CONST_INT && false_rtx != pc_rtx)
|| true_rtx == const0_rtx
- || (GET_RTX_CLASS (GET_CODE (true_rtx)) == 'o'
- && GET_RTX_CLASS (GET_CODE (false_rtx)) != 'o')
- || (GET_CODE (true_rtx) == SUBREG
- && GET_RTX_CLASS (GET_CODE (SUBREG_REG (true_rtx))) == 'o'
- && GET_RTX_CLASS (GET_CODE (false_rtx)) != 'o')
+ || (OBJECT_P (true_rtx) && !OBJECT_P (false_rtx))
+ || (GET_CODE (true_rtx) == SUBREG && OBJECT_P (SUBREG_REG (true_rtx))
+ && !OBJECT_P (false_rtx))
|| reg_mentioned_p (true_rtx, false_rtx)
|| rtx_equal_p (false_rtx, XEXP (cond, 0))))
{
/* It is possible that the conditional has been simplified out. */
true_code = GET_CODE (cond);
- comparison_p = GET_RTX_CLASS (true_code) == '<';
+ comparison_p = COMPARISON_P (cond);
}
/* If the two arms are identical, we don't need the comparison. */
/* Convert a == b ? b : a to "a". */
if (true_code == EQ && ! side_effects_p (cond)
- && (! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations)
+ && !HONOR_NANS (mode)
&& rtx_equal_p (XEXP (cond, 0), false_rtx)
&& rtx_equal_p (XEXP (cond, 1), true_rtx))
return false_rtx;
else if (true_code == NE && ! side_effects_p (cond)
- && (! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations)
+ && !HONOR_NANS (mode)
&& rtx_equal_p (XEXP (cond, 0), true_rtx)
&& rtx_equal_p (XEXP (cond, 1), false_rtx))
return true_rtx;
neither 1 or -1, but it isn't worth checking for. */
if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
- && comparison_p && mode != VOIDmode && ! side_effects_p (x))
+ && comparison_p
+ && GET_MODE_CLASS (mode) == MODE_INT
+ && ! side_effects_p (x))
{
rtx t = make_compound_operation (true_rtx, SET);
rtx f = make_compound_operation (false_rtx, SET);
&& subreg_lowpart_p (XEXP (XEXP (t, 0), 0))
&& rtx_equal_p (SUBREG_REG (XEXP (XEXP (t, 0), 0)), f)
&& (num_sign_bit_copies (f, GET_MODE (f))
- > (GET_MODE_BITSIZE (mode)
+ > (unsigned int)
+ (GET_MODE_BITSIZE (mode)
- GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (t, 0), 0))))))
{
c1 = XEXP (XEXP (t, 0), 1); z = f; op = GET_CODE (XEXP (t, 0));
&& subreg_lowpart_p (XEXP (XEXP (t, 0), 1))
&& rtx_equal_p (SUBREG_REG (XEXP (XEXP (t, 0), 1)), f)
&& (num_sign_bit_copies (f, GET_MODE (f))
- > (GET_MODE_BITSIZE (mode)
+ > (unsigned int)
+ (GET_MODE_BITSIZE (mode)
- GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (t, 0), 1))))))
{
c1 = XEXP (XEXP (t, 0), 0); z = f; op = GET_CODE (XEXP (t, 0));
temp = gen_binary (MULT, m, temp,
gen_binary (MULT, m, c1, const_true_rtx));
temp = subst (temp, pc_rtx, pc_rtx, 0, 0);
- temp = gen_binary (op, m, gen_lowpart_for_combine (m, z), temp);
+ temp = gen_binary (op, m, gen_lowpart (m, z), temp);
if (extend_op != NIL)
temp = simplify_gen_unary (extend_op, mode, temp, m);
&& (i = exact_log2 (-INTVAL (true_rtx))) >= 0)))
return
simplify_shift_const (NULL_RTX, ASHIFT, mode,
- gen_lowpart_for_combine (mode, XEXP (cond, 0)), i);
+ gen_lowpart (mode, XEXP (cond, 0)), i);
+
+ /* (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
+ && GET_MODE (XEXP (cond, 0)) == mode
+ && (INTVAL (true_rtx) & GET_MODE_MASK (mode))
+ == nonzero_bits (XEXP (cond, 0), mode)
+ && (i = exact_log2 (INTVAL (true_rtx) & GET_MODE_MASK (mode))) >= 0)
+ return XEXP (cond, 0);
return x;
}
/* Simplify X, a SET expression. Return the new expression. */
static rtx
-simplify_set (x)
- rtx x;
+simplify_set (rtx x)
{
rtx src = SET_SRC (x);
rtx dest = SET_DEST (x);
simplify the expression for the object knowing that we only need the
low-order bits. */
- if (GET_MODE_CLASS (mode) == MODE_INT)
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
{
src = force_to_mode (src, mode, ~(HOST_WIDE_INT) 0, NULL_RTX, 0);
SUBST (SET_SRC (x), src);
/* If we are setting CC0 or if the source is a COMPARE, look for the use of
the comparison result and try to simplify it unless we already have used
undobuf.other_insn. */
- if ((GET_CODE (src) == COMPARE
-#ifdef HAVE_cc0
- || dest == cc0_rtx
-#endif
- )
+ if ((GET_MODE_CLASS (mode) == MODE_CC
+ || GET_CODE (src) == COMPARE
+ || CC0_P (dest))
&& (cc_use = find_single_use (dest, subst_insn, &other_insn)) != 0
&& (undobuf.other_insn == 0 || other_insn == undobuf.other_insn)
- && GET_RTX_CLASS (GET_CODE (*cc_use)) == '<'
+ && COMPARISON_P (*cc_use)
&& rtx_equal_p (XEXP (*cc_use, 0), dest))
{
enum rtx_code old_code = GET_CODE (*cc_use);
enum rtx_code new_code;
- rtx op0, op1;
+ rtx op0, op1, tmp;
int other_changed = 0;
enum machine_mode compare_mode = GET_MODE (dest);
+ enum machine_mode tmp_mode;
if (GET_CODE (src) == COMPARE)
op0 = XEXP (src, 0), op1 = XEXP (src, 1);
else
op0 = src, op1 = const0_rtx;
+ /* Check whether the comparison is known at compile time. */
+ if (GET_MODE (op0) != VOIDmode)
+ tmp_mode = GET_MODE (op0);
+ else if (GET_MODE (op1) != VOIDmode)
+ tmp_mode = GET_MODE (op1);
+ else
+ tmp_mode = compare_mode;
+ tmp = simplify_const_relational_operation (old_code, tmp_mode,
+ op0, op1);
+ if (tmp != NULL_RTX)
+ {
+ rtx pat = PATTERN (other_insn);
+ undobuf.other_insn = other_insn;
+ SUBST (*cc_use, tmp);
+
+ /* 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);
+ }
+
+ /* Convert X into a no-op move. */
+ SUBST (SET_DEST (x), pc_rtx);
+ SUBST (SET_SRC (x), pc_rtx);
+ return x;
+ }
+
/* Simplify our comparison, if possible. */
new_code = simplify_comparison (old_code, &op0, &op1);
-#ifdef EXTRA_CC_MODES
+#ifdef SELECT_CC_MODE
/* If this machine has CC modes other than CCmode, check to see if we
need to use a different CC mode here. */
compare_mode = SELECT_CC_MODE (new_code, op0, op1);
-#endif /* EXTRA_CC_MODES */
-#if !defined (HAVE_cc0) && defined (EXTRA_CC_MODES)
+#ifndef HAVE_cc0
/* If the mode changed, we have to change SET_DEST, the mode in the
compare, and the mode in the place SET_DEST is used. If SET_DEST is
a hard register, just build new versions with the proper mode. If it
dest = new_dest;
}
}
-#endif
+#endif /* cc0 */
+#endif /* SELECT_CC_MODE */
/* If the code changed, we have to build a new comparison in
undobuf.other_insn. */
if (new_code != old_code)
{
+ int other_changed_previously = other_changed;
unsigned HOST_WIDE_INT mask;
SUBST (*cc_use, gen_rtx_fmt_ee (new_code, GET_MODE (*cc_use),
dest, const0_rtx));
+ other_changed = 1;
/* If the only change we made was to change an EQ into an NE or
vice versa, OP0 has only one bit that might be nonzero, and OP1
if (((old_code == NE && new_code == EQ)
|| (old_code == EQ && new_code == NE))
- && ! other_changed && op1 == const0_rtx
+ && ! other_changed_previously && op1 == const0_rtx
&& GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT
&& exact_log2 (mask = nonzero_bits (op0, GET_MODE (op0))) >= 0)
{
&& ! check_asm_operands (pat)))
{
PUT_CODE (*cc_use, old_code);
- other_insn = 0;
+ other_changed = 0;
op0 = gen_binary (XOR, GET_MODE (op0), op0, GEN_INT (mask));
}
}
-
- other_changed = 1;
}
if (other_changed)
as long as M1 and M2 have the same number of words. */
if (GET_CODE (src) == SUBREG && subreg_lowpart_p (src)
- && GET_RTX_CLASS (GET_CODE (SUBREG_REG (src))) != 'o'
+ && !OBJECT_P (SUBREG_REG (src))
&& (((GET_MODE_SIZE (GET_MODE (src)) + (UNITS_PER_WORD - 1))
/ UNITS_PER_WORD)
== ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))
+ (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 CLASS_CANNOT_CHANGE_MODE
+#ifdef CANNOT_CHANGE_MODE_CLASS
&& ! (GET_CODE (dest) == REG && REGNO (dest) < FIRST_PSEUDO_REGISTER
- && (TEST_HARD_REG_BIT
- (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE],
- REGNO (dest)))
- && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (src),
- GET_MODE (SUBREG_REG (src))))
+ && REG_CANNOT_CHANGE_MODE_P (REGNO (dest),
+ GET_MODE (SUBREG_REG (src)),
+ GET_MODE (src)))
#endif
&& (GET_CODE (dest) == REG
|| (GET_CODE (dest) == SUBREG
&& GET_CODE (SUBREG_REG (dest)) == REG)))
{
SUBST (SET_DEST (x),
- gen_lowpart_for_combine (GET_MODE (SUBREG_REG (src)),
+ gen_lowpart (GET_MODE (SUBREG_REG (src)),
dest));
SUBST (SET_SRC (x), SUBREG_REG (src));
src = SET_SRC (x), dest = SET_DEST (x);
}
+#ifdef HAVE_cc0
+ /* If we have (set (cc0) (subreg ...)), we try to remove the subreg
+ in SRC. */
+ if (dest == cc0_rtx
+ && GET_CODE (src) == SUBREG
+ && subreg_lowpart_p (src)
+ && (GET_MODE_BITSIZE (GET_MODE (src))
+ < GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (src)))))
+ {
+ rtx inner = SUBREG_REG (src);
+ enum machine_mode inner_mode = GET_MODE (inner);
+
+ /* Here we make sure that we don't have a sign bit on. */
+ if (GET_MODE_BITSIZE (inner_mode) <= HOST_BITS_PER_WIDE_INT
+ && (nonzero_bits (inner, inner_mode)
+ < ((unsigned HOST_WIDE_INT) 1
+ << (GET_MODE_BITSIZE (GET_MODE (src)) - 1))))
+ {
+ SUBST (SET_SRC (x), inner);
+ src = SET_SRC (x);
+ }
+ }
+#endif
+
#ifdef LOAD_EXTEND_OP
/* If we have (set FOO (subreg:M (mem:N BAR) 0)) with M wider than N, this
would require a paradoxical subreg. Replace the subreg with a
&& GET_CODE (SUBREG_REG (src)) == MEM)
{
SUBST (SET_SRC (x),
- gen_rtx (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))),
- GET_MODE (src), SUBREG_REG (src)));
+ gen_rtx_fmt_e (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))),
+ GET_MODE (src), SUBREG_REG (src)));
src = SET_SRC (x);
}
if (GET_CODE (true_rtx) == IOR
&& rtx_equal_p (XEXP (true_rtx, 0), false_rtx))
- term1 = false_rtx, true_rtx = XEXP(true_rtx, 1), false_rtx = const0_rtx;
+ term1 = false_rtx, true_rtx = XEXP (true_rtx, 1), false_rtx = const0_rtx;
else if (GET_CODE (true_rtx) == IOR
&& rtx_equal_p (XEXP (true_rtx, 1), false_rtx))
- term1 = false_rtx, true_rtx = XEXP(true_rtx, 0), false_rtx = const0_rtx;
+ term1 = false_rtx, true_rtx = XEXP (true_rtx, 0), false_rtx = const0_rtx;
else if (GET_CODE (false_rtx) == IOR
&& rtx_equal_p (XEXP (false_rtx, 0), true_rtx))
- term1 = true_rtx, false_rtx = XEXP(false_rtx, 1), true_rtx = const0_rtx;
+ term1 = true_rtx, false_rtx = XEXP (false_rtx, 1), true_rtx = const0_rtx;
else if (GET_CODE (false_rtx) == IOR
&& rtx_equal_p (XEXP (false_rtx, 1), true_rtx))
- term1 = true_rtx, false_rtx = XEXP(false_rtx, 0), true_rtx = const0_rtx;
+ term1 = true_rtx, false_rtx = XEXP (false_rtx, 0), true_rtx = const0_rtx;
term2 = gen_binary (AND, GET_MODE (src),
XEXP (XEXP (src, 0), 0), true_rtx);
}
\f
/* Simplify, X, and AND, IOR, or XOR operation, and return the simplified
- result. LAST is nonzero if this is the last retry. */
+ result. */
static rtx
-simplify_logical (x, last)
- rtx x;
- int last;
+simplify_logical (rtx x)
{
enum machine_mode mode = GET_MODE (x);
rtx op0 = XEXP (x, 0);
/* If we have (ior (and (X C1) C2)) and the next restart would be
the last, simplify this by making C1 as small as possible
- and then exit. */
- if (last
- && GET_CODE (x) == IOR && GET_CODE (op0) == AND
+ and then exit. Only do this if C1 actually changes: for now
+ this only saves memory but, should this transformation be
+ moved to simplify-rtx.c, we'd risk unbounded recursion there. */
+ if (GET_CODE (x) == IOR && GET_CODE (op0) == AND
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
- && GET_CODE (op1) == CONST_INT)
+ && GET_CODE (op1) == CONST_INT
+ && (INTVAL (XEXP (op0, 1)) & INTVAL (op1)) != 0)
return gen_binary (IOR, mode,
gen_binary (AND, mode, XEXP (op0, 0),
GEN_INT (INTVAL (XEXP (op0, 1))
if (GET_CODE (x) != AND)
return x;
- if (GET_RTX_CLASS (GET_CODE (x)) == 'c'
- || GET_RTX_CLASS (GET_CODE (x)) == '2')
- op0 = XEXP (x, 0), op1 = XEXP (x, 1);
+ op0 = XEXP (x, 0);
+ op1 = XEXP (x, 1);
}
/* Convert (A | B) & A to A. */
comparison if STORE_FLAG_VALUE is 1. */
if (STORE_FLAG_VALUE == 1
&& op1 == const1_rtx
- && GET_RTX_CLASS (GET_CODE (op0)) == '<'
+ && COMPARISON_P (op0)
&& (reversed = reversed_comparison (op0, mode, XEXP (op0, 0),
XEXP (op0, 1))))
return reversed;
&& ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
== (unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))
&& op1 == const_true_rtx
- && GET_RTX_CLASS (GET_CODE (op0)) == '<'
+ && COMPARISON_P (op0)
&& (reversed = reversed_comparison (op0, mode, XEXP (op0, 0),
XEXP (op0, 1))))
return reversed;
It is the inverse of this function, loosely speaking. */
static rtx
-expand_compound_operation (x)
- rtx x;
+expand_compound_operation (rtx x)
{
unsigned HOST_WIDE_INT pos = 0, len;
int unsignedp = 0;
if (GET_MODE_SIZE (GET_MODE (XEXP (x, 0))) > UNITS_PER_WORD)
return x;
+ /* Reject MODEs that aren't scalar integers because turning vector
+ or complex modes into shifts causes problems. */
+
+ if (! SCALAR_INT_MODE_P (GET_MODE (XEXP (x, 0))))
+ return x;
+
len = GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)));
/* If the inner object has VOIDmode (the only way this can happen
- is if it is a ASM_OPERANDS), we can't do anything since we don't
+ is if it is an ASM_OPERANDS), we can't do anything since we don't
know how much masking to do. */
if (len == 0)
return x;
|| GET_MODE (XEXP (x, 0)) == VOIDmode)
return x;
+ /* Reject MODEs that aren't scalar integers because turning vector
+ or complex modes into shifts causes problems. */
+
+ if (! SCALAR_INT_MODE_P (GET_MODE (XEXP (x, 0))))
+ return x;
+
len = INTVAL (XEXP (x, 1));
pos = INTVAL (XEXP (x, 2));
== 0)))
{
rtx temp = gen_rtx_ZERO_EXTEND (GET_MODE (x), XEXP (x, 0));
- return expand_compound_operation (temp);
+ rtx temp2 = expand_compound_operation (temp);
+
+ /* Make sure this is a profitable operation. */
+ if (rtx_cost (x, SET) > rtx_cost (temp2, SET))
+ return temp2;
+ else if (rtx_cost (x, SET) > rtx_cost (temp, SET))
+ return temp;
+ else
+ return x;
}
/* We can optimize some special cases of ZERO_EXTEND. */
than HOST_WIDE_INT. */
if (GET_CODE (XEXP (x, 0)) == TRUNCATE
&& GET_MODE (XEXP (XEXP (x, 0), 0)) == GET_MODE (x)
- && GET_RTX_CLASS (GET_CODE (XEXP (XEXP (x, 0), 0))) == '<'
+ && COMPARISON_P (XEXP (XEXP (x, 0), 0))
&& (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
<= HOST_BITS_PER_WIDE_INT)
&& ((HOST_WIDE_INT) STORE_FLAG_VALUE
if (GET_CODE (XEXP (x, 0)) == SUBREG
&& GET_MODE (SUBREG_REG (XEXP (x, 0))) == GET_MODE (x)
&& subreg_lowpart_p (XEXP (x, 0))
- && GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 0)))) == '<'
+ && COMPARISON_P (SUBREG_REG (XEXP (x, 0)))
&& (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
<= HOST_BITS_PER_WIDE_INT)
&& ((HOST_WIDE_INT) STORE_FLAG_VALUE
support variable lengths. */
static rtx
-expand_field_assignment (x)
- rtx x;
+expand_field_assignment (rtx x)
{
rtx inner;
rtx pos; /* Always counts from low bit. */
+ (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)))
{
x = gen_rtx_SET (VOIDmode, SUBREG_REG (SET_DEST (x)),
- gen_lowpart_for_combine
+ gen_lowpart
(GET_MODE (SUBREG_REG (SET_DEST (x))),
SET_SRC (x)));
continue;
compute_mode = GET_MODE (inner);
- /* Don't attempt bitwise arithmetic on non-integral modes. */
- if (! INTEGRAL_MODE_P (compute_mode))
+ /* Don't attempt bitwise arithmetic on non scalar integer modes. */
+ if (! SCALAR_INT_MODE_P (compute_mode))
{
enum machine_mode imode;
- /* Something is probably seriously wrong if this matches. */
+ /* Don't do anything for vector or complex integral types. */
if (! FLOAT_MODE_P (compute_mode))
break;
break;
compute_mode = imode;
- inner = gen_lowpart_for_combine (imode, inner);
+ inner = gen_lowpart (imode, inner);
}
/* Compute a mask of LEN bits, if we can do this on the host machine. */
inner),
gen_binary (ASHIFT, compute_mode,
gen_binary (AND, compute_mode,
- gen_lowpart_for_combine
+ gen_lowpart
(compute_mode, SET_SRC (x)),
mask),
pos)));
code that understands the USE is this routine. If it is not removed,
it will cause the resulting insn not to match.
- UNSIGNEDP is non-zero for an unsigned reference and zero for a
+ UNSIGNEDP is nonzero for an unsigned reference and zero for a
signed reference.
- IN_DEST is non-zero if this is a reference in the destination of a
- SET. This is used when a ZERO_ or SIGN_EXTRACT isn't needed. If non-zero,
+ IN_DEST is nonzero if this is a reference in the destination of a
+ SET. This is used when a ZERO_ or SIGN_EXTRACT isn't needed. If nonzero,
a STRICT_LOW_PART will be used, if zero, ZERO_EXTEND or SIGN_EXTEND will
be used.
- IN_COMPARE is non-zero if we are in a COMPARE. This means that a
+ IN_COMPARE is nonzero if we are in a COMPARE. This means that a
ZERO_EXTRACT should be built even for bits starting at bit 0.
MODE is the desired mode of the result (if IN_DEST == 0).
can't handle it. */
static rtx
-make_extraction (mode, inner, pos, pos_rtx, len,
- unsignedp, in_dest, in_compare)
- enum machine_mode mode;
- rtx inner;
- HOST_WIDE_INT pos;
- rtx pos_rtx;
- unsigned HOST_WIDE_INT len;
- int unsignedp;
- int in_dest, in_compare;
+make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
+ rtx pos_rtx, unsigned HOST_WIDE_INT len, int unsignedp,
+ int in_dest, int in_compare)
{
/* This mode describes the size of the storage area
to fetch the overall value from. Within that, we
is_mode = GET_MODE (SUBREG_REG (inner));
inner = SUBREG_REG (inner);
}
+ else if (GET_CODE (inner) == ASHIFT
+ && GET_CODE (XEXP (inner, 1)) == CONST_INT
+ && pos_rtx == 0 && pos == 0
+ && len > (unsigned HOST_WIDE_INT) INTVAL (XEXP (inner, 1)))
+ {
+ /* We're extracting the least significant bits of an rtx
+ (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),
+ 0, 0, len - INTVAL (XEXP (inner, 1)),
+ unsignedp, in_dest, in_compare);
+ if (new != 0)
+ return gen_rtx_ASHIFT (mode, new, XEXP (inner, 1));
+ }
inner_mode = GET_MODE (inner);
}
else if (GET_CODE (inner) == REG)
{
- /* We can't call gen_lowpart_for_combine here since we always want
- a SUBREG and it would sometimes return a new hard register. */
if (tmode != inner_mode)
{
- HOST_WIDE_INT final_word = pos / BITS_PER_WORD;
-
- if (WORDS_BIG_ENDIAN
- && GET_MODE_SIZE (inner_mode) > UNITS_PER_WORD)
- final_word = ((GET_MODE_SIZE (inner_mode)
- - GET_MODE_SIZE (tmode))
- / UNITS_PER_WORD) - final_word;
-
- final_word *= UNITS_PER_WORD;
- if (BYTES_BIG_ENDIAN &&
- GET_MODE_SIZE (inner_mode) > GET_MODE_SIZE (tmode))
- final_word += (GET_MODE_SIZE (inner_mode)
- - GET_MODE_SIZE (tmode)) % UNITS_PER_WORD;
-
- new = gen_rtx_SUBREG (tmode, inner, final_word);
+ /* We can't call gen_lowpart in a DEST since we
+ always want a SUBREG (see below) and it would sometimes
+ return a new hard register. */
+ if (pos || in_dest)
+ {
+ HOST_WIDE_INT final_word = pos / BITS_PER_WORD;
+
+ if (WORDS_BIG_ENDIAN
+ && GET_MODE_SIZE (inner_mode) > UNITS_PER_WORD)
+ final_word = ((GET_MODE_SIZE (inner_mode)
+ - GET_MODE_SIZE (tmode))
+ / UNITS_PER_WORD) - final_word;
+
+ final_word *= UNITS_PER_WORD;
+ if (BYTES_BIG_ENDIAN &&
+ GET_MODE_SIZE (inner_mode) > GET_MODE_SIZE (tmode))
+ final_word += (GET_MODE_SIZE (inner_mode)
+ - GET_MODE_SIZE (tmode)) % UNITS_PER_WORD;
+
+ /* Avoid creating invalid subregs, for example when
+ simplifying (x>>32)&255. */
+ if (final_word >= GET_MODE_SIZE (inner_mode))
+ return NULL_RTX;
+
+ new = gen_rtx_SUBREG (tmode, inner, final_word);
+ }
+ else
+ new = gen_lowpart (tmode, inner);
}
else
new = inner;
return new;
if (GET_CODE (new) == CONST_INT)
- return trunc_int_for_mode (INTVAL (new), mode);
+ return gen_int_mode (INTVAL (new), 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
}
else if (pos_rtx != 0
&& GET_MODE_SIZE (pos_mode) < GET_MODE_SIZE (GET_MODE (pos_rtx)))
- pos_rtx = gen_lowpart_for_combine (pos_mode, pos_rtx);
+ pos_rtx = gen_lowpart (pos_mode, pos_rtx);
/* Make POS_RTX unless we already have it and it is correct. If we don't
have a POS_RTX but we do have an ORIG_POS_RTX, the latter must
new = gen_rtx_fmt_eee (unsignedp ? ZERO_EXTRACT : SIGN_EXTRACT,
extraction_mode, inner, GEN_INT (len), pos_rtx);
if (! in_dest)
- new = gen_lowpart_for_combine (mode, new);
+ new = gen_lowpart (mode, new);
return new;
}
with any other operations in X. Return X without that shift if so. */
static rtx
-extract_left_shift (x, count)
- rtx x;
- int count;
+extract_left_shift (rtx x, int count)
{
enum rtx_code code = GET_CODE (x);
enum machine_mode mode = GET_MODE (x);
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 (GET_CODE (XEXP (x, 1)) == CONST_INT
&& (INTVAL (XEXP (x, 1)) & ((((HOST_WIDE_INT) 1 << count)) - 1)) == 0
&& (tem = extract_left_shift (XEXP (x, 0), count)) != 0)
return gen_binary (code, mode, tem,
or a COMPARE against zero, it is COMPARE. */
static rtx
-make_compound_operation (x, in_code)
- rtx x;
- enum rtx_code in_code;
+make_compound_operation (rtx x, enum rtx_code in_code)
{
enum rtx_code code = GET_CODE (x);
enum machine_mode mode = GET_MODE (x);
but once inside, go back to our default of SET. */
next_code = (code == MEM || code == PLUS || code == MINUS ? MEM
- : ((code == COMPARE || GET_RTX_CLASS (code) == '<')
+ : ((code == COMPARE || COMPARISON_P (x))
&& XEXP (x, 1) == const0_rtx) ? COMPARE
: in_code == COMPARE ? SET : in_code);
/* Process depending on the code of this operation. If NEW is set
- non-zero, it will be returned. */
+ nonzero, it will be returned. */
switch (code)
{
also do this for some cases of SIGN_EXTRACT, but it doesn't
seem worth the effort; the case checked for occurs on Alpha. */
- if (GET_RTX_CLASS (GET_CODE (lhs)) != 'o'
+ if (!OBJECT_P (lhs)
&& ! (GET_CODE (lhs) == SUBREG
- && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (lhs))) == 'o'))
+ && (OBJECT_P (SUBREG_REG (lhs))))
&& GET_CODE (rhs) == CONST_INT
&& INTVAL (rhs) < HOST_BITS_PER_WIDE_INT
&& (new = extract_left_shift (lhs, INTVAL (rhs))) != 0)
if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (tem))
|| (GET_MODE_SIZE (mode) >
GET_MODE_SIZE (GET_MODE (XEXP (tem, 0)))))
- tem = gen_rtx_fmt_e (GET_CODE (tem), mode, XEXP (tem, 0));
+ {
+ if (! SCALAR_INT_MODE_P (mode))
+ break;
+ tem = gen_rtx_fmt_e (GET_CODE (tem), mode, XEXP (tem, 0));
+ }
else
- tem = gen_lowpart_for_combine (mode, XEXP (tem, 0));
+ tem = gen_lowpart (mode, XEXP (tem, 0));
return tem;
}
break;
if (new)
{
- x = gen_lowpart_for_combine (mode, new);
+ x = gen_lowpart (mode, new);
code = GET_CODE (x);
}
*PLEN is set to the length of the field. */
static int
-get_pos_from_mask (m, plen)
- unsigned HOST_WIDE_INT m;
- unsigned HOST_WIDE_INT *plen;
+get_pos_from_mask (unsigned HOST_WIDE_INT m, unsigned HOST_WIDE_INT *plen)
{
/* Get the bit number of the first 1 bit from the right, -1 if none. */
int pos = exact_log2 (m & -m);
Return a possibly simplified expression, but always convert X to
MODE. If X is a CONST_INT, AND the CONST_INT with MASK.
- Also, if REG is non-zero and X is a register equal in value to REG,
+ Also, if REG is nonzero and X is a register equal in value to REG,
replace X with REG.
If JUST_SELECT is nonzero, don't optimize by noticing that bits in MASK
NOT, NEG, or XOR. */
static rtx
-force_to_mode (x, mode, mask, reg, just_select)
- rtx x;
- enum machine_mode mode;
- unsigned HOST_WIDE_INT mask;
- rtx reg;
- int just_select;
+force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
+ rtx reg, int just_select)
{
enum rtx_code code = GET_CODE (x);
int next_select = just_select || code == XOR || code == NOT || code == NEG;
expression is VOIDmode.
Also do nothing if X is a CLOBBER; this can happen if X was
- the return value from a call to gen_lowpart_for_combine. */
+ the return value from a call to gen_lowpart. */
if (code == CALL || code == ASM_OPERANDS || code == CLOBBER)
return x;
mask &= GET_MODE_MASK (op_mode);
/* When we have an arithmetic operation, or a shift whose count we
- do not know, we need to assume that all bit the up to the highest-order
+ do not know, we need to assume that all bits up to the highest-order
bit in MASK will be needed. This is how we form such a mask. */
- if (op_mode)
- fuller_mask = (GET_MODE_BITSIZE (op_mode) >= HOST_BITS_PER_WIDE_INT
- ? GET_MODE_MASK (op_mode)
- : (((unsigned HOST_WIDE_INT) 1 << (floor_log2 (mask) + 1))
- - 1));
+ if (mask & ((unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)))
+ fuller_mask = ~(unsigned HOST_WIDE_INT) 0;
else
- fuller_mask = ~(HOST_WIDE_INT) 0;
+ fuller_mask = (((unsigned HOST_WIDE_INT) 1 << (floor_log2 (mask) + 1))
+ - 1);
/* Determine what bits of X are guaranteed to be (non)zero. */
nonzero = nonzero_bits (x, mode);
/* If none of the bits in X are needed, return a zero. */
if (! just_select && (nonzero & mask) == 0)
- return const0_rtx;
+ 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)
{
- HOST_WIDE_INT cval = INTVAL (x) & mask;
- int width = GET_MODE_BITSIZE (mode);
-
- /* If MODE is narrower that HOST_WIDE_INT and CVAL is a negative
- number, sign extend it. */
- if (width > 0 && width < HOST_BITS_PER_WIDE_INT
- && (cval & ((HOST_WIDE_INT) 1 << (width - 1))) != 0)
- cval |= (HOST_WIDE_INT) -1 << width;
-
- return GEN_INT (cval);
+ if (SCALAR_INT_MODE_P (mode))
+ return gen_int_mode (INTVAL (x) & mask, mode);
+ else
+ {
+ x = GEN_INT (INTVAL (x) & mask);
+ return gen_lowpart_common (mode, x);
+ }
}
/* If X is narrower than MODE and we want all the bits in X's mode, just
get X in the proper mode. */
if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode)
&& (GET_MODE_MASK (GET_MODE (x)) & ~mask) == 0)
- return gen_lowpart_for_combine (mode, x);
+ return gen_lowpart (mode, x);
/* If we aren't changing the mode, X is not a SUBREG, and all zero bits in
MASK are already known to be zero in X, we need not do anything. */
if (GET_CODE (x) == AND && GET_CODE (XEXP (x, 1)) == CONST_INT
&& ((INTVAL (XEXP (x, 1)) & GET_MODE_MASK (GET_MODE (x)))
- == (HOST_WIDE_INT) mask))
+ == mask))
x = XEXP (x, 0);
/* If it remains an AND, try making another AND with the bits
int width = GET_MODE_BITSIZE (GET_MODE (x));
rtx y;
- /* If MODE is narrower that HOST_WIDE_INT and CVAL is a negative
+ /* If MODE is narrower than HOST_WIDE_INT and CVAL is a negative
number, sign extend it. */
if (width > 0 && width < HOST_BITS_PER_WIDE_INT
&& (cval & ((HOST_WIDE_INT) 1 << (width - 1))) != 0)
return force_to_mode (x, mode, mask, reg, next_select);
}
- /* Similarly, if C contains every bit in the mask, then we may
+ /* 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
- && ((INTVAL (XEXP (x, 0)) | (HOST_WIDE_INT) mask)
+ && ((INTVAL (XEXP (x, 0)) | (HOST_WIDE_INT) fuller_mask)
== INTVAL (XEXP (x, 0))))
{
x = simplify_gen_unary (NOT, 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_for_combine (op_mode,
- force_to_mode (XEXP (x, 0), mode, mask,
- reg, next_select));
- op1 = gen_lowpart_for_combine (op_mode,
- force_to_mode (XEXP (x, 1), mode, mask,
- reg, next_select));
-
- /* If OP1 is a CONST_INT and X is an IOR or XOR, clear bits outside
- MASK since OP1 might have been sign-extended but we never want
- to turn on extra bits, since combine might have previously relied
- on them being off. */
- if (GET_CODE (op1) == CONST_INT && (code == IOR || code == XOR)
- && (INTVAL (op1) & mask) != 0)
- op1 = GEN_INT (INTVAL (op1) & mask);
+ op0 = gen_lowpart (op_mode,
+ force_to_mode (XEXP (x, 0), mode, mask,
+ reg, next_select));
+ op1 = gen_lowpart (op_mode,
+ force_to_mode (XEXP (x, 1), mode, mask,
+ reg, next_select));
if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
x = gen_binary (code, op_mode, op0, op1);
else
mask = fuller_mask;
- op0 = gen_lowpart_for_combine (op_mode,
- force_to_mode (XEXP (x, 0), op_mode,
- mask, reg, next_select));
+ op0 = gen_lowpart (op_mode,
+ force_to_mode (XEXP (x, 0), op_mode,
+ mask, reg, next_select));
if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0))
x = gen_binary (code, op_mode, op0, XEXP (x, 1));
}
}
- /* If MASK is 1, convert this to a LSHIFTRT. This can be done
+ /* If MASK is 1, convert this to an LSHIFTRT. This can be done
even if the shift count isn't a constant. */
if (mask == 1)
x = gen_binary (LSHIFTRT, GET_MODE (x), XEXP (x, 0), XEXP (x, 1));
&& (INTVAL (XEXP (x, 1))
<= GET_MODE_BITSIZE (GET_MODE (x)) - (floor_log2 (mask) + 1))
&& GET_CODE (XEXP (x, 0)) == ASHIFT
- && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
- && INTVAL (XEXP (XEXP (x, 0), 1)) == INTVAL (XEXP (x, 1)))
+ && XEXP (XEXP (x, 0), 1) == XEXP (x, 1))
return force_to_mode (XEXP (XEXP (x, 0), 0), mode, mask,
reg, next_select);
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 && GET_CODE (temp) == CONST_INT)
SUBST (XEXP (x, 0),
force_to_mode (XEXP (x, 0), GET_MODE (x),
INTVAL (temp), reg, next_select));
< GET_MODE_BITSIZE (GET_MODE (x)))
&& INTVAL (XEXP (XEXP (x, 0), 1)) < HOST_BITS_PER_WIDE_INT)
{
- temp = GEN_INT (mask << INTVAL (XEXP (XEXP (x, 0), 1)));
+ temp = gen_int_mode (mask << INTVAL (XEXP (XEXP (x, 0), 1)),
+ GET_MODE (x));
temp = gen_binary (XOR, GET_MODE (x), XEXP (XEXP (x, 0), 0), temp);
x = gen_binary (LSHIFTRT, GET_MODE (x), temp, XEXP (XEXP (x, 0), 1));
mask = fuller_mask;
unop:
- op0 = gen_lowpart_for_combine (op_mode,
- force_to_mode (XEXP (x, 0), mode, mask,
- reg, next_select));
+ op0 = gen_lowpart (op_mode,
+ force_to_mode (XEXP (x, 0), mode, mask,
+ reg, next_select));
if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0))
x = simplify_gen_unary (code, op_mode, op0, op_mode);
break;
which is equal to STORE_FLAG_VALUE. */
if ((mask & ~STORE_FLAG_VALUE) == 0 && XEXP (x, 1) == const0_rtx
&& exact_log2 (nonzero_bits (XEXP (x, 0), mode)) >= 0
- && nonzero_bits (XEXP (x, 0), mode) == STORE_FLAG_VALUE)
+ && (nonzero_bits (XEXP (x, 0), mode)
+ == (unsigned HOST_WIDE_INT) STORE_FLAG_VALUE))
return force_to_mode (XEXP (x, 0), mode, mask, reg, next_select);
break;
written in a narrower mode. We play it safe and do not do so. */
SUBST (XEXP (x, 1),
- gen_lowpart_for_combine (GET_MODE (x),
+ gen_lowpart (GET_MODE (x),
force_to_mode (XEXP (x, 1), mode,
mask, reg, next_select)));
SUBST (XEXP (x, 2),
- gen_lowpart_for_combine (GET_MODE (x),
+ gen_lowpart (GET_MODE (x),
force_to_mode (XEXP (x, 2), mode,
- mask, reg,next_select)));
+ mask, reg, next_select)));
break;
default:
}
/* Ensure we return a value of the proper mode. */
- return gen_lowpart_for_combine (mode, x);
+ return gen_lowpart (mode, x);
}
\f
/* Return nonzero if X is an expression that has one of two values depending on
If we return zero, we set *PTRUE and *PFALSE to X. */
static rtx
-if_then_else_cond (x, ptrue, pfalse)
- rtx x;
- rtx *ptrue, *pfalse;
+if_then_else_cond (rtx x, rtx *ptrue, rtx *pfalse)
{
enum machine_mode mode = GET_MODE (x);
enum rtx_code code = GET_CODE (x);
/* If we are comparing a value against zero, we are done. */
if ((code == NE || code == EQ)
- && GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) == 0)
+ && XEXP (x, 1) == const0_rtx)
{
*ptrue = (code == NE) ? const_true_rtx : const0_rtx;
*pfalse = (code == NE) ? const0_rtx : const_true_rtx;
/* If this is a unary operation whose operand has one of two values, apply
our opcode to compute those values. */
- else if (GET_RTX_CLASS (code) == '1'
+ else if (UNARY_P (x)
&& (cond0 = if_then_else_cond (XEXP (x, 0), &true0, &false0)) != 0)
{
*ptrue = simplify_gen_unary (code, mode, true0, GET_MODE (XEXP (x, 0)));
/* If this is a binary operation, see if either side has only one of two
values. If either one does or if both do and they are conditional on
the same value, compute the new true and false values. */
- else if (GET_RTX_CLASS (code) == 'c' || GET_RTX_CLASS (code) == '2'
- || GET_RTX_CLASS (code) == '<')
+ else if (BINARY_P (x))
{
cond0 = if_then_else_cond (XEXP (x, 0), &true0, &false0);
cond1 = if_then_else_cond (XEXP (x, 1), &true1, &false1);
}
/* See if we have PLUS, IOR, XOR, MINUS or UMAX, where one of the
- operands is zero when the other is non-zero, and vice-versa,
+ operands is zero when the other is nonzero, and vice-versa,
and STORE_FLAG_VALUE is 1 or -1. */
if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
cond0 = XEXP (XEXP (x, 0), 0);
cond1 = XEXP (XEXP (x, 1), 0);
- if (GET_RTX_CLASS (GET_CODE (cond0)) == '<'
- && GET_RTX_CLASS (GET_CODE (cond1)) == '<'
+ if (COMPARISON_P (cond0)
+ && COMPARISON_P (cond1)
&& ((GET_CODE (cond0) == combine_reversed_comparison_code (cond1)
&& rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 0))
&& rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 1)))
cond0 = XEXP (XEXP (x, 0), 0);
cond1 = XEXP (XEXP (x, 1), 0);
- if (GET_RTX_CLASS (GET_CODE (cond0)) == '<'
- && GET_RTX_CLASS (GET_CODE (cond1)) == '<'
+ if (COMPARISON_P (cond0)
+ && COMPARISON_P (cond1)
&& ((GET_CODE (cond0) == combine_reversed_comparison_code (cond1)
&& rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 0))
&& rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 1)))
&& 0 != (cond0 = if_then_else_cond (SUBREG_REG (x),
&true0, &false0)))
{
- *ptrue = simplify_gen_subreg (mode, true0,
+ true0 = simplify_gen_subreg (mode, true0,
+ GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
+ false0 = simplify_gen_subreg (mode, false0,
GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
- *pfalse = simplify_gen_subreg (mode, false0,
- GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
-
- return cond0;
+ if (true0 && false0)
+ {
+ *ptrue = true0;
+ *pfalse = false0;
+ return cond0;
+ }
}
/* If X is a constant, this isn't special and will cause confusions
}
/* Likewise for 0 or a single bit. */
- else if (mode != VOIDmode
+ else if (SCALAR_INT_MODE_P (mode)
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& exact_log2 (nz = nonzero_bits (x, mode)) >= 0)
{
- *ptrue = GEN_INT (nz), *pfalse = const0_rtx;
+ *ptrue = gen_int_mode (nz, mode), *pfalse = const0_rtx;
return x;
}
arise with IF_THEN_ELSE expressions. */
static rtx
-known_cond (x, cond, reg, val)
- rtx x;
- enum rtx_code cond;
- rtx reg, val;
+known_cond (rtx x, enum rtx_code cond, rtx reg, rtx val)
{
enum rtx_code code = GET_CODE (x);
rtx temp;
/* The only other cases we handle are MIN, MAX, and comparisons if the
operands are the same as REG and VAL. */
- else if (GET_RTX_CLASS (code) == '<' || GET_RTX_CLASS (code) == 'c')
+ else if (COMPARISON_P (x) || COMMUTATIVE_ARITH_P (x))
{
if (rtx_equal_p (XEXP (x, 0), val))
cond = swap_condition (cond), temp = val, val = reg, reg = temp;
if (rtx_equal_p (XEXP (x, 0), reg) && rtx_equal_p (XEXP (x, 1), val))
{
- if (GET_RTX_CLASS (code) == '<')
+ if (COMPARISON_P (x))
{
if (comparison_dominates_p (cond, code))
return const_true_rtx;
assignment as a field assignment. */
static int
-rtx_equal_for_field_assignment_p (x, y)
- rtx x;
- rtx y;
+rtx_equal_for_field_assignment_p (rtx x, rtx y)
{
if (x == y || rtx_equal_p (x, y))
return 1;
if (GET_CODE (x) == MEM && GET_CODE (y) == SUBREG
&& GET_CODE (SUBREG_REG (y)) == MEM
&& rtx_equal_p (SUBREG_REG (y),
- gen_lowpart_for_combine (GET_MODE (SUBREG_REG (y)), x)))
+ gen_lowpart (GET_MODE (SUBREG_REG (y)), x)))
return 1;
if (GET_CODE (y) == MEM && GET_CODE (x) == SUBREG
&& GET_CODE (SUBREG_REG (x)) == MEM
&& rtx_equal_p (SUBREG_REG (x),
- gen_lowpart_for_combine (GET_MODE (SUBREG_REG (x)), y)))
+ gen_lowpart (GET_MODE (SUBREG_REG (x)), y)))
return 1;
/* We used to see if get_last_value of X and Y were the same but that's
We only handle the most common cases. */
static rtx
-make_field_assignment (x)
- rtx x;
+make_field_assignment (rtx x)
{
rtx dest = SET_DEST (x);
rtx src = SET_SRC (x);
&& (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
&& INTVAL (XEXP (SUBREG_REG (XEXP (src, 0)), 0)) == -2
&& rtx_equal_for_field_assignment_p (dest, XEXP (src, 1)))
{
: ((unsigned HOST_WIDE_INT) 1 << len) - 1,
dest, 0);
+ /* 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
+ && INTVAL (XEXP (assign, 1)) < HOST_BITS_PER_WIDE_INT
+ && GET_CODE (src) == AND
+ && GET_CODE (XEXP (src, 1)) == CONST_INT
+ && ((unsigned HOST_WIDE_INT) INTVAL (XEXP (src, 1))
+ == ((unsigned HOST_WIDE_INT) 1 << INTVAL (XEXP (assign, 1))) - 1))
+ src = XEXP (src, 0);
+
return gen_rtx_SET (VOIDmode, assign, src);
}
\f
if so. */
static rtx
-apply_distributive_law (x)
- rtx x;
+apply_distributive_law (rtx x)
{
enum rtx_code code = GET_CODE (x);
+ enum rtx_code inner_code;
rtx lhs, rhs, other;
rtx tem;
- enum rtx_code inner_code;
- /* Distributivity is not true for floating point.
- It can change the value. So don't do it.
- -- rms and moshier@world.std.com. */
- if (FLOAT_MODE_P (GET_MODE (x)))
+ /* Distributivity is not true for floating point as it can change the
+ value. So we don't do it unless -funsafe-math-optimizations. */
+ if (FLOAT_MODE_P (GET_MODE (x))
+ && ! flag_unsafe_math_optimizations)
return x;
/* The outer operation can only be one of the following: */
&& code != PLUS && code != MINUS)
return x;
- lhs = XEXP (x, 0), rhs = XEXP (x, 1);
+ lhs = XEXP (x, 0);
+ rhs = XEXP (x, 1);
/* If either operand is a primitive we can't do anything, so get out
fast. */
- if (GET_RTX_CLASS (GET_CODE (lhs)) == 'o'
- || GET_RTX_CLASS (GET_CODE (rhs)) == 'o')
+ if (OBJECT_P (lhs) || OBJECT_P (rhs))
return x;
lhs = expand_compound_operation (lhs);
tem = gen_binary (code, GET_MODE (SUBREG_REG (lhs)),
SUBREG_REG (lhs), SUBREG_REG (rhs));
- return gen_lowpart_for_combine (GET_MODE (x), tem);
+ return gen_lowpart (GET_MODE (x), tem);
default:
return x;
/* Set LHS and RHS to the inner operands (A and B in the example
above) and set OTHER to the common operand (C in the example).
- These is only one way to do this unless the inner operation is
+ There is only one way to do this unless the inner operation is
commutative. */
- if (GET_RTX_CLASS (inner_code) == 'c'
+ if (COMMUTATIVE_ARITH_P (lhs)
&& rtx_equal_p (XEXP (lhs, 0), XEXP (rhs, 0)))
other = XEXP (lhs, 0), lhs = XEXP (lhs, 1), rhs = XEXP (rhs, 1);
- else if (GET_RTX_CLASS (inner_code) == 'c'
+ else if (COMMUTATIVE_ARITH_P (lhs)
&& rtx_equal_p (XEXP (lhs, 0), XEXP (rhs, 1)))
other = XEXP (lhs, 0), lhs = XEXP (lhs, 1), rhs = XEXP (rhs, 0);
- else if (GET_RTX_CLASS (inner_code) == 'c'
+ else if (COMMUTATIVE_ARITH_P (lhs)
&& rtx_equal_p (XEXP (lhs, 1), XEXP (rhs, 0)))
other = XEXP (lhs, 1), lhs = XEXP (lhs, 0), rhs = XEXP (rhs, 1);
else if (rtx_equal_p (XEXP (lhs, 1), XEXP (rhs, 1)))
tem = gen_binary (code, GET_MODE (x), lhs, rhs);
/* There is one exception to the general way of distributing:
- (a ^ b) | (a ^ c) -> (~a) & (b ^ c) */
+ (a | c) ^ (b | c) -> (a ^ b) & ~c */
if (code == XOR && inner_code == IOR)
{
inner_code = AND;
X is zero, we are to always construct the equivalent form. */
static rtx
-simplify_and_const_int (x, mode, varop, constop)
- rtx x;
- enum machine_mode mode;
- rtx varop;
- unsigned HOST_WIDE_INT constop;
+simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
+ unsigned HOST_WIDE_INT constop)
{
unsigned HOST_WIDE_INT nonzero;
int i;
/* Simplify VAROP knowing that we will be only looking at some of the
- bits in it. */
+ bits in it.
+
+ Note by passing in CONSTOP, we guarantee that the bits not set in
+ CONSTOP are not significant and will never be examined. We must
+ ensure that is the case by explicitly masking out those bits
+ before returning. */
varop = force_to_mode (varop, mode, constop, NULL_RTX, 0);
- /* If VAROP is a CLOBBER, we will fail so return it; if it is a
- CONST_INT, we are done. */
- if (GET_CODE (varop) == CLOBBER || GET_CODE (varop) == CONST_INT)
+ /* If VAROP is a CLOBBER, we will fail so return it. */
+ if (GET_CODE (varop) == CLOBBER)
return varop;
+ /* 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)
+ return GEN_INT (trunc_int_for_mode (INTVAL (varop) & constop, mode));
+
/* See what bits may be nonzero in VAROP. Unlike the general case of
a call to nonzero_bits, here we don't care about bits outside
MODE. */
return const0_rtx;
/* If VAROP is a NEG of something known to be zero or 1 and CONSTOP is
- a power of two, we can replace this with a ASHIFT. */
+ a power of two, we can replace this with an ASHIFT. */
if (GET_CODE (varop) == NEG && nonzero_bits (XEXP (varop, 0), mode) == 1
&& (i = exact_log2 (constop)) >= 0)
return simplify_shift_const (NULL_RTX, ASHIFT, mode, XEXP (varop, 0), i);
if (GET_CODE (varop) == IOR || GET_CODE (varop) == XOR)
return
- gen_lowpart_for_combine
+ gen_lowpart
(mode,
apply_distributive_law
(gen_binary (GET_CODE (varop), GET_MODE (varop),
&& SUBREG_REG (XEXP (x, 0)) == varop)
varop = XEXP (x, 0);
else
- varop = gen_lowpart_for_combine (mode, varop);
+ varop = gen_lowpart (mode, varop);
/* If we can't make the SUBREG, try to return what we were given. */
if (GET_CODE (varop) == CLOBBER)
return x;
}
\f
+#define nonzero_bits_with_known(X, MODE) \
+ cached_nonzero_bits (X, MODE, known_x, known_mode, known_ret)
+
+/* The function cached_nonzero_bits is a wrapper around nonzero_bits1.
+ It avoids exponential behavior in nonzero_bits1 when X has
+ identical subexpressions on the first or the second level. */
+
+static unsigned HOST_WIDE_INT
+cached_nonzero_bits (rtx x, enum machine_mode mode, rtx known_x,
+ enum machine_mode known_mode,
+ unsigned HOST_WIDE_INT known_ret)
+{
+ if (x == known_x && mode == known_mode)
+ return known_ret;
+
+ /* Try to find identical subexpressions. If found call
+ nonzero_bits1 on X with the subexpressions as KNOWN_X and the
+ precomputed value for the subexpression as KNOWN_RET. */
+
+ if (ARITHMETIC_P (x))
+ {
+ rtx x0 = XEXP (x, 0);
+ rtx x1 = XEXP (x, 1);
+
+ /* Check the first level. */
+ if (x0 == x1)
+ return nonzero_bits1 (x, mode, x0, mode,
+ nonzero_bits_with_known (x0, mode));
+
+ /* Check the second level. */
+ if (ARITHMETIC_P (x0)
+ && (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1)))
+ return nonzero_bits1 (x, mode, x1, mode,
+ nonzero_bits_with_known (x1, mode));
+
+ if (ARITHMETIC_P (x1)
+ && (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1)))
+ return nonzero_bits1 (x, mode, x0, mode,
+ nonzero_bits_with_known (x0, mode));
+ }
+
+ return nonzero_bits1 (x, mode, known_x, known_mode, known_ret);
+}
+
/* We let num_sign_bit_copies recur into nonzero_bits as that is useful.
We don't let nonzero_bits recur into num_sign_bit_copies, because that
is less useful. We can't allow both, because that results in exponential
run time recursion. There is a nullstone testcase that triggered
this. This macro avoids accidental uses of num_sign_bit_copies. */
-#define num_sign_bit_copies()
+#define cached_num_sign_bit_copies()
-/* Given an expression, X, compute which bits in X can be non-zero.
+/* Given an expression, X, compute which bits in X can be nonzero.
We don't care about bits outside of those defined in MODE.
For most X this is simply GET_MODE_MASK (GET_MODE (MODE)), but if X is
a shift, AND, or zero_extract, we can do better. */
static unsigned HOST_WIDE_INT
-nonzero_bits (x, mode)
- rtx x;
- enum machine_mode mode;
+nonzero_bits1 (rtx x, enum machine_mode mode, rtx known_x,
+ enum machine_mode known_mode,
+ unsigned HOST_WIDE_INT known_ret)
{
unsigned HOST_WIDE_INT nonzero = GET_MODE_MASK (mode);
unsigned HOST_WIDE_INT inner_nz;
&& GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
&& GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (GET_MODE (x)))
{
- nonzero &= nonzero_bits (x, GET_MODE (x));
+ nonzero &= nonzero_bits_with_known (x, GET_MODE (x));
nonzero |= GET_MODE_MASK (mode) & ~GET_MODE_MASK (GET_MODE (x));
return nonzero;
}
stack to be momentarily aligned only to that amount,
so we pick the least alignment. */
if (x == stack_pointer_rtx && PUSH_ARGS)
- alignment = MIN (PUSH_ROUNDING (1), alignment);
+ alignment = MIN ((unsigned HOST_WIDE_INT) PUSH_ROUNDING (1),
+ alignment);
#endif
nonzero &= ~(alignment - 1);
for this register. */
if (reg_last_set_value[REGNO (x)] != 0
- && reg_last_set_mode[REGNO (x)] == mode
+ && (reg_last_set_mode[REGNO (x)] == mode
+ || (GET_MODE_CLASS (reg_last_set_mode[REGNO (x)]) == MODE_INT
+ && GET_MODE_CLASS (mode) == MODE_INT))
&& (reg_last_set_label[REGNO (x)] == label_tick
|| (REGNO (x) >= FIRST_PSEUDO_REGISTER
&& REG_N_SETS (REGNO (x)) == 1
- && ! REGNO_REG_SET_P (BASIC_BLOCK (0)->global_live_at_start,
+ && ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start,
REGNO (x))))
&& INSN_CUID (reg_last_set[REGNO (x)]) < subst_low_cuid)
return reg_last_set_nonzero_bits[REGNO (x)] & nonzero;
| ((HOST_WIDE_INT) (-1)
<< GET_MODE_BITSIZE (GET_MODE (x))));
#endif
- return nonzero_bits (tem, mode) & nonzero;
+ return nonzero_bits_with_known (tem, mode) & nonzero;
}
else if (nonzero_sign_valid && reg_nonzero_bits[REGNO (x)])
{
break;
case TRUNCATE:
- nonzero &= (nonzero_bits (XEXP (x, 0), mode) & GET_MODE_MASK (mode));
+ nonzero &= (nonzero_bits_with_known (XEXP (x, 0), mode)
+ & GET_MODE_MASK (mode));
break;
case ZERO_EXTEND:
- nonzero &= nonzero_bits (XEXP (x, 0), mode);
+ nonzero &= nonzero_bits_with_known (XEXP (x, 0), mode);
if (GET_MODE (XEXP (x, 0)) != VOIDmode)
nonzero &= GET_MODE_MASK (GET_MODE (XEXP (x, 0)));
break;
case SIGN_EXTEND:
/* If the sign bit is known clear, this is the same as ZERO_EXTEND.
Otherwise, show all the bits in the outer mode but not the inner
- may be non-zero. */
- inner_nz = nonzero_bits (XEXP (x, 0), mode);
+ may be nonzero. */
+ inner_nz = nonzero_bits_with_known (XEXP (x, 0), mode);
if (GET_MODE (XEXP (x, 0)) != VOIDmode)
{
inner_nz &= GET_MODE_MASK (GET_MODE (XEXP (x, 0)));
break;
case AND:
- nonzero &= (nonzero_bits (XEXP (x, 0), mode)
- & nonzero_bits (XEXP (x, 1), mode));
+ nonzero &= (nonzero_bits_with_known (XEXP (x, 0), mode)
+ & nonzero_bits_with_known (XEXP (x, 1), mode));
break;
case XOR: case IOR:
case UMIN: case UMAX: case SMIN: case SMAX:
- nonzero &= (nonzero_bits (XEXP (x, 0), mode)
- | nonzero_bits (XEXP (x, 1), mode));
+ {
+ unsigned HOST_WIDE_INT nonzero0 =
+ nonzero_bits_with_known (XEXP (x, 0), mode);
+
+ /* Don't call nonzero_bits for the second time if it cannot change
+ anything. */
+ if ((nonzero & nonzero0) != nonzero)
+ nonzero &= (nonzero0
+ | nonzero_bits_with_known (XEXP (x, 1), mode));
+ }
break;
case PLUS: case MINUS:
case MOD: case UMOD:
/* We can apply the rules of arithmetic to compute the number of
high- and low-order zero bits of these operations. We start by
- computing the width (position of the highest-order non-zero bit)
+ computing the width (position of the highest-order nonzero bit)
and the number of low-order zero bits for each value. */
{
- unsigned HOST_WIDE_INT nz0 = nonzero_bits (XEXP (x, 0), mode);
- unsigned HOST_WIDE_INT nz1 = nonzero_bits (XEXP (x, 1), mode);
+ unsigned HOST_WIDE_INT nz0 =
+ nonzero_bits_with_known (XEXP (x, 0), mode);
+ unsigned HOST_WIDE_INT nz1 =
+ nonzero_bits_with_known (XEXP (x, 1), mode);
+ int sign_index = GET_MODE_BITSIZE (GET_MODE (x)) - 1;
int width0 = floor_log2 (nz0) + 1;
int width1 = floor_log2 (nz1) + 1;
int low0 = floor_log2 (nz0 & -nz0);
int low1 = floor_log2 (nz1 & -nz1);
HOST_WIDE_INT op0_maybe_minusp
- = (nz0 & ((HOST_WIDE_INT) 1 << (mode_width - 1)));
+ = (nz0 & ((HOST_WIDE_INT) 1 << sign_index));
HOST_WIDE_INT op1_maybe_minusp
- = (nz1 & ((HOST_WIDE_INT) 1 << (mode_width - 1)));
+ = (nz1 & ((HOST_WIDE_INT) 1 << sign_index));
unsigned int result_width = mode_width;
int result_low = 0;
if (SUBREG_PROMOTED_VAR_P (x) && SUBREG_PROMOTED_UNSIGNED_P (x) > 0)
nonzero = (GET_MODE_MASK (GET_MODE (x))
- & nonzero_bits (SUBREG_REG (x), GET_MODE (x)));
+ & nonzero_bits_with_known (SUBREG_REG (x), GET_MODE (x)));
/* If the inner mode is a single word for both the host and target
machines, we can compute this from which bits of the inner
&& (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))
<= HOST_BITS_PER_WIDE_INT))
{
- nonzero &= nonzero_bits (SUBREG_REG (x), mode);
+ nonzero &= nonzero_bits_with_known (SUBREG_REG (x), mode);
#if defined (WORD_REGISTER_OPERATIONS) && defined (LOAD_EXTEND_OP)
/* If this is a typical RISC machine, we only have to worry
about the way loads are extended. */
- if (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) == SIGN_EXTEND
- ? (((nonzero
- & (((unsigned HOST_WIDE_INT) 1
- << (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) - 1))))
- != 0))
- : LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) != ZERO_EXTEND)
+ if ((LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) == SIGN_EXTEND
+ ? (((nonzero
+ & (((unsigned HOST_WIDE_INT) 1
+ << (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) - 1))))
+ != 0))
+ : LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) != ZERO_EXTEND)
+ || GET_CODE (SUBREG_REG (x)) != MEM)
#endif
{
/* On many CISC machines, accessing an object in a wider mode
unsigned int width = GET_MODE_BITSIZE (inner_mode);
int count = INTVAL (XEXP (x, 1));
unsigned HOST_WIDE_INT mode_mask = GET_MODE_MASK (inner_mode);
- unsigned HOST_WIDE_INT op_nonzero = nonzero_bits (XEXP (x, 0), mode);
+ unsigned HOST_WIDE_INT op_nonzero =
+ nonzero_bits_with_known (XEXP (x, 0), mode);
unsigned HOST_WIDE_INT inner = op_nonzero & mode_mask;
unsigned HOST_WIDE_INT outer = 0;
break;
case FFS:
+ case POPCOUNT:
/* This is at most the number of bits in the mode. */
- nonzero = ((HOST_WIDE_INT) 1 << (floor_log2 (mode_width) + 1)) - 1;
+ nonzero = ((HOST_WIDE_INT) 2 << (floor_log2 (mode_width))) - 1;
+ break;
+
+ case CLZ:
+ /* If CLZ has a known value at zero, then the nonzero bits are
+ that value, plus the number of bits in the mode minus one. */
+ if (CLZ_DEFINED_VALUE_AT_ZERO (mode, nonzero))
+ nonzero |= ((HOST_WIDE_INT) 1 << (floor_log2 (mode_width))) - 1;
+ else
+ nonzero = -1;
+ break;
+
+ case CTZ:
+ /* If CTZ has a known value at zero, then the nonzero bits are
+ that value, plus the number of bits in the mode minus one. */
+ if (CTZ_DEFINED_VALUE_AT_ZERO (mode, nonzero))
+ nonzero |= ((HOST_WIDE_INT) 1 << (floor_log2 (mode_width))) - 1;
+ else
+ nonzero = -1;
+ break;
+
+ case PARITY:
+ nonzero = 1;
break;
case IF_THEN_ELSE:
- nonzero &= (nonzero_bits (XEXP (x, 1), mode)
- | nonzero_bits (XEXP (x, 2), mode));
+ nonzero &= (nonzero_bits_with_known (XEXP (x, 1), mode)
+ | nonzero_bits_with_known (XEXP (x, 2), mode));
break;
default:
}
/* See the macro definition above. */
-#undef num_sign_bit_copies
+#undef cached_num_sign_bit_copies
\f
+#define num_sign_bit_copies_with_known(X, M) \
+ cached_num_sign_bit_copies (X, M, known_x, known_mode, known_ret)
+
+/* The function cached_num_sign_bit_copies is a wrapper around
+ num_sign_bit_copies1. It avoids exponential behavior in
+ num_sign_bit_copies1 when X has identical subexpressions on the
+ first or the second level. */
+
+static unsigned int
+cached_num_sign_bit_copies (rtx x, enum machine_mode mode, rtx known_x,
+ enum machine_mode known_mode,
+ unsigned int known_ret)
+{
+ if (x == known_x && mode == known_mode)
+ return known_ret;
+
+ /* Try to find identical subexpressions. If found call
+ num_sign_bit_copies1 on X with the subexpressions as KNOWN_X and
+ the precomputed value for the subexpression as KNOWN_RET. */
+
+ if (ARITHMETIC_P (x))
+ {
+ rtx x0 = XEXP (x, 0);
+ rtx x1 = XEXP (x, 1);
+
+ /* Check the first level. */
+ if (x0 == x1)
+ return
+ num_sign_bit_copies1 (x, mode, x0, mode,
+ num_sign_bit_copies_with_known (x0, mode));
+
+ /* Check the second level. */
+ if (ARITHMETIC_P (x0)
+ && (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1)))
+ return
+ num_sign_bit_copies1 (x, mode, x1, mode,
+ num_sign_bit_copies_with_known (x1, mode));
+
+ if (ARITHMETIC_P (x1)
+ && (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1)))
+ return
+ num_sign_bit_copies1 (x, mode, x0, mode,
+ num_sign_bit_copies_with_known (x0, mode));
+ }
+
+ return num_sign_bit_copies1 (x, mode, known_x, known_mode, known_ret);
+}
+
/* Return the number of bits at the high-order end of X that are known to
be equal to the sign bit. X will be used in mode MODE; if MODE is
VOIDmode, X will be used in its own mode. The returned value will always
be between 1 and the number of bits in MODE. */
static unsigned int
-num_sign_bit_copies (x, mode)
- rtx x;
- enum machine_mode mode;
+num_sign_bit_copies1 (rtx x, enum machine_mode mode, rtx known_x,
+ enum machine_mode known_mode,
+ unsigned int known_ret)
{
enum rtx_code code = GET_CODE (x);
unsigned int bitwidth;
/* For a smaller object, just ignore the high bits. */
if (bitwidth < GET_MODE_BITSIZE (GET_MODE (x)))
{
- num0 = num_sign_bit_copies (x, GET_MODE (x));
+ num0 = num_sign_bit_copies_with_known (x, GET_MODE (x));
return MAX (1,
num0 - (int) (GET_MODE_BITSIZE (GET_MODE (x)) - bitwidth));
}
&& (reg_last_set_label[REGNO (x)] == label_tick
|| (REGNO (x) >= FIRST_PSEUDO_REGISTER
&& REG_N_SETS (REGNO (x)) == 1
- && ! REGNO_REG_SET_P (BASIC_BLOCK (0)->global_live_at_start,
+ && ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start,
REGNO (x))))
&& INSN_CUID (reg_last_set[REGNO (x)]) < subst_low_cuid)
return reg_last_set_sign_bit_copies[REGNO (x)];
tem = get_last_value (x);
if (tem != 0)
- return num_sign_bit_copies (tem, mode);
+ return num_sign_bit_copies_with_known (tem, mode);
if (nonzero_sign_valid && reg_sign_bit_copies[REGNO (x)] != 0
&& GET_MODE_BITSIZE (GET_MODE (x)) == bitwidth)
if (SUBREG_PROMOTED_VAR_P (x) && ! SUBREG_PROMOTED_UNSIGNED_P (x))
{
- num0 = num_sign_bit_copies (SUBREG_REG (x), mode);
+ num0 = num_sign_bit_copies_with_known (SUBREG_REG (x), mode);
return MAX ((int) bitwidth
- (int) GET_MODE_BITSIZE (GET_MODE (x)) + 1,
num0);
/* For a smaller object, just ignore the high bits. */
if (bitwidth <= GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))))
{
- num0 = num_sign_bit_copies (SUBREG_REG (x), VOIDmode);
+ num0 = num_sign_bit_copies_with_known (SUBREG_REG (x), VOIDmode);
return MAX (1, (num0
- (int) (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))
- bitwidth)));
if ((GET_MODE_SIZE (GET_MODE (x))
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
- && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) == SIGN_EXTEND)
- return num_sign_bit_copies (SUBREG_REG (x), mode);
+ && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) == SIGN_EXTEND
+ && GET_CODE (SUBREG_REG (x)) == MEM)
+ return num_sign_bit_copies_with_known (SUBREG_REG (x), mode);
#endif
#endif
break;
case SIGN_EXTEND:
return (bitwidth - GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
- + num_sign_bit_copies (XEXP (x, 0), VOIDmode));
+ + num_sign_bit_copies_with_known (XEXP (x, 0), VOIDmode));
case TRUNCATE:
/* For a smaller object, just ignore the high bits. */
- num0 = num_sign_bit_copies (XEXP (x, 0), VOIDmode);
+ num0 = num_sign_bit_copies_with_known (XEXP (x, 0), VOIDmode);
return MAX (1, (num0 - (int) (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
- bitwidth)));
case NOT:
- return num_sign_bit_copies (XEXP (x, 0), mode);
+ return num_sign_bit_copies_with_known (XEXP (x, 0), mode);
case ROTATE: case ROTATERT:
/* If we are rotating left by a number of bits less than the number
&& INTVAL (XEXP (x, 1)) >= 0
&& INTVAL (XEXP (x, 1)) < (int) bitwidth)
{
- num0 = num_sign_bit_copies (XEXP (x, 0), mode);
+ num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode);
return MAX (1, num0 - (code == ROTATE ? INTVAL (XEXP (x, 1))
: (int) bitwidth - INTVAL (XEXP (x, 1))));
}
is known to be positive, the number of sign bit copies is the
same as that of the input. Finally, if the input has just one bit
that might be nonzero, all the bits are copies of the sign bit. */
- num0 = num_sign_bit_copies (XEXP (x, 0), mode);
+ num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode);
if (bitwidth > HOST_BITS_PER_WIDE_INT)
return num0 > 1 ? num0 - 1 : 1;
case SMIN: case SMAX: case UMIN: case UMAX:
/* Logical operations will preserve the number of sign-bit copies.
MIN and MAX operations always return one of the operands. */
- num0 = num_sign_bit_copies (XEXP (x, 0), mode);
- num1 = num_sign_bit_copies (XEXP (x, 1), mode);
+ num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode);
+ num1 = num_sign_bit_copies_with_known (XEXP (x, 1), mode);
return MIN (num0, num1);
case PLUS: case MINUS:
: bitwidth - floor_log2 (nonzero) - 1);
}
- num0 = num_sign_bit_copies (XEXP (x, 0), mode);
- num1 = num_sign_bit_copies (XEXP (x, 1), mode);
+ num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode);
+ num1 = num_sign_bit_copies_with_known (XEXP (x, 1), mode);
result = MAX (1, MIN (num0, num1) - 1);
#ifdef POINTERS_EXTEND_UNSIGNED
to be positive, we must allow for an additional bit since negating
a negative number can remove one sign bit copy. */
- num0 = num_sign_bit_copies (XEXP (x, 0), mode);
- num1 = num_sign_bit_copies (XEXP (x, 1), mode);
+ num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode);
+ num1 = num_sign_bit_copies_with_known (XEXP (x, 1), mode);
result = bitwidth - (bitwidth - num0) - (bitwidth - num1);
if (result > 0
& ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
return 1;
else
- return num_sign_bit_copies (XEXP (x, 0), mode);
+ return num_sign_bit_copies_with_known (XEXP (x, 0), mode);
case UMOD:
/* The result must be <= the second operand. */
- return num_sign_bit_copies (XEXP (x, 1), mode);
+ return num_sign_bit_copies_with_known (XEXP (x, 1), mode);
case DIV:
/* Similar to unsigned division, except that we have to worry about
the case where the divisor is negative, in which case we have
to add 1. */
- result = num_sign_bit_copies (XEXP (x, 0), mode);
+ result = num_sign_bit_copies_with_known (XEXP (x, 0), mode);
if (result > 1
&& (bitwidth > HOST_BITS_PER_WIDE_INT
|| (nonzero_bits (XEXP (x, 1), mode)
return result;
case MOD:
- result = num_sign_bit_copies (XEXP (x, 1), mode);
+ result = num_sign_bit_copies_with_known (XEXP (x, 1), mode);
if (result > 1
&& (bitwidth > HOST_BITS_PER_WIDE_INT
|| (nonzero_bits (XEXP (x, 1), mode)
case ASHIFTRT:
/* Shifts by a constant add to the number of bits equal to the
sign bit. */
- num0 = num_sign_bit_copies (XEXP (x, 0), mode);
+ num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode);
if (GET_CODE (XEXP (x, 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) > 0)
num0 = MIN ((int) bitwidth, num0 + INTVAL (XEXP (x, 1)));
|| INTVAL (XEXP (x, 1)) >= (int) bitwidth)
return 1;
- num0 = num_sign_bit_copies (XEXP (x, 0), mode);
+ num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode);
return MAX (1, num0 - INTVAL (XEXP (x, 1)));
case IF_THEN_ELSE:
- num0 = num_sign_bit_copies (XEXP (x, 1), mode);
- num1 = num_sign_bit_copies (XEXP (x, 2), mode);
+ num0 = num_sign_bit_copies_with_known (XEXP (x, 1), mode);
+ num1 = num_sign_bit_copies_with_known (XEXP (x, 2), mode);
return MIN (num0, num1);
case EQ: case NE: case GE: case GT: case LE: case LT:
implies that it must be called from a define_split. */
unsigned int
-extended_count (x, mode, unsignedp)
- rtx x;
- enum machine_mode mode;
- int unsignedp;
+extended_count (rtx x, enum machine_mode mode, int unsignedp)
{
if (nonzero_sign_valid == 0)
return 0;
return (unsignedp
? (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
- ? (GET_MODE_BITSIZE (mode) - 1
- - floor_log2 (nonzero_bits (x, mode)))
+ ? (unsigned int) (GET_MODE_BITSIZE (mode) - 1
+ - floor_log2 (nonzero_bits (x, mode)))
: 0)
: num_sign_bit_copies (x, mode) - 1);
}
return 0 and do not change *POP0, *PCONST0, and *PCOMP_P. */
static int
-merge_outer_ops (pop0, pconst0, op1, const1, mode, pcomp_p)
- enum rtx_code *pop0;
- HOST_WIDE_INT *pconst0;
- enum rtx_code op1;
- HOST_WIDE_INT const1;
- enum machine_mode mode;
- int *pcomp_p;
+merge_outer_ops (enum rtx_code *pop0, HOST_WIDE_INT *pconst0, enum rtx_code op1, HOST_WIDE_INT const1, enum machine_mode mode, int *pcomp_p)
{
enum rtx_code op0 = *pop0;
HOST_WIDE_INT const0 = *pconst0;
op0 = AND, *pcomp_p = 1;
else /* op1 == IOR */
/* (a | b) ^ b == a & ~b */
- op0 = AND, *pconst0 = ~const0;
+ op0 = AND, const0 = ~const0;
break;
case AND:
}
\f
/* Simplify a shift of VAROP by COUNT bits. CODE says what kind of shift.
- The result of the shift is RESULT_MODE. X, if non-zero, is an expression
+ The result of the shift is RESULT_MODE. X, if nonzero, is an expression
that we started with.
The shift is normally computed in the widest mode we find in VAROP, as
are ASHIFTRT and ROTATE, which are always done in their original mode, */
static rtx
-simplify_shift_const (x, code, result_mode, varop, orig_count)
- rtx x;
- enum rtx_code code;
- enum machine_mode result_mode;
- rtx varop;
- int orig_count;
+simplify_shift_const (rtx x, enum rtx_code code,
+ enum machine_mode result_mode, rtx varop,
+ int orig_count)
{
enum rtx_code orig_code = code;
unsigned int count;
/* 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
combine shifts. */
-#ifdef SHIFT_COUNT_TRUNCATED
if (SHIFT_COUNT_TRUNCATED)
orig_count &= GET_MODE_BITSIZE (mode) - 1;
-#endif
/* If we were given an invalid count, don't do anything except exactly
what was requested. */
/* Convert ROTATERT to ROTATE. */
if (code == ROTATERT)
- code = ROTATE, count = GET_MODE_BITSIZE (result_mode) - count;
+ {
+ unsigned int bitsize = GET_MODE_BITSIZE (result_mode);;
+ code = ROTATE;
+ if (VECTOR_MODE_P (result_mode))
+ count = bitsize / GET_MODE_NUNITS (result_mode) - count;
+ else
+ 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
multiple operations, each of which are defined, we know what the
result is supposed to be. */
- if (count > GET_MODE_BITSIZE (shift_mode) - 1)
+ if (count > (unsigned int) (GET_MODE_BITSIZE (shift_mode) - 1))
{
if (code == ASHIFTRT)
count = GET_MODE_BITSIZE (shift_mode) - 1;
/* We simplify the tests below and elsewhere by converting
ASHIFTRT to LSHIFTRT if we know the sign bit is clear.
- `make_compound_operation' will convert it to a ASHIFTRT for
- those machines (such as VAX) that don't have a LSHIFTRT. */
+ `make_compound_operation' will convert it to an ASHIFTRT for
+ those machines (such as VAX) that don't have an LSHIFTRT. */
if (GET_MODE_BITSIZE (shift_mode) <= HOST_BITS_PER_WIDE_INT
&& code == ASHIFTRT
&& ((nonzero_bits (varop, shift_mode)
== 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)))
+ varop = const0_rtx;
+
switch (GET_CODE (varop))
{
case SIGN_EXTEND:
if (subreg_lowpart_p (varop)
&& (GET_MODE_SIZE (GET_MODE (SUBREG_REG (varop)))
> GET_MODE_SIZE (GET_MODE (varop)))
- && (((GET_MODE_SIZE (GET_MODE (SUBREG_REG (varop)))
- + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
- == mode_words))
+ && (unsigned int) ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (varop)))
+ + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
+ == mode_words)
{
varop = SUBREG_REG (varop);
if (GET_MODE_SIZE (GET_MODE (varop)) > GET_MODE_SIZE (mode))
bit of a wider mode may be different from what would be
interpreted as the sign bit in a narrower mode, so, if
the result is narrower, don't discard the shift. */
- if (code == LSHIFTRT && count == GET_MODE_BITSIZE (result_mode) - 1
+ if (code == LSHIFTRT
+ && count == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1)
&& (GET_MODE_BITSIZE (result_mode)
>= GET_MODE_BITSIZE (GET_MODE (varop))))
{
(ashiftrt:M1 (ashift:M1 (and:M1 (subreg:M1 FOO 0 C2) C3) C1).
This simplifies certain SIGN_EXTEND operations. */
if (code == ASHIFT && first_code == ASHIFTRT
- && (GET_MODE_BITSIZE (result_mode)
- - GET_MODE_BITSIZE (GET_MODE (varop))) == count)
+ && count == (unsigned int)
+ (GET_MODE_BITSIZE (result_mode)
+ - GET_MODE_BITSIZE (GET_MODE (varop))))
{
/* C3 has the low-order C1 bits zero. */
/* If this was (ashiftrt (ashift foo C1) C2) and FOO has more
than C1 high-order bits equal to the sign bit, we can convert
- this to either an ASHIFT or a ASHIFTRT depending on the
+ this to either an ASHIFT or an ASHIFTRT depending on the
two counts.
We cannot do this if VAROP's mode is not SHIFT_MODE. */
&& XEXP (XEXP (varop, 0), 1) == constm1_rtx
&& (STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
&& (code == LSHIFTRT || code == ASHIFTRT)
- && count == GET_MODE_BITSIZE (GET_MODE (varop)) - 1
+ && count == (unsigned int)
+ (GET_MODE_BITSIZE (GET_MODE (varop)) - 1)
&& rtx_equal_p (XEXP (XEXP (varop, 0), 0), XEXP (varop, 1)))
{
count = 0;
(and (shift)) insns. */
if (GET_CODE (XEXP (varop, 1)) == CONST_INT
+ /* 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_binary_operation (code, result_mode,
XEXP (varop, 1),
GEN_INT (count))) != 0
/* If we can't do that, try to simplify the shift in each arm of the
logical expression, make a new logical expression, and apply
- the inverse distributive law. */
- {
- rtx lhs = simplify_shift_const (NULL_RTX, code, shift_mode,
- XEXP (varop, 0), count);
- rtx rhs = simplify_shift_const (NULL_RTX, code, shift_mode,
- XEXP (varop, 1), count);
+ the inverse distributive law. This also can't be done
+ for some (ashiftrt (xor)). */
+ if (code != ASHIFTRT || GET_CODE (varop)!= XOR
+ || 0 <= trunc_int_for_mode (INTVAL (XEXP (varop, 1)),
+ shift_mode))
+ {
+ rtx lhs = simplify_shift_const (NULL_RTX, code, shift_mode,
+ XEXP (varop, 0), count);
+ rtx rhs = simplify_shift_const (NULL_RTX, code, shift_mode,
+ XEXP (varop, 1), count);
- varop = gen_binary (GET_CODE (varop), shift_mode, lhs, rhs);
- varop = apply_distributive_law (varop);
+ varop = gen_binary (GET_CODE (varop), shift_mode, lhs, rhs);
+ varop = apply_distributive_law (varop);
- count = 0;
- }
+ count = 0;
+ }
break;
case EQ:
- /* convert (lshiftrt (eq FOO 0) C) to (xor FOO 1) if STORE_FLAG_VALUE
+ /* Convert (lshiftrt (eq FOO 0) C) to (xor FOO 1) if STORE_FLAG_VALUE
says that the sign bit can be tested, FOO has mode MODE, C is
GET_MODE_BITSIZE (MODE) - 1, and FOO has only its low-order bit
that may be nonzero. */
if (code == LSHIFTRT
&& XEXP (varop, 1) == const0_rtx
&& GET_MODE (XEXP (varop, 0)) == result_mode
- && count == GET_MODE_BITSIZE (result_mode) - 1
+ && count == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1)
&& GET_MODE_BITSIZE (result_mode) <= HOST_BITS_PER_WIDE_INT
&& ((STORE_FLAG_VALUE
& ((HOST_WIDE_INT) 1
case NEG:
/* (lshiftrt (neg A) C) where A is either 0 or 1 and C is one less
than the number of bits in the mode is equivalent to A. */
- if (code == LSHIFTRT && count == GET_MODE_BITSIZE (result_mode) - 1
+ if (code == LSHIFTRT
+ && count == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1)
&& nonzero_bits (XEXP (varop, 0), result_mode) == 1)
{
varop = XEXP (varop, 0);
/* (lshiftrt (plus A -1) C) where A is either 0 or 1 and C
is one less than the number of bits in the mode is
equivalent to (xor A 1). */
- if (code == LSHIFTRT && count == GET_MODE_BITSIZE (result_mode) - 1
+ if (code == LSHIFTRT
+ && count == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1)
&& XEXP (varop, 1) == constm1_rtx
&& nonzero_bits (XEXP (varop, 0), result_mode) == 1
&& merge_outer_ops (&outer_op, &outer_const, XOR,
if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
&& GET_CODE (XEXP (varop, 0)) == ASHIFTRT
- && count == GET_MODE_BITSIZE (GET_MODE (varop)) - 1
+ && count == (unsigned int)
+ (GET_MODE_BITSIZE (GET_MODE (varop)) - 1)
&& (code == LSHIFTRT || code == ASHIFTRT)
&& GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT
- && INTVAL (XEXP (XEXP (varop, 0), 1)) == count
+ && (unsigned HOST_WIDE_INT) INTVAL (XEXP (XEXP (varop, 0), 1))
+ == count
&& rtx_equal_p (XEXP (XEXP (varop, 0), 0), XEXP (varop, 1)))
{
count = 0;
If we were passed a value for X, see if we can use any pieces of
it. If not, make new rtx. */
- if (x && GET_RTX_CLASS (GET_CODE (x)) == '2'
+ if (x && GET_RTX_CLASS (GET_CODE (x)) == RTX_BIN_ARITH
&& GET_CODE (XEXP (x, 1)) == CONST_INT
- && INTVAL (XEXP (x, 1)) == count)
+ && (unsigned HOST_WIDE_INT) INTVAL (XEXP (x, 1)) == count)
const_rtx = XEXP (x, 1);
else
const_rtx = GEN_INT (count);
&& SUBREG_REG (XEXP (x, 0)) == varop)
varop = XEXP (x, 0);
else if (GET_MODE (varop) != shift_mode)
- varop = gen_lowpart_for_combine (shift_mode, varop);
+ varop = gen_lowpart (shift_mode, varop);
/* If we can't make the SUBREG, try to return what we were given. */
if (GET_CODE (varop) == CLOBBER)
x = simplify_shift_const (x, code, shift_mode, XEXP (x, 0),
INTVAL (XEXP (x, 1)));
- /* If we were doing a LSHIFTRT in a wider mode than it was originally,
+ /* If we were doing an LSHIFTRT in a wider mode than it was originally,
turn off all the bits that the shift would have turned off. */
if (orig_code == LSHIFTRT && result_mode != shift_mode)
x = simplify_and_const_int (NULL_RTX, shift_mode, x,
GET_MODE_MASK (result_mode) >> orig_count);
/* Do the remainder of the processing in RESULT_MODE. */
- x = gen_lowpart_for_combine (result_mode, x);
+ x = gen_lowpart (result_mode, x);
/* If COMPLEMENT_P is set, we have to complement X before doing the outer
operation. */
if (complement_p)
- x =simplify_gen_unary (NOT, result_mode, x, result_mode);
+ x = simplify_gen_unary (NOT, result_mode, x, result_mode);
if (outer_op != NIL)
{
/* This means that we have determined that the result is
equivalent to a constant. This should be rare. */
x = GEN_INT (outer_const);
- else if (GET_RTX_CLASS (outer_op) == '1')
+ else if (GET_RTX_CLASS (outer_op) == RTX_UNARY)
x = simplify_gen_unary (outer_op, result_mode, x, result_mode);
else
x = gen_binary (outer_op, result_mode, x, GEN_INT (outer_const));
or -1. */
static int
-recog_for_combine (pnewpat, insn, pnotes)
- rtx *pnewpat;
- rtx insn;
- rtx *pnotes;
+recog_for_combine (rtx *pnewpat, rtx insn, rtx *pnotes)
{
rtx pat = *pnewpat;
int insn_code_number;
int num_clobbers_to_add = 0;
int i;
rtx notes = 0;
- rtx dummy_insn;
+ rtx old_notes, old_pat;
/* If PAT is a PARALLEL, check to see if it contains the CLOBBER
we use to indicate that something didn't match. If we find such a
&& XEXP (XVECEXP (pat, 0, i), 0) == const0_rtx)
return -1;
- /* *pnewpat does not have to be actual PATTERN (insn), so make a dummy
- instruction for pattern recognition. */
- dummy_insn = shallow_copy_rtx (insn);
- PATTERN (dummy_insn) = pat;
- REG_NOTES (dummy_insn) = 0;
+ old_pat = PATTERN (insn);
+ old_notes = REG_NOTES (insn);
+ PATTERN (insn) = pat;
+ REG_NOTES (insn) = 0;
- insn_code_number = recog (pat, dummy_insn, &num_clobbers_to_add);
+ insn_code_number = recog (pat, insn, &num_clobbers_to_add);
/* 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
if (pos == 1)
pat = XVECEXP (pat, 0, 0);
- PATTERN (dummy_insn) = pat;
- insn_code_number = recog (pat, dummy_insn, &num_clobbers_to_add);
+ PATTERN (insn) = pat;
+ insn_code_number = recog (pat, insn, &num_clobbers_to_add);
}
+ PATTERN (insn) = old_pat;
+ REG_NOTES (insn) = old_notes;
/* Recognize all noop sets, these will be killed by followup pass. */
if (insn_code_number < 0 && GET_CODE (pat) == SET && set_noop_p (pat))
return insn_code_number;
}
\f
-/* Like gen_lowpart but for use by combine. In combine it is not possible
- to create any new pseudoregs. However, it is safe to create
- invalid memory addresses, because combine will try to recognize
- them and all they will do is make the combine attempt fail.
+/* Like gen_lowpart_general but for use by combine. In combine it
+ is not possible to create any new pseudoregs. However, it is
+ safe to create invalid memory addresses, because combine will
+ try to recognize them and all they will do is make the combine
+ attempt fail.
If for some reason this cannot do its job, an rtx
(clobber (const_int 0)) is returned.
An insn containing that will not be recognized. */
-#undef gen_lowpart
-
static rtx
-gen_lowpart_for_combine (mode, x)
- enum machine_mode mode;
- rtx x;
+gen_lowpart_for_combine (enum machine_mode mode, rtx x)
{
rtx result;
if (GET_MODE (x) == mode)
return x;
+ /* Return identity if this is a CONST or symbolic
+ reference. */
+ if (mode == Pmode
+ && (GET_CODE (x) == CONST
+ || GET_CODE (x) == SYMBOL_REF
+ || GET_CODE (x) == LABEL_REF))
+ return x;
+
/* We can only support MODE being wider than a word if X is a
constant integer or has a mode the same size. */
}
result = gen_lowpart_common (mode, x);
-#ifdef CLASS_CANNOT_CHANGE_MODE
+#ifdef CANNOT_CHANGE_MODE_CLASS
if (result != 0
&& GET_CODE (result) == SUBREG
&& GET_CODE (SUBREG_REG (result)) == REG
- && REGNO (SUBREG_REG (result)) >= FIRST_PSEUDO_REGISTER
- && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (result),
- GET_MODE (SUBREG_REG (result))))
- REG_CHANGES_MODE (REGNO (SUBREG_REG (result))) = 1;
+ && REGNO (SUBREG_REG (result)) >= FIRST_PSEUDO_REGISTER)
+ bitmap_set_bit (&subregs_of_mode, REGNO (SUBREG_REG (result))
+ * MAX_MACHINE_MODE
+ + GET_MODE (result));
#endif
if (result)
return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
/* If we want to refer to something bigger than the original memref,
- generate a perverse subreg instead. That will force a reload
+ generate a paradoxical subreg instead. That will force a reload
of the original memref X. */
if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode))
return gen_rtx_SUBREG (mode, x, 0);
/* If X is a comparison operator, rewrite it in a new mode. This
probably won't match, but may allow further simplifications. */
- else if (GET_RTX_CLASS (GET_CODE (x)) == '<')
+ else if (COMPARISON_P (x))
return gen_rtx_fmt_ee (GET_CODE (x), mode, XEXP (x, 0), XEXP (x, 1));
/* If we couldn't simplify X any other way, just enclose it in a
{
int offset = 0;
rtx res;
+ enum machine_mode sub_mode = GET_MODE (x);
- offset = subreg_lowpart_offset (mode, GET_MODE (x));
- res = simplify_gen_subreg (mode, x, GET_MODE (x), offset);
+ offset = subreg_lowpart_offset (mode, sub_mode);
+ if (sub_mode == VOIDmode)
+ {
+ sub_mode = int_mode_for_mode (mode);
+ x = gen_lowpart_common (sub_mode, x);
+ if (x == 0)
+ return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
+ }
+ res = simplify_gen_subreg (mode, x, sub_mode, offset);
if (res)
return res;
return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
fold; if not, a new expression is allocated. */
static rtx
-gen_binary (code, mode, op0, op1)
- enum rtx_code code;
- enum machine_mode mode;
- rtx op0, op1;
+gen_binary (enum rtx_code code, enum machine_mode mode, rtx op0, rtx op1)
{
rtx result;
rtx tem;
- if (GET_RTX_CLASS (code) == 'c'
+ if (GET_CODE (op0) == CLOBBER)
+ return op0;
+ else if (GET_CODE (op1) == CLOBBER)
+ return op1;
+
+ if (GET_RTX_CLASS (code) == RTX_COMM_ARITH
&& swap_commutative_operands_p (op0, op1))
tem = op0, op0 = op1, op1 = tem;
- if (GET_RTX_CLASS (code) == '<')
+ if (GET_RTX_CLASS (code) == RTX_COMPARE
+ || GET_RTX_CLASS (code) == RTX_COMM_COMPARE)
{
enum machine_mode op_mode = GET_MODE (op0);
if (op_mode == VOIDmode)
op_mode = GET_MODE (op1);
- result = simplify_relational_operation (code, op_mode, op0, op1);
+ result = simplify_relational_operation (code, mode, op_mode, op0, op1);
}
else
result = simplify_binary_operation (code, mode, op0, op1);
return result;
/* Put complex operands first and constants second. */
- if (GET_RTX_CLASS (code) == 'c'
+ if (GET_RTX_CLASS (code) == RTX_COMM_ARITH
&& swap_commutative_operands_p (op0, op1))
return gen_rtx_fmt_ee (code, mode, op1, op0);
should have been detected earlier. Hence we ignore all such cases. */
static enum rtx_code
-simplify_comparison (code, pop0, pop1)
- enum rtx_code code;
- rtx *pop0;
- rtx *pop1;
+simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
{
rtx op0 = *pop0;
rtx op1 = *pop1;
&& (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
- && GET_CODE (XEXP (op1, 1)) == CONST_INT
- && GET_CODE (XEXP (XEXP (op0, 0), 1)) == CONST_INT
- && GET_CODE (XEXP (XEXP (op1, 0), 1)) == CONST_INT
- && INTVAL (XEXP (op0, 1)) == INTVAL (XEXP (op1, 1))
- && INTVAL (XEXP (op0, 1)) == INTVAL (XEXP (XEXP (op0, 0), 1))
- && INTVAL (XEXP (op0, 1)) == INTVAL (XEXP (XEXP (op1, 0), 1))
+ && XEXP (op0, 1) == XEXP (op1, 1)
+ && XEXP (op0, 1) == XEXP (XEXP (op0, 0), 1)
+ && XEXP (op0, 1) == XEXP (XEXP (op1, 0), 1)
&& (INTVAL (XEXP (op0, 1))
== (GET_MODE_BITSIZE (GET_MODE (op0))
- (GET_MODE_BITSIZE
tmode != GET_MODE (op0); tmode = GET_MODE_WIDER_MODE (tmode))
if ((unsigned HOST_WIDE_INT) c0 == GET_MODE_MASK (tmode))
{
- op0 = gen_lowpart_for_combine (tmode, inner_op0);
- op1 = gen_lowpart_for_combine (tmode, inner_op1);
+ op0 = gen_lowpart (tmode, inner_op0);
+ op1 = gen_lowpart (tmode, inner_op1);
code = unsigned_condition (code);
changed = 1;
break;
if (GET_MODE_CLASS (mode) != MODE_INT
&& ! (mode == VOIDmode
- && (GET_CODE (op0) == COMPARE
- || GET_RTX_CLASS (GET_CODE (op0)) == '<')))
+ && (GET_CODE (op0) == COMPARE || COMPARISON_P (op0))))
break;
/* Get the constant we are comparing against and turn off all bits
not on in our mode. */
- const_op = trunc_int_for_mode (INTVAL (op1), mode);
+ const_op = INTVAL (op1);
+ if (mode != VOIDmode)
+ const_op = trunc_int_for_mode (const_op, mode);
op1 = GEN_INT (const_op);
/* If we are comparing against a constant power of two and the value
/* (unsigned) > 0x7fffffff is equivalent to < 0. */
else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
- && (const_op == ((HOST_WIDE_INT) 1 << (mode_width - 1)) - 1))
+ && (const_op == ((HOST_WIDE_INT) 1 << (mode_width - 1)) - 1))
{
const_op = 0, op1 = const0_rtx;
code = LT;
a constant that has only a single bit set and are comparing it
with zero, we can convert this into an equality comparison
between the position and the location of the single bit. */
-
- if (GET_CODE (XEXP (op0, 0)) == CONST_INT
+ /* 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
&& XEXP (op0, 1) == const1_rtx
&& equality_comparison_p && const_op == 0
&& (i = exact_log2 (INTVAL (XEXP (op0, 0)))) >= 0)
& ~GET_MODE_MASK (mode))
|| (num_sign_bit_copies (XEXP (SUBREG_REG (op0), 0),
GET_MODE (SUBREG_REG (op0)))
- > (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)))
+ > (unsigned int)
+ (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)))
- GET_MODE_BITSIZE (mode)))))
{
op0 = SUBREG_REG (op0);
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
- && INTVAL (XEXP (XEXP (op0, 0), 1)) == mode_width - 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)))
{
op0 = XEXP (op0, 1);
/* We can't do anything if OP0 is a condition code value, rather
than an actual data value. */
if (const_op != 0
-#ifdef HAVE_cc0
- || XEXP (op0, 0) == cc0_rtx
-#endif
+ || CC0_P (XEXP (op0, 0))
|| GET_MODE_CLASS (GET_MODE (XEXP (op0, 0))) == MODE_CC)
break;
break;
case IOR:
- /* The sign bit of (ior (plus X (const_int -1)) X) is non-zero
+ /* The sign bit of (ior (plus X (const_int -1)) X) is nonzero
iff X <= 0. */
if (sign_bit_comparison_p && GET_CODE (XEXP (op0, 0)) == PLUS
&& XEXP (XEXP (op0, 0), 1) == constm1_rtx
mask = ((INTVAL (XEXP (op0, 1)) & GET_MODE_MASK (mode))
<< INTVAL (XEXP (XEXP (op0, 0), 1)));
if ((~STORE_FLAG_VALUE & mask) == 0
- && (GET_RTX_CLASS (GET_CODE (XEXP (XEXP (op0, 0), 0))) == '<'
+ && (COMPARISON_P (XEXP (XEXP (op0, 0), 0))
|| ((tem = get_last_value (XEXP (XEXP (op0, 0), 0))) != 0
- && GET_RTX_CLASS (GET_CODE (tem)) == '<')))
+ && COMPARISON_P (tem))))
{
op0 = XEXP (XEXP (op0, 0), 0);
continue;
&& const_op >> i == 0
&& (tmode = mode_for_size (i, MODE_INT, 1)) != BLKmode)
{
- op0 = gen_lowpart_for_combine (tmode, XEXP (op0, 0));
+ op0 = gen_lowpart (tmode, XEXP (op0, 0));
continue;
}
- /* If this is (and:M1 (subreg:M2 X 0) (const_int C1)) where C1 fits
- in both M1 and M2 and the SUBREG is either paradoxical or
- represents the low part, permute the SUBREG and the AND and
- try again. */
- if (GET_CODE (XEXP (op0, 0)) == SUBREG
- && (0
+ /* If this is (and:M1 (subreg:M2 X 0) (const_int C1)) where C1
+ fits in both M1 and M2 and the SUBREG is either paradoxical
+ or represents the low part, permute the SUBREG and the AND
+ and try again. */
+ if (GET_CODE (XEXP (op0, 0)) == SUBREG)
+ {
+ unsigned HOST_WIDE_INT c1;
+ tmode = GET_MODE (SUBREG_REG (XEXP (op0, 0)));
+ /* Require an integral mode, to avoid creating something like
+ (AND:SF ...). */
+ if (SCALAR_INT_MODE_P (tmode)
+ /* It is unsafe to commute the AND into the SUBREG if the
+ SUBREG is paradoxical and WORD_REGISTER_OPERATIONS is
+ not defined. As originally written the upper bits
+ have a defined value due to the AND operation.
+ However, if we commute the AND inside the SUBREG then
+ they no longer have defined values and the meaning of
+ the code has been changed. */
+ && (0
#ifdef WORD_REGISTER_OPERATIONS
- || ((mode_width
- > (GET_MODE_BITSIZE
- (GET_MODE (SUBREG_REG (XEXP (op0, 0))))))
- && mode_width <= BITS_PER_WORD)
-#endif
- || ((mode_width
- <= (GET_MODE_BITSIZE
- (GET_MODE (SUBREG_REG (XEXP (op0, 0))))))
- && subreg_lowpart_p (XEXP (op0, 0))))
-#ifndef WORD_REGISTER_OPERATIONS
- /* It is unsafe to commute the AND into the SUBREG if the SUBREG
- is paradoxical and WORD_REGISTER_OPERATIONS is not defined.
- As originally written the upper bits have a defined value
- due to the AND operation. However, if we commute the AND
- inside the SUBREG then they no longer have defined values
- and the meaning of the code has been changed. */
- && (GET_MODE_SIZE (GET_MODE (XEXP (op0, 0)))
- <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (op0, 0)))))
+ || (mode_width > GET_MODE_BITSIZE (tmode)
+ && mode_width <= BITS_PER_WORD)
#endif
- && GET_CODE (XEXP (op0, 1)) == CONST_INT
- && mode_width <= HOST_BITS_PER_WIDE_INT
- && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (XEXP (op0, 0))))
- <= HOST_BITS_PER_WIDE_INT)
- && (INTVAL (XEXP (op0, 1)) & ~mask) == 0
- && 0 == (~GET_MODE_MASK (GET_MODE (SUBREG_REG (XEXP (op0, 0))))
- & INTVAL (XEXP (op0, 1)))
- && (unsigned HOST_WIDE_INT) INTVAL (XEXP (op0, 1)) != mask
- && ((unsigned HOST_WIDE_INT) INTVAL (XEXP (op0, 1))
- != GET_MODE_MASK (GET_MODE (SUBREG_REG (XEXP (op0, 0))))))
-
- {
- op0
- = gen_lowpart_for_combine
- (mode,
- gen_binary (AND, GET_MODE (SUBREG_REG (XEXP (op0, 0))),
- SUBREG_REG (XEXP (op0, 0)), XEXP (op0, 1)));
- continue;
+ || (mode_width <= GET_MODE_BITSIZE (tmode)
+ && subreg_lowpart_p (XEXP (op0, 0))))
+ && GET_CODE (XEXP (op0, 1)) == CONST_INT
+ && mode_width <= HOST_BITS_PER_WIDE_INT
+ && GET_MODE_BITSIZE (tmode) <= HOST_BITS_PER_WIDE_INT
+ && ((c1 = INTVAL (XEXP (op0, 1))) & ~mask) == 0
+ && (c1 & ~GET_MODE_MASK (tmode)) == 0
+ && c1 != mask
+ && c1 != GET_MODE_MASK (tmode))
+ {
+ op0 = gen_binary (AND, tmode,
+ SUBREG_REG (XEXP (op0, 0)),
+ gen_int_mode (c1, tmode));
+ op0 = gen_lowpart (mode, op0);
+ continue;
+ }
}
- /* Convert (ne (and (lshiftrt (not X)) 1) 0) to
- (eq (and (lshiftrt X) 1) 0). */
+ /* Convert (ne (and (not X) 1) 0) to (eq (and X 1) 0). */
if (const_op == 0 && equality_comparison_p
&& XEXP (op0, 1) == const1_rtx
- && GET_CODE (XEXP (op0, 0)) == LSHIFTRT
- && GET_CODE (XEXP (XEXP (op0, 0), 0)) == NOT)
+ && GET_CODE (XEXP (op0, 0)) == NOT)
{
op0 = simplify_and_const_int
- (op0, mode,
- gen_rtx_LSHIFTRT (mode, XEXP (XEXP (XEXP (op0, 0), 0), 0),
- XEXP (XEXP (op0, 0), 1)),
- (HOST_WIDE_INT) 1);
+ (NULL_RTX, mode, XEXP (XEXP (op0, 0), 0), (HOST_WIDE_INT) 1);
code = (code == NE ? EQ : NE);
continue;
}
+
+ /* Convert (ne (and (lshiftrt (not X)) 1) 0) to
+ (eq (and (lshiftrt X) 1) 0).
+ Also handle the case where (not X) is expressed using xor. */
+ if (const_op == 0 && equality_comparison_p
+ && XEXP (op0, 1) == const1_rtx
+ && GET_CODE (XEXP (op0, 0)) == LSHIFTRT)
+ {
+ rtx shift_op = XEXP (XEXP (op0, 0), 0);
+ rtx shift_count = XEXP (XEXP (op0, 0), 1);
+
+ 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
+ && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+ && (INTVAL (XEXP (shift_op, 1))
+ == (HOST_WIDE_INT) 1 << INTVAL (shift_count))))
+ {
+ op0 = simplify_and_const_int
+ (NULL_RTX, mode,
+ gen_rtx_LSHIFTRT (mode, XEXP (shift_op, 0), shift_count),
+ (HOST_WIDE_INT) 1);
+ code = (code == NE ? EQ : NE);
+ continue;
+ }
+ }
break;
case ASHIFT:
unsigned HOST_WIDE_INT temp = const_op & GET_MODE_MASK (mode);
temp >>= INTVAL (XEXP (op0, 1));
- op1 = GEN_INT (trunc_int_for_mode (temp, mode));
+ op1 = gen_int_mode (temp, mode);
op0 = XEXP (op0, 0);
continue;
}
low-order bit. */
if (const_op == 0 && equality_comparison_p
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
- && INTVAL (XEXP (op0, 1)) == mode_width - 1)
+ && (unsigned HOST_WIDE_INT) INTVAL (XEXP (op0, 1))
+ == mode_width - 1)
{
op0 = simplify_and_const_int (NULL_RTX, mode, XEXP (op0, 0),
(HOST_WIDE_INT) 1);
&& XEXP (op0, 1) == XEXP (XEXP (op0, 0), 1)
&& (tmode = mode_for_size (mode_width - INTVAL (XEXP (op0, 1)),
MODE_INT, 1)) != BLKmode
- && ((unsigned HOST_WIDE_INT) const_op <= GET_MODE_MASK (tmode)
- || ((unsigned HOST_WIDE_INT) -const_op
- <= GET_MODE_MASK (tmode))))
+ && (((unsigned HOST_WIDE_INT) const_op
+ + (GET_MODE_MASK (tmode) >> 1) + 1)
+ <= GET_MODE_MASK (tmode)))
{
- op0 = gen_lowpart_for_combine (tmode, XEXP (XEXP (op0, 0), 0));
+ op0 = gen_lowpart (tmode, XEXP (XEXP (op0, 0), 0));
continue;
}
&& XEXP (op0, 1) == XEXP (XEXP (XEXP (op0, 0), 0), 1)
&& (tmode = mode_for_size (mode_width - INTVAL (XEXP (op0, 1)),
MODE_INT, 1)) != BLKmode
- && ((unsigned HOST_WIDE_INT) const_op <= GET_MODE_MASK (tmode)
- || ((unsigned HOST_WIDE_INT) -const_op
- <= GET_MODE_MASK (tmode))))
+ && (((unsigned HOST_WIDE_INT) const_op
+ + (GET_MODE_MASK (tmode) >> 1) + 1)
+ <= GET_MODE_MASK (tmode)))
{
rtx inner = XEXP (XEXP (XEXP (op0, 0), 0), 0);
rtx add_const = XEXP (XEXP (op0, 0), 1);
XEXP (op0, 1));
op0 = gen_binary (PLUS, tmode,
- gen_lowpart_for_combine (tmode, inner),
+ gen_lowpart (tmode, inner),
new_const);
continue;
}
&& mode_width <= HOST_BITS_PER_WIDE_INT
&& (nonzero_bits (XEXP (op0, 0), mode)
& (((HOST_WIDE_INT) 1 << INTVAL (XEXP (op0, 1))) - 1)) == 0
- && (const_op == 0
- || (floor_log2 (const_op) + INTVAL (XEXP (op0, 1))
- < mode_width)))
+ && (((unsigned HOST_WIDE_INT) const_op
+ + (GET_CODE (op0) != LSHIFTRT
+ ? ((GET_MODE_MASK (mode) >> INTVAL (XEXP (op0, 1)) >> 1)
+ + 1)
+ : 0))
+ <= GET_MODE_MASK (mode) >> INTVAL (XEXP (op0, 1))))
{
/* If the shift was logical, then we must make the condition
unsigned. */
if (const_op == 0
&& (equality_comparison_p || sign_bit_comparison_p)
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
- && INTVAL (XEXP (op0, 1)) == mode_width - 1)
+ && (unsigned HOST_WIDE_INT) INTVAL (XEXP (op0, 1))
+ == mode_width - 1)
{
op0 = XEXP (op0, 0);
code = (code == NE || code == GT ? LT : GE);
/* Now make any compound operations involved in this comparison. Then,
check for an outmost SUBREG on OP0 that is not doing anything or is
- paradoxical. The latter case can only occur when it is known that the
- "extra" bits will be zero. Therefore, it is safe to remove the SUBREG.
- We can never remove a SUBREG for a non-equality comparison because the
- sign bit is in a different place in the underlying object. */
+ paradoxical. The latter transformation must only be performed when
+ it is known that the "extra" bits will be the same in op0 and op1 or
+ that they don't matter. There are three cases to consider:
+
+ 1. SUBREG_REG (op0) is a register. In this case the bits are don't
+ care bits and we can assume they have any convenient value. So
+ making the transformation is safe.
+
+ 2. SUBREG_REG (op0) is a memory and LOAD_EXTEND_OP is not defined.
+ In this case the upper bits of op0 are undefined. We should not make
+ the simplification in that case as we do not know the contents of
+ those bits.
+
+ 3. SUBREG_REG (op0) is a memory and LOAD_EXTEND_OP is defined and not
+ NIL. In that case we know those bits are zeros or ones. We must
+ also be sure that they are the same as the upper bits of op1.
+
+ We can never remove a SUBREG for a non-equality comparison because
+ the sign bit is in a different place in the underlying object. */
op0 = make_compound_operation (op0, op1 == const0_rtx ? COMPARE : SET);
op1 = make_compound_operation (op1, SET);
if (GET_CODE (op0) == SUBREG && subreg_lowpart_p (op0)
&& GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
&& GET_MODE_CLASS (GET_MODE (SUBREG_REG (op0))) == MODE_INT
- && (code == NE || code == EQ)
- && ((GET_MODE_SIZE (GET_MODE (op0))
- > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))))))
+ && (code == NE || code == EQ))
{
- op0 = SUBREG_REG (op0);
- op1 = gen_lowpart_for_combine (GET_MODE (op0), op1);
- }
+ if (GET_MODE_SIZE (GET_MODE (op0))
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))))
+ {
+ /* For paradoxical subregs, allow case 1 as above. Case 3 isn't
+ implemented. */
+ if (GET_CODE (SUBREG_REG (op0)) == REG)
+ {
+ op0 = SUBREG_REG (op0);
+ op1 = gen_lowpart (GET_MODE (op0), op1);
+ }
+ }
+ else if ((GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)))
+ <= HOST_BITS_PER_WIDE_INT)
+ && (nonzero_bits (SUBREG_REG (op0),
+ GET_MODE (SUBREG_REG (op0)))
+ & ~GET_MODE_MASK (GET_MODE (op0))) == 0)
+ {
+ tem = gen_lowpart (GET_MODE (SUBREG_REG (op0)), op1);
- else if (GET_CODE (op0) == SUBREG && subreg_lowpart_p (op0)
- && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
- && GET_MODE_CLASS (GET_MODE (SUBREG_REG (op0))) == MODE_INT
- && (code == NE || code == EQ)
- && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)))
- <= HOST_BITS_PER_WIDE_INT)
- && (nonzero_bits (SUBREG_REG (op0), GET_MODE (SUBREG_REG (op0)))
- & ~GET_MODE_MASK (GET_MODE (op0))) == 0
- && (tem = gen_lowpart_for_combine (GET_MODE (SUBREG_REG (op0)),
- op1),
- (nonzero_bits (tem, GET_MODE (SUBREG_REG (op0)))
- & ~GET_MODE_MASK (GET_MODE (op0))) == 0))
- op0 = SUBREG_REG (op0), op1 = tem;
+ if ((nonzero_bits (tem, GET_MODE (SUBREG_REG (op0)))
+ & ~GET_MODE_MASK (GET_MODE (op0))) == 0)
+ op0 = SUBREG_REG (op0), op1 = tem;
+ }
+ }
/* We now do the opposite procedure: Some machines don't have compare
insns in all modes. If OP0's mode is an integer mode smaller than a
tmode = GET_MODE_WIDER_MODE (tmode))
if (have_insn_for (COMPARE, tmode))
{
+ int zero_extended;
+
/* If the only nonzero bits in OP0 and OP1 are those in the
narrower mode and this is an equality or unsigned comparison,
we can use the wider mode. Similarly for sign-extended
values, in which case it is true for all comparisons. */
- if (((code == EQ || code == NE
- || code == GEU || code == GTU || code == LEU || code == LTU)
- && (nonzero_bits (op0, tmode) & ~GET_MODE_MASK (mode)) == 0
- && (nonzero_bits (op1, tmode) & ~GET_MODE_MASK (mode)) == 0)
+ zero_extended = ((code == EQ || code == NE
+ || code == GEU || code == GTU
+ || code == LEU || code == LTU)
+ && (nonzero_bits (op0, tmode)
+ & ~GET_MODE_MASK (mode)) == 0
+ && ((GET_CODE (op1) == CONST_INT
+ || (nonzero_bits (op1, tmode)
+ & ~GET_MODE_MASK (mode)) == 0)));
+
+ if (zero_extended
|| ((num_sign_bit_copies (op0, tmode)
- > GET_MODE_BITSIZE (tmode) - GET_MODE_BITSIZE (mode))
+ > (unsigned int) (GET_MODE_BITSIZE (tmode)
+ - GET_MODE_BITSIZE (mode)))
&& (num_sign_bit_copies (op1, tmode)
- > GET_MODE_BITSIZE (tmode) - GET_MODE_BITSIZE (mode))))
+ > (unsigned int) (GET_MODE_BITSIZE (tmode)
+ - GET_MODE_BITSIZE (mode)))))
{
/* If OP0 is an AND and we don't have an AND in MODE either,
make a new AND in the proper mode. */
if (GET_CODE (op0) == AND
&& !have_insn_for (AND, mode))
op0 = gen_binary (AND, tmode,
- gen_lowpart_for_combine (tmode,
- XEXP (op0, 0)),
- gen_lowpart_for_combine (tmode,
- XEXP (op0, 1)));
-
- op0 = gen_lowpart_for_combine (tmode, op0);
- op1 = gen_lowpart_for_combine (tmode, op1);
+ gen_lowpart (tmode,
+ XEXP (op0, 0)),
+ gen_lowpart (tmode,
+ XEXP (op0, 1)));
+
+ op0 = gen_lowpart (tmode, op0);
+ if (zero_extended && GET_CODE (op1) == CONST_INT)
+ op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (mode));
+ op1 = gen_lowpart (tmode, op1);
break;
}
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
{
op0 = gen_binary (AND, tmode,
- gen_lowpart_for_combine (tmode, op0),
+ gen_lowpart (tmode, op0),
GEN_INT ((HOST_WIDE_INT) 1
<< (GET_MODE_BITSIZE (mode) - 1)));
code = (code == LT) ? NE : EQ;
/* Like jump.c' reversed_comparison_code, but use combine infrastructure for
searching backward. */
static enum rtx_code
-combine_reversed_comparison_code (exp)
- rtx exp;
+combine_reversed_comparison_code (rtx exp)
{
enum rtx_code code1 = reversed_comparison_code (exp, NULL);
rtx x;
return reversed_comparison_code_parts (GET_CODE (exp),
XEXP (x, 0), XEXP (x, 1), NULL);
}
+
/* Return comparison with reversed code of EXP and operands OP0 and OP1.
Return NULL_RTX in case we fail to do the reversal. */
static rtx
-reversed_comparison (exp, mode, op0, op1)
- rtx exp, op0, op1;
- enum machine_mode mode;
+reversed_comparison (rtx exp, enum machine_mode mode, rtx op0, rtx op1)
{
enum rtx_code reversed_code = combine_reversed_comparison_code (exp);
if (reversed_code == UNKNOWN)
for each register mentioned. Similar to mention_regs in cse.c */
static void
-update_table_tick (x)
- rtx x;
+update_table_tick (rtx x)
{
enum rtx_code code = GET_CODE (x);
const char *fmt = GET_RTX_FORMAT (code);
unsigned int regno = REGNO (x);
unsigned int endregno
= regno + (regno < FIRST_PSEUDO_REGISTER
- ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
+ ? hard_regno_nregs[regno][GET_MODE (x)] : 1);
unsigned int r;
for (r = regno; r < endregno; r++)
/* Note that we can't have an "E" in values stored; see
get_last_value_validate. */
if (fmt[i] == 'e')
- update_table_tick (XEXP (x, i));
+ {
+ /* Check for identical subexpressions. If x contains
+ identical subexpression we only have to traverse one of
+ them. */
+ if (i == 0 && ARITHMETIC_P (x))
+ {
+ /* Note that at this point x1 has already been
+ processed. */
+ rtx x0 = XEXP (x, 0);
+ rtx x1 = XEXP (x, 1);
+
+ /* If x0 and x1 are identical then there is no need to
+ process x0. */
+ if (x0 == x1)
+ break;
+
+ /* If x0 is identical to a subexpression of x1 then while
+ processing x1, x0 has already been processed. Thus we
+ are done with x. */
+ if (ARITHMETIC_P (x1)
+ && (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1)))
+ break;
+
+ /* If x1 is identical to a subexpression of x0 then we
+ still have to process the rest of x0. */
+ if (ARITHMETIC_P (x0)
+ && (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1)))
+ {
+ update_table_tick (XEXP (x0, x1 == XEXP (x0, 0) ? 1 : 0));
+ break;
+ }
+ }
+
+ update_table_tick (XEXP (x, i));
+ }
}
/* Record that REG is set to VALUE in insn INSN. If VALUE is zero, we
with VALUE also zero and is used to invalidate the register. */
static void
-record_value_for_reg (reg, insn, value)
- rtx reg;
- rtx insn;
- rtx value;
+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);
+ ? hard_regno_nregs[regno][GET_MODE (reg)] : 1);
unsigned int i;
/* If VALUE contains REG and we have a previous value for REG, substitute
if (tem)
{
- if ((GET_RTX_CLASS (GET_CODE (tem)) == '2'
- || GET_RTX_CLASS (GET_CODE (tem)) == 'c')
+ if (ARITHMETIC_P (tem)
&& GET_CODE (XEXP (tem, 0)) == CLOBBER
&& GET_CODE (XEXP (tem, 1)) == CLOBBER)
tem = XEXP (tem, 0);
if (value)
{
+ enum machine_mode mode = GET_MODE (reg);
subst_low_cuid = INSN_CUID (insn);
- reg_last_set_mode[regno] = GET_MODE (reg);
- reg_last_set_nonzero_bits[regno] = nonzero_bits (value, GET_MODE (reg));
+ reg_last_set_mode[regno] = mode;
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+ mode = nonzero_bits_mode;
+ reg_last_set_nonzero_bits[regno] = nonzero_bits (value, mode);
reg_last_set_sign_bit_copies[regno]
= num_sign_bit_copies (value, GET_MODE (reg));
}
set is occurring. */
static void
-record_dead_and_set_regs_1 (dest, setter, data)
- rtx dest, setter;
- void *data;
+record_dead_and_set_regs_1 (rtx dest, rtx setter, void *data)
{
rtx record_dead_insn = (rtx) data;
&& GET_MODE_BITSIZE (GET_MODE (dest)) <= BITS_PER_WORD
&& subreg_lowpart_p (SET_DEST (setter)))
record_value_for_reg (dest, record_dead_insn,
- gen_lowpart_for_combine (GET_MODE (dest),
+ gen_lowpart (GET_MODE (dest),
SET_SRC (setter)));
else
record_value_for_reg (dest, record_dead_insn, NULL_RTX);
subroutine call). */
static void
-record_dead_and_set_regs (insn)
- rtx insn;
+record_dead_and_set_regs (rtx insn)
{
rtx link;
unsigned int i;
unsigned int regno = REGNO (XEXP (link, 0));
unsigned int endregno
= regno + (regno < FIRST_PSEUDO_REGISTER
- ? HARD_REGNO_NREGS (regno, GET_MODE (XEXP (link, 0)))
+ ? hard_regno_nregs[regno][GET_MODE (XEXP (link, 0))]
: 1);
for (i = regno; i < endregno; i++)
missed because of that. */
static void
-record_promoted_value (insn, subreg)
- rtx insn;
- rtx subreg;
+record_promoted_value (rtx insn, rtx subreg)
{
rtx links, set;
unsigned int regno = REGNO (SUBREG_REG (subreg));
note what it implies to the registers used in it. */
static void
-check_promoted_subreg (insn, x)
- rtx insn;
- rtx x;
+check_promoted_subreg (rtx insn, rtx x)
{
if (GET_CODE (x) == SUBREG && SUBREG_PROMOTED_VAR_P (x)
&& GET_CODE (SUBREG_REG (x)) == REG)
mentioned in *LOC are valid when *LOC was part of a value set when
label_tick == TICK. Return 0 if some are not.
- If REPLACE is non-zero, replace the invalid reference with
+ If REPLACE is nonzero, replace the invalid reference with
(clobber (const_int 0)) and return 1. This replacement is useful because
we often can get useful information about the form of a value (e.g., if
it was produced by a shift that always produces -1 or 0) even though
we don't know exactly what registers it was produced from. */
static int
-get_last_value_validate (loc, insn, tick, replace)
- rtx *loc;
- rtx insn;
- int tick;
- int replace;
+get_last_value_validate (rtx *loc, rtx insn, int tick, int replace)
{
rtx x = *loc;
const char *fmt = GET_RTX_FORMAT (GET_CODE (x));
unsigned int regno = REGNO (x);
unsigned int endregno
= regno + (regno < FIRST_PSEUDO_REGISTER
- ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
+ ? hard_regno_nregs[regno][GET_MODE (x)] : 1);
unsigned int j;
for (j = regno; j < endregno; j++)
|| (! (regno >= FIRST_PSEUDO_REGISTER
&& REG_N_SETS (regno) == 1
&& (! REGNO_REG_SET_P
- (BASIC_BLOCK (0)->global_live_at_start, regno)))
+ (ENTRY_BLOCK_PTR->next_bb->global_live_at_start, regno)))
&& reg_last_set_label[j] > tick))
{
if (replace)
}
for (i = 0; i < len; i++)
- if ((fmt[i] == 'e'
- && get_last_value_validate (&XEXP (x, i), insn, tick, replace) == 0)
- /* Don't bother with these. They shouldn't occur anyway. */
- || fmt[i] == 'E')
- return 0;
+ {
+ if (fmt[i] == 'e')
+ {
+ /* Check for identical subexpressions. If x contains
+ identical subexpression we only have to traverse one of
+ them. */
+ if (i == 1 && ARITHMETIC_P (x))
+ {
+ /* Note that at this point x0 has already been checked
+ and found valid. */
+ rtx x0 = XEXP (x, 0);
+ rtx x1 = XEXP (x, 1);
+
+ /* If x0 and x1 are identical then x is also valid. */
+ if (x0 == x1)
+ return 1;
+
+ /* If x1 is identical to a subexpression of x0 then
+ while checking x0, x1 has already been checked. Thus
+ it is valid and so as x. */
+ if (ARITHMETIC_P (x0)
+ && (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1)))
+ return 1;
+
+ /* If x0 is identical to a subexpression of x1 then x is
+ valid iff the rest of x1 is valid. */
+ if (ARITHMETIC_P (x1)
+ && (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1)))
+ return
+ get_last_value_validate (&XEXP (x1,
+ x0 == XEXP (x1, 0) ? 1 : 0),
+ insn, tick, replace);
+ }
+
+ if (get_last_value_validate (&XEXP (x, i), insn, tick,
+ replace) == 0)
+ return 0;
+ }
+ /* Don't bother with these. They shouldn't occur anyway. */
+ else if (fmt[i] == 'E')
+ return 0;
+ }
/* If we haven't found a reason for it to be invalid, it is valid. */
return 1;
is known longer known reliably. */
static rtx
-get_last_value (x)
- rtx x;
+get_last_value (rtx x)
{
unsigned int regno;
rtx value;
&& (GET_MODE_SIZE (GET_MODE (x))
<= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
&& (value = get_last_value (SUBREG_REG (x))) != 0)
- return gen_lowpart_for_combine (GET_MODE (x), value);
+ return gen_lowpart (GET_MODE (x), value);
if (GET_CODE (x) != REG)
return 0;
&& (regno < FIRST_PSEUDO_REGISTER
|| REG_N_SETS (regno) != 1
|| (REGNO_REG_SET_P
- (BASIC_BLOCK (0)->global_live_at_start, regno)))))
+ (ENTRY_BLOCK_PTR->next_bb->global_live_at_start, regno)))))
return 0;
/* If the value was set in a later insn than the ones we are processing,
that is set in an instruction more recent than FROM_CUID. */
static int
-use_crosses_set_p (x, from_cuid)
- rtx x;
- int from_cuid;
+use_crosses_set_p (rtx x, int from_cuid)
{
const char *fmt;
int i;
{
unsigned int regno = REGNO (x);
unsigned endreg = regno + (regno < FIRST_PSEUDO_REGISTER
- ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
+ ? hard_regno_nregs[regno][GET_MODE (x)] : 1);
#ifdef PUSH_ROUNDING
/* Don't allow uses of the stack pointer to be moved,
reg_dead_flag to 1 if X is a CLOBBER and to -1 it is a SET. */
static void
-reg_dead_at_p_1 (dest, x, data)
- rtx dest;
- rtx x;
- void *data ATTRIBUTE_UNUSED;
+reg_dead_at_p_1 (rtx dest, rtx x, void *data ATTRIBUTE_UNUSED)
{
unsigned int regno, endregno;
regno = REGNO (dest);
endregno = regno + (regno < FIRST_PSEUDO_REGISTER
- ? HARD_REGNO_NREGS (regno, GET_MODE (dest)) : 1);
+ ? hard_regno_nregs[regno][GET_MODE (dest)] : 1);
if (reg_dead_endregno > regno && reg_dead_regno < endregno)
reg_dead_flag = (GET_CODE (x) == CLOBBER) ? 1 : -1;
}
-/* Return non-zero if REG is known to be dead at INSN.
+/* Return nonzero if REG is known to be dead at INSN.
We scan backwards from INSN. If we hit a REG_DEAD note or a CLOBBER
referencing REG, it is dead. If we hit a SET referencing REG, it is
must be assumed to be always live. */
static int
-reg_dead_at_p (reg, insn)
- rtx reg;
- rtx insn;
+reg_dead_at_p (rtx reg, rtx insn)
{
- int block;
+ basic_block block;
unsigned int i;
/* 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))
+ ? hard_regno_nregs[reg_dead_regno]
+ [GET_MODE (reg)]
: 1);
reg_dead_flag = 0;
return 1;
}
- /* Get the basic block number that we were in. */
+ /* Get the basic block that we were in. */
if (insn == 0)
- block = 0;
+ block = ENTRY_BLOCK_PTR->next_bb;
else
{
- for (block = 0; block < n_basic_blocks; block++)
- if (insn == BLOCK_HEAD (block))
+ FOR_EACH_BB (block)
+ if (insn == BB_HEAD (block))
break;
- if (block == n_basic_blocks)
+ if (block == EXIT_BLOCK_PTR)
return 0;
}
for (i = reg_dead_regno; i < reg_dead_endregno; i++)
- if (REGNO_REG_SET_P (BASIC_BLOCK (block)->global_live_at_start, i))
+ if (REGNO_REG_SET_P (block->global_live_at_start, i))
return 0;
return 1;
that in flow.c, but much simpler since we don't care about pseudos. */
static void
-mark_used_regs_combine (x)
- rtx x;
+mark_used_regs_combine (rtx x)
{
RTX_CODE code = GET_CODE (x);
unsigned int regno;
{
unsigned int endregno, r;
- /* None of this applies to the stack, frame or arg pointers */
+ /* 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 == HARD_FRAME_POINTER_REGNUM
|| regno == FRAME_POINTER_REGNUM)
return;
- endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
+ endregno = regno + hard_regno_nregs[regno][GET_MODE (x)];
for (r = regno; r < endregno; r++)
SET_HARD_REG_BIT (newpat_used_regs, r);
}
Return the note used to record the death, if there was one. */
rtx
-remove_death (regno, insn)
- unsigned int regno;
- rtx insn;
+remove_death (unsigned int regno, rtx insn)
{
rtx note = find_regno_note (insn, REG_DEAD, regno);
notes will then be distributed as needed. */
static void
-move_deaths (x, maybe_kill_insn, from_cuid, to_insn, pnotes)
- rtx x;
- rtx maybe_kill_insn;
- int from_cuid;
- rtx to_insn;
- rtx *pnotes;
+move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn,
+ rtx *pnotes)
{
const char *fmt;
int len, i;
rtx where_dead = reg_last_death[regno];
rtx before_dead, after_dead;
- /* Don't move the register if it gets killed in between from and to */
+ /* Don't move the register if it gets killed in between from and to. */
if (maybe_kill_insn && reg_set_p (x, maybe_kill_insn)
&& ! reg_referenced_p (x, maybe_kill_insn))
return;
{
unsigned int deadregno = REGNO (XEXP (note, 0));
unsigned int deadend
- = (deadregno + HARD_REGNO_NREGS (deadregno,
- GET_MODE (XEXP (note, 0))));
+ = (deadregno + hard_regno_nregs[deadregno]
+ [GET_MODE (XEXP (note, 0))]);
unsigned int ourend
- = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
+ = regno + hard_regno_nregs[regno][GET_MODE (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,
- gen_rtx_REG (reg_raw_mode[i], i),
+ regno_reg_rtx[i],
REG_NOTES (where_dead));
}
&& (GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
< GET_MODE_SIZE (GET_MODE (x)))))
&& regno < FIRST_PSEUDO_REGISTER
- && HARD_REGNO_NREGS (regno, GET_MODE (x)) > 1)
+ && hard_regno_nregs[regno][GET_MODE (x)] > 1)
{
unsigned int ourend
- = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
+ = regno + hard_regno_nregs[regno][GET_MODE (x)];
unsigned int i, offset;
rtx oldnotes = 0;
if (note)
- offset = HARD_REGNO_NREGS (regno, GET_MODE (XEXP (note, 0)));
+ offset = hard_regno_nregs[regno][GET_MODE (XEXP (note, 0))];
else
offset = 1;
for (i = regno + offset; i < ourend; i++)
- move_deaths (gen_rtx_REG (reg_raw_mode[i], i),
+ move_deaths (regno_reg_rtx[i],
maybe_kill_insn, from_cuid, to_insn, &oldnotes);
}
pattern of an insn. X must be a REG. */
static int
-reg_bitfield_target_p (x, body)
- rtx x;
- rtx body;
+reg_bitfield_target_p (rtx x, rtx body)
{
int i;
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 = tregno + hard_regno_nregs[tregno][GET_MODE (target)];
+ endregno = regno + hard_regno_nregs[regno][GET_MODE (x)];
return endregno > tregno && regno < endtregno;
}
as appropriate. I3 and I2 are the insns resulting from the combination
insns including FROM (I2 may be zero).
- ELIM_I2 and ELIM_I1 are either zero or registers that we know will
- not need REG_DEAD notes because they are being substituted for. This
- saves searching in the most common cases.
-
Each note in the list is either ignored or placed on some insns, depending
on the type of note. */
static void
-distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
- rtx notes;
- rtx from_insn;
- rtx i3, i2;
- rtx elim_i2, elim_i1;
+distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
{
rtx note, next_note;
rtx tem;
{
case REG_BR_PROB:
case REG_BR_PRED:
- case REG_EXEC_COUNT:
/* Doesn't matter much where we put this, as long as it's somewhere.
It is preferable to keep these notes on branches, which is most
likely to be i3. */
place = i3;
break;
+ case REG_VALUE_PROFILE:
+ /* Just get rid of this note, as it is unused later anyway. */
+ break;
+
case REG_VTABLE_REF:
/* ??? Should remain with *a particular* memory load. Given the
nature of vtable data, the last insn seems relatively safe. */
abort ();
break;
+ case REG_ALWAYS_RETURN:
case REG_NORETURN:
case REG_SETJMP:
/* These notes must remain with the call. It should not be
break;
case REG_NONNEG:
- case REG_WAS_0:
- /* These notes say something about the value of a register prior
+ /* This note says something about the value of a register prior
to the execution of an insn. It is too much trouble to see
if the note is still correct in all situations. It is better
to simply delete it. */
case REG_DEAD:
/* If the register is used as an input in I3, it dies there.
- Similarly for I2, if it is non-zero and adjacent to I3.
+ 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
and it is not one of the registers we were supposed to eliminate,
&& reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
place = i2;
- if (rtx_equal_p (XEXP (note, 0), elim_i2)
- || rtx_equal_p (XEXP (note, 0), elim_i1))
- break;
-
if (place == 0)
{
- basic_block bb = BASIC_BLOCK (this_basic_block);
+ basic_block bb = this_basic_block;
for (tem = PREV_INSN (i3); place == 0; tem = PREV_INSN (tem))
{
if (! INSN_P (tem))
{
- if (tem == bb->head)
+ if (tem == BB_HEAD (bb))
break;
continue;
}
This might delete other dead insns recursively.
First set the pattern to something that won't use
any register. */
+ rtx old_notes = REG_NOTES (tem);
PATTERN (tem) = pc_rtx;
+ REG_NOTES (tem) = NULL;
- distribute_notes (REG_NOTES (tem), tem, tem,
- NULL_RTX, NULL_RTX, NULL_RTX);
+ distribute_notes (old_notes, tem, tem, NULL_RTX);
distribute_links (LOG_LINKS (tem));
PUT_CODE (tem, NOTE);
if (cc0_setter)
{
PATTERN (cc0_setter) = pc_rtx;
+ old_notes = REG_NOTES (cc0_setter);
+ REG_NOTES (cc0_setter) = NULL;
- distribute_notes (REG_NOTES (cc0_setter),
- cc0_setter, cc0_setter,
- NULL_RTX, NULL_RTX, NULL_RTX);
+ distribute_notes (old_notes, cc0_setter,
+ cc0_setter, NULL_RTX);
distribute_links (LOG_LINKS (cc0_setter));
PUT_CODE (cc0_setter, NOTE);
}
#endif
}
- /* If the register is both set and used here, put the
- REG_DEAD note here, but place a REG_UNUSED note
- here too unless there already is one. */
- else if (reg_referenced_p (XEXP (note, 0),
- PATTERN (tem)))
- {
- place = tem;
-
- if (! find_regno_note (tem, REG_UNUSED,
- REGNO (XEXP (note, 0))))
- REG_NOTES (tem)
- = gen_rtx_EXPR_LIST (REG_UNUSED, XEXP (note, 0),
- REG_NOTES (tem));
- }
else
{
PUT_REG_NOTE_KIND (note, REG_UNUSED);
/* If there isn't already a REG_UNUSED note, put one
- here. */
+ here. Do not place a REG_DEAD note, even if
+ the register is also used here; that would not
+ match the algorithm used in lifetime analysis
+ and can cause the consistency check in the
+ scheduler to fail. */
if (! find_regno_note (tem, REG_UNUSED,
REGNO (XEXP (note, 0))))
place = tem;
break;
}
- if (tem == bb->head)
+ if (tem == BB_HEAD (bb))
break;
}
if (REG_NOTE_KIND (note) == REG_DEAD && place == 0
&& REGNO_REG_SET_P (bb->global_live_at_start,
REGNO (XEXP (note, 0))))
- {
- SET_BIT (refresh_blocks, this_basic_block);
- need_refresh = 1;
- }
+ SET_BIT (refresh_blocks, this_basic_block->index);
}
/* If the register is set or already dead at PLACE, we needn't do
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);
- need_refresh = 1;
- }
+ SET_BIT (refresh_blocks, this_basic_block->index);
if (dead_or_set_p (place, XEXP (note, 0))
|| reg_bitfield_target_p (XEXP (note, 0), PATTERN (place)))
the previous insn that used this register. */
if (place && regno < FIRST_PSEUDO_REGISTER
- && HARD_REGNO_NREGS (regno, GET_MODE (XEXP (note, 0))) > 1)
+ && hard_regno_nregs[regno][GET_MODE (XEXP (note, 0))] > 1)
{
unsigned int endregno
- = regno + HARD_REGNO_NREGS (regno,
- GET_MODE (XEXP (note, 0)));
+ = regno + hard_regno_nregs[regno]
+ [GET_MODE (XEXP (note, 0))];
int all_used = 1;
unsigned int i;
not already dead or set. */
for (i = regno; i < endregno;
- i += HARD_REGNO_NREGS (i, reg_raw_mode[i]))
+ i += hard_regno_nregs[i][reg_raw_mode[i]])
{
- rtx piece = gen_rtx_REG (reg_raw_mode[i], i);
- basic_block bb = BASIC_BLOCK (this_basic_block);
+ rtx piece = regno_reg_rtx[i];
+ basic_block bb = this_basic_block;
if (! dead_or_set_p (place, piece)
&& ! reg_bitfield_target_p (piece,
= gen_rtx_EXPR_LIST (REG_DEAD, piece, NULL_RTX);
distribute_notes (new_note, place, place,
- NULL_RTX, NULL_RTX, NULL_RTX);
+ NULL_RTX);
}
else if (! refers_to_regno_p (i, i + 1,
PATTERN (place), 0)
{
if (! INSN_P (tem))
{
- if (tem == bb->head)
+ if (tem == BB_HEAD (bb))
{
SET_BIT (refresh_blocks,
- this_basic_block);
- need_refresh = 1;
+ this_basic_block->index);
break;
}
continue;
}
\f
/* Similarly to above, distribute the LOG_LINKS that used to be present on
- I3, I2, and I1 to new locations. This is also called in one case to
- add a link pointing at I3 when I3's destination is changed. */
+ I3, I2, and I1 to new locations. This is also called to add a link
+ pointing at I3 when I3's destination is changed. */
static void
-distribute_links (links)
- rtx links;
+distribute_links (rtx links)
{
rtx link, next_link;
since most links don't point very far away. */
for (insn = NEXT_INSN (XEXP (link, 0));
- (insn && (this_basic_block == n_basic_blocks - 1
- || BLOCK_HEAD (this_basic_block + 1) != insn));
+ (insn && (this_basic_block->next_bb == EXIT_BLOCK_PTR
+ || BB_HEAD (this_basic_block->next_bb) != insn));
insn = NEXT_INSN (insn))
if (INSN_P (insn) && reg_overlap_mentioned_p (reg, PATTERN (insn)))
{
place = insn;
break;
}
+ else if (INSN_P (insn) && reg_set_p (reg, insn))
+ break;
/* If we found a place to put the link, place it there unless there
is already a link to the same insn as LINK at that point. */
}
}
\f
+/* Subroutine of unmentioned_reg_p and callback from for_each_rtx.
+ Check whether the expression pointer to by LOC is a register or
+ memory, and if so return 1 if it isn't mentioned in the rtx EXPR.
+ Otherwise return zero. */
+
+static int
+unmentioned_reg_p_1 (rtx *loc, void *expr)
+{
+ rtx x = *loc;
+
+ if (x != NULL_RTX
+ && (GET_CODE (x) == REG || GET_CODE (x) == MEM)
+ && ! reg_mentioned_p (x, (rtx) expr))
+ return 1;
+ return 0;
+}
+
+/* Check for any register or memory mentioned in EQUIV that is not
+ mentioned in EXPR. This is used to restrict EQUIV to "specializations"
+ of EXPR where some registers may have been replaced by constants. */
+
+static bool
+unmentioned_reg_p (rtx equiv, rtx expr)
+{
+ 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 (insn)
- rtx insn;
+insn_cuid (rtx insn)
{
while (insn != 0 && INSN_UID (insn) > max_uid_cuid
&& GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == USE)
}
\f
void
-dump_combine_stats (file)
- FILE *file;
+dump_combine_stats (FILE *file)
{
fnotice
(file,
}
void
-dump_combine_total_stats (file)
- FILE *file;
+dump_combine_total_stats (FILE *file)
{
fnotice
(file,