https://gcc.gnu.org/g:850b5135e5ea7e64c7694a4a12c894a052696c1b

commit r17-5451-g850b5135e5ea7e64c7694a4a12c894a052696c1b
Author: Roger Sayle <[email protected]>
Date:   Wed Oct 21 13:17:43 2026 +0100

    combine: Missed any-or-plus optimization in make_field_assignment.
    
    This simple patch tweaks combine.cc to catch a missed-optimization
    identified by my recent any-or-plus changes.  Currently the logic
    in make_field_assignment checks for IOR or XOR, this one-line tweak
    adds PLUS to the list.
    
    The motivating example is taken from PR target/15184.
    
    On i386, for the code:
    
    unsigned int x;
    
    void foo(unsigned char c)
    {
        x = (x & 0xFFFFFF00) + (unsigned int)c;
    }
    
    current GCC (and earlier GCCs) with -m32 -O2 generates:
    
    foo:    movl    x, %eax
            movzbl  4(%esp), %edx
            xorb    %al, %al
            addl    %edx, %eax
            movl    %eax, x
            ret
    
    with this patch, we now generate:
    
    foo:    movzbl  4(%esp), %eax
            movb    %al, x
            ret
    
    which matches what we'd generate if the source code
    had used "|" or "^" as an operator.
    
    2026-10-21  Roger Sayle  <[email protected]>
    
    gcc/ChangeLog
            * combine.cc (make_field_assignment): Treat PLUS like IOR and XOR.
    
    gcc/testsuite/ChangeLog
            * gcc.target/i386/pr15184-3.c: New test case.

Diff:
---
 gcc/combine.cc                            |  4 +++-
 gcc/testsuite/gcc.target/i386/pr15184-3.c | 34 +++++++++++++++++++++++++++++++
 2 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/gcc/combine.cc b/gcc/combine.cc
index 6cdbdbb6dc62..c9daefc905c3 100644
--- a/gcc/combine.cc
+++ b/gcc/combine.cc
@@ -9825,7 +9825,9 @@ make_field_assignment (rtx x)
       && is_a <scalar_int_mode> (GET_MODE (SUBREG_REG (src)), &src_mode))
     src = SUBREG_REG (src);
 
-  if (GET_CODE (src) != IOR && GET_CODE (src) != XOR)
+  if (GET_CODE (src) != IOR
+      && GET_CODE (src) != XOR
+      && GET_CODE (src) != PLUS)
     return x;
 
   rhs = expand_compound_operation (XEXP (src, 0));
diff --git a/gcc/testsuite/gcc.target/i386/pr15184-3.c 
b/gcc/testsuite/gcc.target/i386/pr15184-3.c
new file mode 100644
index 000000000000..dc92275b790e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr15184-3.c
@@ -0,0 +1,34 @@
+/* PR 15184 addition forms of pr15184-1.c.  */
+/* { dg-do compile { target ia32 } } */
+/* { dg-options "-O2 -march=pentiumpro" } */
+/* { dg-additional-options "-fno-PIE" { target ia32 } } */
+/* { dg-additional-options "-mdynamic-no-pic" { target { *-*-darwin* && ia32 } 
} } */
+
+#define regparm __attribute__((__regparm__(1)))
+
+extern unsigned int x;
+
+void regparm f0(unsigned char c)
+{
+       x = (x & 0xFFFFFF00) + (unsigned int)c;
+}
+
+void regparm f1(unsigned char c)
+{
+     x = (x & 0xFFFF00FF) + ((unsigned int)c << 8);
+}
+
+void regparm f2(unsigned char c)
+{
+     x = (x & 0xFF00FFFF) + ((unsigned int)c << 16);
+}
+void regparm f3(unsigned char c)
+{
+     x = (x & 0x00FFFFFF) + ((unsigned int)c << 24);
+}
+
+
+/* Each function should compile down to a byte move from
+   the input register into x, possibly at an offset within x.  */
+/* { dg-final { scan-assembler-times "movb\[ \\t\]+%al" 4 } } */
+

Reply via email to