[PATCH] Remove one strange limitation of conversion folding (and fix PR19637)

Richard Guenther rguenther@suse.de
Mon Mar 17 14:46:00 GMT 2008


This removes the limitation to not fold (P2)(P1)p3 with the three
pointer types P2, P1 and typeof(p3) for the case that typeof(p3)
is a pointer to array type and P2 is not.  I put this limit in place
because otherwise we were facing missed optimizations (or rather
we didn't recognize the different trees we fold to later) and
appearantly I wasn't willing to fix this fallout.

So, here it goes.  This teaches the places that were triggered
by the testsuite to cope with this.  In addition we now optimize
the code in PR19637 to all return 1 as we should (even if there
is no consensus if the testcases are valid C++).

Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to
trunk.

Richard.

2008-03-16  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/19637
	* fold-const.c (fold_unary): Remove restrictions of removing
	intermediate pointer-conversions (P2)(P1)P0.
	* tree-ssa-ccp.c (maybe_fold_stmt_addition): Recover from
	conversion to void pointer.
	(get_maxval_strlen): Handle addresses of the form &(*p)[0].

	* g++.dg/tree-ssa/pr19637.C: New testcase.

Index: fold-const.c
===================================================================
*** fold-const.c	(revision 133272)
--- fold-const.c	(working copy)
*************** fold_unary (enum tree_code code, tree ty
*** 7784,7792 ****
  	     - the initial type is a pointer type and the precisions of the
  	       intermediate and final types differ, or
  	     - the final type is a pointer type and the precisions of the
! 	       initial and intermediate types differ.
! 	     - the initial type is a pointer to an array and the final type
! 	       not.  */
  	  if (! inside_float && ! inter_float && ! final_float
  	      && ! inside_vec && ! inter_vec && ! final_vec
  	      && (inter_prec >= inside_prec || inter_prec >= final_prec)
--- 7784,7790 ----
  	     - the initial type is a pointer type and the precisions of the
  	       intermediate and final types differ, or
  	     - the final type is a pointer type and the precisions of the
! 	       initial and intermediate types differ.  */
  	  if (! inside_float && ! inter_float && ! final_float
  	      && ! inside_vec && ! inter_vec && ! final_vec
  	      && (inter_prec >= inside_prec || inter_prec >= final_prec)
*************** fold_unary (enum tree_code code, tree ty
*** 7798,7807 ****
  	      && ! (inside_ptr && inter_prec != final_prec)
  	      && ! (final_ptr && inside_prec != inter_prec)
  	      && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type))
! 		    && TYPE_MODE (type) == TYPE_MODE (inter_type))
! 	      && ! (inside_ptr && final_ptr
! 		    && TREE_CODE (TREE_TYPE (inside_type)) == ARRAY_TYPE
! 		    && TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE))
  	    return fold_build1 (code, type, TREE_OPERAND (op0, 0));
  	}
  
--- 7796,7802 ----
  	      && ! (inside_ptr && inter_prec != final_prec)
  	      && ! (final_ptr && inside_prec != inter_prec)
  	      && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type))
! 		    && TYPE_MODE (type) == TYPE_MODE (inter_type)))
  	    return fold_build1 (code, type, TREE_OPERAND (op0, 0));
  	}
  
Index: testsuite/g++.dg/tree-ssa/pr19637.C
===================================================================
*** testsuite/g++.dg/tree-ssa/pr19637.C	(revision 0)
--- testsuite/g++.dg/tree-ssa/pr19637.C	(revision 0)
***************
*** 0 ****
--- 1,33 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O2 -fdump-tree-dom1" } */
+ 
+ #include <new>
+ 
+ struct Foo {
+   Foo() { i[0] = 1; }
+   int i[2];
+ };
+ 
+ int foo_char(void)
+ {
+   int i[2];
+   new (reinterpret_cast<char *>(i)) Foo();
+   return reinterpret_cast<Foo *>(i)->i[0];
+ }
+ 
+ int foo_void(void)
+ {
+   int i[2];
+   new (reinterpret_cast<void *>(i)) Foo();
+   return reinterpret_cast<Foo *>(i)->i[0];
+ }
+ 
+ int foo_void_offset(void)
+ {
+   int i[2];
+   new (reinterpret_cast<void *>(&i[0])) Foo();
+   return reinterpret_cast<Foo *>(&i[0])->i[0];
+ }
+ 
+ /* { dg-final { scan-tree-dump-times "return 1;" 3 "dom1" } } */
+ /* { dg-final { cleanup-tree-dump "dom1" } } */
Index: tree-ssa-ccp.c
===================================================================
*** tree-ssa-ccp.c	(revision 133287)
--- tree-ssa-ccp.c	(working copy)
*************** maybe_fold_stmt_addition (tree expr)
*** 2105,2110 ****
--- 2105,2116 ----
      }
  
    ptd_type = TREE_TYPE (ptr_type);
+   /* If we want a pointer to void, reconstruct the reference from the
+      array element type.  A pointer to that can be trivially converted
+      to void *.  This happens as we fold (void *)(ptr p+ off).  */
+   if (VOID_TYPE_P (ptd_type)
+       && TREE_CODE (TREE_TYPE (op0)) == ARRAY_TYPE)
+     ptd_type = TREE_TYPE (TREE_TYPE (op0));
  
    /* At which point we can try some of the same things as for indirects.  */
    t = maybe_fold_offset_to_array_ref (op0, op1, ptd_type, true);
*************** get_maxval_strlen (tree arg, tree *lengt
*** 2292,2297 ****
--- 2298,2314 ----
        if (TREE_CODE (arg) == COND_EXPR)
          return get_maxval_strlen (COND_EXPR_THEN (arg), length, visited, type)
                 && get_maxval_strlen (COND_EXPR_ELSE (arg), length, visited, type);
+       /* We can end up with &(*iftmp_1)[0] here as well, so handle it.  */
+       else if (TREE_CODE (arg) == ADDR_EXPR
+ 	       && TREE_CODE (TREE_OPERAND (arg, 0)) == ARRAY_REF
+ 	       && integer_zerop (TREE_OPERAND (TREE_OPERAND (arg, 0), 1)))
+ 	{
+ 	  tree aop0 = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
+ 	  if (TREE_CODE (aop0) == INDIRECT_REF
+ 	      && TREE_CODE (TREE_OPERAND (aop0, 0)) == SSA_NAME)
+ 	    return get_maxval_strlen (TREE_OPERAND (aop0, 0),
+ 				      length, visited, type);
+ 	}
  
        if (type == 2)
  	{



More information about the Gcc-patches mailing list