OSDN Git Service

Revert accidental commit.
[pf3gnuchains/gcc-fork.git] / gcc / fold-const.c
index 8be8f3e..7306863 100644 (file)
@@ -53,6 +53,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "expr.h"
 #include "tm_p.h"
 #include "target.h"
+#include "diagnostic-core.h"
 #include "toplev.h"
 #include "intl.h"
 #include "ggc.h"
@@ -1795,16 +1796,10 @@ fold_convert_const (enum tree_code code, tree type, tree arg1)
 static tree
 build_zero_vector (tree type)
 {
-  tree elem, list;
-  int i, units;
-
-  elem = fold_convert_const (NOP_EXPR, TREE_TYPE (type), integer_zero_node);
-  units = TYPE_VECTOR_SUBPARTS (type);
+  tree t;
 
-  list = NULL_TREE;
-  for (i = 0; i < units; i++)
-    list = tree_cons (NULL_TREE, elem, list);
-  return build_vector (type, list);
+  t = fold_convert_const (NOP_EXPR, TREE_TYPE (type), integer_zero_node);
+  return build_vector_from_val (type, t);
 }
 
 /* Returns true, if ARG is convertible to TYPE using a NOP_EXPR.  */
@@ -2043,7 +2038,6 @@ maybe_lvalue_p (const_tree x)
   case COMPONENT_REF:
   case MEM_REF:
   case INDIRECT_REF:
-  case MISALIGNED_INDIRECT_REF:
   case ARRAY_REF:
   case ARRAY_RANGE_REF:
   case BIT_FIELD_REF:
@@ -2103,7 +2097,16 @@ pedantic_non_lvalue_loc (location_t loc, tree x)
 {
   if (pedantic_lvalues)
     return non_lvalue_loc (loc, x);
-  protected_set_expr_location (x, loc);
+
+  if (CAN_HAVE_LOCATION_P (x)
+      && EXPR_LOCATION (x) != loc
+      && !(TREE_CODE (x) == SAVE_EXPR
+          || TREE_CODE (x) == TARGET_EXPR
+          || TREE_CODE (x) == BIND_EXPR))
+    {
+      x = copy_node (x);
+      SET_EXPR_LOCATION (x, loc);
+    }
   return x;
 }
 \f
@@ -2586,20 +2589,22 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
       switch (TREE_CODE (arg0))
        {
        case INDIRECT_REF:
-       case MISALIGNED_INDIRECT_REF:
        case REALPART_EXPR:
        case IMAGPART_EXPR:
          return OP_SAME (0);
 
        case MEM_REF:
-         /* Require equal access sizes.  We can have incomplete types
-            for array references of variable-sized arrays from the
-            Fortran frontent though.  */
+         /* Require equal access sizes, and similar pointer types.
+            We can have incomplete types for array references of
+            variable-sized arrays from the Fortran frontent
+            though.  */
          return ((TYPE_SIZE (TREE_TYPE (arg0)) == TYPE_SIZE (TREE_TYPE (arg1))
                   || (TYPE_SIZE (TREE_TYPE (arg0))
                       && TYPE_SIZE (TREE_TYPE (arg1))
                       && operand_equal_p (TYPE_SIZE (TREE_TYPE (arg0)),
                                           TYPE_SIZE (TREE_TYPE (arg1)), flags)))
+                 && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg0, 1)))
+                     == TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg1, 1))))
                  && OP_SAME (0) && OP_SAME (1));
 
        case ARRAY_REF:
@@ -2639,6 +2644,14 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
        case TRUTH_ORIF_EXPR:
          return OP_SAME (0) && OP_SAME (1);
 
+       case FMA_EXPR:
+       case WIDEN_MULT_PLUS_EXPR:
+       case WIDEN_MULT_MINUS_EXPR:
+         if (!OP_SAME (2))
+           return 0;
+         /* The multiplcation operands are commutative.  */
+         /* FALLTHRU */
+
        case TRUTH_AND_EXPR:
        case TRUTH_OR_EXPR:
        case TRUTH_XOR_EXPR:
@@ -2652,6 +2665,8 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
                                      TREE_OPERAND (arg1, 0), flags));
 
        case COND_EXPR:
+       case VEC_COND_EXPR:
+       case DOT_PROD_EXPR:
          return OP_SAME (0) && OP_SAME (1) && OP_SAME (2);
 
        default:
@@ -3984,9 +3999,9 @@ make_range (tree exp, int *pin_p, tree *plow, tree *phigh,
          n_high = range_binop (MINUS_EXPR, exp_type,
                                build_int_cst (exp_type, 0),
                                0, low, 0);
-         low = n_low, high = n_high;
-         exp = arg0;
-         continue;
+         if (n_high != 0 && TREE_OVERFLOW (n_high))
+           break;
+         goto normalize;
 
        case BIT_NOT_EXPR:
          /* ~ X -> -X - 1  */
@@ -4020,6 +4035,7 @@ make_range (tree exp, int *pin_p, tree *plow, tree *phigh,
          if (TYPE_OVERFLOW_UNDEFINED (arg0_type))
            *strict_overflow_p = true;
 
+       normalize:
          /* Check for an unsigned range which has wrapped around the maximum
             value thus making n_high < n_low, and normalize it.  */
          if (n_low && n_high && tree_int_cst_lt (n_high, n_low))
@@ -7595,8 +7611,7 @@ build_fold_addr_expr_with_type_loc (location_t loc, tree t, tree ptrtype)
   if (TREE_CODE (t) == WITH_SIZE_EXPR)
     t = TREE_OPERAND (t, 0);
 
-  if (TREE_CODE (t) == INDIRECT_REF
-      || TREE_CODE (t) == MISALIGNED_INDIRECT_REF)
+  if (TREE_CODE (t) == INDIRECT_REF)
     {
       t = TREE_OPERAND (t, 0);
 
@@ -8232,7 +8247,7 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
 
     case IMAGPART_EXPR:
       if (TREE_CODE (TREE_TYPE (arg0)) != COMPLEX_TYPE)
-       return fold_convert_loc (loc, type, integer_zero_node);
+       return build_zero_cst (type);
       if (TREE_CODE (arg0) == COMPLEX_EXPR)
        return omit_one_operand_loc (loc, type, TREE_OPERAND (arg0, 1),
                                 TREE_OPERAND (arg0, 0));
@@ -8681,6 +8696,7 @@ fold_comparison (location_t loc, enum tree_code code, tree type,
       else if (TREE_CODE (arg0) == POINTER_PLUS_EXPR)
        {
          base0 = TREE_OPERAND (arg0, 0);
+         STRIP_SIGN_NOPS (base0);
          if (TREE_CODE (base0) == ADDR_EXPR)
            {
              base0 = TREE_OPERAND (base0, 0);
@@ -8703,6 +8719,7 @@ fold_comparison (location_t loc, enum tree_code code, tree type,
       else if (TREE_CODE (arg1) == POINTER_PLUS_EXPR)
        {
          base1 = TREE_OPERAND (arg1, 0);
+         STRIP_SIGN_NOPS (base1);
          if (TREE_CODE (base1) == ADDR_EXPR)
            {
              base1 = TREE_OPERAND (base1, 0);
@@ -9285,7 +9302,7 @@ fold_mult_zconjz (location_t loc, tree type, tree expr)
                     fold_build2_loc (loc, MULT_EXPR, itype, rpart, rpart),
                     fold_build2_loc (loc, MULT_EXPR, itype, ipart, ipart));
   return fold_build2_loc (loc, COMPLEX_EXPR, type, tem,
-                     fold_convert_loc (loc, itype, integer_zero_node));
+                         build_zero_cst (itype));
 }
 
 
@@ -10277,7 +10294,7 @@ fold_binary_loc (location_t loc,
 
       if ((!FLOAT_TYPE_P (type) || !HONOR_NANS (TYPE_MODE (type)))
          && operand_equal_p (arg0, arg1, 0))
-       return fold_convert_loc (loc, type, integer_zero_node);
+       return build_zero_cst (type);
 
       /* A - B -> A + (-B) if B is easily negatable.  */
       if (negate_expr_p (arg1)
@@ -10664,7 +10681,7 @@ fold_binary_loc (location_t loc,
       if (TREE_CODE (arg0) == BIT_NOT_EXPR
          && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
        {
-         t1 = fold_convert_loc (loc, type, integer_zero_node);
+         t1 = build_zero_cst (type);
          t1 = fold_unary_loc (loc, BIT_NOT_EXPR, type, t1);
          return omit_one_operand_loc (loc, type, t1, arg1);
        }
@@ -10673,7 +10690,7 @@ fold_binary_loc (location_t loc,
       if (TREE_CODE (arg1) == BIT_NOT_EXPR
          && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
        {
-         t1 = fold_convert_loc (loc, type, integer_zero_node);
+         t1 = build_zero_cst (type);
          t1 = fold_unary_loc (loc, BIT_NOT_EXPR, type, t1);
          return omit_one_operand_loc (loc, type, t1, arg0);
        }
@@ -10803,7 +10820,7 @@ fold_binary_loc (location_t loc,
       if (TREE_CODE (arg0) == BIT_NOT_EXPR
          && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
        {
-         t1 = fold_convert_loc (loc, type, integer_zero_node);
+         t1 = build_zero_cst (type);
          t1 = fold_unary_loc (loc, BIT_NOT_EXPR, type, t1);
          return omit_one_operand_loc (loc, type, t1, arg1);
        }
@@ -10812,7 +10829,7 @@ fold_binary_loc (location_t loc,
       if (TREE_CODE (arg1) == BIT_NOT_EXPR
          && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
        {
-         t1 = fold_convert_loc (loc, type, integer_zero_node);
+         t1 = build_zero_cst (type);
          t1 = fold_unary_loc (loc, BIT_NOT_EXPR, type, t1);
          return omit_one_operand_loc (loc, type, t1, arg0);
        }
@@ -11067,6 +11084,126 @@ fold_binary_loc (location_t loc,
                              fold_convert_loc (loc, type, arg0));
        }
 
+      /* For constants M and N, if M == (1LL << cst) - 1 && (N & M) == M,
+        ((A & N) + B) & M -> (A + B) & M
+        Similarly if (N & M) == 0,
+        ((A | N) + B) & M -> (A + B) & M
+        and for - instead of + (or unary - instead of +)
+        and/or ^ instead of |.
+        If B is constant and (B & M) == 0, fold into A & M.  */
+      if (host_integerp (arg1, 1))
+       {
+         unsigned HOST_WIDE_INT cst1 = tree_low_cst (arg1, 1);
+         if (~cst1 && (cst1 & (cst1 + 1)) == 0
+             && INTEGRAL_TYPE_P (TREE_TYPE (arg0))
+             && (TREE_CODE (arg0) == PLUS_EXPR
+                 || TREE_CODE (arg0) == MINUS_EXPR
+                 || TREE_CODE (arg0) == NEGATE_EXPR)
+             && (TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0))
+                 || TREE_CODE (TREE_TYPE (arg0)) == INTEGER_TYPE))
+           {
+             tree pmop[2];
+             int which = 0;
+             unsigned HOST_WIDE_INT cst0;
+
+             /* Now we know that arg0 is (C + D) or (C - D) or
+                -C and arg1 (M) is == (1LL << cst) - 1.
+                Store C into PMOP[0] and D into PMOP[1].  */
+             pmop[0] = TREE_OPERAND (arg0, 0);
+             pmop[1] = NULL;
+             if (TREE_CODE (arg0) != NEGATE_EXPR)
+               {
+                 pmop[1] = TREE_OPERAND (arg0, 1);
+                 which = 1;
+               }
+
+             if (!host_integerp (TYPE_MAX_VALUE (TREE_TYPE (arg0)), 1)
+                 || (tree_low_cst (TYPE_MAX_VALUE (TREE_TYPE (arg0)), 1)
+                     & cst1) != cst1)
+               which = -1;
+
+             for (; which >= 0; which--)
+               switch (TREE_CODE (pmop[which]))
+                 {
+                 case BIT_AND_EXPR:
+                 case BIT_IOR_EXPR:
+                 case BIT_XOR_EXPR:
+                   if (TREE_CODE (TREE_OPERAND (pmop[which], 1))
+                       != INTEGER_CST)
+                     break;
+                   /* tree_low_cst not used, because we don't care about
+                      the upper bits.  */
+                   cst0 = TREE_INT_CST_LOW (TREE_OPERAND (pmop[which], 1));
+                   cst0 &= cst1;
+                   if (TREE_CODE (pmop[which]) == BIT_AND_EXPR)
+                     {
+                       if (cst0 != cst1)
+                         break;
+                     }
+                   else if (cst0 != 0)
+                     break;
+                   /* If C or D is of the form (A & N) where
+                      (N & M) == M, or of the form (A | N) or
+                      (A ^ N) where (N & M) == 0, replace it with A.  */
+                   pmop[which] = TREE_OPERAND (pmop[which], 0);
+                   break;
+                 case INTEGER_CST:
+                   /* If C or D is a N where (N & M) == 0, it can be
+                      omitted (assumed 0).  */
+                   if ((TREE_CODE (arg0) == PLUS_EXPR
+                        || (TREE_CODE (arg0) == MINUS_EXPR && which == 0))
+                       && (TREE_INT_CST_LOW (pmop[which]) & cst1) == 0)
+                     pmop[which] = NULL;
+                   break;
+                 default:
+                   break;
+                 }
+
+             /* Only build anything new if we optimized one or both arguments
+                above.  */
+             if (pmop[0] != TREE_OPERAND (arg0, 0)
+                 || (TREE_CODE (arg0) != NEGATE_EXPR
+                     && pmop[1] != TREE_OPERAND (arg0, 1)))
+               {
+                 tree utype = TREE_TYPE (arg0);
+                 if (! TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0)))
+                   {
+                     /* Perform the operations in a type that has defined
+                        overflow behavior.  */
+                     utype = unsigned_type_for (TREE_TYPE (arg0));
+                     if (pmop[0] != NULL)
+                       pmop[0] = fold_convert_loc (loc, utype, pmop[0]);
+                     if (pmop[1] != NULL)
+                       pmop[1] = fold_convert_loc (loc, utype, pmop[1]);
+                   }
+
+                 if (TREE_CODE (arg0) == NEGATE_EXPR)
+                   tem = fold_build1_loc (loc, NEGATE_EXPR, utype, pmop[0]);
+                 else if (TREE_CODE (arg0) == PLUS_EXPR)
+                   {
+                     if (pmop[0] != NULL && pmop[1] != NULL)
+                       tem = fold_build2_loc (loc, PLUS_EXPR, utype,
+                                              pmop[0], pmop[1]);
+                     else if (pmop[0] != NULL)
+                       tem = pmop[0];
+                     else if (pmop[1] != NULL)
+                       tem = pmop[1];
+                     else
+                       return build_int_cst (type, 0);
+                   }
+                 else if (pmop[0] == NULL)
+                   tem = fold_build1_loc (loc, NEGATE_EXPR, utype, pmop[1]);
+                 else
+                   tem = fold_build2_loc (loc, MINUS_EXPR, utype,
+                                          pmop[0], pmop[1]);
+                 /* TEM is now the new binary +, - or unary - replacement.  */
+                 tem = fold_build2_loc (loc, BIT_AND_EXPR, utype, tem,
+                                        fold_convert_loc (loc, utype, arg1));
+                 return fold_convert_loc (loc, type, tem);
+               }
+           }
+       }
+
       t1 = distribute_bit_expr (loc, code, type, arg0, arg1);
       if (t1 != NULL_TREE)
        return t1;
@@ -11475,6 +11612,31 @@ fold_binary_loc (location_t loc,
       return NULL_TREE;
 
     case TRUNC_DIV_EXPR:
+      /* Optimize (X & (-A)) / A where A is a power of 2,
+        to X >> log2(A) */
+      if (TREE_CODE (arg0) == BIT_AND_EXPR
+         && !TYPE_UNSIGNED (type) && TREE_CODE (arg1) == INTEGER_CST
+         && integer_pow2p (arg1) && tree_int_cst_sgn (arg1) > 0)
+       {
+         tree sum = fold_binary_loc (loc, PLUS_EXPR, TREE_TYPE (arg1),
+                                     arg1, TREE_OPERAND (arg0, 1));
+         if (sum && integer_zerop (sum)) {
+           unsigned long pow2;
+
+           if (TREE_INT_CST_LOW (arg1))
+             pow2 = exact_log2 (TREE_INT_CST_LOW (arg1));
+           else
+             pow2 = exact_log2 (TREE_INT_CST_HIGH (arg1))
+                     + HOST_BITS_PER_WIDE_INT;
+
+           return fold_build2_loc (loc, RSHIFT_EXPR, type,
+                         TREE_OPERAND (arg0, 0),
+                         build_int_cst (NULL_TREE, pow2));
+         }
+       }
+
+      /* Fall thru */
+      
     case FLOOR_DIV_EXPR:
       /* Simplify A / (B << N) where A and B are positive and B is
         a power of 2, to A >> (N + log2(B)).  */
@@ -11487,7 +11649,13 @@ fold_binary_loc (location_t loc,
          if (integer_pow2p (sval) && tree_int_cst_sgn (sval) > 0)
            {
              tree sh_cnt = TREE_OPERAND (arg1, 1);
-             unsigned long pow2 = exact_log2 (TREE_INT_CST_LOW (sval));
+             unsigned long pow2;
+
+             if (TREE_INT_CST_LOW (sval))
+               pow2 = exact_log2 (TREE_INT_CST_LOW (sval));
+             else
+               pow2 = exact_log2 (TREE_INT_CST_HIGH (sval))
+                      + HOST_BITS_PER_WIDE_INT;
 
              if (strict_overflow_p)
                fold_overflow_warning (("assuming signed overflow does not "
@@ -13132,10 +13300,10 @@ contains_label_p (tree st)
 
 tree
 fold_ternary_loc (location_t loc, enum tree_code code, tree type,
-             tree op0, tree op1, tree op2)
+                 tree op0, tree op1, tree op2)
 {
   tree tem;
-  tree arg0 = NULL_TREE, arg1 = NULL_TREE;
+  tree arg0 = NULL_TREE, arg1 = NULL_TREE, arg2 = NULL_TREE;
   enum tree_code_class kind = TREE_CODE_CLASS (code);
 
   gcc_assert (IS_EXPR_CODE_CLASS (kind)
@@ -13163,6 +13331,12 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
       STRIP_NOPS (arg1);
     }
 
+  if (op2)
+    {
+      arg2 = op2;
+      STRIP_NOPS (arg2);
+    }
+
   switch (code)
     {
     case COMPONENT_REF:
@@ -13449,7 +13623,7 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
              if (elements)
                return TREE_VALUE (elements);
              else
-               return fold_convert_loc (loc, type, integer_zero_node);
+               return build_zero_cst (type);
            }
        }
 
@@ -13461,6 +13635,17 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
 
       return NULL_TREE;
 
+    case FMA_EXPR:
+      /* For integers we can decompose the FMA if possible.  */
+      if (TREE_CODE (arg0) == INTEGER_CST
+         && TREE_CODE (arg1) == INTEGER_CST)
+       return fold_build2_loc (loc, PLUS_EXPR, type,
+                               const_binop (MULT_EXPR, arg0, arg1), arg2);
+      if (integer_zerop (arg2))
+       return fold_build2_loc (loc, MULT_EXPR, type, arg0, arg1);
+
+      return fold_fma (loc, type, arg0, arg1, arg2);
+
     default:
       return NULL_TREE;
     } /* switch (code) */
@@ -13644,7 +13829,7 @@ fold_check_failed (const_tree expr ATTRIBUTE_UNUSED, const_tree ret ATTRIBUTE_UN
 static void
 fold_checksum_tree (const_tree expr, struct md5_ctx *ctx, htab_t ht)
 {
-  const void **slot;
+  void **slot;
   enum tree_code code;
   union tree_node buf;
   int i, len;
@@ -13656,10 +13841,10 @@ recursive_label:
              && sizeof (struct tree_type) <= sizeof (struct tree_function_decl));
   if (expr == NULL)
     return;
-  slot = (const void **) htab_find_slot (ht, expr, INSERT);
+  slot = (void **) htab_find_slot (ht, expr, INSERT);
   if (*slot != NULL)
     return;
-  *slot = expr;
+  *slot = CONST_CAST_TREE (expr);
   code = TREE_CODE (expr);
   if (TREE_CODE_CLASS (code) == tcc_declaration
       && DECL_ASSEMBLER_NAME_SET_P (expr))
@@ -15494,53 +15679,59 @@ fold_indirect_ref_1 (location_t loc, tree type, tree op0)
        }
     }
 
-  /* ((foo*)&vectorfoo)[1] => BIT_FIELD_REF<vectorfoo,...> */
   if (TREE_CODE (sub) == POINTER_PLUS_EXPR
       && TREE_CODE (TREE_OPERAND (sub, 1)) == INTEGER_CST)
     {
       tree op00 = TREE_OPERAND (sub, 0);
       tree op01 = TREE_OPERAND (sub, 1);
-      tree op00type;
 
       STRIP_NOPS (op00);
-      op00type = TREE_TYPE (op00);
-      if (TREE_CODE (op00) == ADDR_EXPR
-          && TREE_CODE (TREE_TYPE (op00type)) == VECTOR_TYPE
-          && type == TREE_TYPE (TREE_TYPE (op00type)))
+      if (TREE_CODE (op00) == ADDR_EXPR)
        {
-         HOST_WIDE_INT offset = tree_low_cst (op01, 0);
-         tree part_width = TYPE_SIZE (type);
-         unsigned HOST_WIDE_INT part_widthi = tree_low_cst (part_width, 0)/BITS_PER_UNIT;
-         unsigned HOST_WIDE_INT indexi = offset * BITS_PER_UNIT;
-         tree index = bitsize_int (indexi);
-
-         if (offset/part_widthi <= TYPE_VECTOR_SUBPARTS (TREE_TYPE (op00type)))
-           return fold_build3_loc (loc,
-                               BIT_FIELD_REF, type, TREE_OPERAND (op00, 0),
-                               part_width, index);
-
-       }
-    }
+         tree op00type;
+         op00 = TREE_OPERAND (op00, 0);
+         op00type = TREE_TYPE (op00);
 
+         /* ((foo*)&vectorfoo)[1] => BIT_FIELD_REF<vectorfoo,...> */
+         if (TREE_CODE (op00type) == VECTOR_TYPE
+             && type == TREE_TYPE (op00type))
+           {
+             HOST_WIDE_INT offset = tree_low_cst (op01, 0);
+             tree part_width = TYPE_SIZE (type);
+             unsigned HOST_WIDE_INT part_widthi = tree_low_cst (part_width, 0)/BITS_PER_UNIT;
+             unsigned HOST_WIDE_INT indexi = offset * BITS_PER_UNIT;
+             tree index = bitsize_int (indexi);
 
-  /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */
-  if (TREE_CODE (sub) == POINTER_PLUS_EXPR
-      && TREE_CODE (TREE_OPERAND (sub, 1)) == INTEGER_CST)
-    {
-      tree op00 = TREE_OPERAND (sub, 0);
-      tree op01 = TREE_OPERAND (sub, 1);
-      tree op00type;
+             if (offset/part_widthi <= TYPE_VECTOR_SUBPARTS (op00type))
+               return fold_build3_loc (loc,
+                                       BIT_FIELD_REF, type, op00,
+                                       part_width, index);
 
-      STRIP_NOPS (op00);
-      op00type = TREE_TYPE (op00);
-      if (TREE_CODE (op00) == ADDR_EXPR
-         && TREE_CODE (TREE_TYPE (op00type)) == COMPLEX_TYPE
-         && type == TREE_TYPE (TREE_TYPE (op00type)))
-       {
-         tree size = TYPE_SIZE_UNIT (type);
-         if (tree_int_cst_equal (size, op01))
-           return fold_build1_loc (loc, IMAGPART_EXPR, type,
-                               TREE_OPERAND (op00, 0));
+           }
+         /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */
+         else if (TREE_CODE (op00type) == COMPLEX_TYPE
+                  && type == TREE_TYPE (op00type))
+           {
+             tree size = TYPE_SIZE_UNIT (type);
+             if (tree_int_cst_equal (size, op01))
+               return fold_build1_loc (loc, IMAGPART_EXPR, type, op00);
+           }
+         /* ((foo *)&fooarray)[1] => fooarray[1] */
+         else if (TREE_CODE (op00type) == ARRAY_TYPE
+                  && type == TREE_TYPE (op00type))
+           {
+             tree type_domain = TYPE_DOMAIN (op00type);
+             tree min_val = size_zero_node;
+             if (type_domain && TYPE_MIN_VALUE (type_domain))
+               min_val = TYPE_MIN_VALUE (type_domain);
+             op01 = size_binop_loc (loc, EXACT_DIV_EXPR, op01,
+                                    TYPE_SIZE_UNIT (type));
+             op01 = size_binop_loc (loc, PLUS_EXPR, op01, min_val);
+             op0 = build4 (ARRAY_REF, type, op00, op01,
+                           NULL_TREE, NULL_TREE);
+             SET_EXPR_LOCATION (op0, loc);
+             return op0;
+           }
        }
     }