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]

Re: [PATCH] Fix PR52406


On Thu, 1 Mar 2012, Richard Guenther wrote:

> On Wed, 29 Feb 2012, Richard Guenther wrote:
> 
> > On Wed, 29 Feb 2012, Michael Matz wrote:
> > 
> > > Hi,
> > > 
> > > On Wed, 29 Feb 2012, Richard Guenther wrote:
> > > 
> > > > the whole base object - instead I mark the base MEM_REF of such accesses 
> > > > with TREE_NO_WARNING (ugh) and special-case for them in dr_may_alias_p.  
> > > 
> > > At least use a flag that isn't currently used for MEM_REF.  E.g. 
> > > addressable_flag, and make a new macro that checks for the tree being a 
> > > MEMREF to access it.
> > 
> > Ok, I'll use TREE_VISITED.  The alternative is to increase the size of
> > struct indices (and thus all data-refs) and have a separate flag.
> 
> As follows (also removes an unused entry in all data-refs and updates
> the docs).
> 
> Bootstrapped and tested on x86_64-unknown-linux-gnu, queued for stage1 / 
> 4.7.1.

And after more complaints I have just added a new flag to the dataref
instead.

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

Richard.

2012-03-02  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/52406
	* tree-data-ref.h: Update documentation about DR_BASE_OBJECT.
	(struct indices): Add unconstrained_base member.
	(struct dr_alias): Remove unused vops member.
	(DR_UNCONSTRAINED_BASE): New define.
	* tree-data-ref.c (dr_analyze_indices): For COMPONENT_REFs
	add indices to allow their disambiguation.  Make DR_BASE_OBJECT
	be an artificial access that covers the whole indexed object,
	or mark it with DR_UNCONSTRAINED_BASE if we cannot do so.  Canonicalize
	plain decl base-objects to their MEM_REF variant.
	(dr_may_alias_p): When the base-object of either data reference
	has unknown size use only points-to information.
	(compute_affine_dependence): Make dumps easier to read and
	more verbose.
	* tree-vect-data-ref.c (vector_alignment_reachable_p): Use
	DR_REF when looking for packed references.
	(vect_supportable_dr_alignment): Likewise.

	* gcc.dg/torture/pr52406.c: New testcase.

Index: gcc/tree-data-ref.h
===================================================================
*** gcc/tree-data-ref.h	(revision 184782)
--- gcc/tree-data-ref.h	(working copy)
*************** struct innermost_loop_behavior
*** 60,75 ****
  };
  
  /* Describes the evolutions of indices of the memory reference.  The indices
!    are indices of the ARRAY_REFs and the operands of INDIRECT_REFs.
!    For ARRAY_REFs, BASE_OBJECT is the reference with zeroed indices
!    (note that this reference does not have to be valid, if zero does not
!    belong to the range of the array; hence it is not recommended to use
!    BASE_OBJECT in any code generation).  For INDIRECT_REFs, the address is
!    set to the loop-invariant part of the address of the object, except for
!    the constant offset.  For the examples above,
  
!    base_object:        a[0].b[0][0]                   *(p + x + 4B * j_0)
     indices:            {j_0, +, 1}_2                  {16, +, 4}_2
  		       {i_0, +, 1}_1
  		       {j_0, +, 1}_2
  */
--- 60,76 ----
  };
  
  /* Describes the evolutions of indices of the memory reference.  The indices
!    are indices of the ARRAY_REFs, indexes in artificial dimensions
!    added for member selection of records and the operands of MEM_REFs.
!    BASE_OBJECT is the part of the reference that is loop-invariant
!    (note that this reference does not have to cover the whole object
!    being accessed, in which case UNCONSTRAINED_BASE is set; hence it is
!    not recommended to use BASE_OBJECT in any code generation).
!    For the examples above,
  
!    base_object:        a                              *(p + x + 4B * j_0)
     indices:            {j_0, +, 1}_2                  {16, +, 4}_2
+ 		       4
  		       {i_0, +, 1}_1
  		       {j_0, +, 1}_2
  */
*************** struct indices
*** 81,98 ****
  
    /* A list of chrecs.  Access functions of the indices.  */
    VEC(tree,heap) *access_fns;
  };
  
  struct dr_alias
  {
    /* The alias information that should be used for new pointers to this
!      location.  SYMBOL_TAG is either a DECL or a SYMBOL_MEMORY_TAG.  */
    struct ptr_info_def *ptr_info;
- 
-   /* The set of virtual operands corresponding to this memory reference,
-      serving as a description of the alias information for the memory
-      reference.  This could be eliminated if we had alias oracle.  */
-   bitmap vops;
  };
  
  /* An integer vector.  A vector formally consists of an element of a vector
--- 82,98 ----
  
    /* A list of chrecs.  Access functions of the indices.  */
    VEC(tree,heap) *access_fns;
+ 
+   /* Whether BASE_OBJECT is an access representing the whole object
+      or whether the access could not be constrained.  */
+   bool unconstrained_base;
  };
  
  struct dr_alias
  {
    /* The alias information that should be used for new pointers to this
!      location.  */
    struct ptr_info_def *ptr_info;
  };
  
  /* An integer vector.  A vector formally consists of an element of a vector
*************** struct data_reference
*** 201,206 ****
--- 201,207 ----
  #define DR_STMT(DR)                (DR)->stmt
  #define DR_REF(DR)                 (DR)->ref
  #define DR_BASE_OBJECT(DR)         (DR)->indices.base_object
+ #define DR_UNCONSTRAINED_BASE(DR)  (DR)->indices.unconstrained_base
  #define DR_ACCESS_FNS(DR)	   (DR)->indices.access_fns
  #define DR_ACCESS_FN(DR, I)        VEC_index (tree, DR_ACCESS_FNS (DR), I)
  #define DR_NUM_DIMENSIONS(DR)      VEC_length (tree, DR_ACCESS_FNS (DR))
Index: gcc/tree-data-ref.c
===================================================================
*** gcc/tree-data-ref.c	(revision 184782)
--- gcc/tree-data-ref.c	(working copy)
*************** static void
*** 856,862 ****
  dr_analyze_indices (struct data_reference *dr, loop_p nest, loop_p loop)
  {
    VEC (tree, heap) *access_fns = NULL;
!   tree ref, *aref, op;
    tree base, off, access_fn;
    basic_block before_loop;
  
--- 856,862 ----
  dr_analyze_indices (struct data_reference *dr, loop_p nest, loop_p loop)
  {
    VEC (tree, heap) *access_fns = NULL;
!   tree ref, op;
    tree base, off, access_fn;
    basic_block before_loop;
  
*************** dr_analyze_indices (struct data_referenc
*** 869,875 ****
        return;
      }
  
!   ref = unshare_expr (DR_REF (dr));
    before_loop = block_before_loop (nest);
  
    /* REALPART_EXPR and IMAGPART_EXPR can be handled like accesses
--- 869,875 ----
        return;
      }
  
!   ref = DR_REF (dr);
    before_loop = block_before_loop (nest);
  
    /* REALPART_EXPR and IMAGPART_EXPR can be handled like accesses
*************** dr_analyze_indices (struct data_referenc
*** 887,947 ****
      }
  
    /* Analyze access functions of dimensions we know to be independent.  */
!   aref = &ref;
!   while (handled_component_p (*aref))
      {
!       if (TREE_CODE (*aref) == ARRAY_REF)
  	{
! 	  op = TREE_OPERAND (*aref, 1);
  	  access_fn = analyze_scalar_evolution (loop, op);
  	  access_fn = instantiate_scev (before_loop, loop, access_fn);
  	  VEC_safe_push (tree, heap, access_fns, access_fn);
- 	  /* For ARRAY_REFs the base is the reference with the index replaced
- 	     by zero if we can not strip it as the outermost component.  */
- 	  if (*aref == ref)
- 	    {
- 	      *aref = TREE_OPERAND (*aref, 0);
- 	      continue;
- 	    }
- 	  else
- 	    TREE_OPERAND (*aref, 1) = build_int_cst (TREE_TYPE (op), 0);
  	}
  
!       aref = &TREE_OPERAND (*aref, 0);
      }
  
    /* If the address operand of a MEM_REF base has an evolution in the
       analyzed nest, add it as an additional independent access-function.  */
!   if (TREE_CODE (*aref) == MEM_REF)
      {
!       op = TREE_OPERAND (*aref, 0);
        access_fn = analyze_scalar_evolution (loop, op);
        access_fn = instantiate_scev (before_loop, loop, access_fn);
        if (TREE_CODE (access_fn) == POLYNOMIAL_CHREC)
  	{
  	  tree orig_type;
  	  base = initial_condition (access_fn);
  	  orig_type = TREE_TYPE (base);
  	  STRIP_USELESS_TYPE_CONVERSION (base);
  	  split_constant_offset (base, &base, &off);
  	  /* Fold the MEM_REF offset into the evolutions initial
  	     value to make more bases comparable.  */
! 	  if (!integer_zerop (TREE_OPERAND (*aref, 1)))
  	    {
  	      off = size_binop (PLUS_EXPR, off,
! 				fold_convert (ssizetype,
! 					      TREE_OPERAND (*aref, 1)));
! 	      TREE_OPERAND (*aref, 1)
! 		= build_int_cst (TREE_TYPE (TREE_OPERAND (*aref, 1)), 0);
  	    }
  	  access_fn = chrec_replace_initial_condition
  	      (access_fn, fold_convert (orig_type, off));
! 	  *aref = fold_build2_loc (EXPR_LOCATION (*aref),
! 				   MEM_REF, TREE_TYPE (*aref),
! 				   base, TREE_OPERAND (*aref, 1));
  	  VEC_safe_push (tree, heap, access_fns, access_fn);
  	}
      }
  
    DR_BASE_OBJECT (dr) = ref;
    DR_ACCESS_FNS (dr) = access_fns;
--- 887,970 ----
      }
  
    /* Analyze access functions of dimensions we know to be independent.  */
!   while (handled_component_p (ref))
      {
!       if (TREE_CODE (ref) == ARRAY_REF)
  	{
! 	  op = TREE_OPERAND (ref, 1);
  	  access_fn = analyze_scalar_evolution (loop, op);
  	  access_fn = instantiate_scev (before_loop, loop, access_fn);
  	  VEC_safe_push (tree, heap, access_fns, access_fn);
  	}
+       else if (TREE_CODE (ref) == COMPONENT_REF
+ 	       && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 0))) == RECORD_TYPE)
+ 	{
+ 	  /* For COMPONENT_REFs of records (but not unions!) use the
+ 	     FIELD_DECL offset as constant access function so we can
+ 	     disambiguate a[i].f1 and a[i].f2.  */
+ 	  tree off = component_ref_field_offset (ref);
+ 	  off = size_binop (PLUS_EXPR,
+ 			    size_binop (MULT_EXPR,
+ 					fold_convert (bitsizetype, off),
+ 					bitsize_int (BITS_PER_UNIT)),
+ 			    DECL_FIELD_BIT_OFFSET (TREE_OPERAND (ref, 1)));
+ 	  VEC_safe_push (tree, heap, access_fns, off);
+ 	}
+       else
+ 	/* If we have an unhandled component we could not translate
+ 	   to an access function stop analyzing.  We have determined
+ 	   our base object in this case.  */
+ 	break;
  
!       ref = TREE_OPERAND (ref, 0);
      }
  
    /* If the address operand of a MEM_REF base has an evolution in the
       analyzed nest, add it as an additional independent access-function.  */
!   if (TREE_CODE (ref) == MEM_REF)
      {
!       op = TREE_OPERAND (ref, 0);
        access_fn = analyze_scalar_evolution (loop, op);
        access_fn = instantiate_scev (before_loop, loop, access_fn);
        if (TREE_CODE (access_fn) == POLYNOMIAL_CHREC)
  	{
  	  tree orig_type;
+ 	  tree memoff = TREE_OPERAND (ref, 1);
  	  base = initial_condition (access_fn);
  	  orig_type = TREE_TYPE (base);
  	  STRIP_USELESS_TYPE_CONVERSION (base);
  	  split_constant_offset (base, &base, &off);
  	  /* Fold the MEM_REF offset into the evolutions initial
  	     value to make more bases comparable.  */
! 	  if (!integer_zerop (memoff))
  	    {
  	      off = size_binop (PLUS_EXPR, off,
! 				fold_convert (ssizetype, memoff));
! 	      memoff = build_int_cst (TREE_TYPE (memoff), 0);
  	    }
  	  access_fn = chrec_replace_initial_condition
  	      (access_fn, fold_convert (orig_type, off));
! 	  /* ???  This is still not a suitable base object for
! 	     dr_may_alias_p - the base object needs to be an
! 	     access that covers the object as whole.  With
! 	     an evolution in the pointer this cannot be
! 	     guaranteed.
! 	     As a band-aid, mark the access so we can special-case
! 	     it in dr_may_alias_p.  */
! 	  ref = fold_build2_loc (EXPR_LOCATION (ref),
! 				 MEM_REF, TREE_TYPE (ref),
! 				 base, memoff);
! 	  DR_UNCONSTRAINED_BASE (dr) = true;
  	  VEC_safe_push (tree, heap, access_fns, access_fn);
  	}
      }
+   else if (DECL_P (ref))
+     {
+       /* Canonicalize DR_BASE_OBJECT to MEM_REF form.  */
+       ref = build2 (MEM_REF, TREE_TYPE (ref),
+ 		    build_fold_addr_expr (ref),
+ 		    build_int_cst (reference_alias_ptr_type (ref), 0));
+     }
  
    DR_BASE_OBJECT (dr) = ref;
    DR_ACCESS_FNS (dr) = access_fns;
*************** dr_may_alias_p (const struct data_refere
*** 1345,1350 ****
--- 1368,1394 ----
  	return false;
      }
  
+   /* If we had an evolution in a MEM_REF BASE_OBJECT we do not know
+      the size of the base-object.  So we cannot do any offset/overlap
+      based analysis but have to rely on points-to information only.  */
+   if (TREE_CODE (addr_a) == MEM_REF
+       && DR_UNCONSTRAINED_BASE (a))
+     {
+       if (TREE_CODE (addr_b) == MEM_REF
+ 	  && DR_UNCONSTRAINED_BASE (b))
+ 	return ptr_derefs_may_alias_p (TREE_OPERAND (addr_a, 0),
+ 				       TREE_OPERAND (addr_b, 0));
+       else
+ 	return ptr_derefs_may_alias_p (TREE_OPERAND (addr_a, 0),
+ 				       build_fold_addr_expr (addr_b));
+     }
+   else if (TREE_CODE (addr_b) == MEM_REF
+ 	   && DR_UNCONSTRAINED_BASE (b))
+     return ptr_derefs_may_alias_p (build_fold_addr_expr (addr_a),
+ 				   TREE_OPERAND (addr_b, 0));
+ 
+   /* Otherwise DR_BASE_OBJECT is an access that covers the whole object
+      that is being subsetted in the loop nest.  */
    if (DR_IS_WRITE (a) && DR_IS_WRITE (b))
      return refs_output_dependent_p (addr_a, addr_b);
    else if (DR_IS_READ (a) && DR_IS_WRITE (b))
*************** compute_affine_dependence (struct data_d
*** 4049,4059 ****
    if (dump_file && (dump_flags & TDF_DETAILS))
      {
        fprintf (dump_file, "(compute_affine_dependence\n");
!       fprintf (dump_file, "  (stmt_a = \n");
!       print_gimple_stmt (dump_file, DR_STMT (dra), 0, 0);
!       fprintf (dump_file, ")\n  (stmt_b = \n");
!       print_gimple_stmt (dump_file, DR_STMT (drb), 0, 0);
!       fprintf (dump_file, ")\n");
      }
  
    /* Analyze only when the dependence relation is not yet known.  */
--- 4093,4102 ----
    if (dump_file && (dump_flags & TDF_DETAILS))
      {
        fprintf (dump_file, "(compute_affine_dependence\n");
!       fprintf (dump_file, "  stmt_a: ");
!       print_gimple_stmt (dump_file, DR_STMT (dra), 0, TDF_SLIM);
!       fprintf (dump_file, "  stmt_b: ");
!       print_gimple_stmt (dump_file, DR_STMT (drb), 0, TDF_SLIM);
      }
  
    /* Analyze only when the dependence relation is not yet known.  */
*************** compute_affine_dependence (struct data_d
*** 4129,4135 ****
      }
  
    if (dump_file && (dump_flags & TDF_DETAILS))
!     fprintf (dump_file, ")\n");
  }
  
  /* Compute in DEPENDENCE_RELATIONS the data dependence graph for all
--- 4172,4185 ----
      }
  
    if (dump_file && (dump_flags & TDF_DETAILS))
!     {
!       if (DDR_ARE_DEPENDENT (ddr) == chrec_known)
! 	fprintf (dump_file, ") -> no dependence\n");
!       else if (DDR_ARE_DEPENDENT (ddr) == chrec_dont_know)
! 	fprintf (dump_file, ") -> dependence analysis failed\n");
!       else
! 	fprintf (dump_file, ")\n");
!     }
  }
  
  /* Compute in DEPENDENCE_RELATIONS the data dependence graph for all
Index: gcc/tree-vect-data-refs.c
===================================================================
*** gcc/tree-vect-data-refs.c	(revision 184782)
--- gcc/tree-vect-data-refs.c	(working copy)
*************** vector_alignment_reachable_p (struct dat
*** 1141,1151 ****
    if (!known_alignment_for_access_p (dr))
      {
        tree type = (TREE_TYPE (DR_REF (dr)));
!       tree ba = DR_BASE_OBJECT (dr);
!       bool is_packed = false;
! 
!       if (ba)
! 	is_packed = contains_packed_reference (ba);
  
        if (compare_tree_int (TYPE_SIZE (type), TYPE_ALIGN (type)) > 0)
  	is_packed = true;
--- 1141,1147 ----
    if (!known_alignment_for_access_p (dr))
      {
        tree type = (TREE_TYPE (DR_REF (dr)));
!       bool is_packed = contains_packed_reference (DR_REF (dr));
  
        if (compare_tree_int (TYPE_SIZE (type), TYPE_ALIGN (type)) > 0)
  	is_packed = true;
*************** vect_supportable_dr_alignment (struct da
*** 4672,4683 ****
  	    return dr_explicit_realign_optimized;
  	}
        if (!known_alignment_for_access_p (dr))
! 	{
! 	  tree ba = DR_BASE_OBJECT (dr);
! 
! 	  if (ba)
! 	    is_packed = contains_packed_reference (ba);
! 	}
  
        if (targetm.vectorize.
  	  support_vector_misalignment (mode, type,
--- 4668,4674 ----
  	    return dr_explicit_realign_optimized;
  	}
        if (!known_alignment_for_access_p (dr))
! 	is_packed = contains_packed_reference (DR_REF (dr));
  
        if (targetm.vectorize.
  	  support_vector_misalignment (mode, type,
*************** vect_supportable_dr_alignment (struct da
*** 4691,4702 ****
        tree type = (TREE_TYPE (DR_REF (dr)));
  
        if (!known_alignment_for_access_p (dr))
! 	{
! 	  tree ba = DR_BASE_OBJECT (dr);
! 
! 	  if (ba)
! 	    is_packed = contains_packed_reference (ba);
! 	}
  
       if (targetm.vectorize.
           support_vector_misalignment (mode, type,
--- 4682,4688 ----
        tree type = (TREE_TYPE (DR_REF (dr)));
  
        if (!known_alignment_for_access_p (dr))
! 	is_packed = contains_packed_reference (DR_REF (dr));
  
       if (targetm.vectorize.
           support_vector_misalignment (mode, type,
Index: gcc/testsuite/gcc.dg/torture/pr52406.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/pr52406.c	(revision 0)
--- gcc/testsuite/gcc.dg/torture/pr52406.c	(revision 0)
***************
*** 0 ****
--- 1,29 ----
+ /* { dg-do run } */
+ 
+ extern void abort (void);
+ struct { int f1; } a[2];
+ 
+ int *b, *const k = &a[1].f1;
+ static int **c = &b;
+ 
+ int e, f, d;
+ 
+ int
+ main ()
+ {
+   int **l = &b;
+   *l = k;
+   for (; d <= 0; d++)
+     {
+       int *j = &e;
+       **c = 1;
+       *l = k;
+       *k ^= 0;
+       f = **l;
+       *j = f;
+     }
+   if (e != 1)
+     abort ();
+   return 0;
+ }
+ 


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