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 "";
}