diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 09cd2bdb811..92e704cd2a4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,53 @@ +2014-11-12 Richard Biener + + Merge from match-and-simplify branch + 2014-11-04 Prathamesh Kulkarni + + * genmatch.c (user_id): Add new member is_oper_list. + (user_id::user_id): Add new default argument. + (parser::parse_operator_list): New function. + (parser::parse_for): Allow operator-list. + (parser::parse_pattern): Call parser::parse_operator_list. + (parser::parse_operation): Reject operator-list. + * match-builtin.pd: Define operator lists POWs, CBRTs and SQRTs. + + 2014-10-31 Prathamesh Kulkarni + + * genmatch.c (parser::parse_c_expr): Mark user-defined ops as used. + + 2014-10-30 Prathamesh Kulkarni + + * genmatch.c (parser::parse_op): Check if predicate is used in + result operand. + + 2014-10-29 Prathamesh Kulkarni + + * genmatch.c (parser::parse_for): Make sure to have a valid + token to report errors at. + + 2014-10-28 Prathamesh Kulkarni + + * genmatch.c (parser): Add new member parsing_match_operand. + (parser::parse_operation): Check for conditional convert in result + operand. + (parser::parse_expr): Check for commutative operator in result operand. + Check for :type in match operand. + (parser::parse_simplify): Set/unset parsing_match_operand. + (parser::parser): Initialize parsing_match_operand. + + 2014-10-28 Richard Biener + + * genmatch.c (parser::parse_for): Properly check for already + defined operators. + + 2014-10-28 Prathamesh Kulkarni + + * genmatch.c (error_cb): Adjust for printing warnings. + (warning_at): New function. + (user_id): Add new member used. + (get_operator): Mark user_id as used. + (parse_for): Warn for unused operators. + 2014-11-12 Richard Biener * match.pd: Implement simple complex operations cancelling. diff --git a/gcc/genmatch.c b/gcc/genmatch.c index 437e29a3468..0e4208f17e7 100644 --- a/gcc/genmatch.c +++ b/gcc/genmatch.c @@ -54,13 +54,14 @@ static bool #if GCC_VERSION >= 4001 __attribute__((format (printf, 6, 0))) #endif -error_cb (cpp_reader *, int, int, source_location location, +error_cb (cpp_reader *, int errtype, int, source_location location, unsigned int, const char *msg, va_list *ap) { const line_map *map; linemap_resolve_location (line_table, location, LRK_SPELLING_LOCATION, &map); expanded_location loc = linemap_expand_location (line_table, map, location); - fprintf (stderr, "%s:%d:%d error: ", loc.file, loc.line, loc.column); + fprintf (stderr, "%s:%d:%d %s: ", loc.file, loc.line, loc.column, + (errtype == CPP_DL_WARNING) ? "warning" : "error"); vfprintf (stderr, msg, *ap); fprintf (stderr, "\n"); FILE *f = fopen (loc.file, "r"); @@ -86,7 +87,10 @@ error_cb (cpp_reader *, int, int, source_location location, notfound: fclose (f); } - exit (1); + + if (errtype == CPP_DL_FATAL) + exit (1); + return false; } static void @@ -101,6 +105,18 @@ fatal_at (const cpp_token *tk, const char *msg, ...) va_end (ap); } +static void +#if GCC_VERSION >= 4001 +__attribute__((format (printf, 2, 3))) +#endif +warning_at (const cpp_token *tk, const char *msg, ...) +{ + va_list ap; + va_start (ap, msg); + error_cb (NULL, CPP_DL_WARNING, 0, tk->src_loc, 0, msg, &ap); + va_end (ap); +} + static void output_line_directive (FILE *f, source_location location, bool dumpfile = false) @@ -228,9 +244,12 @@ struct predicate_id : public id_base struct user_id : public id_base { - user_id (const char *id_) - : id_base (id_base::USER, id_), substitutes (vNULL) {} + user_id (const char *id_, bool is_oper_list_ = false) + : id_base (id_base::USER, id_), substitutes (vNULL), + used (false), is_oper_list (is_oper_list_) {} vec substitutes; + bool used; + bool is_oper_list; }; template<> @@ -331,7 +350,12 @@ get_operator (const char *id) id_base *op = operators->find_with_hash (&tem, tem.hashval); if (op) - return op; + { + /* If this is a user-defined identifier track whether it was used. */ + if (user_id *uid = dyn_cast (op)) + uid->used = true; + return op; + } /* Try all-uppercase. */ char *id2 = xstrdup (id); @@ -2650,6 +2674,7 @@ private: 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 active_ifs; @@ -2660,6 +2685,7 @@ private: public: vec simplifiers; vec user_predicates; + bool parsing_match_operand; }; /* Lexing helpers. */ @@ -2805,6 +2831,10 @@ parser::parse_operation () ; else fatal_at (id_tok, "non-convert operator conditionalized"); + + if (!parsing_match_operand) + fatal_at (id_tok, "conditional convert can only be used in " + "match expression"); eat_token (CPP_QUERY); } else if (strcmp (id, "convert1") == 0 @@ -2813,6 +2843,11 @@ parser::parse_operation () id_base *op = get_operator (id); if (!op) fatal_at (id_tok, "unknown operator %s", id); + + user_id *p = dyn_cast (op); + if (p && p->is_oper_list) + fatal_at (id_tok, "operator-list not allowed in expression"); + return op; } @@ -2824,7 +2859,7 @@ parser::parse_capture (operand *op) { eat_token (CPP_ATSIGN); const cpp_token *token = peek (); - const char *id; + const char *id = NULL; if (token->type == CPP_NUMBER) id = get_number (); else if (token->type == CPP_NAME) @@ -2861,11 +2896,21 @@ parser::parse_expr () { const char *s = get_ident (); if (s[0] == 'c' && !s[1]) - is_commutative = true; + { + if (!parsing_match_operand) + fatal_at (token, + "flag 'c' can only be used in match expression"); + is_commutative = true; + } else if (s[1] != '\0') - expr_type = s; + { + if (parsing_match_operand) + fatal_at (token, "type can only be used in result expression"); + expr_type = s; + } else fatal_at (token, "flag %s not recognized", s); + token = peek (); } else @@ -2937,6 +2982,11 @@ parser::parse_c_expr (cpp_ttype start) if (token->type == CPP_SEMICOLON) nr_stmts++; + /* If this is possibly a user-defined identifier mark it used. */ + if (token->type == CPP_NAME) + get_operator ((const char *)CPP_HASHNODE + (token->val.node.node)->ident.str); + /* Record the token. */ code.safe_push (*token); } @@ -2984,6 +3034,8 @@ parser::parse_op () op = new predicate (p); else fatal_at (token, "using an unsupported operator as predicate"); + if (!parsing_match_operand) + fatal_at (token, "predicates are only allowed in match expression"); token = peek (); if (token->flags & PREV_WHITE) return op; @@ -3020,7 +3072,9 @@ parser::parse_simplify (source_location match_location, capture_ids = new cid_map_t; const cpp_token *loc = peek (); + parsing_match_operand = true; struct operand *match = parse_op (); + parsing_match_operand = false; if (match->type == operand::OP_CAPTURE && !matcher) fatal_at (loc, "outermost expression cannot be captured"); if (match->type == operand::OP_EXPR @@ -3138,24 +3192,26 @@ parser::parse_simplify (source_location match_location, void parser::parse_for (source_location) { + auto_vec user_id_tokens; vec user_ids = vNULL; const cpp_token *token; unsigned min_n_opers = 0, max_n_opers = 0; while (1) { - token = peek_ident (); - if (token == 0) + token = peek (); + if (token->type != CPP_NAME) break; /* Insert the user defined operators into the operator hash. */ const char *id = get_ident (); + if (get_operator (id) != 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); - if (*slot) - fatal_at (token, "operator already defined"); *slot = op; user_ids.safe_push (op); + user_id_tokens.safe_push (token); eat_token (CPP_OPEN_PAREN); @@ -3177,7 +3233,11 @@ parser::parse_for (source_location) fatal_at (token, "operator '%s' with arity %d does not match " "others with arity %d", oper, idb->nargs, arity); - op->substitutes.safe_push (idb); + user_id *p = dyn_cast (idb); + if (p && p->is_oper_list) + op->substitutes.safe_splice (p->substitutes); + else + op->substitutes.safe_push (idb); } op->nargs = arity; token = expect (CPP_CLOSE_PAREN); @@ -3225,7 +3285,59 @@ parser::parse_for (source_location) /* Remove user-defined operators from the hash again. */ for (unsigned i = 0; i < user_ids.length (); ++i) - operators->remove_elt (user_ids[i]); + { + if (!user_ids[i]->used) + warning_at (user_id_tokens[i], + "operator %s defined but not used", user_ids[i]->id); + operators->remove_elt (user_ids[i]); + } +} + +/* Parse an identifier associated with a list of operators. + oprs = '(' 'define_operator_list' ... ')' */ + +void +parser::parse_operator_list (source_location) +{ + const cpp_token *token = peek (); + const char *id = get_ident (); + + if (get_operator (id) != 0) + fatal_at (token, "operator %s already defined", id); + + user_id *op = new user_id (id, true); + int arity = -1; + + while ((token = peek_ident ()) != 0) + { + token = peek (); + const char *oper = get_ident (); + id_base *idb = get_operator (oper); + + if (idb == 0) + fatal_at (token, "no such operator '%s'", oper); + + if (arity == -1) + arity = idb->nargs; + else if (idb->nargs == -1) + ; + else if (arity != idb->nargs) + fatal_at (token, "operator '%s' with arity %d does not match " + "others with arity %d", oper, idb->nargs, arity); + + /* We allow composition of multiple operator lists. */ + if (user_id *p = dyn_cast (idb)) + op->substitutes.safe_splice (p->substitutes); + else + op->substitutes.safe_push (idb); + } + + if (op->substitutes.length () == 0) + fatal_at (token, "operator-list cannot be empty"); + + op->nargs = arity; + id_base **slot = operators->find_slot_with_hash (op, op->hashval, INSERT); + *slot = op; } /* Parse an outer if expression. @@ -3328,6 +3440,13 @@ parser::parse_pattern () 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) + { + if (active_ifs.length () > 0 + || active_fors.length () > 0) + fatal_at (token, "operator-list inside if or for is not supported"); + parse_operator_list (token->src_loc); + } else fatal_at (token, "expected %s'simplify', 'match', 'for' or 'if'", active_ifs.length () == 0 && active_fors.length () == 0 @@ -3345,6 +3464,7 @@ parser::parser (cpp_reader *r_) active_fors = vNULL; simplifiers = vNULL; user_predicates = vNULL; + parsing_match_operand = false; const cpp_token *token = next (); while (token->type != CPP_EOF)