/* 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,
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
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_)
- : location (location_), cexpr (cexpr_), is_with (is_with_) {}
- source_location location;
- operand *cexpr;
- bool is_with;
-};
+ 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
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;
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);
}
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);
}
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);
}
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. */
{
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];
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);
}
}
: 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);
};
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
/* 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;
&& (*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. */
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))
{
&& 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))
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. */
}
-
/* 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->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;
- 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");
+ 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)
{
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. */
{
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
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");
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;
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)
{
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)
&& 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
{
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. */
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 ();
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)
|| (!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)
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. */
(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. */
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
(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))
}
/* ((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). */
&& (((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
&& (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
&& ((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
&& ! (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. */
(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
&& 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
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. */
(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
(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. */
/* 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))))
/* 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
(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
{
(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
{
/* 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
&& 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
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))))))))