This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[tuples][patch] Convert pass_fold_builtins to tuples and related fixes


This patch converts pass_fold_builtins to tuples and enables it,
removes some FIXMES and makes other minor corrections in
tree-ssa-ccp.c, and corrects several errors elsewhere revealed
during the development and testing of that work.

	* tree.h (fold_call_stmt, gimple_fold_builtin_snprintf_chk):
	Declare new functions.
	* builtins.c (fold_builtin_object_size): Disable call to
	compute_builtin_object_size, which has not been converted.
	(gimple_rewrite_call_expr, gimple_fold_builtin_sprintf_chk,
	gimple_fold_builtin_snprintf_chk, gimple_fold_builtin_varargs,
	fold_call_stmt): New functions.
	* tree-chrec.h (build_polynomial_chrec): Silence uninitialized
	variable warning.
	* tree-ssa-ccp.c (likely_value): Recognize additional cases
	of constant values.
	(surely_varying_stmt_p): Note that return statements are not
	interesting to CCP as they no longer contain assignments.
	(ccp_fold): Add missing spaces.
	(valid_gimple_call_p): New function.
	(get_maxval_strlen): Don't trip over unary operator.
	(ccp_fold_builtin): Use fold_call_stmt and
	gimple_fold_builtin_snprintf_chk.  Enable disabled
	call now that target has been converted for tuples.
	Add missing spaces.
	(move_ssa_defining_stmt_for_defs): New function.
	(update_call_from_tree): New function.
	(fold_gimple_call): Use update_call_from_tree.
	(fold_stmt_inplace): Assert that operand folding tree
	walk goes to completion, i.e., does not return non-null.
	(optimize_stack_restore, optimize_stdarg_builtin):
	Convert to tuples
	(convert_to_gimple_builtin): Removed.
	(gimplify_and_update_call_from_tree): New function.
	Replaces convert_to_gimple_builtin.
	(execute_fold_all_builtins): Convert to tuples.
	* tree-ssa-propagate.c (substitute_and_fold):
	Add comment regarding unused value of replaced_address.
	* gimple-iterator.c (update_modified_stmt): Moved to
	head of file to avoid a forward declaration.
	(update_modified_stmts): New function.
	(gsi_insert_seq_before_without_update,
	gsi_insert_before_without_update,
	gsi_insert_seq_after_without_update,
	gsi_insert_after_without_update): New functions.
	(gsi_insert_before, gsi_insert_seq_before,
	gsi_insert_after, gsi_insert_seq_after): Call the
	_without_update variants.
	* gimplify.c (gimplify_seq_add_stmt, gimplify_seq_add_seq):
	New functions.
	(gimple_pop_condition, gimplify_return_expr, gimplify_loop_expr,
	gimplify_switch_expr, gimplify_case_label_expr,
	gimplify_self_mod_expr, gimplify_call_expr,
	gimplify_modify_expr_to_memcpy, gimplify_modify_expr_to_memset,
	gimplify_init_ctor_eval_range, gimpllify_modify_expr_complex_part,
	gimplify_modify_expr, gimplify_asm_expr, gimplify_cleanup_point_expr,
	gimple_push_cleanup, gimplify_omp_parallel, gimplify_omp_atomic,
	gimplify_expr, gimplify_body, gimplify_function_tree): When adding
	to statement sequences in the gimplifier, do not update operands.
	* tree-dfa.c (find_new_referenced_vars): Convert to tuples.
	* tree-flow.h (find_new_referenced_vars): Declare with new signature.
	* gimple.h (gimple_return_set_retval): Add comment regarding
	inconsistent validation of GIMPLE_RETURN result.
	(gsi_insert_seq_before_without_update,
	gsi_insert_before_without_update,
	gsi_insert_seq_after_without_update,
	gsi_insert_after_without_update): Declare new functions.
	* passes.c (init_optimization_passes): Enable pass_fold_builtins.


Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(revision 133160)
+++ gcc/tree.h	(working copy)
@@ -4814,6 +4814,8 @@ extern tree build_va_arg_indirect_ref (t
 extern tree build_string_literal (int, const char *);
 extern rtx builtin_memset_read_str (void *, HOST_WIDE_INT, enum machine_mode);
 extern int get_pointer_alignment (tree, unsigned int);
+extern tree fold_call_stmt (gimple, bool);
+extern tree gimple_fold_builtin_snprintf_chk (gimple, tree, enum
built_in_function);

 /* In convert.c */
 extern tree strip_float_extensions (tree);
Index: gcc/builtins.c
===================================================================
--- gcc/builtins.c	(revision 133160)
+++ gcc/builtins.c	(working copy)
@@ -12154,6 +12154,8 @@ fold_builtin_object_size (tree ptr, tree
   if (TREE_SIDE_EFFECTS (ptr))
     return build_int_cst_type (size_type_node, object_size_type < 2 ? -1 : 0);

+  /* FIXME tuples.  */
+#if 0
   if (TREE_CODE (ptr) == ADDR_EXPR)
     ret = build_int_cstu (size_type_node,
 			  compute_builtin_object_size (ptr, object_size_type));
@@ -12170,6 +12172,9 @@ fold_builtin_object_size (tree ptr, tree
 					     ? -1 : 0))
 	ret = build_int_cstu (size_type_node, bytes);
     }
+#else
+  ret = NULL_TREE;
+#endif

   if (ret)
     {
@@ -13337,3 +13342,304 @@ do_mpfr_lgamma_r (tree arg, tree arg_sg,
   return result;
 }
 #endif
+
+/* FIXME tuples.
+   The functions below provide an alternate interface for folding
builtin function
+   calls presented as GIMPLE_CALL statements rather than as
CALL_EXPRs.  The folded
+   result is still expressed as a tree.  There is too much code duplication in
+   the handling of varargs functions, and a more intrusive
re-factoring would permit
+   better sharing of code between the tree and statement-based
versions of these
+   functions.  */
+
+/* Construct a new CALL_EXPR using the tail of the argument list of STMT
+   along with N new arguments specified as the "..." parameters.  SKIP
+   is the number of arguments in STMT to be omitted.  This function is used
+   to do varargs-to-varargs transformations.  */
+
+static tree
+gimple_rewrite_call_expr (gimple stmt, int skip, tree fndecl, int n, ...)
+{
+  int oldnargs = gimple_call_num_args (stmt);
+  int nargs = oldnargs - skip + n;
+  tree fntype = TREE_TYPE (fndecl);
+  tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
+  tree *buffer;
+  int i, j;
+  va_list ap;
+
+  buffer = alloca (nargs * sizeof (tree));
+  va_start (ap, n);
+  for (i = 0; i < n; i++)
+    buffer[i] = va_arg (ap, tree);
+  va_end (ap);
+  for (j = skip; j < oldnargs; j++, i++)
+    buffer[i] = gimple_call_arg (stmt, j);
+
+  return fold (build_call_array (TREE_TYPE (fntype), fn, nargs, buffer));
+}
+
+/* Fold a call STMT to __{,v}sprintf_chk.  Return NULL_TREE if
+   a normal call should be emitted rather than expanding the function
+   inline.  FCODE is either BUILT_IN_SPRINTF_CHK or BUILT_IN_VSPRINTF_CHK.  */
+
+static tree
+gimple_fold_builtin_sprintf_chk (gimple stmt, enum built_in_function fcode)
+{
+  tree dest, size, len, fn, fmt, flag;
+  const char *fmt_str;
+  int nargs = gimple_call_num_args (stmt);
+
+  /* Verify the required arguments in the original call.  */
+  if (nargs < 4)
+    return NULL_TREE;
+  dest = gimple_call_arg (stmt, 0);
+  if (!validate_arg (dest, POINTER_TYPE))
+    return NULL_TREE;
+  flag = gimple_call_arg (stmt, 1);
+  if (!validate_arg (flag, INTEGER_TYPE))
+    return NULL_TREE;
+  size = gimple_call_arg (stmt, 2);
+  if (!validate_arg (size, INTEGER_TYPE))
+    return NULL_TREE;
+  fmt = gimple_call_arg (stmt, 3);
+  if (!validate_arg (fmt, POINTER_TYPE))
+    return NULL_TREE;
+
+  if (! host_integerp (size, 1))
+    return NULL_TREE;
+
+  len = NULL_TREE;
+
+  if (!init_target_chars ())
+    return NULL_TREE;
+
+  /* Check whether the format is a literal string constant.  */
+  fmt_str = c_getstr (fmt);
+  if (fmt_str != NULL)
+    {
+      /* If the format doesn't contain % args or %%, we know the size.  */
+      if (strchr (fmt_str, target_percent) == 0)
+	{
+	  if (fcode != BUILT_IN_SPRINTF_CHK || nargs == 4)
+	    len = build_int_cstu (size_type_node, strlen (fmt_str));
+	}
+      /* If the format is "%s" and first ... argument is a string literal,
+	 we know the size too.  */
+      else if (fcode == BUILT_IN_SPRINTF_CHK
+	       && strcmp (fmt_str, target_percent_s) == 0)
+	{
+	  tree arg;
+
+	  if (nargs == 5)
+	    {
+	      arg = gimple_call_arg (stmt, 4);
+	      if (validate_arg (arg, POINTER_TYPE))
+		{
+		  len = c_strlen (arg, 1);
+		  if (! len || ! host_integerp (len, 1))
+		    len = NULL_TREE;
+		}
+	    }
+	}
+    }
+
+  if (! integer_all_onesp (size))
+    {
+      if (! len || ! tree_int_cst_lt (len, size))
+	return NULL_TREE;
+    }
+
+  /* Only convert __{,v}sprintf_chk to {,v}sprintf if flag is 0
+     or if format doesn't contain % chars or is "%s".  */
+  if (! integer_zerop (flag))
+    {
+      if (fmt_str == NULL)
+	return NULL_TREE;
+      if (strchr (fmt_str, target_percent) != NULL
+	  && strcmp (fmt_str, target_percent_s))
+	return NULL_TREE;
+    }
+
+  /* If __builtin_{,v}sprintf_chk is used, assume {,v}sprintf is available.  */
+  fn = built_in_decls[fcode == BUILT_IN_VSPRINTF_CHK
+		      ? BUILT_IN_VSPRINTF : BUILT_IN_SPRINTF];
+  if (!fn)
+    return NULL_TREE;
+
+  return gimple_rewrite_call_expr (stmt, 4, fn, 2, dest, fmt);
+}
+
+/* Fold a call STMT to {,v}snprintf.  Return NULL_TREE if
+   a normal call should be emitted rather than expanding the function
+   inline.  FCODE is either BUILT_IN_SNPRINTF_CHK or
+   BUILT_IN_VSNPRINTF_CHK.  If MAXLEN is not NULL, it is maximum length
+   passed as second argument.  */
+
+tree
+gimple_fold_builtin_snprintf_chk (gimple stmt, tree maxlen,
+                                  enum built_in_function fcode)
+{
+  tree dest, size, len, fn, fmt, flag;
+  const char *fmt_str;
+
+  /* Verify the required arguments in the original call.  */
+  if (gimple_call_num_args (stmt) < 5)
+    return NULL_TREE;
+  dest = gimple_call_arg (stmt, 0);
+  if (!validate_arg (dest, POINTER_TYPE))
+    return NULL_TREE;
+  len = gimple_call_arg (stmt, 1);
+  if (!validate_arg (len, INTEGER_TYPE))
+    return NULL_TREE;
+  flag = gimple_call_arg (stmt, 2);
+  if (!validate_arg (flag, INTEGER_TYPE))
+    return NULL_TREE;
+  size = gimple_call_arg (stmt, 3);
+  if (!validate_arg (size, INTEGER_TYPE))
+    return NULL_TREE;
+  fmt = gimple_call_arg (stmt, 4);
+  if (!validate_arg (fmt, POINTER_TYPE))
+    return NULL_TREE;
+
+  if (! host_integerp (size, 1))
+    return NULL_TREE;
+
+  if (! integer_all_onesp (size))
+    {
+      if (! host_integerp (len, 1))
+	{
+	  /* If LEN is not constant, try MAXLEN too.
+	     For MAXLEN only allow optimizing into non-_ocs function
+	     if SIZE is >= MAXLEN, never convert to __ocs_fail ().  */
+	  if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
+	    return NULL_TREE;
+	}
+      else
+	maxlen = len;
+
+      if (tree_int_cst_lt (size, maxlen))
+	return NULL_TREE;
+    }
+
+  if (!init_target_chars ())
+    return NULL_TREE;
+
+  /* Only convert __{,v}snprintf_chk to {,v}snprintf if flag is 0
+     or if format doesn't contain % chars or is "%s".  */
+  if (! integer_zerop (flag))
+    {
+      fmt_str = c_getstr (fmt);
+      if (fmt_str == NULL)
+	return NULL_TREE;
+      if (strchr (fmt_str, target_percent) != NULL
+	  && strcmp (fmt_str, target_percent_s))
+	return NULL_TREE;
+    }
+
+  /* If __builtin_{,v}snprintf_chk is used, assume {,v}snprintf is
+     available.  */
+  fn = built_in_decls[fcode == BUILT_IN_VSNPRINTF_CHK
+		      ? BUILT_IN_VSNPRINTF : BUILT_IN_SNPRINTF];
+  if (!fn)
+    return NULL_TREE;
+
+  return gimple_rewrite_call_expr (stmt, 5, fn, 3, dest, len, fmt);
+}
+
+/* Builtins with folding operations that operate on "..." arguments
+   need special handling; we need to store the arguments in a convenient
+   data structure before attempting any folding.  Fortunately there are
+   only a few builtins that fall into this category.  FNDECL is the
+   function, EXP is the CALL_EXPR for the call, and IGNORE is true if the
+   result of the function call is ignored.  */
+
+static tree
+gimple_fold_builtin_varargs (tree fndecl, gimple stmt, bool ignore
ATTRIBUTE_UNUSED)
+{
+  enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
+  tree ret = NULL_TREE;
+
+  switch (fcode)
+    {
+    case BUILT_IN_SPRINTF_CHK:
+    case BUILT_IN_VSPRINTF_CHK:
+      ret = gimple_fold_builtin_sprintf_chk (stmt, fcode);
+      break;
+
+    case BUILT_IN_SNPRINTF_CHK:
+    case BUILT_IN_VSNPRINTF_CHK:
+      ret = gimple_fold_builtin_snprintf_chk (stmt, NULL_TREE, fcode);
+
+    default:
+      break;
+    }
+  if (ret)
+    {
+      ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
+      TREE_NO_WARNING (ret) = 1;
+      return ret;
+    }
+  return NULL_TREE;
+}
+
+/* A wrapper function for builtin folding that prevents warnings for
+   "statement without effect" and the like, caused by removing the
+   call node earlier than the warning is generated.  */
+
+tree
+fold_call_stmt (gimple stmt, bool ignore)
+{
+  tree ret = NULL_TREE;
+  tree fndecl = gimple_call_fndecl (stmt);
+  if (fndecl
+      && TREE_CODE (fndecl) == FUNCTION_DECL
+      && DECL_BUILT_IN (fndecl)
+      /* FIXME tuples.  Do we need this?
+         Are we guaranteed that the arguments have been finalized
+         by the time we are in GIMPLE?  */
+      && true /* !CALL_EXPR_VA_ARG_PACK (exp) */ )
+    {
+      int nargs = gimple_call_num_args (stmt);
+
+      /* FIXME: Don't use a list in this interface.  */
+      if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
+        {
+          tree arglist = NULL_TREE;
+          int i;
+          for (i = nargs - 1; i >= 0; i--)
+            arglist = tree_cons (NULL_TREE, gimple_call_arg (stmt,
i), arglist);
+	  return targetm.fold_builtin (fndecl, arglist, ignore);
+        }
+      else
+	{
+	  if (nargs <= MAX_ARGS_TO_FOLD_BUILTIN)
+	    {
+              tree args[MAX_ARGS_TO_FOLD_BUILTIN];
+              int i;
+              for (i = 0; i < nargs; i++)
+                args[i] = gimple_call_arg (stmt, i);
+	      ret = fold_builtin_n (fndecl, args, nargs, ignore);
+	    }
+	  if (!ret)
+	    ret = gimple_fold_builtin_varargs (fndecl, stmt, ignore);
+	  if (ret)
+	    {
+	      /* Propagate location information from original call to
+		 expansion of builtin.  Otherwise things like
+		 maybe_emit_chk_warning, that operate on the expansion
+		 of a builtin, will use the wrong location information.  */
+	      if (gimple_has_location (stmt))
+                {
+		  tree realret = ret;
+		  if (TREE_CODE (ret) == NOP_EXPR)
+		    realret = TREE_OPERAND (ret, 0);
+		  if (CAN_HAVE_LOCATION_P (realret)
+		      && !EXPR_HAS_LOCATION (realret))
+		    SET_EXPR_LOCATION (realret, gimple_location (stmt));
+                }
+	      return ret;
+	    }
+	}
+    }
+  return NULL_TREE;
+}
Index: gcc/tree-chrec.h
===================================================================
--- gcc/tree-chrec.h	(revision 133160)
+++ gcc/tree-chrec.h	(working copy)
@@ -123,7 +123,7 @@ build_polynomial_chrec (unsigned loop_nu
 			tree left,
 			tree right)
 {
-  bool val;
+  bool val = false;  /* Silence warning.  */

   if (left == chrec_dont_know
       || right == chrec_dont_know)
Index: gcc/tree-ssa-ccp.c
===================================================================
--- gcc/tree-ssa-ccp.c	(revision 133160)
+++ gcc/tree-ssa-ccp.c	(working copy)
@@ -566,6 +566,15 @@ likely_value (gimple stmt)
       && is_gimple_min_invariant (gimple_assign_rhs1 (stmt)))
     return CONSTANT;

+  if (code == GIMPLE_COND
+      && is_gimple_min_invariant (gimple_cond_lhs (stmt))
+      && is_gimple_min_invariant (gimple_cond_rhs (stmt)))
+    return CONSTANT;
+
+  if (code == GIMPLE_SWITCH
+      && is_gimple_min_invariant (gimple_switch_index (stmt)))
+    return CONSTANT;
+
   /* Arrive here for more complex cases.  */

   has_constant_operand = false;
@@ -652,8 +661,6 @@ surely_varying_stmt_p (gimple stmt)
   /* Anything other than assignments and conditional jumps are not
      interesting for CCP.  */
   if (gimple_code (stmt) != GIMPLE_ASSIGN
-      && !(gimple_code (stmt) == GIMPLE_RETURN
-           && gimple_return_retval (stmt) != NULL_TREE)
       && (gimple_code (stmt) != GIMPLE_COND)
       && (gimple_code (stmt) != GIMPLE_SWITCH))
     return true;
@@ -991,7 +998,7 @@ ccp_fold (gimple stmt)
             }

           default:
-            gcc_unreachable();
+            gcc_unreachable ();
           }
       }
       break;
@@ -1000,7 +1007,7 @@ ccp_fold (gimple stmt)
       /* It may be possible to fold away calls to builtin functions if
          their arguments are constants.  At present, such folding will not
          be attempted, as likely_value classifies all calls as VARYING.  */
-      gcc_unreachable();
+      gcc_unreachable ();
       break;

     case GIMPLE_COND:
@@ -1043,7 +1050,7 @@ ccp_fold (gimple stmt)
       }

     default:
-      gcc_unreachable();
+      gcc_unreachable ();
     }
 }

@@ -2251,6 +2258,22 @@ valid_gimple_rhs_p (tree expr)
   return true;
 }

+static bool
+valid_gimple_call_p (tree expr)
+{
+  unsigned i, nargs;
+
+  if (TREE_CODE (expr) != CALL_EXPR)
+    return false;
+
+  nargs = call_expr_nargs (expr);
+  for (i = 0; i < nargs; i++)
+    if (! is_gimple_operand (CALL_EXPR_ARG (expr, i)))
+      return false;
+
+  return true;
+}
+
 /* For passing state through walk_tree into fold_stmt_r and its
    children.  */

@@ -2483,14 +2506,13 @@ get_maxval_strlen (tree arg, tree *lengt
     {
       case GIMPLE_ASSIGN:
 	{
-	  tree rhs;
-
 	  /* The RHS of the statement defining VAR must either have a
 	     constant length or come from another SSA_NAME with a constant
 	     length.  */
-          if (gimple_num_ops (def_stmt) == 2)
+          if (get_gimple_rhs_class (gimple_subcode (def_stmt))
+              == GIMPLE_SINGLE_RHS)
             {
-              rhs = gimple_assign_rhs1 (def_stmt);
+              tree rhs = gimple_assign_rhs1 (def_stmt);
               return get_maxval_strlen (rhs, length, visited, type);
             }
         }
@@ -2548,18 +2570,15 @@ ccp_fold_builtin (gimple stmt)

   ignore = (gimple_call_lhs (stmt) == NULL);

-  /* FIXME tuples.  */
-#if 0
   /* First try the generic builtin folder.  If that succeeds, return the
      result directly.  */
-  result = fold_call_expr (fn, ignore);
+  result = fold_call_stmt (stmt, ignore);
   if (result)
     {
       if (ignore)
 	STRIP_NOPS (result);
       return result;
     }
-#endif

   /* Ignore MD builtins.  */
   callee = gimple_call_fndecl (stmt);
@@ -2708,12 +2727,9 @@ ccp_fold_builtin (gimple stmt)

     case BUILT_IN_SNPRINTF_CHK:
     case BUILT_IN_VSNPRINTF_CHK:
-    /* FIXME tuples.  */
-#if 0
       if (val[1] && is_gimple_val (val[1]))
-	result = fold_builtin_snprintf_chk (fn, val[1],
-					    DECL_FUNCTION_CODE (callee));
-#endif
+	result = gimple_fold_builtin_snprintf_chk (stmt, val[1],
+                                                   DECL_FUNCTION_CODE
(callee));
       break;

     default:
@@ -2808,7 +2824,7 @@ fold_gimple_assign (gimple stmt)
       break;

     case GIMPLE_INVALID_RHS:
-      gcc_unreachable();
+      gcc_unreachable ();
     }

   return false;
@@ -2840,6 +2856,124 @@ fold_gimple_cond (gimple stmt)
   return false;
 }

+
+/* Make SSA names defined by OLD_STMT point to NEW_STMT
+   as their defining statement.  */
+
+static void
+move_ssa_defining_stmt_for_defs (gimple new_stmt, gimple old_stmt)
+{
+  tree var;
+  ssa_op_iter iter;
+
+  if (gimple_in_ssa_p (cfun))
+    {
+      /* Make defined SSA_NAMEs point to the new
+         statement as their definition.  */
+      FOR_EACH_SSA_TREE_OPERAND (var, old_stmt, iter, SSA_OP_ALL_DEFS)
+        {
+          if (TREE_CODE (var) == SSA_NAME)
+            SSA_NAME_DEF_STMT (var) = new_stmt;
+        }
+    }
+}
+
+
+/* Update a GIMPLE_CALL statement at iterator *SI_P to reflect the
+   value of EXPR, which is expected to be the result of folding the
+   call.  This can only be done if EXPR is a CALL_EXPR with valid
+   GIMPLE operands as arguments, or if it is a suitable RHS expression
+   for a GIMPLE_ASSIGN.  More complex expressions will require
+   gimplification, which will introduce addtional statements.  In this
+   event, no update is performed, and the function returns false.
+   Note that we cannot mutate a GIMPLE_CALL in-place, so we always
+   replace the statement at *SI_P with an entirely new statement.
+   The new statement need not be a call, e.g., if the original call
+   folded to a constant.  */
+
+static bool
+update_call_from_tree (gimple_stmt_iterator *si_p, tree expr)
+{
+  tree lhs;
+
+  gimple stmt = gsi_stmt (*si_p);
+
+  gcc_assert (gimple_code (stmt) == GIMPLE_CALL);
+
+  lhs = gimple_call_lhs (stmt);
+
+  if (valid_gimple_call_p (expr))
+    {
+      /* The call has simplified to another call.  */
+      tree fn = CALL_EXPR_FN (expr);
+      unsigned i;
+      unsigned nargs = call_expr_nargs (expr);
+      VEC(tree, gc) *args = NULL;
+      gimple new_stmt;
+
+      if (nargs > 0)
+        {
+          args = VEC_alloc (tree, gc, nargs);
+          VEC_safe_grow (tree, gc, args, nargs);
+
+          for (i = 0; i < nargs; i++)
+            VEC_replace (tree, args, i, CALL_EXPR_ARG (expr, i));
+        }
+
+      new_stmt = gimple_build_call_vec (fn, args);
+      gimple_call_set_lhs (new_stmt, lhs);
+      copy_virtual_operands (new_stmt, stmt);
+      move_ssa_defining_stmt_for_defs (new_stmt, stmt);
+      gimple_set_location (new_stmt, gimple_location (stmt));
+      gsi_replace (si_p, new_stmt, false);
+      return true;
+    }
+  else if (valid_gimple_rhs_p (expr))
+    {
+      gimple new_stmt;
+
+      /* The call has simplified to an expression
+         that cannot be represented as a GIMPLE_CALL. */
+      if (lhs)
+        {
+          /* A value is expected.
+             Introduce a new GIMPLE_ASSIGN statement.  */
+          STRIP_USELESS_TYPE_CONVERSION (expr);
+          new_stmt = gimple_build_assign (lhs, expr);
+          copy_virtual_operands (new_stmt, stmt);
+          move_ssa_defining_stmt_for_defs (new_stmt, stmt);
+        }
+      else if (!TREE_SIDE_EFFECTS (expr))
+        {
+          /* No value is expected, and EXPR has no effect.
+             Replace it with an empty statement.  */
+          new_stmt = gimple_build_nop ();
+        }
+      else
+        {
+          /* No value is expected, but EXPR has an effect,
+             e.g., it could be a reference to a volatile
+             variable.  Create an assignment statement
+             with a dummy (unused) lhs variable.  */
+          STRIP_USELESS_TYPE_CONVERSION (expr);
+          lhs = create_tmp_var (TREE_TYPE (expr), NULL);
+          new_stmt = gimple_build_assign (lhs, expr);
+          add_referenced_var (lhs);
+          lhs = make_ssa_name (lhs, new_stmt);
+          gimple_assign_set_lhs (new_stmt, lhs);
+          copy_virtual_operands (new_stmt, stmt);
+          move_ssa_defining_stmt_for_defs (new_stmt, stmt);
+        }
+      gimple_set_location (new_stmt, gimple_location (stmt));
+      gsi_replace (si_p, new_stmt, false);
+      return true;
+    }
+  else
+    /* The call simplified to an expression that is
+       not a valid GIMPLE RHS.  */
+    return false;
+}
+
 /* Attempt to fold a call statement referenced by the statement iterator GSI.
    The statement may be replaced by another statement, e.g., if the call
    simplifies to a constant value. Return true if any changes were made.
@@ -2858,33 +2992,8 @@ fold_gimple_call (gimple_stmt_iterator *
     {
       tree result = ccp_fold_builtin (stmt);

-      if (result) {
-        if (TREE_CODE (result) == CALL_EXPR)
-          {
-            /* FIXME tuples.  Replace statement with the new call.  */
-            return false;
-          }
-        else if (valid_gimple_rhs_p (result))
-          {
-            /* The call has simplified to an expression
-               that cannot be represented as a GIMPLE_CALL.
-               Introduce a new GIMPLE_ASSIGN statement.  */
-            gimple new_stmt;
-            tree lhs = gimple_call_lhs (stmt);
-
-            STRIP_USELESS_TYPE_CONVERSION (result);
-            new_stmt = gimple_build_assign (lhs, result);
-            gimple_set_location (new_stmt, gimple_location (stmt));
-            gsi_replace (gsi, new_stmt, false);
-            return true;
-          }
-        else
-          /* The call simplified to an expression that is
-             not a valid GIMPLE RHS.  */
-          return false;
-        }
-      else
-        return false;
+      if (result)
+        return update_call_from_tree (gsi, result);
     }
   else
     {
@@ -3014,7 +3123,7 @@ fold_stmt_inplace (gimple stmt)
      signal that the entire statement should be replaced with
      a call to _builtin_trap.  This functionality is currently
      disabled, as noted in a FIXME, and cannot be supported here.  */
-  walk_gimple_op (stmt, fold_stmt_r, &wi);
+  gcc_assert (!walk_gimple_op (stmt, fold_stmt_r, &wi));

   /* Fold the main computation performed by the statement.  */
   switch (gimple_code (stmt))
@@ -3033,9 +3142,6 @@ fold_stmt_inplace (gimple stmt)
   return changed;
 }

-/* FIXME tuples.  */
-#if 0
-
 /* Try to optimize out __builtin_stack_restore.  Optimize it out
    if there is another __builtin_stack_restore in the same basic
    block and no calls or ASM_EXPRs are in between, or if this block's
@@ -3043,108 +3149,109 @@ fold_stmt_inplace (gimple stmt)
    ASM_EXPRs after this __builtin_stack_restore.  */

 static tree
-optimize_stack_restore (basic_block bb, tree call, block_stmt_iterator i)
+optimize_stack_restore (gimple_stmt_iterator i)
 {
-  tree stack_save, stmt, callee;
+  tree callee, rhs;
+  gimple stmt, stack_save;
+  gimple_stmt_iterator stack_save_gsi;

-  if (TREE_CODE (call) != CALL_EXPR
-      || call_expr_nargs (call) != 1
-      || TREE_CODE (CALL_EXPR_ARG (call, 0)) != SSA_NAME
-      || !POINTER_TYPE_P (TREE_TYPE (CALL_EXPR_ARG (call, 0))))
-    return NULL_TREE;
+  basic_block bb = gsi_bb (i);
+  gimple call = gsi_stmt (i);

-  for (bsi_next (&i); !bsi_end_p (i); bsi_next (&i))
-    {
-      tree call;
+  if (gimple_code (call) != GIMPLE_CALL
+      || gimple_call_num_args (call) != 1
+      || TREE_CODE (gimple_call_arg (call, 0)) != SSA_NAME
+      || !POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, 0))))
+    return false;

-      stmt = bsi_stmt (i);
-      if (TREE_CODE (stmt) == ASM_EXPR)
-	return NULL_TREE;
-      call = get_call_expr_in (stmt);
-      if (call == NULL)
+  for (gsi_next (&i); !gsi_end_p (i); gsi_next (&i))
+    {
+      stmt = gsi_stmt (i);
+      if (gimple_code (stmt) == GIMPLE_ASM)
+	return false;
+      if (gimple_code (stmt) != GIMPLE_CALL)
 	continue;

-      callee = get_callee_fndecl (call);
+      callee = gimple_call_fndecl (stmt);
       if (!callee || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL)
-	return NULL_TREE;
+	return false;

       if (DECL_FUNCTION_CODE (callee) == BUILT_IN_STACK_RESTORE)
 	break;
     }

-  if (bsi_end_p (i)
+  if (gsi_end_p (i)
       && (! single_succ_p (bb)
 	  || single_succ_edge (bb)->dest != EXIT_BLOCK_PTR))
-    return NULL_TREE;
+    return false;

-  stack_save = SSA_NAME_DEF_STMT (CALL_EXPR_ARG (call, 0));
-  if (TREE_CODE (stack_save) != GIMPLE_MODIFY_STMT
-      || GIMPLE_STMT_OPERAND (stack_save, 0) != CALL_EXPR_ARG (call, 0)
-      || TREE_CODE (GIMPLE_STMT_OPERAND (stack_save, 1)) != CALL_EXPR
-      || tree_could_throw_p (stack_save)
-      || !has_single_use (CALL_EXPR_ARG (call, 0)))
-    return NULL_TREE;
+  stack_save = SSA_NAME_DEF_STMT (gimple_call_arg (call, 0));
+  if (gimple_code (stack_save) != GIMPLE_CALL
+      || gimple_call_lhs (stack_save) != gimple_call_arg (call, 0)
+      || stmt_could_throw_p (stack_save)
+      || !has_single_use (gimple_call_arg (call, 0)))
+    return false;

-  callee = get_callee_fndecl (GIMPLE_STMT_OPERAND (stack_save, 1));
+  callee = gimple_call_fndecl (stack_save);
   if (!callee
       || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL
       || DECL_FUNCTION_CODE (callee) != BUILT_IN_STACK_SAVE
-      || call_expr_nargs (GIMPLE_STMT_OPERAND (stack_save, 1)) != 0)
-    return NULL_TREE;
+      || gimple_call_num_args (stack_save) != 0)
+    return false;

-  stmt = stack_save;
-  push_stmt_changes (&stmt);
-  if (!set_rhs (&stmt,
-		build_int_cst (TREE_TYPE (CALL_EXPR_ARG (call, 0)), 0)))
+  stack_save_gsi = gsi_for_stmt (stack_save);
+  push_stmt_changes (gsi_stmt_ptr (&stack_save_gsi));
+  rhs = build_int_cst (TREE_TYPE (gimple_call_arg (call, 0)), 0);
+  if (!update_call_from_tree (&stack_save_gsi, rhs))
     {
-      discard_stmt_changes (&stmt);
+      discard_stmt_changes (gsi_stmt_ptr (&stack_save_gsi));
       return NULL_TREE;
     }
-  gcc_assert (stmt == stack_save);
-  pop_stmt_changes (&stmt);
+  pop_stmt_changes (gsi_stmt_ptr (&stack_save_gsi));

+  /* No effect, so the statement will be deleted.  */
   return integer_zero_node;
 }
-
+
 /* If va_list type is a simple pointer and nothing special is needed,
    optimize __builtin_va_start (&ap, 0) into ap = __builtin_next_arg (0),
    __builtin_va_end (&ap) out as NOP and __builtin_va_copy into a simple
    pointer assignment.  */

 static tree
-optimize_stdarg_builtin (tree call)
+optimize_stdarg_builtin (gimple call)
 {
   tree callee, lhs, rhs;
   bool va_list_simple_ptr;

-  if (TREE_CODE (call) != CALL_EXPR)
+  if (gimple_code (call) != GIMPLE_CALL)
     return NULL_TREE;

   va_list_simple_ptr = POINTER_TYPE_P (va_list_type_node)
 		       && (TREE_TYPE (va_list_type_node) == void_type_node
 			   || TREE_TYPE (va_list_type_node) == char_type_node);

-  callee = get_callee_fndecl (call);
+  callee = gimple_call_fndecl (call);
   switch (DECL_FUNCTION_CODE (callee))
     {
     case BUILT_IN_VA_START:
       if (!va_list_simple_ptr
 	  || targetm.expand_builtin_va_start != NULL
-	  || built_in_decls[BUILT_IN_NEXT_ARG] == NULL)
+          || built_in_decls[BUILT_IN_NEXT_ARG] == NULL)
 	return NULL_TREE;

-      if (call_expr_nargs (call) != 2)
+      if (gimple_call_num_args (call) != 2)
 	return NULL_TREE;

-      lhs = CALL_EXPR_ARG (call, 0);
+      lhs = gimple_call_arg (call, 0);
       if (!POINTER_TYPE_P (TREE_TYPE (lhs))
 	  || TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (lhs)))
 	     != TYPE_MAIN_VARIANT (va_list_type_node))
 	return NULL_TREE;
-
+
       lhs = build_fold_indirect_ref (lhs);
       rhs = build_call_expr (built_in_decls[BUILT_IN_NEXT_ARG],
-			     1, integer_zero_node);
+                             1, integer_zero_node);
       rhs = fold_convert (TREE_TYPE (lhs), rhs);
       return build2 (MODIFY_EXPR, TREE_TYPE (lhs), lhs, rhs);

@@ -3152,17 +3259,17 @@ optimize_stdarg_builtin (tree call)
       if (!va_list_simple_ptr)
 	return NULL_TREE;

-      if (call_expr_nargs (call) != 2)
+      if (gimple_call_num_args (call) != 2)
 	return NULL_TREE;

-      lhs = CALL_EXPR_ARG (call, 0);
+      lhs = gimple_call_arg (call, 0);
       if (!POINTER_TYPE_P (TREE_TYPE (lhs))
 	  || TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (lhs)))
 	     != TYPE_MAIN_VARIANT (va_list_type_node))
 	return NULL_TREE;

       lhs = build_fold_indirect_ref (lhs);
-      rhs = CALL_EXPR_ARG (call, 1);
+      rhs = gimple_call_arg (call, 1);
       if (TYPE_MAIN_VARIANT (TREE_TYPE (rhs))
 	  != TYPE_MAIN_VARIANT (va_list_type_node))
 	return NULL_TREE;
@@ -3171,52 +3278,72 @@ optimize_stdarg_builtin (tree call)
       return build2 (MODIFY_EXPR, TREE_TYPE (lhs), lhs, rhs);

     case BUILT_IN_VA_END:
+      /* No effect, so the statement will be deleted.  */
       return integer_zero_node;

     default:
       gcc_unreachable ();
     }
 }
-
+
 /* Convert EXPR into a GIMPLE value suitable for substitution on the
    RHS of an assignment.  Insert the necessary statements before
-   iterator *SI_P.
-   When IGNORE is set, don't worry about the return value.  */
+   iterator *SI_P.  The statement at *SI_P, which must be a GIMPLE_CALL
+   is replaced.  If the call is expected to produces a result, then it
+   is replaced by an assignment of the new RHS to the result variable.
+   If the result is to be ignored, then the call is replaced by a
+   GIMPLE_NOP.  */

-static tree
-convert_to_gimple_builtin (block_stmt_iterator *si_p, tree expr, bool ignore)
+static void
+gimplify_and_update_call_from_tree (gimple_stmt_iterator *si_p, tree expr)
 {
-  tree_stmt_iterator ti;
-  tree stmt = bsi_stmt (*si_p);
-  tree tmp, stmts = NULL;
+  tree lhs;
+  tree tmp = NULL_TREE;  /* Silence warning.  */
+  gimple stmt, new_stmt;
+  gimple_stmt_iterator i;
+  gimple_seq stmts = gimple_seq_alloc();
+
+  stmt = gsi_stmt (*si_p);
+
+  gcc_assert (gimple_code (stmt) == GIMPLE_CALL);
+
+  lhs = gimple_call_lhs (stmt);

   push_gimplify_context ();
-  if (ignore)
-    {
-      tmp = build_empty_stmt ();
-      gimplify_and_add (expr, &stmts);
-    }
-  else
+
+  if (lhs == NULL_TREE)
+    gimplify_and_add (expr, &stmts);
+  else
     tmp = get_initialized_tmp_var (expr, &stmts, NULL);
+
   pop_gimplify_context (NULL);

-  if (EXPR_HAS_LOCATION (stmt))
-    annotate_all_with_location (&stmts, EXPR_LOCATION (stmt));
+  if (gimple_has_location (stmt))
+    annotate_all_with_location (stmts, gimple_location (stmt));

   /* The replacement can expose previously unreferenced variables.  */
-  for (ti = tsi_start (stmts); !tsi_end_p (ti); tsi_next (&ti))
+  for (i = gsi_start (stmts); !gsi_end_p (i); gsi_next (&i))
+  {
+    new_stmt = gsi_stmt (i);
+    find_new_referenced_vars (&i);
+    gsi_insert_before (si_p, new_stmt, GSI_NEW_STMT);
+    mark_symbols_for_renaming (new_stmt);
+    gsi_next (si_p);
+  }
+
+  if (lhs == NULL_TREE)
+    new_stmt = gimple_build_nop ();
+  else
     {
-      tree new_stmt = tsi_stmt (ti);
-      find_new_referenced_vars (tsi_stmt_ptr (ti));
-      bsi_insert_before (si_p, new_stmt, BSI_NEW_STMT);
-      mark_symbols_for_renaming (new_stmt);
-      bsi_next (si_p);
+      new_stmt = gimple_build_assign (lhs, tmp);
+      copy_virtual_operands (new_stmt, stmt);
+      move_ssa_defining_stmt_for_defs (new_stmt, stmt);
     }

-  return tmp;
+  gimple_set_location (new_stmt, gimple_location (stmt));
+  gsi_replace (si_p, new_stmt, false);
 }

-
 /* A simple pass that attempts to fold all builtin functions.  This pass
    is run after we've propagated as many constants as we can.  */

@@ -3229,29 +3356,29 @@ execute_fold_all_builtins (void)

   FOR_EACH_BB (bb)
     {
-      block_stmt_iterator i;
-      for (i = bsi_start (bb); !bsi_end_p (i); )
+      gimple_stmt_iterator i;
+      for (i = gsi_start_bb (bb); !gsi_end_p (i); )
 	{
-	  tree *stmtp = bsi_stmt_ptr (i);
-	  tree old_stmt = *stmtp;
-	  tree call = get_rhs (*stmtp);
+          gimple stmt, old_stmt;
 	  tree callee, result;
 	  enum built_in_function fcode;

-	  if (!call || TREE_CODE (call) != CALL_EXPR)
+	  stmt = gsi_stmt (i);
+
+          if (gimple_code (stmt) != GIMPLE_CALL)
 	    {
-	      bsi_next (&i);
+	      gsi_next (&i);
 	      continue;
 	    }
-	  callee = get_callee_fndecl (call);
+	  callee = gimple_call_fndecl (stmt);
 	  if (!callee || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL)
 	    {
-	      bsi_next (&i);
+	      gsi_next (&i);
 	      continue;
 	    }
 	  fcode = DECL_FUNCTION_CODE (callee);

-	  result = ccp_fold_builtin (*stmtp, call);
+	  result = ccp_fold_builtin (stmt);
 	  if (!result)
 	    switch (DECL_FUNCTION_CODE (callee))
 	      {
@@ -3259,77 +3386,71 @@ execute_fold_all_builtins (void)
 		/* Resolve __builtin_constant_p.  If it hasn't been
 		   folded to integer_one_node by now, it's fairly
 		   certain that the value simply isn't constant.  */
-		result = integer_zero_node;
+                result = integer_zero_node;
 		break;

 	      case BUILT_IN_STACK_RESTORE:
-		result = optimize_stack_restore (bb, *stmtp, i);
+		result = optimize_stack_restore (i);
 		if (result)
 		  break;
-		bsi_next (&i);
+		gsi_next (&i);
 		continue;

 	      case BUILT_IN_VA_START:
 	      case BUILT_IN_VA_END:
 	      case BUILT_IN_VA_COPY:
 		/* These shouldn't be folded before pass_stdarg.  */
-		result = optimize_stdarg_builtin (*stmtp);
+		result = optimize_stdarg_builtin (stmt);
 		if (result)
 		  break;
 		/* FALLTHRU */

 	      default:
-		bsi_next (&i);
+		gsi_next (&i);
 		continue;
 	      }

 	  if (dump_file && (dump_flags & TDF_DETAILS))
 	    {
 	      fprintf (dump_file, "Simplified\n  ");
-	      print_generic_stmt (dump_file, *stmtp, dump_flags);
+	      print_gimple_stmt (dump_file, stmt, 0, dump_flags);
 	    }

-	  push_stmt_changes (stmtp);
+          old_stmt = stmt;
+	  push_stmt_changes (gsi_stmt_ptr (&i));

-	  if (!set_rhs (stmtp, result))
-	    {
-	      result = convert_to_gimple_builtin (&i, result,
-			      			  TREE_CODE (old_stmt)
-						  != GIMPLE_MODIFY_STMT);
-	      if (result)
-		{
-		  bool ok = set_rhs (stmtp, result);
-		  gcc_assert (ok);
-		  todoflags |= TODO_rebuild_alias;
-		}
-	    }
+          if (!update_call_from_tree (&i, result))
+            {
+              gimplify_and_update_call_from_tree (&i, result);
+              todoflags |= TODO_rebuild_alias;
+            }

-	  pop_stmt_changes (stmtp);
+	  stmt = gsi_stmt (i);
+	  pop_stmt_changes (gsi_stmt_ptr (&i));

-	  if (maybe_clean_or_replace_eh_stmt (old_stmt, *stmtp)
-	      && tree_purge_dead_eh_edges (bb))
+	  if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt)
+	      && gimple_purge_dead_eh_edges (bb))
 	    cfg_changed = true;

 	  if (dump_file && (dump_flags & TDF_DETAILS))
 	    {
 	      fprintf (dump_file, "to\n  ");
-	      print_generic_stmt (dump_file, *stmtp, dump_flags);
+	      print_gimple_stmt (dump_file, stmt, 0, dump_flags);
 	      fprintf (dump_file, "\n");
 	    }

 	  /* Retry the same statement if it changed into another
 	     builtin, there might be new opportunities now.  */
-	  call = get_rhs (*stmtp);
-	  if (!call || TREE_CODE (call) != CALL_EXPR)
+          if (gimple_code (stmt) != GIMPLE_CALL)
 	    {
-	      bsi_next (&i);
+	      gsi_next (&i);
 	      continue;
 	    }
-	  callee = get_callee_fndecl (call);
+	  callee = gimple_call_fndecl (stmt);
 	  if (!callee
-	      || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL
+              || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL
 	      || DECL_FUNCTION_CODE (callee) == fcode)
-	    bsi_next (&i);
+	    gsi_next (&i);
 	}
     }

@@ -3359,4 +3480,3 @@ struct tree_opt_pass pass_fold_builtins
     | TODO_update_ssa,			/* todo_flags_finish */
   0					/* letter */
 };
-#endif
Index: gcc/tree-ssa-propagate.c
===================================================================
--- gcc/tree-ssa-propagate.c	(revision 133160)
+++ gcc/tree-ssa-propagate.c	(working copy)
@@ -1183,6 +1183,7 @@ substitute_and_fold (prop_value_t *prop_
 	  if (use_ranges_p)
 	    did_replace = fold_predicate_in (stmt);

+          /* NOTE: The boolean variable REPLACED_ADDRESS is never used.  */
 	  if (prop_value)
 	    {
 	      /* Only replace real uses if we couldn't fold the
Index: gcc/gimple-iterator.c
===================================================================
--- gcc/gimple-iterator.c	(revision 133160)
+++ gcc/gimple-iterator.c	(working copy)
@@ -29,6 +29,31 @@ Boston, MA 02110-1301, USA.  */
 #include "value-prof.h"


+/* Mark the statement STMT as modified, and update it.  */
+
+static inline void
+update_modified_stmt (gimple stmt)
+{
+  if (!ssa_operands_active ())
+    return;
+  update_stmt_if_modified (stmt);
+}
+
+
+/* Mark the statements in SEQ as modified, and update them.  */
+
+static void
+update_modified_stmts (gimple_seq seq)
+{
+  gimple_stmt_iterator gsi;
+
+  if (!ssa_operands_active ())
+    return;
+  for (gsi = gsi_start (seq); !gsi_end_p (gsi); gsi_next (&gsi))
+    update_stmt_if_modified (gsi_stmt (gsi));
+}
+
+
 /* Set BB to be the basic block for all the statements in the list
    starting at FIRST and LAST.  */

@@ -108,11 +133,16 @@ gsi_insert_seq_nodes_before (gimple_stmt

 /* Inserts the sequence of statements SEQ before the statement pointed
    by iterator I.  MODE indicates what to do with the iterator after
-   insertion (see enum gsi_iterator_update).  */
+   insertion (see enum gsi_iterator_update).
+
+   This function does not scan for new operands.  It is provided for
+   the use of the gimplifier, which manipulates statements for which
+   def/use information has not yet been constructed.  Most callers
+   should use gsi_insert_seq_before.  */

 void
-gsi_insert_seq_before (gimple_stmt_iterator *i, gimple_seq seq,
-		       enum gsi_iterator_update mode)
+gsi_insert_seq_before_without_update (gimple_stmt_iterator *i, gimple_seq seq,
+                                      enum gsi_iterator_update mode)
 {
   gimple_seq_node first, last;

@@ -137,6 +167,20 @@ gsi_insert_seq_before (gimple_stmt_itera
 }


+/* Inserts the sequence of statements SEQ before the statement pointed
+   by iterator I.  MODE indicates what to do with the iterator after
+   insertion (see enum gsi_iterator_update). Scan the statements in SEQ
+   for new operands.  */
+
+void
+gsi_insert_seq_before (gimple_stmt_iterator *i, gimple_seq seq,
+		       enum gsi_iterator_update mode)
+{
+  update_modified_stmts (seq);
+  gsi_insert_seq_before_without_update (i, seq, mode);
+}
+
+
 /* Insert the sequence delimited by nodes FIRST and LAST after
    iterator I.  M specifies how to update iterator I after insertion
    (see enum gsi_iterator_update).
@@ -197,11 +241,16 @@ gsi_insert_seq_nodes_after (gimple_stmt_


 /* Links sequence SEQ after the statement pointed-to by iterator I.
-   MODE is as in gsi_insert_after.  */
+   MODE is as in gsi_insert_after.
+
+   This function does not scan for new operands.  It is provided for
+   the use of the gimplifier, which manipulates statements for which
+   def/use information has not yet been constructed.  Most callers
+   should use gsi_insert_seq_after.  */

 void
-gsi_insert_seq_after (gimple_stmt_iterator *i, gimple_seq seq,
-		      enum gsi_iterator_update mode)
+gsi_insert_seq_after_without_update (gimple_stmt_iterator *i, gimple_seq seq,
+                                     enum gsi_iterator_update mode)
 {
   gimple_seq_node first, last;

@@ -226,6 +275,19 @@ gsi_insert_seq_after (gimple_stmt_iterat
 }


+/* Links sequence SEQ after the statement pointed-to by iterator I.
+   MODE is as in gsi_insert_after.  Scan the statements in SEQ
+   for new operands.  */
+
+void
+gsi_insert_seq_after (gimple_stmt_iterator *i, gimple_seq seq,
+		      enum gsi_iterator_update mode)
+{
+  update_modified_stmts (seq);
+  gsi_insert_seq_after_without_update (i, seq, mode);
+}
+
+
 /* Move all statements in the sequence after I to a new sequence.
    Return this new sequence.  */

@@ -289,17 +351,6 @@ gsi_split_seq_before (gimple_stmt_iterat
 }


-/* Mark the statement T as modified, and update it.  */
-
-static inline void
-update_modified_stmt (gimple t)
-{
-  if (!ssa_operands_active ())
-    return;
-  update_stmt_if_modified (t);
-}
-
-
 /* Replace the statement pointed-to by GSI to STMT.  If UPDATE_EH_INFO
    is true, the exception handling information of the original
    statement is moved to the new statement.  */
@@ -337,18 +388,20 @@ gsi_replace (gimple_stmt_iterator *gsi,
 }


-/* Insert statement STMT before the statement pointed-to by iterator
-   I, update STMT's basic block and scan it for new operands.  M
-   specifies how to update iterator I after insertion (see enum
-   gsi_iterator_update).  */
+/* Insert statement STMT before the statement pointed-to by iterator I.
+   M specifies how to update iterator I after insertion (see enum
+   gsi_iterator_update).
+
+   This function does not scan for new operands.  It is provided for
+   the use of the gimplifier, which manipulates statements for which
+   def/use information has not yet been constructed.  Most callers
+   should use gsi_insert_before.  */

 void
-gsi_insert_before (gimple_stmt_iterator *i, gimple stmt,
-		   enum gsi_iterator_update m)
+gsi_insert_before_without_update (gimple_stmt_iterator *i, gimple stmt,
+                                  enum gsi_iterator_update m)
 {
   gimple_seq_node n;
-
-  update_modified_stmt (stmt);

   n = ggc_alloc (sizeof (*n));
   n->prev = n->next = NULL;
@@ -356,19 +409,34 @@ gsi_insert_before (gimple_stmt_iterator
   gsi_insert_seq_nodes_before (i, n, n, m);
 }

-
-/* Insert statement STMT after the statement pointed-to by iterator I,
-   update STMT's basic block and scan it for new operands.  M
+/* Insert statement STMT before the statement pointed-to by iterator I.
+   Update STMT's basic block and scan it for new operands.  M
    specifies how to update iterator I after insertion (see enum
    gsi_iterator_update).  */

 void
-gsi_insert_after (gimple_stmt_iterator *i, gimple stmt,
-		  enum gsi_iterator_update m)
+gsi_insert_before (gimple_stmt_iterator *i, gimple stmt,
+                   enum gsi_iterator_update m)
 {
-  gimple_seq_node n;
-
   update_modified_stmt (stmt);
+  gsi_insert_before_without_update (i, stmt, m);
+}
+
+
+/* Insert statement STMT after the statement pointed-to by iterator I.
+   M specifies how to update iterator I after insertion (see enum
+   gsi_iterator_update).
+
+   This function does not scan for new operands.  It is provided for
+   the use of the gimplifier, which manipulates statements for which
+   def/use information has not yet been constructed.  Most callers
+   should use gsi_insert_after.  */
+
+void
+gsi_insert_after_without_update (gimple_stmt_iterator *i, gimple stmt,
+                                 enum gsi_iterator_update m)
+{
+  gimple_seq_node n;

   n = ggc_alloc (sizeof (*n));
   n->prev = n->next = NULL;
@@ -377,6 +445,20 @@ gsi_insert_after (gimple_stmt_iterator *
 }


+/* Insert statement STMT after the statement pointed-to by iterator I.
+   Update STMT's basic block and scan it for new operands.  M
+   specifies how to update iterator I after insertion (see enum
+   gsi_iterator_update).  */
+
+void
+gsi_insert_after (gimple_stmt_iterator *i, gimple stmt,
+		  enum gsi_iterator_update m)
+{
+  update_modified_stmt (stmt);
+  gsi_insert_after_without_update (i, stmt, m);
+}
+
+
 /* Remove the current stmt from the sequence.  The iterator is updated
    to point to the next statement.

Index: gcc/gimplify.c
===================================================================
--- gcc/gimplify.c	(revision 133160)
+++ gcc/gimplify.c	(working copy)
@@ -160,6 +160,49 @@ gimple_tree_eq (const void *p1, const vo
   return 1;
 }

+/* Link gimple statement GS to the end of the sequence *SEQ_P.  If
+   *SEQ_P is NULL, a new sequence is allocated.  This function is
+   similar to gimple_seq_add_stmt, but does not scan the operands.
+   During gimplification, we need to manipulate statement sequences
+   before the def/use vectors have been constructed.  */
+
+static void
+gimplify_seq_add_stmt (gimple_seq *seq_p, gimple gs)
+{
+  gimple_stmt_iterator si;
+
+  if (gs == NULL)
+    return;
+
+  if (*seq_p == NULL)
+    *seq_p = gimple_seq_alloc ();
+
+  si = gsi_last (*seq_p);
+
+  gsi_insert_after_without_update (&si, gs, GSI_NEW_STMT);
+}
+
+/* Append sequence SRC to the end of sequence *DST_P.  If *DST_P is
+   NULL, a new sequence is allocated.   This function is
+   similar to gimple_seq_add_seq, but does not scan the operands.
+   During gimplification, we need to manipulate statement sequences
+   before the def/use vectors have been constructed.  */
+
+static void
+gimplify_seq_add_seq (gimple_seq *dst_p, gimple_seq src)
+{
+  gimple_stmt_iterator si;
+
+  if (src == NULL)
+    return;
+
+  if (*dst_p == NULL)
+    *dst_p = gimple_seq_alloc ();
+
+  si = gsi_last (*dst_p);
+  gsi_insert_seq_after_without_update (&si, src, GSI_NEW_STMT);
+}
+
 /* Set up a context for the gimplifier.  */

 void
@@ -254,7 +297,7 @@ gimple_pop_condition (gimple_seq *pre_p)
   gcc_assert (conds >= 0);
   if (conds == 0)
     {
-      gimple_seq_add_seq (pre_p, gimplify_ctxp->conditional_cleanups);
+      gimplify_seq_add_seq (pre_p, gimplify_ctxp->conditional_cleanups);
       gimple_seq_free (gimplify_ctxp->conditional_cleanups);
     }
 }
@@ -1148,19 +1191,19 @@ gimplify_bind_expr (tree *expr_p, gimple
       build_stack_save_restore (&stack_save, &stack_restore);

       cleanup = new_body = NULL;
-      gimple_seq_add_stmt (&cleanup, stack_restore);
+      gimplify_seq_add_stmt (&cleanup, stack_restore);
       gs = gimple_build_try (gimple_bind_body (gimple_bind), cleanup,
 	  		     GIMPLE_TRY_FINALLY);

-      gimple_seq_add_stmt (&new_body, stack_save);
-      gimple_seq_add_stmt (&new_body, gs);
+      gimplify_seq_add_stmt (&new_body, stack_save);
+      gimplify_seq_add_stmt (&new_body, gs);
       gimple_bind_set_body (gimple_bind, new_body);
     }

   gimplify_ctxp->save_stack = old_save_stack;
   gimple_pop_bind_expr ();

-  gimple_seq_add_stmt (pre_p, gimple_bind);
+  gimplify_seq_add_stmt (pre_p, gimple_bind);

   if (temp)
     {
@@ -1194,7 +1237,7 @@ gimplify_return_expr (tree stmt, gimple_
     {
       gimple ret = gimple_build_return (ret_expr);
       gimple_set_no_warning (ret, TREE_NO_WARNING (stmt));
-      gimple_seq_add_stmt (pre_p, ret);
+      gimplify_seq_add_stmt (pre_p, ret);
       return GS_ALL_DONE;
     }

@@ -1252,7 +1295,7 @@ gimplify_return_expr (tree stmt, gimple_

   ret = gimple_build_return (result);
   gimple_set_no_warning (ret, TREE_NO_WARNING (stmt));
-  gimple_seq_add_stmt (pre_p, ret);
+  gimplify_seq_add_stmt (pre_p, ret);

   return GS_ALL_DONE;
 }
@@ -1355,16 +1398,16 @@ gimplify_loop_expr (tree *expr_p, gimple
   tree saved_label = gimplify_ctxp->exit_label;
   tree start_label = create_artificial_label ();

-  gimple_seq_add_stmt (pre_p, gimple_build_label (start_label));
+  gimplify_seq_add_stmt (pre_p, gimple_build_label (start_label));

   gimplify_ctxp->exit_label = NULL_TREE;

   gimplify_and_add (LOOP_EXPR_BODY (*expr_p), pre_p);

-  gimple_seq_add_stmt (pre_p, gimple_build_goto (start_label));
+  gimplify_seq_add_stmt (pre_p, gimple_build_goto (start_label));

   if (gimplify_ctxp->exit_label)
-    gimple_seq_add_stmt (pre_p, gimple_build_label
(gimplify_ctxp->exit_label));
+    gimplify_seq_add_stmt (pre_p, gimple_build_label
(gimplify_ctxp->exit_label));

   gimplify_ctxp->exit_label = saved_label;

@@ -1499,7 +1542,7 @@ gimplify_switch_expr (tree *expr_p, gimp
 	  default_case = build3 (CASE_LABEL_EXPR, void_type_node, NULL_TREE,
 	                         NULL_TREE, create_artificial_label ());
 	  new_default = gimple_build_label (CASE_LABEL (default_case));
-	  gimple_seq_add_stmt (&switch_body_seq, new_default);
+	  gimplify_seq_add_stmt (&switch_body_seq, new_default);
 	}

       if (!VEC_empty (tree, labels))
@@ -1507,8 +1550,8 @@ gimplify_switch_expr (tree *expr_p, gimp

       gimple_switch = gimple_build_switch_vec (SWITCH_COND (switch_expr),
                                                default_case, labels);
-      gimple_seq_add_stmt (pre_p, gimple_switch);
-      gimple_seq_add_seq (pre_p, switch_body_seq);
+      gimplify_seq_add_stmt (pre_p, gimple_switch);
+      gimplify_seq_add_seq (pre_p, switch_body_seq);
       VEC_free(tree, heap, labels);
     }
   else
@@ -1533,7 +1576,7 @@ gimplify_case_label_expr (tree *expr_p,

   gimple_label = gimple_build_label (CASE_LABEL (*expr_p));
   VEC_safe_push (tree, heap, ctxp->case_labels, *expr_p);
-  gimple_seq_add_stmt (pre_p, gimple_label);
+  gimplify_seq_add_stmt (pre_p, gimple_label);

   return GS_ALL_DONE;
 }
@@ -2058,7 +2101,7 @@ gimplify_self_mod_expr (tree *expr_p, gi
   if (postfix)
     {
       gimplify_and_add (t1, orig_post_p);
-      gimple_seq_add_seq (orig_post_p, post);
+      gimplify_seq_add_seq (orig_post_p, post);
       *expr_p = lhs;
       return GS_ALL_DONE;
     }
@@ -2339,7 +2382,7 @@ gimplify_call_expr (tree *expr_p, gimple
   /* Now add the GIMPLE call to PRE_P.  If WANT_VALUE is set, we need
      to create the appropriate temporary for the call's LHS.  */
   call = gimple_build_call_vec (fndecl ? fndecl : CALL_EXPR_FN
(*expr_p), args);
-  gimple_seq_add_stmt (pre_p, call);
+  gimplify_seq_add_stmt (pre_p, call);
   if (want_value)
     {
       tree lhs = get_tmp_var_for (call);
@@ -2823,14 +2866,14 @@ gimplify_cond_expr (tree *expr_p, gimple
   gimple_cond = gimple_build_cond (pred_code, arm1, arm2, label_true,
                                    label_false);

-  gimple_seq_add_stmt (pre_p, gimple_cond);
-  gimple_seq_add_stmt (pre_p, gimple_build_label (label_true));
+  gimplify_seq_add_stmt (pre_p, gimple_cond);
+  gimplify_seq_add_stmt (pre_p, gimple_build_label (label_true));
   have_then_clause_p = gimplify_stmt (&TREE_OPERAND (expr, 1), pre_p);
   label_cont = create_artificial_label ();
-  gimple_seq_add_stmt (pre_p, gimple_build_goto (label_cont));
-  gimple_seq_add_stmt (pre_p, gimple_build_label (label_false));
+  gimplify_seq_add_stmt (pre_p, gimple_build_goto (label_cont));
+  gimplify_seq_add_stmt (pre_p, gimple_build_label (label_false));
   have_else_clause_p = gimplify_stmt (&TREE_OPERAND (expr, 2), pre_p);
-  gimple_seq_add_stmt (pre_p, gimple_build_label (label_cont));
+  gimplify_seq_add_stmt (pre_p, gimple_build_label (label_cont));

   gimple_pop_condition (pre_p);

@@ -2873,13 +2916,13 @@ gimplify_modify_expr_to_memcpy (tree *ex
       /* tmp = memcpy() */
       t = create_tmp_var (TREE_TYPE (to_ptr), NULL);
       gimple_call_set_lhs (gs, t);
-      gimple_seq_add_stmt (seq_p, gs);
+      gimplify_seq_add_stmt (seq_p, gs);

       *expr_p = build1 (INDIRECT_REF, TREE_TYPE (to), t);
       return GS_ALL_DONE;
     }

-  gimple_seq_add_stmt (seq_p, gs);
+  gimplify_seq_add_stmt (seq_p, gs);
   *expr_p = NULL;
   return GS_ALL_DONE;
 }
@@ -2907,13 +2950,13 @@ gimplify_modify_expr_to_memset (tree *ex
       /* tmp = memset() */
       t = create_tmp_var (TREE_TYPE (to_ptr), NULL);
       gimple_call_set_lhs (gs, t);
-      gimple_seq_add_stmt (seq_p, gs);
+      gimplify_seq_add_stmt (seq_p, gs);

       *expr_p = build1 (INDIRECT_REF, TREE_TYPE (to), t);
       return GS_ALL_DONE;
     }

-  gimple_seq_add_stmt (seq_p, gs);
+  gimplify_seq_add_stmt (seq_p, gs);
   *expr_p = NULL;
   return GS_ALL_DONE;
 }
@@ -3076,10 +3119,10 @@ gimplify_init_ctor_eval_range (tree obje
   /* Create and initialize the index variable.  */
   var_type = TREE_TYPE (upper);
   var = create_tmp_var (var_type, NULL);
-  gimple_seq_add_stmt (pre_p, gimple_build_assign (var, lower));
+  gimplify_seq_add_stmt (pre_p, gimple_build_assign (var, lower));

   /* Add the loop entry label.  */
-  gimple_seq_add_stmt (pre_p, gimple_build_label (loop_entry_label));
+  gimplify_seq_add_stmt (pre_p, gimple_build_label (loop_entry_label));

   /* Build the reference.  */
   cref = build4 (ARRAY_REF, array_elt_type, unshare_expr (object),
@@ -3094,22 +3137,22 @@ gimplify_init_ctor_eval_range (tree obje
     gimplify_init_ctor_eval (cref, CONSTRUCTOR_ELTS (value),
 			     pre_p, cleared);
   else
-    gimple_seq_add_stmt (pre_p, gimple_build_assign (cref, value));
+    gimplify_seq_add_stmt (pre_p, gimple_build_assign (cref, value));

   /* We exit the loop when the index var is equal to the upper bound.  */
-  gimple_seq_add_stmt (pre_p, gimple_build_cond (EQ_EXPR, var, upper,
+  gimplify_seq_add_stmt (pre_p, gimple_build_cond (EQ_EXPR, var, upper,
 					     loop_exit_label, NULL_TREE));

   /* Otherwise, increment the index var...  */
   tmp = build2 (PLUS_EXPR, var_type, var,
 		fold_convert (var_type, integer_one_node));
-  gimple_seq_add_stmt (pre_p, gimple_build_assign (var, tmp));
+  gimplify_seq_add_stmt (pre_p, gimple_build_assign (var, tmp));

   /* ...and jump back to the loop entry.  */
-  gimple_seq_add_stmt (pre_p, gimple_build_goto (loop_entry_label));
+  gimplify_seq_add_stmt (pre_p, gimple_build_goto (loop_entry_label));

   /* Add the loop exit label.  */
-  gimple_seq_add_stmt (pre_p, gimple_build_label (loop_exit_label));
+  gimplify_seq_add_stmt (pre_p, gimple_build_label (loop_exit_label));
 }

 /* Return true if FDECL is accessing a field that is zero sized.  */
@@ -3554,7 +3597,7 @@ gimplify_init_constructor (tree *expr_p,
 	  tree lhs = TREE_OPERAND (*expr_p, 0);
 	  tree rhs = TREE_OPERAND (*expr_p, 1);
 	  gimple init = gimple_build_assign (lhs, rhs);
-	  gimple_seq_add_stmt (pre_p, init);
+	  gimplify_seq_add_stmt (pre_p, init);
 	  *expr_p = NULL;
 	}

@@ -3898,7 +3941,7 @@ gimplify_modify_expr_complex_part (tree
   else
     new_rhs = build2 (COMPLEX_EXPR, TREE_TYPE (lhs), realpart, imagpart);

-  gimple_seq_add_stmt (pre_p, gimple_build_assign (lhs, new_rhs));
+  gimplify_seq_add_stmt (pre_p, gimple_build_assign (lhs, new_rhs));
   *expr_p = (want_value) ? rhs : NULL_TREE;

   return GS_ALL_DONE;
@@ -4015,7 +4058,7 @@ gimplify_modify_expr (tree *expr_p, gimp
     }

   assign = gimple_build_assign (unshare_expr (*to_p), unshare_expr (*from_p));
-  gimple_seq_add_stmt (pre_p, assign);
+  gimplify_seq_add_stmt (pre_p, assign);

   if (gimplify_ctxp->into_ssa && is_gimple_reg (*to_p))
     {
@@ -4483,7 +4526,7 @@ gimplify_asm_expr (tree *expr_p, gimple_
   if (TREE_THIS_VOLATILE (expr))
     gimple_asm_set_volatile (stmt);

-  gimple_seq_add_stmt (pre_p, stmt);
+  gimplify_seq_add_stmt (pre_p, stmt);
   return ret;
 }

@@ -4529,8 +4572,11 @@ gimplify_cleanup_point_expr (tree *expr_
 	{
 	  if (gsi_one_before_end_p (iter))
 	    {
-	      gsi_insert_seq_before (&iter, gimple_wce_cleanup (wce),
-		  		   GSI_SAME_STMT);
+              /* Note that gsi_insert_seq_before and gsi_remove do not
+                 scan operands, unlike some other sequence mutators.  */
+	      gsi_insert_seq_before_without_update (&iter,
+                                                    gimple_wce_cleanup (wce),
+                                                    GSI_SAME_STMT);
 	      gsi_remove (&iter, true);
 	      break;
 	    }
@@ -4544,12 +4590,12 @@ gimplify_cleanup_point_expr (tree *expr_
 		kind = GIMPLE_TRY_CATCH;
 	      else
 		kind = GIMPLE_TRY_FINALLY;
-
 	      seq = gsi_split_seq_after (iter);

 	      try = gimple_build_try (seq, gimple_wce_cleanup (wce), kind);
-
-	      gsi_replace (&iter, try, GSI_SAME_STMT);
+              /* Do not use gsi_replace here, as it may scan operands.
+                 We want to do a simple structural modification only.  */
+              *gsi_stmt_ptr (&iter) = try;
 	      iter = gsi_start (seq);
 	    }
 	}
@@ -4557,7 +4603,7 @@ gimplify_cleanup_point_expr (tree *expr_
 	gsi_next (&iter);
     }

-  gimple_seq_add_seq (pre_p, body_sequence);
+  gimplify_seq_add_seq (pre_p, body_sequence);
   if (temp)
     {
       *expr_p = temp;
@@ -4615,9 +4661,9 @@ gimple_push_cleanup (tree var, tree clea
       gimplify_stmt (&cleanup, &cleanup_stmts);
       wce = gimple_build_wce (cleanup_stmts);

-      gimple_seq_add_stmt (&gimplify_ctxp->conditional_cleanups, ffalse);
-      gimple_seq_add_stmt (&gimplify_ctxp->conditional_cleanups, wce);
-      gimple_seq_add_stmt (pre_p, ftrue);
+      gimplify_seq_add_stmt (&gimplify_ctxp->conditional_cleanups, ffalse);
+      gimplify_seq_add_stmt (&gimplify_ctxp->conditional_cleanups, wce);
+      gimplify_seq_add_stmt (pre_p, ftrue);

       /* Because of this manipulation, and the EH edges that jump
 	 threading cannot redirect, the temporary (VAR) will appear
@@ -4629,7 +4675,7 @@ gimple_push_cleanup (tree var, tree clea
       gimplify_stmt (&cleanup, &cleanup_stmts);
       wce = gimple_build_wce (cleanup_stmts);
       gimple_wce_set_cleanup_eh_only (wce, eh_only);
-      gimple_seq_add_stmt (pre_p, wce);
+      gimplify_seq_add_stmt (pre_p, wce);
     }
 }

@@ -5354,7 +5400,7 @@ gimplify_omp_parallel (tree *expr_p, gim
 				 OMP_PARALLEL_DATA_ARG (expr));
   if (OMP_PARALLEL_COMBINED (expr))
     gimple_set_subcode (g, GF_OMP_PARALLEL_COMBINED);
-  gimple_seq_add_stmt (pre_p, g);
+  gimplify_seq_add_stmt (pre_p, g);
   *expr_p = NULL_TREE;
 }

@@ -5477,12 +5523,12 @@ gimplify_omp_for (tree *expr_p, gimple_s

   for_body = gimple_seq_alloc ();
   if (init_decl)
-    gimple_seq_add_stmt (&for_body, init_decl);
+    gimplify_seq_add_stmt (&for_body, init_decl);
   gimplify_and_add (OMP_FOR_BODY (for_stmt), &for_body);

   gimplify_adjust_omp_clauses (&OMP_FOR_CLAUSES (for_stmt));

-  gimple_seq_add_stmt
+  gimplify_seq_add_stmt
     (pre_p, gimple_build_omp_for (for_body, OMP_FOR_CLAUSES (for_stmt),
 				  for_index, for_initial, for_final, for_incr,
 				  for_pre_body, for_predicate));
@@ -5618,11 +5664,11 @@ gimplify_omp_atomic (tree *expr_p, gimpl
        != GS_ALL_DONE)
      return GS_ERROR;

-   gimple_seq_add_stmt (pre_p, gimple_build_omp_atomic_load (tmp_load, addr));
+   gimplify_seq_add_stmt (pre_p, gimple_build_omp_atomic_load
(tmp_load, addr));
    if (gimplify_expr (&rhs, pre_p, NULL, is_gimple_val, fb_rvalue)
        != GS_ALL_DONE)
      return GS_ERROR;
-   gimple_seq_add_stmt (pre_p, gimple_build_omp_atomic_store (rhs));
+   gimplify_seq_add_stmt (pre_p, gimple_build_omp_atomic_store (rhs));
    *expr_p = NULL;

    return GS_ALL_DONE;
@@ -5981,7 +6027,7 @@ gimplify_expr (tree *expr_p, gimple_seq
 	  if (TREE_CODE (GOTO_DESTINATION (*expr_p)) != LABEL_DECL)
 	    ret = gimplify_expr (&GOTO_DESTINATION (*expr_p), pre_p,
 				 NULL, is_gimple_val, fb_rvalue);
-	  gimple_seq_add_stmt (pre_p,
+	  gimplify_seq_add_stmt (pre_p,
 			  gimple_build_goto (GOTO_DESTINATION (*expr_p)));
 	  break;

@@ -5989,7 +6035,7 @@ gimplify_expr (tree *expr_p, gimple_seq
 	  ret = GS_ALL_DONE;
 	  gcc_assert (decl_function_context (LABEL_EXPR_LABEL (*expr_p))
 		      == current_function_decl);
-	  gimple_seq_add_stmt (pre_p,
+	  gimplify_seq_add_stmt (pre_p,
 			  gimple_build_label (LABEL_EXPR_LABEL (*expr_p)));
 	  break;

@@ -6079,7 +6125,7 @@ gimplify_expr (tree *expr_p, gimple_seq
 				     TREE_CODE (*expr_p) == TRY_FINALLY_EXPR
 				     ? GIMPLE_TRY_FINALLY
 				     : GIMPLE_TRY_CATCH);
-	    gimple_seq_add_stmt (pre_p, try_);
+	    gimplify_seq_add_stmt (pre_p, try_);
 	    ret = GS_ALL_DONE;
 	    break;
 	  }
@@ -6098,7 +6144,7 @@ gimplify_expr (tree *expr_p, gimple_seq
 	    gimple_seq handler = NULL;
 	    gimplify_and_add (CATCH_BODY (*expr_p), &handler);
 	    c = gimple_build_catch (CATCH_TYPES (*expr_p), handler);
-	    gimple_seq_add_stmt (pre_p, c);
+	    gimplify_seq_add_stmt (pre_p, c);
 	    ret = GS_ALL_DONE;
 	    break;
 	  }
@@ -6112,7 +6158,7 @@ gimplify_expr (tree *expr_p, gimple_seq
 	    ehf = gimple_build_eh_filter (EH_FILTER_TYPES (*expr_p), failure);
 	    gimple_eh_filter_set_must_not_throw
 	      (ehf, EH_FILTER_MUST_NOT_THROW (*expr_p));
-	    gimple_seq_add_stmt (pre_p, ehf);
+	    gimplify_seq_add_stmt (pre_p, ehf);
 	    ret = GS_ALL_DONE;
 	    break;
 	  }
@@ -6125,7 +6171,7 @@ gimplify_expr (tree *expr_p, gimple_seq
 				 pre_p, post_p, is_gimple_reg, fb_lvalue);
 	    cdt = gimple_build_cdt (CHANGE_DYNAMIC_TYPE_NEW_TYPE (*expr_p),
 				    CHANGE_DYNAMIC_TYPE_LOCATION (*expr_p));
-	    gimple_seq_add_stmt (pre_p, cdt);
+	    gimplify_seq_add_stmt (pre_p, cdt);
 	    ret = GS_ALL_DONE;
 	  }
 	  break;
@@ -6222,7 +6268,7 @@ gimplify_expr (tree *expr_p, gimple_seq
 	      default:
 		gcc_unreachable ();
 	      }
-	    gimple_seq_add_stmt (pre_p, g);
+	    gimplify_seq_add_stmt (pre_p, g);
 	    ret = GS_ALL_DONE;
 	    break;
 	  }
@@ -6433,8 +6479,8 @@ gimplify_expr (tree *expr_p, gimple_seq
       if (!gimple_seq_empty_p (internal_pre)
 	  || !gimple_seq_empty_p (internal_post))
 	{
-	  gimple_seq_add_seq (&internal_pre, internal_post);
-	  gimple_seq_add_seq (pre_p, internal_pre);
+	  gimplify_seq_add_seq (&internal_pre, internal_post);
+	  gimplify_seq_add_seq (pre_p, internal_pre);
 	}

       if (!gimple_seq_empty_p (*pre_p))
@@ -6546,7 +6592,7 @@ gimplify_expr (tree *expr_p, gimple_seq
   if (!gimple_seq_empty_p (internal_post))
     {
       annotate_all_with_location (internal_post, input_location);
-      gimple_seq_add_seq (pre_p, internal_post);
+      gimplify_seq_add_seq (pre_p, internal_post);
     }

  out:
@@ -6727,7 +6773,7 @@ gimplify_body (tree *body_p, tree fndecl
   if (!outer_bind)
     {
       outer_bind = gimple_build_nop ();
-      gimple_seq_add_stmt (&seq, outer_bind);
+      gimplify_seq_add_stmt (&seq, outer_bind);
     }

   /* The body must contain exactly one statement, a GIMPLE_BIND.  If this is
@@ -6744,7 +6790,7 @@ gimplify_body (tree *body_p, tree fndecl
      of the function.  */
   if (!gimple_seq_empty_p (parm_stmts))
     {
-      gimple_seq_add_seq (&parm_stmts, gimple_bind_body (outer_bind));
+      gimplify_seq_add_seq (&parm_stmts, gimple_bind_body (outer_bind));
       gimple_bind_set_body (outer_bind, parm_stmts);
     }

@@ -6816,19 +6862,19 @@ gimplify_function_tree (tree fndecl)
       gimple_seq cleanup = NULL, body = NULL;

       x = implicit_built_in_decls[BUILT_IN_PROFILE_FUNC_EXIT];
-      gimple_seq_add_stmt (&cleanup, gimple_build_call (x, 0));
+      gimplify_seq_add_stmt (&cleanup, gimple_build_call (x, 0));
       tf = gimple_build_try (seq, cleanup, GIMPLE_TRY_FINALLY);

       x = implicit_built_in_decls[BUILT_IN_PROFILE_FUNC_ENTER];
-      gimple_seq_add_stmt (&body, gimple_build_call (x, 0));
-      gimple_seq_add_stmt (&body, tf);
+      gimplify_seq_add_stmt (&body, gimple_build_call (x, 0));
+      gimplify_seq_add_stmt (&body, tf);
       bind = gimple_build_bind (NULL, body);
     }

   /* The tree body of the function is no longer needed, replace it
      with the new GIMPLE body.  */
   seq = gimple_seq_alloc ();
-  gimple_seq_add_stmt (&seq, bind);
+  gimplify_seq_add_stmt (&seq, bind);
   gimple_set_body (fndecl, seq);
   DECL_SAVED_TREE (fndecl) = NULL_TREE;

Index: gcc/tree-dfa.c
===================================================================
--- gcc/tree-dfa.c	(revision 133160)
+++ gcc/tree-dfa.c	(working copy)
@@ -797,9 +797,11 @@ find_new_referenced_vars_1 (tree *tp, in
 }

 void
-find_new_referenced_vars (tree *stmt_p)
+find_new_referenced_vars (gimple_stmt_iterator *gsi)
 {
-  walk_tree (stmt_p, find_new_referenced_vars_1, NULL, NULL);
+  /* Invoke callback on each operand, in both the statement
+     referenced by GSI and in any embedded statements.  */
+  walk_gimple_stmt (gsi, NULL, find_new_referenced_vars_1, NULL);
 }


@@ -987,4 +989,3 @@ stmt_references_abnormal_ssa_name (gimpl

   return false;
 }
-
Index: gcc/tree-flow.h
===================================================================
--- gcc/tree-flow.h	(revision 133160)
+++ gcc/tree-flow.h	(working copy)
@@ -775,7 +775,7 @@ extern tree get_virtual_var (tree);
 extern void add_referenced_var (tree);
 extern void remove_referenced_var (tree);
 extern void mark_symbols_for_renaming (gimple);
-extern void find_new_referenced_vars (tree *);
+extern void find_new_referenced_vars (gimple_stmt_iterator *);
 extern tree make_rename_temp (tree, const char *);
 extern void set_default_def (tree, tree);
 extern tree gimple_default_def (struct function *, tree);
Index: gcc/gimple.h
===================================================================
--- gcc/gimple.h	(revision 133160)
+++ gcc/gimple.h	(working copy)
@@ -2722,6 +2722,8 @@ gimple_return_set_retval (gimple gs, tre
 {
   GIMPLE_CHECK (gs, GIMPLE_RETURN);
   gcc_assert (gs->with_ops.num_ops == 1);
+  /* FIXME tuples.  The check in gimple_build_return
+     is more restrictive.  Which one is correct?  */
   gcc_assert (is_gimple_operand (retval));
   gimple_set_op (gs, 0, retval);
 }
@@ -3013,12 +3015,20 @@ gimple_seq gsi_split_seq_before (gimple_
 void gsi_replace (gimple_stmt_iterator *, gimple, bool);
 void gsi_insert_before (gimple_stmt_iterator *, gimple,
 			enum gsi_iterator_update);
+void gsi_insert_before_without_update (gimple_stmt_iterator *, gimple,
+                                       enum gsi_iterator_update);
 void gsi_insert_seq_before (gimple_stmt_iterator *, gimple_seq,
-		       enum gsi_iterator_update);
+                            enum gsi_iterator_update);
+void gsi_insert_seq_before_without_update (gimple_stmt_iterator *, gimple_seq,
+                                           enum gsi_iterator_update);
 void gsi_insert_after (gimple_stmt_iterator *, gimple,
 		       enum gsi_iterator_update);
+void gsi_insert_after_without_update (gimple_stmt_iterator *, gimple,
+                                      enum gsi_iterator_update);
 void gsi_insert_seq_after (gimple_stmt_iterator *, gimple_seq,
 			   enum gsi_iterator_update);
+void gsi_insert_seq_after_without_update (gimple_stmt_iterator *, gimple_seq,
+                                          enum gsi_iterator_update);
 void gsi_remove (gimple_stmt_iterator *, bool);
 gimple_stmt_iterator gsi_for_stmt (gimple);
 void gsi_move_after (gimple_stmt_iterator *, gimple_stmt_iterator *);
Index: gcc/passes.c
===================================================================
--- gcc/passes.c	(revision 133160)
+++ gcc/passes.c	(working copy)
@@ -652,7 +652,10 @@ init_optimization_passes (void)
       /* FIXME tuples.  */
 #if 0
       NEXT_PASS (pass_copy_prop);
+#endif
       NEXT_PASS (pass_fold_builtins);
+      /* FIXME tuples.  */
+#if 0
       NEXT_PASS (pass_cse_sincos);
       NEXT_PASS (pass_split_crit_edges);
       NEXT_PASS (pass_pre);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]