On Fri, May 29, 2026 at 08:16:13AM +0200, Uros Bizjak wrote:
> LEA is not fully compatible with ADD because %rsp can't be used as an
> index register (this is a general limitation of address expression
> which LEA inherits). As shown by Jakub, there are some problems when
> instructions are shadowing each other. In this particular case, the
> splitter at i386.md::7215 is not triggered for some reason, so we just
> skip the split and emit LEA by hand.
I've debugged this now on the 16 branch where my patch is not present.
The
(define_split
[(set (match_operand:SWI 0 "register_operand")
(plus:SWI (match_operand:SWI 1 "register_operand")
(match_operand:SWI 2 "<nonmemory_operand>")))]
"TARGET_APX_NF && reload_completed
&& ix86_lea_for_add_ok (insn, operands)"
[(set (match_dup 0)
(plus:<LEAMODE> (match_dup 1) (match_dup 2)))]
{
if (<MODE>mode != <LEAMODE>mode)
{
operands[0] = gen_lowpart (<LEAMODE>mode, operands[0]);
operands[1] = gen_lowpart (<LEAMODE>mode, operands[1]);
operands[2] = gen_lowpart (<LEAMODE>mode, operands[2]);
}
})
splitter there is matched, including ix86_lea_for_add_ok on
(insn 12 10 13 2 (set (reg:DI 2 cx [108])
(plus:DI (reg:DI 0 ax [orig:104 s ] [104])
(reg:DI 5 di [ _2+8 ]))) "apx-nf-pr125469.c":10:5 288 {*adddi_1_nf}
(nil))
But then goes into:
rtx_insn *
gen_split_138 (rtx_insn *curr_insn ATTRIBUTE_UNUSED, rtx *operands)
{
if (dump_file)
fprintf (dump_file, "Splitting with gen_split_138 (i386.md:7136)\n");
start_sequence ();
#define FAIL return (end_sequence (), nullptr)
#define DONE return end_sequence ()
#line 7144 "../../gcc/config/i386/i386.md"
{
if (DImode != DImode)
{
operands[0] = gen_lowpart (DImode, operands[0]);
operands[1] = gen_lowpart (DImode, operands[1]);
operands[2] = gen_lowpart (DImode, operands[2]);
}
}
#undef DONE
#undef FAIL
static const uint8_t expand_encoding[] = {
0x01, 0x1f, 0x01, 0x00, 0x3b, 0x12, 0x01, 0x01,
0x01, 0x02
};
return complete_seq (expand_encoding, operands);
}
That returns
(insn 37 0 0 (set (reg:DI 2 cx [108])
(plus:DI (reg:DI 0 ax [orig:104 s ] [104])
(reg:DI 5 di [ _2+8 ]))) -1
(nil))
But then in try_split we have:
/* Avoid infinite loop if any insn of the result matches
the original pattern. */
insn_last = seq;
while (1)
{
if (INSN_P (insn_last)
&& rtx_equal_p (PATTERN (insn_last), pat))
return trial;
which is a must, otherwise we'd try to split the newly created insn again
and again succeed in splitting it and so forth forever.
So perhaps all we need to do in the splitter is:
--- gcc/config/i386/i386.md.jj 2026-05-20 11:51:10.378282182 +0200
+++ gcc/config/i386/i386.md 2026-05-29 09:46:06.703661092 +0200
@@ -7148,6 +7148,11 @@
operands[1] = gen_lowpart (<LEAMODE>mode, operands[1]);
operands[2] = gen_lowpart (<LEAMODE>mode, operands[2]);
}
+ else
+ /* *lea<mode> and *add<mode>_1_nf have the same pattern, try_split
+ refuses to split an insn into itself, so just request
+ a new recog which will match *lea<mode> which comes first. */
+ INSN_CODE (curr_insn) = -1;
})
;; Convert add to the lea pattern to avoid flags dependency.
Jakub