On Tue, 17 Apr 2012, Richard Guenther wrote:

> 
> Loop bound computation uses undefined behavior when accessing arrays
> outside of their domain.  Unfortunately while it tries to honor
> issues with trailing arrays in allocated storage its implementation
> is broken (for one, it does consider a TYPE_DECL after the array
> as a sign that the array is not at struct end).  The following patch
> moves array_at_struct_end_p to expr.c near its natural user
> (it's also used by graphite) and re-implements it.  It also adjusts
> array_ref_up_bound to not return any bound in the case of an
> access to a trailing array - at present what it returns is a
> conservative answer in the wrong sense in two of its four callers
> (it returns a lower bound for the upper bound).  Given the fact
> that array_ref_low_bound returns an exact answer not returning
> any lower / upper bound for the upper bound but only what we would
> consider exact sounds like the most reasonable solution.
> 
> Bootstrapped on x86_64-unknown-linux-gnu, testing in progress.
> 
> This does not yet fully recover bootstrap if you make use of
> undefined behavior loop bound detection in VRP, but two miscompiles
> of GCC vanish.

I ended up with the following simplified variant because we have
testcases that test that niter still records an estimate for
a trailing a[5].

Bootstrapped and tested on x86_64-unknown-linux-gnu, committed.

Richard.

2012-04-17  Richard Guenther  <rguent...@suse.de>

        * tree-flow.h (array_at_struct_end_p): Move declaration ...
        * tree.h (array_at_struct_end_p): ... here.
        * tree-ssa-loop-niter.c (array_at_struct_end_p): Move ...
        * expr.c (array_at_struct_end_p): ... here.  Rewrite.

Index: gcc/tree.h
===================================================================
*** gcc/tree.h  (revision 186496)
--- gcc/tree.h  (working copy)
*************** extern bool contains_packed_reference (c
*** 5068,5073 ****
--- 5068,5075 ----
  
  extern tree array_ref_element_size (tree);
  
+ bool array_at_struct_end_p (tree);
+ 
  /* Return a tree representing the lower bound of the array mentioned in
     EXP, an ARRAY_REF or an ARRAY_RANGE_REF.  */
  
Index: gcc/expr.c
===================================================================
*** gcc/expr.c  (revision 186496)
--- gcc/expr.c  (working copy)
*************** array_ref_low_bound (tree exp)
*** 6778,6783 ****
--- 6778,6820 ----
    return build_int_cst (TREE_TYPE (TREE_OPERAND (exp, 1)), 0);
  }
  
+ /* Returns true if REF is an array reference to an array at the end of
+    a structure.  If this is the case, the array may be allocated larger
+    than its upper bound implies.  */
+ 
+ bool
+ array_at_struct_end_p (tree ref)
+ {
+   if (TREE_CODE (ref) != ARRAY_REF
+       && TREE_CODE (ref) != ARRAY_RANGE_REF)
+     return false;
+ 
+   while (handled_component_p (ref))
+     {
+       /* If the reference chain contains a component reference to a
+          non-union type and there follows another field the reference
+        is not at the end of a structure.  */
+       if (TREE_CODE (ref) == COMPONENT_REF
+         && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 0))) == RECORD_TYPE)
+       {
+         tree nextf = DECL_CHAIN (TREE_OPERAND (ref, 1));
+         while (nextf && TREE_CODE (nextf) != FIELD_DECL)
+           nextf = DECL_CHAIN (nextf);
+         if (nextf)
+           return false;
+       }
+ 
+       ref = TREE_OPERAND (ref, 0);
+     }
+ 
+   /* If the reference is based on a declared entity, the size of the array
+      is constrained by its given domain.  */
+   if (DECL_P (ref))
+     return false;
+ 
+   return true;
+ }
+ 
  /* Return a tree representing the upper bound of the array mentioned in
     EXP, an ARRAY_REF or an ARRAY_RANGE_REF.  */
  
Index: gcc/tree-flow.h
===================================================================
*** gcc/tree-flow.h     (revision 186496)
--- gcc/tree-flow.h     (working copy)
*************** tree find_loop_niter (struct loop *, edg
*** 686,692 ****
  tree loop_niter_by_eval (struct loop *, edge);
  tree find_loop_niter_by_eval (struct loop *, edge *);
  void estimate_numbers_of_iterations (bool);
- bool array_at_struct_end_p (tree);
  bool scev_probably_wraps_p (tree, tree, gimple, struct loop *, bool);
  bool convert_affine_scev (struct loop *, tree, tree *, tree *, gimple, bool);
  
--- 686,691 ----
Index: gcc/tree-ssa-loop-niter.c
===================================================================
*** gcc/tree-ssa-loop-niter.c   (revision 186496)
--- gcc/tree-ssa-loop-niter.c   (working copy)
*************** record_nonwrapping_iv (struct loop *loop
*** 2640,2686 ****
    record_estimate (loop, niter_bound, max, stmt, false, realistic, upper);
  }
  
- /* Returns true if REF is a reference to an array at the end of a dynamically
-    allocated structure.  If this is the case, the array may be allocated 
larger
-    than its upper bound implies.  */
- 
- bool
- array_at_struct_end_p (tree ref)
- {
-   tree base = get_base_address (ref);
-   tree parent, field;
- 
-   /* Unless the reference is through a pointer, the size of the array matches
-      its declaration.  */
-   if (!base || (!INDIRECT_REF_P (base) && TREE_CODE (base) != MEM_REF))
-     return false;
- 
-   for (;handled_component_p (ref); ref = parent)
-     {
-       parent = TREE_OPERAND (ref, 0);
- 
-       if (TREE_CODE (ref) == COMPONENT_REF)
-       {
-         /* All fields of a union are at its end.  */
-         if (TREE_CODE (TREE_TYPE (parent)) == UNION_TYPE)
-           continue;
- 
-         /* Unless the field is at the end of the struct, we are done.  */
-         field = TREE_OPERAND (ref, 1);
-         if (DECL_CHAIN (field))
-           return false;
-       }
- 
-       /* The other options are ARRAY_REF, ARRAY_RANGE_REF, VIEW_CONVERT_EXPR.
-        In all these cases, we might be accessing the last element, and
-        although in practice this will probably never happen, it is legal for
-        the indices of this last element to exceed the bounds of the array.
-        Therefore, continue checking.  */
-     }
- 
-   return true;
- }
- 
  /* Determine information about number of iterations a LOOP from the index
     IDX of a data reference accessed in STMT.  RELIABLE is true if STMT is
     guaranteed to be executed in every iteration of LOOP.  Callback for
--- 2648,2653 ----

Reply via email to