re PR tree-optimization/67328 (range test rather than single bit test for code testin...
[gcc.git] / gcc / fold-const.c
index a8bb8af45c3aedce5cfb98873e1e6548bf953d20..74bbdb07ffb4fdaee2c90fd7a13b814245576828 100644 (file)
@@ -139,6 +139,7 @@ static tree fold_relational_const (enum tree_code, tree, tree, tree);
 static tree fold_convert_const (enum tree_code, tree, tree);
 static tree fold_view_convert_expr (tree, tree);
 static bool vec_cst_ctor_to_array (tree, tree *);
+static tree fold_negate_expr (location_t, tree);
 
 
 /* Return EXPR_LOCATION of T if it is not UNKNOWN_LOCATION.
@@ -522,7 +523,7 @@ negate_expr_p (tree t)
    returned.  */
 
 static tree
-fold_negate_expr (location_t loc, tree t)
+fold_negate_expr_1 (location_t loc, tree t)
 {
   tree type = TREE_TYPE (t);
   tree tem;
@@ -533,7 +534,7 @@ fold_negate_expr (location_t loc, tree t)
     case BIT_NOT_EXPR:
       if (INTEGRAL_TYPE_P (type))
         return fold_build2_loc (loc, PLUS_EXPR, type, TREE_OPERAND (t, 0),
-                            build_one_cst (type));
+                               build_one_cst (type));
       break;
 
     case INTEGER_CST:
@@ -581,14 +582,14 @@ fold_negate_expr (location_t loc, tree t)
     case COMPLEX_EXPR:
       if (negate_expr_p (t))
        return fold_build2_loc (loc, COMPLEX_EXPR, type,
-                           fold_negate_expr (loc, TREE_OPERAND (t, 0)),
-                           fold_negate_expr (loc, TREE_OPERAND (t, 1)));
+                               fold_negate_expr (loc, TREE_OPERAND (t, 0)),
+                               fold_negate_expr (loc, TREE_OPERAND (t, 1)));
       break;
 
     case CONJ_EXPR:
       if (negate_expr_p (t))
        return fold_build1_loc (loc, CONJ_EXPR, type,
-                           fold_negate_expr (loc, TREE_OPERAND (t, 0)));
+                               fold_negate_expr (loc, TREE_OPERAND (t, 0)));
       break;
 
     case NEGATE_EXPR:
@@ -605,7 +606,7 @@ fold_negate_expr (location_t loc, tree t)
            {
              tem = negate_expr (TREE_OPERAND (t, 1));
              return fold_build2_loc (loc, MINUS_EXPR, type,
-                                 tem, TREE_OPERAND (t, 0));
+                                     tem, TREE_OPERAND (t, 0));
            }
 
          /* -(A + B) -> (-A) - B.  */
@@ -613,7 +614,7 @@ fold_negate_expr (location_t loc, tree t)
            {
              tem = negate_expr (TREE_OPERAND (t, 0));
              return fold_build2_loc (loc, MINUS_EXPR, type,
-                                 tem, TREE_OPERAND (t, 1));
+                                     tem, TREE_OPERAND (t, 1));
            }
        }
       break;
@@ -623,7 +624,7 @@ fold_negate_expr (location_t loc, tree t)
       if (!HONOR_SIGN_DEPENDENT_ROUNDING (element_mode (type))
          && !HONOR_SIGNED_ZEROS (element_mode (type)))
        return fold_build2_loc (loc, MINUS_EXPR, type,
-                           TREE_OPERAND (t, 1), TREE_OPERAND (t, 0));
+                               TREE_OPERAND (t, 1), TREE_OPERAND (t, 0));
       break;
 
     case MULT_EXPR:
@@ -638,11 +639,11 @@ fold_negate_expr (location_t loc, tree t)
          tem = TREE_OPERAND (t, 1);
          if (negate_expr_p (tem))
            return fold_build2_loc (loc, TREE_CODE (t), type,
-                               TREE_OPERAND (t, 0), negate_expr (tem));
+                                   TREE_OPERAND (t, 0), negate_expr (tem));
          tem = TREE_OPERAND (t, 0);
          if (negate_expr_p (tem))
            return fold_build2_loc (loc, TREE_CODE (t), type,
-                               negate_expr (tem), TREE_OPERAND (t, 1));
+                                   negate_expr (tem), TREE_OPERAND (t, 1));
        }
       break;
 
@@ -715,6 +716,19 @@ fold_negate_expr (location_t loc, tree t)
   return NULL_TREE;
 }
 
+/* A wrapper for fold_negate_expr_1.  */
+
+static tree
+fold_negate_expr (location_t loc, tree t)
+{
+  tree type = TREE_TYPE (t);
+  STRIP_SIGN_NOPS (t);
+  tree tem = fold_negate_expr_1 (loc, t);
+  if (tem == NULL_TREE)
+    return NULL_TREE;
+  return fold_convert_loc (loc, type, tem);
+}
+
 /* Like fold_negate_expr, but return a NEGATE_EXPR tree, if T can not be
    negated in a simpler way.  Also allow for T to be NULL_TREE, in which case
    return NULL_TREE. */
@@ -784,8 +798,11 @@ split_tree (location_t loc, tree in, tree type, enum tree_code code,
                  though the C standard doesn't say so) for integers because
                  the value is not affected.  For reals, the value might be
                  affected, so we can't.  */
-              && ((code == PLUS_EXPR && TREE_CODE (in) == MINUS_EXPR)
-                  || (code == MINUS_EXPR && TREE_CODE (in) == PLUS_EXPR))))
+              && ((code == PLUS_EXPR && TREE_CODE (in) == POINTER_PLUS_EXPR)
+                  || (code == PLUS_EXPR && TREE_CODE (in) == MINUS_EXPR)
+                  || (code == MINUS_EXPR
+                      && (TREE_CODE (in) == PLUS_EXPR
+                          || TREE_CODE (in) == POINTER_PLUS_EXPR)))))
     {
       tree op0 = TREE_OPERAND (in, 0);
       tree op1 = TREE_OPERAND (in, 1);
@@ -817,8 +834,12 @@ split_tree (location_t loc, tree in, tree type, enum tree_code code,
       /* Now do any needed negations.  */
       if (neg_litp_p)
        *minus_litp = *litp, *litp = 0;
-      if (neg_conp_p)
-       *conp = negate_expr (*conp);
+      if (neg_conp_p && *conp)
+       {
+         /* Convert to TYPE before negating.  */
+         *conp = fold_convert_loc (loc, type, *conp);
+         *conp = negate_expr (*conp);
+       }
       if (neg_var_p && var)
        {
          /* Convert to TYPE before negating.  */
@@ -845,7 +866,12 @@ split_tree (location_t loc, tree in, tree type, enum tree_code code,
        *minus_litp = *litp, *litp = 0;
       else if (*minus_litp)
        *litp = *minus_litp, *minus_litp = 0;
-      *conp = negate_expr (*conp);
+      if (*conp)
+       {
+         /* Convert to TYPE before negating.  */
+         *conp = fold_convert_loc (loc, type, *conp);
+         *conp = negate_expr (*conp);
+       }
       if (var)
        {
          /* Convert to TYPE before negating.  */
@@ -1235,7 +1261,7 @@ const_binop (enum tree_code code, tree arg1, tree arg2)
              return NULL_TREE;
            wide_int w2 = arg2;
            f2.data.high = w2.elt (1);
-           f2.data.low = w2.elt (0);
+           f2.data.low = w2.ulow ();
            f2.mode = SImode;
          }
          break;
@@ -3848,6 +3874,31 @@ make_bit_field_ref (location_t loc, tree inner, tree orig_inner, tree type,
 {
   tree result, bftype;
 
+  /* Attempt not to lose the access path if possible.  */
+  if (TREE_CODE (orig_inner) == COMPONENT_REF)
+    {
+      tree ninner = TREE_OPERAND (orig_inner, 0);
+      machine_mode nmode;
+      HOST_WIDE_INT nbitsize, nbitpos;
+      tree noffset;
+      int nunsignedp, nreversep, nvolatilep = 0;
+      tree base = get_inner_reference (ninner, &nbitsize, &nbitpos,
+                                      &noffset, &nmode, &nunsignedp,
+                                      &nreversep, &nvolatilep);
+      if (base == inner
+         && noffset == NULL_TREE
+         && nbitsize >= bitsize
+         && nbitpos <= bitpos
+         && bitpos + bitsize <= nbitpos + nbitsize
+         && !reversep
+         && !nreversep
+         && !nvolatilep)
+       {
+         inner = ninner;
+         bitpos -= nbitpos;
+       }
+    }
+
   alias_set_type iset = get_alias_set (orig_inner);
   if (iset == 0 && get_alias_set (inner) != iset)
     inner = fold_build2 (MEM_REF, TREE_TYPE (inner),
@@ -4119,7 +4170,11 @@ decode_field_reference (location_t loc, tree *exp_, HOST_WIDE_INT *pbitsize,
                               punsignedp, preversep, pvolatilep);
   if ((inner == exp && and_mask == 0)
       || *pbitsize < 0 || offset != 0
-      || TREE_CODE (inner) == PLACEHOLDER_EXPR)
+      || TREE_CODE (inner) == PLACEHOLDER_EXPR
+      /* Reject out-of-bound accesses (PR79731).  */
+      || (! AGGREGATE_TYPE_P (TREE_TYPE (inner))
+         && compare_tree_int (TYPE_SIZE (TREE_TYPE (inner)),
+                              *pbitpos + *pbitsize) < 0))
     return 0;
 
   *exp_ = exp;
@@ -4690,6 +4745,40 @@ make_range (tree exp, int *pin_p, tree *plow, tree *phigh,
   *pin_p = in_p, *plow = low, *phigh = high;
   return exp;
 }
+
+/* Returns TRUE if [LOW, HIGH] range check can be optimized to
+   a bitwise check i.e. when
+     LOW  == 0xXX...X00...0
+     HIGH == 0xXX...X11...1
+   Return corresponding mask in MASK and stem in VALUE.  */
+
+static bool
+maskable_range_p (const_tree low, const_tree high, tree type, tree *mask,
+                 tree *value)
+{
+  if (TREE_CODE (low) != INTEGER_CST
+      || TREE_CODE (high) != INTEGER_CST)
+    return false;
+
+  unsigned prec = TYPE_PRECISION (type);
+  wide_int lo = wi::to_wide (low, prec);
+  wide_int hi = wi::to_wide (high, prec);
+
+  wide_int end_mask = lo ^ hi;
+  if ((end_mask & (end_mask + 1)) != 0
+      || (lo & end_mask) != 0)
+    return false;
+
+  wide_int stem_mask = ~end_mask;
+  wide_int stem = lo & stem_mask;
+  if (stem != (hi & stem_mask))
+    return false;
+
+  *mask = wide_int_to_tree (type, stem_mask);
+  *value = wide_int_to_tree (type, stem);
+
+  return true;
+}
 \f
 /* Given a range, LOW, HIGH, and IN_P, an expression, EXP, and a result
    type, TYPE, return an expression to test if EXP is in (or out of, depending
@@ -4699,7 +4788,7 @@ tree
 build_range_check (location_t loc, tree type, tree exp, int in_p,
                   tree low, tree high)
 {
-  tree etype = TREE_TYPE (exp), value;
+  tree etype = TREE_TYPE (exp), mask, value;
 
   /* Disable this optimization for function pointer expressions
      on targets that require function pointer canonicalization.  */
@@ -4732,6 +4821,13 @@ build_range_check (location_t loc, tree type, tree exp, int in_p,
     return fold_build2_loc (loc, EQ_EXPR, type, exp,
                        fold_convert_loc (loc, etype, low));
 
+  if (TREE_CODE (exp) == BIT_AND_EXPR
+      && maskable_range_p (low, high, etype, &mask, &value))
+    return fold_build2_loc (loc, EQ_EXPR, type,
+                           fold_build2_loc (loc, BIT_AND_EXPR, etype,
+                                             exp, mask),
+                           value);
+
   if (integer_zerop (low))
     {
       if (! TYPE_UNSIGNED (etype))
@@ -6123,6 +6219,7 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type,
       t1 = extract_muldiv (op0, c, code, wide_type, &sub_strict_overflow_p);
       t2 = extract_muldiv (op1, c, code, wide_type, &sub_strict_overflow_p);
       if (t1 != 0 && t2 != 0
+         && TYPE_OVERFLOW_WRAPS (ctype)
          && (code == MULT_EXPR
              /* If not multiplication, we can only do this if both operands
                 are divisible by c.  */
@@ -6185,11 +6282,6 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type,
       if (TYPE_UNSIGNED (ctype) && ctype != type)
        break;
 
-      /* If we were able to eliminate our operation from the first side,
-        apply our operation to the second side and reform the PLUS.  */
-      if (t1 != 0 && (TREE_CODE (t1) != code || code == MULT_EXPR))
-       return fold_build2 (tcode, ctype, fold_convert (ctype, t1), op1);
-
       /* The last case is if we are a multiply.  In that case, we can
         apply the distributive law to commute the multiply and addition
         if the multiplication of the constants doesn't overflow
@@ -6226,11 +6318,13 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type,
         new operation.  Likewise for the RHS from a MULT_EXPR.  Otherwise,
         do something only if the second operand is a constant.  */
       if (same_p
+         && TYPE_OVERFLOW_WRAPS (ctype)
          && (t1 = extract_muldiv (op0, c, code, wide_type,
                                   strict_overflow_p)) != 0)
        return fold_build2 (tcode, ctype, fold_convert (ctype, t1),
                            fold_convert (ctype, op1));
       else if (tcode == MULT_EXPR && code == MULT_EXPR
+              && TYPE_OVERFLOW_WRAPS (ctype)
               && (t1 = extract_muldiv (op1, c, code, wide_type,
                                        strict_overflow_p)) != 0)
        return fold_build2 (tcode, ctype, fold_convert (ctype, op0),
@@ -6876,10 +6970,11 @@ fold_plusminus_mult_expr (location_t loc, enum tree_code code, tree type,
     }
   same = NULL_TREE;
 
-  if (operand_equal_p (arg01, arg11, 0))
-    same = arg01, alt0 = arg00, alt1 = arg10;
-  else if (operand_equal_p (arg00, arg10, 0))
+  /* Prefer factoring a common non-constant.  */
+  if (operand_equal_p (arg00, arg10, 0))
     same = arg00, alt0 = arg01, alt1 = arg11;
+  else if (operand_equal_p (arg01, arg11, 0))
+    same = arg01, alt0 = arg00, alt1 = arg10;
   else if (operand_equal_p (arg00, arg11, 0))
     same = arg00, alt0 = arg01, alt1 = arg10;
   else if (operand_equal_p (arg01, arg10, 0))
@@ -6924,14 +7019,36 @@ fold_plusminus_mult_expr (location_t loc, enum tree_code code, tree type,
        }
     }
 
-  if (same)
+  if (!same)
+    return NULL_TREE;
+
+  if (! INTEGRAL_TYPE_P (type)
+      || TYPE_OVERFLOW_WRAPS (type)
+      /* We are neither factoring zero nor minus one.  */
+      || TREE_CODE (same) == INTEGER_CST)
     return fold_build2_loc (loc, MULT_EXPR, type,
                        fold_build2_loc (loc, code, type,
                                     fold_convert_loc (loc, type, alt0),
                                     fold_convert_loc (loc, type, alt1)),
                        fold_convert_loc (loc, type, same));
 
-  return NULL_TREE;
+  /* Same may be zero and thus the operation 'code' may overflow.  Likewise
+     same may be minus one and thus the multiplication may overflow.  Perform
+     the operations in an unsigned type.  */
+  tree utype = unsigned_type_for (type);
+  tree tem = fold_build2_loc (loc, code, utype,
+                             fold_convert_loc (loc, utype, alt0),
+                             fold_convert_loc (loc, utype, alt1));
+  /* If the sum evaluated to a constant that is not -INF the multiplication
+     cannot overflow.  */
+  if (TREE_CODE (tem) == INTEGER_CST
+      && ! wi::eq_p (tem, wi::min_value (TYPE_PRECISION (utype), SIGNED)))
+    return fold_build2_loc (loc, MULT_EXPR, type,
+                           fold_convert (type, tem), same);
+
+  return fold_convert_loc (loc, type,
+                          fold_build2_loc (loc, MULT_EXPR, utype, tem,
+                                           fold_convert_loc (loc, utype, same)));
 }
 
 /* Subroutine of native_encode_expr.  Encode the INTEGER_CST
@@ -8029,7 +8146,7 @@ fold_truth_andor (location_t loc, enum tree_code code, tree type,
          return fold_build2_loc (loc, icode, type, TREE_OPERAND (arg0, 0),
                                  tem);
        }
-       /* Same as abouve but for (A AND[-IF] (B AND-IF C)) -> ((A AND B) AND-IF C),
+       /* Same as above but for (A AND[-IF] (B AND-IF C)) -> ((A AND B) AND-IF C),
           or (A OR[-IF] (B OR-IF C) -> ((A OR B) OR-IF C).  */
       else if (TREE_CODE (arg1) == icode
          && simple_operand_p_2 (arg0)
@@ -8661,7 +8778,7 @@ fold_comparison (location_t loc, enum tree_code code, tree type,
              if (save_p)
                {
                  tem = save_expr (build2 (code, type, cval1, cval2));
-                 SET_EXPR_LOCATION (tem, loc);
+                 protected_set_expr_location (tem, loc);
                  return tem;
                }
              return fold_build2_loc (loc, code, type, cval1, cval2);
@@ -8827,7 +8944,7 @@ fold_addr_of_array_ref_difference (location_t loc, tree type,
       tree op0 = fold_convert_loc (loc, type, TREE_OPERAND (aref0, 1));
       tree op1 = fold_convert_loc (loc, type, TREE_OPERAND (aref1, 1));
       tree esz = fold_convert_loc (loc, type, array_ref_element_size (aref0));
-      tree diff = build2 (MINUS_EXPR, type, op0, op1);
+      tree diff = fold_build2_loc (loc, MINUS_EXPR, type, op0, op1);
       return fold_build2_loc (loc, PLUS_EXPR, type,
                              base_offset,
                              fold_build2_loc (loc, MULT_EXPR, type,
@@ -9756,6 +9873,7 @@ fold_binary_loc (location_t loc,
          if (TREE_CODE (op1) == INTEGER_CST
              && tree_int_cst_sgn (op1) == -1
              && negate_expr_p (op0)
+             && negate_expr_p (op1)
              && (tem = negate_expr (op1)) != op1
              && ! TREE_OVERFLOW (tem))
            return fold_build2_loc (loc, MULT_EXPR, type,
@@ -9843,8 +9961,10 @@ fold_binary_loc (location_t loc,
 
          /* If (C1|C2) == ~0 then (X&C1)|C2 becomes X|C2.  */
          if (msk.and_not (c1 | c2) == 0)
-           return fold_build2_loc (loc, BIT_IOR_EXPR, type,
-                                   TREE_OPERAND (arg0, 0), arg1);
+           {
+             tem = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0));
+             return fold_build2_loc (loc, BIT_IOR_EXPR, type, tem, arg1);
+           }
 
          /* Minimize the number of bits set in C1, i.e. C1 := C1 & ~C2,
             unless (C1 & ~C2) | (C2 & C3) for some C3 is a mask of some
@@ -9864,12 +9984,12 @@ fold_binary_loc (location_t loc,
            }
 
          if (c3 != c1)
-           return fold_build2_loc (loc, BIT_IOR_EXPR, type,
-                                   fold_build2_loc (loc, BIT_AND_EXPR, type,
-                                                    TREE_OPERAND (arg0, 0),
-                                                    wide_int_to_tree (type,
-                                                                      c3)),
-                                   arg1);
+           {
+             tem = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0));
+             tem = fold_build2_loc (loc, BIT_AND_EXPR, type, tem,
+                                    wide_int_to_tree (type, c3));
+             return fold_build2_loc (loc, BIT_IOR_EXPR, type, tem, arg1);
+           }
        }
 
       /* See if this can be simplified into a rotate first.  If that
@@ -10153,7 +10273,7 @@ fold_binary_loc (location_t loc,
       /* Convert -A / -B to A / B when the type is signed and overflow is
         undefined.  */
       if ((!INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type))
-         && TREE_CODE (arg0) == NEGATE_EXPR
+         && TREE_CODE (op0) == NEGATE_EXPR
          && negate_expr_p (op1))
        {
          if (INTEGRAL_TYPE_P (type))
@@ -10475,30 +10595,6 @@ fold_binary_loc (location_t loc,
                                        TREE_OPERAND (arg1, 0), arg0);
        }
 
-      /* Transform comparisons of the form C - X CMP X if C % 2 == 1.  */
-      if (TREE_CODE (arg0) == MINUS_EXPR
-         && TREE_CODE (TREE_OPERAND (arg0, 0)) == INTEGER_CST
-         && operand_equal_p (tree_strip_nop_conversions (TREE_OPERAND (arg0,
-                                                                       1)),
-                             arg1, 0)
-         && wi::extract_uhwi (TREE_OPERAND (arg0, 0), 0, 1) == 1)
-       return omit_two_operands_loc (loc, type,
-                                     code == NE_EXPR
-                                     ? boolean_true_node : boolean_false_node,
-                                     TREE_OPERAND (arg0, 1), arg1);
-
-      /* Transform comparisons of the form X CMP C - X if C % 2 == 1.  */
-      if (TREE_CODE (arg1) == MINUS_EXPR
-         && TREE_CODE (TREE_OPERAND (arg1, 0)) == INTEGER_CST
-         && operand_equal_p (tree_strip_nop_conversions (TREE_OPERAND (arg1,
-                                                                       1)),
-                             arg0, 0)
-         && wi::extract_uhwi (TREE_OPERAND (arg1, 0), 0, 1) == 1)
-       return omit_two_operands_loc (loc, type,
-                                     code == NE_EXPR
-                                     ? boolean_true_node : boolean_false_node,
-                                     TREE_OPERAND (arg1, 1), arg0);
-
       /* If this is an EQ or NE comparison with zero and ARG0 is
         (1 << foo) & bar, convert it to (bar >> foo) & 1.  Both require
         two operations, but the latter can be done in one less insn
@@ -10601,24 +10697,6 @@ fold_binary_loc (location_t loc,
            }
        }
 
-      /* If we have (A & C) == D where D & ~C != 0, convert this into 0.
-        Similarly for NE_EXPR.  */
-      if (TREE_CODE (arg0) == BIT_AND_EXPR
-         && TREE_CODE (arg1) == INTEGER_CST
-         && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
-       {
-         tree notc = fold_build1_loc (loc, BIT_NOT_EXPR,
-                                  TREE_TYPE (TREE_OPERAND (arg0, 1)),
-                                  TREE_OPERAND (arg0, 1));
-         tree dandnotc
-           = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (arg0),
-                              fold_convert_loc (loc, TREE_TYPE (arg0), arg1),
-                              notc);
-         tree rslt = code == EQ_EXPR ? integer_zero_node : integer_one_node;
-         if (integer_nonzerop (dandnotc))
-           return omit_one_operand_loc (loc, 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)
@@ -10740,40 +10818,37 @@ fold_binary_loc (location_t loc,
          tree itype = TREE_TYPE (arg0);
 
          if (operand_equal_p (arg01, arg11, 0))
-           return fold_build2_loc (loc, code, type,
-                               fold_build2_loc (loc, BIT_AND_EXPR, itype,
-                                            fold_build2_loc (loc,
-                                                         BIT_XOR_EXPR, itype,
-                                                         arg00, arg10),
-                                            arg01),
-                               build_zero_cst (itype));
-
+           {
+             tem = fold_convert_loc (loc, itype, arg10);
+             tem = fold_build2_loc (loc, BIT_XOR_EXPR, itype, arg00, tem);
+             tem = fold_build2_loc (loc, BIT_AND_EXPR, itype, tem, arg01);
+             return fold_build2_loc (loc, code, type, tem,
+                                     build_zero_cst (itype));
+           }
          if (operand_equal_p (arg01, arg10, 0))
-           return fold_build2_loc (loc, code, type,
-                               fold_build2_loc (loc, BIT_AND_EXPR, itype,
-                                            fold_build2_loc (loc,
-                                                         BIT_XOR_EXPR, itype,
-                                                         arg00, arg11),
-                                            arg01),
-                               build_zero_cst (itype));
-
+           {
+             tem = fold_convert_loc (loc, itype, arg11);
+             tem = fold_build2_loc (loc, BIT_XOR_EXPR, itype, arg00, tem);
+             tem = fold_build2_loc (loc, BIT_AND_EXPR, itype, tem, arg01);
+             return fold_build2_loc (loc, code, type, tem,
+                                     build_zero_cst (itype));
+           }
          if (operand_equal_p (arg00, arg11, 0))
-           return fold_build2_loc (loc, code, type,
-                               fold_build2_loc (loc, BIT_AND_EXPR, itype,
-                                            fold_build2_loc (loc,
-                                                         BIT_XOR_EXPR, itype,
-                                                         arg01, arg10),
-                                            arg00),
-                               build_zero_cst (itype));
-
+           {
+             tem = fold_convert_loc (loc, itype, arg10);
+             tem = fold_build2_loc (loc, BIT_XOR_EXPR, itype, arg01, tem);
+             tem = fold_build2_loc (loc, BIT_AND_EXPR, itype, tem, arg00);
+             return fold_build2_loc (loc, code, type, tem,
+                                     build_zero_cst (itype));
+           }
          if (operand_equal_p (arg00, arg10, 0))
-           return fold_build2_loc (loc, code, type,
-                               fold_build2_loc (loc, BIT_AND_EXPR, itype,
-                                            fold_build2_loc (loc,
-                                                         BIT_XOR_EXPR, itype,
-                                                         arg01, arg11),
-                                            arg00),
-                               build_zero_cst (itype));
+           {
+             tem = fold_convert_loc (loc, itype, arg11);
+             tem = fold_build2_loc (loc, BIT_XOR_EXPR, itype, arg01, tem);
+             tem = fold_build2_loc (loc, BIT_AND_EXPR, itype, tem, arg00);
+             return fold_build2_loc (loc, code, type, tem,
+                                     build_zero_cst (itype));
+           }
        }
 
       if (TREE_CODE (arg0) == BIT_XOR_EXPR
@@ -11456,10 +11531,12 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
          STRIP_NOPS (tem);
          if (TREE_CODE (tem) == RSHIFT_EXPR
              && tree_fits_uhwi_p (TREE_OPERAND (tem, 1))
-              && (unsigned HOST_WIDE_INT) tree_log2 (arg1) ==
-                tree_to_uhwi (TREE_OPERAND (tem, 1)))
+              && (unsigned HOST_WIDE_INT) tree_log2 (arg1)
+                == tree_to_uhwi (TREE_OPERAND (tem, 1)))
            return fold_build2_loc (loc, BIT_AND_EXPR, type,
-                               TREE_OPERAND (tem, 0), arg1);
+                                   fold_convert_loc (loc, type,
+                                                     TREE_OPERAND (tem, 0)),
+                                   op1);
        }
 
       /* A & N ? N : 0 is simply A & N if N is a power of two.  This
@@ -11490,7 +11567,7 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
          && (code == VEC_COND_EXPR || !VECTOR_TYPE_P (type)))
        return fold_build2_loc (loc, code == VEC_COND_EXPR ? BIT_AND_EXPR
                                                           : TRUTH_ANDIF_EXPR,
-                               type, fold_convert_loc (loc, type, arg0), arg1);
+                               type, fold_convert_loc (loc, type, arg0), op1);
 
       /* Convert A ? B : 1 into !A || B if A and B are truth values.  */
       if (code == VEC_COND_EXPR ? integer_all_onesp (op2) : integer_onep (op2)
@@ -11506,7 +11583,7 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
                                         ? BIT_IOR_EXPR
                                         : TRUTH_ORIF_EXPR,
                                    type, fold_convert_loc (loc, type, tem),
-                                   arg1);
+                                   op1);
        }
 
       /* Convert A ? 0 : B into !A && B if A and B are truth values.  */
@@ -13355,6 +13432,11 @@ tree_single_nonzero_warnv_p (tree t, bool *strict_overflow_p)
        }
       break;
 
+    case SSA_NAME:
+      if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+       break;
+      return expr_not_equal_to (t, wi::zero (TYPE_PRECISION (TREE_TYPE (t))));
+
     default:
       break;
     }
@@ -13963,7 +14045,8 @@ fold_indirect_ref_1 (location_t loc, tree type, tree op0)
 
   STRIP_NOPS (sub);
   subtype = TREE_TYPE (sub);
-  if (!POINTER_TYPE_P (subtype))
+  if (!POINTER_TYPE_P (subtype)
+      || TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (op0)))
     return NULL_TREE;
 
   if (TREE_CODE (sub) == ADDR_EXPR)
@@ -14207,7 +14290,7 @@ round_up_loc (location_t loc, tree value, unsigned int divisor)
 
          overflow_p = TREE_OVERFLOW (value);
          val += divisor - 1;
-         val &= - (int) divisor;
+         val &= (int) -divisor;
          if (val == 0)
            overflow_p = true;
 
@@ -14297,6 +14380,24 @@ split_address_to_core_and_offset (tree exp,
                                  &volatilep);
       core = build_fold_addr_expr_loc (loc, core);
     }
+  else if (TREE_CODE (exp) == POINTER_PLUS_EXPR)
+    {
+      core = TREE_OPERAND (exp, 0);
+      STRIP_NOPS (core);
+      *pbitpos = 0;
+      *poffset = TREE_OPERAND (exp, 1);
+      if (TREE_CODE (*poffset) == INTEGER_CST)
+       {
+         offset_int tem = wi::sext (wi::to_offset (*poffset),
+                                    TYPE_PRECISION (TREE_TYPE (*poffset)));
+         tem <<= LOG2_BITS_PER_UNIT;
+         if (wi::fits_shwi_p (tem))
+           {
+             *pbitpos = tem.to_shwi ();
+             *poffset = NULL_TREE;
+           }
+       }
+    }
   else
     {
       core = exp;