AVR: target/98762 - Handle partial clobber in movqi output.

PR target/98762
gcc/
	* config/avr/avr.cc (avr_out_movqi_r_mr_reg_disp_tiny): Properly
	restore the base register when it is partially clobbered.
gcc/testsuite/
	* gcc.target/avr/torture/pr98762.c: New test.

(cherry picked from commit e9fb6efa1cf542353fd44ddcbb5136344c463fd0)
This commit is contained in:
Georg-Johann Lay 2024-07-03 10:29:18 +02:00
parent 052f78d010
commit 55744507ab
2 changed files with 41 additions and 5 deletions

View file

@ -4838,13 +4838,30 @@ avr_out_movqi_r_mr_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen)
rtx dest = op[0];
rtx src = op[1];
rtx x = XEXP (src, 0);
rtx base = XEXP (x, 0);
avr_asm_len (TINY_ADIW (%I1, %J1, %o1) CR_TAB
"ld %0,%b1" , op, plen, -3);
if (plen)
*plen = 0;
if (!reg_overlap_mentioned_p (dest, XEXP (x, 0))
&& !reg_unused_after (insn, XEXP (x, 0)))
avr_asm_len (TINY_SBIW (%I1, %J1, %o1), op, plen, 2);
if (!reg_overlap_mentioned_p (dest, base))
{
avr_asm_len (TINY_ADIW (%I1, %J1, %o1) CR_TAB
"ld %0,%b1", op, plen, 3);
if (!reg_unused_after (insn, base))
avr_asm_len (TINY_SBIW (%I1, %J1, %o1), op, plen, 2);
}
else
{
// PR98762: The base register overlaps dest and is only partly clobbered.
rtx base2 = all_regs_rtx[1 ^ REGNO (dest)];
if (!reg_unused_after (insn, base2))
avr_asm_len ("mov __tmp_reg__,%0" , &base2, plen, 1);
avr_asm_len (TINY_ADIW (%I1, %J1, %o1) CR_TAB
"ld %0,%b1", op, plen, 3);
if (!reg_unused_after (insn, base2))
avr_asm_len ("mov %0,__tmp_reg__" , &base2, plen, 1);
}
return "";
}

View file

@ -0,0 +1,19 @@
/* { dg-do run } */
/* { dg-additional-options "-std=c99" } */
long long acc = 0x1122334455667788;
__attribute__((noinline,noclone))
void addhi (short a)
{
acc += (long long) a << 32;
}
int main (void)
{
addhi (0x0304);
if (acc != 0x1122364855667788)
__builtin_abort();
return 0;
}