(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.
|| !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
/* 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 (wi::to_wide (@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)
(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 == 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))
(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; }))))))))))