This is sort of the "final" state I ended up trying to teach
the C frontend not to emit array-to-pointer decay as
  ADDR_EXPR (element-type*, array)
but as
  ADDR_EXPR (element-type*, ARRAY_REF (element-type, array, 0))
for both type correctness and for possible simplifications of
fold and the tree optimizers that will no longer have to handle
&a as &a[0] specially if trying to optimize ARRAY_REF operations.

While the patch to teach the C frontend to emit &a[0] is not
complicated (see the c-typeck.c (default_function_array_conversion)
patch chunk), there is a lot of fall-out in the frontend and in
the optimizers.

In the patch you will find intermixed (fold-const.c parts) code
to fold more of address calculation with &a[i] especially in
the case of char arrays which gets excercised quite a lot in
the C testsuite.

I also came along problems in fold_indirect_ref_1 (see also separate
post) and fold_stmt.

The gimplify.c chunk was applied to check if C no longer creates
those "invalid" trees.  Until other frontends are fixed, this
is not safe.


The patch was bootstrapped and tested on i686-pc-linux-gnu for
the C language with the only remaining regression being c99-init-4.c
(I didn't manage to find the place to fix).


I'll stop right here until I get encouragement and help from other
frontend maintainers to maybe fix all of the frontends (I know of
at least gfortran that needs to be fixed) to really have a benefit
of the patch.

Other suggestions?  Like f.e. how to fix c99-init-4.c?


Thanks,
Richard.
2005-04-28  Richard Guenther  <[EMAIL PROTECTED]>

        * builtins.c (fold_builtin_constant_p): Handle constant
        strings of the form &str[0].
        * c-format.c (check_format_arg): Handle &a[offset] as valid
        format string.
        * c-typeck.c (default_function_array_conversion): Emit
        array-to-pointer decay as &a[0].
        (build_unary_op): Emit &a[i] in its original form rather
        than splitting it to a + i.
        * expr.c (string_constant): Handle &"Foo"[0] as string
        constant.
        * tree-ssa-ccp.c (fold_stmt): Do not use results from fold
        that are not TREE_CONSTANT.
        * fold-const.c (extract_array_ref): Remove.
        (try_move_mult_to_index): Handle folding of &a[i] OP x
        with x being constant or array element size one.  Fix type
        correctness.
        (fold_binary): Dispatch to try_move_mult_to_index in more
        cases.  Simplify folding of comparisons of ARRAY_REFs.
        (fold_indirect_ref_1): Avoid removing NOP_EXPRs with type
        qualifiers like const.

        * gimplify.c (check_pointer_types_r): ADDR_EXPR no longer
        can be of type array element for array operands.

Index: gcc/builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.460
diff -c -3 -p -r1.460 builtins.c
*** gcc/builtins.c      23 Apr 2005 21:27:24 -0000      1.460
--- gcc/builtins.c      28 Apr 2005 13:24:21 -0000
*************** fold_builtin_constant_p (tree arglist)
*** 6320,6326 ****
        || (TREE_CODE (arglist) == CONSTRUCTOR
          && TREE_CONSTANT (arglist))
        || (TREE_CODE (arglist) == ADDR_EXPR
!         && TREE_CODE (TREE_OPERAND (arglist, 0)) == STRING_CST))
      return integer_one_node;
  
    /* If this expression has side effects, show we don't know it to be a
--- 6320,6329 ----
        || (TREE_CODE (arglist) == CONSTRUCTOR
          && TREE_CONSTANT (arglist))
        || (TREE_CODE (arglist) == ADDR_EXPR
!         && (TREE_CODE (TREE_OPERAND (arglist, 0)) == STRING_CST
!             || (TREE_CODE (TREE_OPERAND (arglist, 0)) == ARRAY_REF
!                 && integer_zerop (TREE_OPERAND (TREE_OPERAND (arglist, 0), 1))
!                 && TREE_CODE (TREE_OPERAND (TREE_OPERAND (arglist, 0), 0)) == 
STRING_CST))))
      return integer_one_node;
  
    /* If this expression has side effects, show we don't know it to be a
Index: gcc/c-format.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-format.c,v
retrieving revision 1.74
diff -c -3 -p -r1.74 c-format.c
*** gcc/c-format.c      26 Apr 2005 23:57:55 -0000      1.74
--- gcc/c-format.c      28 Apr 2005 13:24:22 -0000
*************** check_format_arg (void *ctx, tree format
*** 1260,1265 ****
--- 1260,1269 ----
        return;
      }
    format_tree = TREE_OPERAND (format_tree, 0);
+   if (TREE_CODE (format_tree) == ARRAY_REF
+       && host_integerp (TREE_OPERAND (format_tree, 1), 0)
+       && (offset = tree_low_cst (TREE_OPERAND (format_tree, 1), 0)) >= 0)
+     format_tree = TREE_OPERAND (format_tree, 0);
    if (TREE_CODE (format_tree) == VAR_DECL
        && TREE_CODE (TREE_TYPE (format_tree)) == ARRAY_TYPE
        && (array_init = decl_constant_value (format_tree)) != format_tree
Index: gcc/c-typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-typeck.c,v
retrieving revision 1.438
diff -c -3 -p -r1.438 c-typeck.c
*** gcc/c-typeck.c      28 Apr 2005 00:45:42 -0000      1.438
--- gcc/c-typeck.c      28 Apr 2005 13:24:27 -0000
*************** default_function_array_conversion (tree 
*** 1335,1356 ****
  
        ptrtype = build_pointer_type (restype);
  
!       if (TREE_CODE (exp) == VAR_DECL)
!       {
!         /* We are making an ADDR_EXPR of ptrtype.  This is a valid
!            ADDR_EXPR because it's the best way of representing what
!            happens in C when we take the address of an array and place
!            it in a pointer to the element type.  */
!         adr = build1 (ADDR_EXPR, ptrtype, exp);
!         if (!c_mark_addressable (exp))
!           return error_mark_node;
!         TREE_SIDE_EFFECTS (adr) = 0;   /* Default would be, same as EXP.  */
!         return adr;
!       }
!       /* This way is better for a COMPONENT_REF since it can
!        simplify the offset for a component.  */
!       adr = build_unary_op (ADDR_EXPR, exp, 1);
!       return convert (ptrtype, adr);
      }
    return exp;
  }
--- 1335,1353 ----
  
        ptrtype = build_pointer_type (restype);
  
!       /* We are making an ADDR_EXPR of ptrtype.  So we need to
!        construct an ARRAY_REF to the first element of the
!        array for tree type correctness.  This is the best way of
!        representing what happens in C when we take the address of
!        an array and place it in a pointer to the element type.  */
!       adr = build1 (ADDR_EXPR, ptrtype,
!                   build4 (ARRAY_REF, restype,
!                           exp, integer_zero_node,
!                           NULL_TREE, NULL_TREE));
!       if (!c_mark_addressable (exp))
!       return error_mark_node;
!       TREE_SIDE_EFFECTS (adr) = 0;   /* Default would be, same as EXP.  */
!       return adr;
      }
    return exp;
  }
*************** build_unary_op (enum tree_code code, tre
*** 2713,2726 ****
          return TREE_OPERAND (arg, 0);
        }
  
!       /* For &x[y], return x+y */
!       if (TREE_CODE (arg) == ARRAY_REF)
!       {
!         if (!c_mark_addressable (TREE_OPERAND (arg, 0)))
!           return error_mark_node;
!         return build_binary_op (PLUS_EXPR, TREE_OPERAND (arg, 0),
!                                 TREE_OPERAND (arg, 1), 1);
!       }
  
        /* Anything not already handled and not a true memory reference
         or a non-lvalue array is an error.  */
--- 2710,2718 ----
          return TREE_OPERAND (arg, 0);
        }
  
!       if (TREE_CODE (arg) == ARRAY_REF
!         && !c_mark_addressable (TREE_OPERAND (arg, 0)))
!       return error_mark_node;
  
        /* Anything not already handled and not a true memory reference
         or a non-lvalue array is an error.  */
Index: gcc/expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.788
diff -c -3 -p -r1.788 expr.c
*** gcc/expr.c  28 Apr 2005 05:03:03 -0000      1.788
--- gcc/expr.c  28 Apr 2005 13:24:28 -0000
*************** string_constant (tree arg, tree *ptr_off
*** 8484,8499 ****
  
        if (TREE_CODE (arg0) == ADDR_EXPR
          && (TREE_CODE (TREE_OPERAND (arg0, 0)) == STRING_CST
!             || TREE_CODE (TREE_OPERAND (arg0, 0)) == VAR_DECL))
        {
          array = TREE_OPERAND (arg0, 0);
          offset = arg1;
        }
        else if (TREE_CODE (arg1) == ADDR_EXPR
               && (TREE_CODE (TREE_OPERAND (arg1, 0)) == STRING_CST
!                  || TREE_CODE (TREE_OPERAND (arg1, 0)) == VAR_DECL))
        {
          array = TREE_OPERAND (arg1, 0);
          offset = arg0;
        }
        else
--- 8484,8507 ----
  
        if (TREE_CODE (arg0) == ADDR_EXPR
          && (TREE_CODE (TREE_OPERAND (arg0, 0)) == STRING_CST
!             || TREE_CODE (TREE_OPERAND (arg0, 0)) == VAR_DECL
!             || (TREE_CODE (TREE_OPERAND (arg0, 0)) == ARRAY_REF
!                 && integer_zerop (TREE_OPERAND (TREE_OPERAND (arg0, 0), 1)))))
        {
          array = TREE_OPERAND (arg0, 0);
+         if (TREE_CODE (TREE_OPERAND (arg0, 0)) == ARRAY_REF)
+           array = TREE_OPERAND (array, 0);
          offset = arg1;
        }
        else if (TREE_CODE (arg1) == ADDR_EXPR
               && (TREE_CODE (TREE_OPERAND (arg1, 0)) == STRING_CST
!                  || TREE_CODE (TREE_OPERAND (arg1, 0)) == VAR_DECL
!                  || (TREE_CODE (TREE_OPERAND (arg1, 0)) == ARRAY_REF
!                      && integer_zerop (TREE_OPERAND (TREE_OPERAND (arg1, 0), 
1)))))
        {
          array = TREE_OPERAND (arg1, 0);
+         if (TREE_CODE (TREE_OPERAND (arg1, 0)) == ARRAY_REF)
+           array = TREE_OPERAND (array, 0);
          offset = arg0;
        }
        else
Index: gcc/gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gimplify.c,v
retrieving revision 2.125
diff -c -3 -p -r2.125 gimplify.c
*** gcc/gimplify.c      22 Apr 2005 16:14:54 -0000      2.125
--- gcc/gimplify.c      28 Apr 2005 13:24:28 -0000
*************** check_pointer_types_r (tree *tp, int *wa
*** 4500,4516 ****
        ptype = TREE_TYPE (t);
        otype = TREE_TYPE (TREE_OPERAND (t, 0));
        dtype = TREE_TYPE (ptype);
!       if (!cpt_same_type (otype, dtype))
!       {
!         /* &array is allowed to produce a pointer to the element, rather than
!            a pointer to the array type.  We must allow this in order to
!            properly represent assigning the address of an array in C into
!            pointer to the element type.  */
!         gcc_assert (TREE_CODE (otype) == ARRAY_TYPE
!                     && POINTER_TYPE_P (ptype)
!                     && cpt_same_type (TREE_TYPE (otype), dtype));
!         break;
!       }
        break;
  
      default:
--- 4500,4506 ----
        ptype = TREE_TYPE (t);
        otype = TREE_TYPE (TREE_OPERAND (t, 0));
        dtype = TREE_TYPE (ptype);
!       gcc_assert (cpt_same_type (otype, dtype));
        break;
  
      default:
Index: gcc/tree-ssa-ccp.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-ccp.c,v
retrieving revision 2.67
diff -c -3 -p -r2.67 tree-ssa-ccp.c
*** gcc/tree-ssa-ccp.c  21 Apr 2005 18:05:24 -0000      2.67
--- gcc/tree-ssa-ccp.c  28 Apr 2005 13:24:28 -0000
*************** fold_stmt (tree *stmt_p)
*** 2177,2183 ****
  
    /* If we couldn't fold the RHS, hand over to the generic fold routines.  */
    if (result == NULL_TREE)
!     result = fold (rhs);
  
    /* Strip away useless type conversions.  Both the NON_LVALUE_EXPR that
       may have been added by fold, and "useless" type conversions that might
--- 2177,2186 ----
  
    /* If we couldn't fold the RHS, hand over to the generic fold routines.  */
    if (result == NULL_TREE)
!     {
!       tree tmp = fold (rhs);
!       result = TREE_CONSTANT (tmp) ? tmp : rhs;
!     }
  
    /* Strip away useless type conversions.  Both the NON_LVALUE_EXPR that
       may have been added by fold, and "useless" type conversions that might
Index: gcc/fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.573
diff -c -3 -p -r1.573 fold-const.c
*** gcc/fold-const.c    27 Apr 2005 19:38:57 -0000      1.573
--- gcc/fold-const.c    28 Apr 2005 13:31:37 -0000
*************** constant_boolean_node (int value, tree t
*** 5416,5471 ****
  }
  
  
- /* Return true if expr looks like an ARRAY_REF and set base and
-    offset to the appropriate trees.  If there is no offset,
-    offset is set to NULL_TREE.  */
- 
- static bool
- extract_array_ref (tree expr, tree *base, tree *offset)
- {
-   /* We have to be careful with stripping nops as with the
-      base type the meaning of the offset can change.  */
-   tree inner_expr = expr;
-   STRIP_NOPS (inner_expr);
-   /* One canonical form is a PLUS_EXPR with the first
-      argument being an ADDR_EXPR with a possible NOP_EXPR
-      attached.  */
-   if (TREE_CODE (expr) == PLUS_EXPR)
-     {
-       tree op0 = TREE_OPERAND (expr, 0);
-       STRIP_NOPS (op0);
-       if (TREE_CODE (op0) == ADDR_EXPR)
-       {
-         *base = TREE_OPERAND (expr, 0);
-         *offset = TREE_OPERAND (expr, 1);
-         return true;
-       }
-     }
-   /* Other canonical form is an ADDR_EXPR of an ARRAY_REF,
-      which we transform into an ADDR_EXPR with appropriate
-      offset.  For other arguments to the ADDR_EXPR we assume
-      zero offset and as such do not care about the ADDR_EXPR
-      type and strip possible nops from it.  */
-   else if (TREE_CODE (inner_expr) == ADDR_EXPR)
-     {
-       tree op0 = TREE_OPERAND (inner_expr, 0);
-       if (TREE_CODE (op0) == ARRAY_REF)
-       {
-         *base = build_fold_addr_expr (TREE_OPERAND (op0, 0));
-         *offset = TREE_OPERAND (op0, 1);
-       }
-       else
-       {
-         *base = inner_expr;
-         *offset = NULL_TREE;
-       }
-       return true;
-     }
- 
-   return false;
- }
- 
- 
  /* Transform `a + (b ? x : y)' into `b ? (a + x) : (a + y)'.
     Transform, `a + (x < y)' into `(x < y) ? (a + 1) : (a + 0)'.  Here
     CODE corresponds to the `+', COND to the `(b ? x : y)' or `(x < y)'
--- 5416,5421 ----
*************** fold_sign_changed_comparison (enum tree_
*** 6258,6312 ****
  }
  
  /* Tries to replace &a[idx] CODE s * delta with &a[idx CODE delta], if s is
!    step of the array.  ADDR is the address. MULT is the multiplicative 
expression.
     If the function succeeds, the new address expression is returned.  
Otherwise
     NULL_TREE is returned.  */
  
  static tree
! try_move_mult_to_index (enum tree_code code, tree addr, tree mult)
  {
    tree s, delta, step;
-   tree arg0 = TREE_OPERAND (mult, 0), arg1 = TREE_OPERAND (mult, 1);
    tree ref = TREE_OPERAND (addr, 0), pref;
    tree ret, pos;
    tree itype;
  
!   STRIP_NOPS (arg0);
!   STRIP_NOPS (arg1);
!   
!   if (TREE_CODE (arg0) == INTEGER_CST)
      {
!       s = arg0;
!       delta = arg1;
      }
!   else if (TREE_CODE (arg1) == INTEGER_CST)
      {
!       s = arg1;
!       delta = arg0;
      }
    else
!     return NULL_TREE;
  
    for (;; ref = TREE_OPERAND (ref, 0))
      {
        if (TREE_CODE (ref) == ARRAY_REF)
        {
          step = array_ref_element_size (ref);
  
          if (TREE_CODE (step) != INTEGER_CST)
            continue;
  
!         itype = TREE_TYPE (step);
  
!         /* If the type sizes do not match, we might run into problems
!            when one of them would overflow.  */
!         if (TYPE_PRECISION (itype) != TYPE_PRECISION (TREE_TYPE (s)))
!           continue;
  
!         if (!operand_equal_p (step, fold_convert (itype, s), 0))
!           continue;
  
!         delta = fold_convert (itype, delta);
          break;
        }
  
--- 6208,6292 ----
  }
  
  /* Tries to replace &a[idx] CODE s * delta with &a[idx CODE delta], if s is
!    step of the array.  Reconstructs s and delta in the case of s * delta
!    being an integer constant (and thus already folded).
!    ADDR is the address. MULT is the multiplicative expression.
     If the function succeeds, the new address expression is returned.  
Otherwise
     NULL_TREE is returned.  */
  
  static tree
! try_move_mult_to_index (enum tree_code code, tree addr, tree op1)
  {
    tree s, delta, step;
    tree ref = TREE_OPERAND (addr, 0), pref;
    tree ret, pos;
    tree itype;
  
!   /* Canonicalize op1 into a possibly non-constant delta
!      and an INTEGER_CST s.  */
!   if (TREE_CODE (op1) == MULT_EXPR)
      {
!       tree arg0 = TREE_OPERAND (op1, 0), arg1 = TREE_OPERAND (op1, 1);
! 
!       STRIP_NOPS (arg0);
!       STRIP_NOPS (arg1);
!   
!       if (TREE_CODE (arg0) == INTEGER_CST)
!         {
!           s = arg0;
!           delta = arg1;
!         }
!       else if (TREE_CODE (arg1) == INTEGER_CST)
!         {
!           s = arg1;
!           delta = arg0;
!         }
!       else
!         return NULL_TREE;
      }
!   else if (TREE_CODE (op1) == INTEGER_CST)
      {
!       delta = op1;
!       s = NULL_TREE;
      }
    else
!     {
!       delta = op1;
!       s = integer_one_node;
!     }
  
    for (;; ref = TREE_OPERAND (ref, 0))
      {
        if (TREE_CODE (ref) == ARRAY_REF)
        {
          step = array_ref_element_size (ref);
+         itype = TREE_TYPE (step);
  
          if (TREE_CODE (step) != INTEGER_CST)
            continue;
  
!         if (s)
!           {
!             /* If the type sizes do not match, we might run into problems
!                when one of them would overflow.  */
!             if (TYPE_PRECISION (itype) != TYPE_PRECISION (TREE_TYPE (s)))
!               continue;
  
!             if (!operand_equal_p (step, fold_convert (itype, s), 0))
!               continue;
  
!           }
!         else
!           {
!             /* Try if delta is a multiple of step.  */
!             tree mod = int_const_binop (TRUNC_MOD_EXPR, delta, step, 0);
!             if (!integer_zerop (mod))
!               continue;
! 
!             delta = int_const_binop (EXACT_DIV_EXPR, delta, step, 0);
!           }
  
!         /*delta = fold_convert (itype, delta);*/
          break;
        }
  
*************** try_move_mult_to_index (enum tree_code c
*** 6328,6336 ****
        pos = TREE_OPERAND (pos, 0);
      }
  
!   TREE_OPERAND (pos, 1) = fold_build2 (code, itype,
!                                      TREE_OPERAND (pos, 1),
!                                      delta);
  
    return build1 (ADDR_EXPR, TREE_TYPE (addr), ret);
  }
--- 6308,6338 ----
        pos = TREE_OPERAND (pos, 0);
      }
  
!   /* fold_convert operands of CODE appropriately.  */
!   pref = TREE_OPERAND (pos, 1);
!   if (! TREE_TYPE (pref) && TREE_TYPE (delta))
!     {
!       itype = TREE_TYPE (delta);
!       pref = fold_convert (itype, pref);
!     }
!   else if (! TREE_TYPE (delta) && TREE_TYPE (pref))
!     {
!       itype = TREE_TYPE (pref);
!       delta = fold_convert (itype, delta);
!     }
!   else if (TREE_TYPE (delta) && TREE_TYPE (pref)
!          && TREE_TYPE (delta) == TREE_TYPE (pref))
!     ;
!   else
!     {
!       itype = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (pos, 0)));
!       if (! itype)
!       return NULL_TREE;
!       pref = fold_convert (itype, pref);
!       delta = fold_convert (itype, delta);
!     }
! 
!   TREE_OPERAND (pos, 1) = fold_build2 (code, itype, pref, delta);
  
    return build1 (ADDR_EXPR, TREE_TYPE (addr), ret);
  }
*************** fold_binary (enum tree_code code, tree t
*** 7440,7454 ****
          /* Try replacing &a[i1] + c * i2 with &a[i1 + i2], if c is step
             of the array.  Loop optimizer sometimes produce this type of
             expressions.  */
!         if (TREE_CODE (arg0) == ADDR_EXPR
!             && TREE_CODE (arg1) == MULT_EXPR)
            {
              tem = try_move_mult_to_index (PLUS_EXPR, arg0, arg1);
              if (tem)
                return fold_convert (type, fold (tem));
            }
!         else if (TREE_CODE (arg1) == ADDR_EXPR
!                  && TREE_CODE (arg0) == MULT_EXPR)
            {
              tem = try_move_mult_to_index (PLUS_EXPR, arg1, arg0);
              if (tem)
--- 7442,7454 ----
          /* Try replacing &a[i1] + c * i2 with &a[i1 + i2], if c is step
             of the array.  Loop optimizer sometimes produce this type of
             expressions.  */
!         if (TREE_CODE (arg0) == ADDR_EXPR)
            {
              tem = try_move_mult_to_index (PLUS_EXPR, arg0, arg1);
              if (tem)
                return fold_convert (type, fold (tem));
            }
!         else if (TREE_CODE (arg1) == ADDR_EXPR)
            {
              tem = try_move_mult_to_index (PLUS_EXPR, arg1, arg0);
              if (tem)
*************** fold_binary (enum tree_code code, tree t
*** 7866,7873 ****
        /* Try replacing &a[i1] - c * i2 with &a[i1 - i2], if c is step
         of the array.  Loop optimizer sometimes produce this type of
         expressions.  */
!       if (TREE_CODE (arg0) == ADDR_EXPR
!         && TREE_CODE (arg1) == MULT_EXPR)
        {
          tem = try_move_mult_to_index (MINUS_EXPR, arg0, arg1);
          if (tem)
--- 7866,7872 ----
        /* Try replacing &a[i1] - c * i2 with &a[i1 - i2], if c is step
         of the array.  Loop optimizer sometimes produce this type of
         expressions.  */
!       if (TREE_CODE (arg0) == ADDR_EXPR)
        {
          tem = try_move_mult_to_index (MINUS_EXPR, arg0, arg1);
          if (tem)
*************** fold_binary (enum tree_code code, tree t
*** 8893,8916 ****
        /* If this is a comparison of two exprs that look like an
         ARRAY_REF of the same object, then we can fold this to a
         comparison of the two offsets.  */
!       if (TREE_CODE_CLASS (code) == tcc_comparison)
        {
!         tree base0, offset0, base1, offset1;
  
!         if (extract_array_ref (arg0, &base0, &offset0)
!             && extract_array_ref (arg1, &base1, &offset1)
!             && operand_equal_p (base0, base1, 0))
            {
!             if (offset0 == NULL_TREE
!                 && offset1 == NULL_TREE)
!               {
!                 offset0 = integer_zero_node;
!                 offset1 = integer_zero_node;
                }
-             else if (offset0 == NULL_TREE)
-               offset0 = build_int_cst (TREE_TYPE (offset1), 0);
-             else if (offset1 == NULL_TREE)
-               offset1 = build_int_cst (TREE_TYPE (offset0), 0);
  
              if (TREE_TYPE (offset0) == TREE_TYPE (offset1))
                return fold_build2 (code, type, offset0, offset1);
--- 8892,8921 ----
        /* If this is a comparison of two exprs that look like an
         ARRAY_REF of the same object, then we can fold this to a
         comparison of the two offsets.  */
!       if (TREE_CODE (arg0) == ADDR_EXPR
!         && TREE_CODE (arg1) == ADDR_EXPR
!         && TREE_CODE (TREE_OPERAND (arg0, 0)) == ARRAY_REF
!         && TREE_CODE (TREE_OPERAND (arg1, 0)) == ARRAY_REF)
        {
!         tree aref0 = TREE_OPERAND (arg0, 0);
!         tree aref1 = TREE_OPERAND (arg1, 0);
  
!         if (operand_equal_p (TREE_OPERAND (aref0, 0),
!                              TREE_OPERAND (aref1, 0), 0))
            {
!             tree offset0 = TREE_OPERAND (aref0, 1);
!             tree offset1 = TREE_OPERAND (aref1, 1);
!             tree dtype = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (aref0, 0)));
!             if (integer_zerop (array_ref_element_size (aref0)))
!               offset0 = integer_zero_node;
!             if (integer_zerop (array_ref_element_size (aref1)))
!               offset1 = integer_zero_node;
!             if (TREE_TYPE (offset0) != TREE_TYPE (offset1)
!                 && dtype)
!               {
!                 offset0 = fold_convert (dtype, offset0);
!                 offset1 = fold_convert (dtype, offset1);
                }
  
              if (TREE_TYPE (offset0) == TREE_TYPE (offset1))
                return fold_build2 (code, type, offset0, offset1);
*************** fold_indirect_ref_1 (tree t)
*** 11310,11316 ****
    tree sub = t;
    tree subtype;
  
!   STRIP_NOPS (sub);
    subtype = TREE_TYPE (sub);
    if (!POINTER_TYPE_P (subtype))
      return NULL_TREE;
--- 11315,11321 ----
    tree sub = t;
    tree subtype;
  
!   STRIP_TYPE_NOPS (sub);
    subtype = TREE_TYPE (sub);
    if (!POINTER_TYPE_P (subtype))
      return NULL_TREE;

Reply via email to