This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH 3/5] Rewrite part of and_comparisons_1 into match.pd.
I'm sending updated version of the patch where I changed
from previous version:
- more compact matching is used (note @3 and @4):
(and (code1:c@3 @0 INTEGER_CST@1) (code2:c@4 @0 INTEGER_CST@2))
Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
Ready to be installed?
Thanks,
Martin
>From e21404f55f51701d25a6d859b892b219d2041e02 Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Fri, 6 Sep 2019 12:34:49 +0200
Subject: [PATCH 3/5] Rewrite part of and_comparisons_1 into match.pd.
gcc/ChangeLog:
2019-09-09 Martin Liska <mliska@suse.cz>
* genmatch.c (dt_node::append_simplify): Do not print
warning when we have duplicate patterns belonging
to a same simplify rule.
* gimple-fold.c (same_bool_result_p): Handle SSA_NAMEs
created in maybe_fold_comparisons_from_match_pd.
(and_comparisons_1): Remove matching moved to match.pd.
(maybe_fold_comparisons_from_match_pd): Handle
tcc_comparison as a results.
(maybe_fold_and_comparisons):Call maybe_fold_comparisons_from_match_pd
first.
(maybe_fold_or_comparisons): Likewise.
* match.pd: Handle (X == CST1) && (X OP2 CST2) conditions.
---
gcc/genmatch.c | 4 +-
gcc/gimple-fold.c | 174 +++++++++-------------------------------------
gcc/match.pd | 68 ++++++++++++++++++
3 files changed, 105 insertions(+), 141 deletions(-)
diff --git a/gcc/genmatch.c b/gcc/genmatch.c
index 2e7bf27eeda..b7194448a0f 100644
--- a/gcc/genmatch.c
+++ b/gcc/genmatch.c
@@ -1894,9 +1894,11 @@ dt_node *
dt_node::append_simplify (simplify *s, unsigned pattern_no,
dt_operand **indexes)
{
+ dt_simplify *s2;
dt_simplify *n = new dt_simplify (s, pattern_no, indexes);
for (unsigned i = 0; i < kids.length (); ++i)
- if (dt_simplify *s2 = dyn_cast <dt_simplify *> (kids[i]))
+ if ((s2 = dyn_cast <dt_simplify *> (kids[i]))
+ && s->match->location != s2->s->match->location)
{
warning_at (s->match->location, "duplicate pattern");
warning_at (s2->s->match->location, "previous pattern defined here");
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index aa2f94ace28..58235d613d3 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -5350,6 +5350,19 @@ same_bool_result_p (const_tree op1, const_tree op2)
if (operand_equal_p (op1, op2, 0))
return true;
+ /* Function maybe_fold_comparisons_from_match_pd creates temporary
+ SSA_NAMEs. */
+ if (TREE_CODE (op1) == SSA_NAME && TREE_CODE (op2) == SSA_NAME)
+ {
+ gimple *s = SSA_NAME_DEF_STMT (op2);
+ if (is_gimple_assign (s))
+ return same_bool_comparison_p (op1, gimple_assign_rhs_code (s),
+ gimple_assign_rhs1 (s),
+ gimple_assign_rhs2 (s));
+ else
+ return false;
+ }
+
/* Check the cases where at least one of the operands is a comparison.
These are a bit smarter than operand_equal_p in that they apply some
identifies on SSA_NAMEs. */
@@ -5620,136 +5633,6 @@ and_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
return t;
}
- /* If both comparisons are of the same value against constants, we might
- be able to merge them. */
- if (operand_equal_p (op1a, op2a, 0)
- && TREE_CODE (op1b) == INTEGER_CST
- && TREE_CODE (op2b) == INTEGER_CST)
- {
- int cmp = tree_int_cst_compare (op1b, op2b);
-
- /* If we have (op1a == op1b), we should either be able to
- return that or FALSE, depending on whether the constant op1b
- also satisfies the other comparison against op2b. */
- if (code1 == EQ_EXPR)
- {
- bool done = true;
- bool val;
- switch (code2)
- {
- case EQ_EXPR: val = (cmp == 0); break;
- case NE_EXPR: val = (cmp != 0); break;
- case LT_EXPR: val = (cmp < 0); break;
- case GT_EXPR: val = (cmp > 0); break;
- case LE_EXPR: val = (cmp <= 0); break;
- case GE_EXPR: val = (cmp >= 0); break;
- default: done = false;
- }
- if (done)
- {
- if (val)
- return fold_build2 (code1, boolean_type_node, op1a, op1b);
- else
- return boolean_false_node;
- }
- }
- /* Likewise if the second comparison is an == comparison. */
- else if (code2 == EQ_EXPR)
- {
- bool done = true;
- bool val;
- switch (code1)
- {
- case EQ_EXPR: val = (cmp == 0); break;
- case NE_EXPR: val = (cmp != 0); break;
- case LT_EXPR: val = (cmp > 0); break;
- case GT_EXPR: val = (cmp < 0); break;
- case LE_EXPR: val = (cmp >= 0); break;
- case GE_EXPR: val = (cmp <= 0); break;
- default: done = false;
- }
- if (done)
- {
- if (val)
- return fold_build2 (code2, boolean_type_node, op2a, op2b);
- else
- return boolean_false_node;
- }
- }
-
- /* Same business with inequality tests. */
- else if (code1 == NE_EXPR)
- {
- bool val;
- switch (code2)
- {
- case EQ_EXPR: val = (cmp != 0); break;
- case NE_EXPR: val = (cmp == 0); break;
- case LT_EXPR: val = (cmp >= 0); break;
- case GT_EXPR: val = (cmp <= 0); break;
- case LE_EXPR: val = (cmp > 0); break;
- case GE_EXPR: val = (cmp < 0); break;
- default:
- val = false;
- }
- if (val)
- return fold_build2 (code2, boolean_type_node, op2a, op2b);
- }
- else if (code2 == NE_EXPR)
- {
- bool val;
- switch (code1)
- {
- case EQ_EXPR: val = (cmp == 0); break;
- case NE_EXPR: val = (cmp != 0); break;
- case LT_EXPR: val = (cmp <= 0); break;
- case GT_EXPR: val = (cmp >= 0); break;
- case LE_EXPR: val = (cmp < 0); break;
- case GE_EXPR: val = (cmp > 0); break;
- default:
- val = false;
- }
- if (val)
- return fold_build2 (code1, boolean_type_node, op1a, op1b);
- }
-
- /* Chose the more restrictive of two < or <= comparisons. */
- else if ((code1 == LT_EXPR || code1 == LE_EXPR)
- && (code2 == LT_EXPR || code2 == LE_EXPR))
- {
- if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
- return fold_build2 (code1, boolean_type_node, op1a, op1b);
- else
- return fold_build2 (code2, boolean_type_node, op2a, op2b);
- }
-
- /* Likewise chose the more restrictive of two > or >= comparisons. */
- else if ((code1 == GT_EXPR || code1 == GE_EXPR)
- && (code2 == GT_EXPR || code2 == GE_EXPR))
- {
- if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR))
- return fold_build2 (code1, boolean_type_node, op1a, op1b);
- else
- return fold_build2 (code2, boolean_type_node, op2a, op2b);
- }
-
- /* Check for singleton ranges. */
- else if (cmp == 0
- && ((code1 == LE_EXPR && code2 == GE_EXPR)
- || (code1 == GE_EXPR && code2 == LE_EXPR)))
- return fold_build2 (EQ_EXPR, boolean_type_node, op1a, op2b);
-
- /* Check for disjoint ranges. */
- else if (cmp <= 0
- && (code1 == LT_EXPR || code1 == LE_EXPR)
- && (code2 == GT_EXPR || code2 == GE_EXPR))
- return boolean_false_node;
- else if (cmp >= 0
- && (code1 == GT_EXPR || code1 == GE_EXPR)
- && (code2 == LT_EXPR || code2 == LE_EXPR))
- return boolean_false_node;
- }
-
/* Perhaps the first comparison is (NAME != 0) or (NAME == 1) where
NAME's definition is a truth value. See if there are any simplifications
that can be done against the NAME's definition. */
@@ -5899,6 +5782,16 @@ maybe_fold_comparisons_from_match_pd (tree type, enum tree_code code,
else
return res;
}
+ else if (op.code.is_tree_code ()
+ && TREE_CODE_CLASS ((tree_code)op.code) == tcc_comparison)
+ {
+ tree op0 = op.ops[0];
+ tree op1 = op.ops[1];
+ if (op0 == lhs1 || op0 == lhs2 || op1 == lhs1 || op1 == lhs2)
+ return NULL_TREE; /* not simple */
+
+ return build2 ((enum tree_code)op.code, op.type, op0, op1);
+ }
}
return NULL_TREE;
@@ -5916,17 +5809,18 @@ maybe_fold_and_comparisons (tree type,
enum tree_code code1, tree op1a, tree op1b,
enum tree_code code2, tree op2a, tree op2b)
{
- if (tree t = and_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
- return t;
-
- if (tree t = and_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
- return t;
if (tree t = maybe_fold_comparisons_from_match_pd (type, BIT_AND_EXPR, code1,
op1a, op1b, code2, op2a,
op2b))
return t;
+ if (tree t = and_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
+ return t;
+
+ if (tree t = and_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
+ return t;
+
return NULL_TREE;
}
@@ -6391,15 +6285,15 @@ maybe_fold_or_comparisons (tree type,
enum tree_code code1, tree op1a, tree op1b,
enum tree_code code2, tree op2a, tree op2b)
{
- if (tree t = or_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
+ if (tree t = maybe_fold_comparisons_from_match_pd (type, BIT_IOR_EXPR, code1,
+ op1a, op1b, code2, op2a,
+ op2b))
return t;
- if (tree t = or_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
+ if (tree t = or_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
return t;
- if (tree t = maybe_fold_comparisons_from_match_pd (type, BIT_IOR_EXPR, code1,
- op1a, op1b, code2, op2a,
- op2b))
+ if (tree t = or_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
return t;
return NULL_TREE;
diff --git a/gcc/match.pd b/gcc/match.pd
index 0e557025b34..008b93d906f 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1967,6 +1967,74 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(if (eqne == NE_EXPR)
{ constant_boolean_node (true, type); })))))
+/* Convert (X == CST1) && (X OP2 CST2) to a known value
+ based on CST1 OP2 CST2. Similarly for (X != CST1). */
+
+(for code1 (eq ne)
+ (for code2 (eq ne lt gt le ge)
+ (for and (truth_and bit_and)
+ (simplify
+ (and:c (code1@3 @0 INTEGER_CST@1) (code2@4 @0 INTEGER_CST@2))
+ (with
+ {
+ int cmp = tree_int_cst_compare (@1, @2);
+ bool val;
+ switch (code2)
+ {
+ case EQ_EXPR: val = (cmp == 0); break;
+ case NE_EXPR: val = (cmp != 0); break;
+ case LT_EXPR: val = (cmp < 0); break;
+ case GT_EXPR: val = (cmp > 0); break;
+ case LE_EXPR: val = (cmp <= 0); break;
+ case GE_EXPR: val = (cmp >= 0); break;
+ default: gcc_unreachable ();
+ }
+ }
+ (switch
+ (if (code1 == EQ_EXPR && val) @3)
+ (if (code1 == EQ_EXPR && !val) { constant_boolean_node (false, type); })
+ (if (code1 == NE_EXPR && !val) @4)))))))
+
+/* Convert (X OP1 CST1) && (X OP2 CST2). */
+
+(for code1 (lt le gt ge)
+ (for code2 (lt le gt ge)
+ (for and (truth_and bit_and)
+ (simplify
+ (and (code1:c@3 @0 INTEGER_CST@1) (code2:c@4 @0 INTEGER_CST@2))
+ (with
+ {
+ int cmp = tree_int_cst_compare (@1, @2);
+ }
+ (switch
+ /* Choose the more restrictive of two < or <= comparisons. */
+ (if ((code1 == LT_EXPR || code1 == LE_EXPR)
+ && (code2 == LT_EXPR || code2 == LE_EXPR))
+ (if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
+ @3
+ @4))
+ /* Likewise chose the more restrictive of two > or >= comparisons. */
+ (if ((code1 == GT_EXPR || code1 == GE_EXPR)
+ && (code2 == GT_EXPR || code2 == GE_EXPR))
+ (if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR))
+ @3
+ @4))
+ /* Check for singleton ranges. */
+ (if (cmp == 0
+ && ((code1 == LE_EXPR && code2 == GE_EXPR)
+ || (code1 == GE_EXPR && code2 == LE_EXPR)))
+ (eq @0 @1))
+ /* Check for disjoint ranges. */
+ (if (cmp <= 0
+ && (code1 == LT_EXPR || code1 == LE_EXPR)
+ && (code2 == GT_EXPR || code2 == GE_EXPR))
+ { constant_boolean_node (false, type); })
+ (if (cmp >= 0
+ && (code1 == GT_EXPR || code1 == GE_EXPR)
+ && (code2 == LT_EXPR || code2 == LE_EXPR))
+ { constant_boolean_node (false, type); })
+ ))))))
+
/* We can't reassociate at all for saturating types. */
(if (!TYPE_SATURATING (type))
--
2.23.0