[tuples][patch] Convert pass_object_sizes to tuples

Bill Maddox maddox@google.com
Tue Mar 18 07:53:00 GMT 2008


This patch enables pass_object_sizes, and corrects mishandling of
unary NOPs in get_maxval_strlen.

        * builtins.c (fold_builtin_object_size):
	Enable call to compute_builtin_object_size, previously
	stubbed out awaiting tuplification.
	* tree-ssa-ccp.c (valid_gimple_rhs_p, valid_gimple_call_p,
	move_ssa_defining_stmt_for_defs, update_call_from_tree):
	Deleted, moved to tree-ssa-propagate.c.
	(get_maxval_strlen): Use gimple_assign_single_p.
	Handle assignment with unary NOP correctly.
	* tree-ssa-propagate.c (valid_gimple_rhs_p, valid_gimple_call_p,
	move_ssa_defining_stmt_for_defs, update_call_from_tree):
	Moved here from tree-ssa-ccp.c.
	* tree-ssa-propagate.h (valid_gimple_rhs_p, valid_gimple_call_p,
	move_ssa_defining_stmt_for_defs, update_call_from_tree): Declared.
	* gimple-dummy.c (compute_builtin_object_size): Removed dummy.
	* tree_object_size.c (addr_object_size, alloc_object_size)
	Tuplified.
	(pass_through_call, compute_builtin_object_size): Tuplified.
	(expr_object_size): Tuplified.  Some cases broken out.
	(plus_expr_object_size): Deleted.
	(call_object_size, unknown_object_size, plus_stmt_object_size):
	New functions.  Handle cases broken out from expr_object_size.
	(cond_expr_object_size): Fix comment.
	(collect_object_sizes_for): Tuplify.
	(check_for_plus_in_loops_1, check_for_plus_in_loops): Tuplify.
	(compute_object_sizes): Tuplify.
	* gimple.c (gimple_assign_single_p, gimple_assign_unary_nop_p):
	New functions.
	* gimple.h (gimple_assign_single_p, gimple_assign_unary_nop_p):
	Declare.
	* passes.c (init_optimization_passes): Enable pass_object_sizes.

--Bill

Index: gcc/builtins.c
===================================================================
--- gcc/builtins.c	(revision 133203)
+++ gcc/builtins.c	(working copy)
@@ -12154,8 +12154,6 @@ 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));
@@ -12172,9 +12170,6 @@ fold_builtin_object_size (tree ptr, tree
 					     ? -1 : 0))
 	ret = build_int_cstu (size_type_node, bytes);
     }
-#else
-  ret = NULL_TREE;
-#endif

   if (ret)
     {
Index: gcc/tree-ssa-ccp.c
===================================================================
--- gcc/tree-ssa-ccp.c	(revision 133203)
+++ gcc/tree-ssa-ccp.c	(working copy)
@@ -2162,122 +2162,6 @@ maybe_fold_stmt_addition (tree expr)
   return t;
 }

-/* Return true if EXPR is an acceptable right-hand-side for a
-   GIMPLE assignment.  We validate the entire tree, not just
-   the root node, thus catching expressions that embed complex
-   operands that are not permitted in GIMPLE.  This function
-   is needed because the folding routines in fold-const.c
-   may return such expressions in some cases, e.g., an array
-   access with an embedded index addition.  It may make more
-   sense to have folding routines that are sensitive to the
-   constraints on GIMPLE operands, rather than abandoning any
-   any attempt to fold if the usual folding turns out to be too
-   aggressive.  */
-
-static bool
-valid_gimple_rhs_p (tree expr)
-{
-  enum tree_code code = TREE_CODE (expr);
-
-  switch (TREE_CODE_CLASS (code))
-    {
-    case tcc_declaration:
-      if (!is_gimple_variable (expr))
-	return false;
-      break;
-
-    case tcc_constant:
-      /* All constants are ok.  */
-      break;
-
-    case tcc_binary:
-    case tcc_comparison:
-      if (!is_gimple_val (TREE_OPERAND (expr, 0))
-	  || !is_gimple_val (TREE_OPERAND (expr, 1)))
-	return false;
-      break;
-
-    case tcc_unary:
-      if (!is_gimple_val (TREE_OPERAND (expr, 0)))
-	return false;
-      break;
-
-    case tcc_expression:
-      switch (code)
-        {
-        case ADDR_EXPR:
-          {
-            tree t = TREE_OPERAND (expr, 0);
-            while (handled_component_p (t))
-              {
-                /* ??? More checks needed, see the GIMPLE verifier.  */
-                if ((TREE_CODE (t) == ARRAY_REF
-                     || TREE_CODE (t) == ARRAY_RANGE_REF)
-                    && !is_gimple_val (TREE_OPERAND (t, 1)))
-                  return false;
-                t = TREE_OPERAND (t, 0);
-              }
-            if (!is_gimple_id (t))
-              return false;
-          }
-          break;
-
-	case TRUTH_NOT_EXPR:
-	  if (!is_gimple_val (TREE_OPERAND (expr, 0)))
-	    return false;
-	  break;
-
-	case TRUTH_AND_EXPR:
-	case TRUTH_XOR_EXPR:
-	case TRUTH_OR_EXPR:
-	  if (!is_gimple_val (TREE_OPERAND (expr, 0))
-	      || !is_gimple_val (TREE_OPERAND (expr, 1)))
-	    return false;
-	  break;
-
-	case EXC_PTR_EXPR:
-	case FILTER_EXPR:
-	  break;
-
-	default:
-	  return false;
-	}
-      break;
-
-    case tcc_vl_exp:
-      return false;
-
-    case tcc_exceptional:
-      if (code != SSA_NAME)
-        return false;
-
-    default:
-      return false;
-    }
-
-  return true;
-}
-
-/* Return true if EXPR is a CALL_EXPR suitable for representation
-   as a single GIMPLE_CALL statement.  If the arguments require
-   further gimplification, return false.  */
-
-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.  */

@@ -2444,7 +2328,6 @@ fold_stmt_r (tree *expr_p, int *walk_sub
   return NULL_TREE;
 }

-
 /* Return the string length, maximum string length or maximum value of
    ARG in LENGTH.
    If ARG is an SSA name variable, follow its use-def chains.  If LENGTH
@@ -2509,17 +2392,15 @@ get_maxval_strlen (tree arg, tree *lengt
   switch (gimple_code (def_stmt))
     {
       case GIMPLE_ASSIGN:
-	{
-	  /* The RHS of the statement defining VAR must either have a
-	     constant length or come from another SSA_NAME with a constant
-	     length.  */
-          if (get_gimple_rhs_class (gimple_subcode (def_stmt))
-              == GIMPLE_SINGLE_RHS)
-            {
-              tree rhs = gimple_assign_rhs1 (def_stmt);
-              return get_maxval_strlen (rhs, length, visited, type);
-            }
-        }
+        /* 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_assign_single_p (def_stmt)
+            || gimple_assign_unary_nop_p (def_stmt))
+          {
+            tree rhs = gimple_assign_rhs1 (def_stmt);
+            return get_maxval_strlen (rhs, length, visited, type);
+          }
         return false;

       case GIMPLE_PHI:
@@ -2861,123 +2742,6 @@ fold_gimple_cond (gimple stmt)
 }


-/* 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.
Index: gcc/tree-ssa-propagate.c
===================================================================
--- gcc/tree-ssa-propagate.c	(revision 133203)
+++ gcc/tree-ssa-propagate.c	(working copy)
@@ -687,6 +687,242 @@ set_rhs (gimple *stmt_p ATTRIBUTE_UNUSED
 }


+/* Return true if EXPR is an acceptable right-hand-side for a
+   GIMPLE assignment.  We validate the entire tree, not just
+   the root node, thus catching expressions that embed complex
+   operands that are not permitted in GIMPLE.  This function
+   is needed because the folding routines in fold-const.c
+   may return such expressions in some cases, e.g., an array
+   access with an embedded index addition.  It may make more
+   sense to have folding routines that are sensitive to the
+   constraints on GIMPLE operands, rather than abandoning any
+   any attempt to fold if the usual folding turns out to be too
+   aggressive.  */
+
+bool
+valid_gimple_rhs_p (tree expr)
+{
+  enum tree_code code = TREE_CODE (expr);
+
+  switch (TREE_CODE_CLASS (code))
+    {
+    case tcc_declaration:
+      if (!is_gimple_variable (expr))
+	return false;
+      break;
+
+    case tcc_constant:
+      /* All constants are ok.  */
+      break;
+
+    case tcc_binary:
+    case tcc_comparison:
+      if (!is_gimple_val (TREE_OPERAND (expr, 0))
+	  || !is_gimple_val (TREE_OPERAND (expr, 1)))
+	return false;
+      break;
+
+    case tcc_unary:
+      if (!is_gimple_val (TREE_OPERAND (expr, 0)))
+	return false;
+      break;
+
+    case tcc_expression:
+      switch (code)
+        {
+        case ADDR_EXPR:
+          {
+            tree t = TREE_OPERAND (expr, 0);
+            while (handled_component_p (t))
+              {
+                /* ??? More checks needed, see the GIMPLE verifier.  */
+                if ((TREE_CODE (t) == ARRAY_REF
+                     || TREE_CODE (t) == ARRAY_RANGE_REF)
+                    && !is_gimple_val (TREE_OPERAND (t, 1)))
+                  return false;
+                t = TREE_OPERAND (t, 0);
+              }
+            if (!is_gimple_id (t))
+              return false;
+          }
+          break;
+
+	case TRUTH_NOT_EXPR:
+	  if (!is_gimple_val (TREE_OPERAND (expr, 0)))
+	    return false;
+	  break;
+
+	case TRUTH_AND_EXPR:
+	case TRUTH_XOR_EXPR:
+	case TRUTH_OR_EXPR:
+	  if (!is_gimple_val (TREE_OPERAND (expr, 0))
+	      || !is_gimple_val (TREE_OPERAND (expr, 1)))
+	    return false;
+	  break;
+
+	case EXC_PTR_EXPR:
+	case FILTER_EXPR:
+	  break;
+
+	default:
+	  return false;
+	}
+      break;
+
+    case tcc_vl_exp:
+      return false;
+
+    case tcc_exceptional:
+      if (code != SSA_NAME)
+        return false;
+
+    default:
+      return false;
+    }
+
+  return true;
+}
+
+
+/* Return true if EXPR is a CALL_EXPR suitable for representation
+   as a single GIMPLE_CALL statement.  If the arguments require
+   further gimplification, return false.  */
+
+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;
+}
+
+
+/* Make SSA names defined by OLD_STMT point to NEW_STMT
+   as their defining statement.  */
+
+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.  */
+
+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;
+}
+
+
 /* Entry point to the propagation engine.

    VISIT_STMT is called for every statement visited.
Index: gcc/gimple-dummy.c
===================================================================
--- gcc/gimple-dummy.c	(revision 133202)
+++ gcc/gimple-dummy.c	(working copy)
@@ -18,7 +18,6 @@ DUMMY_VAR (memory_identifier_string);


 DUMMY_FN (canonicalize_induction_variables)
-DUMMY_FN (compute_builtin_object_size)
 DUMMY_FN (get_type)
 DUMMY_FN (ipa_add_method)
 DUMMY_FN (ipa_callsite_callee)
Index: gcc/tree-ssa-propagate.h
===================================================================
--- gcc/tree-ssa-propagate.h	(revision 133203)
+++ gcc/tree-ssa-propagate.h	(working copy)
@@ -127,6 +127,10 @@ void ssa_propagate (ssa_prop_visit_stmt_
 tree get_rhs (gimple);				/* FIXME tuples.  Depecrate.  */
 bool valid_gimple_expression_p (tree expr);	/* FIXME tuples.  Depecrate.  */
 bool set_rhs (gimple *, tree);			/* FIXME tuples.  Depecrate.  */
+bool valid_gimple_rhs_p (tree);
+bool valid_gimple_call_p (tree);
+void move_ssa_defining_stmt_for_defs (gimple, gimple);
+bool update_call_from_tree (gimple_stmt_iterator *, tree);
 tree first_vdef (gimple);
 bool stmt_makes_single_load (gimple);
 bool stmt_makes_single_store (gimple);
Index: gcc/tree-object-size.c
===================================================================
--- gcc/tree-object-size.c	(revision 133202)
+++ gcc/tree-object-size.c	(working copy)
@@ -29,8 +29,6 @@ along with GCC; see the file COPYING3.
 #include "tree-pass.h"
 #include "tree-ssa-propagate.h"

-/* FIXME tuples.  */
-#if 0
 struct object_size_info
 {
   int object_size_type;
@@ -45,13 +43,13 @@ static unsigned HOST_WIDE_INT unknown[4]

 static tree compute_object_offset (const_tree, const_tree);
 static unsigned HOST_WIDE_INT addr_object_size (const_tree, int);
-static unsigned HOST_WIDE_INT alloc_object_size (const_tree, int);
-static tree pass_through_call (const_tree);
+static unsigned HOST_WIDE_INT alloc_object_size (const_gimple, int);
+static tree pass_through_call (const_gimple);
 static void collect_object_sizes_for (struct object_size_info *, tree);
 static void expr_object_size (struct object_size_info *, tree, tree);
 static bool merge_object_sizes (struct object_size_info *, tree, tree,
 				unsigned HOST_WIDE_INT);
-static bool plus_expr_object_size (struct object_size_info *, tree, tree);
+static bool plus_stmt_object_size (struct object_size_info *, tree, gimple);
 static bool cond_expr_object_size (struct object_size_info *, tree, tree);
 static unsigned int compute_object_sizes (void);
 static void init_offset_limit (void);
@@ -222,21 +220,21 @@ addr_object_size (const_tree ptr, int ob
 }


-/* Compute __builtin_object_size for CALL, which is a CALL_EXPR.
+/* Compute __builtin_object_size for CALL, which is a GIMPLE_CALL.
    Handles various allocation calls.  OBJECT_SIZE_TYPE is the second
    argument from __builtin_object_size.  If unknown, return
    unknown[object_size_type].  */

 static unsigned HOST_WIDE_INT
-alloc_object_size (const_tree call, int object_size_type)
+alloc_object_size (const_gimple call, int object_size_type)
 {
   tree callee, bytes = NULL_TREE;
   tree alloc_size;
   int arg1 = -1, arg2 = -1;

-  gcc_assert (TREE_CODE (call) == CALL_EXPR);
+  gcc_assert (gimple_code (call) == GIMPLE_CALL);

-  callee = get_callee_fndecl (call);
+  callee = gimple_call_fndecl (call);
   if (!callee)
     return unknown[object_size_type];

@@ -247,7 +245,7 @@ alloc_object_size (const_tree call, int

       arg1 = TREE_INT_CST_LOW (TREE_VALUE (p))-1;
       if (TREE_CHAIN (p))
-	  arg2 = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (p)))-1;
+        arg2 = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (p)))-1;
     }

   if (DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
@@ -263,19 +261,19 @@ alloc_object_size (const_tree call, int
 	break;
       }

-  if (arg1 < 0 || arg1 >= call_expr_nargs (call)
-      || TREE_CODE (CALL_EXPR_ARG (call, arg1)) != INTEGER_CST
+  if (arg1 < 0 || arg1 >= (int)gimple_call_num_args (call)
+      || TREE_CODE (gimple_call_arg (call, arg1)) != INTEGER_CST
       || (arg2 >= 0
-	  && (arg2 >= call_expr_nargs (call)
-	      || TREE_CODE (CALL_EXPR_ARG (call, arg2)) != INTEGER_CST)))
+	  && (arg2 >= (int)gimple_call_num_args (call)
+	      || TREE_CODE (gimple_call_arg (call, arg2)) != INTEGER_CST)))
     return unknown[object_size_type];	

   if (arg2 >= 0)
     bytes = size_binop (MULT_EXPR,
-	fold_convert (sizetype, CALL_EXPR_ARG (call, arg1)),
-	fold_convert (sizetype, CALL_EXPR_ARG (call, arg2)));
+	fold_convert (sizetype, gimple_call_arg (call, arg1)),
+	fold_convert (sizetype, gimple_call_arg (call, arg2)));
   else if (arg1 >= 0)
-    bytes = fold_convert (sizetype, CALL_EXPR_ARG (call, arg1));
+    bytes = fold_convert (sizetype, gimple_call_arg (call, arg1));

   if (bytes && host_integerp (bytes, 1))
     return tree_low_cst (bytes, 1);
@@ -285,13 +283,13 @@ alloc_object_size (const_tree call, int


 /* If object size is propagated from one of function's arguments directly
-   to its return value, return that argument for CALL_EXPR CALL.
+   to its return value, return that argument for GIMPLE_CALL statement CALL.
    Otherwise return NULL.  */

 static tree
-pass_through_call (const_tree call)
+pass_through_call (const_gimple call)
 {
-  tree callee = get_callee_fndecl (call);
+  tree callee = gimple_call_fndecl (call);

   if (callee
       && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
@@ -311,8 +309,8 @@ pass_through_call (const_tree call)
       case BUILT_IN_STRNCPY_CHK:
       case BUILT_IN_STRCAT_CHK:
       case BUILT_IN_STRNCAT_CHK:
-	if (call_expr_nargs (call) >= 1)
-	  return CALL_EXPR_ARG (call, 0);
+	if (gimple_call_num_args (call) >= 1)
+	  return gimple_call_arg (call, 0);
 	break;
       default:
 	break;
@@ -330,21 +328,16 @@ compute_builtin_object_size (tree ptr, i
 {
   gcc_assert (object_size_type >= 0 && object_size_type <= 3);

+  /* FIXME tuples.  Paranoia.  */
+  gcc_assert (TREE_CODE (ptr) != CALL_EXPR);
+
   if (! offset_limit)
     init_offset_limit ();

   if (TREE_CODE (ptr) == ADDR_EXPR)
     return addr_object_size (ptr, object_size_type);
-  else if (TREE_CODE (ptr) == CALL_EXPR)
-    {
-      tree arg = pass_through_call (ptr);

-      if (arg)
-	return compute_builtin_object_size (arg, object_size_type);
-      else
-	return alloc_object_size (ptr, object_size_type);
-    }
-  else if (TREE_CODE (ptr) == SSA_NAME
+  if (TREE_CODE (ptr) == SSA_NAME
 	   && POINTER_TYPE_P (TREE_TYPE (ptr))
 	   && object_sizes[object_size_type] != NULL)
     {
@@ -466,9 +459,7 @@ compute_builtin_object_size (tree ptr, i
   return unknown[object_size_type];
 }

-
-/* Compute object_sizes for PTR, defined to VALUE, which is not
-   a SSA_NAME.  */
+/* Compute object_sizes for PTR, defined to VALUE, which is not an
SSA_NAME.  */

 static void
 expr_object_size (struct object_size_info *osi, tree ptr, tree value)
@@ -490,10 +481,72 @@ expr_object_size (struct object_size_inf

   if (TREE_CODE (value) == ADDR_EXPR)
     bytes = addr_object_size (value, object_size_type);
-  else if (TREE_CODE (value) == CALL_EXPR)
-    bytes = alloc_object_size (value, object_size_type);
   else
-    bytes = unknown[object_size_type];
+    {
+      /* FIXME tuples.  Paranoia.  */
+      gcc_assert (TREE_CODE (value) != CALL_EXPR
+                  && TREE_CODE (value) != POINTER_PLUS_EXPR);
+
+      bytes = unknown[object_size_type];
+    }
+
+  if ((object_size_type & 2) == 0)
+    {
+      if (object_sizes[object_size_type][varno] < bytes)
+	object_sizes[object_size_type][varno] = bytes;
+    }
+  else
+    {
+      if (object_sizes[object_size_type][varno] > bytes)
+	object_sizes[object_size_type][varno] = bytes;
+    }
+}
+
+
+/* Compute object_sizes for PTR, defined to the result of a call.  */
+
+static void
+call_object_size (struct object_size_info *osi, tree ptr, gimple call)
+{
+  int object_size_type = osi->object_size_type;
+  unsigned int varno = SSA_NAME_VERSION (ptr);
+  unsigned HOST_WIDE_INT bytes;
+
+  gcc_assert (gimple_code (call) == GIMPLE_CALL);
+
+  gcc_assert (object_sizes[object_size_type][varno]
+	      != unknown[object_size_type]);
+  gcc_assert (osi->pass == 0);
+
+  bytes = alloc_object_size (call, object_size_type);
+
+  if ((object_size_type & 2) == 0)
+    {
+      if (object_sizes[object_size_type][varno] < bytes)
+	object_sizes[object_size_type][varno] = bytes;
+    }
+  else
+    {
+      if (object_sizes[object_size_type][varno] > bytes)
+	object_sizes[object_size_type][varno] = bytes;
+    }
+}
+
+
+/* Compute object_sizes for PTR, defined to an unknown value.  */
+
+static void
+unknown_object_size (struct object_size_info *osi, tree ptr)
+{
+  int object_size_type = osi->object_size_type;
+  unsigned int varno = SSA_NAME_VERSION (ptr);
+  unsigned HOST_WIDE_INT bytes;
+
+  gcc_assert (object_sizes[object_size_type][varno]
+	      != unknown[object_size_type]);
+  gcc_assert (osi->pass == 0);
+
+  bytes = unknown[object_size_type];

   if ((object_size_type & 2) == 0)
     {
@@ -555,20 +608,23 @@ merge_object_sizes (struct object_size_i
 }


-/* Compute object_sizes for PTR, defined to VALUE, which is
-   a POINTER_PLUS_EXPR.  Return true if the object size might need
reexamination
-   later.  */
+/* Compute object_sizes for VAR, defined to the result of an assignment
+   with operator POINTER_PLUS_EXPR.  Return true if the object size might
+   need reexamination  later.  */

 static bool
-plus_expr_object_size (struct object_size_info *osi, tree var, tree value)
+plus_stmt_object_size (struct object_size_info *osi, tree var, gimple stmt)
 {
-  tree op0 = TREE_OPERAND (value, 0);
-  tree op1 = TREE_OPERAND (value, 1);
   int object_size_type = osi->object_size_type;
   unsigned int varno = SSA_NAME_VERSION (var);
   unsigned HOST_WIDE_INT bytes;
+  tree op0, op1;

-  gcc_assert (TREE_CODE (value) == POINTER_PLUS_EXPR);
+  gcc_assert (gimple_code (stmt) == GIMPLE_ASSIGN);
+  gcc_assert (gimple_subcode (stmt) == POINTER_PLUS_EXPR);
+
+  op0 = gimple_assign_rhs1 (stmt);
+  op1 = gimple_assign_rhs2 (stmt);

   if (object_sizes[object_size_type][varno] == unknown[object_size_type])
     return false;
@@ -586,6 +642,7 @@ plus_expr_object_size (struct object_siz
 	{
 	  unsigned HOST_WIDE_INT off = tree_low_cst (op1, 1);

+          /* op0 will be ADDR_EXPR here.  */
 	  bytes = compute_builtin_object_size (op0, object_size_type);
 	  if (bytes == unknown[object_size_type])
 	    ;
@@ -614,7 +671,7 @@ plus_expr_object_size (struct object_siz
 }


-/* Compute object_sizes for PTR, defined to VALUE, which is
+/* Compute object_sizes for VAR, defined to VALUE, which is
    a COND_EXPR.  Return true if the object size might need reexamination
    later.  */

@@ -647,12 +704,11 @@ cond_expr_object_size (struct object_siz
   return reexamine;
 }

-
 /* Compute object sizes for VAR.
    For ADDR_EXPR an object size is the number of remaining bytes
    to the end of the object (where what is considered an object depends on
    OSI->object_size_type).
-   For allocation CALL_EXPR like malloc or calloc object size is the size
+   For allocation GIMPLE_CALL like malloc or calloc object size is the size
    of the allocation.
    For POINTER_PLUS_EXPR where second operand is a constant integer,
    object size is object size of the first operand minus the constant.
@@ -663,7 +719,7 @@ cond_expr_object_size (struct object_siz
    unknown[object_size_type] for all objects bigger than half of the address
    space, and constants less than half of the address space are considered
    addition, while bigger constants subtraction.
-   For a memcpy like CALL_EXPR that always returns one of its arguments, the
+   For a memcpy like GIMPLE_CALL that always returns one of its arguments, the
    object size is object size of that argument.
    Otherwise, object size is the maximum of object sizes of variables
    that it might be set to.  */
@@ -673,7 +729,7 @@ collect_object_sizes_for (struct object_
 {
   int object_size_type = osi->object_size_type;
   unsigned int varno = SSA_NAME_VERSION (var);
-  tree stmt;
+  gimple stmt;
   bool reexamine;

   if (bitmap_bit_p (computed[object_size_type], varno))
@@ -712,51 +768,57 @@ collect_object_sizes_for (struct object_
   stmt = SSA_NAME_DEF_STMT (var);
   reexamine = false;

-  switch (TREE_CODE (stmt))
+  switch (gimple_code (stmt))
     {
-    case RETURN_EXPR:
-      gcc_assert (TREE_CODE (TREE_OPERAND (stmt, 0)) == GIMPLE_MODIFY_STMT);
-      stmt = TREE_OPERAND (stmt, 0);
-      /* FALLTHRU  */
-
-    case GIMPLE_MODIFY_STMT:
+    case GIMPLE_ASSIGN:
       {
-	tree rhs = GIMPLE_STMT_OPERAND (stmt, 1), arg;
-	STRIP_NOPS (rhs);
-
-	if (TREE_CODE (rhs) == CALL_EXPR)
-	  {
-	    arg = pass_through_call (rhs);
-	    if (arg)
-	      rhs = arg;
-	  }
-
-	if (TREE_CODE (rhs) == SSA_NAME
-	    && POINTER_TYPE_P (TREE_TYPE (rhs)))
-	  reexamine = merge_object_sizes (osi, var, rhs, 0);
-
-	else if (TREE_CODE (rhs) == POINTER_PLUS_EXPR)
-	  reexamine = plus_expr_object_size (osi, var, rhs);
-
-        else if (TREE_CODE (rhs) == COND_EXPR)
-	  reexamine = cond_expr_object_size (osi, var, rhs);
+        if (gimple_subcode (stmt) == POINTER_PLUS_EXPR)
+          reexamine = plus_stmt_object_size (osi, var, stmt);
+        else if (gimple_assign_single_p (stmt)
+                 || gimple_assign_unary_nop_p (stmt))
+          {
+            tree rhs = gimple_assign_rhs1 (stmt);
+
+            if (TREE_CODE (rhs) == SSA_NAME
+                && POINTER_TYPE_P (TREE_TYPE (rhs)))
+              reexamine = merge_object_sizes (osi, var, rhs, 0);
+            else if (TREE_CODE (rhs) == COND_EXPR)
+              reexamine = cond_expr_object_size (osi, var, rhs);
+            else
+              expr_object_size (osi, var, rhs);
+          }
+        else
+          unknown_object_size (osi, var);
+        break;
+      }

-	else
-	  expr_object_size (osi, var, rhs);
+    case GIMPLE_CALL:
+      {
+        tree arg = pass_through_call (stmt);
+        if (arg)
+          {
+            if (TREE_CODE (arg) == SSA_NAME
+                && POINTER_TYPE_P (TREE_TYPE (arg)))
+              reexamine = merge_object_sizes (osi, var, arg, 0);
+            else if (TREE_CODE (arg) == COND_EXPR)
+              reexamine = cond_expr_object_size (osi, var, arg);
+            else
+              expr_object_size (osi, var, arg);
+          }
+        else
+          call_object_size (osi, var, stmt);
 	break;
       }

-    case ASM_EXPR:
+    case GIMPLE_ASM:
       /* Pointers defined by __asm__ statements can point anywhere.  */
       object_sizes[object_size_type][varno] = unknown[object_size_type];
       break;

-    case NOP_EXPR:
+    case GIMPLE_NOP:
       {
 	tree decl = SSA_NAME_VAR (var);

-	gcc_assert (IS_EMPTY_STMT (stmt));
-
 	if (TREE_CODE (decl) != PARM_DECL && DECL_INITIAL (decl))
 	  expr_object_size (osi, var, DECL_INITIAL (decl));
 	else
@@ -764,15 +826,13 @@ collect_object_sizes_for (struct object_
       }
       break;

-      /* FIXME tuples.  */
-#if 0
-    case PHI_NODE:
+    case GIMPLE_PHI:
       {
-	int i;
+	unsigned i;

-	for (i = 0; i < PHI_NUM_ARGS (stmt); i++)
+	for (i = 0; i < gimple_phi_num_args (stmt); i++)
 	  {
-	    tree rhs = PHI_ARG_DEF (stmt, i);
+	    tree rhs = gimple_phi_arg (stmt, i)->def;

 	    if (object_sizes[object_size_type][varno]
 		== unknown[object_size_type])
@@ -785,7 +845,7 @@ collect_object_sizes_for (struct object_
 	  }
 	break;
       }
-#endif
+
     default:
       gcc_unreachable ();
     }
@@ -816,7 +876,7 @@ static void
 check_for_plus_in_loops_1 (struct object_size_info *osi, tree var,
 			   unsigned int depth)
 {
-  tree stmt = SSA_NAME_DEF_STMT (var);
+  gimple stmt = SSA_NAME_DEF_STMT (var);
   unsigned int varno = SSA_NAME_VERSION (var);

   if (osi->depths[varno])
@@ -844,60 +904,61 @@ check_for_plus_in_loops_1 (struct object
   osi->depths[varno] = depth;
   *osi->tos++ = varno;

-  switch (TREE_CODE (stmt))
+  switch (gimple_code (stmt))
     {
-    case RETURN_EXPR:
-      gcc_assert (TREE_CODE (TREE_OPERAND (stmt, 0)) == GIMPLE_MODIFY_STMT);
-      stmt = TREE_OPERAND (stmt, 0);
-      /* FALLTHRU  */

-    case GIMPLE_MODIFY_STMT:
+    case GIMPLE_ASSIGN:
       {
-	tree rhs = GIMPLE_STMT_OPERAND (stmt, 1), arg;
-	STRIP_NOPS (rhs);
-
-	if (TREE_CODE (rhs) == CALL_EXPR)
-	  {
-	    arg = pass_through_call (rhs);
-	    if (arg)
-	      rhs = arg;
-	  }
-
-	if (TREE_CODE (rhs) == SSA_NAME)
-	  check_for_plus_in_loops_1 (osi, rhs, depth);
-	else if (TREE_CODE (rhs) == POINTER_PLUS_EXPR)
-	  {
-	    tree op0 = TREE_OPERAND (rhs, 0);
-	    tree op1 = TREE_OPERAND (rhs, 1);
-	    tree cst, basevar;
-
-	    basevar = op0;
-	    cst = op1;
-	    gcc_assert (TREE_CODE (cst) == INTEGER_CST);
+        if ((gimple_assign_single_p (stmt)
+             || gimple_assign_unary_nop_p (stmt))
+            && TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME)
+          {
+            tree rhs = gimple_assign_rhs1 (stmt);
+
+            check_for_plus_in_loops_1 (osi, rhs, depth);
+          }
+        else if (gimple_subcode (stmt) == POINTER_PLUS_EXPR)
+          {
+            tree basevar = gimple_assign_rhs1 (stmt);
+            tree cst = gimple_assign_rhs2 (stmt);
+
+            gcc_assert (TREE_CODE (cst) == INTEGER_CST);
+
+            check_for_plus_in_loops_1 (osi, basevar,
+                                       depth + !integer_zerop (cst));
+          }
+        else
+          gcc_unreachable ();
+        break;
+      }

-	    check_for_plus_in_loops_1 (osi, basevar,
-				       depth + !integer_zerop (cst));
-	  }
-	else
-	  gcc_unreachable ();
-	break;
+    case GIMPLE_CALL:
+      {
+        tree arg = pass_through_call (stmt);
+        if (arg)
+          {
+            if (TREE_CODE (arg) == SSA_NAME)
+              check_for_plus_in_loops_1 (osi, arg, depth);
+            else
+              gcc_unreachable ();
+          }
+        break;
       }
-    /* FIXME tuples.  */
-#if 0
-    case PHI_NODE:
+
+    case GIMPLE_PHI:
       {
-	int i;
+	unsigned i;

-	for (i = 0; i < PHI_NUM_ARGS (stmt); i++)
+	for (i = 0; i < gimple_phi_num_args (stmt); i++)
 	  {
-	    tree rhs = PHI_ARG_DEF (stmt, i);
+	    tree rhs = gimple_phi_arg (stmt, i)->def;

 	    if (TREE_CODE (rhs) == SSA_NAME)
 	      check_for_plus_in_loops_1 (osi, rhs, depth);
 	  }
 	break;
       }
-#endif
+
     default:
       gcc_unreachable ();
     }
@@ -914,50 +975,29 @@ check_for_plus_in_loops_1 (struct object
 static void
 check_for_plus_in_loops (struct object_size_info *osi, tree var)
 {
-  tree stmt = SSA_NAME_DEF_STMT (var);
-
-  switch (TREE_CODE (stmt))
-    {
-    case RETURN_EXPR:
-      gcc_assert (TREE_CODE (TREE_OPERAND (stmt, 0)) == GIMPLE_MODIFY_STMT);
-      stmt = TREE_OPERAND (stmt, 0);
-      /* FALLTHRU  */
-
-    case GIMPLE_MODIFY_STMT:
-      {
-	tree rhs = GIMPLE_STMT_OPERAND (stmt, 1), arg;
-	STRIP_NOPS (rhs);
-
-	if (TREE_CODE (rhs) == CALL_EXPR)
-	  {
-	    arg = pass_through_call (rhs);
-	    if (arg)
-	      rhs = arg;
-	  }
-
-	if (TREE_CODE (rhs) == POINTER_PLUS_EXPR)
-	  {
-	    tree op0 = TREE_OPERAND (rhs, 0);
-	    tree op1 = TREE_OPERAND (rhs, 1);
-	    tree cst, basevar;
-
-	    basevar = op0;
-	    cst = op1;
-	    gcc_assert (TREE_CODE (cst) == INTEGER_CST);
+  gimple stmt = SSA_NAME_DEF_STMT (var);

-	    if (integer_zerop (cst))
-	      break;
-
-	    osi->depths[SSA_NAME_VERSION (basevar)] = 1;
-	    *osi->tos++ = SSA_NAME_VERSION (basevar);
-	    check_for_plus_in_loops_1 (osi, var, 2);
-	    osi->depths[SSA_NAME_VERSION (basevar)] = 0;
-	    osi->tos--;
-	  }
-	break;
-      }
-    default:
-      break;
+  /* NOTE: In the pre-tuples code, we handled a CALL_EXPR here,
+     and looked for a POINTER_PLUS_EXPR in the pass-through
+     argument, if any.  In GIMPLE, however, such an expression
+     is not a valid call operand.  */
+
+  if (gimple_code (stmt) == GIMPLE_ASSIGN
+      && gimple_subcode (stmt) == POINTER_PLUS_EXPR)
+    {
+      tree basevar = gimple_assign_rhs1 (stmt);
+      tree cst = gimple_assign_rhs2 (stmt);
+	
+      gcc_assert (TREE_CODE (cst) == INTEGER_CST);
+
+      if (integer_zerop (cst))
+        return;
+
+      osi->depths[SSA_NAME_VERSION (basevar)] = 1;
+      *osi->tos++ = SSA_NAME_VERSION (basevar);
+      check_for_plus_in_loops_1 (osi, var, 2);
+      osi->depths[SSA_NAME_VERSION (basevar)] = 0;
+      osi->tos--;
     }
 }

@@ -996,42 +1036,39 @@ fini_object_sizes (void)
       object_sizes[object_size_type] = NULL;
     }
 }
-#endif
+

 /* Simple pass to optimize all __builtin_object_size () builtins.  */

 static unsigned int
 compute_object_sizes (void)
 {
-  /* FIXME tuples.  */
-#if 0
   basic_block bb;
   FOR_EACH_BB (bb)
     {
-      block_stmt_iterator i;
-      for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i))
+      gimple_stmt_iterator i;
+      for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
 	{
-	  tree *stmtp = bsi_stmt_ptr (i);
-	  tree call = get_rhs (*stmtp);
 	  tree callee, result;
+	  gimple call = gsi_stmt (i);

-	  if (!call || TREE_CODE (call) != CALL_EXPR)
+          if (gimple_code (call) != GIMPLE_CALL)
 	    continue;

-	  callee = get_callee_fndecl (call);
+	  callee = gimple_call_fndecl (call);
 	  if (!callee
 	      || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL
 	      || DECL_FUNCTION_CODE (callee) != BUILT_IN_OBJECT_SIZE)
 	    continue;

 	  init_object_sizes ();
-	  result = fold_call_expr (call, false);
+	  result = fold_call_stmt (call, false);
 	  if (!result)
 	    {
-	      if (call_expr_nargs (call) == 2
-		  && POINTER_TYPE_P (TREE_TYPE (CALL_EXPR_ARG (call, 0))))
+	      if (gimple_call_num_args (call) == 2
+		  && POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, 0))))
 		{
-		  tree ost = CALL_EXPR_ARG (call, 1);
+		  tree ost = gimple_call_arg (call, 1);

 		  if (host_integerp (ost, 1))
 		    {
@@ -1053,17 +1090,19 @@ compute_object_sizes (void)
 	  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, call, 0, dump_flags);
 	    }

-	  if (!set_rhs (stmtp, result))
+	  if (!update_call_from_tree (&i, result))
 	    gcc_unreachable ();
-	  update_stmt (*stmtp);
+
+          /* NOTE: In the pre-tuples code, we called update_stmt here.  This is
+             now handled by gsi_replace, called from update_call_from_tree.  */

 	  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, call, 0, dump_flags);
 	      fprintf (dump_file, "\n");
 	    }
 	}
@@ -1071,10 +1110,6 @@ compute_object_sizes (void)

   fini_object_sizes ();
   return 0;
-#else
-  gimple_unreachable ();
-  return 0;
-#endif
 }

 struct tree_opt_pass pass_object_sizes =
Index: gcc/gimple.c
===================================================================
--- gcc/gimple.c	(revision 133203)
+++ gcc/gimple.c	(working copy)
@@ -1624,6 +1624,44 @@ gimple_assign_copy_p (gimple gs)
 	 && is_gimple_val (gimple_op (gs, 1));
 }

+/* Return true if GS is an assignment with a singleton RHS, i.e.,
+   there is no operator associated with the assignment itself.
+   Unlike gimple_assign_copy_p, this predicate returns true for
+   any RHS operand, including those that perform an operation
+   and do not have the semantics of a copy, such as COND_EXPR.  */
+
+bool
+gimple_assign_single_p (gimple gs)
+{
+  return (gimple_code (gs) == GIMPLE_ASSIGN
+          && get_gimple_rhs_class (gimple_subcode (gs)) == GIMPLE_SINGLE_RHS);
+}
+
+/* Return true if GS is an assignment with a unary RHS, but the
+   operator has no effect on the assigned value.  The logic is adapted
+   from STRIP_NOPS.  This predicate is intended to be used in tuplifying
+   instances in which STRIP_NOPS was previously applied to the RHS of
+   an assignment.
+
+   NOTE: In the use cases that led to the creation of this function
+   and of gimple_assign_single_p, it is typical to test for either
+   condition and to proceed in the same manner.  In each case, the
+   assigned value is represented by the single RHS operand of the
+   assignment.  I suspect there may be cases where gimple_assign_copy_p,
+   gimple_assign_single_p, or equivalent logic is used where a similar
+   treatment of unary NOPs is appropriate.  */
+
+bool
+gimple_assign_unary_nop_p (gimple gs)
+{
+  return (gimple_code (gs) == GIMPLE_ASSIGN
+          && (gimple_subcode (gs) == NOP_EXPR
+              || gimple_subcode (gs) == CONVERT_EXPR
+              || gimple_subcode (gs) == NON_LVALUE_EXPR)
+          && gimple_assign_rhs1 (gs) != error_mark_node
+          && (TYPE_MODE (TREE_TYPE (gimple_assign_lhs (gs)))
+              == TYPE_MODE (GENERIC_TREE_TYPE (gimple_assign_rhs1 (gs)))));
+}

 /* Set BB to be the basic block holding G.  */

Index: gcc/gimple.h
===================================================================
--- gcc/gimple.h	(revision 133203)
+++ gcc/gimple.h	(working copy)
@@ -558,6 +558,8 @@ void gimple_seq_add_seq (gimple_seq *, g
 gimple_seq gimple_seq_deep_copy (gimple_seq);
 int gimple_call_flags (gimple);
 bool gimple_assign_copy_p (gimple);
+bool gimple_assign_single_p (gimple);
+bool gimple_assign_unary_nop_p (gimple);
 void gimple_set_bb (gimple, struct basic_block_def *);
 tree gimple_fold (const_gimple);
 void gimple_assign_set_rhs_from_tree (gimple, tree);
Index: gcc/passes.c
===================================================================
--- gcc/passes.c	(revision 133203)
+++ gcc/passes.c	(working copy)
@@ -646,8 +646,8 @@ init_optimization_passes (void)
       NEXT_PASS (pass_dse);
       NEXT_PASS (pass_forwprop);
       NEXT_PASS (pass_phiopt);
-      NEXT_PASS (pass_object_sizes);
 #endif
+      NEXT_PASS (pass_object_sizes);
       NEXT_PASS (pass_store_ccp);
       /* FIXME tuples.  */
 #if 0



More information about the Gcc-patches mailing list