This shuffles routines around, grouping them properly and adding function comments. Applies minor code TLC.
Applied. Richard. 2014-09-25 Richard Biener <rguent...@suse.de> * genmatch.c: TLC. Index: gcc/genmatch.c =================================================================== --- gcc/genmatch.c (revision 215554) +++ gcc/genmatch.c (working copy) @@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. #include "vec.h" #include "is-a.h" + /* libccp helpers. */ static struct line_maps *line_table; @@ -112,26 +113,8 @@ output_line_directive (FILE *f, source_l } -/* Grammar - - capture = '@' number - op = predicate | expr [capture] - c_expr = '{' ... '}' - genexpr = '(' code genop... ')' - genop = capture | genexpr | c_expr - transform = 'match_and_transform' name expr genop - - Match and simplify (A + B) - B -> A - (simplify foo - (PLUS_EXPR (MINUS_EXPR integral_op_p@0 @1) @1) - @0) - - Match and simplify (CST + A) + CST to CST' + A - (simplify bar - (PLUS_EXPR INTEGER_CST_P@0 (PLUS_EXPR @1 INTEGER_CST_P@2)) - (PLUS_EXPR { int_const_binop (PLUS_EXPR, captures[0], captures[2]); } @1)) -*/ - +/* Pull in tree codes and builtin function codes from their + definition files. */ #define DEFTREECODE(SYM, STRING, TYPE, NARGS) SYM, enum tree_code { @@ -150,12 +133,12 @@ END_BUILTINS }; #undef DEF_BUILTIN -/* Hashtable of known pattern operators. This is pre-seeded from - all known tree codes and all known builtin function ids. */ + +/* Base class for all identifiers the parser knows. */ struct id_base : typed_noop_remove<id_base> { - enum id_kind { CODE, FN, PREDICATE, USER_DEFINED } kind; + enum id_kind { CODE, FN, PREDICATE, USER } kind; id_base (id_kind, const char *, int = -1); @@ -184,6 +167,8 @@ id_base::equal (const value_type *op1, && strcmp (op1->id, op2->id) == 0); } +/* 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; id_base::id_base (id_kind kind_, const char *id_, int nargs_) @@ -194,6 +179,8 @@ id_base::id_base (id_kind kind_, const c hashval = htab_hash_string (id); } +/* Identifier that maps to a tree code. */ + struct operator_id : public id_base { operator_id (enum tree_code code_, const char *id_, unsigned nargs_, @@ -203,6 +190,8 @@ struct operator_id : public id_base const char *tcc; }; +/* Identifier that maps to a builtin function code. */ + struct fn_id : public id_base { fn_id (enum built_in_function fn_, const char *id_) @@ -212,6 +201,8 @@ struct fn_id : public id_base struct simplify; +/* Identifier that maps to a user-defined predicate. */ + struct predicate_id : public id_base { predicate_id (const char *id_) @@ -219,10 +210,12 @@ struct predicate_id : public id_base vec<simplify *> matchers; }; +/* Identifier that maps to a operator defined by a 'for' directive. */ + struct user_id : public id_base { user_id (const char *id_) - : id_base (id_base::USER_DEFINED, id_), substitutes (vNULL) {} + : id_base (id_base::USER, id_), substitutes (vNULL) {} vec<id_base *> substitutes; }; @@ -250,6 +243,16 @@ is_a_helper <predicate_id *>::test (id_b return id->kind == id_base::PREDICATE; } +template<> +template<> +inline bool +is_a_helper <user_id *>::test (id_base *id) +{ + return id->kind == id_base::USER; +} + +/* Add a predicate identifier to the hash. */ + static predicate_id * add_predicate (const char *id) { @@ -261,6 +264,8 @@ add_predicate (const char *id) return p; } +/* Add a tree code identifier to the hash. */ + static void add_operator (enum tree_code code, const char *id, const char *tcc, unsigned nargs) @@ -281,6 +286,8 @@ add_operator (enum tree_code code, const *slot = op; } +/* Add a builtin identifier to the hash. */ + static void add_builtin (enum built_in_function code, const char *id) { @@ -291,35 +298,80 @@ add_builtin (enum built_in_function code *slot = fn; } +/* Helper for easy comparing ID with tree code CODE. */ + static bool operator==(id_base &id, enum tree_code code) { - if (id.kind != id_base::CODE) - return false; - return static_cast <operator_id&>(id).code == code; + if (operator_id *oid = dyn_cast <operator_id *> (&id)) + return oid->code == code; + return false; +} + +/* Lookup the identifier ID. */ + +id_base * +get_operator (const char *id) +{ + id_base tem (id_base::CODE, id); + + id_base *op = operators->find_with_hash (&tem, tem.hashval); + if (op) + return op; + + /* Try all-uppercase. */ + char *id2 = xstrdup (id); + for (unsigned i = 0; i < strlen (id2); ++i) + id2[i] = TOUPPER (id2[i]); + new (&tem) id_base (id_base::CODE, id2); + op = operators->find_with_hash (&tem, tem.hashval); + if (op) + { + free (id2); + return op; + } + + /* Try _EXPR appended. */ + id2 = (char *)xrealloc (id2, strlen (id2) + sizeof ("_EXPR") + 1); + strcat (id2, "_EXPR"); + new (&tem) id_base (id_base::CODE, id2); + op = operators->find_with_hash (&tem, tem.hashval); + if (op) + { + free (id2); + return op; + } + + return 0; } -/* The predicate expression tree structure. */ +/* The AST produced by parsing of the pattern definitions. */ struct dt_operand; +/* The base class for operands. */ + struct operand { enum op_type { OP_PREDICATE, OP_EXPR, OP_CAPTURE, OP_C_EXPR }; operand (enum op_type type_) : type (type_) {} enum op_type type; - virtual void gen_transform (FILE *f, const char *, bool, int, const char *, dt_operand ** = 0) = 0; + virtual void gen_transform (FILE *, const char *, bool, int, + const char *, dt_operand ** = 0) + { gcc_unreachable (); } }; +/* A predicate operand. Predicates are leafs in the AST. */ + struct predicate : public operand { predicate (predicate_id *p_) : operand (OP_PREDICATE), p (p_) {} predicate_id *p; - virtual void gen_transform (FILE *, const char *, bool, int, const char *, dt_operand ** = 0) - { gcc_unreachable (); } }; +/* An operand that constitutes an expression. Expressions include + function calls and user-defined predicate invocations. */ struct expr : public operand { @@ -327,41 +379,54 @@ struct expr : public operand : operand (OP_EXPR), operation (operation_), ops (vNULL), expr_type (NULL), is_commutative (is_commutative_) {} void append_op (operand *op) { ops.safe_push (op); } + /* The operator and its operands. */ id_base *operation; vec<operand *> ops; + /* An explicitely specified type - used exclusively for conversions. */ const char *expr_type; + /* Whether the operation is to be applied commutatively. This is + later lowered to two separate patterns. */ bool is_commutative; virtual void gen_transform (FILE *f, const char *, bool, int, const char *, dt_operand ** = 0); }; +/* An operator that is represented by native C code. This is always + a leaf operand in the AST. This class is also used to represent + the code to be generated for 'if' and 'with' expressions. */ + struct c_expr : public operand { + /* A mapping of an identifier and its replacement. Used to apply + 'for' lowering. */ struct id_tab { const char *id; const char *oper; - id_tab (const char *id_, const char *oper_): id (id_), oper (oper_) {} }; - c_expr (cpp_reader *r_, vec<cpp_token> code_, unsigned nr_stmts_, vec<id_tab> ids_ = vNULL) : operand (OP_C_EXPR), r (r_), code (code_), - nr_stmts (nr_stmts_), fname (NULL), ids (ids_) {} + nr_stmts (nr_stmts_), ids (ids_) {} + /* cpplib tokens and state to transform this back to source. */ cpp_reader *r; vec<cpp_token> code; + /* The number of statements parsed (well, the number of ';'s). */ unsigned nr_stmts; - char *fname; + /* The identifier replacement vector. */ vec<id_tab> ids; - virtual void gen_transform (FILE *f, const char *, bool, int, const char *, dt_operand **); }; +/* A wrapper around another operand that captures its value. */ + struct capture : public operand { capture (const char *where_, operand *what_) : operand (OP_CAPTURE), where (where_), what (what_) {} + /* Identifier for the value. */ const char *where; + /* The captured value. */ operand *what; virtual void gen_transform (FILE *f, const char *, bool, int, const char *, dt_operand ** = 0); }; @@ -398,153 +463,48 @@ is_a_helper <expr *>::test (operand *op) return op->type == operand::OP_EXPR; } -id_base * -get_operator (const char *id) -{ - id_base tem (id_base::CODE, id); - - id_base *op = operators->find_with_hash (&tem, tem.hashval); - if (op) - return op; +/* Helper to distinguish 'if' from 'with' expressions. */ - /* Try all-uppercase. */ - char *id2 = xstrdup (id); - for (unsigned i = 0; i < strlen (id2); ++i) - id2[i] = TOUPPER (id2[i]); - new (&tem) id_base (id_base::CODE, id2); - op = operators->find_with_hash (&tem, tem.hashval); - if (op) - { - free (id2); - return op; - } - - /* Try _EXPR appended. */ - id2 = (char *)xrealloc (id2, strlen (id2) + sizeof ("_EXPR") + 1); - strcat (id2, "_EXPR"); - new (&tem) id_base (id_base::CODE, id2); - op = operators->find_with_hash (&tem, tem.hashval); - if (op) - { - free (id2); - return op; - } - - return 0; -} - -struct if_or_with { - 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; +struct if_or_with +{ + 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; }; -struct simplify { +/* The main class of a pattern and its transform. This is used to + represent both (simplify ...) and (match ...) kinds. The AST + duplicates all outer 'if' and 'for' expressions here so each + simplify can exist in isolation. */ + +struct simplify +{ simplify (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_) + struct operand *result_, source_location result_location_, + vec<if_or_with> ifexpr_vec_, vec<vec<user_id *> > for_vec_) : match (match_), match_location (match_location_), result (result_), result_location (result_location_), ifexpr_vec (ifexpr_vec_), for_vec (for_vec_) {} + /* 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. */ 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; }; -struct dt_node -{ - enum dt_type { DT_NODE, DT_OPERAND, DT_TRUE, DT_MATCH, DT_SIMPLIFY }; - - enum dt_type type; - unsigned level; - vec<dt_node *> kids; - - dt_node (enum dt_type type_): type (type_), level (0), kids (vNULL) {} - - dt_node *append_node (dt_node *); - dt_node *append_op (operand *, dt_node *parent = 0, unsigned pos = 0); - dt_node *append_true_op (dt_node *parent = 0, unsigned pos = 0); - dt_node *append_match_op (dt_operand *, dt_node *parent = 0, unsigned pos = 0); - dt_node *append_simplify (simplify *, unsigned, dt_operand **); - - virtual void gen_gimple (FILE *) {} - virtual void gen_generic (FILE *) {} - - void gen_gimple_kids (FILE *); - void gen_generic_kids (FILE *); -}; - -struct dt_operand: public dt_node -{ - operand *op; - dt_operand *match_dop; - dt_operand *parent; - unsigned pos; - - dt_operand (enum dt_type type, operand *op_, dt_operand *match_dop_, dt_operand *parent_ = 0, unsigned pos_ = 0) - : dt_node (type), op (op_), match_dop (match_dop_), parent (parent_), pos (pos_) {} - - virtual void gen_gimple (FILE *); - virtual void gen_generic (FILE *); - unsigned gen_predicate (FILE *, const char *, bool); - unsigned gen_match_op (FILE *, const char *); - - unsigned gen_gimple_expr (FILE *); - unsigned gen_generic_expr (FILE *, const char *); - - char *get_name (char *); - void gen_opname (char *, unsigned); -}; - - -struct dt_simplify: public dt_node -{ - static const unsigned capture_max = 6; - simplify *s; - unsigned pattern_no; - dt_operand *indexes[capture_max]; - - dt_simplify (simplify *s_, unsigned pattern_no_, dt_operand **indexes_) - : dt_node (DT_SIMPLIFY), s (s_), pattern_no (pattern_no_) - { - for (unsigned i = 0; i < capture_max; ++i) - indexes[i] = indexes_[i]; - } - - void gen (FILE *f, bool); - virtual void gen_gimple (FILE *f) { gen (f, true); } - virtual void gen_generic (FILE *f) { gen (f, false); } -}; - -template<> -template<> -inline bool -is_a_helper <dt_operand *>::test (dt_node *n) -{ - return n->type == dt_node::DT_OPERAND; -} - -struct decision_tree -{ - dt_node *root; - - void insert (struct simplify *, unsigned); - void gen_gimple (FILE *f = stderr); - void gen_generic (FILE *f = stderr); - void print (FILE *f = stderr); - - decision_tree () { root = new dt_node (dt_node::DT_NODE); } - - static dt_node *insert_operand (dt_node *, operand *, dt_operand **indexes, unsigned pos = 0, dt_node *parent = 0); - static dt_node *find_node (vec<dt_node *>&, dt_node *); - static bool cmp_node (dt_node *, dt_node *); - static void print_node (dt_node *, FILE *f = stderr, unsigned = 0); -}; +/* Debugging routines for dumping the AST. */ DEBUG_FUNCTION void print_operand (operand *o, FILE *f = stderr, bool flattened = false) @@ -594,7 +554,12 @@ print_matches (struct simplify *s, FILE putc ('\n', f); } -void + +/* AST lowering. */ + +/* Lowering of commutative operators. */ + +static void cartesian_product (const vec< vec<operand *> >& ops_vector, vec< vec<operand *> >& result, vec<operand *>& v, unsigned n) { if (n == ops_vector.length ()) @@ -611,7 +576,7 @@ cartesian_product (const vec< vec<operan } } -void +static void cartesian_product (const vec< vec<operand *> >& ops_vector, vec< vec<operand *> >& result, unsigned n_ops) { vec<operand *> v = vNULL; @@ -619,14 +584,13 @@ cartesian_product (const vec< vec<operan cartesian_product (ops_vector, result, v, 0); } -vec<operand *> +static vec<operand *> commutate (operand *op) { vec<operand *> ret = vNULL; - if (op->type == operand::OP_CAPTURE) + if (capture *c = dyn_cast <capture *> (op)) { - capture *c = static_cast<capture *> (op); if (!c->what) { ret.safe_push (op); @@ -641,19 +605,13 @@ commutate (operand *op) return ret; } - if (op->type != operand::OP_EXPR) + expr *e = dyn_cast <expr *> (op); + if (!e || e->ops.length () == 0) { ret.safe_push (op); return ret; } - expr *e = static_cast<expr *> (op); - if (e->ops.length () == 0) - { - ret.safe_push (e); - return ret; - } - vec< vec<operand *> > ops_vector = vNULL; for (unsigned i = 0; i < e->ops.length (); ++i) ops_vector.safe_push (commutate (e->ops[i])); @@ -684,7 +642,7 @@ commutate (operand *op) return ret; } -void +static void lower_commutative (simplify *s, vec<simplify *>& simplifiers) { vec<operand *> matchers = commutate (s->match); @@ -697,7 +655,9 @@ lower_commutative (simplify *s, vec<simp } } -operand * +/* Lowering of conditional converts. */ + +static operand * lower_opt_convert (operand *o, enum tree_code oper) { if (capture *c = dyn_cast<capture *> (o)) @@ -708,10 +668,10 @@ lower_opt_convert (operand *o, enum tree return c; } - if (!is_a<expr *> (o)) + expr *e = dyn_cast<expr *> (o); + if (!e) return o; - expr *e = as_a<expr *> (o); if (*e->operation == oper) { expr *ne = new expr (get_operator ("CONVERT_EXPR")); @@ -737,10 +697,10 @@ remove_opt_convert (operand *o, enum tre return c; } - if (!is_a<expr *> (o)) + expr *e = as_a<expr *> (o); + if (!e) return o; - expr *e = as_a<expr *> (o); if (*e->operation == oper) return remove_opt_convert (e->ops[0], oper); @@ -751,7 +711,7 @@ remove_opt_convert (operand *o, enum tre return ne; } -bool +static bool has_opt_convert (operand *o, enum tree_code oper) { if (capture *c = dyn_cast<capture *> (o)) @@ -762,11 +722,10 @@ has_opt_convert (operand *o, enum tree_c return false; } - if (!is_a<expr *> (o)) + expr *e = dyn_cast<expr *> (o); + if (!e) return false; - expr *e = as_a<expr *> (o); - if (*e->operation == oper) return true; @@ -777,7 +736,7 @@ has_opt_convert (operand *o, enum tree_c return false; } -void +static void lower_opt_convert (vec<operand *>& v, operand *o, enum tree_code oper) { if (has_opt_convert (o, oper)) @@ -787,7 +746,7 @@ lower_opt_convert (vec<operand *>& v, op } } -vec<operand *> +static vec<operand *> lower_opt_convert (operand *o) { vec<operand *> v1 = vNULL, v2; @@ -813,7 +772,7 @@ lower_opt_convert (operand *o) return v1; } -void +static void lower_opt_convert (simplify *s, vec<simplify *>& simplifiers) { vec<operand *> matchers = lower_opt_convert (s->match); @@ -862,7 +821,7 @@ replace_id (operand *o, user_id *id, id_ /* Lower recorded fors for SIN and output to SIMPLIFIERS. */ -void +static void lower_for (simplify *sin, vec<simplify *>& simplifiers) { vec<vec<user_id *> >& for_vec = sin->for_vec; @@ -918,219 +877,123 @@ lower_for (simplify *sin, vec<simplify * simplifiers.safe_push (worklist[i]); } -bool -is_conversion (id_base *op) +/* Lower the AST for everything in SIMPLIFIERS. */ + +static void +lower (vec<simplify *>& simplifiers) { - return (*op == CONVERT_EXPR - || *op == NOP_EXPR - || *op == FLOAT_EXPR - || *op == FIX_TRUNC_EXPR - || *op == VIEW_CONVERT_EXPR); -} + auto_vec<simplify *> out_simplifiers0; + for (unsigned i = 0; i < simplifiers.length (); ++i) + lower_opt_convert (simplifiers[i], out_simplifiers0); -/* Get the type to be used for generating operands of OP from the - various sources. */ + auto_vec<simplify *> out_simplifiers1; + for (unsigned i = 0; i < out_simplifiers0.length (); ++i) + lower_commutative (out_simplifiers0[i], out_simplifiers1); -static const char * -get_operand_type (id_base *op, const char *in_type, - const char *expr_type, - const char *other_oprnd_type) -{ - /* Generally operands whose type does not match the type of the - expression generated need to know their types but match and - thus can fall back to 'other_oprnd_type'. */ - if (is_conversion (op)) - return other_oprnd_type; - else if (*op == REALPART_EXPR - || *op == IMAGPART_EXPR) - return other_oprnd_type; - else if (is_a <operator_id *> (op) - && strcmp (as_a <operator_id *> (op)->tcc, "tcc_comparison") == 0) - return other_oprnd_type; - else - { - /* Otherwise all types should match - choose one in order of - preference. */ - if (expr_type) - return expr_type; - else if (in_type) - return in_type; - else - return other_oprnd_type; - } + simplifiers.truncate (0); + for (unsigned i = 0; i < out_simplifiers1.length (); ++i) + lower_for (out_simplifiers1[i], simplifiers); } -/* Code gen off the AST. */ -void -expr::gen_transform (FILE *f, const char *dest, bool gimple, int depth, - const char *in_type, dt_operand **indexes) + + +/* The decision tree built for generating GIMPLE and GENERIC pattern + matching code. It represents the 'match' expression of all + simplifies and has those as its leafs. */ + +struct dt_node { - bool conversion_p = is_conversion (operation); - const char *type = expr_type; - char optype[64]; - if (type) - /* If there was a type specification in the pattern use it. */ - ; - else if (conversion_p) - /* For conversions we need to build the expression using the - outer type passed in. */ - type = in_type; - else if (*operation == REALPART_EXPR - || *operation == IMAGPART_EXPR) - { - /* __real and __imag use the component type of its operand. */ - sprintf (optype, "TREE_TYPE (TREE_TYPE (ops%d[0]))", depth); - type = optype; - } - else if (is_a <operator_id *> (operation) - && strcmp (as_a <operator_id *> (operation)->tcc, "tcc_comparison") == 0) - { - /* comparisons use boolean_type_node (or what gets in), but - their operands need to figure out the types themselves. */ - sprintf (optype, "boolean_type_node"); - type = optype; - } - else - { - /* Other operations are of the same type as their first operand. */ - sprintf (optype, "TREE_TYPE (ops%d[0])", depth); - type = optype; - } - if (!type) - fatal ("two conversions in a row"); + enum dt_type { DT_NODE, DT_OPERAND, DT_TRUE, DT_MATCH, DT_SIMPLIFY }; - fprintf (f, "{\n"); - fprintf (f, " tree ops%d[%u], res;\n", depth, ops.length ()); - char op0type[64]; - snprintf (op0type, 64, "TREE_TYPE (ops%d[0])", depth); - for (unsigned i = 0; i < ops.length (); ++i) - { - char dest[32]; - snprintf (dest, 32, " ops%d[%u]", depth, i); - const char *optype - = get_operand_type (operation, in_type, expr_type, - i == 0 ? NULL : op0type); - ops[i]->gen_transform (f, dest, gimple, depth + 1, optype, indexes); - } + enum dt_type type; + unsigned level; + vec<dt_node *> kids; - if (gimple) - { - /* ??? Have another helper that is like gimple_build but may - fail if seq == NULL. */ - fprintf (f, " if (!seq)\n" - " {\n" - " res = gimple_simplify (%s, %s", - operation->id, type); - for (unsigned i = 0; i < ops.length (); ++i) - fprintf (f, ", ops%d[%u]", depth, i); - fprintf (f, ", seq, valueize);\n"); - fprintf (f, " if (!res) return false;\n"); - fprintf (f, " }\n"); - fprintf (f, " else\n"); - fprintf (f, " res = gimple_build (seq, UNKNOWN_LOCATION, %s, %s", - operation->id, type); - for (unsigned i = 0; i < ops.length (); ++i) - fprintf (f, ", ops%d[%u]", depth, i); - fprintf (f, ", valueize);\n"); - } - else - { - if (operation->kind == id_base::CODE) - fprintf (f, " res = fold_build%d (%s, %s", - ops.length(), operation->id, type); - else - fprintf (f, " res = build_call_expr (builtin_decl_implicit (%s), %d", - operation->id, ops.length()); - for (unsigned i = 0; i < ops.length (); ++i) - fprintf (f, ", ops%d[%u]", depth, i); - fprintf (f, ");\n"); - } - fprintf (f, " %s = res;\n", dest); - fprintf (f, "}\n"); -} + dt_node (enum dt_type type_): type (type_), level (0), kids (vNULL) {} + + dt_node *append_node (dt_node *); + dt_node *append_op (operand *, dt_node *parent = 0, unsigned pos = 0); + dt_node *append_true_op (dt_node *parent = 0, unsigned pos = 0); + dt_node *append_match_op (dt_operand *, dt_node *parent = 0, unsigned pos = 0); + dt_node *append_simplify (simplify *, unsigned, dt_operand **); -/* Generate code for a c_expr which is either the expression inside - an if statement or a sequence of statements which computes a - result to be stored to DEST. */ + virtual void gen_gimple (FILE *) {} + virtual void gen_generic (FILE *) {} -void -c_expr::gen_transform (FILE *f, const char *dest, - bool, int, const char *, dt_operand **) + void gen_gimple_kids (FILE *); + void gen_generic_kids (FILE *); +}; + +struct dt_operand : public dt_node { - if (dest && nr_stmts == 1) - fprintf (f, "%s = ", dest); + operand *op; + dt_operand *match_dop; + dt_operand *parent; + unsigned pos; + + dt_operand (enum dt_type type, operand *op_, dt_operand *match_dop_, + dt_operand *parent_ = 0, unsigned pos_ = 0) + : dt_node (type), op (op_), match_dop (match_dop_), + parent (parent_), pos (pos_) {} - unsigned stmt_nr = 1; - for (unsigned i = 0; i < code.length (); ++i) - { - const cpp_token *token = &code[i]; + virtual void gen_gimple (FILE *); + virtual void gen_generic (FILE *); + unsigned gen_predicate (FILE *, const char *, bool); + unsigned gen_match_op (FILE *, const char *); - /* Replace captures for code-gen. */ - if (token->type == CPP_ATSIGN) - { - const cpp_token *n = &code[i+1]; - if (n->type == CPP_NUMBER - && !(n->flags & PREV_WHITE)) - { - if (token->flags & PREV_WHITE) - fputc (' ', f); - fprintf (f, "captures[%s]", n->val.str.text); - ++i; - continue; - } - } + unsigned gen_gimple_expr (FILE *); + unsigned gen_generic_expr (FILE *, const char *); - if (token->flags & PREV_WHITE) - fputc (' ', f); + char *get_name (char *); + void gen_opname (char *, unsigned); +}; - if (token->type == CPP_NAME) - { - const char *id = (const char *) NODE_NAME (token->val.node.node); - unsigned j; - for (j = 0; j < ids.length (); ++j) - { - if (strcmp (id, ids[j].id) == 0) - { - fprintf (f, "%s", ids[j].oper); - break; - } - } - if (j < ids.length ()) - continue; - } +struct dt_simplify : public dt_node +{ + static const unsigned capture_max = 6; + simplify *s; + unsigned pattern_no; + dt_operand *indexes[capture_max]; + + dt_simplify (simplify *s_, unsigned pattern_no_, dt_operand **indexes_) + : dt_node (DT_SIMPLIFY), s (s_), pattern_no (pattern_no_) + { + for (unsigned i = 0; i < capture_max; ++i) + indexes[i] = indexes_[i]; + } - /* Output the token as string. */ - char *tk = (char *)cpp_token_as_text (r, token); - fputs (tk, f); + void gen (FILE *f, bool); + virtual void gen_gimple (FILE *f) { gen (f, true); } + virtual void gen_generic (FILE *f) { gen (f, false); } +}; - if (token->type == CPP_SEMICOLON) - { - stmt_nr++; - if (dest && stmt_nr == nr_stmts) - fprintf (f, "\n %s = ", dest); - else - fputc ('\n', f); - } - } +template<> +template<> +inline bool +is_a_helper <dt_operand *>::test (dt_node *n) +{ + return (n->type == dt_node::DT_OPERAND + || n->type == dt_node::DT_MATCH); } -void -capture::gen_transform (FILE *f, const char *dest, bool gimple, int depth, const char *in_type, dt_operand **indexes) +struct decision_tree { - if (what && is_a<expr *> (what)) - { - int index = atoi (where); - if (indexes[index] == 0) - { - char buf[20]; - sprintf (buf, "captures[%s]", where); - what->gen_transform (f, buf, gimple, depth, in_type, NULL); - } - } - - fprintf (f, "%s = captures[%s];\n", dest, where); -} + dt_node *root; + + void insert (struct simplify *, unsigned); + void gen_gimple (FILE *f = stderr); + void gen_generic (FILE *f = stderr); + void print (FILE *f = stderr); + + decision_tree () { root = new dt_node (dt_node::DT_NODE); } + + static dt_node *insert_operand (dt_node *, operand *, dt_operand **indexes, + unsigned pos = 0, dt_node *parent = 0); + static dt_node *find_node (vec<dt_node *>&, dt_node *); + static bool cmp_node (dt_node *, dt_node *); + static void print_node (dt_node *, FILE *f = stderr, unsigned = 0); +}; bool cmp_operand (operand *o1, operand *o2) @@ -1148,31 +1011,28 @@ cmp_operand (operand *o1, operand *o2) { expr *e1 = static_cast<expr *>(o1); expr *e2 = static_cast<expr *>(o2); - return strcmp (e1->operation->id, e2->operation->id) == 0; + return e1->operation == e2->operation; } else return false; } - bool decision_tree::cmp_node (dt_node *n1, dt_node *n2) { if (!n1 || !n2 || n1->type != n2->type) return false; - if (n1 == n2 || n1->type == dt_node::DT_TRUE) return true; if (n1->type == dt_node::DT_OPERAND) - return cmp_operand ((static_cast<dt_operand *> (n1))->op, (static_cast<dt_operand *> (n2))->op); - + return cmp_operand ((as_a<dt_operand *> (n1))->op, + (as_a<dt_operand *> (n2))->op); else if (n1->type == dt_node::DT_MATCH) - return (static_cast<dt_operand *> (n1))->match_dop == (static_cast<dt_operand *> (n2))->match_dop; - - else - return false; + return ((as_a<dt_operand *> (n1))->match_dop + == (as_a<dt_operand *> (n2))->match_dop); + return false; } dt_node * @@ -1212,7 +1072,7 @@ dt_node::append_node (dt_node *n) dt_node * dt_node::append_op (operand *op, dt_node *parent, unsigned pos) { - dt_operand *parent_ = static_cast<dt_operand *> (parent); + dt_operand *parent_ = safe_as_a<dt_operand *> (parent); dt_node *n = new dt_operand (DT_OPERAND, op, 0, parent_, pos); dt_node *p = append_node (n); @@ -1225,7 +1085,7 @@ dt_node::append_op (operand *op, dt_node dt_node * dt_node::append_true_op (dt_node *parent, unsigned pos) { - dt_operand *parent_ = static_cast<dt_operand *> (parent); + dt_operand *parent_ = as_a<dt_operand *> (parent); dt_node *n = new dt_operand (DT_TRUE, 0, 0, parent_, pos); dt_node *p = append_node (n); @@ -1260,9 +1120,8 @@ decision_tree::insert_operand (dt_node * { dt_node *q, *elm = 0; - if (o->type == operand::OP_CAPTURE) + if (capture *c = dyn_cast<capture *> (o)) { - capture *c = static_cast<capture *> (o); unsigned capt_index = atoi (c->where); if (indexes[capt_index] == 0) @@ -1275,10 +1134,12 @@ decision_tree::insert_operand (dt_node * goto at_assert_elm; } // get to the last capture - for (operand *what = c->what; what && is_a<capture *> (what); c = as_a<capture *> (what), what = c->what) + for (operand *what = c->what; + what && is_a<capture *> (what); + c = as_a<capture *> (what), what = c->what) ; - if (c->what == 0) + if (!c->what) { unsigned cc_index = atoi (c->where); dt_operand *match_op = indexes[cc_index]; @@ -1297,13 +1158,14 @@ decision_tree::insert_operand (dt_node * dt_operand temp (dt_node::DT_OPERAND, c->what, 0); elm = decision_tree::find_node (p->kids, &temp); } - + at_assert_elm: - gcc_assert (elm); - gcc_assert (elm->type == dt_node::DT_TRUE || elm->type == dt_node::DT_OPERAND || elm->type == dt_node::DT_MATCH); - indexes[capt_index] = static_cast<dt_operand *> (elm); - return q; - } + gcc_assert (elm->type == dt_node::DT_TRUE + || elm->type == dt_node::DT_OPERAND + || elm->type == dt_node::DT_MATCH); + indexes[capt_index] = static_cast<dt_operand *> (elm); + return q; + } else { p = p->append_match_op (indexes[capt_index], parent, pos); @@ -1316,11 +1178,10 @@ at_assert_elm: p = p->append_op (o, parent, pos); q = p; - if (o->type == operand::OP_EXPR) + if (expr *e = dyn_cast <expr *>(o)) { - expr *e = static_cast<expr *> (o); for (unsigned i = 0; i < e->ops.length (); ++i) - q = decision_tree::insert_operand (q, e->ops[i], indexes, i, p); + q = decision_tree::insert_operand (q, e->ops[i], indexes, i, p); } return q; @@ -1341,6 +1202,8 @@ decision_tree::insert (struct simplify * p->append_simplify (s, pattern_no, indexes); } +/* Debug functions to dump the decision tree. */ + DEBUG_FUNCTION void decision_tree::print_node (dt_node *p, FILE *f, unsigned indent) { @@ -1377,13 +1240,228 @@ decision_tree::print_node (dt_node *p, F decision_tree::print_node (p->kids[i], f, indent + 2); } - DEBUG_FUNCTION void decision_tree::print (FILE *f) { return decision_tree::print_node (root, f); } + + +/* Code generation off the decision tree and the refered AST nodes. */ + +bool +is_conversion (id_base *op) +{ + return (*op == CONVERT_EXPR + || *op == NOP_EXPR + || *op == FLOAT_EXPR + || *op == FIX_TRUNC_EXPR + || *op == VIEW_CONVERT_EXPR); +} + +/* Get the type to be used for generating operands of OP from the + various sources. */ + +static const char * +get_operand_type (id_base *op, const char *in_type, + const char *expr_type, + const char *other_oprnd_type) +{ + /* Generally operands whose type does not match the type of the + expression generated need to know their types but match and + thus can fall back to 'other_oprnd_type'. */ + if (is_conversion (op)) + return other_oprnd_type; + else if (*op == REALPART_EXPR + || *op == IMAGPART_EXPR) + return other_oprnd_type; + else if (is_a <operator_id *> (op) + && strcmp (as_a <operator_id *> (op)->tcc, "tcc_comparison") == 0) + return other_oprnd_type; + else + { + /* Otherwise all types should match - choose one in order of + preference. */ + if (expr_type) + return expr_type; + else if (in_type) + return in_type; + else + return other_oprnd_type; + } +} + +void +expr::gen_transform (FILE *f, const char *dest, bool gimple, int depth, + const char *in_type, dt_operand **indexes) +{ + bool conversion_p = is_conversion (operation); + const char *type = expr_type; + char optype[64]; + if (type) + /* If there was a type specification in the pattern use it. */ + ; + else if (conversion_p) + /* For conversions we need to build the expression using the + outer type passed in. */ + type = in_type; + else if (*operation == REALPART_EXPR + || *operation == IMAGPART_EXPR) + { + /* __real and __imag use the component type of its operand. */ + sprintf (optype, "TREE_TYPE (TREE_TYPE (ops%d[0]))", depth); + type = optype; + } + else if (is_a <operator_id *> (operation) + && strcmp (as_a <operator_id *> (operation)->tcc, "tcc_comparison") == 0) + { + /* comparisons use boolean_type_node (or what gets in), but + their operands need to figure out the types themselves. */ + sprintf (optype, "boolean_type_node"); + type = optype; + } + else + { + /* Other operations are of the same type as their first operand. */ + sprintf (optype, "TREE_TYPE (ops%d[0])", depth); + type = optype; + } + if (!type) + fatal ("two conversions in a row"); + + fprintf (f, "{\n"); + fprintf (f, " tree ops%d[%u], res;\n", depth, ops.length ()); + char op0type[64]; + snprintf (op0type, 64, "TREE_TYPE (ops%d[0])", depth); + for (unsigned i = 0; i < ops.length (); ++i) + { + char dest[32]; + snprintf (dest, 32, " ops%d[%u]", depth, i); + const char *optype + = get_operand_type (operation, in_type, expr_type, + i == 0 ? NULL : op0type); + ops[i]->gen_transform (f, dest, gimple, depth + 1, optype, indexes); + } + + if (gimple) + { + /* ??? Have another helper that is like gimple_build but may + fail if seq == NULL. */ + fprintf (f, " if (!seq)\n" + " {\n" + " res = gimple_simplify (%s, %s", + operation->id, type); + for (unsigned i = 0; i < ops.length (); ++i) + fprintf (f, ", ops%d[%u]", depth, i); + fprintf (f, ", seq, valueize);\n"); + fprintf (f, " if (!res) return false;\n"); + fprintf (f, " }\n"); + fprintf (f, " else\n"); + fprintf (f, " res = gimple_build (seq, UNKNOWN_LOCATION, %s, %s", + operation->id, type); + for (unsigned i = 0; i < ops.length (); ++i) + fprintf (f, ", ops%d[%u]", depth, i); + fprintf (f, ", valueize);\n"); + } + else + { + if (operation->kind == id_base::CODE) + fprintf (f, " res = fold_build%d (%s, %s", + ops.length(), operation->id, type); + else + fprintf (f, " res = build_call_expr (builtin_decl_implicit (%s), %d", + operation->id, ops.length()); + for (unsigned i = 0; i < ops.length (); ++i) + fprintf (f, ", ops%d[%u]", depth, i); + fprintf (f, ");\n"); + } + fprintf (f, " %s = res;\n", dest); + fprintf (f, "}\n"); +} + +/* Generate code for a c_expr which is either the expression inside + an if statement or a sequence of statements which computes a + result to be stored to DEST. */ + +void +c_expr::gen_transform (FILE *f, const char *dest, + bool, int, const char *, dt_operand **) +{ + if (dest && nr_stmts == 1) + fprintf (f, "%s = ", dest); + + unsigned stmt_nr = 1; + for (unsigned i = 0; i < code.length (); ++i) + { + const cpp_token *token = &code[i]; + + /* Replace captures for code-gen. */ + if (token->type == CPP_ATSIGN) + { + const cpp_token *n = &code[i+1]; + if (n->type == CPP_NUMBER + && !(n->flags & PREV_WHITE)) + { + if (token->flags & PREV_WHITE) + fputc (' ', f); + fprintf (f, "captures[%s]", n->val.str.text); + ++i; + continue; + } + } + + if (token->flags & PREV_WHITE) + fputc (' ', f); + + if (token->type == CPP_NAME) + { + const char *id = (const char *) NODE_NAME (token->val.node.node); + unsigned j; + for (j = 0; j < ids.length (); ++j) + { + if (strcmp (id, ids[j].id) == 0) + { + fprintf (f, "%s", ids[j].oper); + break; + } + } + if (j < ids.length ()) + continue; + } + + /* Output the token as string. */ + char *tk = (char *)cpp_token_as_text (r, token); + fputs (tk, f); + + if (token->type == CPP_SEMICOLON) + { + stmt_nr++; + if (dest && stmt_nr == nr_stmts) + fprintf (f, "\n %s = ", dest); + else + fputc ('\n', f); + } + } +} + +void +capture::gen_transform (FILE *f, const char *dest, bool gimple, int depth, const char *in_type, dt_operand **indexes) +{ + if (what && is_a<expr *> (what)) + { + int index = atoi (where); + if (indexes[index] == 0) + { + char buf[20]; + sprintf (buf, "captures[%s]", where); + what->gen_transform (f, buf, gimple, depth, in_type, NULL); + } + } + + fprintf (f, "%s = captures[%s];\n", dest, where); +} + char * dt_operand::get_name (char *name) { @@ -1515,8 +1593,9 @@ dt_node::gen_gimple_kids (FILE *f) dt_node *true_operand = NULL; for (unsigned i = 0; i < kids.length (); ++i) { - if (dt_operand *op = dyn_cast <dt_operand *> (kids[i])) + if (kids[i]->type == dt_node::DT_OPERAND) { + dt_operand *op = as_a<dt_operand *> (kids[i]); if (expr *e = dyn_cast <expr *> (op->op)) { if (e->ops.length () == 0) @@ -1856,13 +1935,17 @@ dt_node::gen_generic_kids (FILE *f) } } +/* 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, bool gimple) { fprintf (f, "{\n"); output_line_directive (f, s->result_location); - fprintf (f, "tree captures[%u] ATTRIBUTE_UNUSED = {};\n", dt_simplify::capture_max); + fprintf (f, "tree captures[%u] ATTRIBUTE_UNUSED = {};\n", + dt_simplify::capture_max); for (unsigned i = 0; i < dt_simplify::capture_max; ++i) if (indexes[i]) @@ -2021,6 +2104,8 @@ dt_simplify::gen (FILE *f, bool gimple) fprintf (f, "}\n"); } +/* Main entry to generate code for matching GIMPLE IL off the decision + tree. */ void decision_tree::gen_gimple (FILE *f) @@ -2065,6 +2150,8 @@ decision_tree::gen_gimple (FILE *f) } } +/* Main entry to generate code for matching GENERIC IL off the decision + tree. */ void decision_tree::gen_generic (FILE *f) @@ -2072,7 +2159,8 @@ decision_tree::gen_generic (FILE *f) for (unsigned n = 1; n <= 3; ++n) { fprintf (f, "\ntree\n" - "generic_simplify (enum tree_code code, tree type ATTRIBUTE_UNUSED"); + "generic_simplify (enum tree_code code, " + "tree type ATTRIBUTE_UNUSED"); for (unsigned i = 0; i < n; ++i) fprintf (f, ", tree op%d", i); fprintf (f, ")\n"); @@ -2122,6 +2210,8 @@ decision_tree::gen_generic (FILE *f) } } +/* Write a prototype for the function defined by the predicate P. */ + void write_predicate_prototype (FILE *f, predicate_id *p, bool gimple) { @@ -2131,6 +2221,8 @@ write_predicate_prototype (FILE *f, pred gimple ? ", tree (*valueize)(tree) = NULL" : ""); } +/* Output code to implement the predicate P from the decision tree DT. */ + void write_predicate (FILE *f, predicate_id *p, decision_tree &dt, bool gimple) { @@ -2156,6 +2248,7 @@ write_predicate (FILE *f, predicate_id * "}\n"); } +/* Write the common header for the GIMPLE/GENERIC IL matching routines. */ static void write_header (FILE *f, const char *head) @@ -2168,6 +2261,9 @@ write_header (FILE *f, const char *head) } + +/* Lexing helpers. */ + /* Read the next non-whitespace token from R. */ static const cpp_token * @@ -2204,6 +2300,9 @@ peek (cpp_reader *r) return token; } +/* Peek at the next identifier token (or return NULL if the next + token is not an identifier or equal to ID if supplied). */ + static const cpp_token * peek_ident (cpp_reader *r, const char *id = 0) { @@ -2262,14 +2361,15 @@ get_ident (cpp_reader *r) return (const char *)CPP_HASHNODE (token->val.node.node)->ident.str; } +/* Eat an identifier token with value S from R. */ + static void eat_ident (cpp_reader *r, const char *s) { - const cpp_token *token = expect (r, CPP_NAME); - const char *t = (const char *) CPP_HASHNODE (token->val.node.node)->ident.str; - - if (strcmp (s, t)) - fatal_at (token, "expected %s got %s\n", s, t); + const cpp_token *token = peek (r); + const char *t = get_ident (r); + if (strcmp (s, t) != 0) + fatal_at (token, "expected '%s' got '%s'\n", s, t); } /* Read the next token from R and assert it is of type CPP_NUMBER and @@ -2283,7 +2383,9 @@ get_number (cpp_reader *r) } -/* Parsing. */ +/* AST parsing routines. */ + +static struct operand * parse_op (cpp_reader *r); /* Parse the operator ID, special-casing convert?, convert1? and convert2? */ @@ -2318,7 +2420,8 @@ parse_operation (cpp_reader *r) return op; } -static struct operand * parse_op (cpp_reader *r); +/* Parse a capture. + capture = '@'<number> */ static struct operand * parse_capture (cpp_reader *r, operand *op) @@ -2327,9 +2430,9 @@ parse_capture (cpp_reader *r, operand *o return new capture (get_number (r), op); } +/* Parse an expression + expr = '(' <operation>[capture][flag][type] <operand>... ')' */ -/* Parse - expr = (operation[capture] op...) */ static struct operand * parse_expr (cpp_reader *r) { @@ -2379,7 +2482,8 @@ parse_expr (cpp_reader *r) if (e->ops.length () == 2) e->is_commutative = true; else - fatal_at (token, "only binary operators or function with two arguments can be marked commutative"); + fatal_at (token, "only binary operators or function with " + "two arguments can be marked commutative"); } e->expr_type = expr_type; return op; @@ -2389,13 +2493,13 @@ parse_expr (cpp_reader *r) while (1); } -/* Parse [({] .... [})] literally recording everything as string and only - replacing captures. */ +/* Lex native C code delimited by START recording the preprocessing tokens + for later processing. + c_expr = ('{'|'(') <pp token>... ('}'|')') */ static c_expr * parse_c_expr (cpp_reader *r, cpp_ttype start) { - /* ??? Use an obstack to build the string. */ const cpp_token *token; cpp_ttype end; unsigned opencnt; @@ -2420,6 +2524,7 @@ parse_c_expr (cpp_reader *r, cpp_ttype s && --opencnt == 0) break; + /* This is a lame way of counting the number of statements. */ if (token->type == CPP_SEMICOLON) nr_stmts++; @@ -2430,8 +2535,9 @@ parse_c_expr (cpp_reader *r, cpp_ttype s return new c_expr (r, code, nr_stmts); } -/* Parse - op = predicate | ( expr ) */ +/* Parse an operand which is either an expression, a predicate or + a standalone capture. + op = predicate | expr | c_expr | capture */ static struct operand * parse_op (cpp_reader *r) @@ -2487,7 +2593,9 @@ parse_op (cpp_reader *r) } /* Parse - 'simplify' [ <ident> ] <expr> <result-op> + simplify = 'simplify' <expr> <result-op> + or + match = 'match' <ident> <expr> [<result-op>] with <result-op> = <op> | <if> | <with> <if> = '(' 'if' '(' <c-expr> ')' <result-op> ')' @@ -2569,7 +2677,8 @@ parse_simplify (cpp_reader *r, source_lo { expr *e = dyn_cast <expr *> (op); if (!e) - fatal_at (token, "match operand expression cannot be captured"); + fatal_at (token, "match operand expression cannot " + "be captured"); if (matcher->nargs == -1) matcher->nargs = e->ops.length (); if (matcher->nargs == 0 @@ -2624,9 +2733,15 @@ parse_simplify (cpp_reader *r, source_lo } } +/* Parsing of the outer control structures. */ + void parse_pattern (cpp_reader *, vec<simplify *>&, vec<if_or_with>&, vec<vec<user_id *> >&); +/* Parse a for expression + for = '(' 'for' <subst>... <pattern> ')' + subst = <ident> '(' <ident>... ')' */ + void parse_for (cpp_reader *r, source_location, vec<simplify *>& simplifiers, vec<if_or_with>& active_ifs, vec<vec<user_id *> >& active_fors) @@ -2721,6 +2836,9 @@ parse_for (cpp_reader *r, source_locatio operators->remove_elt (user_ids[i]); } +/* Parse an outer if expression. + if = '(' 'if' '(' <c-expr> ')' <pattern> ')' */ + void parse_if (cpp_reader *r, source_location loc, vec<simplify *>& simplifiers, vec<if_or_with>& active_ifs, vec<vec<user_id *> >& active_fors) @@ -2743,6 +2861,9 @@ parse_if (cpp_reader *r, source_location active_ifs.pop (); } +/* Parse a list of predefined predicate identifiers. + preds = '(' 'define_predicates' <ident>... ')' */ + static void parse_predicates (cpp_reader *r, source_location) { @@ -2757,11 +2878,8 @@ parse_predicates (cpp_reader *r, source_ while (1); } -static size_t -round_alloc_size (size_t s) -{ - return s; -} +/* Main entry for the parser. Parse outer control structures. + pattern = <preds>|<for>|<if>|<simplify>|<match> */ void parse_pattern (cpp_reader *r, vec<simplify *>& simplifiers, @@ -2807,23 +2925,15 @@ parse_pattern (cpp_reader *r, vec<simpli eat_token (r, CPP_CLOSE_PAREN); } -static vec<simplify *> -lower (vec<simplify *> simplifiers) +static size_t +round_alloc_size (size_t s) { - vec<simplify *> out_simplifiers0 = vNULL; - for (unsigned i = 0; i < simplifiers.length (); ++i) - lower_opt_convert (simplifiers[i], out_simplifiers0); - - vec<simplify *> out_simplifiers1 = vNULL; - for (unsigned i = 0; i < out_simplifiers0.length (); ++i) - lower_commutative (out_simplifiers0[i], out_simplifiers1); + return s; +} - vec<simplify *> out_simplifiers = vNULL; - for (unsigned i = 0; i < out_simplifiers1.length (); ++i) - lower_for (out_simplifiers1[i], out_simplifiers); - return out_simplifiers; -} +/* The genmatch generator progam. It reads from a pattern description + and outputs GIMPLE or GENERIC IL matching and simplification routines. */ int main(int argc, char **argv) @@ -2922,16 +3032,15 @@ add_operator (CONVERT2, "CONVERT2", "tcc if (predicate_id *p = dyn_cast <predicate_id *> (id)) if (p->matchers.exists ()) { - vec<simplify *> matchers = lower (p->matchers); - p->matchers = matchers; + lower (p->matchers); if (verbose) - for (unsigned i = 0; i < matchers.length (); ++i) - print_matches (matchers[i]); + for (unsigned i = 0; i < p->matchers.length (); ++i) + print_matches (p->matchers[i]); decision_tree dt; - for (unsigned i = 0; i < matchers.length (); ++i) - dt.insert (matchers[i], i); + for (unsigned i = 0; i < p->matchers.length (); ++i) + dt.insert (p->matchers[i], i); if (verbose) dt.print (stderr); @@ -2940,15 +3049,16 @@ add_operator (CONVERT2, "CONVERT2", "tcc } } - vec<simplify *> out_simplifiers = lower (simplifiers); + /* Lower the main simplifiers and generate code for them. */ + lower (simplifiers); if (verbose) - for (unsigned i = 0; i < out_simplifiers.length (); ++i) - print_matches (out_simplifiers[i]); + for (unsigned i = 0; i < simplifiers.length (); ++i) + print_matches (simplifiers[i]); decision_tree dt; - for (unsigned i = 0; i < out_simplifiers.length (); ++i) - dt.insert (out_simplifiers[i], i); + for (unsigned i = 0; i < simplifiers.length (); ++i) + dt.insert (simplifiers[i], i); if (verbose) dt.print (stderr); @@ -2958,6 +3068,7 @@ add_operator (CONVERT2, "CONVERT2", "tcc else dt.gen_generic (stdout); + /* Finalize. */ cpp_finish (r, NULL); cpp_destroy (r);