diff mbox series

[committed] Fix combine make_extraction (PR rtl-optimization/82192)

Message ID 20170915160516.GV1701@tucnak
State New
Headers show
Series [committed] Fix combine make_extraction (PR rtl-optimization/82192) | expand

Commit Message

Jakub Jelinek Sept. 15, 2017, 4:05 p.m. UTC
Hi!

When we have (x >> y) & 0x1fff or similar (for non-constant y or
even for constant y if y + 13 is bigger than x's bits) and x is
a non-paradoxical lowpart subreg (in the testcase (subreg:SI (reg:DI ...) 0))
then the lshiftrt extracts some bits out (0 to 13) out of the wider
DImode registers starting at y, but the upper bits if should be zeroed
out.  make_extraction happily changes it into an extraction out of
the reg:DI directly and that (at least for initially valid y 0 to 31)
will always extract exactly 13 bits out of the register; if there are
any bits above the low SImode part that are non-zero, this results
in different behavior.

The following patch stops doing that unless we can prove we don't care
about any of the bits above it.

Bootstrapped/regtested on x86_64-linux and i686-linux, extra statistics
collection didn't reveal changes in combiner's total_* vars at the end
of compilations except for this new testcase and combine.c itself.
Preapproved by Segher in the PR, committed to trunk.
For possible backports to release branches I'd like to wait some time.

2017-09-15  Jakub Jelinek  <jakub@redhat.com>

	PR rtl-optimization/82192
	* combine.c (make_extraction): Don't look through non-paradoxical
	SUBREGs or TRUNCATE if pos + len is or might be bigger than
	inner's mode.

	* gcc.c-torture/execute/pr82192.c: New test.


	Jakub
diff mbox series

Patch

--- gcc/combine.c.jj	2017-09-14 10:04:56.000000000 +0200
+++ gcc/combine.c	2017-09-14 16:59:28.529783572 +0200
@@ -7444,7 +7444,14 @@  make_extraction (machine_mode mode, rtx
   if (pos_rtx && CONST_INT_P (pos_rtx))
     pos = INTVAL (pos_rtx), pos_rtx = 0;
 
-  if (GET_CODE (inner) == SUBREG && subreg_lowpart_p (inner))
+  if (GET_CODE (inner) == SUBREG
+      && subreg_lowpart_p (inner)
+      && (paradoxical_subreg_p (inner)
+	  /* If trying or potentionally trying to extract
+	     bits outside of is_mode, don't look through
+	     non-paradoxical SUBREGs.  See PR82192.  */
+	  || (pos_rtx == NULL_RTX
+	      && pos + len <= GET_MODE_PRECISION (is_mode))))
     {
       /* If going from (subreg:SI (mem:QI ...)) to (mem:QI ...),
 	 consider just the QI as the memory to extract from.
@@ -7470,7 +7477,12 @@  make_extraction (machine_mode mode, rtx
       if (new_rtx != 0)
 	return gen_rtx_ASHIFT (mode, new_rtx, XEXP (inner, 1));
     }
-  else if (GET_CODE (inner) == TRUNCATE)
+  else if (GET_CODE (inner) == TRUNCATE
+	   /* If trying or potentionally trying to extract
+	      bits outside of is_mode, don't look through
+	      TRUNCATE.  See PR82192.  */
+	   && pos_rtx == NULL_RTX
+	   && pos + len <= GET_MODE_PRECISION (is_mode))
     inner = XEXP (inner, 0);
 
   inner_mode = GET_MODE (inner);
--- gcc/testsuite/gcc.c-torture/execute/pr82192.c.jj	2017-09-14 17:02:54.281234432 +0200
+++ gcc/testsuite/gcc.c-torture/execute/pr82192.c	2017-09-14 17:02:39.000000000 +0200
@@ -0,0 +1,22 @@ 
+/* PR rtl-optimization/82192 */
+
+unsigned long long int a = 0x95dd3d896f7422e2ULL;
+struct S { unsigned int m : 13; } b;
+
+__attribute__((noinline, noclone)) void
+foo (void)
+{
+  b.m = ((unsigned) a) >> (0x644eee9667723bf7LL
+			   | a & ~0xdee27af8U) - 0x644eee9667763bd8LL;
+}
+
+int
+main ()
+{
+  if (__INT_MAX__ != 0x7fffffffULL)
+    return 0;
+  foo ();
+  if (b.m != 0)
+    __builtin_abort ();
+  return 0;
+}