genmatch.c (struct operand): Add OP_IF and OP_WITH op_types.
2015-07-14 Richard Biener <rguenther@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. From-SVN: r225760
This commit is contained in:
parent
67a546ab45
commit
8fdc6c67ad
@ -1,3 +1,29 @@
|
||||
2015-07-14 Richard Biener <rguenther@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.
|
||||
|
||||
2015-07-13 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
* rtl.c (rtx_equal_p_cb): Fix typo.
|
||||
|
518
gcc/genmatch.c
518
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 <expr *>::test (operand *op)
|
||||
return op->type == operand::OP_EXPR;
|
||||
}
|
||||
|
||||
/* Helper to distinguish 'if' from 'with' expressions. */
|
||||
|
||||
struct if_or_with
|
||||
template<>
|
||||
template<>
|
||||
inline bool
|
||||
is_a_helper <if_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_IF;
|
||||
}
|
||||
|
||||
template<>
|
||||
template<>
|
||||
inline bool
|
||||
is_a_helper <with_expr *>::test (operand *op)
|
||||
{
|
||||
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<simplify *>& simplifiers)
|
||||
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<simplify *>& simplifiers)
|
||||
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 *>& simplifiers)
|
||||
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_base *with)
|
||||
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 *>& simplifiers)
|
||||
{
|
||||
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 *>& 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 <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, 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 <capture *> (o))
|
||||
{
|
||||
@ -1650,7 +1684,7 @@ capture_info::walk_result (operand *o, bool conditional_p)
|
||||
&& 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, 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 <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, 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 <with_expr *> (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.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");
|
||||
}
|
||||
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))
|
||||
{
|
||||
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, "else\n");
|
||||
fprintf_indent (f, indent + 2, "{\n");
|
||||
indent += 4;
|
||||
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, 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<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 *>& 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' <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 match_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 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' '(' <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)
|
||||
|
258
gcc/match.pd
258
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))))))))
|
||||
|
Loading…
Reference in New Issue
Block a user