This introduces a :s flag to match expressions which enforces the expression to have a single-use if(!) the simplified expression is larger than one statement.
Thus with that we for example allow tem = a + 1; x = tem - 3; foo (tem); to simplify to tem = a + 1; x = a - 2; foo (tem); and more importantly not require "hacks" like /* Associate (p +p off1) +p off2 as (p +p (off1 + off2)). */ (simplify ! (pointer_plus (pointer_plus@2 @0 @1) @3) ! (if (single_use (@2) ! || (TREE_CODE (@1) == INTEGER_CST && TREE_CODE (@3) == INTEGER_CST)) ! (pointer_plus @0 (plus @1 @3)))) to allow the simplification if (plus @1 @3) will simplify further. The trick is that generated code is changed like tree captures[4] ATTRIBUTE_UNUSED = {}; captures[0] = op0; captures[1] = o20; captures[2] = o21; captures[3] = op1; -/* #line 659 "/space/rguenther/tramp3d/trunk/gcc/match.pd" */ -if (single_use (captures[0]) || (TREE_CODE (captures[2]) == INTEGER_CST && TREE _CODE (captures[3]) == INTEGER_CST)) -{ +gimple_seq *lseq = seq; +if (!single_use (captures[0])) lseq = NULL; ... so in particular it disables all single-use restrictions if seq is NULL anyway (that is enough of a restriction already). Bootstrap / regtest running on x86_64-unknown-linux-gnu. Richard. 2015-07-08 Richard Biener <rguent...@suse.de> * genmatch.c (struct expr): Add force_single_use flag. (capture_info::walk_match): Gather force_single_use captures. (expr::gen_transform): Use possibly NULLified sequence. (dt_simplify::gen): Apply single-use restrictions by NULLifying seq if any constrained expr is not single-use. (parser::parse_expr): Refactor to allow multiple flags. Handle 's' flag to force an expression have a single-use if the pattern simplifies to more than one statement. * match.pd: Convert some single_use conditionals to :s flags. Index: gcc/genmatch.c =================================================================== *** gcc/genmatch.c (revision 225556) --- gcc/genmatch.c (working copy) *************** struct expr : public operand *** 491,497 **** expr (id_base *operation_, bool is_commutative_ = false) : operand (OP_EXPR), operation (operation_), ops (vNULL), expr_type (NULL), is_commutative (is_commutative_), ! is_generic (false) {} void append_op (operand *op) { ops.safe_push (op); } /* The operator and its operands. */ id_base *operation; --- 491,497 ---- expr (id_base *operation_, bool is_commutative_ = false) : operand (OP_EXPR), operation (operation_), ops (vNULL), expr_type (NULL), is_commutative (is_commutative_), ! is_generic (false), force_single_use (false) {} void append_op (operand *op) { ops.safe_push (op); } /* The operator and its operands. */ id_base *operation; *************** struct expr : public operand *** 503,508 **** --- 503,511 ---- bool is_commutative; /* Whether the expression is expected to be in GENERIC form. */ bool is_generic; + /* Whether pushing any stmt to the sequence should be conditional + on this expression having a single-use. */ + bool force_single_use; virtual void gen_transform (FILE *f, const char *, bool, int, const char *, capture_info *, dt_operand ** = 0, bool = true); *************** commutate (operand *op) *** 748,753 **** --- 751,757 ---- for (unsigned i = 0; i < result.length (); ++i) { expr *ne = new expr (e->operation); + ne->force_single_use = e->force_single_use; for (unsigned j = 0; j < result[i].length (); ++j) ne->append_op (result[i][j]); ret.safe_push (ne); *************** commutate (operand *op) *** 759,764 **** --- 763,769 ---- for (unsigned i = 0; i < result.length (); ++i) { expr *ne = new expr (e->operation); + ne->force_single_use = e->force_single_use; // result[i].length () is 2 since e->operation is binary for (unsigned j = result[i].length (); j; --j) ne->append_op (result[i][j-1]); *************** lower_opt_convert (operand *o, enum tree *** 812,822 **** --- 817,829 ---- expr *ne = new expr (to_oper == CONVERT_EXPR ? get_operator ("CONVERT_EXPR") : get_operator ("VIEW_CONVERT_EXPR")); + ne->force_single_use = e->force_single_use; ne->append_op (lower_opt_convert (e->ops[0], oper, to_oper, strip)); return ne; } expr *ne = new expr (e->operation, e->is_commutative); + ne->force_single_use = e->force_single_use; for (unsigned i = 0; i < e->ops.length (); ++i) ne->append_op (lower_opt_convert (e->ops[i], oper, to_oper, strip)); *************** lower_cond (operand *o) *** 952,957 **** --- 959,965 ---- for (unsigned i = 0; i < result.length (); ++i) { expr *ne = new expr (e->operation); + ne->force_single_use = e->force_single_use; for (unsigned j = 0; j < result[i].length (); ++j) ne->append_op (result[i][j]); ro.safe_push (ne); *************** lower_cond (operand *o) *** 969,980 **** --- 977,990 ---- && as_a <expr *> (e->ops[0])->ops.length () == 2))) { expr *ne = new expr (e->operation); + ne->force_single_use = e->force_single_use; for (unsigned j = 0; j < result[i].length (); ++j) ne->append_op (result[i][j]); if (capture *c = dyn_cast <capture *> (ne->ops[0])) { expr *ocmp = as_a <expr *> (c->what); expr *cmp = new expr (ocmp->operation); + cmp->force_single_use = ocmp->force_single_use; for (unsigned j = 0; j < ocmp->ops.length (); ++j) cmp->append_op (ocmp->ops[j]); cmp->is_generic = true; *************** lower_cond (operand *o) *** 984,989 **** --- 994,1000 ---- { expr *ocmp = as_a <expr *> (ne->ops[0]); expr *cmp = new expr (ocmp->operation); + cmp->force_single_use = ocmp->force_single_use; for (unsigned j = 0; j < ocmp->ops.length (); ++j) cmp->append_op (ocmp->ops[j]); cmp->is_generic = true; *************** replace_id (operand *o, user_id *id, id_ *** 1029,1034 **** --- 1040,1046 ---- { expr *ne = new expr (e->operation == id ? with : e->operation, e->is_commutative); + ne->force_single_use = e->force_single_use; ne->expr_type = e->expr_type; for (unsigned i = 0; i < e->ops.length (); ++i) ne->append_op (replace_id (e->ops[i], id, with)); *************** struct capture_info *** 1513,1518 **** --- 1525,1531 ---- bool expr_p; bool cse_p; bool force_no_side_effects_p; + bool force_single_use; bool cond_expr_cond_p; unsigned long toplevel_msk; int result_use_count; *************** capture_info::walk_match (operand *o, un *** 1566,1575 **** info[c->where].force_no_side_effects_p |= conditional_p; info[c->where].cond_expr_cond_p |= cond_expr_cond_p; /* Mark expr (non-leaf) captures and recurse. */ if (c->what ! && is_a <expr *> (c->what)) { info[c->where].expr_p = true; walk_match (c->what, toplevel_arg, conditional_p, false); } } --- 1579,1590 ---- info[c->where].force_no_side_effects_p |= conditional_p; info[c->where].cond_expr_cond_p |= cond_expr_cond_p; /* Mark expr (non-leaf) captures and recurse. */ + expr *e; if (c->what ! && (e = dyn_cast <expr *> (c->what))) { info[c->where].expr_p = true; + info[c->where].force_single_use |= e->force_single_use; walk_match (c->what, toplevel_arg, conditional_p, false); } } *************** expr::gen_transform (FILE *f, const char *** 1808,1816 **** for (unsigned i = 0; i < ops.length (); ++i) fprintf (f, "ops%d[%u]%s", depth, i, i == ops.length () - 1 ? " };\n" : ", "); ! fprintf (f, " gimple_resimplify%d (seq, &tem_code, %s, tem_ops, valueize);\n", ops.length (), type); ! fprintf (f, " res = maybe_push_res_to_seq (tem_code, %s, tem_ops, seq);\n" " if (!res) return false;\n", type); if (*operation == CONVERT_EXPR) fprintf (f, " }\n" --- 1823,1831 ---- for (unsigned i = 0; i < ops.length (); ++i) fprintf (f, "ops%d[%u]%s", depth, i, i == ops.length () - 1 ? " };\n" : ", "); ! fprintf (f, " gimple_resimplify%d (lseq, &tem_code, %s, tem_ops, valueize);\n", ops.length (), type); ! fprintf (f, " res = maybe_push_res_to_seq (tem_code, %s, tem_ops, lseq);\n" " if (!res) return false;\n", type); if (*operation == CONVERT_EXPR) fprintf (f, " }\n" *************** dt_simplify::gen (FILE *f, bool gimple) *** 2449,2475 **** that cover cases we cannot handle. */ capture_info cinfo (s); expr *e; ! if (!gimple ! && s->result && !((e = dyn_cast <expr *> (s->result)) && is_a <predicate_id *> (e->operation))) { ! for (unsigned i = 0; i < as_a <expr *> (s->match)->ops.length (); ++i) ! if (cinfo.force_no_side_effects & (1 << i)) ! fprintf (f, "if (TREE_SIDE_EFFECTS (op%d)) return NULL_TREE;\n", i); ! for (int i = 0; i <= s->capture_max; ++i) ! if (cinfo.info[i].cse_p) ! ; ! else if (cinfo.info[i].force_no_side_effects_p ! && (cinfo.info[i].toplevel_msk ! & cinfo.force_no_side_effects) == 0) ! fprintf (f, "if (TREE_SIDE_EFFECTS (captures[%d])) " ! "return NULL_TREE;\n", i); ! else if ((cinfo.info[i].toplevel_msk ! & cinfo.force_no_side_effects) != 0) ! /* Mark capture as having no side-effects if we had to verify ! that via forced toplevel operand checks. */ ! cinfo.info[i].force_no_side_effects_p = true; } fprintf (f, "if (dump_file && (dump_flags & TDF_DETAILS)) " --- 2464,2501 ---- 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))) { ! if (!gimple) ! { ! for (unsigned i = 0; i < as_a <expr *> (s->match)->ops.length (); ++i) ! if (cinfo.force_no_side_effects & (1 << i)) ! fprintf (f, "if (TREE_SIDE_EFFECTS (op%d)) return NULL_TREE;\n", i); ! for (int i = 0; i <= s->capture_max; ++i) ! if (cinfo.info[i].cse_p) ! ; ! else if (cinfo.info[i].force_no_side_effects_p ! && (cinfo.info[i].toplevel_msk ! & cinfo.force_no_side_effects) == 0) ! fprintf (f, "if (TREE_SIDE_EFFECTS (captures[%d])) " ! "return NULL_TREE;\n", i); ! else if ((cinfo.info[i].toplevel_msk ! & cinfo.force_no_side_effects) != 0) ! /* Mark capture as having no side-effects if we had to verify ! that via forced toplevel operand checks. */ ! cinfo.info[i].force_no_side_effects_p = true; ! } ! if (gimple) ! { ! /* Force single-use restriction by only allowing simple ! results via setting seq to NULL. */ ! fprintf (f, "gimple_seq *lseq = seq;\n"); ! for (int i = 0; i <= s->capture_max; ++i) ! if (cinfo.info[i].force_single_use) ! fprintf (f, "if (!single_use (captures[%d])) lseq = NULL;\n", i); ! } } fprintf (f, "if (dump_file && (dump_flags & TDF_DETAILS)) " *************** dt_simplify::gen (FILE *f, bool gimple) *** 2524,2530 **** /* Re-fold the toplevel result. It's basically an embedded gimple_build w/o actually building the stmt. */ if (!is_predicate) ! fprintf (f, "gimple_resimplify%d (seq, res_code, type, " "res_ops, valueize);\n", e->ops.length ()); } else if (result->type == operand::OP_CAPTURE --- 2550,2556 ---- /* Re-fold the toplevel result. It's basically an embedded gimple_build w/o actually building the stmt. */ if (!is_predicate) ! fprintf (f, "gimple_resimplify%d (lseq, res_code, type, " "res_ops, valueize);\n", e->ops.length ()); } else if (result->type == operand::OP_CAPTURE *************** parser::parse_expr () *** 3051,3056 **** --- 3077,3083 ---- const cpp_token *token = peek (); operand *op; bool is_commutative = false; + bool force_capture = false; const char *expr_type = NULL; if (token->type == CPP_COLON *************** parser::parse_expr () *** 3062,3083 **** && !(token->flags & PREV_WHITE)) { const char *s = get_ident (); ! if (s[0] == 'c' && !s[1]) { ! if (!parsing_match_operand) ! fatal_at (token, ! "flag 'c' can only be used in match expression"); ! is_commutative = true; ! } ! else if (s[1] != '\0') ! { ! if (parsing_match_operand) ! fatal_at (token, "type can only be used in result expression"); ! expr_type = s; } - else - fatal_at (token, "flag %s not recognized", s); - token = peek (); } else --- 3089,3113 ---- && !(token->flags & PREV_WHITE)) { const char *s = get_ident (); ! if (!parsing_match_operand) ! expr_type = s; ! else { ! const char *sp = s; ! while (*sp) ! { ! if (*sp == 'c') ! is_commutative = true; ! else if (*sp == 's') ! { ! e->force_single_use = true; ! force_capture = true; ! } ! else ! fatal_at (token, "flag %c not recognized", *sp); ! sp++; ! } } token = peek (); } else *************** parser::parse_expr () *** 3087,3092 **** --- 3117,3133 ---- if (token->type == CPP_ATSIGN && !(token->flags & PREV_WHITE)) op = parse_capture (e); + else if (force_capture) + { + unsigned num = capture_ids->elements (); + char id[8]; + bool existed; + sprintf (id, "__%u", num); + capture_ids->get_or_insert (xstrdup (id), &existed); + if (existed) + fatal_at (token, "reserved capture id '%s' already used", id); + op = new capture (num, e); + } else op = e; do Index: gcc/match.pd =================================================================== *** gcc/match.pd (revision 225556) --- gcc/match.pd (working copy) *************** (define_operator_list CBRT BUILT_IN_CBRT *** 334,350 **** /* x + (x & 1) -> (x + 1) & ~1 */ (simplify ! (plus:c @0 (bit_and@2 @0 integer_onep@1)) ! (if (single_use (@2)) ! (bit_and (plus @0 @1) (bit_not @1)))) /* x & ~(x & y) -> x & ~y */ /* x | ~(x | y) -> x | ~y */ (for bitop (bit_and bit_ior) (simplify ! (bitop:c @0 (bit_not (bitop:c@2 @0 @1))) ! (if (single_use (@2)) ! (bitop @0 (bit_not @1))))) /* (x | y) & ~x -> y & ~x */ /* (x & y) | ~x -> y | ~x */ --- 334,348 ---- /* x + (x & 1) -> (x + 1) & ~1 */ (simplify ! (plus:c @0 (bit_and:s @0 integer_onep@1)) ! (bit_and (plus @0 @1) (bit_not @1))) /* x & ~(x & y) -> x & ~y */ /* x | ~(x | y) -> x | ~y */ (for bitop (bit_and bit_ior) (simplify ! (bitop:c @0 (bit_not (bitop:cs @0 @1))) ! (bitop @0 (bit_not @1)))) /* (x | y) & ~x -> y & ~x */ /* (x & y) | ~x -> y | ~x */ *************** (define_operator_list CBRT BUILT_IN_CBRT *** 633,649 **** /* (x & ~m) | (y & m) -> ((x ^ y) & m) ^ x */ (simplify ! (bit_ior:c (bit_and:c@3 @0 (bit_not @2)) (bit_and:c@4 @1 @2)) ! (if (single_use (@3) && single_use (@4)) ! (bit_xor (bit_and (bit_xor @0 @1) @2) @0))) /* Associate (p +p off1) +p off2 as (p +p (off1 + off2)). */ (simplify ! (pointer_plus (pointer_plus@2 @0 @1) @3) ! (if (single_use (@2) ! || (TREE_CODE (@1) == INTEGER_CST && TREE_CODE (@3) == INTEGER_CST)) ! (pointer_plus @0 (plus @1 @3)))) /* Pattern match tem1 = (long) ptr1; --- 631,644 ---- /* (x & ~m) | (y & m) -> ((x ^ y) & m) ^ x */ (simplify ! (bit_ior:c (bit_and:cs @0 (bit_not @2)) (bit_and:cs @1 @2)) ! (bit_xor (bit_and (bit_xor @0 @1) @2) @0)) /* Associate (p +p off1) +p off2 as (p +p (off1 + off2)). */ (simplify ! (pointer_plus (pointer_plus:s@2 @0 @1) @3) ! (pointer_plus @0 (plus @1 @3))) /* Pattern match tem1 = (long) ptr1;