Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

13049 lines (11202 sloc) 430.407 kB
/* Optimize by combining instructions for GNU compiler.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
/* This module is essentially the "combiner" phase of the U. of Arizona
Portable Optimizer, but redone to work on our list-structured
representation for RTL instead of their string representation.
The LOG_LINKS of each insn identify the most recent assignment
to each REG used in the insn. It is a list of previous insns,
each of which contains a SET for a REG that is used in this insn
and not used or set in between. LOG_LINKs never cross basic blocks.
They were set up by the preceding pass (lifetime analysis).
We try to combine each pair of insns joined by a logical link.
We also try to combine triples of insns A, B and C when
C has a link back to B and B has a link back to A.
LOG_LINKS does not have links for use of the CC0. They don't
need to, because the insn that sets the CC0 is always immediately
before the insn that tests it. So we always regard a branch
insn as having a logical link to the preceding insn. The same is true
for an insn explicitly using CC0.
We check (with use_crosses_set_p) to avoid combining in such a way
as to move a computation to a place where its value would be different.
Combination is done by mathematically substituting the previous
insn(s) values for the regs they set into the expressions in
the later insns that refer to these regs. If the result is a valid insn
for our target machine, according to the machine description,
we install it, delete the earlier insns, and update the data flow
information (LOG_LINKS and REG_NOTES) for what we did.
There are a few exceptions where the dataflow information isn't
completely updated (however this is only a local issue since it is
regenerated before the next pass that uses it):
- reg_live_length is not updated
- reg_n_refs is not adjusted in the rare case when a register is
no longer required in a computation
- there are extremely rare cases (see distribute_notes) when a
REG_DEAD note is lost
- a LOG_LINKS entry that refers to an insn with multiple SETs may be
removed because there is no way to know which register it was
linking
To simplify substitution, we combine only when the earlier insn(s)
consist of only a single assignment. To simplify updating afterward,
we never combine when a subroutine call appears in the middle.
Since we do not represent assignments to CC0 explicitly except when that
is all an insn does, there is no LOG_LINKS entry in an insn that uses
the condition code for the insn that set the condition code.
Fortunately, these two insns must be consecutive.
Therefore, every JUMP_INSN is taken to have an implicit logical link
to the preceding insn. This is not quite right, since non-jumps can
also use the condition code; but in practice such insns would not
combine anyway. */
#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 after insn-config.h so we get HAVE_conditional_move. */
#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 for dump_file. */
#include "output.h"
#include "params.h"
#include "timevar.h"
#include "tree-pass.h"
#include "df.h"
#include "cgraph.h"
/* Number of attempts to combine instructions in this function. */
static int combine_attempts;
/* Number of attempts that got as far as substitution in this function. */
static int combine_merges;
/* Number of instructions combined with added SETs in this function. */
static int combine_extras;
/* Number of instructions combined in this function. */
static int combine_successes;
/* Totals over entire compilation. */
static int total_attempts, total_merges, total_extras, total_successes;
/* combine_instructions may try to replace the right hand side of the
second instruction with the value of an associated REG_EQUAL note
before throwing it at try_combine. That is problematic when there
is a REG_DEAD note for a register used in the old right hand side
and can cause distribute_notes to do wrong things. This is the
second instruction if it has been so modified, null otherwise. */
static rtx i2mod;
/* When I2MOD is nonnull, this is a copy of the old right hand side. */
static rtx i2mod_old_rhs;
/* When I2MOD is nonnull, this is a copy of the new right hand side. */
static rtx i2mod_new_rhs;
typedef struct reg_stat_struct {
/* Record last point of death of (hard or pseudo) register n. */
rtx last_death;
/* Record last point of modification of (hard or pseudo) register n. */
rtx last_set;
/* The next group of fields allows the recording of the last value assigned
to (hard or pseudo) register n. We use this information to see if an
operation being processed is redundant given a prior operation performed
on the register. For example, an `and' with a constant is redundant if
all the zero bits are already known to be turned off.
We use an approach similar to that used by cse, but change it in the
following ways:
(1) We do not want to reinitialize at each label.
(2) It is useful, but not critical, to know the actual value assigned
to a register. Often just its form is helpful.
Therefore, we maintain the following fields:
last_set_value the last value assigned
last_set_label records the value of label_tick when the
register was assigned
last_set_table_tick records the value of label_tick when a
value using the register is assigned
last_set_invalid set to nonzero when it is not valid
to use the value of this register in some
register's value
To understand the usage of these tables, it is important to understand
the distinction between the value in last_set_value being valid and
the register being validly contained in some other expression in the
table.
(The next two parameters are out of date).
reg_stat[i].last_set_value is valid if it is nonzero, and either
reg_n_sets[i] is 1 or reg_stat[i].last_set_label == label_tick.
Register I may validly appear in any expression returned for the value
of another register if reg_n_sets[i] is 1. It may also appear in the
value for register J if reg_stat[j].last_set_invalid is zero, or
reg_stat[i].last_set_label < reg_stat[j].last_set_label.
If an expression is found in the table containing a register which may
not validly appear in an expression, the register is replaced by
something that won't match, (clobber (const_int 0)). */
/* Record last value assigned to (hard or pseudo) register n. */
rtx last_set_value;
/* Record the value of label_tick when an expression involving register n
is placed in last_set_value. */
int last_set_table_tick;
/* Record the value of label_tick when the value for register n is placed in
last_set_value. */
int last_set_label;
/* These fields are maintained in parallel with last_set_value and are
used to store the mode in which the register was last set, the bits
that were known to be zero when it was last set, and the number of
sign bits copies it was known to have when it was last set. */
unsigned HOST_WIDE_INT last_set_nonzero_bits;
char last_set_sign_bit_copies;
ENUM_BITFIELD(machine_mode) last_set_mode : 8;
/* Set nonzero if references to register n in expressions should not be
used. last_set_invalid is set nonzero when this register is being
assigned to and last_set_table_tick == label_tick. */
char last_set_invalid;
/* Some registers that are set more than once and used in more than one
basic block are nevertheless always set in similar ways. For example,
a QImode register may be loaded from memory in two places on a machine
where byte loads zero extend.
We record in the following fields if a register has some leading bits
that are always equal to the sign bit, and what we know about the
nonzero bits of a register, specifically which bits are known to be
zero.
If an entry is zero, it means that we don't know anything special. */
unsigned char sign_bit_copies;
unsigned HOST_WIDE_INT nonzero_bits;
/* Record the value of the label_tick when the last truncation
happened. The field truncated_to_mode is only valid if
truncation_label == label_tick. */
int truncation_label;
/* Record the last truncation seen for this register. If truncation
is not a nop to this mode we might be able to save an explicit
truncation if we know that value already contains a truncated
value. */
ENUM_BITFIELD(machine_mode) truncated_to_mode : 8;
} reg_stat_type;
DEF_VEC_O(reg_stat_type);
DEF_VEC_ALLOC_O(reg_stat_type,heap);
static VEC(reg_stat_type,heap) *reg_stat;
/* Record the luid of the last insn that invalidated memory
(anything that writes memory, and subroutine calls, but not pushes). */
static int mem_last_set;
/* Record the luid of the last CALL_INSN
so we can tell whether a potential combination crosses any calls. */
static int last_call_luid;
/* When `subst' is called, this is the insn that is being modified
(by combining in a previous insn). The PATTERN of this insn
is still the old pattern partially modified and it should not be
looked at, but this may be used to examine the successors of the insn
to judge whether a simplification is valid. */
static rtx subst_insn;
/* This is the lowest LUID that `subst' is currently dealing with.
get_last_value will not return a value if the register was set at or
after this LUID. If not for this mechanism, we could get confused if
I2 or I1 in try_combine were an insn that used the old value of a register
to obtain a new value. In that case, we might erroneously get the
new value of the register when we wanted the old one. */
static int subst_low_luid;
/* This contains any hard registers that are used in newpat; reg_dead_at_p
must consider all these registers to be always live. */
static HARD_REG_SET newpat_used_regs;
/* This is an insn to which a LOG_LINKS entry has been added. If this
insn is the earlier than I2 or I3, combine should rescan starting at
that location. */
static rtx added_links_insn;
/* Basic block in which we are performing combines. */
static basic_block this_basic_block;
static bool optimize_this_for_speed_p;
/* Length of the currently allocated uid_insn_cost array. */
static int max_uid_known;
/* The following array records the insn_rtx_cost for every insn
in the instruction stream. */
static int *uid_insn_cost;
/* The following array records the LOG_LINKS for every insn in the
instruction stream as an INSN_LIST rtx. */
static rtx *uid_log_links;
#define INSN_COST(INSN) (uid_insn_cost[INSN_UID (INSN)])
#define LOG_LINKS(INSN) (uid_log_links[INSN_UID (INSN)])
/* Incremented for each basic block. */
static int label_tick;
/* Reset to label_tick for each label. */
static int label_tick_ebb_start;
/* Mode used to compute significance in reg_stat[].nonzero_bits. It is the
largest integer mode that can fit in HOST_BITS_PER_WIDE_INT. */
static enum machine_mode nonzero_bits_mode;
/* Nonzero when reg_stat[].nonzero_bits and reg_stat[].sign_bit_copies can
be safely used. It is zero while computing them and after combine has
completed. This former test prevents propagating values based on
previously set values, which can be incorrect if a variable is modified
in a loop. */
static int nonzero_sign_valid;
/* Record one modification to rtl structure
to be undone by storing old_contents into *where. */
struct undo
{
struct undo *next;
enum { UNDO_RTX, UNDO_INT, UNDO_MODE } kind;
union { rtx r; int i; enum machine_mode m; } old_contents;
union { rtx *r; int *i; } where;
};
/* Record a bunch of changes to be undone, up to MAX_UNDO of them.
num_undo says how many are currently recorded.
other_insn is nonzero if we have modified some other insn in the process
of working on subst_insn. It must be verified too. */
struct undobuf
{
struct undo *undos;
struct undo *frees;
rtx other_insn;
};
static struct undobuf undobuf;
/* Number of times the pseudo being substituted for
was found and replaced. */
static int n_occurrences;
static rtx reg_nonzero_bits_for_combine (const_rtx, enum machine_mode, const_rtx,
enum machine_mode,
unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT *);
static rtx reg_num_sign_bit_copies_for_combine (const_rtx, enum machine_mode, const_rtx,
enum machine_mode,
unsigned int, unsigned int *);
static void do_SUBST (rtx *, rtx);
static void do_SUBST_INT (int *, int);
static void init_reg_last (void);
static void setup_incoming_promotions (rtx);
static void set_nonzero_bits_and_sign_copies (rtx, const_rtx, void *);
static int cant_combine_insn_p (rtx);
static int can_combine_p (rtx, rtx, rtx, rtx, rtx *, rtx *);
static int combinable_i3pat (rtx, rtx *, rtx, rtx, int, rtx *);
static 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 const_rtx expand_field_assignment (const_rtx);
static rtx make_extraction (enum machine_mode, rtx, HOST_WIDE_INT,
rtx, unsigned HOST_WIDE_INT, int, int, int);
static rtx extract_left_shift (rtx, int);
static rtx make_compound_operation (rtx, enum rtx_code);
static int get_pos_from_mask (unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT *);
static rtx canon_reg_for_combine (rtx, rtx);
static rtx force_to_mode (rtx, enum machine_mode,
unsigned HOST_WIDE_INT, 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_1 (enum machine_mode, rtx,
unsigned HOST_WIDE_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_1 (enum rtx_code, enum machine_mode, rtx, 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, const_rtx, void *);
static void record_dead_and_set_regs (rtx);
static int get_last_value_validate (rtx *, rtx, int, int);
static rtx get_last_value (const_rtx);
static int use_crosses_set_p (const_rtx, int);
static void reg_dead_at_p_1 (rtx, const_rtx, void *);
static int reg_dead_at_p (rtx, rtx);
static void move_deaths (rtx, rtx, int, rtx, rtx *);
static int reg_bitfield_target_p (rtx, rtx);
static void distribute_notes (rtx, rtx, rtx, rtx, rtx, rtx);
static void distribute_links (rtx);
static void mark_used_regs_combine (rtx);
static void record_promoted_value (rtx, rtx);
static int unmentioned_reg_p_1 (rtx *, void *);
static bool unmentioned_reg_p (rtx, rtx);
static int record_truncated_value (rtx *, void *);
static void record_truncated_values (rtx *, void *);
static bool reg_truncated_to_mode (enum machine_mode, const_rtx);
static rtx gen_lowpart_or_truncate (enum machine_mode, rtx);
/* It is not safe to use ordinary gen_lowpart in combine.
See comments in gen_lowpart_for_combine. */
#undef RTL_HOOKS_GEN_LOWPART
#define RTL_HOOKS_GEN_LOWPART gen_lowpart_for_combine
/* Our implementation of gen_lowpart never emits a new pseudo. */
#undef RTL_HOOKS_GEN_LOWPART_NO_EMIT
#define RTL_HOOKS_GEN_LOWPART_NO_EMIT 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
#undef RTL_HOOKS_REG_TRUNCATED_TO_MODE
#define RTL_HOOKS_REG_TRUNCATED_TO_MODE reg_truncated_to_mode
static const struct rtl_hooks combine_rtl_hooks = RTL_HOOKS_INITIALIZER;
/* Try to split PATTERN found in INSN. This returns NULL_RTX if
PATTERN can not be split. Otherwise, it returns an insn sequence.
This is a wrapper around split_insns which ensures that the
reg_stat vector is made larger if the splitter creates a new
register. */
static rtx
combine_split_insns (rtx pattern, rtx insn)
{
rtx ret;
unsigned int nregs;
ret = split_insns (pattern, insn);
nregs = max_reg_num ();
if (nregs > VEC_length (reg_stat_type, reg_stat))
VEC_safe_grow_cleared (reg_stat_type, heap, reg_stat, nregs);
return ret;
}
/* This is used by find_single_use to locate an rtx in LOC that
contains exactly one use of DEST, which is typically either a REG
or CC0. It returns a pointer to the innermost rtx expression
containing DEST. Appearances of DEST that are being used to
totally replace it are not counted. */
static rtx *
find_single_use_1 (rtx dest, rtx *loc)
{
rtx x = *loc;
enum rtx_code code = GET_CODE (x);
rtx *result = NULL;
rtx *this_result;
int i;
const char *fmt;
switch (code)
{
case CONST_INT:
case CONST:
case LABEL_REF:
case SYMBOL_REF:
case CONST_DOUBLE:
case CONST_VECTOR:
case CLOBBER:
return 0;
case SET:
/* If the destination is anything other than CC0, PC, a REG or a SUBREG
of a REG that occupies all of the REG, the insn uses DEST if
it is mentioned in the destination or the source. Otherwise, we
need just check the source. */
if (GET_CODE (SET_DEST (x)) != CC0
&& GET_CODE (SET_DEST (x)) != PC
&& !REG_P (SET_DEST (x))
&& ! (GET_CODE (SET_DEST (x)) == SUBREG
&& REG_P (SUBREG_REG (SET_DEST (x)))
&& (((GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (x))))
+ (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
== ((GET_MODE_SIZE (GET_MODE (SET_DEST (x)))
+ (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))))
break;
return find_single_use_1 (dest, &SET_SRC (x));
case MEM:
case SUBREG:
return find_single_use_1 (dest, &XEXP (x, 0));
default:
break;
}
/* If it wasn't one of the common cases above, check each expression and
vector of this code. Look for a unique usage of DEST. */
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
{
if (dest == XEXP (x, i)
|| (REG_P (dest) && REG_P (XEXP (x, i))
&& REGNO (dest) == REGNO (XEXP (x, i))))
this_result = loc;
else
this_result = find_single_use_1 (dest, &XEXP (x, i));
if (result == NULL)
result = this_result;
else if (this_result)
/* Duplicate usage. */
return NULL;
}
else if (fmt[i] == 'E')
{
int j;
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
{
if (XVECEXP (x, i, j) == dest
|| (REG_P (dest)
&& REG_P (XVECEXP (x, i, j))
&& REGNO (XVECEXP (x, i, j)) == REGNO (dest)))
this_result = loc;
else
this_result = find_single_use_1 (dest, &XVECEXP (x, i, j));
if (result == NULL)
result = this_result;
else if (this_result)
return NULL;
}
}
}
return result;
}
/* See if DEST, produced in INSN, is used only a single time in the
sequel. If so, return a pointer to the innermost rtx expression in which
it is used.
If PLOC is nonzero, *PLOC is set to the insn containing the single use.
If DEST is cc0_rtx, we look only at the next insn. In that case, we don't
care about REG_DEAD notes or LOG_LINKS.
Otherwise, we find the single use by finding an insn that has a
LOG_LINKS pointing at INSN and has a REG_DEAD note for DEST. If DEST is
only referenced once in that insn, we know that it must be the first
and last insn referencing DEST. */
static rtx *
find_single_use (rtx dest, rtx insn, rtx *ploc)
{
rtx next;
rtx *result;
rtx link;
#ifdef HAVE_cc0
if (dest == cc0_rtx)
{
next = NEXT_INSN (insn);
if (next == 0
|| (!NONJUMP_INSN_P (next) && !JUMP_P (next)))
return 0;
result = find_single_use_1 (dest, &PATTERN (next));
if (result && ploc)
*ploc = next;
return result;
}
#endif
if (!REG_P (dest))
return 0;
for (next = next_nonnote_insn (insn);
next != 0 && !LABEL_P (next);
next = next_nonnote_insn (next))
if (INSN_P (next) && dead_or_set_p (next, dest))
{
for (link = LOG_LINKS (next); link; link = XEXP (link, 1))
if (XEXP (link, 0) == insn)
break;
if (link)
{
result = find_single_use_1 (dest, &PATTERN (next));
if (ploc)
*ploc = next;
return result;
}
}
return 0;
}
/* Substitute NEWVAL, an rtx expression, into INTO, a place in some
insn. The substitution can be undone by undo_all. If INTO is already
set to NEWVAL, do not record this change. Because computing NEWVAL might
also call SUBST, we have to compute it before we put anything into
the undo table. */
static void
do_SUBST (rtx *into, rtx newval)
{
struct undo *buf;
rtx oldval = *into;
if (oldval == newval)
return;
/* We'd like to catch as many invalid transformations here as
possible. Unfortunately, there are way too many mode changes
that are perfectly valid, so we'd waste too much effort for
little gain doing the checks here. Focus on catching invalid
transformations involving integer constants. */
if (GET_MODE_CLASS (GET_MODE (oldval)) == MODE_INT
&& GET_CODE (newval) == CONST_INT)
{
/* Sanity check that we're replacing oldval with a CONST_INT
that is a valid sign-extension for the original mode. */
gcc_assert (INTVAL (newval)
== trunc_int_for_mode (INTVAL (newval), GET_MODE (oldval)));
/* Replacing the operand of a SUBREG or a ZERO_EXTEND with a
CONST_INT is not valid, because after the replacement, the
original mode would be gone. Unfortunately, we can't tell
when do_SUBST is called to replace the operand thereof, so we
perform this test on oldval instead, checking whether an
invalid replacement took place before we got here. */
gcc_assert (!(GET_CODE (oldval) == SUBREG
&& GET_CODE (SUBREG_REG (oldval)) == CONST_INT));
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 = XNEW (struct undo);
buf->kind = UNDO_RTX;
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))
/* Similar to SUBST, but NEWVAL is an int expression. Note that substitution
for the value of a HOST_WIDE_INT value (including CONST_INT) is
not safe. */
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 = XNEW (struct undo);
buf->kind = UNDO_INT;
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))
/* Similar to SUBST, but just substitute the mode. This is used when
changing the mode of a pseudo-register, so that any other
references to the entry in the regno_reg_rtx array will change as
well. */
static void
do_SUBST_MODE (rtx *into, enum machine_mode newval)
{
struct undo *buf;
enum machine_mode oldval = GET_MODE (*into);
if (oldval == newval)
return;
if (undobuf.frees)
buf = undobuf.frees, undobuf.frees = buf->next;
else
buf = XNEW (struct undo);
buf->kind = UNDO_MODE;
buf->where.r = into;
buf->old_contents.m = oldval;
adjust_reg_mode (*into, newval);
buf->next = undobuf.undos, undobuf.undos = buf;
}
#define SUBST_MODE(INTO, NEWVAL) do_SUBST_MODE(&(INTO), (NEWVAL))
/* Subroutine of try_combine. Determine whether the combine replacement
patterns NEWPAT, NEWI2PAT and NEWOTHERPAT are cheaper according to
insn_rtx_cost that the original instruction sequence I1, I2, I3 and
undobuf.other_insn. Note that I1 and/or NEWI2PAT may be NULL_RTX.
NEWOTHERPAT and undobuf.other_insn may also both be NULL_RTX. This
function returns false, if the costs of all instructions can be
estimated, and the replacements are more expensive than the original
sequence. */
static bool
combine_validate_cost (rtx i1, rtx i2, rtx i3, rtx newpat, rtx newi2pat,
rtx newotherpat)
{
int i1_cost, i2_cost, i3_cost;
int new_i2_cost, new_i3_cost;
int old_cost, new_cost;
/* Lookup the original insn_rtx_costs. */
i2_cost = INSN_COST (i2);
i3_cost = INSN_COST (i3);
if (i1)
{
i1_cost = INSN_COST (i1);
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;
}
/* Calculate the replacement insn_rtx_costs. */
new_i3_cost = insn_rtx_cost (newpat, optimize_this_for_speed_p);
if (newi2pat)
{
new_i2_cost = insn_rtx_cost (newi2pat, optimize_this_for_speed_p);
new_cost = (new_i2_cost > 0 && new_i3_cost > 0)
? new_i2_cost + new_i3_cost : 0;
}
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_COST (undobuf.other_insn);
new_other_cost = insn_rtx_cost (newotherpat, optimize_this_for_speed_p);
if (old_other_cost > 0 && new_other_cost > 0)
{
old_cost += old_other_cost;
new_cost += new_other_cost;
}
else
old_cost = 0;
}
/* Disallow this recombination if both new_cost and old_cost are
greater than zero, and new_cost is greater than old cost. */
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;
}
/* Update the uid_insn_cost array with the replacement costs. */
INSN_COST (i2) = new_i2_cost;
INSN_COST (i3) = new_i3_cost;
if (i1)
INSN_COST (i1) = 0;
return true;
}
/* Delete any insns that copy a register to itself. */
static void
delete_noop_moves (void)
{
rtx insn, next;
basic_block bb;
FOR_EACH_BB (bb)
{
for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb)); insn = next)
{
next = NEXT_INSN (insn);
if (INSN_P (insn) && noop_move_p (insn))
{
if (dump_file)
fprintf (dump_file, "deleting noop move %d\n", INSN_UID (insn));
delete_insn_and_edges (insn);
}
}
}
}
/* Fill in log links field for all insns. */
static void
create_log_links (void)
{
basic_block bb;
rtx *next_use, insn;
df_ref *def_vec, *use_vec;
next_use = XCNEWVEC (rtx, max_reg_num ());
/* Pass through each block from the end, recording the uses of each
register and establishing log links when def is encountered.
Note that we do not clear next_use array in order to save time,
so we have to test whether the use is in the same basic block as def.
There are a few cases below when we do not consider the definition or
usage -- these are taken from original flow.c did. Don't ask me why it is
done this way; I don't know and if it works, I don't want to know. */
FOR_EACH_BB (bb)
{
FOR_BB_INSNS_REVERSE (bb, insn)
{
if (!INSN_P (insn))
continue;
/* Log links are created only once. */
gcc_assert (!LOG_LINKS (insn));
for (def_vec = DF_INSN_DEFS (insn); *def_vec; def_vec++)
{
df_ref def = *def_vec;
int regno = DF_REF_REGNO (def);
rtx use_insn;
if (!next_use[regno])
continue;
/* Do not consider if it is pre/post modification in MEM. */
if (DF_REF_FLAGS (def) & DF_REF_PRE_POST_MODIFY)
continue;
/* Do not make the log link for frame pointer. */
if ((regno == FRAME_POINTER_REGNUM
&& (! reload_completed || frame_pointer_needed))
#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
|| (regno == HARD_FRAME_POINTER_REGNUM
&& (! reload_completed || frame_pointer_needed))
#endif
#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
|| (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
#endif
)
continue;
use_insn = next_use[regno];
if (BLOCK_FOR_INSN (use_insn) == bb)
{
/* flow.c claimed:
We don't build a LOG_LINK for hard registers contained
in ASM_OPERANDs. If these registers get replaced,
we might wind up changing the semantics of the insn,
even if reload can make what appear to be valid
assignments later. */
if (regno >= FIRST_PSEUDO_REGISTER
|| asm_noperands (PATTERN (use_insn)) < 0)
{
/* Don't add duplicate links between instructions. */
rtx links;
for (links = LOG_LINKS (use_insn); links;
links = XEXP (links, 1))
if (insn == XEXP (links, 0))
break;
if (!links)
LOG_LINKS (use_insn) =
alloc_INSN_LIST (insn, LOG_LINKS (use_insn));
}
}
next_use[regno] = NULL_RTX;
}
for (use_vec = DF_INSN_USES (insn); *use_vec; use_vec++)
{
df_ref use = *use_vec;
int regno = DF_REF_REGNO (use);
/* Do not consider the usage of the stack pointer
by function call. */
if (DF_REF_FLAGS (use) & DF_REF_CALL_STACK_USAGE)
continue;
next_use[regno] = insn;
}
}
}
free (next_use);
}
/* Clear LOG_LINKS fields of insns. */
static void
clear_log_links (void)
{
rtx insn;
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
if (INSN_P (insn))
free_INSN_LIST_list (&LOG_LINKS (insn));
}
/* Main entry point for combiner. F is the first insn of the function.
NREGS is the first unused pseudo-reg number.
Return nonzero if the combiner has turned an indirect jump
instruction into a direct jump. */
static int
combine_instructions (rtx f, unsigned int nregs)
{
rtx insn, next;
#ifdef HAVE_cc0
rtx prev;
#endif
rtx links, nextlinks;
rtx first;
int new_direct_jump_p = 0;
for (first = f; first && !INSN_P (first); )
first = NEXT_INSN (first);
if (!first)
return 0;
combine_attempts = 0;
combine_merges = 0;
combine_extras = 0;
combine_successes = 0;
rtl_hooks = combine_rtl_hooks;
VEC_safe_grow_cleared (reg_stat_type, heap, reg_stat, nregs);
init_recog_no_volatile ();
/* Allocate array for insn info. */
max_uid_known = get_max_uid ();
uid_log_links = XCNEWVEC (rtx, max_uid_known + 1);
uid_insn_cost = XCNEWVEC (int, max_uid_known + 1);
nonzero_bits_mode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0);
/* Don't use reg_stat[].nonzero_bits when computing it. This can cause
problems when, for example, we have j <<= 1 in a loop. */
nonzero_sign_valid = 0;
/* Scan all SETs and see if we can deduce anything about what
bits are known to be zero for some registers and how many copies
of the sign bit are known to exist for those registers.
Also set any known values so that we can use it while searching
for what bits are known to be set. */
label_tick = label_tick_ebb_start = 1;
setup_incoming_promotions (first);
create_log_links ();
FOR_EACH_BB (this_basic_block)
{
optimize_this_for_speed_p = optimize_bb_for_speed_p (this_basic_block);
last_call_luid = 0;
mem_last_set = -1;
label_tick++;
FOR_BB_INSNS (this_basic_block, insn)
if (INSN_P (insn) && BLOCK_FOR_INSN (insn))
{
subst_low_luid = DF_INSN_LUID (insn);
subst_insn = insn;
note_stores (PATTERN (insn), set_nonzero_bits_and_sign_copies,
insn);
record_dead_and_set_regs (insn);
#ifdef AUTO_INC_DEC
for (links = REG_NOTES (insn); links; links = XEXP (links, 1))
if (REG_NOTE_KIND (links) == REG_INC)
set_nonzero_bits_and_sign_copies (XEXP (links, 0), NULL_RTX,
insn);
#endif
/* Record the current insn_rtx_cost of this instruction. */
if (NONJUMP_INSN_P (insn))
INSN_COST (insn) = insn_rtx_cost (PATTERN (insn),
optimize_this_for_speed_p);
if (dump_file)
fprintf(dump_file, "insn_cost %d: %d\n",
INSN_UID (insn), INSN_COST (insn));
}
else if (LABEL_P (insn))
label_tick_ebb_start = label_tick;
}
nonzero_sign_valid = 1;
/* Now scan all the insns in forward order. */
label_tick = label_tick_ebb_start = 1;
init_reg_last ();
setup_incoming_promotions (first);
FOR_EACH_BB (this_basic_block)
{
optimize_this_for_speed_p = optimize_bb_for_speed_p (this_basic_block);
last_call_luid = 0;
mem_last_set = -1;
label_tick++;
rtl_profile_for_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 (INSN_P (insn))
{
/* See if we know about function return values before this
insn based upon SUBREG flags. */
check_promoted_subreg (insn, PATTERN (insn));
/* See if we can find hardregs and subreg of pseudos in
narrower modes. This could help turning TRUNCATEs
into SUBREGs. */
note_uses (&PATTERN (insn), record_truncated_values, NULL);
/* Try this insn with each insn it links back to. */
for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
if ((next = try_combine (insn, XEXP (links, 0),
NULL_RTX, &new_direct_jump_p)) != 0)
goto retry;
/* Try each sequence of three linked insns ending with this one. */
for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
{
rtx link = XEXP (links, 0);
/* If the linked insn has been replaced by a note, then there
is no point in pursuing this chain any further. */
if (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
/* Try to combine a jump insn that uses CC0
with a preceding insn that sets CC0, and maybe with its
logical predecessor as well.
This is how we make decrement-and-branch insns.
We need this special code because data flow connections
via CC0 do not get entered in LOG_LINKS. */
if (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;
}
/* Do the same for an insn that explicitly references CC0. */
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;
}
/* Finally, see if any of the insns that this insn links to
explicitly references CC0. If so, try this insn, that insn,
and its predecessor if it sets CC0. */
for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
if (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
/* Try combining an insn with two different insns whose results it
uses. */
for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
for (nextlinks = XEXP (links, 1); nextlinks;
nextlinks = XEXP (nextlinks, 1))
if ((next = try_combine (insn, XEXP (links, 0),
XEXP (nextlinks, 0),
&new_direct_jump_p)) != 0)
goto retry;
/* Try this insn with each REG_EQUAL note it links back to. */
for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
{
rtx set, note;
rtx temp = XEXP (links, 0);
if ((set = single_set (temp)) != 0
&& (note = find_reg_equal_equiv_note (temp)) != 0
&& (note = XEXP (note, 0), GET_CODE (note)) != EXPR_LIST
/* Avoid using a register that may already been marked
dead by an earlier instruction. */
&& ! unmentioned_reg_p (note, SET_SRC (set))
&& (GET_MODE (note) == VOIDmode
? SCALAR_INT_MODE_P (GET_MODE (SET_DEST (set)))
: GET_MODE (SET_DEST (set)) == GET_MODE (note)))
{
/* Temporarily replace the set's source with the
contents of the REG_EQUAL note. The insn will
be deleted or recognized by try_combine. */
rtx orig = SET_SRC (set);
SET_SRC (set) = note;
i2mod = temp;
i2mod_old_rhs = copy_rtx (orig);
i2mod_new_rhs = copy_rtx (note);
next = try_combine (insn, i2mod, NULL_RTX,
&new_direct_jump_p);
i2mod = NULL_RTX;
if (next)
goto retry;
SET_SRC (set) = orig;
}
}
if (!NOTE_P (insn))
record_dead_and_set_regs (insn);
retry:
;
}
else if (LABEL_P (insn))
label_tick_ebb_start = label_tick;
}
}
default_rtl_profile ();
clear_log_links ();
clear_bb_flags ();
new_direct_jump_p |= purge_all_dead_edges ();
delete_noop_moves ();
/* Clean up. */
free (uid_log_links);
free (uid_insn_cost);
VEC_free (reg_stat_type, heap, reg_stat);
{
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;
/* Make recognizer allow volatile MEMs again. */
init_recog ();
return new_direct_jump_p;
}
/* Wipe the last_xxx fields of reg_stat in preparation for another pass. */
static void
init_reg_last (void)
{
unsigned int i;
reg_stat_type *p;
for (i = 0; VEC_iterate (reg_stat_type, reg_stat, i, p); ++i)
memset (p, 0, offsetof (reg_stat_type, sign_bit_copies));
}
/* Set up any promoted values for incoming argument registers. */
static void
setup_incoming_promotions (rtx first)
{
tree arg;
bool strictly_local = false;
if (!targetm.calls.promote_function_args (TREE_TYPE (cfun->decl)))
return;
for (arg = DECL_ARGUMENTS (current_function_decl); arg;
arg = TREE_CHAIN (arg))
{
rtx reg = DECL_INCOMING_RTL (arg);
int uns1, uns3;
enum machine_mode mode1, mode2, mode3, mode4;
/* Only continue if the incoming argument is in a register. */
if (!REG_P (reg))
continue;
/* Determine, if possible, whether all call sites of the current
function lie within the current compilation unit. (This does
take into account the exporting of a function via taking its
address, and so forth.) */
strictly_local = cgraph_local_info (current_function_decl)->local;
/* The mode and signedness of the argument before any promotions happen
(equal to the mode of the pseudo holding it at that stage). */
mode1 = TYPE_MODE (TREE_TYPE (arg));
uns1 = TYPE_UNSIGNED (TREE_TYPE (arg));
/* The mode and signedness of the argument after any source language and
TARGET_PROMOTE_PROTOTYPES-driven promotions. */
mode2 = TYPE_MODE (DECL_ARG_TYPE (arg));
uns3 = TYPE_UNSIGNED (DECL_ARG_TYPE (arg));
/* The mode and signedness of the argument as it is actually passed,
after any TARGET_PROMOTE_FUNCTION_ARGS-driven ABI promotions. */
mode3 = promote_mode (DECL_ARG_TYPE (arg), mode2, &uns3, 1);
/* The mode of the register in which the argument is being passed. */
mode4 = GET_MODE (reg);
/* Eliminate sign extensions in the callee when possible. Only
do this when:
(a) a mode promotion has occurred;
(b) the mode of the register is the same as the mode of
the argument as it is passed; and
(c) the signedness does not change across any of the promotions; and
(d) when no language-level promotions (which we cannot guarantee
will have been done by an external caller) are necessary,
unless we know that this function is only ever called from
the current compilation unit -- all of whose call sites will
do the mode1 --> mode2 promotion. */
if (mode1 != mode3
&& mode3 == mode4
&& uns1 == uns3
&& (mode1 == mode2 || strictly_local))
{
/* Record that the value was promoted from mode1 to mode3,
so that any sign extension at the head of the current
function may be eliminated. */
rtx x;
x = gen_rtx_CLOBBER (mode1, const0_rtx);
x = gen_rtx_fmt_e ((uns3 ? ZERO_EXTEND : SIGN_EXTEND), mode3, x);
record_value_for_reg (reg, first, x);
}
}
}
/* Called via note_stores. If X is a pseudo that is narrower than
HOST_BITS_PER_WIDE_INT and is being set, record what bits are known zero.
If we are setting only a portion of X and we can't figure out what
portion, assume all bits will be used since we don't know what will
be happening.
Similarly, set how many bits of X are known to be copies of the sign bit
at all locations in the function. This is the smallest number implied
by any set of X. */
static void
set_nonzero_bits_and_sign_copies (rtx x, const_rtx set, void *data)
{
rtx insn = (rtx) data;
unsigned int num;
if (REG_P (x)
&& REGNO (x) >= FIRST_PSEUDO_REGISTER
/* If this register is undefined at the start of the file, we can't
say what its contents were. */
&& ! REGNO_REG_SET_P
(DF_LR_IN (ENTRY_BLOCK_PTR->next_bb), REGNO (x))
&& GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT)
{
reg_stat_type *rsp = VEC_index (reg_stat_type, reg_stat, REGNO (x));
if (set == 0 || GET_CODE (set) == CLOBBER)
{
rsp->nonzero_bits = GET_MODE_MASK (GET_MODE (x));
rsp->sign_bit_copies = 1;
return;
}
/* If this register is being initialized using itself, and the
register is uninitialized in this basic block, and there are
no LOG_LINKS which set the register, then part of the
register is uninitialized. In that case we can't assume
anything about the number of nonzero bits.
??? We could do better if we checked this in
reg_{nonzero_bits,num_sign_bit_copies}_for_combine. Then we
could avoid making assumptions about the insn which initially
sets the register, while still using the information in other
insns. We would have to be careful to check every insn
involved in the combination. */
if (insn
&& reg_referenced_p (x, PATTERN (insn))
&& !REGNO_REG_SET_P (DF_LR_IN (BLOCK_FOR_INSN (insn)),
REGNO (x)))
{
rtx link;
for (link = LOG_LINKS (insn); link; link = XEXP (link, 1))
{
if (dead_or_set_p (XEXP (link, 0), x))
break;
}
if (!link)
{
rsp->nonzero_bits = GET_MODE_MASK (GET_MODE (x));
rsp->sign_bit_copies = 1;
return;
}
}
/* If this is a complex assignment, see if we can convert it into a
simple assignment. */
set = expand_field_assignment (set);
/* If this is a simple assignment, or we have a paradoxical SUBREG,
set what we know about X. */
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 X is narrower than a word and SRC is a non-negative
constant that would appear negative in the mode of X,
sign-extend it for use in reg_stat[].nonzero_bits because some
machines (maybe most) will actually do the sign-extension
and this is the conservative approach.
??? For 2.5, try to tighten up the MD files in this regard
instead of this kludge. */
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
/* Don't call nonzero_bits if it cannot change anything. */
if (rsp->nonzero_bits != ~(unsigned HOST_WIDE_INT) 0)
rsp->nonzero_bits |= nonzero_bits (src, nonzero_bits_mode);
num = num_sign_bit_copies (SET_SRC (set), GET_MODE (x));
if (rsp->sign_bit_copies == 0
|| rsp->sign_bit_copies > num)
rsp->sign_bit_copies = num;
}
else
{
rsp->nonzero_bits = GET_MODE_MASK (GET_MODE (x));
rsp->sign_bit_copies = 1;
}
}
}
/* See if INSN can be combined into I3. PRED and SUCC are optionally
insns that were previously combined into I3 or that will be combined
into the merger of INSN and I3.
Return 0 if the combination is not allowed for any reason.
If the combination is allowed, *PDEST will be set to the single
destination of INSN and *PSRC to the single source, and this function
will return 1. */
static int
can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
rtx *pdest, rtx *psrc)
{
int i;
const_rtx set = 0;
rtx 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);
/* Can combine only if previous insn is a SET of a REG, a SUBREG or CC0.
or a PARALLEL consisting of such a SET and CLOBBERs.
If INSN has CLOBBER parallel parts, ignore them for our processing.
By definition, these happen during the execution of the insn. When it
is merged with another insn, all bets are off. If they are, in fact,
needed and aren't also supplied in I3, they may be added by
recog_for_combine. Otherwise, it won't match.
We can also ignore a SET whose SET_DEST is mentioned in a REG_UNUSED
note.
Get the source and destination of INSN. If more than one, can't
combine. */
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))
{
/* This is important to combine floating point insns
for the SH4 port. */
case USE:
/* Combining an isolated USE doesn't make sense.
We depend here on combinable_i3pat to reject them. */
/* The code below this loop only verifies that the inputs of
the SET in INSN do not change. We call reg_set_between_p
to verify that the REG in the USE does not change between
I3 and INSN.
If the USE in INSN was for a pseudo register, the matching
insn pattern will likely match any register; combining this
with any other USE would only be safe if we knew that the
used registers have identical values, or if there was
something to tell them apart, e.g. different modes. For
now, we forgo such complicated tests and simply disallow
combining of USES of pseudo registers with any other 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;
/* We can ignore CLOBBERs. */
case CLOBBER:
break;
case SET:
/* Ignore SETs whose result isn't used but not those that
have side-effects. */
if (find_reg_note (insn, REG_UNUSED, SET_DEST (elt))
&& (!(note = find_reg_note (insn, REG_EH_REGION, NULL_RTX))
|| INTVAL (XEXP (note, 0)) <= 0)
&& ! side_effects_p (elt))
break;
/* If we have already found a SET, this is a second one and
so we cannot combine with this insn. */
if (set)
return 0;
set = elt;
break;
default:
/* Anything else means we can't combine. */
return 0;
}
}
if (set == 0
/* If SET_SRC is an ASM_OPERANDS we can't throw away these CLOBBERs,
so don't do anything with it. */
|| 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);
/* Don't eliminate a store in the stack pointer. */
if (dest == stack_pointer_rtx
/* Don't combine with an insn that sets a register to itself if it has
a REG_EQUAL note. This may be part of a LIBCALL sequence. */
|| (rtx_equal_p (src, dest) && find_reg_note (insn, REG_EQUAL, NULL_RTX))
/* Can't merge an ASM_OPERANDS. */
|| GET_CODE (src) == ASM_OPERANDS
/* Can't merge a function call. */
|| GET_CODE (src) == CALL
/* Don't eliminate a function call argument. */
|| (CALL_P (i3)
&& (find_reg_fusage (i3, USE, dest)
|| (REG_P (dest)
&& REGNO (dest) < FIRST_PSEUDO_REGISTER
&& global_regs[REGNO (dest)])))
/* Don't substitute into an incremented register. */
|| FIND_REG_INC_NOTE (i3, dest)
|| (succ && FIND_REG_INC_NOTE (succ, dest))
/* Don't substitute into a non-local goto, this confuses CFG. */
|| (JUMP_P (i3) && find_reg_note (i3, REG_NON_LOCAL_GOTO, NULL_RTX))
/* Make sure that DEST is not used after SUCC but before I3. */
|| (succ && ! all_adjacent
&& reg_used_between_p (dest, succ, i3))
/* Make sure that the value that is to be substituted for the register
does not use any registers whose values alter in between. However,
If the insns are adjacent, a use can't cross a set even though we
think it might (this can happen for a sequence of insns each setting
the same destination; last_set of that register might point to
a NOTE). If INSN has a REG_EQUIV note, the register is always
equivalent to the memory so the substitution is valid even if there
are intervening stores. Also, don't move a volatile asm or
UNSPEC_VOLATILE across any other insns. */
|| (! all_adjacent
&& (((!MEM_P (src)
|| ! find_reg_note (insn, REG_EQUIV, src))
&& use_crosses_set_p (src, DF_INSN_LUID (insn)))
|| (GET_CODE (src) == ASM_OPERANDS && MEM_VOLATILE_P (src))
|| GET_CODE (src) == UNSPEC_VOLATILE))
/* Don't combine across a CALL_INSN, because that would possibly
change whether the life span of some REGs crosses calls or not,
and it is a pain to update that information.
Exception: if source is a constant, moving it later can't hurt.
Accept that as a special case. */
|| (DF_INSN_LUID (insn) < last_call_luid && ! CONSTANT_P (src)))
return 0;
/* DEST must either be a REG or CC0. */
if (REG_P (dest))
{
/* If register alignment is being enforced for multi-word items in all
cases except for parameters, it is possible to have a register copy
insn referencing a hard register that is not allowed to contain the
mode being copied and which would not be valid as an operand of most
insns. Eliminate this problem by not combining with such an insn.
Also, on some machines we don't want to extend the life of a hard
register. */
if (REG_P (src)
&& ((REGNO (dest) < FIRST_PSEUDO_REGISTER
&& ! HARD_REGNO_MODE_OK (REGNO (dest), GET_MODE (dest)))
/* Don't extend the life of a hard register unless it is
user variable (if we have few registers) or it can't
fit into the desired register (meaning something special
is going on).
Also avoid substituting a return register into I3, because
reload can't handle a conflict with constraints of other
inputs. */
|| (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)
{
/* Don't substitute for a register intended as a clobberable
operand. */
rtx reg = XEXP (XVECEXP (PATTERN (i3), 0, i), 0);
if (rtx_equal_p (reg, dest))
return 0;
/* If the clobber represents an earlyclobber operand, we must not
substitute an expression containing the clobbered register.
As we do not analyze the constraint strings here, we have to
make the conservative assumption. However, if the register is
a fixed hard reg, the clobber cannot represent any operand;
we leave it up to the machine description to either accept or
reject use-and-clobber patterns. */
if (!REG_P (reg)
|| REGNO (reg) >= FIRST_PSEUDO_REGISTER
|| !fixed_regs[REGNO (reg)])
if (reg_overlap_mentioned_p (reg, src))
return 0;
}
/* If INSN contains anything volatile, or is an `asm' (whether volatile
or not), reject, unless nothing volatile comes between it and I3 */
if (GET_CODE (src) == ASM_OPERANDS || volatile_refs_p (src))
{
/* Make sure succ doesn't contain a volatile reference. */
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 INSN is an asm, and DEST is a hard register, reject, since it has
to be an explicit register variable, and was chosen for a reason. */
if (GET_CODE (src) == ASM_OPERANDS
&& REG_P (dest) && REGNO (dest) < FIRST_PSEUDO_REGISTER)
return 0;
/* If there are any volatile insns between INSN and I3, reject, because
they might affect machine state. */
for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))
if (INSN_P (p) && p != succ && volatile_insn_p (PATTERN (p)))
return 0;
/* If INSN contains an autoincrement or autodecrement, make sure that
register is not used between there and I3, and not already used in
I3 either. Neither must it be used in PRED or SUCC, if they exist.
Also insist that I3 not be a jump; if it were one
and the incremented register were spilled, we would lose. */
#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
/* Don't combine an insn that follows a CC0-setting insn.
An insn that uses CC0 must not be separated from the one that sets it.
We do, however, allow I2 to follow a CC0-setting insn if that insn
is passed as I1; in that case it will be deleted also.
We also allow combining in this case if all the insns are adjacent
because that would leave the two CC0 insns adjacent as well.
It would be more logical to test whether CC0 occurs inside I1 or I2,
but that would be much slower, and this ought to be equivalent. */
p = prev_nonnote_insn (insn);
if (p && p != pred && NONJUMP_INSN_P (p) && sets_cc0_p (PATTERN (p))
&& ! all_adjacent)
return 0;
#endif
/* If we get here, we have passed all the tests and the combination is
to be allowed. */
*pdest = dest;
*psrc = src;
return 1;
}
/* LOC is the location within I3 that contains its pattern or the component
of a PARALLEL of the pattern. We validate that it is valid for combining.
One problem is if I3 modifies its output, as opposed to replacing it
entirely, we can't allow the output to contain I2DEST or I1DEST as doing
so would produce an insn that is not equivalent to the original insns.
Consider:
(set (reg:DI 101) (reg:DI 100))
(set (subreg:SI (reg:DI 101) 0) <foo>)
This is NOT equivalent to:
(parallel [(set (subreg:SI (reg:DI 100) 0) <foo>)
(set (reg:DI 101) (reg:DI 100))])
Not only does this modify 100 (in which case it might still be valid
if 100 were dead in I2), it sets 101 to the ORIGINAL value of 100.
We can also run into a problem if I2 sets a register that I1
uses and I1 gets directly substituted into I3 (not via I2). In that
case, we would be getting the wrong value of I2DEST into I3, so we
must reject the combination. This case occurs when I2 and I1 both
feed into I3, rather than when I1 feeds into I2, which feeds into I3.
If I1_NOT_IN_SRC is nonzero, it means that finding I1 in the source
of a SET must prevent combination from occurring.
Before doing the above check, we first try to expand a field assignment
into a set of logical operations.
If PI3_DEST_KILLED is nonzero, it is a pointer to a location in which
we place a register that is both set and used within I3. If more than one
such register is detected, we fail.
Return 1 if the combination is valid, zero otherwise. */
static int
combinable_i3pat (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;
rtx subdest;
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);
/* Check for the case where I3 modifies its output, as discussed
above. We don't want to prevent pseudos from being combined
into the address of a MEM, so only prevent the combination if
i1 or i2 set the same MEM. */
if ((inner_dest != dest &&
(!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))))
/* This is the same test done in can_combine_p except we can't test
all_adjacent; we don't have to, since this instruction will stay
in place, thus we are not considering increasing the lifetime of
INNER_DEST.
Also, if this insn sets a function argument, combining it with
something that might need a spill could clobber a previous
function argument; the all_adjacent test in can_combine_p also
checks this; here, we do a more specific test for this case. */
|| (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 DEST is used in I3, it is being killed in this insn, so
record that for later. We have to consider paradoxical
subregs here, since they kill the whole register, but we
ignore partial subregs, STRICT_LOW_PART, etc.
Never add REG_DEAD notes for the FRAME_POINTER_REGNUM or the
STACK_POINTER_REGNUM, since these are always considered to be
live. Similarly for ARG_POINTER_REGNUM if it is fixed. */
subdest = dest;
if (GET_CODE (subdest) == SUBREG
&& (GET_MODE_SIZE (GET_MODE (subdest))
>= GET_MODE_SIZE (GET_MODE (SUBREG_REG (subdest)))))
subdest = SUBREG_REG (subdest);
if (pi3dest_killed
&& REG_P (subdest)
&& reg_referenced_p (subdest, PATTERN (i3))
&& REGNO (subdest) != FRAME_POINTER_REGNUM
#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
&& REGNO (subdest) != HARD_FRAME_POINTER_REGNUM
#endif
#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
&& (REGNO (subdest) != ARG_POINTER_REGNUM
|| ! fixed_regs [REGNO (subdest)])
#endif
&& REGNO (subdest) != STACK_POINTER_REGNUM)
{
if (*pi3dest_killed)
return 0;
*pi3dest_killed = subdest;
}
}
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;
}
/* Return 1 if X is an arithmetic expression that contains a multiplication
and division. We don't count multiplications by powers of two here. */
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;
}
}
/* Determine whether INSN can be used in a combination. Return nonzero if
not. This is used in try_combine to detect early some cases where we
can't perform combinations. */
static int
cant_combine_insn_p (rtx insn)
{
rtx set;
rtx src, dest;
/* If this isn't really an insn, we can't do anything.
This can occur when flow deletes an insn that it has merged into an
auto-increment address. */
if (! INSN_P (insn))
return 1;
/* Never combine loads and stores involving hard regs that are likely
to be spilled. The register allocator can usually handle such
reg-reg moves by tying. If we allow the combiner to make
substitutions of likely-spilled regs, reload might die.
As an exception, we allow combinations involving fixed regs; these are
not available to the register allocator so there's no risk involved. */
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;
}
struct likely_spilled_retval_info
{
unsigned regno, nregs;
unsigned mask;
};
/* Called via note_stores by likely_spilled_retval_p. Remove from info->mask
hard registers that are known to be written to / clobbered in full. */
static void
likely_spilled_retval_1 (rtx x, const_rtx set, void *data)
{
struct likely_spilled_retval_info *const info =
(struct likely_spilled_retval_info *) data;
unsigned regno, nregs;
unsigned new_mask;
if (!REG_P (XEXP (set, 0)))
return;
regno = REGNO (x);
if (regno >= info->regno + info->nregs)
return;
nregs = hard_regno_nregs[regno][GET_MODE (x)];
if (regno + nregs <= info->regno)
return;
new_mask = (2U << (nregs - 1)) - 1;
if (regno < info->regno)
new_mask >>= info->regno - regno;
else
new_mask <<= regno - info->regno;
info->mask &= ~new_mask;
}
/* Return nonzero iff part of the return value is live during INSN, and
it is likely spilled. This can happen when more than one insn is needed
to copy the return value, e.g. when we consider to combine into the
second copy insn for a complex value. */
static int
likely_spilled_retval_p (rtx insn)
{
rtx use = BB_END (this_basic_block);
rtx reg, p;
unsigned regno, nregs;
/* We assume here that no machine mode needs more than
32 hard registers when the value overlaps with a register
for which FUNCTION_VALUE_REGNO_P is true. */
unsigned mask;
struct likely_spilled_retval_info info;
if (!NONJUMP_INSN_P (use) || GET_CODE (PATTERN (use)) != USE || insn == use)
return 0;
reg = XEXP (PATTERN (use), 0);
if (!REG_P (reg) || !FUNCTION_VALUE_REGNO_P (REGNO (reg)))
return 0;
regno = REGNO (reg);
nregs = hard_regno_nregs[regno][GET_MODE (reg)];
if (nregs == 1)
return 0;
mask = (2U << (nregs - 1)) - 1;
/* Disregard parts of the return value that are set later. */
info.regno = regno;
info.nregs = nregs;
info.mask = mask;
for (p = PREV_INSN (use); info.mask && p != insn; p = PREV_INSN (p))
if (INSN_P (p))
note_stores (PATTERN (p), likely_spilled_retval_1, &info);
mask = info.mask;
/* Check if any of the (probably) live return value registers is
likely spilled. */
nregs --;
do
{
if ((mask & 1 << nregs)
&& CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (regno + nregs)))
return 1;
} while (nregs--);
return 0;
}
/* Adjust INSN after we made a change to its destination.
Changing the destination can invalidate notes that say something about
the results of the insn and a LOG_LINK pointing to the insn. */
static void
adjust_for_new_dest (rtx insn)
{
/* For notes, be conservative and simply remove them. */
remove_reg_equal_equiv_notes (insn);
/* The new insn will have a destination that was previously the destination
of an insn just above it. Call distribute_links to make a LOG_LINK from
the next use of that destination. */
distribute_links (gen_rtx_INSN_LIST (VOIDmode, insn, NULL_RTX));
df_insn_rescan (insn);
}
/* Return TRUE if combine can reuse reg X in mode MODE.
ADDED_SETS is nonzero if the original set is still required. */
static bool
can_change_dest_mode (rtx x, int added_sets, enum machine_mode mode)
{
unsigned int regno;
if (!REG_P(x))
return false;
regno = REGNO (x);
/* Allow hard registers if the new mode is legal, and occupies no more
registers than the old mode. */
if (regno < FIRST_PSEUDO_REGISTER)
return (HARD_REGNO_MODE_OK (regno, mode)
&& (hard_regno_nregs[regno][GET_MODE (x)]
>= hard_regno_nregs[regno][mode]));
/* Or a pseudo that is only used once. */
return (REG_N_SETS (regno) == 1 && !added_sets
&& !REG_USERVAR_P (x));
}
/* Check whether X, the destination of a set, refers to part of
the register specified by REG. */
static bool
reg_subword_p (rtx x, rtx reg)
{
/* Check that reg is an integer mode register. */
if (!REG_P (reg) || GET_MODE_CLASS (GET_MODE (reg)) != MODE_INT)
return false;
if (GET_CODE (x) == STRICT_LOW_PART
|| GET_CODE (x) == ZERO_EXTRACT)
x = XEXP (x, 0);
return GET_CODE (x) == SUBREG
&& SUBREG_REG (x) == reg
&& GET_MODE_CLASS (GET_MODE (x)) == MODE_INT;
}
/* Try to combine the insns I1 and I2 into I3.
Here I1 and I2 appear earlier than I3.
I1 can be zero; then we combine just I2 into I3.
If we are combining three insns and the resulting insn is not recognized,
try splitting it into two insns. If that happens, I2 and I3 are retained
and I1 is pseudo-deleted by turning it into a NOTE. Otherwise, I1 and I2
are pseudo-deleted.
Return 0 if the combination does not work. Then nothing is changed.
If we did the combination, return the insn at which combine should
resume scanning.
Set NEW_DIRECT_JUMP_P to a nonzero value if try_combine creates a
new direct jump instruction. */
static rtx
try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
{
/* New patterns for I3 and I2, respectively. */
rtx newpat, newi2pat = 0;
rtvec newpat_vec_with_clobbers = 0;
int substed_i2 = 0, substed_i1 = 0;
/* Indicates need to preserve SET in I1 or I2 in I3 if it is not dead. */
int added_sets_1, added_sets_2;
/* Total number of SETs to put into I3. */
int total_sets;
/* Nonzero if I2's body now appears in I3. */
int i2_is_used;
/* INSN_CODEs for new I3, new I2, and user of condition code. */
int insn_code_number, i2_code_number = 0, other_code_number = 0;
/* Contains I3 if the destination of I3 is used in its source, which means
that the old life of I3 is being killed. If that usage is placed into
I2 and not in I3, a REG_DEAD note must be made. */
rtx i3dest_killed = 0;
/* SET_DEST and SET_SRC of I2 and I1. */
rtx i2dest, i2src, i1dest = 0, i1src = 0;
/* PATTERN (I1) and PATTERN (I2), or a copy of it in certain cases. */
rtx i1pat = 0, i2pat = 0;
/* Indicates if I2DEST or I1DEST is in I2SRC or I1_SRC. */
int i2dest_in_i2src = 0, i1dest_in_i1src = 0, i2dest_in_i1src = 0;
int i2dest_killed = 0, i1dest_killed = 0;
int i1_feeds_i3 = 0;
/* Notes that must be added to REG_NOTES in I3 and I2. */
rtx new_i3_notes, new_i2_notes;
/* Notes that we substituted I3 into I2 instead of the normal case. */
int i3_subst_into_i2 = 0;
/* Notes that I1, I2 or I3 is a MULT operation. */
int have_mult = 0;
int swap_i2i3 = 0;
int changed_i3_dest = 0;
int maxreg;
rtx temp;
rtx link;
rtx other_pat = 0;
rtx new_other_notes;
int i;
/* Exit early if one of the insns involved can't be used for
combinations. */
if (cant_combine_insn_p (i3)
|| cant_combine_insn_p (i2)
|| (i1 && cant_combine_insn_p (i1))
|| likely_spilled_retval_p (i3))
return 0;
combine_attempts++;
undobuf.other_insn = 0;
/* Reset the hard register usage information. */
CLEAR_HARD_REG_SET (newpat_used_regs);
/* If I1 and I2 both feed I3, they can be in any order. To simplify the
code below, set I1 to be the earlier of the two insns. */
if (i1 && DF_INSN_LUID (i1) > DF_INSN_LUID (i2))
temp = i1, i1 = i2, i2 = temp;
added_links_insn = 0;
/* First check for one important special-case that the code below will
not handle. Namely, the case where I1 is zero, I2 is a PARALLEL
and I3 is a SET whose SET_SRC is a SET_DEST in I2. In that case,
we may be able to replace that destination with the destination of I3.
This occurs in the common code where we compute both a quotient and
remainder into a structure, in which case we want to do the computation
directly into the structure to avoid register-register copies.
Note that this case handles both multiple sets in I2 and also
cases where I2 has a number of CLOBBER or PARALLELs.
We make very conservative checks below and only try to handle the
most common cases of this. For example, we only handle the case
where I2 and I3 are adjacent to avoid making difficult register
usage tests. */
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)))
/* If the dest of I3 is a ZERO_EXTRACT or STRICT_LOW_PART, the code
below would need to check what is inside (and reg_overlap_mentioned_p
doesn't support those codes anyway). Don't allow those destinations;
the resulting insn isn't likely to be recognized anyway. */
&& 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);
/* Make sure that the destination of I3,
which we are going to substitute into one output of I2,
is not used within another output of I2. We must avoid making this:
(parallel [(set (mem (reg 69)) ...)
(set (reg 69) ...)])
which is not well-defined as to order of actions.
(Besides, reload can't handle output reloads for this.)
The problem can also happen if the dest of I3 is a memory ref,
if another dest in I2 is an indirect memory ref. */
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_luid = DF_INSN_LUID (i2);
added_sets_2 = added_sets_1 = 0;
i2dest = SET_SRC (PATTERN (i3));
i2dest_killed = dead_or_set_p (i2, i2dest);
/* Replace the dest in I2 with our dest and make the resulting
insn the new pattern for I3. Then skip to where we
validate the pattern. Everything was set up above. */
SUBST (SET_DEST (XVECEXP (p2, 0, i)),
SET_DEST (PATTERN (i3)));
newpat = p2;
i3_subst_into_i2 = 1;
goto validate_replacement;
}
}
/* If I2 is setting a pseudo to a constant and I3 is setting some
sub-part of it to another constant, merge them by making a new
constant. */
if (i1 == 0
&& (temp = single_set (i2)) != 0
&& (GET_CODE (SET_SRC (temp)) == CONST_INT
|| GET_CODE (SET_SRC (temp)) == CONST_DOUBLE)
&& GET_CODE (PATTERN (i3)) == SET
&& (GET_CODE (SET_SRC (PATTERN (i3))) == CONST_INT
|| GET_CODE (SET_SRC (PATTERN (i3))) == CONST_DOUBLE)
&& reg_subword_p (SET_DEST (PATTERN (i3)), SET_DEST (temp)))
{
rtx dest = SET_DEST (PATTERN (i3));
int offset = -1;
int width = 0;
if (GET_CODE (dest) == ZERO_EXTRACT)
{
if (GET_CODE (XEXP (dest, 1)) == CONST_INT
&& GET_CODE (XEXP (dest, 2)) == CONST_INT)
{
width = INTVAL (XEXP (dest, 1));
offset = INTVAL (XEXP (dest, 2));
dest = XEXP (dest, 0);
if (BITS_BIG_ENDIAN)
offset = GET_MODE_BITSIZE (GET_MODE (dest)) - width - offset;
}
}
else
{
if (GET_CODE (dest) == STRICT_LOW_PART)
dest = XEXP (dest, 0);
width = GET_MODE_BITSIZE (GET_MODE (dest));
offset = 0;
}
if (offset >= 0)
{
/* If this is the low part, we're done. */
if (subreg_lowpart_p (dest))
;
/* Handle the case where inner is twice the size of outer. */
else if (GET_MODE_BITSIZE (GET_MODE (SET_DEST (temp)))
== 2 * GET_MODE_BITSIZE (GET_MODE (dest)))
offset += GET_MODE_BITSIZE (GET_MODE (dest));
/* Otherwise give up for now. */
else
offset = -1;
}
if (offset >= 0
&& (GET_MODE_BITSIZE (GET_MODE (SET_DEST (temp)))
<= HOST_BITS_PER_WIDE_INT * 2))
{
HOST_WIDE_INT mhi, ohi, ihi;
HOST_WIDE_INT mlo, olo, ilo;
rtx inner = SET_SRC (PATTERN (i3));
rtx outer = SET_SRC (temp);
if (GET_CODE (outer) == CONST_INT)
{
olo = INTVAL (outer);
ohi = olo < 0 ? -1 : 0;
}
else
{
olo = CONST_DOUBLE_LOW (outer);
ohi = CONST_DOUBLE_HIGH (outer);
}
if (GET_CODE (inner) == CONST_INT)
{
ilo = INTVAL (inner);
ihi = ilo < 0 ? -1 : 0;
}
else
{
ilo = CONST_DOUBLE_LOW (inner);
ihi = CONST_DOUBLE_HIGH (inner);
}
if (width < HOST_BITS_PER_WIDE_INT)
{
mlo = ((unsigned HOST_WIDE_INT) 1 << width) - 1;
mhi = 0;
}
else if (width < HOST_BITS_PER_WIDE_INT * 2)
{
mhi = ((unsigned HOST_WIDE_INT) 1
<< (width - HOST_BITS_PER_WIDE_INT)) - 1;
mlo = -1;
}
else
{
mlo = -1;
mhi = -1;
}
ilo &= mlo;
ihi &= mhi;
if (offset >= HOST_BITS_PER_WIDE_INT)
{
mhi = mlo << (offset - HOST_BITS_PER_WIDE_INT);
mlo = 0;
ihi = ilo << (offset - HOST_BITS_PER_WIDE_INT);
ilo = 0;
}
else if (offset > 0)
{
mhi = (mhi << offset) | ((unsigned HOST_WIDE_INT) mlo
>> (HOST_BITS_PER_WIDE_INT - offset));
mlo = mlo << offset;
ihi = (ihi << offset) | ((unsigned HOST_WIDE_INT) ilo
>> (HOST_BITS_PER_WIDE_INT - offset));
ilo = ilo << offset;
}
olo = (olo & ~mlo) | ilo;
ohi = (ohi & ~mhi) | ihi;
combine_merges++;
subst_insn = i3;
subst_low_luid = DF_INSN_LUID (i2);
added_sets_2 = added_sets_1 = 0;
i2dest = SET_DEST (temp);
i2dest_killed = dead_or_set_p (i2, i2dest);
/* Replace the source in I2 with the new constant and make the
resulting insn the new pattern for I3. Then skip to
where we validate the pattern. Everything was set up above. */
SUBST (SET_SRC (temp),
immed_double_const (olo, ohi, GET_MODE (SET_DEST (temp))));
newpat = PATTERN (i2);
/* The dest of I3 has been replaced with the dest of I2. */
changed_i3_dest = 1;
goto validate_replacement;
}
}
#ifndef HAVE_cc0
/* If we have no I1 and I2 looks like:
(parallel [(set (reg:CC X) (compare:CC OP (const_int 0)))
(set Y OP)])
make up a dummy I1 that is
(set Y OP)
and change I2 to be
(set (reg:CC X) (compare:CC Y (const_int 0)))
(We can ignore any trailing CLOBBERs.)
This undoes a previous combination and allows us to match a branch-and-
decrement insn. */
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)
{
/* We make I1 with the same INSN_UID as I2. This gives it
the same DF_INSN_LUID for value tracking. Our fake I1 will
never appear in the insn stream so giving it the same INSN_UID
as I2 will not cause a problem. */
i1 = gen_rtx_INSN (VOIDmode, INSN_UID (i2), NULL_RTX, i2,
BLOCK_FOR_INSN (i2), INSN_LOCATOR (i2),
XVECEXP (PATTERN (i2), 0, 1), -1, NULL_RTX);
SUBST (PATTERN (i2), XVECEXP (PATTERN (i2), 0, 0));
SUBST (XEXP (SET_SRC (PATTERN (i2)), 0),
SET_DEST (PATTERN (i1)));
}
}
#endif
/* Verify that I2 and I1 are valid for combining. */
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;
}
/* Record whether I2DEST is used in I2SRC and similarly for the other
cases. Knowing this will help in register status updating below. */
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);
i2dest_killed = dead_or_set_p (i2, i2dest);
i1dest_killed = i1 && dead_or_set_p (i1, i1dest);
/* See if I1 directly feeds into I3. It does if I1DEST is not used
in I2SRC. */
i1_feeds_i3 = i1 && ! reg_overlap_mentioned_p (i1dest, i2src);
/* Ensure that I3's pattern can be the destination of combines. */
if (! combinable_i3pat (i3, &PATTERN (i3), i2dest, i1dest,
i1 && i2dest_in_i1src && i1_feeds_i3,
&i3dest_killed))
{
undo_all ();
return 0;
}
/* See if any of the insns is a MULT operation. Unless one is, we will
reject a combination that is, since it must be slower. Be conservative
here. */
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 I3 has an inc, then give up if I1 or I2 uses the reg that is inc'd.
We used to do this EXCEPT in one case: I3 has a post-inc in an
output operand. However, that exception can give rise to insns like
mov r3,(r3)+
which is a famous insn on the PDP-11 where the value of r3 used as the
source was model-dependent. Avoid this sort of thing. */
#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)))
/* It's not the exception. */
#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
/* See if the SETs in I1 or I2 need to be kept around in the merged
instruction: whenever the value set there is still needed past I3.
For the SETs in I2, this is easy: we see if I2DEST dies or is set in I3.
For the SET in I1, we have two cases: If I1 and I2 independently
feed into I3, the set in I1 needs to be kept around if I1DEST dies
or is set in I3. Otherwise (if I1 feeds I2 which feeds I3), the set
in I1 needs to be kept around unless I1DEST dies or is set in either
I2 or I3. We can distinguish these cases by seeing if I2SRC mentions
I1DEST. If so, we know I1 feeds into I2. */
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)));
/* If the set in I2 needs to be kept around, we must make a copy of
PATTERN (I2), so that when we substitute I1SRC for I1DEST in
PATTERN (I2), we are only substituting for the original I1DEST, not into
an already-substituted copy. This also prevents making self-referential
rtx. If I2 is a PARALLEL, we just need the piece that assigns I2SRC to
I2DEST. */
if (added_sets_2)
{
if (GET_CODE (PATTERN (i2)) == PARALLEL)
i2pat = gen_rtx_SET (VOIDmode, i2dest, copy_rtx (i2src));
else
i2pat = copy_rtx (PATTERN (i2));
}
if (added_sets_1)
{
if (GET_CODE (PATTERN (i1)) == PARALLEL)
i1pat = gen_rtx_SET (VOIDmode, i1dest, copy_rtx (i1src));
else
i1pat = copy_rtx (PATTERN (i1));
}
combine_merges++;
/* Substitute in the latest insn for the regs set by the earlier ones. */
maxreg = max_reg_num ();
subst_insn = i3;
#ifndef HAVE_cc0
/* Many machines that don't use CC0 have insns that can both perform an
arithmetic operation and set the condition code. These operations will
be represented as a PARALLEL with the first element of the vector
being a COMPARE of an arithmetic operation with the constant zero.
The second element of the vector will set some pseudo to the result
of the same arithmetic operation. If we simplify the COMPARE, we won't
match such a pattern and so will generate an extra insn. Here we test
for this case, where both the comparison and the operation result are
needed, and make the PARALLEL by just replacing I2DEST in I3SRC with
I2SRC. Later we will make the PARALLEL that contains I2. */
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
/* See if a COMPARE with the operand we substituted in should be done
with the mode that is currently being used. If not, do the same
processing we do in `subst' for a SET; namely, if the destination
is used only once, try to replace it with a register of the proper
mode and also replace the COMPARE. */
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))))
{
if (can_change_dest_mode(SET_DEST (newpat), added_sets_2,
compare_mode))
{
unsigned int regno = REGNO (SET_DEST (newpat));
rtx new_dest;
if (regno < FIRST_PSEUDO_REGISTER)
new_dest = gen_rtx_REG (compare_mode, regno);
else
{
SUBST_MODE (regno_reg_rtx[regno], compare_mode);
new_dest = regno_reg_rtx[regno];
}
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
{
/* It is possible that the source of I2 or I1 may be performing
an unneeded operation, such as a ZERO_EXTEND of something
that is known to have the high part zero. Handle that case
by letting subst look at the innermost one of them.
Another way to do this would be to have a function that tries
to simplify a single insn instead of merging two or more
insns. We don't do this because of the potential of infinite
loops and because of the potential extra memory required.
However, doing it the way we are is a bit of a kludge and
doesn't catch all cases.
But only do this if -fexpensive-optimizations since it slows
things down and doesn't usually win.
This is not done in the COMPARE case above because the
unmodified I2PAT is used in the PARALLEL and so a pattern
with a modified I2SRC would not match. */
if (flag_expensive_optimizations)
{
/* Pass pc_rtx so no substitutions are done, just
simplifications. */
if (i1)
{
subst_low_luid = DF_INSN_LUID (i1);
i1src = subst (i1src, pc_rtx, pc_rtx, 0, 0);
}
else
{
subst_low_luid = DF_INSN_LUID (i2);
i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0);
}
}
n_occurrences = 0; /* `subst' counts here */
/* If I1 feeds into I2 (not into I3) and I1DEST is in I1SRC, we
need to make a unique copy of I2SRC each time we substitute it
to avoid self-referential rtl. */
subst_low_luid = DF_INSN_LUID (i2);
newpat = subst (PATTERN (i3), i2dest, i2src, 0,
! i1_feeds_i3 && i1dest_in_i1src);
substed_i2 = 1;
/* Record whether i2's body now appears within i3's body. */
i2_is_used = n_occurrences;
}
/* If we already got a failure, don't try to do more. Otherwise,
try to substitute in I1 if we have it. */
if (i1 && GET_CODE (newpat) != CLOBBER)
{
/* Check that an autoincrement side-effect on I1 has not been lost.
This happens if I1DEST is mentioned in I2 and dies there, and
has disappeared from the new pattern. */
if ((FIND_REG_INC_NOTE (i1, NULL_RTX) != 0
&& !i1_feeds_i3
&& dead_or_set_p (i2, i1dest)
&& !reg_overlap_mentioned_p (i1dest, newpat))
/* Before we can do this substitution, we must redo the test done
above (see detailed comments there) that ensures that I1DEST
isn't mentioned in any SETs in NEWPAT that are field assignments. */
|| !combinable_i3pat (NULL_RTX, &newpat, i1dest, NULL_RTX, 0, 0))
{
undo_all ();
return 0;
}
n_occurrences = 0;
subst_low_luid = DF_INSN_LUID (i1);
newpat = subst (newpat, i1dest, i1src, 0, 0);
substed_i1 = 1;
}
/* Fail if an autoincrement side-effect has been duplicated. Be careful
to count all the ways that I2SRC and I1SRC can be used. */
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))
/* Fail if we tried to make a new register. */
|| max_reg_num () != maxreg
/* Fail if we couldn't do something and have a CLOBBER. */
|| GET_CODE (newpat) == CLOBBER
/* Fail if this new pattern is a MULT and we didn't have one before
at the outer level. */
|| (GET_CODE (newpat) == SET && GET_CODE (SET_SRC (newpat)) == MULT
&& ! have_mult))
{
undo_all ();
return 0;
}
/* If the actions of the earlier insns must be kept
in addition to substituting them into the latest one,
we must make a new PARALLEL for the latest insn
to hold additional the SETs. */
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) = i1pat;
if (added_sets_2)
{
/* If there is no I1, use I2's body as is. We used to also not do
the subst call below if I2 was substituted into I3,
but that could lose a simplification. */
if (i1 == 0)
XVECEXP (newpat, 0, --total_sets) = i2pat;
else
/* See comment where i2pat is assigned. */
XVECEXP (newpat, 0, --total_sets)
= subst (i2pat, i1dest, i1src, 0, 0);
}
}
validate_replacement:
/* Note which hard regs this insn has as inputs. */
mark_used_regs_combine (newpat);
/* If recog_for_combine fails, it strips existing clobbers. If we'll
consider splitting this pattern, we might need these clobbers. */
if (i1 && GET_CODE (newpat) == PARALLEL
&& GET_CODE (XVECEXP (newpat, 0, XVECLEN (newpat, 0) - 1)) == CLOBBER)
{
int len = XVECLEN (newpat, 0);
newpat_vec_with_clobbers = rtvec_alloc (len);
for (i = 0; i < len; i++)
RTVEC_ELT (newpat_vec_with_clobbers, i) = XVECEXP (newpat, 0, i);
}
/* Is the result of combination a valid instruction? */
insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
/* If the result isn't valid, see if it is a PARALLEL of two SETs where
the second SET's destination is a register that is unused and isn't
marked as an instruction that might trap in an EH region. In that case,
we just need the first SET. This can occur when simplifying a divmod
insn. We *must* test for this case here because the code below that
splits two independent SETs doesn't handle this case correctly when it
updates the register status.
It's pointless doing this if we originally had two sets, one from
i3, and one from i2. Combining then splitting the parallel results
in the original i2 again plus an invalid insn (which we delete).
The net effect is only to move instructions around, which makes
debug info less accurate.
Also check the case where the first SET's destination is unused.
That would not cause incorrect code, but does cause an unneeded
insn to remain. */
if (insn_code_number < 0
&& !(added_sets_2 && i1 == 0)
&& GET_CODE (newpat) == PARALLEL
&& XVECLEN (newpat, 0) == 2
&& GET_CODE (XVECEXP (newpat, 0, 0)) == SET
&& GET_CODE (XVECEXP (newpat, 0, 1)) == SET
&& 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)
changed_i3_dest = 1;
}
}
/* If we were combining three insns and the result is a simple SET
with no ASM_OPERANDS that wasn't recognized, try to split it into two
insns. There are two ways to do this. It can be split using a
machine-specific method (like when you have an addition of a large
constant) or by combine in the function find_split_point. */
if (i1 && insn_code_number < 0 && GET_CODE (newpat) == SET
&& asm_noperands (newpat) < 0)
{
rtx parallel, m_split, *split;
/* See if the MD file can split NEWPAT. If it can't, see if letting it
use I2DEST as a scratch register will help. In the latter case,
convert I2DEST to the mode of the source of NEWPAT if we can. */
m_split = combine_split_insns (newpat, i3);
/* We can only use I2DEST as a scratch reg if it doesn't overlap any
inputs of NEWPAT. */
/* ??? If I2DEST is not safe, and I1DEST exists, then it would be
possible to try that as a scratch reg. This would require adding
more code to make it work though. */
if (m_split == 0 && ! reg_overlap_mentioned_p (i2dest, newpat))
{
enum machine_mode new_mode = GET_MODE (SET_DEST (newpat));
/* First try to split using the original register as a
scratch register. */
parallel = gen_rtx_PARALLEL (VOIDmode,
gen_rtvec (2, newpat,
gen_rtx_CLOBBER (VOIDmode,
i2dest)));
m_split = combine_split_insns (parallel, i3);
/* If that didn't work, try changing the mode of I2DEST if
we can. */
if (m_split == 0
&& new_mode != GET_MODE (i2dest)
&& new_mode != VOIDmode
&& can_change_dest_mode (i2dest, added_sets_2, new_mode))
{
enum machine_mode old_mode = GET_MODE (i2dest);
rtx ni2dest;
if (REGNO (i2dest) < FIRST_PSEUDO_REGISTER)
ni2dest = gen_rtx_REG (new_mode, REGNO (i2dest));
else
{
SUBST_MODE (regno_reg_rtx[REGNO (i2dest)], new_mode);
ni2dest = regno_reg_rtx[REGNO (i2dest)];
}
parallel = (gen_rtx_PARALLEL
(VOIDmode,
gen_rtvec (2, newpat,
gen_rtx_CLOBBER (VOIDmode,
ni2dest))));
m_split = combine_split_insns (parallel, i3);
if (m_split == 0
&& REGNO (i2dest) >= FIRST_PSEUDO_REGISTER)
{
struct undo *buf;
adjust_reg_mode (regno_reg_rtx[REGNO (i2dest)], old_mode);
buf = undobuf.undos;
undobuf.undos = buf->next;
buf->next = undobuf.frees;
undobuf.frees = buf;
}
}
}
/* If recog_for_combine has discarded clobbers, try to use them
again for the split. */
if (m_split == 0 && newpat_vec_with_clobbers)
{
parallel = gen_rtx_PARALLEL (VOIDmode, newpat_vec_with_clobbers);
m_split = combine_split_insns (parallel, i3);
}
if (m_split && NEXT_INSN (m_split) == NULL_RTX)
{
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), DF_INSN_LUID (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);
i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
/* If I2 or I3 has multiple SETs, we won't know how to track
register status, so don't use these insns. If I2's destination
is used between I2 and I3, we also can't use these insns. */
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;
/* It is possible that both insns now set the destination of I3.
If so, we must show an extra use of it. */
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))
INC_REG_N_SETS (REGNO (new_i2_dest), 1);
}
}
/* If we can split it and use I2DEST, go ahead and see if that
helps things be recognized. Verify that none of the registers
are set between I2 and I3. */
if (insn_code_number < 0 && (split = find_split_point (&newpat, i3)) != 0
#ifdef HAVE_cc0
&& REG_P (i2dest)
#endif
/* We need I2DEST in the proper mode. If it is a hard register
or the only use of a pseudo, we can change its mode.
Make sure we don't change a hard register to have a mode that
isn't valid for it, or change the number of registers. */
&& (GET_MODE (*split) == GET_MODE (i2dest)
|| GET_MODE (*split) == VOIDmode
|| can_change_dest_mode (i2dest, added_sets_2,
GET_MODE (*split)))
&& (next_real_insn (i2) == i3
|| ! use_crosses_set_p (*split, DF_INSN_LUID (i2)))
/* We can't overwrite I2DEST if its value is still used by
NEWPAT. */
&& ! reg_referenced_p (i2dest, newpat))
{
rtx newdest = i2dest;
enum rtx_code split_code = GET_CODE (*split);
enum machine_mode split_mode = GET_MODE (*split);
bool subst_done = false;
newi2pat = NULL_RTX;
/* Get NEWDEST as a register in the proper mode. We have already
validated that we can do this. */
if (GET_MODE (i2dest) != split_mode && split_mode != VOIDmode)
{
if (REGNO (i2dest) < FIRST_PSEUDO_REGISTER)
newdest = gen_rtx_REG (split_mode, REGNO (i2dest));
else
{
SUBST_MODE (regno_reg_rtx[REGNO (i2dest)], split_mode);
newdest = regno_reg_rtx[REGNO (i2dest)];
}
}
/* If *SPLIT is a (mult FOO (const_int pow2)), convert it to
an ASHIFT. This can occur if it was inside a PLUS and hence
appeared to be a memory address. This is a kludge. */
if (split_code == MULT
&& GET_CODE (XEXP (*split, 1)) == CONST_INT
&& 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)));
/* Update split_code because we may not have a multiply
anymore. */
split_code = GET_CODE (*split);
}
#ifdef INSN_SCHEDULING
/* If *SPLIT is a paradoxical SUBREG, when we split it, it should
be written as a ZERO_EXTEND. */
if (split_code == SUBREG && MEM_P (SUBREG_REG (*split)))
{
#ifdef LOAD_EXTEND_OP
/* Or as a SIGN_EXTEND if LOAD_EXTEND_OP says that that's
what it really is. */
if (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (*split)))
== SIGN_EXTEND)
SUBST (*split, gen_rtx_SIGN_EXTEND (split_mode,
SUBREG_REG (*split)));
else
#endif
SUBST (*split, gen_rtx_ZERO_EXTEND (split_mode,
SUBREG_REG (*split)));
}
#endif
/* Attempt to split binary operators using arithmetic identities. */
if (BINARY_P (SET_SRC (newpat))
&& split_mode == GET_MODE (SET_SRC (newpat))
&& ! side_effects_p (SET_SRC (newpat)))
{
rtx setsrc = SET_SRC (newpat);
enum machine_mode mode = GET_MODE (setsrc);
enum rtx_code code = GET_CODE (setsrc);
rtx src_op0 = XEXP (setsrc, 0);
rtx src_op1 = XEXP (setsrc, 1);
/* Split "X = Y op Y" as "Z = Y; X = Z op Z". */
if (rtx_equal_p (src_op0, src_op1))
{
newi2pat = gen_rtx_SET (VOIDmode, newdest, src_op0);
SUBST (XEXP (setsrc, 0), newdest);
SUBST (XEXP (setsrc, 1), newdest);
subst_done = true;
}
/* Split "((P op Q) op R) op S" where op is PLUS or MULT. */
else if ((code == PLUS || code == MULT)
&& GET_CODE (src_op0) == code
&& GET_CODE (XEXP (src_op0, 0)) == code
&& (INTEGRAL_MODE_P (mode)
|| (FLOAT_MODE_P (mode)
&& flag_unsafe_math_optimizations)))
{
rtx p = XEXP (XEXP (src_op0, 0), 0);
rtx q = XEXP (XEXP (src_op0, 0), 1);
rtx r = XEXP (src_op0, 1);
rtx s = src_op1;
/* Split both "((X op Y) op X) op Y" and
"((X op Y) op Y) op X" as "T op T" where T is
"X op Y". */
if ((rtx_equal_p (p,r) && rtx_equal_p (q,s))
|| (rtx_equal_p (p,s) && rtx_equal_p (q,r)))
{
newi2pat = gen_rtx_SET (VOIDmode, newdest,
XEXP (src_op0, 0));
SUBST (XEXP (setsrc, 0), newdest);
SUBST (XEXP (setsrc, 1), newdest);
subst_done = true;
}
/* Split "((X op X) op Y) op Y)" as "T op T" where
T is "X op Y". */
else if (rtx_equal_p (p,q) && rtx_equal_p (r,s))
{
rtx tmp = simplify_gen_binary (code, mode, p, r);
newi2pat = gen_rtx_SET (VOIDmode, newdest, tmp);
SUBST (XEXP (setsrc, 0), newdest);
SUBST (XEXP (setsrc, 1), newdest);
subst_done = true;
}
}
}
if (!subst_done)
{
newi2pat = gen_rtx_SET (VOIDmode, newdest, *split);
SUBST (*split, newdest);
}
i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
/* recog_for_combine might have added CLOBBERs to newi2pat.
Make sure NEWPAT does not depend on the clobbered regs. */
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 the split point was a MULT and we didn't have one before,
don't use one now. */
if (i2_code_number >= 0 && ! (split_code == MULT && ! have_mult))
insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
}
}
/* Check for a case where we loaded from memory in a narrow mode and
then sign extended it, but we need both registers. In that case,
we have a PARALLEL with both loads from the same memory location.
We can split this into a load from memory followed by a register-register
copy. This saves at least one insn, more if register allocation can
eliminate the copy.
We cannot do this if the destination of the first assignment is a
condition code register or cc0. We eliminate this case by making sure
the SET_DEST and SET_SRC have the same mode.
We cannot do this if the destination of the second assignment is
a register that we have already assumed is zero-extended. Similarly
for a SUBREG of such a register. */
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)),
DF_INSN_LUID (i2))
&& GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != ZERO_EXTRACT
&& GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != STRICT_LOW_PART
&& ! (temp = SET_DEST (XVECEXP (newpat, 0, 1)),
(REG_P (temp)
&& VEC_index (reg_stat_type, reg_stat,
REGNO (temp))->nonzero_bits != 0
&& GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD
&& GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT
&& (VEC_index (reg_stat_type, reg_stat,
REGNO (temp))->nonzero_bits
!= GET_MODE_MASK (word_mode))))
&& ! (GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) == SUBREG
&& (temp = SUBREG_REG (SET_DEST (XVECEXP (newpat, 0, 1))),
(REG_P (temp)
&& VEC_index (reg_stat_type, reg_stat,
REGNO (temp))->nonzero_bits != 0
&& GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD
&& GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT
&& (VEC_index (reg_stat_type, reg_stat,
REGNO (temp))->nonzero_bits
!= GET_MODE_MASK (word_mode)))))
&& ! reg_overlap_mentioned_p (SET_DEST (XVECEXP (newpat, 0, 1)),
SET_SRC (XVECEXP (newpat, 0, 1)))
&& ! 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;
}
/* Similarly, check for a case where we have a PARALLEL of two independent
SETs but we started with three insns. In this case, we can do the sets
as two separate insns. This case occurs when some SET allows two
other insns to combine, but the destination of that SET is still live. */
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)),
DF_INSN_LUID (i2))
&& ! reg_referenced_p (SET_DEST (XVECEXP (newpat, 0, 1)),
XVECEXP (newpat, 0, 0))
&& ! reg_referenced_p (SET_DEST (XVECEXP (newpat, 0, 0)),
XVECEXP (newpat, 0, 1))
&& ! (contains_muldiv (SET_SRC (XVECEXP (newpat, 0, 0)))
&& contains_muldiv (SET_SRC (XVECEXP (newpat, 0, 1))))
#ifdef HAVE_cc0
/* We cannot split the parallel into two sets if both sets
reference cc0. */
&& ! (reg_referenced_p (cc0_rtx, XVECEXP (newpat, 0, 0))
&& reg_referenced_p (cc0_rtx, XVECEXP (newpat, 0, 1)))
#endif
)
{
/* Normally, it doesn't matter which of the two is done first,
but it does if one references cc0. In that case, it has to
be first. */
#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 it still isn't recognized, fail and change things back the way they
were. */
if ((insn_code_number < 0
/* Is the result a reasonable ASM_OPERANDS? */
&& (! check_asm_operands (newpat) || added_sets_1 || added_sets_2)))
{
undo_all ();
return 0;
}
/* If we had to change another insn, make sure it is valid also. */
if (undobuf.other_insn)
{
CLEAR_HARD_REG_SET (newpat_used_regs);
other_pat = PATTERN (undobuf.other_insn);
other_code_number = recog_for_combine (&other_pat, undobuf.other_insn,
&new_other_notes);
if (other_code_number < 0 && ! check_asm_operands (other_pat))
{
undo_all ();
return 0;
}
}
#ifdef HAVE_cc0
/* If I2 is the CC0 setter and I3 is the CC0 user then check whether
they are adjacent to each other or not. */
{
rtx p = prev_nonnote_insn (i3);
if (p && p != i2 && NONJUMP_INSN_P (p) && newi2pat
&& sets_cc0_p (newi2pat))
{
undo_all ();
return 0;
}
}
#endif
/* Only allow this combination if insn_rtx_costs reports that the
replacement instructions are cheaper than the originals. */
if (!combine_validate_cost (i1, i2, i3, newpat, newi2pat, other_pat))
{
undo_all ();
return 0;
}
/* If we will be able to accept this, we have made a
change to the destination of I3. This requires us to
do a few adjustments. */
if (changed_i3_dest)
{
PATTERN (i3) = newpat;
adjust_for_new_dest (i3);
}
/* We now know that we can do this combination. Merge the insns and
update the status of registers and LOG_LINKS. */
if (undobuf.other_insn)
{
rtx note, next;
PATTERN (undobuf.other_insn) = other_pat;
/* If any of the notes in OTHER_INSN were REG_UNUSED, ensure that they
are still valid. Then add any non-duplicate notes added by
recog_for_combine. */
for (note = REG_NOTES (undobuf.other_insn); note; note = next)
{
next = XEXP (note, 1);
if (REG_NOTE_KIND (note) == REG_UNUSED
&& ! reg_set_p (XEXP (note, 0), PATTERN (undobuf.other_insn)))
remove_note (undobuf.other_insn, note);
}
distribute_notes (new_other_notes, undobuf.other_insn,
undobuf.other_insn, NULL_RTX, NULL_RTX, NULL_RTX);
}
if (swap_i2i3)
{
rtx insn;
rtx link;
rtx ni2dest;
/* I3 now uses what used to be its destination and which is now
I2's destination. This requires us to do a few adjustments. */
PATTERN (i3) = newpat;
adjust_for_new_dest (i3);
/* We need a LOG_LINK from I3 to I2. But we used to have one,
so we still will.
However, some later insn might be using I2's dest and have
a LOG_LINK pointing at I3. We must remove this link.
The simplest way to remove the link is to point it at I1,
which we know will be a NOTE. */
/* newi2pat is usually a SET here; however, recog_for_combine might
have added some clobbers. */
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;
/* Compute which registers we expect to eliminate. newi2pat may be setting
either i3dest or i2dest, so we must check it. Also, i1dest may be the
same as i3dest, in which case newi2pat may be setting i1dest. */
rtx elim_i2 = ((newi2pat && reg_set_p (i2dest, newi2pat))
|| i2dest_in_i2src || i2dest_in_i1src
|| !i2dest_killed
? 0 : i2dest);
rtx elim_i1 = (i1 == 0 || i1dest_in_i1src
|| (newi2pat && reg_set_p (i1dest, newi2pat))
|| !i1dest_killed
? 0 : i1dest);
/* Get the old REG_NOTES and LOG_LINKS from all our insns and
clear them. */
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);
/* Ensure that we do not have something that should not be shared but
occurs multiple times in the new insns. Check this by first
resetting all the `used' flags and then copying anything is shared. */
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;
/* We had one special case above where I2 had more than one set and
we replaced a destination of one of those sets with the destination
of I3. In that case, we have to update LOG_LINKS of insns later
in this basic block. Note that this (expensive) case is rare.
Also, in this case, we must pretend that all REG_NOTEs for I2
actually came from I3, so that REG_UNUSED notes from I2 will be
properly handled. */
if (i3_subst_into_i2)
{
for (i = 0; i < XVECLEN (PATTERN (i2), 0); i++)
if ((GET_CODE (XVECEXP (PATTERN (i2), 0, i)) == SET
|| GET_CODE (XVECEXP (PATTERN (i2), 0, i)) == CLOBBER)
&& REG_P (SET_DEST (XVECEXP (PATTERN (i2), 0, i)))
&& SET_DEST (XVECEXP (PATTERN (i2), 0, i)) != i2dest
&& ! find_reg_note (i2, REG_UNUSED,
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);
}
/* Get death notes for everything that is now used in either I3 or
I2 and used to die in a previous insn. If we built two new
patterns, move from I1 to I2 then I2 to I3 so that we get the
proper movement on registers that I2 modifies. */
if (newi2pat)
{
move_deaths (newi2pat, NULL_RTX, DF_INSN_LUID (i1), i2, &midnotes);
move_deaths (newpat, newi2pat, DF_INSN_LUID (i1), i3, &midnotes);
}
else
move_deaths (newpat, NULL_RTX, i1 ? DF_INSN_LUID (i1) : DF_INSN_LUID (i2),
i3, &midnotes);
/* Distribute all the LOG_LINKS and REG_NOTES from I1, I2, and I3. */
if (i3notes)
distribute_notes (i3notes, i3, i3, newi2pat ? i2 : NULL_RTX,
elim_i2, elim_i1);
if (i2notes)
distribute_notes (i2notes, i2, i3, newi2pat ? i2 : NULL_RTX,
elim_i2, elim_i1);
if (i1notes)
distribute_notes (i1notes, i1, i3, newi2pat ? i2 : NULL_RTX,
elim_i2, elim_i1);
if (midnotes)
distribute_notes (midnotes, NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
elim_i2, elim_i1);
/* Distribute any notes added to I2 or I3 by recog_for_combine. We
know these are REG_UNUSED and want them to go to the desired insn,
so we always pass it as i3. */
if (newi2pat && new_i2_notes)
distribute_notes (new_i2_notes, i2, i2, NULL_RTX, NULL_RTX, NULL_RTX);
if (new_i3_notes)
distribute_notes (new_i3_notes, i3, i3, NULL_RTX, NULL_RTX, NULL_RTX);
/* If I3DEST was used in I3SRC, it really died in I3. We may need to
put a REG_DEAD note for it somewhere. If NEWI2PAT exists and sets
I3DEST, the death must be somewhere before I2, not I3. If we passed I3
in that case, it might delete I2. Similarly for I2 and I1.
Show an additional death due to the REG_DEAD note we make here. If
we discard it in distribute_notes, we will decrement it again. */
if (i3dest_killed)
{
if (newi2pat && reg_set_p (i3dest_killed, newi2pat))
distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i3dest_killed,
NULL_RTX),
NULL_RTX, i2, NULL_RTX, elim_i2, elim_i1);
else
distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i3dest_killed,
NULL_RTX),
NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
elim_i2, elim_i1);
}
if (i2dest_in_i2src)
{
if (newi2pat && reg_set_p (i2dest, newi2pat))
distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i2dest, NULL_RTX),
NULL_RTX, i2, NULL_RTX, NULL_RTX, NULL_RTX);
else
distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i2dest, NULL_RTX),
NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
NULL_RTX, NULL_RTX);
}
if (i1dest_in_i1src)
{
if (newi2pat && reg_set_p (i1dest, newi2pat))
distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i1dest, NULL_RTX),
NULL_RTX, i2, NULL_RTX, NULL_RTX, NULL_RTX);
else
distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i1dest, NULL_RTX),
NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
NULL_RTX, NULL_RTX);
}
distribute_links (i3links);
distribute_links (i2links);
distribute_links (i1links);
if (REG_P (i2dest))
{
rtx link;
rtx i2_insn = 0, i2_val = 0, set;
/* The insn that used to set this register doesn't exist, and
this life of the register may not exist either. See if one of
I3's links points to an insn that sets I2DEST. If it does,
that is now the last known value for I2DEST. If we don't update
this and I2 set the register to a value that depended on its old
contents, we will get confused. If this insn is used, thing
will be set correctly in combine_instructions. */
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 the reg formerly set in I2 died only once and that was in I3,
zero its use count so it won't make `reload' do any work. */
if (! added_sets_2
&& (newi2pat == 0 || ! reg_mentioned_p (i2dest, newi2pat))
&& ! i2dest_in_i2src)
{
regno = REGNO (i2dest);
INC_REG_N_SETS (regno, -1);
}
}
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)
INC_REG_N_SETS (regno, -1);
}
/* Update reg_stat[].nonzero_bits et al for any changes that may have
been made to this insn. The order of
set_nonzero_bits_and_sign_copies() is important. Because newi2pat
can affect nonzero_bits of newpat */
if (newi2pat)
note_stores (newi2pat, set_nonzero_bits_and_sign_copies, NULL);
note_stores (newpat, set_nonzero_bits_and_sign_copies, NULL);
/* Set new_direct_jump_p if a new return or simple jump instruction
has been created.
If I3 is now an unconditional jump, ensure that it has a
BARRIER following it since it may have initially been a
conditional jump. It may also be the last nonnote insn. */
if (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);
}
/* An NOOP jump does not need barrier, but it does need cleaning up
of CFG. */
if (GET_CODE (newpat) == SET
&& SET_SRC (newpat) == pc_rtx
&& SET_DEST (newpat) == pc_rtx)
*new_direct_jump_p = 1;
}
if (undobuf.other_insn != NULL_RTX)
{
if (dump_file)
{
fprintf (dump_file, "modifying other_insn ");
dump_insn_slim (dump_file, undobuf.other_insn);
}
df_insn_rescan (undobuf.other_insn);
}
if (i1 && !(NOTE_P(i1) && (NOTE_KIND (i1) == NOTE_INSN_DELETED)))
{
if (dump_file)
{
fprintf (dump_file, "modifying insn i1 ");
dump_insn_slim (dump_file, i1);
}
df_insn_rescan (i1);
}
if (i2 && !(NOTE_P(i2) && (NOTE_KIND (i2) == NOTE_INSN_DELETED)))
{
if (dump_file)
{
fprintf (dump_file, "modifying insn i2 ");
dump_insn_slim (dump_file, i2);
}
df_insn_rescan (i2);
}
if (i3 && !(NOTE_P(i3) && (NOTE_KIND (i3) == NOTE_INSN_DELETED)))
{
if (dump_file)
{
fprintf (dump_file, "modifying insn i3 ");
dump_insn_slim (dump_file, i3);
}
df_insn_rescan (i3);
}
combine_successes++;
undo_commit ();
if (added_links_insn
&& (newi2pat == 0 || DF_INSN_LUID (added_links_insn) < DF_INSN_LUID (i2))
&& DF_INSN_LUID (added_links_insn) < DF_INSN_LUID (i3))
return added_links_insn;
else
return newi2pat ? i2 : i3;
}
/* Undo all the modifications recorded in undobuf. */
static void
undo_all (void)
{
struct undo *undo, *next;
for (undo = undobuf.undos; undo; undo = next)
{
next = undo->next;
switch (undo->kind)
{
case UNDO_RTX:
*undo->where.r = undo->old_contents.r;
break;
case UNDO_INT:
*undo->where.i = undo->old_contents.i;
break;
case UNDO_MODE:
adjust_reg_mode (*undo->where.r, undo->old_contents.m);
break;
default:
gcc_unreachable ();
}
undo->next = undobuf.frees;
undobuf.frees = undo;
}
undobuf.undos = 0;
}
/* We've committed to accepting the changes we made. Move all
of the undos to the free list. */
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;
}
/* Find the innermost point within the rtx at LOC, possibly LOC itself,
where we have an arithmetic expression and return that point. LOC will
be inside INSN.
try_combine will call this function to see if an insn can be split into
two insns. */
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;
/* First special-case some codes. */
switch (code)
{
case SUBREG:
#ifdef INSN_SCHEDULING
/* If we are making a paradoxical SUBREG invalid, it becomes a split
point. */
if (MEM_P (SUBREG_REG (x)))
return loc;
#endif
return find_split_point (&SUBREG_REG (x), insn);
case MEM:
#ifdef HAVE_lo_sum
/* If we have (mem (const ..)) or (mem (symbol_ref ...)), split it
using LO_SUM and HIGH. */
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 we have a PLUS whose second operand is a constant and the
address is not valid, perhaps will can split it up using
the machine-specific way to split large constants. We use
the first pseudo-reg (one of the virtual regs) as a placeholder;
it will not remain in the result. */
if (GET_CODE (XEXP (x, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
&& ! memory_address_p (GET_MODE (x), XEXP (x, 0)))
{
rtx reg = regno_reg_rtx[FIRST_PSEUDO_REGISTER];
rtx seq = combine_split_insns (gen_rtx_SET (VOIDmode, reg,
XEXP (x, 0)),
subst_insn);
/* This should have produced two insns, each of which sets our
placeholder. If the source of the second is a valid address,
we can make put both sources together and make a split point
in the middle. */
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)));
/* Replace the placeholder in SRC2 with SRC1. If we can
find where in SRC2 it was placed, that can become our
split point and we can replace this address with SRC2.
Just try two obvious places. */