From bf4ef7ada5c3687c695ff6b3738ae6f943521b75 Mon Sep 17 00:00:00 2001
From: Fei Yang <felix.yang@huawei.com>
Date: Wed, 6 May 2020 16:33:40 +0800
Subject: [PATCH] combine: missed opportunity to simplify comparisons with zero
 [PR94026]

If we have (and (lshiftrt X C) M) and M is a constant that would select
a field of bits within an item, but not the entire word, fold this into
a simple AND if we are in an equality comparison against zero.

2020-05-06  Felix Yang  <felix.yang@huawei.com>

gcc/
    PR rtl-optimization/94026
    * combine.c (make_compound_operation_int): If we have (and
    (lshiftrt X C) M) and M is a constant that would select a field
    of bits within an item, but not the entire word, fold this into
    a simple AND if we are in an equality comparison.

gcc/testsuite/
    PR rtl-optimization/94026
    * gcc.dg/pr94026.c: New test.
---
 gcc/ChangeLog                  |  8 ++++++++
 gcc/combine.c                  | 20 ++++++++++++++++++++
 gcc/testsuite/ChangeLog        |  5 +++++
 gcc/testsuite/gcc.dg/pr94026.c | 21 +++++++++++++++++++++
 4 files changed, 54 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/pr94026.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 15ac1c3c4df..58c78dcdb3a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+2020-05-06  Felix Yang  <felix.yang@huawei.com>
+
+	PR rtl-optimization/94026
+	* combine.c (make_compound_operation_int): If we have (and
+	(lshiftrt X C) M) and M is a constant that would select a field
+	of bits within an item, but not the entire word, fold this into
+	a simple AND if we are in an equality comparison.
+
 2020-05-05  Michael Meissner  <meissner@linux.ibm.com>
 
 	* config/rs6000/rs6000-builtin.def: Delete changes meant for a
diff --git a/gcc/combine.c b/gcc/combine.c
index 4c324f38660..351aea9dfed 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -8177,6 +8177,10 @@ make_compound_operation_int (scalar_int_mode mode, rtx *x_ptr,
       if (!CONST_INT_P (XEXP (x, 1)))
 	break;
 
+      HOST_WIDE_INT pos;
+      unsigned HOST_WIDE_INT len;
+      pos = get_pos_from_mask (UINTVAL (XEXP (x, 1)), &len);
+
       /* If the constant is a power of two minus one and the first operand
 	 is a logical right shift, make an extraction.  */
       if (GET_CODE (XEXP (x, 0)) == LSHIFTRT
@@ -8230,6 +8234,22 @@ make_compound_operation_int (scalar_int_mode mode, rtx *x_ptr,
 	  new_rtx = make_compound_operation (new_rtx, in_code);
 	}
 
+      /* If we have (and (lshiftrt X C) M) and M is a constant that would select
+	 a field of bits within an item, but not the entire word, this might be
+	 representable by a simple AND if we are in an equality comparison.  */
+      else if (pos > 0 && equality_comparison
+	       && GET_CODE (XEXP (x, 0)) == LSHIFTRT
+	       && CONST_INT_P (XEXP (XEXP (x, 0), 1))
+	       && pos + UINTVAL (XEXP (XEXP (x, 0), 1))
+		  <= GET_MODE_BITSIZE (mode))
+	{
+	  new_rtx = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code);
+	  HOST_WIDE_INT real_pos = pos + UINTVAL (XEXP (XEXP (x, 0), 1));
+	  unsigned HOST_WIDE_INT mask = ((unsigned HOST_WIDE_INT)1 << len) - 1;
+	  new_rtx = gen_rtx_AND (mode, new_rtx,
+				 gen_int_mode (mask << real_pos, mode));
+	}
+
       /* If we are have (and (rotate X C) M) and C is larger than the number
 	 of bits in M, this is an extraction.  */
 
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 40a925e87ea..1c865a1b1ab 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2020-05-06  Felix Yang  <felix.yang@huawei.com>
+
+	PR rtl-optimization/94026
+	* gcc.dg/pr94026.c: New test.
+
 2020-05-05  H.J. Lu  <hongjiu.lu@intel.com>
 
 	PR testsuite/84324
diff --git a/gcc/testsuite/gcc.dg/pr94026.c b/gcc/testsuite/gcc.dg/pr94026.c
new file mode 100644
index 00000000000..5f309b7a34e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr94026.c
@@ -0,0 +1,21 @@
+/* { dg-do compile { target aarch64*-*-* i?86-*-* x86_64-*-* } } */
+/* { dg-options "-O2 -fdump-rtl-combine" } */
+
+int
+foo (int c)
+{
+  int a = (c >> 8) & 7;
+
+  if (a >= 2) {
+    return 1;
+  }
+
+  return 0;
+}
+
+/* The combine phase should transform (compare (and (lshiftrt x 8) 6) 0)
+   to (compare (and (x 1536)) 0). We look for the *attempt* to match this
+   RTL pattern, regardless of whether an actual insn may be found on the
+   platform.  */
+
+/* { dg-final { scan-rtl-dump "\\(const_int 1536" "combine" } } */
-- 
2.19.1

