Commit 8fdc6c67 by Richard Biener Committed by Richard Biener

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
parent 67a546ab
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> 2015-07-13 Marek Polacek <polacek@redhat.com>
* rtl.c (rtx_equal_p_cb): Fix typo. * rtl.c (rtx_equal_p_cb): Fix typo.
......
...@@ -482,7 +482,7 @@ struct capture_info; ...@@ -482,7 +482,7 @@ struct capture_info;
/* The base class for operands. */ /* The base class for operands. */
struct operand { 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_) {} operand (enum op_type type_) : type (type_) {}
enum op_type type; enum op_type type;
virtual void gen_transform (FILE *, int, const char *, bool, int, virtual void gen_transform (FILE *, int, const char *, bool, int,
...@@ -578,6 +578,26 @@ struct capture : public operand ...@@ -578,6 +578,26 @@ struct capture : public operand
dt_operand ** = 0, bool = true); 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<>
template<> template<>
inline bool inline bool
...@@ -610,16 +630,21 @@ is_a_helper <expr *>::test (operand *op) ...@@ -610,16 +630,21 @@ is_a_helper <expr *>::test (operand *op)
return op->type == operand::OP_EXPR; return op->type == operand::OP_EXPR;
} }
/* Helper to distinguish 'if' from 'with' expressions. */ template<>
template<>
inline bool
is_a_helper <if_expr *>::test (operand *op)
{
return op->type == operand::OP_IF;
}
struct if_or_with template<>
template<>
inline bool
is_a_helper <with_expr *>::test (operand *op)
{ {
if_or_with (operand *cexpr_, source_location location_, bool is_with_) return op->type == operand::OP_WITH;
: location (location_), cexpr (cexpr_), is_with (is_with_) {} }
source_location location;
operand *cexpr;
bool is_with;
};
/* The main class of a pattern and its transform. This is used to /* The main class of a pattern and its transform. This is used to
represent both (simplify ...) and (match ...) kinds. The AST represent both (simplify ...) and (match ...) kinds. The AST
...@@ -628,26 +653,27 @@ struct if_or_with ...@@ -628,26 +653,27 @@ struct if_or_with
struct simplify 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_, struct operand *result_, source_location result_location_,
vec<if_or_with> ifexpr_vec_, vec<vec<user_id *> > for_vec_, vec<vec<user_id *> > for_vec_, cid_map_t *capture_ids_)
cid_map_t *capture_ids_) : kind (kind_), match (match_), match_location (match_location_),
: match (match_), match_location (match_location_),
result (result_), result_location (result_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) {} capture_ids (capture_ids_), capture_max (capture_ids_->elements () - 1) {}
simplify_kind kind;
/* The expression that is matched against the GENERIC or GIMPLE IL. */ /* The expression that is matched against the GENERIC or GIMPLE IL. */
operand *match; operand *match;
source_location match_location; source_location match_location;
/* For a (simplify ...) the expression produced when the pattern applies. /* For a (simplify ...) an expression with ifs and withs with the expression
For a (match ...) either NULL if it is a simple predicate or the produced when the pattern applies in the leafs.
single expression specifying the matched operands. */ 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; struct operand *result;
source_location result_location; 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 /* Collected 'for' expression operators that have to be replaced
in the lowering phase. */ in the lowering phase. */
vec<vec<user_id *> > for_vec; vec<vec<user_id *> > for_vec;
...@@ -803,8 +829,8 @@ lower_commutative (simplify *s, vec<simplify *>& simplifiers) ...@@ -803,8 +829,8 @@ lower_commutative (simplify *s, vec<simplify *>& simplifiers)
vec<operand *> matchers = commutate (s->match); vec<operand *> matchers = commutate (s->match);
for (unsigned i = 0; i < matchers.length (); ++i) for (unsigned i = 0; i < matchers.length (); ++i)
{ {
simplify *ns = new simplify (matchers[i], s->match_location, simplify *ns = new simplify (s->kind, matchers[i], s->match_location,
s->result, s->result_location, s->ifexpr_vec, s->result, s->result_location,
s->for_vec, s->capture_ids); s->for_vec, s->capture_ids);
simplifiers.safe_push (ns); simplifiers.safe_push (ns);
} }
...@@ -932,8 +958,8 @@ lower_opt_convert (simplify *s, vec<simplify *>& simplifiers) ...@@ -932,8 +958,8 @@ lower_opt_convert (simplify *s, vec<simplify *>& simplifiers)
vec<operand *> matchers = lower_opt_convert (s->match); vec<operand *> matchers = lower_opt_convert (s->match);
for (unsigned i = 0; i < matchers.length (); ++i) for (unsigned i = 0; i < matchers.length (); ++i)
{ {
simplify *ns = new simplify (matchers[i], s->match_location, simplify *ns = new simplify (s->kind, matchers[i], s->match_location,
s->result, s->result_location, s->ifexpr_vec, s->result, s->result_location,
s->for_vec, s->capture_ids); s->for_vec, s->capture_ids);
simplifiers.safe_push (ns); simplifiers.safe_push (ns);
} }
...@@ -1032,8 +1058,8 @@ lower_cond (simplify *s, vec<simplify *>& simplifiers) ...@@ -1032,8 +1058,8 @@ lower_cond (simplify *s, vec<simplify *>& simplifiers)
vec<operand *> matchers = lower_cond (s->match); vec<operand *> matchers = lower_cond (s->match);
for (unsigned i = 0; i < matchers.length (); ++i) for (unsigned i = 0; i < matchers.length (); ++i)
{ {
simplify *ns = new simplify (matchers[i], s->match_location, simplify *ns = new simplify (s->kind, matchers[i], s->match_location,
s->result, s->result_location, s->ifexpr_vec, s->result, s->result_location,
s->for_vec, s->capture_ids); s->for_vec, s->capture_ids);
simplifiers.safe_push (ns); simplifiers.safe_push (ns);
} }
...@@ -1061,6 +1087,22 @@ replace_id (operand *o, user_id *id, id_base *with) ...@@ -1061,6 +1087,22 @@ replace_id (operand *o, user_id *id, id_base *with)
ne->append_op (replace_id (e->ops[i], id, with)); ne->append_op (replace_id (e->ops[i], id, with));
return ne; 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 /* For c_expr we simply record a string replacement table which is
applied at code-generation time. */ applied at code-generation time. */
...@@ -1105,8 +1147,6 @@ lower_for (simplify *sin, vec<simplify *>& simplifiers) ...@@ -1105,8 +1147,6 @@ lower_for (simplify *sin, vec<simplify *>& simplifiers)
{ {
operand *match_op = s->match; operand *match_op = s->match;
operand *result_op = s->result; operand *result_op = s->result;
vec<if_or_with> ifexpr_vec = s->ifexpr_vec.copy ();
for (unsigned i = 0; i < n_ids; ++i) for (unsigned i = 0; i < n_ids; ++i)
{ {
user_id *id = ids[i]; user_id *id = ids[i];
...@@ -1114,13 +1154,10 @@ lower_for (simplify *sin, vec<simplify *>& simplifiers) ...@@ -1114,13 +1154,10 @@ lower_for (simplify *sin, vec<simplify *>& simplifiers)
match_op = replace_id (match_op, id, oper); match_op = replace_id (match_op, id, oper);
if (result_op) if (result_op)
result_op = replace_id (result_op, id, oper); 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, result_op, s->result_location,
ifexpr_vec, vNULL, s->capture_ids); vNULL, s->capture_ids);
worklist.safe_push (ns); worklist.safe_push (ns);
} }
} }
...@@ -1228,6 +1265,7 @@ struct dt_simplify : public dt_node ...@@ -1228,6 +1265,7 @@ struct dt_simplify : public dt_node
: dt_node (DT_SIMPLIFY), s (s_), pattern_no (pattern_no_), : dt_node (DT_SIMPLIFY), s (s_), pattern_no (pattern_no_),
indexes (indexes_) {} indexes (indexes_) {}
void gen_1 (FILE *, int, bool, operand *);
void gen (FILE *f, int, bool); void gen (FILE *f, int, bool);
}; };
...@@ -1530,9 +1568,9 @@ decision_tree::print (FILE *f) ...@@ -1530,9 +1568,9 @@ decision_tree::print (FILE *f)
struct capture_info struct capture_info
{ {
capture_info (simplify *s); capture_info (simplify *s, operand *);
void walk_match (operand *o, unsigned toplevel_arg, bool, bool); 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 *); void walk_c_expr (c_expr *);
struct cinfo struct cinfo
...@@ -1552,12 +1590,10 @@ struct capture_info ...@@ -1552,12 +1590,10 @@ struct capture_info
/* Analyze captures in S. */ /* Analyze captures in S. */
capture_info::capture_info (simplify *s) capture_info::capture_info (simplify *s, operand *result)
{ {
expr *e; expr *e;
if (!s->result if (s->kind == simplify::MATCH)
|| ((e = dyn_cast <expr *> (s->result))
&& is_a <predicate_id *> (e->operation)))
{ {
force_no_side_effects = -1; force_no_side_effects = -1;
return; return;
...@@ -1575,11 +1611,7 @@ capture_info::capture_info (simplify *s) ...@@ -1575,11 +1611,7 @@ capture_info::capture_info (simplify *s)
&& (*e->operation == COND_EXPR && (*e->operation == COND_EXPR
|| *e->operation == VEC_COND_EXPR)); || *e->operation == VEC_COND_EXPR));
walk_result (s->result, false); walk_result (s->result, false, result);
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));
} }
/* Analyze captures in the match expression piece O. */ /* Analyze captures in the match expression piece O. */
...@@ -1630,10 +1662,12 @@ capture_info::walk_match (operand *o, unsigned toplevel_arg, ...@@ -1630,10 +1662,12 @@ capture_info::walk_match (operand *o, unsigned toplevel_arg,
gcc_unreachable (); 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 bool
capture_info::walk_result (operand *o, bool conditional_p) capture_info::walk_result (operand *o, bool conditional_p, operand *result)
{ {
if (capture *c = dyn_cast <capture *> (o)) if (capture *c = dyn_cast <capture *> (o))
{ {
...@@ -1650,7 +1684,7 @@ capture_info::walk_result (operand *o, bool conditional_p) ...@@ -1650,7 +1684,7 @@ capture_info::walk_result (operand *o, bool conditional_p)
&& is_a <expr *> (c->what)) && is_a <expr *> (c->what))
{ {
info[c->where].cse_p = true; 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)) else if (expr *e = dyn_cast <expr *> (o))
...@@ -1663,13 +1697,49 @@ capture_info::walk_result (operand *o, bool conditional_p) ...@@ -1663,13 +1697,49 @@ capture_info::walk_result (operand *o, bool conditional_p)
else if (*e->operation == TRUTH_ANDIF_EXPR else if (*e->operation == TRUTH_ANDIF_EXPR
|| *e->operation == TRUTH_ORIF_EXPR) || *e->operation == TRUTH_ORIF_EXPR)
cond_p = true; 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)) else if (c_expr *e = dyn_cast <c_expr *> (o))
walk_c_expr (e); walk_c_expr (e);
else else
gcc_unreachable (); gcc_unreachable ();
return false;
} }
/* Look for captures in the C expr E. */ /* Look for captures in the C expr E. */
...@@ -2487,87 +2557,55 @@ dt_operand::gen (FILE *f, int indent, bool gimple) ...@@ -2487,87 +2557,55 @@ dt_operand::gen (FILE *f, int indent, bool gimple)
} }
/* Generate code for the '(if ...)', '(with ..)' and actual transform /* Generate code for the '(if ...)', '(with ..)' and actual transform
step of a '(simplify ...)' or '(match ...)'. This handles everything 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 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"); if (result)
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)
{ {
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]; fprintf_indent (f, indent, "{\n");
if (w.is_with) 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, "{\n"); fprintf_indent (f, indent, "else\n");
fprintf_indent (f, indent + 2, "{\n");
indent += 4; indent += 4;
output_line_directive (f, w.location); gen_1 (f, indent, gimple, ife->falseexpr);
w.cexpr->gen_transform (f, indent, NULL, true, 1, "type", NULL); indent -= 4;
n_braces++; fprintf_indent (f, indent + 2, "}\n");
}
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");
} }
return;
} }
fprintf_indent (f, indent + 2, "{\n");
indent += 4;
n_braces++;
} }
/* Analyze captures and perform early-outs on the incoming arguments /* Analyze captures and perform early-outs on the incoming arguments
that cover cases we cannot handle. */ that cover cases we cannot handle. */
capture_info cinfo (s); capture_info cinfo (s, result);
expr *e; if (s->kind == simplify::SIMPLIFY)
if (s->result
&& !((e = dyn_cast <expr *> (s->result))
&& is_a <predicate_id *> (e->operation)))
{ {
if (!gimple) if (!gimple)
{ {
...@@ -2626,7 +2664,6 @@ dt_simplify::gen (FILE *f, int indent, bool gimple) ...@@ -2626,7 +2664,6 @@ dt_simplify::gen (FILE *f, int indent, bool gimple)
output_line_directive (f, s->result_location, true); output_line_directive (f, s->result_location, true);
fprintf (f, ", %%s:%%d\\n\", __FILE__, __LINE__);\n"); fprintf (f, ", %%s:%%d\\n\", __FILE__, __LINE__);\n");
operand *result = s->result;
if (!result) if (!result)
{ {
/* If there is no result then this is a predicate implementation. */ /* If there is no result then this is a predicate implementation. */
...@@ -2782,7 +2819,7 @@ dt_simplify::gen (FILE *f, int indent, bool gimple) ...@@ -2782,7 +2819,7 @@ dt_simplify::gen (FILE *f, int indent, bool gimple)
{ {
fprintf_indent (f, indent, "tree res;\n"); 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); &cinfo, indexes);
} }
else else
...@@ -2809,12 +2846,31 @@ dt_simplify::gen (FILE *f, int indent, bool gimple) ...@@ -2809,12 +2846,31 @@ dt_simplify::gen (FILE *f, int indent, bool gimple)
fprintf_indent (f, indent, "return res;\n"); fprintf_indent (f, indent, "return res;\n");
} }
} }
}
for (unsigned i = 0; i < n_braces; ++i) /* Generate code for the '(if ...)', '(with ..)' and actual transform
{ step of a '(simplify ...)' or '(match ...)'. This handles everything
fprintf_indent (f, indent - 2, "}\n"); that is not part of the decision tree (simplify->match). */
indent -= 4;
} 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; indent -= 2;
fprintf_indent (f, indent, "}\n"); fprintf_indent (f, indent, "}\n");
...@@ -2976,17 +3032,20 @@ private: ...@@ -2976,17 +3032,20 @@ private:
void record_operlist (source_location, user_id *); void record_operlist (source_location, user_id *);
void parse_pattern (); 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); operand *, source_location);
void parse_simplify (source_location, vec<simplify *>&, predicate_id *, void parse_simplify (simplify::simplify_kind,
expr *); source_location, vec<simplify *>&, predicate_id *,
operand *);
void parse_for (source_location); void parse_for (source_location);
void parse_if (source_location); void parse_if (source_location);
void parse_predicates (source_location); void parse_predicates (source_location);
void parse_operator_list (source_location); void parse_operator_list (source_location);
cpp_reader *r; cpp_reader *r;
vec<if_or_with> active_ifs; vec<c_expr *> active_ifs;
vec<vec<user_id *> > active_fors; vec<vec<user_id *> > active_fors;
hash_set<user_id *> *oper_lists_set; hash_set<user_id *> *oper_lists_set;
vec<user_id *> oper_lists; vec<user_id *> oper_lists;
...@@ -3425,7 +3484,8 @@ parser::parse_op () ...@@ -3425,7 +3484,8 @@ parser::parse_op ()
MATCH_LOC, RESULT and RESULT_LOC and push it to SIMPLIFIERS. */ MATCH_LOC, RESULT and RESULT_LOC and push it to SIMPLIFIERS. */
void void
parser::push_simplify (vec<simplify *>& simplifiers, parser::push_simplify (simplify::simplify_kind kind,
vec<simplify *>& simplifiers,
operand *match, source_location match_loc, operand *match, source_location match_loc,
operand *result, source_location result_loc) operand *result, source_location result_loc)
{ {
...@@ -3434,27 +3494,90 @@ parser::push_simplify (vec<simplify *>& simplifiers, ...@@ -3434,27 +3494,90 @@ parser::push_simplify (vec<simplify *>& simplifiers,
active_fors.safe_push (oper_lists); active_fors.safe_push (oper_lists);
simplifiers.safe_push simplifiers.safe_push
(new simplify (match, match_loc, result, result_loc, (new simplify (kind, match, match_loc, result, result_loc,
active_ifs.copy (), active_fors.copy (), capture_ids)); active_fors.copy (), capture_ids));
if (!oper_lists.is_empty ()) if (!oper_lists.is_empty ())
active_fors.pop (); active_fors.pop ();
} }
/* Parse /* Parse
simplify = 'simplify' <expr> <result-op>
or
match = 'match' <ident> <expr> [<result-op>]
with
<result-op> = <op> | <if> | <with> <result-op> = <op> | <if> | <with>
<if> = '(' 'if' '(' <c-expr> ')' <result-op> ')' <if> = '(' 'if' '(' <c-expr> ')' <result-op> ')'
<with> = '(' 'with' '{' <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. */ and fill SIMPLIFIERS with the results. */
void 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, vec<simplify *>& simplifiers, predicate_id *matcher,
expr *result) operand *result)
{ {
/* Reset the capture map. */ /* Reset the capture map. */
if (!capture_ids) if (!capture_ids)
...@@ -3474,6 +3597,20 @@ parser::parse_simplify (source_location match_location, ...@@ -3474,6 +3597,20 @@ parser::parse_simplify (source_location match_location,
&& is_a <predicate_id *> (as_a <expr *> (match)->operation)) && is_a <predicate_id *> (as_a <expr *> (match)->operation))
fatal_at (loc, "outermost expression cannot be a predicate"); 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 (); const cpp_token *token = peek ();
/* If this if is immediately closed then it is part of a predicate /* If this if is immediately closed then it is part of a predicate
...@@ -3482,89 +3619,27 @@ parser::parse_simplify (source_location match_location, ...@@ -3482,89 +3619,27 @@ parser::parse_simplify (source_location match_location,
{ {
if (!matcher) if (!matcher)
fatal_at (token, "expected transform expression"); 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); result, token->src_loc);
return; return;
} }
unsigned active_ifs_len = active_ifs.length (); operand *tem = parse_result (result, matcher);
while (1) if (active_if)
{ {
if (token->type == CPP_OPEN_PAREN) active_if->trueexpr = tem;
{ result = outermost_if;
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 ();
} }
else
result = tem;
push_simplify (kind, simplifiers, match, match_location,
result, token->src_loc);
} }
/* Parsing of the outer control structures. */ /* Parsing of the outer control structures. */
...@@ -3740,15 +3815,15 @@ parser::parse_operator_list (source_location) ...@@ -3740,15 +3815,15 @@ parser::parse_operator_list (source_location)
if = '(' 'if' '(' <c-expr> ')' <pattern> ')' */ if = '(' 'if' '(' <c-expr> ')' <pattern> ')' */
void 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 (); const cpp_token *token = peek ();
if (token->type == CPP_CLOSE_PAREN) if (token->type == CPP_CLOSE_PAREN)
fatal_at (token, "no pattern defined in if"); 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) while (1)
{ {
const cpp_token *token = peek (); const cpp_token *token = peek ();
...@@ -3789,7 +3864,8 @@ parser::parse_pattern () ...@@ -3789,7 +3864,8 @@ parser::parse_pattern ()
const char *id = get_ident (); const char *id = get_ident ();
if (strcmp (id, "simplify") == 0) 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; capture_ids = NULL;
} }
else if (strcmp (id, "match") == 0) else if (strcmp (id, "match") == 0)
...@@ -3827,7 +3903,7 @@ parser::parse_pattern () ...@@ -3827,7 +3903,7 @@ parser::parse_pattern ()
|| (!e && p->nargs != 0))) || (!e && p->nargs != 0)))
fatal_at (token, "non-matching number of match operands"); fatal_at (token, "non-matching number of match operands");
p->nargs = e ? e->ops.length () : 0; 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; capture_ids = NULL;
} }
else if (strcmp (id, "for") == 0) else if (strcmp (id, "for") == 0)
......
...@@ -153,11 +153,10 @@ along with GCC; see the file COPYING3. If not see ...@@ -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); wide_int mul = wi::mul (@1, @2, TYPE_SIGN (type), &overflow_p);
} }
(if (!overflow_p) (if (!overflow_p)
(div @0 { wide_int_to_tree (type, mul); })) (div @0 { wide_int_to_tree (type, mul); })
(if (overflow_p (if (TYPE_UNSIGNED (type)
&& (TYPE_UNSIGNED (type) || mul != wi::min_value (TYPE_PRECISION (type), SIGNED))
|| mul != wi::min_value (TYPE_PRECISION (type), SIGNED))) { build_zero_cst (type); })))))
{ build_zero_cst (type); }))))
/* Optimize A / A to 1.0 if we don't care about /* Optimize A / A to 1.0 if we don't care about
NaNs or Infinities. */ NaNs or Infinities. */
...@@ -203,11 +202,11 @@ along with GCC; see the file COPYING3. If not see ...@@ -203,11 +202,11 @@ along with GCC; see the file COPYING3. If not see
(with (with
{ tree tem = const_binop (RDIV_EXPR, type, build_one_cst (type), @1); } { tree tem = const_binop (RDIV_EXPR, type, build_one_cst (type), @1); }
(if (tem) (if (tem)
(mult @0 { tem; } )))) (mult @0 { tem; } )))
(if (cst != COMPLEX_CST) (if (cst != COMPLEX_CST)
(with { tree inverse = exact_inverse (type, @1); } (with { tree inverse = exact_inverse (type, @1); }
(if (inverse) (if (inverse)
(mult @0 { inverse; } ))))))) (mult @0 { inverse; } ))))))))
/* Same applies to modulo operations, but fold is inconsistent here /* Same applies to modulo operations, but fold is inconsistent here
and simplifies 0 % x to 0, only preserving literal 0 % 0. */ 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 ...@@ -908,11 +907,11 @@ along with GCC; see the file COPYING3. If not see
being well defined. */ being well defined. */
(if (low >= prec) (if (low >= prec)
(if (op == LROTATE_EXPR || op == RROTATE_EXPR) (if (op == LROTATE_EXPR || op == RROTATE_EXPR)
(op @0 { build_int_cst (TREE_TYPE (@1), low % prec); })) (op @0 { build_int_cst (TREE_TYPE (@1), low % prec); })
(if (TYPE_UNSIGNED (type) || code == LSHIFT_EXPR) (if (TYPE_UNSIGNED (type) || code == LSHIFT_EXPR)
{ build_zero_cst (type); }) { build_zero_cst (type); }
(op @0 { build_int_cst (TREE_TYPE (@1), prec - 1); })) (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); })))))))
/* ((1 << A) & 1) != 0 -> A == 0 /* ((1 << A) & 1) != 0 -> A == 0
...@@ -933,10 +932,10 @@ along with GCC; see the file COPYING3. If not see ...@@ -933,10 +932,10 @@ along with GCC; see the file COPYING3. If not see
(if (cand < 0 (if (cand < 0
|| (!integer_zerop (@2) || (!integer_zerop (@2)
&& wi::ne_p (wi::lshift (@0, cand), @2))) && wi::ne_p (wi::lshift (@0, cand), @2)))
{ constant_boolean_node (cmp == NE_EXPR, type); }) { constant_boolean_node (cmp == NE_EXPR, type); }
(if (!integer_zerop (@2) (if (!integer_zerop (@2)
&& wi::eq_p (wi::lshift (@0, cand), @2)) && wi::eq_p (wi::lshift (@0, cand), @2))
(cmp @1 { build_int_cst (TREE_TYPE (@1), cand); }))))) (cmp @1 { build_int_cst (TREE_TYPE (@1), cand); }))))))
/* Fold (X << C1) & C2 into (X << C1) & (C2 | ((1 << C1) - 1)) /* Fold (X << C1) & C2 into (X << C1) & (C2 | ((1 << C1) - 1))
(X >> C1) & C2 into (X >> C1) & (C2 | ~((type) -1 >> C1)) (X >> C1) & C2 into (X >> C1) & (C2 | ~((type) -1 >> C1))
...@@ -1007,27 +1006,26 @@ along with GCC; see the file COPYING3. If not see ...@@ -1007,27 +1006,26 @@ along with GCC; see the file COPYING3. If not see
} }
/* ((X << 16) & 0xff00) is (X, 0). */ /* ((X << 16) & 0xff00) is (X, 0). */
(if ((mask & zerobits) == mask) (if ((mask & zerobits) == mask)
{ build_int_cst (type, 0); }) { build_int_cst (type, 0); }
(with { newmask = mask | zerobits; } (with { newmask = mask | zerobits; }
(if (newmask != mask && (newmask & (newmask + 1)) == 0) (if (newmask != mask && (newmask & (newmask + 1)) == 0)
(with (with
{ {
/* Only do the transformation if NEWMASK is some integer /* Only do the transformation if NEWMASK is some integer
mode's mask. */ mode's mask. */
for (prec = BITS_PER_UNIT; for (prec = BITS_PER_UNIT;
prec < HOST_BITS_PER_WIDE_INT; prec <<= 1) prec < HOST_BITS_PER_WIDE_INT; prec <<= 1)
if (newmask == (((unsigned HOST_WIDE_INT) 1) << prec) - 1) if (newmask == (((unsigned HOST_WIDE_INT) 1) << prec) - 1)
break; break;
} }
(if (prec < HOST_BITS_PER_WIDE_INT (if (prec < HOST_BITS_PER_WIDE_INT
|| newmask == ~(unsigned HOST_WIDE_INT) 0) || newmask == ~(unsigned HOST_WIDE_INT) 0)
(with (with
{ tree newmaskt = build_int_cst_type (TREE_TYPE (@2), newmask); } { tree newmaskt = build_int_cst_type (TREE_TYPE (@2), newmask); }
(if (!tree_int_cst_equal (newmaskt, @2)) (if (!tree_int_cst_equal (newmaskt, @2))
(if (shift_type != TREE_TYPE (@3)) (if (shift_type != TREE_TYPE (@3))
(bit_and (convert (shift:shift_type (convert @3) @1)) { newmaskt; })) (bit_and (convert (shift:shift_type (convert @3) @1)) { newmaskt; })
(if (shift_type == TREE_TYPE (@3)) (bit_and @4 { newmaskt; })))))))))))))
(bit_and @4 { newmaskt; }))))))))))))
/* Fold (X & C2) << C1 into (X << C1) & (C2 << C1) /* Fold (X & C2) << C1 into (X << C1) & (C2 << C1)
(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 ...@@ -1119,7 +1117,7 @@ along with GCC; see the file COPYING3. If not see
&& (((inter_int || inter_ptr) && final_int) && (((inter_int || inter_ptr) && final_int)
|| (inter_float && final_float)) || (inter_float && final_float))
&& inter_prec >= final_prec) && inter_prec >= final_prec)
(ocvt @0)) (ocvt @0)
/* Likewise, if the intermediate and initial types are either both /* Likewise, if the intermediate and initial types are either both
float or both integer, we don't need the middle conversion if the 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 ...@@ -1133,7 +1131,7 @@ along with GCC; see the file COPYING3. If not see
&& (inter_float || inter_unsignedp == inside_unsignedp) && (inter_float || inter_unsignedp == inside_unsignedp)
&& ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type)) && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type))
&& TYPE_MODE (type) == TYPE_MODE (inter_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 /* If we have a sign-extension of a zero-extended value, we can
replace that by a single zero-extension. Likewise if the replace that by a single zero-extension. Likewise if the
...@@ -1143,7 +1141,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -1143,7 +1141,7 @@ along with GCC; see the file COPYING3. If not see
&& ((inside_prec < inter_prec && inter_prec < final_prec && ((inside_prec < inter_prec && inter_prec < final_prec
&& inside_unsignedp && !inter_unsignedp) && inside_unsignedp && !inter_unsignedp)
|| final_prec == inter_prec)) || final_prec == inter_prec))
(ocvt @0)) (ocvt @0)
/* Two conversions in a row are not needed unless: /* Two conversions in a row are not needed unless:
- some conversion is floating-point (overstrict for now), or - some conversion is floating-point (overstrict for now), or
...@@ -1168,7 +1166,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -1168,7 +1166,7 @@ along with GCC; see the file COPYING3. If not see
&& ! (final_ptr && inside_prec != inter_prec) && ! (final_ptr && inside_prec != inter_prec)
&& ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type)) && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type))
&& TYPE_MODE (type) == TYPE_MODE (inter_type))) && TYPE_MODE (type) == TYPE_MODE (inter_type)))
(ocvt @0)) (ocvt @0)
/* A truncation to an unsigned type (a zero-extension) should be /* A truncation to an unsigned type (a zero-extension) should be
canonicalized as bitwise and of a mask. */ canonicalized as bitwise and of a mask. */
...@@ -1179,7 +1177,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -1179,7 +1177,7 @@ along with GCC; see the file COPYING3. If not see
(convert (bit_and @0 { wide_int_to_tree (convert (bit_and @0 { wide_int_to_tree
(inside_type, (inside_type,
wi::mask (inter_prec, false, 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 /* If we are converting an integer to a floating-point that can
represent it exactly and back to an integer, we can skip the 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 ...@@ -1188,7 +1186,7 @@ along with GCC; see the file COPYING3. If not see
&& inside_int && inter_float && final_int && && inside_int && inter_float && final_int &&
(unsigned) significand_size (TYPE_MODE (inter_type)) (unsigned) significand_size (TYPE_MODE (inter_type))
>= inside_prec - !inside_unsignedp) >= inside_prec - !inside_unsignedp)
(convert @0)))))) (convert @0)))))))))))
/* If we have a narrowing conversion to an integral type that is fed by a /* 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 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 ...@@ -1281,20 +1279,17 @@ along with GCC; see the file COPYING3. If not see
genmatch cannot handle. */ genmatch cannot handle. */
(simplify (simplify
(cond INTEGER_CST@0 @1 @2) (cond INTEGER_CST@0 @1 @2)
(if (integer_zerop (@0) (if (integer_zerop (@0))
&& (!VOID_TYPE_P (TREE_TYPE (@2)) (if (!VOID_TYPE_P (TREE_TYPE (@2)) || VOID_TYPE_P (type))
|| VOID_TYPE_P (type))) @2)
@2) (if (!VOID_TYPE_P (TREE_TYPE (@1)) || VOID_TYPE_P (type))
(if (!integer_zerop (@0) @1)))
&& (!VOID_TYPE_P (TREE_TYPE (@1))
|| VOID_TYPE_P (type)))
@1))
(simplify (simplify
(vec_cond VECTOR_CST@0 @1 @2) (vec_cond VECTOR_CST@0 @1 @2)
(if (integer_all_onesp (@0)) (if (integer_all_onesp (@0))
@1) @1
(if (integer_zerop (@0)) (if (integer_zerop (@0))
@2)) @2)))
(for cnd (cond vec_cond) (for cnd (cond vec_cond)
/* A ? B : (A ? X : C) -> A ? B : C. */ /* A ? B : (A ? X : C) -> A ? B : C. */
...@@ -1362,17 +1357,17 @@ along with GCC; see the file COPYING3. If not see ...@@ -1362,17 +1357,17 @@ along with GCC; see the file COPYING3. If not see
(with { enum tree_code ic = invert_tree_comparison (with { enum tree_code ic = invert_tree_comparison
(cmp, HONOR_NANS (@0)); } (cmp, HONOR_NANS (@0)); }
(if (ic == icmp) (if (ic == icmp)
(icmp @0 @1)) (icmp @0 @1)
(if (ic == ncmp) (if (ic == ncmp)
(ncmp @0 @1))))) (ncmp @0 @1))))))
(simplify (simplify
(bit_xor (cmp @0 @1) integer_truep) (bit_xor (cmp @0 @1) integer_truep)
(with { enum tree_code ic = invert_tree_comparison (with { enum tree_code ic = invert_tree_comparison
(cmp, HONOR_NANS (@0)); } (cmp, HONOR_NANS (@0)); }
(if (ic == icmp) (if (ic == icmp)
(icmp @0 @1)) (icmp @0 @1)
(if (ic == ncmp) (if (ic == ncmp)
(ncmp @0 @1))))) (ncmp @0 @1))))))
/* Transform comparisons of the form X - Y CMP 0 to X CMP Y. /* Transform comparisons of the form X - Y CMP 0 to X CMP Y.
??? The transformation is valid for the other operators if overflow ??? The transformation is valid for the other operators if overflow
...@@ -1395,13 +1390,13 @@ along with GCC; see the file COPYING3. If not see ...@@ -1395,13 +1390,13 @@ along with GCC; see the file COPYING3. If not see
(cmp (mult @0 INTEGER_CST@1) integer_zerop@2) (cmp (mult @0 INTEGER_CST@1) integer_zerop@2)
/* Handle unfolded multiplication by zero. */ /* Handle unfolded multiplication by zero. */
(if (integer_zerop (@1)) (if (integer_zerop (@1))
(cmp @1 @2)) (cmp @1 @2)
(if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0)) (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
&& TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))) && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)))
/* If @1 is negative we swap the sense of the comparison. */ /* If @1 is negative we swap the sense of the comparison. */
(if (tree_int_cst_sgn (@1) < 0) (if (tree_int_cst_sgn (@1) < 0)
(scmp @0 @2)) (scmp @0 @2)
(cmp @0 @2)))) (cmp @0 @2))))))
/* Simplify comparison of something with itself. For IEEE /* Simplify comparison of something with itself. For IEEE
floating-point, we can only do some of these simplifications. */ floating-point, we can only do some of these simplifications. */
...@@ -1470,11 +1465,11 @@ along with GCC; see the file COPYING3. If not see ...@@ -1470,11 +1465,11 @@ along with GCC; see the file COPYING3. If not see
/* IEEE doesn't distinguish +0 and -0 in comparisons. */ /* IEEE doesn't distinguish +0 and -0 in comparisons. */
/* a CMP (-0) -> a CMP 0 */ /* a CMP (-0) -> a CMP 0 */
(if (REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (@1))) (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. */ /* x != NaN is always true, other ops are always false. */
(if (REAL_VALUE_ISNAN (TREE_REAL_CST (@1)) (if (REAL_VALUE_ISNAN (TREE_REAL_CST (@1))
&& ! HONOR_SNANS (@1)) && ! HONOR_SNANS (@1))
{ constant_boolean_node (cmp == NE_EXPR, type); }) { constant_boolean_node (cmp == NE_EXPR, type); }
/* Fold comparisons against infinity. */ /* Fold comparisons against infinity. */
(if (REAL_VALUE_ISINF (TREE_REAL_CST (@1)) (if (REAL_VALUE_ISINF (TREE_REAL_CST (@1))
&& MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (@1)))) && MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (@1))))
...@@ -1489,37 +1484,37 @@ along with GCC; see the file COPYING3. If not see ...@@ -1489,37 +1484,37 @@ along with GCC; see the file COPYING3. If not see
/* x > +Inf is always false, if with ignore sNANs. */ /* x > +Inf is always false, if with ignore sNANs. */
(if (code == GT_EXPR (if (code == GT_EXPR
&& ! HONOR_SNANS (@0)) && ! HONOR_SNANS (@0))
{ constant_boolean_node (false, type); }) { constant_boolean_node (false, type); }
(if (code == LE_EXPR) (if (code == LE_EXPR)
/* x <= +Inf is always true, if we don't case about NaNs. */ /* x <= +Inf is always true, if we don't case about NaNs. */
(if (! HONOR_NANS (@0)) (if (! HONOR_NANS (@0))
{ constant_boolean_node (true, type); }) { constant_boolean_node (true, type); }
/* x <= +Inf is the same as x == x, i.e. isfinite(x). */ /* x <= +Inf is the same as x == x, i.e. isfinite(x). */
(eq @0 @0)) (eq @0 @0))
/* x == +Inf and x >= +Inf are always equal to x > DBL_MAX. */ /* x == +Inf and x >= +Inf are always equal to x > DBL_MAX. */
(if (code == EQ_EXPR || code == GE_EXPR) (if (code == EQ_EXPR || code == GE_EXPR)
(with { real_maxval (&max, neg, TYPE_MODE (TREE_TYPE (@0))); } (with { real_maxval (&max, neg, TYPE_MODE (TREE_TYPE (@0))); }
(if (neg) (if (neg)
(lt @0 { build_real (TREE_TYPE (@0), max); })) (lt @0 { build_real (TREE_TYPE (@0), max); })
(gt @0 { build_real (TREE_TYPE (@0), max); }))) (gt @0 { build_real (TREE_TYPE (@0), max); })))
/* x < +Inf is always equal to x <= DBL_MAX. */ /* x < +Inf is always equal to x <= DBL_MAX. */
(if (code == LT_EXPR) (if (code == LT_EXPR)
(with { real_maxval (&max, neg, TYPE_MODE (TREE_TYPE (@0))); } (with { real_maxval (&max, neg, TYPE_MODE (TREE_TYPE (@0))); }
(if (neg) (if (neg)
(ge @0 { build_real (TREE_TYPE (@0), max); })) (ge @0 { build_real (TREE_TYPE (@0), max); })
(le @0 { build_real (TREE_TYPE (@0), max); }))) (le @0 { build_real (TREE_TYPE (@0), max); })))
/* x != +Inf is always equal to !(x > DBL_MAX). */ /* x != +Inf is always equal to !(x > DBL_MAX). */
(if (code == NE_EXPR) (if (code == NE_EXPR)
(with { real_maxval (&max, neg, TYPE_MODE (TREE_TYPE (@0))); } (with { real_maxval (&max, neg, TYPE_MODE (TREE_TYPE (@0))); }
(if (! HONOR_NANS (@0)) (if (! HONOR_NANS (@0))
(if (neg) (if (neg)
(ge @0 { build_real (TREE_TYPE (@0), max); })) (ge @0 { build_real (TREE_TYPE (@0), max); })
(le @0 { build_real (TREE_TYPE (@0), max); })) (le @0 { build_real (TREE_TYPE (@0), max); }))
(if (neg) (if (neg)
(bit_xor (lt @0 { build_real (TREE_TYPE (@0), max); }) (bit_xor (lt @0 { build_real (TREE_TYPE (@0), max); })
{ build_one_cst (type); })) { build_one_cst (type); })
(bit_xor (gt @0 { build_real (TREE_TYPE (@0), max); }) (bit_xor (gt @0 { build_real (TREE_TYPE (@0), max); })
{ build_one_cst (type); })))))) { build_one_cst (type); }))))))))))))))
/* If this is a comparison of a real constant with a PLUS_EXPR /* 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 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 ...@@ -1557,13 +1552,13 @@ along with GCC; see the file COPYING3. If not see
(if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (@1))) (if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (@1)))
/* sqrt(x) < y is always false, if y is negative. */ /* sqrt(x) < y is always false, if y is negative. */
(if (cmp == EQ_EXPR || cmp == LT_EXPR || cmp == LE_EXPR) (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 /* sqrt(x) > y is always true, if y is negative and we
don't care about NaNs, i.e. negative values of x. */ don't care about NaNs, i.e. negative values of x. */
(if (cmp == NE_EXPR || !HONOR_NANS (@0)) (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. */ /* 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) (if (cmp == GT_EXPR || cmp == GE_EXPR)
(with (with
{ {
...@@ -1574,10 +1569,10 @@ along with GCC; see the file COPYING3. If not see ...@@ -1574,10 +1569,10 @@ along with GCC; see the file COPYING3. If not see
(if (REAL_VALUE_ISINF (c2)) (if (REAL_VALUE_ISINF (c2))
/* sqrt(x) > y is x == +Inf, when y is very large. */ /* sqrt(x) > y is x == +Inf, when y is very large. */
(if (HONOR_INFINITIES (@0)) (if (HONOR_INFINITIES (@0))
(eq @0 { build_real (TREE_TYPE (@0), c2); })) (eq @0 { build_real (TREE_TYPE (@0), c2); })
{ constant_boolean_node (false, type); }) { constant_boolean_node (false, type); })
/* sqrt(x) > c is the same as x > c*c. */ /* sqrt(x) > c is the same as x > c*c. */
(cmp @0 { build_real (TREE_TYPE (@0), c2); }))) (cmp @0 { build_real (TREE_TYPE (@0), c2); })))
(if (cmp == LT_EXPR || cmp == LE_EXPR) (if (cmp == LT_EXPR || cmp == LE_EXPR)
(with (with
{ {
...@@ -1589,30 +1584,30 @@ along with GCC; see the file COPYING3. If not see ...@@ -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 /* sqrt(x) < y is always true, when y is a very large
value and we don't care about NaNs or Infinities. */ value and we don't care about NaNs or Infinities. */
(if (! HONOR_NANS (@0) && ! HONOR_INFINITIES (@0)) (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 /* sqrt(x) < y is x != +Inf when y is very large and we
don't care about NaNs. */ don't care about NaNs. */
(if (! HONOR_NANS (@0)) (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 /* sqrt(x) < y is x >= 0 when y is very large and we
don't care about Infinities. */ don't care about Infinities. */
(if (! HONOR_INFINITIES (@0)) (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. */ /* sqrt(x) < y is x >= 0 && x != +Inf, when y is large. */
(if (GENERIC) (if (GENERIC)
(truth_andif (truth_andif
(ge @0 { build_real (TREE_TYPE (@0), dconst0); }) (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. */ /* sqrt(x) < c is the same as x < c*c, if we ignore NaNs. */
(if (! REAL_VALUE_ISINF (c2) (if (! REAL_VALUE_ISINF (c2)
&& ! HONOR_NANS (@0)) && ! 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. */ /* sqrt(x) < c is the same as x >= 0 && x < c*c. */
(if (! REAL_VALUE_ISINF (c2) (if (! REAL_VALUE_ISINF (c2)
&& GENERIC) && GENERIC)
(truth_andif (truth_andif
(ge @0 { build_real (TREE_TYPE (@0), dconst0); }) (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. */ /* Unordered tests if either argument is a NaN. */
(simplify (simplify
...@@ -1782,9 +1777,9 @@ along with GCC; see the file COPYING3. If not see ...@@ -1782,9 +1777,9 @@ along with GCC; see the file COPYING3. If not see
&& types_match (@0, @1) && types_match (@0, @1)
&& types_match (@0, type)) && types_match (@0, type))
(if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))) (if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0)))
(convert (op @0 @1))) (convert (op @0 @1))
(with { tree utype = unsigned_type_for (TREE_TYPE (@0)); } (with { tree utype = unsigned_type_for (TREE_TYPE (@0)); }
(convert (op (convert:utype @0) (convert:utype @1))))))) (convert (op (convert:utype @0) (convert:utype @1))))))))
/* This is another case of narrowing, specifically when there's an outer /* 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 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 ...@@ -1792,32 +1787,31 @@ along with GCC; see the file COPYING3. If not see
to unsigned types to avoid introducing undefined behaviour for the to unsigned types to avoid introducing undefined behaviour for the
arithmetic operation. */ arithmetic operation. */
(for op (minus plus) (for op (minus plus)
(simplify (simplify
(bit_and (op:s (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) (if (INTEGRAL_TYPE_P (type)
/* We check for type compatibility between @0 and @1 below, /* We check for type compatibility between @0 and @1 below,
so there's no need to check that @1/@3 are integral types. */ so there's no need to check that @1/@3 are integral types. */
&& INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE (@0))
&& INTEGRAL_TYPE_P (TREE_TYPE (@2)) && INTEGRAL_TYPE_P (TREE_TYPE (@2))
/* The precision of the type of each operand must match the /* The precision of the type of each operand must match the
precision of the mode of each operand, similarly for the precision of the mode of each operand, similarly for the
result. */ result. */
&& (TYPE_PRECISION (TREE_TYPE (@0)) && (TYPE_PRECISION (TREE_TYPE (@0))
== GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (@0)))) == GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (@0))))
&& (TYPE_PRECISION (TREE_TYPE (@1)) && (TYPE_PRECISION (TREE_TYPE (@1))
== GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (@1)))) == GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (@1))))
&& TYPE_PRECISION (type) == GET_MODE_PRECISION (TYPE_MODE (type)) && TYPE_PRECISION (type) == GET_MODE_PRECISION (TYPE_MODE (type))
/* The inner conversion must be a widening conversion. */ /* The inner conversion must be a widening conversion. */
&& TYPE_PRECISION (TREE_TYPE (@2)) > TYPE_PRECISION (TREE_TYPE (@0)) && TYPE_PRECISION (TREE_TYPE (@2)) > TYPE_PRECISION (TREE_TYPE (@0))
&& types_match (@0, @1) && types_match (@0, @1)
&& (tree_int_cst_min_precision (@4, TYPE_SIGN (TREE_TYPE (@0))) && (tree_int_cst_min_precision (@4, TYPE_SIGN (TREE_TYPE (@0)))
<= TYPE_PRECISION (TREE_TYPE (@0))) <= TYPE_PRECISION (TREE_TYPE (@0)))
&& (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0)) && (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))
|| tree_int_cst_sgn (@4) >= 0)) || tree_int_cst_sgn (@4) >= 0))
(if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))) (if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0)))
(with { tree ntype = TREE_TYPE (@0); } (with { tree ntype = TREE_TYPE (@0); }
(convert (bit_and (op @0 @1) (convert:ntype @4))))) (convert (bit_and (op @0 @1) (convert:ntype @4))))
(with { tree utype = unsigned_type_for (TREE_TYPE (@0)); } (with { tree utype = unsigned_type_for (TREE_TYPE (@0)); }
(convert (bit_and (op (convert:utype @0) (convert:utype @1)) (convert (bit_and (op (convert:utype @0) (convert:utype @1))
(convert:utype @4))))))) (convert:utype @4))))))))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment