]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/tree-ssa-operands.c
c++: Handle multiple aggregate overloads [PR95319].
[thirdparty/gcc.git] / gcc / tree-ssa-operands.c
index c068a65c23c24fcd80218e46a4f6ee7b57908832..f4716d0e36fae857b8a46076814f8d965abd52de 100644 (file)
@@ -1,5 +1,5 @@
 /* SSA operands management for trees.
-   Copyright (C) 2003-2014 Free Software Foundation, Inc.
+   Copyright (C) 2003-2020 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -20,37 +20,16 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
+#include "backend.h"
 #include "tree.h"
-#include "stmt.h"
-#include "print-tree.h"
-#include "flags.h"
-#include "hashtab.h"
-#include "hash-set.h"
-#include "vec.h"
-#include "machmode.h"
-#include "hard-reg-set.h"
-#include "input.h"
-#include "function.h"
-#include "gimple-pretty-print.h"
-#include "bitmap.h"
-#include "basic-block.h"
-#include "tree-ssa-alias.h"
-#include "internal-fn.h"
-#include "gimple-expr.h"
-#include "is-a.h"
 #include "gimple.h"
-#include "gimple-ssa.h"
-#include "tree-phinodes.h"
-#include "ssa-iterators.h"
-#include "stringpool.h"
-#include "tree-ssanames.h"
-#include "tree-inline.h"
 #include "timevar.h"
-#include "dumpfile.h"
-#include "timevar.h"
-#include "langhooks.h"
+#include "ssa.h"
+#include "gimple-pretty-print.h"
 #include "diagnostic-core.h"
+#include "stmt.h"
+#include "print-tree.h"
+#include "dumpfile.h"
 
 
 /* This file contains the code required to manage the operands cache of the
@@ -120,23 +99,111 @@ along with GCC; see the file COPYING3.  If not see
 /* Operand is having its address taken.  */
 #define opf_address_taken (1 << 5)
 
-/* Array for building all the use operands.  */
-static vec<tree> build_uses;
+/* Class containing temporary per-stmt state.  */
+
+class operands_scanner
+{
+  public:
+    operands_scanner (struct function *fun, gimple *statement)
+      {
+       build_vuse = NULL_TREE;
+       build_vdef = NULL_TREE;
+       fn = fun;
+       stmt = statement;
+      }
+
+    /* Create an operands cache for STMT.  */
+    void build_ssa_operands ();
+
+    /* Verifies SSA statement operands.  */
+    DEBUG_FUNCTION bool verify_ssa_operands ();
+
+  private:
+    /* Disable copy and assign of this class, as it may have problems with
+       build_uses vec.  */
+    DISABLE_COPY_AND_ASSIGN (operands_scanner);
+
+    /* Array for building all the use operands.  */
+    auto_vec<tree *, 16> build_uses;
+
+    /* The built VDEF operand.  */
+    tree build_vdef;
+
+    /* The built VUSE operand.  */
+    tree build_vuse;
+
+    /* Function which STMT belongs to.  */
+    struct function *fn;
+
+    /* Statement to work on.  */
+    gimple *stmt;
+
+    /* Takes elements from build_uses and turns them into use operands of STMT.  */
+    void finalize_ssa_uses ();
+
+    /* Clear the in_list bits and empty the build array for VDEFs and
+       VUSEs.  */
+    void cleanup_build_arrays ();
+
+    /* Finalize all the build vectors, fill the new ones into INFO.  */
+    void finalize_ssa_stmt_operands ();
+
+    /* Start the process of building up operands vectors in INFO.  */
+    void start_ssa_stmt_operands ();
 
-/* The built VDEF operand.  */
-static tree build_vdef;
+    /* Add USE_P to the list of pointers to operands.  */
+    void append_use (tree *use_p);
 
-/* The built VUSE operand.  */
-static tree build_vuse;
+    /* Add VAR to the set of variables that require a VDEF operator.  */
+    void append_vdef (tree var);
 
-/* Bitmap obstack for our datastructures that needs to survive across
-   compilations of multiple functions.  */
-static bitmap_obstack operands_bitmap_obstack;
+    /* Add VAR to the set of variables that require a VUSE operator.  */
+    void append_vuse (tree var);
 
-static void get_expr_operands (struct function *, gimple, tree *, int);
+    /* Add virtual operands for STMT.  FLAGS is as in get_expr_operands.  */
+    void add_virtual_operand (int flags);
 
-/* Number of functions with initialized ssa_operands.  */
-static int n_initialized = 0;
+
+    /* Add *VAR_P to the appropriate operand array for statement STMT.
+       FLAGS is as in get_expr_operands.  If *VAR_P is a GIMPLE register,
+       it will be added to the statement's real operands, otherwise it is
+       added to virtual operands.  */
+    void add_stmt_operand (tree *var_p, int flags);
+
+    /* A subroutine of get_expr_operands to handle MEM_REF.
+
+       STMT is the statement being processed, EXPR is the MEM_REF
+         that got us here.
+
+       FLAGS is as in get_expr_operands.  */
+    void get_mem_ref_operands (tree expr, int flags);
+
+    /* A subroutine of get_expr_operands to handle TARGET_MEM_REF.  */
+    void get_tmr_operands (tree expr, int flags);
+
+
+    /* If STMT is a call that may clobber globals and other symbols that
+       escape, add them to the VDEF/VUSE lists for it.  */
+    void maybe_add_call_vops (gcall *stmt);
+
+    /* Scan operands in the ASM_EXPR stmt referred to in INFO.  */
+    void get_asm_stmt_operands (gasm *stmt);
+
+
+    /* Recursively scan the expression pointed to by EXPR_P in statement
+       STMT.  FLAGS is one of the OPF_* constants modifying how to
+       interpret the operands found.  */
+    void get_expr_operands (tree *expr_p, int flags);
+
+    /* Parse STMT looking for operands.  When finished, the various
+       build_* operand vectors will have potential operands in them.  */
+    void parse_ssa_operands ();
+
+
+    /* Takes elements from build_defs and turns them into def operands of STMT.
+       TODO -- Make build_defs vec of tree *.  */
+    void finalize_ssa_defs ();
+};
 
 /* Accessor to tree-ssa-operands.c caches.  */
 static inline struct ssa_operands *
@@ -202,14 +269,6 @@ create_vop_var (struct function *fn)
 void
 init_ssa_operands (struct function *fn)
 {
-  if (!n_initialized++)
-    {
-      build_uses.create (10);
-      build_vuse = NULL_TREE;
-      build_vdef = NULL_TREE;
-      bitmap_obstack_initialize (&operands_bitmap_obstack);
-    }
-
   gcc_assert (gimple_ssa_operands (fn)->operand_memory == NULL);
   gimple_ssa_operands (fn)->operand_memory_index
      = gimple_ssa_operands (fn)->ssa_operand_mem_size;
@@ -226,13 +285,6 @@ fini_ssa_operands (struct function *fn)
 {
   struct ssa_operand_memory_d *ptr;
 
-  if (!--n_initialized)
-    {
-      build_uses.release ();
-      build_vdef = NULL_TREE;
-      build_vuse = NULL_TREE;
-    }
-
   gimple_ssa_operands (fn)->free_uses = NULL;
 
   while ((ptr = gimple_ssa_operands (fn)->operand_memory) != NULL)
@@ -244,9 +296,6 @@ fini_ssa_operands (struct function *fn)
 
   gimple_ssa_operands (fn)->ops_active = false;
 
-  if (!n_initialized)
-    bitmap_obstack_release (&operands_bitmap_obstack);
-
   fn->gimple_df->vop = NULL_TREE;
 }
 
@@ -319,7 +368,7 @@ alloc_use (struct function *fn)
 /* Adds OP to the list of uses of statement STMT after LAST.  */
 
 static inline use_optype_p
-add_use_op (struct function *fn, gimple stmt, tree *op, use_optype_p last)
+add_use_op (struct function *fn, gimple *stmt, tree *op, use_optype_p last)
 {
   use_optype_p new_use;
 
@@ -336,8 +385,8 @@ add_use_op (struct function *fn, gimple stmt, tree *op, use_optype_p last)
 /* Takes elements from build_defs and turns them into def operands of STMT.
    TODO -- Make build_defs vec of tree *.  */
 
-static inline void
-finalize_ssa_defs (struct function *fn, gimple stmt)
+inline void
+operands_scanner::finalize_ssa_defs ()
 {
   /* Pre-pend the vdef we may have built.  */
   if (build_vdef != NULL_TREE)
@@ -372,11 +421,10 @@ finalize_ssa_defs (struct function *fn, gimple stmt)
 }
 
 
-/* Takes elements from build_uses and turns them into use operands of STMT.
-   TODO -- Make build_uses vec of tree *.  */
+/* Takes elements from build_uses and turns them into use operands of STMT.  */
 
-static inline void
-finalize_ssa_uses (struct function *fn, gimple stmt)
+inline void
+operands_scanner::finalize_ssa_uses ()
 {
   unsigned new_i;
   struct use_optype_d new_list;
@@ -392,7 +440,7 @@ finalize_ssa_uses (struct function *fn, gimple stmt)
       if (oldvuse != (build_vuse != NULL_TREE
                      ? build_vuse : build_vdef))
        gimple_set_vuse (stmt, NULL_TREE);
-      build_uses.safe_insert (0, (tree)gimple_vuse_ptr (stmt));
+      build_uses.safe_insert (0, gimple_vuse_ptr (stmt));
     }
 
   new_list.next = NULL;
@@ -408,9 +456,10 @@ finalize_ssa_uses (struct function *fn, gimple stmt)
   /* If there is anything in the old list, free it.  */
   if (old_ops)
     {
-      for (ptr = old_ops; ptr; ptr = ptr->next)
+      for (ptr = old_ops; ptr->next; ptr = ptr->next)
        delink_imm_use (USE_OP_PTR (ptr));
-      old_ops->next = gimple_ssa_operands (fn)->free_uses;
+      delink_imm_use (USE_OP_PTR (ptr));
+      ptr->next = gimple_ssa_operands (fn)->free_uses;
       gimple_ssa_operands (fn)->free_uses = old_ops;
     }
 
@@ -427,7 +476,7 @@ finalize_ssa_uses (struct function *fn, gimple stmt)
   /* Now create nodes for all the new nodes.  */
   for (new_i = 0; new_i < build_uses.length (); new_i++)
     {
-      tree *op = (tree *) build_uses[new_i];
+      tree *op = build_uses[new_i];
       last = add_use_op (fn, stmt, op, last);
     }
 
@@ -439,8 +488,8 @@ finalize_ssa_uses (struct function *fn, gimple stmt)
 /* Clear the in_list bits and empty the build array for VDEFs and
    VUSEs.  */
 
-static inline void
-cleanup_build_arrays (void)
+inline void
+operands_scanner::cleanup_build_arrays ()
 {
   build_vdef = NULL_TREE;
   build_vuse = NULL_TREE;
@@ -450,19 +499,19 @@ cleanup_build_arrays (void)
 
 /* Finalize all the build vectors, fill the new ones into INFO.  */
 
-static inline void
-finalize_ssa_stmt_operands (struct function *fn, gimple stmt)
+inline void
+operands_scanner::finalize_ssa_stmt_operands ()
 {
-  finalize_ssa_defs (fn, stmt);
-  finalize_ssa_uses (fn, stmt);
+  finalize_ssa_defs ();
+  finalize_ssa_uses ();
   cleanup_build_arrays ();
 }
 
 
 /* Start the process of building up operands vectors in INFO.  */
 
-static inline void
-start_ssa_stmt_operands (void)
+inline void
+operands_scanner::start_ssa_stmt_operands ()
 {
   gcc_assert (build_uses.length () == 0);
   gcc_assert (build_vuse == NULL_TREE);
@@ -472,17 +521,17 @@ start_ssa_stmt_operands (void)
 
 /* Add USE_P to the list of pointers to operands.  */
 
-static inline void
-append_use (tree *use_p)
+inline void
+operands_scanner::append_use (tree *use_p)
 {
-  build_uses.safe_push ((tree) use_p);
+  build_uses.safe_push (use_p);
 }
 
 
 /* Add VAR to the set of variables that require a VDEF operator.  */
 
-static inline void
-append_vdef (tree var)
+inline void
+operands_scanner::append_vdef (tree var)
 {
   gcc_assert ((build_vdef == NULL_TREE
               || build_vdef == var)
@@ -496,8 +545,8 @@ append_vdef (tree var)
 
 /* Add VAR to the set of variables that require a VUSE operator.  */
 
-static inline void
-append_vuse (tree var)
+inline void
+operands_scanner::append_vuse (tree var)
 {
   gcc_assert (build_vuse == NULL_TREE
              || build_vuse == var);
@@ -507,9 +556,8 @@ append_vuse (tree var)
 
 /* Add virtual operands for STMT.  FLAGS is as in get_expr_operands.  */
 
-static void
-add_virtual_operand (struct function *fn,
-                    gimple stmt ATTRIBUTE_UNUSED, int flags)
+void
+operands_scanner::add_virtual_operand (int flags)
 {
   /* Add virtual operands to the stmt, unless the caller has specifically
      requested not to do that (used when adding operands inside an
@@ -531,12 +579,14 @@ add_virtual_operand (struct function *fn,
    it will be added to the statement's real operands, otherwise it is
    added to virtual operands.  */
 
-static void
-add_stmt_operand (struct function *fn, tree *var_p, gimple stmt, int flags)
+void
+operands_scanner::add_stmt_operand (tree *var_p, int flags)
 {
   tree var = *var_p;
 
-  gcc_assert (SSA_VAR_P (*var_p));
+  gcc_assert (SSA_VAR_P (*var_p)
+             || TREE_CODE (*var_p) == STRING_CST
+             || TREE_CODE (*var_p) == CONST_DECL);
 
   if (is_gimple_reg (var))
     {
@@ -556,7 +606,7 @@ add_stmt_operand (struct function *fn, tree *var_p, gimple stmt, int flags)
        gimple_set_has_volatile_ops (stmt, true);
 
       /* The variable is a memory access.  Add virtual operands.  */
-      add_virtual_operand (fn, stmt, flags);
+      add_virtual_operand (flags);
     }
 }
 
@@ -595,9 +645,8 @@ mark_address_taken (tree ref)
 
    FLAGS is as in get_expr_operands.  */
 
-static void
-get_mem_ref_operands (struct function *fn,
-                     gimple stmt, tree expr, int flags)
+void
+operands_scanner::get_mem_ref_operands (tree expr, int flags)
 {
   tree *pptr = &TREE_OPERAND (expr, 0);
 
@@ -606,10 +655,10 @@ get_mem_ref_operands (struct function *fn,
     gimple_set_has_volatile_ops (stmt, true);
 
   /* Add the VOP.  */
-  add_virtual_operand (fn, stmt, flags);
+  add_virtual_operand (flags);
 
   /* If requested, add a USE operand for the base pointer.  */
-  get_expr_operands (fn, stmt, pptr,
+  get_expr_operands (pptr,
                     opf_non_addressable | opf_use
                     | (flags & (opf_no_vops|opf_not_non_addressable)));
 }
@@ -617,30 +666,27 @@ get_mem_ref_operands (struct function *fn,
 
 /* A subroutine of get_expr_operands to handle TARGET_MEM_REF.  */
 
-static void
-get_tmr_operands (struct function *fn, gimple stmt, tree expr, int flags)
+void
+operands_scanner::get_tmr_operands(tree expr, int flags)
 {
   if (!(flags & opf_no_vops)
       && TREE_THIS_VOLATILE (expr))
     gimple_set_has_volatile_ops (stmt, true);
 
   /* First record the real operands.  */
-  get_expr_operands (fn, stmt,
-                    &TMR_BASE (expr), opf_use | (flags & opf_no_vops));
-  get_expr_operands (fn, stmt,
-                    &TMR_INDEX (expr), opf_use | (flags & opf_no_vops));
-  get_expr_operands (fn, stmt,
-                    &TMR_INDEX2 (expr), opf_use | (flags & opf_no_vops));
-
-  add_virtual_operand (fn, stmt, flags);
+  get_expr_operands (&TMR_BASE (expr), opf_use | (flags & opf_no_vops));
+  get_expr_operands (&TMR_INDEX (expr), opf_use | (flags & opf_no_vops));
+  get_expr_operands (&TMR_INDEX2 (expr), opf_use | (flags & opf_no_vops));
+
+  add_virtual_operand (flags);
 }
 
 
 /* If STMT is a call that may clobber globals and other symbols that
    escape, add them to the VDEF/VUSE lists for it.  */
 
-static void
-maybe_add_call_vops (struct function *fn, gimple stmt)
+void
+operands_scanner::maybe_add_call_vops (gcall *stmt)
 {
   int call_flags = gimple_call_flags (stmt);
 
@@ -651,17 +697,17 @@ maybe_add_call_vops (struct function *fn, gimple stmt)
     {
       /* A 'pure' or a 'const' function never call-clobbers anything.  */
       if (!(call_flags & (ECF_PURE | ECF_CONST)))
-       add_virtual_operand (fn, stmt, opf_def);
+       add_virtual_operand (opf_def);
       else if (!(call_flags & ECF_CONST))
-       add_virtual_operand (fn, stmt, opf_use);
+       add_virtual_operand (opf_use);
     }
 }
 
 
 /* Scan operands in the ASM_EXPR stmt referred to in INFO.  */
 
-static void
-get_asm_stmt_operands (struct function *fn, gimple stmt)
+void
+operands_scanner::get_asm_stmt_operands (gasm *stmt)
 {
   size_t i, noutputs;
   const char **oconstraints;
@@ -688,8 +734,7 @@ get_asm_stmt_operands (struct function *fn, gimple stmt)
       if (!allows_reg && allows_mem)
        mark_address_taken (TREE_VALUE (link));
 
-      get_expr_operands (fn, stmt,
-                        &TREE_VALUE (link), opf_def | opf_not_non_addressable);
+      get_expr_operands (&TREE_VALUE (link), opf_def | opf_not_non_addressable);
     }
 
   /* Gather all input operands.  */
@@ -705,12 +750,12 @@ get_asm_stmt_operands (struct function *fn, gimple stmt)
       if (!allows_reg && allows_mem)
        mark_address_taken (TREE_VALUE (link));
 
-      get_expr_operands (fn, stmt, &TREE_VALUE (link), opf_not_non_addressable);
+      get_expr_operands (&TREE_VALUE (link), opf_not_non_addressable);
     }
 
   /* Clobber all memory and addressable symbols for asm ("" : : : "memory");  */
   if (gimple_asm_clobbers_memory_p (stmt))
-    add_virtual_operand (fn, stmt, opf_def);
+    add_virtual_operand (opf_def);
 }
 
 
@@ -718,8 +763,8 @@ get_asm_stmt_operands (struct function *fn, gimple stmt)
    STMT.  FLAGS is one of the OPF_* constants modifying how to
    interpret the operands found.  */
 
-static void
-get_expr_operands (struct function *fn, gimple stmt, tree *expr_p, int flags)
+void
+operands_scanner::get_expr_operands (tree *expr_p, int flags)
 {
   enum tree_code code;
   enum tree_code_class codeclass;
@@ -753,7 +798,7 @@ get_expr_operands (struct function *fn, gimple stmt, tree *expr_p, int flags)
         here are ARRAY_REF indices which will always be real operands
         (GIMPLE does not allow non-registers as array indices).  */
       flags |= opf_no_vops;
-      get_expr_operands (fn, stmt, &TREE_OPERAND (expr, 0),
+      get_expr_operands (&TREE_OPERAND (expr, 0),
                         flags | opf_not_non_addressable | opf_address_taken);
       return;
 
@@ -761,8 +806,10 @@ get_expr_operands (struct function *fn, gimple stmt, tree *expr_p, int flags)
     case VAR_DECL:
     case PARM_DECL:
     case RESULT_DECL:
+    case STRING_CST:
+    case CONST_DECL:
       if (!(flags & opf_address_taken))
-       add_stmt_operand (fn, expr_p, stmt, flags);
+       add_stmt_operand (expr_p, flags);
       return;
 
     case DEBUG_EXPR_DECL:
@@ -770,11 +817,11 @@ get_expr_operands (struct function *fn, gimple stmt, tree *expr_p, int flags)
       return;
 
     case MEM_REF:
-      get_mem_ref_operands (fn, stmt, expr, flags);
+      get_mem_ref_operands (expr, flags);
       return;
 
     case TARGET_MEM_REF:
-      get_tmr_operands (fn, stmt, expr, flags);
+      get_tmr_operands (expr, flags);
       return;
 
     case ARRAY_REF:
@@ -787,20 +834,20 @@ get_expr_operands (struct function *fn, gimple stmt, tree *expr_p, int flags)
            && TREE_THIS_VOLATILE (expr))
          gimple_set_has_volatile_ops (stmt, true);
 
-       get_expr_operands (fn, stmt, &TREE_OPERAND (expr, 0), flags);
+       get_expr_operands (&TREE_OPERAND (expr, 0), flags);
 
        if (code == COMPONENT_REF)
          {
            if (!(flags & opf_no_vops)
                && TREE_THIS_VOLATILE (TREE_OPERAND (expr, 1)))
              gimple_set_has_volatile_ops (stmt, true);
-           get_expr_operands (fn, stmt, &TREE_OPERAND (expr, 2), uflags);
+           get_expr_operands (&TREE_OPERAND (expr, 2), uflags);
          }
        else if (code == ARRAY_REF || code == ARRAY_RANGE_REF)
          {
-            get_expr_operands (fn, stmt, &TREE_OPERAND (expr, 1), uflags);
-            get_expr_operands (fn, stmt, &TREE_OPERAND (expr, 2), uflags);
-            get_expr_operands (fn, stmt, &TREE_OPERAND (expr, 3), uflags);
+           get_expr_operands (&TREE_OPERAND (expr, 1), uflags);
+           get_expr_operands (&TREE_OPERAND (expr, 2), uflags);
+           get_expr_operands (&TREE_OPERAND (expr, 3), uflags);
          }
 
        return;
@@ -809,16 +856,16 @@ get_expr_operands (struct function *fn, gimple stmt, tree *expr_p, int flags)
     case WITH_SIZE_EXPR:
       /* WITH_SIZE_EXPR is a pass-through reference to its first argument,
         and an rvalue reference to its second argument.  */
-      get_expr_operands (fn, stmt, &TREE_OPERAND (expr, 1), uflags);
-      get_expr_operands (fn, stmt, &TREE_OPERAND (expr, 0), flags);
+      get_expr_operands (&TREE_OPERAND (expr, 1), uflags);
+      get_expr_operands (&TREE_OPERAND (expr, 0), flags);
       return;
 
     case COND_EXPR:
     case VEC_COND_EXPR:
     case VEC_PERM_EXPR:
-      get_expr_operands (fn, stmt, &TREE_OPERAND (expr, 0), uflags);
-      get_expr_operands (fn, stmt, &TREE_OPERAND (expr, 1), uflags);
-      get_expr_operands (fn, stmt, &TREE_OPERAND (expr, 2), uflags);
+      get_expr_operands (&TREE_OPERAND (expr, 0), uflags);
+      get_expr_operands (&TREE_OPERAND (expr, 1), uflags);
+      get_expr_operands (&TREE_OPERAND (expr, 2), uflags);
       return;
 
     case CONSTRUCTOR:
@@ -838,7 +885,7 @@ get_expr_operands (struct function *fn, gimple stmt, tree *expr_p, int flags)
        for (idx = 0;
             vec_safe_iterate (CONSTRUCTOR_ELTS (expr), idx, &ce);
             idx++)
-         get_expr_operands (fn, stmt, &ce->value, uflags);
+         get_expr_operands (&ce->value, uflags);
 
        return;
       }
@@ -851,16 +898,17 @@ get_expr_operands (struct function *fn, gimple stmt, tree *expr_p, int flags)
 
     case VIEW_CONVERT_EXPR:
     do_unary:
-      get_expr_operands (fn, stmt, &TREE_OPERAND (expr, 0), flags);
+      get_expr_operands (&TREE_OPERAND (expr, 0), flags);
       return;
 
+    case BIT_INSERT_EXPR:
     case COMPOUND_EXPR:
     case OBJ_TYPE_REF:
     case ASSERT_EXPR:
     do_binary:
       {
-       get_expr_operands (fn, stmt, &TREE_OPERAND (expr, 0), flags);
-       get_expr_operands (fn, stmt, &TREE_OPERAND (expr, 1), flags);
+       get_expr_operands (&TREE_OPERAND (expr, 0), flags);
+       get_expr_operands (&TREE_OPERAND (expr, 1), flags);
        return;
       }
 
@@ -869,17 +917,15 @@ get_expr_operands (struct function *fn, gimple stmt, tree *expr_p, int flags)
     case REALIGN_LOAD_EXPR:
     case WIDEN_MULT_PLUS_EXPR:
     case WIDEN_MULT_MINUS_EXPR:
-    case FMA_EXPR:
       {
-       get_expr_operands (fn, stmt, &TREE_OPERAND (expr, 0), flags);
-       get_expr_operands (fn, stmt, &TREE_OPERAND (expr, 1), flags);
-       get_expr_operands (fn, stmt, &TREE_OPERAND (expr, 2), flags);
+       get_expr_operands (&TREE_OPERAND (expr, 0), flags);
+       get_expr_operands (&TREE_OPERAND (expr, 1), flags);
+       get_expr_operands (&TREE_OPERAND (expr, 2), flags);
        return;
       }
 
     case FUNCTION_DECL:
     case LABEL_DECL:
-    case CONST_DECL:
     case CASE_LABEL_EXPR:
       /* Expressions that make no memory references.  */
       return;
@@ -894,20 +940,21 @@ get_expr_operands (struct function *fn, gimple stmt, tree *expr_p, int flags)
     }
 
   /* If we get here, something has gone wrong.  */
-#ifdef ENABLE_CHECKING
-  fprintf (stderr, "unhandled expression in get_expr_operands():\n");
-  debug_tree (expr);
-  fputs ("\n", stderr);
-#endif
-  gcc_unreachable ();
+  if (flag_checking)
+    {
+      fprintf (stderr, "unhandled expression in get_expr_operands():\n");
+      debug_tree (expr);
+      fputs ("\n", stderr);
+      gcc_unreachable ();
+    }
 }
 
 
 /* Parse STMT looking for operands.  When finished, the various
    build_* operand vectors will have potential operands in them.  */
 
-static void
-parse_ssa_operands (struct function *fn, gimple stmt)
+void
+operands_scanner::parse_ssa_operands ()
 {
   enum gimple_code code = gimple_code (stmt);
   size_t i, n, start = 0;
@@ -915,18 +962,18 @@ parse_ssa_operands (struct function *fn, gimple stmt)
   switch (code)
     {
     case GIMPLE_ASM:
-      get_asm_stmt_operands (fn, stmt);
+      get_asm_stmt_operands (as_a <gasm *> (stmt));
       break;
 
     case GIMPLE_TRANSACTION:
       /* The start of a transaction is a memory barrier.  */
-      add_virtual_operand (fn, stmt, opf_def | opf_use);
+      add_virtual_operand (opf_def | opf_use);
       break;
 
     case GIMPLE_DEBUG:
       if (gimple_debug_bind_p (stmt)
          && gimple_debug_bind_has_value_p (stmt))
-       get_expr_operands (fn, stmt, gimple_debug_bind_get_value_ptr (stmt),
+       get_expr_operands (gimple_debug_bind_get_value_ptr (stmt),
                           opf_use | opf_no_vops);
       break;
 
@@ -936,11 +983,11 @@ parse_ssa_operands (struct function *fn, gimple stmt)
 
     case GIMPLE_CALL:
       /* Add call-clobbered operands, if needed.  */
-      maybe_add_call_vops (fn, stmt);
+      maybe_add_call_vops (as_a <gcall *> (stmt));
       /* FALLTHRU */
 
     case GIMPLE_ASSIGN:
-      get_expr_operands (fn, stmt, gimple_op_ptr (stmt, 0), opf_def);
+      get_expr_operands (gimple_op_ptr (stmt, 0), opf_def);
       start = 1;
       /* FALLTHRU */
 
@@ -948,7 +995,7 @@ parse_ssa_operands (struct function *fn, gimple stmt)
     do_default:
       n = gimple_num_ops (stmt);
       for (i = start; i < n; i++)
-       get_expr_operands (fn, stmt, gimple_op_ptr (stmt, i), opf_use);
+       get_expr_operands (gimple_op_ptr (stmt, i), opf_use);
       break;
     }
 }
@@ -956,33 +1003,33 @@ parse_ssa_operands (struct function *fn, gimple stmt)
 
 /* Create an operands cache for STMT.  */
 
-static void
-build_ssa_operands (struct function *fn, gimple stmt)
+void
+operands_scanner::build_ssa_operands ()
 {
   /* Initially assume that the statement has no volatile operands.  */
   gimple_set_has_volatile_ops (stmt, false);
 
   start_ssa_stmt_operands ();
-  parse_ssa_operands (fn, stmt);
-  finalize_ssa_stmt_operands (fn, stmt);
+  parse_ssa_operands ();
+  finalize_ssa_stmt_operands ();
 }
 
 /* Verifies SSA statement operands.  */
 
 DEBUG_FUNCTION bool
-verify_ssa_operands (struct function *fn, gimple stmt)
+operands_scanner::verify_ssa_operands ()
 {
   use_operand_p use_p;
   def_operand_p def_p;
   ssa_op_iter iter;
   unsigned i;
-  tree use, def;
+  tree def;
   bool volatile_p = gimple_has_volatile_ops (stmt);
 
   /* build_ssa_operands w/o finalizing them.  */
   gimple_set_has_volatile_ops (stmt, false);
   start_ssa_stmt_operands ();
-  parse_ssa_operands (fn, stmt);
+  parse_ssa_operands ();
 
   /* Now verify the built operands are the same as present in STMT.  */
   def = gimple_vdef (stmt);
@@ -991,62 +1038,65 @@ verify_ssa_operands (struct function *fn, gimple stmt)
     def = SSA_NAME_VAR (def);
   if (build_vdef != def)
     {
-      error ("virtual definition of statement not up-to-date");
+      error ("virtual definition of statement not up to date");
       return true;
     }
   if (gimple_vdef (stmt)
       && ((def_p = gimple_vdef_op (stmt)) == NULL_DEF_OPERAND_P
          || DEF_FROM_PTR (def_p) != gimple_vdef (stmt)))
     {
-      error ("virtual def operand missing for stmt");
+      error ("virtual def operand missing for statement");
       return true;
     }
 
-  use = gimple_vuse (stmt);
+  tree use = gimple_vuse (stmt);
   if (use
       && TREE_CODE (use) == SSA_NAME)
     use = SSA_NAME_VAR (use);
   if (build_vuse != use)
     {
-      error ("virtual use of statement not up-to-date");
+      error ("virtual use of statement not up to date");
       return true;
     }
   if (gimple_vuse (stmt)
       && ((use_p = gimple_vuse_op (stmt)) == NULL_USE_OPERAND_P
          || USE_FROM_PTR (use_p) != gimple_vuse (stmt)))
     {
-      error ("virtual use operand missing for stmt");
+      error ("virtual use operand missing for statement");
       return true;
     }
 
   FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
     {
-      FOR_EACH_VEC_ELT (build_uses, i, use)
+      tree *op;
+      FOR_EACH_VEC_ELT (build_uses, i, op)
        {
-         if (use_p->use == (tree *)use)
+         if (use_p->use == op)
            {
-             build_uses[i] = NULL_TREE;
+             build_uses[i] = NULL;
              break;
            }
        }
       if (i == build_uses.length ())
        {
-         error ("excess use operand for stmt");
+         error ("excess use operand for statement");
          debug_generic_expr (USE_FROM_PTR (use_p));
          return true;
        }
     }
-  FOR_EACH_VEC_ELT (build_uses, i, use)
-    if (use != NULL_TREE)
+
+  tree *op;
+  FOR_EACH_VEC_ELT (build_uses, i, op)
+    if (op != NULL)
       {
-       error ("use operand missing for stmt");
-       debug_generic_expr (*(tree *)use);
+       error ("use operand missing for statement");
+       debug_generic_expr (*op);
        return true;
       }
 
   if (gimple_has_volatile_ops (stmt) != volatile_p)
     {
-      error ("stmt volatile flag not up-to-date");
+      error ("statement volatile flag not up to date");
       return true;
     }
 
@@ -1054,12 +1104,20 @@ verify_ssa_operands (struct function *fn, gimple stmt)
   return false;
 }
 
+/* Interface for external use.  */
+
+DEBUG_FUNCTION bool
+verify_ssa_operands (struct function *fn, gimple *stmt)
+{
+  return operands_scanner (fn, stmt).verify_ssa_operands ();
+}
+
 
 /* Releases the operands of STMT back to their freelists, and clears
    the stmt operand lists.  */
 
 void
-free_stmt_operands (struct function *fn, gimple stmt)
+free_stmt_operands (struct function *fn, gimple *stmt)
 {
   use_optype_p uses = gimple_use_ops (stmt), last_use;
 
@@ -1084,7 +1142,7 @@ free_stmt_operands (struct function *fn, gimple stmt)
 /* Get the operands of statement STMT.  */
 
 void
-update_stmt_operands (struct function *fn, gimple stmt)
+update_stmt_operands (struct function *fn, gimple *stmt)
 {
   /* If update_stmt_operands is called before SSA is initialized, do
      nothing.  */
@@ -1094,7 +1152,7 @@ update_stmt_operands (struct function *fn, gimple stmt)
   timevar_push (TV_TREE_OPS);
 
   gcc_assert (gimple_modified_p (stmt));
-  build_ssa_operands (fn, stmt);
+  operands_scanner (fn, stmt).build_ssa_operands ();
   gimple_set_modified (stmt, false);
 
   timevar_pop (TV_TREE_OPS);
@@ -1105,7 +1163,7 @@ update_stmt_operands (struct function *fn, gimple stmt)
    to test the validity of the swap operation.  */
 
 void
-swap_ssa_operands (gimple stmt, tree *exp0, tree *exp1)
+swap_ssa_operands (gimple *stmt, tree *exp0, tree *exp1)
 {
   tree op0, op1;
   op0 = *exp0;
@@ -1155,7 +1213,7 @@ DEBUG_FUNCTION bool
 verify_imm_links (FILE *f, tree var)
 {
   use_operand_p ptr, prev, list;
-  int count;
+  unsigned int count;
 
   gcc_assert (TREE_CODE (var) == SSA_NAME);
 
@@ -1173,20 +1231,31 @@ verify_imm_links (FILE *f, tree var)
   for (ptr = list->next; ptr != list; )
     {
       if (prev != ptr->prev)
-       goto error;
+       {
+         fprintf (f, "prev != ptr->prev\n");
+         goto error;
+       }
 
       if (ptr->use == NULL)
-       goto error; /* 2 roots, or SAFE guard node.  */
+       {
+         fprintf (f, "ptr->use == NULL\n");
+         goto error; /* 2 roots, or SAFE guard node.  */
+       }
       else if (*(ptr->use) != var)
-       goto error;
+       {
+         fprintf (f, "*(ptr->use) != var\n");
+         goto error;
+       }
 
       prev = ptr;
       ptr = ptr->next;
 
-      /* Avoid infinite loops.  50,000,000 uses probably indicates a
-        problem.  */
-      if (count++ > 50000000)
-       goto error;
+      count++;
+      if (count == 0)
+       {
+         fprintf (f, "number of immediate uses doesn't fit unsigned int\n");
+         goto error;
+       }
     }
 
   /* Verify list in the other direction.  */
@@ -1194,15 +1263,25 @@ verify_imm_links (FILE *f, tree var)
   for (ptr = list->prev; ptr != list; )
     {
       if (prev != ptr->next)
-       goto error;
+       {
+         fprintf (f, "prev != ptr->next\n");
+         goto error;
+       }
       prev = ptr;
       ptr = ptr->prev;
-      if (count-- < 0)
-       goto error;
+      if (count == 0)
+       {
+         fprintf (f, "count-- < 0\n");
+         goto error;
+       }
+      count--;
     }
 
   if (count != 0)
-    goto error;
+    {
+      fprintf (f, "count != 0\n");
+      goto error;
+    }
 
   return false;
 
@@ -1263,11 +1342,8 @@ dump_immediate_uses (FILE *file)
   unsigned int x;
 
   fprintf (file, "Immediate_uses: \n\n");
-  for (x = 1; x < num_ssa_names; x++)
+  FOR_EACH_SSA_NAME (x, var, cfun)
     {
-      var = ssa_name (x);
-      if (!var)
-        continue;
       dump_immediate_uses_for (file, var);
     }
 }
@@ -1294,11 +1370,11 @@ debug_immediate_uses_for (tree var)
 /* Unlink STMTs virtual definition from the IL by propagating its use.  */
 
 void
-unlink_stmt_vdef (gimple stmt)
+unlink_stmt_vdef (gimple *stmt)
 {
   use_operand_p use_p;
   imm_use_iterator iter;
-  gimple use_stmt;
+  gimple *use_stmt;
   tree vdef = gimple_vdef (stmt);
   tree vuse = gimple_vuse (stmt);
 
@@ -1316,33 +1392,17 @@ unlink_stmt_vdef (gimple stmt)
     SSA_NAME_OCCURS_IN_ABNORMAL_PHI (vuse) = 1;
 }
 
-
-/* Return true if the var whose chain of uses starts at PTR has no
-   nondebug uses.  */
-bool
-has_zero_uses_1 (const ssa_use_operand_t *head)
-{
-  const ssa_use_operand_t *ptr;
-
-  for (ptr = head->next; ptr != head; ptr = ptr->next)
-    if (!is_gimple_debug (USE_STMT (ptr)))
-      return false;
-
-  return true;
-}
-
-
 /* Return true if the var whose chain of uses starts at PTR has a
    single nondebug use.  Set USE_P and STMT to that single nondebug
    use, if so, or to NULL otherwise.  */
 bool
 single_imm_use_1 (const ssa_use_operand_t *head,
-                 use_operand_p *use_p, gimple *stmt)
+                 use_operand_p *use_p, gimple **stmt)
 {
   ssa_use_operand_t *ptr, *single_use = 0;
 
   for (ptr = head->next; ptr != head; ptr = ptr->next)
-    if (!is_gimple_debug (USE_STMT (ptr)))
+    if (USE_STMT(ptr) && !is_gimple_debug (USE_STMT (ptr)))
       {
        if (single_use)
          {
@@ -1360,3 +1420,4 @@ single_imm_use_1 (const ssa_use_operand_t *head,
 
   return single_use;
 }
+