This file is consumed by genmatch which produces gimple-match.cc
and generic-match.cc from it.
- Copyright (C) 2014-2023 Free Software Foundation, Inc.
+ Copyright (C) 2014-2024 Free Software Foundation, Inc.
Contributed by Richard Biener <rguenther@suse.de>
and Prathamesh Kulkarni <bilbotheelffriend@gmail.com>
negate bit_not)
(define_operator_list COND_UNARY
IFN_COND_NEG IFN_COND_NOT)
+(define_operator_list COND_LEN_UNARY
+ IFN_COND_LEN_NEG IFN_COND_LEN_NOT)
/* Binary operations and their associated IFN_COND_* function. */
(define_operator_list UNCOND_BINARY
plus minus
mult trunc_div trunc_mod rdiv
min max
- IFN_FMIN IFN_FMAX
+ IFN_FMIN IFN_FMAX IFN_COPYSIGN
bit_and bit_ior bit_xor
lshift rshift)
(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_FMIN IFN_COND_FMAX
+ IFN_COND_FMIN IFN_COND_FMAX IFN_COND_COPYSIGN
IFN_COND_AND IFN_COND_IOR IFN_COND_XOR
IFN_COND_SHL IFN_COND_SHR)
+(define_operator_list COND_LEN_BINARY
+ IFN_COND_LEN_ADD IFN_COND_LEN_SUB
+ IFN_COND_LEN_MUL IFN_COND_LEN_DIV
+ IFN_COND_LEN_MOD IFN_COND_LEN_RDIV
+ IFN_COND_LEN_MIN IFN_COND_LEN_MAX
+ IFN_COND_LEN_FMIN IFN_COND_LEN_FMAX IFN_COND_LEN_COPYSIGN
+ IFN_COND_LEN_AND IFN_COND_LEN_IOR IFN_COND_LEN_XOR
+ IFN_COND_LEN_SHL IFN_COND_LEN_SHR)
/* 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)
+(define_operator_list COND_LEN_TERNARY
+ IFN_COND_LEN_FMA IFN_COND_LEN_FMS IFN_COND_LEN_FNMA IFN_COND_LEN_FNMS)
/* __atomic_fetch_or_*, __atomic_fetch_xor_*, __atomic_xor_fetch_* */
(define_operator_list ATOMIC_FETCH_OR_XOR_N
TYPE_VECTOR_SUBPARTS (TREE_TYPE (@0)))
&& tree_nop_conversion_p (TREE_TYPE (type), TREE_TYPE (TREE_TYPE (@0))))))
-#if GIMPLE
/* These are used by gimple_bitwise_inverted_equal_p to simplify
detection of BIT_NOT and comparisons. */
(match (bit_not_with_nop @0)
(match (bit_not_with_nop @0)
(convert (bit_not @0))
(if (tree_nop_conversion_p (type, TREE_TYPE (@0)))))
+(match (bit_xor_cst @0 @1)
+ (bit_xor @0 uniform_integer_cst_p@1))
(for cmp (tcc_comparison)
(match (maybe_cmp @0)
(cmp@0 @1 @2))
(convert (cmp@0 @1 @2))
(if (tree_nop_conversion_p (type, TREE_TYPE (@0)))))
)
-#endif
+/* `a ^ b` is another form of `a != b` when the type
+ is a 1bit precission integer. */
+(match (maybe_cmp @0)
+ (bit_xor@0 @1 @2)
+ (if (INTEGRAL_TYPE_P (type)
+ && TYPE_PRECISION (type) == 1)))
+/* maybe_bit_not is used to match what
+ is acceptable for bitwise_inverted_equal_p. */
+(match (maybe_bit_not @0)
+ (bit_not_with_nop@0 @1))
+(match (maybe_bit_not @0)
+ (INTEGER_CST@0))
+(match (maybe_bit_not @0)
+ (maybe_cmp@0 @1))
+(match (maybe_bit_not @0)
+ (bit_xor_cst@0 @1 @2))
/* 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
/* (x >= 0 ? x : 0) + (x <= 0 ? -x : 0) -> abs x. */
(simplify
- (plus:c (max @0 integer_zerop) (max (negate @0) integer_zerop))
- (abs @0))
+ (plus:c (max @0 integer_zerop) (max (negate @0) integer_zerop))
+ (if (ANY_INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_UNDEFINED (type))
+ (abs @0)))
/* X * 1, X / 1 -> X. */
(for op (mult trunc_div ceil_div floor_div round_div exact_div)
1 / X -> X >= -1 && X <= 1 ? X : 0 for signed integer X.
But not for 1 / 0 so that we can get proper warnings and errors,
and not for 1-bit integers as they are edge cases better handled
- elsewhere. */
+ elsewhere. Delay the conversion of the signed division until late
+ because `1 / X` is simplier to handle than the resulting COND_EXPR. */
(simplify
(trunc_div integer_onep@0 @1)
(if (INTEGRAL_TYPE_P (type)
&& (!flag_non_call_exceptions || tree_expr_nonzero_p (@1)))
(if (TYPE_UNSIGNED (type))
(convert (eq:boolean_type_node @1 { build_one_cst (type); }))
- (with { tree utype = unsigned_type_for (type); }
- (cond (le (plus (convert:utype @1) { build_one_cst (utype); })
- { build_int_cst (utype, 2); })
- @1 { build_zero_cst (type); })))))
+ (if (!canonicalize_math_p ())
+ (with { tree utype = unsigned_type_for (type); }
+ (cond (le (plus (convert:utype @1) { build_one_cst (utype); })
+ { build_int_cst (utype, 2); })
+ @1 { build_zero_cst (type); }))))))
/* Combine two successive divisions. Note that combining ceil_div
and floor_div is trickier and combining round_div even more so. */
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && TYPE_UNSIGNED (TREE_TYPE (@0)))
(bit_and @0 (negate @1))))
-/* Simplify (t * 2) / 2) -> t. */
(for div (trunc_div ceil_div floor_div round_div exact_div)
+ /* Simplify (t * u) / u -> t. */
(simplify
(div (mult:c @0 @1) @1)
(if (ANY_INTEGRAL_TYPE_P (type))
- (if (TYPE_OVERFLOW_UNDEFINED (type))
+ (if (TYPE_OVERFLOW_UNDEFINED (type) && !TYPE_OVERFLOW_SANITIZED (type))
@0
#if GIMPLE
(with {value_range vr0, vr1;}
&& get_range_query (cfun)->range_of_expr (vr1, @1)
&& range_op_handler (MULT_EXPR).overflow_free_p (vr0, vr1))
@0))
+#endif
+ )))
+#if GIMPLE
+ /* Simplify (t * u) / v -> t * (u / v) if u is multiple of v. */
+ (simplify
+ (div (mult @0 INTEGER_CST@1) INTEGER_CST@2)
+ (if (INTEGRAL_TYPE_P (type)
+ && wi::multiple_of_p (wi::to_widest (@1), wi::to_widest (@2), SIGNED))
+ (if (TYPE_OVERFLOW_UNDEFINED (type) && !TYPE_OVERFLOW_SANITIZED (type))
+ (mult @0 (div! @1 @2))
+ (with {value_range vr0, vr1;}
+ (if (get_range_query (cfun)->range_of_expr (vr0, @0)
+ && get_range_query (cfun)->range_of_expr (vr1, @1)
+ && range_op_handler (MULT_EXPR).overflow_free_p (vr0, vr1))
+ (mult @0 (div! @1 @2))))
+ )))
+#endif
+ /* Simplify (t * u) / (t * v) -> (u / v) if u is multiple of v. */
+ (simplify
+ (div (mult @0 INTEGER_CST@1) (mult @0 INTEGER_CST@2))
+ (if (INTEGRAL_TYPE_P (type)
+ && wi::multiple_of_p (wi::to_widest (@1), wi::to_widest (@2), SIGNED))
+ (if (TYPE_OVERFLOW_UNDEFINED (type) && !TYPE_OVERFLOW_SANITIZED (type))
+ (div @1 @2)
+#if GIMPLE
+ (with {value_range vr0, vr1, vr2;}
+ (if (get_range_query (cfun)->range_of_expr (vr0, @0)
+ && get_range_query (cfun)->range_of_expr (vr1, @1)
+ && get_range_query (cfun)->range_of_expr (vr2, @2)
+ && range_op_handler (MULT_EXPR).overflow_free_p (vr0, vr1)
+ && range_op_handler (MULT_EXPR).overflow_free_p (vr0, vr2))
+ (div @1 @2)))
#endif
))))
/* (nop_outer_cast)-(inner_cast)var -> -(outer_cast)(var)
if var is smaller in precision.
This is always safe for both doing the negative in signed or unsigned
- as the value for undefined will not show up. */
+ as the value for undefined will not show up.
+ Note the outer cast cannot be a boolean type as the only valid values
+ are 0,-1/1 (depending on the signedness of the boolean) and the negative
+ is there to get the correct value. */
(simplify
(convert (negate:s@1 (convert:s @0)))
(if (INTEGRAL_TYPE_P (type)
&& tree_nop_conversion_p (type, TREE_TYPE (@1))
- && TYPE_PRECISION (type) > TYPE_PRECISION (TREE_TYPE (@0)))
+ && TYPE_PRECISION (type) > TYPE_PRECISION (TREE_TYPE (@0))
+ && TREE_CODE (type) != BOOLEAN_TYPE)
(negate (convert @0))))
(for op (negate abs)
/* cos(copysign(x, y)) -> cos(x). Similarly for cosh. */
(for coss (COS COSH)
- copysigns (COPYSIGN)
- (simplify
- (coss (copysigns @0 @1))
- (coss @0)))
+ (for copysigns (COPYSIGN)
+ (simplify
+ (coss (copysigns @0 @1))
+ (coss @0))))
/* pow(copysign(x, y), z) -> pow(x, z) if z is an even integer. */
(for pows (POW)
- copysigns (COPYSIGN)
- (simplify
- (pows (copysigns @0 @2) REAL_CST@1)
- (with { HOST_WIDE_INT n; }
- (if (real_isinteger (&TREE_REAL_CST (@1), &n) && (n & 1) == 0)
- (pows @0 @1)))))
+ (for copysigns (COPYSIGN)
+ (simplify
+ (pows (copysigns @0 @2) REAL_CST@1)
+ (with { HOST_WIDE_INT n; }
+ (if (real_isinteger (&TREE_REAL_CST (@1), &n) && (n & 1) == 0)
+ (pows @0 @1))))))
/* Likewise for powi. */
(for pows (POWI)
- copysigns (COPYSIGN)
- (simplify
- (pows (copysigns @0 @2) INTEGER_CST@1)
- (if ((wi::to_wide (@1) & 1) == 0)
- (pows @0 @1))))
+ (for copysigns (COPYSIGN)
+ (simplify
+ (pows (copysigns @0 @2) INTEGER_CST@1)
+ (if ((wi::to_wide (@1) & 1) == 0)
+ (pows @0 @1)))))
(for hypots (HYPOT)
- copysigns (COPYSIGN)
- /* hypot(copysign(x, y), z) -> hypot(x, z). */
- (simplify
- (hypots (copysigns @0 @1) @2)
- (hypots @0 @2))
- /* hypot(x, copysign(y, z)) -> hypot(x, y). */
- (simplify
- (hypots @0 (copysigns @1 @2))
- (hypots @0 @1)))
+ (for copysigns (COPYSIGN)
+ /* hypot(copysign(x, y), z) -> hypot(x, z). */
+ (simplify
+ (hypots (copysigns @0 @1) @2)
+ (hypots @0 @2))
+ /* hypot(x, copysign(y, z)) -> hypot(x, y). */
+ (simplify
+ (hypots @0 (copysigns @1 @2))
+ (hypots @0 @1))))
-/* copysign(x, CST) -> [-]abs (x). */
+/* copysign(x, CST) -> abs (x). If the target does not
+ support the copysign optab then canonicalize
+ copysign(x, -CST) -> fneg (abs (x)). */
(for copysigns (COPYSIGN_ALL)
(simplify
(copysigns @0 REAL_CST@1)
- (if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (@1)))
- (negate (abs @0))
- (abs @0))))
+ (if (!REAL_VALUE_NEGATIVE (TREE_REAL_CST (@1)))
+ (abs @0)
+#if GIMPLE
+ (if (!direct_internal_fn_supported_p (IFN_COPYSIGN, type,
+ OPTIMIZE_FOR_BOTH))
+ (negate (abs @0)))
+#endif
+ )))
+#if GIMPLE
+/* Transform fneg (fabs (X)) -> copysign (X, -1) as the canonical
+ representation if the target supports the copysign optab. */
+(simplify
+ (negate (abs @0))
+ (if (direct_internal_fn_supported_p (IFN_COPYSIGN, type,
+ OPTIMIZE_FOR_BOTH))
+ (IFN_COPYSIGN @0 { build_minus_one_cst (type); })))
+#endif
/* copysign(copysign(x, y), z) -> copysign(x, z). */
(for copysigns (COPYSIGN_ALL)
(simplify
&& tree_nop_conversion_p (type, TREE_TYPE (@1)))
(lshift @0 @2)))
+/* Fold a * !a into 0. */
+(simplify
+ (mult:c @0 (convert? (eq @0 integer_zerop)))
+ { build_zero_cst (type); })
+(simplify
+ (mult:c @0 (vec_cond (eq @0 integer_zerop) @1 integer_zerop))
+ { build_zero_cst (type); })
+(simplify
+ (mult:c @0 (vec_cond (ne @0 integer_zerop) integer_zerop @1))
+ { build_zero_cst (type); })
+
/* Shifts by precision or greater result in zero. */
(for shift (lshift rshift)
(simplify
/* Simplify ~X & X as zero. */
(simplify
- (bit_and (convert? @0) (convert? @1))
+ (bit_and:c (convert? @0) (convert? (maybe_bit_not @1)))
(with { bool wascmp; }
(if (types_match (TREE_TYPE (@0), TREE_TYPE (@1))
&& bitwise_inverted_equal_p (@0, @1, wascmp))
&& TYPE_PRECISION (TREE_TYPE (@0)) == 1)
(bit_ior @0 (bit_xor @1 { build_one_cst (type); }))))
+/* a | ((~a) ^ b) --> a | (~b) (alt version of the above 2) */
+(simplify
+ (bit_ior:c @0 (bit_xor:cs @1 @2))
+ (with { bool wascmp; }
+ (if (bitwise_inverted_equal_p (@0, @1, wascmp)
+ && (!wascmp || element_precision (type) == 1))
+ (bit_ior @0 (bit_not @2)))))
+
+/* a & ~(a ^ b) --> a & b */
+(simplify
+ (bit_and:c @0 (bit_not (bit_xor:c @0 @1)))
+ (bit_and @0 @1))
+
+/* a & (a == b) --> a & b (boolean version of the above). */
+(simplify
+ (bit_and:c @0 (nop_convert? (eq:c @0 @1)))
+ (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
+ && TYPE_PRECISION (TREE_TYPE (@0)) == 1)
+ (bit_and @0 @1)))
+
+/* a & ((~a) ^ b) --> a & b (alt version of the above 2) */
+(simplify
+ (bit_and:c @0 (bit_xor:c @1 @2))
+ (with { bool wascmp; }
+ (if (bitwise_inverted_equal_p (@0, @1, wascmp)
+ && (!wascmp || element_precision (type) == 1))
+ (bit_and @0 @2))))
+
/* (a | b) | (a &^ b) --> a | b */
(for op (bit_and bit_xor)
(simplify
/* ~x ^ x -> -1 */
(for op (bit_ior bit_xor)
(simplify
- (op (convert? @0) (convert? @1))
+ (op:c (convert? @0) (convert? (maybe_bit_not @1)))
(with { bool wascmp; }
(if (types_match (TREE_TYPE (@0), TREE_TYPE (@1))
&& bitwise_inverted_equal_p (@0, @1, wascmp))
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
&& wi::bit_and_not (get_nonzero_bits (@0), wi::to_wide (@1)) == 0)
@0))
+
+/* `a & (x | CST)` -> a if we know that (a & ~CST) == 0 */
+(simplify
+ (bit_and:c SSA_NAME@0 (bit_ior @1 INTEGER_CST@2))
+ (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
+ && wi::bit_and_not (get_nonzero_bits (@0), wi::to_wide (@2)) == 0)
+ @0))
+
/* x | C -> C if we know that x & ~C == 0. */
(simplify
(bit_ior SSA_NAME@0 INTEGER_CST@1)
(simplify
(bit_xor:c (convert1? (bit_xor:c @0 @@1)) (convert2? @1))
(convert @0))
+
+/* (X & ~Y) & Y -> 0 */
+(simplify
+ (bit_and:c (bit_and @0 @1) @2)
+ (with { bool wascmp; }
+ (if (bitwise_inverted_equal_p (@0, @2, wascmp)
+ || bitwise_inverted_equal_p (@1, @2, wascmp))
+ { wascmp ? constant_boolean_node (false, type) : build_zero_cst (type); })))
+/* (X | ~Y) | Y -> -1 */
+(simplify
+ (bit_ior:c (bit_ior @0 @1) @2)
+ (with { bool wascmp; }
+ (if ((bitwise_inverted_equal_p (@0, @2, wascmp)
+ || bitwise_inverted_equal_p (@1, @2, wascmp))
+ && (!wascmp || element_precision (type) == 1))
+ { build_all_ones_cst (TREE_TYPE (@0)); })))
+
/* (X & Y) & (X & Z) -> (X & Y) & Z
(X | Y) | (X | Z) -> (X | Y) | Z */
(for op (bit_and bit_ior)
(if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
&& (TYPE_UNSIGNED (TREE_TYPE (@1))
|| TYPE_PRECISION (TREE_TYPE (@1)) > 1)
+ && INTEGRAL_TYPE_P (type)
+ && (TYPE_UNSIGNED (type)
+ || TYPE_PRECISION (type) > 1)
&& wi::leu_p (tree_nonzero_bits (@1), 1))))
/* Transform { 0 or 1 } * { 0 or 1 } into { 0 or 1 } & { 0 or 1 }. */
(mult (convert @0) @1)))
/* Narrow integer multiplication by a zero_one_valued_p operand.
- Multiplication by [0,1] is guaranteed not to overflow. */
+ Multiplication by [0,1] is guaranteed not to overflow except for
+ 1bit signed types. */
(simplify
(convert (mult@0 zero_one_valued_p@1 INTEGER_CST@2))
(if (INTEGRAL_TYPE_P (type)
&& INTEGRAL_TYPE_P (TREE_TYPE (@0))
- && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (@0)))
+ && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (@0))
+ && (TYPE_UNSIGNED (type) || TYPE_PRECISION (type) > 1))
(mult (convert @1) (convert @2))))
/* (X << C) != 0 can be simplified to X, when C is zero_one_valued_p.
&& (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
|| TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))))
(op @0 @1))))
+/* And similar for pointers. */
+(for op (eq ne)
+ (simplify
+ (op (pointer_plus @0 @1) (pointer_plus @0 @2))
+ (op @1 @2)))
+(simplify
+ (pointer_diff (pointer_plus @0 @1) (pointer_plus @0 @2))
+ (if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@1)))
+ (convert (minus @1 @2))))
/* X - Z < Y - Z is the same as X < Y when there is no overflow. */
(for op (lt le ge gt)
(if (TREE_INT_CST_LOW (@1) & 1)
{ constant_boolean_node (cmp == NE_EXPR, type); })))
+/*
+ U & N <= U -> true
+ U & N > U -> false
+ U needs to be non-negative.
+
+ U | N < U -> false
+ U | N >= U -> true
+ U and N needs to be non-negative
+
+ U | N < U -> true
+ U | N >= U -> false
+ U needs to be non-negative and N needs to be a negative constant.
+ */
+(for cmp (lt ge le gt )
+ bitop (bit_ior bit_ior bit_and bit_and)
+ (simplify
+ (cmp:c (bitop:c tree_expr_nonnegative_p@0 @1) @0)
+ (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)))
+ (if (bitop == BIT_AND_EXPR || tree_expr_nonnegative_p (@1))
+ { constant_boolean_node (cmp == GE_EXPR || cmp == LE_EXPR, type); }
+ /* The sign is opposite now so the comparison is swapped around. */
+ (if (TREE_CODE (@1) == INTEGER_CST && wi::neg_p (wi::to_wide (@1)))
+ { constant_boolean_node (cmp == LT_EXPR, type); })))))
+
/* Arguments on which one can call get_nonzero_bits to get the bits
possibly set. */
(match with_possible_nonzero_bits
|| POINTER_TYPE_P (itype))
&& wi::eq_p (wi::to_wide (int_cst), wi::max_value (itype))))))
+/* Unsigned Saturation Add */
+(match (usadd_left_part_1 @0 @1)
+ (plus:c @0 @1)
+ (if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type)
+ && types_match (type, @0, @1))))
+
+(match (usadd_left_part_2 @0 @1)
+ (realpart (IFN_ADD_OVERFLOW:c @0 @1))
+ (if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type)
+ && types_match (type, @0, @1))))
+
+(match (usadd_right_part_1 @0 @1)
+ (negate (convert (lt (plus:c @0 @1) @0)))
+ (if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type)
+ && types_match (type, @0, @1))))
+
+(match (usadd_right_part_1 @0 @1)
+ (negate (convert (gt @0 (plus:c @0 @1))))
+ (if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type)
+ && types_match (type, @0, @1))))
+
+(match (usadd_right_part_2 @0 @1)
+ (negate (convert (ne (imagpart (IFN_ADD_OVERFLOW:c @0 @1)) integer_zerop)))
+ (if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type)
+ && types_match (type, @0, @1))))
+
+/* We cannot merge or overload usadd_left_part_1 and usadd_left_part_2
+ because the sub part of left_part_2 cannot work with right_part_1.
+ For example, left_part_2 pattern focus one .ADD_OVERFLOW but the
+ right_part_1 has nothing to do with .ADD_OVERFLOW. */
+
+/* Unsigned saturation add, case 1 (branchless):
+ SAT_U_ADD = (X + Y) | - ((X + Y) < X) or
+ SAT_U_ADD = (X + Y) | - (X > (X + Y)). */
+(match (unsigned_integer_sat_add @0 @1)
+ (bit_ior:c (usadd_left_part_1 @0 @1) (usadd_right_part_1 @0 @1)))
+
+/* Unsigned saturation add, case 2 (branchless with .ADD_OVERFLOW). */
+(match (unsigned_integer_sat_add @0 @1)
+ (bit_ior:c (usadd_left_part_2 @0 @1) (usadd_right_part_2 @0 @1)))
+
/* x > y && x != XXX_MIN --> x > y
x > y && x == XXX_MIN --> false . */
(for eqne (eq ne)
&& TYPE_OVERFLOW_WRAPS (TREE_TYPE (@1)))
(gt @0 (minus @1 { build_int_cst (TREE_TYPE (@1), 1); }))))
-/* Convert (X == CST1) && (X OP2 CST2) to a known value
+/* Convert (X == CST1) && ((other)X OP2 CST2) to a known value
based on CST1 OP2 CST2. Similarly for (X != CST1). */
/* Convert (X == Y) && (X OP2 Y) to a known value if X is an integral type.
Similarly for (X != Y). */
(for code1 (eq ne)
(for code2 (eq ne lt gt le ge)
(simplify
- (bit_and:c (code1@3 @0 @1) (code2@4 @0 @2))
+ (bit_and:c (code1:c@3 @0 @1) (code2:c@4 (convert?@c0 @0) @2))
(if ((TREE_CODE (@1) == INTEGER_CST
&& TREE_CODE (@2) == INTEGER_CST)
|| ((INTEGRAL_TYPE_P (TREE_TYPE (@1))
|| POINTER_TYPE_P (TREE_TYPE (@1)))
- && operand_equal_p (@1, @2)))
+ && bitwise_equal_p (@1, @2)))
(with
{
bool one_before = false;
bool one_after = false;
int cmp = 0;
+ bool allbits = true;
if (TREE_CODE (@1) == INTEGER_CST
&& TREE_CODE (@2) == INTEGER_CST)
{
- cmp = tree_int_cst_compare (@1, @2);
+ allbits = TYPE_PRECISION (TREE_TYPE (@1)) <= TYPE_PRECISION (TREE_TYPE (@2));
+ auto t1 = wi::to_wide (fold_convert (TREE_TYPE (@2), @1));
+ auto t2 = wi::to_wide (@2);
+ cmp = wi::cmp (t1, t2, TYPE_SIGN (TREE_TYPE (@2)));
if (cmp < 0
- && wi::to_wide (@1) == wi::to_wide (@2) - 1)
+ && t1 == t2 - 1)
one_before = true;
if (cmp > 0
- && wi::to_wide (@1) == wi::to_wide (@2) + 1)
+ && t1 == t2 + 1)
one_after = true;
}
bool val;
(switch
(if (code1 == EQ_EXPR && val) @3)
(if (code1 == EQ_EXPR && !val) { constant_boolean_node (false, type); })
- (if (code1 == NE_EXPR && !val) @4)
+ (if (code1 == NE_EXPR && !val && allbits) @4)
(if (code1 == NE_EXPR
&& code2 == GE_EXPR
- && cmp == 0)
- (gt @0 @1))
+ && cmp == 0
+ && allbits)
+ (gt @c0 (convert @1)))
(if (code1 == NE_EXPR
&& code2 == LE_EXPR
- && cmp == 0)
- (lt @0 @1))
+ && cmp == 0
+ && allbits)
+ (lt @c0 (convert @1)))
/* (a != (b+1)) & (a > b) -> a > (b+1) */
(if (code1 == NE_EXPR
&& code2 == GT_EXPR
- && one_after)
- (gt @0 @1))
+ && one_after
+ && allbits)
+ (gt @c0 (convert @1)))
/* (a != (b-1)) & (a < b) -> a < (b-1) */
(if (code1 == NE_EXPR
&& code2 == LT_EXPR
- && one_before)
- (lt @0 @1))
+ && one_before
+ && allbits)
+ (lt @c0 (convert @1)))
)
)
)
(for code1 (eq ne)
(for code2 (eq ne lt gt le ge)
(simplify
- (bit_ior:c (code1@3 @0 @1) (code2@4 @0 @2))
+ (bit_ior:c (code1:c@3 @0 @1) (code2:c@4 (convert?@c0 @0) @2))
(if ((TREE_CODE (@1) == INTEGER_CST
&& TREE_CODE (@2) == INTEGER_CST)
|| ((INTEGRAL_TYPE_P (TREE_TYPE (@1))
|| POINTER_TYPE_P (TREE_TYPE (@1)))
- && operand_equal_p (@1, @2)))
+ && bitwise_equal_p (@1, @2)))
(with
{
bool one_before = false;
bool one_after = false;
int cmp = 0;
+ bool allbits = true;
if (TREE_CODE (@1) == INTEGER_CST
&& TREE_CODE (@2) == INTEGER_CST)
{
- cmp = tree_int_cst_compare (@1, @2);
+ allbits = TYPE_PRECISION (TREE_TYPE (@1)) <= TYPE_PRECISION (TREE_TYPE (@2));
+ auto t1 = wi::to_wide (fold_convert (TREE_TYPE (@2), @1));
+ auto t2 = wi::to_wide (@2);
+ cmp = wi::cmp (t1, t2, TYPE_SIGN (TREE_TYPE (@2)));
if (cmp < 0
- && wi::to_wide (@1) == wi::to_wide (@2) - 1)
+ && t1 == t2 - 1)
one_before = true;
if (cmp > 0
- && wi::to_wide (@1) == wi::to_wide (@2) + 1)
+ && t1 == t2 + 1)
one_after = true;
}
bool val;
}
(switch
(if (code1 == EQ_EXPR && val) @4)
- (if (code1 == NE_EXPR && val) { constant_boolean_node (true, type); })
- (if (code1 == NE_EXPR && !val) @3)
+ (if (code1 == NE_EXPR && val && allbits) { constant_boolean_node (true, type); })
+ (if (code1 == NE_EXPR && !val && allbits) @3)
(if (code1 == EQ_EXPR
&& code2 == GT_EXPR
- && cmp == 0)
- (ge @0 @1))
+ && cmp == 0
+ && allbits)
+ (ge @c0 @2))
(if (code1 == EQ_EXPR
&& code2 == LT_EXPR
- && cmp == 0)
- (le @0 @1))
+ && cmp == 0
+ && allbits)
+ (le @c0 @2))
/* (a == (b-1)) | (a >= b) -> a >= (b-1) */
(if (code1 == EQ_EXPR
&& code2 == GE_EXPR
- && one_before)
- (ge @0 @1))
+ && one_before
+ && allbits)
+ (ge @c0 (convert @1)))
/* (a == (b+1)) | (a <= b) -> a <= (b-1) */
(if (code1 == EQ_EXPR
&& code2 == LE_EXPR
- && one_after)
- (le @0 @1))
+ && one_after
+ && allbits)
+ (le @c0 (convert @1)))
)
)
)
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) || POINTER_TYPE_P (TREE_TYPE (@0)))
(rcmp @0 @1))))
+/* (type)([0,1]@a != 0) -> (type)a
+ (type)([0,1]@a == 1) -> (type)a
+ (type)([0,1]@a == 0) -> a ^ 1
+ (type)([0,1]@a != 1) -> a ^ 1. */
+(for eqne (eq ne)
+ (simplify
+ (convert (eqne zero_one_valued_p@0 INTEGER_CST@1))
+ (if ((integer_zerop (@1) || integer_onep (@1)))
+ (if ((eqne == EQ_EXPR) ^ integer_zerop (@1))
+ (convert @0)
+ /* Only do this if the types match as (type)(a == 0) is
+ canonical form normally, while `a ^ 1` is canonical when
+ there is no type change. */
+ (if (types_match (type, TREE_TYPE (@0)))
+ (bit_xor @0 { build_one_cst (type); } ))))))
+
/* We can't reassociate at all for saturating types. */
(if (!TYPE_SATURATING (type))
/* (x <= 0 ? -x : 0) -> max(-x, 0). */
(simplify
- (cond (le @0 integer_zerop@1) (negate@2 @0) integer_zerop@1)
- (max @2 @1))
+ (cond (le @0 integer_zerop@1) (negate@2 @0) integer_zerop@1)
+ (if (ANY_INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_UNDEFINED (type))
+ (max @2 @1)))
/* (zero_one == 0) ? y : z <op> y -> ((typeof(y))zero_one * z) <op> y */
(for op (bit_xor bit_ior plus)
&& (INTEGRAL_TYPE_P (TREE_TYPE (@0))))
(op (mult (convert:type @0) @2) @1))))
+/* ?: Value replacement. */
+/* a == 0 ? b : b + a -> b + a */
+(for op (plus bit_ior bit_xor)
+ (simplify
+ (cond (eq @0 integer_zerop) @1 (op:c@2 @1 @0))
+ @2))
+/* a == 0 ? b : b - a -> b - a */
+/* a == 0 ? b : b ptr+ a -> b ptr+ a */
+/* a == 0 ? b : b shift/rotate a -> b shift/rotate a */
+(for op (lrotate rrotate lshift rshift minus pointer_plus)
+ (simplify
+ (cond (eq @0 integer_zerop) @1 (op@2 @1 @0))
+ @2))
+
+/* a == 1 ? b : b / a -> b / a */
+(for op (trunc_div ceil_div floor_div round_div exact_div)
+ (simplify
+ (cond (eq @0 integer_onep) @1 (op@2 @1 @0))
+ @2))
+
+/* a == 1 ? b : a * b -> a * b */
+(for op (mult)
+ (simplify
+ (cond (eq @0 integer_onep) @1 (op:c@2 @1 @0))
+ @2))
+
+/* a == -1 ? b : a & b -> a & b */
+(for op (bit_and)
+ (simplify
+ (cond (eq @0 integer_all_onesp) @1 (op:c@2 @1 @0))
+ @2))
+
+/* a != 0 ? a / b : 0 -> a / b iff b is nonzero. */
+(for op (trunc_div ceil_div floor_div round_div exact_div)
+ (simplify
+ (cond (ne @0 integer_zerop) (op@2 @3 @1) integer_zerop )
+ (if (bitwise_equal_p (@0, @3)
+ && tree_expr_nonzero_p (@1))
+ @2)))
+
+/* Note we prefer the != case here
+ as (a != 0) * (a * b) will generate that version. */
+/* a != 0 ? a * b : 0 -> a * b */
+/* a != 0 ? a & b : 0 -> a & b */
+(for op (mult bit_and)
+ (simplify
+ (cond (ne @0 integer_zerop) (op:c@2 @1 @3) integer_zerop)
+ (if (bitwise_equal_p (@0, @3))
+ @2)))
+
/* Simplifications of shift and rotates. */
(for rotate (lrotate rrotate)
/* If we have a sign-extension of a zero-extended value, we can
replace that by a single zero-extension. Likewise if the
final conversion does not change precision we can drop the
- intermediate conversion. */
+ intermediate conversion. Similarly truncation of a sign-extension
+ can be replaced by a single sign-extension. */
(if (inside_int && inter_int && final_int
&& ((inside_prec < inter_prec && inter_prec < final_prec
&& inside_unsignedp && !inter_unsignedp)
- || final_prec == inter_prec))
+ || final_prec == inter_prec
+ || (inside_prec < inter_prec && inter_prec > final_prec
+ && !inside_unsignedp && inter_unsignedp)))
(ocvt @0))
/* Two conversions in a row are not needed unless:
(simplify
(float (fix_trunc @0))
(if (!flag_trapping_math
+ && !HONOR_SIGNED_ZEROS (type)
&& types_match (type, TREE_TYPE (@0))
&& direct_internal_fn_supported_p (IFN_TRUNC, type,
OPTIMIZE_FOR_BOTH))
/* (c ? a : b) op (c ? d : e) --> c ? (a op d) : (b op e) */
(simplify
(op (vec_cond:s @0 @1 @2) (vec_cond:s @0 @3 @4))
- (vec_cond @0 (op! @1 @3) (op! @2 @4)))
+ (if (TREE_CODE_CLASS (op) != tcc_comparison
+ || types_match (type, TREE_TYPE (@1))
+ || expand_vec_cond_expr_p (type, TREE_TYPE (@0), ERROR_MARK)
+ || (optimize_vectors_before_lowering_p ()
+ /* The following is optimistic on the side of non-support, we are
+ missing the legacy vcond{,u,eq} cases. Do this only when
+ lowering will be able to fixup.. */
+ && !expand_vec_cond_expr_p (TREE_TYPE (@1),
+ TREE_TYPE (@0), ERROR_MARK)))
+ (vec_cond @0 (op! @1 @3) (op! @2 @4))))
/* (c ? a : b) op d --> c ? (a op d) : (b op d) */
(simplify
(op (vec_cond:s @0 @1 @2) @3)
- (vec_cond @0 (op! @1 @3) (op! @2 @3)))
+ (if (TREE_CODE_CLASS (op) != tcc_comparison
+ || types_match (type, TREE_TYPE (@1))
+ || expand_vec_cond_expr_p (type, TREE_TYPE (@0), ERROR_MARK)
+ || (optimize_vectors_before_lowering_p ()
+ && !expand_vec_cond_expr_p (TREE_TYPE (@1),
+ TREE_TYPE (@0), ERROR_MARK)))
+ (vec_cond @0 (op! @1 @3) (op! @2 @3))))
(simplify
(op @3 (vec_cond:s @0 @1 @2))
- (vec_cond @0 (op! @3 @1) (op! @3 @2))))
+ (if (TREE_CODE_CLASS (op) != tcc_comparison
+ || types_match (type, TREE_TYPE (@1))
+ || expand_vec_cond_expr_p (type, TREE_TYPE (@0), ERROR_MARK)
+ || (optimize_vectors_before_lowering_p ()
+ && !expand_vec_cond_expr_p (TREE_TYPE (@1),
+ TREE_TYPE (@0), ERROR_MARK)))
+ (vec_cond @0 (op! @3 @1) (op! @3 @2)))))
#if GIMPLE
(match (nop_atomic_bit_test_and_p @0 @1 @4)
/* (v ? w : 0) ? a : b is just (v & w) ? a : b
Currently disabled after pass lvec because ARM understands
VEC_COND_EXPR<v==w,-1,0> but not a plain v==w fed to BIT_IOR_EXPR. */
+#if GIMPLE
+/* These can only be done in gimple as fold likes to convert:
+ (CMP) & N into (CMP) ? N : 0
+ and we try to match the same pattern again and again. */
(simplify
(vec_cond (vec_cond:s @0 @3 integer_zerop) @1 @2)
(if (optimize_vectors_before_lowering_p () && types_match (@0, @3))
(if (optimize_vectors_before_lowering_p () && types_match (@0, @3))
(vec_cond (bit_and @0 (bit_not @3)) @2 @1)))
+/* ((VCE (a cmp b ? -1 : 0)) < 0) ? c : d is just
+ (VCE ((a cmp b) ? (VCE c) : (VCE d))) when TYPE_PRECISION of the
+ component type of the outer vec_cond is greater equal the inner one. */
+(for cmp (simple_comparison)
+ (simplify
+ (vec_cond
+ (lt (view_convert@5 (vec_cond@6 (cmp@4 @0 @1)
+ integer_all_onesp
+ integer_zerop))
+ integer_zerop) @2 @3)
+ (if (VECTOR_INTEGER_TYPE_P (TREE_TYPE (@0))
+ && VECTOR_INTEGER_TYPE_P (TREE_TYPE (@5))
+ && !TYPE_UNSIGNED (TREE_TYPE (@5))
+ && VECTOR_TYPE_P (TREE_TYPE (@6))
+ && VECTOR_TYPE_P (type)
+ && tree_int_cst_le (TYPE_SIZE (TREE_TYPE (type)),
+ TYPE_SIZE (TREE_TYPE (TREE_TYPE (@6))))
+ && TYPE_SIZE (type) == TYPE_SIZE (TREE_TYPE (@6)))
+ (with { tree vtype = TREE_TYPE (@6);}
+ (view_convert:type
+ (vec_cond @4 (view_convert:vtype @2) (view_convert:vtype @3)))))))
+
/* c1 ? c2 ? a : b : b --> (c1 & c2) ? a : b */
(simplify
(vec_cond @0 (vec_cond:s @1 @2 @3) @3)
(vec_cond @0 @3 (vec_cond:s @1 @2 @3))
(if (optimize_vectors_before_lowering_p () && types_match (@0, @1))
(vec_cond (bit_and (bit_not @0) @1) @2 @3)))
+#endif
/* Canonicalize mask ? { 0, ... } : { -1, ...} to ~mask if the mask
types are compatible. */
(switch
(if (integer_zerop (@2))
(switch
- /* a ? 1 : 0 -> a if 0 and 1 are integral types. */
+ /* a ? 1 : 0 -> a if 0 and 1 are integral types. */
(if (integer_onep (@1))
(convert (convert:boolean_type_node @0)))
+ /* a ? -1 : 0 -> -a. */
+ (if (INTEGRAL_TYPE_P (type) && integer_all_onesp (@1))
+ (if (TYPE_PRECISION (type) == 1)
+ /* For signed 1-bit precision just cast bool to the type. */
+ (convert (convert:boolean_type_node @0))
+ (if (TREE_CODE (type) == BOOLEAN_TYPE)
+ (with {
+ tree intt = build_nonstandard_integer_type (TYPE_PRECISION (type),
+ TYPE_UNSIGNED (type));
+ }
+ (convert (negate (convert:intt (convert:boolean_type_node @0)))))
+ (negate (convert:type (convert:boolean_type_node @0))))))
/* a ? powerof2cst : 0 -> a << (log2(powerof2cst)) */
(if (INTEGRAL_TYPE_P (type) && integer_pow2p (@1))
(with {
tree shift = build_int_cst (integer_type_node, tree_log2 (@1));
}
- (lshift (convert (convert:boolean_type_node @0)) { shift; })))
- /* a ? -1 : 0 -> -a. No need to check the TYPE_PRECISION not being 1
- here as the powerof2cst case above will handle that case correctly. */
- (if (INTEGRAL_TYPE_P (type) && integer_all_onesp (@1))
- (negate (convert:type (convert:boolean_type_node @0))))))
+ (lshift (convert (convert:boolean_type_node @0)) { shift; })))))
(if (integer_zerop (@1))
(switch
- /* a ? 0 : 1 -> !a. */
+ /* a ? 0 : 1 -> !a. */
(if (integer_onep (@2))
(convert (bit_xor (convert:boolean_type_node @0) { boolean_true_node; })))
- /* a ? powerof2cst : 0 -> (!a) << (log2(powerof2cst)) */
+ /* a ? 0 : -1 -> -(!a). */
+ (if (INTEGRAL_TYPE_P (type) && integer_all_onesp (@2))
+ (if (TYPE_PRECISION (type) == 1)
+ /* For signed 1-bit precision just cast bool to the type. */
+ (convert (bit_xor (convert:boolean_type_node @0) { boolean_true_node; }))
+ (if (TREE_CODE (type) == BOOLEAN_TYPE)
+ (with {
+ tree intt = build_nonstandard_integer_type (TYPE_PRECISION (type),
+ TYPE_UNSIGNED (type));
+ }
+ (convert (negate (convert:intt (bit_xor (convert:boolean_type_node @0)
+ { boolean_true_node; })))))
+ (negate (convert:type (bit_xor (convert:boolean_type_node @0)
+ { boolean_true_node; }))))))
+ /* a ? 0 : powerof2cst -> (!a) << (log2(powerof2cst)) */
(if (INTEGRAL_TYPE_P (type) && integer_pow2p (@2))
(with {
tree shift = build_int_cst (integer_type_node, tree_log2 (@2));
}
(lshift (convert (bit_xor (convert:boolean_type_node @0)
- { boolean_true_node; })) { shift; })))
- /* a ? -1 : 0 -> -(!a). No need to check the TYPE_PRECISION not being 1
- here as the powerof2cst case above will handle that case correctly. */
- (if (INTEGRAL_TYPE_P (type) && integer_all_onesp (@2))
- (negate (convert:type (bit_xor (convert:boolean_type_node @0)
- { boolean_true_node; }))))))))
+ { boolean_true_node; })) { shift; })))))))
/* (a > 1) ? 0 : (cast)a is the same as (cast)(a == 1)
for unsigned types. */
/* Optimize
# x_5 in range [cst1, cst2] where cst2 = cst1 + 1
- x_5 ? cstN ? cst4 : cst3
+ x_5 == cstN ? cst4 : cst3
# op is == or != and N is 1 or 2
to r_6 = x_5 + (min (cst3, cst4) - cst1) or
r_6 = (min (cst3, cst4) + cst1) - x_5 depending on op, N and which
type1 = type;
auto prec = TYPE_PRECISION (type1);
auto unsign = TYPE_UNSIGNED (type1);
- type1 = build_nonstandard_integer_type (prec, unsign);
+ if (TREE_CODE (type1) == BOOLEAN_TYPE)
+ type1 = build_nonstandard_integer_type (prec, unsign);
min = wide_int::from (min, prec,
TYPE_SIGN (TREE_TYPE (@0)));
wide_int a = wide_int::from (wi::to_wide (arg0), prec,
}
(if (code == PLUS_EXPR)
(convert (plus (convert:type1 @0) { arg; }))
- (convert (minus { arg; } (convert:type1 @0)))
- )
- )
- )
- )
- )
- )
-)
+ (convert (minus { arg; } (convert:type1 @0))))))))))
#endif
(simplify
(if (VECTOR_TYPE_P (type))
(view_convert @c0)
(convert @c0))))))))
+
+/* This is for VEC_COND_EXPR
+ Optimize A < B ? A : B to MIN (A, B)
+ A > B ? A : B to MAX (A, B). */
+(for cmp (lt le ungt unge gt ge unlt unle)
+ minmax (min min min min max max max max)
+ MINMAX (MIN_EXPR MIN_EXPR MIN_EXPR MIN_EXPR MAX_EXPR MAX_EXPR MAX_EXPR MAX_EXPR)
+ (simplify
+ (vec_cond (cmp @0 @1) @0 @1)
+ (if (VECTOR_INTEGER_TYPE_P (type)
+ && target_supports_op_p (type, MINMAX, optab_vector))
+ (minmax @0 @1))))
+
+(for cmp (lt le ungt unge gt ge unlt unle)
+ minmax (max max max max min min min min)
+ MINMAX (MAX_EXPR MAX_EXPR MAX_EXPR MAX_EXPR MIN_EXPR MIN_EXPR MIN_EXPR MIN_EXPR)
+ (simplify
+ (vec_cond (cmp @0 @1) @1 @0)
+ (if (VECTOR_INTEGER_TYPE_P (type)
+ && target_supports_op_p (type, MINMAX, optab_vector))
+ (minmax @0 @1))))
#endif
(for cnd (cond vec_cond)
@2)))
/* (a != b) ? (a + b) : (2 * a) -> (a + b) */
(simplify
- (cnd (ne:c @0 @1) (plus@2 @0 @1) (mult @0 uniform_integer_cst_p@3))
+ (cnd (ne:c @0 @1) (plus:c@2 @0 @1) (mult @0 uniform_integer_cst_p@3))
(if (wi::to_wide (uniform_integer_cst_p (@3)) == 2)
@2))
)
(if (wi::eq_p (wi::bit_not (wi::to_wide (@1)), wi::to_wide (@2)))
@3))
+/* X != C1 ? abs(X) : C2 simplifies to abs(x) when abs(C1) == C2. */
+(for op (abs absu)
+ (simplify
+ (cond (ne @0 INTEGER_CST@1) (op@3 @0) INTEGER_CST@2)
+ (if (wi::abs (wi::to_wide (@1)) == wi::to_wide (@2))
+ (if (op != ABSU_EXPR && wi::only_sign_bit_p (wi::to_wide (@1)))
+ (with { tree utype = unsigned_type_for (TREE_TYPE (@0)); }
+ (convert (absu:utype @0)))
+ @3))))
+
+/* X > Positive ? X : ABS(X) -> ABS(X) */
+/* X >= Positive ? X : ABS(X) -> ABS(X) */
+/* X == Positive ? X : ABS(X) -> ABS(X) */
+(for cmp (eq gt ge)
+ (simplify
+ (cond (cmp:c @0 tree_expr_nonnegative_p@1) @0 (abs@3 @0))
+ (if (INTEGRAL_TYPE_P (type))
+ @3)))
+
+/* X == Positive ? Positive : ABS(X) -> ABS(X) */
+(simplify
+ (cond (eq:c @0 tree_expr_nonnegative_p@1) @1 (abs@3 @0))
+ (if (INTEGRAL_TYPE_P (type))
+ @3))
+
/* (X + 1) > Y ? -X : 1 simplifies to X >= Y ? -X : 1 when
X is unsigned, as when X + 1 overflows, X is -1, so -X == 1. */
(simplify
/* !A ? B : C -> A ? C : B. */
(simplify
(cnd (logical_inverted_value truth_valued_p@0) @1 @2)
- (cnd @0 @2 @1)))
+ /* For CONDs, don't handle signed values here. */
+ (if (cnd == VEC_COND_EXPR
+ || TYPE_UNSIGNED (TREE_TYPE (@0)))
+ (cnd @0 @2 @1))))
-/* abs/negative simplifications moved from fold_cond_expr_with_comparison,
- Need to handle (A - B) case as fold_cond_expr_with_comparison does.
- Need to handle UN* comparisons.
+/* abs/negative simplifications moved from fold_cond_expr_with_comparison.
None of these transformations work for modes with signed
zeros. If A is +/-0, the first two transformations will
/* A == 0 ? A : -A same as -A */
(for cmp (eq uneq)
(simplify
- (cnd (cmp @0 zerop) @0 (negate@1 @0))
- (if (!HONOR_SIGNED_ZEROS (type))
+ (cnd (cmp @0 zerop) @2 (negate@1 @2))
+ (if (!HONOR_SIGNED_ZEROS (type)
+ && bitwise_equal_p (@0, @2))
@1))
(simplify
- (cnd (cmp @0 zerop) zerop (negate@1 @0))
- (if (!HONOR_SIGNED_ZEROS (type))
+ (cnd (cmp @0 zerop) zerop (negate@1 @2))
+ (if (!HONOR_SIGNED_ZEROS (type)
+ && bitwise_equal_p (@0, @2))
@1))
)
/* A != 0 ? A : -A same as A */
(for cmp (ne ltgt)
(simplify
- (cnd (cmp @0 zerop) @0 (negate @0))
- (if (!HONOR_SIGNED_ZEROS (type))
- @0))
+ (cnd (cmp @0 zerop) @1 (negate @1))
+ (if (!HONOR_SIGNED_ZEROS (type)
+ && bitwise_equal_p (@0, @1))
+ @1))
(simplify
- (cnd (cmp @0 zerop) @0 integer_zerop)
- (if (!HONOR_SIGNED_ZEROS (type))
- @0))
+ (cnd (cmp @0 zerop) @1 integer_zerop)
+ (if (!HONOR_SIGNED_ZEROS (type)
+ && bitwise_equal_p (@0, @1))
+ @1))
)
/* A >=/> 0 ? A : -A same as abs (A) */
(for cmp (ge gt)
(simplify
- (cnd (cmp @0 zerop) @0 (negate @0))
- (if (!HONOR_SIGNED_ZEROS (type)
- && !TYPE_UNSIGNED (type))
- (abs @0))))
+ (cnd (cmp @0 zerop) @1 (negate @1))
+ (if (!HONOR_SIGNED_ZEROS (TREE_TYPE(@0))
+ && !TYPE_UNSIGNED (TREE_TYPE(@0))
+ && bitwise_equal_p (@0, @1))
+ (if (TYPE_UNSIGNED (type))
+ (absu:type @0)
+ (abs @0)))))
/* A <=/< 0 ? A : -A same as -abs (A) */
(for cmp (le lt)
(simplify
- (cnd (cmp @0 zerop) @0 (negate @0))
- (if (!HONOR_SIGNED_ZEROS (type)
- && !TYPE_UNSIGNED (type))
- (if (ANY_INTEGRAL_TYPE_P (type)
- && !TYPE_OVERFLOW_WRAPS (type))
+ (cnd (cmp @0 zerop) @1 (negate @1))
+ (if (!HONOR_SIGNED_ZEROS (TREE_TYPE(@0))
+ && !TYPE_UNSIGNED (TREE_TYPE(@0))
+ && bitwise_equal_p (@0, @1))
+ (if ((ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
+ && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0)))
+ || TYPE_UNSIGNED (type))
(with {
- tree utype = unsigned_type_for (type);
+ tree utype = unsigned_type_for (TREE_TYPE(@0));
}
(convert (negate (absu:utype @0))))
(negate (abs @0)))))
)
+
+ /* (A - B) == 0 ? (A - B) : (B - A) same as (B - A) */
+ (for cmp (eq uneq)
+ (simplify
+ (cnd (cmp (minus@0 @1 @2) zerop) @0 (minus@3 @2 @1))
+ (if (!HONOR_SIGNED_ZEROS (type))
+ @3))
+ (simplify
+ (cnd (cmp (minus@0 @1 @2) integer_zerop) integer_zerop (minus@3 @2 @1))
+ @3)
+ )
+ /* (A - B) != 0 ? (A - B) : (B - A) same as (A - B) */
+ (for cmp (ne ltgt)
+ (simplify
+ (cnd (cmp (minus@0 @1 @2) zerop) @0 (minus @2 @1))
+ (if (!HONOR_SIGNED_ZEROS (type))
+ @0))
+ (simplify
+ (cnd (cmp (minus@0 @1 @2) integer_zerop) @0 integer_zerop)
+ @0)
+ )
+ /* (A - B) >=/> 0 ? (A - B) : (B - A) same as abs (A - B) */
+ (for cmp (ge gt)
+ (simplify
+ (cnd (cmp (minus@0 @1 @2) zerop) @0 (minus @2 @1))
+ (if (!HONOR_SIGNED_ZEROS (type)
+ && !TYPE_UNSIGNED (type))
+ (abs @0))))
+ /* (A - B) <=/< 0 ? (A - B) : (B - A) same as -abs (A - B) */
+ (for cmp (le lt)
+ (simplify
+ (cnd (cmp (minus@0 @1 @2) zerop) @0 (minus @2 @1))
+ (if (!HONOR_SIGNED_ZEROS (type)
+ && !TYPE_UNSIGNED (type))
+ (if (ANY_INTEGRAL_TYPE_P (type)
+ && !TYPE_OVERFLOW_WRAPS (type))
+ (with {
+ tree utype = unsigned_type_for (type);
+ }
+ (convert (negate (absu:utype @0))))
+ (negate (abs @0)))))
+ )
)
/* -(type)!A -> (type)A - 1. */
/* Fold ~X op ~Y as Y op X. */
(for cmp (simple_comparison)
(simplify
- (cmp (bit_not@2 @0) (bit_not@3 @1))
+ (cmp (nop_convert1?@4 (bit_not@2 @0)) (nop_convert2? (bit_not@3 @1)))
(if (single_use (@2) && single_use (@3))
- (cmp @1 @0))))
+ (with { tree otype = TREE_TYPE (@4); }
+ (cmp (convert:otype @1) (convert:otype @0))))))
/* Fold ~X op C as X op' ~C, where op' is the swapped comparison. */
(for cmp (simple_comparison)
scmp (swapped_simple_comparison)
(simplify
- (cmp (bit_not@2 @0) CONSTANT_CLASS_P@1)
+ (cmp (nop_convert? (bit_not@2 @0)) CONSTANT_CLASS_P@1)
(if (single_use (@2)
&& (TREE_CODE (@1) == INTEGER_CST || TREE_CODE (@1) == VECTOR_CST))
- (scmp @0 (bit_not @1)))))
+ (with { tree otype = TREE_TYPE (@1); }
+ (scmp (convert:otype @0) (bit_not @1))))))
(for cmp (simple_comparison)
(simplify
code and here to avoid a spurious overflow flag on the resulting
constant which fold_convert produces. */
(if (TREE_CODE (@1) == INTEGER_CST)
- (cmp @00 { force_fit_type (TREE_TYPE (@00), wi::to_widest (@1), 0,
- TREE_OVERFLOW (@1)); })
+ (cmp @00 { force_fit_type (TREE_TYPE (@00),
+ wide_int::from (wi::to_wide (@1),
+ MAX (TYPE_PRECISION (TREE_TYPE (@1)),
+ TYPE_PRECISION (TREE_TYPE (@00))),
+ TYPE_SIGN (TREE_TYPE (@1))),
+ 0, TREE_OVERFLOW (@1)); })
(cmp @00 (convert @1)))
(if (TYPE_PRECISION (TREE_TYPE (@0)) > TYPE_PRECISION (TREE_TYPE (@00)))
>= TYPE_PRECISION (TREE_TYPE (@10)))
&& (TYPE_UNSIGNED (TREE_TYPE (@00))
== TYPE_UNSIGNED (TREE_TYPE (@10))))
- || (TREE_CODE (@10) == INTEGER_CST
+ || (TREE_CODE (@1) == INTEGER_CST
&& INTEGRAL_TYPE_P (TREE_TYPE (@00))
- && int_fits_type_p (@10, TREE_TYPE (@00)))))
+ && int_fits_type_p (@1, TREE_TYPE (@00)))))
(cmp @00 (convert @10))
- (if (TREE_CODE (@10) == INTEGER_CST
+ (if (TREE_CODE (@1) == INTEGER_CST
&& INTEGRAL_TYPE_P (TREE_TYPE (@00))
- && !int_fits_type_p (@10, TREE_TYPE (@00)))
+ && !int_fits_type_p (@1, TREE_TYPE (@00)))
(with
{
tree min = lower_bound_in_type (TREE_TYPE (@10), TREE_TYPE (@00));
tree max = upper_bound_in_type (TREE_TYPE (@10), TREE_TYPE (@00));
- bool above = integer_nonzerop (const_binop (LT_EXPR, type, max, @10));
- bool below = integer_nonzerop (const_binop (LT_EXPR, type, @10, min));
+ bool above = integer_nonzerop (const_binop (LT_EXPR, type, max, @1));
+ bool below = integer_nonzerop (const_binop (LT_EXPR, type, @1, min));
}
(if (above || below)
(if (cmp == EQ_EXPR || cmp == NE_EXPR)
&& exact_real_truncate (TYPE_MODE (double_type_node), &orig))
type1 = double_type_node;
}
- tree newtype
- = (element_precision (TREE_TYPE (@00)) > element_precision (type1)
- ? TREE_TYPE (@00) : type1);
+ tree newtype
+ = (element_precision (TREE_TYPE (@00)) > element_precision (type1)
+ ? TREE_TYPE (@00) : type1);
}
- (if (element_precision (TREE_TYPE (@0)) > element_precision (newtype))
+ (if (element_precision (TREE_TYPE (@0)) > element_precision (newtype)
+ && (!VECTOR_TYPE_P (type) || is_truth_type_for (newtype, type)))
(cmp (convert:newtype @00) (convert:newtype @10))))))))
(cond @0 @1 @2)
(with { bool wascmp; }
(if (INTEGRAL_TYPE_P (type)
+ && TYPE_UNSIGNED (TREE_TYPE (@0))
&& bitwise_inverted_equal_p (@1, @2, wascmp)
- && (!wascmp || element_precision (type) == 1))
- (with {
- auto prec = TYPE_PRECISION (type);
- auto unsign = TYPE_UNSIGNED (type);
- tree inttype = build_nonstandard_integer_type (prec, unsign);
- }
- (convert (bit_xor (negate (convert:inttype @0)) (convert:inttype @2)))))))
+ && (!wascmp || TYPE_PRECISION (type) == 1))
+ (if ((!TYPE_UNSIGNED (type) && TREE_CODE (type) == BOOLEAN_TYPE)
+ || TYPE_PRECISION (type) == 1)
+ (bit_xor (convert:type @0) @2)
+ (bit_xor (negate (convert:type @0)) @2)))))
#endif
/* Simplify pointer equality compares using PTA. */
(COPYSIGN_ALL @0 tree_expr_nonnegative_p@1)
(abs @0))
+(simplify
+ /* fabs (copysign(x, y)) -> fabs (x). */
+ (abs (COPYSIGN_ALL @0 @1))
+ (abs @0))
+
(for scale (LDEXP SCALBN SCALBLN)
/* ldexp(0, x) -> 0. */
(simplify
(simplify
(BIT_FIELD_REF (view_convert @0) @1 @2)
- (BIT_FIELD_REF @0 @1 @2))
+ (if (! INTEGRAL_TYPE_P (TREE_TYPE (@0))
+ || type_has_mode_precision_p (TREE_TYPE (@0)))
+ (BIT_FIELD_REF @0 @1 @2)))
(simplify
(BIT_FIELD_REF @0 @1 integer_zerop)
(simplify
(bit_insert @0 (BIT_FIELD_REF@2 @1 @rsize @rpos) @ipos)
(if (VECTOR_TYPE_P (type)
+ && (VECTOR_MODE_P (TYPE_MODE (type))
+ || optimize_vectors_before_lowering_p ())
&& types_match (@0, @1)
&& types_match (TREE_TYPE (TREE_TYPE (@0)), TREE_TYPE (@2))
- && TYPE_VECTOR_SUBPARTS (type).is_constant ())
+ && TYPE_VECTOR_SUBPARTS (type).is_constant ()
+ && multiple_p (wi::to_poly_offset (@rpos),
+ wi::to_poly_offset (TYPE_SIZE (TREE_TYPE (type)))))
(with
{
unsigned HOST_WIDE_INT elsz
(op (clz:s@2 @0) INTEGER_CST@1)
(if (integer_zerop (@1) && single_use (@2))
/* clz(X) == 0 is (int)X < 0 and clz(X) != 0 is (int)X >= 0. */
- (with { tree type0 = TREE_TYPE (@0);
- tree stype = signed_type_for (type0);
- HOST_WIDE_INT val = 0;
- /* Punt on hypothetical weird targets. */
- if (clz == CFN_CLZ
- && CLZ_DEFINED_VALUE_AT_ZERO (SCALAR_TYPE_MODE (type0),
- val) == 2
- && val == 0)
- stype = NULL_TREE;
- }
- (if (stype)
- (cmp (convert:stype @0) { build_zero_cst (stype); })))
+ (with { tree stype = signed_type_for (TREE_TYPE (@0)); }
+ (cmp (convert:stype @0) { build_zero_cst (stype); }))
/* clz(X) == (prec-1) is X == 1 and clz(X) != (prec-1) is X != 1. */
- (with { bool ok = true;
- HOST_WIDE_INT val = 0;
- tree type0 = TREE_TYPE (@0);
- /* Punt on hypothetical weird targets. */
- if (clz == CFN_CLZ
- && CLZ_DEFINED_VALUE_AT_ZERO (SCALAR_TYPE_MODE (type0),
- val) == 2
- && val == TYPE_PRECISION (type0) - 1)
- ok = false;
- }
- (if (ok && wi::to_wide (@1) == (TYPE_PRECISION (type0) - 1))
- (op @0 { build_one_cst (type0); })))))))
+ (if (wi::to_wide (@1) == TYPE_PRECISION (TREE_TYPE (@0)) - 1)
+ (op @0 { build_one_cst (TREE_TYPE (@0)); }))))))
+(for op (eq ne)
+ cmp (lt ge)
+ (simplify
+ (op (IFN_CLZ:s@2 @0 @3) INTEGER_CST@1)
+ (if (integer_zerop (@1) && single_use (@2))
+ /* clz(X) == 0 is (int)X < 0 and clz(X) != 0 is (int)X >= 0. */
+ (with { tree type0 = TREE_TYPE (@0);
+ tree stype = signed_type_for (TREE_TYPE (@0));
+ /* Punt if clz(0) == 0. */
+ if (integer_zerop (@3))
+ stype = NULL_TREE;
+ }
+ (if (stype)
+ (cmp (convert:stype @0) { build_zero_cst (stype); })))
+ /* clz(X) == (prec-1) is X == 1 and clz(X) != (prec-1) is X != 1. */
+ (with { bool ok = true;
+ tree type0 = TREE_TYPE (@0);
+ /* Punt if clz(0) == prec - 1. */
+ if (wi::to_widest (@3) == TYPE_PRECISION (type0) - 1)
+ ok = false;
+ }
+ (if (ok && wi::to_wide (@1) == (TYPE_PRECISION (type0) - 1))
+ (op @0 { build_one_cst (type0); }))))))
/* CTZ simplifications. */
(for ctz (CTZ)
val++;
}
}
- bool zero_res = false;
- HOST_WIDE_INT zero_val = 0;
tree type0 = TREE_TYPE (@0);
int prec = TYPE_PRECISION (type0);
- if (ctz == CFN_CTZ
- && CTZ_DEFINED_VALUE_AT_ZERO (SCALAR_TYPE_MODE (type0),
- zero_val) == 2)
- zero_res = true;
}
- (if (val <= 0)
- (if (ok && (!zero_res || zero_val >= val))
- { constant_boolean_node (cmp == EQ_EXPR ? true : false, type); })
- (if (val >= prec)
- (if (ok && (!zero_res || zero_val < val))
- { constant_boolean_node (cmp == EQ_EXPR ? false : true, type); })
- (if (ok && (!zero_res || zero_val < 0 || zero_val >= prec))
+ (if (ok && prec <= MAX_FIXED_MODE_SIZE)
+ (if (val <= 0)
+ { constant_boolean_node (cmp == EQ_EXPR ? true : false, type); }
+ (if (val >= prec)
+ { constant_boolean_node (cmp == EQ_EXPR ? false : true, type); }
(cmp (bit_and @0 { wide_int_to_tree (type0,
wi::mask (val, false, prec)); })
{ build_zero_cst (type0); })))))))
(simplify
/* __builtin_ctz (x) == C -> (x & ((1 << (C + 1)) - 1)) == (1 << C). */
(op (ctz:s @0) INTEGER_CST@1)
- (with { bool zero_res = false;
- HOST_WIDE_INT zero_val = 0;
- tree type0 = TREE_TYPE (@0);
+ (with { tree type0 = TREE_TYPE (@0);
int prec = TYPE_PRECISION (type0);
- if (ctz == CFN_CTZ
- && CTZ_DEFINED_VALUE_AT_ZERO (SCALAR_TYPE_MODE (type0),
- zero_val) == 2)
- zero_res = true;
}
+ (if (prec <= MAX_FIXED_MODE_SIZE)
+ (if (tree_int_cst_sgn (@1) < 0 || wi::to_widest (@1) >= prec)
+ { constant_boolean_node (op == EQ_EXPR ? false : true, type); }
+ (op (bit_and @0 { wide_int_to_tree (type0,
+ wi::mask (tree_to_uhwi (@1) + 1,
+ false, prec)); })
+ { wide_int_to_tree (type0,
+ wi::shifted_mask (tree_to_uhwi (@1), 1,
+ false, prec)); })))))))
+(for op (ge gt le lt)
+ cmp (eq eq ne ne)
+ (simplify
+ /* __builtin_ctz (x) >= C -> (x & ((1 << C) - 1)) == 0. */
+ (op (IFN_CTZ:s @0 @2) INTEGER_CST@1)
+ (with { bool ok = true;
+ HOST_WIDE_INT val = 0;
+ if (!tree_fits_shwi_p (@1))
+ ok = false;
+ else
+ {
+ val = tree_to_shwi (@1);
+ /* Canonicalize to >= or <. */
+ if (op == GT_EXPR || op == LE_EXPR)
+ {
+ if (val == HOST_WIDE_INT_MAX)
+ ok = false;
+ else
+ val++;
+ }
+ }
+ HOST_WIDE_INT zero_val = tree_to_shwi (@2);
+ tree type0 = TREE_TYPE (@0);
+ int prec = TYPE_PRECISION (type0);
+ if (prec > MAX_FIXED_MODE_SIZE)
+ ok = false;
+ }
+ (if (val <= 0)
+ (if (ok && zero_val >= val)
+ { constant_boolean_node (cmp == EQ_EXPR ? true : false, type); })
+ (if (val >= prec)
+ (if (ok && zero_val < val)
+ { constant_boolean_node (cmp == EQ_EXPR ? false : true, type); })
+ (if (ok && (zero_val < 0 || zero_val >= prec))
+ (cmp (bit_and @0 { wide_int_to_tree (type0,
+ wi::mask (val, false, prec)); })
+ { build_zero_cst (type0); })))))))
+(for op (eq ne)
+ (simplify
+ /* __builtin_ctz (x) == C -> (x & ((1 << (C + 1)) - 1)) == (1 << C). */
+ (op (IFN_CTZ:s @0 @2) INTEGER_CST@1)
+ (with { HOST_WIDE_INT zero_val = tree_to_shwi (@2);
+ tree type0 = TREE_TYPE (@0);
+ int prec = TYPE_PRECISION (type0);
+ }
+ (if (prec <= MAX_FIXED_MODE_SIZE)
(if (tree_int_cst_sgn (@1) < 0 || wi::to_widest (@1) >= prec)
- (if (!zero_res || zero_val != wi::to_widest (@1))
+ (if (zero_val != wi::to_widest (@1))
{ constant_boolean_node (op == EQ_EXPR ? false : true, type); })
- (if (!zero_res || zero_val < 0 || zero_val >= prec)
+ (if (zero_val < 0 || zero_val >= prec)
(op (bit_and @0 { wide_int_to_tree (type0,
wi::mask (tree_to_uhwi (@1) + 1,
false, prec)); })
wi::shifted_mask (tree_to_uhwi (@1), 1,
false, prec)); })))))))
+#if GIMPLE
+/* ctz(ext(X)) == ctz(X). Valid just for the UB at zero cases though. */
+(simplify
+ (CTZ (convert@1 @0))
+ (if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
+ && INTEGRAL_TYPE_P (TREE_TYPE (@0))
+ && TYPE_PRECISION (TREE_TYPE (@1)) > TYPE_PRECISION (TREE_TYPE (@0)))
+ (with { combined_fn cfn = CFN_LAST;
+ tree type0 = TREE_TYPE (@0);
+ if (TREE_CODE (type0) == BITINT_TYPE)
+ {
+ if (TYPE_PRECISION (type0) > MAX_FIXED_MODE_SIZE)
+ cfn = CFN_CTZ;
+ else
+ type0
+ = build_nonstandard_integer_type (TYPE_PRECISION (type0),
+ 1);
+ }
+ type0 = unsigned_type_for (type0);
+ if (cfn == CFN_LAST
+ && direct_internal_fn_supported_p (IFN_CTZ, type0,
+ OPTIMIZE_FOR_BOTH))
+ cfn = CFN_CTZ;
+ if (cfn == CFN_LAST
+ && TYPE_PRECISION (TREE_TYPE (@1)) > BITS_PER_WORD
+ && !direct_internal_fn_supported_p (IFN_CTZ,
+ TREE_TYPE (@1),
+ OPTIMIZE_FOR_BOTH))
+ {
+ if (TYPE_PRECISION (type0)
+ == TYPE_PRECISION (unsigned_type_node))
+ cfn = CFN_BUILT_IN_CTZ;
+ else if (TYPE_PRECISION (type0)
+ == TYPE_PRECISION (long_long_unsigned_type_node))
+ cfn = CFN_BUILT_IN_CTZLL;
+ } }
+ (if (cfn == CFN_CTZ)
+ (IFN_CTZ (convert:type0 @0))
+ (if (cfn == CFN_BUILT_IN_CTZ)
+ (BUILT_IN_CTZ (convert:type0 @0))
+ (if (cfn == CFN_BUILT_IN_CTZLL)
+ (BUILT_IN_CTZLL (convert:type0 @0))))))))
+#endif
+
/* POPCOUNT simplifications. */
/* popcount(X) + popcount(Y) is popcount(X|Y) when X&Y must be zero. */
(simplify
(plus (POPCOUNT:s @0) (POPCOUNT:s @1))
(if (INTEGRAL_TYPE_P (type)
- && wi::bit_and (tree_nonzero_bits (@0), tree_nonzero_bits (@1)) == 0)
- (POPCOUNT (bit_ior @0 @1))))
+ && (wi::bit_and (widest_int::from (tree_nonzero_bits (@0), UNSIGNED),
+ widest_int::from (tree_nonzero_bits (@1), UNSIGNED))
+ == 0))
+ (with { tree utype = TREE_TYPE (@0);
+ if (TYPE_PRECISION (utype) < TYPE_PRECISION (TREE_TYPE (@1)))
+ utype = TREE_TYPE (@1); }
+ (POPCOUNT (bit_ior (convert:utype @0) (convert:utype @1))))))
/* popcount(X) == 0 is X == 0, and related (in)equalities. */
(for popcount (POPCOUNT)
/* popcount(X&Y) + popcount(X|Y) is popcount(x) + popcount(Y). */
(simplify
(plus:c (POPCOUNT:s (bit_and:s @0 @1)) (POPCOUNT:s (bit_ior:cs @0 @1)))
- (plus (POPCOUNT @0) (POPCOUNT @1)))
+ (plus (POPCOUNT:type @0) (POPCOUNT:type @1)))
/* popcount(X) + popcount(Y) - popcount(X&Y) is popcount(X|Y). */
/* popcount(X) + popcount(Y) - popcount(X|Y) is popcount(X&Y). */
(popcount:s @1))
(popcount (log2 @0 @1)))))
+#if GIMPLE
+/* popcount(zext(X)) == popcount(X). */
+(simplify
+ (POPCOUNT (convert@1 @0))
+ (if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
+ && INTEGRAL_TYPE_P (TREE_TYPE (@0))
+ && TYPE_UNSIGNED (TREE_TYPE (@0))
+ && TYPE_PRECISION (TREE_TYPE (@1)) > TYPE_PRECISION (TREE_TYPE (@0)))
+ (with { combined_fn cfn = CFN_LAST;
+ tree type0 = TREE_TYPE (@0);
+ if (TREE_CODE (type0) == BITINT_TYPE)
+ {
+ if (TYPE_PRECISION (type0) > MAX_FIXED_MODE_SIZE)
+ cfn = CFN_POPCOUNT;
+ else
+ type0
+ = build_nonstandard_integer_type (TYPE_PRECISION (type0),
+ 1);
+ }
+ if (cfn == CFN_LAST
+ && direct_internal_fn_supported_p (IFN_POPCOUNT, type0,
+ OPTIMIZE_FOR_BOTH))
+ cfn = CFN_POPCOUNT;
+ if (cfn == CFN_LAST
+ && TYPE_PRECISION (TREE_TYPE (@1)) > BITS_PER_WORD
+ && !direct_internal_fn_supported_p (IFN_POPCOUNT,
+ TREE_TYPE (@1),
+ OPTIMIZE_FOR_BOTH))
+ {
+ if (TYPE_PRECISION (type0)
+ == TYPE_PRECISION (unsigned_type_node))
+ cfn = CFN_BUILT_IN_POPCOUNT;
+ else if (TYPE_PRECISION (type0)
+ == TYPE_PRECISION (long_long_unsigned_type_node))
+ cfn = CFN_BUILT_IN_POPCOUNTLL;
+ } }
+ (if (cfn == CFN_POPCOUNT)
+ (IFN_POPCOUNT (convert:type0 @0))
+ (if (cfn == CFN_BUILT_IN_POPCOUNT)
+ (BUILT_IN_POPCOUNT (convert:type0 @0))
+ (if (cfn == CFN_BUILT_IN_POPCOUNTLL)
+ (BUILT_IN_POPCOUNTLL (convert:type0 @0))))))))
+#endif
+
/* PARITY simplifications. */
/* parity(~X) is parity(X). */
(simplify
/* parity(X)^parity(Y) is parity(X^Y). */
(simplify
(bit_xor (PARITY:s @0) (PARITY:s @1))
- (PARITY (bit_xor @0 @1)))
+ (if (types_match (TREE_TYPE (@0), TREE_TYPE (@1)))
+ (PARITY (bit_xor @0 @1))
+ (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
+ && INTEGRAL_TYPE_P (TREE_TYPE (@1)))
+ (with { tree utype = TREE_TYPE (@0);
+ if (TYPE_PRECISION (utype) < TYPE_PRECISION (TREE_TYPE (@1)))
+ utype = TREE_TYPE (@1); }
+ (PARITY (bit_xor (convert:utype @0) (convert:utype @1)))))))
+
+#if GIMPLE
+/* parity(zext(X)) == parity(X). */
+/* parity(sext(X)) == parity(X) if the difference in precision is even. */
+(simplify
+ (PARITY (convert@1 @0))
+ (if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
+ && INTEGRAL_TYPE_P (TREE_TYPE (@0))
+ && TYPE_PRECISION (TREE_TYPE (@1)) > TYPE_PRECISION (TREE_TYPE (@0))
+ && (TYPE_UNSIGNED (TREE_TYPE (@0))
+ || ((TYPE_PRECISION (TREE_TYPE (@1))
+ - TYPE_PRECISION (TREE_TYPE (@0))) & 1) == 0))
+ (with { combined_fn cfn = CFN_LAST;
+ tree type0 = TREE_TYPE (@0);
+ if (TREE_CODE (type0) == BITINT_TYPE)
+ {
+ if (TYPE_PRECISION (type0) > MAX_FIXED_MODE_SIZE)
+ cfn = CFN_PARITY;
+ else
+ type0
+ = build_nonstandard_integer_type (TYPE_PRECISION (type0),
+ 1);
+ }
+ type0 = unsigned_type_for (type0);
+ if (cfn == CFN_LAST
+ && direct_internal_fn_supported_p (IFN_PARITY, type0,
+ OPTIMIZE_FOR_BOTH))
+ cfn = CFN_PARITY;
+ if (cfn == CFN_LAST
+ && TYPE_PRECISION (TREE_TYPE (@1)) > BITS_PER_WORD
+ && !direct_internal_fn_supported_p (IFN_PARITY,
+ TREE_TYPE (@1),
+ OPTIMIZE_FOR_BOTH))
+ {
+ if (TYPE_PRECISION (type0)
+ == TYPE_PRECISION (unsigned_type_node))
+ cfn = CFN_BUILT_IN_PARITY;
+ else if (TYPE_PRECISION (type0)
+ == TYPE_PRECISION (long_long_unsigned_type_node))
+ cfn = CFN_BUILT_IN_PARITYLL;
+ } }
+ (if (cfn == CFN_PARITY)
+ (IFN_PARITY (convert:type0 @0))
+ (if (cfn == CFN_BUILT_IN_PARITY)
+ (BUILT_IN_PARITY (convert:type0 @0))
+ (if (cfn == CFN_BUILT_IN_PARITYLL)
+ (BUILT_IN_PARITYLL (convert:type0 @0))))))))
+#endif
/* a != 0 ? FUN(a) : 0 -> Fun(a) for some builtin functions. */
(for func (POPCOUNT BSWAP FFS PARITY)
(cond (ne @0 integer_zerop@1) (func (convert?@3 @0)) INTEGER_CST@2)
(with { int val;
internal_fn ifn = IFN_LAST;
- if (direct_internal_fn_supported_p (IFN_CLZ, type, OPTIMIZE_FOR_BOTH)
- && CLZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (type),
- val) == 2)
+ if (TREE_CODE (TREE_TYPE (@3)) == BITINT_TYPE)
+ {
+ if (tree_fits_shwi_p (@2))
+ {
+ HOST_WIDE_INT valw = tree_to_shwi (@2);
+ if ((int) valw == valw)
+ {
+ val = valw;
+ ifn = IFN_CLZ;
+ }
+ }
+ }
+ else if (direct_internal_fn_supported_p (IFN_CLZ, TREE_TYPE (@3),
+ OPTIMIZE_FOR_BOTH)
+ && CLZ_DEFINED_VALUE_AT_ZERO
+ (SCALAR_INT_TYPE_MODE (TREE_TYPE (@3)), val) == 2)
ifn = IFN_CLZ;
}
(if (ifn == IFN_CLZ && wi::to_widest (@2) == val)
- (IFN_CLZ @3)))))
+ (IFN_CLZ @3 @2)))))
+(simplify
+ (cond (ne @0 integer_zerop@1) (IFN_CLZ (convert?@3 @0) INTEGER_CST@2) @2)
+ (with { int val;
+ internal_fn ifn = IFN_LAST;
+ if (TREE_CODE (TREE_TYPE (@3)) == BITINT_TYPE)
+ ifn = IFN_CLZ;
+ else if (direct_internal_fn_supported_p (IFN_CLZ, TREE_TYPE (@3),
+ OPTIMIZE_FOR_BOTH))
+ ifn = IFN_CLZ;
+ }
+ (if (ifn == IFN_CLZ)
+ (IFN_CLZ @3 @2))))
/* a != 0 ? CTZ(a) : CST -> .CTZ(a) where CST is the result of the internal function for 0. */
(for func (CTZ)
(cond (ne @0 integer_zerop@1) (func (convert?@3 @0)) INTEGER_CST@2)
(with { int val;
internal_fn ifn = IFN_LAST;
- if (direct_internal_fn_supported_p (IFN_CTZ, type, OPTIMIZE_FOR_BOTH)
- && CTZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (type),
- val) == 2)
+ if (TREE_CODE (TREE_TYPE (@3)) == BITINT_TYPE)
+ {
+ if (tree_fits_shwi_p (@2))
+ {
+ HOST_WIDE_INT valw = tree_to_shwi (@2);
+ if ((int) valw == valw)
+ {
+ val = valw;
+ ifn = IFN_CTZ;
+ }
+ }
+ }
+ else if (direct_internal_fn_supported_p (IFN_CTZ, TREE_TYPE (@3),
+ OPTIMIZE_FOR_BOTH)
+ && CTZ_DEFINED_VALUE_AT_ZERO
+ (SCALAR_INT_TYPE_MODE (TREE_TYPE (@3)), val) == 2)
ifn = IFN_CTZ;
}
(if (ifn == IFN_CTZ && wi::to_widest (@2) == val)
- (IFN_CTZ @3)))))
+ (IFN_CTZ @3 @2)))))
+(simplify
+ (cond (ne @0 integer_zerop@1) (IFN_CTZ (convert?@3 @0) INTEGER_CST@2) @2)
+ (with { int val;
+ internal_fn ifn = IFN_LAST;
+ if (TREE_CODE (TREE_TYPE (@3)) == BITINT_TYPE)
+ ifn = IFN_CTZ;
+ else if (direct_internal_fn_supported_p (IFN_CTZ, TREE_TYPE (@3),
+ OPTIMIZE_FOR_BOTH))
+ ifn = IFN_CTZ;
+ }
+ (if (ifn == IFN_CTZ)
+ (IFN_CTZ @3 @2))))
#endif
/* Common POPCOUNT/PARITY simplifications. */
(plus (CTZ:type (convert:utype @0)) { build_one_cst (type); }))))
#endif
-(for ffs (BUILT_IN_FFS BUILT_IN_FFSL BUILT_IN_FFSLL
- BUILT_IN_FFSIMAX)
+(for ffs (FFS)
/* __builtin_ffs (X) == 0 -> X == 0.
__builtin_ffs (X) == 6 -> (X & 63) == 32. */
(for cmp (eq ne)
false, prec)); })
{ build_zero_cst (TREE_TYPE (@0)); }))))))))
+#if GIMPLE
+/* ffs(ext(X)) == ffs(X). */
+(simplify
+ (FFS (convert@1 @0))
+ (if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
+ && INTEGRAL_TYPE_P (TREE_TYPE (@0))
+ && TYPE_PRECISION (TREE_TYPE (@1)) > TYPE_PRECISION (TREE_TYPE (@0)))
+ (with { combined_fn cfn = CFN_LAST;
+ tree type0 = TREE_TYPE (@0);
+ if (TREE_CODE (type0) == BITINT_TYPE)
+ {
+ if (TYPE_PRECISION (type0) > MAX_FIXED_MODE_SIZE)
+ cfn = CFN_FFS;
+ else
+ type0
+ = build_nonstandard_integer_type (TYPE_PRECISION (type0),
+ 0);
+ }
+ type0 = signed_type_for (type0);
+ if (cfn == CFN_LAST
+ && direct_internal_fn_supported_p (IFN_FFS, type0,
+ OPTIMIZE_FOR_BOTH))
+ cfn = CFN_FFS;
+ if (cfn == CFN_LAST
+ && TYPE_PRECISION (TREE_TYPE (@1)) > BITS_PER_WORD
+ && !direct_internal_fn_supported_p (IFN_FFS,
+ TREE_TYPE (@1),
+ OPTIMIZE_FOR_BOTH))
+ {
+ if (TYPE_PRECISION (type0)
+ == TYPE_PRECISION (integer_type_node))
+ cfn = CFN_BUILT_IN_FFS;
+ else if (TYPE_PRECISION (type0)
+ == TYPE_PRECISION (long_long_integer_type_node))
+ cfn = CFN_BUILT_IN_FFSLL;
+ } }
+ (if (cfn == CFN_FFS)
+ (IFN_FFS (convert:type0 @0))
+ (if (cfn == CFN_BUILT_IN_FFS)
+ (BUILT_IN_FFS (convert:type0 @0))
+ (if (cfn == CFN_BUILT_IN_FFSLL)
+ (BUILT_IN_FFSLL (convert:type0 @0))))))))
+#endif
+
#if GIMPLE
/* Simplify:
(with { tree op_type = TREE_TYPE (@3); }
(if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
&& is_truth_type_for (op_type, TREE_TYPE (@0)))
- (cond_op @0 @1 @2))))
+ (cond_op @0 (view_convert @1) @2))))
(simplify
(vec_cond @0 @1 (view_convert? (uncond_op@3 @2)))
(with { tree op_type = TREE_TYPE (@3); }
(if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
&& is_truth_type_for (op_type, TREE_TYPE (@0)))
- (cond_op (bit_not @0) @2 @1)))))
+ (cond_op (bit_not @0) (view_convert @2) @1)))))
+
+(for uncond_op (UNCOND_UNARY)
+ cond_op (COND_LEN_UNARY)
+ (simplify
+ (IFN_VCOND_MASK_LEN @0 (view_convert? (uncond_op@3 @1)) @2 @4 @5)
+ (with { tree op_type = TREE_TYPE (@3); }
+ (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+ && is_truth_type_for (op_type, TREE_TYPE (@0)))
+ (cond_op @0 (view_convert @1) @2 @4 @5))))
+ (simplify
+ (IFN_VCOND_MASK_LEN @0 @1 (view_convert? (uncond_op@3 @2)) @4 @5)
+ (with { tree op_type = TREE_TYPE (@3); }
+ (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+ && is_truth_type_for (op_type, TREE_TYPE (@0)))
+ (cond_op (bit_not @0) (view_convert @2) @1 @4 @5)))))
/* `(a ? -1 : 0) ^ b` can be converted into a conditional not. */
(simplify
&& single_use (@4))
(view_convert (cond_op (bit_not @0) @2 @3 (view_convert:op_type @1)))))))
+(for uncond_op (UNCOND_BINARY)
+ cond_op (COND_LEN_BINARY)
+ (simplify
+ (IFN_VCOND_MASK_LEN @0 (view_convert? (uncond_op@4 @1 @2)) @3 @5 @6)
+ (with { tree op_type = TREE_TYPE (@4); }
+ (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+ && is_truth_type_for (op_type, TREE_TYPE (@0))
+ && single_use (@4))
+ (view_convert (cond_op @0 @1 @2 (view_convert:op_type @3) @5 @6)))))
+ (simplify
+ (IFN_VCOND_MASK_LEN @0 @1 (view_convert? (uncond_op@4 @2 @3)) @5 @6)
+ (with { tree op_type = TREE_TYPE (@4); }
+ (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+ && is_truth_type_for (op_type, TREE_TYPE (@0))
+ && single_use (@4))
+ (view_convert (cond_op (bit_not @0) @2 @3 (view_convert:op_type @1) @5 @6))))))
+
/* Same for ternary operations. */
(for uncond_op (UNCOND_TERNARY)
cond_op (COND_TERNARY)
&& single_use (@5))
(view_convert (cond_op (bit_not @0) @2 @3 @4
(view_convert:op_type @1)))))))
+
+(for uncond_op (UNCOND_TERNARY)
+ cond_op (COND_LEN_TERNARY)
+ (simplify
+ (IFN_VCOND_MASK_LEN @0 (view_convert? (uncond_op@5 @1 @2 @3)) @4 @6 @7)
+ (with { tree op_type = TREE_TYPE (@5); }
+ (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+ && is_truth_type_for (op_type, TREE_TYPE (@0))
+ && single_use (@5))
+ (view_convert (cond_op @0 @1 @2 @3 (view_convert:op_type @4) @6 @7)))))
+ (simplify
+ (IFN_VCOND_MASK_LEN @0 @1 (view_convert? (uncond_op@5 @2 @3 @4 @6 @7)))
+ (with { tree op_type = TREE_TYPE (@5); }
+ (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+ && is_truth_type_for (op_type, TREE_TYPE (@0))
+ && single_use (@5))
+ (view_convert (cond_op (bit_not @0) @2 @3 @4 (view_convert:op_type @1) @6 @7))))))
#endif
/* Detect cases in which a VEC_COND_EXPR effectively replaces the
&& element_precision (type) == element_precision (op_type))
(view_convert (cond_op @2 @3 @4 @5 (view_convert:op_type @1)))))))
+/* Detect cases in which a VEC_COND_EXPR effectively replaces the
+ "else" value of an IFN_COND_LEN_*. */
+(for cond_len_op (COND_LEN_BINARY)
+ (simplify
+ (vec_cond @0 (view_convert? (cond_len_op @0 @1 @2 @3 @4 @5)) @6)
+ (with { tree op_type = TREE_TYPE (@3); }
+ (if (element_precision (type) == element_precision (op_type))
+ (view_convert (cond_len_op @0 @1 @2 (view_convert:op_type @6) @4 @5)))))
+ (simplify
+ (vec_cond @0 @1 (view_convert? (cond_len_op @2 @3 @4 @5 @6 @7)))
+ (with { tree op_type = TREE_TYPE (@5); }
+ (if (inverse_conditions_p (@0, @2)
+ && element_precision (type) == element_precision (op_type))
+ (view_convert (cond_len_op @2 @3 @4 (view_convert:op_type @1) @6 @7))))))
+
+/* Same for ternary operations. */
+(for cond_len_op (COND_LEN_TERNARY)
+ (simplify
+ (vec_cond @0 (view_convert? (cond_len_op @0 @1 @2 @3 @4 @5 @6)) @7)
+ (with { tree op_type = TREE_TYPE (@4); }
+ (if (element_precision (type) == element_precision (op_type))
+ (view_convert (cond_len_op @0 @1 @2 @3 (view_convert:op_type @7) @5 @6)))))
+ (simplify
+ (vec_cond @0 @1 (view_convert? (cond_len_op @2 @3 @4 @5 @6 @7 @8)))
+ (with { tree op_type = TREE_TYPE (@6); }
+ (if (inverse_conditions_p (@0, @2)
+ && element_precision (type) == element_precision (op_type))
+ (view_convert (cond_len_op @2 @3 @4 @5 (view_convert:op_type @1) @7 @8))))))
+
/* Detect simplication for a conditional reduction where
a = mask1 ? b : 0
c = mask1 && mask2 ? d + b : d. */
(simplify
- (IFN_COND_ADD @0 @1 (vec_cond @2 @3 integer_zerop) @1)
- (IFN_COND_ADD (bit_and @0 @2) @1 @3 @1))
+ (IFN_COND_ADD @0 @1 (vec_cond @2 @3 zerop@4) @1)
+ (if (ANY_INTEGRAL_TYPE_P (type)
+ || (FLOAT_TYPE_P (type)
+ && fold_real_zero_addition_p (type, NULL_TREE, @4, 0)))
+ (IFN_COND_ADD (bit_and @0 @2) @1 @3 @1)))
+
+/* Detect simplication for a conditional length reduction where
+
+ a = mask ? b : 0
+ c = i < len + bias ? d + a : d
+
+ is turned into
+
+ c = mask && i < len + bias ? d + b : d. */
+(simplify
+ (IFN_COND_LEN_ADD integer_truep @0 (vec_cond @1 @2 zerop@5) @0 @3 @4)
+ (if (ANY_INTEGRAL_TYPE_P (type)
+ || (FLOAT_TYPE_P (type)
+ && fold_real_zero_addition_p (type, NULL_TREE, @5, 0)))
+ (IFN_COND_LEN_ADD @1 @0 @2 @0 @3 @4)))
+
+/* Detect simplification for vector condition folding where
+
+ c = mask1 ? (masked_op mask2 a b els) : els
+
+ into
+
+ c = masked_op (mask1 & mask2) a b els
+
+ where the operation can be partially applied to one operand. */
+
+(for cond_op (COND_BINARY)
+ (simplify
+ (vec_cond @0
+ (cond_op:s @1 @2 @3 @4) @4)
+ (cond_op (bit_and @1 @0) @2 @3 @4)))
+
+/* And same for ternary expressions. */
+
+(for cond_op (COND_TERNARY)
+ (simplify
+ (vec_cond @0
+ (cond_op:s @1 @2 @3 @4 @5) @5)
+ (cond_op (bit_and @1 @0) @2 @3 @4 @5)))
/* For pointers @0 and @2 and nonnegative constant offset @1, look for
expressions like:
d = VEC_PERM_EXPR <a, b, NEW_VCST>; */
(simplify
- (vec_perm (vec_perm@0 @1 @2 VECTOR_CST@3) @0 VECTOR_CST@4)
+ (vec_perm (view_convert?@0 (vec_perm@1 @2 @3 VECTOR_CST@4)) @0 VECTOR_CST@5)
(if (TYPE_VECTOR_SUBPARTS (type).is_constant ())
(with
{
machine_mode result_mode = TYPE_MODE (type);
- machine_mode op_mode = TYPE_MODE (TREE_TYPE (@1));
+ machine_mode op_mode = TYPE_MODE (TREE_TYPE (@2));
int nelts = TYPE_VECTOR_SUBPARTS (type).to_constant ();
vec_perm_builder builder0;
vec_perm_builder builder1;
vec_perm_builder builder2 (nelts, nelts, 1);
}
- (if (tree_to_vec_perm_builder (&builder0, @3)
- && tree_to_vec_perm_builder (&builder1, @4))
+ (if (tree_to_vec_perm_builder (&builder0, @4)
+ && tree_to_vec_perm_builder (&builder1, @5)
+ && TYPE_SIZE (TREE_TYPE (TREE_TYPE (@0)))
+ == TYPE_SIZE (TREE_TYPE (TREE_TYPE (@1))))
(with
{
vec_perm_indices sel0 (builder0, 2, nelts);
? (!can_vec_perm_const_p (result_mode, op_mode, sel0, false)
|| !can_vec_perm_const_p (result_mode, op_mode, sel1, false))
: !can_vec_perm_const_p (result_mode, op_mode, sel1, false)))
- op0 = vec_perm_indices_to_tree (TREE_TYPE (@4), sel2);
+ op0 = vec_perm_indices_to_tree (TREE_TYPE (@5), sel2);
}
(if (op0)
- (vec_perm @1 @2 { op0; })))))))
+ (view_convert (vec_perm @2 @3 { op0; }))))))))
/* Merge
c = VEC_PERM_EXPR <a, b, VCST0>;