diff --git a/gcc/config/avr/avr-modes.def b/gcc/config/avr/avr-modes.def
index e0633d680d5..77b05dd8509 100644
--- a/gcc/config/avr/avr-modes.def
+++ b/gcc/config/avr/avr-modes.def
@@ -18,6 +18,11 @@
 
 FRACTIONAL_INT_MODE (PSI, 24, 3);
 
+/* Used when the N (and Z) flag(s) of SREG are set.
+   The N flag indicates  whether the value is negative.  */
+CC_MODE (CCN);
+CC_MODE (CCZN);
+
 /* Make TA and UTA 64 bits wide.
    128 bit wide modes would be insane on a 8-bit machine.
    This needs special treatment in avr.cc and avr-lib.h.  */
diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h
index dc23cfbf461..664513864fe 100644
--- a/gcc/config/avr/avr-protos.h
+++ b/gcc/config/avr/avr-protos.h
@@ -54,7 +54,7 @@ extern const char *avr_out_tsthi (rtx_insn *, rtx*, int*);
 extern const char *avr_out_tstpsi (rtx_insn *, rtx*, int*);
 extern const char *avr_out_compare (rtx_insn *, rtx*, int*);
 extern const char *avr_out_compare64 (rtx_insn *, rtx*, int*);
-extern const char *ret_cond_branch (rtx x, int len, int reverse);
+extern const char *ret_cond_branch (rtx x, int len, machine_mode);
 extern const char *avr_out_movpsi (rtx_insn *, rtx*, int*);
 extern const char *avr_out_sign_extend (rtx_insn *, rtx*, int*);
 extern const char *avr_out_insert_notbit (rtx_insn *, rtx*, int*);
@@ -62,6 +62,10 @@ extern const char *avr_out_insv (rtx_insn *, rtx*, int*);
 extern const char *avr_out_extr (rtx_insn *, rtx*, int*);
 extern const char *avr_out_extr_not (rtx_insn *, rtx*, int*);
 extern const char *avr_out_plus_set_ZN (rtx*, int*);
+extern const char *avr_out_plus_set_N (rtx*, int*);
+extern const char *avr_out_op8_set_ZN (RTX_CODE, rtx*, int*);
+extern int avr_len_op8_set_ZN (RTX_CODE, rtx*);
+extern bool avr_op8_ZN_operator (rtx);
 extern const char *avr_out_cmp_ext (rtx*, enum rtx_code, int*);
 
 extern const char *ashlqi3_out (rtx_insn *insn, rtx operands[], int *len);
diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index d299fceb782..270fa0f49ba 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -54,6 +54,7 @@
 #include "builtins.h"
 #include "context.h"
 #include "tree-pass.h"
+#include "pass_manager.h"
 #include "print-rtl.h"
 #include "rtl-iter.h"
 
@@ -157,7 +158,6 @@ static const char *out_movsi_mr_r (rtx_insn *, rtx[], int *);
 static int get_sequence_length (rtx_insn *insns);
 static int sequent_regs_live (void);
 static const char *ptrreg_to_str (int);
-static const char *cond_string (enum rtx_code);
 static int avr_num_arg_regs (machine_mode, const_tree);
 static int avr_operand_rtx_cost (rtx, machine_mode, enum rtx_code,
 				 int, bool);
@@ -1185,6 +1185,18 @@ avr_option_override (void)
   init_machine_status = avr_init_machine_status;
 
   avr_log_set_avr_log();
+
+  /* As long as peep2_rescan is not implemented, see
+     http://gcc.gnu.org/ml/gcc-patches/2011-10/msg02819.html
+     we add a second peephole2 run to get best results.  */
+  {
+    opt_pass *extra_peephole2
+      = g->get_passes ()->get_pass_peephole2 ()->clone ();
+    struct register_pass_info peep2_2_info
+      = { extra_peephole2, "peephole2", 1, PASS_POS_INSERT_AFTER };
+
+    register_pass (&peep2_2_info);
+  }
 }
 
 /* Function to set up the backend function structure.  */
@@ -3623,10 +3635,8 @@ ptrreg_to_str (int regno)
    Used in conditional jump constructing  */
 
 static const char *
-cond_string (enum rtx_code code)
+cond_string (enum rtx_code code, bool cc_overflow_unusable)
 {
-  bool cc_overflow_unusable = false;
-
   switch (code)
     {
     case NE:
@@ -3955,10 +3965,11 @@ avr_print_operand (FILE *file, rtx x, int code)
     }
   else if (GET_CODE (x) == CONST_STRING)
     fputs (XSTR (x, 0), file);
-  else if (code == 'j')
-    fputs (cond_string (GET_CODE (x)), file);
-  else if (code == 'k')
-    fputs (cond_string (reverse_condition (GET_CODE (x))), file);
+  else if (code == 'j' || code == 'L')
+    fputs (cond_string (GET_CODE (x), code == 'L'), file);
+  else if (code == 'k' || code == 'K')
+    fputs (cond_string (reverse_condition (GET_CODE (x)), code == 'K'),
+	   file);
   else
     avr_print_operand_address (file, VOIDmode, x);
 }
@@ -4008,13 +4019,17 @@ avr_jump_mode (rtx x, rtx_insn *insn)
 /* Return an AVR condition jump commands.
    X is a comparison RTX.
    LEN is a number returned by avr_jump_mode function.
-   If REVERSE nonzero then condition code in X must be reversed.  */
+   CCMODE is the mode of the comparison in CCmode, CCNmode, CCZNmode.  */
 
 const char *
-ret_cond_branch (rtx x, int len, int reverse)
+ret_cond_branch (rtx x, int len, machine_mode ccmode)
 {
-  RTX_CODE cond = reverse ? reverse_condition (GET_CODE (x)) : GET_CODE (x);
-  bool cc_overflow_unusable = false;
+  bool cc_overflow_unusable = ccmode != CCmode;
+  RTX_CODE cond = GET_CODE (x);
+
+  if (ccmode == CCNmode)
+    // The N flag can only do < 0 and >= 0.
+    gcc_assert (cond == GE || cond == LT);
 
   switch (cond)
     {
@@ -4076,33 +4091,20 @@ ret_cond_branch (rtx x, int len, int reverse)
 	       "brsh .+4" CR_TAB
 	       "jmp %0"));
     default:
-      if (reverse)
+      switch (len)
 	{
-	  switch (len)
-	    {
-	    case 1:
-	      return "br%k1 %0";
-	    case 2:
-	      return ("br%j1 .+2" CR_TAB
-		      "rjmp %0");
-	    default:
-	      return ("br%j1 .+4" CR_TAB
-		      "jmp %0");
-	    }
-	}
-      else
-	{
-	  switch (len)
-	    {
-	    case 1:
-	      return "br%j1 %0";
-	    case 2:
-	      return ("br%k1 .+2" CR_TAB
-		      "rjmp %0");
-	    default:
-	      return ("br%k1 .+4" CR_TAB
-		      "jmp %0");
-	    }
+	case 1:
+	  return cc_overflow_unusable
+	    ? "br%L1 %0"
+	    : "br%j1 %0";
+	case 2:
+	  return cc_overflow_unusable
+	    ? "br%K1 .+2" CR_TAB "rjmp %0"
+	    : "br%k1 .+2" CR_TAB "rjmp %0";
+	default:
+	  return cc_overflow_unusable
+	    ? "br%K1 .+4" CR_TAB "jmp %0"
+	    : "br%k1 .+4" CR_TAB "jmp %0";
 	}
     }
   return "";
@@ -9455,6 +9457,41 @@ avr_out_plus (rtx insn, rtx *xop, int *plen, bool out_label)
 }
 
 
+/* Output an addition with a compile-time constant that sets SREG.N:
+
+      XOP[0] += XOP[1]
+
+   where XOP[0] is a QI, HI, PSI or SI register, and XOP[1] is a compile-time
+   constant.  XOP[2] is SCRATCH or a QI clobber reg.  Return "".
+
+   If PLEN == NULL output the instructions.
+   If PLEN != NULL set *PLEN to the length of the sequence in words.  */
+
+const char *
+avr_out_plus_set_N (rtx *xop, int *plen)
+{
+  gcc_assert (xop[1] != const0_rtx);
+
+  if (GET_MODE_SIZE (GET_MODE (xop[0])) == 1
+      && ! test_hard_reg_class (LD_REGS, xop[0]))
+    return avr_out_plus_set_ZN (xop, plen);
+
+  // The output function for vanilla additions, avr_out_plus_1, can be
+  // used because it always issues an operation on the MSB (except when
+  // the addend is zero).
+
+  rtx op[] = { xop[0], xop[0], xop[1], xop[2] };
+  int len_plus, len_minus;
+
+  avr_out_plus_1 (NULL_RTX, op, &len_plus,  PLUS,  UNKNOWN, 0, false);
+  avr_out_plus_1 (NULL_RTX, op, &len_minus, MINUS, UNKNOWN, 0, false);
+
+  avr_out_plus_1 (NULL_RTX, op, plen, len_minus < len_plus ? MINUS : PLUS,
+		  UNKNOWN, 0, false);
+  return "";
+}
+
+
 /* Output an instruction sequence for addition of REG in XOP[0] and CONST_INT
    in XOP[1] in such a way that SREG.Z and SREG.N are set according to the
    result.  XOP[2] might be a d-regs clobber register.  If XOP[2] is SCRATCH,
@@ -9478,13 +9515,17 @@ avr_out_plus_set_ZN (rtx *xop, int *plen)
   // Number of bytes to operate on.
   int n_bytes = GET_MODE_SIZE (mode);
 
-  if (n_bytes == 1)
+  if (n_bytes == 1
+      && ! test_hard_reg_class (LD_REGS, xreg))
     {
-      if (INTVAL (xval) == 1)
-	return avr_asm_len ("inc %0", xop, plen, 1);
+      gcc_assert (abs1_abs2_operand (xval, QImode));
+      int ival = (int) INTVAL (xval);
 
-      if (INTVAL (xval) == -1)
-	return avr_asm_len ("dec %0", xop, plen, 1);
+      if (ival >= +1) avr_asm_len ("inc %0", xop, plen, 1);
+      if (ival == +2) avr_asm_len ("inc %0", xop, plen, 1);
+      if (ival <= -1) avr_asm_len ("dec %0", xop, plen, 1);
+      if (ival == -2) avr_asm_len ("dec %0", xop, plen, 1);
+      return "";
     }
 
   if (n_bytes == 2
@@ -9571,6 +9612,136 @@ avr_out_plus_set_ZN (rtx *xop, int *plen)
 }
 
 
+/* A helper worker for op8_ZN_operator.  Allow
+
+     OP0 <code> op1
+
+  QImode operations that set SREG.N and SREG.Z in a usable way.
+  these are:
+
+  * OP0 is a QImode register, and
+  * OP1 is a QImode register or CONST_INT, and
+
+  the allowed operations is one of:
+
+  * SHIFTs with a const_int offset in { 1, 2, 3 }.
+  * MINUS and XOR with a register operand
+  * IOR and AND with a register operand, or d-reg + const_int
+  * PLUS with a register operand, or d-reg + const_int,
+    or a const_int in { -2, -1, 1, 2 }.  */
+
+bool
+avr_op8_ZN_operator (rtx op)
+{
+  const RTX_CODE code = GET_CODE (op);
+  rtx op0 = XEXP (op, 0);
+  rtx op1 = XEXP (op, 1);
+
+  if (! register_operand (op0, QImode)
+      || ! (register_operand (op1, QImode)
+	    || const_int_operand (op1, QImode)))
+    return false;
+
+  const bool reg1_p = REG_P (op1);
+  const bool ld_reg0_p = test_hard_reg_class (LD_REGS, op0);
+
+  switch (code)
+    {
+    default:
+      break;
+
+    case ASHIFT:
+    case ASHIFTRT:
+    case LSHIFTRT:
+      return const_1_to_3_operand (op1, QImode);
+
+    case MINUS:
+    case XOR:
+      return reg1_p;
+
+    case IOR:
+    case AND:
+      return reg1_p || ld_reg0_p;
+
+    case PLUS:
+      return reg1_p || ld_reg0_p || abs1_abs2_operand (op1, QImode);
+    }
+
+  return false;
+}
+
+
+/* Output a QImode instruction sequence for
+
+      XOP[0] = XOP[0]  <CODE>  XOP[2]
+
+   where XOP[0] is a register, and the possible operands and CODEs
+   are according to  avr_op8_ZN_operator()  from above.  Return "".
+
+   If PLEN == NULL, then output the instructions.
+   If PLEN != NULL, then set *PLEN to the length of the sequence in words.  */
+
+const char *
+avr_out_op8_set_ZN (RTX_CODE code, rtx *xop, int *plen)
+{
+  const bool reg2_p = REG_P (xop[2]);
+  const int ival = CONST_INT_P (xop[2]) ? (int) INTVAL (xop[2]) : 0;
+
+  gcc_assert (op8_ZN_operator (gen_rtx_fmt_ee (code, QImode, xop[0], xop[2]),
+			       QImode));
+  if (plen)
+    *plen = 0;
+
+  const char *tpl = nullptr;
+  int times = 1;
+
+  if (code == ASHIFT)
+    tpl = "lsl %0", times = ival;
+  else if (code == LSHIFTRT)
+    tpl = "lsr %0", times = ival;
+  else if (code == ASHIFTRT)
+    tpl = "asr %0", times = ival;
+  else if (code == MINUS)
+    tpl = "sub %0,%2";
+  else if (code == XOR)
+    tpl = "eor %0,%2";
+  else if (code == AND)
+    tpl = reg2_p ? "and %0,%2" : "andi %0,lo8(%2)";
+  else if (code == IOR)
+    tpl = reg2_p ? "or %0,%2" : "ori %0,lo8(%2)";
+  else if (code == PLUS)
+    {
+      if (ival
+	  && ! test_hard_reg_class (LD_REGS, xop[0]))
+	{
+	  tpl = ival > 0 ? "inc %0" : "dec %0";
+	  times = ival > 0 ? ival : -ival;
+	}
+      else
+	tpl = reg2_p ? "add %0,%2" : "subi %0,lo8(%n2)";
+    }
+  else
+    gcc_unreachable();
+
+  for (int i = 0; i < times; ++i)
+    avr_asm_len (tpl, xop, plen, 1);
+
+  return "";
+}
+
+
+/* Used in the "length" attribute of insn "*op8.for.cczn.<code>".  */
+
+int
+avr_len_op8_set_ZN (RTX_CODE code, rtx *xop)
+{
+  int len;
+  (void) avr_out_op8_set_ZN (code, xop, &len);
+
+  return len;
+}
+
+
 /* Output bit operation (IOR, AND, XOR) with register XOP[0] and compile
    time constant XOP[2]:
 
@@ -11022,6 +11193,7 @@ avr_adjust_insn_length (rtx_insn *insn, int len)
 
     case ADJUST_LEN_INSERT_BITS: avr_out_insert_bits (op, &len); break;
     case ADJUST_LEN_ADD_SET_ZN: avr_out_plus_set_ZN (op, &len); break;
+    case ADJUST_LEN_ADD_SET_N:  avr_out_plus_set_N (op, &len); break;
 
     case ADJUST_LEN_INSV_NOTBIT: avr_out_insert_notbit (insn, op, &len); break;
 
@@ -11210,7 +11382,7 @@ avr_assemble_integer (rtx x, unsigned int size, int aligned_p)
 static unsigned char
 avr_class_max_nregs (reg_class_t rclass, machine_mode mode)
 {
-  if (rclass == CC_REG && mode == CCmode)
+  if (rclass == CC_REG && GET_MODE_CLASS (mode) == MODE_CC)
     return 1;
 
   return CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD);
@@ -13750,7 +13922,7 @@ jump_over_one_insn_p (rtx_insn *insn, rtx dest)
 static unsigned int
 avr_hard_regno_nregs (unsigned int regno, machine_mode mode)
 {
-  if (regno == REG_CC && mode == CCmode)
+  if (regno == REG_CC && GET_MODE_CLASS (mode) == MODE_CC)
     return 1;
 
   return CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD);
@@ -13765,7 +13937,7 @@ static bool
 avr_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
 {
   if (regno == REG_CC)
-    return mode == CCmode;
+    return GET_MODE_CLASS (mode) == MODE_CC;
 
   /* NOTE: 8-bit values must not be disallowed for R28 or R29.
 	Disallowing QI et al. in these regs might lead to code like
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index 2783b8c986f..e4f55fb7f4f 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -171,7 +171,7 @@ (define_attr "adjust_len"
    ashlsi, ashrsi, lshrsi,
    ashlpsi, ashrpsi, lshrpsi,
    insert_bits, insv_notbit, insv,
-   add_set_ZN, cmp_uext, cmp_sext,
+   add_set_ZN, add_set_N, cmp_uext, cmp_sext,
    no"
   (const_string "no"))
 
@@ -277,6 +277,11 @@ (define_mode_iterator ALLs4 [SI SQ SA])
 (define_mode_iterator ALLs234 [HI SI PSI
                                HQ HA SQ SA])
 
+(define_mode_iterator ALLCC [CC CCN CCZN])
+(define_mode_iterator CCN_CCZN [CCN CCZN])
+
+(define_mode_attr CCname [(CC "") (CCN "_N") (CCZN "_ZN")])
+
 ;; All supported move-modes
 (define_mode_iterator MOVMODE [QI QQ UQQ
                                HI HQ UHQ HA UHA
@@ -319,6 +324,9 @@ (define_code_iterator bitop [xor ior and])
 (define_code_iterator xior [xor ior])
 (define_code_iterator eqne [eq ne])
 (define_code_iterator gelt [ge lt])
+(define_code_iterator eqnegtle [eq ne gt le])
+(define_code_iterator cmp_signed [eq ne ge lt gt le])
+(define_code_iterator op8_ZN [plus minus and ior xor ashift ashiftrt lshiftrt])
 
 (define_code_iterator ss_addsub [ss_plus ss_minus])
 (define_code_iterator us_addsub [us_plus us_minus])
@@ -350,6 +358,20 @@ (define_code_attr gelt_eqne
   [(ge "eq")
    (lt "ne")])
 
+(define_code_attr swap
+  [(eq "eq") (ne "ne")
+   (lt "gt") (gt "lt")
+   (le "ge") (ge "le")])
+
+(define_code_attr SWAP
+  [(eq "EQ") (ne "NE")
+   (lt "GT") (gt "LT")
+   (le "GE") (ge "LE")])
+
+;; Convert test of MSB to < 0 resp. >= 0.
+(define_code_attr tstMSB
+  [(eq "ge") (ne "lt")])
+
 ;; Map RTX code to its standard insn name
 (define_code_attr code_stdname
   [(ashift   "ashl")
@@ -7199,32 +7221,26 @@ (define_peephole2 ; "*sbrx_branch<mode>"
 ;;  Compare with 0 (test) jumps
 ;; ************************************************************************
 
-(define_insn "branch"
+;; "branch"
+;; "branch_N"
+;; "branch_ZN"
+(define_insn "branch<CCname>"
   [(set (pc)
-        (if_then_else (match_operator 1 "simple_comparison_operator"
-                        [(reg:CC REG_CC)
+        (if_then_else (match_operator 1 "ordered_comparison_operator"
+                        [(reg:ALLCC REG_CC)
                          (const_int 0)])
                       (label_ref (match_operand 0))
                       (pc)))]
   "reload_completed"
   {
-    return ret_cond_branch (operands[1], avr_jump_mode (operands[0], insn), 0);
-  }
-  [(set_attr "type" "branch")])
-
-
-(define_insn "difficult_branch"
-  [(set (pc)
-        (if_then_else (match_operator 1 "difficult_comparison_operator"
-                        [(reg:CC REG_CC)
-                         (const_int 0)])
-                      (label_ref (match_operand 0 "" ""))
-                      (pc)))]
-  "reload_completed"
-  {
-    return ret_cond_branch (operands[1], avr_jump_mode (operands[0], insn), 0);
+    return ret_cond_branch (operands[1], avr_jump_mode (operands[0], insn),
+                            <MODE>mode);
   }
-  [(set_attr "type" "branch1")])
+  [(set (attr "type")
+        (if_then_else
+         (match_test "simple_comparison_operator (operands[1], VOIDmode)")
+         (const_string "branch")
+         (const_string "branch1")))])
 
 
 ;; **************************************************************************
@@ -9547,8 +9563,8 @@ (define_peephole2
 ;; by a comparison of the result against zero, we can output the addition
 ;; in such a way that SREG.N and SREG.Z are set according to the result.
 
-;; { -1, +1 } for QImode, otherwise the empty set.
-(define_mode_attr p1m1 [(QI "N P")
+;; { -2, -1, +1, +2 } for QImode, otherwise the empty set.
+(define_mode_attr p2m2 [(QI "Cm2 N P K")
                         (HI "Yxx") (PSI "Yxx") (SI "Yxx")])
 
 ;; FIXME: reload1.cc::do_output_reload() does not support output reloads
@@ -9587,46 +9603,72 @@ (define_mode_attr p1m1 [(QI "N P")
 ;; doloop_end doesn't reload either, so doloop_end also won't work.
 
 (define_expand "gen_add_for_<code>_<mode>"
-  ; "*add.for.eqne.<mode>"
-  [(parallel [(set (reg:CC REG_CC)
-                   (compare:CC (plus:QISI (match_operand:QISI 0 "register_operand")
-                                          (match_operand:QISI 1 "const_int_operand"))
-                               (const_int 0)))
+  ; "*add.for.cczn.<mode>"
+  [(parallel [(set (reg:CCZN REG_CC)
+                   (compare:CCZN (plus:QISI (match_operand:QISI 0 "register_operand")
+                                            (match_operand:QISI 1 "const_int_operand"))
+                                 (const_int 0)))
               (set (match_dup 0)
                    (plus:QISI (match_dup 0)
                               (match_dup 1)))
               (clobber (match_operand:QI 3))])
-   ; "branch"
+   ; "branch_ZN"
    (set (pc)
-        (if_then_else (eqne (reg:CC REG_CC)
+        (if_then_else (eqnegtle (reg:CCZN REG_CC)
+                                (const_int 0))
+                      (label_ref (match_dup 2))
+                      (pc)))])
+
+(define_expand "gen_add_for_<code>_<mode>"
+  ; "*add.for.ccn.<mode>"
+  [(parallel [(set (reg:CCN REG_CC)
+                   (compare:CCN (plus:QISI (match_operand:QISI 0 "register_operand")
+                                           (match_operand:QISI 1 "const_int_operand"))
+                                (const_int 0)))
+              (set (match_dup 0)
+                   (plus:QISI (match_dup 0)
+                              (match_dup 1)))
+              (clobber (match_operand:QI 3))])
+   ; "branch_N"
+   (set (pc)
+        (if_then_else (gelt (reg:CCN REG_CC)
                             (const_int 0))
                       (label_ref (match_dup 2))
                       (pc)))])
 
 
-;; 1/3: A version without clobber: d-reg or 8-bit adds +/-1.
+;; 1/3: A version without clobber: d-reg or 8-bit adds -2, -1, 1 or 2.
 (define_peephole2
   [(parallel [(set (match_operand:QISI 0 "register_operand")
                    (plus:QISI (match_dup 0)
                               (match_operand:QISI 1 "const_int_operand")))
               (clobber (reg:CC REG_CC))])
    (set (reg:CC REG_CC)
-        (compare:CC (match_dup 0)
-                    (const_int 0)))
+        (compare:CC (match_operand:QISI 3 "reg_or_0_operand")   ; 0 or $0
+                    (match_operand:QISI 4 "reg_or_0_operand"))) ; 0 or $0
    (set (pc)
-        (if_then_else (eqne (reg:CC REG_CC)
-                            (const_int 0))
+        (if_then_else (cmp_signed (reg:CC REG_CC)
+                                  (const_int 0))
                       (label_ref (match_operand 2))
                       (pc)))]
   "peep2_regno_dead_p (3, REG_CC)
    && (d_register_operand (operands[0], <MODE>mode)
        || (<MODE>mode == QImode
-           && (INTVAL (operands[1]) == 1
-               || INTVAL (operands[1]) == -1)))"
+           && abs1_abs2_operand (operands[1], QImode)))"
   [(scratch)]
   {
-    emit (gen_gen_add_for_<code>_<mode> (operands[0], operands[1], operands[2],
-          gen_rtx_SCRATCH (QImode)));
+    rtx (*gen)(rtx, rtx, rtx, rtx);
+
+    if (rtx_equal_p (operands[0], operands[3])
+        && const0_operand (operands[4], <MODE>mode))
+      gen = gen_gen_add_for_<code>_<mode>;
+    else if (const0_operand (operands[3], <MODE>mode)
+             && rtx_equal_p (operands[0], operands[4]))
+      gen = gen_gen_add_for_<cmp_signed:swap>_<mode>;
+    else
+      FAIL;
+
+    emit (gen (operands[0], operands[1], operands[2], gen_rtx_SCRATCH (QImode)));
     DONE;
   })
 
@@ -9638,30 +9680,39 @@ (define_peephole2
               (clobber (match_operand:QI 3 "scratch_or_d_register_operand"))
               (clobber (reg:CC REG_CC))])
    (parallel [(set (reg:CC REG_CC)
-                   (compare:CC (match_dup 0)
-                               (const_int 0)))
+                   (compare:CC (match_operand:QISI 5 "reg_or_0_operand")   ; 0 or $0
+                               (match_operand:QISI 6 "reg_or_0_operand"))) ; 0 or $0
               (clobber (match_operand:QI 4 "scratch_or_d_register_operand"))])
    (set (pc)
-        (if_then_else (eqne (reg:CC REG_CC)
-                            (const_int 0))
+        (if_then_else (cmp_signed (reg:CC REG_CC)
+                                  (const_int 0))
                       (label_ref (match_operand 2))
                       (pc)))]
   "peep2_regno_dead_p (3, REG_CC)"
   [(scratch)]
   {
     rtx scratch = REG_P (operands[3]) ? operands[3] : operands[4];
+    rtx (*gen)(rtx, rtx, rtx, rtx);
 
     // We need either a d-register or a scratch register to clobber.
     if (! REG_P (scratch)
         && ! d_register_operand (operands[0], <MODE>mode)
         && ! (QImode == <MODE>mode
-              && (INTVAL (operands[1]) == 1
-                  || INTVAL (operands[1]) == -1)))
+              && abs1_abs2_operand (operands[1], QImode)))
       {
         FAIL;
       }
-    emit (gen_gen_add_for_<code>_<mode> (operands[0], operands[1], operands[2],
-          scratch));
+
+    if (rtx_equal_p (operands[0], operands[5])
+        && const0_operand (operands[6], <MODE>mode))
+      gen = gen_gen_add_for_<code>_<mode>;
+    else if (const0_operand (operands[5], <MODE>mode)
+             && rtx_equal_p (operands[0], operands[6]))
+      gen = gen_gen_add_for_<cmp_signed:swap>_<mode>;
+    else
+      FAIL;
+
+    emit (gen (operands[0], operands[1], operands[2], scratch));
     DONE;
   })
 
@@ -9673,41 +9724,255 @@ (define_peephole2
                               (match_operand:QISI 1 "const_int_operand")))
               (clobber (reg:CC REG_CC))])
    (set (reg:CC REG_CC)
-        (compare:CC (match_dup 0)
-                    (const_int 0)))
+        (compare:CC (match_operand:QISI 4 "reg_or_0_operand")   ; 0 or $0
+                    (match_operand:QISI 5 "reg_or_0_operand"))) ; 0 or $0
    (set (pc)
-        (if_then_else (eqne (reg:CC REG_CC)
-                            (const_int 0))
+        (if_then_else (cmp_signed (reg:CC REG_CC)
+                                  (const_int 0))
                       (label_ref (match_operand 2))
                       (pc)))]
   "peep2_regno_dead_p (3, REG_CC)"
   [(scratch)]
   {
-    emit (gen_gen_add_for_<code>_<mode> (operands[0], operands[1], operands[2],
-          operands[3]));
+    rtx (*gen)(rtx, rtx, rtx, rtx);
+
+    if (rtx_equal_p (operands[0], operands[4])
+        && const0_operand (operands[5], <MODE>mode))
+      gen = gen_gen_add_for_<code>_<mode>;
+    else if (const0_operand (operands[4], <MODE>mode)
+             && rtx_equal_p (operands[0], operands[5]))
+      gen = gen_gen_add_for_<cmp_signed:swap>_<mode>;
+    else
+      FAIL;
+
+    emit (gen (operands[0], operands[1], operands[2], operands[3]));
     DONE;
   })
 
 ;; Result of the above three peepholes is an addition that also
-;; performs an EQ or NE comparison (of the result) against zero.
+;; performs a signed comparison (of the result) against zero.
 ;; FIXME: Using (match_dup 0) instead of operands[3/4] makes rnregs
 ;; barf in regrename.cc::merge_overlapping_regs().  For now, use the
 ;; fix from PR50788: Constrain as "0".
-(define_insn "*add.for.eqne.<mode>"
-  [(set (reg:CC REG_CC)
-        (compare:CC
-         (plus:QISI (match_operand:QISI 3 "register_operand"  "0,0     ,0")
-                    (match_operand:QISI 1 "const_int_operand" "n,<p1m1>,n"))
+; "*add.for.ccn.qi"   "*add.for.cczn.qi"
+; "*add.for.ccn.hi"   "*add.for.cczn.hi"
+; "*add.for.ccn.psi"  "*add.for.cczn.psi"
+; "*add.for.ccn.si"   "*add.for.cczn.si"
+(define_insn "*add.for.<CCN_CCZN:mode>.<QISI:mode>"
+  [(set (reg:CCN_CCZN REG_CC)
+        (compare:CCN_CCZN
+         (plus:QISI (match_operand:QISI 3 "register_operand"  "0,0          ,0")
+                    (match_operand:QISI 1 "const_int_operand" "n,<QISI:p2m2>,n"))
          (const_int 0)))
-   (set (match_operand:QISI 0 "register_operand"             "=d,*r    ,r")
-        (plus:QISI (match_operand:QISI 4 "register_operand"   "0,0     ,0")
+   (set (match_operand:QISI 0 "register_operand"             "=d,*r         ,r")
+        (plus:QISI (match_operand:QISI 4 "register_operand"   "0,0          ,0")
                    (match_dup 1)))
-   (clobber (match_scratch:QI 2                              "=X,X     ,&d"))]
+   (clobber (match_scratch:QI 2                              "=X,X          ,&d"))]
+  "reload_completed"
+  {
+    return avr_out_plus_set<CCname> (operands, nullptr);
+  }
+  [(set_attr "adjust_len" "add_set<CCname>")])
+
+
+
+;; Operations other that PLUS can set the condition code in
+;; a meaningful way, too.
+
+;; 1/2 Left shift sets the N bit.
+(define_peephole2
+  [(parallel [(set (match_operand:HISI 0 "register_operand")
+                   (ashift:HISI (match_dup 0)
+                                (const_int 1)))
+              (clobber (match_operand:QI 3 "scratch_operand"))
+              (clobber (reg:CC REG_CC))])
+   (set (reg:CC REG_CC)
+        (compare:CC (match_dup 0)
+                    (const_int 0)))
+   (set (pc)
+        (if_then_else (gelt (reg:CC REG_CC)
+                            (const_int 0))
+                      (label_ref (match_operand 2))
+                      (pc)))]
+  "peep2_regno_dead_p (3, REG_CC)"
+  [; "*ashift.for.ccn.<mode>"
+   (parallel [(set (reg:CCN REG_CC)
+                   (compare:CCN (ashift:HISI (match_dup 0)
+                                             (const_int 1))
+                                (const_int 0)))
+              (set (match_dup 0)
+                   (ashift:HISI (match_dup 0)
+                                (const_int 1)))])
+   ; "branch_N"
+   (set (pc)
+        (if_then_else (gelt (reg:CCN REG_CC)
+                            (const_int 0))
+                      (label_ref (match_operand 2))
+                      (pc)))])
+
+
+;; 2/2 Left shift sets the N bit.  Same like above, but with ZERO_EXTRACT
+(define_peephole2
+  [(parallel [(set (match_operand:HISI 0 "register_operand")
+                   (ashift:HISI (match_dup 0)
+                                (const_int 1)))
+              (clobber (match_operand:QI 3 "scratch_operand"))
+              (clobber (reg:CC REG_CC))])
+   (parallel [(set (pc)
+                   (if_then_else
+                    (eqne (zero_extract (match_dup 0)
+                                        (const_int 1)
+                                        (match_operand 4 "const<MSB>_operand"))
+                          (const_int 0))
+                    (label_ref (match_operand 2))
+                    (pc)))
+              (clobber (reg:CC REG_CC))])]
+  ""
+  [; "*ashift.for.ccn.<mode>"
+   (parallel [(set (reg:CCN REG_CC)
+                   (compare:CCN (ashift:HISI (match_dup 0)
+                                             (const_int 1))
+                                (const_int 0)))
+              (set (match_dup 0)
+                   (ashift:HISI (match_dup 0)
+                                (const_int 1)))])
+   ; "branch_N"
+   (set (pc)
+        (if_then_else (<tstMSB> (reg:CCN REG_CC)
+                                (const_int 0))
+                      (label_ref (match_operand 2))
+                      (pc)))])
+
+
+(define_insn "*ashift.for.ccn.<mode>"
+  [(set (reg:CCN REG_CC)
+        (compare:CCN (ashift:HISI (match_operand:HISI 2 "register_operand" "0")
+                                  (const_int 1))
+                     (const_int 0)))
+   (set (match_operand:HISI 0 "register_operand"             "=r")
+        (ashift:HISI (match_operand:HISI 1 "register_operand" "0")
+                     (const_int 1)))]
   "reload_completed"
   {
-    return avr_out_plus_set_ZN (operands, nullptr);
+    output_asm_insn ("lsl %A0", operands);
+    if (<SIZE> >= 2) output_asm_insn ("rol %B0", operands);
+    if (<SIZE> >= 3) output_asm_insn ("rol %C0", operands);
+    if (<SIZE> >= 4) output_asm_insn ("rol %D0", operands);
+    return "";
+  }
+  [(set_attr "length" "<SIZE>")])
+
+
+;; 1/2 QImode operations that set Z and N in a meaningful way.
+(define_peephole2
+  [(parallel [(set (match_operand:QI 0 "register_operand")
+                   (match_operator:QI 2 "op8_ZN_operator" [(match_dup 0)
+                                                           (match_operand:QI 1)]))
+              (clobber (reg:CC REG_CC))])
+   (parallel [(set (pc)
+                   (if_then_else (eqne (zero_extract (match_dup 0)
+                                                     (const_int 1)
+                                                     (const_int 7))
+                                       (const_int 0))
+                                 (label_ref (match_operand 3))
+                                 (pc)))
+              (clobber (reg:CC REG_CC))])]
+  ""
+  [; "*op8.for.cczn.<code>"
+   (parallel [(set (reg:CCZN REG_CC)
+                   (compare:CCZN (match_op_dup 2 [(match_dup 0)
+                                                  (match_dup 1)])
+                                 (const_int 0)))
+              (set (match_dup 0)
+                   (match_op_dup 2 [(match_dup 0)
+                                    (match_dup 1)]))])
+   ; "branch_ZN"
+   (set (pc)
+        (if_then_else (<tstMSB> (reg:CCZN REG_CC)
+                                (const_int 0))
+                      (label_ref (match_operand 3))
+                      (pc)))])
+
+
+;; 2/2 QImode operations that set Z and N in a meaningful way.
+(define_peephole2
+  [(parallel [(set (match_operand:QI 0 "register_operand")
+                   (match_operator:QI 2 "op8_ZN_operator" [(match_dup 0)
+                                                           (match_operand:QI 1)]))
+              (clobber (reg:CC REG_CC))])
+   (set (reg:CC REG_CC)
+        (compare:CC (match_operand:QI 4 "reg_or_0_operand")   ; 0 or $0
+                    (match_operand:QI 5 "reg_or_0_operand"))) ; 0 or $0
+   (set (pc)
+        (if_then_else (cmp_signed (reg:CC REG_CC)
+                                  (const_int 0))
+                      (label_ref (match_operand 3))
+                      (pc)))]
+  "peep2_regno_dead_p (3, REG_CC)"
+  [; "*op8.for.cczn.<code>"
+   (parallel [(set (reg:CCZN REG_CC)
+                   (compare:CCZN (match_op_dup 2 [(match_dup 0)
+                                                  (match_dup 1)])
+                                 (const_int 0)))
+              (set (match_dup 0)
+                   (match_op_dup 2 [(match_dup 0)
+                                    (match_dup 1)]))])
+   ; "branch_ZN"
+   (set (pc)
+        (if_then_else (match_dup 6)
+                      (label_ref (match_operand 3))
+                      (pc)))]
+  {
+    RTX_CODE code = UNKNOWN;
+
+    if (rtx_equal_p (operands[4], operands[0])
+        && const0_operand (operands[5], QImode))
+      code = <cmp_signed:CODE>;
+    else if (const0_operand (operands[4], QImode)
+             && rtx_equal_p (operands[5], operands[0]))
+      code = <cmp_signed:SWAP>;
+    else
+      FAIL;
+
+  operands[6] = gen_rtx_fmt_ee (code, VOIDmode,
+                                gen_rtx_REG (CCZNmode, REG_CC), const0_rtx);
+  })
+
+;; Constraints and predicate for the insn below.
+;; This is what op8_ZN_operator allows.
+;; Note again that due to nregs, match_dup's won't work.
+(define_code_attr c0_op8
+  [(minus "r") (xor "r") (and "d,r") (ior "d,r") (plus "d,r") (ashift "r") (ashiftrt "r") (lshiftrt "r")])
+(define_code_attr c1_op8
+  [(minus "0") (xor "0") (and "0,0") (ior "0,0") (plus "0,0") (ashift "0") (ashiftrt "0") (lshiftrt "0")])
+(define_code_attr c4_op8
+  [(minus "2") (xor "2") (and "2,2") (ior "2,2") (plus "2,2") (ashift "2") (ashiftrt "2") (lshiftrt "2")])
+(define_code_attr c2_op8
+  [(minus "r") (xor "r") (and "n,r") (ior "n,r") (plus "n,rPNKCm2")
+   (ashift "PKC03") (ashiftrt "PKC03") (lshiftrt "PKC03")])
+
+(define_code_attr p2_op8
+  [(ashift "const_1_to_3")  (ashiftrt "const_1_to_3")  (lshiftrt "const_1_to_3")
+   (minus "register")  (xor "register")
+   (plus "nonmemory")  (and "nonmemory")  (ior "nonmemory")])
+
+;; Result of the two peephole2's above:  An 8-bit operation that
+;; sets Z and N.  The allowed operations are:
+;; PLUS, MINUS, AND, IOR, XOR and SHIFTs.
+(define_insn "*op8.for.cczn.<code>"
+  [(parallel [(set (reg:CCZN REG_CC)
+                   (compare:CCZN (op8_ZN:QI (match_operand:QI 3 "register_operand" "<c1_op8>")
+                                            (match_operand:QI 4 "<p2_op8>_operand" "<c4_op8>"))
+                                 (const_int 0)))
+              (set (match_operand:QI 0 "register_operand"           "=<c0_op8>")
+                   (op8_ZN:QI (match_operand:QI 1 "register_operand" "<c1_op8>")
+                              (match_operand:QI 2 "<p2_op8>_operand" "<c2_op8>")))])]
+  "reload_completed"
+  {
+    return avr_out_op8_set_ZN (<CODE>, operands, nullptr);
   }
-  [(set_attr "adjust_len" "add_set_ZN")])
+  [(set (attr "length")
+        (symbol_ref ("avr_len_op8_set_ZN (<CODE>, operands)")))])
 
 
 ;; Swapping both comparison and branch condition.  This can turn difficult
diff --git a/gcc/config/avr/predicates.md b/gcc/config/avr/predicates.md
index 12013660ed1..0a35c8c31c1 100644
--- a/gcc/config/avr/predicates.md
+++ b/gcc/config/avr/predicates.md
@@ -147,6 +147,11 @@ (define_predicate "const_2_to_7_operand"
   (and (match_code "const_int")
        (match_test "IN_RANGE (INTVAL (op), 2, 7)")))
 
+;; Return true if OP is constant integer 1..3 for MODE.
+(define_predicate "const_1_to_3_operand"
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (INTVAL (op), 1, 3)")))
+
 ;; Return 1 if OP is constant integer 1..6 for MODE.
 (define_predicate "const_1_to_6_operand"
   (and (match_code "const_int")
@@ -162,6 +167,12 @@ (define_predicate "const_m255_to_m1_operand"
   (and (match_code "const_int")
        (match_test "IN_RANGE (INTVAL (op), -255, -1)")))
 
+;; Return true if OP is a CONST_INT in { -2, -1, 1, 2 }.
+(define_predicate "abs1_abs2_operand"
+  (and (match_code "const_int")
+       (match_test "INTVAL (op) != 0")
+       (match_test "IN_RANGE (INTVAL (op), -2, 2)")))
+
 ;; Returns true if OP is either the constant zero or a register.
 (define_predicate "reg_or_0_operand"
   (ior (match_operand 0 "register_operand")
@@ -228,10 +239,30 @@ (define_predicate "simple_comparison_operator"
   (and (match_operand 0 "comparison_operator")
        (not (match_code "gt,gtu,le,leu"))))
 
+;; True for EQ, NE, GE, LT, GT, LE
+(define_predicate "signed_comparison_operator"
+  (match_code "eq,ne,ge,lt,gt,le"))
+
 ;; True for SIGN_EXTEND, ZERO_EXTEND.
 (define_predicate "extend_operator"
   (match_code "sign_extend,zero_extend"))
 
+;; True for 8-bit operations that set SREG.N and SREG.Z in a
+;; usable way:
+;; * OP0 is a QImode register, and
+;; * OP1 is a QImode register or CONST_INT, and
+;;
+;; the allowed operations is one of:
+;;
+;; * SHIFTs with a const_int offset in { 1, 2, 3 }.
+;; * MINUS and XOR with a register operand
+;; * IOR and AND with a register operand, or d-reg + const_int
+;; * PLUS with a register operand, or d-reg + const_int,
+;;   or a const_int in { -2, -1, 1, 2 }.  */
+(define_predicate "op8_ZN_operator"
+  (and (match_code "plus,minus,ashift,ashiftrt,lshiftrt,and,ior,xor")
+       (match_test "avr_op8_ZN_operator (op)")))
+
 ;; Return true if OP is a valid call operand.
 (define_predicate "call_insn_operand"
   (and (match_code "mem")
diff --git a/gcc/testsuite/gcc.target/avr/pr115830-add-c.c b/gcc/testsuite/gcc.target/avr/pr115830-add-c.c
new file mode 100644
index 00000000000..4f269293590
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/pr115830-add-c.c
@@ -0,0 +1,79 @@
+/* { dg-do run } */
+/* { dg-additional-options { -std=c99 -fwrapv -Os } } */
+
+typedef __UINT8_TYPE__ uint8_t;
+typedef __INT8_TYPE__  int8_t;
+
+#define AI static inline __attribute__((always_inline))
+#define NI __attribute__((noinline,noclone,no_icf))
+
+#define TYP int8_t
+
+TYP volatile v;
+
+#define MK_FUN(ID, OP, TST)                     \
+NI TYP func1_##ID (TYP c)                       \
+{                                               \
+  v = 42;                                       \
+  c OP;                                         \
+  if (c TST)                                    \
+    v = c;                                      \
+  return v;                                     \
+}                                               \
+                                                \
+NI TYP func2_##ID (TYP c)                       \
+{                                               \
+  TYP v = 42;                                   \
+  c OP;                                         \
+  __asm ("" : "+r" (c));                        \
+  if (c TST)                                    \
+    v = c;                                      \
+  return v;                                     \
+}
+
+MK_FUN (ADD_01, += 1, != 0)
+MK_FUN (ADD_02, += 1, == 0)
+MK_FUN (ADD_03, += 1, >= 0)
+MK_FUN (ADD_04, += 1, <= 0)
+MK_FUN (ADD_05, += 1, > 0)
+MK_FUN (ADD_06, += 1, < 0)
+MK_FUN (ADD_07, -= 2, != 0)
+MK_FUN (ADD_08, -= 2, == 0)
+MK_FUN (ADD_09, -= 2, >= 0)
+MK_FUN (ADD_10, -= 2, <= 0)
+MK_FUN (ADD_11, -= 2, > 0)
+MK_FUN (ADD_12, -= 2, < 0)
+MK_FUN (ADD_13, += 42, != 0)
+MK_FUN (ADD_14, += 42, == 0)
+MK_FUN (ADD_15, += 42, >= 0)
+MK_FUN (ADD_16, += 42, <= 0)
+MK_FUN (ADD_17, += 42, > 0)
+MK_FUN (ADD_18, += 42, < 0)
+	
+
+int main (void)
+{
+  uint8_t c = 0;
+  do {
+    if (func1_ADD_01 (c) != func2_ADD_01 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_02 (c) != func2_ADD_02 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_03 (c) != func2_ADD_03 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_04 (c) != func2_ADD_04 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_05 (c) != func2_ADD_05 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_06 (c) != func2_ADD_06 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_07 (c) != func2_ADD_07 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_08 (c) != func2_ADD_08 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_09 (c) != func2_ADD_09 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_10 (c) != func2_ADD_10 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_11 (c) != func2_ADD_11 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_12 (c) != func2_ADD_12 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_13 (c) != func2_ADD_13 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_14 (c) != func2_ADD_14 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_15 (c) != func2_ADD_15 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_16 (c) != func2_ADD_16 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_17 (c) != func2_ADD_17 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_18 (c) != func2_ADD_18 (c)) __builtin_exit (__LINE__);
+  } while (++c);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/pr115830-add-i.c b/gcc/testsuite/gcc.target/avr/pr115830-add-i.c
new file mode 100644
index 00000000000..f3b4df95fd7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/pr115830-add-i.c
@@ -0,0 +1,103 @@
+/* { dg-do run } */
+/* { dg-additional-options { -std=c99 -fwrapv -Os } } */
+
+typedef __UINT16_TYPE__ uint16_t;
+typedef __INT16_TYPE__  int16_t;
+
+#define AI static inline __attribute__((always_inline))
+#define NI __attribute__((noinline,noclone,no_icf))
+
+#define TYP int16_t
+
+TYP volatile v;
+
+#define MK_FUN(ID, OP, TST)                     \
+NI TYP func1_##ID (TYP c)                       \
+{                                               \
+  v = 42;                                       \
+  c OP;                                         \
+  if (c TST)                                    \
+    v = c;                                      \
+  return v;                                     \
+}                                               \
+                                                \
+NI TYP func2_##ID (TYP c)                       \
+{                                               \
+  TYP v = 42;                                   \
+  c OP;                                         \
+  __asm ("" : "+r" (c));                        \
+  if (c TST)                                    \
+    v = c;                                      \
+  return v;                                     \
+}
+
+MK_FUN (ADD_01, += 1, != 0)
+MK_FUN (ADD_02, += 1, == 0)
+MK_FUN (ADD_03, += 1, >= 0)
+MK_FUN (ADD_04, += 1, <= 0)
+MK_FUN (ADD_05, += 1, > 0)
+MK_FUN (ADD_06, += 1, < 0)
+MK_FUN (ADD_07, -= 2, != 0)
+MK_FUN (ADD_08, -= 2, == 0)
+MK_FUN (ADD_09, -= 2, >= 0)
+MK_FUN (ADD_10, -= 2, <= 0)
+MK_FUN (ADD_11, -= 2, > 0)
+MK_FUN (ADD_12, -= 2, < 0)
+MK_FUN (ADD_13, += 42, != 0)
+MK_FUN (ADD_14, += 42, == 0)
+MK_FUN (ADD_15, += 42, >= 0)
+MK_FUN (ADD_16, += 42, <= 0)
+MK_FUN (ADD_17, += 42, > 0)
+MK_FUN (ADD_18, += 42, < 0)
+MK_FUN (ADD_19, += 256, != 0)
+MK_FUN (ADD_20, += 256, == 0)
+MK_FUN (ADD_21, += 256, >= 0)
+MK_FUN (ADD_22, += 256, <= 0)
+MK_FUN (ADD_23, += 256, > 0)
+MK_FUN (ADD_24, += 256, < 0)
+MK_FUN (ADD_25, += 512, != 0)
+MK_FUN (ADD_26, += 512, == 0)
+MK_FUN (ADD_27, += 512, >= 0)
+MK_FUN (ADD_28, += 512, <= 0)
+MK_FUN (ADD_29, += 512, > 0)
+MK_FUN (ADD_30, += 512, < 0)
+	
+
+int main (void)
+{
+  uint16_t c = 0;
+  do {
+    if (func1_ADD_01 (c) != func2_ADD_01 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_02 (c) != func2_ADD_02 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_03 (c) != func2_ADD_03 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_04 (c) != func2_ADD_04 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_05 (c) != func2_ADD_05 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_06 (c) != func2_ADD_06 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_07 (c) != func2_ADD_07 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_08 (c) != func2_ADD_08 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_09 (c) != func2_ADD_09 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_10 (c) != func2_ADD_10 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_11 (c) != func2_ADD_11 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_12 (c) != func2_ADD_12 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_13 (c) != func2_ADD_13 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_14 (c) != func2_ADD_14 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_15 (c) != func2_ADD_15 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_16 (c) != func2_ADD_16 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_17 (c) != func2_ADD_17 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_18 (c) != func2_ADD_18 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_19 (c) != func2_ADD_19 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_20 (c) != func2_ADD_20 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_21 (c) != func2_ADD_21 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_22 (c) != func2_ADD_22 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_23 (c) != func2_ADD_23 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_24 (c) != func2_ADD_24 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_25 (c) != func2_ADD_25 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_26 (c) != func2_ADD_26 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_27 (c) != func2_ADD_27 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_28 (c) != func2_ADD_28 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_29 (c) != func2_ADD_29 (c)) __builtin_exit (__LINE__);
+    if (func1_ADD_30 (c) != func2_ADD_30 (c)) __builtin_exit (__LINE__);
+  } while (++c);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/pr115830-and.c b/gcc/testsuite/gcc.target/avr/pr115830-and.c
new file mode 100644
index 00000000000..317486feb03
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/pr115830-and.c
@@ -0,0 +1,67 @@
+/* { dg-do run } */
+/* { dg-additional-options { -std=c99 -fwrapv -Os } } */
+
+typedef __UINT8_TYPE__ uint8_t;
+typedef __INT8_TYPE__  int8_t;
+
+#define AI static inline __attribute__((always_inline))
+#define NI __attribute__((noinline,noclone,no_icf))
+
+#define TYP int8_t
+
+TYP volatile v;
+
+#define MK_FUN(ID, OP, TST)                     \
+NI TYP func1_##ID (TYP c)                       \
+{                                               \
+  v = 42;                                       \
+  c OP;                                         \
+  if (c TST)                                    \
+    v = c;                                      \
+  return v;                                     \
+}                                               \
+                                                \
+NI TYP func2_##ID (TYP c)                       \
+{                                               \
+  TYP v = 42;                                   \
+  c OP;                                         \
+  __asm ("" : "+r" (c));                        \
+  if (c TST)                                    \
+    v = c;                                      \
+  return v;                                     \
+}
+
+MK_FUN (AND_01, &= 0x80, != 0)
+MK_FUN (AND_02, &= 0x80, == 0)
+MK_FUN (AND_03, &= 0x80, >= 0)
+MK_FUN (AND_04, &= 0x80, <= 0)
+MK_FUN (AND_05, &= 0x80, > 0)
+MK_FUN (AND_06, &= 0x80, < 0)
+MK_FUN (AND_07, &= 0xef, != 0)
+MK_FUN (AND_08, &= 0xef, == 0)
+MK_FUN (AND_09, &= 0xef, >= 0)
+MK_FUN (AND_10, &= 0xef, <= 0)
+MK_FUN (AND_11, &= 0xef, > 0)
+MK_FUN (AND_12, &= 0xef, < 0)
+	
+
+int main (void)
+{
+  uint8_t c = 0;
+  do {
+    if (func1_AND_01 (c) != func2_AND_01 (c)) __builtin_exit (__LINE__);
+    if (func1_AND_02 (c) != func2_AND_02 (c)) __builtin_exit (__LINE__);
+    if (func1_AND_03 (c) != func2_AND_03 (c)) __builtin_exit (__LINE__);
+    if (func1_AND_04 (c) != func2_AND_04 (c)) __builtin_exit (__LINE__);
+    if (func1_AND_05 (c) != func2_AND_05 (c)) __builtin_exit (__LINE__);
+    if (func1_AND_06 (c) != func2_AND_06 (c)) __builtin_exit (__LINE__);
+    if (func1_AND_07 (c) != func2_AND_07 (c)) __builtin_exit (__LINE__);
+    if (func1_AND_08 (c) != func2_AND_08 (c)) __builtin_exit (__LINE__);
+    if (func1_AND_09 (c) != func2_AND_09 (c)) __builtin_exit (__LINE__);
+    if (func1_AND_10 (c) != func2_AND_10 (c)) __builtin_exit (__LINE__);
+    if (func1_AND_11 (c) != func2_AND_11 (c)) __builtin_exit (__LINE__);
+    if (func1_AND_12 (c) != func2_AND_12 (c)) __builtin_exit (__LINE__);
+  } while (++c);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/pr115830-asl.c b/gcc/testsuite/gcc.target/avr/pr115830-asl.c
new file mode 100644
index 00000000000..09a4495caac
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/pr115830-asl.c
@@ -0,0 +1,78 @@
+/* { dg-do run } */
+/* { dg-additional-options { -std=c99 -fwrapv -Os } } */
+
+typedef __UINT8_TYPE__ uint8_t;
+typedef __INT8_TYPE__  int8_t;
+
+#define AI static inline __attribute__((always_inline))
+#define NI __attribute__((noinline,noclone,no_icf))
+
+#define TYP int8_t
+
+TYP volatile v;
+
+#define MK_FUN(ID, OP, TST)                     \
+NI TYP func1_##ID (TYP c)                       \
+{                                               \
+  v = 42;                                       \
+  c OP;                                         \
+  if (c TST)                                    \
+    v = c;                                      \
+  return v;                                     \
+}                                               \
+                                                \
+NI TYP func2_##ID (TYP c)                       \
+{                                               \
+  TYP v = 42;                                   \
+  c OP;                                         \
+  __asm ("" : "+r" (c));                        \
+  if (c TST)                                    \
+    v = c;                                      \
+  return v;                                     \
+}
+
+MK_FUN (ASL_01, <<= 1, != 0)
+MK_FUN (ASL_02, <<= 2, != 0)
+MK_FUN (ASL_03, <<= 3, != 0)
+MK_FUN (ASL_04, <<= 1, == 0)
+MK_FUN (ASL_05, <<= 2, == 0)
+MK_FUN (ASL_06, <<= 3, == 0)
+MK_FUN (ASL_07, <<= 1, >= 0)
+MK_FUN (ASL_08, <<= 2, >= 0)
+MK_FUN (ASL_09, <<= 3, >= 0)
+MK_FUN (ASL_10, <<= 1, <= 0)
+MK_FUN (ASL_11, <<= 2, <= 0)
+MK_FUN (ASL_12, <<= 3, <= 0)
+MK_FUN (ASL_13, <<= 1, > 0)
+MK_FUN (ASL_14, <<= 2, > 0)
+MK_FUN (ASL_15, <<= 3, > 0)
+MK_FUN (ASL_16, <<= 1, < 0)
+MK_FUN (ASL_17, <<= 2, < 0)
+MK_FUN (ASL_18, <<= 3, < 0)
+
+int main (void)
+{
+  uint8_t c = 0;
+  do {
+    if (func1_ASL_01 (c) != func2_ASL_01 (c)) __builtin_exit (__LINE__);
+    if (func1_ASL_02 (c) != func2_ASL_02 (c)) __builtin_exit (__LINE__);
+    if (func1_ASL_03 (c) != func2_ASL_03 (c)) __builtin_exit (__LINE__);
+    if (func1_ASL_04 (c) != func2_ASL_04 (c)) __builtin_exit (__LINE__);
+    if (func1_ASL_05 (c) != func2_ASL_05 (c)) __builtin_exit (__LINE__);
+    if (func1_ASL_06 (c) != func2_ASL_06 (c)) __builtin_exit (__LINE__);
+    if (func1_ASL_07 (c) != func2_ASL_07 (c)) __builtin_exit (__LINE__);
+    if (func1_ASL_08 (c) != func2_ASL_08 (c)) __builtin_exit (__LINE__);
+    if (func1_ASL_09 (c) != func2_ASL_09 (c)) __builtin_exit (__LINE__);
+    if (func1_ASL_10 (c) != func2_ASL_10 (c)) __builtin_exit (__LINE__);
+    if (func1_ASL_11 (c) != func2_ASL_11 (c)) __builtin_exit (__LINE__);
+    if (func1_ASL_12 (c) != func2_ASL_12 (c)) __builtin_exit (__LINE__);
+    if (func1_ASL_13 (c) != func2_ASL_13 (c)) __builtin_exit (__LINE__);
+    if (func1_ASL_14 (c) != func2_ASL_14 (c)) __builtin_exit (__LINE__);
+    if (func1_ASL_15 (c) != func2_ASL_15 (c)) __builtin_exit (__LINE__);
+    if (func1_ASL_16 (c) != func2_ASL_16 (c)) __builtin_exit (__LINE__);
+    if (func1_ASL_17 (c) != func2_ASL_17 (c)) __builtin_exit (__LINE__);
+    if (func1_ASL_18 (c) != func2_ASL_18 (c)) __builtin_exit (__LINE__);
+  } while (++c);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/pr115830-asl32.c b/gcc/testsuite/gcc.target/avr/pr115830-asl32.c
new file mode 100644
index 00000000000..6e8100f5f58
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/pr115830-asl32.c
@@ -0,0 +1,57 @@
+/* { dg-do run } */
+/* { dg-additional-options { -std=c99 -fwrapv -Os } } */
+
+typedef __UINT32_TYPE__ uint32_t;
+typedef __INT32_TYPE__  int32_t;
+
+#define AI static inline __attribute__((always_inline))
+#define NI __attribute__((noinline,noclone,no_icf))
+
+#define TYP int32_t
+
+TYP volatile v;
+
+#define MK_FUN(ID, OP, TST)                     \
+NI TYP func1_##ID (TYP c)                       \
+{                                               \
+  v = 0x77665544;                               \
+  c OP;                                         \
+  if (c TST)                                    \
+    v = c;                                      \
+  return v;                                     \
+}                                               \
+                                                \
+NI TYP func2_##ID (TYP c)                       \
+{                                               \
+  TYP v = 0x77665544;                           \
+  c OP;                                         \
+  __asm ("" : "+r" (c));                        \
+  if (c TST)                                    \
+    v = c;                                      \
+  return v;                                     \
+}
+
+MK_FUN (ASL_03, <<= 1, >= 0)
+MK_FUN (ASL_06, <<= 1, < 0)
+
+NI void test_asl (uint32_t c)
+{
+    if (func1_ASL_03 (c) != func2_ASL_03 (c)) __builtin_exit (__LINE__);
+    if (func1_ASL_06 (c) != func2_ASL_06 (c)) __builtin_exit (__LINE__);
+}
+
+int main (void)
+{
+  test_asl (0);
+  test_asl (0x80000000);
+  test_asl (0x80000001);
+  test_asl (0xc0000000);
+  test_asl (0xc0000001);
+  test_asl (0);
+  test_asl (0xff00ff00);
+  test_asl (0x00ff00ff);
+  test_asl (0xff00ff00 >> 1);
+  test_asl (0x00ff00ff >> 1);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/pr115830-asr.c b/gcc/testsuite/gcc.target/avr/pr115830-asr.c
new file mode 100644
index 00000000000..1ceafb9a537
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/pr115830-asr.c
@@ -0,0 +1,78 @@
+/* { dg-do run } */
+/* { dg-additional-options { -std=c99 -fwrapv -Os } } */
+
+typedef __UINT8_TYPE__ uint8_t;
+typedef __INT8_TYPE__  int8_t;
+
+#define AI static inline __attribute__((always_inline))
+#define NI __attribute__((noinline,noclone,no_icf))
+
+#define TYP int8_t
+
+TYP volatile v;
+
+#define MK_FUN(ID, OP, TST)                     \
+NI TYP func1_##ID (TYP c)                       \
+{                                               \
+  v = 42;                                       \
+  c OP;                                         \
+  if (c TST)                                    \
+    v = c;                                      \
+  return v;                                     \
+}                                               \
+                                                \
+NI TYP func2_##ID (TYP c)                       \
+{                                               \
+  TYP v = 42;                                   \
+  c OP;                                         \
+  __asm ("" : "+r" (c));                        \
+  if (c TST)                                    \
+    v = c;                                      \
+  return v;                                     \
+}
+
+MK_FUN (ASR_01, >>= 1, != 0)
+MK_FUN (ASR_02, >>= 2, != 0)
+MK_FUN (ASR_03, >>= 3, != 0)
+MK_FUN (ASR_04, >>= 1, == 0)
+MK_FUN (ASR_05, >>= 2, == 0)
+MK_FUN (ASR_06, >>= 3, == 0)
+MK_FUN (ASR_07, >>= 1, >= 0)
+MK_FUN (ASR_08, >>= 2, >= 0)
+MK_FUN (ASR_09, >>= 3, >= 0)
+MK_FUN (ASR_10, >>= 1, <= 0)
+MK_FUN (ASR_11, >>= 2, <= 0)
+MK_FUN (ASR_12, >>= 3, <= 0)
+MK_FUN (ASR_13, >>= 1, > 0)
+MK_FUN (ASR_14, >>= 2, > 0)
+MK_FUN (ASR_15, >>= 3, > 0)
+MK_FUN (ASR_16, >>= 1, < 0)
+MK_FUN (ASR_17, >>= 2, < 0)
+MK_FUN (ASR_18, >>= 3, < 0)
+
+int main (void)
+{
+  uint8_t c = 0;
+  do {
+    if (func1_ASR_01 (c) != func2_ASR_01 (c)) __builtin_exit (__LINE__);
+    if (func1_ASR_02 (c) != func2_ASR_02 (c)) __builtin_exit (__LINE__);
+    if (func1_ASR_03 (c) != func2_ASR_03 (c)) __builtin_exit (__LINE__);
+    if (func1_ASR_04 (c) != func2_ASR_04 (c)) __builtin_exit (__LINE__);
+    if (func1_ASR_05 (c) != func2_ASR_05 (c)) __builtin_exit (__LINE__);
+    if (func1_ASR_06 (c) != func2_ASR_06 (c)) __builtin_exit (__LINE__);
+    if (func1_ASR_07 (c) != func2_ASR_07 (c)) __builtin_exit (__LINE__);
+    if (func1_ASR_08 (c) != func2_ASR_08 (c)) __builtin_exit (__LINE__);
+    if (func1_ASR_09 (c) != func2_ASR_09 (c)) __builtin_exit (__LINE__);
+    if (func1_ASR_10 (c) != func2_ASR_10 (c)) __builtin_exit (__LINE__);
+    if (func1_ASR_11 (c) != func2_ASR_11 (c)) __builtin_exit (__LINE__);
+    if (func1_ASR_12 (c) != func2_ASR_12 (c)) __builtin_exit (__LINE__);
+    if (func1_ASR_13 (c) != func2_ASR_13 (c)) __builtin_exit (__LINE__);
+    if (func1_ASR_14 (c) != func2_ASR_14 (c)) __builtin_exit (__LINE__);
+    if (func1_ASR_15 (c) != func2_ASR_15 (c)) __builtin_exit (__LINE__);
+    if (func1_ASR_16 (c) != func2_ASR_16 (c)) __builtin_exit (__LINE__);
+    if (func1_ASR_17 (c) != func2_ASR_17 (c)) __builtin_exit (__LINE__);
+    if (func1_ASR_18 (c) != func2_ASR_18 (c)) __builtin_exit (__LINE__);
+  } while (++c);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/pr115830-ior.c b/gcc/testsuite/gcc.target/avr/pr115830-ior.c
new file mode 100644
index 00000000000..51451b4f32f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/pr115830-ior.c
@@ -0,0 +1,67 @@
+/* { dg-do run } */
+/* { dg-additional-options { -std=c99 -fwrapv -Os } } */
+
+typedef __UINT8_TYPE__ uint8_t;
+typedef __INT8_TYPE__  int8_t;
+
+#define AI static inline __attribute__((always_inline))
+#define NI __attribute__((noinline,noclone,no_icf))
+
+#define TYP int8_t
+
+TYP volatile v;
+
+#define MK_FUN(ID, OP, TST)                     \
+NI TYP func1_##ID (TYP c)                       \
+{                                               \
+  v = 42;                                       \
+  c OP;                                         \
+  if (c TST)                                    \
+    v = c;                                      \
+  return v;                                     \
+}                                               \
+                                                \
+NI TYP func2_##ID (TYP c)                       \
+{                                               \
+  TYP v = 42;                                   \
+  c OP;                                         \
+  __asm ("" : "+r" (c));                        \
+  if (c TST)                                    \
+    v = c;                                      \
+  return v;                                     \
+}
+
+MK_FUN (IOR_01, &= 0x8, != 0)
+MK_FUN (IOR_02, &= 0x8, == 0)
+MK_FUN (IOR_03, &= 0x8, >= 0)
+MK_FUN (IOR_04, &= 0x8, <= 0)
+MK_FUN (IOR_05, &= 0x8, > 0)
+MK_FUN (IOR_06, &= 0x8, < 0)
+MK_FUN (IOR_07, &= 0x7f, != 0)
+MK_FUN (IOR_08, &= 0x7f, == 0)
+MK_FUN (IOR_09, &= 0x7f, >= 0)
+MK_FUN (IOR_10, &= 0x7f, <= 0)
+MK_FUN (IOR_11, &= 0x7f, > 0)
+MK_FUN (IOR_12, &= 0x7f, < 0)
+	
+
+int main (void)
+{
+  uint8_t c = 0;
+  do {
+    if (func1_IOR_01 (c) != func2_IOR_01 (c)) __builtin_exit (__LINE__);
+    if (func1_IOR_02 (c) != func2_IOR_02 (c)) __builtin_exit (__LINE__);
+    if (func1_IOR_03 (c) != func2_IOR_03 (c)) __builtin_exit (__LINE__);
+    if (func1_IOR_04 (c) != func2_IOR_04 (c)) __builtin_exit (__LINE__);
+    if (func1_IOR_05 (c) != func2_IOR_05 (c)) __builtin_exit (__LINE__);
+    if (func1_IOR_06 (c) != func2_IOR_06 (c)) __builtin_exit (__LINE__);
+    if (func1_IOR_07 (c) != func2_IOR_07 (c)) __builtin_exit (__LINE__);
+    if (func1_IOR_08 (c) != func2_IOR_08 (c)) __builtin_exit (__LINE__);
+    if (func1_IOR_09 (c) != func2_IOR_09 (c)) __builtin_exit (__LINE__);
+    if (func1_IOR_10 (c) != func2_IOR_10 (c)) __builtin_exit (__LINE__);
+    if (func1_IOR_11 (c) != func2_IOR_11 (c)) __builtin_exit (__LINE__);
+    if (func1_IOR_12 (c) != func2_IOR_12 (c)) __builtin_exit (__LINE__);
+  } while (++c);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/pr115830-lsr.c b/gcc/testsuite/gcc.target/avr/pr115830-lsr.c
new file mode 100644
index 00000000000..1e027154c73
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/pr115830-lsr.c
@@ -0,0 +1,60 @@
+/* { dg-do run } */
+/* { dg-additional-options { -std=c99 -fwrapv -Os } } */
+
+typedef __UINT8_TYPE__ uint8_t;
+typedef __INT8_TYPE__  int8_t;
+
+#define AI static inline __attribute__((always_inline))
+#define NI __attribute__((noinline,noclone,no_icf))
+
+#define TYP uint8_t
+
+TYP volatile v;
+
+#define MK_FUN(ID, OP, TST)                     \
+NI TYP func1_##ID (TYP c)                       \
+{                                               \
+  v = 42;                                       \
+  c OP;                                         \
+  if (c TST)                                    \
+    v = c;                                      \
+  return v;                                     \
+}                                               \
+                                                \
+NI TYP func2_##ID (TYP c)                       \
+{                                               \
+  TYP v = 42;                                   \
+  c OP;                                         \
+  __asm ("" : "+r" (c));                        \
+  if (c TST)                                    \
+    v = c;                                      \
+  return v;                                     \
+}
+
+MK_FUN (LSR_01, >>= 1, != 0)
+MK_FUN (LSR_02, >>= 2, != 0)
+MK_FUN (LSR_03, >>= 3, != 0)
+MK_FUN (LSR_04, >>= 1, == 0)
+MK_FUN (LSR_05, >>= 2, == 0)
+MK_FUN (LSR_06, >>= 3, == 0)
+MK_FUN (LSR_13, >>= 1, > 0)
+MK_FUN (LSR_14, >>= 2, > 0)
+MK_FUN (LSR_15, >>= 3, > 0)
+
+int main (void)
+{
+  uint8_t c = 0;
+  do {
+    if (func1_LSR_01 (c) != func2_LSR_01 (c)) __builtin_exit (__LINE__);
+    if (func1_LSR_02 (c) != func2_LSR_02 (c)) __builtin_exit (__LINE__);
+    if (func1_LSR_03 (c) != func2_LSR_03 (c)) __builtin_exit (__LINE__);
+    if (func1_LSR_04 (c) != func2_LSR_04 (c)) __builtin_exit (__LINE__);
+    if (func1_LSR_05 (c) != func2_LSR_05 (c)) __builtin_exit (__LINE__);
+    if (func1_LSR_06 (c) != func2_LSR_06 (c)) __builtin_exit (__LINE__);
+    if (func1_LSR_13 (c) != func2_LSR_13 (c)) __builtin_exit (__LINE__);
+    if (func1_LSR_14 (c) != func2_LSR_14 (c)) __builtin_exit (__LINE__);
+    if (func1_LSR_15 (c) != func2_LSR_15 (c)) __builtin_exit (__LINE__);
+  } while (++c);
+
+  return 0;
+}
