This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Teach genmatch.c to generate single-use restrictions from flags
- From: Richard Biener <rguenther at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 8 Jul 2015 16:39:14 +0200 (CEST)
- Subject: [PATCH] Teach genmatch.c to generate single-use restrictions from flags
- Authentication-results: sourceware.org; auth=none
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 <rguenther@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;