[PATCH v2 1/3] match: allow c variable for the code/operation of the result [PR126912]
Andrea Pinski <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
This allows a C variable for the code of the result to reduce how many for loops are needed and reduces the code size of the generated files by a factor of 6 (in some cases). This should allow for arm to build again at -O0. Currently this only allows if the variable contains `code` in it. If the identifier has cmp in it; genmatch assumes it will be a tcc_comparison for type resultion. I can add support for combined_fn and internal_fn later if needed. From looking into the match patterns right now; there is a few but none use a for loop for cases but rather just a few (3/4) if statements. So it was not high on my list of things to support currently. Bootstrapped and tested on x86_64-linux-gnu. PR middle-end/126912 gcc/ChangeLog: * doc/match-and-simplify.texi: Document new syntax. * genmatch.cc (class c_code_id): New class. (c_code_id::get_c_code_id): New method. (c_ids): New hashtable. (test): Handle C_CODE_ID. (lower_for): Handle c_code_id. (get_operand_type): Check cmp of c_code_id. (expr::gen_transform): Likewise. (dt_simplify::gen_1): Handle C_CODE_ID like CODE. (parser::parse_operation): Add bool res argument. For unknown id see if this can be a c code id for res. (parser::parse_expr): Add bool res argument. Pass down to parse_op and parse_operation. (parser::parse_op): Add bool res argument. Pass down to parse_expr and parse_op. (parser::parse_result): Pass true to parse_op and parse_expr. (parser::parse_simplify): Pass false to parse_op. (main): Allocate and free c_ids. * match.pd (`(a CMP1 b) bitop (a CMP2 b)`): Remove rcmp loop and update for the new syntax. (other comparison loops): Update for the new syntax. Signed-off-by: Andrea Pinski <[email protected]> --- gcc/doc/match-and-simplify.texi | 13 ++++ gcc/genmatch.cc | 114 ++++++++++++++++++++++++-------- gcc/match.pd | 77 +++++++++------------ 3 files changed, 129 insertions(+), 75 deletions(-) diff --git a/gcc/doc/match-and-simplify.texi b/gcc/doc/match-and-simplify.texi index b187dd27561..4f171a36f69 100644 --- a/gcc/doc/match-and-simplify.texi +++ b/gcc/doc/match-and-simplify.texi @@ -361,6 +361,19 @@ Usually the types of the generated result expressions are determined from the context, but sometimes like in the above case it is required that you specify them explicitly. +In the result of a simplify, a variable defined in @code{with} can be +use as the resulting tree code if it contains @code{code} in the name. +Comparisons results need to have cmp in its name to get the correct type for it. + +@smallexample + (simplify + (bit_xor (cmp @@0 @@1) integer_truep) + (with @{ enum tree_code rescmpcode = invert_tree_comparison + (cmp, HONOR_NANS (@@0)); @} + (if (TREE_CODE_CLASS (rescmpcode) == tcc_comparison) + (rescmpcode @@0 @@1)))) +@end smallexample + Another modifier for generated expressions is @code{^} which tells the machinery to try more matches for some special cases. For example, normally the @code{cond} only allows the gimple diff --git a/gcc/genmatch.cc b/gcc/genmatch.cc index 920cf27877d..44da9fa3970 100644 --- a/gcc/genmatch.cc +++ b/gcc/genmatch.cc @@ -1121,7 +1121,7 @@ comparison_code_p (enum tree_code code) class id_base : public nofree_ptr_hash<id_base> { public: - enum id_kind { CODE, FN, PREDICATE, USER, NULL_ID } kind; + enum id_kind { CODE, FN, PREDICATE, USER, C_CODE_ID, NULL_ID } kind; id_base (id_kind, const char *, int = -1); @@ -1199,6 +1199,37 @@ public: vec<simplify *> matchers; }; +// Identifier that maps to a operator defined by a 'C' identifier. +// Contains code in the id, also if contains cmp then it is a compare. + +class c_code_id : public id_base +{ +public: + c_code_id (const char *id_) + : id_base (id_base::C_CODE_ID, xstrdup (id_)), + cmp (strstr (id_, "cmp")) {} + static id_base *get_c_code_id (const char *); + ~c_code_id() { delete const_cast<char*>(id); } + bool cmp; +}; + +static hash_table<id_base> *c_ids; + +id_base * +c_code_id::get_c_code_id (const char *id) +{ + if (!strstr (id, "code")) + return nullptr; + id_base tem (id_base::C_CODE_ID, id); + + id_base **op = c_ids->find_slot_with_hash (&tem, tem.hashval, INSERT); + if (!*op) + *op = new c_code_id (id); + + return *op; +} + + /* Identifier that maps to a operator defined by a 'for' directive. */ class user_id : public id_base @@ -1244,6 +1275,14 @@ is_a_helper <user_id *>::test (id_base *id) return id->kind == id_base::USER; } +template<> +template<> +inline bool +is_a_helper <c_code_id *>::test (id_base *id) +{ + return id->kind == id_base::C_CODE_ID; +} + /* If ID has a pair of consecutive, commutative operands, return the index of the first, otherwise return -1. */ @@ -2301,6 +2340,8 @@ lower_for (simplify *sin, vec<simplify *>& simplifiers) } else if (is_a <fn_id *> (ids[i]->substitutes[j])) ; + else if (is_a <c_code_id *> (ids[i]->substitutes[j])) + ; else can_delay_subst = false; } @@ -3222,8 +3263,10 @@ get_operand_type (id_base *op, unsigned pos, 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) + else if ((is_a <operator_id *> (op) + && strcmp (as_a <operator_id *> (op)->tcc, "tcc_comparison") == 0) + || (is_a <c_code_id *> (op) + && as_a <c_code_id *>(op)->cmp)) return other_oprnd_type; else if (*op == COND_EXPR && pos == 0) @@ -3285,8 +3328,10 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple, depth); type = optype; } - else if (is_a <operator_id *> (opr) - && !strcmp (as_a <operator_id *> (opr)->tcc, "tcc_comparison")) + else if ((is_a <operator_id *> (opr) + && !strcmp (as_a <operator_id *> (opr)->tcc, "tcc_comparison")) + || (is_a <c_code_id *> (opr) + && as_a <c_code_id *> (opr)->cmp)) { /* comparisons use boolean_type_node (or what gets in), but their operands need to figure out the types themselves. */ @@ -3451,7 +3496,7 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple, fprintf_indent (f, indent + 2, "{\n"); indent += 4; } - if (opr->kind == id_base::CODE) + if (opr->kind == id_base::CODE || opr->kind == id_base::C_CODE_ID) fprintf_indent (f, indent, "_r%d = fold_build%d_loc (loc, %s, %s", depth, ops.length(), opr_name, type); else @@ -3460,7 +3505,7 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple, for (unsigned i = 0; i < ops.length (); ++i) fprintf (f, ", _o%d[%u]", depth, i); fprintf (f, ");\n"); - if (opr->kind != id_base::CODE) + if (opr->kind != id_base::CODE && opr->kind != id_base::C_CODE_ID) { fprintf_indent (f, indent, "if (!_r%d)\n", depth); fprintf_indent (f, indent, " goto %s;\n", fail_label); @@ -4630,7 +4675,7 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result) "_r = non_lvalue_loc (loc, res_op0);\n"); else { - if (is_a <operator_id *> (opr)) + if (is_a <operator_id *> (opr) || is_a <c_code_id *> (opr)) fprintf_indent (f, indent, "_r = fold_build%d_loc (loc, %s, type", e->ops.length (), @@ -4644,7 +4689,7 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result) for (unsigned j = 0; j < e->ops.length (); ++j) fprintf (f, ", res_op%d", j); fprintf (f, ");\n"); - if (!is_a <operator_id *> (opr)) + if (!is_a <operator_id *> (opr) && !is_a<c_code_id *> (opr)) { fprintf_indent (f, indent, "if (!_r)\n"); fprintf_indent (f, indent, " goto %s;\n", fail_label); @@ -5146,11 +5191,11 @@ private: unsigned get_internal_capture_id (); - id_base *parse_operation (unsigned char &); + id_base *parse_operation (unsigned char &, bool); operand *parse_capture (operand *, bool); - operand *parse_expr (); + operand *parse_expr (bool = false); c_expr *parse_c_expr (cpp_ttype); - operand *parse_op (); + operand *parse_op (bool); void record_operlist (location_t, user_id *); @@ -5338,7 +5383,7 @@ parser::record_operlist (location_t loc, user_id *p) convert2? */ id_base * -parser::parse_operation (unsigned char &opt_grp) +parser::parse_operation (unsigned char &opt_grp, bool res) { const cpp_token *id_tok = peek (); char *alt_id = NULL; @@ -5365,7 +5410,18 @@ parser::parse_operation (unsigned char &opt_grp) } id_base *op = get_operator (alt_id ? alt_id : id); if (!op) - fatal_at (id_tok, "unknown operator %s", alt_id ? alt_id : id); + { + // An unknown id that contains code in it is considered a C code identifier + if (res) + { + if (id_base *op = c_code_id::get_c_code_id (id)) + { + free (alt_id); + return op; + } + } + fatal_at (id_tok, "unknown operator %s", alt_id ? alt_id : id); + } if (alt_id) free (alt_id); user_id *p = dyn_cast<user_id *> (op); @@ -5420,11 +5476,11 @@ parser::parse_capture (operand *op, bool require_existing) expr = '(' <operation>[capture][flag][type] <operand>... ')' */ class operand * -parser::parse_expr () +parser::parse_expr (bool res) { const cpp_token *token = peek (); unsigned char opt_grp; - expr *e = new expr (parse_operation (opt_grp), token->src_loc); + expr *e = new expr (parse_operation (opt_grp, res), token->src_loc); token = peek (); operand *op; bool is_commutative = false; @@ -5537,7 +5593,7 @@ parser::parse_expr () else if (!(token->flags & PREV_WHITE)) fatal_at (token, "expected expression operand"); - e->append_op (parse_op ()); + e->append_op (parse_op (res)); } while (1); } @@ -5602,14 +5658,14 @@ parser::parse_c_expr (cpp_ttype start) op = predicate | expr | c_expr | capture */ class operand * -parser::parse_op () +parser::parse_op (bool res) { const cpp_token *token = peek (); class operand *op = NULL; if (token->type == CPP_OPEN_PAREN) { eat_token (CPP_OPEN_PAREN); - op = parse_expr (); + op = parse_expr (res); eat_token (CPP_CLOSE_PAREN); } else if (token->type == CPP_OPEN_BRACE) @@ -5695,7 +5751,7 @@ parser::parse_result (operand *result, predicate_id *matcher) { const cpp_token *token = peek (); if (token->type != CPP_OPEN_PAREN) - return parse_op (); + return parse_op (true); eat_token (CPP_OPEN_PAREN); if (peek_ident ("if")) @@ -5709,15 +5765,15 @@ parser::parse_result (operand *result, predicate_id *matcher) if (peek ()->type == CPP_OPEN_PAREN) ife->falseexpr = parse_result (result, matcher); else if (peek ()->type != CPP_CLOSE_PAREN) - ife->falseexpr = parse_op (); + ife->falseexpr = parse_op (true); } else if (peek ()->type != CPP_CLOSE_PAREN) { - ife->trueexpr = parse_op (); + ife->trueexpr = parse_op (true); if (peek ()->type == CPP_OPEN_PAREN) ife->falseexpr = parse_result (result, matcher); else if (peek ()->type != CPP_CLOSE_PAREN) - ife->falseexpr = parse_op (); + ife->falseexpr = parse_op (true); } /* If this if is immediately closed then it contains a manual matcher or is part of a predicate definition. */ @@ -5752,7 +5808,7 @@ parser::parse_result (operand *result, predicate_id *matcher) if (peek ()->type == CPP_OPEN_PAREN) ife->trueexpr = parse_result (result, matcher); else - ife->trueexpr = parse_op (); + ife->trueexpr = parse_op (true); eat_token (CPP_CLOSE_PAREN); if (peek ()->type != CPP_OPEN_PAREN || !peek_ident ("if", 2)) @@ -5771,7 +5827,7 @@ parser::parse_result (operand *result, predicate_id *matcher) if (peek ()->type == CPP_OPEN_PAREN) ife->trueexpr = parse_result (result, matcher); else - ife->trueexpr = parse_op (); + ife->trueexpr = parse_op (true); if (peek ()->type == CPP_OPEN_PAREN) fatal_at (peek(), "if inside switch cannot have an else"); eat_token (CPP_CLOSE_PAREN); @@ -5787,7 +5843,7 @@ parser::parse_result (operand *result, predicate_id *matcher) else { /* switch default clause */ - ife->falseexpr = parse_op (); + ife->falseexpr = parse_op (true); eat_token (CPP_CLOSE_PAREN); return res; } @@ -5799,7 +5855,7 @@ parser::parse_result (operand *result, predicate_id *matcher) { operand *op = result; if (!matcher) - op = parse_expr (); + op = parse_expr (true); eat_token (CPP_CLOSE_PAREN); return op; } @@ -5826,7 +5882,7 @@ parser::parse_simplify (simplify::simplify_kind kind, const cpp_token *loc = peek (); parsing_match_operand = true; - class operand *match = parse_op (); + class operand *match = parse_op (false); finish_match_operand (match); parsing_match_operand = false; if (match->type == operand::OP_CAPTURE && !matcher) @@ -6366,6 +6422,7 @@ main (int argc, char **argv) /* Pre-seed operators. */ operators = new hash_table<id_base> (1024); + c_ids = new hash_table<id_base> (4); #define DEFTREECODE(SYM, STRING, TYPE, NARGS) \ add_operator (SYM, # SYM, # TYPE, NARGS); #define END_OF_BASE_TREE_CODES @@ -6471,6 +6528,7 @@ main (int argc, char **argv) cpp_destroy (r); delete operators; + delete c_ids; return 0; } diff --git a/gcc/match.pd b/gcc/match.pd index eae8717bcfe..d255795c8dd 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -4006,20 +4006,19 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (for bitop (bit_and bit_ior) (for cmp1 (tcc_comparison) (for cmp2 (tcc_comparison) - (for rcmp (tcc_comparison) - (simplify - (bitop (cmp1 @0 @1) (cmp2 @0 @1)) - (with { - tree_code rescode; - tree res; - bool honor_nans = HONOR_NANS (@0); - rescode = combine_comparisons (bitop, cmp1, cmp2, - type, honor_nans, &res); - } - (if (rescode == INTEGER_CST) - { res; } - (if (rescode == rcmp) - (rcmp @0 @1))))))))) + (simplify + (bitop (cmp1 @0 @1) (cmp2 @0 @1)) + (with { + tree_code rescmpcode; + tree res; + bool honor_nans = HONOR_NANS (@0); + rescmpcode = combine_comparisons (bitop, cmp1, cmp2, + type, honor_nans, &res); + } + (if (rescmpcode == INTEGER_CST) + { res; } + (if (TREE_CODE_CLASS (rescmpcode) == tcc_comparison) + (rescmpcode @0 @1)))))))) /* (type)([0,1]@a != 0) -> (type)a (type)([0,1]@a == 1) -> (type)a @@ -7781,8 +7780,6 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) operator using invert_tree_comparison we have to simulate that with expression code iteration. */ (for cmp (tcc_comparison) - icmp (inverted_tcc_comparison) - ncmp (inverted_tcc_comparison_with_nans) /* Ideally we'd like to combine the following two patterns and handle some more cases by using (logical_inverted_value (cmp @0 @1)) @@ -7793,39 +7790,29 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (if (VECTOR_TYPE_P (type) || (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) == 1)) /* Comparison inversion may be impossible for trapping math, - invert_tree_comparison will tell us. But we can't use - a computed operator in the replacement tree thus we have - to play the trick below. */ - (with { enum tree_code ic = invert_tree_comparison + invert_tree_comparison will tell us. */ + (with { enum tree_code rescmpcode = invert_tree_comparison (cmp, HONOR_NANS (@0)); } - (if (ic == icmp) - (icmp @0 @1) - (if (ic == ncmp) - (ncmp @0 @1)))))) + (if (TREE_CODE_CLASS (rescmpcode) == tcc_comparison) + (rescmpcode @0 @1))))) (simplify (bit_xor (cmp @0 @1) integer_truep) - (with { enum tree_code ic = invert_tree_comparison + (with { enum tree_code rescmpcode = invert_tree_comparison (cmp, HONOR_NANS (@0)); } - (if (ic == icmp) - (icmp @0 @1) - (if (ic == ncmp) - (ncmp @0 @1))))) + (if (TREE_CODE_CLASS (rescmpcode) == tcc_comparison) + (rescmpcode @0 @1)))) /* ((cast)cmp) - 1 -> -(cast)icmp . */ (simplify (plus (convert? (cmp@2 @0 @1)) integer_minus_onep) (if (TYPE_PRECISION (type) > 1 && INTEGRAL_TYPE_P (TREE_TYPE (@2)) && TYPE_PRECISION (TREE_TYPE (@2)) == 1) /* Comparison inversion may be impossible for trapping math, - invert_tree_comparison will tell us. But we can't use - a computed operator in the replacement tree thus we have - to play the trick below. */ - (with { enum tree_code ic = invert_tree_comparison + invert_tree_comparison will tell us. */ + (with { enum tree_code rescmpcode = invert_tree_comparison (cmp, HONOR_NANS (@0)); tree cmptype = TREE_TYPE (@2); } - (if (ic == icmp) - (negate (convert (icmp:cmptype @0 @1))) - (if (ic == ncmp) - (negate (convert (ncmp:cmptype @0 @1)))))))) + (if (TREE_CODE_CLASS (rescmpcode) == tcc_comparison) + (negate (convert (rescmpcode:cmptype @0 @1))))))) /* The following bits are handled by fold_binary_op_with_conditional_arg. */ (simplify (ne (cmp@2 @0 @1) integer_zerop) @@ -7838,21 +7825,17 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (simplify (ne (cmp@2 @0 @1) integer_truep) (if (types_match (type, TREE_TYPE (@2))) - (with { enum tree_code ic = invert_tree_comparison + (with { enum tree_code rescmpcode = invert_tree_comparison (cmp, HONOR_NANS (@0)); } - (if (ic == icmp) - (icmp @0 @1) - (if (ic == ncmp) - (ncmp @0 @1)))))) + (if (TREE_CODE_CLASS (rescmpcode) == tcc_comparison) + (rescmpcode @0 @1))))) (simplify (eq (cmp@2 @0 @1) integer_zerop) (if (types_match (type, TREE_TYPE (@2))) - (with { enum tree_code ic = invert_tree_comparison + (with { enum tree_code rescmpcode = invert_tree_comparison (cmp, HONOR_NANS (@0)); } - (if (ic == icmp) - (icmp @0 @1) - (if (ic == ncmp) - (ncmp @0 @1))))))) + (if (TREE_CODE_CLASS (rescmpcode) == tcc_comparison) + (rescmpcode @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 -- 2.43.0