This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH, PR84660] Fix combine bug with SHIFT_COUNT_TRUNCATED.


This fixes a wrong-code issue on RISC-V, but in theory could be a problem for
any SHIFT_COUNT_TRUNCATED target.

The testcase computes 46 or 47 (0x2e or 0x2f), then ANDs the value with 0xf,
and then SHIFTs the value.  On a SHIFT_COUNT_TRUNCATED target, the AND can get
optimized away because for a 32-bit shift we can use the 46/47 directly and
still get the correct result.  Combine then tries to convert the 32-bit shift
into a 64-bit shift, and then we have a problem, as the AND 0xf is no longer
redundant.  So we must prevent combine from converting a 32-bit shift to a
64-bit shift on a SHIFT_COUNT_TRUNCATED target when there are non-zero bits
in the shift count that matter for the larger shift mode.

Combine already has code to handle the case where shifts are being narrowed
and this accidentally changes the shift amount.  This patch adds additional
code to handle the case where shifts are being widened.

This was tested with a cross riscv64-linux toolchain build and make check.
The new testcase fails without the patch, and works with the patch.  This was
also tested with an x86_64-linux build and make check.  There were no
regressions.

OK?

Jim

	gcc/
	PR rtl-optimization/84660
	* combine.c (force_int_to_mode) <ASHIFT>: If SHIFT_COUNT_TRUNCATED,
	call nonzero_bits and compare against xmode precision.

	gcc/testsuite/
	PR rtl-optimization/84660
	* gcc.dg/pr84660.c: New.
---
 gcc/combine.c                  | 10 ++++++++--
 gcc/testsuite/gcc.dg/pr84660.c | 17 +++++++++++++++++
 2 files changed, 25 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr84660.c

diff --git a/gcc/combine.c b/gcc/combine.c
index ff672ad2adb..4ed59eb88c8 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -8897,14 +8897,20 @@ force_int_to_mode (rtx x, scalar_int_mode mode, scalar_int_mode xmode,
 	 However, we cannot do anything with shifts where we cannot
 	 guarantee that the counts are smaller than the size of the mode
 	 because such a count will have a different meaning in a
-	 wider mode.  */
+	 different mode.  If we are narrowing the mode, the shift count must
+	 be compared against mode.  If we are widening the mode, and shift
+	 counts are truncated, then the shift count must be compared against
+	 xmode.  */
 
       if (! (CONST_INT_P (XEXP (x, 1))
 	     && INTVAL (XEXP (x, 1)) >= 0
 	     && INTVAL (XEXP (x, 1)) < GET_MODE_PRECISION (mode))
 	  && ! (GET_MODE (XEXP (x, 1)) != VOIDmode
 		&& (nonzero_bits (XEXP (x, 1), GET_MODE (XEXP (x, 1)))
-		    < (unsigned HOST_WIDE_INT) GET_MODE_PRECISION (mode))))
+		    < (unsigned HOST_WIDE_INT) GET_MODE_PRECISION (mode))
+		&& (! SHIFT_COUNT_TRUNCATED
+		    || (nonzero_bits (XEXP (x, 1), GET_MODE (XEXP (x, 1)))
+			< (unsigned HOST_WIDE_INT) GET_MODE_PRECISION (xmode)))))
 	break;
 
       /* If the shift count is a constant and we can do arithmetic in
diff --git a/gcc/testsuite/gcc.dg/pr84660.c b/gcc/testsuite/gcc.dg/pr84660.c
new file mode 100644
index 00000000000..a87fa0a914d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr84660.c
@@ -0,0 +1,17 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+extern void abort (void);
+extern void exit (int);
+
+unsigned int __attribute__ ((noinline, noclone))
+foo(unsigned int i) {
+
+  return 0xFFFF & (0xd066 << (((i & 0x1) ^ 0x2f) & 0xf));
+}
+
+int main() {
+  if (foo (1) != 0x8000)
+    abort ();
+  exit (0);
+}
-- 
2.14.1


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]