[PATCH] Fix PR36945, PRE and call-exprs

Richard Guenther rguenther@suse.de
Tue Jul 29 19:38:00 GMT 2008


This fixes value-numbering and re-constructing call expressions which
can have arguments with an arbitrary complicated reference structure.

Fixed by just using copy_reference_ops_from_ref and de-serializing
arguments on-the-fly.  For consistency I made invariant addresses
always serialized as a single reference op - this avoids touching
phi-translation and more.

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

Richard.

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.

Index: gcc/tree-ssa-sccvn.c
===================================================================
*** gcc/tree-ssa-sccvn.c.orig	2008-07-29 15:43:41.000000000 +0200
--- gcc/tree-ssa-sccvn.c	2008-07-29 18:10:27.000000000 +0200
*************** shared_vuses_from_stmt (gimple stmt)
*** 557,563 ****
  /* Copy the operations present in load/store REF into RESULT, a vector of
     vn_reference_op_s's.  */
  
! static void
  copy_reference_ops_from_ref (tree ref, VEC(vn_reference_op_s, heap) **result)
  {
    if (TREE_CODE (ref) == TARGET_MEM_REF)
--- 557,563 ----
  /* Copy the operations present in load/store REF into RESULT, a vector of
     vn_reference_op_s's.  */
  
! void
  copy_reference_ops_from_ref (tree ref, VEC(vn_reference_op_s, heap) **result)
  {
    if (TREE_CODE (ref) == TARGET_MEM_REF)
*************** copy_reference_ops_from_ref (tree ref, V
*** 646,651 ****
--- 646,658 ----
  	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
*************** copy_reference_ops_from_ref (tree ref, V
*** 654,668 ****
  	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)
  	ref = TREE_OPERAND (ref, 0);
        else
  	ref = NULL_TREE;
--- 661,675 ----
  	case IMAGPART_EXPR:
  	case REALPART_EXPR:
  	case VIEW_CONVERT_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
! 	      && !is_gimple_min_invariant (ref)))
  	ref = TREE_OPERAND (ref, 0);
        else
  	ref = NULL_TREE;
*************** copy_reference_ops_from_call (gimple cal
*** 677,683 ****
  			      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
--- 684,689 ----
*************** copy_reference_ops_from_call (gimple cal
*** 685,717 ****
    memset (&temp, 0, sizeof (temp));
    temp.type = gimple_call_return_type (call);
    temp.opcode = CALL_EXPR;
    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);
! 
    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);
      }
    return;
  }
--- 691,705 ----
    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);
  
!   /* 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);
!       copy_reference_ops_from_ref (callarg, result);
      }
    return;
  }
Index: gcc/tree-ssa-pre.c
===================================================================
*** gcc/tree-ssa-pre.c.orig	2008-07-29 15:43:41.000000000 +0200
--- gcc/tree-ssa-pre.c	2008-07-29 18:10:27.000000000 +0200
*************** static VEC(gimple,heap) *inserted_exprs;
*** 2421,2484 ****
     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.
  
-    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)
  {
    vn_reference_op_t currop = VEC_index (vn_reference_op_s, ref->operands,
! 					operand);
    tree genop;
    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++)
  	  {
! 	    args[i] = create_component_ref_by_pieces (block, ref,
! 						      operand + 2 + i, stmts,
! 						      domstmt, true);
  	  }
  	folded = build_call_array (currop->type,
! 				   TREE_CODE (declop->op0) == FUNCTION_DECL
! 				   ? build_fold_addr_expr (declop->op0)
! 				   : declop->op0,
  				   nargs, args);
  	free (args);
  	return folded;
        }
        break;
      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);
  	if (!genop0)
  	  return NULL_TREE;
  	folded = fold_build1 (currop->opcode, currop->type,
--- 2421,2476 ----
     to see which expressions need to be put into GC'able memory  */
  static VEC(gimple, heap) *need_creation;
  
! /* The actual worker for create_component_ref_by_pieces.  */
  
  static tree
! 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);
    tree genop;
+   ++*operand;
    switch (currop->opcode)
      {
      case CALL_EXPR:
        {
  	tree folded;
! 	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[nargs] = create_component_ref_by_pieces_1 (block, ref,
! 							    operand, stmts,
! 							    domstmt);
! 	    nargs++;
  	  }
  	folded = build_call_array (currop->type,
! 				   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_1 (block, ref,
! 							operand,
! 							stmts, domstmt);
  	if (!genop0)
  	  return NULL_TREE;
  	folded = fold_build1 (currop->opcode, currop->type,
*************** create_component_ref_by_pieces (basic_bl
*** 2490,2534 ****
      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);
  
! 	    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);
  	pre_expr op1expr = get_or_alloc_expr_for (currop->op0);
  	pre_expr op2expr = get_or_alloc_expr_for (currop->op1);
  	tree genop1;
--- 2482,2506 ----
      case MISALIGNED_INDIRECT_REF:
      case INDIRECT_REF:
        {
! 	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;
        }
        break;
      case BIT_FIELD_REF:
        {
  	tree folded;
! 	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;
*************** create_component_ref_by_pieces (basic_bl
*** 2553,2569 ****
      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);
  	if (!genop0)
  	  return NULL_TREE;
  	op1expr = get_or_alloc_expr_for (genop1);
--- 2525,2538 ----
      case ARRAY_RANGE_REF:
      case ARRAY_REF:
        {
  	tree genop0;
  	tree genop1 = currop->op0;
  	pre_expr op1expr;
  	tree genop2 = currop->op1;
  	pre_expr op2expr;
  	tree genop3;
! 	genop0 = create_component_ref_by_pieces_1 (block, ref, operand,
! 						   stmts, domstmt);
  	if (!genop0)
  	  return NULL_TREE;
  	op1expr = get_or_alloc_expr_for (genop1);
*************** create_component_ref_by_pieces (basic_bl
*** 2589,2596 ****
  	tree op1;
  	tree genop2 = currop->op1;
  	pre_expr op2expr;
! 	op0 = create_component_ref_by_pieces (block, ref, operand + 1,
! 					      stmts, domstmt, in_call);
  	if (!op0)
  	  return NULL_TREE;
  	/* op1 should be a FIELD_DECL, which are represented by
--- 2558,2565 ----
  	tree op1;
  	tree genop2 = currop->op1;
  	pre_expr op2expr;
! 	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
*************** create_component_ref_by_pieces (basic_bl
*** 2626,2636 ****
      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:
--- 2595,2600 ----
*************** create_component_ref_by_pieces (basic_bl
*** 2638,2643 ****
--- 2602,2627 ----
      }
  }
  
+ /* 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.
*************** create_expression_by_pieces (basic_block
*** 2743,2750 ****
      case REFERENCE:
        {
  	vn_reference_t ref = PRE_EXPR_REFERENCE (expr);
! 	folded = create_component_ref_by_pieces (block, ref, 0, stmts,
! 						 domstmt, false);
        }
        break;
      case NARY:
--- 2727,2733 ----
      case REFERENCE:
        {
  	vn_reference_t ref = PRE_EXPR_REFERENCE (expr);
! 	folded = create_component_ref_by_pieces (block, ref, stmts, domstmt);
        }
        break;
      case NARY:
*************** compute_avail (void)
*** 3616,3621 ****
--- 3599,3606 ----
  		      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;
*************** compute_avail (void)
*** 3688,3693 ****
--- 3673,3680 ----
  			    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;
Index: gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-18.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-18.c	2008-07-29 18:10:27.000000000 +0200
***************
*** 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" } } */
Index: gcc/tree-ssa-sccvn.h
===================================================================
*** gcc/tree-ssa-sccvn.h.orig	2008-07-29 18:10:06.000000000 +0200
--- gcc/tree-ssa-sccvn.h	2008-07-29 18:10:27.000000000 +0200
*************** vn_nary_op_t vn_nary_op_insert_stmt (gim
*** 174,179 ****
--- 174,180 ----
  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) *,



More information about the Gcc-patches mailing list