https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107812
Roger Sayle <roger at nextmovesoftware dot com> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |roger at nextmovesoftware dot com --- Comment #3 from Roger Sayle <roger at nextmovesoftware dot com> --- Things are better but not perfect on trunk (GCC 14.0.0): pushl %esi pushl %ebx movl 16(%esp), %eax ; y movl 20(%esp), %ecx ; z movl 12(%esp), %edx ; x movl 4(%eax), %ebx ; y[1] movl (%eax), %esi ; y[0] movl %ebx, %eax shrdl %esi, %eax movl %eax, (%edx) popl %ebx popl %esi ret So the xorl and orl are gone, and we're down to two pushs/pops. It looks like the additional spill is just a difference in register allocation. Perhaps i386.md's *concatsidi3_3 could be cleverer (to avoid the early clobber &r when both operands are mem, and their addressing mode is sufficently simple). i.e. movl (%eax), %esi ; y[0] movl 4(%eax), %eax ; y[1] instead of movl 4(%eax), %ebx ; y[1] movl (%eax), %esi ; y[0] movl %ebx, %eax