The following patch solves https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127244
The patch was successfully bootstrapped and tested on x86-64, aarhc64, ppc64le
commit cf6605e1e4a1ab76a09f96635b919e53aaf48af1 Author: Vladimir N. Makarov <[email protected]> Date: Fri Sep 11 09:44:22 2026 -0400 [PR 127244][LRA]: Inherit optional reload for output operands The PR reveals that optional reload for output operands is not inherited and this results in bad code generation. The patch fixes this. gcc/ChangeLog: PR rtl-optimization/127244 * lra-constraints.cc (inheritance_pseudo_p): New function. (undo_optional_reloads): Keep optional reload for output operand if it is inherited. gcc/testsuite/ChangeLog: PR rtl-optimization/127244 * gcc.target/i386/pr127244.c: New diff --git a/gcc/lra-constraints.cc b/gcc/lra-constraints.cc index 153624b8859..16866033d50 100644 --- a/gcc/lra-constraints.cc +++ b/gcc/lra-constraints.cc @@ -8259,6 +8259,14 @@ remove_inheritance_pseudos (bitmap remove_pseudos) return change_p; } +/* Return true if REGNO is an inheritance pseudo. */ +static bool +inheritance_pseudo_p (int regno) +{ + return (regno >= new_regno_start + && bitmap_bit_p (&lra_inheritance_pseudos, regno)); +} + /* If optional reload pseudos failed to get a hard register or was not inherited, it is better to remove optional reloads. We do this transformation after undoing inheritance to figure out necessity to @@ -8291,19 +8299,22 @@ undo_optional_reloads (void) insn = lra_insn_recog_data[uid]->insn; if ((set = single_set (insn)) == NULL_RTX) continue; - src = SET_SRC (set); - dest = SET_DEST (set); - if ((! REG_P (src) && ! SUBREG_P (src)) - || (! REG_P (dest) && ! SUBREG_P (dest))) + int src_regno = get_regno (SET_SRC (set)); + int dest_regno = get_regno (SET_DEST (set)); + if (src_regno < 0 || dest_regno < 0) + continue; + int restore_regno = get_regno (lra_reg_info[regno].restore_rtx); + if (restore_regno < 0) continue; - if (get_regno (dest) == (int) regno - /* Ignore insn for optional reloads itself. */ - && (get_regno (lra_reg_info[regno].restore_rtx) - != get_regno (src)) - /* Check only inheritance on last inheritance pass. */ - && get_regno (src) >= new_regno_start - /* Check that the optional reload was inherited. */ - && bitmap_bit_p (&lra_inheritance_pseudos, get_regno (src))) + if (((dest_regno == (int) regno + /* Ignore insn for optional reloads itself. */ + && restore_regno != src_regno + /* Check that the optional reload was inherited. */ + && inheritance_pseudo_p (src_regno)) + || (src_regno == (int) regno + && restore_regno != dest_regno + /* The optional reload is an inheritance source. */ + && inheritance_pseudo_p (dest_regno)))) { keep_p = true; break; diff --git a/gcc/testsuite/gcc.target/i386/pr127244.c b/gcc/testsuite/gcc.target/i386/pr127244.c new file mode 100644 index 00000000000..8582c29c431 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr127244.c @@ -0,0 +1,57 @@ +/* PR rtl-optimization/127244 */ +/* { dg-do compile { target lp64 } } */ +/* { dg-options "-O2" } */ + +typedef unsigned int __u32; + +extern unsigned long __rdgsbase_inactive (void); + +static inline unsigned long +native_save_fl (void) { + unsigned long flags; + asm volatile ("# __raw_save_flags\n\tpushf ; pop %0" + : "=rm" (flags) + : + : "memory"); + return flags; +} + +static inline void +native_irq_disable (void) { + asm volatile ("cli" : : : "memory"); +} + +static inline void +native_irq_enable (void) { + asm volatile ("sti" : : : "memory"); +} + +struct cpuinfo_x86 { + union { __u32 x86_capability[24]; }; +}; + +struct cpuinfo_x86 boot_cpu_data; + +static inline _Bool +constant_test_bit (long nr, const volatile unsigned long *addr) { + return ((1UL << (nr & 63)) & addr[nr >> 6]) != 0; +} + +unsigned long +x86_gsbase_read_cpu_inactive (void) { + unsigned long gsbase; + + if (constant_test_bit (9 * 32, (unsigned long *) boot_cpu_data.x86_capability)) { + unsigned long flags = native_save_fl (); + native_irq_disable (); + gsbase = __rdgsbase_inactive (); + if (flags & (1UL << 9)) + native_irq_enable (); + } + + return gsbase; +} + +/* { dg-final { scan-assembler "pushf ; pop %r" } } */ +/* { dg-final { scan-assembler-not "pushf ; pop \[0-9-]*\\(%rsp\\)" } } */ +/* { dg-final { scan-assembler-not "movq\[ \t\]+\[0-9-]*\\(%rsp\\), %r" } } */
