OSDN Git Service

libunwind related patch from David Mosberger
[pf3gnuchains/gcc-fork.git] / gcc / rtlanal.c
index a738acb..0a0d4d4 100644 (file)
@@ -1,35 +1,48 @@
 /* Analyze RTL for C-Compiler
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+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 GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
 
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "toplev.h"
 #include "rtl.h"
-
-static void set_of_1           PARAMS ((rtx, rtx, void *));
-static void insn_dependent_p_1 PARAMS ((rtx, rtx, void *));
+#include "hard-reg-set.h"
+#include "insn-config.h"
+#include "recog.h"
+#include "tm_p.h"
+#include "flags.h"
+#include "basic-block.h"
+#include "real.h"
 
 /* Forward declarations */
-static int computed_jump_p_1   PARAMS ((rtx));
+static int global_reg_mentioned_p_1 (rtx *, void *);
+static void set_of_1 (rtx, rtx, void *);
+static void insn_dependent_p_1 (rtx, rtx, void *);
+static int rtx_referenced_p_1 (rtx *, void *);
+static int computed_jump_p_1 (rtx);
+static void parms_set (rtx, rtx, void *);
+static bool hoist_test_store (rtx, rtx, regset);
+static void hoist_update_store (rtx, rtx *, rtx, rtx);
 
 /* Bit flags that specify the machine subtype we are compiling for.
    Bits are tested using macros TARGET_... defined in the tm.h file
@@ -43,12 +56,11 @@ int target_flags;
    (within one function) and so is anything marked `unchanging'.  */
 
 int
-rtx_unstable_p (x)
-     rtx x;
+rtx_unstable_p (rtx x)
 {
-  register RTX_CODE code = GET_CODE (x);
-  register int i;
-  register const char *fmt;
+  RTX_CODE code = GET_CODE (x);
+  int i;
+  const char *fmt;
 
   switch (code)
     {
@@ -58,9 +70,11 @@ rtx_unstable_p (x)
     case QUEUED:
       return 1;
 
+    case ADDRESSOF:
     case CONST:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case SYMBOL_REF:
     case LABEL_REF:
       return 0;
@@ -68,7 +82,9 @@ rtx_unstable_p (x)
     case REG:
       /* As in rtx_varies_p, we have to use the actual rtx, not reg number.  */
       if (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
-         || x == arg_pointer_rtx || RTX_UNCHANGING_P (x))
+         /* The arg pointer varies if it is not a fixed register.  */
+         || (x == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM])
+         || RTX_UNCHANGING_P (x))
        return 0;
 #ifndef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
       /* ??? When call-clobbered, the value is stable modulo the restore
@@ -115,13 +131,11 @@ rtx_unstable_p (x)
    The frame pointer and the arg pointer are considered constant.  */
 
 int
-rtx_varies_p (x, for_alias)
-     rtx x;
-     int for_alias;
+rtx_varies_p (rtx x, int for_alias)
 {
-  register RTX_CODE code = GET_CODE (x);
-  register int i;
-  register const char *fmt;
+  RTX_CODE code = GET_CODE (x);
+  int i;
+  const char *fmt;
 
   switch (code)
     {
@@ -134,17 +148,23 @@ rtx_varies_p (x, for_alias)
     case CONST:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case SYMBOL_REF:
     case LABEL_REF:
       return 0;
 
+    case ADDRESSOF:
+      /* This will resolve to some offset from the frame pointer.  */
+      return 0;
+
     case REG:
       /* Note that we have to test for the actual rtx used for the frame
         and arg pointers and not just the register number in case we have
         eliminated the frame and/or arg pointer and are using it
         for pseudos.  */
       if (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
-         || x == arg_pointer_rtx)
+         /* The arg pointer varies if it is not a fixed register.  */
+         || (x == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM]))
        return 0;
       if (x == pic_offset_table_rtx
 #ifdef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
@@ -160,9 +180,11 @@ rtx_varies_p (x, for_alias)
 
     case LO_SUM:
       /* The operand 0 of a LO_SUM is considered constant
-        (in fact is it related specifically to operand 1).  */
-      return rtx_varies_p (XEXP (x, 1), for_alias);
-      
+        (in fact it is related specifically to operand 1)
+        during alias analysis.  */
+      return (! for_alias && rtx_varies_p (XEXP (x, 0), for_alias))
+            || rtx_varies_p (XEXP (x, 1), for_alias);
+
     case ASM_OPERANDS:
       if (MEM_VOLATILE_P (x))
        return 1;
@@ -194,25 +216,34 @@ rtx_varies_p (x, for_alias)
 /* Return 0 if the use of X as an address in a MEM can cause a trap.  */
 
 int
-rtx_addr_can_trap_p (x)
-     register rtx x;
+rtx_addr_can_trap_p (rtx x)
 {
-  register enum rtx_code code = GET_CODE (x);
+  enum rtx_code code = GET_CODE (x);
 
   switch (code)
     {
     case SYMBOL_REF:
+      return SYMBOL_REF_WEAK (x);
+
     case LABEL_REF:
-      /* SYMBOL_REF is problematic due to the possible presence of
-        a #pragma weak, but to say that loads from symbols can trap is
-        *very* costly.  It's not at all clear what's best here.  For
-        now, we ignore the impact of #pragma weak.  */
+      return 0;
+
+    case ADDRESSOF:
+      /* This will resolve to some offset from the frame pointer.  */
       return 0;
 
     case REG:
       /* As in rtx_varies_p, we have to use the actual rtx, not reg number.  */
-      return ! (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
-               || x == stack_pointer_rtx || x == arg_pointer_rtx);
+      if (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
+         || x == stack_pointer_rtx
+         /* The arg pointer varies if it is not a fixed register.  */
+         || (x == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM]))
+       return 0;
+      /* All of the virtual frame registers are stack references.  */
+      if (REGNO (x) >= FIRST_VIRTUAL_REGISTER
+         && REGNO (x) <= LAST_VIRTUAL_REGISTER)
+       return 0;
+      return 1;
 
     case CONST:
       return rtx_addr_can_trap_p (XEXP (x, 0));
@@ -227,8 +258,16 @@ rtx_addr_can_trap_p (x)
                    && CONSTANT_P (XEXP (x, 1))));
 
     case LO_SUM:
+    case PRE_MODIFY:
       return rtx_addr_can_trap_p (XEXP (x, 1));
-      
+
+    case PRE_DEC:
+    case PRE_INC:
+    case POST_DEC:
+    case POST_INC:
+    case POST_MODIFY:
+      return rtx_addr_can_trap_p (XEXP (x, 0));
+
     default:
       break;
     }
@@ -237,20 +276,101 @@ rtx_addr_can_trap_p (x)
   return 1;
 }
 
-/* Return 1 if X refers to a memory location whose address 
+/* Return true if X is an address that is known to not be zero.  */
+
+bool
+nonzero_address_p (rtx x)
+{
+  enum rtx_code code = GET_CODE (x);
+
+  switch (code)
+    {
+    case SYMBOL_REF:
+      return !SYMBOL_REF_WEAK (x);
+
+    case LABEL_REF:
+      return true;
+
+    case ADDRESSOF:
+      /* This will resolve to some offset from the frame pointer.  */
+      return true;
+
+    case REG:
+      /* As in rtx_varies_p, we have to use the actual rtx, not reg number.  */
+      if (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
+         || x == stack_pointer_rtx
+         || (x == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM]))
+       return true;
+      /* All of the virtual frame registers are stack references.  */
+      if (REGNO (x) >= FIRST_VIRTUAL_REGISTER
+         && REGNO (x) <= LAST_VIRTUAL_REGISTER)
+       return true;
+      return false;
+
+    case CONST:
+      return nonzero_address_p (XEXP (x, 0));
+
+    case PLUS:
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+       {
+         /* Pointers aren't allowed to wrap.  If we've got a register
+            that is known to be a pointer, and a positive offset, then
+            the composite can't be zero.  */
+         if (INTVAL (XEXP (x, 1)) > 0
+             && REG_P (XEXP (x, 0))
+             && REG_POINTER (XEXP (x, 0)))
+           return true;
+
+         return nonzero_address_p (XEXP (x, 0));
+       }
+      /* Handle PIC references.  */
+      else if (XEXP (x, 0) == pic_offset_table_rtx
+              && CONSTANT_P (XEXP (x, 1)))
+       return true;
+      return false;
+
+    case PRE_MODIFY:
+      /* Similar to the above; allow positive offsets.  Further, since
+        auto-inc is only allowed in memories, the register must be a
+        pointer.  */
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT
+         && INTVAL (XEXP (x, 1)) > 0)
+       return true;
+      return nonzero_address_p (XEXP (x, 0));
+
+    case PRE_INC:
+      /* Similarly.  Further, the offset is always positive.  */
+      return true;
+
+    case PRE_DEC:
+    case POST_DEC:
+    case POST_INC:
+    case POST_MODIFY:
+      return nonzero_address_p (XEXP (x, 0));
+
+    case LO_SUM:
+      return nonzero_address_p (XEXP (x, 1));
+
+    default:
+      break;
+    }
+
+  /* If it isn't one of the case above, might be zero.  */
+  return false;
+}
+
+/* Return 1 if X refers to a memory location whose address
    cannot be compared reliably with constant addresses,
-   or if X refers to a BLKmode memory object. 
+   or if X refers to a BLKmode memory object.
    FOR_ALIAS is nonzero if we are called from alias analysis; if it is
    zero, we are slightly more conservative.  */
 
 int
-rtx_addr_varies_p (x, for_alias)
-     rtx x;
-     int for_alias;
+rtx_addr_varies_p (rtx x, int for_alias)
 {
-  register enum rtx_code code;
-  register int i;
-  register const char *fmt;
+  enum rtx_code code;
+  int i;
+  const char *fmt;
 
   if (x == 0)
     return 0;
@@ -279,11 +399,10 @@ rtx_addr_varies_p (x, for_alias)
 /* Return the value of the integer term in X, if one is apparent;
    otherwise return 0.
    Only obvious integer terms are detected.
-   This is used in cse.c with the `related_value' field.*/
+   This is used in cse.c with the `related_value' field.  */
 
 HOST_WIDE_INT
-get_integer_term (x)
-     rtx x;
+get_integer_term (rtx x)
 {
   if (GET_CODE (x) == CONST)
     x = XEXP (x, 0);
@@ -302,8 +421,7 @@ get_integer_term (x)
    Only obvious integer terms are detected.  */
 
 rtx
-get_related_value (x)
-     rtx x;
+get_related_value (rtx x)
 {
   if (GET_CODE (x) != CONST)
     return 0;
@@ -317,13 +435,215 @@ get_related_value (x)
   return 0;
 }
 \f
+/* Given a tablejump insn INSN, return the RTL expression for the offset
+   into the jump table.  If the offset cannot be determined, then return
+   NULL_RTX.
+
+   If EARLIEST is nonzero, it is a pointer to a place where the earliest
+   insn used in locating the offset was found.  */
+
+rtx
+get_jump_table_offset (rtx insn, rtx *earliest)
+{
+  rtx label;
+  rtx table;
+  rtx set;
+  rtx old_insn;
+  rtx x;
+  rtx old_x;
+  rtx y;
+  rtx old_y;
+  int i;
+
+  if (!tablejump_p (insn, &label, &table) || !(set = single_set (insn)))
+    return NULL_RTX;
+
+  x = SET_SRC (set);
+
+  /* Some targets (eg, ARM) emit a tablejump that also
+     contains the out-of-range target.  */
+  if (GET_CODE (x) == IF_THEN_ELSE
+      && GET_CODE (XEXP (x, 2)) == LABEL_REF)
+    x = XEXP (x, 1);
+
+  /* Search backwards and locate the expression stored in X.  */
+  for (old_x = NULL_RTX; GET_CODE (x) == REG && x != old_x;
+       old_x = x, x = find_last_value (x, &insn, NULL_RTX, 0))
+    ;
+
+  /* If X is an expression using a relative address then strip
+     off the addition / subtraction of PC, PIC_OFFSET_TABLE_REGNUM,
+     or the jump table label.  */
+  if (GET_CODE (PATTERN (table)) == ADDR_DIFF_VEC
+      && (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS))
+    {
+      for (i = 0; i < 2; i++)
+       {
+         old_insn = insn;
+         y = XEXP (x, i);
+
+         if (y == pc_rtx || y == pic_offset_table_rtx)
+           break;
+
+         for (old_y = NULL_RTX; GET_CODE (y) == REG && y != old_y;
+              old_y = y, y = find_last_value (y, &old_insn, NULL_RTX, 0))
+           ;
+
+         if ((GET_CODE (y) == LABEL_REF && XEXP (y, 0) == label))
+           break;
+       }
+
+      if (i >= 2)
+       return NULL_RTX;
+
+      x = XEXP (x, 1 - i);
+
+      for (old_x = NULL_RTX; GET_CODE (x) == REG && x != old_x;
+          old_x = x, x = find_last_value (x, &insn, NULL_RTX, 0))
+       ;
+    }
+
+  /* Strip off any sign or zero extension.  */
+  if (GET_CODE (x) == SIGN_EXTEND || GET_CODE (x) == ZERO_EXTEND)
+    {
+      x = XEXP (x, 0);
+
+      for (old_x = NULL_RTX; GET_CODE (x) == REG && x != old_x;
+          old_x = x, x = find_last_value (x, &insn, NULL_RTX, 0))
+       ;
+    }
+
+  /* If X isn't a MEM then this isn't a tablejump we understand.  */
+  if (GET_CODE (x) != MEM)
+    return NULL_RTX;
+
+  /* Strip off the MEM.  */
+  x = XEXP (x, 0);
+
+  for (old_x = NULL_RTX; GET_CODE (x) == REG && x != old_x;
+       old_x = x, x = find_last_value (x, &insn, NULL_RTX, 0))
+    ;
+
+  /* If X isn't a PLUS than this isn't a tablejump we understand.  */
+  if (GET_CODE (x) != PLUS)
+    return NULL_RTX;
+
+  /* At this point we should have an expression representing the jump table
+     plus an offset.  Examine each operand in order to determine which one
+     represents the jump table.  Knowing that tells us that the other operand
+     must represent the offset.  */
+  for (i = 0; i < 2; i++)
+    {
+      old_insn = insn;
+      y = XEXP (x, i);
+
+      for (old_y = NULL_RTX; GET_CODE (y) == REG && y != old_y;
+          old_y = y, y = find_last_value (y, &old_insn, NULL_RTX, 0))
+       ;
+
+      if ((GET_CODE (y) == CONST || GET_CODE (y) == LABEL_REF)
+         && reg_mentioned_p (label, y))
+       break;
+    }
+
+  if (i >= 2)
+    return NULL_RTX;
+
+  x = XEXP (x, 1 - i);
+
+  /* Strip off the addition / subtraction of PIC_OFFSET_TABLE_REGNUM.  */
+  if (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS)
+    for (i = 0; i < 2; i++)
+      if (XEXP (x, i) == pic_offset_table_rtx)
+       {
+         x = XEXP (x, 1 - i);
+         break;
+       }
+
+  if (earliest)
+    *earliest = insn;
+
+  /* Return the RTL expression representing the offset.  */
+  return x;
+}
+\f
+/* A subroutine of global_reg_mentioned_p, returns 1 if *LOC mentions
+   a global register.  */
+
+static int
+global_reg_mentioned_p_1 (rtx *loc, void *data ATTRIBUTE_UNUSED)
+{
+  int regno;
+  rtx x = *loc;
+
+  if (! x)
+    return 0;
+
+  switch (GET_CODE (x))
+    {
+    case SUBREG:
+      if (GET_CODE (SUBREG_REG (x)) == REG)
+       {
+         if (REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER
+             && global_regs[subreg_regno (x)])
+           return 1;
+         return 0;
+       }
+      break;
+
+    case REG:
+      regno = REGNO (x);
+      if (regno < FIRST_PSEUDO_REGISTER && global_regs[regno])
+       return 1;
+      return 0;
+
+    case SCRATCH:
+    case PC:
+    case CC0:
+    case CONST_INT:
+    case CONST_DOUBLE:
+    case CONST:
+    case LABEL_REF:
+      return 0;
+
+    case CALL:
+      /* A non-constant call might use a global register.  */
+      return 1;
+
+    default:
+      break;
+    }
+
+  return 0;
+}
+
+/* Returns nonzero if X mentions a global register.  */
+
+int
+global_reg_mentioned_p (rtx x)
+{
+  if (INSN_P (x))
+    {
+      if (GET_CODE (x) == CALL_INSN)
+       {
+         if (! CONST_OR_PURE_CALL_P (x))
+           return 1;
+         x = CALL_INSN_FUNCTION_USAGE (x);
+         if (x == 0)
+           return 0;
+       }
+      else
+       x = PATTERN (x);
+    }
+
+  return for_each_rtx (&x, global_reg_mentioned_p_1, NULL);
+}
+\f
 /* Return the number of places FIND appears within X.  If COUNT_DEST is
    zero, we do not count occurrences inside the destination of a SET.  */
 
 int
-count_occurrences (x, find, count_dest)
-     rtx x, find;
-     int count_dest;
+count_occurrences (rtx x, rtx find, int count_dest)
 {
   int i, j;
   enum rtx_code code;
@@ -340,6 +660,7 @@ count_occurrences (x, find, count_dest)
     case REG:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case SYMBOL_REF:
     case CODE_LABEL:
     case PC:
@@ -385,12 +706,11 @@ count_occurrences (x, find, count_dest)
    for a subexpression of IN that is Lisp "equal" to REG.  */
 
 int
-reg_mentioned_p (reg, in)
-     register rtx reg, in;
+reg_mentioned_p (rtx reg, rtx in)
 {
-  register const char *fmt;
-  register int i;
-  register enum rtx_code code;
+  const char *fmt;
+  int i;
+  enum rtx_code code;
 
   if (in == 0)
     return 0;
@@ -417,12 +737,11 @@ reg_mentioned_p (reg, in)
       return 0;
 
     case CONST_INT:
-      return GET_CODE (reg) == CONST_INT && INTVAL (in) == INTVAL (reg);
-      
+    case CONST_VECTOR:
     case CONST_DOUBLE:
       /* These are kept unique for a given value.  */
       return 0;
-      
+
     default:
       break;
     }
@@ -436,7 +755,7 @@ reg_mentioned_p (reg, in)
     {
       if (fmt[i] == 'E')
        {
-         register int j;
+         int j;
          for (j = XVECLEN (in, i) - 1; j >= 0; j--)
            if (reg_mentioned_p (reg, XVECEXP (in, i, j)))
              return 1;
@@ -452,10 +771,11 @@ reg_mentioned_p (reg, in)
    no CODE_LABEL insn.  */
 
 int
-no_labels_between_p (beg, end)
-     rtx beg, end;
+no_labels_between_p (rtx beg, rtx end)
 {
-  register rtx p;
+  rtx p;
+  if (beg == end)
+    return 0;
   for (p = NEXT_INSN (beg); p != end; p = NEXT_INSN (p))
     if (GET_CODE (p) == CODE_LABEL)
       return 0;
@@ -466,10 +786,9 @@ no_labels_between_p (beg, end)
    no JUMP_INSN insn.  */
 
 int
-no_jumps_between_p (beg, end)
-     rtx beg, end;
+no_jumps_between_p (rtx beg, rtx end)
 {
-  register rtx p;
+  rtx p;
   for (p = NEXT_INSN (beg); p != end; p = NEXT_INSN (p))
     if (GET_CODE (p) == JUMP_INSN)
       return 0;
@@ -480,10 +799,9 @@ no_jumps_between_p (beg, end)
    FROM_INSN and TO_INSN (exclusive of those two).  */
 
 int
-reg_used_between_p (reg, from_insn, to_insn)
-     rtx reg, from_insn, to_insn;
+reg_used_between_p (rtx reg, rtx from_insn, rtx to_insn)
 {
-  register rtx insn;
+  rtx insn;
 
   if (from_insn == to_insn)
     return 0;
@@ -503,9 +821,7 @@ reg_used_between_p (reg, from_insn, to_insn)
    we do not consider it a reference.  */
 
 int
-reg_referenced_p (x, body)
-     rtx x;
-     rtx body;
+reg_referenced_p (rtx x, rtx body)
 {
   int i;
 
@@ -545,6 +861,9 @@ reg_referenced_p (x, body)
     case TRAP_IF:
       return reg_overlap_mentioned_p (x, TRAP_CONDITION (body));
 
+    case PREFETCH:
+      return reg_overlap_mentioned_p (x, XEXP (body, 0));
+
     case UNSPEC:
     case UNSPEC_VOLATILE:
       for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
@@ -557,7 +876,7 @@ reg_referenced_p (x, body)
        if (reg_referenced_p (x, XVECEXP (body, 0, i)))
          return 1;
       return 0;
-      
+
     case CLOBBER:
       if (GET_CODE (XEXP (body, 0)) == MEM)
        if (reg_overlap_mentioned_p (x, XEXP (XEXP (body, 0), 0)))
@@ -579,10 +898,9 @@ reg_referenced_p (x, body)
    not count.  */
 
 int
-reg_referenced_between_p (reg, from_insn, to_insn)
-     rtx reg, from_insn, to_insn;
+reg_referenced_between_p (rtx reg, rtx from_insn, rtx to_insn)
 {
-  register rtx insn;
+  rtx insn;
 
   if (from_insn == to_insn)
     return 0;
@@ -600,10 +918,9 @@ reg_referenced_between_p (reg, from_insn, to_insn)
    FROM_INSN and TO_INSN (exclusive of those two).  */
 
 int
-reg_set_between_p (reg, from_insn, to_insn)
-     rtx reg, from_insn, to_insn;
+reg_set_between_p (rtx reg, rtx from_insn, rtx to_insn)
 {
-  register rtx insn;
+  rtx insn;
 
   if (from_insn == to_insn)
     return 0;
@@ -616,16 +933,12 @@ reg_set_between_p (reg, from_insn, to_insn)
 
 /* Internals of reg_set_between_p.  */
 int
-reg_set_p (reg, insn)
-     rtx reg, insn;
+reg_set_p (rtx reg, rtx insn)
 {
-  rtx body = insn;
-
   /* We can be passed an insn or part of one.  If we are passed an insn,
      check if a side-effect of the insn clobbers REG.  */
-  if (INSN_P (insn))
-    {
-      if (FIND_REG_INC_NOTE (insn, reg)
+  if (INSN_P (insn)
+      && (FIND_REG_INC_NOTE (insn, reg)
          || (GET_CODE (insn) == CALL_INSN
              /* We'd like to test call_used_regs here, but rtlanal.c can't
                 reference that variable due to its use in genattrtab.  So
@@ -636,11 +949,8 @@ reg_set_p (reg, insn)
              && ((GET_CODE (reg) == REG
                   && REGNO (reg) < FIRST_PSEUDO_REGISTER)
                  || GET_CODE (reg) == MEM
-                 || find_reg_fusage (insn, CLOBBER, reg))))
-       return 1;
-
-      body = PATTERN (insn);
-    }
+                 || find_reg_fusage (insn, CLOBBER, reg)))))
+    return 1;
 
   return set_of (reg, insn) != NULL_RTX;
 }
@@ -650,9 +960,7 @@ reg_set_p (reg, insn)
    consider non-registers one way or the other.  */
 
 int
-regs_set_between_p (x, start, end)
-     rtx x;
-     rtx start, end;
+regs_set_between_p (rtx x, rtx start, rtx end)
 {
   enum rtx_code code = GET_CODE (x);
   const char *fmt;
@@ -662,6 +970,7 @@ regs_set_between_p (x, start, end)
     {
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case CONST:
     case SYMBOL_REF:
     case LABEL_REF:
@@ -671,7 +980,7 @@ regs_set_between_p (x, start, end)
 
     case REG:
       return reg_set_between_p (x, start, end);
-      
+
     default:
       break;
     }
@@ -693,21 +1002,24 @@ regs_set_between_p (x, start, end)
 
 /* Similar to reg_set_between_p, but check all registers in X.  Return 0
    only if none of them are modified between START and END.  Return 1 if
-   X contains a MEM; this routine does not perform any memory aliasing.  */
+   X contains a MEM; this routine does usememory aliasing.  */
 
 int
-modified_between_p (x, start, end)
-     rtx x;
-     rtx start, end;
+modified_between_p (rtx x, rtx start, rtx end)
 {
   enum rtx_code code = GET_CODE (x);
   const char *fmt;
   int i, j;
+  rtx insn;
+
+  if (start == end)
+    return 0;
 
   switch (code)
     {
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case CONST:
     case SYMBOL_REF:
     case LABEL_REF:
@@ -718,15 +1030,19 @@ modified_between_p (x, start, end)
       return 1;
 
     case MEM:
-      /* If the memory is not constant, assume it is modified.  If it is
-        constant, we still have to check the address.  */
-      if (! RTX_UNCHANGING_P (x))
+      if (RTX_UNCHANGING_P (x))
+       return 0;
+      if (modified_between_p (XEXP (x, 0), start, end))
        return 1;
+      for (insn = NEXT_INSN (start); insn != end; insn = NEXT_INSN (insn))
+       if (memory_modified_in_insn_p (x, insn))
+         return 1;
+      return 0;
       break;
 
     case REG:
       return reg_set_between_p (x, start, end);
-      
+
     default:
       break;
     }
@@ -748,12 +1064,10 @@ modified_between_p (x, start, end)
 
 /* Similar to reg_set_p, but check all registers in X.  Return 0 only if none
    of them are modified in INSN.  Return 1 if X contains a MEM; this routine
-   does not perform any memory aliasing.  */
+   does use memory aliasing.  */
 
 int
-modified_in_p (x, insn)
-     rtx x;
-     rtx insn;
+modified_in_p (rtx x, rtx insn)
 {
   enum rtx_code code = GET_CODE (x);
   const char *fmt;
@@ -763,6 +1077,7 @@ modified_in_p (x, insn)
     {
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case CONST:
     case SYMBOL_REF:
     case LABEL_REF:
@@ -773,10 +1088,13 @@ modified_in_p (x, insn)
       return 1;
 
     case MEM:
-      /* If the memory is not constant, assume it is modified.  If it is
-        constant, we still have to check the address.  */
-      if (! RTX_UNCHANGING_P (x))
+      if (RTX_UNCHANGING_P (x))
+       return 0;
+      if (modified_in_p (XEXP (x, 0), insn))
        return 1;
+      if (memory_modified_in_insn_p (x, insn))
+       return 1;
+      return 0;
       break;
 
     case REG:
@@ -805,8 +1123,7 @@ modified_in_p (x, insn)
    anything in insn Y.  */
 
 int
-insn_dependent_p (x, y)
-     rtx x, y;
+insn_dependent_p (rtx x, rtx y)
 {
   rtx tmp;
 
@@ -829,10 +1146,7 @@ insn_dependent_p (x, y)
 /* A helper routine for insn_dependent_p called through note_stores.  */
 
 static void
-insn_dependent_p_1 (x, pat, data)
-     rtx x;
-     rtx pat ATTRIBUTE_UNUSED;
-     void *data;
+insn_dependent_p_1 (rtx x, rtx pat ATTRIBUTE_UNUSED, void *data)
 {
   rtx * pinsn = (rtx *) data;
 
@@ -848,10 +1162,7 @@ struct set_of_data
   };
 
 static void
-set_of_1 (x, pat, data1)
-     rtx x;
-     rtx pat;
-     void *data1;
+set_of_1 (rtx x, rtx pat, void *data1)
 {
    struct set_of_data *data = (struct set_of_data *) (data1);
    if (rtx_equal_p (x, data->pat)
@@ -860,10 +1171,9 @@ set_of_1 (x, pat, data1)
 }
 
 /* Give an INSN, return a SET or CLOBBER expression that does modify PAT
-   (eighter directly or via STRICT_LOW_PART and similar modifiers).  */
+   (either directly or via STRICT_LOW_PART and similar modifiers).  */
 rtx
-set_of (pat, insn)
-     rtx pat, insn;
+set_of (rtx pat, rtx insn)
 {
   struct set_of_data data;
   data.found = NULL_RTX;
@@ -877,8 +1187,7 @@ set_of (pat, insn)
    will not be used, which we ignore.  */
 
 rtx
-single_set_2 (insn, pat)
-     rtx insn, pat;
+single_set_2 (rtx insn, rtx pat)
 {
   rtx set = NULL;
   int set_verified = 1;
@@ -899,7 +1208,7 @@ single_set_2 (insn, pat)
              /* We can consider insns having multiple sets, where all
                 but one are dead as single set insns.  In common case
                 only single set is present in the pattern so we want
-                to avoid checking for REG_UNUSED notes unless neccesary.
+                to avoid checking for REG_UNUSED notes unless necessary.
 
                 When we reach set first time, we just expect this is
                 the single set we are looking for and only when more
@@ -931,12 +1240,11 @@ single_set_2 (insn, pat)
    zero.  */
 
 int
-multiple_sets (insn)
-     rtx insn;
+multiple_sets (rtx insn)
 {
   int found;
   int i;
-  
+
   /* INSN must be an insn.  */
   if (! INSN_P (insn))
     return 0;
@@ -954,11 +1262,93 @@ multiple_sets (insn)
              found = 1;
          }
     }
-  
+
   /* Either zero or one SET.  */
   return 0;
 }
 \f
+/* Return nonzero if the destination of SET equals the source
+   and there are no side effects.  */
+
+int
+set_noop_p (rtx set)
+{
+  rtx src = SET_SRC (set);
+  rtx dst = SET_DEST (set);
+
+  if (dst == pc_rtx && src == pc_rtx)
+    return 1;
+
+  if (GET_CODE (dst) == MEM && GET_CODE (src) == MEM)
+    return rtx_equal_p (dst, src) && !side_effects_p (dst);
+
+  if (GET_CODE (dst) == SIGN_EXTRACT
+      || GET_CODE (dst) == ZERO_EXTRACT)
+    return rtx_equal_p (XEXP (dst, 0), src)
+          && ! BYTES_BIG_ENDIAN && XEXP (dst, 2) == const0_rtx
+          && !side_effects_p (src);
+
+  if (GET_CODE (dst) == STRICT_LOW_PART)
+    dst = XEXP (dst, 0);
+
+  if (GET_CODE (src) == SUBREG && GET_CODE (dst) == SUBREG)
+    {
+      if (SUBREG_BYTE (src) != SUBREG_BYTE (dst))
+       return 0;
+      src = SUBREG_REG (src);
+      dst = SUBREG_REG (dst);
+    }
+
+  return (GET_CODE (src) == REG && GET_CODE (dst) == REG
+         && REGNO (src) == REGNO (dst));
+}
+\f
+/* Return nonzero if an insn consists only of SETs, each of which only sets a
+   value to itself.  */
+
+int
+noop_move_p (rtx insn)
+{
+  rtx pat = PATTERN (insn);
+
+  if (INSN_CODE (insn) == NOOP_MOVE_INSN_CODE)
+    return 1;
+
+  /* Insns carrying these notes are useful later on.  */
+  if (find_reg_note (insn, REG_EQUAL, NULL_RTX))
+    return 0;
+
+  /* For now treat an insn with a REG_RETVAL note as a
+     a special insn which should not be considered a no-op.  */
+  if (find_reg_note (insn, REG_RETVAL, NULL_RTX))
+    return 0;
+
+  if (GET_CODE (pat) == SET && set_noop_p (pat))
+    return 1;
+
+  if (GET_CODE (pat) == PARALLEL)
+    {
+      int i;
+      /* If nothing but SETs of registers to themselves,
+        this insn can also be deleted.  */
+      for (i = 0; i < XVECLEN (pat, 0); i++)
+       {
+         rtx tem = XVECEXP (pat, 0, i);
+
+         if (GET_CODE (tem) == USE
+             || GET_CODE (tem) == CLOBBER)
+           continue;
+
+         if (GET_CODE (tem) != SET || ! set_noop_p (tem))
+           return 0;
+       }
+
+      return 1;
+    }
+  return 0;
+}
+\f
+
 /* Return the last thing that X was assigned from before *PINSN.  If VALID_TO
    is not NULL_RTX then verify that the object is not modified up to VALID_TO.
    If the object was modified, if we hit a partial assignment to X, or hit a
@@ -967,11 +1357,7 @@ multiple_sets (insn)
    be the src.  */
 
 rtx
-find_last_value (x, pinsn, valid_to, allow_hwreg)
-     rtx x;
-     rtx *pinsn;
-     rtx valid_to;
-     int allow_hwreg;
+find_last_value (rtx x, rtx *pinsn, rtx valid_to, int allow_hwreg)
 {
   rtx p;
 
@@ -1000,14 +1386,14 @@ find_last_value (x, pinsn, valid_to, allow_hwreg)
                return src;
              }
          }
-         
+
        /* If set in non-simple way, we don't have a value.  */
        if (reg_set_p (x, p))
          break;
       }
 
   return x;
-}     
+}
 \f
 /* Return nonzero if register in range [REGNO, ENDREGNO)
    appears either explicitly or implicitly in X
@@ -1017,10 +1403,8 @@ find_last_value (x, pinsn, valid_to, allow_hwreg)
    LOC may be zero, meaning don't ignore anything.  */
 
 int
-refers_to_regno_p (regno, endregno, x, loc)
-     unsigned int regno, endregno;
-     rtx x;
-     rtx *loc;
+refers_to_regno_p (unsigned int regno, unsigned int endregno, rtx x,
+                  rtx *loc)
 {
   int i;
   unsigned int x_regno;
@@ -1052,7 +1436,7 @@ refers_to_regno_p (regno, endregno, x, loc)
        return 1;
 
       return (endregno > x_regno
-             && regno < x_regno + (x_regno < FIRST_PSEUDO_REGISTER 
+             && regno < x_regno + (x_regno < FIRST_PSEUDO_REGISTER
                                    ? HARD_REGNO_NREGS (x_regno, GET_MODE (x))
                              : 1));
 
@@ -1062,7 +1446,7 @@ refers_to_regno_p (regno, endregno, x, loc)
       if (GET_CODE (SUBREG_REG (x)) == REG
          && REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER)
        {
-         unsigned int inner_regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x);
+         unsigned int inner_regno = subreg_regno (x);
          unsigned int inner_endregno
            = inner_regno + (inner_regno < FIRST_PSEUDO_REGISTER
                             ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
@@ -1114,8 +1498,8 @@ refers_to_regno_p (regno, endregno, x, loc)
        }
       else if (fmt[i] == 'E')
        {
-         register int j;
-         for (j = XVECLEN (x, i) - 1; j >=0; j--)
+         int j;
+         for (j = XVECLEN (x, i) - 1; j >= 0; j--)
            if (loc != &XVECEXP (x, i, j)
                && refers_to_regno_p (regno, endregno, XVECEXP (x, i, j), loc))
              return 1;
@@ -1131,13 +1515,14 @@ refers_to_regno_p (regno, endregno, x, loc)
    conflict because we expect this to be a rare case.  */
 
 int
-reg_overlap_mentioned_p (x, in)
-     rtx x, in;
+reg_overlap_mentioned_p (rtx x, rtx in)
 {
   unsigned int regno, endregno;
 
   /* Overly conservative.  */
-  if (GET_CODE (x) == STRICT_LOW_PART)
+  if (GET_CODE (x) == STRICT_LOW_PART
+      || GET_CODE (x) == ZERO_EXTRACT
+      || GET_CODE (x) == SIGN_EXTRACT)
     x = XEXP (x, 0);
 
   /* If either argument is a constant, then modifying X can not affect IN.  */
@@ -1149,7 +1534,7 @@ reg_overlap_mentioned_p (x, in)
     case SUBREG:
       regno = REGNO (SUBREG_REG (x));
       if (regno < FIRST_PSEUDO_REGISTER)
-       regno += SUBREG_WORD (x);
+       regno = subreg_regno (x);
       goto do_reg;
 
     case REG:
@@ -1157,7 +1542,7 @@ reg_overlap_mentioned_p (x, in)
     do_reg:
       endregno = regno + (regno < FIRST_PSEUDO_REGISTER
                          ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
-      return refers_to_regno_p (regno, endregno, in, NULL_PTR);
+      return refers_to_regno_p (regno, endregno, in, (rtx*) 0);
 
     case MEM:
       {
@@ -1206,9 +1591,7 @@ reg_overlap_mentioned_p (x, in)
    check if a MEM remains unchanged.  */
 
 rtx
-reg_set_last (x, insn)
-     rtx x;
-     rtx insn;
+reg_set_last (rtx x, rtx insn)
 {
   rtx orig_insn = insn;
 
@@ -1257,12 +1640,9 @@ reg_set_last (x, insn)
 
   If the item being stored in or clobbered is a SUBREG of a hard register,
   the SUBREG will be passed.  */
-     
+
 void
-note_stores (x, fun, data)
-     register rtx x;
-     void (*fun) PARAMS ((rtx, rtx, void *));
-     void *data;
+note_stores (rtx x, void (*fun) (rtx, rtx, void *), void *data)
 {
   int i;
 
@@ -1271,7 +1651,7 @@ note_stores (x, fun, data)
 
   if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER)
     {
-      register rtx dest = SET_DEST (x);
+      rtx dest = SET_DEST (x);
 
       while ((GET_CODE (dest) == SUBREG
              && (GET_CODE (SUBREG_REG (dest)) != REG
@@ -1282,17 +1662,12 @@ note_stores (x, fun, data)
        dest = XEXP (dest, 0);
 
       /* If we have a PARALLEL, SET_DEST is a list of EXPR_LIST expressions,
-        each of whose first operand is a register.  We can't know what
-        precisely is being set in these cases, so make up a CLOBBER to pass
-        to the function.  */
+        each of whose first operand is a register.  */
       if (GET_CODE (dest) == PARALLEL)
        {
          for (i = XVECLEN (dest, 0) - 1; i >= 0; i--)
            if (XEXP (XVECEXP (dest, 0, i), 0) != 0)
-             (*fun) (XEXP (XVECEXP (dest, 0, i), 0),
-                     gen_rtx_CLOBBER (VOIDmode,
-                                      XEXP (XVECEXP (dest, 0, i), 0)),
-                     data);
+             (*fun) (XEXP (XVECEXP (dest, 0, i), 0), x, data);
        }
       else
        (*fun) (dest, x, data);
@@ -1303,32 +1678,114 @@ note_stores (x, fun, data)
       note_stores (XVECEXP (x, 0, i), fun, data);
 }
 \f
-/* Return nonzero if X's old contents don't survive after INSN.
-   This will be true if X is (cc0) or if X is a register and
-   X dies in INSN or because INSN entirely sets X.
-
-   "Entirely set" means set directly and not through a SUBREG,
-   ZERO_EXTRACT or SIGN_EXTRACT, so no trace of the old contents remains.
-   Likewise, REG_INC does not count.
-
-   REG may be a hard or pseudo reg.  Renumbering is not taken into account,
-   but for this use that makes no difference, since regs don't overlap
-   during their lifetimes.  Therefore, this function may be used
-   at any time after deaths have been computed (in flow.c).
+/* Like notes_stores, but call FUN for each expression that is being
+   referenced in PBODY, a pointer to the PATTERN of an insn.  We only call
+   FUN for each expression, not any interior subexpressions.  FUN receives a
+   pointer to the expression and the DATA passed to this function.
 
-   If REG is a hard reg that occupies multiple machine registers, this
-   function will only return 1 if each of those registers will be replaced
-   by INSN.  */
+   Note that this is not quite the same test as that done in reg_referenced_p
+   since that considers something as being referenced if it is being
+   partially set, while we do not.  */
 
-int
-dead_or_set_p (insn, x)
-     rtx insn;
-     rtx x;
+void
+note_uses (rtx *pbody, void (*fun) (rtx *, void *), void *data)
 {
-  unsigned int regno, last_regno;
-  unsigned int i;
+  rtx body = *pbody;
+  int i;
 
-  /* Can't use cc0_rtx below since this file is used by genattrtab.c.  */
+  switch (GET_CODE (body))
+    {
+    case COND_EXEC:
+      (*fun) (&COND_EXEC_TEST (body), data);
+      note_uses (&COND_EXEC_CODE (body), fun, data);
+      return;
+
+    case PARALLEL:
+      for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
+       note_uses (&XVECEXP (body, 0, i), fun, data);
+      return;
+
+    case USE:
+      (*fun) (&XEXP (body, 0), data);
+      return;
+
+    case ASM_OPERANDS:
+      for (i = ASM_OPERANDS_INPUT_LENGTH (body) - 1; i >= 0; i--)
+       (*fun) (&ASM_OPERANDS_INPUT (body, i), data);
+      return;
+
+    case TRAP_IF:
+      (*fun) (&TRAP_CONDITION (body), data);
+      return;
+
+    case PREFETCH:
+      (*fun) (&XEXP (body, 0), data);
+      return;
+
+    case UNSPEC:
+    case UNSPEC_VOLATILE:
+      for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
+       (*fun) (&XVECEXP (body, 0, i), data);
+      return;
+
+    case CLOBBER:
+      if (GET_CODE (XEXP (body, 0)) == MEM)
+       (*fun) (&XEXP (XEXP (body, 0), 0), data);
+      return;
+
+    case SET:
+      {
+       rtx dest = SET_DEST (body);
+
+       /* For sets we replace everything in source plus registers in memory
+          expression in store and operands of a ZERO_EXTRACT.  */
+       (*fun) (&SET_SRC (body), data);
+
+       if (GET_CODE (dest) == ZERO_EXTRACT)
+         {
+           (*fun) (&XEXP (dest, 1), data);
+           (*fun) (&XEXP (dest, 2), data);
+         }
+
+       while (GET_CODE (dest) == SUBREG || GET_CODE (dest) == STRICT_LOW_PART)
+         dest = XEXP (dest, 0);
+
+       if (GET_CODE (dest) == MEM)
+         (*fun) (&XEXP (dest, 0), data);
+      }
+      return;
+
+    default:
+      /* All the other possibilities never store.  */
+      (*fun) (pbody, data);
+      return;
+    }
+}
+\f
+/* Return nonzero if X's old contents don't survive after INSN.
+   This will be true if X is (cc0) or if X is a register and
+   X dies in INSN or because INSN entirely sets X.
+
+   "Entirely set" means set directly and not through a SUBREG,
+   ZERO_EXTRACT or SIGN_EXTRACT, so no trace of the old contents remains.
+   Likewise, REG_INC does not count.
+
+   REG may be a hard or pseudo reg.  Renumbering is not taken into account,
+   but for this use that makes no difference, since regs don't overlap
+   during their lifetimes.  Therefore, this function may be used
+   at any time after deaths have been computed (in flow.c).
+
+   If REG is a hard reg that occupies multiple machine registers, this
+   function will only return 1 if each of those registers will be replaced
+   by INSN.  */
+
+int
+dead_or_set_p (rtx insn, rtx x)
+{
+  unsigned int regno, last_regno;
+  unsigned int i;
+
+  /* Can't use cc0_rtx below since this file is used by genattrtab.c.  */
   if (GET_CODE (x) == CC0)
     return 1;
 
@@ -1350,9 +1807,7 @@ dead_or_set_p (insn, x)
    called from flow.c.  */
 
 int
-dead_or_set_regno_p (insn, test_regno)
-     rtx insn;
-     unsigned int test_regno;
+dead_or_set_regno_p (rtx insn, unsigned int test_regno)
 {
   unsigned int regno, endregno;
   rtx pattern;
@@ -1372,8 +1827,8 @@ dead_or_set_regno_p (insn, test_regno)
 
   if (GET_CODE (pattern) == SET)
     {
-      rtx dest = SET_DEST (PATTERN (insn));
+      rtx dest = SET_DEST (pattern);
+
       /* A value is totally replaced if it is the destination or the
         destination is a SUBREG of REGNO that does not change the number of
         words in it.  */
@@ -1395,7 +1850,7 @@ dead_or_set_regno_p (insn, test_regno)
     }
   else if (GET_CODE (pattern) == PARALLEL)
     {
-      register int i;
+      int i;
 
       for (i = XVECLEN (pattern, 0) - 1; i >= 0; i--)
        {
@@ -1435,12 +1890,9 @@ dead_or_set_regno_p (insn, test_regno)
    If DATUM is nonzero, look for one whose datum is DATUM.  */
 
 rtx
-find_reg_note (insn, kind, datum)
-     rtx insn;
-     enum reg_note kind;
-     rtx datum;
+find_reg_note (rtx insn, enum reg_note kind, rtx datum)
 {
-  register rtx link;
+  rtx link;
 
   /* Ignore anything that is not an INSN, JUMP_INSN or CALL_INSN.  */
   if (! INSN_P (insn))
@@ -1459,12 +1911,9 @@ find_reg_note (insn, kind, datum)
    it might be the case that the note overlaps REGNO.  */
 
 rtx
-find_regno_note (insn, kind, regno)
-     rtx insn;
-     enum reg_note kind;
-     unsigned int regno;
+find_regno_note (rtx insn, enum reg_note kind, unsigned int regno)
 {
-  register rtx link;
+  rtx link;
 
   /* Ignore anything that is not an INSN, JUMP_INSN or CALL_INSN.  */
   if (! INSN_P (insn))
@@ -1485,14 +1934,32 @@ find_regno_note (insn, kind, regno)
   return 0;
 }
 
+/* Return a REG_EQUIV or REG_EQUAL note if insn has only a single set and
+   has such a note.  */
+
+rtx
+find_reg_equal_equiv_note (rtx insn)
+{
+  rtx link;
+
+  if (!INSN_P (insn))
+    return 0;
+  for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+    if (REG_NOTE_KIND (link) == REG_EQUAL
+       || REG_NOTE_KIND (link) == REG_EQUIV)
+      {
+       if (single_set (insn) == 0)
+         return 0;
+       return link;
+      }
+  return NULL;
+}
+
 /* Return true if DATUM, or any overlap of DATUM, of kind CODE is found
    in the CALL_INSN_FUNCTION_USAGE information of INSN.  */
 
 int
-find_reg_fusage (insn, code, datum)
-     rtx insn;
-     enum rtx_code code;
-     rtx datum;
+find_reg_fusage (rtx insn, enum rtx_code code, rtx datum)
 {
   /* If it's not a CALL_INSN, it can't possibly have a
      CALL_INSN_FUNCTION_USAGE field, so don't bother checking.  */
@@ -1500,18 +1967,18 @@ find_reg_fusage (insn, code, datum)
     return 0;
 
   if (! datum)
-    abort();
+    abort ();
 
   if (GET_CODE (datum) != REG)
     {
-      register rtx link;
+      rtx link;
 
       for (link = CALL_INSN_FUNCTION_USAGE (insn);
-           link;
+          link;
           link = XEXP (link, 1))
-        if (GET_CODE (XEXP (link, 0)) == code
-           && rtx_equal_p (datum, SET_DEST (XEXP (link, 0))))
-          return 1;
+       if (GET_CODE (XEXP (link, 0)) == code
+           && rtx_equal_p (datum, XEXP (XEXP (link, 0), 0)))
+         return 1;
     }
   else
     {
@@ -1521,7 +1988,7 @@ find_reg_fusage (insn, code, datum)
         to pseudo registers, so don't bother checking.  */
 
       if (regno < FIRST_PSEUDO_REGISTER)
-        {
+       {
          unsigned int end_regno
            = regno + HARD_REGNO_NREGS (regno, GET_MODE (datum));
          unsigned int i;
@@ -1529,7 +1996,7 @@ find_reg_fusage (insn, code, datum)
          for (i = regno; i < end_regno; i++)
            if (find_regno_fusage (insn, code, i))
              return 1;
-        }
+       }
     }
 
   return 0;
@@ -1539,12 +2006,9 @@ find_reg_fusage (insn, code, datum)
    in the CALL_INSN_FUNCTION_USAGE information of INSN.  */
 
 int
-find_regno_fusage (insn, code, regno)
-     rtx insn;
-     enum rtx_code code;
-     unsigned int regno;
+find_regno_fusage (rtx insn, enum rtx_code code, unsigned int regno)
 {
-  register rtx link;
+  rtx link;
 
   /* CALL_INSN_FUNCTION_USAGE information cannot contain references
      to pseudo registers, so don't bother checking.  */
@@ -1567,15 +2031,37 @@ find_regno_fusage (insn, code, regno)
 
   return 0;
 }
+
+/* Return true if INSN is a call to a pure function.  */
+
+int
+pure_call_p (rtx insn)
+{
+  rtx link;
+
+  if (GET_CODE (insn) != CALL_INSN || ! CONST_OR_PURE_CALL_P (insn))
+    return 0;
+
+  /* Look for the note that differentiates const and pure functions.  */
+  for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
+    {
+      rtx u, m;
+
+      if (GET_CODE (u = XEXP (link, 0)) == USE
+         && GET_CODE (m = XEXP (u, 0)) == MEM && GET_MODE (m) == BLKmode
+         && GET_CODE (XEXP (m, 0)) == SCRATCH)
+       return 1;
+    }
+
+  return 0;
+}
 \f
 /* Remove register note NOTE from the REG_NOTES of INSN.  */
 
 void
-remove_note (insn, note)
-     register rtx insn;
-     register rtx note;
+remove_note (rtx insn, rtx note)
 {
-  register rtx link;
+  rtx link;
 
   if (note == NULL_RTX)
     return;
@@ -1597,14 +2083,28 @@ remove_note (insn, note)
 }
 
 /* Search LISTP (an EXPR_LIST) for an entry whose first operand is NODE and
+   return 1 if it is found.  A simple equality test is used to determine if
+   NODE matches.  */
+
+int
+in_expr_list_p (rtx listp, rtx node)
+{
+  rtx x;
+
+  for (x = listp; x; x = XEXP (x, 1))
+    if (node == XEXP (x, 0))
+      return 1;
+
+  return 0;
+}
+
+/* Search LISTP (an EXPR_LIST) for an entry whose first operand is NODE and
    remove that entry from the list if it is found.
 
    A simple equality test is used to determine if NODE matches.  */
 
 void
-remove_node_from_expr_list (node, listp)
-     rtx node;
-     rtx *listp;
+remove_node_from_expr_list (rtx node, rtx *listp)
 {
   rtx temp = *listp;
   rtx prev = NULL_RTX;
@@ -1633,10 +2133,9 @@ remove_node_from_expr_list (node, listp)
    only volatile asms and UNSPEC_VOLATILE instructions.  */
 
 int
-volatile_insn_p (x)
-     rtx x;
+volatile_insn_p (rtx x)
 {
-  register RTX_CODE code;
+  RTX_CODE code;
 
   code = GET_CODE (x);
   switch (code)
@@ -1646,12 +2145,12 @@ volatile_insn_p (x)
     case CONST_INT:
     case CONST:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case CC0:
     case PC:
     case REG:
     case SCRATCH:
     case CLOBBER:
-    case ASM_INPUT:
     case ADDR_VEC:
     case ADDR_DIFF_VEC:
     case CALL:
@@ -1662,6 +2161,7 @@ volatile_insn_p (x)
  /* case TRAP_IF: This isn't clear yet.  */
       return 1;
 
+    case ASM_INPUT:
     case ASM_OPERANDS:
       if (MEM_VOLATILE_P (x))
        return 1;
@@ -1673,9 +2173,9 @@ volatile_insn_p (x)
   /* Recursively scan the operands of this expression.  */
 
   {
-    register const char *fmt = GET_RTX_FORMAT (code);
-    register int i;
-    
+    const char *fmt = GET_RTX_FORMAT (code);
+    int i;
+
     for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
       {
        if (fmt[i] == 'e')
@@ -1685,7 +2185,7 @@ volatile_insn_p (x)
          }
        else if (fmt[i] == 'E')
          {
-           register int j;
+           int j;
            for (j = 0; j < XVECLEN (x, i); j++)
              if (volatile_insn_p (XVECEXP (x, i, j)))
                return 1;
@@ -1699,10 +2199,9 @@ volatile_insn_p (x)
    UNSPEC_VOLATILE operations or volatile ASM_OPERANDS expressions.  */
 
 int
-volatile_refs_p (x)
-     rtx x;
+volatile_refs_p (rtx x)
 {
-  register RTX_CODE code;
+  RTX_CODE code;
 
   code = GET_CODE (x);
   switch (code)
@@ -1712,22 +2211,21 @@ volatile_refs_p (x)
     case CONST_INT:
     case CONST:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case CC0:
     case PC:
     case REG:
     case SCRATCH:
     case CLOBBER:
-    case ASM_INPUT:
     case ADDR_VEC:
     case ADDR_DIFF_VEC:
       return 0;
 
-    case CALL:
     case UNSPEC_VOLATILE:
- /* case TRAP_IF: This isn't clear yet.  */
       return 1;
 
     case MEM:
+    case ASM_INPUT:
     case ASM_OPERANDS:
       if (MEM_VOLATILE_P (x))
        return 1;
@@ -1739,9 +2237,9 @@ volatile_refs_p (x)
   /* Recursively scan the operands of this expression.  */
 
   {
-    register const char *fmt = GET_RTX_FORMAT (code);
-    register int i;
-    
+    const char *fmt = GET_RTX_FORMAT (code);
+    int i;
+
     for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
       {
        if (fmt[i] == 'e')
@@ -1751,7 +2249,7 @@ volatile_refs_p (x)
          }
        else if (fmt[i] == 'E')
          {
-           register int j;
+           int j;
            for (j = 0; j < XVECLEN (x, i); j++)
              if (volatile_refs_p (XVECEXP (x, i, j)))
                return 1;
@@ -1765,10 +2263,9 @@ volatile_refs_p (x)
    incrementing.  */
 
 int
-side_effects_p (x)
-     rtx x;
+side_effects_p (rtx x)
 {
-  register RTX_CODE code;
+  RTX_CODE code;
 
   code = GET_CODE (x);
   switch (code)
@@ -1778,11 +2275,11 @@ side_effects_p (x)
     case CONST_INT:
     case CONST:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case CC0:
     case PC:
     case REG:
     case SCRATCH:
-    case ASM_INPUT:
     case ADDR_VEC:
     case ADDR_DIFF_VEC:
       return 0;
@@ -1805,6 +2302,7 @@ side_effects_p (x)
       return 1;
 
     case MEM:
+    case ASM_INPUT:
     case ASM_OPERANDS:
       if (MEM_VOLATILE_P (x))
        return 1;
@@ -1816,9 +2314,9 @@ side_effects_p (x)
   /* Recursively scan the operands of this expression.  */
 
   {
-    register const char *fmt = GET_RTX_FORMAT (code);
-    register int i;
-    
+    const char *fmt = GET_RTX_FORMAT (code);
+    int i;
+
     for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
       {
        if (fmt[i] == 'e')
@@ -1828,7 +2326,7 @@ side_effects_p (x)
          }
        else if (fmt[i] == 'E')
          {
-           register int j;
+           int j;
            for (j = 0; j < XVECLEN (x, i); j++)
              if (side_effects_p (XVECEXP (x, i, j)))
                return 1;
@@ -1841,8 +2339,7 @@ side_effects_p (x)
 /* Return nonzero if evaluating rtx X might cause a trap.  */
 
 int
-may_trap_p (x)
-     rtx x;
+may_trap_p (rtx x)
 {
   int i;
   enum rtx_code code;
@@ -1856,6 +2353,7 @@ may_trap_p (x)
       /* Handle these cases quickly.  */
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case SYMBOL_REF:
     case LABEL_REF:
     case CONST:
@@ -1875,6 +2373,8 @@ may_trap_p (x)
 
       /* Memory ref can trap unless it's a static var or a stack slot.  */
     case MEM:
+      if (MEM_NOTRAP_P (x))
+       return 0;
       return rtx_addr_can_trap_p (XEXP (x, 0));
 
       /* Division by a non-constant might trap.  */
@@ -1882,12 +2382,13 @@ may_trap_p (x)
     case MOD:
     case UDIV:
     case UMOD:
+      if (HONOR_SNANS (GET_MODE (x)))
+       return 1;
       if (! CONSTANT_P (XEXP (x, 1))
-         || GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
+         || (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT
+             && flag_trapping_math))
        return 1;
-      /* This was const0_rtx, but by not using that,
-        we can link this file into other programs.  */
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) == 0)
+      if (XEXP (x, 1) == const0_rtx)
        return 1;
       break;
 
@@ -1902,22 +2403,46 @@ may_trap_p (x)
     case LT:
     case COMPARE:
       /* Some floating point comparisons may trap.  */
+      if (!flag_trapping_math)
+       break;
       /* ??? There is no machine independent way to check for tests that trap
         when COMPARE is used, though many targets do make this distinction.
         For instance, sparc uses CCFPE for compares which generate exceptions
         and CCFP for compares which do not generate exceptions.  */
-      if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
+      if (HONOR_NANS (GET_MODE (x)))
        return 1;
       /* But often the compare has some CC mode, so check operand
         modes as well.  */
-      if (GET_MODE_CLASS (GET_MODE (XEXP (x, 0))) == MODE_FLOAT
-         || GET_MODE_CLASS (GET_MODE (XEXP (x, 1))) == MODE_FLOAT)
+      if (HONOR_NANS (GET_MODE (XEXP (x, 0)))
+         || HONOR_NANS (GET_MODE (XEXP (x, 1))))
        return 1;
       break;
 
+    case EQ:
+    case NE:
+      if (HONOR_SNANS (GET_MODE (x)))
+       return 1;
+      /* Often comparison is CC mode, so check operand modes.  */
+      if (HONOR_SNANS (GET_MODE (XEXP (x, 0)))
+         || HONOR_SNANS (GET_MODE (XEXP (x, 1))))
+       return 1;
+      break;
+
+    case FIX:
+      /* Conversion of floating point might trap.  */
+      if (flag_trapping_math && HONOR_NANS (GET_MODE (XEXP (x, 0))))
+       return 1;
+      break;
+
+    case NEG:
+    case ABS:
+      /* These operations don't trap even with floating point.  */
+      break;
+
     default:
       /* Any floating arithmetic may trap.  */
-      if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
+      if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT
+         && flag_trapping_math)
        return 1;
     }
 
@@ -1931,7 +2456,7 @@ may_trap_p (x)
        }
       else if (fmt[i] == 'E')
        {
-         register int j;
+         int j;
          for (j = 0; j < XVECLEN (x, i); j++)
            if (may_trap_p (XVECEXP (x, i, j)))
              return 1;
@@ -1944,12 +2469,11 @@ may_trap_p (x)
    i.e., an inequality.  */
 
 int
-inequality_comparisons_p (x)
-     rtx x;
+inequality_comparisons_p (rtx x)
 {
-  register const char *fmt;
-  register int len, i;
-  register enum rtx_code code = GET_CODE (x);
+  const char *fmt;
+  int len, i;
+  enum rtx_code code = GET_CODE (x);
 
   switch (code)
     {
@@ -1959,6 +2483,7 @@ inequality_comparisons_p (x)
     case CC0:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case CONST:
     case LABEL_REF:
     case SYMBOL_REF:
@@ -1973,7 +2498,7 @@ inequality_comparisons_p (x)
     case GE:
     case GEU:
       return 1;
-      
+
     default:
       break;
     }
@@ -1990,13 +2515,13 @@ inequality_comparisons_p (x)
        }
       else if (fmt[i] == 'E')
        {
-         register int j;
+         int j;
          for (j = XVECLEN (x, i) - 1; j >= 0; j--)
            if (inequality_comparisons_p (XVECEXP (x, i, j)))
              return 1;
        }
     }
-           
+
   return 0;
 }
 \f
@@ -2007,14 +2532,13 @@ inequality_comparisons_p (x)
    are to be modified.  */
 
 rtx
-replace_rtx (x, from, to)
-     rtx x, from, to;
+replace_rtx (rtx x, rtx from, rtx to)
 {
-  register int i, j;
-  register const char *fmt;
+  int i, j;
+  const char *fmt;
 
   /* The following prevents loops occurrence when we change MEM in
-     CONST_DOUBLE onto the same CONST_DOUBLE. */
+     CONST_DOUBLE onto the same CONST_DOUBLE.  */
   if (x != 0 && GET_CODE (x) == CONST_DOUBLE)
     return x;
 
@@ -2025,6 +2549,40 @@ replace_rtx (x, from, to)
   if (x == 0)
     return 0;
 
+  if (GET_CODE (x) == SUBREG)
+    {
+      rtx new = replace_rtx (SUBREG_REG (x), from, to);
+
+      if (GET_CODE (new) == CONST_INT)
+       {
+         x = simplify_subreg (GET_MODE (x), new,
+                              GET_MODE (SUBREG_REG (x)),
+                              SUBREG_BYTE (x));
+         if (! x)
+           abort ();
+       }
+      else
+       SUBREG_REG (x) = new;
+
+      return x;
+    }
+  else if (GET_CODE (x) == ZERO_EXTEND)
+    {
+      rtx new = replace_rtx (XEXP (x, 0), from, to);
+
+      if (GET_CODE (new) == CONST_INT)
+       {
+         x = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
+                                       new, GET_MODE (XEXP (x, 0)));
+         if (! x)
+           abort ();
+       }
+      else
+       XEXP (x, 0) = new;
+
+      return x;
+    }
+
   fmt = GET_RTX_FORMAT (GET_CODE (x));
   for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
     {
@@ -2036,12 +2594,12 @@ replace_rtx (x, from, to)
     }
 
   return x;
-}  
+}
 \f
 /* Throughout the rtx X, replace many registers according to REG_MAP.
    Return the replacement for X (which may be X with altered contents).
    REG_MAP[R] is the replacement for register R, or 0 for don't replace.
-   NREGS is the length of REG_MAP; regs >= NREGS are not mapped.  
+   NREGS is the length of REG_MAP; regs >= NREGS are not mapped.
 
    We only support REG_MAP entries of REG or SUBREG.  Also, hard registers
    should not be mapped to pseudos or vice versa since validate_change
@@ -2051,15 +2609,11 @@ replace_rtx (x, from, to)
    otherwise, only sources are replaced.  */
 
 rtx
-replace_regs (x, reg_map, nregs, replace_dest)
-     rtx x;
-     rtx *reg_map;
-     unsigned int nregs;
-     int replace_dest;
+replace_regs (rtx x, rtx *reg_map, unsigned int nregs, int replace_dest)
 {
-  register enum rtx_code code;
-  register int i;
-  register const char *fmt;
+  enum rtx_code code;
+  int i;
+  const char *fmt;
 
   if (x == 0)
     return x;
@@ -2072,6 +2626,7 @@ replace_regs (x, reg_map, nregs, replace_dest)
     case CC0:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case CONST:
     case SYMBOL_REF:
     case LABEL_REF:
@@ -2097,26 +2652,9 @@ replace_regs (x, reg_map, nregs, replace_dest)
          && GET_CODE (reg_map[REGNO (SUBREG_REG (x))]) == SUBREG)
        {
          rtx map_val = reg_map[REGNO (SUBREG_REG (x))];
-         rtx map_inner = SUBREG_REG (map_val);
-
-         if (GET_MODE (x) == GET_MODE (map_inner))
-           return map_inner;
-         else
-           {
-             /* We cannot call gen_rtx here since we may be linked with
-                genattrtab.c.  */
-             /* Let's try clobbering the incoming SUBREG and see
-                if this is really safe.  */
-             SUBREG_REG (x) = map_inner;
-             SUBREG_WORD (x) += SUBREG_WORD (map_val);
-             return x;
-#if 0
-             rtx new = rtx_alloc (SUBREG);
-             PUT_MODE (new, GET_MODE (x));
-             SUBREG_REG (new) = map_inner;
-             SUBREG_WORD (new) = SUBREG_WORD (x) + SUBREG_WORD (map_val);
-#endif
-           }
+         return simplify_gen_subreg (GET_MODE (x), map_val,
+                                     GET_MODE (SUBREG_REG (x)),
+                                     SUBREG_BYTE (x));
        }
       break;
 
@@ -2137,7 +2675,7 @@ replace_regs (x, reg_map, nregs, replace_dest)
 
       SET_SRC (x) = replace_regs (SET_SRC (x), reg_map, nregs, 0);
       return x;
-      
+
     default:
       break;
     }
@@ -2149,7 +2687,7 @@ replace_regs (x, reg_map, nregs, replace_dest)
        XEXP (x, i) = replace_regs (XEXP (x, i), reg_map, nregs, replace_dest);
       else if (fmt[i] == 'E')
        {
-         register int j;
+         int j;
          for (j = 0; j < XVECLEN (x, i); j++)
            XVECEXP (x, i, j) = replace_regs (XVECEXP (x, i, j), reg_map,
                                              nregs, replace_dest);
@@ -2158,13 +2696,133 @@ replace_regs (x, reg_map, nregs, replace_dest)
   return x;
 }
 
+/* Replace occurrences of the old label in *X with the new one.
+   DATA is a REPLACE_LABEL_DATA containing the old and new labels.  */
+
+int
+replace_label (rtx *x, void *data)
+{
+  rtx l = *x;
+  rtx tmp;
+  rtx old_label = ((replace_label_data *) data)->r1;
+  rtx new_label = ((replace_label_data *) data)->r2;
+  bool update_label_nuses = ((replace_label_data *) data)->update_label_nuses;
+
+  if (l == NULL_RTX)
+    return 0;
+
+  if (GET_CODE (l) == MEM
+      && (tmp = XEXP (l, 0)) != NULL_RTX
+      && GET_CODE (tmp) == SYMBOL_REF
+      && CONSTANT_POOL_ADDRESS_P (tmp))
+    {
+      rtx c = get_pool_constant (tmp);
+      if (rtx_referenced_p (old_label, c))
+       {
+         rtx new_c, new_l;
+         replace_label_data *d = (replace_label_data *) data;
+
+         /* Create a copy of constant C; replace the label inside
+            but do not update LABEL_NUSES because uses in constant pool
+            are not counted.  */
+         new_c = copy_rtx (c);
+         d->update_label_nuses = false;
+         for_each_rtx (&new_c, replace_label, data);
+         d->update_label_nuses = update_label_nuses;
+
+         /* Add the new constant NEW_C to constant pool and replace
+            the old reference to constant by new reference.  */
+         new_l = force_const_mem (get_pool_mode (tmp), new_c);
+         *x = replace_rtx (l, l, new_l);
+       }
+      return 0;
+    }
+
+  /* If this is a JUMP_INSN, then we also need to fix the JUMP_LABEL
+     field.  This is not handled by for_each_rtx because it doesn't
+     handle unprinted ('0') fields.  */
+  if (GET_CODE (l) == JUMP_INSN && JUMP_LABEL (l) == old_label)
+    JUMP_LABEL (l) = new_label;
+
+  if ((GET_CODE (l) == LABEL_REF
+       || GET_CODE (l) == INSN_LIST)
+      && XEXP (l, 0) == old_label)
+    {
+      XEXP (l, 0) = new_label;
+      if (update_label_nuses)
+       {
+         ++LABEL_NUSES (new_label);
+         --LABEL_NUSES (old_label);
+       }
+      return 0;
+    }
+
+  return 0;
+}
+
+/* When *BODY is equal to X or X is directly referenced by *BODY
+   return nonzero, thus FOR_EACH_RTX stops traversing and returns nonzero
+   too, otherwise FOR_EACH_RTX continues traversing *BODY.  */
+
+static int
+rtx_referenced_p_1 (rtx *body, void *x)
+{
+  rtx y = (rtx) x;
+
+  if (*body == NULL_RTX)
+    return y == NULL_RTX;
+
+  /* Return true if a label_ref *BODY refers to label Y.  */
+  if (GET_CODE (*body) == LABEL_REF && GET_CODE (y) == CODE_LABEL)
+    return XEXP (*body, 0) == y;
+
+  /* If *BODY is a reference to pool constant traverse the constant.  */
+  if (GET_CODE (*body) == SYMBOL_REF
+      && CONSTANT_POOL_ADDRESS_P (*body))
+    return rtx_referenced_p (y, get_pool_constant (*body));
+
+  /* By default, compare the RTL expressions.  */
+  return rtx_equal_p (*body, y);
+}
+
+/* Return true if X is referenced in BODY.  */
+
+int
+rtx_referenced_p (rtx x, rtx body)
+{
+  return for_each_rtx (&body, rtx_referenced_p_1, x);
+}
+
+/* If INSN is a tablejump return true and store the label (before jump table) to
+   *LABELP and the jump table to *TABLEP.  LABELP and TABLEP may be NULL.  */
+
+bool
+tablejump_p (rtx insn, rtx *labelp, rtx *tablep)
+{
+  rtx label, table;
+
+  if (GET_CODE (insn) == JUMP_INSN
+      && (label = JUMP_LABEL (insn)) != NULL_RTX
+      && (table = next_active_insn (label)) != NULL_RTX
+      && GET_CODE (table) == JUMP_INSN
+      && (GET_CODE (PATTERN (table)) == ADDR_VEC
+         || GET_CODE (PATTERN (table)) == ADDR_DIFF_VEC))
+    {
+      if (labelp)
+       *labelp = label;
+      if (tablep)
+       *tablep = table;
+      return true;
+    }
+  return false;
+}
+
 /* A subroutine of computed_jump_p, return 1 if X contains a REG or MEM or
    constant that is not in the constant pool and not in the condition
    of an IF_THEN_ELSE.  */
 
 static int
-computed_jump_p_1 (x)
-     rtx x;
+computed_jump_p_1 (rtx x)
 {
   enum rtx_code code = GET_CODE (x);
   int i, j;
@@ -2179,6 +2837,7 @@ computed_jump_p_1 (x)
     case CONST:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case SYMBOL_REF:
     case REG:
       return 1;
@@ -2217,8 +2876,7 @@ computed_jump_p_1 (x)
    we can recognize them by a (use (label_ref)).  */
 
 int
-computed_jump_p (insn)
-     rtx insn;
+computed_jump_p (rtx insn)
 {
   int i;
   if (GET_CODE (insn) == JUMP_INSN)
@@ -2257,7 +2915,7 @@ computed_jump_p (insn)
    sub-expression (including X itself).  F is also passed the DATA.
    If F returns -1, do not traverse sub-expressions, but continue
    traversing the rest of the tree.  If F ever returns any other
-   non-zero value, stop the traversal, and return the value returned
+   nonzero value, stop the traversal, and return the value returned
    by F.  Otherwise, return 0.  This function does not traverse inside
    tree structure that contains RTX_EXPRs, or into sub-expressions
    whose format code is `0' since it is not known whether or not those
@@ -2267,18 +2925,15 @@ computed_jump_p (insn)
    implement many of the other routines in this file.  */
 
 int
-for_each_rtx (x, f, data)
-     rtx *x;
-     rtx_function f;
-     void *data;
+for_each_rtx (rtx *x, rtx_function f, void *data)
 {
   int result;
   int length;
-  const charformat;
+  const char *format;
   int i;
 
   /* Call F on X.  */
-  result = (*f)(x, data);
+  result = (*f) (x, data);
   if (result == -1)
     /* Do not traverse sub-expressions.  */
     return 0;
@@ -2293,9 +2948,9 @@ for_each_rtx (x, f, data)
   length = GET_RTX_LENGTH (GET_CODE (*x));
   format = GET_RTX_FORMAT (GET_CODE (*x));
 
-  for (i = 0; i < length; ++i) 
+  for (i = 0; i < length; ++i)
     {
-      switch (format[i]) 
+      switch (format[i])
        {
        case 'e':
          result = for_each_rtx (&XEXP (*x, i), f, data);
@@ -2305,7 +2960,7 @@ for_each_rtx (x, f, data)
 
        case 'V':
        case 'E':
-         if (XVEC (*x, i) != 0) 
+         if (XVEC (*x, i) != 0)
            {
              int j;
              for (j = 0; j < XVECLEN (*x, i); ++j)
@@ -2315,7 +2970,7 @@ for_each_rtx (x, f, data)
                    return result;
                }
            }
-         break; 
+         break;
 
        default:
          /* Nothing to do.  */
@@ -2331,11 +2986,9 @@ for_each_rtx (x, f, data)
    reference found if any.  Otherwise, returns NULL_RTX.  */
 
 rtx
-regno_use_in (regno, x)
-     unsigned int regno;
-     rtx x;
+regno_use_in (unsigned int regno, rtx x)
 {
-  register const char *fmt;
+  const char *fmt;
   int i, j;
   rtx tem;
 
@@ -2359,12 +3012,57 @@ regno_use_in (regno, x)
   return NULL_RTX;
 }
 
+/* Return a value indicating whether OP, an operand of a commutative
+   operation, is preferred as the first or second operand.  The higher
+   the value, the stronger the preference for being the first operand.
+   We use negative values to indicate a preference for the first operand
+   and positive values for the second operand.  */
+
+int
+commutative_operand_precedence (rtx op)
+{
+  /* Constants always come the second operand.  Prefer "nice" constants.  */
+  if (GET_CODE (op) == CONST_INT)
+    return -5;
+  if (GET_CODE (op) == CONST_DOUBLE)
+    return -4;
+  if (CONSTANT_P (op))
+    return -3;
+
+  /* SUBREGs of objects should come second.  */
+  if (GET_CODE (op) == SUBREG
+      && GET_RTX_CLASS (GET_CODE (SUBREG_REG (op))) == 'o')
+    return -2;
+
+  /* If only one operand is a `neg', `not',
+    `mult', `plus', or `minus' expression, it will be the first
+    operand.  */
+  if (GET_CODE (op) == NEG || GET_CODE (op) == NOT
+      || GET_CODE (op) == MULT || GET_CODE (op) == PLUS
+      || GET_CODE (op) == MINUS)
+    return 2;
+
+  /* Complex expressions should be the first, so decrease priority
+     of objects.  */
+  if (GET_RTX_CLASS (GET_CODE (op)) == 'o')
+    return -1;
+  return 0;
+}
+
+/* Return 1 iff it is necessary to swap operands of commutative operation
+   in order to canonicalize expression.  */
+
+int
+swap_commutative_operands_p (rtx x, rtx y)
+{
+  return (commutative_operand_precedence (x)
+         < commutative_operand_precedence (y));
+}
 
 /* Return 1 if X is an autoincrement side effect and the register is
    not the stack pointer.  */
 int
-auto_inc_p (x)
-     rtx x;
+auto_inc_p (rtx x)
 {
   switch (GET_CODE (x))
     {
@@ -2387,17 +3085,14 @@ auto_inc_p (x)
    to and including TO is safe to move.  If NEW_TO is non-NULL, and
    the sequence is not already safe to move, but can be easily
    extended to a sequence which is safe, then NEW_TO will point to the
-   end of the extended sequence.  
+   end of the extended sequence.
+
    For now, this function only checks that the region contains whole
    exception regions, but it could be extended to check additional
    conditions as well.  */
 
 int
-insns_safe_to_move_p (from, to, new_to)
-     rtx from;
-     rtx to;
-     rtx *new_to;
+insns_safe_to_move_p (rtx from, rtx to, rtx *new_to)
 {
   int eh_region_count = 0;
   int past_to_p = 0;
@@ -2443,7 +3138,7 @@ insns_safe_to_move_p (from, to, new_to)
            /* It's OK to move the sequence if there were matched sets of
               exception region notes.  */
            return eh_region_count == 0;
-         
+
          past_to_p = 1;
        }
 
@@ -2458,14 +3153,13 @@ insns_safe_to_move_p (from, to, new_to)
       /* Go to the next instruction.  */
       r = NEXT_INSN (r);
     }
-  
+
   return 0;
 }
 
-/* Return non-zero if IN contains a piece of rtl that has the address LOC */
+/* Return nonzero if IN contains a piece of rtl that has the address LOC.  */
 int
-loc_mentioned_in_p (loc, in)
-     rtx *loc, in;
+loc_mentioned_in_p (rtx *loc, rtx in)
 {
   enum rtx_code code = GET_CODE (in);
   const char *fmt = GET_RTX_FORMAT (code);
@@ -2473,7 +3167,7 @@ loc_mentioned_in_p (loc, in)
 
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
-      if (loc == &in->fld[i].rtx)
+      if (loc == &in->u.fld[i].rtx)
        return 1;
       if (fmt[i] == 'e')
        {
@@ -2487,3 +3181,531 @@ loc_mentioned_in_p (loc, in)
     }
   return 0;
 }
+
+/* Given a subreg X, return the bit offset where the subreg begins
+   (counting from the least significant bit of the reg).  */
+
+unsigned int
+subreg_lsb (rtx x)
+{
+  enum machine_mode inner_mode = GET_MODE (SUBREG_REG (x));
+  enum machine_mode mode = GET_MODE (x);
+  unsigned int bitpos;
+  unsigned int byte;
+  unsigned int word;
+
+  /* A paradoxical subreg begins at bit position 0.  */
+  if (GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (inner_mode))
+    return 0;
+
+  if (WORDS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
+    /* If the subreg crosses a word boundary ensure that
+       it also begins and ends on a word boundary.  */
+    if ((SUBREG_BYTE (x) % UNITS_PER_WORD
+        + GET_MODE_SIZE (mode)) > UNITS_PER_WORD
+       && (SUBREG_BYTE (x) % UNITS_PER_WORD
+           || GET_MODE_SIZE (mode) % UNITS_PER_WORD))
+       abort ();
+
+  if (WORDS_BIG_ENDIAN)
+    word = (GET_MODE_SIZE (inner_mode)
+           - (SUBREG_BYTE (x) + GET_MODE_SIZE (mode))) / UNITS_PER_WORD;
+  else
+    word = SUBREG_BYTE (x) / UNITS_PER_WORD;
+  bitpos = word * BITS_PER_WORD;
+
+  if (BYTES_BIG_ENDIAN)
+    byte = (GET_MODE_SIZE (inner_mode)
+           - (SUBREG_BYTE (x) + GET_MODE_SIZE (mode))) % UNITS_PER_WORD;
+  else
+    byte = SUBREG_BYTE (x) % UNITS_PER_WORD;
+  bitpos += byte * BITS_PER_UNIT;
+
+  return bitpos;
+}
+
+/* This function returns the regno offset of a subreg expression.
+   xregno - A regno of an inner hard subreg_reg (or what will become one).
+   xmode  - The mode of xregno.
+   offset - The byte offset.
+   ymode  - The mode of a top level SUBREG (or what may become one).
+   RETURN - The regno offset which would be used.  */
+unsigned int
+subreg_regno_offset (unsigned int xregno, enum machine_mode xmode,
+                    unsigned int offset, enum machine_mode ymode)
+{
+  int nregs_xmode, nregs_ymode;
+  int mode_multiple, nregs_multiple;
+  int y_offset;
+
+  if (xregno >= FIRST_PSEUDO_REGISTER)
+    abort ();
+
+  nregs_xmode = HARD_REGNO_NREGS (xregno, xmode);
+  nregs_ymode = HARD_REGNO_NREGS (xregno, ymode);
+
+  /* If this is a big endian paradoxical subreg, which uses more actual
+     hard registers than the original register, we must return a negative
+     offset so that we find the proper highpart of the register.  */
+  if (offset == 0
+      && nregs_ymode > nregs_xmode
+      && (GET_MODE_SIZE (ymode) > UNITS_PER_WORD
+         ? WORDS_BIG_ENDIAN : BYTES_BIG_ENDIAN))
+    return nregs_xmode - nregs_ymode;
+
+  if (offset == 0 || nregs_xmode == nregs_ymode)
+    return 0;
+
+  /* size of ymode must not be greater than the size of xmode.  */
+  mode_multiple = GET_MODE_SIZE (xmode) / GET_MODE_SIZE (ymode);
+  if (mode_multiple == 0)
+    abort ();
+
+  y_offset = offset / GET_MODE_SIZE (ymode);
+  nregs_multiple =  nregs_xmode / nregs_ymode;
+  return (y_offset / (mode_multiple / nregs_multiple)) * nregs_ymode;
+}
+
+/* This function returns true when the offset is representable via
+   subreg_offset in the given regno.
+   xregno - A regno of an inner hard subreg_reg (or what will become one).
+   xmode  - The mode of xregno.
+   offset - The byte offset.
+   ymode  - The mode of a top level SUBREG (or what may become one).
+   RETURN - The regno offset which would be used.  */
+bool
+subreg_offset_representable_p (unsigned int xregno, enum machine_mode xmode,
+                              unsigned int offset, enum machine_mode ymode)
+{
+  int nregs_xmode, nregs_ymode;
+  int mode_multiple, nregs_multiple;
+  int y_offset;
+
+  if (xregno >= FIRST_PSEUDO_REGISTER)
+    abort ();
+
+  nregs_xmode = HARD_REGNO_NREGS (xregno, xmode);
+  nregs_ymode = HARD_REGNO_NREGS (xregno, ymode);
+
+  /* paradoxical subregs are always valid.  */
+  if (offset == 0
+      && nregs_ymode > nregs_xmode
+      && (GET_MODE_SIZE (ymode) > UNITS_PER_WORD
+         ? WORDS_BIG_ENDIAN : BYTES_BIG_ENDIAN))
+    return true;
+
+  /* Lowpart subregs are always valid.  */
+  if (offset == subreg_lowpart_offset (ymode, xmode))
+    return true;
+
+#ifdef ENABLE_CHECKING
+  /* This should always pass, otherwise we don't know how to verify the
+     constraint.  These conditions may be relaxed but subreg_offset would
+     need to be redesigned.  */
+  if (GET_MODE_SIZE (xmode) % GET_MODE_SIZE (ymode)
+      || GET_MODE_SIZE (ymode) % nregs_ymode
+      || nregs_xmode % nregs_ymode)
+    abort ();
+#endif
+
+  /* The XMODE value can be seen as a vector of NREGS_XMODE
+     values.  The subreg must represent a lowpart of given field.
+     Compute what field it is.  */
+  offset -= subreg_lowpart_offset (ymode,
+                                  mode_for_size (GET_MODE_BITSIZE (xmode)
+                                                 / nregs_xmode,
+                                                 MODE_INT, 0));
+
+  /* size of ymode must not be greater than the size of xmode.  */
+  mode_multiple = GET_MODE_SIZE (xmode) / GET_MODE_SIZE (ymode);
+  if (mode_multiple == 0)
+    abort ();
+
+  y_offset = offset / GET_MODE_SIZE (ymode);
+  nregs_multiple =  nregs_xmode / nregs_ymode;
+#ifdef ENABLE_CHECKING
+  if (offset % GET_MODE_SIZE (ymode)
+      || mode_multiple % nregs_multiple)
+    abort ();
+#endif
+  return (!(y_offset % (mode_multiple / nregs_multiple)));
+}
+
+/* Return the final regno that a subreg expression refers to.  */
+unsigned int
+subreg_regno (rtx x)
+{
+  unsigned int ret;
+  rtx subreg = SUBREG_REG (x);
+  int regno = REGNO (subreg);
+
+  ret = regno + subreg_regno_offset (regno,
+                                    GET_MODE (subreg),
+                                    SUBREG_BYTE (x),
+                                    GET_MODE (x));
+  return ret;
+
+}
+struct parms_set_data
+{
+  int nregs;
+  HARD_REG_SET regs;
+};
+
+/* Helper function for noticing stores to parameter registers.  */
+static void
+parms_set (rtx x, rtx pat ATTRIBUTE_UNUSED, void *data)
+{
+  struct parms_set_data *d = data;
+  if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER
+      && TEST_HARD_REG_BIT (d->regs, REGNO (x)))
+    {
+      CLEAR_HARD_REG_BIT (d->regs, REGNO (x));
+      d->nregs--;
+    }
+}
+
+/* Look backward for first parameter to be loaded.
+   Do not skip BOUNDARY.  */
+rtx
+find_first_parameter_load (rtx call_insn, rtx boundary)
+{
+  struct parms_set_data parm;
+  rtx p, before;
+
+  /* Since different machines initialize their parameter registers
+     in different orders, assume nothing.  Collect the set of all
+     parameter registers.  */
+  CLEAR_HARD_REG_SET (parm.regs);
+  parm.nregs = 0;
+  for (p = CALL_INSN_FUNCTION_USAGE (call_insn); p; p = XEXP (p, 1))
+    if (GET_CODE (XEXP (p, 0)) == USE
+       && GET_CODE (XEXP (XEXP (p, 0), 0)) == REG)
+      {
+       if (REGNO (XEXP (XEXP (p, 0), 0)) >= FIRST_PSEUDO_REGISTER)
+         abort ();
+
+       /* We only care about registers which can hold function
+          arguments.  */
+       if (!FUNCTION_ARG_REGNO_P (REGNO (XEXP (XEXP (p, 0), 0))))
+         continue;
+
+       SET_HARD_REG_BIT (parm.regs, REGNO (XEXP (XEXP (p, 0), 0)));
+       parm.nregs++;
+      }
+  before = call_insn;
+
+  /* Search backward for the first set of a register in this set.  */
+  while (parm.nregs && before != boundary)
+    {
+      before = PREV_INSN (before);
+
+      /* It is possible that some loads got CSEed from one call to
+         another.  Stop in that case.  */
+      if (GET_CODE (before) == CALL_INSN)
+       break;
+
+      /* Our caller needs either ensure that we will find all sets
+         (in case code has not been optimized yet), or take care
+         for possible labels in a way by setting boundary to preceding
+         CODE_LABEL.  */
+      if (GET_CODE (before) == CODE_LABEL)
+       {
+         if (before != boundary)
+           abort ();
+         break;
+       }
+
+      if (INSN_P (before))
+       note_stores (PATTERN (before), parms_set, &parm);
+    }
+  return before;
+}
+
+/* Return true if we should avoid inserting code between INSN and preceding
+   call instruction.  */
+
+bool
+keep_with_call_p (rtx insn)
+{
+  rtx set;
+
+  if (INSN_P (insn) && (set = single_set (insn)) != NULL)
+    {
+      if (GET_CODE (SET_DEST (set)) == REG
+         && REGNO (SET_DEST (set)) < FIRST_PSEUDO_REGISTER
+         && fixed_regs[REGNO (SET_DEST (set))]
+         && general_operand (SET_SRC (set), VOIDmode))
+       return true;
+      if (GET_CODE (SET_SRC (set)) == REG
+         && FUNCTION_VALUE_REGNO_P (REGNO (SET_SRC (set)))
+         && GET_CODE (SET_DEST (set)) == REG
+         && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER)
+       return true;
+      /* There may be a stack pop just after the call and before the store
+        of the return register.  Search for the actual store when deciding
+        if we can break or not.  */
+      if (SET_DEST (set) == stack_pointer_rtx)
+       {
+         rtx i2 = next_nonnote_insn (insn);
+         if (i2 && keep_with_call_p (i2))
+           return true;
+       }
+    }
+  return false;
+}
+
+/* Return true when store to register X can be hoisted to the place
+   with LIVE registers (can be NULL).  Value VAL contains destination
+   whose value will be used.  */
+
+static bool
+hoist_test_store (rtx x, rtx val, regset live)
+{
+  if (GET_CODE (x) == SCRATCH)
+    return true;
+
+  if (rtx_equal_p (x, val))
+    return true;
+
+  /* Allow subreg of X in case it is not writing just part of multireg pseudo.
+     Then we would need to update all users to care hoisting the store too.
+     Caller may represent that by specifying whole subreg as val.  */
+
+  if (GET_CODE (x) == SUBREG && rtx_equal_p (SUBREG_REG (x), val))
+    {
+      if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) > UNITS_PER_WORD
+         && GET_MODE_BITSIZE (GET_MODE (x)) <
+         GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))))
+       return false;
+      return true;
+    }
+  if (GET_CODE (x) == SUBREG)
+    x = SUBREG_REG (x);
+
+  /* Anything except register store is not hoistable.  This includes the
+     partial stores to registers.  */
+
+  if (!REG_P (x))
+    return false;
+
+  /* Pseudo registers can be always replaced by another pseudo to avoid
+     the side effect, for hard register we must ensure that they are dead.
+     Eventually we may want to add code to try turn pseudos to hards, but it
+     is unlikely useful.  */
+
+  if (REGNO (x) < FIRST_PSEUDO_REGISTER)
+    {
+      int regno = REGNO (x);
+      int n = HARD_REGNO_NREGS (regno, GET_MODE (x));
+
+      if (!live)
+       return false;
+      if (REGNO_REG_SET_P (live, regno))
+       return false;
+      while (--n > 0)
+       if (REGNO_REG_SET_P (live, regno + n))
+         return false;
+    }
+  return true;
+}
+
+
+/* Return true if INSN can be hoisted to place with LIVE hard registers
+   (LIVE can be NULL when unknown).  VAL is expected to be stored by the insn
+   and used by the hoisting pass.  */
+
+bool
+can_hoist_insn_p (rtx insn, rtx val, regset live)
+{
+  rtx pat = PATTERN (insn);
+  int i;
+
+  /* It probably does not worth the complexity to handle multiple
+     set stores.  */
+  if (!single_set (insn))
+    return false;
+  /* We can move CALL_INSN, but we need to check that all caller clobbered
+     regs are dead.  */
+  if (GET_CODE (insn) == CALL_INSN)
+    return false;
+  /* In future we will handle hoisting of libcall sequences, but
+     give up for now.  */
+  if (find_reg_note (insn, REG_RETVAL, NULL_RTX))
+    return false;
+  switch (GET_CODE (pat))
+    {
+    case SET:
+      if (!hoist_test_store (SET_DEST (pat), val, live))
+       return false;
+      break;
+    case USE:
+      /* USES do have sick semantics, so do not move them.  */
+      return false;
+      break;
+    case CLOBBER:
+      if (!hoist_test_store (XEXP (pat, 0), val, live))
+       return false;
+      break;
+    case PARALLEL:
+      for (i = 0; i < XVECLEN (pat, 0); i++)
+       {
+         rtx x = XVECEXP (pat, 0, i);
+         switch (GET_CODE (x))
+           {
+           case SET:
+             if (!hoist_test_store (SET_DEST (x), val, live))
+               return false;
+             break;
+           case USE:
+             /* We need to fix callers to really ensure availability
+                of all values insn uses, but for now it is safe to prohibit
+                hoisting of any insn having such a hidden uses.  */
+             return false;
+             break;
+           case CLOBBER:
+             if (!hoist_test_store (SET_DEST (x), val, live))
+               return false;
+             break;
+           default:
+             break;
+           }
+       }
+      break;
+    default:
+      abort ();
+    }
+  return true;
+}
+
+/* Update store after hoisting - replace all stores to pseudo registers
+   by new ones to avoid clobbering of values except for store to VAL that will
+   be updated to NEW.  */
+
+static void
+hoist_update_store (rtx insn, rtx *xp, rtx val, rtx new)
+{
+  rtx x = *xp;
+
+  if (GET_CODE (x) == SCRATCH)
+    return;
+
+  if (GET_CODE (x) == SUBREG && SUBREG_REG (x) == val)
+    validate_change (insn, xp,
+                    simplify_gen_subreg (GET_MODE (x), new, GET_MODE (new),
+                                         SUBREG_BYTE (x)), 1);
+  if (rtx_equal_p (x, val))
+    {
+      validate_change (insn, xp, new, 1);
+      return;
+    }
+  if (GET_CODE (x) == SUBREG)
+    {
+      xp = &SUBREG_REG (x);
+      x = *xp;
+    }
+
+  if (!REG_P (x))
+    abort ();
+
+  /* We've verified that hard registers are dead, so we may keep the side
+     effect.  Otherwise replace it by new pseudo.  */
+  if (REGNO (x) >= FIRST_PSEUDO_REGISTER)
+    validate_change (insn, xp, gen_reg_rtx (GET_MODE (x)), 1);
+  REG_NOTES (insn)
+    = alloc_EXPR_LIST (REG_UNUSED, *xp, REG_NOTES (insn));
+}
+
+/* Create a copy of INSN after AFTER replacing store of VAL to NEW
+   and each other side effect to pseudo register by new pseudo register.  */
+
+rtx
+hoist_insn_after (rtx insn, rtx after, rtx val, rtx new)
+{
+  rtx pat;
+  int i;
+  rtx note;
+
+  insn = emit_copy_of_insn_after (insn, after);
+  pat = PATTERN (insn);
+
+  /* Remove REG_UNUSED notes as we will re-emit them.  */
+  while ((note = find_reg_note (insn, REG_UNUSED, NULL_RTX)))
+    remove_note (insn, note);
+
+  /* To get this working callers must ensure to move everything referenced
+     by REG_EQUAL/REG_EQUIV notes too.  Lets remove them, it is probably
+     easier.  */
+  while ((note = find_reg_note (insn, REG_EQUAL, NULL_RTX)))
+    remove_note (insn, note);
+  while ((note = find_reg_note (insn, REG_EQUIV, NULL_RTX)))
+    remove_note (insn, note);
+
+  /* Remove REG_DEAD notes as they might not be valid anymore in case
+     we create redundancy.  */
+  while ((note = find_reg_note (insn, REG_DEAD, NULL_RTX)))
+    remove_note (insn, note);
+  switch (GET_CODE (pat))
+    {
+    case SET:
+      hoist_update_store (insn, &SET_DEST (pat), val, new);
+      break;
+    case USE:
+      break;
+    case CLOBBER:
+      hoist_update_store (insn, &XEXP (pat, 0), val, new);
+      break;
+    case PARALLEL:
+      for (i = 0; i < XVECLEN (pat, 0); i++)
+       {
+         rtx x = XVECEXP (pat, 0, i);
+         switch (GET_CODE (x))
+           {
+           case SET:
+             hoist_update_store (insn, &SET_DEST (x), val, new);
+             break;
+           case USE:
+             break;
+           case CLOBBER:
+             hoist_update_store (insn, &SET_DEST (x), val, new);
+             break;
+           default:
+             break;
+           }
+       }
+      break;
+    default:
+      abort ();
+    }
+  if (!apply_change_group ())
+    abort ();
+
+  return insn;
+}
+
+rtx
+hoist_insn_to_edge (rtx insn, edge e, rtx val, rtx new)
+{
+  rtx new_insn;
+
+  /* We cannot insert instructions on an abnormal critical edge.
+     It will be easier to find the culprit if we die now.  */
+  if ((e->flags & EDGE_ABNORMAL) && EDGE_CRITICAL_P (e))
+    abort ();
+
+  /* Do not use emit_insn_on_edge as we want to preserve notes and similar
+     stuff.  We also emit CALL_INSNS and firends.  */
+  if (e->insns == NULL_RTX)
+    {
+      start_sequence ();
+      emit_note (NOTE_INSN_DELETED);
+    }
+  else
+    push_to_sequence (e->insns);
+
+  new_insn = hoist_insn_after (insn, get_last_insn (), val, new);
+
+  e->insns = get_insns ();
+  end_sequence ();
+  return new_insn;
+}