OSDN Git Service

PR rtl-optimization/36006
[pf3gnuchains/gcc-fork.git] / gcc / fold-const.c
index 7ee72ff..4015f62 100644 (file)
@@ -58,6 +58,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "rtl.h"
 #include "expr.h"
 #include "tm_p.h"
+#include "target.h"
 #include "toplev.h"
 #include "intl.h"
 #include "ggc.h"
@@ -109,12 +110,9 @@ static int twoval_comparison_p (tree, tree *, tree *, int *);
 static tree eval_subst (tree, tree, tree, tree, tree);
 static tree pedantic_omit_one_operand (tree, tree, tree);
 static tree distribute_bit_expr (enum tree_code, tree, tree, tree);
-static tree make_bit_field_ref (tree, tree, int, int, int);
-static tree optimize_bit_field_compare (enum tree_code, tree, tree, tree);
 static tree decode_field_reference (tree, HOST_WIDE_INT *, HOST_WIDE_INT *,
                                    enum machine_mode *, int *, int *,
                                    tree *, tree *);
-static int all_ones_mask_p (const_tree, int);
 static tree sign_bit_p (tree, const_tree);
 static int simple_operand_p (const_tree);
 static tree range_binop (enum tree_code, tree, tree, int, tree, int);
@@ -1014,7 +1012,6 @@ fold_deferring_overflow_warnings_p (void)
 static void
 fold_overflow_warning (const char* gmsgid, enum warn_strict_overflow_code wc)
 {
-  gcc_assert (!flag_wrapv && !flag_trapv);
   if (fold_deferring_overflow_warnings > 0)
     {
       if (fold_deferred_overflow_warning == NULL
@@ -3029,6 +3026,11 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
   if (TREE_CODE (arg0) == ERROR_MARK || TREE_CODE (arg1) == ERROR_MARK)
     return 0;
 
+  /* Check equality of integer constants before bailing out due to
+     precision differences.  */
+  if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
+    return tree_int_cst_equal (arg0, arg1);
+
   /* If both types don't have the same signedness, then we can't consider
      them equal.  We must check this before the STRIP_NOPS calls
      because they may change the signedness of the arguments.  */
@@ -3855,202 +3857,6 @@ distribute_real_division (enum tree_code code, tree type, tree arg0, tree arg1)
   return NULL_TREE;
 }
 \f
-/* Return a BIT_FIELD_REF of type TYPE to refer to BITSIZE bits of INNER
-   starting at BITPOS.  The field is unsigned if UNSIGNEDP is nonzero.  */
-
-static tree
-make_bit_field_ref (tree inner, tree type, int bitsize, int bitpos,
-                   int unsignedp)
-{
-  tree result;
-
-  if (bitpos == 0)
-    {
-      tree size = TYPE_SIZE (TREE_TYPE (inner));
-      if ((INTEGRAL_TYPE_P (TREE_TYPE (inner))
-          || POINTER_TYPE_P (TREE_TYPE (inner)))
-         && host_integerp (size, 0) 
-         && tree_low_cst (size, 0) == bitsize)
-       return fold_convert (type, inner);
-    }
-
-  result = build3 (BIT_FIELD_REF, type, inner,
-                  size_int (bitsize), bitsize_int (bitpos));
-
-  BIT_FIELD_REF_UNSIGNED (result) = unsignedp;
-
-  return result;
-}
-
-/* Optimize a bit-field compare.
-
-   There are two cases:  First is a compare against a constant and the
-   second is a comparison of two items where the fields are at the same
-   bit position relative to the start of a chunk (byte, halfword, word)
-   large enough to contain it.  In these cases we can avoid the shift
-   implicit in bitfield extractions.
-
-   For constants, we emit a compare of the shifted constant with the
-   BIT_AND_EXPR of a mask and a byte, halfword, or word of the operand being
-   compared.  For two fields at the same position, we do the ANDs with the
-   similar mask and compare the result of the ANDs.
-
-   CODE is the comparison code, known to be either NE_EXPR or EQ_EXPR.
-   COMPARE_TYPE is the type of the comparison, and LHS and RHS
-   are the left and right operands of the comparison, respectively.
-
-   If the optimization described above can be done, we return the resulting
-   tree.  Otherwise we return zero.  */
-
-static tree
-optimize_bit_field_compare (enum tree_code code, tree compare_type,
-                           tree lhs, tree rhs)
-{
-  HOST_WIDE_INT lbitpos, lbitsize, rbitpos, rbitsize, nbitpos, nbitsize;
-  tree type = TREE_TYPE (lhs);
-  tree signed_type, unsigned_type;
-  int const_p = TREE_CODE (rhs) == INTEGER_CST;
-  enum machine_mode lmode, rmode, nmode;
-  int lunsignedp, runsignedp;
-  int lvolatilep = 0, rvolatilep = 0;
-  tree linner, rinner = NULL_TREE;
-  tree mask;
-  tree offset;
-
-  /* Get all the information about the extractions being done.  If the bit size
-     if the same as the size of the underlying object, we aren't doing an
-     extraction at all and so can do nothing.  We also don't want to
-     do anything if the inner expression is a PLACEHOLDER_EXPR since we
-     then will no longer be able to replace it.  */
-  linner = get_inner_reference (lhs, &lbitsize, &lbitpos, &offset, &lmode,
-                               &lunsignedp, &lvolatilep, false);
-  if (linner == lhs || lbitsize == GET_MODE_BITSIZE (lmode) || lbitsize < 0
-      || offset != 0 || TREE_CODE (linner) == PLACEHOLDER_EXPR)
-    return 0;
-
- if (!const_p)
-   {
-     /* If this is not a constant, we can only do something if bit positions,
-       sizes, and signedness are the same.  */
-     rinner = get_inner_reference (rhs, &rbitsize, &rbitpos, &offset, &rmode,
-                                  &runsignedp, &rvolatilep, false);
-
-     if (rinner == rhs || lbitpos != rbitpos || lbitsize != rbitsize
-        || lunsignedp != runsignedp || offset != 0
-        || TREE_CODE (rinner) == PLACEHOLDER_EXPR)
-       return 0;
-   }
-
-  /* See if we can find a mode to refer to this field.  We should be able to,
-     but fail if we can't.  */
-  nmode = get_best_mode (lbitsize, lbitpos,
-                        const_p ? TYPE_ALIGN (TREE_TYPE (linner))
-                        : MIN (TYPE_ALIGN (TREE_TYPE (linner)),
-                               TYPE_ALIGN (TREE_TYPE (rinner))),
-                        word_mode, lvolatilep || rvolatilep);
-  if (nmode == VOIDmode)
-    return 0;
-
-  /* Set signed and unsigned types of the precision of this mode for the
-     shifts below.  */
-  signed_type = lang_hooks.types.type_for_mode (nmode, 0);
-  unsigned_type = lang_hooks.types.type_for_mode (nmode, 1);
-
-  /* Compute the bit position and size for the new reference and our offset
-     within it. If the new reference is the same size as the original, we
-     won't optimize anything, so return zero.  */
-  nbitsize = GET_MODE_BITSIZE (nmode);
-  nbitpos = lbitpos & ~ (nbitsize - 1);
-  lbitpos -= nbitpos;
-  if (nbitsize == lbitsize)
-    return 0;
-
-  if (BYTES_BIG_ENDIAN)
-    lbitpos = nbitsize - lbitsize - lbitpos;
-
-  /* Make the mask to be used against the extracted field.  */
-  mask = build_int_cst_type (unsigned_type, -1);
-  mask = const_binop (LSHIFT_EXPR, mask, size_int (nbitsize - lbitsize), 0);
-  mask = const_binop (RSHIFT_EXPR, mask,
-                     size_int (nbitsize - lbitsize - lbitpos), 0);
-
-  if (! const_p)
-    /* If not comparing with constant, just rework the comparison
-       and return.  */
-    return fold_build2 (code, compare_type,
-                       fold_build2 (BIT_AND_EXPR, unsigned_type,
-                                    make_bit_field_ref (linner,
-                                                        unsigned_type,
-                                                        nbitsize, nbitpos,
-                                                        1),
-                                    mask),
-                       fold_build2 (BIT_AND_EXPR, unsigned_type,
-                                    make_bit_field_ref (rinner,
-                                                        unsigned_type,
-                                                        nbitsize, nbitpos,
-                                                        1),
-                                    mask));
-
-  /* Otherwise, we are handling the constant case. See if the constant is too
-     big for the field.  Warn and return a tree of for 0 (false) if so.  We do
-     this not only for its own sake, but to avoid having to test for this
-     error case below.  If we didn't, we might generate wrong code.
-
-     For unsigned fields, the constant shifted right by the field length should
-     be all zero.  For signed fields, the high-order bits should agree with
-     the sign bit.  */
-
-  if (lunsignedp)
-    {
-      if (! integer_zerop (const_binop (RSHIFT_EXPR,
-                                       fold_convert (unsigned_type, rhs),
-                                       size_int (lbitsize), 0)))
-       {
-         warning (0, "comparison is always %d due to width of bit-field",
-                  code == NE_EXPR);
-         return constant_boolean_node (code == NE_EXPR, compare_type);
-       }
-    }
-  else
-    {
-      tree tem = const_binop (RSHIFT_EXPR, fold_convert (signed_type, rhs),
-                             size_int (lbitsize - 1), 0);
-      if (! integer_zerop (tem) && ! integer_all_onesp (tem))
-       {
-         warning (0, "comparison is always %d due to width of bit-field",
-                  code == NE_EXPR);
-         return constant_boolean_node (code == NE_EXPR, compare_type);
-       }
-    }
-
-  /* Single-bit compares should always be against zero.  */
-  if (lbitsize == 1 && ! integer_zerop (rhs))
-    {
-      code = code == EQ_EXPR ? NE_EXPR : EQ_EXPR;
-      rhs = build_int_cst (type, 0);
-    }
-
-  /* Make a new bitfield reference, shift the constant over the
-     appropriate number of bits and mask it with the computed mask
-     (in case this was a signed field).  If we changed it, make a new one.  */
-  lhs = make_bit_field_ref (linner, unsigned_type, nbitsize, nbitpos, 1);
-  if (lvolatilep)
-    {
-      TREE_SIDE_EFFECTS (lhs) = 1;
-      TREE_THIS_VOLATILE (lhs) = 1;
-    }
-
-  rhs = const_binop (BIT_AND_EXPR,
-                    const_binop (LSHIFT_EXPR,
-                                 fold_convert (unsigned_type, rhs),
-                                 size_int (lbitpos), 0),
-                    mask, 0);
-
-  return build2 (code, compare_type,
-                build2 (BIT_AND_EXPR, unsigned_type, lhs, mask),
-                rhs);
-}
-\f
 /* Subroutine for fold_truthop: decode a field reference.
 
    If EXP is a comparison reference, we return the innermost reference.
@@ -4142,27 +3948,6 @@ decode_field_reference (tree exp, HOST_WIDE_INT *pbitsize,
   return inner;
 }
 
-/* Return nonzero if MASK represents a mask of SIZE ones in the low-order
-   bit positions.  */
-
-static int
-all_ones_mask_p (const_tree mask, int size)
-{
-  tree type = TREE_TYPE (mask);
-  unsigned int precision = TYPE_PRECISION (type);
-  tree tmask;
-
-  tmask = build_int_cst_type (signed_type_for (type), -1);
-
-  return
-    tree_int_cst_equal (mask,
-                       const_binop (RSHIFT_EXPR,
-                                    const_binop (LSHIFT_EXPR, tmask,
-                                                 size_int (precision - size),
-                                                 0),
-                                    size_int (precision - size), 0));
-}
-
 /* Subroutine for fold: determine if VAL is the INTEGER_CONST that
    represents the sign bit of EXP's type.  If EXP represents a sign
    or zero extension, also test VAL against the unextended type.
@@ -5488,15 +5273,15 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
   tree ll_inner, lr_inner, rl_inner, rr_inner;
   HOST_WIDE_INT ll_bitsize, ll_bitpos, lr_bitsize, lr_bitpos;
   HOST_WIDE_INT rl_bitsize, rl_bitpos, rr_bitsize, rr_bitpos;
-  HOST_WIDE_INT xll_bitpos, xlr_bitpos, xrl_bitpos, xrr_bitpos;
-  HOST_WIDE_INT lnbitsize, lnbitpos, rnbitsize, rnbitpos;
+  HOST_WIDE_INT xll_bitpos, xrl_bitpos;
+  HOST_WIDE_INT lnbitsize, lnbitpos;
   int ll_unsignedp, lr_unsignedp, rl_unsignedp, rr_unsignedp;
   enum machine_mode ll_mode, lr_mode, rl_mode, rr_mode;
-  enum machine_mode lnmode, rnmode;
+  enum machine_mode lnmode;
   tree ll_mask, lr_mask, rl_mask, rr_mask;
   tree ll_and_mask, lr_and_mask, rl_and_mask, rr_and_mask;
   tree l_const, r_const;
-  tree lntype, rntype, result;
+  tree lntype, result;
   int first_bit, end_bit;
   int volatilep;
   tree orig_lhs = lhs, orig_rhs = rhs;
@@ -5577,7 +5362,8 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
       if (code == TRUTH_OR_EXPR
          && lcode == NE_EXPR && integer_zerop (lr_arg)
          && rcode == NE_EXPR && integer_zerop (rr_arg)
-         && TREE_TYPE (ll_arg) == TREE_TYPE (rl_arg))
+         && TREE_TYPE (ll_arg) == TREE_TYPE (rl_arg)
+         && INTEGRAL_TYPE_P (TREE_TYPE (ll_arg)))
        return build2 (NE_EXPR, truth_type,
                       build2 (BIT_IOR_EXPR, TREE_TYPE (ll_arg),
                               ll_arg, rl_arg),
@@ -5587,7 +5373,8 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
       if (code == TRUTH_AND_EXPR
          && lcode == EQ_EXPR && integer_zerop (lr_arg)
          && rcode == EQ_EXPR && integer_zerop (rr_arg)
-         && TREE_TYPE (ll_arg) == TREE_TYPE (rl_arg))
+         && TREE_TYPE (ll_arg) == TREE_TYPE (rl_arg)
+         && INTEGRAL_TYPE_P (TREE_TYPE (ll_arg)))
        return build2 (EQ_EXPR, truth_type,
                       build2 (BIT_IOR_EXPR, TREE_TYPE (ll_arg),
                               ll_arg, rl_arg),
@@ -5732,118 +5519,6 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
        }
     }
 
-  /* If the right sides are not constant, do the same for it.  Also,
-     disallow this optimization if a size or signedness mismatch occurs
-     between the left and right sides.  */
-  if (l_const == 0)
-    {
-      if (ll_bitsize != lr_bitsize || rl_bitsize != rr_bitsize
-         || ll_unsignedp != lr_unsignedp || rl_unsignedp != rr_unsignedp
-         /* Make sure the two fields on the right
-            correspond to the left without being swapped.  */
-         || ll_bitpos - rl_bitpos != lr_bitpos - rr_bitpos)
-       return 0;
-
-      first_bit = MIN (lr_bitpos, rr_bitpos);
-      end_bit = MAX (lr_bitpos + lr_bitsize, rr_bitpos + rr_bitsize);
-      rnmode = get_best_mode (end_bit - first_bit, first_bit,
-                             TYPE_ALIGN (TREE_TYPE (lr_inner)), word_mode,
-                             volatilep);
-      if (rnmode == VOIDmode)
-       return 0;
-
-      rnbitsize = GET_MODE_BITSIZE (rnmode);
-      rnbitpos = first_bit & ~ (rnbitsize - 1);
-      rntype = lang_hooks.types.type_for_size (rnbitsize, 1);
-      xlr_bitpos = lr_bitpos - rnbitpos, xrr_bitpos = rr_bitpos - rnbitpos;
-
-      if (BYTES_BIG_ENDIAN)
-       {
-         xlr_bitpos = rnbitsize - xlr_bitpos - lr_bitsize;
-         xrr_bitpos = rnbitsize - xrr_bitpos - rr_bitsize;
-       }
-
-      lr_mask = const_binop (LSHIFT_EXPR, fold_convert (rntype, lr_mask),
-                            size_int (xlr_bitpos), 0);
-      rr_mask = const_binop (LSHIFT_EXPR, fold_convert (rntype, rr_mask),
-                            size_int (xrr_bitpos), 0);
-
-      /* Make a mask that corresponds to both fields being compared.
-        Do this for both items being compared.  If the operands are the
-        same size and the bits being compared are in the same position
-        then we can do this by masking both and comparing the masked
-        results.  */
-      ll_mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask, 0);
-      lr_mask = const_binop (BIT_IOR_EXPR, lr_mask, rr_mask, 0);
-      if (lnbitsize == rnbitsize && xll_bitpos == xlr_bitpos)
-       {
-         lhs = make_bit_field_ref (ll_inner, lntype, lnbitsize, lnbitpos,
-                                   ll_unsignedp || rl_unsignedp);
-         if (! all_ones_mask_p (ll_mask, lnbitsize))
-           lhs = build2 (BIT_AND_EXPR, lntype, lhs, ll_mask);
-
-         rhs = make_bit_field_ref (lr_inner, rntype, rnbitsize, rnbitpos,
-                                   lr_unsignedp || rr_unsignedp);
-         if (! all_ones_mask_p (lr_mask, rnbitsize))
-           rhs = build2 (BIT_AND_EXPR, rntype, rhs, lr_mask);
-
-         return build2 (wanted_code, truth_type, lhs, rhs);
-       }
-
-      /* There is still another way we can do something:  If both pairs of
-        fields being compared are adjacent, we may be able to make a wider
-        field containing them both.
-
-        Note that we still must mask the lhs/rhs expressions.  Furthermore,
-        the mask must be shifted to account for the shift done by
-        make_bit_field_ref.  */
-      if ((ll_bitsize + ll_bitpos == rl_bitpos
-          && lr_bitsize + lr_bitpos == rr_bitpos)
-         || (ll_bitpos == rl_bitpos + rl_bitsize
-             && lr_bitpos == rr_bitpos + rr_bitsize))
-       {
-         tree type;
-
-         lhs = make_bit_field_ref (ll_inner, lntype, ll_bitsize + rl_bitsize,
-                                   MIN (ll_bitpos, rl_bitpos), ll_unsignedp);
-         rhs = make_bit_field_ref (lr_inner, rntype, lr_bitsize + rr_bitsize,
-                                   MIN (lr_bitpos, rr_bitpos), lr_unsignedp);
-
-         ll_mask = const_binop (RSHIFT_EXPR, ll_mask,
-                                size_int (MIN (xll_bitpos, xrl_bitpos)), 0);
-         lr_mask = const_binop (RSHIFT_EXPR, lr_mask,
-                                size_int (MIN (xlr_bitpos, xrr_bitpos)), 0);
-
-         /* Convert to the smaller type before masking out unwanted bits.  */
-         type = lntype;
-         if (lntype != rntype)
-           {
-             if (lnbitsize > rnbitsize)
-               {
-                 lhs = fold_convert (rntype, lhs);
-                 ll_mask = fold_convert (rntype, ll_mask);
-                 type = rntype;
-               }
-             else if (lnbitsize < rnbitsize)
-               {
-                 rhs = fold_convert (lntype, rhs);
-                 lr_mask = fold_convert (lntype, lr_mask);
-                 type = lntype;
-               }
-           }
-
-         if (! all_ones_mask_p (ll_mask, ll_bitsize + rl_bitsize))
-           lhs = build2 (BIT_AND_EXPR, type, lhs, ll_mask);
-
-         if (! all_ones_mask_p (lr_mask, lr_bitsize + rr_bitsize))
-           rhs = build2 (BIT_AND_EXPR, type, rhs, lr_mask);
-
-         return build2 (wanted_code, truth_type, lhs, rhs);
-       }
-
-      return 0;
-    }
-
   /* Handle the case of comparisons with constants.  If there is something in
      common between the masks, those bits of the constants must be the same.
      If not, the condition is always false.  Test for this to avoid generating
@@ -5865,19 +5540,7 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
        }
     }
 
-  /* Construct the expression we will return.  First get the component
-     reference we will make.  Unless the mask is all ones the width of
-     that field, perform the mask operation.  Then compare with the
-     merged constant.  */
-  result = make_bit_field_ref (ll_inner, lntype, lnbitsize, lnbitpos,
-                              ll_unsignedp || rl_unsignedp);
-
-  ll_mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask, 0);
-  if (! all_ones_mask_p (ll_mask, lnbitsize))
-    result = build2 (BIT_AND_EXPR, lntype, result, ll_mask);
-
-  return build2 (wanted_code, truth_type, result,
-                const_binop (BIT_IOR_EXPR, l_const, r_const, 0));
+  return NULL_TREE;
 }
 \f
 /* Optimize T, which is a comparison of a MIN_EXPR or MAX_EXPR with a
@@ -5888,7 +5551,7 @@ optimize_minmax_comparison (enum tree_code code, tree type, tree op0, tree op1)
 {
   tree arg0 = op0;
   enum tree_code op_code;
-  tree comp_const = op1;
+  tree comp_const;
   tree minmax_const;
   int consts_equal, consts_lt;
   tree inner;
@@ -5897,6 +5560,7 @@ optimize_minmax_comparison (enum tree_code code, tree type, tree op0, tree op1)
 
   op_code = TREE_CODE (arg0);
   minmax_const = TREE_OPERAND (arg0, 1);
+  comp_const = fold_convert (TREE_TYPE (arg0), op1);
   consts_equal = tree_int_cst_equal (minmax_const, comp_const);
   consts_lt = tree_int_cst_lt (minmax_const, comp_const);
   inner = TREE_OPERAND (arg0, 0);
@@ -7061,7 +6725,11 @@ fold_widened_comparison (enum tree_code code, tree type, tree arg0, tree arg1)
        || TYPE_UNSIGNED (TREE_TYPE (arg0)) == TYPE_UNSIGNED (shorter_type))
       && (TREE_TYPE (arg1_unw) == shorter_type
          || (TYPE_PRECISION (shorter_type)
-             >= TYPE_PRECISION (TREE_TYPE (arg1_unw)))
+             > TYPE_PRECISION (TREE_TYPE (arg1_unw)))
+         || ((TYPE_PRECISION (shorter_type)
+              == TYPE_PRECISION (TREE_TYPE (arg1_unw)))
+             && (TYPE_UNSIGNED (shorter_type)
+                 == TYPE_UNSIGNED (TREE_TYPE (arg1_unw))))
          || (TREE_CODE (arg1_unw) == INTEGER_CST
              && (TREE_CODE (shorter_type) == INTEGER_TYPE
                  || TREE_CODE (shorter_type) == BOOLEAN_TYPE)
@@ -7148,6 +6816,11 @@ fold_sign_changed_comparison (enum tree_code code, tree type,
   if (TYPE_PRECISION (inner_type) != TYPE_PRECISION (outer_type))
     return NULL_TREE;
 
+  /* If the conversion is from an integral subtype to its basetype
+     leave it alone.  */
+  if (TREE_TYPE (inner_type) == outer_type)
+    return NULL_TREE;
+
   if (TREE_CODE (arg1) != INTEGER_CST
       && !((TREE_CODE (arg1) == NOP_EXPR
            || TREE_CODE (arg1) == CONVERT_EXPR)
@@ -8128,9 +7801,7 @@ fold_unary (enum tree_code code, tree type, tree op0)
             - the initial type is a pointer type and the precisions of the
               intermediate and final types differ, or
             - the final type is a pointer type and the precisions of the
-              initial and intermediate types differ.
-            - the initial type is a pointer to an array and the final type
-              not.  */
+              initial and intermediate types differ.  */
          if (! inside_float && ! inter_float && ! final_float
              && ! inside_vec && ! inter_vec && ! final_vec
              && (inter_prec >= inside_prec || inter_prec >= final_prec)
@@ -8142,10 +7813,7 @@ fold_unary (enum tree_code code, tree type, tree op0)
              && ! (inside_ptr && inter_prec != final_prec)
              && ! (final_ptr && inside_prec != inter_prec)
              && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type))
-                   && TYPE_MODE (type) == TYPE_MODE (inter_type))
-             && ! (inside_ptr && final_ptr
-                   && TREE_CODE (TREE_TYPE (inside_type)) == ARRAY_TYPE
-                   && TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE))
+                   && TYPE_MODE (type) == TYPE_MODE (inter_type)))
            return fold_build1 (code, type, TREE_OPERAND (op0, 0));
        }
 
@@ -8270,6 +7938,26 @@ fold_unary (enum tree_code code, tree type, tree op0)
            return fold_build1 (BIT_NOT_EXPR, type, fold_convert (type, tem));
        }
 
+      /* Convert (T1)(X * Y) into (T1)X * (T1)Y if T1 is narrower than the
+        type of X and Y (integer types only).  */
+      if (INTEGRAL_TYPE_P (type)
+         && TREE_CODE (op0) == MULT_EXPR
+         && INTEGRAL_TYPE_P (TREE_TYPE (op0))
+         && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (op0)))
+       {
+         /* Be careful not to introduce new overflows.  */
+         tree mult_type;
+          if (TYPE_OVERFLOW_WRAPS (type))
+           mult_type = type;
+         else
+           mult_type = unsigned_type_for (type);
+         
+         tem = fold_build2 (MULT_EXPR, mult_type,
+                            fold_convert (mult_type, TREE_OPERAND (op0, 0)),
+                            fold_convert (mult_type, TREE_OPERAND (op0, 1)));
+         return fold_convert (type, tem);
+       }
+
       tem = fold_convert_const (code, type, op0);
       return tem ? tem : NULL_TREE;
 
@@ -8285,19 +7973,24 @@ fold_unary (enum tree_code code, tree type, tree op0)
 
       /* For integral conversions with the same precision or pointer
         conversions use a NOP_EXPR instead.  */
-      if ((INTEGRAL_TYPE_P (type) && INTEGRAL_TYPE_P (TREE_TYPE (op0))
-          && TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (op0))
-          /* Do not muck with VIEW_CONVERT_EXPRs that convert from
-             a sub-type to its base type as generated by the Ada FE.  */
-          && !TREE_TYPE (TREE_TYPE (op0)))
-         || (POINTER_TYPE_P (type) && POINTER_TYPE_P (TREE_TYPE (op0))))
+      if ((INTEGRAL_TYPE_P (type)
+          || POINTER_TYPE_P (type))
+         && (INTEGRAL_TYPE_P (TREE_TYPE (op0))
+             || POINTER_TYPE_P (TREE_TYPE (op0)))
+         && TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (op0))
+         /* Do not muck with VIEW_CONVERT_EXPRs that convert from
+            a sub-type to its base type as generated by the Ada FE.  */
+         && !(INTEGRAL_TYPE_P (TREE_TYPE (op0))
+              && TREE_TYPE (TREE_TYPE (op0))))
        return fold_convert (type, op0);
 
       /* Strip inner integral conversions that do not change the precision.  */
       if ((TREE_CODE (op0) == NOP_EXPR
           || TREE_CODE (op0) == CONVERT_EXPR)
-         && INTEGRAL_TYPE_P (TREE_TYPE (op0))
-         && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (op0, 0)))
+         && (INTEGRAL_TYPE_P (TREE_TYPE (op0))
+             || POINTER_TYPE_P (TREE_TYPE (op0)))
+         && (INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (op0, 0)))
+             || POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (op0, 0))))
          && (TYPE_PRECISION (TREE_TYPE (op0))
              == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op0, 0)))))
        return fold_build1 (VIEW_CONVERT_EXPR, type, TREE_OPERAND (op0, 0));
@@ -8701,6 +8394,62 @@ maybe_canonicalize_comparison (enum tree_code code, tree type,
   return t;
 }
 
+/* Return whether BASE + OFFSET + BITPOS may wrap around the address
+   space.  This is used to avoid issuing overflow warnings for
+   expressions like &p->x which can not wrap.  */
+
+static bool
+pointer_may_wrap_p (tree base, tree offset, HOST_WIDE_INT bitpos)
+{
+  unsigned HOST_WIDE_INT offset_low, total_low;
+  HOST_WIDE_INT size, offset_high, total_high;
+
+  if (!POINTER_TYPE_P (TREE_TYPE (base)))
+    return true;
+
+  if (bitpos < 0)
+    return true;
+
+  if (offset == NULL_TREE)
+    {
+      offset_low = 0;
+      offset_high = 0;
+    }
+  else if (TREE_CODE (offset) != INTEGER_CST || TREE_OVERFLOW (offset))
+    return true;
+  else
+    {
+      offset_low = TREE_INT_CST_LOW (offset);
+      offset_high = TREE_INT_CST_HIGH (offset);
+    }
+
+  if (add_double_with_sign (offset_low, offset_high,
+                           bitpos / BITS_PER_UNIT, 0,
+                           &total_low, &total_high,
+                           true))
+    return true;
+
+  if (total_high != 0)
+    return true;
+
+  size = int_size_in_bytes (TREE_TYPE (TREE_TYPE (base)));
+  if (size <= 0)
+    return true;
+
+  /* We can do slightly better for SIZE if we have an ADDR_EXPR of an
+     array.  */
+  if (TREE_CODE (base) == ADDR_EXPR)
+    {
+      HOST_WIDE_INT base_size;
+
+      base_size = int_size_in_bytes (TREE_TYPE (TREE_OPERAND (base, 0)));
+      if (base_size > 0 && size < base_size)
+       size = base_size;
+    }
+
+  return total_low > (unsigned HOST_WIDE_INT) size;
+}
+
 /* Subroutine of fold_binary.  This routine performs all of the
    transformations that are common to the equality/inequality
    operators (EQ_EXPR and NE_EXPR) and the ordering operators
@@ -8805,11 +8554,12 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
       HOST_WIDE_INT bitsize, bitpos0 = 0, bitpos1 = 0;
       enum machine_mode mode;
       int volatilep, unsignedp;
-      bool indirect_base0 = false;
+      bool indirect_base0 = false, indirect_base1 = false;
 
       /* Get base and offset for the access.  Strip ADDR_EXPR for
         get_inner_reference, but put it back by stripping INDIRECT_REF
-        off the base object if possible.  */
+        off the base object if possible.  indirect_baseN will be true
+        if baseN is not an address but refers to the object itself.  */
       base0 = arg0;
       if (TREE_CODE (arg0) == ADDR_EXPR)
        {
@@ -8833,32 +8583,41 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
          base1 = get_inner_reference (TREE_OPERAND (arg1, 0),
                                       &bitsize, &bitpos1, &offset1, &mode,
                                       &unsignedp, &volatilep, false);
-         /* We have to make sure to have an indirect/non-indirect base1
-            just the same as we did for base0.  */
-         if (TREE_CODE (base1) == INDIRECT_REF
-             && !indirect_base0)
+         if (TREE_CODE (base1) == INDIRECT_REF)
            base1 = TREE_OPERAND (base1, 0);
-         else if (!indirect_base0)
-           base1 = NULL_TREE;
+         else
+           indirect_base1 = true;
        }
       else if (TREE_CODE (arg1) == POINTER_PLUS_EXPR)
        {
          base1 = TREE_OPERAND (arg1, 0);
          offset1 = TREE_OPERAND (arg1, 1);
        }
-      else if (indirect_base0)
-       base1 = NULL_TREE;
 
       /* If we have equivalent bases we might be able to simplify.  */
-      if (base0 && base1
+      if (indirect_base0 == indirect_base1
          && operand_equal_p (base0, base1, 0))
        {
          /* We can fold this expression to a constant if the non-constant
             offset parts are equal.  */
-         if (offset0 == offset1
-             || (offset0 && offset1
-                 && operand_equal_p (offset0, offset1, 0)))
+         if ((offset0 == offset1
+              || (offset0 && offset1
+                  && operand_equal_p (offset0, offset1, 0)))
+             && (code == EQ_EXPR
+                 || code == NE_EXPR
+                 || POINTER_TYPE_OVERFLOW_UNDEFINED))
+               
            {
+             if (code != EQ_EXPR
+                 && code != NE_EXPR
+                 && bitpos0 != bitpos1
+                 && (pointer_may_wrap_p (base0, offset0, bitpos0)
+                     || pointer_may_wrap_p (base1, offset1, bitpos1)))
+               fold_overflow_warning (("assuming pointer wraparound does not "
+                                       "occur when comparing P +- C1 with "
+                                       "P +- C2"),
+                                      WARN_STRICT_OVERFLOW_CONDITIONAL);
+
              switch (code)
                {
                case EQ_EXPR:
@@ -8883,7 +8642,9 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
             because pointer arithmetic is restricted to retain within an
             object and overflow on pointer differences is undefined as of
             6.5.6/8 and /9 with respect to the signed ptrdiff_t.  */
-         else if (bitpos0 == bitpos1)
+         else if (bitpos0 == bitpos1
+                  && ((code == EQ_EXPR || code == NE_EXPR)
+                      || POINTER_TYPE_OVERFLOW_UNDEFINED))
            {
              tree signed_size_type_node;
              signed_size_type_node = signed_type_for (size_type_node);
@@ -8902,9 +8663,60 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
              else
                offset1 = fold_convert (signed_size_type_node, offset1);
 
+             if (code != EQ_EXPR
+                 && code != NE_EXPR
+                 && (pointer_may_wrap_p (base0, offset0, bitpos0)
+                     || pointer_may_wrap_p (base1, offset1, bitpos1)))
+               fold_overflow_warning (("assuming pointer wraparound does not "
+                                       "occur when comparing P +- C1 with "
+                                       "P +- C2"),
+                                      WARN_STRICT_OVERFLOW_COMPARISON);
+
              return fold_build2 (code, type, offset0, offset1);
            }
        }
+      /* For non-equal bases we can simplify if they are addresses
+        of local binding decls or constants.  */
+      else if (indirect_base0 && indirect_base1
+              /* We know that !operand_equal_p (base0, base1, 0)
+                 because the if condition was false.  But make
+                 sure two decls are not the same.  */
+              && base0 != base1
+              && TREE_CODE (arg0) == ADDR_EXPR
+              && TREE_CODE (arg1) == ADDR_EXPR
+              && (((TREE_CODE (base0) == VAR_DECL
+                    || TREE_CODE (base0) == PARM_DECL)
+                   && (targetm.binds_local_p (base0)
+                       || CONSTANT_CLASS_P (base1)))
+                  || CONSTANT_CLASS_P (base0))
+              && (((TREE_CODE (base1) == VAR_DECL
+                    || TREE_CODE (base1) == PARM_DECL)
+                   && (targetm.binds_local_p (base1)
+                       || CONSTANT_CLASS_P (base0)))
+                  || CONSTANT_CLASS_P (base1)))
+       {
+         if (code == EQ_EXPR)
+           return omit_two_operands (type, boolean_false_node, arg0, arg1);
+         else if (code == NE_EXPR)
+           return omit_two_operands (type, boolean_true_node, arg0, arg1);
+       }
+      /* For equal offsets we can simplify to a comparison of the
+        base addresses.  */
+      else if (bitpos0 == bitpos1
+              && (indirect_base0
+                  ? base0 != TREE_OPERAND (arg0, 0) : base0 != arg0)
+              && (indirect_base1
+                  ? base1 != TREE_OPERAND (arg1, 0) : base1 != arg1)
+              && ((offset0 == offset1)
+                  || (offset0 && offset1
+                      && operand_equal_p (offset0, offset1, 0))))
+       {
+         if (indirect_base0)
+           base0 = fold_addr_expr (base0);
+         if (indirect_base1)
+           base1 = fold_addr_expr (base1);
+         return fold_build2 (code, type, base0, base1);
+       }
     }
 
   /* Transform comparisons of the form X +- C1 CMP Y +- C2 to
@@ -9251,27 +9063,6 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
        }
     }
 
-  /* Fold a comparison of the address of COMPONENT_REFs with the same
-     type and component to a comparison of the address of the base
-     object.  In short, &x->a OP &y->a to x OP y and
-     &x->a OP &y.a to x OP &y  */
-  if (TREE_CODE (arg0) == ADDR_EXPR
-      && TREE_CODE (TREE_OPERAND (arg0, 0)) == COMPONENT_REF
-      && TREE_CODE (arg1) == ADDR_EXPR
-      && TREE_CODE (TREE_OPERAND (arg1, 0)) == COMPONENT_REF)
-    {
-      tree cref0 = TREE_OPERAND (arg0, 0);
-      tree cref1 = TREE_OPERAND (arg1, 0);
-      if (TREE_OPERAND (cref0, 1) == TREE_OPERAND (cref1, 1))
-       {
-         tree op0 = TREE_OPERAND (cref0, 0);
-         tree op1 = TREE_OPERAND (cref1, 0);
-         return fold_build2 (code, type,
-                             fold_addr_expr (op0),
-                             fold_addr_expr (op1));
-       }
-    }
-
   /* We can fold X/C1 op C2 where C1 and C2 are integer constants
      into a single range test.  */
   if ((TREE_CODE (arg0) == TRUNC_DIV_EXPR
@@ -9389,7 +9180,7 @@ get_pointer_modulus_and_residue (tree expr, unsigned HOST_WIDE_INT *residue)
            }
        }
 
-      if (DECL_P (expr))
+      if (DECL_P (expr) && TREE_CODE (expr) != FUNCTION_DECL)
        return DECL_ALIGN_UNIT (expr);
     }
   else if (code == POINTER_PLUS_EXPR)
@@ -10005,7 +9796,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
 
          /* With undefined overflow we can only associate constants
             with one variable.  */
-         if ((POINTER_TYPE_P (type)
+         if (((POINTER_TYPE_P (type) && POINTER_TYPE_OVERFLOW_UNDEFINED)
               || (INTEGRAL_TYPE_P (type) && !TYPE_OVERFLOW_WRAPS (type)))
              && var0 && var1)
            {
@@ -10724,8 +10515,10 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
        {
          return fold_build1 (BIT_NOT_EXPR, type,
                              build2 (BIT_AND_EXPR, type,
-                                     TREE_OPERAND (arg0, 0),
-                                     TREE_OPERAND (arg1, 0)));
+                                     fold_convert (type,
+                                                   TREE_OPERAND (arg0, 0)),
+                                     fold_convert (type,
+                                                   TREE_OPERAND (arg1, 0))));
        }
 
       /* See if this can be simplified into a rotate first.  If that
@@ -12192,18 +11985,6 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
            return omit_one_operand (type, rslt, arg0);
        }
 
-      /* If this is a comparison of a field, we may be able to simplify it.  */
-      if ((TREE_CODE (arg0) == COMPONENT_REF
-          || TREE_CODE (arg0) == BIT_FIELD_REF)
-         /* Handle the constant case even without -O
-            to make sure the warnings are given.  */
-         && (optimize || TREE_CODE (arg1) == INTEGER_CST))
-       {
-         t1 = optimize_bit_field_compare (code, type, arg0, arg1);
-         if (t1)
-           return t1;
-       }
-
       /* Optimize comparisons of strlen vs zero to a compare of the
         first character of the string vs zero.  To wit,
                strlen(ptr) == 0   =>  *ptr == 0
@@ -13289,9 +13070,7 @@ fold_ternary (enum tree_code code, tree type, tree op0, tree op1, tree op2)
     case BIT_FIELD_REF:
       if ((TREE_CODE (arg0) == VECTOR_CST
           || (TREE_CODE (arg0) == CONSTRUCTOR && TREE_CONSTANT (arg0)))
-         && type == TREE_TYPE (TREE_TYPE (arg0))
-         && host_integerp (arg1, 1)
-         && host_integerp (op2, 1))
+         && type == TREE_TYPE (TREE_TYPE (arg0)))
        {
          unsigned HOST_WIDE_INT width = tree_low_cst (arg1, 1);
          unsigned HOST_WIDE_INT idx = tree_low_cst (op2, 1);
@@ -13396,6 +13175,45 @@ fold (tree expr)
 
   switch (code)
     {
+    case ARRAY_REF:
+      {
+       tree op0 = TREE_OPERAND (t, 0);
+       tree op1 = TREE_OPERAND (t, 1);
+
+       if (TREE_CODE (op1) == INTEGER_CST
+           && TREE_CODE (op0) == CONSTRUCTOR
+           && ! type_contains_placeholder_p (TREE_TYPE (op0)))
+         {
+           VEC(constructor_elt,gc) *elts = CONSTRUCTOR_ELTS (op0);
+           unsigned HOST_WIDE_INT end = VEC_length (constructor_elt, elts);
+           unsigned HOST_WIDE_INT begin = 0;
+
+           /* Find a matching index by means of a binary search.  */
+           while (begin != end)
+             {
+               unsigned HOST_WIDE_INT middle = (begin + end) / 2;
+               tree index = VEC_index (constructor_elt, elts, middle)->index;
+
+               if (TREE_CODE (index) == INTEGER_CST
+                   && tree_int_cst_lt (index, op1))
+                 begin = middle + 1;
+               else if (TREE_CODE (index) == INTEGER_CST
+                        && tree_int_cst_lt (op1, index))
+                 end = middle;
+               else if (TREE_CODE (index) == RANGE_EXPR
+                        && tree_int_cst_lt (TREE_OPERAND (index, 1), op1))
+                 begin = middle + 1;
+               else if (TREE_CODE (index) == RANGE_EXPR
+                        && tree_int_cst_lt (op1, TREE_OPERAND (index, 0)))
+                 end = middle;
+               else
+                 return VEC_index (constructor_elt, elts, middle)->value;
+             }
+         }
+
+       return t;
+      }
+
     case CONST_DECL:
       return fold (DECL_INITIAL (t));
 
@@ -14061,7 +13879,7 @@ tree_simple_nonnegative_warnv_p (enum tree_code code, tree type)
    set *STRICT_OVERFLOW_P to true; otherwise, don't change
    *STRICT_OVERFLOW_P.  */
 
-static bool
+bool
 tree_unary_nonnegative_warnv_p (enum tree_code code, tree type, tree op0,
                                bool *strict_overflow_p)
 {
@@ -14131,7 +13949,7 @@ tree_unary_nonnegative_warnv_p (enum tree_code code, tree type, tree op0,
    set *STRICT_OVERFLOW_P to true; otherwise, don't change
    *STRICT_OVERFLOW_P.  */
 
-static bool
+bool
 tree_binary_nonnegative_warnv_p (enum tree_code code, tree type, tree op0,
                                      tree op1, bool *strict_overflow_p)
 {
@@ -14232,7 +14050,7 @@ tree_binary_nonnegative_warnv_p (enum tree_code code, tree type, tree op0,
    set *STRICT_OVERFLOW_P to true; otherwise, don't change
    *STRICT_OVERFLOW_P.  */
 
-static bool
+bool
 tree_single_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
 {
   if (TYPE_UNSIGNED (TREE_TYPE (t)))
@@ -14272,7 +14090,138 @@ tree_single_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
    set *STRICT_OVERFLOW_P to true; otherwise, don't change
    *STRICT_OVERFLOW_P.  */
 
-static bool
+bool
+tree_call_nonnegative_warnv_p (enum tree_code code,  tree type, tree fndecl,
+                              tree arg0, tree arg1, bool *strict_overflow_p)
+{
+  if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+    switch (DECL_FUNCTION_CODE (fndecl))
+      {
+       CASE_FLT_FN (BUILT_IN_ACOS):
+       CASE_FLT_FN (BUILT_IN_ACOSH):
+       CASE_FLT_FN (BUILT_IN_CABS):
+       CASE_FLT_FN (BUILT_IN_COSH):
+       CASE_FLT_FN (BUILT_IN_ERFC):
+       CASE_FLT_FN (BUILT_IN_EXP):
+       CASE_FLT_FN (BUILT_IN_EXP10):
+       CASE_FLT_FN (BUILT_IN_EXP2):
+       CASE_FLT_FN (BUILT_IN_FABS):
+       CASE_FLT_FN (BUILT_IN_FDIM):
+       CASE_FLT_FN (BUILT_IN_HYPOT):
+       CASE_FLT_FN (BUILT_IN_POW10):
+       CASE_INT_FN (BUILT_IN_FFS):
+       CASE_INT_FN (BUILT_IN_PARITY):
+       CASE_INT_FN (BUILT_IN_POPCOUNT):
+      case BUILT_IN_BSWAP32:
+      case BUILT_IN_BSWAP64:
+       /* Always true.  */
+       return true;
+
+       CASE_FLT_FN (BUILT_IN_SQRT):
+       /* sqrt(-0.0) is -0.0.  */
+       if (!HONOR_SIGNED_ZEROS (TYPE_MODE (type)))
+         return true;
+       return tree_expr_nonnegative_warnv_p (arg0,
+                                             strict_overflow_p);
+
+       CASE_FLT_FN (BUILT_IN_ASINH):
+       CASE_FLT_FN (BUILT_IN_ATAN):
+       CASE_FLT_FN (BUILT_IN_ATANH):
+       CASE_FLT_FN (BUILT_IN_CBRT):
+       CASE_FLT_FN (BUILT_IN_CEIL):
+       CASE_FLT_FN (BUILT_IN_ERF):
+       CASE_FLT_FN (BUILT_IN_EXPM1):
+       CASE_FLT_FN (BUILT_IN_FLOOR):
+       CASE_FLT_FN (BUILT_IN_FMOD):
+       CASE_FLT_FN (BUILT_IN_FREXP):
+       CASE_FLT_FN (BUILT_IN_LCEIL):
+       CASE_FLT_FN (BUILT_IN_LDEXP):
+       CASE_FLT_FN (BUILT_IN_LFLOOR):
+       CASE_FLT_FN (BUILT_IN_LLCEIL):
+       CASE_FLT_FN (BUILT_IN_LLFLOOR):
+       CASE_FLT_FN (BUILT_IN_LLRINT):
+       CASE_FLT_FN (BUILT_IN_LLROUND):
+       CASE_FLT_FN (BUILT_IN_LRINT):
+       CASE_FLT_FN (BUILT_IN_LROUND):
+       CASE_FLT_FN (BUILT_IN_MODF):
+       CASE_FLT_FN (BUILT_IN_NEARBYINT):
+       CASE_FLT_FN (BUILT_IN_RINT):
+       CASE_FLT_FN (BUILT_IN_ROUND):
+       CASE_FLT_FN (BUILT_IN_SCALB):
+       CASE_FLT_FN (BUILT_IN_SCALBLN):
+       CASE_FLT_FN (BUILT_IN_SCALBN):
+       CASE_FLT_FN (BUILT_IN_SIGNBIT):
+       CASE_FLT_FN (BUILT_IN_SIGNIFICAND):
+       CASE_FLT_FN (BUILT_IN_SINH):
+       CASE_FLT_FN (BUILT_IN_TANH):
+       CASE_FLT_FN (BUILT_IN_TRUNC):
+       /* True if the 1st argument is nonnegative.  */
+       return tree_expr_nonnegative_warnv_p (arg0,
+                                             strict_overflow_p);
+
+       CASE_FLT_FN (BUILT_IN_FMAX):
+       /* True if the 1st OR 2nd arguments are nonnegative.  */
+       return (tree_expr_nonnegative_warnv_p (arg0,
+                                              strict_overflow_p)
+               || (tree_expr_nonnegative_warnv_p (arg1,
+                                                  strict_overflow_p)));
+
+       CASE_FLT_FN (BUILT_IN_FMIN):
+       /* True if the 1st AND 2nd arguments are nonnegative.  */
+       return (tree_expr_nonnegative_warnv_p (arg0,
+                                              strict_overflow_p)
+               && (tree_expr_nonnegative_warnv_p (arg1,
+                                                  strict_overflow_p)));
+
+       CASE_FLT_FN (BUILT_IN_COPYSIGN):
+       /* True if the 2nd argument is nonnegative.  */
+       return tree_expr_nonnegative_warnv_p (arg1,
+                                             strict_overflow_p);
+
+       CASE_FLT_FN (BUILT_IN_POWI):
+       /* True if the 1st argument is nonnegative or the second
+          argument is an even integer.  */
+       if (TREE_CODE (arg1) == INTEGER_CST
+           && (TREE_INT_CST_LOW (arg1) & 1) == 0)
+         return true;
+       return tree_expr_nonnegative_warnv_p (arg0,
+                                             strict_overflow_p);
+
+       CASE_FLT_FN (BUILT_IN_POW):
+       /* True if the 1st argument is nonnegative or the second
+          argument is an even integer valued real.  */
+       if (TREE_CODE (arg1) == REAL_CST)
+         {
+           REAL_VALUE_TYPE c;
+           HOST_WIDE_INT n;
+
+           c = TREE_REAL_CST (arg1);
+           n = real_to_integer (&c);
+           if ((n & 1) == 0)
+             {
+               REAL_VALUE_TYPE cint;
+               real_from_integer (&cint, VOIDmode, n,
+                                  n < 0 ? -1 : 0, 0);
+               if (real_identical (&c, &cint))
+                 return true;
+             }
+         }
+       return tree_expr_nonnegative_warnv_p (arg0,
+                                             strict_overflow_p);
+
+      default:
+       break;
+      }
+  return tree_simple_nonnegative_warnv_p (code,
+                                         type);
+}
+
+/* Return true if T is known to be non-negative.  If the return
+   value is based on the assumption that signed overflow is undefined,
+   set *STRICT_OVERFLOW_P to true; otherwise, don't change
+   *STRICT_OVERFLOW_P.  */
+
+bool
 tree_invalid_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
 {
   enum tree_code code = TREE_CODE (t);
@@ -14316,133 +14265,16 @@ tree_invalid_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
 
     case CALL_EXPR:
       {
-       tree fndecl = get_callee_fndecl (t);
-       if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
-         switch (DECL_FUNCTION_CODE (fndecl))
-           {
-           CASE_FLT_FN (BUILT_IN_ACOS):
-           CASE_FLT_FN (BUILT_IN_ACOSH):
-           CASE_FLT_FN (BUILT_IN_CABS):
-           CASE_FLT_FN (BUILT_IN_COSH):
-           CASE_FLT_FN (BUILT_IN_ERFC):
-           CASE_FLT_FN (BUILT_IN_EXP):
-           CASE_FLT_FN (BUILT_IN_EXP10):
-           CASE_FLT_FN (BUILT_IN_EXP2):
-           CASE_FLT_FN (BUILT_IN_FABS):
-           CASE_FLT_FN (BUILT_IN_FDIM):
-           CASE_FLT_FN (BUILT_IN_HYPOT):
-           CASE_FLT_FN (BUILT_IN_POW10):
-           CASE_INT_FN (BUILT_IN_FFS):
-           CASE_INT_FN (BUILT_IN_PARITY):
-           CASE_INT_FN (BUILT_IN_POPCOUNT):
-           case BUILT_IN_BSWAP32:
-           case BUILT_IN_BSWAP64:
-             /* Always true.  */
-             return true;
-
-           CASE_FLT_FN (BUILT_IN_SQRT):
-             /* sqrt(-0.0) is -0.0.  */
-             if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (t))))
-               return true;
-             return tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 0),
-                                                   strict_overflow_p);
-
-           CASE_FLT_FN (BUILT_IN_ASINH):
-           CASE_FLT_FN (BUILT_IN_ATAN):
-           CASE_FLT_FN (BUILT_IN_ATANH):
-           CASE_FLT_FN (BUILT_IN_CBRT):
-           CASE_FLT_FN (BUILT_IN_CEIL):
-           CASE_FLT_FN (BUILT_IN_ERF):
-           CASE_FLT_FN (BUILT_IN_EXPM1):
-           CASE_FLT_FN (BUILT_IN_FLOOR):
-           CASE_FLT_FN (BUILT_IN_FMOD):
-           CASE_FLT_FN (BUILT_IN_FREXP):
-           CASE_FLT_FN (BUILT_IN_LCEIL):
-           CASE_FLT_FN (BUILT_IN_LDEXP):
-           CASE_FLT_FN (BUILT_IN_LFLOOR):
-           CASE_FLT_FN (BUILT_IN_LLCEIL):
-           CASE_FLT_FN (BUILT_IN_LLFLOOR):
-           CASE_FLT_FN (BUILT_IN_LLRINT):
-           CASE_FLT_FN (BUILT_IN_LLROUND):
-           CASE_FLT_FN (BUILT_IN_LRINT):
-           CASE_FLT_FN (BUILT_IN_LROUND):
-           CASE_FLT_FN (BUILT_IN_MODF):
-           CASE_FLT_FN (BUILT_IN_NEARBYINT):
-           CASE_FLT_FN (BUILT_IN_RINT):
-           CASE_FLT_FN (BUILT_IN_ROUND):
-           CASE_FLT_FN (BUILT_IN_SCALB):
-           CASE_FLT_FN (BUILT_IN_SCALBLN):
-           CASE_FLT_FN (BUILT_IN_SCALBN):
-           CASE_FLT_FN (BUILT_IN_SIGNBIT):
-           CASE_FLT_FN (BUILT_IN_SIGNIFICAND):
-           CASE_FLT_FN (BUILT_IN_SINH):
-           CASE_FLT_FN (BUILT_IN_TANH):
-           CASE_FLT_FN (BUILT_IN_TRUNC):
-             /* True if the 1st argument is nonnegative.  */
-             return tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 0),
-                                                   strict_overflow_p);
-
-           CASE_FLT_FN (BUILT_IN_FMAX):
-             /* True if the 1st OR 2nd arguments are nonnegative.  */
-             return (tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 0),
-                                                    strict_overflow_p)
-                     || (tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 1),
-                                                        strict_overflow_p)));
-
-           CASE_FLT_FN (BUILT_IN_FMIN):
-             /* True if the 1st AND 2nd arguments are nonnegative.  */
-             return (tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 0),
-                                                    strict_overflow_p)
-                     && (tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 1),
-                                                        strict_overflow_p)));
-
-           CASE_FLT_FN (BUILT_IN_COPYSIGN):
-             /* True if the 2nd argument is nonnegative.  */
-             return tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 1),
-                                                   strict_overflow_p);
-
-           CASE_FLT_FN (BUILT_IN_POWI):
-             /* True if the 1st argument is nonnegative or the second
-                argument is an even integer.  */
-             if (TREE_CODE (CALL_EXPR_ARG (t, 1)) == INTEGER_CST)
-               {
-                 tree arg1 = CALL_EXPR_ARG (t, 1);
-                 if ((TREE_INT_CST_LOW (arg1) & 1) == 0)
-                   return true;
-               }
-             return tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 0),
-                                                   strict_overflow_p);
-
-           CASE_FLT_FN (BUILT_IN_POW):
-             /* True if the 1st argument is nonnegative or the second
-                argument is an even integer valued real.  */
-             if (TREE_CODE (CALL_EXPR_ARG (t, 1)) == REAL_CST)
-               {
-                 REAL_VALUE_TYPE c;
-                 HOST_WIDE_INT n;
-
-                 c = TREE_REAL_CST (CALL_EXPR_ARG (t, 1));
-                 n = real_to_integer (&c);
-                 if ((n & 1) == 0)
-                   {
-                     REAL_VALUE_TYPE cint;
-                     real_from_integer (&cint, VOIDmode, n,
-                                        n < 0 ? -1 : 0, 0);
-                     if (real_identical (&c, &cint))
-                       return true;
-                   }
-               }
-             return tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 0),
-                                                   strict_overflow_p);
+       tree arg0 = call_expr_nargs (t) > 0 ?  CALL_EXPR_ARG (t, 0) : NULL_TREE;
+       tree arg1 = call_expr_nargs (t) > 1 ?  CALL_EXPR_ARG (t, 1) : NULL_TREE;
 
-           default:
-             break;
-           }
-       return tree_simple_nonnegative_warnv_p (TREE_CODE (t),
-                                                    TREE_TYPE (t));
+       return tree_call_nonnegative_warnv_p (TREE_CODE (t),
+                                             TREE_TYPE (t),
+                                             get_callee_fndecl (t),
+                                             arg0,
+                                             arg1,
+                                             strict_overflow_p);
       }
-      break;
-
     case COMPOUND_EXPR:
     case MODIFY_EXPR:
     case GIMPLE_MODIFY_STMT:
@@ -14561,7 +14393,7 @@ tree_expr_nonnegative_p (tree t)
    is undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't
    change *STRICT_OVERFLOW_P.  */
 
-static bool
+bool
 tree_unary_nonzero_warnv_p (enum tree_code code, tree type, tree op0,
                                 bool *strict_overflow_p)
 {
@@ -14601,7 +14433,7 @@ tree_unary_nonzero_warnv_p (enum tree_code code, tree type, tree op0,
    is undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't
    change *STRICT_OVERFLOW_P.  */
 
-static bool
+bool
 tree_binary_nonzero_warnv_p (enum tree_code code,
                             tree type,
                             tree op0,
@@ -14709,7 +14541,7 @@ tree_binary_nonzero_warnv_p (enum tree_code code,
    is undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't
    change *STRICT_OVERFLOW_P.  */
 
-static bool
+bool
 tree_single_nonzero_warnv_p (tree t, bool *strict_overflow_p)
 {
   bool sub_strict_overflow_p;
@@ -15274,6 +15106,34 @@ fold_indirect_ref_1 (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)))
+       { 
+         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 (BIT_FIELD_REF, type, TREE_OPERAND (op00, 0),
+                               part_width, index);
+        
+       }
+    }
+
+
   /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */
   if (TREE_CODE (sub) == POINTER_PLUS_EXPR
       && TREE_CODE (TREE_OPERAND (sub, 1)) == INTEGER_CST)