#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
#include "tree.h"
#include "tm_p.h"
#include "flags.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "basic-block.h"
#include "insn-config.h"
#include "function.h"
#include "expr.h"
#include "insn-attr.h"
#include "recog.h"
#include "real.h"
#include "toplev.h"
#include "target.h"
#include "optabs.h"
#include "insn-codes.h"
#include "rtlhooks-def.h"
#include "output.h"
#include "params.h"
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;
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)])
#define UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD(val) \
(((unsigned HOST_WIDE_INT) (val) << (BITS_PER_WORD - 1)) << 1)
static unsigned int combine_max_regno;
struct reg_stat {
rtx last_death;
rtx last_set;
rtx last_set_value;
int last_set_table_tick;
int last_set_label;
unsigned HOST_WIDE_INT last_set_nonzero_bits;
char last_set_sign_bit_copies;
ENUM_BITFIELD(machine_mode) last_set_mode : 8;
char last_set_invalid;
unsigned char sign_bit_copies;
unsigned HOST_WIDE_INT nonzero_bits;
};
static struct reg_stat *reg_stat;
static int mem_last_set;
static int last_call_cuid;
static rtx subst_insn;
static int subst_low_cuid;
static HARD_REG_SET newpat_used_regs;
static rtx added_links_insn;
static basic_block this_basic_block;
static sbitmap refresh_blocks;
static int *uid_insn_cost;
static int last_insn_cost;
static int label_tick;
static enum machine_mode nonzero_bits_mode;
static int nonzero_sign_valid;
struct undo
{
struct undo *next;
int is_int;
union {rtx r; int i;} old_contents;
union {rtx *r; int *i;} where;
};
struct undobuf
{
struct undo *undos;
struct undo *frees;
rtx other_insn;
};
static struct undobuf undobuf;
static int n_occurrences;
static rtx reg_nonzero_bits_for_combine (rtx, enum machine_mode, rtx,
enum machine_mode,
unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT *);
static rtx reg_num_sign_bit_copies_for_combine (rtx, enum machine_mode, rtx,
enum machine_mode,
unsigned int, unsigned int *);
static void do_SUBST (rtx *, rtx);
static void do_SUBST_INT (int *, int);
static void init_reg_last (void);
static void setup_incoming_promotions (void);
static void set_nonzero_bits_and_sign_copies (rtx, rtx, void *);
static int cant_combine_insn_p (rtx);
static int can_combine_p (rtx, rtx, rtx, rtx, rtx *, rtx *);
static int combinable_i3pat (rtx, rtx *, rtx, rtx, int, rtx *);
static int contains_muldiv (rtx);
static rtx try_combine (rtx, rtx, rtx, int *);
static void undo_all (void);
static void undo_commit (void);
static rtx *find_split_point (rtx *, rtx);
static rtx subst (rtx, rtx, rtx, int, int);
static rtx combine_simplify_rtx (rtx, enum machine_mode, int);
static rtx simplify_if_then_else (rtx);
static rtx simplify_set (rtx);
static rtx simplify_logical (rtx);
static rtx expand_compound_operation (rtx);
static rtx expand_field_assignment (rtx);
static rtx make_extraction (enum machine_mode, rtx, HOST_WIDE_INT,
rtx, unsigned HOST_WIDE_INT, int, int, int);
static rtx extract_left_shift (rtx, int);
static rtx make_compound_operation (rtx, enum rtx_code);
static int get_pos_from_mask (unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT *);
static rtx force_to_mode (rtx, enum machine_mode,
unsigned HOST_WIDE_INT, rtx, int);
static rtx if_then_else_cond (rtx, rtx *, rtx *);
static rtx known_cond (rtx, enum rtx_code, rtx, rtx);
static int rtx_equal_for_field_assignment_p (rtx, rtx);
static rtx make_field_assignment (rtx);
static rtx apply_distributive_law (rtx);
static rtx distribute_and_simplify_rtx (rtx, int);
static rtx simplify_and_const_int (rtx, enum machine_mode, rtx,
unsigned HOST_WIDE_INT);
static int merge_outer_ops (enum rtx_code *, HOST_WIDE_INT *, enum rtx_code,
HOST_WIDE_INT, enum machine_mode, int *);
static rtx simplify_shift_const (rtx, enum rtx_code, enum machine_mode, rtx,
int);
static int recog_for_combine (rtx *, rtx, rtx *);
static rtx gen_lowpart_for_combine (enum machine_mode, rtx);
static enum rtx_code simplify_comparison (enum rtx_code, rtx *, rtx *);
static void update_table_tick (rtx);
static void record_value_for_reg (rtx, rtx, rtx);
static void check_promoted_subreg (rtx, rtx);
static void record_dead_and_set_regs_1 (rtx, rtx, void *);
static void record_dead_and_set_regs (rtx);
static int get_last_value_validate (rtx *, rtx, int, int);
static rtx get_last_value (rtx);
static int use_crosses_set_p (rtx, int);
static void reg_dead_at_p_1 (rtx, rtx, void *);
static int reg_dead_at_p (rtx, rtx);
static void move_deaths (rtx, rtx, int, rtx, rtx *);
static int reg_bitfield_target_p (rtx, rtx);
static void distribute_notes (rtx, rtx, rtx, rtx);
static void distribute_links (rtx);
static void mark_used_regs_combine (rtx);
static int insn_cuid (rtx);
static void record_promoted_value (rtx, rtx);
static rtx reversed_comparison (rtx, enum machine_mode, rtx, rtx);
static enum rtx_code combine_reversed_comparison_code (rtx);
static int unmentioned_reg_p_1 (rtx *, void *);
static bool unmentioned_reg_p (rtx, rtx);
#undef RTL_HOOKS_GEN_LOWPART
#define RTL_HOOKS_GEN_LOWPART gen_lowpart_for_combine
#undef RTL_HOOKS_REG_NONZERO_REG_BITS
#define RTL_HOOKS_REG_NONZERO_REG_BITS reg_nonzero_bits_for_combine
#undef RTL_HOOKS_REG_NUM_SIGN_BIT_COPIES
#define RTL_HOOKS_REG_NUM_SIGN_BIT_COPIES reg_num_sign_bit_copies_for_combine
static const struct rtl_hooks combine_rtl_hooks = RTL_HOOKS_INITIALIZER;
static void
do_SUBST (rtx *into, rtx newval)
{
struct undo *buf;
rtx oldval = *into;
if (oldval == newval)
return;
if (GET_MODE_CLASS (GET_MODE (oldval)) == MODE_INT
&& GET_CODE (newval) == CONST_INT)
{
gcc_assert (INTVAL (newval)
== trunc_int_for_mode (INTVAL (newval), GET_MODE (oldval)));
gcc_assert (!(GET_CODE (oldval) == SUBREG
&& GET_CODE (SUBREG_REG (oldval)) == CONST_INT));
gcc_assert (!(GET_CODE (oldval) == ZERO_EXTEND
&& GET_CODE (XEXP (oldval, 0)) == CONST_INT));
}
if (undobuf.frees)
buf = undobuf.frees, undobuf.frees = buf->next;
else
buf = xmalloc (sizeof (struct undo));
buf->is_int = 0;
buf->where.r = into;
buf->old_contents.r = oldval;
*into = newval;
buf->next = undobuf.undos, undobuf.undos = buf;
}
#define SUBST(INTO, NEWVAL) do_SUBST(&(INTO), (NEWVAL))
static void
do_SUBST_INT (int *into, int newval)
{
struct undo *buf;
int oldval = *into;
if (oldval == newval)
return;
if (undobuf.frees)
buf = undobuf.frees, undobuf.frees = buf->next;
else
buf = xmalloc (sizeof (struct undo));
buf->is_int = 1;
buf->where.i = into;
buf->old_contents.i = oldval;
*into = newval;
buf->next = undobuf.undos, undobuf.undos = buf;
}
#define SUBST_INT(INTO, NEWVAL) do_SUBST_INT(&(INTO), (NEWVAL))
static bool
combine_validate_cost (rtx i1, rtx i2, rtx i3, rtx newpat, rtx newi2pat)
{
int i1_cost, i2_cost, i3_cost;
int new_i2_cost, new_i3_cost;
int old_cost, new_cost;
i2_cost = INSN_UID (i2) <= last_insn_cost
? uid_insn_cost[INSN_UID (i2)] : 0;
i3_cost = INSN_UID (i3) <= last_insn_cost
? uid_insn_cost[INSN_UID (i3)] : 0;
if (i1)
{
i1_cost = INSN_UID (i1) <= last_insn_cost
? uid_insn_cost[INSN_UID (i1)] : 0;
old_cost = (i1_cost > 0 && i2_cost > 0 && i3_cost > 0)
? i1_cost + i2_cost + i3_cost : 0;
}
else
{
old_cost = (i2_cost > 0 && i3_cost > 0) ? i2_cost + i3_cost : 0;
i1_cost = 0;
}
new_i3_cost = insn_rtx_cost (newpat);
if (newi2pat)
{
new_i2_cost = insn_rtx_cost (newi2pat);
new_cost = (new_i2_cost > 0 && new_i3_cost > 0)
? new_i2_cost + new_i3_cost : 0;
}
else
{
new_cost = new_i3_cost;
new_i2_cost = 0;
}
if (undobuf.other_insn)
{
int old_other_cost, new_other_cost;
old_other_cost = (INSN_UID (undobuf.other_insn) <= last_insn_cost
? uid_insn_cost[INSN_UID (undobuf.other_insn)] : 0);
new_other_cost = insn_rtx_cost (PATTERN (undobuf.other_insn));
if (old_other_cost > 0 && new_other_cost > 0)
{
old_cost += old_other_cost;
new_cost += new_other_cost;
}
else
old_cost = 0;
}
if (old_cost > 0
&& new_cost > old_cost)
{
if (dump_file)
{
if (i1)
{
fprintf (dump_file,
"rejecting combination of insns %d, %d and %d\n",
INSN_UID (i1), INSN_UID (i2), INSN_UID (i3));
fprintf (dump_file, "original costs %d + %d + %d = %d\n",
i1_cost, i2_cost, i3_cost, old_cost);
}
else
{
fprintf (dump_file,
"rejecting combination of insns %d and %d\n",
INSN_UID (i2), INSN_UID (i3));
fprintf (dump_file, "original costs %d + %d = %d\n",
i2_cost, i3_cost, old_cost);
}
if (newi2pat)
{
fprintf (dump_file, "replacement costs %d + %d = %d\n",
new_i2_cost, new_i3_cost, new_cost);
}
else
fprintf (dump_file, "replacement cost %d\n", new_cost);
}
return false;
}
uid_insn_cost[INSN_UID (i2)] = new_i2_cost;
uid_insn_cost[INSN_UID (i3)] = new_i3_cost;
if (i1)
uid_insn_cost[INSN_UID (i1)] = 0;
return true;
}
int
combine_instructions (rtx f, unsigned int nregs)
{
rtx insn, next;
#ifdef HAVE_cc0
rtx prev;
#endif
int i;
rtx links, nextlinks;
int new_direct_jump_p = 0;
combine_attempts = 0;
combine_merges = 0;
combine_extras = 0;
combine_successes = 0;
combine_max_regno = nregs;
rtl_hooks = combine_rtl_hooks;
reg_stat = xcalloc (nregs, sizeof (struct reg_stat));
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 = xmalloc ((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;
setup_incoming_promotions ();
refresh_blocks = sbitmap_alloc (last_basic_block);
sbitmap_zero (refresh_blocks);
uid_insn_cost = xcalloc (max_uid_cuid + 1, sizeof (int));
last_insn_cost = max_uid_cuid;
for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
{
uid_cuid[INSN_UID (insn)] = ++i;
subst_low_cuid = i;
subst_insn = insn;
if (INSN_P (insn))
{
note_stores (PATTERN (insn), set_nonzero_bits_and_sign_copies,
NULL);
record_dead_and_set_regs (insn);
#ifdef AUTO_INC_DEC
for (links = REG_NOTES (insn); links; links = XEXP (links, 1))
if (REG_NOTE_KIND (links) == REG_INC)
set_nonzero_bits_and_sign_copies (XEXP (links, 0), NULL_RTX,
NULL);
#endif
if (NONJUMP_INSN_P (insn))
uid_insn_cost[INSN_UID (insn)] = insn_rtx_cost (PATTERN (insn));
if (dump_file)
fprintf(dump_file, "insn_cost %d: %d\n",
INSN_UID (insn), uid_insn_cost[INSN_UID (insn)]);
}
if (LABEL_P (insn))
label_tick++;
}
nonzero_sign_valid = 1;
label_tick = 1;
last_call_cuid = 0;
mem_last_set = 0;
init_reg_last ();
setup_incoming_promotions ();
FOR_EACH_BB (this_basic_block)
{
for (insn = BB_HEAD (this_basic_block);
insn != NEXT_INSN (BB_END (this_basic_block));
insn = next ? next : NEXT_INSN (insn))
{
next = 0;
if (LABEL_P (insn))
label_tick++;
else if (INSN_P (insn))
{
check_promoted_subreg (insn, PATTERN (insn));
for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
if ((next = try_combine (insn, XEXP (links, 0),
NULL_RTX, &new_direct_jump_p)) != 0)
goto retry;
for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
{
rtx link = XEXP (links, 0);
if (NOTE_P (link))
continue;
for (nextlinks = LOG_LINKS (link);
nextlinks;
nextlinks = XEXP (nextlinks, 1))
if ((next = try_combine (insn, link,
XEXP (nextlinks, 0),
&new_direct_jump_p)) != 0)
goto retry;
}
#ifdef HAVE_cc0
if (JUMP_P (insn)
&& (prev = prev_nonnote_insn (insn)) != 0
&& NONJUMP_INSN_P (prev)
&& sets_cc0_p (PATTERN (prev)))
{
if ((next = try_combine (insn, prev,
NULL_RTX, &new_direct_jump_p)) != 0)
goto retry;
for (nextlinks = LOG_LINKS (prev); nextlinks;
nextlinks = XEXP (nextlinks, 1))
if ((next = try_combine (insn, prev,
XEXP (nextlinks, 0),
&new_direct_jump_p)) != 0)
goto retry;
}
if (NONJUMP_INSN_P (insn)
&& (prev = prev_nonnote_insn (insn)) != 0
&& NONJUMP_INSN_P (prev)
&& sets_cc0_p (PATTERN (prev))
&& GET_CODE (PATTERN (insn)) == SET
&& reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (insn))))
{
if ((next = try_combine (insn, prev,
NULL_RTX, &new_direct_jump_p)) != 0)
goto retry;
for (nextlinks = LOG_LINKS (prev); nextlinks;
nextlinks = XEXP (nextlinks, 1))
if ((next = try_combine (insn, prev,
XEXP (nextlinks, 0),
&new_direct_jump_p)) != 0)
goto retry;
}
for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
if (NONJUMP_INSN_P (XEXP (links, 0))
&& 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
&& NONJUMP_INSN_P (prev)
&& sets_cc0_p (PATTERN (prev))
&& (next = try_combine (insn, XEXP (links, 0),
prev, &new_direct_jump_p)) != 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),
&new_direct_jump_p)) != 0)
goto retry;
for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
{
rtx set, note;
rtx temp = XEXP (links, 0);
if ((set = single_set (temp)) != 0
&& (note = find_reg_equal_equiv_note (temp)) != 0
&& GET_CODE (XEXP (note, 0)) != EXPR_LIST
&& ! unmentioned_reg_p (XEXP (note, 0), SET_SRC (set)))
{
rtx orig = SET_SRC (set);
SET_SRC (set) = XEXP (note, 0);
next = try_combine (insn, temp, NULL_RTX,
&new_direct_jump_p);
if (next)
goto retry;
SET_SRC (set) = orig;
}
}
if (!NOTE_P (insn))
record_dead_and_set_regs (insn);
retry:
;
}
}
}
clear_bb_flags ();
EXECUTE_IF_SET_IN_SBITMAP (refresh_blocks, 0, i,
BASIC_BLOCK (i)->flags |= BB_DIRTY);
new_direct_jump_p |= purge_all_dead_edges (0);
delete_noop_moves ();
update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES,
PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE
| PROP_KILL_DEAD_CODE);
sbitmap_free (refresh_blocks);
free (uid_insn_cost);
free (reg_stat);
free (uid_cuid);
{
struct undo *undo, *next;
for (undo = undobuf.frees; undo; undo = next)
{
next = undo->next;
free (undo);
}
undobuf.frees = 0;
}
total_attempts += combine_attempts;
total_merges += combine_merges;
total_extras += combine_extras;
total_successes += combine_successes;
nonzero_sign_valid = 0;
rtl_hooks = general_rtl_hooks;
init_recog ();
return new_direct_jump_p;
}
static void
init_reg_last (void)
{
unsigned int i;
for (i = 0; i < combine_max_regno; i++)
memset (reg_stat + i, 0, offsetof (struct reg_stat, sign_bit_copies));
}
static void
setup_incoming_promotions (void)
{
unsigned int regno;
rtx reg;
enum machine_mode mode;
int unsignedp;
rtx first = get_insns ();
if (targetm.calls.promote_function_args (TREE_TYPE (cfun->decl)))
{
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (FUNCTION_ARG_REGNO_P (OUTGOING_REGNO (regno))
&& (reg = promoted_input_arg (regno, &mode, &unsignedp)) != 0)
{
record_value_for_reg
(reg, first, gen_rtx_fmt_e ((unsignedp ? ZERO_EXTEND
: SIGN_EXTEND),
GET_MODE (reg),
gen_rtx_CLOBBER (mode, const0_rtx)));
}
}
}
static void
set_nonzero_bits_and_sign_copies (rtx x, rtx set,
void *data ATTRIBUTE_UNUSED)
{
unsigned int num;
if (REG_P (x)
&& REGNO (x) >= FIRST_PSEUDO_REGISTER
&& ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start, REGNO (x))
&& GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT)
{
if (set == 0 || GET_CODE (set) == CLOBBER)
{
reg_stat[REGNO (x)].nonzero_bits = GET_MODE_MASK (GET_MODE (x));
reg_stat[REGNO (x)].sign_bit_copies = 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
if (reg_stat[REGNO (x)].nonzero_bits != ~(unsigned HOST_WIDE_INT) 0)
reg_stat[REGNO (x)].nonzero_bits
|= nonzero_bits (src, nonzero_bits_mode);
num = num_sign_bit_copies (SET_SRC (set), GET_MODE (x));
if (reg_stat[REGNO (x)].sign_bit_copies == 0
|| reg_stat[REGNO (x)].sign_bit_copies > num)
reg_stat[REGNO (x)].sign_bit_copies = num;
}
else
{
reg_stat[REGNO (x)].nonzero_bits = GET_MODE_MASK (GET_MODE (x));
reg_stat[REGNO (x)].sign_bit_copies = 1;
}
}
}
static int
can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
rtx *pdest, rtx *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);
rtx note;
switch (GET_CODE (elt))
{
case USE:
if (REG_P (XEXP (elt, 0))
&& GET_CODE (PATTERN (i3)) == PARALLEL)
{
rtx i3pat = PATTERN (i3);
int i = XVECLEN (i3pat, 0) - 1;
unsigned int regno = REGNO (XEXP (elt, 0));
do
{
rtx i3elt = XVECEXP (i3pat, 0, i);
if (GET_CODE (i3elt) == USE
&& REG_P (XEXP (i3elt, 0))
&& (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))
&& (!(note = find_reg_note (insn, REG_EH_REGION, NULL_RTX))
|| INTVAL (XEXP (note, 0)) <= 0)
&& ! 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
|| (rtx_equal_p (src, dest) && find_reg_note (insn, REG_EQUAL, NULL_RTX))
|| GET_CODE (src) == ASM_OPERANDS
|| GET_CODE (src) == CALL
|| (CALL_P (i3)
&& (find_reg_fusage (i3, USE, dest)
|| (REG_P (dest)
&& REGNO (dest) < FIRST_PSEUDO_REGISTER
&& global_regs[REGNO (dest)])))
|| FIND_REG_INC_NOTE (i3, dest)
|| (succ && FIND_REG_INC_NOTE (succ, dest))
|| (JUMP_P (i3) && find_reg_note (i3, REG_NON_LOCAL_GOTO, NULL_RTX))
#if 0
|| find_reg_note (insn, REG_RETVAL, NULL_RTX)
#endif
|| (succ && ! all_adjacent
&& reg_used_between_p (dest, succ, i3))
|| (! all_adjacent
&& (((!MEM_P (src)
|| ! find_reg_note (insn, REG_EQUIV, src))
&& use_crosses_set_p (src, INSN_CUID (insn)))
|| (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 (REG_P (dest))
{
if (REG_P (src)
&& ((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)))))
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)
{
rtx reg = XEXP (XVECEXP (PATTERN (i3), 0, i), 0);
if (rtx_equal_p (reg, dest))
return 0;
if (!REG_P (reg)
|| REGNO (reg) >= FIRST_PSEUDO_REGISTER
|| !fixed_regs[REGNO (reg)])
if (reg_overlap_mentioned_p (reg, src))
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 (INSN_P (p) && p != succ && volatile_refs_p (PATTERN (p)))
return 0;
}
if (GET_CODE (src) == ASM_OPERANDS
&& REG_P (dest) && REGNO (dest) < FIRST_PSEUDO_REGISTER)
return 0;
for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))
if (INSN_P (p) && 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
&& (JUMP_P (i3)
|| reg_used_between_p (XEXP (link, 0), insn, i3)
|| (pred != NULL_RTX
&& reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (pred)))
|| (succ != NULL_RTX
&& reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (succ)))
|| reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i3))))
return 0;
#endif
#ifdef HAVE_cc0
p = prev_nonnote_insn (insn);
if (p && p != pred && NONJUMP_INSN_P (p) && sets_cc0_p (PATTERN (p))
&& ! all_adjacent)
return 0;
#endif
*pdest = dest;
*psrc = src;
return 1;
}
static int
combinable_i3pat (rtx i3, rtx *loc, rtx i2dest, rtx i1dest,
int i1_not_in_src, rtx *pi3dest_killed)
{
rtx x = *loc;
if (GET_CODE (x) == SET)
{
rtx set = x ;
rtx dest = SET_DEST (set);
rtx src = SET_SRC (set);
rtx inner_dest = dest;
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 ((inner_dest != dest &&
(!MEM_P (inner_dest)
|| rtx_equal_p (i2dest, inner_dest)
|| (i1dest && rtx_equal_p (i1dest, inner_dest)))
&& (reg_overlap_mentioned_p (i2dest, inner_dest)
|| (i1dest && reg_overlap_mentioned_p (i1dest, inner_dest))))
|| (REG_P (inner_dest)
&& REGNO (inner_dest) < FIRST_PSEUDO_REGISTER
&& (! HARD_REGNO_MODE_OK (REGNO (inner_dest),
GET_MODE (inner_dest))))
|| (i1_not_in_src && reg_overlap_mentioned_p (i1dest, src)))
return 0;
if (pi3dest_killed && REG_P (dest)
&& 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 int
contains_muldiv (rtx x)
{
switch (GET_CODE (x))
{
case MOD: case DIV: case UMOD: case UDIV:
return 1;
case MULT:
return ! (GET_CODE (XEXP (x, 1)) == CONST_INT
&& exact_log2 (INTVAL (XEXP (x, 1))) >= 0);
default:
if (BINARY_P (x))
return contains_muldiv (XEXP (x, 0))
|| contains_muldiv (XEXP (x, 1));
if (UNARY_P (x))
return contains_muldiv (XEXP (x, 0));
return 0;
}
}
static int
cant_combine_insn_p (rtx insn)
{
rtx set;
rtx src, dest;
if (! INSN_P (insn))
return 1;
set = single_set (insn);
if (! set)
return 0;
src = SET_SRC (set);
dest = SET_DEST (set);
if (GET_CODE (src) == SUBREG)
src = SUBREG_REG (src);
if (GET_CODE (dest) == SUBREG)
dest = SUBREG_REG (dest);
if (REG_P (src) && REG_P (dest)
&& ((REGNO (src) < FIRST_PSEUDO_REGISTER
&& ! fixed_regs[REGNO (src)]
&& CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (REGNO (src))))
|| (REGNO (dest) < FIRST_PSEUDO_REGISTER
&& ! fixed_regs[REGNO (dest)]
&& CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (REGNO (dest))))))
return 1;
return 0;
}
static void
adjust_for_new_dest (rtx insn)
{
rtx *loc;
loc = ®_NOTES (insn);
while (*loc)
{
enum reg_note kind = REG_NOTE_KIND (*loc);
if (kind == REG_EQUAL || kind == REG_EQUIV)
*loc = XEXP (*loc, 1);
else
loc = &XEXP (*loc, 1);
}
distribute_links (gen_rtx_INSN_LIST (VOIDmode, insn, NULL_RTX));
}
static rtx
try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
{
rtx newpat, newi2pat = 0;
int substed_i2 = 0, substed_i1 = 0;
int added_sets_1, added_sets_2;
int total_sets;
int i2_is_used;
int insn_code_number, i2_code_number = 0, other_code_number = 0;
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 swap_i2i3 = 0;
int maxreg;
rtx temp;
rtx link;
int i;
if (cant_combine_insn_p (i3)
|| cant_combine_insn_p (i2)
|| (i1 && cant_combine_insn_p (i1))
#if 0
|| find_reg_note (i3, REG_LIBCALL, NULL_RTX)
#endif
)
return 0;
combine_attempts++;
undobuf.other_insn = 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 && NONJUMP_INSN_P (i3) && GET_CODE (PATTERN (i3)) == SET
&& REG_P (SET_SRC (PATTERN (i3)))
&& REGNO (SET_SRC (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER
&& 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 ((GET_CODE (XVECEXP (p2, 0, i)) == SET
|| GET_CODE (XVECEXP (p2, 0, i)) == CLOBBER)
&& 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;
}
}
if (i1 == 0
&& (temp = single_set (i2)) != 0
&& (GET_CODE (SET_SRC (temp)) == CONST_INT
|| GET_CODE (SET_SRC (temp)) == CONST_DOUBLE)
&& REG_P (SET_DEST (temp))
&& GET_MODE_CLASS (GET_MODE (SET_DEST (temp))) == MODE_INT
&& GET_MODE_SIZE (GET_MODE (SET_DEST (temp))) == 2 * UNITS_PER_WORD
&& GET_CODE (PATTERN (i3)) == SET
&& GET_CODE (SET_DEST (PATTERN (i3))) == SUBREG
&& SUBREG_REG (SET_DEST (PATTERN (i3))) == SET_DEST (temp)
&& GET_MODE_CLASS (GET_MODE (SET_DEST (PATTERN (i3)))) == MODE_INT
&& GET_MODE_SIZE (GET_MODE (SET_DEST (PATTERN (i3)))) == UNITS_PER_WORD
&& GET_CODE (SET_SRC (PATTERN (i3))) == CONST_INT)
{
HOST_WIDE_INT lo, hi;
if (GET_CODE (SET_SRC (temp)) == CONST_INT)
lo = INTVAL (SET_SRC (temp)), hi = lo < 0 ? -1 : 0;
else
{
lo = CONST_DOUBLE_LOW (SET_SRC (temp));
hi = CONST_DOUBLE_HIGH (SET_SRC (temp));
}
if (subreg_lowpart_p (SET_DEST (PATTERN (i3))))
{
gcc_assert (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD);
lo &= ~(UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD (1) - 1);
lo |= (INTVAL (SET_SRC (PATTERN (i3)))
& (UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD (1) - 1));
}
else if (HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)
hi = INTVAL (SET_SRC (PATTERN (i3)));
else if (HOST_BITS_PER_WIDE_INT >= 2 * BITS_PER_WORD)
{
int sign = -(int) ((unsigned HOST_WIDE_INT) lo
>> (HOST_BITS_PER_WIDE_INT - 1));
lo &= ~ (UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD
(UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD (1) - 1));
lo |= (UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD
(INTVAL (SET_SRC (PATTERN (i3)))));
if (hi == sign)
hi = lo < 0 ? -1 : 0;
}
else
gcc_unreachable ();
combine_merges++;
subst_insn = i3;
subst_low_cuid = INSN_CUID (i2);
added_sets_2 = added_sets_1 = 0;
i2dest = SET_DEST (temp);
SUBST (SET_SRC (temp),
immed_double_const (lo, hi, GET_MODE (SET_DEST (temp))));
newpat = PATTERN (i2);
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
&& REG_P (SET_DEST (XVECEXP (PATTERN (i2), 0, 1)))
&& 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)
{
i1 = gen_rtx_INSN (VOIDmode, INSN_UID (i2), NULL_RTX, i2,
BLOCK_FOR_INSN (i2), INSN_LOCATOR (i2),
XVECEXP (PATTERN (i2), 0, 1), -1, NULL_RTX,
NULL_RTX);
SUBST (PATTERN (i2), XVECEXP (PATTERN (i2), 0, 0));
SUBST (XEXP (SET_SRC (PATTERN (i2)), 0),
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
&& REG_P (SET_SRC (PATTERN (i3)))
&& MEM_P (SET_DEST (PATTERN (i3)))
&& (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);
}
}
#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 SELECT_CC_MODE
rtx *cc_use;
enum machine_mode compare_mode;
#endif
newpat = PATTERN (i3);
SUBST (XEXP (SET_SRC (newpat), 0), i2src);
i2_is_used = 1;
#ifdef SELECT_CC_MODE
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))))
{
unsigned 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_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);
substed_i2 = 1;
i2_is_used = n_occurrences;
}
if (i1 && GET_CODE (newpat) != CLOBBER)
{
if (! combinable_i3pat (NULL_RTX, &newpat, i1dest, NULL_RTX,
0, (rtx*) 0))
{
undo_all ();
return 0;
}
n_occurrences = 0;
subst_low_cuid = INSN_CUID (i1);
newpat = subst (newpat, i1dest, i1src, 0, 0);
substed_i1 = 1;
}
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));
memcpy (XVEC (newpat, 0)->elem, &old->elem[0],
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
&& !(added_sets_2 && i1 == 0)
&& GET_CODE (newpat) == PARALLEL
&& XVECLEN (newpat, 0) == 2
&& GET_CODE (XVECEXP (newpat, 0, 0)) == SET
&& GET_CODE (XVECEXP (newpat, 0, 1)) == SET
&& asm_noperands (newpat) < 0)
{
rtx set0 = XVECEXP (newpat, 0, 0);
rtx set1 = XVECEXP (newpat, 0, 1);
rtx note;
if (((REG_P (SET_DEST (set1))
&& find_reg_note (i3, REG_UNUSED, SET_DEST (set1)))
|| (GET_CODE (SET_DEST (set1)) == SUBREG
&& find_reg_note (i3, REG_UNUSED, SUBREG_REG (SET_DEST (set1)))))
&& (!(note = find_reg_note (i3, REG_EH_REGION, NULL_RTX))
|| INTVAL (XEXP (note, 0)) <= 0)
&& ! side_effects_p (SET_SRC (set1)))
{
newpat = set0;
insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
}
else if (((REG_P (SET_DEST (set0))
&& find_reg_note (i3, REG_UNUSED, SET_DEST (set0)))
|| (GET_CODE (SET_DEST (set0)) == SUBREG
&& find_reg_note (i3, REG_UNUSED,
SUBREG_REG (SET_DEST (set0)))))
&& (!(note = find_reg_note (i3, REG_EH_REGION, NULL_RTX))
|| INTVAL (XEXP (note, 0)) <= 0)
&& ! side_effects_p (SET_SRC (set0)))
{
newpat = set1;
insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
if (insn_code_number >= 0)
{
PATTERN (i3) = newpat;
adjust_for_new_dest (i3);
}
}
}
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
&& REG_P (i2dest)
&& (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 && ni2dest != i2dest)
{
ni2dest = i2dest;
m_split = split_insns (gen_rtx_PARALLEL
(VOIDmode,
gen_rtvec (2, newpat,
gen_rtx_CLOBBER (VOIDmode,
i2dest))),
i3);
}
}
if (m_split && NEXT_INSN (m_split) == NULL_RTX)
{
m_split = PATTERN (m_split);
insn_code_number = recog_for_combine (&m_split, i3, &new_i3_notes);
if (insn_code_number >= 0)
newpat = m_split;
}
else if (m_split && NEXT_INSN (NEXT_INSN (m_split)) == NULL_RTX
&& (next_real_insn (i2) == i3
|| ! use_crosses_set_p (PATTERN (m_split), INSN_CUID (i2))))
{
rtx i2set, i3set;
rtx newi3pat = PATTERN (NEXT_INSN (m_split));
newi2pat = PATTERN (m_split);
i3set = single_set (NEXT_INSN (m_split));
i2set = single_set (m_split);
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 (REG_P (new_i3_dest)
&& REG_P (new_i2_dest)
&& REGNO (new_i3_dest) == REGNO (new_i2_dest))
REG_N_SETS (REGNO (new_i2_dest))++;
}
}
if (insn_code_number < 0 && (split = find_split_point (&newpat, i3)) != 0
#ifdef HAVE_cc0
&& REG_P (i2dest)
#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
&& INTVAL (XEXP (*split, 1)) > 0
&& (i = exact_log2 (INTVAL (XEXP (*split, 1)))) >= 0)
{
SUBST (*split, gen_rtx_ASHIFT (split_mode,
XEXP (*split, 0), GEN_INT (i)));
split_code = GET_CODE (*split);
}
#ifdef INSN_SCHEDULING
if (split_code == SUBREG && MEM_P (SUBREG_REG (*split)))
{
#ifdef LOAD_EXTEND_OP
if (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (*split)))
== SIGN_EXTEND)
SUBST (*split, gen_rtx_SIGN_EXTEND (split_mode,
SUBREG_REG (*split)));
else
#endif
SUBST (*split, gen_rtx_ZERO_EXTEND (split_mode,
SUBREG_REG (*split)));
}
#endif
newi2pat = gen_rtx_SET (VOIDmode, newdest, *split);
SUBST (*split, newdest);
i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
if (GET_CODE (newi2pat) == PARALLEL)
for (i = XVECLEN (newi2pat, 0) - 1; i >= 0; i--)
if (GET_CODE (XVECEXP (newi2pat, 0, i)) == CLOBBER)
{
rtx reg = XEXP (XVECEXP (newi2pat, 0, i), 0);
if (reg_overlap_mentioned_p (reg, newpat))
{
undo_all ();
return 0;
}
}
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_MODE (SET_DEST (XVECEXP (newpat, 0, 0)))
== GET_MODE (SET_SRC (XVECEXP (newpat, 0, 0))))
&& GET_CODE (XVECEXP (newpat, 0, 1)) == SET
&& rtx_equal_p (SET_SRC (XVECEXP (newpat, 0, 1)),
XEXP (SET_SRC (XVECEXP (newpat, 0, 0)), 0))
&& ! 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)),
(REG_P (temp)
&& reg_stat[REGNO (temp)].nonzero_bits != 0
&& GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD
&& GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT
&& (reg_stat[REGNO (temp)].nonzero_bits
!= GET_MODE_MASK (word_mode))))
&& ! (GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) == SUBREG
&& (temp = SUBREG_REG (SET_DEST (XVECEXP (newpat, 0, 1))),
(REG_P (temp)
&& reg_stat[REGNO (temp)].nonzero_bits != 0
&& GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD
&& GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT
&& (reg_stat[REGNO (temp)].nonzero_bits
!= 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 (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)
swap_i2i3 = 1;
}
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))
&& ! (contains_muldiv (SET_SRC (XVECEXP (newpat, 0, 0)))
&& contains_muldiv (SET_SRC (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 (REG_P (XEXP (note, 0)))
REG_N_DEATHS (REGNO (XEXP (note, 0)))--;
remove_note (undobuf.other_insn, note);
}
}
for (note = new_other_notes; note; note = XEXP (note, 1))
if (REG_P (XEXP (note, 0)))
REG_N_DEATHS (REGNO (XEXP (note, 0)))++;
distribute_notes (new_other_notes, undobuf.other_insn,
undobuf.other_insn, NULL_RTX);
}
#ifdef HAVE_cc0
{
rtx p = prev_nonnote_insn (i3);
if (p && p != i2 && NONJUMP_INSN_P (p) && newi2pat
&& sets_cc0_p (newi2pat))
{
undo_all ();
return 0;
}
}
#endif
if (!combine_validate_cost (i1, i2, i3, newpat, newi2pat))
{
undo_all ();
return 0;
}
if (swap_i2i3)
{
rtx insn;
rtx link;
rtx ni2dest;
PATTERN (i3) = newpat;
adjust_for_new_dest (i3);
if (GET_CODE (newi2pat) == PARALLEL)
ni2dest = SET_DEST (XVECEXP (newi2pat, 0, 0));
else
ni2dest = SET_DEST (newi2pat);
for (insn = NEXT_INSN (i3);
insn && (this_basic_block->next_bb == EXIT_BLOCK_PTR
|| insn != BB_HEAD (this_basic_block->next_bb));
insn = NEXT_INSN (insn))
{
if (INSN_P (insn) && reg_referenced_p (ni2dest, PATTERN (insn)))
{
for (link = LOG_LINKS (insn); link;
link = XEXP (link, 1))
if (XEXP (link, 0) == i3)
XEXP (link, 0) = i1;
break;
}
}
}
{
rtx i3notes, i2notes, i1notes = 0;
rtx i3links, i2links, i1links = 0;
rtx midnotes = 0;
unsigned int regno;
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 (CALL_P (i3) && CALL_INSN_FUNCTION_USAGE (i3))
{
rtx call_usage = CALL_INSN_FUNCTION_USAGE (i3);
reset_used_flags (call_usage);
call_usage = copy_rtx (call_usage);
if (substed_i2)
replace_rtx (call_usage, i2dest, i2src);
if (substed_i1)
replace_rtx (call_usage, i1dest, i1src);
CALL_INSN_FUNCTION_USAGE (i3) = call_usage;
}
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 (XVECEXP (PATTERN (i2), 0, i)) != USE
&& REG_P (SET_DEST (XVECEXP (PATTERN (i2), 0, i)))
&& 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->next_bb == EXIT_BLOCK_PTR
|| BB_HEAD (this_basic_block) != temp);
temp = NEXT_INSN (temp))
if (temp != i3 && INSN_P (temp))
for (link = LOG_LINKS (temp); link; link = XEXP (link, 1))
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
SET_INSN_DELETED (i2);
if (i1)
{
LOG_LINKS (i1) = 0;
REG_NOTES (i1) = 0;
SET_INSN_DELETED (i1);
}
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);
if (i2notes)
distribute_notes (i2notes, i2, i3, newi2pat ? i2 : NULL_RTX);
if (i1notes)
distribute_notes (i1notes, i1, i3, newi2pat ? i2 : NULL_RTX);
if (midnotes)
distribute_notes (midnotes, NULL_RTX, i3, newi2pat ? i2 : NULL_RTX);
if (newi2pat && new_i2_notes)
{
for (temp = new_i2_notes; temp; temp = XEXP (temp, 1))
if (REG_P (XEXP (temp, 0)))
REG_N_DEATHS (REGNO (XEXP (temp, 0)))++;
distribute_notes (new_i2_notes, i2, i2, NULL_RTX);
}
if (new_i3_notes)
{
for (temp = new_i3_notes; temp; temp = XEXP (temp, 1))
if (REG_P (XEXP (temp, 0)))
REG_N_DEATHS (REGNO (XEXP (temp, 0)))++;
distribute_notes (new_i3_notes, i3, i3, NULL_RTX);
}
if (i3dest_killed)
{
if (REG_P (i3dest_killed))
REG_N_DEATHS (REGNO (i3dest_killed))++;
if (newi2pat && reg_set_p (i3dest_killed, newi2pat))
distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i3dest_killed,
NULL_RTX),
NULL_RTX, i2, NULL_RTX);
else
distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i3dest_killed,
NULL_RTX),
NULL_RTX, i3, newi2pat ? i2 : NULL_RTX);
}
if (i2dest_in_i2src)
{
if (REG_P (i2dest))
REG_N_DEATHS (REGNO (i2dest))++;
if (newi2pat && reg_set_p (i2dest, newi2pat))
distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i2dest, NULL_RTX),
NULL_RTX, i2, NULL_RTX);
else
distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i2dest, NULL_RTX),
NULL_RTX, i3, newi2pat ? i2 : NULL_RTX);
}
if (i1dest_in_i1src)
{
if (REG_P (i1dest))
REG_N_DEATHS (REGNO (i1dest))++;
if (newi2pat && reg_set_p (i1dest, newi2pat))
distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i1dest, NULL_RTX),
NULL_RTX, i2, NULL_RTX);
else
distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i1dest, NULL_RTX),
NULL_RTX, i3, newi2pat ? i2 : NULL_RTX);
}
distribute_links (i3links);
distribute_links (i2links);
distribute_links (i1links);
if (REG_P (i2dest))
{
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 (i1 && REG_P (i1dest))
{
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 (newi2pat)
note_stores (newi2pat, set_nonzero_bits_and_sign_copies, NULL);
note_stores (newpat, set_nonzero_bits_and_sign_copies, NULL);
if (returnjump_p (i3) || any_uncondjump_p (i3))
{
*new_direct_jump_p = 1;
mark_jump_label (PATTERN (i3), i3, 0);
if ((temp = next_nonnote_insn (i3)) == NULL_RTX
|| !BARRIER_P (temp))
emit_barrier_after (i3);
}
if (undobuf.other_insn != NULL_RTX
&& (returnjump_p (undobuf.other_insn)
|| any_uncondjump_p (undobuf.other_insn)))
{
*new_direct_jump_p = 1;
if ((temp = next_nonnote_insn (undobuf.other_insn)) == NULL_RTX
|| !BARRIER_P (temp))
emit_barrier_after (undobuf.other_insn);
}
if (GET_CODE (newpat) == SET
&& SET_SRC (newpat) == pc_rtx
&& SET_DEST (newpat) == pc_rtx)
*new_direct_jump_p = 1;
}
combine_successes++;
undo_commit ();
if (added_links_insn
&& (newi2pat == 0 || INSN_CUID (added_links_insn) < INSN_CUID (i2))
&& INSN_CUID (added_links_insn) < INSN_CUID (i3))
return added_links_insn;
else
return newi2pat ? i2 : i3;
}
static void
undo_all (void)
{
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;
}
undobuf.undos = 0;
}
static void
undo_commit (void)
{
struct undo *undo, *next;
for (undo = undobuf.undos; undo; undo = next)
{
next = undo->next;
undo->next = undobuf.frees;
undobuf.frees = undo;
}
undobuf.undos = 0;
}
static rtx *
find_split_point (rtx *loc, rtx insn)
{
rtx x = *loc;
enum rtx_code code = GET_CODE (x);
rtx *split;
unsigned HOST_WIDE_INT len = 0;
HOST_WIDE_INT pos = 0;
int unsignedp = 0;
rtx inner = NULL_RTX;
switch (code)
{
case SUBREG:
#ifdef INSN_SCHEDULING
if (MEM_P (SUBREG_REG (x)))
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_LO_SUM (Pmode,
gen_rtx_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
&& NEXT_INSN (seq) != NULL_RTX
&& NEXT_INSN (NEXT_INSN (seq)) == NULL_RTX
&& NONJUMP_INSN_P (seq)
&& GET_CODE (PATTERN (seq)) == SET
&& SET_DEST (PATTERN (seq)) == reg
&& ! reg_mentioned_p (reg,
SET_SRC (PATTERN (seq)))
&& NONJUMP_INSN_P (NEXT_INSN (seq))
&& GET_CODE (PATTERN (NEXT_INSN (seq))) == SET
&& SET_DEST (PATTERN (NEXT_INSN (seq))) == reg
&& memory_address_p (GET_MODE (x),
SET_SRC (PATTERN (NEXT_INSN (seq)))))
{
rtx src1 = SET_SRC (PATTERN (seq));
rtx src2 = SET_SRC (PATTERN (NEXT_INSN (seq)));
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 (!OBJECT_P (XEXP (XEXP (x, 0), 0))
&& ! (GET_CODE (XEXP (XEXP (x, 0), 0)) == SUBREG
&& OBJECT_P (SUBREG_REG (XEXP (XEXP (x, 0), 0)))))
return &XEXP (XEXP (x, 0), 0);
}
break;
case SET:
#ifdef HAVE_cc0
if (SET_DEST (x) == cc0_rtx
&& GET_CODE (SET_SRC (x)) != COMPARE
&& GET_CODE (SET_SRC (x)) != ZERO_EXTRACT
&& !OBJECT_P (SET_SRC (x))
&& ! (GET_CODE (SET_SRC (x)) == SUBREG
&& OBJECT_P (SUBREG_REG (SET_SRC (x)))))
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)))
{
HOST_WIDE_INT pos = INTVAL (XEXP (SET_DEST (x), 2));
unsigned HOST_WIDE_INT len = INTVAL (XEXP (SET_DEST (x), 1));
unsigned HOST_WIDE_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;
rtx or_mask;
if (BITS_BIG_ENDIAN)
pos = GET_MODE_BITSIZE (mode) - len - pos;
or_mask = gen_int_mode (src << pos, mode);
if (src == mask)
SUBST (SET_SRC (x),
simplify_gen_binary (IOR, mode, dest, or_mask));
else
{
rtx negmask = gen_int_mode (~(mask << pos), mode);
SUBST (SET_SRC (x),
simplify_gen_binary (IOR, mode,
simplify_gen_binary (AND, mode,
dest, negmask),
or_mask));
}
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
&& REG_P (XEXP (SET_SRC (x), 0))
&& (pos = exact_log2 (INTVAL (XEXP (SET_SRC (x), 1)))) >= 7
&& REG_P (SET_DEST (x))
&& (split = find_single_use (SET_DEST (x), insn, (rtx*) 0)) != 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_NEG (mode,
gen_rtx_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_AND (mode,
gen_rtx_LSHIFTRT
(mode, gen_lowpart (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_fmt_ee
(unsignedp ? LSHIFTRT : ASHIFTRT, mode,
gen_rtx_ASHIFT (mode,
gen_lowpart (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 (BINARY_P (SET_SRC (x))
&& CONSTANT_P (XEXP (SET_SRC (x), 1))
&& (OBJECT_P (XEXP (SET_SRC (x), 0))
|| (GET_CODE (XEXP (SET_SRC (x), 0)) == SUBREG
&& OBJECT_P (SUBREG_REG (XEXP (SET_SRC (x), 0))))))
return &XEXP (SET_SRC (x), 1);
if ((BINARY_P (SET_SRC (x)) || UNARY_P (SET_SRC (x)))
&& ! register_operand (XEXP (SET_SRC (x), 0), VOIDmode))
return &XEXP (SET_SRC (x), 0);
return 0;
case AND:
case IOR:
if (GET_CODE (XEXP (x, 0)) == NOT && GET_CODE (XEXP (x, 1)) == NOT)
{
SUBST (*loc,
gen_rtx_NOT (GET_MODE (x),
gen_rtx_fmt_ee (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 RTX_BITFIELD_OPS:
case RTX_TERNARY:
split = find_split_point (&XEXP (x, 2), insn);
if (split)
return split;
case RTX_BIN_ARITH:
case RTX_COMM_ARITH:
case RTX_COMPARE:
case RTX_COMM_COMPARE:
split = find_split_point (&XEXP (x, 1), insn);
if (split)
return split;
case RTX_UNARY:
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;
default:
return 0;
}
}
static rtx
subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
{
enum rtx_code code = GET_CODE (x);
enum machine_mode op0_mode = VOIDmode;
const char *fmt;
int len, i;
rtx new;
#define COMBINE_RTX_EQUAL_P(X,Y) \
((X) == (Y) \
|| (REG_P (X) && REG_P (Y) \
&& 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 && REG_P (from)
&& REGNO (x) == REGNO (from))
return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
if (code != MEM && code != LO_SUM && OBJECT_P (x))
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 (!REG_P (dest)
&& 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
&& (REG_P (SET_DEST (x))
|| 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')
{
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')
{
new = XEXP (x, i);
if (in_dest
&& i == 0
&& (((code == SUBREG || code == ZERO_EXTRACT)
&& REG_P (new))
|| code == STRICT_LOW_PART))
;
else 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);
#ifdef CANNOT_CHANGE_MODE_CLASS
if (code == SUBREG
&& REG_P (to)
&& REGNO (to) < FIRST_PSEUDO_REGISTER
&& REG_CANNOT_CHANGE_MODE_P (REGNO (to),
GET_MODE (to),
GET_MODE (x)))
return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
#endif
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;
if (GET_CODE (x) == SUBREG
&& (GET_CODE (new) == CONST_INT
|| GET_CODE (new) == CONST_DOUBLE))
{
enum machine_mode mode = GET_MODE (x);
x = simplify_subreg (GET_MODE (x), new,
GET_MODE (SUBREG_REG (x)),
SUBREG_BYTE (x));
if (! x)
x = gen_rtx_CLOBBER (mode, const0_rtx);
}
else if (GET_CODE (new) == CONST_INT
&& GET_CODE (x) == ZERO_EXTEND)
{
x = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
new, GET_MODE (XEXP (x, 0)));
gcc_assert (x);
}
else
SUBST (XEXP (x, i), new);
}
}
}
for (i = 0; i < 4; i++)
{
if (code != CONST_INT && code != REG && code != CLOBBER)
x = combine_simplify_rtx (x, op0_mode, in_dest);
if (GET_CODE (x) == code)
break;
code = GET_CODE (x);
op0_mode = VOIDmode;
}
return x;
}
static rtx
combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
{
enum rtx_code code = GET_CODE (x);
enum machine_mode mode = GET_MODE (x);
rtx temp;
rtx reversed;
int i;
if (COMMUTATIVE_ARITH_P (x)
&& swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
{
temp = XEXP (x, 0);
SUBST (XEXP (x, 0), XEXP (x, 1));
SUBST (XEXP (x, 1), temp);
}
if ((BINARY_P (x)
&& ((!OBJECT_P (XEXP (x, 0))
&& ! (GET_CODE (XEXP (x, 0)) == SUBREG
&& OBJECT_P (SUBREG_REG (XEXP (x, 0)))))
|| (!OBJECT_P (XEXP (x, 1))
&& ! (GET_CODE (XEXP (x, 1)) == SUBREG
&& OBJECT_P (SUBREG_REG (XEXP (x, 1)))))))
|| (UNARY_P (x)
&& (!OBJECT_P (XEXP (x, 0))
&& ! (GET_CODE (XEXP (x, 0)) == SUBREG
&& OBJECT_P (SUBREG_REG (XEXP (x, 0)))))))
{
rtx cond, true_rtx, false_rtx;
cond = if_then_else_cond (x, &true_rtx, &false_rtx);
if (cond != 0
&& ! (COMPARISON_P (x)
&& (COMPARISON_P (true_rtx) || COMPARISON_P (false_rtx))))
{
rtx cop1 = const0_rtx;
enum rtx_code cond_code = simplify_comparison (NE, &cond, &cop1);
if (cond_code == NE && COMPARISON_P (cond))
return x;
true_rtx = subst (copy_rtx (true_rtx), pc_rtx, pc_rtx, 0, 0);
false_rtx = subst (copy_rtx (false_rtx), pc_rtx, pc_rtx, 0, 0);
if (general_operand (true_rtx, VOIDmode)
&& general_operand (false_rtx, VOIDmode))
{
enum rtx_code reversed;
if (true_rtx == const_true_rtx && false_rtx == const0_rtx)
x = simplify_gen_relational (cond_code, mode, VOIDmode,
cond, cop1);
else if (true_rtx == const0_rtx && false_rtx == const_true_rtx
&& ((reversed = reversed_comparison_code_parts
(cond_code, cond, cop1, NULL))
!= UNKNOWN))
x = simplify_gen_relational (reversed, mode, VOIDmode,
cond, cop1);
else if (GET_CODE (true_rtx) == CONST_INT
&& INTVAL (true_rtx) == - STORE_FLAG_VALUE
&& false_rtx == const0_rtx)
x = simplify_gen_unary (NEG, mode,
simplify_gen_relational (cond_code,
mode, VOIDmode,
cond, cop1),
mode);
else if (GET_CODE (false_rtx) == CONST_INT
&& INTVAL (false_rtx) == - STORE_FLAG_VALUE
&& true_rtx == const0_rtx
&& ((reversed = reversed_comparison_code_parts
(cond_code, cond, cop1, NULL))
!= UNKNOWN))
x = simplify_gen_unary (NEG, mode,
simplify_gen_relational (reversed,
mode, VOIDmode,
cond, cop1),
mode);
else
return gen_rtx_IF_THEN_ELSE (mode,
simplify_gen_relational (cond_code,
mode,
VOIDmode,
cond,
cop1),
true_rtx, false_rtx);
code = GET_CODE (x);
op0_mode = VOIDmode;
}
}
}
temp = 0;
switch (GET_RTX_CLASS (code))
{
case RTX_UNARY:
if (op0_mode == VOIDmode)
op0_mode = GET_MODE (XEXP (x, 0));
temp = simplify_unary_operation (code, mode, XEXP (x, 0), op0_mode);
break;
case RTX_COMPARE:
case RTX_COMM_COMPARE:
{
enum machine_mode cmp_mode = GET_MODE (XEXP (x, 0));
if (cmp_mode == VOIDmode)
{
cmp_mode = GET_MODE (XEXP (x, 1));
if (cmp_mode == VOIDmode)
cmp_mode = op0_mode;
}
temp = simplify_relational_operation (code, mode, cmp_mode,
XEXP (x, 0), XEXP (x, 1));
}
break;
case RTX_COMM_ARITH:
case RTX_BIN_ARITH:
temp = simplify_binary_operation (code, mode, XEXP (x, 0), XEXP (x, 1));
break;
case RTX_BITFIELD_OPS:
case RTX_TERNARY:
temp = simplify_ternary_operation (code, mode, op0_mode, XEXP (x, 0),
XEXP (x, 1), XEXP (x, 2));
break;
default:
break;
}
if (temp)
{
x = temp;
code = GET_CODE (temp);
op0_mode = VOIDmode;
mode = GET_MODE (temp);
}
if (code == PLUS || code == MINUS
|| code == AND || code == IOR || code == XOR)
{
x = apply_distributive_law (x);
code = GET_CODE (x);
op0_mode = VOIDmode;
}
if ((code == PLUS || code == MINUS || code == MULT || code == DIV
|| code == AND || code == IOR || code == XOR
|| code == SMAX || code == SMIN || code == UMAX || code == UMIN)
&& ((INTEGRAL_MODE_P (mode) && code != DIV)
|| (flag_unsafe_math_optimizations && FLOAT_MODE_P (mode))))
{
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) && COMMUTATIVE_ARITH_P (x))
{
rtx tem = inner_op0;
inner_op0 = inner_op1;
inner_op1 = tem;
}
inner = simplify_binary_operation (code == MINUS ? PLUS
: code == DIV ? MULT
: code,
mode, inner_op0, inner_op1);
if (inner == 0 && COMMUTATIVE_ARITH_P (x))
{
other = XEXP (XEXP (x, 0), 1);
inner = simplify_binary_operation (code, mode,
XEXP (XEXP (x, 0), 0),
XEXP (x, 1));
}
if (inner)
return simplify_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 (op0_mode == VOIDmode)
op0_mode = GET_MODE (SUBREG_REG (x));
if (CONSTANT_P (SUBREG_REG (x))
&& subreg_lowpart_offset (mode, op0_mode) == SUBREG_BYTE (x)
&& (GET_MODE (SUBREG_REG (x)) != VOIDmode
|| gen_lowpart_common (mode, SUBREG_REG (x))))
return gen_lowpart (mode, SUBREG_REG (x));
if (GET_MODE_CLASS (GET_MODE (SUBREG_REG (x))) == MODE_CC)
break;
{
rtx temp;
temp = simplify_subreg (mode, SUBREG_REG (x), op0_mode,
SUBREG_BYTE (x));
if (temp)
return temp;
}
if (MEM_P (SUBREG_REG (x))
&& (MEM_VOLATILE_P (SUBREG_REG (x))
|| mode_dependent_address_p (XEXP (SUBREG_REG (x), 0))))
return gen_rtx_CLOBBER (mode, const0_rtx);
break;
case NOT:
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,
simplify_gen_unary (NOT, inner_mode, const1_rtx,
inner_mode),
XEXP (SUBREG_REG (XEXP (x, 0)), 1));
return gen_lowpart (mode, x);
}
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);
enum machine_mode op_mode;
op_mode = GET_MODE (in1);
in1 = simplify_gen_unary (NOT, op_mode, in1, op_mode);
op_mode = GET_MODE (in2);
if (op_mode == VOIDmode)
op_mode = mode;
in2 = simplify_gen_unary (NOT, op_mode, in2, op_mode);
if (GET_CODE (in2) == NOT && GET_CODE (in1) != NOT)
{
rtx tem = in2;
in2 = in1; in1 = tem;
}
return gen_rtx_fmt_ee (GET_CODE (XEXP (x, 0)) == IOR ? AND : IOR,
mode, in1, in2);
}
break;
case NEG:
if (GET_CODE (XEXP (x, 0)) == XOR
&& XEXP (XEXP (x, 0), 1) == const1_rtx
&& nonzero_bits (XEXP (XEXP (x, 0), 0), mode) == 1)
return simplify_gen_binary (PLUS, mode, XEXP (XEXP (x, 0), 0),
constm1_rtx);
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 (!REG_P (temp)
&& ! (GET_CODE (temp) == SUBREG
&& REG_P (SUBREG_REG (temp)))
&& (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 simplify_gen_unary (GET_CODE (XEXP (x, 0)), mode,
XEXP (XEXP (XEXP (x, 0), 0), 0), mode);
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)))
>= (unsigned int) (GET_MODE_BITSIZE (mode) + 1)
&& ! (GET_CODE (XEXP (x, 0)) == LSHIFTRT
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT))
return gen_lowpart (mode, XEXP (x, 0));
if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& COMPARISON_P (XEXP (x, 0))
&& ((HOST_WIDE_INT) STORE_FLAG_VALUE & ~GET_MODE_MASK (mode)) == 0)
return gen_lowpart (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)))
&& COMPARISON_P (temp))
return gen_lowpart (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)) == FLOAT_TRUNCATE
&& flag_unsafe_math_optimizations)
|| GET_CODE (XEXP (x, 0)) == FLOAT_EXTEND)
return simplify_gen_unary (GET_MODE_SIZE (GET_MODE (XEXP (XEXP (x, 0),
0)))
> GET_MODE_SIZE (mode)
? FLOAT_TRUNCATE : FLOAT_EXTEND,
mode,
XEXP (XEXP (x, 0), 0), mode);
if (GET_CODE (XEXP (x, 0)) == FLOAT
&& (flag_unsafe_math_optimizations
|| ((unsigned)significand_size (GET_MODE (XEXP (x, 0)))
>= (GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (x, 0), 0)))
- num_sign_bit_copies (XEXP (XEXP (x, 0), 0),
GET_MODE (XEXP (XEXP (x, 0), 0)))))))
return simplify_gen_unary (FLOAT, mode,
XEXP (XEXP (x, 0), 0),
GET_MODE (XEXP (XEXP (x, 0), 0)));
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 simplify_gen_unary (GET_CODE (XEXP (x, 0)), mode,
XEXP (XEXP (XEXP (x, 0), 0), 0), mode);
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;
case FLOAT_EXTEND:
if (GET_CODE (XEXP (x, 0)) == FLOAT_EXTEND
|| (GET_CODE (XEXP (x, 0)) == FLOAT
&& ((unsigned)significand_size (GET_MODE (XEXP (x, 0)))
>= (GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (x, 0), 0)))
- num_sign_bit_copies (XEXP (XEXP (x, 0), 0),
GET_MODE (XEXP (XEXP (x, 0), 0)))))))
return simplify_gen_unary (GET_CODE (XEXP (x, 0)), mode,
XEXP (XEXP (x, 0), 0),
GET_MODE (XEXP (XEXP (x, 0), 0)));
break;
#ifdef HAVE_cc0
case COMPARE:
if (XEXP (x, 1) == const0_rtx)
return XEXP (x, 0);
if (!(HONOR_SIGNED_ZEROS (GET_MODE (XEXP (x, 0)))
&& HONOR_SIGN_DEPENDENT_ROUNDING (GET_MODE (XEXP (x, 0))))
&& XEXP (x, 1) == CONST0_RTX (GET_MODE (XEXP (x, 0))))
return XEXP (x, 0);
break;
#endif
case CONST:
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)) == MULT
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == NEG)
{
rtx in1, in2;
in1 = XEXP (XEXP (XEXP (x, 0), 0), 0);
in2 = XEXP (XEXP (x, 0), 1);
return simplify_gen_binary (MINUS, mode, XEXP (x, 1),
simplify_gen_binary (MULT, mode,
in1, in2));
}
if (GET_CODE (XEXP (x, 0)) == PLUS
&& CONSTANT_ADDRESS_P (XEXP (XEXP (x, 0), 1)))
return simplify_gen_binary (PLUS, mode,
simplify_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
|| (i = exact_log2 (INTVAL (XEXP (x, 1)))) >= 0)
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& ((GET_CODE (XEXP (XEXP (x, 0), 0)) == AND
&& GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == CONST_INT
&& (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)))
== (unsigned int) 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 (COMPARISON_P (XEXP (x, 0))
&& ((STORE_FLAG_VALUE == -1 && XEXP (x, 1) == const1_rtx)
|| (STORE_FLAG_VALUE == 1 && XEXP (x, 1) == constm1_rtx))
&& (reversed = reversed_comparison (XEXP (x, 0), mode,
XEXP (XEXP (x, 0), 0),
XEXP (XEXP (x, 0), 1))))
return
simplify_gen_unary (NEG, mode, reversed, mode);
if (XEXP (x, 1) == constm1_rtx
&& !REG_P (XEXP (x, 0))
&& ! (GET_CODE (XEXP (x, 0)) == SUBREG
&& REG_P (SUBREG_REG (XEXP (x, 0))))
&& nonzero_bits (XEXP (x, 0), mode) == 1)
return simplify_shift_const (NULL_RTX, ASHIFTRT, mode,
simplify_shift_const (NULL_RTX, ASHIFT, mode,
gen_rtx_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)
{
rtx tor = simplify_gen_binary (IOR, mode, XEXP (x, 0), XEXP (x, 1));
temp = combine_simplify_rtx (tor, mode, in_dest);
if (GET_CODE (temp) != CLOBBER && temp != tor)
return temp;
}
break;
case MINUS:
if (STORE_FLAG_VALUE == 1
&& XEXP (x, 0) == const1_rtx
&& COMPARISON_P (XEXP (x, 1))
&& (reversed = reversed_comparison (XEXP (x, 1), mode,
XEXP (XEXP (x, 1), 0),
XEXP (XEXP (x, 1), 1))))
return reversed;
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)) == MULT
&& GET_CODE (XEXP (XEXP (x, 1), 0)) == NEG)
{
rtx in1, in2;
in1 = XEXP (XEXP (XEXP (x, 1), 0), 0);
in2 = XEXP (XEXP (x, 1), 1);
return simplify_gen_binary (PLUS, mode,
simplify_gen_binary (MULT, mode,
in1, in2),
XEXP (x, 0));
}
if (GET_CODE (XEXP (x, 1)) == MULT
&& GET_CODE (XEXP (x, 0)) == NEG)
{
rtx in1, in2;
in1 = simplify_gen_unary (NEG, mode, XEXP (XEXP (x, 1), 0), mode);
in2 = XEXP (XEXP (x, 1), 1);
return simplify_gen_binary (MINUS, mode,
simplify_gen_binary (MULT, mode,
in1, in2),
XEXP (XEXP (x, 0), 0));
}
if (GET_CODE (XEXP (x, 1)) == PLUS && INTEGRAL_MODE_P (mode))
return simplify_gen_binary (MINUS, mode,
simplify_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)
{
rtx result = distribute_and_simplify_rtx (x, 0);
if (result)
return result;
}
if (FLOAT_MODE_P (mode) && flag_unsafe_math_optimizations
&& GET_CODE (XEXP (x, 0)) == DIV)
{
rtx tem = simplify_binary_operation (MULT, mode,
XEXP (XEXP (x, 0), 0),
XEXP (x, 1));
if (tem)
return simplify_gen_binary (DIV, mode, tem, XEXP (XEXP (x, 0), 1));
}
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:
case UNEQ: case LTGT:
case UNGT: case UNGE:
case UNLT: case UNLE:
case UNORDERED: case ORDERED:
if (GET_CODE (XEXP (x, 0)) == COMPARE
|| (GET_MODE_CLASS (GET_MODE (XEXP (x, 0))) != MODE_CC
&& ! CC0_P (XEXP (x, 0))))
{
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
&& mode == GET_MODE (op0)
&& nonzero_bits (op0, mode) == 1)
return gen_lowpart (mode,
expand_compound_operation (op0));
else if (STORE_FLAG_VALUE == 1
&& new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& mode == GET_MODE (op0)
&& (num_sign_bit_copies (op0, mode)
== GET_MODE_BITSIZE (mode)))
{
op0 = expand_compound_operation (op0);
return simplify_gen_unary (NEG, mode,
gen_lowpart (mode, op0),
mode);
}
else if (STORE_FLAG_VALUE == 1
&& new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& mode == GET_MODE (op0)
&& nonzero_bits (op0, mode) == 1)
{
op0 = expand_compound_operation (op0);
return simplify_gen_binary (XOR, mode,
gen_lowpart (mode, op0),
const1_rtx);
}
else if (STORE_FLAG_VALUE == 1
&& new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& mode == GET_MODE (op0)
&& (num_sign_bit_copies (op0, mode)
== GET_MODE_BITSIZE (mode)))
{
op0 = expand_compound_operation (op0);
return plus_constant (gen_lowpart (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 (mode,
expand_compound_operation (op0));
else if (STORE_FLAG_VALUE == -1
&& new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& mode == GET_MODE (op0)
&& nonzero_bits (op0, mode) == 1)
{
op0 = expand_compound_operation (op0);
return simplify_gen_unary (NEG, mode,
gen_lowpart (mode, op0),
mode);
}
else if (STORE_FLAG_VALUE == -1
&& new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& mode == GET_MODE (op0)
&& (num_sign_bit_copies (op0, mode)
== GET_MODE_BITSIZE (mode)))
{
op0 = expand_compound_operation (op0);
return simplify_gen_unary (NOT, mode,
gen_lowpart (mode, op0),
mode);
}
else if (STORE_FLAG_VALUE == -1
&& new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& mode == GET_MODE (op0)
&& nonzero_bits (op0, mode) == 1)
{
op0 = expand_compound_operation (op0);
return plus_constant (gen_lowpart (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_fmt_ee (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);
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_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 POPCOUNT:
case PARITY:
if (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)));
else if (SHIFT_COUNT_TRUNCATED && !REG_P (XEXP (x, 1)))
SUBST (XEXP (x, 1),
force_to_mode (XEXP (x, 1), GET_MODE (XEXP (x, 1)),
((HOST_WIDE_INT) 1
<< exact_log2 (GET_MODE_BITSIZE (GET_MODE (x))))
- 1,
NULL_RTX, 0));
break;
case VEC_SELECT:
{
rtx op0 = XEXP (x, 0);
rtx op1 = XEXP (x, 1);
int len;
gcc_assert (GET_CODE (op1) == PARALLEL);
len = XVECLEN (op1, 0);
if (len == 1
&& GET_CODE (XVECEXP (op1, 0, 0)) == CONST_INT
&& GET_CODE (op0) == VEC_CONCAT)
{
int offset = INTVAL (XVECEXP (op1, 0, 0)) * GET_MODE_SIZE (GET_MODE (x));
for (;;)
{
if (GET_MODE (op0) == GET_MODE (x))
return op0;
if (GET_CODE (op0) == VEC_CONCAT)
{
HOST_WIDE_INT op0_size = GET_MODE_SIZE (GET_MODE (XEXP (op0, 0)));
if (offset < op0_size)
op0 = XEXP (op0, 0);
else
{
offset -= op0_size;
op0 = XEXP (op0, 1);
}
}
else
break;
}
}
}
break;
default:
break;
}
return x;
}
static rtx
simplify_if_then_else (rtx x)
{
enum machine_mode mode = GET_MODE (x);
rtx cond = XEXP (x, 0);
rtx true_rtx = XEXP (x, 1);
rtx false_rtx = XEXP (x, 2);
enum rtx_code true_code = GET_CODE (cond);
int comparison_p = COMPARISON_P (cond);
rtx temp;
int i;
enum rtx_code false_code;
rtx reversed;
if (comparison_p && true_rtx == const_true_rtx && false_rtx == const0_rtx)
return simplify_gen_relational (true_code, mode, VOIDmode,
XEXP (cond, 0), XEXP (cond, 1));
if (comparison_p
&& true_rtx == const0_rtx && false_rtx == const_true_rtx
&& (reversed = reversed_comparison (cond, mode, XEXP (cond, 0),
XEXP (cond, 1))))
return reversed;
if (comparison_p
&& ((false_code = combine_reversed_comparison_code (cond))
!= UNKNOWN)
&& REG_P (XEXP (cond, 0)))
{
HOST_WIDE_INT nzb;
rtx from = XEXP (cond, 0);
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_rtx, true_rtx = false_rtx, false_rtx = 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_rtx))
true_rtx = subst (known_cond (copy_rtx (true_rtx), true_code,
from, true_val),
pc_rtx, pc_rtx, 0, 0);
if (reg_mentioned_p (from, false_rtx))
false_rtx = subst (known_cond (copy_rtx (false_rtx), false_code,
from, false_val),
pc_rtx, pc_rtx, 0, 0);
SUBST (XEXP (x, 1), swapped ? false_rtx : true_rtx);
SUBST (XEXP (x, 2), swapped ? true_rtx : false_rtx);
true_rtx = XEXP (x, 1);
false_rtx = XEXP (x, 2);
true_code = GET_CODE (cond);
}
if (comparison_p
&& combine_reversed_comparison_code (cond) != UNKNOWN
&& (true_rtx == pc_rtx
|| (CONSTANT_P (true_rtx)
&& GET_CODE (false_rtx) != CONST_INT && false_rtx != pc_rtx)
|| true_rtx == const0_rtx
|| (OBJECT_P (true_rtx) && !OBJECT_P (false_rtx))
|| (GET_CODE (true_rtx) == SUBREG && OBJECT_P (SUBREG_REG (true_rtx))
&& !OBJECT_P (false_rtx))
|| reg_mentioned_p (true_rtx, false_rtx)
|| rtx_equal_p (false_rtx, XEXP (cond, 0))))
{
true_code = reversed_comparison_code (cond, NULL);
SUBST (XEXP (x, 0),
reversed_comparison (cond, GET_MODE (cond), XEXP (cond, 0),
XEXP (cond, 1)));
SUBST (XEXP (x, 1), false_rtx);
SUBST (XEXP (x, 2), true_rtx);
temp = true_rtx, true_rtx = false_rtx, false_rtx = temp;
cond = XEXP (x, 0);
true_code = GET_CODE (cond);
comparison_p = COMPARISON_P (cond);
}
if (rtx_equal_p (true_rtx, false_rtx) && ! side_effects_p (cond))
return true_rtx;
if (true_code == EQ && ! side_effects_p (cond)
&& !HONOR_NANS (mode)
&& rtx_equal_p (XEXP (cond, 0), false_rtx)
&& rtx_equal_p (XEXP (cond, 1), true_rtx))
return false_rtx;
else if (true_code == NE && ! side_effects_p (cond)
&& !HONOR_NANS (mode)
&& rtx_equal_p (XEXP (cond, 0), true_rtx)
&& rtx_equal_p (XEXP (cond, 1), false_rtx))
return true_rtx;
if (GET_MODE_CLASS (mode) == MODE_INT
&& GET_CODE (false_rtx) == NEG
&& rtx_equal_p (true_rtx, XEXP (false_rtx, 0))
&& comparison_p
&& rtx_equal_p (true_rtx, XEXP (cond, 0))
&& ! side_effects_p (true_rtx))
switch (true_code)
{
case GT:
case GE:
return simplify_gen_unary (ABS, mode, true_rtx, mode);
case LT:
case LE:
return
simplify_gen_unary (NEG, mode,
simplify_gen_unary (ABS, mode, true_rtx, mode),
mode);
default:
break;
}
if ((! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations)
&& comparison_p
&& rtx_equal_p (XEXP (cond, 0), true_rtx)
&& rtx_equal_p (XEXP (cond, 1), false_rtx)
&& ! side_effects_p (cond))
switch (true_code)
{
case GE:
case GT:
return simplify_gen_binary (SMAX, mode, true_rtx, false_rtx);
case LE:
case LT:
return simplify_gen_binary (SMIN, mode, true_rtx, false_rtx);
case GEU:
case GTU:
return simplify_gen_binary (UMAX, mode, true_rtx, false_rtx);
case LEU:
case LTU:
return simplify_gen_binary (UMIN, mode, true_rtx, false_rtx);
default:
break;
}
if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
&& comparison_p
&& GET_MODE_CLASS (mode) == MODE_INT
&& ! side_effects_p (x))
{
rtx t = make_compound_operation (true_rtx, SET);
rtx f = make_compound_operation (false_rtx, SET);
rtx cond_op0 = XEXP (cond, 0);
rtx cond_op1 = XEXP (cond, 1);
enum rtx_code op = UNKNOWN, extend_op = UNKNOWN;
enum machine_mode m = mode;
rtx z = 0, c1 = NULL_RTX;
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))
> (unsigned int)
(GET_MODE_BITSIZE (mode)
- GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (t, 0), 0))))))
{
c1 = XEXP (XEXP (t, 0), 1); z = f; op = GET_CODE (XEXP (t, 0));
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))
> (unsigned int)
(GET_MODE_BITSIZE (mode)
- GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (t, 0), 1))))))
{
c1 = XEXP (XEXP (t, 0), 0); z = f; op = GET_CODE (XEXP (t, 0));
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 (simplify_gen_relational (true_code, m, VOIDmode,
cond_op0, cond_op1),
pc_rtx, pc_rtx, 0, 0);
temp = simplify_gen_binary (MULT, m, temp,
simplify_gen_binary (MULT, m, c1,
const_true_rtx));
temp = subst (temp, pc_rtx, pc_rtx, 0, 0);
temp = simplify_gen_binary (op, m, gen_lowpart (m, z), temp);
if (extend_op != UNKNOWN)
temp = simplify_gen_unary (extend_op, mode, temp, m);
return temp;
}
}
if (true_code == NE && XEXP (cond, 1) == const0_rtx
&& false_rtx == const0_rtx && GET_CODE (true_rtx) == CONST_INT
&& ((1 == nonzero_bits (XEXP (cond, 0), mode)
&& (i = exact_log2 (INTVAL (true_rtx))) >= 0)
|| ((num_sign_bit_copies (XEXP (cond, 0), mode)
== GET_MODE_BITSIZE (mode))
&& (i = exact_log2 (-INTVAL (true_rtx))) >= 0)))
return
simplify_shift_const (NULL_RTX, ASHIFT, mode,
gen_lowpart (mode, XEXP (cond, 0)), i);
if (true_code == NE && XEXP (cond, 1) == const0_rtx
&& false_rtx == const0_rtx && GET_CODE (true_rtx) == CONST_INT
&& GET_MODE (XEXP (cond, 0)) == mode
&& (INTVAL (true_rtx) & GET_MODE_MASK (mode))
== nonzero_bits (XEXP (cond, 0), mode)
&& (i = exact_log2 (INTVAL (true_rtx) & GET_MODE_MASK (mode))) >= 0)
return XEXP (cond, 0);
return x;
}
static rtx
simplify_set (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
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
{
src = force_to_mode (src, mode, ~(HOST_WIDE_INT) 0, NULL_RTX, 0);
SUBST (SET_SRC (x), src);
}
if ((GET_MODE_CLASS (mode) == MODE_CC
|| GET_CODE (src) == COMPARE
|| CC0_P (dest))
&& (cc_use = find_single_use (dest, subst_insn, &other_insn)) != 0
&& (undobuf.other_insn == 0 || other_insn == undobuf.other_insn)
&& COMPARISON_P (*cc_use)
&& rtx_equal_p (XEXP (*cc_use, 0), dest))
{
enum rtx_code old_code = GET_CODE (*cc_use);
enum rtx_code new_code;
rtx op0, op1, tmp;
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 (GET_MODE (src));
tmp = simplify_relational_operation (old_code, compare_mode, VOIDmode,
op0, op1);
if (!tmp)
new_code = old_code;
else if (!CONSTANT_P (tmp))
{
new_code = GET_CODE (tmp);
op0 = XEXP (tmp, 0);
op1 = XEXP (tmp, 1);
}
else
{
rtx pat = PATTERN (other_insn);
undobuf.other_insn = other_insn;
SUBST (*cc_use, tmp);
if (GET_CODE (pat) == SET)
{
rtx new = simplify_rtx (SET_SRC (pat));
if (new != NULL_RTX)
SUBST (SET_SRC (pat), new);
}
SUBST (SET_DEST (x), pc_rtx);
SUBST (SET_SRC (x), pc_rtx);
return x;
}
new_code = simplify_comparison (new_code, &op0, &op1);
#ifdef SELECT_CC_MODE
if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC)
compare_mode = GET_MODE (op0);
else
compare_mode = SELECT_CC_MODE (new_code, op0, op1);
#ifndef HAVE_cc0
if (compare_mode != GET_MODE (dest))
{
unsigned 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
#endif
if (new_code != old_code)
{
int other_changed_previously = other_changed;
unsigned HOST_WIDE_INT mask;
SUBST (*cc_use, gen_rtx_fmt_ee (new_code, GET_MODE (*cc_use),
dest, const0_rtx));
other_changed = 1;
if (((old_code == NE && new_code == EQ)
|| (old_code == EQ && new_code == NE))
&& ! other_changed_previously && op1 == const0_rtx
&& GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT
&& exact_log2 (mask = nonzero_bits (op0, GET_MODE (op0))) >= 0)
{
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_changed = 0;
op0 = simplify_gen_binary (XOR, GET_MODE (op0),
op0, GEN_INT (mask));
}
}
}
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_COMPARE (compare_mode, op0, op1));
src = SET_SRC (x);
}
else if (GET_MODE (op0) == compare_mode && op1 == const0_rtx)
{
SUBST(SET_SRC (x), op0);
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)
&& !OBJECT_P (SUBREG_REG (src))
&& (((GET_MODE_SIZE (GET_MODE (src)) + (UNITS_PER_WORD - 1))
/ UNITS_PER_WORD)
== ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))
+ (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))
#ifndef WORD_REGISTER_OPERATIONS
&& (GET_MODE_SIZE (GET_MODE (src))
< GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))))
#endif
#ifdef CANNOT_CHANGE_MODE_CLASS
&& ! (REG_P (dest) && REGNO (dest) < FIRST_PSEUDO_REGISTER
&& REG_CANNOT_CHANGE_MODE_P (REGNO (dest),
GET_MODE (SUBREG_REG (src)),
GET_MODE (src)))
#endif
&& (REG_P (dest)
|| (GET_CODE (dest) == SUBREG
&& REG_P (SUBREG_REG (dest)))))
{
SUBST (SET_DEST (x),
gen_lowpart (GET_MODE (SUBREG_REG (src)),
dest));
SUBST (SET_SRC (x), SUBREG_REG (src));
src = SET_SRC (x), dest = SET_DEST (x);
}
#ifdef HAVE_cc0
if (dest == cc0_rtx
&& GET_CODE (src) == SUBREG
&& subreg_lowpart_p (src)
&& (GET_MODE_BITSIZE (GET_MODE (src))
< GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (src)))))
{
rtx inner = SUBREG_REG (src);
enum machine_mode inner_mode = GET_MODE (inner);
if (GET_MODE_BITSIZE (inner_mode) <= HOST_BITS_PER_WIDE_INT
&& (nonzero_bits (inner, inner_mode)
< ((unsigned HOST_WIDE_INT) 1
<< (GET_MODE_BITSIZE (GET_MODE (src)) - 1))))
{
SUBST (SET_SRC (x), inner);
src = SET_SRC (x);
}
}
#endif
#ifdef LOAD_EXTEND_OP
if (GET_CODE (src) == SUBREG && subreg_lowpart_p (src)
&& LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))) != UNKNOWN
&& SUBREG_BYTE (src) == 0
&& (GET_MODE_SIZE (GET_MODE (src))
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))))
&& MEM_P (SUBREG_REG (src)))
{
SUBST (SET_SRC (x),
gen_rtx_fmt_e (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))),
GET_MODE (src), SUBREG_REG (src)));
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_rtx = (GET_CODE (XEXP (src, 0)) == NE
? XEXP (src, 1) : XEXP (src, 2));
rtx false_rtx = (GET_CODE (XEXP (src, 0)) == NE
? XEXP (src, 2) : XEXP (src, 1));
rtx term1 = const0_rtx, term2, term3;
if (GET_CODE (true_rtx) == IOR
&& rtx_equal_p (XEXP (true_rtx, 0), false_rtx))
term1 = false_rtx, true_rtx = XEXP (true_rtx, 1), false_rtx = const0_rtx;
else if (GET_CODE (true_rtx) == IOR
&& rtx_equal_p (XEXP (true_rtx, 1), false_rtx))
term1 = false_rtx, true_rtx = XEXP (true_rtx, 0), false_rtx = const0_rtx;
else if (GET_CODE (false_rtx) == IOR
&& rtx_equal_p (XEXP (false_rtx, 0), true_rtx))
term1 = true_rtx, false_rtx = XEXP (false_rtx, 1), true_rtx = const0_rtx;
else if (GET_CODE (false_rtx) == IOR
&& rtx_equal_p (XEXP (false_rtx, 1), true_rtx))
term1 = true_rtx, false_rtx = XEXP (false_rtx, 0), true_rtx = const0_rtx;
term2 = simplify_gen_binary (AND, GET_MODE (src),
XEXP (XEXP (src, 0), 0), true_rtx);
term3 = simplify_gen_binary (AND, GET_MODE (src),
simplify_gen_unary (NOT, GET_MODE (src),
XEXP (XEXP (src, 0), 0),
GET_MODE (src)),
false_rtx);
SUBST (SET_SRC (x),
simplify_gen_binary (IOR, GET_MODE (src),
simplify_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 (rtx x)
{
enum machine_mode mode = GET_MODE (x);
rtx op0 = XEXP (x, 0);
rtx op1 = XEXP (x, 1);
rtx reversed;
switch (GET_CODE (x))
{
case AND:
if (GET_CODE (op0) == XOR
&& rtx_equal_p (XEXP (op0, 0), op1)
&& ! side_effects_p (op1))
x = simplify_gen_binary (AND, mode,
simplify_gen_unary (NOT, mode,
XEXP (op0, 1), mode),
op1);
if (GET_CODE (op0) == XOR
&& rtx_equal_p (XEXP (op0, 1), op1)
&& ! side_effects_p (op1))
x = simplify_gen_binary (AND, mode,
simplify_gen_unary (NOT, mode,
XEXP (op0, 0), mode),
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 = simplify_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 = simplify_gen_binary (AND, mode, XEXP (XEXP (op0, 0), 0), op1);
if (GET_CODE (op1) == CONST_INT
&& (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
|| INTVAL (op1) > 0))
{
x = simplify_and_const_int (x, mode, op0, INTVAL (op1));
if (GET_CODE (x) == IOR && GET_CODE (op0) == AND
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
&& GET_CODE (op1) == CONST_INT
&& (INTVAL (XEXP (op0, 1)) & INTVAL (op1)) != 0)
return simplify_gen_binary (IOR, mode,
simplify_gen_binary
(AND, mode, XEXP (op0, 0),
GEN_INT (INTVAL (XEXP (op0, 1))
& ~INTVAL (op1))), op1);
if (GET_CODE (x) != AND)
return x;
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)
{
rtx result = distribute_and_simplify_rtx (x, 0);
if (result)
return result;
}
if (GET_CODE (op1) == IOR || GET_CODE (op1) == XOR)
{
rtx result = distribute_and_simplify_rtx (x, 1);
if (result)
return result;
}
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)
{
rtx result = distribute_and_simplify_rtx (x, 0);
if (result)
return result;
}
if (GET_CODE (op1) == AND)
{
rtx result = distribute_and_simplify_rtx (x, 1);
if (result)
return result;
}
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:
if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& (nonzero_bits (op0, mode)
& nonzero_bits (op1, mode)) == 0)
return (simplify_gen_binary (IOR, mode, op0, op1));
{
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
simplify_gen_unary (NOT, mode,
simplify_gen_binary (XOR, mode, op0, op1),
mode);
}
if (GET_CODE (op0) == AND
&& rtx_equal_p (XEXP (op0, 1), op1)
&& ! side_effects_p (op1))
return simplify_gen_binary (AND, mode,
simplify_gen_unary (NOT, mode,
XEXP (op0, 0), mode),
op1);
else if (GET_CODE (op0) == AND
&& rtx_equal_p (XEXP (op0, 0), op1)
&& ! side_effects_p (op1))
return simplify_gen_binary (AND, mode,
simplify_gen_unary (NOT, mode,
XEXP (op0, 1), mode),
op1);
if (STORE_FLAG_VALUE == 1
&& op1 == const1_rtx
&& COMPARISON_P (op0)
&& (reversed = reversed_comparison (op0, mode, XEXP (op0, 0),
XEXP (op0, 1))))
return reversed;
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_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
&& COMPARISON_P (op0)
&& (reversed = reversed_comparison (op0, mode, XEXP (op0, 0),
XEXP (op0, 1))))
return reversed;
break;
default:
gcc_unreachable ();
}
return x;
}
static rtx
expand_compound_operation (rtx x)
{
unsigned HOST_WIDE_INT pos = 0, len;
int unsignedp = 0;
unsigned 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;
if (! SCALAR_INT_MODE_P (GET_MODE (XEXP (x, 0))))
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;
if (! SCALAR_INT_MODE_P (GET_MODE (XEXP (x, 0))))
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) == SIGN_EXTEND
&& (GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
&& ((nonzero_bits (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
& ~(((unsigned HOST_WIDE_INT)
GET_MODE_MASK (GET_MODE (XEXP (x, 0))))
>> 1))
== 0)))
{
rtx temp = gen_rtx_ZERO_EXTEND (GET_MODE (x), XEXP (x, 0));
rtx temp2 = expand_compound_operation (temp);
if (rtx_cost (x, SET) > rtx_cost (temp2, SET))
return temp2;
else if (rtx_cost (x, SET) > rtx_cost (temp, SET))
return temp;
else
return x;
}
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)
&& COMPARISON_P (XEXP (XEXP (x, 0), 0))
&& (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
<= HOST_BITS_PER_WIDE_INT)
&& ((HOST_WIDE_INT) STORE_FLAG_VALUE
& ~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))
&& COMPARISON_P (SUBREG_REG (XEXP (x, 0)))
&& (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
<= HOST_BITS_PER_WIDE_INT)
&& ((HOST_WIDE_INT) STORE_FLAG_VALUE
& ~GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
return SUBREG_REG (XEXP (x, 0));
}
modewidth = GET_MODE_BITSIZE (GET_MODE (x));
if (modewidth + len >= pos)
tem = simplify_shift_const (NULL_RTX, unsignedp ? LSHIFTRT : ASHIFTRT,
GET_MODE (x),
simplify_shift_const (NULL_RTX, ASHIFT,
GET_MODE (x),
XEXP (x, 0),
modewidth - pos - len),
modewidth - len);
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 (rtx x)
{
rtx inner;
rtx pos;
int len;
rtx mask, cleared, masked;
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 (subreg_lsb (XEXP (SET_DEST (x), 0)));
}
else if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT
&& GET_CODE (XEXP (SET_DEST (x), 1)) == CONST_INT)
{
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 = simplify_gen_binary (MINUS, GET_MODE (pos),
GEN_INT (GET_MODE_BITSIZE (
GET_MODE (inner))
- len),
pos);
}
}
else if (GET_CODE (SET_DEST (x)) == SUBREG
&& nonzero_sign_valid
&& (((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
(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 (! SCALAR_INT_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 (imode, inner);
}
if (len >= HOST_BITS_PER_WIDE_INT)
break;
mask = GEN_INT (((HOST_WIDE_INT) 1 << len) - 1);
cleared = simplify_gen_binary (AND, compute_mode,
simplify_gen_unary (NOT, compute_mode,
simplify_gen_binary (ASHIFT,
compute_mode,
mask, pos),
compute_mode),
inner);
masked = simplify_gen_binary (ASHIFT, compute_mode,
simplify_gen_binary (
AND, compute_mode,
gen_lowpart (compute_mode, SET_SRC (x)),
mask),
pos);
x = gen_rtx_SET (VOIDmode, copy_rtx (inner),
simplify_gen_binary (IOR, compute_mode,
cleared, masked));
}
return x;
}
static rtx
make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
rtx pos_rtx, unsigned HOST_WIDE_INT len, int unsignedp,
int in_dest, int in_compare)
{
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;
HOST_WIDE_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 (MEM_P (SUBREG_REG (inner)))
is_mode = GET_MODE (SUBREG_REG (inner));
inner = SUBREG_REG (inner);
}
else if (GET_CODE (inner) == ASHIFT
&& GET_CODE (XEXP (inner, 1)) == CONST_INT
&& pos_rtx == 0 && pos == 0
&& len > (unsigned HOST_WIDE_INT) INTVAL (XEXP (inner, 1)))
{
new = make_extraction (mode, XEXP (inner, 0),
0, 0, len - INTVAL (XEXP (inner, 1)),
unsignedp, in_dest, in_compare);
if (new != 0)
return gen_rtx_ASHIFT (mode, new, XEXP (inner, 1));
}
inner_mode = GET_MODE (inner);
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
&& !MEM_P (inner)
&& (! in_dest
|| (REG_P (inner)
&& have_insn_for (STRICT_LOW_PART, tmode))))
|| (MEM_P (inner) && 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 (MEM_P (inner))
{
HOST_WIDE_INT offset;
if (BYTES_BIG_ENDIAN)
offset = (GET_MODE_BITSIZE (is_mode) - len - pos) / BITS_PER_UNIT;
else
offset = pos / BITS_PER_UNIT;
new = adjust_address_nv (inner, tmode, offset);
}
else if (REG_P (inner))
{
if (tmode != inner_mode)
{
if (pos || in_dest)
{
HOST_WIDE_INT final_word = pos / BITS_PER_WORD;
if (WORDS_BIG_ENDIAN
&& GET_MODE_SIZE (inner_mode) > UNITS_PER_WORD)
final_word = ((GET_MODE_SIZE (inner_mode)
- GET_MODE_SIZE (tmode))
/ UNITS_PER_WORD) - final_word;
final_word *= UNITS_PER_WORD;
if (BYTES_BIG_ENDIAN &&
GET_MODE_SIZE (inner_mode) > GET_MODE_SIZE (tmode))
final_word += (GET_MODE_SIZE (inner_mode)
- GET_MODE_SIZE (tmode)) % UNITS_PER_WORD;
if (!validate_subreg (tmode, inner_mode, inner, final_word))
return NULL_RTX;
new = gen_rtx_SUBREG (tmode, inner, final_word);
}
else
new = gen_lowpart (tmode, inner);
}
else
new = inner;
}
else
new = force_to_mode (inner, tmode,
len >= HOST_BITS_PER_WIDE_INT
? ~(unsigned HOST_WIDE_INT) 0
: ((unsigned HOST_WIDE_INT) 1 << len) - 1,
NULL_RTX, 0);
if (in_dest)
return (MEM_P (new) ? new
: (GET_CODE (new) != SUBREG
? gen_rtx_CLOBBER (tmode, const0_rtx)
: gen_rtx_STRICT_LOW_PART (VOIDmode, new)));
if (mode == tmode)
return new;
if (GET_CODE (new) == CONST_INT)
return gen_int_mode (INTVAL (new), mode);
if (flag_expensive_optimizations
&& (GET_MODE_BITSIZE (tmode) <= HOST_BITS_PER_WIDE_INT
&& ((nonzero_bits (new, tmode)
& ~(((unsigned HOST_WIDE_INT)
GET_MODE_MASK (tmode))
>> 1))
== 0)))
{
rtx temp = gen_rtx_ZERO_EXTEND (mode, new);
rtx temp1 = gen_rtx_SIGN_EXTEND (mode, new);
if (rtx_cost (temp, SET) <= rtx_cost (temp1, SET))
return temp;
return temp1;
}
return (gen_rtx_fmt_e (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 && MEM_P (inner)
&& ((pos_rtx == 0 && pos + len > GET_MODE_BITSIZE (is_mode))
|| (pos_rtx != 0 && len != 1)))
return 0;
if (in_dest && mode_for_extraction (EP_insv, -1) != MAX_MACHINE_MODE)
{
wanted_inner_reg_mode = mode_for_extraction (EP_insv, 0);
pos_mode = mode_for_extraction (EP_insv, 2);
extraction_mode = mode_for_extraction (EP_insv, 3);
}
if (! in_dest && unsignedp
&& mode_for_extraction (EP_extzv, -1) != MAX_MACHINE_MODE)
{
wanted_inner_reg_mode = mode_for_extraction (EP_extzv, 1);
pos_mode = mode_for_extraction (EP_extzv, 3);
extraction_mode = mode_for_extraction (EP_extzv, 0);
}
if (! in_dest && ! unsignedp
&& mode_for_extraction (EP_extv, -1) != MAX_MACHINE_MODE)
{
wanted_inner_reg_mode = mode_for_extraction (EP_extv, 1);
pos_mode = mode_for_extraction (EP_extv, 3);
extraction_mode = mode_for_extraction (EP_extv, 0);
}
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 (!MEM_P (inner))
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 = (MEM_P (inner)
? GET_MODE_BITSIZE (is_mode)
: GET_MODE_BITSIZE (wanted_inner_mode));
if (pos_rtx == 0)
pos = width - len - pos;
else
pos_rtx
= gen_rtx_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)
&& ((MEM_P (inner)
&& (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)
{
enum machine_mode bfmode = smallest_mode_for_size (len, MODE_INT);
offset += pos / GET_MODE_BITSIZE (bfmode);
pos %= GET_MODE_BITSIZE (bfmode);
}
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)
inner = adjust_address_nv (inner, wanted_inner_mode, offset);
}
else if (!MEM_P (inner))
{
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
? ~(unsigned HOST_WIDE_INT) 0
: ((((unsigned 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)))
{
rtx temp = gen_rtx_ZERO_EXTEND (pos_mode, pos_rtx);
if (flag_expensive_optimizations
&& (GET_MODE_BITSIZE (GET_MODE (pos_rtx)) <= HOST_BITS_PER_WIDE_INT
&& ((nonzero_bits (pos_rtx, GET_MODE (pos_rtx))
& ~(((unsigned HOST_WIDE_INT)
GET_MODE_MASK (GET_MODE (pos_rtx)))
>> 1))
== 0)))
{
rtx temp1 = gen_rtx_SIGN_EXTEND (pos_mode, pos_rtx);
if (rtx_cost (temp1, SET) < rtx_cost (temp, SET))
temp = temp1;
}
pos_rtx = temp;
}
else if (pos_rtx != 0
&& GET_MODE_SIZE (pos_mode) < GET_MODE_SIZE (GET_MODE (pos_rtx)))
pos_rtx = gen_lowpart (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_fmt_eee (unsignedp ? ZERO_EXTRACT : SIGN_EXTRACT,
extraction_mode, inner, GEN_INT (len), pos_rtx);
if (! in_dest)
new = gen_lowpart (mode, new);
return new;
}
static rtx
extract_left_shift (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 simplify_gen_unary (code, mode, tem, mode);
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 simplify_gen_binary (code, mode, tem,
GEN_INT (INTVAL (XEXP (x, 1)) >> count));
break;
default:
break;
}
return 0;
}
static rtx
make_compound_operation (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;
const char *fmt;
next_code = (code == MEM || code == PLUS || code == MINUS ? MEM
: ((code == COMPARE || COMPARISON_P (x))
&& 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_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_fmt_ee (GET_CODE (XEXP (x, 0)), mode,
gen_rtx_AND (mode, XEXP (XEXP (x, 0), 0),
XEXP (x, 1)),
gen_rtx_AND (mode, XEXP (XEXP (x, 0), 1),
XEXP (x, 1)));
new = make_compound_operation (new, in_code);
}
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 (GET_CODE (XEXP (x, 0)) == LSHIFTRT
&& !have_insn_for (LSHIFTRT, mode)
&& have_insn_for (ASHIFTRT, mode)
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
&& 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_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 (have_insn_for (ASHIFTRT, mode)
&& ! have_insn_for (LSHIFTRT, mode)
&& mode_width <= HOST_BITS_PER_WIDE_INT
&& (nonzero_bits (XEXP (x, 0), mode) & (1 << (mode_width - 1))) == 0)
{
new = gen_rtx_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);
break;
}
if (!OBJECT_P (lhs)
&& ! (GET_CODE (lhs) == SUBREG
&& (OBJECT_P (SUBREG_REG (lhs))))
&& GET_CODE (rhs) == CONST_INT
&& INTVAL (rhs) < HOST_BITS_PER_WIDE_INT
&& (new = extract_left_shift (lhs, INTVAL (rhs))) != 0)
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, ~(HOST_WIDE_INT) 0,
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)))))
{
if (! SCALAR_INT_MODE_P (mode))
break;
tem = gen_rtx_fmt_e (GET_CODE (tem), mode, XEXP (tem, 0));
}
else
tem = gen_lowpart (mode, XEXP (tem, 0));
return tem;
}
break;
default:
break;
}
if (new)
{
x = gen_lowpart (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 (unsigned HOST_WIDE_INT m, unsigned HOST_WIDE_INT *plen)
{
int pos = exact_log2 (m & -m);
int len = 0;
if (pos >= 0)
len = exact_log2 ((m >> pos) + 1);
if (len <= 0)
pos = -1;
*plen = len;
return pos;
}
static rtx
force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
rtx reg, int just_select)
{
enum rtx_code code = GET_CODE (x);
int next_select = just_select || code == XOR || code == NOT || code == NEG;
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))
&& have_insn_for (code, mode))
? 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 (mask & ((unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)))
fuller_mask = ~(unsigned HOST_WIDE_INT) 0;
else
fuller_mask = (((unsigned HOST_WIDE_INT) 1 << (floor_log2 (mask) + 1))
- 1);
nonzero = nonzero_bits (x, mode);
if (! just_select && (nonzero & mask) == 0)
x = const0_rtx;
if (GET_CODE (x) == CONST_INT)
{
if (SCALAR_INT_MODE_P (mode))
return gen_int_mode (INTVAL (x) & mask, mode);
else
{
x = GEN_INT (INTVAL (x) & mask);
return gen_lowpart_common (mode, x);
}
}
if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode)
&& (GET_MODE_MASK (GET_MODE (x)) & ~mask) == 0)
return gen_lowpart (mode, 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
&& ((INTVAL (XEXP (x, 1)) & GET_MODE_MASK (GET_MODE (x)))
== 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 = simplify_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:
{
unsigned 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
&& (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 MULT:
mask = fuller_mask;
goto binop;
case MINUS:
if (GET_CODE (XEXP (x, 0)) == CONST_INT
&& (((unsigned HOST_WIDE_INT) (INTVAL (XEXP (x, 0))
& -INTVAL (XEXP (x, 0))))
> mask))
{
x = simplify_gen_unary (NEG, GET_MODE (x), XEXP (x, 1),
GET_MODE (x));
return force_to_mode (x, mode, mask, reg, next_select);
}
if (GET_CODE (XEXP (x, 0)) == CONST_INT
&& ((INTVAL (XEXP (x, 0)) | (HOST_WIDE_INT) fuller_mask)
== INTVAL (XEXP (x, 0))))
{
x = simplify_gen_unary (NOT, GET_MODE (x),
XEXP (x, 1), GET_MODE (x));
return force_to_mode (x, mode, mask, reg, next_select);
}
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 = simplify_gen_binary (GET_CODE (x), GET_MODE (x),
XEXP (XEXP (x, 0), 0), temp);
x = simplify_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 (op_mode,
force_to_mode (XEXP (x, 0), mode, mask,
reg, next_select));
op1 = gen_lowpart (op_mode,
force_to_mode (XEXP (x, 1), mode, mask,
reg, next_select));
if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
x = simplify_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 (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 = simplify_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);
unsigned HOST_WIDE_INT inner_mask;
inner_mask = mask << INTVAL (XEXP (x, 1));
if ((inner_mask & ~GET_MODE_MASK (GET_MODE (x))) != 0)
op_mode = GET_MODE (x);
inner = force_to_mode (inner, op_mode, inner_mask, reg, next_select);
if (GET_MODE (x) != op_mode || inner != XEXP (x, 0))
x = simplify_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
&& ((INTVAL (XEXP (x, 1)) + exact_log2 (mask + 1))
<= GET_MODE_BITSIZE (GET_MODE (x)))
&& ((int) num_sign_bit_copies (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
>= exact_log2 (mask + 1)))
x = simplify_gen_binary (LSHIFTRT, GET_MODE (x), XEXP (x, 0),
GEN_INT (GET_MODE_BITSIZE (GET_MODE (x))
- exact_log2 (mask + 1)));
goto shiftrt;
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 = simplify_gen_binary (LSHIFTRT, GET_MODE (x),
XEXP (x, 0), XEXP (x, 1));
shiftrt:
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
&& XEXP (XEXP (x, 0), 1) == 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_mode (mask << INTVAL (XEXP (XEXP (x, 0), 1)),
GET_MODE (x));
temp = simplify_gen_binary (XOR, GET_MODE (x),
XEXP (XEXP (x, 0), 0), temp);
x = simplify_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 (op_mode,
force_to_mode (XEXP (x, 0), mode, mask,
reg, next_select));
if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0))
x = simplify_gen_unary (code, op_mode, op0, op_mode);
break;
case NE:
if ((mask & ~STORE_FLAG_VALUE) == 0 && XEXP (x, 1) == const0_rtx
&& GET_MODE (XEXP (x, 0)) == mode
&& exact_log2 (nonzero_bits (XEXP (x, 0), mode)) >= 0
&& (nonzero_bits (XEXP (x, 0), mode)
== (unsigned HOST_WIDE_INT) STORE_FLAG_VALUE))
return force_to_mode (XEXP (x, 0), mode, mask, reg, next_select);
break;
case IF_THEN_ELSE:
SUBST (XEXP (x, 1),
gen_lowpart (GET_MODE (x),
force_to_mode (XEXP (x, 1), mode,
mask, reg, next_select)));
SUBST (XEXP (x, 2),
gen_lowpart (GET_MODE (x),
force_to_mode (XEXP (x, 2), mode,
mask, reg, next_select)));
break;
default:
break;
}
return gen_lowpart (mode, x);
}
static rtx
if_then_else_cond (rtx x, rtx *ptrue, rtx *pfalse)
{
enum machine_mode mode = GET_MODE (x);
enum rtx_code code = GET_CODE (x);
rtx cond0, cond1, true0, true1, false0, false1;
unsigned HOST_WIDE_INT nz;
if ((code == NE || code == EQ)
&& XEXP (x, 1) == const0_rtx)
{
*ptrue = (code == NE) ? const_true_rtx : const0_rtx;
*pfalse = (code == NE) ? const0_rtx : const_true_rtx;
return XEXP (x, 0);
}
else if (UNARY_P (x)
&& (cond0 = if_then_else_cond (XEXP (x, 0), &true0, &false0)) != 0)
{
*ptrue = simplify_gen_unary (code, mode, true0, GET_MODE (XEXP (x, 0)));
*pfalse = simplify_gen_unary (code, mode, false0,
GET_MODE (XEXP (x, 0)));
return cond0;
}
else if (code == COMPARE)
;
else if (BINARY_P (x))
{
cond0 = if_then_else_cond (XEXP (x, 0), &true0, &false0);
cond1 = if_then_else_cond (XEXP (x, 1), &true1, &false1);
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);
if (COMPARISON_P (x))
{
*ptrue = simplify_gen_relational (code, mode, VOIDmode,
true0, true1);
*pfalse = simplify_gen_relational (code, mode, VOIDmode,
false0, false1);
}
else
{
*ptrue = simplify_gen_binary (code, mode, true0, true1);
*pfalse = simplify_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 (COMPARISON_P (cond0)
&& COMPARISON_P (cond1)
&& ((GET_CODE (cond0) == combine_reversed_comparison_code (cond1)
&& rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 0))
&& rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 1)))
|| ((swap_condition (GET_CODE (cond0))
== combine_reversed_comparison_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 = simplify_gen_binary (MULT, mode, op0, const_true_rtx);
*pfalse = simplify_gen_binary (MULT, mode,
(code == MINUS
? simplify_gen_unary (NEG, mode,
op1, mode)
: 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 (COMPARISON_P (cond0)
&& COMPARISON_P (cond1)
&& ((GET_CODE (cond0) == combine_reversed_comparison_code (cond1)
&& rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 0))
&& rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 1)))
|| ((swap_condition (GET_CODE (cond0))
== combine_reversed_comparison_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
&& 0 != (cond0 = if_then_else_cond (SUBREG_REG (x),
&true0, &false0)))
{
true0 = simplify_gen_subreg (mode, true0,
GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
false0 = simplify_gen_subreg (mode, false0,
GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
if (true0 && false0)
{
*ptrue = true0;
*pfalse = false0;
return cond0;
}
}
else if (CONSTANT_P (x)
|| ((cond0 = get_last_value (x)) != 0 && CONSTANT_P (cond0)))
;
else if (mode == BImode)
{
*ptrue = GEN_INT (STORE_FLAG_VALUE), *pfalse = const0_rtx;
return x;
}
else if (x == constm1_rtx || x == const0_rtx
|| (mode != VOIDmode
&& num_sign_bit_copies (x, mode) == GET_MODE_BITSIZE (mode)))
{
*ptrue = constm1_rtx, *pfalse = const0_rtx;
return x;
}
else if (SCALAR_INT_MODE_P (mode)
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& exact_log2 (nz = nonzero_bits (x, mode)) >= 0)
{
*ptrue = gen_int_mode (nz, mode), *pfalse = const0_rtx;
return x;
}
*ptrue = *pfalse = x;
return 0;
}
static rtx
known_cond (rtx x, enum rtx_code cond, rtx reg, rtx val)
{
enum rtx_code code = GET_CODE (x);
rtx temp;
const char *fmt;
int i, j;
if (side_effects_p (x))
return x;
if (cond == EQ
&& rtx_equal_p (x, reg)
&& ! FLOAT_MODE_P (GET_MODE (x))
&& ! FLOAT_MODE_P (GET_MODE (val)))
return val;
if (cond == UNEQ && 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 simplify_gen_unary (NEG, GET_MODE (XEXP (x, 0)),
XEXP (x, 0),
GET_MODE (XEXP (x, 0)));
default:
break;
}
else if (COMPARISON_P (x) || COMMUTATIVE_ARITH_P (x))
{
if (rtx_equal_p (XEXP (x, 0), val))
cond = swap_condition (cond), temp = val, val = reg, reg = temp;
if (rtx_equal_p (XEXP (x, 0), reg) && rtx_equal_p (XEXP (x, 1), val))
{
if (COMPARISON_P (x))
{
if (comparison_dominates_p (cond, code))
return const_true_rtx;
code = combine_reversed_comparison_code (x);
if (code != UNKNOWN
&& comparison_dominates_p (cond, code))
return const0_rtx;
else
return x;
}
else if (code == SMAX || code == SMIN
|| code == UMIN || code == UMAX)
{
int unsignedp = (code == UMIN || code == UMAX);
if ((code == SMAX || code == UMAX)
&& ! (cond == EQ || cond == NE))
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;
}
}
}
}
else if (code == SUBREG)
{
enum machine_mode inner_mode = GET_MODE (SUBREG_REG (x));
rtx new, r = known_cond (SUBREG_REG (x), cond, reg, val);
if (SUBREG_REG (x) != r)
{
new = simplify_subreg (GET_MODE (x), r,
inner_mode, SUBREG_BYTE (x));
if (new)
return new;
else
SUBST (SUBREG_REG (x), r);
}
return x;
}
else if (code == ZERO_EXTEND)
{
enum machine_mode inner_mode = GET_MODE (XEXP (x, 0));
rtx new, r = known_cond (XEXP (x, 0), cond, reg, val);
if (XEXP (x, 0) != r)
{
new = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
r, inner_mode);
if (new)
return new;
else
SUBST (XEXP (x, 0), r);
}
return x;
}
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 (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 (MEM_P (x) && GET_CODE (y) == SUBREG
&& MEM_P (SUBREG_REG (y))
&& rtx_equal_p (SUBREG_REG (y),
gen_lowpart (GET_MODE (SUBREG_REG (y)), x)))
return 1;
if (MEM_P (y) && GET_CODE (x) == SUBREG
&& MEM_P (SUBREG_REG (x))
&& rtx_equal_p (SUBREG_REG (x),
gen_lowpart (GET_MODE (SUBREG_REG (x)), y)))
return 1;
return 0;
}
static rtx
make_field_assignment (rtx x)
{
rtx dest = SET_DEST (x);
rtx src = SET_SRC (x);
rtx assign;
rtx rhs, lhs;
HOST_WIDE_INT c1;
HOST_WIDE_INT pos;
unsigned HOST_WIDE_INT 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;
}
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
&& GET_CODE (XEXP (SUBREG_REG (XEXP (src, 0)), 0)) == CONST_INT
&& INTVAL (XEXP (SUBREG_REG (XEXP (src, 0)), 0)) == -2
&& rtx_equal_for_field_assignment_p (dest, XEXP (src, 1)))
{
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;
}
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 (dest) == ZERO_EXTRACT
&& GET_CODE (XEXP (dest, 1)) == CONST_INT
&& GET_CODE (src) == AND
&& GET_CODE (XEXP (src, 1)) == CONST_INT)
{
HOST_WIDE_INT width = INTVAL (XEXP (dest, 1));
unsigned HOST_WIDE_INT and_mask = INTVAL (XEXP (src, 1));
unsigned HOST_WIDE_INT ze_mask;
if (width >= HOST_BITS_PER_WIDE_INT)
ze_mask = -1;
else
ze_mask = ((unsigned HOST_WIDE_INT)1 << width) - 1;
if ((and_mask & ze_mask) == ze_mask)
return gen_rtx_SET (VOIDmode, dest, XEXP (src, 0));
if ((and_mask & ze_mask) != and_mask)
{
mode = GET_MODE (src);
src = gen_rtx_AND (mode, XEXP (src, 0),
gen_int_mode (and_mask & ze_mask, mode));
return gen_rtx_SET (VOIDmode, dest, src);
}
}
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
? ~(unsigned HOST_WIDE_INT) 0
: ((unsigned HOST_WIDE_INT) 1 << len) - 1,
dest, 0);
if (GET_CODE (assign) == ZERO_EXTRACT
&& GET_CODE (XEXP (assign, 1)) == CONST_INT
&& INTVAL (XEXP (assign, 1)) < HOST_BITS_PER_WIDE_INT
&& GET_CODE (src) == AND
&& GET_CODE (XEXP (src, 1)) == CONST_INT
&& ((unsigned HOST_WIDE_INT) INTVAL (XEXP (src, 1))
== ((unsigned HOST_WIDE_INT) 1 << INTVAL (XEXP (assign, 1))) - 1))
src = XEXP (src, 0);
return gen_rtx_SET (VOIDmode, assign, src);
}
static rtx
apply_distributive_law (rtx x)
{
enum rtx_code code = GET_CODE (x);
enum rtx_code inner_code;
rtx lhs, rhs, other;
rtx tem;
if (FLOAT_MODE_P (GET_MODE (x))
&& ! flag_unsafe_math_optimizations)
return x;
if (code != IOR && code != AND && code != XOR
&& code != PLUS && code != MINUS)
return x;
lhs = XEXP (x, 0);
rhs = XEXP (x, 1);
if (OBJECT_P (lhs) || OBJECT_P (rhs))
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_BYTE (lhs) != SUBREG_BYTE (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 = simplify_gen_binary (code, GET_MODE (SUBREG_REG (lhs)),
SUBREG_REG (lhs), SUBREG_REG (rhs));
return gen_lowpart (GET_MODE (x), tem);
default:
return x;
}
if (COMMUTATIVE_ARITH_P (lhs)
&& rtx_equal_p (XEXP (lhs, 0), XEXP (rhs, 0)))
other = XEXP (lhs, 0), lhs = XEXP (lhs, 1), rhs = XEXP (rhs, 1);
else if (COMMUTATIVE_ARITH_P (lhs)
&& rtx_equal_p (XEXP (lhs, 0), XEXP (rhs, 1)))
other = XEXP (lhs, 0), lhs = XEXP (lhs, 1), rhs = XEXP (rhs, 0);
else if (COMMUTATIVE_ARITH_P (lhs)
&& rtx_equal_p (XEXP (lhs, 1), XEXP (rhs, 0)))
other = XEXP (lhs, 1), lhs = XEXP (lhs, 0), rhs = XEXP (rhs, 1);
else if (rtx_equal_p (XEXP (lhs, 1), XEXP (rhs, 1)))
other = XEXP (lhs, 1), lhs = XEXP (lhs, 0), rhs = XEXP (rhs, 0);
else
return x;
tem = simplify_gen_binary (code, GET_MODE (x), lhs, rhs);
if (code == XOR && inner_code == IOR)
{
inner_code = AND;
other = simplify_gen_unary (NOT, GET_MODE (x), other, GET_MODE (x));
}
return simplify_gen_binary (inner_code, GET_MODE (x),
apply_distributive_law (tem), other);
}
static rtx
distribute_and_simplify_rtx (rtx x, int n)
{
enum machine_mode mode;
enum rtx_code outer_code, inner_code;
rtx decomposed, distributed, inner_op0, inner_op1, new_op0, new_op1, tmp;
decomposed = XEXP (x, n);
if (!ARITHMETIC_P (decomposed))
return NULL_RTX;
mode = GET_MODE (x);
outer_code = GET_CODE (x);
distributed = XEXP (x, !n);
inner_code = GET_CODE (decomposed);
inner_op0 = XEXP (decomposed, 0);
inner_op1 = XEXP (decomposed, 1);
if (outer_code == AND && inner_code == XOR && GET_CODE (distributed) == NOT)
{
distributed = XEXP (distributed, 0);
outer_code = IOR;
}
if (n == 0)
{
new_op0 = simplify_gen_binary (outer_code, mode, inner_op0, distributed);
new_op1 = simplify_gen_binary (outer_code, mode, inner_op1, distributed);
}
else
{
new_op0 = simplify_gen_binary (outer_code, mode, distributed, inner_op0);
new_op1 = simplify_gen_binary (outer_code, mode, distributed, inner_op1);
}
tmp = apply_distributive_law (simplify_gen_binary (inner_code, mode,
new_op0, new_op1));
if (GET_CODE (tmp) != outer_code
&& rtx_cost (tmp, SET) < rtx_cost (x, SET))
return tmp;
return NULL_RTX;
}
static rtx
simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
unsigned HOST_WIDE_INT constop)
{
unsigned HOST_WIDE_INT nonzero;
int i;
varop = force_to_mode (varop, mode, constop, NULL_RTX, 0);
if (GET_CODE (varop) == CLOBBER)
return varop;
if (GET_CODE (varop) == CONST_INT)
return GEN_INT (trunc_int_for_mode (INTVAL (varop) & constop, mode));
nonzero = nonzero_bits (varop, mode) & GET_MODE_MASK (mode);
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
(mode,
apply_distributive_law
(simplify_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 (GET_CODE (varop) == PLUS
&& exact_log2 (constop + 1) >= 0)
{
rtx o0, o1;
o0 = simplify_and_const_int (NULL_RTX, mode, XEXP (varop, 0), constop);
o1 = simplify_and_const_int (NULL_RTX, mode, XEXP (varop, 1), constop);
if (o0 == const0_rtx)
return o1;
if (o1 == const0_rtx)
return o0;
}
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 (mode, varop);
if (GET_CODE (varop) == CLOBBER)
return x ? x : varop;
if (constop == nonzero)
x = varop;
else
{
constop = trunc_int_for_mode (constop, mode);
if (x == 0 || GET_CODE (x) != AND || GET_MODE (x) != mode)
x = simplify_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;
}
static rtx
reg_nonzero_bits_for_combine (rtx x, enum machine_mode mode,
rtx known_x ATTRIBUTE_UNUSED,
enum machine_mode known_mode ATTRIBUTE_UNUSED,
unsigned HOST_WIDE_INT known_ret ATTRIBUTE_UNUSED,
unsigned HOST_WIDE_INT *nonzero)
{
rtx tem;
if (reg_stat[REGNO (x)].last_set_value != 0
&& (reg_stat[REGNO (x)].last_set_mode == mode
|| (GET_MODE_CLASS (reg_stat[REGNO (x)].last_set_mode) == MODE_INT
&& GET_MODE_CLASS (mode) == MODE_INT))
&& (reg_stat[REGNO (x)].last_set_label == label_tick
|| (REGNO (x) >= FIRST_PSEUDO_REGISTER
&& REG_N_SETS (REGNO (x)) == 1
&& ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start,
REGNO (x))))
&& INSN_CUID (reg_stat[REGNO (x)].last_set) < subst_low_cuid)
{
*nonzero &= reg_stat[REGNO (x)].last_set_nonzero_bits;
return NULL;
}
tem = get_last_value (x);
if (tem)
{
#ifdef SHORT_IMMEDIATES_SIGN_EXTEND
if (GET_MODE_BITSIZE (GET_MODE (x)) < GET_MODE_BITSIZE (mode)
&& 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 tem;
}
else if (nonzero_sign_valid && reg_stat[REGNO (x)].nonzero_bits)
{
unsigned HOST_WIDE_INT mask = reg_stat[REGNO (x)].nonzero_bits;
if (GET_MODE_BITSIZE (GET_MODE (x)) < GET_MODE_BITSIZE (mode))
mask |= GET_MODE_MASK (mode) ^ GET_MODE_MASK (GET_MODE (x));
*nonzero &= mask;
}
return NULL;
}
static rtx
reg_num_sign_bit_copies_for_combine (rtx x, enum machine_mode mode,
rtx known_x ATTRIBUTE_UNUSED,
enum machine_mode known_mode
ATTRIBUTE_UNUSED,
unsigned int known_ret ATTRIBUTE_UNUSED,
unsigned int *result)
{
rtx tem;
if (reg_stat[REGNO (x)].last_set_value != 0
&& reg_stat[REGNO (x)].last_set_mode == mode
&& (reg_stat[REGNO (x)].last_set_label == label_tick
|| (REGNO (x) >= FIRST_PSEUDO_REGISTER
&& REG_N_SETS (REGNO (x)) == 1
&& ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start,
REGNO (x))))
&& INSN_CUID (reg_stat[REGNO (x)].last_set) < subst_low_cuid)
{
*result = reg_stat[REGNO (x)].last_set_sign_bit_copies;
return NULL;
}
tem = get_last_value (x);
if (tem != 0)
return tem;
if (nonzero_sign_valid && reg_stat[REGNO (x)].sign_bit_copies != 0
&& GET_MODE_BITSIZE (GET_MODE (x)) == GET_MODE_BITSIZE (mode))
*result = reg_stat[REGNO (x)].sign_bit_copies;
return NULL;
}
unsigned int
extended_count (rtx x, enum machine_mode mode, int unsignedp)
{
if (nonzero_sign_valid == 0)
return 0;
return (unsignedp
? (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
? (unsigned int) (GET_MODE_BITSIZE (mode) - 1
- floor_log2 (nonzero_bits (x, mode)))
: 0)
: num_sign_bit_copies (x, mode) - 1);
}
static int
merge_outer_ops (enum rtx_code *pop0, HOST_WIDE_INT *pconst0, enum rtx_code op1, HOST_WIDE_INT const1, enum machine_mode mode, int *pcomp_p)
{
enum rtx_code op0 = *pop0;
HOST_WIDE_INT const0 = *pconst0;
const0 &= GET_MODE_MASK (mode);
const1 &= GET_MODE_MASK (mode);
if (op0 == AND)
const1 &= const0;
if (op1 == UNKNOWN || op0 == SET)
return 1;
else if (op0 == UNKNOWN)
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 = UNKNOWN;
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, const0 = ~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 = UNKNOWN;
else if (const0 == 0 && op0 == AND)
op0 = SET;
else if ((unsigned HOST_WIDE_INT) const0 == GET_MODE_MASK (mode)
&& op0 == AND)
op0 = UNKNOWN;
const0 = trunc_int_for_mode (const0, mode);
*pop0 = op0;
*pconst0 = const0;
return 1;
}
static rtx
simplify_shift_const (rtx x, enum rtx_code code,
enum machine_mode result_mode, rtx varop,
int orig_count)
{
enum rtx_code orig_code = code;
unsigned int count;
int signed_count;
enum machine_mode mode = result_mode;
enum machine_mode shift_mode, tmode;
unsigned int mode_words
= (GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;
enum rtx_code outer_op = UNKNOWN;
HOST_WIDE_INT outer_const = 0;
rtx const_rtx;
int complement_p = 0;
rtx new;
if (SHIFT_COUNT_TRUNCATED)
orig_count &= GET_MODE_BITSIZE (mode) - 1;
if (orig_count < 0 || orig_count >= (int) GET_MODE_BITSIZE (mode))
{
if (x)
return x;
return gen_rtx_fmt_ee (code, mode, varop, GEN_INT (orig_count));
}
count = orig_count;
while (count != 0)
{
if (GET_CODE (varop) == CLOBBER)
return varop;
if (complement_p)
break;
if (code == ROTATERT)
{
unsigned int bitsize = GET_MODE_BITSIZE (result_mode);;
code = ROTATE;
if (VECTOR_MODE_P (result_mode))
count = bitsize / GET_MODE_NUNITS (result_mode) - count;
else
count = bitsize - count;
}
shift_mode
= (code == ASHIFTRT || code == LSHIFTRT || code == ROTATE
? result_mode : mode);
if (count > (unsigned int) (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;
}
}
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;
if (code == LSHIFTRT
&& GET_MODE_BITSIZE (shift_mode) <= HOST_BITS_PER_WIDE_INT
&& !(nonzero_bits (varop, shift_mode) >> count))
varop = const0_rtx;
if (code == ASHIFT
&& GET_MODE_BITSIZE (shift_mode) <= HOST_BITS_PER_WIDE_INT
&& !((nonzero_bits (varop, shift_mode) << count)
& GET_MODE_MASK (shift_mode)))
varop = const0_rtx;
switch (GET_CODE (varop))
{
case SIGN_EXTEND:
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)
{
new = adjust_address_nv (varop, tmode,
BYTES_BIG_ENDIAN ? 0
: count / BITS_PER_UNIT);
varop = gen_rtx_fmt_e (code == ASHIFTRT ? SIGN_EXTEND
: ZERO_EXTEND, mode, new);
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_fmt_e (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)))
&& (unsigned int) ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (varop)))
+ (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
== mode_words)
{
varop = SUBREG_REG (varop);
if (GET_MODE_SIZE (GET_MODE (varop)) > GET_MODE_SIZE (mode))
mode = GET_MODE (varop);
continue;
}
break;
case MULT:
if (GET_CODE (XEXP (varop, 1)) == CONST_INT
&& exact_log2 (INTVAL (XEXP (varop, 1))) >= 0)
{
varop
= simplify_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
= simplify_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 == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1)
&& (GET_MODE_BITSIZE (result_mode)
>= GET_MODE_BITSIZE (GET_MODE (varop))))
{
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);
unsigned int first_count = INTVAL (XEXP (varop, 1));
unsigned HOST_WIDE_INT mask;
rtx mask_rtx;
if (code == ASHIFT && first_code == ASHIFTRT
&& count == (unsigned int)
(GET_MODE_BITSIZE (result_mode)
- GET_MODE_BITSIZE (GET_MODE (varop))))
{
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))
{
varop = XEXP (varop, 0);
signed_count = count - first_count;
if (signed_count < 0)
count = -signed_count, code = ASHIFT;
else
count = signed_count;
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;
signed_count = count;
if ((code == ASHIFTRT || code == LSHIFTRT)
== (first_code == ASHIFTRT || first_code == LSHIFTRT))
signed_count += first_count;
else
signed_count -= first_count;
if (signed_count > 0
&& ((first_code == ROTATE && code == ASHIFT)
|| (first_code == ASHIFTRT && code == LSHIFTRT)))
code = first_code, count = signed_count;
else if (signed_count < 0)
code = first_code, count = -signed_count;
else
count = signed_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_fmt_ee (code, mode, new, XEXP (varop, 1));
count = 0;
continue;
}
break;
case NOT:
varop = gen_rtx_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 == (unsigned int)
(GET_MODE_BITSIZE (GET_MODE (varop)) - 1)
&& rtx_equal_p (XEXP (XEXP (varop, 0), 0), XEXP (varop, 1)))
{
count = 0;
varop = gen_rtx_LE (GET_MODE (varop), XEXP (varop, 1),
const0_rtx);
if (STORE_FLAG_VALUE == 1 ? code == ASHIFTRT : code == LSHIFTRT)
varop = gen_rtx_NEG (GET_MODE (varop), varop);
continue;
}
if (GET_CODE (XEXP (varop, 1)) == CONST_INT
&& !(code == ASHIFTRT && GET_CODE (varop) == XOR
&& 0 > trunc_int_for_mode (INTVAL (XEXP (varop, 1)),
shift_mode))
&& (new = simplify_binary_operation (code, result_mode,
XEXP (varop, 1),
GEN_INT (count))) != 0
&& 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;
}
if (GET_CODE (XEXP (varop, 1)) == CONST_INT
&& !(code == ASHIFTRT && GET_CODE (varop) == XOR
&& 0 > trunc_int_for_mode (INTVAL (XEXP (varop, 1)),
shift_mode)))
{
rtx lhs = simplify_shift_const (NULL_RTX, code, shift_mode,
XEXP (varop, 0), count);
rtx rhs = simplify_shift_const (NULL_RTX, code, shift_mode,
XEXP (varop, 1), count);
varop = simplify_gen_binary (GET_CODE (varop), shift_mode,
lhs, rhs);
varop = apply_distributive_law (varop);
count = 0;
continue;
}
break;
case EQ:
if (code == LSHIFTRT
&& XEXP (varop, 1) == const0_rtx
&& GET_MODE (XEXP (varop, 0)) == result_mode
&& count == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1)
&& GET_MODE_BITSIZE (result_mode) <= HOST_BITS_PER_WIDE_INT
&& ((STORE_FLAG_VALUE
& ((HOST_WIDE_INT) 1
< (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 == (unsigned int) (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 == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1)
&& XEXP (varop, 1) == constm1_rtx
&& nonzero_bits (XEXP (varop, 0), result_mode) == 1
&& merge_outer_ops (&outer_op, &outer_const, XOR,
(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;
}
if (code == LSHIFTRT
&& GET_CODE (XEXP (varop, 1)) == CONST_INT
&& mode_signbit_p (result_mode, XEXP (varop, 1))
&& (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, XOR,
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 == (unsigned int)
(GET_MODE_BITSIZE (GET_MODE (varop)) - 1)
&& (code == LSHIFTRT || code == ASHIFTRT)
&& GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT
&& (unsigned HOST_WIDE_INT) INTVAL (XEXP (XEXP (varop, 0), 1))
== count
&& rtx_equal_p (XEXP (XEXP (varop, 0), 0), XEXP (varop, 1)))
{
count = 0;
varop = gen_rtx_GT (GET_MODE (varop), XEXP (varop, 1),
const0_rtx);
if (STORE_FLAG_VALUE == 1 ? code == ASHIFTRT : code == LSHIFTRT)
varop = gen_rtx_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_LSHIFTRT (GET_MODE (varop_inner),
XEXP (varop_inner, 0),
GEN_INT
(count + INTVAL (XEXP (varop_inner, 1))));
varop = gen_rtx_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)) == RTX_BIN_ARITH
&& GET_CODE (XEXP (x, 1)) == CONST_INT
&& (unsigned HOST_WIDE_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 (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
x = gen_rtx_fmt_ee (code, shift_mode, varop, const_rtx);
if (outer_op != UNKNOWN && 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 (result_mode, x);
if (complement_p)
x = simplify_gen_unary (NOT, result_mode, x, result_mode);
if (outer_op != UNKNOWN)
{
if (GET_MODE_BITSIZE (result_mode) < HOST_BITS_PER_WIDE_INT)
outer_const = trunc_int_for_mode (outer_const, result_mode);
if (outer_op == AND)
x = simplify_and_const_int (NULL_RTX, result_mode, x, outer_const);
else if (outer_op == SET)
x = GEN_INT (outer_const);
else if (GET_RTX_CLASS (outer_op) == RTX_UNARY)
x = simplify_gen_unary (outer_op, result_mode, x, result_mode);
else
x = simplify_gen_binary (outer_op, result_mode, x,
GEN_INT (outer_const));
}
return x;
}
static int
recog_for_combine (rtx *pnewpat, rtx insn, rtx *pnotes)
{
rtx pat = *pnewpat;
int insn_code_number;
int num_clobbers_to_add = 0;
int i;
rtx notes = 0;
rtx old_notes, old_pat;
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;
old_pat = PATTERN (insn);
old_notes = REG_NOTES (insn);
PATTERN (insn) = pat;
REG_NOTES (insn) = 0;
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);
PATTERN (insn) = pat;
insn_code_number = recog (pat, insn, &num_clobbers_to_add);
}
PATTERN (insn) = old_pat;
REG_NOTES (insn) = old_notes;
if (insn_code_number < 0 && GET_CODE (pat) == SET && set_noop_p (pat))
insn_code_number = NOOP_MOVE_INSN_CODE, num_clobbers_to_add = 0;
if (num_clobbers_to_add)
{
rtx newpat = gen_rtx_PARALLEL (VOIDmode,
rtvec_alloc (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 (REG_P (XEXP (XVECEXP (newpat, 0, i), 0))
&& ! reg_dead_at_p (XEXP (XVECEXP (newpat, 0, i), 0), insn))
return -1;
notes = gen_rtx_EXPR_LIST (REG_UNUSED,
XEXP (XVECEXP (newpat, 0, i), 0), notes);
}
pat = newpat;
}
*pnewpat = pat;
*pnotes = notes;
return insn_code_number;
}
static rtx
gen_lowpart_for_combine (enum machine_mode omode, rtx x)
{
enum machine_mode imode = GET_MODE (x);
unsigned int osize = GET_MODE_SIZE (omode);
unsigned int isize = GET_MODE_SIZE (imode);
rtx result;
if (omode == imode)
return x;
if (omode == Pmode
&& (GET_CODE (x) == CONST
|| GET_CODE (x) == SYMBOL_REF
|| GET_CODE (x) == LABEL_REF))
return x;
if (GET_MODE_SIZE (omode) > UNITS_PER_WORD
&& ! ((imode == VOIDmode
&& (GET_CODE (x) == CONST_INT
|| GET_CODE (x) == CONST_DOUBLE))
|| isize == osize))
goto fail;
if (GET_CODE (x) == SUBREG && MEM_P (SUBREG_REG (x)))
{
x = SUBREG_REG (x);
imode = GET_MODE (x);
if (imode == omode)
return x;
isize = GET_MODE_SIZE (imode);
}
result = gen_lowpart_common (omode, x);
#ifdef CANNOT_CHANGE_MODE_CLASS
if (result != 0 && GET_CODE (result) == SUBREG)
record_subregs_of_mode (result);
#endif
if (result)
return result;
if (MEM_P (x))
{
int offset = 0;
if (MEM_VOLATILE_P (x) || mode_dependent_address_p (XEXP (x, 0)))
goto fail;
if (isize < osize)
return gen_rtx_SUBREG (omode, x, 0);
if (WORDS_BIG_ENDIAN)
offset = MAX (isize, UNITS_PER_WORD) - MAX (osize, UNITS_PER_WORD);
if (BYTES_BIG_ENDIAN)
offset -= MIN (UNITS_PER_WORD, osize) - MIN (UNITS_PER_WORD, isize);
return adjust_address_nv (x, omode, offset);
}
else if (COMPARISON_P (x))
return gen_rtx_fmt_ee (GET_CODE (x), omode, XEXP (x, 0), XEXP (x, 1));
else
{
int offset = 0;
rtx res;
offset = subreg_lowpart_offset (omode, imode);
if (imode == VOIDmode)
{
imode = int_mode_for_mode (omode);
x = gen_lowpart_common (imode, x);
if (x == NULL)
goto fail;
}
res = simplify_gen_subreg (omode, x, imode, offset);
if (res)
return res;
}
fail:
return gen_rtx_CLOBBER (imode, const0_rtx);
}
static enum rtx_code
simplify_comparison (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
&& XEXP (op0, 1) == XEXP (op1, 1)
&& XEXP (op0, 1) == XEXP (XEXP (op0, 0), 1)
&& XEXP (op0, 1) == XEXP (XEXP (op1, 0), 1)
&& (INTVAL (XEXP (op0, 1))
== (GET_MODE_BITSIZE (GET_MODE (op0))
- (GET_MODE_BITSIZE
(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 != LEU)))
&& 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 (tmode, inner_op0);
op1 = gen_lowpart (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 (swap_commutative_operands_p (op0, op1))
{
tem = op0, op0 = op1, op1 = tem;
code = swap_condition (code);
}
while (GET_CODE (op1) == CONST_INT)
{
enum machine_mode mode = GET_MODE (op0);
unsigned 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 || COMPARISON_P (op0))))
break;
const_op = INTVAL (op1);
if (mode != VOIDmode)
const_op = trunc_int_for_mode (const_op, mode);
op1 = GEN_INT (const_op);
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 == GEU);
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 (!SHIFT_COUNT_TRUNCATED
&& GET_CODE (XEXP (op0, 0)) == CONST_INT
&& XEXP (op0, 1) == const1_rtx
&& equality_comparison_p && const_op == 0
&& (i = exact_log2 (INTVAL (XEXP (op0, 0)))) >= 0)
{
if (BITS_BIG_ENDIAN)
{
enum machine_mode new_mode
= mode_for_extraction (EP_extzv, 1);
if (new_mode == MAX_MACHINE_MODE)
i = BITS_PER_WORD - 1 - i;
else
{
mode = new_mode;
i = (GET_MODE_BITSIZE (mode) - 1 - i);
}
}
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:
mode = GET_MODE (XEXP (op0, 0));
if (mode != VOIDmode && GET_MODE_CLASS (mode) == MODE_INT
&& ! unsigned_comparison_p
&& (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
&& ((unsigned HOST_WIDE_INT) const_op
< (((unsigned HOST_WIDE_INT) 1
<< (GET_MODE_BITSIZE (mode) - 1))))
&& cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
op0 = XEXP (op0, 0);
continue;
}
break;
case SUBREG:
if (mode_width <= HOST_BITS_PER_WIDE_INT
&& subreg_lowpart_p (op0)
&& GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0))) > mode_width
&& GET_CODE (SUBREG_REG (op0)) == PLUS
&& GET_CODE (XEXP (SUBREG_REG (op0), 1)) == CONST_INT)
{
enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
rtx a = XEXP (SUBREG_REG (op0), 0);
HOST_WIDE_INT c1 = -INTVAL (XEXP (SUBREG_REG (op0), 1));
if ((c1 > 0
&& (unsigned HOST_WIDE_INT) c1
< (unsigned HOST_WIDE_INT) 1 << (mode_width - 1)
&& (equality_comparison_p || unsigned_comparison_p)
&& ((0 == (nonzero_bits (a, inner_mode)
& ~GET_MODE_MASK (mode))
&& const_op >= 0)
|| (num_sign_bit_copies (a, inner_mode)
> (unsigned int) (GET_MODE_BITSIZE (inner_mode)
- mode_width)
&& const_op < 0)))
|| ((unsigned HOST_WIDE_INT) c1
< (unsigned HOST_WIDE_INT) 1 << (mode_width - 2)
&& num_sign_bit_copies (a, inner_mode)
> (unsigned int) (GET_MODE_BITSIZE (inner_mode)
- mode_width - 1)))
{
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:
mode = GET_MODE (XEXP (op0, 0));
if (mode != VOIDmode && GET_MODE_CLASS (mode) == MODE_INT
&& (unsigned_comparison_p || equality_comparison_p)
&& (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
&& ((unsigned HOST_WIDE_INT) const_op < GET_MODE_MASK (mode))
&& cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
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
&& (unsigned HOST_WIDE_INT) INTVAL (XEXP (XEXP (op0, 0), 1))
== mode_width - 1
&& rtx_equal_p (XEXP (XEXP (op0, 0), 0), XEXP (op0, 1)))
{
op0 = XEXP (op0, 1);
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 UNEQ: case LTGT:
case LT: case LTU: case UNLT: case LE: case LEU: case UNLE:
case GT: case GTU: case UNGT: case GE: case GEU: case UNGE:
case UNORDERED: case ORDERED:
if (const_op != 0
|| CC0_P (XEXP (op0, 0))
|| 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
|| (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)))
{
enum rtx_code new_code;
if (code == LT || code == NE)
new_code = GET_CODE (op0);
else
new_code = combine_reversed_comparison_code (op0);
if (new_code != UNKNOWN)
{
code = new_code;
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_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
&& (COMPARISON_P (XEXP (XEXP (op0, 0), 0))
|| ((tem = get_last_value (XEXP (XEXP (op0, 0), 0))) != 0
&& COMPARISON_P (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 (tmode, XEXP (op0, 0));
continue;
}
if (GET_CODE (XEXP (op0, 0)) == SUBREG)
{
unsigned HOST_WIDE_INT c1;
tmode = GET_MODE (SUBREG_REG (XEXP (op0, 0)));
if (SCALAR_INT_MODE_P (tmode)
&& (0
#ifdef WORD_REGISTER_OPERATIONS
|| (mode_width > GET_MODE_BITSIZE (tmode)
&& mode_width <= BITS_PER_WORD)
#endif
|| (mode_width <= GET_MODE_BITSIZE (tmode)
&& subreg_lowpart_p (XEXP (op0, 0))))
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
&& mode_width <= HOST_BITS_PER_WIDE_INT
&& GET_MODE_BITSIZE (tmode) <= HOST_BITS_PER_WIDE_INT
&& ((c1 = INTVAL (XEXP (op0, 1))) & ~mask) == 0
&& (c1 & ~GET_MODE_MASK (tmode)) == 0
&& c1 != mask
&& c1 != GET_MODE_MASK (tmode))
{
op0 = simplify_gen_binary (AND, tmode,
SUBREG_REG (XEXP (op0, 0)),
gen_int_mode (c1, tmode));
op0 = gen_lowpart (mode, op0);
continue;
}
}
if (const_op == 0 && equality_comparison_p
&& XEXP (op0, 1) == const1_rtx
&& GET_CODE (XEXP (op0, 0)) == NOT)
{
op0 = simplify_and_const_int
(NULL_RTX, mode, XEXP (XEXP (op0, 0), 0), (HOST_WIDE_INT) 1);
code = (code == NE ? EQ : NE);
continue;
}
if (const_op == 0 && equality_comparison_p
&& XEXP (op0, 1) == const1_rtx
&& GET_CODE (XEXP (op0, 0)) == LSHIFTRT)
{
rtx shift_op = XEXP (XEXP (op0, 0), 0);
rtx shift_count = XEXP (XEXP (op0, 0), 1);
if (GET_CODE (shift_op) == NOT
|| (GET_CODE (shift_op) == XOR
&& GET_CODE (XEXP (shift_op, 1)) == CONST_INT
&& GET_CODE (shift_count) == CONST_INT
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& (INTVAL (XEXP (shift_op, 1))
== (HOST_WIDE_INT) 1 << INTVAL (shift_count))))
{
op0 = simplify_and_const_int
(NULL_RTX, mode,
gen_rtx_LSHIFTRT (mode, XEXP (shift_op, 0), shift_count),
(HOST_WIDE_INT) 1);
code = (code == NE ? EQ : NE);
continue;
}
}
break;
case ASHIFT:
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)
{
unsigned HOST_WIDE_INT temp = const_op & GET_MODE_MASK (mode);
temp >>= INTVAL (XEXP (op0, 1));
op1 = gen_int_mode (temp, mode);
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
&& (unsigned HOST_WIDE_INT) INTVAL (XEXP (op0, 1))
== mode_width - 1)
{
op0 = simplify_and_const_int (NULL_RTX, mode, XEXP (op0, 0),
(HOST_WIDE_INT) 1);
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) >> 1) + 1)
<= GET_MODE_MASK (tmode)))
{
op0 = gen_lowpart (tmode, XEXP (XEXP (op0, 0), 0));
continue;
}
if (! unsigned_comparison_p
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
&& GET_CODE (XEXP (op0, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (op0, 0), 1)) == CONST_INT
&& GET_CODE (XEXP (XEXP (op0, 0), 0)) == ASHIFT
&& XEXP (op0, 1) == XEXP (XEXP (XEXP (op0, 0), 0), 1)
&& (tmode = mode_for_size (mode_width - INTVAL (XEXP (op0, 1)),
MODE_INT, 1)) != BLKmode
&& (((unsigned HOST_WIDE_INT) const_op
+ (GET_MODE_MASK (tmode) >> 1) + 1)
<= GET_MODE_MASK (tmode)))
{
rtx inner = XEXP (XEXP (XEXP (op0, 0), 0), 0);
rtx add_const = XEXP (XEXP (op0, 0), 1);
rtx new_const = simplify_gen_binary (ASHIFTRT, GET_MODE (op0),
add_const, XEXP (op0, 1));
op0 = simplify_gen_binary (PLUS, tmode,
gen_lowpart (tmode, inner),
new_const);
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
&& (((unsigned HOST_WIDE_INT) const_op
+ (GET_CODE (op0) != LSHIFTRT
? ((GET_MODE_MASK (mode) >> INTVAL (XEXP (op0, 1)) >> 1)
+ 1)
: 0))
<= GET_MODE_MASK (mode) >> INTVAL (XEXP (op0, 1))))
{
if (GET_CODE (op0) == LSHIFTRT)
code = unsigned_condition (code);
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
&& (unsigned HOST_WIDE_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
&& GET_MODE_CLASS (GET_MODE (SUBREG_REG (op0))) == MODE_INT
&& (code == NE || code == EQ))
{
if (GET_MODE_SIZE (GET_MODE (op0))
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))))
{
if (REG_P (SUBREG_REG (op0)))
{
op0 = SUBREG_REG (op0);
op1 = gen_lowpart (GET_MODE (op0), op1);
}
}
else if ((GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)))
<= HOST_BITS_PER_WIDE_INT)
&& (nonzero_bits (SUBREG_REG (op0),
GET_MODE (SUBREG_REG (op0)))
& ~GET_MODE_MASK (GET_MODE (op0))) == 0)
{
tem = gen_lowpart (GET_MODE (SUBREG_REG (op0)), op1);
if ((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
&& ! have_insn_for (COMPARE, mode))
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 (have_insn_for (COMPARE, tmode))
{
int zero_extended;
zero_extended = ((code == EQ || code == NE
|| code == GEU || code == GTU
|| code == LEU || code == LTU)
&& (nonzero_bits (op0, tmode)
& ~GET_MODE_MASK (mode)) == 0
&& ((GET_CODE (op1) == CONST_INT
|| (nonzero_bits (op1, tmode)
& ~GET_MODE_MASK (mode)) == 0)));
if (zero_extended
|| ((num_sign_bit_copies (op0, tmode)
> (unsigned int) (GET_MODE_BITSIZE (tmode)
- GET_MODE_BITSIZE (mode)))
&& (num_sign_bit_copies (op1, tmode)
> (unsigned int) (GET_MODE_BITSIZE (tmode)
- GET_MODE_BITSIZE (mode)))))
{
if (GET_CODE (op0) == AND
&& !have_insn_for (AND, mode))
op0 = simplify_gen_binary (AND, tmode,
gen_lowpart (tmode,
XEXP (op0, 0)),
gen_lowpart (tmode,
XEXP (op0, 1)));
op0 = gen_lowpart (tmode, op0);
if (zero_extended && GET_CODE (op1) == CONST_INT)
op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (mode));
op1 = gen_lowpart (tmode, op1);
break;
}
if (op1 == const0_rtx && (code == LT || code == GE)
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
{
op0 = simplify_gen_binary (AND, tmode,
gen_lowpart (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 enum rtx_code
combine_reversed_comparison_code (rtx exp)
{
enum rtx_code code1 = reversed_comparison_code (exp, NULL);
rtx x;
if (code1 != UNKNOWN
|| GET_MODE_CLASS (GET_MODE (XEXP (exp, 0))) != MODE_CC)
return code1;
x = get_last_value (XEXP (exp, 0));
if (!x || GET_CODE (x) != COMPARE)
return UNKNOWN;
return reversed_comparison_code_parts (GET_CODE (exp),
XEXP (x, 0), XEXP (x, 1), NULL);
}
static rtx
reversed_comparison (rtx exp, enum machine_mode mode, rtx op0, rtx op1)
{
enum rtx_code reversed_code = combine_reversed_comparison_code (exp);
if (reversed_code == UNKNOWN)
return NULL_RTX;
else
return simplify_gen_relational (reversed_code, mode, VOIDmode, op0, op1);
}
static int
count_rtxs (rtx x)
{
enum rtx_code code = GET_CODE (x);
const char *fmt;
int i, ret = 1;
if (GET_RTX_CLASS (code) == '2'
|| GET_RTX_CLASS (code) == 'c')
{
rtx x0 = XEXP (x, 0);
rtx x1 = XEXP (x, 1);
if (x0 == x1)
return 1 + 2 * count_rtxs (x0);
if ((GET_RTX_CLASS (GET_CODE (x1)) == '2'
|| GET_RTX_CLASS (GET_CODE (x1)) == 'c')
&& (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1)))
return 2 + 2 * count_rtxs (x0)
+ count_rtxs (x == XEXP (x1, 0)
? XEXP (x1, 1) : XEXP (x1, 0));
if ((GET_RTX_CLASS (GET_CODE (x0)) == '2'
|| GET_RTX_CLASS (GET_CODE (x0)) == 'c')
&& (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1)))
return 2 + 2 * count_rtxs (x1)
+ count_rtxs (x == XEXP (x0, 0)
? XEXP (x0, 1) : XEXP (x0, 0));
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
if (fmt[i] == 'e')
ret += count_rtxs (XEXP (x, i));
return ret;
}
static void
update_table_tick (rtx x)
{
enum rtx_code code = GET_CODE (x);
const char *fmt = GET_RTX_FORMAT (code);
int i;
if (code == REG)
{
unsigned int regno = REGNO (x);
unsigned int endregno
= regno + (regno < FIRST_PSEUDO_REGISTER
? hard_regno_nregs[regno][GET_MODE (x)] : 1);
unsigned int r;
for (r = regno; r < endregno; r++)
reg_stat[r].last_set_table_tick = label_tick;
return;
}
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
if (fmt[i] == 'e')
{
if (i == 0 && ARITHMETIC_P (x))
{
rtx x0 = XEXP (x, 0);
rtx x1 = XEXP (x, 1);
if (x0 == x1)
break;
if (ARITHMETIC_P (x1)
&& (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1)))
break;
if (ARITHMETIC_P (x0)
&& (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1)))
{
update_table_tick (XEXP (x0, x1 == XEXP (x0, 0) ? 1 : 0));
break;
}
}
update_table_tick (XEXP (x, i));
}
}
static void
record_value_for_reg (rtx reg, rtx insn, rtx value)
{
unsigned int regno = REGNO (reg);
unsigned int endregno
= regno + (regno < FIRST_PSEUDO_REGISTER
? hard_regno_nregs[regno][GET_MODE (reg)] : 1);
unsigned int 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)
{
if (ARITHMETIC_P (tem)
&& GET_CODE (XEXP (tem, 0)) == CLOBBER
&& GET_CODE (XEXP (tem, 1)) == CLOBBER)
tem = XEXP (tem, 0);
else if (count_occurrences (value, reg, 1) >= 2)
{
if (count_rtxs (tem) > MAX_LAST_VALUE_RTL)
tem = gen_rtx_CLOBBER (GET_MODE (tem), const0_rtx);
}
value = replace_rtx (copy_rtx (value), reg, tem);
}
}
for (i = regno; i < endregno; i++)
{
if (insn)
reg_stat[i].last_set = insn;
reg_stat[i].last_set_value = 0;
reg_stat[i].last_set_mode = 0;
reg_stat[i].last_set_nonzero_bits = 0;
reg_stat[i].last_set_sign_bit_copies = 0;
reg_stat[i].last_death = 0;
}
if (value)
update_table_tick (value);
for (i = regno; i < endregno; i++)
{
reg_stat[i].last_set_label = label_tick;
if (value && reg_stat[i].last_set_table_tick == label_tick)
reg_stat[i].last_set_invalid = 1;
else
reg_stat[i].last_set_invalid = 0;
}
if (value && ! get_last_value_validate (&value, insn,
reg_stat[regno].last_set_label, 0))
{
value = copy_rtx (value);
if (! get_last_value_validate (&value, insn,
reg_stat[regno].last_set_label, 1))
value = 0;
}
reg_stat[regno].last_set_value = value;
if (value)
{
enum machine_mode mode = GET_MODE (reg);
subst_low_cuid = INSN_CUID (insn);
reg_stat[regno].last_set_mode = mode;
if (GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
mode = nonzero_bits_mode;
reg_stat[regno].last_set_nonzero_bits = nonzero_bits (value, mode);
reg_stat[regno].last_set_sign_bit_copies
= num_sign_bit_copies (value, GET_MODE (reg));
}
}
static void
record_dead_and_set_regs_1 (rtx dest, rtx setter, void *data)
{
rtx record_dead_insn = (rtx) data;
if (GET_CODE (dest) == SUBREG)
dest = SUBREG_REG (dest);
if (REG_P (dest))
{
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 (GET_MODE (dest),
SET_SRC (setter)));
else
record_value_for_reg (dest, record_dead_insn, NULL_RTX);
}
else if (MEM_P (dest)
&& ! push_operand (dest, GET_MODE (dest)))
mem_last_set = INSN_CUID (record_dead_insn);
}
static void
record_dead_and_set_regs (rtx insn)
{
rtx link;
unsigned int i;
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
{
if (REG_NOTE_KIND (link) == REG_DEAD
&& REG_P (XEXP (link, 0)))
{
unsigned int regno = REGNO (XEXP (link, 0));
unsigned int endregno
= regno + (regno < FIRST_PSEUDO_REGISTER
? hard_regno_nregs[regno][GET_MODE (XEXP (link, 0))]
: 1);
for (i = regno; i < endregno; i++)
reg_stat[i].last_death = insn;
}
else if (REG_NOTE_KIND (link) == REG_INC)
record_value_for_reg (XEXP (link, 0), insn, NULL_RTX);
}
if (CALL_P (insn))
{
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
{
reg_stat[i].last_set_value = 0;
reg_stat[i].last_set_mode = 0;
reg_stat[i].last_set_nonzero_bits = 0;
reg_stat[i].last_set_sign_bit_copies = 0;
reg_stat[i].last_death = 0;
}
last_call_cuid = mem_last_set = INSN_CUID (insn);
return;
}
note_stores (PATTERN (insn), record_dead_and_set_regs_1, insn);
}
static void
record_promoted_value (rtx insn, rtx subreg)
{
rtx links, set;
unsigned int regno = REGNO (SUBREG_REG (subreg));
enum machine_mode mode = GET_MODE (subreg);
if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
return;
for (links = LOG_LINKS (insn); links;)
{
insn = XEXP (links, 0);
set = single_set (insn);
if (! set || !REG_P (SET_DEST (set))
|| REGNO (SET_DEST (set)) != regno
|| GET_MODE (SET_DEST (set)) != GET_MODE (SUBREG_REG (subreg)))
{
links = XEXP (links, 1);
continue;
}
if (reg_stat[regno].last_set == insn)
{
if (SUBREG_PROMOTED_UNSIGNED_P (subreg) > 0)
reg_stat[regno].last_set_nonzero_bits &= GET_MODE_MASK (mode);
}
if (REG_P (SET_SRC (set)))
{
regno = REGNO (SET_SRC (set));
links = LOG_LINKS (insn);
}
else
break;
}
}
static void
check_promoted_subreg (rtx insn, rtx x)
{
if (GET_CODE (x) == SUBREG && SUBREG_PROMOTED_VAR_P (x)
&& REG_P (SUBREG_REG (x)))
record_promoted_value (insn, x);
else
{
const char *format = GET_RTX_FORMAT (GET_CODE (x));
int i, j;
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (x)); i++)
switch (format[i])
{
case 'e':
check_promoted_subreg (insn, XEXP (x, i));
break;
case 'V':
case 'E':
if (XVEC (x, i) != 0)
for (j = 0; j < XVECLEN (x, i); j++)
check_promoted_subreg (insn, XVECEXP (x, i, j));
break;
}
}
}
static int
get_last_value_validate (rtx *loc, rtx insn, int tick, int replace)
{
rtx x = *loc;
const char *fmt = GET_RTX_FORMAT (GET_CODE (x));
int len = GET_RTX_LENGTH (GET_CODE (x));
int i;
if (REG_P (x))
{
unsigned int regno = REGNO (x);
unsigned int endregno
= regno + (regno < FIRST_PSEUDO_REGISTER
? hard_regno_nregs[regno][GET_MODE (x)] : 1);
unsigned int j;
for (j = regno; j < endregno; j++)
if (reg_stat[j].last_set_invalid
|| (! (regno >= FIRST_PSEUDO_REGISTER
&& REG_N_SETS (regno) == 1
&& (! REGNO_REG_SET_P
(ENTRY_BLOCK_PTR->next_bb->global_live_at_start, regno)))
&& reg_stat[j].last_set_label > tick))
{
if (replace)
*loc = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
return replace;
}
return 1;
}
else if (MEM_P (x) && !MEM_READONLY_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')
{
if (i == 1 && ARITHMETIC_P (x))
{
rtx x0 = XEXP (x, 0);
rtx x1 = XEXP (x, 1);
if (x0 == x1)
return 1;
if (ARITHMETIC_P (x0)
&& (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1)))
return 1;
if (ARITHMETIC_P (x1)
&& (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1)))
return
get_last_value_validate (&XEXP (x1,
x0 == XEXP (x1, 0) ? 1 : 0),
insn, tick, replace);
}
if (get_last_value_validate (&XEXP (x, i), insn, tick,
replace) == 0)
return 0;
}
else if (fmt[i] == 'E')
return 0;
}
return 1;
}
static rtx
get_last_value (rtx x)
{
unsigned 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 (GET_MODE (x), value);
if (!REG_P (x))
return 0;
regno = REGNO (x);
value = reg_stat[regno].last_set_value;
if (value == 0
|| (reg_stat[regno].last_set_label != label_tick
&& (regno < FIRST_PSEUDO_REGISTER
|| REG_N_SETS (regno) != 1
|| (REGNO_REG_SET_P
(ENTRY_BLOCK_PTR->next_bb->global_live_at_start, regno)))))
return 0;
if (INSN_CUID (reg_stat[regno].last_set) >= subst_low_cuid)
return 0;
if (get_last_value_validate (&value, reg_stat[regno].last_set,
reg_stat[regno].last_set_label, 0))
return value;
value = copy_rtx (value);
if (get_last_value_validate (&value, reg_stat[regno].last_set,
reg_stat[regno].last_set_label, 1))
return value;
return 0;
}
static int
use_crosses_set_p (rtx x, int from_cuid)
{
const char *fmt;
int i;
enum rtx_code code = GET_CODE (x);
if (code == REG)
{
unsigned int regno = REGNO (x);
unsigned endreg = regno + (regno < FIRST_PSEUDO_REGISTER
? hard_regno_nregs[regno][GET_MODE (x)] : 1);
#ifdef PUSH_ROUNDING
if (regno == STACK_POINTER_REGNUM && PUSH_ARGS)
return 1;
#endif
for (; regno < endreg; regno++)
if (reg_stat[regno].last_set
&& INSN_CUID (reg_stat[regno].last_set) > 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')
{
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 unsigned int reg_dead_regno, reg_dead_endregno;
static int reg_dead_flag;
static void
reg_dead_at_p_1 (rtx dest, rtx x, void *data ATTRIBUTE_UNUSED)
{
unsigned int regno, endregno;
if (!REG_P (dest))
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 (rtx reg, rtx insn)
{
basic_block block;
unsigned int 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 (!fixed_regs[i] && TEST_HARD_REG_BIT (newpat_used_regs, i))
return 0;
}
for (; insn && !LABEL_P (insn) && !BARRIER_P (insn);
insn = prev_nonnote_insn (insn))
{
note_stores (PATTERN (insn), reg_dead_at_p_1, NULL);
if (reg_dead_flag)
return reg_dead_flag == 1 ? 1 : 0;
if (find_regno_note (insn, REG_DEAD, reg_dead_regno))
return 1;
}
if (insn == 0)
block = ENTRY_BLOCK_PTR->next_bb;
else
{
FOR_EACH_BB (block)
if (insn == BB_HEAD (block))
break;
if (block == EXIT_BLOCK_PTR)
return 0;
}
for (i = reg_dead_regno; i < reg_dead_endregno; i++)
if (REGNO_REG_SET_P (block->global_live_at_start, i))
return 0;
return 1;
}
static void
mark_used_regs_combine (rtx x)
{
RTX_CODE code = GET_CODE (x);
unsigned int regno;
int i;
switch (code)
{
case LABEL_REF:
case SYMBOL_REF:
case CONST_INT:
case CONST:
case CONST_DOUBLE:
case CONST_VECTOR:
case PC:
case ADDR_VEC:
case ADDR_DIFF_VEC:
case ASM_INPUT:
#ifdef HAVE_cc0
case CC0:
#endif
return;
case CLOBBER:
if (MEM_P (XEXP (x, 0)))
mark_used_regs_combine (XEXP (XEXP (x, 0), 0));
return;
case REG:
regno = REGNO (x);
if (regno < FIRST_PSEUDO_REGISTER)
{
unsigned int endregno, r;
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;
endregno = regno + hard_regno_nregs[regno][GET_MODE (x)];
for (r = regno; r < endregno; r++)
SET_HARD_REG_BIT (newpat_used_regs, r);
}
return;
case SET:
{
rtx testreg = SET_DEST (x);
while (GET_CODE (testreg) == SUBREG
|| GET_CODE (testreg) == ZERO_EXTRACT
|| GET_CODE (testreg) == STRICT_LOW_PART)
testreg = XEXP (testreg, 0);
if (MEM_P (testreg))
mark_used_regs_combine (XEXP (testreg, 0));
mark_used_regs_combine (SET_SRC (x));
}
return;
default:
break;
}
{
const 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')
{
int j;
for (j = 0; j < XVECLEN (x, i); j++)
mark_used_regs_combine (XVECEXP (x, i, j));
}
}
}
}
rtx
remove_death (unsigned int regno, rtx insn)
{
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 (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn,
rtx *pnotes)
{
const char *fmt;
int len, i;
enum rtx_code code = GET_CODE (x);
if (code == REG)
{
unsigned int regno = REGNO (x);
rtx where_dead = reg_stat[regno].last_death;
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))))
{
unsigned int deadregno = REGNO (XEXP (note, 0));
unsigned int deadend
= (deadregno + hard_regno_nregs[deadregno]
[GET_MODE (XEXP (note, 0))]);
unsigned int ourend
= regno + hard_regno_nregs[regno][GET_MODE (x)];
unsigned int i;
for (i = deadregno; i < deadend; i++)
if (i < regno || i >= ourend)
REG_NOTES (where_dead)
= gen_rtx_EXPR_LIST (REG_DEAD,
regno_reg_rtx[i],
REG_NOTES (where_dead));
}
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)
{
unsigned int ourend
= regno + hard_regno_nregs[regno][GET_MODE (x)];
unsigned int i, offset;
rtx oldnotes = 0;
if (note)
offset = hard_regno_nregs[regno][GET_MODE (XEXP (note, 0))];
else
offset = 1;
for (i = regno + offset; i < ourend; i++)
move_deaths (regno_reg_rtx[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 (MEM_P (dest))
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')
{
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 (rtx x, rtx body)
{
int i;
if (GET_CODE (body) == SET)
{
rtx dest = SET_DEST (body);
rtx target;
unsigned 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 (!REG_P (target))
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 (rtx notes, rtx from_insn, rtx i3, rtx i2)
{
rtx note, next_note;
rtx tem;
for (note = notes; note; note = next_note)
{
rtx place = 0, place2 = 0;
if (XEXP (note, 0) && REG_P (XEXP (note, 0))
&& 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_BR_PRED:
place = i3;
break;
case REG_VALUE_PROFILE:
break;
case REG_NON_LOCAL_GOTO:
if (JUMP_P (i3))
place = i3;
else
{
gcc_assert (i2 && JUMP_P (i2));
place = i2;
}
break;
case REG_EH_REGION:
if (CALL_P (i3))
place = i3;
else if (i2 && CALL_P (i2))
place = i2;
else
{
gcc_assert (flag_non_call_exceptions);
if (may_trap_p (i3))
place = i3;
else if (i2 && may_trap_p (i2))
place = i2;
}
break;
case REG_ALWAYS_RETURN:
case REG_NORETURN:
case REG_SETJMP:
if (CALL_P (i3))
place = i3;
else
{
gcc_assert (i2 && CALL_P (i2));
place = i2;
}
break;
case REG_UNUSED:
if (reg_set_p (XEXP (note, 0), PATTERN (i3)))
{
if (from_insn != i3)
break;
if (! (REG_P (XEXP (note, 0))
? 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))
&& ! (REG_P (XEXP (note, 0))
? 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_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;
}
if (place && JUMP_P (place))
{
rtx label = JUMP_LABEL (place);
if (!label)
JUMP_LABEL (place) = XEXP (note, 0);
else
{
gcc_assert (label == XEXP (note, 0));
if (LABEL_P (label))
LABEL_NUSES (label)--;
}
place = 0;
}
if (place2 && JUMP_P (place2))
{
rtx label = JUMP_LABEL (place2);
if (!label)
JUMP_LABEL (place2) = XEXP (note, 0);
else
{
gcc_assert (label == XEXP (note, 0));
if (LABEL_P (label))
LABEL_NUSES (label)--;
}
place2 = 0;
}
break;
case REG_NONNEG:
break;
case REG_RETVAL:
if (!NOTE_P (from_insn))
place = from_insn;
else
{
tem = find_reg_note (XEXP (note, 0), REG_LIBCALL, NULL_RTX);
place = prev_real_insn (from_insn);
if (tem && place)
XEXP (tem, 0) = place;
else if (XEXP (note, 0) == from_insn)
tem = place = 0;
else if (! tem)
place = 0;
}
break;
case REG_LIBCALL:
if (!NOTE_P (from_insn))
place = from_insn;
else
{
tem = find_reg_note (XEXP (note, 0), REG_RETVAL, NULL_RTX);
place = next_real_insn (from_insn);
if (tem && place)
XEXP (tem, 0) = place;
else if (XEXP (note, 0) == from_insn)
tem = place = 0;
else if (! tem)
place = 0;
}
break;
case REG_DEAD:
if (from_insn
&& CALL_P (from_insn)
&& find_reg_fusage (from_insn, USE, XEXP (note, 0)))
place = from_insn;
else if (reg_referenced_p (XEXP (note, 0), PATTERN (i3)))
place = i3;
else if (i2 != 0 && next_nonnote_insn (i2) == i3
&& reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
place = i2;
if (place == 0)
{
basic_block bb = this_basic_block;
for (tem = PREV_INSN (i3); place == 0; tem = PREV_INSN (tem))
{
if (! INSN_P (tem))
{
if (tem == BB_HEAD (bb))
break;
continue;
}
if ((REGNO (XEXP (note, 0)) >= FIRST_PSEUDO_REGISTER
|| !global_regs[REGNO (XEXP (note, 0))])
&& 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
)
{
rtx old_notes = REG_NOTES (tem);
PATTERN (tem) = pc_rtx;
REG_NOTES (tem) = NULL;
distribute_notes (old_notes, tem, tem, NULL_RTX);
distribute_links (LOG_LINKS (tem));
SET_INSN_DELETED (tem);
#ifdef HAVE_cc0
if (cc0_setter)
{
PATTERN (cc0_setter) = pc_rtx;
old_notes = REG_NOTES (cc0_setter);
REG_NOTES (cc0_setter) = NULL;
distribute_notes (old_notes, cc0_setter,
cc0_setter, NULL_RTX);
distribute_links (LOG_LINKS (cc0_setter));
SET_INSN_DELETED (cc0_setter);
}
#endif
}
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))
|| (CALL_P (tem)
&& 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 (tem == BB_HEAD (bb))
break;
}
if (REG_NOTE_KIND (note) == REG_DEAD && place == 0
&& REGNO_REG_SET_P (bb->global_live_at_start,
REGNO (XEXP (note, 0))))
SET_BIT (refresh_blocks, this_basic_block->index);
}
if (place && REG_NOTE_KIND (note) == REG_DEAD)
{
unsigned int regno = REGNO (XEXP (note, 0));
if (noop_move_p (place))
SET_BIT (refresh_blocks, this_basic_block->index);
if (dead_or_set_p (place, XEXP (note, 0))
|| reg_bitfield_target_p (XEXP (note, 0), PATTERN (place)))
{
if (reg_stat[regno].last_death != place)
reg_stat[regno].last_death = 0;
place = 0;
}
else
reg_stat[regno].last_death = place;
if (place && regno < FIRST_PSEUDO_REGISTER
&& hard_regno_nregs[regno][GET_MODE (XEXP (note, 0))] > 1)
{
unsigned int endregno
= regno + hard_regno_nregs[regno]
[GET_MODE (XEXP (note, 0))];
int all_used = 1;
unsigned 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))
|| dead_or_set_regno_p (place, i))
all_used = 0;
if (! all_used)
{
for (i = regno; i < endregno;
i += hard_regno_nregs[i][reg_raw_mode[i]])
{
rtx piece = regno_reg_rtx[i];
basic_block bb = this_basic_block;
if (! dead_or_set_p (place, piece)
&& ! reg_bitfield_target_p (piece,
PATTERN (place)))
{
rtx new_note
= gen_rtx_EXPR_LIST (REG_DEAD, piece, NULL_RTX);
distribute_notes (new_note, place, place,
NULL_RTX);
}
else if (! refers_to_regno_p (i, i + 1,
PATTERN (place), 0)
&& ! find_regno_fusage (place, USE, i))
for (tem = PREV_INSN (place); ;
tem = PREV_INSN (tem))
{
if (! INSN_P (tem))
{
if (tem == BB_HEAD (bb))
{
SET_BIT (refresh_blocks,
this_basic_block->index);
break;
}
continue;
}
if (dead_or_set_p (tem, piece)
|| reg_bitfield_target_p (piece,
PATTERN (tem)))
{
REG_NOTES (tem)
= gen_rtx_EXPR_LIST (REG_UNUSED, piece,
REG_NOTES (tem));
break;
}
}
}
place = 0;
}
}
}
break;
default:
gcc_unreachable ();
}
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)
&& REG_P (XEXP (note, 0)))
REG_N_DEATHS (REGNO (XEXP (note, 0)))--;
if (place2)
{
if ((REG_NOTE_KIND (note) == REG_DEAD
|| REG_NOTE_KIND (note) == REG_UNUSED)
&& REG_P (XEXP (note, 0)))
REG_N_DEATHS (REGNO (XEXP (note, 0)))++;
REG_NOTES (place2) = gen_rtx_fmt_ee (GET_CODE (note),
REG_NOTE_KIND (note),
XEXP (note, 0),
REG_NOTES (place2));
}
}
}
static void
distribute_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 (NOTE_P (XEXP (link, 0))
|| (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) == STRICT_LOW_PART)
reg = XEXP (reg, 0);
for (insn = NEXT_INSN (XEXP (link, 0));
(insn && (this_basic_block->next_bb == EXIT_BLOCK_PTR
|| BB_HEAD (this_basic_block->next_bb) != insn));
insn = NEXT_INSN (insn))
if (INSN_P (insn) && reg_overlap_mentioned_p (reg, PATTERN (insn)))
{
if (reg_referenced_p (reg, PATTERN (insn)))
place = insn;
break;
}
else if (CALL_P (insn)
&& find_reg_fusage (insn, USE, reg))
{
place = insn;
break;
}
else if (INSN_P (insn) && reg_set_p (reg, 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
unmentioned_reg_p_1 (rtx *loc, void *expr)
{
rtx x = *loc;
if (x != NULL_RTX
&& (REG_P (x) || MEM_P (x))
&& ! reg_mentioned_p (x, (rtx) expr))
return 1;
return 0;
}
static bool
unmentioned_reg_p (rtx equiv, rtx expr)
{
return for_each_rtx (&equiv, unmentioned_reg_p_1, expr);
}
static int
insn_cuid (rtx insn)
{
while (insn != 0 && INSN_UID (insn) > max_uid_cuid
&& NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == USE)
insn = NEXT_INSN (insn);
gcc_assert (INSN_UID (insn) <= max_uid_cuid);
return INSN_CUID (insn);
}
void
dump_combine_stats (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)
{
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);
}