[patch] tree-ssa-forwprop.c: Make a COND_EXPR absorb a non-narrowing cast.

Kazu Hirata kazu@cs.umass.edu
Fri May 27 13:44:00 GMT 2005


Hi,

Attached is a patch to make a COND_EXPR absorb a non-narrowing cast.

Consider

int
foo (unsigned char *p)
{
  unsigned char a = *p;
  unsigned int b = (unsigned int) a;
  if (b == 2)
    return 100;
  return 200;
}

Note that we could replace the "if" statement's condition with
"a == 2".

The patch attempts to do this in forwprop.  The patch appears to be
very big because it moves the existing code to handle limited forms of
casts.  This is because the existing code was under

  else if (TREE_CODE (cond) == SSA_NAME
	   || integer_zerop (TREE_OPERAND (cond, 1))
	   || integer_onep (TREE_OPERAND (cond, 1)))

That is, it was only for booleans.  Since we are now extending cast
elimination to non-narrowing casts, I took the code outside the
"else if (...)".

FWIW, DOM already does this transformation in
find_equivalent_equality_comparison.  The function does not care the
number of immediate uses of the variable being tested.  I haven't
investigated if that has positive or negative effects on generated
code.

This patch catches 5% more forward propagation opportunities while
compiling cc1-i files.

Tested on i686-pc-linux-gnu.  OK to apply?

Kazu Hirata

2005-05-27  Kazu Hirata  <kazu@cs.umass.edu>

	PR tree-optimization/21694
	* tree-ssa-forwprop.c (forward_propagate_into_cond_1):
	Forward-propagate a non-narrowing cast into a COND_EXPR.

2005-05-27  Kazu Hirata  <kazu@cs.umass.edu>

	PR tree-optimization/21694
	* gcc.dg/tree-ssa/pr21694.c: New.

Index: tree-ssa-forwprop.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-forwprop.c,v
retrieving revision 2.21
diff -u -d -p -r2.21 tree-ssa-forwprop.c
--- tree-ssa-forwprop.c	26 May 2005 21:07:38 -0000	2.21
+++ tree-ssa-forwprop.c	26 May 2005 23:09:59 -0000
@@ -249,6 +249,84 @@ forward_propagate_into_cond_1 (tree cond
 	}
     }
 
+  /* We may be able to have COND absorb a cast in DEF_RHS.  */
+  else if (TREE_CODE (def_rhs) == NOP_EXPR
+	   || TREE_CODE (def_rhs) == CONVERT_EXPR)
+    {
+      tree outer_type = TREE_TYPE (def_rhs);
+      tree inner_type = TREE_TYPE (TREE_OPERAND (def_rhs, 0));
+      bool boolean_p = false;
+
+      if (((TREE_CODE (outer_type) == BOOLEAN_TYPE
+	    && INTEGRAL_TYPE_P (inner_type))
+	   || (TREE_CODE (inner_type) == BOOLEAN_TYPE
+	       && INTEGRAL_TYPE_P (outer_type)))
+	  && (TREE_CODE (cond) == SSA_NAME
+	      || integer_zerop (TREE_OPERAND (cond, 1))
+	      || integer_onep (TREE_OPERAND (cond, 1))))
+	boolean_p = true;
+
+      else if (INTEGRAL_TYPE_P (outer_type)
+	       && INTEGRAL_TYPE_P (inner_type)
+	       && TREE_CODE (TREE_OPERAND (def_rhs, 0)) == SSA_NAME
+	       && ssa_name_defined_by_comparison_p (TREE_OPERAND (def_rhs,
+								  0))
+	       && (TREE_CODE (cond) == SSA_NAME
+		   || integer_zerop (TREE_OPERAND (cond, 1))
+		   || integer_onep (TREE_OPERAND (cond, 1))))
+	boolean_p = true;
+
+      /* Handle a non-narrowing cast.  */
+      else if (TYPE_PRECISION (inner_type) <= TYPE_PRECISION (outer_type)
+	       && INTEGRAL_TYPE_P (outer_type)
+	       && INTEGRAL_TYPE_P (inner_type)
+	       && cond_code != SSA_NAME)
+	{
+	  tree op1 = TREE_OPERAND (cond, 1);
+	  tree new_op1 = fold_convert (inner_type, op1);
+	  if (TREE_CODE (new_op1) != INTEGER_CST
+	      || !tree_int_cst_equal (new_op1, op1))
+	    return NULL_TREE;
+	}
+      else
+	return NULL_TREE;
+
+      /* Don't propagate if the operand occurs in
+	 an abnormal PHI.  */
+      if (TREE_CODE (TREE_OPERAND (def_rhs, 0)) == SSA_NAME
+	  && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (TREE_OPERAND
+					      (def_rhs, 0)))
+	return NULL_TREE;
+
+      if (has_single_use (test_var))
+	{
+	  enum tree_code new_code;
+	  tree new_op0, new_op1;
+	  tree op1;
+
+	  if (cond_code == SSA_NAME)
+	    {
+	      new_code = NE_EXPR;
+	      op1 = boolean_false_node;
+	    }
+	  else
+	    {
+	      new_code = cond_code;
+	      op1 = TREE_OPERAND (cond, 1);
+	      if (boolean_p && integer_onep (op1))
+		{
+		  new_code = (new_code == EQ_EXPR) ? NE_EXPR : EQ_EXPR;
+		  op1 = integer_zero_node;
+		}
+	    }
+
+	  new_op0 = TREE_OPERAND (def_rhs, 0);
+	  new_op1 = fold_convert (TREE_TYPE (new_op0), op1);
+	  new_cond = build2 (new_code, boolean_type_node,
+			     new_op0, new_op1);
+	}
+    }
+
   /* These cases require comparisons of a naked SSA_NAME or
      comparison of an SSA_NAME against zero or one.  */
   else if (TREE_CODE (cond) == SSA_NAME
@@ -339,60 +417,6 @@ forward_propagate_into_cond_1 (tree cond
 			     fold_convert (TREE_TYPE (def_rhs),
 					   integer_zero_node));
 	}
-
-      /* If TEST_VAR was set from a cast of an integer type
-	 to a boolean type or a cast of a boolean to an
-	 integral, then it is interesting.  */
-      else if (TREE_CODE (def_rhs) == NOP_EXPR
-	       || TREE_CODE (def_rhs) == CONVERT_EXPR)
-	{
-	  tree outer_type;
-	  tree inner_type;
-
-	  outer_type = TREE_TYPE (def_rhs);
-	  inner_type = TREE_TYPE (TREE_OPERAND (def_rhs, 0));
-
-	  if ((TREE_CODE (outer_type) == BOOLEAN_TYPE
-	       && INTEGRAL_TYPE_P (inner_type))
-	      || (TREE_CODE (inner_type) == BOOLEAN_TYPE
-		  && INTEGRAL_TYPE_P (outer_type)))
-	    ;
-	  else if (INTEGRAL_TYPE_P (outer_type)
-		   && INTEGRAL_TYPE_P (inner_type)
-		   && TREE_CODE (TREE_OPERAND (def_rhs, 0)) == SSA_NAME
-		   && ssa_name_defined_by_comparison_p (TREE_OPERAND (def_rhs,
-								      0)))
-	    ;
-	  else
-	    return NULL_TREE;
-
-	  /* Don't propagate if the operand occurs in
-	     an abnormal PHI.  */
-	  if (TREE_CODE (TREE_OPERAND (def_rhs, 0)) == SSA_NAME
-	      && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (TREE_OPERAND
-						  (def_rhs, 0)))
-	    return NULL_TREE;
-
-	  if (has_single_use (test_var))
-	    {
-	      enum tree_code new_code;
-	      tree new_arg;
-
-	      if (cond_code == SSA_NAME
-		  || (cond_code == NE_EXPR
-		      && integer_zerop (TREE_OPERAND (cond, 1)))
-		  || (cond_code == EQ_EXPR
-		      && integer_onep (TREE_OPERAND (cond, 1))))
-		new_code = NE_EXPR;
-	      else
-		new_code = EQ_EXPR;
-
-	      new_arg = TREE_OPERAND (def_rhs, 0);
-	      new_cond = build2 (new_code, boolean_type_node, new_arg,
-				 fold_convert (TREE_TYPE (new_arg),
-					       integer_zero_node));
-	    }
-	}
     }
 
   *test_var_p = test_var;
--- /dev/null	2005-05-20 10:05:10.845484096 -0400
+++ testsuite/gcc.dg/tree-ssa/pr21694.c	2005-05-26 19:08:04.000000000 -0400
@@ -0,0 +1,19 @@
+/* PR tree-optimization/21694
+   Make sure that the widening cast is propagated into the "if"
+   statement.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-forwprop1-details" } */
+
+int
+foo (unsigned char *p)
+{
+  unsigned char a = *p;
+  unsigned int b = (unsigned int) a;
+  if (b == 2)
+    return 100;
+  return 200;
+}
+
+/* { dg-final { scan-tree-dump-times "Replaced" 1 "forwprop1"} } */
+/* { dg-final { cleanup-tree-dump "forwprop1" } } */



More information about the Gcc-patches mailing list