===================================================================
@@ -2419,6 +2419,7 @@
void parse_simplify (source_location, vec<simplify *>&, predicate_id *,
expr *);
void parse_for (source_location);
+ void parse_operator_list ();
void parse_if (source_location);
void parse_predicates (source_location);
@@ -2582,8 +2583,10 @@
|| strcmp (id, "convert2") == 0)
fatal_at (id_tok, "expected '?' after conditional operator");
id_base *op = get_operator (id);
+
if (!op)
fatal_at (id_tok, "unknown operator %s", id);
+
return op;
}
@@ -2900,6 +2903,20 @@
/* Parsing of the outer control structures. */
+bool
+add_substitute (user_id *op, id_base *idb, int& arity)
+{
+ if (arity == -1)
+ arity = idb->nargs;
+ else if (idb->nargs == -1)
+ ;
+ else if (idb->nargs != arity)
+ return false;
+
+ op->substitutes.safe_push (idb);
+ return true;
+}
+
/* Parse a for expression
for = '(' 'for' <subst>... <pattern> ')'
subst = <ident> '(' <ident>... ')' */
@@ -2938,15 +2955,16 @@
if (*idb == CONVERT0 || *idb == CONVERT1 || *idb == CONVERT2)
fatal_at (token, "conditional operators cannot be used inside for");
- if (arity == -1)
- arity = idb->nargs;
- else if (idb->nargs == -1)
- ;
- else if (idb->nargs != arity)
- fatal_at (token, "operator '%s' with arity %d does not match "
- "others with arity %d", oper, idb->nargs, arity);
+ vec<id_base *> substitutes = vNULL;
+ if (idb->kind == id_base::USER)
+ substitutes = (as_a<user_id *> (idb))->substitutes;
+ else
+ substitutes.safe_push (idb);
- op->substitutes.safe_push (idb);
+ for (unsigned si = 0; si < substitutes.length (); ++si)
+ if (!add_substitute (op, substitutes[si], arity))
+ fatal_at (token, "operator '%s' with arity %d does not match "
+ "others with arity %d", oper, idb->nargs, arity);
}
op->nargs = arity;
token = expect (CPP_CLOSE_PAREN);
@@ -2997,6 +3015,55 @@
operators->remove_elt (user_ids[i]);
}
+void
+flatten_substitutes (vec<id_base *>& ids, vec<id_base *>& substitutes)
+{
+ user_id *op;
+
+ for (unsigned i = 0; i < ids.length (); ++i)
+ if ((op = dyn_cast<user_id *> (ids[i])) != 0)
+ flatten_substitutes (op->substitutes, substitutes);
+ else
+ substitutes.safe_push (ids[i]);
+}
+
+void
+parser::parse_operator_list ()
+{
+ const char *id = get_ident ();
+ user_id *op = new user_id (id);
+ vec<const cpp_token *> user_id_tokens = vNULL;
+
+ id_base **slot = operators->find_slot_with_hash (op, op->hashval, INSERT);
+ if (*slot)
+ fatal ("operator %s already defined", id);
+ *slot = op;
+
+ const cpp_token *token;
+ vec<id_base *> ids = vNULL;
+
+ while ((token = peek_ident ()) != 0)
+ {
+ const char *oper = get_ident ();
+ id_base *p = get_operator (oper);
+ if (p == 0)
+ fatal_at (token, "%s is not defined", oper);
+ ids.safe_push (p);
+ user_id_tokens.safe_push (token);
+ }
+
+ if (ids.length () == 0)
+ fatal_at (token, "operator list cannot be empty");
+
+ flatten_substitutes (ids, op->substitutes);
+ int arity = op->substitutes[0]->nargs;
+ for (unsigned i = 1; i < op->substitutes.length (); ++i)
+ if (op->substitutes[i]->nargs != -1 && arity != op->substitutes[i]->nargs)
+ fatal_at (user_id_tokens[i], "operator '%s' with arity %d does not match "
+ "others with arity %d", op->substitutes[i]->id, op->substitutes[i]->nargs, arity);
+}
+
+
/* Parse an outer if expression.
if = '(' 'if' '(' <c-expr> ')' <pattern> ')' */
@@ -3097,6 +3164,8 @@
fatal_at (token, "define_predicates inside if or for is not supported");
parse_predicates (token->src_loc);
}
+ else if (strcmp (id, "define_operator_list") == 0)
+ parse_operator_list ();
else
fatal_at (token, "expected %s'simplify', 'match', 'for' or 'if'",
active_ifs.length () == 0 && active_fors.length () == 0
===================================================================
@@ -17,6 +17,9 @@
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
+(define_operator_list bitwise_ors bit_ior bit_xor)
+(define_operator_list bitwise_ops bit_and bitwise_ors)
+
/* Try to fold (type) X op CST -> (type) (X op ((type-x) CST))
when profitable. */
/* For bitwise binary operations apply operand conversions to the
@@ -23,7 +26,7 @@
binary operation result instead of to the operands. This allows
to combine successive conversions and bitwise binary operations. */
/* We combine the above two cases by using a conditional convert. */
-(for bitop (bit_and bit_ior bit_xor)
+(for bitop (bitwise_ops))
(simplify
(bitop (convert @0) (convert? @1))
(if (((TREE_CODE (@1) == INTEGER_CST
@@ -48,7 +51,7 @@
(convert (bitop @0 (convert @1))))))
/* Simplify (A & B) OP0 (C & B) to (A OP0 C) & B. */
-(for bitop (bit_and bit_ior bit_xor)
+(for bitop (bitwise_ops)
(simplify
(bitop (bit_and:c @0 @1) (bit_and @2 @1))
(bit_and (bitop @0 @2) @1)))
@@ -59,7 +62,7 @@
(bit_ior (bit_and @0 @2) (bit_and @1 @2)))
/* Combine successive equal operations with constants. */
-(for bitop (bit_and bit_ior bit_xor)
+(for bitop (bitwise_ops)
(simplify
(bitop (bitop @0 CONSTANT_CLASS_P@1) CONSTANT_CLASS_P@2)
(bitop @0 (bitop @1 @2))))
@@ -95,7 +98,7 @@
(bit_and @0 (logical_inverted_value @0))
{ build_zero_cst (type); })
/* X | !X and X ^ !X -> 1, , if X is truth-valued. */
-(for op (bit_ior bit_xor)
+(for op (bitwise_ors)
(simplify
(op truth_valued_p@0 (logical_inverted_value @0))
{ build_one_cst (type); }))
@@ -110,7 +113,7 @@
(bit_and:c @0 (bit_not @0))
{ build_zero_cst (type); })
/* X | ~X -> ~0, X ^ ~X -> ~0. */
-(for bitop (bit_ior bit_xor)
+(for bitop (bitwise_ors)
(simplify
(bitop:c @0 (bit_not @0))
{ build_all_ones_cst (type); }))
@@ -118,7 +121,7 @@
Also X != 1 vs. X ^ 1 vs ~X wants canonicalization for truth
values. */
#if 0 /* FIXME. truth_valued_ssa_name isn't exported either. */
-(for bitop (bit_and bit_ior bit_xor)
+(for bitop (bitwise_ops)
/* X & (X == 0) -> 0. */
/* X | (X == 0) -> 1. */
(simplify
@@ -201,7 +204,7 @@
/* Simple association cases that cancel one operand. */
/* ((a OP b) & ~a) -> (b & ~a) OP 0 */
-(for bitop (bit_and bit_ior bit_xor)
+(for bitop (bitwise_ops)
(simplify
(bit_and:c (bitop:c @0 @1) (bit_not@2 @0))
(bitop (bit_and @1 @2) { build_zero_cst (type); })))
@@ -264,7 +267,7 @@
/* Similar transform for vector permute.
??? Missing an easy way to check if a mask is a reverse
operation of another mask (most masks are not reversible). */
-(for bitop (bit_xor bit_ior bit_and)
+(for bitop (bitwise_ops)
(simplify
(bitop (vec_perm @1 @2 @0) (vec_perm @3 @4 @0))
(vec_perm (bitop @1 @3) (bitop @2 @4) @0)))
===================================================================
@@ -1,5 +1,8 @@
/* From fold_binary. */
+(define_operator_list eq_ops eq ne)
+(define_operator_list cmp_ops eq_ops lt le gt ge)
+
/* On GIMPLE bool != 0 is simply the canonical way to express a
condition in COND_EXPRs and GIMPLE_CONDs.
??? Of course for assignments we still may want to strip those... */
@@ -15,7 +18,7 @@
@0)))
/* Distribute operations in equality compares. */
-(for op (eq ne)
+(for op (eq_ops)
/* -exp op CST is exp op -CST. */
(simplify
/* ??? fix fold-const to use negate_expr_p */
@@ -29,7 +32,7 @@
/* From fold_comparison, in the order of transforms in there. */
/* Transform comparisons of the form X +- C1 CMP C2 to X CMP C2 -+ C1. */
-(for cmp (lt le eq ge gt ne)
+(for cmp (cmp_ops)
(for op (plus minus)
(simplify
(cmp (op @0 INTEGER_CST@1) INTEGER_CST@2)
@@ -47,7 +50,7 @@
is undefined for the type, but performing it here badly interacts
with the transformation in fold_cond_expr_with_comparison which
attempts to synthetize ABS_EXPR. */
-(for cmp (eq ne)
+(for cmp (eq_ops)
(simplify
(cmp (minus @0 @1) integer_zerop)
(cmp @0 @1)))
@@ -65,7 +68,7 @@
#endif
/* Simplify X * C1 CMP 0 to X CMP 0 if C1 is not zero. */
-(for op (lt le eq ne ge gt)
+(for op (cmp_ops)
(simplify
(op (mult @0 INTEGER_CST@1) integer_zerop@2)
/* In fold-const.c we have this and the following pattern
@@ -131,13 +134,13 @@
#endif
/* Fold ~X op ~Y as Y op X. */
-(for cmp (lt le eq ge gt ne)
+(for cmp (cmp_ops)
(simplify
(cmp (bit_not @0) (bit_not @1))
(cmp @1 @0)))
/* Fold ~X op C as X op' ~C, where op' is the swapped comparison. */
-(for cmp (lt le eq ge gt ne)
+(for cmp (cmp_ops)
(simplify
(cmp (bit_not @0) @1)
/* ??? (for cst in INTEGER_CST VECTOR_CST) is not supported yet. */