The BZ in question is a failure to recognize a pair of shifts as a sign extension.

I originally thought simplify-rtx would be the right framework to address this problem, but fwprop is actually better. We can write the recognizer much simpler in that framework.

fwprop already simplifies nested shifts/extensions to the desired RTL, but it's not considered profitable and we throw away the good work done by fwprop & simplifiers.

It's hard to see a scenario where nested shifts or nested extensions that simplify down to a single sign/zero extension isn't a profitable transformation. So when fwprop has nested shifts/extensions that simplifies to an extension, we consider it profitable.

This allow us to simplify the testcase on rv64 with ZBB enabled from a pair of shifts to a single byte or half-word sign extension.

Bootstrapped and regression tested on x86 as well.. Also tested in my tester. I just don't remember when I installed it, so I don't know which of the natives have been tested with it, but all the crosses have...

Richard -- any thoughts here?

Jeff
        PR rtl-optimization/109592
gcc
        * fwprop.cc (any_shift_p, any_extension_p): New functions.
        (fwprop_propagation::classify_result): If we have nested shifts
        or nested extensions that simplify to a single extension, then
        consider it profitable.

gcc/testsuite
        * gcc.target/riscv/pr109592.c: New test.

diff --git a/gcc/fwprop.cc b/gcc/fwprop.cc
index 9b8fba59216..c844d870a87 100644
--- a/gcc/fwprop.cc
+++ b/gcc/fwprop.cc
@@ -242,6 +242,24 @@ fwprop_propagation::check_mem (int old_num_changes, rtx 
mem)
   return true;
 }
 
+/* Return TRUE if X is a shift, FALSE otherwise.  */
+
+static bool
+any_shift_p (rtx x)
+{
+  enum rtx_code code = GET_CODE (x);
+  return code == ASHIFTRT || code == LSHIFTRT || code == ASHIFT;
+}
+
+/* Return TRUE if X is an extension, FALSE otherwise.  */
+
+static bool
+any_extension_p (rtx x)
+{
+  enum rtx_code code = GET_CODE (x);
+  return code == SIGN_EXTEND || code == ZERO_EXTEND;
+}
+
 /* OLDX has been simplified to NEWX.  Describe the change in terms of
    result_flags.  */
 
@@ -288,6 +306,22 @@ fwprop_propagation::classify_result (rtx old_rtx, rtx 
new_rtx)
       && !MEM_VOLATILE_P (new_rtx))
     return PROFITABLE;
 
+  /* If we had nested extensions that simplified to a single extension of
+     the same underlying object, then consider it profitable.  */
+  if (any_extension_p (old_rtx)
+      && any_extension_p (XEXP (old_rtx, 0))
+      && any_extension_p (new_rtx)
+      && rtx_equal_p (XEXP (XEXP (old_rtx, 0), 0), XEXP (new_rtx, 0)))
+    return PROFITABLE;
+
+  /* If we had nested shifts that simplify to a single extension of the
+     same underlying object, then consider it profitable.  */
+  if (any_shift_p (old_rtx)
+      && any_shift_p (XEXP (old_rtx, 0))
+      && any_extension_p (new_rtx)
+      && rtx_equal_p (XEXP (XEXP (old_rtx, 0), 0), XEXP (new_rtx, 0)))
+    return PROFITABLE;
+
   return 0;
 }
 
diff --git a/gcc/testsuite/gcc.target/riscv/pr109592.c 
b/gcc/testsuite/gcc.target/riscv/pr109592.c
new file mode 100644
index 00000000000..dbade3d5149
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr109592.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zbb -mabi=lp64d" { target { riscv64*-*-* } } } 
*/
+/* { dg-options "-march=rv32gc_zbb -mabi=ilp32" { target { riscv32*-*-* } } } 
*/
+
+int sextb32(int x) { return (x << 24) >> 24; }
+int sexth32(int x) { return (x << 16) >> 16; }
+
+/* { dg-final { scan-assembler-times "sext.b\t" 1 } } */
+/* { dg-final { scan-assembler-times "sext.h\t" 1 } } */
+/* { dg-final { scan-assembler-not "slli\t" } } */
+/* { dg-final { scan-assembler-not "srai\t" } } */
+
+
+

Reply via email to