This file is consumed by genmatch which produces gimple-match.c
and generic-match.c from it.
- Copyright (C) 2014-2017 Free Software Foundation, Inc.
+ Copyright (C) 2014-2019 Free Software Foundation, Inc.
Contributed by Richard Biener <rguenther@suse.de>
and Prathamesh Kulkarni <bilbotheelffriend@gmail.com>
integer_each_onep integer_truep integer_nonzerop
real_zerop real_onep real_minus_onep
zerop
+ initializer_each_zero_or_onep
CONSTANT_CLASS_P
tree_expr_nonnegative_p
tree_expr_nonzero_p
integer_valued_real_p
integer_pow2p
+ uniform_integer_cst_p
HONOR_NANS)
/* Operator lists. */
DEFINE_INT_AND_FLOAT_ROUND_FN (CEIL)
DEFINE_INT_AND_FLOAT_ROUND_FN (ROUND)
DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
-
+
+/* Binary operations and their associated IFN_COND_* function. */
+(define_operator_list UNCOND_BINARY
+ plus minus
+ mult trunc_div trunc_mod rdiv
+ min max
+ bit_and bit_ior bit_xor)
+(define_operator_list COND_BINARY
+ IFN_COND_ADD IFN_COND_SUB
+ IFN_COND_MUL IFN_COND_DIV IFN_COND_MOD IFN_COND_RDIV
+ IFN_COND_MIN IFN_COND_MAX
+ IFN_COND_AND IFN_COND_IOR IFN_COND_XOR)
+
+/* Same for ternary operations. */
+(define_operator_list UNCOND_TERNARY
+ IFN_FMA IFN_FMS IFN_FNMA IFN_FNMS)
+(define_operator_list COND_TERNARY
+ IFN_COND_FMA IFN_COND_FMS IFN_COND_FNMA IFN_COND_FNMS)
+
/* As opposed to convert?, this still creates a single pattern, so
it is not a suitable replacement for convert? in all cases. */
(match (nop_convert @0)
(match (nop_convert @0)
(view_convert @0)
(if (VECTOR_TYPE_P (type) && VECTOR_TYPE_P (TREE_TYPE (@0))
- && TYPE_VECTOR_SUBPARTS (type) == TYPE_VECTOR_SUBPARTS (TREE_TYPE (@0))
+ && known_eq (TYPE_VECTOR_SUBPARTS (type),
+ TYPE_VECTOR_SUBPARTS (TREE_TYPE (@0)))
&& tree_nop_conversion_p (TREE_TYPE (type), TREE_TYPE (TREE_TYPE (@0))))))
/* This one has to be last, or it shadows the others. */
(match (nop_convert @0)
- @0)
+ @0)
+
+/* Transform likes of (char) ABS_EXPR <(int) x> into (char) ABSU_EXPR <x>
+ ABSU_EXPR returns unsigned absolute value of the operand and the operand
+ of the ABSU_EXPR will have the corresponding signed type. */
+(simplify (abs (convert @0))
+ (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
+ && !TYPE_UNSIGNED (TREE_TYPE (@0))
+ && element_precision (type) > element_precision (TREE_TYPE (@0)))
+ (with { tree utype = unsigned_type_for (TREE_TYPE (@0)); }
+ (convert (absu:utype @0)))))
+
/* Simplifications of operations with one constant operand and
simplifications to constants or single values. */
(pointer_plus integer_zerop @1)
(non_lvalue (convert @1)))
+/* ptr - 0 -> (type)ptr */
+(simplify
+ (pointer_diff @0 integer_zerop)
+ (convert @0))
+
/* See if ARG1 is zero and X + ARG1 reduces to X.
Likewise if the operands are reversed. */
(simplify
(if (fold_real_zero_addition_p (type, @1, 1))
(non_lvalue @0)))
+/* Even if the fold_real_zero_addition_p can't simplify X + 0.0
+ into X, we can optimize (X + 0.0) + 0.0 or (X + 0.0) - 0.0
+ or (X - 0.0) + 0.0 into X + 0.0 and (X - 0.0) - 0.0 into X - 0.0
+ if not -frounding-math. For sNaNs the first operation would raise
+ exceptions but turn the result into qNan, so the second operation
+ would not raise it. */
+(for inner_op (plus minus)
+ (for outer_op (plus minus)
+ (simplify
+ (outer_op (inner_op@3 @0 REAL_CST@1) REAL_CST@2)
+ (if (real_zerop (@1)
+ && real_zerop (@2)
+ && !HONOR_SIGN_DEPENDENT_ROUNDING (type))
+ (with { bool inner_plus = ((inner_op == PLUS_EXPR)
+ ^ REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (@1)));
+ bool outer_plus
+ = ((outer_op == PLUS_EXPR)
+ ^ REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (@2))); }
+ (if (outer_plus && !inner_plus)
+ (outer_op @0 @2)
+ @3))))))
+
/* Simplify x - x.
This is unsafe for certain floats even in non-IEEE formats.
In IEEE, it is unsafe because it does wrong for NaNs.
(minus @0 @0)
(if (!FLOAT_TYPE_P (type) || !HONOR_NANS (type))
{ build_zero_cst (type); }))
+(simplify
+ (pointer_diff @@0 @0)
+ { build_zero_cst (type); })
(simplify
(mult @0 integer_zerop@1)
|| !COMPLEX_FLOAT_TYPE_P (type)))
(negate @0)))
+/* Transform { 0 or 1 } * { 0 or 1 } into { 0 or 1 } & { 0 or 1 } */
+(simplify
+ (mult SSA_NAME@1 SSA_NAME@2)
+ (if (INTEGRAL_TYPE_P (type)
+ && get_nonzero_bits (@1) == 1
+ && get_nonzero_bits (@2) == 1)
+ (bit_and @1 @2)))
+
+/* Transform x * { 0 or 1, 0 or 1, ... } into x & { 0 or -1, 0 or -1, ...},
+ unless the target has native support for the former but not the latter. */
+(simplify
+ (mult @0 VECTOR_CST@1)
+ (if (initializer_each_zero_or_onep (@1)
+ && !HONOR_SNANS (type)
+ && !HONOR_SIGNED_ZEROS (type))
+ (with { tree itype = FLOAT_TYPE_P (type) ? unsigned_type_for (type) : type; }
+ (if (itype
+ && (!VECTOR_MODE_P (TYPE_MODE (type))
+ || (VECTOR_MODE_P (TYPE_MODE (itype))
+ && optab_handler (and_optab,
+ TYPE_MODE (itype)) != CODE_FOR_nothing)))
+ (view_convert (bit_and:itype (view_convert @0)
+ (ne @1 { build_zero_cst (type); })))))))
+
(for cmp (gt ge lt le)
outp (convert convert negate negate)
outn (negate negate convert convert)
/* Transform X * copysign (1.0, X) into abs(X). */
(simplify
- (mult:c @0 (COPYSIGN real_onep @0))
+ (mult:c @0 (COPYSIGN_ALL real_onep @0))
(if (!HONOR_NANS (type) && !HONOR_SIGNED_ZEROS (type))
(abs @0)))
/* Transform X * copysign (1.0, -X) into -abs(X). */
(simplify
- (mult:c @0 (COPYSIGN real_onep (negate @0)))
+ (mult:c @0 (COPYSIGN_ALL real_onep (negate @0)))
(if (!HONOR_NANS (type) && !HONOR_SIGNED_ZEROS (type))
(negate (abs @0))))
/* Transform copysign (CST, X) into copysign (ABS(CST), X). */
(simplify
- (COPYSIGN REAL_CST@0 @1)
+ (COPYSIGN_ALL REAL_CST@0 @1)
(if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (@0)))
- (COPYSIGN (negate @0) @1)))
+ (COPYSIGN_ALL (negate @0) @1)))
/* X * 1, X / 1 -> X. */
(for op (mult trunc_div ceil_div floor_div round_div exact_div)
And not for _Fract types where we can't build 1. */
(if (!integer_zerop (@0) && !ALL_FRACT_MODE_P (TYPE_MODE (type)))
{ build_one_cst (type); }))
- /* X / abs (X) is X < 0 ? -1 : 1. */
+ /* X / abs (X) is X < 0 ? -1 : 1. */
(simplify
(div:C @0 (abs @0))
(if (INTEGRAL_TYPE_P (type)
and floor_div is trickier and combining round_div even more so. */
(for div (trunc_div exact_div)
(simplify
- (div (div @0 INTEGER_CST@1) INTEGER_CST@2)
+ (div (div@3 @0 INTEGER_CST@1) INTEGER_CST@2)
(with {
- bool overflow_p;
- wide_int mul = wi::mul (@1, @2, TYPE_SIGN (type), &overflow_p);
+ wi::overflow_type overflow;
+ wide_int mul = wi::mul (wi::to_wide (@1), wi::to_wide (@2),
+ TYPE_SIGN (type), &overflow);
}
- (if (!overflow_p)
- (div @0 { wide_int_to_tree (type, mul); })
- (if (TYPE_UNSIGNED (type)
- || mul != wi::min_value (TYPE_PRECISION (type), SIGNED))
- { build_zero_cst (type); })))))
+ (if (div == EXACT_DIV_EXPR
+ || optimize_successive_divisions_p (@2, @3))
+ (if (!overflow)
+ (div @0 { wide_int_to_tree (type, mul); })
+ (if (TYPE_UNSIGNED (type)
+ || mul != wi::min_value (TYPE_PRECISION (type), SIGNED))
+ { build_zero_cst (type); }))))))
/* Combine successive multiplications. Similar to above, but handling
overflow is different. */
(simplify
(mult (mult @0 INTEGER_CST@1) INTEGER_CST@2)
(with {
- bool overflow_p;
- wide_int mul = wi::mul (@1, @2, TYPE_SIGN (type), &overflow_p);
+ wi::overflow_type overflow;
+ wide_int mul = wi::mul (wi::to_wide (@1), wi::to_wide (@2),
+ TYPE_SIGN (type), &overflow);
}
/* Skip folding on overflow: the only special case is @1 * @2 == -INT_MIN,
otherwise undefined overflow implies that @0 must be zero. */
- (if (!overflow_p || TYPE_OVERFLOW_WRAPS (type))
+ (if (!overflow || TYPE_OVERFLOW_WRAPS (type))
(mult @0 { wide_int_to_tree (type, mul); }))))
/* Optimize A / A to 1.0 if we don't care about
(negate @0)))
(if (flag_reciprocal_math)
- /* Convert (A/B)/C to A/(B*C) */
+ /* Convert (A/B)/C to A/(B*C). */
(simplify
(rdiv (rdiv:s @0 @1) @2)
- (rdiv @0 (mult @1 @2)))
+ (rdiv @0 (mult @1 @2)))
+
+ /* Canonicalize x / (C1 * y) to (x * C2) / y. */
+ (simplify
+ (rdiv @0 (mult:s @1 REAL_CST@2))
+ (with
+ { tree tem = const_binop (RDIV_EXPR, type, build_one_cst (type), @2); }
+ (if (tem)
+ (rdiv (mult @0 { tem; } ) @1))))
/* Convert A/(B/C) to (A/B)*C */
(simplify
(rdiv @0 (rdiv:s @1 @2))
(mult (rdiv @0 @1) @2)))
+/* Simplify x / (- y) to -x / y. */
+(simplify
+ (rdiv @0 (negate @1))
+ (rdiv (negate @0) @1))
+
+(if (flag_unsafe_math_optimizations)
+ /* Simplify (C / x op 0.0) to x op 0.0 for C != 0, C != Inf/Nan.
+ Since C / x may underflow to zero, do this only for unsafe math. */
+ (for op (lt le gt ge)
+ neg_op (gt ge lt le)
+ (simplify
+ (op (rdiv REAL_CST@0 @1) real_zerop@2)
+ (if (!HONOR_SIGNED_ZEROS (@1) && !HONOR_INFINITIES (@1))
+ (switch
+ (if (real_less (&dconst0, TREE_REAL_CST_PTR (@0)))
+ (op @1 @2))
+ /* For C < 0, use the inverted operator. */
+ (if (real_less (TREE_REAL_CST_PTR (@0), &dconst0))
+ (neg_op @1 @2)))))))
+
/* Optimize (X & (-A)) / A where A is a power of 2, to X >> log2(A) */
(for div (trunc_div ceil_div floor_div round_div exact_div)
(simplify
(div (convert? (bit_and @0 INTEGER_CST@1)) INTEGER_CST@2)
(if (integer_pow2p (@2)
&& tree_int_cst_sgn (@2) > 0
- && wi::add (@2, @1) == 0
- && tree_nop_conversion_p (type, TREE_TYPE (@0)))
- (rshift (convert @0) { build_int_cst (integer_type_node,
- wi::exact_log2 (@2)); }))))
+ && tree_nop_conversion_p (type, TREE_TYPE (@0))
+ && wi::to_wide (@2) + wi::to_wide (@1) == 0)
+ (rshift (convert @0)
+ { build_int_cst (integer_type_node,
+ wi::exact_log2 (wi::to_wide (@2))); }))))
/* If ARG1 is a constant, we can convert this to a multiply by the
reciprocal. This does not have the same rounding properties,
(mod (mult @0 INTEGER_CST@1) INTEGER_CST@2)
(if (ANY_INTEGRAL_TYPE_P (type)
&& TYPE_OVERFLOW_UNDEFINED (type)
- && wi::multiple_of_p (@1, @2, TYPE_SIGN (type)))
- { build_zero_cst (type); })))
+ && wi::multiple_of_p (wi::to_wide (@1), wi::to_wide (@2),
+ TYPE_SIGN (type)))
+ { build_zero_cst (type); }))
+ /* For (X % C) == 0, if X is signed and C is power of 2, use unsigned
+ modulo and comparison, since it is simpler and equivalent. */
+ (for cmp (eq ne)
+ (simplify
+ (cmp (mod @0 integer_pow2p@2) integer_zerop@1)
+ (if (!TYPE_UNSIGNED (TREE_TYPE (@0)))
+ (with { tree utype = unsigned_type_for (TREE_TYPE (@0)); }
+ (cmp (mod (convert:utype @0) (convert:utype @2)) (convert:utype @1)))))))
/* X % -C is the same as X % C. */
(simplify
(trunc_mod @0 INTEGER_CST@1)
(if (TYPE_SIGN (type) == SIGNED
&& !TREE_OVERFLOW (@1)
- && wi::neg_p (@1)
+ && wi::neg_p (wi::to_wide (@1))
&& !TYPE_OVERFLOW_TRAPS (type)
/* Avoid this transformation if C is INT_MIN, i.e. C == -C. */
&& !sign_bit_p (@1, @1))
/* Avoid this transformation if X might be INT_MIN or
Y might be -1, because we would then change valid
INT_MIN % -(-1) into invalid INT_MIN % -1. */
- && (expr_not_equal_to (@0, TYPE_MIN_VALUE (type))
+ && (expr_not_equal_to (@0, wi::to_wide (TYPE_MIN_VALUE (type)))
|| expr_not_equal_to (@1, wi::minus_one (TYPE_PRECISION
(TREE_TYPE (@1))))))
(trunc_mod @0 (convert @1))))
(trunc_div (mult @0 integer_pow2p@1) @1)
(if (TYPE_UNSIGNED (TREE_TYPE (@0)))
(bit_and @0 { wide_int_to_tree
- (type, wi::mask (TYPE_PRECISION (type) - wi::exact_log2 (@1),
+ (type, wi::mask (TYPE_PRECISION (type)
+ - wi::exact_log2 (wi::to_wide (@1)),
false, TYPE_PRECISION (type))); })))
/* Simplify (unsigned t / 2) * 2 -> unsigned t & ~1. */
/* Simplify (t * 2) / 2) -> t. */
(for div (trunc_div ceil_div floor_div round_div exact_div)
(simplify
- (div (mult @0 @1) @1)
+ (div (mult:c @0 @1) @1)
(if (ANY_INTEGRAL_TYPE_P (type)
&& TYPE_OVERFLOW_UNDEFINED (type))
@0)))
(for pows (POWI)
(simplify
(pows (op @0) INTEGER_CST@1)
- (if (wi::bit_and (@1, 1) == 0)
+ (if ((wi::to_wide (@1) & 1) == 0)
(pows @0 @1))))
/* Strip negate and abs from both operands of hypot. */
(for hypots (HYPOT)
(hypots @0 (op @1))
(hypots @0 @1)))
/* copysign(-x, y) and copysign(abs(x), y) -> copysign(x, y). */
- (for copysigns (COPYSIGN)
+ (for copysigns (COPYSIGN_ALL)
(simplify
(copysigns (op @0) @1)
(copysigns @0 @1))))
(mult (abs@1 @0) @1)
(mult @0 @0))
+/* Convert absu(x)*absu(x) -> x*x. */
+(simplify
+ (mult (absu@1 @0) @1)
+ (mult (convert@2 @0) @2))
+
/* cos(copysign(x, y)) -> cos(x). Similarly for cosh. */
(for coss (COS COSH)
copysigns (COPYSIGN)
copysigns (COPYSIGN)
(simplify
(pows (copysigns @0 @2) INTEGER_CST@1)
- (if (wi::bit_and (@1, 1) == 0)
+ (if ((wi::to_wide (@1) & 1) == 0)
(pows @0 @1))))
(for hypots (HYPOT)
(hypots @0 @1)))
/* copysign(x, CST) -> [-]abs (x). */
-(for copysigns (COPYSIGN)
+(for copysigns (COPYSIGN_ALL)
(simplify
(copysigns @0 REAL_CST@1)
(if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (@1)))
(abs @0))))
/* copysign(copysign(x, y), z) -> copysign(x, z). */
-(for copysigns (COPYSIGN)
+(for copysigns (COPYSIGN_ALL)
(simplify
(copysigns (copysigns @0 @1) @2)
(copysigns @0 @2)))
/* copysign(x,y)*copysign(x,y) -> x*x. */
-(for copysigns (COPYSIGN)
+(for copysigns (COPYSIGN_ALL)
(simplify
(mult (copysigns@2 @0 @1) @2)
(mult @0 @0)))
&& tree_nop_conversion_p (type, TREE_TYPE (@1)))
(lshift @0 @2)))
+/* Fold (1 << (C - x)) where C = precision(type) - 1
+ into ((1 << C) >> x). */
+(simplify
+ (lshift integer_onep@0 (minus@1 INTEGER_CST@2 @3))
+ (if (INTEGRAL_TYPE_P (type)
+ && wi::eq_p (wi::to_wide (@2), TYPE_PRECISION (type) - 1)
+ && single_use (@1))
+ (if (TYPE_UNSIGNED (type))
+ (rshift (lshift @0 @2) @3)
+ (with
+ { tree utype = unsigned_type_for (type); }
+ (convert (rshift (lshift (convert:utype @0) @2) @3))))))
+
/* Fold (C1/X)*C2 into (C1*C2)/X. */
(simplify
(mult (rdiv@3 REAL_CST@0 @1) REAL_CST@2)
(if (tem)
(rdiv { tem; } @1)))))
-/* Convert C1/(X*C2) into (C1/C2)/X */
-(simplify
- (rdiv REAL_CST@0 (mult @1 REAL_CST@2))
- (if (flag_reciprocal_math)
- (with
- { tree tem = const_binop (RDIV_EXPR, type, @0, @2); }
- (if (tem)
- (rdiv { tem; } @1)))))
-
/* Simplify ~X & X as zero. */
(simplify
(bit_and:c (convert? @0) (convert? (bit_not @0)))
(minus (bit_xor @0 @1) @1))
(simplify
(minus (bit_and:s @0 INTEGER_CST@2) (bit_and:s @0 INTEGER_CST@1))
- (if (wi::bit_not (@2) == @1)
+ (if (~wi::to_wide (@2) == wi::to_wide (@1))
(minus (bit_xor @0 @1) @1)))
/* Fold (A & B) - (A & ~B) into B - (A ^ B). */
(bit_xor @0 @1))
(simplify
(op:c (bit_and @0 INTEGER_CST@2) (bit_and (bit_not @0) INTEGER_CST@1))
- (if (wi::bit_not (@2) == @1)
+ (if (~wi::to_wide (@2) == wi::to_wide (@1))
(bit_xor @0 @1))))
/* PR53979: Transform ((a ^ b) | a) -> (a | b) */
(bit_ior:c (bit_xor:c @0 @1) @0)
(bit_ior @0 @1))
+/* (a & ~b) | (a ^ b) --> a ^ b */
+(simplify
+ (bit_ior:c (bit_and:c @0 (bit_not @1)) (bit_xor:c@2 @0 @1))
+ @2)
+
+/* (a & ~b) ^ ~a --> ~(a & b) */
+(simplify
+ (bit_xor:c (bit_and:cs @0 (bit_not @1)) (bit_not @0))
+ (bit_not (bit_and @0 @1)))
+
+/* (a | b) & ~(a ^ b) --> a & b */
+(simplify
+ (bit_and:c (bit_ior @0 @1) (bit_not (bit_xor:c @0 @1)))
+ (bit_and @0 @1))
+
+/* a | ~(a ^ b) --> a | ~b */
+(simplify
+ (bit_ior:c @0 (bit_not:s (bit_xor:c @0 @1)))
+ (bit_ior @0 (bit_not @1)))
+
+/* (a | b) | (a &^ b) --> a | b */
+(for op (bit_and bit_xor)
+ (simplify
+ (bit_ior:c (bit_ior@2 @0 @1) (op:c @0 @1))
+ @2))
+
+/* (a & b) | ~(a ^ b) --> ~(a ^ b) */
+(simplify
+ (bit_ior:c (bit_and:c @0 @1) (bit_not@2 (bit_xor @0 @1)))
+ @2)
+
+/* ~(~a & b) --> a | ~b */
+(simplify
+ (bit_not (bit_and:cs (bit_not @0) @1))
+ (bit_ior @0 (bit_not @1)))
+
+/* ~(~a | b) --> a & ~b */
+(simplify
+ (bit_not (bit_ior:cs (bit_not @0) @1))
+ (bit_and @0 (bit_not @1)))
+
/* Simplify (~X & Y) to X ^ Y if we know that (X & ~Y) is 0. */
#if GIMPLE
(simplify
(bit_and (bit_not SSA_NAME@0) INTEGER_CST@1)
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
- && (get_nonzero_bits (@0) & wi::bit_not (@1)) == 0)
+ && wi::bit_and_not (get_nonzero_bits (@0), wi::to_wide (@1)) == 0)
(bit_xor @0 @1)))
#endif
+/* For constants M and N, if M == (1LL << cst) - 1 && (N & M) == M,
+ ((A & N) + B) & M -> (A + B) & M
+ Similarly if (N & M) == 0,
+ ((A | N) + B) & M -> (A + B) & M
+ and for - instead of + (or unary - instead of +)
+ and/or ^ instead of |.
+ If B is constant and (B & M) == 0, fold into A & M. */
+(for op (plus minus)
+ (for bitop (bit_and bit_ior bit_xor)
+ (simplify
+ (bit_and (op:s (bitop:s@0 @3 INTEGER_CST@4) @1) INTEGER_CST@2)
+ (with
+ { tree pmop[2];
+ tree utype = fold_bit_and_mask (TREE_TYPE (@0), @2, op, @0, bitop,
+ @3, @4, @1, ERROR_MARK, NULL_TREE,
+ NULL_TREE, pmop); }
+ (if (utype)
+ (convert (bit_and (op (convert:utype { pmop[0]; })
+ (convert:utype { pmop[1]; }))
+ (convert:utype @2))))))
+ (simplify
+ (bit_and (op:s @0 (bitop:s@1 @3 INTEGER_CST@4)) INTEGER_CST@2)
+ (with
+ { tree pmop[2];
+ tree utype = fold_bit_and_mask (TREE_TYPE (@0), @2, op, @0, ERROR_MARK,
+ NULL_TREE, NULL_TREE, @1, bitop, @3,
+ @4, pmop); }
+ (if (utype)
+ (convert (bit_and (op (convert:utype { pmop[0]; })
+ (convert:utype { pmop[1]; }))
+ (convert:utype @2)))))))
+ (simplify
+ (bit_and (op:s @0 @1) INTEGER_CST@2)
+ (with
+ { tree pmop[2];
+ tree utype = fold_bit_and_mask (TREE_TYPE (@0), @2, op, @0, ERROR_MARK,
+ NULL_TREE, NULL_TREE, @1, ERROR_MARK,
+ NULL_TREE, NULL_TREE, pmop); }
+ (if (utype)
+ (convert (bit_and (op (convert:utype { pmop[0]; })
+ (convert:utype { pmop[1]; }))
+ (convert:utype @2)))))))
+(for bitop (bit_and bit_ior bit_xor)
+ (simplify
+ (bit_and (negate:s (bitop:s@0 @2 INTEGER_CST@3)) INTEGER_CST@1)
+ (with
+ { tree pmop[2];
+ tree utype = fold_bit_and_mask (TREE_TYPE (@0), @1, NEGATE_EXPR, @0,
+ bitop, @2, @3, NULL_TREE, ERROR_MARK,
+ NULL_TREE, NULL_TREE, pmop); }
+ (if (utype)
+ (convert (bit_and (negate (convert:utype { pmop[0]; }))
+ (convert:utype @1)))))))
+
/* X % Y is smaller than Y. */
(for cmp (lt ge)
(simplify
(simplify
(bit_and SSA_NAME@0 INTEGER_CST@1)
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
- && (get_nonzero_bits (@0) & wi::bit_not (@1)) == 0)
+ && wi::bit_and_not (get_nonzero_bits (@0), wi::to_wide (@1)) == 0)
@0))
#endif
(bitop:c @0 (bit_not (bitop:cs @0 @1)))
(bitop @0 (bit_not @1))))
+/* (~x & y) | ~(x | y) -> ~x */
+(simplify
+ (bit_ior:c (bit_and:c (bit_not@2 @0) @1) (bit_not (bit_ior:c @0 @1)))
+ @2)
+
+/* (x | y) ^ (x | ~y) -> ~x */
+(simplify
+ (bit_xor:c (bit_ior:c @0 @1) (bit_ior:c @0 (bit_not @1)))
+ (bit_not @0))
+
+/* (x & y) | ~(x | y) -> ~(x ^ y) */
+(simplify
+ (bit_ior:c (bit_and:s @0 @1) (bit_not:s (bit_ior:s @0 @1)))
+ (bit_not (bit_xor @0 @1)))
+
+/* (~x | y) ^ (x ^ y) -> x | ~y */
+(simplify
+ (bit_xor:c (bit_ior:cs (bit_not @0) @1) (bit_xor:s @0 @1))
+ (bit_ior @0 (bit_not @1)))
+
+/* (x ^ y) | ~(x | y) -> ~(x & y) */
+(simplify
+ (bit_ior:c (bit_xor:s @0 @1) (bit_not:s (bit_ior:s @0 @1)))
+ (bit_not (bit_and @0 @1)))
+
/* (x | y) & ~x -> y & ~x */
/* (x & y) | ~x -> y | ~x */
(for bitop (bit_and bit_ior)
(bit_and:c (bit_ior:c @0 @1) (bit_xor:c @1 (bit_not @0)))
(bit_and @0 @1))
+/* (~x | y) & (x | ~y) -> ~(x ^ y) */
+(simplify
+ (bit_and (bit_ior:cs (bit_not @0) @1) (bit_ior:cs @0 (bit_not @1)))
+ (bit_not (bit_xor @0 @1)))
+
+/* (~x | y) ^ (x | ~y) -> x ^ y */
+(simplify
+ (bit_xor (bit_ior:c (bit_not @0) @1) (bit_ior:c @0 (bit_not @1)))
+ (bit_xor @0 @1))
+
/* ~x & ~y -> ~(x | y)
~x | ~y -> ~(x & y) */
(for op (bit_and bit_ior)
(convert2? (bit_and@5 @2 INTEGER_CST@3)))
(if (tree_nop_conversion_p (type, TREE_TYPE (@0))
&& tree_nop_conversion_p (type, TREE_TYPE (@2))
- && wi::bit_and (@1, @3) == 0)
+ && (wi::to_wide (@1) & wi::to_wide (@3)) == 0)
(bit_ior (convert @4) (convert @5)))))
/* (X | Y) ^ X -> Y & ~ X*/
(for opo (bit_and bit_xor)
opi (bit_xor bit_and)
(simplify
- (opo:c (opi:c @0 @1) @1)
+ (opo:c (opi:cs @0 @1) @1)
(bit_and (bit_not @0) @1)))
/* Given a bit-wise operation CODE applied to ARG0 and ARG1, see if both
&& tree_nop_conversion_p (type, TREE_TYPE (@2)))
(bit_xor (convert @1) (convert @2))))
+/* Convert abs (abs (X)) into abs (X).
+ also absu (absu (X)) into absu (X). */
(simplify
(abs (abs@1 @0))
@1)
+
+(simplify
+ (absu (convert@2 (absu@1 @0)))
+ (if (tree_nop_conversion_p (TREE_TYPE (@2), TREE_TYPE (@1)))
+ @1))
+
+/* Convert abs[u] (-X) -> abs[u] (X). */
(simplify
(abs (negate @0))
(abs @0))
+
+(simplify
+ (absu (negate @0))
+ (absu @0))
+
+/* Convert abs[u] (X) where X is nonnegative -> (X). */
(simplify
(abs tree_expr_nonnegative_p@0)
@0)
+(simplify
+ (absu tree_expr_nonnegative_p@0)
+ (convert @0))
+
/* A few cases of fold-const.c negate_expr_p predicate. */
(match negate_expr_p
INTEGER_CST
(match negate_expr_p
VECTOR_CST
(if (FLOAT_TYPE_P (TREE_TYPE (type)) || TYPE_OVERFLOW_WRAPS (type))))
+(match negate_expr_p
+ (minus @0 @1)
+ (if ((ANY_INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_WRAPS (type))
+ || (FLOAT_TYPE_P (type)
+ && !HONOR_SIGN_DEPENDENT_ROUNDING (type)
+ && !HONOR_SIGNED_ZEROS (type)))))
/* (-A) * (-B) -> A * B */
(simplify
(if (tree_nop_conversion_p (type, TREE_TYPE (@0))
&& tree_nop_conversion_p (type, TREE_TYPE (@1)))
(mult (convert @0) (convert (negate @1)))))
-
+
/* -(A + B) -> (-B) - A. */
(simplify
(negate (plus:c @0 negate_expr_p@1))
&& !HONOR_SIGNED_ZEROS (element_mode (type)))
(minus (negate @1) @0)))
+/* -(A - B) -> B - A. */
+(simplify
+ (negate (minus @0 @1))
+ (if ((ANY_INTEGRAL_TYPE_P (type) && !TYPE_OVERFLOW_SANITIZED (type))
+ || (FLOAT_TYPE_P (type)
+ && !HONOR_SIGN_DEPENDENT_ROUNDING (type)
+ && !HONOR_SIGNED_ZEROS (type)))
+ (minus @1 @0)))
+(simplify
+ (negate (pointer_diff @0 @1))
+ (if (TYPE_OVERFLOW_UNDEFINED (type))
+ (pointer_diff @1 @0)))
+
/* A - B -> A + (-B) if B is easily negatable. */
(simplify
(minus @0 negate_expr_p@1)
(for bitop (bit_and bit_ior bit_xor)
(simplify
(bitop (bitop @0 CONSTANT_CLASS_P@1) CONSTANT_CLASS_P@2)
- (bitop @0 (bitop @1 @2))))
+ (if (!CONSTANT_CLASS_P (@0))
+ /* This is the canonical form regardless of whether (bitop @1 @2) can be
+ folded to a constant. */
+ (bitop @0 (bitop @1 @2))
+ /* In this case we have three constants and (bitop @0 @1) doesn't fold
+ to a constant. This can happen if @0 or @1 is a POLY_INT_CST and if
+ the values involved are such that the operation can't be decided at
+ compile time. Try folding one of @0 or @1 with @2 to see whether
+ that combination can be decided at compile time.
+
+ Keep the existing form if both folds fail, to avoid endless
+ oscillation. */
+ (with { tree cst1 = const_binop (bitop, type, @0, @2); }
+ (if (cst1)
+ (bitop @1 { cst1; })
+ (with { tree cst2 = const_binop (bitop, type, @1, @2); }
+ (if (cst2)
+ (bitop @0 { cst2; }))))))))
/* Try simple folding for X op !X, and X op X with the help
of the truth_valued_p and logical_inverted_value predicates. */
|| !TYPE_UNSIGNED (TREE_TYPE (@0)))
(convert (minus @0 { build_each_one_cst (TREE_TYPE (@0)); }))))
+/* Convert - (~A) to A + 1. */
+(simplify
+ (negate (nop_convert (bit_not @0)))
+ (plus (view_convert @0) { build_each_one_cst (type); }))
+
/* Convert ~ (A - 1) or ~ (A + -1) to -A. */
(simplify
(bit_not (convert? (minus @0 integer_each_onep)))
(if (tree_nop_conversion_p (type, TREE_TYPE (@0)))
(convert (bit_xor @0 @1))))
+/* Otherwise prefer ~(X ^ Y) to ~X ^ Y as more canonical. */
+(simplify
+ (bit_xor:c (nop_convert:s (bit_not:s @0)) @1)
+ (if (tree_nop_conversion_p (type, TREE_TYPE (@0)))
+ (bit_not (bit_xor (view_convert @0) @1))))
+
/* (x & ~m) | (y & m) -> ((x ^ y) & m) ^ x */
(simplify
(bit_ior:c (bit_and:cs @0 (bit_not @2)) (bit_and:cs @1 @2))
(if (tree_expr_nonnegative_p (@1) && tree_expr_nonzero_p (@1))
(cmp @0 @2)
(if (TREE_CODE (@1) == INTEGER_CST
- && wi::neg_p (@1, TYPE_SIGN (TREE_TYPE (@1))))
+ && wi::neg_p (wi::to_wide (@1), TYPE_SIGN (TREE_TYPE (@1))))
(cmp @2 @0))))))
/* (X - 1U) <= INT_MAX-1U into (int) X > 0. */
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
&& TYPE_UNSIGNED (TREE_TYPE (@0))
&& TYPE_PRECISION (TREE_TYPE (@0)) > 1
- && wi::eq_p (@2, wi::max_value (TYPE_PRECISION (TREE_TYPE (@0)),
- SIGNED) - 1))
+ && (wi::to_wide (@2)
+ == wi::max_value (TYPE_PRECISION (TREE_TYPE (@0)), SIGNED) - 1))
(with { tree stype = signed_type_for (TREE_TYPE (@0)); }
(icmp (convert:stype @0) { build_int_cst (stype, 0); })))))
/* X / 4 < Y / 4 iff X < Y when the division is known to be exact. */
(for cmp (simple_comparison)
(simplify
- (cmp (exact_div @0 INTEGER_CST@2) (exact_div @1 @2))
- (if (wi::gt_p(@2, 0, TYPE_SIGN (TREE_TYPE (@2))))
- (cmp @0 @1))))
+ (cmp (convert?@3 (exact_div @0 INTEGER_CST@2)) (convert? (exact_div @1 @2)))
+ (if (element_precision (@3) >= element_precision (@0)
+ && types_match (@0, @1))
+ (if (wi::lt_p (wi::to_wide (@2), 0, TYPE_SIGN (TREE_TYPE (@2))))
+ (if (!TYPE_UNSIGNED (TREE_TYPE (@3)))
+ (cmp @1 @0)
+ (if (tree_expr_nonzero_p (@0) && tree_expr_nonzero_p (@1))
+ (with
+ {
+ tree utype = unsigned_type_for (TREE_TYPE (@0));
+ }
+ (cmp (convert:utype @1) (convert:utype @0)))))
+ (if (wi::gt_p (wi::to_wide (@2), 1, TYPE_SIGN (TREE_TYPE (@2))))
+ (if (TYPE_UNSIGNED (TREE_TYPE (@0)) || !TYPE_UNSIGNED (TREE_TYPE (@3)))
+ (cmp @0 @1)
+ (with
+ {
+ tree utype = unsigned_type_for (TREE_TYPE (@0));
+ }
+ (cmp (convert:utype @0) (convert:utype @1)))))))))
/* X / C1 op C2 into a simple range test. */
(for cmp (simple_comparison)
&& (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
|| TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))))
(op @0 @1))))
+/* And for pointers... */
+(for op (simple_comparison)
+ (simplify
+ (op (pointer_diff@3 @0 @2) (pointer_diff @1 @2))
+ (if (!TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@2)))
+ (op @0 @1))))
+(simplify
+ (minus (pointer_diff@3 @0 @2) (pointer_diff @1 @2))
+ (if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@3))
+ && !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@2)))
+ (pointer_diff @0 @1)))
/* Z - X < Z - Y is the same as Y < X when there is no overflow. */
(for op (lt le ge gt)
&& (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
|| TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))))
(op @1 @0))))
+/* And for pointers... */
+(for op (simple_comparison)
+ (simplify
+ (op (pointer_diff@3 @2 @0) (pointer_diff @2 @1))
+ (if (!TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@2)))
+ (op @1 @0))))
+(simplify
+ (minus (pointer_diff@3 @2 @0) (pointer_diff @2 @1))
+ (if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@3))
+ && !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@2)))
+ (pointer_diff @1 @0)))
+
+/* X + Y < Y is the same as X < 0 when there is no overflow. */
+(for op (lt le gt ge)
+ (simplify
+ (op:c (plus:c@2 @0 @1) @1)
+ (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
+ && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
+ && !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@0))
+ && (CONSTANT_CLASS_P (@0) || single_use (@2)))
+ (op @0 { build_zero_cst (TREE_TYPE (@0)); }))))
+/* For equality, this is also true with wrapping overflow. */
+(for op (eq ne)
+ (simplify
+ (op:c (nop_convert@3 (plus:c@2 @0 (convert1? @1))) (convert2? @1))
+ (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
+ && (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
+ || TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0)))
+ && (CONSTANT_CLASS_P (@0) || (single_use (@2) && single_use (@3)))
+ && tree_nop_conversion_p (TREE_TYPE (@3), TREE_TYPE (@2))
+ && tree_nop_conversion_p (TREE_TYPE (@3), TREE_TYPE (@1)))
+ (op @0 { build_zero_cst (TREE_TYPE (@0)); })))
+ (simplify
+ (op:c (nop_convert@3 (pointer_plus@2 (convert1? @0) @1)) (convert2? @0))
+ (if (tree_nop_conversion_p (TREE_TYPE (@2), TREE_TYPE (@0))
+ && tree_nop_conversion_p (TREE_TYPE (@3), TREE_TYPE (@0))
+ && (CONSTANT_CLASS_P (@1) || (single_use (@2) && single_use (@3))))
+ (op @1 { build_zero_cst (TREE_TYPE (@1)); }))))
+
+/* X - Y < X is the same as Y > 0 when there is no overflow.
+ For equality, this is also true with wrapping overflow. */
+(for op (simple_comparison)
+ (simplify
+ (op:c @0 (minus@2 @0 @1))
+ (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
+ && (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
+ || ((op == EQ_EXPR || op == NE_EXPR)
+ && TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))))
+ && (CONSTANT_CLASS_P (@1) || single_use (@2)))
+ (op @1 { build_zero_cst (TREE_TYPE (@1)); }))))
+
+/* Transform:
+ (X / Y) == 0 -> X < Y if X, Y are unsigned.
+ (X / Y) != 0 -> X >= Y, if X, Y are unsigned. */
+(for cmp (eq ne)
+ ocmp (lt ge)
+ (simplify
+ (cmp (trunc_div @0 @1) integer_zerop)
+ (if (TYPE_UNSIGNED (TREE_TYPE (@0))
+ /* Complex ==/!= is allowed, but not </>=. */
+ && TREE_CODE (TREE_TYPE (@0)) != COMPLEX_TYPE
+ && (VECTOR_TYPE_P (type) || !VECTOR_TYPE_P (TREE_TYPE (@0))))
+ (ocmp @0 @1))))
/* X == C - X can never be true if C is odd. */
(for cmp (eq ne)
(for cmp (eq ne)
(simplify
(cmp:c (with_possible_nonzero_bits2 @0) (with_certain_nonzero_bits2 @1))
- (if ((~get_nonzero_bits (@0) & @1) != 0)
+ (if (wi::bit_and_not (wi::to_wide (@1), get_nonzero_bits (@0)) != 0)
{ constant_boolean_node (cmp == NE_EXPR, type); })))
/* ((X inner_op C0) outer_op C1)
if (inner_op == BIT_XOR_EXPR)
{
- C0 = wi::bit_and_not (@0, @1);
- cst_emit = wi::bit_or (C0, @1);
+ C0 = wi::bit_and_not (wi::to_wide (@0), wi::to_wide (@1));
+ cst_emit = C0 | wi::to_wide (@1);
}
else
{
- C0 = @0;
- cst_emit = wi::bit_xor (@0, @1);
+ C0 = wi::to_wide (@0);
+ cst_emit = C0 ^ wi::to_wide (@1);
}
}
- (if (!fail && wi::bit_and (C0, zero_mask_not) == 0)
+ (if (!fail && (C0 & zero_mask_not) == 0)
(outer_op @2 { wide_int_to_tree (type, cst_emit); })
- (if (!fail && wi::bit_and (@1, zero_mask_not) == 0)
+ (if (!fail && (wi::to_wide (@1) & zero_mask_not) == 0)
(inner_op @2 { wide_int_to_tree (type, cst_emit); }))))))
/* Associate (p +p off1) +p off2 as (p +p (off1 + off2)). */
&& ((GIMPLE && useless_type_conversion_p (type, TREE_TYPE (@1)))
|| (GENERIC && type == TREE_TYPE (@1))))
@1))
+(simplify
+ (pointer_plus @0 (convert?@2 (pointer_diff@3 @1 @@0)))
+ (if (TYPE_PRECISION (TREE_TYPE (@2)) >= TYPE_PRECISION (TREE_TYPE (@3)))
+ (convert @1)))
/* Pattern match
tem = (sizetype) ptr;
... = ptr & ~algn; */
(simplify
(pointer_plus @0 (negate (bit_and (convert @0) INTEGER_CST@1)))
- (with { tree algn = wide_int_to_tree (TREE_TYPE (@0), wi::bit_not (@1)); }
+ (with { tree algn = wide_int_to_tree (TREE_TYPE (@0), ~wi::to_wide (@1)); }
(bit_and @0 { algn; })))
/* Try folding difference of addresses. */
(simplify
(minus (convert ADDR_EXPR@0) (convert @1))
(if (tree_nop_conversion_p (type, TREE_TYPE (@0)))
- (with { HOST_WIDE_INT diff; }
+ (with { poly_int64 diff; }
(if (ptr_difference_const (@0, @1, &diff))
{ build_int_cst_type (type, diff); }))))
(simplify
(minus (convert @0) (convert ADDR_EXPR@1))
(if (tree_nop_conversion_p (type, TREE_TYPE (@0)))
- (with { HOST_WIDE_INT diff; }
+ (with { poly_int64 diff; }
+ (if (ptr_difference_const (@0, @1, &diff))
+ { build_int_cst_type (type, diff); }))))
+(simplify
+ (pointer_diff (convert?@2 ADDR_EXPR@0) (convert1?@3 @1))
+ (if (tree_nop_conversion_p (TREE_TYPE(@2), TREE_TYPE (@0))
+ && tree_nop_conversion_p (TREE_TYPE(@3), TREE_TYPE (@1)))
+ (with { poly_int64 diff; }
+ (if (ptr_difference_const (@0, @1, &diff))
+ { build_int_cst_type (type, diff); }))))
+(simplify
+ (pointer_diff (convert?@2 @0) (convert1?@3 ADDR_EXPR@1))
+ (if (tree_nop_conversion_p (TREE_TYPE(@2), TREE_TYPE (@0))
+ && tree_nop_conversion_p (TREE_TYPE(@3), TREE_TYPE (@1)))
+ (with { poly_int64 diff; }
(if (ptr_difference_const (@0, @1, &diff))
{ build_int_cst_type (type, diff); }))))
unsigned HOST_WIDE_INT bitpos;
get_pointer_alignment_1 (@0, &align, &bitpos);
}
- (if (wi::ltu_p (@1, align / BITS_PER_UNIT))
- { wide_int_to_tree (type, wi::bit_and (@1, bitpos / BITS_PER_UNIT)); }))))
+ (if (wi::ltu_p (wi::to_wide (@1), align / BITS_PER_UNIT))
+ { wide_int_to_tree (type, (wi::to_wide (@1)
+ & (bitpos / BITS_PER_UNIT))); }))))
/* We can't reassociate at all for saturating types. */
t1 = TYPE_OVERFLOW_WRAPS (type) ? type : TREE_TYPE (@1);
}
(convert (plus (convert:t1 @0) (convert:t1 @1))))))
- /* -(-A) -> A */
+ /* -(T)(-A) -> (T)A
+ Sign-extension is ok except for INT_MIN, which thankfully cannot
+ happen without overflow. */
(simplify
- (negate (convert? (negate @1)))
- (if (tree_nop_conversion_p (type, TREE_TYPE (@1))
- && !TYPE_OVERFLOW_SANITIZED (type))
+ (negate (convert (negate @1)))
+ (if (INTEGRAL_TYPE_P (type)
+ && (TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@1))
+ || (!TYPE_UNSIGNED (TREE_TYPE (@1))
+ && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@1))))
+ && !TYPE_OVERFLOW_SANITIZED (type)
+ && !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@1)))
(convert @1)))
+ (simplify
+ (negate (convert negate_expr_p@1))
+ (if (SCALAR_FLOAT_TYPE_P (type)
+ && ((DECIMAL_FLOAT_TYPE_P (type)
+ == DECIMAL_FLOAT_TYPE_P (TREE_TYPE (@1))
+ && TYPE_PRECISION (type) >= TYPE_PRECISION (TREE_TYPE (@1)))
+ || !HONOR_SIGN_DEPENDENT_ROUNDING (type)))
+ (convert (negate @1))))
+ (simplify
+ (negate (nop_convert (negate @1)))
+ (if (!TYPE_OVERFLOW_SANITIZED (type)
+ && !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@1)))
+ (view_convert @1)))
/* We can't reassociate floating-point unless -fassociative-math
or fixed-point plus or minus because of saturation to +-Inf. */
(simplify
(plus:c (minus @0 @1) (minus @2 @0))
(minus @2 @1))
+ (simplify
+ (plus:c (pointer_diff @0 @1) (pointer_diff @2 @0))
+ (if (TYPE_OVERFLOW_UNDEFINED (type)
+ && !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@0)))
+ (pointer_diff @2 @1)))
(simplify
(minus (plus:c @0 @1) (minus @0 @2))
(plus @1 @2))
CONSTANT_CLASS_P@2)
/* If one of the types wraps, use that one. */
(if (!ANY_INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_WRAPS (type))
- (if (outer_op == PLUS_EXPR)
- (plus (view_convert @0) (inner_op @2 (view_convert @1)))
- (minus (view_convert @0) (neg_inner_op @2 (view_convert @1))))
+ /* If all 3 captures are CONSTANT_CLASS_P, punt, as we might recurse
+ forever if something doesn't simplify into a constant. */
+ (if (!CONSTANT_CLASS_P (@0))
+ (if (outer_op == PLUS_EXPR)
+ (plus (view_convert @0) (inner_op @2 (view_convert @1)))
+ (minus (view_convert @0) (neg_inner_op @2 (view_convert @1)))))
(if (!ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
|| TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0)))
(if (outer_op == PLUS_EXPR)
(inner_op @0 { cst; } )
/* X+INT_MAX+1 is X-INT_MIN. */
(if (INTEGRAL_TYPE_P (type) && cst
- && wi::eq_p (cst, wi::min_value (type)))
- (neg_inner_op @0 { wide_int_to_tree (type, cst); })
+ && wi::to_wide (cst) == wi::min_value (type))
+ (neg_inner_op @0 { wide_int_to_tree (type, wi::to_wide (cst)); })
/* Last resort, use some unsigned type. */
(with { tree utype = unsigned_type_for (type); }
- (view_convert (inner_op
- (view_convert:utype @0)
- (view_convert:utype
- { drop_tree_overflow (cst); })))))))))))))
+ (if (utype)
+ (view_convert (inner_op
+ (view_convert:utype @0)
+ (view_convert:utype
+ { drop_tree_overflow (cst); }))))))))))))))
/* (CST1 - A) +- CST2 -> CST3 - A */
(for outer_op (plus minus)
(bit_not @0))
/* (T)(P + A) - (T)P -> (T) A */
- (for add (plus pointer_plus)
+ (simplify
+ (minus (convert (plus:c @@0 @1))
+ (convert? @0))
+ (if (element_precision (type) <= element_precision (TREE_TYPE (@1))
+ /* For integer types, if A has a smaller type
+ than T the result depends on the possible
+ overflow in P + A.
+ E.g. T=size_t, A=(unsigned)429497295, P>0.
+ However, if an overflow in P + A would cause
+ undefined behavior, we can assume that there
+ is no overflow. */
+ || (INTEGRAL_TYPE_P (TREE_TYPE (@1))
+ && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@1))))
+ (convert @1)))
+ (simplify
+ (minus (convert (pointer_plus @@0 @1))
+ (convert @0))
+ (if (element_precision (type) <= element_precision (TREE_TYPE (@1))
+ /* For pointer types, if the conversion of A to the
+ final type requires a sign- or zero-extension,
+ then we have to punt - it is not defined which
+ one is correct. */
+ || (POINTER_TYPE_P (TREE_TYPE (@0))
+ && TREE_CODE (@1) == INTEGER_CST
+ && tree_int_cst_sign_bit (@1) == 0))
+ (convert @1)))
(simplify
- (minus (convert (add @@0 @1))
- (convert @0))
- (if (element_precision (type) <= element_precision (TREE_TYPE (@1))
- /* For integer types, if A has a smaller type
- than T the result depends on the possible
- overflow in P + A.
- E.g. T=size_t, A=(unsigned)429497295, P>0.
- However, if an overflow in P + A would cause
- undefined behavior, we can assume that there
- is no overflow. */
- || (INTEGRAL_TYPE_P (TREE_TYPE (@0))
- && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)))
- /* For pointer types, if the conversion of A to the
- final type requires a sign- or zero-extension,
- then we have to punt - it is not defined which
- one is correct. */
- || (POINTER_TYPE_P (TREE_TYPE (@0))
- && TREE_CODE (@1) == INTEGER_CST
- && tree_int_cst_sign_bit (@1) == 0))
- (convert @1))))
+ (pointer_diff (pointer_plus @@0 @1) @0)
+ /* The second argument of pointer_plus must be interpreted as signed, and
+ thus sign-extended if necessary. */
+ (with { tree stype = signed_type_for (TREE_TYPE (@1)); }
+ /* Use view_convert instead of convert here, as POINTER_PLUS_EXPR
+ second arg is unsigned even when we need to consider it as signed,
+ we don't want to diagnose overflow here. */
+ (convert (view_convert:stype @1))))
/* (T)P - (T)(P + A) -> -(T) A */
- (for add (plus pointer_plus)
- (simplify
- (minus (convert @0)
- (convert (add @@0 @1)))
+ (simplify
+ (minus (convert? @0)
+ (convert (plus:c @@0 @1)))
+ (if (INTEGRAL_TYPE_P (type)
+ && TYPE_OVERFLOW_UNDEFINED (type)
+ && element_precision (type) <= element_precision (TREE_TYPE (@1)))
+ (with { tree utype = unsigned_type_for (type); }
+ (convert (negate (convert:utype @1))))
(if (element_precision (type) <= element_precision (TREE_TYPE (@1))
/* For integer types, if A has a smaller type
than T the result depends on the possible
However, if an overflow in P + A would cause
undefined behavior, we can assume that there
is no overflow. */
- || (INTEGRAL_TYPE_P (TREE_TYPE (@0))
- && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)))
+ || (INTEGRAL_TYPE_P (TREE_TYPE (@1))
+ && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@1))))
+ (negate (convert @1)))))
+ (simplify
+ (minus (convert @0)
+ (convert (pointer_plus @@0 @1)))
+ (if (INTEGRAL_TYPE_P (type)
+ && TYPE_OVERFLOW_UNDEFINED (type)
+ && element_precision (type) <= element_precision (TREE_TYPE (@1)))
+ (with { tree utype = unsigned_type_for (type); }
+ (convert (negate (convert:utype @1))))
+ (if (element_precision (type) <= element_precision (TREE_TYPE (@1))
/* For pointer types, if the conversion of A to the
final type requires a sign- or zero-extension,
then we have to punt - it is not defined which
&& TREE_CODE (@1) == INTEGER_CST
&& tree_int_cst_sign_bit (@1) == 0))
(negate (convert @1)))))
+ (simplify
+ (pointer_diff @0 (pointer_plus @@0 @1))
+ /* The second argument of pointer_plus must be interpreted as signed, and
+ thus sign-extended if necessary. */
+ (with { tree stype = signed_type_for (TREE_TYPE (@1)); }
+ /* Use view_convert instead of convert here, as POINTER_PLUS_EXPR
+ second arg is unsigned even when we need to consider it as signed,
+ we don't want to diagnose overflow here. */
+ (negate (convert (view_convert:stype @1)))))
/* (T)(P + A) - (T)(P + B) -> (T)A - (T)B */
- (for add (plus pointer_plus)
- (simplify
- (minus (convert (add @@0 @1))
- (convert (add @0 @2)))
+ (simplify
+ (minus (convert (plus:c @@0 @1))
+ (convert (plus:c @0 @2)))
+ (if (INTEGRAL_TYPE_P (type)
+ && TYPE_OVERFLOW_UNDEFINED (type)
+ && element_precision (type) <= element_precision (TREE_TYPE (@1))
+ && element_precision (type) <= element_precision (TREE_TYPE (@2)))
+ (with { tree utype = unsigned_type_for (type); }
+ (convert (minus (convert:utype @1) (convert:utype @2))))
+ (if (((element_precision (type) <= element_precision (TREE_TYPE (@1)))
+ == (element_precision (type) <= element_precision (TREE_TYPE (@2))))
+ && (element_precision (type) <= element_precision (TREE_TYPE (@1))
+ /* For integer types, if A has a smaller type
+ than T the result depends on the possible
+ overflow in P + A.
+ E.g. T=size_t, A=(unsigned)429497295, P>0.
+ However, if an overflow in P + A would cause
+ undefined behavior, we can assume that there
+ is no overflow. */
+ || (INTEGRAL_TYPE_P (TREE_TYPE (@1))
+ && INTEGRAL_TYPE_P (TREE_TYPE (@2))
+ && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@1))
+ && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@2)))))
+ (minus (convert @1) (convert @2)))))
+ (simplify
+ (minus (convert (pointer_plus @@0 @1))
+ (convert (pointer_plus @0 @2)))
+ (if (INTEGRAL_TYPE_P (type)
+ && TYPE_OVERFLOW_UNDEFINED (type)
+ && element_precision (type) <= element_precision (TREE_TYPE (@1)))
+ (with { tree utype = unsigned_type_for (type); }
+ (convert (minus (convert:utype @1) (convert:utype @2))))
(if (element_precision (type) <= element_precision (TREE_TYPE (@1))
- /* For integer types, if A has a smaller type
- than T the result depends on the possible
- overflow in P + A.
- E.g. T=size_t, A=(unsigned)429497295, P>0.
- However, if an overflow in P + A would cause
- undefined behavior, we can assume that there
- is no overflow. */
- || (INTEGRAL_TYPE_P (TREE_TYPE (@0))
- && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)))
/* For pointer types, if the conversion of A to the
final type requires a sign- or zero-extension,
then we have to punt - it is not defined which
&& tree_int_cst_sign_bit (@1) == 0
&& TREE_CODE (@2) == INTEGER_CST
&& tree_int_cst_sign_bit (@2) == 0))
- (minus (convert @1) (convert @2)))))))
-
+ (minus (convert @1) (convert @2)))))
+ (simplify
+ (pointer_diff (pointer_plus @@0 @1) (pointer_plus @0 @2))
+ /* The second argument of pointer_plus must be interpreted as signed, and
+ thus sign-extended if necessary. */
+ (with { tree stype = signed_type_for (TREE_TYPE (@1)); }
+ /* Use view_convert instead of convert here, as POINTER_PLUS_EXPR
+ second arg is unsigned even when we need to consider it as signed,
+ we don't want to diagnose overflow here. */
+ (minus (convert (view_convert:stype @1))
+ (convert (view_convert:stype @2)))))))
+
+/* (A * C) +- (B * C) -> (A+-B) * C and (A * C) +- A -> A * (C+-1).
+ Modeled after fold_plusminus_mult_expr. */
+(if (!TYPE_SATURATING (type)
+ && (!FLOAT_TYPE_P (type) || flag_associative_math))
+ (for plusminus (plus minus)
+ (simplify
+ (plusminus (mult:cs@3 @0 @1) (mult:cs@4 @0 @2))
+ (if ((!ANY_INTEGRAL_TYPE_P (type)
+ || TYPE_OVERFLOW_WRAPS (type)
+ || (INTEGRAL_TYPE_P (type)
+ && tree_expr_nonzero_p (@0)
+ && expr_not_equal_to (@0, wi::minus_one (TYPE_PRECISION (type)))))
+ /* If @1 +- @2 is constant require a hard single-use on either
+ original operand (but not on both). */
+ && (single_use (@3) || single_use (@4)))
+ (mult (plusminus @1 @2) @0)))
+ /* We cannot generate constant 1 for fract. */
+ (if (!ALL_FRACT_MODE_P (TYPE_MODE (type)))
+ (simplify
+ (plusminus @0 (mult:c@3 @0 @2))
+ (if ((!ANY_INTEGRAL_TYPE_P (type)
+ || TYPE_OVERFLOW_WRAPS (type)
+ || (INTEGRAL_TYPE_P (type)
+ && tree_expr_nonzero_p (@0)
+ && expr_not_equal_to (@0, wi::minus_one (TYPE_PRECISION (type)))))
+ && single_use (@3))
+ (mult (plusminus { build_one_cst (type); } @2) @0)))
+ (simplify
+ (plusminus (mult:c@3 @0 @2) @0)
+ (if ((!ANY_INTEGRAL_TYPE_P (type)
+ || TYPE_OVERFLOW_WRAPS (type)
+ || (INTEGRAL_TYPE_P (type)
+ && tree_expr_nonzero_p (@0)
+ && expr_not_equal_to (@0, wi::minus_one (TYPE_PRECISION (type)))))
+ && single_use (@3))
+ (mult (plusminus @2 { build_one_cst (type); }) @0))))))
/* Simplifications of MIN_EXPR, MAX_EXPR, fmin() and fmax(). */
-(for minmax (min max FMIN FMAX)
+(for minmax (min max FMIN_ALL FMAX_ALL)
(simplify
(minmax @0 @0)
@0))
&& TYPE_PRECISION (TREE_TYPE (@0)) > TYPE_PRECISION (type))
(minmax @1 (convert @2)))))
-(for minmax (FMIN FMAX)
+(for minmax (FMIN_ALL FMAX_ALL)
/* If either argument is NaN, return the other one. Avoid the
transformation if we get (and honor) a signalling NaN. */
(simplify
worry about it either. */
(if (flag_finite_math_only)
(simplify
- (FMIN @0 @1)
+ (FMIN_ALL @0 @1)
(min @0 @1))
(simplify
- (FMAX @0 @1)
+ (FMAX_ALL @0 @1)
(max @0 @1)))
/* min (-A, -B) -> -max (A, B) */
-(for minmax (min max FMIN FMAX)
- maxmin (max min FMAX FMIN)
+(for minmax (min max FMIN_ALL FMAX_ALL)
+ maxmin (max min FMAX_ALL FMIN_ALL)
(simplify
(minmax (negate:s@2 @0) (negate:s@3 @1))
(if (FLOAT_TYPE_P (TREE_TYPE (@0))
(for cmp (eq ne)
(simplify
(cmp (min @0 INTEGER_CST@1) INTEGER_CST@2)
- (if (wi::lt_p (@1, @2, TYPE_SIGN (TREE_TYPE (@0))))
+ (if (wi::lt_p (wi::to_wide (@1), wi::to_wide (@2),
+ TYPE_SIGN (TREE_TYPE (@0))))
{ constant_boolean_node (cmp == NE_EXPR, type); }
- (if (wi::gt_p (@1, @2, TYPE_SIGN (TREE_TYPE (@0))))
+ (if (wi::gt_p (wi::to_wide (@1), wi::to_wide (@2),
+ TYPE_SIGN (TREE_TYPE (@0))))
(cmp @0 @2)))))
(for cmp (eq ne)
(simplify
(cmp (max @0 INTEGER_CST@1) INTEGER_CST@2)
- (if (wi::gt_p (@1, @2, TYPE_SIGN (TREE_TYPE (@0))))
+ (if (wi::gt_p (wi::to_wide (@1), wi::to_wide (@2),
+ TYPE_SIGN (TREE_TYPE (@0))))
{ constant_boolean_node (cmp == NE_EXPR, type); }
- (if (wi::lt_p (@1, @2, TYPE_SIGN (TREE_TYPE (@0))))
+ (if (wi::lt_p (wi::to_wide (@1), wi::to_wide (@2),
+ TYPE_SIGN (TREE_TYPE (@0))))
(cmp @0 @2)))))
/* MIN (X, C1) < C2 -> X < C2 || C1 < C2 */
(for minmax (min min max max min min max max )
/* Optimize (x >> c) << c into x & (-1<<c). */
(simplify
(lshift (rshift @0 INTEGER_CST@1) @1)
- (if (wi::ltu_p (@1, element_precision (type)))
+ (if (wi::ltu_p (wi::to_wide (@1), element_precision (type)))
(bit_and @0 (lshift { build_minus_one_cst (type); } @1))))
/* Optimize (x << c) >> c into x & ((unsigned)-1 >> c) for unsigned
(simplify
(rshift (lshift @0 INTEGER_CST@1) @1)
(if (TYPE_UNSIGNED (type)
- && (wi::ltu_p (@1, element_precision (type))))
+ && (wi::ltu_p (wi::to_wide (@1), element_precision (type))))
(bit_and @0 (rshift { build_minus_one_cst (type); } @1))))
(for shiftrotate (lrotate rrotate lshift rshift)
(simplify
(op (op @0 INTEGER_CST@1) INTEGER_CST@2)
(with { unsigned int prec = element_precision (type); }
- (if (wi::ge_p (@1, 0, TYPE_SIGN (TREE_TYPE (@1)))
- && wi::lt_p (@1, prec, TYPE_SIGN (TREE_TYPE (@1)))
- && wi::ge_p (@2, 0, TYPE_SIGN (TREE_TYPE (@2)))
- && wi::lt_p (@2, prec, TYPE_SIGN (TREE_TYPE (@2))))
- (with { unsigned int low = wi::add (@1, @2).to_uhwi (); }
+ (if (wi::ge_p (wi::to_wide (@1), 0, TYPE_SIGN (TREE_TYPE (@1)))
+ && wi::lt_p (wi::to_wide (@1), prec, TYPE_SIGN (TREE_TYPE (@1)))
+ && wi::ge_p (wi::to_wide (@2), 0, TYPE_SIGN (TREE_TYPE (@2)))
+ && wi::lt_p (wi::to_wide (@2), prec, TYPE_SIGN (TREE_TYPE (@2))))
+ (with { unsigned int low = (tree_to_uhwi (@1)
+ + tree_to_uhwi (@2)); }
/* Deal with a OP (c1 + c2) being undefined but (a OP c1) OP c2
being well defined. */
(if (low >= prec)
(for cmp (ne eq)
(simplify
(cmp (lshift INTEGER_CST@0 @1) INTEGER_CST@2)
- (with { int cand = wi::ctz (@2) - wi::ctz (@0); }
+ (with { int cand = wi::ctz (wi::to_wide (@2)) - wi::ctz (wi::to_wide (@0)); }
(if (cand < 0
|| (!integer_zerop (@2)
- && wi::ne_p (wi::lshift (@0, cand), @2)))
+ && wi::lshift (wi::to_wide (@0), cand) != wi::to_wide (@2)))
{ constant_boolean_node (cmp == NE_EXPR, type); }
(if (!integer_zerop (@2)
- && wi::eq_p (wi::lshift (@0, cand), @2))
+ && wi::lshift (wi::to_wide (@0), cand) == wi::to_wide (@2))
(cmp @1 { build_int_cst (TREE_TYPE (@1), cand); }))))))
/* Fold (X << C1) & C2 into (X << C1) & (C2 | ((1 << C1) - 1))
&& TYPE_UNSIGNED (TREE_TYPE (@1)))))
(view_convert @1)))
+/* Simplify a view-converted empty constructor. */
+(simplify
+ (view_convert CONSTRUCTOR@0)
+ (if (TREE_CODE (@0) != SSA_NAME
+ && CONSTRUCTOR_NELTS (@0) == 0)
+ { build_zero_cst (type); }))
+
/* Re-association barriers around constants and other re-association
barriers can be removed. */
(simplify
(mult (convert1? (exact_div @0 @@1)) (convert2? @1))
(convert @0))
+/* Simplify (A / B) * B + (A % B) -> A. */
+(for div (trunc_div ceil_div floor_div round_div)
+ mod (trunc_mod ceil_mod floor_mod round_mod)
+ (simplify
+ (plus:c (mult:c (div @0 @1) @1) (mod @0 @1))
+ @0))
+
+/* ((X /[ex] A) +- B) * A --> X +- A * B. */
+(for op (plus minus)
+ (simplify
+ (mult (convert1? (op (convert2? (exact_div @0 INTEGER_CST@@1)) INTEGER_CST@2)) @1)
+ (if (tree_nop_conversion_p (type, TREE_TYPE (@2))
+ && tree_nop_conversion_p (TREE_TYPE (@0), TREE_TYPE (@2)))
+ (with
+ {
+ wi::overflow_type overflow;
+ wide_int mul = wi::mul (wi::to_wide (@1), wi::to_wide (@2),
+ TYPE_SIGN (type), &overflow);
+ }
+ (if (types_match (type, TREE_TYPE (@2))
+ && types_match (TREE_TYPE (@0), TREE_TYPE (@2)) && !overflow)
+ (op @0 { wide_int_to_tree (type, mul); })
+ (with { tree utype = unsigned_type_for (type); }
+ (convert (op (convert:utype @0)
+ (mult (convert:utype @1) (convert:utype @2))))))))))
+
/* Canonicalization of binary operations. */
/* Convert X + -C into X - C. */
(if (INTEGRAL_TYPE_P (type))
(mult @0 { build_int_cst (type, 2); }))))
+/* 0 - X -> -X. */
(simplify
(minus integer_zerop @1)
(negate @1))
+(simplify
+ (pointer_diff integer_zerop @1)
+ (negate (convert @1)))
/* (ARG0 - ARG1) is the same as (-ARG1 + ARG0). So check whether
ARG0 is zero and X + ARG0 reduces to X, since that would mean
/* Reassociate (X * CST) * Y to (X * Y) * CST. This does not introduce
signed overflow for CST != 0 && CST != -1. */
(simplify
- (mult:c (mult:s @0 INTEGER_CST@1) @2)
+ (mult:c (mult:s@3 @0 INTEGER_CST@1) @2)
(if (TREE_CODE (@2) != INTEGER_CST
+ && single_use (@3)
&& !integer_zerop (@1) && !integer_minus_onep (@1))
(mult (mult @0 @2) @1)))
(if (integer_zerop (@0))
@2)))
+/* Sink unary operations to constant branches, but only if we do fold it to
+ constants. */
+(for op (negate bit_not abs absu)
+ (simplify
+ (op (vec_cond @0 VECTOR_CST@1 VECTOR_CST@2))
+ (with
+ {
+ tree cst1, cst2;
+ cst1 = const_unop (op, type, @1);
+ if (cst1)
+ cst2 = const_unop (op, type, @2);
+ }
+ (if (cst1 && cst2)
+ (vec_cond @0 { cst1; } { cst2; })))))
+
/* Simplification moved from fold_cond_expr_with_comparison. It may also
be extended. */
/* This pattern implements two kinds simplification:
&& (cmp == LT_EXPR || cmp == GE_EXPR)))
(with
{
- bool overflow = false;
+ wi::overflow_type overflow = wi::OVF_NONE;
enum tree_code code, cmp_code = cmp;
- wide_int real_c1, c1 = @1, c2 = @2, c3 = @3;
+ wide_int real_c1;
+ wide_int c1 = wi::to_wide (@1);
+ wide_int c2 = wi::to_wide (@2);
+ wide_int c3 = wi::to_wide (@3);
signop sgn = TYPE_SIGN (from_type);
/* Handle special case A), given x of unsigned type:
from if-conversion. */
(simplify
(cnd @0 @1 (cnd @2 @3 @4))
- (if (COMPARISON_CLASS_P (@0)
- && COMPARISON_CLASS_P (@2)
- && invert_tree_comparison
- (TREE_CODE (@0), HONOR_NANS (TREE_OPERAND (@0, 0))) == TREE_CODE (@2)
- && operand_equal_p (TREE_OPERAND (@0, 0), TREE_OPERAND (@2, 0), 0)
- && operand_equal_p (TREE_OPERAND (@0, 1), TREE_OPERAND (@2, 1), 0))
+ (if (inverse_conditions_p (@0, @2))
(cnd @0 @1 @3)))
(simplify
(cnd @0 (cnd @1 @2 @3) @4)
- (if (COMPARISON_CLASS_P (@0)
- && COMPARISON_CLASS_P (@1)
- && invert_tree_comparison
- (TREE_CODE (@0), HONOR_NANS (TREE_OPERAND (@0, 0))) == TREE_CODE (@1)
- && operand_equal_p (TREE_OPERAND (@0, 0), TREE_OPERAND (@1, 0), 0)
- && operand_equal_p (TREE_OPERAND (@0, 1), TREE_OPERAND (@1, 1), 0))
+ (if (inverse_conditions_p (@0, @1))
(cnd @0 @3 @4)))
/* A ? B : B -> B. */
(simplify
(plus:c @3 (view_convert? (vec_cond:s @0 integer_each_onep@1 integer_zerop@2)))
(if (VECTOR_TYPE_P (type)
- && TYPE_VECTOR_SUBPARTS (type) == TYPE_VECTOR_SUBPARTS (TREE_TYPE (@1))
+ && known_eq (TYPE_VECTOR_SUBPARTS (type),
+ TYPE_VECTOR_SUBPARTS (TREE_TYPE (@1)))
&& (TYPE_MODE (TREE_TYPE (type))
== TYPE_MODE (TREE_TYPE (TREE_TYPE (@1)))))
(minus @3 (view_convert (vec_cond @0 (negate @1) @2)))))
(simplify
(minus @3 (view_convert? (vec_cond:s @0 integer_each_onep@1 integer_zerop@2)))
(if (VECTOR_TYPE_P (type)
- && TYPE_VECTOR_SUBPARTS (type) == TYPE_VECTOR_SUBPARTS (TREE_TYPE (@1))
+ && known_eq (TYPE_VECTOR_SUBPARTS (type),
+ TYPE_VECTOR_SUBPARTS (TREE_TYPE (@1)))
&& (TYPE_MODE (TREE_TYPE (type))
== TYPE_MODE (TREE_TYPE (TREE_TYPE (@1)))))
(plus @3 (view_convert (vec_cond @0 (negate @1) @2)))))
(for cmp (le gt)
acmp (lt ge)
(simplify
- (cmp @0 INTEGER_CST@1)
- (if (tree_int_cst_sgn (@1) == -1)
- (acmp @0 { wide_int_to_tree (TREE_TYPE (@1), wi::add (@1, 1)); }))))
+ (cmp @0 uniform_integer_cst_p@1)
+ (with { tree cst = uniform_integer_cst_p (@1); }
+ (if (tree_int_cst_sgn (cst) == -1)
+ (acmp @0 { build_uniform_cst (TREE_TYPE (@1),
+ wide_int_to_tree (TREE_TYPE (cst),
+ wi::to_wide (cst)
+ + 1)); })))))
(for cmp (ge lt)
acmp (gt le)
(simplify
- (cmp @0 INTEGER_CST@1)
- (if (tree_int_cst_sgn (@1) == 1)
- (acmp @0 { wide_int_to_tree (TREE_TYPE (@1), wi::sub (@1, 1)); }))))
-
+ (cmp @0 uniform_integer_cst_p@1)
+ (with { tree cst = uniform_integer_cst_p (@1); }
+ (if (tree_int_cst_sgn (cst) == 1)
+ (acmp @0 { build_uniform_cst (TREE_TYPE (@1),
+ wide_int_to_tree (TREE_TYPE (cst),
+ wi::to_wide (cst) - 1)); })))))
/* We can simplify a logical negation of a comparison to the
inverted comparison. As we cannot compute an expression
with the transformation in fold_cond_expr_with_comparison which
attempts to synthetize ABS_EXPR. */
(for cmp (eq ne)
- (simplify
- (cmp (minus@2 @0 @1) integer_zerop)
- (if (single_use (@2))
- (cmp @0 @1))))
+ (for sub (minus pointer_diff)
+ (simplify
+ (cmp (sub@2 @0 @1) integer_zerop)
+ (if (single_use (@2))
+ (cmp @0 @1)))))
/* Transform comparisons of the form X * C1 CMP 0 to X CMP 0 in the
signed arithmetic case. That form is created by the compiler
(if (tree_int_cst_sgn (@1) < 0)
(scmp @0 @2)
(cmp @0 @2))))))
-
+
/* Simplify comparison of something with itself. For IEEE
floating-point, we can only do some of these simplifications. */
(for cmp (eq ge le)
}
tree newtype
= (TYPE_PRECISION (TREE_TYPE (@0)) > TYPE_PRECISION (type1)
- ? TREE_TYPE (@0) : type1);
+ ? TREE_TYPE (@0) : type1);
}
(if (TYPE_PRECISION (TREE_TYPE (@2)) > TYPE_PRECISION (newtype))
(cmp (convert:newtype @0) (convert:newtype @1))))))
-
+
(simplify
(cmp @0 REAL_CST@1)
/* IEEE doesn't distinguish +0 and -0 in comparisons. */
code = swap_tree_comparison (code);
}
(switch
- /* x > +Inf is always false, if with ignore sNANs. */
+ /* x > +Inf is always false, if we ignore NaNs or exceptions. */
(if (code == GT_EXPR
- && ! HONOR_SNANS (@0))
+ && !(HONOR_NANS (@0) && flag_trapping_math))
{ constant_boolean_node (false, type); })
(if (code == LE_EXPR)
- /* x <= +Inf is always true, if we don't case about NaNs. */
+ /* x <= +Inf is always true, if we don't care about NaNs. */
(if (! HONOR_NANS (@0))
{ constant_boolean_node (true, type); }
- /* x <= +Inf is the same as x == x, i.e. !isnan(x). */
- (eq @0 @0)))
- /* x == +Inf and x >= +Inf are always equal to x > DBL_MAX. */
- (if (code == EQ_EXPR || code == GE_EXPR)
+ /* x <= +Inf is the same as x == x, i.e. !isnan(x), but this loses
+ an "invalid" exception. */
+ (if (!flag_trapping_math)
+ (eq @0 @0))))
+ /* x == +Inf and x >= +Inf are always equal to x > DBL_MAX, but
+ for == this introduces an exception for x a NaN. */
+ (if ((code == EQ_EXPR && !(HONOR_NANS (@0) && flag_trapping_math))
+ || code == GE_EXPR)
(with { real_maxval (&max, neg, TYPE_MODE (TREE_TYPE (@0))); }
(if (neg)
(lt @0 { build_real (TREE_TYPE (@0), max); })
(if (neg)
(ge @0 { build_real (TREE_TYPE (@0), max); })
(le @0 { build_real (TREE_TYPE (@0), max); }))))
- /* x != +Inf is always equal to !(x > DBL_MAX). */
+ /* x != +Inf is always equal to !(x > DBL_MAX), but this introduces
+ an exception for x a NaN so use an unordered comparison. */
(if (code == NE_EXPR)
(with { real_maxval (&max, neg, TYPE_MODE (TREE_TYPE (@0))); }
(if (! HONOR_NANS (@0))
(ge @0 { build_real (TREE_TYPE (@0), max); })
(le @0 { build_real (TREE_TYPE (@0), max); }))
(if (neg)
- (bit_xor (lt @0 { build_real (TREE_TYPE (@0), max); })
- { build_one_cst (type); })
- (bit_xor (gt @0 { build_real (TREE_TYPE (@0), max); })
- { build_one_cst (type); }))))))))))
+ (unge @0 { build_real (TREE_TYPE (@0), max); })
+ (unle @0 { build_real (TREE_TYPE (@0), max); }))))))))))
/* If this is a comparison of a real constant with a PLUS_EXPR
or a MINUS_EXPR of a real constant, we can convert it into a
(if (! HONOR_NANS (@0))
(cmp @0 @1))))))
+/* Optimize various special cases of (FTYPE) N CMP (FTYPE) M. */
+(for cmp (lt le eq ne ge gt unordered ordered unlt unle ungt unge uneq ltgt)
+ icmp (lt le eq ne ge gt unordered ordered lt le gt ge eq ne)
+ (simplify
+ (cmp (float@0 @1) (float @2))
+ (if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (@0))
+ && ! DECIMAL_FLOAT_TYPE_P (TREE_TYPE (@0)))
+ (with
+ {
+ format_helper fmt (REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (@0))));
+ tree type1 = TREE_TYPE (@1);
+ bool type1_signed_p = TYPE_SIGN (type1) == SIGNED;
+ tree type2 = TREE_TYPE (@2);
+ bool type2_signed_p = TYPE_SIGN (type2) == SIGNED;
+ }
+ (if (fmt.can_represent_integral_type_p (type1)
+ && fmt.can_represent_integral_type_p (type2))
+ (if (cmp == ORDERED_EXPR || cmp == UNORDERED_EXPR)
+ { constant_boolean_node (cmp == ORDERED_EXPR, type); }
+ (if (TYPE_PRECISION (type1) > TYPE_PRECISION (type2)
+ && type1_signed_p >= type2_signed_p)
+ (icmp @1 (convert @2))
+ (if (TYPE_PRECISION (type1) < TYPE_PRECISION (type2)
+ && type1_signed_p <= type2_signed_p)
+ (icmp (convert:type2 @1) @2)
+ (if (TYPE_PRECISION (type1) == TYPE_PRECISION (type2)
+ && type1_signed_p == type2_signed_p)
+ (icmp @1 @2))))))))))
+
/* Optimize various special cases of (FTYPE) N CMP CST. */
(for cmp (lt le eq ne ge gt)
icmp (le le eq ne ge ge)
(with
{
tree itype = TREE_TYPE (@0);
- signop isign = TYPE_SIGN (itype);
format_helper fmt (REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (@1))));
const REAL_VALUE_TYPE *cst = TREE_REAL_CST_PTR (@1);
/* Be careful to preserve any potential exceptions due to
bool exception_p
= real_isnan (cst) && (cst->signalling
|| (cmp != EQ_EXPR && cmp != NE_EXPR));
- /* INT?_MIN is power-of-two so it takes
- only one mantissa bit. */
- bool signed_p = isign == SIGNED;
- bool itype_fits_ftype_p
- = TYPE_PRECISION (itype) - signed_p <= significand_size (fmt);
}
/* TODO: allow non-fitting itype and SNaNs when
-fno-trapping-math. */
- (if (itype_fits_ftype_p && ! exception_p)
+ (if (fmt.can_represent_integral_type_p (itype) && ! exception_p)
(with
{
+ signop isign = TYPE_SIGN (itype);
REAL_VALUE_TYPE imin, imax;
real_from_integer (&imin, fmt, wi::min_value (itype), isign);
real_from_integer (&imax, fmt, wi::max_value (itype), isign);
else
real_trunc (&icst, fmt, cst);
- bool cst_int_p = real_identical (&icst, cst);
+ bool cst_int_p = !real_isnan (cst) && real_identical (&icst, cst);
bool overflow_p = false;
wide_int icst_val
(FTYPE) N == CST -> 0
(FTYPE) N != CST -> 1. */
(if (cmp == EQ_EXPR || cmp == NE_EXPR)
- { constant_boolean_node (cmp == NE_EXPR, type); })
+ { constant_boolean_node (cmp == NE_EXPR, type); })
/* Otherwise replace with sensible integer constant. */
(with
{
(simplify
(cmp (exact_div @0 @1) INTEGER_CST@2)
(if (!integer_zerop (@1))
- (if (wi::eq_p (@2, 0))
+ (if (wi::to_wide (@2) == 0)
(cmp @0 @2)
(if (TREE_CODE (@1) == INTEGER_CST)
(with
{
- bool ovf;
- wide_int prod = wi::mul (@2, @1, TYPE_SIGN (TREE_TYPE (@1)), &ovf);
+ wi::overflow_type ovf;
+ wide_int prod = wi::mul (wi::to_wide (@2), wi::to_wide (@1),
+ TYPE_SIGN (TREE_TYPE (@1)), &ovf);
}
(if (ovf)
{ constant_boolean_node (cmp == NE_EXPR, type); }
(for cmp (lt le gt ge)
(simplify
(cmp (exact_div @0 INTEGER_CST@1) INTEGER_CST@2)
- (if (wi::gt_p (@1, 0, TYPE_SIGN (TREE_TYPE (@1))))
+ (if (wi::gt_p (wi::to_wide (@1), 0, TYPE_SIGN (TREE_TYPE (@1))))
(with
{
- bool ovf;
- wide_int prod = wi::mul (@2, @1, TYPE_SIGN (TREE_TYPE (@1)), &ovf);
+ wi::overflow_type ovf;
+ wide_int prod = wi::mul (wi::to_wide (@2), wi::to_wide (@1),
+ TYPE_SIGN (TREE_TYPE (@1)), &ovf);
}
(if (ovf)
- { constant_boolean_node (wi::lt_p (@2, 0, TYPE_SIGN (TREE_TYPE (@2)))
+ { constant_boolean_node (wi::lt_p (wi::to_wide (@2), 0,
+ TYPE_SIGN (TREE_TYPE (@2)))
!= (cmp == LT_EXPR || cmp == LE_EXPR), type); }
(cmp @0 { wide_int_to_tree (TREE_TYPE (@0), prod); }))))))
+/* Fold (size_t)(A /[ex] B) CMP C to (size_t)A CMP (size_t)B * C or A CMP' 0.
+
+ For small C (less than max/B), this is (size_t)A CMP (size_t)B * C.
+ For large C (more than min/B+2^size), this is also true, with the
+ multiplication computed modulo 2^size.
+ For intermediate C, this just tests the sign of A. */
+(for cmp (lt le gt ge)
+ cmp2 (ge ge lt lt)
+ (simplify
+ (cmp (convert (exact_div @0 INTEGER_CST@1)) INTEGER_CST@2)
+ (if (tree_nop_conversion_p (TREE_TYPE (@0), TREE_TYPE (@2))
+ && TYPE_UNSIGNED (TREE_TYPE (@2)) && !TYPE_UNSIGNED (TREE_TYPE (@0))
+ && wi::gt_p (wi::to_wide (@1), 0, TYPE_SIGN (TREE_TYPE (@1))))
+ (with
+ {
+ tree utype = TREE_TYPE (@2);
+ wide_int denom = wi::to_wide (@1);
+ wide_int right = wi::to_wide (@2);
+ wide_int smax = wi::sdiv_trunc (wi::max_value (TREE_TYPE (@0)), denom);
+ wide_int smin = wi::sdiv_trunc (wi::min_value (TREE_TYPE (@0)), denom);
+ bool small = wi::leu_p (right, smax);
+ bool large = wi::geu_p (right, smin);
+ }
+ (if (small || large)
+ (cmp (convert:utype @0) (mult @2 (convert @1)))
+ (cmp2 @0 { build_zero_cst (TREE_TYPE (@0)); }))))))
+
/* Unordered tests if either argument is a NaN. */
(simplify
(bit_ior (unordered @0 @0) (unordered @1 @1))
(op (abs @0) zerop@1)
(op @0 @1)))
-/* From fold_sign_changed_comparison and fold_widened_comparison. */
+/* From fold_sign_changed_comparison and fold_widened_comparison.
+ FIXME: the lack of symmetry is disturbing. */
(for cmp (simple_comparison)
(simplify
(cmp (convert@0 @00) (convert?@1 @10))
/* Disable this optimization if we're casting a function pointer
type on targets that require function pointer canonicalization. */
&& !(targetm.have_canonicalize_funcptr_for_compare ()
- && TREE_CODE (TREE_TYPE (@00)) == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (TREE_TYPE (@00))) == FUNCTION_TYPE)
+ && ((POINTER_TYPE_P (TREE_TYPE (@00))
+ && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (TREE_TYPE (@00))))
+ || (POINTER_TYPE_P (TREE_TYPE (@10))
+ && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (TREE_TYPE (@10))))))
&& single_use (@0))
(if (TYPE_PRECISION (TREE_TYPE (@00)) == TYPE_PRECISION (TREE_TYPE (@0))
&& (TREE_CODE (@10) == INTEGER_CST
- || (@1 != @10 && types_match (TREE_TYPE (@10), TREE_TYPE (@00))))
+ || @1 != @10)
&& (TYPE_UNSIGNED (TREE_TYPE (@00)) == TYPE_UNSIGNED (TREE_TYPE (@0))
|| cmp == NE_EXPR
|| cmp == EQ_EXPR)
- && (POINTER_TYPE_P (TREE_TYPE (@00)) == POINTER_TYPE_P (TREE_TYPE (@0))))
+ && !POINTER_TYPE_P (TREE_TYPE (@00)))
/* ??? The special-casing of INTEGER_CST conversion was in the original
code and here to avoid a spurious overflow flag on the resulting
constant which fold_convert produces. */
(simplify
(cmp (convert?@3 (bit_ior @0 INTEGER_CST@1)) INTEGER_CST@2)
(if (tree_nop_conversion_p (TREE_TYPE (@3), TREE_TYPE (@0))
- && wi::bit_and_not (@1, @2) != 0)
+ && wi::bit_and_not (wi::to_wide (@1), wi::to_wide (@2)) != 0)
{ constant_boolean_node (cmp == NE_EXPR, type); }))
/* (X ^ Y) == 0 becomes X == Y, and (X ^ Y) != 0 becomes X != Y. */
(simplify
(cmp (bit_and@2 @0 integer_pow2p@1) @1)
(icmp @2 { build_zero_cst (TREE_TYPE (@0)); })))
-
+
/* If we have (A & C) != 0 ? D : 0 where C and D are powers of 2,
convert this into a shift followed by ANDing with D. */
(simplify
(cond
(ne (bit_and @0 integer_pow2p@1) integer_zerop)
- integer_pow2p@2 integer_zerop)
- (with {
- int shift = wi::exact_log2 (@2) - wi::exact_log2 (@1);
- }
- (if (shift > 0)
- (bit_and
- (lshift (convert @0) { build_int_cst (integer_type_node, shift); }) @2)
- (bit_and
- (convert (rshift @0 { build_int_cst (integer_type_node, -shift); })) @2))))
+ INTEGER_CST@2 integer_zerop)
+ (if (integer_pow2p (@2))
+ (with {
+ int shift = (wi::exact_log2 (wi::to_wide (@2))
+ - wi::exact_log2 (wi::to_wide (@1)));
+ }
+ (if (shift > 0)
+ (bit_and
+ (lshift (convert @0) { build_int_cst (integer_type_node, shift); }) @2)
+ (bit_and
+ (convert (rshift @0 { build_int_cst (integer_type_node, -shift); }))
+ @2)))))
/* If we have (A & C) != 0 where C is the sign bit of A, convert
this into A < 0. Similarly for (A & C) == 0 into A >= 0. */
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
&& type_has_mode_precision_p (TREE_TYPE (@0))
&& element_precision (@2) >= element_precision (@0)
- && wi::only_sign_bit_p (@1, element_precision (@0)))
+ && wi::only_sign_bit_p (wi::to_wide (@1), element_precision (@0)))
(with { tree stype = signed_type_for (TREE_TYPE (@0)); }
(ncmp (convert:stype @0) { build_zero_cst (stype); })))))
(simplify
(cond
(lt @0 integer_zerop)
- integer_pow2p@1 integer_zerop)
- (if (!TYPE_UNSIGNED (TREE_TYPE (@0)))
+ INTEGER_CST@1 integer_zerop)
+ (if (integer_pow2p (@1)
+ && !TYPE_UNSIGNED (TREE_TYPE (@0)))
(with {
- int shift = element_precision (@0) - wi::exact_log2 (@1) - 1;
+ int shift = element_precision (@0) - wi::exact_log2 (wi::to_wide (@1)) - 1;
}
(if (shift >= 0)
(bit_and
(cmp (convert1?@2 addr@0) (convert2? addr@1))
(with
{
- HOST_WIDE_INT off0, off1;
+ poly_int64 off0, off1;
tree base0 = get_addr_base_and_unit_offset (TREE_OPERAND (@0, 0), &off0);
tree base1 = get_addr_base_and_unit_offset (TREE_OPERAND (@1, 0), &off1);
if (base0 && TREE_CODE (base0) == MEM_REF)
{
- off0 += mem_ref_offset (base0).to_short_addr ();
+ off0 += mem_ref_offset (base0).force_shwi ();
base0 = TREE_OPERAND (base0, 0);
}
if (base1 && TREE_CODE (base1) == MEM_REF)
{
- off1 += mem_ref_offset (base1).to_short_addr ();
+ off1 += mem_ref_offset (base1).force_shwi ();
base1 = TREE_OPERAND (base1, 0);
}
}
|| TREE_CODE (base1) == SSA_NAME
|| TREE_CODE (base1) == STRING_CST))
equal = (base0 == base1);
+ if (equal == 0)
+ {
+ HOST_WIDE_INT ioff0 = -1, ioff1 = -1;
+ off0.is_constant (&ioff0);
+ off1.is_constant (&ioff1);
+ if ((DECL_P (base0) && TREE_CODE (base1) == STRING_CST)
+ || (TREE_CODE (base0) == STRING_CST && DECL_P (base1))
+ || (TREE_CODE (base0) == STRING_CST
+ && TREE_CODE (base1) == STRING_CST
+ && ioff0 >= 0 && ioff1 >= 0
+ && ioff0 < TREE_STRING_LENGTH (base0)
+ && ioff1 < TREE_STRING_LENGTH (base1)
+ /* This is a too conservative test that the STRING_CSTs
+ will not end up being string-merged. */
+ && strncmp (TREE_STRING_POINTER (base0) + ioff0,
+ TREE_STRING_POINTER (base1) + ioff1,
+ MIN (TREE_STRING_LENGTH (base0) - ioff0,
+ TREE_STRING_LENGTH (base1) - ioff1)) != 0))
+ ;
+ else if (!DECL_P (base0) || !DECL_P (base1))
+ equal = 2;
+ else if (cmp != EQ_EXPR && cmp != NE_EXPR)
+ equal = 2;
+ /* If this is a pointer comparison, ignore for now even
+ valid equalities where one pointer is the offset zero
+ of one object and the other to one past end of another one. */
+ else if (!INTEGRAL_TYPE_P (TREE_TYPE (@2)))
+ ;
+ /* Assume that automatic variables can't be adjacent to global
+ variables. */
+ else if (is_global_var (base0) != is_global_var (base1))
+ ;
+ else
+ {
+ tree sz0 = DECL_SIZE_UNIT (base0);
+ tree sz1 = DECL_SIZE_UNIT (base1);
+ /* If sizes are unknown, e.g. VLA or not representable,
+ punt. */
+ if (!tree_fits_poly_int64_p (sz0)
+ || !tree_fits_poly_int64_p (sz1))
+ equal = 2;
+ else
+ {
+ poly_int64 size0 = tree_to_poly_int64 (sz0);
+ poly_int64 size1 = tree_to_poly_int64 (sz1);
+ /* If one offset is pointing (or could be) to the beginning
+ of one object and the other is pointing to one past the
+ last byte of the other object, punt. */
+ if (maybe_eq (off0, 0) && maybe_eq (off1, size1))
+ equal = 2;
+ else if (maybe_eq (off1, 0) && maybe_eq (off0, size0))
+ equal = 2;
+ /* If both offsets are the same, there are some cases
+ we know that are ok. Either if we know they aren't
+ zero, or if we know both sizes are no zero. */
+ if (equal == 2
+ && known_eq (off0, off1)
+ && (known_ne (off0, 0)
+ || (known_ne (size0, 0) && known_ne (size1, 0))))
+ equal = 0;
+ }
+ }
+ }
}
- (if (equal == 1)
+ (if (equal == 1
+ && (cmp == EQ_EXPR || cmp == NE_EXPR
+ /* If the offsets are equal we can ignore overflow. */
+ || known_eq (off0, off1)
+ || TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
+ /* Or if we compare using pointers to decls or strings. */
+ || (POINTER_TYPE_P (TREE_TYPE (@2))
+ && (DECL_P (base0) || TREE_CODE (base0) == STRING_CST))))
(switch
- (if (cmp == EQ_EXPR)
- { constant_boolean_node (off0 == off1, type); })
- (if (cmp == NE_EXPR)
- { constant_boolean_node (off0 != off1, type); })
- (if (cmp == LT_EXPR)
- { constant_boolean_node (off0 < off1, type); })
- (if (cmp == LE_EXPR)
- { constant_boolean_node (off0 <= off1, type); })
- (if (cmp == GE_EXPR)
- { constant_boolean_node (off0 >= off1, type); })
- (if (cmp == GT_EXPR)
- { constant_boolean_node (off0 > off1, type); }))
- (if (equal == 0
- && DECL_P (base0) && DECL_P (base1)
- /* If we compare this as integers require equal offset. */
- && (!INTEGRAL_TYPE_P (TREE_TYPE (@2))
- || off0 == off1))
- (switch
- (if (cmp == EQ_EXPR)
- { constant_boolean_node (false, type); })
- (if (cmp == NE_EXPR)
- { constant_boolean_node (true, type); })))))))))
+ (if (cmp == EQ_EXPR && (known_eq (off0, off1) || known_ne (off0, off1)))
+ { constant_boolean_node (known_eq (off0, off1), type); })
+ (if (cmp == NE_EXPR && (known_eq (off0, off1) || known_ne (off0, off1)))
+ { constant_boolean_node (known_ne (off0, off1), type); })
+ (if (cmp == LT_EXPR && (known_lt (off0, off1) || known_ge (off0, off1)))
+ { constant_boolean_node (known_lt (off0, off1), type); })
+ (if (cmp == LE_EXPR && (known_le (off0, off1) || known_gt (off0, off1)))
+ { constant_boolean_node (known_le (off0, off1), type); })
+ (if (cmp == GE_EXPR && (known_ge (off0, off1) || known_lt (off0, off1)))
+ { constant_boolean_node (known_ge (off0, off1), type); })
+ (if (cmp == GT_EXPR && (known_gt (off0, off1) || known_le (off0, off1)))
+ { constant_boolean_node (known_gt (off0, off1), type); }))
+ (if (equal == 0)
+ (switch
+ (if (cmp == EQ_EXPR)
+ { constant_boolean_node (false, type); })
+ (if (cmp == NE_EXPR)
+ { constant_boolean_node (true, type); })))))))))
/* Simplify pointer equality compares using PTA. */
(for neeq (ne eq)
(neeq @0 @1)
(if (POINTER_TYPE_P (TREE_TYPE (@0))
&& ptrs_compare_unequal (@0, @1))
- { neeq == EQ_EXPR ? boolean_false_node : boolean_true_node; })))
+ { constant_boolean_node (neeq != EQ_EXPR, type); })))
/* PR70920: Transform (intptr_t)x eq/ne CST to x eq/ne (typeof x) CST.
and (typeof ptr_cst) x eq/ne ptr_cst to x eq/ne (typeof x) CST.
(for cmp (ne eq)
(simplify
(cmp (convert @0) INTEGER_CST@1)
- (if ((POINTER_TYPE_P (TREE_TYPE (@0)) && !FUNC_OR_METHOD_TYPE_P (TREE_TYPE (TREE_TYPE (@0)))
- && INTEGRAL_TYPE_P (TREE_TYPE (@1)))
- || (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && POINTER_TYPE_P (TREE_TYPE (@1))
- && !FUNC_OR_METHOD_TYPE_P (TREE_TYPE (TREE_TYPE (@1)))))
+ (if (((POINTER_TYPE_P (TREE_TYPE (@0))
+ && !FUNC_OR_METHOD_TYPE_P (TREE_TYPE (TREE_TYPE (@0)))
+ && INTEGRAL_TYPE_P (TREE_TYPE (@1)))
+ || (INTEGRAL_TYPE_P (TREE_TYPE (@0))
+ && POINTER_TYPE_P (TREE_TYPE (@1))
+ && !FUNC_OR_METHOD_TYPE_P (TREE_TYPE (TREE_TYPE (@1)))))
+ && TYPE_PRECISION (TREE_TYPE (@0)) == TYPE_PRECISION (TREE_TYPE (@1)))
(cmp @0 (convert @1)))))
/* Non-equality compare simplifications from fold_binary */
/* Comparisons with the highest or lowest possible integer of
the specified precision will have known values. */
(simplify
- (cmp (convert?@2 @0) INTEGER_CST@1)
- (if ((INTEGRAL_TYPE_P (TREE_TYPE (@1)) || POINTER_TYPE_P (TREE_TYPE (@1)))
+ (cmp (convert?@2 @0) uniform_integer_cst_p@1)
+ (if ((INTEGRAL_TYPE_P (TREE_TYPE (@1))
+ || POINTER_TYPE_P (TREE_TYPE (@1))
+ || VECTOR_INTEGER_TYPE_P (TREE_TYPE (@1)))
&& tree_nop_conversion_p (TREE_TYPE (@2), TREE_TYPE (@0)))
(with
{
- tree arg1_type = TREE_TYPE (@1);
+ tree cst = uniform_integer_cst_p (@1);
+ tree arg1_type = TREE_TYPE (cst);
unsigned int prec = TYPE_PRECISION (arg1_type);
wide_int max = wi::max_value (arg1_type);
wide_int signed_max = wi::max_value (prec, SIGNED);
wide_int min = wi::min_value (arg1_type);
}
(switch
- (if (wi::eq_p (@1, max))
+ (if (wi::to_wide (cst) == max)
(switch
(if (cmp == GT_EXPR)
{ constant_boolean_node (false, type); })
{ constant_boolean_node (true, type); })
(if (cmp == LT_EXPR)
(ne @2 @1))))
- (if (wi::eq_p (@1, min))
+ (if (wi::to_wide (cst) == min)
(switch
(if (cmp == LT_EXPR)
{ constant_boolean_node (false, type); })
{ constant_boolean_node (true, type); })
(if (cmp == GT_EXPR)
(ne @2 @1))))
- (if (wi::eq_p (@1, max - 1))
+ (if (wi::to_wide (cst) == max - 1)
(switch
(if (cmp == GT_EXPR)
- (eq @2 { wide_int_to_tree (TREE_TYPE (@1), wi::add (@1, 1)); }))
+ (eq @2 { build_uniform_cst (TREE_TYPE (@1),
+ wide_int_to_tree (TREE_TYPE (cst),
+ wi::to_wide (cst)
+ + 1)); }))
(if (cmp == LE_EXPR)
- (ne @2 { wide_int_to_tree (TREE_TYPE (@1), wi::add (@1, 1)); }))))
- (if (wi::eq_p (@1, min + 1))
+ (ne @2 { build_uniform_cst (TREE_TYPE (@1),
+ wide_int_to_tree (TREE_TYPE (cst),
+ wi::to_wide (cst)
+ + 1)); }))))
+ (if (wi::to_wide (cst) == min + 1)
(switch
(if (cmp == GE_EXPR)
- (ne @2 { wide_int_to_tree (TREE_TYPE (@1), wi::sub (@1, 1)); }))
+ (ne @2 { build_uniform_cst (TREE_TYPE (@1),
+ wide_int_to_tree (TREE_TYPE (cst),
+ wi::to_wide (cst)
+ - 1)); }))
(if (cmp == LT_EXPR)
- (eq @2 { wide_int_to_tree (TREE_TYPE (@1), wi::sub (@1, 1)); }))))
- (if (wi::eq_p (@1, signed_max)
+ (eq @2 { build_uniform_cst (TREE_TYPE (@1),
+ wide_int_to_tree (TREE_TYPE (cst),
+ wi::to_wide (cst)
+ - 1)); }))))
+ (if (wi::to_wide (cst) == signed_max
&& TYPE_UNSIGNED (arg1_type)
/* We will flip the signedness of the comparison operator
associated with the mode of @1, so the sign bit is
/* The following case also applies to X < signed_max+1
and X >= signed_max+1 because previous transformations. */
(if (cmp == LE_EXPR || cmp == GT_EXPR)
- (with { tree st = signed_type_for (arg1_type); }
- (if (cmp == LE_EXPR)
- (ge (convert:st @0) { build_zero_cst (st); })
- (lt (convert:st @0) { build_zero_cst (st); }))))))))))
-
+ (with { tree st = signed_type_for (TREE_TYPE (@1)); }
+ (switch
+ (if (cst == @1 && cmp == LE_EXPR)
+ (ge (convert:st @0) { build_zero_cst (st); }))
+ (if (cst == @1 && cmp == GT_EXPR)
+ (lt (convert:st @0) { build_zero_cst (st); }))
+ (if (cmp == LE_EXPR)
+ (ge (view_convert:st @0) { build_zero_cst (st); }))
+ (if (cmp == GT_EXPR)
+ (lt (view_convert:st @0) { build_zero_cst (st); })))))))))))
+
(for cmp (unordered ordered unlt unle ungt unge uneq ltgt)
/* If the second operand is NaN, the result is constant. */
(simplify
(cmp:c (plus@2 @0 INTEGER_CST@1) @0)
(if (TYPE_UNSIGNED (TREE_TYPE (@0))
&& TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))
- && wi::ne_p (@1, 0)
+ && wi::to_wide (@1) != 0
&& single_use (@2))
- (out @0 { wide_int_to_tree (TREE_TYPE (@0), wi::max_value
- (TYPE_PRECISION (TREE_TYPE (@0)), UNSIGNED) - @1); }))))
+ (with { unsigned int prec = TYPE_PRECISION (TREE_TYPE (@0)); }
+ (out @0 { wide_int_to_tree (TREE_TYPE (@0),
+ wi::max_value (prec, UNSIGNED)
+ - wi::to_wide (@1)); })))))
/* To detect overflow in unsigned A - B, A < B is simpler than A - B > A.
However, the detection logic for SUB_OVERFLOW in tree-ssa-math-opts.c
(if (flag_unsafe_math_optimizations)
/* Simplify sqrt(x) * sqrt(x) -> x. */
(simplify
- (mult (SQRT@1 @0) @1)
+ (mult (SQRT_ALL@1 @0) @1)
(if (!HONOR_SNANS (type))
@0))
(rdiv @2 @1))
(rdiv (op @0 @2) @1)))
+ (for cmp (lt le gt ge)
+ neg_cmp (gt ge lt le)
+ /* Simplify (x * C1) cmp C2 -> x cmp (C2 / C1), where C1 != 0. */
+ (simplify
+ (cmp (mult @0 REAL_CST@1) REAL_CST@2)
+ (with
+ { tree tem = const_binop (RDIV_EXPR, type, @2, @1); }
+ (if (tem
+ && !(REAL_VALUE_ISINF (TREE_REAL_CST (tem))
+ || (real_zerop (tem) && !real_zerop (@1))))
+ (switch
+ (if (real_less (&dconst0, TREE_REAL_CST_PTR (@1)))
+ (cmp @0 { tem; }))
+ (if (real_less (TREE_REAL_CST_PTR (@1), &dconst0))
+ (neg_cmp @0 { tem; })))))))
+
/* Simplify sqrt(x) * sqrt(y) -> sqrt(x*y). */
(for root (SQRT CBRT)
(simplify
(logs (pows @0 @1))
(mult @1 (logs @0))))
- /* pow(C,x) -> exp(log(C)*x) if C > 0. */
+ /* pow(C,x) -> exp(log(C)*x) if C > 0,
+ or if C is a positive power of 2,
+ pow(C,x) -> exp2(log2(C)*x). */
+#if GIMPLE
(for pows (POW)
exps (EXP)
logs (LOG)
+ exp2s (EXP2)
+ log2s (LOG2)
(simplify
(pows REAL_CST@0 @1)
- (if (real_compare (GT_EXPR, TREE_REAL_CST_PTR (@0), &dconst0)
- && real_isfinite (TREE_REAL_CST_PTR (@0)))
- (exps (mult (logs @0) @1)))))
+ (if (real_compare (GT_EXPR, TREE_REAL_CST_PTR (@0), &dconst0)
+ && real_isfinite (TREE_REAL_CST_PTR (@0))
+ /* As libmvec doesn't have a vectorized exp2, defer optimizing
+ the use_exp2 case until after vectorization. It seems actually
+ beneficial for all constants to postpone this until later,
+ because exp(log(C)*x), while faster, will have worse precision
+ and if x folds into a constant too, that is unnecessary
+ pessimization. */
+ && canonicalize_math_after_vectorization_p ())
+ (with {
+ const REAL_VALUE_TYPE *const value = TREE_REAL_CST_PTR (@0);
+ bool use_exp2 = false;
+ if (targetm.libc_has_function (function_c99_misc)
+ && value->cl == rvc_normal)
+ {
+ REAL_VALUE_TYPE frac_rvt = *value;
+ SET_REAL_EXP (&frac_rvt, 1);
+ if (real_equal (&frac_rvt, &dconst1))
+ use_exp2 = true;
+ }
+ }
+ (if (!use_exp2)
+ (if (optimize_pow_to_exp (@0, @1))
+ (exps (mult (logs @0) @1)))
+ (exp2s (mult (log2s @0) @1)))))))
+#endif
+
+ /* pow(C,x)*expN(y) -> expN(logN(C)*x+y) if C > 0. */
+ (for pows (POW)
+ exps (EXP EXP2 EXP10 POW10)
+ logs (LOG LOG2 LOG10 LOG10)
+ (simplify
+ (mult:c (pows:s REAL_CST@0 @1) (exps:s @2))
+ (if (real_compare (GT_EXPR, TREE_REAL_CST_PTR (@0), &dconst0)
+ && real_isfinite (TREE_REAL_CST_PTR (@0)))
+ (exps (plus (mult (logs @0) @1) @2)))))
(for sqrts (SQRT)
cbrts (CBRT)
(tans (atans @0))
@0)))
+ /* Simplify sin(atan(x)) -> x / sqrt(x*x + 1). */
+ (for sins (SIN)
+ atans (ATAN)
+ sqrts (SQRT)
+ copysigns (COPYSIGN)
+ (simplify
+ (sins (atans:s @0))
+ (with
+ {
+ REAL_VALUE_TYPE r_cst;
+ build_sinatan_real (&r_cst, type);
+ tree t_cst = build_real (type, r_cst);
+ tree t_one = build_one_cst (type);
+ }
+ (if (SCALAR_FLOAT_TYPE_P (type))
+ (cond (lt (abs @0) { t_cst; })
+ (rdiv @0 (sqrts (plus (mult @0 @0) { t_one; })))
+ (copysigns { t_one; } @0))))))
+
+/* Simplify cos(atan(x)) -> 1 / sqrt(x*x + 1). */
+ (for coss (COS)
+ atans (ATAN)
+ sqrts (SQRT)
+ copysigns (COPYSIGN)
+ (simplify
+ (coss (atans:s @0))
+ (with
+ {
+ REAL_VALUE_TYPE r_cst;
+ build_sinatan_real (&r_cst, type);
+ tree t_cst = build_real (type, r_cst);
+ tree t_one = build_one_cst (type);
+ tree t_zero = build_zero_cst (type);
+ }
+ (if (SCALAR_FLOAT_TYPE_P (type))
+ (cond (lt (abs @0) { t_cst; })
+ (rdiv { t_one; } (sqrts (plus (mult @0 @0) { t_one; })))
+ (copysigns { t_zero; } @0))))))
+
+ (if (!flag_errno_math)
+ /* Simplify sinh(atanh(x)) -> x / sqrt((1 - x)*(1 + x)). */
+ (for sinhs (SINH)
+ atanhs (ATANH)
+ sqrts (SQRT)
+ (simplify
+ (sinhs (atanhs:s @0))
+ (with { tree t_one = build_one_cst (type); }
+ (rdiv @0 (sqrts (mult (minus { t_one; } @0) (plus { t_one; } @0)))))))
+
+ /* Simplify cosh(atanh(x)) -> 1 / sqrt((1 - x)*(1 + x)) */
+ (for coshs (COSH)
+ atanhs (ATANH)
+ sqrts (SQRT)
+ (simplify
+ (coshs (atanhs:s @0))
+ (with { tree t_one = build_one_cst (type); }
+ (rdiv { t_one; } (sqrts (mult (minus { t_one; } @0) (plus { t_one; } @0))))))))
+
/* cabs(x+0i) or cabs(0+xi) -> abs(x). */
(simplify
(CABS (complex:C @0 real_zerop@1))
(abs @0))
/* trunc(trunc(x)) -> trunc(x), etc. */
-(for fns (TRUNC FLOOR CEIL ROUND NEARBYINT RINT)
+(for fns (TRUNC_ALL FLOOR_ALL CEIL_ALL ROUND_ALL NEARBYINT_ALL RINT_ALL)
(simplify
(fns (fns @0))
(fns @0)))
/* f(x) -> x if x is integer valued and f does nothing for such values. */
-(for fns (TRUNC FLOOR CEIL ROUND NEARBYINT RINT)
+(for fns (TRUNC_ALL FLOOR_ALL CEIL_ALL ROUND_ALL NEARBYINT_ALL RINT_ALL)
(simplify
(fns integer_valued_real_p@0)
@0))
(simplify
/* copysign(x,x) -> x. */
- (COPYSIGN @0 @0)
+ (COPYSIGN_ALL @0 @0)
@0)
(simplify
/* copysign(x,y) -> fabs(x) if y is nonnegative. */
- (COPYSIGN @0 tree_expr_nonnegative_p@1)
+ (COPYSIGN_ALL @0 tree_expr_nonnegative_p@1)
(abs @0))
(for scale (LDEXP SCALBN SCALBLN)
(if (canonicalize_math_p ())
/* floor(x) -> trunc(x) if x is nonnegative. */
- (for floors (FLOOR)
- truncs (TRUNC)
+ (for floors (FLOOR_ALL)
+ truncs (TRUNC_ALL)
(simplify
(floors tree_expr_nonnegative_p@0)
(truncs @0))))
(POWI @0 INTEGER_CST@1)
(switch
/* powi(x,0) -> 1. */
- (if (wi::eq_p (@1, 0))
+ (if (wi::to_wide (@1) == 0)
{ build_real (type, dconst1); })
/* powi(x,1) -> x. */
- (if (wi::eq_p (@1, 1))
+ (if (wi::to_wide (@1) == 1)
@0)
/* powi(x,-1) -> 1/x. */
- (if (wi::eq_p (@1, -1))
+ (if (wi::to_wide (@1) == -1)
(rdiv { build_real (type, dconst1); } @0))))
-/* Narrowing of arithmetic and logical operations.
+/* Narrowing of arithmetic and logical operations.
These are conceptually similar to the transformations performed for
the C/C++ front-ends by shorten_binary_op and shorten_compare. Long
&& types_match (@0, @1)
&& (tree_int_cst_min_precision (@4, TYPE_SIGN (TREE_TYPE (@0)))
<= TYPE_PRECISION (TREE_TYPE (@0)))
- && (wi::bit_and (@4, wi::mask (TYPE_PRECISION (TREE_TYPE (@0)),
- true, TYPE_PRECISION (type))) == 0))
+ && (wi::to_wide (@4)
+ & wi::mask (TYPE_PRECISION (TREE_TYPE (@0)),
+ true, TYPE_PRECISION (type))) == 0)
(if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0)))
(with { tree ntype = TREE_TYPE (@0); }
(convert (bit_and (op @0 @1) (convert:ntype @4))))
(convert (bit_and (op (convert:utype @0) (convert:utype @1))
(convert:utype @4))))))))
-/* Transform (@0 < @1 and @0 < @2) to use min,
+/* Transform (@0 < @1 and @0 < @2) to use min,
(@0 > @1 and @0 > @2) to use max */
-(for op (lt le gt ge)
- ext (min min max max)
+(for logic (bit_and bit_and bit_and bit_and bit_ior bit_ior bit_ior bit_ior)
+ op (lt le gt ge lt le gt ge )
+ ext (min min max max max max min min )
(simplify
- (bit_and (op:cs @0 @1) (op:cs @0 @2))
+ (logic (op:cs @0 @1) (op:cs @0 @2))
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
&& TREE_CODE (@0) != INTEGER_CST)
(op @0 (ext @1 @2)))))
&& TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)))
{ constant_boolean_node (cmp == NE_EXPR, type); }
(if (single_use (@3))
- (cmp @0 { res; }))))))))
+ (cmp @0 { TREE_OVERFLOW (res)
+ ? drop_tree_overflow (res) : res; }))))))))
(for cmp (lt le gt ge)
(for op (plus minus)
rop (minus plus)
WARN_STRICT_OVERFLOW_CONDITIONAL);
bool less = cmp == LE_EXPR || cmp == LT_EXPR;
/* wi::ges_p (@2, 0) should be sufficient for a signed type. */
- bool ovf_high = wi::lt_p (@1, 0, TYPE_SIGN (TREE_TYPE (@1)))
+ bool ovf_high = wi::lt_p (wi::to_wide (@1), 0,
+ TYPE_SIGN (TREE_TYPE (@1)))
!= (op == MINUS_EXPR);
constant_boolean_node (less == ovf_high, type);
}
/* Canonicalizations of BIT_FIELD_REFs. */
+(simplify
+ (BIT_FIELD_REF (BIT_FIELD_REF @0 @1 @2) @3 @4)
+ (BIT_FIELD_REF @0 @3 { const_binop (PLUS_EXPR, bitsizetype, @2, @4); }))
+
+(simplify
+ (BIT_FIELD_REF (view_convert @0) @1 @2)
+ (BIT_FIELD_REF @0 @1 @2))
+
+(simplify
+ (BIT_FIELD_REF @0 @1 integer_zerop)
+ (if (tree_int_cst_equal (@1, TYPE_SIZE (TREE_TYPE (@0))))
+ (view_convert @0)))
+
(simplify
(BIT_FIELD_REF @0 @1 @2)
(switch
(if (n != 0
&& (idx % width) == 0
&& (n % width) == 0
- && ((idx + n) / width) <= TYPE_VECTOR_SUBPARTS (TREE_TYPE (ctor)))
+ && known_le ((idx + n) / width,
+ TYPE_VECTOR_SUBPARTS (TREE_TYPE (ctor))))
(with
{
idx = idx / width;
n = n / width;
/* Constructor elements can be subvectors. */
- unsigned HOST_WIDE_INT k = 1;
+ poly_uint64 k = 1;
if (CONSTRUCTOR_NELTS (ctor) != 0)
{
tree cons_elem = TREE_TYPE (CONSTRUCTOR_ELT (ctor, 0)->value);
if (TREE_CODE (cons_elem) == VECTOR_TYPE)
k = TYPE_VECTOR_SUBPARTS (cons_elem);
}
+ unsigned HOST_WIDE_INT elt, count, const_k;
}
(switch
/* We keep an exact subset of the constructor elements. */
- (if ((idx % k) == 0 && (n % k) == 0)
+ (if (multiple_p (idx, k, &elt) && multiple_p (n, k, &count))
(if (CONSTRUCTOR_NELTS (ctor) == 0)
{ build_constructor (type, NULL); }
- (with
+ (if (count == 1)
+ (if (elt < CONSTRUCTOR_NELTS (ctor))
+ (view_convert { CONSTRUCTOR_ELT (ctor, elt)->value; })
+ { build_zero_cst (type); })
{
- idx /= k;
- n /= k;
- }
- (if (n == 1)
- (if (idx < CONSTRUCTOR_NELTS (ctor))
- { CONSTRUCTOR_ELT (ctor, idx)->value; }
- { build_zero_cst (type); })
- {
- vec<constructor_elt, va_gc> *vals;
- vec_alloc (vals, n);
- for (unsigned i = 0;
- i < n && idx + i < CONSTRUCTOR_NELTS (ctor); ++i)
- CONSTRUCTOR_APPEND_ELT (vals, NULL_TREE,
- CONSTRUCTOR_ELT (ctor, idx + i)->value);
- build_constructor (type, vals);
- }))))
+ vec<constructor_elt, va_gc> *vals;
+ vec_alloc (vals, count);
+ for (unsigned i = 0;
+ i < count && elt + i < CONSTRUCTOR_NELTS (ctor); ++i)
+ CONSTRUCTOR_APPEND_ELT (vals, NULL_TREE,
+ CONSTRUCTOR_ELT (ctor, elt + i)->value);
+ build_constructor (type, vals);
+ })))
/* The bitfield references a single constructor element. */
- (if (idx + n <= (idx / k + 1) * k)
+ (if (k.is_constant (&const_k)
+ && idx + n <= (idx / const_k + 1) * const_k)
(switch
- (if (CONSTRUCTOR_NELTS (ctor) <= idx / k)
+ (if (CONSTRUCTOR_NELTS (ctor) <= idx / const_k)
{ build_zero_cst (type); })
- (if (n == k)
- { CONSTRUCTOR_ELT (ctor, idx / k)->value; })
- (BIT_FIELD_REF { CONSTRUCTOR_ELT (ctor, idx / k)->value; }
- @1 { bitsize_int ((idx % k) * width); })))))))))
+ (if (n == const_k)
+ (view_convert { CONSTRUCTOR_ELT (ctor, idx / const_k)->value; }))
+ (BIT_FIELD_REF { CONSTRUCTOR_ELT (ctor, idx / const_k)->value; }
+ @1 { bitsize_int ((idx % const_k) * width); })))))))))
/* Simplify a bit extraction from a bit insertion for the cases with
the inserted element fully covering the extraction or the insertion
isize = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (@1)));
}
(switch
- (if (wi::leu_p (@ipos, @rpos)
- && wi::leu_p (wi::add (@rpos, @rsize), wi::add (@ipos, isize)))
+ (if (wi::leu_p (wi::to_wide (@ipos), wi::to_wide (@rpos))
+ && wi::leu_p (wi::to_wide (@rpos) + wi::to_wide (@rsize),
+ wi::to_wide (@ipos) + isize))
(BIT_FIELD_REF @1 @rsize { wide_int_to_tree (bitsizetype,
- wi::sub (@rpos, @ipos)); }))
- (if (wi::geu_p (@ipos, wi::add (@rpos, @rsize))
- || wi::geu_p (@rpos, wi::add (@ipos, isize)))
+ wi::to_wide (@rpos)
+ - wi::to_wide (@ipos)); }))
+ (if (wi::geu_p (wi::to_wide (@ipos),
+ wi::to_wide (@rpos) + wi::to_wide (@rsize))
+ || wi::geu_p (wi::to_wide (@rpos),
+ wi::to_wide (@ipos) + isize))
(BIT_FIELD_REF @0 @rsize @rpos)))))
+
+(if (canonicalize_math_after_vectorization_p ())
+ (for fmas (FMA)
+ (simplify
+ (fmas:c (negate @0) @1 @2)
+ (IFN_FNMA @0 @1 @2))
+ (simplify
+ (fmas @0 @1 (negate @2))
+ (IFN_FMS @0 @1 @2))
+ (simplify
+ (fmas:c (negate @0) @1 (negate @2))
+ (IFN_FNMS @0 @1 @2))
+ (simplify
+ (negate (fmas@3 @0 @1 @2))
+ (if (single_use (@3))
+ (IFN_FNMS @0 @1 @2))))
+
+ (simplify
+ (IFN_FMS:c (negate @0) @1 @2)
+ (IFN_FNMS @0 @1 @2))
+ (simplify
+ (IFN_FMS @0 @1 (negate @2))
+ (IFN_FMA @0 @1 @2))
+ (simplify
+ (IFN_FMS:c (negate @0) @1 (negate @2))
+ (IFN_FNMA @0 @1 @2))
+ (simplify
+ (negate (IFN_FMS@3 @0 @1 @2))
+ (if (single_use (@3))
+ (IFN_FNMA @0 @1 @2)))
+
+ (simplify
+ (IFN_FNMA:c (negate @0) @1 @2)
+ (IFN_FMA @0 @1 @2))
+ (simplify
+ (IFN_FNMA @0 @1 (negate @2))
+ (IFN_FNMS @0 @1 @2))
+ (simplify
+ (IFN_FNMA:c (negate @0) @1 (negate @2))
+ (IFN_FMS @0 @1 @2))
+ (simplify
+ (negate (IFN_FNMA@3 @0 @1 @2))
+ (if (single_use (@3))
+ (IFN_FMS @0 @1 @2)))
+
+ (simplify
+ (IFN_FNMS:c (negate @0) @1 @2)
+ (IFN_FMS @0 @1 @2))
+ (simplify
+ (IFN_FNMS @0 @1 (negate @2))
+ (IFN_FNMA @0 @1 @2))
+ (simplify
+ (IFN_FNMS:c (negate @0) @1 (negate @2))
+ (IFN_FMA @0 @1 @2))
+ (simplify
+ (negate (IFN_FNMS@3 @0 @1 @2))
+ (if (single_use (@3))
+ (IFN_FMA @0 @1 @2))))
+
+/* POPCOUNT simplifications. */
+(for popcount (BUILT_IN_POPCOUNT BUILT_IN_POPCOUNTL BUILT_IN_POPCOUNTLL
+ BUILT_IN_POPCOUNTIMAX)
+ /* popcount(X&1) is nop_expr(X&1). */
+ (simplify
+ (popcount @0)
+ (if (tree_nonzero_bits (@0) == 1)
+ (convert @0)))
+ /* popcount(X) + popcount(Y) is popcount(X|Y) when X&Y must be zero. */
+ (simplify
+ (plus (popcount:s @0) (popcount:s @1))
+ (if (wi::bit_and (tree_nonzero_bits (@0), tree_nonzero_bits (@1)) == 0)
+ (popcount (bit_ior @0 @1))))
+ /* popcount(X) == 0 is X == 0, and related (in)equalities. */
+ (for cmp (le eq ne gt)
+ rep (eq eq ne ne)
+ (simplify
+ (cmp (popcount @0) integer_zerop)
+ (rep @0 { build_zero_cst (TREE_TYPE (@0)); }))))
+
+/* Simplify:
+
+ a = a1 op a2
+ r = c ? a : b;
+
+ to:
+
+ r = c ? a1 op a2 : b;
+
+ if the target can do it in one go. This makes the operation conditional
+ on c, so could drop potentially-trapping arithmetic, but that's a valid
+ simplification if the result of the operation isn't needed.
+
+ Avoid speculatively generating a stand-alone vector comparison
+ on targets that might not support them. Any target implementing
+ conditional internal functions must support the same comparisons
+ inside and outside a VEC_COND_EXPR. */
+
+#if GIMPLE
+(for uncond_op (UNCOND_BINARY)
+ cond_op (COND_BINARY)
+ (simplify
+ (vec_cond @0 (view_convert? (uncond_op@4 @1 @2)) @3)
+ (with { tree op_type = TREE_TYPE (@4); }
+ (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+ && element_precision (type) == element_precision (op_type))
+ (view_convert (cond_op @0 @1 @2 (view_convert:op_type @3))))))
+ (simplify
+ (vec_cond @0 @1 (view_convert? (uncond_op@4 @2 @3)))
+ (with { tree op_type = TREE_TYPE (@4); }
+ (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+ && element_precision (type) == element_precision (op_type))
+ (view_convert (cond_op (bit_not @0) @2 @3 (view_convert:op_type @1)))))))
+
+/* Same for ternary operations. */
+(for uncond_op (UNCOND_TERNARY)
+ cond_op (COND_TERNARY)
+ (simplify
+ (vec_cond @0 (view_convert? (uncond_op@5 @1 @2 @3)) @4)
+ (with { tree op_type = TREE_TYPE (@5); }
+ (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+ && element_precision (type) == element_precision (op_type))
+ (view_convert (cond_op @0 @1 @2 @3 (view_convert:op_type @4))))))
+ (simplify
+ (vec_cond @0 @1 (view_convert? (uncond_op@5 @2 @3 @4)))
+ (with { tree op_type = TREE_TYPE (@5); }
+ (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+ && element_precision (type) == element_precision (op_type))
+ (view_convert (cond_op (bit_not @0) @2 @3 @4
+ (view_convert:op_type @1)))))))
+#endif
+
+/* Detect cases in which a VEC_COND_EXPR effectively replaces the
+ "else" value of an IFN_COND_*. */
+(for cond_op (COND_BINARY)
+ (simplify
+ (vec_cond @0 (view_convert? (cond_op @0 @1 @2 @3)) @4)
+ (with { tree op_type = TREE_TYPE (@3); }
+ (if (element_precision (type) == element_precision (op_type))
+ (view_convert (cond_op @0 @1 @2 (view_convert:op_type @4))))))
+ (simplify
+ (vec_cond @0 @1 (view_convert? (cond_op @2 @3 @4 @5)))
+ (with { tree op_type = TREE_TYPE (@5); }
+ (if (inverse_conditions_p (@0, @2)
+ && element_precision (type) == element_precision (op_type))
+ (view_convert (cond_op @2 @3 @4 (view_convert:op_type @1)))))))
+
+/* Same for ternary operations. */
+(for cond_op (COND_TERNARY)
+ (simplify
+ (vec_cond @0 (view_convert? (cond_op @0 @1 @2 @3 @4)) @5)
+ (with { tree op_type = TREE_TYPE (@4); }
+ (if (element_precision (type) == element_precision (op_type))
+ (view_convert (cond_op @0 @1 @2 @3 (view_convert:op_type @5))))))
+ (simplify
+ (vec_cond @0 @1 (view_convert? (cond_op @2 @3 @4 @5 @6)))
+ (with { tree op_type = TREE_TYPE (@6); }
+ (if (inverse_conditions_p (@0, @2)
+ && element_precision (type) == element_precision (op_type))
+ (view_convert (cond_op @2 @3 @4 @5 (view_convert:op_type @1)))))))
+
+/* For pointers @0 and @2 and nonnegative constant offset @1, look for
+ expressions like:
+
+ A: (@0 + @1 < @2) | (@2 + @1 < @0)
+ B: (@0 + @1 <= @2) | (@2 + @1 <= @0)
+
+ If pointers are known not to wrap, B checks whether @1 bytes starting
+ at @0 and @2 do not overlap, while A tests the same thing for @1 + 1
+ bytes. A is more efficiently tested as:
+
+ A: (sizetype) (@0 + @1 - @2) > @1 * 2
+
+ The equivalent expression for B is given by replacing @1 with @1 - 1:
+
+ B: (sizetype) (@0 + (@1 - 1) - @2) > (@1 - 1) * 2
+
+ @0 and @2 can be swapped in both expressions without changing the result.
+
+ The folds rely on sizetype's being unsigned (which is always true)
+ and on its being the same width as the pointer (which we have to check).
+
+ The fold replaces two pointer_plus expressions, two comparisons and
+ an IOR with a pointer_plus, a pointer_diff, and a comparison, so in
+ the best case it's a saving of two operations. The A fold retains one
+ of the original pointer_pluses, so is a win even if both pointer_pluses
+ are used elsewhere. The B fold is a wash if both pointer_pluses are
+ used elsewhere, since all we end up doing is replacing a comparison with
+ a pointer_plus. We do still apply the fold under those circumstances
+ though, in case applying it to other conditions eventually makes one of the
+ pointer_pluses dead. */
+(for ior (truth_orif truth_or bit_ior)
+ (for cmp (le lt)
+ (simplify
+ (ior (cmp:cs (pointer_plus@3 @0 INTEGER_CST@1) @2)
+ (cmp:cs (pointer_plus@4 @2 @1) @0))
+ (if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
+ && TYPE_OVERFLOW_WRAPS (sizetype)
+ && TYPE_PRECISION (TREE_TYPE (@0)) == TYPE_PRECISION (sizetype))
+ /* Calculate the rhs constant. */
+ (with { offset_int off = wi::to_offset (@1) - (cmp == LE_EXPR ? 1 : 0);
+ offset_int rhs = off * 2; }
+ /* Always fails for negative values. */
+ (if (wi::min_precision (rhs, UNSIGNED) <= TYPE_PRECISION (sizetype))
+ /* Since the order of @0 and @2 doesn't matter, let tree_swap_operands_p
+ pick a canonical order. This increases the chances of using the
+ same pointer_plus in multiple checks. */
+ (with { bool swap_p = tree_swap_operands_p (@0, @2);
+ tree rhs_tree = wide_int_to_tree (sizetype, rhs); }
+ (if (cmp == LT_EXPR)
+ (gt (convert:sizetype
+ (pointer_diff:ssizetype { swap_p ? @4 : @3; }
+ { swap_p ? @0 : @2; }))
+ { rhs_tree; })
+ (gt (convert:sizetype
+ (pointer_diff:ssizetype
+ (pointer_plus { swap_p ? @2 : @0; }
+ { wide_int_to_tree (sizetype, off); })
+ { swap_p ? @0 : @2; }))
+ { rhs_tree; })))))))))
+
+/* Fold REDUC (@0 & @1) -> @0[I] & @1[I] if element I is the only nonzero
+ element of @1. */
+(for reduc (IFN_REDUC_PLUS IFN_REDUC_IOR IFN_REDUC_XOR)
+ (simplify (reduc (view_convert? (bit_and @0 VECTOR_CST@1)))
+ (with { int i = single_nonzero_element (@1); }
+ (if (i >= 0)
+ (with { tree elt = vector_cst_elt (@1, i);
+ tree elt_type = TREE_TYPE (elt);
+ unsigned int elt_bits = tree_to_uhwi (TYPE_SIZE (elt_type));
+ tree size = bitsize_int (elt_bits);
+ tree pos = bitsize_int (elt_bits * i); }
+ (view_convert
+ (bit_and:elt_type
+ (BIT_FIELD_REF:elt_type @0 { size; } { pos; })
+ { elt; })))))))
+
+(simplify
+ (vec_perm @0 @1 VECTOR_CST@2)
+ (with
+ {
+ tree op0 = @0, op1 = @1, op2 = @2;
+
+ /* Build a vector of integers from the tree mask. */
+ vec_perm_builder builder;
+ if (!tree_to_vec_perm_builder (&builder, op2))
+ return NULL_TREE;
+
+ /* Create a vec_perm_indices for the integer vector. */
+ poly_uint64 nelts = TYPE_VECTOR_SUBPARTS (type);
+ bool single_arg = (op0 == op1);
+ vec_perm_indices sel (builder, single_arg ? 1 : 2, nelts);
+ }
+ (if (sel.series_p (0, 1, 0, 1))
+ { op0; }
+ (if (sel.series_p (0, 1, nelts, 1))
+ { op1; }
+ (with
+ {
+ if (!single_arg)
+ {
+ if (sel.all_from_input_p (0))
+ op1 = op0;
+ else if (sel.all_from_input_p (1))
+ {
+ op0 = op1;
+ sel.rotate_inputs (1);
+ }
+ else if (known_ge (poly_uint64 (sel[0]), nelts))
+ {
+ std::swap (op0, op1);
+ sel.rotate_inputs (1);
+ }
+ }
+ gassign *def;
+ tree cop0 = op0, cop1 = op1;
+ if (TREE_CODE (op0) == SSA_NAME
+ && (def = dyn_cast <gassign *> (SSA_NAME_DEF_STMT (op0)))
+ && gimple_assign_rhs_code (def) == CONSTRUCTOR)
+ cop0 = gimple_assign_rhs1 (def);
+ if (TREE_CODE (op1) == SSA_NAME
+ && (def = dyn_cast <gassign *> (SSA_NAME_DEF_STMT (op1)))
+ && gimple_assign_rhs_code (def) == CONSTRUCTOR)
+ cop1 = gimple_assign_rhs1 (def);
+
+ tree t;
+ }
+ (if ((TREE_CODE (cop0) == VECTOR_CST
+ || TREE_CODE (cop0) == CONSTRUCTOR)
+ && (TREE_CODE (cop1) == VECTOR_CST
+ || TREE_CODE (cop1) == CONSTRUCTOR)
+ && (t = fold_vec_perm (type, cop0, cop1, sel)))
+ { t; }
+ (with
+ {
+ bool changed = (op0 == op1 && !single_arg);
+ tree ins = NULL_TREE;
+ unsigned at = 0;
+
+ /* See if the permutation is performing a single element
+ insert from a CONSTRUCTOR or constant and use a BIT_INSERT_EXPR
+ in that case. But only if the vector mode is supported,
+ otherwise this is invalid GIMPLE. */
+ if (TYPE_MODE (type) != BLKmode
+ && (TREE_CODE (cop0) == VECTOR_CST
+ || TREE_CODE (cop0) == CONSTRUCTOR
+ || TREE_CODE (cop1) == VECTOR_CST
+ || TREE_CODE (cop1) == CONSTRUCTOR))
+ {
+ if (sel.series_p (1, 1, nelts + 1, 1))
+ {
+ /* After canonicalizing the first elt to come from the
+ first vector we only can insert the first elt from
+ the first vector. */
+ at = 0;
+ if ((ins = fold_read_from_vector (cop0, 0)))
+ op0 = op1;
+ }
+ else
+ {
+ unsigned int encoded_nelts = sel.encoding ().encoded_nelts ();
+ for (at = 0; at < encoded_nelts; ++at)
+ if (maybe_ne (sel[at], at))
+ break;
+ if (at < encoded_nelts && sel.series_p (at + 1, 1, at + 1, 1))
+ {
+ if (known_lt (at, nelts))
+ ins = fold_read_from_vector (cop0, sel[at]);
+ else
+ ins = fold_read_from_vector (cop1, sel[at] - nelts);
+ }
+ }
+ }
+
+ /* Generate a canonical form of the selector. */
+ if (!ins && sel.encoding () != builder)
+ {
+ /* Some targets are deficient and fail to expand a single
+ argument permutation while still allowing an equivalent
+ 2-argument version. */
+ tree oldop2 = op2;
+ if (sel.ninputs () == 2
+ || can_vec_perm_const_p (TYPE_MODE (type), sel, false))
+ op2 = vec_perm_indices_to_tree (TREE_TYPE (op2), sel);
+ else
+ {
+ vec_perm_indices sel2 (builder, 2, nelts);
+ if (can_vec_perm_const_p (TYPE_MODE (type), sel2, false))
+ op2 = vec_perm_indices_to_tree (TREE_TYPE (op2), sel2);
+ else
+ /* Not directly supported with either encoding,
+ so use the preferred form. */
+ op2 = vec_perm_indices_to_tree (TREE_TYPE (op2), sel);
+ }
+ if (!operand_equal_p (op2, oldop2, 0))
+ changed = true;
+ }
+ }
+ (if (ins)
+ (bit_insert { op0; } { ins; }
+ { bitsize_int (at * tree_to_uhwi (TYPE_SIZE (TREE_TYPE (type)))); })
+ (if (changed)
+ (vec_perm { op0; } { op1; } { op2; }))))))))))