ipa/97673 - fix input_location leak
[gcc.git] / gcc / rtlanal.c
index e75ff103fcbf82df6ddcf9114ea6d06fd4741360..d1240b0b7c5a8ffcc0e505c4ccc078270175bf53 100644 (file)
@@ -1,5 +1,5 @@
 /* Analyze RTL for GNU compiler.
-   Copyright (C) 1987-2017 Free Software Foundation, Inc.
+   Copyright (C) 1987-2021 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "backend.h"
 #include "target.h"
 #include "rtl.h"
+#include "rtlanal.h"
 #include "tree.h"
 #include "predict.h"
 #include "df.h"
@@ -35,6 +36,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "recog.h"
 #include "addresses.h"
 #include "rtl-iter.h"
+#include "hard-reg-set.h"
+#include "function-abi.h"
 
 /* Forward declarations */
 static void set_of_1 (rtx, const_rtx, void *);
@@ -95,7 +98,7 @@ generic_subrtx_iterator <T>::add_single_to_queue (array_type &array,
       /* A previous iteration might also have moved from the stack to the
         heap, in which case the heap array will already be big enough.  */
       if (vec_safe_length (array.heap) <= i)
-       vec_safe_grow (array.heap, i + 1);
+       vec_safe_grow (array.heap, i + 1, true);
       base = array.heap->address ();
       memcpy (base, array.stack, sizeof (array.stack));
       base[LOCAL_ELEMS] = x;
@@ -358,10 +361,10 @@ get_initial_register_offset (int from, int to)
   if (to == from)
     return 0;
 
-  /* It is not safe to call INITIAL_ELIMINATION_OFFSET
-     before the reload pass.  We need to give at least
-     an estimation for the resulting frame size.  */
-  if (! reload_completed)
+  /* It is not safe to call INITIAL_ELIMINATION_OFFSET before the epilogue
+     is completed, but we need to give at least an estimate for the stack
+     pointer based on the frame size.  */
+  if (!epilogue_completed)
     {
       offset1 = crtl->outgoing_args_size + get_frame_size ();
 #if !STACK_GROWS_DOWNWARD
@@ -462,6 +465,7 @@ rtx_addr_can_trap_p_1 (const_rtx x, poly_int64 offset, poly_int64 size,
 {
   enum rtx_code code = GET_CODE (x);
   gcc_checking_assert (mode == BLKmode || known_size_p (size));
+  poly_int64 const_x1;
 
   /* The offset must be a multiple of the mode size if we are considering
      unaligned memory references on strict alignment machines.  */
@@ -519,7 +523,7 @@ rtx_addr_can_trap_p_1 (const_rtx x, poly_int64 offset, poly_int64 size,
 
          return (!known_size_p (decl_size) || known_eq (decl_size, 0)
                  ? maybe_ne (offset, 0)
-                 : maybe_gt (offset + size, decl_size));
+                 : !known_subrange_p (offset, size, 0, decl_size));
         }
 
       return 0;
@@ -653,8 +657,8 @@ rtx_addr_can_trap_p_1 (const_rtx x, poly_int64 offset, poly_int64 size,
        return 0;
 
       /* - or it is an address that can't trap plus a constant integer.  */
-      if (CONST_INT_P (XEXP (x, 1))
-         && !rtx_addr_can_trap_p_1 (XEXP (x, 0), offset + INTVAL (XEXP (x, 1)),
+      if (poly_int_rtx_p (XEXP (x, 1), &const_x1)
+         && !rtx_addr_can_trap_p_1 (XEXP (x, 0), offset + const_x1,
                                     size, mode, unaligned_mems))
        return 0;
 
@@ -809,10 +813,9 @@ rtx_addr_varies_p (const_rtx x, bool for_alias)
 /* Return the CALL in X if there is one.  */
 
 rtx
-get_call_rtx_from (rtx x)
+get_call_rtx_from (const rtx_insn *insn)
 {
-  if (INSN_P (x))
-    x = PATTERN (x);
+  rtx x = PATTERN (insn);
   if (GET_CODE (x) == PARALLEL)
     x = XVECEXP (x, 0, 0);
   if (GET_CODE (x) == SET)
@@ -821,6 +824,24 @@ get_call_rtx_from (rtx x)
     return x;
   return NULL_RTX;
 }
+
+/* Get the declaration of the function called by INSN.  */
+
+tree
+get_call_fndecl (const rtx_insn *insn)
+{
+  rtx note, datum;
+
+  note = find_reg_note (insn, REG_CALL_DECL, NULL_RTX);
+  if (note == NULL_RTX)
+    return NULL_TREE;
+
+  datum = XEXP (note, 0);
+  if (datum != NULL_RTX)
+    return SYMBOL_REF_DECL (datum);
+
+  return NULL_TREE;
+}
 \f
 /* Return the value of the integer term in X, if one is apparent;
    otherwise return 0.
@@ -1247,8 +1268,8 @@ reg_set_p (const_rtx reg, const_rtx insn)
          || (CALL_P (insn)
              && ((REG_P (reg)
                   && REGNO (reg) < FIRST_PSEUDO_REGISTER
-                  && overlaps_hard_reg_set_p (regs_invalidated_by_call,
-                                              GET_MODE (reg), REGNO (reg)))
+                  && (insn_callee_abi (as_a<const rtx_insn *> (insn))
+                      .clobbers_reg_p (GET_MODE (reg), REGNO (reg))))
                  || MEM_P (reg)
                  || find_reg_fusage (insn, CLOBBER, reg)))))
     return true;
@@ -1395,13 +1416,15 @@ modified_in_p (const_rtx x, const_rtx insn)
 bool
 read_modify_subreg_p (const_rtx x)
 {
-  unsigned int isize, osize;
   if (GET_CODE (x) != SUBREG)
     return false;
-  isize = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)));
-  osize = GET_MODE_SIZE (GET_MODE (x));
-  return isize > osize
-        && isize > REGMODE_NATURAL_SIZE (GET_MODE (SUBREG_REG (x)));
+  poly_uint64 isize = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)));
+  poly_uint64 osize = GET_MODE_SIZE (GET_MODE (x));
+  poly_uint64 regsize = REGMODE_NATURAL_SIZE (GET_MODE (SUBREG_REG (x)));
+  /* The inner and outer modes of a subreg must be ordered, so that we
+     can tell whether they're paradoxical or partial.  */
+  gcc_checking_assert (ordered_p (isize, osize));
+  return (maybe_gt (isize, osize) && maybe_gt (isize, regsize));
 }
 \f
 /* Helper function for set_of.  */
@@ -1428,10 +1451,45 @@ set_of (const_rtx pat, const_rtx insn)
   struct set_of_data data;
   data.found = NULL_RTX;
   data.pat = pat;
-  note_stores (INSN_P (insn) ? PATTERN (insn) : insn, set_of_1, &data);
+  note_pattern_stores (INSN_P (insn) ? PATTERN (insn) : insn, set_of_1, &data);
   return data.found;
 }
 
+/* Check whether instruction pattern PAT contains a SET with the following
+   properties:
+
+   - the SET is executed unconditionally; and
+   - either:
+     - the destination of the SET is a REG that contains REGNO; or
+     - both:
+       - the destination of the SET is a SUBREG of such a REG; and
+       - writing to the subreg clobbers all of the SUBREG_REG
+        (in other words, read_modify_subreg_p is false).
+
+   If PAT does have a SET like that, return the set, otherwise return null.
+
+   This is intended to be an alternative to single_set for passes that
+   can handle patterns with multiple_sets.  */
+rtx
+simple_regno_set (rtx pat, unsigned int regno)
+{
+  if (GET_CODE (pat) == PARALLEL)
+    {
+      int last = XVECLEN (pat, 0) - 1;
+      for (int i = 0; i < last; ++i)
+       if (rtx set = simple_regno_set (XVECEXP (pat, 0, i), regno))
+         return set;
+
+      pat = XVECEXP (pat, 0, last);
+    }
+
+  if (GET_CODE (pat) == SET
+      && covers_regno_no_parallel_p (SET_DEST (pat), regno))
+    return pat;
+
+  return nullptr;
+}
+
 /* Add all hard register in X to *PSET.  */
 void
 find_all_hard_regs (const_rtx x, HARD_REG_SET *pset)
@@ -1457,22 +1515,20 @@ record_hard_reg_sets (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data)
 }
 
 /* Examine INSN, and compute the set of hard registers written by it.
-   Store it in *PSET.  Should only be called after reload.  */
+   Store it in *PSET.  Should only be called after reload.
+
+   IMPLICIT is true if we should include registers that are fully-clobbered
+   by calls.  This should be used with caution, since it doesn't include
+   partially-clobbered registers.  */
 void
 find_all_hard_reg_sets (const rtx_insn *insn, HARD_REG_SET *pset, bool implicit)
 {
   rtx link;
 
   CLEAR_HARD_REG_SET (*pset);
-  note_stores (PATTERN (insn), record_hard_reg_sets, pset);
-  if (CALL_P (insn))
-    {
-      if (implicit)
-       IOR_HARD_REG_SET (*pset, call_used_reg_set);
-
-      for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
-       record_hard_reg_sets (XEXP (link, 0), NULL, pset);
-    }
+  note_stores (insn, record_hard_reg_sets, pset);
+  if (CALL_P (insn) && implicit)
+    *pset |= insn_callee_abi (insn).full_reg_clobbers ();
   for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
     if (REG_NOTE_KIND (link) == REG_INC)
       record_hard_reg_sets (XEXP (link, 0), NULL, pset);
@@ -1599,6 +1655,10 @@ set_noop_p (const_rtx set)
        return 0;
       src = SUBREG_REG (src);
       dst = SUBREG_REG (dst);
+      if (GET_MODE (src) != GET_MODE (dst))
+       /* It is hard to tell whether subregs refer to the same bits, so act
+          conservatively and return 0.  */
+       return 0;
     }
 
   /* It is a NOOP if destination overlaps with selected src vector
@@ -1611,15 +1671,22 @@ set_noop_p (const_rtx set)
       int i;
       rtx par = XEXP (src, 1);
       rtx src0 = XEXP (src, 0);
-      int c0 = INTVAL (XVECEXP (par, 0, 0));
-      HOST_WIDE_INT offset = GET_MODE_UNIT_SIZE (GET_MODE (src0)) * c0;
+      poly_int64 c0;
+      if (!poly_int_rtx_p (XVECEXP (par, 0, 0), &c0))
+       return 0;
+      poly_int64 offset = GET_MODE_UNIT_SIZE (GET_MODE (src0)) * c0;
 
       for (i = 1; i < XVECLEN (par, 0); i++)
-       if (INTVAL (XVECEXP (par, 0, i)) != c0 + i)
-         return 0;
+       {
+         poly_int64 c0i;
+         if (!poly_int_rtx_p (XVECEXP (par, 0, i), &c0i)
+             || maybe_ne (c0i, c0 + i))
+           return 0;
+       }
       return
-       simplify_subreg_regno (REGNO (src0), GET_MODE (src0),
-                              offset, GET_MODE (dst)) == (int) REGNO (dst);
+       REG_CAN_CHANGE_MODE_P (REGNO (dst), GET_MODE (src0), GET_MODE (dst))
+       && simplify_subreg_regno (REGNO (src0), GET_MODE (src0),
+                                 offset, GET_MODE (dst)) == (int) REGNO (dst);
     }
 
   return (REG_P (src) && REG_P (dst)
@@ -1637,10 +1704,6 @@ noop_move_p (const rtx_insn *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;
-
   /* Check the code to be executed for COND_EXEC.  */
   if (GET_CODE (pat) == COND_EXEC)
     pat = COND_EXEC_CODE (pat);
@@ -1657,8 +1720,7 @@ noop_move_p (const rtx_insn *insn)
        {
          rtx tem = XVECEXP (pat, 0, i);
 
-         if (GET_CODE (tem) == USE
-             || GET_CODE (tem) == CLOBBER)
+         if (GET_CODE (tem) == USE || GET_CODE (tem) == CLOBBER)
            continue;
 
          if (GET_CODE (tem) != SET || ! set_noop_p (tem))
@@ -1791,7 +1853,7 @@ reg_overlap_mentioned_p (const_rtx x, const_rtx in)
 {
   unsigned int regno, endregno;
 
-  /* If either argument is a constant, then modifying X can not
+  /* If either argument is a constant, then modifying X cannot
      affect IN.  Here we look at IN, we can profitably combine
      CONSTANT_P (x) with the switch statement below.  */
   if (CONSTANT_P (in))
@@ -1800,6 +1862,7 @@ reg_overlap_mentioned_p (const_rtx x, const_rtx in)
  recurse:
   switch (GET_CODE (x))
     {
+    case CLOBBER:
     case STRICT_LOW_PART:
     case ZERO_EXTRACT:
     case SIGN_EXTRACT:
@@ -1883,7 +1946,8 @@ reg_overlap_mentioned_p (const_rtx x, const_rtx in)
   the SUBREG will be passed.  */
 
 void
-note_stores (const_rtx x, void (*fun) (rtx, const_rtx, void *), void *data)
+note_pattern_stores (const_rtx x,
+                    void (*fun) (rtx, const_rtx, void *), void *data)
 {
   int i;
 
@@ -1915,7 +1979,22 @@ note_stores (const_rtx x, void (*fun) (rtx, const_rtx, void *), void *data)
 
   else if (GET_CODE (x) == PARALLEL)
     for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
-      note_stores (XVECEXP (x, 0, i), fun, data);
+      note_pattern_stores (XVECEXP (x, 0, i), fun, data);
+}
+
+/* Same, but for an instruction.  If the instruction is a call, include
+   any CLOBBERs in its CALL_INSN_FUNCTION_USAGE.  */
+
+void
+note_stores (const rtx_insn *insn,
+            void (*fun) (rtx, const_rtx, void *), void *data)
+{
+  if (CALL_P (insn))
+    for (rtx link = CALL_INSN_FUNCTION_USAGE (insn);
+        link; link = XEXP (link, 1))
+      if (GET_CODE (XEXP (link, 0)) == CLOBBER)
+       note_pattern_stores (XEXP (link, 0), fun, data);
+  note_pattern_stores (PATTERN (insn), fun, data);
 }
 \f
 /* Like notes_stores, but call FUN for each expression that is being
@@ -2006,6 +2085,287 @@ note_uses (rtx *pbody, void (*fun) (rtx *, void *), void *data)
       return;
     }
 }
+
+/* Try to add a description of REG X to this object, stopping once
+   the REF_END limit has been reached.  FLAGS is a bitmask of
+   rtx_obj_reference flags that describe the context.  */
+
+void
+rtx_properties::try_to_add_reg (const_rtx x, unsigned int flags)
+{
+  if (REG_NREGS (x) != 1)
+    flags |= rtx_obj_flags::IS_MULTIREG;
+  machine_mode mode = GET_MODE (x);
+  unsigned int start_regno = REGNO (x);
+  unsigned int end_regno = END_REGNO (x);
+  for (unsigned int regno = start_regno; regno < end_regno; ++regno)
+    if (ref_iter != ref_end)
+      *ref_iter++ = rtx_obj_reference (regno, flags, mode,
+                                      regno - start_regno);
+}
+
+/* Add a description of destination X to this object.  FLAGS is a bitmask
+   of rtx_obj_reference flags that describe the context.
+
+   This routine accepts all rtxes that can legitimately appear in a
+   SET_DEST.  */
+
+void
+rtx_properties::try_to_add_dest (const_rtx x, unsigned int flags)
+{
+  /* If we have a PARALLEL, SET_DEST is a list of EXPR_LIST expressions,
+     each of whose first operand is a register.  */
+  if (__builtin_expect (GET_CODE (x) == PARALLEL, 0))
+    {
+      for (int i = XVECLEN (x, 0) - 1; i >= 0; --i)
+       if (rtx dest = XEXP (XVECEXP (x, 0, i), 0))
+         try_to_add_dest (dest, flags);
+      return;
+    }
+
+  unsigned int base_flags = flags & rtx_obj_flags::STICKY_FLAGS;
+  flags |= rtx_obj_flags::IS_WRITE;
+  for (;;)
+    if (GET_CODE (x) == ZERO_EXTRACT)
+      {
+       try_to_add_src (XEXP (x, 1), base_flags);
+       try_to_add_src (XEXP (x, 2), base_flags);
+       flags |= rtx_obj_flags::IS_READ;
+       x = XEXP (x, 0);
+      }
+    else if (GET_CODE (x) == STRICT_LOW_PART)
+      {
+       flags |= rtx_obj_flags::IS_READ;
+       x = XEXP (x, 0);
+      }
+    else if (GET_CODE (x) == SUBREG)
+      {
+       flags |= rtx_obj_flags::IN_SUBREG;
+       if (read_modify_subreg_p (x))
+         flags |= rtx_obj_flags::IS_READ;
+       x = SUBREG_REG (x);
+      }
+    else
+      break;
+
+  if (MEM_P (x))
+    {
+      if (ref_iter != ref_end)
+       *ref_iter++ = rtx_obj_reference (MEM_REGNO, flags, GET_MODE (x));
+
+      unsigned int addr_flags = base_flags | rtx_obj_flags::IN_MEM_STORE;
+      if (flags & rtx_obj_flags::IS_READ)
+       addr_flags |= rtx_obj_flags::IN_MEM_LOAD;
+      try_to_add_src (XEXP (x, 0), addr_flags);
+      return;
+    }
+
+  if (__builtin_expect (REG_P (x), 1))
+    {
+      /* We want to keep sp alive everywhere -  by making all
+        writes to sp also use sp. */
+      if (REGNO (x) == STACK_POINTER_REGNUM)
+       flags |= rtx_obj_flags::IS_READ;
+      try_to_add_reg (x, flags);
+      return;
+    }
+}
+
+/* Try to add a description of source X to this object, stopping once
+   the REF_END limit has been reached.  FLAGS is a bitmask of
+   rtx_obj_reference flags that describe the context.
+
+   This routine accepts all rtxes that can legitimately appear in a SET_SRC.  */
+
+void
+rtx_properties::try_to_add_src (const_rtx x, unsigned int flags)
+{
+  unsigned int base_flags = flags & rtx_obj_flags::STICKY_FLAGS;
+  subrtx_iterator::array_type array;
+  FOR_EACH_SUBRTX (iter, array, x, NONCONST)
+    {
+      const_rtx x = *iter;
+      rtx_code code = GET_CODE (x);
+      if (code == REG)
+       try_to_add_reg (x, flags | rtx_obj_flags::IS_READ);
+      else if (code == MEM)
+       {
+         if (MEM_VOLATILE_P (x))
+           has_volatile_refs = true;
+
+         if (!MEM_READONLY_P (x) && ref_iter != ref_end)
+           {
+             auto mem_flags = flags | rtx_obj_flags::IS_READ;
+             *ref_iter++ = rtx_obj_reference (MEM_REGNO, mem_flags,
+                                              GET_MODE (x));
+           }
+
+         try_to_add_src (XEXP (x, 0),
+                         base_flags | rtx_obj_flags::IN_MEM_LOAD);
+         iter.skip_subrtxes ();
+       }
+      else if (code == SUBREG)
+       {
+         try_to_add_src (SUBREG_REG (x), flags | rtx_obj_flags::IN_SUBREG);
+         iter.skip_subrtxes ();
+       }
+      else if (code == UNSPEC_VOLATILE)
+       has_volatile_refs = true;
+      else if (code == ASM_INPUT || code == ASM_OPERANDS)
+       {
+         has_asm = true;
+         if (MEM_VOLATILE_P (x))
+           has_volatile_refs = true;
+       }
+      else if (code == PRE_INC
+              || code == PRE_DEC
+              || code == POST_INC
+              || code == POST_DEC
+              || code == PRE_MODIFY
+              || code == POST_MODIFY)
+       {
+         has_pre_post_modify = true;
+
+         unsigned int addr_flags = (base_flags
+                                    | rtx_obj_flags::IS_PRE_POST_MODIFY
+                                    | rtx_obj_flags::IS_READ);
+         try_to_add_dest (XEXP (x, 0), addr_flags);
+         if (code == PRE_MODIFY || code == POST_MODIFY)
+           iter.substitute (XEXP (XEXP (x, 1), 1));
+         else
+           iter.skip_subrtxes ();
+       }
+      else if (code == CALL)
+       has_call = true;
+    }
+}
+
+/* Try to add a description of instruction pattern PAT to this object,
+   stopping once the REF_END limit has been reached.  */
+
+void
+rtx_properties::try_to_add_pattern (const_rtx pat)
+{
+  switch (GET_CODE (pat))
+    {
+    case COND_EXEC:
+      try_to_add_src (COND_EXEC_TEST (pat));
+      try_to_add_pattern (COND_EXEC_CODE (pat));
+      break;
+
+    case PARALLEL:
+      {
+       int last = XVECLEN (pat, 0) - 1;
+       for (int i = 0; i < last; ++i)
+         try_to_add_pattern (XVECEXP (pat, 0, i));
+       try_to_add_pattern (XVECEXP (pat, 0, last));
+       break;
+      }
+
+    case ASM_OPERANDS:
+      for (int i = 0, len = ASM_OPERANDS_INPUT_LENGTH (pat); i < len; ++i)
+       try_to_add_src (ASM_OPERANDS_INPUT (pat, i));
+      break;
+
+    case CLOBBER:
+      try_to_add_dest (XEXP (pat, 0), rtx_obj_flags::IS_CLOBBER);
+      break;
+
+    case SET:
+      try_to_add_dest (SET_DEST (pat));
+      try_to_add_src (SET_SRC (pat));
+      break;
+
+    default:
+      /* All the other possibilities never store and can use a normal
+        rtx walk.  This includes:
+
+        - USE
+        - TRAP_IF
+        - PREFETCH
+        - UNSPEC
+        - UNSPEC_VOLATILE.  */
+      try_to_add_src (pat);
+      break;
+    }
+}
+
+/* Try to add a description of INSN to this object, stopping once
+   the REF_END limit has been reached.  INCLUDE_NOTES is true if the
+   description should include REG_EQUAL and REG_EQUIV notes; all such
+   references will then be marked with rtx_obj_flags::IN_NOTE.
+
+   For calls, this description includes all accesses in
+   CALL_INSN_FUNCTION_USAGE.  It also include all implicit accesses
+   to global registers by the target function.  However, it does not
+   include clobbers performed by the target function; callers that want
+   this information should instead use the function_abi interface.  */
+
+void
+rtx_properties::try_to_add_insn (const rtx_insn *insn, bool include_notes)
+{
+  if (CALL_P (insn))
+    {
+      /* Adding the global registers first removes a situation in which
+        a fixed-form clobber of register R could come before a real set
+        of register R.  */
+      if (!hard_reg_set_empty_p (global_reg_set))
+       {
+         unsigned int flags = (rtx_obj_flags::IS_READ
+                               | rtx_obj_flags::IS_WRITE);
+         for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)
+           if (global_regs[regno] && ref_iter != ref_end)
+             *ref_iter++ = rtx_obj_reference (regno, flags,
+                                              reg_raw_mode[regno], 0);
+       }
+      if (ref_iter != ref_end && !RTL_CONST_CALL_P (insn))
+       {
+         auto mem_flags = rtx_obj_flags::IS_READ;
+         if (!RTL_PURE_CALL_P (insn))
+           mem_flags |= rtx_obj_flags::IS_WRITE;
+         *ref_iter++ = rtx_obj_reference (MEM_REGNO, mem_flags, BLKmode);
+       }
+      try_to_add_pattern (PATTERN (insn));
+      for (rtx link = CALL_INSN_FUNCTION_USAGE (insn); link;
+          link = XEXP (link, 1))
+       {
+         rtx x = XEXP (link, 0);
+         if (GET_CODE (x) == CLOBBER)
+           try_to_add_dest (XEXP (x, 0), rtx_obj_flags::IS_CLOBBER);
+         else if (GET_CODE (x) == USE)
+           try_to_add_src (XEXP (x, 0));
+       }
+    }
+  else
+    try_to_add_pattern (PATTERN (insn));
+
+  if (include_notes)
+    for (rtx note = REG_NOTES (insn); note; note = XEXP (note, 1))
+      if (REG_NOTE_KIND (note) == REG_EQUAL
+         || REG_NOTE_KIND (note) == REG_EQUIV)
+       try_to_add_note (XEXP (note, 0));
+}
+
+/* Grow the storage by a bit while keeping the contents of the first
+   START elements.  */
+
+void
+vec_rtx_properties_base::grow (ptrdiff_t start)
+{
+  /* The same heuristic that vec uses.  */
+  ptrdiff_t new_elems = (ref_end - ref_begin) * 3 / 2;
+  if (ref_begin == m_storage)
+    {
+      ref_begin = XNEWVEC (rtx_obj_reference, new_elems);
+      if (start)
+       memcpy (ref_begin, m_storage, start * sizeof (rtx_obj_reference));
+    }
+  else
+    ref_begin = reinterpret_cast<rtx_obj_reference *>
+      (xrealloc (ref_begin, new_elems * sizeof (rtx_obj_reference)));
+  ref_iter = ref_begin + start;
+  ref_end = ref_begin + new_elems;
+}
 \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
@@ -2437,10 +2797,11 @@ remove_note (rtx_insn *insn, const_rtx note)
 }
 
 /* Remove REG_EQUAL and/or REG_EQUIV notes if INSN has such notes.
-   Return true if any note has been removed.  */
+   If NO_RESCAN is false and any notes were removed, call
+   df_notes_rescan.  Return true if any note has been removed.  */
 
 bool
-remove_reg_equal_equiv_notes (rtx_insn *insn)
+remove_reg_equal_equiv_notes (rtx_insn *insn, bool no_rescan)
 {
   rtx *loc;
   bool ret = false;
@@ -2457,6 +2818,8 @@ remove_reg_equal_equiv_notes (rtx_insn *insn)
       else
        loc = &XEXP (*loc, 1);
     }
+  if (ret && !no_rescan)
+    df_notes_rescan (insn);
   return ret;
 }
 
@@ -2828,10 +3191,28 @@ may_trap_p_1 (const_rtx x, unsigned flags)
     case UMOD:
       if (HONOR_SNANS (x))
        return 1;
-      if (SCALAR_FLOAT_MODE_P (GET_MODE (x)))
+      if (FLOAT_MODE_P (GET_MODE (x)))
        return flag_trapping_math;
       if (!CONSTANT_P (XEXP (x, 1)) || (XEXP (x, 1) == const0_rtx))
        return 1;
+      if (GET_CODE (XEXP (x, 1)) == CONST_VECTOR)
+       {
+         /* For CONST_VECTOR, return 1 if any element is or might be zero.  */
+         unsigned int n_elts;
+         rtx op = XEXP (x, 1);
+         if (!GET_MODE_NUNITS (GET_MODE (op)).is_constant (&n_elts))
+           {
+             if (!CONST_VECTOR_DUPLICATE_P (op))
+               return 1;
+             for (unsigned i = 0; i < (unsigned int) XVECLEN (op, 0); i++)
+               if (CONST_VECTOR_ENCODED_ELT (op, i) == const0_rtx)
+                 return 1;
+           }
+         else
+           for (unsigned i = 0; i < n_elts; i++)
+             if (CONST_VECTOR_ELT (op, i) == const0_rtx)
+               return 1;
+       }
       break;
 
     case EXPR_LIST:
@@ -2880,12 +3261,16 @@ may_trap_p_1 (const_rtx x, unsigned flags)
     case NEG:
     case ABS:
     case SUBREG:
+    case VEC_MERGE:
+    case VEC_SELECT:
+    case VEC_CONCAT:
+    case VEC_DUPLICATE:
       /* These operations don't trap even with floating point.  */
       break;
 
     default:
       /* Any floating arithmetic may trap.  */
-      if (SCALAR_FLOAT_MODE_P (GET_MODE (x)) && flag_trapping_math)
+      if (FLOAT_MODE_P (GET_MODE (x)) && flag_trapping_math)
        return 1;
     }
 
@@ -2962,64 +3347,6 @@ may_trap_or_fault_p (const_rtx x)
   return may_trap_p_1 (x, 1);
 }
 \f
-/* Return nonzero if X contains a comparison that is not either EQ or NE,
-   i.e., an inequality.  */
-
-int
-inequality_comparisons_p (const_rtx x)
-{
-  const char *fmt;
-  int len, i;
-  const enum rtx_code code = GET_CODE (x);
-
-  switch (code)
-    {
-    case REG:
-    case SCRATCH:
-    case PC:
-    case CC0:
-    CASE_CONST_ANY:
-    case CONST:
-    case LABEL_REF:
-    case SYMBOL_REF:
-      return 0;
-
-    case LT:
-    case LTU:
-    case GT:
-    case GTU:
-    case LE:
-    case LEU:
-    case GE:
-    case GEU:
-      return 1;
-
-    default:
-      break;
-    }
-
-  len = GET_RTX_LENGTH (code);
-  fmt = GET_RTX_FORMAT (code);
-
-  for (i = 0; i < len; i++)
-    {
-      if (fmt[i] == 'e')
-       {
-         if (inequality_comparisons_p (XEXP (x, i)))
-           return 1;
-       }
-      else if (fmt[i] == 'E')
-       {
-         int j;
-         for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-           if (inequality_comparisons_p (XVECEXP (x, i, j)))
-             return 1;
-       }
-    }
-
-  return 0;
-}
-\f
 /* Replace any occurrence of FROM in X with TO.  The function does
    not enter into CONST_DOUBLE for the replace.
 
@@ -3232,6 +3559,23 @@ tablejump_p (const rtx_insn *insn, rtx_insn **labelp,
   return true;
 }
 
+/* For INSN known to satisfy tablejump_p, determine if it actually is a
+   CASESI.  Return the insn pattern if so, NULL_RTX otherwise.  */
+
+rtx
+tablejump_casesi_pattern (const rtx_insn *insn)
+{
+  rtx tmp;
+
+  if ((tmp = single_set (insn)) != NULL
+      && SET_DEST (tmp) == pc_rtx
+      && GET_CODE (SET_SRC (tmp)) == IF_THEN_ELSE
+      && GET_CODE (XEXP (SET_SRC (tmp), 2)) == LABEL_REF)
+    return tmp;
+
+  return NULL_RTX;
+}
+
 /* 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.  */
@@ -3344,7 +3688,7 @@ for_each_inc_dec_find_inc_dec (rtx mem, for_each_inc_dec_fn fn, void *data)
     case PRE_INC:
     case POST_INC:
       {
-       int size = GET_MODE_SIZE (GET_MODE (mem));
+       poly_int64 size = GET_MODE_SIZE (GET_MODE (mem));
        rtx r1 = XEXP (x, 0);
        rtx c = gen_int_mode (size, GET_MODE (r1));
        return fn (mem, x, r1, r1, c, data);
@@ -3353,7 +3697,7 @@ for_each_inc_dec_find_inc_dec (rtx mem, for_each_inc_dec_fn fn, void *data)
     case PRE_DEC:
     case POST_DEC:
       {
-       int size = GET_MODE_SIZE (GET_MODE (mem));
+       poly_int64 size = GET_MODE_SIZE (GET_MODE (mem));
        rtx r1 = XEXP (x, 0);
        rtx c = gen_int_mode (-size, GET_MODE (r1));
        return fn (mem, x, r1, r1, c, data);
@@ -3571,23 +3915,31 @@ loc_mentioned_in_p (rtx *loc, const_rtx in)
   return 0;
 }
 
-/* Helper function for subreg_lsb.  Given a subreg's OUTER_MODE, INNER_MODE,
-   and SUBREG_BYTE, return the bit offset where the subreg begins
-   (counting from the least significant bit of the operand).  */
+/* Reinterpret a subreg as a bit extraction from an integer and return
+   the position of the least significant bit of the extracted value.
+   In other words, if the extraction were performed as a shift right
+   and mask, return the number of bits to shift right.
+
+   The outer value of the subreg has OUTER_BYTES bytes and starts at
+   byte offset SUBREG_BYTE within an inner value of INNER_BYTES bytes.  */
 
 poly_uint64
-subreg_lsb_1 (machine_mode outer_mode,
-             machine_mode inner_mode,
-             poly_uint64 subreg_byte)
+subreg_size_lsb (poly_uint64 outer_bytes,
+                poly_uint64 inner_bytes,
+                poly_uint64 subreg_byte)
 {
   poly_uint64 subreg_end, trailing_bytes, byte_pos;
 
   /* A paradoxical subreg begins at bit position 0.  */
-  if (paradoxical_subreg_p (outer_mode, inner_mode))
-    return 0;
+  gcc_checking_assert (ordered_p (outer_bytes, inner_bytes));
+  if (maybe_gt (outer_bytes, inner_bytes))
+    {
+      gcc_checking_assert (known_eq (subreg_byte, 0U));
+      return 0;
+    }
 
-  subreg_end = subreg_byte + GET_MODE_SIZE (outer_mode);
-  trailing_bytes = GET_MODE_SIZE (inner_mode) - subreg_end;
+  subreg_end = subreg_byte + outer_bytes;
+  trailing_bytes = inner_bytes - subreg_end;
   if (WORDS_BIG_ENDIAN && BYTES_BIG_ENDIAN)
     byte_pos = trailing_bytes;
   else if (!WORDS_BIG_ENDIAN && !BYTES_BIG_ENDIAN)
@@ -3692,8 +4044,9 @@ subreg_get_info (unsigned int xregno, machine_mode xmode,
 
   gcc_assert (xregno < FIRST_PSEUDO_REGISTER);
 
-  unsigned int xsize = GET_MODE_SIZE (xmode);
-  unsigned int ysize = GET_MODE_SIZE (ymode);
+  poly_uint64 xsize = GET_MODE_SIZE (xmode);
+  poly_uint64 ysize = GET_MODE_SIZE (ymode);
+
   bool rknown = false;
 
   /* If the register representation of a non-scalar mode has holes in it,
@@ -3703,10 +4056,11 @@ subreg_get_info (unsigned int xregno, machine_mode xmode,
   if (HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode))
     {
       /* As a consequence, we must be dealing with a constant number of
-        scalars, and thus a constant offset.  */
+        scalars, and thus a constant offset and number of units.  */
       HOST_WIDE_INT coffset = offset.to_constant ();
+      HOST_WIDE_INT cysize = ysize.to_constant ();
       nregs_xmode = HARD_REGNO_NREGS_WITH_PADDING (xregno, xmode);
-      unsigned int nunits = GET_MODE_NUNITS (xmode);
+      unsigned int nunits = GET_MODE_NUNITS (xmode).to_constant ();
       scalar_mode xmode_unit = GET_MODE_INNER (xmode);
       gcc_assert (HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode_unit));
       gcc_assert (nregs_xmode
@@ -3725,7 +4079,7 @@ subreg_get_info (unsigned int xregno, machine_mode xmode,
         of each unit.  */
       if ((coffset / GET_MODE_SIZE (xmode_unit) + 1 < nunits)
          && (coffset / GET_MODE_SIZE (xmode_unit)
-             != ((coffset + ysize - 1) / GET_MODE_SIZE (xmode_unit))))
+             != ((coffset + cysize - 1) / GET_MODE_SIZE (xmode_unit))))
        {
          info->representable_p = false;
          rknown = true;
@@ -3736,8 +4090,12 @@ subreg_get_info (unsigned int xregno, machine_mode xmode,
 
   nregs_ymode = hard_regno_nregs (xregno, ymode);
 
+  /* Subreg sizes must be ordered, so that we can tell whether they are
+     partial, paradoxical or complete.  */
+  gcc_checking_assert (ordered_p (xsize, ysize));
+
   /* Paradoxical subregs are otherwise valid.  */
-  if (!rknown && known_eq (offset, 0U) && ysize > xsize)
+  if (!rknown && known_eq (offset, 0U) && maybe_gt (ysize, xsize))
     {
       info->representable_p = true;
       /* If this is a big endian paradoxical subreg, which uses more
@@ -3759,20 +4117,19 @@ subreg_get_info (unsigned int xregno, machine_mode xmode,
 
   /* If registers store different numbers of bits in the different
      modes, we cannot generally form this subreg.  */
+  poly_uint64 regsize_xmode, regsize_ymode;
   if (!HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode)
       && !HARD_REGNO_NREGS_HAS_PADDING (xregno, ymode)
-      && (xsize % nregs_xmode) == 0
-      && (ysize % nregs_ymode) == 0)
+      && multiple_p (xsize, nregs_xmode, &regsize_xmode)
+      && multiple_p (ysize, nregs_ymode, &regsize_ymode))
     {
-      int regsize_xmode = xsize / nregs_xmode;
-      int regsize_ymode = ysize / nregs_ymode;
       if (!rknown
-         && ((nregs_ymode > 1 && regsize_xmode > regsize_ymode)
-             || (nregs_xmode > 1 && regsize_ymode > regsize_xmode)))
+         && ((nregs_ymode > 1 && maybe_gt (regsize_xmode, regsize_ymode))
+             || (nregs_xmode > 1 && maybe_gt (regsize_ymode, regsize_xmode))))
        {
          info->representable_p = false;
-         info->nregs = CEIL (ysize, regsize_xmode);
-         if (!can_div_trunc_p (offset, regsize_xmode, &info->offset))
+         if (!can_div_away_from_zero_p (ysize, regsize_xmode, &info->nregs)
+             || !can_div_trunc_p (offset, regsize_xmode, &info->offset))
            /* Checked by validate_subreg.  We must know at compile time
               which inner registers are being accessed.  */
            gcc_unreachable ();
@@ -3798,7 +4155,7 @@ subreg_get_info (unsigned int xregno, machine_mode xmode,
       HOST_WIDE_INT count;
       if (!rknown
          && WORDS_BIG_ENDIAN == REG_WORDS_BIG_ENDIAN
-         && regsize_xmode == regsize_ymode
+         && known_eq (regsize_xmode, regsize_ymode)
          && constant_multiple_p (offset, regsize_ymode, &count))
        {
          info->representable_p = true;
@@ -3835,8 +4192,7 @@ subreg_get_info (unsigned int xregno, machine_mode xmode,
      be exact, otherwise we don't know how to verify the constraint.
      These conditions may be relaxed but subreg_regno_offset would
      need to be redesigned.  */
-  gcc_assert ((xsize % num_blocks) == 0);
-  poly_uint64 bytes_per_block = xsize / num_blocks;
+  poly_uint64 bytes_per_block = exact_div (xsize, num_blocks);
 
   /* Get the number of the first block that contains the subreg and the byte
      offset of the subreg from the start of that block.  */
@@ -3921,9 +4277,7 @@ simplify_subreg_regno (unsigned int xregno, machine_mode xmode,
   /* Give the backend a chance to disallow the mode change.  */
   if (GET_MODE_CLASS (xmode) != MODE_COMPLEX_INT
       && GET_MODE_CLASS (xmode) != MODE_COMPLEX_FLOAT
-      && !REG_CAN_CHANGE_MODE_P (xregno, xmode, ymode)
-      /* We can use mode change in LRA for some transformations.  */
-      && ! lra_in_progress)
+      && !REG_CAN_CHANGE_MODE_P (xregno, xmode, ymode))
     return -1;
 
   /* We shouldn't simplify stack-related registers.  */
@@ -4079,7 +4433,7 @@ find_first_parameter_load (rtx_insn *call_insn, rtx_insn *boundary)
       if (INSN_P (before))
        {
          int nregs_old = parm.nregs;
-         note_stores (PATTERN (before), parms_set, &parm);
+         note_stores (before, parms_set, &parm);
          /* If we found something that did not set a parameter reg,
             we're done.  Do not keep going, as that might result
             in hoisting an insn before the setting of a pseudo
@@ -4179,18 +4533,23 @@ rtx_cost (rtx x, machine_mode mode, enum rtx_code outer_code,
   const char *fmt;
   int total;
   int factor;
+  unsigned mode_size;
 
   if (x == 0)
     return 0;
 
-  if (GET_MODE (x) != VOIDmode)
+  if (GET_CODE (x) == SET)
+    /* A SET doesn't have a mode, so let's look at the SET_DEST to get
+       the mode for the factor.  */
+    mode = GET_MODE (SET_DEST (x));
+  else if (GET_MODE (x) != VOIDmode)
     mode = GET_MODE (x);
 
+  mode_size = estimated_poly_value (GET_MODE_SIZE (mode));
+
   /* A size N times larger than UNITS_PER_WORD likely needs N times as
      many insns, taking N times as long.  */
-  factor = GET_MODE_SIZE (mode) / UNITS_PER_WORD;
-  if (factor == 0)
-    factor = 1;
+  factor = mode_size > UNITS_PER_WORD ? mode_size / UNITS_PER_WORD : 1;
 
   /* Compute the default costs of certain things.
      Note that targetm.rtx_costs can override the defaults.  */
@@ -4215,14 +4574,6 @@ rtx_cost (rtx x, machine_mode mode, enum rtx_code outer_code,
       /* Used in combine.c as a marker.  */
       total = 0;
       break;
-    case SET:
-      /* A SET doesn't have a mode, so let's look at the SET_DEST to get
-        the mode for the factor.  */
-      mode = GET_MODE (SET_DEST (x));
-      factor = GET_MODE_SIZE (mode) / UNITS_PER_WORD;
-      if (factor == 0)
-       factor = 1;
-      /* FALLTHRU */
     default:
       total = factor * COSTS_N_INSNS (1);
     }
@@ -4423,8 +4774,9 @@ nonzero_bits1 (const_rtx x, scalar_int_mode mode, const_rtx known_x,
 {
   unsigned HOST_WIDE_INT nonzero = GET_MODE_MASK (mode);
   unsigned HOST_WIDE_INT inner_nz;
-  enum rtx_code code;
+  enum rtx_code code = GET_CODE (x);
   machine_mode inner_mode;
+  unsigned int inner_width;
   scalar_int_mode xmode;
 
   unsigned int mode_width = GET_MODE_PRECISION (mode);
@@ -4458,16 +4810,16 @@ nonzero_bits1 (const_rtx x, scalar_int_mode mode, const_rtx known_x,
     return nonzero;
 
   /* If MODE is wider than X, but both are a single word for both the host
-     and target machines, we can compute this from which bits of the
-     object might be nonzero in its own mode, taking into account the fact
-     that on many CISC machines, accessing an object in a wider mode
-     causes the high-order bits to become undefined.  So they are
-     not known to be zero.  */
-
-  if (!WORD_REGISTER_OPERATIONS
-      && mode_width > xmode_width
+     and target machines, we can compute this from which bits of the object
+     might be nonzero in its own mode, taking into account the fact that, on
+     CISC machines, accessing an object in a wider mode generally causes the
+     high-order bits to become undefined, so they are not known to be zero.
+     We extend this reasoning to RISC machines for operations that might not
+     operate on the full registers.  */
+  if (mode_width > xmode_width
       && xmode_width <= BITS_PER_WORD
-      && xmode_width <= HOST_BITS_PER_WIDE_INT)
+      && xmode_width <= HOST_BITS_PER_WIDE_INT
+      && !(WORD_REGISTER_OPERATIONS && word_register_operation_p (x)))
     {
       nonzero &= cached_nonzero_bits (x, xmode,
                                      known_x, known_mode, known_ret);
@@ -4477,7 +4829,6 @@ nonzero_bits1 (const_rtx x, scalar_int_mode mode, const_rtx known_x,
 
   /* Please keep nonzero_bits_binary_arith_p above in sync with
      the code in the switch below.  */
-  code = GET_CODE (x);
   switch (code)
     {
     case REG:
@@ -4512,8 +4863,10 @@ nonzero_bits1 (const_rtx x, scalar_int_mode mode, const_rtx known_x,
             stack to be momentarily aligned only to that amount,
             so we pick the least alignment.  */
          if (x == stack_pointer_rtx && PUSH_ARGS)
-           alignment = MIN ((unsigned HOST_WIDE_INT) PUSH_ROUNDING (1),
-                            alignment);
+           {
+             poly_uint64 rounded_1 = PUSH_ROUNDING (poly_int64 (1));
+             alignment = MIN (known_alignment (rounded_1), alignment);
+           }
 #endif
 
          nonzero &= ~(alignment - 1);
@@ -4727,32 +5080,38 @@ nonzero_bits1 (const_rtx x, scalar_int_mode mode, const_rtx known_x,
         machines, we can compute this from which bits of the inner
         object might be nonzero.  */
       inner_mode = GET_MODE (SUBREG_REG (x));
-      if (GET_MODE_PRECISION (inner_mode) <= BITS_PER_WORD
-         && GET_MODE_PRECISION (inner_mode) <= HOST_BITS_PER_WIDE_INT)
+      if (GET_MODE_PRECISION (inner_mode).is_constant (&inner_width)
+         && inner_width <= BITS_PER_WORD
+         && inner_width <= HOST_BITS_PER_WIDE_INT)
        {
          nonzero &= cached_nonzero_bits (SUBREG_REG (x), mode,
                                          known_x, known_mode, known_ret);
 
-          /* On many CISC machines, accessing an object in a wider mode
+          /* On a typical CISC machine, accessing an object in a wider mode
             causes the high-order bits to become undefined.  So they are
-            not known to be zero.  */
+            not known to be zero.
+
+            On a typical RISC machine, we only have to worry about the way
+            loads are extended.  Otherwise, if we get a reload for the inner
+            part, it may be loaded from the stack, and then we may lose all
+            the zero bits that existed before the store to the stack.  */
          rtx_code extend_op;
          if ((!WORD_REGISTER_OPERATIONS
-              /* If this is a typical RISC machine, we only have to worry
-                 about the way loads are extended.  */
               || ((extend_op = load_extend_op (inner_mode)) == SIGN_EXTEND
                   ? val_signbit_known_set_p (inner_mode, nonzero)
                   : extend_op != ZERO_EXTEND)
-              || (!MEM_P (SUBREG_REG (x)) && !REG_P (SUBREG_REG (x))))
-             && xmode_width > GET_MODE_PRECISION (inner_mode))
-           nonzero |= (GET_MODE_MASK (xmode) & ~GET_MODE_MASK (inner_mode));
+              || !MEM_P (SUBREG_REG (x)))
+             && xmode_width > inner_width)
+           nonzero
+             |= (GET_MODE_MASK (GET_MODE (x)) & ~GET_MODE_MASK (inner_mode));
        }
       break;
 
+    case ASHIFT:
     case ASHIFTRT:
     case LSHIFTRT:
-    case ASHIFT:
     case ROTATE:
+    case ROTATERT:
       /* The nonzero bits are in two classes: any bits within MODE
         that aren't in xmode are always significant.  The rest of the
         nonzero bits are those that are significant in the operand of
@@ -4775,10 +5134,17 @@ nonzero_bits1 (const_rtx x, scalar_int_mode mode, const_rtx known_x,
          if (mode_width > xmode_width)
            outer = (op_nonzero & nonzero & ~mode_mask);
 
-         if (code == LSHIFTRT)
-           inner >>= count;
-         else if (code == ASHIFTRT)
+         switch (code)
            {
+           case ASHIFT:
+             inner <<= count;
+             break;
+
+           case LSHIFTRT:
+             inner >>= count;
+             break;
+
+           case ASHIFTRT:
              inner >>= count;
 
              /* If the sign bit may have been nonzero before the shift, we
@@ -4787,13 +5153,23 @@ nonzero_bits1 (const_rtx x, scalar_int_mode mode, const_rtx known_x,
              if (inner & (HOST_WIDE_INT_1U << (xmode_width - 1 - count)))
                inner |= (((HOST_WIDE_INT_1U << count) - 1)
                          << (xmode_width - count));
+             break;
+
+           case ROTATE:
+             inner = (inner << (count % xmode_width)
+                      | (inner >> (xmode_width - (count % xmode_width))))
+                     & mode_mask;
+             break;
+
+           case ROTATERT:
+             inner = (inner >> (count % xmode_width)
+                      | (inner << (xmode_width - (count % xmode_width))))
+                     & mode_mask;
+             break;
+
+           default:
+             gcc_unreachable ();
            }
-         else if (code == ASHIFT)
-           inner <<= count;
-         else
-           inner = ((inner << (count % xmode_width)
-                     | (inner >> (xmode_width - (count % xmode_width))))
-                    & mode_mask);
 
          nonzero &= (outer | inner);
        }
@@ -4981,8 +5357,9 @@ num_sign_bit_copies1 (const_rtx x, scalar_int_mode mode, const_rtx known_x,
     {
       /* If this machine does not do all register operations on the entire
         register and MODE is wider than the mode of X, we can say nothing
-        at all about the high-order bits.  */
-      if (!WORD_REGISTER_OPERATIONS)
+        at all about the high-order bits.  We extend this reasoning to RISC
+        machines for operations that might not operate on full registers.  */
+      if (!(WORD_REGISTER_OPERATIONS && word_register_operation_p (x)))
        return 1;
 
       /* Likewise on machines that do, if the mode of the object is smaller
@@ -5061,17 +5438,16 @@ num_sign_bit_copies1 (const_rtx x, scalar_int_mode mode, const_rtx known_x,
          /* For paradoxical SUBREGs on machines where all register operations
             affect the entire register, just look inside.  Note that we are
             passing MODE to the recursive call, so the number of sign bit
-            copies will remain relative to that mode, not the inner mode.  */
+            copies will remain relative to that mode, not the inner mode.
 
-         /* This works only if loads sign extend.  Otherwise, if we get a
+            This works only if loads sign extend.  Otherwise, if we get a
             reload for the inner part, it may be loaded from the stack, and
             then we lose all sign bit copies that existed before the store
             to the stack.  */
-
          if (WORD_REGISTER_OPERATIONS
              && load_extend_op (inner_mode) == SIGN_EXTEND
              && paradoxical_subreg_p (x)
-             && (MEM_P (SUBREG_REG (x)) || REG_P (SUBREG_REG (x))))
+             && MEM_P (SUBREG_REG (x)))
            return cached_num_sign_bit_copies (SUBREG_REG (x), mode,
                                               known_x, known_mode, known_ret);
        }
@@ -6070,8 +6446,9 @@ lsb_bitfield_op_p (rtx x)
       machine_mode mode = GET_MODE (XEXP (x, 0));
       HOST_WIDE_INT len = INTVAL (XEXP (x, 1));
       HOST_WIDE_INT pos = INTVAL (XEXP (x, 2));
+      poly_int64 remaining_bits = GET_MODE_PRECISION (mode) - len;
 
-      return (pos == (BITS_BIG_ENDIAN ? GET_MODE_PRECISION (mode) - len : 0));
+      return known_eq (pos, BITS_BIG_ENDIAN ? remaining_bits : 0);
     }
   return false;
 }
@@ -6503,6 +6880,20 @@ contains_symbolic_reference_p (const_rtx x)
   return false;
 }
 
+/* Return true if RTL X contains a constant pool address.  */
+
+bool
+contains_constant_pool_address_p (const_rtx x)
+{
+  subrtx_iterator::array_type array;
+  FOR_EACH_SUBRTX (iter, array, x, ALL)
+    if (SYMBOL_REF_P (*iter) && CONSTANT_POOL_ADDRESS_P (*iter))
+      return true;
+
+  return false;
+}
+
+
 /* Return true if X contains a thread-local symbol.  */
 
 bool
@@ -6517,3 +6908,41 @@ tls_referenced_p (const_rtx x)
       return true;
   return false;
 }
+
+/* Process recursively X of INSN and add REG_INC notes if necessary.  */
+void
+add_auto_inc_notes (rtx_insn *insn, rtx x)
+{
+  enum rtx_code code = GET_CODE (x);
+  const char *fmt;
+  int i, j;
+
+  if (code == MEM && auto_inc_p (XEXP (x, 0)))
+    {
+      add_reg_note (insn, REG_INC, XEXP (XEXP (x, 0), 0));
+      return;
+    }
+
+  /* Scan all X sub-expressions.  */
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e')
+       add_auto_inc_notes (insn, XEXP (x, i));
+      else if (fmt[i] == 'E')
+       for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+         add_auto_inc_notes (insn, XVECEXP (x, i, j));
+    }
+}
+
+/* Return true if X is register asm.  */
+
+bool
+register_asm_p (const_rtx x)
+{
+  return (REG_P (x)
+         && REG_EXPR (x) != NULL_TREE
+         && HAS_DECL_ASSEMBLER_NAME_P (REG_EXPR (x))
+         && DECL_ASSEMBLER_NAME_SET_P (REG_EXPR (x))
+         && DECL_REGISTER (REG_EXPR (x)));
+}