https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125469
--- Comment #2 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
I think the bug is in both *leadi and *adddi_1_nf matching insn like
(set (reg:DI 2 cx [108])
(plus:DI (reg:DI 0 ax [orig:104 s ] [104])
(reg:DI 5 di [ _2+8 ])))
without TARGET_APX_NDD (but with TARGET_APX_NF).
This is matched by combine:
insn 12 10 13 2 (set (reg:DI 108)
(plus:DI (reg:DI 104 [ s ])
(subreg:DI (reg:TI 103 [ _2 ]) 8))) "pr125469.c":6:5 288
{*adddi_1_nf}
(expr_list:REG_DEAD (reg:TI 103 [ _2 ])
(nil)))
and at that point the subreg in there prevents it from being matched as *leadi.
This is due to ix86_validate_address_register
12038 /* Don't allow SUBREGs that span more than a word. It can
12039 lead to spill failures when the register is one word out
12040 of a two word structure. */
12041 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
12042 return NULL_RTX;
So, INSN_CODE is set to 288 (*adddi_1_nf) and not *leadi.
But *add<mode>_1<nf_name> has
case TYPE_LEA:
if (TARGET_APX_NDD && <nf_applied>)
return "%{nf%} add{<imodesuffix>}\t{%2, %1, %0|%0, %1, %2}";
else
return "#";
TARGET_APX_NDD is false, so we require splitting into lea. Except there is no
splitter for that case, all we need instead is re-recog the insn, but that
won't happen, so we ICE.
So, either we'd need a dumb splitter that does nothing for this case (matches
the (set (reg:SWI48) (plus:SWI48 (reg:SWI48) (nonimmediate_operand:SWI48
"le"))) case and splits it into the same thing), or handle that case here
directly instead of "#".
I think the easier fix is
--- gcc/config/i386/i386.md.jj 2026-05-20 14:05:56.000000000 +0200
+++ gcc/config/i386/i386.md 2026-05-27 18:12:47.265960379 +0200
@@ -6749,7 +6749,10 @@
if (TARGET_APX_NDD && <nf_applied>)
return "%{nf%} add{<imodesuffix>}\t{%2, %1, %0|%0, %1, %2}";
else
- return "#";
+ {
+ operands[3] = gen_rtx_PLUS (<MODE>mode, operands[1], operands[2]);
+ return "lea{<imodesuffix>}\t{%E3, %0|%0, %E3}";
+ }
case TYPE_INCDEC:
if (operands[2] == const1_rtx)