This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Add 'switch' statement to match.pd language
- From: Richard Biener <rguenther at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 14 Jul 2015 15:02:37 +0200 (CEST)
- Subject: [PATCH] Add 'switch' statement to match.pd language
- Authentication-results: sourceware.org; auth=none
The following as promised adds a 'switch' statement. This way
(if (A)
B
(if (B)
C
(if (C)
D
E)))
can now be written as
(switch
(if (A)
B)
(if (B)
C)
(if (C)
D)
E)
the ifs immediately nested in the switch cannot have else clauses and
I reject switches that can be expressed as single if.
Bootstrapped on x86_64-unknown-linux-gnu, testing in progress.
I know Micha detests the extra 'if' as much as the extra braces thus
would have prefered
(switch
(A) B
(B) C
(C) D
E)
but that's hard to unambiguously parse and adding a keyword
without braces like
(switch
if (A) B
if (B) C
if (C) D
E)
looked too inconsistent with all the rest of the language.
Thus - barring any comments I plan to commit this tomorrow
and then (being done with IL changes) will update the internals
documentation to reflect recent changes.
Note that internally the switch statement is represented as
a if () { } else { if () {} else { if () .... chain.
Thanks,
Richard.
2015-07-14 Richard Biener <rguenther@suse.de>
* genmatch.c (parser::peek, parser::peek_ident): Add argument
to tell how many tokens to peek ahead (default 1).
(parser::eat_token, parser::eat_ident): Return token consumed.
(parser::parse_result): Parse new switch statement.
* match.pd: Use case statements where appropriate.
Index: gcc/genmatch.c
===================================================================
*** gcc/genmatch.c (revision 225765)
--- gcc/genmatch.c (working copy)
*************** public:
*** 3014,3026 ****
private:
const cpp_token *next ();
! const cpp_token *peek ();
! const cpp_token *peek_ident (const char * = NULL);
const cpp_token *expect (enum cpp_ttype);
! void eat_token (enum cpp_ttype);
const char *get_string ();
const char *get_ident ();
! void eat_ident (const char *);
const char *get_number ();
id_base *parse_operation ();
--- 3014,3026 ----
private:
const cpp_token *next ();
! const cpp_token *peek (unsigned = 1);
! const cpp_token *peek_ident (const char * = NULL, unsigned = 1);
const cpp_token *expect (enum cpp_ttype);
! const cpp_token *eat_token (enum cpp_ttype);
const char *get_string ();
const char *get_ident ();
! const cpp_token *eat_ident (const char *);
const char *get_number ();
id_base *parse_operation ();
*************** parser::next ()
*** 3078,3084 ****
/* Peek at the next non-whitespace token from R. */
const cpp_token *
! parser::peek ()
{
const cpp_token *token;
unsigned i = 0;
--- 3078,3084 ----
/* Peek at the next non-whitespace token from R. */
const cpp_token *
! parser::peek (unsigned num)
{
const cpp_token *token;
unsigned i = 0;
*************** parser::peek ()
*** 3086,3093 ****
{
token = cpp_peek_token (r, i++);
}
! while (token->type == CPP_PADDING
! && token->type != CPP_EOF);
/* If we peek at EOF this is a fatal error as it leaves the
cpp_reader in unusable state. Assume we really wanted a
token and thus this EOF is unexpected. */
--- 3086,3094 ----
{
token = cpp_peek_token (r, i++);
}
! while ((token->type == CPP_PADDING
! && token->type != CPP_EOF)
! || (--num > 0));
/* If we peek at EOF this is a fatal error as it leaves the
cpp_reader in unusable state. Assume we really wanted a
token and thus this EOF is unexpected. */
*************** parser::peek ()
*** 3100,3108 ****
token is not an identifier or equal to ID if supplied). */
const cpp_token *
! parser::peek_ident (const char *id)
{
! const cpp_token *token = peek ();
if (token->type != CPP_NAME)
return 0;
--- 3101,3109 ----
token is not an identifier or equal to ID if supplied). */
const cpp_token *
! parser::peek_ident (const char *id, unsigned num)
{
! const cpp_token *token = peek (num);
if (token->type != CPP_NAME)
return 0;
*************** parser::expect (enum cpp_ttype tk)
*** 3131,3140 ****
/* Consume the next token from R and assert it is of type TK. */
! void
parser::eat_token (enum cpp_ttype tk)
{
! expect (tk);
}
/* Read the next token from R and assert it is of type CPP_STRING and
--- 3132,3141 ----
/* Consume the next token from R and assert it is of type TK. */
! const cpp_token *
parser::eat_token (enum cpp_ttype tk)
{
! return expect (tk);
}
/* Read the next token from R and assert it is of type CPP_STRING and
*************** parser::get_ident ()
*** 3159,3171 ****
/* Eat an identifier token with value S from R. */
! void
parser::eat_ident (const char *s)
{
const cpp_token *token = peek ();
const char *t = get_ident ();
if (strcmp (s, t) != 0)
fatal_at (token, "expected '%s' got '%s'\n", s, t);
}
/* Read the next token from R and assert it is of type CPP_NUMBER and
--- 3160,3173 ----
/* Eat an identifier token with value S from R. */
! const cpp_token *
parser::eat_ident (const char *s)
{
const cpp_token *token = peek ();
const char *t = get_ident ();
if (strcmp (s, t) != 0)
fatal_at (token, "expected '%s' got '%s'\n", s, t);
+ return token;
}
/* Read the next token from R and assert it is of type CPP_NUMBER and
*************** parser::parse_result (operand *result, p
*** 3557,3562 ****
--- 3559,3616 ----
eat_token (CPP_CLOSE_PAREN);
return withe;
}
+ else if (peek_ident ("switch"))
+ {
+ token = eat_ident ("switch");
+ eat_token (CPP_OPEN_PAREN);
+ eat_ident ("if");
+ if_expr *ife = new if_expr ();
+ operand *res = ife;
+ ife->cond = parse_c_expr (CPP_OPEN_PAREN);
+ if (peek ()->type == CPP_OPEN_PAREN)
+ ife->trueexpr = parse_result (result, matcher);
+ else
+ ife->trueexpr = parse_op ();
+ eat_token (CPP_CLOSE_PAREN);
+ if (peek ()->type != CPP_OPEN_PAREN
+ || !peek_ident ("if", 2))
+ fatal_at (token, "switch can be implemented with a single if");
+ while (peek ()->type != CPP_CLOSE_PAREN)
+ {
+ if (peek ()->type == CPP_OPEN_PAREN)
+ {
+ if (peek_ident ("if", 2))
+ {
+ eat_token (CPP_OPEN_PAREN);
+ eat_ident ("if");
+ ife->falseexpr = new if_expr ();
+ ife = as_a <if_expr *> (ife->falseexpr);
+ ife->cond = parse_c_expr (CPP_OPEN_PAREN);
+ if (peek ()->type == CPP_OPEN_PAREN)
+ ife->trueexpr = parse_result (result, matcher);
+ else
+ ife->trueexpr = parse_op ();
+ eat_token (CPP_CLOSE_PAREN);
+ }
+ else
+ {
+ /* switch default clause */
+ ife->falseexpr = parse_result (result, matcher);
+ eat_token (CPP_CLOSE_PAREN);
+ return res;
+ }
+ }
+ else
+ {
+ /* switch default clause */
+ ife->falseexpr = parse_op ();
+ eat_token (CPP_CLOSE_PAREN);
+ return res;
+ }
+ }
+ eat_token (CPP_CLOSE_PAREN);
+ return res;
+ }
else
{
operand *op = result;
Index: gcc/match.pd
===================================================================
*** gcc/match.pd (revision 225764)
--- gcc/match.pd (working copy)
*************** (define_operator_list CBRT BUILT_IN_CBRT
*** 1107,1149 ****
unsigned int final_prec = TYPE_PRECISION (type);
int final_unsignedp = TYPE_UNSIGNED (type);
}
! /* 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. Likewise if the
! final type has a precision not equal to the size of its mode. */
! (if (((inter_int && inside_int) || (inter_float && inside_float))
! && (final_int || final_float)
! && inter_prec >= inside_prec
! && (inter_float || inter_unsignedp == inside_unsignedp)
! && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type))
! && TYPE_MODE (type) == TYPE_MODE (inter_type)))
! (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
--- 1167,1210 ----
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. Likewise if the
! final type has a precision not equal to the size of its mode. */
! (if (((inter_int && inside_int) || (inter_float && inside_float))
! && (final_int || final_float)
! && inter_prec >= inside_prec
! && (inter_float || inter_unsignedp == inside_unsignedp)
! && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type))
! && TYPE_MODE (type) == TYPE_MODE (inter_type)))
! (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
*************** (define_operator_list CBRT BUILT_IN_CBRT
*** 1154,1192 ****
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)
! && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type))
! && TYPE_MODE (type) == TYPE_MODE (inter_type)))
! (ocvt @0)
!
! /* A truncation to an unsigned type (a zero-extension) should be
! canonicalized as bitwise and of a mask. */
! (if (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)))))))))))
/* 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
--- 1215,1253 ----
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)
! && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type))
! && TYPE_MODE (type) == TYPE_MODE (inter_type)))
! (ocvt @0))
!
! /* A truncation to an unsigned type (a zero-extension) should be
! canonicalized as bitwise and of a mask. */
! (if (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)))))))
/* 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
*************** (define_operator_list CBRT BUILT_IN_CBRT
*** 1463,1520 ****
(simplify
(cmp @0 REAL_CST@1)
/* IEEE doesn't distinguish +0 and -0 in comparisons. */
! /* a CMP (-0) -> a CMP 0 */
! (if (REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (@1)))
! (cmp @0 { build_real (TREE_TYPE (@1), dconst0); })
! /* x != NaN is always true, other ops are always false. */
! (if (REAL_VALUE_ISNAN (TREE_REAL_CST (@1))
! && ! HONOR_SNANS (@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);
! }
! /* x > +Inf is always false, if with ignore sNANs. */
! (if (code == GT_EXPR
! && ! HONOR_SNANS (@0))
! { constant_boolean_node (false, type); }
! (if (code == LE_EXPR)
! /* x <= +Inf is always true, if we don't case about NaNs. */
! (if (! HONOR_NANS (@0))
! { constant_boolean_node (true, type); }
! /* x <= +Inf is the same as x == x, i.e. isfinite(x). */
! (eq @0 @0))
! /* x == +Inf and x >= +Inf are always equal to x > DBL_MAX. */
! (if (code == EQ_EXPR || 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). */
! (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)
! (bit_xor (lt @0 { build_real (TREE_TYPE (@0), max); })
! { build_one_cst (type); })
! (bit_xor (gt @0 { build_real (TREE_TYPE (@0), max); })
! { build_one_cst (type); }))))))))))))))
/* 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
--- 1537,1596 ----
(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); }))
! /* x != NaN is always true, other ops are always false. */
! (if (REAL_VALUE_ISNAN (TREE_REAL_CST (@1))
! && ! HONOR_SNANS (@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 with ignore sNANs. */
! (if (code == GT_EXPR
! && ! HONOR_SNANS (@0))
! { constant_boolean_node (false, type); })
! (if (code == LE_EXPR)
! /* x <= +Inf is always true, if we don't case about NaNs. */
! (if (! HONOR_NANS (@0))
! { constant_boolean_node (true, type); }
! /* x <= +Inf is the same as x == x, i.e. isfinite(x). */
! (eq @0 @0)))
! /* x == +Inf and x >= +Inf are always equal to x > DBL_MAX. */
! (if (code == EQ_EXPR || 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). */
! (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)
! (bit_xor (lt @0 { build_real (TREE_TYPE (@0), max); })
! { build_one_cst (type); })
! (bit_xor (gt @0 { build_real (TREE_TYPE (@0), max); })
! { build_one_cst (type); }))))))))))
/* 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
*************** (define_operator_list CBRT BUILT_IN_CBRT
*** 1549,1613 ****
(for sq (SQRT)
(simplify
(cmp (sq @0) REAL_CST@1)
! (if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (@1)))
! /* 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 (cmp == GT_EXPR || cmp == GE_EXPR)
! (with
! {
! REAL_VALUE_TYPE c2;
! REAL_ARITHMETIC (c2, MULT_EXPR, TREE_REAL_CST (@1), TREE_REAL_CST (@1));
! real_convert (&c2, TYPE_MODE (TREE_TYPE (@0)), &c2);
! }
! (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. */
! (cmp @0 { build_real (TREE_TYPE (@0), c2); })))
! (if (cmp == LT_EXPR || cmp == LE_EXPR)
! (with
! {
! REAL_VALUE_TYPE c2;
! REAL_ARITHMETIC (c2, MULT_EXPR, TREE_REAL_CST (@1), TREE_REAL_CST (@1));
! real_convert (&c2, TYPE_MODE (TREE_TYPE (@0)), &c2);
! }
! (if (REAL_VALUE_ISINF (c2))
! /* 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 (! REAL_VALUE_ISINF (c2)
! && ! HONOR_NANS (@0))
! (cmp @0 { build_real (TREE_TYPE (@0), c2); })
! /* sqrt(x) < c is the same as x >= 0 && x < c*c. */
! (if (! REAL_VALUE_ISINF (c2)
! && GENERIC)
! (truth_andif
! (ge @0 { build_real (TREE_TYPE (@0), dconst0); })
! (cmp @0 { build_real (TREE_TYPE (@0), c2); })))))))))))))
/* Unordered tests if either argument is a NaN. */
(simplify
--- 1625,1692 ----
(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 (cmp == GT_EXPR || cmp == GE_EXPR)
! (with
! {
! REAL_VALUE_TYPE c2;
! REAL_ARITHMETIC (c2, MULT_EXPR,
! TREE_REAL_CST (@1), TREE_REAL_CST (@1));
! real_convert (&c2, TYPE_MODE (TREE_TYPE (@0)), &c2);
! }
! (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. */
! (cmp @0 { build_real (TREE_TYPE (@0), c2); }))))
! (if (cmp == LT_EXPR || cmp == LE_EXPR)
! (with
! {
! REAL_VALUE_TYPE c2;
! REAL_ARITHMETIC (c2, MULT_EXPR,
! TREE_REAL_CST (@1), TREE_REAL_CST (@1));
! real_convert (&c2, TYPE_MODE (TREE_TYPE (@0)), &c2);
! }
! (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 (! HONOR_NANS (@0))
! (cmp @0 { build_real (TREE_TYPE (@0), c2); })
! /* sqrt(x) < c is the same as x >= 0 && x < c*c. */
! (if (GENERIC)
! (truth_andif
! (ge @0 { build_real (TREE_TYPE (@0), dconst0); })
! (cmp @0 { build_real (TREE_TYPE (@0), c2); }))))))))))))
/* Unordered tests if either argument is a NaN. */
(simplify