From 44fc0a5136eea2fb4eb7d46a8065ee518f6eb575 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Thu, 9 Jul 2015 12:23:22 +0000 Subject: [PATCH] genmatch.c (struct expr): Add force_single_use flag. 2015-07-09 Richard Biener * genmatch.c (struct expr): Add force_single_use flag. (expr::expr): Add copy constructor. (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 most single_use conditionals to :s flags. From-SVN: r225610 --- gcc/ChangeLog | 13 +++++ gcc/genmatch.c | 155 +++++++++++++++++++++++++++++++++---------------- gcc/match.pd | 37 +++++------- 3 files changed, 132 insertions(+), 73 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4e81e8cce04..8e05c427c45 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2015-07-09 Richard Biener + + * genmatch.c (struct expr): Add force_single_use flag. + (expr::expr): Add copy constructor. + (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 most single_use conditionals to :s flags. + 2015-07-09 H.J. Lu * config/i386/iamcu.h (ASM_OUTPUT_ALIGNED_BSS): New. diff --git a/gcc/genmatch.c b/gcc/genmatch.c index 7ee6fb5b50f..15ce1f591bd 100644 --- a/gcc/genmatch.c +++ b/gcc/genmatch.c @@ -491,7 +491,11 @@ struct expr : public operand 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) {} + is_generic (false), force_single_use (false) {} + expr (expr *e) + : operand (OP_EXPR), operation (e->operation), + ops (vNULL), expr_type (e->expr_type), is_commutative (e->is_commutative), + is_generic (e->is_generic), force_single_use (e->force_single_use) {} void append_op (operand *op) { ops.safe_push (op); } /* The operator and its operands. */ id_base *operation; @@ -503,6 +507,9 @@ struct expr : public operand 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); @@ -747,7 +754,8 @@ commutate (operand *op) for (unsigned i = 0; i < result.length (); ++i) { - expr *ne = new expr (e->operation); + expr *ne = new expr (e); + ne->is_commutative = false; for (unsigned j = 0; j < result[i].length (); ++j) ne->append_op (result[i][j]); ret.safe_push (ne); @@ -758,7 +766,8 @@ commutate (operand *op) for (unsigned i = 0; i < result.length (); ++i) { - expr *ne = new expr (e->operation); + expr *ne = new expr (e); + ne->is_commutative = false; // 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]); @@ -809,14 +818,15 @@ lower_opt_convert (operand *o, enum tree_code oper, if (strip) return lower_opt_convert (e->ops[0], oper, to_oper, strip); - expr *ne = new expr (to_oper == CONVERT_EXPR - ? get_operator ("CONVERT_EXPR") - : get_operator ("VIEW_CONVERT_EXPR")); + expr *ne = new expr (e); + ne->operation = (to_oper == CONVERT_EXPR + ? get_operator ("CONVERT_EXPR") + : get_operator ("VIEW_CONVERT_EXPR")); ne->append_op (lower_opt_convert (e->ops[0], oper, to_oper, strip)); return ne; } - expr *ne = new expr (e->operation, e->is_commutative); + expr *ne = new expr (e); for (unsigned i = 0; i < e->ops.length (); ++i) ne->append_op (lower_opt_convert (e->ops[i], oper, to_oper, strip)); @@ -951,7 +961,7 @@ lower_cond (operand *o) for (unsigned i = 0; i < result.length (); ++i) { - expr *ne = new expr (e->operation); + expr *ne = new expr (e); for (unsigned j = 0; j < result[i].length (); ++j) ne->append_op (result[i][j]); ro.safe_push (ne); @@ -968,13 +978,13 @@ lower_cond (operand *o) || (is_a (e->ops[0]) && as_a (e->ops[0])->ops.length () == 2))) { - expr *ne = new expr (e->operation); + expr *ne = new expr (e); for (unsigned j = 0; j < result[i].length (); ++j) ne->append_op (result[i][j]); if (capture *c = dyn_cast (ne->ops[0])) { expr *ocmp = as_a (c->what); - expr *cmp = new expr (ocmp->operation); + expr *cmp = new expr (ocmp); for (unsigned j = 0; j < ocmp->ops.length (); ++j) cmp->append_op (ocmp->ops[j]); cmp->is_generic = true; @@ -983,7 +993,7 @@ lower_cond (operand *o) else { expr *ocmp = as_a (ne->ops[0]); - expr *cmp = new expr (ocmp->operation); + expr *cmp = new expr (ocmp); for (unsigned j = 0; j < ocmp->ops.length (); ++j) cmp->append_op (ocmp->ops[j]); cmp->is_generic = true; @@ -1027,9 +1037,9 @@ replace_id (operand *o, user_id *id, id_base *with) } else if (expr *e = dyn_cast (o)) { - expr *ne = new expr (e->operation == id ? with : e->operation, - e->is_commutative); - ne->expr_type = e->expr_type; + expr *ne = new expr (e); + if (e->operation == id) + ne->operation = with; for (unsigned i = 0; i < e->ops.length (); ++i) ne->append_op (replace_id (e->ops[i], id, with)); return ne; @@ -1513,6 +1523,7 @@ struct capture_info 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; @@ -1566,10 +1577,12 @@ capture_info::walk_match (operand *o, unsigned toplevel_arg, 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 - && is_a (c->what)) + && (e = dyn_cast (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); } } @@ -1808,9 +1821,9 @@ expr::gen_transform (FILE *f, const char *dest, bool gimple, int depth, 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", + 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, seq);\n" + 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" @@ -2449,27 +2462,52 @@ dt_simplify::gen (FILE *f, bool gimple) that cover cases we cannot handle. */ capture_info cinfo (s); expr *e; - if (!gimple - && s->result + if (s->result && !((e = dyn_cast (s->result)) && is_a (e->operation))) { - for (unsigned i = 0; i < as_a (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) + { + for (unsigned i = 0; i < as_a (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"); + bool first_p = true; + for (int i = 0; i <= s->capture_max; ++i) + if (cinfo.info[i].force_single_use) + { + if (first_p) + { + fprintf (f, "if (lseq\n" + "&& ("); + first_p = false; + } + else + fprintf (f, "\n|| "); + fprintf (f, "!single_use (captures[%d])", i); + } + if (!first_p) + fprintf (f, "))\n" + "lseq = NULL;\n"); + } } fprintf (f, "if (dump_file && (dump_flags & TDF_DETAILS)) " @@ -2524,7 +2562,7 @@ dt_simplify::gen (FILE *f, bool gimple) /* 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, " + fprintf (f, "gimple_resimplify%d (lseq, res_code, type, " "res_ops, valueize);\n", e->ops.length ()); } else if (result->type == operand::OP_CAPTURE @@ -3051,6 +3089,7 @@ parser::parse_expr () 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 @@ -3062,22 +3101,25 @@ parser::parse_expr () && !(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; - } + if (!parsing_match_operand) + expr_type = s; else - fatal_at (token, "flag %s not recognized", s); - + { + 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 @@ -3087,6 +3129,17 @@ parser::parse_expr () 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 diff --git a/gcc/match.pd b/gcc/match.pd index 5e8fd32ed22..b28f107be90 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -334,17 +334,15 @@ along with GCC; see the file COPYING3. If not see /* 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)))) + (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:c@2 @0 @1))) - (if (single_use (@2)) - (bitop @0 (bit_not @1))))) + (bitop:c @0 (bit_not (bitop:cs @0 @1))) + (bitop @0 (bit_not @1)))) /* (x | y) & ~x -> y & ~x */ /* (x & y) | ~x -> y | ~x */ @@ -633,17 +631,14 @@ along with GCC; see the file COPYING3. If not see /* (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))) + (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@2 @0 @1) @3) - (if (single_use (@2) - || (TREE_CODE (@1) == INTEGER_CST && TREE_CODE (@3) == INTEGER_CST)) - (pointer_plus @0 (plus @1 @3)))) + (pointer_plus (pointer_plus:s @0 @1) @3) + (pointer_plus @0 (plus @1 @3))) /* Pattern match tem1 = (long) ptr1; @@ -913,7 +908,8 @@ along with GCC; see the file COPYING3. If not see if the new mask might be further optimized. */ (for shift (lshift rshift) (simplify - (bit_and (convert?@4 (shift@5 (convert1?@3 @0) INTEGER_CST@1)) INTEGER_CST@2) + (bit_and (convert?:s@4 (shift:s@5 (convert1?@3 @0) INTEGER_CST@1)) + INTEGER_CST@2) (if (tree_nop_conversion_p (TREE_TYPE (@4), TREE_TYPE (@5)) && TYPE_PRECISION (type) <= HOST_BITS_PER_WIDE_INT && tree_fits_uhwi_p (@1) @@ -993,8 +989,7 @@ along with GCC; see the file COPYING3. If not see (with { tree newmaskt = build_int_cst_type (TREE_TYPE (@2), newmask); } (if (!tree_int_cst_equal (newmaskt, @2)) - (if (shift_type != TREE_TYPE (@3) - && single_use (@4) && single_use (@5)) + (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; })))))))))))) @@ -1733,7 +1728,7 @@ along with GCC; see the file COPYING3. If not see operation and convert the result to the desired type. */ (for op (plus minus) (simplify - (convert (op@4 (convert@2 @0) (convert@3 @1))) + (convert (op:s (convert@2 @0) (convert@3 @1))) (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. */ @@ -1750,8 +1745,7 @@ along with GCC; see the file COPYING3. If not see /* The inner conversion must be a widening conversion. */ && TYPE_PRECISION (TREE_TYPE (@2)) > TYPE_PRECISION (TREE_TYPE (@0)) && types_match (@0, @1) - && types_match (@0, type) - && single_use (@4)) + && types_match (@0, type)) (if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))) (convert (op @0 @1))) (with { tree utype = unsigned_type_for (TREE_TYPE (@0)); } @@ -1764,7 +1758,7 @@ along with GCC; see the file COPYING3. If not see arithmetic operation. */ (for op (minus plus) (simplify - (bit_and (op@5 (convert@2 @0) (convert@3 @1)) INTEGER_CST@4) + (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. */ @@ -1784,8 +1778,7 @@ along with GCC; see the file COPYING3. If not see && (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) - && single_use (@5)) + || 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)))))