https://gcc.gnu.org/g:e46d96d20bbfa786d30c9371631da00939845f05
commit r17-2413-ge46d96d20bbfa786d30c9371631da00939845f05 Author: Roger Sayle <[email protected]> Date: Wed Jul 15 12:26:16 2026 +0100 PR middle-end/123236: Simplify (int)((long long)x >> 4) 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 <[email protected]> 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. Diff: --- gcc/simplify-rtx.cc | 14 +++++++------- gcc/testsuite/gcc.target/i386/pr123236-1.c | 10 ++++++++++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc index 92a2a6e954a8..882a11c5760d 100644 --- a/gcc/simplify-rtx.cc +++ b/gcc/simplify-rtx.cc @@ -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 index 000000000000..67e872f9b2d7 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr123236-1.c @@ -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" } } */
