OSDN Git Service

2008-06-02 Daniel Kraft <d@domob.eu>
[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index 6fbf816..c194d66 100644 (file)
@@ -1,13 +1,13 @@
 /* Optimize by combining instructions for GNU compiler.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+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
@@ -16,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 /* This module is essentially the "combiner" phase of the U. of Arizona
    Portable Optimizer, but redone to work on our list-structured
@@ -105,6 +104,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "timevar.h"
 #include "tree-pass.h"
 #include "df.h"
+#include "cgraph.h"
 
 /* Number of attempts to combine instructions in this function.  */
 
@@ -143,11 +143,7 @@ static rtx i2mod_old_rhs;
 
 static rtx i2mod_new_rhs;
 \f
-/* Maximum register number, which is the size of the tables below.  */
-
-static unsigned int combine_max_regno;
-
-struct reg_stat {
+typedef struct reg_stat_struct {
   /* Record last point of death of (hard or pseudo) register n.  */
   rtx                          last_death;
 
@@ -254,9 +250,12 @@ struct reg_stat {
      value.  */
 
   ENUM_BITFIELD(machine_mode)  truncated_to_mode : 8;
-};
+} reg_stat_type;
 
-static struct reg_stat *reg_stat;
+DEF_VEC_O(reg_stat_type);
+DEF_VEC_ALLOC_O(reg_stat_type,heap);
+
+static VEC(reg_stat_type,heap) *reg_stat;
 
 /* Record the luid of the last insn that invalidated memory
    (anything that writes memory, and subroutine calls, but not pushes).  */
@@ -370,18 +369,18 @@ static struct undobuf undobuf;
 
 static int n_occurrences;
 
-static rtx reg_nonzero_bits_for_combine (rtx, enum machine_mode, rtx,
+static rtx reg_nonzero_bits_for_combine (const_rtx, enum machine_mode, const_rtx,
                                         enum machine_mode,
                                         unsigned HOST_WIDE_INT,
                                         unsigned HOST_WIDE_INT *);
-static rtx reg_num_sign_bit_copies_for_combine (rtx, enum machine_mode, rtx,
+static rtx reg_num_sign_bit_copies_for_combine (const_rtx, enum machine_mode, const_rtx,
                                                enum machine_mode,
                                                unsigned int, unsigned int *);
 static void do_SUBST (rtx *, rtx);
 static void do_SUBST_INT (int *, int);
 static void init_reg_last (void);
 static void setup_incoming_promotions (rtx);
-static void set_nonzero_bits_and_sign_copies (rtx, rtx, void *);
+static void set_nonzero_bits_and_sign_copies (rtx, const_rtx, void *);
 static int cant_combine_insn_p (rtx);
 static int can_combine_p (rtx, rtx, rtx, rtx, rtx *, rtx *);
 static int combinable_i3pat (rtx, rtx *, rtx, rtx, int, rtx *);
@@ -396,7 +395,7 @@ static rtx simplify_if_then_else (rtx);
 static rtx simplify_set (rtx);
 static rtx simplify_logical (rtx);
 static rtx expand_compound_operation (rtx);
-static rtx expand_field_assignment (rtx);
+static const_rtx expand_field_assignment (const_rtx);
 static rtx make_extraction (enum machine_mode, rtx, HOST_WIDE_INT,
                            rtx, unsigned HOST_WIDE_INT, int, int, int);
 static rtx extract_left_shift (rtx, int);
@@ -426,13 +425,13 @@ static rtx gen_lowpart_for_combine (enum machine_mode, rtx);
 static enum rtx_code simplify_comparison (enum rtx_code, rtx *, rtx *);
 static void update_table_tick (rtx);
 static void record_value_for_reg (rtx, rtx, rtx);
-static void check_conversions (rtx, rtx);
-static void record_dead_and_set_regs_1 (rtx, rtx, void *);
+static void check_promoted_subreg (rtx, rtx);
+static void record_dead_and_set_regs_1 (rtx, const_rtx, void *);
 static void record_dead_and_set_regs (rtx);
 static int get_last_value_validate (rtx *, rtx, int, int);
-static rtx get_last_value (rtx);
-static int use_crosses_set_p (rtx, int);
-static void reg_dead_at_p_1 (rtx, rtx, void *);
+static rtx get_last_value (const_rtx);
+static int use_crosses_set_p (const_rtx, int);
+static void reg_dead_at_p_1 (rtx, const_rtx, void *);
 static int reg_dead_at_p (rtx, rtx);
 static void move_deaths (rtx, rtx, int, rtx, rtx *);
 static int reg_bitfield_target_p (rtx, rtx);
@@ -442,8 +441,9 @@ static void mark_used_regs_combine (rtx);
 static void record_promoted_value (rtx, rtx);
 static int unmentioned_reg_p_1 (rtx *, void *);
 static bool unmentioned_reg_p (rtx, rtx);
-static void record_truncated_value (rtx);
-static bool reg_truncated_to_mode (enum machine_mode, rtx);
+static int record_truncated_value (rtx *, void *);
+static void record_truncated_values (rtx *, void *);
+static bool reg_truncated_to_mode (enum machine_mode, const_rtx);
 static rtx gen_lowpart_or_truncate (enum machine_mode, rtx);
 \f
 
@@ -468,6 +468,25 @@ static rtx gen_lowpart_or_truncate (enum machine_mode, rtx);
 static const struct rtl_hooks combine_rtl_hooks = RTL_HOOKS_INITIALIZER;
 
 \f
+/* Try to split PATTERN found in INSN.  This returns NULL_RTX if
+   PATTERN can not be split.  Otherwise, it returns an insn sequence.
+   This is a wrapper around split_insns which ensures that the
+   reg_stat vector is made larger if the splitter creates a new
+   register.  */
+
+static rtx
+combine_split_insns (rtx pattern, rtx insn)
+{
+  rtx ret;
+  unsigned int nregs;
+
+  ret = split_insns (pattern, insn);
+  nregs = max_reg_num ();
+  if (nregs > VEC_length (reg_stat_type, reg_stat))
+    VEC_safe_grow_cleared (reg_stat_type, heap, reg_stat, nregs);
+  return ret;
+}
+
 /* This is used by find_single_use to locate an rtx in LOC that
    contains exactly one use of DEST, which is typically either a REG
    or CC0.  It returns a pointer to the innermost rtx expression
@@ -733,7 +752,7 @@ do_SUBST_MODE (rtx *into, enum machine_mode newval)
   buf->kind = UNDO_MODE;
   buf->where.r = into;
   buf->old_contents.m = oldval;
-  PUT_MODE (*into, newval);
+  adjust_reg_mode (*into, newval);
 
   buf->next = undobuf.undos, undobuf.undos = buf;
 }
@@ -741,14 +760,17 @@ do_SUBST_MODE (rtx *into, enum machine_mode newval)
 #define SUBST_MODE(INTO, NEWVAL)  do_SUBST_MODE(&(INTO), (NEWVAL))
 \f
 /* Subroutine of try_combine.  Determine whether the combine replacement
-   patterns NEWPAT and NEWI2PAT are cheaper according to insn_rtx_cost
-   that the original instruction sequence I1, I2 and I3.  Note that I1
-   and/or NEWI2PAT may be NULL_RTX.  This function returns false, if the
-   costs of all instructions can be estimated, and the replacements are
-   more expensive than the original sequence.  */
+   patterns NEWPAT, NEWI2PAT and NEWOTHERPAT are cheaper according to
+   insn_rtx_cost that the original instruction sequence I1, I2, I3 and
+   undobuf.other_insn.  Note that I1 and/or NEWI2PAT may be NULL_RTX. 
+   NEWOTHERPAT and undobuf.other_insn may also both be NULL_RTX.  This
+   function returns false, if the costs of all instructions can be
+   estimated, and the replacements are more expensive than the original
+   sequence.  */
 
 static bool
-combine_validate_cost (rtx i1, rtx i2, rtx i3, rtx newpat, rtx newi2pat)
+combine_validate_cost (rtx i1, rtx i2, rtx i3, rtx newpat, rtx newi2pat,
+                      rtx newotherpat)
 {
   int i1_cost, i2_cost, i3_cost;
   int new_i2_cost, new_i3_cost;
@@ -789,7 +811,7 @@ combine_validate_cost (rtx i1, rtx i2, rtx i3, rtx newpat, rtx newi2pat)
       int old_other_cost, new_other_cost;
 
       old_other_cost = INSN_COST (undobuf.other_insn);
-      new_other_cost = insn_rtx_cost (PATTERN (undobuf.other_insn));
+      new_other_cost = insn_rtx_cost (newotherpat);
       if (old_other_cost > 0 && new_other_cost > 0)
        {
          old_cost += old_other_cost;
@@ -955,8 +977,18 @@ create_log_links (void)
                      assignments later.  */
                   if (regno >= FIRST_PSEUDO_REGISTER
                       || asm_noperands (PATTERN (use_insn)) < 0)
-                    LOG_LINKS (use_insn) =
-                      alloc_INSN_LIST (insn, LOG_LINKS (use_insn));
+                   {
+                     /* Don't add duplicate links between instructions.  */
+                     rtx links;
+                     for (links = LOG_LINKS (use_insn); links;
+                          links = XEXP (links, 1))
+                       if (insn == XEXP (links, 0))
+                         break;
+
+                     if (!links)
+                       LOG_LINKS (use_insn) =
+                         alloc_INSN_LIST (insn, LOG_LINKS (use_insn));
+                   }
                 }
               next_use[regno] = NULL_RTX;
             }
@@ -1021,11 +1053,9 @@ combine_instructions (rtx f, unsigned int nregs)
   combine_extras = 0;
   combine_successes = 0;
 
-  combine_max_regno = nregs;
-
   rtl_hooks = combine_rtl_hooks;
 
-  reg_stat = XCNEWVEC (struct reg_stat, nregs);
+  VEC_safe_grow_cleared (reg_stat_type, heap, reg_stat, nregs);
 
   init_recog_no_volatile ();
 
@@ -1108,7 +1138,12 @@ combine_instructions (rtx f, unsigned int nregs)
            {
              /* See if we know about function return values before this
                 insn based upon SUBREG flags.  */
-             check_conversions (insn, PATTERN (insn));
+             check_promoted_subreg (insn, PATTERN (insn));
+
+             /* See if we can find hardregs and subreg of pseudos in
+                narrower modes.  This could help turning TRUNCATEs
+                into SUBREGs.  */
+             note_uses (&PATTERN (insn), record_truncated_values, NULL);
 
              /* Try this insn with each insn it links back to.  */
 
@@ -1258,7 +1293,7 @@ combine_instructions (rtx f, unsigned int nregs)
   /* Clean up.  */
   free (uid_log_links);
   free (uid_insn_cost);
-  free (reg_stat);
+  VEC_free (reg_stat_type, heap, reg_stat);
 
   {
     struct undo *undo, *next;
@@ -1290,8 +1325,10 @@ static void
 init_reg_last (void)
 {
   unsigned int i;
-  for (i = 0; i < combine_max_regno; i++)
-    memset (reg_stat + i, 0, offsetof (struct reg_stat, sign_bit_copies));
+  reg_stat_type *p;
+
+  for (i = 0; VEC_iterate (reg_stat_type, reg_stat, i, p); ++i)
+    memset (p, 0, offsetof (reg_stat_type, sign_bit_copies));
 }
 \f
 /* Set up any promoted values for incoming argument registers.  */
@@ -1300,6 +1337,7 @@ static void
 setup_incoming_promotions (rtx first)
 {
   tree arg;
+  bool strictly_local = false;
 
   if (!targetm.calls.promote_function_args (TREE_TYPE (cfun->decl)))
     return;
@@ -1308,27 +1346,64 @@ setup_incoming_promotions (rtx first)
        arg = TREE_CHAIN (arg))
     {
       rtx reg = DECL_INCOMING_RTL (arg);
+      int uns1, uns3;
+      enum machine_mode mode1, mode2, mode3, mode4;
 
+      /* Only continue if the incoming argument is in a register.  */
       if (!REG_P (reg))
        continue;
 
-      if (TYPE_MODE (DECL_ARG_TYPE (arg)) == TYPE_MODE (TREE_TYPE (arg)))
-       {
-         enum machine_mode mode = TYPE_MODE (TREE_TYPE (arg));
-         int uns = TYPE_UNSIGNED (TREE_TYPE (arg));
-
-         mode = promote_mode (TREE_TYPE (arg), mode, &uns, 1);
-         if (mode == GET_MODE (reg) && mode != DECL_MODE (arg))
-           {
-             rtx x;
-             x = gen_rtx_CLOBBER (DECL_MODE (arg), const0_rtx);
-             x = gen_rtx_fmt_e ((uns ? ZERO_EXTEND : SIGN_EXTEND), mode, x);
-             record_value_for_reg (reg, first, x);
-           }
+      /* Determine, if possible, whether all call sites of the current
+         function lie within the current compilation unit.  (This does
+        take into account the exporting of a function via taking its
+        address, and so forth.)  */
+      if (flag_unit_at_a_time)
+       strictly_local = cgraph_local_info (current_function_decl)->local;
+
+      /* The mode and signedness of the argument before any promotions happen
+         (equal to the mode of the pseudo holding it at that stage).  */
+      mode1 = TYPE_MODE (TREE_TYPE (arg));
+      uns1 = TYPE_UNSIGNED (TREE_TYPE (arg));
+
+      /* The mode and signedness of the argument after any source language and
+         TARGET_PROMOTE_PROTOTYPES-driven promotions.  */
+      mode2 = TYPE_MODE (DECL_ARG_TYPE (arg));
+      uns3 = TYPE_UNSIGNED (DECL_ARG_TYPE (arg));
+
+      /* The mode and signedness of the argument as it is actually passed, 
+         after any TARGET_PROMOTE_FUNCTION_ARGS-driven ABI promotions.  */
+      mode3 = promote_mode (DECL_ARG_TYPE (arg), mode2, &uns3, 1);
+
+      /* The mode of the register in which the argument is being passed.  */
+      mode4 = GET_MODE (reg);
+
+      /* Eliminate sign extensions in the callee when possible.  Only
+         do this when:
+        (a) a mode promotion has occurred;
+        (b) the mode of the register is the same as the mode of
+            the argument as it is passed; and
+        (c) the signedness does not change across any of the promotions; and
+        (d) when no language-level promotions (which we cannot guarantee
+            will have been done by an external caller) are necessary,
+            unless we know that this function is only ever called from
+            the current compilation unit -- all of whose call sites will
+            do the mode1 --> mode2 promotion.  */
+      if (mode1 != mode3
+          && mode3 == mode4
+          && uns1 == uns3
+         && (mode1 == mode2 || strictly_local))
+        {
+         /* Record that the value was promoted from mode1 to mode3,
+            so that any sign extension at the head of the current
+            function may be eliminated.  */
+         rtx x;
+         x = gen_rtx_CLOBBER (mode1, const0_rtx);
+         x = gen_rtx_fmt_e ((uns3 ? ZERO_EXTEND : SIGN_EXTEND), mode3, x);
+         record_value_for_reg (reg, first, x);
        }
     }
 }
-\f
+
 /* Called via note_stores.  If X is a pseudo that is narrower than
    HOST_BITS_PER_WIDE_INT and is being set, record what bits are known zero.
 
@@ -1341,7 +1416,7 @@ setup_incoming_promotions (rtx first)
    by any set of X.  */
 
 static void
-set_nonzero_bits_and_sign_copies (rtx x, rtx set, void *data)
+set_nonzero_bits_and_sign_copies (rtx x, const_rtx set, void *data)
 {
   rtx insn = (rtx) data;
   unsigned int num;
@@ -1354,10 +1429,12 @@ set_nonzero_bits_and_sign_copies (rtx x, rtx set, void *data)
            (DF_LR_IN (ENTRY_BLOCK_PTR->next_bb), REGNO (x))
       && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT)
     {
+      reg_stat_type *rsp = VEC_index (reg_stat_type, reg_stat, REGNO (x));
+
       if (set == 0 || GET_CODE (set) == CLOBBER)
        {
-         reg_stat[REGNO (x)].nonzero_bits = GET_MODE_MASK (GET_MODE (x));
-         reg_stat[REGNO (x)].sign_bit_copies = 1;
+         rsp->nonzero_bits = GET_MODE_MASK (GET_MODE (x));
+         rsp->sign_bit_copies = 1;
          return;
        }
 
@@ -1388,8 +1465,8 @@ set_nonzero_bits_and_sign_copies (rtx x, rtx set, void *data)
            }
          if (!link)
            {
-             reg_stat[REGNO (x)].nonzero_bits = GET_MODE_MASK (GET_MODE (x));
-             reg_stat[REGNO (x)].sign_bit_copies = 1;
+             rsp->nonzero_bits = GET_MODE_MASK (GET_MODE (x));
+             rsp->sign_bit_copies = 1;
              return;
            }
        }
@@ -1431,18 +1508,17 @@ set_nonzero_bits_and_sign_copies (rtx x, rtx set, void *data)
 #endif
 
          /* Don't call nonzero_bits if it cannot change anything.  */
-         if (reg_stat[REGNO (x)].nonzero_bits != ~(unsigned HOST_WIDE_INT) 0)
-           reg_stat[REGNO (x)].nonzero_bits
-             |= nonzero_bits (src, nonzero_bits_mode);
+         if (rsp->nonzero_bits != ~(unsigned HOST_WIDE_INT) 0)
+           rsp->nonzero_bits |= nonzero_bits (src, nonzero_bits_mode);
          num = num_sign_bit_copies (SET_SRC (set), GET_MODE (x));
-         if (reg_stat[REGNO (x)].sign_bit_copies == 0
-             || reg_stat[REGNO (x)].sign_bit_copies > num)
-           reg_stat[REGNO (x)].sign_bit_copies = num;
+         if (rsp->sign_bit_copies == 0
+             || rsp->sign_bit_copies > num)
+           rsp->sign_bit_copies = num;
        }
       else
        {
-         reg_stat[REGNO (x)].nonzero_bits = GET_MODE_MASK (GET_MODE (x));
-         reg_stat[REGNO (x)].sign_bit_copies = 1;
+         rsp->nonzero_bits = GET_MODE_MASK (GET_MODE (x));
+         rsp->sign_bit_copies = 1;
        }
     }
 }
@@ -1462,7 +1538,8 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
               rtx *pdest, rtx *psrc)
 {
   int i;
-  rtx set = 0, src, dest;
+  const_rtx set = 0;
+  rtx src, dest;
   rtx p;
 #ifdef AUTO_INC_DEC
   rtx link;
@@ -1582,7 +1659,7 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
   /* Don't eliminate a store in the stack pointer.  */
   if (dest == stack_pointer_rtx
       /* Don't combine with an insn that sets a register to itself if it has
-        a REG_EQUAL note.  This may be part of a REG_NO_CONFLICT sequence.  */
+        a REG_EQUAL note.  This may be part of a LIBCALL sequence.  */
       || (rtx_equal_p (src, dest) && find_reg_note (insn, REG_EQUAL, NULL_RTX))
       /* Can't merge an ASM_OPERANDS.  */
       || GET_CODE (src) == ASM_OPERANDS
@@ -1625,15 +1702,11 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
               && use_crosses_set_p (src, DF_INSN_LUID (insn)))
              || (GET_CODE (src) == ASM_OPERANDS && MEM_VOLATILE_P (src))
              || GET_CODE (src) == UNSPEC_VOLATILE))
-      /* If there is a REG_NO_CONFLICT note for DEST in I3 or SUCC, we get
-        better register allocation by not doing the combine.  */
-      || find_reg_note (i3, REG_NO_CONFLICT, dest)
-      || (succ && find_reg_note (succ, REG_NO_CONFLICT, dest))
       /* Don't combine across a CALL_INSN, because that would possibly
         change whether the life span of some REGs crosses calls or not,
         and it is a pain to update that information.
         Exception: if source is a constant, moving it later can't hurt.
-        Accept that special case, because it helps -fforce-addr a lot.  */
+        Accept that as a special case.  */
       || (DF_INSN_LUID (insn) < last_call_luid && ! CONSTANT_P (src)))
     return 0;
 
@@ -1971,7 +2044,7 @@ struct likely_spilled_retval_info
 /* Called via note_stores by likely_spilled_retval_p.  Remove from info->mask
    hard registers that are known to be written to / clobbered in full.  */
 static void
-likely_spilled_retval_1 (rtx x, rtx set, void *data)
+likely_spilled_retval_1 (rtx x, const_rtx set, void *data)
 {
   struct likely_spilled_retval_info *info = data;
   unsigned regno, nregs;
@@ -2057,6 +2130,8 @@ adjust_for_new_dest (rtx insn)
      of an insn just above it.  Call distribute_links to make a LOG_LINK from
      the next use of that destination.  */
   distribute_links (gen_rtx_INSN_LIST (VOIDmode, insn, NULL_RTX));
+
+  df_insn_rescan (insn);
 }
 
 /* Return TRUE if combine can reuse reg X in mode MODE.
@@ -2157,6 +2232,8 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
   int maxreg;
   rtx temp;
   rtx link;
+  rtx other_pat = 0;
+  rtx new_other_notes;
   int i;
 
   /* Exit early if one of the insns involved can't be used for
@@ -2686,12 +2763,17 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
 
   if (i1 && GET_CODE (newpat) != CLOBBER)
     {
-      /* Before we can do this substitution, we must redo the test done
-        above (see detailed comments there) that ensures  that I1DEST
-        isn't mentioned in any SETs in NEWPAT that are field assignments.  */
-
-      if (! combinable_i3pat (NULL_RTX, &newpat, i1dest, NULL_RTX,
-                             0, (rtx*) 0))
+      /* Check that an autoincrement side-effect on I1 has not been lost.
+        This happens if I1DEST is mentioned in I2 and dies there, and
+        has disappeared from the new pattern.  */
+      if ((FIND_REG_INC_NOTE (i1, NULL_RTX) != 0
+          && !i1_feeds_i3
+          && dead_or_set_p (i2, i1dest)
+          && !reg_overlap_mentioned_p (i1dest, newpat))
+         /* Before we can do this substitution, we must redo the test done
+            above (see detailed comments there) that ensures  that I1DEST
+            isn't mentioned in any SETs in NEWPAT that are field assignments.  */
+          || !combinable_i3pat (NULL_RTX, &newpat, i1dest, NULL_RTX, 0, 0))
        {
          undo_all ();
          return 0;
@@ -2862,13 +2944,13 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
   if (i1 && insn_code_number < 0 && GET_CODE (newpat) == SET
       && asm_noperands (newpat) < 0)
     {
-      rtx m_split, *split;
+      rtx parallel, m_split, *split;
 
       /* See if the MD file can split NEWPAT.  If it can't, see if letting it
         use I2DEST as a scratch register will help.  In the latter case,
         convert I2DEST to the mode of the source of NEWPAT if we can.  */
 
-      m_split = split_insns (newpat, i3);
+      m_split = combine_split_insns (newpat, i3);
 
       /* We can only use I2DEST as a scratch reg if it doesn't overlap any
         inputs of NEWPAT.  */
@@ -2883,12 +2965,11 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
 
          /* First try to split using the original register as a
             scratch register.  */
-         m_split = split_insns (gen_rtx_PARALLEL
-                                (VOIDmode,
-                                 gen_rtvec (2, newpat,
-                                            gen_rtx_CLOBBER (VOIDmode,
-                                                             i2dest))),
-                                i3);
+         parallel = gen_rtx_PARALLEL (VOIDmode,
+                                      gen_rtvec (2, newpat,
+                                                 gen_rtx_CLOBBER (VOIDmode,
+                                                                  i2dest)));
+         m_split = combine_split_insns (parallel, i3);
 
          /* If that didn't work, try changing the mode of I2DEST if
             we can.  */
@@ -2908,19 +2989,19 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
                  ni2dest = regno_reg_rtx[REGNO (i2dest)];
                }
 
-             m_split = split_insns (gen_rtx_PARALLEL
-                                    (VOIDmode,
-                                     gen_rtvec (2, newpat,
-                                                gen_rtx_CLOBBER (VOIDmode,
-                                                                 ni2dest))),
-                                    i3);
+             parallel = (gen_rtx_PARALLEL
+                         (VOIDmode,
+                          gen_rtvec (2, newpat,
+                                     gen_rtx_CLOBBER (VOIDmode,
+                                                      ni2dest))));
+             m_split = combine_split_insns (parallel, i3);
 
              if (m_split == 0
                  && REGNO (i2dest) >= FIRST_PSEUDO_REGISTER)
                {
                  struct undo *buf;
 
-                 PUT_MODE (regno_reg_rtx[REGNO (i2dest)], old_mode);
+                 adjust_reg_mode (regno_reg_rtx[REGNO (i2dest)], old_mode);
                  buf = undobuf.undos;
                  undobuf.undos = buf->next;
                  buf->next = undobuf.frees;
@@ -2932,9 +3013,10 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
       /* If recog_for_combine has discarded clobbers, try to use them
         again for the split.  */
       if (m_split == 0 && newpat_vec_with_clobbers)
-       m_split
-         = split_insns (gen_rtx_PARALLEL (VOIDmode,
-                                          newpat_vec_with_clobbers), i3);
+       {
+         parallel = gen_rtx_PARALLEL (VOIDmode, newpat_vec_with_clobbers);
+         m_split = combine_split_insns (parallel, i3);
+       }
 
       if (m_split && NEXT_INSN (m_split) == NULL_RTX)
        {
@@ -3184,18 +3266,22 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
           && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != STRICT_LOW_PART
           && ! (temp = SET_DEST (XVECEXP (newpat, 0, 1)),
                 (REG_P (temp)
-                 && reg_stat[REGNO (temp)].nonzero_bits != 0
+                 && VEC_index (reg_stat_type, reg_stat,
+                               REGNO (temp))->nonzero_bits != 0
                  && GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD
                  && GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT
-                 && (reg_stat[REGNO (temp)].nonzero_bits
+                 && (VEC_index (reg_stat_type, reg_stat,
+                                REGNO (temp))->nonzero_bits
                      != GET_MODE_MASK (word_mode))))
           && ! (GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) == SUBREG
                 && (temp = SUBREG_REG (SET_DEST (XVECEXP (newpat, 0, 1))),
                     (REG_P (temp)
-                     && reg_stat[REGNO (temp)].nonzero_bits != 0
+                     && VEC_index (reg_stat_type, reg_stat,
+                                   REGNO (temp))->nonzero_bits != 0
                      && GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD
                      && GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT
-                     && (reg_stat[REGNO (temp)].nonzero_bits
+                     && (VEC_index (reg_stat_type, reg_stat,
+                                    REGNO (temp))->nonzero_bits
                          != GET_MODE_MASK (word_mode)))))
           && ! reg_overlap_mentioned_p (SET_DEST (XVECEXP (newpat, 0, 1)),
                                         SET_SRC (XVECEXP (newpat, 0, 1)))
@@ -3283,12 +3369,9 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
   /* If we had to change another insn, make sure it is valid also.  */
   if (undobuf.other_insn)
     {
-      rtx other_pat = PATTERN (undobuf.other_insn);
-      rtx new_other_notes;
-      rtx note, next;
-
       CLEAR_HARD_REG_SET (newpat_used_regs);
 
+      other_pat = PATTERN (undobuf.other_insn);
       other_code_number = recog_for_combine (&other_pat, undobuf.other_insn,
                                             &new_other_notes);
 
@@ -3297,24 +3380,8 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
          undo_all ();
          return 0;
        }
-
-      PATTERN (undobuf.other_insn) = other_pat;
-
-      /* If any of the notes in OTHER_INSN were REG_UNUSED, ensure that they
-        are still valid.  Then add any non-duplicate notes added by
-        recog_for_combine.  */
-      for (note = REG_NOTES (undobuf.other_insn); note; note = next)
-       {
-         next = XEXP (note, 1);
-
-         if (REG_NOTE_KIND (note) == REG_UNUSED
-             && ! reg_set_p (XEXP (note, 0), PATTERN (undobuf.other_insn)))
-           remove_note (undobuf.other_insn, note);
-       }
-
-      distribute_notes (new_other_notes, undobuf.other_insn,
-                       undobuf.other_insn, NULL_RTX, NULL_RTX, NULL_RTX);
     }
+
 #ifdef HAVE_cc0
   /* If I2 is the CC0 setter and I3 is the CC0 user then check whether
      they are adjacent to each other or not.  */
@@ -3331,7 +3398,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
 
   /* Only allow this combination if insn_rtx_costs reports that the
      replacement instructions are cheaper than the originals.  */
-  if (!combine_validate_cost (i1, i2, i3, newpat, newi2pat))
+  if (!combine_validate_cost (i1, i2, i3, newpat, newi2pat, other_pat))
     {
       undo_all ();
       return 0;
@@ -3340,6 +3407,28 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
   /* We now know that we can do this combination.  Merge the insns and
      update the status of registers and LOG_LINKS.  */
 
+  if (undobuf.other_insn)
+    {
+      rtx note, next;
+
+      PATTERN (undobuf.other_insn) = other_pat;
+
+      /* If any of the notes in OTHER_INSN were REG_UNUSED, ensure that they
+        are still valid.  Then add any non-duplicate notes added by
+        recog_for_combine.  */
+      for (note = REG_NOTES (undobuf.other_insn); note; note = next)
+       {
+         next = XEXP (note, 1);
+
+         if (REG_NOTE_KIND (note) == REG_UNUSED
+             && ! reg_set_p (XEXP (note, 0), PATTERN (undobuf.other_insn)))
+           remove_note (undobuf.other_insn, note);
+       }
+
+      distribute_notes (new_other_notes, undobuf.other_insn,
+                       undobuf.other_insn, NULL_RTX, NULL_RTX, NULL_RTX);
+    }
+
   if (swap_i2i3)
     {
       rtx insn;
@@ -3754,7 +3843,7 @@ undo_all (void)
          *undo->where.i = undo->old_contents.i;
          break;
        case UNDO_MODE:
-         PUT_MODE (*undo->where.r, undo->old_contents.m);
+         adjust_reg_mode (*undo->where.r, undo->old_contents.m);
          break;
        default:
          gcc_unreachable ();
@@ -3839,8 +3928,9 @@ find_split_point (rtx *loc, rtx insn)
          && ! memory_address_p (GET_MODE (x), XEXP (x, 0)))
        {
          rtx reg = regno_reg_rtx[FIRST_PSEUDO_REGISTER];
-         rtx seq = split_insns (gen_rtx_SET (VOIDmode, reg, XEXP (x, 0)),
-                                subst_insn);
+         rtx seq = combine_split_insns (gen_rtx_SET (VOIDmode, reg,
+                                                     XEXP (x, 0)),
+                                        subst_insn);
 
          /* This should have produced two insns, each of which sets our
             placeholder.  If the source of the second is a valid address,
@@ -3894,6 +3984,15 @@ find_split_point (rtx *loc, rtx insn)
                         && OBJECT_P (SUBREG_REG (XEXP (XEXP (x, 0), 0)))))
            return &XEXP (XEXP (x, 0), 0);
        }
+
+      /* If we have a PLUS whose first operand is complex, try computing it
+         separately by making a split there.  */
+      if (GET_CODE (XEXP (x, 0)) == PLUS
+          && ! memory_address_p (GET_MODE (x), XEXP (x, 0))
+          && ! OBJECT_P (XEXP (XEXP (x, 0), 0))
+          && ! (GET_CODE (XEXP (XEXP (x, 0), 0)) == SUBREG
+                && OBJECT_P (SUBREG_REG (XEXP (XEXP (x, 0), 0)))))
+        return &XEXP (XEXP (x, 0), 0);
       break;
 
     case SET:
@@ -4444,6 +4543,18 @@ subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
        }
     }
 
+  /* Check if we are loading something from the constant pool via float
+     extension; in this case we would undo compress_float_constant
+     optimization and degenerate constant load to an immediate value.  */
+  if (GET_CODE (x) == FLOAT_EXTEND
+      && MEM_P (XEXP (x, 0))
+      && MEM_READONLY_P (XEXP (x, 0)))
+    {
+      rtx tmp = avoid_constant_pool_reference (x);
+      if (x != tmp)
+        return x;
+    }
+
   /* Try to simplify X.  If the simplification changed the code, it is likely
      that further simplification will help, so loop, but limit the number
      of repetitions that will be performed.  */
@@ -4653,7 +4764,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
        || code == AND || code == IOR || code == XOR
        || code == SMAX || code == SMIN || code == UMAX || code == UMIN)
       && ((INTEGRAL_MODE_P (mode) && code != DIV)
-         || (flag_unsafe_math_optimizations && FLOAT_MODE_P (mode))))
+         || (flag_associative_math && FLOAT_MODE_P (mode))))
     {
       if (GET_CODE (XEXP (x, 0)) == code)
        {
@@ -4926,7 +5037,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
        }
 
       /* Try simplify a*(b/c) as (a*b)/c.  */
-      if (FLOAT_MODE_P (mode) && flag_unsafe_math_optimizations
+      if (FLOAT_MODE_P (mode) && flag_associative_math 
          && GET_CODE (XEXP (x, 0)) == DIV)
        {
          rtx tem = simplify_binary_operation (MULT, mode,
@@ -5294,9 +5405,10 @@ simplify_if_then_else (rtx x)
   /* Look for cases where we have (abs x) or (neg (abs X)).  */
 
   if (GET_MODE_CLASS (mode) == MODE_INT
+      && comparison_p
+      && XEXP (cond, 1) == const0_rtx
       && GET_CODE (false_rtx) == NEG
       && rtx_equal_p (true_rtx, XEXP (false_rtx, 0))
-      && comparison_p
       && rtx_equal_p (true_rtx, XEXP (cond, 0))
       && ! side_effects_p (true_rtx))
     switch (true_code)
@@ -6136,8 +6248,8 @@ expand_compound_operation (rtx x)
    We half-heartedly support variable positions, but do not at all
    support variable lengths.  */
 
-static rtx
-expand_field_assignment (rtx x)
+static const_rtx
+expand_field_assignment (const_rtx x)
 {
   rtx inner;
   rtx pos;                     /* Always counts from low bit.  */
@@ -8589,33 +8701,35 @@ simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
    a shift, AND, or zero_extract, we can do better.  */
 
 static rtx
-reg_nonzero_bits_for_combine (rtx x, enum machine_mode mode,
-                             rtx known_x ATTRIBUTE_UNUSED,
+reg_nonzero_bits_for_combine (const_rtx x, enum machine_mode mode,
+                             const_rtx known_x ATTRIBUTE_UNUSED,
                              enum machine_mode known_mode ATTRIBUTE_UNUSED,
                              unsigned HOST_WIDE_INT known_ret ATTRIBUTE_UNUSED,
                              unsigned HOST_WIDE_INT *nonzero)
 {
   rtx tem;
+  reg_stat_type *rsp;
 
   /* If X is a register whose nonzero bits value is current, use it.
      Otherwise, if X is a register whose value we can find, use that
      value.  Otherwise, use the previously-computed global nonzero bits
      for this register.  */
 
-  if (reg_stat[REGNO (x)].last_set_value != 0
-      && (reg_stat[REGNO (x)].last_set_mode == mode
-         || (GET_MODE_CLASS (reg_stat[REGNO (x)].last_set_mode) == MODE_INT
+  rsp = VEC_index (reg_stat_type, reg_stat, REGNO (x));
+  if (rsp->last_set_value != 0
+      && (rsp->last_set_mode == mode
+         || (GET_MODE_CLASS (rsp->last_set_mode) == MODE_INT
              && GET_MODE_CLASS (mode) == MODE_INT))
-      && ((reg_stat[REGNO (x)].last_set_label >= label_tick_ebb_start
-          && reg_stat[REGNO (x)].last_set_label < label_tick)
-         || (reg_stat[REGNO (x)].last_set_label == label_tick
-              && DF_INSN_LUID (reg_stat[REGNO (x)].last_set) < subst_low_luid)
+      && ((rsp->last_set_label >= label_tick_ebb_start
+          && rsp->last_set_label < label_tick)
+         || (rsp->last_set_label == label_tick
+              && DF_INSN_LUID (rsp->last_set) < subst_low_luid)
          || (REGNO (x) >= FIRST_PSEUDO_REGISTER
              && REG_N_SETS (REGNO (x)) == 1
              && !REGNO_REG_SET_P
                  (DF_LR_IN (ENTRY_BLOCK_PTR->next_bb), REGNO (x)))))
     {
-      *nonzero &= reg_stat[REGNO (x)].last_set_nonzero_bits;
+      *nonzero &= rsp->last_set_nonzero_bits;
       return NULL;
     }
 
@@ -8645,9 +8759,9 @@ reg_nonzero_bits_for_combine (rtx x, enum machine_mode mode,
 #endif
       return tem;
     }
-  else if (nonzero_sign_valid && reg_stat[REGNO (x)].nonzero_bits)
+  else if (nonzero_sign_valid && rsp->nonzero_bits)
     {
-      unsigned HOST_WIDE_INT mask = reg_stat[REGNO (x)].nonzero_bits;
+      unsigned HOST_WIDE_INT mask = rsp->nonzero_bits;
 
       if (GET_MODE_BITSIZE (GET_MODE (x)) < GET_MODE_BITSIZE (mode))
        /* We don't know anything about the upper bits.  */
@@ -8664,27 +8778,29 @@ reg_nonzero_bits_for_combine (rtx x, enum machine_mode mode,
    be between 1 and the number of bits in MODE.  */
 
 static rtx
-reg_num_sign_bit_copies_for_combine (rtx x, enum machine_mode mode,
-                                    rtx known_x ATTRIBUTE_UNUSED,
+reg_num_sign_bit_copies_for_combine (const_rtx x, enum machine_mode mode,
+                                    const_rtx known_x ATTRIBUTE_UNUSED,
                                     enum machine_mode known_mode
                                     ATTRIBUTE_UNUSED,
                                     unsigned int known_ret ATTRIBUTE_UNUSED,
                                     unsigned int *result)
 {
   rtx tem;
-
-  if (reg_stat[REGNO (x)].last_set_value != 0
-      && reg_stat[REGNO (x)].last_set_mode == mode
-      && ((reg_stat[REGNO (x)].last_set_label >= label_tick_ebb_start
-          && reg_stat[REGNO (x)].last_set_label < label_tick)
-         || (reg_stat[REGNO (x)].last_set_label == label_tick
-              && DF_INSN_LUID (reg_stat[REGNO (x)].last_set) < subst_low_luid)
+  reg_stat_type *rsp;
+
+  rsp = VEC_index (reg_stat_type, reg_stat, REGNO (x));
+  if (rsp->last_set_value != 0
+      && rsp->last_set_mode == mode
+      && ((rsp->last_set_label >= label_tick_ebb_start
+          && rsp->last_set_label < label_tick)
+         || (rsp->last_set_label == label_tick
+              && DF_INSN_LUID (rsp->last_set) < subst_low_luid)
          || (REGNO (x) >= FIRST_PSEUDO_REGISTER
              && REG_N_SETS (REGNO (x)) == 1
              && !REGNO_REG_SET_P
                  (DF_LR_IN (ENTRY_BLOCK_PTR->next_bb), REGNO (x)))))
     {
-      *result = reg_stat[REGNO (x)].last_set_sign_bit_copies;
+      *result = rsp->last_set_sign_bit_copies;
       return NULL;
     }
 
@@ -8692,9 +8808,9 @@ reg_num_sign_bit_copies_for_combine (rtx x, enum machine_mode mode,
   if (tem != 0)
     return tem;
 
-  if (nonzero_sign_valid && reg_stat[REGNO (x)].sign_bit_copies != 0
+  if (nonzero_sign_valid && rsp->sign_bit_copies != 0
       && GET_MODE_BITSIZE (GET_MODE (x)) == GET_MODE_BITSIZE (mode))
-    *result = reg_stat[REGNO (x)].sign_bit_copies;
+    *result = rsp->sign_bit_copies;
 
   return NULL;
 }
@@ -8711,7 +8827,7 @@ reg_num_sign_bit_copies_for_combine (rtx x, enum machine_mode mode,
    implies that it must be called from a define_split.  */
 
 unsigned int
-extended_count (rtx x, enum machine_mode mode, int unsignedp)
+extended_count (const_rtx x, enum machine_mode mode, int unsignedp)
 {
   if (nonzero_sign_valid == 0)
     return 0;
@@ -9254,6 +9370,9 @@ simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode,
          break;
 
        case NOT:
+         if (VECTOR_MODE_P (mode))
+           break;
+
          /* Make this fit the case below.  */
          varop = gen_rtx_XOR (mode, XEXP (varop, 0),
                               GEN_INT (GET_MODE_MASK (mode)));
@@ -9655,6 +9774,14 @@ recog_for_combine (rtx *pnewpat, rtx insn, rtx *pnotes)
   REG_NOTES (insn) = 0;
 
   insn_code_number = recog (pat, insn, &num_clobbers_to_add);
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      if (insn_code_number < 0)
+       fputs ("Failed to match this instruction:\n", dump_file);
+      else
+       fputs ("Successfully matched this instruction:\n", dump_file);
+      print_rtl_single (dump_file, pat);
+    }
 
   /* If it isn't, there is the possibility that we previously had an insn
      that clobbered some register as a side effect, but the combined
@@ -9681,6 +9808,14 @@ recog_for_combine (rtx *pnewpat, rtx insn, rtx *pnotes)
 
       PATTERN (insn) = pat;
       insn_code_number = recog (pat, insn, &num_clobbers_to_add);
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         if (insn_code_number < 0)
+           fputs ("Failed to match this instruction:\n", dump_file);
+         else
+           fputs ("Successfully matched this instruction:\n", dump_file);
+         print_rtl_single (dump_file, pat);
+       }
     }
   PATTERN (insn) = old_pat;
   REG_NOTES (insn) = old_notes;
@@ -10388,7 +10523,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
              && ((unsigned HOST_WIDE_INT) const_op
                  < (((unsigned HOST_WIDE_INT) 1
                      << (GET_MODE_BITSIZE (mode) - 1))))
-             && cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+             && optab_handler (cmp_optab, mode)->insn_code != CODE_FOR_nothing)
            {
              op0 = XEXP (op0, 0);
              continue;
@@ -10469,7 +10604,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
              && (unsigned_comparison_p || equality_comparison_p)
              && (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
              && ((unsigned HOST_WIDE_INT) const_op < GET_MODE_MASK (mode))
-             && cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+             && optab_handler (cmp_optab, mode)->insn_code != CODE_FOR_nothing)
            {
              op0 = XEXP (op0, 0);
              continue;
@@ -11130,7 +11265,10 @@ update_table_tick (rtx x)
       unsigned int r;
 
       for (r = regno; r < endregno; r++)
-       reg_stat[r].last_set_table_tick = label_tick;
+       {
+         reg_stat_type *rsp = VEC_index (reg_stat_type, reg_stat, r);
+         rsp->last_set_table_tick = label_tick;
+       }
 
       return;
     }
@@ -11188,6 +11326,7 @@ record_value_for_reg (rtx reg, rtx insn, rtx value)
   unsigned int regno = REGNO (reg);
   unsigned int endregno = END_REGNO (reg);
   unsigned int i;
+  reg_stat_type *rsp;
 
   /* If VALUE contains REG and we have a previous value for REG, substitute
      the previous value.  */
@@ -11228,15 +11367,17 @@ record_value_for_reg (rtx reg, rtx insn, rtx value)
      register.  */
   for (i = regno; i < endregno; i++)
     {
+      rsp = VEC_index (reg_stat_type, reg_stat, i);
+
       if (insn)
-       reg_stat[i].last_set = insn;
+       rsp->last_set = insn;
 
-      reg_stat[i].last_set_value = 0;
-      reg_stat[i].last_set_mode = 0;
-      reg_stat[i].last_set_nonzero_bits = 0;
-      reg_stat[i].last_set_sign_bit_copies = 0;
-      reg_stat[i].last_death = 0;
-      reg_stat[i].truncated_to_mode = 0;
+      rsp->last_set_value = 0;
+      rsp->last_set_mode = 0;
+      rsp->last_set_nonzero_bits = 0;
+      rsp->last_set_sign_bit_copies = 0;
+      rsp->last_death = 0;
+      rsp->truncated_to_mode = 0;
     }
 
   /* Mark registers that are being referenced in this value.  */
@@ -11252,41 +11393,43 @@ record_value_for_reg (rtx reg, rtx insn, rtx value)
 
   for (i = regno; i < endregno; i++)
     {
-      reg_stat[i].last_set_label = label_tick;
+      rsp = VEC_index (reg_stat_type, reg_stat, i);
+      rsp->last_set_label = label_tick;
       if (!insn
-         || (value && reg_stat[i].last_set_table_tick >= label_tick_ebb_start))
-       reg_stat[i].last_set_invalid = 1;
+         || (value && rsp->last_set_table_tick >= label_tick_ebb_start))
+       rsp->last_set_invalid = 1;
       else
-       reg_stat[i].last_set_invalid = 0;
+       rsp->last_set_invalid = 0;
     }
 
   /* The value being assigned might refer to X (like in "x++;").  In that
      case, we must replace it with (clobber (const_int 0)) to prevent
      infinite loops.  */
+  rsp = VEC_index (reg_stat_type, reg_stat, regno);
   if (value && ! get_last_value_validate (&value, insn,
-                                         reg_stat[regno].last_set_label, 0))
+                                         rsp->last_set_label, 0))
     {
       value = copy_rtx (value);
       if (! get_last_value_validate (&value, insn,
-                                    reg_stat[regno].last_set_label, 1))
+                                    rsp->last_set_label, 1))
        value = 0;
     }
 
   /* For the main register being modified, update the value, the mode, the
      nonzero bits, and the number of sign bit copies.  */
 
-  reg_stat[regno].last_set_value = value;
+  rsp->last_set_value = value;
 
   if (value)
     {
       enum machine_mode mode = GET_MODE (reg);
       subst_low_luid = DF_INSN_LUID (insn);
-      reg_stat[regno].last_set_mode = mode;
+      rsp->last_set_mode = mode;
       if (GET_MODE_CLASS (mode) == MODE_INT
          && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
        mode = nonzero_bits_mode;
-      reg_stat[regno].last_set_nonzero_bits = nonzero_bits (value, mode);
-      reg_stat[regno].last_set_sign_bit_copies
+      rsp->last_set_nonzero_bits = nonzero_bits (value, mode);
+      rsp->last_set_sign_bit_copies
        = num_sign_bit_copies (value, GET_MODE (reg));
     }
 }
@@ -11296,7 +11439,7 @@ record_value_for_reg (rtx reg, rtx insn, rtx value)
    set is occurring.  */
 
 static void
-record_dead_and_set_regs_1 (rtx dest, rtx setter, void *data)
+record_dead_and_set_regs_1 (rtx dest, const_rtx setter, void *data)
 {
   rtx record_dead_insn = (rtx) data;
 
@@ -11359,7 +11502,12 @@ record_dead_and_set_regs (rtx insn)
          unsigned int endregno = END_REGNO (XEXP (link, 0));
 
          for (i = regno; i < endregno; i++)
-           reg_stat[i].last_death = insn;
+           {
+             reg_stat_type *rsp;
+
+             rsp = VEC_index (reg_stat_type, reg_stat, i);
+             rsp->last_death = insn;
+           }
        }
       else if (REG_NOTE_KIND (link) == REG_INC)
        record_value_for_reg (XEXP (link, 0), insn, NULL_RTX);
@@ -11370,14 +11518,17 @@ record_dead_and_set_regs (rtx insn)
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
        if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
          {
-           reg_stat[i].last_set_invalid = 1;
-           reg_stat[i].last_set = insn;
-           reg_stat[i].last_set_value = 0;
-           reg_stat[i].last_set_mode = 0;
-           reg_stat[i].last_set_nonzero_bits = 0;
-           reg_stat[i].last_set_sign_bit_copies = 0;
-           reg_stat[i].last_death = 0;
-           reg_stat[i].truncated_to_mode = 0;
+           reg_stat_type *rsp;
+
+           rsp = VEC_index (reg_stat_type, reg_stat, i);
+           rsp->last_set_invalid = 1;
+           rsp->last_set = insn;
+           rsp->last_set_value = 0;
+           rsp->last_set_mode = 0;
+           rsp->last_set_nonzero_bits = 0;
+           rsp->last_set_sign_bit_copies = 0;
+           rsp->last_death = 0;
+           rsp->truncated_to_mode = 0;
          }
 
       last_call_luid = mem_last_set = DF_INSN_LUID (insn);
@@ -11413,6 +11564,8 @@ record_promoted_value (rtx insn, rtx subreg)
 
   for (links = LOG_LINKS (insn); links;)
     {
+      reg_stat_type *rsp;
+
       insn = XEXP (links, 0);
       set = single_set (insn);
 
@@ -11424,10 +11577,11 @@ record_promoted_value (rtx insn, rtx subreg)
          continue;
        }
 
-      if (reg_stat[regno].last_set == insn)
+      rsp = VEC_index (reg_stat_type, reg_stat, regno);
+      if (rsp->last_set == insn)
        {
          if (SUBREG_PROMOTED_UNSIGNED_P (subreg) > 0)
-           reg_stat[regno].last_set_nonzero_bits &= GET_MODE_MASK (mode);
+           rsp->last_set_nonzero_bits &= GET_MODE_MASK (mode);
        }
 
       if (REG_P (SET_SRC (set)))
@@ -11446,12 +11600,13 @@ record_promoted_value (rtx insn, rtx subreg)
    an explicit truncation.  */
 
 static bool
-reg_truncated_to_mode (enum machine_mode mode, rtx x)
+reg_truncated_to_mode (enum machine_mode mode, const_rtx x)
 {
-  enum machine_mode truncated = reg_stat[REGNO (x)].truncated_to_mode;
+  reg_stat_type *rsp = VEC_index (reg_stat_type, reg_stat, REGNO (x));
+  enum machine_mode truncated = rsp->truncated_to_mode;
 
   if (truncated == 0
-      || reg_stat[REGNO (x)].truncation_label < label_tick_ebb_start)
+      || rsp->truncation_label < label_tick_ebb_start)
     return false;
   if (GET_MODE_SIZE (truncated) <= GET_MODE_SIZE (mode))
     return true;
@@ -11461,14 +11616,17 @@ reg_truncated_to_mode (enum machine_mode mode, rtx x)
   return false;
 }
 
-/* X is a REG or a SUBREG.  If X is some sort of a truncation record
-   it.  For non-TRULY_NOOP_TRUNCATION targets we might be able to turn
-   a truncate into a subreg using this information.  */
+/* Callback for for_each_rtx.  If *P is a hard reg or a subreg record the mode
+   that the register is accessed in.  For non-TRULY_NOOP_TRUNCATION targets we
+   might be able to turn a truncate into a subreg using this information.
+   Return -1 if traversing *P is complete or 0 otherwise.  */
 
-static void
-record_truncated_value (rtx x)
+static int
+record_truncated_value (rtx *p, void *data ATTRIBUTE_UNUSED)
 {
+  rtx x = *p;
   enum machine_mode truncated_mode;
+  reg_stat_type *rsp;
 
   if (GET_CODE (x) == SUBREG && REG_P (SUBREG_REG (x)))
     {
@@ -11476,11 +11634,11 @@ record_truncated_value (rtx x)
       truncated_mode = GET_MODE (x);
 
       if (GET_MODE_SIZE (original_mode) <= GET_MODE_SIZE (truncated_mode))
-       return;
+       return -1;
 
       if (TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (truncated_mode),
                                 GET_MODE_BITSIZE (original_mode)))
-       return;
+       return -1;
 
       x = SUBREG_REG (x);
     }
@@ -11489,33 +11647,41 @@ record_truncated_value (rtx x)
   else if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
     truncated_mode = GET_MODE (x);
   else
-    return;
+    return 0;
 
-  if (reg_stat[REGNO (x)].truncated_to_mode == 0
-      || reg_stat[REGNO (x)].truncation_label < label_tick_ebb_start
+  rsp = VEC_index (reg_stat_type, reg_stat, REGNO (x));
+  if (rsp->truncated_to_mode == 0
+      || rsp->truncation_label < label_tick_ebb_start
       || (GET_MODE_SIZE (truncated_mode)
-         < GET_MODE_SIZE (reg_stat[REGNO (x)].truncated_to_mode)))
+         < GET_MODE_SIZE (rsp->truncated_to_mode)))
     {
-      reg_stat[REGNO (x)].truncated_to_mode = truncated_mode;
-      reg_stat[REGNO (x)].truncation_label = label_tick;
+      rsp->truncated_to_mode = truncated_mode;
+      rsp->truncation_label = label_tick;
     }
+
+  return -1;
 }
 
-/* Scan X for promoted SUBREGs and truncated REGs.  For each one
-   found, note what it implies to the registers used in it.  */
+/* Callback for note_uses.  Find hardregs and subregs of pseudos and
+   the modes they are used in.  This can help truning TRUNCATEs into
+   SUBREGs.  */
 
 static void
-check_conversions (rtx insn, rtx x)
+record_truncated_values (rtx *x, void *data ATTRIBUTE_UNUSED)
 {
-  if (GET_CODE (x) == SUBREG || REG_P (x))
-    {
-      if (GET_CODE (x) == SUBREG
-         && SUBREG_PROMOTED_VAR_P (x)
-         && REG_P (SUBREG_REG (x)))
-       record_promoted_value (insn, x);
+  for_each_rtx (x, record_truncated_value, NULL);
+}
 
-      record_truncated_value (x);
-    }
+/* Scan X for promoted SUBREGs.  For each one found,
+   note what it implies to the registers used in it.  */
+
+static void
+check_promoted_subreg (rtx insn, rtx x)
+{
+  if (GET_CODE (x) == SUBREG
+      && SUBREG_PROMOTED_VAR_P (x)
+      && REG_P (SUBREG_REG (x)))
+    record_promoted_value (insn, x);
   else
     {
       const char *format = GET_RTX_FORMAT (GET_CODE (x));
@@ -11525,13 +11691,13 @@ check_conversions (rtx insn, rtx x)
        switch (format[i])
          {
          case 'e':
-           check_conversions (insn, XEXP (x, i));
+           check_promoted_subreg (insn, XEXP (x, i));
            break;
          case 'V':
          case 'E':
            if (XVEC (x, i) != 0)
              for (j = 0; j < XVECLEN (x, i); j++)
-               check_conversions (insn, XVECEXP (x, i, j));
+               check_promoted_subreg (insn, XVECEXP (x, i, j));
            break;
          }
     }
@@ -11562,19 +11728,22 @@ get_last_value_validate (rtx *loc, rtx insn, int tick, int replace)
       unsigned int j;
 
       for (j = regno; j < endregno; j++)
-       if (reg_stat[j].last_set_invalid
-           /* If this is a pseudo-register that was only set once and not
-              live at the beginning of the function, it is always valid.  */
-           || (! (regno >= FIRST_PSEUDO_REGISTER
-                  && REG_N_SETS (regno) == 1
-                  && !REGNO_REG_SET_P
-                      (DF_LR_IN (ENTRY_BLOCK_PTR->next_bb), regno))
-               && reg_stat[j].last_set_label > tick))
+       {
+         reg_stat_type *rsp = VEC_index (reg_stat_type, reg_stat, j);
+         if (rsp->last_set_invalid
+             /* If this is a pseudo-register that was only set once and not
+                live at the beginning of the function, it is always valid.  */
+             || (! (regno >= FIRST_PSEUDO_REGISTER
+                    && REG_N_SETS (regno) == 1
+                    && (!REGNO_REG_SET_P
+                        (DF_LR_IN (ENTRY_BLOCK_PTR->next_bb), regno)))
+                 && rsp->last_set_label > tick))
          {
            if (replace)
              *loc = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
            return replace;
          }
+       }
 
       return 1;
     }
@@ -11642,10 +11811,11 @@ get_last_value_validate (rtx *loc, rtx insn, int tick, int replace)
    is known longer known reliably.  */
 
 static rtx
-get_last_value (rtx x)
+get_last_value (const_rtx x)
 {
   unsigned int regno;
   rtx value;
+  reg_stat_type *rsp;
 
   /* If this is a non-paradoxical SUBREG, get the value of its operand and
      then convert it to the desired mode.  If this is a paradoxical SUBREG,
@@ -11661,7 +11831,8 @@ get_last_value (rtx x)
     return 0;
 
   regno = REGNO (x);
-  value = reg_stat[regno].last_set_value;
+  rsp = VEC_index (reg_stat_type, reg_stat, regno);
+  value = rsp->last_set_value;
 
   /* If we don't have a value, or if it isn't for this basic block and
      it's either a hard register, set more than once, or it's a live
@@ -11674,7 +11845,7 @@ get_last_value (rtx x)
      block.  */
 
   if (value == 0
-      || (reg_stat[regno].last_set_label < label_tick_ebb_start
+      || (rsp->last_set_label < label_tick_ebb_start
          && (regno < FIRST_PSEUDO_REGISTER
              || REG_N_SETS (regno) != 1
              || REGNO_REG_SET_P
@@ -11683,21 +11854,21 @@ get_last_value (rtx x)
 
   /* If the value was set in a later insn than the ones we are processing,
      we can't use it even if the register was only set once.  */
-  if (reg_stat[regno].last_set_label == label_tick
-      && DF_INSN_LUID (reg_stat[regno].last_set) >= subst_low_luid)
+  if (rsp->last_set_label == label_tick
+      && DF_INSN_LUID (rsp->last_set) >= subst_low_luid)
     return 0;
 
   /* If the value has all its registers valid, return it.  */
-  if (get_last_value_validate (&value, reg_stat[regno].last_set,
-                              reg_stat[regno].last_set_label, 0))
+  if (get_last_value_validate (&value, rsp->last_set,
+                              rsp->last_set_label, 0))
     return value;
 
   /* Otherwise, make a copy and replace any invalid register with
      (clobber (const_int 0)).  If that fails for some reason, return 0.  */
 
   value = copy_rtx (value);
-  if (get_last_value_validate (&value, reg_stat[regno].last_set,
-                              reg_stat[regno].last_set_label, 1))
+  if (get_last_value_validate (&value, rsp->last_set,
+                              rsp->last_set_label, 1))
     return value;
 
   return 0;
@@ -11707,7 +11878,7 @@ get_last_value (rtx x)
    that is set in an instruction more recent than FROM_LUID.  */
 
 static int
-use_crosses_set_p (rtx x, int from_luid)
+use_crosses_set_p (const_rtx x, int from_luid)
 {
   const char *fmt;
   int i;
@@ -11725,10 +11896,13 @@ use_crosses_set_p (rtx x, int from_luid)
        return 1;
 #endif
       for (; regno < endreg; regno++)
-       if (reg_stat[regno].last_set
-           && reg_stat[regno].last_set_label == label_tick
-           && DF_INSN_LUID (reg_stat[regno].last_set) > from_luid)
-         return 1;
+       {
+         reg_stat_type *rsp = VEC_index (reg_stat_type, reg_stat, regno);
+         if (rsp->last_set
+             && rsp->last_set_label == label_tick
+             && DF_INSN_LUID (rsp->last_set) > from_luid)
+           return 1;
+       }
       return 0;
     }
 
@@ -11765,7 +11939,7 @@ static int reg_dead_flag;
    reg_dead_flag to 1 if X is a CLOBBER and to -1 it is a SET.  */
 
 static void
-reg_dead_at_p_1 (rtx dest, rtx x, void *data ATTRIBUTE_UNUSED)
+reg_dead_at_p_1 (rtx dest, const_rtx x, void *data ATTRIBUTE_UNUSED)
 {
   unsigned int regno, endregno;
 
@@ -11835,7 +12009,7 @@ reg_dead_at_p (rtx reg, rtx insn)
     }
 
   for (i = reg_dead_regno; i < reg_dead_endregno; i++)
-    if (REGNO_REG_SET_P (DF_LIVE_IN (block), i))
+    if (REGNO_REG_SET_P (df_get_live_in (block), i))
       return 0;
 
   return 1;
@@ -11975,7 +12149,7 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_luid, rtx to_insn,
   if (code == REG)
     {
       unsigned int regno = REGNO (x);
-      rtx where_dead = reg_stat[regno].last_death;
+      rtx where_dead = VEC_index (reg_stat_type, reg_stat, regno)->last_death;
 
       /* Don't move the register if it gets killed in between from and to.  */
       if (maybe_kill_insn && reg_set_p (x, maybe_kill_insn)
@@ -12297,7 +12471,6 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
          break;
 
        case REG_INC:
-       case REG_NO_CONFLICT:
          /* These notes say something about how a register is used.  They must
             be present on any use of the register in I2 or I3.  */
          if (reg_mentioned_p (XEXP (note, 0), PATTERN (i3)))
@@ -12312,7 +12485,8 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
            }
          break;
 
-       case REG_LABEL:
+       case REG_LABEL_TARGET:
+       case REG_LABEL_OPERAND:
          /* This can show up in several ways -- either directly in the
             pattern, or hidden off in the constant pool with (or without?)
             a REG_EQUAL note.  */
@@ -12335,34 +12509,33 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
                place = i2;
            }
 
-         /* Don't attach REG_LABEL note to a JUMP_INSN.  Add
-            a JUMP_LABEL instead or decrement LABEL_NUSES.  */
-         if (place && JUMP_P (place))
+         /* For REG_LABEL_TARGET on a JUMP_P, we prefer to put the note
+            as a JUMP_LABEL or decrement LABEL_NUSES if it's already
+            there.  */
+         if (place && JUMP_P (place)
+             && REG_NOTE_KIND (note) == REG_LABEL_TARGET
+             && (JUMP_LABEL (place) == NULL
+                 || JUMP_LABEL (place) == XEXP (note, 0)))
            {
              rtx label = JUMP_LABEL (place);
 
              if (!label)
                JUMP_LABEL (place) = XEXP (note, 0);
-             else
-               {
-                 gcc_assert (label == XEXP (note, 0));
-                 if (LABEL_P (label))
-                   LABEL_NUSES (label)--;
-               }
-             place = 0;
+             else if (LABEL_P (label))
+               LABEL_NUSES (label)--;
            }
-         if (place2 && JUMP_P (place2))
+
+         if (place2 && JUMP_P (place2)
+             && REG_NOTE_KIND (note) == REG_LABEL_TARGET
+             && (JUMP_LABEL (place2) == NULL
+                 || JUMP_LABEL (place2) == XEXP (note, 0)))
            {
              rtx label = JUMP_LABEL (place2);
 
              if (!label)
                JUMP_LABEL (place2) = XEXP (note, 0);
-             else
-               {
-                 gcc_assert (label == XEXP (note, 0));
-                 if (LABEL_P (label))
-                   LABEL_NUSES (label)--;
-               }
+             else if (LABEL_P (label))
+               LABEL_NUSES (label)--;
              place2 = 0;
            }
          break;
@@ -12374,15 +12547,6 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
             to simply delete it.  */
          break;
 
-       case REG_LIBCALL_ID:
-         /* If the insn previously containing this note still exists,
-            put it back where it was.  Otherwise move it to the previous
-            insn.  */
-         if (!NOTE_P (from_insn))
-           place = from_insn;
-         else
-           place = prev_real_insn (from_insn);
-         break;
        case REG_RETVAL:
          /* If the insn previously containing this note still exists,
             put it back where it was.  Otherwise move it to the previous
@@ -12611,7 +12775,7 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
          if (place && REG_NOTE_KIND (note) == REG_DEAD)
            {
              unsigned int regno = REGNO (XEXP (note, 0));
-
+             reg_stat_type *rsp = VEC_index (reg_stat_type, reg_stat, regno);
 
              if (dead_or_set_p (place, XEXP (note, 0))
                  || reg_bitfield_target_p (XEXP (note, 0), PATTERN (place)))
@@ -12619,12 +12783,12 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
                  /* Unless the register previously died in PLACE, clear
                     last_death.  [I no longer understand why this is
                     being done.] */
-                 if (reg_stat[regno].last_death != place)
-                   reg_stat[regno].last_death = 0;
+                 if (rsp->last_death != place)
+                   rsp->last_death = 0;
                  place = 0;
                }
              else
-               reg_stat[regno].last_death = place;
+               rsp->last_death = place;
 
              /* If this is a death note for a hard reg that is occupying
                 multiple registers, ensure that we are still using all
@@ -12891,8 +13055,10 @@ rest_of_handle_combine (void)
   return 0;
 }
 
-struct tree_opt_pass pass_combine =
+struct rtl_opt_pass pass_combine =
 {
+ {
+  RTL_PASS,
   "combine",                            /* name */
   gate_handle_combine,                  /* gate */
   rest_of_handle_combine,               /* execute */
@@ -12905,8 +13071,8 @@ struct tree_opt_pass pass_combine =
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
   TODO_dump_func |
-  TODO_df_finish |
+  TODO_df_finish | TODO_verify_rtl_sharing |
   TODO_ggc_collect,                     /* todo_flags_finish */
-  'c'                                   /* letter */
+ }
 };