The following patch fixes a subtle issue with how (if ...) is currently operating. Take
/* Transform comparisons of the form X * C1 CMP 0 to X CMP 0 in the signed arithmetic case. That form is created by the compiler often enough for folding it to be of value. One example is in computing loop trip counts after Operator Strength Reduction. */ (for cmp (simple_comparison) scmp (swapped_simple_comparison) (simplify (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)))) as an example. Currently there is no "else" arm implemented because of an implementation detail. That implementation detail is that currently the above is equivalent to three separate simplify patterns, each collecting 'if's from their final result expression. Thus, (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)) and (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0)) && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))) (cmp @0 @2)))) and the fact that the last one is "mostly" equivalent to (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0)) && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))) (if (!(tree_int_cst_sgn (@1) < 0)) (cmp @0 @2)))) is just because the first one is guaranteed to match first - _if_ it matches. Matching can fail due to various reasons though and it is not always obvious whether the fallthru is really equivalent to an else. Lack of an explicit else was also pointed out as a missing feature. The following patch fixes the above implementation detail and keeps a single 'simplify' for the whole if/with expression tree (thus also not duplicating common ifs and withs). It adds an explicit else and removes the ability to "sequence" stuff via the fallthru. Thus the above pattern now becomes /* Transform comparisons of the form X * C1 CMP 0 to X CMP 0 in the signed arithmetic case. That form is created by the compiler often enough for folding it to be of value. One example is in computing loop trip counts after Operator Strength Reduction. */ (for cmp (simple_comparison) scmp (swapped_simple_comparison) (simplify (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)))))) as the new if syntax is (if (cond-expr) (then-expr) [(else-expr)]) with the else-expr being optional. Note that writing (if (cond1) (bla)) (if (cond2) (foo)) (if (cond3) (baz)) is no longer supported (I might introduce that again as followup with explicitely denoting this as 'switch/case' list). This means touching quite a few patterns in match.pd. Most cases simply didn't continue parsing but the following one for example has different meaning before and after: (if (cond1) (if (cond2) (expr1)) (expr2)) now expr2 is guarded by !cond1 while formerly it was guarded by cond1. Anticipating 'switch/case' support I have not re-indented the cases of large (if ..) (else if ...) (else if ...) forms. As this now keeps the if/with expression tree doing further simplifications to make the generated code smaller should now be easier. Bootstrapped on x86_64-unknown-linux-gnu, testing in progress. Richard. 2015-07-13 Richard Biener <rguent...@suse.de> * 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. Index: gcc/genmatch.c =================================================================== --- gcc/genmatch.c (revision 225727) +++ gcc/genmatch.c (working copy) @@ -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 <expr *>::test (operand *op) return op->type == operand::OP_EXPR; } -/* Helper to distinguish 'if' from 'with' expressions. */ +template<> +template<> +inline bool +is_a_helper <if_expr *>::test (operand *op) +{ + return op->type == operand::OP_IF; +} -struct if_or_with +template<> +template<> +inline bool +is_a_helper <with_expr *>::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<if_or_with> ifexpr_vec_, vec<vec<user_id *> > for_vec_, - cid_map_t *capture_ids_) - : match (match_), match_location (match_location_), + vec<vec<user_id *> > 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<if_or_with> ifexpr_vec; /* Collected 'for' expression operators that have to be replaced in the lowering phase. */ vec<vec<user_id *> > for_vec; @@ -803,8 +829,8 @@ lower_commutative (simplify *s, vec<simp vec<operand *> 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<simp vec<operand *> 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<simplify *> vec<operand *> 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_ ne->append_op (replace_id (e->ops[i], id, with)); return ne; } + else if (with_expr *w = dyn_cast <with_expr *> (o)) + { + with_expr *nw = new with_expr (); + nw->with = as_a <c_expr *> (replace_id (w->with, id, with)); + nw->subexpr = replace_id (w->subexpr, id, with); + return nw; + } + else if (if_expr *ife = dyn_cast <if_expr *> (o)) + { + if_expr *nife = new if_expr (); + nife->cond = as_a <c_expr *> (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<simplify * { operand *match_op = s->match; operand *result_op = s->result; - vec<if_or_with> 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<simplify * 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 <expr *> (s->result)) - && is_a <predicate_id *> (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 <c_expr *>(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, un 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 <capture *> (o)) { @@ -1650,7 +1684,7 @@ capture_info::walk_result (operand *o, b && is_a <expr *> (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 <expr *> (o)) @@ -1663,13 +1697,49 @@ capture_info::walk_result (operand *o, b 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 <if_expr *> (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 <if_expr *> (e->trueexpr) + || is_a <with_expr *> (e->trueexpr)) + res |= walk_result (e->trueexpr, false, result); + if (e->falseexpr + && (is_a <if_expr *> (e->falseexpr) + || is_a <with_expr *> (e->falseexpr))) + res |= walk_result (e->falseexpr, false, result); + return res; + } + else if (with_expr *e = dyn_cast <with_expr *> (o)) + { + bool res = (e->subexpr == result); + if (res + || is_a <if_expr *> (e->subexpr) + || is_a <with_expr *> (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 <c_expr *> (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, bo } - /* 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 <with_expr *> (result)) + { + 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 <if_expr *> (result)) { - if_or_with &w = s->ifexpr_vec[i]; - if (w.is_with) + 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 <expr *> (s->result)) - && is_a <predicate_id *> (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, b 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, b { 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, b 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<simplify *>&, operand *, source_location, + operand *parse_result (operand *, predicate_id *); + void push_simplify (simplify::simplify_kind, + vec<simplify *>&, operand *, source_location, operand *, source_location); - void parse_simplify (source_location, vec<simplify *>&, predicate_id *, - expr *); + void parse_simplify (simplify::simplify_kind, + source_location, vec<simplify *>&, 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<if_or_with> active_ifs; + vec<c_expr *> active_ifs; vec<vec<user_id *> > active_fors; hash_set<user_id *> *oper_lists_set; vec<user_id *> 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<simplify *>& simplifiers, +parser::push_simplify (simplify::simplify_kind kind, + vec<simplify *>& simplifiers, operand *match, source_location match_loc, operand *result, source_location result_loc) { @@ -3434,27 +3494,90 @@ parser::push_simplify (vec<simplify *>& 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' <expr> <result-op> - or - match = 'match' <ident> <expr> [<result-op>] - with <result-op> = <op> | <if> | <with> <if> = '(' 'if' '(' <c-expr> ')' <result-op> ')' <with> = '(' 'with' '{' <c-expr> '}' <result-op> ')' + 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' <expr> <result-op> + or + match = 'match' <ident> <expr> [<result-op>] 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<simplify *>& simplifiers, predicate_id *matcher, - expr *result) + operand *result) { /* Reset the capture map. */ if (!capture_ids) @@ -3474,6 +3597,20 @@ parser::parse_simplify (source_location && is_a <predicate_id *> (as_a <expr *> (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 <if_expr *> (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 { 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_loca if = '(' 'if' '(' <c-expr> ')' <pattern> ')' */ 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) Index: gcc/match.pd =================================================================== --- gcc/match.pd (revision 225727) +++ gcc/match.pd (working copy) @@ -153,11 +153,10 @@ (define_operator_list CBRT BUILT_IN_CBRT 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 @@ (define_operator_list CBRT BUILT_IN_CBRT (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 @@ (define_operator_list CBRT BUILT_IN_CBRT 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 @@ (define_operator_list CBRT BUILT_IN_CBRT (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 @@ (define_operator_list CBRT BUILT_IN_CBRT } /* ((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 @@ (define_operator_list CBRT BUILT_IN_CBRT && (((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 @@ (define_operator_list CBRT BUILT_IN_CBRT && (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 @@ (define_operator_list CBRT BUILT_IN_CBRT && ((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 @@ (define_operator_list CBRT BUILT_IN_CBRT && ! (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 @@ (define_operator_list CBRT BUILT_IN_CBRT (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 @@ (define_operator_list CBRT BUILT_IN_CBRT && 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 @@ (define_operator_list CBRT BUILT_IN_CBRT 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 @@ (define_operator_list CBRT BUILT_IN_CBRT (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 @@ (define_operator_list CBRT BUILT_IN_CBRT (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 @@ (define_operator_list CBRT BUILT_IN_CBRT /* 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 @@ (define_operator_list CBRT BUILT_IN_CBRT /* 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 @@ (define_operator_list CBRT BUILT_IN_CBRT (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 @@ (define_operator_list CBRT BUILT_IN_CBRT (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 @@ (define_operator_list CBRT BUILT_IN_CBRT /* 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 @@ (define_operator_list CBRT BUILT_IN_CBRT && 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 @@ (define_operator_list CBRT BUILT_IN_CBRT 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))))))))