mirror of
https://github.com/autc04/Retro68.git
synced 2024-12-22 04:30:03 +00:00
7764 lines
264 KiB
Plaintext
7764 lines
264 KiB
Plaintext
/* Match-and-simplify patterns for shared GENERIC and GIMPLE folding.
|
|
This file is consumed by genmatch which produces gimple-match.cc
|
|
and generic-match.cc from it.
|
|
|
|
Copyright (C) 2014-2022 Free Software Foundation, Inc.
|
|
Contributed by Richard Biener <rguenther@suse.de>
|
|
and Prathamesh Kulkarni <bilbotheelffriend@gmail.com>
|
|
|
|
This file is part of GCC.
|
|
|
|
GCC is free software; you can redistribute it and/or modify it under
|
|
the terms of the GNU General Public License as published by the Free
|
|
Software Foundation; either version 3, or (at your option) any later
|
|
version.
|
|
|
|
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GCC; see the file COPYING3. If not see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
|
|
/* Generic tree predicates we inherit. */
|
|
(define_predicates
|
|
integer_onep integer_zerop integer_all_onesp integer_minus_onep
|
|
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
|
|
uniform_vector_p
|
|
expand_vec_cmp_expr_p
|
|
bitmask_inv_cst_vector_p)
|
|
|
|
/* Operator lists. */
|
|
(define_operator_list tcc_comparison
|
|
lt le eq ne ge gt unordered ordered unlt unle ungt unge uneq ltgt)
|
|
(define_operator_list inverted_tcc_comparison
|
|
ge gt ne eq lt le ordered unordered ge gt le lt ltgt uneq)
|
|
(define_operator_list inverted_tcc_comparison_with_nans
|
|
unge ungt ne eq unlt unle ordered unordered ge gt le lt ltgt uneq)
|
|
(define_operator_list swapped_tcc_comparison
|
|
gt ge eq ne le lt unordered ordered ungt unge unlt unle uneq ltgt)
|
|
(define_operator_list simple_comparison lt le eq ne ge gt)
|
|
(define_operator_list swapped_simple_comparison gt ge eq ne le lt)
|
|
|
|
#include "cfn-operators.pd"
|
|
|
|
/* Define operand lists for math rounding functions {,i,l,ll}FN,
|
|
where the versions prefixed with "i" return an int, those prefixed with
|
|
"l" return a long and those prefixed with "ll" return a long long.
|
|
|
|
Also define operand lists:
|
|
|
|
X<FN>F for all float functions, in the order i, l, ll
|
|
X<FN> for all double functions, in the same order
|
|
X<FN>L for all long double functions, in the same order. */
|
|
#define DEFINE_INT_AND_FLOAT_ROUND_FN(FN) \
|
|
(define_operator_list X##FN##F BUILT_IN_I##FN##F \
|
|
BUILT_IN_L##FN##F \
|
|
BUILT_IN_LL##FN##F) \
|
|
(define_operator_list X##FN BUILT_IN_I##FN \
|
|
BUILT_IN_L##FN \
|
|
BUILT_IN_LL##FN) \
|
|
(define_operator_list X##FN##L BUILT_IN_I##FN##L \
|
|
BUILT_IN_L##FN##L \
|
|
BUILT_IN_LL##FN##L)
|
|
|
|
DEFINE_INT_AND_FLOAT_ROUND_FN (FLOOR)
|
|
DEFINE_INT_AND_FLOAT_ROUND_FN (CEIL)
|
|
DEFINE_INT_AND_FLOAT_ROUND_FN (ROUND)
|
|
DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
|
|
|
|
/* Unary operations and their associated IFN_COND_* function. */
|
|
(define_operator_list UNCOND_UNARY
|
|
negate)
|
|
(define_operator_list COND_UNARY
|
|
IFN_COND_NEG)
|
|
|
|
/* 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
|
|
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_AND IFN_COND_IOR IFN_COND_XOR
|
|
IFN_COND_SHL IFN_COND_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)
|
|
|
|
/* __atomic_fetch_or_*, __atomic_fetch_xor_*, __atomic_xor_fetch_* */
|
|
(define_operator_list ATOMIC_FETCH_OR_XOR_N
|
|
BUILT_IN_ATOMIC_FETCH_OR_1 BUILT_IN_ATOMIC_FETCH_OR_2
|
|
BUILT_IN_ATOMIC_FETCH_OR_4 BUILT_IN_ATOMIC_FETCH_OR_8
|
|
BUILT_IN_ATOMIC_FETCH_OR_16
|
|
BUILT_IN_ATOMIC_FETCH_XOR_1 BUILT_IN_ATOMIC_FETCH_XOR_2
|
|
BUILT_IN_ATOMIC_FETCH_XOR_4 BUILT_IN_ATOMIC_FETCH_XOR_8
|
|
BUILT_IN_ATOMIC_FETCH_XOR_16
|
|
BUILT_IN_ATOMIC_XOR_FETCH_1 BUILT_IN_ATOMIC_XOR_FETCH_2
|
|
BUILT_IN_ATOMIC_XOR_FETCH_4 BUILT_IN_ATOMIC_XOR_FETCH_8
|
|
BUILT_IN_ATOMIC_XOR_FETCH_16)
|
|
/* __sync_fetch_and_or_*, __sync_fetch_and_xor_*, __sync_xor_and_fetch_* */
|
|
(define_operator_list SYNC_FETCH_OR_XOR_N
|
|
BUILT_IN_SYNC_FETCH_AND_OR_1 BUILT_IN_SYNC_FETCH_AND_OR_2
|
|
BUILT_IN_SYNC_FETCH_AND_OR_4 BUILT_IN_SYNC_FETCH_AND_OR_8
|
|
BUILT_IN_SYNC_FETCH_AND_OR_16
|
|
BUILT_IN_SYNC_FETCH_AND_XOR_1 BUILT_IN_SYNC_FETCH_AND_XOR_2
|
|
BUILT_IN_SYNC_FETCH_AND_XOR_4 BUILT_IN_SYNC_FETCH_AND_XOR_8
|
|
BUILT_IN_SYNC_FETCH_AND_XOR_16
|
|
BUILT_IN_SYNC_XOR_AND_FETCH_1 BUILT_IN_SYNC_XOR_AND_FETCH_2
|
|
BUILT_IN_SYNC_XOR_AND_FETCH_4 BUILT_IN_SYNC_XOR_AND_FETCH_8
|
|
BUILT_IN_SYNC_XOR_AND_FETCH_16)
|
|
/* __atomic_fetch_and_*. */
|
|
(define_operator_list ATOMIC_FETCH_AND_N
|
|
BUILT_IN_ATOMIC_FETCH_AND_1 BUILT_IN_ATOMIC_FETCH_AND_2
|
|
BUILT_IN_ATOMIC_FETCH_AND_4 BUILT_IN_ATOMIC_FETCH_AND_8
|
|
BUILT_IN_ATOMIC_FETCH_AND_16)
|
|
/* __sync_fetch_and_and_*. */
|
|
(define_operator_list SYNC_FETCH_AND_AND_N
|
|
BUILT_IN_SYNC_FETCH_AND_AND_1 BUILT_IN_SYNC_FETCH_AND_AND_2
|
|
BUILT_IN_SYNC_FETCH_AND_AND_4 BUILT_IN_SYNC_FETCH_AND_AND_8
|
|
BUILT_IN_SYNC_FETCH_AND_AND_16)
|
|
|
|
/* With nop_convert? combine convert? and view_convert? in one pattern
|
|
plus conditionalize on tree_nop_conversion_p conversions. */
|
|
(match (nop_convert @0)
|
|
(convert @0)
|
|
(if (tree_nop_conversion_p (type, TREE_TYPE (@0)))))
|
|
(match (nop_convert @0)
|
|
(view_convert @0)
|
|
(if (VECTOR_TYPE_P (type) && VECTOR_TYPE_P (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))))))
|
|
|
|
/* 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)))))
|
|
|
|
#if GIMPLE
|
|
/* Optimize (X + (X >> (prec - 1))) ^ (X >> (prec - 1)) into abs (X). */
|
|
(simplify
|
|
(bit_xor:c (plus:c @0 (rshift@2 @0 INTEGER_CST@1)) @2)
|
|
(if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& !TYPE_UNSIGNED (TREE_TYPE (@0))
|
|
&& wi::to_widest (@1) == element_precision (TREE_TYPE (@0)) - 1)
|
|
(abs @0)))
|
|
#endif
|
|
|
|
/* Simplifications of operations with one constant operand and
|
|
simplifications to constants or single values. */
|
|
|
|
(for op (plus pointer_plus minus bit_ior bit_xor)
|
|
(simplify
|
|
(op @0 integer_zerop)
|
|
(non_lvalue @0)))
|
|
|
|
/* 0 +p index -> (type)index */
|
|
(simplify
|
|
(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
|
|
(plus:c @0 real_zerop@1)
|
|
(if (fold_real_zero_addition_p (type, @0, @1, 0))
|
|
(non_lvalue @0)))
|
|
|
|
/* See if ARG1 is zero and X - ARG1 reduces to X. */
|
|
(simplify
|
|
(minus @0 real_zerop@1)
|
|
(if (fold_real_zero_addition_p (type, @0, @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.
|
|
PR middle-end/98420: x - x may be -0.0 with FE_DOWNWARD.
|
|
Also note that operand_equal_p is always false if an operand
|
|
is volatile. */
|
|
(simplify
|
|
(minus @0 @0)
|
|
(if (!FLOAT_TYPE_P (type)
|
|
|| (!tree_expr_maybe_nan_p (@0)
|
|
&& !tree_expr_maybe_infinite_p (@0)
|
|
&& (!HONOR_SIGN_DEPENDENT_ROUNDING (type)
|
|
|| !HONOR_SIGNED_ZEROS (type))))
|
|
{ build_zero_cst (type); }))
|
|
(simplify
|
|
(pointer_diff @@0 @0)
|
|
{ build_zero_cst (type); })
|
|
|
|
(simplify
|
|
(mult @0 integer_zerop@1)
|
|
@1)
|
|
|
|
/* -x == x -> x == 0 */
|
|
(for cmp (eq ne)
|
|
(simplify
|
|
(cmp:c @0 (negate @0))
|
|
(if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& !TYPE_OVERFLOW_WRAPS (TREE_TYPE(@0)))
|
|
(cmp @0 { build_zero_cst (TREE_TYPE(@0)); }))))
|
|
|
|
/* Maybe fold x * 0 to 0. The expressions aren't the same
|
|
when x is NaN, since x * 0 is also NaN. Nor are they the
|
|
same in modes with signed zeros, since multiplying a
|
|
negative value by 0 gives -0, not +0. Nor when x is +-Inf,
|
|
since x * 0 is NaN. */
|
|
(simplify
|
|
(mult @0 real_zerop@1)
|
|
(if (!tree_expr_maybe_nan_p (@0)
|
|
&& (!HONOR_NANS (type) || !tree_expr_maybe_infinite_p (@0))
|
|
&& (!HONOR_SIGNED_ZEROS (type) || tree_expr_nonnegative_p (@0)))
|
|
@1))
|
|
|
|
/* In IEEE floating point, x*1 is not equivalent to x for snans.
|
|
Likewise for complex arithmetic with signed zeros. */
|
|
(simplify
|
|
(mult @0 real_onep)
|
|
(if (!tree_expr_maybe_signaling_nan_p (@0)
|
|
&& (!HONOR_SIGNED_ZEROS (type)
|
|
|| !COMPLEX_FLOAT_TYPE_P (type)))
|
|
(non_lvalue @0)))
|
|
|
|
/* Transform x * -1.0 into -x. */
|
|
(simplify
|
|
(mult @0 real_minus_onep)
|
|
(if (!tree_expr_maybe_signaling_nan_p (@0)
|
|
&& (!HONOR_SIGNED_ZEROS (type)
|
|
|| !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 * (X > 0.0 ? 1.0 : -1.0) into abs(X). */
|
|
/* Transform X * (X >= 0.0 ? 1.0 : -1.0) into abs(X). */
|
|
/* Transform X * (X < 0.0 ? 1.0 : -1.0) into -abs(X). */
|
|
/* Transform X * (X <= 0.0 ? 1.0 : -1.0) into -abs(X). */
|
|
(simplify
|
|
(mult:c @0 (cond (cmp @0 real_zerop) real_onep@1 real_minus_onep))
|
|
(if (!tree_expr_maybe_nan_p (@0) && !HONOR_SIGNED_ZEROS (type))
|
|
(outp (abs @0))))
|
|
/* Transform X * (X > 0.0 ? -1.0 : 1.0) into -abs(X). */
|
|
/* Transform X * (X >= 0.0 ? -1.0 : 1.0) into -abs(X). */
|
|
/* Transform X * (X < 0.0 ? -1.0 : 1.0) into abs(X). */
|
|
/* Transform X * (X <= 0.0 ? -1.0 : 1.0) into abs(X). */
|
|
(simplify
|
|
(mult:c @0 (cond (cmp @0 real_zerop) real_minus_onep real_onep@1))
|
|
(if (!tree_expr_maybe_nan_p (@0) && !HONOR_SIGNED_ZEROS (type))
|
|
(outn (abs @0)))))
|
|
|
|
/* Transform X * copysign (1.0, X) into abs(X). */
|
|
(simplify
|
|
(mult:c @0 (COPYSIGN_ALL real_onep @0))
|
|
(if (!tree_expr_maybe_nan_p (@0) && !HONOR_SIGNED_ZEROS (type))
|
|
(abs @0)))
|
|
|
|
/* Transform X * copysign (1.0, -X) into -abs(X). */
|
|
(simplify
|
|
(mult:c @0 (COPYSIGN_ALL real_onep (negate @0)))
|
|
(if (!tree_expr_maybe_nan_p (@0) && !HONOR_SIGNED_ZEROS (type))
|
|
(negate (abs @0))))
|
|
|
|
/* Transform copysign (CST, X) into copysign (ABS(CST), X). */
|
|
(simplify
|
|
(COPYSIGN_ALL REAL_CST@0 @1)
|
|
(if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (@0)))
|
|
(COPYSIGN_ALL (negate @0) @1)))
|
|
|
|
/* X * 1, X / 1 -> X. */
|
|
(for op (mult trunc_div ceil_div floor_div round_div exact_div)
|
|
(simplify
|
|
(op @0 integer_onep)
|
|
(non_lvalue @0)))
|
|
|
|
/* (A / (1 << B)) -> (A >> B).
|
|
Only for unsigned A. For signed A, this would not preserve rounding
|
|
toward zero.
|
|
For example: (-1 / ( 1 << B)) != -1 >> B.
|
|
Also also widening conversions, like:
|
|
(A / (unsigned long long) (1U << B)) -> (A >> B)
|
|
or
|
|
(A / (unsigned long long) (1 << B)) -> (A >> B).
|
|
If the left shift is signed, it can be done only if the upper bits
|
|
of A starting from shift's type sign bit are zero, as
|
|
(unsigned long long) (1 << 31) is -2147483648ULL, not 2147483648ULL,
|
|
so it is valid only if A >> 31 is zero. */
|
|
(simplify
|
|
(trunc_div (convert?@0 @3) (convert2? (lshift integer_onep@1 @2)))
|
|
(if ((TYPE_UNSIGNED (type) || tree_expr_nonnegative_p (@0))
|
|
&& (!VECTOR_TYPE_P (type)
|
|
|| target_supports_op_p (type, RSHIFT_EXPR, optab_vector)
|
|
|| target_supports_op_p (type, RSHIFT_EXPR, optab_scalar))
|
|
&& (useless_type_conversion_p (type, TREE_TYPE (@1))
|
|
|| (element_precision (type) >= element_precision (TREE_TYPE (@1))
|
|
&& (TYPE_UNSIGNED (TREE_TYPE (@1))
|
|
|| (element_precision (type)
|
|
== element_precision (TREE_TYPE (@1)))
|
|
|| (INTEGRAL_TYPE_P (type)
|
|
&& (tree_nonzero_bits (@0)
|
|
& wi::mask (element_precision (TREE_TYPE (@1)) - 1,
|
|
true,
|
|
element_precision (type))) == 0)))))
|
|
(if (!VECTOR_TYPE_P (type)
|
|
&& useless_type_conversion_p (TREE_TYPE (@3), TREE_TYPE (@1))
|
|
&& element_precision (TREE_TYPE (@3)) < element_precision (type))
|
|
(convert (rshift @3 @2))
|
|
(rshift @0 @2))))
|
|
|
|
/* Preserve explicit divisions by 0: the C++ front-end wants to detect
|
|
undefined behavior in constexpr evaluation, and assuming that the division
|
|
traps enables better optimizations than these anyway. */
|
|
(for div (trunc_div ceil_div floor_div round_div exact_div)
|
|
/* 0 / X is always zero. */
|
|
(simplify
|
|
(div integer_zerop@0 @1)
|
|
/* But not for 0 / 0 so that we can get the proper warnings and errors. */
|
|
(if (!integer_zerop (@1))
|
|
@0))
|
|
/* X / -1 is -X. */
|
|
(simplify
|
|
(div @0 integer_minus_onep@1)
|
|
(if (!TYPE_UNSIGNED (type))
|
|
(negate @0)))
|
|
/* X / bool_range_Y is X. */
|
|
(simplify
|
|
(div @0 SSA_NAME@1)
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& ssa_name_has_boolean_range (@1)
|
|
&& !flag_non_call_exceptions)
|
|
@0))
|
|
/* X / X is one. */
|
|
(simplify
|
|
(div @0 @0)
|
|
/* But not for 0 / 0 so that we can get the proper warnings and errors.
|
|
And not for _Fract types where we can't build 1. */
|
|
(if (!ALL_FRACT_MODE_P (TYPE_MODE (type))
|
|
&& !integer_zerop (@0)
|
|
&& (!flag_non_call_exceptions || tree_expr_nonzero_p (@0)))
|
|
{ build_one_cst (type); }))
|
|
/* X / abs (X) is X < 0 ? -1 : 1. */
|
|
(simplify
|
|
(div:C @0 (abs @0))
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& TYPE_OVERFLOW_UNDEFINED (type)
|
|
&& !integer_zerop (@0)
|
|
&& (!flag_non_call_exceptions || tree_expr_nonzero_p (@0)))
|
|
(cond (lt @0 { build_zero_cst (type); })
|
|
{ build_minus_one_cst (type); } { build_one_cst (type); })))
|
|
/* X / -X is -1. */
|
|
(simplify
|
|
(div:C @0 (negate @0))
|
|
(if ((INTEGRAL_TYPE_P (type) || VECTOR_INTEGER_TYPE_P (type))
|
|
&& TYPE_OVERFLOW_UNDEFINED (type)
|
|
&& !integer_zerop (@0)
|
|
&& (!flag_non_call_exceptions || tree_expr_nonzero_p (@0)))
|
|
{ build_minus_one_cst (type); })))
|
|
|
|
/* For unsigned integral types, FLOOR_DIV_EXPR is the same as
|
|
TRUNC_DIV_EXPR. Rewrite into the latter in this case. Similarly
|
|
for MOD instead of DIV. */
|
|
(for floor_divmod (floor_div floor_mod)
|
|
trunc_divmod (trunc_div trunc_mod)
|
|
(simplify
|
|
(floor_divmod @0 @1)
|
|
(if ((INTEGRAL_TYPE_P (type) || VECTOR_INTEGER_TYPE_P (type))
|
|
&& TYPE_UNSIGNED (type))
|
|
(trunc_divmod @0 @1))))
|
|
|
|
/* 1 / X -> X == 1 for unsigned integer X.
|
|
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. */
|
|
(simplify
|
|
(trunc_div integer_onep@0 @1)
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& TYPE_PRECISION (type) > 1
|
|
&& !integer_zerop (@1)
|
|
&& (!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); })))))
|
|
|
|
/* Combine two successive divisions. Note that combining ceil_div
|
|
and floor_div is trickier and combining round_div even more so. */
|
|
(for div (trunc_div exact_div)
|
|
(simplify
|
|
(div (div@3 @0 INTEGER_CST@1) INTEGER_CST@2)
|
|
(with {
|
|
wi::overflow_type overflow;
|
|
wide_int mul = wi::mul (wi::to_wide (@1), wi::to_wide (@2),
|
|
TYPE_SIGN (type), &overflow);
|
|
}
|
|
(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 {
|
|
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 || TYPE_OVERFLOW_WRAPS (type))
|
|
(mult @0 { wide_int_to_tree (type, mul); }))))
|
|
|
|
/* Optimize A / A to 1.0 if we don't care about
|
|
NaNs or Infinities. */
|
|
(simplify
|
|
(rdiv @0 @0)
|
|
(if (FLOAT_TYPE_P (type)
|
|
&& ! HONOR_NANS (type)
|
|
&& ! HONOR_INFINITIES (type))
|
|
{ build_one_cst (type); }))
|
|
|
|
/* Optimize -A / A to -1.0 if we don't care about
|
|
NaNs or Infinities. */
|
|
(simplify
|
|
(rdiv:C @0 (negate @0))
|
|
(if (FLOAT_TYPE_P (type)
|
|
&& ! HONOR_NANS (type)
|
|
&& ! HONOR_INFINITIES (type))
|
|
{ build_minus_one_cst (type); }))
|
|
|
|
/* PR71078: x / abs(x) -> copysign (1.0, x) */
|
|
(simplify
|
|
(rdiv:C (convert? @0) (convert? (abs @0)))
|
|
(if (SCALAR_FLOAT_TYPE_P (type)
|
|
&& ! HONOR_NANS (type)
|
|
&& ! HONOR_INFINITIES (type))
|
|
(switch
|
|
(if (types_match (type, float_type_node))
|
|
(BUILT_IN_COPYSIGNF { build_one_cst (type); } (convert @0)))
|
|
(if (types_match (type, double_type_node))
|
|
(BUILT_IN_COPYSIGN { build_one_cst (type); } (convert @0)))
|
|
(if (types_match (type, long_double_type_node))
|
|
(BUILT_IN_COPYSIGNL { build_one_cst (type); } (convert @0))))))
|
|
|
|
/* In IEEE floating point, x/1 is not equivalent to x for snans. */
|
|
(simplify
|
|
(rdiv @0 real_onep)
|
|
(if (!tree_expr_maybe_signaling_nan_p (@0))
|
|
(non_lvalue @0)))
|
|
|
|
/* In IEEE floating point, x/-1 is not equivalent to -x for snans. */
|
|
(simplify
|
|
(rdiv @0 real_minus_onep)
|
|
(if (!tree_expr_maybe_signaling_nan_p (@0))
|
|
(negate @0)))
|
|
|
|
(if (flag_reciprocal_math)
|
|
/* Convert (A/B)/C to A/(B*C). */
|
|
(simplify
|
|
(rdiv (rdiv:s @0 @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
|
|
&& 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,
|
|
so only do this if -freciprocal-math. We can actually
|
|
always safely do it if ARG1 is a power of two, but it's hard to
|
|
tell if it is or not in a portable manner. */
|
|
(for cst (REAL_CST COMPLEX_CST VECTOR_CST)
|
|
(simplify
|
|
(rdiv @0 cst@1)
|
|
(if (optimize)
|
|
(if (flag_reciprocal_math
|
|
&& !real_zerop (@1))
|
|
(with
|
|
{ tree tem = const_binop (RDIV_EXPR, type, build_one_cst (type), @1); }
|
|
(if (tem)
|
|
(mult @0 { tem; } )))
|
|
(if (cst != COMPLEX_CST)
|
|
(with { tree inverse = exact_inverse (type, @1); }
|
|
(if (inverse)
|
|
(mult @0 { inverse; } ))))))))
|
|
|
|
(for mod (ceil_mod floor_mod round_mod trunc_mod)
|
|
/* 0 % X is always zero. */
|
|
(simplify
|
|
(mod integer_zerop@0 @1)
|
|
/* But not for 0 % 0 so that we can get the proper warnings and errors. */
|
|
(if (!integer_zerop (@1))
|
|
@0))
|
|
/* X % 1 is always zero. */
|
|
(simplify
|
|
(mod @0 integer_onep)
|
|
{ build_zero_cst (type); })
|
|
/* X % -1 is zero. */
|
|
(simplify
|
|
(mod @0 integer_minus_onep@1)
|
|
(if (!TYPE_UNSIGNED (type))
|
|
{ build_zero_cst (type); }))
|
|
/* X % X is zero. */
|
|
(simplify
|
|
(mod @0 @0)
|
|
/* But not for 0 % 0 so that we can get the proper warnings and errors. */
|
|
(if (!integer_zerop (@0))
|
|
{ build_zero_cst (type); }))
|
|
/* (X % Y) % Y is just X % Y. */
|
|
(simplify
|
|
(mod (mod@2 @0 @1) @1)
|
|
@2)
|
|
/* From extract_muldiv_1: (X * C1) % C2 is zero if C1 is a multiple of C2. */
|
|
(simplify
|
|
(mod (mult @0 INTEGER_CST@1) INTEGER_CST@2)
|
|
(if (ANY_INTEGRAL_TYPE_P (type)
|
|
&& TYPE_OVERFLOW_UNDEFINED (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 (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))
|
|
(trunc_mod @0 (negate @1))))
|
|
|
|
/* X % -Y is the same as X % Y. */
|
|
(simplify
|
|
(trunc_mod @0 (convert? (negate @1)))
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& !TYPE_UNSIGNED (type)
|
|
&& !TYPE_OVERFLOW_TRAPS (type)
|
|
&& tree_nop_conversion_p (type, TREE_TYPE (@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, 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))))
|
|
|
|
/* X - (X / Y) * Y is the same as X % Y. */
|
|
(simplify
|
|
(minus (convert1? @0) (convert2? (mult:c (trunc_div @@0 @@1) @1)))
|
|
(if (INTEGRAL_TYPE_P (type) || VECTOR_INTEGER_TYPE_P (type))
|
|
(convert (trunc_mod @0 @1))))
|
|
|
|
/* x * (1 + y / x) - y -> x - y % x */
|
|
(simplify
|
|
(minus (mult:cs @0 (plus:s (trunc_div:s @1 @0) integer_onep)) @1)
|
|
(if (INTEGRAL_TYPE_P (type))
|
|
(minus @0 (trunc_mod @1 @0))))
|
|
|
|
/* Optimize TRUNC_MOD_EXPR by a power of two into a BIT_AND_EXPR,
|
|
i.e. "X % C" into "X & (C - 1)", if X and C are positive.
|
|
Also optimize A % (C << N) where C is a power of 2,
|
|
to A & ((C << N) - 1).
|
|
Also optimize "A shift (B % C)", if C is a power of 2, to
|
|
"A shift (B & (C - 1))". SHIFT operation include "<<" and ">>"
|
|
and assume (B % C) is nonnegative as shifts negative values would
|
|
be UB. */
|
|
(match (power_of_two_cand @1)
|
|
INTEGER_CST@1)
|
|
(match (power_of_two_cand @1)
|
|
(lshift INTEGER_CST@1 @2))
|
|
(for mod (trunc_mod floor_mod)
|
|
(for shift (lshift rshift)
|
|
(simplify
|
|
(shift @0 (mod @1 (power_of_two_cand@2 @3)))
|
|
(if (integer_pow2p (@3) && tree_int_cst_sgn (@3) > 0)
|
|
(shift @0 (bit_and @1 (minus @2 { build_int_cst (TREE_TYPE (@2),
|
|
1); }))))))
|
|
(simplify
|
|
(mod @0 (convert? (power_of_two_cand@1 @2)))
|
|
(if ((TYPE_UNSIGNED (type) || tree_expr_nonnegative_p (@0))
|
|
/* Allow any integral conversions of the divisor, except
|
|
conversion from narrower signed to wider unsigned type
|
|
where if @1 would be negative power of two, the divisor
|
|
would not be a power of two. */
|
|
&& INTEGRAL_TYPE_P (type)
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@1))
|
|
&& (TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@1))
|
|
|| TYPE_UNSIGNED (TREE_TYPE (@1))
|
|
|| !TYPE_UNSIGNED (type))
|
|
&& integer_pow2p (@2) && tree_int_cst_sgn (@2) > 0)
|
|
(with { tree utype = TREE_TYPE (@1);
|
|
if (!TYPE_OVERFLOW_WRAPS (utype))
|
|
utype = unsigned_type_for (utype); }
|
|
(bit_and @0 (convert (minus (convert:utype @1)
|
|
{ build_one_cst (utype); })))))))
|
|
|
|
/* Simplify (unsigned t * 2)/2 -> unsigned t & 0x7FFFFFFF. */
|
|
(simplify
|
|
(trunc_div (mult @0 integer_pow2p@1) @1)
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && TYPE_UNSIGNED (TREE_TYPE (@0)))
|
|
(bit_and @0 { wide_int_to_tree
|
|
(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
|
|
(mult (trunc_div @0 integer_pow2p@1) @1)
|
|
(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
|
|
(div (mult:c @0 @1) @1)
|
|
(if (ANY_INTEGRAL_TYPE_P (type))
|
|
(if (TYPE_OVERFLOW_UNDEFINED (type))
|
|
@0
|
|
#if GIMPLE
|
|
(with
|
|
{
|
|
bool overflowed = true;
|
|
value_range vr0, vr1;
|
|
if (INTEGRAL_TYPE_P (type)
|
|
&& get_global_range_query ()->range_of_expr (vr0, @0)
|
|
&& get_global_range_query ()->range_of_expr (vr1, @1)
|
|
&& vr0.kind () == VR_RANGE
|
|
&& vr1.kind () == VR_RANGE)
|
|
{
|
|
wide_int wmin0 = vr0.lower_bound ();
|
|
wide_int wmax0 = vr0.upper_bound ();
|
|
wide_int wmin1 = vr1.lower_bound ();
|
|
wide_int wmax1 = vr1.upper_bound ();
|
|
/* If the multiplication can't overflow/wrap around, then
|
|
it can be optimized too. */
|
|
wi::overflow_type min_ovf, max_ovf;
|
|
wi::mul (wmin0, wmin1, TYPE_SIGN (type), &min_ovf);
|
|
wi::mul (wmax0, wmax1, TYPE_SIGN (type), &max_ovf);
|
|
if (min_ovf == wi::OVF_NONE && max_ovf == wi::OVF_NONE)
|
|
{
|
|
wi::mul (wmin0, wmax1, TYPE_SIGN (type), &min_ovf);
|
|
wi::mul (wmax0, wmin1, TYPE_SIGN (type), &max_ovf);
|
|
if (min_ovf == wi::OVF_NONE && max_ovf == wi::OVF_NONE)
|
|
overflowed = false;
|
|
}
|
|
}
|
|
}
|
|
(if (!overflowed)
|
|
@0))
|
|
#endif
|
|
))))
|
|
|
|
(for op (negate abs)
|
|
/* Simplify cos(-x) and cos(|x|) -> cos(x). Similarly for cosh. */
|
|
(for coss (COS COSH)
|
|
(simplify
|
|
(coss (op @0))
|
|
(coss @0)))
|
|
/* Simplify pow(-x, y) and pow(|x|,y) -> pow(x,y) if y is an even integer. */
|
|
(for pows (POW)
|
|
(simplify
|
|
(pows (op @0) 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)
|
|
(simplify
|
|
(pows (op @0) INTEGER_CST@1)
|
|
(if ((wi::to_wide (@1) & 1) == 0)
|
|
(pows @0 @1))))
|
|
/* Strip negate and abs from both operands of hypot. */
|
|
(for hypots (HYPOT)
|
|
(simplify
|
|
(hypots (op @0) @1)
|
|
(hypots @0 @1))
|
|
(simplify
|
|
(hypots @0 (op @1))
|
|
(hypots @0 @1)))
|
|
/* copysign(-x, y) and copysign(abs(x), y) -> copysign(x, y). */
|
|
(for copysigns (COPYSIGN_ALL)
|
|
(simplify
|
|
(copysigns (op @0) @1)
|
|
(copysigns @0 @1))))
|
|
|
|
/* abs(x)*abs(x) -> x*x. Should be valid for all types. */
|
|
(simplify
|
|
(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)
|
|
(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)))))
|
|
/* 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 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)))
|
|
|
|
/* copysign(x, CST) -> [-]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))))
|
|
|
|
/* copysign(copysign(x, y), z) -> copysign(x, z). */
|
|
(for copysigns (COPYSIGN_ALL)
|
|
(simplify
|
|
(copysigns (copysigns @0 @1) @2)
|
|
(copysigns @0 @2)))
|
|
|
|
/* copysign(x,y)*copysign(x,y) -> x*x. */
|
|
(for copysigns (COPYSIGN_ALL)
|
|
(simplify
|
|
(mult (copysigns@2 @0 @1) @2)
|
|
(mult @0 @0)))
|
|
|
|
/* ccos(-x) -> ccos(x). Similarly for ccosh. */
|
|
(for ccoss (CCOS CCOSH)
|
|
(simplify
|
|
(ccoss (negate @0))
|
|
(ccoss @0)))
|
|
|
|
/* cabs(-x) and cos(conj(x)) -> cabs(x). */
|
|
(for ops (conj negate)
|
|
(for cabss (CABS)
|
|
(simplify
|
|
(cabss (ops @0))
|
|
(cabss @0))))
|
|
|
|
/* Fold (a * (1 << b)) into (a << b) */
|
|
(simplify
|
|
(mult:c @0 (convert? (lshift integer_onep@1 @2)))
|
|
(if (! FLOAT_TYPE_P (type)
|
|
&& 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 ((type)(a<0)) << SIGNBITOFA into ((type)a) & signbit. */
|
|
(simplify
|
|
(lshift (convert (lt @0 integer_zerop@1)) INTEGER_CST@2)
|
|
(if (TYPE_SIGN (TREE_TYPE (@0)) == SIGNED
|
|
&& wi::eq_p (wi::to_wide (@2), TYPE_PRECISION (TREE_TYPE (@0)) - 1))
|
|
(with { wide_int wone = wi::one (TYPE_PRECISION (type)); }
|
|
(bit_and (convert @0)
|
|
{ wide_int_to_tree (type,
|
|
wi::lshift (wone, wi::to_wide (@2))); }))))
|
|
|
|
/* Fold (-x >> C) into -(x > 0) where C = precision(type) - 1. */
|
|
(for cst (INTEGER_CST VECTOR_CST)
|
|
(simplify
|
|
(rshift (negate:s @0) cst@1)
|
|
(if (!TYPE_UNSIGNED (type)
|
|
&& TYPE_OVERFLOW_UNDEFINED (type))
|
|
(with { tree stype = TREE_TYPE (@1);
|
|
tree bt = truth_type_for (type);
|
|
tree zeros = build_zero_cst (type);
|
|
tree cst = NULL_TREE; }
|
|
(switch
|
|
/* Handle scalar case. */
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
/* If we apply the rule to the scalar type before vectorization
|
|
we will enforce the result of the comparison being a bool
|
|
which will require an extra AND on the result that will be
|
|
indistinguishable from when the user did actually want 0
|
|
or 1 as the result so it can't be removed. */
|
|
&& canonicalize_math_after_vectorization_p ()
|
|
&& wi::eq_p (wi::to_wide (@1), TYPE_PRECISION (type) - 1))
|
|
(negate (convert (gt @0 { zeros; }))))
|
|
/* Handle vector case. */
|
|
(if (VECTOR_INTEGER_TYPE_P (type)
|
|
/* First check whether the target has the same mode for vector
|
|
comparison results as it's operands do. */
|
|
&& TYPE_MODE (bt) == TYPE_MODE (type)
|
|
/* Then check to see if the target is able to expand the comparison
|
|
with the given type later on, otherwise we may ICE. */
|
|
&& expand_vec_cmp_expr_p (type, bt, GT_EXPR)
|
|
&& (cst = uniform_integer_cst_p (@1)) != NULL
|
|
&& wi::eq_p (wi::to_wide (cst), element_precision (type) - 1))
|
|
(view_convert (gt:bt @0 { zeros; }))))))))
|
|
|
|
/* Fold (C1/X)*C2 into (C1*C2)/X. */
|
|
(simplify
|
|
(mult (rdiv@3 REAL_CST@0 @1) REAL_CST@2)
|
|
(if (flag_associative_math
|
|
&& single_use (@3))
|
|
(with
|
|
{ tree tem = const_binop (MULT_EXPR, type, @0, @2); }
|
|
(if (tem)
|
|
(rdiv { tem; } @1)))))
|
|
|
|
/* Simplify ~X & X as zero. */
|
|
(simplify
|
|
(bit_and:c (convert? @0) (convert? (bit_not @0)))
|
|
{ build_zero_cst (type); })
|
|
|
|
/* PR71636: Transform x & ((1U << b) - 1) -> x & ~(~0U << b); */
|
|
(simplify
|
|
(bit_and:c @0 (plus:s (lshift:s integer_onep @1) integer_minus_onep))
|
|
(if (TYPE_UNSIGNED (type))
|
|
(bit_and @0 (bit_not (lshift { build_all_ones_cst (type); } @1)))))
|
|
|
|
(for bitop (bit_and bit_ior)
|
|
cmp (eq ne)
|
|
/* PR35691: Transform
|
|
(x == 0 & y == 0) -> (x | typeof(x)(y)) == 0.
|
|
(x != 0 | y != 0) -> (x | typeof(x)(y)) != 0. */
|
|
(simplify
|
|
(bitop (cmp @0 integer_zerop@2) (cmp @1 integer_zerop))
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@1))
|
|
&& TYPE_PRECISION (TREE_TYPE (@0)) == TYPE_PRECISION (TREE_TYPE (@1)))
|
|
(cmp (bit_ior @0 (convert @1)) @2)))
|
|
/* Transform:
|
|
(x == -1 & y == -1) -> (x & typeof(x)(y)) == -1.
|
|
(x != -1 | y != -1) -> (x & typeof(x)(y)) != -1. */
|
|
(simplify
|
|
(bitop (cmp @0 integer_all_onesp@2) (cmp @1 integer_all_onesp))
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@1))
|
|
&& TYPE_PRECISION (TREE_TYPE (@0)) == TYPE_PRECISION (TREE_TYPE (@1)))
|
|
(cmp (bit_and @0 (convert @1)) @2))))
|
|
|
|
/* Fold (A & ~B) - (A & B) into (A ^ B) - B. */
|
|
(simplify
|
|
(minus (bit_and:cs @0 (bit_not @1)) (bit_and:cs @0 @1))
|
|
(minus (bit_xor @0 @1) @1))
|
|
(simplify
|
|
(minus (bit_and:s @0 INTEGER_CST@2) (bit_and:s @0 INTEGER_CST@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). */
|
|
(simplify
|
|
(minus (bit_and:cs @0 @1) (bit_and:cs @0 (bit_not @1)))
|
|
(minus @1 (bit_xor @0 @1)))
|
|
|
|
/* Simplify (X & ~Y) |^+ (~X & Y) -> X ^ Y. */
|
|
(for op (bit_ior bit_xor plus)
|
|
(simplify
|
|
(op (bit_and:c @0 (bit_not @1)) (bit_and:c (bit_not @0) @1))
|
|
(bit_xor @0 @1))
|
|
(simplify
|
|
(op:c (bit_and @0 INTEGER_CST@2) (bit_and (bit_not @0) INTEGER_CST@1))
|
|
(if (~wi::to_wide (@2) == wi::to_wide (@1))
|
|
(bit_xor @0 @1))))
|
|
|
|
/* PR53979: Transform ((a ^ b) | a) -> (a | b) */
|
|
(simplify
|
|
(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 --> (a | b) */
|
|
(simplify
|
|
(bit_xor:c (bit_and:cs (bit_not @0) @1) @0)
|
|
(bit_ior @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)))
|
|
|
|
/* (a ^ b) & ((b ^ c) ^ a) --> (a ^ b) & ~c */
|
|
(simplify
|
|
(bit_and:c (bit_xor:c@3 @0 @1) (bit_xor:cs (bit_xor:cs @1 @2) @0))
|
|
(bit_and @3 (bit_not @2)))
|
|
|
|
/* (a ^ b) | ((b ^ c) ^ a) --> (a ^ b) | c */
|
|
(simplify
|
|
(bit_ior:c (bit_xor:c@3 @0 @1) (bit_xor:c (bit_xor:c @1 @2) @0))
|
|
(bit_ior @3 @2))
|
|
|
|
#if GIMPLE
|
|
/* (~X | C) ^ D -> (X | C) ^ (~D ^ C) if (~D ^ C) can be simplified. */
|
|
(simplify
|
|
(bit_xor:c (bit_ior:cs (bit_not:s @0) @1) @2)
|
|
(bit_xor (bit_ior @0 @1) (bit_xor! (bit_not! @2) @1)))
|
|
|
|
/* (~X & C) ^ D -> (X & C) ^ (D ^ C) if (D ^ C) can be simplified. */
|
|
(simplify
|
|
(bit_xor:c (bit_and:cs (bit_not:s @0) @1) @2)
|
|
(bit_xor (bit_and @0 @1) (bit_xor! @2 @1)))
|
|
|
|
/* Simplify (~X & Y) to X ^ Y if we know that (X & ~Y) is 0. */
|
|
(simplify
|
|
(bit_and (bit_not SSA_NAME@0) INTEGER_CST@1)
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@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
|
|
(cmp (trunc_mod @0 @1) @1)
|
|
(if (TYPE_UNSIGNED (TREE_TYPE (@0)))
|
|
{ constant_boolean_node (cmp == LT_EXPR, type); })))
|
|
(for cmp (gt le)
|
|
(simplify
|
|
(cmp @1 (trunc_mod @0 @1))
|
|
(if (TYPE_UNSIGNED (TREE_TYPE (@0)))
|
|
{ constant_boolean_node (cmp == GT_EXPR, type); })))
|
|
|
|
/* x | ~0 -> ~0 */
|
|
(simplify
|
|
(bit_ior @0 integer_all_onesp@1)
|
|
@1)
|
|
|
|
/* x | 0 -> x */
|
|
(simplify
|
|
(bit_ior @0 integer_zerop)
|
|
@0)
|
|
|
|
/* x & 0 -> 0 */
|
|
(simplify
|
|
(bit_and @0 integer_zerop@1)
|
|
@1)
|
|
|
|
/* ~x | x -> -1 */
|
|
/* ~x ^ x -> -1 */
|
|
/* ~x + x -> -1 */
|
|
(for op (bit_ior bit_xor plus)
|
|
(simplify
|
|
(op:c (convert? @0) (convert? (bit_not @0)))
|
|
(convert { build_all_ones_cst (TREE_TYPE (@0)); })))
|
|
|
|
/* x ^ x -> 0 */
|
|
(simplify
|
|
(bit_xor @0 @0)
|
|
{ build_zero_cst (type); })
|
|
|
|
/* Canonicalize X ^ ~0 to ~X. */
|
|
(simplify
|
|
(bit_xor @0 integer_all_onesp@1)
|
|
(bit_not @0))
|
|
|
|
/* x & ~0 -> x */
|
|
(simplify
|
|
(bit_and @0 integer_all_onesp)
|
|
(non_lvalue @0))
|
|
|
|
/* x & x -> x, x | x -> x */
|
|
(for bitop (bit_and bit_ior)
|
|
(simplify
|
|
(bitop @0 @0)
|
|
(non_lvalue @0)))
|
|
|
|
/* x & C -> x if we know that x & ~C == 0. */
|
|
#if GIMPLE
|
|
(simplify
|
|
(bit_and SSA_NAME@0 INTEGER_CST@1)
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& wi::bit_and_not (get_nonzero_bits (@0), wi::to_wide (@1)) == 0)
|
|
@0))
|
|
#endif
|
|
|
|
/* ~(~X - Y) -> X + Y and ~(~X + Y) -> X - Y. */
|
|
(simplify
|
|
(bit_not (minus (bit_not @0) @1))
|
|
(plus @0 @1))
|
|
(simplify
|
|
(bit_not (plus:c (bit_not @0) @1))
|
|
(minus @0 @1))
|
|
|
|
/* ~(X - Y) -> ~X + Y. */
|
|
(simplify
|
|
(bit_not (minus:s @0 @1))
|
|
(plus (bit_not @0) @1))
|
|
(simplify
|
|
(bit_not (plus:s @0 INTEGER_CST@1))
|
|
(if ((INTEGRAL_TYPE_P (type)
|
|
&& TYPE_UNSIGNED (type))
|
|
|| (!TYPE_OVERFLOW_SANITIZED (type)
|
|
&& may_negate_without_overflow_p (@1)))
|
|
(plus (bit_not @0) { const_unop (NEGATE_EXPR, type, @1); })))
|
|
|
|
#if GIMPLE
|
|
/* ~X + Y -> (Y - X) - 1. */
|
|
(simplify
|
|
(plus:c (bit_not @0) @1)
|
|
(if (ANY_INTEGRAL_TYPE_P (type)
|
|
&& TYPE_OVERFLOW_WRAPS (type)
|
|
/* -1 - X is folded to ~X, so we'd recurse endlessly. */
|
|
&& !integer_all_onesp (@1))
|
|
(plus (minus @1 @0) { build_minus_one_cst (type); })
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& TREE_CODE (@1) == INTEGER_CST
|
|
&& wi::to_wide (@1) != wi::min_value (TYPE_PRECISION (type),
|
|
SIGNED))
|
|
(minus (plus @1 { build_minus_one_cst (type); }) @0))))
|
|
|
|
/* ~(X >> Y) -> ~X >> Y if ~X can be simplified. */
|
|
(simplify
|
|
(bit_not (rshift:s @0 @1))
|
|
(if (!TYPE_UNSIGNED (TREE_TYPE (@0)))
|
|
(rshift (bit_not! @0) @1)
|
|
/* For logical right shifts, this is possible only if @0 doesn't
|
|
have MSB set and the logical right shift is changed into
|
|
arithmetic shift. */
|
|
(if (!wi::neg_p (tree_nonzero_bits (@0)))
|
|
(with { tree stype = signed_type_for (TREE_TYPE (@0)); }
|
|
(convert (rshift (bit_not! (convert:stype @0)) @1))))))
|
|
#endif
|
|
|
|
/* x + (x & 1) -> (x + 1) & ~1 */
|
|
(simplify
|
|
(plus:c @0 (bit_and:s @0 integer_onep@1))
|
|
(bit_and (plus @0 @1) (bit_not @1)))
|
|
|
|
/* x & ~(x & y) -> x & ~y */
|
|
/* x | ~(x | y) -> x | ~y */
|
|
(for bitop (bit_and bit_ior)
|
|
(simplify
|
|
(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)
|
|
rbitop (bit_ior bit_and)
|
|
(simplify
|
|
(bitop:c (rbitop:c @0 @1) (bit_not@2 @0))
|
|
(bitop @1 @2)))
|
|
|
|
/* (x & y) ^ (x | y) -> x ^ y */
|
|
(simplify
|
|
(bit_xor:c (bit_and @0 @1) (bit_ior @0 @1))
|
|
(bit_xor @0 @1))
|
|
|
|
/* (x ^ y) ^ (x | y) -> x & y */
|
|
(simplify
|
|
(bit_xor:c (bit_xor @0 @1) (bit_ior @0 @1))
|
|
(bit_and @0 @1))
|
|
|
|
/* (x & y) + (x ^ y) -> x | y */
|
|
/* (x & y) | (x ^ y) -> x | y */
|
|
/* (x & y) ^ (x ^ y) -> x | y */
|
|
(for op (plus bit_ior bit_xor)
|
|
(simplify
|
|
(op:c (bit_and @0 @1) (bit_xor @0 @1))
|
|
(bit_ior @0 @1)))
|
|
|
|
/* (x & y) + (x | y) -> x + y */
|
|
(simplify
|
|
(plus:c (bit_and @0 @1) (bit_ior @0 @1))
|
|
(plus @0 @1))
|
|
|
|
/* (x + y) - (x | y) -> x & y */
|
|
(simplify
|
|
(minus (plus @0 @1) (bit_ior @0 @1))
|
|
(if (!TYPE_OVERFLOW_SANITIZED (type) && !TYPE_OVERFLOW_TRAPS (type)
|
|
&& !TYPE_SATURATING (type))
|
|
(bit_and @0 @1)))
|
|
|
|
/* (x + y) - (x & y) -> x | y */
|
|
(simplify
|
|
(minus (plus @0 @1) (bit_and @0 @1))
|
|
(if (!TYPE_OVERFLOW_SANITIZED (type) && !TYPE_OVERFLOW_TRAPS (type)
|
|
&& !TYPE_SATURATING (type))
|
|
(bit_ior @0 @1)))
|
|
|
|
/* (x | y) - y -> (x & ~y) */
|
|
(simplify
|
|
(minus (bit_ior:cs @0 @1) @1)
|
|
(bit_and @0 (bit_not @1)))
|
|
|
|
/* (x | y) - (x ^ y) -> x & y */
|
|
(simplify
|
|
(minus (bit_ior @0 @1) (bit_xor @0 @1))
|
|
(bit_and @0 @1))
|
|
|
|
/* (x | y) - (x & y) -> x ^ y */
|
|
(simplify
|
|
(minus (bit_ior @0 @1) (bit_and @0 @1))
|
|
(bit_xor @0 @1))
|
|
|
|
/* (x | y) & ~(x & y) -> x ^ y */
|
|
(simplify
|
|
(bit_and:c (bit_ior @0 @1) (bit_not (bit_and @0 @1)))
|
|
(bit_xor @0 @1))
|
|
|
|
/* (x | y) & (~x ^ y) -> x & y */
|
|
(simplify
|
|
(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)) - 1 -> ~(x ^ y) */
|
|
(simplify
|
|
(plus (nop_convert1? (minus@2 (nop_convert2? (bit_and:c @0 @1))
|
|
(nop_convert2? (bit_ior @0 @1))))
|
|
integer_all_onesp)
|
|
(if (!TYPE_OVERFLOW_SANITIZED (type) && !TYPE_OVERFLOW_TRAPS (type)
|
|
&& !TYPE_SATURATING (type) && !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@2))
|
|
&& !TYPE_OVERFLOW_TRAPS (TREE_TYPE (@2))
|
|
&& !TYPE_SATURATING (TREE_TYPE (@2)))
|
|
(bit_not (convert (bit_xor @0 @1)))))
|
|
(simplify
|
|
(minus (nop_convert1? (plus@2 (nop_convert2? (bit_and:c @0 @1))
|
|
integer_all_onesp))
|
|
(nop_convert3? (bit_ior @0 @1)))
|
|
(if (!TYPE_OVERFLOW_SANITIZED (type) && !TYPE_OVERFLOW_TRAPS (type)
|
|
&& !TYPE_SATURATING (type) && !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@2))
|
|
&& !TYPE_OVERFLOW_TRAPS (TREE_TYPE (@2))
|
|
&& !TYPE_SATURATING (TREE_TYPE (@2)))
|
|
(bit_not (convert (bit_xor @0 @1)))))
|
|
(simplify
|
|
(minus (nop_convert1? (bit_and @0 @1))
|
|
(nop_convert2? (plus@2 (nop_convert3? (bit_ior:c @0 @1))
|
|
integer_onep)))
|
|
(if (!TYPE_OVERFLOW_SANITIZED (type) && !TYPE_OVERFLOW_TRAPS (type)
|
|
&& !TYPE_SATURATING (type) && !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@2))
|
|
&& !TYPE_OVERFLOW_TRAPS (TREE_TYPE (@2))
|
|
&& !TYPE_SATURATING (TREE_TYPE (@2)))
|
|
(bit_not (convert (bit_xor @0 @1)))))
|
|
|
|
/* ~x & ~y -> ~(x | y)
|
|
~x | ~y -> ~(x & y) */
|
|
(for op (bit_and bit_ior)
|
|
rop (bit_ior bit_and)
|
|
(simplify
|
|
(op (convert1? (bit_not @0)) (convert2? (bit_not @1)))
|
|
(if (element_precision (type) <= element_precision (TREE_TYPE (@0))
|
|
&& element_precision (type) <= element_precision (TREE_TYPE (@1)))
|
|
(bit_not (rop (convert @0) (convert @1))))))
|
|
|
|
/* If we are XORing or adding two BIT_AND_EXPR's, both of which are and'ing
|
|
with a constant, and the two constants have no bits in common,
|
|
we should treat this as a BIT_IOR_EXPR since this may produce more
|
|
simplifications. */
|
|
(for op (bit_xor plus)
|
|
(simplify
|
|
(op (convert1? (bit_and@4 @0 INTEGER_CST@1))
|
|
(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::to_wide (@1) & wi::to_wide (@3)) == 0)
|
|
(bit_ior (convert @4) (convert @5)))))
|
|
|
|
/* (X | Y) ^ X -> Y & ~ X*/
|
|
(simplify
|
|
(bit_xor:c (convert1? (bit_ior:c @@0 @1)) (convert2? @0))
|
|
(if (tree_nop_conversion_p (type, TREE_TYPE (@0)))
|
|
(convert (bit_and @1 (bit_not @0)))))
|
|
|
|
/* Convert ~X ^ ~Y to X ^ Y. */
|
|
(simplify
|
|
(bit_xor (convert1? (bit_not @0)) (convert2? (bit_not @1)))
|
|
(if (element_precision (type) <= element_precision (TREE_TYPE (@0))
|
|
&& element_precision (type) <= element_precision (TREE_TYPE (@1)))
|
|
(bit_xor (convert @0) (convert @1))))
|
|
|
|
/* Convert ~X ^ C to X ^ ~C. */
|
|
(simplify
|
|
(bit_xor (convert? (bit_not @0)) INTEGER_CST@1)
|
|
(if (tree_nop_conversion_p (type, TREE_TYPE (@0)))
|
|
(bit_xor (convert @0) (bit_not @1))))
|
|
|
|
/* Fold (X & Y) ^ Y and (X ^ Y) & Y as ~X & Y. */
|
|
(for opo (bit_and bit_xor)
|
|
opi (bit_xor bit_and)
|
|
(simplify
|
|
(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
|
|
operands are another bit-wise operation with a common input. If so,
|
|
distribute the bit operations to save an operation and possibly two if
|
|
constants are involved. For example, convert
|
|
(A | B) & (A | C) into A | (B & C)
|
|
Further simplification will occur if B and C are constants. */
|
|
(for op (bit_and bit_ior bit_xor)
|
|
rop (bit_ior bit_and bit_and)
|
|
(simplify
|
|
(op (convert? (rop:c @@0 @1)) (convert? (rop:c @0 @2)))
|
|
(if (tree_nop_conversion_p (type, TREE_TYPE (@1))
|
|
&& tree_nop_conversion_p (type, TREE_TYPE (@2)))
|
|
(rop (convert @0) (op (convert @1) (convert @2))))))
|
|
|
|
/* Some simple reassociation for bit operations, also handled in reassoc. */
|
|
/* (X & Y) & Y -> X & Y
|
|
(X | Y) | Y -> X | Y */
|
|
(for op (bit_and bit_ior)
|
|
(simplify
|
|
(op:c (convert1?@2 (op:c @0 @@1)) (convert2? @1))
|
|
@2))
|
|
/* (X ^ Y) ^ Y -> X */
|
|
(simplify
|
|
(bit_xor:c (convert1? (bit_xor:c @0 @@1)) (convert2? @1))
|
|
(convert @0))
|
|
/* (X & Y) & (X & Z) -> (X & Y) & Z
|
|
(X | Y) | (X | Z) -> (X | Y) | Z */
|
|
(for op (bit_and bit_ior)
|
|
(simplify
|
|
(op (convert1?@3 (op:c@4 @0 @1)) (convert2?@5 (op:c@6 @0 @2)))
|
|
(if (tree_nop_conversion_p (type, TREE_TYPE (@1))
|
|
&& tree_nop_conversion_p (type, TREE_TYPE (@2)))
|
|
(if (single_use (@5) && single_use (@6))
|
|
(op @3 (convert @2))
|
|
(if (single_use (@3) && single_use (@4))
|
|
(op (convert @1) @5))))))
|
|
/* (X ^ Y) ^ (X ^ Z) -> Y ^ Z */
|
|
(simplify
|
|
(bit_xor (convert1? (bit_xor:c @0 @1)) (convert2? (bit_xor:c @0 @2)))
|
|
(if (tree_nop_conversion_p (type, TREE_TYPE (@1))
|
|
&& 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))
|
|
|
|
/* Simplify (-(X < 0) | 1) * X into abs (X) or absu(X). */
|
|
(simplify
|
|
(mult:c (nop_convert1?
|
|
(bit_ior (nop_convert2? (negate (convert? (lt @0 integer_zerop))))
|
|
integer_onep))
|
|
(nop_convert3? @0))
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& !TYPE_UNSIGNED (TREE_TYPE (@0)))
|
|
(if (TYPE_UNSIGNED (type))
|
|
(absu @0)
|
|
(abs @0)
|
|
)
|
|
)
|
|
)
|
|
|
|
/* A few cases of fold-const.cc negate_expr_p predicate. */
|
|
(match negate_expr_p
|
|
INTEGER_CST
|
|
(if ((INTEGRAL_TYPE_P (type)
|
|
&& TYPE_UNSIGNED (type))
|
|
|| (!TYPE_OVERFLOW_SANITIZED (type)
|
|
&& may_negate_without_overflow_p (t)))))
|
|
(match negate_expr_p
|
|
FIXED_CST)
|
|
(match negate_expr_p
|
|
(negate @0)
|
|
(if (!TYPE_OVERFLOW_SANITIZED (type))))
|
|
(match negate_expr_p
|
|
REAL_CST
|
|
(if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (t)))))
|
|
/* VECTOR_CST handling of non-wrapping types would recurse in unsupported
|
|
ways. */
|
|
(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
|
|
(mult:c (convert1? (negate @0)) (convert2? negate_expr_p@1))
|
|
(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))
|
|
(if (!HONOR_SIGN_DEPENDENT_ROUNDING (type)
|
|
&& !HONOR_SIGNED_ZEROS (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)
|
|
(if (!FIXED_POINT_TYPE_P (type))
|
|
(plus @0 (negate @1))))
|
|
|
|
/* Other simplifications of negation (c.f. fold_negate_expr_1). */
|
|
(simplify
|
|
(negate (mult:c@0 @1 negate_expr_p@2))
|
|
(if (! TYPE_UNSIGNED (type)
|
|
&& ! HONOR_SIGN_DEPENDENT_ROUNDING (type)
|
|
&& single_use (@0))
|
|
(mult @1 (negate @2))))
|
|
|
|
(simplify
|
|
(negate (rdiv@0 @1 negate_expr_p@2))
|
|
(if (! HONOR_SIGN_DEPENDENT_ROUNDING (type)
|
|
&& single_use (@0))
|
|
(rdiv @1 (negate @2))))
|
|
|
|
(simplify
|
|
(negate (rdiv@0 negate_expr_p@1 @2))
|
|
(if (! HONOR_SIGN_DEPENDENT_ROUNDING (type)
|
|
&& single_use (@0))
|
|
(rdiv (negate @1) @2)))
|
|
|
|
/* Fold -((int)x >> (prec - 1)) into (unsigned)x >> (prec - 1). */
|
|
(simplify
|
|
(negate (convert? (rshift @0 INTEGER_CST@1)))
|
|
(if (tree_nop_conversion_p (type, TREE_TYPE (@0))
|
|
&& wi::to_wide (@1) == element_precision (type) - 1)
|
|
(with { tree stype = TREE_TYPE (@0);
|
|
tree ntype = TYPE_UNSIGNED (stype) ? signed_type_for (stype)
|
|
: unsigned_type_for (stype); }
|
|
(if (VECTOR_TYPE_P (type))
|
|
(view_convert (rshift (view_convert:ntype @0) @1))
|
|
(convert (rshift (convert:ntype @0) @1))))))
|
|
|
|
/* Try to fold (type) X op CST -> (type) (X op ((type-x) CST))
|
|
when profitable.
|
|
For bitwise binary operations apply operand conversions to the
|
|
binary operation result instead of to the operands. This allows
|
|
to combine successive conversions and bitwise binary operations.
|
|
We combine the above two cases by using a conditional convert. */
|
|
(for bitop (bit_and bit_ior bit_xor)
|
|
(simplify
|
|
(bitop (convert@2 @0) (convert?@3 @1))
|
|
(if (((TREE_CODE (@1) == INTEGER_CST
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& (int_fits_type_p (@1, TREE_TYPE (@0))
|
|
|| tree_nop_conversion_p (TREE_TYPE (@0), type)))
|
|
|| types_match (@0, @1))
|
|
/* ??? This transform conflicts with fold-const.cc doing
|
|
Convert (T)(x & c) into (T)x & (T)c, if c is an integer
|
|
constants (if x has signed type, the sign bit cannot be set
|
|
in c). This folds extension into the BIT_AND_EXPR.
|
|
Restrict it to GIMPLE to avoid endless recursions. */
|
|
&& (bitop != BIT_AND_EXPR || GIMPLE)
|
|
&& (/* That's a good idea if the conversion widens the operand, thus
|
|
after hoisting the conversion the operation will be narrower.
|
|
It is also a good if the conversion is a nop as moves the
|
|
conversion to one side; allowing for combining of the conversions. */
|
|
TYPE_PRECISION (TREE_TYPE (@0)) < TYPE_PRECISION (type)
|
|
/* The conversion check for being a nop can only be done at the gimple
|
|
level as fold_binary has some re-association code which can conflict
|
|
with this if there is a "constant" which is not a full INTEGER_CST. */
|
|
|| (GIMPLE && TYPE_PRECISION (TREE_TYPE (@0)) == TYPE_PRECISION (type))
|
|
/* It's also a good idea if the conversion is to a non-integer
|
|
mode. */
|
|
|| GET_MODE_CLASS (TYPE_MODE (type)) != MODE_INT
|
|
/* Or if the precision of TO is not the same as the precision
|
|
of its mode. */
|
|
|| !type_has_mode_precision_p (type)
|
|
/* In GIMPLE, getting rid of 2 conversions for one new results
|
|
in smaller IL. */
|
|
|| (GIMPLE
|
|
&& TREE_CODE (@1) != INTEGER_CST
|
|
&& tree_nop_conversion_p (type, TREE_TYPE (@0))
|
|
&& single_use (@2)
|
|
&& single_use (@3))))
|
|
(convert (bitop @0 (convert @1)))))
|
|
/* In GIMPLE, getting rid of 2 conversions for one new results
|
|
in smaller IL. */
|
|
(simplify
|
|
(convert (bitop:cs@2 (nop_convert:s @0) @1))
|
|
(if (GIMPLE
|
|
&& TREE_CODE (@1) != INTEGER_CST
|
|
&& tree_nop_conversion_p (type, TREE_TYPE (@2))
|
|
&& types_match (type, @0))
|
|
(bitop @0 (convert @1)))))
|
|
|
|
(for bitop (bit_and bit_ior)
|
|
rbitop (bit_ior bit_and)
|
|
/* (x | y) & x -> x */
|
|
/* (x & y) | x -> x */
|
|
(simplify
|
|
(bitop:c (rbitop:c @0 @1) @0)
|
|
@0)
|
|
/* (~x | y) & x -> x & y */
|
|
/* (~x & y) | x -> x | y */
|
|
(simplify
|
|
(bitop:c (rbitop:c (bit_not @0) @1) @0)
|
|
(bitop @0 @1)))
|
|
|
|
/* ((x | y) & z) | x -> (z & y) | x */
|
|
(simplify
|
|
(bit_ior:c (bit_and:cs (bit_ior:cs @0 @1) @2) @0)
|
|
(bit_ior (bit_and @2 @1) @0))
|
|
|
|
/* (x | CST1) & CST2 -> (x & CST2) | (CST1 & CST2) */
|
|
(simplify
|
|
(bit_and (bit_ior @0 CONSTANT_CLASS_P@1) CONSTANT_CLASS_P@2)
|
|
(bit_ior (bit_and @0 @2) (bit_and @1 @2)))
|
|
|
|
/* Combine successive equal operations with constants. */
|
|
(for bitop (bit_and bit_ior bit_xor)
|
|
(simplify
|
|
(bitop (bitop @0 CONSTANT_CLASS_P@1) CONSTANT_CLASS_P@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. */
|
|
(match truth_valued_p
|
|
@0
|
|
(if (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) == 1)))
|
|
(for op (tcc_comparison truth_and truth_andif truth_or truth_orif truth_xor)
|
|
(match truth_valued_p
|
|
(op @0 @1)))
|
|
(match truth_valued_p
|
|
(truth_not @0))
|
|
|
|
(match (logical_inverted_value @0)
|
|
(truth_not @0))
|
|
(match (logical_inverted_value @0)
|
|
(bit_not truth_valued_p@0))
|
|
(match (logical_inverted_value @0)
|
|
(eq @0 integer_zerop))
|
|
(match (logical_inverted_value @0)
|
|
(ne truth_valued_p@0 integer_truep))
|
|
(match (logical_inverted_value @0)
|
|
(bit_xor truth_valued_p@0 integer_truep))
|
|
|
|
/* X & !X -> 0. */
|
|
(simplify
|
|
(bit_and:c @0 (logical_inverted_value @0))
|
|
{ build_zero_cst (type); })
|
|
/* X | !X and X ^ !X -> 1, , if X is truth-valued. */
|
|
(for op (bit_ior bit_xor)
|
|
(simplify
|
|
(op:c truth_valued_p@0 (logical_inverted_value @0))
|
|
{ constant_boolean_node (true, type); }))
|
|
/* X ==/!= !X is false/true. */
|
|
(for op (eq ne)
|
|
(simplify
|
|
(op:c truth_valued_p@0 (logical_inverted_value @0))
|
|
{ constant_boolean_node (op == NE_EXPR ? true : false, type); }))
|
|
|
|
/* ~~x -> x */
|
|
(simplify
|
|
(bit_not (bit_not @0))
|
|
@0)
|
|
|
|
/* Convert ~ (-A) to A - 1. */
|
|
(simplify
|
|
(bit_not (convert? (negate @0)))
|
|
(if (element_precision (type) <= element_precision (TREE_TYPE (@0))
|
|
|| !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); }))
|
|
|
|
/* (a & b) ^ (a == b) -> !(a | b) */
|
|
/* (a & b) == (a ^ b) -> !(a | b) */
|
|
(for first_op (bit_xor eq)
|
|
second_op (eq bit_xor)
|
|
(simplify
|
|
(first_op:c (bit_and:c truth_valued_p@0 truth_valued_p@1) (second_op:c @0 @1))
|
|
(bit_not (bit_ior @0 @1))))
|
|
|
|
/* Convert ~ (A - 1) or ~ (A + -1) to -A. */
|
|
(simplify
|
|
(bit_not (convert? (minus @0 integer_each_onep)))
|
|
(if (element_precision (type) <= element_precision (TREE_TYPE (@0))
|
|
|| !TYPE_UNSIGNED (TREE_TYPE (@0)))
|
|
(convert (negate @0))))
|
|
(simplify
|
|
(bit_not (convert? (plus @0 integer_all_onesp)))
|
|
(if (element_precision (type) <= element_precision (TREE_TYPE (@0))
|
|
|| !TYPE_UNSIGNED (TREE_TYPE (@0)))
|
|
(convert (negate @0))))
|
|
|
|
/* Part of convert ~(X ^ Y) to ~X ^ Y or X ^ ~Y if ~X or ~Y simplify. */
|
|
(simplify
|
|
(bit_not (convert? (bit_xor @0 INTEGER_CST@1)))
|
|
(if (tree_nop_conversion_p (type, TREE_TYPE (@0)))
|
|
(convert (bit_xor @0 (bit_not @1)))))
|
|
(simplify
|
|
(bit_not (convert? (bit_xor:c (bit_not @0) @1)))
|
|
(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))
|
|
(bit_xor (bit_and (bit_xor @0 @1) @2) @0))
|
|
|
|
/* Fold A - (A & B) into ~B & A. */
|
|
(simplify
|
|
(minus (convert1? @0) (convert2?:s (bit_and:cs @@0 @1)))
|
|
(if (tree_nop_conversion_p (type, TREE_TYPE (@0))
|
|
&& tree_nop_conversion_p (type, TREE_TYPE (@1)))
|
|
(convert (bit_and (bit_not @1) @0))))
|
|
|
|
/* (m1 CMP m2) * d -> (m1 CMP m2) ? d : 0 */
|
|
(if (!canonicalize_math_p ())
|
|
(for cmp (gt lt ge le)
|
|
(simplify
|
|
(mult (convert (cmp @0 @1)) @2)
|
|
(cond (cmp @0 @1) @2 { build_zero_cst (type); }))))
|
|
|
|
/* For integral types with undefined overflow and C != 0 fold
|
|
x * C EQ/NE y * C into x EQ/NE y. */
|
|
(for cmp (eq ne)
|
|
(simplify
|
|
(cmp (mult:c @0 @1) (mult:c @2 @1))
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
|
|
&& TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
|
|
&& tree_expr_nonzero_p (@1))
|
|
(cmp @0 @2))))
|
|
|
|
/* For integral types with wrapping overflow and C odd fold
|
|
x * C EQ/NE y * C into x EQ/NE y. */
|
|
(for cmp (eq ne)
|
|
(simplify
|
|
(cmp (mult @0 INTEGER_CST@1) (mult @2 @1))
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
|
|
&& TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))
|
|
&& (TREE_INT_CST_LOW (@1) & 1) != 0)
|
|
(cmp @0 @2))))
|
|
|
|
/* For integral types with undefined overflow and C != 0 fold
|
|
x * C RELOP y * C into:
|
|
|
|
x RELOP y for nonnegative C
|
|
y RELOP x for negative C */
|
|
(for cmp (lt gt le ge)
|
|
(simplify
|
|
(cmp (mult:c @0 @1) (mult:c @2 @1))
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
|
|
&& TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)))
|
|
(if (tree_expr_nonnegative_p (@1) && tree_expr_nonzero_p (@1))
|
|
(cmp @0 @2)
|
|
(if (TREE_CODE (@1) == INTEGER_CST
|
|
&& wi::neg_p (wi::to_wide (@1), TYPE_SIGN (TREE_TYPE (@1))))
|
|
(cmp @2 @0))))))
|
|
|
|
/* (X - 1U) <= INT_MAX-1U into (int) X > 0. */
|
|
(for cmp (le gt)
|
|
icmp (gt le)
|
|
(simplify
|
|
(cmp (plus @0 integer_minus_onep@1) INTEGER_CST@2)
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& TYPE_UNSIGNED (TREE_TYPE (@0))
|
|
&& TYPE_PRECISION (TREE_TYPE (@0)) > 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 (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)
|
|
(simplify
|
|
(cmp (trunc_div:s @0 INTEGER_CST@1) INTEGER_CST@2)
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& integer_nonzerop (@1)
|
|
&& !TREE_OVERFLOW (@1)
|
|
&& !TREE_OVERFLOW (@2))
|
|
(with { tree lo, hi; bool neg_overflow;
|
|
enum tree_code code = fold_div_compare (cmp, @1, @2, &lo, &hi,
|
|
&neg_overflow); }
|
|
(switch
|
|
(if (code == LT_EXPR || code == GE_EXPR)
|
|
(if (TREE_OVERFLOW (lo))
|
|
{ build_int_cst (type, (code == LT_EXPR) ^ neg_overflow); }
|
|
(if (code == LT_EXPR)
|
|
(lt @0 { lo; })
|
|
(ge @0 { lo; }))))
|
|
(if (code == LE_EXPR || code == GT_EXPR)
|
|
(if (TREE_OVERFLOW (hi))
|
|
{ build_int_cst (type, (code == LE_EXPR) ^ neg_overflow); }
|
|
(if (code == LE_EXPR)
|
|
(le @0 { hi; })
|
|
(gt @0 { hi; }))))
|
|
(if (!lo && !hi)
|
|
{ build_int_cst (type, code == NE_EXPR); })
|
|
(if (code == EQ_EXPR && !hi)
|
|
(ge @0 { lo; }))
|
|
(if (code == EQ_EXPR && !lo)
|
|
(le @0 { hi; }))
|
|
(if (code == NE_EXPR && !hi)
|
|
(lt @0 { lo; }))
|
|
(if (code == NE_EXPR && !lo)
|
|
(gt @0 { hi; }))
|
|
(if (GENERIC)
|
|
{ build_range_check (UNKNOWN_LOCATION, type, @0, code == EQ_EXPR,
|
|
lo, hi); })
|
|
(with
|
|
{
|
|
tree etype = range_check_type (TREE_TYPE (@0));
|
|
if (etype)
|
|
{
|
|
hi = fold_convert (etype, hi);
|
|
lo = fold_convert (etype, lo);
|
|
hi = const_binop (MINUS_EXPR, etype, hi, lo);
|
|
}
|
|
}
|
|
(if (etype && hi && !TREE_OVERFLOW (hi))
|
|
(if (code == EQ_EXPR)
|
|
(le (minus (convert:etype @0) { lo; }) { hi; })
|
|
(gt (minus (convert:etype @0) { lo; }) { hi; })))))))))
|
|
|
|
/* X + Z < Y + Z is the same as X < Y when there is no overflow. */
|
|
(for op (lt le ge gt)
|
|
(simplify
|
|
(op (plus:c @0 @2) (plus:c @1 @2))
|
|
(if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)))
|
|
(op @0 @1))))
|
|
/* For equality and subtraction, this is also true with wrapping overflow. */
|
|
(for op (eq ne minus)
|
|
(simplify
|
|
(op (plus:c @0 @2) (plus:c @1 @2))
|
|
(if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
|
|
|| TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))))
|
|
(op @0 @1))))
|
|
|
|
/* X - Z < Y - Z is the same as X < Y when there is no overflow. */
|
|
(for op (lt le ge gt)
|
|
(simplify
|
|
(op (minus @0 @2) (minus @1 @2))
|
|
(if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)))
|
|
(op @0 @1))))
|
|
/* For equality and subtraction, this is also true with wrapping overflow. */
|
|
(for op (eq ne minus)
|
|
(simplify
|
|
(op (minus @0 @2) (minus @1 @2))
|
|
(if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& (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)
|
|
(simplify
|
|
(op (minus @2 @0) (minus @2 @1))
|
|
(if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)))
|
|
(op @1 @0))))
|
|
/* For equality and subtraction, this is also true with wrapping overflow. */
|
|
(for op (eq ne minus)
|
|
(simplify
|
|
(op (minus @2 @0) (minus @2 @1))
|
|
(if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& (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)
|
|
(simplify
|
|
(cmp:c (convert? @0) (convert1? (minus INTEGER_CST@1 (convert2? @0))))
|
|
(if (TREE_INT_CST_LOW (@1) & 1)
|
|
{ constant_boolean_node (cmp == NE_EXPR, type); })))
|
|
|
|
/* Arguments on which one can call get_nonzero_bits to get the bits
|
|
possibly set. */
|
|
(match with_possible_nonzero_bits
|
|
INTEGER_CST@0)
|
|
(match with_possible_nonzero_bits
|
|
SSA_NAME@0
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) || POINTER_TYPE_P (TREE_TYPE (@0)))))
|
|
/* Slightly extended version, do not make it recursive to keep it cheap. */
|
|
(match (with_possible_nonzero_bits2 @0)
|
|
with_possible_nonzero_bits@0)
|
|
(match (with_possible_nonzero_bits2 @0)
|
|
(bit_and:c with_possible_nonzero_bits@0 @2))
|
|
|
|
/* Same for bits that are known to be set, but we do not have
|
|
an equivalent to get_nonzero_bits yet. */
|
|
(match (with_certain_nonzero_bits2 @0)
|
|
INTEGER_CST@0)
|
|
(match (with_certain_nonzero_bits2 @0)
|
|
(bit_ior @1 INTEGER_CST@0))
|
|
|
|
/* X == C (or X & Z == Y | C) is impossible if ~nonzero(X) & C != 0. */
|
|
(for cmp (eq ne)
|
|
(simplify
|
|
(cmp:c (with_possible_nonzero_bits2 @0) (with_certain_nonzero_bits2 @1))
|
|
(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)
|
|
With X being a tree where value_range has reasoned certain bits to always be
|
|
zero throughout its computed value range,
|
|
inner_op = {|,^}, outer_op = {|,^} and inner_op != outer_op
|
|
where zero_mask has 1's for all bits that are sure to be 0 in
|
|
and 0's otherwise.
|
|
if (inner_op == '^') C0 &= ~C1;
|
|
if ((C0 & ~zero_mask) == 0) then emit (X outer_op (C0 outer_op C1)
|
|
if ((C1 & ~zero_mask) == 0) then emit (X inner_op (C0 outer_op C1)
|
|
*/
|
|
(for inner_op (bit_ior bit_xor)
|
|
outer_op (bit_xor bit_ior)
|
|
(simplify
|
|
(outer_op
|
|
(inner_op:s @2 INTEGER_CST@0) INTEGER_CST@1)
|
|
(with
|
|
{
|
|
bool fail = false;
|
|
wide_int zero_mask_not;
|
|
wide_int C0;
|
|
wide_int cst_emit;
|
|
|
|
if (TREE_CODE (@2) == SSA_NAME)
|
|
zero_mask_not = get_nonzero_bits (@2);
|
|
else
|
|
fail = true;
|
|
|
|
if (inner_op == BIT_XOR_EXPR)
|
|
{
|
|
C0 = wi::bit_and_not (wi::to_wide (@0), wi::to_wide (@1));
|
|
cst_emit = C0 | wi::to_wide (@1);
|
|
}
|
|
else
|
|
{
|
|
C0 = wi::to_wide (@0);
|
|
cst_emit = C0 ^ wi::to_wide (@1);
|
|
}
|
|
}
|
|
(if (!fail && (C0 & zero_mask_not) == 0)
|
|
(outer_op @2 { wide_int_to_tree (type, cst_emit); })
|
|
(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)). */
|
|
(simplify
|
|
(pointer_plus (pointer_plus:s @0 @1) @3)
|
|
(pointer_plus @0 (plus @1 @3)))
|
|
#if GENERIC
|
|
(simplify
|
|
(pointer_plus (convert:s (pointer_plus:s @0 @1)) @3)
|
|
(convert:type (pointer_plus @0 (plus @1 @3))))
|
|
#endif
|
|
|
|
/* Pattern match
|
|
tem1 = (long) ptr1;
|
|
tem2 = (long) ptr2;
|
|
tem3 = tem2 - tem1;
|
|
tem4 = (unsigned long) tem3;
|
|
tem5 = ptr1 + tem4;
|
|
and produce
|
|
tem5 = ptr2; */
|
|
(simplify
|
|
(pointer_plus @0 (convert?@2 (minus@3 (convert @1) (convert @0))))
|
|
/* Conditionally look through a sign-changing conversion. */
|
|
(if (TYPE_PRECISION (TREE_TYPE (@2)) == TYPE_PRECISION (TREE_TYPE (@3))
|
|
&& ((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;
|
|
tem = tem & algn;
|
|
tem = -tem;
|
|
... = ptr p+ tem;
|
|
and produce the simpler and easier to analyze with respect to alignment
|
|
... = 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::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 { 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 { 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); }))))
|
|
|
|
/* (&a+b) - (&a[1] + c) -> sizeof(a[0]) + (b - c) */
|
|
(simplify
|
|
(pointer_diff (pointer_plus ADDR_EXPR@0 @1) (pointer_plus ADDR_EXPR@2 @3))
|
|
(with { poly_int64 diff; }
|
|
(if (ptr_difference_const (@0, @2, &diff))
|
|
(plus { build_int_cst_type (type, diff); } (convert (minus @1 @3))))))
|
|
|
|
/* (&a+b) !=/== (&a[1] + c) -> sizeof(a[0]) + b !=/== c */
|
|
(for neeq (ne eq)
|
|
(simplify
|
|
(neeq (pointer_plus ADDR_EXPR@0 @1) (pointer_plus ADDR_EXPR@2 @3))
|
|
(with { poly_int64 diff; tree inner_type = TREE_TYPE (@1);}
|
|
(if (ptr_difference_const (@0, @2, &diff))
|
|
(neeq (plus { build_int_cst_type (inner_type, diff); } @1) @3)))))
|
|
|
|
/* Canonicalize (T *)(ptr - ptr-cst) to &MEM[ptr + -ptr-cst]. */
|
|
(simplify
|
|
(convert (pointer_diff @0 INTEGER_CST@1))
|
|
(if (POINTER_TYPE_P (type))
|
|
{ build_fold_addr_expr_with_type
|
|
(build2 (MEM_REF, char_type_node, @0,
|
|
wide_int_to_tree (ptr_type_node, wi::neg (wi::to_wide (@1)))),
|
|
type); }))
|
|
|
|
/* If arg0 is derived from the address of an object or function, we may
|
|
be able to fold this expression using the object or function's
|
|
alignment. */
|
|
(simplify
|
|
(bit_and (convert? @0) INTEGER_CST@1)
|
|
(if (POINTER_TYPE_P (TREE_TYPE (@0))
|
|
&& tree_nop_conversion_p (type, TREE_TYPE (@0)))
|
|
(with
|
|
{
|
|
unsigned int align;
|
|
unsigned HOST_WIDE_INT bitpos;
|
|
get_pointer_alignment_1 (@0, &align, &bitpos);
|
|
}
|
|
(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))); }))))
|
|
|
|
(match min_value
|
|
INTEGER_CST
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& wi::eq_p (wi::to_wide (t), wi::min_value (type)))))
|
|
|
|
(match max_value
|
|
INTEGER_CST
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& wi::eq_p (wi::to_wide (t), wi::max_value (type)))))
|
|
|
|
/* x > y && x != XXX_MIN --> x > y
|
|
x > y && x == XXX_MIN --> false . */
|
|
(for eqne (eq ne)
|
|
(simplify
|
|
(bit_and:c (gt:c@2 @0 @1) (eqne @0 min_value))
|
|
(switch
|
|
(if (eqne == EQ_EXPR)
|
|
{ constant_boolean_node (false, type); })
|
|
(if (eqne == NE_EXPR)
|
|
@2)
|
|
)))
|
|
|
|
/* x < y && x != XXX_MAX --> x < y
|
|
x < y && x == XXX_MAX --> false. */
|
|
(for eqne (eq ne)
|
|
(simplify
|
|
(bit_and:c (lt:c@2 @0 @1) (eqne @0 max_value))
|
|
(switch
|
|
(if (eqne == EQ_EXPR)
|
|
{ constant_boolean_node (false, type); })
|
|
(if (eqne == NE_EXPR)
|
|
@2)
|
|
)))
|
|
|
|
/* x <= y && x == XXX_MIN --> x == XXX_MIN. */
|
|
(simplify
|
|
(bit_and:c (le:c @0 @1) (eq@2 @0 min_value))
|
|
@2)
|
|
|
|
/* x >= y && x == XXX_MAX --> x == XXX_MAX. */
|
|
(simplify
|
|
(bit_and:c (ge:c @0 @1) (eq@2 @0 max_value))
|
|
@2)
|
|
|
|
/* x > y || x != XXX_MIN --> x != XXX_MIN. */
|
|
(simplify
|
|
(bit_ior:c (gt:c @0 @1) (ne@2 @0 min_value))
|
|
@2)
|
|
|
|
/* x <= y || x != XXX_MIN --> true. */
|
|
(simplify
|
|
(bit_ior:c (le:c @0 @1) (ne @0 min_value))
|
|
{ constant_boolean_node (true, type); })
|
|
|
|
/* x <= y || x == XXX_MIN --> x <= y. */
|
|
(simplify
|
|
(bit_ior:c (le:c@2 @0 @1) (eq @0 min_value))
|
|
@2)
|
|
|
|
/* x < y || x != XXX_MAX --> x != XXX_MAX. */
|
|
(simplify
|
|
(bit_ior:c (lt:c @0 @1) (ne@2 @0 max_value))
|
|
@2)
|
|
|
|
/* x >= y || x != XXX_MAX --> true
|
|
x >= y || x == XXX_MAX --> x >= y. */
|
|
(for eqne (eq ne)
|
|
(simplify
|
|
(bit_ior:c (ge:c@2 @0 @1) (eqne @0 max_value))
|
|
(switch
|
|
(if (eqne == EQ_EXPR)
|
|
@2)
|
|
(if (eqne == NE_EXPR)
|
|
{ constant_boolean_node (true, type); }))))
|
|
|
|
/* y == XXX_MIN || x < y --> x <= y - 1 */
|
|
(simplify
|
|
(bit_ior:c (eq:s @1 min_value) (lt:s @0 @1))
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
|
|
&& TYPE_OVERFLOW_WRAPS (TREE_TYPE (@1)))
|
|
(le @0 (minus @1 { build_int_cst (TREE_TYPE (@1), 1); }))))
|
|
|
|
/* y != XXX_MIN && x >= y --> x > y - 1 */
|
|
(simplify
|
|
(bit_and:c (ne:s @1 min_value) (ge:s @0 @1))
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
|
|
&& 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
|
|
based on CST1 OP2 CST2. Similarly for (X != CST1). */
|
|
|
|
(for code1 (eq ne)
|
|
(for code2 (eq ne lt gt le ge)
|
|
(simplify
|
|
(bit_and:c (code1@3 @0 INTEGER_CST@1) (code2@4 @0 INTEGER_CST@2))
|
|
(with
|
|
{
|
|
int cmp = tree_int_cst_compare (@1, @2);
|
|
bool val;
|
|
switch (code2)
|
|
{
|
|
case EQ_EXPR: val = (cmp == 0); break;
|
|
case NE_EXPR: val = (cmp != 0); break;
|
|
case LT_EXPR: val = (cmp < 0); break;
|
|
case GT_EXPR: val = (cmp > 0); break;
|
|
case LE_EXPR: val = (cmp <= 0); break;
|
|
case GE_EXPR: val = (cmp >= 0); break;
|
|
default: gcc_unreachable ();
|
|
}
|
|
}
|
|
(switch
|
|
(if (code1 == EQ_EXPR && val) @3)
|
|
(if (code1 == EQ_EXPR && !val) { constant_boolean_node (false, type); })
|
|
(if (code1 == NE_EXPR && !val) @4))))))
|
|
|
|
/* Convert (X OP1 CST1) && (X OP2 CST2). */
|
|
|
|
(for code1 (lt le gt ge)
|
|
(for code2 (lt le gt ge)
|
|
(simplify
|
|
(bit_and (code1:c@3 @0 INTEGER_CST@1) (code2:c@4 @0 INTEGER_CST@2))
|
|
(with
|
|
{
|
|
int cmp = tree_int_cst_compare (@1, @2);
|
|
}
|
|
(switch
|
|
/* Choose the more restrictive of two < or <= comparisons. */
|
|
(if ((code1 == LT_EXPR || code1 == LE_EXPR)
|
|
&& (code2 == LT_EXPR || code2 == LE_EXPR))
|
|
(if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
|
|
@3
|
|
@4))
|
|
/* Likewise chose the more restrictive of two > or >= comparisons. */
|
|
(if ((code1 == GT_EXPR || code1 == GE_EXPR)
|
|
&& (code2 == GT_EXPR || code2 == GE_EXPR))
|
|
(if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR))
|
|
@3
|
|
@4))
|
|
/* Check for singleton ranges. */
|
|
(if (cmp == 0
|
|
&& ((code1 == LE_EXPR && code2 == GE_EXPR)
|
|
|| (code1 == GE_EXPR && code2 == LE_EXPR)))
|
|
(eq @0 @1))
|
|
/* Check for disjoint ranges. */
|
|
(if (cmp <= 0
|
|
&& (code1 == LT_EXPR || code1 == LE_EXPR)
|
|
&& (code2 == GT_EXPR || code2 == GE_EXPR))
|
|
{ constant_boolean_node (false, type); })
|
|
(if (cmp >= 0
|
|
&& (code1 == GT_EXPR || code1 == GE_EXPR)
|
|
&& (code2 == LT_EXPR || code2 == LE_EXPR))
|
|
{ constant_boolean_node (false, type); })
|
|
)))))
|
|
|
|
/* Convert (X == CST1) || (X OP2 CST2) to a known value
|
|
based on CST1 OP2 CST2. Similarly for (X != CST1). */
|
|
|
|
(for code1 (eq ne)
|
|
(for code2 (eq ne lt gt le ge)
|
|
(simplify
|
|
(bit_ior:c (code1@3 @0 INTEGER_CST@1) (code2@4 @0 INTEGER_CST@2))
|
|
(with
|
|
{
|
|
int cmp = tree_int_cst_compare (@1, @2);
|
|
bool val;
|
|
switch (code2)
|
|
{
|
|
case EQ_EXPR: val = (cmp == 0); break;
|
|
case NE_EXPR: val = (cmp != 0); break;
|
|
case LT_EXPR: val = (cmp < 0); break;
|
|
case GT_EXPR: val = (cmp > 0); break;
|
|
case LE_EXPR: val = (cmp <= 0); break;
|
|
case GE_EXPR: val = (cmp >= 0); break;
|
|
default: gcc_unreachable ();
|
|
}
|
|
}
|
|
(switch
|
|
(if (code1 == EQ_EXPR && val) @4)
|
|
(if (code1 == NE_EXPR && val) { constant_boolean_node (true, type); })
|
|
(if (code1 == NE_EXPR && !val) @3))))))
|
|
|
|
/* Convert (X OP1 CST1) || (X OP2 CST2). */
|
|
|
|
(for code1 (lt le gt ge)
|
|
(for code2 (lt le gt ge)
|
|
(simplify
|
|
(bit_ior (code1@3 @0 INTEGER_CST@1) (code2@4 @0 INTEGER_CST@2))
|
|
(with
|
|
{
|
|
int cmp = tree_int_cst_compare (@1, @2);
|
|
}
|
|
(switch
|
|
/* Choose the more restrictive of two < or <= comparisons. */
|
|
(if ((code1 == LT_EXPR || code1 == LE_EXPR)
|
|
&& (code2 == LT_EXPR || code2 == LE_EXPR))
|
|
(if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
|
|
@4
|
|
@3))
|
|
/* Likewise chose the more restrictive of two > or >= comparisons. */
|
|
(if ((code1 == GT_EXPR || code1 == GE_EXPR)
|
|
&& (code2 == GT_EXPR || code2 == GE_EXPR))
|
|
(if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR))
|
|
@4
|
|
@3))
|
|
/* Check for singleton ranges. */
|
|
(if (cmp == 0
|
|
&& ((code1 == LT_EXPR && code2 == GT_EXPR)
|
|
|| (code1 == GT_EXPR && code2 == LT_EXPR)))
|
|
(ne @0 @2))
|
|
/* Check for disjoint ranges. */
|
|
(if (cmp >= 0
|
|
&& (code1 == LT_EXPR || code1 == LE_EXPR)
|
|
&& (code2 == GT_EXPR || code2 == GE_EXPR))
|
|
{ constant_boolean_node (true, type); })
|
|
(if (cmp <= 0
|
|
&& (code1 == GT_EXPR || code1 == GE_EXPR)
|
|
&& (code2 == LT_EXPR || code2 == LE_EXPR))
|
|
{ constant_boolean_node (true, type); })
|
|
)))))
|
|
|
|
/* We can't reassociate at all for saturating types. */
|
|
(if (!TYPE_SATURATING (type))
|
|
|
|
/* Contract negates. */
|
|
/* A + (-B) -> A - B */
|
|
(simplify
|
|
(plus:c @0 (convert? (negate @1)))
|
|
/* Apply STRIP_NOPS on the negate. */
|
|
(if (tree_nop_conversion_p (type, TREE_TYPE (@1))
|
|
&& !TYPE_OVERFLOW_SANITIZED (type))
|
|
(with
|
|
{
|
|
tree t1 = type;
|
|
if (INTEGRAL_TYPE_P (type)
|
|
&& TYPE_OVERFLOW_WRAPS (type) != TYPE_OVERFLOW_WRAPS (TREE_TYPE (@1)))
|
|
t1 = TYPE_OVERFLOW_WRAPS (type) ? type : TREE_TYPE (@1);
|
|
}
|
|
(convert (minus (convert:t1 @0) (convert:t1 @1))))))
|
|
/* A - (-B) -> A + B */
|
|
(simplify
|
|
(minus @0 (convert? (negate @1)))
|
|
(if (tree_nop_conversion_p (type, TREE_TYPE (@1))
|
|
&& !TYPE_OVERFLOW_SANITIZED (type))
|
|
(with
|
|
{
|
|
tree t1 = type;
|
|
if (INTEGRAL_TYPE_P (type)
|
|
&& TYPE_OVERFLOW_WRAPS (type) != TYPE_OVERFLOW_WRAPS (TREE_TYPE (@1)))
|
|
t1 = TYPE_OVERFLOW_WRAPS (type) ? type : TREE_TYPE (@1);
|
|
}
|
|
(convert (plus (convert:t1 @0) (convert:t1 @1))))))
|
|
/* -(T)(-A) -> (T)A
|
|
Sign-extension is ok except for INT_MIN, which thankfully cannot
|
|
happen without overflow. */
|
|
(simplify
|
|
(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. */
|
|
(if ((!FLOAT_TYPE_P (type) || flag_associative_math)
|
|
&& !FIXED_POINT_TYPE_P (type))
|
|
|
|
/* Match patterns that allow contracting a plus-minus pair
|
|
irrespective of overflow issues. */
|
|
/* (A +- B) - A -> +- B */
|
|
/* (A +- B) -+ B -> A */
|
|
/* A - (A +- B) -> -+ B */
|
|
/* A +- (B -+ A) -> +- B */
|
|
(simplify
|
|
(minus (nop_convert1? (plus:c (nop_convert2? @0) @1)) @0)
|
|
(view_convert @1))
|
|
(simplify
|
|
(minus (nop_convert1? (minus (nop_convert2? @0) @1)) @0)
|
|
(if (!ANY_INTEGRAL_TYPE_P (type)
|
|
|| TYPE_OVERFLOW_WRAPS (type))
|
|
(negate (view_convert @1))
|
|
(view_convert (negate @1))))
|
|
(simplify
|
|
(plus:c (nop_convert1? (minus @0 (nop_convert2? @1))) @1)
|
|
(view_convert @0))
|
|
(simplify
|
|
(minus @0 (nop_convert1? (plus:c (nop_convert2? @0) @1)))
|
|
(if (!ANY_INTEGRAL_TYPE_P (type)
|
|
|| TYPE_OVERFLOW_WRAPS (type))
|
|
(negate (view_convert @1))
|
|
(view_convert (negate @1))))
|
|
(simplify
|
|
(minus @0 (nop_convert1? (minus (nop_convert2? @0) @1)))
|
|
(view_convert @1))
|
|
/* (A +- B) + (C - A) -> C +- B */
|
|
/* (A + B) - (A - C) -> B + C */
|
|
/* More cases are handled with comparisons. */
|
|
(simplify
|
|
(plus:c (plus:c @0 @1) (minus @2 @0))
|
|
(plus @2 @1))
|
|
(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))
|
|
|
|
/* (A +- CST1) +- CST2 -> A + CST3
|
|
Use view_convert because it is safe for vectors and equivalent for
|
|
scalars. */
|
|
(for outer_op (plus minus)
|
|
(for inner_op (plus minus)
|
|
neg_inner_op (minus plus)
|
|
(simplify
|
|
(outer_op (nop_convert? (inner_op @0 CONSTANT_CLASS_P@1))
|
|
CONSTANT_CLASS_P@2)
|
|
/* If one of the types wraps, use that one. */
|
|
(if (!ANY_INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_WRAPS (type))
|
|
/* 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)
|
|
(view_convert (plus @0 (inner_op (view_convert @2) @1)))
|
|
(view_convert (minus @0 (neg_inner_op (view_convert @2) @1))))
|
|
/* If the constant operation overflows we cannot do the transform
|
|
directly as we would introduce undefined overflow, for example
|
|
with (a - 1) + INT_MIN. */
|
|
(if (types_match (type, @0))
|
|
(with { tree cst = const_binop (outer_op == inner_op
|
|
? PLUS_EXPR : MINUS_EXPR,
|
|
type, @1, @2); }
|
|
(if (cst && !TREE_OVERFLOW (cst))
|
|
(inner_op @0 { cst; } )
|
|
/* X+INT_MAX+1 is X-INT_MIN. */
|
|
(if (INTEGRAL_TYPE_P (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); }
|
|
(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)
|
|
(simplify
|
|
(outer_op (nop_convert? (minus CONSTANT_CLASS_P@1 @0)) CONSTANT_CLASS_P@2)
|
|
/* If one of the types wraps, use that one. */
|
|
(if (!ANY_INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_WRAPS (type))
|
|
/* 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))
|
|
(minus (outer_op (view_convert @1) @2) (view_convert @0)))
|
|
(if (!ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
|| TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0)))
|
|
(view_convert (minus (outer_op @1 (view_convert @2)) @0))
|
|
(if (types_match (type, @0))
|
|
(with { tree cst = const_binop (outer_op, type, @1, @2); }
|
|
(if (cst && !TREE_OVERFLOW (cst))
|
|
(minus { cst; } @0))))))))
|
|
|
|
/* CST1 - (CST2 - A) -> CST3 + A
|
|
Use view_convert because it is safe for vectors and equivalent for
|
|
scalars. */
|
|
(simplify
|
|
(minus CONSTANT_CLASS_P@1 (nop_convert? (minus CONSTANT_CLASS_P@2 @0)))
|
|
/* If one of the types wraps, use that one. */
|
|
(if (!ANY_INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_WRAPS (type))
|
|
/* 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))
|
|
(plus (view_convert @0) (minus @1 (view_convert @2))))
|
|
(if (!ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
|| TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0)))
|
|
(view_convert (plus @0 (minus (view_convert @1) @2)))
|
|
(if (types_match (type, @0))
|
|
(with { tree cst = const_binop (MINUS_EXPR, type, @1, @2); }
|
|
(if (cst && !TREE_OVERFLOW (cst))
|
|
(plus { cst; } @0)))))))
|
|
|
|
/* ((T)(A)) + CST -> (T)(A + CST) */
|
|
#if GIMPLE
|
|
(simplify
|
|
(plus (convert:s SSA_NAME@0) INTEGER_CST@1)
|
|
(if (TREE_CODE (TREE_TYPE (@0)) == INTEGER_TYPE
|
|
&& TREE_CODE (type) == INTEGER_TYPE
|
|
&& TYPE_PRECISION (type) > TYPE_PRECISION (TREE_TYPE (@0))
|
|
&& int_fits_type_p (@1, TREE_TYPE (@0)))
|
|
/* Perform binary operation inside the cast if the constant fits
|
|
and (A + CST)'s range does not overflow. */
|
|
(with
|
|
{
|
|
wi::overflow_type min_ovf = wi::OVF_OVERFLOW,
|
|
max_ovf = wi::OVF_OVERFLOW;
|
|
tree inner_type = TREE_TYPE (@0);
|
|
|
|
wide_int w1
|
|
= wide_int::from (wi::to_wide (@1), TYPE_PRECISION (inner_type),
|
|
TYPE_SIGN (inner_type));
|
|
|
|
value_range vr;
|
|
if (get_global_range_query ()->range_of_expr (vr, @0)
|
|
&& vr.kind () == VR_RANGE)
|
|
{
|
|
wide_int wmin0 = vr.lower_bound ();
|
|
wide_int wmax0 = vr.upper_bound ();
|
|
wi::add (wmin0, w1, TYPE_SIGN (inner_type), &min_ovf);
|
|
wi::add (wmax0, w1, TYPE_SIGN (inner_type), &max_ovf);
|
|
}
|
|
}
|
|
(if (min_ovf == wi::OVF_NONE && max_ovf == wi::OVF_NONE)
|
|
(convert (plus @0 { wide_int_to_tree (TREE_TYPE (@0), w1); } )))
|
|
)))
|
|
#endif
|
|
|
|
/* ((T)(A + CST1)) + CST2 -> (T)(A) + (T)CST1 + CST2 */
|
|
#if GIMPLE
|
|
(for op (plus minus)
|
|
(simplify
|
|
(plus (convert:s (op:s @0 INTEGER_CST@1)) INTEGER_CST@2)
|
|
(if (TREE_CODE (TREE_TYPE (@0)) == INTEGER_TYPE
|
|
&& TREE_CODE (type) == INTEGER_TYPE
|
|
&& TYPE_PRECISION (type) > TYPE_PRECISION (TREE_TYPE (@0))
|
|
&& TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
|
|
&& !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@0))
|
|
&& TYPE_OVERFLOW_WRAPS (type))
|
|
(plus (convert @0) (op @2 (convert @1))))))
|
|
#endif
|
|
|
|
/* (T)(A) +- (T)(B) -> (T)(A +- B) only when (A +- B) could be simplified
|
|
to a simple value. */
|
|
#if GIMPLE
|
|
(for op (plus minus)
|
|
(simplify
|
|
(op (convert @0) (convert @1))
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@0))
|
|
&& types_match (TREE_TYPE (@0), TREE_TYPE (@1))
|
|
&& !TYPE_OVERFLOW_TRAPS (type)
|
|
&& !TYPE_OVERFLOW_SANITIZED (type))
|
|
(convert (op! @0 @1)))))
|
|
#endif
|
|
|
|
/* ~A + A -> -1 */
|
|
(simplify
|
|
(plus:c (bit_not @0) @0)
|
|
(if (!TYPE_OVERFLOW_TRAPS (type))
|
|
{ build_all_ones_cst (type); }))
|
|
|
|
/* ~A + 1 -> -A */
|
|
(simplify
|
|
(plus (convert? (bit_not @0)) integer_each_onep)
|
|
(if (tree_nop_conversion_p (type, TREE_TYPE (@0)))
|
|
(negate (convert @0))))
|
|
|
|
/* -A - 1 -> ~A */
|
|
(simplify
|
|
(minus (convert? (negate @0)) integer_each_onep)
|
|
(if (!TYPE_OVERFLOW_TRAPS (type)
|
|
&& TREE_CODE (type) != COMPLEX_TYPE
|
|
&& tree_nop_conversion_p (type, TREE_TYPE (@0)))
|
|
(bit_not (convert @0))))
|
|
|
|
/* -1 - A -> ~A */
|
|
(simplify
|
|
(minus integer_all_onesp @0)
|
|
(if (TREE_CODE (type) != COMPLEX_TYPE)
|
|
(bit_not @0)))
|
|
|
|
/* (T)(P + A) - (T)P -> (T) A */
|
|
(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
|
|
(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 */
|
|
(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
|
|
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))))
|
|
(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
|
|
one is correct. */
|
|
|| (POINTER_TYPE_P (TREE_TYPE (@0))
|
|
&& 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 */
|
|
(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 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
|
|
&& TREE_CODE (@2) == INTEGER_CST
|
|
&& tree_int_cst_sign_bit (@2) == 0))
|
|
(minus (convert @1) (convert @2)))))
|
|
(simplify
|
|
(pointer_diff (pointer_plus @0 @2) (pointer_plus @1 @2))
|
|
(pointer_diff @0 @1))
|
|
(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 (single_use (@3) || single_use (@4))
|
|
/* If @1 +- @2 is constant require a hard single-use on either
|
|
original operand (but not on both). */
|
|
(mult (plusminus @1 @2) @0)
|
|
#if GIMPLE
|
|
(mult! (plusminus @1 @2) @0)
|
|
#endif
|
|
)))
|
|
/* 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)
|
|
/* For @0 + @0*@2 this transformation would introduce UB
|
|
(where there was none before) for @0 in [-1,0] and @2 max.
|
|
For @0 - @0*@2 this transformation would introduce UB
|
|
for @0 0 and @2 in [min,min+1] or @0 -1 and @2 min+1. */
|
|
|| (INTEGRAL_TYPE_P (type)
|
|
&& ((tree_expr_nonzero_p (@0)
|
|
&& expr_not_equal_to (@0,
|
|
wi::minus_one (TYPE_PRECISION (type))))
|
|
|| (plusminus == PLUS_EXPR
|
|
? expr_not_equal_to (@2,
|
|
wi::max_value (TYPE_PRECISION (type), SIGNED))
|
|
/* Let's ignore the @0 -1 and @2 min case. */
|
|
: (expr_not_equal_to (@2,
|
|
wi::min_value (TYPE_PRECISION (type), SIGNED))
|
|
&& expr_not_equal_to (@2,
|
|
wi::min_value (TYPE_PRECISION (type), SIGNED)
|
|
+ 1))))))
|
|
&& 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)
|
|
/* For @0*@2 + @0 this transformation would introduce UB
|
|
(where there was none before) for @0 in [-1,0] and @2 max.
|
|
For @0*@2 - @0 this transformation would introduce UB
|
|
for @0 0 and @2 min. */
|
|
|| (INTEGRAL_TYPE_P (type)
|
|
&& ((tree_expr_nonzero_p (@0)
|
|
&& (plusminus == MINUS_EXPR
|
|
|| expr_not_equal_to (@0,
|
|
wi::minus_one (TYPE_PRECISION (type)))))
|
|
|| expr_not_equal_to (@2,
|
|
(plusminus == PLUS_EXPR
|
|
? wi::max_value (TYPE_PRECISION (type), SIGNED)
|
|
: wi::min_value (TYPE_PRECISION (type), SIGNED))))))
|
|
&& single_use (@3))
|
|
(mult (plusminus @2 { build_one_cst (type); }) @0))))))
|
|
|
|
#if GIMPLE
|
|
/* Canonicalize X + (X << C) into X * (1 + (1 << C)) and
|
|
(X << C1) + (X << C2) into X * ((1 << C1) + (1 << C2)). */
|
|
(simplify
|
|
(plus:c @0 (lshift:s @0 INTEGER_CST@1))
|
|
(if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& tree_fits_uhwi_p (@1)
|
|
&& tree_to_uhwi (@1) < element_precision (type)
|
|
&& (INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
|| optab_handler (smul_optab,
|
|
TYPE_MODE (type)) != CODE_FOR_nothing))
|
|
(with { tree t = type;
|
|
if (!TYPE_OVERFLOW_WRAPS (t)) t = unsigned_type_for (t);
|
|
wide_int w = wi::set_bit_in_zero (tree_to_uhwi (@1),
|
|
element_precision (type));
|
|
w += 1;
|
|
tree cst = wide_int_to_tree (VECTOR_TYPE_P (t) ? TREE_TYPE (t)
|
|
: t, w);
|
|
cst = build_uniform_cst (t, cst); }
|
|
(convert (mult (convert:t @0) { cst; })))))
|
|
(simplify
|
|
(plus (lshift:s @0 INTEGER_CST@1) (lshift:s @0 INTEGER_CST@2))
|
|
(if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& tree_fits_uhwi_p (@1)
|
|
&& tree_to_uhwi (@1) < element_precision (type)
|
|
&& tree_fits_uhwi_p (@2)
|
|
&& tree_to_uhwi (@2) < element_precision (type)
|
|
&& (INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
|| optab_handler (smul_optab,
|
|
TYPE_MODE (type)) != CODE_FOR_nothing))
|
|
(with { tree t = type;
|
|
if (!TYPE_OVERFLOW_WRAPS (t)) t = unsigned_type_for (t);
|
|
unsigned int prec = element_precision (type);
|
|
wide_int w = wi::set_bit_in_zero (tree_to_uhwi (@1), prec);
|
|
w += wi::set_bit_in_zero (tree_to_uhwi (@2), prec);
|
|
tree cst = wide_int_to_tree (VECTOR_TYPE_P (t) ? TREE_TYPE (t)
|
|
: t, w);
|
|
cst = build_uniform_cst (t, cst); }
|
|
(convert (mult (convert:t @0) { cst; })))))
|
|
#endif
|
|
|
|
/* Canonicalize (X*C1)|(X*C2) and (X*C1)^(X*C2) to (C1+C2)*X when
|
|
tree_nonzero_bits allows IOR and XOR to be treated like PLUS.
|
|
Likewise, handle (X<<C3) and X as legitimate variants of X*C. */
|
|
(for op (bit_ior bit_xor)
|
|
(simplify
|
|
(op (mult:s@0 @1 INTEGER_CST@2)
|
|
(mult:s@3 @1 INTEGER_CST@4))
|
|
(if (INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_WRAPS (type)
|
|
&& (tree_nonzero_bits (@0) & tree_nonzero_bits (@3)) == 0)
|
|
(mult @1
|
|
{ wide_int_to_tree (type, wi::to_wide (@2) + wi::to_wide (@4)); })))
|
|
(simplify
|
|
(op:c (mult:s@0 @1 INTEGER_CST@2)
|
|
(lshift:s@3 @1 INTEGER_CST@4))
|
|
(if (INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_WRAPS (type)
|
|
&& tree_int_cst_sgn (@4) > 0
|
|
&& (tree_nonzero_bits (@0) & tree_nonzero_bits (@3)) == 0)
|
|
(with { wide_int wone = wi::one (TYPE_PRECISION (type));
|
|
wide_int c = wi::add (wi::to_wide (@2),
|
|
wi::lshift (wone, wi::to_wide (@4))); }
|
|
(mult @1 { wide_int_to_tree (type, c); }))))
|
|
(simplify
|
|
(op:c (mult:s@0 @1 INTEGER_CST@2)
|
|
@1)
|
|
(if (INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_WRAPS (type)
|
|
&& (tree_nonzero_bits (@0) & tree_nonzero_bits (@1)) == 0)
|
|
(mult @1
|
|
{ wide_int_to_tree (type,
|
|
wi::add (wi::to_wide (@2), 1)); })))
|
|
(simplify
|
|
(op (lshift:s@0 @1 INTEGER_CST@2)
|
|
(lshift:s@3 @1 INTEGER_CST@4))
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& tree_int_cst_sgn (@2) > 0
|
|
&& tree_int_cst_sgn (@4) > 0
|
|
&& (tree_nonzero_bits (@0) & tree_nonzero_bits (@3)) == 0)
|
|
(with { tree t = type;
|
|
if (!TYPE_OVERFLOW_WRAPS (t))
|
|
t = unsigned_type_for (t);
|
|
wide_int wone = wi::one (TYPE_PRECISION (t));
|
|
wide_int c = wi::add (wi::lshift (wone, wi::to_wide (@2)),
|
|
wi::lshift (wone, wi::to_wide (@4))); }
|
|
(convert (mult:t (convert:t @1) { wide_int_to_tree (t,c); })))))
|
|
(simplify
|
|
(op:c (lshift:s@0 @1 INTEGER_CST@2)
|
|
@1)
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& tree_int_cst_sgn (@2) > 0
|
|
&& (tree_nonzero_bits (@0) & tree_nonzero_bits (@1)) == 0)
|
|
(with { tree t = type;
|
|
if (!TYPE_OVERFLOW_WRAPS (t))
|
|
t = unsigned_type_for (t);
|
|
wide_int wone = wi::one (TYPE_PRECISION (t));
|
|
wide_int c = wi::add (wi::lshift (wone, wi::to_wide (@2)), wone); }
|
|
(convert (mult:t (convert:t @1) { wide_int_to_tree (t, c); }))))))
|
|
|
|
/* Simplifications of MIN_EXPR, MAX_EXPR, fmin() and fmax(). */
|
|
|
|
(for minmax (min max FMIN_ALL FMAX_ALL)
|
|
(simplify
|
|
(minmax @0 @0)
|
|
@0))
|
|
/* min(max(x,y),y) -> y. */
|
|
(simplify
|
|
(min:c (max:c @0 @1) @1)
|
|
@1)
|
|
/* max(min(x,y),y) -> y. */
|
|
(simplify
|
|
(max:c (min:c @0 @1) @1)
|
|
@1)
|
|
/* max(a,-a) -> abs(a). */
|
|
(simplify
|
|
(max:c @0 (negate @0))
|
|
(if (TREE_CODE (type) != COMPLEX_TYPE
|
|
&& (! ANY_INTEGRAL_TYPE_P (type)
|
|
|| TYPE_OVERFLOW_UNDEFINED (type)))
|
|
(abs @0)))
|
|
/* min(a,-a) -> -abs(a). */
|
|
(simplify
|
|
(min:c @0 (negate @0))
|
|
(if (TREE_CODE (type) != COMPLEX_TYPE
|
|
&& (! ANY_INTEGRAL_TYPE_P (type)
|
|
|| TYPE_OVERFLOW_UNDEFINED (type)))
|
|
(negate (abs @0))))
|
|
(simplify
|
|
(min @0 @1)
|
|
(switch
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& TYPE_MIN_VALUE (type)
|
|
&& operand_equal_p (@1, TYPE_MIN_VALUE (type), OEP_ONLY_CONST))
|
|
@1)
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& TYPE_MAX_VALUE (type)
|
|
&& operand_equal_p (@1, TYPE_MAX_VALUE (type), OEP_ONLY_CONST))
|
|
@0)))
|
|
(simplify
|
|
(max @0 @1)
|
|
(switch
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& TYPE_MAX_VALUE (type)
|
|
&& operand_equal_p (@1, TYPE_MAX_VALUE (type), OEP_ONLY_CONST))
|
|
@1)
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& TYPE_MIN_VALUE (type)
|
|
&& operand_equal_p (@1, TYPE_MIN_VALUE (type), OEP_ONLY_CONST))
|
|
@0)))
|
|
|
|
/* max (a, a + CST) -> a + CST where CST is positive. */
|
|
/* max (a, a + CST) -> a where CST is negative. */
|
|
(simplify
|
|
(max:c @0 (plus@2 @0 INTEGER_CST@1))
|
|
(if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)))
|
|
(if (tree_int_cst_sgn (@1) > 0)
|
|
@2
|
|
@0)))
|
|
|
|
/* min (a, a + CST) -> a where CST is positive. */
|
|
/* min (a, a + CST) -> a + CST where CST is negative. */
|
|
(simplify
|
|
(min:c @0 (plus@2 @0 INTEGER_CST@1))
|
|
(if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)))
|
|
(if (tree_int_cst_sgn (@1) > 0)
|
|
@0
|
|
@2)))
|
|
|
|
/* Simplify min (&var[off0], &var[off1]) etc. depending on whether
|
|
the addresses are known to be less, equal or greater. */
|
|
(for minmax (min max)
|
|
cmp (lt gt)
|
|
(simplify
|
|
(minmax (convert1?@2 addr@0) (convert2?@3 addr@1))
|
|
(with
|
|
{
|
|
poly_int64 off0, off1;
|
|
tree base0, base1;
|
|
int equal = address_compare (cmp, TREE_TYPE (@2), @0, @1, base0, base1,
|
|
off0, off1, GENERIC);
|
|
}
|
|
(if (equal == 1)
|
|
(if (minmax == MIN_EXPR)
|
|
(if (known_le (off0, off1))
|
|
@2
|
|
(if (known_gt (off0, off1))
|
|
@3))
|
|
(if (known_ge (off0, off1))
|
|
@2
|
|
(if (known_lt (off0, off1))
|
|
@3)))))))
|
|
|
|
/* (convert (minmax ((convert (x) c)))) -> minmax (x c) if x is promoted
|
|
and the outer convert demotes the expression back to x's type. */
|
|
(for minmax (min max)
|
|
(simplify
|
|
(convert (minmax@0 (convert @1) INTEGER_CST@2))
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& types_match (@1, type) && int_fits_type_p (@2, type)
|
|
&& TYPE_SIGN (TREE_TYPE (@0)) == TYPE_SIGN (type)
|
|
&& TYPE_PRECISION (TREE_TYPE (@0)) > TYPE_PRECISION (type))
|
|
(minmax @1 (convert @2)))))
|
|
|
|
(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
|
|
(minmax:c @0 REAL_CST@1)
|
|
(if (real_isnan (TREE_REAL_CST_PTR (@1))
|
|
&& (!HONOR_SNANS (@1) || !TREE_REAL_CST (@1).signalling))
|
|
@0)))
|
|
/* Convert fmin/fmax to MIN_EXPR/MAX_EXPR. C99 requires these
|
|
functions to return the numeric arg if the other one is NaN.
|
|
MIN and MAX don't honor that, so only transform if -ffinite-math-only
|
|
is set. C99 doesn't require -0.0 to be handled, so we don't have to
|
|
worry about it either. */
|
|
(if (flag_finite_math_only)
|
|
(simplify
|
|
(FMIN_ALL @0 @1)
|
|
(min @0 @1))
|
|
(simplify
|
|
(FMAX_ALL @0 @1)
|
|
(max @0 @1)))
|
|
/* min (-A, -B) -> -max (A, B) */
|
|
(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))
|
|
|| (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))))
|
|
(negate (maxmin @0 @1)))))
|
|
/* MIN (~X, ~Y) -> ~MAX (X, Y)
|
|
MAX (~X, ~Y) -> ~MIN (X, Y) */
|
|
(for minmax (min max)
|
|
maxmin (max min)
|
|
(simplify
|
|
(minmax (bit_not:s@2 @0) (bit_not:s@3 @1))
|
|
(bit_not (maxmin @0 @1))))
|
|
|
|
/* MIN (X, Y) == X -> X <= Y */
|
|
(for minmax (min min max max)
|
|
cmp (eq ne eq ne )
|
|
out (le gt ge lt )
|
|
(simplify
|
|
(cmp:c (minmax:c @0 @1) @0)
|
|
(if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0)))
|
|
(out @0 @1))))
|
|
/* MIN (X, 5) == 0 -> X == 0
|
|
MIN (X, 5) == 7 -> false */
|
|
(for cmp (eq ne)
|
|
(simplify
|
|
(cmp (min @0 INTEGER_CST@1) INTEGER_CST@2)
|
|
(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 (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 (wi::to_wide (@1), wi::to_wide (@2),
|
|
TYPE_SIGN (TREE_TYPE (@0))))
|
|
{ constant_boolean_node (cmp == NE_EXPR, type); }
|
|
(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 )
|
|
cmp (lt le gt ge gt ge lt le )
|
|
comb (bit_ior bit_ior bit_ior bit_ior bit_and bit_and bit_and bit_and)
|
|
(simplify
|
|
(cmp (minmax @0 INTEGER_CST@1) INTEGER_CST@2)
|
|
(comb (cmp @0 @2) (cmp @1 @2))))
|
|
|
|
/* X <= MAX(X, Y) -> true
|
|
X > MAX(X, Y) -> false
|
|
X >= MIN(X, Y) -> true
|
|
X < MIN(X, Y) -> false */
|
|
(for minmax (min min max max )
|
|
cmp (ge lt le gt )
|
|
(simplify
|
|
(cmp @0 (minmax:c @0 @1))
|
|
{ constant_boolean_node (cmp == GE_EXPR || cmp == LE_EXPR, type); } ))
|
|
|
|
/* Undo fancy way of writing max/min or other ?: expressions,
|
|
like a - ((a - b) & -(a < b)), in this case into (a < b) ? b : a.
|
|
People normally use ?: and that is what we actually try to optimize. */
|
|
(for cmp (simple_comparison)
|
|
(simplify
|
|
(minus @0 (bit_and:c (minus @0 @1)
|
|
(convert? (negate@4 (convert? (cmp@5 @2 @3))))))
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@4))
|
|
&& TREE_CODE (TREE_TYPE (@4)) != BOOLEAN_TYPE
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@5))
|
|
&& (TYPE_PRECISION (TREE_TYPE (@4)) >= TYPE_PRECISION (type)
|
|
|| !TYPE_UNSIGNED (TREE_TYPE (@4)))
|
|
&& (GIMPLE || !TREE_SIDE_EFFECTS (@1)))
|
|
(cond (cmp @2 @3) @1 @0)))
|
|
(simplify
|
|
(plus:c @0 (bit_and:c (minus @1 @0)
|
|
(convert? (negate@4 (convert? (cmp@5 @2 @3))))))
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@4))
|
|
&& TREE_CODE (TREE_TYPE (@4)) != BOOLEAN_TYPE
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@5))
|
|
&& (TYPE_PRECISION (TREE_TYPE (@4)) >= TYPE_PRECISION (type)
|
|
|| !TYPE_UNSIGNED (TREE_TYPE (@4)))
|
|
&& (GIMPLE || !TREE_SIDE_EFFECTS (@1)))
|
|
(cond (cmp @2 @3) @1 @0)))
|
|
/* Similarly with ^ instead of - though in that case with :c. */
|
|
(simplify
|
|
(bit_xor:c @0 (bit_and:c (bit_xor:c @0 @1)
|
|
(convert? (negate@4 (convert? (cmp@5 @2 @3))))))
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@4))
|
|
&& TREE_CODE (TREE_TYPE (@4)) != BOOLEAN_TYPE
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@5))
|
|
&& (TYPE_PRECISION (TREE_TYPE (@4)) >= TYPE_PRECISION (type)
|
|
|| !TYPE_UNSIGNED (TREE_TYPE (@4)))
|
|
&& (GIMPLE || !TREE_SIDE_EFFECTS (@1)))
|
|
(cond (cmp @2 @3) @1 @0))))
|
|
|
|
/* Simplifications of shift and rotates. */
|
|
|
|
(for rotate (lrotate rrotate)
|
|
(simplify
|
|
(rotate integer_all_onesp@0 @1)
|
|
@0))
|
|
|
|
/* Optimize -1 >> x for arithmetic right shifts. */
|
|
(simplify
|
|
(rshift integer_all_onesp@0 @1)
|
|
(if (!TYPE_UNSIGNED (type))
|
|
@0))
|
|
|
|
/* Optimize (x >> c) << c into x & (-1<<c). */
|
|
(simplify
|
|
(lshift (nop_convert? (rshift @0 INTEGER_CST@1)) @1)
|
|
(if (wi::ltu_p (wi::to_wide (@1), element_precision (type)))
|
|
/* It doesn't matter if the right shift is arithmetic or logical. */
|
|
(bit_and (view_convert @0) (lshift { build_minus_one_cst (type); } @1))))
|
|
|
|
(simplify
|
|
(lshift (convert (convert@2 (rshift @0 INTEGER_CST@1))) @1)
|
|
(if (wi::ltu_p (wi::to_wide (@1), element_precision (type))
|
|
/* Allow intermediate conversion to integral type with whatever sign, as
|
|
long as the low TYPE_PRECISION (type)
|
|
- TYPE_PRECISION (TREE_TYPE (@2)) bits are preserved. */
|
|
&& INTEGRAL_TYPE_P (type)
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@2))
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (@0))
|
|
&& (TYPE_PRECISION (TREE_TYPE (@2)) >= TYPE_PRECISION (type)
|
|
|| wi::geu_p (wi::to_wide (@1),
|
|
TYPE_PRECISION (type)
|
|
- TYPE_PRECISION (TREE_TYPE (@2)))))
|
|
(bit_and (convert @0) (lshift { build_minus_one_cst (type); } @1))))
|
|
|
|
/* Optimize (x << c) >> c into x & ((unsigned)-1 >> c) for unsigned
|
|
types. */
|
|
(simplify
|
|
(rshift (lshift @0 INTEGER_CST@1) @1)
|
|
(if (TYPE_UNSIGNED (type)
|
|
&& (wi::ltu_p (wi::to_wide (@1), element_precision (type))))
|
|
(bit_and @0 (rshift { build_minus_one_cst (type); } @1))))
|
|
|
|
/* Optimize x >> x into 0 */
|
|
(simplify
|
|
(rshift @0 @0)
|
|
{ build_zero_cst (type); })
|
|
|
|
(for shiftrotate (lrotate rrotate lshift rshift)
|
|
(simplify
|
|
(shiftrotate @0 integer_zerop)
|
|
(non_lvalue @0))
|
|
(simplify
|
|
(shiftrotate integer_zerop@0 @1)
|
|
@0)
|
|
/* Prefer vector1 << scalar to vector1 << vector2
|
|
if vector2 is uniform. */
|
|
(for vec (VECTOR_CST CONSTRUCTOR)
|
|
(simplify
|
|
(shiftrotate @0 vec@1)
|
|
(with { tree tem = uniform_vector_p (@1); }
|
|
(if (tem)
|
|
(shiftrotate @0 { tem; }))))))
|
|
|
|
/* Simplify X << Y where Y's low width bits are 0 to X, as only valid
|
|
Y is 0. Similarly for X >> Y. */
|
|
#if GIMPLE
|
|
(for shift (lshift rshift)
|
|
(simplify
|
|
(shift @0 SSA_NAME@1)
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@1)))
|
|
(with {
|
|
int width = ceil_log2 (element_precision (TREE_TYPE (@0)));
|
|
int prec = TYPE_PRECISION (TREE_TYPE (@1));
|
|
}
|
|
(if ((get_nonzero_bits (@1) & wi::mask (width, false, prec)) == 0)
|
|
@0)))))
|
|
#endif
|
|
|
|
/* Rewrite an LROTATE_EXPR by a constant into an
|
|
RROTATE_EXPR by a new constant. */
|
|
(simplify
|
|
(lrotate @0 INTEGER_CST@1)
|
|
(rrotate @0 { const_binop (MINUS_EXPR, TREE_TYPE (@1),
|
|
build_int_cst (TREE_TYPE (@1),
|
|
element_precision (type)), @1); }))
|
|
|
|
/* Turn (a OP c1) OP c2 into a OP (c1+c2). */
|
|
(for op (lrotate rrotate rshift lshift)
|
|
(simplify
|
|
(op (op @0 INTEGER_CST@1) INTEGER_CST@2)
|
|
(with { unsigned int prec = element_precision (type); }
|
|
(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)
|
|
(if (op == LROTATE_EXPR || op == RROTATE_EXPR)
|
|
(op @0 { build_int_cst (TREE_TYPE (@1), low % prec); })
|
|
(if (TYPE_UNSIGNED (type) || op == LSHIFT_EXPR)
|
|
{ build_zero_cst (type); }
|
|
(op @0 { build_int_cst (TREE_TYPE (@1), prec - 1); })))
|
|
(op @0 { build_int_cst (TREE_TYPE (@1), low); })))))))
|
|
|
|
|
|
/* Simplify (CST << x) & 1 to 0 if CST is even or to x == 0 if it is odd. */
|
|
(simplify
|
|
(bit_and (lshift INTEGER_CST@1 @0) integer_onep)
|
|
(if ((wi::to_wide (@1) & 1) != 0)
|
|
(convert (eq:boolean_type_node @0 { build_zero_cst (TREE_TYPE (@0)); }))
|
|
{ build_zero_cst (type); }))
|
|
|
|
/* Simplify ((C << x) & D) != 0 where C and D are power of two constants,
|
|
either to false if D is smaller (unsigned comparison) than C, or to
|
|
x == log2 (D) - log2 (C). Similarly for right shifts. */
|
|
(for cmp (ne eq)
|
|
icmp (eq ne)
|
|
(simplify
|
|
(cmp (bit_and (lshift integer_pow2p@1 @0) integer_pow2p@2) integer_zerop)
|
|
(with { int c1 = wi::clz (wi::to_wide (@1));
|
|
int c2 = wi::clz (wi::to_wide (@2)); }
|
|
(if (c1 < c2)
|
|
{ constant_boolean_node (cmp == NE_EXPR ? false : true, type); }
|
|
(icmp @0 { build_int_cst (TREE_TYPE (@0), c1 - c2); }))))
|
|
(simplify
|
|
(cmp (bit_and (rshift integer_pow2p@1 @0) integer_pow2p@2) integer_zerop)
|
|
(if (tree_int_cst_sgn (@1) > 0)
|
|
(with { int c1 = wi::clz (wi::to_wide (@1));
|
|
int c2 = wi::clz (wi::to_wide (@2)); }
|
|
(if (c1 > c2)
|
|
{ constant_boolean_node (cmp == NE_EXPR ? false : true, type); }
|
|
(icmp @0 { build_int_cst (TREE_TYPE (@0), c2 - c1); }))))))
|
|
|
|
/* (CST1 << A) == CST2 -> A == ctz (CST2) - ctz (CST1)
|
|
(CST1 << A) != CST2 -> A != ctz (CST2) - ctz (CST1)
|
|
if CST2 != 0. */
|
|
(for cmp (ne eq)
|
|
(simplify
|
|
(cmp (lshift INTEGER_CST@0 @1) INTEGER_CST@2)
|
|
(with { int cand = wi::ctz (wi::to_wide (@2)) - wi::ctz (wi::to_wide (@0)); }
|
|
(if (cand < 0
|
|
|| (!integer_zerop (@2)
|
|
&& wi::lshift (wi::to_wide (@0), cand) != wi::to_wide (@2)))
|
|
{ constant_boolean_node (cmp == NE_EXPR, type); }
|
|
(if (!integer_zerop (@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))
|
|
(X >> C1) & C2 into (X >> C1) & (C2 | ~((type) -1 >> C1))
|
|
if the new mask might be further optimized. */
|
|
(for shift (lshift rshift)
|
|
(simplify
|
|
(bit_and (convert?:s@4 (shift:s@5 (convert1?@3 @0) INTEGER_CST@1))
|
|
INTEGER_CST@2)
|
|
(if (tree_nop_conversion_p (TREE_TYPE (@4), TREE_TYPE (@5))
|
|
&& TYPE_PRECISION (type) <= HOST_BITS_PER_WIDE_INT
|
|
&& tree_fits_uhwi_p (@1)
|
|
&& tree_to_uhwi (@1) > 0
|
|
&& tree_to_uhwi (@1) < TYPE_PRECISION (type))
|
|
(with
|
|
{
|
|
unsigned int shiftc = tree_to_uhwi (@1);
|
|
unsigned HOST_WIDE_INT mask = TREE_INT_CST_LOW (@2);
|
|
unsigned HOST_WIDE_INT newmask, zerobits = 0;
|
|
tree shift_type = TREE_TYPE (@3);
|
|
unsigned int prec;
|
|
|
|
if (shift == LSHIFT_EXPR)
|
|
zerobits = ((HOST_WIDE_INT_1U << shiftc) - 1);
|
|
else if (shift == RSHIFT_EXPR
|
|
&& type_has_mode_precision_p (shift_type))
|
|
{
|
|
prec = TYPE_PRECISION (TREE_TYPE (@3));
|
|
tree arg00 = @0;
|
|
/* See if more bits can be proven as zero because of
|
|
zero extension. */
|
|
if (@3 != @0
|
|
&& TYPE_UNSIGNED (TREE_TYPE (@0)))
|
|
{
|
|
tree inner_type = TREE_TYPE (@0);
|
|
if (type_has_mode_precision_p (inner_type)
|
|
&& TYPE_PRECISION (inner_type) < prec)
|
|
{
|
|
prec = TYPE_PRECISION (inner_type);
|
|
/* See if we can shorten the right shift. */
|
|
if (shiftc < prec)
|
|
shift_type = inner_type;
|
|
/* Otherwise X >> C1 is all zeros, so we'll optimize
|
|
it into (X, 0) later on by making sure zerobits
|
|
is all ones. */
|
|
}
|
|
}
|
|
zerobits = HOST_WIDE_INT_M1U;
|
|
if (shiftc < prec)
|
|
{
|
|
zerobits >>= HOST_BITS_PER_WIDE_INT - shiftc;
|
|
zerobits <<= prec - shiftc;
|
|
}
|
|
/* For arithmetic shift if sign bit could be set, zerobits
|
|
can contain actually sign bits, so no transformation is
|
|
possible, unless MASK masks them all away. In that
|
|
case the shift needs to be converted into logical shift. */
|
|
if (!TYPE_UNSIGNED (TREE_TYPE (@3))
|
|
&& prec == TYPE_PRECISION (TREE_TYPE (@3)))
|
|
{
|
|
if ((mask & zerobits) == 0)
|
|
shift_type = unsigned_type_for (TREE_TYPE (@3));
|
|
else
|
|
zerobits = 0;
|
|
}
|
|
}
|
|
}
|
|
/* ((X << 16) & 0xff00) is (X, 0). */
|
|
(if ((mask & zerobits) == mask)
|
|
{ build_int_cst (type, 0); }
|
|
(with { newmask = mask | zerobits; }
|
|
(if (newmask != mask && (newmask & (newmask + 1)) == 0)
|
|
(with
|
|
{
|
|
/* Only do the transformation if NEWMASK is some integer
|
|
mode's mask. */
|
|
for (prec = BITS_PER_UNIT;
|
|
prec < HOST_BITS_PER_WIDE_INT; prec <<= 1)
|
|
if (newmask == (HOST_WIDE_INT_1U << prec) - 1)
|
|
break;
|
|
}
|
|
(if (prec < HOST_BITS_PER_WIDE_INT
|
|
|| newmask == HOST_WIDE_INT_M1U)
|
|
(with
|
|
{ tree newmaskt = build_int_cst_type (TREE_TYPE (@2), newmask); }
|
|
(if (!tree_int_cst_equal (newmaskt, @2))
|
|
(if (shift_type != TREE_TYPE (@3))
|
|
(bit_and (convert (shift:shift_type (convert @3) @1)) { newmaskt; })
|
|
(bit_and @4 { newmaskt; })))))))))))))
|
|
|
|
/* ((1 << n) & M) != 0 -> n == log2 (M) */
|
|
(for cmp (ne eq)
|
|
icmp (eq ne)
|
|
(simplify
|
|
(cmp
|
|
(bit_and
|
|
(nop_convert? (lshift integer_onep @0)) integer_pow2p@1) integer_zerop)
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0)))
|
|
(icmp @0 { wide_int_to_tree (TREE_TYPE (@0),
|
|
wi::exact_log2 (wi::to_wide (@1))); }))))
|
|
|
|
/* Fold (X {&,^,|} C2) << C1 into (X << C1) {&,^,|} (C2 << C1)
|
|
(X {&,^,|} C2) >> C1 into (X >> C1) & (C2 >> C1). */
|
|
(for shift (lshift rshift)
|
|
(for bit_op (bit_and bit_xor bit_ior)
|
|
(simplify
|
|
(shift (convert?:s (bit_op:s @0 INTEGER_CST@2)) INTEGER_CST@1)
|
|
(if (tree_nop_conversion_p (type, TREE_TYPE (@0)))
|
|
(with { tree mask = int_const_binop (shift, fold_convert (type, @2), @1); }
|
|
(if (mask)
|
|
(bit_op (shift (convert @0) @1) { mask; })))))))
|
|
|
|
/* ~(~X >> Y) -> X >> Y (for arithmetic shift). */
|
|
(simplify
|
|
(bit_not (convert1?:s (rshift:s (convert2?@0 (bit_not @1)) @2)))
|
|
(if (!TYPE_UNSIGNED (TREE_TYPE (@0))
|
|
&& (element_precision (TREE_TYPE (@0))
|
|
<= element_precision (TREE_TYPE (@1))
|
|
|| !TYPE_UNSIGNED (TREE_TYPE (@1))))
|
|
(with
|
|
{ tree shift_type = TREE_TYPE (@0); }
|
|
(convert (rshift (convert:shift_type @1) @2)))))
|
|
|
|
/* ~(~X >>r Y) -> X >>r Y
|
|
~(~X <<r Y) -> X <<r Y */
|
|
(for rotate (lrotate rrotate)
|
|
(simplify
|
|
(bit_not (convert1?:s (rotate:s (convert2?@0 (bit_not @1)) @2)))
|
|
(if ((element_precision (TREE_TYPE (@0))
|
|
<= element_precision (TREE_TYPE (@1))
|
|
|| !TYPE_UNSIGNED (TREE_TYPE (@1)))
|
|
&& (element_precision (type) <= element_precision (TREE_TYPE (@0))
|
|
|| !TYPE_UNSIGNED (TREE_TYPE (@0))))
|
|
(with
|
|
{ tree rotate_type = TREE_TYPE (@0); }
|
|
(convert (rotate (convert:rotate_type @1) @2))))))
|
|
|
|
(for cmp (eq ne)
|
|
(for rotate (lrotate rrotate)
|
|
invrot (rrotate lrotate)
|
|
/* (X >>r Y) cmp (Z >>r Y) may simplify to X cmp Y. */
|
|
(simplify
|
|
(cmp (rotate @1 @0) (rotate @2 @0))
|
|
(cmp @1 @2))
|
|
/* (X >>r C1) cmp C2 may simplify to X cmp C3. */
|
|
(simplify
|
|
(cmp (rotate @0 INTEGER_CST@1) INTEGER_CST@2)
|
|
(cmp @0 { const_binop (invrot, TREE_TYPE (@0), @2, @1); }))
|
|
/* (X >>r Y) cmp C where C is 0 or ~0, may simplify to X cmp C. */
|
|
(simplify
|
|
(cmp (rotate @0 @1) INTEGER_CST@2)
|
|
(if (integer_zerop (@2) || integer_all_onesp (@2))
|
|
(cmp @0 @2)))))
|
|
|
|
/* Both signed and unsigned lshift produce the same result, so use
|
|
the form that minimizes the number of conversions. Postpone this
|
|
transformation until after shifts by zero have been folded. */
|
|
(simplify
|
|
(convert (lshift:s@0 (convert:s@1 @2) INTEGER_CST@3))
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& tree_nop_conversion_p (type, TREE_TYPE (@0))
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@2))
|
|
&& TYPE_PRECISION (TREE_TYPE (@2)) <= TYPE_PRECISION (type)
|
|
&& !integer_zerop (@3))
|
|
(lshift (convert @2) @3)))
|
|
|
|
/* Simplifications of conversions. */
|
|
|
|
/* Basic strip-useless-type-conversions / strip_nops. */
|
|
(for cvt (convert view_convert float fix_trunc)
|
|
(simplify
|
|
(cvt @0)
|
|
(if ((GIMPLE && useless_type_conversion_p (type, TREE_TYPE (@0)))
|
|
|| (GENERIC && type == TREE_TYPE (@0)))
|
|
@0)))
|
|
|
|
/* Contract view-conversions. */
|
|
(simplify
|
|
(view_convert (view_convert @0))
|
|
(view_convert @0))
|
|
|
|
/* For integral conversions with the same precision or pointer
|
|
conversions use a NOP_EXPR instead. */
|
|
(simplify
|
|
(view_convert @0)
|
|
(if ((INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
|
|
&& (INTEGRAL_TYPE_P (TREE_TYPE (@0)) || POINTER_TYPE_P (TREE_TYPE (@0)))
|
|
&& TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (@0)))
|
|
(convert @0)))
|
|
|
|
/* Strip inner integral conversions that do not change precision or size, or
|
|
zero-extend while keeping the same size (for bool-to-char). */
|
|
(simplify
|
|
(view_convert (convert@0 @1))
|
|
(if ((INTEGRAL_TYPE_P (TREE_TYPE (@0)) || POINTER_TYPE_P (TREE_TYPE (@0)))
|
|
&& (INTEGRAL_TYPE_P (TREE_TYPE (@1)) || POINTER_TYPE_P (TREE_TYPE (@1)))
|
|
&& TYPE_SIZE (TREE_TYPE (@0)) == TYPE_SIZE (TREE_TYPE (@1))
|
|
&& (TYPE_PRECISION (TREE_TYPE (@0)) == TYPE_PRECISION (TREE_TYPE (@1))
|
|
|| (TYPE_PRECISION (TREE_TYPE (@0)) > TYPE_PRECISION (TREE_TYPE (@1))
|
|
&& TYPE_UNSIGNED (TREE_TYPE (@1)))))
|
|
(view_convert @1)))
|
|
|
|
/* Simplify a view-converted empty or single-element constructor. */
|
|
(simplify
|
|
(view_convert CONSTRUCTOR@0)
|
|
(with
|
|
{ tree ctor = (TREE_CODE (@0) == SSA_NAME
|
|
? gimple_assign_rhs1 (SSA_NAME_DEF_STMT (@0)) : @0); }
|
|
(switch
|
|
(if (CONSTRUCTOR_NELTS (ctor) == 0)
|
|
{ build_zero_cst (type); })
|
|
(if (CONSTRUCTOR_NELTS (ctor) == 1
|
|
&& VECTOR_TYPE_P (TREE_TYPE (ctor))
|
|
&& operand_equal_p (TYPE_SIZE (type),
|
|
TYPE_SIZE (TREE_TYPE
|
|
(CONSTRUCTOR_ELT (ctor, 0)->value))))
|
|
(view_convert { CONSTRUCTOR_ELT (ctor, 0)->value; })))))
|
|
|
|
/* Re-association barriers around constants and other re-association
|
|
barriers can be removed. */
|
|
(simplify
|
|
(paren CONSTANT_CLASS_P@0)
|
|
@0)
|
|
(simplify
|
|
(paren (paren@1 @0))
|
|
@1)
|
|
|
|
/* Handle cases of two conversions in a row. */
|
|
(for ocvt (convert float fix_trunc)
|
|
(for icvt (convert float)
|
|
(simplify
|
|
(ocvt (icvt@1 @0))
|
|
(with
|
|
{
|
|
tree inside_type = TREE_TYPE (@0);
|
|
tree inter_type = TREE_TYPE (@1);
|
|
int inside_int = INTEGRAL_TYPE_P (inside_type);
|
|
int inside_ptr = POINTER_TYPE_P (inside_type);
|
|
int inside_float = FLOAT_TYPE_P (inside_type);
|
|
int inside_vec = VECTOR_TYPE_P (inside_type);
|
|
unsigned int inside_prec = TYPE_PRECISION (inside_type);
|
|
int inside_unsignedp = TYPE_UNSIGNED (inside_type);
|
|
int inter_int = INTEGRAL_TYPE_P (inter_type);
|
|
int inter_ptr = POINTER_TYPE_P (inter_type);
|
|
int inter_float = FLOAT_TYPE_P (inter_type);
|
|
int inter_vec = VECTOR_TYPE_P (inter_type);
|
|
unsigned int inter_prec = TYPE_PRECISION (inter_type);
|
|
int inter_unsignedp = TYPE_UNSIGNED (inter_type);
|
|
int final_int = INTEGRAL_TYPE_P (type);
|
|
int final_ptr = POINTER_TYPE_P (type);
|
|
int final_float = FLOAT_TYPE_P (type);
|
|
int final_vec = VECTOR_TYPE_P (type);
|
|
unsigned int final_prec = TYPE_PRECISION (type);
|
|
int final_unsignedp = TYPE_UNSIGNED (type);
|
|
}
|
|
(switch
|
|
/* In addition to the cases of two conversions in a row
|
|
handled below, if we are converting something to its own
|
|
type via an object of identical or wider precision, neither
|
|
conversion is needed. */
|
|
(if (((GIMPLE && useless_type_conversion_p (type, inside_type))
|
|
|| (GENERIC
|
|
&& TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (inside_type)))
|
|
&& (((inter_int || inter_ptr) && final_int)
|
|
|| (inter_float && final_float))
|
|
&& inter_prec >= final_prec)
|
|
(ocvt @0))
|
|
|
|
/* Likewise, if the intermediate and initial types are either both
|
|
float or both integer, we don't need the middle conversion if the
|
|
former is wider than the latter and doesn't change the signedness
|
|
(for integers). Avoid this if the final type is a pointer since
|
|
then we sometimes need the middle conversion. */
|
|
(if (((inter_int && inside_int) || (inter_float && inside_float))
|
|
&& (final_int || final_float)
|
|
&& inter_prec >= inside_prec
|
|
&& (inter_float || inter_unsignedp == inside_unsignedp))
|
|
(ocvt @0))
|
|
|
|
/* 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. */
|
|
(if (inside_int && inter_int && final_int
|
|
&& ((inside_prec < inter_prec && inter_prec < final_prec
|
|
&& inside_unsignedp && !inter_unsignedp)
|
|
|| final_prec == inter_prec))
|
|
(ocvt @0))
|
|
|
|
/* Two conversions in a row are not needed unless:
|
|
- some conversion is floating-point (overstrict for now), or
|
|
- some conversion is a vector (overstrict for now), or
|
|
- the intermediate type is narrower than both initial and
|
|
final, or
|
|
- the intermediate type and innermost type differ in signedness,
|
|
and the outermost type is wider than the intermediate, or
|
|
- the initial type is a pointer type and the precisions of the
|
|
intermediate and final types differ, or
|
|
- the final type is a pointer type and the precisions of the
|
|
initial and intermediate types differ. */
|
|
(if (! inside_float && ! inter_float && ! final_float
|
|
&& ! inside_vec && ! inter_vec && ! final_vec
|
|
&& (inter_prec >= inside_prec || inter_prec >= final_prec)
|
|
&& ! (inside_int && inter_int
|
|
&& inter_unsignedp != inside_unsignedp
|
|
&& inter_prec < final_prec)
|
|
&& ((inter_unsignedp && inter_prec > inside_prec)
|
|
== (final_unsignedp && final_prec > inter_prec))
|
|
&& ! (inside_ptr && inter_prec != final_prec)
|
|
&& ! (final_ptr && inside_prec != inter_prec))
|
|
(ocvt @0))
|
|
|
|
/* A truncation to an unsigned type (a zero-extension) should be
|
|
canonicalized as bitwise and of a mask. */
|
|
(if (GIMPLE /* PR70366: doing this in GENERIC breaks -Wconversion. */
|
|
&& final_int && inter_int && inside_int
|
|
&& final_prec == inside_prec
|
|
&& final_prec > inter_prec
|
|
&& inter_unsignedp)
|
|
(convert (bit_and @0 { wide_int_to_tree
|
|
(inside_type,
|
|
wi::mask (inter_prec, false,
|
|
TYPE_PRECISION (inside_type))); })))
|
|
|
|
/* If we are converting an integer to a floating-point that can
|
|
represent it exactly and back to an integer, we can skip the
|
|
floating-point conversion. */
|
|
(if (GIMPLE /* PR66211 */
|
|
&& inside_int && inter_float && final_int &&
|
|
(unsigned) significand_size (TYPE_MODE (inter_type))
|
|
>= inside_prec - !inside_unsignedp)
|
|
(convert @0)))))))
|
|
|
|
/* (float_type)(integer_type) x -> trunc (x) if the type of x matches
|
|
float_type. Only do the transformation if we do not need to preserve
|
|
trapping behaviour, so require !flag_trapping_math. */
|
|
#if GIMPLE
|
|
(simplify
|
|
(float (fix_trunc @0))
|
|
(if (!flag_trapping_math
|
|
&& types_match (type, TREE_TYPE (@0))
|
|
&& direct_internal_fn_supported_p (IFN_TRUNC, type,
|
|
OPTIMIZE_FOR_BOTH))
|
|
(IFN_TRUNC @0)))
|
|
#endif
|
|
|
|
/* If we have a narrowing conversion to an integral type that is fed by a
|
|
BIT_AND_EXPR, we might be able to remove the BIT_AND_EXPR if it merely
|
|
masks off bits outside the final type (and nothing else). */
|
|
(simplify
|
|
(convert (bit_and @0 INTEGER_CST@1))
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@0))
|
|
&& operand_equal_p (@1, build_low_bits_mask (TREE_TYPE (@1),
|
|
TYPE_PRECISION (type)), 0))
|
|
(convert @0)))
|
|
|
|
|
|
/* (X /[ex] A) * A -> X. */
|
|
(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. */
|
|
(simplify
|
|
(plus @0 REAL_CST@1)
|
|
(if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (@1)))
|
|
(with { tree tem = const_unop (NEGATE_EXPR, type, @1); }
|
|
(if (!TREE_OVERFLOW (tem) || !flag_trapping_math)
|
|
(minus @0 { tem; })))))
|
|
|
|
/* Convert x+x into x*2. */
|
|
(simplify
|
|
(plus @0 @0)
|
|
(if (SCALAR_FLOAT_TYPE_P (type))
|
|
(mult @0 { build_real (type, dconst2); })
|
|
(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
|
|
(-ARG1 + ARG0) reduces to -ARG1. */
|
|
(simplify
|
|
(minus real_zerop@0 @1)
|
|
(if (fold_real_zero_addition_p (type, @1, @0, 0))
|
|
(negate @1)))
|
|
|
|
/* Transform x * -1 into -x. */
|
|
(simplify
|
|
(mult @0 integer_minus_onep)
|
|
(negate @0))
|
|
|
|
/* Reassociate (X * CST) * Y to (X * Y) * CST. This does not introduce
|
|
signed overflow for CST != 0 && CST != -1. */
|
|
(simplify
|
|
(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)))
|
|
|
|
/* True if we can easily extract the real and imaginary parts of a complex
|
|
number. */
|
|
(match compositional_complex
|
|
(convert? (complex @0 @1)))
|
|
|
|
/* COMPLEX_EXPR and REALPART/IMAGPART_EXPR cancellations. */
|
|
(simplify
|
|
(complex (realpart @0) (imagpart @0))
|
|
@0)
|
|
(simplify
|
|
(realpart (complex @0 @1))
|
|
@0)
|
|
(simplify
|
|
(imagpart (complex @0 @1))
|
|
@1)
|
|
|
|
/* Sometimes we only care about half of a complex expression. */
|
|
(simplify
|
|
(realpart (convert?:s (conj:s @0)))
|
|
(convert (realpart @0)))
|
|
(simplify
|
|
(imagpart (convert?:s (conj:s @0)))
|
|
(convert (negate (imagpart @0))))
|
|
(for part (realpart imagpart)
|
|
(for op (plus minus)
|
|
(simplify
|
|
(part (convert?:s@2 (op:s @0 @1)))
|
|
(convert (op (part @0) (part @1))))))
|
|
(simplify
|
|
(realpart (convert?:s (CEXPI:s @0)))
|
|
(convert (COS @0)))
|
|
(simplify
|
|
(imagpart (convert?:s (CEXPI:s @0)))
|
|
(convert (SIN @0)))
|
|
|
|
/* conj(conj(x)) -> x */
|
|
(simplify
|
|
(conj (convert? (conj @0)))
|
|
(if (tree_nop_conversion_p (TREE_TYPE (@0), type))
|
|
(convert @0)))
|
|
|
|
/* conj({x,y}) -> {x,-y} */
|
|
(simplify
|
|
(conj (convert?:s (complex:s @0 @1)))
|
|
(with { tree itype = TREE_TYPE (type); }
|
|
(complex (convert:itype @0) (negate (convert:itype @1)))))
|
|
|
|
/* BSWAP simplifications, transforms checked by gcc.dg/builtin-bswap-8.c. */
|
|
(for bswap (BUILT_IN_BSWAP16 BUILT_IN_BSWAP32
|
|
BUILT_IN_BSWAP64 BUILT_IN_BSWAP128)
|
|
(simplify
|
|
(bswap (bswap @0))
|
|
@0)
|
|
(simplify
|
|
(bswap (bit_not (bswap @0)))
|
|
(bit_not @0))
|
|
(for bitop (bit_xor bit_ior bit_and)
|
|
(simplify
|
|
(bswap (bitop:c (bswap @0) @1))
|
|
(bitop @0 (bswap @1))))
|
|
(for cmp (eq ne)
|
|
(simplify
|
|
(cmp (bswap@2 @0) (bswap @1))
|
|
(with { tree ctype = TREE_TYPE (@2); }
|
|
(cmp (convert:ctype @0) (convert:ctype @1))))
|
|
(simplify
|
|
(cmp (bswap @0) INTEGER_CST@1)
|
|
(with { tree ctype = TREE_TYPE (@1); }
|
|
(cmp (convert:ctype @0) (bswap! @1)))))
|
|
/* (bswap(x) >> C1) & C2 can sometimes be simplified to (x >> C3) & C2. */
|
|
(simplify
|
|
(bit_and (convert1? (rshift@0 (convert2? (bswap@4 @1)) INTEGER_CST@2))
|
|
INTEGER_CST@3)
|
|
(if (BITS_PER_UNIT == 8
|
|
&& tree_fits_uhwi_p (@2)
|
|
&& tree_fits_uhwi_p (@3))
|
|
(with
|
|
{
|
|
unsigned HOST_WIDE_INT prec = TYPE_PRECISION (TREE_TYPE (@4));
|
|
unsigned HOST_WIDE_INT bits = tree_to_uhwi (@2);
|
|
unsigned HOST_WIDE_INT mask = tree_to_uhwi (@3);
|
|
unsigned HOST_WIDE_INT lo = bits & 7;
|
|
unsigned HOST_WIDE_INT hi = bits - lo;
|
|
}
|
|
(if (bits < prec
|
|
&& mask < (256u>>lo)
|
|
&& bits < TYPE_PRECISION (TREE_TYPE(@0)))
|
|
(with { unsigned HOST_WIDE_INT ns = (prec - (hi + 8)) + lo; }
|
|
(if (ns == 0)
|
|
(bit_and (convert @1) @3)
|
|
(with
|
|
{
|
|
tree utype = unsigned_type_for (TREE_TYPE (@1));
|
|
tree nst = build_int_cst (integer_type_node, ns);
|
|
}
|
|
(bit_and (convert (rshift:utype (convert:utype @1) {nst;})) @3))))))))
|
|
/* bswap(x) >> C1 can sometimes be simplified to (T)x >> C2. */
|
|
(simplify
|
|
(rshift (convert? (bswap@2 @0)) INTEGER_CST@1)
|
|
(if (BITS_PER_UNIT == 8
|
|
&& CHAR_TYPE_SIZE == 8
|
|
&& tree_fits_uhwi_p (@1))
|
|
(with
|
|
{
|
|
unsigned HOST_WIDE_INT prec = TYPE_PRECISION (TREE_TYPE (@2));
|
|
unsigned HOST_WIDE_INT bits = tree_to_uhwi (@1);
|
|
/* If the bswap was extended before the original shift, this
|
|
byte (shift) has the sign of the extension, not the sign of
|
|
the original shift. */
|
|
tree st = TYPE_PRECISION (type) > prec ? TREE_TYPE (@2) : type;
|
|
}
|
|
/* Special case: logical right shift of sign-extended bswap.
|
|
(unsigned)(short)bswap16(x)>>12 is (unsigned)((short)x<<8)>>12. */
|
|
(if (TYPE_PRECISION (type) > prec
|
|
&& !TYPE_UNSIGNED (TREE_TYPE (@2))
|
|
&& TYPE_UNSIGNED (type)
|
|
&& bits < prec && bits + 8 >= prec)
|
|
(with { tree nst = build_int_cst (integer_type_node, prec - 8); }
|
|
(rshift (convert (lshift:st (convert:st @0) {nst;})) @1))
|
|
(if (bits + 8 == prec)
|
|
(if (TYPE_UNSIGNED (st))
|
|
(convert (convert:unsigned_char_type_node @0))
|
|
(convert (convert:signed_char_type_node @0)))
|
|
(if (bits < prec && bits + 8 > prec)
|
|
(with
|
|
{
|
|
tree nst = build_int_cst (integer_type_node, bits & 7);
|
|
tree bt = TYPE_UNSIGNED (st) ? unsigned_char_type_node
|
|
: signed_char_type_node;
|
|
}
|
|
(convert (rshift:bt (convert:bt @0) {nst;})))))))))
|
|
/* bswap(x) & C1 can sometimes be simplified to (x >> C2) & C1. */
|
|
(simplify
|
|
(bit_and (convert? (bswap@2 @0)) INTEGER_CST@1)
|
|
(if (BITS_PER_UNIT == 8
|
|
&& tree_fits_uhwi_p (@1)
|
|
&& tree_to_uhwi (@1) < 256)
|
|
(with
|
|
{
|
|
unsigned HOST_WIDE_INT prec = TYPE_PRECISION (TREE_TYPE (@2));
|
|
tree utype = unsigned_type_for (TREE_TYPE (@0));
|
|
tree nst = build_int_cst (integer_type_node, prec - 8);
|
|
}
|
|
(bit_and (convert (rshift:utype (convert:utype @0) {nst;})) @1)))))
|
|
|
|
|
|
/* Combine COND_EXPRs and VEC_COND_EXPRs. */
|
|
|
|
/* Simplify constant conditions.
|
|
Only optimize constant conditions when the selected branch
|
|
has the same type as the COND_EXPR. This avoids optimizing
|
|
away "c ? x : throw", where the throw has a void type.
|
|
Note that we cannot throw away the fold-const.cc variant nor
|
|
this one as we depend on doing this transform before possibly
|
|
A ? B : B -> B triggers and the fold-const.cc one can optimize
|
|
0 ? A : B to B even if A has side-effects. Something
|
|
genmatch cannot handle. */
|
|
(simplify
|
|
(cond INTEGER_CST@0 @1 @2)
|
|
(if (integer_zerop (@0))
|
|
(if (!VOID_TYPE_P (TREE_TYPE (@2)) || VOID_TYPE_P (type))
|
|
@2)
|
|
(if (!VOID_TYPE_P (TREE_TYPE (@1)) || VOID_TYPE_P (type))
|
|
@1)))
|
|
(simplify
|
|
(vec_cond VECTOR_CST@0 @1 @2)
|
|
(if (integer_all_onesp (@0))
|
|
@1
|
|
(if (integer_zerop (@0))
|
|
@2)))
|
|
|
|
#if GIMPLE
|
|
/* Sink unary operations to branches, but only if we do fold both. */
|
|
(for op (negate bit_not abs absu)
|
|
(simplify
|
|
(op (vec_cond:s @0 @1 @2))
|
|
(vec_cond @0 (op! @1) (op! @2))))
|
|
|
|
/* Sink binary operation to branches, but only if we can fold it. */
|
|
(for op (tcc_comparison plus minus mult bit_and bit_ior bit_xor
|
|
lshift rshift rdiv trunc_div ceil_div floor_div round_div
|
|
trunc_mod ceil_mod floor_mod round_mod min max)
|
|
/* (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)))
|
|
|
|
/* (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)))
|
|
(simplify
|
|
(op @3 (vec_cond:s @0 @1 @2))
|
|
(vec_cond @0 (op! @3 @1) (op! @3 @2))))
|
|
#endif
|
|
|
|
#if GIMPLE
|
|
(match (nop_atomic_bit_test_and_p @0 @1 @4)
|
|
(bit_and (convert?@4 (ATOMIC_FETCH_OR_XOR_N @2 INTEGER_CST@0 @3))
|
|
INTEGER_CST@1)
|
|
(with {
|
|
int ibit = tree_log2 (@0);
|
|
int ibit2 = tree_log2 (@1);
|
|
}
|
|
(if (ibit == ibit2
|
|
&& ibit >= 0
|
|
&& TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@0))))))
|
|
|
|
(match (nop_atomic_bit_test_and_p @0 @1 @3)
|
|
(bit_and (convert?@3 (SYNC_FETCH_OR_XOR_N @2 INTEGER_CST@0))
|
|
INTEGER_CST@1)
|
|
(with {
|
|
int ibit = tree_log2 (@0);
|
|
int ibit2 = tree_log2 (@1);
|
|
}
|
|
(if (ibit == ibit2
|
|
&& ibit >= 0
|
|
&& TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@0))))))
|
|
|
|
(match (nop_atomic_bit_test_and_p @0 @0 @4)
|
|
(bit_and:c
|
|
(convert1?@4
|
|
(ATOMIC_FETCH_OR_XOR_N @2 (nop_convert? (lshift@0 integer_onep@5 @6)) @3))
|
|
(convert2? @0))
|
|
(if (TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@0)))))
|
|
|
|
(match (nop_atomic_bit_test_and_p @0 @0 @4)
|
|
(bit_and:c
|
|
(convert1?@4
|
|
(SYNC_FETCH_OR_XOR_N @2 (nop_convert? (lshift@0 integer_onep@3 @5))))
|
|
(convert2? @0))
|
|
(if (TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@0)))))
|
|
|
|
(match (nop_atomic_bit_test_and_p @0 @1 @3)
|
|
(bit_and@4 (convert?@3 (ATOMIC_FETCH_AND_N @2 INTEGER_CST@0 @5))
|
|
INTEGER_CST@1)
|
|
(with {
|
|
int ibit = wi::exact_log2 (wi::zext (wi::bit_not (wi::to_wide (@0)),
|
|
TYPE_PRECISION(type)));
|
|
int ibit2 = tree_log2 (@1);
|
|
}
|
|
(if (ibit == ibit2
|
|
&& ibit >= 0
|
|
&& TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@0))))))
|
|
|
|
(match (nop_atomic_bit_test_and_p @0 @1 @3)
|
|
(bit_and@4
|
|
(convert?@3 (SYNC_FETCH_AND_AND_N @2 INTEGER_CST@0))
|
|
INTEGER_CST@1)
|
|
(with {
|
|
int ibit = wi::exact_log2 (wi::zext (wi::bit_not (wi::to_wide (@0)),
|
|
TYPE_PRECISION(type)));
|
|
int ibit2 = tree_log2 (@1);
|
|
}
|
|
(if (ibit == ibit2
|
|
&& ibit >= 0
|
|
&& TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@0))))))
|
|
|
|
(match (nop_atomic_bit_test_and_p @4 @0 @3)
|
|
(bit_and:c
|
|
(convert1?@3
|
|
(ATOMIC_FETCH_AND_N @2 (nop_convert?@4 (bit_not (lshift@0 integer_onep@6 @7))) @5))
|
|
(convert2? @0))
|
|
(if (TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@4)))))
|
|
|
|
(match (nop_atomic_bit_test_and_p @4 @0 @3)
|
|
(bit_and:c
|
|
(convert1?@3
|
|
(SYNC_FETCH_AND_AND_N @2 (nop_convert?@4 (bit_not (lshift@0 integer_onep@6 @7)))))
|
|
(convert2? @0))
|
|
(if (TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@4)))))
|
|
|
|
#endif
|
|
|
|
/* (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. */
|
|
(simplify
|
|
(vec_cond (vec_cond:s @0 @3 integer_zerop) @1 @2)
|
|
(if (optimize_vectors_before_lowering_p () && types_match (@0, @3))
|
|
(vec_cond (bit_and @0 @3) @1 @2)))
|
|
(simplify
|
|
(vec_cond (vec_cond:s @0 integer_all_onesp @3) @1 @2)
|
|
(if (optimize_vectors_before_lowering_p () && types_match (@0, @3))
|
|
(vec_cond (bit_ior @0 @3) @1 @2)))
|
|
(simplify
|
|
(vec_cond (vec_cond:s @0 integer_zerop @3) @1 @2)
|
|
(if (optimize_vectors_before_lowering_p () && types_match (@0, @3))
|
|
(vec_cond (bit_ior @0 (bit_not @3)) @2 @1)))
|
|
(simplify
|
|
(vec_cond (vec_cond:s @0 @3 integer_all_onesp) @1 @2)
|
|
(if (optimize_vectors_before_lowering_p () && types_match (@0, @3))
|
|
(vec_cond (bit_and @0 (bit_not @3)) @2 @1)))
|
|
|
|
/* c1 ? c2 ? a : b : b --> (c1 & c2) ? a : b */
|
|
(simplify
|
|
(vec_cond @0 (vec_cond:s @1 @2 @3) @3)
|
|
(if (optimize_vectors_before_lowering_p () && types_match (@0, @1))
|
|
(vec_cond (bit_and @0 @1) @2 @3)))
|
|
(simplify
|
|
(vec_cond @0 @2 (vec_cond:s @1 @2 @3))
|
|
(if (optimize_vectors_before_lowering_p () && types_match (@0, @1))
|
|
(vec_cond (bit_ior @0 @1) @2 @3)))
|
|
(simplify
|
|
(vec_cond @0 (vec_cond:s @1 @2 @3) @2)
|
|
(if (optimize_vectors_before_lowering_p () && types_match (@0, @1))
|
|
(vec_cond (bit_ior (bit_not @0) @1) @2 @3)))
|
|
(simplify
|
|
(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)))
|
|
|
|
/* Canonicalize mask ? { 0, ... } : { -1, ...} to ~mask if the mask
|
|
types are compatible. */
|
|
(simplify
|
|
(vec_cond @0 VECTOR_CST@1 VECTOR_CST@2)
|
|
(if (VECTOR_BOOLEAN_TYPE_P (type)
|
|
&& types_match (type, TREE_TYPE (@0)))
|
|
(if (integer_zerop (@1) && integer_all_onesp (@2))
|
|
(bit_not @0)
|
|
(if (integer_all_onesp (@1) && integer_zerop (@2))
|
|
@0))))
|
|
|
|
/* A few simplifications of "a ? CST1 : CST2". */
|
|
/* NOTE: Only do this on gimple as the if-chain-to-switch
|
|
optimization depends on the gimple to have if statements in it. */
|
|
#if GIMPLE
|
|
(simplify
|
|
(cond @0 INTEGER_CST@1 INTEGER_CST@2)
|
|
(switch
|
|
(if (integer_zerop (@2))
|
|
(switch
|
|
/* a ? 1 : 0 -> a if 0 and 1 are integral types. */
|
|
(if (integer_onep (@1))
|
|
(convert (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 (convert:boolean_type_node @0))))))
|
|
(if (integer_zerop (@1))
|
|
(with {
|
|
tree booltrue = constant_boolean_node (true, boolean_type_node);
|
|
}
|
|
(switch
|
|
/* a ? 0 : 1 -> !a. */
|
|
(if (integer_onep (@2))
|
|
(convert (bit_xor (convert:boolean_type_node @0) { booltrue; } )))
|
|
/* a ? powerof2cst : 0 -> (!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) { booltrue; } ))
|
|
{ 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 (bit_xor (convert:boolean_type_node @0) { booltrue; } ))))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
#endif
|
|
|
|
/* Simplification moved from fold_cond_expr_with_comparison. It may also
|
|
be extended. */
|
|
/* This pattern implements two kinds simplification:
|
|
|
|
Case 1)
|
|
(cond (cmp (convert1? x) c1) (convert2? x) c2) -> (minmax (x c)) if:
|
|
1) Conversions are type widening from smaller type.
|
|
2) Const c1 equals to c2 after canonicalizing comparison.
|
|
3) Comparison has tree code LT, LE, GT or GE.
|
|
This specific pattern is needed when (cmp (convert x) c) may not
|
|
be simplified by comparison patterns because of multiple uses of
|
|
x. It also makes sense here because simplifying across multiple
|
|
referred var is always benefitial for complicated cases.
|
|
|
|
Case 2)
|
|
(cond (eq (convert1? x) c1) (convert2? x) c2) -> (cond (eq x c1) c1 c2). */
|
|
(for cmp (lt le gt ge eq)
|
|
(simplify
|
|
(cond (cmp (convert1? @1) INTEGER_CST@3) (convert2? @1) INTEGER_CST@2)
|
|
(with
|
|
{
|
|
tree from_type = TREE_TYPE (@1);
|
|
tree c1_type = TREE_TYPE (@3), c2_type = TREE_TYPE (@2);
|
|
enum tree_code code = ERROR_MARK;
|
|
|
|
if (INTEGRAL_TYPE_P (from_type)
|
|
&& int_fits_type_p (@2, from_type)
|
|
&& (types_match (c1_type, from_type)
|
|
|| (TYPE_PRECISION (c1_type) > TYPE_PRECISION (from_type)
|
|
&& (TYPE_UNSIGNED (from_type)
|
|
|| TYPE_SIGN (c1_type) == TYPE_SIGN (from_type))))
|
|
&& (types_match (c2_type, from_type)
|
|
|| (TYPE_PRECISION (c2_type) > TYPE_PRECISION (from_type)
|
|
&& (TYPE_UNSIGNED (from_type)
|
|
|| TYPE_SIGN (c2_type) == TYPE_SIGN (from_type)))))
|
|
{
|
|
if (cmp != EQ_EXPR)
|
|
{
|
|
if (wi::to_widest (@3) == (wi::to_widest (@2) - 1))
|
|
{
|
|
/* X <= Y - 1 equals to X < Y. */
|
|
if (cmp == LE_EXPR)
|
|
code = LT_EXPR;
|
|
/* X > Y - 1 equals to X >= Y. */
|
|
if (cmp == GT_EXPR)
|
|
code = GE_EXPR;
|
|
}
|
|
if (wi::to_widest (@3) == (wi::to_widest (@2) + 1))
|
|
{
|
|
/* X < Y + 1 equals to X <= Y. */
|
|
if (cmp == LT_EXPR)
|
|
code = LE_EXPR;
|
|
/* X >= Y + 1 equals to X > Y. */
|
|
if (cmp == GE_EXPR)
|
|
code = GT_EXPR;
|
|
}
|
|
if (code != ERROR_MARK
|
|
|| wi::to_widest (@2) == wi::to_widest (@3))
|
|
{
|
|
if (cmp == LT_EXPR || cmp == LE_EXPR)
|
|
code = MIN_EXPR;
|
|
if (cmp == GT_EXPR || cmp == GE_EXPR)
|
|
code = MAX_EXPR;
|
|
}
|
|
}
|
|
/* Can do A == C1 ? A : C2 -> A == C1 ? C1 : C2? */
|
|
else if (int_fits_type_p (@3, from_type))
|
|
code = EQ_EXPR;
|
|
}
|
|
}
|
|
(if (code == MAX_EXPR)
|
|
(convert (max @1 (convert @2)))
|
|
(if (code == MIN_EXPR)
|
|
(convert (min @1 (convert @2)))
|
|
(if (code == EQ_EXPR)
|
|
(convert (cond (eq @1 (convert @3))
|
|
(convert:from_type @3) (convert:from_type @2)))))))))
|
|
|
|
/* (cond (cmp (convert? x) c1) (op x c2) c3) -> (op (minmax x c1) c2) if:
|
|
|
|
1) OP is PLUS or MINUS.
|
|
2) CMP is LT, LE, GT or GE.
|
|
3) C3 == (C1 op C2), and computation doesn't have undefined behavior.
|
|
|
|
This pattern also handles special cases like:
|
|
|
|
A) Operand x is a unsigned to signed type conversion and c1 is
|
|
integer zero. In this case,
|
|
(signed type)x < 0 <=> x > MAX_VAL(signed type)
|
|
(signed type)x >= 0 <=> x <= MAX_VAL(signed type)
|
|
B) Const c1 may not equal to (C3 op' C2). In this case we also
|
|
check equality for (c1+1) and (c1-1) by adjusting comparison
|
|
code.
|
|
|
|
TODO: Though signed type is handled by this pattern, it cannot be
|
|
simplified at the moment because C standard requires additional
|
|
type promotion. In order to match&simplify it here, the IR needs
|
|
to be cleaned up by other optimizers, i.e, VRP. */
|
|
(for op (plus minus)
|
|
(for cmp (lt le gt ge)
|
|
(simplify
|
|
(cond (cmp (convert? @X) INTEGER_CST@1) (op @X INTEGER_CST@2) INTEGER_CST@3)
|
|
(with { tree from_type = TREE_TYPE (@X), to_type = TREE_TYPE (@1); }
|
|
(if (types_match (from_type, to_type)
|
|
/* Check if it is special case A). */
|
|
|| (TYPE_UNSIGNED (from_type)
|
|
&& !TYPE_UNSIGNED (to_type)
|
|
&& TYPE_PRECISION (from_type) == TYPE_PRECISION (to_type)
|
|
&& integer_zerop (@1)
|
|
&& (cmp == LT_EXPR || cmp == GE_EXPR)))
|
|
(with
|
|
{
|
|
wi::overflow_type overflow = wi::OVF_NONE;
|
|
enum tree_code code, cmp_code = cmp;
|
|
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:
|
|
((signed type)x < 0) <=> (x > MAX_VAL(signed type))
|
|
((signed type)x >= 0) <=> (x <= MAX_VAL(signed type)) */
|
|
if (!types_match (from_type, to_type))
|
|
{
|
|
if (cmp_code == LT_EXPR)
|
|
cmp_code = GT_EXPR;
|
|
if (cmp_code == GE_EXPR)
|
|
cmp_code = LE_EXPR;
|
|
c1 = wi::max_value (to_type);
|
|
}
|
|
/* To simplify this pattern, we require c3 = (c1 op c2). Here we
|
|
compute (c3 op' c2) and check if it equals to c1 with op' being
|
|
the inverted operator of op. Make sure overflow doesn't happen
|
|
if it is undefined. */
|
|
if (op == PLUS_EXPR)
|
|
real_c1 = wi::sub (c3, c2, sgn, &overflow);
|
|
else
|
|
real_c1 = wi::add (c3, c2, sgn, &overflow);
|
|
|
|
code = cmp_code;
|
|
if (!overflow || !TYPE_OVERFLOW_UNDEFINED (from_type))
|
|
{
|
|
/* Check if c1 equals to real_c1. Boundary condition is handled
|
|
by adjusting comparison operation if necessary. */
|
|
if (!wi::cmp (wi::sub (real_c1, 1, sgn, &overflow), c1, sgn)
|
|
&& !overflow)
|
|
{
|
|
/* X <= Y - 1 equals to X < Y. */
|
|
if (cmp_code == LE_EXPR)
|
|
code = LT_EXPR;
|
|
/* X > Y - 1 equals to X >= Y. */
|
|
if (cmp_code == GT_EXPR)
|
|
code = GE_EXPR;
|
|
}
|
|
if (!wi::cmp (wi::add (real_c1, 1, sgn, &overflow), c1, sgn)
|
|
&& !overflow)
|
|
{
|
|
/* X < Y + 1 equals to X <= Y. */
|
|
if (cmp_code == LT_EXPR)
|
|
code = LE_EXPR;
|
|
/* X >= Y + 1 equals to X > Y. */
|
|
if (cmp_code == GE_EXPR)
|
|
code = GT_EXPR;
|
|
}
|
|
if (code != cmp_code || !wi::cmp (real_c1, c1, sgn))
|
|
{
|
|
if (cmp_code == LT_EXPR || cmp_code == LE_EXPR)
|
|
code = MIN_EXPR;
|
|
if (cmp_code == GT_EXPR || cmp_code == GE_EXPR)
|
|
code = MAX_EXPR;
|
|
}
|
|
}
|
|
}
|
|
(if (code == MAX_EXPR)
|
|
(op (max @X { wide_int_to_tree (from_type, real_c1); })
|
|
{ wide_int_to_tree (from_type, c2); })
|
|
(if (code == MIN_EXPR)
|
|
(op (min @X { wide_int_to_tree (from_type, real_c1); })
|
|
{ wide_int_to_tree (from_type, c2); })))))))))
|
|
|
|
/* X != C1 ? -X : C2 simplifies to -X when -C1 == C2. */
|
|
(simplify
|
|
(cond (ne @0 INTEGER_CST@1) (negate@3 @0) INTEGER_CST@2)
|
|
(if (!TYPE_SATURATING (type)
|
|
&& (TYPE_OVERFLOW_WRAPS (type)
|
|
|| !wi::only_sign_bit_p (wi::to_wide (@1)))
|
|
&& wi::eq_p (wi::neg (wi::to_wide (@1)), wi::to_wide (@2)))
|
|
@3))
|
|
|
|
/* X != C1 ? ~X : C2 simplifies to ~X when ~C1 == C2. */
|
|
(simplify
|
|
(cond (ne @0 INTEGER_CST@1) (bit_not@3 @0) INTEGER_CST@2)
|
|
(if (wi::eq_p (wi::bit_not (wi::to_wide (@1)), wi::to_wide (@2)))
|
|
@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
|
|
(cond (gt (plus @0 integer_onep) @1) (negate @0) integer_onep@2)
|
|
(if (TYPE_UNSIGNED (type))
|
|
(cond (ge @0 @1) (negate @0) @2)))
|
|
|
|
(for cnd (cond vec_cond)
|
|
/* A ? B : (A ? X : C) -> A ? B : C. */
|
|
(simplify
|
|
(cnd @0 (cnd @0 @1 @2) @3)
|
|
(cnd @0 @1 @3))
|
|
(simplify
|
|
(cnd @0 @1 (cnd @0 @2 @3))
|
|
(cnd @0 @1 @3))
|
|
/* A ? B : (!A ? C : X) -> A ? B : C. */
|
|
/* ??? This matches embedded conditions open-coded because genmatch
|
|
would generate matching code for conditions in separate stmts only.
|
|
The following is still important to merge then and else arm cases
|
|
from if-conversion. */
|
|
(simplify
|
|
(cnd @0 @1 (cnd @2 @3 @4))
|
|
(if (inverse_conditions_p (@0, @2))
|
|
(cnd @0 @1 @3)))
|
|
(simplify
|
|
(cnd @0 (cnd @1 @2 @3) @4)
|
|
(if (inverse_conditions_p (@0, @1))
|
|
(cnd @0 @3 @4)))
|
|
|
|
/* A ? B : B -> B. */
|
|
(simplify
|
|
(cnd @0 @1 @1)
|
|
@1)
|
|
|
|
/* !A ? B : C -> A ? C : B. */
|
|
(simplify
|
|
(cnd (logical_inverted_value truth_valued_p@0) @1 @2)
|
|
(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.
|
|
|
|
None of these transformations work for modes with signed
|
|
zeros. If A is +/-0, the first two transformations will
|
|
change the sign of the result (from +0 to -0, or vice
|
|
versa). The last four will fix the sign of the result,
|
|
even though the original expressions could be positive or
|
|
negative, depending on the sign of A.
|
|
|
|
Note that all these transformations are correct if A is
|
|
NaN, since the two alternatives (A and -A) are also NaNs. */
|
|
|
|
(for cnd (cond vec_cond)
|
|
/* 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))
|
|
@1))
|
|
(simplify
|
|
(cnd (cmp @0 zerop) integer_zerop (negate@1 @0))
|
|
(if (!HONOR_SIGNED_ZEROS (type))
|
|
@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))
|
|
(simplify
|
|
(cnd (cmp @0 zerop) @0 integer_zerop)
|
|
(if (!HONOR_SIGNED_ZEROS (type))
|
|
@0))
|
|
)
|
|
/* 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))))
|
|
/* 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))
|
|
(with {
|
|
tree utype = unsigned_type_for (type);
|
|
}
|
|
(convert (negate (absu:utype @0))))
|
|
(negate (abs @0)))))
|
|
)
|
|
)
|
|
|
|
/* -(type)!A -> (type)A - 1. */
|
|
(simplify
|
|
(negate (convert?:s (logical_inverted_value:s @0)))
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& TREE_CODE (type) != BOOLEAN_TYPE
|
|
&& TYPE_PRECISION (type) > 1
|
|
&& TREE_CODE (@0) == SSA_NAME
|
|
&& ssa_name_has_boolean_range (@0))
|
|
(plus (convert:type @0) { build_all_ones_cst (type); })))
|
|
|
|
/* A + (B vcmp C ? 1 : 0) -> A - (B vcmp C ? -1 : 0), since vector comparisons
|
|
return all -1 or all 0 results. */
|
|
/* ??? We could instead convert all instances of the vec_cond to negate,
|
|
but that isn't necessarily a win on its own. */
|
|
(simplify
|
|
(plus:c @3 (view_convert? (vec_cond:s @0 integer_each_onep@1 integer_zerop@2)))
|
|
(if (VECTOR_TYPE_P (type)
|
|
&& 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)))))
|
|
|
|
/* ... likewise A - (B vcmp C ? 1 : 0) -> A + (B vcmp C ? -1 : 0). */
|
|
(simplify
|
|
(minus @3 (view_convert? (vec_cond:s @0 integer_each_onep@1 integer_zerop@2)))
|
|
(if (VECTOR_TYPE_P (type)
|
|
&& 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)))))
|
|
|
|
|
|
/* Simplifications of comparisons. */
|
|
|
|
/* See if we can reduce the magnitude of a constant involved in a
|
|
comparison by changing the comparison code. This is a canonicalization
|
|
formerly done by maybe_canonicalize_comparison_1. */
|
|
(for cmp (le gt)
|
|
acmp (lt ge)
|
|
(simplify
|
|
(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 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
|
|
operator using invert_tree_comparison we have to simulate
|
|
that with expression code iteration. */
|
|
(for cmp (tcc_comparison)
|
|
icmp (inverted_tcc_comparison)
|
|
ncmp (inverted_tcc_comparison_with_nans)
|
|
/* Ideally we'd like to combine the following two patterns
|
|
and handle some more cases by using
|
|
(logical_inverted_value (cmp @0 @1))
|
|
here but for that genmatch would need to "inline" that.
|
|
For now implement what forward_propagate_comparison did. */
|
|
(simplify
|
|
(bit_not (cmp @0 @1))
|
|
(if (VECTOR_TYPE_P (type)
|
|
|| (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) == 1))
|
|
/* Comparison inversion may be impossible for trapping math,
|
|
invert_tree_comparison will tell us. But we can't use
|
|
a computed operator in the replacement tree thus we have
|
|
to play the trick below. */
|
|
(with { enum tree_code ic = invert_tree_comparison
|
|
(cmp, HONOR_NANS (@0)); }
|
|
(if (ic == icmp)
|
|
(icmp @0 @1)
|
|
(if (ic == ncmp)
|
|
(ncmp @0 @1))))))
|
|
(simplify
|
|
(bit_xor (cmp @0 @1) integer_truep)
|
|
(with { enum tree_code ic = invert_tree_comparison
|
|
(cmp, HONOR_NANS (@0)); }
|
|
(if (ic == icmp)
|
|
(icmp @0 @1)
|
|
(if (ic == ncmp)
|
|
(ncmp @0 @1))))))
|
|
|
|
/* Transform comparisons of the form X - Y CMP 0 to X CMP Y.
|
|
??? The transformation is valid for the other operators if overflow
|
|
is undefined for the type, but performing it here badly interacts
|
|
with the transformation in fold_cond_expr_with_comparison which
|
|
attempts to synthetize ABS_EXPR. */
|
|
(for cmp (eq ne)
|
|
(for sub (minus pointer_diff)
|
|
(simplify
|
|
(cmp (sub@2 @0 @1) integer_zerop)
|
|
(if (single_use (@2))
|
|
(cmp @0 @1)))))
|
|
|
|
/* Simplify (x < 0) ^ (y < 0) to (x ^ y) < 0 and
|
|
(x >= 0) ^ (y >= 0) to (x ^ y) < 0. */
|
|
(for cmp (lt ge)
|
|
(simplify
|
|
(bit_xor (cmp:s @0 integer_zerop) (cmp:s @1 integer_zerop))
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& !TYPE_UNSIGNED (TREE_TYPE (@0))
|
|
&& types_match (TREE_TYPE (@0), TREE_TYPE (@1)))
|
|
(lt (bit_xor @0 @1) { build_zero_cst (TREE_TYPE (@0)); }))))
|
|
/* Simplify (x < 0) ^ (y >= 0) to (x ^ y) >= 0 and
|
|
(x >= 0) ^ (y < 0) to (x ^ y) >= 0. */
|
|
(simplify
|
|
(bit_xor:c (lt:s @0 integer_zerop) (ge:s @1 integer_zerop))
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& !TYPE_UNSIGNED (TREE_TYPE (@0))
|
|
&& types_match (TREE_TYPE (@0), TREE_TYPE (@1)))
|
|
(ge (bit_xor @0 @1) { build_zero_cst (TREE_TYPE (@0)); })))
|
|
|
|
/* 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
|
|
often enough for folding it to be of value. One example is in
|
|
computing loop trip counts after Operator Strength Reduction. */
|
|
(for cmp (simple_comparison)
|
|
scmp (swapped_simple_comparison)
|
|
(simplify
|
|
(cmp (mult@3 @0 INTEGER_CST@1) integer_zerop@2)
|
|
/* Handle unfolded multiplication by zero. */
|
|
(if (integer_zerop (@1))
|
|
(cmp @1 @2)
|
|
(if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
|
|
&& single_use (@3))
|
|
/* If @1 is negative we swap the sense of the comparison. */
|
|
(if (tree_int_cst_sgn (@1) < 0)
|
|
(scmp @0 @2)
|
|
(cmp @0 @2))))))
|
|
|
|
/* For integral types with undefined overflow fold
|
|
x * C1 == C2 into x == C2 / C1 or false.
|
|
If overflow wraps and C1 is odd, simplify to x == C2 / C1 in the ring
|
|
Z / 2^n Z. */
|
|
(for cmp (eq ne)
|
|
(simplify
|
|
(cmp (mult @0 INTEGER_CST@1) INTEGER_CST@2)
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
|
|
&& wi::to_wide (@1) != 0)
|
|
(with { widest_int quot; }
|
|
(if (wi::multiple_of_p (wi::to_widest (@2), wi::to_widest (@1),
|
|
TYPE_SIGN (TREE_TYPE (@0)), "))
|
|
(cmp @0 { wide_int_to_tree (TREE_TYPE (@0), quot); })
|
|
{ constant_boolean_node (cmp == NE_EXPR, type); }))
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))
|
|
&& (wi::bit_and (wi::to_wide (@1), 1) == 1))
|
|
(cmp @0
|
|
{
|
|
tree itype = TREE_TYPE (@0);
|
|
int p = TYPE_PRECISION (itype);
|
|
wide_int m = wi::one (p + 1) << p;
|
|
wide_int a = wide_int::from (wi::to_wide (@1), p + 1, UNSIGNED);
|
|
wide_int i = wide_int::from (wi::mod_inv (a, m),
|
|
p, TYPE_SIGN (itype));
|
|
wide_int_to_tree (itype, wi::mul (i, wi::to_wide (@2)));
|
|
})))))
|
|
|
|
/* Simplify comparison of something with itself. For IEEE
|
|
floating-point, we can only do some of these simplifications. */
|
|
(for cmp (eq ge le)
|
|
(simplify
|
|
(cmp @0 @0)
|
|
(if (! FLOAT_TYPE_P (TREE_TYPE (@0))
|
|
|| ! tree_expr_maybe_nan_p (@0))
|
|
{ constant_boolean_node (true, type); }
|
|
(if (cmp != EQ_EXPR
|
|
/* With -ftrapping-math conversion to EQ loses an exception. */
|
|
&& (! FLOAT_TYPE_P (TREE_TYPE (@0))
|
|
|| ! flag_trapping_math))
|
|
(eq @0 @0)))))
|
|
(for cmp (ne gt lt)
|
|
(simplify
|
|
(cmp @0 @0)
|
|
(if (cmp != NE_EXPR
|
|
|| ! FLOAT_TYPE_P (TREE_TYPE (@0))
|
|
|| ! tree_expr_maybe_nan_p (@0))
|
|
{ constant_boolean_node (false, type); })))
|
|
(for cmp (unle unge uneq)
|
|
(simplify
|
|
(cmp @0 @0)
|
|
{ constant_boolean_node (true, type); }))
|
|
(for cmp (unlt ungt)
|
|
(simplify
|
|
(cmp @0 @0)
|
|
(unordered @0 @0)))
|
|
(simplify
|
|
(ltgt @0 @0)
|
|
(if (!flag_trapping_math || !tree_expr_maybe_nan_p (@0))
|
|
{ constant_boolean_node (false, type); }))
|
|
|
|
/* x == ~x -> false */
|
|
/* x != ~x -> true */
|
|
(for cmp (eq ne)
|
|
(simplify
|
|
(cmp:c @0 (bit_not @0))
|
|
{ constant_boolean_node (cmp == NE_EXPR, type); }))
|
|
|
|
/* Fold ~X op ~Y as Y op X. */
|
|
(for cmp (simple_comparison)
|
|
(simplify
|
|
(cmp (bit_not@2 @0) (bit_not@3 @1))
|
|
(if (single_use (@2) && single_use (@3))
|
|
(cmp @1 @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)
|
|
(if (single_use (@2)
|
|
&& (TREE_CODE (@1) == INTEGER_CST || TREE_CODE (@1) == VECTOR_CST))
|
|
(scmp @0 (bit_not @1)))))
|
|
|
|
(for cmp (simple_comparison)
|
|
/* Fold (double)float1 CMP (double)float2 into float1 CMP float2. */
|
|
(simplify
|
|
(cmp (convert@2 @0) (convert? @1))
|
|
(if (FLOAT_TYPE_P (TREE_TYPE (@0))
|
|
&& (DECIMAL_FLOAT_TYPE_P (TREE_TYPE (@2))
|
|
== DECIMAL_FLOAT_TYPE_P (TREE_TYPE (@0)))
|
|
&& (DECIMAL_FLOAT_TYPE_P (TREE_TYPE (@2))
|
|
== DECIMAL_FLOAT_TYPE_P (TREE_TYPE (@1))))
|
|
(with
|
|
{
|
|
tree type1 = TREE_TYPE (@1);
|
|
if (TREE_CODE (@1) == REAL_CST && !DECIMAL_FLOAT_TYPE_P (type1))
|
|
{
|
|
REAL_VALUE_TYPE orig = TREE_REAL_CST (@1);
|
|
if (TYPE_PRECISION (type1) > TYPE_PRECISION (float_type_node)
|
|
&& exact_real_truncate (TYPE_MODE (float_type_node), &orig))
|
|
type1 = float_type_node;
|
|
if (TYPE_PRECISION (type1) > TYPE_PRECISION (double_type_node)
|
|
&& exact_real_truncate (TYPE_MODE (double_type_node), &orig))
|
|
type1 = double_type_node;
|
|
}
|
|
tree newtype
|
|
= (TYPE_PRECISION (TREE_TYPE (@0)) > TYPE_PRECISION (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. */
|
|
(switch
|
|
/* a CMP (-0) -> a CMP 0 */
|
|
(if (REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (@1)))
|
|
(cmp @0 { build_real (TREE_TYPE (@1), dconst0); }))
|
|
/* (-0) CMP b -> 0 CMP b. */
|
|
(if (TREE_CODE (@0) == REAL_CST
|
|
&& REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (@0)))
|
|
(cmp { build_real (TREE_TYPE (@0), dconst0); } @1))
|
|
/* x != NaN is always true, other ops are always false. */
|
|
(if (REAL_VALUE_ISNAN (TREE_REAL_CST (@1))
|
|
&& !tree_expr_signaling_nan_p (@1)
|
|
&& !tree_expr_maybe_signaling_nan_p (@0))
|
|
{ constant_boolean_node (cmp == NE_EXPR, type); })
|
|
/* NaN != y is always true, other ops are always false. */
|
|
(if (TREE_CODE (@0) == REAL_CST
|
|
&& REAL_VALUE_ISNAN (TREE_REAL_CST (@0))
|
|
&& !tree_expr_signaling_nan_p (@0)
|
|
&& !tree_expr_signaling_nan_p (@1))
|
|
{ constant_boolean_node (cmp == NE_EXPR, type); })
|
|
/* Fold comparisons against infinity. */
|
|
(if (REAL_VALUE_ISINF (TREE_REAL_CST (@1))
|
|
&& MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (@1))))
|
|
(with
|
|
{
|
|
REAL_VALUE_TYPE max;
|
|
enum tree_code code = cmp;
|
|
bool neg = REAL_VALUE_NEGATIVE (TREE_REAL_CST (@1));
|
|
if (neg)
|
|
code = swap_tree_comparison (code);
|
|
}
|
|
(switch
|
|
/* x > +Inf is always false, if we ignore NaNs or exceptions. */
|
|
(if (code == GT_EXPR
|
|
&& !(HONOR_NANS (@0) && flag_trapping_math))
|
|
{ constant_boolean_node (false, type); })
|
|
(if (code == LE_EXPR)
|
|
/* 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), 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); })
|
|
(gt @0 { build_real (TREE_TYPE (@0), max); }))))
|
|
/* x < +Inf is always equal to x <= DBL_MAX. */
|
|
(if (code == LT_EXPR)
|
|
(with { real_maxval (&max, neg, TYPE_MODE (TREE_TYPE (@0))); }
|
|
(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), 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))
|
|
(if (neg)
|
|
(ge @0 { build_real (TREE_TYPE (@0), max); })
|
|
(le @0 { build_real (TREE_TYPE (@0), max); }))
|
|
(if (neg)
|
|
(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
|
|
comparison with a revised real constant as long as no overflow
|
|
occurs when unsafe_math_optimizations are enabled. */
|
|
(if (flag_unsafe_math_optimizations)
|
|
(for op (plus minus)
|
|
(simplify
|
|
(cmp (op @0 REAL_CST@1) REAL_CST@2)
|
|
(with
|
|
{
|
|
tree tem = const_binop (op == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR,
|
|
TREE_TYPE (@1), @2, @1);
|
|
}
|
|
(if (tem && !TREE_OVERFLOW (tem))
|
|
(cmp @0 { tem; }))))))
|
|
|
|
/* Likewise, we can simplify a comparison of a real constant with
|
|
a MINUS_EXPR whose first operand is also a real constant, i.e.
|
|
(c1 - x) < c2 becomes x > c1-c2. Reordering is allowed on
|
|
floating-point types only if -fassociative-math is set. */
|
|
(if (flag_associative_math)
|
|
(simplify
|
|
(cmp (minus REAL_CST@0 @1) REAL_CST@2)
|
|
(with { tree tem = const_binop (MINUS_EXPR, TREE_TYPE (@1), @0, @2); }
|
|
(if (tem && !TREE_OVERFLOW (tem))
|
|
(cmp { tem; } @1)))))
|
|
|
|
/* Fold comparisons against built-in math functions. */
|
|
(if (flag_unsafe_math_optimizations && ! flag_errno_math)
|
|
(for sq (SQRT)
|
|
(simplify
|
|
(cmp (sq @0) REAL_CST@1)
|
|
(switch
|
|
(if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (@1)))
|
|
(switch
|
|
/* sqrt(x) < y is always false, if y is negative. */
|
|
(if (cmp == EQ_EXPR || cmp == LT_EXPR || cmp == LE_EXPR)
|
|
{ constant_boolean_node (false, type); })
|
|
/* sqrt(x) > y is always true, if y is negative and we
|
|
don't care about NaNs, i.e. negative values of x. */
|
|
(if (cmp == NE_EXPR || !HONOR_NANS (@0))
|
|
{ constant_boolean_node (true, type); })
|
|
/* sqrt(x) > y is the same as x >= 0, if y is negative. */
|
|
(ge @0 { build_real (TREE_TYPE (@0), dconst0); })))
|
|
(if (real_equal (TREE_REAL_CST_PTR (@1), &dconst0))
|
|
(switch
|
|
/* sqrt(x) < 0 is always false. */
|
|
(if (cmp == LT_EXPR)
|
|
{ constant_boolean_node (false, type); })
|
|
/* sqrt(x) >= 0 is always true if we don't care about NaNs. */
|
|
(if (cmp == GE_EXPR && !HONOR_NANS (@0))
|
|
{ constant_boolean_node (true, type); })
|
|
/* sqrt(x) <= 0 -> x == 0. */
|
|
(if (cmp == LE_EXPR)
|
|
(eq @0 @1))
|
|
/* Otherwise sqrt(x) cmp 0 -> x cmp 0. Here cmp can be >=, >,
|
|
== or !=. In the last case:
|
|
|
|
(sqrt(x) != 0) == (NaN != 0) == true == (x != 0)
|
|
|
|
if x is negative or NaN. Due to -funsafe-math-optimizations,
|
|
the results for other x follow from natural arithmetic. */
|
|
(cmp @0 @1)))
|
|
(if ((cmp == LT_EXPR
|
|
|| cmp == LE_EXPR
|
|
|| cmp == GT_EXPR
|
|
|| cmp == GE_EXPR)
|
|
&& !REAL_VALUE_ISNAN (TREE_REAL_CST (@1))
|
|
/* Give up for -frounding-math. */
|
|
&& !HONOR_SIGN_DEPENDENT_ROUNDING (TREE_TYPE (@0)))
|
|
(with
|
|
{
|
|
REAL_VALUE_TYPE c2;
|
|
enum tree_code ncmp = cmp;
|
|
const real_format *fmt
|
|
= REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (@0)));
|
|
real_arithmetic (&c2, MULT_EXPR,
|
|
&TREE_REAL_CST (@1), &TREE_REAL_CST (@1));
|
|
real_convert (&c2, fmt, &c2);
|
|
/* See PR91734: if c2 is inexact and sqrt(c2) < c (or sqrt(c2) >= c),
|
|
then change LT_EXPR into LE_EXPR or GE_EXPR into GT_EXPR. */
|
|
if (!REAL_VALUE_ISINF (c2))
|
|
{
|
|
tree c3 = fold_const_call (CFN_SQRT, TREE_TYPE (@0),
|
|
build_real (TREE_TYPE (@0), c2));
|
|
if (c3 == NULL_TREE || TREE_CODE (c3) != REAL_CST)
|
|
ncmp = ERROR_MARK;
|
|
else if ((cmp == LT_EXPR || cmp == GE_EXPR)
|
|
&& real_less (&TREE_REAL_CST (c3), &TREE_REAL_CST (@1)))
|
|
ncmp = cmp == LT_EXPR ? LE_EXPR : GT_EXPR;
|
|
else if ((cmp == LE_EXPR || cmp == GT_EXPR)
|
|
&& real_less (&TREE_REAL_CST (@1), &TREE_REAL_CST (c3)))
|
|
ncmp = cmp == LE_EXPR ? LT_EXPR : GE_EXPR;
|
|
else
|
|
{
|
|
/* With rounding to even, sqrt of up to 3 different values
|
|
gives the same normal result, so in some cases c2 needs
|
|
to be adjusted. */
|
|
REAL_VALUE_TYPE c2alt, tow;
|
|
if (cmp == LT_EXPR || cmp == GE_EXPR)
|
|
tow = dconst0;
|
|
else
|
|
real_inf (&tow);
|
|
real_nextafter (&c2alt, fmt, &c2, &tow);
|
|
real_convert (&c2alt, fmt, &c2alt);
|
|
if (REAL_VALUE_ISINF (c2alt))
|
|
ncmp = ERROR_MARK;
|
|
else
|
|
{
|
|
c3 = fold_const_call (CFN_SQRT, TREE_TYPE (@0),
|
|
build_real (TREE_TYPE (@0), c2alt));
|
|
if (c3 == NULL_TREE || TREE_CODE (c3) != REAL_CST)
|
|
ncmp = ERROR_MARK;
|
|
else if (real_equal (&TREE_REAL_CST (c3),
|
|
&TREE_REAL_CST (@1)))
|
|
c2 = c2alt;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
(if (cmp == GT_EXPR || cmp == GE_EXPR)
|
|
(if (REAL_VALUE_ISINF (c2))
|
|
/* sqrt(x) > y is x == +Inf, when y is very large. */
|
|
(if (HONOR_INFINITIES (@0))
|
|
(eq @0 { build_real (TREE_TYPE (@0), c2); })
|
|
{ constant_boolean_node (false, type); })
|
|
/* sqrt(x) > c is the same as x > c*c. */
|
|
(if (ncmp != ERROR_MARK)
|
|
(if (ncmp == GE_EXPR)
|
|
(ge @0 { build_real (TREE_TYPE (@0), c2); })
|
|
(gt @0 { build_real (TREE_TYPE (@0), c2); }))))
|
|
/* else if (cmp == LT_EXPR || cmp == LE_EXPR) */
|
|
(if (REAL_VALUE_ISINF (c2))
|
|
(switch
|
|
/* sqrt(x) < y is always true, when y is a very large
|
|
value and we don't care about NaNs or Infinities. */
|
|
(if (! HONOR_NANS (@0) && ! HONOR_INFINITIES (@0))
|
|
{ constant_boolean_node (true, type); })
|
|
/* sqrt(x) < y is x != +Inf when y is very large and we
|
|
don't care about NaNs. */
|
|
(if (! HONOR_NANS (@0))
|
|
(ne @0 { build_real (TREE_TYPE (@0), c2); }))
|
|
/* sqrt(x) < y is x >= 0 when y is very large and we
|
|
don't care about Infinities. */
|
|
(if (! HONOR_INFINITIES (@0))
|
|
(ge @0 { build_real (TREE_TYPE (@0), dconst0); }))
|
|
/* sqrt(x) < y is x >= 0 && x != +Inf, when y is large. */
|
|
(if (GENERIC)
|
|
(truth_andif
|
|
(ge @0 { build_real (TREE_TYPE (@0), dconst0); })
|
|
(ne @0 { build_real (TREE_TYPE (@0), c2); }))))
|
|
/* sqrt(x) < c is the same as x < c*c, if we ignore NaNs. */
|
|
(if (ncmp != ERROR_MARK && ! HONOR_NANS (@0))
|
|
(if (ncmp == LT_EXPR)
|
|
(lt @0 { build_real (TREE_TYPE (@0), c2); })
|
|
(le @0 { build_real (TREE_TYPE (@0), c2); }))
|
|
/* sqrt(x) < c is the same as x >= 0 && x < c*c. */
|
|
(if (ncmp != ERROR_MARK && GENERIC)
|
|
(if (ncmp == LT_EXPR)
|
|
(truth_andif
|
|
(ge @0 { build_real (TREE_TYPE (@0), dconst0); })
|
|
(lt @0 { build_real (TREE_TYPE (@0), c2); }))
|
|
(truth_andif
|
|
(ge @0 { build_real (TREE_TYPE (@0), dconst0); })
|
|
(le @0 { build_real (TREE_TYPE (@0), c2); })))))))))))
|
|
/* Transform sqrt(x) cmp sqrt(y) -> x cmp y. */
|
|
(simplify
|
|
(cmp (sq @0) (sq @1))
|
|
(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)
|
|
(simplify
|
|
(cmp (float @0) REAL_CST@1)
|
|
(if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (@1))
|
|
&& ! DECIMAL_FLOAT_TYPE_P (TREE_TYPE (@1)))
|
|
(with
|
|
{
|
|
tree itype = TREE_TYPE (@0);
|
|
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
|
|
NaNs. qNaNs are ok in == or != context.
|
|
TODO: relax under -fno-trapping-math or
|
|
-fno-signaling-nans. */
|
|
bool exception_p
|
|
= real_isnan (cst) && (cst->signalling
|
|
|| (cmp != EQ_EXPR && cmp != NE_EXPR));
|
|
}
|
|
/* TODO: allow non-fitting itype and SNaNs when
|
|
-fno-trapping-math. */
|
|
(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);
|
|
|
|
REAL_VALUE_TYPE icst;
|
|
if (cmp == GT_EXPR || cmp == GE_EXPR)
|
|
real_ceil (&icst, fmt, cst);
|
|
else if (cmp == LT_EXPR || cmp == LE_EXPR)
|
|
real_floor (&icst, fmt, cst);
|
|
else
|
|
real_trunc (&icst, fmt, cst);
|
|
|
|
bool cst_int_p = !real_isnan (cst) && real_identical (&icst, cst);
|
|
|
|
bool overflow_p = false;
|
|
wide_int icst_val
|
|
= real_to_integer (&icst, &overflow_p, TYPE_PRECISION (itype));
|
|
}
|
|
(switch
|
|
/* Optimize cases when CST is outside of ITYPE's range. */
|
|
(if (real_compare (LT_EXPR, cst, &imin))
|
|
{ constant_boolean_node (cmp == GT_EXPR || cmp == GE_EXPR || cmp == NE_EXPR,
|
|
type); })
|
|
(if (real_compare (GT_EXPR, cst, &imax))
|
|
{ constant_boolean_node (cmp == LT_EXPR || cmp == LE_EXPR || cmp == NE_EXPR,
|
|
type); })
|
|
/* Remove cast if CST is an integer representable by ITYPE. */
|
|
(if (cst_int_p)
|
|
(cmp @0 { gcc_assert (!overflow_p);
|
|
wide_int_to_tree (itype, icst_val); })
|
|
)
|
|
/* When CST is fractional, optimize
|
|
(FTYPE) N == CST -> 0
|
|
(FTYPE) N != CST -> 1. */
|
|
(if (cmp == EQ_EXPR || cmp == NE_EXPR)
|
|
{ constant_boolean_node (cmp == NE_EXPR, type); })
|
|
/* Otherwise replace with sensible integer constant. */
|
|
(with
|
|
{
|
|
gcc_checking_assert (!overflow_p);
|
|
}
|
|
(icmp @0 { wide_int_to_tree (itype, icst_val); })))))))))
|
|
|
|
/* Fold A /[ex] B CMP C to A CMP B * C. */
|
|
(for cmp (eq ne)
|
|
(simplify
|
|
(cmp (exact_div @0 @1) INTEGER_CST@2)
|
|
(if (!integer_zerop (@1))
|
|
(if (wi::to_wide (@2) == 0)
|
|
(cmp @0 @2)
|
|
(if (TREE_CODE (@1) == INTEGER_CST)
|
|
(with
|
|
{
|
|
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); }
|
|
(cmp @0 { wide_int_to_tree (TREE_TYPE (@0), prod); }))))))))
|
|
(for cmp (lt le gt ge)
|
|
(simplify
|
|
(cmp (exact_div @0 INTEGER_CST@1) INTEGER_CST@2)
|
|
(if (wi::gt_p (wi::to_wide (@1), 0, TYPE_SIGN (TREE_TYPE (@1))))
|
|
(with
|
|
{
|
|
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 (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))
|
|
(if (types_match (@0, @1))
|
|
(unordered @0 @1)))
|
|
(simplify
|
|
(bit_and (ordered @0 @0) (ordered @1 @1))
|
|
(if (types_match (@0, @1))
|
|
(ordered @0 @1)))
|
|
(simplify
|
|
(bit_ior:c (unordered @0 @0) (unordered:c@2 @0 @1))
|
|
@2)
|
|
(simplify
|
|
(bit_and:c (ordered @0 @0) (ordered:c@2 @0 @1))
|
|
@2)
|
|
|
|
/* Simple range test simplifications. */
|
|
/* A < B || A >= B -> true. */
|
|
(for test1 (lt le le le ne ge)
|
|
test2 (ge gt ge ne eq ne)
|
|
(simplify
|
|
(bit_ior:c (test1 @0 @1) (test2 @0 @1))
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
|| VECTOR_INTEGER_TYPE_P (TREE_TYPE (@0)))
|
|
{ constant_boolean_node (true, type); })))
|
|
/* A < B && A >= B -> false. */
|
|
(for test1 (lt lt lt le ne eq)
|
|
test2 (ge gt eq gt eq gt)
|
|
(simplify
|
|
(bit_and:c (test1 @0 @1) (test2 @0 @1))
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
|| VECTOR_INTEGER_TYPE_P (TREE_TYPE (@0)))
|
|
{ constant_boolean_node (false, type); })))
|
|
|
|
/* A & (2**N - 1) <= 2**K - 1 -> A & (2**N - 2**K) == 0
|
|
A & (2**N - 1) > 2**K - 1 -> A & (2**N - 2**K) != 0
|
|
|
|
Note that comparisons
|
|
A & (2**N - 1) < 2**K -> A & (2**N - 2**K) == 0
|
|
A & (2**N - 1) >= 2**K -> A & (2**N - 2**K) != 0
|
|
will be canonicalized to above so there's no need to
|
|
consider them here.
|
|
*/
|
|
|
|
(for cmp (le gt)
|
|
eqcmp (eq ne)
|
|
(simplify
|
|
(cmp (bit_and@0 @1 INTEGER_CST@2) INTEGER_CST@3)
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0)))
|
|
(with
|
|
{
|
|
tree ty = TREE_TYPE (@0);
|
|
unsigned prec = TYPE_PRECISION (ty);
|
|
wide_int mask = wi::to_wide (@2, prec);
|
|
wide_int rhs = wi::to_wide (@3, prec);
|
|
signop sgn = TYPE_SIGN (ty);
|
|
}
|
|
(if ((mask & (mask + 1)) == 0 && wi::gt_p (rhs, 0, sgn)
|
|
&& (rhs & (rhs + 1)) == 0 && wi::ge_p (mask, rhs, sgn))
|
|
(eqcmp (bit_and @1 { wide_int_to_tree (ty, mask - rhs); })
|
|
{ build_zero_cst (ty); }))))))
|
|
|
|
/* -A CMP -B -> B CMP A. */
|
|
(for cmp (tcc_comparison)
|
|
scmp (swapped_tcc_comparison)
|
|
(simplify
|
|
(cmp (negate @0) (negate @1))
|
|
(if (FLOAT_TYPE_P (TREE_TYPE (@0))
|
|
|| (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))))
|
|
(scmp @0 @1)))
|
|
(simplify
|
|
(cmp (negate @0) CONSTANT_CLASS_P@1)
|
|
(if (FLOAT_TYPE_P (TREE_TYPE (@0))
|
|
|| (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))))
|
|
(with { tree tem = const_unop (NEGATE_EXPR, TREE_TYPE (@0), @1); }
|
|
(if (tem && !TREE_OVERFLOW (tem))
|
|
(scmp @0 { tem; }))))))
|
|
|
|
/* Convert ABS_EXPR<x> == 0 or ABS_EXPR<x> != 0 to x == 0 or x != 0. */
|
|
(for op (eq ne)
|
|
(simplify
|
|
(op (abs @0) zerop@1)
|
|
(op @0 @1)))
|
|
|
|
/* 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))
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
/* Disable this optimization if we're casting a function pointer
|
|
type on targets that require function pointer canonicalization. */
|
|
&& !(targetm.have_canonicalize_funcptr_for_compare ()
|
|
&& ((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)
|
|
&& (TYPE_UNSIGNED (TREE_TYPE (@00)) == TYPE_UNSIGNED (TREE_TYPE (@0))
|
|
|| cmp == NE_EXPR
|
|
|| cmp == EQ_EXPR)
|
|
&& !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. */
|
|
(if (TREE_CODE (@1) == INTEGER_CST)
|
|
(cmp @00 { force_fit_type (TREE_TYPE (@00), wi::to_widest (@1), 0,
|
|
TREE_OVERFLOW (@1)); })
|
|
(cmp @00 (convert @1)))
|
|
|
|
(if (TYPE_PRECISION (TREE_TYPE (@0)) > TYPE_PRECISION (TREE_TYPE (@00)))
|
|
/* If possible, express the comparison in the shorter mode. */
|
|
(if ((cmp == EQ_EXPR || cmp == NE_EXPR
|
|
|| TYPE_UNSIGNED (TREE_TYPE (@0)) == TYPE_UNSIGNED (TREE_TYPE (@00))
|
|
|| (!TYPE_UNSIGNED (TREE_TYPE (@0))
|
|
&& TYPE_UNSIGNED (TREE_TYPE (@00))))
|
|
&& (types_match (TREE_TYPE (@10), TREE_TYPE (@00))
|
|
|| ((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
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@00))
|
|
&& int_fits_type_p (@10, TREE_TYPE (@00)))))
|
|
(cmp @00 (convert @10))
|
|
(if (TREE_CODE (@10) == INTEGER_CST
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@00))
|
|
&& !int_fits_type_p (@10, 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));
|
|
}
|
|
(if (above || below)
|
|
(if (cmp == EQ_EXPR || cmp == NE_EXPR)
|
|
{ constant_boolean_node (cmp == EQ_EXPR ? false : true, type); }
|
|
(if (cmp == LT_EXPR || cmp == LE_EXPR)
|
|
{ constant_boolean_node (above ? true : false, type); }
|
|
(if (cmp == GT_EXPR || cmp == GE_EXPR)
|
|
{ constant_boolean_node (above ? false : true, type); }))))))))))))
|
|
|
|
(for cmp (eq ne)
|
|
(simplify
|
|
/* SSA names are canonicalized to 2nd place. */
|
|
(cmp addr@0 SSA_NAME@1)
|
|
(with
|
|
{ poly_int64 off; tree base; }
|
|
/* A local variable can never be pointed to by
|
|
the default SSA name of an incoming parameter. */
|
|
(if (SSA_NAME_IS_DEFAULT_DEF (@1)
|
|
&& TREE_CODE (SSA_NAME_VAR (@1)) == PARM_DECL
|
|
&& (base = get_base_address (TREE_OPERAND (@0, 0)))
|
|
&& TREE_CODE (base) == VAR_DECL
|
|
&& auto_var_in_fn_p (base, current_function_decl))
|
|
(if (cmp == NE_EXPR)
|
|
{ constant_boolean_node (true, type); }
|
|
{ constant_boolean_node (false, type); })
|
|
/* If the address is based on @1 decide using the offset. */
|
|
(if ((base = get_addr_base_and_unit_offset (TREE_OPERAND (@0, 0), &off))
|
|
&& TREE_CODE (base) == MEM_REF
|
|
&& TREE_OPERAND (base, 0) == @1)
|
|
(with { off += mem_ref_offset (base).force_shwi (); }
|
|
(if (known_ne (off, 0))
|
|
{ constant_boolean_node (cmp == NE_EXPR, type); }
|
|
(if (known_eq (off, 0))
|
|
{ constant_boolean_node (cmp == EQ_EXPR, type); }))))))))
|
|
|
|
/* Equality compare simplifications from fold_binary */
|
|
(for cmp (eq ne)
|
|
|
|
/* If we have (A | C) == D where C & ~D != 0, convert this into 0.
|
|
Similarly for NE_EXPR. */
|
|
(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 (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_xor @0 @1) integer_zerop)
|
|
(cmp @0 @1))
|
|
|
|
/* (X ^ Y) == Y becomes X == 0.
|
|
Likewise (X ^ Y) == X becomes Y == 0. */
|
|
(simplify
|
|
(cmp:c (bit_xor:c @0 @1) @0)
|
|
(cmp @1 { build_zero_cst (TREE_TYPE (@1)); }))
|
|
|
|
#if GIMPLE
|
|
/* (X & Y) == X becomes (X & ~Y) == 0. */
|
|
(simplify
|
|
(cmp:c (bit_and:c @0 @1) @0)
|
|
(cmp (bit_and @0 (bit_not! @1)) { build_zero_cst (TREE_TYPE (@0)); }))
|
|
(simplify
|
|
(cmp:c (convert@3 (bit_and (convert@2 @0) INTEGER_CST@1)) (convert @0))
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@2))
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@3))
|
|
&& TYPE_PRECISION (TREE_TYPE (@2)) == TYPE_PRECISION (TREE_TYPE (@0))
|
|
&& TYPE_PRECISION (TREE_TYPE (@3)) > TYPE_PRECISION (TREE_TYPE (@2))
|
|
&& !wi::neg_p (wi::to_wide (@1)))
|
|
(cmp (bit_and @0 (convert (bit_not @1)))
|
|
{ build_zero_cst (TREE_TYPE (@0)); })))
|
|
|
|
/* (X | Y) == Y becomes (X & ~Y) == 0. */
|
|
(simplify
|
|
(cmp:c (bit_ior:c @0 @1) @1)
|
|
(cmp (bit_and @0 (bit_not! @1)) { build_zero_cst (TREE_TYPE (@0)); }))
|
|
#endif
|
|
|
|
/* (X ^ C1) op C2 can be rewritten as X op (C1 ^ C2). */
|
|
(simplify
|
|
(cmp (convert?@3 (bit_xor @0 INTEGER_CST@1)) INTEGER_CST@2)
|
|
(if (tree_nop_conversion_p (TREE_TYPE (@3), TREE_TYPE (@0)))
|
|
(cmp @0 (bit_xor @1 (convert @2)))))
|
|
|
|
(simplify
|
|
(cmp (convert? addr@0) integer_zerop)
|
|
(if (tree_single_nonzero_warnv_p (@0, NULL))
|
|
{ constant_boolean_node (cmp == NE_EXPR, type); }))
|
|
|
|
/* (X & C) op (Y & C) into (X ^ Y) & C op 0. */
|
|
(simplify
|
|
(cmp (bit_and:cs @0 @2) (bit_and:cs @1 @2))
|
|
(cmp (bit_and (bit_xor @0 @1) @2) { build_zero_cst (TREE_TYPE (@2)); })))
|
|
|
|
/* (X < 0) != (Y < 0) into (X ^ Y) < 0.
|
|
(X >= 0) != (Y >= 0) into (X ^ Y) < 0.
|
|
(X < 0) == (Y < 0) into (X ^ Y) >= 0.
|
|
(X >= 0) == (Y >= 0) into (X ^ Y) >= 0. */
|
|
(for cmp (eq ne)
|
|
ncmp (ge lt)
|
|
(for sgncmp (ge lt)
|
|
(simplify
|
|
(cmp (sgncmp @0 integer_zerop@2) (sgncmp @1 integer_zerop))
|
|
(if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& !TYPE_UNSIGNED (TREE_TYPE (@0))
|
|
&& types_match (@0, @1))
|
|
(ncmp (bit_xor @0 @1) @2)))))
|
|
/* (X < 0) == (Y >= 0) into (X ^ Y) < 0.
|
|
(X < 0) != (Y >= 0) into (X ^ Y) >= 0. */
|
|
(for cmp (eq ne)
|
|
ncmp (lt ge)
|
|
(simplify
|
|
(cmp:c (lt @0 integer_zerop@2) (ge @1 integer_zerop))
|
|
(if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& !TYPE_UNSIGNED (TREE_TYPE (@0))
|
|
&& types_match (@0, @1))
|
|
(ncmp (bit_xor @0 @1) @2))))
|
|
|
|
/* If we have (A & C) == C where C is a power of 2, convert this into
|
|
(A & C) != 0. Similarly for NE_EXPR. */
|
|
(for cmp (eq ne)
|
|
icmp (ne eq)
|
|
(simplify
|
|
(cmp (bit_and@2 @0 integer_pow2p@1) @1)
|
|
(icmp @2 { build_zero_cst (TREE_TYPE (@0)); })))
|
|
|
|
(for cmp (ge lt)
|
|
/* x < 0 ? ~y : y into (x >> (prec-1)) ^ y. */
|
|
/* x >= 0 ? ~y : y into ~((x >> (prec-1)) ^ y). */
|
|
(simplify
|
|
(cond (cmp @0 integer_zerop) (bit_not @1) @1)
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& !TYPE_UNSIGNED (TREE_TYPE (@0))
|
|
&& TYPE_PRECISION (TREE_TYPE (@0)) == TYPE_PRECISION (type))
|
|
(with
|
|
{
|
|
tree shifter = build_int_cst (integer_type_node, TYPE_PRECISION (type) - 1);
|
|
}
|
|
(if (cmp == LT_EXPR)
|
|
(bit_xor (convert (rshift @0 {shifter;})) @1)
|
|
(bit_not (bit_xor (convert (rshift @0 {shifter;})) @1))))))
|
|
/* x < 0 ? y : ~y into ~((x >> (prec-1)) ^ y). */
|
|
/* x >= 0 ? y : ~y into (x >> (prec-1)) ^ y. */
|
|
(simplify
|
|
(cond (cmp @0 integer_zerop) @1 (bit_not @1))
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& !TYPE_UNSIGNED (TREE_TYPE (@0))
|
|
&& TYPE_PRECISION (TREE_TYPE (@0)) == TYPE_PRECISION (type))
|
|
(with
|
|
{
|
|
tree shifter = build_int_cst (integer_type_node, TYPE_PRECISION (type) - 1);
|
|
}
|
|
(if (cmp == GE_EXPR)
|
|
(bit_xor (convert (rshift @0 {shifter;})) @1)
|
|
(bit_not (bit_xor (convert (rshift @0 {shifter;})) @1)))))))
|
|
|
|
/* 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_CST@2 integer_zerop)
|
|
(if (!POINTER_TYPE_P (type) && 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. */
|
|
(for cmp (eq ne)
|
|
ncmp (ge lt)
|
|
(simplify
|
|
(cmp (bit_and (convert?@2 @0) integer_pow2p@1) integer_zerop)
|
|
(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 (wi::to_wide (@1), element_precision (@0)))
|
|
(with { tree stype = signed_type_for (TREE_TYPE (@0)); }
|
|
(ncmp (convert:stype @0) { build_zero_cst (stype); })))))
|
|
|
|
/* If we have A < 0 ? C : 0 where C is a power of 2, convert
|
|
this into a right shift or sign extension followed by ANDing with C. */
|
|
(simplify
|
|
(cond
|
|
(lt @0 integer_zerop)
|
|
INTEGER_CST@1 integer_zerop)
|
|
(if (integer_pow2p (@1)
|
|
&& !TYPE_UNSIGNED (TREE_TYPE (@0)))
|
|
(with {
|
|
int shift = element_precision (@0) - wi::exact_log2 (wi::to_wide (@1)) - 1;
|
|
}
|
|
(if (shift >= 0)
|
|
(bit_and
|
|
(convert (rshift @0 { build_int_cst (integer_type_node, shift); }))
|
|
@1)
|
|
/* Otherwise ctype must be wider than TREE_TYPE (@0) and pure
|
|
sign extension followed by AND with C will achieve the effect. */
|
|
(bit_and (convert @0) @1)))))
|
|
|
|
/* When the addresses are not directly of decls compare base and offset.
|
|
This implements some remaining parts of fold_comparison address
|
|
comparisons but still no complete part of it. Still it is good
|
|
enough to make fold_stmt not regress when not dispatching to fold_binary. */
|
|
(for cmp (simple_comparison)
|
|
(simplify
|
|
(cmp (convert1?@2 addr@0) (convert2? addr@1))
|
|
(with
|
|
{
|
|
poly_int64 off0, off1;
|
|
tree base0, base1;
|
|
int equal = address_compare (cmp, TREE_TYPE (@2), @0, @1, base0, base1,
|
|
off0, off1, GENERIC);
|
|
}
|
|
(if (equal == 1)
|
|
(switch
|
|
(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)
|
|
(simplify
|
|
(neeq @0 @1)
|
|
(if (POINTER_TYPE_P (TREE_TYPE (@0))
|
|
&& ptrs_compare_unequal (@0, @1))
|
|
{ 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.
|
|
Disable the transform if either operand is pointer to function.
|
|
This broke pr22051-2.c for arm where function pointer
|
|
canonicalizaion is not wanted. */
|
|
|
|
(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))
|
|
/* Don't perform this optimization in GENERIC if @0 has reference
|
|
type when sanitizing. See PR101210. */
|
|
&& !(GENERIC
|
|
&& TREE_CODE (TREE_TYPE (@0)) == REFERENCE_TYPE
|
|
&& (flag_sanitize & (SANITIZE_NULL | SANITIZE_ALIGNMENT))))
|
|
|| (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 */
|
|
(for cmp (lt gt le ge)
|
|
/* Comparisons with the highest or lowest possible integer of
|
|
the specified precision will have known values. */
|
|
(simplify
|
|
(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 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::to_wide (cst) == max)
|
|
(switch
|
|
(if (cmp == GT_EXPR)
|
|
{ constant_boolean_node (false, type); })
|
|
(if (cmp == GE_EXPR)
|
|
(eq @2 @1))
|
|
(if (cmp == LE_EXPR)
|
|
{ constant_boolean_node (true, type); })
|
|
(if (cmp == LT_EXPR)
|
|
(ne @2 @1))))
|
|
(if (wi::to_wide (cst) == min)
|
|
(switch
|
|
(if (cmp == LT_EXPR)
|
|
{ constant_boolean_node (false, type); })
|
|
(if (cmp == LE_EXPR)
|
|
(eq @2 @1))
|
|
(if (cmp == GE_EXPR)
|
|
{ constant_boolean_node (true, type); })
|
|
(if (cmp == GT_EXPR)
|
|
(ne @2 @1))))
|
|
(if (wi::to_wide (cst) == max - 1)
|
|
(switch
|
|
(if (cmp == GT_EXPR)
|
|
(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 { 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 { build_uniform_cst (TREE_TYPE (@1),
|
|
wide_int_to_tree (TREE_TYPE (cst),
|
|
wi::to_wide (cst)
|
|
- 1)); }))
|
|
(if (cmp == LT_EXPR)
|
|
(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
|
|
specified by this mode. Check that @1 is the signed
|
|
max associated with this sign bit. */
|
|
&& prec == GET_MODE_PRECISION (SCALAR_INT_TYPE_MODE (arg1_type))
|
|
/* signed_type does not work on pointer types. */
|
|
&& INTEGRAL_TYPE_P (arg1_type))
|
|
/* 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 (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 @0 REAL_CST@1)
|
|
(if (REAL_VALUE_ISNAN (TREE_REAL_CST (@1))
|
|
&& (cmp != LTGT_EXPR || ! flag_trapping_math))
|
|
{ constant_boolean_node (cmp == ORDERED_EXPR || cmp == LTGT_EXPR
|
|
? false : true, type); })))
|
|
|
|
/* Fold UNORDERED if either operand must be NaN, or neither can be. */
|
|
(simplify
|
|
(unordered @0 @1)
|
|
(switch
|
|
(if (tree_expr_nan_p (@0) || tree_expr_nan_p (@1))
|
|
{ constant_boolean_node (true, type); })
|
|
(if (!tree_expr_maybe_nan_p (@0) && !tree_expr_maybe_nan_p (@1))
|
|
{ constant_boolean_node (false, type); })))
|
|
|
|
/* Fold ORDERED if either operand must be NaN, or neither can be. */
|
|
(simplify
|
|
(ordered @0 @1)
|
|
(switch
|
|
(if (tree_expr_nan_p (@0) || tree_expr_nan_p (@1))
|
|
{ constant_boolean_node (false, type); })
|
|
(if (!tree_expr_maybe_nan_p (@0) && !tree_expr_maybe_nan_p (@1))
|
|
{ constant_boolean_node (true, type); })))
|
|
|
|
/* bool_var != 0 becomes bool_var. */
|
|
(simplify
|
|
(ne @0 integer_zerop)
|
|
(if (TREE_CODE (TREE_TYPE (@0)) == BOOLEAN_TYPE
|
|
&& types_match (type, TREE_TYPE (@0)))
|
|
(non_lvalue @0)))
|
|
/* bool_var == 1 becomes bool_var. */
|
|
(simplify
|
|
(eq @0 integer_onep)
|
|
(if (TREE_CODE (TREE_TYPE (@0)) == BOOLEAN_TYPE
|
|
&& types_match (type, TREE_TYPE (@0)))
|
|
(non_lvalue @0)))
|
|
/* Do not handle
|
|
bool_var == 0 becomes !bool_var or
|
|
bool_var != 1 becomes !bool_var
|
|
here because that only is good in assignment context as long
|
|
as we require a tcc_comparison in GIMPLE_CONDs where we'd
|
|
replace if (x == 0) with tem = ~x; if (tem != 0) which is
|
|
clearly less optimal and which we'll transform again in forwprop. */
|
|
|
|
/* Transform comparisons of the form (X & Y) CMP 0 to X CMP2 Z
|
|
where ~Y + 1 == pow2 and Z = ~Y. */
|
|
(for cst (VECTOR_CST INTEGER_CST)
|
|
(for cmp (eq ne)
|
|
icmp (le gt)
|
|
(simplify
|
|
(cmp (bit_and:c@2 @0 cst@1) integer_zerop)
|
|
(with { tree csts = bitmask_inv_cst_vector_p (@1); }
|
|
(if (csts && (VECTOR_TYPE_P (TREE_TYPE (@1)) || single_use (@2)))
|
|
(with { auto optab = VECTOR_TYPE_P (TREE_TYPE (@1))
|
|
? optab_vector : optab_default;
|
|
tree utype = unsigned_type_for (TREE_TYPE (@1)); }
|
|
(if (target_supports_op_p (utype, icmp, optab)
|
|
|| (optimize_vectors_before_lowering_p ()
|
|
&& (!target_supports_op_p (type, cmp, optab)
|
|
|| !target_supports_op_p (type, BIT_AND_EXPR, optab))))
|
|
(if (TYPE_UNSIGNED (TREE_TYPE (@1)))
|
|
(icmp @0 { csts; })
|
|
(icmp (view_convert:utype @0) { csts; })))))))))
|
|
|
|
/* When one argument is a constant, overflow detection can be simplified.
|
|
Currently restricted to single use so as not to interfere too much with
|
|
ADD_OVERFLOW detection in tree-ssa-math-opts.cc.
|
|
CONVERT?(CONVERT?(A) + CST) CMP A -> A CMP' CST' */
|
|
(for cmp (lt le ge gt)
|
|
out (gt gt le le)
|
|
(simplify
|
|
(cmp:c (convert?@3 (plus@2 (convert?@4 @0) INTEGER_CST@1)) @0)
|
|
(if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@2))
|
|
&& types_match (TREE_TYPE (@0), TREE_TYPE (@3))
|
|
&& tree_nop_conversion_p (TREE_TYPE (@4), TREE_TYPE (@0))
|
|
&& wi::to_wide (@1) != 0
|
|
&& single_use (@2))
|
|
(with {
|
|
unsigned int prec = TYPE_PRECISION (TREE_TYPE (@0));
|
|
signop sign = TYPE_SIGN (TREE_TYPE (@0));
|
|
}
|
|
(out @0 { wide_int_to_tree (TREE_TYPE (@0),
|
|
wi::max_value (prec, sign)
|
|
- 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.cc
|
|
expects the long form, so we restrict the transformation for now. */
|
|
(for cmp (gt le)
|
|
(simplify
|
|
(cmp:c (minus@2 @0 @1) @0)
|
|
(if (single_use (@2)
|
|
&& ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& TYPE_UNSIGNED (TREE_TYPE (@0)))
|
|
(cmp @1 @0))))
|
|
|
|
/* Optimize A - B + -1 >= A into B >= A for unsigned comparisons. */
|
|
(for cmp (ge lt)
|
|
(simplify
|
|
(cmp:c (plus (minus @0 @1) integer_minus_onep) @0)
|
|
(if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& TYPE_UNSIGNED (TREE_TYPE (@0)))
|
|
(cmp @1 @0))))
|
|
|
|
/* Testing for overflow is unnecessary if we already know the result. */
|
|
/* A - B > A */
|
|
(for cmp (gt le)
|
|
out (ne eq)
|
|
(simplify
|
|
(cmp:c (realpart (IFN_SUB_OVERFLOW@2 @0 @1)) @0)
|
|
(if (TYPE_UNSIGNED (TREE_TYPE (@0))
|
|
&& types_match (TREE_TYPE (@0), TREE_TYPE (@1)))
|
|
(out (imagpart @2) { build_zero_cst (TREE_TYPE (@0)); }))))
|
|
/* A + B < A */
|
|
(for cmp (lt ge)
|
|
out (ne eq)
|
|
(simplify
|
|
(cmp:c (realpart (IFN_ADD_OVERFLOW:c@2 @0 @1)) @0)
|
|
(if (TYPE_UNSIGNED (TREE_TYPE (@0))
|
|
&& types_match (TREE_TYPE (@0), TREE_TYPE (@1)))
|
|
(out (imagpart @2) { build_zero_cst (TREE_TYPE (@0)); }))))
|
|
|
|
/* For unsigned operands, -1 / B < A checks whether A * B would overflow.
|
|
Simplify it to __builtin_mul_overflow (A, B, <unused>). */
|
|
(for cmp (lt ge)
|
|
out (ne eq)
|
|
(simplify
|
|
(cmp:c (trunc_div:s integer_all_onesp @1) @0)
|
|
(if (TYPE_UNSIGNED (TREE_TYPE (@0)) && !VECTOR_TYPE_P (TREE_TYPE (@0)))
|
|
(with { tree t = TREE_TYPE (@0), cpx = build_complex_type (t); }
|
|
(out (imagpart (IFN_MUL_OVERFLOW:cpx @0 @1)) { build_zero_cst (t); })))))
|
|
|
|
/* Similarly, for unsigned operands, (((type) A * B) >> prec) != 0 where type
|
|
is at least twice as wide as type of A and B, simplify to
|
|
__builtin_mul_overflow (A, B, <unused>). */
|
|
(for cmp (eq ne)
|
|
(simplify
|
|
(cmp (rshift (mult:s (convert@3 @0) (convert @1)) INTEGER_CST@2)
|
|
integer_zerop)
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@3))
|
|
&& TYPE_UNSIGNED (TREE_TYPE (@0))
|
|
&& (TYPE_PRECISION (TREE_TYPE (@3))
|
|
>= 2 * TYPE_PRECISION (TREE_TYPE (@0)))
|
|
&& tree_fits_uhwi_p (@2)
|
|
&& tree_to_uhwi (@2) == TYPE_PRECISION (TREE_TYPE (@0))
|
|
&& types_match (@0, @1)
|
|
&& type_has_mode_precision_p (TREE_TYPE (@0))
|
|
&& (optab_handler (umulv4_optab, TYPE_MODE (TREE_TYPE (@0)))
|
|
!= CODE_FOR_nothing))
|
|
(with { tree t = TREE_TYPE (@0), cpx = build_complex_type (t); }
|
|
(cmp (imagpart (IFN_MUL_OVERFLOW:cpx @0 @1)) { build_zero_cst (t); })))))
|
|
|
|
/* Demote operands of IFN_{ADD,SUB,MUL}_OVERFLOW. */
|
|
(for ovf (IFN_ADD_OVERFLOW IFN_SUB_OVERFLOW IFN_MUL_OVERFLOW)
|
|
(simplify
|
|
(ovf (convert@2 @0) @1)
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@2))
|
|
&& TYPE_PRECISION (TREE_TYPE (@2)) > TYPE_PRECISION (TREE_TYPE (@0))
|
|
&& (!TYPE_UNSIGNED (TREE_TYPE (@2)) || TYPE_UNSIGNED (TREE_TYPE (@0))))
|
|
(ovf @0 @1)))
|
|
(simplify
|
|
(ovf @1 (convert@2 @0))
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@2))
|
|
&& TYPE_PRECISION (TREE_TYPE (@2)) > TYPE_PRECISION (TREE_TYPE (@0))
|
|
&& (!TYPE_UNSIGNED (TREE_TYPE (@2)) || TYPE_UNSIGNED (TREE_TYPE (@0))))
|
|
(ovf @1 @0))))
|
|
|
|
/* Simplification of math builtins. These rules must all be optimizations
|
|
as well as IL simplifications. If there is a possibility that the new
|
|
form could be a pessimization, the rule should go in the canonicalization
|
|
section that follows this one.
|
|
|
|
Rules can generally go in this section if they satisfy one of
|
|
the following:
|
|
|
|
- the rule describes an identity
|
|
|
|
- the rule replaces calls with something as simple as addition or
|
|
multiplication
|
|
|
|
- the rule contains unary calls only and simplifies the surrounding
|
|
arithmetic. (The idea here is to exclude non-unary calls in which
|
|
one operand is constant and in which the call is known to be cheap
|
|
when the operand has that value.) */
|
|
|
|
(if (flag_unsafe_math_optimizations)
|
|
/* Simplify sqrt(x) * sqrt(x) -> x. */
|
|
(simplify
|
|
(mult (SQRT_ALL@1 @0) @1)
|
|
(if (!tree_expr_maybe_signaling_nan_p (@0))
|
|
@0))
|
|
|
|
(for op (plus minus)
|
|
/* Simplify (A / C) +- (B / C) -> (A +- B) / C. */
|
|
(simplify
|
|
(op (rdiv @0 @1)
|
|
(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
|
|
(mult (root:s @0) (root:s @1))
|
|
(root (mult @0 @1))))
|
|
|
|
/* Simplify expN(x) * expN(y) -> expN(x+y). */
|
|
(for exps (EXP EXP2 EXP10 POW10)
|
|
(simplify
|
|
(mult (exps:s @0) (exps:s @1))
|
|
(exps (plus @0 @1))))
|
|
|
|
/* Simplify a/root(b/c) into a*root(c/b). */
|
|
(for root (SQRT CBRT)
|
|
(simplify
|
|
(rdiv @0 (root:s (rdiv:s @1 @2)))
|
|
(mult @0 (root (rdiv @2 @1)))))
|
|
|
|
/* Simplify x/expN(y) into x*expN(-y). */
|
|
(for exps (EXP EXP2 EXP10 POW10)
|
|
(simplify
|
|
(rdiv @0 (exps:s @1))
|
|
(mult @0 (exps (negate @1)))))
|
|
|
|
(for logs (LOG LOG2 LOG10 LOG10)
|
|
exps (EXP EXP2 EXP10 POW10)
|
|
/* logN(expN(x)) -> x. */
|
|
(simplify
|
|
(logs (exps @0))
|
|
@0)
|
|
/* expN(logN(x)) -> x. */
|
|
(simplify
|
|
(exps (logs @0))
|
|
@0))
|
|
|
|
/* Optimize logN(func()) for various exponential functions. We
|
|
want to determine the value "x" and the power "exponent" in
|
|
order to transform logN(x**exponent) into exponent*logN(x). */
|
|
(for logs (LOG LOG LOG LOG2 LOG2 LOG2 LOG10 LOG10)
|
|
exps (EXP2 EXP10 POW10 EXP EXP10 POW10 EXP EXP2)
|
|
(simplify
|
|
(logs (exps @0))
|
|
(if (SCALAR_FLOAT_TYPE_P (type))
|
|
(with {
|
|
tree x;
|
|
switch (exps)
|
|
{
|
|
CASE_CFN_EXP:
|
|
/* Prepare to do logN(exp(exponent)) -> exponent*logN(e). */
|
|
x = build_real_truncate (type, dconst_e ());
|
|
break;
|
|
CASE_CFN_EXP2:
|
|
/* Prepare to do logN(exp2(exponent)) -> exponent*logN(2). */
|
|
x = build_real (type, dconst2);
|
|
break;
|
|
CASE_CFN_EXP10:
|
|
CASE_CFN_POW10:
|
|
/* Prepare to do logN(exp10(exponent)) -> exponent*logN(10). */
|
|
{
|
|
REAL_VALUE_TYPE dconst10;
|
|
real_from_integer (&dconst10, VOIDmode, 10, SIGNED);
|
|
x = build_real (type, dconst10);
|
|
}
|
|
break;
|
|
default:
|
|
gcc_unreachable ();
|
|
}
|
|
}
|
|
(mult (logs { x; }) @0)))))
|
|
|
|
(for logs (LOG LOG
|
|
LOG2 LOG2
|
|
LOG10 LOG10)
|
|
exps (SQRT CBRT)
|
|
(simplify
|
|
(logs (exps @0))
|
|
(if (SCALAR_FLOAT_TYPE_P (type))
|
|
(with {
|
|
tree x;
|
|
switch (exps)
|
|
{
|
|
CASE_CFN_SQRT:
|
|
/* Prepare to do logN(sqrt(x)) -> 0.5*logN(x). */
|
|
x = build_real (type, dconsthalf);
|
|
break;
|
|
CASE_CFN_CBRT:
|
|
/* Prepare to do logN(cbrt(x)) -> (1/3)*logN(x). */
|
|
x = build_real_truncate (type, dconst_third ());
|
|
break;
|
|
default:
|
|
gcc_unreachable ();
|
|
}
|
|
}
|
|
(mult { x; } (logs @0))))))
|
|
|
|
/* logN(pow(x,exponent)) -> exponent*logN(x). */
|
|
(for logs (LOG LOG2 LOG10)
|
|
pows (POW)
|
|
(simplify
|
|
(logs (pows @0 @1))
|
|
(mult @1 (logs @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))
|
|
/* 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, TREE_TYPE (@0))
|
|
&& 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)
|
|
pows (POW)
|
|
exps (EXP EXP2 EXP10 POW10)
|
|
/* sqrt(expN(x)) -> expN(x*0.5). */
|
|
(simplify
|
|
(sqrts (exps @0))
|
|
(exps (mult @0 { build_real (type, dconsthalf); })))
|
|
/* cbrt(expN(x)) -> expN(x/3). */
|
|
(simplify
|
|
(cbrts (exps @0))
|
|
(exps (mult @0 { build_real_truncate (type, dconst_third ()); })))
|
|
/* pow(expN(x), y) -> expN(x*y). */
|
|
(simplify
|
|
(pows (exps @0) @1)
|
|
(exps (mult @0 @1))))
|
|
|
|
/* tan(atan(x)) -> x. */
|
|
(for tans (TAN)
|
|
atans (ATAN)
|
|
(simplify
|
|
(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_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_ALL FLOOR_ALL CEIL_ALL ROUND_ALL NEARBYINT_ALL RINT_ALL)
|
|
(simplify
|
|
(fns integer_valued_real_p@0)
|
|
@0))
|
|
|
|
/* hypot(x,0) and hypot(0,x) -> abs(x). */
|
|
(simplify
|
|
(HYPOT:c @0 real_zerop@1)
|
|
(abs @0))
|
|
|
|
/* pow(1,x) -> 1. */
|
|
(simplify
|
|
(POW real_onep@0 @1)
|
|
@0)
|
|
|
|
(simplify
|
|
/* copysign(x,x) -> x. */
|
|
(COPYSIGN_ALL @0 @0)
|
|
@0)
|
|
|
|
(simplify
|
|
/* copysign(x,-x) -> -x. */
|
|
(COPYSIGN_ALL @0 (negate@1 @0))
|
|
@1)
|
|
|
|
(simplify
|
|
/* copysign(x,y) -> fabs(x) if y is nonnegative. */
|
|
(COPYSIGN_ALL @0 tree_expr_nonnegative_p@1)
|
|
(abs @0))
|
|
|
|
(for scale (LDEXP SCALBN SCALBLN)
|
|
/* ldexp(0, x) -> 0. */
|
|
(simplify
|
|
(scale real_zerop@0 @1)
|
|
@0)
|
|
/* ldexp(x, 0) -> x. */
|
|
(simplify
|
|
(scale @0 integer_zerop@1)
|
|
@0)
|
|
/* ldexp(x, y) -> x if x is +-Inf or NaN. */
|
|
(simplify
|
|
(scale REAL_CST@0 @1)
|
|
(if (!real_isfinite (TREE_REAL_CST_PTR (@0)))
|
|
@0)))
|
|
|
|
/* Canonicalization of sequences of math builtins. These rules represent
|
|
IL simplifications but are not necessarily optimizations.
|
|
|
|
The sincos pass is responsible for picking "optimal" implementations
|
|
of math builtins, which may be more complicated and can sometimes go
|
|
the other way, e.g. converting pow into a sequence of sqrts.
|
|
We only want to do these canonicalizations before the pass has run. */
|
|
|
|
(if (flag_unsafe_math_optimizations && canonicalize_math_p ())
|
|
/* Simplify tan(x) * cos(x) -> sin(x). */
|
|
(simplify
|
|
(mult:c (TAN:s @0) (COS:s @0))
|
|
(SIN @0))
|
|
|
|
/* Simplify x * pow(x,c) -> pow(x,c+1). */
|
|
(simplify
|
|
(mult:c @0 (POW:s @0 REAL_CST@1))
|
|
(if (!TREE_OVERFLOW (@1))
|
|
(POW @0 (plus @1 { build_one_cst (type); }))))
|
|
|
|
/* Simplify sin(x) / cos(x) -> tan(x). */
|
|
(simplify
|
|
(rdiv (SIN:s @0) (COS:s @0))
|
|
(TAN @0))
|
|
|
|
/* Simplify sinh(x) / cosh(x) -> tanh(x). */
|
|
(simplify
|
|
(rdiv (SINH:s @0) (COSH:s @0))
|
|
(TANH @0))
|
|
|
|
/* Simplify tanh (x) / sinh (x) -> 1.0 / cosh (x). */
|
|
(simplify
|
|
(rdiv (TANH:s @0) (SINH:s @0))
|
|
(rdiv {build_one_cst (type);} (COSH @0)))
|
|
|
|
/* Simplify cos(x) / sin(x) -> 1 / tan(x). */
|
|
(simplify
|
|
(rdiv (COS:s @0) (SIN:s @0))
|
|
(rdiv { build_one_cst (type); } (TAN @0)))
|
|
|
|
/* Simplify sin(x) / tan(x) -> cos(x). */
|
|
(simplify
|
|
(rdiv (SIN:s @0) (TAN:s @0))
|
|
(if (! HONOR_NANS (@0)
|
|
&& ! HONOR_INFINITIES (@0))
|
|
(COS @0)))
|
|
|
|
/* Simplify tan(x) / sin(x) -> 1.0 / cos(x). */
|
|
(simplify
|
|
(rdiv (TAN:s @0) (SIN:s @0))
|
|
(if (! HONOR_NANS (@0)
|
|
&& ! HONOR_INFINITIES (@0))
|
|
(rdiv { build_one_cst (type); } (COS @0))))
|
|
|
|
/* Simplify pow(x,y) * pow(x,z) -> pow(x,y+z). */
|
|
(simplify
|
|
(mult (POW:s @0 @1) (POW:s @0 @2))
|
|
(POW @0 (plus @1 @2)))
|
|
|
|
/* Simplify pow(x,y) * pow(z,y) -> pow(x*z,y). */
|
|
(simplify
|
|
(mult (POW:s @0 @1) (POW:s @2 @1))
|
|
(POW (mult @0 @2) @1))
|
|
|
|
/* Simplify powi(x,y) * powi(z,y) -> powi(x*z,y). */
|
|
(simplify
|
|
(mult (POWI:s @0 @1) (POWI:s @2 @1))
|
|
(POWI (mult @0 @2) @1))
|
|
|
|
/* Simplify pow(x,c) / x -> pow(x,c-1). */
|
|
(simplify
|
|
(rdiv (POW:s @0 REAL_CST@1) @0)
|
|
(if (!TREE_OVERFLOW (@1))
|
|
(POW @0 (minus @1 { build_one_cst (type); }))))
|
|
|
|
/* Simplify x / pow (y,z) -> x * pow(y,-z). */
|
|
(simplify
|
|
(rdiv @0 (POW:s @1 @2))
|
|
(mult @0 (POW @1 (negate @2))))
|
|
|
|
(for sqrts (SQRT)
|
|
cbrts (CBRT)
|
|
pows (POW)
|
|
/* sqrt(sqrt(x)) -> pow(x,1/4). */
|
|
(simplify
|
|
(sqrts (sqrts @0))
|
|
(pows @0 { build_real (type, dconst_quarter ()); }))
|
|
/* sqrt(cbrt(x)) -> pow(x,1/6). */
|
|
(simplify
|
|
(sqrts (cbrts @0))
|
|
(pows @0 { build_real_truncate (type, dconst_sixth ()); }))
|
|
/* cbrt(sqrt(x)) -> pow(x,1/6). */
|
|
(simplify
|
|
(cbrts (sqrts @0))
|
|
(pows @0 { build_real_truncate (type, dconst_sixth ()); }))
|
|
/* cbrt(cbrt(x)) -> pow(x,1/9), iff x is nonnegative. */
|
|
(simplify
|
|
(cbrts (cbrts tree_expr_nonnegative_p@0))
|
|
(pows @0 { build_real_truncate (type, dconst_ninth ()); }))
|
|
/* sqrt(pow(x,y)) -> pow(|x|,y*0.5). */
|
|
(simplify
|
|
(sqrts (pows @0 @1))
|
|
(pows (abs @0) (mult @1 { build_real (type, dconsthalf); })))
|
|
/* cbrt(pow(x,y)) -> pow(x,y/3), iff x is nonnegative. */
|
|
(simplify
|
|
(cbrts (pows tree_expr_nonnegative_p@0 @1))
|
|
(pows @0 (mult @1 { build_real_truncate (type, dconst_third ()); })))
|
|
/* pow(sqrt(x),y) -> pow(x,y*0.5). */
|
|
(simplify
|
|
(pows (sqrts @0) @1)
|
|
(pows @0 (mult @1 { build_real (type, dconsthalf); })))
|
|
/* pow(cbrt(x),y) -> pow(x,y/3) iff x is nonnegative. */
|
|
(simplify
|
|
(pows (cbrts tree_expr_nonnegative_p@0) @1)
|
|
(pows @0 (mult @1 { build_real_truncate (type, dconst_third ()); })))
|
|
/* pow(pow(x,y),z) -> pow(x,y*z) iff x is nonnegative. */
|
|
(simplify
|
|
(pows (pows tree_expr_nonnegative_p@0 @1) @2)
|
|
(pows @0 (mult @1 @2))))
|
|
|
|
/* cabs(x+xi) -> fabs(x)*sqrt(2). */
|
|
(simplify
|
|
(CABS (complex @0 @0))
|
|
(mult (abs @0) { build_real_truncate (type, dconst_sqrt2 ()); }))
|
|
|
|
/* hypot(x,x) -> fabs(x)*sqrt(2). */
|
|
(simplify
|
|
(HYPOT @0 @0)
|
|
(mult (abs @0) { build_real_truncate (type, dconst_sqrt2 ()); }))
|
|
|
|
/* cexp(x+yi) -> exp(x)*cexpi(y). */
|
|
(for cexps (CEXP)
|
|
exps (EXP)
|
|
cexpis (CEXPI)
|
|
(simplify
|
|
(cexps compositional_complex@0)
|
|
(if (targetm.libc_has_function (function_c99_math_complex, TREE_TYPE (@0)))
|
|
(complex
|
|
(mult (exps@1 (realpart @0)) (realpart (cexpis:type@2 (imagpart @0))))
|
|
(mult @1 (imagpart @2)))))))
|
|
|
|
(if (canonicalize_math_p ())
|
|
/* floor(x) -> trunc(x) if x is nonnegative. */
|
|
(for floors (FLOOR_ALL)
|
|
truncs (TRUNC_ALL)
|
|
(simplify
|
|
(floors tree_expr_nonnegative_p@0)
|
|
(truncs @0))))
|
|
|
|
(match double_value_p
|
|
@0
|
|
(if (TYPE_MAIN_VARIANT (TREE_TYPE (@0)) == double_type_node)))
|
|
(for froms (BUILT_IN_TRUNCL
|
|
BUILT_IN_FLOORL
|
|
BUILT_IN_CEILL
|
|
BUILT_IN_ROUNDL
|
|
BUILT_IN_NEARBYINTL
|
|
BUILT_IN_RINTL)
|
|
tos (BUILT_IN_TRUNC
|
|
BUILT_IN_FLOOR
|
|
BUILT_IN_CEIL
|
|
BUILT_IN_ROUND
|
|
BUILT_IN_NEARBYINT
|
|
BUILT_IN_RINT)
|
|
/* truncl(extend(x)) -> extend(trunc(x)), etc., if x is a double. */
|
|
(if (optimize && canonicalize_math_p ())
|
|
(simplify
|
|
(froms (convert double_value_p@0))
|
|
(convert (tos @0)))))
|
|
|
|
(match float_value_p
|
|
@0
|
|
(if (TYPE_MAIN_VARIANT (TREE_TYPE (@0)) == float_type_node)))
|
|
(for froms (BUILT_IN_TRUNCL BUILT_IN_TRUNC
|
|
BUILT_IN_FLOORL BUILT_IN_FLOOR
|
|
BUILT_IN_CEILL BUILT_IN_CEIL
|
|
BUILT_IN_ROUNDL BUILT_IN_ROUND
|
|
BUILT_IN_NEARBYINTL BUILT_IN_NEARBYINT
|
|
BUILT_IN_RINTL BUILT_IN_RINT)
|
|
tos (BUILT_IN_TRUNCF BUILT_IN_TRUNCF
|
|
BUILT_IN_FLOORF BUILT_IN_FLOORF
|
|
BUILT_IN_CEILF BUILT_IN_CEILF
|
|
BUILT_IN_ROUNDF BUILT_IN_ROUNDF
|
|
BUILT_IN_NEARBYINTF BUILT_IN_NEARBYINTF
|
|
BUILT_IN_RINTF BUILT_IN_RINTF)
|
|
/* truncl(extend(x)) and trunc(extend(x)) -> extend(truncf(x)), etc.,
|
|
if x is a float. */
|
|
(if (optimize && canonicalize_math_p ()
|
|
&& targetm.libc_has_function (function_c99_misc, NULL_TREE))
|
|
(simplify
|
|
(froms (convert float_value_p@0))
|
|
(convert (tos @0)))))
|
|
|
|
#if GIMPLE
|
|
(match float16_value_p
|
|
@0
|
|
(if (TYPE_MAIN_VARIANT (TREE_TYPE (@0)) == float16_type_node)))
|
|
(for froms (BUILT_IN_TRUNCL BUILT_IN_TRUNC BUILT_IN_TRUNCF
|
|
BUILT_IN_FLOORL BUILT_IN_FLOOR BUILT_IN_FLOORF
|
|
BUILT_IN_CEILL BUILT_IN_CEIL BUILT_IN_CEILF
|
|
BUILT_IN_ROUNDEVENL BUILT_IN_ROUNDEVEN BUILT_IN_ROUNDEVENF
|
|
BUILT_IN_ROUNDL BUILT_IN_ROUND BUILT_IN_ROUNDF
|
|
BUILT_IN_NEARBYINTL BUILT_IN_NEARBYINT BUILT_IN_NEARBYINTF
|
|
BUILT_IN_RINTL BUILT_IN_RINT BUILT_IN_RINTF
|
|
BUILT_IN_SQRTL BUILT_IN_SQRT BUILT_IN_SQRTF)
|
|
tos (IFN_TRUNC IFN_TRUNC IFN_TRUNC
|
|
IFN_FLOOR IFN_FLOOR IFN_FLOOR
|
|
IFN_CEIL IFN_CEIL IFN_CEIL
|
|
IFN_ROUNDEVEN IFN_ROUNDEVEN IFN_ROUNDEVEN
|
|
IFN_ROUND IFN_ROUND IFN_ROUND
|
|
IFN_NEARBYINT IFN_NEARBYINT IFN_NEARBYINT
|
|
IFN_RINT IFN_RINT IFN_RINT
|
|
IFN_SQRT IFN_SQRT IFN_SQRT)
|
|
/* (_Float16) round ((doube) x) -> __built_in_roundf16 (x), etc.,
|
|
if x is a _Float16. */
|
|
(simplify
|
|
(convert (froms (convert float16_value_p@0)))
|
|
(if (optimize
|
|
&& types_match (type, TREE_TYPE (@0))
|
|
&& direct_internal_fn_supported_p (as_internal_fn (tos),
|
|
type, OPTIMIZE_FOR_BOTH))
|
|
(tos @0))))
|
|
|
|
/* Simplify (trunc)copysign ((extend)x, (extend)y) to copysignf (x, y),
|
|
x,y is float value, similar for _Float16/double. */
|
|
(for copysigns (COPYSIGN_ALL)
|
|
(simplify
|
|
(convert (copysigns (convert@2 @0) (convert @1)))
|
|
(if (optimize
|
|
&& !HONOR_SNANS (@2)
|
|
&& types_match (type, TREE_TYPE (@0))
|
|
&& types_match (type, TREE_TYPE (@1))
|
|
&& TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (@2))
|
|
&& direct_internal_fn_supported_p (IFN_COPYSIGN,
|
|
type, OPTIMIZE_FOR_BOTH))
|
|
(IFN_COPYSIGN @0 @1))))
|
|
|
|
(for froms (BUILT_IN_FMAF BUILT_IN_FMA BUILT_IN_FMAL)
|
|
tos (IFN_FMA IFN_FMA IFN_FMA)
|
|
(simplify
|
|
(convert (froms (convert@3 @0) (convert @1) (convert @2)))
|
|
(if (flag_unsafe_math_optimizations
|
|
&& optimize
|
|
&& FLOAT_TYPE_P (type)
|
|
&& FLOAT_TYPE_P (TREE_TYPE (@3))
|
|
&& types_match (type, TREE_TYPE (@0))
|
|
&& types_match (type, TREE_TYPE (@1))
|
|
&& types_match (type, TREE_TYPE (@2))
|
|
&& TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (@3))
|
|
&& direct_internal_fn_supported_p (as_internal_fn (tos),
|
|
type, OPTIMIZE_FOR_BOTH))
|
|
(tos @0 @1 @2))))
|
|
|
|
(for maxmin (max min)
|
|
(simplify
|
|
(convert (maxmin (convert@2 @0) (convert @1)))
|
|
(if (optimize
|
|
&& FLOAT_TYPE_P (type)
|
|
&& FLOAT_TYPE_P (TREE_TYPE (@2))
|
|
&& types_match (type, TREE_TYPE (@0))
|
|
&& types_match (type, TREE_TYPE (@1))
|
|
&& element_precision (type) < element_precision (TREE_TYPE (@2)))
|
|
(maxmin @0 @1))))
|
|
#endif
|
|
|
|
(for froms (XFLOORL XCEILL XROUNDL XRINTL)
|
|
tos (XFLOOR XCEIL XROUND XRINT)
|
|
/* llfloorl(extend(x)) -> llfloor(x), etc., if x is a double. */
|
|
(if (optimize && canonicalize_math_p ())
|
|
(simplify
|
|
(froms (convert double_value_p@0))
|
|
(tos @0))))
|
|
|
|
(for froms (XFLOORL XCEILL XROUNDL XRINTL
|
|
XFLOOR XCEIL XROUND XRINT)
|
|
tos (XFLOORF XCEILF XROUNDF XRINTF)
|
|
/* llfloorl(extend(x)) and llfloor(extend(x)) -> llfloorf(x), etc.,
|
|
if x is a float. */
|
|
(if (optimize && canonicalize_math_p ())
|
|
(simplify
|
|
(froms (convert float_value_p@0))
|
|
(tos @0))))
|
|
|
|
(if (canonicalize_math_p ())
|
|
/* xfloor(x) -> fix_trunc(x) if x is nonnegative. */
|
|
(for floors (IFLOOR LFLOOR LLFLOOR)
|
|
(simplify
|
|
(floors tree_expr_nonnegative_p@0)
|
|
(fix_trunc @0))))
|
|
|
|
(if (canonicalize_math_p ())
|
|
/* xfloor(x) -> fix_trunc(x), etc., if x is integer valued. */
|
|
(for fns (IFLOOR LFLOOR LLFLOOR
|
|
ICEIL LCEIL LLCEIL
|
|
IROUND LROUND LLROUND)
|
|
(simplify
|
|
(fns integer_valued_real_p@0)
|
|
(fix_trunc @0)))
|
|
(if (!flag_errno_math)
|
|
/* xrint(x) -> fix_trunc(x), etc., if x is integer valued. */
|
|
(for rints (IRINT LRINT LLRINT)
|
|
(simplify
|
|
(rints integer_valued_real_p@0)
|
|
(fix_trunc @0)))))
|
|
|
|
(if (canonicalize_math_p ())
|
|
(for ifn (IFLOOR ICEIL IROUND IRINT)
|
|
lfn (LFLOOR LCEIL LROUND LRINT)
|
|
llfn (LLFLOOR LLCEIL LLROUND LLRINT)
|
|
/* Canonicalize iround (x) to lround (x) on ILP32 targets where
|
|
sizeof (int) == sizeof (long). */
|
|
(if (TYPE_PRECISION (integer_type_node)
|
|
== TYPE_PRECISION (long_integer_type_node))
|
|
(simplify
|
|
(ifn @0)
|
|
(lfn:long_integer_type_node @0)))
|
|
/* Canonicalize llround (x) to lround (x) on LP64 targets where
|
|
sizeof (long long) == sizeof (long). */
|
|
(if (TYPE_PRECISION (long_long_integer_type_node)
|
|
== TYPE_PRECISION (long_integer_type_node))
|
|
(simplify
|
|
(llfn @0)
|
|
(lfn:long_integer_type_node @0)))))
|
|
|
|
/* cproj(x) -> x if we're ignoring infinities. */
|
|
(simplify
|
|
(CPROJ @0)
|
|
(if (!HONOR_INFINITIES (type))
|
|
@0))
|
|
|
|
/* If the real part is inf and the imag part is known to be
|
|
nonnegative, return (inf + 0i). */
|
|
(simplify
|
|
(CPROJ (complex REAL_CST@0 tree_expr_nonnegative_p@1))
|
|
(if (real_isinf (TREE_REAL_CST_PTR (@0)))
|
|
{ build_complex_inf (type, false); }))
|
|
|
|
/* If the imag part is inf, return (inf+I*copysign(0,imag)). */
|
|
(simplify
|
|
(CPROJ (complex @0 REAL_CST@1))
|
|
(if (real_isinf (TREE_REAL_CST_PTR (@1)))
|
|
{ build_complex_inf (type, TREE_REAL_CST_PTR (@1)->sign); }))
|
|
|
|
(for pows (POW)
|
|
sqrts (SQRT)
|
|
cbrts (CBRT)
|
|
(simplify
|
|
(pows @0 REAL_CST@1)
|
|
(with {
|
|
const REAL_VALUE_TYPE *value = TREE_REAL_CST_PTR (@1);
|
|
REAL_VALUE_TYPE tmp;
|
|
}
|
|
(switch
|
|
/* pow(x,0) -> 1. */
|
|
(if (real_equal (value, &dconst0))
|
|
{ build_real (type, dconst1); })
|
|
/* pow(x,1) -> x. */
|
|
(if (real_equal (value, &dconst1))
|
|
@0)
|
|
/* pow(x,-1) -> 1/x. */
|
|
(if (real_equal (value, &dconstm1))
|
|
(rdiv { build_real (type, dconst1); } @0))
|
|
/* pow(x,0.5) -> sqrt(x). */
|
|
(if (flag_unsafe_math_optimizations
|
|
&& canonicalize_math_p ()
|
|
&& real_equal (value, &dconsthalf))
|
|
(sqrts @0))
|
|
/* pow(x,1/3) -> cbrt(x). */
|
|
(if (flag_unsafe_math_optimizations
|
|
&& canonicalize_math_p ()
|
|
&& (tmp = real_value_truncate (TYPE_MODE (type), dconst_third ()),
|
|
real_equal (value, &tmp)))
|
|
(cbrts @0))))))
|
|
|
|
/* powi(1,x) -> 1. */
|
|
(simplify
|
|
(POWI real_onep@0 @1)
|
|
@0)
|
|
|
|
(simplify
|
|
(POWI @0 INTEGER_CST@1)
|
|
(switch
|
|
/* powi(x,0) -> 1. */
|
|
(if (wi::to_wide (@1) == 0)
|
|
{ build_real (type, dconst1); })
|
|
/* powi(x,1) -> x. */
|
|
(if (wi::to_wide (@1) == 1)
|
|
@0)
|
|
/* powi(x,-1) -> 1/x. */
|
|
(if (wi::to_wide (@1) == -1)
|
|
(rdiv { build_real (type, dconst1); } @0))))
|
|
|
|
/* 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
|
|
term we want to move all that code out of the front-ends into here. */
|
|
|
|
/* Convert (outertype)((innertype0)a+(innertype1)b)
|
|
into ((newtype)a+(newtype)b) where newtype
|
|
is the widest mode from all of these. */
|
|
(for op (plus minus mult rdiv)
|
|
(simplify
|
|
(convert (op:s@0 (convert1?@3 @1) (convert2?@4 @2)))
|
|
/* If we have a narrowing conversion of an arithmetic operation where
|
|
both operands are widening conversions from the same type as the outer
|
|
narrowing conversion. Then convert the innermost operands to a
|
|
suitable unsigned type (to avoid introducing undefined behavior),
|
|
perform the operation and convert the result to the desired type. */
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& op != MULT_EXPR
|
|
&& op != RDIV_EXPR
|
|
/* We check for type compatibility between @0 and @1 below,
|
|
so there's no need to check that @2/@4 are integral types. */
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@1))
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@3))
|
|
/* The precision of the type of each operand must match the
|
|
precision of the mode of each operand, similarly for the
|
|
result. */
|
|
&& type_has_mode_precision_p (TREE_TYPE (@1))
|
|
&& type_has_mode_precision_p (TREE_TYPE (@2))
|
|
&& type_has_mode_precision_p (type)
|
|
/* The inner conversion must be a widening conversion. */
|
|
&& TYPE_PRECISION (TREE_TYPE (@3)) > TYPE_PRECISION (TREE_TYPE (@1))
|
|
&& types_match (@1, type)
|
|
&& (types_match (@1, @2)
|
|
/* Or the second operand is const integer or converted const
|
|
integer from valueize. */
|
|
|| poly_int_tree_p (@4)))
|
|
(if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@1)))
|
|
(op @1 (convert @2))
|
|
(with { tree utype = unsigned_type_for (TREE_TYPE (@1)); }
|
|
(convert (op (convert:utype @1)
|
|
(convert:utype @2)))))
|
|
(if (FLOAT_TYPE_P (type)
|
|
&& DECIMAL_FLOAT_TYPE_P (TREE_TYPE (@0))
|
|
== DECIMAL_FLOAT_TYPE_P (type))
|
|
(with { tree arg0 = strip_float_extensions (@1);
|
|
tree arg1 = strip_float_extensions (@2);
|
|
tree itype = TREE_TYPE (@0);
|
|
tree ty1 = TREE_TYPE (arg0);
|
|
tree ty2 = TREE_TYPE (arg1);
|
|
enum tree_code code = TREE_CODE (itype); }
|
|
(if (FLOAT_TYPE_P (ty1)
|
|
&& FLOAT_TYPE_P (ty2))
|
|
(with { tree newtype = type;
|
|
if (TYPE_MODE (ty1) == SDmode
|
|
|| TYPE_MODE (ty2) == SDmode
|
|
|| TYPE_MODE (type) == SDmode)
|
|
newtype = dfloat32_type_node;
|
|
if (TYPE_MODE (ty1) == DDmode
|
|
|| TYPE_MODE (ty2) == DDmode
|
|
|| TYPE_MODE (type) == DDmode)
|
|
newtype = dfloat64_type_node;
|
|
if (TYPE_MODE (ty1) == TDmode
|
|
|| TYPE_MODE (ty2) == TDmode
|
|
|| TYPE_MODE (type) == TDmode)
|
|
newtype = dfloat128_type_node; }
|
|
(if ((newtype == dfloat32_type_node
|
|
|| newtype == dfloat64_type_node
|
|
|| newtype == dfloat128_type_node)
|
|
&& newtype == type
|
|
&& types_match (newtype, type))
|
|
(op (convert:newtype @1) (convert:newtype @2))
|
|
(with { if (TYPE_PRECISION (ty1) > TYPE_PRECISION (newtype))
|
|
newtype = ty1;
|
|
if (TYPE_PRECISION (ty2) > TYPE_PRECISION (newtype))
|
|
newtype = ty2; }
|
|
/* Sometimes this transformation is safe (cannot
|
|
change results through affecting double rounding
|
|
cases) and sometimes it is not. If NEWTYPE is
|
|
wider than TYPE, e.g. (float)((long double)double
|
|
+ (long double)double) converted to
|
|
(float)(double + double), the transformation is
|
|
unsafe regardless of the details of the types
|
|
involved; double rounding can arise if the result
|
|
of NEWTYPE arithmetic is a NEWTYPE value half way
|
|
between two representable TYPE values but the
|
|
exact value is sufficiently different (in the
|
|
right direction) for this difference to be
|
|
visible in ITYPE arithmetic. If NEWTYPE is the
|
|
same as TYPE, however, the transformation may be
|
|
safe depending on the types involved: it is safe
|
|
if the ITYPE has strictly more than twice as many
|
|
mantissa bits as TYPE, can represent infinities
|
|
and NaNs if the TYPE can, and has sufficient
|
|
exponent range for the product or ratio of two
|
|
values representable in the TYPE to be within the
|
|
range of normal values of ITYPE. */
|
|
(if (TYPE_PRECISION (newtype) < TYPE_PRECISION (itype)
|
|
&& (flag_unsafe_math_optimizations
|
|
|| (TYPE_PRECISION (newtype) == TYPE_PRECISION (type)
|
|
&& real_can_shorten_arithmetic (TYPE_MODE (itype),
|
|
TYPE_MODE (type))
|
|
&& !excess_precision_type (newtype)))
|
|
&& !types_match (itype, newtype))
|
|
(convert:type (op (convert:newtype @1)
|
|
(convert:newtype @2)))
|
|
)))) )
|
|
))
|
|
)))
|
|
|
|
/* This is another case of narrowing, specifically when there's an outer
|
|
BIT_AND_EXPR which masks off bits outside the type of the innermost
|
|
operands. Like the previous case we have to convert the operands
|
|
to unsigned types to avoid introducing undefined behavior for the
|
|
arithmetic operation. */
|
|
(for op (minus plus)
|
|
(simplify
|
|
(bit_and (op:s (convert@2 @0) (convert@3 @1)) INTEGER_CST@4)
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
/* We check for type compatibility between @0 and @1 below,
|
|
so there's no need to check that @1/@3 are integral types. */
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@2))
|
|
/* The precision of the type of each operand must match the
|
|
precision of the mode of each operand, similarly for the
|
|
result. */
|
|
&& type_has_mode_precision_p (TREE_TYPE (@0))
|
|
&& type_has_mode_precision_p (TREE_TYPE (@1))
|
|
&& type_has_mode_precision_p (type)
|
|
/* The inner conversion must be a widening conversion. */
|
|
&& TYPE_PRECISION (TREE_TYPE (@2)) > TYPE_PRECISION (TREE_TYPE (@0))
|
|
&& types_match (@0, @1)
|
|
&& (tree_int_cst_min_precision (@4, TYPE_SIGN (TREE_TYPE (@0)))
|
|
<= TYPE_PRECISION (TREE_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))))
|
|
(with { tree utype = unsigned_type_for (TREE_TYPE (@0)); }
|
|
(convert (bit_and (op (convert:utype @0) (convert:utype @1))
|
|
(convert:utype @4))))))))
|
|
|
|
/* Transform (@0 < @1 and @0 < @2) to use min,
|
|
(@0 > @1 and @0 > @2) to use 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
|
|
(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)))))
|
|
|
|
(simplify
|
|
/* signbit(x) -> 0 if x is nonnegative. */
|
|
(SIGNBIT tree_expr_nonnegative_p@0)
|
|
{ integer_zero_node; })
|
|
|
|
(simplify
|
|
/* signbit(x) -> x<0 if x doesn't have signed zeros. */
|
|
(SIGNBIT @0)
|
|
(if (!HONOR_SIGNED_ZEROS (@0))
|
|
(convert (lt @0 { build_real (TREE_TYPE (@0), dconst0); }))))
|
|
|
|
/* Transform comparisons of the form X +- C1 CMP C2 to X CMP C2 -+ C1. */
|
|
(for cmp (eq ne)
|
|
(for op (plus minus)
|
|
rop (minus plus)
|
|
(simplify
|
|
(cmp (op@3 @0 INTEGER_CST@1) INTEGER_CST@2)
|
|
(if (!TREE_OVERFLOW (@1) && !TREE_OVERFLOW (@2)
|
|
&& !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@0))
|
|
&& !TYPE_OVERFLOW_TRAPS (TREE_TYPE (@0))
|
|
&& !TYPE_SATURATING (TREE_TYPE (@0)))
|
|
(with { tree res = int_const_binop (rop, @2, @1); }
|
|
(if (TREE_OVERFLOW (res)
|
|
&& TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)))
|
|
{ constant_boolean_node (cmp == NE_EXPR, type); }
|
|
(if (single_use (@3))
|
|
(cmp @0 { TREE_OVERFLOW (res)
|
|
? drop_tree_overflow (res) : res; }))))))))
|
|
(for cmp (lt le gt ge)
|
|
(for op (plus minus)
|
|
rop (minus plus)
|
|
(simplify
|
|
(cmp (op@3 @0 INTEGER_CST@1) INTEGER_CST@2)
|
|
(if (!TREE_OVERFLOW (@1) && !TREE_OVERFLOW (@2)
|
|
&& TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)))
|
|
(with { tree res = int_const_binop (rop, @2, @1); }
|
|
(if (TREE_OVERFLOW (res))
|
|
{
|
|
fold_overflow_warning (("assuming signed overflow does not occur "
|
|
"when simplifying conditional to constant"),
|
|
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 (wi::to_wide (@1), 0,
|
|
TYPE_SIGN (TREE_TYPE (@1)))
|
|
!= (op == MINUS_EXPR);
|
|
constant_boolean_node (less == ovf_high, type);
|
|
}
|
|
(if (single_use (@3))
|
|
(with
|
|
{
|
|
fold_overflow_warning (("assuming signed overflow does not occur "
|
|
"when changing X +- C1 cmp C2 to "
|
|
"X cmp C2 -+ C1"),
|
|
WARN_STRICT_OVERFLOW_COMPARISON);
|
|
}
|
|
(cmp @0 { res; })))))))))
|
|
|
|
/* 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 (TREE_CODE (TREE_TYPE (@0)) == COMPLEX_TYPE
|
|
&& tree_int_cst_equal (@1, TYPE_SIZE (TREE_TYPE (TREE_TYPE (@0)))))
|
|
(switch
|
|
(if (integer_zerop (@2))
|
|
(view_convert (realpart @0)))
|
|
(if (tree_int_cst_equal (@2, TYPE_SIZE (TREE_TYPE (TREE_TYPE (@0)))))
|
|
(view_convert (imagpart @0)))))
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& INTEGRAL_TYPE_P (type)
|
|
/* On GIMPLE this should only apply to register arguments. */
|
|
&& (! GIMPLE || is_gimple_reg (@0))
|
|
/* A bit-field-ref that referenced the full argument can be stripped. */
|
|
&& ((compare_tree_int (@1, TYPE_PRECISION (TREE_TYPE (@0))) == 0
|
|
&& integer_zerop (@2))
|
|
/* Low-parts can be reduced to integral conversions.
|
|
??? The following doesn't work for PDP endian. */
|
|
|| (BYTES_BIG_ENDIAN == WORDS_BIG_ENDIAN
|
|
/* But only do this after vectorization. */
|
|
&& canonicalize_math_after_vectorization_p ()
|
|
/* Don't even think about BITS_BIG_ENDIAN. */
|
|
&& TYPE_PRECISION (TREE_TYPE (@0)) % BITS_PER_UNIT == 0
|
|
&& TYPE_PRECISION (type) % BITS_PER_UNIT == 0
|
|
&& compare_tree_int (@2, (BYTES_BIG_ENDIAN
|
|
? (TYPE_PRECISION (TREE_TYPE (@0))
|
|
- TYPE_PRECISION (type))
|
|
: 0)) == 0)))
|
|
(convert @0))))
|
|
|
|
/* Simplify vector extracts. */
|
|
|
|
(simplify
|
|
(BIT_FIELD_REF CONSTRUCTOR@0 @1 @2)
|
|
(if (VECTOR_TYPE_P (TREE_TYPE (@0))
|
|
&& tree_fits_uhwi_p (TYPE_SIZE (type))
|
|
&& ((tree_to_uhwi (TYPE_SIZE (type))
|
|
== tree_to_uhwi (TYPE_SIZE (TREE_TYPE (TREE_TYPE (@0)))))
|
|
|| (VECTOR_TYPE_P (type)
|
|
&& (tree_to_uhwi (TYPE_SIZE (TREE_TYPE (type)))
|
|
== tree_to_uhwi (TYPE_SIZE (TREE_TYPE (TREE_TYPE (@0))))))))
|
|
(with
|
|
{
|
|
tree ctor = (TREE_CODE (@0) == SSA_NAME
|
|
? gimple_assign_rhs1 (SSA_NAME_DEF_STMT (@0)) : @0);
|
|
tree eltype = TREE_TYPE (TREE_TYPE (ctor));
|
|
unsigned HOST_WIDE_INT width = tree_to_uhwi (TYPE_SIZE (eltype));
|
|
unsigned HOST_WIDE_INT n = tree_to_uhwi (@1);
|
|
unsigned HOST_WIDE_INT idx = tree_to_uhwi (@2);
|
|
}
|
|
(if (n != 0
|
|
&& (idx % width) == 0
|
|
&& (n % width) == 0
|
|
&& known_le ((idx + n) / width,
|
|
TYPE_VECTOR_SUBPARTS (TREE_TYPE (ctor))))
|
|
(with
|
|
{
|
|
idx = idx / width;
|
|
n = n / width;
|
|
/* Constructor elements can be subvectors. */
|
|
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 (multiple_p (idx, k, &elt) && multiple_p (n, k, &count))
|
|
(if (CONSTRUCTOR_NELTS (ctor) == 0)
|
|
{ build_zero_cst (type); }
|
|
(if (count == 1)
|
|
(if (elt < CONSTRUCTOR_NELTS (ctor))
|
|
(view_convert { CONSTRUCTOR_ELT (ctor, elt)->value; })
|
|
{ build_zero_cst (type); })
|
|
/* We don't want to emit new CTORs unless the old one goes away.
|
|
??? Eventually allow this if the CTOR ends up constant or
|
|
uniform. */
|
|
(if (single_use (@0))
|
|
(with
|
|
{
|
|
vec<constructor_elt, va_gc> *vals;
|
|
vec_alloc (vals, count);
|
|
bool constant_p = true;
|
|
tree res;
|
|
for (unsigned i = 0;
|
|
i < count && elt + i < CONSTRUCTOR_NELTS (ctor); ++i)
|
|
{
|
|
tree e = CONSTRUCTOR_ELT (ctor, elt + i)->value;
|
|
CONSTRUCTOR_APPEND_ELT (vals, NULL_TREE, e);
|
|
if (!CONSTANT_CLASS_P (e))
|
|
constant_p = false;
|
|
}
|
|
tree evtype = (types_match (TREE_TYPE (type),
|
|
TREE_TYPE (TREE_TYPE (ctor)))
|
|
? type
|
|
: build_vector_type (TREE_TYPE (TREE_TYPE (ctor)),
|
|
count * k));
|
|
res = (constant_p ? build_vector_from_ctor (evtype, vals)
|
|
: build_constructor (evtype, vals));
|
|
}
|
|
(view_convert { res; }))))))
|
|
/* The bitfield references a single constructor element. */
|
|
(if (k.is_constant (&const_k)
|
|
&& idx + n <= (idx / const_k + 1) * const_k)
|
|
(switch
|
|
(if (CONSTRUCTOR_NELTS (ctor) <= idx / const_k)
|
|
{ build_zero_cst (type); })
|
|
(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
|
|
not touching the extraction. */
|
|
(simplify
|
|
(BIT_FIELD_REF (bit_insert @0 @1 @ipos) @rsize @rpos)
|
|
(with
|
|
{
|
|
unsigned HOST_WIDE_INT isize;
|
|
if (INTEGRAL_TYPE_P (TREE_TYPE (@1)))
|
|
isize = TYPE_PRECISION (TREE_TYPE (@1));
|
|
else
|
|
isize = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (@1)));
|
|
}
|
|
(switch
|
|
(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::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))))
|
|
|
|
/* CLZ simplifications. */
|
|
(for clz (CLZ)
|
|
(for op (eq ne)
|
|
cmp (lt ge)
|
|
(simplify
|
|
(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); })))
|
|
/* 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); })))))))
|
|
|
|
/* CTZ simplifications. */
|
|
(for ctz (CTZ)
|
|
(for op (ge gt le lt)
|
|
cmp (eq eq ne ne)
|
|
(simplify
|
|
/* __builtin_ctz (x) >= C -> (x & ((1 << C) - 1)) == 0. */
|
|
(op (ctz:s @0) 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++;
|
|
}
|
|
}
|
|
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))
|
|
(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 (ctz:s @0) INTEGER_CST@1)
|
|
(with { 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 (tree_int_cst_sgn (@1) < 0 || wi::to_widest (@1) >= prec)
|
|
(if (!zero_res || zero_val != wi::to_widest (@1))
|
|
{ constant_boolean_node (op == EQ_EXPR ? false : true, type); })
|
|
(if (!zero_res || zero_val < 0 || zero_val >= prec)
|
|
(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)); })))))))
|
|
|
|
/* 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 (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 popcount (POPCOUNT)
|
|
(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)); }))))
|
|
|
|
/* Canonicalize POPCOUNT(x)&1 as PARITY(X). */
|
|
(simplify
|
|
(bit_and (POPCOUNT @0) integer_onep)
|
|
(PARITY @0))
|
|
|
|
/* PARITY simplifications. */
|
|
/* parity(~X) is parity(X). */
|
|
(simplify
|
|
(PARITY (bit_not @0))
|
|
(PARITY @0))
|
|
|
|
/* parity(X)^parity(Y) is parity(X^Y). */
|
|
(simplify
|
|
(bit_xor (PARITY:s @0) (PARITY:s @1))
|
|
(PARITY (bit_xor @0 @1)))
|
|
|
|
/* Common POPCOUNT/PARITY simplifications. */
|
|
/* popcount(X&C1) is (X>>C2)&1 when C1 == 1<<C2. Same for parity(X&C1). */
|
|
(for pfun (POPCOUNT PARITY)
|
|
(simplify
|
|
(pfun @0)
|
|
(with { wide_int nz = tree_nonzero_bits (@0); }
|
|
(switch
|
|
(if (nz == 1)
|
|
(convert @0))
|
|
(if (wi::popcount (nz) == 1)
|
|
(with { tree utype = unsigned_type_for (TREE_TYPE (@0)); }
|
|
(convert (rshift:utype (convert:utype @0)
|
|
{ build_int_cst (integer_type_node,
|
|
wi::ctz (nz)); }))))))))
|
|
|
|
#if GIMPLE
|
|
/* 64- and 32-bits branchless implementations of popcount are detected:
|
|
|
|
int popcount64c (uint64_t x)
|
|
{
|
|
x -= (x >> 1) & 0x5555555555555555ULL;
|
|
x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL);
|
|
x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
|
|
return (x * 0x0101010101010101ULL) >> 56;
|
|
}
|
|
|
|
int popcount32c (uint32_t x)
|
|
{
|
|
x -= (x >> 1) & 0x55555555;
|
|
x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
|
|
x = (x + (x >> 4)) & 0x0f0f0f0f;
|
|
return (x * 0x01010101) >> 24;
|
|
} */
|
|
(simplify
|
|
(rshift
|
|
(mult
|
|
(bit_and
|
|
(plus:c
|
|
(rshift @8 INTEGER_CST@5)
|
|
(plus:c@8
|
|
(bit_and @6 INTEGER_CST@7)
|
|
(bit_and
|
|
(rshift
|
|
(minus@6 @0
|
|
(bit_and (rshift @0 INTEGER_CST@4) INTEGER_CST@11))
|
|
INTEGER_CST@10)
|
|
INTEGER_CST@9)))
|
|
INTEGER_CST@3)
|
|
INTEGER_CST@2)
|
|
INTEGER_CST@1)
|
|
/* Check constants and optab. */
|
|
(with { unsigned prec = TYPE_PRECISION (type);
|
|
int shift = (64 - prec) & 63;
|
|
unsigned HOST_WIDE_INT c1
|
|
= HOST_WIDE_INT_UC (0x0101010101010101) >> shift;
|
|
unsigned HOST_WIDE_INT c2
|
|
= HOST_WIDE_INT_UC (0x0F0F0F0F0F0F0F0F) >> shift;
|
|
unsigned HOST_WIDE_INT c3
|
|
= HOST_WIDE_INT_UC (0x3333333333333333) >> shift;
|
|
unsigned HOST_WIDE_INT c4
|
|
= HOST_WIDE_INT_UC (0x5555555555555555) >> shift;
|
|
}
|
|
(if (prec >= 16
|
|
&& prec <= 64
|
|
&& pow2p_hwi (prec)
|
|
&& TYPE_UNSIGNED (type)
|
|
&& integer_onep (@4)
|
|
&& wi::to_widest (@10) == 2
|
|
&& wi::to_widest (@5) == 4
|
|
&& wi::to_widest (@1) == prec - 8
|
|
&& tree_to_uhwi (@2) == c1
|
|
&& tree_to_uhwi (@3) == c2
|
|
&& tree_to_uhwi (@9) == c3
|
|
&& tree_to_uhwi (@7) == c3
|
|
&& tree_to_uhwi (@11) == c4)
|
|
(if (direct_internal_fn_supported_p (IFN_POPCOUNT, type,
|
|
OPTIMIZE_FOR_BOTH))
|
|
(convert (IFN_POPCOUNT:type @0))
|
|
/* Try to do popcount in two halves. PREC must be at least
|
|
five bits for this to work without extension before adding. */
|
|
(with {
|
|
tree half_type = NULL_TREE;
|
|
opt_machine_mode m = mode_for_size ((prec + 1) / 2, MODE_INT, 1);
|
|
int half_prec = 8;
|
|
if (m.exists ()
|
|
&& m.require () != TYPE_MODE (type))
|
|
{
|
|
half_prec = GET_MODE_PRECISION (as_a <scalar_int_mode> (m));
|
|
half_type = build_nonstandard_integer_type (half_prec, 1);
|
|
}
|
|
gcc_assert (half_prec > 2);
|
|
}
|
|
(if (half_type != NULL_TREE
|
|
&& direct_internal_fn_supported_p (IFN_POPCOUNT, half_type,
|
|
OPTIMIZE_FOR_BOTH))
|
|
(convert (plus
|
|
(IFN_POPCOUNT:half_type (convert @0))
|
|
(IFN_POPCOUNT:half_type (convert (rshift @0
|
|
{ build_int_cst (integer_type_node, half_prec); } )))))))))))
|
|
|
|
/* __builtin_ffs needs to deal on many targets with the possible zero
|
|
argument. If we know the argument is always non-zero, __builtin_ctz + 1
|
|
should lead to better code. */
|
|
(simplify
|
|
(FFS tree_expr_nonzero_p@0)
|
|
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& direct_internal_fn_supported_p (IFN_CTZ, TREE_TYPE (@0),
|
|
OPTIMIZE_FOR_SPEED))
|
|
(with { tree utype = unsigned_type_for (TREE_TYPE (@0)); }
|
|
(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)
|
|
/* __builtin_ffs (X) == 0 -> X == 0.
|
|
__builtin_ffs (X) == 6 -> (X & 63) == 32. */
|
|
(for cmp (eq ne)
|
|
(simplify
|
|
(cmp (ffs@2 @0) INTEGER_CST@1)
|
|
(with { int prec = TYPE_PRECISION (TREE_TYPE (@0)); }
|
|
(switch
|
|
(if (integer_zerop (@1))
|
|
(cmp @0 { build_zero_cst (TREE_TYPE (@0)); }))
|
|
(if (tree_int_cst_sgn (@1) < 0 || wi::to_widest (@1) > prec)
|
|
{ constant_boolean_node (cmp == NE_EXPR ? true : false, type); })
|
|
(if (single_use (@2))
|
|
(cmp (bit_and @0 { wide_int_to_tree (TREE_TYPE (@0),
|
|
wi::mask (tree_to_uhwi (@1),
|
|
false, prec)); })
|
|
{ wide_int_to_tree (TREE_TYPE (@0),
|
|
wi::shifted_mask (tree_to_uhwi (@1) - 1, 1,
|
|
false, prec)); }))))))
|
|
|
|
/* __builtin_ffs (X) > 6 -> X != 0 && (X & 63) == 0. */
|
|
(for cmp (gt le)
|
|
cmp2 (ne eq)
|
|
cmp3 (eq ne)
|
|
bit_op (bit_and bit_ior)
|
|
(simplify
|
|
(cmp (ffs@2 @0) INTEGER_CST@1)
|
|
(with { int prec = TYPE_PRECISION (TREE_TYPE (@0)); }
|
|
(switch
|
|
(if (integer_zerop (@1))
|
|
(cmp2 @0 { build_zero_cst (TREE_TYPE (@0)); }))
|
|
(if (tree_int_cst_sgn (@1) < 0)
|
|
{ constant_boolean_node (cmp == GT_EXPR ? true : false, type); })
|
|
(if (wi::to_widest (@1) >= prec)
|
|
{ constant_boolean_node (cmp == GT_EXPR ? false : true, type); })
|
|
(if (wi::to_widest (@1) == prec - 1)
|
|
(cmp3 @0 { wide_int_to_tree (TREE_TYPE (@0),
|
|
wi::shifted_mask (prec - 1, 1,
|
|
false, prec)); }))
|
|
(if (single_use (@2))
|
|
(bit_op (cmp2 @0 { build_zero_cst (TREE_TYPE (@0)); })
|
|
(cmp3 (bit_and @0
|
|
{ wide_int_to_tree (TREE_TYPE (@0),
|
|
wi::mask (tree_to_uhwi (@1),
|
|
false, prec)); })
|
|
{ build_zero_cst (TREE_TYPE (@0)); }))))))))
|
|
|
|
#if GIMPLE
|
|
|
|
/* Simplify:
|
|
a = op a1
|
|
r = cond ? a : b
|
|
--> r = .COND_FN (cond, a, b)
|
|
and,
|
|
a = op a1
|
|
r = cond ? b : a
|
|
--> r = .COND_FN (~cond, b, a). */
|
|
|
|
(for uncond_op (UNCOND_UNARY)
|
|
cond_op (COND_UNARY)
|
|
(simplify
|
|
(vec_cond @0 (view_convert? (uncond_op@3 @1)) @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 @0 @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)))))
|
|
|
|
/* 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. */
|
|
|
|
(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)
|
|
&& is_truth_type_for (op_type, TREE_TYPE (@0))
|
|
&& single_use (@4))
|
|
(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)
|
|
&& 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)))))))
|
|
|
|
/* 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)
|
|
&& 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))))))
|
|
(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)
|
|
&& 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)))))))
|
|
#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)))))))
|
|
|
|
/* Detect simplication for a conditional reduction where
|
|
|
|
a = mask1 ? b : 0
|
|
c = mask2 ? d + a : d
|
|
|
|
is turned into
|
|
|
|
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))
|
|
|
|
/* 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; })))))))
|
|
|
|
/* Fold reduction of a single nonzero element constructor. */
|
|
(for reduc (IFN_REDUC_PLUS IFN_REDUC_IOR IFN_REDUC_XOR)
|
|
(simplify (reduc (CONSTRUCTOR@0))
|
|
(with { tree ctor = (TREE_CODE (@0) == SSA_NAME
|
|
? gimple_assign_rhs1 (SSA_NAME_DEF_STMT (@0)) : @0);
|
|
tree elt = ctor_single_nonzero_element (ctor); }
|
|
(if (elt
|
|
&& !HONOR_SNANS (type)
|
|
&& !HONOR_SIGNED_ZEROS (type))
|
|
{ elt; }))))
|
|
|
|
/* Fold REDUC (@0 op VECTOR_CST) as REDUC (@0) op REDUC (VECTOR_CST). */
|
|
(for reduc (IFN_REDUC_PLUS IFN_REDUC_MAX IFN_REDUC_MIN IFN_REDUC_FMAX
|
|
IFN_REDUC_FMIN IFN_REDUC_AND IFN_REDUC_IOR IFN_REDUC_XOR)
|
|
op (plus max min IFN_FMAX IFN_FMIN bit_and bit_ior bit_xor)
|
|
(simplify (reduc (op @0 VECTOR_CST@1))
|
|
(op (reduc:type @0) (reduc:type @1))))
|
|
|
|
(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))
|
|
{
|
|
bool insert_first_p = sel.series_p (1, 1, nelts + 1, 1);
|
|
if (insert_first_p)
|
|
{
|
|
/* 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, sel[0])))
|
|
op0 = op1;
|
|
}
|
|
/* The above can fail for two-element vectors which always
|
|
appear to insert the first element, so try inserting
|
|
into the second lane as well. For more than two
|
|
elements that's wasted time. */
|
|
if (!insert_first_p || (!ins && maybe_eq (nelts, 2u)))
|
|
{
|
|
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
|
|
&& (known_eq (at + 1, nelts)
|
|
|| sel.series_p (at + 1, 1, at + 1, 1)))
|
|
{
|
|
if (known_lt (poly_uint64 (sel[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 * vector_element_bits (type)); })
|
|
(if (changed)
|
|
(vec_perm { op0; } { op1; } { op2; }))))))))))
|
|
|
|
/* VEC_PERM_EXPR (v, v, mask) -> v where v contains same element. */
|
|
|
|
(match vec_same_elem_p
|
|
(vec_duplicate @0))
|
|
|
|
(match vec_same_elem_p
|
|
CONSTRUCTOR@0
|
|
(if (TREE_CODE (@0) == SSA_NAME
|
|
&& uniform_vector_p (gimple_assign_rhs1 (SSA_NAME_DEF_STMT (@0))))))
|
|
|
|
(match vec_same_elem_p
|
|
@0
|
|
(if (uniform_vector_p (@0))))
|
|
|
|
|
|
(simplify
|
|
(vec_perm vec_same_elem_p@0 @0 @1)
|
|
@0)
|
|
|
|
/* Push VEC_PERM earlier if that may help FMA perception (PR101895). */
|
|
(simplify
|
|
(plus:c (vec_perm:s (mult:c@0 @1 vec_same_elem_p@2) @0 @3) @4)
|
|
(if (TREE_CODE (@0) == SSA_NAME && num_imm_uses (@0) == 2)
|
|
(plus (mult (vec_perm @1 @1 @3) @2) @4)))
|
|
(simplify
|
|
(minus (vec_perm:s (mult:c@0 @1 vec_same_elem_p@2) @0 @3) @4)
|
|
(if (TREE_CODE (@0) == SSA_NAME && num_imm_uses (@0) == 2)
|
|
(minus (mult (vec_perm @1 @1 @3) @2) @4)))
|
|
|
|
|
|
/* Match count trailing zeroes for simplify_count_trailing_zeroes in fwprop.
|
|
The canonical form is array[((x & -x) * C) >> SHIFT] where C is a magic
|
|
constant which when multiplied by a power of 2 contains a unique value
|
|
in the top 5 or 6 bits. This is then indexed into a table which maps it
|
|
to the number of trailing zeroes. */
|
|
(match (ctz_table_index @1 @2 @3)
|
|
(rshift (mult (bit_and:c (negate @1) @1) INTEGER_CST@2) INTEGER_CST@3))
|
|
|
|
(match (cond_expr_convert_p @0 @2 @3 @6)
|
|
(cond (simple_comparison@6 @0 @1) (convert@4 @2) (convert@5 @3))
|
|
(if (INTEGRAL_TYPE_P (type)
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@2))
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
|
&& INTEGRAL_TYPE_P (TREE_TYPE (@3))
|
|
&& TYPE_PRECISION (type) != TYPE_PRECISION (TREE_TYPE (@0))
|
|
&& TYPE_PRECISION (TREE_TYPE (@0))
|
|
== TYPE_PRECISION (TREE_TYPE (@2))
|
|
&& TYPE_PRECISION (TREE_TYPE (@0))
|
|
== TYPE_PRECISION (TREE_TYPE (@3))
|
|
/* For vect_recog_cond_expr_convert_pattern, @2 and @3 can differ in
|
|
signess when convert is truncation, but not ok for extension since
|
|
it's sign_extend vs zero_extend. */
|
|
&& (TYPE_PRECISION (TREE_TYPE (@0)) > TYPE_PRECISION (type)
|
|
|| (TYPE_UNSIGNED (TREE_TYPE (@2))
|
|
== TYPE_UNSIGNED (TREE_TYPE (@3))))
|
|
&& single_use (@4)
|
|
&& single_use (@5))))
|