[PATCH] MATCH: `(nop_convert)-a` into -(nop_convert)a if the negate is single use and a is known not to be signed min value

Andrew Pinski apinski@marvell.com
Fri Sep 1 02:26:32 GMT 2023


This pushes the conversion further down the chain which allows to optimize away more
conversions in many cases.

OK? Bootstrapped and tested on x86_64-linux-gnu with no regressions.

	PR tree-optimization/107765
	PR tree-optimization/107137

gcc/ChangeLog:

	* match.pd (`(nop_convert)-a`): New pattern.

gcc/testsuite/ChangeLog:

	* gcc.dg/tree-ssa/neg-cast-1.c: New test.
	* gcc.dg/tree-ssa/neg-cast-2.c: New test.
	* gcc.dg/tree-ssa/neg-cast-3.c: New test.
---
 gcc/match.pd                               | 31 ++++++++++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/neg-cast-1.c | 17 ++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/neg-cast-2.c | 20 ++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/neg-cast-3.c | 15 +++++++++++
 4 files changed, 83 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/neg-cast-1.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/neg-cast-2.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/neg-cast-3.c

diff --git a/gcc/match.pd b/gcc/match.pd
index 487a7e38719..3cff9b03d92 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -959,6 +959,37 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 #endif
    ))))
 
+/* (nop_cast)-var -> -(nop_cast)(var)
+   if -var is known to not overflow; that is does not include
+   the signed integer MIN. */
+(simplify
+ (convert (negate:s @0))
+ (if (INTEGRAL_TYPE_P (type)
+      && tree_nop_conversion_p (type, TREE_TYPE (@0)))
+  (with {
+    /* If the top is not set, there is no overflow happening. */
+    bool contains_signed_min = !wi::ges_p (tree_nonzero_bits (@0), 0);
+#if GIMPLE
+    int_range_max vr;
+    if (contains_signed_min
+        && TREE_CODE (@0) == SSA_NAME
+	&& get_range_query (cfun)->range_of_expr (vr, @0)
+	&& !vr.undefined_p ())
+      {
+        tree stype = signed_type_for (type);
+	auto minvalue = wi::min_value (stype);
+	int_range_max valid_range (TREE_TYPE (@0), minvalue, minvalue);
+	vr.intersect (valid_range);
+	/* If the range does not include min value,
+	   then we can do this change around. */
+	if (vr.undefined_p ())
+	  contains_signed_min = false;
+      }
+#endif
+   }
+   (if (!contains_signed_min)
+    (negate (convert @0))))))
+
 (for op (negate abs)
  /* Simplify cos(-x) and cos(|x|) -> cos(x).  Similarly for cosh.  */
  (for coss (COS COSH)
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/neg-cast-1.c b/gcc/testsuite/gcc.dg/tree-ssa/neg-cast-1.c
new file mode 100644
index 00000000000..7ddf40aca29
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/neg-cast-1.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+/* PR tree-optimization/107765 */
+
+#include <limits.h>
+
+int a(int input)
+{
+    if (input == INT_MIN) __builtin_unreachable();
+    unsigned t = input;
+    int tt =  -t;
+    return tt == -input;
+}
+
+/* Should be able to optimize this down to just `return 1;` during evrp. */
+/* { dg-final { scan-tree-dump "return 1;" "evrp" } } */
+/* { dg-final { scan-tree-dump-not " - " "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/neg-cast-2.c b/gcc/testsuite/gcc.dg/tree-ssa/neg-cast-2.c
new file mode 100644
index 00000000000..ce49079e235
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/neg-cast-2.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-fre3 -fdump-tree-optimized" } */
+/* part of PR tree-optimization/108397 */
+
+long long
+foo (unsigned char o)
+{
+  unsigned long long t1 = -(long long) (o == 0);
+  unsigned long long t2 = -(long long) (t1 != 0);
+  unsigned long long t3 = -(long long) (t1 <= t2);
+  return t3;
+}
+
+/* Should be able to optimize this down to just `return -1;` during fre3. */
+/* { dg-final { scan-tree-dump "return -1;" "fre3" } } */
+/* FRE does not remove all dead statements */
+/* { dg-final { scan-tree-dump-not " - " "fre3" { xfail *-*-* } } } */
+
+/* { dg-final { scan-tree-dump "return -1;" "optimized" } } */
+/* { dg-final { scan-tree-dump-not " - " "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/neg-cast-3.c b/gcc/testsuite/gcc.dg/tree-ssa/neg-cast-3.c
new file mode 100644
index 00000000000..a26a6051bda
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/neg-cast-3.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-forwprop2 -fdump-tree-optimized" } */
+/* PR tree-optimization/107137 */
+
+unsigned f(_Bool a)
+{
+  int t = a;
+  t = -t;
+  return t;
+}
+
+/* There should be no cast to int at all. */
+/* Forwprop2 does not remove all of the statements. */
+/* { dg-final { scan-tree-dump-not "\\\(int\\\)" "forwprop2" { xfail *-*-* } } } */
+/* { dg-final { scan-tree-dump-not "\\\(int\\\)" "optimized" } } */
-- 
2.31.1



More information about the Gcc-patches mailing list