diff mbox

Fix make_compound_operation in COMPAREs (PR rtl-optimization/80501)

Message ID 20170424212342.GR1809@tucnak
State New
Headers show

Commit Message

Jakub Jelinek April 24, 2017, 9:23 p.m. UTC
Hi!

For SUBREGs, make_compound_operation* recurses on the SUBREG_REG.
If the original in_code is EQ (i.e. equality comparison against 0) or SET,
we handle it correctly, but as the following testcase shows, for COMPARE
(some other comparison against 0) we in some cases don't.

The problem is that the recursive call can encounter:
      /* If we are in a comparison and this is an AND with a power of two,
         convert this into the appropriate bit extract.  */
      else if (in_code == COMPARE
               && (i = exact_log2 (UINTVAL (XEXP (x, 1)))) >= 0
               && (equality_comparison || i < GET_MODE_PRECISION (mode) - 1))
        new_rtx = make_extraction (mode,
                                   make_compound_operation (XEXP (x, 0),
                                                            next_code),
                                   i, NULL_RTX, 1, 1, 0, 1);
and mode in that case is the mode of the SUBREG_REG, so on the following
testcase SImode, while SUBREG's mode is QImode, and inner is AND with 0x80
constant.  For COMPARE (i.e. non-equality_comparison), we can do that only
if the AND is with a mask smaller than the sign bit and we can then just
extract the corresponding bits in lower positions.  But with SUBREGs,
we actually need to make sure that we only consider masks smaller than
the sign bit of the outer SUBREG's mode.

Apparently the caller already has a spot where I've fixed similar issues
already, but only if the mask was completely outside of the bits of the
inner mode, the following patch just extends it also to the sign bit
of the SUBREG's mode.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk/7.1?

2017-04-24  Jakub Jelinek  <jakub@redhat.com>

	PR rtl-optimization/80501
	* combine.c (make_compound_operation_int): Set subreg_code to SET
	even for AND with mask of the sign bit of mode.

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


	Jakub

Comments

Segher Boessenkool April 24, 2017, 10:16 p.m. UTC | #1
Hi Jakub,

On Mon, Apr 24, 2017 at 11:23:42PM +0200, Jakub Jelinek wrote:
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk/7.1?

Yes, okay everywhere, thank you for fixing it!

Segher


> 2017-04-24  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR rtl-optimization/80501
> 	* combine.c (make_compound_operation_int): Set subreg_code to SET
> 	even for AND with mask of the sign bit of mode.
> 
> 	* gcc.c-torture/execute/pr80501.c: New test.
diff mbox

Patch

--- gcc/combine.c.jj	2017-03-30 15:24:24.000000000 +0200
+++ gcc/combine.c	2017-04-24 13:05:49.264713210 +0200
@@ -8170,12 +8170,15 @@  make_compound_operation_int (machine_mod
 		|| GET_CODE (inner) == SUBREG
 		/* (subreg:SI (and:DI (reg:DI) (const_int 0x800000000)) 0)
 		   is (const_int 0), rather than
-		   (subreg:SI (lshiftrt:DI (reg:DI) (const_int 35)) 0).  */
+		   (subreg:SI (lshiftrt:DI (reg:DI) (const_int 35)) 0).
+		   Similarly (subreg:QI (and:SI (reg:SI) (const_int 0x80)) 0)
+		   for non-equality comparisons against 0 is not equivalent
+		   to (subreg:QI (lshiftrt:SI (reg:SI) (const_int 7)) 0).  */
 		|| (GET_CODE (inner) == AND
 		    && CONST_INT_P (XEXP (inner, 1))
 		    && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (inner))
 		    && exact_log2 (UINTVAL (XEXP (inner, 1)))
-		       >= GET_MODE_BITSIZE (mode))))
+		       >= GET_MODE_BITSIZE (mode) - 1)))
 	  subreg_code = SET;
 
 	tem = make_compound_operation (inner, subreg_code);
--- gcc/testsuite/gcc.c-torture/execute/pr80501.c.jj	2017-04-24 13:20:19.681024137 +0200
+++ gcc/testsuite/gcc.c-torture/execute/pr80501.c	2017-04-24 13:20:08.000000000 +0200
@@ -0,0 +1,23 @@ 
+/* PR rtl-optimization/80501 */
+
+signed char v = 0;
+
+static signed char
+foo (int x, int y)
+{
+  return x << y;
+}
+
+__attribute__((noinline, noclone)) int
+bar (void)
+{
+  return foo (v >= 0, __CHAR_BIT__ - 1) >= 1;
+}
+
+int
+main ()
+{
+  if (sizeof (int) > sizeof (char) && bar () != 0)
+    __builtin_abort ();
+  return 0;
+}