re PR tree-optimization/67328 (range test rather than single bit test for code testin...
[gcc.git] / gcc / fold-const.c
index b4c117c84948f6994c2ac0354b76ce8d393eb2b4..74bbdb07ffb4fdaee2c90fd7a13b814245576828 100644 (file)
@@ -798,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);
@@ -4742,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
@@ -4751,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.  */
@@ -4784,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))
@@ -6175,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.  */
@@ -6237,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
@@ -6278,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),
@@ -6928,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))
@@ -6976,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
@@ -8879,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,
@@ -9808,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,
@@ -9895,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
@@ -9916,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
@@ -10205,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))
@@ -10527,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
@@ -10653,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)
@@ -10792,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
@@ -11508,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
@@ -11542,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)
@@ -11558,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.  */
@@ -13407,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;
     }