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]

[PATCH] RHS INDIRECT_REF optimizations (PR tree-optimization/26069)


Hi!

unsigned short x;
...
y = *(short *) &x;

can be optimized as

y = (short) x;

Similarly
unsigned long x;
...
y = *(char *) &x;

can be optimized as

y = (char) x; on little endian and
y = (char) (x >> N); on big endian.

It is especially helpful if the var is no longer addressable
because of these transformations, but they work only on RHS,
so they can't be done in fold_indirect_ref_1.
With older GCCs this was usually optimized using ADDRESSOF,
so this is actually a regression from 3.4.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2008-01-11  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/26069
	* gimplify.c (fold_indirect_ref_rhs): Renamed to ...
	(gimple_fold_indirect_ref): ... this.
	(gimple_fold_indirect_ref_rhs): New function.
	(gimplify_modify_expr_rhs): Call gimple_fold_indirect_ref_rhs
	instead of fold_indirect_ref_rhs.
	(gimplify_expr) <case INDIRECT_REF>: If fold_indirect_ref
	didn't optimize anything, try gimple_fold_indirect_ref_rhs
	or gimple_fold_indirect_ref depending on fallback value.

	* gcc.dg/tree-ssa/pr26069.c: New test.

--- gcc/gimplify.c.jj	2008-01-11 16:31:21.000000000 +0100
+++ gcc/gimplify.c	2008-01-11 17:39:27.000000000 +0100
@@ -1,6 +1,6 @@
 /* Tree lowering pass.  This pass converts the GENERIC functions-as-trees
    tree representation into the GIMPLE form.
-   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007
+   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
    Major work done by Sebastian Pop <s.pop@laposte.net>,
    Diego Novillo <dnovillo@redhat.com> and Jason Merrill <jason@redhat.com>.
@@ -3449,13 +3449,12 @@ gimplify_init_constructor (tree *expr_p,
 
 /* Given a pointer value OP0, return a simplified version of an
    indirection through OP0, or NULL_TREE if no simplification is
-   possible.  This may only be applied to a rhs of an expression.
-   Note that the resulting type may be different from the type pointed
-   to in the sense that it is still compatible from the langhooks
-   point of view. */
+   possible.  Note that the resulting type may be different from
+   the type pointed to in the sense that it is still compatible
+   from the langhooks point of view. */
 
 static tree
-fold_indirect_ref_rhs (tree t)
+gimple_fold_indirect_ref (tree t)
 {
   tree type = TREE_TYPE (TREE_TYPE (t));
   tree sub = t;
@@ -3473,9 +3472,10 @@ fold_indirect_ref_rhs (tree t)
       /* *&p => p */
       if (useless_type_conversion_p (type, optype))
         return op;
+
       /* *(foo *)&fooarray => fooarray[0] */
-      else if (TREE_CODE (optype) == ARRAY_TYPE
-	       && useless_type_conversion_p (type, TREE_TYPE (optype)))
+      if (TREE_CODE (optype) == ARRAY_TYPE
+	  && useless_type_conversion_p (type, TREE_TYPE (optype)))
        {
          tree type_domain = TYPE_DOMAIN (optype);
          tree min_val = size_zero_node;
@@ -3492,7 +3492,7 @@ fold_indirect_ref_rhs (tree t)
       tree type_domain;
       tree min_val = size_zero_node;
       tree osub = sub;
-      sub = fold_indirect_ref_rhs (sub);
+      sub = gimple_fold_indirect_ref (sub);
       if (! sub)
 	sub = build1 (INDIRECT_REF, TREE_TYPE (subtype), osub);
       type_domain = TYPE_DOMAIN (TREE_TYPE (sub));
@@ -3504,6 +3504,82 @@ fold_indirect_ref_rhs (tree t)
   return NULL_TREE;
 }
 
+/* Given a pointer value OP0, return a simplified version of an
+   indirection through OP0, or NULL_TREE if no simplification is
+   possible.  This may only be applied to a rhs of an expression.
+   Note that the resulting type may be different from the type pointed
+   to in the sense that it is still compatible from the langhooks
+   point of view. */
+static tree
+gimple_fold_indirect_ref_rhs (tree t)
+{
+  tree type;
+  tree sub;
+  tree subtype;
+
+  sub = gimple_fold_indirect_ref (t);
+  if (sub)
+    return sub;
+
+  type = TREE_TYPE (TREE_TYPE (t));
+  sub = t;
+  STRIP_NOPS (sub);
+  subtype = TREE_TYPE (sub);
+  if (!POINTER_TYPE_P (subtype))
+    return NULL_TREE;
+
+  if (TREE_CODE (sub) == ADDR_EXPR)
+    {
+      tree op = TREE_OPERAND (sub, 0);
+      tree optype = TREE_TYPE (op);
+
+      if ((INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
+	  && (INTEGRAL_TYPE_P (optype) || POINTER_TYPE_P (optype))
+	  && TYPE_PRECISION (type) == GET_MODE_BITSIZE (TYPE_MODE (type))
+	  && !TREE_THIS_VOLATILE (op)
+	  && !TYPE_VOLATILE (optype) && !TYPE_VOLATILE (type))
+	{
+	  /* Handle e.g. unsigned short int x; *(short int *) &x;  */
+	  if (TYPE_MODE (type) == TYPE_MODE (optype)
+	      && TYPE_PRECISION (type) == TYPE_PRECISION (optype))
+	    return fold_convert (type, op);
+
+	  /* Handle e.g. unsigned long int x; *(char *) &x;  */
+	  if (TYPE_PRECISION (type) == BITS_PER_UNIT
+	      && TYPE_PRECISION (optype) > TYPE_PRECISION (type)
+	      && (TYPE_PRECISION (optype)
+		  == GET_MODE_BITSIZE (TYPE_MODE (optype))))
+	    {
+	      int shift = 0;
+	      tree itype;
+
+	      if (TYPE_PRECISION (optype) > BITS_PER_WORD)
+		{
+		  if (WORDS_BIG_ENDIAN)
+		    shift = (TYPE_PRECISION (optype) / BITS_PER_WORD - 1)
+			    * BITS_PER_WORD;
+		  if (BYTES_BIG_ENDIAN)
+		    shift += BITS_PER_WORD - BITS_PER_UNIT;
+		}
+	      else if (BYTES_BIG_ENDIAN)
+		shift = TYPE_PRECISION (optype) - BITS_PER_UNIT;
+
+	      if (shift == 0)
+		return fold_convert (type, op);
+
+	      itype = lang_hooks.types.type_for_size (TYPE_PRECISION (optype),
+						      TYPE_UNSIGNED (type));
+	      return fold_convert (type,
+				   fold_build2 (RSHIFT_EXPR, itype,
+						fold_convert (itype, op),
+						build_int_cst (NULL, shift)));
+	    }
+	}
+    }
+
+  return NULL_TREE;
+}
+
 /* Subroutine of gimplify_modify_expr to do simplifications of
    MODIFY_EXPRs based on the code of the RHS.  We loop for as long as
    something changes.  */
@@ -3557,7 +3633,7 @@ gimplify_modify_expr_rhs (tree *expr_p, 
 	     This kind of code arises in C++ when an object is bound
 	     to a const reference, and if "x" is a TARGET_EXPR we want
 	     to take advantage of the optimization below.  */
-	  tree t = fold_indirect_ref_rhs (TREE_OPERAND (*from_p, 0));
+	  tree t = gimple_fold_indirect_ref_rhs (TREE_OPERAND (*from_p, 0));
 	  if (t)
 	    {
 	      *from_p = t;
@@ -5750,6 +5826,16 @@ gimplify_expr (tree *expr_p, tree *pre_p
 	  *expr_p = fold_indirect_ref (*expr_p);
 	  if (*expr_p != save_expr)
 	    break;
+	  if (fallback == fb_rvalue)
+	    tmp = gimple_fold_indirect_ref_rhs (TREE_OPERAND (*expr_p, 0));
+	  else
+	    tmp = gimple_fold_indirect_ref (TREE_OPERAND (*expr_p, 0));
+	  if (tmp != NULL_TREE)
+	    {
+	      *expr_p = tmp;
+	      break;
+	    }
+
 	  /* else fall through.  */
 	case ALIGN_INDIRECT_REF:
 	case MISALIGNED_INDIRECT_REF:
--- gcc/testsuite/gcc.dg/tree-ssa/pr26069.c.jj	2008-01-11 17:50:10.000000000 +0100
+++ gcc/testsuite/gcc.dg/tree-ssa/pr26069.c	2008-01-11 17:53:45.000000000 +0100
@@ -0,0 +1,39 @@
+/* PR tree-optimization/26069 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-gimple" } */
+
+extern void f5 (int *);
+
+int
+f1 ()
+{
+  unsigned x = 1;
+  return *(char *) &x;
+}
+
+int
+f2 (short a)
+{
+  unsigned short b = *(unsigned short *) &a;
+  return b;
+}
+
+struct S { int i; } s;
+
+int
+f3 (void)
+{
+  return *(char *) &s.i;
+}
+
+int
+f4 (int x)
+{
+  int ret = *(char *) &x;
+  f5 (&x);
+  return ret;
+}
+
+/* All ADDR_EXPRs but the one in f5 (&x) should be optimized out.  */
+/* { dg-final { scan-tree-dump-times "&" 1 "gimple"} } */
+/* { dg-final { cleanup-tree-dump "gimple" } } */

	Jakub


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