]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/cse.c
middle-end/115110 - Fix view_converted_memref_p
[thirdparty/gcc.git] / gcc / cse.c
diff --git a/gcc/cse.c b/gcc/cse.c
deleted file mode 100644 (file)
index df191d5..0000000
--- a/gcc/cse.c
+++ /dev/null
@@ -1,7803 +0,0 @@
-/* Common subexpression elimination for GNU compiler.
-   Copyright (C) 1987-2021 Free Software Foundation, Inc.
-
-This file is part of GCC.
-
-GCC is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 3, or (at your option) any later
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING3.  If not see
-<http://www.gnu.org/licenses/>.  */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "backend.h"
-#include "target.h"
-#include "rtl.h"
-#include "tree.h"
-#include "cfghooks.h"
-#include "df.h"
-#include "memmodel.h"
-#include "tm_p.h"
-#include "insn-config.h"
-#include "regs.h"
-#include "emit-rtl.h"
-#include "recog.h"
-#include "cfgrtl.h"
-#include "cfganal.h"
-#include "cfgcleanup.h"
-#include "alias.h"
-#include "toplev.h"
-#include "rtlhooks-def.h"
-#include "tree-pass.h"
-#include "dbgcnt.h"
-#include "rtl-iter.h"
-#include "regs.h"
-#include "function-abi.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_insn *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;
-
-/* 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 current and last value 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 this_insn_cc0, prev_insn_cc0;
-static machine_mode this_insn_cc0_mode, prev_insn_cc0_mode;
-
-/* Insn being scanned.  */
-
-static rtx_insn *this_insn;
-static bool optimize_this_for_speed_p;
-
-/* 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_extended_basic_block.  We increment this variable at the beginning of
-   the current run of cse_extended_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_extended_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;
-
-/* True if CSE has altered the CFG.  */
-static bool cse_cfg_altered;
-
-/* True if CSE has altered conditional jump insns in such a way
-   that jump optimization should be redone.  */
-static bool cse_jumps_altered;
-
-/* True if we put a LABEL_REF into the hash table for an INSN
-   without a REG_LABEL_OPERAND, we have to rerun jump after CSE
-   to put in the note.  */
-static bool 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, MODE)                                                  \
-  (REG_P (X) ? 0 : notreg_cost (X, MODE, SET, 1))
-#define COST_IN(X, MODE, OUTER, OPNO)                                  \
-  (REG_P (X) ? 0 : notreg_cost (X, MODE, OUTER, OPNO))
-
-/* 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)
-
-/* Compare table_elt X and Y and return true iff X is cheaper than Y.  */
-
-#define CHEAPER(X, Y) \
- (preferable ((X)->cost, (X)->regcost, (Y)->cost, (Y)->regcost) < 0)
-
-static struct table_elt *table[HASH_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;
-
-/* Trace a patch through the CFG.  */
-
-struct branch_path
-{
-  /* The basic block for this path entry.  */
-  basic_block bb;
-};
-
-/* This data describes a block that will be processed by
-   cse_extended_basic_block.  */
-
-struct cse_basic_block_data
-{
-  /* Total number of SETs in block.  */
-  int nsets;
-  /* Size of current branch path, if any.  */
-  int path_size;
-  /* Current path, indicating which basic_blocks will be processed.  */
-  struct branch_path *path;
-};
-
-
-/* Pointers to the live in/live out bitmaps for the boundaries of the
-   current EBB.  */
-static bitmap cse_ebb_live_in, cse_ebb_live_out;
-
-/* A simple bitmap to track which basic blocks have been visited
-   already as part of an already processed extended basic block.  */
-static sbitmap cse_visited_basic_blocks;
-
-static bool fixed_base_plus_p (rtx x);
-static int notreg_cost (rtx, machine_mode, enum rtx_code, int);
-static int preferable (int, int, int, int);
-static void new_basic_block (void);
-static void make_new_qty (unsigned int, 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 void remove_pseudo_from_table (rtx, unsigned);
-static struct table_elt *lookup (rtx, unsigned, machine_mode);
-static struct table_elt *lookup_for_remove (rtx, unsigned, machine_mode);
-static rtx lookup_as_function (rtx, enum rtx_code);
-static struct table_elt *insert_with_costs (rtx, struct table_elt *, unsigned,
-                                           machine_mode, int, int);
-static struct table_elt *insert (rtx, struct table_elt *, unsigned,
-                                machine_mode);
-static void merge_equiv_classes (struct table_elt *, struct table_elt *);
-static void invalidate (rtx, machine_mode);
-static void remove_invalid_refs (unsigned int);
-static void remove_invalid_subreg_refs (unsigned int, poly_uint64,
-                                       machine_mode);
-static void rehash_using_reg (rtx);
-static void invalidate_memory (void);
-static rtx use_related_value (rtx, struct table_elt *);
-
-static inline unsigned canon_hash (rtx, machine_mode);
-static inline unsigned safe_hash (rtx, machine_mode);
-static inline unsigned hash_rtx_string (const char *);
-
-static rtx canon_reg (rtx, rtx_insn *);
-static enum rtx_code find_comparison_args (enum rtx_code, rtx *, rtx *,
-                                          machine_mode *,
-                                          machine_mode *);
-static rtx fold_rtx (rtx, rtx_insn *);
-static rtx equiv_constant (rtx);
-static void record_jump_equiv (rtx_insn *, bool);
-static void record_jump_cond (enum rtx_code, machine_mode, rtx, rtx,
-                             int);
-static void cse_insn (rtx_insn *);
-static void cse_prescan_path (struct cse_basic_block_data *);
-static void invalidate_from_clobbers (rtx_insn *);
-static void invalidate_from_sets_and_clobbers (rtx_insn *);
-static void cse_extended_basic_block (struct cse_basic_block_data *);
-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 void flush_hash_table (void);
-static bool insn_live_p (rtx_insn *, int *);
-static bool set_live_p (rtx, rtx_insn *, int *);
-static void cse_change_cc_mode_insn (rtx_insn *, rtx);
-static void cse_change_cc_mode_insns (rtx_insn *, rtx_insn *, rtx);
-static machine_mode cse_cc_succs (basic_block, basic_block, rtx, rtx,
-                                      bool);
-\f
-
-#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;
-\f
-/* Nonzero if X has the form (PLUS frame-pointer integer).  */
-
-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;
-      return false;
-
-    case PLUS:
-      if (!CONST_INT_P (XEXP (x, 1)))
-       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.  */
-DEBUG_FUNCTION 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");
-    }
-}
-
-/* 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 (const_rtx x)
-{
-  int cost = 0;
-  subrtx_iterator::array_type array;
-  FOR_EACH_SUBRTX (iter, array, x, NONCONST)
-    {
-      const_rtx x = *iter;
-      if (REG_P (x))
-       {
-         unsigned int regno = REGNO (x);
-         if (!CHEAP_REGNO (regno))
-           {
-             if (regno < FIRST_PSEUDO_REGISTER)
-               {
-                 if (targetm.small_register_classes_for_mode_p (GET_MODE (x)))
-                   return MAX_COST;
-                 cost += 2;
-               }
-             else
-               cost += 1;
-           }
-       }
-    }
-  return cost;
-}
-
-/* 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, machine_mode mode, enum rtx_code outer, int opno)
-{
-  scalar_int_mode int_mode, inner_mode;
-  return ((GET_CODE (x) == SUBREG
-          && REG_P (SUBREG_REG (x))
-          && is_int_mode (mode, &int_mode)
-          && is_int_mode (GET_MODE (SUBREG_REG (x)), &inner_mode)
-          && GET_MODE_SIZE (int_mode) < GET_MODE_SIZE (inner_mode)
-          && subreg_lowpart_p (x)
-          && TRULY_NOOP_TRUNCATION_MODES_P (int_mode, inner_mode))
-         ? 0
-         : rtx_cost (x, mode, outer, opno, optimize_this_for_speed_p) * 2);
-}
-
-\f
-/* 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.  */
-      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;
-       }
-    }
-
-  prev_insn_cc0 = 0;
-}
-
-/* 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, 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;
-  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_reg, unsigned int old_reg)
-{
-  unsigned int lastr, firstr;
-  int q = REG_QTY (old_reg);
-  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));
-
-  REG_QTY (new_reg) = 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_reg >= FIRST_PSEUDO_REGISTER || REGNO_REG_CLASS (new_reg) != NO_REGS)
-      && ((new_reg < FIRST_PSEUDO_REGISTER && FIXED_REGNO_P (new_reg))
-         || (new_reg >= FIRST_PSEUDO_REGISTER
-             && (firstr < FIRST_PSEUDO_REGISTER
-                 || (bitmap_bit_p (cse_ebb_live_out, new_reg)
-                     && !bitmap_bit_p (cse_ebb_live_out, firstr))
-                 || (bitmap_bit_p (cse_ebb_live_in, new_reg)
-                     && !bitmap_bit_p (cse_ebb_live_in, firstr))))))
-    {
-      reg_eqv_table[firstr].prev = new_reg;
-      reg_eqv_table[new_reg].next = firstr;
-      reg_eqv_table[new_reg].prev = -1;
-      ent->first_reg = new_reg;
-    }
-  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_reg >= FIRST_PSEUDO_REGISTER)
-       lastr = reg_eqv_table[lastr].prev;
-      reg_eqv_table[new_reg].next = reg_eqv_table[lastr].next;
-      if (reg_eqv_table[lastr].next >= 0)
-       reg_eqv_table[reg_eqv_table[lastr].next].prev = new_reg;
-      else
-       qty_table[q].last_reg = new_reg;
-      reg_eqv_table[lastr].next = new_reg;
-      reg_eqv_table[new_reg].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 = END_REGNO (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);
-}
-\f
-
-/* Compute upper and lower anchors for CST.  Also compute the offset of CST
-   from these anchors/bases such that *_BASE + *_OFFS = CST.  Return false iff
-   CST is equal to an anchor.  */
-
-static bool
-compute_const_anchors (rtx cst,
-                      HOST_WIDE_INT *lower_base, HOST_WIDE_INT *lower_offs,
-                      HOST_WIDE_INT *upper_base, HOST_WIDE_INT *upper_offs)
-{
-  HOST_WIDE_INT n = INTVAL (cst);
-
-  *lower_base = n & ~(targetm.const_anchor - 1);
-  if (*lower_base == n)
-    return false;
-
-  *upper_base =
-    (n + (targetm.const_anchor - 1)) & ~(targetm.const_anchor - 1);
-  *upper_offs = n - *upper_base;
-  *lower_offs = n - *lower_base;
-  return true;
-}
-
-/* Insert the equivalence between ANCHOR and (REG + OFF) in mode MODE.  */
-
-static void
-insert_const_anchor (HOST_WIDE_INT anchor, rtx reg, HOST_WIDE_INT offs,
-                    machine_mode mode)
-{
-  struct table_elt *elt;
-  unsigned hash;
-  rtx anchor_exp;
-  rtx exp;
-
-  anchor_exp = GEN_INT (anchor);
-  hash = HASH (anchor_exp, mode);
-  elt = lookup (anchor_exp, hash, mode);
-  if (!elt)
-    elt = insert (anchor_exp, NULL, hash, mode);
-
-  exp = plus_constant (mode, reg, offs);
-  /* REG has just been inserted and the hash codes recomputed.  */
-  mention_regs (exp);
-  hash = HASH (exp, mode);
-
-  /* Use the cost of the register rather than the whole expression.  When
-     looking up constant anchors we will further offset the corresponding
-     expression therefore it does not make sense to prefer REGs over
-     reg-immediate additions.  Prefer instead the oldest expression.  Also
-     don't prefer pseudos over hard regs so that we derive constants in
-     argument registers from other argument registers rather than from the
-     original pseudo that was used to synthesize the constant.  */
-  insert_with_costs (exp, elt, hash, mode, COST (reg, mode), 1);
-}
-
-/* The constant CST is equivalent to the register REG.  Create
-   equivalences between the two anchors of CST and the corresponding
-   register-offset expressions using REG.  */
-
-static void
-insert_const_anchors (rtx reg, rtx cst, machine_mode mode)
-{
-  HOST_WIDE_INT lower_base, lower_offs, upper_base, upper_offs;
-
-  if (!compute_const_anchors (cst, &lower_base, &lower_offs,
-                             &upper_base, &upper_offs))
-      return;
-
-  /* Ignore anchors of value 0.  Constants accessible from zero are
-     simple.  */
-  if (lower_base != 0)
-    insert_const_anchor (lower_base, reg, -lower_offs, mode);
-
-  if (upper_base != 0)
-    insert_const_anchor (upper_base, reg, -upper_offs, mode);
-}
-
-/* We need to express ANCHOR_ELT->exp + OFFS.  Walk the equivalence list of
-   ANCHOR_ELT and see if offsetting any of the entries by OFFS would create a
-   valid expression.  Return the cheapest and oldest of such expressions.  In
-   *OLD, return how old the resulting expression is compared to the other
-   equivalent expressions.  */
-
-static rtx
-find_reg_offset_for_const (struct table_elt *anchor_elt, HOST_WIDE_INT offs,
-                          unsigned *old)
-{
-  struct table_elt *elt;
-  unsigned idx;
-  struct table_elt *match_elt;
-  rtx match;
-
-  /* Find the cheapest and *oldest* expression to maximize the chance of
-     reusing the same pseudo.  */
-
-  match_elt = NULL;
-  match = NULL_RTX;
-  for (elt = anchor_elt->first_same_value, idx = 0;
-       elt;
-       elt = elt->next_same_value, idx++)
-    {
-      if (match_elt && CHEAPER (match_elt, elt))
-       return match;
-
-      if (REG_P (elt->exp)
-         || (GET_CODE (elt->exp) == PLUS
-             && REG_P (XEXP (elt->exp, 0))
-             && GET_CODE (XEXP (elt->exp, 1)) == CONST_INT))
-       {
-         rtx x;
-
-         /* Ignore expressions that are no longer valid.  */
-         if (!REG_P (elt->exp) && !exp_equiv_p (elt->exp, elt->exp, 1, false))
-           continue;
-
-         x = plus_constant (GET_MODE (elt->exp), elt->exp, offs);
-         if (REG_P (x)
-             || (GET_CODE (x) == PLUS
-                 && IN_RANGE (INTVAL (XEXP (x, 1)),
-                              -targetm.const_anchor,
-                              targetm.const_anchor - 1)))
-           {
-             match = x;
-             match_elt = elt;
-             *old = idx;
-           }
-       }
-    }
-
-  return match;
-}
-
-/* Try to express the constant SRC_CONST using a register+offset expression
-   derived from a constant anchor.  Return it if successful or NULL_RTX,
-   otherwise.  */
-
-static rtx
-try_const_anchors (rtx src_const, machine_mode mode)
-{
-  struct table_elt *lower_elt, *upper_elt;
-  HOST_WIDE_INT lower_base, lower_offs, upper_base, upper_offs;
-  rtx lower_anchor_rtx, upper_anchor_rtx;
-  rtx lower_exp = NULL_RTX, upper_exp = NULL_RTX;
-  unsigned lower_old, upper_old;
-
-  /* CONST_INT is used for CC modes, but we should leave those alone.  */
-  if (GET_MODE_CLASS (mode) == MODE_CC)
-    return NULL_RTX;
-
-  gcc_assert (SCALAR_INT_MODE_P (mode));
-  if (!compute_const_anchors (src_const, &lower_base, &lower_offs,
-                             &upper_base, &upper_offs))
-    return NULL_RTX;
-
-  lower_anchor_rtx = GEN_INT (lower_base);
-  upper_anchor_rtx = GEN_INT (upper_base);
-  lower_elt = lookup (lower_anchor_rtx, HASH (lower_anchor_rtx, mode), mode);
-  upper_elt = lookup (upper_anchor_rtx, HASH (upper_anchor_rtx, mode), mode);
-
-  if (lower_elt)
-    lower_exp = find_reg_offset_for_const (lower_elt, lower_offs, &lower_old);
-  if (upper_elt)
-    upper_exp = find_reg_offset_for_const (upper_elt, upper_offs, &upper_old);
-
-  if (!lower_exp)
-    return upper_exp;
-  if (!upper_exp)
-    return lower_exp;
-
-  /* Return the older expression.  */
-  return (upper_old > lower_old ? upper_exp : lower_exp);
-}
-\f
-/* 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;
-}
-
-/* Same as above, but X is a pseudo-register.  */
-
-static void
-remove_pseudo_from_table (rtx x, unsigned int hash)
-{
-  struct table_elt *elt;
-
-  /* Because a pseudo-register can be referenced in more than one
-     mode, we might have to remove more than one table entry.  */
-  while ((elt = lookup_for_remove (x, hash, VOIDmode)))
-    remove_from_table (elt, hash);
-}
-
-/* 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, 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, 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 (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).  COST is the code of X and reg_cost is the
-   cost of registers in X.  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.  */
-
-static struct table_elt *
-insert_with_costs (rtx x, struct table_elt *classp, unsigned int hash,
-                  machine_mode mode, int cost, int reg_cost)
-{
-  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)
-    add_to_hard_reg_set (&hard_regs_in_table, GET_MODE (x), REGNO (x));
-
-  /* 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;
-  elt->regcost = reg_cost;
-  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));
-
-  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;
-       }
-    }
-
-  return elt;
-}
-
-/* Wrap insert_with_costs by passing the default costs.  */
-
-static struct table_elt *
-insert (rtx x, struct table_elt *classp, unsigned int hash,
-       machine_mode mode)
-{
-  return insert_with_costs (x, classp, hash, mode,
-                           COST (x, mode), approx_reg_cost (x));
-}
-
-\f
-/* 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_elt;
-
-  /* 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;
-      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));
-           }
-
-         if (REG_P (exp) && REGNO (exp) >= FIRST_PSEUDO_REGISTER)
-           remove_pseudo_from_table (exp, hash);
-         else
-           remove_from_table (elt, hash);
-
-         if (insert_regs (exp, class1, 0) || need_rehash)
-           {
-             rehash_using_reg (exp);
-             hash = HASH (exp, mode);
-           }
-         new_elt = insert (exp, class1, hash, mode);
-         new_elt->in_memory = hash_arg_in_memory;
-         if (GET_CODE (exp) == ASM_OPERANDS && elt->cost == MAX_COST)
-           new_elt->cost = MAX_COST;
-       }
-    }
-}
-\f
-/* 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);
-      }
-}
-\f
-/* Check whether an anti dependence exists between X and EXP.  MODE and
-   ADDR are as for canon_anti_dependence.  */
-
-static bool
-check_dependence (const_rtx x, rtx exp, machine_mode mode, rtx addr)
-{
-  subrtx_iterator::array_type array;
-  FOR_EACH_SUBRTX (iter, array, x, NONCONST)
-    {
-      const_rtx x = *iter;
-      if (MEM_P (x) && canon_anti_dependence (x, true, exp, mode, addr))
-       return true;
-    }
-  return false;
-}
-
-/* Remove from the hash table, or mark as invalid, all expressions whose
-   values could be altered by storing in register X.  */
-
-static void
-invalidate_reg (rtx x)
-{
-  gcc_assert (GET_CODE (x) == 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)
-    remove_pseudo_from_table (x, hash);
-  else
-    {
-      HOST_WIDE_INT in_table = TEST_HARD_REG_BIT (hard_regs_in_table, regno);
-      unsigned int endregno = END_REGNO (x);
-      unsigned int 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;
-
-             unsigned int tregno = REGNO (p->exp);
-             unsigned int tendregno = END_REGNO (p->exp);
-             if (tendregno > regno && tregno < endregno)
-               remove_from_table (p, hash);
-           }
-    }
-}
-
-/* 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, machine_mode full_mode)
-{
-  int i;
-  struct table_elt *p;
-  rtx addr;
-
-  switch (GET_CODE (x))
-    {
-    case REG:
-      invalidate_reg (x);
-      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)
-               {
-                 /* 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);
-                 if (check_dependence (p->canon_exp, x, full_mode, addr))
-                   remove_from_table (p, i);
-               }
-           }
-       }
-      return;
-
-    default:
-      gcc_unreachable ();
-    }
-}
-
-/* Invalidate DEST.  Used when DEST is not going to be added
-   into the hash table for some reason, e.g. do_not_record
-   flagged on it.  */
-
-static void
-invalidate_dest (rtx dest)
-{
-  if (REG_P (dest)
-      || GET_CODE (dest) == SUBREG
-      || 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));
-}
-\f
-/* 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, p->exp))
-         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, poly_uint64 offset,
-                           machine_mode mode)
-{
-  unsigned int i;
-  struct table_elt *p, *next;
-
-  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
-               || ranges_maybe_overlap_p (SUBREG_BYTE (exp),
-                                          GET_MODE_SIZE (GET_MODE (exp)),
-                                          offset, GET_MODE_SIZE (mode)))
-           && refers_to_regno_p (regno, p->exp))
-         remove_from_table (p, i);
-      }
-}
-\f
-/* 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;
-         }
-      }
-}
-\f
-/* Remove from the hash table any expression that is a call-clobbered
-   register in INSN.  Also update their TICK values.  */
-
-static void
-invalidate_for_call (rtx_insn *insn)
-{
-  unsigned int regno;
-  unsigned hash;
-  struct table_elt *p, *next;
-  int in_table = 0;
-  hard_reg_set_iterator hrsi;
-
-  /* Go through all the hard registers.  For each that might be clobbered
-     in call insn 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.
-
-     ??? We could be more precise for partially-clobbered registers,
-     and only invalidate values that actually occupy the clobbered part
-     of the registers.  It doesn't seem worth the effort though, since
-     we shouldn't see this situation much before RA.  Whatever choice
-     we make here has to be consistent with the table walk below,
-     so any change to this test will require a change there too.  */
-  HARD_REG_SET callee_clobbers
-    = insn_callee_abi (insn).full_and_partial_reg_clobbers ();
-  EXECUTE_IF_SET_IN_HARD_REG_SET (callee_clobbers, 0, regno, hrsi)
-    {
-      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;
-
-         /* This must use the same test as above rather than the
-            more accurate clobbers_reg_p.  */
-         if (overlaps_hard_reg_set_p (callee_clobbers, GET_MODE (p->exp),
-                                      REGNO (p->exp)))
-           remove_from_table (p, hash);
-       }
-}
-\f
-/* 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->mode, q->exp, offset);
-}
-\f
-
-/* 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;
-}
-
-/* Same as hash_rtx, but call CB on each rtx if it is not NULL.
-   When the callback returns true, we continue with the new rtx.  */
-
-unsigned
-hash_rtx_cb (const_rtx x, machine_mode mode,
-             int *do_not_record_p, int *hash_arg_in_memory_p,
-             bool have_reg_qty, hash_rtx_callback_function cb)
-{
-  int i, j;
-  unsigned hash = 0;
-  enum rtx_code code;
-  const char *fmt;
-  machine_mode newmode;
-  rtx newx;
-
-  /* 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;
-
-  /* Invoke the callback first.  */
-  if (cb != NULL
-      && ((*cb) (x, mode, &newx, &newmode)))
-    {
-      hash += hash_rtx_cb (newx, newmode, do_not_record_p,
-                           hash_arg_in_memory_p, have_reg_qty, cb);
-      return hash;
-    }
-
-  code = GET_CODE (x);
-  switch (code)
-    {
-    case REG:
-      {
-       unsigned int regno = REGNO (x);
-
-       if (do_not_record_p && !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 TARGET_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 (targetm.small_register_classes_for_mode_p (GET_MODE (x)))
-             record = false;
-           else if (targetm.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))
-                    + (constant_lower_bound (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_WIDE_INT:
-      for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
-       hash += CONST_WIDE_INT_ELT (x, i);
-      return hash;
-
-    case CONST_POLY_INT:
-      {
-       inchash::hash h;
-       h.add_int (hash);
-       for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
-         h.add_wide_int (CONST_POLY_INT_COEFFS (x)[i]);
-       return h.end ();
-      }
-
-    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 (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (x) == VOIDmode)
-       hash += ((unsigned int) CONST_DOUBLE_LOW (x)
-                + (unsigned int) CONST_DOUBLE_HIGH (x));
-      else
-       hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
-      return hash;
-
-    case CONST_FIXED:
-      hash += (unsigned int) code + (unsigned int) GET_MODE (x);
-      hash += fixed_hash (CONST_FIXED_VALUE (x));
-      return hash;
-
-    case CONST_VECTOR:
-      {
-       int units;
-       rtx elt;
-
-       units = const_vector_encoded_nelts (x);
-
-       for (i = 0; i < units; ++i)
-         {
-           elt = CONST_VECTOR_ENCODED_ELT (x, i);
-           hash += hash_rtx_cb (elt, GET_MODE (elt),
-                                 do_not_record_p, hash_arg_in_memory_p,
-                                 have_reg_qty, cb);
-         }
-
-       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 (label_ref_label (x)));
-      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 (do_not_record_p && (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:
-      if (do_not_record_p) {
-        *do_not_record_p = 1;
-        return 0;
-      }
-      else
-        return hash;
-      break;
-
-    case ASM_OPERANDS:
-      if (do_not_record_p && 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_cb (ASM_OPERANDS_INPUT (x, i),
-                                        GET_MODE (ASM_OPERANDS_INPUT (x, i)),
-                                        do_not_record_p, hash_arg_in_memory_p,
-                                        have_reg_qty, cb)
-                          + 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_cb (XEXP (x, i), VOIDmode, do_not_record_p,
-                               hash_arg_in_memory_p,
-                               have_reg_qty, cb);
-         break;
-
-       case 'E':
-         for (j = 0; j < XVECLEN (x, i); j++)
-           hash += hash_rtx_cb (XVECEXP (x, i, j), VOIDmode, do_not_record_p,
-                                 hash_arg_in_memory_p,
-                                 have_reg_qty, cb);
-         break;
-
-       case 's':
-         hash += hash_rtx_string (XSTR (x, i));
-         break;
-
-       case 'i':
-         hash += (unsigned int) XINT (x, i);
-         break;
-
-       case 'p':
-         hash += constant_lower_bound (SUBREG_BYTE (x));
-         break;
-
-       case '0': case 't':
-         /* Unused.  */
-         break;
-
-       default:
-         gcc_unreachable ();
-       }
-    }
-
-  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 MEM_READONLY_P flag 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 (const_rtx x, machine_mode mode, int *do_not_record_p,
-         int *hash_arg_in_memory_p, bool have_reg_qty)
-{
-  return hash_rtx_cb (x, mode, do_not_record_p,
-                      hash_arg_in_memory_p, have_reg_qty, NULL);
-}
-
-/* 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 MEM_READONLY_P flag set.  */
-
-static inline unsigned
-canon_hash (rtx x, 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, machine_mode mode)
-{
-  int dummy_do_not_record;
-  return hash_rtx (x, mode, &dummy_do_not_record, NULL, true);
-}
-\f
-/* 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 (const_rtx x, const_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;
-
-  /* MEMs referring to different address space are not equivalent.  */
-  if (code == MEM && MEM_ADDR_SPACE (x) != MEM_ADDR_SPACE (y))
-    return 0;
-
-  switch (code)
-    {
-    case PC:
-    case CC0:
-    CASE_CONST_UNIQUE:
-      return x == y;
-
-    case CONST_VECTOR:
-      if (!same_vector_encodings_p (x, y))
-       return false;
-      break;
-
-    case LABEL_REF:
-      return label_ref_label (x) == label_ref_label (y);
-
-    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 = END_REGNO (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_eq_p (MEM_ATTRS (x), MEM_ATTRS (y)))
-           return 0;
-
-         /* If we are handling exceptions, we cannot consider two expressions
-            with different trapping status as equivalent, because simple_mem
-            might accept one and reject the other.  */
-         if (cfun->can_throw_non_call_exceptions
-             && (MEM_NOTRAP_P (x) != MEM_NOTRAP_P (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 'p':
-         if (maybe_ne (SUBREG_BYTE (x), SUBREG_BYTE (y)))
-           return 0;
-         break;
-
-       case '0':
-       case 't':
-         break;
-
-       default:
-         gcc_unreachable ();
-       }
-    }
-
-  return 1;
-}
-\f
-/* 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 *insn)
-{
-  if (*xloc)
-    {
-      rtx new_rtx = 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.  */
-      gcc_assert (insn && new_rtx);
-      validate_change (insn, xloc, new_rtx, 1);
-    }
-}
-
-/* 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 *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_ANY:
-    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;
-}
-\f
-/* 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,
-                     machine_mode *pmode1, machine_mode *pmode2)
-{
-  rtx arg1, arg2;
-  hash_set<rtx> *visited = NULL;
-  /* Set nonzero when we find something of interest.  */
-  rtx x = NULL;
-
-  arg1 = *parg1, arg2 = *parg2;
-
-  /* If ARG2 is const0_rtx, see what ARG1 is equivalent to.  */
-
-  while (arg2 == CONST0_RTX (GET_MODE (arg1)))
-    {
-      int reverse_code = 0;
-      struct table_elt *p = 0;
-
-      /* Remember state from previous iteration.  */
-      if (x)
-       {
-         if (!visited)
-           visited = new hash_set<rtx>;
-         visited->add (x);
-         x = 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)
-       {
-         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 it's a comparison we've used before, skip it.  */
-         if (visited && visited->contains (p->exp))
-           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
-                      && val_signbit_known_set_p (inner_mode,
-                                                  STORE_FLAG_VALUE))
-#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
-                       && val_signbit_known_set_p (inner_mode,
-                                                   STORE_FLAG_VALUE))
-#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 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);
-         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);
-
-  if (visited)
-    delete visited;
-  return code;
-}
-\f
-/* 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 changed to a forward-propagated constant.
-
-   If X is a register whose contents are known, we do NOT return
-   those contents here; equiv_constant is called to perform that task.
-   For SUBREGs and MEMs, we do that both here and in equiv_constant.
-
-   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 *insn)
-{
-  enum rtx_code code;
-  machine_mode mode;
-  const char *fmt;
-  int i;
-  rtx new_rtx = 0;
-  int changed = 0;
-  poly_int64 xval;
-
-  /* Operands of X.  */
-  /* Workaround -Wmaybe-uninitialized false positive during
-     profiledbootstrap by initializing them.  */
-  rtx folded_arg0 = NULL_RTX;
-  rtx folded_arg1 = NULL_RTX;
-
-  /* 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.  */
-  machine_mode mode_arg0;
-
-  if (x == 0)
-    return x;
-
-  /* Try to perform some initial simplifications on X.  */
-  code = GET_CODE (x);
-  switch (code)
-    {
-    case MEM:
-    case SUBREG:
-    /* The first operand of a SIGN/ZERO_EXTRACT has a different meaning
-       than it would in other contexts.  Basically its mode does not
-       signify the size of the object read.  That information is carried
-       by size operand.    If we happen to have a MEM of the appropriate
-       mode in our tables with a constant value we could simplify the
-       extraction incorrectly if we allowed substitution of that value
-       for the MEM.   */
-    case ZERO_EXTRACT:
-    case SIGN_EXTRACT:
-      if ((new_rtx = equiv_constant (x)) != NULL_RTX)
-        return new_rtx;
-      return x;
-
-    case CONST:
-    CASE_CONST_ANY:
-    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;
-
-    case CC0:
-      return prev_insn_cc0;
-
-    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);
-       }
-      return x;
-
-    case CALL:
-      if (NO_FUNCTION_CSE && CONSTANT_P (XEXP (XEXP (x, 0), 0)))
-       return x;
-      break;
-
-    /* Anything else goes through the loop below.  */
-    default:
-      break;
-    }
-
-  mode = GET_MODE (x);
-  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 folded_arg = XEXP (x, i), const_arg;
-       machine_mode mode_arg = GET_MODE (folded_arg);
-
-       switch (GET_CODE (folded_arg))
-         {
-         case MEM:
-         case REG:
-         case SUBREG:
-           const_arg = equiv_constant (folded_arg);
-           break;
-
-         case CONST:
-         CASE_CONST_ANY:
-         case SYMBOL_REF:
-         case LABEL_REF:
-           const_arg = folded_arg;
-           break;
-
-         case CC0:
-           /* The cc0-user and cc0-setter may be in different blocks if
-              the cc0-setter potentially traps.  In that case PREV_INSN_CC0
-              will have been cleared as we exited the block with the
-              setter.
-
-              While we could potentially track cc0 in this case, it just
-              doesn't seem to be worth it given that cc0 targets are not
-              terribly common or important these days and trapping math
-              is rarely used.  The combination of those two conditions
-              necessary to trip this situation is exceedingly rare in the
-              real world.  */
-           if (!prev_insn_cc0)
-             {
-               const_arg = NULL_RTX;
-             }
-           else
-             {
-               folded_arg = prev_insn_cc0;
-               mode_arg = prev_insn_cc0_mode;
-               const_arg = equiv_constant (folded_arg);
-             }
-           break;
-
-         default:
-           folded_arg = fold_rtx (folded_arg, insn);
-           const_arg = equiv_constant (folded_arg);
-           break;
-         }
-
-       /* 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 argument and an equivalent constant
-          argument.  */
-       if (const_arg != 0
-           && const_arg != folded_arg
-           && (COST_IN (const_arg, mode_arg, code, i)
-               <= COST_IN (folded_arg, mode_arg, code, i))
-
-           /* 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.  */
-           && (GET_RTX_CLASS (code) != RTX_UNARY
-               || GET_MODE (const_arg) == 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)))
-         folded_arg = const_arg;
-
-       if (folded_arg == XEXP (x, i))
-         continue;
-
-       if (insn == NULL_RTX && !changed)
-         x = copy_rtx (x);
-       changed = 1;
-       validate_unshare_change (insn, &XEXP (x, i), folded_arg, 1);
-      }
-
-  if (changed)
-    {
-      /* Canonicalize X if necessary, and keep const_argN and folded_argN
-        consistent with the order in X.  */
-      if (canonicalize_change_group (insn, x))
-       {
-         std::swap (const_arg0, const_arg1);
-         std::swap (folded_arg0, folded_arg1);
-       }
-
-      apply_change_group ();
-    }
-
-  /* If X is an arithmetic operation, see if we can simplify it.  */
-
-  switch (GET_RTX_CLASS (code))
-    {
-    case RTX_UNARY:
-      {
-       /* We can't simplify extension ops unless we know the
-          original mode.  */
-       if ((code == ZERO_EXTEND || code == SIGN_EXTEND)
-           && mode_arg0 == VOIDmode)
-         break;
-
-       new_rtx = simplify_unary_operation (code, mode,
-                                           const_arg0 ? const_arg0 : folded_arg0,
-                                           mode_arg0);
-      }
-      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, false_rtx;
-         machine_mode mode_arg1;
-
-         if (SCALAR_FLOAT_MODE_P (mode))
-           {
-#ifdef FLOAT_STORE_FLAG_VALUE
-             true_rtx = (const_double_from_real_value
-                         (FLOAT_STORE_FLAG_VALUE (mode), mode));
-#else
-             true_rtx = NULL_RTX;
-#endif
-             false_rtx = CONST0_RTX (mode);
-           }
-         else
-           {
-             true_rtx = const_true_rtx;
-             false_rtx = const0_rtx;
-           }
-
-         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, mode);
-
-                     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, mode);
-                         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 (copy_rtx (cheapest_simplification),
-                                        insn);
-                   }
-               }
-
-             /* See if the two operands are the same.  */
-
-             if ((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))
-               folded_arg1 = folded_arg0;
-
-             /* 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)
-                                 && (REG_QTY (REGNO (folded_arg1)) == ent->comparison_qty))))
-                       {
-                         if (comparison_dominates_p (ent->comparison_code, code))
-                           {
-                             if (true_rtx)
-                               return true_rtx;
-                             else
-                               break;
-                           }
-                         else
-                           return 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 && !const_arg0)
-       {
-         rtx y = lookup_as_function (folded_arg0, IOR);
-         rtx inner_const;
-
-         if (y != 0
-             && (inner_const = equiv_constant (XEXP (y, 1))) != 0
-             && CONST_INT_P (inner_const)
-             && INTVAL (inner_const) != 0)
-           folded_arg0 = gen_rtx_IOR (mode_arg0, XEXP (y, 0), inner_const);
-       }
-
-      {
-       rtx op0 = const_arg0 ? const_arg0 : copy_rtx (folded_arg0);
-       rtx op1 = const_arg1 ? const_arg1 : copy_rtx (folded_arg1);
-       new_rtx = 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
-                 && label_ref_label (XEXP (y, 1)) == label_ref_label (const_arg1))
-               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
-                 && label_ref_label (XEXP (XEXP (y, 0), 1)) == label_ref_label (const_arg1))
-               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
-                 && label_ref_label (XEXP (y, 1)) == label_ref_label (const_arg0))
-               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
-                 && label_ref_label (XEXP (XEXP (y, 0), 1)) == label_ref_label (const_arg0))
-               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 && CONST_INT_P (const_arg1)
-             && 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));
-           }
-         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 && poly_int_rtx_p (const_arg1, &xval))
-           {
-             rtx y = lookup_as_function (XEXP (x, 0), PLUS);
-             if (y && poly_int_rtx_p (XEXP (y, 1)))
-               return fold_rtx (plus_constant (mode, copy_rtx (y), -xval),
-                                NULL);
-           }
-
-         /* 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 && CONST_INT_P (const_arg1))
-           {
-             int is_shift
-               = (code == ASHIFT || code == ASHIFTRT || code == LSHIFTRT);
-             rtx y, inner_const, new_const;
-             rtx canon_const_arg1 = const_arg1;
-             enum rtx_code associate_code;
-
-             if (is_shift
-                 && (INTVAL (const_arg1) >= GET_MODE_UNIT_PRECISION (mode)
-                     || INTVAL (const_arg1) < 0))
-               {
-                 if (SHIFT_COUNT_TRUNCATED)
-                   canon_const_arg1 = gen_int_shift_amount
-                     (mode, (INTVAL (const_arg1)
-                             & (GET_MODE_UNIT_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 || !CONST_INT_P (inner_const))
-               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
-                         && pow2p_hwi (INTVAL (const_arg1)))
-                     || (HAVE_POST_INCREMENT
-                         && pow2p_hwi (INTVAL (const_arg1)))
-                     || (HAVE_PRE_DECREMENT
-                         && pow2p_hwi (- INTVAL (const_arg1)))
-                     || (HAVE_POST_DECREMENT
-                         && pow2p_hwi (- INTVAL (const_arg1)))))
-               break;
-
-             /* ??? Vector mode shifts by scalar
-                shift operand are not supported yet.  */
-             if (is_shift && VECTOR_MODE_P (mode))
-                break;
-
-             if (is_shift
-                 && (INTVAL (inner_const) >= GET_MODE_UNIT_PRECISION (mode)
-                     || INTVAL (inner_const) < 0))
-               {
-                 if (SHIFT_COUNT_TRUNCATED)
-                   inner_const = gen_int_shift_amount
-                     (mode, (INTVAL (inner_const)
-                             & (GET_MODE_UNIT_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,
-                                                    canon_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
-                 && CONST_INT_P (new_const)
-                 && INTVAL (new_const) >= GET_MODE_UNIT_PRECISION (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_shift_amount
-                     (mode, GET_MODE_UNIT_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_rtx = 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_rtx = 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_rtx ? new_rtx : x;
-}
-\f
-/* 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 (GET_CODE (x) == SUBREG)
-    {
-      machine_mode mode = GET_MODE (x);
-      machine_mode imode = GET_MODE (SUBREG_REG (x));
-      rtx new_rtx;
-
-      /* See if we previously assigned a constant value to this SUBREG.  */
-      if ((new_rtx = lookup_as_function (x, CONST_INT)) != 0
-         || (new_rtx = lookup_as_function (x, CONST_WIDE_INT)) != 0
-         || (NUM_POLY_INT_COEFFS > 1
-             && (new_rtx = lookup_as_function (x, CONST_POLY_INT)) != 0)
-          || (new_rtx = lookup_as_function (x, CONST_DOUBLE)) != 0
-          || (new_rtx = lookup_as_function (x, CONST_FIXED)) != 0)
-        return new_rtx;
-
-      /* If we didn't and if doing so makes sense, see if we previously
-        assigned a constant value to the enclosing word mode SUBREG.  */
-      if (known_lt (GET_MODE_SIZE (mode), UNITS_PER_WORD)
-         && known_lt (UNITS_PER_WORD, GET_MODE_SIZE (imode)))
-       {
-         poly_int64 byte = (SUBREG_BYTE (x)
-                            - subreg_lowpart_offset (mode, word_mode));
-         if (known_ge (byte, 0) && multiple_p (byte, UNITS_PER_WORD))
-           {
-             rtx y = gen_rtx_SUBREG (word_mode, SUBREG_REG (x), byte);
-             new_rtx = lookup_as_function (y, CONST_INT);
-             if (new_rtx)
-               return gen_lowpart (mode, new_rtx);
-           }
-       }
-
-      /* Otherwise see if we already have a constant for the inner REG,
-        and if that is enough to calculate an equivalent constant for
-        the subreg.  Note that the upper bits of paradoxical subregs
-        are undefined, so they cannot be said to equal anything.  */
-      if (REG_P (SUBREG_REG (x))
-         && !paradoxical_subreg_p (x)
-         && (new_rtx = equiv_constant (SUBREG_REG (x))) != 0)
-        return simplify_subreg (mode, new_rtx, imode, SUBREG_BYTE (x));
-
-      return 0;
-    }
-
-  /* If X is a MEM, see if it is a constant-pool reference, or look it up in
-     the hash table in case its value was seen before.  */
-
-  if (MEM_P (x))
-    {
-      struct table_elt *elt;
-
-      x = avoid_constant_pool_reference (x);
-      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;
-}
-\f
-/* Given INSN, a jump insn, TAKEN indicates if we are following the
-   "taken" branch.
-
-   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 *insn, bool taken)
-{
-  int cond_known_true;
-  rtx op0, op1;
-  rtx set;
-  machine_mode mode, mode0, mode1;
-  int reversed_nonequality = 0;
-  enum rtx_code code;
-
-  /* Ensure this is the right kind of insn.  */
-  gcc_assert (any_condjump_p (insn));
-
-  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);
-
-  /* On a cc0 target the cc0-setter and cc0-user may end up in different
-     blocks.  When that happens the tracking of the cc0-setter via
-     PREV_INSN_CC0 is spoiled.  That means that fold_rtx may return
-     NULL_RTX.  In those cases, there's nothing to record.  */
-  if (op0 == NULL_RTX || op1 == NULL_RTX)
-    return;
-
-  code = find_comparison_args (code, &op0, &op1, &mode0, &mode1);
-  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 (machine_mode mode, rtx op)
-{
-  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, 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 && paradoxical_subreg_p (op0))
-    {
-      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 && paradoxical_subreg_p (op1))
-    {
-      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
-      && partial_subreg_p (op0)
-      && subreg_lowpart_p (op0))
-    {
-      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
-      && partial_subreg_p (op1)
-      && subreg_lowpart_p (op1))
-    {
-      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);
-}
-\f
-/* CSE processing for one instruction.
-
-   Most "true" common subexpressions are mostly optimized away in GIMPLE,
-   but the few that "leak through" are cleaned up by cse_insn, and complex
-   addressing modes are often formed here.
-
-   The main function is cse_insn, and between here and that function
-   a couple of helper functions is defined to keep the size of cse_insn
-   within reasonable proportions.
-   
-   Data is shared between the main and helper functions via STRUCT SET,
-   that contains all data related for every set in the instruction that
-   is being processed.
-   
-   Note that cse_main processes all sets in the instruction.  Most
-   passes in GCC only process simple SET insns or single_set insns, but
-   CSE processes insns with multiple sets as well.  */
-
-/* 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;
-  /* Hash value of constant equivalent for SET_SRC.  */
-  unsigned src_const_hash;
-  /* A constant equivalent for SET_SRC, if any.  */
-  rtx src_const;
-  /* 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;
-};
-\f
-/* 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.
-   
-   This is the last transformation that cse_insn will try to do.  */
-
-static void
-try_back_substitute_reg (rtx set, rtx_insn *insn)
-{
-  rtx dest = SET_DEST (set);
-  rtx src = SET_SRC (set);
-
-  if (REG_P (dest)
-      && REG_P (src) && ! HARD_REGISTER_P (src)
-      && REGNO_QTY_VALID_P (REGNO (src)))
-    {
-      int src_q = REG_QTY (REGNO (src));
-      struct qty_table_elem *src_ent = &qty_table[src_q];
-
-      if (src_ent->first_reg == REGNO (dest))
-       {
-         /* Scan for the previous nonnote insn, but stop at a basic
-            block boundary.  */
-         rtx_insn *prev = insn;
-         rtx_insn *bb_head = BB_HEAD (BLOCK_FOR_INSN (insn));
-         do
-           {
-             prev = PREV_INSN (prev);
-           }
-         while (prev != bb_head && (NOTE_P (prev) || DEBUG_INSN_P (prev)));
-
-         /* 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 (NONJUMP_INSN_P (prev)
-             && GET_CODE (PATTERN (prev)) == SET
-             && SET_DEST (PATTERN (prev)) == src
-             && ! find_reg_note (prev, REG_EQUIV, NULL_RTX))
-           {
-             rtx note;
-
-             validate_change (prev, &SET_DEST (PATTERN (prev)), dest, 1);
-             validate_change (insn, &SET_DEST (set), src, 1);
-             validate_change (insn, &SET_SRC (set), 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 INSN has a REG_ARGS_SIZE note, move it to PREV.  */
-             note = find_reg_note (insn, REG_ARGS_SIZE, NULL_RTX);
-             if (note != 0)
-               {
-                 remove_note (insn, note);
-                 gcc_assert (!find_reg_note (prev, REG_ARGS_SIZE, NULL_RTX));
-                 set_unique_reg_note (prev, REG_ARGS_SIZE, XEXP (note, 0));
-               }
-           }
-       }
-    }
-}
-\f
-/* Record all the SETs in this instruction into SETS_PTR,
-   and return the number of recorded sets.  */
-static int
-find_sets_in_insn (rtx_insn *insn, struct set **psets)
-{
-  struct set *sets = *psets;
-  int n_sets = 0;
-  rtx x = PATTERN (insn);
-
-  if (GET_CODE (x) == SET)
-    {
-      /* 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.  */
-      else if (GET_CODE (SET_SRC (x)) == CALL)
-       ;
-      else
-       sets[n_sets++].rtl = x;
-    }
-  else if (GET_CODE (x) == PARALLEL)
-    {
-      int i, lim = XVECLEN (x, 0);
-
-      /* Go over the expressions of the PARALLEL in forward order, to
-        put them in the same order in the SETS array.  */
-      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 (SET_DEST (y) == pc_rtx
-                 && GET_CODE (SET_SRC (y)) == LABEL_REF)
-               ;
-             else if (GET_CODE (SET_SRC (y)) == CALL)
-               ;
-             else
-               sets[n_sets++].rtl = y;
-           }
-       }
-    }
-
-  return n_sets;
-}
-\f
-/* Subroutine of canonicalize_insn.  X is an ASM_OPERANDS in INSN.  */
-
-static void
-canon_asm_operands (rtx x, rtx_insn *insn)
-{
-  for (int i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--)
-    {
-      rtx input = ASM_OPERANDS_INPUT (x, i);
-      if (!(REG_P (input) && HARD_REGISTER_P (input)))
-       {
-         input = canon_reg (input, insn);
-         validate_change (insn, &ASM_OPERANDS_INPUT (x, i), input, 1);
-       }
-    }
-}
-
-/* Where possible, substitute every register reference in the N_SETS
-   number of SETS in INSN with the canonical register.
-
-   Register canonicalization propagatest the earliest register (i.e.
-   one that is set before INSN) with the same value.  This is a very
-   useful, simple form of CSE, to clean up warts from expanding GIMPLE
-   to RTL.  For instance, a CONST for an address is usually expanded
-   multiple times to loads into different registers, thus creating many
-   subexpressions of the form:
-
-   (set (reg1) (some_const))
-   (set (mem (... reg1 ...) (thing)))
-   (set (reg2) (some_const))
-   (set (mem (... reg2 ...) (thing)))
-
-   After canonicalizing, the code takes the following form:
-
-   (set (reg1) (some_const))
-   (set (mem (... reg1 ...) (thing)))
-   (set (reg2) (some_const))
-   (set (mem (... reg1 ...) (thing)))
-
-   The set to reg2 is now trivially dead, and the memory reference (or
-   address, or whatever) may be a candidate for further CSEing.
-
-   In this function, the result of apply_change_group can be ignored;
-   see canon_reg.  */
-
-static void
-canonicalize_insn (rtx_insn *insn, struct set **psets, int n_sets)
-{
-  struct set *sets = *psets;
-  rtx tem;
-  rtx x = PATTERN (insn);
-  int i;
-
-  if (CALL_P (insn))
-    {
-      for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
-       if (GET_CODE (XEXP (tem, 0)) != SET)
-         XEXP (tem, 0) = canon_reg (XEXP (tem, 0), insn);
-    }
-
-  if (GET_CODE (x) == SET && GET_CODE (SET_SRC (x)) == CALL)
-    {
-      canon_reg (SET_SRC (x), insn);
-      apply_change_group ();
-      fold_rtx (SET_SRC (x), insn);
-    }
-  else if (GET_CODE (x) == 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 (x, 0)))
-       canon_reg (XEXP (x, 0), insn);
-    }
-  else if (GET_CODE (x) == USE
-          && ! (REG_P (XEXP (x, 0))
-                && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER))
-    /* Canonicalize a USE of a pseudo register or memory location.  */
-    canon_reg (x, insn);
-  else if (GET_CODE (x) == ASM_OPERANDS)
-    canon_asm_operands (x, insn);
-  else if (GET_CODE (x) == CALL)
-    {
-      canon_reg (x, insn);
-      apply_change_group ();
-      fold_rtx (x, insn);
-    }
-  else if (DEBUG_INSN_P (insn))
-    canon_reg (PATTERN (insn), insn);
-  else if (GET_CODE (x) == PARALLEL)
-    {
-      for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
-       {
-         rtx y = XVECEXP (x, 0, i);
-         if (GET_CODE (y) == SET && GET_CODE (SET_SRC (y)) == CALL)
-           {
-             canon_reg (SET_SRC (y), insn);
-             apply_change_group ();
-             fold_rtx (SET_SRC (y), insn);
-           }
-         else if (GET_CODE (y) == CLOBBER)
-           {
-             if (MEM_P (XEXP (y, 0)))
-               canon_reg (XEXP (y, 0), insn);
-           }
-         else if (GET_CODE (y) == USE
-                  && ! (REG_P (XEXP (y, 0))
-                        && REGNO (XEXP (y, 0)) < FIRST_PSEUDO_REGISTER))
-           canon_reg (y, insn);
-         else if (GET_CODE (y) == ASM_OPERANDS)
-           canon_asm_operands (y, insn);
-         else if (GET_CODE (y) == CALL)
-           {
-             canon_reg (y, insn);
-             apply_change_group ();
-             fold_rtx (y, insn);
-           }
-       }
-    }
-
-  if (n_sets == 1 && REG_NOTES (insn) != 0
-      && (tem = find_reg_note (insn, REG_EQUAL, NULL_RTX)) != 0)
-    {
-      /* We potentially will process this insn many times.  Therefore,
-        drop the REG_EQUAL note if it is equal to the SET_SRC of the
-        unique set in INSN.
-
-        Do not do so if the REG_EQUAL note is for a STRICT_LOW_PART,
-        because cse_insn handles those specially.  */
-      if (GET_CODE (SET_DEST (sets[0].rtl)) != STRICT_LOW_PART
-         && rtx_equal_p (XEXP (tem, 0), SET_SRC (sets[0].rtl)))
-       remove_note (insn, tem);
-      else
-       {
-         canon_reg (XEXP (tem, 0), insn);
-         apply_change_group ();
-         XEXP (tem, 0) = fold_rtx (XEXP (tem, 0), insn);
-         df_notes_rescan (insn);
-       }
-    }
-
-  /* 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_rtx = canon_reg (src, insn);
-
-      validate_change (insn, &SET_SRC (sets[i].rtl), new_rtx, 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 ();
-}
-\f
-/* Main function of CSE.
-   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.  */
-
-static void
-cse_insn (rtx_insn *insn)
-{
-  rtx x = PATTERN (insn);
-  int i;
-  rtx tem;
-  int n_sets = 0;
-
-  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;
-
-  if (GET_CODE (x) == SET)
-    sets = XALLOCA (struct set);
-  else if (GET_CODE (x) == PARALLEL)
-    sets = XALLOCAVEC (struct set, XVECLEN (x, 0));
-
-  this_insn = insn;
-  /* Records what this insn does to set CC0.  */
-  this_insn_cc0 = 0;
-  this_insn_cc0_mode = VOIDmode;
-
-  /* Find all regs explicitly clobbered in this insn,
-     to ensure they are not replaced with any other regs
-     elsewhere in this insn.  */
-  invalidate_from_sets_and_clobbers (insn);
-
-  /* Record all the SETs in this instruction.  */
-  n_sets = find_sets_in_insn (insn, &sets);
-
-  /* Substitute the canonical register where possible.  */
-  canonicalize_insn (insn, &sets, n_sets);
-
-  /* If this insn has a REG_EQUAL note, store the equivalent value in SRC_EQV,
-     if different, or if the DEST is a STRICT_LOW_PART/ZERO_EXTRACT.  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)
-    {
-
-      if (GET_CODE (SET_DEST (sets[0].rtl)) != ZERO_EXTRACT
-         && (! rtx_equal_p (XEXP (tem, 0), SET_SRC (sets[0].rtl))
-             || GET_CODE (SET_DEST (sets[0].rtl)) == STRICT_LOW_PART))
-       src_eqv = copy_rtx (XEXP (tem, 0));
-      /* If DEST is of the form ZERO_EXTACT, as in:
-        (set (zero_extract:SI (reg:SI 119)
-                 (const_int 16 [0x10])
-                 (const_int 16 [0x10]))
-             (const_int 51154 [0xc7d2]))
-        REG_EQUAL note will specify the value of register (reg:SI 119) at this
-        point.  Note that this is different from SRC_EQV. We can however
-        calculate SRC_EQV with the position and width of ZERO_EXTRACT.  */
-      else if (GET_CODE (SET_DEST (sets[0].rtl)) == ZERO_EXTRACT
-              && CONST_INT_P (XEXP (tem, 0))
-              && CONST_INT_P (XEXP (SET_DEST (sets[0].rtl), 1))
-              && CONST_INT_P (XEXP (SET_DEST (sets[0].rtl), 2)))
-       {
-         rtx dest_reg = XEXP (SET_DEST (sets[0].rtl), 0);
-         /* This is the mode of XEXP (tem, 0) as well.  */
-         scalar_int_mode dest_mode
-           = as_a <scalar_int_mode> (GET_MODE (dest_reg));
-         rtx width = XEXP (SET_DEST (sets[0].rtl), 1);
-         rtx pos = XEXP (SET_DEST (sets[0].rtl), 2);
-         HOST_WIDE_INT val = INTVAL (XEXP (tem, 0));
-         HOST_WIDE_INT mask;
-         unsigned int shift;
-         if (BITS_BIG_ENDIAN)
-           shift = (GET_MODE_PRECISION (dest_mode)
-                    - INTVAL (pos) - INTVAL (width));
-         else
-           shift = INTVAL (pos);
-         if (INTVAL (width) == HOST_BITS_PER_WIDE_INT)
-           mask = HOST_WIDE_INT_M1;
-         else
-           mask = (HOST_WIDE_INT_1 << INTVAL (width)) - 1;
-         val = (val >> shift) & mask;
-         src_eqv = GEN_INT (val);
-       }
-    }
-
-  /* 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++)
-    {
-      bool repeat = false;
-      bool noop_insn = false;
-      rtx src, dest;
-      rtx src_folded;
-      struct table_elt *elt = 0, *p;
-      machine_mode mode;
-      rtx src_eqv_here;
-      rtx src_const = 0;
-      rtx src_related = 0;
-      bool src_related_is_const_anchor = false;
-      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;
-      scalar_int_mode int_mode;
-
-      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)
-       {
-         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, NULL);
-
-#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 (CONST_INT_P (src)
-             && CONST_INT_P (width)
-             && 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.
-
-        We set DO_NOT_RECORD if the destination has a REG_UNUSED note.
-        This avoids getting the source register into the tables, where it
-        may be invalidated later (via REG_QTY), then trigger an ICE upon
-        re-insertion.
-
-        This is only a problem in multi-set insns.  If it were a single
-        set the dead copy would have been removed.  If the RHS were anything
-        but a simple REG, then we won't call insert_regs and thus there's
-        no potential for triggering the ICE.  */
-      do_not_record = (REG_P (dest)
-                      && REG_P (src)
-                      && find_reg_note (insn, REG_UNUSED, dest));
-      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;
-
-      else if (GET_CODE (src) == ASM_OPERANDS
-              && GET_CODE (x) == PARALLEL)
-       {
-         /* Do not record result of a non-volatile inline asm with
-            more than one result.  */
-         if (n_sets > 1)
-           sets[i].src_volatile = 1;
-
-         int j, lim = XVECLEN (x, 0);
-         for (j = 0; j < lim; j++)
-           {
-             rtx y = XVECEXP (x, 0, j);
-             /* And do not record result of a non-volatile inline asm
-                with "memory" clobber.  */
-             if (GET_CODE (y) == CLOBBER && MEM_P (XEXP (y, 0)))
-               {
-                 sets[i].src_volatile = 1;
-                 break;
-               }
-           }
-       }
-
-#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 (paradoxical_subreg_p (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)
-       elt = lookup (src, sets[i].src_hash, mode);
-
-      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)
-           {
-             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 && CONST_INT_P (src_const)
-         && is_int_mode (mode, &int_mode)
-         && GET_MODE_PRECISION (int_mode) < BITS_PER_WORD)
-       {
-         opt_scalar_int_mode wider_mode_iter;
-         FOR_EACH_WIDER_MODE (wider_mode_iter, int_mode)
-           {
-             scalar_int_mode wider_mode = wider_mode_iter.require ();
-             if (GET_MODE_PRECISION (wider_mode) > BITS_PER_WORD)
-               break;
-
-             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 (int_mode, const_elt->exp);
-                   break;
-                 }
-
-             if (src_related != 0)
-               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
-         && is_a <scalar_int_mode> (mode, &int_mode)
-         && GET_CODE (src) == AND && CONST_INT_P (XEXP (src, 1))
-         && GET_MODE_SIZE (int_mode) < UNITS_PER_WORD)
-       {
-         opt_scalar_int_mode tmode_iter;
-         rtx new_and = gen_rtx_AND (VOIDmode, NULL_RTX, XEXP (src, 1));
-
-         FOR_EACH_WIDER_MODE (tmode_iter, int_mode)
-           {
-             scalar_int_mode tmode = tmode_iter.require ();
-             if (GET_MODE_SIZE (tmode) > UNITS_PER_WORD)
-               break;
-
-             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 (int_mode, larger_elt->exp);
-                       break;
-                     }
-
-                 if (src_related)
-                   break;
-               }
-           }
-       }
-
-      /* 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.  */
-
-      rtx_code extend_op;
-      if (flag_expensive_optimizations && src_related == 0
-         && MEM_P (src) && ! do_not_record
-         && is_a <scalar_int_mode> (mode, &int_mode)
-         && (extend_op = load_extend_op (int_mode)) != UNKNOWN)
-       {
-         struct rtx_def memory_extend_buf;
-         rtx memory_extend_rtx = &memory_extend_buf;
-
-         /* 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, extend_op);
-         XEXP (memory_extend_rtx, 0) = src;
-
-         opt_scalar_int_mode tmode_iter;
-         FOR_EACH_WIDER_MODE (tmode_iter, int_mode)
-           {
-             struct table_elt *larger_elt;
-
-             scalar_int_mode tmode = tmode_iter.require ();
-             if (GET_MODE_SIZE (tmode) > UNITS_PER_WORD)
-               break;
-
-             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 (int_mode, larger_elt->exp);
-                   break;
-                 }
-
-             if (src_related)
-               break;
-           }
-       }
-
-      /* Try to express the constant using a register+offset expression
-        derived from a constant anchor.  */
-
-      if (targetm.const_anchor
-         && !src_related
-         && src_const
-         && GET_CODE (src_const) == CONST_INT)
-       {
-         src_related = try_const_anchors (src_const, mode);
-         src_related_is_const_anchor = src_related != NULL_RTX;
-       }
-
-
-      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 (paradoxical_subreg_p (p->exp)
-             && ! (src != 0
-                   && GET_CODE (src) == SUBREG
-                   && GET_MODE (src) == GET_MODE (p->exp)
-                   && partial_subreg_p (GET_MODE (SUBREG_REG (src)),
-                                        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 = p->exp;
-       }
-
-      /* 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, mode);
-             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, mode);
-             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, mode);
-             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, mode);
-             src_related_regcost = approx_reg_cost (src_related);
-
-             /* If a const-anchor is used to synthesize a constant that
-                normally requires multiple instructions then slightly prefer
-                it over the original sequence.  These instructions are likely
-                to become redundant now.  We can't compare against the cost
-                of src_eqv_here because, on MIPS for example, multi-insn
-                constants have zero cost; they are assumed to be hoisted from
-                loops.  */
-             if (src_related_is_const_anchor
-                 && src_related_cost == src_cost
-                 && src_eqv_here)
-               src_related_cost--;
-           }
-       }
-
-      /* 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
-             && paradoxical_subreg_p (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)
-                   && partial_subreg_p (GET_MODE (SUBREG_REG (src)),
-                                        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 = 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 = src_related, src_related_cost = MAX_COST;
-         else
-           {
-             trial = elt->exp;
-             elt = elt->next_same_value;
-             src_elt_cost = MAX_COST;
-           }
-
-         /* Try to optimize
-            (set (reg:M N) (const_int A))
-            (set (reg:M2 O) (const_int B))
-            (set (zero_extract:M2 (reg:M N) (const_int C) (const_int D))
-                 (reg:M2 O)).  */
-         if (GET_CODE (SET_DEST (sets[i].rtl)) == ZERO_EXTRACT
-             && CONST_INT_P (trial)
-             && CONST_INT_P (XEXP (SET_DEST (sets[i].rtl), 1))
-             && CONST_INT_P (XEXP (SET_DEST (sets[i].rtl), 2))
-             && REG_P (XEXP (SET_DEST (sets[i].rtl), 0))
-             && (known_ge
-                 (GET_MODE_PRECISION (GET_MODE (SET_DEST (sets[i].rtl))),
-                  INTVAL (XEXP (SET_DEST (sets[i].rtl), 1))))
-             && ((unsigned) INTVAL (XEXP (SET_DEST (sets[i].rtl), 1))
-                 + (unsigned) INTVAL (XEXP (SET_DEST (sets[i].rtl), 2))
-                 <= HOST_BITS_PER_WIDE_INT))
-           {
-             rtx dest_reg = XEXP (SET_DEST (sets[i].rtl), 0);
-             rtx width = XEXP (SET_DEST (sets[i].rtl), 1);
-             rtx pos = XEXP (SET_DEST (sets[i].rtl), 2);
-             unsigned int dest_hash = HASH (dest_reg, GET_MODE (dest_reg));
-             struct table_elt *dest_elt
-               = lookup (dest_reg, dest_hash, GET_MODE (dest_reg));
-             rtx dest_cst = NULL;
-
-             if (dest_elt)
-               for (p = dest_elt->first_same_value; p; p = p->next_same_value)
-                 if (p->is_const && CONST_INT_P (p->exp))
-                   {
-                     dest_cst = p->exp;
-                     break;
-                   }
-             if (dest_cst)
-               {
-                 HOST_WIDE_INT val = INTVAL (dest_cst);
-                 HOST_WIDE_INT mask;
-                 unsigned int shift;
-                 /* This is the mode of DEST_CST as well.  */
-                 scalar_int_mode dest_mode
-                   = as_a <scalar_int_mode> (GET_MODE (dest_reg));
-                 if (BITS_BIG_ENDIAN)
-                   shift = GET_MODE_PRECISION (dest_mode)
-                           - INTVAL (pos) - INTVAL (width);
-                 else
-                   shift = INTVAL (pos);
-                 if (INTVAL (width) == HOST_BITS_PER_WIDE_INT)
-                   mask = HOST_WIDE_INT_M1;
-                 else
-                   mask = (HOST_WIDE_INT_1 << INTVAL (width)) - 1;
-                 val &= ~(mask << shift);
-                 val |= (INTVAL (trial) & mask) << shift;
-                 val = trunc_int_for_mode (val, dest_mode);
-                 validate_unshare_change (insn, &SET_DEST (sets[i].rtl),
-                                          dest_reg, 1);
-                 validate_unshare_change (insn, &SET_SRC (sets[i].rtl),
-                                          GEN_INT (val), 1);
-                 if (apply_change_group ())
-                   {
-                     rtx note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
-                     if (note)
-                       {
-                         remove_note (insn, note);
-                         df_notes_rescan (insn);
-                       }
-                     src_eqv = NULL_RTX;
-                     src_eqv_elt = NULL;
-                     src_eqv_volatile = 0;
-                     src_eqv_in_memory = 0;
-                     src_eqv_hash = 0;
-                     repeat = true;
-                     break;
-                   }
-               }
-           }
-
-         /* 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 = true;
-             break;
-           }
-
-         /* Similarly, lots of targets don't allow no-op
-            (set (mem x) (mem x)) moves.  Even (set (reg x) (reg x))
-            might be impossible for certain registers (like CC registers).  */
-         else if (n_sets == 1
-                  && !CALL_P (insn)
-                  && (MEM_P (trial) || REG_P (trial))
-                  && rtx_equal_p (trial, dest)
-                  && !side_effects_p (dest)
-                  && (cfun->can_delete_dead_exceptions
-                      || insn_nothrow_p (insn))
-                  /* We can only remove the later store if the earlier aliases
-                     at least all accesses the later one.  */
-                  && (!MEM_P (trial)
-                      || ((MEM_ALIAS_SET (dest) == MEM_ALIAS_SET (trial)
-                           || alias_set_subset_of (MEM_ALIAS_SET (dest),
-                                                   MEM_ALIAS_SET (trial)))
-                           && (!MEM_EXPR (trial)
-                               || refs_same_for_tbaa_p (MEM_EXPR (trial),
-                                                        MEM_EXPR (dest))))))
-           {
-             SET_SRC (sets[i].rtl) = trial;
-             noop_insn = true;
-             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.  */
-           ;
-
-         /* Do not replace anything with a MEM, except the replacement
-            is a no-op.  This allows this loop to terminate.  */
-         else if (MEM_P (trial) && !rtx_equal_p (trial, SET_SRC(sets[i].rtl)))
-           /* Do nothing for this case.  */
-           ;
-
-         /* Look for a substitution that makes a valid insn.  */
-         else if (validate_unshare_change (insn, &SET_SRC (sets[i].rtl),
-                                           trial, 0))
-           {
-             rtx new_rtx = canon_reg (SET_SRC (sets[i].rtl), insn);
-
-             /* The result of apply_change_group can be ignored; see
-                canon_reg.  */
-
-             validate_change (insn, &SET_SRC (sets[i].rtl), new_rtx, 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;
-           }
-       }
-
-      /* If we changed the insn too much, handle this set from scratch.  */
-      if (repeat)
-       {
-         i--;
-         continue;
-       }
-
-      src = SET_SRC (sets[i].rtl);
-
-      /* 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, mode) < COST (src, mode)
-                     && 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)
-       {
-         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_EQUAL note if the constant
-        is different from the source.  We don't want to do it for a constant
-        pseudo since verifying that this pseudo hasn't been eliminated is a
-        pain; moreover such a note 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
-         && REG_P (dest)
-         && src_const
-         && !REG_P (src_const)
-         && !(GET_CODE (src_const) == SUBREG
-              && REG_P (SUBREG_REG (src_const)))
-         && !(GET_CODE (src_const) == CONST
-              && GET_CODE (XEXP (src_const, 0)) == MINUS
-              && GET_CODE (XEXP (XEXP (src_const, 0), 0)) == LABEL_REF
-              && GET_CODE (XEXP (XEXP (src_const, 0), 1)) == LABEL_REF)
-         && !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);
-         df_notes_rescan (insn);
-       }
-
-      /* 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 && CONST_INT_P (src_const)
-             && CONST_INT_P (width)
-             && INTVAL (width) < HOST_BITS_PER_WIDE_INT
-             && ! (INTVAL (src_const)
-                   & (HOST_WIDE_INT_M1U << 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.  */
-         cse_cfg_altered |= delete_insn_and_edges (insn);
-         cse_jumps_altered = true;
-         /* No more processing for this set.  */
-         sets[i].rtl = 0;
-       }
-
-      /* Similarly for no-op moves.  */
-      else if (noop_insn)
-       {
-         if (cfun->can_throw_non_call_exceptions && can_throw_internal (insn))
-           cse_cfg_altered = true;
-         cse_cfg_altered |= delete_insn_and_edges (insn);
-         /* 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))
-       {
-         /* 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_jump_insn *new_rtx;
-             rtx note;
-
-             rtx_insn *seq = targetm.gen_jump (XEXP (src, 0));
-             new_rtx = emit_jump_insn_before (seq, insn);
-             JUMP_LABEL (new_rtx) = 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_rtx) = note;
-               }
-
-             cse_cfg_altered |= delete_insn_and_edges (insn);
-             insn = new_rtx;
-           }
-         else
-           INSN_CODE (insn) = -1;
-
-         /* Do not bother deleting any unreachable code, let jump do it.  */
-         cse_jumps_altered = true;
-         sets[i].rtl = 0;
-       }
-
-      /* If destination is volatile, invalidate it and then do no further
-        processing for this assignment.  */
-
-      else if (do_not_record)
-       {
-         invalidate_dest (dest);
-         sets[i].rtl = 0;
-       }
-
-      if (sets[i].rtl != 0 && dest != SET_DEST (sets[i].rtl))
-       {
-         do_not_record = 0;
-         sets[i].dest_hash = HASH (SET_DEST (sets[i].rtl), mode);
-         if (do_not_record)
-           {
-             invalidate_dest (SET_DEST (sets[i].rtl));
-             sets[i].rtl = 0;
-           }
-       }
-
-      /* 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));
-       }
-    }
-
-  /* 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);
-      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);
-           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)
-             {
-               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;
-               /* If inline asm has any clobbers, ensure we only reuse
-                  existing inline asms and never try to put the ASM_OPERANDS
-                  into an insn that isn't inline asm.  */
-               if (GET_CODE (src) == ASM_OPERANDS
-                   && GET_CODE (x) == PARALLEL)
-                 elt->cost = MAX_COST;
-               sets[i].src_elt = classp = elt;
-             }
-           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;
-         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 (insn);
-
-  /* Some registers are invalidated by subroutine calls.  Memory is
-     invalidated by non-constant calls.  */
-
-  if (CALL_P (insn))
-    {
-      if (!(RTL_CONST_OR_PURE_CALL_P (insn)))
-       invalidate_memory ();
-      else
-       /* For const/pure calls, invalidate any argument slots, because
-          those are owned by the callee.  */
-       for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
-         if (GET_CODE (XEXP (tem, 0)) == USE
-             && MEM_P (XEXP (XEXP (tem, 0), 0)))
-           invalidate (XEXP (XEXP (tem, 0), 0), VOIDmode);
-      invalidate_for_call (insn);
-    }
-
-  /* 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));
-      }
-
-  /* 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 (CALL_P (insn) && find_reg_note (insn, REG_SETJMP, NULL))
-    {
-      flush_hash_table ();
-      goto done;
-    }
-
-  /* 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 = END_REGNO (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
-           /* 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)
-         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));
-           }
-
-       /* If DEST is a paradoxical SUBREG, don't record DEST since the bits
-          outside the mode of GET_MODE (SUBREG_REG (dest)) are undefined.  */
-       if (paradoxical_subreg_p (dest))
-         continue;
-
-       elt = insert (dest, sets[i].src_elt,
-                     sets[i].dest_hash, GET_MODE (dest));
-
-       /* If this is a constant, insert the constant anchors with the
-          equivalent register-offset expressions using register DEST.  */
-       if (targetm.const_anchor
-           && REG_P (dest)
-           && SCALAR_INT_MODE_P (GET_MODE (dest))
-           && GET_CODE (sets[i].src_elt->exp) == CONST_INT)
-         insert_const_anchors (dest, sets[i].src_elt->exp, 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
-           && (known_equal_after_align_down
-               (GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))) - 1,
-                GET_MODE_SIZE (GET_MODE (dest)) - 1,
-                UNITS_PER_WORD))
-           && !partial_subreg_p (dest)
-           && sets[i].src_elt != 0)
-         {
-           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;
-
-               /* 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
-                 {
-                   poly_uint64 byte
-                     = subreg_lowpart_offset (new_mode, GET_MODE (dest));
-                   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;
-                   if (GET_CODE (new_src) == ASM_OPERANDS
-                       && elt->cost == MAX_COST)
-                     src_elt->cost = MAX_COST;
-                 }
-               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.  */
-
-  if (n_sets == 1 && sets[0].rtl)
-    try_back_substitute_reg (sets[0].rtl, insn);
-
-done:;
-}
-\f
-/* 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);
-      }
-}
-
-/* Perform invalidation on the basis of everything about 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.  */
-
-static void
-invalidate_from_clobbers (rtx_insn *insn)
-{
-  rtx x = PATTERN (insn);
-
-  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));
-           }
-       }
-    }
-}
-\f
-/* Perform invalidation on the basis of everything about INSN.
-   This includes the places CLOBBERed, and anything that might
-   alias with something that is SET or CLOBBERed.  */
-
-static void
-invalidate_from_sets_and_clobbers (rtx_insn *insn)
-{
-  rtx tem;
-  rtx x = PATTERN (insn);
-
-  if (CALL_P (insn))
-    {
-      for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
-       {
-         rtx temx = XEXP (tem, 0);
-         if (GET_CODE (temx) == CLOBBER)
-           invalidate (SET_DEST (temx), VOIDmode);
-       }
-    }
-
-  /* Ensure we invalidate the destination register of a CALL insn.
-     This is necessary for machines where this register is a fixed_reg,
-     because no other code would invalidate it.  */
-  if (GET_CODE (x) == SET && GET_CODE (SET_SRC (x)) == CALL)
-    invalidate (SET_DEST (x), VOIDmode);
-
-  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 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));
-           }
-         else if (GET_CODE (y) == SET && GET_CODE (SET_SRC (y)) == CALL)
-           invalidate (SET_DEST (y), VOIDmode);
-       }
-    }
-}
-\f
-static rtx cse_process_note (rtx);
-
-/* A simplify_replace_fn_rtx callback for cse_process_note.  Process X,
-   part of the REG_NOTES of an insn.  Replace any registers with either
-   an equivalent constant or the canonical form of the register.
-   Only replace addresses if the containing MEM remains valid.
-
-   Return the replacement for X, or null if it should be simplified
-   recursively.  */
-
-static rtx
-cse_process_note_1 (rtx x, const_rtx, void *)
-{
-  if (MEM_P (x))
-    {
-      validate_change (x, &XEXP (x, 0), cse_process_note (XEXP (x, 0)), false);
-      return x;
-    }
-
-  if (REG_P (x))
-    {
-      int 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_rtx = gen_lowpart (GET_MODE (x), ent->const_rtx);
-             if (new_rtx)
-               return copy_rtx (new_rtx);
-           }
-       }
-
-      /* Otherwise, canonicalize this register.  */
-      return canon_reg (x, NULL);
-    }
-
-  return NULL_RTX;
-}
-
-/* Process X, part of the REG_NOTES of an insn.  Replace any registers in it
-   with either an equivalent constant or the canonical form of the register.
-   Only replace addresses if the containing MEM remains valid.  */
-
-static rtx
-cse_process_note (rtx x)
-{
-  return simplify_replace_fn_rtx (x, NULL_RTX, cse_process_note_1, NULL);
-}
-
-\f
-/* Find a path in the CFG, starting with FIRST_BB to perform CSE on.
-
-   DATA is a pointer to a struct cse_basic_block_data, that is used to
-   describe the path.
-   It is filled with a queue of basic blocks, starting with FIRST_BB
-   and following a trace through the CFG.
-
-   If all paths starting at FIRST_BB have been followed, or no new path
-   starting at FIRST_BB can be constructed, this function returns FALSE.
-   Otherwise, DATA->path is filled and the function returns TRUE indicating
-   that a path to follow was found.
-
-   If FOLLOW_JUMPS is false, the maximum path length is 1 and the only
-   block in the path will be FIRST_BB.  */
-
-static bool
-cse_find_path (basic_block first_bb, struct cse_basic_block_data *data,
-              int follow_jumps)
-{
-  basic_block bb;
-  edge e;
-  int path_size;
-
-  bitmap_set_bit (cse_visited_basic_blocks, first_bb->index);
-
-  /* See if there is a previous path.  */
-  path_size = data->path_size;
-
-  /* There is a previous path.  Make sure it started with FIRST_BB.  */
-  if (path_size)
-    gcc_assert (data->path[0].bb == first_bb);
-
-  /* There was only one basic block in the last path.  Clear the path and
-     return, so that paths starting at another basic block can be tried.  */
-  if (path_size == 1)
-    {
-      path_size = 0;
-      goto done;
-    }
-
-  /* If the path was empty from the beginning, construct a new path.  */
-  if (path_size == 0)
-    data->path[path_size++].bb = first_bb;
-  else
-    {
-      /* Otherwise, path_size must be equal to or greater than 2, because
-        a previous path exists that is at least two basic blocks long.
-
-        Update the previous branch path, if any.  If the last branch was
-        previously along the branch edge, take the fallthrough edge now.  */
-      while (path_size >= 2)
-       {
-         basic_block last_bb_in_path, previous_bb_in_path;
-         edge e;
-
-         --path_size;
-         last_bb_in_path = data->path[path_size].bb;
-         previous_bb_in_path = data->path[path_size - 1].bb;
-
-         /* If we previously followed a path along the branch edge, try
-            the fallthru edge now.  */
-         if (EDGE_COUNT (previous_bb_in_path->succs) == 2
-             && any_condjump_p (BB_END (previous_bb_in_path))
-             && (e = find_edge (previous_bb_in_path, last_bb_in_path))
-             && e == BRANCH_EDGE (previous_bb_in_path))
-           {
-             bb = FALLTHRU_EDGE (previous_bb_in_path)->dest;
-             if (bb != EXIT_BLOCK_PTR_FOR_FN (cfun)
-                 && single_pred_p (bb)
-                 /* We used to assert here that we would only see blocks
-                    that we have not visited yet.  But we may end up
-                    visiting basic blocks twice if the CFG has changed
-                    in this run of cse_main, because when the CFG changes
-                    the topological sort of the CFG also changes.  A basic
-                    blocks that previously had more than two predecessors
-                    may now have a single predecessor, and become part of
-                    a path that starts at another basic block.
-
-                    We still want to visit each basic block only once, so
-                    halt the path here if we have already visited BB.  */
-                 && !bitmap_bit_p (cse_visited_basic_blocks, bb->index))
-               {
-                 bitmap_set_bit (cse_visited_basic_blocks, bb->index);
-                 data->path[path_size++].bb = bb;
-                 break;
-               }
-           }
-
-         data->path[path_size].bb = NULL;
-       }
-
-      /* If only one block remains in the path, bail.  */
-      if (path_size == 1)
-       {
-         path_size = 0;
-         goto done;
-       }
-    }
-
-  /* Extend the path if possible.  */
-  if (follow_jumps)
-    {
-      bb = data->path[path_size - 1].bb;
-      while (bb && path_size < param_max_cse_path_length)
-       {
-         if (single_succ_p (bb))
-           e = single_succ_edge (bb);
-         else if (EDGE_COUNT (bb->succs) == 2
-                  && any_condjump_p (BB_END (bb)))
-           {
-             /* First try to follow the branch.  If that doesn't lead
-                to a useful path, follow the fallthru edge.  */
-             e = BRANCH_EDGE (bb);
-             if (!single_pred_p (e->dest))
-               e = FALLTHRU_EDGE (bb);
-           }
-         else
-           e = NULL;
-
-         if (e
-             && !((e->flags & EDGE_ABNORMAL_CALL) && cfun->has_nonlocal_label)
-             && e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun)
-             && single_pred_p (e->dest)
-             /* Avoid visiting basic blocks twice.  The large comment
-                above explains why this can happen.  */
-             && !bitmap_bit_p (cse_visited_basic_blocks, e->dest->index))
-           {
-             basic_block bb2 = e->dest;
-             bitmap_set_bit (cse_visited_basic_blocks, bb2->index);
-             data->path[path_size++].bb = bb2;
-             bb = bb2;
-           }
-         else
-           bb = NULL;
-       }
-    }
-
-done:
-  data->path_size = path_size;
-  return path_size != 0;
-}
-\f
-/* Dump the path in DATA to file F.  NSETS is the number of sets
-   in the path.  */
-
-static void
-cse_dump_path (struct cse_basic_block_data *data, int nsets, FILE *f)
-{
-  int path_entry;
-
-  fprintf (f, ";; Following path with %d sets: ", nsets);
-  for (path_entry = 0; path_entry < data->path_size; path_entry++)
-    fprintf (f, "%d ", (data->path[path_entry].bb)->index);
-  fputc ('\n', f);
-  fflush (f);
-}
-
-\f
-/* Return true if BB has exception handling successor edges.  */
-
-static bool
-have_eh_succ_edges (basic_block bb)
-{
-  edge e;
-  edge_iterator ei;
-
-  FOR_EACH_EDGE (e, ei, bb->succs)
-    if (e->flags & EDGE_EH)
-      return true;
-
-  return false;
-}
-
-\f
-/* Scan to the end of the path described by DATA.  Return an estimate of
-   the total number of SETs of all insns in the path.  */
-
-static void
-cse_prescan_path (struct cse_basic_block_data *data)
-{
-  int nsets = 0;
-  int path_size = data->path_size;
-  int path_entry;
-
-  /* Scan to end of each basic block in the path.  */
-  for (path_entry = 0; path_entry < path_size; path_entry++)
-    {
-      basic_block bb;
-      rtx_insn *insn;
-
-      bb = data->path[path_entry].bb;
-
-      FOR_BB_INSNS (bb, insn)
-       {
-         if (!INSN_P (insn))
-           continue;
-
-         /* A PARALLEL can have lots of SETs in it,
-            especially if it is really an ASM_OPERANDS.  */
-         if (GET_CODE (PATTERN (insn)) == PARALLEL)
-           nsets += XVECLEN (PATTERN (insn), 0);
-         else
-           nsets += 1;
-       }
-    }
-
-  data->nsets = nsets;
-}
-\f
-/* Return true if the pattern of INSN uses a LABEL_REF for which
-   there isn't a REG_LABEL_OPERAND note.  */
-
-static bool
-check_for_label_ref (rtx_insn *insn)
-{
-  /* If this insn uses a LABEL_REF and there isn't a REG_LABEL_OPERAND
-     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_OPERAND will be added.  */
-  subrtx_iterator::array_type array;
-  FOR_EACH_SUBRTX (iter, array, PATTERN (insn), ALL)
-    {
-      const_rtx x = *iter;
-      if (GET_CODE (x) == LABEL_REF
-         && !LABEL_REF_NONLOCAL_P (x)
-         && (!JUMP_P (insn)
-             || !label_is_jump_target_p (label_ref_label (x), insn))
-         && LABEL_P (label_ref_label (x))
-         && INSN_UID (label_ref_label (x)) != 0
-         && !find_reg_note (insn, REG_LABEL_OPERAND, label_ref_label (x)))
-       return true;
-    }
-  return false;
-}
-
-/* Process a single extended basic block described by EBB_DATA.  */
-
-static void
-cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
-{
-  int path_size = ebb_data->path_size;
-  int path_entry;
-  int num_insns = 0;
-
-  /* Allocate the space needed by qty_table.  */
-  qty_table = XNEWVEC (struct qty_table_elem, max_qty);
-
-  new_basic_block ();
-  cse_ebb_live_in = df_get_live_in (ebb_data->path[0].bb);
-  cse_ebb_live_out = df_get_live_out (ebb_data->path[path_size - 1].bb);
-  for (path_entry = 0; path_entry < path_size; path_entry++)
-    {
-      basic_block bb;
-      rtx_insn *insn;
-
-      bb = ebb_data->path[path_entry].bb;
-
-      /* Invalidate recorded information for eh regs if there is an EH
-        edge pointing to that bb.  */
-      if (bb_has_eh_pred (bb))
-       {
-         df_ref def;
-
-         FOR_EACH_ARTIFICIAL_DEF (def, bb->index)
-           if (DF_REF_FLAGS (def) & DF_REF_AT_TOP)
-             invalidate (DF_REF_REG (def), GET_MODE (DF_REF_REG (def)));
-       }
-
-      optimize_this_for_speed_p = optimize_bb_for_speed_p (bb);
-      FOR_BB_INSNS (bb, 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.
-
-            FIXME: This is a real kludge and needs to be done some other
-                   way.  */
-         if (NONDEBUG_INSN_P (insn)
-             && num_insns++ > param_max_cse_insns)
-           {
-             flush_hash_table ();
-             num_insns = 0;
-           }
-
-         if (INSN_P (insn))
-           {
-             /* Process notes first so we have all notes in canonical forms
-                when looking for duplicate operations.  */
-             bool changed = false;
-             for (rtx note = REG_NOTES (insn); note; note = XEXP (note, 1))
-               if (REG_NOTE_KIND (note) == REG_EQUAL)
-                 {
-                   rtx newval = cse_process_note (XEXP (note, 0));
-                   if (newval != XEXP (note, 0))
-                     {
-                       XEXP (note, 0) = newval;
-                       changed = true;
-                     }
-                 }
-             if (changed)
-               df_notes_rescan (insn);
-
-             cse_insn (insn);
-
-             /* If we haven't already found an insn where we added a LABEL_REF,
-                check this one.  */
-             if (INSN_P (insn) && !recorded_label_ref
-                 && check_for_label_ref (insn))
-               recorded_label_ref = true;
-
-             if (HAVE_cc0 && NONDEBUG_INSN_P (insn))
-               {
-                 /* If the previous insn sets CC0 and this insn no
-                    longer references CC0, delete the previous insn.
-                    Here we use fact that nothing expects CC0 to be
-                    valid over an insn, which is true until the final
-                    pass.  */
-                 rtx_insn *prev_insn;
-                 rtx tem;
-
-                 prev_insn = prev_nonnote_nondebug_insn (insn);
-                 if (prev_insn && NONJUMP_INSN_P (prev_insn)
-                     && (tem = single_set (prev_insn)) != NULL_RTX
-                     && SET_DEST (tem) == cc0_rtx
-                     && ! reg_mentioned_p (cc0_rtx, PATTERN (insn)))
-                   delete_insn (prev_insn);
-
-                 /* If this insn is not the last insn in the basic
-                    block, it will be PREV_INSN(insn) in the next
-                    iteration.  If we recorded any CC0-related
-                    information for this insn, remember it.  */
-                 if (insn != BB_END (bb))
-                   {
-                     prev_insn_cc0 = this_insn_cc0;
-                     prev_insn_cc0_mode = this_insn_cc0_mode;
-                   }
-               }
-           }
-       }
-
-      /* With non-call exceptions, we are not always able to update
-        the CFG properly inside cse_insn.  So clean up possibly
-        redundant EH edges here.  */
-      if (cfun->can_throw_non_call_exceptions && have_eh_succ_edges (bb))
-       cse_cfg_altered |= purge_dead_edges (bb);
-
-      /* If we changed a conditional jump, we may have terminated
-        the path we are following.  Check that by verifying that
-        the edge we would take still exists.  If the edge does
-        not exist anymore, purge the remainder of the path.
-        Note that this will cause us to return to the caller.  */
-      if (path_entry < path_size - 1)
-       {
-         basic_block next_bb = ebb_data->path[path_entry + 1].bb;
-         if (!find_edge (bb, next_bb))
-           {
-             do
-               {
-                 path_size--;
-
-                 /* If we truncate the path, we must also reset the
-                    visited bit on the remaining blocks in the path,
-                    or we will never visit them at all.  */
-                 bitmap_clear_bit (cse_visited_basic_blocks,
-                            ebb_data->path[path_size].bb->index);
-                 ebb_data->path[path_size].bb = NULL;
-               }
-             while (path_size - 1 != path_entry);
-             ebb_data->path_size = path_size;
-           }
-       }
-
-      /* If this is a conditional jump insn, record any known
-        equivalences due to the condition being tested.  */
-      insn = BB_END (bb);
-      if (path_entry < path_size - 1
-         && EDGE_COUNT (bb->succs) == 2
-         && JUMP_P (insn)
-         && single_set (insn)
-         && any_condjump_p (insn))
-       {
-         basic_block next_bb = ebb_data->path[path_entry + 1].bb;
-         bool taken = (next_bb == BRANCH_EDGE (bb)->dest);
-         record_jump_equiv (insn, taken);
-       }
-
-      /* Clear the CC0-tracking related insns, they can't provide
-        useful information across basic block boundaries.  */
-      prev_insn_cc0 = 0;
-    }
-
-  gcc_assert (next_qty <= max_qty);
-
-  free (qty_table);
-}
-
-\f
-/* 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.
-
-   Return 2 if jump optimizations should be redone due to simplifications
-   in conditional jump instructions.
-   Return 1 if the CFG should be cleaned up because it has been modified.
-   Return 0 otherwise.  */
-
-static int
-cse_main (rtx_insn *f ATTRIBUTE_UNUSED, int nregs)
-{
-  struct cse_basic_block_data ebb_data;
-  basic_block bb;
-  int *rc_order = XNEWVEC (int, last_basic_block_for_fn (cfun));
-  int i, n_blocks;
-
-  /* CSE doesn't use dominane info but can invalidate it in different ways.
-     For simplicity free dominance info here.  */
-  free_dominance_info (CDI_DOMINATORS);
-
-  df_set_flags (DF_LR_RUN_DCE);
-  df_note_add_problem ();
-  df_analyze ();
-  df_set_flags (DF_DEFER_INSN_RESCAN);
-
-  reg_scan (get_insns (), max_reg_num ());
-  init_cse_reg_info (nregs);
-
-  ebb_data.path = XNEWVEC (struct branch_path,
-                          param_max_cse_path_length);
-
-  cse_cfg_altered = false;
-  cse_jumps_altered = false;
-  recorded_label_ref = false;
-  constant_pool_entries_cost = 0;
-  constant_pool_entries_regcost = 0;
-  ebb_data.path_size = 0;
-  ebb_data.nsets = 0;
-  rtl_hooks = cse_rtl_hooks;
-
-  init_recog ();
-  init_alias_analysis ();
-
-  reg_eqv_table = XNEWVEC (struct reg_eqv_elem, nregs);
-
-  /* Set up the table of already visited basic blocks.  */
-  cse_visited_basic_blocks = sbitmap_alloc (last_basic_block_for_fn (cfun));
-  bitmap_clear (cse_visited_basic_blocks);
-
-  /* Loop over basic blocks in reverse completion order (RPO),
-     excluding the ENTRY and EXIT blocks.  */
-  n_blocks = pre_and_rev_post_order_compute (NULL, rc_order, false);
-  i = 0;
-  while (i < n_blocks)
-    {
-      /* Find the first block in the RPO queue that we have not yet
-        processed before.  */
-      do
-       {
-         bb = BASIC_BLOCK_FOR_FN (cfun, rc_order[i++]);
-       }
-      while (bitmap_bit_p (cse_visited_basic_blocks, bb->index)
-            && i < n_blocks);
-
-      /* Find all paths starting with BB, and process them.  */
-      while (cse_find_path (bb, &ebb_data, flag_cse_follow_jumps))
-       {
-         /* Pre-scan the path.  */
-         cse_prescan_path (&ebb_data);
-
-         /* If this basic block has no sets, skip it.  */
-         if (ebb_data.nsets == 0)
-           continue;
-
-         /* Get a reasonable estimate for the maximum number of qty's
-            needed for this path.  For this, we take the number of sets
-            and multiply that by MAX_RECOG_OPERANDS.  */
-         max_qty = ebb_data.nsets * MAX_RECOG_OPERANDS;
-
-         /* Dump the path we're about to process.  */
-         if (dump_file)
-           cse_dump_path (&ebb_data, ebb_data.nsets, dump_file);
-
-         cse_extended_basic_block (&ebb_data);
-       }
-    }
-
-  /* Clean up.  */
-  end_alias_analysis ();
-  free (reg_eqv_table);
-  free (ebb_data.path);
-  sbitmap_free (cse_visited_basic_blocks);
-  free (rc_order);
-  rtl_hooks = general_rtl_hooks;
-
-  if (cse_jumps_altered || recorded_label_ref)
-    return 2;
-  else if (cse_cfg_altered)
-    return 1;
-  else
-    return 0;
-}
-\f
-/* 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, or for an insn with side effects.
-   We must then 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_ANY:
-    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 DEBUG_INSN:
-      return;
-
-    case CALL_INSN:
-    case INSN:
-    case JUMP_INSN:
-      /* We expect dest to be NULL_RTX here.  If the insn may throw,
-        or if it cannot be deleted due to side-effects, mark this fact
-        by setting DEST to pc_rtx.  */
-      if ((!cfun->can_delete_dead_exceptions && !insn_nothrow_p (x))
-         || side_effects_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:
-      /* 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:
-    case INT_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);
-    }
-}
-\f
-/* Return true if X is a dead register.  */
-
-static inline int
-is_dead_reg (const_rtx x, int *counts)
-{
-  return (REG_P (x)
-         && REGNO (x) >= FIRST_PSEUDO_REGISTER
-         && counts[REGNO (x)] == 0);
-}
-
-/* Return true if set is live.  */
-static bool
-set_live_p (rtx set, rtx_insn *insn ATTRIBUTE_UNUSED, /* Only used with HAVE_cc0.  */
-           int *counts)
-{
-  rtx_insn *tem;
-
-  if (set_noop_p (set))
-    ;
-
-  else if (GET_CODE (SET_DEST (set)) == CC0
-          && !side_effects_p (SET_SRC (set))
-          && ((tem = next_nonnote_nondebug_insn (insn)) == NULL_RTX
-              || !INSN_P (tem)
-              || !reg_referenced_p (cc0_rtx, PATTERN (tem))))
-    return false;
-  else if (!is_dead_reg (SET_DEST (set), counts)
-          || side_effects_p (SET_SRC (set)))
-    return true;
-  return false;
-}
-
-/* Return true if insn is live.  */
-
-static bool
-insn_live_p (rtx_insn *insn, int *counts)
-{
-  int i;
-  if (!cfun->can_delete_dead_exceptions && !insn_nothrow_p (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 if (DEBUG_INSN_P (insn))
-    {
-      rtx_insn *next;
-
-      if (DEBUG_MARKER_INSN_P (insn))
-       return true;
-
-      for (next = NEXT_INSN (insn); next; next = NEXT_INSN (next))
-       if (NOTE_P (next))
-         continue;
-       else if (!DEBUG_INSN_P (next))
-         return true;
-       /* If we find an inspection point, such as a debug begin stmt,
-          we want to keep the earlier debug insn.  */
-       else if (DEBUG_MARKER_INSN_P (next))
-         return true;
-       else if (INSN_VAR_LOCATION_DECL (insn) == INSN_VAR_LOCATION_DECL (next))
-         return false;
-
-      return true;
-    }
-  else
-    return true;
-}
-
-/* Count the number of stores into pseudo.  Callback for note_stores.  */
-
-static void
-count_stores (rtx x, const_rtx set ATTRIBUTE_UNUSED, void *data)
-{
-  int *counts = (int *) data;
-  if (REG_P (x) && REGNO (x) >= FIRST_PSEUDO_REGISTER)
-    counts[REGNO (x)]++;
-}
-
-/* Return if DEBUG_INSN pattern PAT needs to be reset because some dead
-   pseudo doesn't have a replacement.  COUNTS[X] is zero if register X
-   is dead and REPLACEMENTS[X] is null if it has no replacemenet.
-   Set *SEEN_REPL to true if we see a dead register that does have
-   a replacement.  */
-
-static bool
-is_dead_debug_insn (const_rtx pat, int *counts, rtx *replacements,
-                   bool *seen_repl)
-{
-  subrtx_iterator::array_type array;
-  FOR_EACH_SUBRTX (iter, array, pat, NONCONST)
-    {
-      const_rtx x = *iter;
-      if (is_dead_reg (x, counts))
-       {
-         if (replacements && replacements[REGNO (x)] != NULL_RTX)
-           *seen_repl = true;
-         else
-           return true;
-       }
-    }
-  return false;
-}
-
-/* Replace a dead pseudo in a DEBUG_INSN with replacement DEBUG_EXPR.
-   Callback for simplify_replace_fn_rtx.  */
-
-static rtx
-replace_dead_reg (rtx x, const_rtx old_rtx ATTRIBUTE_UNUSED, void *data)
-{
-  rtx *replacements = (rtx *) data;
-
-  if (REG_P (x)
-      && REGNO (x) >= FIRST_PSEUDO_REGISTER
-      && replacements[REGNO (x)] != NULL_RTX)
-    {
-      if (GET_MODE (x) == GET_MODE (replacements[REGNO (x)]))
-       return replacements[REGNO (x)];
-      return lowpart_subreg (GET_MODE (x), replacements[REGNO (x)],
-                            GET_MODE (replacements[REGNO (x)]));
-    }
-  return NULL_RTX;
-}
-
-/* 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_insn *insns, int nreg)
-{
-  int *counts;
-  rtx_insn *insn, *prev;
-  rtx *replacements = NULL;
-  int ndead = 0;
-
-  timevar_push (TV_DELETE_TRIVIALLY_DEAD);
-  /* First count the number of times each register is used.  */
-  if (MAY_HAVE_DEBUG_BIND_INSNS)
-    {
-      counts = XCNEWVEC (int, nreg * 3);
-      for (insn = insns; insn; insn = NEXT_INSN (insn))
-       if (DEBUG_BIND_INSN_P (insn))
-         count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
-                          NULL_RTX, 1);
-       else if (INSN_P (insn))
-         {
-           count_reg_usage (insn, counts, NULL_RTX, 1);
-           note_stores (insn, count_stores, counts + nreg * 2);
-         }
-      /* If there can be debug insns, COUNTS are 3 consecutive arrays.
-        First one counts how many times each pseudo is used outside
-        of debug insns, second counts how many times each pseudo is
-        used in debug insns and third counts how many times a pseudo
-        is stored.  */
-    }
-  else
-    {
-      counts = XCNEWVEC (int, nreg);
-      for (insn = insns; insn; insn = NEXT_INSN (insn))
-       if (INSN_P (insn))
-         count_reg_usage (insn, counts, NULL_RTX, 1);
-      /* If no debug insns can be present, COUNTS is just an array
-        which counts how many times each pseudo is used.  */
-    }
-  /* Pseudo PIC register should be considered as used due to possible
-     new usages generated.  */
-  if (!reload_completed
-      && pic_offset_table_rtx
-      && REGNO (pic_offset_table_rtx) >= FIRST_PSEUDO_REGISTER)
-    counts[REGNO (pic_offset_table_rtx)]++;
-  /* 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.
-
-     If some otherwise unused register is only used in DEBUG_INSNs,
-     try to create a DEBUG_EXPR temporary and emit a DEBUG_INSN before
-     the setter.  Then go through DEBUG_INSNs and if a DEBUG_EXPR
-     has been created for the unused register, replace it with
-     the DEBUG_EXPR, otherwise reset the DEBUG_INSN.  */
-  for (insn = get_last_insn (); insn; insn = prev)
-    {
-      int live_insn = 0;
-
-      prev = PREV_INSN (insn);
-      if (!INSN_P (insn))
-       continue;
-
-      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 && dbg_cnt (delete_trivial_dead))
-       {
-         if (DEBUG_INSN_P (insn))
-           {
-             if (DEBUG_BIND_INSN_P (insn))
-               count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
-                                NULL_RTX, -1);
-           }
-         else
-           {
-             rtx set;
-             if (MAY_HAVE_DEBUG_BIND_INSNS
-                 && (set = single_set (insn)) != NULL_RTX
-                 && is_dead_reg (SET_DEST (set), counts)
-                 /* Used at least once in some DEBUG_INSN.  */
-                 && counts[REGNO (SET_DEST (set)) + nreg] > 0
-                 /* And set exactly once.  */
-                 && counts[REGNO (SET_DEST (set)) + nreg * 2] == 1
-                 && !side_effects_p (SET_SRC (set))
-                 && asm_noperands (PATTERN (insn)) < 0)
-               {
-                 rtx dval, bind_var_loc;
-                 rtx_insn *bind;
-
-                 /* Create DEBUG_EXPR (and DEBUG_EXPR_DECL).  */
-                 dval = make_debug_expr_from_rtl (SET_DEST (set));
-
-                 /* Emit a debug bind insn before the insn in which
-                    reg dies.  */
-                 bind_var_loc =
-                   gen_rtx_VAR_LOCATION (GET_MODE (SET_DEST (set)),
-                                         DEBUG_EXPR_TREE_DECL (dval),
-                                         SET_SRC (set),
-                                         VAR_INIT_STATUS_INITIALIZED);
-                 count_reg_usage (bind_var_loc, counts + nreg, NULL_RTX, 1);
-
-                 bind = emit_debug_insn_before (bind_var_loc, insn);
-                 df_insn_rescan (bind);
-
-                 if (replacements == NULL)
-                   replacements = XCNEWVEC (rtx, nreg);
-                 replacements[REGNO (SET_DEST (set))] = dval;
-               }
-
-             count_reg_usage (insn, counts, NULL_RTX, -1);
-             ndead++;
-           }
-         cse_cfg_altered |= delete_insn_and_edges (insn);
-       }
-    }
-
-  if (MAY_HAVE_DEBUG_BIND_INSNS)
-    {
-      for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
-       if (DEBUG_BIND_INSN_P (insn))
-         {
-           /* If this debug insn references a dead register that wasn't replaced
-              with an DEBUG_EXPR, reset the DEBUG_INSN.  */
-           bool seen_repl = false;
-           if (is_dead_debug_insn (INSN_VAR_LOCATION_LOC (insn),
-                                   counts, replacements, &seen_repl))
-             {
-               INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
-               df_insn_rescan (insn);
-             }
-           else if (seen_repl)
-             {
-               INSN_VAR_LOCATION_LOC (insn)
-                 = simplify_replace_fn_rtx (INSN_VAR_LOCATION_LOC (insn),
-                                            NULL_RTX, replace_dead_reg,
-                                            replacements);
-               df_insn_rescan (insn);
-             }
-         }
-      free (replacements);
-    }
-
-  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;
-}
-
-/* If LOC contains references to NEWREG in a different mode, change them
-   to use NEWREG instead.  */
-
-static void
-cse_change_cc_mode (subrtx_ptr_iterator::array_type &array,
-                   rtx *loc, rtx_insn *insn, rtx newreg)
-{
-  FOR_EACH_SUBRTX_PTR (iter, array, loc, NONCONST)
-    {
-      rtx *loc = *iter;
-      rtx x = *loc;
-      if (x
-         && REG_P (x)
-         && REGNO (x) == REGNO (newreg)
-         && GET_MODE (x) != GET_MODE (newreg))
-       {
-         validate_change (insn, loc, newreg, 1);
-         iter.skip_subrtxes ();
-       }
-    }
-}
-
-/* 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 *insn, rtx newreg)
-{
-  int success;
-
-  if (!INSN_P (insn))
-    return;
-
-  subrtx_ptr_iterator::array_type array;
-  cse_change_cc_mode (array, &PATTERN (insn), insn, newreg);
-  cse_change_cc_mode (array, &REG_NOTES (insn), insn, newreg);
-
-  /* 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_insn *start, rtx_insn *end, rtx newreg)
-{
-  rtx_insn *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.
-   ORIG_BB should be the same as BB in the outermost cse_cc_succs call,
-   but is passed unmodified down to recursive calls in order to prevent
-   endless recursion.
-
-   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 machine_mode
-cse_cc_succs (basic_block bb, basic_block orig_bb, rtx cc_reg, rtx cc_src,
-             bool can_change_mode)
-{
-  bool found_equiv;
-  machine_mode mode;
-  unsigned int insn_count;
-  edge e;
-  rtx_insn *insns[2];
-  machine_mode modes[2];
-  rtx_insn *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 *insn;
-      rtx_insn *end;
-
-      if (e->flags & EDGE_COMPLEX)
-       continue;
-
-      if (EDGE_COUNT (e->dest->preds) != 1
-         || e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun)
-         /* Avoid endless recursion on unreachable blocks.  */
-         || e->dest == orig_bb)
-       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;
-             machine_mode set_mode;
-             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)
-       {
-         machine_mode submode;
-
-         submode = cse_cc_succs (e->dest, orig_bb, 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);
-       }
-
-      cse_cfg_altered |= delete_insn_and_edges (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_FN (bb, cfun)
-    {
-      rtx_insn *last_insn;
-      rtx cc_reg;
-      rtx_insn *insn;
-      rtx_insn *cc_src_insn;
-      rtx cc_src;
-      machine_mode mode;
-      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;
-      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, 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);
-           }
-       }
-    }
-}
-\f
-
-/* 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 unsigned int
-rest_of_handle_cse (void)
-{
-  int tem;
-
-  if (dump_file)
-    dump_flow_info (dump_file, dump_flags);
-
-  tem = cse_main (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 == 2)
-    {
-      timevar_push (TV_JUMP);
-      rebuild_jump_labels (get_insns ());
-      cse_cfg_altered |= cleanup_cfg (CLEANUP_CFG_CHANGED);
-      timevar_pop (TV_JUMP);
-    }
-  else if (tem == 1 || optimize > 1)
-    cse_cfg_altered |= cleanup_cfg (0);
-
-  return 0;
-}
-
-namespace {
-
-const pass_data pass_data_cse =
-{
-  RTL_PASS, /* type */
-  "cse1", /* name */
-  OPTGROUP_NONE, /* optinfo_flags */
-  TV_CSE, /* tv_id */
-  0, /* properties_required */
-  0, /* properties_provided */
-  0, /* properties_destroyed */
-  0, /* todo_flags_start */
-  TODO_df_finish, /* todo_flags_finish */
-};
-
-class pass_cse : public rtl_opt_pass
-{
-public:
-  pass_cse (gcc::context *ctxt)
-    : rtl_opt_pass (pass_data_cse, ctxt)
-  {}
-
-  /* opt_pass methods: */
-  virtual bool gate (function *) { return optimize > 0; }
-  virtual unsigned int execute (function *) { return rest_of_handle_cse (); }
-
-}; // class pass_cse
-
-} // anon namespace
-
-rtl_opt_pass *
-make_pass_cse (gcc::context *ctxt)
-{
-  return new pass_cse (ctxt);
-}
-
-
-/* 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 ();
-
-  delete_trivially_dead_insns (get_insns (), max_reg_num ());
-
-  if (tem == 2)
-    {
-      timevar_push (TV_JUMP);
-      rebuild_jump_labels (get_insns ());
-      cse_cfg_altered |= cleanup_cfg (CLEANUP_CFG_CHANGED);
-      timevar_pop (TV_JUMP);
-    }
-  else if (tem == 1 || cse_cfg_altered)
-    cse_cfg_altered |= cleanup_cfg (0);
-
-  cse_not_expected = 1;
-  return 0;
-}
-
-
-namespace {
-
-const pass_data pass_data_cse2 =
-{
-  RTL_PASS, /* type */
-  "cse2", /* name */
-  OPTGROUP_NONE, /* optinfo_flags */
-  TV_CSE2, /* tv_id */
-  0, /* properties_required */
-  0, /* properties_provided */
-  0, /* properties_destroyed */
-  0, /* todo_flags_start */
-  TODO_df_finish, /* todo_flags_finish */
-};
-
-class pass_cse2 : public rtl_opt_pass
-{
-public:
-  pass_cse2 (gcc::context *ctxt)
-    : rtl_opt_pass (pass_data_cse2, ctxt)
-  {}
-
-  /* opt_pass methods: */
-  virtual bool gate (function *)
-    {
-      return optimize > 0 && flag_rerun_cse_after_loop;
-    }
-
-  virtual unsigned int execute (function *) { return rest_of_handle_cse2 (); }
-
-}; // class pass_cse2
-
-} // anon namespace
-
-rtl_opt_pass *
-make_pass_cse2 (gcc::context *ctxt)
-{
-  return new pass_cse2 (ctxt);
-}
-
-/* Run second CSE pass after loop optimizations.  */
-static unsigned int
-rest_of_handle_cse_after_global_opts (void)
-{
-  int save_cfj;
-  int tem;
-
-  /* We only want to do local CSE, so don't follow jumps.  */
-  save_cfj = flag_cse_follow_jumps;
-  flag_cse_follow_jumps = 0;
-
-  rebuild_jump_labels (get_insns ());
-  tem = cse_main (get_insns (), max_reg_num ());
-  cse_cfg_altered |= purge_all_dead_edges ();
-  delete_trivially_dead_insns (get_insns (), max_reg_num ());
-
-  cse_not_expected = !flag_rerun_cse_after_loop;
-
-  /* If cse altered any jumps, rerun jump opts to clean things up.  */
-  if (tem == 2)
-    {
-      timevar_push (TV_JUMP);
-      rebuild_jump_labels (get_insns ());
-      cse_cfg_altered |= cleanup_cfg (CLEANUP_CFG_CHANGED);
-      timevar_pop (TV_JUMP);
-    }
-  else if (tem == 1 || cse_cfg_altered)
-    cse_cfg_altered |= cleanup_cfg (0);
-
-  flag_cse_follow_jumps = save_cfj;
-  return 0;
-}
-
-namespace {
-
-const pass_data pass_data_cse_after_global_opts =
-{
-  RTL_PASS, /* type */
-  "cse_local", /* name */
-  OPTGROUP_NONE, /* optinfo_flags */
-  TV_CSE, /* tv_id */
-  0, /* properties_required */
-  0, /* properties_provided */
-  0, /* properties_destroyed */
-  0, /* todo_flags_start */
-  TODO_df_finish, /* todo_flags_finish */
-};
-
-class pass_cse_after_global_opts : public rtl_opt_pass
-{
-public:
-  pass_cse_after_global_opts (gcc::context *ctxt)
-    : rtl_opt_pass (pass_data_cse_after_global_opts, ctxt)
-  {}
-
-  /* opt_pass methods: */
-  virtual bool gate (function *)
-    {
-      return optimize > 0 && flag_rerun_cse_after_global_opts;
-    }
-
-  virtual unsigned int execute (function *)
-    {
-      return rest_of_handle_cse_after_global_opts ();
-    }
-
-}; // class pass_cse_after_global_opts
-
-} // anon namespace
-
-rtl_opt_pass *
-make_pass_cse_after_global_opts (gcc::context *ctxt)
-{
-  return new pass_cse_after_global_opts (ctxt);
-}