https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92151
Alexander Monakov <amonakov at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |amonakov at gcc dot gnu.org
--- Comment #3 from Alexander Monakov <amonakov at gcc dot gnu.org> ---
>> (or write actual assembly rather than using inline-asm).
> In this case, yes -- I now declare the function "naked" and avoid the issue.
I think this solution (hand-writing asm for the entire function) is generally
undesirable because you become responsible for ABI/calling convention, the
compiler won't help you with things like properly restoring callee-saved
registers, and violations may stay unnoticed as long as callers don't try to
use a particular callee-saved reg.
Here's a manually reduced variant that exhibits a similar issue at -O1:
void foo(int num, int c) {
asm("# %0" : "+r"(num));
while (--c)
asm goto("# %0" :: "r"(num) :: l2);
l2:
asm("# %0" :: "r"(num));
}
The main issue seems to be our 'asmcons' pass transforming RTL in such a way
that REG_DEAD notes are "behind" the actual death, so if the RA takes them
literally it operates on wrong (too conservative) lifetime information; e.g.,
for the first asm, just before IRA we have:
(insn 29 4 8 2 (set (reg:SI 84 [ num ])
(reg:SI 85)) "./example.c":3:5 -1
(nil))
(insn 8 29 7 2 (parallel [
(set (reg:SI 84 [ num ])
(asm_operands:SI ("# %0") ("=r") 0 [
(reg:SI 84 [ num ])
]
[
(asm_input:SI ("0") ./example.c:3)
]
[] ./example.c:3))
(clobber (reg:CC 17 flags))
]) "./example.c":3:5 -1
(expr_list:REG_DEAD (reg:SI 85)
(expr_list:REG_UNUSED (reg:CC 17 flags)
(nil))))
but register 85 actually dies in insn 29, not in insn 8.