aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/avr/avr.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/avr/avr.cc')
-rw-r--r--gcc/config/avr/avr.cc43
1 files changed, 42 insertions, 1 deletions
diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index 227c12a..0bdba55 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -3272,7 +3272,8 @@ avr_load_libgcc_p (rtx op)
return (n_bytes > 2
&& !AVR_HAVE_LPMX
- && avr_mem_flash_p (op));
+ && avr_mem_flash_p (op)
+ && MEM_ADDR_SPACE (op) == ADDR_SPACE_FLASH);
}
@@ -3624,6 +3625,46 @@ avr_out_lpm_no_lpmx (rtx_insn *insn, rtx *xop, int *plen)
avr_asm_len ("sbiw %2,1", xop, plen, 1);
break; /* 2 */
+
+ /* cases 3 and 4 are only needed with ELPM but no ELPMx. */
+
+ case 3:
+ if (REGNO (dest) == REG_Z - 2
+ && !reg_unused_after (insn, all_regs_rtx[REG_31]))
+ avr_asm_len ("push r31", xop, plen, 1);
+
+ avr_asm_len ("%4lpm $ mov %A0,%3 $ adiw %2,1", xop, plen, 3);
+ avr_asm_len ("%4lpm $ mov %B0,%3 $ adiw %2,1", xop, plen, 3);
+ avr_asm_len ("%4lpm $ mov %C0,%3", xop, plen, 2);
+
+ if (REGNO (dest) == REG_Z - 2)
+ {
+ if (!reg_unused_after (insn, all_regs_rtx[REG_31]))
+ avr_asm_len ("pop r31", xop, plen, 1);
+ }
+ else if (!reg_unused_after (insn, addr))
+ avr_asm_len ("sbiw %2,2", xop, plen, 1);
+
+ break; /* 3 */
+
+ case 4:
+ avr_asm_len ("%4lpm $ mov %A0,%3 $ adiw %2,1", xop, plen, 3);
+ avr_asm_len ("%4lpm $ mov %B0,%3 $ adiw %2,1", xop, plen, 3);
+ if (REGNO (dest) != REG_Z - 2)
+ {
+ avr_asm_len ("%4lpm $ mov %C0,%3 $ adiw %2,1", xop, plen, 3);
+ avr_asm_len ("%4lpm $ mov %D0,%3", xop, plen, 2);
+ if (!reg_unused_after (insn, addr))
+ avr_asm_len ("sbiw %2,3", xop, plen, 1);
+ }
+ else
+ {
+ avr_asm_len ("%4lpm $ push %3 $ adiw %2,1", xop, plen, 3);
+ avr_asm_len ("%4lpm $ mov %D0,%3", xop, plen, 2);
+ avr_asm_len ("pop $C0", xop, plen, 1);
+ }
+
+ break; /* 4 */
}
break; /* REG */