blob: 7c84a3d65592b362cd0014b073241f122e4a82db [file] [log] [blame]
/* Optimize by combining instructions for GNU compiler.
Copyright (C) 1987-2013 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
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
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
<>. */
/* 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 triplets of insns A, B and C when C has
a link back to B and B has a link back to A. Likewise for a
small number of quadruplets of insns A, B, C and D for which
there's high likelihood of of success.
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
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 "diagnostic-core.h"
#include "target.h"
#include "optabs.h"
#include "insn-codes.h"
#include "rtlhooks-def.h"
#include "params.h"
#include "tree-pass.h"
#include "df.h"
#include "valtrack.h"
#include "cgraph.h"
#include "obstack.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
(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
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;
static vec<reg_stat_type> 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 struct insn_link pointers. */
struct insn_link {
rtx insn;
struct insn_link *next;
static struct insn_link **uid_log_links;
#define INSN_COST(INSN) (uid_insn_cost[INSN_UID (INSN)])
#define LOG_LINKS(INSN) (uid_log_links[INSN_UID (INSN)])
for ((L) = LOG_LINKS (INSN); (L); (L) = (L)->next)
/* Links for LOG_LINKS are allocated from this obstack. */
static struct obstack insn_link_obstack;
/* Allocate a link. */
static inline struct insn_link *
alloc_insn_link (rtx insn, struct insn_link *next)
struct insn_link *l
= (struct insn_link *) obstack_alloc (&insn_link_obstack,
sizeof (struct insn_link));
l->insn = insn;
l->next = next;
return l;
/* Incremented for each basic block. */
static int label_tick;
/* Reset to label_tick for each extended basic block in scanning order. */
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_kind kind;
union { rtx r; int i; enum machine_mode m; struct insn_link *l; } old_contents;
union { rtx *r; int *i; struct insn_link **l; } 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, rtx *, rtx *);
static int combinable_i3pat (rtx, rtx *, rtx, rtx, rtx, int, int, rtx *);
static int contains_muldiv (rtx);
static rtx try_combine (rtx, rtx, rtx, rtx, int *, rtx);
static void undo_all (void);
static void undo_commit (void);
static rtx *find_split_point (rtx *, rtx, bool);
static rtx subst (rtx, rtx, rtx, int, int, int);
static rtx combine_simplify_rtx (rtx, enum machine_mode, int, int);
static rtx simplify_if_then_else (rtx);
static rtx simplify_set (rtx);
static rtx simplify_logical (rtx);
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 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,
static int recog_for_combine (rtx *, rtx, rtx *);
static rtx gen_lowpart_for_combine (enum machine_mode, rtx);
static enum rtx_code simplify_compare_const (enum rtx_code, rtx, rtx *);
static enum rtx_code simplify_comparison (enum rtx_code, rtx *, rtx *);
static void update_table_tick (rtx);
static void record_value_for_reg (rtx, rtx, rtx);
static void check_promoted_subreg (rtx, rtx);
static void record_dead_and_set_regs_1 (rtx, 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, rtx);
static void distribute_links (struct insn_link *);
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. */
#define RTL_HOOKS_GEN_LOWPART gen_lowpart_for_combine
/* Our implementation of gen_lowpart never emits a new pseudo. */
#define RTL_HOOKS_GEN_LOWPART_NO_EMIT gen_lowpart_for_combine
#define RTL_HOOKS_REG_NONZERO_REG_BITS reg_nonzero_bits_for_combine
#define RTL_HOOKS_REG_NUM_SIGN_BIT_COPIES reg_num_sign_bit_copies_for_combine
#define RTL_HOOKS_REG_TRUNCATED_TO_MODE reg_truncated_to_mode
static const struct rtl_hooks combine_rtl_hooks = RTL_HOOKS_INITIALIZER;
/* Convenience wrapper for the canonicalize_comparison target hook.
Target hooks cannot use enum rtx_code. */
static inline void
target_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1,
bool op0_preserve_value)
int code_int = (int)*code;
targetm.canonicalize_comparison (&code_int, op0, op1, op0_preserve_value);
*code = (enum rtx_code)code_int;
/* 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 > reg_stat.length ())
reg_stat.safe_grow_cleared (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:
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))
return find_single_use_1 (dest, &SET_SRC (x));
case MEM:
case SUBREG:
return find_single_use_1 (dest, &XEXP (x, 0));
/* 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;
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;
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)
basic_block bb;
rtx next;
rtx *result;
struct insn_link *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;
if (!REG_P (dest))
return 0;
bb = BLOCK_FOR_INSN (insn);
for (next = NEXT_INSN (insn);
next && BLOCK_FOR_INSN (next) == bb;
next = NEXT_INSN (next))
if (INSN_P (next) && dead_or_set_p (next, dest))
FOR_EACH_LOG_LINK (link, next)
if (link->insn == insn)
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)
/* 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. */
&& CONST_INT_P (newval))
/* 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
&& CONST_INT_P (SUBREG_REG (oldval))));
gcc_assert (!(GET_CODE (oldval) == ZERO_EXTEND
&& CONST_INT_P (XEXP (oldval, 0))));
if (undobuf.frees)
buf = undobuf.frees, undobuf.frees = buf->next;
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;
/* 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)
if (undobuf.frees)
buf = undobuf.frees, undobuf.frees = buf->next;
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;
/* 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)
if (undobuf.frees)
buf = undobuf.frees, undobuf.frees = buf->next;
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;
#ifndef HAVE_cc0
/* Similar to SUBST, but NEWVAL is a LOG_LINKS expression. */
static void
do_SUBST_LINK (struct insn_link **into, struct insn_link *newval)
struct undo *buf;
struct insn_link * oldval = *into;
if (oldval == newval)
if (undobuf.frees)
buf = undobuf.frees, undobuf.frees = buf->next;
buf = XNEW (struct undo);
buf->kind = UNDO_LINKS;
buf->where.l = into;
buf->old_contents.l = oldval;
*into = newval;
buf->next = undobuf.undos, undobuf.undos = buf;
#define SUBST_LINK(oldval, newval) do_SUBST_LINK (&oldval, newval)
/* Subroutine of try_combine. Determine whether the replacement patterns
NEWPAT, NEWI2PAT and NEWOTHERPAT are cheaper according to insn_rtx_cost
than the original sequence I0, I1, I2, I3 and undobuf.other_insn. Note
that I0, I1 and/or NEWI2PAT may be NULL_RTX. Similarly, NEWOTHERPAT and
undobuf.other_insn may also both be NULL_RTX. Return false if the cost
of all the instructions can be estimated and the replacements are more
expensive than the original sequence. */
static bool
combine_validate_cost (rtx i0, rtx i1, rtx i2, rtx i3, rtx newpat,
rtx newi2pat, rtx newotherpat)
int i0_cost, 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);
if (i0)
i0_cost = INSN_COST (i0);
old_cost = (i0_cost > 0 && i1_cost > 0 && i2_cost > 0 && i3_cost > 0
? i0_cost + i1_cost + i2_cost + i3_cost : 0);
old_cost = (i1_cost > 0 && i2_cost > 0 && i3_cost > 0
? i1_cost + i2_cost + i3_cost : 0);
i0_cost = 0;
old_cost = (i2_cost > 0 && i3_cost > 0) ? i2_cost + i3_cost : 0;
i1_cost = i0_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;
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;
old_cost = 0;
/* Disallow this combination 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 (i0)
fprintf (dump_file,
"rejecting combination of insns %d, %d, %d and %d\n",
INSN_UID (i0), INSN_UID (i1), INSN_UID (i2),
INSN_UID (i3));
fprintf (dump_file, "original costs %d + %d + %d + %d = %d\n",
i0_cost, i1_cost, i2_cost, i3_cost, old_cost);
else 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);
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);
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;
if (i0)
INSN_COST (i0) = 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 (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. */
if (!NONDEBUG_INSN_P (insn))
/* 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])
/* Do not consider if it is pre/post modification in MEM. */
/* Do not make the log link for frame pointer. */
&& (! reload_completed || frame_pointer_needed))
&& (! reload_completed || frame_pointer_needed))
|| (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
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. */
|| asm_noperands (PATTERN (use_insn)) < 0)
/* Don't add duplicate links between instructions. */
struct insn_link *links;
FOR_EACH_LOG_LINK (links, use_insn)
if (insn == links->insn)
if (!links)
LOG_LINKS (use_insn)
= alloc_insn_link (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. */
next_use[regno] = insn;
free (next_use);
/* Walk the LOG_LINKS of insn B to see if we find a reference to A. Return
true if we found a LOG_LINK that proves that A feeds B. This only works
if there are no instructions between A and B which could have a link
depending on A, since in that case we would not record a link for B.
We also check the implicit dependency created by a cc0 setter/user
pair. */
static bool
insn_a_feeds_b (rtx a, rtx b)
struct insn_link *links;
FOR_EACH_LOG_LINK (links, b)
if (links->insn == a)
return true;
#ifdef HAVE_cc0
if (sets_cc0_p (a))
return true;
return false;
/* 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;
struct insn_link *links, *nextlinks;
rtx first;
basic_block last_bb;
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;
reg_stat.safe_grow_cleared (nregs);
init_recog_no_volatile ();
/* Allocate array for insn info. */
max_uid_known = get_max_uid ();
uid_log_links = XCNEWVEC (struct insn_link *, max_uid_known + 1);
uid_insn_cost = XCNEWVEC (int, max_uid_known + 1);
gcc_obstack_init (&insn_link_obstack);
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;
label_tick = label_tick_ebb_start = 1;
/* 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. */
setup_incoming_promotions (first);
/* Allow the entry block and the first block to fall into the same EBB.
Conceptually the incoming promotions are assigned to the entry block. */
last_bb = ENTRY_BLOCK_PTR;
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;
if (!single_pred_p (this_basic_block)
|| single_pred (this_basic_block) != last_bb)
label_tick_ebb_start = label_tick;
last_bb = this_basic_block;
FOR_BB_INSNS (this_basic_block, insn)
if (INSN_P (insn) && BLOCK_FOR_INSN (insn))
rtx links;
subst_low_luid = DF_INSN_LUID (insn);
subst_insn = insn;
note_stores (PATTERN (insn), set_nonzero_bits_and_sign_copies,
record_dead_and_set_regs (insn);
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,
/* Record the current insn_rtx_cost of this instruction. */
if (NONJUMP_INSN_P (insn))
INSN_COST (insn) = insn_rtx_cost (PATTERN (insn),
if (dump_file)
fprintf(dump_file, "insn_cost %d: %d\n",
INSN_UID (insn), INSN_COST (insn));
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);
last_bb = ENTRY_BLOCK_PTR;
FOR_EACH_BB (this_basic_block)
rtx last_combined_insn = NULL_RTX;
optimize_this_for_speed_p = optimize_bb_for_speed_p (this_basic_block);
last_call_luid = 0;
mem_last_set = -1;
if (!single_pred_p (this_basic_block)
|| single_pred (this_basic_block) != last_bb)
label_tick_ebb_start = label_tick;
last_bb = this_basic_block;
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 (NONDEBUG_INSN_P (insn))
while (last_combined_insn
&& INSN_DELETED_P (last_combined_insn))
last_combined_insn = PREV_INSN (last_combined_insn);
if (last_combined_insn == NULL_RTX
|| BARRIER_P (last_combined_insn)
|| BLOCK_FOR_INSN (last_combined_insn) != this_basic_block
|| DF_INSN_LUID (last_combined_insn) <= DF_INSN_LUID (insn))
last_combined_insn = 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_EACH_LOG_LINK (links, insn)
if ((next = try_combine (insn, links->insn, NULL_RTX,
NULL_RTX, &new_direct_jump_p,
last_combined_insn)) != 0)
goto retry;
/* Try each sequence of three linked insns ending with this one. */
FOR_EACH_LOG_LINK (links, insn)
rtx link = links->insn;
/* 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))
FOR_EACH_LOG_LINK (nextlinks, link)
if ((next = try_combine (insn, link, nextlinks->insn,
NULL_RTX, &new_direct_jump_p,
last_combined_insn)) != 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, NULL_RTX,
last_combined_insn)) != 0)
goto retry;
FOR_EACH_LOG_LINK (nextlinks, prev)
if ((next = try_combine (insn, prev, nextlinks->insn,
NULL_RTX, &new_direct_jump_p,
last_combined_insn)) != 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, NULL_RTX,
last_combined_insn)) != 0)
goto retry;
FOR_EACH_LOG_LINK (nextlinks, prev)
if ((next = try_combine (insn, prev, nextlinks->insn,
NULL_RTX, &new_direct_jump_p,
last_combined_insn)) != 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_EACH_LOG_LINK (links, insn)
if (NONJUMP_INSN_P (links->insn)
&& GET_CODE (PATTERN (links->insn)) == SET
&& reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (links->insn)))
&& (prev = prev_nonnote_insn (links->insn)) != 0
&& NONJUMP_INSN_P (prev)
&& sets_cc0_p (PATTERN (prev))
&& (next = try_combine (insn, links->insn,
prev, NULL_RTX, &new_direct_jump_p,
last_combined_insn)) != 0)
goto retry;
/* Try combining an insn with two different insns whose results it
uses. */
FOR_EACH_LOG_LINK (links, insn)
for (nextlinks = links->next; nextlinks;
nextlinks = nextlinks->next)
if ((next = try_combine (insn, links->insn,
nextlinks->insn, NULL_RTX,
last_combined_insn)) != 0)
goto retry;
/* Try four-instruction combinations. */
FOR_EACH_LOG_LINK (links, insn)
struct insn_link *next1;
rtx link = links->insn;
/* 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))
FOR_EACH_LOG_LINK (next1, link)
rtx link1 = next1->insn;
if (NOTE_P (link1))
/* I0 -> I1 -> I2 -> I3. */
FOR_EACH_LOG_LINK (nextlinks, link1)
if ((next = try_combine (insn, link, link1,
last_combined_insn)) != 0)
goto retry;
/* I0, I1 -> I2, I2 -> I3. */
for (nextlinks = next1->next; nextlinks;
nextlinks = nextlinks->next)
if ((next = try_combine (insn, link, link1,
last_combined_insn)) != 0)
goto retry;
for (next1 = links->next; next1; next1 = next1->next)
rtx link1 = next1->insn;
if (NOTE_P (link1))
/* I0 -> I2; I1, I2 -> I3. */
FOR_EACH_LOG_LINK (nextlinks, link)
if ((next = try_combine (insn, link, link1,
last_combined_insn)) != 0)
goto retry;
/* I0 -> I1; I1, I2 -> I3. */
FOR_EACH_LOG_LINK (nextlinks, link1)
if ((next = try_combine (insn, link, link1,
last_combined_insn)) != 0)
goto retry;
/* Try this insn with each REG_EQUAL note it links back to. */
FOR_EACH_LOG_LINK (links, insn)
rtx set, note;
rtx temp = links->insn;
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
: 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, NULL_RTX,
i2mod = NULL_RTX;
if (next)
goto retry;
SET_SRC (set) = orig;
if (!NOTE_P (insn))
record_dead_and_set_regs (insn);
default_rtl_profile ();
clear_bb_flags ();
new_direct_jump_p |= purge_all_dead_edges ();
delete_noop_moves ();
/* Clean up. */
obstack_free (&insn_link_obstack, NULL);
free (uid_log_links);
free (uid_insn_cost);
reg_stat.release ();
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_EACH_VEC_ELT (reg_stat, i, p)
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;
for (arg = DECL_ARGUMENTS (current_function_decl); arg;
arg = DECL_CHAIN (arg))
rtx x, 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))
/* 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));
/* The mode and signedness of the argument after any source language and
TARGET_PROMOTE_PROTOTYPES-driven promotions. */
mode2 = TYPE_MODE (DECL_ARG_TYPE (arg));
/* The mode and signedness of the argument as it is actually passed,
see assign_parm_setup_reg in function.c. */
mode3 = promote_function_mode (TREE_TYPE (arg), mode1, &uns3,
TREE_TYPE (cfun->decl), 0);
/* The mode of the register in which the argument is being passed. */
mode4 = GET_MODE (reg);
/* Eliminate sign extensions in the callee when:
(a) A mode promotion has occurred; */
if (mode1 == mode3)
/* (b) The mode of the register is the same as the mode of
the argument as it is passed; */
if (mode3 != mode4)
/* (c) There's no language level extension; */
if (mode1 == mode2)
/* (c.1) All callers are from the current compilation unit. If that's
the case we don't have to rely on an ABI, we only have to know
what we're generating right now, and we know that we will do the
mode1 to mode2 promotion with the given sign. */
else if (!strictly_local)
/* (c.2) The combination of the two promotions is useful. This is
true when the signs match, or if the first promotion is unsigned.
In the later case, (sign_extend (zero_extend x)) is the same as
(zero_extend (zero_extend x)), so make sure to force UNS3 true. */
else if (uns1)
uns3 = true;
else if (uns3)
/* 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. */
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)
/* If this register is undefined at the start of the file, we can't
say what its contents were. */
(DF_LR_IN (ENTRY_BLOCK_PTR->next_bb), REGNO (x))
reg_stat_type *rsp = &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;
/* 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 (x)))
struct insn_link *link;
FOR_EACH_LOG_LINK (link, insn)
if (dead_or_set_p (link->insn, x))
if (!link)
rsp->nonzero_bits = GET_MODE_MASK (GET_MODE (x));
rsp->sign_bit_copies = 1;
/* 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
|| (paradoxical_subreg_p (SET_DEST (set))
&& SUBREG_REG (SET_DEST (set)) == x))
rtx src = SET_SRC (set);
/* 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. */
&& CONST_INT_P (src)
&& INTVAL (src) > 0
&& val_signbit_known_set_p (GET_MODE (x), INTVAL (src)))
src = GEN_INT (INTVAL (src) | ~GET_MODE_MASK (GET_MODE (x)));
/* 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;
rsp->nonzero_bits = GET_MODE_MASK (GET_MODE (x));
rsp->sign_bit_copies = 1;
/* See if INSN can be combined into I3. PRED, PRED2, SUCC and SUCC2 are
optionally insns that were previously combined into I3 or that will be
combined into the merger of INSN and I3. The order is PRED, PRED2,
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 pred2 ATTRIBUTE_UNUSED, rtx succ, rtx succ2,
rtx *pdest, rtx *psrc)
int i;
const_rtx set = 0;
rtx src, dest;
rtx p;
rtx link;
bool all_adjacent = true;
int (*is_volatile_p) (const_rtx);
if (succ)
if (succ2)
if (next_active_insn (succ2) != i3)
all_adjacent = false;
if (next_active_insn (succ) != succ2)
all_adjacent = false;
else if (next_active_insn (succ) != i3)
all_adjacent = false;
if (next_active_insn (insn) != succ)
all_adjacent = false;
else if (next_active_insn (insn) != i3)
all_adjacent = false;
/* 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
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);
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))
rtx i3pat = PATTERN (i3);
int i = XVECLEN (i3pat, 0) - 1;
unsigned int regno = REGNO (XEXP (elt, 0));
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)
return 0;
while (--i >= 0);
/* We can ignore CLOBBERs. */
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))
&& insn_nothrow_p (insn)
&& !side_effects_p (elt))
/* 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;
/* 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. */
return 0;
return 0;
if (set == 0)
return 0;
/* The simplification in expand_field_assignment may call back to
get_last_value, so set safe guard here. */
subst_low_luid = DF_INSN_LUID (insn);
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. */
/* 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)
&& global_regs[REGNO (dest)])))
/* Don't substitute into an incremented register. */
|| FIND_REG_INC_NOTE (i3, dest)
|| (succ && FIND_REG_INC_NOTE (succ, dest))
|| (succ2 && FIND_REG_INC_NOTE (succ2, 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. */
|| (!all_adjacent
&& ((succ2
&& (reg_used_between_p (dest, succ2, i3)
|| reg_used_between_p (dest, succ, succ2)))
|| (!succ2 && succ && 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)))
/* 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)
&& ! 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. */
&& ! HARD_REGNO_MODE_OK (REGNO (src), GET_MODE (src)))))
return 0;
else if (GET_CODE (dest) != CC0)
return 0;
for (i = XVECLEN (PATTERN (i3), 0) - 1; i >= 0; i--)
/* 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)
|| !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 neither succ nor succ2 contains a volatile reference. */
if (succ2 != 0 && volatile_refs_p (PATTERN (succ2)))
return 0;
if (succ != 0 && volatile_refs_p (PATTERN (succ)))
return 0;
/* We'll check insns between INSN and I3 below. */
/* 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. */
&& REG_P (dest) && REGNO (dest) < FIRST_PSEUDO_REGISTER)
return 0;
/* If INSN contains volatile references (specifically volatile MEMs),
we cannot combine across any other volatile references.
Even if INSN doesn't contain volatile references, any intervening
volatile insn might affect machine state. */
is_volatile_p = volatile_refs_p (PATTERN (insn))
? volatile_refs_p
: volatile_insn_p;
for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))
if (INSN_P (p) && p != succ && p != succ2 && is_volatile_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. */
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)))
|| (pred2 != NULL_RTX
&& reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (pred2)))
|| (succ != NULL_RTX
&& reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (succ)))
|| (succ2 != NULL_RTX
&& reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (succ2)))
|| reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i3))))
return 0;
#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;
/* 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, I1DEST or I0DEST as
doing so would produce an insn that is not equivalent to the original insns.
(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. The same situation
can occur for I0, in which case I0_NOT_IN_SRC is set.
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, rtx i0dest,
int i1_not_in_src, int i0_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))
|| (i0dest && rtx_equal_p (i0dest, inner_dest)))
&& (reg_overlap_mentioned_p (i2dest, inner_dest)
|| (i1dest && reg_overlap_mentioned_p (i1dest, inner_dest))
|| (i0dest && reg_overlap_mentioned_p (i0dest, 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
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)
&& (! HARD_REGNO_MODE_OK (REGNO (inner_dest),
GET_MODE (inner_dest))))
|| (i1_not_in_src && reg_overlap_mentioned_p (i1dest, src))
|| (i0_not_in_src && reg_overlap_mentioned_p (i0dest, 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))
subdest = SUBREG_REG (subdest);
if (pi3dest_killed
&& REG_P (subdest)
&& reg_referenced_p (subdest, PATTERN (i3))
|| ! fixed_regs [REGNO (subdest)])
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, i0dest,
i1_not_in_src, i0_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 ! (CONST_INT_P (XEXP (x, 1))
&& exact_log2 (UINTVAL (XEXP (x, 1))) >= 0);
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)
&& ((HARD_REGISTER_P (src)
&& ! TEST_HARD_REG_BIT (fixed_reg_set, REGNO (src))
&& targetm.class_likely_spilled_p (REGNO_REG_CLASS (REGNO (src))))
|| (HARD_REGISTER_P (dest)
&& ! TEST_HARD_REG_BIT (fixed_reg_set, REGNO (dest))
&& targetm.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)))
regno = REGNO (x);
if (regno >= info->regno + info->nregs)
nregs = hard_regno_nregs[regno][GET_MODE (x)];
if (regno + nregs <= info->regno)
new_mask = (2U << (nregs - 1)) - 1;
if (regno < info->regno)
new_mask >>= info->regno - regno;
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 TARGET_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) || !targetm.calls.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 --;
if ((mask & 1 << nregs)
&& targetm.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 (alloc_insn_link (insn, NULL));
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. */
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;
x = XEXP (x, 0);
return GET_CODE (x) == SUBREG
&& SUBREG_REG (x) == reg
/* Delete the unconditional jump INSN and adjust the CFG correspondingly.
Note that the INSN should be deleted *after* removing dead edges, so
that the kept edge is the fallthrough edge for a (set (pc) (pc))
but not for a (set (pc) (label_ref FOO)). */
static void
update_cfg_for_uncondjump (rtx insn)
basic_block bb = BLOCK_FOR_INSN (insn);
gcc_assert (BB_END (bb) == insn);
purge_dead_edges (bb);
delete_insn (insn);
if (EDGE_COUNT (bb->succs) == 1)
rtx insn;
single_succ_edge (bb)->flags |= EDGE_FALLTHRU;
/* Remove barriers from the footer if there are any. */
for (insn = BB_FOOTER (bb); insn; insn = NEXT_INSN (insn))
if (BARRIER_P (insn))
if (PREV_INSN (insn))
NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn);
BB_FOOTER (bb) = NEXT_INSN (insn);
if (NEXT_INSN (insn))
PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn);
else if (LABEL_P (insn))
/* Try to combine the insns I0, I1 and I2 into I3.
Here I0, I1 and I2 appear earlier than I3.
I0 and I1 can be zero; then we combine just I2 into I3, or I1 and I2 into
If we are combining more than two insns and the resulting insn is not
recognized, try splitting it into two insns. If that happens, I2 and I3
are retained and I1/I0 are pseudo-deleted by turning them into a NOTE.
Otherwise, I0, 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.
LAST_COMBINED_INSN is either I3, or some insn after I3 that has
been I3 passed to an earlier try_combine within the same basic
block. */
static rtx
try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
rtx last_combined_insn)
/* New patterns for I3 and I2, respectively. */
rtx newpat, newi2pat = 0;
rtvec newpat_vec_with_clobbers = 0;
int substed_i2 = 0, substed_i1 = 0, substed_i0 = 0;
/* Indicates need to preserve SET in I0, I1 or I2 in I3 if it is not
dead. */
int added_sets_0, added_sets_1, added_sets_2;
/* Total number of SETs to put into I3. */
int total_sets;
/* Nonzero if I2's or I1's body now appears in I3. */
int i2_is_used = 0, i1_is_used = 0;
/* 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, I1 and I0. */
rtx i2dest = 0, i2src = 0, i1dest = 0, i1src = 0, i0dest = 0, i0src = 0;
/* Copy of SET_SRC of I1 and I0, if needed. */
rtx i1src_copy = 0, i0src_copy = 0, i0src_copy2 = 0;
/* Set if I2DEST was reused as a scratch register. */
bool i2scratch = false;
/* The PATTERNs of I0, I1, and I2, or a copy of them in certain cases. */
rtx i0pat = 0, 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 i0dest_in_i0src = 0, i1dest_in_i0src = 0, i2dest_in_i0src = 0;
int i2dest_killed = 0, i1dest_killed = 0, i0dest_killed = 0;
int i1_feeds_i2_n = 0, i0_feeds_i2_n = 0, i0_feeds_i1_n = 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;
struct insn_link *link;
rtx other_pat = 0;
rtx new_other_notes;
int i;
/* Only try four-insn combinations when there's high likelihood of
success. Look for simple insns, such as loads of constants or
binary operations involving a constant. */
if (i0)
int i;
int ngood = 0;
int nshift = 0;
if (!flag_expensive_optimizations)
return 0;
for (i = 0; i < 4; i++)
rtx insn = i == 0 ? i0 : i == 1 ? i1 : i == 2 ? i2 : i3;
rtx set = single_set (insn);
rtx src;
if (!set)
src = SET_SRC (set);
if (CONSTANT_P (src))
ngood += 2;
else if (BINARY_P (src) && CONSTANT_P (XEXP (src, 1)))
else if (GET_CODE (src) == ASHIFT || GET_CODE (src) == ASHIFTRT
|| GET_CODE (src) == LSHIFTRT)
if (ngood < 2 && nshift < 2)
return 0;
/* 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))
|| (i0 && cant_combine_insn_p (i0))
|| likely_spilled_retval_p (i3))
return 0;
undobuf.other_insn = 0;
/* Reset the hard register usage information. */
CLEAR_HARD_REG_SET (newpat_used_regs);
if (dump_file && (dump_flags & TDF_DETAILS))
if (i0)
fprintf (dump_file, "\nTrying %d, %d, %d -> %d:\n",
INSN_UID (i0), INSN_UID (i1), INSN_UID (i2), INSN_UID (i3));
else if (i1)
fprintf (dump_file, "\nTrying %d, %d -> %d:\n",
INSN_UID (i1), INSN_UID (i2), INSN_UID (i3));
fprintf (dump_file, "\nTrying %d -> %d:\n",
INSN_UID (i2), INSN_UID (i3));
/* If multiple insns feed into one of I2 or I3, they can be in any
order. To simplify the code below, reorder them in sequence. */
if (i0 && DF_INSN_LUID (i0) > DF_INSN_LUID (i2))
temp = i2, i2 = i0, i0 = temp;
if (i0 && DF_INSN_LUID (i0) > DF_INSN_LUID (i1))
temp = i1, i1 = i0, i0 = temp;
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 CLOBBERs inside the PARALLEL.
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
&& find_reg_note (i3, REG_DEAD, SET_SRC (PATTERN (i3)))
&& ! 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. */
&& ! reg_overlap_mentioned_p (SET_SRC (PATTERN (i3)),
&& next_active_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))))
if (i == XVECLEN (p2, 0))
for (i = 0; i < XVECLEN (p2, 0); i++)
if (GET_CODE (XVECEXP (p2, 0, i)) == SET
&& SET_DEST (XVECEXP (p2, 0, i)) == SET_SRC (PATTERN (i3)))
subst_insn = i3;
subst_low_luid = DF_INSN_LUID (i2);
added_sets_2 = added_sets_1 = added_sets_0 = 0;
i2src = SET_SRC (XVECEXP (p2, 0, i));
i2dest = SET_DEST (XVECEXP (p2, 0, i));
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. */
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
&& reg_subword_p (SET_DEST (PATTERN (i3)), SET_DEST (temp)))
rtx dest = SET_DEST (PATTERN (i3));
int offset = -1;
int width = 0;
/* There are not explicit tests to make sure that this is not a
float, but there is code here that would not be correct if it
was. */
gcc_assert (GET_MODE_CLASS (GET_MODE (SET_SRC (temp))) != MODE_FLOAT);
if (GET_CODE (dest) == ZERO_EXTRACT)
if (CONST_INT_P (XEXP (dest, 1))
&& CONST_INT_P (XEXP (dest, 2)))
width = INTVAL (XEXP (dest, 1));
offset = INTVAL (XEXP (dest, 2));
dest = XEXP (dest, 0);
offset = GET_MODE_PRECISION (GET_MODE (dest)) - width - offset;
dest = XEXP (dest, 0);
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. */
offset += GET_MODE_PRECISION (GET_MODE (dest));
/* Otherwise give up for now. */
offset = -1;
if (offset >= 0
double_int m, o, i;
rtx inner = SET_SRC (PATTERN (i3));
rtx outer = SET_SRC (temp);
o = rtx_to_double_int (outer);
i = rtx_to_double_int (inner);
m = double_int::mask (width);
i &= m;
m = m.llshift (offset, HOST_BITS_PER_DOUBLE_INT);
i = i.llshift (offset, HOST_BITS_PER_DOUBLE_INT);
o = o.and_not (m) | i;
subst_insn = i3;
subst_low_luid = DF_INSN_LUID (i2);
added_sets_2 = added_sets_1 = added_sets_0 = 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_int_const (o, 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
&& 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 (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,
SUBST_LINK (LOG_LINKS (i2), alloc_insn_link (i1, LOG_LINKS (i2)));
/* Verify that I2 and I1 are valid for combining. */
if (! can_combine_p (i2, i3, i0, i1, NULL_RTX, NULL_RTX, &i2dest, &i2src)
|| (i1 && ! can_combine_p (i1, i3, i0, NULL_RTX, i2, NULL_RTX,
&i1dest, &i1src))
|| (i0 && ! can_combine_p (i0, i3, NULL_RTX, NULL_RTX, i1, i2,
&i0dest, &i0src)))
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);
i0dest_in_i0src = i0 && reg_overlap_mentioned_p (i0dest, i0src);
i1dest_in_i0src = i0 && reg_overlap_mentioned_p (i1dest, i0src);
i2dest_in_i0src = i0 && reg_overlap_mentioned_p (i2dest, i0src);
i2dest_killed = dead_or_set_p (i2, i2dest);
i1dest_killed = i1 && dead_or_set_p (i1, i1dest);
i0dest_killed = i0 && dead_or_set_p (i0, i0dest);
/* For the earlier insns, determine which of the subsequent ones they
feed. */
i1_feeds_i2_n = i1 && insn_a_feeds_b (i1, i2);
i0_feeds_i1_n = i0 && insn_a_feeds_b (i0, i1);
i0_feeds_i2_n = (i0 && (!i0_feeds_i1_n ? insn_a_feeds_b (i0, i2)
: (!reg_overlap_mentioned_p (i1dest, i0dest)
&& reg_overlap_mentioned_p (i0dest, i2src))));
/* Ensure that I3's pattern can be the destination of combines. */
if (! combinable_i3pat (i3, &PATTERN (i3), i2dest, i1dest, i0dest,
i1 && i2dest_in_i1src && !i1_feeds_i2_n,
i0 && ((i2dest_in_i0src && !i0_feeds_i2_n)
|| (i1dest_in_i0src && !i0_feeds_i1_n)),
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)
|| (i0 != 0 && GET_CODE (i0src) == MULT)
|| (GET_CODE (PATTERN (i3)) == SET
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
/* It's not the exception. */
rtx link;
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;
/* 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. The same consideration applies to I0. */
added_sets_2 = !dead_or_set_p (i3, i2dest);
if (i1)
added_sets_1 = !(dead_or_set_p (i3, i1dest)
|| (i1_feeds_i2_n && dead_or_set_p (i2, i1dest)));
added_sets_1 = 0;
if (i0)
added_sets_0 = !(dead_or_set_p (i3, i0dest)
|| (i0_feeds_i2_n && dead_or_set_p (i2, i0dest))
|| (i0_feeds_i1_n && dead_or_set_p (i1, i0dest)));
added_sets_0 = 0;
/* We are about to copy insns for the case where they need to be kept
around. Check that they can be copied in the merged instruction. */
if (targetm.cannot_copy_insn_p
&& ((added_sets_2 && targetm.cannot_copy_insn_p (i2))
|| (i1 && added_sets_1 && targetm.cannot_copy_insn_p (i1))
|| (i0 && added_sets_0 && targetm.cannot_copy_insn_p (i0))))
undo_all ();
return 0;
/* 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)
i2pat = gen_rtx_SET (VOIDmode, i2dest, copy_rtx (i2src));
i2pat = copy_rtx (PATTERN (i2));
if (added_sets_1)
i1pat = gen_rtx_SET (VOIDmode, i1dest, copy_rtx (i1src));
i1pat = copy_rtx (PATTERN (i1));
if (added_sets_0)
i0pat = gen_rtx_SET (VOIDmode, i0dest, copy_rtx (i0src));
i0pat = copy_rtx (PATTERN (i0));
/* 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
&& rtx_equal_p (XEXP (SET_SRC (PATTERN (i3)), 0), i2dest))
rtx newpat_dest;
rtx *cc_use_loc = NULL, cc_use_insn = NULL_RTX;
rtx op0 = i2src, op1 = XEXP (SET_SRC (PATTERN (i3)), 1);
enum machine_mode compare_mode, orig_compare_mode;
enum rtx_code compare_code = UNKNOWN, orig_compare_code = UNKNOWN;
newpat = PATTERN (i3);
newpat_dest = SET_DEST (newpat);
compare_mode = orig_compare_mode = GET_MODE (newpat_dest);
if (undobuf.other_insn == 0
&& (cc_use_loc = find_single_use (SET_DEST (newpat), i3,
compare_code = orig_compare_code = GET_CODE (*cc_use_loc);
compare_code = simplify_compare_const (compare_code,
op0, &op1);
target_canonicalize_comparison (&compare_code, &op0, &op1, 1);
/* Do the rest only if op1 is const0_rtx, which may be the
result of simplification. */
if (op1 == const0_rtx)
/* If a single use of the CC is found, prepare to modify it
when SELECT_CC_MODE returns a new CC-class mode, or when
the above simplify_compare_const() returned a new comparison
operator. undobuf.other_insn is assigned the CC use insn
when modifying it. */
if (cc_use_loc)
enum machine_mode new_mode
= SELECT_CC_MODE (compare_code, op0, op1);
if (new_mode != orig_compare_mode
&& can_change_dest_mode (SET_DEST (newpat),
added_sets_2, new_mode))
unsigned int regno = REGNO (newpat_dest);
compare_mode = new_mode;
newpat_dest = gen_rtx_REG (compare_mode, regno);
SUBST_MODE (regno_reg_rtx[regno], compare_mode);
newpat_dest = regno_reg_rtx[regno];
/* Cases for modifying the CC-using comparison. */
if (compare_code != orig_compare_code
/* ??? Do we need to verify the zero rtx? */
&& XEXP (*cc_use_loc, 1) == const0_rtx)
/* Replace cc_use_loc with entire new RTX. */
SUBST (*cc_use_loc,
gen_rtx_fmt_ee (compare_code, compare_mode,
newpat_dest, const0_rtx));
undobuf.other_insn = cc_use_insn;
else if (compare_mode != orig_compare_mode)
/* Just replace the CC reg with a new mode. */
SUBST (XEXP (*cc_use_loc, 0), newpat_dest);
undobuf.other_insn = cc_use_insn;
/* Now we modify the current newpat:
First, SET_DEST(newpat) is updated if the CC mode has been
altered. For targets without SELECT_CC_MODE, this should be
optimized away. */
if (compare_mode != orig_compare_mode)
SUBST (SET_DEST (newpat), newpat_dest);
/* This is always done to propagate i2src into newpat. */
SUBST (SET_SRC (newpat),
gen_rtx_COMPARE (compare_mode, op0, op1));
/* Create new version of i2pat if needed; the below PARALLEL
creation needs this to work correctly. */
if (! rtx_equal_p (i2src, op0))
i2pat = gen_rtx_SET (VOIDmode, i2dest, op0);
i2_is_used = 1;
if (i2_is_used == 0)
/* 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 inner insns.
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, 0);
subst_low_luid = DF_INSN_LUID (i2);
i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0, 0);
n_occurrences = 0; /* `subst' counts here */
subst_low_luid = DF_INSN_LUID (i2);
/* If I1 feeds into I2 and I1DEST is in I1SRC, we need to make a unique
copy of I2SRC each time we substitute it, in order to avoid creating
self-referential RTL when we will be substituting I1SRC for I1DEST
later. Likewise if I0 feeds into I2, either directly or indirectly
through I1, and I0DEST is in I0SRC. */
newpat = subst (PATTERN (i3), i2dest, i2src, 0, 0,
(i1_feeds_i2_n && i1dest_in_i1src)
|| ((i0_feeds_i2_n || (i0_feeds_i1_n && i1_feeds_i2_n))
&& i0dest_in_i0src));
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 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_i2_n
&& 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 I1DEST isn't
mentioned in any SETs in NEWPAT that are field assignments. */
|| !combinable_i3pat (NULL_RTX, &newpat, i1dest, NULL_RTX, NULL_RTX,
0, 0, 0))
undo_all ();
return 0;
n_occurrences = 0;
subst_low_luid = DF_INSN_LUID (i1);
/* If the following substitution will modify I1SRC, make a copy of it
for the case where it is substituted for I1DEST in I2PAT later. */
if (added_sets_2 && i1_feeds_i2_n)
i1src_copy = copy_rtx (i1src);
/* If I0 feeds into I1 and I0DEST is in I0SRC, we need to make a unique
copy of I1SRC each time we substitute it, in order to avoid creating
self-referential RTL when we will be substituting I0SRC for I0DEST
later. */
newpat = subst (newpat, i1dest, i1src, 0, 0,
i0_feeds_i1_n && i0dest_in_i0src);
substed_i1 = 1;
/* Record whether I1's body now appears within I3's body. */
i1_is_used = n_occurrences;
/* Likewise for I0 if we have it. */
if (i0 && GET_CODE (newpat) != CLOBBER)
if ((FIND_REG_INC_NOTE (i0, NULL_RTX) != 0
&& ((i0_feeds_i2_n && dead_or_set_p (i2, i0dest))
|| (i0_feeds_i1_n && dead_or_set_p (i1, i0dest)))
&& !reg_overlap_mentioned_p (i0dest, newpat))
|| !combinable_i3pat (NULL_RTX, &newpat, i0dest, NULL_RTX, NULL_RTX,
0, 0, 0))
undo_all ();
return 0;
/* If the following substitution will modify I0SRC, make a copy of it
for the case where it is substituted for I0DEST in I1PAT later. */
if (added_sets_1 && i0_feeds_i1_n)
i0src_copy = copy_rtx (i0src);
/* And a copy for I0DEST in I2PAT substitution. */
if (added_sets_2 && ((i0_feeds_i1_n && i1_feeds_i2_n)
|| (i0_feeds_i2_n)))
i0src_copy2 = copy_rtx (i0src);