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