https://gcc.gnu.org/g:65b912675f92d3d6ce339993f5ea7d7d9c596b4f

commit 65b912675f92d3d6ce339993f5ea7d7d9c596b4f
Author: Michael Matz <[email protected]>
Date:   Sun Feb 25 04:46:38 2018 +0100

    no-update-stmt: more progress
    
    run whole testsuite (not just check-gcc), fixed some things
    turning up.  Also introduce gimple_change_in_op() which can
    be used to overwrite trees within an operand, which can be used
    from e.g. walk_gimple_op callbacks to update operand caches.
    
    Use it to get rid of two update_stmt_for_real calls.

Diff:
---
 gcc/gimple-fold.c                   |  46 ++++++++------
 gcc/gimple-ssa-strength-reduction.c |  26 ++++----
 gcc/gimple-streamer-in.c            |  43 ++++++++++++-
 gcc/gimple-walk.c                   |  96 ++++++++++++++++-------------
 gcc/gimple-walk.h                   |   3 +
 gcc/gimple.h                        |  29 +++++++++
 gcc/gimplify-me.c                   |  14 +++--
 gcc/ipa-split.c                     |   8 +--
 gcc/lto-streamer-in.c               |  51 +---------------
 gcc/omp-simd-clone.c                |   8 +--
 gcc/tree-cfg.c                      |  14 ++++-
 gcc/tree-chkp-opt.c                 |  12 ++--
 gcc/tree-ssa-forwprop.c             |   2 -
 gcc/tree-ssa-operands.c             | 119 ++++++++++++++++++++++++++++++++----
 gcc/value-prof.c                    |  23 ++++---
 15 files changed, 320 insertions(+), 174 deletions(-)

diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 2a44bb806109..d5ded2b1104e 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -4508,7 +4508,7 @@ replace_stmt_with_simplification (gimple_stmt_iterator 
*gsi,
 /* Canonicalize MEM_REFs invariant address operand after propagation.  */
 
 static bool
-maybe_canonicalize_mem_ref_addr (tree *t)
+maybe_canonicalize_mem_ref_addr (gimple *stmt, tree *op_ptr, tree *t)
 {
   bool res = false;
 
@@ -4541,11 +4541,13 @@ maybe_canonicalize_mem_ref_addr (tree *t)
                    = wi::add (idx, wi::to_widest (TYPE_SIZE (TREE_TYPE (*t))));
                  if (wi::les_p (ext, wi::to_widest (TYPE_SIZE (vtype))))
                    {
-                     *t = build3_loc (EXPR_LOCATION (*t), BIT_FIELD_REF,
-                                      TREE_TYPE (*t),
-                                      TREE_OPERAND (TREE_OPERAND (*t, 0), 0),
-                                      TYPE_SIZE (TREE_TYPE (*t)),
-                                      wide_int_to_tree (bitsizetype, idx));
+                     tree val
+                         = build3_loc (EXPR_LOCATION (*t), BIT_FIELD_REF,
+                                       TREE_TYPE (*t),
+                                       TREE_OPERAND (TREE_OPERAND (*t, 0), 0),
+                                       TYPE_SIZE (TREE_TYPE (*t)),
+                                       wide_int_to_tree (bitsizetype, idx));
+                     gimple_change_in_op (stmt, op_ptr, t, val);
                      res = true;
                    }
                }
@@ -4573,7 +4575,8 @@ maybe_canonicalize_mem_ref_addr (tree *t)
          if (!base)
            gcc_unreachable ();
 
-         TREE_OPERAND (*t, 0) = build_fold_addr_expr (base);
+         gimple_change_in_op (stmt, op_ptr, &TREE_OPERAND (*t, 0),
+                              build_fold_addr_expr (base));
          TREE_OPERAND (*t, 1) = int_const_binop (PLUS_EXPR,
                                                  TREE_OPERAND (*t, 1),
                                                  size_int (coffset));
@@ -4606,7 +4609,8 @@ maybe_canonicalize_mem_ref_addr (tree *t)
             compatibility.  */
          && types_compatible_p (TREE_TYPE (*t), TREE_TYPE (decl)))
        {
-         *t = TREE_OPERAND (TREE_OPERAND (*t, 0), 0);
+         gimple_change_in_op (stmt, op_ptr, t,
+                              TREE_OPERAND (TREE_OPERAND (*t, 0), 0));
          res = true;
        }
     }
@@ -4618,7 +4622,7 @@ maybe_canonicalize_mem_ref_addr (tree *t)
       tree tem = maybe_fold_tmr (*t);
       if (tem)
        {
-         *t = tem;
+         gimple_change_in_op (stmt, op_ptr, t, tem);
          res = true;
        }
     }
@@ -4652,11 +4656,11 @@ fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace, 
tree (*valueize) (tree))
          tree *rhs = gimple_assign_rhs1_ptr (stmt);
          if ((REFERENCE_CLASS_P (*rhs)
               || TREE_CODE (*rhs) == ADDR_EXPR)
-             && maybe_canonicalize_mem_ref_addr (rhs))
+             && maybe_canonicalize_mem_ref_addr (stmt, rhs, rhs))
            changed = true;
          tree *lhs = gimple_assign_lhs_ptr (stmt);
          if (REFERENCE_CLASS_P (*lhs)
-             && maybe_canonicalize_mem_ref_addr (lhs))
+             && maybe_canonicalize_mem_ref_addr (stmt, lhs, lhs))
            changed = true;
        }
       else
@@ -4687,13 +4691,13 @@ fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace, 
tree (*valueize) (tree))
          {
            tree *arg = gimple_call_arg_ptr (stmt, i);
            if (REFERENCE_CLASS_P (*arg)
-               && maybe_canonicalize_mem_ref_addr (arg))
+               && maybe_canonicalize_mem_ref_addr (stmt, arg, arg))
              changed = true;
          }
        tree *lhs = gimple_call_lhs_ptr (stmt);
        if (*lhs
            && REFERENCE_CLASS_P (*lhs)
-           && maybe_canonicalize_mem_ref_addr (lhs))
+           && maybe_canonicalize_mem_ref_addr (stmt, lhs, lhs))
          changed = true;
        break;
       }
@@ -4702,19 +4706,21 @@ fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace, 
tree (*valueize) (tree))
        gasm *asm_stmt = as_a <gasm *> (stmt);
        for (i = 0; i < gimple_asm_noutputs (asm_stmt); ++i)
          {
-           tree link = gimple_asm_output_op (asm_stmt, i);
-           tree op = TREE_VALUE (link);
+           tree *link = gimple_asm_output_op_ptr (asm_stmt, i);
+           tree op = TREE_VALUE (*link);
            if (REFERENCE_CLASS_P (op)
-               && maybe_canonicalize_mem_ref_addr (&TREE_VALUE (link)))
+               && maybe_canonicalize_mem_ref_addr (stmt, link,
+                                                   &TREE_VALUE (*link)))
              changed = true;
          }
        for (i = 0; i < gimple_asm_ninputs (asm_stmt); ++i)
          {
-           tree link = gimple_asm_input_op (asm_stmt, i);
-           tree op = TREE_VALUE (link);
+           tree *link = gimple_asm_input_op_ptr (asm_stmt, i);
+           tree op = TREE_VALUE (*link);
            if ((REFERENCE_CLASS_P (op)
                 || TREE_CODE (op) == ADDR_EXPR)
-               && maybe_canonicalize_mem_ref_addr (&TREE_VALUE (link)))
+               && maybe_canonicalize_mem_ref_addr (stmt, link,
+                                                   &TREE_VALUE (*link)))
              changed = true;
          }
       }
@@ -4726,7 +4732,7 @@ fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace, 
tree (*valueize) (tree))
          if (*val
              && (REFERENCE_CLASS_P (*val)
                  || TREE_CODE (*val) == ADDR_EXPR)
-             && maybe_canonicalize_mem_ref_addr (val))
+             && maybe_canonicalize_mem_ref_addr (stmt, val, val))
            changed = true;
        }
       break;
diff --git a/gcc/gimple-ssa-strength-reduction.c 
b/gcc/gimple-ssa-strength-reduction.c
index ba418fdbafac..02eb8d2cf7b1 100644
--- a/gcc/gimple-ssa-strength-reduction.c
+++ b/gcc/gimple-ssa-strength-reduction.c
@@ -1961,19 +1961,19 @@ dump_incr_vec (void)
     }
 }
 
-/* Replace *EXPR in candidate C with an equivalent strength-reduced
+/* For EXPR in candidate C return an equivalent strength-reduced
    data reference.  */
 
-static void
-replace_ref (tree *expr, slsr_cand_t c)
+static tree
+replace_ref (tree expr, slsr_cand_t c)
 {
-  tree add_expr, mem_ref, acc_type = TREE_TYPE (*expr);
+  tree add_expr, mem_ref, acc_type = TREE_TYPE (expr);
   unsigned HOST_WIDE_INT misalign;
   unsigned align;
 
   /* Ensure the memory reference carries the minimum alignment
      requirement for the data type.  See PR58041.  */
-  get_object_alignment_1 (*expr, &align, &misalign);
+  get_object_alignment_1 (expr, &align, &misalign);
   if (misalign != 0)
     align = least_bit_hwi (misalign);
   if (align < TYPE_ALIGN (acc_type))
@@ -1990,11 +1990,8 @@ replace_ref (tree *expr, slsr_cand_t c)
     = force_gimple_operand_gsi (&gsi, TREE_OPERAND (mem_ref, 0),
                                /*simple_p=*/true, NULL,
                                /*before=*/true, GSI_SAME_STMT);
-  copy_ref_info (mem_ref, *expr);
-  *expr = mem_ref;
-  /* XXX change gimple operands via proper wrappers not via
-     pointer store, so no update_stmt would be needed.  */
-  update_stmt_for_real (c->cand_stmt);
+  copy_ref_info (mem_ref, expr);
+  return mem_ref;
 }
 
 /* Replace CAND_REF candidate C, each sibling of candidate C, and each
@@ -2012,14 +2009,15 @@ replace_refs (slsr_cand_t c)
 
   if (gimple_vdef (c->cand_stmt))
     {
-      tree *lhs = gimple_assign_lhs_ptr (c->cand_stmt);
-      replace_ref (lhs, c);
+      tree lhs = gimple_assign_lhs (c->cand_stmt);
+      gimple_assign_set_lhs (c->cand_stmt, replace_ref (lhs, c));
     }
   else
     {
-      tree *rhs = gimple_assign_rhs1_ptr (c->cand_stmt);
-      replace_ref (rhs, c);
+      tree rhs = gimple_assign_rhs1 (c->cand_stmt);
+      gimple_assign_set_rhs1 (c->cand_stmt, replace_ref (rhs, c));
     }
+  update_stmt (c->cand_stmt);
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
diff --git a/gcc/gimple-streamer-in.c b/gcc/gimple-streamer-in.c
index 6ffef29bf1f8..2cf7cf7e801c 100644
--- a/gcc/gimple-streamer-in.c
+++ b/gcc/gimple-streamer-in.c
@@ -186,8 +186,47 @@ input_gimple_stmt (struct lto_input_block *ib, struct 
data_in *data_in,
       if (gcall *call_stmt = dyn_cast <gcall *> (stmt))
        {
          if (gimple_call_internal_p (call_stmt))
-           gimple_call_set_internal_fn
-             (call_stmt, streamer_read_enum (ib, internal_fn, IFN_LAST));
+           {
+             enum internal_fn ifn
+               = streamer_read_enum (ib, internal_fn, IFN_LAST);
+             /* Patch out all *SAN calls if we're not supposed
+                to have them due to compiling with different flags now.  */
+             switch (ifn)
+               {
+                 case IFN_UBSAN_NULL:
+                     if ((flag_sanitize
+                          & (SANITIZE_NULL | SANITIZE_ALIGNMENT)) == 0)
+                       ifn = IFN_NOP;
+                     break;
+                 case IFN_UBSAN_BOUNDS:
+                     if ((flag_sanitize & SANITIZE_BOUNDS) == 0)
+                       ifn = IFN_NOP;
+                     break;
+                 case IFN_UBSAN_VPTR:
+                     if ((flag_sanitize & SANITIZE_VPTR) == 0)
+                       ifn = IFN_NOP;
+                     break;
+                 case IFN_UBSAN_OBJECT_SIZE:
+                     if ((flag_sanitize & SANITIZE_OBJECT_SIZE) == 0)
+                       ifn = IFN_NOP;
+                     break;
+                 case IFN_UBSAN_PTR:
+                     if ((flag_sanitize & SANITIZE_POINTER_OVERFLOW) == 0)
+                       ifn = IFN_NOP;
+                     break;
+                 case IFN_ASAN_MARK:
+                     if ((flag_sanitize & SANITIZE_ADDRESS) == 0)
+                       ifn = IFN_NOP;
+                     break;
+                 case IFN_TSAN_FUNC_EXIT:
+                     if ((flag_sanitize & SANITIZE_THREAD) == 0)
+                       ifn = IFN_NOP;
+                     break;
+                 default:
+                     break;
+               }
+             gimple_call_set_internal_fn (call_stmt, ifn);
+           }
          else
            gimple_call_set_fntype (call_stmt, stream_read_tree (ib, data_in));
        }
diff --git a/gcc/gimple-walk.c b/gcc/gimple-walk.c
index c50a6dd61413..9a716a21c96b 100644
--- a/gcc/gimple-walk.c
+++ b/gcc/gimple-walk.c
@@ -110,6 +110,7 @@ walk_gimple_asm (gasm *stmt, walk_tree_fn callback_op,
          if (parse_output_constraint (&constraint, i, 0, 0, &allows_mem,
                                       &allows_reg, &is_inout))
            wi->val_only = (allows_reg || !allows_mem);
+         wi->op_ptr = gimple_asm_output_op_ptr (stmt, i);
        }
       if (wi)
        wi->is_lhs = true;
@@ -133,6 +134,7 @@ walk_gimple_asm (gasm *stmt, walk_tree_fn callback_op,
              /* Although input "m" is not really a LHS, we need a lvalue.  */
              wi->is_lhs = !wi->val_only;
            }
+         wi->op_ptr = gimple_asm_input_op_ptr (stmt, i);
        }
       ret = walk_tree (&TREE_VALUE (op), callback_op, wi, NULL);
       if (ret)
@@ -149,6 +151,8 @@ walk_gimple_asm (gasm *stmt, walk_tree_fn callback_op,
   for (i = 0; i < n; i++)
     {
       op = gimple_asm_label_op (stmt, i);
+      if (wi)
+       wi->op_ptr = gimple_asm_label_op_ptr (stmt, i);
       ret = walk_tree (&TREE_VALUE (op), callback_op, wi, NULL);
       if (ret)
        return ret;
@@ -157,6 +161,14 @@ walk_gimple_asm (gasm *stmt, walk_tree_fn callback_op,
   return NULL_TREE;
 }
 
+static tree
+walk_help (tree *tp, walk_tree_fn func, struct walk_stmt_info *wi,
+          hash_set<tree> *pset)
+{
+  if (wi)
+    wi->op_ptr = tp;
+  return walk_tree (tp, func, wi, pset);
+}
 
 /* Helper function of WALK_GIMPLE_STMT.  Walk every tree operand in
    STMT.  CALLBACK_OP and WI are as in WALK_GIMPLE_STMT.
@@ -199,7 +211,7 @@ walk_gimple_op (gimple *stmt, walk_tree_fn callback_op,
 
       for (i = 1; i < gimple_num_ops (stmt); i++)
        {
-         ret = walk_tree (gimple_op_ptr (stmt, i), callback_op, wi,
+         ret = walk_help (gimple_op_ptr (stmt, i), callback_op, wi,
                           pset);
          if (ret)
            return ret;
@@ -218,7 +230,7 @@ walk_gimple_op (gimple *stmt, walk_tree_fn callback_op,
          wi->is_lhs = true;
        }
 
-      ret = walk_tree (gimple_op_ptr (stmt, 0), callback_op, wi, pset);
+      ret = walk_help (gimple_op_ptr (stmt, 0), callback_op, wi, pset);
       if (ret)
        return ret;
 
@@ -236,12 +248,12 @@ walk_gimple_op (gimple *stmt, walk_tree_fn callback_op,
          wi->val_only = true;
        }
 
-      ret = walk_tree (gimple_call_chain_ptr (as_a <gcall *> (stmt)),
+      ret = walk_help (gimple_call_chain_ptr (as_a <gcall *> (stmt)),
                       callback_op, wi, pset);
       if (ret)
         return ret;
 
-      ret = walk_tree (gimple_call_fn_ptr (stmt), callback_op, wi, pset);
+      ret = walk_help (gimple_call_fn_ptr (stmt), callback_op, wi, pset);
       if (ret)
         return ret;
 
@@ -250,7 +262,7 @@ walk_gimple_op (gimple *stmt, walk_tree_fn callback_op,
          if (wi)
            wi->val_only
              = is_gimple_reg_type (TREE_TYPE (gimple_call_arg (stmt, i)));
-         ret = walk_tree (gimple_call_arg_ptr (stmt, i), callback_op, wi,
+         ret = walk_help (gimple_call_arg_ptr (stmt, i), callback_op, wi,
                           pset);
          if (ret)
            return ret;
@@ -265,7 +277,7 @@ walk_gimple_op (gimple *stmt, walk_tree_fn callback_op,
                = is_gimple_reg_type (TREE_TYPE (gimple_call_lhs (stmt)));
            }
 
-         ret = walk_tree (gimple_call_lhs_ptr (stmt), callback_op, wi, pset);
+         ret = walk_help (gimple_call_lhs_ptr (stmt), callback_op, wi, pset);
          if (ret)
            return ret;
        }
@@ -278,14 +290,14 @@ walk_gimple_op (gimple *stmt, walk_tree_fn callback_op,
       break;
 
     case GIMPLE_CATCH:
-      ret = walk_tree (gimple_catch_types_ptr (as_a <gcatch *> (stmt)),
+      ret = walk_help (gimple_catch_types_ptr (as_a <gcatch *> (stmt)),
                       callback_op, wi, pset);
       if (ret)
        return ret;
       break;
 
     case GIMPLE_EH_FILTER:
-      ret = walk_tree (gimple_eh_filter_types_ptr (stmt), callback_op, wi,
+      ret = walk_help (gimple_eh_filter_types_ptr (stmt), callback_op, wi,
                       pset);
       if (ret)
        return ret;
@@ -300,12 +312,12 @@ walk_gimple_op (gimple *stmt, walk_tree_fn callback_op,
     case GIMPLE_OMP_CONTINUE:
       {
        gomp_continue *cont_stmt = as_a <gomp_continue *> (stmt);
-       ret = walk_tree (gimple_omp_continue_control_def_ptr (cont_stmt),
+       ret = walk_help (gimple_omp_continue_control_def_ptr (cont_stmt),
                         callback_op, wi, pset);
        if (ret)
          return ret;
 
-       ret = walk_tree (gimple_omp_continue_control_use_ptr (cont_stmt),
+       ret = walk_help (gimple_omp_continue_control_use_ptr (cont_stmt),
                         callback_op, wi, pset);
        if (ret)
          return ret;
@@ -315,11 +327,11 @@ walk_gimple_op (gimple *stmt, walk_tree_fn callback_op,
     case GIMPLE_OMP_CRITICAL:
       {
        gomp_critical *omp_stmt = as_a <gomp_critical *> (stmt);
-       ret = walk_tree (gimple_omp_critical_name_ptr (omp_stmt),
+       ret = walk_help (gimple_omp_critical_name_ptr (omp_stmt),
                         callback_op, wi, pset);
        if (ret)
          return ret;
-       ret = walk_tree (gimple_omp_critical_clauses_ptr (omp_stmt),
+       ret = walk_help (gimple_omp_critical_clauses_ptr (omp_stmt),
                         callback_op, wi, pset);
        if (ret)
          return ret;
@@ -329,7 +341,7 @@ walk_gimple_op (gimple *stmt, walk_tree_fn callback_op,
     case GIMPLE_OMP_ORDERED:
       {
        gomp_ordered *omp_stmt = as_a <gomp_ordered *> (stmt);
-       ret = walk_tree (gimple_omp_ordered_clauses_ptr (omp_stmt),
+       ret = walk_help (gimple_omp_ordered_clauses_ptr (omp_stmt),
                         callback_op, wi, pset);
        if (ret)
          return ret;
@@ -337,25 +349,25 @@ walk_gimple_op (gimple *stmt, walk_tree_fn callback_op,
       break;
 
     case GIMPLE_OMP_FOR:
-      ret = walk_tree (gimple_omp_for_clauses_ptr (stmt), callback_op, wi,
+      ret = walk_help (gimple_omp_for_clauses_ptr (stmt), callback_op, wi,
                       pset);
       if (ret)
        return ret;
       for (i = 0; i < gimple_omp_for_collapse (stmt); i++)
        {
-         ret = walk_tree (gimple_omp_for_index_ptr (stmt, i), callback_op,
+         ret = walk_help (gimple_omp_for_index_ptr (stmt, i), callback_op,
                           wi, pset);
          if (ret)
            return ret;
-         ret = walk_tree (gimple_omp_for_initial_ptr (stmt, i), callback_op,
+         ret = walk_help (gimple_omp_for_initial_ptr (stmt, i), callback_op,
                           wi, pset);
          if (ret)
            return ret;
-         ret = walk_tree (gimple_omp_for_final_ptr (stmt, i), callback_op,
+         ret = walk_help (gimple_omp_for_final_ptr (stmt, i), callback_op,
                           wi, pset);
          if (ret)
            return ret;
-         ret = walk_tree (gimple_omp_for_incr_ptr (stmt, i), callback_op,
+         ret = walk_help (gimple_omp_for_incr_ptr (stmt, i), callback_op,
                           wi, pset);
          if (ret)
            return ret;
@@ -365,15 +377,15 @@ walk_gimple_op (gimple *stmt, walk_tree_fn callback_op,
     case GIMPLE_OMP_PARALLEL:
       {
        gomp_parallel *omp_par_stmt = as_a <gomp_parallel *> (stmt);
-       ret = walk_tree (gimple_omp_parallel_clauses_ptr (omp_par_stmt),
+       ret = walk_help (gimple_omp_parallel_clauses_ptr (omp_par_stmt),
                         callback_op, wi, pset);
        if (ret)
          return ret;
-       ret = walk_tree (gimple_omp_parallel_child_fn_ptr (omp_par_stmt),
+       ret = walk_help (gimple_omp_parallel_child_fn_ptr (omp_par_stmt),
                         callback_op, wi, pset);
        if (ret)
          return ret;
-       ret = walk_tree (gimple_omp_parallel_data_arg_ptr (omp_par_stmt),
+       ret = walk_help (gimple_omp_parallel_data_arg_ptr (omp_par_stmt),
                         callback_op, wi, pset);
        if (ret)
          return ret;
@@ -381,38 +393,38 @@ walk_gimple_op (gimple *stmt, walk_tree_fn callback_op,
       break;
 
     case GIMPLE_OMP_TASK:
-      ret = walk_tree (gimple_omp_task_clauses_ptr (stmt), callback_op,
+      ret = walk_help (gimple_omp_task_clauses_ptr (stmt), callback_op,
                       wi, pset);
       if (ret)
        return ret;
-      ret = walk_tree (gimple_omp_task_child_fn_ptr (stmt), callback_op,
+      ret = walk_help (gimple_omp_task_child_fn_ptr (stmt), callback_op,
                       wi, pset);
       if (ret)
        return ret;
-      ret = walk_tree (gimple_omp_task_data_arg_ptr (stmt), callback_op,
+      ret = walk_help (gimple_omp_task_data_arg_ptr (stmt), callback_op,
                       wi, pset);
       if (ret)
        return ret;
-      ret = walk_tree (gimple_omp_task_copy_fn_ptr (stmt), callback_op,
+      ret = walk_help (gimple_omp_task_copy_fn_ptr (stmt), callback_op,
                       wi, pset);
       if (ret)
        return ret;
-      ret = walk_tree (gimple_omp_task_arg_size_ptr (stmt), callback_op,
+      ret = walk_help (gimple_omp_task_arg_size_ptr (stmt), callback_op,
                       wi, pset);
       if (ret)
        return ret;
-      ret = walk_tree (gimple_omp_task_arg_align_ptr (stmt), callback_op,
+      ret = walk_help (gimple_omp_task_arg_align_ptr (stmt), callback_op,
                       wi, pset);
       if (ret)
        return ret;
       break;
 
     case GIMPLE_OMP_SECTIONS:
-      ret = walk_tree (gimple_omp_sections_clauses_ptr (stmt), callback_op,
+      ret = walk_help (gimple_omp_sections_clauses_ptr (stmt), callback_op,
                       wi, pset);
       if (ret)
        return ret;
-      ret = walk_tree (gimple_omp_sections_control_ptr (stmt), callback_op,
+      ret = walk_help (gimple_omp_sections_control_ptr (stmt), callback_op,
                       wi, pset);
       if (ret)
        return ret;
@@ -420,7 +432,7 @@ walk_gimple_op (gimple *stmt, walk_tree_fn callback_op,
       break;
 
     case GIMPLE_OMP_SINGLE:
-      ret = walk_tree (gimple_omp_single_clauses_ptr (stmt), callback_op, wi,
+      ret = walk_help (gimple_omp_single_clauses_ptr (stmt), callback_op, wi,
                       pset);
       if (ret)
        return ret;
@@ -429,15 +441,15 @@ walk_gimple_op (gimple *stmt, walk_tree_fn callback_op,
     case GIMPLE_OMP_TARGET:
       {
        gomp_target *omp_stmt = as_a <gomp_target *> (stmt);
-       ret = walk_tree (gimple_omp_target_clauses_ptr (omp_stmt),
+       ret = walk_help (gimple_omp_target_clauses_ptr (omp_stmt),
                         callback_op, wi, pset);
        if (ret)
          return ret;
-       ret = walk_tree (gimple_omp_target_child_fn_ptr (omp_stmt),
+       ret = walk_help (gimple_omp_target_child_fn_ptr (omp_stmt),
                         callback_op, wi, pset);
        if (ret)
          return ret;
-       ret = walk_tree (gimple_omp_target_data_arg_ptr (omp_stmt),
+       ret = walk_help (gimple_omp_target_data_arg_ptr (omp_stmt),
                         callback_op, wi, pset);
        if (ret)
          return ret;
@@ -445,7 +457,7 @@ walk_gimple_op (gimple *stmt, walk_tree_fn callback_op,
       break;
 
     case GIMPLE_OMP_TEAMS:
-      ret = walk_tree (gimple_omp_teams_clauses_ptr (stmt), callback_op, wi,
+      ret = walk_help (gimple_omp_teams_clauses_ptr (stmt), callback_op, wi,
                       pset);
       if (ret)
        return ret;
@@ -454,11 +466,11 @@ walk_gimple_op (gimple *stmt, walk_tree_fn callback_op,
     case GIMPLE_OMP_ATOMIC_LOAD:
       {
        gomp_atomic_load *omp_stmt = as_a <gomp_atomic_load *> (stmt);
-       ret = walk_tree (gimple_omp_atomic_load_lhs_ptr (omp_stmt),
+       ret = walk_help (gimple_omp_atomic_load_lhs_ptr (omp_stmt),
                         callback_op, wi, pset);
        if (ret)
          return ret;
-       ret = walk_tree (gimple_omp_atomic_load_rhs_ptr (omp_stmt),
+       ret = walk_help (gimple_omp_atomic_load_rhs_ptr (omp_stmt),
                         callback_op, wi, pset);
        if (ret)
          return ret;
@@ -468,7 +480,7 @@ walk_gimple_op (gimple *stmt, walk_tree_fn callback_op,
     case GIMPLE_OMP_ATOMIC_STORE:
       {
        gomp_atomic_store *omp_stmt = as_a <gomp_atomic_store *> (stmt);
-       ret = walk_tree (gimple_omp_atomic_store_val_ptr (omp_stmt),
+       ret = walk_help (gimple_omp_atomic_store_val_ptr (omp_stmt),
                         callback_op, wi, pset);
        if (ret)
          return ret;
@@ -479,15 +491,15 @@ walk_gimple_op (gimple *stmt, walk_tree_fn callback_op,
       {
        gtransaction *txn = as_a <gtransaction *> (stmt);
 
-       ret = walk_tree (gimple_transaction_label_norm_ptr (txn),
+       ret = walk_help (gimple_transaction_label_norm_ptr (txn),
                         callback_op, wi, pset);
        if (ret)
          return ret;
-       ret = walk_tree (gimple_transaction_label_uninst_ptr (txn),
+       ret = walk_help (gimple_transaction_label_uninst_ptr (txn),
                         callback_op, wi, pset);
        if (ret)
          return ret;
-       ret = walk_tree (gimple_transaction_label_over_ptr (txn),
+       ret = walk_help (gimple_transaction_label_over_ptr (txn),
                         callback_op, wi, pset);
        if (ret)
          return ret;
@@ -495,7 +507,7 @@ walk_gimple_op (gimple *stmt, walk_tree_fn callback_op,
       break;
 
     case GIMPLE_OMP_RETURN:
-      ret = walk_tree (gimple_omp_return_lhs_ptr (stmt), callback_op, wi,
+      ret = walk_help (gimple_omp_return_lhs_ptr (stmt), callback_op, wi,
                       pset);
       if (ret)
        return ret;
@@ -514,7 +526,7 @@ walk_gimple_op (gimple *stmt, walk_tree_fn callback_op,
        if (gss == GSS_WITH_OPS || gss == GSS_WITH_MEM_OPS)
          for (i = 0; i < gimple_num_ops (stmt); i++)
            {
-             ret = walk_tree (gimple_op_ptr (stmt, i), callback_op, wi, pset);
+             ret = walk_help (gimple_op_ptr (stmt, i), callback_op, wi, pset);
              if (ret)
                return ret;
            }
diff --git a/gcc/gimple-walk.h b/gcc/gimple-walk.h
index a051b3e35355..2ad609ada82b 100644
--- a/gcc/gimple-walk.h
+++ b/gcc/gimple-walk.h
@@ -30,6 +30,9 @@ struct walk_stmt_info
   gimple_stmt_iterator gsi;
   gimple *stmt;
 
+  /* Pointer to the gimple operand currently being walked.  */
+  tree *op_ptr;
+
   /* Additional data that the callback functions may want to carry
      through the recursion.  */
   void *info;
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 76f38b81e6f5..45d619092238 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -2351,6 +2351,7 @@ gimple_num_ops (const gimple *gs)
 
 
 void gimple_set_op_update (gimple *, unsigned, tree);
+void gimple_change_in_op (gimple *, tree *, tree *, tree);
 
 /* Set the number of operands for statement GS.  */
 
@@ -3872,6 +3873,13 @@ gimple_asm_input_op (const gasm *asm_stmt, unsigned 
index)
   return asm_stmt->op[index + asm_stmt->no];
 }
 
+static inline tree *
+gimple_asm_input_op_ptr (gasm *asm_stmt, unsigned index)
+{
+  gcc_gimple_checking_assert (index < asm_stmt->ni);
+  return &asm_stmt->op[index + asm_stmt->no];
+}
+
 /* Set IN_OP to be input operand INDEX in GIMPLE_ASM ASM_STMT.  */
 
 static inline void
@@ -3893,6 +3901,13 @@ gimple_asm_output_op (const gasm *asm_stmt, unsigned 
index)
   return asm_stmt->op[index];
 }
 
+static inline tree *
+gimple_asm_output_op_ptr (gasm *asm_stmt, unsigned index)
+{
+  gcc_gimple_checking_assert (index < asm_stmt->no);
+  return &asm_stmt->op[index];
+}
+
 /* Set OUT_OP to be output operand INDEX in GIMPLE_ASM ASM_STMT.  */
 
 static inline void
@@ -3914,6 +3929,13 @@ gimple_asm_clobber_op (const gasm *asm_stmt, unsigned 
index)
   return asm_stmt->op[index + asm_stmt->ni + asm_stmt->no];
 }
 
+static inline tree *
+gimple_asm_clobber_op_ptr (gasm *asm_stmt, unsigned index)
+{
+  gcc_gimple_checking_assert (index < asm_stmt->nc);
+  return &asm_stmt->op[index + asm_stmt->ni + asm_stmt->no];
+}
+
 
 /* Set CLOBBER_OP to be clobber operand INDEX in GIMPLE_ASM ASM_STMT.  */
 
@@ -3936,6 +3958,13 @@ gimple_asm_label_op (const gasm *asm_stmt, unsigned 
index)
   return asm_stmt->op[index + asm_stmt->ni + asm_stmt->nc];
 }
 
+static inline tree *
+gimple_asm_label_op_ptr (gasm *asm_stmt, unsigned index)
+{
+  gcc_gimple_checking_assert (index < asm_stmt->nl);
+  return &asm_stmt->op[index + asm_stmt->ni + asm_stmt->nc];
+}
+
 /* Set LABEL_OP to be label operand INDEX in GIMPLE_ASM ASM_STMT.  */
 
 static inline void
diff --git a/gcc/gimplify-me.c b/gcc/gimplify-me.c
index eca7681ff0d2..bb9b9141de56 100644
--- a/gcc/gimplify-me.c
+++ b/gcc/gimplify-me.c
@@ -316,10 +316,14 @@ gimple_regimplify_operands (gimple *stmt, 
gimple_stmt_iterator *gsi_p)
 
   pop_gimplify_context (NULL);
 
-  /* XXX some of the above transforms directly change gimple ops
-     instead of going through setters.  Once rewritten, update_stmt
-     isn't necessary.  */
+  /* The above uses direct pointer access to change operands, so we
+     need to reparse all operands.
+
+     It might look tempting to call gimplify_expr and an operand setter
+     only when !is_gimple_val (op) (or the other predicates).  That
+     doesn't work because DECLs might have DECL_VALUE_EXPR set,
+     which isn't checked by the predicates.  So we must always
+     invoke gimplify_expr on all operands and so can just as well
+     only update once at the end.  */
   update_stmt_for_real (stmt);
 }
-
-
diff --git a/gcc/ipa-split.c b/gcc/ipa-split.c
index 3d18f071e347..8712d04b2513 100644
--- a/gcc/ipa-split.c
+++ b/gcc/ipa-split.c
@@ -1356,13 +1356,13 @@ split_function (basic_block return_bb, struct 
split_point *split_point,
             gsi_next (&gsi))
          {
            gimple *stmt = gsi_stmt (gsi);
+           /* We are simple-minded and just rename the VOP if it's used. */
            if (gimple_vuse (stmt))
              {
-               gimple_set_vuse (stmt, NULL_TREE);
-               update_stmt_for_real (stmt); // XXX find better way to set vuse
+               gimple_set_vuse (stmt, gimple_vop (cfun));
+               mark_virtual_operands_for_renaming (cfun);
+               break;
              }
-           if (gimple_vdef (stmt))
-             break;
          }
     }
 
diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
index 7e737a4b4151..3ae4b5c0b3b9 100644
--- a/gcc/lto-streamer-in.c
+++ b/gcc/lto-streamer-in.c
@@ -1122,8 +1122,7 @@ input_function (tree fn_decl, struct data_in *data_in,
             we're not supposed to have debug stmts, remove them now.
             We can't remove them earlier because this would cause uid
             mismatches in fixups, but we can do it at this point, as
-            long as debug stmts don't require fixups.
-            Similarly remove all IFN_*SAN_* internal calls   */
+            long as debug stmts don't require fixups.  */
          if (!flag_wpa)
            {
              if (is_gimple_debug (stmt)
@@ -1131,54 +1130,6 @@ input_function (tree fn_decl, struct data_in *data_in,
                      ? !MAY_HAVE_DEBUG_MARKER_STMTS
                      : !MAY_HAVE_DEBUG_BIND_STMTS))
                remove = true;
-             if (is_gimple_call (stmt)
-                 && gimple_call_internal_p (stmt))
-               {
-                 bool replace = false;
-                 switch (gimple_call_internal_fn (stmt))
-                   {
-                   case IFN_UBSAN_NULL:
-                     if ((flag_sanitize
-                         & (SANITIZE_NULL | SANITIZE_ALIGNMENT)) == 0)
-                       replace = true;
-                     break;
-                   case IFN_UBSAN_BOUNDS:
-                     if ((flag_sanitize & SANITIZE_BOUNDS) == 0)
-                       replace = true;
-                     break;
-                   case IFN_UBSAN_VPTR:
-                     if ((flag_sanitize & SANITIZE_VPTR) == 0)
-                       replace = true;
-                     break;
-                   case IFN_UBSAN_OBJECT_SIZE:
-                     if ((flag_sanitize & SANITIZE_OBJECT_SIZE) == 0)
-                       replace = true;
-                     break;
-                   case IFN_UBSAN_PTR:
-                     if ((flag_sanitize & SANITIZE_POINTER_OVERFLOW) == 0)
-                       replace = true;
-                     break;
-                   case IFN_ASAN_MARK:
-                     if ((flag_sanitize & SANITIZE_ADDRESS) == 0)
-                       replace = true;
-                     break;
-                   case IFN_TSAN_FUNC_EXIT:
-                     if ((flag_sanitize & SANITIZE_THREAD) == 0)
-                       replace = true;
-                     break;
-                   default:
-                     break;
-                   }
-                 if (replace)
-                   {
-                     gimple_call_set_internal_fn (as_a <gcall *> (stmt),
-                                                  IFN_NOP);
-                     /* XXX replacing statement could also be done at
-                        read-in time (input_gimple_stmt), then this
-                        update wouldn't be needed.  */
-                     update_stmt_for_real (stmt);
-                   }
-               }
            }
          if (remove)
            {
diff --git a/gcc/omp-simd-clone.c b/gcc/omp-simd-clone.c
index 92a5fd8bc330..64cd91e3b391 100644
--- a/gcc/omp-simd-clone.c
+++ b/gcc/omp-simd-clone.c
@@ -882,15 +882,15 @@ ipa_simd_modify_stmt_ops (tree *tp, int *walk_subtrees, 
void *data)
        }
       gimple_stmt_iterator gsi = gsi_for_stmt (info->stmt);
       gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
-      *orig_tp = repl;
+      gimple_change_in_op (wi->stmt, wi->op_ptr, orig_tp, repl);
     }
   else if (!useless_type_conversion_p (TREE_TYPE (*tp), TREE_TYPE (repl)))
     {
       tree vce = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (*tp), repl);
-      *tp = vce;
+      gimple_change_in_op (wi->stmt, wi->op_ptr, tp, vce);
     }
   else
-    *tp = repl;
+    gimple_change_in_op (wi->stmt, wi->op_ptr, tp, repl);
 
   info->modified = true;
   return NULL_TREE;
@@ -1014,7 +1014,7 @@ ipa_simd_modify_function_body (struct cgraph_node *node,
            {
              /* XXX direct operand changes via walk_gimple_op make
                 this necessary:  */
-             update_stmt_for_real (stmt);
+             update_stmt (stmt);
              if (maybe_clean_eh_stmt (stmt))
                gimple_purge_dead_eh_edges (gimple_bb (stmt));
            }
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index fca7a2f7287b..5fe405506424 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -1976,6 +1976,11 @@ replace_uses_by (tree name, tree val)
 
   FOR_EACH_IMM_USE_STMT (stmt, imm_iter, name)
     {
+      int oldcf = 0;
+      gcall *call;
+      if ((call = dyn_cast <gcall *> (stmt)))
+       oldcf = gimple_call_flags (call);
+
       /* Mark the block if we change the last stmt in it.  */
       if (cfgcleanup_altered_bbs
          && stmt_ends_bb_p (stmt))
@@ -2028,7 +2033,14 @@ replace_uses_by (tree name, tree val)
          if (maybe_clean_or_replace_eh_stmt (orig_stmt, stmt))
            gimple_purge_dead_eh_edges (gimple_bb (stmt));
 
-         update_stmt (stmt);
+         /* SET_USE (within replace_exp) update all operand caches
+            and VOPs, except when we change the call target from e.g.
+            unknown to pure/const.  */
+         if ((call = dyn_cast <gcall *> (stmt))
+             && oldcf != gimple_call_flags (call))
+           update_stmt_for_real (stmt);
+         else
+           update_stmt (stmt);
        }
     }
 
diff --git a/gcc/tree-chkp-opt.c b/gcc/tree-chkp-opt.c
index df90016de5dc..5d39d525e775 100644
--- a/gcc/tree-chkp-opt.c
+++ b/gcc/tree-chkp-opt.c
@@ -28,6 +28,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple.h"
 #include "tree-pass.h"
 #include "ssa.h"
+#include "tree-into-ssa.h"
 #include "gimple-pretty-print.h"
 #include "diagnostic.h"
 #include "fold-const.h"
@@ -1215,7 +1216,7 @@ chkp_reduce_bounds_lifetime (void)
              || (dom_use && gimple_bb (dom_use) == bb))
            {
                  if (dump_file && (dump_flags & TDF_DETAILS))
-                   fprintf (dump_file, "Cannot move statement bacause there is 
no "
+                   fprintf (dump_file, "Cannot move statement because there is 
no "
                             "suitable dominator block other than entry 
block.\n");
 
                  gsi_next (&i);
@@ -1236,10 +1237,11 @@ chkp_reduce_bounds_lifetime (void)
                  gsi_move_before (&i, &gsi);
                }
 
-             gimple_set_vdef (stmt, NULL_TREE);
-             gimple_set_vuse (stmt, NULL_TREE);
-             /* XXX only needed to reset vops. */
-             update_stmt_for_real (stmt);
+             if (gimple_vuse (stmt))
+               {
+                 gimple_set_vuse (stmt, gimple_vop (cfun));
+                 mark_virtual_operands_for_renaming (cfun);
+               }
            }
        }
       else
diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c
index dd74294ff56f..31286868c34f 100644
--- a/gcc/tree-ssa-forwprop.c
+++ b/gcc/tree-ssa-forwprop.c
@@ -2463,8 +2463,6 @@ pass_forwprop::execute (function *fun)
                if (gimple_cond_true_p (cond)
                    || gimple_cond_false_p (cond))
                  cfg_changed = true;
-             /* XXX for_real only necessary with update_stmt_use??? 
-             update_stmt_for_real (stmt); */
              update_stmt (stmt);
            }
 
diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c
index 33f4b473c33c..3d5cfd02966c 100644
--- a/gcc/tree-ssa-operands.c
+++ b/gcc/tree-ssa-operands.c
@@ -1169,6 +1169,10 @@ update_stmt_use (use_operand_p use)
       gcc_assert (gimple_code (stmt) == GIMPLE_PHI);
       return;
     }
+  gcc_assert (is_gimple_debug (stmt)
+             || !USE_FROM_PTR (use)
+             || is_gimple_min_invariant (USE_FROM_PTR (use)));
+
   use_optype_p *puse, stmtuse;
   for (puse = &ops_stmt->use_ops; USE_OP_PTR (*puse) != use; puse = 
&((*puse)->next))
     ;
@@ -1209,11 +1213,19 @@ easy_stmt_p (gimple *stmt, unsigned i)
          return 2;
        /* Also, if we ignore the LHS or have none there can only be a
           vdef if the function isn't pure (or const).  */
-       if ((i == 0 || !gimple_call_lhs (stmt))
-           && !(call_flags & ECF_NOVOPS)
-           && (call_flags & (ECF_PURE | ECF_CONST)))
-         return 1;
-
+       if ((i == 0 || !gimple_call_lhs (stmt)) && !(call_flags & ECF_NOVOPS))
+           {
+             /* If it's pure we definitely need a vuse.  */
+             if ((call_flags & (ECF_PURE | ECF_CONST)) == ECF_PURE)
+               return 1;
+             /* If it's const and we have no arguments, or we ignore
+                the single argument (and hence have no LHS), then
+                there won't be a vop.  */
+             if ((call_flags & ECF_CONST)
+                 && (!gimple_call_num_args (stmt)
+                     || (gimple_call_num_args (stmt) == 1 && i == 3)))
+               return 0;
+           }
        return -1;
       }
 
@@ -1274,7 +1286,10 @@ diddle_vops (gimple *stmt, int oldvop, int newvop, 
unsigned nop)
     }
 
   if (newvop)
-    ensure_vop (stmt, newvop >= 2 ? opf_def : opf_use);
+    {
+      gcc_assert (!is_gimple_debug (stmt));
+      ensure_vop (stmt, newvop >= 2 ? opf_def : opf_use);
+    }
   else if (gimple_vuse (stmt))
     gimple_set_vuse (stmt, NULL_TREE);
 
@@ -1287,7 +1302,7 @@ add_ssa_op (gimple *stmt, tree *pop, tree val, unsigned 
nop, int flags)
   gimple_statement_with_ops *ops_stmt =
       dyn_cast <gimple_statement_with_ops *> (stmt);
   use_optype_p *puse = NULL;
-  int was_vop = 0;
+  int was_vop = 0, newvop;
   /* We'd like to search the cache only
        if (*pop && SSA_VAR_P (*pop))
      but we can't currently, because the list might contain stale entries
@@ -1303,8 +1318,20 @@ add_ssa_op (gimple *stmt, tree *pop, tree val, unsigned 
nop, int flags)
 
   /* If there's the danger that we replace the last operand that caused
      a vop with one that doesn't we need to revisit everything.  */
-  if (*pop && SSA_VAR_P (*pop) && !is_gimple_reg (*pop) && !virtual_operand_p 
(*pop))
+  if (!(flags & opf_no_vops) && *pop && SSA_VAR_P (*pop)
+      && !is_gimple_reg (*pop) && !virtual_operand_p (*pop))
     was_vop = (flags & opf_def) ? 2 : 1;
+  if (nop == 1 && gimple_code (stmt) == GIMPLE_CALL)
+    {
+      int call_flags = gimple_call_flags (stmt);
+      if (!(call_flags & ECF_NOVOPS))
+       {
+         if (!(call_flags & (ECF_PURE | ECF_CONST)))
+           was_vop = 2;
+         else if (!(call_flags & ECF_CONST))
+           was_vop = 1;
+       }
+    }
 
   *pop = val;
 
@@ -1354,7 +1381,19 @@ add_ssa_op (gimple *stmt, tree *pop, tree val, unsigned 
nop, int flags)
       gcc_assert (!val || is_gimple_min_invariant (val));
       if (puse && *puse)
        *puse = (*puse)->next;
-      if (was_vop && diddle_vops (stmt, was_vop, 0, nop) < 0)
+      newvop = 0;
+      if (nop == 1 && gimple_code (stmt) == GIMPLE_CALL)
+       {
+         int call_flags = gimple_call_flags (stmt);
+         if (!(call_flags & ECF_NOVOPS))
+           {
+             if (!(call_flags & (ECF_PURE | ECF_CONST)))
+               newvop = 2;
+             else if (!(call_flags & ECF_CONST))
+               newvop = 1;
+           }
+       }
+      if (was_vop && diddle_vops (stmt, was_vop, newvop, nop) < 0)
        return 1;
       /* And check for addresses in val.  */
       if (val && TREE_CODE (val) == ADDR_EXPR && !is_gimple_debug (stmt))
@@ -1371,6 +1410,11 @@ add_ssa_op (gimple *stmt, tree *pop, tree val, unsigned 
nop, int flags)
 static void
 ensure_vop (gimple *stmt, int flags)
 {
+  if (flags & opf_no_vops)
+    {
+      gcc_assert (!gimple_vuse (stmt));
+      return;
+    }
   if (flags & opf_def)
     {
       if (!gimple_vdef (stmt))
@@ -1406,11 +1450,13 @@ exchange_complex_op (gimple *stmt, tree *pop, tree val, 
unsigned nop, int flags)
   int oldvop, newvop;
 
   start_ssa_stmt_operands ();
-  get_expr_operands (cfun, stmt, pop, flags);
+  get_expr_operands (cfun, stmt, gimple_op_ptr (stmt, nop), flags);
+  if (nop == 1 && gimple_code (stmt) == GIMPLE_CALL)
+    maybe_add_call_vops (cfun, as_a <gcall *> (stmt));
   was_volatile = !!(build_flags & BF_VOLATILE);
   oldvop = build_vdef ? 2 : build_vuse ? 1 : 0;
 
-  /* Remove all use ops for things in *pop.  */
+  /* Remove all use ops for things in op[nop].  */
   for (i = 0; i < build_uses.length (); i++)
     {
       tree *op = build_uses[i];
@@ -1441,7 +1487,9 @@ exchange_complex_op (gimple *stmt, tree *pop, tree val, 
unsigned nop, int flags)
 
   /* Now inspect the new value.  */
   start_ssa_stmt_operands ();
-  get_expr_operands (cfun, stmt, pop, flags);
+  get_expr_operands (cfun, stmt, gimple_op_ptr (stmt, nop), flags);
+  if (nop == 1 && gimple_code (stmt) == GIMPLE_CALL)
+    maybe_add_call_vops (cfun, as_a <gcall *> (stmt));
   newvop = build_vdef ? 2 : build_vuse ? 1 : 0;
 
   /* If the op was volatile and now isn't we need to recheck everything.  */
@@ -1452,7 +1500,10 @@ exchange_complex_op (gimple *stmt, tree *pop, tree val, 
unsigned nop, int flags)
     }
 
   if (diddle_vops (stmt, oldvop, newvop, nop) < 0)
-    return 1;
+    {
+      cleanup_build_arrays ();
+      return 1;
+    }
 
   for (i = 0; i < build_uses.length (); i++)
     {
@@ -1577,6 +1628,48 @@ do_full_update:
     }
 }
 
+void
+gimple_change_in_op (gimple *gs, tree *op_ptr, tree *pop, tree val)
+{
+  unsigned i = op_ptr - gimple_op_ptr (gs, 0);
+  gcc_assert (i < gimple_num_ops (gs));
+  if (!flag_try_patch || !gs->bb || !ssa_operands_active (cfun))
+    *pop = val;
+  else
+    {
+      tree old = *pop;
+      if (gimple_code (gs) != GIMPLE_ASM)
+       {
+         if (gimple_code (gs) != GIMPLE_DEBUG
+             /* GIMPLE_DEBUG only has opcache for debug_bind and operand 1! .*/
+             || (gimple_debug_bind_p (gs) && i == 1))
+           {
+             int flags = opf_use;
+             if (i == 0 && (is_gimple_assign (gs) || is_gimple_call (gs)))
+               flags = opf_def;
+             if (gimple_code (gs) == GIMPLE_DEBUG)
+               flags |= opf_no_vops;
+             if (exchange_complex_op (gs, pop, val, i, flags))
+               goto do_full_update;
+           }
+         else
+           *pop = val;
+       }
+      else
+       {
+         *pop = val;
+do_full_update:
+         fprintf (stderr, " YYY replace ");
+         print_generic_expr (stderr, old, TDF_VOPS|TDF_MEMSYMS);
+         fprintf (stderr, " with ");
+         print_generic_expr (stderr, val, TDF_VOPS|TDF_MEMSYMS);
+         fprintf (stderr, " in ");
+         print_gimple_stmt (stderr, gs, 0, 0);
+         update_stmt_for_real (gs);
+       }
+    }
+}
+
 /* Swap operands EXP0 and EXP1 in statement STMT.  No attempt is done
    to test the validity of the swap operation.  */
 
diff --git a/gcc/value-prof.c b/gcc/value-prof.c
index d6ac350e4ca1..84c6ec6f5632 100644
--- a/gcc/value-prof.c
+++ b/gcc/value-prof.c
@@ -26,6 +26,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple.h"
 #include "cfghooks.h"
 #include "ssa.h"
+#include "tree-into-ssa.h"
 #include "cgraph.h"
 #include "coverage.h"
 #include "data-streamer.h"
@@ -1334,10 +1335,10 @@ gimple_ic (gcall *icall_stmt, struct cgraph_node 
*direct_call,
       unlink_stmt_vdef (icall_stmt);
       release_ssa_name (gimple_vdef (icall_stmt));
     }
-  gimple_set_vdef (icall_stmt, NULL_TREE);
-  gimple_set_vuse (icall_stmt, NULL_TREE);
-  /* XXX only needed to reset vops. */
-  update_stmt_for_real (icall_stmt);
+  gimple_set_vdef (icall_stmt, gimple_vop (cfun));
+  gimple_set_vuse (icall_stmt, gimple_vop (cfun));
+  mark_virtual_operands_for_renaming (cfun);
+  update_stmt (icall_stmt);
   dcall_stmt = as_a <gcall *> (gimple_copy (icall_stmt));
   gimple_call_set_fndecl (dcall_stmt, direct_call->decl);
   dflags = flags_from_decl_or_type (direct_call->decl);
@@ -1421,10 +1422,9 @@ gimple_ic (gcall *icall_stmt, struct cgraph_node 
*direct_call,
                  unlink_stmt_vdef (iretbnd_stmt);
                  release_ssa_name (gimple_vdef (iretbnd_stmt));
                }
-             gimple_set_vdef (iretbnd_stmt, NULL_TREE);
-             gimple_set_vuse (iretbnd_stmt, NULL_TREE);
-             /* XXX only needed to reset vops. */
-             update_stmt_for_real (iretbnd_stmt);
+             gimple_set_vdef (iretbnd_stmt, gimple_vop (cfun));
+             gimple_set_vuse (iretbnd_stmt, gimple_vop (cfun));
+             update_stmt (iretbnd_stmt);
 
              result = gimple_call_lhs (iretbnd_stmt);
              phi = create_phi_node (result, join_bb);
@@ -1655,10 +1655,9 @@ gimple_stringop_fixed_value (gcall *vcall_stmt, tree 
icall_size, profile_probabi
       unlink_stmt_vdef (vcall_stmt);
       release_ssa_name (gimple_vdef (vcall_stmt));
     }
-  gimple_set_vdef (vcall_stmt, NULL);
-  gimple_set_vuse (vcall_stmt, NULL);
-  /* XXX only needed to reset vops. */
-  update_stmt_for_real (vcall_stmt);
+  gimple_set_vdef (vcall_stmt, gimple_vop (cfun));
+  gimple_set_vuse (vcall_stmt, gimple_vop (cfun));
+  update_stmt (vcall_stmt);
   icall_stmt = as_a <gcall *> (gimple_copy (vcall_stmt));
   gimple_call_set_arg (icall_stmt, size_arg,
                       fold_convert (optype, icall_size));

Reply via email to