From 8fdc6c67ad030e6caf88f391eb1deac0ce3679b3 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Tue, 14 Jul 2015 07:25:55 +0000 Subject: [PATCH] genmatch.c (struct operand): Add OP_IF and OP_WITH op_types. 2015-07-14 Richard Biener * genmatch.c (struct operand): Add OP_IF and OP_WITH op_types. (struct if_expr): New. (struct with_expr): Likewise. (is_a_helper): Add helpers for if_expr and with_expr. (struct simplify): Add simplify_kind enum and member. Remove ifexpr_vec member. (simplify::simplify): Adjust. (lower_commutative): Adjust. (lower_opt_convert): Likewise. (lower_cond): Likewise. (replace_id): Handle with_expr and if_expr. (lower_for): Adjust. (dt_simplify::gen_1): New recursive worker, split out from ... (dt_simplify::gen): ... here. Deal with if and with expansion recursively. (capture_info::capture_info): Take context argument (capture_info::walk_result): Only analyze specific result. (parser::parse_result): New function. (parser::parse_simplify): Adjust to parse ifs with then end else case. (parser::parse_if): Simplify. (parser::parse_pattern): Pass down simplify kind. * match.pd: Convert if structure to new syntax. From-SVN: r225760 --- gcc/ChangeLog | 26 +++ gcc/genmatch.c | 510 ++++++++++++++++++++++++++++--------------------- gcc/match.pd | 258 ++++++++++++------------- 3 files changed, 445 insertions(+), 349 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4f3bc5bcbf9..de40c6084f2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,29 @@ +2015-07-14 Richard Biener + + * genmatch.c (struct operand): Add OP_IF and OP_WITH op_types. + (struct if_expr): New. + (struct with_expr): Likewise. + (is_a_helper): Add helpers for if_expr and with_expr. + (struct simplify): Add simplify_kind enum and member. Remove + ifexpr_vec member. + (simplify::simplify): Adjust. + (lower_commutative): Adjust. + (lower_opt_convert): Likewise. + (lower_cond): Likewise. + (replace_id): Handle with_expr and if_expr. + (lower_for): Adjust. + (dt_simplify::gen_1): New recursive worker, split out from ... + (dt_simplify::gen): ... here. Deal with if and with expansion + recursively. + (capture_info::capture_info): Take context argument + (capture_info::walk_result): Only analyze specific result. + (parser::parse_result): New function. + (parser::parse_simplify): Adjust to parse ifs with then end + else case. + (parser::parse_if): Simplify. + (parser::parse_pattern): Pass down simplify kind. + * match.pd: Convert if structure to new syntax. + 2015-07-13 Marek Polacek * rtl.c (rtx_equal_p_cb): Fix typo. diff --git a/gcc/genmatch.c b/gcc/genmatch.c index baa244cc676..12f04b05a81 100644 --- a/gcc/genmatch.c +++ b/gcc/genmatch.c @@ -482,7 +482,7 @@ struct capture_info; /* The base class for operands. */ struct operand { - enum op_type { OP_PREDICATE, OP_EXPR, OP_CAPTURE, OP_C_EXPR }; + enum op_type { OP_PREDICATE, OP_EXPR, OP_CAPTURE, OP_C_EXPR, OP_IF, OP_WITH }; operand (enum op_type type_) : type (type_) {} enum op_type type; virtual void gen_transform (FILE *, int, const char *, bool, int, @@ -578,6 +578,26 @@ struct capture : public operand dt_operand ** = 0, bool = true); }; +/* if expression. */ + +struct if_expr : public operand +{ + if_expr () : operand (OP_IF), cond (NULL), trueexpr (NULL), + falseexpr (NULL) {} + c_expr *cond; + operand *trueexpr; + operand *falseexpr; +}; + +/* with expression. */ + +struct with_expr : public operand +{ + with_expr () : operand (OP_WITH), with (NULL), subexpr (NULL) {} + c_expr *with; + operand *subexpr; +}; + template<> template<> inline bool @@ -610,16 +630,21 @@ is_a_helper ::test (operand *op) return op->type == operand::OP_EXPR; } -/* Helper to distinguish 'if' from 'with' expressions. */ +template<> +template<> +inline bool +is_a_helper ::test (operand *op) +{ + return op->type == operand::OP_IF; +} -struct if_or_with +template<> +template<> +inline bool +is_a_helper ::test (operand *op) { - if_or_with (operand *cexpr_, source_location location_, bool is_with_) - : location (location_), cexpr (cexpr_), is_with (is_with_) {} - source_location location; - operand *cexpr; - bool is_with; -}; + return op->type == operand::OP_WITH; +} /* The main class of a pattern and its transform. This is used to represent both (simplify ...) and (match ...) kinds. The AST @@ -628,26 +653,27 @@ struct if_or_with struct simplify { - simplify (operand *match_, source_location match_location_, + enum simplify_kind { SIMPLIFY, MATCH }; + + simplify (simplify_kind kind_, + operand *match_, source_location match_location_, struct operand *result_, source_location result_location_, - vec ifexpr_vec_, vec > for_vec_, - cid_map_t *capture_ids_) - : match (match_), match_location (match_location_), + vec > for_vec_, cid_map_t *capture_ids_) + : kind (kind_), match (match_), match_location (match_location_), result (result_), result_location (result_location_), - ifexpr_vec (ifexpr_vec_), for_vec (for_vec_), + for_vec (for_vec_), capture_ids (capture_ids_), capture_max (capture_ids_->elements () - 1) {} + simplify_kind kind; /* The expression that is matched against the GENERIC or GIMPLE IL. */ operand *match; source_location match_location; - /* For a (simplify ...) the expression produced when the pattern applies. - For a (match ...) either NULL if it is a simple predicate or the - single expression specifying the matched operands. */ + /* For a (simplify ...) an expression with ifs and withs with the expression + produced when the pattern applies in the leafs. + For a (match ...) the leafs are either empty if it is a simple predicate + or the single expression specifying the matched operands. */ struct operand *result; source_location result_location; - /* Collected 'if' expressions that need to evaluate to true to make - the pattern apply. */ - vec ifexpr_vec; /* Collected 'for' expression operators that have to be replaced in the lowering phase. */ vec > for_vec; @@ -803,8 +829,8 @@ lower_commutative (simplify *s, vec& simplifiers) vec matchers = commutate (s->match); for (unsigned i = 0; i < matchers.length (); ++i) { - simplify *ns = new simplify (matchers[i], s->match_location, - s->result, s->result_location, s->ifexpr_vec, + simplify *ns = new simplify (s->kind, matchers[i], s->match_location, + s->result, s->result_location, s->for_vec, s->capture_ids); simplifiers.safe_push (ns); } @@ -932,8 +958,8 @@ lower_opt_convert (simplify *s, vec& simplifiers) vec matchers = lower_opt_convert (s->match); for (unsigned i = 0; i < matchers.length (); ++i) { - simplify *ns = new simplify (matchers[i], s->match_location, - s->result, s->result_location, s->ifexpr_vec, + simplify *ns = new simplify (s->kind, matchers[i], s->match_location, + s->result, s->result_location, s->for_vec, s->capture_ids); simplifiers.safe_push (ns); } @@ -1032,8 +1058,8 @@ lower_cond (simplify *s, vec& simplifiers) vec matchers = lower_cond (s->match); for (unsigned i = 0; i < matchers.length (); ++i) { - simplify *ns = new simplify (matchers[i], s->match_location, - s->result, s->result_location, s->ifexpr_vec, + simplify *ns = new simplify (s->kind, matchers[i], s->match_location, + s->result, s->result_location, s->for_vec, s->capture_ids); simplifiers.safe_push (ns); } @@ -1061,6 +1087,22 @@ replace_id (operand *o, user_id *id, id_base *with) ne->append_op (replace_id (e->ops[i], id, with)); return ne; } + else if (with_expr *w = dyn_cast (o)) + { + with_expr *nw = new with_expr (); + nw->with = as_a (replace_id (w->with, id, with)); + nw->subexpr = replace_id (w->subexpr, id, with); + return nw; + } + else if (if_expr *ife = dyn_cast (o)) + { + if_expr *nife = new if_expr (); + nife->cond = as_a (replace_id (ife->cond, id, with)); + nife->trueexpr = replace_id (ife->trueexpr, id, with); + if (ife->falseexpr) + nife->falseexpr = replace_id (ife->falseexpr, id, with); + return nife; + } /* For c_expr we simply record a string replacement table which is applied at code-generation time. */ @@ -1105,8 +1147,6 @@ lower_for (simplify *sin, vec& simplifiers) { operand *match_op = s->match; operand *result_op = s->result; - vec ifexpr_vec = s->ifexpr_vec.copy (); - for (unsigned i = 0; i < n_ids; ++i) { user_id *id = ids[i]; @@ -1114,13 +1154,10 @@ lower_for (simplify *sin, vec& simplifiers) match_op = replace_id (match_op, id, oper); if (result_op) result_op = replace_id (result_op, id, oper); - for (unsigned k = 0; k < s->ifexpr_vec.length (); ++k) - ifexpr_vec[k].cexpr = replace_id (ifexpr_vec[k].cexpr, - id, oper); } - simplify *ns = new simplify (match_op, s->match_location, + simplify *ns = new simplify (s->kind, match_op, s->match_location, result_op, s->result_location, - ifexpr_vec, vNULL, s->capture_ids); + vNULL, s->capture_ids); worklist.safe_push (ns); } } @@ -1228,6 +1265,7 @@ struct dt_simplify : public dt_node : dt_node (DT_SIMPLIFY), s (s_), pattern_no (pattern_no_), indexes (indexes_) {} + void gen_1 (FILE *, int, bool, operand *); void gen (FILE *f, int, bool); }; @@ -1530,9 +1568,9 @@ decision_tree::print (FILE *f) struct capture_info { - capture_info (simplify *s); + capture_info (simplify *s, operand *); void walk_match (operand *o, unsigned toplevel_arg, bool, bool); - void walk_result (operand *o, bool); + bool walk_result (operand *o, bool, operand *); void walk_c_expr (c_expr *); struct cinfo @@ -1552,12 +1590,10 @@ struct capture_info /* Analyze captures in S. */ -capture_info::capture_info (simplify *s) +capture_info::capture_info (simplify *s, operand *result) { expr *e; - if (!s->result - || ((e = dyn_cast (s->result)) - && is_a (e->operation))) + if (s->kind == simplify::MATCH) { force_no_side_effects = -1; return; @@ -1575,11 +1611,7 @@ capture_info::capture_info (simplify *s) && (*e->operation == COND_EXPR || *e->operation == VEC_COND_EXPR)); - walk_result (s->result, false); - - for (unsigned i = 0; i < s->ifexpr_vec.length (); ++i) - if (s->ifexpr_vec[i].is_with) - walk_c_expr (as_a (s->ifexpr_vec[i].cexpr)); + walk_result (s->result, false, result); } /* Analyze captures in the match expression piece O. */ @@ -1630,10 +1662,12 @@ capture_info::walk_match (operand *o, unsigned toplevel_arg, gcc_unreachable (); } -/* Analyze captures in the result expression piece O. */ +/* Analyze captures in the result expression piece O. Return true + if RESULT was visited in one of the children. Only visit + non-if/with children if they are rooted on RESULT. */ -void -capture_info::walk_result (operand *o, bool conditional_p) +bool +capture_info::walk_result (operand *o, bool conditional_p, operand *result) { if (capture *c = dyn_cast (o)) { @@ -1650,7 +1684,7 @@ capture_info::walk_result (operand *o, bool conditional_p) && is_a (c->what)) { info[c->where].cse_p = true; - walk_result (c->what, true); + walk_result (c->what, true, result); } } else if (expr *e = dyn_cast (o)) @@ -1663,13 +1697,49 @@ capture_info::walk_result (operand *o, bool conditional_p) else if (*e->operation == TRUTH_ANDIF_EXPR || *e->operation == TRUTH_ORIF_EXPR) cond_p = true; - walk_result (e->ops[i], cond_p); + walk_result (e->ops[i], cond_p, result); + } + } + else if (if_expr *e = dyn_cast (o)) + { + /* 'if' conditions should be all fine. */ + if (e->trueexpr == result) + { + walk_result (e->trueexpr, false, result); + return true; + } + if (e->falseexpr == result) + { + walk_result (e->falseexpr, false, result); + return true; } + bool res = false; + if (is_a (e->trueexpr) + || is_a (e->trueexpr)) + res |= walk_result (e->trueexpr, false, result); + if (e->falseexpr + && (is_a (e->falseexpr) + || is_a (e->falseexpr))) + res |= walk_result (e->falseexpr, false, result); + return res; + } + else if (with_expr *e = dyn_cast (o)) + { + bool res = (e->subexpr == result); + if (res + || is_a (e->subexpr) + || is_a (e->subexpr)) + res |= walk_result (e->subexpr, false, result); + if (res) + walk_c_expr (e->with); + return res; } else if (c_expr *e = dyn_cast (o)) walk_c_expr (e); else gcc_unreachable (); + + return false; } /* Look for captures in the C expr E. */ @@ -2487,87 +2557,55 @@ dt_operand::gen (FILE *f, int indent, bool gimple) } - /* Generate code for the '(if ...)', '(with ..)' and actual transform step of a '(simplify ...)' or '(match ...)'. This handles everything - that is not part of the decision tree (simplify->match). */ + that is not part of the decision tree (simplify->match). + Main recursive worker. */ void -dt_simplify::gen (FILE *f, int indent, bool gimple) +dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result) { - fprintf_indent (f, indent, "{\n"); - indent += 2; - output_line_directive (f, s->result_location); - if (s->capture_max >= 0) - fprintf_indent (f, indent, "tree captures[%u] ATTRIBUTE_UNUSED = {};\n", - s->capture_max + 1); - - for (int i = 0; i <= s->capture_max; ++i) - if (indexes[i]) - { - char opname[20]; - fprintf_indent (f, indent, "captures[%u] = %s;\n", - i, indexes[i]->get_name (opname)); - } - - unsigned n_braces = 0; - if (s->ifexpr_vec != vNULL) + if (result) { - for (unsigned i = 0; i < s->ifexpr_vec.length (); ++i) + if (with_expr *w = dyn_cast (result)) { - if_or_with &w = s->ifexpr_vec[i]; - if (w.is_with) + fprintf_indent (f, indent, "{\n"); + indent += 4; + output_line_directive (f, w->with->code[0].src_loc); + w->with->gen_transform (f, indent, NULL, true, 1, "type", NULL); + gen_1 (f, indent, gimple, w->subexpr); + indent -= 4; + fprintf_indent (f, indent, "}\n"); + return; + } + else if (if_expr *ife = dyn_cast (result)) + { + output_line_directive (f, ife->cond->code[0].src_loc); + fprintf_indent (f, indent, "if ("); + ife->cond->gen_transform (f, indent, NULL, true, 1, "type", NULL); + fprintf (f, ")\n"); + fprintf_indent (f, indent + 2, "{\n"); + indent += 4; + gen_1 (f, indent, gimple, ife->trueexpr); + indent -= 4; + fprintf_indent (f, indent + 2, "}\n"); + if (ife->falseexpr) { - fprintf_indent (f, indent, "{\n"); + fprintf_indent (f, indent, "else\n"); + fprintf_indent (f, indent + 2, "{\n"); indent += 4; - output_line_directive (f, w.location); - w.cexpr->gen_transform (f, indent, NULL, true, 1, "type", NULL); - n_braces++; - } - else - { - output_line_directive (f, w.location); - fprintf_indent (f, indent, "if ("); - if (i == s->ifexpr_vec.length () - 1 - || s->ifexpr_vec[i+1].is_with) - w.cexpr->gen_transform (f, indent, NULL, true, 1, "type", NULL); - else - { - unsigned j = i; - do - { - if (j != i) - { - fprintf (f, "\n"); - output_line_directive (f, s->ifexpr_vec[j].location); - fprintf_indent (f, indent + 4, "&& "); - } - fprintf (f, "("); - s->ifexpr_vec[j].cexpr->gen_transform (f, 0, NULL, - true, 1, "type", - NULL); - fprintf (f, ")"); - ++j; - } - while (j < s->ifexpr_vec.length () - && !s->ifexpr_vec[j].is_with); - i = j - 1; - } - fprintf (f, ")\n"); + gen_1 (f, indent, gimple, ife->falseexpr); + indent -= 4; + fprintf_indent (f, indent + 2, "}\n"); } + return; } - fprintf_indent (f, indent + 2, "{\n"); - indent += 4; - n_braces++; } /* Analyze captures and perform early-outs on the incoming arguments that cover cases we cannot handle. */ - capture_info cinfo (s); - expr *e; - if (s->result - && !((e = dyn_cast (s->result)) - && is_a (e->operation))) + capture_info cinfo (s, result); + if (s->kind == simplify::SIMPLIFY) { if (!gimple) { @@ -2626,7 +2664,6 @@ dt_simplify::gen (FILE *f, int indent, bool gimple) output_line_directive (f, s->result_location, true); fprintf (f, ", %%s:%%d\\n\", __FILE__, __LINE__);\n"); - operand *result = s->result; if (!result) { /* If there is no result then this is a predicate implementation. */ @@ -2782,7 +2819,7 @@ dt_simplify::gen (FILE *f, int indent, bool gimple) { fprintf_indent (f, indent, "tree res;\n"); - s->result->gen_transform (f, indent, "res", false, 1, "type", + result->gen_transform (f, indent, "res", false, 1, "type", &cinfo, indexes); } else @@ -2809,12 +2846,31 @@ dt_simplify::gen (FILE *f, int indent, bool gimple) fprintf_indent (f, indent, "return res;\n"); } } +} - for (unsigned i = 0; i < n_braces; ++i) - { - fprintf_indent (f, indent - 2, "}\n"); - indent -= 4; - } +/* Generate code for the '(if ...)', '(with ..)' and actual transform + step of a '(simplify ...)' or '(match ...)'. This handles everything + that is not part of the decision tree (simplify->match). */ + +void +dt_simplify::gen (FILE *f, int indent, bool gimple) +{ + fprintf_indent (f, indent, "{\n"); + indent += 2; + output_line_directive (f, s->result_location); + if (s->capture_max >= 0) + fprintf_indent (f, indent, "tree captures[%u] ATTRIBUTE_UNUSED = {};\n", + s->capture_max + 1); + + for (int i = 0; i <= s->capture_max; ++i) + if (indexes[i]) + { + char opname[20]; + fprintf_indent (f, indent, "captures[%u] = %s;\n", + i, indexes[i]->get_name (opname)); + } + + gen_1 (f, indent, gimple, s->result); indent -= 2; fprintf_indent (f, indent, "}\n"); @@ -2976,17 +3032,20 @@ private: void record_operlist (source_location, user_id *); void parse_pattern (); - void push_simplify (vec&, operand *, source_location, + operand *parse_result (operand *, predicate_id *); + void push_simplify (simplify::simplify_kind, + vec&, operand *, source_location, operand *, source_location); - void parse_simplify (source_location, vec&, predicate_id *, - expr *); + void parse_simplify (simplify::simplify_kind, + source_location, vec&, predicate_id *, + operand *); void parse_for (source_location); void parse_if (source_location); void parse_predicates (source_location); void parse_operator_list (source_location); cpp_reader *r; - vec active_ifs; + vec active_ifs; vec > active_fors; hash_set *oper_lists_set; vec oper_lists; @@ -3425,7 +3484,8 @@ parser::parse_op () MATCH_LOC, RESULT and RESULT_LOC and push it to SIMPLIFIERS. */ void -parser::push_simplify (vec& simplifiers, +parser::push_simplify (simplify::simplify_kind kind, + vec& simplifiers, operand *match, source_location match_loc, operand *result, source_location result_loc) { @@ -3434,27 +3494,90 @@ parser::push_simplify (vec& simplifiers, active_fors.safe_push (oper_lists); simplifiers.safe_push - (new simplify (match, match_loc, result, result_loc, - active_ifs.copy (), active_fors.copy (), capture_ids)); + (new simplify (kind, match, match_loc, result, result_loc, + active_fors.copy (), capture_ids)); if (!oper_lists.is_empty ()) active_fors.pop (); } /* Parse - simplify = 'simplify' - or - match = 'match' [] - with = | | = '(' 'if' '(' ')' ')' = '(' 'with' '{' '}' ')' + and return it. */ + +operand * +parser::parse_result (operand *result, predicate_id *matcher) +{ + const cpp_token *token = peek (); + if (token->type != CPP_OPEN_PAREN) + return parse_op (); + + eat_token (CPP_OPEN_PAREN); + if (peek_ident ("if")) + { + eat_ident ("if"); + if_expr *ife = new if_expr (); + ife->cond = parse_c_expr (CPP_OPEN_PAREN); + if (peek ()->type == CPP_OPEN_PAREN) + { + ife->trueexpr = parse_result (result, matcher); + if (peek ()->type == CPP_OPEN_PAREN) + ife->falseexpr = parse_result (result, matcher); + else if (peek ()->type != CPP_CLOSE_PAREN) + ife->falseexpr = parse_op (); + } + else if (peek ()->type != CPP_CLOSE_PAREN) + { + ife->trueexpr = parse_op (); + if (peek ()->type == CPP_OPEN_PAREN) + ife->falseexpr = parse_result (result, matcher); + else if (peek ()->type != CPP_CLOSE_PAREN) + ife->falseexpr = parse_op (); + } + /* If this if is immediately closed then it contains a + manual matcher or is part of a predicate definition. */ + else /* if (peek ()->type == CPP_CLOSE_PAREN) */ + { + if (!matcher) + fatal_at (peek (), "manual transform not implemented"); + } + eat_token (CPP_CLOSE_PAREN); + return ife; + } + else if (peek_ident ("with")) + { + eat_ident ("with"); + with_expr *withe = new with_expr (); + /* Parse (with c-expr expr) as (if-with (true) expr). */ + withe->with = parse_c_expr (CPP_OPEN_BRACE); + withe->with->nr_stmts = 0; + withe->subexpr = parse_result (result, matcher); + eat_token (CPP_CLOSE_PAREN); + return withe; + } + else + { + operand *op = result; + if (!matcher) + op = parse_expr (); + eat_token (CPP_CLOSE_PAREN); + return op; + } +} + +/* Parse + simplify = 'simplify' + or + match = 'match' [] and fill SIMPLIFIERS with the results. */ void -parser::parse_simplify (source_location match_location, +parser::parse_simplify (simplify::simplify_kind kind, + source_location match_location, vec& simplifiers, predicate_id *matcher, - expr *result) + operand *result) { /* Reset the capture map. */ if (!capture_ids) @@ -3474,6 +3597,20 @@ parser::parse_simplify (source_location match_location, && is_a (as_a (match)->operation)) fatal_at (loc, "outermost expression cannot be a predicate"); + /* Splice active_ifs onto result and continue parsing the + "then" expr. */ + if_expr *active_if = NULL; + for (int i = active_ifs.length (); i > 0; --i) + { + if_expr *ifc = new if_expr (); + ifc->cond = active_ifs[i-1]; + ifc->trueexpr = active_if; + active_if = ifc; + } + if_expr *outermost_if = active_if; + while (active_if && active_if->trueexpr) + active_if = as_a (active_if->trueexpr); + const cpp_token *token = peek (); /* If this if is immediately closed then it is part of a predicate @@ -3482,89 +3619,27 @@ parser::parse_simplify (source_location match_location, { if (!matcher) fatal_at (token, "expected transform expression"); - push_simplify (simplifiers, match, match_location, + if (active_if) + { + active_if->trueexpr = result; + result = outermost_if; + } + push_simplify (kind, simplifiers, match, match_location, result, token->src_loc); return; } - unsigned active_ifs_len = active_ifs.length (); - while (1) + operand *tem = parse_result (result, matcher); + if (active_if) { - if (token->type == CPP_OPEN_PAREN) - { - source_location paren_loc = token->src_loc; - eat_token (CPP_OPEN_PAREN); - if (peek_ident ("if")) - { - eat_ident ("if"); - active_ifs.safe_push (if_or_with (parse_c_expr (CPP_OPEN_PAREN), - token->src_loc, false)); - /* If this if is immediately closed then it contains a - manual matcher or is part of a predicate definition. - Push it. */ - if (peek ()->type == CPP_CLOSE_PAREN) - { - if (!matcher) - fatal_at (token, "manual transform not implemented"); - push_simplify (simplifiers, match, match_location, - result, paren_loc); - } - } - else if (peek_ident ("with")) - { - eat_ident ("with"); - /* Parse (with c-expr expr) as (if-with (true) expr). */ - c_expr *e = parse_c_expr (CPP_OPEN_BRACE); - e->nr_stmts = 0; - active_ifs.safe_push (if_or_with (e, token->src_loc, true)); - } - else - { - operand *op = result; - if (!matcher) - op = parse_expr (); - push_simplify (simplifiers, match, match_location, - op, token->src_loc); - eat_token (CPP_CLOSE_PAREN); - /* A "default" result closes the enclosing scope. */ - if (active_ifs.length () > active_ifs_len) - { - eat_token (CPP_CLOSE_PAREN); - active_ifs.pop (); - } - else - return; - } - } - else if (token->type == CPP_CLOSE_PAREN) - { - /* Close a scope if requested. */ - if (active_ifs.length () > active_ifs_len) - { - eat_token (CPP_CLOSE_PAREN); - active_ifs.pop (); - token = peek (); - } - else - return; - } - else - { - if (matcher) - fatal_at (token, "expected match operand expression"); - push_simplify (simplifiers, match, match_location, - matcher ? result : parse_op (), token->src_loc); - /* A "default" result closes the enclosing scope. */ - if (active_ifs.length () > active_ifs_len) - { - eat_token (CPP_CLOSE_PAREN); - active_ifs.pop (); - } - else - return; - } - token = peek (); + active_if->trueexpr = tem; + result = outermost_if; } + else + result = tem; + + push_simplify (kind, simplifiers, match, match_location, + result, token->src_loc); } /* Parsing of the outer control structures. */ @@ -3740,15 +3815,15 @@ parser::parse_operator_list (source_location) if = '(' 'if' '(' ')' ')' */ void -parser::parse_if (source_location loc) +parser::parse_if (source_location) { - operand *ifexpr = parse_c_expr (CPP_OPEN_PAREN); + c_expr *ifexpr = parse_c_expr (CPP_OPEN_PAREN); const cpp_token *token = peek (); if (token->type == CPP_CLOSE_PAREN) fatal_at (token, "no pattern defined in if"); - active_ifs.safe_push (if_or_with (ifexpr, loc, false)); + active_ifs.safe_push (ifexpr); while (1) { const cpp_token *token = peek (); @@ -3789,7 +3864,8 @@ parser::parse_pattern () const char *id = get_ident (); if (strcmp (id, "simplify") == 0) { - parse_simplify (token->src_loc, simplifiers, NULL, NULL); + parse_simplify (simplify::SIMPLIFY, + token->src_loc, simplifiers, NULL, NULL); capture_ids = NULL; } else if (strcmp (id, "match") == 0) @@ -3827,7 +3903,7 @@ parser::parse_pattern () || (!e && p->nargs != 0))) fatal_at (token, "non-matching number of match operands"); p->nargs = e ? e->ops.length () : 0; - parse_simplify (token->src_loc, p->matchers, p, e); + parse_simplify (simplify::MATCH, token->src_loc, p->matchers, p, e); capture_ids = NULL; } else if (strcmp (id, "for") == 0) diff --git a/gcc/match.pd b/gcc/match.pd index b991008b47f..8694854faa1 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -153,11 +153,10 @@ along with GCC; see the file COPYING3. If not see wide_int mul = wi::mul (@1, @2, TYPE_SIGN (type), &overflow_p); } (if (!overflow_p) - (div @0 { wide_int_to_tree (type, mul); })) - (if (overflow_p - && (TYPE_UNSIGNED (type) - || mul != wi::min_value (TYPE_PRECISION (type), SIGNED))) - { build_zero_cst (type); })))) + (div @0 { wide_int_to_tree (type, mul); }) + (if (TYPE_UNSIGNED (type) + || mul != wi::min_value (TYPE_PRECISION (type), SIGNED)) + { build_zero_cst (type); }))))) /* Optimize A / A to 1.0 if we don't care about NaNs or Infinities. */ @@ -203,11 +202,11 @@ along with GCC; see the file COPYING3. If not see (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; } ))))))) + (mult @0 { tem; } ))) + (if (cst != COMPLEX_CST) + (with { tree inverse = exact_inverse (type, @1); } + (if (inverse) + (mult @0 { inverse; } )))))))) /* Same applies to modulo operations, but fold is inconsistent here and simplifies 0 % x to 0, only preserving literal 0 % 0. */ @@ -908,11 +907,11 @@ along with GCC; see the file COPYING3. If not see 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) || code == 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); })))))) + (op @0 { build_int_cst (TREE_TYPE (@1), low % prec); }) + (if (TYPE_UNSIGNED (type) || code == 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); }))))))) /* ((1 << A) & 1) != 0 -> A == 0 @@ -933,10 +932,10 @@ along with GCC; see the file COPYING3. If not see (if (cand < 0 || (!integer_zerop (@2) && wi::ne_p (wi::lshift (@0, cand), @2))) - { constant_boolean_node (cmp == NE_EXPR, type); }) - (if (!integer_zerop (@2) - && wi::eq_p (wi::lshift (@0, cand), @2)) - (cmp @1 { build_int_cst (TREE_TYPE (@1), cand); }))))) + { constant_boolean_node (cmp == NE_EXPR, type); } + (if (!integer_zerop (@2) + && wi::eq_p (wi::lshift (@0, cand), @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)) @@ -1007,27 +1006,26 @@ along with GCC; see the file COPYING3. If not see } /* ((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 == (((unsigned HOST_WIDE_INT) 1) << prec) - 1) - break; - } - (if (prec < HOST_BITS_PER_WIDE_INT - || newmask == ~(unsigned HOST_WIDE_INT) 0) - (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; })) - (if (shift_type == TREE_TYPE (@3)) - (bit_and @4 { newmaskt; })))))))))))) + { 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 == (((unsigned HOST_WIDE_INT) 1) << prec) - 1) + break; + } + (if (prec < HOST_BITS_PER_WIDE_INT + || newmask == ~(unsigned HOST_WIDE_INT) 0) + (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; }))))))))))))) /* Fold (X & C2) << C1 into (X << C1) & (C2 << C1) (X & C2) >> C1 into (X >> C1) & (C2 >> C1). */ @@ -1119,7 +1117,7 @@ along with GCC; see the file COPYING3. If not see && (((inter_int || inter_ptr) && final_int) || (inter_float && final_float)) && inter_prec >= final_prec) - (ocvt @0)) + (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 @@ -1133,7 +1131,7 @@ along with GCC; see the file COPYING3. If not see && (inter_float || inter_unsignedp == inside_unsignedp) && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type)) && TYPE_MODE (type) == TYPE_MODE (inter_type))) - (ocvt @0)) + (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 @@ -1143,7 +1141,7 @@ along with GCC; see the file COPYING3. If not see && ((inside_prec < inter_prec && inter_prec < final_prec && inside_unsignedp && !inter_unsignedp) || final_prec == inter_prec)) - (ocvt @0)) + (ocvt @0) /* Two conversions in a row are not needed unless: - some conversion is floating-point (overstrict for now), or @@ -1168,7 +1166,7 @@ along with GCC; see the file COPYING3. If not see && ! (final_ptr && inside_prec != inter_prec) && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type)) && TYPE_MODE (type) == TYPE_MODE (inter_type))) - (ocvt @0)) + (ocvt @0) /* A truncation to an unsigned type (a zero-extension) should be canonicalized as bitwise and of a mask. */ @@ -1179,7 +1177,7 @@ along with GCC; see the file COPYING3. If not see (convert (bit_and @0 { wide_int_to_tree (inside_type, wi::mask (inter_prec, false, - TYPE_PRECISION (inside_type))); }))) + 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 @@ -1188,7 +1186,7 @@ along with GCC; see the file COPYING3. If not see && inside_int && inter_float && final_int && (unsigned) significand_size (TYPE_MODE (inter_type)) >= inside_prec - !inside_unsignedp) - (convert @0)))))) + (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 @@ -1281,20 +1279,17 @@ along with GCC; see the file COPYING3. If not see genmatch cannot handle. */ (simplify (cond INTEGER_CST@0 @1 @2) - (if (integer_zerop (@0) - && (!VOID_TYPE_P (TREE_TYPE (@2)) - || VOID_TYPE_P (type))) - @2) - (if (!integer_zerop (@0) - && (!VOID_TYPE_P (TREE_TYPE (@1)) - || VOID_TYPE_P (type))) - @1)) + (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)) + @1 + (if (integer_zerop (@0)) + @2))) (for cnd (cond vec_cond) /* A ? B : (A ? X : C) -> A ? B : C. */ @@ -1362,17 +1357,17 @@ along with GCC; see the file COPYING3. If not see (with { enum tree_code ic = invert_tree_comparison (cmp, HONOR_NANS (@0)); } (if (ic == icmp) - (icmp @0 @1)) - (if (ic == ncmp) - (ncmp @0 @1))))) + (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))))) + (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 @@ -1395,13 +1390,13 @@ along with GCC; see the file COPYING3. If not see (cmp (mult @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))) - /* If @1 is negative we swap the sense of the comparison. */ - (if (tree_int_cst_sgn (@1) < 0) - (scmp @0 @2)) - (cmp @0 @2)))) + (cmp @1 @2) + (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0)) + && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))) + /* If @1 is negative we swap the sense of the comparison. */ + (if (tree_int_cst_sgn (@1) < 0) + (scmp @0 @2) + (cmp @0 @2)))))) /* Simplify comparison of something with itself. For IEEE floating-point, we can only do some of these simplifications. */ @@ -1470,11 +1465,11 @@ along with GCC; see the file COPYING3. If not see /* 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); })) + (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); }) + { 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)))) @@ -1489,37 +1484,37 @@ along with GCC; see the file COPYING3. If not see /* x > +Inf is always false, if with ignore sNANs. */ (if (code == GT_EXPR && ! HONOR_SNANS (@0)) - { constant_boolean_node (false, type); }) + { 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)) + { 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); }))) + (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); }))) + (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); })))))) + (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 @@ -1557,13 +1552,13 @@ along with GCC; see the file COPYING3. If not see (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); }) + { 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); }) + { 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); })) + (ge @0 { build_real (TREE_TYPE (@0), dconst0); }))) (if (cmp == GT_EXPR || cmp == GE_EXPR) (with { @@ -1574,10 +1569,10 @@ along with GCC; see the file COPYING3. If not see (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); }))) + (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 { @@ -1589,30 +1584,30 @@ along with GCC; see the file COPYING3. If not see /* 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); }) + { 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); })) + (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); })) + (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); })))) + (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); })) + (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); }))))))))) + (cmp @0 { build_real (TREE_TYPE (@0), c2); }))))))))))))) /* Unordered tests if either argument is a NaN. */ (simplify @@ -1782,9 +1777,9 @@ along with GCC; see the file COPYING3. If not see && types_match (@0, @1) && types_match (@0, type)) (if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))) - (convert (op @0 @1))) - (with { tree utype = unsigned_type_for (TREE_TYPE (@0)); } - (convert (op (convert:utype @0) (convert:utype @1))))))) + (convert (op @0 @1)) + (with { tree utype = unsigned_type_for (TREE_TYPE (@0)); } + (convert (op (convert:utype @0) (convert:utype @1)))))))) /* 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 @@ -1792,32 +1787,31 @@ along with GCC; see the file COPYING3. If not see to unsigned types to avoid introducing undefined behaviour 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_PRECISION (TREE_TYPE (@0)) - == GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (@0)))) - && (TYPE_PRECISION (TREE_TYPE (@1)) - == GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (@1)))) - && TYPE_PRECISION (type) == GET_MODE_PRECISION (TYPE_MODE (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))) - && (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0)) - || tree_int_cst_sgn (@4) >= 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))))))) - + (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_PRECISION (TREE_TYPE (@0)) + == GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (@0)))) + && (TYPE_PRECISION (TREE_TYPE (@1)) + == GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (@1)))) + && TYPE_PRECISION (type) == GET_MODE_PRECISION (TYPE_MODE (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))) + && (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0)) + || tree_int_cst_sgn (@4) >= 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)))))))) -- 2.30.2