aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2015-11-17 18:48:23 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2015-11-17 18:48:23 +0000
commitfa74b47a8c825cbdde6f97591befb474b739006f (patch)
treebdc10567de14ef2c88576714c0c54d848ad98243 /gcc
parentc9e926ce2bdc8bdce5fd9892443cf6147868e7f6 (diff)
downloadgcc-fa74b47a8c825cbdde6f97591befb474b739006f.zip
gcc-fa74b47a8c825cbdde6f97591befb474b739006f.tar.gz
gcc-fa74b47a8c825cbdde6f97591befb474b739006f.tar.bz2
Add null identifiers to genmatch
This patch adds a null identifier that can never match anything and can never be generated. It is only valid in operator lists and fors. Later patches will add uses of it. The idea is to allow operator lists for maths functions that have four entries: - float built-in - double built-in - long double built-in - internal function Not all maths functions have an associated internal function, and for those the final operator will be "null". Any simplification that tries to use a null substitution will be skipped. Tested on x86_64-linux-gnu, aarch64-linux-gnu and arm-linux-gnueabi. gcc/ * doc/match-and-simplify.texi: Document the "null" identifier. * genmatch.c (id_base::NULL_ID): New kind. (null_id): New variable. (get_operator): Add a parameter that says whether null identifiers are allowed. (contains_id): New function. (lower_for): Skip substitutions that would have a null_id in either the match or the result. (parser::parse_for): Allow the null identifier to be used. (parser::parse_operator_list): Likewise. (main): Initialize null_id. From-SVN: r230485
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog14
-rw-r--r--gcc/doc/match-and-simplify.texi5
-rw-r--r--gcc/genmatch.c69
3 files changed, 81 insertions, 7 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index af6477a..bd233a6 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,19 @@
2015-11-17 Richard Sandiford <richard.sandiford@arm.com>
+ * doc/match-and-simplify.texi: Document the "null" identifier.
+ * genmatch.c (id_base::NULL_ID): New kind.
+ (null_id): New variable.
+ (get_operator): Add a parameter that says whether null identifiers
+ are allowed.
+ (contains_id): New function.
+ (lower_for): Skip substitutions that would have a null_id in
+ either the match or the result.
+ (parser::parse_for): Allow the null identifier to be used.
+ (parser::parse_operator_list): Likewise.
+ (main): Initialize null_id.
+
+2015-11-17 Richard Sandiford <richard.sandiford@arm.com>
+
* match.pd: Use HYPOT and COS rather than hypot and cos.
Use CASE_CFN_* macros. Guard log/exp folds with
SCALAR_FLOAT_TYPE_P.
diff --git a/gcc/doc/match-and-simplify.texi b/gcc/doc/match-and-simplify.texi
index c5c2b7e..db6519d 100644
--- a/gcc/doc/match-and-simplify.texi
+++ b/gcc/doc/match-and-simplify.texi
@@ -323,6 +323,11 @@ is the same as
(POW (abs @@0) (mult @@1 @{ built_real (TREE_TYPE (@@1), dconsthalf); @}))))
@end smallexample
+@code{for}s and operator lists can include the special identifier
+@code{null} that matches nothing and can never be generated. This can
+be used to pad an operator list so that it has a standard form,
+even if there isn't a suitable operator for every form.
+
Another building block are @code{with} expressions in the
result expression which nest the generated code in a new C block
followed by its argument:
diff --git a/gcc/genmatch.c b/gcc/genmatch.c
index daa66d9..4df5689 100644
--- a/gcc/genmatch.c
+++ b/gcc/genmatch.c
@@ -297,7 +297,7 @@ commutative_ternary_tree_code (enum tree_code code)
struct id_base : nofree_ptr_hash<id_base>
{
- enum id_kind { CODE, FN, PREDICATE, USER } kind;
+ enum id_kind { CODE, FN, PREDICATE, USER, NULL_ID } kind;
id_base (id_kind, const char *, int = -1);
@@ -324,6 +324,9 @@ id_base::equal (const id_base *op1,
&& strcmp (op1->id, op2->id) == 0);
}
+/* The special id "null", which matches nothing. */
+static id_base *null_id;
+
/* Hashtable of known pattern operators. This is pre-seeded from
all known tree codes and all known builtin function ids. */
static hash_table<id_base> *operators;
@@ -479,11 +482,14 @@ operator==(id_base &id, enum tree_code code)
return false;
}
-/* Lookup the identifier ID. */
+/* Lookup the identifier ID. Allow "null" if ALLOW_NULL. */
id_base *
-get_operator (const char *id)
+get_operator (const char *id, bool allow_null = false)
{
+ if (allow_null && strcmp (id, "null") == 0)
+ return null_id;
+
id_base tem (id_base::CODE, id);
id_base *op = operators->find_with_hash (&tem, tem.hashval);
@@ -1115,6 +1121,40 @@ lower_cond (simplify *s, vec<simplify *>& simplifiers)
}
}
+/* Return true if O refers to ID. */
+
+bool
+contains_id (operand *o, user_id *id)
+{
+ if (capture *c = dyn_cast<capture *> (o))
+ return c->what && contains_id (c->what, id);
+
+ if (expr *e = dyn_cast<expr *> (o))
+ {
+ if (e->operation == id)
+ return true;
+ for (unsigned i = 0; i < e->ops.length (); ++i)
+ if (contains_id (e->ops[i], id))
+ return true;
+ return false;
+ }
+
+ if (with_expr *w = dyn_cast <with_expr *> (o))
+ return (contains_id (w->with, id)
+ || contains_id (w->subexpr, id));
+
+ if (if_expr *ife = dyn_cast <if_expr *> (o))
+ return (contains_id (ife->cond, id)
+ || contains_id (ife->trueexpr, id)
+ || (ife->falseexpr && contains_id (ife->falseexpr, id)));
+
+ if (c_expr *ce = dyn_cast<c_expr *> (o))
+ return ce->capture_ids && ce->capture_ids->get (id->id);
+
+ return false;
+}
+
+
/* In AST operand O replace operator ID with operator WITH. */
operand *
@@ -1270,16 +1310,29 @@ lower_for (simplify *sin, vec<simplify *>& simplifiers)
operand *result_op = s->result;
vec<std::pair<user_id *, id_base *> > subst;
subst.create (n_ids);
+ bool skip = false;
for (unsigned i = 0; i < n_ids; ++i)
{
user_id *id = ids[i];
id_base *oper = id->substitutes[j % id->substitutes.length ()];
+ if (oper == null_id
+ && (contains_id (match_op, id)
+ || contains_id (result_op, id)))
+ {
+ skip = true;
+ break;
+ }
subst.quick_push (std::make_pair (id, oper));
match_op = replace_id (match_op, id, oper);
if (result_op
&& !can_delay_subst)
result_op = replace_id (result_op, id, oper);
}
+ if (skip)
+ {
+ subst.release ();
+ continue;
+ }
simplify *ns = new simplify (s->kind, match_op, result_op,
vNULL, s->capture_ids);
ns->for_subst_vec.safe_splice (s->for_subst_vec);
@@ -4242,7 +4295,7 @@ parser::parse_for (source_location)
/* Insert the user defined operators into the operator hash. */
const char *id = get_ident ();
- if (get_operator (id) != NULL)
+ if (get_operator (id, true) != NULL)
fatal_at (token, "operator already defined");
user_id *op = new user_id (id);
id_base **slot = operators->find_slot_with_hash (op, op->hashval, INSERT);
@@ -4256,7 +4309,7 @@ parser::parse_for (source_location)
while ((token = peek_ident ()) != 0)
{
const char *oper = get_ident ();
- id_base *idb = get_operator (oper);
+ id_base *idb = get_operator (oper, true);
if (idb == NULL)
fatal_at (token, "no such operator '%s'", oper);
if (*idb == CONVERT0 || *idb == CONVERT1 || *idb == CONVERT2
@@ -4346,7 +4399,7 @@ parser::parse_operator_list (source_location)
const cpp_token *token = peek ();
const char *id = get_ident ();
- if (get_operator (id) != 0)
+ if (get_operator (id, true) != 0)
fatal_at (token, "operator %s already defined", id);
user_id *op = new user_id (id, true);
@@ -4356,7 +4409,7 @@ parser::parse_operator_list (source_location)
{
token = peek ();
const char *oper = get_ident ();
- id_base *idb = get_operator (oper);
+ id_base *idb = get_operator (oper, true);
if (idb == 0)
fatal_at (token, "no such operator '%s'", oper);
@@ -4590,6 +4643,8 @@ main (int argc, char **argv)
cpp_define (r, gimple ? "GIMPLE=1": "GENERIC=1");
cpp_define (r, gimple ? "GENERIC=0": "GIMPLE=0");
+ null_id = new id_base (id_base::NULL_ID, "null");
+
/* Pre-seed operators. */
operators = new hash_table<id_base> (1024);
#define DEFTREECODE(SYM, STRING, TYPE, NARGS) \