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:
Richard Biener 2015-07-14 07:25:55 +00:00 committed by Richard Biener
parent 67a546ab45
commit 8fdc6c67ad
3 changed files with 449 additions and 353 deletions

View File

@ -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.

View File

@ -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)

View File

@ -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))))))))