blob: 44cca31aec8f57ee316d4d1e607075951dd13771 [file] [log] [blame]
/* Optimize by combining instructions for GNU compiler.
Copyright (C) 1987, 88, 92-96, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC 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 2, or (at your option)
any later version.
GNU CC 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* 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 created by
flow.c aren't completely updated:
- reg_live_length is not updated
- reg_n_refs is not adjusted in the rare case when a register is
no longer required in a computation
- there are extremely rare cases (see distribute_regnotes) when a
REG_DEAD note is lost
- a LOG_LINKS entry that refers to an insn with multiple SETs may be
removed because there is no way to know which register it was
linking
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"
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
/* Must precede rtl.h for FFS. */
#include <stdio.h>
#include "rtl.h"
#include "flags.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "expr.h"
#include "basic-block.h"
#include "insn-config.h"
#include "insn-flags.h"
#include "insn-codes.h"
#include "insn-attr.h"
#include "recog.h"
#include "real.h"
/* It is not safe to use ordinary gen_lowpart in combine.
Use gen_lowpart_for_combine instead. See comments there. */
#define gen_lowpart dont_use_gen_lowpart_you_dummy
/* 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;
/* Define a default value for REVERSIBLE_CC_MODE.
We can never assume that a condition code mode is safe to reverse unless
the md tells us so. */
#ifndef REVERSIBLE_CC_MODE
#define REVERSIBLE_CC_MODE(MODE) 0
#endif
/* Vector mapping INSN_UIDs to cuids.
The cuids are like uids but increase monotonically always.
Combine always uses cuids so that it can compare them.
But actually renumbering the uids, which we used to do,
proves to be a bad idea because it makes it hard to compare
the dumps produced by earlier passes with those from later passes. */
static int *uid_cuid;
static int max_uid_cuid;
/* Get the cuid of an insn. */
#define INSN_CUID(INSN) \
(INSN_UID (INSN) > max_uid_cuid ? insn_cuid (INSN) : uid_cuid[INSN_UID (INSN)])
/* Maximum register number, which is the size of the tables below. */
static int combine_max_regno;
/* Record last point of death of (hard or pseudo) register n. */
static rtx *reg_last_death;
/* Record last point of modification of (hard or pseudo) register n. */
static rtx *reg_last_set;
/* Record the cuid of the last insn that invalidated memory
(anything that writes memory, and subroutine calls, but not pushes). */
static int mem_last_set;
/* Record the cuid of the last CALL_INSN
so we can tell whether a potential combination crosses any calls. */
static int last_call_cuid;
/* 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 an insn that belongs before subst_insn, but is not currently
on the insn chain. */
static rtx subst_prev_insn;
/* This is the lowest CUID that `subst' is currently dealing with.
get_last_value will not return a value if the register was set at or
after this CUID. 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_cuid;
/* 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 number of the block in which we are performing combines. */
static int this_basic_block;
/* The next group of arrays allows the recording of the last value assigned
to (hard or pseudo) register n. We use this information to see if a
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 arrays:
reg_last_set_value the last value assigned
reg_last_set_label records the value of label_tick when the
register was assigned
reg_last_set_table_tick records the value of label_tick when a
value using the register is assigned
reg_last_set_invalid set to non-zero 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 reg_last_set_value being valid
and the register being validly contained in some other expression in the
table.
Entry I in reg_last_set_value is valid if it is non-zero, and either
reg_n_sets[i] is 1 or reg_last_set_label[i] == 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_last_set_label[i] < reg_last_set_label[j] or
reg_last_set_invalid[j] is zero.
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)).
reg_last_set_invalid[i] is set non-zero when register I is being assigned
to and reg_last_set_table_tick[i] == label_tick. */
/* Record last value assigned to (hard or pseudo) register n. */
static rtx *reg_last_set_value;
/* Record the value of label_tick when the value for register n is placed in
reg_last_set_value[n]. */
static int *reg_last_set_label;
/* Record the value of label_tick when an expression involving register n
is placed in reg_last_set_value. */
static int *reg_last_set_table_tick;
/* Set non-zero if references to register n in expressions should not be
used. */
static char *reg_last_set_invalid;
/* Incremented for each label. */
static int label_tick;
/* 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 array 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. */
static unsigned HOST_WIDE_INT *reg_nonzero_bits;
/* Mode used to compute significance in reg_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 if we know that a register has some leading bits that are always
equal to the sign bit. */
static char *reg_sign_bit_copies;
/* Nonzero when reg_nonzero_bits and reg_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;
/* These arrays are maintained in parallel with reg_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. */
static enum machine_mode *reg_last_set_mode;
static unsigned HOST_WIDE_INT *reg_last_set_nonzero_bits;
static char *reg_last_set_sign_bit_copies;
/* Record one modification to rtl structure
to be undone by storing old_contents into *where.
is_int is 1 if the contents are an int. */
struct undo
{
struct undo *next;
int is_int;
union {rtx r; int i;} 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.
storage is nonzero if we must undo the allocation of new storage.
The value of storage is what to pass to obfree.
other_insn is nonzero if we have modified some other insn in the process
of working on subst_insn. It must be verified too.
previous_undos is the value of undobuf.undos when we started processing
this substitution. This will prevent gen_rtx_combine from re-used a piece
from the previous expression. Doing so can produce circular rtl
structures. */
struct undobuf
{
char *storage;
struct undo *undos;
struct undo *frees;
struct undo *previous_undos;
rtx other_insn;
};
static struct undobuf undobuf;
/* 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. */
#define SUBST(INTO, NEWVAL) \
do { rtx _new = (NEWVAL); \
struct undo *_buf; \
\
if (undobuf.frees) \
_buf = undobuf.frees, undobuf.frees = _buf->next; \
else \
_buf = (struct undo *) xmalloc (sizeof (struct undo)); \
\
_buf->is_int = 0; \
_buf->where.r = &INTO; \
_buf->old_contents.r = INTO; \
INTO = _new; \
if (_buf->old_contents.r == INTO) \
_buf->next = undobuf.frees, undobuf.frees = _buf; \
else \
_buf->next = undobuf.undos, undobuf.undos = _buf; \
} while (0)
/* 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. */
#define SUBST_INT(INTO, NEWVAL) \
do { struct undo *_buf; \
\
if (undobuf.frees) \
_buf = undobuf.frees, undobuf.frees = _buf->next; \
else \
_buf = (struct undo *) xmalloc (sizeof (struct undo)); \
\
_buf->is_int = 1; \
_buf->where.i = (int *) &INTO; \
_buf->old_contents.i = INTO; \
INTO = NEWVAL; \
if (_buf->old_contents.i == INTO) \
_buf->next = undobuf.frees, undobuf.frees = _buf; \
else \
_buf->next = undobuf.undos, undobuf.undos = _buf; \
} while (0)
/* Number of times the pseudo being substituted for
was found and replaced. */
static int n_occurrences;
static void init_reg_last_arrays PROTO((void));
static void setup_incoming_promotions PROTO((void));
static void set_nonzero_bits_and_sign_copies PROTO((rtx, rtx));
static int can_combine_p PROTO((rtx, rtx, rtx, rtx, rtx *, rtx *));
static int combinable_i3pat PROTO((rtx, rtx *, rtx, rtx, int, rtx *));
static rtx try_combine PROTO((rtx, rtx, rtx));
static void undo_all PROTO((void));
static rtx *find_split_point PROTO((rtx *, rtx));
static rtx subst PROTO((rtx, rtx, rtx, int, int));
static rtx simplify_rtx PROTO((rtx, enum machine_mode, int, int));
static rtx simplify_if_then_else PROTO((rtx));
static rtx simplify_set PROTO((rtx));
static rtx simplify_logical PROTO((rtx, int));
static rtx expand_compound_operation PROTO((rtx));
static rtx expand_field_assignment PROTO((rtx));
static rtx make_extraction PROTO((enum machine_mode, rtx, int, rtx, int,
int, int, int));
static rtx extract_left_shift PROTO((rtx, int));
static rtx make_compound_operation PROTO((rtx, enum rtx_code));
static int get_pos_from_mask PROTO((unsigned HOST_WIDE_INT, int *));
static rtx force_to_mode PROTO((rtx, enum machine_mode,
unsigned HOST_WIDE_INT, rtx, int));
static rtx if_then_else_cond PROTO((rtx, rtx *, rtx *));
static rtx known_cond PROTO((rtx, enum rtx_code, rtx, rtx));
static int rtx_equal_for_field_assignment_p PROTO((rtx, rtx));
static rtx make_field_assignment PROTO((rtx));
static rtx apply_distributive_law PROTO((rtx));
static rtx simplify_and_const_int PROTO((rtx, enum machine_mode, rtx,
unsigned HOST_WIDE_INT));
static unsigned HOST_WIDE_INT nonzero_bits PROTO((rtx, enum machine_mode));
static int num_sign_bit_copies PROTO((rtx, enum machine_mode));
static int merge_outer_ops PROTO((enum rtx_code *, HOST_WIDE_INT *,
enum rtx_code, HOST_WIDE_INT,
enum machine_mode, int *));
static rtx simplify_shift_const PROTO((rtx, enum rtx_code, enum machine_mode,
rtx, int));
static int recog_for_combine PROTO((rtx *, rtx, rtx *, int *));
static rtx gen_lowpart_for_combine PROTO((enum machine_mode, rtx));
static rtx gen_rtx_combine PVPROTO((enum rtx_code code, enum machine_mode mode,
...));
static rtx gen_binary PROTO((enum rtx_code, enum machine_mode,
rtx, rtx));
static rtx gen_unary PROTO((enum rtx_code, enum machine_mode,
enum machine_mode, rtx));
static enum rtx_code simplify_comparison PROTO((enum rtx_code, rtx *, rtx *));
static int reversible_comparison_p PROTO((rtx));
static void update_table_tick PROTO((rtx));
static void record_value_for_reg PROTO((rtx, rtx, rtx));
static void record_dead_and_set_regs_1 PROTO((rtx, rtx));
static void record_dead_and_set_regs PROTO((rtx));
static int get_last_value_validate PROTO((rtx *, rtx, int, int));
static rtx get_last_value PROTO((rtx));
static int use_crosses_set_p PROTO((rtx, int));
static void reg_dead_at_p_1 PROTO((rtx, rtx));
static int reg_dead_at_p PROTO((rtx, rtx));
static void move_deaths PROTO((rtx, rtx, int, rtx, rtx *));
static int reg_bitfield_target_p PROTO((rtx, rtx));
static void distribute_notes PROTO((rtx, rtx, rtx, rtx, rtx, rtx));
static void distribute_links PROTO((rtx));
static void mark_used_regs_combine PROTO((rtx));
static int insn_cuid PROTO((rtx));
/* Main entry point for combiner. F is the first insn of the function.
NREGS is the first unused pseudo-reg number. */
void
combine_instructions (f, nregs)
rtx f;
int nregs;
{
register rtx insn, next, prev;
register int i;
register rtx links, nextlinks;
combine_attempts = 0;
combine_merges = 0;
combine_extras = 0;
combine_successes = 0;
undobuf.undos = undobuf.previous_undos = 0;
combine_max_regno = nregs;
reg_nonzero_bits
= (unsigned HOST_WIDE_INT *) alloca (nregs * sizeof (HOST_WIDE_INT));
reg_sign_bit_copies = (char *) alloca (nregs * sizeof (char));
bzero ((char *) reg_nonzero_bits, nregs * sizeof (HOST_WIDE_INT));
bzero (reg_sign_bit_copies, nregs * sizeof (char));
reg_last_death = (rtx *) alloca (nregs * sizeof (rtx));
reg_last_set = (rtx *) alloca (nregs * sizeof (rtx));
reg_last_set_value = (rtx *) alloca (nregs * sizeof (rtx));
reg_last_set_table_tick = (int *) alloca (nregs * sizeof (int));
reg_last_set_label = (int *) alloca (nregs * sizeof (int));
reg_last_set_invalid = (char *) alloca (nregs * sizeof (char));
reg_last_set_mode
= (enum machine_mode *) alloca (nregs * sizeof (enum machine_mode));
reg_last_set_nonzero_bits
= (unsigned HOST_WIDE_INT *) alloca (nregs * sizeof (HOST_WIDE_INT));
reg_last_set_sign_bit_copies
= (char *) alloca (nregs * sizeof (char));
init_reg_last_arrays ();
init_recog_no_volatile ();
/* Compute maximum uid value so uid_cuid can be allocated. */
for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
if (INSN_UID (insn) > i)
i = INSN_UID (insn);
uid_cuid = (int *) alloca ((i + 1) * sizeof (int));
max_uid_cuid = i;
nonzero_bits_mode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0);
/* Don't use reg_nonzero_bits when computing it. This can cause problems
when, for example, we have j <<= 1 in a loop. */
nonzero_sign_valid = 0;
/* Compute the mapping from uids to cuids.
Cuids are numbers assigned to insns, like uids,
except that cuids increase monotonically through the code.
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 = 1;
/* We need to initialize it here, because record_dead_and_set_regs may call
get_last_value. */
subst_prev_insn = NULL_RTX;
setup_incoming_promotions ();
for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
{
uid_cuid[INSN_UID (insn)] = ++i;
subst_low_cuid = i;
subst_insn = insn;
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
note_stores (PATTERN (insn), set_nonzero_bits_and_sign_copies);
record_dead_and_set_regs (insn);
#ifdef AUTO_INC_DEC
for (links = REG_NOTES (insn); links; links = XEXP (links, 1))
if (REG_NOTE_KIND (links) == REG_INC)
set_nonzero_bits_and_sign_copies (XEXP (links, 0), NULL_RTX);
#endif
}
if (GET_CODE (insn) == CODE_LABEL)
label_tick++;
}
nonzero_sign_valid = 1;
/* Now scan all the insns in forward order. */
this_basic_block = -1;
label_tick = 1;
last_call_cuid = 0;
mem_last_set = 0;
init_reg_last_arrays ();
setup_incoming_promotions ();
for (insn = f; insn; insn = next ? next : NEXT_INSN (insn))
{
next = 0;
/* If INSN starts a new basic block, update our basic block number. */
if (this_basic_block + 1 < n_basic_blocks
&& basic_block_head[this_basic_block + 1] == insn)
this_basic_block++;
if (GET_CODE (insn) == CODE_LABEL)
label_tick++;
else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
/* 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)) != 0)
goto retry;
/* Try each sequence of three linked insns ending with this one. */
for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
for (nextlinks = LOG_LINKS (XEXP (links, 0)); nextlinks;
nextlinks = XEXP (nextlinks, 1))
if ((next = try_combine (insn, XEXP (links, 0),
XEXP (nextlinks, 0))) != 0)
goto retry;
#ifdef HAVE_cc0
/* 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 (GET_CODE (insn) == JUMP_INSN
&& (prev = prev_nonnote_insn (insn)) != 0
&& GET_CODE (prev) == INSN
&& sets_cc0_p (PATTERN (prev)))
{
if ((next = try_combine (insn, prev, NULL_RTX)) != 0)
goto retry;
for (nextlinks = LOG_LINKS (prev); nextlinks;
nextlinks = XEXP (nextlinks, 1))
if ((next = try_combine (insn, prev,
XEXP (nextlinks, 0))) != 0)
goto retry;
}
/* Do the same for an insn that explicitly references CC0. */
if (GET_CODE (insn) == INSN
&& (prev = prev_nonnote_insn (insn)) != 0
&& GET_CODE (prev) == INSN
&& sets_cc0_p (PATTERN (prev))
&& GET_CODE (PATTERN (insn)) == SET
&& reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (insn))))
{
if ((next = try_combine (insn, prev, NULL_RTX)) != 0)
goto retry;
for (nextlinks = LOG_LINKS (prev); nextlinks;
nextlinks = XEXP (nextlinks, 1))
if ((next = try_combine (insn, prev,
XEXP (nextlinks, 0))) != 0)
goto retry;
}
/* 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 (GET_CODE (XEXP (links, 0)) == INSN
&& GET_CODE (PATTERN (XEXP (links, 0))) == SET
&& reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (XEXP (links, 0))))
&& (prev = prev_nonnote_insn (XEXP (links, 0))) != 0
&& GET_CODE (prev) == INSN
&& sets_cc0_p (PATTERN (prev))
&& (next = try_combine (insn, XEXP (links, 0), prev)) != 0)
goto retry;
#endif
/* 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))) != 0)
goto retry;
if (GET_CODE (insn) != NOTE)
record_dead_and_set_regs (insn);
retry:
;
}
}
total_attempts += combine_attempts;
total_merges += combine_merges;
total_extras += combine_extras;
total_successes += combine_successes;
nonzero_sign_valid = 0;
}
/* Wipe the reg_last_xxx arrays in preparation for another pass. */
static void
init_reg_last_arrays ()
{
int nregs = combine_max_regno;
bzero ((char *) reg_last_death, nregs * sizeof (rtx));
bzero ((char *) reg_last_set, nregs * sizeof (rtx));
bzero ((char *) reg_last_set_value, nregs * sizeof (rtx));
bzero ((char *) reg_last_set_table_tick, nregs * sizeof (int));
bzero ((char *) reg_last_set_label, nregs * sizeof (int));
bzero (reg_last_set_invalid, nregs * sizeof (char));
bzero ((char *) reg_last_set_mode, nregs * sizeof (enum machine_mode));
bzero ((char *) reg_last_set_nonzero_bits, nregs * sizeof (HOST_WIDE_INT));
bzero (reg_last_set_sign_bit_copies, nregs * sizeof (char));
}
/* Set up any promoted values for incoming argument registers. */
static void
setup_incoming_promotions ()
{
#ifdef PROMOTE_FUNCTION_ARGS
int regno;
rtx reg;
enum machine_mode mode;
int unsignedp;
rtx first = get_insns ();
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (FUNCTION_ARG_REGNO_P (regno)
&& (reg = promoted_input_arg (regno, &mode, &unsignedp)) != 0)
record_value_for_reg (reg, first,
gen_rtx (unsignedp ? ZERO_EXTEND : SIGN_EXTEND,
GET_MODE (reg),
gen_rtx (CLOBBER, mode, const0_rtx)));
#endif
}
/* 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 (x, set)
rtx x;
rtx set;
{
int num;
if (GET_CODE (x) == REG
&& 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 (basic_block_live_at_start[0], REGNO (x))
&& GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT)
{
if (set == 0 || GET_CODE (set) == CLOBBER)
{
reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x));
reg_sign_bit_copies[REGNO (x)] = 1;
return;
}
/* 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_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
reg_nonzero_bits[REGNO (x)]
|= nonzero_bits (src, nonzero_bits_mode);
num = num_sign_bit_copies (SET_SRC (set), GET_MODE (x));
if (reg_sign_bit_copies[REGNO (x)] == 0
|| reg_sign_bit_copies[REGNO (x)] > num)
reg_sign_bit_copies[REGNO (x)] = num;
}
else
{
reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x));
reg_sign_bit_copies[REGNO (x)] = 1;
}
}
}
/* 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 (insn, i3, pred, succ, pdest, psrc)
rtx insn;
rtx i3;
rtx pred, succ;
rtx *pdest, *psrc;
{
int i;
rtx set = 0, src, dest;
rtx p, link;
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);
switch (GET_CODE (elt))
{
/* 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))
&& ! 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
/* If we couldn't eliminate a field assignment, we can't combine. */
|| GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == STRICT_LOW_PART
/* 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 REG_NO_CONFLICT sequence. */
|| (rtx_equal_p (src, dest) && find_reg_note (insn, REG_EQUAL, NULL_RTX))
/* Can't merge a function call. */
|| GET_CODE (src) == CALL
/* Don't eliminate a function call argument. */
|| (GET_CODE (i3) == CALL_INSN
&& (find_reg_fusage (i3, USE, dest)
|| (GET_CODE (dest) == REG
&& 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 combine the end of a libcall into anything. */
|| find_reg_note (insn, REG_RETVAL, 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; reg_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
&& (((GET_CODE (src) != MEM
|| ! find_reg_note (insn, REG_EQUIV, src))
&& use_crosses_set_p (src, INSN_CUID (insn)))
|| (GET_CODE (src) == ASM_OPERANDS && MEM_VOLATILE_P (src))
|| GET_CODE (src) == UNSPEC_VOLATILE))
/* If there is a REG_NO_CONFLICT note for DEST in I3 or SUCC, we get
better register allocation by not doing the combine. */
|| find_reg_note (i3, REG_NO_CONFLICT, dest)
|| (succ && find_reg_note (succ, REG_NO_CONFLICT, dest))
/* 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 special case, because it helps -fforce-addr a lot. */
|| (INSN_CUID (insn) < last_call_cuid && ! CONSTANT_P (src)))
return 0;
/* DEST must either be a REG or CC0. */
if (GET_CODE (dest) == REG)
{
/* 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.
This is the same test done in can_combine except that we don't test
if SRC is a CALL operation to permit a hard register with
SMALL_REGISTER_CLASSES, and that we have to take all_adjacent
into account. */
if (GET_CODE (src) == REG
&& ((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))
#ifdef SMALL_REGISTER_CLASSES
|| (SMALL_REGISTER_CLASSES
&& ((! all_adjacent && ! REG_USERVAR_P (src))
|| (FUNCTION_VALUE_REGNO_P (REGNO (src))
&& ! REG_USERVAR_P (src))))
#endif
))))
return 0;
}
else if (GET_CODE (dest) != CC0)
return 0;
/* Don't substitute for a register intended as a clobberable operand.
Similarly, don't substitute an expression containing a register that
will be clobbered in I3. */
if (GET_CODE (PATTERN (i3)) == PARALLEL)
for (i = XVECLEN (PATTERN (i3), 0) - 1; i >= 0; i--)
if (GET_CODE (XVECEXP (PATTERN (i3), 0, i)) == CLOBBER
&& (reg_overlap_mentioned_p (XEXP (XVECEXP (PATTERN (i3), 0, i), 0),
src)
|| rtx_equal_p (XEXP (XVECEXP (PATTERN (i3), 0, i), 0), dest)))
return 0;
/* If INSN contains anything volatile, or is an `asm' (whether volatile
or not), reject, unless nothing volatile comes between it and I3,
with the exception of SUCC. */
if (GET_CODE (src) == ASM_OPERANDS || volatile_refs_p (src))
for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))
if (GET_RTX_CLASS (GET_CODE (p)) == 'i'
&& p != succ && volatile_refs_p (PATTERN (p)))
return 0;
/* If 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 (GET_RTX_CLASS (GET_CODE (p)) == 'i'
&& p != succ && volatile_insn_p (PATTERN (p)))
return 0;
/* If INSN or I2 contains an autoincrement or autodecrement,
make sure that register is not used between there and I3,
and not already used in I3 either.
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
&& (GET_CODE (i3) == JUMP_INSN
|| reg_used_between_p (XEXP (link, 0), insn, i3)
|| reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i3))))
return 0;
#endif
#ifdef HAVE_cc0
/* 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 && GET_CODE (p) == INSN && 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 non-zero, it means that finding I1 in the source
of a SET must prevent combination from occurring.
On machines where SMALL_REGISTER_CLASSES is defined, we don't combine
if the destination of a SET is a hard register that isn't a user
variable.
Before doing the above check, we first try to expand a field assignment
into a set of logical operations.
If PI3_DEST_KILLED is non-zero, 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 (i3, loc, i2dest, i1dest, i1_not_in_src, pi3dest_killed)
rtx i3;
rtx *loc;
rtx i2dest;
rtx i1dest;
int i1_not_in_src;
rtx *pi3dest_killed;
{
rtx x = *loc;
if (GET_CODE (x) == SET)
{
rtx set = expand_field_assignment (x);
rtx dest = SET_DEST (set);
rtx src = SET_SRC (set);
rtx inner_dest = dest, inner_src = src;
SUBST (*loc, set);
while (GET_CODE (inner_dest) == STRICT_LOW_PART
|| GET_CODE (inner_dest) == SUBREG
|| GET_CODE (inner_dest) == ZERO_EXTRACT)
inner_dest = XEXP (inner_dest, 0);
/* We probably don't need this any more now that LIMIT_RELOAD_CLASS
was added. */
#if 0
while (GET_CODE (inner_src) == STRICT_LOW_PART
|| GET_CODE (inner_src) == SUBREG
|| GET_CODE (inner_src) == ZERO_EXTRACT)
inner_src = XEXP (inner_src, 0);
/* If it is better that two different modes keep two different pseudos,
avoid combining them. This avoids producing the following pattern
on a 386:
(set (subreg:SI (reg/v:QI 21) 0)
(lshiftrt:SI (reg/v:SI 20)
(const_int 24)))
If that were made, reload could not handle the pair of
reg 20/21, since it would try to get any GENERAL_REGS
but some of them don't handle QImode. */
if (rtx_equal_p (inner_src, i2dest)
&& GET_CODE (inner_dest) == REG
&& ! MODES_TIEABLE_P (GET_MODE (i2dest), GET_MODE (inner_dest)))
return 0;
#endif
/* Check for the case where I3 modifies its output, as
discussed above. */
if ((inner_dest != 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 that we
allow a hard register with SMALL_REGISTER_CLASSES if SRC is a
CALL operation.
Moreover, we can't test all_adjacent; we don't have to, since
this instruction will stay in place, thus we are not considering
to increase the lifetime of INNER_DEST. */
|| (GET_CODE (inner_dest) == REG
&& REGNO (inner_dest) < FIRST_PSEUDO_REGISTER
&& (! HARD_REGNO_MODE_OK (REGNO (inner_dest),
GET_MODE (inner_dest))
#ifdef SMALL_REGISTER_CLASSES
|| (SMALL_REGISTER_CLASSES
&& GET_CODE (src) != CALL && ! REG_USERVAR_P (inner_dest)
&& FUNCTION_VALUE_REGNO_P (REGNO (inner_dest)))
#endif
))
|| (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.
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. */
if (pi3dest_killed && GET_CODE (dest) == REG
&& reg_referenced_p (dest, PATTERN (i3))
&& REGNO (dest) != FRAME_POINTER_REGNUM
#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
&& REGNO (dest) != HARD_FRAME_POINTER_REGNUM
#endif
#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
&& (REGNO (dest) != ARG_POINTER_REGNUM
|| ! fixed_regs [REGNO (dest)])
#endif
&& REGNO (dest) != STACK_POINTER_REGNUM)
{
if (*pi3dest_killed)
return 0;
*pi3dest_killed = dest;
}
}
else if (GET_CODE (x) == PARALLEL)
{
int i;
for (i = 0; i < XVECLEN (x, 0); i++)
if (! combinable_i3pat (i3, &XVECEXP (x, 0, i), i2dest, i1dest,
i1_not_in_src, pi3dest_killed))
return 0;
}
return 1;
}
/* 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.
It 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. */
static rtx
try_combine (i3, i2, i1)
register rtx i3, i2, i1;
{
/* New patterns for I3 and I3, respectively. */
rtx newpat, newi2pat = 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 is 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, other_code_number;
/* 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 (I2), or a copy of it in certain cases. */
rtx i2pat;
/* 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 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;
/* Number of clobbers of SCRATCH we had to add. */
int i3_scratches = 0, i2_scratches = 0, other_scratches = 0;
int maxreg;
rtx temp;
register rtx link;
int i;
/* If any of I1, I2, and I3 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. We also can't do anything if I3 has a
REG_LIBCALL note since we don't want to disrupt the contiguity of a
libcall. */
if (GET_RTX_CLASS (GET_CODE (i3)) != 'i'
|| GET_RTX_CLASS (GET_CODE (i2)) != 'i'
|| (i1 && GET_RTX_CLASS (GET_CODE (i1)) != 'i')
|| find_reg_note (i3, REG_LIBCALL, NULL_RTX))
return 0;
combine_attempts++;
undobuf.undos = undobuf.previous_undos = 0;
undobuf.other_insn = 0;
/* Save the current high-water-mark so we can free storage if we didn't
accept this combination. */
undobuf.storage = (char *) oballoc (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 && INSN_CUID (i1) > INSN_CUID (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 has multiple sets,
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.
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 && GET_CODE (i3) == INSN && GET_CODE (PATTERN (i3)) == SET
&& GET_CODE (SET_SRC (PATTERN (i3))) == REG
&& REGNO (SET_SRC (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER
#ifdef SMALL_REGISTER_CLASSES
&& (! SMALL_REGISTER_CLASSES
|| GET_CODE (SET_DEST (PATTERN (i3))) != REG
|| REGNO (SET_DEST (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER
|| REG_USERVAR_P (SET_DEST (PATTERN (i3))))
#endif
&& 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 (SET_DEST (XVECEXP (p2, 0, i)) == SET_SRC (PATTERN (i3)))
{
combine_merges++;
subst_insn = i3;
subst_low_cuid = INSN_CUID (i2);
added_sets_2 = added_sets_1 = 0;
i2dest = SET_SRC (PATTERN (i3));
/* 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;
}
}
#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
&& GET_CODE (SET_DEST (XVECEXP (PATTERN (i2), 0, 1))) == REG
&& rtx_equal_p (XEXP (SET_SRC (XVECEXP (PATTERN (i2), 0, 0)), 0),
SET_SRC (XVECEXP (PATTERN (i2), 0, 1))))
{
for (i = XVECLEN (PATTERN (i2), 0) - 1; i >= 2; i--)
if (GET_CODE (XVECEXP (PATTERN (i2), 0, i)) != CLOBBER)
break;
if (i == 1)
{
/* We make I1 with the same INSN_UID as I2. This gives it
the same INSN_CUID 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. */
subst_prev_insn = i1
= gen_rtx (INSN, VOIDmode, INSN_UID (i2), 0, i2,
XVECEXP (PATTERN (i2), 0, 1), -1, 0, 0);
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);
/* 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
&& GET_CODE (SET_SRC (PATTERN (i3))) == REG
&& GET_CODE (SET_DEST (PATTERN (i3))) == MEM
&& (GET_CODE (XEXP (SET_DEST (PATTERN (i3)), 0)) == POST_INC
|| GET_CODE (XEXP (SET_DEST (PATTERN (i3)), 0)) == POST_DEC)))
/* 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. */
i2pat = (GET_CODE (PATTERN (i2)) == PARALLEL
? gen_rtx (SET, VOIDmode, i2dest, i2src)
: PATTERN (i2));
if (added_sets_2)
i2pat = copy_rtx (i2pat);
combine_merges++;
/* Substitute in the latest insn for the regs set by the earlier ones. */
maxreg = max_reg_num ();
subst_insn = i3;
/* 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. */
if (flag_expensive_optimizations)
{
/* Pass pc_rtx so no substitutions are done, just simplifications.
The cases that we are interested in here do not involve the few
cases were is_replaced is checked. */
if (i1)
{
subst_low_cuid = INSN_CUID (i1);
i1src = subst (i1src, pc_rtx, pc_rtx, 0, 0);
}
else
{
subst_low_cuid = INSN_CUID (i2);
i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0);
}
undobuf.previous_undos = undobuf.undos;
}
#ifndef HAVE_cc0
/* 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))
{
rtx *cc_use;
enum machine_mode compare_mode;
newpat = PATTERN (i3);
SUBST (XEXP (SET_SRC (newpat), 0), i2src);
i2_is_used = 1;
#ifdef EXTRA_CC_MODES
/* 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))))
{
int regno = REGNO (SET_DEST (newpat));
rtx new_dest = gen_rtx (REG, compare_mode, regno);
if (regno < FIRST_PSEUDO_REGISTER
|| (REG_N_SETS (regno) == 1 && ! added_sets_2
&& ! REG_USERVAR_P (SET_DEST (newpat))))
{
if (regno >= FIRST_PSEUDO_REGISTER)
SUBST (regno_reg_rtx[regno], new_dest);
SUBST (SET_DEST (newpat), new_dest);
SUBST (XEXP (*cc_use, 0), new_dest);
SUBST (SET_SRC (newpat),
gen_rtx_combine (COMPARE, compare_mode,
i2src, const0_rtx));
}
else
undobuf.other_insn = 0;
}
#endif
}
else
#endif
{
n_occurrences = 0; /* `subst' 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_cuid = INSN_CUID (i2);
newpat = subst (PATTERN (i3), i2dest, i2src, 0,
! i1_feeds_i3 && i1dest_in_i1src);
undobuf.previous_undos = undobuf.undos;
/* 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)
{
/* 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. */
if (! combinable_i3pat (NULL_RTX, &newpat, i1dest, NULL_RTX,
0, NULL_PTR))
{
undo_all ();
return 0;
}
n_occurrences = 0;
subst_low_cuid = INSN_CUID (i1);
newpat = subst (newpat, i1dest, i1src, 0, 0);
undobuf.previous_undos = undobuf.undos;
}
/* 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 (we used to abort, but there's
really no reason to). */
|| 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));
bcopy ((char *) &old->elem[0], (char *) XVEC (newpat, 0)->elem,
sizeof (old->elem[0]) * old->num_elem);
}
else
{
rtx old = newpat;
total_sets = 1 + added_sets_1 + added_sets_2;
newpat = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (total_sets));
XVECEXP (newpat, 0, 0) = old;
}
if (added_sets_1)
XVECEXP (newpat, 0, --total_sets)
= (GET_CODE (PATTERN (i1)) == PARALLEL
? gen_rtx (SET, VOIDmode, i1dest, i1src) : PATTERN (i1));
if (added_sets_2)
{
/* If 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);
}
}
/* We come here when we are replacing a destination in I2 with the
destination of I3. */
validate_replacement:
/* Note which hard regs this insn has as inputs. */
mark_used_regs_combine (newpat);
/* Is the result of combination a valid instruction? */
insn_code_number
= recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
/* 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. 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. 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 && GET_CODE (newpat) == PARALLEL
&& XVECLEN (newpat, 0) == 2
&& GET_CODE (XVECEXP (newpat, 0, 0)) == SET
&& GET_CODE (XVECEXP (newpat, 0, 1)) == SET
&& GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) == REG
&& find_reg_note (i3, REG_UNUSED, SET_DEST (XVECEXP (newpat, 0, 1)))
&& ! side_effects_p (SET_SRC (XVECEXP (newpat, 0, 1)))
&& asm_noperands (newpat) < 0)
{
newpat = XVECEXP (newpat, 0, 0);
insn_code_number
= recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
}
else if (insn_code_number < 0 && GET_CODE (newpat) == PARALLEL
&& XVECLEN (newpat, 0) == 2
&& GET_CODE (XVECEXP (newpat, 0, 0)) == SET
&& GET_CODE (XVECEXP (newpat, 0, 1)) == SET
&& GET_CODE (SET_DEST (XVECEXP (newpat, 0, 0))) == REG
&& find_reg_note (i3, REG_UNUSED, SET_DEST (XVECEXP (newpat, 0, 0)))
&& ! side_effects_p (SET_SRC (XVECEXP (newpat, 0, 0)))
&& asm_noperands (newpat) < 0)
{
newpat = XVECEXP (newpat, 0, 1);
insn_code_number
= recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
}
/* 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 m_split, *split;
rtx ni2dest = i2dest;
/* 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 = 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 (ni2dest, newpat))
{
/* If I2DEST is a hard register or the only use of a pseudo,
we can change its mode. */
if (GET_MODE (SET_DEST (newpat)) != GET_MODE (i2dest)
&& GET_MODE (SET_DEST (newpat)) != VOIDmode
&& GET_CODE (i2dest) == REG
&& (REGNO (i2dest) < FIRST_PSEUDO_REGISTER
|| (REG_N_SETS (REGNO (i2dest)) == 1 && ! added_sets_2
&& ! REG_USERVAR_P (i2dest))))
ni2dest = gen_rtx (REG, GET_MODE (SET_DEST (newpat)),
REGNO (i2dest));
m_split = split_insns (gen_rtx (PARALLEL, VOIDmode,
gen_rtvec (2, newpat,
gen_rtx (CLOBBER,
VOIDmode,
ni2dest))),
i3);
}
if (m_split && GET_CODE (m_split) == SEQUENCE
&& XVECLEN (m_split, 0) == 2
&& (next_real_insn (i2) == i3
|| ! use_crosses_set_p (PATTERN (XVECEXP (m_split, 0, 0)),
INSN_CUID (i2))))
{
rtx i2set, i3set;
rtx newi3pat = PATTERN (XVECEXP (m_split, 0, 1));
newi2pat = PATTERN (XVECEXP (m_split, 0, 0));
i3set = single_set (XVECEXP (m_split, 0, 1));
i2set = single_set (XVECEXP (m_split, 0, 0));
/* In case we changed the mode of I2DEST, replace it in the
pseudo-register table here. We can't do it above in case this
code doesn't get executed and we do a split the other way. */
if (REGNO (i2dest) >= FIRST_PSEUDO_REGISTER)
SUBST (regno_reg_rtx[REGNO (i2dest)], ni2dest);
i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes,
&i2_scratches);
/* 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,
&i3_scratches);
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 (GET_CODE (new_i3_dest) == REG
&& GET_CODE (new_i2_dest) == REG
&& REGNO (new_i3_dest) == REGNO (new_i2_dest))
REG_N_SETS (REGNO (new_i2_dest))++;
}
}
/* If 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
&& GET_CODE (i2dest) == REG
#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. */
&& (GET_MODE (*split) == GET_MODE (i2dest)
|| GET_MODE (*split) == VOIDmode
|| REGNO (i2dest) < FIRST_PSEUDO_REGISTER
|| (REG_N_SETS (REGNO (i2dest)) == 1 && ! added_sets_2
&& ! REG_USERVAR_P (i2dest)))
&& (next_real_insn (i2) == i3
|| ! use_crosses_set_p (*split, INSN_CUID (i2)))
/* 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);
/* 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)
{
newdest = gen_rtx (REG, split_mode, REGNO (i2dest));
if (REGNO (i2dest) >= FIRST_PSEUDO_REGISTER)
SUBST (regno_reg_rtx[REGNO (i2dest)], newdest);
}
/* 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
&& (i = exact_log2 (INTVAL (XEXP (*split, 1)))) >= 0)
{
SUBST (*split, gen_rtx_combine (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 && GET_CODE (SUBREG_REG (*split)) == MEM)
SUBST (*split, gen_rtx_combine (ZERO_EXTEND, split_mode,
XEXP (*split, 0)));
#endif
newi2pat = gen_rtx_combine (SET, VOIDmode, newdest, *split);
SUBST (*split, newdest);
i2_code_number
= recog_for_combine (&newi2pat, i2, &new_i2_notes, &i2_scratches);
/* 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, &i3_scratches);
}
}
/* 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 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_CODE (XVECEXP (newpat, 0, 1)) == SET
&& rtx_equal_p (SET_SRC (XVECEXP (newpat, 0, 1)),
XEXP (SET_SRC (XVECEXP (newpat, 0, 0)), 0))
&& ! use_crosses_set_p (SET_SRC (XVECEXP (newpat, 0, 1)),
INSN_CUID (i2))
&& GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != ZERO_EXTRACT
&& GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != STRICT_LOW_PART
&& ! (temp = SET_DEST (XVECEXP (newpat, 0, 1)),
(GET_CODE (temp) == REG
&& reg_nonzero_bits[REGNO (temp)] != 0
&& GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD
&& GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT
&& (reg_nonzero_bits[REGNO (temp)]
!= GET_MODE_MASK (word_mode))))
&& ! (GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) == SUBREG
&& (temp = SUBREG_REG (SET_DEST (XVECEXP (newpat, 0, 1))),
(GET_CODE (temp) == REG
&& reg_nonzero_bits[REGNO (temp)] != 0
&& GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD
&& GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT
&& (reg_nonzero_bits[REGNO (temp)]
!= GET_MODE_MASK (word_mode)))))
&& ! reg_overlap_mentioned_p (SET_DEST (XVECEXP (newpat, 0, 1)),
SET_SRC (XVECEXP (newpat, 0, 1)))
&& ! find_reg_note (i3, REG_UNUSED,
SET_DEST (XVECEXP (newpat, 0, 0))))
{
rtx ni2dest;
newi2pat = XVECEXP (newpat, 0, 0);
ni2dest = SET_DEST (XVECEXP (newpat, 0, 0));
newpat = XVECEXP (newpat, 0, 1);
SUBST (SET_SRC (newpat),
gen_lowpart_for_combine (GET_MODE (SET_SRC (newpat)), ni2dest));
i2_code_number
= recog_for_combine (&newi2pat, i2, &new_i2_notes, &i2_scratches);
if (i2_code_number >= 0)
insn_code_number
= recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
if (insn_code_number >= 0)
{
rtx insn;
rtx link;
/* If we will be able to accept this, we have made a change to the
destination of I3. This can invalidate a LOG_LINKS pointing
to I3. No other part of combine.c makes such a transformation.
The new I3 will have a destination that was previously the
destination of I1 or I2 and which was used in i2 or I3. Call
distribute_links to make a LOG_LINK from the next use of
that destination. */
PATTERN (i3) = newpat;
distribute_links (gen_rtx (INSN_LIST, VOIDmode, i3, NULL_RTX));
/* I3 now uses what used to be its destination and which is
now I2's destination. That means 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. */
for (insn = NEXT_INSN (i3);
insn && (this_basic_block == n_basic_blocks - 1
|| insn != basic_block_head[this_basic_block + 1]);
insn = NEXT_INSN (insn))
{
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
&& reg_referenced_p (ni2dest, PATTERN (insn)))
{
for (link = LOG_LINKS (insn); link;
link = XEXP (link, 1))
if (XEXP (link, 0) == i3)
XEXP (link, 0) = i1;
break;
}
}
}
}
/* 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)),
INSN_CUID (i2))
/* Don't pass sets with (USE (MEM ...)) dests to the following. */
&& GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != USE
&& GET_CODE (SET_DEST (XVECEXP (newpat, 0, 0))) != USE
&& ! reg_referenced_p (SET_DEST (XVECEXP (newpat, 0, 1)),
XVECEXP (newpat, 0, 0))
&& ! reg_referenced_p (SET_DEST (XVECEXP (newpat, 0, 0)),
XVECEXP (newpat, 0, 1)))
{
newi2pat = XVECEXP (newpat, 0, 1);
newpat = XVECEXP (newpat, 0, 0);
i2_code_number
= recog_for_combine (&newi2pat, i2, &new_i2_notes, &i2_scratches);
if (i2_code_number >= 0)
insn_code_number
= recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
}
/* 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)
{
rtx other_pat = PATTERN (undobuf.other_insn);
rtx new_other_notes;
rtx note, next;
CLEAR_HARD_REG_SET (newpat_used_regs);
other_code_number
= recog_for_combine (&other_pat, undobuf.other_insn,
&new_other_notes, &other_scratches);
if (other_code_number < 0 && ! check_asm_operands (other_pat))
{
undo_all ();
return 0;
}
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)))
{
if (GET_CODE (XEXP (note, 0)) == REG)
REG_N_DEATHS (REGNO (XEXP (note, 0)))--;
remove_note (undobuf.other_insn, note);
}
}
for (note = new_other_notes; note; note = XEXP (note, 1))
if (GET_CODE (XEXP (note, 0)) == REG)
REG_N_DEATHS (REGNO (XEXP (note, 0)))++;
distribute_notes (new_other_notes, undobuf.other_insn,
undobuf.other_insn, NULL_RTX, NULL_RTX, NULL_RTX);
}
/* We now know that we can do this combination. Merge the insns and
update the status of registers and LOG_LINKS. */
{
rtx i3notes, i2notes, i1notes = 0;
rtx i3links, i2links, i1links = 0;
rtx midnotes = 0;
register int regno;
/* Compute which registers we expect to eliminate. */
rtx elim_i2 = (newi2pat || i2dest_in_i2src || i2dest_in_i1src
? 0 : i2dest);
rtx elim_i1 = i1 == 0 || i1dest_in_i1src ? 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 (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 (SET_DEST (XVECEXP (PATTERN (i2), 0, i))) == REG
&& SET_DEST (XVECEXP (PATTERN (i2), 0, i)) != i2dest
&& ! find_reg_note (i2, REG_UNUSED,
SET_DEST (XVECEXP (PATTERN (i2), 0, i))))
for (temp = NEXT_INSN (i2);
temp && (this_basic_block == n_basic_blocks - 1
|| basic_block_head[this_basic_block] != temp);
temp = NEXT_INSN (temp))
if (temp != i3 && GET_RTX_CLASS (GET_CODE (temp)) == 'i')
for (link = LOG_LINKS (temp); link; link = XEXP (link, 1))
if (XEXP (link, 0) == i2)
XEXP (link, 0) = i3;
if (i3notes)
{
rtx link = i3notes;
while (XEXP (link, 1))
link = XEXP (link, 1);
XEXP (link, 1) = i2notes;
}
else
i3notes = i2notes;
i2notes = 0;
}
LOG_LINKS (i3) = 0;
REG_NOTES (i3) = 0;
LOG_LINKS (i2) = 0;
REG_NOTES (i2) = 0;
if (newi2pat)
{
INSN_CODE (i2) = i2_code_number;
PATTERN (i2) = newi2pat;
}
else
{
PUT_CODE (i2, NOTE);
NOTE_LINE_NUMBER (i2) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (i2) = 0;
}
if (i1)
{
LOG_LINKS (i1) = 0;
REG_NOTES (i1) = 0;
PUT_CODE (i1, NOTE);
NOTE_LINE_NUMBER (i1) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (i1) = 0;
}
/* 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, INSN_CUID (i1), i2, &midnotes);
move_deaths (newpat, newi2pat, INSN_CUID (i1), i3, &midnotes);
}
else
move_deaths (newpat, NULL_RTX, i1 ? INSN_CUID (i1) : INSN_CUID (i2),
i3, &midnotes);
/* 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. We have not counted the notes in
reg_n_deaths yet, so we need to do so now. */
if (newi2pat && new_i2_notes)
{
for (temp = new_i2_notes; temp; temp = XEXP (temp, 1))
if (GET_CODE (XEXP (temp, 0)) == REG)
REG_N_DEATHS (REGNO (XEXP (temp, 0)))++;
distribute_notes (new_i2_notes, i2, i2, NULL_RTX, NULL_RTX, NULL_RTX);
}
if (new_i3_notes)
{
for (temp = new_i3_notes; temp; temp = XEXP (temp, 1))
if (GET_CODE (XEXP (temp, 0)) == REG)
REG_N_DEATHS (REGNO (XEXP (temp, 0)))++;
distribute_notes (new_i3_notes, i3, i3, NULL_RTX, NULL_RTX, NULL_RTX);
}
/* If I3DEST was used in I3SRC, it really died in I3. We may need to
put a REG_DEAD note for it somewhere. 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 (GET_CODE (i3dest_killed) == REG)
REG_N_DEATHS (REGNO (i3dest_killed))++;
distribute_notes (gen_rtx (EXPR_LIST, REG_DEAD, i3dest_killed,
NULL_RTX),
NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
NULL_RTX, NULL_RTX);
}
/* For I2 and I1, we have to be careful. If NEWI2PAT exists and sets
I2DEST or I1DEST, the death must be somewhere before I2, not I3. If
we passed I3 in that case, it might delete I2. */
if (i2dest_in_i2src)
{
if (GET_CODE (i2dest) == REG)
REG_N_DEATHS (REGNO (i2dest))++;
if (newi2pat && reg_set_p (i2dest, newi2pat))
distribute_notes (gen_rtx (EXPR_LIST, REG_DEAD, i2dest, NULL_RTX),
NULL_RTX, i2, NULL_RTX, NULL_RTX, NULL_RTX);
else
distribute_notes (gen_rtx (EXPR_LIST, REG_DEAD, i2dest, NULL_RTX),
NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
NULL_RTX, NULL_RTX);
}
if (i1dest_in_i1src)
{
if (GET_CODE (i1dest) == REG)
REG_N_DEATHS (REGNO (i1dest))++;
if (newi2pat && reg_set_p (i1dest, newi2pat))
distribute_notes (gen_rtx (EXPR_LIST, REG_DEAD, i1dest, NULL_RTX),
NULL_RTX, i2, NULL_RTX, NULL_RTX, NULL_RTX);
else
distribute_notes (gen_rtx (EXPR_LIST, REG_DEAD, i1dest, NULL_RTX),
NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
NULL_RTX, NULL_RTX);
}
distribute_links (i3links);
distribute_links (i2links);
distribute_links (i1links);
if (GET_CODE (i2dest) == REG)
{
rtx link;
rtx i2_insn = 0, i2_val = 0, set;
/* 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);
REG_N_SETS (regno)--;
if (REG_N_SETS (regno) == 0
&& ! REGNO_REG_SET_P (basic_block_live_at_start[0], regno))
REG_N_REFS (regno) = 0;
}
}
if (i1 && GET_CODE (i1dest) == REG)
{
rtx link;
rtx i1_insn = 0, i1_val = 0, set;
for (link = LOG_LINKS (i3); link; link = XEXP (link, 1))
if ((set = single_set (XEXP (link, 0))) != 0
&& rtx_equal_p (i1dest, SET_DEST (set)))
i1_insn = XEXP (link, 0), i1_val = SET_SRC (set);
record_value_for_reg (i1dest, i1_insn, i1_val);
regno = REGNO (i1dest);
if (! added_sets_1 && ! i1dest_in_i1src)
{
REG_N_SETS (regno)--;
if (REG_N_SETS (regno) == 0
&& ! REGNO_REG_SET_P (basic_block_live_at_start[0], regno))
REG_N_REFS (regno) = 0;
}
}
/* Update reg_nonzero_bits et al for any changes that may have been made
to this insn. */
note_stores (newpat, set_nonzero_bits_and_sign_copies);
if (newi2pat)
note_stores (newi2pat, set_nonzero_bits_and_sign_copies);
/* If we added any (clobber (scratch)), add them to the max for a
block. This is a very pessimistic calculation, since we might
have had them already and this might not be the worst block, but
it's not worth doing any better. */
max_scratch += i3_scratches + i2_scratches + other_scratches;
/* 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 ((GET_CODE (newpat) == RETURN || simplejump_p (i3))
&& ((temp = next_nonnote_insn (i3)) == NULL_RTX
|| GET_CODE (temp) != BARRIER))
emit_barrier_after (i3);
}
combine_successes++;
/* Clear this here, so that subsequent get_last_value calls are not
affected. */
subst_prev_insn = NULL_RTX;
if (added_links_insn
&& (newi2pat == 0 || INSN_CUID (added_links_insn) < INSN_CUID (i2))
&& INSN_CUID (added_links_insn) < INSN_CUID (i3))
return added_links_insn;
else
return newi2pat ? i2 : i3;
}
/* Undo all the modifications recorded in undobuf. */
static void
undo_all ()
{
struct undo *undo, *next;
for (undo = undobuf.undos; undo; undo = next)
{
next = undo->next;
if (undo->is_int)
*undo->where.i = undo->old_contents.i;
else
*undo->where.r = undo->old_contents.r;
undo->next = undobuf.frees;
undobuf.frees = undo;
}
obfree (undobuf.storage);
undobuf.undos = undobuf.previous_undos = 0;
/* Clear this here, so that subsequent get_last_value calls are not
affected. */
subst_prev_insn = NULL_RTX;
}
/* 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 (loc, insn)
rtx *loc;
rtx insn;
{
rtx x = *loc;
enum rtx_code code = GET_CODE (x);
rtx *split;
int len = 0, pos, unsignedp;
rtx inner;
/* 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 (GET_CODE (SUBREG_REG (x)) == MEM)
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_combine (LO_SUM, Pmode,
gen_rtx_combine (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 = 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 && XVECLEN (seq, 0) == 2
&& GET_CODE (XVECEXP (seq, 0, 0)) == INSN
&& GET_CODE (PATTERN (XVECEXP (seq, 0, 0))) == SET
&& SET_DEST (PATTERN (XVECEXP (seq, 0, 0))) == reg
&& ! reg_mentioned_p (reg,
SET_SRC (PATTERN (XVECEXP (seq, 0, 0))))
&& GET_CODE (XVECEXP (seq, 0, 1)) == INSN
&& GET_CODE (PATTERN (XVECEXP (seq, 0, 1))) == SET
&& SET_DEST (PATTERN (XVECEXP (seq, 0, 1))) == reg
&& memory_address_p (GET_MODE (x),
SET_SRC (PATTERN (XVECEXP (seq, 0, 1)))))
{
rtx src1 = SET_SRC (PATTERN (XVECEXP (seq, 0, 0)));
rtx src2 = SET_SRC (PATTERN (XVECEXP (seq, 0, 1)));
/* 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. */
src2 = replace_rtx (src2, reg, src1);
split = 0;
if (XEXP (src2, 0) == src1)
split = &XEXP (src2, 0);
else if (GET_RTX_FORMAT (GET_CODE (XEXP (src2, 0)))[0] == 'e'
&& XEXP (XEXP (src2, 0), 0) == src1)
split = &XEXP (XEXP (src2, 0), 0);
if (split)
{
SUBST (XEXP (x, 0), src2);
return split;
}
}
/* If that didn't work, perhaps the first operand is complex and
needs to be computed separately, so make a split point there.
This will occur on machines that just support REG + CONST
and have a constant moved through some previous computation. */
else if (GET_RTX_CLASS (GET_CODE (XEXP (XEXP (x, 0), 0))) != 'o'
&& ! (GET_CODE (XEXP (XEXP (x, 0), 0)) == SUBREG
&& (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (XEXP (x, 0), 0))))
== 'o')))
return &XEXP (XEXP (x, 0), 0);
}
break;
case SET:
#ifdef HAVE_cc0
/* If SET_DEST is CC0 and SET_SRC is not an operand, a COMPARE, or a
ZERO_EXTRACT, the most likely reason why this doesn't match is that
we need to put the operand into a register. So split at that
point. */
if (SET_DEST (x) == cc0_rtx
&& GET_CODE (SET_SRC (x)) != COMPARE
&& GET_CODE (SET_SRC (x)) != ZERO_EXTRACT
&& GET_RTX_CLASS (GET_CODE (SET_SRC (x))) != 'o'
&& ! (GET_CODE (SET_SRC (x)) == SUBREG
&& GET_RTX_CLASS (GET_CODE (SUBREG_REG (SET_SRC (x)))) == 'o'))
return &SET_SRC (x);
#endif
/* See if we can split SET_SRC as it stands. */
split = find_split_point (&SET_SRC (x), insn);
if (split && split != &SET_SRC (x))
return split;
/* See if we can split SET_DEST as it stands. */
split = find_split_point (&SET_DEST (x), insn);
if (split && split != &SET_DEST (x))
return split;
/* See if this is a bitfield assignment with everything constant. If
so, this is an IOR of an AND, so split it into that. */
if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT
&& (GET_MODE_BITSIZE (GET_MODE (XEXP (SET_DEST (x), 0)))
<= HOST_BITS_PER_WIDE_INT)
&& GET_CODE (XEXP (SET_DEST (x), 1)) == CONST_INT
&& GET_CODE (XEXP (SET_DEST (x), 2)) == CONST_INT
&& GET_CODE (SET_SRC (x)) == CONST_INT
&& ((INTVAL (XEXP (SET_DEST (x), 1))
+ INTVAL (XEXP (SET_DEST (x), 2)))
<= GET_MODE_BITSIZE (GET_MODE (XEXP (SET_DEST (x), 0))))
&& ! side_effects_p (XEXP (SET_DEST (x), 0)))
{
int pos = INTVAL (XEXP (SET_DEST (x), 2));
int len = INTVAL (XEXP (SET_DEST (x), 1));
int src = INTVAL (SET_SRC (x));
rtx dest = XEXP (SET_DEST (x), 0);
enum machine_mode mode = GET_MODE (dest);
unsigned HOST_WIDE_INT mask = ((HOST_WIDE_INT) 1 << len) - 1;
if (BITS_BIG_ENDIAN)
pos = GET_MODE_BITSIZE (mode) - len - pos;
if (src == mask)
SUBST (SET_SRC (x),
gen_binary (IOR, mode, dest, GEN_INT (src << pos)));
else
SUBST (SET_SRC (x),
gen_binary (IOR, mode,
gen_binary (AND, mode, dest,
GEN_INT (~ (mask << pos)
& GET_MODE_MASK (mode))),
GEN_INT (src << pos)));
SUBST (SET_DEST (x), dest);
split = find_split_point (&SET_SRC (x), insn);
if (split && split != &SET_SRC (x))
return split;
}
/* Otherwise, see if this is an operation that we can split into two.
If so, try to split that. */
code = GET_CODE (SET_SRC (x));
switch (code)
{
case AND:
/* If we are AND'ing with a large constant that is only a single
bit and the result is only being used in a context where we
need to know if it is zero or non-zero, replace it with a bit
extraction. This will avoid the large constant, which might
have taken more than one insn to make. If the constant were
not a valid argument to the AND but took only one insn to make,
this is no worse, but if it took more than one insn, it will
be better. */
if (GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT
&& GET_CODE (XEXP (SET_SRC (x), 0)) == REG
&& (pos = exact_log2 (INTVAL (XEXP (SET_SRC (x), 1)))) >= 7
&& GET_CODE (SET_DEST (x)) == REG
&& (split = find_single_use (SET_DEST (x), insn, NULL_PTR)) != 0
&& (GET_CODE (*split) == EQ || GET_CODE (*split) == NE)
&& XEXP (*split, 0) == SET_DEST (x)
&& XEXP (*split, 1) == const0_rtx)
{
rtx extraction = make_extraction (GET_MODE (SET_DEST (x)),
XEXP (SET_SRC (x), 0),
pos, NULL_RTX, 1, 1, 0, 0);
if (extraction != 0)
{
SUBST (SET_SRC (x), extraction);
return find_split_point (loc, insn);
}
}
break;
case NE:
/* if STORE_FLAG_VALUE is -1, this is (NE X 0) and only one bit of X
is known to be on, this can be converted into a NEG of a shift. */
if (STORE_FLAG_VALUE == -1 && XEXP (SET_SRC (x), 1) == const0_rtx
&& GET_MODE (SET_SRC (x)) == GET_MODE (XEXP (SET_SRC (x), 0))
&& 1 <= (pos = exact_log2
(nonzero_bits (XEXP (SET_SRC (x), 0),
GET_MODE (XEXP (SET_SRC (x), 0))))))
{
enum machine_mode mode = GET_MODE (XEXP (SET_SRC (x), 0));
SUBST (SET_SRC (x),
gen_rtx_combine (NEG, mode,
gen_rtx_combine (LSHIFTRT, mode,
XEXP (SET_SRC (x), 0),
GEN_INT (pos))));
split = find_split_point (&SET_SRC (x), insn);
if (split && split != &SET_SRC (x))
return split;
}
break;
case SIGN_EXTEND:
inner = XEXP (SET_SRC (x), 0);
/* We can't optimize if either mode is a partial integer
mode as we don't know how many bits are significant
in those modes. */
if (GET_MODE_CLASS (GET_MODE (inner)) == MODE_PARTIAL_INT
|| GET_MODE_CLASS (GET_MODE (SET_SRC (x))) == MODE_PARTIAL_INT)
break;
pos = 0;
len = GET_MODE_BITSIZE (GET_MODE (inner));
unsignedp = 0;
break;
case SIGN_EXTRACT:
case ZERO_EXTRACT:
if (GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT
&& GET_CODE (XEXP (SET_SRC (x), 2)) == CONST_INT)
{
inner = XEXP (SET_SRC (x), 0);
len = INTVAL (XEXP (SET_SRC (x), 1));
pos = INTVAL (XEXP (SET_SRC (x), 2));
if (BITS_BIG_ENDIAN)
pos = GET_MODE_BITSIZE (GET_MODE (inner)) - len - pos;
unsignedp = (code == ZERO_EXTRACT);
}
break;
}
if (len && pos >= 0 && pos + len <= GET_MODE_BITSIZE (GET_MODE (inner)))
{
enum machine_mode mode = GET_MODE (SET_SRC (x));
/* For unsigned, we have a choice of a shift followed by an
AND or two shifts. Use two shifts for field sizes where the
constant might be too large. We assume here that we can
always at least get 8-bit constants in an AND insn, which is
true for every current RISC. */
if (unsignedp && len <= 8)
{
SUBST (SET_SRC (x),
gen_rtx_combine
(AND, mode,
gen_rtx_combine (LSHIFTRT, mode,
gen_lowpart_for_combine (mode, inner),
GEN_INT (pos)),
GEN_INT (((HOST_WIDE_INT) 1 << len) - 1)));
split = find_split_point (&SET_SRC (x), insn);
if (split && split != &SET_SRC (x))
return split;
}
else
{
SUBST (SET_SRC (x),
gen_rtx_combine
(unsignedp ? LSHIFTRT : ASHIFTRT, mode,
gen_rtx_combine (ASHIFT, mode,
gen_lowpart_for_combine (mode, inner),
GEN_INT (GET_MODE_BITSIZE (mode)
- len - pos)),
GEN_INT (GET_MODE_BITSIZE (mode) - len)));
split = find_split_point (&SET_SRC (x), insn);
if (split && split != &SET_SRC (x))
return split;
}
}
/* See if this is a simple operation with a constant as the second
operand. It might be that this constant is out of range and hence
could be used as a split point. */
if ((GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '2'
|| GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == 'c'
|| GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '<')
&& CONSTANT_P (XEXP (SET_SRC (x), 1))
&& (GET_RTX_CLASS (GET_CODE (XEXP (SET_SRC (x), 0))) == 'o'
|| (GET_CODE (XEXP (SET_SRC (x), 0)) == SUBREG
&& (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (SET_SRC (x), 0))))
== 'o'))))
return &XEXP (SET_SRC (x), 1);
/* Finally, see if this is a simple operation with its first operand
not in a register. The operation might require this operand in a
register, so return it as a split point. We can always do this
because if the first operand were another operation, we would have
already found it as a split point. */
if ((GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '2'
|| GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == 'c'
|| GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '<'
|| GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '1')
&& ! register_operand (XEXP (SET_SRC (x), 0), VOIDmode))
return &XEXP (SET_SRC (x), 0);
return 0;
case AND:
case IOR:
/* We write NOR as (and (not A) (not B)), but if we don't have a NOR,
it is better to write this as (not (ior A B)) so we can split it.
Similarly for IOR. */
if (GET_CODE (XEXP (x, 0)) == NOT && GET_CODE (XEXP (x, 1)) == NOT)
{
SUBST (*loc,
gen_rtx_combine (NOT, GET_MODE (x),
gen_rtx_combine (code == IOR ? AND : IOR,
GET_MODE (x),
XEXP (XEXP (x, 0), 0),
XEXP (XEXP (x, 1), 0))));
return find_split_point (loc, insn);
}
/* Many RISC machines have a large set of logical insns. If the
second operand is a NOT, put it first so we will try to split the
other operand first. */
if (GET_CODE (XEXP (x, 1)) == NOT)
{
rtx tem = XEXP (x, 0);
SUBST (XEXP (x, 0), XEXP (x, 1));
SUBST (XEXP (x, 1), tem);
}
break;
}
/* Otherwise, select our actions depending on our rtx class. */
switch (GET_RTX_CLASS (code))
{
case 'b': /* This is ZERO_EXTRACT and SIGN_EXTRACT. */
case '3':
split = find_split_point (&XEXP (x, 2), insn);
if (split)
return split;
/* ... fall through ... */
case '2':
case 'c':
case '<':
split = find_split_point (&XEXP (x, 1), insn);
if (split)
return split;
/* ... fall through ... */
case '1':
/* Some machines have (and (shift ...) ...) insns. If X is not
an AND, but XEXP (X, 0) is, use it as our split point. */
if (GET_CODE (x) != AND && GET_CODE (XEXP (x, 0)) == AND)
return &XEXP (x, 0);
split = find_split_point (&XEXP (x, 0), insn);
if (split)
return split;
return loc;
}
/* Otherwise, we don't have a split point. */
return 0;
}
/* Throughout X, replace FROM with TO, and return the result.
The result is TO if X is FROM;
otherwise the result is X, but its contents may have been modified.
If they were modified, a record was made in undobuf so that
undo_all will (among other things) return X to its original state.
If the number of changes necessary is too much to record to undo,
the excess changes are not made, so the result is invalid.
The changes already made can still be undone.
undobuf.num_undo is incremented for such changes, so by testing that
the caller can tell whether the result is valid.
`n_occurrences' is incremented each time FROM is replaced.
IN_DEST is non-zero if we are processing the SET_DEST of a SET.
UNIQUE_COPY is non-zero if each substitution must be unique. We do this
by copying if `n_occurrences' is non-zero. */
static rtx
subst (x, from, to, in_dest, unique_copy)
register rtx x, from, to;
int in_dest;
int unique_copy;
{
register enum rtx_code code = GET_CODE (x);
enum machine_mode op0_mode = VOIDmode;
register char *fmt;
register int len, i;
rtx new;
/* Two expressions are equal if they are identical copies of a shared
RTX or if they are both registers with the same register number
and mode. */
#define COMBINE_RTX_EQUAL_P(X,Y) \
((X) == (Y) \
|| (GET_CODE (X) == REG && GET_CODE (Y) == REG \
&& REGNO (X) == REGNO (Y) && GET_MODE (X) == GET_MODE (Y)))
if (! in_dest && COMBINE_RTX_EQUAL_P (x, from))
{
n_occurrences++;
return (unique_copy && n_occurrences > 1 ? copy_rtx (to) : to);
}
/* If X and FROM are the same register but different modes, they will
not have been seen as equal above. However, flow.c will make a
LOG_LINKS entry for that case. If we do nothing, we will try to
rerecognize our original insn and, when it succeeds, we will
delete the feeding insn, which is incorrect.
So force this insn not to match in this (rare) case. */
if (! in_dest && code == REG && GET_CODE (from) == REG
&& REGNO (x) == REGNO (from))
return gen_rtx (CLOBBER, GET_MODE (x), const0_rtx);
/* If this is an object, we are done unless it is a MEM or LO_SUM, both
of which may contain things that can be combined. */
if (code != MEM && code != LO_SUM && GET_RTX_CLASS (code) == 'o')
return x;
/* It is possible to have a subexpression appear twice in the insn.
Suppose that FROM is a register that appears within TO.
Then, after that subexpression has been scanned once by `subst',
the second time it is scanned, TO may be found. If we were
to scan TO here, we would find FROM within it and create a
self-referent rtl structure which is completely wrong. */
if (COMBINE_RTX_EQUAL_P (x, to))
return to;
len = GET_RTX_LENGTH (code);
fmt = GET_RTX_FORMAT (code);
/* We don't need to process a SET_DEST that is a register, CC0, or PC, so
set up to skip this common case. All other cases where we want to
suppress replacing something inside a SET_SRC are handled via the
IN_DEST operand. */
if (code == SET
&& (GET_CODE (SET_DEST (x)) == REG
|| GET_CODE (SET_DEST (x)) == CC0
|| GET_CODE (SET_DEST (x)) == PC))
fmt = "ie";
/* Get the mode of operand 0 in case X is now a SIGN_EXTEND of a
constant. */
if (fmt[0] == 'e')
op0_mode = GET_MODE (XEXP (x, 0));
for (i = 0; i < len; i++)
{
if (fmt[i] == 'E')
{
register int j;