tree-optimization/93508 - make VN translate through _chk and valueize length
[gcc.git] / gcc / tree-ssa-sccvn.c
index c29e2de61acdf69dbf6af4594d9b8c8569044a52..e260ca4eed179898175f93433d99ca214af099e4 100644 (file)
@@ -1,5 +1,5 @@
 /* SCC value numbering for trees
-   Copyright (C) 2006-2019 Free Software Foundation, Inc.
+   Copyright (C) 2006-2020 Free Software Foundation, Inc.
    Contributed by Daniel Berlin <dan@dberlin.org>
 
 This file is part of GCC.
@@ -53,7 +53,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa.h"
 #include "dumpfile.h"
 #include "cfgloop.h"
-#include "params.h"
 #include "tree-ssa-propagate.h"
 #include "tree-cfg.h"
 #include "domwalk.h"
@@ -309,6 +308,10 @@ static vn_tables_t valid_info;
 /* Valueization hook.  Valueize NAME if it is an SSA name, otherwise
    just return it.  */
 tree (*vn_valueize) (tree);
+tree vn_valueize_wrapper (tree t, void* context ATTRIBUTE_UNUSED)
+{
+  return vn_valueize (t);
+}
 
 
 /* This represents the top of the VN lattice, which is the universal
@@ -332,6 +335,7 @@ struct vn_ssa_aux_hasher : typed_noop_remove <vn_ssa_aux_t>
   static inline hashval_t hash (const value_type &);
   static inline bool equal (const value_type &, const compare_type &);
   static inline void mark_deleted (value_type &) {}
+  static const bool empty_zero_p = true;
   static inline void mark_empty (value_type &e) { e = NULL; }
   static inline bool is_deleted (value_type &) { return false; }
   static inline bool is_empty (value_type &e) { return e == NULL; }
@@ -924,6 +928,7 @@ copy_reference_ops_from_ref (tree ref, vec<vn_reference_op_s> *result)
          break;
        case STRING_CST:
        case INTEGER_CST:
+       case POLY_INT_CST:
        case COMPLEX_CST:
        case VECTOR_CST:
        case REAL_CST:
@@ -1682,25 +1687,31 @@ struct vn_walk_cb_data
 {
   vn_walk_cb_data (vn_reference_t vr_, tree orig_ref_, tree *last_vuse_ptr_,
                   vn_lookup_kind vn_walk_kind_, bool tbaa_p_)
-    : vr (vr_), last_vuse_ptr (last_vuse_ptr_),
-      vn_walk_kind (vn_walk_kind_), tbaa_p (tbaa_p_), known_ranges (NULL)
+    : vr (vr_), last_vuse_ptr (last_vuse_ptr_), last_vuse (NULL_TREE),
+      vn_walk_kind (vn_walk_kind_), tbaa_p (tbaa_p_),
+      saved_operands (vNULL), first_set (-2), known_ranges (NULL)
    {
+     if (!last_vuse_ptr)
+       last_vuse_ptr = &last_vuse;
      ao_ref_init (&orig_ref, orig_ref_);
    }
   ~vn_walk_cb_data ();
-  void *push_partial_def (const pd_data& pd, tree, HOST_WIDE_INT);
+  void *finish (alias_set_type, tree);
+  void *push_partial_def (const pd_data& pd, alias_set_type, HOST_WIDE_INT);
 
   vn_reference_t vr;
   ao_ref orig_ref;
   tree *last_vuse_ptr;
+  tree last_vuse;
   vn_lookup_kind vn_walk_kind;
   bool tbaa_p;
+  vec<vn_reference_op_s> saved_operands;
 
   /* The VDEFs of partial defs we come along.  */
   auto_vec<pd_data, 2> partial_defs;
   /* The first defs range to avoid splay tree setup in most cases.  */
   pd_range first_range;
-  tree first_vuse;
+  alias_set_type first_set;
   splay_tree known_ranges;
   obstack ranges_obstack;
 };
@@ -1712,6 +1723,17 @@ vn_walk_cb_data::~vn_walk_cb_data ()
       splay_tree_delete (known_ranges);
       obstack_free (&ranges_obstack, NULL);
     }
+  saved_operands.release ();
+}
+
+void *
+vn_walk_cb_data::finish (alias_set_type set, tree val)
+{
+  if (first_set != -2)
+    set = first_set;
+  return vn_reference_lookup_or_insert_for_pieces
+      (last_vuse, set, vr->type,
+       saved_operands.exists () ? saved_operands : vr->operands, val);
 }
 
 /* pd_range splay-tree helpers.  */
@@ -1741,20 +1763,37 @@ pd_tree_dealloc (void *, void *)
 }
 
 /* Push PD to the vector of partial definitions returning a
-   value when we are ready to combine things with VUSE and MAXSIZEI,
+   value when we are ready to combine things with VUSE, SET and MAXSIZEI,
    NULL when we want to continue looking for partial defs or -1
    on failure.  */
 
 void *
-vn_walk_cb_data::push_partial_def (const pd_data &pd, tree vuse,
-                                  HOST_WIDE_INT maxsizei)
-{
+vn_walk_cb_data::push_partial_def (const pd_data &pd,
+                                  alias_set_type set, HOST_WIDE_INT maxsizei)
+{
+  const HOST_WIDE_INT bufsize = 64;
+  /* We're using a fixed buffer for encoding so fail early if the object
+     we want to interpret is bigger.  */
+  if (maxsizei > bufsize * BITS_PER_UNIT
+      || CHAR_BIT != 8
+      || BITS_PER_UNIT != 8
+      /* Not prepared to handle PDP endian.  */
+      || BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN)
+    return (void *)-1;
+
+  bool pd_constant_p = (TREE_CODE (pd.rhs) == CONSTRUCTOR
+                       || CONSTANT_CLASS_P (pd.rhs));
   if (partial_defs.is_empty ())
     {
+      /* If we get a clobber upfront, fail.  */
+      if (TREE_CLOBBER_P (pd.rhs))
+       return (void *)-1;
+      if (!pd_constant_p)
+       return (void *)-1;
       partial_defs.safe_push (pd);
       first_range.offset = pd.offset;
       first_range.size = pd.size;
-      first_vuse = vuse;
+      first_set = set;
       last_vuse_ptr = NULL;
       /* Continue looking for partial defs.  */
       return NULL;
@@ -1782,7 +1821,8 @@ vn_walk_cb_data::push_partial_def (const pd_data &pd, tree vuse,
       && ranges_known_overlap_p (r->offset, r->size + 1,
                                 newr.offset, newr.size))
     {
-      /* Ignore partial defs already covered.  */
+      /* Ignore partial defs already covered.  Here we also drop shadowed
+         clobbers arriving here at the floor.  */
       if (known_subrange_p (newr.offset, newr.size, r->offset, r->size))
        return NULL;
       r->size = MAX (r->offset + r->size, newr.offset + newr.size) - r->offset;
@@ -1807,45 +1847,50 @@ vn_walk_cb_data::push_partial_def (const pd_data &pd, tree vuse,
                     rafter->offset + rafter->size) - r->offset;
       splay_tree_remove (known_ranges, (splay_tree_key)&rafter->offset);
     }
+  /* If we get a clobber, fail.  */
+  if (TREE_CLOBBER_P (pd.rhs))
+    return (void *)-1;
+  /* Non-constants are OK as long as they are shadowed by a constant.  */
+  if (!pd_constant_p)
+    return (void *)-1;
   partial_defs.safe_push (pd);
 
   /* Now we have merged newr into the range tree.  When we have covered
      [offseti, sizei] then the tree will contain exactly one node which has
      the desired properties and it will be 'r'.  */
-  if (!known_subrange_p (0, maxsizei / BITS_PER_UNIT, r->offset, r->size))
+  if (!known_subrange_p (0, maxsizei, r->offset, r->size))
     /* Continue looking for partial defs.  */
     return NULL;
 
   /* Now simply native encode all partial defs in reverse order.  */
   unsigned ndefs = partial_defs.length ();
   /* We support up to 512-bit values (for V8DFmode).  */
-  unsigned char buffer[64];
+  unsigned char buffer[bufsize + 1];
+  unsigned char this_buffer[bufsize + 1];
   int len;
 
+  memset (buffer, 0, bufsize + 1);
+  unsigned needed_len = ROUND_UP (maxsizei, BITS_PER_UNIT) / BITS_PER_UNIT;
   while (!partial_defs.is_empty ())
     {
       pd_data pd = partial_defs.pop ();
+      unsigned int amnt;
       if (TREE_CODE (pd.rhs) == CONSTRUCTOR)
-       /* Empty CONSTRUCTOR.  */
-       memset (buffer + MAX (0, pd.offset),
-               0, MIN ((HOST_WIDE_INT)sizeof (buffer) - MAX (0, pd.offset),
-                       pd.size + MIN (0, pd.offset)));
+       {
+         /* Empty CONSTRUCTOR.  */
+         if (pd.size >= needed_len * BITS_PER_UNIT)
+           len = needed_len;
+         else
+           len = ROUND_UP (pd.size, BITS_PER_UNIT) / BITS_PER_UNIT;
+         memset (this_buffer, 0, len);
+       }
       else
        {
-         unsigned pad = 0;
-         if (BYTES_BIG_ENDIAN
-             && is_a <scalar_mode> (TYPE_MODE (TREE_TYPE (pd.rhs))))
-           {
-             /* On big-endian the padding is at the 'front' so just skip
-                the initial bytes.  */
-             fixed_size_mode mode
-               = as_a <fixed_size_mode> (TYPE_MODE (TREE_TYPE (pd.rhs)));
-             pad = GET_MODE_SIZE (mode) - pd.size;
-           }
-         len = native_encode_expr (pd.rhs, buffer + MAX (0, pd.offset),
-                                   sizeof (buffer) - MAX (0, pd.offset),
-                                   MAX (0, -pd.offset) + pad);
-         if (len <= 0 || len < (pd.size - MAX (0, -pd.offset)))
+         len = native_encode_expr (pd.rhs, this_buffer, bufsize,
+                                   MAX (0, -pd.offset) / BITS_PER_UNIT);
+         if (len <= 0
+             || len < (ROUND_UP (pd.size, BITS_PER_UNIT) / BITS_PER_UNIT
+                       - MAX (0, -pd.offset) / BITS_PER_UNIT))
            {
              if (dump_file && (dump_flags & TDF_DETAILS))
                fprintf (dump_file, "Failed to encode %u "
@@ -1853,6 +1898,125 @@ vn_walk_cb_data::push_partial_def (const pd_data &pd, tree vuse,
              return (void *)-1;
            }
        }
+
+      unsigned char *p = buffer;
+      HOST_WIDE_INT size = pd.size;
+      if (pd.offset < 0)
+       size -= ROUND_DOWN (-pd.offset, BITS_PER_UNIT);
+      this_buffer[len] = 0;
+      if (BYTES_BIG_ENDIAN)
+       {
+         /* LSB of this_buffer[len - 1] byte should be at
+            pd.offset + pd.size - 1 bits in buffer.  */
+         amnt = ((unsigned HOST_WIDE_INT) pd.offset
+                 + pd.size) % BITS_PER_UNIT;
+         if (amnt)
+           shift_bytes_in_array_right (this_buffer, len + 1, amnt);
+         unsigned char *q = this_buffer;
+         unsigned int off = 0;
+         if (pd.offset >= 0)
+           {
+             unsigned int msk;
+             off = pd.offset / BITS_PER_UNIT;
+             gcc_assert (off < needed_len);
+             p = buffer + off;
+             if (size <= amnt)
+               {
+                 msk = ((1 << size) - 1) << (BITS_PER_UNIT - amnt);
+                 *p = (*p & ~msk) | (this_buffer[len] & msk);
+                 size = 0;
+               }
+             else
+               {
+                 if (TREE_CODE (pd.rhs) != CONSTRUCTOR)
+                   q = (this_buffer + len
+                        - (ROUND_UP (size - amnt, BITS_PER_UNIT)
+                           / BITS_PER_UNIT));
+                 if (pd.offset % BITS_PER_UNIT)
+                   {
+                     msk = -1U << (BITS_PER_UNIT
+                                   - (pd.offset % BITS_PER_UNIT));
+                     *p = (*p & msk) | (*q & ~msk);
+                     p++;
+                     q++;
+                     off++;
+                     size -= BITS_PER_UNIT - (pd.offset % BITS_PER_UNIT);
+                     gcc_assert (size >= 0);
+                   }
+               }
+           }
+         else if (TREE_CODE (pd.rhs) != CONSTRUCTOR)
+           {
+             q = (this_buffer + len
+                  - (ROUND_UP (size - amnt, BITS_PER_UNIT)
+                     / BITS_PER_UNIT));
+             if (pd.offset % BITS_PER_UNIT)
+               {
+                 q++;
+                 size -= BITS_PER_UNIT - ((unsigned HOST_WIDE_INT) pd.offset
+                                          % BITS_PER_UNIT);
+                 gcc_assert (size >= 0);
+               }
+           }
+         if ((unsigned HOST_WIDE_INT) size / BITS_PER_UNIT + off
+             > needed_len)
+           size = (needed_len - off) * BITS_PER_UNIT;
+         memcpy (p, q, size / BITS_PER_UNIT);
+         if (size % BITS_PER_UNIT)
+           {
+             unsigned int msk
+               = -1U << (BITS_PER_UNIT - (size % BITS_PER_UNIT));
+             p += size / BITS_PER_UNIT;
+             q += size / BITS_PER_UNIT;
+             *p = (*q & msk) | (*p & ~msk);
+           }
+       }
+      else
+       {
+         size = MIN (size, (HOST_WIDE_INT) needed_len * BITS_PER_UNIT);
+         if (pd.offset >= 0)
+           {
+             /* LSB of this_buffer[0] byte should be at pd.offset bits
+                in buffer.  */
+             unsigned int msk;
+             amnt = pd.offset % BITS_PER_UNIT;
+             if (amnt)
+               shift_bytes_in_array_left (this_buffer, len + 1, amnt);
+             unsigned int off = pd.offset / BITS_PER_UNIT;
+             gcc_assert (off < needed_len);
+             p = buffer + off;
+             if (amnt + size < BITS_PER_UNIT)
+               {
+                 /* Low amnt bits come from *p, then size bits
+                    from this_buffer[0] and the remaining again from
+                    *p.  */
+                 msk = ((1 << size) - 1) << amnt;
+                 *p = (*p & ~msk) | (this_buffer[0] & msk);
+                 size = 0;
+               }
+             else if (amnt)
+               {
+                 msk = -1U << amnt;
+                 *p = (*p & ~msk) | (this_buffer[0] & msk);
+                 p++;
+                 size -= (BITS_PER_UNIT - amnt);
+               }
+           }
+         else
+           {
+             amnt = (unsigned HOST_WIDE_INT) pd.offset % BITS_PER_UNIT;
+             if (amnt)
+               shift_bytes_in_array_left (this_buffer, len + 1, amnt);
+           }
+         memcpy (p, this_buffer + (amnt != 0), size / BITS_PER_UNIT);
+         p += size / BITS_PER_UNIT;
+         if (size % BITS_PER_UNIT)
+           {
+             unsigned int msk = -1U << (size % BITS_PER_UNIT);
+             *p = (this_buffer[(amnt != 0) + size / BITS_PER_UNIT]
+                   & ~msk) | (*p & msk);
+           }
+       }
     }
 
   tree type = vr->type;
@@ -1860,7 +2024,26 @@ vn_walk_cb_data::push_partial_def (const pd_data &pd, tree vuse,
      access size.  */
   if (INTEGRAL_TYPE_P (vr->type) && maxsizei != TYPE_PRECISION (vr->type))
     type = build_nonstandard_integer_type (maxsizei, TYPE_UNSIGNED (type));
-  tree val = native_interpret_expr (type, buffer, maxsizei / BITS_PER_UNIT);
+  tree val;
+  if (BYTES_BIG_ENDIAN)
+    {
+      unsigned sz = needed_len;
+      if (maxsizei % BITS_PER_UNIT)
+       shift_bytes_in_array_right (buffer, needed_len,
+                                   BITS_PER_UNIT
+                                   - (maxsizei % BITS_PER_UNIT));
+      if (INTEGRAL_TYPE_P (type))
+       sz = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type));
+      if (sz > needed_len)
+       {
+         memcpy (this_buffer + (sz - needed_len), buffer, needed_len);
+         val = native_interpret_expr (type, this_buffer, sz);
+       }
+      else
+       val = native_interpret_expr (type, buffer, needed_len);
+    }
+  else
+    val = native_interpret_expr (type, buffer, bufsize);
   /* If we chop off bits because the types precision doesn't match the memory
      access size this is ok when optimizing reads but not when called from
      the DSE code during elimination.  */
@@ -1877,8 +2060,9 @@ vn_walk_cb_data::push_partial_def (const pd_data &pd, tree vuse,
       if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file,
                 "Successfully combined %u partial definitions\n", ndefs);
-      return vn_reference_lookup_or_insert_for_pieces
-               (first_vuse, vr->set, vr->type, vr->operands, val);
+      /* We are using the alias-set of the first store we encounter which
+        should be appropriate here.  */
+      return finish (first_set, val);
     }
   else
     {
@@ -1906,7 +2090,10 @@ vn_reference_lookup_2 (ao_ref *op ATTRIBUTE_UNUSED, tree vuse, void *data_)
     return NULL;
 
   if (data->last_vuse_ptr)
-    *data->last_vuse_ptr = vuse;
+    {
+      *data->last_vuse_ptr = vuse;
+      data->last_vuse = vuse;
+    }
 
   /* Fixup vuse and hash.  */
   if (vr->vuse)
@@ -1918,7 +2105,11 @@ vn_reference_lookup_2 (ao_ref *op ATTRIBUTE_UNUSED, tree vuse, void *data_)
   hash = vr->hashcode;
   slot = valid_info->references->find_slot_with_hash (vr, hash, NO_INSERT);
   if (slot)
-    return *slot;
+    {
+      if ((*slot)->result && data->saved_operands.exists ())
+       return data->finish (vr->set, (*slot)->result);
+      return *slot;
+    }
 
   return NULL;
 }
@@ -2195,7 +2386,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
   vn_reference_t vr = data->vr;
   gimple *def_stmt = SSA_NAME_DEF_STMT (vuse);
   tree base = ao_ref_base (ref);
-  HOST_WIDE_INT offseti, maxsizei;
+  HOST_WIDE_INT offseti = 0, maxsizei, sizei = 0;
   static vec<vn_reference_op_s> lhs_ops;
   ao_ref lhs_ref;
   bool lhs_ref_ok = false;
@@ -2331,9 +2522,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
        }
     }
 
-  /* If we are looking for redundant stores do not create new hashtable
-     entries from aliasing defs with made up alias-sets.  */
-  if (*disambiguate_only > TR_TRANSLATE || !data->tbaa_p)
+  if (*disambiguate_only > TR_TRANSLATE)
     return (void *)-1;
 
   /* If we cannot constrain the size of the reference we cannot
@@ -2344,22 +2533,25 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
   poly_int64 offset = ref->offset;
   poly_int64 maxsize = ref->max_size;
 
-  /* We can't deduce anything useful from clobbers.  */
-  if (gimple_clobber_p (def_stmt))
-    return (void *)-1;
-
   /* def_stmt may-defs *ref.  See if we can derive a value for *ref
      from that definition.
      1) Memset.  */
   if (is_gimple_reg_type (vr->type)
-      && gimple_call_builtin_p (def_stmt, BUILT_IN_MEMSET)
+      && (gimple_call_builtin_p (def_stmt, BUILT_IN_MEMSET)
+         || gimple_call_builtin_p (def_stmt, BUILT_IN_MEMSET_CHK))
       && (integer_zerop (gimple_call_arg (def_stmt, 1))
          || ((TREE_CODE (gimple_call_arg (def_stmt, 1)) == INTEGER_CST
               || (INTEGRAL_TYPE_P (vr->type) && known_eq (ref->size, 8)))
-             && CHAR_BIT == 8 && BITS_PER_UNIT == 8
+             && CHAR_BIT == 8
+             && BITS_PER_UNIT == 8
+             && BYTES_BIG_ENDIAN == WORDS_BIG_ENDIAN
              && offset.is_constant (&offseti)
-             && offseti % BITS_PER_UNIT == 0))
-      && poly_int_tree_p (gimple_call_arg (def_stmt, 2))
+             && ref->size.is_constant (&sizei)
+             && (offseti % BITS_PER_UNIT == 0
+                 || TREE_CODE (gimple_call_arg (def_stmt, 1)) == INTEGER_CST)))
+      && (poly_int_tree_p (gimple_call_arg (def_stmt, 2))
+         || (TREE_CODE (gimple_call_arg (def_stmt, 2)) == SSA_NAME
+             && poly_int_tree_p (SSA_VAL (gimple_call_arg (def_stmt, 2)))))
       && (TREE_CODE (gimple_call_arg (def_stmt, 0)) == ADDR_EXPR
          || TREE_CODE (gimple_call_arg (def_stmt, 0)) == SSA_NAME))
     {
@@ -2419,7 +2611,15 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
       else
        return (void *)-1;
       tree len = gimple_call_arg (def_stmt, 2);
-      HOST_WIDE_INT leni, offset2i, offseti;
+      HOST_WIDE_INT leni, offset2i;
+      if (TREE_CODE (len) == SSA_NAME)
+       len = SSA_VAL (len);
+      /* Sometimes the above trickery is smarter than alias analysis.  Take
+         advantage of that.  */
+      if (!ranges_maybe_overlap_p (offset, maxsize, offset2,
+                                  (wi::to_poly_offset (len)
+                                   << LOG2_BITS_PER_UNIT)))
+       return NULL;
       if (data->partial_defs.is_empty ()
          && known_subrange_p (offset, maxsize, offset2,
                               wi::to_poly_offset (len) << LOG2_BITS_PER_UNIT))
@@ -2428,7 +2628,8 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
          if (integer_zerop (gimple_call_arg (def_stmt, 1)))
            val = build_zero_cst (vr->type);
          else if (INTEGRAL_TYPE_P (vr->type)
-                  && known_eq (ref->size, 8))
+                  && known_eq (ref->size, 8)
+                  && offseti % BITS_PER_UNIT == 0)
            {
              gimple_match_op res_op (gimple_match_cond::UNCOND, NOP_EXPR,
                                      vr->type, gimple_call_arg (def_stmt, 1));
@@ -2440,30 +2641,57 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
            }
          else
            {
-             unsigned len = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (vr->type));
-             unsigned char *buf = XALLOCAVEC (unsigned char, len);
+             unsigned buflen = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (vr->type)) + 1;
+             if (INTEGRAL_TYPE_P (vr->type))
+               buflen = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (vr->type)) + 1;
+             unsigned char *buf = XALLOCAVEC (unsigned char, buflen);
              memset (buf, TREE_INT_CST_LOW (gimple_call_arg (def_stmt, 1)),
-                     len);
-             val = native_interpret_expr (vr->type, buf, len);
+                     buflen);
+             if (BYTES_BIG_ENDIAN)
+               {
+                 unsigned int amnt
+                   = (((unsigned HOST_WIDE_INT) offseti + sizei)
+                      % BITS_PER_UNIT);
+                 if (amnt)
+                   {
+                     shift_bytes_in_array_right (buf, buflen,
+                                                 BITS_PER_UNIT - amnt);
+                     buf++;
+                     buflen--;
+                   }
+               }
+             else if (offseti % BITS_PER_UNIT != 0)
+               {
+                 unsigned int amnt
+                   = BITS_PER_UNIT - ((unsigned HOST_WIDE_INT) offseti
+                                      % BITS_PER_UNIT);
+                 shift_bytes_in_array_left (buf, buflen, amnt);
+                 buf++;
+                 buflen--;
+               }
+             val = native_interpret_expr (vr->type, buf, buflen);
              if (!val)
                return (void *)-1;
            }
-         return vn_reference_lookup_or_insert_for_pieces
-                  (vuse, vr->set, vr->type, vr->operands, val);
+         return data->finish (0, val);
        }
       /* For now handle clearing memory with partial defs.  */
       else if (known_eq (ref->size, maxsize)
               && integer_zerop (gimple_call_arg (def_stmt, 1))
+              && tree_fits_poly_int64_p (len)
               && tree_to_poly_int64 (len).is_constant (&leni)
+              && leni <= INTTYPE_MAXIMUM (HOST_WIDE_INT) / BITS_PER_UNIT
               && offset.is_constant (&offseti)
               && offset2.is_constant (&offset2i)
-              && maxsize.is_constant (&maxsizei))
+              && maxsize.is_constant (&maxsizei)
+              && ranges_known_overlap_p (offseti, maxsizei, offset2i,
+                                         leni << LOG2_BITS_PER_UNIT))
        {
          pd_data pd;
          pd.rhs = build_constructor (NULL_TREE, NULL);
-         pd.offset = (offset2i - offseti) / BITS_PER_UNIT;
-         pd.size = leni;
-         return data->push_partial_def (pd, vuse, maxsizei);
+         pd.offset = offset2i - offseti;
+         pd.size = leni << LOG2_BITS_PER_UNIT;
+         return data->push_partial_def (pd, 0, maxsizei);
        }
     }
 
@@ -2497,25 +2725,29 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
          if (data->partial_defs.is_empty ()
              && known_subrange_p (offset, maxsize, offset2, size2))
            {
+             /* While technically undefined behavior do not optimize
+                a full read from a clobber.  */
+             if (gimple_clobber_p (def_stmt))
+               return (void *)-1;
              tree val = build_zero_cst (vr->type);
-             return vn_reference_lookup_or_insert_for_pieces
-                 (vuse, vr->set, vr->type, vr->operands, val);
+             return data->finish (get_alias_set (lhs), val);
            }
          else if (known_eq (ref->size, maxsize)
                   && maxsize.is_constant (&maxsizei)
-                  && maxsizei % BITS_PER_UNIT == 0
                   && offset.is_constant (&offseti)
-                  && offseti % BITS_PER_UNIT == 0
                   && offset2.is_constant (&offset2i)
-                  && offset2i % BITS_PER_UNIT == 0
                   && size2.is_constant (&size2i)
-                  && size2i % BITS_PER_UNIT == 0)
+                  && ranges_known_overlap_p (offseti, maxsizei,
+                                             offset2i, size2i))
            {
+             /* Let clobbers be consumed by the partial-def tracker
+                which can choose to ignore them if they are shadowed
+                by a later def.  */
              pd_data pd;
              pd.rhs = gimple_assign_rhs1 (def_stmt);
-             pd.offset = (offset2i - offseti) / BITS_PER_UNIT;
-             pd.size = size2i / BITS_PER_UNIT;
-             return data->push_partial_def (pd, vuse, maxsizei);
+             pd.offset = offset2i - offseti;
+             pd.size = size2i;
+             return data->push_partial_def (pd, get_alias_set (lhs), maxsizei);
            }
        }
     }
@@ -2526,13 +2758,13 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
           && is_gimple_reg_type (vr->type)
           && !contains_storage_order_barrier_p (vr->operands)
           && gimple_assign_single_p (def_stmt)
-          && CHAR_BIT == 8 && BITS_PER_UNIT == 8
+          && CHAR_BIT == 8
+          && BITS_PER_UNIT == 8
+          && BYTES_BIG_ENDIAN == WORDS_BIG_ENDIAN
           /* native_encode and native_decode operate on arrays of bytes
              and so fundamentally need a compile-time size and offset.  */
           && maxsize.is_constant (&maxsizei)
-          && maxsizei % BITS_PER_UNIT == 0
           && offset.is_constant (&offseti)
-          && offseti % BITS_PER_UNIT == 0
           && (is_gimple_min_invariant (gimple_assign_rhs1 (def_stmt))
               || (TREE_CODE (gimple_assign_rhs1 (def_stmt)) == SSA_NAME
                   && is_gimple_min_invariant (SSA_VAL (gimple_assign_rhs1 (def_stmt))))))
@@ -2555,9 +2787,8 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
                                         &offset2, &size2, &maxsize2, &reverse);
       if (base2
          && !reverse
+         && !storage_order_barrier_p (lhs)
          && known_eq (maxsize2, size2)
-         && multiple_p (size2, BITS_PER_UNIT)
-         && multiple_p (offset2, BITS_PER_UNIT)
          && adjust_offsets_for_equal_base_address (base, &offset,
                                                    base2, &offset2)
          && offset.is_constant (&offseti)
@@ -2568,37 +2799,80 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
              && known_subrange_p (offseti, maxsizei, offset2, size2))
            {
              /* We support up to 512-bit values (for V8DFmode).  */
-             unsigned char buffer[64];
+             unsigned char buffer[65];
              int len;
 
              tree rhs = gimple_assign_rhs1 (def_stmt);
              if (TREE_CODE (rhs) == SSA_NAME)
                rhs = SSA_VAL (rhs);
-             unsigned pad = 0;
-             if (BYTES_BIG_ENDIAN
-                 && is_a <scalar_mode> (TYPE_MODE (TREE_TYPE (rhs))))
-               {
-                 /* On big-endian the padding is at the 'front' so
-                    just skip the initial bytes.  */
-                 fixed_size_mode mode
-                   = as_a <fixed_size_mode> (TYPE_MODE (TREE_TYPE (rhs)));
-                 pad = GET_MODE_SIZE (mode) - size2i / BITS_PER_UNIT;
-               }
              len = native_encode_expr (rhs,
-                                       buffer, sizeof (buffer),
-                                       ((offseti - offset2i) / BITS_PER_UNIT
-                                        + pad));
+                                       buffer, sizeof (buffer) - 1,
+                                       (offseti - offset2i) / BITS_PER_UNIT);
              if (len > 0 && len * BITS_PER_UNIT >= maxsizei)
                {
                  tree type = vr->type;
+                 unsigned char *buf = buffer;
+                 unsigned int amnt = 0;
                  /* Make sure to interpret in a type that has a range
                     covering the whole access size.  */
                  if (INTEGRAL_TYPE_P (vr->type)
                      && maxsizei != TYPE_PRECISION (vr->type))
                    type = build_nonstandard_integer_type (maxsizei,
                                                           TYPE_UNSIGNED (type));
-                 tree val = native_interpret_expr (type, buffer,
-                                                   maxsizei / BITS_PER_UNIT);
+                 if (BYTES_BIG_ENDIAN)
+                   {
+                     /* For big-endian native_encode_expr stored the rhs
+                        such that the LSB of it is the LSB of buffer[len - 1].
+                        That bit is stored into memory at position
+                        offset2 + size2 - 1, i.e. in byte
+                        base + (offset2 + size2 - 1) / BITS_PER_UNIT.
+                        E.g. for offset2 1 and size2 14, rhs -1 and memory
+                        previously cleared that is:
+                        0        1
+                        01111111|11111110
+                        Now, if we want to extract offset 2 and size 12 from
+                        it using native_interpret_expr (which actually works
+                        for integral bitfield types in terms of byte size of
+                        the mode), the native_encode_expr stored the value
+                        into buffer as
+                        XX111111|11111111
+                        and returned len 2 (the X bits are outside of
+                        precision).
+                        Let sz be maxsize / BITS_PER_UNIT if not extracting
+                        a bitfield, and GET_MODE_SIZE otherwise.
+                        We need to align the LSB of the value we want to
+                        extract as the LSB of buf[sz - 1].
+                        The LSB from memory we need to read is at position
+                        offset + maxsize - 1.  */
+                     HOST_WIDE_INT sz = maxsizei / BITS_PER_UNIT;
+                     if (INTEGRAL_TYPE_P (type))
+                       sz = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type));
+                     amnt = ((unsigned HOST_WIDE_INT) offset2i + size2i
+                             - offseti - maxsizei) % BITS_PER_UNIT;
+                     if (amnt)
+                       shift_bytes_in_array_right (buffer, len, amnt);
+                     amnt = ((unsigned HOST_WIDE_INT) offset2i + size2i
+                             - offseti - maxsizei - amnt) / BITS_PER_UNIT;
+                     if ((unsigned HOST_WIDE_INT) sz + amnt > (unsigned) len)
+                       len = 0;
+                     else
+                       {
+                         buf = buffer + len - sz - amnt;
+                         len -= (buf - buffer);
+                       }
+                   }
+                 else
+                   {
+                     amnt = ((unsigned HOST_WIDE_INT) offset2i
+                             - offseti) % BITS_PER_UNIT;
+                     if (amnt)
+                       {
+                         buffer[len] = 0;
+                         shift_bytes_in_array_left (buffer, len + 1, amnt);
+                         buf = buffer + 1;
+                       }
+                   }
+                 tree val = native_interpret_expr (type, buf, len);
                  /* If we chop off bits because the types precision doesn't
                     match the memory access size this is ok when optimizing
                     reads but not when called from the DSE code during
@@ -2613,40 +2887,36 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
                    }
 
                  if (val)
-                   return vn_reference_lookup_or_insert_for_pieces
-                       (vuse, vr->set, vr->type, vr->operands, val);
+                   return data->finish (get_alias_set (lhs), val);
                }
            }
-         else if (ranges_known_overlap_p (offseti, maxsizei, offset2i, size2i))
+         else if (ranges_known_overlap_p (offseti, maxsizei, offset2i,
+                                          size2i))
            {
              pd_data pd;
              tree rhs = gimple_assign_rhs1 (def_stmt);
              if (TREE_CODE (rhs) == SSA_NAME)
                rhs = SSA_VAL (rhs);
              pd.rhs = rhs;
-             pd.offset = (offset2i - offseti) / BITS_PER_UNIT;
-             pd.size = size2i / BITS_PER_UNIT;
-             return data->push_partial_def (pd, vuse, maxsizei);
+             pd.offset = offset2i - offseti;
+             pd.size = size2i;
+             return data->push_partial_def (pd, get_alias_set (lhs), maxsizei);
            }
        }
     }
 
   /* 4) Assignment from an SSA name which definition we may be able
-     to access pieces from.  */
+     to access pieces from or we can combine to a larger entity.  */
   else if (known_eq (ref->size, maxsize)
           && is_gimple_reg_type (vr->type)
           && !contains_storage_order_barrier_p (vr->operands)
           && gimple_assign_single_p (def_stmt)
-          && TREE_CODE (gimple_assign_rhs1 (def_stmt)) == SSA_NAME
-          /* A subset of partial defs from non-constants can be handled
-             by for example inserting a CONSTRUCTOR, a COMPLEX_EXPR or
-             even a (series of) BIT_INSERT_EXPR hoping for simplifications
-             downstream, not so much for actually doing the insertion.  */
-          && data->partial_defs.is_empty ())
+          && TREE_CODE (gimple_assign_rhs1 (def_stmt)) == SSA_NAME)
     {
       tree lhs = gimple_assign_lhs (def_stmt);
       tree base2;
       poly_int64 offset2, size2, maxsize2;
+      HOST_WIDE_INT offset2i, size2i, offseti;
       bool reverse;
       if (lhs_ref_ok)
        {
@@ -2661,34 +2931,56 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
                                         &offset2, &size2, &maxsize2, &reverse);
       tree def_rhs = gimple_assign_rhs1 (def_stmt);
       if (!reverse
+         && !storage_order_barrier_p (lhs)
          && known_size_p (maxsize2)
          && known_eq (maxsize2, size2)
          && adjust_offsets_for_equal_base_address (base, &offset,
-                                                   base2, &offset2)
-         && known_subrange_p (offset, maxsize, offset2, size2)
-         /* ???  We can't handle bitfield precision extracts without
-            either using an alternate type for the BIT_FIELD_REF and
-            then doing a conversion or possibly adjusting the offset
-            according to endianness.  */
-         && (! INTEGRAL_TYPE_P (vr->type)
-             || known_eq (ref->size, TYPE_PRECISION (vr->type)))
-         && multiple_p (ref->size, BITS_PER_UNIT)
-         && (! INTEGRAL_TYPE_P (TREE_TYPE (def_rhs))
-             || type_has_mode_precision_p (TREE_TYPE (def_rhs))))
+                                                   base2, &offset2))
        {
-         gimple_match_op op (gimple_match_cond::UNCOND,
-                             BIT_FIELD_REF, vr->type,
-                             vn_valueize (def_rhs),
-                             bitsize_int (ref->size),
-                             bitsize_int (offset - offset2));
-         tree val = vn_nary_build_or_lookup (&op);
-         if (val
-             && (TREE_CODE (val) != SSA_NAME
-                 || ! SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val)))
+         if (data->partial_defs.is_empty ()
+             && known_subrange_p (offset, maxsize, offset2, size2)
+             /* ???  We can't handle bitfield precision extracts without
+                either using an alternate type for the BIT_FIELD_REF and
+                then doing a conversion or possibly adjusting the offset
+                according to endianness.  */
+             && (! INTEGRAL_TYPE_P (vr->type)
+                 || known_eq (ref->size, TYPE_PRECISION (vr->type)))
+             && multiple_p (ref->size, BITS_PER_UNIT))
            {
-             vn_reference_t res = vn_reference_lookup_or_insert_for_pieces
-                 (vuse, vr->set, vr->type, vr->operands, val);
-             return res;
+             tree val = NULL_TREE;
+             if (! INTEGRAL_TYPE_P (TREE_TYPE (def_rhs))
+                 || type_has_mode_precision_p (TREE_TYPE (def_rhs)))
+               {
+                 gimple_match_op op (gimple_match_cond::UNCOND,
+                                     BIT_FIELD_REF, vr->type,
+                                     SSA_VAL (def_rhs),
+                                     bitsize_int (ref->size),
+                                     bitsize_int (offset - offset2));
+                 val = vn_nary_build_or_lookup (&op);
+               }
+             else if (known_eq (ref->size, size2))
+               {
+                 gimple_match_op op (gimple_match_cond::UNCOND,
+                                     VIEW_CONVERT_EXPR, vr->type,
+                                     SSA_VAL (def_rhs));
+                 val = vn_nary_build_or_lookup (&op);
+               }
+             if (val
+                 && (TREE_CODE (val) != SSA_NAME
+                     || ! SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val)))
+               return data->finish (get_alias_set (lhs), val);
+           }
+         else if (maxsize.is_constant (&maxsizei)
+                  && offset.is_constant (&offseti)
+                  && offset2.is_constant (&offset2i)
+                  && size2.is_constant (&size2i)
+                  && ranges_known_overlap_p (offset, maxsize, offset2, size2))
+           {
+             pd_data pd;
+             pd.rhs = SSA_VAL (def_rhs);
+             pd.offset = offset2i - offseti;
+             pd.size = size2i;
+             return data->push_partial_def (pd, get_alias_set (lhs), maxsizei);
            }
        }
     }
@@ -2701,6 +2993,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
               || TREE_CODE (gimple_assign_rhs1 (def_stmt)) == MEM_REF
               || handled_component_p (gimple_assign_rhs1 (def_stmt))))
     {
+      tree lhs = gimple_assign_lhs (def_stmt);
       tree base2;
       int i, j, k;
       auto_vec<vn_reference_op_s> rhs;
@@ -2770,7 +3063,8 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
        }
 
       /* Now re-write REF to be based on the rhs of the assignment.  */
-      copy_reference_ops_from_ref (gimple_assign_rhs1 (def_stmt), &rhs);
+      tree rhs1 = gimple_assign_rhs1 (def_stmt);
+      copy_reference_ops_from_ref (rhs1, &rhs);
 
       /* Apply an extra offset to the inner MEM_REF of the RHS.  */
       if (maybe_ne (extra_off, 0))
@@ -2787,6 +3081,11 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
                                                        extra_off));
        }
 
+      /* Save the operands since we need to use the original ones for
+        the hash entry we use.  */
+      if (!data->saved_operands.exists ())
+       data->saved_operands = vr->operands.copy ();
+
       /* We need to pre-pend vr->operands[0..i] to rhs.  */
       vec<vn_reference_op_s> old = vr->operands;
       if (i + 1 + rhs.length () > vr->operands.length ())
@@ -2805,20 +3104,19 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
       if (val)
        {
          if (data->partial_defs.is_empty ())
-           return vn_reference_lookup_or_insert_for_pieces
-               (vuse, vr->set, vr->type, vr->operands, val);
+           return data->finish (get_alias_set (lhs), val);
          /* This is the only interesting case for partial-def handling
             coming from targets that like to gimplify init-ctors as
             aggregate copies from constant data like aarch64 for
             PR83518.  */
-         if (maxsize.is_constant (&maxsizei)
-             && known_eq (ref->size, maxsize))
+         if (maxsize.is_constant (&maxsizei) && known_eq (ref->size, maxsize))
            {
              pd_data pd;
              pd.rhs = val;
              pd.offset = 0;
-             pd.size = maxsizei / BITS_PER_UNIT;
-             return data->push_partial_def (pd, vuse, maxsizei);
+             pd.size = maxsizei;
+             return data->push_partial_def (pd, get_alias_set (lhs),
+                                            maxsizei);
            }
        }
 
@@ -2829,7 +3127,8 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
        return (void *)-1;
 
       /* Adjust *ref from the new operands.  */
-      if (!ao_ref_init_from_vn_reference (&r, vr->set, vr->type, vr->operands))
+      if (!ao_ref_init_from_vn_reference (&r, get_alias_set (rhs1),
+                                         vr->type, vr->operands))
        return (void *)-1;
       /* This can happen with bitfields.  */
       if (maybe_ne (ref->size, r.size))
@@ -2841,6 +3140,9 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
       /* Invalidate the original access path since it now contains
          the wrong base.  */
       data->orig_ref.ref = NULL_TREE;
+      /* Use the alias-set of this LHS for recording an eventual result.  */
+      if (data->first_set == -2)
+       data->first_set = get_alias_set (lhs);
 
       /* Keep looking for the adjusted *REF / VR pair.  */
       return NULL;
@@ -2852,13 +3154,19 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
           && is_gimple_reg_type (vr->type)
           /* ???  Handle BCOPY as well.  */
           && (gimple_call_builtin_p (def_stmt, BUILT_IN_MEMCPY)
+              || gimple_call_builtin_p (def_stmt, BUILT_IN_MEMCPY_CHK)
               || gimple_call_builtin_p (def_stmt, BUILT_IN_MEMPCPY)
-              || gimple_call_builtin_p (def_stmt, BUILT_IN_MEMMOVE))
+              || gimple_call_builtin_p (def_stmt, BUILT_IN_MEMPCPY_CHK)
+              || gimple_call_builtin_p (def_stmt, BUILT_IN_MEMMOVE)
+              || gimple_call_builtin_p (def_stmt, BUILT_IN_MEMMOVE_CHK))
           && (TREE_CODE (gimple_call_arg (def_stmt, 0)) == ADDR_EXPR
               || TREE_CODE (gimple_call_arg (def_stmt, 0)) == SSA_NAME)
           && (TREE_CODE (gimple_call_arg (def_stmt, 1)) == ADDR_EXPR
               || TREE_CODE (gimple_call_arg (def_stmt, 1)) == SSA_NAME)
-          && poly_int_tree_p (gimple_call_arg (def_stmt, 2), &copy_size)
+          && (poly_int_tree_p (gimple_call_arg (def_stmt, 2), &copy_size)
+              || (TREE_CODE (gimple_call_arg (def_stmt, 2)) == SSA_NAME
+                  && poly_int_tree_p (SSA_VAL (gimple_call_arg (def_stmt, 2)),
+                                      &copy_size)))
           /* Handling this is more complicated, give up for now.  */
           && data->partial_defs.is_empty ())
     {
@@ -2935,8 +3243,9 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
          else
            return (void *)-1;
        }
-      if (TREE_CODE (rhs) != SSA_NAME
-         && TREE_CODE (rhs) != ADDR_EXPR)
+      if (TREE_CODE (rhs) == SSA_NAME)
+       rhs = SSA_VAL (rhs);
+      else if (TREE_CODE (rhs) != ADDR_EXPR)
        return (void *)-1;
 
       /* The bases of the destination and the references have to agree.  */
@@ -2960,6 +3269,11 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
       if (!known_subrange_p (at, byte_maxsize, lhs_offset, copy_size))
        return (void *)-1;
 
+      /* Save the operands since we need to use the original ones for
+        the hash entry we use.  */
+      if (!data->saved_operands.exists ())
+       data->saved_operands = vr->operands.copy ();
+
       /* Make room for 2 operands in the new reference.  */
       if (vr->operands.length () < 2)
        {
@@ -2988,11 +3302,10 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
       /* Try folding the new reference to a constant.  */
       tree val = fully_constant_vn_reference_p (vr);
       if (val)
-       return vn_reference_lookup_or_insert_for_pieces
-                (vuse, vr->set, vr->type, vr->operands, val);
+       return data->finish (0, val);
 
       /* Adjust *ref from the new operands.  */
-      if (!ao_ref_init_from_vn_reference (&r, vr->set, vr->type, vr->operands))
+      if (!ao_ref_init_from_vn_reference (&r, 0, vr->type, vr->operands))
        return (void *)-1;
       /* This can happen with bitfields.  */
       if (maybe_ne (ref->size, r.size))
@@ -3004,6 +3317,9 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
       /* Invalidate the original access path since it now contains
          the wrong base.  */
       data->orig_ref.ref = NULL_TREE;
+      /* Use the alias-set of this stmt for recording an eventual result.  */
+      if (data->first_set == -2)
+       data->first_set = 0;
 
       /* Keep looking for the adjusted *REF / VR pair.  */
       return NULL;
@@ -3063,7 +3379,7 @@ vn_reference_lookup_pieces (tree vuse, alias_set_type set, tree type,
       && vr1.vuse)
     {
       ao_ref r;
-      unsigned limit = PARAM_VALUE (PARAM_SCCVN_MAX_ALIAS_QUERIES_PER_ACCESS);
+      unsigned limit = param_sccvn_max_alias_queries_per_access;
       vn_walk_cb_data data (&vr1, NULL_TREE, NULL, kind, true);
       if (ao_ref_init_from_vn_reference (&r, set, type, vr1.operands))
        *vnresult =
@@ -3114,7 +3430,7 @@ vn_reference_lookup (tree op, tree vuse, vn_lookup_kind kind,
     {
       vn_reference_t wvnresult;
       ao_ref r;
-      unsigned limit = PARAM_VALUE (PARAM_SCCVN_MAX_ALIAS_QUERIES_PER_ACCESS);
+      unsigned limit = param_sccvn_max_alias_queries_per_access;
       /* Make sure to use a valueized reference if we valueized anything.
          Otherwise preserve the full reference for advanced TBAA.  */
       if (!valuezied_anything
@@ -3139,6 +3455,8 @@ vn_reference_lookup (tree op, tree vuse, vn_lookup_kind kind,
       return NULL_TREE;
     }
 
+  if (last_vuse_ptr)
+    *last_vuse_ptr = vr1.vuse;
   return vn_reference_lookup_1 (&vr1, vnresult);
 }
 
@@ -5099,18 +5417,15 @@ vn_nary_may_trap (vn_nary_op_t nary)
          honor_nans = flag_trapping_math && !flag_finite_math_only;
          honor_snans = flag_signaling_nans != 0;
        }
-      else if (INTEGRAL_TYPE_P (type)
-              && TYPE_OVERFLOW_TRAPS (type))
+      else if (INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_TRAPS (type))
        honor_trapv = true;
     }
   if (nary->length >= 2)
     rhs2 = nary->op[1];
   ret = operation_could_trap_helper_p (nary->opcode, fp_operation,
-                                      honor_trapv,
-                                      honor_nans, honor_snans, rhs2,
-                                      &handled);
-  if (handled
-      && ret)
+                                      honor_trapv, honor_nans, honor_snans,
+                                      rhs2, &handled);
+  if (handled && ret)
     return true;
 
   for (i = 0; i < nary->length; ++i)
@@ -5456,8 +5771,13 @@ eliminate_dom_walker::eliminate_stmt (basic_block b, gimple_stmt_iterator *gsi)
 
          /* If this is an assignment from our leader (which
             happens in the case the value-number is a constant)
-            then there is nothing to do.  */
-         if (gimple_assign_single_p (stmt)
+            then there is nothing to do.  Likewise if we run into
+            inserted code that needed a conversion because of
+            our type-agnostic value-numbering of loads.  */
+         if ((gimple_assign_single_p (stmt)
+              || (is_gimple_assign (stmt)
+                  && (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt))
+                      || gimple_assign_rhs_code (stmt) == VIEW_CONVERT_EXPR)))
              && sprime == gimple_assign_rhs1 (stmt))
            return;
 
@@ -5535,15 +5855,62 @@ eliminate_dom_walker::eliminate_stmt (basic_block b, gimple_stmt_iterator *gsi)
       && (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
          || is_gimple_min_invariant (gimple_assign_rhs1 (stmt))))
     {
-      tree val;
       tree rhs = gimple_assign_rhs1 (stmt);
       vn_reference_t vnresult;
-      val = vn_reference_lookup (lhs, gimple_vuse (stmt), VN_WALKREWRITE,
-                                &vnresult, false);
+      /* ???  gcc.dg/torture/pr91445.c shows that we lookup a boolean
+         typed load of a byte known to be 0x11 as 1 so a store of
+        a boolean 1 is detected as redundant.  Because of this we
+        have to make sure to lookup with a ref where its size
+        matches the precision.  */
+      tree lookup_lhs = lhs;
+      if (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
+         && (TREE_CODE (lhs) != COMPONENT_REF
+             || !DECL_BIT_FIELD_TYPE (TREE_OPERAND (lhs, 1)))
+         && !type_has_mode_precision_p (TREE_TYPE (lhs)))
+       {
+         if (TREE_CODE (lhs) == COMPONENT_REF
+             || TREE_CODE (lhs) == MEM_REF)
+           {
+             tree ltype = build_nonstandard_integer_type
+                               (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (lhs))),
+                                TYPE_UNSIGNED (TREE_TYPE (lhs)));
+             if (TREE_CODE (lhs) == COMPONENT_REF)
+               {
+                 tree foff = component_ref_field_offset (lhs);
+                 tree f = TREE_OPERAND (lhs, 1);
+                 if (!poly_int_tree_p (foff))
+                   lookup_lhs = NULL_TREE;
+                 else
+                   lookup_lhs = build3 (BIT_FIELD_REF, ltype,
+                                        TREE_OPERAND (lhs, 0),
+                                        TYPE_SIZE (TREE_TYPE (lhs)),
+                                        bit_from_pos
+                                          (foff, DECL_FIELD_BIT_OFFSET (f)));
+               }
+             else
+               lookup_lhs = build2 (MEM_REF, ltype,
+                                    TREE_OPERAND (lhs, 0),
+                                    TREE_OPERAND (lhs, 1));
+           }
+         else
+           lookup_lhs = NULL_TREE;
+       }
+      tree val = NULL_TREE;
+      if (lookup_lhs)
+       val = vn_reference_lookup (lookup_lhs, gimple_vuse (stmt),
+                                  VN_WALKREWRITE, &vnresult, false);
       if (TREE_CODE (rhs) == SSA_NAME)
        rhs = VN_INFO (rhs)->valnum;
       if (val
-         && operand_equal_p (val, rhs, 0))
+         && (operand_equal_p (val, rhs, 0)
+             /* Due to the bitfield lookups above we can get bit
+                interpretations of the same RHS as values here.  Those
+                are redundant as well.  */
+             || (TREE_CODE (val) == SSA_NAME
+                 && gimple_assign_single_p (SSA_NAME_DEF_STMT (val))
+                 && (val = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (val)))
+                 && TREE_CODE (val) == VIEW_CONVERT_EXPR
+                 && TREE_OPERAND (val, 0) == rhs)))
        {
          /* We can only remove the later store if the former aliases
             at least all accesses the later one does or if the store
@@ -6364,7 +6731,7 @@ process_bb (rpo_elim &avail, basic_block bb,
       if (bb->loop_father->nb_iterations)
        bb->loop_father->nb_iterations
          = simplify_replace_tree (bb->loop_father->nb_iterations,
-                                  NULL_TREE, NULL_TREE, vn_valueize);
+                                  NULL_TREE, NULL_TREE, &vn_valueize_wrapper);
     }
 
   /* Value-number all defs in the basic-block.  */
@@ -6932,7 +7299,7 @@ do_rpo_vn (function *fn, edge entry, bitmap exit_bbs,
   if (iterate)
     {
       loop_p loop;
-      unsigned max_depth = PARAM_VALUE (PARAM_RPO_VN_MAX_LOOP_DEPTH);
+      unsigned max_depth = param_rpo_vn_max_loop_depth;
       FOR_EACH_LOOP (loop, LI_ONLY_INNERMOST)
        if (loop_depth (loop) > max_depth)
          for (unsigned i = 2;