genmatch.c (parser::peek, [...]): Add argument to tell how many tokens to peek ahead (default 1).

2015-07-15  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.

From-SVN: r225809
This commit is contained in:
Richard Biener 2015-07-15 08:35:15 +00:00 committed by Richard Biener
parent a16bca311a
commit 64d3a1f040
3 changed files with 255 additions and 187 deletions

View file

@ -1,3 +1,11 @@
2015-07-15 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.
2015-07-15 Uros Bizjak <ubizjak@gmail.com>
PR rtl-optimization/58066

View file

@ -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 <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;

View file

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