https://gcc.gnu.org/g:e77642a6f29d87c48a935ea6da7c26ce3f8747d3
commit r17-4661-ge77642a6f29d87c48a935ea6da7c26ce3f8747d3 Author: Vladimir N. Makarov <[email protected]> Date: Fri Sep 25 10:13:41 2026 -0400 [PR 127326][LRA]: Fall back to memory when won operand is already a MEM The previous fix resolves 'g' operand to memory when no hard register of can hold the operand mode, but it only does so when OFFMEMOK is set. In case 'g' OFFMEMOK is set for reg operands only, so an operand which is already a MEM never gets marked and stays recorded as GENERAL_REGS. An operand matching it then inherits that class, finds no hard register able to hold the mode, and LRA rejects the asm. Treating won MEM operand the same way as an OFFMEMOK one solves the issue. gcc/ChangeLog: PR rtl-optimization/127326 * lra-constraints.cc (process_alt_operands): Resolve the operand to memory when it is a winning MEM and the value can be held in a register. gcc/testsuite/ChangeLog: PR rtl-optimization/127326 * gcc.target/i386/pr127326.c (test2): New test. Diff: --- gcc/lra-constraints.cc | 7 +++++-- gcc/testsuite/gcc.target/i386/pr127326.c | 13 +++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/gcc/lra-constraints.cc b/gcc/lra-constraints.cc index 72430d517321..76489c976ba8 100644 --- a/gcc/lra-constraints.cc +++ b/gcc/lra-constraints.cc @@ -3065,8 +3065,11 @@ process_alt_operands (int only_alternative) the operand to memory. Mark it so that an operand matching this one can also fall back to memory, otherwise the matched operand would try to reload into an impossible hard reg and - LRA would cycle (e.g. TDmode "+g" asm on 32-bit x86). */ - if (offmemok && this_alternative != NO_REGS + LRA would cycle (e.g. TDmode "+g" asm on 32-bit x86). + An operand which is already memory and won implies the + constraint accepts memory too, even if nothing set + OFFMEMOK for it. */ + if ((offmemok || MEM_P (op)) && this_alternative != NO_REGS && hard_reg_set_subset_p (reg_class_contents[this_alternative], ira_prohibited_class_mode_regs [this_alternative][mode] diff --git a/gcc/testsuite/gcc.target/i386/pr127326.c b/gcc/testsuite/gcc.target/i386/pr127326.c index ed618cf70928..a45c033e1df6 100644 --- a/gcc/testsuite/gcc.target/i386/pr127326.c +++ b/gcc/testsuite/gcc.target/i386/pr127326.c @@ -15,3 +15,16 @@ test (void) __asm ("" : "+g" (u.d)); /* { dg-bogus "inconsistent operand constraints" } */ return u.d; } + +/* Here the union is also read as integers, so it stays in memory and the asm + operand is MEM. The matched input operand still has to be resolved in + memory. */ + +unsigned long long +test2 (void) +{ + union { _Decimal128 d; unsigned long long u[2]; } u; + u.d = 1.0DL; + __asm ("" : "+g" (u.d)); /* { dg-bogus "inconsistent operand constraints" } */ + return u.u[0] + u.u[1]; +}
