This extends try_move_mult_to_index folding to be less picky about
the outermost array reference and handles a component-ref of an
array the same as if that were wrapped with an array-ref with
minimum index.

This consolidates array-ref reconstruction to the frontend-closest
position we have right now (eventually that function should move
to some c-family helper I guess).

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

Richard.

2011-09-28  Richard Guenther  <rguent...@suse.de>

        PR middle-end/50460
        * fold-const.c (try_move_mult_to_index): Handle &a.array the
        same as &a.array[0].

Index: gcc/fold-const.c
===================================================================
*** gcc/fold-const.c    (revision 179308)
--- gcc/fold-const.c    (working copy)
*************** try_move_mult_to_index (location_t loc,
*** 6870,6875 ****
--- 6870,6929 ----
  
          break;
        }
+       else if (TREE_CODE (ref) == COMPONENT_REF
+              && TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE)
+       {
+         tree domain;
+ 
+         /* Remember if this was a multi-dimensional array.  */
+         if (TREE_CODE (TREE_OPERAND (ref, 0)) == ARRAY_REF)
+           mdim = true;
+ 
+         domain = TYPE_DOMAIN (TREE_TYPE (ref));
+         if (! domain)
+           continue;
+         itype = TREE_TYPE (domain);
+ 
+         step = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ref)));
+         if (TREE_CODE (step) != INTEGER_CST)
+           continue;
+ 
+         if (s)
+           {
+             if (! tree_int_cst_equal (step, s))
+                 continue;
+           }
+         else
+           {
+             /* Try if delta is a multiple of step.  */
+             tree tmp = div_if_zero_remainder (EXACT_DIV_EXPR, op1, step);
+             if (! tmp)
+               continue;
+             delta = tmp;
+           }
+ 
+         /* Only fold here if we can verify we do not overflow one
+            dimension of a multi-dimensional array.  */
+         if (mdim)
+           {
+             tree tmp;
+ 
+             if (!TYPE_MIN_VALUE (domain)
+                 || !TYPE_MAX_VALUE (domain)
+                 || TREE_CODE (TYPE_MAX_VALUE (domain)) != INTEGER_CST)
+               continue;
+ 
+             tmp = fold_binary_loc (loc, PLUS_EXPR, itype,
+                                    fold_convert_loc (loc, itype,
+                                                      TYPE_MIN_VALUE (domain)),
+                                    fold_convert_loc (loc, itype, delta));
+             if (TREE_CODE (tmp) != INTEGER_CST
+                 || tree_int_cst_lt (TYPE_MAX_VALUE (domain), tmp))
+               continue;
+           }
+ 
+         break;
+       }
        else
        mdim = false;
  
*************** try_move_mult_to_index (location_t loc,
*** 6892,6903 ****
        pos = TREE_OPERAND (pos, 0);
      }
  
!   TREE_OPERAND (pos, 1) = fold_build2_loc (loc, PLUS_EXPR, itype,
!                                      fold_convert_loc (loc, itype,
!                                                        TREE_OPERAND (pos, 1)),
!                                      fold_convert_loc (loc, itype, delta));
! 
!   return fold_build1_loc (loc, ADDR_EXPR, TREE_TYPE (addr), ret);
  }
  
  
--- 6946,6974 ----
        pos = TREE_OPERAND (pos, 0);
      }
  
!   if (TREE_CODE (ref) == ARRAY_REF)
!     {
!       TREE_OPERAND (pos, 1)
!       = fold_build2_loc (loc, PLUS_EXPR, itype,
!                          fold_convert_loc (loc, itype, TREE_OPERAND (pos, 1)),
!                          fold_convert_loc (loc, itype, delta));
!       return fold_build1_loc (loc, ADDR_EXPR, TREE_TYPE (addr), ret);
!     }
!   else if (TREE_CODE (ref) == COMPONENT_REF)
!     {
!       gcc_assert (ret == pos);
!       ret = build4_loc (loc, ARRAY_REF, TREE_TYPE (TREE_TYPE (ref)), ret,
!                       fold_build2_loc
!                         (loc, PLUS_EXPR, itype,
!                          fold_convert_loc (loc, itype,
!                                            TYPE_MIN_VALUE
!                                              (TYPE_DOMAIN (TREE_TYPE (ref)))),
!                          fold_convert_loc (loc, itype, delta)),
!                       NULL_TREE, NULL_TREE);
!       return build_fold_addr_expr_loc (loc, ret);
!     }
!   else
!     gcc_unreachable ();
  }
  
  

Reply via email to