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
static int n_occurrences;
-static void do_SUBST PARAMS ((rtx *, rtx));
-static void do_SUBST_INT PARAMS ((int *, int));
-static void init_reg_last_arrays PARAMS ((void));
-static void setup_incoming_promotions PARAMS ((void));
-static void set_nonzero_bits_and_sign_copies PARAMS ((rtx, rtx, void *));
-static int 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 cached_nonzero_bits
- PARAMS ((rtx, enum machine_mode, rtx,
- enum machine_mode,
- unsigned HOST_WIDE_INT));
-static unsigned HOST_WIDE_INT nonzero_bits1
- PARAMS ((rtx, enum machine_mode, rtx,
- enum machine_mode,
- unsigned HOST_WIDE_INT));
-static unsigned int cached_num_sign_bit_copies
- PARAMS ((rtx, enum machine_mode, rtx,
- enum machine_mode, unsigned int));
-static unsigned int num_sign_bit_copies1
- PARAMS ((rtx, enum machine_mode, rtx,
- enum machine_mode, unsigned int));
-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 sets_function_arg_p (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, int);
+static rtx simplify_if_then_else (rtx);
+static rtx simplify_set (rtx);
+static rtx simplify_logical (rtx, int);
+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);
\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;
not safe. */
static void
-do_SUBST_INT (into, newval)
- int *into, newval;
+do_SUBST_INT (int *into, int newval)
{
struct undo *buf;
int oldval = *into;
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
/* 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;
/* 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;
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;
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;
argument for a function in a hard register. */
static int
-sets_function_arg_p (pat)
- rtx pat;
+sets_function_arg_p (rtx pat)
{
int i;
rtx inner_dest;
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;
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))
{
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;
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;
as I2 will not cause a problem. */
i1 = gen_rtx_INSN (VOIDmode, INSN_UID (i2), NULL_RTX, i2,
- BLOCK_FOR_INSN (i2), INSN_SCOPE (i2),
+ BLOCK_FOR_INSN (i2), INSN_LOCATOR (i2),
XVECEXP (PATTERN (i2), 0, 1), -1, NULL_RTX,
NULL_RTX);
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
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. */
/* 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);
/* Undo all the modifications recorded in undobuf. */
static void
-undo_all ()
+undo_all (void)
{
struct undo *undo, *next;
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);
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;
X is returned; 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 last,
+ int in_dest)
{
enum rtx_code code = GET_CODE (x);
enum machine_mode mode = GET_MODE (x);
x = gen_binary (cond_code, mode, cond, cop1);
else if (true_rtx == const0_rtx && false_rtx == const_true_rtx
&& ((reversed = reversed_comparison_code_parts
- (cond_code, cond, cop1, NULL))
+ (cond_code, cond, cop1, NULL))
!= UNKNOWN))
x = gen_binary (reversed, mode, cond, cop1);
&& INTVAL (false_rtx) == - STORE_FLAG_VALUE
&& true_rtx == const0_rtx
&& ((reversed = reversed_comparison_code_parts
- (cond_code, cond, cop1, NULL))
+ (cond_code, cond, cop1, NULL))
!= UNKNOWN))
x = simplify_gen_unary (NEG, mode,
gen_binary (reversed, mode,
- cond, cop1),
+ cond, cop1),
mode);
else
return gen_rtx_IF_THEN_ELSE (mode,
&& 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)
+ 0)))
+ > GET_MODE_SIZE (mode)
? FLOAT_TRUNCATE : FLOAT_EXTEND,
- mode,
+ mode,
XEXP (XEXP (x, 0), 0), mode);
/* (float_truncate (float x)) is (float x) */
/* 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);
simplify_shift_const (NULL_RTX, ASHIFT, mode,
gen_lowpart_for_combine (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
+ && (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;
}
\f
/* 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);
SUBST (SET_SRC (x), src);
}
+#ifdef WORD_REGISTER_OPERATIONS
/* If we have (set x (subreg:m1 (op:m2 ...) 0)) with OP being some operation,
and X being a REG or (subreg (reg)), we may be able to convert this to
(set (subreg:m2 x) (op)).
- We can always do this if M1 is narrower than M2 because that means that
- we only care about the low bits of the result.
+ On a machine where WORD_REGISTER_OPERATIONS is defined, this
+ transformation is safe as long as M1 and M2 have the same number
+ of words.
- However, on machines without WORD_REGISTER_OPERATIONS defined, we cannot
- perform a narrower operation than requested since the high-order bits will
- be undefined. On machine where it is defined, this transformation is safe
- as long as M1 and M2 have the same number of words. */
+ However, on a machine without WORD_REGISTER_OPERATIONS defined,
+ we cannot apply this transformation because it would create a
+ paradoxical subreg in SET_DEST. */
if (GET_CODE (src) == SUBREG && subreg_lowpart_p (src)
&& GET_RTX_CLASS (GET_CODE (SUBREG_REG (src))) != 'o'
/ 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))))
-#endif
#ifdef CANNOT_CHANGE_MODE_CLASS
&& ! (GET_CODE (dest) == REG && REGNO (dest) < FIRST_PSEUDO_REGISTER
&& REG_CANNOT_CHANGE_MODE_P (REGNO (dest),
src = SET_SRC (x), dest = SET_DEST (x);
}
+#endif
#ifdef HAVE_cc0
/* If we have (set (cc0) (subreg ...)), we try to remove the subreg
result. LAST is nonzero if this is the last retry. */
static rtx
-simplify_logical (x, last)
- rtx x;
- int last;
+simplify_logical (rtx x, int last)
{
enum machine_mode mode = GET_MODE (x);
rtx op0 = XEXP (x, 0);
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;
== 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. */
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. */
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
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);
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);
*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);
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;
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);
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;
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;
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);
if so. */
static rtx
-apply_distributive_law (x)
- rtx x;
+apply_distributive_law (rtx x)
{
enum rtx_code code = GET_CODE (x);
rtx lhs, rhs, other;
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;
identical subexpressions on the first or the second level. */
static unsigned HOST_WIDE_INT
-cached_nonzero_bits (x, mode, known_x, known_mode, known_ret)
- rtx x;
- enum machine_mode mode;
- rtx known_x;
- enum machine_mode known_mode;
- unsigned HOST_WIDE_INT known_ret;
+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;
a shift, AND, or zero_extract, we can do better. */
static unsigned HOST_WIDE_INT
-nonzero_bits1 (x, mode, known_x, known_mode, known_ret)
- rtx x;
- enum machine_mode mode;
- rtx known_x;
- enum machine_mode known_mode;
- unsigned HOST_WIDE_INT known_ret;
+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;
first or the second level. */
static unsigned int
-cached_num_sign_bit_copies (x, mode, known_x, known_mode, known_ret)
- rtx x;
- enum machine_mode mode;
- rtx known_x;
- enum machine_mode known_mode;
- unsigned int known_ret;
+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;
be between 1 and the number of bits in MODE. */
static unsigned int
-num_sign_bit_copies1 (x, mode, known_x, known_mode, known_ret)
- rtx x;
- enum machine_mode mode;
- rtx known_x;
- enum machine_mode known_mode;
- unsigned int known_ret;
+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;
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 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:
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;
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;
#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. */
{
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)
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;
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;
/* 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 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);
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
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;
subroutine call). */
static void
-record_dead_and_set_regs (insn)
- rtx insn;
+record_dead_and_set_regs (rtx insn)
{
rtx link;
unsigned int 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)
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));
is known longer known reliably. */
static rtx
-get_last_value (x)
- rtx x;
+get_last_value (rtx x)
{
unsigned int regno;
rtx value;
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;
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;
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)
{
basic_block block;
unsigned int i;
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;
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;
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;
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;
&& 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 = this_basic_block;
PATTERN (tem) = pc_rtx;
distribute_notes (REG_NOTES (tem), tem, tem,
- NULL_RTX, NULL_RTX, NULL_RTX);
+ NULL_RTX);
distribute_links (LOG_LINKS (tem));
PUT_CODE (tem, NOTE);
distribute_notes (REG_NOTES (cc0_setter),
cc0_setter, cc0_setter,
- NULL_RTX, NULL_RTX, NULL_RTX);
+ NULL_RTX);
distribute_links (LOG_LINKS (cc0_setter));
PUT_CODE (cc0_setter, NOTE);
= 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)
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;
/* 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,