#include "config.h"
#include "system.h"
#include "rtl.h"
#include "flags.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "basic-block.h"
#include "insn-config.h"
#include "expr.h"
#include "insn-flags.h"
#include "insn-codes.h"
#include "insn-attr.h"
#include "recog.h"
#include "real.h"
#include "toplev.h"
#define gen_lowpart dont_use_gen_lowpart_you_dummy
static int combine_attempts;
static int combine_merges;
static int combine_extras;
static int combine_successes;
static int total_attempts, total_merges, total_extras, total_successes;
#ifndef REVERSIBLE_CC_MODE
#define REVERSIBLE_CC_MODE(MODE) 0
#endif
static int *uid_cuid;
static int max_uid_cuid;
#define INSN_CUID(INSN) \
(INSN_UID (INSN) > max_uid_cuid ? insn_cuid (INSN) : uid_cuid[INSN_UID (INSN)])
static int combine_max_regno;
static rtx *reg_last_death;
static rtx *reg_last_set;
static int mem_last_set;
static int last_call_cuid;
static rtx subst_insn;
static rtx subst_prev_insn;
static int subst_low_cuid;
static HARD_REG_SET newpat_used_regs;
static rtx added_links_insn;
static int this_basic_block;
static rtx *reg_last_set_value;
static int *reg_last_set_label;
static int *reg_last_set_table_tick;
static char *reg_last_set_invalid;
static int label_tick;
static unsigned HOST_WIDE_INT *reg_nonzero_bits;
static enum machine_mode nonzero_bits_mode;
static char *reg_sign_bit_copies;
static int nonzero_sign_valid;
static enum machine_mode *reg_last_set_mode;
static unsigned HOST_WIDE_INT *reg_last_set_nonzero_bits;
static char *reg_last_set_sign_bit_copies;
struct undo
{
struct undo *next;
int is_int;
union {rtx r; int i;} old_contents;
union {rtx *r; int *i;} where;
};
struct undobuf
{
char *storage;
struct undo *undos;
struct undo *frees;
struct undo *previous_undos;
rtx other_insn;
};
static struct undobuf undobuf;
#define SUBST(INTO, NEWVAL) \
do { rtx _new = (NEWVAL); \
struct undo *_buf; \
\
if (undobuf.frees) \
_buf = undobuf.frees, undobuf.frees = _buf->next; \
else \
_buf = (struct undo *) xmalloc (sizeof (struct undo)); \
\
_buf->is_int = 0; \
_buf->where.r = &INTO; \
_buf->old_contents.r = INTO; \
INTO = _new; \
if (_buf->old_contents.r == INTO) \
_buf->next = undobuf.frees, undobuf.frees = _buf; \
else \
_buf->next = undobuf.undos, undobuf.undos = _buf; \
} while (0)
#define SUBST_INT(INTO, NEWVAL) \
do { struct undo *_buf; \
\
if (undobuf.frees) \
_buf = undobuf.frees, undobuf.frees = _buf->next; \
else \
_buf = (struct undo *) xmalloc (sizeof (struct undo)); \
\
_buf->is_int = 1; \
_buf->where.i = (int *) &INTO; \
_buf->old_contents.i = INTO; \
INTO = NEWVAL; \
if (_buf->old_contents.i == INTO) \
_buf->next = undobuf.frees, undobuf.frees = _buf; \
else \
_buf->next = undobuf.undos, undobuf.undos = _buf; \
} while (0)
static int n_occurrences;
static void init_reg_last_arrays PROTO((void));
static void setup_incoming_promotions PROTO((void));
static void set_nonzero_bits_and_sign_copies PROTO((rtx, rtx));
static int can_combine_p PROTO((rtx, rtx, rtx, rtx, rtx *, rtx *));
static int sets_function_arg_p PROTO((rtx));
static int combinable_i3pat PROTO((rtx, rtx *, rtx, rtx, int, rtx *));
static rtx try_combine PROTO((rtx, rtx, rtx));
static void undo_all PROTO((void));
static rtx *find_split_point PROTO((rtx *, rtx));
static rtx subst PROTO((rtx, rtx, rtx, int, int));
static rtx simplify_rtx PROTO((rtx, enum machine_mode, int, int));
static rtx simplify_if_then_else PROTO((rtx));
static rtx simplify_set PROTO((rtx));
static rtx simplify_logical PROTO((rtx, int));
static rtx expand_compound_operation PROTO((rtx));
static rtx expand_field_assignment PROTO((rtx));
static rtx make_extraction PROTO((enum machine_mode, rtx, int, rtx, int,
int, int, int));
static rtx extract_left_shift PROTO((rtx, int));
static rtx make_compound_operation PROTO((rtx, enum rtx_code));
static int get_pos_from_mask PROTO((unsigned HOST_WIDE_INT, int *));
static rtx force_to_mode PROTO((rtx, enum machine_mode,
unsigned HOST_WIDE_INT, rtx, int));
static rtx if_then_else_cond PROTO((rtx, rtx *, rtx *));
static rtx known_cond PROTO((rtx, enum rtx_code, rtx, rtx));
static int rtx_equal_for_field_assignment_p PROTO((rtx, rtx));
static rtx make_field_assignment PROTO((rtx));
static rtx apply_distributive_law PROTO((rtx));
static rtx simplify_and_const_int PROTO((rtx, enum machine_mode, rtx,
unsigned HOST_WIDE_INT));
static unsigned HOST_WIDE_INT nonzero_bits PROTO((rtx, enum machine_mode));
static int num_sign_bit_copies PROTO((rtx, enum machine_mode));
static int merge_outer_ops PROTO((enum rtx_code *, HOST_WIDE_INT *,
enum rtx_code, HOST_WIDE_INT,
enum machine_mode, int *));
static rtx simplify_shift_const PROTO((rtx, enum rtx_code, enum machine_mode,
rtx, int));
static int recog_for_combine PROTO((rtx *, rtx, rtx *));
static rtx gen_lowpart_for_combine PROTO((enum machine_mode, rtx));
static rtx gen_rtx_combine PVPROTO((enum rtx_code code, enum machine_mode mode,
...));
static rtx gen_binary PROTO((enum rtx_code, enum machine_mode,
rtx, rtx));
static rtx gen_unary PROTO((enum rtx_code, enum machine_mode,
enum machine_mode, rtx));
static enum rtx_code simplify_comparison PROTO((enum rtx_code, rtx *, rtx *));
static int reversible_comparison_p PROTO((rtx));
static void update_table_tick PROTO((rtx));
static void record_value_for_reg PROTO((rtx, rtx, rtx));
static void record_dead_and_set_regs_1 PROTO((rtx, rtx));
static void record_dead_and_set_regs PROTO((rtx));
static int get_last_value_validate PROTO((rtx *, rtx, int, int));
static rtx get_last_value PROTO((rtx));
static int use_crosses_set_p PROTO((rtx, int));
static void reg_dead_at_p_1 PROTO((rtx, rtx));
static int reg_dead_at_p PROTO((rtx, rtx));
static void move_deaths PROTO((rtx, rtx, int, rtx, rtx *));
static int reg_bitfield_target_p PROTO((rtx, rtx));
static void distribute_notes PROTO((rtx, rtx, rtx, rtx, rtx, rtx));
static void distribute_links PROTO((rtx));
static void mark_used_regs_combine PROTO((rtx));
static int insn_cuid PROTO((rtx));
void
combine_instructions (f, nregs)
rtx f;
int nregs;
{
register rtx insn, next;
#ifdef HAVE_cc0
register rtx prev;
#endif
register int i;
register rtx links, nextlinks;
combine_attempts = 0;
combine_merges = 0;
combine_extras = 0;
combine_successes = 0;
undobuf.undos = undobuf.previous_undos = 0;
combine_max_regno = nregs;
reg_nonzero_bits
= (unsigned HOST_WIDE_INT *) alloca (nregs * sizeof (HOST_WIDE_INT));
reg_sign_bit_copies = (char *) alloca (nregs * sizeof (char));
bzero ((char *) reg_nonzero_bits, nregs * sizeof (HOST_WIDE_INT));
bzero (reg_sign_bit_copies, nregs * sizeof (char));
reg_last_death = (rtx *) alloca (nregs * sizeof (rtx));
reg_last_set = (rtx *) alloca (nregs * sizeof (rtx));
reg_last_set_value = (rtx *) alloca (nregs * sizeof (rtx));
reg_last_set_table_tick = (int *) alloca (nregs * sizeof (int));
reg_last_set_label = (int *) alloca (nregs * sizeof (int));
reg_last_set_invalid = (char *) alloca (nregs * sizeof (char));
reg_last_set_mode
= (enum machine_mode *) alloca (nregs * sizeof (enum machine_mode));
reg_last_set_nonzero_bits
= (unsigned HOST_WIDE_INT *) alloca (nregs * sizeof (HOST_WIDE_INT));
reg_last_set_sign_bit_copies
= (char *) alloca (nregs * sizeof (char));
init_reg_last_arrays ();
init_recog_no_volatile ();
for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
if (INSN_UID (insn) > i)
i = INSN_UID (insn);
uid_cuid = (int *) alloca ((i + 1) * sizeof (int));
max_uid_cuid = i;
nonzero_bits_mode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0);
nonzero_sign_valid = 0;
label_tick = 1;
subst_prev_insn = NULL_RTX;
setup_incoming_promotions ();
for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
{
uid_cuid[INSN_UID (insn)] = ++i;
subst_low_cuid = i;
subst_insn = insn;
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
note_stores (PATTERN (insn), set_nonzero_bits_and_sign_copies);
record_dead_and_set_regs (insn);
#ifdef AUTO_INC_DEC
for (links = REG_NOTES (insn); links; links = XEXP (links, 1))
if (REG_NOTE_KIND (links) == REG_INC)
set_nonzero_bits_and_sign_copies (XEXP (links, 0), NULL_RTX);
#endif
}
if (GET_CODE (insn) == CODE_LABEL)
label_tick++;
}
nonzero_sign_valid = 1;
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))
{
next = 0;
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 (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
if ((next = try_combine (insn, XEXP (links, 0), NULL_RTX)) != 0)
goto retry;
for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
for (nextlinks = LOG_LINKS (XEXP (links, 0)); nextlinks;
nextlinks = XEXP (nextlinks, 1))
if ((next = try_combine (insn, XEXP (links, 0),
XEXP (nextlinks, 0))) != 0)
goto retry;
#ifdef HAVE_cc0
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)) != 0)
goto retry;
for (nextlinks = LOG_LINKS (prev); nextlinks;
nextlinks = XEXP (nextlinks, 1))
if ((next = try_combine (insn, prev,
XEXP (nextlinks, 0))) != 0)
goto retry;
}
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)) != 0)
goto retry;
for (nextlinks = LOG_LINKS (prev); nextlinks;
nextlinks = XEXP (nextlinks, 1))
if ((next = try_combine (insn, prev,
XEXP (nextlinks, 0))) != 0)
goto retry;
}
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)) != 0)
goto retry;
#endif
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))) != 0)
goto retry;
if (GET_CODE (insn) != NOTE)
record_dead_and_set_regs (insn);
retry:
;
}
}
total_attempts += combine_attempts;
total_merges += combine_merges;
total_extras += combine_extras;
total_successes += combine_successes;
nonzero_sign_valid = 0;
init_recog ();
}
static void
init_reg_last_arrays ()
{
int nregs = combine_max_regno;
bzero ((char *) reg_last_death, nregs * sizeof (rtx));
bzero ((char *) reg_last_set, nregs * sizeof (rtx));
bzero ((char *) reg_last_set_value, nregs * sizeof (rtx));
bzero ((char *) reg_last_set_table_tick, nregs * sizeof (int));
bzero ((char *) reg_last_set_label, nregs * sizeof (int));
bzero (reg_last_set_invalid, nregs * sizeof (char));
bzero ((char *) reg_last_set_mode, nregs * sizeof (enum machine_mode));
bzero ((char *) reg_last_set_nonzero_bits, nregs * sizeof (HOST_WIDE_INT));
bzero (reg_last_set_sign_bit_copies, nregs * sizeof (char));
}
static void
setup_incoming_promotions ()
{
#ifdef PROMOTE_FUNCTION_ARGS
int regno;
rtx reg;
enum machine_mode mode;
int unsignedp;
rtx first = get_insns ();
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (FUNCTION_ARG_REGNO_P (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
}
static void
set_nonzero_bits_and_sign_copies (x, set)
rtx x;
rtx set;
{
int num;
if (GET_CODE (x) == REG
&& REGNO (x) >= FIRST_PSEUDO_REGISTER
&& ! REGNO_REG_SET_P (BASIC_BLOCK (0)->global_live_at_start, REGNO (x))
&& GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT)
{
if (set == 0 || GET_CODE (set) == CLOBBER)
{
reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x));
reg_sign_bit_copies[REGNO (x)] = 1;
return;
}
set = expand_field_assignment (set);
if (SET_DEST (set) == x
|| (GET_CODE (SET_DEST (set)) == SUBREG
&& (GET_MODE_SIZE (GET_MODE (SET_DEST (set)))
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (set)))))
&& SUBREG_REG (SET_DEST (set)) == x))
{
rtx src = SET_SRC (set);
#ifdef SHORT_IMMEDIATES_SIGN_EXTEND
if (GET_MODE_BITSIZE (GET_MODE (x)) < BITS_PER_WORD
&& GET_CODE (src) == CONST_INT
&& INTVAL (src) > 0
&& 0 != (INTVAL (src)
& ((HOST_WIDE_INT) 1
<< (GET_MODE_BITSIZE (GET_MODE (x)) - 1))))
src = GEN_INT (INTVAL (src)
| ((HOST_WIDE_INT) (-1)
<< GET_MODE_BITSIZE (GET_MODE (x))));
#endif
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)
reg_sign_bit_copies[REGNO (x)] = num;
}
else
{
reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x));
reg_sign_bit_copies[REGNO (x)] = 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;
{
int i;
rtx set = 0, src, dest;
rtx p;
#ifdef AUTO_INC_DEC
rtx link;
#endif
int all_adjacent = (succ ? (next_active_insn (insn) == succ
&& next_active_insn (succ) == i3)
: next_active_insn (insn) == i3);
if (GET_CODE (PATTERN (insn)) == SET)
set = PATTERN (insn);
else if (GET_CODE (PATTERN (insn)) == PARALLEL
&& GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET)
{
for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
{
rtx elt = XVECEXP (PATTERN (insn), 0, i);
switch (GET_CODE (elt))
{
case USE:
if (GET_CODE (XEXP (elt, 0)) == REG
&& GET_CODE (PATTERN (i3)) == PARALLEL)
{
rtx i3pat = PATTERN (i3);
int i = XVECLEN (i3pat, 0) - 1;
int regno = REGNO (XEXP (elt, 0));
do
{
rtx i3elt = XVECEXP (i3pat, 0, i);
if (GET_CODE (i3elt) == USE
&& GET_CODE (XEXP (i3elt, 0)) == REG
&& (REGNO (XEXP (i3elt, 0)) == regno
? reg_set_between_p (XEXP (elt, 0),
PREV_INSN (insn), i3)
: regno >= FIRST_PSEUDO_REGISTER))
return 0;
}
while (--i >= 0);
}
break;
case CLOBBER:
break;
case SET:
if (find_reg_note (insn, REG_UNUSED, SET_DEST (elt))
&& ! side_effects_p (elt))
break;
if (set)
return 0;
set = elt;
break;
default:
return 0;
}
}
if (set == 0
|| GET_CODE (SET_SRC (set)) == ASM_OPERANDS)
return 0;
}
else
return 0;
if (set == 0)
return 0;
set = expand_field_assignment (set);
src = SET_SRC (set), dest = SET_DEST (set);
if (dest == stack_pointer_rtx
|| GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == STRICT_LOW_PART
|| (rtx_equal_p (src, dest) && find_reg_note (insn, REG_EQUAL, NULL_RTX))
|| GET_CODE (src) == CALL
|| (GET_CODE (i3) == CALL_INSN
&& (find_reg_fusage (i3, USE, dest)
|| (GET_CODE (dest) == REG
&& REGNO (dest) < FIRST_PSEUDO_REGISTER
&& global_regs[REGNO (dest)])))
|| FIND_REG_INC_NOTE (i3, dest)
|| (succ && FIND_REG_INC_NOTE (succ, dest))
#if 0
|| find_reg_note (insn, REG_RETVAL, NULL_RTX)
#endif
|| (succ && ! all_adjacent
&& reg_used_between_p (dest, succ, i3))
|| (! all_adjacent
&& (((GET_CODE (src) != MEM
|| ! find_reg_note (insn, REG_EQUIV, src))
&& use_crosses_set_p (src, INSN_CUID (insn)))
|| (GET_CODE (src) == ASM_OPERANDS && MEM_VOLATILE_P (src))
|| GET_CODE (src) == UNSPEC_VOLATILE))
|| find_reg_note (i3, REG_NO_CONFLICT, dest)
|| (succ && find_reg_note (succ, REG_NO_CONFLICT, dest))
|| (INSN_CUID (insn) < last_call_cuid && ! CONSTANT_P (src)))
return 0;
if (GET_CODE (dest) == REG)
{
if (GET_CODE (src) == REG
&& ((REGNO (dest) < FIRST_PSEUDO_REGISTER
&& ! HARD_REGNO_MODE_OK (REGNO (dest), GET_MODE (dest)))
|| (REGNO (src) < FIRST_PSEUDO_REGISTER
&& (! HARD_REGNO_MODE_OK (REGNO (src), GET_MODE (src))
|| (SMALL_REGISTER_CLASSES
&& ((! all_adjacent && ! REG_USERVAR_P (src))
|| (FUNCTION_VALUE_REGNO_P (REGNO (src))
&& ! REG_USERVAR_P (src))))))))
return 0;
}
else if (GET_CODE (dest) != CC0)
return 0;
if (GET_CODE (PATTERN (i3)) == PARALLEL)
for (i = XVECLEN (PATTERN (i3), 0) - 1; i >= 0; i--)
if (GET_CODE (XVECEXP (PATTERN (i3), 0, i)) == CLOBBER
&& (reg_overlap_mentioned_p (XEXP (XVECEXP (PATTERN (i3), 0, i), 0),
src)
|| rtx_equal_p (XEXP (XVECEXP (PATTERN (i3), 0, i), 0), dest)))
return 0;
if (GET_CODE (src) == ASM_OPERANDS || volatile_refs_p (src))
{
if (succ != 0 && volatile_refs_p (PATTERN (succ)))
return 0;
for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))
if (GET_RTX_CLASS (GET_CODE (p)) == 'i'
&& p != succ && volatile_refs_p (PATTERN (p)))
return 0;
}
if (GET_CODE (src) == ASM_OPERANDS
&& GET_CODE (dest) == REG && REGNO (dest) < FIRST_PSEUDO_REGISTER)
return 0;
for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))
if (GET_RTX_CLASS (GET_CODE (p)) == 'i'
&& p != succ && volatile_insn_p (PATTERN (p)))
return 0;
#ifdef AUTO_INC_DEC
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == REG_INC
&& (GET_CODE (i3) == JUMP_INSN
|| reg_used_between_p (XEXP (link, 0), insn, i3)
|| reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i3))))
return 0;
#endif
#ifdef HAVE_cc0
p = prev_nonnote_insn (insn);
if (p && p != pred && GET_CODE (p) == INSN && sets_cc0_p (PATTERN (p))
&& ! all_adjacent)
return 0;
#endif
*pdest = dest;
*psrc = src;
return 1;
}
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;
}
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;
{
rtx x = *loc;
if (GET_CODE (x) == SET)
{
rtx set = expand_field_assignment (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);
#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 (rtx_equal_p (inner_src, i2dest)
&& GET_CODE (inner_dest) == REG
&& ! MODES_TIEABLE_P (GET_MODE (i2dest), GET_MODE (inner_dest)))
return 0;
#endif
if ((inner_dest != dest
&& (reg_overlap_mentioned_p (i2dest, inner_dest)
|| (i1dest && reg_overlap_mentioned_p (i1dest, inner_dest))))
|| (GET_CODE (inner_dest) == REG
&& REGNO (inner_dest) < FIRST_PSEUDO_REGISTER
&& (! HARD_REGNO_MODE_OK (REGNO (inner_dest),
GET_MODE (inner_dest))
|| (SMALL_REGISTER_CLASSES && GET_CODE (src) != CALL
&& ! REG_USERVAR_P (inner_dest)
&& (FUNCTION_VALUE_REGNO_P (REGNO (inner_dest))
|| (FUNCTION_ARG_REGNO_P (REGNO (inner_dest))
&& i3 != 0
&& sets_function_arg_p (prev_nonnote_insn (i3)))))))
|| (i1_not_in_src && reg_overlap_mentioned_p (i1dest, src)))
return 0;
if (pi3dest_killed && GET_CODE (dest) == REG
&& reg_referenced_p (dest, PATTERN (i3))
&& REGNO (dest) != FRAME_POINTER_REGNUM
#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
&& REGNO (dest) != HARD_FRAME_POINTER_REGNUM
#endif
#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
&& (REGNO (dest) != ARG_POINTER_REGNUM
|| ! fixed_regs [REGNO (dest)])
#endif
&& REGNO (dest) != STACK_POINTER_REGNUM)
{
if (*pi3dest_killed)
return 0;
*pi3dest_killed = dest;
}
}
else if (GET_CODE (x) == PARALLEL)
{
int i;
for (i = 0; i < XVECLEN (x, 0); i++)
if (! combinable_i3pat (i3, &XVECEXP (x, 0, i), i2dest, i1dest,
i1_not_in_src, pi3dest_killed))
return 0;
}
return 1;
}
static rtx
try_combine (i3, i2, i1)
register rtx i3, i2, i1;
{
rtx newpat, newi2pat = 0;
int added_sets_1, added_sets_2;
int total_sets;
int i2_is_used;
int insn_code_number, i2_code_number, other_code_number;
rtx i3dest_killed = 0;
rtx i2dest, i2src, i1dest = 0, i1src = 0;
rtx i2pat;
int i2dest_in_i2src = 0, i1dest_in_i1src = 0, i2dest_in_i1src = 0;
int i1_feeds_i3 = 0;
rtx new_i3_notes, new_i2_notes;
int i3_subst_into_i2 = 0;
int have_mult = 0;
int maxreg;
rtx temp;
register rtx link;
int i;
if (GET_RTX_CLASS (GET_CODE (i3)) != 'i'
|| GET_RTX_CLASS (GET_CODE (i2)) != 'i'
|| (i1 && GET_RTX_CLASS (GET_CODE (i1)) != 'i')
#if 0
|| find_reg_note (i3, REG_LIBCALL, NULL_RTX)
#endif
)
return 0;
combine_attempts++;
undobuf.undos = undobuf.previous_undos = 0;
undobuf.other_insn = 0;
undobuf.storage = (char *) oballoc (0);
CLEAR_HARD_REG_SET (newpat_used_regs);
if (i1 && INSN_CUID (i1) > INSN_CUID (i2))
temp = i1, i1 = i2, i2 = temp;
added_links_insn = 0;
if (i1 == 0 && GET_CODE (i3) == INSN && GET_CODE (PATTERN (i3)) == SET
&& GET_CODE (SET_SRC (PATTERN (i3))) == REG
&& REGNO (SET_SRC (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER
&& (! SMALL_REGISTER_CLASSES
|| (GET_CODE (SET_DEST (PATTERN (i3))) != REG
|| REGNO (SET_DEST (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER
|| REG_USERVAR_P (SET_DEST (PATTERN (i3)))))
&& find_reg_note (i3, REG_DEAD, SET_SRC (PATTERN (i3)))
&& GET_CODE (PATTERN (i2)) == PARALLEL
&& ! side_effects_p (SET_DEST (PATTERN (i3)))
&& GET_CODE (SET_DEST (PATTERN (i3))) != ZERO_EXTRACT
&& GET_CODE (SET_DEST (PATTERN (i3))) != STRICT_LOW_PART
&& ! reg_overlap_mentioned_p (SET_SRC (PATTERN (i3)),
SET_DEST (PATTERN (i3)))
&& next_real_insn (i2) == i3)
{
rtx p2 = PATTERN (i2);
for (i = 0; i < XVECLEN (p2, 0); i++)
if ((GET_CODE (XVECEXP (p2, 0, i)) == SET
|| GET_CODE (XVECEXP (p2, 0, i)) == CLOBBER)
&& reg_overlap_mentioned_p (SET_DEST (PATTERN (i3)),
SET_DEST (XVECEXP (p2, 0, i))))
break;
if (i == XVECLEN (p2, 0))
for (i = 0; i < XVECLEN (p2, 0); i++)
if (SET_DEST (XVECEXP (p2, 0, i)) == SET_SRC (PATTERN (i3)))
{
combine_merges++;
subst_insn = i3;
subst_low_cuid = INSN_CUID (i2);
added_sets_2 = added_sets_1 = 0;
i2dest = SET_SRC (PATTERN (i3));
SUBST (SET_DEST (XVECEXP (p2, 0, i)),
SET_DEST (PATTERN (i3)));
newpat = p2;
i3_subst_into_i2 = 1;
goto validate_replacement;
}
}
#ifndef HAVE_cc0
if (i1 == 0 && GET_CODE (PATTERN (i2)) == PARALLEL
&& XVECLEN (PATTERN (i2), 0) >= 2
&& GET_CODE (XVECEXP (PATTERN (i2), 0, 0)) == SET
&& (GET_MODE_CLASS (GET_MODE (SET_DEST (XVECEXP (PATTERN (i2), 0, 0))))
== MODE_CC)
&& GET_CODE (SET_SRC (XVECEXP (PATTERN (i2), 0, 0))) == COMPARE
&& XEXP (SET_SRC (XVECEXP (PATTERN (i2), 0, 0)), 1) == const0_rtx
&& GET_CODE (XVECEXP (PATTERN (i2), 0, 1)) == SET
&& GET_CODE (SET_DEST (XVECEXP (PATTERN (i2), 0, 1))) == REG
&& rtx_equal_p (XEXP (SET_SRC (XVECEXP (PATTERN (i2), 0, 0)), 0),
SET_SRC (XVECEXP (PATTERN (i2), 0, 1))))
{
for (i = XVECLEN (PATTERN (i2), 0) - 1; i >= 2; i--)
if (GET_CODE (XVECEXP (PATTERN (i2), 0, i)) != CLOBBER)
break;
if (i == 1)
{
subst_prev_insn = i1
= gen_rtx_INSN (VOIDmode, INSN_UID (i2), NULL_RTX, 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),
SET_DEST (PATTERN (i1)));
}
}
#endif
if (! can_combine_p (i2, i3, i1, NULL_RTX, &i2dest, &i2src)
|| (i1 && ! can_combine_p (i1, i3, NULL_RTX, i2, &i1dest, &i1src)))
{
undo_all ();
return 0;
}
i2dest_in_i2src = reg_overlap_mentioned_p (i2dest, i2src);
i1dest_in_i1src = i1 && reg_overlap_mentioned_p (i1dest, i1src);
i2dest_in_i1src = i1 && reg_overlap_mentioned_p (i2dest, i1src);
i1_feeds_i3 = i1 && ! reg_overlap_mentioned_p (i1dest, i2src);
if (! combinable_i3pat (i3, &PATTERN (i3), i2dest, i1dest,
i1 && i2dest_in_i1src && i1_feeds_i3,
&i3dest_killed))
{
undo_all ();
return 0;
}
if (GET_CODE (i2src) == MULT
|| (i1 != 0 && GET_CODE (i1src) == MULT)
|| (GET_CODE (PATTERN (i3)) == SET
&& GET_CODE (SET_SRC (PATTERN (i3))) == MULT))
have_mult = 1;
#if 0
if (!(GET_CODE (PATTERN (i3)) == SET
&& GET_CODE (SET_SRC (PATTERN (i3))) == REG
&& GET_CODE (SET_DEST (PATTERN (i3))) == MEM
&& (GET_CODE (XEXP (SET_DEST (PATTERN (i3)), 0)) == POST_INC
|| GET_CODE (XEXP (SET_DEST (PATTERN (i3)), 0)) == POST_DEC)))
#endif
#ifdef AUTO_INC_DEC
for (link = REG_NOTES (i3); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == REG_INC
&& (reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i2))
|| (i1 != 0
&& reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i1)))))
{
undo_all ();
return 0;
}
#endif
added_sets_2 = ! dead_or_set_p (i3, i2dest);
added_sets_1
= i1 && ! (i1_feeds_i3 ? dead_or_set_p (i3, i1dest)
: (dead_or_set_p (i3, i1dest) || dead_or_set_p (i2, i1dest)));
i2pat = (GET_CODE (PATTERN (i2)) == PARALLEL
? gen_rtx_SET (VOIDmode, i2dest, i2src)
: PATTERN (i2));
if (added_sets_2)
i2pat = copy_rtx (i2pat);
combine_merges++;
maxreg = max_reg_num ();
subst_insn = i3;
if (flag_expensive_optimizations)
{
if (i1)
{
subst_low_cuid = INSN_CUID (i1);
i1src = subst (i1src, pc_rtx, pc_rtx, 0, 0);
}
else
{
subst_low_cuid = INSN_CUID (i2);
i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0);
}
undobuf.previous_undos = undobuf.undos;
}
#ifndef HAVE_cc0
if (i1 == 0 && added_sets_2 && GET_CODE (PATTERN (i3)) == SET
&& GET_CODE (SET_SRC (PATTERN (i3))) == COMPARE
&& XEXP (SET_SRC (PATTERN (i3)), 1) == const0_rtx
&& rtx_equal_p (XEXP (SET_SRC (PATTERN (i3)), 0), i2dest))
{
#ifdef EXTRA_CC_MODES
rtx *cc_use;
enum machine_mode compare_mode;
#endif
newpat = PATTERN (i3);
SUBST (XEXP (SET_SRC (newpat), 0), i2src);
i2_is_used = 1;
#ifdef EXTRA_CC_MODES
if (undobuf.other_insn == 0
&& (cc_use = find_single_use (SET_DEST (newpat), i3,
&undobuf.other_insn))
&& ((compare_mode = SELECT_CC_MODE (GET_CODE (*cc_use),
i2src, const0_rtx))
!= GET_MODE (SET_DEST (newpat))))
{
int regno = REGNO (SET_DEST (newpat));
rtx new_dest = gen_rtx_REG (compare_mode, regno);
if (regno < FIRST_PSEUDO_REGISTER
|| (REG_N_SETS (regno) == 1 && ! added_sets_2
&& ! REG_USERVAR_P (SET_DEST (newpat))))
{
if (regno >= FIRST_PSEUDO_REGISTER)
SUBST (regno_reg_rtx[regno], new_dest);
SUBST (SET_DEST (newpat), new_dest);
SUBST (XEXP (*cc_use, 0), new_dest);
SUBST (SET_SRC (newpat),
gen_rtx_combine (COMPARE, compare_mode,
i2src, const0_rtx));
}
else
undobuf.other_insn = 0;
}
#endif
}
else
#endif
{
n_occurrences = 0;
subst_low_cuid = INSN_CUID (i2);
newpat = subst (PATTERN (i3), i2dest, i2src, 0,
! i1_feeds_i3 && i1dest_in_i1src);
undobuf.previous_undos = undobuf.undos;
i2_is_used = n_occurrences;
}
if (i1 && GET_CODE (newpat) != CLOBBER)
{
if (! combinable_i3pat (NULL_RTX, &newpat, i1dest, NULL_RTX,
0, NULL_PTR))
{
undo_all ();
return 0;
}
n_occurrences = 0;
subst_low_cuid = INSN_CUID (i1);
newpat = subst (newpat, i1dest, i1src, 0, 0);
undobuf.previous_undos = undobuf.undos;
}
if ((FIND_REG_INC_NOTE (i2, NULL_RTX) != 0
&& i2_is_used + added_sets_2 > 1)
|| (i1 != 0 && FIND_REG_INC_NOTE (i1, NULL_RTX) != 0
&& (n_occurrences + added_sets_1 + (added_sets_2 && ! i1_feeds_i3)
> 1))
|| max_reg_num () != maxreg
|| GET_CODE (newpat) == CLOBBER
|| (GET_CODE (newpat) == SET && GET_CODE (SET_SRC (newpat)) == MULT
&& ! have_mult))
{
undo_all ();
return 0;
}
if (added_sets_1 || added_sets_2)
{
combine_extras++;
if (GET_CODE (newpat) == PARALLEL)
{
rtvec old = XVEC (newpat, 0);
total_sets = XVECLEN (newpat, 0) + added_sets_1 + added_sets_2;
newpat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_sets));
bcopy ((char *) &old->elem[0], (char *) XVEC (newpat, 0)->elem,
sizeof (old->elem[0]) * old->num_elem);
}
else
{
rtx old = newpat;
total_sets = 1 + added_sets_1 + added_sets_2;
newpat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_sets));
XVECEXP (newpat, 0, 0) = old;
}
if (added_sets_1)
XVECEXP (newpat, 0, --total_sets)
= (GET_CODE (PATTERN (i1)) == PARALLEL
? gen_rtx_SET (VOIDmode, i1dest, i1src) : PATTERN (i1));
if (added_sets_2)
{
if (i1 == 0)
XVECEXP (newpat, 0, --total_sets) = i2pat;
else
XVECEXP (newpat, 0, --total_sets)
= subst (i2pat, i1dest, i1src, 0, 0);
}
}
validate_replacement:
mark_used_regs_combine (newpat);
insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
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, 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);
}
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 (i1 && insn_code_number < 0 && GET_CODE (newpat) == SET
&& asm_noperands (newpat) < 0)
{
rtx m_split, *split;
rtx ni2dest = i2dest;
m_split = split_insns (newpat, i3);
if (m_split == 0 && ! reg_overlap_mentioned_p (ni2dest, newpat))
{
if (GET_MODE (SET_DEST (newpat)) != GET_MODE (i2dest)
&& GET_MODE (SET_DEST (newpat)) != VOIDmode
&& GET_CODE (i2dest) == REG
&& (REGNO (i2dest) < FIRST_PSEUDO_REGISTER
|| (REG_N_SETS (REGNO (i2dest)) == 1 && ! added_sets_2
&& ! REG_USERVAR_P (i2dest))))
ni2dest = gen_rtx_REG (GET_MODE (SET_DEST (newpat)),
REGNO (i2dest));
m_split = split_insns
(gen_rtx_PARALLEL (VOIDmode,
gen_rtvec (2, newpat,
gen_rtx_CLOBBER (VOIDmode,
ni2dest))),
i3);
}
if (m_split && GET_CODE (m_split) == SEQUENCE
&& XVECLEN (m_split, 0) == 2
&& (next_real_insn (i2) == i3
|| ! use_crosses_set_p (PATTERN (XVECEXP (m_split, 0, 0)),
INSN_CUID (i2))))
{
rtx i2set, i3set;
rtx newi3pat = PATTERN (XVECEXP (m_split, 0, 1));
newi2pat = PATTERN (XVECEXP (m_split, 0, 0));
i3set = single_set (XVECEXP (m_split, 0, 1));
i2set = single_set (XVECEXP (m_split, 0, 0));
if (REGNO (i2dest) >= FIRST_PSEUDO_REGISTER)
SUBST (regno_reg_rtx[REGNO (i2dest)], ni2dest);
i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
if (i2_code_number >= 0 && i2set && i3set
&& (next_real_insn (i2) == i3
|| ! reg_used_between_p (SET_DEST (i2set), i2, i3)))
insn_code_number = recog_for_combine (&newi3pat, i3,
&new_i3_notes);
if (insn_code_number >= 0)
newpat = newi3pat;
if (insn_code_number >= 0)
{
rtx new_i3_dest = SET_DEST (i3set);
rtx new_i2_dest = SET_DEST (i2set);
while (GET_CODE (new_i3_dest) == ZERO_EXTRACT
|| GET_CODE (new_i3_dest) == STRICT_LOW_PART
|| GET_CODE (new_i3_dest) == SUBREG)
new_i3_dest = XEXP (new_i3_dest, 0);
while (GET_CODE (new_i2_dest) == ZERO_EXTRACT
|| GET_CODE (new_i2_dest) == STRICT_LOW_PART
|| GET_CODE (new_i2_dest) == SUBREG)
new_i2_dest = XEXP (new_i2_dest, 0);
if (GET_CODE (new_i3_dest) == REG
&& GET_CODE (new_i2_dest) == REG
&& REGNO (new_i3_dest) == REGNO (new_i2_dest))
REG_N_SETS (REGNO (new_i2_dest))++;
}
}
if (insn_code_number < 0 && (split = find_split_point (&newpat, i3)) != 0
#ifdef HAVE_cc0
&& GET_CODE (i2dest) == REG
#endif
&& (GET_MODE (*split) == GET_MODE (i2dest)
|| GET_MODE (*split) == VOIDmode
|| REGNO (i2dest) < FIRST_PSEUDO_REGISTER
|| (REG_N_SETS (REGNO (i2dest)) == 1 && ! added_sets_2
&& ! REG_USERVAR_P (i2dest)))
&& (next_real_insn (i2) == i3
|| ! use_crosses_set_p (*split, INSN_CUID (i2)))
&& ! reg_referenced_p (i2dest, newpat))
{
rtx newdest = i2dest;
enum rtx_code split_code = GET_CODE (*split);
enum machine_mode split_mode = GET_MODE (*split);
if (GET_MODE (i2dest) != split_mode && split_mode != VOIDmode)
{
newdest = gen_rtx_REG (split_mode, REGNO (i2dest));
if (REGNO (i2dest) >= FIRST_PSEUDO_REGISTER)
SUBST (regno_reg_rtx[REGNO (i2dest)], newdest);
}
if (split_code == MULT
&& GET_CODE (XEXP (*split, 1)) == CONST_INT
&& (i = exact_log2 (INTVAL (XEXP (*split, 1)))) >= 0)
{
SUBST (*split, gen_rtx_combine (ASHIFT, split_mode,
XEXP (*split, 0), GEN_INT (i)));
split_code = GET_CODE (*split);
}
#ifdef INSN_SCHEDULING
if (split_code == SUBREG && GET_CODE (SUBREG_REG (*split)) == MEM)
SUBST (*split, gen_rtx_combine (ZERO_EXTEND, split_mode,
XEXP (*split, 0)));
#endif
newi2pat = gen_rtx_combine (SET, VOIDmode, newdest, *split);
SUBST (*split, newdest);
i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
if (i2_code_number >= 0 && ! (split_code == MULT && ! have_mult))
insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
}
}
else if (i1 && insn_code_number < 0 && asm_noperands (newpat) < 0
&& GET_CODE (newpat) == PARALLEL
&& XVECLEN (newpat, 0) == 2
&& GET_CODE (XVECEXP (newpat, 0, 0)) == SET
&& GET_CODE (SET_SRC (XVECEXP (newpat, 0, 0))) == SIGN_EXTEND
&& GET_CODE (XVECEXP (newpat, 0, 1)) == SET
&& rtx_equal_p (SET_SRC (XVECEXP (newpat, 0, 1)),
XEXP (SET_SRC (XVECEXP (newpat, 0, 0)), 0))
&& ! use_crosses_set_p (SET_SRC (XVECEXP (newpat, 0, 1)),
INSN_CUID (i2))
&& GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != ZERO_EXTRACT
&& GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != STRICT_LOW_PART
&& ! (temp = SET_DEST (XVECEXP (newpat, 0, 1)),
(GET_CODE (temp) == REG
&& reg_nonzero_bits[REGNO (temp)] != 0
&& GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD
&& GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT
&& (reg_nonzero_bits[REGNO (temp)]
!= GET_MODE_MASK (word_mode))))
&& ! (GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) == SUBREG
&& (temp = SUBREG_REG (SET_DEST (XVECEXP (newpat, 0, 1))),
(GET_CODE (temp) == REG
&& reg_nonzero_bits[REGNO (temp)] != 0
&& GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD
&& GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT
&& (reg_nonzero_bits[REGNO (temp)]
!= GET_MODE_MASK (word_mode)))))
&& ! reg_overlap_mentioned_p (SET_DEST (XVECEXP (newpat, 0, 1)),
SET_SRC (XVECEXP (newpat, 0, 1)))
&& ! find_reg_note (i3, REG_UNUSED,
SET_DEST (XVECEXP (newpat, 0, 0))))
{
rtx ni2dest;
newi2pat = XVECEXP (newpat, 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));
i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
if (i2_code_number >= 0)
insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
if (insn_code_number >= 0)
{
rtx insn;
rtx link;
PATTERN (i3) = newpat;
distribute_links (gen_rtx_INSN_LIST (VOIDmode, i3, NULL_RTX));
for (insn = NEXT_INSN (i3);
insn && (this_basic_block == n_basic_blocks - 1
|| insn != BLOCK_HEAD (this_basic_block + 1));
insn = NEXT_INSN (insn))
{
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
&& reg_referenced_p (ni2dest, PATTERN (insn)))
{
for (link = LOG_LINKS (insn); link;
link = XEXP (link, 1))
if (XEXP (link, 0) == i3)
XEXP (link, 0) = i1;
break;
}
}
}
}
else if (i1 && insn_code_number < 0 && asm_noperands (newpat) < 0
&& GET_CODE (newpat) == PARALLEL
&& XVECLEN (newpat, 0) == 2
&& GET_CODE (XVECEXP (newpat, 0, 0)) == SET
&& GET_CODE (SET_DEST (XVECEXP (newpat, 0, 0))) != ZERO_EXTRACT
&& GET_CODE (SET_DEST (XVECEXP (newpat, 0, 0))) != STRICT_LOW_PART
&& GET_CODE (XVECEXP (newpat, 0, 1)) == SET
&& GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != ZERO_EXTRACT
&& GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != STRICT_LOW_PART
&& ! use_crosses_set_p (SET_SRC (XVECEXP (newpat, 0, 1)),
INSN_CUID (i2))
&& GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != USE
&& GET_CODE (SET_DEST (XVECEXP (newpat, 0, 0))) != USE
&& ! reg_referenced_p (SET_DEST (XVECEXP (newpat, 0, 1)),
XVECEXP (newpat, 0, 0))
&& ! reg_referenced_p (SET_DEST (XVECEXP (newpat, 0, 0)),
XVECEXP (newpat, 0, 1)))
{
#ifdef HAVE_cc0
if (reg_referenced_p (cc0_rtx, XVECEXP (newpat, 0, 0)))
{
newi2pat = XVECEXP (newpat, 0, 0);
newpat = XVECEXP (newpat, 0, 1);
}
else
#endif
{
newi2pat = XVECEXP (newpat, 0, 1);
newpat = XVECEXP (newpat, 0, 0);
}
i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
if (i2_code_number >= 0)
insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
}
if ((insn_code_number < 0
&& (! check_asm_operands (newpat) || added_sets_1 || added_sets_2)))
{
undo_all ();
return 0;
}
if (undobuf.other_insn)
{
rtx other_pat = PATTERN (undobuf.other_insn);
rtx new_other_notes;
rtx note, next;
CLEAR_HARD_REG_SET (newpat_used_regs);
other_code_number = recog_for_combine (&other_pat, undobuf.other_insn,
&new_other_notes);
if (other_code_number < 0 && ! check_asm_operands (other_pat))
{
undo_all ();
return 0;
}
PATTERN (undobuf.other_insn) = other_pat;
for (note = REG_NOTES (undobuf.other_insn); note; note = next)
{
next = XEXP (note, 1);
if (REG_NOTE_KIND (note) == REG_UNUSED
&& ! reg_set_p (XEXP (note, 0), PATTERN (undobuf.other_insn)))
{
if (GET_CODE (XEXP (note, 0)) == REG)
REG_N_DEATHS (REGNO (XEXP (note, 0)))--;
remove_note (undobuf.other_insn, note);
}
}
for (note = new_other_notes; note; note = XEXP (note, 1))
if (GET_CODE (XEXP (note, 0)) == REG)
REG_N_DEATHS (REGNO (XEXP (note, 0)))++;
distribute_notes (new_other_notes, undobuf.other_insn,
undobuf.other_insn, NULL_RTX, NULL_RTX, NULL_RTX);
}
{
rtx i3notes, i2notes, i1notes = 0;
rtx i3links, i2links, i1links = 0;
rtx midnotes = 0;
register int regno;
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);
i3notes = REG_NOTES (i3), i3links = LOG_LINKS (i3);
i2notes = REG_NOTES (i2), i2links = LOG_LINKS (i2);
if (i1)
i1notes = REG_NOTES (i1), i1links = LOG_LINKS (i1);
reset_used_flags (i3notes);
reset_used_flags (i2notes);
reset_used_flags (i1notes);
reset_used_flags (newpat);
reset_used_flags (newi2pat);
if (undobuf.other_insn)
reset_used_flags (PATTERN (undobuf.other_insn));
i3notes = copy_rtx_if_shared (i3notes);
i2notes = copy_rtx_if_shared (i2notes);
i1notes = copy_rtx_if_shared (i1notes);
newpat = copy_rtx_if_shared (newpat);
newi2pat = copy_rtx_if_shared (newi2pat);
if (undobuf.other_insn)
reset_used_flags (PATTERN (undobuf.other_insn));
INSN_CODE (i3) = insn_code_number;
PATTERN (i3) = newpat;
if (undobuf.other_insn)
INSN_CODE (undobuf.other_insn) = other_code_number;
if (i3_subst_into_i2)
{
for (i = 0; i < XVECLEN (PATTERN (i2), 0); i++)
if (GET_CODE (SET_DEST (XVECEXP (PATTERN (i2), 0, i))) == REG
&& SET_DEST (XVECEXP (PATTERN (i2), 0, i)) != i2dest
&& ! 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 = NEXT_INSN (temp))
if (temp != i3 && GET_RTX_CLASS (GET_CODE (temp)) == 'i')
for (link = LOG_LINKS (temp); link; link = XEXP (link, 1))
if (XEXP (link, 0) == i2)
XEXP (link, 0) = i3;
if (i3notes)
{
rtx link = i3notes;
while (XEXP (link, 1))
link = XEXP (link, 1);
XEXP (link, 1) = i2notes;
}
else
i3notes = i2notes;
i2notes = 0;
}
LOG_LINKS (i3) = 0;
REG_NOTES (i3) = 0;
LOG_LINKS (i2) = 0;
REG_NOTES (i2) = 0;
if (newi2pat)
{
INSN_CODE (i2) = i2_code_number;
PATTERN (i2) = newi2pat;
}
else
{
PUT_CODE (i2, NOTE);
NOTE_LINE_NUMBER (i2) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (i2) = 0;
}
if (i1)
{
LOG_LINKS (i1) = 0;
REG_NOTES (i1) = 0;
PUT_CODE (i1, NOTE);
NOTE_LINE_NUMBER (i1) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (i1) = 0;
}
if (newi2pat)
{
move_deaths (newi2pat, NULL_RTX, INSN_CUID (i1), i2, &midnotes);
move_deaths (newpat, newi2pat, INSN_CUID (i1), i3, &midnotes);
}
else
move_deaths (newpat, NULL_RTX, i1 ? INSN_CUID (i1) : INSN_CUID (i2),
i3, &midnotes);
if (i3notes)
distribute_notes (i3notes, i3, i3, newi2pat ? i2 : NULL_RTX,
elim_i2, elim_i1);
if (i2notes)
distribute_notes (i2notes, i2, i3, newi2pat ? i2 : NULL_RTX,
elim_i2, elim_i1);
if (i1notes)
distribute_notes (i1notes, i1, i3, newi2pat ? i2 : NULL_RTX,
elim_i2, elim_i1);
if (midnotes)
distribute_notes (midnotes, NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
elim_i2, elim_i1);
if (newi2pat && new_i2_notes)
{
for (temp = new_i2_notes; temp; temp = XEXP (temp, 1))
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);
}
if (new_i3_notes)
{
for (temp = new_i3_notes; temp; temp = XEXP (temp, 1))
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);
}
if (i3dest_killed)
{
if (GET_CODE (i3dest_killed) == REG)
REG_N_DEATHS (REGNO (i3dest_killed))++;
if (newi2pat && reg_set_p (i3dest_killed, newi2pat))
distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i3dest_killed,
NULL_RTX),
NULL_RTX, i2, NULL_RTX, elim_i2, elim_i1);
else
distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i3dest_killed,
NULL_RTX),
NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
elim_i2, elim_i1);
}
if (i2dest_in_i2src)
{
if (GET_CODE (i2dest) == REG)
REG_N_DEATHS (REGNO (i2dest))++;
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);
else
distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i2dest, NULL_RTX),
NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
NULL_RTX, NULL_RTX);
}
if (i1dest_in_i1src)
{
if (GET_CODE (i1dest) == REG)
REG_N_DEATHS (REGNO (i1dest))++;
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);
else
distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i1dest, NULL_RTX),
NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
NULL_RTX, NULL_RTX);
}
distribute_links (i3links);
distribute_links (i2links);
distribute_links (i1links);
if (GET_CODE (i2dest) == REG)
{
rtx link;
rtx i2_insn = 0, i2_val = 0, set;
for (link = LOG_LINKS (i3); link; link = XEXP (link, 1))
if ((set = single_set (XEXP (link, 0))) != 0
&& rtx_equal_p (i2dest, SET_DEST (set)))
i2_insn = XEXP (link, 0), i2_val = SET_SRC (set);
record_value_for_reg (i2dest, i2_insn, i2_val);
if (! added_sets_2
&& (newi2pat == 0 || ! reg_mentioned_p (i2dest, newi2pat))
&& ! i2dest_in_i2src)
{
regno = REGNO (i2dest);
REG_N_SETS (regno)--;
if (REG_N_SETS (regno) == 0
&& ! REGNO_REG_SET_P (BASIC_BLOCK (0)->global_live_at_start,
regno))
REG_N_REFS (regno) = 0;
}
}
if (i1 && GET_CODE (i1dest) == REG)
{
rtx link;
rtx i1_insn = 0, i1_val = 0, set;
for (link = LOG_LINKS (i3); link; link = XEXP (link, 1))
if ((set = single_set (XEXP (link, 0))) != 0
&& rtx_equal_p (i1dest, SET_DEST (set)))
i1_insn = XEXP (link, 0), i1_val = SET_SRC (set);
record_value_for_reg (i1dest, i1_insn, i1_val);
regno = REGNO (i1dest);
if (! added_sets_1 && ! i1dest_in_i1src)
{
REG_N_SETS (regno)--;
if (REG_N_SETS (regno) == 0
&& ! REGNO_REG_SET_P (BASIC_BLOCK (0)->global_live_at_start,
regno))
REG_N_REFS (regno) = 0;
}
}
note_stores (newpat, set_nonzero_bits_and_sign_copies);
if (newi2pat)
note_stores (newi2pat, set_nonzero_bits_and_sign_copies);
if ((GET_CODE (newpat) == RETURN || simplejump_p (i3))
&& ((temp = next_nonnote_insn (i3)) == NULL_RTX
|| GET_CODE (temp) != BARRIER))
emit_barrier_after (i3);
}
combine_successes++;
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))
return added_links_insn;
else
return newi2pat ? i2 : i3;
}
static void
undo_all ()
{
struct undo *undo, *next;
for (undo = undobuf.undos; undo; undo = next)
{
next = undo->next;
if (undo->is_int)
*undo->where.i = undo->old_contents.i;
else
*undo->where.r = undo->old_contents.r;
undo->next = undobuf.frees;
undobuf.frees = undo;
}
obfree (undobuf.storage);
undobuf.undos = undobuf.previous_undos = 0;
subst_prev_insn = NULL_RTX;
}
static rtx *
find_split_point (loc, insn)
rtx *loc;
rtx insn;
{
rtx x = *loc;
enum rtx_code code = GET_CODE (x);
rtx *split;
int len = 0, pos, unsignedp;
rtx inner;
switch (code)
{
case SUBREG:
#ifdef INSN_SCHEDULING
if (GET_CODE (SUBREG_REG (x)) == MEM)
return loc;
#endif
return find_split_point (&SUBREG_REG (x), insn);
case MEM:
#ifdef HAVE_lo_sum
if (GET_CODE (XEXP (x, 0)) == CONST
|| GET_CODE (XEXP (x, 0)) == SYMBOL_REF)
{
SUBST (XEXP (x, 0),
gen_rtx_combine (LO_SUM, Pmode,
gen_rtx_combine (HIGH, Pmode, XEXP (x, 0)),
XEXP (x, 0)));
return &XEXP (XEXP (x, 0), 0);
}
#endif
if (GET_CODE (XEXP (x, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
&& ! memory_address_p (GET_MODE (x), XEXP (x, 0)))
{
rtx reg = regno_reg_rtx[FIRST_PSEUDO_REGISTER];
rtx seq = split_insns (gen_rtx_SET (VOIDmode, reg, XEXP (x, 0)),
subst_insn);
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
&& ! 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
&& memory_address_p (GET_MODE (x),
SET_SRC (PATTERN (XVECEXP (seq, 0, 1)))))
{
rtx src1 = SET_SRC (PATTERN (XVECEXP (seq, 0, 0)));
rtx src2 = SET_SRC (PATTERN (XVECEXP (seq, 0, 1)));
src2 = replace_rtx (src2, reg, src1);
split = 0;
if (XEXP (src2, 0) == src1)
split = &XEXP (src2, 0);
else if (GET_RTX_FORMAT (GET_CODE (XEXP (src2, 0)))[0] == 'e'
&& XEXP (XEXP (src2, 0), 0) == src1)
split = &XEXP (XEXP (src2, 0), 0);
if (split)
{
SUBST (XEXP (x, 0), src2);
return split;
}
}
else if (GET_RTX_CLASS (GET_CODE (XEXP (XEXP (x, 0), 0))) != 'o'
&& ! (GET_CODE (XEXP (XEXP (x, 0), 0)) == SUBREG
&& (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (XEXP (x, 0), 0))))
== 'o')))
return &XEXP (XEXP (x, 0), 0);
}
break;
case SET:
#ifdef HAVE_cc0
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'
&& ! (GET_CODE (SET_SRC (x)) == SUBREG
&& GET_RTX_CLASS (GET_CODE (SUBREG_REG (SET_SRC (x)))) == 'o'))
return &SET_SRC (x);
#endif
split = find_split_point (&SET_SRC (x), insn);
if (split && split != &SET_SRC (x))
return split;
split = find_split_point (&SET_DEST (x), insn);
if (split && split != &SET_DEST (x))
return split;
if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT
&& (GET_MODE_BITSIZE (GET_MODE (XEXP (SET_DEST (x), 0)))
<= HOST_BITS_PER_WIDE_INT)
&& GET_CODE (XEXP (SET_DEST (x), 1)) == CONST_INT
&& GET_CODE (XEXP (SET_DEST (x), 2)) == CONST_INT
&& GET_CODE (SET_SRC (x)) == CONST_INT
&& ((INTVAL (XEXP (SET_DEST (x), 1))
+ INTVAL (XEXP (SET_DEST (x), 2)))
<= GET_MODE_BITSIZE (GET_MODE (XEXP (SET_DEST (x), 0))))
&& ! side_effects_p (XEXP (SET_DEST (x), 0)))
{
int pos = INTVAL (XEXP (SET_DEST (x), 2));
int len = INTVAL (XEXP (SET_DEST (x), 1));
int src = INTVAL (SET_SRC (x));
rtx dest = XEXP (SET_DEST (x), 0);
enum machine_mode mode = GET_MODE (dest);
unsigned HOST_WIDE_INT mask = ((HOST_WIDE_INT) 1 << len) - 1;
if (BITS_BIG_ENDIAN)
pos = GET_MODE_BITSIZE (mode) - len - pos;
if ((unsigned HOST_WIDE_INT) src == mask)
SUBST (SET_SRC (x),
gen_binary (IOR, mode, dest, GEN_INT (src << pos)));
else
SUBST (SET_SRC (x),
gen_binary (IOR, mode,
gen_binary (AND, mode, dest,
GEN_INT (~ (mask << pos)
& GET_MODE_MASK (mode))),
GEN_INT (src << pos)));
SUBST (SET_DEST (x), dest);
split = find_split_point (&SET_SRC (x), insn);
if (split && split != &SET_SRC (x))
return split;
}
code = GET_CODE (SET_SRC (x));
switch (code)
{
case AND:
if (GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT
&& GET_CODE (XEXP (SET_SRC (x), 0)) == REG
&& (pos = exact_log2 (INTVAL (XEXP (SET_SRC (x), 1)))) >= 7
&& GET_CODE (SET_DEST (x)) == REG
&& (split = find_single_use (SET_DEST (x), insn, NULL_PTR)) != 0
&& (GET_CODE (*split) == EQ || GET_CODE (*split) == NE)
&& XEXP (*split, 0) == SET_DEST (x)
&& XEXP (*split, 1) == const0_rtx)
{
rtx extraction = make_extraction (GET_MODE (SET_DEST (x)),
XEXP (SET_SRC (x), 0),
pos, NULL_RTX, 1, 1, 0, 0);
if (extraction != 0)
{
SUBST (SET_SRC (x), extraction);
return find_split_point (loc, insn);
}
}
break;
case NE:
if (STORE_FLAG_VALUE == -1 && XEXP (SET_SRC (x), 1) == const0_rtx
&& GET_MODE (SET_SRC (x)) == GET_MODE (XEXP (SET_SRC (x), 0))
&& 1 <= (pos = exact_log2
(nonzero_bits (XEXP (SET_SRC (x), 0),
GET_MODE (XEXP (SET_SRC (x), 0))))))
{
enum machine_mode mode = GET_MODE (XEXP (SET_SRC (x), 0));
SUBST (SET_SRC (x),
gen_rtx_combine (NEG, mode,
gen_rtx_combine (LSHIFTRT, mode,
XEXP (SET_SRC (x), 0),
GEN_INT (pos))));
split = find_split_point (&SET_SRC (x), insn);
if (split && split != &SET_SRC (x))
return split;
}
break;
case SIGN_EXTEND:
inner = XEXP (SET_SRC (x), 0);
if (GET_MODE_CLASS (GET_MODE (inner)) == MODE_PARTIAL_INT
|| GET_MODE_CLASS (GET_MODE (SET_SRC (x))) == MODE_PARTIAL_INT)
break;
pos = 0;
len = GET_MODE_BITSIZE (GET_MODE (inner));
unsignedp = 0;
break;
case SIGN_EXTRACT:
case ZERO_EXTRACT:
if (GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT
&& GET_CODE (XEXP (SET_SRC (x), 2)) == CONST_INT)
{
inner = XEXP (SET_SRC (x), 0);
len = INTVAL (XEXP (SET_SRC (x), 1));
pos = INTVAL (XEXP (SET_SRC (x), 2));
if (BITS_BIG_ENDIAN)
pos = GET_MODE_BITSIZE (GET_MODE (inner)) - len - pos;
unsignedp = (code == ZERO_EXTRACT);
}
break;
default:
break;
}
if (len && pos >= 0 && pos + len <= GET_MODE_BITSIZE (GET_MODE (inner)))
{
enum machine_mode mode = GET_MODE (SET_SRC (x));
if (unsignedp && len <= 8)
{
SUBST (SET_SRC (x),
gen_rtx_combine
(AND, mode,
gen_rtx_combine (LSHIFTRT, mode,
gen_lowpart_for_combine (mode, inner),
GEN_INT (pos)),
GEN_INT (((HOST_WIDE_INT) 1 << len) - 1)));
split = find_split_point (&SET_SRC (x), insn);
if (split && split != &SET_SRC (x))
return split;
}
else
{
SUBST (SET_SRC (x),
gen_rtx_combine
(unsignedp ? LSHIFTRT : ASHIFTRT, mode,
gen_rtx_combine (ASHIFT, mode,
gen_lowpart_for_combine (mode, inner),
GEN_INT (GET_MODE_BITSIZE (mode)
- len - pos)),
GEN_INT (GET_MODE_BITSIZE (mode) - len)));
split = find_split_point (&SET_SRC (x), insn);
if (split && split != &SET_SRC (x))
return split;
}
}
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))) == '<')
&& CONSTANT_P (XEXP (SET_SRC (x), 1))
&& (GET_RTX_CLASS (GET_CODE (XEXP (SET_SRC (x), 0))) == 'o'
|| (GET_CODE (XEXP (SET_SRC (x), 0)) == SUBREG
&& (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (SET_SRC (x), 0))))
== 'o'))))
return &XEXP (SET_SRC (x), 1);
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')
&& ! register_operand (XEXP (SET_SRC (x), 0), VOIDmode))
return &XEXP (SET_SRC (x), 0);
return 0;
case AND:
case IOR:
if (GET_CODE (XEXP (x, 0)) == NOT && GET_CODE (XEXP (x, 1)) == NOT)
{
SUBST (*loc,
gen_rtx_combine (NOT, GET_MODE (x),
gen_rtx_combine (code == IOR ? AND : IOR,
GET_MODE (x),
XEXP (XEXP (x, 0), 0),
XEXP (XEXP (x, 1), 0))));
return find_split_point (loc, insn);
}
if (GET_CODE (XEXP (x, 1)) == NOT)
{
rtx tem = XEXP (x, 0);
SUBST (XEXP (x, 0), XEXP (x, 1));
SUBST (XEXP (x, 1), tem);
}
break;
default:
break;
}
switch (GET_RTX_CLASS (code))
{
case 'b':
case '3':
split = find_split_point (&XEXP (x, 2), insn);
if (split)
return split;
case '2':
case 'c':
case '<':
split = find_split_point (&XEXP (x, 1), insn);
if (split)
return split;
case '1':
if (GET_CODE (x) != AND && GET_CODE (XEXP (x, 0)) == AND)
return &XEXP (x, 0);
split = find_split_point (&XEXP (x, 0), insn);
if (split)
return split;
return loc;
}
return 0;
}
static rtx
subst (x, from, to, in_dest, unique_copy)
register rtx x, from, to;
int in_dest;
int unique_copy;
{
register enum rtx_code code = GET_CODE (x);
enum machine_mode op0_mode = VOIDmode;
register char *fmt;
register int len, i;
rtx new;
#define COMBINE_RTX_EQUAL_P(X,Y) \
((X) == (Y) \
|| (GET_CODE (X) == REG && GET_CODE (Y) == REG \
&& REGNO (X) == REGNO (Y) && GET_MODE (X) == GET_MODE (Y)))
if (! in_dest && COMBINE_RTX_EQUAL_P (x, from))
{
n_occurrences++;
return (unique_copy && n_occurrences > 1 ? copy_rtx (to) : to);
}
if (! in_dest && code == REG && GET_CODE (from) == REG
&& REGNO (x) == REGNO (from))
return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
if (code != MEM && code != LO_SUM && GET_RTX_CLASS (code) == 'o')
return x;
if (COMBINE_RTX_EQUAL_P (x, to))
return to;
if (code == PARALLEL
&& GET_CODE (XVECEXP (x, 0, 0)) == SET
&& GET_CODE (SET_SRC (XVECEXP (x, 0, 0))) == ASM_OPERANDS)
{
new = subst (XVECEXP (x, 0, 0), from, to, 0, unique_copy);
if (GET_CODE (new) == CLOBBER
&& XEXP (new, 0) == const0_rtx)
return new;
SUBST (XVECEXP (x, 0, 0), new);
for (i = XVECLEN (x, 0) - 1; i >= 1; i--)
{
rtx dest = SET_DEST (XVECEXP (x, 0, i));
if (GET_CODE (dest) != REG
&& GET_CODE (dest) != CC0
&& GET_CODE (dest) != PC)
{
new = subst (dest, from, to, 0, unique_copy);
if (GET_CODE (new) == CLOBBER
&& XEXP (new, 0) == const0_rtx)
return new;
SUBST (SET_DEST (XVECEXP (x, 0, i)), new);
}
}
}
else
{
len = GET_RTX_LENGTH (code);
fmt = GET_RTX_FORMAT (code);
if (code == SET
&& (GET_CODE (SET_DEST (x)) == REG
|| GET_CODE (SET_DEST (x)) == CC0
|| GET_CODE (SET_DEST (x)) == PC))
fmt = "ie";
if (fmt[0] == 'e')
op0_mode = GET_MODE (XEXP (x, 0));
for (i = 0; i < len; i++)
{
if (fmt[i] == 'E')
{
register int j;
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
{
if (COMBINE_RTX_EQUAL_P (XVECEXP (x, i, j), from))
{
new = (unique_copy && n_occurrences
? copy_rtx (to) : to);
n_occurrences++;
}
else
{
new = subst (XVECEXP (x, i, j), from, to, 0,
unique_copy);
if (GET_CODE (new) == CLOBBER
&& XEXP (new, 0) == const0_rtx)
return new;
}
SUBST (XVECEXP (x, i, j), new);
}
}
else if (fmt[i] == 'e')
{
if (COMBINE_RTX_EQUAL_P (XEXP (x, i), from))
{
if (GET_CODE (to) == SUBREG
&& ! MODES_TIEABLE_P (GET_MODE (to),
GET_MODE (SUBREG_REG (to)))
&& ! (code == SUBREG
&& MODES_TIEABLE_P (GET_MODE (x),
GET_MODE (SUBREG_REG (to))))
#ifdef HAVE_cc0
&& ! (code == SET && i == 1 && XEXP (x, 0) == cc0_rtx)
#endif
)
return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
new = (unique_copy && n_occurrences ? copy_rtx (to) : to);
n_occurrences++;
}
else
new = subst (XEXP (x, i), from, to,
(((in_dest
&& (code == SUBREG || code == STRICT_LOW_PART
|| code == ZERO_EXTRACT))
|| code == SET)
&& i == 0), unique_copy);
if (GET_CODE (new) == CLOBBER && XEXP (new, 0) == const0_rtx)
return new;
SUBST (XEXP (x, i), new);
}
}
}
for (i = 0; i < 4; i++)
{
if (code != CONST_INT && code != REG && code != CLOBBER)
x = simplify_rtx (x, op0_mode, i == 3, in_dest);
if (GET_CODE (x) == code)
break;
code = GET_CODE (x);
op0_mode = VOIDmode;
}
return x;
}
static rtx
simplify_rtx (x, op0_mode, last, in_dest)
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);
rtx temp;
int i;
if (GET_RTX_CLASS (code) == 'c'
&& ((CONSTANT_P (XEXP (x, 0)) && GET_CODE (XEXP (x, 1)) != CONST_INT)
|| (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == 'o'
&& GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) != 'o')
|| (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')))
{
temp = XEXP (x, 0);
SUBST (XEXP (x, 0), XEXP (x, 1));
SUBST (XEXP (x, 1), temp);
}
if ((code == PLUS || code == MINUS || code == MULT)
&& GET_CODE (XEXP (x, 0)) == ASHIFTRT
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == PLUS
&& GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == ASHIFT
&& GET_CODE (XEXP (XEXP (XEXP (XEXP (x, 0), 0), 0), 1)) == CONST_INT
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
&& XEXP (XEXP (XEXP (XEXP (x, 0), 0), 0), 1) == XEXP (XEXP (x, 0), 1)
&& GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == CONST_INT
&& (temp = simplify_binary_operation (ASHIFTRT, mode,
XEXP (XEXP (XEXP (x, 0), 0), 1),
XEXP (XEXP (x, 0), 1))) != 0)
{
rtx new
= simplify_shift_const (NULL_RTX, ASHIFT, mode,
XEXP (XEXP (XEXP (XEXP (x, 0), 0), 0), 0),
INTVAL (XEXP (XEXP (x, 0), 1)));
new = simplify_shift_const (NULL_RTX, ASHIFTRT, mode, new,
INTVAL (XEXP (XEXP (x, 0), 1)));
SUBST (XEXP (x, 0), gen_binary (PLUS, mode, new, temp));
}
if (((GET_RTX_CLASS (code) == '2' || GET_RTX_CLASS (code) == 'c'
|| GET_RTX_CLASS (code) == '<')
&& ((GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) != 'o'
&& ! (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'
&& ! (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'
&& ! (GET_CODE (XEXP (x, 0)) == SUBREG
&& (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 0))))
== 'o'))))))
{
rtx cond, true, false;
cond = if_then_else_cond (x, &true, &false);
if (cond != 0
&& ! (GET_RTX_CLASS (code) == '<'
&& (GET_RTX_CLASS (GET_CODE (true)) == '<'
|| GET_RTX_CLASS (GET_CODE (false)) == '<')))
{
rtx cop1 = const0_rtx;
enum rtx_code cond_code = simplify_comparison (NE, &cond, &cop1);
if (cond_code == NE && GET_RTX_CLASS (GET_CODE (cond)) == '<')
return x;
true = subst (true, pc_rtx, pc_rtx, 0, 0);
false = subst (false, pc_rtx, pc_rtx, 0, 0);
if (true == const_true_rtx && false == const0_rtx)
x = gen_binary (cond_code, mode, cond, cop1);
else if (true == const0_rtx && false == const_true_rtx)
x = gen_binary (reverse_condition (cond_code), mode, cond, cop1);
else if (GET_CODE (true) == CONST_INT
&& INTVAL (true) == - STORE_FLAG_VALUE
&& false == const0_rtx)
x = gen_unary (NEG, mode, mode,
gen_binary (cond_code, mode, cond, cop1));
else if (GET_CODE (false) == CONST_INT
&& INTVAL (false) == - STORE_FLAG_VALUE
&& true == const0_rtx)
x = gen_unary (NEG, mode, mode,
gen_binary (reverse_condition (cond_code),
mode, cond, cop1));
else
return gen_rtx_IF_THEN_ELSE (mode,
gen_binary (cond_code, VOIDmode,
cond, cop1),
true, false);
code = GET_CODE (x);
op0_mode = VOIDmode;
}
}
temp = 0;
switch (GET_RTX_CLASS (code))
{
case '1':
temp = simplify_unary_operation (code, mode, XEXP (x, 0), op0_mode);
break;
case '<':
temp = simplify_relational_operation (code, op0_mode,
XEXP (x, 0), XEXP (x, 1));
#ifdef FLOAT_STORE_FLAG_VALUE
if (temp != 0 && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
temp = ((temp == const0_rtx) ? CONST0_RTX (GET_MODE (x))
: immed_real_const_1 (FLOAT_STORE_FLAG_VALUE, GET_MODE (x)));
#endif
break;
case 'c':
case '2':
temp = simplify_binary_operation (code, mode, XEXP (x, 0), XEXP (x, 1));
break;
case 'b':
case '3':
temp = simplify_ternary_operation (code, mode, op0_mode, XEXP (x, 0),
XEXP (x, 1), XEXP (x, 2));
break;
}
if (temp)
x = temp, code = GET_CODE (temp);
if (code == PLUS || code == MINUS
|| code == AND || code == IOR || code == XOR)
{
x = apply_distributive_law (x);
code = GET_CODE (x);
}
if ((code == PLUS || code == MINUS
|| code == MULT || code == AND || code == IOR || code == XOR
|| code == DIV || code == UDIV
|| code == SMAX || code == SMIN || code == UMAX || code == UMIN)
&& INTEGRAL_MODE_P (mode))
{
if (GET_CODE (XEXP (x, 0)) == code)
{
rtx other = XEXP (XEXP (x, 0), 0);
rtx inner_op0 = XEXP (XEXP (x, 0), 1);
rtx inner_op1 = XEXP (x, 1);
rtx inner;
if (CONSTANT_P (inner_op0) && GET_RTX_CLASS (code) == 'c')
{
rtx tem = inner_op0;
inner_op0 = inner_op1;
inner_op1 = tem;
}
inner = simplify_binary_operation (code == MINUS ? PLUS
: code == DIV ? MULT
: code == UDIV ? MULT
: code,
mode, inner_op0, inner_op1);
if (inner == 0 && GET_RTX_CLASS (code) == 'c')
{
other = XEXP (XEXP (x, 0), 1);
inner = simplify_binary_operation (code, mode,
XEXP (XEXP (x, 0), 0),
XEXP (x, 1));
}
if (inner)
return gen_binary (code, mode, other, inner);
}
}
switch (code)
{
case MEM:
temp = make_compound_operation (XEXP (x, 0), MEM);
SUBST (XEXP (x, 0), temp);
break;
case SUBREG:
if (GET_CODE (SUBREG_REG (x)) == MEM
&& (GET_MODE_SIZE (mode)
<= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
{
rtx inner = SUBREG_REG (x);
int endian_offset = 0;
if (MEM_VOLATILE_P (SUBREG_REG (x))
|| mode_dependent_address_p (XEXP (inner, 0)))
return gen_rtx_CLOBBER (mode, const0_rtx);
if (BYTES_BIG_ENDIAN)
{
if (GET_MODE_SIZE (mode) < UNITS_PER_WORD)
endian_offset += UNITS_PER_WORD - GET_MODE_SIZE (mode);
if (GET_MODE_SIZE (GET_MODE (inner)) < UNITS_PER_WORD)
endian_offset -= (UNITS_PER_WORD
- GET_MODE_SIZE (GET_MODE (inner)));
}
x = gen_rtx_MEM (mode,
plus_constant (XEXP (inner, 0),
(SUBREG_WORD (x) * UNITS_PER_WORD
+ endian_offset)));
RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (inner);
MEM_COPY_ATTRIBUTES (x, inner);
return x;
}
if (in_dest)
return x;
if (GET_CODE (SUBREG_REG (x)) == SUBREG)
{
if (mode == GET_MODE (SUBREG_REG (SUBREG_REG (x)))
&& SUBREG_WORD (x) == 0 && SUBREG_WORD (SUBREG_REG (x)) == 0)
return SUBREG_REG (SUBREG_REG (x));
SUBST_INT (SUBREG_WORD (x),
SUBREG_WORD (x) + SUBREG_WORD (SUBREG_REG (x)));
SUBST (SUBREG_REG (x), SUBREG_REG (SUBREG_REG (x)));
}
if (GET_CODE (SUBREG_REG (x)) == REG
&& REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER
&& REGNO (SUBREG_REG (x)) != FRAME_POINTER_REGNUM
#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
&& REGNO (SUBREG_REG (x)) != HARD_FRAME_POINTER_REGNUM
#endif
#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
&& REGNO (SUBREG_REG (x)) != ARG_POINTER_REGNUM
#endif
&& REGNO (SUBREG_REG (x)) != STACK_POINTER_REGNUM)
{
if (HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (x)) + SUBREG_WORD (x),
mode))
return gen_rtx_REG (mode,
REGNO (SUBREG_REG (x)) + SUBREG_WORD (x));
else
return gen_rtx_CLOBBER (mode, const0_rtx);
}
if (CONSTANT_P (SUBREG_REG (x)) && op0_mode != VOIDmode
&& GET_MODE_SIZE (mode) == UNITS_PER_WORD
&& GET_MODE_SIZE (op0_mode) > UNITS_PER_WORD
&& GET_MODE_CLASS (mode) == MODE_INT)
{
temp = operand_subword (SUBREG_REG (x), SUBREG_WORD (x),
0, op0_mode);
if (temp)
return temp;
}
if (CONSTANT_P (SUBREG_REG (x))
&& ((GET_MODE_SIZE (op0_mode) <= UNITS_PER_WORD
|| ! WORDS_BIG_ENDIAN)
? SUBREG_WORD (x) == 0
: (SUBREG_WORD (x)
== ((GET_MODE_SIZE (op0_mode)
- MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
/ UNITS_PER_WORD)))
&& GET_MODE_SIZE (mode) <= GET_MODE_SIZE (op0_mode)
&& (! WORDS_BIG_ENDIAN
|| GET_MODE_BITSIZE (op0_mode) <= BITS_PER_WORD))
return gen_lowpart_for_combine (mode, SUBREG_REG (x));
if (CONSTANT_P (SUBREG_REG (x)) && GET_MODE (SUBREG_REG (x)) == VOIDmode
&& GET_MODE_SIZE (mode) > GET_MODE_SIZE (op0_mode))
return SUBREG_REG (x);
break;
case NOT:
if (GET_CODE (XEXP (x, 0)) == PLUS
&& XEXP (XEXP (x, 0), 1) == constm1_rtx)
return gen_rtx_combine (NEG, mode, XEXP (XEXP (x, 0), 0));
if (GET_CODE (XEXP (x, 0)) == NEG)
return gen_rtx_combine (PLUS, mode, XEXP (XEXP (x, 0), 0),
constm1_rtx);
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);
if (GET_CODE (XEXP (x, 0)) == ASHIFT
&& XEXP (XEXP (x, 0), 0) == const1_rtx)
return gen_rtx_ROTATE (mode, gen_unary (NOT, mode, mode, const1_rtx),
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)))
< GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (x, 0)))))
&& GET_CODE (SUBREG_REG (XEXP (x, 0))) == ASHIFT
&& XEXP (SUBREG_REG (XEXP (x, 0)), 0) == const1_rtx)
{
enum machine_mode inner_mode = GET_MODE (SUBREG_REG (XEXP (x, 0)));
x = gen_rtx_ROTATE (inner_mode,
gen_unary (NOT, inner_mode, inner_mode,
const1_rtx),
XEXP (SUBREG_REG (XEXP (x, 0)), 1));
return gen_lowpart_for_combine (mode, x);
}
if (STORE_FLAG_VALUE == -1
&& GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
&& reversible_comparison_p (XEXP (x, 0)))
return gen_rtx_combine (reverse_condition (GET_CODE (XEXP (x, 0))),
mode, XEXP (XEXP (x, 0), 0),
XEXP (XEXP (x, 0), 1));
if (STORE_FLAG_VALUE == -1
&& XEXP (x, 1) == const1_rtx
&& GET_CODE (XEXP (x, 0)) == ASHIFTRT
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
&& INTVAL (XEXP (XEXP (x, 0), 1)) == GET_MODE_BITSIZE (mode) - 1)
return gen_rtx_combine (GE, mode, XEXP (XEXP (x, 0), 0), const0_rtx);
if (GET_CODE (XEXP (x, 0)) == IOR || GET_CODE (XEXP (x, 0)) == AND)
{
rtx in1 = XEXP (XEXP (x, 0), 0), in2 = XEXP (XEXP (x, 0), 1);
if (GET_CODE (in1) == NOT)
in1 = XEXP (in1, 0);
else
in1 = gen_rtx_combine (NOT, GET_MODE (in1), in1);
if (GET_CODE (in2) == NOT)
in2 = XEXP (in2, 0);
else if (GET_CODE (in2) == CONST_INT
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
in2 = GEN_INT (GET_MODE_MASK (mode) & ~ INTVAL (in2));
else
in2 = gen_rtx_combine (NOT, GET_MODE (in2), in2);
if (GET_CODE (in2) == NOT)
{
rtx tem = in2;
in2 = in1; in1 = tem;
}
return gen_rtx_combine (GET_CODE (XEXP (x, 0)) == IOR ? AND : IOR,
mode, in1, in2);
}
break;
case NEG:
if (GET_CODE (XEXP (x, 0)) == PLUS
&& XEXP (XEXP (x, 0), 1) == const1_rtx)
return gen_rtx_combine (NOT, mode, XEXP (XEXP (x, 0), 0));
if (GET_CODE (XEXP (x, 0)) == NOT)
return plus_constant (XEXP (XEXP (x, 0), 0), 1);
if (GET_CODE (XEXP (x, 0)) == MINUS
&& (! FLOAT_MODE_P (mode)
|| TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
|| flag_fast_math))
return gen_binary (MINUS, mode, XEXP (XEXP (x, 0), 1),
XEXP (XEXP (x, 0), 0));
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);
if (GET_CODE (XEXP (x, 0)) == ASHIFT)
{
temp = simplify_unary_operation (NEG, mode,
XEXP (XEXP (x, 0), 0), mode);
if (temp)
{
SUBST (XEXP (XEXP (x, 0), 0), temp);
return XEXP (x, 0);
}
}
temp = expand_compound_operation (XEXP (x, 0));
if (GET_CODE (temp) == ASHIFTRT
&& GET_CODE (XEXP (temp, 1)) == CONST_INT
&& INTVAL (XEXP (temp, 1)) == GET_MODE_BITSIZE (mode) - 1)
return simplify_shift_const (temp, LSHIFTRT, mode, XEXP (temp, 0),
INTVAL (XEXP (temp, 1)));
if (GET_CODE (temp) != REG
&& ! (GET_CODE (temp) == SUBREG
&& GET_CODE (SUBREG_REG (temp)) == REG)
&& (i = exact_log2 (nonzero_bits (temp, mode))) >= 0)
{
rtx temp1 = simplify_shift_const
(NULL_RTX, ASHIFTRT, mode,
simplify_shift_const (NULL_RTX, ASHIFT, mode, temp,
GET_MODE_BITSIZE (mode) - 1 - i),
GET_MODE_BITSIZE (mode) - 1 - i);
if (GET_CODE (temp1) != ASHIFTRT
|| GET_CODE (XEXP (temp1, 0)) != ASHIFT
|| XEXP (XEXP (temp1, 0), 0) != temp)
return temp1;
}
break;
case TRUNCATE:
if (GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
break;
if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))))
SUBST (XEXP (x, 0),
force_to_mode (XEXP (x, 0), GET_MODE (XEXP (x, 0)),
GET_MODE_MASK (mode), NULL_RTX, 0));
if ((GET_CODE (XEXP (x, 0)) == SIGN_EXTEND
|| GET_CODE (XEXP (x, 0)) == ZERO_EXTEND)
&& GET_MODE (XEXP (XEXP (x, 0), 0)) == mode)
return XEXP (XEXP (x, 0), 0);
if ((GET_CODE (XEXP (x, 0)) == ABS
|| GET_CODE (XEXP (x, 0)) == NEG)
&& (GET_CODE (XEXP (XEXP (x, 0), 0)) == SIGN_EXTEND
|| GET_CODE (XEXP (XEXP (x, 0), 0)) == ZERO_EXTEND)
&& GET_MODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == mode)
return gen_unary (GET_CODE (XEXP (x, 0)), mode, mode,
XEXP (XEXP (XEXP (x, 0), 0), 0));
if (GET_CODE (XEXP (x, 0)) == SUBREG
&& GET_CODE (SUBREG_REG (XEXP (x, 0))) == TRUNCATE
&& subreg_lowpart_p (XEXP (x, 0)))
return SUBREG_REG (XEXP (x, 0));
if (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)
return gen_lowpart_for_combine (mode, XEXP (x, 0));
if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
&& ((HOST_WIDE_INT) STORE_FLAG_VALUE &~ GET_MODE_MASK (mode)) == 0)
return gen_lowpart_for_combine (mode, XEXP (x, 0));
if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& ((HOST_WIDE_INT) STORE_FLAG_VALUE &~ GET_MODE_MASK (mode)) == 0
&& (temp = get_last_value (XEXP (x, 0)))
&& GET_RTX_CLASS (GET_CODE (temp)) == '<')
return gen_lowpart_for_combine (mode, XEXP (x, 0));
break;
case FLOAT_TRUNCATE:
if (GET_CODE (XEXP (x, 0)) == FLOAT_EXTEND
&& GET_MODE (XEXP (XEXP (x, 0), 0)) == mode)
return XEXP (XEXP (x, 0), 0);
if ((GET_CODE (XEXP (x, 0)) == ABS
|| GET_CODE (XEXP (x, 0)) == NEG)
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == FLOAT_EXTEND
&& GET_MODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == mode)
return gen_unary (GET_CODE (XEXP (x, 0)), mode, mode,
XEXP (XEXP (XEXP (x, 0), 0), 0));
if (GET_CODE (XEXP (x, 0)) == SUBREG
&& subreg_lowpart_p (XEXP (x, 0))
&& GET_CODE (SUBREG_REG (XEXP (x, 0))) == FLOAT_TRUNCATE)
return SUBREG_REG (XEXP (x, 0));
break;
#ifdef HAVE_cc0
case COMPARE:
if (XEXP (x, 1) == const0_rtx)
return XEXP (x, 0);
if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
|| ! FLOAT_MODE_P (GET_MODE (XEXP (x, 0)))
|| flag_fast_math)
&& XEXP (x, 1) == CONST0_RTX (GET_MODE (XEXP (x, 0))))
return XEXP (x, 0);
break;
#endif
case CONST:
if (GET_CODE (XEXP (x, 0)) == CONST)
SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
break;
#ifdef HAVE_lo_sum
case LO_SUM:
if (GET_CODE (XEXP (x, 0)) == HIGH
&& rtx_equal_p (XEXP (XEXP (x, 0), 0), XEXP (x, 1)))
return XEXP (x, 1);
break;
#endif
case PLUS:
if (GET_CODE (XEXP (x, 0)) == PLUS
&& CONSTANT_ADDRESS_P (XEXP (XEXP (x, 0), 1)))
return gen_binary (PLUS, mode,
gen_binary (PLUS, mode, XEXP (XEXP (x, 0), 0),
XEXP (x, 1)),
XEXP (XEXP (x, 0), 1));
if (GET_CODE (XEXP (x, 0)) == XOR
&& GET_CODE (XEXP (x, 1)) == CONST_INT
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) == - INTVAL (XEXP (XEXP (x, 0), 1))
&& (i = exact_log2 (INTVAL (XEXP (XEXP (x, 0), 1)))) >= 0
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& ((GET_CODE (XEXP (XEXP (x, 0), 0)) == AND
&& GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == CONST_INT
&& (INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1))
== ((HOST_WIDE_INT) 1 << (i + 1)) - 1))
|| (GET_CODE (XEXP (XEXP (x, 0), 0)) == ZERO_EXTEND
&& (GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (XEXP (x, 0), 0), 0)))
== i + 1))))
return simplify_shift_const
(NULL_RTX, ASHIFTRT, mode,
simplify_shift_const (NULL_RTX, ASHIFT, mode,
XEXP (XEXP (XEXP (x, 0), 0), 0),
GET_MODE_BITSIZE (mode) - (i + 1)),
GET_MODE_BITSIZE (mode) - (i + 1));
if (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
&& reversible_comparison_p (XEXP (x, 0))
&& ((STORE_FLAG_VALUE == -1 && XEXP (x, 1) == const1_rtx)
|| (STORE_FLAG_VALUE == 1 && XEXP (x, 1) == constm1_rtx)))
return
gen_unary (NEG, mode, mode,
gen_binary (reverse_condition (GET_CODE (XEXP (x, 0))),
mode, XEXP (XEXP (x, 0), 0),
XEXP (XEXP (x, 0), 1)));
if (XEXP (x, 1) == constm1_rtx
&& GET_CODE (XEXP (x, 0)) != REG
&& ! (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,
simplify_shift_const (NULL_RTX, ASHIFT, mode,
gen_rtx_combine (XOR, mode,
XEXP (x, 0), const1_rtx),
GET_MODE_BITSIZE (mode) - 1),
GET_MODE_BITSIZE (mode) - 1);
if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& (nonzero_bits (XEXP (x, 0), mode)
& nonzero_bits (XEXP (x, 1), mode)) == 0)
return gen_binary (IOR, mode, XEXP (x, 0), XEXP (x, 1));
break;
case MINUS:
if (STORE_FLAG_VALUE == 1
&& XEXP (x, 0) == const1_rtx
&& GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<'
&& reversible_comparison_p (XEXP (x, 1)))
return gen_binary (reverse_condition (GET_CODE (XEXP (x, 1))),
mode, XEXP (XEXP (x, 1), 0),
XEXP (XEXP (x, 1), 1));
if (GET_CODE (XEXP (x, 1)) == AND
&& GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT
&& exact_log2 (- INTVAL (XEXP (XEXP (x, 1), 1))) >= 0
&& rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0)))
return simplify_and_const_int (NULL_RTX, mode, XEXP (x, 0),
- INTVAL (XEXP (XEXP (x, 1), 1)) - 1);
if (GET_CODE (XEXP (x, 1)) == PLUS && INTEGRAL_MODE_P (mode))
return gen_binary (MINUS, mode,
gen_binary (MINUS, mode, XEXP (x, 0),
XEXP (XEXP (x, 1), 0)),
XEXP (XEXP (x, 1), 1));
break;
case MULT:
if (GET_CODE (XEXP (x, 0)) == PLUS)
{
x = apply_distributive_law
(gen_binary (PLUS, mode,
gen_binary (MULT, mode,
XEXP (XEXP (x, 0), 0), XEXP (x, 1)),
gen_binary (MULT, mode,
XEXP (XEXP (x, 0), 1), XEXP (x, 1))));
if (GET_CODE (x) != MULT)
return x;
}
break;
case UDIV:
if (GET_CODE (XEXP (x, 1)) == CONST_INT
&& (i = exact_log2 (INTVAL (XEXP (x, 1)))) >= 0
&& (GET_CODE (XEXP (x, 0)) == ASHIFT
|| GET_CODE (XEXP (x, 0)) == LSHIFTRT
|| GET_CODE (XEXP (x, 0)) == ASHIFTRT
|| GET_CODE (XEXP (x, 0)) == ROTATE
|| GET_CODE (XEXP (x, 0)) == ROTATERT))
return simplify_shift_const (NULL_RTX, LSHIFTRT, mode, XEXP (x, 0), i);
break;
case EQ: case NE:
case GT: case GTU: case GE: case GEU:
case LT: case LTU: case LE: case LEU:
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
))
{
rtx op0 = XEXP (x, 0);
rtx op1 = XEXP (x, 1);
enum rtx_code new_code;
if (GET_CODE (op0) == COMPARE)
op1 = XEXP (op0, 1), op0 = XEXP (op0, 0);
new_code = simplify_comparison (code, &op0, &op1);
if (STORE_FLAG_VALUE == 1
&& new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx && nonzero_bits (op0, mode) == 1)
return gen_lowpart_for_combine (mode,
expand_compound_operation (op0));
else if (STORE_FLAG_VALUE == 1
&& new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& (num_sign_bit_copies (op0, mode)
== GET_MODE_BITSIZE (mode)))
{
op0 = expand_compound_operation (op0);
return gen_unary (NEG, mode, mode,
gen_lowpart_for_combine (mode, op0));
}
else if (STORE_FLAG_VALUE == 1
&& new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& nonzero_bits (op0, mode) == 1)
{
op0 = expand_compound_operation (op0);
return gen_binary (XOR, mode,
gen_lowpart_for_combine (mode, op0),
const1_rtx);
}
else if (STORE_FLAG_VALUE == 1
&& new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& (num_sign_bit_copies (op0, mode)
== GET_MODE_BITSIZE (mode)))
{
op0 = expand_compound_operation (op0);
return plus_constant (gen_lowpart_for_combine (mode, op0), 1);
}
if (STORE_FLAG_VALUE == -1
&& new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& (num_sign_bit_copies (op0, mode)
== GET_MODE_BITSIZE (mode)))
return gen_lowpart_for_combine (mode,
expand_compound_operation (op0));
else if (STORE_FLAG_VALUE == -1
&& new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& nonzero_bits (op0, mode) == 1)
{
op0 = expand_compound_operation (op0);
return gen_unary (NEG, mode, mode,
gen_lowpart_for_combine (mode, op0));
}
else if (STORE_FLAG_VALUE == -1
&& new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& (num_sign_bit_copies (op0, mode)
== GET_MODE_BITSIZE (mode)))
{
op0 = expand_compound_operation (op0);
return gen_unary (NOT, mode, mode,
gen_lowpart_for_combine (mode, op0));
}
else if (STORE_FLAG_VALUE == -1
&& new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& nonzero_bits (op0, mode) == 1)
{
op0 = expand_compound_operation (op0);
return plus_constant (gen_lowpart_for_combine (mode, op0), -1);
}
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))
&& op1 == const0_rtx
&& mode == GET_MODE (op0)
&& (i = exact_log2 (nonzero_bits (op0, mode))) >= 0)
{
x = simplify_shift_const (NULL_RTX, ASHIFT, mode,
expand_compound_operation (op0),
GET_MODE_BITSIZE (mode) - 1 - i);
if (GET_CODE (x) == AND && XEXP (x, 1) == const_true_rtx)
return XEXP (x, 0);
else
return x;
}
if (new_code != code)
return gen_rtx_combine (new_code, mode, op0, op1);
SUBST (XEXP (x, 0), op0);
SUBST (XEXP (x, 1), op1);
}
break;
case IF_THEN_ELSE:
return simplify_if_then_else (x);
case ZERO_EXTRACT:
case SIGN_EXTRACT:
case ZERO_EXTEND:
case SIGN_EXTEND:
if (in_dest)
return x;
return expand_compound_operation (x);
case SET:
return simplify_set (x);
case AND:
case IOR:
case XOR:
return simplify_logical (x, last);
case ABS:
if (GET_CODE (XEXP (x, 0)) == NEG)
SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
if (GET_MODE (XEXP (x, 0)) == VOIDmode)
break;
if (GET_CODE (XEXP (x, 0)) == FFS || GET_CODE (XEXP (x, 0)) == ABS
|| ((GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
<= HOST_BITS_PER_WIDE_INT)
&& ((nonzero_bits (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
& ((HOST_WIDE_INT) 1
<< (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - 1)))
== 0)))
return XEXP (x, 0);
if (num_sign_bit_copies (XEXP (x, 0), mode) == GET_MODE_BITSIZE (mode))
return gen_rtx_combine (NEG, mode, XEXP (x, 0));
break;
case FFS:
if (GET_CODE (XEXP (x, 0)) == SIGN_EXTEND
|| GET_CODE (XEXP (x, 0)) == ZERO_EXTEND)
SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
break;
case FLOAT:
if (GET_CODE (XEXP (x, 0)) == SIGN_EXTEND)
SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
break;
case ASHIFT:
case LSHIFTRT:
case ASHIFTRT:
case ROTATE:
case ROTATERT:
if (GET_CODE (XEXP (x, 1)) == CONST_INT)
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),
((HOST_WIDE_INT) 1
<< exact_log2 (GET_MODE_BITSIZE (GET_MODE (x))))
- 1,
NULL_RTX, 0));
#endif
break;
default:
break;
}
return x;
}
static rtx
simplify_if_then_else (x)
rtx x;
{
enum machine_mode mode = GET_MODE (x);
rtx cond = XEXP (x, 0);
rtx true = XEXP (x, 1);
rtx false = XEXP (x, 2);
enum rtx_code true_code = GET_CODE (cond);
int comparison_p = GET_RTX_CLASS (true_code) == '<';
rtx temp;
int i;
if (comparison_p && true == const_true_rtx && false == const0_rtx)
return gen_binary (true_code, mode, XEXP (cond, 0), XEXP (cond, 1));
if (comparison_p && reversible_comparison_p (cond)
&& true == const0_rtx && false == const_true_rtx)
return gen_binary (reverse_condition (true_code),
mode, XEXP (cond, 0), XEXP (cond, 1));
if (comparison_p && reversible_comparison_p (cond)
&& GET_CODE (XEXP (cond, 0)) == REG)
{
HOST_WIDE_INT nzb;
rtx from = XEXP (cond, 0);
enum rtx_code false_code = reverse_condition (true_code);
rtx true_val = XEXP (cond, 1);
rtx false_val = true_val;
int swapped = 0;
if (false_code == EQ)
{
swapped = 1, true_code = EQ, false_code = NE;
temp = true, true = false, false = temp;
}
if (true_code == EQ && true_val == const0_rtx
&& exact_log2 (nzb = nonzero_bits (from, GET_MODE (from))) >= 0)
false_code = EQ, false_val = GEN_INT (nzb);
else if (true_code == EQ && true_val == const0_rtx
&& (num_sign_bit_copies (from, GET_MODE (from))
== GET_MODE_BITSIZE (GET_MODE (from))))
false_code = EQ, false_val = constm1_rtx;
if (reg_mentioned_p (from, true))
true = subst (known_cond (copy_rtx (true), true_code, from, true_val),
pc_rtx, pc_rtx, 0, 0);
if (reg_mentioned_p (from, false))
false = subst (known_cond (copy_rtx (false), false_code,
from, false_val),
pc_rtx, pc_rtx, 0, 0);
SUBST (XEXP (x, 1), swapped ? false : true);
SUBST (XEXP (x, 2), swapped ? true : false);
true = XEXP (x, 1), false = XEXP (x, 2), true_code = GET_CODE (cond);
}
if (comparison_p && reversible_comparison_p (cond)
&& (true == pc_rtx
|| (CONSTANT_P (true)
&& GET_CODE (false) != CONST_INT && false != pc_rtx)
|| true == const0_rtx
|| (GET_RTX_CLASS (GET_CODE (true)) == 'o'
&& GET_RTX_CLASS (GET_CODE (false)) != 'o')
|| (GET_CODE (true) == SUBREG
&& GET_RTX_CLASS (GET_CODE (SUBREG_REG (true))) == 'o'
&& GET_RTX_CLASS (GET_CODE (false)) != 'o')
|| reg_mentioned_p (true, false)
|| rtx_equal_p (false, XEXP (cond, 0))))
{
true_code = reverse_condition (true_code);
SUBST (XEXP (x, 0),
gen_binary (true_code, GET_MODE (cond), XEXP (cond, 0),
XEXP (cond, 1)));
SUBST (XEXP (x, 1), false);
SUBST (XEXP (x, 2), true);
temp = true, true = false, false = temp, cond = XEXP (x, 0);
true_code = GET_CODE (cond);
comparison_p = GET_RTX_CLASS (true_code) == '<';
}
if (rtx_equal_p (true, false) && ! side_effects_p (cond))
return true;
if (true_code == EQ && ! side_effects_p (cond)
&& rtx_equal_p (XEXP (cond, 0), false)
&& rtx_equal_p (XEXP (cond, 1), true))
return false;
else if (true_code == NE && ! side_effects_p (cond)
&& rtx_equal_p (XEXP (cond, 0), true)
&& rtx_equal_p (XEXP (cond, 1), false))
return true;
if (GET_MODE_CLASS (mode) == MODE_INT
&& GET_CODE (false) == NEG
&& rtx_equal_p (true, XEXP (false, 0))
&& comparison_p
&& rtx_equal_p (true, XEXP (cond, 0))
&& ! side_effects_p (true))
switch (true_code)
{
case GT:
case GE:
return gen_unary (ABS, mode, mode, true);
case LT:
case LE:
return gen_unary (NEG, mode, mode, gen_unary (ABS, mode, mode, true));
default:
break;
}
if ((! FLOAT_MODE_P (mode) || flag_fast_math)
&& comparison_p
&& rtx_equal_p (XEXP (cond, 0), true)
&& rtx_equal_p (XEXP (cond, 1), false)
&& ! side_effects_p (cond))
switch (true_code)
{
case GE:
case GT:
return gen_binary (SMAX, mode, true, false);
case LE:
case LT:
return gen_binary (SMIN, mode, true, false);
case GEU:
case GTU:
return gen_binary (UMAX, mode, true, false);
case LEU:
case LTU:
return gen_binary (UMIN, mode, true, false);
default:
break;
}
if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
&& comparison_p && mode != VOIDmode && ! side_effects_p (x))
{
rtx t = make_compound_operation (true, SET);
rtx f = make_compound_operation (false, SET);
rtx cond_op0 = XEXP (cond, 0);
rtx cond_op1 = XEXP (cond, 1);
enum rtx_code op, extend_op = NIL;
enum machine_mode m = mode;
rtx z = 0, c1;
if ((GET_CODE (t) == PLUS || GET_CODE (t) == MINUS
|| GET_CODE (t) == IOR || GET_CODE (t) == XOR
|| GET_CODE (t) == ASHIFT
|| GET_CODE (t) == LSHIFTRT || GET_CODE (t) == ASHIFTRT)
&& rtx_equal_p (XEXP (t, 0), f))
c1 = XEXP (t, 1), op = GET_CODE (t), z = f;
else if ((GET_CODE (t) == PLUS || GET_CODE (t) == IOR
|| GET_CODE (t) == XOR)
&& rtx_equal_p (XEXP (t, 1), f))
c1 = XEXP (t, 0), op = GET_CODE (t), z = f;
else if (GET_CODE (t) == SIGN_EXTEND
&& (GET_CODE (XEXP (t, 0)) == PLUS
|| GET_CODE (XEXP (t, 0)) == MINUS
|| GET_CODE (XEXP (t, 0)) == IOR
|| GET_CODE (XEXP (t, 0)) == XOR
|| GET_CODE (XEXP (t, 0)) == ASHIFT
|| GET_CODE (XEXP (t, 0)) == LSHIFTRT
|| GET_CODE (XEXP (t, 0)) == ASHIFTRT)
&& GET_CODE (XEXP (XEXP (t, 0), 0)) == SUBREG
&& 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)
- GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (t, 0), 0))))))
{
c1 = XEXP (XEXP (t, 0), 1); z = f; op = GET_CODE (XEXP (t, 0));
extend_op = SIGN_EXTEND;
m = GET_MODE (XEXP (t, 0));
}
else if (GET_CODE (t) == SIGN_EXTEND
&& (GET_CODE (XEXP (t, 0)) == PLUS
|| GET_CODE (XEXP (t, 0)) == IOR
|| GET_CODE (XEXP (t, 0)) == XOR)
&& GET_CODE (XEXP (XEXP (t, 0), 1)) == SUBREG
&& 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)
- GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (t, 0), 1))))))
{
c1 = XEXP (XEXP (t, 0), 0); z = f; op = GET_CODE (XEXP (t, 0));
extend_op = SIGN_EXTEND;
m = GET_MODE (XEXP (t, 0));
}
else if (GET_CODE (t) == ZERO_EXTEND
&& (GET_CODE (XEXP (t, 0)) == PLUS
|| GET_CODE (XEXP (t, 0)) == MINUS
|| GET_CODE (XEXP (t, 0)) == IOR
|| GET_CODE (XEXP (t, 0)) == XOR
|| GET_CODE (XEXP (t, 0)) == ASHIFT
|| GET_CODE (XEXP (t, 0)) == LSHIFTRT
|| GET_CODE (XEXP (t, 0)) == ASHIFTRT)
&& GET_CODE (XEXP (XEXP (t, 0), 0)) == SUBREG
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& subreg_lowpart_p (XEXP (XEXP (t, 0), 0))
&& rtx_equal_p (SUBREG_REG (XEXP (XEXP (t, 0), 0)), f)
&& ((nonzero_bits (f, GET_MODE (f))
& ~ GET_MODE_MASK (GET_MODE (XEXP (XEXP (t, 0), 0))))
== 0))
{
c1 = XEXP (XEXP (t, 0), 1); z = f; op = GET_CODE (XEXP (t, 0));
extend_op = ZERO_EXTEND;
m = GET_MODE (XEXP (t, 0));
}
else if (GET_CODE (t) == ZERO_EXTEND
&& (GET_CODE (XEXP (t, 0)) == PLUS
|| GET_CODE (XEXP (t, 0)) == IOR
|| GET_CODE (XEXP (t, 0)) == XOR)
&& GET_CODE (XEXP (XEXP (t, 0), 1)) == SUBREG
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& subreg_lowpart_p (XEXP (XEXP (t, 0), 1))
&& rtx_equal_p (SUBREG_REG (XEXP (XEXP (t, 0), 1)), f)
&& ((nonzero_bits (f, GET_MODE (f))
& ~ GET_MODE_MASK (GET_MODE (XEXP (XEXP (t, 0), 1))))
== 0))
{
c1 = XEXP (XEXP (t, 0), 0); z = f; op = GET_CODE (XEXP (t, 0));
extend_op = ZERO_EXTEND;
m = GET_MODE (XEXP (t, 0));
}
if (z)
{
temp = subst (gen_binary (true_code, m, cond_op0, cond_op1),
pc_rtx, pc_rtx, 0, 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);
if (extend_op != NIL)
temp = gen_unary (extend_op, mode, m, temp);
return temp;
}
}
if (true_code == NE && XEXP (cond, 1) == const0_rtx
&& false == const0_rtx && GET_CODE (true) == CONST_INT
&& ((1 == nonzero_bits (XEXP (cond, 0), mode)
&& (i = exact_log2 (INTVAL (true))) >= 0)
|| ((num_sign_bit_copies (XEXP (cond, 0), mode)
== GET_MODE_BITSIZE (mode))
&& (i = exact_log2 (- INTVAL (true))) >= 0)))
return
simplify_shift_const (NULL_RTX, ASHIFT, mode,
gen_lowpart_for_combine (mode, XEXP (cond, 0)), i);
return x;
}
static rtx
simplify_set (x)
rtx x;
{
rtx src = SET_SRC (x);
rtx dest = SET_DEST (x);
enum machine_mode mode
= GET_MODE (src) != VOIDmode ? GET_MODE (src) : GET_MODE (dest);
rtx other_insn;
rtx *cc_use;
if (GET_CODE (dest) == PC && GET_CODE (src) == RETURN)
return src;
if (GET_MODE_CLASS (mode) == MODE_INT)
src = force_to_mode (src, mode, GET_MODE_MASK (mode), NULL_RTX, 0);
if ((GET_CODE (src) == COMPARE
#ifdef HAVE_cc0
|| dest == cc0_rtx
#endif
)
&& (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)) == '<'
&& 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;
int other_changed = 0;
enum machine_mode compare_mode = GET_MODE (dest);
if (GET_CODE (src) == COMPARE)
op0 = XEXP (src, 0), op1 = XEXP (src, 1);
else
op0 = src, op1 = const0_rtx;
new_code = simplify_comparison (old_code, &op0, &op1);
#ifdef EXTRA_CC_MODES
compare_mode = SELECT_CC_MODE (new_code, op0, op1);
#endif
#if !defined (HAVE_cc0) && defined (EXTRA_CC_MODES)
if (compare_mode != GET_MODE (dest))
{
int regno = REGNO (dest);
rtx new_dest = gen_rtx_REG (compare_mode, regno);
if (regno < FIRST_PSEUDO_REGISTER
|| (REG_N_SETS (regno) == 1 && ! REG_USERVAR_P (dest)))
{
if (regno >= FIRST_PSEUDO_REGISTER)
SUBST (regno_reg_rtx[regno], new_dest);
SUBST (SET_DEST (x), new_dest);
SUBST (XEXP (*cc_use, 0), new_dest);
other_changed = 1;
dest = new_dest;
}
}
#endif
if (new_code != old_code)
{
unsigned HOST_WIDE_INT mask;
SUBST (*cc_use, gen_rtx_combine (new_code, GET_MODE (*cc_use),
dest, const0_rtx));
if (((old_code == NE && new_code == EQ)
|| (old_code == EQ && new_code == NE))
&& ! other_changed && op1 == const0_rtx
&& GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT
&& exact_log2 (mask = nonzero_bits (op0, GET_MODE (op0))) >= 0)
{
rtx pat = PATTERN (other_insn), note = 0;
if ((recog_for_combine (&pat, other_insn, ¬e) < 0
&& ! check_asm_operands (pat)))
{
PUT_CODE (*cc_use, old_code);
other_insn = 0;
op0 = gen_binary (XOR, GET_MODE (op0), op0, GEN_INT (mask));
}
}
other_changed = 1;
}
if (other_changed)
undobuf.other_insn = other_insn;
#ifdef HAVE_cc0
if (op1 == const0_rtx && dest == cc0_rtx)
{
SUBST (SET_SRC (x), op0);
src = op0;
}
else
#endif
if (GET_CODE (src) != COMPARE || GET_MODE (src) != compare_mode)
{
SUBST (SET_SRC (x),
gen_rtx_combine (COMPARE, compare_mode, op0, op1));
src = SET_SRC (x);
}
else
{
SUBST (XEXP (src, 0), op0);
SUBST (XEXP (src, 1), op1);
}
}
else
{
src = make_compound_operation (src, SET);
SUBST (SET_SRC (x), src);
}
if (GET_CODE (src) == SUBREG && subreg_lowpart_p (src)
&& GET_RTX_CLASS (GET_CODE (SUBREG_REG (src))) != 'o'
&& (((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))))
#endif
#ifdef CLASS_CANNOT_CHANGE_SIZE
&& ! (GET_CODE (dest) == REG && REGNO (dest) < FIRST_PSEUDO_REGISTER
&& (TEST_HARD_REG_BIT
(reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE],
REGNO (dest)))
&& (GET_MODE_SIZE (GET_MODE (src))
!= GET_MODE_SIZE (GET_MODE (SUBREG_REG (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)),
dest));
SUBST (SET_SRC (x), SUBREG_REG (src));
src = SET_SRC (x), dest = SET_DEST (x);
}
#ifdef LOAD_EXTEND_OP
if (GET_CODE (src) == SUBREG && subreg_lowpart_p (src)
&& LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))) != NIL
&& SUBREG_WORD (src) == 0
&& (GET_MODE_SIZE (GET_MODE (src))
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))))
&& GET_CODE (SUBREG_REG (src)) == MEM)
{
SUBST (SET_SRC (x),
gen_rtx_combine (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))),
GET_MODE (src), XEXP (src, 0)));
src = SET_SRC (x);
}
#endif
if (GET_CODE (dest) != PC
&& GET_CODE (src) == IF_THEN_ELSE
&& GET_MODE_CLASS (GET_MODE (src)) == MODE_INT
&& (GET_CODE (XEXP (src, 0)) == EQ || GET_CODE (XEXP (src, 0)) == NE)
&& XEXP (XEXP (src, 0), 1) == const0_rtx
&& GET_MODE (src) == GET_MODE (XEXP (XEXP (src, 0), 0))
#ifdef HAVE_conditional_move
&& ! can_conditionally_move_p (GET_MODE (src))
#endif
&& (num_sign_bit_copies (XEXP (XEXP (src, 0), 0),
GET_MODE (XEXP (XEXP (src, 0), 0)))
== GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (src, 0), 0))))
&& ! side_effects_p (src))
{
rtx true = (GET_CODE (XEXP (src, 0)) == NE
? XEXP (src, 1) : XEXP (src, 2));
rtx false = (GET_CODE (XEXP (src, 0)) == NE
? XEXP (src, 2) : XEXP (src, 1));
rtx term1 = const0_rtx, term2, term3;
if (GET_CODE (true) == IOR && rtx_equal_p (XEXP (true, 0), false))
term1 = false, true = XEXP (true, 1), false = const0_rtx;
else if (GET_CODE (true) == IOR
&& rtx_equal_p (XEXP (true, 1), false))
term1 = false, true = XEXP (true, 0), false = const0_rtx;
else if (GET_CODE (false) == IOR
&& rtx_equal_p (XEXP (false, 0), true))
term1 = true, false = XEXP (false, 1), true = const0_rtx;
else if (GET_CODE (false) == IOR
&& rtx_equal_p (XEXP (false, 1), true))
term1 = true, false = XEXP (false, 0), true = const0_rtx;
term2 = gen_binary (AND, GET_MODE (src), XEXP (XEXP (src, 0), 0), true);
term3 = gen_binary (AND, GET_MODE (src),
gen_unary (NOT, GET_MODE (src), GET_MODE (src),
XEXP (XEXP (src, 0), 0)),
false);
SUBST (SET_SRC (x),
gen_binary (IOR, GET_MODE (src),
gen_binary (IOR, GET_MODE (src), term1, term2),
term3));
src = SET_SRC (x);
}
if (GET_CODE (src) == CLOBBER && XEXP (src, 0) == const0_rtx)
return src;
else if (GET_CODE (dest) == CLOBBER && XEXP (dest, 0) == const0_rtx)
return dest;
else
return make_field_assignment (x);
}
static rtx
simplify_logical (x, last)
rtx x;
int last;
{
enum machine_mode mode = GET_MODE (x);
rtx op0 = XEXP (x, 0);
rtx op1 = XEXP (x, 1);
switch (GET_CODE (x))
{
case AND:
if (GET_CODE (op0) == XOR
&& rtx_equal_p (XEXP (op0, 0), op1)
&& ! side_effects_p (op1))
x = gen_binary (AND, mode,
gen_unary (NOT, mode, mode, XEXP (op0, 1)), op1);
if (GET_CODE (op0) == XOR
&& rtx_equal_p (XEXP (op0, 1), op1)
&& ! side_effects_p (op1))
x = gen_binary (AND, mode,
gen_unary (NOT, mode, mode, XEXP (op0, 0)), op1);
if (GET_CODE (op0) == NOT
&& GET_CODE (XEXP (op0, 0)) == XOR
&& rtx_equal_p (XEXP (XEXP (op0, 0), 0), op1)
&& ! side_effects_p (op1))
x = gen_binary (AND, mode, XEXP (XEXP (op0, 0), 1), op1);
if (GET_CODE (op0) == NOT
&& GET_CODE (XEXP (op0, 0)) == XOR
&& rtx_equal_p (XEXP (XEXP (op0, 0), 1), op1)
&& ! side_effects_p (op1))
x = gen_binary (AND, mode, XEXP (XEXP (op0, 0), 0), op1);
if (GET_CODE (op1) == CONST_INT)
{
x = simplify_and_const_int (x, mode, op0, INTVAL (op1));
if (last
&& GET_CODE (x) == IOR && GET_CODE (op0) == AND
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
&& GET_CODE (op1) == CONST_INT)
return gen_binary (IOR, mode,
gen_binary (AND, mode, XEXP (op0, 0),
GEN_INT (INTVAL (XEXP (op0, 1))
& ~ INTVAL (op1))), op1);
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);
}
if (GET_CODE (op0) == IOR
&& (rtx_equal_p (XEXP (op0, 0), op1)
|| rtx_equal_p (XEXP (op0, 1), op1))
&& ! side_effects_p (XEXP (op0, 0))
&& ! side_effects_p (XEXP (op0, 1)))
return op1;
if (GET_CODE (op0) == IOR || GET_CODE (op0) == XOR)
{
x = apply_distributive_law
(gen_binary (GET_CODE (op0), mode,
gen_binary (AND, mode, XEXP (op0, 0), op1),
gen_binary (AND, mode, XEXP (op0, 1), op1)));
if (GET_CODE (x) != AND)
return x;
}
if (GET_CODE (op1) == IOR || GET_CODE (op1) == XOR)
return apply_distributive_law
(gen_binary (GET_CODE (op1), mode,
gen_binary (AND, mode, XEXP (op1, 0), op0),
gen_binary (AND, mode, XEXP (op1, 1), op0)));
if (GET_CODE (op0) == NOT && GET_CODE (op1) == XOR)
return apply_distributive_law
(gen_binary (XOR, mode,
gen_binary (IOR, mode, XEXP (op0, 0), XEXP (op1, 0)),
gen_binary (IOR, mode, XEXP (op0, 0), XEXP (op1, 1))));
else if (GET_CODE (op1) == NOT && GET_CODE (op0) == XOR)
return apply_distributive_law
(gen_binary (XOR, mode,
gen_binary (IOR, mode, XEXP (op1, 0), XEXP (op0, 0)),
gen_binary (IOR, mode, XEXP (op1, 0), XEXP (op0, 1))));
break;
case IOR:
if (GET_CODE (op1) == CONST_INT
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& (nonzero_bits (op0, mode) & ~ INTVAL (op1)) == 0)
return op1;
if (GET_CODE (op0) == AND
&& (rtx_equal_p (XEXP (op0, 0), op1)
|| rtx_equal_p (XEXP (op0, 1), op1))
&& ! side_effects_p (XEXP (op0, 0))
&& ! side_effects_p (XEXP (op0, 1)))
return op1;
if (GET_CODE (op0) == AND)
{
x = apply_distributive_law
(gen_binary (AND, mode,
gen_binary (IOR, mode, XEXP (op0, 0), op1),
gen_binary (IOR, mode, XEXP (op0, 1), op1)));
if (GET_CODE (x) != IOR)
return x;
}
if (GET_CODE (op1) == AND)
{
x = apply_distributive_law
(gen_binary (AND, mode,
gen_binary (IOR, mode, XEXP (op1, 0), op0),
gen_binary (IOR, mode, XEXP (op1, 1), op0)));
if (GET_CODE (x) != IOR)
return x;
}
if (((GET_CODE (op0) == ASHIFT && GET_CODE (op1) == LSHIFTRT)
|| (GET_CODE (op1) == ASHIFT && GET_CODE (op0) == LSHIFTRT))
&& rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0))
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
&& GET_CODE (XEXP (op1, 1)) == CONST_INT
&& (INTVAL (XEXP (op0, 1)) + INTVAL (XEXP (op1, 1))
== GET_MODE_BITSIZE (mode)))
return gen_rtx_ROTATE (mode, XEXP (op0, 0),
(GET_CODE (op0) == ASHIFT
? XEXP (op0, 1) : XEXP (op1, 1)));
if (GET_CODE (op1) == CONST_INT && GET_CODE (op0) == ASHIFTRT
&& GET_CODE (XEXP (op0, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (op0, 0), 1)) == CONST_INT
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
&& INTVAL (XEXP (op0, 1)) < HOST_BITS_PER_WIDE_INT)
{
int count = INTVAL (XEXP (op0, 1));
HOST_WIDE_INT mask = INTVAL (op1) << count;
if (mask >> count == INTVAL (op1)
&& (mask & nonzero_bits (XEXP (op0, 0), mode)) == 0)
{
SUBST (XEXP (XEXP (op0, 0), 1),
GEN_INT (INTVAL (XEXP (XEXP (op0, 0), 1)) | mask));
return op0;
}
}
break;
case XOR:
{
int num_negated = 0;
if (GET_CODE (op0) == NOT)
num_negated++, op0 = XEXP (op0, 0);
if (GET_CODE (op1) == NOT)
num_negated++, op1 = XEXP (op1, 0);
if (num_negated == 2)
{
SUBST (XEXP (x, 0), op0);
SUBST (XEXP (x, 1), op1);
}
else if (num_negated == 1)
return gen_unary (NOT, mode, mode, gen_binary (XOR, mode, op0, op1));
}
if (GET_CODE (op0) == AND
&& rtx_equal_p (XEXP (op0, 1), op1)
&& ! side_effects_p (op1))
return gen_binary (AND, mode,
gen_unary (NOT, mode, mode, XEXP (op0, 0)),
op1);
else if (GET_CODE (op0) == AND
&& rtx_equal_p (XEXP (op0, 0), op1)
&& ! side_effects_p (op1))
return gen_binary (AND, mode,
gen_unary (NOT, mode, mode, XEXP (op0, 1)),
op1);
if (STORE_FLAG_VALUE == 1
&& op1 == const1_rtx
&& GET_RTX_CLASS (GET_CODE (op0)) == '<'
&& reversible_comparison_p (op0))
return gen_rtx_combine (reverse_condition (GET_CODE (op0)),
mode, XEXP (op0, 0), XEXP (op0, 1));
if (STORE_FLAG_VALUE == 1
&& op1 == const1_rtx
&& GET_CODE (op0) == LSHIFTRT
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
&& INTVAL (XEXP (op0, 1)) == GET_MODE_BITSIZE (mode) - 1)
return gen_rtx_combine (GE, mode, XEXP (op0, 0), const0_rtx);
if (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))
&& op1 == const_true_rtx
&& GET_RTX_CLASS (GET_CODE (op0)) == '<'
&& reversible_comparison_p (op0))
return gen_rtx_combine (reverse_condition (GET_CODE (op0)),
mode, XEXP (op0, 0), XEXP (op0, 1));
break;
default:
abort ();
}
return x;
}
static rtx
expand_compound_operation (x)
rtx x;
{
int pos = 0, len;
int unsignedp = 0;
int modewidth;
rtx tem;
switch (GET_CODE (x))
{
case ZERO_EXTEND:
unsignedp = 1;
case SIGN_EXTEND:
if (GET_CODE (XEXP (x, 0)) == CONST_INT)
return x;
if (GET_MODE_SIZE (GET_MODE (XEXP (x, 0))) > UNITS_PER_WORD)
return x;
len = GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)));
if (len == 0)
return x;
break;
case ZERO_EXTRACT:
unsignedp = 1;
case SIGN_EXTRACT:
if (GET_CODE (XEXP (x, 0)) == CLOBBER)
return XEXP (x, 0);
if (GET_CODE (XEXP (x, 1)) != CONST_INT
|| GET_CODE (XEXP (x, 2)) != CONST_INT
|| GET_MODE (XEXP (x, 0)) == VOIDmode)
return x;
len = INTVAL (XEXP (x, 1));
pos = INTVAL (XEXP (x, 2));
if (len + pos > GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))))
SUBST (XEXP (x, 0), gen_rtx_USE (GET_MODE (x), XEXP (x, 0)));
if (BITS_BIG_ENDIAN)
pos = GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - len - pos;
break;
default:
return x;
}
if (GET_CODE (x) == ZERO_EXTEND)
{
if (GET_CODE (XEXP (x, 0)) == TRUNCATE
&& GET_MODE (XEXP (XEXP (x, 0), 0)) == GET_MODE (x)
&& GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
&& (nonzero_bits (XEXP (XEXP (x, 0), 0), GET_MODE (x))
& ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
return XEXP (XEXP (x, 0), 0);
if (GET_CODE (XEXP (x, 0)) == SUBREG
&& GET_MODE (SUBREG_REG (XEXP (x, 0))) == GET_MODE (x)
&& subreg_lowpart_p (XEXP (x, 0))
&& GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
&& (nonzero_bits (SUBREG_REG (XEXP (x, 0)), GET_MODE (x))
& ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
return SUBREG_REG (XEXP (x, 0));
if (GET_CODE (XEXP (x, 0)) == TRUNCATE
&& GET_MODE (XEXP (XEXP (x, 0), 0)) == GET_MODE (x)
&& GET_RTX_CLASS (GET_CODE (XEXP (XEXP (x, 0), 0))) == '<'
&& (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
<= HOST_BITS_PER_WIDE_INT)
&& ((HOST_WIDE_INT) STORE_FLAG_VALUE
& ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
return XEXP (XEXP (x, 0), 0);
if (GET_CODE (XEXP (x, 0)) == SUBREG
&& GET_MODE (SUBREG_REG (XEXP (x, 0))) == GET_MODE (x)
&& subreg_lowpart_p (XEXP (x, 0))
&& GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 0)))) == '<'
&& (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
<= HOST_BITS_PER_WIDE_INT)
&& ((HOST_WIDE_INT) STORE_FLAG_VALUE
& ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
return SUBREG_REG (XEXP (x, 0));
if (flag_expensive_optimizations
&& ((GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
&& ((nonzero_bits (XEXP (x, 0), GET_MODE (x))
& ~ (((unsigned HOST_WIDE_INT)
GET_MODE_MASK (GET_MODE (XEXP (x, 0))))
>> 1))
== 0))
|| (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
&& (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
<= HOST_BITS_PER_WIDE_INT)
&& (((HOST_WIDE_INT) STORE_FLAG_VALUE
& ~ (((unsigned HOST_WIDE_INT)
GET_MODE_MASK (GET_MODE (XEXP (x, 0))))
>> 1))
== 0))))
{
rtx temp = gen_rtx_SIGN_EXTEND (GET_MODE (x), XEXP (x, 0));
if (rtx_cost (temp, SET) < rtx_cost (x, SET))
return expand_compound_operation (temp);
}
}
modewidth = GET_MODE_BITSIZE (GET_MODE (x));
if (modewidth >= pos - len)
tem = simplify_shift_const (NULL_RTX, unsignedp ? LSHIFTRT : ASHIFTRT,
GET_MODE (x),
simplify_shift_const (NULL_RTX, ASHIFT,
GET_MODE (x),
XEXP (x, 0),
modewidth - pos - len),
modewidth - len);
else if (unsignedp && len < HOST_BITS_PER_WIDE_INT)
tem = simplify_and_const_int (NULL_RTX, GET_MODE (x),
simplify_shift_const (NULL_RTX, LSHIFTRT,
GET_MODE (x),
XEXP (x, 0), pos),
((HOST_WIDE_INT) 1 << len) - 1);
else
return x;
if (GET_CODE (tem) == CLOBBER)
return x;
return tem;
}
static rtx
expand_field_assignment (x)
rtx x;
{
rtx inner;
rtx pos;
int len;
rtx mask;
enum machine_mode compute_mode;
while (1)
{
if (GET_CODE (SET_DEST (x)) == STRICT_LOW_PART
&& GET_CODE (XEXP (SET_DEST (x), 0)) == SUBREG)
{
inner = SUBREG_REG (XEXP (SET_DEST (x), 0));
len = GET_MODE_BITSIZE (GET_MODE (XEXP (SET_DEST (x), 0)));
pos = GEN_INT (BITS_PER_WORD * SUBREG_WORD (XEXP (SET_DEST (x), 0)));
}
else if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT
&& GET_CODE (XEXP (SET_DEST (x), 1)) == CONST_INT)
{
inner = XEXP (SET_DEST (x), 0);
len = INTVAL (XEXP (SET_DEST (x), 1));
pos = XEXP (SET_DEST (x), 2);
if (GET_CODE (pos) == CONST_INT
&& INTVAL (pos) + len > GET_MODE_BITSIZE (GET_MODE (inner)))
inner = gen_rtx_USE (GET_MODE (SET_DEST (x)), inner);
if (BITS_BIG_ENDIAN)
{
if (GET_CODE (pos) == CONST_INT)
pos = GEN_INT (GET_MODE_BITSIZE (GET_MODE (inner)) - len
- INTVAL (pos));
else if (GET_CODE (pos) == MINUS
&& GET_CODE (XEXP (pos, 1)) == CONST_INT
&& (INTVAL (XEXP (pos, 1))
== GET_MODE_BITSIZE (GET_MODE (inner)) - len))
pos = XEXP (pos, 0);
else
pos = gen_binary (MINUS, GET_MODE (pos),
GEN_INT (GET_MODE_BITSIZE (GET_MODE (inner))
- len),
pos);
}
}
else if (GET_CODE (SET_DEST (x)) == SUBREG
&& (((GET_MODE_SIZE (GET_MODE (SET_DEST (x)))
+ (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
== ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (x))))
+ (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)))
{
x = gen_rtx_SET (VOIDmode, SUBREG_REG (SET_DEST (x)),
gen_lowpart_for_combine (GET_MODE (SUBREG_REG (SET_DEST (x))),
SET_SRC (x)));
continue;
}
else
break;
while (GET_CODE (inner) == SUBREG && subreg_lowpart_p (inner))
inner = SUBREG_REG (inner);
compute_mode = GET_MODE (inner);
if (! INTEGRAL_MODE_P (compute_mode))
{
enum machine_mode imode;
if (! FLOAT_MODE_P (compute_mode))
break;
imode = mode_for_size (GET_MODE_BITSIZE (compute_mode), MODE_INT, 0);
if (imode == BLKmode)
break;
compute_mode = imode;
inner = gen_lowpart_for_combine (imode, inner);
}
if (len < HOST_BITS_PER_WIDE_INT)
mask = GEN_INT (((HOST_WIDE_INT) 1 << len) - 1);
else
break;
x = gen_rtx_SET (VOIDmode, copy_rtx (inner),
gen_binary (IOR, compute_mode,
gen_binary (AND, compute_mode,
gen_unary (NOT, compute_mode,
compute_mode,
gen_binary (ASHIFT,
compute_mode,
mask, pos)),
inner),
gen_binary (ASHIFT, compute_mode,
gen_binary (AND, compute_mode,
gen_lowpart_for_combine
(compute_mode,
SET_SRC (x)),
mask),
pos)));
}
return x;
}
static rtx
make_extraction (mode, inner, pos, pos_rtx, len,
unsignedp, in_dest, in_compare)
enum machine_mode mode;
rtx inner;
int pos;
rtx pos_rtx;
int len;
int unsignedp;
int in_dest, in_compare;
{
enum machine_mode is_mode = GET_MODE (inner);
enum machine_mode inner_mode;
enum machine_mode wanted_inner_mode = byte_mode;
enum machine_mode wanted_inner_reg_mode = word_mode;
enum machine_mode pos_mode = word_mode;
enum machine_mode extraction_mode = word_mode;
enum machine_mode tmode = mode_for_size (len, MODE_INT, 1);
int spans_byte = 0;
rtx new = 0;
rtx orig_pos_rtx = pos_rtx;
int orig_pos;
if (GET_CODE (inner) == USE)
spans_byte = 1, inner = XEXP (inner, 0);
else if (GET_CODE (inner) == SUBREG && subreg_lowpart_p (inner))
{
if (GET_CODE (SUBREG_REG (inner)) == MEM)
is_mode = GET_MODE (SUBREG_REG (inner));
inner = SUBREG_REG (inner);
}
inner_mode = GET_MODE (inner);
if (pos_rtx && GET_CODE (pos_rtx) == CONST_INT)
pos = INTVAL (pos_rtx), pos_rtx = 0;
if (tmode != BLKmode
&& ! (spans_byte && inner_mode != tmode)
&& ((pos_rtx == 0 && (pos % BITS_PER_WORD) == 0
&& GET_CODE (inner) != MEM
&& (! in_dest
|| (GET_CODE (inner) == REG
&& (movstrict_optab->handlers[(int) tmode].insn_code
!= CODE_FOR_nothing))))
|| (GET_CODE (inner) == MEM && pos_rtx == 0
&& (pos
% (STRICT_ALIGNMENT ? GET_MODE_ALIGNMENT (tmode)
: BITS_PER_UNIT)) == 0
&& GET_MODE_BITSIZE (inner_mode) >= GET_MODE_BITSIZE (tmode)
&& (inner_mode == tmode
|| (! mode_dependent_address_p (XEXP (inner, 0))
&& ! MEM_VOLATILE_P (inner))))))
{
if (GET_CODE (inner) == MEM)
{
int offset;
if (BYTES_BIG_ENDIAN)
offset = (GET_MODE_BITSIZE (is_mode) - len - pos) / BITS_PER_UNIT;
else
offset = pos / BITS_PER_UNIT;
new = gen_rtx_MEM (tmode, plus_constant (XEXP (inner, 0), offset));
RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (inner);
MEM_COPY_ATTRIBUTES (new, inner);
}
else if (GET_CODE (inner) == REG)
{
if (tmode != inner_mode)
new = gen_rtx_SUBREG (tmode, inner,
(WORDS_BIG_ENDIAN
&& GET_MODE_SIZE (inner_mode) > UNITS_PER_WORD
? (((GET_MODE_SIZE (inner_mode)
- GET_MODE_SIZE (tmode))
/ UNITS_PER_WORD)
- pos / BITS_PER_WORD)
: pos / BITS_PER_WORD));
else
new = inner;
}
else
new = force_to_mode (inner, tmode,
len >= HOST_BITS_PER_WIDE_INT
? GET_MODE_MASK (tmode)
: ((HOST_WIDE_INT) 1 << len) - 1,
NULL_RTX, 0);
if (in_dest)
return (GET_CODE (new) == MEM ? new
: (GET_CODE (new) != SUBREG
? gen_rtx_CLOBBER (tmode, const0_rtx)
: gen_rtx_combine (STRICT_LOW_PART, VOIDmode, new)));
return (mode == tmode ? new
: gen_rtx_combine (unsignedp ? ZERO_EXTEND : SIGN_EXTEND,
mode, new));
}
if (pos_rtx == 0 && pos == 0 && ! in_dest
&& ! in_compare && ! spans_byte && unsignedp)
return 0;
if (! spans_byte
&& ((pos_rtx == 0 && pos + len > GET_MODE_BITSIZE (is_mode))
|| (pos_rtx != 0 && len != 1)))
return 0;
#ifdef HAVE_insv
if (in_dest)
{
wanted_inner_reg_mode
= (insn_operand_mode[(int) CODE_FOR_insv][0] == VOIDmode
? word_mode
: insn_operand_mode[(int) CODE_FOR_insv][0]);
pos_mode = (insn_operand_mode[(int) CODE_FOR_insv][2] == VOIDmode
? word_mode : insn_operand_mode[(int) CODE_FOR_insv][2]);
extraction_mode = (insn_operand_mode[(int) CODE_FOR_insv][3] == VOIDmode
? word_mode
: insn_operand_mode[(int) CODE_FOR_insv][3]);
}
#endif
#ifdef HAVE_extzv
if (! in_dest && unsignedp)
{
wanted_inner_reg_mode
= (insn_operand_mode[(int) CODE_FOR_extzv][1] == VOIDmode
? word_mode
: insn_operand_mode[(int) CODE_FOR_extzv][1]);
pos_mode = (insn_operand_mode[(int) CODE_FOR_extzv][3] == VOIDmode
? word_mode : insn_operand_mode[(int) CODE_FOR_extzv][3]);
extraction_mode = (insn_operand_mode[(int) CODE_FOR_extzv][0] == VOIDmode
? word_mode
: insn_operand_mode[(int) CODE_FOR_extzv][0]);
}
#endif
#ifdef HAVE_extv
if (! in_dest && ! unsignedp)
{
wanted_inner_reg_mode
= (insn_operand_mode[(int) CODE_FOR_extv][1] == VOIDmode
? word_mode
: insn_operand_mode[(int) CODE_FOR_extv][1]);
pos_mode = (insn_operand_mode[(int) CODE_FOR_extv][3] == VOIDmode
? word_mode : insn_operand_mode[(int) CODE_FOR_extv][3]);
extraction_mode = (insn_operand_mode[(int) CODE_FOR_extv][0] == VOIDmode
? word_mode
: insn_operand_mode[(int) CODE_FOR_extv][0]);
}
#endif
if (mode != VOIDmode
&& GET_MODE_SIZE (extraction_mode) < GET_MODE_SIZE (mode))
extraction_mode = mode;
if (pos_rtx && GET_MODE (pos_rtx) != VOIDmode
&& GET_MODE_SIZE (pos_mode) < GET_MODE_SIZE (GET_MODE (pos_rtx)))
pos_mode = GET_MODE (pos_rtx);
if (GET_CODE (inner) != MEM)
wanted_inner_mode = wanted_inner_reg_mode;
else if (inner_mode != wanted_inner_mode
&& (mode_dependent_address_p (XEXP (inner, 0))
|| MEM_VOLATILE_P (inner)))
wanted_inner_mode = extraction_mode;
orig_pos = pos;
if (BITS_BIG_ENDIAN)
{
int width = (GET_CODE (inner) == MEM
? GET_MODE_BITSIZE (is_mode)
: GET_MODE_BITSIZE (wanted_inner_mode));
if (pos_rtx == 0)
pos = width - len - pos;
else
pos_rtx
= gen_rtx_combine (MINUS, GET_MODE (pos_rtx),
GEN_INT (width - len), pos_rtx);
}
if (wanted_inner_mode != VOIDmode
&& GET_MODE_SIZE (wanted_inner_mode) < GET_MODE_SIZE (is_mode)
&& ((GET_CODE (inner) == MEM
&& (inner_mode == wanted_inner_mode
|| (! mode_dependent_address_p (XEXP (inner, 0))
&& ! MEM_VOLATILE_P (inner))))))
{
int offset = 0;
if (BYTES_BIG_ENDIAN
&& ! spans_byte
&& GET_MODE_SIZE (inner_mode) < GET_MODE_SIZE (is_mode))
offset -= GET_MODE_SIZE (is_mode) - GET_MODE_SIZE (inner_mode);
if (pos_rtx == 0)
{
offset += pos / BITS_PER_UNIT;
pos %= GET_MODE_BITSIZE (wanted_inner_mode);
}
if (BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN
&& ! spans_byte
&& is_mode != wanted_inner_mode)
offset = (GET_MODE_SIZE (is_mode)
- GET_MODE_SIZE (wanted_inner_mode) - offset);
if (offset != 0 || inner_mode != wanted_inner_mode)
{
rtx newmem = gen_rtx_MEM (wanted_inner_mode,
plus_constant (XEXP (inner, 0), offset));
RTX_UNCHANGING_P (newmem) = RTX_UNCHANGING_P (inner);
MEM_COPY_ATTRIBUTES (newmem, inner);
inner = newmem;
}
}
else if (GET_CODE (inner) != MEM)
{
if (GET_MODE (inner) != wanted_inner_mode
&& (pos_rtx != 0
|| orig_pos + len > GET_MODE_BITSIZE (wanted_inner_mode)))
return 0;
inner = force_to_mode (inner, wanted_inner_mode,
pos_rtx
|| len + orig_pos >= HOST_BITS_PER_WIDE_INT
? GET_MODE_MASK (wanted_inner_mode)
: (((HOST_WIDE_INT) 1 << len) - 1) << orig_pos,
NULL_RTX, 0);
}
if (pos_rtx != 0
&& GET_MODE_SIZE (pos_mode) > GET_MODE_SIZE (GET_MODE (pos_rtx)))
pos_rtx = gen_rtx_combine (ZERO_EXTEND, pos_mode, pos_rtx);
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);
if (pos_rtx == 0 && orig_pos_rtx != 0 && INTVAL (orig_pos_rtx) == pos)
pos_rtx = orig_pos_rtx;
else if (pos_rtx == 0)
pos_rtx = GEN_INT (pos);
new = gen_rtx_combine (unsignedp ? ZERO_EXTRACT : SIGN_EXTRACT,
extraction_mode, inner, GEN_INT (len), pos_rtx);
if (! in_dest)
new = gen_lowpart_for_combine (mode, new);
return new;
}
static rtx
extract_left_shift (x, count)
rtx x;
int count;
{
enum rtx_code code = GET_CODE (x);
enum machine_mode mode = GET_MODE (x);
rtx tem;
switch (code)
{
case ASHIFT:
if (GET_CODE (XEXP (x, 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) >= count)
return simplify_shift_const (NULL_RTX, ASHIFT, mode, XEXP (x, 0),
INTVAL (XEXP (x, 1)) - count);
break;
case NEG: case NOT:
if ((tem = extract_left_shift (XEXP (x, 0), count)) != 0)
return gen_unary (code, mode, mode, tem);
break;
case PLUS: case IOR: case XOR: case AND:
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,
GEN_INT (INTVAL (XEXP (x, 1)) >> count));
break;
default:
break;
}
return 0;
}
static rtx
make_compound_operation (x, in_code)
rtx x;
enum rtx_code in_code;
{
enum rtx_code code = GET_CODE (x);
enum machine_mode mode = GET_MODE (x);
int mode_width = GET_MODE_BITSIZE (mode);
rtx rhs, lhs;
enum rtx_code next_code;
int i;
rtx new = 0;
rtx tem;
char *fmt;
next_code = (code == MEM || code == PLUS || code == MINUS ? MEM
: ((code == COMPARE || GET_RTX_CLASS (code) == '<')
&& XEXP (x, 1) == const0_rtx) ? COMPARE
: in_code == COMPARE ? SET : in_code);
switch (code)
{
case ASHIFT:
if (in_code == MEM && GET_CODE (XEXP (x, 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT
&& INTVAL (XEXP (x, 1)) >= 0)
{
new = make_compound_operation (XEXP (x, 0), next_code);
new = gen_rtx_combine (MULT, mode, new,
GEN_INT ((HOST_WIDE_INT) 1
<< INTVAL (XEXP (x, 1))));
}
break;
case AND:
if (GET_CODE (XEXP (x, 1)) != CONST_INT)
break;
if (GET_CODE (XEXP (x, 0)) == LSHIFTRT
&& (i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0)
{
new = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code);
new = make_extraction (mode, new, 0, XEXP (XEXP (x, 0), 1), i, 1,
0, in_code == COMPARE);
}
else if (GET_CODE (XEXP (x, 0)) == SUBREG
&& subreg_lowpart_p (XEXP (x, 0))
&& GET_CODE (SUBREG_REG (XEXP (x, 0))) == LSHIFTRT
&& (i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0)
{
new = make_compound_operation (XEXP (SUBREG_REG (XEXP (x, 0)), 0),
next_code);
new = make_extraction (GET_MODE (SUBREG_REG (XEXP (x, 0))), new, 0,
XEXP (SUBREG_REG (XEXP (x, 0)), 1), i, 1,
0, in_code == COMPARE);
}
else if ((GET_CODE (XEXP (x, 0)) == XOR
|| GET_CODE (XEXP (x, 0)) == IOR)
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == LSHIFTRT
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == LSHIFTRT
&& (i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0)
{
new = gen_rtx_combine (GET_CODE (XEXP (x, 0)), mode,
gen_rtx_AND (mode, XEXP (XEXP (x, 0), 0),
XEXP (x, 1)),
gen_rtx_AND (mode, XEXP (XEXP (x, 0), 1),
XEXP (x, 1)));
new = make_compound_operation (new, in_code);
}
else if (GET_CODE (XEXP (x, 0)) == ROTATE
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
&& (i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0
&& i <= INTVAL (XEXP (XEXP (x, 0), 1)))
{
new = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code);
new = make_extraction (mode, new,
(GET_MODE_BITSIZE (mode)
- INTVAL (XEXP (XEXP (x, 0), 1))),
NULL_RTX, i, 1, 0, in_code == COMPARE);
}
else if (ashr_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing
&& (lshr_optab->handlers[(int) mode].insn_code
== CODE_FOR_nothing)
&& GET_CODE (XEXP (x, 0)) == LSHIFTRT
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
&& INTVAL (XEXP (XEXP (x, 0), 1)) >= 0
&& INTVAL (XEXP (XEXP (x, 0), 1)) < HOST_BITS_PER_WIDE_INT
&& mode_width <= HOST_BITS_PER_WIDE_INT)
{
unsigned HOST_WIDE_INT mask = GET_MODE_MASK (mode);
mask >>= INTVAL (XEXP (XEXP (x, 0), 1));
if ((INTVAL (XEXP (x, 1)) & ~mask) == 0)
SUBST (XEXP (x, 0),
gen_rtx_combine (ASHIFTRT, mode,
make_compound_operation (XEXP (XEXP (x, 0), 0),
next_code),
XEXP (XEXP (x, 0), 1)));
}
else if ((i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0)
new = make_extraction (mode,
make_compound_operation (XEXP (x, 0),
next_code),
0, NULL_RTX, i, 1, 0, in_code == COMPARE);
else if (in_code == COMPARE
&& (i = exact_log2 (INTVAL (XEXP (x, 1)))) >= 0)
new = make_extraction (mode,
make_compound_operation (XEXP (x, 0),
next_code),
i, NULL_RTX, 1, 1, 0, 1);
break;
case LSHIFTRT:
if (ashr_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing
&& lshr_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing
&& mode_width <= HOST_BITS_PER_WIDE_INT
&& (nonzero_bits (XEXP (x, 0), mode) & (1 << (mode_width - 1))) == 0)
{
new = gen_rtx_combine (ASHIFTRT, mode,
make_compound_operation (XEXP (x, 0),
next_code),
XEXP (x, 1));
break;
}
case ASHIFTRT:
lhs = XEXP (x, 0);
rhs = XEXP (x, 1);
if (GET_CODE (rhs) == CONST_INT
&& GET_CODE (lhs) == ASHIFT
&& GET_CODE (XEXP (lhs, 1)) == CONST_INT
&& INTVAL (rhs) >= INTVAL (XEXP (lhs, 1)))
{
new = make_compound_operation (XEXP (lhs, 0), next_code);
new = make_extraction (mode, new,
INTVAL (rhs) - INTVAL (XEXP (lhs, 1)),
NULL_RTX, mode_width - INTVAL (rhs),
code == LSHIFTRT, 0, in_code == COMPARE);
}
if (GET_RTX_CLASS (GET_CODE (lhs)) != 'o'
&& ! (GET_CODE (lhs) == SUBREG
&& (GET_RTX_CLASS (GET_CODE (SUBREG_REG (lhs))) == 'o'))
&& GET_CODE (rhs) == CONST_INT
&& INTVAL (rhs) < HOST_BITS_PER_WIDE_INT
&& (new = extract_left_shift (lhs, INTVAL (rhs))) != 0)
new = make_extraction (mode, make_compound_operation (new, next_code),
0, NULL_RTX, mode_width - INTVAL (rhs),
code == LSHIFTRT, 0, in_code == COMPARE);
break;
case SUBREG:
tem = make_compound_operation (SUBREG_REG (x), in_code);
if (GET_CODE (tem) != GET_CODE (SUBREG_REG (x))
&& GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (tem))
&& subreg_lowpart_p (x))
{
rtx newer = force_to_mode (tem, mode,
GET_MODE_MASK (mode), NULL_RTX, 0);
if (GET_CODE (newer) != SUBREG)
newer = make_compound_operation (newer, in_code);
return newer;
}
if ((GET_CODE (tem) == SIGN_EXTEND
|| GET_CODE (tem) == ZERO_EXTEND)
&& subreg_lowpart_p (x))
{
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_combine (GET_CODE (tem), mode, XEXP (tem, 0));
else
tem = gen_lowpart_for_combine (mode, XEXP (tem, 0));
return tem;
}
break;
default:
break;
}
if (new)
{
x = gen_lowpart_for_combine (mode, new);
code = GET_CODE (x);
}
fmt = GET_RTX_FORMAT (code);
for (i = 0; i < GET_RTX_LENGTH (code); i++)
if (fmt[i] == 'e')
{
new = make_compound_operation (XEXP (x, i), next_code);
SUBST (XEXP (x, i), new);
}
return x;
}
static int
get_pos_from_mask (m, plen)
unsigned HOST_WIDE_INT m;
int *plen;
{
int pos = exact_log2 (m & - m);
if (pos < 0)
return -1;
*plen = exact_log2 ((m >> pos) + 1);
if (*plen <= 0)
return -1;
return pos;
}
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;
{
enum rtx_code code = GET_CODE (x);
int next_select = just_select || code == XOR || code == NOT || code == NEG;
enum machine_mode op_mode;
unsigned HOST_WIDE_INT fuller_mask, nonzero;
rtx op0, op1, temp;
if (code == CALL || code == ASM_OPERANDS || code == CLOBBER)
return x;
op_mode = ((GET_MODE_CLASS (mode) == GET_MODE_CLASS (GET_MODE (x))
&& code_to_optab[(int) code] != 0
&& (code_to_optab[(int) code]->handlers[(int) mode].insn_code
!= CODE_FOR_nothing))
? mode : GET_MODE (x));
if ((code == LSHIFTRT || code == ASHIFTRT)
&& GET_MODE_BITSIZE (mode) < GET_MODE_BITSIZE (GET_MODE (x)))
op_mode = GET_MODE (x);
if (op_mode)
mask &= GET_MODE_MASK (op_mode);
if (op_mode)
fuller_mask = (GET_MODE_BITSIZE (op_mode) >= HOST_BITS_PER_WIDE_INT
? GET_MODE_MASK (op_mode)
: ((HOST_WIDE_INT) 1 << (floor_log2 (mask) + 1)) - 1);
else
fuller_mask = ~ (HOST_WIDE_INT) 0;
nonzero = nonzero_bits (x, mode);
if (! just_select && (nonzero & mask) == 0)
return const0_rtx;
if (GET_CODE (x) == CONST_INT)
{
HOST_WIDE_INT cval = INTVAL (x) & mask;
int width = GET_MODE_BITSIZE (mode);
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 (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);
if (GET_MODE (x) == mode && code != SUBREG && (~ mask & nonzero) == 0)
return x;
switch (code)
{
case CLOBBER:
return x;
case USE:
if (! BITS_BIG_ENDIAN
&& (mask & ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
return force_to_mode (XEXP (x, 0), mode, mask, reg, next_select);
break;
case SIGN_EXTEND:
case ZERO_EXTEND:
case ZERO_EXTRACT:
case SIGN_EXTRACT:
x = expand_compound_operation (x);
if (GET_CODE (x) != code)
return force_to_mode (x, mode, mask, reg, next_select);
break;
case REG:
if (reg != 0 && (rtx_equal_p (get_last_value (reg), x)
|| rtx_equal_p (reg, get_last_value (x))))
x = reg;
break;
case SUBREG:
if (subreg_lowpart_p (x)
&& ((GET_MODE_SIZE (GET_MODE (x))
< GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
|| (0 == (mask
& GET_MODE_MASK (GET_MODE (x))
& ~ GET_MODE_MASK (GET_MODE (SUBREG_REG (x)))))))
return force_to_mode (SUBREG_REG (x), mode, mask, reg, next_select);
break;
case AND:
if (GET_CODE (XEXP (x, 1)) == CONST_INT)
{
x = simplify_and_const_int (x, op_mode, XEXP (x, 0),
mask & INTVAL (XEXP (x, 1)));
if (GET_CODE (x) == AND && GET_CODE (XEXP (x, 1)) == CONST_INT
&& (unsigned HOST_WIDE_INT) INTVAL (XEXP (x, 1)) == mask)
x = XEXP (x, 0);
if (GET_CODE (x) == AND && GET_CODE (XEXP (x, 1)) == CONST_INT
&& GET_MODE_MASK (GET_MODE (x)) != mask
&& GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT)
{
HOST_WIDE_INT cval = (INTVAL (XEXP (x, 1))
| (GET_MODE_MASK (GET_MODE (x)) & ~ mask));
int width = GET_MODE_BITSIZE (GET_MODE (x));
rtx y;
if (width > 0 && width < HOST_BITS_PER_WIDE_INT
&& (cval & ((HOST_WIDE_INT) 1 << (width - 1))) != 0)
cval |= (HOST_WIDE_INT) -1 << width;
y = gen_binary (AND, GET_MODE (x), XEXP (x, 0), GEN_INT (cval));
if (rtx_cost (y, SET) < rtx_cost (x, SET))
x = y;
}
break;
}
goto binop;
case PLUS:
{
int width = GET_MODE_BITSIZE (mode);
unsigned HOST_WIDE_INT smask = mask;
if (width < HOST_BITS_PER_WIDE_INT
&& (smask & ((HOST_WIDE_INT) 1 << (width - 1))) != 0)
smask |= (HOST_WIDE_INT) -1 << width;
if (GET_CODE (XEXP (x, 1)) == CONST_INT
&& exact_log2 (- smask) >= 0)
{
#ifdef STACK_BIAS
if (STACK_BIAS
&& (XEXP (x, 0) == stack_pointer_rtx
|| XEXP (x, 0) == frame_pointer_rtx))
{
int sp_alignment = STACK_BOUNDARY / BITS_PER_UNIT;
unsigned HOST_WIDE_INT sp_mask = GET_MODE_MASK (mode);
sp_mask &= ~ (sp_alignment - 1);
if ((sp_mask & ~ smask) == 0
&& ((INTVAL (XEXP (x, 1)) - STACK_BIAS) & ~ smask) != 0)
return force_to_mode (plus_constant (XEXP (x, 0),
((INTVAL (XEXP (x, 1)) -
STACK_BIAS) & smask)
+ STACK_BIAS),
mode, smask, reg, next_select);
}
#endif
if ((nonzero_bits (XEXP (x, 0), mode) & ~ smask) == 0
&& (INTVAL (XEXP (x, 1)) & ~ smask) != 0)
return force_to_mode (plus_constant (XEXP (x, 0),
(INTVAL (XEXP (x, 1))
& smask)),
mode, smask, reg, next_select);
}
}
case MINUS:
case MULT:
mask = fuller_mask;
goto binop;
case IOR:
case XOR:
if (GET_CODE (XEXP (x, 0)) == LSHIFTRT
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
&& INTVAL (XEXP (XEXP (x, 0), 1)) >= 0
&& INTVAL (XEXP (XEXP (x, 0), 1)) < HOST_BITS_PER_WIDE_INT
&& GET_CODE (XEXP (x, 1)) == CONST_INT
&& ((INTVAL (XEXP (XEXP (x, 0), 1))
+ floor_log2 (INTVAL (XEXP (x, 1))))
< GET_MODE_BITSIZE (GET_MODE (x)))
&& (INTVAL (XEXP (x, 1))
& ~ nonzero_bits (XEXP (x, 0), GET_MODE (x))) == 0)
{
temp = GEN_INT ((INTVAL (XEXP (x, 1)) & mask)
<< INTVAL (XEXP (XEXP (x, 0), 1)));
temp = gen_binary (GET_CODE (x), GET_MODE (x),
XEXP (XEXP (x, 0), 0), temp);
x = gen_binary (LSHIFTRT, GET_MODE (x), temp,
XEXP (XEXP (x, 0), 1));
return force_to_mode (x, mode, mask, reg, next_select);
}
binop:
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 (GET_CODE (op1) == CONST_INT && (code == IOR || code == XOR)
&& (INTVAL (op1) & mask) != 0)
op1 = GEN_INT (INTVAL (op1) & mask);
if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
x = gen_binary (code, op_mode, op0, op1);
break;
case ASHIFT:
if (! (GET_CODE (XEXP (x, 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) >= 0
&& INTVAL (XEXP (x, 1)) < GET_MODE_BITSIZE (mode))
&& ! (GET_MODE (XEXP (x, 1)) != VOIDmode
&& (nonzero_bits (XEXP (x, 1), GET_MODE (XEXP (x, 1)))
< (unsigned HOST_WIDE_INT) GET_MODE_BITSIZE (mode))))
break;
if (GET_CODE (XEXP (x, 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) >= 0
&& INTVAL (XEXP (x, 1)) < GET_MODE_BITSIZE (op_mode)
&& GET_MODE_BITSIZE (op_mode) <= HOST_BITS_PER_WIDE_INT)
mask >>= INTVAL (XEXP (x, 1));
else
mask = fuller_mask;
op0 = gen_lowpart_for_combine (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));
break;
case LSHIFTRT:
if (GET_CODE (XEXP (x, 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT
&& GET_MODE_BITSIZE (op_mode) <= HOST_BITS_PER_WIDE_INT)
{
rtx inner = XEXP (x, 0);
mask <<= INTVAL (XEXP (x, 1));
if (GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT
|| (mask & ~ GET_MODE_MASK (op_mode)) != 0)
op_mode = GET_MODE (x);
inner = force_to_mode (inner, op_mode, mask, reg, next_select);
if (GET_MODE (x) != op_mode || inner != XEXP (x, 0))
x = gen_binary (LSHIFTRT, op_mode, inner, XEXP (x, 1));
}
if (GET_CODE (x) == LSHIFTRT
&& GET_CODE (XEXP (x, 1)) == CONST_INT
&& ((INTVAL (XEXP (x, 1))
+ num_sign_bit_copies (XEXP (x, 0), GET_MODE (XEXP (x, 0))))
>= GET_MODE_BITSIZE (GET_MODE (x)))
&& exact_log2 (mask + 1) >= 0
&& (num_sign_bit_copies (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
>= exact_log2 (mask + 1)))
x = gen_binary (LSHIFTRT, GET_MODE (x), XEXP (x, 0),
GEN_INT (GET_MODE_BITSIZE (GET_MODE (x))
- exact_log2 (mask + 1)));
break;
case ASHIFTRT:
if (GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
&& (mask == ((unsigned HOST_WIDE_INT) 1
<< (GET_MODE_BITSIZE (GET_MODE (x)) - 1))))
return force_to_mode (XEXP (x, 0), mode, mask, reg, next_select);
if (GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0
&& INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT)
{
int i = -1;
if (GET_MODE_BITSIZE (GET_MODE (x)) > HOST_BITS_PER_WIDE_INT)
{
nonzero = ~ (HOST_WIDE_INT) 0;
if (GET_MODE_BITSIZE (GET_MODE (x)) - INTVAL (XEXP (x, 1))
< HOST_BITS_PER_WIDE_INT)
nonzero >>= INTVAL (XEXP (x, 1))
+ HOST_BITS_PER_WIDE_INT
- GET_MODE_BITSIZE (GET_MODE (x)) ;
}
else
{
nonzero = GET_MODE_MASK (GET_MODE (x));
nonzero >>= INTVAL (XEXP (x, 1));
}
if ((mask & ~ nonzero) == 0
|| (i = exact_log2 (mask)) >= 0)
{
x = simplify_shift_const
(x, LSHIFTRT, GET_MODE (x), XEXP (x, 0),
i < 0 ? INTVAL (XEXP (x, 1))
: GET_MODE_BITSIZE (GET_MODE (x)) - 1 - i);
if (GET_CODE (x) != ASHIFTRT)
return force_to_mode (x, mode, mask, reg, next_select);
}
}
if (mask == 1)
x = gen_binary (LSHIFTRT, GET_MODE (x), XEXP (x, 0), XEXP (x, 1));
if ((GET_CODE (x) == LSHIFTRT || GET_CODE (x) == ASHIFTRT)
&& GET_CODE (XEXP (x, 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) >= 0
&& (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)))
return force_to_mode (XEXP (XEXP (x, 0), 0), mode, mask,
reg, next_select);
break;
case ROTATE:
case ROTATERT:
if (GET_CODE (XEXP (x, 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) >= 0)
{
temp = simplify_binary_operation (code == ROTATE ? ROTATERT : ROTATE,
GET_MODE (x), GEN_INT (mask),
XEXP (x, 1));
if (temp && GET_CODE(temp) == CONST_INT)
SUBST (XEXP (x, 0),
force_to_mode (XEXP (x, 0), GET_MODE (x),
INTVAL (temp), reg, next_select));
}
break;
case NEG:
if (mask == 1)
return force_to_mode (XEXP (x, 0), mode, mask, reg, just_select);
mask = fuller_mask;
goto unop;
case NOT:
if (GET_CODE (XEXP (x, 0)) == LSHIFTRT
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
&& INTVAL (XEXP (XEXP (x, 0), 1)) >= 0
&& (INTVAL (XEXP (XEXP (x, 0), 1)) + floor_log2 (mask)
< 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_binary (XOR, GET_MODE (x), XEXP (XEXP (x, 0), 0), temp);
x = gen_binary (LSHIFTRT, GET_MODE (x), temp, XEXP (XEXP (x, 0), 1));
return force_to_mode (x, mode, mask, reg, next_select);
}
mask = fuller_mask;
unop:
op0 = gen_lowpart_for_combine (op_mode,
force_to_mode (XEXP (x, 0), mode, mask,
reg, next_select));
if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0))
x = gen_unary (code, op_mode, op_mode, op0);
break;
case NE:
if ((mask & ~ STORE_FLAG_VALUE) == 0 && XEXP (x, 1) == const0_rtx
&& exact_log2 (nonzero_bits (XEXP (x, 0), mode)) >= 0
&& nonzero_bits (XEXP (x, 0), mode) == STORE_FLAG_VALUE)
return force_to_mode (XEXP (x, 0), mode, mask, reg, next_select);
break;
case IF_THEN_ELSE:
SUBST (XEXP (x, 1),
gen_lowpart_for_combine (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),
force_to_mode (XEXP (x, 2), mode,
mask, reg,next_select)));
break;
default:
break;
}
return gen_lowpart_for_combine (mode, x);
}
static rtx
if_then_else_cond (x, ptrue, pfalse)
rtx x;
rtx *ptrue, *pfalse;
{
enum machine_mode mode = GET_MODE (x);
enum rtx_code code = GET_CODE (x);
int size = GET_MODE_BITSIZE (mode);
rtx cond0, cond1, true0, true1, false0, false1;
unsigned HOST_WIDE_INT nz;
if (GET_RTX_CLASS (code) == '1'
&& (cond0 = if_then_else_cond (XEXP (x, 0), &true0, &false0)) != 0)
{
*ptrue = gen_unary (code, mode, GET_MODE (XEXP (x, 0)), true0);
*pfalse = gen_unary (code, mode, GET_MODE (XEXP (x, 0)), false0);
return cond0;
}
else if (code == COMPARE)
;
else if (GET_RTX_CLASS (code) == 'c' || GET_RTX_CLASS (code) == '2'
|| GET_RTX_CLASS (code) == '<')
{
cond0 = if_then_else_cond (XEXP (x, 0), &true0, &false0);
cond1 = if_then_else_cond (XEXP (x, 1), &true1, &false1);
if ((cond0 != 0 || cond1 != 0)
&& ! (cond0 != 0 && cond1 != 0 && ! rtx_equal_p (cond0, cond1)))
{
if (cond0 == 0)
true0 = copy_rtx (true0);
else if (cond1 == 0)
true1 = copy_rtx (true1);
*ptrue = gen_binary (code, mode, true0, true1);
*pfalse = gen_binary (code, mode, false0, false1);
return cond0 ? cond0 : cond1;
}
if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
&& (code == PLUS || code == IOR || code == XOR || code == MINUS
|| code == UMAX)
&& GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (x, 1)) == MULT)
{
rtx op0 = XEXP (XEXP (x, 0), 1);
rtx op1 = XEXP (XEXP (x, 1), 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)) == '<'
&& reversible_comparison_p (cond1)
&& ((GET_CODE (cond0) == reverse_condition (GET_CODE (cond1))
&& rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 0))
&& rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 1)))
|| ((swap_condition (GET_CODE (cond0))
== reverse_condition (GET_CODE (cond1)))
&& rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 1))
&& rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 0))))
&& ! side_effects_p (x))
{
*ptrue = gen_binary (MULT, mode, op0, const_true_rtx);
*pfalse = gen_binary (MULT, mode,
(code == MINUS
? gen_unary (NEG, mode, mode, op1) : op1),
const_true_rtx);
return cond0;
}
}
if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
&& (code == MULT || code == AND || code == UMIN)
&& GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (x, 1)) == MULT)
{
cond0 = XEXP (XEXP (x, 0), 0);
cond1 = XEXP (XEXP (x, 1), 0);
if (GET_RTX_CLASS (GET_CODE (cond0)) == '<'
&& GET_RTX_CLASS (GET_CODE (cond1)) == '<'
&& reversible_comparison_p (cond1)
&& ((GET_CODE (cond0) == reverse_condition (GET_CODE (cond1))
&& rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 0))
&& rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 1)))
|| ((swap_condition (GET_CODE (cond0))
== reverse_condition (GET_CODE (cond1)))
&& rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 1))
&& rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 0))))
&& ! side_effects_p (x))
{
*ptrue = *pfalse = const0_rtx;
return cond0;
}
}
}
else if (code == IF_THEN_ELSE)
{
cond0 = XEXP (x, 0);
*ptrue = XEXP (x, 1), *pfalse = XEXP (x, 2);
if (GET_CODE (cond0) == NE && XEXP (cond0, 1) == const0_rtx)
return XEXP (cond0, 0);
else if (GET_CODE (cond0) == EQ && XEXP (cond0, 1) == const0_rtx)
{
*ptrue = XEXP (x, 2), *pfalse = XEXP (x, 1);
return XEXP (cond0, 0);
}
else
return cond0;
}
else if (code == SUBREG && GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_CLASS (GET_MODE (SUBREG_REG (x))) == MODE_INT
&& GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
&& 0 != (cond0 = if_then_else_cond (SUBREG_REG (x),
&true0, &false0)))
{
*ptrue = force_to_mode (true0, mode, GET_MODE_MASK (mode), NULL_RTX, 0);
*pfalse
= force_to_mode (false0, mode, GET_MODE_MASK (mode), NULL_RTX, 0);
return cond0;
}
else if (CONSTANT_P (x)
|| ((cond0 = get_last_value (x)) != 0 && CONSTANT_P (cond0)))
;
else if (num_sign_bit_copies (x, mode) == size)
{
*ptrue = constm1_rtx, *pfalse = const0_rtx;
return x;
}
else if (exact_log2 (nz = nonzero_bits (x, mode)) >= 0)
{
*ptrue = GEN_INT (nz), *pfalse = const0_rtx;
return x;
}
*ptrue = *pfalse = x;
return 0;
}
static rtx
known_cond (x, cond, reg, val)
rtx x;
enum rtx_code cond;
rtx reg, val;
{
enum rtx_code code = GET_CODE (x);
rtx temp;
char *fmt;
int i, j;
if (side_effects_p (x))
return x;
if (cond == EQ && rtx_equal_p (x, reg))
return val;
if (code == ABS && rtx_equal_p (XEXP (x, 0), reg) && val == const0_rtx)
switch (cond)
{
case GE: case GT: case EQ:
return XEXP (x, 0);
case LT: case LE:
return gen_unary (NEG, GET_MODE (XEXP (x, 0)), GET_MODE (XEXP (x, 0)),
XEXP (x, 0));
default:
break;
}
else if (GET_RTX_CLASS (code) == '<' || GET_RTX_CLASS (code) == 'c')
{
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) == '<')
return (comparison_dominates_p (cond, code) ? const_true_rtx
: (comparison_dominates_p (cond,
reverse_condition (code))
? const0_rtx : x));
else if (code == SMAX || code == SMIN
|| code == UMIN || code == UMAX)
{
int unsignedp = (code == UMIN || code == UMAX);
if (code == SMAX || code == UMAX)
cond = reverse_condition (cond);
switch (cond)
{
case GE: case GT:
return unsignedp ? x : XEXP (x, 1);
case LE: case LT:
return unsignedp ? x : XEXP (x, 0);
case GEU: case GTU:
return unsignedp ? XEXP (x, 1) : x;
case LEU: case LTU:
return unsignedp ? XEXP (x, 0) : x;
default:
break;
}
}
}
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
SUBST (XEXP (x, i), known_cond (XEXP (x, i), cond, reg, val));
else if (fmt[i] == 'E')
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
SUBST (XVECEXP (x, i, j), known_cond (XVECEXP (x, i, j),
cond, reg, val));
}
return x;
}
static int
rtx_equal_for_field_assignment_p (x, y)
rtx x;
rtx y;
{
if (x == y || rtx_equal_p (x, y))
return 1;
if (x == 0 || y == 0 || GET_MODE (x) != GET_MODE (y))
return 0;
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)))
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)))
return 1;
return 0;
}
static rtx
make_field_assignment (x)
rtx x;
{
rtx dest = SET_DEST (x);
rtx src = SET_SRC (x);
rtx assign;
rtx rhs, lhs;
HOST_WIDE_INT c1;
int pos, len;
rtx other;
enum machine_mode mode;
if (GET_CODE (src) == AND && GET_CODE (XEXP (src, 0)) == ROTATE
&& GET_CODE (XEXP (XEXP (src, 0), 0)) == CONST_INT
&& INTVAL (XEXP (XEXP (src, 0), 0)) == -2
&& rtx_equal_for_field_assignment_p (dest, XEXP (src, 1)))
{
assign = make_extraction (VOIDmode, dest, 0, XEXP (XEXP (src, 0), 1),
1, 1, 1, 0);
if (assign != 0)
return gen_rtx_SET (VOIDmode, assign, const0_rtx);
return x;
}
else if (GET_CODE (src) == AND && GET_CODE (XEXP (src, 0)) == SUBREG
&& subreg_lowpart_p (XEXP (src, 0))
&& (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
&& INTVAL (XEXP (SUBREG_REG (XEXP (src, 0)), 0)) == -2
&& rtx_equal_for_field_assignment_p (dest, XEXP (src, 1)))
{
assign = make_extraction (VOIDmode, dest, 0,
XEXP (SUBREG_REG (XEXP (src, 0)), 1),
1, 1, 1, 0);
if (assign != 0)
return gen_rtx_SET (VOIDmode, assign, const0_rtx);
return x;
}
else if (GET_CODE (src) == IOR && GET_CODE (XEXP (src, 0)) == ASHIFT
&& XEXP (XEXP (src, 0), 0) == const1_rtx
&& rtx_equal_for_field_assignment_p (dest, XEXP (src, 1)))
{
assign = make_extraction (VOIDmode, dest, 0, XEXP (XEXP (src, 0), 1),
1, 1, 1, 0);
if (assign != 0)
return gen_rtx_SET (VOIDmode, assign, const1_rtx);
return x;
}
if (GET_CODE (src) != IOR && GET_CODE (src) != XOR)
return x;
rhs = expand_compound_operation (XEXP (src, 0));
lhs = expand_compound_operation (XEXP (src, 1));
if (GET_CODE (rhs) == AND
&& GET_CODE (XEXP (rhs, 1)) == CONST_INT
&& rtx_equal_for_field_assignment_p (XEXP (rhs, 0), dest))
c1 = INTVAL (XEXP (rhs, 1)), other = lhs;
else if (GET_CODE (lhs) == AND
&& GET_CODE (XEXP (lhs, 1)) == CONST_INT
&& rtx_equal_for_field_assignment_p (XEXP (lhs, 0), dest))
c1 = INTVAL (XEXP (lhs, 1)), other = rhs;
else
return x;
pos = get_pos_from_mask ((~ c1) & GET_MODE_MASK (GET_MODE (dest)), &len);
if (pos < 0 || pos + len > GET_MODE_BITSIZE (GET_MODE (dest))
|| GET_MODE_BITSIZE (GET_MODE (dest)) > HOST_BITS_PER_WIDE_INT
|| (c1 & nonzero_bits (other, GET_MODE (dest))) != 0)
return x;
assign = make_extraction (VOIDmode, dest, pos, NULL_RTX, len, 1, 1, 0);
if (assign == 0)
return x;
mode = (GET_CODE (assign) == STRICT_LOW_PART
? GET_MODE (XEXP (assign, 0)) : GET_MODE (assign));
src = force_to_mode (simplify_shift_const (NULL_RTX, LSHIFTRT,
GET_MODE (src), other, pos),
mode,
GET_MODE_BITSIZE (mode) >= HOST_BITS_PER_WIDE_INT
? GET_MODE_MASK (mode)
: ((HOST_WIDE_INT) 1 << len) - 1,
dest, 0);
return gen_rtx_combine (SET, VOIDmode, assign, src);
}
static rtx
apply_distributive_law (x)
rtx x;
{
enum rtx_code code = GET_CODE (x);
rtx lhs, rhs, other;
rtx tem;
enum rtx_code inner_code;
if (FLOAT_MODE_P (GET_MODE (x)))
return x;
if (code != IOR && code != AND && code != XOR
&& code != PLUS && code != MINUS)
return x;
lhs = XEXP (x, 0), rhs = XEXP (x, 1);
if (GET_RTX_CLASS (GET_CODE (lhs)) == 'o'
|| GET_RTX_CLASS (GET_CODE (rhs)) == 'o')
return x;
lhs = expand_compound_operation (lhs);
rhs = expand_compound_operation (rhs);
inner_code = GET_CODE (lhs);
if (inner_code != GET_CODE (rhs))
return x;
switch (inner_code)
{
case LSHIFTRT:
case ASHIFTRT:
case AND:
case IOR:
if (code == PLUS || code == MINUS)
return x;
break;
case MULT:
if (code != PLUS && code != MINUS)
return x;
break;
case ASHIFT:
break;
case SUBREG:
if (GET_MODE (SUBREG_REG (lhs)) != GET_MODE (SUBREG_REG (rhs))
|| SUBREG_WORD (lhs) != SUBREG_WORD (rhs)
|| ! subreg_lowpart_p (lhs)
|| (GET_MODE_CLASS (GET_MODE (lhs))
!= GET_MODE_CLASS (GET_MODE (SUBREG_REG (lhs))))
|| (GET_MODE_SIZE (GET_MODE (lhs))
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (lhs))))
|| GET_MODE_SIZE (GET_MODE (SUBREG_REG (lhs))) > UNITS_PER_WORD)
return x;
tem = gen_binary (code, GET_MODE (SUBREG_REG (lhs)),
SUBREG_REG (lhs), SUBREG_REG (rhs));
return gen_lowpart_for_combine (GET_MODE (x), tem);
default:
return x;
}
if (GET_RTX_CLASS (inner_code) == 'c'
&& 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'
&& 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'
&& 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)))
other = XEXP (lhs, 1), lhs = XEXP (lhs, 0), rhs = XEXP (rhs, 0);
else
return x;
tem = gen_binary (code, GET_MODE (x), lhs, rhs);
if (code == XOR && inner_code == IOR)
{
inner_code = AND;
other = gen_unary (NOT, GET_MODE (x), GET_MODE (x), other);
}
return gen_binary (inner_code, GET_MODE (x),
apply_distributive_law (tem), other);
}
static rtx
simplify_and_const_int (x, mode, varop, constop)
rtx x;
enum machine_mode mode;
rtx varop;
unsigned HOST_WIDE_INT constop;
{
unsigned HOST_WIDE_INT nonzero;
int width = GET_MODE_BITSIZE (mode);
int i;
varop = force_to_mode (varop, mode, constop, NULL_RTX, 0);
if (GET_CODE (varop) == CLOBBER || GET_CODE (varop) == CONST_INT)
return varop;
nonzero = nonzero_bits (varop, mode) & GET_MODE_MASK (mode);
if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
&& (nonzero & ((HOST_WIDE_INT) 1 << (width - 1))))
nonzero |= ((HOST_WIDE_INT) (-1) << width);
constop &= nonzero;
if (constop == 0)
return const0_rtx;
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
(mode,
apply_distributive_law
(gen_binary (GET_CODE (varop), GET_MODE (varop),
simplify_and_const_int (NULL_RTX, GET_MODE (varop),
XEXP (varop, 0), constop),
simplify_and_const_int (NULL_RTX, GET_MODE (varop),
XEXP (varop, 1), constop))));
if (x && GET_CODE (XEXP (x, 0)) == SUBREG
&& GET_MODE (XEXP (x, 0)) == mode
&& SUBREG_REG (XEXP (x, 0)) == varop)
varop = XEXP (x, 0);
else
varop = gen_lowpart_for_combine (mode, varop);
if (GET_CODE (varop) == CLOBBER)
return x ? x : varop;
if (constop == nonzero)
x = varop;
else if (x == 0 || GET_CODE (x) != AND || GET_MODE (x) != mode)
x = gen_binary (AND, mode, varop, GEN_INT (constop));
else
{
if (GET_CODE (XEXP (x, 1)) != CONST_INT
|| (unsigned HOST_WIDE_INT) INTVAL (XEXP (x, 1)) != constop)
SUBST (XEXP (x, 1), GEN_INT (constop));
SUBST (XEXP (x, 0), varop);
}
return x;
}
#define num_sign_bit_copies()
static unsigned HOST_WIDE_INT
nonzero_bits (x, mode)
rtx x;
enum machine_mode mode;
{
unsigned HOST_WIDE_INT nonzero = GET_MODE_MASK (mode);
unsigned HOST_WIDE_INT inner_nz;
enum rtx_code code;
int mode_width = GET_MODE_BITSIZE (mode);
rtx tem;
if (FLOAT_MODE_P (GET_MODE (x)) || FLOAT_MODE_P (mode))
return nonzero;
if (GET_MODE_BITSIZE (GET_MODE (x)) > mode_width)
{
mode = GET_MODE (x);
nonzero = GET_MODE_MASK (mode);
mode_width = GET_MODE_BITSIZE (mode);
}
if (mode_width > HOST_BITS_PER_WIDE_INT)
return nonzero;
#ifndef WORD_REGISTER_OPERATIONS
if (GET_MODE (x) != VOIDmode && GET_MODE (x) != mode
&& GET_MODE_BITSIZE (GET_MODE (x)) <= BITS_PER_WORD
&& 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 |= GET_MODE_MASK (mode) & ~ GET_MODE_MASK (GET_MODE (x));
return nonzero;
}
#endif
code = GET_CODE (x);
switch (code)
{
case REG:
#ifdef POINTERS_EXTEND_UNSIGNED
if (POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode
&& REGNO_POINTER_FLAG (REGNO (x)))
nonzero &= GET_MODE_MASK (ptr_mode);
#endif
#ifdef STACK_BOUNDARY
if ((x == frame_pointer_rtx
|| x == stack_pointer_rtx
|| x == hard_frame_pointer_rtx
|| (REGNO (x) >= FIRST_VIRTUAL_REGISTER
&& REGNO (x) <= LAST_VIRTUAL_REGISTER))
#ifdef STACK_BIAS
&& !STACK_BIAS
#endif
)
{
int sp_alignment = STACK_BOUNDARY / BITS_PER_UNIT;
#ifdef PUSH_ROUNDING
if (REGNO (x) == STACK_POINTER_REGNUM)
sp_alignment = MIN (PUSH_ROUNDING (1), sp_alignment);
#endif
return nonzero &= ~ (sp_alignment - 1);
}
#endif
if (reg_last_set_value[REGNO (x)] != 0
&& reg_last_set_mode[REGNO (x)] == mode
&& (REG_N_SETS (REGNO (x)) == 1
|| reg_last_set_label[REGNO (x)] == label_tick)
&& INSN_CUID (reg_last_set[REGNO (x)]) < subst_low_cuid)
return reg_last_set_nonzero_bits[REGNO (x)];
tem = get_last_value (x);
if (tem)
{
#ifdef SHORT_IMMEDIATES_SIGN_EXTEND
if (GET_MODE_BITSIZE (GET_MODE (x)) < mode_width
&& GET_CODE (tem) == CONST_INT
&& INTVAL (tem) > 0
&& 0 != (INTVAL (tem)
& ((HOST_WIDE_INT) 1
<< (GET_MODE_BITSIZE (GET_MODE (x)) - 1))))
tem = GEN_INT (INTVAL (tem)
| ((HOST_WIDE_INT) (-1)
<< GET_MODE_BITSIZE (GET_MODE (x))));
#endif
return nonzero_bits (tem, mode);
}
else if (nonzero_sign_valid && reg_nonzero_bits[REGNO (x)])
return reg_nonzero_bits[REGNO (x)] & nonzero;
else
return nonzero;
case CONST_INT:
#ifdef SHORT_IMMEDIATES_SIGN_EXTEND
if (INTVAL (x) > 0 && mode_width < BITS_PER_WORD
&& 0 != (INTVAL (x) & ((HOST_WIDE_INT) 1 << (mode_width - 1))))
return (INTVAL (x) | ((HOST_WIDE_INT) (-1) << mode_width));
#endif
return INTVAL (x);
case MEM:
#ifdef LOAD_EXTEND_OP
if (LOAD_EXTEND_OP (GET_MODE (x)) == ZERO_EXTEND)
nonzero &= GET_MODE_MASK (GET_MODE (x));
#endif
break;
case EQ: case NE:
case GT: case GTU:
case LT: case LTU:
case GE: case GEU:
case LE: case LEU:
if (GET_MODE_CLASS (mode) == MODE_INT
&& mode_width <= HOST_BITS_PER_WIDE_INT)
nonzero = STORE_FLAG_VALUE;
break;
case NEG:
#if 0
if (num_sign_bit_copies (XEXP (x, 0), GET_MODE (x))
== GET_MODE_BITSIZE (GET_MODE (x)))
nonzero = 1;
#endif
if (GET_MODE_SIZE (GET_MODE (x)) < mode_width)
nonzero |= (GET_MODE_MASK (mode) & ~ GET_MODE_MASK (GET_MODE (x)));
break;
case ABS:
#if 0
if (num_sign_bit_copies (XEXP (x, 0), GET_MODE (x))
== GET_MODE_BITSIZE (GET_MODE (x)))
nonzero = 1;
#endif
break;
case TRUNCATE:
nonzero &= (nonzero_bits (XEXP (x, 0), mode) & GET_MODE_MASK (mode));
break;
case ZERO_EXTEND:
nonzero &= nonzero_bits (XEXP (x, 0), mode);
if (GET_MODE (XEXP (x, 0)) != VOIDmode)
nonzero &= GET_MODE_MASK (GET_MODE (XEXP (x, 0)));
break;
case SIGN_EXTEND:
inner_nz = nonzero_bits (XEXP (x, 0), mode);
if (GET_MODE (XEXP (x, 0)) != VOIDmode)
{
inner_nz &= GET_MODE_MASK (GET_MODE (XEXP (x, 0)));
if (inner_nz
& (((HOST_WIDE_INT) 1
<< (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - 1))))
inner_nz |= (GET_MODE_MASK (mode)
& ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0))));
}
nonzero &= inner_nz;
break;
case AND:
nonzero &= (nonzero_bits (XEXP (x, 0), mode)
& nonzero_bits (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));
break;
case PLUS: case MINUS:
case MULT:
case DIV: case UDIV:
case MOD: case UMOD:
{
unsigned HOST_WIDE_INT nz0 = nonzero_bits (XEXP (x, 0), mode);
unsigned HOST_WIDE_INT nz1 = nonzero_bits (XEXP (x, 1), mode);
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)));
HOST_WIDE_INT op1_maybe_minusp
= (nz1 & ((HOST_WIDE_INT) 1 << (mode_width - 1)));
int result_width = mode_width;
int result_low = 0;
switch (code)
{
case PLUS:
#ifdef STACK_BIAS
if (STACK_BIAS
&& (XEXP (x, 0) == stack_pointer_rtx
|| XEXP (x, 0) == frame_pointer_rtx)
&& GET_CODE (XEXP (x, 1)) == CONST_INT)
{
int sp_alignment = STACK_BOUNDARY / BITS_PER_UNIT;
nz0 = (GET_MODE_MASK (mode) & ~ (sp_alignment - 1));
nz1 = INTVAL (XEXP (x, 1)) - STACK_BIAS;
width0 = floor_log2 (nz0) + 1;
width1 = floor_log2 (nz1) + 1;
low0 = floor_log2 (nz0 & -nz0);
low1 = floor_log2 (nz1 & -nz1);
}
#endif
result_width = MAX (width0, width1) + 1;
result_low = MIN (low0, low1);
break;
case MINUS:
result_low = MIN (low0, low1);
break;
case MULT:
result_width = width0 + width1;
result_low = low0 + low1;
break;
case DIV:
if (! op0_maybe_minusp && ! op1_maybe_minusp)
result_width = width0;
break;
case UDIV:
result_width = width0;
break;
case MOD:
if (! op0_maybe_minusp && ! op1_maybe_minusp)
result_width = MIN (width0, width1);
result_low = MIN (low0, low1);
break;
case UMOD:
result_width = MIN (width0, width1);
result_low = MIN (low0, low1);
break;
default:
abort ();
}
if (result_width < mode_width)
nonzero &= ((HOST_WIDE_INT) 1 << result_width) - 1;
if (result_low > 0)
nonzero &= ~ (((HOST_WIDE_INT) 1 << result_low) - 1);
}
break;
case ZERO_EXTRACT:
if (GET_CODE (XEXP (x, 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT)
nonzero &= ((HOST_WIDE_INT) 1 << INTVAL (XEXP (x, 1))) - 1;
break;
case SUBREG:
if (SUBREG_PROMOTED_VAR_P (x) && SUBREG_PROMOTED_UNSIGNED_P (x))
nonzero = (GET_MODE_MASK (GET_MODE (x))
& nonzero_bits (SUBREG_REG (x), GET_MODE (x)));
if (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) <= BITS_PER_WORD
&& (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))
<= HOST_BITS_PER_WIDE_INT))
{
nonzero &= nonzero_bits (SUBREG_REG (x), mode);
#if defined (WORD_REGISTER_OPERATIONS) && defined (LOAD_EXTEND_OP)
if (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) == SIGN_EXTEND
? (nonzero
& (1L << (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) - 1)))
: LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) != ZERO_EXTEND)
#endif
{
if (GET_MODE_SIZE (GET_MODE (x))
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
nonzero |= (GET_MODE_MASK (GET_MODE (x))
& ~ GET_MODE_MASK (GET_MODE (SUBREG_REG (x))));
}
}
break;
case ASHIFTRT:
case LSHIFTRT:
case ASHIFT:
case ROTATE:
if (GET_CODE (XEXP (x, 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) >= 0
&& INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT)
{
enum machine_mode inner_mode = GET_MODE (x);
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 inner = op_nonzero & mode_mask;
unsigned HOST_WIDE_INT outer = 0;
if (mode_width > width)
outer = (op_nonzero & nonzero & ~ mode_mask);
if (code == LSHIFTRT)
inner >>= count;
else if (code == ASHIFTRT)
{
inner >>= count;
if (inner & ((HOST_WIDE_INT) 1 << (width - 1 - count)))
inner |= (((HOST_WIDE_INT) 1 << count) - 1) << (width - count);
}
else if (code == ASHIFT)
inner <<= count;
else
inner = ((inner << (count % width)
| (inner >> (width - (count % width)))) & mode_mask);
nonzero &= (outer | inner);
}
break;
case FFS:
nonzero = ((HOST_WIDE_INT) 1 << (floor_log2 (mode_width) + 1)) - 1;
break;
case IF_THEN_ELSE:
nonzero &= (nonzero_bits (XEXP (x, 1), mode)
| nonzero_bits (XEXP (x, 2), mode));
break;
default:
break;
}
return nonzero;
}
#undef num_sign_bit_copies
static int
num_sign_bit_copies (x, mode)
rtx x;
enum machine_mode mode;
{
enum rtx_code code = GET_CODE (x);
int bitwidth;
int num0, num1, result;
unsigned HOST_WIDE_INT nonzero;
rtx tem;
if (mode == VOIDmode)
mode = GET_MODE (x);
if (mode == VOIDmode || FLOAT_MODE_P (mode) || FLOAT_MODE_P (GET_MODE (x)))
return 1;
bitwidth = GET_MODE_BITSIZE (mode);
if (bitwidth < GET_MODE_BITSIZE (GET_MODE (x)))
return MAX (1, (num_sign_bit_copies (x, GET_MODE (x))
- (GET_MODE_BITSIZE (GET_MODE (x)) - bitwidth)));
if (GET_MODE (x) != VOIDmode && bitwidth > GET_MODE_BITSIZE (GET_MODE (x)))
{
#ifndef WORD_REGISTER_OPERATIONS
return 1;
#else
if (GET_MODE_BITSIZE (GET_MODE (x)) < BITS_PER_WORD
#ifdef LOAD_EXTEND_OP
&& LOAD_EXTEND_OP (GET_MODE (x)) != SIGN_EXTEND
#endif
)
return 1;
#endif
}
switch (code)
{
case REG:
#ifdef POINTERS_EXTEND_UNSIGNED
if (! POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode && mode == Pmode
&& REGNO_POINTER_FLAG (REGNO (x)))
return GET_MODE_BITSIZE (Pmode) - GET_MODE_BITSIZE (ptr_mode) + 1;
#endif
if (reg_last_set_value[REGNO (x)] != 0
&& reg_last_set_mode[REGNO (x)] == mode
&& (REG_N_SETS (REGNO (x)) == 1
|| reg_last_set_label[REGNO (x)] == label_tick)
&& 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);
if (nonzero_sign_valid && reg_sign_bit_copies[REGNO (x)] != 0)
return reg_sign_bit_copies[REGNO (x)];
break;
case MEM:
#ifdef LOAD_EXTEND_OP
if (LOAD_EXTEND_OP (GET_MODE (x)) == SIGN_EXTEND)
return MAX (1, bitwidth - GET_MODE_BITSIZE (GET_MODE (x)) + 1);
#endif
break;
case CONST_INT:
nonzero = INTVAL (x) & GET_MODE_MASK (mode);
if (bitwidth <= HOST_BITS_PER_WIDE_INT
&& (nonzero & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
nonzero = (~ nonzero) & GET_MODE_MASK (mode);
return (nonzero == 0 ? bitwidth : bitwidth - floor_log2 (nonzero) - 1);
case SUBREG:
if (SUBREG_PROMOTED_VAR_P (x) && ! SUBREG_PROMOTED_UNSIGNED_P (x))
return MAX (bitwidth - GET_MODE_BITSIZE (GET_MODE (x)) + 1,
num_sign_bit_copies (SUBREG_REG (x), mode));
if (bitwidth <= GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))))
{
num0 = num_sign_bit_copies (SUBREG_REG (x), VOIDmode);
return MAX (1, (num0
- (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))
- bitwidth)));
}
#ifdef WORD_REGISTER_OPERATIONS
#ifdef LOAD_EXTEND_OP
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);
#endif
#endif
break;
case SIGN_EXTRACT:
if (GET_CODE (XEXP (x, 1)) == CONST_INT)
return MAX (1, bitwidth - INTVAL (XEXP (x, 1)));
break;
case SIGN_EXTEND:
return (bitwidth - GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
+ num_sign_bit_copies (XEXP (x, 0), VOIDmode));
case TRUNCATE:
num0 = num_sign_bit_copies (XEXP (x, 0), VOIDmode);
return MAX (1, (num0 - (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
- bitwidth)));
case NOT:
return num_sign_bit_copies (XEXP (x, 0), mode);
case ROTATE: case ROTATERT:
if (GET_CODE (XEXP (x, 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) >= 0 && INTVAL (XEXP (x, 1)) < bitwidth)
{
num0 = num_sign_bit_copies (XEXP (x, 0), mode);
return MAX (1, num0 - (code == ROTATE ? INTVAL (XEXP (x, 1))
: bitwidth - INTVAL (XEXP (x, 1))));
}
break;
case NEG:
num0 = num_sign_bit_copies (XEXP (x, 0), mode);
if (bitwidth > HOST_BITS_PER_WIDE_INT)
return num0 > 1 ? num0 - 1 : 1;
nonzero = nonzero_bits (XEXP (x, 0), mode);
if (nonzero == 1)
return bitwidth;
if (num0 > 1
&& (((HOST_WIDE_INT) 1 << (bitwidth - 1)) & nonzero))
num0--;
return num0;
case IOR: case AND: case XOR:
case SMIN: case SMAX: case UMIN: case UMAX:
num0 = num_sign_bit_copies (XEXP (x, 0), mode);
num1 = num_sign_bit_copies (XEXP (x, 1), mode);
return MIN (num0, num1);
case PLUS: case MINUS:
if (code == PLUS && XEXP (x, 1) == constm1_rtx
&& bitwidth <= HOST_BITS_PER_WIDE_INT)
{
nonzero = nonzero_bits (XEXP (x, 0), mode);
if ((((HOST_WIDE_INT) 1 << (bitwidth - 1)) & nonzero) == 0)
return (nonzero == 1 || nonzero == 0 ? bitwidth
: bitwidth - floor_log2 (nonzero) - 1);
}
num0 = num_sign_bit_copies (XEXP (x, 0), mode);
num1 = num_sign_bit_copies (XEXP (x, 1), mode);
return MAX (1, MIN (num0, num1) - 1);
case MULT:
num0 = num_sign_bit_copies (XEXP (x, 0), mode);
num1 = num_sign_bit_copies (XEXP (x, 1), mode);
result = bitwidth - (bitwidth - num0) - (bitwidth - num1);
if (result > 0
&& (bitwidth > HOST_BITS_PER_WIDE_INT
|| (((nonzero_bits (XEXP (x, 0), mode)
& ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
&& ((nonzero_bits (XEXP (x, 1), mode)
& ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0))))
result--;
return MAX (1, result);
case UDIV:
if (bitwidth > HOST_BITS_PER_WIDE_INT)
return 1;
else if ((nonzero_bits (XEXP (x, 0), mode)
& ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
return 1;
else
return num_sign_bit_copies (XEXP (x, 0), mode);
case UMOD:
return num_sign_bit_copies (XEXP (x, 1), mode);
case DIV:
result = num_sign_bit_copies (XEXP (x, 0), mode);
if (result > 1
&& (bitwidth > HOST_BITS_PER_WIDE_INT
|| (nonzero_bits (XEXP (x, 1), mode)
& ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0))
result--;
return result;
case MOD:
result = num_sign_bit_copies (XEXP (x, 1), mode);
if (result > 1
&& (bitwidth > HOST_BITS_PER_WIDE_INT
|| (nonzero_bits (XEXP (x, 1), mode)
& ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0))
result--;
return result;
case ASHIFTRT:
num0 = num_sign_bit_copies (XEXP (x, 0), mode);
if (GET_CODE (XEXP (x, 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) > 0)
num0 = MIN (bitwidth, num0 + INTVAL (XEXP (x, 1)));
return num0;
case ASHIFT:
if (GET_CODE (XEXP (x, 1)) != CONST_INT
|| INTVAL (XEXP (x, 1)) < 0
|| INTVAL (XEXP (x, 1)) >= bitwidth)
return 1;
num0 = num_sign_bit_copies (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);
return MIN (num0, num1);
case EQ: case NE: case GE: case GT: case LE: case LT:
case GEU: case GTU: case LEU: case LTU:
if (STORE_FLAG_VALUE == -1)
return bitwidth;
break;
default:
break;
}
if (bitwidth > HOST_BITS_PER_WIDE_INT)
return 1;
nonzero = nonzero_bits (x, mode);
return (nonzero & ((HOST_WIDE_INT) 1 << (bitwidth - 1))
? 1 : bitwidth - floor_log2 (nonzero) - 1);
}
int
extended_count (x, mode, unsignedp)
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))))
: num_sign_bit_copies (x, mode) - 1);
}
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;
{
enum rtx_code op0 = *pop0;
HOST_WIDE_INT const0 = *pconst0;
int width = GET_MODE_BITSIZE (mode);
const0 &= GET_MODE_MASK (mode);
const1 &= GET_MODE_MASK (mode);
if (op0 == AND)
const1 &= const0;
if (op1 == NIL || op0 == SET)
return 1;
else if (op0 == NIL)
op0 = op1, const0 = const1;
else if (op0 == op1)
{
switch (op0)
{
case AND:
const0 &= const1;
break;
case IOR:
const0 |= const1;
break;
case XOR:
const0 ^= const1;
break;
case PLUS:
const0 += const1;
break;
case NEG:
op0 = NIL;
break;
default:
break;
}
}
else if (op0 == PLUS || op1 == PLUS || op0 == NEG || op1 == NEG)
return 0;
else if (const0 != const1)
return 0;
else
switch (op0)
{
case IOR:
if (op1 == AND)
op0 = SET;
else
{;}
break;
case XOR:
if (op1 == AND)
op0 = AND, *pcomp_p = 1;
else
op0 = AND, *pconst0 = ~ const0;
break;
case AND:
if (op1 == IOR)
op0 = SET;
else
*pcomp_p = 1;
break;
default:
break;
}
const0 &= GET_MODE_MASK (mode);
if (const0 == 0
&& (op0 == IOR || op0 == XOR || op0 == PLUS))
op0 = NIL;
else if (const0 == 0 && op0 == AND)
op0 = SET;
else if ((unsigned HOST_WIDE_INT) const0 == GET_MODE_MASK (mode)
&& op0 == AND)
op0 = NIL;
if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
&& (const0 & ((HOST_WIDE_INT) 1 << (width - 1))))
const0 |= ((HOST_WIDE_INT) (-1) << width);
*pop0 = op0;
*pconst0 = const0;
return 1;
}
static rtx
simplify_shift_const (x, code, result_mode, varop, count)
rtx x;
enum rtx_code code;
enum machine_mode result_mode;
rtx varop;
int count;
{
enum rtx_code orig_code = code;
int orig_count = count;
enum machine_mode mode = result_mode;
enum machine_mode shift_mode, tmode;
int mode_words
= (GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;
enum rtx_code outer_op = NIL;
HOST_WIDE_INT outer_const = 0;
rtx const_rtx;
int complement_p = 0;
rtx new;
if (count < 0 || count > GET_MODE_BITSIZE (mode))
{
if (x)
return x;
return gen_rtx_fmt_ee (code, mode, varop, GEN_INT (count));
}
while (count != 0)
{
if (GET_CODE (varop) == CLOBBER)
return varop;
if (complement_p)
break;
if (code == ROTATERT)
code = ROTATE, count = GET_MODE_BITSIZE (result_mode) - count;
shift_mode
= (code == ASHIFTRT || code == LSHIFTRT || code == ROTATE
? result_mode : mode);
if (count > GET_MODE_BITSIZE (shift_mode) - 1)
{
if (code == ASHIFTRT)
count = GET_MODE_BITSIZE (shift_mode) - 1;
else if (code == ROTATE || code == ROTATERT)
count %= GET_MODE_BITSIZE (shift_mode);
else
{
varop = const0_rtx;
count = 0;
break;
}
}
else if (count < 0)
abort ();
if (code == ASHIFTRT
&& (num_sign_bit_copies (varop, shift_mode)
== GET_MODE_BITSIZE (shift_mode)))
{
count = 0;
break;
}
if (code == ASHIFTRT
&& (count + num_sign_bit_copies (varop, shift_mode)
>= GET_MODE_BITSIZE (shift_mode)))
count = GET_MODE_BITSIZE (shift_mode) - 1;
if (GET_MODE_BITSIZE (shift_mode) <= HOST_BITS_PER_WIDE_INT
&& code == ASHIFTRT
&& ((nonzero_bits (varop, shift_mode)
& ((HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (shift_mode) - 1)))
== 0))
code = LSHIFTRT;
switch (GET_CODE (varop))
{
case SIGN_EXTEND:
case ZERO_EXTEND:
case SIGN_EXTRACT:
case ZERO_EXTRACT:
new = expand_compound_operation (varop);
if (new != varop)
{
varop = new;
continue;
}
break;
case MEM:
if ((code == ASHIFTRT || code == LSHIFTRT)
&& ! mode_dependent_address_p (XEXP (varop, 0))
&& ! MEM_VOLATILE_P (varop)
&& (tmode = mode_for_size (GET_MODE_BITSIZE (mode) - count,
MODE_INT, 1)) != BLKmode)
{
if (BYTES_BIG_ENDIAN)
new = gen_rtx_MEM (tmode, XEXP (varop, 0));
else
new = gen_rtx_MEM (tmode,
plus_constant (XEXP (varop, 0),
count / BITS_PER_UNIT));
RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (varop);
MEM_COPY_ATTRIBUTES (new, varop);
varop = gen_rtx_combine (code == ASHIFTRT ? SIGN_EXTEND
: ZERO_EXTEND, mode, new);
count = 0;
continue;
}
break;
case USE:
if ((code == ASHIFTRT || code == LSHIFTRT)
&& (tmode = mode_for_size (GET_MODE_BITSIZE (mode) - count,
MODE_INT, 1)) != BLKmode
&& tmode == GET_MODE (XEXP (varop, 0)))
{
if (BITS_BIG_ENDIAN)
new = XEXP (varop, 0);
else
{
new = copy_rtx (XEXP (varop, 0));
SUBST (XEXP (new, 0),
plus_constant (XEXP (new, 0),
count / BITS_PER_UNIT));
}
varop = gen_rtx_combine (code == ASHIFTRT ? SIGN_EXTEND
: ZERO_EXTEND, mode, new);
count = 0;
continue;
}
break;
case SUBREG:
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))
{
varop = SUBREG_REG (varop);
if (GET_MODE_SIZE (GET_MODE (varop)) > GET_MODE_SIZE (mode))
mode = GET_MODE (varop);
continue;
}
break;
case MULT:
if (GET_CODE (XEXP (varop, 1)) == CONST_INT
&& exact_log2 (INTVAL (XEXP (varop, 1))) >= 0)
{
varop = gen_binary (ASHIFT, GET_MODE (varop), XEXP (varop, 0),
GEN_INT (exact_log2 (INTVAL (XEXP (varop, 1)))));;
continue;
}
break;
case UDIV:
if (GET_CODE (XEXP (varop, 1)) == CONST_INT
&& exact_log2 (INTVAL (XEXP (varop, 1))) >= 0)
{
varop = gen_binary (LSHIFTRT, GET_MODE (varop), XEXP (varop, 0),
GEN_INT (exact_log2 (INTVAL (XEXP (varop, 1)))));
continue;
}
break;
case ASHIFTRT:
if (code == LSHIFTRT && count == GET_MODE_BITSIZE (result_mode) - 1)
{
varop = XEXP (varop, 0);
continue;
}
case LSHIFTRT:
case ASHIFT:
case ROTATE:
if (GET_CODE (XEXP (varop, 1)) == CONST_INT
&& INTVAL (XEXP (varop, 1)) >= 0
&& INTVAL (XEXP (varop, 1)) < GET_MODE_BITSIZE (GET_MODE (varop))
&& GET_MODE_BITSIZE (result_mode) <= HOST_BITS_PER_WIDE_INT
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
{
enum rtx_code first_code = GET_CODE (varop);
int first_count = INTVAL (XEXP (varop, 1));
unsigned HOST_WIDE_INT mask;
rtx mask_rtx;
if (code == ASHIFT && first_code == ASHIFTRT
&& (GET_MODE_BITSIZE (result_mode)
- GET_MODE_BITSIZE (GET_MODE (varop))) == count)
{
mask = (GET_MODE_MASK (mode)
& ~ (((HOST_WIDE_INT) 1 << first_count) - 1));
varop = simplify_and_const_int (NULL_RTX, result_mode,
XEXP (varop, 0), mask);
varop = simplify_shift_const (NULL_RTX, ASHIFT, result_mode,
varop, count);
count = first_count;
code = ASHIFTRT;
continue;
}
if (code == ASHIFTRT && first_code == ASHIFT
&& GET_MODE (varop) == shift_mode
&& (num_sign_bit_copies (XEXP (varop, 0), shift_mode)
> first_count))
{
count -= first_count;
if (count < 0)
count = - count, code = ASHIFT;
varop = XEXP (varop, 0);
continue;
}
if (code == first_code)
{
if (GET_MODE (varop) != result_mode
&& (code == ASHIFTRT || code == LSHIFTRT
|| code == ROTATE))
break;
count += first_count;
varop = XEXP (varop, 0);
continue;
}
if (code == ASHIFTRT
|| (code == ROTATE && first_code == ASHIFTRT)
|| GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT
|| (GET_MODE (varop) != result_mode
&& (first_code == ASHIFTRT || first_code == LSHIFTRT
|| first_code == ROTATE
|| code == ROTATE)))
break;
mask_rtx = GEN_INT (nonzero_bits (varop, GET_MODE (varop)));
mask_rtx
= simplify_binary_operation (code, result_mode, mask_rtx,
GEN_INT (count));
if (mask_rtx == 0
|| GET_CODE (mask_rtx) != CONST_INT
|| ! merge_outer_ops (&outer_op, &outer_const, AND,
INTVAL (mask_rtx),
result_mode, &complement_p))
break;
if ((code == ASHIFTRT || code == LSHIFTRT)
== (first_code == ASHIFTRT || first_code == LSHIFTRT))
count += first_count;
else
count -= first_count;
if (count > 0
&& ((first_code == ROTATE && code == ASHIFT)
|| (first_code == ASHIFTRT && code == LSHIFTRT)))
code = first_code;
else if (count < 0)
code = first_code, count = - count;
varop = XEXP (varop, 0);
continue;
}
else if (GET_CODE (varop) == code
&& GET_CODE (XEXP (varop, 1)) != CONST_INT
&& 0 != (new
= simplify_binary_operation (code, mode,
XEXP (varop, 0),
GEN_INT (count))))
{
varop = gen_rtx_combine (code, mode, new, XEXP (varop, 1));
count = 0;
continue;
}
break;
case NOT:
varop = gen_rtx_combine (XOR, mode, XEXP (varop, 0),
GEN_INT (GET_MODE_MASK (mode)));
continue;
case IOR:
case AND:
case XOR:
if (GET_CODE (varop) == IOR && GET_CODE (XEXP (varop, 0)) == PLUS
&& 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
&& rtx_equal_p (XEXP (XEXP (varop, 0), 0), XEXP (varop, 1)))
{
count = 0;
varop = gen_rtx_combine (LE, GET_MODE (varop), XEXP (varop, 1),
const0_rtx);
if (STORE_FLAG_VALUE == 1 ? code == ASHIFTRT : code == LSHIFTRT)
varop = gen_rtx_combine (NEG, GET_MODE (varop), varop);
continue;
}
if (GET_CODE (XEXP (varop, 1)) == CONST_INT
&& (new = simplify_binary_operation (code, result_mode,
XEXP (varop, 1),
GEN_INT (count))) != 0
&& GET_CODE(new) == CONST_INT
&& merge_outer_ops (&outer_op, &outer_const, GET_CODE (varop),
INTVAL (new), result_mode, &complement_p))
{
varop = XEXP (varop, 0);
continue;
}
{
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);
count = 0;
}
break;
case EQ:
if (code == LSHIFTRT
&& XEXP (varop, 1) == const0_rtx
&& GET_MODE (XEXP (varop, 0)) == result_mode
&& count == GET_MODE_BITSIZE (result_mode) - 1
&& GET_MODE_BITSIZE (result_mode) <= HOST_BITS_PER_WIDE_INT
&& ((STORE_FLAG_VALUE
& ((HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (result_mode) - 1))))
&& nonzero_bits (XEXP (varop, 0), result_mode) == 1
&& merge_outer_ops (&outer_op, &outer_const, XOR,
(HOST_WIDE_INT) 1, result_mode,
&complement_p))
{
varop = XEXP (varop, 0);
count = 0;
continue;
}
break;
case NEG:
if (code == LSHIFTRT && count == GET_MODE_BITSIZE (result_mode) - 1
&& nonzero_bits (XEXP (varop, 0), result_mode) == 1)
{
varop = XEXP (varop, 0);
count = 0;
continue;
}
if (code == ASHIFT
&& merge_outer_ops (&outer_op, &outer_const, NEG,
(HOST_WIDE_INT) 0, result_mode,
&complement_p))
{
varop = XEXP (varop, 0);
continue;
}
break;
case PLUS:
if (code == LSHIFTRT && count == 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,
(HOST_WIDE_INT) 1, result_mode,
&complement_p))
{
count = 0;
varop = XEXP (varop, 0);
continue;
}
if ((code == ASHIFTRT || code == LSHIFTRT)
&& count < HOST_BITS_PER_WIDE_INT
&& nonzero_bits (XEXP (varop, 1), result_mode) >> count == 0
&& (nonzero_bits (XEXP (varop, 1), result_mode)
& nonzero_bits (XEXP (varop, 0), result_mode)) == 0)
{
varop = XEXP (varop, 0);
continue;
}
else if ((code == ASHIFTRT || code == LSHIFTRT)
&& count < HOST_BITS_PER_WIDE_INT
&& GET_MODE_BITSIZE (result_mode) <= HOST_BITS_PER_WIDE_INT
&& 0 == (nonzero_bits (XEXP (varop, 0), result_mode)
>> count)
&& 0 == (nonzero_bits (XEXP (varop, 0), result_mode)
& nonzero_bits (XEXP (varop, 1),
result_mode)))
{
varop = XEXP (varop, 1);
continue;
}
if (code == ASHIFT
&& GET_CODE (XEXP (varop, 1)) == CONST_INT
&& (new = simplify_binary_operation (ASHIFT, result_mode,
XEXP (varop, 1),
GEN_INT (count))) != 0
&& GET_CODE(new) == CONST_INT
&& merge_outer_ops (&outer_op, &outer_const, PLUS,
INTVAL (new), result_mode, &complement_p))
{
varop = XEXP (varop, 0);
continue;
}
break;
case MINUS:
if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
&& GET_CODE (XEXP (varop, 0)) == ASHIFTRT
&& count == GET_MODE_BITSIZE (GET_MODE (varop)) - 1
&& (code == LSHIFTRT || code == ASHIFTRT)
&& GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT
&& INTVAL (XEXP (XEXP (varop, 0), 1)) == count
&& rtx_equal_p (XEXP (XEXP (varop, 0), 0), XEXP (varop, 1)))
{
count = 0;
varop = gen_rtx_combine (GT, GET_MODE (varop), XEXP (varop, 1),
const0_rtx);
if (STORE_FLAG_VALUE == 1 ? code == ASHIFTRT : code == LSHIFTRT)
varop = gen_rtx_combine (NEG, GET_MODE (varop), varop);
continue;
}
break;
case TRUNCATE:
if (code == LSHIFTRT
&& GET_CODE (XEXP (varop, 0)) == LSHIFTRT
&& GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT
&& (INTVAL (XEXP (XEXP (varop, 0), 1))
>= (GET_MODE_BITSIZE (GET_MODE (XEXP (varop, 0)))
- GET_MODE_BITSIZE (GET_MODE (varop)))))
{
rtx varop_inner = XEXP (varop, 0);
varop_inner = gen_rtx_combine (LSHIFTRT,
GET_MODE (varop_inner),
XEXP (varop_inner, 0),
GEN_INT (count + INTVAL (XEXP (varop_inner, 1))));
varop = gen_rtx_combine (TRUNCATE, GET_MODE (varop),
varop_inner);
count = 0;
continue;
}
break;
default:
break;
}
break;
}
shift_mode
= (code == ASHIFTRT || code == LSHIFTRT || code == ROTATE
? result_mode : mode);
if (x && GET_RTX_CLASS (GET_CODE (x)) == '2'
&& GET_CODE (XEXP (x, 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) == count)
const_rtx = XEXP (x, 1);
else
const_rtx = GEN_INT (count);
if (x && GET_CODE (XEXP (x, 0)) == SUBREG
&& GET_MODE (XEXP (x, 0)) == shift_mode
&& 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);
if (GET_CODE (varop) == CLOBBER)
return x ? x : varop;
new = simplify_binary_operation (code, shift_mode, varop, const_rtx);
if (new != 0)
x = new;
else
{
if (x == 0 || GET_CODE (x) != code || GET_MODE (x) != shift_mode)
x = gen_rtx_combine (code, shift_mode, varop, const_rtx);
SUBST (XEXP (x, 0), varop);
SUBST (XEXP (x, 1), const_rtx);
}
if (outer_op != NIL && GET_CODE (x) == code
&& GET_CODE (XEXP (x, 1)) == CONST_INT)
x = simplify_shift_const (x, code, shift_mode, XEXP (x, 0),
INTVAL (XEXP (x, 1)));
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);
x = gen_lowpart_for_combine (result_mode, x);
if (complement_p)
x = gen_unary (NOT, result_mode, result_mode, x);
if (outer_op != NIL)
{
if (GET_MODE_BITSIZE (result_mode) < HOST_BITS_PER_WIDE_INT)
{
int width = GET_MODE_BITSIZE (result_mode);
outer_const &= GET_MODE_MASK (result_mode);
if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
&& (outer_const & ((HOST_WIDE_INT) 1 << (width - 1))))
outer_const |= ((HOST_WIDE_INT) (-1) << width);
}
if (outer_op == AND)
x = simplify_and_const_int (NULL_RTX, result_mode, x, outer_const);
else if (outer_op == SET)
x = GEN_INT (outer_const);
else if (GET_RTX_CLASS (outer_op) == '1')
x = gen_unary (outer_op, result_mode, result_mode, x);
else
x = gen_binary (outer_op, result_mode, x, GEN_INT (outer_const));
}
return x;
}
static int
recog_for_combine (pnewpat, insn, pnotes)
rtx *pnewpat;
rtx insn;
rtx *pnotes;
{
register rtx pat = *pnewpat;
int insn_code_number;
int num_clobbers_to_add = 0;
int i;
rtx notes = 0;
if (GET_CODE (pat) == PARALLEL)
for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)
if (GET_CODE (XVECEXP (pat, 0, i)) == CLOBBER
&& XEXP (XVECEXP (pat, 0, i), 0) == const0_rtx)
return -1;
insn_code_number = recog (pat, insn, &num_clobbers_to_add);
if (insn_code_number < 0 && ! check_asm_operands (pat)
&& GET_CODE (pat) == PARALLEL)
{
int pos;
for (pos = 0, i = 0; i < XVECLEN (pat, 0); i++)
if (GET_CODE (XVECEXP (pat, 0, i)) != CLOBBER)
{
if (i != pos)
SUBST (XVECEXP (pat, 0, pos), XVECEXP (pat, 0, i));
pos++;
}
SUBST_INT (XVECLEN (pat, 0), pos);
if (pos == 1)
pat = XVECEXP (pat, 0, 0);
insn_code_number = recog (pat, insn, &num_clobbers_to_add);
}
if (num_clobbers_to_add)
{
rtx newpat = gen_rtx_PARALLEL (VOIDmode,
gen_rtvec (GET_CODE (pat) == PARALLEL
? XVECLEN (pat, 0) + num_clobbers_to_add
: num_clobbers_to_add + 1));
if (GET_CODE (pat) == PARALLEL)
for (i = 0; i < XVECLEN (pat, 0); i++)
XVECEXP (newpat, 0, i) = XVECEXP (pat, 0, i);
else
XVECEXP (newpat, 0, 0) = pat;
add_clobbers (newpat, insn_code_number);
for (i = XVECLEN (newpat, 0) - num_clobbers_to_add;
i < XVECLEN (newpat, 0); i++)
{
if (GET_CODE (XEXP (XVECEXP (newpat, 0, i), 0)) == REG
&& ! reg_dead_at_p (XEXP (XVECEXP (newpat, 0, i), 0), insn))
return -1;
notes = gen_rtx_EXPR_LIST (REG_UNUSED,
XEXP (XVECEXP (newpat, 0, i), 0), notes);
}
pat = newpat;
}
*pnewpat = pat;
*pnotes = notes;
return insn_code_number;
}
#undef gen_lowpart
static rtx
gen_lowpart_for_combine (mode, x)
enum machine_mode mode;
register rtx x;
{
rtx result;
if (GET_MODE (x) == mode)
return x;
if (GET_MODE_SIZE (mode) > UNITS_PER_WORD
&& ! ((GET_MODE (x) == VOIDmode
&& (GET_CODE (x) == CONST_INT
|| GET_CODE (x) == CONST_DOUBLE))
|| GET_MODE_SIZE (GET_MODE (x)) == GET_MODE_SIZE (mode)))
return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
if (GET_CODE (x) == SUBREG && GET_CODE (SUBREG_REG (x)) == MEM)
{
x = SUBREG_REG (x);
if (GET_MODE (x) == mode)
return x;
}
result = gen_lowpart_common (mode, x);
if (result != 0
&& GET_CODE (result) == SUBREG
&& GET_CODE (SUBREG_REG (result)) == REG
&& REGNO (SUBREG_REG (result)) >= FIRST_PSEUDO_REGISTER
&& (GET_MODE_SIZE (GET_MODE (result))
!= GET_MODE_SIZE (GET_MODE (SUBREG_REG (result)))))
REG_CHANGES_SIZE (REGNO (SUBREG_REG (result))) = 1;
if (result)
return result;
if (GET_CODE (x) == MEM)
{
register int offset = 0;
rtx new;
if (MEM_VOLATILE_P (x) || mode_dependent_address_p (XEXP (x, 0)))
return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode))
return gen_rtx_SUBREG (mode, x, 0);
if (WORDS_BIG_ENDIAN)
offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)
- MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD));
if (BYTES_BIG_ENDIAN)
{
offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
- MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));
}
new = gen_rtx_MEM (mode, plus_constant (XEXP (x, 0), offset));
RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (x);
MEM_COPY_ATTRIBUTES (new, x);
return new;
}
else if (GET_RTX_CLASS (GET_CODE (x)) == '<')
return gen_rtx_combine (GET_CODE (x), mode, XEXP (x, 0), XEXP (x, 1));
else
{
int word = 0;
if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
word = ((GET_MODE_SIZE (GET_MODE (x))
- MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
/ UNITS_PER_WORD);
return gen_rtx_SUBREG (mode, x, word);
}
}
static rtx
gen_rtx_combine VPROTO((enum rtx_code code, enum machine_mode mode, ...))
{
#ifndef ANSI_PROTOTYPES
enum rtx_code code;
enum machine_mode mode;
#endif
va_list p;
int n_args;
rtx args[3];
int j;
char *fmt;
rtx rt;
struct undo *undo;
VA_START (p, mode);
#ifndef ANSI_PROTOTYPES
code = va_arg (p, enum rtx_code);
mode = va_arg (p, enum machine_mode);
#endif
n_args = GET_RTX_LENGTH (code);
fmt = GET_RTX_FORMAT (code);
if (n_args == 0 || n_args > 3)
abort ();
for (j = 0; j < n_args; j++)
{
if (*fmt++ != 'e')
abort ();
args[j] = va_arg (p, rtx);
}
for (undo = undobuf.undos; undo != undobuf.previous_undos; undo = undo->next)
if (!undo->is_int
&& GET_CODE (undo->old_contents.r) == code
&& GET_MODE (undo->old_contents.r) == mode)
{
for (j = 0; j < n_args; j++)
if (XEXP (undo->old_contents.r, j) != args[j])
break;
if (j == n_args)
return undo->old_contents.r;
}
rt = rtx_alloc (code);
PUT_MODE (rt, mode);
XEXP (rt, 0) = args[0];
if (n_args > 1)
{
XEXP (rt, 1) = args[1];
if (n_args > 2)
XEXP (rt, 2) = args[2];
}
return rt;
}
static rtx
gen_binary (code, mode, op0, op1)
enum rtx_code code;
enum machine_mode mode;
rtx op0, op1;
{
rtx result;
rtx tem;
if (GET_RTX_CLASS (code) == 'c'
&& (GET_CODE (op0) == CONST_INT
|| (CONSTANT_P (op0) && GET_CODE (op1) != CONST_INT)))
tem = op0, op0 = op1, op1 = tem;
if (GET_RTX_CLASS (code) == '<')
{
enum machine_mode op_mode = GET_MODE (op0);
if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
{
op1 = XEXP (op0, 1);
op0 = XEXP (op0, 0);
op_mode = GET_MODE (op0);
}
if (op_mode == VOIDmode)
op_mode = GET_MODE (op1);
result = simplify_relational_operation (code, op_mode, op0, op1);
}
else
result = simplify_binary_operation (code, mode, op0, op1);
if (result)
return result;
if (GET_RTX_CLASS (code) == 'c'
&& ((CONSTANT_P (op0) && GET_CODE (op1) != CONST_INT)
|| (GET_RTX_CLASS (GET_CODE (op0)) == 'o'
&& GET_RTX_CLASS (GET_CODE (op1)) != 'o')
|| (GET_CODE (op0) == SUBREG
&& GET_RTX_CLASS (GET_CODE (SUBREG_REG (op0))) == 'o'
&& GET_RTX_CLASS (GET_CODE (op1)) != 'o')))
return gen_rtx_combine (code, mode, op1, op0);
else if (code == AND && GET_CODE (op1) == CONST_INT
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& (nonzero_bits (op0, mode) & ~ INTVAL (op1)) == 0)
return op0;
return gen_rtx_combine (code, mode, op0, op1);
}
static rtx
gen_unary (code, mode, op0_mode, op0)
enum rtx_code code;
enum machine_mode mode, op0_mode;
rtx op0;
{
rtx result = simplify_unary_operation (code, mode, op0, op0_mode);
if (result)
return result;
return gen_rtx_combine (code, mode, op0);
}
static enum rtx_code
simplify_comparison (code, pop0, pop1)
enum rtx_code code;
rtx *pop0;
rtx *pop1;
{
rtx op0 = *pop0;
rtx op1 = *pop1;
rtx tem, tem1;
int i;
enum machine_mode mode, tmode;
while (1)
{
#ifndef WORD_REGISTER_OPERATIONS
if (code != GTU && code != GEU && code != LTU && code != LEU
&& GET_CODE (op0) == ASHIFTRT && GET_CODE (op1) == ASHIFTRT
&& GET_CODE (XEXP (op0, 0)) == ASHIFT
&& GET_CODE (XEXP (op1, 0)) == ASHIFT
&& GET_CODE (XEXP (XEXP (op0, 0), 0)) == SUBREG
&& GET_CODE (XEXP (XEXP (op1, 0), 0)) == SUBREG
&& (GET_MODE (SUBREG_REG (XEXP (XEXP (op0, 0), 0)))
== GET_MODE (SUBREG_REG (XEXP (XEXP (op1, 0), 0))))
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
&& 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))
&& (INTVAL (XEXP (op0, 1))
== (GET_MODE_BITSIZE (GET_MODE (op0))
- (GET_MODE_BITSIZE
(GET_MODE (SUBREG_REG (XEXP (XEXP (op0, 0), 0))))))))
{
op0 = SUBREG_REG (XEXP (XEXP (op0, 0), 0));
op1 = SUBREG_REG (XEXP (XEXP (op1, 0), 0));
}
#endif
if (GET_CODE (op0) == GET_CODE (op1)
&& GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT
&& ((GET_CODE (op0) == ROTATE && (code == NE || code == EQ))
|| ((GET_CODE (op0) == LSHIFTRT || GET_CODE (op0) == ASHIFT)
&& (code != GT && code != LT && code != GE && code != LE))
|| (GET_CODE (op0) == ASHIFTRT
&& (code != GTU && code != LTU
&& code != GEU && code != GEU)))
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
&& INTVAL (XEXP (op0, 1)) >= 0
&& INTVAL (XEXP (op0, 1)) < HOST_BITS_PER_WIDE_INT
&& XEXP (op0, 1) == XEXP (op1, 1))
{
enum machine_mode mode = GET_MODE (op0);
unsigned HOST_WIDE_INT mask = GET_MODE_MASK (mode);
int shift_count = INTVAL (XEXP (op0, 1));
if (GET_CODE (op0) == LSHIFTRT || GET_CODE (op0) == ASHIFTRT)
mask &= (mask >> shift_count) << shift_count;
else if (GET_CODE (op0) == ASHIFT)
mask = (mask & (mask << shift_count)) >> shift_count;
if ((nonzero_bits (XEXP (op0, 0), mode) & ~ mask) == 0
&& (nonzero_bits (XEXP (op1, 0), mode) & ~ mask) == 0)
op0 = XEXP (op0, 0), op1 = XEXP (op1, 0);
else
break;
}
else if (GET_CODE (op0) == AND && GET_CODE (op1) == AND
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
&& GET_CODE (XEXP (op1, 1)) == CONST_INT)
{
rtx inner_op0 = XEXP (op0, 0);
rtx inner_op1 = XEXP (op1, 0);
HOST_WIDE_INT c0 = INTVAL (XEXP (op0, 1));
HOST_WIDE_INT c1 = INTVAL (XEXP (op1, 1));
int changed = 0;
if (GET_CODE (inner_op0) == SUBREG && GET_CODE (inner_op1) == SUBREG
&& (GET_MODE_SIZE (GET_MODE (inner_op0))
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (inner_op0))))
&& (GET_MODE (SUBREG_REG (inner_op0))
== GET_MODE (SUBREG_REG (inner_op1)))
&& (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (inner_op0)))
<= HOST_BITS_PER_WIDE_INT)
&& (0 == ((~c0) & nonzero_bits (SUBREG_REG (inner_op0),
GET_MODE (SUBREG_REG (inner_op0)))))
&& (0 == ((~c1) & nonzero_bits (SUBREG_REG (inner_op1),
GET_MODE (SUBREG_REG (inner_op1))))))
{
op0 = SUBREG_REG (inner_op0);
op1 = SUBREG_REG (inner_op1);
code = unsigned_condition (code);
changed = 1;
}
else if (c0 == c1)
for (tmode = GET_CLASS_NARROWEST_MODE
(GET_MODE_CLASS (GET_MODE (op0)));
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);
code = unsigned_condition (code);
changed = 1;
break;
}
if (! changed)
break;
}
else if ((GET_CODE (op0) == NOT && GET_CODE (op1) == NOT)
|| (GET_CODE (op0) == NEG && GET_CODE (op1) == NEG
&& (code == EQ || code == NE)))
op0 = XEXP (op0, 0), op1 = XEXP (op1, 0), code = swap_condition (code);
else
break;
}
if (CONSTANT_P (op0) && GET_CODE (op1) != CONST_INT)
{
tem = op0, op0 = op1, op1 = tem;
code = swap_condition (code);
}
while (GET_CODE (op1) == CONST_INT)
{
enum machine_mode mode = GET_MODE (op0);
int mode_width = GET_MODE_BITSIZE (mode);
unsigned HOST_WIDE_INT mask = GET_MODE_MASK (mode);
int equality_comparison_p;
int sign_bit_comparison_p;
int unsigned_comparison_p;
HOST_WIDE_INT const_op;
if (GET_MODE_CLASS (mode) != MODE_INT
&& ! (mode == VOIDmode
&& (GET_CODE (op0) == COMPARE
|| GET_RTX_CLASS (GET_CODE (op0)) == '<')))
break;
const_op = INTVAL (op1);
if (mode_width <= HOST_BITS_PER_WIDE_INT)
const_op &= mask;
if (const_op
&& (code == EQ || code == NE || code == GE || code == GEU
|| code == LT || code == LTU)
&& mode_width <= HOST_BITS_PER_WIDE_INT
&& exact_log2 (const_op) >= 0
&& nonzero_bits (op0, mode) == (unsigned HOST_WIDE_INT) const_op)
{
code = (code == EQ || code == GE || code == GEU ? NE : EQ);
op1 = const0_rtx, const_op = 0;
}
if (const_op == -1
&& (code == EQ || code == NE || code == GT || code == LE
|| code == GEU || code == LTU)
&& num_sign_bit_copies (op0, mode) == mode_width)
{
code = (code == EQ || code == LE || code == GEU ? NE : EQ);
op1 = const0_rtx, const_op = 0;
}
switch (code)
{
case LT:
if (const_op > 0)
{
const_op -= 1;
op1 = GEN_INT (const_op);
code = LE;
}
else
break;
case LE:
if (const_op < 0)
{
const_op += 1;
op1 = GEN_INT (const_op);
code = LT;
}
else if (const_op == 0
&& mode_width <= HOST_BITS_PER_WIDE_INT
&& (nonzero_bits (op0, mode)
& ((HOST_WIDE_INT) 1 << (mode_width - 1))) == 0)
code = EQ;
break;
case GE:
if (const_op > 0)
{
const_op -= 1;
op1 = GEN_INT (const_op);
code = GT;
}
else
break;
case GT:
if (const_op < 0)
{
const_op += 1;
op1 = GEN_INT (const_op);
code = GE;
}
else if (const_op == 0
&& mode_width <= HOST_BITS_PER_WIDE_INT
&& (nonzero_bits (op0, mode)
& ((HOST_WIDE_INT) 1 << (mode_width - 1))) == 0)
code = NE;
break;
case LTU:
if (const_op > 0)
{
const_op -= 1;
op1 = GEN_INT (const_op);
code = LEU;
}
else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
&& (const_op == (HOST_WIDE_INT) 1 << (mode_width - 1)))
{
const_op = 0, op1 = const0_rtx;
code = GE;
break;
}
else
break;
case LEU:
if (const_op == 0)
code = EQ;
else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
&& (const_op == ((HOST_WIDE_INT) 1 << (mode_width - 1)) - 1))
{
const_op = 0, op1 = const0_rtx;
code = GE;
}
break;
case GEU:
if (const_op > 1)
{
const_op -= 1;
op1 = GEN_INT (const_op);
code = GTU;
}
else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
&& (const_op == (HOST_WIDE_INT) 1 << (mode_width - 1)))
{
const_op = 0, op1 = const0_rtx;
code = LT;
break;
}
else
break;
case GTU:
if (const_op == 0)
code = NE;
else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
&& (const_op == ((HOST_WIDE_INT) 1 << (mode_width - 1)) - 1))
{
const_op = 0, op1 = const0_rtx;
code = LT;
}
break;
default:
break;
}
equality_comparison_p = (code == EQ || code == NE);
sign_bit_comparison_p = ((code == LT || code == GE) && const_op == 0);
unsigned_comparison_p = (code == LTU || code == LEU || code == GTU
|| code == LEU);
if (sign_bit_comparison_p
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
op0 = force_to_mode (op0, mode,
((HOST_WIDE_INT) 1
<< (GET_MODE_BITSIZE (mode) - 1)),
NULL_RTX, 0);
switch (GET_CODE (op0))
{
case ZERO_EXTRACT:
if (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)
{
if (BITS_BIG_ENDIAN)
{
#ifdef HAVE_extzv
mode = insn_operand_mode[(int) CODE_FOR_extzv][1];
if (mode == VOIDmode)
mode = word_mode;
i = (GET_MODE_BITSIZE (mode) - 1 - i);
#else
i = BITS_PER_WORD - 1 - i;
#endif
}
op0 = XEXP (op0, 2);
op1 = GEN_INT (i);
const_op = i;
code = reverse_condition (code);
continue;
}
case SIGN_EXTRACT:
tem = expand_compound_operation (op0);
if (tem != op0)
{
op0 = tem;
continue;
}
break;
case NOT:
if (equality_comparison_p
&& (tem = simplify_unary_operation (NOT, mode, op1, mode)) != 0)
{
op0 = XEXP (op0, 0);
op1 = tem;
continue;
}
if (sign_bit_comparison_p)
{
op0 = XEXP (op0, 0);
code = (code == GE ? LT : GE);
continue;
}
break;
case NEG:
if (equality_comparison_p
&& (tem = simplify_unary_operation (NEG, mode, op1, mode)) != 0)
{
op0 = XEXP (op0, 0);
op1 = tem;
continue;
}
if (const_op != 0)
break;
if (sign_bit_comparison_p
&& (GET_CODE (XEXP (op0, 0)) == ABS
|| (mode_width <= HOST_BITS_PER_WIDE_INT
&& (nonzero_bits (XEXP (op0, 0), mode)
& ((HOST_WIDE_INT) 1 << (mode_width - 1))) == 0)))
{
op0 = XEXP (op0, 0);
code = (code == LT ? NE : EQ);
continue;
}
if (num_sign_bit_copies (op0, mode) >= 2)
{
op0 = XEXP (op0, 0);
code = swap_condition (code);
continue;
}
break;
case ROTATE:
if (equality_comparison_p && GET_CODE (XEXP (op0, 1)) == CONST_INT
&& (tem = simplify_binary_operation (ROTATERT, mode,
op1, XEXP (op0, 1))) != 0)
{
op0 = XEXP (op0, 0);
op1 = tem;
continue;
}
if (const_op == 0 && sign_bit_comparison_p
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
&& mode_width <= HOST_BITS_PER_WIDE_INT)
{
op0 = simplify_and_const_int (NULL_RTX, mode, XEXP (op0, 0),
((HOST_WIDE_INT) 1
<< (mode_width - 1
- INTVAL (XEXP (op0, 1)))));
code = (code == LT ? NE : EQ);
continue;
}
case ABS:
if (const_op == 0 && equality_comparison_p)
{
op0 = XEXP (op0, 0);
continue;
}
break;
case SIGN_EXTEND:
if (! unsigned_comparison_p
&& (GET_MODE_BITSIZE (GET_MODE (XEXP (op0, 0)))
<= HOST_BITS_PER_WIDE_INT)
&& ((unsigned HOST_WIDE_INT) const_op
< (((unsigned HOST_WIDE_INT) 1
<< (GET_MODE_BITSIZE (GET_MODE (XEXP (op0, 0))) - 1)))))
{
op0 = XEXP (op0, 0);
continue;
}
break;
case SUBREG:
if (mode_width <= HOST_BITS_PER_WIDE_INT
&& subreg_lowpart_p (op0)
&& GET_CODE (SUBREG_REG (op0)) == PLUS
&& GET_CODE (XEXP (SUBREG_REG (op0), 1)) == CONST_INT
&& INTVAL (XEXP (SUBREG_REG (op0), 1)) < 0
&& (- INTVAL (XEXP (SUBREG_REG (op0), 1))
< (HOST_WIDE_INT)(GET_MODE_MASK (mode) / 2))
&& (unsigned HOST_WIDE_INT) const_op < GET_MODE_MASK (mode) / 2
&& (0 == (nonzero_bits (XEXP (SUBREG_REG (op0), 0),
GET_MODE (SUBREG_REG (op0)))
& ~ 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)))
- GET_MODE_BITSIZE (mode)))))
{
op0 = SUBREG_REG (op0);
continue;
}
if (subreg_lowpart_p (op0)
&& GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0))) < mode_width)
;
else
break;
case ZERO_EXTEND:
if ((unsigned_comparison_p || equality_comparison_p)
&& (GET_MODE_BITSIZE (GET_MODE (XEXP (op0, 0)))
<= HOST_BITS_PER_WIDE_INT)
&& ((unsigned HOST_WIDE_INT) const_op
< GET_MODE_MASK (GET_MODE (XEXP (op0, 0)))))
{
op0 = XEXP (op0, 0);
continue;
}
break;
case PLUS:
if (equality_comparison_p
&& 0 != (tem = simplify_binary_operation (MINUS, mode,
op1, XEXP (op0, 1))))
{
op0 = XEXP (op0, 0);
op1 = tem;
continue;
}
if (const_op == 0 && XEXP (op0, 1) == constm1_rtx
&& GET_CODE (XEXP (op0, 0)) == ABS && sign_bit_comparison_p)
{
op0 = XEXP (XEXP (op0, 0), 0);
code = (code == LT ? EQ : NE);
continue;
}
break;
case MINUS:
if (equality_comparison_p
&& 0 != (tem = simplify_binary_operation (PLUS, mode,
XEXP (op0, 1), op1)))
{
op0 = XEXP (op0, 0);
op1 = tem;
continue;
}
if (equality_comparison_p
&& 0 != (tem = simplify_binary_operation (MINUS, mode,
XEXP (op0, 0), op1)))
{
op0 = XEXP (op0, 1);
op1 = tem;
continue;
}
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
&& rtx_equal_p (XEXP (XEXP (op0, 0), 0), XEXP (op0, 1)))
{
op0 = XEXP (op0, 1);
code = (code == GE ? LE : GT);
continue;
}
break;
case XOR:
if (equality_comparison_p
&& 0 != (tem = simplify_binary_operation (XOR, mode,
XEXP (op0, 1), op1)))
{
op0 = XEXP (op0, 0);
op1 = tem;
continue;
}
break;
case EQ: case NE:
case LT: case LTU: case LE: case LEU:
case GT: case GTU: case GE: case GEU:
if (const_op != 0
#ifdef HAVE_cc0
|| XEXP (op0, 0) == cc0_rtx
#endif
|| GET_MODE_CLASS (GET_MODE (XEXP (op0, 0))) == MODE_CC)
break;
if (GET_CODE (XEXP (op0, 0)) == COMPARE)
tem = XEXP (XEXP (op0, 0), 0), tem1 = XEXP (XEXP (op0, 0), 1);
else
tem = XEXP (op0, 0), tem1 = XEXP (op0, 1);
if (code == NE
|| (code == EQ && reversible_comparison_p (op0))
|| (GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT
&& GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
&& (STORE_FLAG_VALUE
& (((HOST_WIDE_INT) 1
<< (GET_MODE_BITSIZE (GET_MODE (op0)) - 1))))
&& (code == LT
|| (code == GE && reversible_comparison_p (op0)))))
{
code = (code == LT || code == NE
? GET_CODE (op0) : reverse_condition (GET_CODE (op0)));
op0 = tem, op1 = tem1;
continue;
}
break;
case IOR:
if (sign_bit_comparison_p && GET_CODE (XEXP (op0, 0)) == PLUS
&& XEXP (XEXP (op0, 0), 1) == constm1_rtx
&& rtx_equal_p (XEXP (XEXP (op0, 0), 0), XEXP (op0, 1)))
{
op0 = XEXP (op0, 1);
code = (code == GE ? GT : LE);
continue;
}
break;
case AND:
if (const_op == 0 && equality_comparison_p
&& GET_CODE (XEXP (op0, 0)) == ASHIFT
&& XEXP (XEXP (op0, 0), 0) == const1_rtx)
{
op0 = simplify_and_const_int
(op0, mode, gen_rtx_combine (LSHIFTRT, mode,
XEXP (op0, 1),
XEXP (XEXP (op0, 0), 1)),
(HOST_WIDE_INT) 1);
continue;
}
if (const_op == 0 && equality_comparison_p
&& mode_width <= HOST_BITS_PER_WIDE_INT
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
&& GET_CODE (XEXP (op0, 0)) == LSHIFTRT
&& GET_CODE (XEXP (XEXP (op0, 0), 1)) == CONST_INT
&& INTVAL (XEXP (XEXP (op0, 0), 1)) >= 0
&& INTVAL (XEXP (XEXP (op0, 0), 1)) < HOST_BITS_PER_WIDE_INT)
{
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))) == '<'
|| ((tem = get_last_value (XEXP (XEXP (op0, 0), 0))) != 0
&& GET_RTX_CLASS (GET_CODE (tem)) == '<')))
{
op0 = XEXP (XEXP (op0, 0), 0);
continue;
}
}
if (equality_comparison_p
&& const_op == 0
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
&& mode_width <= HOST_BITS_PER_WIDE_INT
&& ((INTVAL (XEXP (op0, 1)) & GET_MODE_MASK (mode))
== (unsigned HOST_WIDE_INT) 1 << (mode_width - 1)))
{
op0 = XEXP (op0, 0);
code = (code == EQ ? GE : LT);
continue;
}
if ((equality_comparison_p || unsigned_comparison_p)
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
&& (i = exact_log2 ((INTVAL (XEXP (op0, 1))
& GET_MODE_MASK (mode))
+ 1)) >= 0
&& const_op >> i == 0
&& (tmode = mode_for_size (i, MODE_INT, 1)) != BLKmode)
{
op0 = gen_lowpart_for_combine (tmode, XEXP (op0, 0));
continue;
}
if (GET_CODE (XEXP (op0, 0)) == SUBREG
&& ((mode_width
>= GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (XEXP (op0, 0)))))
#ifdef WORD_REGISTER_OPERATIONS
|| subreg_lowpart_p (XEXP (op0, 0))
#endif
)
#ifndef WORD_REGISTER_OPERATIONS
&& (GET_MODE_SIZE (GET_MODE (XEXP (op0, 0)))
<= GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (op0, 0)))))
#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;
}
break;
case ASHIFT:
if (GET_CODE (XEXP (op0, 1)) == CONST_INT
&& INTVAL (XEXP (op0, 1)) >= 0
&& ((INTVAL (XEXP (op0, 1)) + ! equality_comparison_p)
< HOST_BITS_PER_WIDE_INT)
&& ((const_op
& (((HOST_WIDE_INT) 1 << INTVAL (XEXP (op0, 1))) - 1)) == 0)
&& mode_width <= HOST_BITS_PER_WIDE_INT
&& (nonzero_bits (XEXP (op0, 0), mode)
& ~ (mask >> (INTVAL (XEXP (op0, 1))
+ ! equality_comparison_p))) == 0)
{
const_op >>= INTVAL (XEXP (op0, 1));
op1 = GEN_INT (const_op);
op0 = XEXP (op0, 0);
continue;
}
if (sign_bit_comparison_p && GET_CODE (XEXP (op0, 1)) == CONST_INT
&& mode_width <= HOST_BITS_PER_WIDE_INT)
{
op0 = simplify_and_const_int (NULL_RTX, mode, XEXP (op0, 0),
((HOST_WIDE_INT) 1
<< (mode_width - 1
- INTVAL (XEXP (op0, 1)))));
code = (code == LT ? NE : EQ);
continue;
}
if (const_op == 0 && equality_comparison_p
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
&& INTVAL (XEXP (op0, 1)) == mode_width - 1)
{
op0 = simplify_and_const_int (NULL_RTX, mode, XEXP (op0, 0),
(HOST_WIDE_INT) 1);
continue;
}
break;
case ASHIFTRT:
if (equality_comparison_p && const_op == 0
&& GET_CODE (XEXP (op0, 1)) == CONST_INT)
{
op0 = simplify_shift_const (NULL_RTX, LSHIFTRT, mode,
XEXP (op0, 0),
INTVAL (XEXP (op0, 1)));
continue;
}
if (! unsigned_comparison_p
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
&& GET_CODE (XEXP (op0, 0)) == ASHIFT
&& 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))))
{
op0 = gen_lowpart_for_combine (tmode, XEXP (XEXP (op0, 0), 0));
continue;
}
case LSHIFTRT:
if (GET_CODE (XEXP (op0, 1)) == CONST_INT
&& INTVAL (XEXP (op0, 1)) >= 0
&& INTVAL (XEXP (op0, 1)) < HOST_BITS_PER_WIDE_INT
&& 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)))
{
const_op <<= INTVAL (XEXP (op0, 1));
op1 = GEN_INT (const_op);
op0 = XEXP (op0, 0);
continue;
}
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)
{
op0 = XEXP (op0, 0);
code = (code == NE || code == GT ? LT : GE);
continue;
}
break;
default:
break;
}
break;
}
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
&& (code == NE || code == EQ)
&& ((GET_MODE_SIZE (GET_MODE (op0))
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))))))
{
op0 = SUBREG_REG (op0);
op1 = gen_lowpart_for_combine (GET_MODE (op0), op1);
}
else if (GET_CODE (op0) == SUBREG && subreg_lowpart_p (op0)
&& GET_MODE_CLASS (GET_MODE (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;
mode = GET_MODE (op0);
if (mode != VOIDmode && GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_SIZE (mode) < UNITS_PER_WORD
&& cmp_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing)
for (tmode = GET_MODE_WIDER_MODE (mode);
(tmode != VOIDmode
&& GET_MODE_BITSIZE (tmode) <= HOST_BITS_PER_WIDE_INT);
tmode = GET_MODE_WIDER_MODE (tmode))
if (cmp_optab->handlers[(int) tmode].insn_code != CODE_FOR_nothing)
{
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)
|| ((num_sign_bit_copies (op0, tmode)
> GET_MODE_BITSIZE (tmode) - GET_MODE_BITSIZE (mode))
&& (num_sign_bit_copies (op1, tmode)
> GET_MODE_BITSIZE (tmode) - GET_MODE_BITSIZE (mode))))
{
op0 = gen_lowpart_for_combine (tmode, op0);
op1 = gen_lowpart_for_combine (tmode, op1);
break;
}
if (op1 == const0_rtx && (code == LT || code == GE)
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
{
op0 = gen_binary (AND, tmode,
gen_lowpart_for_combine (tmode, op0),
GEN_INT ((HOST_WIDE_INT) 1
<< (GET_MODE_BITSIZE (mode) - 1)));
code = (code == LT) ? NE : EQ;
break;
}
}
#ifdef CANONICALIZE_COMPARISON
CANONICALIZE_COMPARISON (code, op0, op1);
#endif
*pop0 = op0;
*pop1 = op1;
return code;
}
static int
reversible_comparison_p (x)
rtx x;
{
if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
|| flag_fast_math
|| GET_CODE (x) == NE || GET_CODE (x) == EQ)
return 1;
switch (GET_MODE_CLASS (GET_MODE (XEXP (x, 0))))
{
case MODE_INT:
case MODE_PARTIAL_INT:
case MODE_COMPLEX_INT:
return 1;
case MODE_CC:
if (REVERSIBLE_CC_MODE (GET_MODE (XEXP (x, 0))))
return 1;
x = get_last_value (XEXP (x, 0));
return (x && GET_CODE (x) == COMPARE
&& ! FLOAT_MODE_P (GET_MODE (XEXP (x, 0))));
default:
return 0;
}
}
static void
update_table_tick (x)
rtx x;
{
register enum rtx_code code = GET_CODE (x);
register char *fmt = GET_RTX_FORMAT (code);
register int i;
if (code == REG)
{
int regno = REGNO (x);
int endregno = regno + (regno < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
for (i = regno; i < endregno; i++)
reg_last_set_table_tick[i] = label_tick;
return;
}
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
if (fmt[i] == 'e')
update_table_tick (XEXP (x, i));
}
static void
record_value_for_reg (reg, insn, value)
rtx reg;
rtx insn;
rtx value;
{
int regno = REGNO (reg);
int endregno = regno + (regno < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (regno, GET_MODE (reg)) : 1);
int i;
if (value && insn && reg_overlap_mentioned_p (reg, value))
{
rtx tem;
subst_low_cuid = INSN_CUID (insn);
tem = get_last_value (reg);
if (tem)
value = replace_rtx (copy_rtx (value), reg, tem);
}
for (i = regno; i < endregno; i ++)
{
if (insn)
reg_last_set[i] = insn;
reg_last_set_value[i] = 0;
reg_last_set_mode[i] = 0;
reg_last_set_nonzero_bits[i] = 0;
reg_last_set_sign_bit_copies[i] = 0;
reg_last_death[i] = 0;
}
if (value)
update_table_tick (value);
for (i = regno; i < endregno; i++)
{
reg_last_set_label[i] = label_tick;
if (value && reg_last_set_table_tick[i] == label_tick)
reg_last_set_invalid[i] = 1;
else
reg_last_set_invalid[i] = 0;
}
if (value && ! get_last_value_validate (&value, insn,
reg_last_set_label[regno], 0))
{
value = copy_rtx (value);
if (! get_last_value_validate (&value, insn,
reg_last_set_label[regno], 1))
value = 0;
}
reg_last_set_value[regno] = value;
if (value)
{
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_sign_bit_copies[regno]
= num_sign_bit_copies (value, GET_MODE (reg));
}
}
static rtx record_dead_insn;
static void
record_dead_and_set_regs_1 (dest, setter)
rtx dest, setter;
{
if (GET_CODE (dest) == SUBREG)
dest = SUBREG_REG (dest);
if (GET_CODE (dest) == REG)
{
if (GET_CODE (setter) == SET && dest == SET_DEST (setter))
record_value_for_reg (dest, record_dead_insn, SET_SRC (setter));
else if (GET_CODE (setter) == SET
&& GET_CODE (SET_DEST (setter)) == SUBREG
&& SUBREG_REG (SET_DEST (setter)) == dest
&& 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),
SET_SRC (setter)));
else
record_value_for_reg (dest, record_dead_insn, NULL_RTX);
}
else if (GET_CODE (dest) == MEM
&& ! push_operand (dest, GET_MODE (dest)))
mem_last_set = INSN_CUID (record_dead_insn);
}
static void
record_dead_and_set_regs (insn)
rtx insn;
{
register rtx link;
int i;
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
{
if (REG_NOTE_KIND (link) == REG_DEAD
&& GET_CODE (XEXP (link, 0)) == REG)
{
int regno = REGNO (XEXP (link, 0));
int endregno
= regno + (regno < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (regno, GET_MODE (XEXP (link, 0)))
: 1);
for (i = regno; i < endregno; i++)
reg_last_death[i] = insn;
}
else if (REG_NOTE_KIND (link) == REG_INC)
record_value_for_reg (XEXP (link, 0), insn, NULL_RTX);
}
if (GET_CODE (insn) == CALL_INSN)
{
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (call_used_regs[i])
{
reg_last_set_value[i] = 0;
reg_last_set_mode[i] = 0;
reg_last_set_nonzero_bits[i] = 0;
reg_last_set_sign_bit_copies[i] = 0;
reg_last_death[i] = 0;
}
last_call_cuid = mem_last_set = INSN_CUID (insn);
}
record_dead_insn = insn;
note_stores (PATTERN (insn), record_dead_and_set_regs_1);
}
static int
get_last_value_validate (loc, insn, tick, replace)
rtx *loc;
rtx insn;
int tick;
int replace;
{
rtx x = *loc;
char *fmt = GET_RTX_FORMAT (GET_CODE (x));
int len = GET_RTX_LENGTH (GET_CODE (x));
int i;
if (GET_CODE (x) == REG)
{
int regno = REGNO (x);
int endregno = regno + (regno < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
int j;
for (j = regno; j < endregno; j++)
if (reg_last_set_invalid[j]
|| (! (regno >= FIRST_PSEUDO_REGISTER && REG_N_SETS (regno) == 1)
&& reg_last_set_label[j] > tick))
{
if (replace)
*loc = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
return replace;
}
return 1;
}
else if (GET_CODE (x) == MEM && ! RTX_UNCHANGING_P (x)
&& INSN_CUID (insn) <= mem_last_set)
{
if (replace)
*loc = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
return replace;
}
for (i = 0; i < len; i++)
if ((fmt[i] == 'e'
&& get_last_value_validate (&XEXP (x, i), insn, tick, replace) == 0)
|| fmt[i] == 'E')
return 0;
return 1;
}
static rtx
get_last_value (x)
rtx x;
{
int regno;
rtx value;
if (GET_CODE (x) == SUBREG
&& subreg_lowpart_p (x)
&& (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);
if (GET_CODE (x) != REG)
return 0;
regno = REGNO (x);
value = reg_last_set_value[regno];
if (value == 0
|| (REG_N_SETS (regno) != 1
&& reg_last_set_label[regno] != label_tick))
return 0;
if (INSN_CUID (reg_last_set[regno]) >= subst_low_cuid)
return 0;
if (get_last_value_validate (&value, reg_last_set[regno],
reg_last_set_label[regno], 0))
return value;
value = copy_rtx (value);
if (get_last_value_validate (&value, reg_last_set[regno],
reg_last_set_label[regno], 1))
return value;
return 0;
}
static int
use_crosses_set_p (x, from_cuid)
register rtx x;
int from_cuid;
{
register char *fmt;
register int i;
register enum rtx_code code = GET_CODE (x);
if (code == REG)
{
register int regno = REGNO (x);
int endreg = regno + (regno < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
#ifdef PUSH_ROUNDING
if (regno == STACK_POINTER_REGNUM)
return 1;
#endif
for (;regno < endreg; regno++)
if (reg_last_set[regno]
&& INSN_CUID (reg_last_set[regno]) > from_cuid)
return 1;
return 0;
}
if (code == MEM && mem_last_set > from_cuid)
return 1;
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'E')
{
register int j;
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
if (use_crosses_set_p (XVECEXP (x, i, j), from_cuid))
return 1;
}
else if (fmt[i] == 'e'
&& use_crosses_set_p (XEXP (x, i), from_cuid))
return 1;
}
return 0;
}
static int reg_dead_regno, reg_dead_endregno;
static int reg_dead_flag;
static void
reg_dead_at_p_1 (dest, x)
rtx dest;
rtx x;
{
int regno, endregno;
if (GET_CODE (dest) != REG)
return;
regno = REGNO (dest);
endregno = regno + (regno < FIRST_PSEUDO_REGISTER
? 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;
}
static int
reg_dead_at_p (reg, insn)
rtx reg;
rtx insn;
{
int block, i;
reg_dead_regno = REGNO (reg);
reg_dead_endregno = reg_dead_regno + (reg_dead_regno < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (reg_dead_regno,
GET_MODE (reg))
: 1);
reg_dead_flag = 0;
if (reg_dead_regno < FIRST_PSEUDO_REGISTER)
{
for (i = reg_dead_regno; i < reg_dead_endregno; i++)
if (TEST_HARD_REG_BIT (newpat_used_regs, i))
return 0;
}
for (; insn && GET_CODE (insn) != CODE_LABEL && GET_CODE (insn) != BARRIER;
insn = prev_nonnote_insn (insn))
{
note_stores (PATTERN (insn), reg_dead_at_p_1);
if (reg_dead_flag)
return reg_dead_flag == 1 ? 1 : 0;
if (find_regno_note (insn, REG_DEAD, reg_dead_regno))
return 1;
}
if (insn == 0)
block = 0;
else
{
for (block = 0; block < n_basic_blocks; block++)
if (insn == BLOCK_HEAD (block))
break;
if (block == n_basic_blocks)
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))
return 0;
return 1;
}
static void
mark_used_regs_combine (x)
rtx x;
{
register RTX_CODE code = GET_CODE (x);
register int regno;
int i;
switch (code)
{
case LABEL_REF:
case SYMBOL_REF:
case CONST_INT:
case CONST:
case CONST_DOUBLE:
case PC:
case ADDR_VEC:
case ADDR_DIFF_VEC:
case ASM_INPUT:
#ifdef HAVE_cc0
case CC0:
#endif
return;
case CLOBBER:
if (GET_CODE (XEXP (x, 0)) == MEM)
mark_used_regs_combine (XEXP (XEXP (x, 0), 0));
return;
case REG:
regno = REGNO (x);
if (regno < FIRST_PSEUDO_REGISTER)
{
if (regno == STACK_POINTER_REGNUM
#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
|| regno == HARD_FRAME_POINTER_REGNUM
#endif
#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
|| (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
#endif
|| regno == FRAME_POINTER_REGNUM)
return;
i = HARD_REGNO_NREGS (regno, GET_MODE (x));
while (i-- > 0)
SET_HARD_REG_BIT (newpat_used_regs, regno + i);
}
return;
case SET:
{
register rtx testreg = SET_DEST (x);
while (GET_CODE (testreg) == SUBREG
|| GET_CODE (testreg) == ZERO_EXTRACT
|| GET_CODE (testreg) == SIGN_EXTRACT
|| GET_CODE (testreg) == STRICT_LOW_PART)
testreg = XEXP (testreg, 0);
if (GET_CODE (testreg) == MEM)
mark_used_regs_combine (XEXP (testreg, 0));
mark_used_regs_combine (SET_SRC (x));
}
return;
default:
break;
}
{
register char *fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
mark_used_regs_combine (XEXP (x, i));
else if (fmt[i] == 'E')
{
register int j;
for (j = 0; j < XVECLEN (x, i); j++)
mark_used_regs_combine (XVECEXP (x, i, j));
}
}
}
}
rtx
remove_death (regno, insn)
int regno;
rtx insn;
{
register rtx note = find_regno_note (insn, REG_DEAD, regno);
if (note)
{
REG_N_DEATHS (regno)--;
remove_note (insn, note);
}
return note;
}
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;
{
register char *fmt;
register int len, i;
register enum rtx_code code = GET_CODE (x);
if (code == REG)
{
register int regno = REGNO (x);
register rtx where_dead = reg_last_death[regno];
register rtx before_dead, after_dead;
if (maybe_kill_insn && reg_set_p (x, maybe_kill_insn)
&& !reg_referenced_p (x, maybe_kill_insn))
return;
before_dead = where_dead;
while (before_dead && INSN_UID (before_dead) > max_uid_cuid)
before_dead = PREV_INSN (before_dead);
after_dead = where_dead;
while (after_dead && INSN_UID (after_dead) > max_uid_cuid)
after_dead = NEXT_INSN (after_dead);
if (before_dead && after_dead
&& INSN_CUID (before_dead) >= from_cuid
&& (INSN_CUID (after_dead) < INSN_CUID (to_insn)
|| (where_dead != after_dead
&& INSN_CUID (after_dead) == INSN_CUID (to_insn))))
{
rtx note = remove_death (regno, where_dead);
if (note != 0 && regno < FIRST_PSEUDO_REGISTER
&& (GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
> GET_MODE_SIZE (GET_MODE (x))))
{
int deadregno = REGNO (XEXP (note, 0));
int deadend
= (deadregno + HARD_REGNO_NREGS (deadregno,
GET_MODE (XEXP (note, 0))));
int ourend = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
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),
REG_NOTES (where_dead));
}
else if ((note == 0
|| (note != 0
&& (GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
< GET_MODE_SIZE (GET_MODE (x)))))
&& regno < FIRST_PSEUDO_REGISTER
&& HARD_REGNO_NREGS (regno, GET_MODE (x)) > 1)
{
int ourend = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
int i, offset;
rtx oldnotes = 0;
if (note)
offset = HARD_REGNO_NREGS (regno, GET_MODE (XEXP (note, 0)));
else
offset = 1;
for (i = regno + offset; i < ourend; i++)
move_deaths (gen_rtx_REG (reg_raw_mode[i], i),
maybe_kill_insn, from_cuid, to_insn, &oldnotes);
}
if (note != 0 && GET_MODE (XEXP (note, 0)) == GET_MODE (x))
{
XEXP (note, 1) = *pnotes;
*pnotes = note;
}
else
*pnotes = gen_rtx_EXPR_LIST (REG_DEAD, x, *pnotes);
REG_N_DEATHS (regno)++;
}
return;
}
else if (GET_CODE (x) == SET)
{
rtx dest = SET_DEST (x);
move_deaths (SET_SRC (x), maybe_kill_insn, from_cuid, to_insn, pnotes);
if (GET_CODE (dest) == ZERO_EXTRACT
|| GET_CODE (dest) == STRICT_LOW_PART
|| (GET_CODE (dest) == SUBREG
&& (((GET_MODE_SIZE (GET_MODE (dest))
+ UNITS_PER_WORD - 1) / UNITS_PER_WORD)
== ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest)))
+ UNITS_PER_WORD - 1) / UNITS_PER_WORD))))
{
move_deaths (dest, maybe_kill_insn, from_cuid, to_insn, pnotes);
return;
}
if (GET_CODE (dest) == SUBREG)
dest = SUBREG_REG (dest);
if (GET_CODE (dest) == MEM)
move_deaths (XEXP (dest, 0), maybe_kill_insn, from_cuid,
to_insn, pnotes);
return;
}
else if (GET_CODE (x) == CLOBBER)
return;
len = GET_RTX_LENGTH (code);
fmt = GET_RTX_FORMAT (code);
for (i = 0; i < len; i++)
{
if (fmt[i] == 'E')
{
register int j;
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
move_deaths (XVECEXP (x, i, j), maybe_kill_insn, from_cuid,
to_insn, pnotes);
}
else if (fmt[i] == 'e')
move_deaths (XEXP (x, i), maybe_kill_insn, from_cuid, to_insn, pnotes);
}
}
static int
reg_bitfield_target_p (x, body)
rtx x;
rtx body;
{
int i;
if (GET_CODE (body) == SET)
{
rtx dest = SET_DEST (body);
rtx target;
int regno, tregno, endregno, endtregno;
if (GET_CODE (dest) == ZERO_EXTRACT)
target = XEXP (dest, 0);
else if (GET_CODE (dest) == STRICT_LOW_PART)
target = SUBREG_REG (XEXP (dest, 0));
else
return 0;
if (GET_CODE (target) == SUBREG)
target = SUBREG_REG (target);
if (GET_CODE (target) != REG)
return 0;
tregno = REGNO (target), regno = REGNO (x);
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));
return endregno > tregno && regno < endtregno;
}
else if (GET_CODE (body) == PARALLEL)
for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
if (reg_bitfield_target_p (x, XVECEXP (body, 0, i)))
return 1;
return 0;
}
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;
{
rtx note, next_note;
rtx tem;
for (note = notes; note; note = next_note)
{
rtx place = 0, place2 = 0;
if (XEXP (note, 0) && GET_CODE (XEXP (note, 0)) == REG
&& REGNO (XEXP (note, 0)) >= FIRST_PSEUDO_REGISTER)
XEXP (note, 0) = regno_reg_rtx[REGNO (XEXP (note, 0))];
next_note = XEXP (note, 1);
switch (REG_NOTE_KIND (note))
{
case REG_BR_PROB:
case REG_EXEC_COUNT:
place = i3;
break;
case REG_EH_REGION:
if (GET_CODE (i3) == CALL_INSN)
place = i3;
else if (i2 && GET_CODE (i2) == CALL_INSN)
place = i2;
else
abort ();
break;
case REG_UNUSED:
if (reg_set_p (XEXP (note, 0), PATTERN (i3)))
{
if (from_insn != i3)
break;
if (! (GET_CODE (XEXP (note, 0)) == REG
? find_regno_note (i3, REG_UNUSED, REGNO (XEXP (note, 0)))
: find_reg_note (i3, REG_UNUSED, XEXP (note, 0))))
place = i3;
}
else if (reg_referenced_p (XEXP (note, 0), PATTERN (i3))
&& ! (GET_CODE (XEXP (note, 0)) == REG
? find_regno_note (i3, REG_DEAD, REGNO (XEXP (note, 0)))
: find_reg_note (i3, REG_DEAD, XEXP (note, 0))))
{
PUT_REG_NOTE_KIND (note, REG_DEAD);
place = i3;
}
break;
case REG_EQUAL:
case REG_EQUIV:
case REG_NONNEG:
case REG_NOALIAS:
if (from_insn == i3
&& (XEXP (note, 0) == 0 || CONSTANT_P (XEXP (note, 0))))
place = i3;
break;
case REG_INC:
case REG_NO_CONFLICT:
if (reg_mentioned_p (XEXP (note, 0), PATTERN (i3)))
place = i3;
if (i2 && reg_mentioned_p (XEXP (note, 0), PATTERN (i2)))
{
if (place)
place2 = i2;
else
place = i2;
}
break;
case REG_LABEL:
if (reg_mentioned_p (XEXP (note, 0), PATTERN (i3))
|| ((tem = find_reg_note (i3, REG_EQUAL, NULL_RTX))
&& GET_CODE (XEXP (tem, 0)) == LABEL_REF
&& XEXP (XEXP (tem, 0), 0) == XEXP (note, 0)))
place = i3;
if (i2
&& (reg_mentioned_p (XEXP (note, 0), PATTERN (i2))
|| ((tem = find_reg_note (i2, REG_EQUAL, NULL_RTX))
&& GET_CODE (XEXP (tem, 0)) == LABEL_REF
&& XEXP (XEXP (tem, 0), 0) == XEXP (note, 0))))
{
if (place)
place2 = i2;
else
place = i2;
}
break;
case REG_WAS_0:
break;
case REG_RETVAL:
if (GET_CODE (from_insn) != NOTE)
place = from_insn;
else
{
tem = find_reg_note (XEXP (note, 0), REG_LIBCALL, NULL_RTX);
place = prev_real_insn (from_insn);
if (tem && place)
XEXP (tem, 0) = place;
}
break;
case REG_LIBCALL:
if (GET_CODE (from_insn) != NOTE)
place = from_insn;
else
{
tem = find_reg_note (XEXP (note, 0), REG_RETVAL, NULL_RTX);
place = next_real_insn (from_insn);
if (tem && place)
XEXP (tem, 0) = place;
}
break;
case REG_DEAD:
if (from_insn
&& GET_CODE (from_insn) == CALL_INSN
&& find_reg_fusage (from_insn, USE, XEXP (note, 0)))
place = from_insn;
else if (reg_referenced_p (XEXP (note, 0), PATTERN (i3)))
place = i3;
else if (i2 != 0 && next_nonnote_insn (i2) == i3
&& reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
place = i2;
if (XEXP (note, 0) == elim_i2 || XEXP (note, 0) == elim_i1)
break;
if (place == i3 && i2 != 0 && GET_CODE (XEXP (note, 0)) == REG
&& REG_N_REFS (REGNO (XEXP (note, 0)))== 2
&& reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
REG_N_REFS (REGNO (XEXP (note, 0))) = 3;
if (place == 0)
{
for (tem = prev_nonnote_insn (i3);
place == 0 && tem
&& (GET_CODE (tem) == INSN || GET_CODE (tem) == CALL_INSN);
tem = prev_nonnote_insn (tem))
{
if (reg_set_p (XEXP (note, 0), PATTERN (tem)))
{
rtx set = single_set (tem);
rtx inner_dest = 0;
#ifdef HAVE_cc0
rtx cc0_setter = NULL_RTX;
#endif
if (set != 0)
for (inner_dest = SET_DEST (set);
GET_CODE (inner_dest) == STRICT_LOW_PART
|| GET_CODE (inner_dest) == SUBREG
|| GET_CODE (inner_dest) == ZERO_EXTRACT;
inner_dest = XEXP (inner_dest, 0))
;
if (set != 0 && ! side_effects_p (SET_SRC (set))
&& rtx_equal_p (XEXP (note, 0), inner_dest)
#ifdef HAVE_cc0
&& (! reg_mentioned_p (cc0_rtx, SET_SRC (set))
|| ((cc0_setter = prev_cc0_setter (tem)) != NULL
&& sets_cc0_p (PATTERN (cc0_setter)) > 0))
#endif
)
{
PATTERN (tem) = pc_rtx;
distribute_notes (REG_NOTES (tem), tem, tem,
NULL_RTX, NULL_RTX, NULL_RTX);
distribute_links (LOG_LINKS (tem));
PUT_CODE (tem, NOTE);
NOTE_LINE_NUMBER (tem) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (tem) = 0;
#ifdef HAVE_cc0
if (cc0_setter)
{
PATTERN (cc0_setter) = pc_rtx;
distribute_notes (REG_NOTES (cc0_setter),
cc0_setter, cc0_setter,
NULL_RTX, NULL_RTX, NULL_RTX);
distribute_links (LOG_LINKS (cc0_setter));
PUT_CODE (cc0_setter, NOTE);
NOTE_LINE_NUMBER (cc0_setter) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (cc0_setter) = 0;
}
#endif
}
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 (! find_regno_note (tem, REG_UNUSED,
REGNO (XEXP (note, 0))))
place = tem;
break;
}
}
else if (reg_referenced_p (XEXP (note, 0), PATTERN (tem))
|| (GET_CODE (tem) == CALL_INSN
&& find_reg_fusage (tem, USE, XEXP (note, 0))))
{
place = tem;
if (i2 && INSN_UID (place) <= max_uid_cuid
&& INSN_CUID (place) > INSN_CUID (i2)
&& from_insn && INSN_CUID (from_insn) > INSN_CUID (i2)
&& reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
{
rtx links = LOG_LINKS (place);
LOG_LINKS (place) = 0;
distribute_links (links);
}
break;
}
}
if (REG_NOTE_KIND (note) == REG_DEAD && place == 0 && tem != 0)
{
place
= emit_insn_after (gen_rtx_USE (VOIDmode, XEXP (note, 0)),
tem);
if (BLOCK_END (this_basic_block - 1) == tem)
BLOCK_HEAD (this_basic_block) = place;
}
}
if (place && REG_NOTE_KIND (note) == REG_DEAD)
{
int regno = REGNO (XEXP (note, 0));
if (dead_or_set_p (place, XEXP (note, 0))
|| reg_bitfield_target_p (XEXP (note, 0), PATTERN (place)))
{
if (reg_last_death[regno] != place)
reg_last_death[regno] = 0;
place = 0;
}
else
reg_last_death[regno] = place;
if (place && regno < FIRST_PSEUDO_REGISTER
&& HARD_REGNO_NREGS (regno, GET_MODE (XEXP (note, 0))) > 1)
{
int endregno
= regno + HARD_REGNO_NREGS (regno,
GET_MODE (XEXP (note, 0)));
int all_used = 1;
int i;
for (i = regno; i < endregno; i++)
if (! refers_to_regno_p (i, i + 1, PATTERN (place), 0)
&& ! find_regno_fusage (place, USE, i))
{
rtx piece = gen_rtx_REG (reg_raw_mode[i], i);
rtx p;
for (p = place;
GET_CODE (PREV_INSN (p)) == INSN
&& GET_CODE (PATTERN (PREV_INSN (p))) == USE;
p = PREV_INSN (p))
if (rtx_equal_p (piece,
XEXP (PATTERN (PREV_INSN (p)), 0)))
{
p = 0;
break;
}
if (p)
{
rtx use_insn
= emit_insn_before (gen_rtx_USE (VOIDmode,
piece),
p);
REG_NOTES (use_insn)
= gen_rtx_EXPR_LIST (REG_DEAD, piece,
REG_NOTES (use_insn));
}
all_used = 0;
}
if (all_used)
for (i = regno; i < endregno; i++)
if (dead_or_set_regno_p (place, i))
{
all_used = 0;
break;
}
if (! all_used)
{
for (i = regno; i < endregno; i++)
{
rtx piece = gen_rtx_REG (reg_raw_mode[i], i);
if ((reg_referenced_p (piece, PATTERN (place))
|| (GET_CODE (place) == CALL_INSN
&& find_reg_fusage (place, USE, piece)))
&& ! dead_or_set_p (place, piece)
&& ! reg_bitfield_target_p (piece,
PATTERN (place)))
REG_NOTES (place)
= gen_rtx_EXPR_LIST (REG_DEAD,
piece, REG_NOTES (place));
}
place = 0;
}
}
}
break;
default:
abort ();
}
if (place)
{
XEXP (note, 1) = REG_NOTES (place);
REG_NOTES (place) = note;
}
else if ((REG_NOTE_KIND (note) == REG_DEAD
|| REG_NOTE_KIND (note) == REG_UNUSED)
&& GET_CODE (XEXP (note, 0)) == REG)
REG_N_DEATHS (REGNO (XEXP (note, 0)))--;
if (place2)
{
if ((REG_NOTE_KIND (note) == REG_DEAD
|| REG_NOTE_KIND (note) == REG_UNUSED)
&& GET_CODE (XEXP (note, 0)) == REG)
REG_N_DEATHS (REGNO (XEXP (note, 0)))++;
REG_NOTES (place2) = gen_rtx_fmt_ee (GET_CODE (note),
REG_NOTE_KIND (note),
XEXP (note, 0),
REG_NOTES (place2));
}
}
}
static void
distribute_links (links)
rtx links;
{
rtx link, next_link;
for (link = links; link; link = next_link)
{
rtx place = 0;
rtx insn;
rtx set, reg;
next_link = XEXP (link, 1);
if (GET_CODE (XEXP (link, 0)) == NOTE
|| (set = single_set (XEXP (link, 0))) == 0)
continue;
reg = SET_DEST (set);
while (GET_CODE (reg) == SUBREG || GET_CODE (reg) == ZERO_EXTRACT
|| GET_CODE (reg) == SIGN_EXTRACT
|| GET_CODE (reg) == STRICT_LOW_PART)
reg = XEXP (reg, 0);
for (insn = NEXT_INSN (XEXP (link, 0));
(insn && (this_basic_block == n_basic_blocks - 1
|| BLOCK_HEAD (this_basic_block + 1) != insn));
insn = NEXT_INSN (insn))
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
&& reg_overlap_mentioned_p (reg, PATTERN (insn)))
{
if (reg_referenced_p (reg, PATTERN (insn)))
place = insn;
break;
}
else if (GET_CODE (insn) == CALL_INSN
&& find_reg_fusage (insn, USE, reg))
{
place = insn;
break;
}
if (place)
{
rtx link2;
for (link2 = LOG_LINKS (place); link2; link2 = XEXP (link2, 1))
if (XEXP (link2, 0) == XEXP (link, 0))
break;
if (link2 == 0)
{
XEXP (link, 1) = LOG_LINKS (place);
LOG_LINKS (place) = link;
if (added_links_insn == 0
|| INSN_CUID (added_links_insn) > INSN_CUID (place))
added_links_insn = place;
}
}
}
}
static int
insn_cuid (insn)
rtx insn;
{
while (insn != 0 && INSN_UID (insn) > max_uid_cuid
&& GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == USE)
insn = NEXT_INSN (insn);
if (INSN_UID (insn) > max_uid_cuid)
abort ();
return INSN_CUID (insn);
}
void
dump_combine_stats (file)
FILE *file;
{
fnotice
(file,
";; Combiner statistics: %d attempts, %d substitutions (%d requiring new space),\n;; %d successes.\n\n",
combine_attempts, combine_merges, combine_extras, combine_successes);
}
void
dump_combine_total_stats (file)
FILE *file;
{
fnotice
(file,
"\n;; Combiner totals: %d attempts, %d substitutions (%d requiring new space),\n;; %d successes.\n",
total_attempts, total_merges, total_extras, total_successes);
}