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 <rguent...@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