*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
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. */
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))
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. */
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
}
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))
}
}
- 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
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,