diff options
author | Georg-Johann Lay <avr@gjlay.de> | 2024-07-03 10:29:18 +0200 |
---|---|---|
committer | Georg-Johann Lay <avr@gjlay.de> | 2024-07-03 10:33:15 +0200 |
commit | e9fb6efa1cf542353fd44ddcbb5136344c463fd0 (patch) | |
tree | 9e7ab06db42291d742736a781caab376d06e9a4c | |
parent | 735edbf1e2479fa2323a2b4a9714fae1a0925f74 (diff) | |
download | gcc-e9fb6efa1cf542353fd44ddcbb5136344c463fd0.zip gcc-e9fb6efa1cf542353fd44ddcbb5136344c463fd0.tar.gz gcc-e9fb6efa1cf542353fd44ddcbb5136344c463fd0.tar.bz2 |
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.
-rw-r--r-- | gcc/config/avr/avr.cc | 27 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/avr/torture/pr98762.c | 19 |
2 files changed, 41 insertions, 5 deletions
diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc index a110af6..f048bf5 100644 --- a/gcc/config/avr/avr.cc +++ b/gcc/config/avr/avr.cc @@ -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 ""; } diff --git a/gcc/testsuite/gcc.target/avr/torture/pr98762.c b/gcc/testsuite/gcc.target/avr/torture/pr98762.c new file mode 100644 index 0000000..c3ba7da --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/torture/pr98762.c @@ -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; +} |