diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index f048bf5fd41c5a0dfafc004a3108bccbf4afa522..d299fceb7824d68b6e53d1068233b885c24f8745 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -4471,28 +4471,21 @@ avr_out_lpm_no_lpmx (rtx_insn *insn, rtx *xop, int *plen)
       gcc_assert (REG_Z == REGNO (XEXP (addr, 0))
 		  && n_bytes <= 4);
 
-      if (regno_dest == LPM_REGNO)
-	avr_asm_len ("%4lpm"      CR_TAB
-		     "adiw %2,1", xop, plen, 2);
-      else
-	avr_asm_len ("%4lpm"      CR_TAB
-		     "mov %A0,%3" CR_TAB
-		     "adiw %2,1", xop, plen, 3);
+      for (int i = 0; i < n_bytes; ++i)
+	{
+	  rtx reg = simplify_gen_subreg (QImode, dest, GET_MODE (dest), i);
 
-      if (n_bytes >= 2)
-	avr_asm_len ("%4lpm"      CR_TAB
-		     "mov %B0,%3" CR_TAB
-		     "adiw %2,1", xop, plen, 3);
+	  if (i > 0)
+	    avr_asm_len ("adiw %2,1", xop, plen, 1);
 
-      if (n_bytes >= 3)
-	avr_asm_len ("%4lpm"      CR_TAB
-		     "mov %C0,%3" CR_TAB
-		     "adiw %2,1", xop, plen, 3);
+	  avr_asm_len ("%4lpm", xop, plen, 1);
 
-      if (n_bytes >= 4)
-	avr_asm_len ("%4lpm"      CR_TAB
-		     "mov %D0,%3" CR_TAB
-		     "adiw %2,1", xop, plen, 3);
+	  if (REGNO (reg) != LPM_REGNO)
+	    avr_asm_len ("mov %0,r0", &reg, plen, 1);
+	}
+
+      if (! _reg_unused_after (insn, xop[2], false))
+	avr_asm_len ("adiw %2,1", xop, plen, 1);
 
       break; /* POST_INC */
 
@@ -6685,6 +6678,14 @@ avr_split_tiny_move (rtx_insn * /*insn*/, rtx *xop)
   if (REGNO (base) > REG_Z)
     return false;
 
+  if (! AVR_TINY
+      // Only keep base registers that can't do PLUS addressing.
+      && ((REGNO (base) != REG_X
+	   && ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (mem)))
+	  || avr_load_libgcc_p (mem)
+	  || avr_mem_memx_p (mem)))
+    return false;
+
   bool volatile_p = MEM_VOLATILE_P (mem);
   bool mem_volatile_p = false;
   if (frame_pointer_needed
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index dabf4c0fc5a891fd6774d6e626fe89133f3768ef..2783b8c986f19eb431b6dfe7170705acf9c014e0 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -1035,8 +1035,7 @@
   [(parallel [(set (match_operand:MOVMODE 0 "nonimmediate_operand")
                    (match_operand:MOVMODE 1 "general_operand"))
               (clobber (reg:CC REG_CC))])]
-  "AVR_TINY
-   && reload_completed
+  "reload_completed
    && avr_fuse_add > 0
    // Only split this for .split2 when we are before
    // pass .avr-fuse-add (which runs after proep).
diff --git a/gcc/testsuite/gcc.target/avr/torture/fuse-add.c b/gcc/testsuite/gcc.target/avr/torture/fuse-add.c
new file mode 100644
index 0000000000000000000000000000000000000000..b78b1aa9fc928e4d3f8e86018014abc49d978b4d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/fuse-add.c
@@ -0,0 +1,59 @@
+/* { dg-do run } */
+/* { dg-additional-options "-std=gnu99" } */
+
+typedef __UINT64_TYPE__ uint64_t;
+
+extern const uint64_t aa __asm ("real_aa");
+extern const uint64_t bb __asm ("real_bb");
+
+__attribute__((used)) const uint64_t real_aa = 0x1122334455667788;
+__attribute__((used)) const uint64_t real_bb = 0x0908070605040302;
+
+__attribute__((noinline,noclone))
+uint64_t add1 (const uint64_t *aa, const uint64_t *bb)
+{
+  return *aa + *bb;
+}
+
+#ifdef __FLASH
+extern const __flash uint64_t fa __asm ("real_fa");
+extern const __flash uint64_t fb __asm ("real_fb");
+
+__attribute__((used)) const __flash uint64_t real_fa = 0x1122334455667788;
+__attribute__((used)) const __flash uint64_t real_fb = 0x0908070605040302;
+
+__attribute__((noinline,noclone))
+uint64_t add2 (const __flash uint64_t *aa, const uint64_t *bb)
+{
+  return *aa + *bb;
+}
+
+uint64_t add3 (const uint64_t *aa, const __flash uint64_t *bb)
+{
+  return *aa + *bb;
+}
+
+uint64_t add4 (const __flash uint64_t *aa, const __flash uint64_t *bb)
+{
+  return *aa + *bb;
+}
+#endif /* have __flash */
+
+int main (void)
+{
+  if (add1 (&aa, &bb) != real_aa + real_bb)
+    __builtin_exit (__LINE__);
+
+#ifdef __FLASH
+  if (add2 (&fa, &bb) != real_fa + real_bb)
+    __builtin_exit (__LINE__);
+
+  if (add3 (&aa, &fb) != real_aa + real_fb)
+    __builtin_exit (__LINE__);
+
+  if (add4 (&fa, &fb) != real_fa + real_fb)
+    __builtin_exit (__LINE__);
+#endif
+
+  return 0;
+}