From 91870dbc8cbf6e35d208d5b657990226754f0b2e Mon Sep 17 00:00:00 2001
From: Fei Yang <felix.yang@huawei.com>
Date: Tue, 26 May 2020 10:41:47 +0800
Subject: [PATCH] combine: Simplify more comparisons with zero [PR94026]

In rtl combine when we have an equality comparison of (and (lshiftrt X C) M)
and zero, simplify this into a simple AND if M is a constant that would select
a field of bits within an item, but not the entire word.

2020-05-26  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/combine.c                  | 21 +++++++++++++++++++++
 gcc/testsuite/gcc.dg/pr94026.c | 21 +++++++++++++++++++++
 2 files changed, 42 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/pr94026.c

diff --git a/gcc/combine.c b/gcc/combine.c
index b044f29fd36..c5787267116 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -8178,6 +8178,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
@@ -8231,6 +8235,23 @@ 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/gcc.dg/pr94026.c b/gcc/testsuite/gcc.dg/pr94026.c
new file mode 100644
index 00000000000..2ddd2b1458c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr94026.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { 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

