diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h
index d3fa6c67723..5fdb1305757 100644
--- a/gcc/config/avr/avr-protos.h
+++ b/gcc/config/avr/avr-protos.h
@@ -96,7 +96,7 @@ extern void avr_output_addr_vec (rtx_insn*, rtx);
 extern const char *avr_out_sbxx_branch (rtx_insn *insn, rtx operands[]);
 extern const char* avr_out_bitop (rtx, rtx*, int*);
 extern const char* avr_out_plus (rtx, rtx*, int* =NULL, bool =true);
-extern const char* avr_out_minus (rtx*);
+extern const char* avr_out_plus_ext (rtx_insn*, rtx*, int*);
 extern const char* avr_out_round (rtx_insn *, rtx*, int* =NULL);
 extern const char* avr_out_addto_sp (rtx*, int*);
 extern const char* avr_out_xload (rtx_insn *, rtx*, int*);
diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index d2a08c60c3a..5fc046a310e 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -8843,30 +8843,90 @@ lshrsi3_out (rtx_insn *insn, rtx operands[], int *len)
 }
 
 
-/* Output subtraction of integer registers XOP[0] and XOP[2] and return ""
+/* Output addition of registers YOP[0] and YOP[1]
 
-      XOP[0] = XOP[0] - XOP[2]
+      YOP[0] += extend (YOP[1])
 
-   where the mode of XOP[0] is in { HI, PSI, SI }, and the mode of
-   XOP[2] is in { QI, HI, PSI }.  When the mode of XOP[0] is larger
-   than the mode of XOP[2], then the latter is zero-extended on the fly.
-   The number of instructions will be the mode size of XOP[0].  */
+   or subtraction of registers YOP[0] and YOP[2]
+
+      YOP[0] -= extend (YOP[2])
+
+   where the integer modes satisfy  SI >= YOP[0].mode > YOP[1/2].mode >= QI,
+   and the extension may be sign- or zero-extend.  Returns "".
+
+   If PLEN == NULL output the instructions.
+   If PLEN != NULL set *PLEN to the length of the sequence in words.  */
 
 const char *
-avr_out_minus (rtx *xop)
+avr_out_plus_ext (rtx_insn *insn, rtx *yop, int *plen)
 {
-  int n_bytes0 = GET_MODE_SIZE (GET_MODE (xop[0]));
-  int n_bytes2 = GET_MODE_SIZE (GET_MODE (xop[2]));
+  rtx regs[2];
+
+  const rtx src = SET_SRC (single_set (insn));
+  const RTX_CODE add = GET_CODE (src);
+  gcc_assert (GET_CODE (src) == PLUS || GET_CODE (src) == MINUS);
+
+  // Use XOP[] in the remainder with XOP[0] = YOP[0] and XOP[1] = YOP[1/2].
+  rtx xop[2] = { yop[0], yop[add == PLUS ? 1 : 2] };
+  const rtx xreg = XEXP (src, add == PLUS ? 1 : 0);
+  const rtx xext = XEXP (src, add == PLUS ? 0 : 1);
+  const RTX_CODE ext = GET_CODE (xext);
+
+  gcc_assert (REG_P (xreg)
+	      && (ext == ZERO_EXTEND || ext == SIGN_EXTEND));
+
+  const int n_bytes0 = GET_MODE_SIZE (GET_MODE (xop[0]));
+  const int n_bytes1 = GET_MODE_SIZE (GET_MODE (xop[1]));
+  rtx msb1 = all_regs_rtx[n_bytes1 - 1 + REGNO (xop[1])];
+
+  const char *const s_ADD = add == PLUS ? "add %0,%1" : "sub %0,%1";
+  const char *const s_ADC = add == PLUS ? "adc %0,%1" : "sbc %0,%1";
+  const char *const s_DEC = add == PLUS
+    ? "adc %0,__zero_reg__"  CR_TAB  "sbrc %1,7"  CR_TAB  "dec %0"
+    : "sbc %0,__zero_reg__"  CR_TAB  "sbrc %1,7"  CR_TAB  "inc %0";
+
+  // A register that containts 8 copies of $1.msb.
+  rtx ext_reg = ext == ZERO_EXTEND ? zero_reg_rtx : NULL_RTX;
+
+  if (plen)
+    *plen = 0;
+
+  if (ext == SIGN_EXTEND
+      && (n_bytes0 > 1 + n_bytes1
+	  || reg_overlap_mentioned_p (msb1, xop[0])))
+    {
+      // Sign-extending more than one byte: Set tmp_reg to 0 or -1
+      // depending on $1.msb. Same for the pathological case where
+      // $0 and $1 overlap.
+
+      regs[0] = ext_reg = tmp_reg_rtx;
+      regs[1] = msb1;
+
+      avr_asm_len ("mov %0,%1"  CR_TAB
+		   "lsl %0"     CR_TAB
+		   "sbc %0,%0", regs, plen, 3);
+    }
 
-  output_asm_insn ("sub %0,%2", xop);
+  // Adding the bytes of $1 is just plain additions / subtractions.
+  // Same for the extended bytes when we have ext_reg.
+
+  avr_asm_len (s_ADD, xop, plen, 1);
 
   for (int i = 1; i < n_bytes0; ++i)
     {
-      rtx op[2];
-      op[0] = all_regs_rtx[i + REGNO (xop[0])];
-      op[1] = (i < n_bytes2) ? all_regs_rtx[i + REGNO (xop[2])] : zero_reg_rtx;
+      regs[0] = all_regs_rtx[i + REGNO (xop[0])];
+      regs[1] = i < n_bytes1 ? all_regs_rtx[i + REGNO (xop[1])] : ext_reg;
+
+      if (! regs[1])
+	{
+	  // Extending just 1 byte:  This is one instruction shorter
+	  // than sign-extending $1.msb to tmp_reg.
 
-      output_asm_insn ("sbc %0,%1", op);
+	  regs[1] = msb1;
+	  avr_asm_len (s_DEC, regs, plen, 3);
+	}
+      else
+	avr_asm_len (s_ADC, regs, plen, 1);
     }
 
   return "";
@@ -11062,6 +11122,7 @@ avr_adjust_insn_length (rtx_insn *insn, int len)
     case ADJUST_LEN_INSV: avr_out_insv (insn, op, &len); break;
 
     case ADJUST_LEN_PLUS: avr_out_plus (insn, op, &len); break;
+    case ADJUST_LEN_PLUS_EXT: avr_out_plus_ext (insn, op, &len); break;
     case ADJUST_LEN_ADDTO_SP: avr_out_addto_sp (op, &len); break;
 
     case ADJUST_LEN_MOV8:  output_movqi (insn, op, &len); break;
@@ -12699,6 +12760,8 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code,
 	  return true;
 	}
 
+      // *add<PSISI:mode>3.zero_extend.<QIPSI:mode>
+      // *addhi3_zero_extend
       if (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
 	  && REG_P (XEXP (x, 1)))
 	{
@@ -12712,6 +12775,16 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code,
 	  return true;
 	}
 
+      // *add<HISI:mode>3.sign_extend.<QIPSI:mode>
+      if (GET_CODE (XEXP (x, 0)) == SIGN_EXTEND
+	  && REG_P (XEXP (x, 1)))
+	{
+	  int size2 = GET_MODE_SIZE (GET_MODE (XEXP (XEXP (x, 0), 0)));
+	  *total = COSTS_N_INSNS (2 + GET_MODE_SIZE (mode)
+				  + (GET_MODE_SIZE (mode) > 1 + size2));
+	  return true;
+	}
+
       switch (mode)
 	{
 	case E_QImode:
@@ -12806,11 +12879,13 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code,
 	  *total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
 	  return true;
 	}
-      // *sub<mode>3.sign_extend2
+      // *sub<HISI:mode>3.sign_extend.<QIPSI:mode>
       if (REG_P (XEXP (x, 0))
 	  && GET_CODE (XEXP (x, 1)) == SIGN_EXTEND)
 	{
-	  *total = COSTS_N_INSNS (2 + GET_MODE_SIZE (mode));
+	  int size2 = GET_MODE_SIZE (GET_MODE (XEXP (XEXP (x, 1), 0)));
+	  *total = COSTS_N_INSNS (2 + GET_MODE_SIZE (mode)
+				  + (GET_MODE_SIZE (mode) > 1 + size2));
 	  return true;
 	}
 
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index cf9541422a3..695ff87f0c2 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -161,7 +161,7 @@ (define_attr "length" ""
 ;; Otherwise do special processing depending on the attribute.
 
 (define_attr "adjust_len"
-  "out_bitop, plus, addto_sp, sext, extr, extr_not,
+  "out_bitop, plus, addto_sp, sext, extr, extr_not, plus_ext,
    tsthi, tstpsi, tstsi, compare, compare64, call,
    mov8, mov16, mov24, mov32, reload_in16, reload_in24, reload_in32,
    ufract, sfract, round,
@@ -1596,33 +1596,6 @@ (define_insn "*addhi3_zero_extend1"
   "add %A0,%2\;adc %B0,__zero_reg__"
   [(set_attr "length" "2")])
 
-(define_insn_and_split "*addhi3.sign_extend1_split"
-  [(set (match_operand:HI 0 "register_operand"                         "=r")
-        (plus:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "r"))
-                 (match_operand:HI 2 "register_operand"                 "0")))]
-  ""
-  "#"
-  "&& reload_completed"
-  [(parallel [(set (match_dup 0)
-                   (plus:HI (sign_extend:HI (match_dup 1))
-                            (match_dup 2)))
-              (clobber (reg:CC REG_CC))])])
-
-
-(define_insn "*addhi3.sign_extend1"
-  [(set (match_operand:HI 0 "register_operand"                         "=r")
-        (plus:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "r"))
-                 (match_operand:HI 2 "register_operand"                 "0")))
-   (clobber (reg:CC REG_CC))]
-  "reload_completed"
-  {
-    return reg_overlap_mentioned_p (operands[0], operands[1])
-      ? "mov __tmp_reg__,%1\;add %A0,%1\;adc %B0,__zero_reg__\;sbrc __tmp_reg__,7\;dec %B0"
-      : "add %A0,%1\;adc %B0,__zero_reg__\;sbrc %1,7\;dec %B0";
-  }
-  [(set (attr "length")
-        (symbol_ref ("4 + reg_overlap_mentioned_p (operands[0], operands[1])")))])
-
 (define_insn_and_split "*addhi3_zero_extend.const_split"
   [(set (match_operand:HI 0 "register_operand"                         "=d")
         (plus:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "0"))
@@ -1878,110 +1851,88 @@ (define_insn "*add<mode>3"
   [(set_attr "length" "4")
    (set_attr "adjust_len" "plus")])
 
-(define_insn_and_split "*addpsi3_zero_extend.qi_split"
-  [(set (match_operand:PSI 0 "register_operand"                          "=r")
-        (plus:PSI (zero_extend:PSI (match_operand:QI 1 "register_operand" "r"))
-                  (match_operand:PSI 2 "register_operand"                 "0")))]
-  ""
-  "#"
-  "&& reload_completed"
-  [(parallel [(set (match_dup 0)
-                   (plus:PSI (zero_extend:PSI (match_dup 1))
-                             (match_dup 2)))
-              (clobber (reg:CC REG_CC))])])
-
-(define_insn "*addpsi3_zero_extend.qi"
-  [(set (match_operand:PSI 0 "register_operand"                          "=r")
-        (plus:PSI (zero_extend:PSI (match_operand:QI 1 "register_operand" "r"))
-                  (match_operand:PSI 2 "register_operand"                 "0")))
-   (clobber (reg:CC REG_CC))]
-  "reload_completed"
-  "add %A0,%A1\;adc %B0,__zero_reg__\;adc %C0,__zero_reg__"
-  [(set_attr "length" "3")])
 
-(define_insn_and_split "*addpsi3_zero_extend.hi_split"
-  [(set (match_operand:PSI 0 "register_operand"                          "=r")
-        (plus:PSI (zero_extend:PSI (match_operand:HI 1 "register_operand" "r"))
-                  (match_operand:PSI 2 "register_operand"                 "0")))]
-  ""
+;;                                  "*addhi3.sign_extend.qi_split"
+;; "*addpsi3.sign_extend.qi_split"  "*addpsi3.sign_extend.qi_split"
+;; "*addpsi3.sign_extend.hi_split"  "*addpsi3.sign_extend.hi_split"
+;; "*addsi3.sign_extend.qi_split"   "*addsi3.sign_extend.qi_split"
+;; "*addsi3.sign_extend.hi_split"   "*addsi3.sign_extend.hi_split"
+;; "*addsi3.sign_extend.psi_split"  "*addsi3.sign_extend.psi_split"
+;; The zero_extend:HI(QI) case is treated in an own insn as it can
+;; more than just "r,r,0".
+(define_insn_and_split "*add<HISI:mode>3.<code>.<QIPSI:mode>_split"
+  [(set (match_operand:HISI 0 "register_operand"                             "=r")
+        (plus:HISI (any_extend:HISI (match_operand:QIPSI 1 "register_operand" "r"))
+                   (match_operand:HISI 2 "register_operand"                   "0")))]
+  "<HISI:SIZE> > <QIPSI:SIZE>
+   && (<HISI:SIZE> > 2 || <CODE> == SIGN_EXTEND)"
   "#"
   "&& reload_completed"
   [(parallel [(set (match_dup 0)
-                   (plus:PSI (zero_extend:PSI (match_dup 1))
-                             (match_dup 2)))
+                   (plus:HISI (any_extend:HISI (match_dup 1))
+                              (match_dup 2)))
               (clobber (reg:CC REG_CC))])])
 
-(define_insn "*addpsi3_zero_extend.hi"
-  [(set (match_operand:PSI 0 "register_operand"                          "=r")
-        (plus:PSI (zero_extend:PSI (match_operand:HI 1 "register_operand" "r"))
-                  (match_operand:PSI 2 "register_operand"                 "0")))
+;;                            "*addhi3.sign_extend.qi"
+;; "*addpsi3.sign_extend.qi"  "*addpsi3.sign_extend.qi"
+;; "*addpsi3.sign_extend.hi"  "*addpsi3.sign_extend.hi"
+;; "*addsi3.sign_extend.qi"   "*addsi3.sign_extend.qi"
+;; "*addsi3.sign_extend.hi"   "*addsi3.sign_extend.hi"
+;; "*addsi3.sign_extend.psi"  "*addsi3.sign_extend.psi"
+(define_insn "*add<HISI:mode>3.<code>.<QIPSI:mode>"
+  [(set (match_operand:HISI 0 "register_operand"                             "=r")
+        (plus:HISI (any_extend:HISI (match_operand:QIPSI 1 "register_operand" "r"))
+                   (match_operand:HISI 2 "register_operand"                   "0")))
    (clobber (reg:CC REG_CC))]
-  "reload_completed"
-  "add %A0,%A1\;adc %B0,%B1\;adc %C0,__zero_reg__"
-  [(set_attr "length" "3")])
-
-(define_insn_and_split "*addpsi3_sign_extend.hi_split"
-  [(set (match_operand:PSI 0 "register_operand"                          "=r")
-        (plus:PSI (sign_extend:PSI (match_operand:HI 1 "register_operand" "r"))
-                  (match_operand:PSI 2 "register_operand"                 "0")))]
-  ""
-  "#"
-  "&& reload_completed"
-  [(parallel [(set (match_dup 0)
-                   (plus:PSI (sign_extend:PSI (match_dup 1))
-                             (match_dup 2)))
-              (clobber (reg:CC REG_CC))])])
+  "reload_completed
+   && <HISI:SIZE> > <QIPSI:SIZE>
+   && (<HISI:SIZE> > 2 || <CODE> == SIGN_EXTEND)"
+  {
+    return avr_out_plus_ext (insn, operands, nullptr);
+  }
+  [(set (attr "length")
+        (symbol_ref "<HISI:SIZE> + 3 * (<CODE> == SIGN_EXTEND)"))
+   (set_attr "adjust_len" "plus_ext")])
 
-(define_insn "*addpsi3_sign_extend.hi"
-  [(set (match_operand:PSI 0 "register_operand"                          "=r")
-        (plus:PSI (sign_extend:PSI (match_operand:HI 1 "register_operand" "r"))
-                  (match_operand:PSI 2 "register_operand"                 "0")))
-   (clobber (reg:CC REG_CC))]
-  "reload_completed"
-  "add %A0,%1\;adc %B0,%B1\;adc %C0,__zero_reg__\;sbrc %B1,7\;dec %C0"
-  [(set_attr "length" "5")])
 
-(define_insn_and_split "*addsi3_zero_extend_split"
-  [(set (match_operand:SI 0 "register_operand"                         "=r")
-        (plus:SI (zero_extend:SI (match_operand:QI 1 "register_operand" "r"))
-                 (match_operand:SI 2 "register_operand"                 "0")))]
-  ""
+;; "*subhi3.zero_extend.qi_split"   "*subhi3.sign_extend.qi_split"
+;; "*subpsi3.zero_extend.qi_split"  "*subpsi3.sign_extend.qi_split"
+;; "*subpsi3.zero_extend.hi_split"  "*subpsi3.sign_extend.hi_split"
+;; "*subsi3.zero_extend.qi_split"   "*subsi3.sign_extend.qi_split"
+;; "*subsi3.zero_extend.hi_split"   "*subsi3.sign_extend.hi_split"
+;; "*subsi3.zero_extend.psi_split"  "*subsi3.sign_extend.psi_split"
+(define_insn_and_split "*sub<HISI:mode>3.<code>.<QIPSI:mode>_split"
+  [(set (match_operand:HISI 0 "register_operand"                              "=r")
+        (minus:HISI (match_operand:HISI 1 "register_operand"                   "0")
+                    (any_extend:HISI (match_operand:QIPSI 2 "register_operand" "r"))))]
+  "<HISI:SIZE> > <QIPSI:SIZE>"
   "#"
   "&& reload_completed"
   [(parallel [(set (match_dup 0)
-                   (plus:SI (zero_extend:SI (match_dup 1))
-                            (match_dup 2)))
+                   (minus:HISI (match_dup 1)
+                               (any_extend:HISI (match_dup 2))))
               (clobber (reg:CC REG_CC))])])
 
-(define_insn "*addsi3_zero_extend"
-  [(set (match_operand:SI 0 "register_operand"                         "=r")
-        (plus:SI (zero_extend:SI (match_operand:QI 1 "register_operand" "r"))
-                 (match_operand:SI 2 "register_operand"                 "0")))
+;; "*subhi3.zero_extend.qi"   "*subhi3.sign_extend.qi"
+;; "*subpsi3.zero_extend.qi"  "*subpsi3.sign_extend.qi"
+;; "*subpsi3.zero_extend.hi"  "*subpsi3.sign_extend.hi"
+;; "*subsi3.zero_extend.qi"   "*subsi3.sign_extend.qi"
+;; "*subsi3.zero_extend.hi"   "*subsi3.sign_extend.hi"
+;; "*subsi3.zero_extend.psi"  "*subsi3.sign_extend.psi"
+(define_insn "*sub<HISI:mode>3.<code>.<QIPSI:mode>"
+  [(set (match_operand:HISI 0 "register_operand"                              "=r")
+        (minus:HISI (match_operand:HISI 1 "register_operand"                   "0")
+                    (any_extend:HISI (match_operand:QIPSI 2 "register_operand" "r"))))
    (clobber (reg:CC REG_CC))]
-  "reload_completed"
-  "add %A0,%1\;adc %B0,__zero_reg__\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__"
-  [(set_attr "length" "4")])
+  "reload_completed
+   && <HISI:SIZE> > <QIPSI:SIZE>"
+  {
+    return avr_out_plus_ext (insn, operands, nullptr);
+  }
+  [(set (attr "length")
+        (symbol_ref "<HISI:SIZE> + 3 * (<CODE> == SIGN_EXTEND)"))
+   (set_attr "adjust_len" "plus_ext")])
 
-(define_insn_and_split "*addsi3_zero_extend.hi_split"
-  [(set (match_operand:SI 0 "register_operand"                         "=r")
-        (plus:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "r"))
-                 (match_operand:SI 2 "register_operand"                 "0")))]
-  ""
-  "#"
-  "&& reload_completed"
-  [(parallel [(set (match_dup 0)
-                   (plus:SI (zero_extend:SI (match_dup 1))
-                            (match_dup 2)))
-              (clobber (reg:CC REG_CC))])])
-
-(define_insn "*addsi3_zero_extend.hi"
-  [(set (match_operand:SI 0 "register_operand"                         "=r")
-        (plus:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "r"))
-                 (match_operand:SI 2 "register_operand"                 "0")))
-   (clobber (reg:CC REG_CC))]
-  "reload_completed"
-  "add %A0,%1\;adc %B0,%B1\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__"
-  [(set_attr "length" "4")])
 
 (define_insn_and_split "addpsi3"
   [(set (match_operand:PSI 0 "register_operand"         "=??r,d ,d,r")
@@ -2032,27 +1983,6 @@ (define_insn "*subpsi3"
   [(set_attr "length" "3")])
 
 
-(define_insn_and_split "*subpsi3_sign_extend.hi_split"
-  [(set (match_operand:PSI 0 "register_operand"                           "=r")
-        (minus:PSI (match_operand:PSI 1 "register_operand"                 "0")
-                   (sign_extend:PSI (match_operand:HI 2 "register_operand" "r"))))]
-  ""
-  "#"
-  "&& reload_completed"
-  [(parallel [(set (match_dup 0)
-                   (minus:PSI (match_dup 1)
-                              (sign_extend:PSI (match_dup 2))))
-              (clobber (reg:CC REG_CC))])])
-
-(define_insn "*subpsi3_sign_extend.hi"
-  [(set (match_operand:PSI 0 "register_operand"                           "=r")
-        (minus:PSI (match_operand:PSI 1 "register_operand"                 "0")
-                   (sign_extend:PSI (match_operand:HI 2 "register_operand" "r"))))
-   (clobber (reg:CC REG_CC))]
-  "reload_completed"
-  "sub %A0,%A2\;sbc %B0,%B2\;sbc %C0,__zero_reg__\;sbrc %B2,7\;inc %C0"
-  [(set_attr "length" "5")])
-
 ;-----------------------------------------------------------------------------
 ; sub bytes
 
@@ -2115,33 +2045,6 @@ (define_insn "*sub<mode>3"
   [(set_attr "adjust_len" "plus")])
 
 
-(define_insn_and_split "*subhi3.sign_extend2_split"
-  [(set (match_operand:HI 0 "register_operand"                          "=r")
-        (minus:HI (match_operand:HI 1 "register_operand"                 "0")
-                  (sign_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
-  ""
-  "#"
-  "&& reload_completed"
-  [(parallel [(set (match_dup 0)
-                   (minus:HI (match_dup 1)
-                             (sign_extend:HI (match_dup 2))))
-              (clobber (reg:CC REG_CC))])])
-
-
-(define_insn "*subhi3.sign_extend2"
-  [(set (match_operand:HI 0 "register_operand"                          "=r")
-        (minus:HI (match_operand:HI 1 "register_operand"                 "0")
-                  (sign_extend:HI (match_operand:QI 2 "register_operand" "r"))))
-   (clobber (reg:CC REG_CC))]
-  "reload_completed"
-  {
-    return reg_overlap_mentioned_p (operands[0], operands[2])
-      ? "mov __tmp_reg__,%2\;sub %A0,%2\;sbc %B0,__zero_reg__\;sbrc __tmp_reg__,7\;inc %B0"
-      : "sub %A0,%2\;sbc %B0,__zero_reg__\;sbrc %2,7\;inc %B0";
-  }
-  [(set (attr "length")
-        (symbol_ref ("4 + reg_overlap_mentioned_p (operands[0], operands[2])")))])
-
 ;; "subsi3"
 ;; "subsq3" "subusq3"
 ;; "subsa3" "subusa3"
@@ -2172,39 +2075,6 @@ (define_insn "*sub<mode>3"
   [(set_attr "adjust_len" "plus")])
 
 
-;; "*subhi3.zero_extend.qi_split"
-;; "*subpsi3.zero_extend.qi_split"  "*subpsi3.zero_extend.hi_split"
-;; "*subsi3.zero_extend.qi_split"   "*subsi3.zero_extend.hi_split"
-;; "*subsi3.zero_extend.psi_split"
-(define_insn_and_split "*sub<HISI:mode>3.zero_extend.<QIPSI:mode>_split"
-  [(set (match_operand:HISI 0 "register_operand"             "=r")
-        (minus:HISI (match_operand:HISI 1 "register_operand"  "0")
-                    (zero_extend:HISI (match_operand:QIPSI 2 "register_operand" "r"))))]
-  "GET_MODE_SIZE (<HISI:MODE>mode) > GET_MODE_SIZE (<QIPSI:MODE>mode)"
-  "#"
-  "&& reload_completed"
-  [(parallel [(set (match_dup 0)
-                   (minus:HISI (match_dup 1)
-                               (zero_extend:HISI (match_dup 2))))
-              (clobber (reg:CC REG_CC))])])
-
-;; "*subhi3.zero_extend.qi"
-;; "*subpsi3.zero_extend.qi"  "*subpsi3.zero_extend.hi"
-;; "*subsi3.zero_extend.qi"   "*subsi3.zero_extend.hi"
-;; "*subsi3.zero_extend.psi"
-(define_insn "*sub<HISI:mode>3.zero_extend.<QIPSI:mode>"
-  [(set (match_operand:HISI 0 "register_operand"             "=r")
-        (minus:HISI (match_operand:HISI 1 "register_operand"  "0")
-                    (zero_extend:HISI (match_operand:QIPSI 2 "register_operand" "r"))))
-   (clobber (reg:CC REG_CC))]
-  "reload_completed
-   && GET_MODE_SIZE (<HISI:MODE>mode) > GET_MODE_SIZE (<QIPSI:MODE>mode)"
-  {
-    return avr_out_minus (operands);
-  }
-  [(set_attr "length" "<HISI:SIZE>")])
-
-
 ;******************************************************************************
 ; mul
 
diff --git a/gcc/testsuite/gcc.target/avr/torture/add-extend.c b/gcc/testsuite/gcc.target/avr/torture/add-extend.c
new file mode 100644
index 00000000000..063f06f43e3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/add-extend.c
@@ -0,0 +1,109 @@
+/* { dg-do run } */
+
+typedef __UINT8_TYPE__ u8;
+typedef __UINT16_TYPE__ u16;
+typedef __uint24 u24;
+typedef __UINT32_TYPE__ u32;
+
+typedef __INT8_TYPE__ s8;
+typedef __INT16_TYPE__ s16;
+typedef __int24 s24;
+typedef __INT32_TYPE__ s32;
+
+#define NI __attribute__((noinline,noclone,noipa))
+
+NI u32 addu_32_8  (u32 a, u8 b)  { return a + b; }
+NI u32 addu_32_16 (u32 a, u16 b) { return a + b; }
+NI u32 addu_32_24 (u32 a, u24 b) { return a + b; }
+
+NI u24 addu_24_8  (u24 a, u8 b)  { return a + b; }
+NI u24 addu_24_16 (u24 a, u16 b) { return a + b; }
+
+NI u16 addu_16_8  (u16 a, u8 b)  { return a + b; }
+
+/************************/
+
+NI s32 adds_32_8  (s32 a, s8 b)  { return a + b; }
+NI s32 adds_32_16 (s32 a, s16 b) { return a + b; }
+NI s32 adds_32_24 (s32 a, s24 b) { return a + b; }
+
+NI s24 adds_24_8  (s24 a, s8 b)  { return a + b; }
+NI s24 adds_24_16 (s24 a, s16 b) { return a + b; }
+
+NI s16 adds_16_8  (s16 a, s8 b)  { return a + b; }
+
+/************************/
+
+NI u32 addu_32 (u32 a, u32 b)    { return a + b; }
+NI u24 addu_24 (u24 a, u24 b)    { return a + b; }
+NI u16 addu_16 (u16 a, u16 b)    { return a + b; }
+
+NI s32 adds_32 (s32 a, s32 b)    { return a + b; }
+NI s24 adds_24 (s24 a, s24 b)    { return a + b; }
+NI s16 adds_16 (s16 a, s16 b)    { return a + b; }
+
+/************************/
+
+NI u8 next (void *p0, u8 n_bytes)
+{
+  u8 *p = (u8*) p0;
+
+  u8 n;
+  for (n = 0; n < n_bytes; ++n)
+    {
+      u8 val = *p;
+
+      /* Cycle over 0 -> 1 -> -1 -> 0 */
+      if (++val == 2)
+	val = -1;
+
+      *p++ = val;
+      if (val)
+	return 1;
+    }
+
+  return 0;
+}
+
+#define MK_TEST(A, B)							\
+NI void test_##A##_##B (void)						\
+{									\
+  u##A a = 0;								\
+  do									\
+    {									\
+      u##B b = 0;							\
+      do								\
+	{								\
+	  if (addu_##A##_##B (a, b) != addu_##A (a, b))			\
+	    __builtin_exit (11);					\
+	  								\
+	  if (adds_##A##_##B (a, b) != adds_##A ((s##A) a, (s##B) b))	\
+	    __builtin_exit (13);					\
+	  								\
+	} while (next (&b, sizeof (b)));				\
+    } while (next (&a, sizeof (a)));					\
+}
+
+MK_TEST (16, 8)
+
+MK_TEST (24, 8)
+MK_TEST (24, 16)
+
+MK_TEST (32, 8)
+MK_TEST (32, 16)
+MK_TEST (32, 24)
+
+
+int main (void)
+{
+  test_16_8 ();
+
+  test_24_8 ();
+  test_24_16 ();
+
+  test_32_8 ();
+  test_32_16 ();
+  test_32_24 ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/torture/sub-extend.c b/gcc/testsuite/gcc.target/avr/torture/sub-extend.c
new file mode 100644
index 00000000000..f97cdeb0ad1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/sub-extend.c
@@ -0,0 +1,109 @@
+/* { dg-do run } */
+
+typedef __UINT8_TYPE__ u8;
+typedef __UINT16_TYPE__ u16;
+typedef __uint24 u24;
+typedef __UINT32_TYPE__ u32;
+
+typedef __INT8_TYPE__ s8;
+typedef __INT16_TYPE__ s16;
+typedef __int24 s24;
+typedef __INT32_TYPE__ s32;
+
+#define NI __attribute__((noinline,noclone,noipa))
+
+NI u32 subu_32_8  (u32 a, u8 b)  { return a - b; }
+NI u32 subu_32_16 (u32 a, u16 b) { return a - b; }
+NI u32 subu_32_24 (u32 a, u24 b) { return a - b; }
+
+NI u24 subu_24_8  (u24 a, u8 b)  { return a - b; }
+NI u24 subu_24_16 (u24 a, u16 b) { return a - b; }
+
+NI u16 subu_16_8  (u16 a, u8 b)  { return a - b; }
+
+/************************/
+
+NI s32 subs_32_8  (s32 a, s8 b)  { return a - b; }
+NI s32 subs_32_16 (s32 a, s16 b) { return a - b; }
+NI s32 subs_32_24 (s32 a, s24 b) { return a - b; }
+
+NI s24 subs_24_8  (s24 a, s8 b)  { return a - b; }
+NI s24 subs_24_16 (s24 a, s16 b) { return a - b; }
+
+NI s16 subs_16_8  (s16 a, s8 b)  { return a - b; }
+
+/************************/
+
+NI u32 subu_32 (u32 a, u32 b)    { return a - b; }
+NI u24 subu_24 (u24 a, u24 b)    { return a - b; }
+NI u16 subu_16 (u16 a, u16 b)    { return a - b; }
+
+NI s32 subs_32 (s32 a, s32 b)    { return a - b; }
+NI s24 subs_24 (s24 a, s24 b)    { return a - b; }
+NI s16 subs_16 (s16 a, s16 b)    { return a - b; }
+
+/************************/
+
+NI u8 next (void *p0, u8 n_bytes)
+{
+  u8 *p = (u8*) p0;
+
+  u8 n;
+  for (n = 0; n < n_bytes; ++n)
+    {
+      u8 val = *p;
+
+      /* Cycle over 0 -> 1 -> -1 -> 0 */
+      if (++val == 2)
+	val = -1;
+
+      *p++ = val;
+      if (val)
+	return 1;
+    }
+
+  return 0;
+}
+
+#define MK_TEST(A, B)							\
+NI void test_##A##_##B (void)						\
+{									\
+  u##A a = 0;								\
+  do									\
+    {									\
+      u##B b = 0;							\
+      do								\
+	{								\
+	  if (subu_##A##_##B (a, b) != subu_##A (a, b))			\
+	    __builtin_exit (11);					\
+	  								\
+	  if (subs_##A##_##B (a, b) != subs_##A ((s##A) a, (s##B) b))	\
+	    __builtin_exit (13);					\
+	  								\
+	} while (next (&b, sizeof (b)));				\
+    } while (next (&a, sizeof (a)));					\
+}
+
+MK_TEST (16, 8)
+
+MK_TEST (24, 8)
+MK_TEST (24, 16)
+
+MK_TEST (32, 8)
+MK_TEST (32, 16)
+MK_TEST (32, 24)
+
+
+int main (void)
+{
+  test_16_8 ();
+
+  test_24_8 ();
+  test_24_16 ();
+
+  test_32_8 ();
+  test_32_16 ();
+  test_32_24 ();
+
+  return 0;
+}
