diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6340afe464f..44fa51a3616 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2015-07-15 Richard Biener + + * 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. + 2015-07-15 Uros Bizjak PR rtl-optimization/58066 diff --git a/gcc/genmatch.c b/gcc/genmatch.c index fa140dfe158..1434719a88e 100644 --- a/gcc/genmatch.c +++ b/gcc/genmatch.c @@ -3014,13 +3014,13 @@ public: private: const cpp_token *next (); - const cpp_token *peek (); - const cpp_token *peek_ident (const char * = NULL); + const cpp_token *peek (unsigned = 1); + const cpp_token *peek_ident (const char * = NULL, unsigned = 1); const cpp_token *expect (enum cpp_ttype); - void eat_token (enum cpp_ttype); + const cpp_token *eat_token (enum cpp_ttype); const char *get_string (); const char *get_ident (); - void eat_ident (const char *); + const cpp_token *eat_ident (const char *); const char *get_number (); id_base *parse_operation (); @@ -3078,7 +3078,7 @@ parser::next () /* Peek at the next non-whitespace token from R. */ const cpp_token * -parser::peek () +parser::peek (unsigned num) { const cpp_token *token; unsigned i = 0; @@ -3086,8 +3086,9 @@ parser::peek () { token = cpp_peek_token (r, i++); } - while (token->type == CPP_PADDING - && token->type != CPP_EOF); + 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. */ @@ -3100,9 +3101,9 @@ parser::peek () token is not an identifier or equal to ID if supplied). */ const cpp_token * -parser::peek_ident (const char *id) +parser::peek_ident (const char *id, unsigned num) { - const cpp_token *token = peek (); + const cpp_token *token = peek (num); if (token->type != CPP_NAME) return 0; @@ -3131,10 +3132,10 @@ parser::expect (enum cpp_ttype tk) /* Consume the next token from R and assert it is of type TK. */ -void +const cpp_token * parser::eat_token (enum cpp_ttype tk) { - expect (tk); + return expect (tk); } /* Read the next token from R and assert it is of type CPP_STRING and @@ -3159,13 +3160,14 @@ parser::get_ident () /* Eat an identifier token with value S from R. */ -void +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 @@ -3557,6 +3559,58 @@ parser::parse_result (operand *result, predicate_id *matcher) 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 (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; diff --git a/gcc/match.pd b/gcc/match.pd index 8694854faa1..8bedb235788 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -1107,43 +1107,44 @@ along with GCC; see the file COPYING3. If not see 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) + (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) + /* 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) + /* 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: + /* 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 @@ -1154,39 +1155,39 @@ along with GCC; see the file COPYING3. If not see 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) + (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))); })) + /* 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 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 @@ -1463,58 +1464,60 @@ along with GCC; see the file COPYING3. If not see (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); })))))))))))))) + (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 @@ -1549,65 +1552,68 @@ along with GCC; see the file COPYING3. If not see (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); }) + (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) > 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); }))))))))))))) + /* 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