aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.2.1-5666.3/gcc/cse.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.2.1-5666.3/gcc/cse.c')
-rw-r--r--gcc-4.2.1-5666.3/gcc/cse.c8183
1 files changed, 8183 insertions, 0 deletions
diff --git a/gcc-4.2.1-5666.3/gcc/cse.c b/gcc-4.2.1-5666.3/gcc/cse.c
new file mode 100644
index 000000000..168e47ff5
--- /dev/null
+++ b/gcc-4.2.1-5666.3/gcc/cse.c
@@ -0,0 +1,8183 @@
+/* Common subexpression elimination for GNU compiler.
+ Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
+
+#include "config.h"
+/* stdio.h must precede rtl.h for FFS. */
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "tm_p.h"
+#include "hard-reg-set.h"
+#include "regs.h"
+#include "basic-block.h"
+#include "flags.h"
+#include "real.h"
+#include "insn-config.h"
+#include "recog.h"
+#include "function.h"
+#include "expr.h"
+#include "toplev.h"
+#include "output.h"
+#include "ggc.h"
+#include "timevar.h"
+#include "except.h"
+#include "target.h"
+#include "params.h"
+#include "rtlhooks-def.h"
+#include "tree-pass.h"
+
+/* The basic idea of common subexpression elimination is to go
+ through the code, keeping a record of expressions that would
+ have the same value at the current scan point, and replacing
+ expressions encountered with the cheapest equivalent expression.
+
+ It is too complicated to keep track of the different possibilities
+ when control paths merge in this code; so, at each label, we forget all
+ that is known and start fresh. This can be described as processing each
+ extended basic block separately. We have a separate pass to perform
+ global CSE.
+
+ Note CSE can turn a conditional or computed jump into a nop or
+ an unconditional jump. When this occurs we arrange to run the jump
+ optimizer after CSE to delete the unreachable code.
+
+ We use two data structures to record the equivalent expressions:
+ a hash table for most expressions, and a vector of "quantity
+ numbers" to record equivalent (pseudo) registers.
+
+ The use of the special data structure for registers is desirable
+ because it is faster. It is possible because registers references
+ contain a fairly small number, the register number, taken from
+ a contiguously allocated series, and two register references are
+ identical if they have the same number. General expressions
+ do not have any such thing, so the only way to retrieve the
+ information recorded on an expression other than a register
+ is to keep it in a hash table.
+
+Registers and "quantity numbers":
+
+ At the start of each basic block, all of the (hardware and pseudo)
+ registers used in the function are given distinct quantity
+ numbers to indicate their contents. During scan, when the code
+ copies one register into another, we copy the quantity number.
+ When a register is loaded in any other way, we allocate a new
+ quantity number to describe the value generated by this operation.
+ `REG_QTY (N)' records what quantity register N is currently thought
+ of as containing.
+
+ All real quantity numbers are greater than or equal to zero.
+ If register N has not been assigned a quantity, `REG_QTY (N)' will
+ equal -N - 1, which is always negative.
+
+ Quantity numbers below zero do not exist and none of the `qty_table'
+ entries should be referenced with a negative index.
+
+ We also maintain a bidirectional chain of registers for each
+ quantity number. The `qty_table` members `first_reg' and `last_reg',
+ and `reg_eqv_table' members `next' and `prev' hold these chains.
+
+ The first register in a chain is the one whose lifespan is least local.
+ Among equals, it is the one that was seen first.
+ We replace any equivalent register with that one.
+
+ If two registers have the same quantity number, it must be true that
+ REG expressions with qty_table `mode' must be in the hash table for both
+ registers and must be in the same class.
+
+ The converse is not true. Since hard registers may be referenced in
+ any mode, two REG expressions might be equivalent in the hash table
+ but not have the same quantity number if the quantity number of one
+ of the registers is not the same mode as those expressions.
+
+Constants and quantity numbers
+
+ When a quantity has a known constant value, that value is stored
+ in the appropriate qty_table `const_rtx'. This is in addition to
+ putting the constant in the hash table as is usual for non-regs.
+
+ Whether a reg or a constant is preferred is determined by the configuration
+ macro CONST_COSTS and will often depend on the constant value. In any
+ event, expressions containing constants can be simplified, by fold_rtx.
+
+ When a quantity has a known nearly constant value (such as an address
+ of a stack slot), that value is stored in the appropriate qty_table
+ `const_rtx'.
+
+ Integer constants don't have a machine mode. However, cse
+ determines the intended machine mode from the destination
+ of the instruction that moves the constant. The machine mode
+ is recorded in the hash table along with the actual RTL
+ constant expression so that different modes are kept separate.
+
+Other expressions:
+
+ To record known equivalences among expressions in general
+ we use a hash table called `table'. It has a fixed number of buckets
+ that contain chains of `struct table_elt' elements for expressions.
+ These chains connect the elements whose expressions have the same
+ hash codes.
+
+ Other chains through the same elements connect the elements which
+ currently have equivalent values.
+
+ Register references in an expression are canonicalized before hashing
+ the expression. This is done using `reg_qty' and qty_table `first_reg'.
+ The hash code of a register reference is computed using the quantity
+ number, not the register number.
+
+ When the value of an expression changes, it is necessary to remove from the
+ hash table not just that expression but all expressions whose values
+ could be different as a result.
+
+ 1. If the value changing is in memory, except in special cases
+ ANYTHING referring to memory could be changed. That is because
+ nobody knows where a pointer does not point.
+ The function `invalidate_memory' removes what is necessary.
+
+ The special cases are when the address is constant or is
+ a constant plus a fixed register such as the frame pointer
+ or a static chain pointer. When such addresses are stored in,
+ we can tell exactly which other such addresses must be invalidated
+ due to overlap. `invalidate' does this.
+ All expressions that refer to non-constant
+ memory addresses are also invalidated. `invalidate_memory' does this.
+
+ 2. If the value changing is a register, all expressions
+ containing references to that register, and only those,
+ must be removed.
+
+ Because searching the entire hash table for expressions that contain
+ a register is very slow, we try to figure out when it isn't necessary.
+ Precisely, this is necessary only when expressions have been
+ entered in the hash table using this register, and then the value has
+ changed, and then another expression wants to be added to refer to
+ the register's new value. This sequence of circumstances is rare
+ within any one basic block.
+
+ `REG_TICK' and `REG_IN_TABLE', accessors for members of
+ cse_reg_info, are used to detect this case. REG_TICK (i) is
+ incremented whenever a value is stored in register i.
+ REG_IN_TABLE (i) holds -1 if no references to register i have been
+ entered in the table; otherwise, it contains the value REG_TICK (i)
+ had when the references were entered. If we want to enter a
+ reference and REG_IN_TABLE (i) != REG_TICK (i), we must scan and
+ remove old references. Until we want to enter a new entry, the
+ mere fact that the two vectors don't match makes the entries be
+ ignored if anyone tries to match them.
+
+ Registers themselves are entered in the hash table as well as in
+ the equivalent-register chains. However, `REG_TICK' and
+ `REG_IN_TABLE' do not apply to expressions which are simple
+ register references. These expressions are removed from the table
+ immediately when they become invalid, and this can be done even if
+ we do not immediately search for all the expressions that refer to
+ the register.
+
+ A CLOBBER rtx in an instruction invalidates its operand for further
+ reuse. A CLOBBER or SET rtx whose operand is a MEM:BLK
+ invalidates everything that resides in memory.
+
+Related expressions:
+
+ Constant expressions that differ only by an additive integer
+ are called related. When a constant expression is put in
+ the table, the related expression with no constant term
+ is also entered. These are made to point at each other
+ so that it is possible to find out if there exists any
+ register equivalent to an expression related to a given expression. */
+
+/* Length of qty_table vector. We know in advance we will not need
+ a quantity number this big. */
+
+static int max_qty;
+
+/* Next quantity number to be allocated.
+ This is 1 + the largest number needed so far. */
+
+static int next_qty;
+
+/* Per-qty information tracking.
+
+ `first_reg' and `last_reg' track the head and tail of the
+ chain of registers which currently contain this quantity.
+
+ `mode' contains the machine mode of this quantity.
+
+ `const_rtx' holds the rtx of the constant value of this
+ quantity, if known. A summations of the frame/arg pointer
+ and a constant can also be entered here. When this holds
+ a known value, `const_insn' is the insn which stored the
+ constant value.
+
+ `comparison_{code,const,qty}' are used to track when a
+ comparison between a quantity and some constant or register has
+ been passed. In such a case, we know the results of the comparison
+ in case we see it again. These members record a comparison that
+ is known to be true. `comparison_code' holds the rtx code of such
+ a comparison, else it is set to UNKNOWN and the other two
+ comparison members are undefined. `comparison_const' holds
+ the constant being compared against, or zero if the comparison
+ is not against a constant. `comparison_qty' holds the quantity
+ being compared against when the result is known. If the comparison
+ is not with a register, `comparison_qty' is -1. */
+
+struct qty_table_elem
+{
+ rtx const_rtx;
+ rtx const_insn;
+ rtx comparison_const;
+ int comparison_qty;
+ unsigned int first_reg, last_reg;
+ /* The sizes of these fields should match the sizes of the
+ code and mode fields of struct rtx_def (see rtl.h). */
+ ENUM_BITFIELD(rtx_code) comparison_code : 16;
+ ENUM_BITFIELD(machine_mode) mode : 8;
+};
+
+/* The table of all qtys, indexed by qty number. */
+static struct qty_table_elem *qty_table;
+
+/* Structure used to pass arguments via for_each_rtx to function
+ cse_change_cc_mode. */
+struct change_cc_mode_args
+{
+ rtx insn;
+ rtx newreg;
+};
+
+#ifdef HAVE_cc0
+/* For machines that have a CC0, we do not record its value in the hash
+ table since its use is guaranteed to be the insn immediately following
+ its definition and any other insn is presumed to invalidate it.
+
+ Instead, we store below the value last assigned to CC0. If it should
+ happen to be a constant, it is stored in preference to the actual
+ assigned value. In case it is a constant, we store the mode in which
+ the constant should be interpreted. */
+
+static rtx prev_insn_cc0;
+static enum machine_mode prev_insn_cc0_mode;
+
+/* Previous actual insn. 0 if at first insn of basic block. */
+
+static rtx prev_insn;
+#endif
+
+/* Insn being scanned. */
+
+static rtx this_insn;
+
+/* Index by register number, gives the number of the next (or
+ previous) register in the chain of registers sharing the same
+ value.
+
+ Or -1 if this register is at the end of the chain.
+
+ If REG_QTY (N) == -N - 1, reg_eqv_table[N].next is undefined. */
+
+/* Per-register equivalence chain. */
+struct reg_eqv_elem
+{
+ int next, prev;
+};
+
+/* The table of all register equivalence chains. */
+static struct reg_eqv_elem *reg_eqv_table;
+
+struct cse_reg_info
+{
+ /* The timestamp at which this register is initialized. */
+ unsigned int timestamp;
+
+ /* The quantity number of the register's current contents. */
+ int reg_qty;
+
+ /* The number of times the register has been altered in the current
+ basic block. */
+ int reg_tick;
+
+ /* The REG_TICK value at which rtx's containing this register are
+ valid in the hash table. If this does not equal the current
+ reg_tick value, such expressions existing in the hash table are
+ invalid. */
+ int reg_in_table;
+
+ /* The SUBREG that was set when REG_TICK was last incremented. Set
+ to -1 if the last store was to the whole register, not a subreg. */
+ unsigned int subreg_ticked;
+};
+
+/* A table of cse_reg_info indexed by register numbers. */
+static struct cse_reg_info *cse_reg_info_table;
+
+/* The size of the above table. */
+static unsigned int cse_reg_info_table_size;
+
+/* The index of the first entry that has not been initialized. */
+static unsigned int cse_reg_info_table_first_uninitialized;
+
+/* The timestamp at the beginning of the current run of
+ cse_basic_block. We increment this variable at the beginning of
+ the current run of cse_basic_block. The timestamp field of a
+ cse_reg_info entry matches the value of this variable if and only
+ if the entry has been initialized during the current run of
+ cse_basic_block. */
+static unsigned int cse_reg_info_timestamp;
+
+/* A HARD_REG_SET containing all the hard registers for which there is
+ currently a REG expression in the hash table. Note the difference
+ from the above variables, which indicate if the REG is mentioned in some
+ expression in the table. */
+
+static HARD_REG_SET hard_regs_in_table;
+
+/* CUID of insn that starts the basic block currently being cse-processed. */
+
+static int cse_basic_block_start;
+
+/* CUID of insn that ends the basic block currently being cse-processed. */
+
+static int cse_basic_block_end;
+
+/* Vector mapping INSN_UIDs to cuids.
+ The cuids are like uids but increase monotonically always.
+ We use them to see whether a reg is used outside a given basic block. */
+
+static int *uid_cuid;
+
+/* Highest UID in UID_CUID. */
+static int max_uid;
+
+/* Get the cuid of an insn. */
+
+#define INSN_CUID(INSN) (uid_cuid[INSN_UID (INSN)])
+
+/* Nonzero if this pass has made changes, and therefore it's
+ worthwhile to run the garbage collector. */
+
+static int cse_altered;
+
+/* Nonzero if cse has altered conditional jump insns
+ in such a way that jump optimization should be redone. */
+
+static int cse_jumps_altered;
+
+/* Nonzero if we put a LABEL_REF into the hash table for an INSN without a
+ REG_LABEL, we have to rerun jump after CSE to put in the note. */
+static int recorded_label_ref;
+
+/* canon_hash stores 1 in do_not_record
+ if it notices a reference to CC0, PC, or some other volatile
+ subexpression. */
+
+static int do_not_record;
+
+/* canon_hash stores 1 in hash_arg_in_memory
+ if it notices a reference to memory within the expression being hashed. */
+
+static int hash_arg_in_memory;
+
+/* The hash table contains buckets which are chains of `struct table_elt's,
+ each recording one expression's information.
+ That expression is in the `exp' field.
+
+ The canon_exp field contains a canonical (from the point of view of
+ alias analysis) version of the `exp' field.
+
+ Those elements with the same hash code are chained in both directions
+ through the `next_same_hash' and `prev_same_hash' fields.
+
+ Each set of expressions with equivalent values
+ are on a two-way chain through the `next_same_value'
+ and `prev_same_value' fields, and all point with
+ the `first_same_value' field at the first element in
+ that chain. The chain is in order of increasing cost.
+ Each element's cost value is in its `cost' field.
+
+ The `in_memory' field is nonzero for elements that
+ involve any reference to memory. These elements are removed
+ whenever a write is done to an unidentified location in memory.
+ To be safe, we assume that a memory address is unidentified unless
+ the address is either a symbol constant or a constant plus
+ the frame pointer or argument pointer.
+
+ The `related_value' field is used to connect related expressions
+ (that differ by adding an integer).
+ The related expressions are chained in a circular fashion.
+ `related_value' is zero for expressions for which this
+ chain is not useful.
+
+ The `cost' field stores the cost of this element's expression.
+ The `regcost' field stores the value returned by approx_reg_cost for
+ this element's expression.
+
+ The `is_const' flag is set if the element is a constant (including
+ a fixed address).
+
+ The `flag' field is used as a temporary during some search routines.
+
+ The `mode' field is usually the same as GET_MODE (`exp'), but
+ if `exp' is a CONST_INT and has no machine mode then the `mode'
+ field is the mode it was being used as. Each constant is
+ recorded separately for each mode it is used with. */
+
+struct table_elt
+{
+ rtx exp;
+ rtx canon_exp;
+ struct table_elt *next_same_hash;
+ struct table_elt *prev_same_hash;
+ struct table_elt *next_same_value;
+ struct table_elt *prev_same_value;
+ struct table_elt *first_same_value;
+ struct table_elt *related_value;
+ int cost;
+ int regcost;
+ /* The size of this field should match the size
+ of the mode field of struct rtx_def (see rtl.h). */
+ ENUM_BITFIELD(machine_mode) mode : 8;
+ char in_memory;
+ char is_const;
+ char flag;
+};
+
+/* We don't want a lot of buckets, because we rarely have very many
+ things stored in the hash table, and a lot of buckets slows
+ down a lot of loops that happen frequently. */
+#define HASH_SHIFT 5
+#define HASH_SIZE (1 << HASH_SHIFT)
+#define HASH_MASK (HASH_SIZE - 1)
+
+/* Compute hash code of X in mode M. Special-case case where X is a pseudo
+ register (hard registers may require `do_not_record' to be set). */
+
+#define HASH(X, M) \
+ ((REG_P (X) && REGNO (X) >= FIRST_PSEUDO_REGISTER \
+ ? (((unsigned) REG << 7) + (unsigned) REG_QTY (REGNO (X))) \
+ : canon_hash (X, M)) & HASH_MASK)
+
+/* Like HASH, but without side-effects. */
+#define SAFE_HASH(X, M) \
+ ((REG_P (X) && REGNO (X) >= FIRST_PSEUDO_REGISTER \
+ ? (((unsigned) REG << 7) + (unsigned) REG_QTY (REGNO (X))) \
+ : safe_hash (X, M)) & HASH_MASK)
+
+/* Determine whether register number N is considered a fixed register for the
+ purpose of approximating register costs.
+ It is desirable to replace other regs with fixed regs, to reduce need for
+ non-fixed hard regs.
+ A reg wins if it is either the frame pointer or designated as fixed. */
+#define FIXED_REGNO_P(N) \
+ ((N) == FRAME_POINTER_REGNUM || (N) == HARD_FRAME_POINTER_REGNUM \
+ || fixed_regs[N] || global_regs[N])
+
+/* Compute cost of X, as stored in the `cost' field of a table_elt. Fixed
+ hard registers and pointers into the frame are the cheapest with a cost
+ of 0. Next come pseudos with a cost of one and other hard registers with
+ a cost of 2. Aside from these special cases, call `rtx_cost'. */
+
+#define CHEAP_REGNO(N) \
+ (REGNO_PTR_FRAME_P(N) \
+ || (HARD_REGISTER_NUM_P (N) \
+ && FIXED_REGNO_P (N) && REGNO_REG_CLASS (N) != NO_REGS))
+
+#define COST(X) (REG_P (X) ? 0 : notreg_cost (X, SET))
+#define COST_IN(X,OUTER) (REG_P (X) ? 0 : notreg_cost (X, OUTER))
+
+/* Get the number of times this register has been updated in this
+ basic block. */
+
+#define REG_TICK(N) (get_cse_reg_info (N)->reg_tick)
+
+/* Get the point at which REG was recorded in the table. */
+
+#define REG_IN_TABLE(N) (get_cse_reg_info (N)->reg_in_table)
+
+/* Get the SUBREG set at the last increment to REG_TICK (-1 if not a
+ SUBREG). */
+
+#define SUBREG_TICKED(N) (get_cse_reg_info (N)->subreg_ticked)
+
+/* Get the quantity number for REG. */
+
+#define REG_QTY(N) (get_cse_reg_info (N)->reg_qty)
+
+/* Determine if the quantity number for register X represents a valid index
+ into the qty_table. */
+
+#define REGNO_QTY_VALID_P(N) (REG_QTY (N) >= 0)
+
+static struct table_elt *table[HASH_SIZE];
+
+/* Number of elements in the hash table. */
+
+static unsigned int table_size;
+
+/* Chain of `struct table_elt's made so far for this function
+ but currently removed from the table. */
+
+static struct table_elt *free_element_chain;
+
+/* Set to the cost of a constant pool reference if one was found for a
+ symbolic constant. If this was found, it means we should try to
+ convert constants into constant pool entries if they don't fit in
+ the insn. */
+
+static int constant_pool_entries_cost;
+static int constant_pool_entries_regcost;
+
+/* This data describes a block that will be processed by cse_basic_block. */
+
+struct cse_basic_block_data
+{
+ /* Lowest CUID value of insns in block. */
+ int low_cuid;
+ /* Highest CUID value of insns in block. */
+ int high_cuid;
+ /* Total number of SETs in block. */
+ int nsets;
+ /* Last insn in the block. */
+ rtx last;
+ /* Size of current branch path, if any. */
+ int path_size;
+ /* Current branch path, indicating which branches will be taken. */
+ struct branch_path
+ {
+ /* The branch insn. */
+ rtx branch;
+ /* Whether it should be taken or not. AROUND is the same as taken
+ except that it is used when the destination label is not preceded
+ by a BARRIER. */
+ enum taken {PATH_TAKEN, PATH_NOT_TAKEN, PATH_AROUND} status;
+ } *path;
+};
+
+static bool fixed_base_plus_p (rtx x);
+static int notreg_cost (rtx, enum rtx_code);
+static int approx_reg_cost_1 (rtx *, void *);
+static int approx_reg_cost (rtx);
+static int preferable (int, int, int, int);
+static void new_basic_block (void);
+static void make_new_qty (unsigned int, enum machine_mode);
+static void make_regs_eqv (unsigned int, unsigned int);
+static void delete_reg_equiv (unsigned int);
+static int mention_regs (rtx);
+static int insert_regs (rtx, struct table_elt *, int);
+static void remove_from_table (struct table_elt *, unsigned);
+static struct table_elt *lookup (rtx, unsigned, enum machine_mode);
+static struct table_elt *lookup_for_remove (rtx, unsigned, enum machine_mode);
+static rtx lookup_as_function (rtx, enum rtx_code);
+static struct table_elt *insert (rtx, struct table_elt *, unsigned,
+ enum machine_mode);
+static void merge_equiv_classes (struct table_elt *, struct table_elt *);
+static void invalidate (rtx, enum machine_mode);
+static int cse_rtx_varies_p (rtx, int);
+static void remove_invalid_refs (unsigned int);
+static void remove_invalid_subreg_refs (unsigned int, unsigned int,
+ enum machine_mode);
+static void rehash_using_reg (rtx);
+static void invalidate_memory (void);
+static void invalidate_for_call (void);
+static rtx use_related_value (rtx, struct table_elt *);
+
+static inline unsigned canon_hash (rtx, enum machine_mode);
+static inline unsigned safe_hash (rtx, enum machine_mode);
+static unsigned hash_rtx_string (const char *);
+
+static rtx canon_reg (rtx, rtx);
+static void find_best_addr (rtx, rtx *, enum machine_mode);
+static enum rtx_code find_comparison_args (enum rtx_code, rtx *, rtx *,
+ enum machine_mode *,
+ enum machine_mode *);
+static rtx fold_rtx (rtx, rtx);
+static rtx equiv_constant (rtx);
+static void record_jump_equiv (rtx, int);
+static void record_jump_cond (enum rtx_code, enum machine_mode, rtx, rtx,
+ int);
+static void cse_insn (rtx, rtx);
+static void cse_end_of_basic_block (rtx, struct cse_basic_block_data *,
+ int, int);
+static int addr_affects_sp_p (rtx);
+static void invalidate_from_clobbers (rtx);
+static rtx cse_process_notes (rtx, rtx);
+static void invalidate_skipped_set (rtx, rtx, void *);
+static void invalidate_skipped_block (rtx);
+static rtx cse_basic_block (rtx, rtx, struct branch_path *);
+static void count_reg_usage (rtx, int *, rtx, int);
+static int check_for_label_ref (rtx *, void *);
+extern void dump_class (struct table_elt*);
+static void get_cse_reg_info_1 (unsigned int regno);
+static struct cse_reg_info * get_cse_reg_info (unsigned int regno);
+static int check_dependence (rtx *, void *);
+
+static void flush_hash_table (void);
+static bool insn_live_p (rtx, int *);
+static bool set_live_p (rtx, rtx, int *);
+static bool dead_libcall_p (rtx, int *);
+static int cse_change_cc_mode (rtx *, void *);
+static void cse_change_cc_mode_insn (rtx, rtx);
+static void cse_change_cc_mode_insns (rtx, rtx, rtx);
+static enum machine_mode cse_cc_succs (basic_block, rtx, rtx, bool);
+
+
+#undef RTL_HOOKS_GEN_LOWPART
+#define RTL_HOOKS_GEN_LOWPART gen_lowpart_if_possible
+
+static const struct rtl_hooks cse_rtl_hooks = RTL_HOOKS_INITIALIZER;
+
+/* Nonzero if X has the form (PLUS frame-pointer integer). We check for
+ virtual regs here because the simplify_*_operation routines are called
+ by integrate.c, which is called before virtual register instantiation. */
+
+static bool
+fixed_base_plus_p (rtx x)
+{
+ switch (GET_CODE (x))
+ {
+ case REG:
+ if (x == frame_pointer_rtx || x == hard_frame_pointer_rtx)
+ return true;
+ if (x == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM])
+ return true;
+ if (REGNO (x) >= FIRST_VIRTUAL_REGISTER
+ && REGNO (x) <= LAST_VIRTUAL_REGISTER)
+ return true;
+ return false;
+
+ case PLUS:
+ if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+ return false;
+ return fixed_base_plus_p (XEXP (x, 0));
+
+ default:
+ return false;
+ }
+}
+
+/* Dump the expressions in the equivalence class indicated by CLASSP.
+ This function is used only for debugging. */
+void
+dump_class (struct table_elt *classp)
+{
+ struct table_elt *elt;
+
+ fprintf (stderr, "Equivalence chain for ");
+ print_rtl (stderr, classp->exp);
+ fprintf (stderr, ": \n");
+
+ for (elt = classp->first_same_value; elt; elt = elt->next_same_value)
+ {
+ print_rtl (stderr, elt->exp);
+ fprintf (stderr, "\n");
+ }
+}
+
+/* Subroutine of approx_reg_cost; called through for_each_rtx. */
+
+static int
+approx_reg_cost_1 (rtx *xp, void *data)
+{
+ rtx x = *xp;
+ int *cost_p = data;
+
+ if (x && REG_P (x))
+ {
+ unsigned int regno = REGNO (x);
+
+ if (! CHEAP_REGNO (regno))
+ {
+ if (regno < FIRST_PSEUDO_REGISTER)
+ {
+ if (SMALL_REGISTER_CLASSES)
+ return 1;
+ *cost_p += 2;
+ }
+ else
+ *cost_p += 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Return an estimate of the cost of the registers used in an rtx.
+ This is mostly the number of different REG expressions in the rtx;
+ however for some exceptions like fixed registers we use a cost of
+ 0. If any other hard register reference occurs, return MAX_COST. */
+
+static int
+approx_reg_cost (rtx x)
+{
+ int cost = 0;
+
+ if (for_each_rtx (&x, approx_reg_cost_1, (void *) &cost))
+ return MAX_COST;
+
+ return cost;
+}
+
+/* Returns a canonical version of X for the address, from the point of view,
+ that all multiplications are represented as MULT instead of the multiply
+ by a power of 2 being represented as ASHIFT. */
+
+static rtx
+canon_for_address (rtx x)
+{
+ enum rtx_code code;
+ enum machine_mode mode;
+ rtx new = 0;
+ int i;
+ const char *fmt;
+
+ if (!x)
+ return x;
+
+ code = GET_CODE (x);
+ mode = GET_MODE (x);
+
+ switch (code)
+ {
+ case ASHIFT:
+ if (GET_CODE (XEXP (x, 1)) == CONST_INT
+ && INTVAL (XEXP (x, 1)) < GET_MODE_BITSIZE (mode)
+ && INTVAL (XEXP (x, 1)) >= 0)
+ {
+ new = canon_for_address (XEXP (x, 0));
+ new = gen_rtx_MULT (mode, new,
+ gen_int_mode ((HOST_WIDE_INT) 1
+ << INTVAL (XEXP (x, 1)),
+ mode));
+ }
+ break;
+ default:
+ break;
+
+ }
+ if (new)
+ return new;
+
+ /* Now recursively process each operand of this operation. */
+ fmt = GET_RTX_FORMAT (code);
+ for (i = 0; i < GET_RTX_LENGTH (code); i++)
+ if (fmt[i] == 'e')
+ {
+ new = canon_for_address (XEXP (x, i));
+ XEXP (x, i) = new;
+ }
+ return x;
+}
+
+/* Return a negative value if an rtx A, whose costs are given by COST_A
+ and REGCOST_A, is more desirable than an rtx B.
+ Return a positive value if A is less desirable, or 0 if the two are
+ equally good. */
+static int
+preferable (int cost_a, int regcost_a, int cost_b, int regcost_b)
+{
+ /* First, get rid of cases involving expressions that are entirely
+ unwanted. */
+ if (cost_a != cost_b)
+ {
+ if (cost_a == MAX_COST)
+ return 1;
+ if (cost_b == MAX_COST)
+ return -1;
+ }
+
+ /* Avoid extending lifetimes of hardregs. */
+ if (regcost_a != regcost_b)
+ {
+ if (regcost_a == MAX_COST)
+ return 1;
+ if (regcost_b == MAX_COST)
+ return -1;
+ }
+
+ /* Normal operation costs take precedence. */
+ if (cost_a != cost_b)
+ return cost_a - cost_b;
+ /* Only if these are identical consider effects on register pressure. */
+ if (regcost_a != regcost_b)
+ return regcost_a - regcost_b;
+ return 0;
+}
+
+/* Internal function, to compute cost when X is not a register; called
+ from COST macro to keep it simple. */
+
+static int
+notreg_cost (rtx x, enum rtx_code outer)
+{
+ return ((GET_CODE (x) == SUBREG
+ && REG_P (SUBREG_REG (x))
+ && GET_MODE_CLASS (GET_MODE (x)) == MODE_INT
+ && GET_MODE_CLASS (GET_MODE (SUBREG_REG (x))) == MODE_INT
+ && (GET_MODE_SIZE (GET_MODE (x))
+ < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
+ && subreg_lowpart_p (x)
+ && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (GET_MODE (x)),
+ GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))))
+ ? 0
+ : rtx_cost (x, outer) * 2);
+}
+
+
+/* Initialize CSE_REG_INFO_TABLE. */
+
+static void
+init_cse_reg_info (unsigned int nregs)
+{
+ /* Do we need to grow the table? */
+ if (nregs > cse_reg_info_table_size)
+ {
+ unsigned int new_size;
+
+ if (cse_reg_info_table_size < 2048)
+ {
+ /* Compute a new size that is a power of 2 and no smaller
+ than the large of NREGS and 64. */
+ new_size = (cse_reg_info_table_size
+ ? cse_reg_info_table_size : 64);
+
+ while (new_size < nregs)
+ new_size *= 2;
+ }
+ else
+ {
+ /* If we need a big table, allocate just enough to hold
+ NREGS registers. */
+ new_size = nregs;
+ }
+
+ /* Reallocate the table with NEW_SIZE entries. */
+ if (cse_reg_info_table)
+ free (cse_reg_info_table);
+ cse_reg_info_table = XNEWVEC (struct cse_reg_info, new_size);
+ cse_reg_info_table_size = new_size;
+ cse_reg_info_table_first_uninitialized = 0;
+ }
+
+ /* Do we have all of the first NREGS entries initialized? */
+ if (cse_reg_info_table_first_uninitialized < nregs)
+ {
+ unsigned int old_timestamp = cse_reg_info_timestamp - 1;
+ unsigned int i;
+
+ /* Put the old timestamp on newly allocated entries so that they
+ will all be considered out of date. We do not touch those
+ entries beyond the first NREGS entries to be nice to the
+ virtual memory. */
+ for (i = cse_reg_info_table_first_uninitialized; i < nregs; i++)
+ cse_reg_info_table[i].timestamp = old_timestamp;
+
+ cse_reg_info_table_first_uninitialized = nregs;
+ }
+}
+
+/* Given REGNO, initialize the cse_reg_info entry for REGNO. */
+
+static void
+get_cse_reg_info_1 (unsigned int regno)
+{
+ /* Set TIMESTAMP field to CSE_REG_INFO_TIMESTAMP so that this
+ entry will be considered to have been initialized. */
+ cse_reg_info_table[regno].timestamp = cse_reg_info_timestamp;
+
+ /* Initialize the rest of the entry. */
+ cse_reg_info_table[regno].reg_tick = 1;
+ cse_reg_info_table[regno].reg_in_table = -1;
+ cse_reg_info_table[regno].subreg_ticked = -1;
+ cse_reg_info_table[regno].reg_qty = -regno - 1;
+}
+
+/* Find a cse_reg_info entry for REGNO. */
+
+static inline struct cse_reg_info *
+get_cse_reg_info (unsigned int regno)
+{
+ struct cse_reg_info *p = &cse_reg_info_table[regno];
+
+ /* If this entry has not been initialized, go ahead and initialize
+ it. */
+ if (p->timestamp != cse_reg_info_timestamp)
+ get_cse_reg_info_1 (regno);
+
+ return p;
+}
+
+/* Clear the hash table and initialize each register with its own quantity,
+ for a new basic block. */
+
+static void
+new_basic_block (void)
+{
+ int i;
+
+ next_qty = 0;
+
+ /* Invalidate cse_reg_info_table. */
+ cse_reg_info_timestamp++;
+
+ /* Clear out hash table state for this pass. */
+ CLEAR_HARD_REG_SET (hard_regs_in_table);
+
+ /* The per-quantity values used to be initialized here, but it is
+ much faster to initialize each as it is made in `make_new_qty'. */
+
+ for (i = 0; i < HASH_SIZE; i++)
+ {
+ struct table_elt *first;
+
+ first = table[i];
+ if (first != NULL)
+ {
+ struct table_elt *last = first;
+
+ table[i] = NULL;
+
+ while (last->next_same_hash != NULL)
+ last = last->next_same_hash;
+
+ /* Now relink this hash entire chain into
+ the free element list. */
+
+ last->next_same_hash = free_element_chain;
+ free_element_chain = first;
+ }
+ }
+
+ table_size = 0;
+
+#ifdef HAVE_cc0
+ prev_insn = 0;
+ prev_insn_cc0 = 0;
+#endif
+}
+
+/* Say that register REG contains a quantity in mode MODE not in any
+ register before and initialize that quantity. */
+
+static void
+make_new_qty (unsigned int reg, enum machine_mode mode)
+{
+ int q;
+ struct qty_table_elem *ent;
+ struct reg_eqv_elem *eqv;
+
+ gcc_assert (next_qty < max_qty);
+
+ q = REG_QTY (reg) = next_qty++;
+ ent = &qty_table[q];
+ ent->first_reg = reg;
+ ent->last_reg = reg;
+ ent->mode = mode;
+ ent->const_rtx = ent->const_insn = NULL_RTX;
+ ent->comparison_code = UNKNOWN;
+
+ eqv = &reg_eqv_table[reg];
+ eqv->next = eqv->prev = -1;
+}
+
+/* Make reg NEW equivalent to reg OLD.
+ OLD is not changing; NEW is. */
+
+static void
+make_regs_eqv (unsigned int new, unsigned int old)
+{
+ unsigned int lastr, firstr;
+ int q = REG_QTY (old);
+ struct qty_table_elem *ent;
+
+ ent = &qty_table[q];
+
+ /* Nothing should become eqv until it has a "non-invalid" qty number. */
+ gcc_assert (REGNO_QTY_VALID_P (old));
+
+ REG_QTY (new) = q;
+ firstr = ent->first_reg;
+ lastr = ent->last_reg;
+
+ /* Prefer fixed hard registers to anything. Prefer pseudo regs to other
+ hard regs. Among pseudos, if NEW will live longer than any other reg
+ of the same qty, and that is beyond the current basic block,
+ make it the new canonical replacement for this qty. */
+ if (! (firstr < FIRST_PSEUDO_REGISTER && FIXED_REGNO_P (firstr))
+ /* Certain fixed registers might be of the class NO_REGS. This means
+ that not only can they not be allocated by the compiler, but
+ they cannot be used in substitutions or canonicalizations
+ either. */
+ && (new >= FIRST_PSEUDO_REGISTER || REGNO_REG_CLASS (new) != NO_REGS)
+ && ((new < FIRST_PSEUDO_REGISTER && FIXED_REGNO_P (new))
+ || (new >= FIRST_PSEUDO_REGISTER
+ && (firstr < FIRST_PSEUDO_REGISTER
+ || ((uid_cuid[REGNO_LAST_UID (new)] > cse_basic_block_end
+ || (uid_cuid[REGNO_FIRST_UID (new)]
+ < cse_basic_block_start))
+ && (uid_cuid[REGNO_LAST_UID (new)]
+ > uid_cuid[REGNO_LAST_UID (firstr)]))))))
+ {
+ reg_eqv_table[firstr].prev = new;
+ reg_eqv_table[new].next = firstr;
+ reg_eqv_table[new].prev = -1;
+ ent->first_reg = new;
+ }
+ else
+ {
+ /* If NEW is a hard reg (known to be non-fixed), insert at end.
+ Otherwise, insert before any non-fixed hard regs that are at the
+ end. Registers of class NO_REGS cannot be used as an
+ equivalent for anything. */
+ while (lastr < FIRST_PSEUDO_REGISTER && reg_eqv_table[lastr].prev >= 0
+ && (REGNO_REG_CLASS (lastr) == NO_REGS || ! FIXED_REGNO_P (lastr))
+ && new >= FIRST_PSEUDO_REGISTER)
+ lastr = reg_eqv_table[lastr].prev;
+ reg_eqv_table[new].next = reg_eqv_table[lastr].next;
+ if (reg_eqv_table[lastr].next >= 0)
+ reg_eqv_table[reg_eqv_table[lastr].next].prev = new;
+ else
+ qty_table[q].last_reg = new;
+ reg_eqv_table[lastr].next = new;
+ reg_eqv_table[new].prev = lastr;
+ }
+}
+
+/* Remove REG from its equivalence class. */
+
+static void
+delete_reg_equiv (unsigned int reg)
+{
+ struct qty_table_elem *ent;
+ int q = REG_QTY (reg);
+ int p, n;
+
+ /* If invalid, do nothing. */
+ if (! REGNO_QTY_VALID_P (reg))
+ return;
+
+ ent = &qty_table[q];
+
+ p = reg_eqv_table[reg].prev;
+ n = reg_eqv_table[reg].next;
+
+ if (n != -1)
+ reg_eqv_table[n].prev = p;
+ else
+ ent->last_reg = p;
+ if (p != -1)
+ reg_eqv_table[p].next = n;
+ else
+ ent->first_reg = n;
+
+ REG_QTY (reg) = -reg - 1;
+}
+
+/* Remove any invalid expressions from the hash table
+ that refer to any of the registers contained in expression X.
+
+ Make sure that newly inserted references to those registers
+ as subexpressions will be considered valid.
+
+ mention_regs is not called when a register itself
+ is being stored in the table.
+
+ Return 1 if we have done something that may have changed the hash code
+ of X. */
+
+static int
+mention_regs (rtx x)
+{
+ enum rtx_code code;
+ int i, j;
+ const char *fmt;
+ int changed = 0;
+
+ if (x == 0)
+ return 0;
+
+ code = GET_CODE (x);
+ if (code == REG)
+ {
+ unsigned int regno = REGNO (x);
+ unsigned int endregno
+ = regno + (regno >= FIRST_PSEUDO_REGISTER ? 1
+ : hard_regno_nregs[regno][GET_MODE (x)]);
+ unsigned int i;
+
+ for (i = regno; i < endregno; i++)
+ {
+ if (REG_IN_TABLE (i) >= 0 && REG_IN_TABLE (i) != REG_TICK (i))
+ remove_invalid_refs (i);
+
+ REG_IN_TABLE (i) = REG_TICK (i);
+ SUBREG_TICKED (i) = -1;
+ }
+
+ return 0;
+ }
+
+ /* If this is a SUBREG, we don't want to discard other SUBREGs of the same
+ pseudo if they don't use overlapping words. We handle only pseudos
+ here for simplicity. */
+ if (code == SUBREG && REG_P (SUBREG_REG (x))
+ && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER)
+ {
+ unsigned int i = REGNO (SUBREG_REG (x));
+
+ if (REG_IN_TABLE (i) >= 0 && REG_IN_TABLE (i) != REG_TICK (i))
+ {
+ /* If REG_IN_TABLE (i) differs from REG_TICK (i) by one, and
+ the last store to this register really stored into this
+ subreg, then remove the memory of this subreg.
+ Otherwise, remove any memory of the entire register and
+ all its subregs from the table. */
+ if (REG_TICK (i) - REG_IN_TABLE (i) > 1
+ || SUBREG_TICKED (i) != REGNO (SUBREG_REG (x)))
+ remove_invalid_refs (i);
+ else
+ remove_invalid_subreg_refs (i, SUBREG_BYTE (x), GET_MODE (x));
+ }
+
+ REG_IN_TABLE (i) = REG_TICK (i);
+ SUBREG_TICKED (i) = REGNO (SUBREG_REG (x));
+ return 0;
+ }
+
+ /* If X is a comparison or a COMPARE and either operand is a register
+ that does not have a quantity, give it one. This is so that a later
+ call to record_jump_equiv won't cause X to be assigned a different
+ hash code and not found in the table after that call.
+
+ It is not necessary to do this here, since rehash_using_reg can
+ fix up the table later, but doing this here eliminates the need to
+ call that expensive function in the most common case where the only
+ use of the register is in the comparison. */
+
+ if (code == COMPARE || COMPARISON_P (x))
+ {
+ if (REG_P (XEXP (x, 0))
+ && ! REGNO_QTY_VALID_P (REGNO (XEXP (x, 0))))
+ if (insert_regs (XEXP (x, 0), NULL, 0))
+ {
+ rehash_using_reg (XEXP (x, 0));
+ changed = 1;
+ }
+
+ if (REG_P (XEXP (x, 1))
+ && ! REGNO_QTY_VALID_P (REGNO (XEXP (x, 1))))
+ if (insert_regs (XEXP (x, 1), NULL, 0))
+ {
+ rehash_using_reg (XEXP (x, 1));
+ changed = 1;
+ }
+ }
+
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ if (fmt[i] == 'e')
+ changed |= mention_regs (XEXP (x, i));
+ else if (fmt[i] == 'E')
+ for (j = 0; j < XVECLEN (x, i); j++)
+ changed |= mention_regs (XVECEXP (x, i, j));
+
+ return changed;
+}
+
+/* Update the register quantities for inserting X into the hash table
+ with a value equivalent to CLASSP.
+ (If the class does not contain a REG, it is irrelevant.)
+ If MODIFIED is nonzero, X is a destination; it is being modified.
+ Note that delete_reg_equiv should be called on a register
+ before insert_regs is done on that register with MODIFIED != 0.
+
+ Nonzero value means that elements of reg_qty have changed
+ so X's hash code may be different. */
+
+static int
+insert_regs (rtx x, struct table_elt *classp, int modified)
+{
+ if (REG_P (x))
+ {
+ unsigned int regno = REGNO (x);
+ int qty_valid;
+
+ /* If REGNO is in the equivalence table already but is of the
+ wrong mode for that equivalence, don't do anything here. */
+
+ qty_valid = REGNO_QTY_VALID_P (regno);
+ if (qty_valid)
+ {
+ struct qty_table_elem *ent = &qty_table[REG_QTY (regno)];
+
+ if (ent->mode != GET_MODE (x))
+ return 0;
+ }
+
+ if (modified || ! qty_valid)
+ {
+ if (classp)
+ for (classp = classp->first_same_value;
+ classp != 0;
+ classp = classp->next_same_value)
+ if (REG_P (classp->exp)
+ && GET_MODE (classp->exp) == GET_MODE (x))
+ {
+ unsigned c_regno = REGNO (classp->exp);
+
+ gcc_assert (REGNO_QTY_VALID_P (c_regno));
+
+ /* Suppose that 5 is hard reg and 100 and 101 are
+ pseudos. Consider
+
+ (set (reg:si 100) (reg:si 5))
+ (set (reg:si 5) (reg:si 100))
+ (set (reg:di 101) (reg:di 5))
+
+ We would now set REG_QTY (101) = REG_QTY (5), but the
+ entry for 5 is in SImode. When we use this later in
+ copy propagation, we get the register in wrong mode. */
+ if (qty_table[REG_QTY (c_regno)].mode != GET_MODE (x))
+ continue;
+
+ make_regs_eqv (regno, c_regno);
+ return 1;
+ }
+
+ /* Mention_regs for a SUBREG checks if REG_TICK is exactly one larger
+ than REG_IN_TABLE to find out if there was only a single preceding
+ invalidation - for the SUBREG - or another one, which would be
+ for the full register. However, if we find here that REG_TICK
+ indicates that the register is invalid, it means that it has
+ been invalidated in a separate operation. The SUBREG might be used
+ now (then this is a recursive call), or we might use the full REG
+ now and a SUBREG of it later. So bump up REG_TICK so that
+ mention_regs will do the right thing. */
+ if (! modified
+ && REG_IN_TABLE (regno) >= 0
+ && REG_TICK (regno) == REG_IN_TABLE (regno) + 1)
+ REG_TICK (regno)++;
+ make_new_qty (regno, GET_MODE (x));
+ return 1;
+ }
+
+ return 0;
+ }
+
+ /* If X is a SUBREG, we will likely be inserting the inner register in the
+ table. If that register doesn't have an assigned quantity number at
+ this point but does later, the insertion that we will be doing now will
+ not be accessible because its hash code will have changed. So assign
+ a quantity number now. */
+
+ else if (GET_CODE (x) == SUBREG && REG_P (SUBREG_REG (x))
+ && ! REGNO_QTY_VALID_P (REGNO (SUBREG_REG (x))))
+ {
+ insert_regs (SUBREG_REG (x), NULL, 0);
+ mention_regs (x);
+ return 1;
+ }
+ else
+ return mention_regs (x);
+}
+
+/* Look in or update the hash table. */
+
+/* Remove table element ELT from use in the table.
+ HASH is its hash code, made using the HASH macro.
+ It's an argument because often that is known in advance
+ and we save much time not recomputing it. */
+
+static void
+remove_from_table (struct table_elt *elt, unsigned int hash)
+{
+ if (elt == 0)
+ return;
+
+ /* Mark this element as removed. See cse_insn. */
+ elt->first_same_value = 0;
+
+ /* Remove the table element from its equivalence class. */
+
+ {
+ struct table_elt *prev = elt->prev_same_value;
+ struct table_elt *next = elt->next_same_value;
+
+ if (next)
+ next->prev_same_value = prev;
+
+ if (prev)
+ prev->next_same_value = next;
+ else
+ {
+ struct table_elt *newfirst = next;
+ while (next)
+ {
+ next->first_same_value = newfirst;
+ next = next->next_same_value;
+ }
+ }
+ }
+
+ /* Remove the table element from its hash bucket. */
+
+ {
+ struct table_elt *prev = elt->prev_same_hash;
+ struct table_elt *next = elt->next_same_hash;
+
+ if (next)
+ next->prev_same_hash = prev;
+
+ if (prev)
+ prev->next_same_hash = next;
+ else if (table[hash] == elt)
+ table[hash] = next;
+ else
+ {
+ /* This entry is not in the proper hash bucket. This can happen
+ when two classes were merged by `merge_equiv_classes'. Search
+ for the hash bucket that it heads. This happens only very
+ rarely, so the cost is acceptable. */
+ for (hash = 0; hash < HASH_SIZE; hash++)
+ if (table[hash] == elt)
+ table[hash] = next;
+ }
+ }
+
+ /* Remove the table element from its related-value circular chain. */
+
+ if (elt->related_value != 0 && elt->related_value != elt)
+ {
+ struct table_elt *p = elt->related_value;
+
+ while (p->related_value != elt)
+ p = p->related_value;
+ p->related_value = elt->related_value;
+ if (p->related_value == p)
+ p->related_value = 0;
+ }
+
+ /* Now add it to the free element chain. */
+ elt->next_same_hash = free_element_chain;
+ free_element_chain = elt;
+
+ table_size--;
+}
+
+/* Look up X in the hash table and return its table element,
+ or 0 if X is not in the table.
+
+ MODE is the machine-mode of X, or if X is an integer constant
+ with VOIDmode then MODE is the mode with which X will be used.
+
+ Here we are satisfied to find an expression whose tree structure
+ looks like X. */
+
+static struct table_elt *
+lookup (rtx x, unsigned int hash, enum machine_mode mode)
+{
+ struct table_elt *p;
+
+ for (p = table[hash]; p; p = p->next_same_hash)
+ if (mode == p->mode && ((x == p->exp && REG_P (x))
+ || exp_equiv_p (x, p->exp, !REG_P (x), false)))
+ return p;
+
+ return 0;
+}
+
+/* Like `lookup' but don't care whether the table element uses invalid regs.
+ Also ignore discrepancies in the machine mode of a register. */
+
+static struct table_elt *
+lookup_for_remove (rtx x, unsigned int hash, enum machine_mode mode)
+{
+ struct table_elt *p;
+
+ if (REG_P (x))
+ {
+ unsigned int regno = REGNO (x);
+
+ /* Don't check the machine mode when comparing registers;
+ invalidating (REG:SI 0) also invalidates (REG:DF 0). */
+ for (p = table[hash]; p; p = p->next_same_hash)
+ if (REG_P (p->exp)
+ && REGNO (p->exp) == regno)
+ return p;
+ }
+ else
+ {
+ for (p = table[hash]; p; p = p->next_same_hash)
+ if (mode == p->mode
+ && (x == p->exp || exp_equiv_p (x, p->exp, 0, false)))
+ return p;
+ }
+
+ return 0;
+}
+
+/* Look for an expression equivalent to X and with code CODE.
+ If one is found, return that expression. */
+
+static rtx
+lookup_as_function (rtx x, enum rtx_code code)
+{
+ struct table_elt *p
+ = lookup (x, SAFE_HASH (x, VOIDmode), GET_MODE (x));
+
+ /* If we are looking for a CONST_INT, the mode doesn't really matter, as
+ long as we are narrowing. So if we looked in vain for a mode narrower
+ than word_mode before, look for word_mode now. */
+ if (p == 0 && code == CONST_INT
+ && GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (word_mode))
+ {
+ x = copy_rtx (x);
+ PUT_MODE (x, word_mode);
+ p = lookup (x, SAFE_HASH (x, VOIDmode), word_mode);
+ }
+
+ if (p == 0)
+ return 0;
+
+ for (p = p->first_same_value; p; p = p->next_same_value)
+ if (GET_CODE (p->exp) == code
+ /* Make sure this is a valid entry in the table. */
+ && exp_equiv_p (p->exp, p->exp, 1, false))
+ return p->exp;
+
+ return 0;
+}
+
+/* Insert X in the hash table, assuming HASH is its hash code
+ and CLASSP is an element of the class it should go in
+ (or 0 if a new class should be made).
+ It is inserted at the proper position to keep the class in
+ the order cheapest first.
+
+ MODE is the machine-mode of X, or if X is an integer constant
+ with VOIDmode then MODE is the mode with which X will be used.
+
+ For elements of equal cheapness, the most recent one
+ goes in front, except that the first element in the list
+ remains first unless a cheaper element is added. The order of
+ pseudo-registers does not matter, as canon_reg will be called to
+ find the cheapest when a register is retrieved from the table.
+
+ The in_memory field in the hash table element is set to 0.
+ The caller must set it nonzero if appropriate.
+
+ You should call insert_regs (X, CLASSP, MODIFY) before calling here,
+ and if insert_regs returns a nonzero value
+ you must then recompute its hash code before calling here.
+
+ If necessary, update table showing constant values of quantities. */
+
+#define CHEAPER(X, Y) \
+ (preferable ((X)->cost, (X)->regcost, (Y)->cost, (Y)->regcost) < 0)
+
+static struct table_elt *
+insert (rtx x, struct table_elt *classp, unsigned int hash, enum machine_mode mode)
+{
+ struct table_elt *elt;
+
+ /* If X is a register and we haven't made a quantity for it,
+ something is wrong. */
+ gcc_assert (!REG_P (x) || REGNO_QTY_VALID_P (REGNO (x)));
+
+ /* If X is a hard register, show it is being put in the table. */
+ if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
+ {
+ unsigned int regno = REGNO (x);
+ unsigned int endregno = regno + hard_regno_nregs[regno][GET_MODE (x)];
+ unsigned int i;
+
+ for (i = regno; i < endregno; i++)
+ SET_HARD_REG_BIT (hard_regs_in_table, i);
+ }
+
+ /* Put an element for X into the right hash bucket. */
+
+ elt = free_element_chain;
+ if (elt)
+ free_element_chain = elt->next_same_hash;
+ else
+ elt = XNEW (struct table_elt);
+
+ elt->exp = x;
+ elt->canon_exp = NULL_RTX;
+ elt->cost = COST (x);
+ elt->regcost = approx_reg_cost (x);
+ elt->next_same_value = 0;
+ elt->prev_same_value = 0;
+ elt->next_same_hash = table[hash];
+ elt->prev_same_hash = 0;
+ elt->related_value = 0;
+ elt->in_memory = 0;
+ elt->mode = mode;
+ elt->is_const = (CONSTANT_P (x) || fixed_base_plus_p (x));
+
+/* APPLE LOCAL begin ARM propagate stack addresses better */
+#ifdef TARGET_ARM
+ /* Adjust cost of SP+const addresses lower; generally, we want to propagate the addition
+ rather than use a register if these are equally cheap. This attempts to compensate
+ for forcing the cost of a reg to 0. */
+ if (fixed_base_plus_p (x))
+ elt->cost -= 2 * COSTS_N_INSNS (1);
+#endif
+/* APPLE LOCAL end ARM propagate stack addresses better */
+
+ if (table[hash])
+ table[hash]->prev_same_hash = elt;
+ table[hash] = elt;
+
+ /* Put it into the proper value-class. */
+ if (classp)
+ {
+ classp = classp->first_same_value;
+ if (CHEAPER (elt, classp))
+ /* Insert at the head of the class. */
+ {
+ struct table_elt *p;
+ elt->next_same_value = classp;
+ classp->prev_same_value = elt;
+ elt->first_same_value = elt;
+
+ for (p = classp; p; p = p->next_same_value)
+ p->first_same_value = elt;
+ }
+ else
+ {
+ /* Insert not at head of the class. */
+ /* Put it after the last element cheaper than X. */
+ struct table_elt *p, *next;
+
+ for (p = classp; (next = p->next_same_value) && CHEAPER (next, elt);
+ p = next);
+
+ /* Put it after P and before NEXT. */
+ elt->next_same_value = next;
+ if (next)
+ next->prev_same_value = elt;
+
+ elt->prev_same_value = p;
+ p->next_same_value = elt;
+ elt->first_same_value = classp;
+ }
+ }
+ else
+ elt->first_same_value = elt;
+
+ /* If this is a constant being set equivalent to a register or a register
+ being set equivalent to a constant, note the constant equivalence.
+
+ If this is a constant, it cannot be equivalent to a different constant,
+ and a constant is the only thing that can be cheaper than a register. So
+ we know the register is the head of the class (before the constant was
+ inserted).
+
+ If this is a register that is not already known equivalent to a
+ constant, we must check the entire class.
+
+ If this is a register that is already known equivalent to an insn,
+ update the qtys `const_insn' to show that `this_insn' is the latest
+ insn making that quantity equivalent to the constant. */
+
+ if (elt->is_const && classp && REG_P (classp->exp)
+ && !REG_P (x))
+ {
+ int exp_q = REG_QTY (REGNO (classp->exp));
+ struct qty_table_elem *exp_ent = &qty_table[exp_q];
+
+ exp_ent->const_rtx = gen_lowpart (exp_ent->mode, x);
+ exp_ent->const_insn = this_insn;
+ }
+
+ else if (REG_P (x)
+ && classp
+ && ! qty_table[REG_QTY (REGNO (x))].const_rtx
+ && ! elt->is_const)
+ {
+ struct table_elt *p;
+
+ for (p = classp; p != 0; p = p->next_same_value)
+ {
+ if (p->is_const && !REG_P (p->exp))
+ {
+ int x_q = REG_QTY (REGNO (x));
+ struct qty_table_elem *x_ent = &qty_table[x_q];
+
+ x_ent->const_rtx
+ = gen_lowpart (GET_MODE (x), p->exp);
+ x_ent->const_insn = this_insn;
+ break;
+ }
+ }
+ }
+
+ else if (REG_P (x)
+ && qty_table[REG_QTY (REGNO (x))].const_rtx
+ && GET_MODE (x) == qty_table[REG_QTY (REGNO (x))].mode)
+ qty_table[REG_QTY (REGNO (x))].const_insn = this_insn;
+
+ /* If this is a constant with symbolic value,
+ and it has a term with an explicit integer value,
+ link it up with related expressions. */
+ if (GET_CODE (x) == CONST)
+ {
+ rtx subexp = get_related_value (x);
+ unsigned subhash;
+ struct table_elt *subelt, *subelt_prev;
+
+ if (subexp != 0)
+ {
+ /* Get the integer-free subexpression in the hash table. */
+ subhash = SAFE_HASH (subexp, mode);
+ subelt = lookup (subexp, subhash, mode);
+ if (subelt == 0)
+ subelt = insert (subexp, NULL, subhash, mode);
+ /* Initialize SUBELT's circular chain if it has none. */
+ if (subelt->related_value == 0)
+ subelt->related_value = subelt;
+ /* Find the element in the circular chain that precedes SUBELT. */
+ subelt_prev = subelt;
+ while (subelt_prev->related_value != subelt)
+ subelt_prev = subelt_prev->related_value;
+ /* Put new ELT into SUBELT's circular chain just before SUBELT.
+ This way the element that follows SUBELT is the oldest one. */
+ elt->related_value = subelt_prev->related_value;
+ subelt_prev->related_value = elt;
+ }
+ }
+
+ table_size++;
+
+ return elt;
+}
+
+/* Given two equivalence classes, CLASS1 and CLASS2, put all the entries from
+ CLASS2 into CLASS1. This is done when we have reached an insn which makes
+ the two classes equivalent.
+
+ CLASS1 will be the surviving class; CLASS2 should not be used after this
+ call.
+
+ Any invalid entries in CLASS2 will not be copied. */
+
+static void
+merge_equiv_classes (struct table_elt *class1, struct table_elt *class2)
+{
+ struct table_elt *elt, *next, *new;
+
+ /* Ensure we start with the head of the classes. */
+ class1 = class1->first_same_value;
+ class2 = class2->first_same_value;
+
+ /* If they were already equal, forget it. */
+ if (class1 == class2)
+ return;
+
+ for (elt = class2; elt; elt = next)
+ {
+ unsigned int hash;
+ rtx exp = elt->exp;
+ enum machine_mode mode = elt->mode;
+
+ next = elt->next_same_value;
+
+ /* Remove old entry, make a new one in CLASS1's class.
+ Don't do this for invalid entries as we cannot find their
+ hash code (it also isn't necessary). */
+ if (REG_P (exp) || exp_equiv_p (exp, exp, 1, false))
+ {
+ bool need_rehash = false;
+
+ hash_arg_in_memory = 0;
+ hash = HASH (exp, mode);
+
+ if (REG_P (exp))
+ {
+ need_rehash = REGNO_QTY_VALID_P (REGNO (exp));
+ delete_reg_equiv (REGNO (exp));
+ }
+
+ remove_from_table (elt, hash);
+
+ if (insert_regs (exp, class1, 0) || need_rehash)
+ {
+ rehash_using_reg (exp);
+ hash = HASH (exp, mode);
+ }
+ new = insert (exp, class1, hash, mode);
+ new->in_memory = hash_arg_in_memory;
+ }
+ }
+}
+
+/* Flush the entire hash table. */
+
+static void
+flush_hash_table (void)
+{
+ int i;
+ struct table_elt *p;
+
+ for (i = 0; i < HASH_SIZE; i++)
+ for (p = table[i]; p; p = table[i])
+ {
+ /* Note that invalidate can remove elements
+ after P in the current hash chain. */
+ if (REG_P (p->exp))
+ invalidate (p->exp, VOIDmode);
+ else
+ remove_from_table (p, i);
+ }
+}
+
+/* Function called for each rtx to check whether true dependence exist. */
+struct check_dependence_data
+{
+ enum machine_mode mode;
+ rtx exp;
+ rtx addr;
+};
+
+static int
+check_dependence (rtx *x, void *data)
+{
+ struct check_dependence_data *d = (struct check_dependence_data *) data;
+ if (*x && MEM_P (*x))
+ return canon_true_dependence (d->exp, d->mode, d->addr, *x,
+ cse_rtx_varies_p);
+ else
+ return 0;
+}
+
+/* Remove from the hash table, or mark as invalid, all expressions whose
+ values could be altered by storing in X. X is a register, a subreg, or
+ a memory reference with nonvarying address (because, when a memory
+ reference with a varying address is stored in, all memory references are
+ removed by invalidate_memory so specific invalidation is superfluous).
+ FULL_MODE, if not VOIDmode, indicates that this much should be
+ invalidated instead of just the amount indicated by the mode of X. This
+ is only used for bitfield stores into memory.
+
+ A nonvarying address may be just a register or just a symbol reference,
+ or it may be either of those plus a numeric offset. */
+
+static void
+invalidate (rtx x, enum machine_mode full_mode)
+{
+ int i;
+ struct table_elt *p;
+ rtx addr;
+
+ switch (GET_CODE (x))
+ {
+ case REG:
+ {
+ /* If X is a register, dependencies on its contents are recorded
+ through the qty number mechanism. Just change the qty number of
+ the register, mark it as invalid for expressions that refer to it,
+ and remove it itself. */
+ unsigned int regno = REGNO (x);
+ unsigned int hash = HASH (x, GET_MODE (x));
+
+ /* Remove REGNO from any quantity list it might be on and indicate
+ that its value might have changed. If it is a pseudo, remove its
+ entry from the hash table.
+
+ For a hard register, we do the first two actions above for any
+ additional hard registers corresponding to X. Then, if any of these
+ registers are in the table, we must remove any REG entries that
+ overlap these registers. */
+
+ delete_reg_equiv (regno);
+ REG_TICK (regno)++;
+ SUBREG_TICKED (regno) = -1;
+
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ {
+ /* Because a register can be referenced in more than one mode,
+ we might have to remove more than one table entry. */
+ struct table_elt *elt;
+
+ while ((elt = lookup_for_remove (x, hash, GET_MODE (x))))
+ remove_from_table (elt, hash);
+ }
+ else
+ {
+ HOST_WIDE_INT in_table
+ = TEST_HARD_REG_BIT (hard_regs_in_table, regno);
+ unsigned int endregno
+ = regno + hard_regno_nregs[regno][GET_MODE (x)];
+ unsigned int tregno, tendregno, rn;
+ struct table_elt *p, *next;
+
+ CLEAR_HARD_REG_BIT (hard_regs_in_table, regno);
+
+ for (rn = regno + 1; rn < endregno; rn++)
+ {
+ in_table |= TEST_HARD_REG_BIT (hard_regs_in_table, rn);
+ CLEAR_HARD_REG_BIT (hard_regs_in_table, rn);
+ delete_reg_equiv (rn);
+ REG_TICK (rn)++;
+ SUBREG_TICKED (rn) = -1;
+ }
+
+ if (in_table)
+ for (hash = 0; hash < HASH_SIZE; hash++)
+ for (p = table[hash]; p; p = next)
+ {
+ next = p->next_same_hash;
+
+ if (!REG_P (p->exp)
+ || REGNO (p->exp) >= FIRST_PSEUDO_REGISTER)
+ continue;
+
+ tregno = REGNO (p->exp);
+ tendregno
+ = tregno + hard_regno_nregs[tregno][GET_MODE (p->exp)];
+ if (tendregno > regno && tregno < endregno)
+ remove_from_table (p, hash);
+ }
+ }
+ }
+ return;
+
+ case SUBREG:
+ invalidate (SUBREG_REG (x), VOIDmode);
+ return;
+
+ case PARALLEL:
+ for (i = XVECLEN (x, 0) - 1; i >= 0; --i)
+ invalidate (XVECEXP (x, 0, i), VOIDmode);
+ return;
+
+ case EXPR_LIST:
+ /* This is part of a disjoint return value; extract the location in
+ question ignoring the offset. */
+ invalidate (XEXP (x, 0), VOIDmode);
+ return;
+
+ case MEM:
+ addr = canon_rtx (get_addr (XEXP (x, 0)));
+ /* Calculate the canonical version of X here so that
+ true_dependence doesn't generate new RTL for X on each call. */
+ x = canon_rtx (x);
+
+ /* Remove all hash table elements that refer to overlapping pieces of
+ memory. */
+ if (full_mode == VOIDmode)
+ full_mode = GET_MODE (x);
+
+ for (i = 0; i < HASH_SIZE; i++)
+ {
+ struct table_elt *next;
+
+ for (p = table[i]; p; p = next)
+ {
+ next = p->next_same_hash;
+ if (p->in_memory)
+ {
+ struct check_dependence_data d;
+
+ /* Just canonicalize the expression once;
+ otherwise each time we call invalidate
+ true_dependence will canonicalize the
+ expression again. */
+ if (!p->canon_exp)
+ p->canon_exp = canon_rtx (p->exp);
+ d.exp = x;
+ d.addr = addr;
+ d.mode = full_mode;
+ if (for_each_rtx (&p->canon_exp, check_dependence, &d))
+ remove_from_table (p, i);
+ }
+ }
+ }
+ return;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Remove all expressions that refer to register REGNO,
+ since they are already invalid, and we are about to
+ mark that register valid again and don't want the old
+ expressions to reappear as valid. */
+
+static void
+remove_invalid_refs (unsigned int regno)
+{
+ unsigned int i;
+ struct table_elt *p, *next;
+
+ for (i = 0; i < HASH_SIZE; i++)
+ for (p = table[i]; p; p = next)
+ {
+ next = p->next_same_hash;
+ if (!REG_P (p->exp)
+ && refers_to_regno_p (regno, regno + 1, p->exp, (rtx *) 0))
+ remove_from_table (p, i);
+ }
+}
+
+/* Likewise for a subreg with subreg_reg REGNO, subreg_byte OFFSET,
+ and mode MODE. */
+static void
+remove_invalid_subreg_refs (unsigned int regno, unsigned int offset,
+ enum machine_mode mode)
+{
+ unsigned int i;
+ struct table_elt *p, *next;
+ unsigned int end = offset + (GET_MODE_SIZE (mode) - 1);
+
+ for (i = 0; i < HASH_SIZE; i++)
+ for (p = table[i]; p; p = next)
+ {
+ rtx exp = p->exp;
+ next = p->next_same_hash;
+
+ if (!REG_P (exp)
+ && (GET_CODE (exp) != SUBREG
+ || !REG_P (SUBREG_REG (exp))
+ || REGNO (SUBREG_REG (exp)) != regno
+ || (((SUBREG_BYTE (exp)
+ + (GET_MODE_SIZE (GET_MODE (exp)) - 1)) >= offset)
+ && SUBREG_BYTE (exp) <= end))
+ && refers_to_regno_p (regno, regno + 1, p->exp, (rtx *) 0))
+ remove_from_table (p, i);
+ }
+}
+
+/* Recompute the hash codes of any valid entries in the hash table that
+ reference X, if X is a register, or SUBREG_REG (X) if X is a SUBREG.
+
+ This is called when we make a jump equivalence. */
+
+static void
+rehash_using_reg (rtx x)
+{
+ unsigned int i;
+ struct table_elt *p, *next;
+ unsigned hash;
+
+ if (GET_CODE (x) == SUBREG)
+ x = SUBREG_REG (x);
+
+ /* If X is not a register or if the register is known not to be in any
+ valid entries in the table, we have no work to do. */
+
+ if (!REG_P (x)
+ || REG_IN_TABLE (REGNO (x)) < 0
+ || REG_IN_TABLE (REGNO (x)) != REG_TICK (REGNO (x)))
+ return;
+
+ /* Scan all hash chains looking for valid entries that mention X.
+ If we find one and it is in the wrong hash chain, move it. */
+
+ for (i = 0; i < HASH_SIZE; i++)
+ for (p = table[i]; p; p = next)
+ {
+ next = p->next_same_hash;
+ if (reg_mentioned_p (x, p->exp)
+ && exp_equiv_p (p->exp, p->exp, 1, false)
+ && i != (hash = SAFE_HASH (p->exp, p->mode)))
+ {
+ if (p->next_same_hash)
+ p->next_same_hash->prev_same_hash = p->prev_same_hash;
+
+ if (p->prev_same_hash)
+ p->prev_same_hash->next_same_hash = p->next_same_hash;
+ else
+ table[i] = p->next_same_hash;
+
+ p->next_same_hash = table[hash];
+ p->prev_same_hash = 0;
+ if (table[hash])
+ table[hash]->prev_same_hash = p;
+ table[hash] = p;
+ }
+ }
+}
+
+/* Remove from the hash table any expression that is a call-clobbered
+ register. Also update their TICK values. */
+
+static void
+invalidate_for_call (void)
+{
+ unsigned int regno, endregno;
+ unsigned int i;
+ unsigned hash;
+ struct table_elt *p, *next;
+ int in_table = 0;
+
+ /* Go through all the hard registers. For each that is clobbered in
+ a CALL_INSN, remove the register from quantity chains and update
+ reg_tick if defined. Also see if any of these registers is currently
+ in the table. */
+
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ if (TEST_HARD_REG_BIT (regs_invalidated_by_call, regno))
+ {
+ delete_reg_equiv (regno);
+ if (REG_TICK (regno) >= 0)
+ {
+ REG_TICK (regno)++;
+ SUBREG_TICKED (regno) = -1;
+ }
+
+ in_table |= (TEST_HARD_REG_BIT (hard_regs_in_table, regno) != 0);
+ }
+
+ /* In the case where we have no call-clobbered hard registers in the
+ table, we are done. Otherwise, scan the table and remove any
+ entry that overlaps a call-clobbered register. */
+
+ if (in_table)
+ for (hash = 0; hash < HASH_SIZE; hash++)
+ for (p = table[hash]; p; p = next)
+ {
+ next = p->next_same_hash;
+
+ if (!REG_P (p->exp)
+ || REGNO (p->exp) >= FIRST_PSEUDO_REGISTER)
+ continue;
+
+ regno = REGNO (p->exp);
+ endregno = regno + hard_regno_nregs[regno][GET_MODE (p->exp)];
+
+ for (i = regno; i < endregno; i++)
+ if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
+ {
+ remove_from_table (p, hash);
+ break;
+ }
+ }
+}
+
+/* Given an expression X of type CONST,
+ and ELT which is its table entry (or 0 if it
+ is not in the hash table),
+ return an alternate expression for X as a register plus integer.
+ If none can be found, return 0. */
+
+static rtx
+use_related_value (rtx x, struct table_elt *elt)
+{
+ struct table_elt *relt = 0;
+ struct table_elt *p, *q;
+ HOST_WIDE_INT offset;
+
+ /* First, is there anything related known?
+ If we have a table element, we can tell from that.
+ Otherwise, must look it up. */
+
+ if (elt != 0 && elt->related_value != 0)
+ relt = elt;
+ else if (elt == 0 && GET_CODE (x) == CONST)
+ {
+ rtx subexp = get_related_value (x);
+ if (subexp != 0)
+ relt = lookup (subexp,
+ SAFE_HASH (subexp, GET_MODE (subexp)),
+ GET_MODE (subexp));
+ }
+
+ if (relt == 0)
+ return 0;
+
+ /* Search all related table entries for one that has an
+ equivalent register. */
+
+ p = relt;
+ while (1)
+ {
+ /* This loop is strange in that it is executed in two different cases.
+ The first is when X is already in the table. Then it is searching
+ the RELATED_VALUE list of X's class (RELT). The second case is when
+ X is not in the table. Then RELT points to a class for the related
+ value.
+
+ Ensure that, whatever case we are in, that we ignore classes that have
+ the same value as X. */
+
+ if (rtx_equal_p (x, p->exp))
+ q = 0;
+ else
+ for (q = p->first_same_value; q; q = q->next_same_value)
+ if (REG_P (q->exp))
+ break;
+
+ if (q)
+ break;
+
+ p = p->related_value;
+
+ /* We went all the way around, so there is nothing to be found.
+ Alternatively, perhaps RELT was in the table for some other reason
+ and it has no related values recorded. */
+ if (p == relt || p == 0)
+ break;
+ }
+
+ if (q == 0)
+ return 0;
+
+ offset = (get_integer_term (x) - get_integer_term (p->exp));
+ /* Note: OFFSET may be 0 if P->xexp and X are related by commutativity. */
+ return plus_constant (q->exp, offset);
+}
+
+/* Hash a string. Just add its bytes up. */
+static inline unsigned
+hash_rtx_string (const char *ps)
+{
+ unsigned hash = 0;
+ const unsigned char *p = (const unsigned char *) ps;
+
+ if (p)
+ while (*p)
+ hash += *p++;
+
+ return hash;
+}
+
+/* Hash an rtx. We are careful to make sure the value is never negative.
+ Equivalent registers hash identically.
+ MODE is used in hashing for CONST_INTs only;
+ otherwise the mode of X is used.
+
+ Store 1 in DO_NOT_RECORD_P if any subexpression is volatile.
+
+ If HASH_ARG_IN_MEMORY_P is not NULL, store 1 in it if X contains
+ a MEM rtx which does not have the RTX_UNCHANGING_P bit set.
+
+ Note that cse_insn knows that the hash code of a MEM expression
+ is just (int) MEM plus the hash code of the address. */
+
+unsigned
+hash_rtx (rtx x, enum machine_mode mode, int *do_not_record_p,
+ int *hash_arg_in_memory_p, bool have_reg_qty)
+{
+ int i, j;
+ unsigned hash = 0;
+ enum rtx_code code;
+ const char *fmt;
+
+ /* Used to turn recursion into iteration. We can't rely on GCC's
+ tail-recursion elimination since we need to keep accumulating values
+ in HASH. */
+ repeat:
+ if (x == 0)
+ return hash;
+
+ code = GET_CODE (x);
+ switch (code)
+ {
+ case REG:
+ {
+ unsigned int regno = REGNO (x);
+
+ if (!reload_completed)
+ {
+ /* On some machines, we can't record any non-fixed hard register,
+ because extending its life will cause reload problems. We
+ consider ap, fp, sp, gp to be fixed for this purpose.
+
+ We also consider CCmode registers to be fixed for this purpose;
+ failure to do so leads to failure to simplify 0<100 type of
+ conditionals.
+
+ On all machines, we can't record any global registers.
+ Nor should we record any register that is in a small
+ class, as defined by CLASS_LIKELY_SPILLED_P. */
+ bool record;
+
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ record = true;
+ else if (x == frame_pointer_rtx
+ || x == hard_frame_pointer_rtx
+ || x == arg_pointer_rtx
+ || x == stack_pointer_rtx
+ || x == pic_offset_table_rtx)
+ record = true;
+ else if (global_regs[regno])
+ record = false;
+ else if (fixed_regs[regno])
+ record = true;
+ else if (GET_MODE_CLASS (GET_MODE (x)) == MODE_CC)
+ record = true;
+ else if (SMALL_REGISTER_CLASSES)
+ record = false;
+ else if (CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (regno)))
+ record = false;
+ else
+ record = true;
+
+ if (!record)
+ {
+ *do_not_record_p = 1;
+ return 0;
+ }
+ }
+
+ hash += ((unsigned int) REG << 7);
+ hash += (have_reg_qty ? (unsigned) REG_QTY (regno) : regno);
+ return hash;
+ }
+
+ /* We handle SUBREG of a REG specially because the underlying
+ reg changes its hash value with every value change; we don't
+ want to have to forget unrelated subregs when one subreg changes. */
+ case SUBREG:
+ {
+ if (REG_P (SUBREG_REG (x)))
+ {
+ hash += (((unsigned int) SUBREG << 7)
+ + REGNO (SUBREG_REG (x))
+ + (SUBREG_BYTE (x) / UNITS_PER_WORD));
+ return hash;
+ }
+ break;
+ }
+
+ case CONST_INT:
+ hash += (((unsigned int) CONST_INT << 7) + (unsigned int) mode
+ + (unsigned int) INTVAL (x));
+ return hash;
+
+ case CONST_DOUBLE:
+ /* This is like the general case, except that it only counts
+ the integers representing the constant. */
+ hash += (unsigned int) code + (unsigned int) GET_MODE (x);
+ if (GET_MODE (x) != VOIDmode)
+ hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
+ else
+ hash += ((unsigned int) CONST_DOUBLE_LOW (x)
+ + (unsigned int) CONST_DOUBLE_HIGH (x));
+ return hash;
+
+ case CONST_VECTOR:
+ {
+ int units;
+ rtx elt;
+
+ units = CONST_VECTOR_NUNITS (x);
+
+ for (i = 0; i < units; ++i)
+ {
+ elt = CONST_VECTOR_ELT (x, i);
+ hash += hash_rtx (elt, GET_MODE (elt), do_not_record_p,
+ hash_arg_in_memory_p, have_reg_qty);
+ }
+
+ return hash;
+ }
+
+ /* Assume there is only one rtx object for any given label. */
+ case LABEL_REF:
+ /* We don't hash on the address of the CODE_LABEL to avoid bootstrap
+ differences and differences between each stage's debugging dumps. */
+ hash += (((unsigned int) LABEL_REF << 7)
+ + CODE_LABEL_NUMBER (XEXP (x, 0)));
+ return hash;
+
+ case SYMBOL_REF:
+ {
+ /* Don't hash on the symbol's address to avoid bootstrap differences.
+ Different hash values may cause expressions to be recorded in
+ different orders and thus different registers to be used in the
+ final assembler. This also avoids differences in the dump files
+ between various stages. */
+ unsigned int h = 0;
+ const unsigned char *p = (const unsigned char *) XSTR (x, 0);
+
+ while (*p)
+ h += (h << 7) + *p++; /* ??? revisit */
+
+ hash += ((unsigned int) SYMBOL_REF << 7) + h;
+ return hash;
+ }
+
+ case MEM:
+ /* We don't record if marked volatile or if BLKmode since we don't
+ know the size of the move. */
+ if (MEM_VOLATILE_P (x) || GET_MODE (x) == BLKmode)
+ {
+ *do_not_record_p = 1;
+ return 0;
+ }
+ if (hash_arg_in_memory_p && !MEM_READONLY_P (x))
+ *hash_arg_in_memory_p = 1;
+
+ /* Now that we have already found this special case,
+ might as well speed it up as much as possible. */
+ hash += (unsigned) MEM;
+ x = XEXP (x, 0);
+ goto repeat;
+
+ case USE:
+ /* A USE that mentions non-volatile memory needs special
+ handling since the MEM may be BLKmode which normally
+ prevents an entry from being made. Pure calls are
+ marked by a USE which mentions BLKmode memory.
+ See calls.c:emit_call_1. */
+ if (MEM_P (XEXP (x, 0))
+ && ! MEM_VOLATILE_P (XEXP (x, 0)))
+ {
+ hash += (unsigned) USE;
+ x = XEXP (x, 0);
+
+ if (hash_arg_in_memory_p && !MEM_READONLY_P (x))
+ *hash_arg_in_memory_p = 1;
+
+ /* Now that we have already found this special case,
+ might as well speed it up as much as possible. */
+ hash += (unsigned) MEM;
+ x = XEXP (x, 0);
+ goto repeat;
+ }
+ break;
+
+ case PRE_DEC:
+ case PRE_INC:
+ case POST_DEC:
+ case POST_INC:
+ case PRE_MODIFY:
+ case POST_MODIFY:
+ case PC:
+ case CC0:
+ case CALL:
+ case UNSPEC_VOLATILE:
+ *do_not_record_p = 1;
+ return 0;
+
+ case ASM_OPERANDS:
+ if (MEM_VOLATILE_P (x))
+ {
+ *do_not_record_p = 1;
+ return 0;
+ }
+ else
+ {
+ /* We don't want to take the filename and line into account. */
+ hash += (unsigned) code + (unsigned) GET_MODE (x)
+ + hash_rtx_string (ASM_OPERANDS_TEMPLATE (x))
+ + hash_rtx_string (ASM_OPERANDS_OUTPUT_CONSTRAINT (x))
+ + (unsigned) ASM_OPERANDS_OUTPUT_IDX (x);
+
+ if (ASM_OPERANDS_INPUT_LENGTH (x))
+ {
+ for (i = 1; i < ASM_OPERANDS_INPUT_LENGTH (x); i++)
+ {
+ hash += (hash_rtx (ASM_OPERANDS_INPUT (x, i),
+ GET_MODE (ASM_OPERANDS_INPUT (x, i)),
+ do_not_record_p, hash_arg_in_memory_p,
+ have_reg_qty)
+ + hash_rtx_string
+ (ASM_OPERANDS_INPUT_CONSTRAINT (x, i)));
+ }
+
+ hash += hash_rtx_string (ASM_OPERANDS_INPUT_CONSTRAINT (x, 0));
+ x = ASM_OPERANDS_INPUT (x, 0);
+ mode = GET_MODE (x);
+ goto repeat;
+ }
+
+ return hash;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ i = GET_RTX_LENGTH (code) - 1;
+ hash += (unsigned) code + (unsigned) GET_MODE (x);
+ fmt = GET_RTX_FORMAT (code);
+ for (; i >= 0; i--)
+ {
+ switch (fmt[i])
+ {
+ case 'e':
+ /* If we are about to do the last recursive call
+ needed at this level, change it into iteration.
+ This function is called enough to be worth it. */
+ if (i == 0)
+ {
+ x = XEXP (x, i);
+ goto repeat;
+ }
+
+ hash += hash_rtx (XEXP (x, i), 0, do_not_record_p,
+ hash_arg_in_memory_p, have_reg_qty);
+ break;
+
+ case 'E':
+ for (j = 0; j < XVECLEN (x, i); j++)
+ hash += hash_rtx (XVECEXP (x, i, j), 0, do_not_record_p,
+ hash_arg_in_memory_p, have_reg_qty);
+ break;
+
+ case 's':
+ hash += hash_rtx_string (XSTR (x, i));
+ break;
+
+ case 'i':
+ hash += (unsigned int) XINT (x, i);
+ break;
+
+ case '0': case 't':
+ /* Unused. */
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ }
+
+ return hash;
+}
+
+/* Hash an rtx X for cse via hash_rtx.
+ Stores 1 in do_not_record if any subexpression is volatile.
+ Stores 1 in hash_arg_in_memory if X contains a mem rtx which
+ does not have the RTX_UNCHANGING_P bit set. */
+
+static inline unsigned
+canon_hash (rtx x, enum machine_mode mode)
+{
+ return hash_rtx (x, mode, &do_not_record, &hash_arg_in_memory, true);
+}
+
+/* Like canon_hash but with no side effects, i.e. do_not_record
+ and hash_arg_in_memory are not changed. */
+
+static inline unsigned
+safe_hash (rtx x, enum machine_mode mode)
+{
+ int dummy_do_not_record;
+ return hash_rtx (x, mode, &dummy_do_not_record, NULL, true);
+}
+
+/* Return 1 iff X and Y would canonicalize into the same thing,
+ without actually constructing the canonicalization of either one.
+ If VALIDATE is nonzero,
+ we assume X is an expression being processed from the rtl
+ and Y was found in the hash table. We check register refs
+ in Y for being marked as valid.
+
+ If FOR_GCSE is true, we compare X and Y for equivalence for GCSE. */
+
+int
+exp_equiv_p (rtx x, rtx y, int validate, bool for_gcse)
+{
+ int i, j;
+ enum rtx_code code;
+ const char *fmt;
+
+ /* Note: it is incorrect to assume an expression is equivalent to itself
+ if VALIDATE is nonzero. */
+ if (x == y && !validate)
+ return 1;
+
+ if (x == 0 || y == 0)
+ return x == y;
+
+ code = GET_CODE (x);
+ if (code != GET_CODE (y))
+ return 0;
+
+ /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent. */
+ if (GET_MODE (x) != GET_MODE (y))
+ return 0;
+
+ switch (code)
+ {
+ case PC:
+ case CC0:
+ case CONST_INT:
+ case CONST_DOUBLE:
+ return x == y;
+
+ case LABEL_REF:
+ return XEXP (x, 0) == XEXP (y, 0);
+
+ case SYMBOL_REF:
+ return XSTR (x, 0) == XSTR (y, 0);
+
+ case REG:
+ if (for_gcse)
+ return REGNO (x) == REGNO (y);
+ else
+ {
+ unsigned int regno = REGNO (y);
+ unsigned int i;
+ unsigned int endregno
+ = regno + (regno >= FIRST_PSEUDO_REGISTER ? 1
+ : hard_regno_nregs[regno][GET_MODE (y)]);
+
+ /* If the quantities are not the same, the expressions are not
+ equivalent. If there are and we are not to validate, they
+ are equivalent. Otherwise, ensure all regs are up-to-date. */
+
+ if (REG_QTY (REGNO (x)) != REG_QTY (regno))
+ return 0;
+
+ if (! validate)
+ return 1;
+
+ for (i = regno; i < endregno; i++)
+ if (REG_IN_TABLE (i) != REG_TICK (i))
+ return 0;
+
+ return 1;
+ }
+
+ case MEM:
+ if (for_gcse)
+ {
+ /* A volatile mem should not be considered equivalent to any
+ other. */
+ if (MEM_VOLATILE_P (x) || MEM_VOLATILE_P (y))
+ return 0;
+
+ /* Can't merge two expressions in different alias sets, since we
+ can decide that the expression is transparent in a block when
+ it isn't, due to it being set with the different alias set.
+
+ Also, can't merge two expressions with different MEM_ATTRS.
+ They could e.g. be two different entities allocated into the
+ same space on the stack (see e.g. PR25130). In that case, the
+ MEM addresses can be the same, even though the two MEMs are
+ absolutely not equivalent.
+
+ But because really all MEM attributes should be the same for
+ equivalent MEMs, we just use the invariant that MEMs that have
+ the same attributes share the same mem_attrs data structure. */
+ if (MEM_ATTRS (x) != MEM_ATTRS (y))
+ return 0;
+ }
+ break;
+
+ /* For commutative operations, check both orders. */
+ case PLUS:
+ case MULT:
+ case AND:
+ case IOR:
+ case XOR:
+ case NE:
+ case EQ:
+ return ((exp_equiv_p (XEXP (x, 0), XEXP (y, 0),
+ validate, for_gcse)
+ && exp_equiv_p (XEXP (x, 1), XEXP (y, 1),
+ validate, for_gcse))
+ || (exp_equiv_p (XEXP (x, 0), XEXP (y, 1),
+ validate, for_gcse)
+ && exp_equiv_p (XEXP (x, 1), XEXP (y, 0),
+ validate, for_gcse)));
+
+ case ASM_OPERANDS:
+ /* We don't use the generic code below because we want to
+ disregard filename and line numbers. */
+
+ /* A volatile asm isn't equivalent to any other. */
+ if (MEM_VOLATILE_P (x) || MEM_VOLATILE_P (y))
+ return 0;
+
+ if (GET_MODE (x) != GET_MODE (y)
+ || strcmp (ASM_OPERANDS_TEMPLATE (x), ASM_OPERANDS_TEMPLATE (y))
+ || strcmp (ASM_OPERANDS_OUTPUT_CONSTRAINT (x),
+ ASM_OPERANDS_OUTPUT_CONSTRAINT (y))
+ || ASM_OPERANDS_OUTPUT_IDX (x) != ASM_OPERANDS_OUTPUT_IDX (y)
+ || ASM_OPERANDS_INPUT_LENGTH (x) != ASM_OPERANDS_INPUT_LENGTH (y))
+ return 0;
+
+ if (ASM_OPERANDS_INPUT_LENGTH (x))
+ {
+ for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--)
+ if (! exp_equiv_p (ASM_OPERANDS_INPUT (x, i),
+ ASM_OPERANDS_INPUT (y, i),
+ validate, for_gcse)
+ || strcmp (ASM_OPERANDS_INPUT_CONSTRAINT (x, i),
+ ASM_OPERANDS_INPUT_CONSTRAINT (y, i)))
+ return 0;
+ }
+
+ return 1;
+
+ default:
+ break;
+ }
+
+ /* Compare the elements. If any pair of corresponding elements
+ fail to match, return 0 for the whole thing. */
+
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ switch (fmt[i])
+ {
+ case 'e':
+ if (! exp_equiv_p (XEXP (x, i), XEXP (y, i),
+ validate, for_gcse))
+ return 0;
+ break;
+
+ case 'E':
+ if (XVECLEN (x, i) != XVECLEN (y, i))
+ return 0;
+ for (j = 0; j < XVECLEN (x, i); j++)
+ if (! exp_equiv_p (XVECEXP (x, i, j), XVECEXP (y, i, j),
+ validate, for_gcse))
+ return 0;
+ break;
+
+ case 's':
+ if (strcmp (XSTR (x, i), XSTR (y, i)))
+ return 0;
+ break;
+
+ case 'i':
+ if (XINT (x, i) != XINT (y, i))
+ return 0;
+ break;
+
+ case 'w':
+ if (XWINT (x, i) != XWINT (y, i))
+ return 0;
+ break;
+
+ case '0':
+ case 't':
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ }
+
+ return 1;
+}
+
+/* Return 1 if X has a value that can vary even between two
+ executions of the program. 0 means X can be compared reliably
+ against certain constants or near-constants. */
+
+static int
+cse_rtx_varies_p (rtx x, int from_alias)
+{
+ /* We need not check for X and the equivalence class being of the same
+ mode because if X is equivalent to a constant in some mode, it
+ doesn't vary in any mode. */
+
+ if (REG_P (x)
+ && REGNO_QTY_VALID_P (REGNO (x)))
+ {
+ int x_q = REG_QTY (REGNO (x));
+ struct qty_table_elem *x_ent = &qty_table[x_q];
+
+ if (GET_MODE (x) == x_ent->mode
+ && x_ent->const_rtx != NULL_RTX)
+ return 0;
+ }
+
+ if (GET_CODE (x) == PLUS
+ && GET_CODE (XEXP (x, 1)) == CONST_INT
+ && REG_P (XEXP (x, 0))
+ && REGNO_QTY_VALID_P (REGNO (XEXP (x, 0))))
+ {
+ int x0_q = REG_QTY (REGNO (XEXP (x, 0)));
+ struct qty_table_elem *x0_ent = &qty_table[x0_q];
+
+ if ((GET_MODE (XEXP (x, 0)) == x0_ent->mode)
+ && x0_ent->const_rtx != NULL_RTX)
+ return 0;
+ }
+
+ /* This can happen as the result of virtual register instantiation, if
+ the initial constant is too large to be a valid address. This gives
+ us a three instruction sequence, load large offset into a register,
+ load fp minus a constant into a register, then a MEM which is the
+ sum of the two `constant' registers. */
+ if (GET_CODE (x) == PLUS
+ && REG_P (XEXP (x, 0))
+ && REG_P (XEXP (x, 1))
+ && REGNO_QTY_VALID_P (REGNO (XEXP (x, 0)))
+ && REGNO_QTY_VALID_P (REGNO (XEXP (x, 1))))
+ {
+ int x0_q = REG_QTY (REGNO (XEXP (x, 0)));
+ int x1_q = REG_QTY (REGNO (XEXP (x, 1)));
+ struct qty_table_elem *x0_ent = &qty_table[x0_q];
+ struct qty_table_elem *x1_ent = &qty_table[x1_q];
+
+ if ((GET_MODE (XEXP (x, 0)) == x0_ent->mode)
+ && x0_ent->const_rtx != NULL_RTX
+ && (GET_MODE (XEXP (x, 1)) == x1_ent->mode)
+ && x1_ent->const_rtx != NULL_RTX)
+ return 0;
+ }
+
+ return rtx_varies_p (x, from_alias);
+}
+
+/* Subroutine of canon_reg. Pass *XLOC through canon_reg, and validate
+ the result if necessary. INSN is as for canon_reg. */
+
+static void
+validate_canon_reg (rtx *xloc, rtx insn)
+{
+ rtx new = canon_reg (*xloc, insn);
+
+ /* If replacing pseudo with hard reg or vice versa, ensure the
+ insn remains valid. Likewise if the insn has MATCH_DUPs. */
+ if (insn != 0 && new != 0)
+ validate_change (insn, xloc, new, 1);
+ else
+ *xloc = new;
+}
+
+/* Canonicalize an expression:
+ replace each register reference inside it
+ with the "oldest" equivalent register.
+
+ If INSN is nonzero validate_change is used to ensure that INSN remains valid
+ after we make our substitution. The calls are made with IN_GROUP nonzero
+ so apply_change_group must be called upon the outermost return from this
+ function (unless INSN is zero). The result of apply_change_group can
+ generally be discarded since the changes we are making are optional. */
+
+static rtx
+canon_reg (rtx x, rtx insn)
+{
+ int i;
+ enum rtx_code code;
+ const char *fmt;
+
+ if (x == 0)
+ return x;
+
+ code = GET_CODE (x);
+ switch (code)
+ {
+ case PC:
+ case CC0:
+ case CONST:
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case CONST_VECTOR:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ case ADDR_VEC:
+ case ADDR_DIFF_VEC:
+ return x;
+
+ case REG:
+ {
+ int first;
+ int q;
+ struct qty_table_elem *ent;
+
+ /* Never replace a hard reg, because hard regs can appear
+ in more than one machine mode, and we must preserve the mode
+ of each occurrence. Also, some hard regs appear in
+ MEMs that are shared and mustn't be altered. Don't try to
+ replace any reg that maps to a reg of class NO_REGS. */
+ if (REGNO (x) < FIRST_PSEUDO_REGISTER
+ || ! REGNO_QTY_VALID_P (REGNO (x)))
+ return x;
+
+ q = REG_QTY (REGNO (x));
+ ent = &qty_table[q];
+ first = ent->first_reg;
+ return (first >= FIRST_PSEUDO_REGISTER ? regno_reg_rtx[first]
+ : REGNO_REG_CLASS (first) == NO_REGS ? x
+ : gen_rtx_REG (ent->mode, first));
+ }
+
+ default:
+ break;
+ }
+
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ int j;
+
+ if (fmt[i] == 'e')
+ validate_canon_reg (&XEXP (x, i), insn);
+ else if (fmt[i] == 'E')
+ for (j = 0; j < XVECLEN (x, i); j++)
+ validate_canon_reg (&XVECEXP (x, i, j), insn);
+ }
+
+ return x;
+}
+
+/* LOC is a location within INSN that is an operand address (the contents of
+ a MEM). Find the best equivalent address to use that is valid for this
+ insn.
+
+ On most CISC machines, complicated address modes are costly, and rtx_cost
+ is a good approximation for that cost. However, most RISC machines have
+ only a few (usually only one) memory reference formats. If an address is
+ valid at all, it is often just as cheap as any other address. Hence, for
+ RISC machines, we use `address_cost' to compare the costs of various
+ addresses. For two addresses of equal cost, choose the one with the
+ highest `rtx_cost' value as that has the potential of eliminating the
+ most insns. For equal costs, we choose the first in the equivalence
+ class. Note that we ignore the fact that pseudo registers are cheaper than
+ hard registers here because we would also prefer the pseudo registers. */
+
+static void
+find_best_addr (rtx insn, rtx *loc, enum machine_mode mode)
+{
+ struct table_elt *elt;
+ rtx addr = *loc;
+ struct table_elt *p;
+ int found_better = 1;
+ int save_do_not_record = do_not_record;
+ int save_hash_arg_in_memory = hash_arg_in_memory;
+ int addr_volatile;
+ int regno;
+ unsigned hash;
+
+ /* Do not try to replace constant addresses or addresses of local and
+ argument slots. These MEM expressions are made only once and inserted
+ in many instructions, as well as being used to control symbol table
+ output. It is not safe to clobber them.
+
+ There are some uncommon cases where the address is already in a register
+ for some reason, but we cannot take advantage of that because we have
+ no easy way to unshare the MEM. In addition, looking up all stack
+ addresses is costly. */
+ if ((GET_CODE (addr) == PLUS
+ && REG_P (XEXP (addr, 0))
+ && GET_CODE (XEXP (addr, 1)) == CONST_INT
+ && (regno = REGNO (XEXP (addr, 0)),
+ regno == FRAME_POINTER_REGNUM || regno == HARD_FRAME_POINTER_REGNUM
+ || regno == ARG_POINTER_REGNUM))
+ || (REG_P (addr)
+ && (regno = REGNO (addr), regno == FRAME_POINTER_REGNUM
+ || regno == HARD_FRAME_POINTER_REGNUM
+ || regno == ARG_POINTER_REGNUM))
+ || CONSTANT_ADDRESS_P (addr))
+ return;
+
+ /* If this address is not simply a register, try to fold it. This will
+ sometimes simplify the expression. Many simplifications
+ will not be valid, but some, usually applying the associative rule, will
+ be valid and produce better code. */
+ if (!REG_P (addr))
+ {
+ rtx folded = canon_for_address (fold_rtx (addr, NULL_RTX));
+
+ if (folded != addr)
+ {
+ int addr_folded_cost = address_cost (folded, mode);
+ int addr_cost = address_cost (addr, mode);
+
+ if ((addr_folded_cost < addr_cost
+ || (addr_folded_cost == addr_cost
+ /* ??? The rtx_cost comparison is left over from an older
+ version of this code. It is probably no longer helpful.*/
+ && (rtx_cost (folded, MEM) > rtx_cost (addr, MEM)
+ || approx_reg_cost (folded) < approx_reg_cost (addr))))
+ && validate_change (insn, loc, folded, 0))
+ addr = folded;
+ }
+ }
+
+ /* If this address is not in the hash table, we can't look for equivalences
+ of the whole address. Also, ignore if volatile. */
+
+ do_not_record = 0;
+ hash = HASH (addr, Pmode);
+ addr_volatile = do_not_record;
+ do_not_record = save_do_not_record;
+ hash_arg_in_memory = save_hash_arg_in_memory;
+
+ if (addr_volatile)
+ return;
+
+ elt = lookup (addr, hash, Pmode);
+
+ if (elt)
+ {
+ /* We need to find the best (under the criteria documented above) entry
+ in the class that is valid. We use the `flag' field to indicate
+ choices that were invalid and iterate until we can't find a better
+ one that hasn't already been tried. */
+
+ for (p = elt->first_same_value; p; p = p->next_same_value)
+ p->flag = 0;
+
+ while (found_better)
+ {
+ int best_addr_cost = address_cost (*loc, mode);
+ int best_rtx_cost = (elt->cost + 1) >> 1;
+ int exp_cost;
+ /* APPLE LOCAL ARM propagate stack addresses better */
+ bool best_fixed_base_plus_p = fixed_base_plus_p (elt->exp);
+ struct table_elt *best_elt = elt;
+
+ found_better = 0;
+ for (p = elt->first_same_value; p; p = p->next_same_value)
+ if (! p->flag)
+ {
+ if ((REG_P (p->exp)
+ || exp_equiv_p (p->exp, p->exp, 1, false))
+ && ((exp_cost = address_cost (p->exp, mode)) < best_addr_cost
+ || (exp_cost == best_addr_cost
+/* APPLE LOCAL begin ARM propagate stack addresses better */
+#ifdef TARGET_ARM
+ /* Prefer a stack address if possible. Thus, prefer a new
+ stack address to an old non-stack address, and do not replace
+ an old stack address with a new non-stack address. */
+ && ((!best_fixed_base_plus_p && fixed_base_plus_p (p->exp))
+ || (!(best_fixed_base_plus_p && !fixed_base_plus_p (p->exp))
+ && ((p->cost + 1) >> 1) > best_rtx_cost))
+#else
+ && ((p->cost + 1) >> 1) > best_rtx_cost
+#endif
+ )))
+/* APPLE LOCAL end ARM propagate stack addresses better */
+ {
+ found_better = 1;
+ best_addr_cost = exp_cost;
+ best_rtx_cost = (p->cost + 1) >> 1;
+ /* APPLE LOCAL ARM propagate stack addresses better */
+ best_fixed_base_plus_p = fixed_base_plus_p (p->exp);
+ best_elt = p;
+ }
+ }
+
+ if (found_better)
+ {
+ if (validate_change (insn, loc,
+ canon_reg (copy_rtx (best_elt->exp),
+ NULL_RTX), 0))
+ return;
+ else
+ best_elt->flag = 1;
+ }
+ }
+ }
+
+ /* If the address is a binary operation with the first operand a register
+ and the second a constant, do the same as above, but looking for
+ equivalences of the register. Then try to simplify before checking for
+ the best address to use. This catches a few cases: First is when we
+ have REG+const and the register is another REG+const. We can often merge
+ the constants and eliminate one insn and one register. It may also be
+ that a machine has a cheap REG+REG+const. Finally, this improves the
+ code on the Alpha for unaligned byte stores. */
+
+ if (flag_expensive_optimizations
+ && ARITHMETIC_P (*loc)
+ && REG_P (XEXP (*loc, 0)))
+ {
+ rtx op1 = XEXP (*loc, 1);
+
+ do_not_record = 0;
+ hash = HASH (XEXP (*loc, 0), Pmode);
+ do_not_record = save_do_not_record;
+ hash_arg_in_memory = save_hash_arg_in_memory;
+
+ elt = lookup (XEXP (*loc, 0), hash, Pmode);
+ if (elt == 0)
+ return;
+
+ /* We need to find the best (under the criteria documented above) entry
+ in the class that is valid. We use the `flag' field to indicate
+ choices that were invalid and iterate until we can't find a better
+ one that hasn't already been tried. */
+
+ for (p = elt->first_same_value; p; p = p->next_same_value)
+ p->flag = 0;
+
+ while (found_better)
+ {
+ int best_addr_cost = address_cost (*loc, mode);
+ int best_rtx_cost = (COST (*loc) + 1) >> 1;
+ struct table_elt *best_elt = elt;
+ rtx best_rtx = *loc;
+ int count;
+
+ /* This is at worst case an O(n^2) algorithm, so limit our search
+ to the first 32 elements on the list. This avoids trouble
+ compiling code with very long basic blocks that can easily
+ call simplify_gen_binary so many times that we run out of
+ memory. */
+
+ found_better = 0;
+ for (p = elt->first_same_value, count = 0;
+ p && count < 32;
+ p = p->next_same_value, count++)
+ if (! p->flag
+ && (REG_P (p->exp)
+ || (GET_CODE (p->exp) != EXPR_LIST
+ && exp_equiv_p (p->exp, p->exp, 1, false))))
+
+ {
+ rtx new = simplify_gen_binary (GET_CODE (*loc), Pmode,
+ p->exp, op1);
+ int new_cost;
+
+ /* Get the canonical version of the address so we can accept
+ more. */
+ new = canon_for_address (new);
+
+ new_cost = address_cost (new, mode);
+
+ if (new_cost < best_addr_cost
+ || (new_cost == best_addr_cost
+ && (COST (new) + 1) >> 1 > best_rtx_cost))
+ {
+ found_better = 1;
+ best_addr_cost = new_cost;
+ best_rtx_cost = (COST (new) + 1) >> 1;
+ best_elt = p;
+ best_rtx = new;
+ }
+ }
+
+ if (found_better)
+ {
+ if (validate_change (insn, loc,
+ canon_reg (copy_rtx (best_rtx),
+ NULL_RTX), 0))
+ return;
+ else
+ best_elt->flag = 1;
+ }
+ }
+ }
+}
+
+/* Given an operation (CODE, *PARG1, *PARG2), where code is a comparison
+ operation (EQ, NE, GT, etc.), follow it back through the hash table and
+ what values are being compared.
+
+ *PARG1 and *PARG2 are updated to contain the rtx representing the values
+ actually being compared. For example, if *PARG1 was (cc0) and *PARG2
+ was (const_int 0), *PARG1 and *PARG2 will be set to the objects that were
+ compared to produce cc0.
+
+ The return value is the comparison operator and is either the code of
+ A or the code corresponding to the inverse of the comparison. */
+
+static enum rtx_code
+find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
+ enum machine_mode *pmode1, enum machine_mode *pmode2)
+{
+ rtx arg1, arg2;
+
+ arg1 = *parg1, arg2 = *parg2;
+
+ /* If ARG2 is const0_rtx, see what ARG1 is equivalent to. */
+
+ while (arg2 == CONST0_RTX (GET_MODE (arg1)))
+ {
+ /* Set nonzero when we find something of interest. */
+ rtx x = 0;
+ int reverse_code = 0;
+ struct table_elt *p = 0;
+
+ /* If arg1 is a COMPARE, extract the comparison arguments from it.
+ On machines with CC0, this is the only case that can occur, since
+ fold_rtx will return the COMPARE or item being compared with zero
+ when given CC0. */
+
+ if (GET_CODE (arg1) == COMPARE && arg2 == const0_rtx)
+ x = arg1;
+
+ /* If ARG1 is a comparison operator and CODE is testing for
+ STORE_FLAG_VALUE, get the inner arguments. */
+
+ else if (COMPARISON_P (arg1))
+ {
+#ifdef FLOAT_STORE_FLAG_VALUE
+ REAL_VALUE_TYPE fsfv;
+#endif
+
+ if (code == NE
+ || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_INT
+ && code == LT && STORE_FLAG_VALUE == -1)
+#ifdef FLOAT_STORE_FLAG_VALUE
+ || (SCALAR_FLOAT_MODE_P (GET_MODE (arg1))
+ && (fsfv = FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)),
+ REAL_VALUE_NEGATIVE (fsfv)))
+#endif
+ )
+ x = arg1;
+ else if (code == EQ
+ || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_INT
+ && code == GE && STORE_FLAG_VALUE == -1)
+#ifdef FLOAT_STORE_FLAG_VALUE
+ || (SCALAR_FLOAT_MODE_P (GET_MODE (arg1))
+ && (fsfv = FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)),
+ REAL_VALUE_NEGATIVE (fsfv)))
+#endif
+ )
+ x = arg1, reverse_code = 1;
+ }
+
+ /* ??? We could also check for
+
+ (ne (and (eq (...) (const_int 1))) (const_int 0))
+
+ and related forms, but let's wait until we see them occurring. */
+
+ if (x == 0)
+ /* Look up ARG1 in the hash table and see if it has an equivalence
+ that lets us see what is being compared. */
+ p = lookup (arg1, SAFE_HASH (arg1, GET_MODE (arg1)), GET_MODE (arg1));
+ if (p)
+ {
+ p = p->first_same_value;
+
+ /* If what we compare is already known to be constant, that is as
+ good as it gets.
+ We need to break the loop in this case, because otherwise we
+ can have an infinite loop when looking at a reg that is known
+ to be a constant which is the same as a comparison of a reg
+ against zero which appears later in the insn stream, which in
+ turn is constant and the same as the comparison of the first reg
+ against zero... */
+ if (p->is_const)
+ break;
+ }
+
+ for (; p; p = p->next_same_value)
+ {
+ enum machine_mode inner_mode = GET_MODE (p->exp);
+#ifdef FLOAT_STORE_FLAG_VALUE
+ REAL_VALUE_TYPE fsfv;
+#endif
+
+ /* If the entry isn't valid, skip it. */
+ if (! exp_equiv_p (p->exp, p->exp, 1, false))
+ continue;
+
+ if (GET_CODE (p->exp) == COMPARE
+ /* Another possibility is that this machine has a compare insn
+ that includes the comparison code. In that case, ARG1 would
+ be equivalent to a comparison operation that would set ARG1 to
+ either STORE_FLAG_VALUE or zero. If this is an NE operation,
+ ORIG_CODE is the actual comparison being done; if it is an EQ,
+ we must reverse ORIG_CODE. On machine with a negative value
+ for STORE_FLAG_VALUE, also look at LT and GE operations. */
+ || ((code == NE
+ || (code == LT
+ && GET_MODE_CLASS (inner_mode) == MODE_INT
+ && (GET_MODE_BITSIZE (inner_mode)
+ <= HOST_BITS_PER_WIDE_INT)
+ && (STORE_FLAG_VALUE
+ & ((HOST_WIDE_INT) 1
+ << (GET_MODE_BITSIZE (inner_mode) - 1))))
+#ifdef FLOAT_STORE_FLAG_VALUE
+ || (code == LT
+ && SCALAR_FLOAT_MODE_P (inner_mode)
+ && (fsfv = FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)),
+ REAL_VALUE_NEGATIVE (fsfv)))
+#endif
+ )
+ && COMPARISON_P (p->exp)))
+ {
+ x = p->exp;
+ break;
+ }
+ else if ((code == EQ
+ || (code == GE
+ && GET_MODE_CLASS (inner_mode) == MODE_INT
+ && (GET_MODE_BITSIZE (inner_mode)
+ <= HOST_BITS_PER_WIDE_INT)
+ && (STORE_FLAG_VALUE
+ & ((HOST_WIDE_INT) 1
+ << (GET_MODE_BITSIZE (inner_mode) - 1))))
+#ifdef FLOAT_STORE_FLAG_VALUE
+ || (code == GE
+ && SCALAR_FLOAT_MODE_P (inner_mode)
+ && (fsfv = FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)),
+ REAL_VALUE_NEGATIVE (fsfv)))
+#endif
+ )
+ && COMPARISON_P (p->exp))
+ {
+ reverse_code = 1;
+ x = p->exp;
+ break;
+ }
+
+ /* If this non-trapping address, e.g. fp + constant, the
+ equivalent is a better operand since it may let us predict
+ the value of the comparison. */
+ else if (!rtx_addr_can_trap_p (p->exp))
+ {
+ arg1 = p->exp;
+ continue;
+ }
+ }
+
+ /* If we didn't find a useful equivalence for ARG1, we are done.
+ Otherwise, set up for the next iteration. */
+ if (x == 0)
+ break;
+
+ /* If we need to reverse the comparison, make sure that that is
+ possible -- we can't necessarily infer the value of GE from LT
+ with floating-point operands. */
+ if (reverse_code)
+ {
+ enum rtx_code reversed = reversed_comparison_code (x, NULL_RTX);
+ if (reversed == UNKNOWN)
+ break;
+ else
+ code = reversed;
+ }
+ else if (COMPARISON_P (x))
+ code = GET_CODE (x);
+ arg1 = XEXP (x, 0), arg2 = XEXP (x, 1);
+ }
+
+ /* Return our results. Return the modes from before fold_rtx
+ because fold_rtx might produce const_int, and then it's too late. */
+ *pmode1 = GET_MODE (arg1), *pmode2 = GET_MODE (arg2);
+ *parg1 = fold_rtx (arg1, 0), *parg2 = fold_rtx (arg2, 0);
+
+ return code;
+}
+
+/* Fold SUBREG. */
+
+static rtx
+fold_rtx_subreg (rtx x, rtx insn)
+{
+ enum machine_mode mode = GET_MODE (x);
+ rtx folded_arg0;
+ rtx const_arg0;
+ rtx new;
+
+ /* See if we previously assigned a constant value to this SUBREG. */
+ if ((new = lookup_as_function (x, CONST_INT)) != 0
+ || (new = lookup_as_function (x, CONST_DOUBLE)) != 0)
+ return new;
+
+ /* If this is a paradoxical SUBREG, we have no idea what value the
+ extra bits would have. However, if the operand is equivalent to
+ a SUBREG whose operand is the same as our mode, and all the modes
+ are within a word, we can just use the inner operand because
+ these SUBREGs just say how to treat the register.
+
+ Similarly if we find an integer constant. */
+
+ if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
+ {
+ enum machine_mode imode = GET_MODE (SUBREG_REG (x));
+ struct table_elt *elt;
+
+ if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
+ && GET_MODE_SIZE (imode) <= UNITS_PER_WORD
+ && (elt = lookup (SUBREG_REG (x), HASH (SUBREG_REG (x), imode),
+ imode)) != 0)
+ for (elt = elt->first_same_value; elt; elt = elt->next_same_value)
+ {
+ if (CONSTANT_P (elt->exp)
+ && GET_MODE (elt->exp) == VOIDmode)
+ return elt->exp;
+
+ if (GET_CODE (elt->exp) == SUBREG
+ && GET_MODE (SUBREG_REG (elt->exp)) == mode
+ && exp_equiv_p (elt->exp, elt->exp, 1, false))
+ return copy_rtx (SUBREG_REG (elt->exp));
+ }
+
+ return x;
+ }
+
+ /* Fold SUBREG_REG. If it changed, see if we can simplify the
+ SUBREG. We might be able to if the SUBREG is extracting a single
+ word in an integral mode or extracting the low part. */
+
+ folded_arg0 = fold_rtx (SUBREG_REG (x), insn);
+ const_arg0 = equiv_constant (folded_arg0);
+ if (const_arg0)
+ folded_arg0 = const_arg0;
+
+ if (folded_arg0 != SUBREG_REG (x))
+ {
+ new = simplify_subreg (mode, folded_arg0,
+ GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
+ if (new)
+ return new;
+ }
+
+ if (REG_P (folded_arg0)
+ && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (folded_arg0)))
+ {
+ struct table_elt *elt;
+
+ elt = lookup (folded_arg0,
+ HASH (folded_arg0, GET_MODE (folded_arg0)),
+ GET_MODE (folded_arg0));
+
+ if (elt)
+ elt = elt->first_same_value;
+
+ if (subreg_lowpart_p (x))
+ /* If this is a narrowing SUBREG and our operand is a REG, see
+ if we can find an equivalence for REG that is an arithmetic
+ operation in a wider mode where both operands are
+ paradoxical SUBREGs from objects of our result mode. In
+ that case, we couldn-t report an equivalent value for that
+ operation, since we don't know what the extra bits will be.
+ But we can find an equivalence for this SUBREG by folding
+ that operation in the narrow mode. This allows us to fold
+ arithmetic in narrow modes when the machine only supports
+ word-sized arithmetic.
+
+ Also look for a case where we have a SUBREG whose operand
+ is the same as our result. If both modes are smaller than
+ a word, we are simply interpreting a register in different
+ modes and we can use the inner value. */
+
+ for (; elt; elt = elt->next_same_value)
+ {
+ enum rtx_code eltcode = GET_CODE (elt->exp);
+
+ /* Just check for unary and binary operations. */
+ if (UNARY_P (elt->exp)
+ && eltcode != SIGN_EXTEND
+ && eltcode != ZERO_EXTEND
+ && GET_CODE (XEXP (elt->exp, 0)) == SUBREG
+ && GET_MODE (SUBREG_REG (XEXP (elt->exp, 0))) == mode
+ && (GET_MODE_CLASS (mode)
+ == GET_MODE_CLASS (GET_MODE (XEXP (elt->exp, 0)))))
+ {
+ rtx op0 = SUBREG_REG (XEXP (elt->exp, 0));
+
+ if (!REG_P (op0) && ! CONSTANT_P (op0))
+ op0 = fold_rtx (op0, NULL_RTX);
+
+ op0 = equiv_constant (op0);
+ if (op0)
+ new = simplify_unary_operation (GET_CODE (elt->exp), mode,
+ op0, mode);
+ }
+ else if (ARITHMETIC_P (elt->exp)
+ && eltcode != DIV && eltcode != MOD
+ && eltcode != UDIV && eltcode != UMOD
+ && eltcode != ASHIFTRT && eltcode != LSHIFTRT
+ && eltcode != ROTATE && eltcode != ROTATERT
+ && ((GET_CODE (XEXP (elt->exp, 0)) == SUBREG
+ && (GET_MODE (SUBREG_REG (XEXP (elt->exp, 0)))
+ == mode))
+ || CONSTANT_P (XEXP (elt->exp, 0)))
+ && ((GET_CODE (XEXP (elt->exp, 1)) == SUBREG
+ && (GET_MODE (SUBREG_REG (XEXP (elt->exp, 1)))
+ == mode))
+ || CONSTANT_P (XEXP (elt->exp, 1))))
+ {
+ rtx op0 = gen_lowpart_common (mode, XEXP (elt->exp, 0));
+ rtx op1 = gen_lowpart_common (mode, XEXP (elt->exp, 1));
+
+ if (op0 && !REG_P (op0) && ! CONSTANT_P (op0))
+ op0 = fold_rtx (op0, NULL_RTX);
+
+ if (op0)
+ op0 = equiv_constant (op0);
+
+ if (op1 && !REG_P (op1) && ! CONSTANT_P (op1))
+ op1 = fold_rtx (op1, NULL_RTX);
+
+ if (op1)
+ op1 = equiv_constant (op1);
+
+ /* If we are looking for the low SImode part of
+ (ashift:DI c (const_int 32)), it doesn't work to
+ compute that in SImode, because a 32-bit shift in
+ SImode is unpredictable. We know the value is
+ 0. */
+ if (op0 && op1
+ && GET_CODE (elt->exp) == ASHIFT
+ && GET_CODE (op1) == CONST_INT
+ && INTVAL (op1) >= GET_MODE_BITSIZE (mode))
+ {
+ if (INTVAL (op1)
+ < GET_MODE_BITSIZE (GET_MODE (elt->exp)))
+ /* If the count fits in the inner mode's width,
+ but exceeds the outer mode's width, the value
+ will get truncated to 0 by the subreg. */
+ new = CONST0_RTX (mode);
+ else
+ /* If the count exceeds even the inner mode's width,
+ don't fold this expression. */
+ new = 0;
+ }
+ else if (op0 && op1)
+ new = simplify_binary_operation (GET_CODE (elt->exp),
+ mode, op0, op1);
+ }
+
+ else if (GET_CODE (elt->exp) == SUBREG
+ && GET_MODE (SUBREG_REG (elt->exp)) == mode
+ && (GET_MODE_SIZE (GET_MODE (folded_arg0))
+ <= UNITS_PER_WORD)
+ && exp_equiv_p (elt->exp, elt->exp, 1, false))
+ new = copy_rtx (SUBREG_REG (elt->exp));
+
+ if (new)
+ return new;
+ }
+ else
+ /* A SUBREG resulting from a zero extension may fold to zero
+ if it extracts higher bits than the ZERO_EXTEND's source
+ bits. FIXME: if combine tried to, er, combine these
+ instructions, this transformation may be moved to
+ simplify_subreg. */
+ for (; elt; elt = elt->next_same_value)
+ {
+ if (GET_CODE (elt->exp) == ZERO_EXTEND
+ && subreg_lsb (x)
+ >= GET_MODE_BITSIZE (GET_MODE (XEXP (elt->exp, 0))))
+ return CONST0_RTX (mode);
+ }
+ }
+
+ return x;
+}
+
+/* Fold MEM. Not to be called directly, see fold_rtx_mem instead. */
+
+static rtx
+fold_rtx_mem_1 (rtx x, rtx insn)
+{
+ enum machine_mode mode = GET_MODE (x);
+ rtx new;
+
+ /* If we are not actually processing an insn, don't try to find the
+ best address. Not only don't we care, but we could modify the
+ MEM in an invalid way since we have no insn to validate
+ against. */
+ if (insn != 0)
+ find_best_addr (insn, &XEXP (x, 0), mode);
+
+ {
+ /* Even if we don't fold in the insn itself, we can safely do so
+ here, in hopes of getting a constant. */
+ rtx addr = fold_rtx (XEXP (x, 0), NULL_RTX);
+ rtx base = 0;
+ HOST_WIDE_INT offset = 0;
+
+ if (REG_P (addr)
+ && REGNO_QTY_VALID_P (REGNO (addr)))
+ {
+ int addr_q = REG_QTY (REGNO (addr));
+ struct qty_table_elem *addr_ent = &qty_table[addr_q];
+
+ if (GET_MODE (addr) == addr_ent->mode
+ && addr_ent->const_rtx != NULL_RTX)
+ addr = addr_ent->const_rtx;
+ }
+
+ /* Call target hook to avoid the effects of -fpic etc.... */
+ addr = targetm.delegitimize_address (addr);
+
+ /* If address is constant, split it into a base and integer
+ offset. */
+ if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
+ base = addr;
+ else if (GET_CODE (addr) == CONST && GET_CODE (XEXP (addr, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST_INT)
+ {
+ base = XEXP (XEXP (addr, 0), 0);
+ offset = INTVAL (XEXP (XEXP (addr, 0), 1));
+ }
+ else if (GET_CODE (addr) == LO_SUM
+ && GET_CODE (XEXP (addr, 1)) == SYMBOL_REF)
+ base = XEXP (addr, 1);
+
+ /* If this is a constant pool reference, we can fold it into its
+ constant to allow better value tracking. */
+ if (base && GET_CODE (base) == SYMBOL_REF
+ && CONSTANT_POOL_ADDRESS_P (base))
+ {
+ rtx constant = get_pool_constant (base);
+ enum machine_mode const_mode = get_pool_mode (base);
+ rtx new;
+
+ if (CONSTANT_P (constant) && GET_CODE (constant) != CONST_INT)
+ {
+ constant_pool_entries_cost = COST (constant);
+ constant_pool_entries_regcost = approx_reg_cost (constant);
+ }
+
+ /* If we are loading the full constant, we have an
+ equivalence. */
+ if (offset == 0 && mode == const_mode)
+ return constant;
+
+ /* If this actually isn't a constant (weird!), we can't do
+ anything. Otherwise, handle the two most common cases:
+ extracting a word from a multi-word constant, and
+ extracting the low-order bits. Other cases don't seem
+ common enough to worry about. */
+ if (! CONSTANT_P (constant))
+ return x;
+
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && GET_MODE_SIZE (mode) == UNITS_PER_WORD
+ && offset % UNITS_PER_WORD == 0
+ && (new = operand_subword (constant,
+ offset / UNITS_PER_WORD,
+ 0, const_mode)) != 0)
+ return new;
+
+ if (((BYTES_BIG_ENDIAN
+ && offset == GET_MODE_SIZE (GET_MODE (constant)) - 1)
+ || (! BYTES_BIG_ENDIAN && offset == 0))
+ && (new = gen_lowpart (mode, constant)) != 0)
+ return new;
+ }
+
+ /* If this is a reference to a label at a known position in a jump
+ table, we also know its value. */
+ if (base && GET_CODE (base) == LABEL_REF)
+ {
+ rtx label = XEXP (base, 0);
+ rtx table_insn = NEXT_INSN (label);
+
+ if (table_insn && JUMP_P (table_insn)
+ && GET_CODE (PATTERN (table_insn)) == ADDR_VEC)
+ {
+ rtx table = PATTERN (table_insn);
+
+ if (offset >= 0
+ && (offset / GET_MODE_SIZE (GET_MODE (table))
+ < XVECLEN (table, 0)))
+ {
+ rtx label = XVECEXP
+ (table, 0, offset / GET_MODE_SIZE (GET_MODE (table)));
+ rtx set;
+
+ /* If we have an insn that loads the label from the
+ jumptable into a reg, we don't want to set the reg
+ to the label, because this may cause a reference to
+ the label to remain after the label is removed in
+ some very obscure cases (PR middle-end/18628). */
+ if (!insn)
+ return label;
+
+ set = single_set (insn);
+
+ if (! set || SET_SRC (set) != x)
+ return x;
+
+ /* If it's a jump, it's safe to reference the label. */
+ if (SET_DEST (set) == pc_rtx)
+ return label;
+
+ return x;
+ }
+ }
+ if (table_insn && JUMP_P (table_insn)
+ && GET_CODE (PATTERN (table_insn)) == ADDR_DIFF_VEC)
+ {
+ rtx table = PATTERN (table_insn);
+
+ if (offset >= 0
+ && (offset / GET_MODE_SIZE (GET_MODE (table))
+ < XVECLEN (table, 1)))
+ {
+ offset /= GET_MODE_SIZE (GET_MODE (table));
+ new = gen_rtx_MINUS (Pmode, XVECEXP (table, 1, offset),
+ XEXP (table, 0));
+
+ if (GET_MODE (table) != Pmode)
+ new = gen_rtx_TRUNCATE (GET_MODE (table), new);
+
+ /* Indicate this is a constant. This isn't a valid
+ form of CONST, but it will only be used to fold the
+ next insns and then discarded, so it should be
+ safe.
+
+ Note this expression must be explicitly discarded,
+ by cse_insn, else it may end up in a REG_EQUAL note
+ and "escape" to cause problems elsewhere. */
+ return gen_rtx_CONST (GET_MODE (new), new);
+ }
+ }
+ }
+
+ return x;
+ }
+}
+
+/* Fold MEM. */
+
+static rtx
+fold_rtx_mem (rtx x, rtx insn)
+{
+ /* To avoid infinite oscillations between fold_rtx and fold_rtx_mem,
+ refuse to allow recursion of the latter past n levels. This can
+ happen because fold_rtx_mem will try to fold the address of the
+ memory reference it is passed, i.e. conceptually throwing away
+ the MEM and reinjecting the bare address into fold_rtx. As a
+ result, patterns like
+
+ set (reg1)
+ (plus (reg)
+ (mem (plus (reg2) (const_int))))
+
+ set (reg2)
+ (plus (reg)
+ (mem (plus (reg1) (const_int))))
+
+ will defeat any "first-order" short-circuit put in either
+ function to prevent these infinite oscillations.
+
+ The heuristics for determining n is as follows: since each time
+ it is invoked fold_rtx_mem throws away a MEM, and since MEMs
+ are generically not nested, we assume that each invocation of
+ fold_rtx_mem corresponds to a new "top-level" operand, i.e.
+ the source or the destination of a SET. So fold_rtx_mem is
+ bound to stop or cycle before n recursions, n being the number
+ of expressions recorded in the hash table. We also leave some
+ play to account for the initial steps. */
+
+ static unsigned int depth;
+ rtx ret;
+
+ if (depth > 3 + table_size)
+ return x;
+
+ depth++;
+ ret = fold_rtx_mem_1 (x, insn);
+ depth--;
+
+ return ret;
+}
+
+/* If X is a nontrivial arithmetic operation on an argument
+ for which a constant value can be determined, return
+ the result of operating on that value, as a constant.
+ Otherwise, return X, possibly with one or more operands
+ modified by recursive calls to this function.
+
+ If X is a register whose contents are known, we do NOT
+ return those contents here. equiv_constant is called to
+ perform that task.
+
+ INSN is the insn that we may be modifying. If it is 0, make a copy
+ of X before modifying it. */
+
+static rtx
+fold_rtx (rtx x, rtx insn)
+{
+ enum rtx_code code;
+ enum machine_mode mode;
+ const char *fmt;
+ int i;
+ rtx new = 0;
+ int copied = 0;
+ int must_swap = 0;
+
+ /* Folded equivalents of first two operands of X. */
+ rtx folded_arg0;
+ rtx folded_arg1;
+
+ /* Constant equivalents of first three operands of X;
+ 0 when no such equivalent is known. */
+ rtx const_arg0;
+ rtx const_arg1;
+ rtx const_arg2;
+
+ /* The mode of the first operand of X. We need this for sign and zero
+ extends. */
+ enum machine_mode mode_arg0;
+
+ if (x == 0)
+ return x;
+
+ mode = GET_MODE (x);
+ code = GET_CODE (x);
+ switch (code)
+ {
+ case CONST:
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case CONST_VECTOR:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ case REG:
+ case PC:
+ /* No use simplifying an EXPR_LIST
+ since they are used only for lists of args
+ in a function call's REG_EQUAL note. */
+ case EXPR_LIST:
+ return x;
+
+#ifdef HAVE_cc0
+ case CC0:
+ return prev_insn_cc0;
+#endif
+
+ case SUBREG:
+ return fold_rtx_subreg (x, insn);
+
+ case NOT:
+ case NEG:
+ /* If we have (NOT Y), see if Y is known to be (NOT Z).
+ If so, (NOT Y) simplifies to Z. Similarly for NEG. */
+ new = lookup_as_function (XEXP (x, 0), code);
+ if (new)
+ return fold_rtx (copy_rtx (XEXP (new, 0)), insn);
+ break;
+
+ case MEM:
+ return fold_rtx_mem (x, insn);
+
+#ifdef NO_FUNCTION_CSE
+ case CALL:
+ if (CONSTANT_P (XEXP (XEXP (x, 0), 0)))
+ return x;
+ break;
+#endif
+
+ case ASM_OPERANDS:
+ if (insn)
+ {
+ for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--)
+ validate_change (insn, &ASM_OPERANDS_INPUT (x, i),
+ fold_rtx (ASM_OPERANDS_INPUT (x, i), insn), 0);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ const_arg0 = 0;
+ const_arg1 = 0;
+ const_arg2 = 0;
+ mode_arg0 = VOIDmode;
+
+ /* Try folding our operands.
+ Then see which ones have constant values known. */
+
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ if (fmt[i] == 'e')
+ {
+ rtx arg = XEXP (x, i);
+ rtx folded_arg = arg, const_arg = 0;
+ enum machine_mode mode_arg = GET_MODE (arg);
+ rtx cheap_arg, expensive_arg;
+ rtx replacements[2];
+ int j;
+ int old_cost = COST_IN (XEXP (x, i), code);
+
+ /* Most arguments are cheap, so handle them specially. */
+ switch (GET_CODE (arg))
+ {
+ case REG:
+ /* This is the same as calling equiv_constant; it is duplicated
+ here for speed. */
+ if (REGNO_QTY_VALID_P (REGNO (arg)))
+ {
+ int arg_q = REG_QTY (REGNO (arg));
+ struct qty_table_elem *arg_ent = &qty_table[arg_q];
+
+ if (arg_ent->const_rtx != NULL_RTX
+ && !REG_P (arg_ent->const_rtx)
+ && GET_CODE (arg_ent->const_rtx) != PLUS)
+ const_arg
+ = gen_lowpart (GET_MODE (arg),
+ arg_ent->const_rtx);
+ }
+ break;
+
+ case CONST:
+ case CONST_INT:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ case CONST_DOUBLE:
+ case CONST_VECTOR:
+ const_arg = arg;
+ break;
+
+#ifdef HAVE_cc0
+ case CC0:
+ folded_arg = prev_insn_cc0;
+ mode_arg = prev_insn_cc0_mode;
+ const_arg = equiv_constant (folded_arg);
+ break;
+#endif
+
+ default:
+ folded_arg = fold_rtx (arg, insn);
+ const_arg = equiv_constant (folded_arg);
+ }
+
+ /* For the first three operands, see if the operand
+ is constant or equivalent to a constant. */
+ switch (i)
+ {
+ case 0:
+ folded_arg0 = folded_arg;
+ const_arg0 = const_arg;
+ mode_arg0 = mode_arg;
+ break;
+ case 1:
+ folded_arg1 = folded_arg;
+ const_arg1 = const_arg;
+ break;
+ case 2:
+ const_arg2 = const_arg;
+ break;
+ }
+
+ /* Pick the least expensive of the folded argument and an
+ equivalent constant argument. */
+ if (const_arg == 0 || const_arg == folded_arg
+ || COST_IN (const_arg, code) > COST_IN (folded_arg, code))
+ cheap_arg = folded_arg, expensive_arg = const_arg;
+ else
+ cheap_arg = const_arg, expensive_arg = folded_arg;
+
+ /* Try to replace the operand with the cheapest of the two
+ possibilities. If it doesn't work and this is either of the first
+ two operands of a commutative operation, try swapping them.
+ If THAT fails, try the more expensive, provided it is cheaper
+ than what is already there. */
+
+ if (cheap_arg == XEXP (x, i))
+ continue;
+
+ if (insn == 0 && ! copied)
+ {
+ x = copy_rtx (x);
+ copied = 1;
+ }
+
+ /* Order the replacements from cheapest to most expensive. */
+ replacements[0] = cheap_arg;
+ replacements[1] = expensive_arg;
+
+ for (j = 0; j < 2 && replacements[j]; j++)
+ {
+ int new_cost = COST_IN (replacements[j], code);
+
+ /* Stop if what existed before was cheaper. Prefer constants
+ in the case of a tie. */
+ if (new_cost > old_cost
+ || (new_cost == old_cost && CONSTANT_P (XEXP (x, i))))
+ break;
+
+ /* It's not safe to substitute the operand of a conversion
+ operator with a constant, as the conversion's identity
+ depends upon the mode of its operand. This optimization
+ is handled by the call to simplify_unary_operation. */
+ if (GET_RTX_CLASS (code) == RTX_UNARY
+ && GET_MODE (replacements[j]) != mode_arg0
+ && (code == ZERO_EXTEND
+ || code == SIGN_EXTEND
+ || code == TRUNCATE
+ || code == FLOAT_TRUNCATE
+ || code == FLOAT_EXTEND
+ || code == FLOAT
+ || code == FIX
+ || code == UNSIGNED_FLOAT
+ || code == UNSIGNED_FIX))
+ continue;
+
+ if (validate_change (insn, &XEXP (x, i), replacements[j], 0))
+ break;
+
+ if (GET_RTX_CLASS (code) == RTX_COMM_COMPARE
+ || GET_RTX_CLASS (code) == RTX_COMM_ARITH)
+ {
+ validate_change (insn, &XEXP (x, i), XEXP (x, 1 - i), 1);
+ validate_change (insn, &XEXP (x, 1 - i), replacements[j], 1);
+
+ if (apply_change_group ())
+ {
+ /* Swap them back to be invalid so that this loop can
+ continue and flag them to be swapped back later. */
+ rtx tem;
+
+ tem = XEXP (x, 0); XEXP (x, 0) = XEXP (x, 1);
+ XEXP (x, 1) = tem;
+ must_swap = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ else
+ {
+ if (fmt[i] == 'E')
+ /* Don't try to fold inside of a vector of expressions.
+ Doing nothing is harmless. */
+ {;}
+ }
+
+ /* If a commutative operation, place a constant integer as the second
+ operand unless the first operand is also a constant integer. Otherwise,
+ place any constant second unless the first operand is also a constant. */
+
+ if (COMMUTATIVE_P (x))
+ {
+ if (must_swap
+ || swap_commutative_operands_p (const_arg0 ? const_arg0
+ : XEXP (x, 0),
+ const_arg1 ? const_arg1
+ : XEXP (x, 1)))
+ {
+ rtx tem = XEXP (x, 0);
+
+ if (insn == 0 && ! copied)
+ {
+ x = copy_rtx (x);
+ copied = 1;
+ }
+
+ validate_change (insn, &XEXP (x, 0), XEXP (x, 1), 1);
+ validate_change (insn, &XEXP (x, 1), tem, 1);
+ if (apply_change_group ())
+ {
+ tem = const_arg0, const_arg0 = const_arg1, const_arg1 = tem;
+ tem = folded_arg0, folded_arg0 = folded_arg1, folded_arg1 = tem;
+ }
+ }
+ }
+
+ /* If X is an arithmetic operation, see if we can simplify it. */
+
+ switch (GET_RTX_CLASS (code))
+ {
+ case RTX_UNARY:
+ {
+ int is_const = 0;
+
+ /* We can't simplify extension ops unless we know the
+ original mode. */
+ if ((code == ZERO_EXTEND || code == SIGN_EXTEND)
+ && mode_arg0 == VOIDmode)
+ break;
+
+ /* If we had a CONST, strip it off and put it back later if we
+ fold. */
+ if (const_arg0 != 0 && GET_CODE (const_arg0) == CONST)
+ is_const = 1, const_arg0 = XEXP (const_arg0, 0);
+
+ new = simplify_unary_operation (code, mode,
+ const_arg0 ? const_arg0 : folded_arg0,
+ mode_arg0);
+ /* NEG of PLUS could be converted into MINUS, but that causes
+ expressions of the form
+ (CONST (MINUS (CONST_INT) (SYMBOL_REF)))
+ which many ports mistakenly treat as LEGITIMATE_CONSTANT_P.
+ FIXME: those ports should be fixed. */
+ if (new != 0 && is_const
+ && GET_CODE (new) == PLUS
+ && (GET_CODE (XEXP (new, 0)) == SYMBOL_REF
+ || GET_CODE (XEXP (new, 0)) == LABEL_REF)
+ && GET_CODE (XEXP (new, 1)) == CONST_INT)
+ new = gen_rtx_CONST (mode, new);
+ }
+ break;
+
+ case RTX_COMPARE:
+ case RTX_COMM_COMPARE:
+ /* See what items are actually being compared and set FOLDED_ARG[01]
+ to those values and CODE to the actual comparison code. If any are
+ constant, set CONST_ARG0 and CONST_ARG1 appropriately. We needn't
+ do anything if both operands are already known to be constant. */
+
+ /* ??? Vector mode comparisons are not supported yet. */
+ if (VECTOR_MODE_P (mode))
+ break;
+
+ if (const_arg0 == 0 || const_arg1 == 0)
+ {
+ struct table_elt *p0, *p1;
+ rtx true_rtx = const_true_rtx, false_rtx = const0_rtx;
+ enum machine_mode mode_arg1;
+
+#ifdef FLOAT_STORE_FLAG_VALUE
+ if (SCALAR_FLOAT_MODE_P (mode))
+ {
+ true_rtx = (CONST_DOUBLE_FROM_REAL_VALUE
+ (FLOAT_STORE_FLAG_VALUE (mode), mode));
+ false_rtx = CONST0_RTX (mode);
+ }
+#endif
+
+ code = find_comparison_args (code, &folded_arg0, &folded_arg1,
+ &mode_arg0, &mode_arg1);
+
+ /* If the mode is VOIDmode or a MODE_CC mode, we don't know
+ what kinds of things are being compared, so we can't do
+ anything with this comparison. */
+
+ if (mode_arg0 == VOIDmode || GET_MODE_CLASS (mode_arg0) == MODE_CC)
+ break;
+
+ const_arg0 = equiv_constant (folded_arg0);
+ const_arg1 = equiv_constant (folded_arg1);
+
+ /* If we do not now have two constants being compared, see
+ if we can nevertheless deduce some things about the
+ comparison. */
+ if (const_arg0 == 0 || const_arg1 == 0)
+ {
+ if (const_arg1 != NULL)
+ {
+ rtx cheapest_simplification;
+ int cheapest_cost;
+ rtx simp_result;
+ struct table_elt *p;
+
+ /* See if we can find an equivalent of folded_arg0
+ that gets us a cheaper expression, possibly a
+ constant through simplifications. */
+ p = lookup (folded_arg0, SAFE_HASH (folded_arg0, mode_arg0),
+ mode_arg0);
+
+ if (p != NULL)
+ {
+ cheapest_simplification = x;
+ cheapest_cost = COST (x);
+
+ for (p = p->first_same_value; p != NULL; p = p->next_same_value)
+ {
+ int cost;
+
+ /* If the entry isn't valid, skip it. */
+ if (! exp_equiv_p (p->exp, p->exp, 1, false))
+ continue;
+
+ /* Try to simplify using this equivalence. */
+ simp_result
+ = simplify_relational_operation (code, mode,
+ mode_arg0,
+ p->exp,
+ const_arg1);
+
+ if (simp_result == NULL)
+ continue;
+
+ cost = COST (simp_result);
+ if (cost < cheapest_cost)
+ {
+ cheapest_cost = cost;
+ cheapest_simplification = simp_result;
+ }
+ }
+
+ /* If we have a cheaper expression now, use that
+ and try folding it further, from the top. */
+ if (cheapest_simplification != x)
+ return fold_rtx (cheapest_simplification, insn);
+ }
+ }
+
+ /* Some addresses are known to be nonzero. We don't know
+ their sign, but equality comparisons are known. */
+ if (const_arg1 == const0_rtx
+ && nonzero_address_p (folded_arg0))
+ {
+ if (code == EQ)
+ return false_rtx;
+ else if (code == NE)
+ return true_rtx;
+ }
+
+ /* See if the two operands are the same. */
+
+ if (folded_arg0 == folded_arg1
+ || (REG_P (folded_arg0)
+ && REG_P (folded_arg1)
+ && (REG_QTY (REGNO (folded_arg0))
+ == REG_QTY (REGNO (folded_arg1))))
+ || ((p0 = lookup (folded_arg0,
+ SAFE_HASH (folded_arg0, mode_arg0),
+ mode_arg0))
+ && (p1 = lookup (folded_arg1,
+ SAFE_HASH (folded_arg1, mode_arg0),
+ mode_arg0))
+ && p0->first_same_value == p1->first_same_value))
+ {
+ /* Sadly two equal NaNs are not equivalent. */
+ if (!HONOR_NANS (mode_arg0))
+ return ((code == EQ || code == LE || code == GE
+ || code == LEU || code == GEU || code == UNEQ
+ || code == UNLE || code == UNGE
+ || code == ORDERED)
+ ? true_rtx : false_rtx);
+ /* Take care for the FP compares we can resolve. */
+ if (code == UNEQ || code == UNLE || code == UNGE)
+ return true_rtx;
+ if (code == LTGT || code == LT || code == GT)
+ return false_rtx;
+ }
+
+ /* If FOLDED_ARG0 is a register, see if the comparison we are
+ doing now is either the same as we did before or the reverse
+ (we only check the reverse if not floating-point). */
+ else if (REG_P (folded_arg0))
+ {
+ int qty = REG_QTY (REGNO (folded_arg0));
+
+ if (REGNO_QTY_VALID_P (REGNO (folded_arg0)))
+ {
+ struct qty_table_elem *ent = &qty_table[qty];
+
+ if ((comparison_dominates_p (ent->comparison_code, code)
+ || (! FLOAT_MODE_P (mode_arg0)
+ && comparison_dominates_p (ent->comparison_code,
+ reverse_condition (code))))
+ && (rtx_equal_p (ent->comparison_const, folded_arg1)
+ || (const_arg1
+ && rtx_equal_p (ent->comparison_const,
+ const_arg1))
+ || (REG_P (folded_arg1)
+ /* APPLE LOCAL ARM 4587904 */
+ && (REGNO_QTY_VALID_P (REGNO (folded_arg1)))
+ && (REG_QTY (REGNO (folded_arg1)) == ent->comparison_qty))))
+ return (comparison_dominates_p (ent->comparison_code, code)
+ ? true_rtx : false_rtx);
+ }
+ }
+ }
+ }
+
+ /* If we are comparing against zero, see if the first operand is
+ equivalent to an IOR with a constant. If so, we may be able to
+ determine the result of this comparison. */
+
+ if (const_arg1 == const0_rtx)
+ {
+ rtx y = lookup_as_function (folded_arg0, IOR);
+ rtx inner_const;
+
+ if (y != 0
+ && (inner_const = equiv_constant (XEXP (y, 1))) != 0
+ && GET_CODE (inner_const) == CONST_INT
+ && INTVAL (inner_const) != 0)
+ {
+ int sign_bitnum = GET_MODE_BITSIZE (mode_arg0) - 1;
+ int has_sign = (HOST_BITS_PER_WIDE_INT >= sign_bitnum
+ && (INTVAL (inner_const)
+ & ((HOST_WIDE_INT) 1 << sign_bitnum)));
+ rtx true_rtx = const_true_rtx, false_rtx = const0_rtx;
+
+#ifdef FLOAT_STORE_FLAG_VALUE
+ if (SCALAR_FLOAT_MODE_P (mode))
+ {
+ true_rtx = (CONST_DOUBLE_FROM_REAL_VALUE
+ (FLOAT_STORE_FLAG_VALUE (mode), mode));
+ false_rtx = CONST0_RTX (mode);
+ }
+#endif
+
+ switch (code)
+ {
+ case EQ:
+ return false_rtx;
+ case NE:
+ return true_rtx;
+ case LT: case LE:
+ if (has_sign)
+ return true_rtx;
+ break;
+ case GT: case GE:
+ if (has_sign)
+ return false_rtx;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ {
+ rtx op0 = const_arg0 ? const_arg0 : folded_arg0;
+ rtx op1 = const_arg1 ? const_arg1 : folded_arg1;
+ new = simplify_relational_operation (code, mode, mode_arg0, op0, op1);
+ }
+ break;
+
+ case RTX_BIN_ARITH:
+ case RTX_COMM_ARITH:
+ switch (code)
+ {
+ case PLUS:
+ /* If the second operand is a LABEL_REF, see if the first is a MINUS
+ with that LABEL_REF as its second operand. If so, the result is
+ the first operand of that MINUS. This handles switches with an
+ ADDR_DIFF_VEC table. */
+ if (const_arg1 && GET_CODE (const_arg1) == LABEL_REF)
+ {
+ rtx y
+ = GET_CODE (folded_arg0) == MINUS ? folded_arg0
+ : lookup_as_function (folded_arg0, MINUS);
+
+ if (y != 0 && GET_CODE (XEXP (y, 1)) == LABEL_REF
+ && XEXP (XEXP (y, 1), 0) == XEXP (const_arg1, 0))
+ return XEXP (y, 0);
+
+ /* Now try for a CONST of a MINUS like the above. */
+ if ((y = (GET_CODE (folded_arg0) == CONST ? folded_arg0
+ : lookup_as_function (folded_arg0, CONST))) != 0
+ && GET_CODE (XEXP (y, 0)) == MINUS
+ && GET_CODE (XEXP (XEXP (y, 0), 1)) == LABEL_REF
+ && XEXP (XEXP (XEXP (y, 0), 1), 0) == XEXP (const_arg1, 0))
+ return XEXP (XEXP (y, 0), 0);
+ }
+
+ /* Likewise if the operands are in the other order. */
+ if (const_arg0 && GET_CODE (const_arg0) == LABEL_REF)
+ {
+ rtx y
+ = GET_CODE (folded_arg1) == MINUS ? folded_arg1
+ : lookup_as_function (folded_arg1, MINUS);
+
+ if (y != 0 && GET_CODE (XEXP (y, 1)) == LABEL_REF
+ && XEXP (XEXP (y, 1), 0) == XEXP (const_arg0, 0))
+ return XEXP (y, 0);
+
+ /* Now try for a CONST of a MINUS like the above. */
+ if ((y = (GET_CODE (folded_arg1) == CONST ? folded_arg1
+ : lookup_as_function (folded_arg1, CONST))) != 0
+ && GET_CODE (XEXP (y, 0)) == MINUS
+ && GET_CODE (XEXP (XEXP (y, 0), 1)) == LABEL_REF
+ && XEXP (XEXP (XEXP (y, 0), 1), 0) == XEXP (const_arg0, 0))
+ return XEXP (XEXP (y, 0), 0);
+ }
+
+ /* If second operand is a register equivalent to a negative
+ CONST_INT, see if we can find a register equivalent to the
+ positive constant. Make a MINUS if so. Don't do this for
+ a non-negative constant since we might then alternate between
+ choosing positive and negative constants. Having the positive
+ constant previously-used is the more common case. Be sure
+ the resulting constant is non-negative; if const_arg1 were
+ the smallest negative number this would overflow: depending
+ on the mode, this would either just be the same value (and
+ hence not save anything) or be incorrect. */
+ if (const_arg1 != 0 && GET_CODE (const_arg1) == CONST_INT
+ && INTVAL (const_arg1) < 0
+ /* This used to test
+
+ -INTVAL (const_arg1) >= 0
+
+ But The Sun V5.0 compilers mis-compiled that test. So
+ instead we test for the problematic value in a more direct
+ manner and hope the Sun compilers get it correct. */
+ && INTVAL (const_arg1) !=
+ ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1))
+ && REG_P (folded_arg1))
+ {
+ rtx new_const = GEN_INT (-INTVAL (const_arg1));
+ struct table_elt *p
+ = lookup (new_const, SAFE_HASH (new_const, mode), mode);
+
+ if (p)
+ for (p = p->first_same_value; p; p = p->next_same_value)
+ if (REG_P (p->exp))
+ return simplify_gen_binary (MINUS, mode, folded_arg0,
+ canon_reg (p->exp, NULL_RTX));
+ }
+ goto from_plus;
+
+ case MINUS:
+ /* If we have (MINUS Y C), see if Y is known to be (PLUS Z C2).
+ If so, produce (PLUS Z C2-C). */
+ if (const_arg1 != 0 && GET_CODE (const_arg1) == CONST_INT)
+ {
+ rtx y = lookup_as_function (XEXP (x, 0), PLUS);
+ if (y && GET_CODE (XEXP (y, 1)) == CONST_INT)
+ return fold_rtx (plus_constant (copy_rtx (y),
+ -INTVAL (const_arg1)),
+ NULL_RTX);
+ }
+
+ /* Fall through. */
+
+ from_plus:
+ case SMIN: case SMAX: case UMIN: case UMAX:
+ case IOR: case AND: case XOR:
+ case MULT:
+ case ASHIFT: case LSHIFTRT: case ASHIFTRT:
+ /* If we have (<op> <reg> <const_int>) for an associative OP and REG
+ is known to be of similar form, we may be able to replace the
+ operation with a combined operation. This may eliminate the
+ intermediate operation if every use is simplified in this way.
+ Note that the similar optimization done by combine.c only works
+ if the intermediate operation's result has only one reference. */
+
+ if (REG_P (folded_arg0)
+ && const_arg1 && GET_CODE (const_arg1) == CONST_INT)
+ {
+ int is_shift
+ = (code == ASHIFT || code == ASHIFTRT || code == LSHIFTRT);
+ rtx y, inner_const, new_const;
+ enum rtx_code associate_code;
+
+ if (is_shift
+ && (INTVAL (const_arg1) >= GET_MODE_BITSIZE (mode)
+ || INTVAL (const_arg1) < 0))
+ {
+ if (SHIFT_COUNT_TRUNCATED)
+ const_arg1 = GEN_INT (INTVAL (const_arg1)
+ & (GET_MODE_BITSIZE (mode) - 1));
+ else
+ break;
+ }
+
+ y = lookup_as_function (folded_arg0, code);
+ if (y == 0)
+ break;
+
+ /* If we have compiled a statement like
+ "if (x == (x & mask1))", and now are looking at
+ "x & mask2", we will have a case where the first operand
+ of Y is the same as our first operand. Unless we detect
+ this case, an infinite loop will result. */
+ if (XEXP (y, 0) == folded_arg0)
+ break;
+
+ inner_const = equiv_constant (fold_rtx (XEXP (y, 1), 0));
+ if (!inner_const || GET_CODE (inner_const) != CONST_INT)
+ break;
+
+ /* Don't associate these operations if they are a PLUS with the
+ same constant and it is a power of two. These might be doable
+ with a pre- or post-increment. Similarly for two subtracts of
+ identical powers of two with post decrement. */
+
+ if (code == PLUS && const_arg1 == inner_const
+ && ((HAVE_PRE_INCREMENT
+ && exact_log2 (INTVAL (const_arg1)) >= 0)
+ || (HAVE_POST_INCREMENT
+ && exact_log2 (INTVAL (const_arg1)) >= 0)
+ || (HAVE_PRE_DECREMENT
+ && exact_log2 (- INTVAL (const_arg1)) >= 0)
+ || (HAVE_POST_DECREMENT
+ && exact_log2 (- INTVAL (const_arg1)) >= 0)))
+ break;
+
+ if (is_shift
+ && (INTVAL (inner_const) >= GET_MODE_BITSIZE (mode)
+ || INTVAL (inner_const) < 0))
+ {
+ if (SHIFT_COUNT_TRUNCATED)
+ inner_const = GEN_INT (INTVAL (inner_const)
+ & (GET_MODE_BITSIZE (mode) - 1));
+ else
+ break;
+ }
+
+ /* Compute the code used to compose the constants. For example,
+ A-C1-C2 is A-(C1 + C2), so if CODE == MINUS, we want PLUS. */
+
+ associate_code = (is_shift || code == MINUS ? PLUS : code);
+
+ new_const = simplify_binary_operation (associate_code, mode,
+ const_arg1, inner_const);
+
+ if (new_const == 0)
+ break;
+
+ /* If we are associating shift operations, don't let this
+ produce a shift of the size of the object or larger.
+ This could occur when we follow a sign-extend by a right
+ shift on a machine that does a sign-extend as a pair
+ of shifts. */
+
+ if (is_shift
+ && GET_CODE (new_const) == CONST_INT
+ && INTVAL (new_const) >= GET_MODE_BITSIZE (mode))
+ {
+ /* As an exception, we can turn an ASHIFTRT of this
+ form into a shift of the number of bits - 1. */
+ if (code == ASHIFTRT)
+ new_const = GEN_INT (GET_MODE_BITSIZE (mode) - 1);
+ else if (!side_effects_p (XEXP (y, 0)))
+ return CONST0_RTX (mode);
+ else
+ break;
+ }
+
+ y = copy_rtx (XEXP (y, 0));
+
+ /* If Y contains our first operand (the most common way this
+ can happen is if Y is a MEM), we would do into an infinite
+ loop if we tried to fold it. So don't in that case. */
+
+ if (! reg_mentioned_p (folded_arg0, y))
+ y = fold_rtx (y, insn);
+
+ return simplify_gen_binary (code, mode, y, new_const);
+ }
+ break;
+
+ case DIV: case UDIV:
+ /* ??? The associative optimization performed immediately above is
+ also possible for DIV and UDIV using associate_code of MULT.
+ However, we would need extra code to verify that the
+ multiplication does not overflow, that is, there is no overflow
+ in the calculation of new_const. */
+ break;
+
+ default:
+ break;
+ }
+
+ new = simplify_binary_operation (code, mode,
+ const_arg0 ? const_arg0 : folded_arg0,
+ const_arg1 ? const_arg1 : folded_arg1);
+ break;
+
+ case RTX_OBJ:
+ /* (lo_sum (high X) X) is simply X. */
+ if (code == LO_SUM && const_arg0 != 0
+ && GET_CODE (const_arg0) == HIGH
+ && rtx_equal_p (XEXP (const_arg0, 0), const_arg1))
+ return const_arg1;
+ break;
+
+ case RTX_TERNARY:
+ case RTX_BITFIELD_OPS:
+ new = simplify_ternary_operation (code, mode, mode_arg0,
+ const_arg0 ? const_arg0 : folded_arg0,
+ const_arg1 ? const_arg1 : folded_arg1,
+ const_arg2 ? const_arg2 : XEXP (x, 2));
+ break;
+
+ default:
+ break;
+ }
+
+ return new ? new : x;
+}
+
+/* Return a constant value currently equivalent to X.
+ Return 0 if we don't know one. */
+
+static rtx
+equiv_constant (rtx x)
+{
+ if (REG_P (x)
+ && REGNO_QTY_VALID_P (REGNO (x)))
+ {
+ int x_q = REG_QTY (REGNO (x));
+ struct qty_table_elem *x_ent = &qty_table[x_q];
+
+ if (x_ent->const_rtx)
+ x = gen_lowpart (GET_MODE (x), x_ent->const_rtx);
+ }
+
+ if (x == 0 || CONSTANT_P (x))
+ return x;
+
+ /* If X is a MEM, try to fold it outside the context of any insn to see if
+ it might be equivalent to a constant. That handles the case where it
+ is a constant-pool reference. Then try to look it up in the hash table
+ in case it is something whose value we have seen before. */
+
+ if (MEM_P (x))
+ {
+ struct table_elt *elt;
+
+ x = fold_rtx (x, NULL_RTX);
+ if (CONSTANT_P (x))
+ return x;
+
+ elt = lookup (x, SAFE_HASH (x, GET_MODE (x)), GET_MODE (x));
+ if (elt == 0)
+ return 0;
+
+ for (elt = elt->first_same_value; elt; elt = elt->next_same_value)
+ if (elt->is_const && CONSTANT_P (elt->exp))
+ return elt->exp;
+ }
+
+ return 0;
+}
+
+/* Given INSN, a jump insn, PATH_TAKEN indicates if we are following the "taken"
+ branch. It will be zero if not.
+
+ In certain cases, this can cause us to add an equivalence. For example,
+ if we are following the taken case of
+ if (i == 2)
+ we can add the fact that `i' and '2' are now equivalent.
+
+ In any case, we can record that this comparison was passed. If the same
+ comparison is seen later, we will know its value. */
+
+static void
+record_jump_equiv (rtx insn, int taken)
+{
+ int cond_known_true;
+ rtx op0, op1;
+ rtx set;
+ enum machine_mode mode, mode0, mode1;
+ int reversed_nonequality = 0;
+ enum rtx_code code;
+
+ /* Ensure this is the right kind of insn. */
+ if (! any_condjump_p (insn))
+ return;
+ set = pc_set (insn);
+
+ /* See if this jump condition is known true or false. */
+ if (taken)
+ cond_known_true = (XEXP (SET_SRC (set), 2) == pc_rtx);
+ else
+ cond_known_true = (XEXP (SET_SRC (set), 1) == pc_rtx);
+
+ /* Get the type of comparison being done and the operands being compared.
+ If we had to reverse a non-equality condition, record that fact so we
+ know that it isn't valid for floating-point. */
+ code = GET_CODE (XEXP (SET_SRC (set), 0));
+ op0 = fold_rtx (XEXP (XEXP (SET_SRC (set), 0), 0), insn);
+ op1 = fold_rtx (XEXP (XEXP (SET_SRC (set), 0), 1), insn);
+
+ code = find_comparison_args (code, &op0, &op1, &mode0, &mode1);
+
+ /* If the mode is a MODE_CC mode, we don't know what kinds of things
+ are being compared, so we can't do anything with this
+ comparison. */
+
+ if (GET_MODE_CLASS (mode0) == MODE_CC)
+ return;
+
+ if (! cond_known_true)
+ {
+ code = reversed_comparison_code_parts (code, op0, op1, insn);
+
+ /* Don't remember if we can't find the inverse. */
+ if (code == UNKNOWN)
+ return;
+ }
+
+ /* The mode is the mode of the non-constant. */
+ mode = mode0;
+ if (mode1 != VOIDmode)
+ mode = mode1;
+
+ record_jump_cond (code, mode, op0, op1, reversed_nonequality);
+}
+
+/* Yet another form of subreg creation. In this case, we want something in
+ MODE, and we should assume OP has MODE iff it is naturally modeless. */
+
+static rtx
+record_jump_cond_subreg (enum machine_mode mode, rtx op)
+{
+ enum machine_mode op_mode = GET_MODE (op);
+ if (op_mode == mode || op_mode == VOIDmode)
+ return op;
+ return lowpart_subreg (mode, op, op_mode);
+}
+
+/* We know that comparison CODE applied to OP0 and OP1 in MODE is true.
+ REVERSED_NONEQUALITY is nonzero if CODE had to be swapped.
+ Make any useful entries we can with that information. Called from
+ above function and called recursively. */
+
+static void
+record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
+ rtx op1, int reversed_nonequality)
+{
+ unsigned op0_hash, op1_hash;
+ int op0_in_memory, op1_in_memory;
+ struct table_elt *op0_elt, *op1_elt;
+
+ /* If OP0 and OP1 are known equal, and either is a paradoxical SUBREG,
+ we know that they are also equal in the smaller mode (this is also
+ true for all smaller modes whether or not there is a SUBREG, but
+ is not worth testing for with no SUBREG). */
+
+ /* Note that GET_MODE (op0) may not equal MODE. */
+ if (code == EQ && GET_CODE (op0) == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (op0))
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))))
+ {
+ enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
+ rtx tem = record_jump_cond_subreg (inner_mode, op1);
+ if (tem)
+ record_jump_cond (code, mode, SUBREG_REG (op0), tem,
+ reversed_nonequality);
+ }
+
+ if (code == EQ && GET_CODE (op1) == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (op1))
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1)))))
+ {
+ enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
+ rtx tem = record_jump_cond_subreg (inner_mode, op0);
+ if (tem)
+ record_jump_cond (code, mode, SUBREG_REG (op1), tem,
+ reversed_nonequality);
+ }
+
+ /* Similarly, if this is an NE comparison, and either is a SUBREG
+ making a smaller mode, we know the whole thing is also NE. */
+
+ /* Note that GET_MODE (op0) may not equal MODE;
+ if we test MODE instead, we can get an infinite recursion
+ alternating between two modes each wider than MODE. */
+
+ if (code == NE && GET_CODE (op0) == SUBREG
+ && subreg_lowpart_p (op0)
+ && (GET_MODE_SIZE (GET_MODE (op0))
+ < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))))
+ {
+ enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
+ rtx tem = record_jump_cond_subreg (inner_mode, op1);
+ if (tem)
+ record_jump_cond (code, mode, SUBREG_REG (op0), tem,
+ reversed_nonequality);
+ }
+
+ if (code == NE && GET_CODE (op1) == SUBREG
+ && subreg_lowpart_p (op1)
+ && (GET_MODE_SIZE (GET_MODE (op1))
+ < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1)))))
+ {
+ enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
+ rtx tem = record_jump_cond_subreg (inner_mode, op0);
+ if (tem)
+ record_jump_cond (code, mode, SUBREG_REG (op1), tem,
+ reversed_nonequality);
+ }
+
+ /* Hash both operands. */
+
+ do_not_record = 0;
+ hash_arg_in_memory = 0;
+ op0_hash = HASH (op0, mode);
+ op0_in_memory = hash_arg_in_memory;
+
+ if (do_not_record)
+ return;
+
+ do_not_record = 0;
+ hash_arg_in_memory = 0;
+ op1_hash = HASH (op1, mode);
+ op1_in_memory = hash_arg_in_memory;
+
+ if (do_not_record)
+ return;
+
+ /* Look up both operands. */
+ op0_elt = lookup (op0, op0_hash, mode);
+ op1_elt = lookup (op1, op1_hash, mode);
+
+ /* If both operands are already equivalent or if they are not in the
+ table but are identical, do nothing. */
+ if ((op0_elt != 0 && op1_elt != 0
+ && op0_elt->first_same_value == op1_elt->first_same_value)
+ || op0 == op1 || rtx_equal_p (op0, op1))
+ return;
+
+ /* If we aren't setting two things equal all we can do is save this
+ comparison. Similarly if this is floating-point. In the latter
+ case, OP1 might be zero and both -0.0 and 0.0 are equal to it.
+ If we record the equality, we might inadvertently delete code
+ whose intent was to change -0 to +0. */
+
+ if (code != EQ || FLOAT_MODE_P (GET_MODE (op0)))
+ {
+ struct qty_table_elem *ent;
+ int qty;
+
+ /* If we reversed a floating-point comparison, if OP0 is not a
+ register, or if OP1 is neither a register or constant, we can't
+ do anything. */
+
+ if (!REG_P (op1))
+ op1 = equiv_constant (op1);
+
+ if ((reversed_nonequality && FLOAT_MODE_P (mode))
+ || !REG_P (op0) || op1 == 0)
+ return;
+
+ /* Put OP0 in the hash table if it isn't already. This gives it a
+ new quantity number. */
+ if (op0_elt == 0)
+ {
+ if (insert_regs (op0, NULL, 0))
+ {
+ rehash_using_reg (op0);
+ op0_hash = HASH (op0, mode);
+
+ /* If OP0 is contained in OP1, this changes its hash code
+ as well. Faster to rehash than to check, except
+ for the simple case of a constant. */
+ if (! CONSTANT_P (op1))
+ op1_hash = HASH (op1,mode);
+ }
+
+ op0_elt = insert (op0, NULL, op0_hash, mode);
+ op0_elt->in_memory = op0_in_memory;
+ }
+
+ qty = REG_QTY (REGNO (op0));
+ ent = &qty_table[qty];
+
+ ent->comparison_code = code;
+ if (REG_P (op1))
+ {
+ /* Look it up again--in case op0 and op1 are the same. */
+ op1_elt = lookup (op1, op1_hash, mode);
+
+ /* Put OP1 in the hash table so it gets a new quantity number. */
+ if (op1_elt == 0)
+ {
+ if (insert_regs (op1, NULL, 0))
+ {
+ rehash_using_reg (op1);
+ op1_hash = HASH (op1, mode);
+ }
+
+ op1_elt = insert (op1, NULL, op1_hash, mode);
+ op1_elt->in_memory = op1_in_memory;
+ }
+
+ ent->comparison_const = NULL_RTX;
+ ent->comparison_qty = REG_QTY (REGNO (op1));
+ }
+ else
+ {
+ ent->comparison_const = op1;
+ ent->comparison_qty = -1;
+ }
+
+ return;
+ }
+
+ /* If either side is still missing an equivalence, make it now,
+ then merge the equivalences. */
+
+ if (op0_elt == 0)
+ {
+ if (insert_regs (op0, NULL, 0))
+ {
+ rehash_using_reg (op0);
+ op0_hash = HASH (op0, mode);
+ }
+
+ op0_elt = insert (op0, NULL, op0_hash, mode);
+ op0_elt->in_memory = op0_in_memory;
+ }
+
+ if (op1_elt == 0)
+ {
+ if (insert_regs (op1, NULL, 0))
+ {
+ rehash_using_reg (op1);
+ op1_hash = HASH (op1, mode);
+ }
+
+ op1_elt = insert (op1, NULL, op1_hash, mode);
+ op1_elt->in_memory = op1_in_memory;
+ }
+
+ merge_equiv_classes (op0_elt, op1_elt);
+}
+
+/* CSE processing for one instruction.
+ First simplify sources and addresses of all assignments
+ in the instruction, using previously-computed equivalents values.
+ Then install the new sources and destinations in the table
+ of available values.
+
+ If LIBCALL_INSN is nonzero, don't record any equivalence made in
+ the insn. It means that INSN is inside libcall block. In this
+ case LIBCALL_INSN is the corresponding insn with REG_LIBCALL. */
+
+/* Data on one SET contained in the instruction. */
+
+struct set
+{
+ /* The SET rtx itself. */
+ rtx rtl;
+ /* The SET_SRC of the rtx (the original value, if it is changing). */
+ rtx src;
+ /* The hash-table element for the SET_SRC of the SET. */
+ struct table_elt *src_elt;
+ /* Hash value for the SET_SRC. */
+ unsigned src_hash;
+ /* Hash value for the SET_DEST. */
+ unsigned dest_hash;
+ /* The SET_DEST, with SUBREG, etc., stripped. */
+ rtx inner_dest;
+ /* Nonzero if the SET_SRC is in memory. */
+ char src_in_memory;
+ /* Nonzero if the SET_SRC contains something
+ whose value cannot be predicted and understood. */
+ char src_volatile;
+ /* Original machine mode, in case it becomes a CONST_INT.
+ The size of this field should match the size of the mode
+ field of struct rtx_def (see rtl.h). */
+ ENUM_BITFIELD(machine_mode) mode : 8;
+ /* A constant equivalent for SET_SRC, if any. */
+ rtx src_const;
+ /* Original SET_SRC value used for libcall notes. */
+ rtx orig_src;
+ /* Hash value of constant equivalent for SET_SRC. */
+ unsigned src_const_hash;
+ /* Table entry for constant equivalent for SET_SRC, if any. */
+ struct table_elt *src_const_elt;
+ /* Table entry for the destination address. */
+ struct table_elt *dest_addr_elt;
+};
+
+static void
+cse_insn (rtx insn, rtx libcall_insn)
+{
+ rtx x = PATTERN (insn);
+ int i;
+ rtx tem;
+ int n_sets = 0;
+
+#ifdef HAVE_cc0
+ /* Records what this insn does to set CC0. */
+ rtx this_insn_cc0 = 0;
+ enum machine_mode this_insn_cc0_mode = VOIDmode;
+#endif
+
+ rtx src_eqv = 0;
+ struct table_elt *src_eqv_elt = 0;
+ int src_eqv_volatile = 0;
+ int src_eqv_in_memory = 0;
+ unsigned src_eqv_hash = 0;
+
+ struct set *sets = (struct set *) 0;
+
+ this_insn = insn;
+
+ /* Find all the SETs and CLOBBERs in this instruction.
+ Record all the SETs in the array `set' and count them.
+ Also determine whether there is a CLOBBER that invalidates
+ all memory references, or all references at varying addresses. */
+
+ if (CALL_P (insn))
+ {
+ for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
+ {
+ if (GET_CODE (XEXP (tem, 0)) == CLOBBER)
+ invalidate (SET_DEST (XEXP (tem, 0)), VOIDmode);
+ XEXP (tem, 0) = canon_reg (XEXP (tem, 0), insn);
+ }
+ }
+
+ if (GET_CODE (x) == SET)
+ {
+ sets = alloca (sizeof (struct set));
+ sets[0].rtl = x;
+
+ /* Ignore SETs that are unconditional jumps.
+ They never need cse processing, so this does not hurt.
+ The reason is not efficiency but rather
+ so that we can test at the end for instructions
+ that have been simplified to unconditional jumps
+ and not be misled by unchanged instructions
+ that were unconditional jumps to begin with. */
+ if (SET_DEST (x) == pc_rtx
+ && GET_CODE (SET_SRC (x)) == LABEL_REF)
+ ;
+
+ /* Don't count call-insns, (set (reg 0) (call ...)), as a set.
+ The hard function value register is used only once, to copy to
+ someplace else, so it isn't worth cse'ing (and on 80386 is unsafe)!
+ Ensure we invalidate the destination register. On the 80386 no
+ other code would invalidate it since it is a fixed_reg.
+ We need not check the return of apply_change_group; see canon_reg. */
+
+ else if (GET_CODE (SET_SRC (x)) == CALL)
+ {
+ canon_reg (SET_SRC (x), insn);
+ apply_change_group ();
+ fold_rtx (SET_SRC (x), insn);
+ invalidate (SET_DEST (x), VOIDmode);
+ }
+ else
+ n_sets = 1;
+ }
+ else if (GET_CODE (x) == PARALLEL)
+ {
+ int lim = XVECLEN (x, 0);
+
+ sets = alloca (lim * sizeof (struct set));
+
+ /* Find all regs explicitly clobbered in this insn,
+ and ensure they are not replaced with any other regs
+ elsewhere in this insn.
+ When a reg that is clobbered is also used for input,
+ we should presume that that is for a reason,
+ and we should not substitute some other register
+ which is not supposed to be clobbered.
+ Therefore, this loop cannot be merged into the one below
+ because a CALL may precede a CLOBBER and refer to the
+ value clobbered. We must not let a canonicalization do
+ anything in that case. */
+ for (i = 0; i < lim; i++)
+ {
+ rtx y = XVECEXP (x, 0, i);
+ if (GET_CODE (y) == CLOBBER)
+ {
+ rtx clobbered = XEXP (y, 0);
+
+ if (REG_P (clobbered)
+ || GET_CODE (clobbered) == SUBREG)
+ invalidate (clobbered, VOIDmode);
+ else if (GET_CODE (clobbered) == STRICT_LOW_PART
+ || GET_CODE (clobbered) == ZERO_EXTRACT)
+ invalidate (XEXP (clobbered, 0), GET_MODE (clobbered));
+ }
+ }
+
+ for (i = 0; i < lim; i++)
+ {
+ rtx y = XVECEXP (x, 0, i);
+ if (GET_CODE (y) == SET)
+ {
+ /* As above, we ignore unconditional jumps and call-insns and
+ ignore the result of apply_change_group. */
+ if (GET_CODE (SET_SRC (y)) == CALL)
+ {
+ canon_reg (SET_SRC (y), insn);
+ apply_change_group ();
+ fold_rtx (SET_SRC (y), insn);
+ invalidate (SET_DEST (y), VOIDmode);
+ }
+ else if (SET_DEST (y) == pc_rtx
+ && GET_CODE (SET_SRC (y)) == LABEL_REF)
+ ;
+ /* APPLE LOCAL begin radar 5596043, mainline candidate */
+ /* Ignore the asm operand of an inline assembly instruction
+ when finding all the SETs and invalidate its target. */
+ else if (GET_CODE (SET_SRC (y)) == ASM_OPERANDS)
+ {
+ invalidate (XEXP (y, 0), VOIDmode);
+ }
+ /* APPLE LOCAL end radar 5596043, mainline candidate */
+ else
+ sets[n_sets++].rtl = y;
+ }
+ else if (GET_CODE (y) == CLOBBER)
+ {
+ /* If we clobber memory, canon the address.
+ This does nothing when a register is clobbered
+ because we have already invalidated the reg. */
+ if (MEM_P (XEXP (y, 0)))
+ canon_reg (XEXP (y, 0), NULL_RTX);
+ }
+ else if (GET_CODE (y) == USE
+ && ! (REG_P (XEXP (y, 0))
+ && REGNO (XEXP (y, 0)) < FIRST_PSEUDO_REGISTER))
+ canon_reg (y, NULL_RTX);
+ else if (GET_CODE (y) == CALL)
+ {
+ /* The result of apply_change_group can be ignored; see
+ canon_reg. */
+ canon_reg (y, insn);
+ apply_change_group ();
+ fold_rtx (y, insn);
+ }
+ }
+ }
+ else if (GET_CODE (x) == CLOBBER)
+ {
+ if (MEM_P (XEXP (x, 0)))
+ canon_reg (XEXP (x, 0), NULL_RTX);
+ }
+
+ /* Canonicalize a USE of a pseudo register or memory location. */
+ else if (GET_CODE (x) == USE
+ && ! (REG_P (XEXP (x, 0))
+ && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER))
+ canon_reg (XEXP (x, 0), NULL_RTX);
+ else if (GET_CODE (x) == CALL)
+ {
+ /* The result of apply_change_group can be ignored; see canon_reg. */
+ canon_reg (x, insn);
+ apply_change_group ();
+ fold_rtx (x, insn);
+ }
+
+ /* Store the equivalent value in SRC_EQV, if different, or if the DEST
+ is a STRICT_LOW_PART. The latter condition is necessary because SRC_EQV
+ is handled specially for this case, and if it isn't set, then there will
+ be no equivalence for the destination. */
+ if (n_sets == 1 && REG_NOTES (insn) != 0
+ && (tem = find_reg_note (insn, REG_EQUAL, NULL_RTX)) != 0
+ && (! rtx_equal_p (XEXP (tem, 0), SET_SRC (sets[0].rtl))
+ || GET_CODE (SET_DEST (sets[0].rtl)) == STRICT_LOW_PART))
+ {
+ src_eqv = fold_rtx (canon_reg (XEXP (tem, 0), NULL_RTX), insn);
+ XEXP (tem, 0) = src_eqv;
+ }
+
+ /* Canonicalize sources and addresses of destinations.
+ We do this in a separate pass to avoid problems when a MATCH_DUP is
+ present in the insn pattern. In that case, we want to ensure that
+ we don't break the duplicate nature of the pattern. So we will replace
+ both operands at the same time. Otherwise, we would fail to find an
+ equivalent substitution in the loop calling validate_change below.
+
+ We used to suppress canonicalization of DEST if it appears in SRC,
+ but we don't do this any more. */
+
+ for (i = 0; i < n_sets; i++)
+ {
+ rtx dest = SET_DEST (sets[i].rtl);
+ rtx src = SET_SRC (sets[i].rtl);
+ rtx new = canon_reg (src, insn);
+
+ sets[i].orig_src = src;
+ validate_change (insn, &SET_SRC (sets[i].rtl), new, 1);
+
+ if (GET_CODE (dest) == ZERO_EXTRACT)
+ {
+ validate_change (insn, &XEXP (dest, 1),
+ canon_reg (XEXP (dest, 1), insn), 1);
+ validate_change (insn, &XEXP (dest, 2),
+ canon_reg (XEXP (dest, 2), insn), 1);
+ }
+
+ while (GET_CODE (dest) == SUBREG
+ || GET_CODE (dest) == ZERO_EXTRACT
+ || GET_CODE (dest) == STRICT_LOW_PART)
+ dest = XEXP (dest, 0);
+
+ if (MEM_P (dest))
+ canon_reg (dest, insn);
+ }
+
+ /* Now that we have done all the replacements, we can apply the change
+ group and see if they all work. Note that this will cause some
+ canonicalizations that would have worked individually not to be applied
+ because some other canonicalization didn't work, but this should not
+ occur often.
+
+ The result of apply_change_group can be ignored; see canon_reg. */
+
+ apply_change_group ();
+
+ /* Set sets[i].src_elt to the class each source belongs to.
+ Detect assignments from or to volatile things
+ and set set[i] to zero so they will be ignored
+ in the rest of this function.
+
+ Nothing in this loop changes the hash table or the register chains. */
+
+ for (i = 0; i < n_sets; i++)
+ {
+ rtx src, dest;
+ rtx src_folded;
+ struct table_elt *elt = 0, *p;
+ enum machine_mode mode;
+ rtx src_eqv_here;
+ rtx src_const = 0;
+ rtx src_related = 0;
+ /* APPLE LOCAL begin cse of ZERO/SIGN EXTEND */
+ rtx zero_sign_extended_src = NULL_RTX;
+ /* APPLE LOCAL end cse of ZERO/SIGN EXTEND */
+ struct table_elt *src_const_elt = 0;
+ int src_cost = MAX_COST;
+ int src_eqv_cost = MAX_COST;
+ int src_folded_cost = MAX_COST;
+ int src_related_cost = MAX_COST;
+ int src_elt_cost = MAX_COST;
+ int src_regcost = MAX_COST;
+ int src_eqv_regcost = MAX_COST;
+ int src_folded_regcost = MAX_COST;
+ int src_related_regcost = MAX_COST;
+ int src_elt_regcost = MAX_COST;
+ /* Set nonzero if we need to call force_const_mem on with the
+ contents of src_folded before using it. */
+ int src_folded_force_flag = 0;
+
+ dest = SET_DEST (sets[i].rtl);
+ src = SET_SRC (sets[i].rtl);
+
+ /* If SRC is a constant that has no machine mode,
+ hash it with the destination's machine mode.
+ This way we can keep different modes separate. */
+
+ mode = GET_MODE (src) == VOIDmode ? GET_MODE (dest) : GET_MODE (src);
+ sets[i].mode = mode;
+
+ if (src_eqv)
+ {
+ enum machine_mode eqvmode = mode;
+ if (GET_CODE (dest) == STRICT_LOW_PART)
+ eqvmode = GET_MODE (SUBREG_REG (XEXP (dest, 0)));
+ do_not_record = 0;
+ hash_arg_in_memory = 0;
+ src_eqv_hash = HASH (src_eqv, eqvmode);
+
+ /* Find the equivalence class for the equivalent expression. */
+
+ if (!do_not_record)
+ src_eqv_elt = lookup (src_eqv, src_eqv_hash, eqvmode);
+
+ src_eqv_volatile = do_not_record;
+ src_eqv_in_memory = hash_arg_in_memory;
+ }
+
+ /* If this is a STRICT_LOW_PART assignment, src_eqv corresponds to the
+ value of the INNER register, not the destination. So it is not
+ a valid substitution for the source. But save it for later. */
+ if (GET_CODE (dest) == STRICT_LOW_PART)
+ src_eqv_here = 0;
+ else
+ src_eqv_here = src_eqv;
+
+ /* Simplify and foldable subexpressions in SRC. Then get the fully-
+ simplified result, which may not necessarily be valid. */
+ src_folded = fold_rtx (src, insn);
+
+#if 0
+ /* ??? This caused bad code to be generated for the m68k port with -O2.
+ Suppose src is (CONST_INT -1), and that after truncation src_folded
+ is (CONST_INT 3). Suppose src_folded is then used for src_const.
+ At the end we will add src and src_const to the same equivalence
+ class. We now have 3 and -1 on the same equivalence class. This
+ causes later instructions to be mis-optimized. */
+ /* If storing a constant in a bitfield, pre-truncate the constant
+ so we will be able to record it later. */
+ if (GET_CODE (SET_DEST (sets[i].rtl)) == ZERO_EXTRACT)
+ {
+ rtx width = XEXP (SET_DEST (sets[i].rtl), 1);
+
+ if (GET_CODE (src) == CONST_INT
+ && GET_CODE (width) == CONST_INT
+ && INTVAL (width) < HOST_BITS_PER_WIDE_INT
+ && (INTVAL (src) & ((HOST_WIDE_INT) (-1) << INTVAL (width))))
+ src_folded
+ = GEN_INT (INTVAL (src) & (((HOST_WIDE_INT) 1
+ << INTVAL (width)) - 1));
+ }
+#endif
+
+ /* Compute SRC's hash code, and also notice if it
+ should not be recorded at all. In that case,
+ prevent any further processing of this assignment. */
+ do_not_record = 0;
+ hash_arg_in_memory = 0;
+
+ sets[i].src = src;
+ sets[i].src_hash = HASH (src, mode);
+ sets[i].src_volatile = do_not_record;
+ sets[i].src_in_memory = hash_arg_in_memory;
+
+ /* If SRC is a MEM, there is a REG_EQUIV note for SRC, and DEST is
+ a pseudo, do not record SRC. Using SRC as a replacement for
+ anything else will be incorrect in that situation. Note that
+ this usually occurs only for stack slots, in which case all the
+ RTL would be referring to SRC, so we don't lose any optimization
+ opportunities by not having SRC in the hash table. */
+
+ if (MEM_P (src)
+ && find_reg_note (insn, REG_EQUIV, NULL_RTX) != 0
+ && REG_P (dest)
+ && REGNO (dest) >= FIRST_PSEUDO_REGISTER)
+ sets[i].src_volatile = 1;
+
+#if 0
+ /* It is no longer clear why we used to do this, but it doesn't
+ appear to still be needed. So let's try without it since this
+ code hurts cse'ing widened ops. */
+ /* If source is a paradoxical subreg (such as QI treated as an SI),
+ treat it as volatile. It may do the work of an SI in one context
+ where the extra bits are not being used, but cannot replace an SI
+ in general. */
+ if (GET_CODE (src) == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (src))
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))))
+ sets[i].src_volatile = 1;
+#endif
+
+ /* Locate all possible equivalent forms for SRC. Try to replace
+ SRC in the insn with each cheaper equivalent.
+
+ We have the following types of equivalents: SRC itself, a folded
+ version, a value given in a REG_EQUAL note, or a value related
+ to a constant.
+
+ Each of these equivalents may be part of an additional class
+ of equivalents (if more than one is in the table, they must be in
+ the same class; we check for this).
+
+ If the source is volatile, we don't do any table lookups.
+
+ We note any constant equivalent for possible later use in a
+ REG_NOTE. */
+
+ if (!sets[i].src_volatile)
+ /* APPLE LOCAL begin cse of ZERO/SIGN EXTEND */
+ {
+ elt = lookup (src, sets[i].src_hash, mode);
+ if (!elt
+ && (GET_CODE(src) == ZERO_EXTEND || GET_CODE(src) == SIGN_EXTEND)
+ && GET_CODE (XEXP (src, 0)) == MEM)
+ {
+ unsigned mem_hash;
+ rtx nsrc = XEXP (src, 0);
+ enum machine_mode nmode = GET_MODE(nsrc);
+ do_not_record = 0;
+ hash_arg_in_memory = 0;
+ mem_hash = HASH (nsrc, nmode);
+ elt = lookup (nsrc, mem_hash, nmode);
+ if (elt)
+ {
+ sets[i].src = nsrc;
+ sets[i].src_hash = mem_hash;
+ sets[i].src_volatile = do_not_record;
+ sets[i].src_in_memory = hash_arg_in_memory;
+ zero_sign_extended_src = src;
+ src = nsrc;
+ mode = GET_MODE (src) == VOIDmode ? GET_MODE (dest) : GET_MODE (src);
+ sets[i].mode = mode;
+ src_folded = fold_rtx (src, insn);
+ }
+ }
+ }
+ /* APPLE LOCAL end cse of ZERO/SIGN EXTEND */
+
+ sets[i].src_elt = elt;
+
+ if (elt && src_eqv_here && src_eqv_elt)
+ {
+ if (elt->first_same_value != src_eqv_elt->first_same_value)
+ {
+ /* The REG_EQUAL is indicating that two formerly distinct
+ classes are now equivalent. So merge them. */
+ merge_equiv_classes (elt, src_eqv_elt);
+ src_eqv_hash = HASH (src_eqv, elt->mode);
+ src_eqv_elt = lookup (src_eqv, src_eqv_hash, elt->mode);
+ }
+
+ src_eqv_here = 0;
+ }
+
+ else if (src_eqv_elt)
+ elt = src_eqv_elt;
+
+ /* Try to find a constant somewhere and record it in `src_const'.
+ Record its table element, if any, in `src_const_elt'. Look in
+ any known equivalences first. (If the constant is not in the
+ table, also set `sets[i].src_const_hash'). */
+ if (elt)
+ for (p = elt->first_same_value; p; p = p->next_same_value)
+ if (p->is_const)
+ {
+ /* APPLE LOCAL begin cse of ZERO/SIGN EXTEND */
+ /* If we're looking at a MEM under a SIGN/ZERO_EXTEND,
+ constants match only if the high bits match. */
+ if (zero_sign_extended_src)
+ {
+ rtx truncated_const, trial;
+ truncated_const = gen_rtx_TRUNCATE (
+ GET_MODE (XEXP (zero_sign_extended_src, 0)),
+ copy_rtx (p->exp));
+ if (GET_CODE (zero_sign_extended_src) == ZERO_EXTEND)
+ trial = gen_rtx_ZERO_EXTEND (
+ GET_MODE (zero_sign_extended_src), truncated_const);
+ else
+ trial = gen_rtx_SIGN_EXTEND (
+ GET_MODE (zero_sign_extended_src), truncated_const);
+ trial = fold_rtx (trial, NULL_RTX);
+ if (!rtx_equal_p (trial, p->exp))
+ continue;
+ }
+ /* APPLE LOCAL end cse of ZERO/SIGN EXTEND */
+ src_const = p->exp;
+ src_const_elt = elt;
+ break;
+ }
+
+ if (src_const == 0
+ && (CONSTANT_P (src_folded)
+ /* Consider (minus (label_ref L1) (label_ref L2)) as
+ "constant" here so we will record it. This allows us
+ to fold switch statements when an ADDR_DIFF_VEC is used. */
+ || (GET_CODE (src_folded) == MINUS
+ && GET_CODE (XEXP (src_folded, 0)) == LABEL_REF
+ && GET_CODE (XEXP (src_folded, 1)) == LABEL_REF)))
+ src_const = src_folded, src_const_elt = elt;
+ else if (src_const == 0 && src_eqv_here && CONSTANT_P (src_eqv_here))
+ src_const = src_eqv_here, src_const_elt = src_eqv_elt;
+
+ /* If we don't know if the constant is in the table, get its
+ hash code and look it up. */
+ if (src_const && src_const_elt == 0)
+ {
+ sets[i].src_const_hash = HASH (src_const, mode);
+ src_const_elt = lookup (src_const, sets[i].src_const_hash, mode);
+ }
+
+ sets[i].src_const = src_const;
+ sets[i].src_const_elt = src_const_elt;
+
+ /* If the constant and our source are both in the table, mark them as
+ equivalent. Otherwise, if a constant is in the table but the source
+ isn't, set ELT to it. */
+ if (src_const_elt && elt
+ && src_const_elt->first_same_value != elt->first_same_value)
+ merge_equiv_classes (elt, src_const_elt);
+ else if (src_const_elt && elt == 0)
+ elt = src_const_elt;
+
+ /* See if there is a register linearly related to a constant
+ equivalent of SRC. */
+ if (src_const
+ && (GET_CODE (src_const) == CONST
+ || (src_const_elt && src_const_elt->related_value != 0)))
+ {
+ src_related = use_related_value (src_const, src_const_elt);
+ if (src_related)
+ {
+ struct table_elt *src_related_elt
+ = lookup (src_related, HASH (src_related, mode), mode);
+ if (src_related_elt && elt)
+ {
+ if (elt->first_same_value
+ != src_related_elt->first_same_value)
+ /* This can occur when we previously saw a CONST
+ involving a SYMBOL_REF and then see the SYMBOL_REF
+ twice. Merge the involved classes. */
+ merge_equiv_classes (elt, src_related_elt);
+
+ src_related = 0;
+ src_related_elt = 0;
+ }
+ else if (src_related_elt && elt == 0)
+ elt = src_related_elt;
+ }
+ }
+
+ /* See if we have a CONST_INT that is already in a register in a
+ wider mode. */
+
+ if (src_const && src_related == 0 && GET_CODE (src_const) == CONST_INT
+ && GET_MODE_CLASS (mode) == MODE_INT
+ && GET_MODE_BITSIZE (mode) < BITS_PER_WORD)
+ {
+ enum machine_mode wider_mode;
+
+ for (wider_mode = GET_MODE_WIDER_MODE (mode);
+ GET_MODE_BITSIZE (wider_mode) <= BITS_PER_WORD
+ && src_related == 0;
+ wider_mode = GET_MODE_WIDER_MODE (wider_mode))
+ {
+ struct table_elt *const_elt
+ = lookup (src_const, HASH (src_const, wider_mode), wider_mode);
+
+ if (const_elt == 0)
+ continue;
+
+ for (const_elt = const_elt->first_same_value;
+ const_elt; const_elt = const_elt->next_same_value)
+ if (REG_P (const_elt->exp))
+ {
+ src_related = gen_lowpart (mode,
+ const_elt->exp);
+ break;
+ }
+ }
+ }
+
+ /* Another possibility is that we have an AND with a constant in
+ a mode narrower than a word. If so, it might have been generated
+ as part of an "if" which would narrow the AND. If we already
+ have done the AND in a wider mode, we can use a SUBREG of that
+ value. */
+
+ if (flag_expensive_optimizations && ! src_related
+ && GET_CODE (src) == AND && GET_CODE (XEXP (src, 1)) == CONST_INT
+ && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
+ {
+ enum machine_mode tmode;
+ rtx new_and = gen_rtx_AND (VOIDmode, NULL_RTX, XEXP (src, 1));
+
+ for (tmode = GET_MODE_WIDER_MODE (mode);
+ GET_MODE_SIZE (tmode) <= UNITS_PER_WORD;
+ tmode = GET_MODE_WIDER_MODE (tmode))
+ {
+ rtx inner = gen_lowpart (tmode, XEXP (src, 0));
+ struct table_elt *larger_elt;
+
+ if (inner)
+ {
+ PUT_MODE (new_and, tmode);
+ XEXP (new_and, 0) = inner;
+ larger_elt = lookup (new_and, HASH (new_and, tmode), tmode);
+ if (larger_elt == 0)
+ continue;
+
+ for (larger_elt = larger_elt->first_same_value;
+ larger_elt; larger_elt = larger_elt->next_same_value)
+ if (REG_P (larger_elt->exp))
+ {
+ src_related
+ = gen_lowpart (mode, larger_elt->exp);
+ break;
+ }
+
+ if (src_related)
+ break;
+ }
+ }
+ }
+
+#ifdef LOAD_EXTEND_OP
+ /* See if a MEM has already been loaded with a widening operation;
+ if it has, we can use a subreg of that. Many CISC machines
+ also have such operations, but this is only likely to be
+ beneficial on these machines. */
+
+ if (flag_expensive_optimizations && src_related == 0
+ && (GET_MODE_SIZE (mode) < UNITS_PER_WORD)
+ && GET_MODE_CLASS (mode) == MODE_INT
+ && MEM_P (src) && ! do_not_record
+ && LOAD_EXTEND_OP (mode) != UNKNOWN)
+ {
+ struct rtx_def memory_extend_buf;
+ rtx memory_extend_rtx = &memory_extend_buf;
+ enum machine_mode tmode;
+
+ /* Set what we are trying to extend and the operation it might
+ have been extended with. */
+ memset (memory_extend_rtx, 0, sizeof(*memory_extend_rtx));
+ PUT_CODE (memory_extend_rtx, LOAD_EXTEND_OP (mode));
+ XEXP (memory_extend_rtx, 0) = src;
+
+ for (tmode = GET_MODE_WIDER_MODE (mode);
+ GET_MODE_SIZE (tmode) <= UNITS_PER_WORD;
+ tmode = GET_MODE_WIDER_MODE (tmode))
+ {
+ struct table_elt *larger_elt;
+
+ PUT_MODE (memory_extend_rtx, tmode);
+ larger_elt = lookup (memory_extend_rtx,
+ HASH (memory_extend_rtx, tmode), tmode);
+ if (larger_elt == 0)
+ continue;
+
+ for (larger_elt = larger_elt->first_same_value;
+ larger_elt; larger_elt = larger_elt->next_same_value)
+ if (REG_P (larger_elt->exp))
+ {
+ src_related = gen_lowpart (mode,
+ larger_elt->exp);
+ break;
+ }
+
+ if (src_related)
+ break;
+ }
+ }
+#endif /* LOAD_EXTEND_OP */
+
+ if (src == src_folded)
+ src_folded = 0;
+
+ /* At this point, ELT, if nonzero, points to a class of expressions
+ equivalent to the source of this SET and SRC, SRC_EQV, SRC_FOLDED,
+ and SRC_RELATED, if nonzero, each contain additional equivalent
+ expressions. Prune these latter expressions by deleting expressions
+ already in the equivalence class.
+
+ Check for an equivalent identical to the destination. If found,
+ this is the preferred equivalent since it will likely lead to
+ elimination of the insn. Indicate this by placing it in
+ `src_related'. */
+
+ if (elt)
+ elt = elt->first_same_value;
+ for (p = elt; p; p = p->next_same_value)
+ {
+ enum rtx_code code = GET_CODE (p->exp);
+
+ /* If the expression is not valid, ignore it. Then we do not
+ have to check for validity below. In most cases, we can use
+ `rtx_equal_p', since canonicalization has already been done. */
+ if (code != REG && ! exp_equiv_p (p->exp, p->exp, 1, false))
+ continue;
+
+ /* Also skip paradoxical subregs, unless that's what we're
+ looking for. */
+ if (code == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (p->exp))
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (p->exp))))
+ && ! (src != 0
+ && GET_CODE (src) == SUBREG
+ && GET_MODE (src) == GET_MODE (p->exp)
+ && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))
+ < GET_MODE_SIZE (GET_MODE (SUBREG_REG (p->exp))))))
+ continue;
+
+ if (src && GET_CODE (src) == code && rtx_equal_p (src, p->exp))
+ src = 0;
+ else if (src_folded && GET_CODE (src_folded) == code
+ && rtx_equal_p (src_folded, p->exp))
+ src_folded = 0;
+ else if (src_eqv_here && GET_CODE (src_eqv_here) == code
+ && rtx_equal_p (src_eqv_here, p->exp))
+ src_eqv_here = 0;
+ else if (src_related && GET_CODE (src_related) == code
+ && rtx_equal_p (src_related, p->exp))
+ src_related = 0;
+
+ /* This is the same as the destination of the insns, we want
+ to prefer it. Copy it to src_related. The code below will
+ then give it a negative cost. */
+ if (GET_CODE (dest) == code && rtx_equal_p (p->exp, dest))
+ src_related = dest;
+ }
+
+ /* Find the cheapest valid equivalent, trying all the available
+ possibilities. Prefer items not in the hash table to ones
+ that are when they are equal cost. Note that we can never
+ worsen an insn as the current contents will also succeed.
+ If we find an equivalent identical to the destination, use it as best,
+ since this insn will probably be eliminated in that case. */
+ if (src)
+ {
+ if (rtx_equal_p (src, dest))
+ src_cost = src_regcost = -1;
+ else
+ {
+ src_cost = COST (src);
+ src_regcost = approx_reg_cost (src);
+ }
+ }
+
+ if (src_eqv_here)
+ {
+ if (rtx_equal_p (src_eqv_here, dest))
+ src_eqv_cost = src_eqv_regcost = -1;
+ else
+ {
+ src_eqv_cost = COST (src_eqv_here);
+ src_eqv_regcost = approx_reg_cost (src_eqv_here);
+ }
+ }
+
+ if (src_folded)
+ {
+ if (rtx_equal_p (src_folded, dest))
+ src_folded_cost = src_folded_regcost = -1;
+ else
+ {
+ src_folded_cost = COST (src_folded);
+ src_folded_regcost = approx_reg_cost (src_folded);
+ }
+ }
+
+ if (src_related)
+ {
+ if (rtx_equal_p (src_related, dest))
+ src_related_cost = src_related_regcost = -1;
+ else
+ {
+ src_related_cost = COST (src_related);
+ src_related_regcost = approx_reg_cost (src_related);
+ }
+ }
+
+ /* If this was an indirect jump insn, a known label will really be
+ cheaper even though it looks more expensive. */
+ if (dest == pc_rtx && src_const && GET_CODE (src_const) == LABEL_REF)
+ src_folded = src_const, src_folded_cost = src_folded_regcost = -1;
+
+ /* Terminate loop when replacement made. This must terminate since
+ the current contents will be tested and will always be valid. */
+ while (1)
+ {
+ rtx trial;
+
+ /* Skip invalid entries. */
+ while (elt && !REG_P (elt->exp)
+ && ! exp_equiv_p (elt->exp, elt->exp, 1, false))
+ elt = elt->next_same_value;
+
+ /* A paradoxical subreg would be bad here: it'll be the right
+ size, but later may be adjusted so that the upper bits aren't
+ what we want. So reject it. */
+ if (elt != 0
+ && GET_CODE (elt->exp) == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (elt->exp))
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (elt->exp))))
+ /* It is okay, though, if the rtx we're trying to match
+ will ignore any of the bits we can't predict. */
+ && ! (src != 0
+ && GET_CODE (src) == SUBREG
+ && GET_MODE (src) == GET_MODE (elt->exp)
+ && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))
+ < GET_MODE_SIZE (GET_MODE (SUBREG_REG (elt->exp))))))
+ {
+ elt = elt->next_same_value;
+ continue;
+ }
+
+ if (elt)
+ {
+ src_elt_cost = elt->cost;
+ src_elt_regcost = elt->regcost;
+ }
+
+ /* Find cheapest and skip it for the next time. For items
+ of equal cost, use this order:
+ src_folded, src, src_eqv, src_related and hash table entry. */
+ if (src_folded
+ && preferable (src_folded_cost, src_folded_regcost,
+ src_cost, src_regcost) <= 0
+ && preferable (src_folded_cost, src_folded_regcost,
+ src_eqv_cost, src_eqv_regcost) <= 0
+ && preferable (src_folded_cost, src_folded_regcost,
+ src_related_cost, src_related_regcost) <= 0
+ && preferable (src_folded_cost, src_folded_regcost,
+ src_elt_cost, src_elt_regcost) <= 0)
+ {
+ trial = src_folded, src_folded_cost = MAX_COST;
+ if (src_folded_force_flag)
+ {
+ rtx forced = force_const_mem (mode, trial);
+ if (forced)
+ trial = forced;
+ }
+ }
+ else if (src
+ && preferable (src_cost, src_regcost,
+ src_eqv_cost, src_eqv_regcost) <= 0
+ && preferable (src_cost, src_regcost,
+ src_related_cost, src_related_regcost) <= 0
+ && preferable (src_cost, src_regcost,
+ src_elt_cost, src_elt_regcost) <= 0)
+ trial = src, src_cost = MAX_COST;
+ else if (src_eqv_here
+ && preferable (src_eqv_cost, src_eqv_regcost,
+ src_related_cost, src_related_regcost) <= 0
+ && preferable (src_eqv_cost, src_eqv_regcost,
+ src_elt_cost, src_elt_regcost) <= 0)
+ trial = copy_rtx (src_eqv_here), src_eqv_cost = MAX_COST;
+ else if (src_related
+ && preferable (src_related_cost, src_related_regcost,
+ src_elt_cost, src_elt_regcost) <= 0)
+ trial = copy_rtx (src_related), src_related_cost = MAX_COST;
+ /* APPLE LOCAL begin cse of ZERO/SIGN EXTEND */
+ else if (zero_sign_extended_src)
+ {
+ rtx truncated_const;
+ if (elt->is_const)
+ truncated_const = gen_rtx_TRUNCATE (
+ GET_MODE (XEXP (zero_sign_extended_src, 0)),
+ copy_rtx (elt->exp));
+ else
+ truncated_const= copy_rtx (elt->exp);
+ trial = GET_CODE(zero_sign_extended_src) == ZERO_EXTEND
+ ? gen_rtx_ZERO_EXTEND (GET_MODE(zero_sign_extended_src),
+ truncated_const)
+ : gen_rtx_SIGN_EXTEND (GET_MODE(zero_sign_extended_src),
+ truncated_const);
+ trial = fold_rtx (trial, NULL_RTX);
+ elt = elt->next_same_value;
+ src_elt_cost = MAX_COST;
+ }
+ /* APPLE LOCAL end cse of ZERO/SIGN EXTEND */
+ else
+ {
+ trial = copy_rtx (elt->exp);
+ elt = elt->next_same_value;
+ src_elt_cost = MAX_COST;
+ }
+
+ /* We don't normally have an insn matching (set (pc) (pc)), so
+ check for this separately here. We will delete such an
+ insn below.
+
+ For other cases such as a table jump or conditional jump
+ where we know the ultimate target, go ahead and replace the
+ operand. While that may not make a valid insn, we will
+ reemit the jump below (and also insert any necessary
+ barriers). */
+ if (n_sets == 1 && dest == pc_rtx
+ && (trial == pc_rtx
+ || (GET_CODE (trial) == LABEL_REF
+ && ! condjump_p (insn))))
+ {
+ /* Don't substitute non-local labels, this confuses CFG. */
+ if (GET_CODE (trial) == LABEL_REF
+ && LABEL_REF_NONLOCAL_P (trial))
+ continue;
+
+ SET_SRC (sets[i].rtl) = trial;
+ cse_jumps_altered = 1;
+ break;
+ }
+
+ /* Reject certain invalid forms of CONST that we create. */
+ else if (CONSTANT_P (trial)
+ && GET_CODE (trial) == CONST
+ /* Reject cases that will cause decode_rtx_const to
+ die. On the alpha when simplifying a switch, we
+ get (const (truncate (minus (label_ref)
+ (label_ref)))). */
+ && (GET_CODE (XEXP (trial, 0)) == TRUNCATE
+ /* Likewise on IA-64, except without the
+ truncate. */
+ || (GET_CODE (XEXP (trial, 0)) == MINUS
+ && GET_CODE (XEXP (XEXP (trial, 0), 0)) == LABEL_REF
+ && GET_CODE (XEXP (XEXP (trial, 0), 1)) == LABEL_REF)))
+ /* Do nothing for this case. */
+ ;
+
+ /* Look for a substitution that makes a valid insn. */
+ else if (validate_change (insn, &SET_SRC (sets[i].rtl), trial, 0))
+ {
+ rtx new = canon_reg (SET_SRC (sets[i].rtl), insn);
+
+ /* If we just made a substitution inside a libcall, then we
+ need to make the same substitution in any notes attached
+ to the RETVAL insn. */
+ if (libcall_insn
+ && (REG_P (sets[i].orig_src)
+ || GET_CODE (sets[i].orig_src) == SUBREG
+ || MEM_P (sets[i].orig_src)))
+ {
+ rtx note = find_reg_equal_equiv_note (libcall_insn);
+ if (note != 0)
+ XEXP (note, 0) = simplify_replace_rtx (XEXP (note, 0),
+ sets[i].orig_src,
+ copy_rtx (new));
+ }
+
+ /* The result of apply_change_group can be ignored; see
+ canon_reg. */
+
+ validate_change (insn, &SET_SRC (sets[i].rtl), new, 1);
+ apply_change_group ();
+ break;
+ }
+
+ /* If we previously found constant pool entries for
+ constants and this is a constant, try making a
+ pool entry. Put it in src_folded unless we already have done
+ this since that is where it likely came from. */
+
+ else if (constant_pool_entries_cost
+ && CONSTANT_P (trial)
+ && (src_folded == 0
+ || (!MEM_P (src_folded)
+ && ! src_folded_force_flag))
+ && GET_MODE_CLASS (mode) != MODE_CC
+ && mode != VOIDmode)
+ {
+ src_folded_force_flag = 1;
+ src_folded = trial;
+ src_folded_cost = constant_pool_entries_cost;
+ src_folded_regcost = constant_pool_entries_regcost;
+ }
+ }
+
+ src = SET_SRC (sets[i].rtl);
+ /* APPLE LOCAL begin cse of ZERO/SIGN EXTEND */
+ if (zero_sign_extended_src
+ && (GET_CODE (src) == GET_CODE (zero_sign_extended_src)))
+ src = XEXP (src, 0);
+ /* APPLE LOCAL end cse of ZERO/SIGN EXTEND */
+
+ /* In general, it is good to have a SET with SET_SRC == SET_DEST.
+ However, there is an important exception: If both are registers
+ that are not the head of their equivalence class, replace SET_SRC
+ with the head of the class. If we do not do this, we will have
+ both registers live over a portion of the basic block. This way,
+ their lifetimes will likely abut instead of overlapping. */
+ if (REG_P (dest)
+ && REGNO_QTY_VALID_P (REGNO (dest)))
+ {
+ int dest_q = REG_QTY (REGNO (dest));
+ struct qty_table_elem *dest_ent = &qty_table[dest_q];
+
+ if (dest_ent->mode == GET_MODE (dest)
+ && dest_ent->first_reg != REGNO (dest)
+ && REG_P (src) && REGNO (src) == REGNO (dest)
+ /* Don't do this if the original insn had a hard reg as
+ SET_SRC or SET_DEST. */
+ && (!REG_P (sets[i].src)
+ || REGNO (sets[i].src) >= FIRST_PSEUDO_REGISTER)
+ && (!REG_P (dest) || REGNO (dest) >= FIRST_PSEUDO_REGISTER))
+ /* We can't call canon_reg here because it won't do anything if
+ SRC is a hard register. */
+ {
+ int src_q = REG_QTY (REGNO (src));
+ struct qty_table_elem *src_ent = &qty_table[src_q];
+ int first = src_ent->first_reg;
+ rtx new_src
+ = (first >= FIRST_PSEUDO_REGISTER
+ ? regno_reg_rtx[first] : gen_rtx_REG (GET_MODE (src), first));
+
+ /* We must use validate-change even for this, because this
+ might be a special no-op instruction, suitable only to
+ tag notes onto. */
+ if (validate_change (insn, &SET_SRC (sets[i].rtl), new_src, 0))
+ {
+ src = new_src;
+ /* If we had a constant that is cheaper than what we are now
+ setting SRC to, use that constant. We ignored it when we
+ thought we could make this into a no-op. */
+ if (src_const && COST (src_const) < COST (src)
+ && validate_change (insn, &SET_SRC (sets[i].rtl),
+ src_const, 0))
+ src = src_const;
+ }
+ }
+ }
+
+ /* If we made a change, recompute SRC values. */
+ if (src != sets[i].src)
+ {
+ cse_altered = 1;
+ do_not_record = 0;
+ hash_arg_in_memory = 0;
+ sets[i].src = src;
+ sets[i].src_hash = HASH (src, mode);
+ sets[i].src_volatile = do_not_record;
+ sets[i].src_in_memory = hash_arg_in_memory;
+ sets[i].src_elt = lookup (src, sets[i].src_hash, mode);
+ }
+
+ /* If this is a single SET, we are setting a register, and we have an
+ equivalent constant, we want to add a REG_NOTE. We don't want
+ to write a REG_EQUAL note for a constant pseudo since verifying that
+ that pseudo hasn't been eliminated is a pain. Such a note also
+ won't help anything.
+
+ Avoid a REG_EQUAL note for (CONST (MINUS (LABEL_REF) (LABEL_REF)))
+ which can be created for a reference to a compile time computable
+ entry in a jump table. */
+
+ if (n_sets == 1 && src_const && REG_P (dest)
+ && !REG_P (src_const)
+ && ! (GET_CODE (src_const) == CONST
+ && GET_CODE (XEXP (src_const, 0)) == MINUS
+ && GET_CODE (XEXP (XEXP (src_const, 0), 0)) == LABEL_REF
+ /* APPLE LOCAL begin cse of ZERO/SIGN EXTEND */
+ && (GET_CODE (XEXP (XEXP (src_const, 0), 1)) == LABEL_REF
+ || rtx_equal_p ((XEXP (XEXP (src_const, 0), 1)),
+ const0_rtx))))
+ /* APPLE LOCAL end */
+ {
+ /* We only want a REG_EQUAL note if src_const != src. */
+ if (! rtx_equal_p (src, src_const))
+ {
+ /* Make sure that the rtx is not shared. */
+ src_const = copy_rtx (src_const);
+
+ /* Record the actual constant value in a REG_EQUAL note,
+ making a new one if one does not already exist. */
+ set_unique_reg_note (insn, REG_EQUAL, src_const);
+ }
+ }
+
+ /* Now deal with the destination. */
+ do_not_record = 0;
+
+ /* Look within any ZERO_EXTRACT to the MEM or REG within it. */
+ while (GET_CODE (dest) == SUBREG
+ || GET_CODE (dest) == ZERO_EXTRACT
+ || GET_CODE (dest) == STRICT_LOW_PART)
+ dest = XEXP (dest, 0);
+
+ sets[i].inner_dest = dest;
+
+ if (MEM_P (dest))
+ {
+#ifdef PUSH_ROUNDING
+ /* Stack pushes invalidate the stack pointer. */
+ rtx addr = XEXP (dest, 0);
+ if (GET_RTX_CLASS (GET_CODE (addr)) == RTX_AUTOINC
+ && XEXP (addr, 0) == stack_pointer_rtx)
+ invalidate (stack_pointer_rtx, VOIDmode);
+#endif
+ dest = fold_rtx (dest, insn);
+ }
+
+ /* Compute the hash code of the destination now,
+ before the effects of this instruction are recorded,
+ since the register values used in the address computation
+ are those before this instruction. */
+ sets[i].dest_hash = HASH (dest, mode);
+
+ /* Don't enter a bit-field in the hash table
+ because the value in it after the store
+ may not equal what was stored, due to truncation. */
+
+ if (GET_CODE (SET_DEST (sets[i].rtl)) == ZERO_EXTRACT)
+ {
+ rtx width = XEXP (SET_DEST (sets[i].rtl), 1);
+
+ if (src_const != 0 && GET_CODE (src_const) == CONST_INT
+ && GET_CODE (width) == CONST_INT
+ && INTVAL (width) < HOST_BITS_PER_WIDE_INT
+ && ! (INTVAL (src_const)
+ & ((HOST_WIDE_INT) (-1) << INTVAL (width))))
+ /* Exception: if the value is constant,
+ and it won't be truncated, record it. */
+ ;
+ else
+ {
+ /* This is chosen so that the destination will be invalidated
+ but no new value will be recorded.
+ We must invalidate because sometimes constant
+ values can be recorded for bitfields. */
+ sets[i].src_elt = 0;
+ sets[i].src_volatile = 1;
+ src_eqv = 0;
+ src_eqv_elt = 0;
+ }
+ }
+
+ /* If only one set in a JUMP_INSN and it is now a no-op, we can delete
+ the insn. */
+ else if (n_sets == 1 && dest == pc_rtx && src == pc_rtx)
+ {
+ /* One less use of the label this insn used to jump to. */
+ delete_insn (insn);
+ cse_jumps_altered = 1;
+ /* No more processing for this set. */
+ sets[i].rtl = 0;
+ }
+
+ /* If this SET is now setting PC to a label, we know it used to
+ be a conditional or computed branch. */
+ else if (dest == pc_rtx && GET_CODE (src) == LABEL_REF
+ && !LABEL_REF_NONLOCAL_P (src))
+ {
+ /* Now emit a BARRIER after the unconditional jump. */
+ if (NEXT_INSN (insn) == 0
+ || !BARRIER_P (NEXT_INSN (insn)))
+ emit_barrier_after (insn);
+
+ /* We reemit the jump in as many cases as possible just in
+ case the form of an unconditional jump is significantly
+ different than a computed jump or conditional jump.
+
+ If this insn has multiple sets, then reemitting the
+ jump is nontrivial. So instead we just force rerecognition
+ and hope for the best. */
+ if (n_sets == 1)
+ {
+ rtx new, note;
+
+ new = emit_jump_insn_after (gen_jump (XEXP (src, 0)), insn);
+ JUMP_LABEL (new) = XEXP (src, 0);
+ LABEL_NUSES (XEXP (src, 0))++;
+
+ /* Make sure to copy over REG_NON_LOCAL_GOTO. */
+ note = find_reg_note (insn, REG_NON_LOCAL_GOTO, 0);
+ if (note)
+ {
+ XEXP (note, 1) = NULL_RTX;
+ REG_NOTES (new) = note;
+ }
+
+ delete_insn (insn);
+ insn = new;
+
+ /* Now emit a BARRIER after the unconditional jump. */
+ if (NEXT_INSN (insn) == 0
+ || !BARRIER_P (NEXT_INSN (insn)))
+ emit_barrier_after (insn);
+ }
+ else
+ INSN_CODE (insn) = -1;
+
+ /* Do not bother deleting any unreachable code,
+ let jump/flow do that. */
+
+ cse_jumps_altered = 1;
+ sets[i].rtl = 0;
+ }
+
+ /* If destination is volatile, invalidate it and then do no further
+ processing for this assignment. */
+
+ else if (do_not_record)
+ {
+ if (REG_P (dest) || GET_CODE (dest) == SUBREG)
+ invalidate (dest, VOIDmode);
+ else if (MEM_P (dest))
+ invalidate (dest, VOIDmode);
+ else if (GET_CODE (dest) == STRICT_LOW_PART
+ || GET_CODE (dest) == ZERO_EXTRACT)
+ invalidate (XEXP (dest, 0), GET_MODE (dest));
+ sets[i].rtl = 0;
+ }
+
+ if (sets[i].rtl != 0 && dest != SET_DEST (sets[i].rtl))
+ sets[i].dest_hash = HASH (SET_DEST (sets[i].rtl), mode);
+
+#ifdef HAVE_cc0
+ /* If setting CC0, record what it was set to, or a constant, if it
+ is equivalent to a constant. If it is being set to a floating-point
+ value, make a COMPARE with the appropriate constant of 0. If we
+ don't do this, later code can interpret this as a test against
+ const0_rtx, which can cause problems if we try to put it into an
+ insn as a floating-point operand. */
+ if (dest == cc0_rtx)
+ {
+ this_insn_cc0 = src_const && mode != VOIDmode ? src_const : src;
+ this_insn_cc0_mode = mode;
+ if (FLOAT_MODE_P (mode))
+ this_insn_cc0 = gen_rtx_COMPARE (VOIDmode, this_insn_cc0,
+ CONST0_RTX (mode));
+ }
+#endif
+ }
+
+ /* Now enter all non-volatile source expressions in the hash table
+ if they are not already present.
+ Record their equivalence classes in src_elt.
+ This way we can insert the corresponding destinations into
+ the same classes even if the actual sources are no longer in them
+ (having been invalidated). */
+
+ if (src_eqv && src_eqv_elt == 0 && sets[0].rtl != 0 && ! src_eqv_volatile
+ && ! rtx_equal_p (src_eqv, SET_DEST (sets[0].rtl)))
+ {
+ struct table_elt *elt;
+ struct table_elt *classp = sets[0].src_elt;
+ rtx dest = SET_DEST (sets[0].rtl);
+ enum machine_mode eqvmode = GET_MODE (dest);
+
+ if (GET_CODE (dest) == STRICT_LOW_PART)
+ {
+ eqvmode = GET_MODE (SUBREG_REG (XEXP (dest, 0)));
+ classp = 0;
+ }
+ if (insert_regs (src_eqv, classp, 0))
+ {
+ rehash_using_reg (src_eqv);
+ src_eqv_hash = HASH (src_eqv, eqvmode);
+ }
+ elt = insert (src_eqv, classp, src_eqv_hash, eqvmode);
+ elt->in_memory = src_eqv_in_memory;
+ src_eqv_elt = elt;
+
+ /* Check to see if src_eqv_elt is the same as a set source which
+ does not yet have an elt, and if so set the elt of the set source
+ to src_eqv_elt. */
+ for (i = 0; i < n_sets; i++)
+ if (sets[i].rtl && sets[i].src_elt == 0
+ && rtx_equal_p (SET_SRC (sets[i].rtl), src_eqv))
+ sets[i].src_elt = src_eqv_elt;
+ }
+
+ for (i = 0; i < n_sets; i++)
+ if (sets[i].rtl && ! sets[i].src_volatile
+ && ! rtx_equal_p (SET_SRC (sets[i].rtl), SET_DEST (sets[i].rtl)))
+ {
+ if (GET_CODE (SET_DEST (sets[i].rtl)) == STRICT_LOW_PART)
+ {
+ /* REG_EQUAL in setting a STRICT_LOW_PART
+ gives an equivalent for the entire destination register,
+ not just for the subreg being stored in now.
+ This is a more interesting equivalence, so we arrange later
+ to treat the entire reg as the destination. */
+ sets[i].src_elt = src_eqv_elt;
+ sets[i].src_hash = src_eqv_hash;
+ }
+ else
+ {
+ /* Insert source and constant equivalent into hash table, if not
+ already present. */
+ struct table_elt *classp = src_eqv_elt;
+ rtx src = sets[i].src;
+ rtx dest = SET_DEST (sets[i].rtl);
+ enum machine_mode mode
+ = GET_MODE (src) == VOIDmode ? GET_MODE (dest) : GET_MODE (src);
+
+ /* It's possible that we have a source value known to be
+ constant but don't have a REG_EQUAL note on the insn.
+ Lack of a note will mean src_eqv_elt will be NULL. This
+ can happen where we've generated a SUBREG to access a
+ CONST_INT that is already in a register in a wider mode.
+ Ensure that the source expression is put in the proper
+ constant class. */
+ if (!classp)
+ classp = sets[i].src_const_elt;
+
+ if (sets[i].src_elt == 0)
+ {
+ /* Don't put a hard register source into the table if this is
+ the last insn of a libcall. In this case, we only need
+ to put src_eqv_elt in src_elt. */
+ if (! find_reg_note (insn, REG_RETVAL, NULL_RTX))
+ {
+ struct table_elt *elt;
+
+ /* Note that these insert_regs calls cannot remove
+ any of the src_elt's, because they would have failed to
+ match if not still valid. */
+ if (insert_regs (src, classp, 0))
+ {
+ rehash_using_reg (src);
+ sets[i].src_hash = HASH (src, mode);
+ }
+ elt = insert (src, classp, sets[i].src_hash, mode);
+ elt->in_memory = sets[i].src_in_memory;
+ sets[i].src_elt = classp = elt;
+ }
+ else
+ sets[i].src_elt = classp;
+ }
+ if (sets[i].src_const && sets[i].src_const_elt == 0
+ && src != sets[i].src_const
+ && ! rtx_equal_p (sets[i].src_const, src))
+ sets[i].src_elt = insert (sets[i].src_const, classp,
+ sets[i].src_const_hash, mode);
+ }
+ }
+ else if (sets[i].src_elt == 0)
+ /* If we did not insert the source into the hash table (e.g., it was
+ volatile), note the equivalence class for the REG_EQUAL value, if any,
+ so that the destination goes into that class. */
+ sets[i].src_elt = src_eqv_elt;
+
+ /* Record destination addresses in the hash table. This allows us to
+ check if they are invalidated by other sets. */
+ for (i = 0; i < n_sets; i++)
+ {
+ if (sets[i].rtl)
+ {
+ rtx x = sets[i].inner_dest;
+ struct table_elt *elt;
+ enum machine_mode mode;
+ unsigned hash;
+
+ if (MEM_P (x))
+ {
+ x = XEXP (x, 0);
+ mode = GET_MODE (x);
+ hash = HASH (x, mode);
+ elt = lookup (x, hash, mode);
+ if (!elt)
+ {
+ if (insert_regs (x, NULL, 0))
+ {
+ rtx dest = SET_DEST (sets[i].rtl);
+
+ rehash_using_reg (x);
+ hash = HASH (x, mode);
+ sets[i].dest_hash = HASH (dest, GET_MODE (dest));
+ }
+ elt = insert (x, NULL, hash, mode);
+ }
+
+ sets[i].dest_addr_elt = elt;
+ }
+ else
+ sets[i].dest_addr_elt = NULL;
+ }
+ }
+
+ invalidate_from_clobbers (x);
+
+ /* Some registers are invalidated by subroutine calls. Memory is
+ invalidated by non-constant calls. */
+
+ if (CALL_P (insn))
+ {
+ if (! CONST_OR_PURE_CALL_P (insn))
+ invalidate_memory ();
+ invalidate_for_call ();
+ }
+
+ /* Now invalidate everything set by this instruction.
+ If a SUBREG or other funny destination is being set,
+ sets[i].rtl is still nonzero, so here we invalidate the reg
+ a part of which is being set. */
+
+ for (i = 0; i < n_sets; i++)
+ if (sets[i].rtl)
+ {
+ /* We can't use the inner dest, because the mode associated with
+ a ZERO_EXTRACT is significant. */
+ rtx dest = SET_DEST (sets[i].rtl);
+
+ /* Needed for registers to remove the register from its
+ previous quantity's chain.
+ Needed for memory if this is a nonvarying address, unless
+ we have just done an invalidate_memory that covers even those. */
+ if (REG_P (dest) || GET_CODE (dest) == SUBREG)
+ invalidate (dest, VOIDmode);
+ else if (MEM_P (dest))
+ invalidate (dest, VOIDmode);
+ else if (GET_CODE (dest) == STRICT_LOW_PART
+ || GET_CODE (dest) == ZERO_EXTRACT)
+ invalidate (XEXP (dest, 0), GET_MODE (dest));
+ }
+
+ /* A volatile ASM invalidates everything. */
+ if (NONJUMP_INSN_P (insn)
+ && GET_CODE (PATTERN (insn)) == ASM_OPERANDS
+ && MEM_VOLATILE_P (PATTERN (insn)))
+ flush_hash_table ();
+
+ /* Make sure registers mentioned in destinations
+ are safe for use in an expression to be inserted.
+ This removes from the hash table
+ any invalid entry that refers to one of these registers.
+
+ We don't care about the return value from mention_regs because
+ we are going to hash the SET_DEST values unconditionally. */
+
+ for (i = 0; i < n_sets; i++)
+ {
+ if (sets[i].rtl)
+ {
+ rtx x = SET_DEST (sets[i].rtl);
+
+ if (!REG_P (x))
+ mention_regs (x);
+ else
+ {
+ /* We used to rely on all references to a register becoming
+ inaccessible when a register changes to a new quantity,
+ since that changes the hash code. However, that is not
+ safe, since after HASH_SIZE new quantities we get a
+ hash 'collision' of a register with its own invalid
+ entries. And since SUBREGs have been changed not to
+ change their hash code with the hash code of the register,
+ it wouldn't work any longer at all. So we have to check
+ for any invalid references lying around now.
+ This code is similar to the REG case in mention_regs,
+ but it knows that reg_tick has been incremented, and
+ it leaves reg_in_table as -1 . */
+ unsigned int regno = REGNO (x);
+ unsigned int endregno
+ = regno + (regno >= FIRST_PSEUDO_REGISTER ? 1
+ : hard_regno_nregs[regno][GET_MODE (x)]);
+ unsigned int i;
+
+ for (i = regno; i < endregno; i++)
+ {
+ if (REG_IN_TABLE (i) >= 0)
+ {
+ remove_invalid_refs (i);
+ REG_IN_TABLE (i) = -1;
+ }
+ }
+ }
+ }
+ }
+
+ /* We may have just removed some of the src_elt's from the hash table.
+ So replace each one with the current head of the same class.
+ Also check if destination addresses have been removed. */
+
+ for (i = 0; i < n_sets; i++)
+ if (sets[i].rtl)
+ {
+ if (sets[i].dest_addr_elt
+ && sets[i].dest_addr_elt->first_same_value == 0)
+ {
+ /* The elt was removed, which means this destination is not
+ valid after this instruction. */
+ sets[i].rtl = NULL_RTX;
+ }
+ else if (sets[i].src_elt && sets[i].src_elt->first_same_value == 0)
+ /* If elt was removed, find current head of same class,
+ or 0 if nothing remains of that class. */
+ {
+ struct table_elt *elt = sets[i].src_elt;
+
+ while (elt && elt->prev_same_value)
+ elt = elt->prev_same_value;
+
+ while (elt && elt->first_same_value == 0)
+ elt = elt->next_same_value;
+ sets[i].src_elt = elt ? elt->first_same_value : 0;
+ }
+ }
+
+ /* Now insert the destinations into their equivalence classes. */
+
+ for (i = 0; i < n_sets; i++)
+ if (sets[i].rtl)
+ {
+ rtx dest = SET_DEST (sets[i].rtl);
+ struct table_elt *elt;
+
+ /* Don't record value if we are not supposed to risk allocating
+ floating-point values in registers that might be wider than
+ memory. */
+ if ((flag_float_store
+ && MEM_P (dest)
+ && FLOAT_MODE_P (GET_MODE (dest)))
+ /* Don't record BLKmode values, because we don't know the
+ size of it, and can't be sure that other BLKmode values
+ have the same or smaller size. */
+ || GET_MODE (dest) == BLKmode
+ /* Don't record values of destinations set inside a libcall block
+ since we might delete the libcall. Things should have been set
+ up so we won't want to reuse such a value, but we play it safe
+ here. */
+ || libcall_insn
+ /* If we didn't put a REG_EQUAL value or a source into the hash
+ table, there is no point is recording DEST. */
+ || sets[i].src_elt == 0
+ /* If DEST is a paradoxical SUBREG and SRC is a ZERO_EXTEND
+ or SIGN_EXTEND, don't record DEST since it can cause
+ some tracking to be wrong.
+
+ ??? Think about this more later. */
+ || (GET_CODE (dest) == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (dest))
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))))
+ && (GET_CODE (sets[i].src) == SIGN_EXTEND
+ || GET_CODE (sets[i].src) == ZERO_EXTEND)))
+ continue;
+
+ /* STRICT_LOW_PART isn't part of the value BEING set,
+ and neither is the SUBREG inside it.
+ Note that in this case SETS[I].SRC_ELT is really SRC_EQV_ELT. */
+ if (GET_CODE (dest) == STRICT_LOW_PART)
+ dest = SUBREG_REG (XEXP (dest, 0));
+
+ if (REG_P (dest) || GET_CODE (dest) == SUBREG)
+ /* Registers must also be inserted into chains for quantities. */
+ if (insert_regs (dest, sets[i].src_elt, 1))
+ {
+ /* If `insert_regs' changes something, the hash code must be
+ recalculated. */
+ rehash_using_reg (dest);
+ sets[i].dest_hash = HASH (dest, GET_MODE (dest));
+ }
+
+ elt = insert (dest, sets[i].src_elt,
+ sets[i].dest_hash, GET_MODE (dest));
+
+ elt->in_memory = (MEM_P (sets[i].inner_dest)
+ && !MEM_READONLY_P (sets[i].inner_dest));
+
+ /* If we have (set (subreg:m1 (reg:m2 foo) 0) (bar:m1)), M1 is no
+ narrower than M2, and both M1 and M2 are the same number of words,
+ we are also doing (set (reg:m2 foo) (subreg:m2 (bar:m1) 0)) so
+ make that equivalence as well.
+
+ However, BAR may have equivalences for which gen_lowpart
+ will produce a simpler value than gen_lowpart applied to
+ BAR (e.g., if BAR was ZERO_EXTENDed from M2), so we will scan all
+ BAR's equivalences. If we don't get a simplified form, make
+ the SUBREG. It will not be used in an equivalence, but will
+ cause two similar assignments to be detected.
+
+ Note the loop below will find SUBREG_REG (DEST) since we have
+ already entered SRC and DEST of the SET in the table. */
+
+ if (GET_CODE (dest) == SUBREG
+ && (((GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))) - 1)
+ / UNITS_PER_WORD)
+ == (GET_MODE_SIZE (GET_MODE (dest)) - 1) / UNITS_PER_WORD)
+ && (GET_MODE_SIZE (GET_MODE (dest))
+ >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))))
+ && sets[i].src_elt != 0)
+ {
+ enum machine_mode new_mode = GET_MODE (SUBREG_REG (dest));
+ struct table_elt *elt, *classp = 0;
+
+ for (elt = sets[i].src_elt->first_same_value; elt;
+ elt = elt->next_same_value)
+ {
+ rtx new_src = 0;
+ unsigned src_hash;
+ struct table_elt *src_elt;
+ int byte = 0;
+
+ /* Ignore invalid entries. */
+ if (!REG_P (elt->exp)
+ && ! exp_equiv_p (elt->exp, elt->exp, 1, false))
+ continue;
+
+ /* We may have already been playing subreg games. If the
+ mode is already correct for the destination, use it. */
+ if (GET_MODE (elt->exp) == new_mode)
+ new_src = elt->exp;
+ else
+ {
+ /* Calculate big endian correction for the SUBREG_BYTE.
+ We have already checked that M1 (GET_MODE (dest))
+ is not narrower than M2 (new_mode). */
+ if (BYTES_BIG_ENDIAN)
+ byte = (GET_MODE_SIZE (GET_MODE (dest))
+ - GET_MODE_SIZE (new_mode));
+
+ new_src = simplify_gen_subreg (new_mode, elt->exp,
+ GET_MODE (dest), byte);
+ }
+
+ /* The call to simplify_gen_subreg fails if the value
+ is VOIDmode, yet we can't do any simplification, e.g.
+ for EXPR_LISTs denoting function call results.
+ It is invalid to construct a SUBREG with a VOIDmode
+ SUBREG_REG, hence a zero new_src means we can't do
+ this substitution. */
+ if (! new_src)
+ continue;
+
+ src_hash = HASH (new_src, new_mode);
+ src_elt = lookup (new_src, src_hash, new_mode);
+
+ /* Put the new source in the hash table is if isn't
+ already. */
+ if (src_elt == 0)
+ {
+ if (insert_regs (new_src, classp, 0))
+ {
+ rehash_using_reg (new_src);
+ src_hash = HASH (new_src, new_mode);
+ }
+ src_elt = insert (new_src, classp, src_hash, new_mode);
+ src_elt->in_memory = elt->in_memory;
+ }
+ else if (classp && classp != src_elt->first_same_value)
+ /* Show that two things that we've seen before are
+ actually the same. */
+ merge_equiv_classes (src_elt, classp);
+
+ classp = src_elt->first_same_value;
+ /* Ignore invalid entries. */
+ while (classp
+ && !REG_P (classp->exp)
+ && ! exp_equiv_p (classp->exp, classp->exp, 1, false))
+ classp = classp->next_same_value;
+ }
+ }
+ }
+
+ /* Special handling for (set REG0 REG1) where REG0 is the
+ "cheapest", cheaper than REG1. After cse, REG1 will probably not
+ be used in the sequel, so (if easily done) change this insn to
+ (set REG1 REG0) and replace REG1 with REG0 in the previous insn
+ that computed their value. Then REG1 will become a dead store
+ and won't cloud the situation for later optimizations.
+
+ Do not make this change if REG1 is a hard register, because it will
+ then be used in the sequel and we may be changing a two-operand insn
+ into a three-operand insn.
+
+ Also do not do this if we are operating on a copy of INSN.
+
+ Also don't do this if INSN ends a libcall; this would cause an unrelated
+ register to be set in the middle of a libcall, and we then get bad code
+ if the libcall is deleted. */
+
+ if (n_sets == 1 && sets[0].rtl && REG_P (SET_DEST (sets[0].rtl))
+ && NEXT_INSN (PREV_INSN (insn)) == insn
+ && REG_P (SET_SRC (sets[0].rtl))
+ && REGNO (SET_SRC (sets[0].rtl)) >= FIRST_PSEUDO_REGISTER
+ && REGNO_QTY_VALID_P (REGNO (SET_SRC (sets[0].rtl))))
+ {
+ int src_q = REG_QTY (REGNO (SET_SRC (sets[0].rtl)));
+ struct qty_table_elem *src_ent = &qty_table[src_q];
+
+ if ((src_ent->first_reg == REGNO (SET_DEST (sets[0].rtl)))
+ && ! find_reg_note (insn, REG_RETVAL, NULL_RTX))
+ {
+ rtx prev = insn;
+ /* Scan for the previous nonnote insn, but stop at a basic
+ block boundary. */
+ do
+ {
+ prev = PREV_INSN (prev);
+ }
+ while (prev && NOTE_P (prev)
+ && NOTE_LINE_NUMBER (prev) != NOTE_INSN_BASIC_BLOCK);
+
+ /* Do not swap the registers around if the previous instruction
+ attaches a REG_EQUIV note to REG1.
+
+ ??? It's not entirely clear whether we can transfer a REG_EQUIV
+ from the pseudo that originally shadowed an incoming argument
+ to another register. Some uses of REG_EQUIV might rely on it
+ being attached to REG1 rather than REG2.
+
+ This section previously turned the REG_EQUIV into a REG_EQUAL
+ note. We cannot do that because REG_EQUIV may provide an
+ uninitialized stack slot when REG_PARM_STACK_SPACE is used. */
+
+ if (prev != 0 && NONJUMP_INSN_P (prev)
+ && GET_CODE (PATTERN (prev)) == SET
+ && SET_DEST (PATTERN (prev)) == SET_SRC (sets[0].rtl)
+ && ! find_reg_note (prev, REG_EQUIV, NULL_RTX))
+ {
+ rtx dest = SET_DEST (sets[0].rtl);
+ rtx src = SET_SRC (sets[0].rtl);
+ rtx note;
+
+ validate_change (prev, &SET_DEST (PATTERN (prev)), dest, 1);
+ validate_change (insn, &SET_DEST (sets[0].rtl), src, 1);
+ validate_change (insn, &SET_SRC (sets[0].rtl), dest, 1);
+ apply_change_group ();
+
+ /* If INSN has a REG_EQUAL note, and this note mentions
+ REG0, then we must delete it, because the value in
+ REG0 has changed. If the note's value is REG1, we must
+ also delete it because that is now this insn's dest. */
+ note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
+ if (note != 0
+ && (reg_mentioned_p (dest, XEXP (note, 0))
+ || rtx_equal_p (src, XEXP (note, 0))))
+ remove_note (insn, note);
+ }
+ }
+ }
+
+ /* If this is a conditional jump insn, record any known equivalences due to
+ the condition being tested. */
+
+ if (JUMP_P (insn)
+ && n_sets == 1 && GET_CODE (x) == SET
+ && GET_CODE (SET_SRC (x)) == IF_THEN_ELSE)
+ record_jump_equiv (insn, 0);
+
+#ifdef HAVE_cc0
+ /* If the previous insn set CC0 and this insn no longer references CC0,
+ delete the previous insn. Here we use the fact that nothing expects CC0
+ to be valid over an insn, which is true until the final pass. */
+ if (prev_insn && NONJUMP_INSN_P (prev_insn)
+ && (tem = single_set (prev_insn)) != 0
+ && SET_DEST (tem) == cc0_rtx
+ && ! reg_mentioned_p (cc0_rtx, x))
+ delete_insn (prev_insn);
+
+ prev_insn_cc0 = this_insn_cc0;
+ prev_insn_cc0_mode = this_insn_cc0_mode;
+ prev_insn = insn;
+#endif
+}
+
+/* Remove from the hash table all expressions that reference memory. */
+
+static void
+invalidate_memory (void)
+{
+ int i;
+ struct table_elt *p, *next;
+
+ for (i = 0; i < HASH_SIZE; i++)
+ for (p = table[i]; p; p = next)
+ {
+ next = p->next_same_hash;
+ if (p->in_memory)
+ remove_from_table (p, i);
+ }
+}
+
+/* If ADDR is an address that implicitly affects the stack pointer, return
+ 1 and update the register tables to show the effect. Else, return 0. */
+
+static int
+addr_affects_sp_p (rtx addr)
+{
+ if (GET_RTX_CLASS (GET_CODE (addr)) == RTX_AUTOINC
+ && REG_P (XEXP (addr, 0))
+ && REGNO (XEXP (addr, 0)) == STACK_POINTER_REGNUM)
+ {
+ if (REG_TICK (STACK_POINTER_REGNUM) >= 0)
+ {
+ REG_TICK (STACK_POINTER_REGNUM)++;
+ /* Is it possible to use a subreg of SP? */
+ SUBREG_TICKED (STACK_POINTER_REGNUM) = -1;
+ }
+
+ /* This should be *very* rare. */
+ if (TEST_HARD_REG_BIT (hard_regs_in_table, STACK_POINTER_REGNUM))
+ invalidate (stack_pointer_rtx, VOIDmode);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Perform invalidation on the basis of everything about an insn
+ except for invalidating the actual places that are SET in it.
+ This includes the places CLOBBERed, and anything that might
+ alias with something that is SET or CLOBBERed.
+
+ X is the pattern of the insn. */
+
+static void
+invalidate_from_clobbers (rtx x)
+{
+ if (GET_CODE (x) == CLOBBER)
+ {
+ rtx ref = XEXP (x, 0);
+ if (ref)
+ {
+ if (REG_P (ref) || GET_CODE (ref) == SUBREG
+ || MEM_P (ref))
+ invalidate (ref, VOIDmode);
+ else if (GET_CODE (ref) == STRICT_LOW_PART
+ || GET_CODE (ref) == ZERO_EXTRACT)
+ invalidate (XEXP (ref, 0), GET_MODE (ref));
+ }
+ }
+ else if (GET_CODE (x) == PARALLEL)
+ {
+ int i;
+ for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
+ {
+ rtx y = XVECEXP (x, 0, i);
+ if (GET_CODE (y) == CLOBBER)
+ {
+ rtx ref = XEXP (y, 0);
+ if (REG_P (ref) || GET_CODE (ref) == SUBREG
+ || MEM_P (ref))
+ invalidate (ref, VOIDmode);
+ else if (GET_CODE (ref) == STRICT_LOW_PART
+ || GET_CODE (ref) == ZERO_EXTRACT)
+ invalidate (XEXP (ref, 0), GET_MODE (ref));
+ }
+ }
+ }
+}
+
+/* Process X, part of the REG_NOTES of an insn. Look at any REG_EQUAL notes
+ and replace any registers in them with either an equivalent constant
+ or the canonical form of the register. If we are inside an address,
+ only do this if the address remains valid.
+
+ OBJECT is 0 except when within a MEM in which case it is the MEM.
+
+ Return the replacement for X. */
+
+static rtx
+cse_process_notes (rtx x, rtx object)
+{
+ enum rtx_code code = GET_CODE (x);
+ const char *fmt = GET_RTX_FORMAT (code);
+ int i;
+
+ switch (code)
+ {
+ case CONST_INT:
+ case CONST:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ case CONST_DOUBLE:
+ case CONST_VECTOR:
+ case PC:
+ case CC0:
+ case LO_SUM:
+ return x;
+
+ case MEM:
+ validate_change (x, &XEXP (x, 0),
+ cse_process_notes (XEXP (x, 0), x), 0);
+ return x;
+
+ case EXPR_LIST:
+ case INSN_LIST:
+ if (REG_NOTE_KIND (x) == REG_EQUAL)
+ XEXP (x, 0) = cse_process_notes (XEXP (x, 0), NULL_RTX);
+ if (XEXP (x, 1))
+ XEXP (x, 1) = cse_process_notes (XEXP (x, 1), NULL_RTX);
+ return x;
+
+ case SIGN_EXTEND:
+ case ZERO_EXTEND:
+ case SUBREG:
+ {
+ rtx new = cse_process_notes (XEXP (x, 0), object);
+ /* We don't substitute VOIDmode constants into these rtx,
+ since they would impede folding. */
+ if (GET_MODE (new) != VOIDmode)
+ validate_change (object, &XEXP (x, 0), new, 0);
+ return x;
+ }
+
+ case REG:
+ i = REG_QTY (REGNO (x));
+
+ /* Return a constant or a constant register. */
+ if (REGNO_QTY_VALID_P (REGNO (x)))
+ {
+ struct qty_table_elem *ent = &qty_table[i];
+
+ if (ent->const_rtx != NULL_RTX
+ && (CONSTANT_P (ent->const_rtx)
+ || REG_P (ent->const_rtx)))
+ {
+ rtx new = gen_lowpart (GET_MODE (x), ent->const_rtx);
+ if (new)
+ return new;
+ }
+ }
+
+ /* Otherwise, canonicalize this register. */
+ return canon_reg (x, NULL_RTX);
+
+ default:
+ break;
+ }
+
+ for (i = 0; i < GET_RTX_LENGTH (code); i++)
+ if (fmt[i] == 'e')
+ validate_change (object, &XEXP (x, i),
+ cse_process_notes (XEXP (x, i), object), 0);
+
+ return x;
+}
+
+/* Process one SET of an insn that was skipped. We ignore CLOBBERs
+ since they are done elsewhere. This function is called via note_stores. */
+
+static void
+invalidate_skipped_set (rtx dest, rtx set, void *data ATTRIBUTE_UNUSED)
+{
+ enum rtx_code code = GET_CODE (dest);
+
+ if (code == MEM
+ && ! addr_affects_sp_p (dest) /* If this is not a stack push ... */
+ /* There are times when an address can appear varying and be a PLUS
+ during this scan when it would be a fixed address were we to know
+ the proper equivalences. So invalidate all memory if there is
+ a BLKmode or nonscalar memory reference or a reference to a
+ variable address. */
+ && (MEM_IN_STRUCT_P (dest) || GET_MODE (dest) == BLKmode
+ || cse_rtx_varies_p (XEXP (dest, 0), 0)))
+ {
+ invalidate_memory ();
+ return;
+ }
+
+ if (GET_CODE (set) == CLOBBER
+ || CC0_P (dest)
+ || dest == pc_rtx)
+ return;
+
+ if (code == STRICT_LOW_PART || code == ZERO_EXTRACT)
+ invalidate (XEXP (dest, 0), GET_MODE (dest));
+ else if (code == REG || code == SUBREG || code == MEM)
+ invalidate (dest, VOIDmode);
+}
+
+/* Invalidate all insns from START up to the end of the function or the
+ next label. This called when we wish to CSE around a block that is
+ conditionally executed. */
+
+static void
+invalidate_skipped_block (rtx start)
+{
+ rtx insn;
+
+ for (insn = start; insn && !LABEL_P (insn);
+ insn = NEXT_INSN (insn))
+ {
+ if (! INSN_P (insn))
+ continue;
+
+ if (CALL_P (insn))
+ {
+ if (! CONST_OR_PURE_CALL_P (insn))
+ invalidate_memory ();
+ invalidate_for_call ();
+ }
+
+ invalidate_from_clobbers (PATTERN (insn));
+ note_stores (PATTERN (insn), invalidate_skipped_set, NULL);
+ }
+}
+
+/* Find the end of INSN's basic block and return its range,
+ the total number of SETs in all the insns of the block, the last insn of the
+ block, and the branch path.
+
+ The branch path indicates which branches should be followed. If a nonzero
+ path size is specified, the block should be rescanned and a different set
+ of branches will be taken. The branch path is only used if
+ FLAG_CSE_FOLLOW_JUMPS or FLAG_CSE_SKIP_BLOCKS is nonzero.
+
+ DATA is a pointer to a struct cse_basic_block_data, defined below, that is
+ used to describe the block. It is filled in with the information about
+ the current block. The incoming structure's branch path, if any, is used
+ to construct the output branch path. */
+
+static void
+cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data,
+ int follow_jumps, int skip_blocks)
+{
+ rtx p = insn, q;
+ int nsets = 0;
+ int low_cuid = INSN_CUID (insn), high_cuid = INSN_CUID (insn);
+ rtx next = INSN_P (insn) ? insn : next_real_insn (insn);
+ int path_size = data->path_size;
+ int path_entry = 0;
+ int i;
+
+ /* Update the previous branch path, if any. If the last branch was
+ previously PATH_TAKEN, mark it PATH_NOT_TAKEN.
+ If it was previously PATH_NOT_TAKEN,
+ shorten the path by one and look at the previous branch. We know that
+ at least one branch must have been taken if PATH_SIZE is nonzero. */
+ while (path_size > 0)
+ {
+ if (data->path[path_size - 1].status != PATH_NOT_TAKEN)
+ {
+ data->path[path_size - 1].status = PATH_NOT_TAKEN;
+ break;
+ }
+ else
+ path_size--;
+ }
+
+ /* If the first instruction is marked with QImode, that means we've
+ already processed this block. Our caller will look at DATA->LAST
+ to figure out where to go next. We want to return the next block
+ in the instruction stream, not some branched-to block somewhere
+ else. We accomplish this by pretending our called forbid us to
+ follow jumps, or skip blocks. */
+ if (GET_MODE (insn) == QImode)
+ follow_jumps = skip_blocks = 0;
+
+ /* Scan to end of this basic block. */
+ while (p && !LABEL_P (p))
+ {
+ /* Don't cse over a call to setjmp; on some machines (eg VAX)
+ the regs restored by the longjmp come from
+ a later time than the setjmp. */
+ if (PREV_INSN (p) && CALL_P (PREV_INSN (p))
+ && find_reg_note (PREV_INSN (p), REG_SETJMP, NULL))
+ break;
+
+ /* A PARALLEL can have lots of SETs in it,
+ especially if it is really an ASM_OPERANDS. */
+ if (INSN_P (p) && GET_CODE (PATTERN (p)) == PARALLEL)
+ nsets += XVECLEN (PATTERN (p), 0);
+ else if (!NOTE_P (p))
+ nsets += 1;
+
+ /* Ignore insns made by CSE; they cannot affect the boundaries of
+ the basic block. */
+
+ if (INSN_UID (p) <= max_uid && INSN_CUID (p) > high_cuid)
+ high_cuid = INSN_CUID (p);
+ if (INSN_UID (p) <= max_uid && INSN_CUID (p) < low_cuid)
+ low_cuid = INSN_CUID (p);
+
+ /* See if this insn is in our branch path. If it is and we are to
+ take it, do so. */
+ if (path_entry < path_size && data->path[path_entry].branch == p)
+ {
+ if (data->path[path_entry].status != PATH_NOT_TAKEN)
+ p = JUMP_LABEL (p);
+
+ /* Point to next entry in path, if any. */
+ path_entry++;
+ }
+
+ /* If this is a conditional jump, we can follow it if -fcse-follow-jumps
+ was specified, we haven't reached our maximum path length, there are
+ insns following the target of the jump, this is the only use of the
+ jump label, and the target label is preceded by a BARRIER.
+
+ Alternatively, we can follow the jump if it branches around a
+ block of code and there are no other branches into the block.
+ In this case invalidate_skipped_block will be called to invalidate any
+ registers set in the block when following the jump. */
+
+ else if ((follow_jumps || skip_blocks) && path_size < PARAM_VALUE (PARAM_MAX_CSE_PATH_LENGTH) - 1
+ && JUMP_P (p)
+ && GET_CODE (PATTERN (p)) == SET
+ && GET_CODE (SET_SRC (PATTERN (p))) == IF_THEN_ELSE
+ && JUMP_LABEL (p) != 0
+ && LABEL_NUSES (JUMP_LABEL (p)) == 1
+ && NEXT_INSN (JUMP_LABEL (p)) != 0)
+ {
+ for (q = PREV_INSN (JUMP_LABEL (p)); q; q = PREV_INSN (q))
+ if ((!NOTE_P (q)
+ || (PREV_INSN (q) && CALL_P (PREV_INSN (q))
+ && find_reg_note (PREV_INSN (q), REG_SETJMP, NULL)))
+ && (!LABEL_P (q) || LABEL_NUSES (q) != 0))
+ break;
+
+ /* If we ran into a BARRIER, this code is an extension of the
+ basic block when the branch is taken. */
+ if (follow_jumps && q != 0 && BARRIER_P (q))
+ {
+ /* Don't allow ourself to keep walking around an
+ always-executed loop. */
+ if (next_real_insn (q) == next)
+ {
+ p = NEXT_INSN (p);
+ continue;
+ }
+
+ /* Similarly, don't put a branch in our path more than once. */
+ for (i = 0; i < path_entry; i++)
+ if (data->path[i].branch == p)
+ break;
+
+ if (i != path_entry)
+ break;
+
+ data->path[path_entry].branch = p;
+ data->path[path_entry++].status = PATH_TAKEN;
+
+ /* This branch now ends our path. It was possible that we
+ didn't see this branch the last time around (when the
+ insn in front of the target was a JUMP_INSN that was
+ turned into a no-op). */
+ path_size = path_entry;
+
+ p = JUMP_LABEL (p);
+ /* Mark block so we won't scan it again later. */
+ PUT_MODE (NEXT_INSN (p), QImode);
+ }
+ /* Detect a branch around a block of code. */
+ else if (skip_blocks && q != 0 && !LABEL_P (q))
+ {
+ rtx tmp;
+
+ if (next_real_insn (q) == next)
+ {
+ p = NEXT_INSN (p);
+ continue;
+ }
+
+ for (i = 0; i < path_entry; i++)
+ if (data->path[i].branch == p)
+ break;
+
+ if (i != path_entry)
+ break;
+
+ /* This is no_labels_between_p (p, q) with an added check for
+ reaching the end of a function (in case Q precedes P). */
+ for (tmp = NEXT_INSN (p); tmp && tmp != q; tmp = NEXT_INSN (tmp))
+ if (LABEL_P (tmp))
+ break;
+
+ if (tmp == q)
+ {
+ data->path[path_entry].branch = p;
+ data->path[path_entry++].status = PATH_AROUND;
+
+ path_size = path_entry;
+
+ p = JUMP_LABEL (p);
+ /* Mark block so we won't scan it again later. */
+ PUT_MODE (NEXT_INSN (p), QImode);
+ }
+ }
+ }
+ p = NEXT_INSN (p);
+ }
+
+ data->low_cuid = low_cuid;
+ data->high_cuid = high_cuid;
+ data->nsets = nsets;
+ data->last = p;
+
+ /* If all jumps in the path are not taken, set our path length to zero
+ so a rescan won't be done. */
+ for (i = path_size - 1; i >= 0; i--)
+ if (data->path[i].status != PATH_NOT_TAKEN)
+ break;
+
+ if (i == -1)
+ data->path_size = 0;
+ else
+ data->path_size = path_size;
+
+ /* End the current branch path. */
+ data->path[path_size].branch = 0;
+}
+
+/* Perform cse on the instructions of a function.
+ F is the first instruction.
+ NREGS is one plus the highest pseudo-reg number used in the instruction.
+
+ Returns 1 if jump_optimize should be redone due to simplifications
+ in conditional jump instructions. */
+
+int
+cse_main (rtx f, int nregs)
+{
+ struct cse_basic_block_data val;
+ rtx insn = f;
+ int i;
+
+ init_cse_reg_info (nregs);
+
+ val.path = XNEWVEC (struct branch_path, PARAM_VALUE (PARAM_MAX_CSE_PATH_LENGTH));
+
+ cse_jumps_altered = 0;
+ recorded_label_ref = 0;
+ constant_pool_entries_cost = 0;
+ constant_pool_entries_regcost = 0;
+ val.path_size = 0;
+ rtl_hooks = cse_rtl_hooks;
+
+ init_recog ();
+ init_alias_analysis ();
+
+ reg_eqv_table = XNEWVEC (struct reg_eqv_elem, nregs);
+
+ /* Find the largest uid. */
+
+ max_uid = get_max_uid ();
+ uid_cuid = XCNEWVEC (int, max_uid + 1);
+
+ /* Compute the mapping from uids to cuids.
+ CUIDs are numbers assigned to insns, like uids,
+ except that cuids increase monotonically through the code.
+ Don't assign cuids to line-number NOTEs, so that the distance in cuids
+ between two insns is not affected by -g. */
+
+ for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
+ {
+ if (!NOTE_P (insn)
+ || NOTE_LINE_NUMBER (insn) < 0)
+ INSN_CUID (insn) = ++i;
+ else
+ /* Give a line number note the same cuid as preceding insn. */
+ INSN_CUID (insn) = i;
+ }
+
+ /* Loop over basic blocks.
+ Compute the maximum number of qty's needed for each basic block
+ (which is 2 for each SET). */
+ insn = f;
+ while (insn)
+ {
+ cse_altered = 0;
+ cse_end_of_basic_block (insn, &val, flag_cse_follow_jumps,
+ flag_cse_skip_blocks);
+
+ /* If this basic block was already processed or has no sets, skip it. */
+ if (val.nsets == 0 || GET_MODE (insn) == QImode)
+ {
+ PUT_MODE (insn, VOIDmode);
+ insn = (val.last ? NEXT_INSN (val.last) : 0);
+ val.path_size = 0;
+ continue;
+ }
+
+ cse_basic_block_start = val.low_cuid;
+ cse_basic_block_end = val.high_cuid;
+ max_qty = val.nsets * 2;
+
+ if (dump_file)
+ fprintf (dump_file, ";; Processing block from %d to %d, %d sets.\n",
+ INSN_UID (insn), val.last ? INSN_UID (val.last) : 0,
+ val.nsets);
+
+ /* Make MAX_QTY bigger to give us room to optimize
+ past the end of this basic block, if that should prove useful. */
+ if (max_qty < 500)
+ max_qty = 500;
+
+ /* If this basic block is being extended by following certain jumps,
+ (see `cse_end_of_basic_block'), we reprocess the code from the start.
+ Otherwise, we start after this basic block. */
+ if (val.path_size > 0)
+ cse_basic_block (insn, val.last, val.path);
+ else
+ {
+ int old_cse_jumps_altered = cse_jumps_altered;
+ rtx temp;
+
+ /* When cse changes a conditional jump to an unconditional
+ jump, we want to reprocess the block, since it will give
+ us a new branch path to investigate. */
+ cse_jumps_altered = 0;
+ temp = cse_basic_block (insn, val.last, val.path);
+ if (cse_jumps_altered == 0
+ || (flag_cse_follow_jumps == 0 && flag_cse_skip_blocks == 0))
+ insn = temp;
+
+ cse_jumps_altered |= old_cse_jumps_altered;
+ }
+
+ if (cse_altered)
+ ggc_collect ();
+
+#ifdef USE_C_ALLOCA
+ alloca (0);
+#endif
+ }
+
+ /* Clean up. */
+ end_alias_analysis ();
+ free (uid_cuid);
+ free (reg_eqv_table);
+ free (val.path);
+ rtl_hooks = general_rtl_hooks;
+
+ return cse_jumps_altered || recorded_label_ref;
+}
+
+/* Process a single basic block. FROM and TO and the limits of the basic
+ block. NEXT_BRANCH points to the branch path when following jumps or
+ a null path when not following jumps. */
+
+static rtx
+cse_basic_block (rtx from, rtx to, struct branch_path *next_branch)
+{
+ rtx insn;
+ int to_usage = 0;
+ rtx libcall_insn = NULL_RTX;
+ int num_insns = 0;
+ int no_conflict = 0;
+
+ /* Allocate the space needed by qty_table. */
+ qty_table = XNEWVEC (struct qty_table_elem, max_qty);
+
+ new_basic_block ();
+
+ /* TO might be a label. If so, protect it from being deleted. */
+ if (to != 0 && LABEL_P (to))
+ ++LABEL_NUSES (to);
+
+ for (insn = from; insn != to; insn = NEXT_INSN (insn))
+ {
+ enum rtx_code code = GET_CODE (insn);
+
+ /* If we have processed 1,000 insns, flush the hash table to
+ avoid extreme quadratic behavior. We must not include NOTEs
+ in the count since there may be more of them when generating
+ debugging information. If we clear the table at different
+ times, code generated with -g -O might be different than code
+ generated with -O but not -g.
+
+ ??? This is a real kludge and needs to be done some other way.
+ Perhaps for 2.9. */
+ if (code != NOTE && num_insns++ > PARAM_VALUE (PARAM_MAX_CSE_INSNS))
+ {
+ flush_hash_table ();
+ num_insns = 0;
+ }
+
+ /* See if this is a branch that is part of the path. If so, and it is
+ to be taken, do so. */
+ if (next_branch->branch == insn)
+ {
+ enum taken status = next_branch++->status;
+ if (status != PATH_NOT_TAKEN)
+ {
+ if (status == PATH_TAKEN)
+ record_jump_equiv (insn, 1);
+ else
+ invalidate_skipped_block (NEXT_INSN (insn));
+
+ /* Set the last insn as the jump insn; it doesn't affect cc0.
+ Then follow this branch. */
+#ifdef HAVE_cc0
+ prev_insn_cc0 = 0;
+ prev_insn = insn;
+#endif
+ insn = JUMP_LABEL (insn);
+ continue;
+ }
+ }
+
+ if (GET_MODE (insn) == QImode)
+ PUT_MODE (insn, VOIDmode);
+
+ if (GET_RTX_CLASS (code) == RTX_INSN)
+ {
+ rtx p;
+
+ /* Process notes first so we have all notes in canonical forms when
+ looking for duplicate operations. */
+
+ if (REG_NOTES (insn))
+ REG_NOTES (insn) = cse_process_notes (REG_NOTES (insn), NULL_RTX);
+
+ /* Track when we are inside in LIBCALL block. Inside such a block,
+ we do not want to record destinations. The last insn of a
+ LIBCALL block is not considered to be part of the block, since
+ its destination is the result of the block and hence should be
+ recorded. */
+
+ if (REG_NOTES (insn) != 0)
+ {
+ if ((p = find_reg_note (insn, REG_LIBCALL, NULL_RTX)))
+ libcall_insn = XEXP (p, 0);
+ else if (find_reg_note (insn, REG_RETVAL, NULL_RTX))
+ {
+ /* Keep libcall_insn for the last SET insn of a no-conflict
+ block to prevent changing the destination. */
+ if (! no_conflict)
+ libcall_insn = 0;
+ else
+ no_conflict = -1;
+ }
+ else if (find_reg_note (insn, REG_NO_CONFLICT, NULL_RTX))
+ no_conflict = 1;
+ }
+
+ cse_insn (insn, libcall_insn);
+
+ if (no_conflict == -1)
+ {
+ libcall_insn = 0;
+ no_conflict = 0;
+ }
+
+ /* If we haven't already found an insn where we added a LABEL_REF,
+ check this one. */
+ if (NONJUMP_INSN_P (insn) && ! recorded_label_ref
+ && for_each_rtx (&PATTERN (insn), check_for_label_ref,
+ (void *) insn))
+ recorded_label_ref = 1;
+ }
+
+ /* If INSN is now an unconditional jump, skip to the end of our
+ basic block by pretending that we just did the last insn in the
+ basic block. If we are jumping to the end of our block, show
+ that we can have one usage of TO. */
+
+ if (any_uncondjump_p (insn))
+ {
+ if (to == 0)
+ {
+ free (qty_table);
+ return 0;
+ }
+
+ if (JUMP_LABEL (insn) == to)
+ to_usage = 1;
+
+ /* Maybe TO was deleted because the jump is unconditional.
+ If so, there is nothing left in this basic block. */
+ /* ??? Perhaps it would be smarter to set TO
+ to whatever follows this insn,
+ and pretend the basic block had always ended here. */
+ if (INSN_DELETED_P (to))
+ break;
+
+ insn = PREV_INSN (to);
+ }
+
+ /* See if it is ok to keep on going past the label
+ which used to end our basic block. Remember that we incremented
+ the count of that label, so we decrement it here. If we made
+ a jump unconditional, TO_USAGE will be one; in that case, we don't
+ want to count the use in that jump. */
+
+ if (to != 0 && NEXT_INSN (insn) == to
+ && LABEL_P (to) && --LABEL_NUSES (to) == to_usage)
+ {
+ struct cse_basic_block_data val;
+ rtx prev;
+
+ insn = NEXT_INSN (to);
+
+ /* If TO was the last insn in the function, we are done. */
+ if (insn == 0)
+ {
+ free (qty_table);
+ return 0;
+ }
+
+ /* If TO was preceded by a BARRIER we are done with this block
+ because it has no continuation. */
+ prev = prev_nonnote_insn (to);
+ if (prev && BARRIER_P (prev))
+ {
+ free (qty_table);
+ return insn;
+ }
+
+ /* Find the end of the following block. Note that we won't be
+ following branches in this case. */
+ to_usage = 0;
+ val.path_size = 0;
+ val.path = XNEWVEC (struct branch_path, PARAM_VALUE (PARAM_MAX_CSE_PATH_LENGTH));
+ cse_end_of_basic_block (insn, &val, 0, 0);
+ free (val.path);
+
+ /* If the tables we allocated have enough space left
+ to handle all the SETs in the next basic block,
+ continue through it. Otherwise, return,
+ and that block will be scanned individually. */
+ if (val.nsets * 2 + next_qty > max_qty)
+ break;
+
+ cse_basic_block_start = val.low_cuid;
+ cse_basic_block_end = val.high_cuid;
+ to = val.last;
+
+ /* Prevent TO from being deleted if it is a label. */
+ if (to != 0 && LABEL_P (to))
+ ++LABEL_NUSES (to);
+
+ /* Back up so we process the first insn in the extension. */
+ insn = PREV_INSN (insn);
+ }
+ }
+
+ gcc_assert (next_qty <= max_qty);
+
+ free (qty_table);
+
+ return to ? NEXT_INSN (to) : 0;
+}
+
+/* Called via for_each_rtx to see if an insn is using a LABEL_REF for which
+ there isn't a REG_LABEL note. Return one if so. DATA is the insn. */
+
+static int
+check_for_label_ref (rtx *rtl, void *data)
+{
+ rtx insn = (rtx) data;
+
+ /* If this insn uses a LABEL_REF and there isn't a REG_LABEL note for it,
+ we must rerun jump since it needs to place the note. If this is a
+ LABEL_REF for a CODE_LABEL that isn't in the insn chain, don't do this
+ since no REG_LABEL will be added. */
+ return (GET_CODE (*rtl) == LABEL_REF
+ && ! LABEL_REF_NONLOCAL_P (*rtl)
+ && LABEL_P (XEXP (*rtl, 0))
+ && INSN_UID (XEXP (*rtl, 0)) != 0
+ && ! find_reg_note (insn, REG_LABEL, XEXP (*rtl, 0)));
+}
+
+/* Count the number of times registers are used (not set) in X.
+ COUNTS is an array in which we accumulate the count, INCR is how much
+ we count each register usage.
+
+ Don't count a usage of DEST, which is the SET_DEST of a SET which
+ contains X in its SET_SRC. This is because such a SET does not
+ modify the liveness of DEST.
+ DEST is set to pc_rtx for a trapping insn, which means that we must count
+ uses of a SET_DEST regardless because the insn can't be deleted here. */
+
+static void
+count_reg_usage (rtx x, int *counts, rtx dest, int incr)
+{
+ enum rtx_code code;
+ rtx note;
+ const char *fmt;
+ int i, j;
+
+ if (x == 0)
+ return;
+
+ switch (code = GET_CODE (x))
+ {
+ case REG:
+ if (x != dest)
+ counts[REGNO (x)] += incr;
+ return;
+
+ case PC:
+ case CC0:
+ case CONST:
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case CONST_VECTOR:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ return;
+
+ case CLOBBER:
+ /* If we are clobbering a MEM, mark any registers inside the address
+ as being used. */
+ if (MEM_P (XEXP (x, 0)))
+ count_reg_usage (XEXP (XEXP (x, 0), 0), counts, NULL_RTX, incr);
+ return;
+
+ case SET:
+ /* Unless we are setting a REG, count everything in SET_DEST. */
+ if (!REG_P (SET_DEST (x)))
+ count_reg_usage (SET_DEST (x), counts, NULL_RTX, incr);
+ count_reg_usage (SET_SRC (x), counts,
+ dest ? dest : SET_DEST (x),
+ incr);
+ return;
+
+ case CALL_INSN:
+ case INSN:
+ case JUMP_INSN:
+ /* We expect dest to be NULL_RTX here. If the insn may trap, mark
+ this fact by setting DEST to pc_rtx. */
+ if (flag_non_call_exceptions && may_trap_p (PATTERN (x)))
+ dest = pc_rtx;
+ if (code == CALL_INSN)
+ count_reg_usage (CALL_INSN_FUNCTION_USAGE (x), counts, dest, incr);
+ count_reg_usage (PATTERN (x), counts, dest, incr);
+
+ /* Things used in a REG_EQUAL note aren't dead since loop may try to
+ use them. */
+
+ note = find_reg_equal_equiv_note (x);
+ if (note)
+ {
+ rtx eqv = XEXP (note, 0);
+
+ if (GET_CODE (eqv) == EXPR_LIST)
+ /* This REG_EQUAL note describes the result of a function call.
+ Process all the arguments. */
+ do
+ {
+ count_reg_usage (XEXP (eqv, 0), counts, dest, incr);
+ eqv = XEXP (eqv, 1);
+ }
+ while (eqv && GET_CODE (eqv) == EXPR_LIST);
+ else
+ count_reg_usage (eqv, counts, dest, incr);
+ }
+ return;
+
+ case EXPR_LIST:
+ if (REG_NOTE_KIND (x) == REG_EQUAL
+ || (REG_NOTE_KIND (x) != REG_NONNEG && GET_CODE (XEXP (x,0)) == USE)
+ /* FUNCTION_USAGE expression lists may include (CLOBBER (mem /u)),
+ involving registers in the address. */
+ || GET_CODE (XEXP (x, 0)) == CLOBBER)
+ count_reg_usage (XEXP (x, 0), counts, NULL_RTX, incr);
+
+ count_reg_usage (XEXP (x, 1), counts, NULL_RTX, incr);
+ return;
+
+ case ASM_OPERANDS:
+ /* If the asm is volatile, then this insn cannot be deleted,
+ and so the inputs *must* be live. */
+ if (MEM_VOLATILE_P (x))
+ dest = NULL_RTX;
+ /* Iterate over just the inputs, not the constraints as well. */
+ for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--)
+ count_reg_usage (ASM_OPERANDS_INPUT (x, i), counts, dest, incr);
+ return;
+
+ case INSN_LIST:
+ gcc_unreachable ();
+
+ default:
+ break;
+ }
+
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ count_reg_usage (XEXP (x, i), counts, dest, incr);
+ else if (fmt[i] == 'E')
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ count_reg_usage (XVECEXP (x, i, j), counts, dest, incr);
+ }
+}
+
+/* Return true if set is live. */
+static bool
+set_live_p (rtx set, rtx insn ATTRIBUTE_UNUSED, /* Only used with HAVE_cc0. */
+ int *counts)
+{
+#ifdef HAVE_cc0
+ rtx tem;
+#endif
+
+ if (set_noop_p (set))
+ ;
+
+#ifdef HAVE_cc0
+ else if (GET_CODE (SET_DEST (set)) == CC0
+ && !side_effects_p (SET_SRC (set))
+ && ((tem = next_nonnote_insn (insn)) == 0
+ || !INSN_P (tem)
+ || !reg_referenced_p (cc0_rtx, PATTERN (tem))))
+ return false;
+#endif
+ else if (!REG_P (SET_DEST (set))
+ || REGNO (SET_DEST (set)) < FIRST_PSEUDO_REGISTER
+ || counts[REGNO (SET_DEST (set))] != 0
+ || side_effects_p (SET_SRC (set)))
+ return true;
+ return false;
+}
+
+/* Return true if insn is live. */
+
+static bool
+insn_live_p (rtx insn, int *counts)
+{
+ int i;
+ if (flag_non_call_exceptions && may_trap_p (PATTERN (insn)))
+ return true;
+ else if (GET_CODE (PATTERN (insn)) == SET)
+ return set_live_p (PATTERN (insn), insn, counts);
+ else if (GET_CODE (PATTERN (insn)) == PARALLEL)
+ {
+ for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
+ {
+ rtx elt = XVECEXP (PATTERN (insn), 0, i);
+
+ if (GET_CODE (elt) == SET)
+ {
+ if (set_live_p (elt, insn, counts))
+ return true;
+ }
+ else if (GET_CODE (elt) != CLOBBER && GET_CODE (elt) != USE)
+ return true;
+ }
+ return false;
+ }
+ else
+ return true;
+}
+
+/* Return true if libcall is dead as a whole. */
+
+static bool
+dead_libcall_p (rtx insn, int *counts)
+{
+ rtx note, set, new;
+
+ /* See if there's a REG_EQUAL note on this insn and try to
+ replace the source with the REG_EQUAL expression.
+
+ We assume that insns with REG_RETVALs can only be reg->reg
+ copies at this point. */
+ note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
+ if (!note)
+ return false;
+
+ set = single_set (insn);
+ if (!set)
+ return false;
+
+ new = simplify_rtx (XEXP (note, 0));
+ if (!new)
+ new = XEXP (note, 0);
+
+ /* While changing insn, we must update the counts accordingly. */
+ count_reg_usage (insn, counts, NULL_RTX, -1);
+
+ if (validate_change (insn, &SET_SRC (set), new, 0))
+ {
+ count_reg_usage (insn, counts, NULL_RTX, 1);
+ remove_note (insn, find_reg_note (insn, REG_RETVAL, NULL_RTX));
+ remove_note (insn, note);
+ return true;
+ }
+
+ if (CONSTANT_P (new))
+ {
+ new = force_const_mem (GET_MODE (SET_DEST (set)), new);
+ if (new && validate_change (insn, &SET_SRC (set), new, 0))
+ {
+ count_reg_usage (insn, counts, NULL_RTX, 1);
+ remove_note (insn, find_reg_note (insn, REG_RETVAL, NULL_RTX));
+ remove_note (insn, note);
+ return true;
+ }
+ }
+
+ count_reg_usage (insn, counts, NULL_RTX, 1);
+ return false;
+}
+
+/* Scan all the insns and delete any that are dead; i.e., they store a register
+ that is never used or they copy a register to itself.
+
+ This is used to remove insns made obviously dead by cse, loop or other
+ optimizations. It improves the heuristics in loop since it won't try to
+ move dead invariants out of loops or make givs for dead quantities. The
+ remaining passes of the compilation are also sped up. */
+
+int
+delete_trivially_dead_insns (rtx insns, int nreg)
+{
+ int *counts;
+ rtx insn, prev;
+ int in_libcall = 0, dead_libcall = 0;
+ int ndead = 0;
+
+ timevar_push (TV_DELETE_TRIVIALLY_DEAD);
+ /* First count the number of times each register is used. */
+ counts = XCNEWVEC (int, nreg);
+ for (insn = insns; insn; insn = NEXT_INSN (insn))
+ if (INSN_P (insn))
+ count_reg_usage (insn, counts, NULL_RTX, 1);
+
+ /* Go from the last insn to the first and delete insns that only set unused
+ registers or copy a register to itself. As we delete an insn, remove
+ usage counts for registers it uses.
+
+ The first jump optimization pass may leave a real insn as the last
+ insn in the function. We must not skip that insn or we may end
+ up deleting code that is not really dead. */
+ for (insn = get_last_insn (); insn; insn = prev)
+ {
+ int live_insn = 0;
+
+ prev = PREV_INSN (insn);
+ if (!INSN_P (insn))
+ continue;
+
+ /* Don't delete any insns that are part of a libcall block unless
+ we can delete the whole libcall block.
+
+ Flow or loop might get confused if we did that. Remember
+ that we are scanning backwards. */
+ if (find_reg_note (insn, REG_RETVAL, NULL_RTX))
+ {
+ in_libcall = 1;
+ live_insn = 1;
+ dead_libcall = dead_libcall_p (insn, counts);
+ }
+ else if (in_libcall)
+ live_insn = ! dead_libcall;
+ else
+ live_insn = insn_live_p (insn, counts);
+
+ /* If this is a dead insn, delete it and show registers in it aren't
+ being used. */
+
+ if (! live_insn)
+ {
+ count_reg_usage (insn, counts, NULL_RTX, -1);
+ delete_insn_and_edges (insn);
+ ndead++;
+ }
+
+ if (in_libcall && find_reg_note (insn, REG_LIBCALL, NULL_RTX))
+ {
+ in_libcall = 0;
+ dead_libcall = 0;
+ }
+ }
+
+ if (dump_file && ndead)
+ fprintf (dump_file, "Deleted %i trivially dead insns\n",
+ ndead);
+ /* Clean up. */
+ free (counts);
+ timevar_pop (TV_DELETE_TRIVIALLY_DEAD);
+ return ndead;
+}
+
+/* This function is called via for_each_rtx. The argument, NEWREG, is
+ a condition code register with the desired mode. If we are looking
+ at the same register in a different mode, replace it with
+ NEWREG. */
+
+static int
+cse_change_cc_mode (rtx *loc, void *data)
+{
+ struct change_cc_mode_args* args = (struct change_cc_mode_args*)data;
+
+ if (*loc
+ && REG_P (*loc)
+ && REGNO (*loc) == REGNO (args->newreg)
+ && GET_MODE (*loc) != GET_MODE (args->newreg))
+ {
+ validate_change (args->insn, loc, args->newreg, 1);
+
+ return -1;
+ }
+ return 0;
+}
+
+/* Change the mode of any reference to the register REGNO (NEWREG) to
+ GET_MODE (NEWREG) in INSN. */
+
+static void
+cse_change_cc_mode_insn (rtx insn, rtx newreg)
+{
+ struct change_cc_mode_args args;
+ int success;
+
+ if (!INSN_P (insn))
+ return;
+
+ args.insn = insn;
+ args.newreg = newreg;
+
+ for_each_rtx (&PATTERN (insn), cse_change_cc_mode, &args);
+ for_each_rtx (&REG_NOTES (insn), cse_change_cc_mode, &args);
+
+ /* If the following assertion was triggered, there is most probably
+ something wrong with the cc_modes_compatible back end function.
+ CC modes only can be considered compatible if the insn - with the mode
+ replaced by any of the compatible modes - can still be recognized. */
+ success = apply_change_group ();
+ gcc_assert (success);
+}
+
+/* Change the mode of any reference to the register REGNO (NEWREG) to
+ GET_MODE (NEWREG), starting at START. Stop before END. Stop at
+ any instruction which modifies NEWREG. */
+
+static void
+cse_change_cc_mode_insns (rtx start, rtx end, rtx newreg)
+{
+ rtx insn;
+
+ for (insn = start; insn != end; insn = NEXT_INSN (insn))
+ {
+ if (! INSN_P (insn))
+ continue;
+
+ if (reg_set_p (newreg, insn))
+ return;
+
+ cse_change_cc_mode_insn (insn, newreg);
+ }
+}
+
+/* BB is a basic block which finishes with CC_REG as a condition code
+ register which is set to CC_SRC. Look through the successors of BB
+ to find blocks which have a single predecessor (i.e., this one),
+ and look through those blocks for an assignment to CC_REG which is
+ equivalent to CC_SRC. CAN_CHANGE_MODE indicates whether we are
+ permitted to change the mode of CC_SRC to a compatible mode. This
+ returns VOIDmode if no equivalent assignments were found.
+ Otherwise it returns the mode which CC_SRC should wind up with.
+
+ The main complexity in this function is handling the mode issues.
+ We may have more than one duplicate which we can eliminate, and we
+ try to find a mode which will work for multiple duplicates. */
+
+static enum machine_mode
+cse_cc_succs (basic_block bb, rtx cc_reg, rtx cc_src, bool can_change_mode)
+{
+ bool found_equiv;
+ enum machine_mode mode;
+ unsigned int insn_count;
+ edge e;
+ rtx insns[2];
+ enum machine_mode modes[2];
+ rtx last_insns[2];
+ unsigned int i;
+ rtx newreg;
+ edge_iterator ei;
+
+ /* We expect to have two successors. Look at both before picking
+ the final mode for the comparison. If we have more successors
+ (i.e., some sort of table jump, although that seems unlikely),
+ then we require all beyond the first two to use the same
+ mode. */
+
+ found_equiv = false;
+ mode = GET_MODE (cc_src);
+ insn_count = 0;
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ {
+ rtx insn;
+ rtx end;
+
+ if (e->flags & EDGE_COMPLEX)
+ continue;
+
+ if (EDGE_COUNT (e->dest->preds) != 1
+ || e->dest == EXIT_BLOCK_PTR)
+ continue;
+
+ end = NEXT_INSN (BB_END (e->dest));
+ for (insn = BB_HEAD (e->dest); insn != end; insn = NEXT_INSN (insn))
+ {
+ rtx set;
+
+ if (! INSN_P (insn))
+ continue;
+
+ /* If CC_SRC is modified, we have to stop looking for
+ something which uses it. */
+ if (modified_in_p (cc_src, insn))
+ break;
+
+ /* Check whether INSN sets CC_REG to CC_SRC. */
+ set = single_set (insn);
+ if (set
+ && REG_P (SET_DEST (set))
+ && REGNO (SET_DEST (set)) == REGNO (cc_reg))
+ {
+ bool found;
+ enum machine_mode set_mode;
+ enum machine_mode comp_mode;
+
+ found = false;
+ set_mode = GET_MODE (SET_SRC (set));
+ comp_mode = set_mode;
+ if (rtx_equal_p (cc_src, SET_SRC (set)))
+ found = true;
+ else if (GET_CODE (cc_src) == COMPARE
+ && GET_CODE (SET_SRC (set)) == COMPARE
+ && mode != set_mode
+ && rtx_equal_p (XEXP (cc_src, 0),
+ XEXP (SET_SRC (set), 0))
+ && rtx_equal_p (XEXP (cc_src, 1),
+ XEXP (SET_SRC (set), 1)))
+
+ {
+ comp_mode = targetm.cc_modes_compatible (mode, set_mode);
+ if (comp_mode != VOIDmode
+ && (can_change_mode || comp_mode == mode))
+ found = true;
+ }
+
+ if (found)
+ {
+ found_equiv = true;
+ if (insn_count < ARRAY_SIZE (insns))
+ {
+ insns[insn_count] = insn;
+ modes[insn_count] = set_mode;
+ last_insns[insn_count] = end;
+ ++insn_count;
+
+ if (mode != comp_mode)
+ {
+ gcc_assert (can_change_mode);
+ mode = comp_mode;
+
+ /* The modified insn will be re-recognized later. */
+ PUT_MODE (cc_src, mode);
+ }
+ }
+ else
+ {
+ if (set_mode != mode)
+ {
+ /* We found a matching expression in the
+ wrong mode, but we don't have room to
+ store it in the array. Punt. This case
+ should be rare. */
+ break;
+ }
+ /* INSN sets CC_REG to a value equal to CC_SRC
+ with the right mode. We can simply delete
+ it. */
+ delete_insn (insn);
+ }
+
+ /* We found an instruction to delete. Keep looking,
+ in the hopes of finding a three-way jump. */
+ continue;
+ }
+
+ /* We found an instruction which sets the condition
+ code, so don't look any farther. */
+ break;
+ }
+
+ /* If INSN sets CC_REG in some other way, don't look any
+ farther. */
+ if (reg_set_p (cc_reg, insn))
+ break;
+ }
+
+ /* If we fell off the bottom of the block, we can keep looking
+ through successors. We pass CAN_CHANGE_MODE as false because
+ we aren't prepared to handle compatibility between the
+ further blocks and this block. */
+ if (insn == end)
+ {
+ enum machine_mode submode;
+
+ submode = cse_cc_succs (e->dest, cc_reg, cc_src, false);
+ if (submode != VOIDmode)
+ {
+ gcc_assert (submode == mode);
+ found_equiv = true;
+ can_change_mode = false;
+ }
+ }
+ }
+
+ if (! found_equiv)
+ return VOIDmode;
+
+ /* Now INSN_COUNT is the number of instructions we found which set
+ CC_REG to a value equivalent to CC_SRC. The instructions are in
+ INSNS. The modes used by those instructions are in MODES. */
+
+ newreg = NULL_RTX;
+ for (i = 0; i < insn_count; ++i)
+ {
+ if (modes[i] != mode)
+ {
+ /* We need to change the mode of CC_REG in INSNS[i] and
+ subsequent instructions. */
+ if (! newreg)
+ {
+ if (GET_MODE (cc_reg) == mode)
+ newreg = cc_reg;
+ else
+ newreg = gen_rtx_REG (mode, REGNO (cc_reg));
+ }
+ cse_change_cc_mode_insns (NEXT_INSN (insns[i]), last_insns[i],
+ newreg);
+ }
+
+ delete_insn (insns[i]);
+ }
+
+ return mode;
+}
+
+/* If we have a fixed condition code register (or two), walk through
+ the instructions and try to eliminate duplicate assignments. */
+
+static void
+cse_condition_code_reg (void)
+{
+ unsigned int cc_regno_1;
+ unsigned int cc_regno_2;
+ rtx cc_reg_1;
+ rtx cc_reg_2;
+ basic_block bb;
+
+ if (! targetm.fixed_condition_code_regs (&cc_regno_1, &cc_regno_2))
+ return;
+
+ cc_reg_1 = gen_rtx_REG (CCmode, cc_regno_1);
+ if (cc_regno_2 != INVALID_REGNUM)
+ cc_reg_2 = gen_rtx_REG (CCmode, cc_regno_2);
+ else
+ cc_reg_2 = NULL_RTX;
+
+ FOR_EACH_BB (bb)
+ {
+ rtx last_insn;
+ rtx cc_reg;
+ rtx insn;
+ rtx cc_src_insn;
+ rtx cc_src;
+ enum machine_mode mode;
+ enum machine_mode orig_mode;
+
+ /* Look for blocks which end with a conditional jump based on a
+ condition code register. Then look for the instruction which
+ sets the condition code register. Then look through the
+ successor blocks for instructions which set the condition
+ code register to the same value. There are other possible
+ uses of the condition code register, but these are by far the
+ most common and the ones which we are most likely to be able
+ to optimize. */
+
+ last_insn = BB_END (bb);
+ if (!JUMP_P (last_insn))
+ continue;
+
+ if (reg_referenced_p (cc_reg_1, PATTERN (last_insn)))
+ cc_reg = cc_reg_1;
+ else if (cc_reg_2 && reg_referenced_p (cc_reg_2, PATTERN (last_insn)))
+ cc_reg = cc_reg_2;
+ else
+ continue;
+
+ cc_src_insn = NULL_RTX;
+ cc_src = NULL_RTX;
+ for (insn = PREV_INSN (last_insn);
+ insn && insn != PREV_INSN (BB_HEAD (bb));
+ insn = PREV_INSN (insn))
+ {
+ rtx set;
+
+ if (! INSN_P (insn))
+ continue;
+ set = single_set (insn);
+ if (set
+ && REG_P (SET_DEST (set))
+ && REGNO (SET_DEST (set)) == REGNO (cc_reg))
+ {
+ cc_src_insn = insn;
+ cc_src = SET_SRC (set);
+ break;
+ }
+ else if (reg_set_p (cc_reg, insn))
+ break;
+ }
+
+ if (! cc_src_insn)
+ continue;
+
+ if (modified_between_p (cc_src, cc_src_insn, NEXT_INSN (last_insn)))
+ continue;
+
+ /* Now CC_REG is a condition code register used for a
+ conditional jump at the end of the block, and CC_SRC, in
+ CC_SRC_INSN, is the value to which that condition code
+ register is set, and CC_SRC is still meaningful at the end of
+ the basic block. */
+
+ orig_mode = GET_MODE (cc_src);
+ mode = cse_cc_succs (bb, cc_reg, cc_src, true);
+ if (mode != VOIDmode)
+ {
+ gcc_assert (mode == GET_MODE (cc_src));
+ if (mode != orig_mode)
+ {
+ rtx newreg = gen_rtx_REG (mode, REGNO (cc_reg));
+
+ cse_change_cc_mode_insn (cc_src_insn, newreg);
+
+ /* Do the same in the following insns that use the
+ current value of CC_REG within BB. */
+ cse_change_cc_mode_insns (NEXT_INSN (cc_src_insn),
+ NEXT_INSN (last_insn),
+ newreg);
+ }
+ }
+ }
+}
+
+
+/* Perform common subexpression elimination. Nonzero value from
+ `cse_main' means that jumps were simplified and some code may now
+ be unreachable, so do jump optimization again. */
+static bool
+gate_handle_cse (void)
+{
+ return optimize > 0;
+}
+
+static unsigned int
+rest_of_handle_cse (void)
+{
+ int tem;
+
+ if (dump_file)
+ dump_flow_info (dump_file, dump_flags);
+
+ reg_scan (get_insns (), max_reg_num ());
+
+ tem = cse_main (get_insns (), max_reg_num ());
+ if (tem)
+ rebuild_jump_labels (get_insns ());
+ if (purge_all_dead_edges ())
+ delete_unreachable_blocks ();
+
+ delete_trivially_dead_insns (get_insns (), max_reg_num ());
+
+ /* If we are not running more CSE passes, then we are no longer
+ expecting CSE to be run. But always rerun it in a cheap mode. */
+ cse_not_expected = !flag_rerun_cse_after_loop && !flag_gcse;
+
+ if (tem)
+ delete_dead_jumptables ();
+
+ if (tem || optimize > 1)
+ cleanup_cfg (CLEANUP_EXPENSIVE);
+ return 0;
+}
+
+struct tree_opt_pass pass_cse =
+{
+ "cse1", /* name */
+ gate_handle_cse, /* gate */
+ rest_of_handle_cse, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_CSE, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_dump_func |
+ TODO_ggc_collect, /* todo_flags_finish */
+ 's' /* letter */
+};
+
+
+static bool
+gate_handle_cse2 (void)
+{
+ return optimize > 0 && flag_rerun_cse_after_loop;
+}
+
+/* Run second CSE pass after loop optimizations. */
+static unsigned int
+rest_of_handle_cse2 (void)
+{
+ int tem;
+
+ if (dump_file)
+ dump_flow_info (dump_file, dump_flags);
+
+ tem = cse_main (get_insns (), max_reg_num ());
+
+ /* Run a pass to eliminate duplicated assignments to condition code
+ registers. We have to run this after bypass_jumps, because it
+ makes it harder for that pass to determine whether a jump can be
+ bypassed safely. */
+ cse_condition_code_reg ();
+
+ purge_all_dead_edges ();
+ delete_trivially_dead_insns (get_insns (), max_reg_num ());
+
+ if (tem)
+ {
+ timevar_push (TV_JUMP);
+ rebuild_jump_labels (get_insns ());
+ delete_dead_jumptables ();
+ cleanup_cfg (CLEANUP_EXPENSIVE);
+ timevar_pop (TV_JUMP);
+ }
+ reg_scan (get_insns (), max_reg_num ());
+ cse_not_expected = 1;
+ return 0;
+}
+
+
+struct tree_opt_pass pass_cse2 =
+{
+ "cse2", /* name */
+ gate_handle_cse2, /* gate */
+ rest_of_handle_cse2, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_CSE2, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_dump_func |
+ TODO_ggc_collect, /* todo_flags_finish */
+ 't' /* letter */
+};
+