[PATCH][mem-ref2] Fixup forwprop some more

Richard Guenther rguenther@suse.de
Tue Mar 30 15:36:00 GMT 2010


This re-instantiates more propagation into dereferences as well
as it adds propagation through constant pointer adjustments - one
new feature possible with the introduction of MEM_REF.  With
that we now can fold

<bb 3>:
  BM_tab_5 = BM_tab_1 + -4;
  *BM_tab_5 = j_6(D);
  BM_tab_7 = BM_tab_5 + -4;
  *BM_tab_7 = j_6(D);
  BM_tab_8 = BM_tab_7 + -4;
  *BM_tab_8 = j_6(D);
  BM_tab_9 = BM_tab_8 + -4;
  *BM_tab_9 = j_6(D);

to

<bb 3>:
  BM_tab_5 = BM_tab_1 + -4;
  MEM[(int *)BM_tab_1 + -4B] = j_6(D);
  MEM[(int *)BM_tab_1 + -8B] = j_6(D);
  MEM[(int *)BM_tab_1 + -12B] = j_6(D);
  BM_tab_9 = &MEM[(void *)BM_tab_1 + -16B];
  MEM[(int *)BM_tab_1 + -16B] = j_6(D);

allowing for better alias analysis and more compact code.

With that (us starting to adjust the constant offset in more cases)
we run into TBAA issues with the oracle which assumes that the
pointer dereference aligns with the access type - something that
is not exactly true in its current form, so I have disabled that
code until I have time to thoroughly think these issues through.
We should be able to recover at least parts here.

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

I do have some SCCVN adjustments pending and then will look into
adjusting testcases that now falsely FAIL (possibly munging them
into something that will pass both on the trunk and the branch,
avoiding the scan of dumps where possible).

Richard.

2010-03-30  Richard Guenther  <rguenther@suse.de>

	* tree-ssa-ccp.c (may_propagate_address_into_dereference):
	Handle MEM_REF.
	* tree-ssa-forwprop.c (forward_propagate_addr_expr_1):
	Propagate through constant pointer adjustments.
	Re-instantiate more cases to propagate into dereferences.
	(tree_ssa_forward_propagate_single_use_vars): Adjust
	accordingly.
	* tree-ssa-alias.c (indirect_ref_may_alias_decl_p): Fix
	offset check.  Disable fancy access-path based TBAA disambiguation.
	(indirect_refs_may_alias_p): Likewise.

Index: mem-ref2/gcc/tree-ssa-ccp.c
===================================================================
*** mem-ref2.orig/gcc/tree-ssa-ccp.c	2010-03-30 14:52:56.000000000 +0200
--- mem-ref2/gcc/tree-ssa-ccp.c	2010-03-30 14:53:39.000000000 +0200
*************** ccp_visit_phi_node (gimple phi)
*** 888,894 ****
  bool
  may_propagate_address_into_dereference (tree addr, tree deref)
  {
!   gcc_assert (INDIRECT_REF_P (deref)
  	      && TREE_CODE (addr) == ADDR_EXPR);
  
    /* Don't propagate if ADDR's operand has incomplete type.  */
--- 888,894 ----
  bool
  may_propagate_address_into_dereference (tree addr, tree deref)
  {
!   gcc_assert (TREE_CODE (deref) == MEM_REF
  	      && TREE_CODE (addr) == ADDR_EXPR);
  
    /* Don't propagate if ADDR's operand has incomplete type.  */
Index: mem-ref2/gcc/tree-ssa-forwprop.c
===================================================================
*** mem-ref2.orig/gcc/tree-ssa-forwprop.c	2010-03-30 14:52:56.000000000 +0200
--- mem-ref2/gcc/tree-ssa-forwprop.c	2010-03-30 15:34:00.000000000 +0200
*************** forward_propagate_addr_expr_1 (tree name
*** 767,772 ****
--- 767,808 ----
        return true;
      }
  
+   /* Propagate through constant pointer adjustments.  */
+   if (TREE_CODE (lhs) == SSA_NAME
+       && rhs_code == POINTER_PLUS_EXPR
+       && rhs == name
+       && TREE_CODE (gimple_assign_rhs2 (use_stmt)) == INTEGER_CST)
+     {
+       tree new_def_rhs;
+       /* As we come here with non-invariant addresses in def_rhs we need
+          to make sure we can build a valid constant offsetted address
+ 	 for further propagation.  Simply rely on fold building that
+ 	 and check after the fact.  */
+       new_def_rhs = fold_build2 (MEM_REF, TREE_TYPE (TREE_TYPE (rhs)),
+ 				 def_rhs,
+ 				 fold_convert (ptr_type_node,
+ 					       gimple_assign_rhs2 (use_stmt)));
+       if (TREE_CODE (new_def_rhs) == MEM_REF
+ 	  && TREE_CODE (TREE_OPERAND (new_def_rhs, 0)) == ADDR_EXPR
+ 	  && !DECL_P (TREE_OPERAND (TREE_OPERAND (new_def_rhs, 0), 0))
+ 	  && !CONSTANT_CLASS_P (TREE_OPERAND (TREE_OPERAND (new_def_rhs, 0), 0)))
+ 	return false;
+       new_def_rhs = build_fold_addr_expr_with_type (new_def_rhs,
+ 						    TREE_TYPE (rhs));
+ 
+       /* Recurse.  If we could propagate into all uses of lhs do not
+ 	 bother to replace into the current use but just pretend we did.  */
+       if (TREE_CODE (new_def_rhs) == ADDR_EXPR
+ 	  && forward_propagate_addr_expr (lhs, new_def_rhs))
+ 	return true;
+ 
+       gimple_assign_set_rhs_with_ops (use_stmt_gsi, TREE_CODE (new_def_rhs),
+ 				      new_def_rhs, NULL_TREE);
+       gcc_assert (gsi_stmt (*use_stmt_gsi) == use_stmt);
+       update_stmt (use_stmt);
+       return true;
+     }
+ 
    /* Now strip away any outer COMPONENT_REF/ARRAY_REF nodes from the LHS.
       ADDR_EXPR will not appear on the LHS.  */
    lhsp = gimple_assign_lhs_ptr (use_stmt);
*************** forward_propagate_addr_expr_1 (tree name
*** 779,785 ****
    if (TREE_CODE (lhs) == MEM_REF
        && TREE_OPERAND (lhs, 0) == name)
      {
!       if (is_gimple_min_invariant (def_rhs))
  	{
  	  TREE_OPERAND (lhs, 0) = unshare_expr (def_rhs);
  	  fold_stmt_inplace (use_stmt);
--- 815,867 ----
    if (TREE_CODE (lhs) == MEM_REF
        && TREE_OPERAND (lhs, 0) == name)
      {
!       /* If *def_rhs has a MEM base we could transfer the alias set of the
!          original MEM.  Likewise for a DECL base we could create a new MEM base
! 	 with the alias set of the original MEM.  For a plain MEM
! 	 *def_rhs we could also embed a conversion.  */
!       tree *def_rhs_basep = &TREE_OPERAND (def_rhs, 0);
!       while (handled_component_p (*def_rhs_basep))
! 	def_rhs_basep = &TREE_OPERAND (*def_rhs_basep, 0);
!       /* Replace MEM[name, 0] with *def_rhs if possible.  That should
!          preserve as much of the original trees as possible.  */
!       if (integer_zerop (TREE_OPERAND (lhs, 1))
! 	  && may_propagate_address_into_dereference (def_rhs, lhs)
! 	  && (lhsp != gimple_assign_lhs_ptr (use_stmt)
! 	      || useless_type_conversion_p
! 	           (TREE_TYPE (TREE_OPERAND (def_rhs, 0)), TREE_TYPE (rhs))))
! 	{
! 	  tree subst_rhs;
! 	  if (TREE_CODE (*def_rhs_basep) == MEM_REF
! 	      && (TREE_TYPE (TREE_OPERAND (*def_rhs_basep, 1))
! 		  != TREE_TYPE (TREE_OPERAND (lhs, 1))))
! 	    {
! 	      tree saved = TREE_OPERAND (*def_rhs_basep, 1);
! 	      TREE_OPERAND (*def_rhs_basep, 1)
! 		= fold_convert (TREE_TYPE (TREE_OPERAND (lhs, 1)),
! 				TREE_OPERAND (*def_rhs_basep, 1));
! 	      subst_rhs = unshare_expr (TREE_OPERAND (def_rhs, 0));
! 	      TREE_OPERAND (*def_rhs_basep, 1) = saved;
! 	    }
! 	  else if (TREE_CODE (*def_rhs_basep) != MEM_REF)
! 	    {
! 	      tree saved = *def_rhs_basep;
! 	      *def_rhs_basep = build2 (MEM_REF, TREE_TYPE (saved),
! 				       build_fold_addr_expr (saved),
! 				       TREE_OPERAND (lhs, 1));
! 	      subst_rhs = unshare_expr (TREE_OPERAND (def_rhs, 0));
! 	      *def_rhs_basep = saved;
! 	    }
! 	  else
! 	    subst_rhs = unshare_expr (TREE_OPERAND (def_rhs, 0));
! 	  *lhsp = subst_rhs;
! 	  fold_stmt_inplace (use_stmt);
! 	  tidy_after_forward_propagate_addr (use_stmt);
! 
! 	  /* Continue propagating into the RHS if this was not the only use.  */
! 	  if (single_use_p)
! 	    return true;
! 	}
!       else if (is_gimple_min_invariant (def_rhs))
  	{
  	  TREE_OPERAND (lhs, 0) = unshare_expr (def_rhs);
  	  fold_stmt_inplace (use_stmt);
*************** forward_propagate_addr_expr_1 (tree name
*** 807,819 ****
    /* Now see if the RHS node is a MEM_REF using NAME.  If so,
       propagate the ADDR_EXPR into the use of NAME and fold the result.  */
    if (TREE_CODE (rhs) == MEM_REF
!       && TREE_OPERAND (rhs, 0) == name
!       && is_gimple_min_invariant (def_rhs))
      {
!       TREE_OPERAND (rhs, 0) = unshare_expr (def_rhs);
!       fold_stmt_inplace (use_stmt);
!       tidy_after_forward_propagate_addr (use_stmt);
!       return res;
      }
  
    /* If the use of the ADDR_EXPR is not a POINTER_PLUS_EXPR, there
--- 889,943 ----
    /* Now see if the RHS node is a MEM_REF using NAME.  If so,
       propagate the ADDR_EXPR into the use of NAME and fold the result.  */
    if (TREE_CODE (rhs) == MEM_REF
!       && TREE_OPERAND (rhs, 0) == name)
      {
!       /* If *def_rhs has a MEM base we could transfer the alias set of the
!          original MEM.  Likewise for a DECL base we could create a new MEM base
! 	 with the alias set of the original MEM.  For a plain MEM
! 	 *def_rhs we could also embed a conversion.  */
!       tree *def_rhs_basep = &TREE_OPERAND (def_rhs, 0);
!       while (handled_component_p (*def_rhs_basep))
! 	def_rhs_basep = &TREE_OPERAND (*def_rhs_basep, 0);
!       /* Replace MEM[name, 0] with *def_rhs if possible.  That should
!          preserve as much of the original trees as possible.  */
!       if (integer_zerop (TREE_OPERAND (rhs, 1))
! 	  && may_propagate_address_into_dereference (def_rhs, rhs))
! 	{
! 	  tree subst_rhs;
! 	  if (TREE_CODE (*def_rhs_basep) == MEM_REF
! 	      && (TREE_TYPE (TREE_OPERAND (*def_rhs_basep, 1))
! 		  != TREE_TYPE (TREE_OPERAND (rhs, 1))))
! 	    {
! 	      tree saved = TREE_OPERAND (*def_rhs_basep, 1);
! 	      TREE_OPERAND (*def_rhs_basep, 1)
! 		= fold_convert (TREE_TYPE (TREE_OPERAND (rhs, 1)),
! 				TREE_OPERAND (*def_rhs_basep, 1));
! 	      subst_rhs = unshare_expr (TREE_OPERAND (def_rhs, 0));
! 	      TREE_OPERAND (*def_rhs_basep, 1) = saved;
! 	    }
! 	  else if (TREE_CODE (*def_rhs_basep) != MEM_REF)
! 	    {
! 	      tree saved = *def_rhs_basep;
! 	      *def_rhs_basep = build2 (MEM_REF, TREE_TYPE (saved),
! 				       build_fold_addr_expr (saved),
! 				       TREE_OPERAND (rhs, 1));
! 	      subst_rhs = unshare_expr (TREE_OPERAND (def_rhs, 0));
! 	      *def_rhs_basep = saved;
! 	    }
! 	  else
! 	    subst_rhs = unshare_expr (TREE_OPERAND (def_rhs, 0));
! 	  *rhsp = subst_rhs;
! 	  fold_stmt_inplace (use_stmt);
! 	  tidy_after_forward_propagate_addr (use_stmt);
! 	  return res;
! 	}
!       else if (is_gimple_min_invariant (def_rhs))
! 	{
! 	  TREE_OPERAND (rhs, 0) = unshare_expr (def_rhs);
! 	  fold_stmt_inplace (use_stmt);
! 	  tidy_after_forward_propagate_addr (use_stmt);
! 	  return res;
! 	}
      }
  
    /* If the use of the ADDR_EXPR is not a POINTER_PLUS_EXPR, there
*************** tree_ssa_forward_propagate_single_use_va
*** 1241,1253 ****
  		  else
  		    gsi_next (&gsi);
  		}
! 	      else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR
! 		       && is_gimple_min_invariant (rhs))
  		{
! 		  /* Make sure to fold &a[0] + off_1 here.  */
! 		  fold_stmt_inplace (stmt);
! 		  update_stmt (stmt);
! 		  if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
  		    gsi_next (&gsi);
  		}
  	      else if ((gimple_assign_rhs_code (stmt) == BIT_NOT_EXPR
--- 1365,1396 ----
  		  else
  		    gsi_next (&gsi);
  		}
! 	      else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
  		{
! 		  if (TREE_CODE (gimple_assign_rhs2 (stmt)) == INTEGER_CST
! 		      /* ???  Better adjust the interface to that function
! 			 instead of building new trees here.  */
! 		      && forward_propagate_addr_expr (lhs,
! 						      build1 (ADDR_EXPR,
! 							      TREE_TYPE (rhs),
! 							      build2 (MEM_REF,
! 								      TREE_TYPE (TREE_TYPE (rhs)),
! 								      rhs,
! 								      fold_convert (ptr_type_node, gimple_assign_rhs2 (stmt))))))
! 		    {
! 		      release_defs (stmt);
! 		      todoflags |= TODO_remove_unused_locals;
! 		      gsi_remove (&gsi, true);
! 		    }
! 		  else if (is_gimple_min_invariant (rhs))
! 		    {
! 		      /* Make sure to fold &a[0] + off_1 here.  */
! 		      fold_stmt_inplace (stmt);
! 		      update_stmt (stmt);
! 		      if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
! 			gsi_next (&gsi);
! 		    }
! 		  else
  		    gsi_next (&gsi);
  		}
  	      else if ((gimple_assign_rhs_code (stmt) == BIT_NOT_EXPR
Index: mem-ref2/gcc/tree-ssa-alias.c
===================================================================
*** mem-ref2.orig/gcc/tree-ssa-alias.c	2010-03-30 14:52:56.000000000 +0200
--- mem-ref2/gcc/tree-ssa-alias.c	2010-03-30 14:53:39.000000000 +0200
*************** same_type_for_tbaa (tree type1, tree typ
*** 564,569 ****
--- 564,570 ----
    return 0;
  }
  
+ #if 0
  /* Determine if the two component references REF1 and REF2 which are
     based on access types TYPE1 and TYPE2 and of which at least one is based
     on an indirect reference may alias.  */
*************** aliasing_component_refs_p (tree ref1, tr
*** 620,625 ****
--- 621,627 ----
       only alias if either B1 is in B2.path2 or B2 is in B1.path1.  */
    return false;
  }
+ #endif
  
  /* Return true if two memory references based on the variables BASE1
     and BASE2 constrained to [OFFSET1, OFFSET1 + MAX_SIZE1) and
*************** decl_refs_may_alias_p (tree base1,
*** 650,659 ****
     if non-NULL are the complete memory reference trees.  */
  
  static bool
! indirect_ref_may_alias_decl_p (tree ref1, tree base1,
! 			       HOST_WIDE_INT offset1, HOST_WIDE_INT max_size1,
  			       alias_set_type base1_alias_set,
! 			       tree ref2, tree base2,
  			       HOST_WIDE_INT offset2, HOST_WIDE_INT max_size2,
  			       alias_set_type base2_alias_set)
  {
--- 652,662 ----
     if non-NULL are the complete memory reference trees.  */
  
  static bool
! indirect_ref_may_alias_decl_p (tree ref1 ATTRIBUTE_UNUSED, tree base1,
! 			       HOST_WIDE_INT offset1,
! 			       HOST_WIDE_INT max_size1 ATTRIBUTE_UNUSED,
  			       alias_set_type base1_alias_set,
! 			       tree ref2 ATTRIBUTE_UNUSED, tree base2,
  			       HOST_WIDE_INT offset2, HOST_WIDE_INT max_size2,
  			       alias_set_type base2_alias_set)
  {
*************** indirect_ref_may_alias_decl_p (tree ref1
*** 665,672 ****
       (the pointer base cannot validly point to an offset less than zero
       of the variable).
       They also cannot alias if the pointer may not point to the decl.  */
!   if (max_size2 != -1
!       && !ranges_overlap_p (offset1, max_size1, 0, offset2 + max_size2))
      return false;
    if (!ptr_deref_may_alias_decl_p (ptr1, base2))
      return false;
--- 668,674 ----
       (the pointer base cannot validly point to an offset less than zero
       of the variable).
       They also cannot alias if the pointer may not point to the decl.  */
!   if (!ranges_overlap_p (MAX (0, offset1), -1, offset2, max_size2))
      return false;
    if (!ptr_deref_may_alias_decl_p (ptr1, base2))
      return false;
*************** indirect_ref_may_alias_decl_p (tree ref1
*** 688,699 ****
--- 690,704 ----
    if (base2_alias_set == -1)
      base2_alias_set = get_alias_set (base2);
  
+   /* See indirect_refs_may_alias_p.  */
+ #if 0
    /* If both references are through the same type, they do not alias
       if the accesses do not overlap.  This does extra disambiguation
       for mixed/pointer accesses but requires strict aliasing.  */
    if (same_type_for_tbaa (TREE_TYPE (ptrtype1),
  			  TREE_TYPE (base2)) == 1)
      return ranges_overlap_p (offset1, max_size1, offset2, max_size2);
+ #endif
  
    /* The only way to access a variable is through a pointer dereference
       of the same alias set or a subset of it.  */
*************** indirect_ref_may_alias_decl_p (tree ref1
*** 701,706 ****
--- 706,713 ----
        && !alias_set_subset_of (base1_alias_set, base2_alias_set))
      return false;
  
+   /* See indirect_refs_may_alias_p.  */
+ #if 0
    /* Do access-path based disambiguation.  */
    if (ref1 && ref2
        && handled_component_p (ref1)
*************** indirect_ref_may_alias_decl_p (tree ref1
*** 709,714 ****
--- 716,722 ----
  				      offset1, max_size1,
  				      ref2, TREE_TYPE (base2),
  				      offset2, max_size2);
+ #endif
  
    return true;
  }
*************** indirect_ref_may_alias_decl_p (tree ref1
*** 721,730 ****
     if non-NULL are the complete memory reference trees. */
  
  static bool
! indirect_refs_may_alias_p (tree ref1, tree base1,
  			   HOST_WIDE_INT offset1, HOST_WIDE_INT max_size1,
  			   alias_set_type base1_alias_set,
! 			   tree ref2, tree base2,
  			   HOST_WIDE_INT offset2, HOST_WIDE_INT max_size2,
  			   alias_set_type base2_alias_set)
  {
--- 729,738 ----
     if non-NULL are the complete memory reference trees. */
  
  static bool
! indirect_refs_may_alias_p (tree ref1 ATTRIBUTE_UNUSED, tree base1,
  			   HOST_WIDE_INT offset1, HOST_WIDE_INT max_size1,
  			   alias_set_type base1_alias_set,
! 			   tree ref2 ATTRIBUTE_UNUSED, tree base2,
  			   HOST_WIDE_INT offset2, HOST_WIDE_INT max_size2,
  			   alias_set_type base2_alias_set)
  {
*************** indirect_refs_may_alias_p (tree ref1, tr
*** 763,780 ****
--- 771,798 ----
    if (base2_alias_set == 0)
      return true;
  
+   /* The following no longer holds true.  The type for TBAA purposes
+      is the type of operand 1 of a MEM_REF, but that doesn't mean
+      that operand 0 points to an object of that type - but instead
+      it might still point anywhere inside of that object (if
+      adjusted by operand 1, the pointer itself may point even outside
+      of the object).  */
+ #if 0
    /* If both references are through the same type, they do not alias
       if the accesses do not overlap.  This does extra disambiguation
       for mixed/pointer accesses but requires strict aliasing.  */
    if (same_type_for_tbaa (TREE_TYPE (ptrtype1),
  			  TREE_TYPE (ptrtype2)) == 1)
      return ranges_overlap_p (offset1, max_size1, offset2, max_size2);
+ #endif
  
    /* Do type-based disambiguation.  */
    if (base1_alias_set != base2_alias_set
        && !alias_sets_conflict_p (base1_alias_set, base2_alias_set))
      return false;
  
+   /* For the same reason as above this won't work anymore.  */
+ #if 0
    /* Do access-path based disambiguation.  */
    if (ref1 && ref2
        && handled_component_p (ref1)
*************** indirect_refs_may_alias_p (tree ref1, tr
*** 783,788 ****
--- 801,807 ----
  				      offset1, max_size1,
  				      ref2, TREE_TYPE (ptrtype2),
  				      offset2, max_size2);
+ #endif
  
    return true;
  }



More information about the Gcc-patches mailing list