]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
PR middle-end/123236: Simplify (int)((long long)x >> 4)
authorRoger Sayle <roger@nextmovesoftware.com>
Wed, 15 Jul 2026 11:26:16 +0000 (12:26 +0100)
committerRoger Sayle <roger@nextmovesoftware.com>
Wed, 15 Jul 2026 11:35:20 +0000 (12:35 +0100)
This patch addresses a code quality regression on x86_64 related to
PR 123236.  That original PR (and the related PR 101266) concern tree
level optimizations, where this problem should also be fixed, but it
also reveals a regression in the RTL optimizers.

A motivating test case (on x86_64) is:

int bar(int a) {
  long long t = a;
  return t >> 4;
}

Currently -O2 generates a 64-bit shift:
bar:    movslq  %edi, %rax
        sarq    $4, %rax
        ret

with this patch we now generate a 32-bit shift:
bar:    movl    %edi, %eax
        sarl    $4, %eax
        ret

The underlying cause of the RTL-level regression is that some
RTL expressions that were previously expressed as {ZERO,SIGN}_EXTEND
are now sometimes represented as the equivalent {ZERO,SIGN}_EXTRACT,
and that not all simplifications of TRUNCATE({ZERO,SIGN}_EXTEND) are
implemented for TRUNCATE({ZERO,SIGN}_EXTRACT).

Thanks to Segher, simplify_rtx does handle some truncations of extracts,
see https://gcc.gnu.org/pipermail/gcc-patches/2016-November/463629.html
but unfortunately this code (and subsequent tweaks) doesn't quite match
the cases that appear here.

2026-07-15  Roger Sayle  <roger@nextmovesoftware.com>

gcc/ChangeLog
PR rtl-optimization/123236
* simplify-rtx.cc (simplify_context::simplify_truncation): Handle
cases where a ZERO_EXTRACT or SIGN_EXTRACT has a different mode
to (but at least as wide as) its first operand.

gcc/testsuite/ChangeLog
PR rtl-optimization/123236
* gcc.target/i386/pr123236-1.c: New test case.

gcc/simplify-rtx.cc
gcc/testsuite/gcc.target/i386/pr123236-1.c [new file with mode: 0644]

index 92a2a6e954a8b899fce862a1e09088a3b4c63375..882a11c5760dc54ff272ac31ce0677441af6a909 100644 (file)
@@ -727,12 +727,10 @@ simplify_context::simplify_truncation (machine_mode mode, rtx op,
        }
     }
 
-  /* Turn (truncate:M1 (*_extract:M2 (reg:M2) (len) (pos))) into
-     (*_extract:M1 (truncate:M1 (reg:M2)) (len) (pos')) if possible without
-     changing len.  */
+  /* Turn (truncate:M1 (*_extract:M2 (reg:M3) (len) (pos))) into
+     (*_extract:M1 (truncate:M1 (reg:M3)) (len) (pos')) if possible.  */
   if ((GET_CODE (op) == ZERO_EXTRACT || GET_CODE (op) == SIGN_EXTRACT)
-      && REG_P (XEXP (op, 0))
-      && GET_MODE (XEXP (op, 0)) == GET_MODE (op)
+      && precision <= GET_MODE_UNIT_PRECISION (GET_MODE (XEXP (op, 0)))
       && CONST_INT_P (XEXP (op, 1))
       && CONST_INT_P (XEXP (op, 2)))
     {
@@ -741,7 +739,8 @@ simplify_context::simplify_truncation (machine_mode mode, rtx op,
       unsigned HOST_WIDE_INT pos = UINTVAL (XEXP (op, 2));
       if (BITS_BIG_ENDIAN && pos >= op_precision - precision)
        {
-         op0 = simplify_gen_unary (TRUNCATE, mode, op0, GET_MODE (op0));
+         if (GET_MODE (op0) != mode)
+           op0 = simplify_gen_unary (TRUNCATE, mode, op0, GET_MODE (op0));
          if (op0)
            {
              pos -= op_precision - precision;
@@ -751,7 +750,8 @@ simplify_context::simplify_truncation (machine_mode mode, rtx op,
        }
       else if (!BITS_BIG_ENDIAN && precision >= len + pos)
        {
-         op0 = simplify_gen_unary (TRUNCATE, mode, op0, GET_MODE (op0));
+         if (GET_MODE (op0) != mode)
+           op0 = simplify_gen_unary (TRUNCATE, mode, op0, GET_MODE (op0));
          if (op0)
            return simplify_gen_ternary (GET_CODE (op), mode, mode, op0,
                                         XEXP (op, 1), XEXP (op, 2));
diff --git a/gcc/testsuite/gcc.target/i386/pr123236-1.c b/gcc/testsuite/gcc.target/i386/pr123236-1.c
new file mode 100644 (file)
index 0000000..67e872f
--- /dev/null
@@ -0,0 +1,10 @@
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2" } */
+
+int foo(int a) {
+  long long t = a;
+  return t >> 4;
+}
+
+/* { dg-final { scan-assembler-not "movslq" } } */
+/* { dg-final { scan-assembler-not "sarq" } } */