From ce94d3547f81cc3dd105f4a3377e72cdbd2bbd2c Mon Sep 17 00:00:00 2001
From: Richard Guenther <rguenther@suse.de>
Date: Tue, 29 Jul 2008 17:09:26 +0000
Subject: [PATCH] re PR tree-optimization/36945 (PRE/SCCVN do not handle
 aggregate function arguments correctly)

2008-07-29  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/36945
	* tree-ssa-sccvn.h (copy_reference_ops_from_ref): Declare.
	* tree-ssa-sccvn.c (copy_reference_ops_from_ref): Export.
	Record invariant addresses un-decomposed.
	(copy_reference_ops_from_call): Record reference call
	arguments properly.  Simplify.
	* tree-ssa-pre.c (create_component_ref_by_pieces_1): New
	helper split out from ...
	(create_component_ref_by_pieces): ... here.  Simplify.
	Prepare for recursive invocation for call arguments.
	(create_expression_by_pieces): Adjust call to
	create_component_ref_by_pieces.
	(compute_avail): Process operand 2 of reference ops.

	* gcc.dg/tree-ssa/ssa-pre-18.c: New testcase.

From-SVN: r138257
---
 gcc/ChangeLog                              |  16 +++
 gcc/testsuite/ChangeLog                    |   5 +
 gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-18.c |  21 +++
 gcc/tree-ssa-pre.c                         | 151 ++++++++++-----------
 gcc/tree-ssa-sccvn.c                       |  42 ++----
 gcc/tree-ssa-sccvn.h                       |   1 +
 6 files changed, 127 insertions(+), 109 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-18.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index d1929ba0cffd..9d0388dd5aa9 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,19 @@
+2008-07-29  Richard Guenther  <rguenther@suse.de>
+
+	PR tree-optimization/36945
+	* tree-ssa-sccvn.h (copy_reference_ops_from_ref): Declare.
+	* tree-ssa-sccvn.c (copy_reference_ops_from_ref): Export.
+	Record invariant addresses un-decomposed.
+	(copy_reference_ops_from_call): Record reference call
+	arguments properly.  Simplify.
+	* tree-ssa-pre.c (create_component_ref_by_pieces_1): New
+	helper split out from ...
+	(create_component_ref_by_pieces): ... here.  Simplify.
+	Prepare for recursive invocation for call arguments.
+	(create_expression_by_pieces): Adjust call to
+	create_component_ref_by_pieces.
+	(compute_avail): Process operand 2 of reference ops.
+
 2008-07-29  Richard Guenther  <rguenther@suse.de>
 
 	* gimplify.c (gimplify_expr): Clear TREE_SIDE_EFFECTS for
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index d4e8ddb8701b..79568ddab397 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2008-07-29  Richard Guenther  <rguenther@suse.de>
+
+	PR tree-optimization/36945
+	* gcc.dg/tree-ssa/ssa-pre-18.c: New testcase.
+
 2008-07-29  Jakub Jelinek  <jakub@redhat.com>
 
 	PR c++/36852
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-18.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-18.c
new file mode 100644
index 000000000000..5e92934f052b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-18.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-pre-details" } */
+
+struct Bar { int a; int b; };
+struct Foo { int x; struct Bar y; };
+
+int __attribute__((const)) foo (struct Bar);
+
+int bar (int b)
+{
+  struct Foo f;
+  int c;
+  while (b--)
+    {
+      c = foo(f.y);
+    }
+  return c;
+}
+
+/* { dg-final { scan-tree-dump "Replaced foo \\(f.y\\)" "pre" } } */
+/* { dg-final { cleanup-tree-dump "pre" } } */
diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
index c772ff2bdaff..c98a18a772c9 100644
--- a/gcc/tree-ssa-pre.c
+++ b/gcc/tree-ssa-pre.c
@@ -2421,64 +2421,56 @@ static VEC(gimple,heap) *inserted_exprs;
    to see which expressions need to be put into GC'able memory  */
 static VEC(gimple, heap) *need_creation;
 
-/* For COMPONENT_REF's and ARRAY_REF's, we can't have any intermediates for the
-   COMPONENT_REF or INDIRECT_REF or ARRAY_REF portion, because we'd end up with
-   trying to rename aggregates into ssa form directly, which is a no
-   no.
-
-   Thus, this routine doesn't create temporaries, it just builds a
-   single access expression for the array, calling
-   find_or_generate_expression to build the innermost pieces.
+/* The actual worker for create_component_ref_by_pieces.  */
 
-   This function is a subroutine of create_expression_by_pieces, and
-   should not be called on it's own unless you really know what you
-   are doing.
-*/
 static tree
-create_component_ref_by_pieces (basic_block block, vn_reference_t ref,
-				unsigned int operand,
-				gimple_seq *stmts,
-				gimple domstmt,
-				bool in_call)
+create_component_ref_by_pieces_1 (basic_block block, vn_reference_t ref,
+				  unsigned int *operand, gimple_seq *stmts,
+				  gimple domstmt)
 {
   vn_reference_op_t currop = VEC_index (vn_reference_op_s, ref->operands,
-					operand);
+					*operand);
   tree genop;
+  ++*operand;
   switch (currop->opcode)
     {
     case CALL_EXPR:
       {
 	tree folded;
-	unsigned int i;
-	vn_reference_op_t declop = VEC_index (vn_reference_op_s,
-					      ref->operands, 1);
-	unsigned int nargs = VEC_length (vn_reference_op_s, ref->operands) - 2;
-	tree *args = XNEWVEC (tree, nargs);
-
-	for (i = 0; i < nargs; i++)
+	unsigned int nargs = 0;
+	tree *args = XNEWVEC (tree, VEC_length (vn_reference_op_s,
+						ref->operands) - 1);
+	while (*operand < VEC_length (vn_reference_op_s, ref->operands))
 	  {
-	    args[i] = create_component_ref_by_pieces (block, ref,
-						      operand + 2 + i, stmts,
-						      domstmt, true);
+	    args[nargs] = create_component_ref_by_pieces_1 (block, ref,
+							    operand, stmts,
+							    domstmt);
+	    nargs++;
 	  }
 	folded = build_call_array (currop->type,
-				   TREE_CODE (declop->op0) == FUNCTION_DECL
-				   ? build_fold_addr_expr (declop->op0)
-				   : declop->op0,
+				   TREE_CODE (currop->op0) == FUNCTION_DECL
+				   ? build_fold_addr_expr (currop->op0)
+				   : currop->op0,
 				   nargs, args);
 	free (args);
 	return folded;
       }
       break;
+    case ADDR_EXPR:
+      if (currop->op0)
+	{
+	  gcc_assert (is_gimple_min_invariant (currop->op0));
+	  return currop->op0;
+	}
+      /* Fallthrough.  */
     case REALPART_EXPR:
     case IMAGPART_EXPR:
     case VIEW_CONVERT_EXPR:
       {
 	tree folded;
-	tree genop0 = create_component_ref_by_pieces (block, ref,
-						      operand + 1,
-						      stmts, domstmt,
-						      in_call);
+	tree genop0 = create_component_ref_by_pieces_1 (block, ref,
+							operand,
+							stmts, domstmt);
 	if (!genop0)
 	  return NULL_TREE;
 	folded = fold_build1 (currop->opcode, currop->type,
@@ -2490,45 +2482,25 @@ create_component_ref_by_pieces (basic_block block, vn_reference_t ref,
     case MISALIGNED_INDIRECT_REF:
     case INDIRECT_REF:
       {
-	/* Inside a CALL_EXPR op0 is the actual indirect_ref.  */
-	if (in_call)
-	  {
-	    tree folded;
-	    tree op0 = TREE_OPERAND (currop->op0, 0);
-	    pre_expr op0expr = get_or_alloc_expr_for (op0);
-	    tree genop0 = find_or_generate_expression (block, op0expr, stmts,
-						       domstmt);
-	    if (!genop0)
-	      return NULL_TREE;
-	    folded = fold_build1 (currop->opcode, currop->type,
-				  genop0);
-	    return folded;
-	  }
-	else
-	  {
-
-	    tree folded;
-	    tree genop1 = create_component_ref_by_pieces (block, ref,
-							  operand + 1,
-							  stmts, domstmt,
-							  in_call);
-	    if (!genop1)
-	      return NULL_TREE;
-	    genop1 = fold_convert (build_pointer_type (currop->type),
-				   genop1);
+	tree folded;
+	tree genop1 = create_component_ref_by_pieces_1 (block, ref,
+							operand,
+							stmts, domstmt);
+	if (!genop1)
+	  return NULL_TREE;
+	genop1 = fold_convert (build_pointer_type (currop->type),
+			       genop1);
 
-	    folded = fold_build1 (currop->opcode, currop->type,
-				  genop1);
-	    return folded;
-	  }
+	folded = fold_build1 (currop->opcode, currop->type,
+			      genop1);
+	return folded;
       }
       break;
     case BIT_FIELD_REF:
       {
 	tree folded;
-	tree genop0 = create_component_ref_by_pieces (block, ref, operand + 1,
-						      stmts, domstmt,
-						      in_call);
+	tree genop0 = create_component_ref_by_pieces_1 (block, ref, operand,
+							stmts, domstmt);
 	pre_expr op1expr = get_or_alloc_expr_for (currop->op0);
 	pre_expr op2expr = get_or_alloc_expr_for (currop->op1);
 	tree genop1;
@@ -2553,17 +2525,14 @@ create_component_ref_by_pieces (basic_block block, vn_reference_t ref,
     case ARRAY_RANGE_REF:
     case ARRAY_REF:
       {
-	vn_reference_op_t op0expr;
 	tree genop0;
 	tree genop1 = currop->op0;
 	pre_expr op1expr;
 	tree genop2 = currop->op1;
 	pre_expr op2expr;
 	tree genop3;
-	op0expr = VEC_index (vn_reference_op_s, ref->operands, operand + 1);
-	genop0 = create_component_ref_by_pieces (block, ref, operand + 1,
-						 stmts, domstmt,
-						 in_call);
+	genop0 = create_component_ref_by_pieces_1 (block, ref, operand,
+						   stmts, domstmt);
 	if (!genop0)
 	  return NULL_TREE;
 	op1expr = get_or_alloc_expr_for (genop1);
@@ -2589,8 +2558,8 @@ create_component_ref_by_pieces (basic_block block, vn_reference_t ref,
 	tree op1;
 	tree genop2 = currop->op1;
 	pre_expr op2expr;
-	op0 = create_component_ref_by_pieces (block, ref, operand + 1,
-					      stmts, domstmt, in_call);
+	op0 = create_component_ref_by_pieces_1 (block, ref, operand,
+						stmts, domstmt);
 	if (!op0)
 	  return NULL_TREE;
 	/* op1 should be a FIELD_DECL, which are represented by
@@ -2626,11 +2595,6 @@ create_component_ref_by_pieces (basic_block block, vn_reference_t ref,
     case CONST_DECL:
     case RESULT_DECL:
     case FUNCTION_DECL:
-      /* For ADDR_EXPR in a CALL_EXPR, op0 is actually the entire
-	 ADDR_EXPR, not just it's operand.  */
-    case ADDR_EXPR:
-      if (currop->opcode == ADDR_EXPR)
-	gcc_assert (currop->op0 != NULL);
       return currop->op0;
 
     default:
@@ -2638,6 +2602,26 @@ create_component_ref_by_pieces (basic_block block, vn_reference_t ref,
     }
 }
 
+/* For COMPONENT_REF's and ARRAY_REF's, we can't have any intermediates for the
+   COMPONENT_REF or INDIRECT_REF or ARRAY_REF portion, because we'd end up with
+   trying to rename aggregates into ssa form directly, which is a no no.
+
+   Thus, this routine doesn't create temporaries, it just builds a
+   single access expression for the array, calling
+   find_or_generate_expression to build the innermost pieces.
+
+   This function is a subroutine of create_expression_by_pieces, and
+   should not be called on it's own unless you really know what you
+   are doing.  */
+
+static tree
+create_component_ref_by_pieces (basic_block block, vn_reference_t ref,
+				gimple_seq *stmts, gimple domstmt)
+{
+  unsigned int op = 0;
+  return create_component_ref_by_pieces_1 (block, ref, &op, stmts, domstmt);
+}
+
 /* Find a leader for an expression, or generate one using
    create_expression_by_pieces if it's ANTIC but
    complex.
@@ -2743,8 +2727,7 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
     case REFERENCE:
       {
 	vn_reference_t ref = PRE_EXPR_REFERENCE (expr);
-	folded = create_component_ref_by_pieces (block, ref, 0, stmts,
-						 domstmt, false);
+	folded = create_component_ref_by_pieces (block, ref, stmts, domstmt);
       }
       break;
     case NARY:
@@ -3616,6 +3599,8 @@ compute_avail (void)
 		      add_to_exp_gen (block, vro->op0);
 		    if (vro->op1 && TREE_CODE (vro->op1) == SSA_NAME)
 		      add_to_exp_gen (block, vro->op1);
+		    if (vro->op2 && TREE_CODE (vro->op2) == SSA_NAME)
+		      add_to_exp_gen (block, vro->op2);
 		  }
 		result = (pre_expr) pool_alloc (pre_expr_pool);
 		result->kind = REFERENCE;
@@ -3688,6 +3673,8 @@ compute_avail (void)
 			    add_to_exp_gen (block, vro->op0);
 			  if (vro->op1 && TREE_CODE (vro->op1) == SSA_NAME)
 			    add_to_exp_gen (block, vro->op1);
+			  if (vro->op2 && TREE_CODE (vro->op2) == SSA_NAME)
+			    add_to_exp_gen (block, vro->op2);
 			}
 		      result = (pre_expr) pool_alloc (pre_expr_pool);
 		      result->kind = REFERENCE;
diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c
index 42d394f55400..f6492bdafd83 100644
--- a/gcc/tree-ssa-sccvn.c
+++ b/gcc/tree-ssa-sccvn.c
@@ -557,7 +557,7 @@ shared_vuses_from_stmt (gimple stmt)
 /* Copy the operations present in load/store REF into RESULT, a vector of
    vn_reference_op_s's.  */
 
-static void
+void
 copy_reference_ops_from_ref (tree ref, VEC(vn_reference_op_s, heap) **result)
 {
   if (TREE_CODE (ref) == TARGET_MEM_REF)
@@ -646,6 +646,13 @@ copy_reference_ops_from_ref (tree ref, VEC(vn_reference_op_s, heap) **result)
 	case SSA_NAME:
 	  temp.op0 = ref;
 	  break;
+	case ADDR_EXPR:
+	  if (is_gimple_min_invariant (ref))
+	    {
+	      temp.op0 = ref;
+	      break;
+	    }
+	  /* Fallthrough.  */
 	  /* These are only interesting for their operands, their
 	     existence, and their type.  They will never be the last
 	     ref in the chain of references (IE they require an
@@ -654,15 +661,15 @@ copy_reference_ops_from_ref (tree ref, VEC(vn_reference_op_s, heap) **result)
 	case IMAGPART_EXPR:
 	case REALPART_EXPR:
 	case VIEW_CONVERT_EXPR:
-	case ADDR_EXPR:
 	  break;
 	default:
 	  gcc_unreachable ();
-
 	}
       VEC_safe_push (vn_reference_op_s, heap, *result, &temp);
 
-      if (REFERENCE_CLASS_P (ref) || TREE_CODE (ref) == ADDR_EXPR)
+      if (REFERENCE_CLASS_P (ref)
+	  || (TREE_CODE (ref) == ADDR_EXPR
+	      && !is_gimple_min_invariant (ref)))
 	ref = TREE_OPERAND (ref, 0);
       else
 	ref = NULL_TREE;
@@ -677,7 +684,6 @@ copy_reference_ops_from_call (gimple call,
 			      VEC(vn_reference_op_s, heap) **result)
 {
   vn_reference_op_s temp;
-  tree callfn;
   unsigned i;
 
   /* Copy the call_expr opcode, type, function being called, and
@@ -685,33 +691,15 @@ copy_reference_ops_from_call (gimple call,
   memset (&temp, 0, sizeof (temp));
   temp.type = gimple_call_return_type (call);
   temp.opcode = CALL_EXPR;
+  temp.op0 = gimple_call_fn (call);
   VEC_safe_push (vn_reference_op_s, heap, *result, &temp);
 
-  /* FIXME tuples
-     We make no attempt to simplify the called function because
-     the typical &FUNCTION_DECL form is also used in function pointer
-     cases that become constant.  If we simplify the original to
-     FUNCTION_DECL but not the function pointer case (which can
-     happen because we have no fold functions that operate on
-     vn_reference_t), we will claim they are not equivalent.
-
-     An example of this behavior can be see if CALL_EXPR_FN below is
-     replaced with get_callee_fndecl and gcc.dg/tree-ssa/ssa-pre-13.c
-     is compiled.  */
-  callfn = gimple_call_fn (call);
-  temp.type = TREE_TYPE (callfn);
-  temp.opcode = TREE_CODE (callfn);
-  temp.op0 = callfn;
-  VEC_safe_push (vn_reference_op_s, heap, *result, &temp);
-
+  /* Copy the call arguments.  As they can be references as well,
+     just chain them together.  */
   for (i = 0; i < gimple_call_num_args (call); ++i)
     {
       tree callarg = gimple_call_arg (call, i);
-      memset (&temp, 0, sizeof (temp));
-      temp.type = TREE_TYPE (callarg);
-      temp.opcode = TREE_CODE (callarg);
-      temp.op0 = callarg;
-      VEC_safe_push (vn_reference_op_s, heap, *result, &temp);
+      copy_reference_ops_from_ref (callarg, result);
     }
   return;
 }
diff --git a/gcc/tree-ssa-sccvn.h b/gcc/tree-ssa-sccvn.h
index 923be1931630..d648cd9bb94b 100644
--- a/gcc/tree-ssa-sccvn.h
+++ b/gcc/tree-ssa-sccvn.h
@@ -174,6 +174,7 @@ vn_nary_op_t vn_nary_op_insert_stmt (gimple, tree);
 vn_nary_op_t vn_nary_op_insert_pieces (unsigned int, enum tree_code,
 				       tree, tree, tree, tree,
 				       tree, tree, unsigned int);
+void copy_reference_ops_from_ref (tree, VEC(vn_reference_op_s, heap) **);
 void copy_reference_ops_from_call (gimple, VEC(vn_reference_op_s, heap) **);
 tree vn_reference_lookup_pieces (VEC (tree, gc) *,
 				 VEC (vn_reference_op_s, heap) *,
-- 
GitLab