diff --git a/gcc/config/avr/avr-modes.def b/gcc/config/avr/avr-modes.def
index e0633d680d5..b756beae9a0 100644
--- a/gcc/config/avr/avr-modes.def
+++ b/gcc/config/avr/avr-modes.def
@@ -18,6 +18,12 @@
 
 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.
+   The Z flag indicates  whether the value is zero.  */
+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 7b666f17718..fb7e0dc6a15 100644
--- a/gcc/config/avr/avr-protos.h
+++ b/gcc/config/avr/avr-protos.h
@@ -55,7 +55,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 *avr_cond_branch (rtx_insn *, rtx *);
 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*);
@@ -63,6 +63,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);
@@ -154,6 +158,8 @@ extern rtx zero_reg_rtx;
 extern rtx all_regs_rtx[32];
 extern rtx rampz_rtx;
 extern rtx cc_reg_rtx;
+extern rtx ccn_reg_rtx;
+extern rtx cczn_reg_rtx;
 
 #endif /* RTX_CODE */
 
diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index 7229aac747b..0ec3e4103ec 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);
@@ -196,7 +196,11 @@ rtx zero_reg_rtx;
 
 /* Condition Code register RTX (reg:CC REG_CC) */
 extern GTY(()) rtx cc_reg_rtx;
+extern GTY(()) rtx ccn_reg_rtx;
+extern GTY(()) rtx cczn_reg_rtx;
 rtx cc_reg_rtx;
+rtx ccn_reg_rtx;
+rtx cczn_reg_rtx;
 
 /* RTXs for all general purpose registers as QImode */
 extern GTY(()) rtx all_regs_rtx[REG_32];
@@ -1185,6 +1189,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.  */
@@ -1209,7 +1225,9 @@ avr_init_expanders (void)
   tmp_reg_rtx  = all_regs_rtx[AVR_TMP_REGNO];
   zero_reg_rtx = all_regs_rtx[AVR_ZERO_REGNO];
 
-  cc_reg_rtx  = gen_rtx_REG (CCmode, REG_CC);
+  cc_reg_rtx = gen_rtx_REG (CCmode, REG_CC);
+  ccn_reg_rtx = gen_rtx_REG (CCNmode, REG_CC);
+  cczn_reg_rtx = gen_rtx_REG (CCZNmode, REG_CC);
 
   lpm_addr_reg_rtx = gen_rtx_REG (HImode, REG_Z);
 
@@ -3756,14 +3774,13 @@ ptrreg_to_str (int regno)
   return NULL;
 }
 
-/* Return the condition name as a string.
-   Used in conditional jump constructing  */
+
+/* Return the condition name as a string to be used in a BR** instruction.
+   Used in conditional jump constructing.  */
 
 static const char *
-cond_string (enum rtx_code code)
+avr_cond_string (rtx_code code, bool cc_overflow_unusable)
 {
-  bool cc_overflow_unusable = false;
-
   switch (code)
     {
     case NE:
@@ -4092,10 +4109,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 (avr_cond_string (GET_CODE (x), code == 'L'), file);
+  else if (code == 'k' || code == 'K')
+    fputs (avr_cond_string (reverse_condition (GET_CODE (x)), code == 'K'),
+	   file);
   else
     avr_print_operand_address (file, VOIDmode, x);
 }
@@ -4144,14 +4162,24 @@ 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.  */
+   LEN in { 1, 2, 3 } is a number returned by `avr_jump_mode()'.
+   CCMODE is the mode of the comparison in { CCmode, CCNmode, CCZNmode }.  */
+
+/* Return the asm code for a conditional branch where XOP[0] is the
+   label and XOP[1] is a comparison operator of REG_CC against 0.
+*/
 
 const char *
-ret_cond_branch (rtx x, int len, int reverse)
+avr_cond_branch (rtx_insn *insn, rtx *xop)
 {
-  RTX_CODE cond = reverse ? reverse_condition (GET_CODE (x)) : GET_CODE (x);
-  bool cc_overflow_unusable = false;
+  machine_mode ccmode = GET_MODE (XEXP (xop[1], 0));
+  rtx_code cond = GET_CODE (xop[1]);
+  bool cc_overflow_unusable = ccmode != CCmode;
+  int len = avr_jump_mode (xop[0], insn);
+
+  if (ccmode == CCNmode)
+    // The N flag can only do < 0 and >= 0.
+    gcc_assert (cond == GE || cond == LT);
 
   switch (cond)
     {
@@ -4213,33 +4241,20 @@ ret_cond_branch (rtx x, int len, int reverse)
 	       "brsh .+4" CR_TAB
 	       "jmp %0"));
     default:
-      if (reverse)
-	{
-	  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)
 	{
-	  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 "";
@@ -8980,6 +8995,34 @@ lshrsi3_out (rtx_insn *insn, rtx operands[], int *len)
 }
 
 
+/* When INSN is a PARALLEL with two SETs, a SET of REG_CC and a SET of a
+   GPR, then return the second SET and set *CCMODE to the first SET's mode.
+   Otherwise, return single_set and set *CCMODE to VOIDmode.  */
+
+static rtx
+avr_cc_set (rtx_insn *insn, machine_mode *ccmode)
+{
+  // single_set() not only depends on the anatomy of an insn but also
+  // on REG_UNUSED notes, thus we have to analyze by hand so that the
+  // result only depends on the pattern.
+
+  rtx pat = PATTERN (insn);
+
+  if (GET_CODE (pat) == PARALLEL
+      && XVECLEN (pat, 0) == 2
+      && GET_CODE (XVECEXP (pat, 0, 0)) == SET
+      && GET_CODE (XVECEXP (pat, 0, 1)) == SET)
+    {
+      rtx ccset = XVECEXP (pat, 0, 0);
+      *ccmode = GET_MODE (SET_DEST (ccset));
+      return XVECEXP (pat, 0, 1);
+    }
+
+  *ccmode = VOIDmode;
+  return single_set (insn);
+}
+
+
 /* Output addition of registers YOP[0] and YOP[1]
 
       YOP[0] += extend (YOP[1])
@@ -8988,8 +9031,11 @@ lshrsi3_out (rtx_insn *insn, rtx operands[], int *len)
 
       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 "".
+   where the integer modes satisfy  SI >= YOP[0].mode >= YOP[1/2].mode >= QI,
+   and the extension may be sign-extend, zero-extend or reg (no extend).
+   INSN is either a single_set or a true parallel insn.  In the latter case,
+   INSN has two SETs: A SET of REG_CC and a SET like in the single_set case.
+   Returns "".
 
    If PLEN == NULL output the instructions.
    If PLEN != NULL set *PLEN to the length of the sequence in words.  */
@@ -8998,8 +9044,13 @@ const char *
 avr_out_plus_ext (rtx_insn *insn, rtx *yop, int *plen)
 {
   rtx regs[2];
+  machine_mode ccmode;
 
-  const rtx src = SET_SRC (single_set (insn));
+  /* Ouch! Whether or not an insn is a single_set does not only depend
+     on the anatomy of the pattern, but also on REG_UNUSED notes.
+     Hence we have to dig by hand... */
+
+  const rtx src = SET_SRC (avr_cc_set (insn, &ccmode));
   const RTX_CODE add = GET_CODE (src);
   gcc_assert (GET_CODE (src) == PLUS || GET_CODE (src) == MINUS);
 
@@ -9010,7 +9061,7 @@ avr_out_plus_ext (rtx_insn *insn, rtx *yop, int *plen)
   const RTX_CODE ext = GET_CODE (xext);
 
   gcc_assert (REG_P (xreg)
-	      && (ext == ZERO_EXTEND || ext == SIGN_EXTEND));
+	      && (ext == ZERO_EXTEND || ext == SIGN_EXTEND || ext == REG));
 
   const int n_bytes0 = GET_MODE_SIZE (GET_MODE (xop[0]));
   const int n_bytes1 = GET_MODE_SIZE (GET_MODE (xop[1]));
@@ -9030,7 +9081,9 @@ avr_out_plus_ext (rtx_insn *insn, rtx *yop, int *plen)
 
   if (ext == SIGN_EXTEND
       && (n_bytes0 > 1 + n_bytes1
-	  || reg_overlap_mentioned_p (msb1, xop[0])))
+	  || reg_overlap_mentioned_p (msb1, xop[0])
+	  // The insn also wants to set SREG.N and SREG.Z.
+	  || ccmode == CCZNmode))
     {
       // Sign-extending more than one byte: Set tmp_reg to 0 or -1
       // depending on $1.msb. Same for the pathological case where
@@ -9688,10 +9741,51 @@ 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 HI, PSI or SI register, and XOP[1] is a register or 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);
+
+  // 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] };
+
+  if (REG_P (xop[1]))
+    {
+      avr_out_plus_1 (NULL_RTX, op, plen, PLUS, UNKNOWN, 0, false);
+    }
+  else
+    {
+      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,
-   then the addition can be performed without a clobber reg.  Return "".
+   result.  The mode is HI, PSI or SI.  XOP[2] might be a d-regs clobber
+   register.  If XOP[2] is SCRATCH, then the addition can be performed
+   without a clobber reg.  Return "".
 
    If PLEN == NULL, then output the instructions.
    If PLEN != NULL, then set *PLEN to the length of the sequence in words. */
@@ -9711,15 +9805,6 @@ 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 (INTVAL (xval) == 1)
-	return avr_asm_len ("inc %0", xop, plen, 1);
-
-      if (INTVAL (xval) == -1)
-	return avr_asm_len ("dec %0", xop, plen, 1);
-    }
-
   if (n_bytes == 2
       && avr_adiw_reg_p (xreg)
       && IN_RANGE (INTVAL (xval), 1, 63))
@@ -9804,6 +9889,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 = std::abs (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]:
 
@@ -11308,6 +11523,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;
 
@@ -11496,7 +11712,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);
@@ -14110,7 +14326,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);
@@ -14125,7 +14341,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 fce5349bbe5..1fad2193c9a 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"))
 
@@ -261,6 +261,7 @@ (define_mode_iterator QISI  [QI HI PSI SI])
 (define_mode_iterator QIDI  [QI HI PSI SI DI])
 (define_mode_iterator QIPSI [QI HI PSI])
 (define_mode_iterator HISI  [HI PSI SI])
+(define_mode_iterator HI_SI [HI SI])
 
 ;; Ordered integral and fixed-point modes of specific sizes.
 (define_mode_iterator ALL1 [QI QQ UQQ])
@@ -277,6 +278,10 @@ (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_attr CCname [(CC "") (CCN "_N") (CCZN "_ZN")])
+
 ;; All supported move-modes
 (define_mode_iterator MOVMODE [QI QQ UQQ
                                HI HQ UHQ HA UHA
@@ -320,6 +325,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])
@@ -6885,6 +6893,469 @@ (define_insn_and_split "*cbranch<HISI:mode>.<code><QIPSI:mode>.0"
   })
 
 
+;; Try optimize decrement-and-branch.  When we have an addition followed
+;; 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.
+;; The comparisons are split2 from their cbranch insns and before
+;; peephole2 patterns like for swapped_tst and sbrx_branch have been applied.
+
+;; We do NOT use cmpelim / SELECT_CC_MODE because it has many shortcomings
+;; and is by no means equipollent to the removed cc0 framework -- at least
+;; with regard to the avr backend:  Whether or not the result of a comparison
+;; can be obtained as a byproduct of an operation might depend on the
+;; availability of a scratch register:  There are cases where we need a
+;; scratch register to optimize away a comparison, and where the operation
+;; without a comparison does not require a scratch.  With the peep2 approach
+;; below, we can get a scratch from the peep2 framework without increasing
+;; the register pressure, whereas cmpelim doesn't offer such a feature.
+;;    When no scratch is available, then we just don't perform the optimizaton,
+;; i.e. the comparison against 0 won't be optimized away, which is preferred
+;; over increasing the register pressure -- in many cases without reason --
+;; which might result in additional spills.
+;;    What we definitely do not want is to pop a scratch without need, and
+;; in some arithmetic insn we won't know whether it might also be considered
+;; for CCmode generation, at least not prior to register allocation:
+;; CCmode only comes into existence after register allocation.
+;;    cmpelim has more shortcomings, for example some comparisons may not
+;; be available, and it does not handle several of the forms supported below,
+;; just to mention two.  A solution for the former would be to return VOIDmode
+;; in SELECT_CC_MODE, but cmpelim doesn't handle that.  Anyway, it's pointless
+;; to speculate about how other shortcomings could be fixed when the scratch
+;; problem is unsoved in cmpelim.
+;;    Apart from that, compare-elim.cc lists some demands that are not
+;; compatible with this bachend.  For example, it assumes that when an insn
+;; can set the condition code, it is always of the form compare:CCM, i.e.
+;; all comparisons are supported.  This is not the case for AVR, see the
+;; peep2 conditions below.  There is no way (at least not a documented one)
+;; to express that in SELECT_CC_MODE.
+;;    Apart from that passes running before register allocation (and thus
+;; before split2) have #ifdef SELECT_CC_MODE, and nowhere there is an
+;; explanation on how to handle that.
+;;    Skipping cmpelim is accomplished by not defining TARGET_FLAGS_REGNUM.
+
+;; Note: reload1.cc::do_output_reload() does not support output reloads
+;; for JUMP_INSNs, hence letting combine doing decrement-and-branch might
+;; run into an ICE.  Doing reloads by hand is too painful, hence, stick with
+;; RTL peepholes for now.
+
+(define_expand "gen_add_for_<code>_<mode>"
+  [;; "*add.for.cczn.<mode>"
+   (parallel [(set (reg:CCZN REG_CC)
+                   (compare:CCZN (plus:HISI (match_operand:HISI 0 "register_operand")
+                                            (match_operand:HISI 1 "const_int_operand"))
+                                 (const_int 0)))
+              (set (match_dup 0)
+                   (plus:HISI (match_dup 0)
+                              (match_dup 1)))
+              (clobber (match_operand:QI 3))])
+   ;; "branch_ZN"
+   (set (pc)
+        (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:HISI (match_operand:HISI 0 "register_operand")
+                                           (match_operand:HISI 1 "nonmemory_operand"))
+                                (const_int 0)))
+              (set (match_dup 0)
+                   (plus:HISI (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: Additions without a scratch register.
+(define_peephole2
+  [(parallel [(set (match_operand:HISI 0 "register_operand")
+                   (plus:HISI (match_dup 0)
+                              (match_operand:HISI 1 "nonmemory_operand")))
+              (clobber (reg:CC REG_CC))])
+   (parallel [(set (reg:CC REG_CC)
+                   (compare:CC (match_dup 0)
+                               (match_operand:HISI 3 "const0_operand")))
+              (clobber (scratch:QI))])
+   (set (pc)
+        (if_then_else (cmp_signed (reg:CC REG_CC)
+                                  (const_int 0))
+                      (label_ref (match_operand 2))
+                      (pc)))]
+  "// Multi-byte reg-reg additions only set the N flag.
+   (<CODE> == GE || <CODE> == LT || ! REG_P (operands[1]))
+   // Needs a const or a d-reg.
+   && (REG_P (operands[1]) || d_register_operand (operands[0], <MODE>mode))
+   && peep2_regno_dead_p (3, REG_CC)"
+  [(scratch)]
+  {
+    emit (gen_gen_add_for_<code>_<mode> (operands[0], operands[1], operands[2],
+                                         gen_rtx_SCRATCH (QImode)));
+    DONE;
+  })
+
+;; 2/3: Additions with a scratch register from the insn.
+(define_peephole2
+  [(parallel [(set (match_operand:HISI 0 "register_operand")
+                   (plus:HISI (match_dup 0)
+                              (match_operand:HISI 1 "nonmemory_operand")))
+              (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)
+                               (match_operand:HISI 4 "const0_operand")))
+              (clobber (scratch:QI))])
+   (set (pc)
+        (if_then_else (cmp_signed (reg:CC REG_CC)
+                                  (const_int 0))
+                      (label_ref (match_operand 2))
+                      (pc)))]
+  "// Multi-byte reg-reg additions only set the N flag.
+   (<CODE> == GE || <CODE> == LT || ! REG_P (operands[1]))
+   && peep2_regno_dead_p (3, REG_CC)"
+  [(scratch)]
+  {
+    rtx scratch = operands[3];
+
+    // We need either a d-register or a scratch register
+    // when $1 is not a register.
+    if (! REG_P (operands[1])
+        && ! REG_P (scratch)
+        && ! d_register_operand (operands[0], <MODE>mode))
+      FAIL;
+
+    emit (gen_gen_add_for_<code>_<mode> (operands[0], operands[1], operands[2],
+                                         scratch));
+    DONE;
+  })
+
+;; 3/3: Additions with a scratch register from peephole2.
+(define_peephole2
+  [(match_scratch:QI 3 "d")
+   (parallel [(set (match_operand:HISI 0 "register_operand")
+                   (plus:HISI (match_dup 0)
+                              (match_operand:HISI 1 "const_int_operand")))
+              (clobber (reg:CC REG_CC))])
+   (parallel [(set (reg:CC REG_CC)
+                   (compare:CC (match_dup 0)
+                               (match_operand:HISI 4 "const0_operand")))
+              (clobber (scratch:QI))])
+   (set (pc)
+        (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]));
+    DONE;
+  })
+
+;; Result of the above three peepholes is an addition that also
+;; 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".
+
+;; "*add.for.cczn.hi"  "*add.for.cczn.psi"  "*add.for.cczn.si"
+(define_insn "*add.for.cczn.<mode>"
+  [(set (reg:CCZN REG_CC)
+        (compare:CCZN
+         (plus:HISI (match_operand:HISI 3 "register_operand"  "0 ,0")
+                    (match_operand:HISI 1 "const_int_operand" "n ,n"))
+         (const_int 0)))
+   (set (match_operand:HISI 0 "register_operand"             "=d ,r")
+        (plus:HISI (match_operand:HISI 4 "register_operand"   "0 ,0")
+                   (match_operand:HISI 5 "const_int_operand"  "1 ,1")))
+   (clobber (match_scratch:QI 2                              "=X ,&d"))]
+  "reload_completed"
+  {
+    return avr_out_plus_set_ZN (operands, nullptr);
+  }
+  [(set (attr "length")
+        (symbol_ref "<SIZE> * (1 + REG_P (operands[2]))"))
+   (set_attr "adjust_len" "add_set_ZN")])
+
+;; "*add.for.ccn.hi"  "*add.for.ccn.psi"  "*add.for.ccn.si"
+(define_insn "*add.for.ccn.<mode>"
+  [(set (reg:CCN REG_CC)
+        (compare:CCN
+         (plus:HISI (match_operand:HISI 3 "register_operand"  "0 ,0 ,0")
+                    (match_operand:HISI 1 "nonmemory_operand" "n ,n ,r"))
+         (const_int 0)))
+   (set (match_operand:HISI 0 "register_operand"             "=d ,r ,r")
+        (plus:HISI (match_operand:HISI 4 "register_operand"   "0 ,0 ,0")
+                   (match_operand:HISI 5 "nonmemory_operand"  "1 ,1 ,1")))
+   (clobber (match_scratch:QI 2                              "=X ,&d,X"))]
+  "reload_completed"
+  {
+    return avr_out_plus_set_N (operands, nullptr);
+  }
+  [(set (attr "length")
+        (symbol_ref "<SIZE> * (1 + REG_P (operands[2]))"))
+   (set_attr "adjust_len" "add_set_N")])
+
+
+;; 1/3: Subtractions with REG subtrahend set Z and N in a meaningful way.
+;; The QI and PSI cases are handled below because they don't have a scratch:QI.
+(define_peephole2
+  [(parallel [(set (match_operand:HI_SI 0 "register_operand")
+                   (minus:HI_SI (match_dup 0)
+                                (match_operand:HI_SI 1 "register_operand")))
+              (clobber (scratch:QI))
+              (clobber (reg:CC REG_CC))])
+   (parallel [(set (reg:CC REG_CC)
+                   (compare:CC (match_dup 0)
+                               (match_operand:HI_SI 3 "const0_operand")))
+              (clobber (scratch:QI))])
+   (set (pc)
+        (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)"
+  [;; "*sub.for.cczn.<mode>"
+   (parallel [(set (reg:CCZN REG_CC)
+                   (compare:CCZN (minus:HI_SI (match_dup 0)
+                                              (match_dup 1))
+                                 (const_int 0)))
+              (set (match_dup 0)
+                   (minus:HI_SI (match_dup 0)
+                                (match_dup 1)))])
+   ;; "branch_ZN"
+   (set (pc)
+        (if_then_else (cmp_signed (reg:CCZN REG_CC)
+                                  (const_int 0))
+                      (label_ref (match_dup 2))
+                      (pc)))])
+
+;; 2/3: Subtractions with a PSImode REG: no scratch:QI.
+(define_peephole2
+  [(parallel [(set (match_operand:PSI 0 "register_operand")
+                   (minus:PSI (match_dup 0)
+                              (match_operand:PSI 1 "register_operand")))
+              (clobber (reg:CC REG_CC))])
+   (parallel [(set (reg:CC REG_CC)
+                   (compare:CC (match_dup 0)
+                               (match_operand:PSI 3 "const0_operand")))
+              (clobber (scratch:QI))])
+   (set (pc)
+        (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)"
+  [;; "*sub.for.cczn.psi"
+   (parallel [(set (reg:CCZN REG_CC)
+                   (compare:CCZN (minus:PSI (match_dup 0)
+                                            (match_dup 1))
+                                 (const_int 0)))
+              (set (match_dup 0)
+                   (minus:PSI (match_dup 0)
+                              (match_dup 1)))])
+   ;; "branch_ZN"
+   (set (pc)
+        (if_then_else (cmp_signed (reg:CCZN REG_CC)
+                                  (const_int 0))
+                      (label_ref (match_dup 2))
+                      (pc)))])
+
+;; 3/3: Subtractions that extend the subtrahend.
+(define_peephole2
+  [(parallel [(set (match_operand:HISI 0 "register_operand")
+                   (minus:HISI (match_dup 0)
+                               (any_extend:HISI (match_operand:QIPSI 1 "register_operand"))))
+              (clobber (reg:CC REG_CC))])
+   (parallel [(set (reg:CC REG_CC)
+                   (compare:CC (match_dup 0)
+                               (match_operand:HISI 3 "const0_operand")))
+              (clobber (scratch:QI))])
+   (set (pc)
+        (if_then_else (cmp_signed (reg:CC REG_CC)
+                                  (const_int 0))
+                      (label_ref (match_operand 2))
+                      (pc)))]
+  "<HISI:SIZE> > <QIPSI:SIZE>
+   && peep2_regno_dead_p (3, REG_CC)"
+  [;; "*sub-extend<QIPSI:mode>.for.cczn.<HISI:mode>"
+   (parallel [(set (reg:CCZN REG_CC)
+                   (compare:CCZN (minus:HISI (match_dup 0)
+                                             (any_extend:HISI (match_dup 1)))
+                                 (const_int 0)))
+              (set (match_dup 0)
+                   (minus:HISI (match_dup 0)
+                               (any_extend:HISI (match_dup 1))))])
+   ;; "branch_ZN"
+   (set (pc)
+        (if_then_else (cmp_signed (reg:CCZN REG_CC)
+                                  (const_int 0))
+                      (label_ref (match_dup 2))
+                      (pc)))])
+
+;; "*sub.for.cczn.hi"
+;; "*sub.for.cczn.psi"
+;; "*sub.for.cczn.si"
+(define_insn "*sub.for.cczn.<mode>"
+  [(set (reg:CCZN REG_CC)
+        (compare:CCZN (minus:HISI (match_operand:HISI 3 "register_operand" "1")
+                                  (match_operand:HISI 4 "register_operand" "2"))
+                      (const_int 0)))
+   (set (match_operand:HISI 0 "register_operand"             "=r")
+        (minus:HISI (match_operand:HISI 1 "register_operand"  "0")
+                    (match_operand:HISI 2 "register_operand"  "r")))]
+  "reload_completed"
+  {
+    return avr_out_plus_ext (insn, operands, nullptr);
+  }
+  [(set_attr "length" "<SIZE>")])
+
+
+(define_insn "*sub-extend<QIPSI:mode>.for.cczn.<HISI:mode>"
+  [(set (reg:CCZN REG_CC)
+        (compare:CCZN (minus:HISI (match_operand:HISI 3 "register_operand"     "0")
+                                  (any_extend:HISI
+                                   (match_operand:QIPSI 4 "register_operand"   "2")))
+                      (const_int 0)))
+   (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"))))]
+  "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)"))])
+
+
+;; Operations other that PLUS can set the condition code in
+;; a meaningful way, too.
+
+;; 1/1 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))])
+   (parallel [(set (reg:CC REG_CC)
+                   (compare:CC (match_dup 0)
+                               (const_int 0)))
+              (clobber (scratch:QI))])
+   (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)))])
+
+(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"
+  {
+    output_asm_insn ("lsl %A0", operands);
+    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/1 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_dup 0)
+                    (match_operand:QI 4 "const0_operand")))
+   (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 (cmp_signed (reg:CCZN REG_CC)
+                                  (const_int 0))
+                      (label_ref (match_operand 3))
+                      (pc)))])
+
+;; Constraints and predicate for the insn below.  This is what op8_ZN_operator
+;; allows.  Constraints are written in such a way that all cases have two
+;; alternatives (shifts, XOR and MINUS have effectively just one alternative).
+;; Note again that due to nregs, match_dup's won't work.
+(define_code_attr c0_op8
+  [(xor "r,r") (minus "r,r") (ashift "r,r") (ashiftrt "r,r") (lshiftrt "r,r")
+   (and "d,r") (ior "d,r") (plus "d,r")])
+
+(define_code_attr c2_op8
+  [(xor "r,r") (minus "r,r") (and "n,r") (ior "n,r") (plus "n,r P N K Cm2")
+   (ashift "P K,C03") (ashiftrt "P K,C03") (lshiftrt "P K,C03")])
+
+(define_code_attr p2_op8
+  [(ashift "const_1_to_3")  (ashiftrt "const_1_to_3")  (lshiftrt "const_1_to_3")
+   (xor "register")  (minus "register")
+   (plus "nonmemory")  (and "nonmemory")  (ior "nonmemory")])
+
+;; Result of the peephole2 above:  An 8-bit operation that sets Z and N.
+;; The allowed operations are:  PLUS, MINUS, AND, IOR, XOR and SHIFTs
+;; with operands according to op8_ZN_operator.
+(define_insn "*op8.for.cczn.<code>"
+  [(set (reg:CCZN REG_CC)
+        (compare:CCZN (op8_ZN:QI (match_operand:QI 3 "register_operand" "0,0")
+                                 (match_operand:QI 4 "<p2_op8>_operand" "2,2"))
+                      (const_int 0)))
+   (set (match_operand:QI 0 "register_operand"           "=<c0_op8>")
+        (op8_ZN:QI (match_operand:QI 1 "register_operand" "0,0")
+                   (match_operand:QI 2 "<p2_op8>_operand" "<c2_op8>")))]
+  "reload_completed"
+  {
+    return avr_out_op8_set_ZN (<CODE>, operands, nullptr);
+  }
+  [(set (attr "length")
+        (symbol_ref "avr_len_op8_set_ZN (<CODE>, operands)"))])
+
+
 ;; Test a single bit in a QI/HI/SImode register.
 ;; Combine will create zero-extract patterns for single-bit tests.
 ;; Permit any mode in source pattern by using VOIDmode.
@@ -7046,32 +7517,25 @@ (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 avr_cond_branch (insn, operands);
   }
-  [(set_attr "type" "branch1")])
+  [(set (attr "type")
+        (if_then_else
+         (match_test "simple_comparison_operator (operands[1], VOIDmode)")
+         (const_string "branch")
+         (const_string "branch1")))])
 
 
 ;; **************************************************************************
@@ -9551,173 +10015,6 @@ (define_peephole2
               (clobber (reg:CC REG_CC))])])
 
 
-;; Try optimize decrement-and-branch.  When we have an addition followed
-;; 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")
-                        (HI "Yxx") (PSI "Yxx") (SI "Yxx")])
-
-;; FIXME: reload1.cc::do_output_reload() does not support output reloads
-;; for JUMP_INSNs, hence letting combine doing decrement-and-branch like
-;; the following might run into ICE.  Doing reloads by hand is too painful...
-;
-; (define_insn_and_split "*add.for.eqne.<mode>.cbranch"
-;   [(set (pc)
-;         (if_then_else (eqne (match_operand:QISI 1 "register_operand"  "0")
-;                             (match_operand:QISI 2 "const_int_operand" "n"))
-;                       (label_ref (match_operand 4))
-;                       (pc)))
-;    (set (match_operand:QISI 0 "register_operand" "=r")
-;         (plus:QISI (match_dup 1)
-;                    (match_operand:QISI 3 "const_int_operand" "n")))]
-;   ;; No clobber for now as combine might not have one handy.
-;   ;; We pop a scatch in split1.
-;   "!reload_completed
-;    && const0_rtx == simplify_binary_operation (PLUS, <MODE>mode,
-;                                                operands[2], operands[3])"
-;   { gcc_unreachable(); }
-;   "&& 1"
-;   [(parallel [(set (pc)
-;                    (if_then_else (eqne (match_dup 1)
-;                                        (match_dup 2))
-;                                  (label_ref (match_dup 4))
-;                                  (pc)))
-;               (set (match_dup 0)
-;                    (plus:QISI (match_dup 1)
-;                               (match_dup 3)))
-;               (clobber (scratch:QI))])])
-;
-;; ...Hence, stick with RTL peepholes for now.  Unfortunately, there is no
-;; canonical form, and if reload shuffles registers around, we might miss
-;; opportunities to match a decrement-and-branch.
-;; 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)))
-              (set (match_dup 0)
-                   (plus:QISI (match_dup 0)
-                              (match_dup 1)))
-              (clobber (match_operand:QI 3))])
-   ; "branch"
-   (set (pc)
-        (if_then_else (eqne (reg:CC REG_CC)
-                            (const_int 0))
-                      (label_ref (match_dup 2))
-                      (pc)))])
-
-
-;; 1/3: A version without clobber: d-reg or 8-bit adds +/-1.
-(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)))
-   (set (pc)
-        (if_then_else (eqne (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)))"
-  [(scratch)]
-  {
-    emit (gen_gen_add_for_<code>_<mode> (operands[0], operands[1], operands[2],
-          gen_rtx_SCRATCH (QImode)));
-    DONE;
-  })
-
-;; 2/3: A version with clobber from the insn.
-(define_peephole2
-  [(parallel [(set (match_operand:QISI 0 "register_operand")
-                   (plus:QISI (match_dup 0)
-                              (match_operand:QISI 1 "const_int_operand")))
-              (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)))
-              (clobber (match_operand:QI 4 "scratch_or_d_register_operand"))])
-   (set (pc)
-        (if_then_else (eqne (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];
-
-    // 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)))
-      {
-        FAIL;
-      }
-    emit (gen_gen_add_for_<code>_<mode> (operands[0], operands[1], operands[2],
-          scratch));
-    DONE;
-  })
-
-;; 3/3 A version with a clobber from peephole2.
-(define_peephole2
-  [(match_scratch:QI 3 "d")
-   (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)))
-   (set (pc)
-        (if_then_else (eqne (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]));
-    DONE;
-  })
-
-;; Result of the above three peepholes is an addition that also
-;; performs an EQ or NE 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"))
-         (const_int 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"))]
-  "reload_completed"
-  {
-    return avr_out_plus_set_ZN (operands, nullptr);
-  }
-  [(set_attr "adjust_len" "add_set_ZN")])
-
-
 ;; Swapping both comparison and branch condition.  This can turn difficult
 ;; branches to easy ones.  And in some cases, a comparison against one can
 ;; be turned into a comparison against zero.
diff --git a/gcc/config/avr/predicates.md b/gcc/config/avr/predicates.md
index 5b49481ff0f..b21acbe323f 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")
@@ -242,10 +253,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..c1891038cf3
--- /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__((noipa))
+
+#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..70f961347c0
--- /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__((noipa))
+
+#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-add.c b/gcc/testsuite/gcc.target/avr/pr115830-add.c
new file mode 100644
index 00000000000..99ac89cd0a6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/pr115830-add.c
@@ -0,0 +1,76 @@
+/* { dg-do run } */
+/* { dg-additional-options { -std=c99 -Os } } */
+
+typedef __UINT8_TYPE__ u8;
+typedef __INT8_TYPE__  i8;
+typedef __UINT16_TYPE__ u16;
+typedef __INT16_TYPE__  i16;
+typedef __uint24 u24;
+typedef __int24  i24;
+typedef __UINT32_TYPE__ u32;
+typedef __INT32_TYPE__  i32;
+
+#define AI static inline __attribute__((always_inline))
+#define NI __attribute__((noipa))
+
+u8 volatile v;
+u8 v1;
+
+#define MK_FUN(TYP, OP, TST)		\
+NI TYP add1_##TYP##_##OP (TYP a, TYP b)	\
+{					\
+  a += b;				\
+  if (a TST)				\
+    v = 0;				\
+  return a;				\
+}					\
+					\
+NI TYP add2_##TYP##_##OP (TYP a, TYP b)	\
+{					\
+  a += b;				\
+  __asm ("" : "+r" (a));		\
+  if (a TST)				\
+    v = 0;				\
+  return a;				\
+}					\
+					\
+NI void test_##TYP##_##OP (TYP a, TYP b)\
+{					\
+  v = 1;				\
+  TYP c1 = add1_##TYP##_##OP (a, b);	\
+  v1 = v;				\
+  v = 1;				\
+  TYP c2 = add2_##TYP##_##OP (a, b);	\
+  if (c1 != c2)				\
+    __builtin_abort();			\
+  if (v1 != v)				\
+    __builtin_abort();			\
+}
+
+MK_FUN (i16, ge, >= 0)
+MK_FUN (i24, ge, >= 0)
+MK_FUN (i32, ge, >= 0)
+
+MK_FUN (i16, lt, < 0)
+MK_FUN (i24, lt, < 0)
+MK_FUN (i32, lt, < 0)
+
+
+int main (void)
+{
+  for (i8 a = -5; a <= 5; ++a)
+    {
+      for (i8 b = -5; b <= 5; ++b)
+	{
+	  test_i16_ge (a, b);
+	  test_i24_ge (a, b);
+	  test_i32_ge (a, b);
+
+	  test_i16_lt (a, b);
+	  test_i24_lt (a, b);
+	  test_i32_lt (a, b);
+	}
+    }
+
+  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..7c2c189da27
--- /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__((noipa))
+
+#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..4680c5c3996
--- /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__((noipa))
+
+#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..523dd9e84d9
--- /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__((noipa))
+
+#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..99934cc0dc1
--- /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__((noipa))
+
+#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..0a8b592a906
--- /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__((noipa))
+
+#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..9a4709b2ea8
--- /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__((noipa))
+
+#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;
+}
diff --git a/gcc/testsuite/gcc.target/avr/pr115830-sub-ext.c b/gcc/testsuite/gcc.target/avr/pr115830-sub-ext.c
new file mode 100644
index 00000000000..3fac6ddd0df
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/pr115830-sub-ext.c
@@ -0,0 +1,100 @@
+/* { dg-do run } */
+/* { dg-additional-options { -std=c99 -Os } } */
+
+typedef __UINT8_TYPE__ u8;
+typedef __INT8_TYPE__  i8;
+typedef __UINT16_TYPE__ u16;
+typedef __INT16_TYPE__  i16;
+typedef __uint24 u24;
+typedef __int24  i24;
+typedef __UINT32_TYPE__ u32;
+typedef __INT32_TYPE__  i32;
+
+#define AI static inline __attribute__((always_inline))
+#define NI __attribute__((noipa))
+
+u8 volatile v;
+u8 v1;
+
+#define MK_FUN(A, B, OP, TST)		\
+NI A sub1_##A##_##B##_##OP (A a, B b)	\
+{					\
+  a -= b;				\
+  if (a TST)				\
+    v = 0;				\
+  return a;				\
+}					\
+					\
+NI A sub2_##A##_##B##_##OP (A a, B b)	\
+{					\
+  a -= b;				\
+  __asm ("" : "+r" (a));		\
+  if (a TST)				\
+    v = 0;				\
+  return a;				\
+}					\
+					\
+NI void test_##A##_##B##_##OP (A a, B b)\
+{					\
+  v = 1;				\
+  A c1 = sub1_##A##_##B##_##OP (a, b);	\
+  v1 = v;				\
+  v = 1;				\
+  A c2 = sub2_##A##_##B##_##OP (a, b);	\
+  if (c1 != c2)				\
+    __builtin_abort();			\
+  if (v1 != v)				\
+    __builtin_abort();			\
+}
+
+MK_FUN (u16, u8, ne, != 0)
+MK_FUN (u24, u8, eq, == 0)
+MK_FUN (u32, u16, ne, != 0)
+
+MK_FUN (i16, i8, ge, >= 0)
+MK_FUN (i24, i8, ge, >= 0)
+MK_FUN (i32, i16, ge, >= 0)
+
+MK_FUN (i16, i8, lt, < 0)
+MK_FUN (i24, i8, lt, < 0)
+MK_FUN (i32, i16, lt, < 0)
+
+MK_FUN (i16, i8, le, <= 0)
+MK_FUN (i24, i8, le, <= 0)
+MK_FUN (i32, i16, le, <= 0)
+
+MK_FUN (i16, i8, gt, > 0)
+MK_FUN (i24, i8, gt, > 0)
+MK_FUN (i32, i16, gt, > 0)
+
+
+int main (void)
+{
+  for (i8 a = -5; a <= 5; ++a)
+    {
+      for (i8 b = -5; b <= 5; ++b)
+	{
+	  test_u16_u8_ne (a, b);
+	  test_u24_u8_eq (a, b);
+	  test_u32_u16_ne (a, b);
+
+	  test_i16_i8_ge (a, b);
+	  test_i24_i8_ge (a, b);
+	  test_i32_i16_ge (a, b);
+
+	  test_i16_i8_lt (a, b);
+	  test_i24_i8_lt (a, b);
+	  test_i32_i16_lt (a, b);
+
+	  test_i16_i8_gt (a, b);
+	  test_i24_i8_gt (a, b);
+	  test_i32_i16_gt (a, b);
+
+	  test_i16_i8_le (a, b);
+	  test_i24_i8_le (a, b);
+	  test_i32_i16_le (a, b);
+	}
+    }
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/pr115830-sub.c b/gcc/testsuite/gcc.target/avr/pr115830-sub.c
new file mode 100644
index 00000000000..ef24e74752d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/pr115830-sub.c
@@ -0,0 +1,100 @@
+/* { dg-do run } */
+/* { dg-additional-options { -std=c99 -Os } } */
+
+typedef __UINT8_TYPE__ u8;
+typedef __INT8_TYPE__  i8;
+typedef __UINT16_TYPE__ u16;
+typedef __INT16_TYPE__  i16;
+typedef __uint24 u24;
+typedef __int24  i24;
+typedef __UINT32_TYPE__ u32;
+typedef __INT32_TYPE__  i32;
+
+#define AI static inline __attribute__((always_inline))
+#define NI __attribute__((noipa))
+
+u8 volatile v;
+u8 v1;
+
+#define MK_FUN(TYP, OP, TST)		\
+NI TYP sub1_##TYP##_##OP (TYP a, TYP b)	\
+{					\
+  a -= b;				\
+  if (a TST)				\
+    v = 0;				\
+  return a;				\
+}					\
+					\
+NI TYP sub2_##TYP##_##OP (TYP a, TYP b)	\
+{					\
+  a -= b;				\
+  __asm ("" : "+r" (a));		\
+  if (a TST)				\
+    v = 0;				\
+  return a;				\
+}					\
+					\
+NI void test_##TYP##_##OP (TYP a, TYP b)\
+{					\
+  v = 1;				\
+  TYP c1 = sub1_##TYP##_##OP (a, b);	\
+  v1 = v;				\
+  v = 1;				\
+  TYP c2 = sub2_##TYP##_##OP (a, b);	\
+  if (c1 != c2)				\
+    __builtin_abort();			\
+  if (v1 != v)				\
+    __builtin_abort();			\
+}
+
+MK_FUN (i8, ge, >= 0)
+MK_FUN (i16, ge, >= 0)
+MK_FUN (i24, ge, >= 0)
+MK_FUN (i32, ge, >= 0)
+
+MK_FUN (i8, lt, < 0)
+MK_FUN (i16, lt, < 0)
+MK_FUN (i24, lt, < 0)
+MK_FUN (i32, lt, < 0)
+
+MK_FUN (i8, le, <= 0)
+MK_FUN (i16, le, <= 0)
+MK_FUN (i24, le, <= 0)
+MK_FUN (i32, le, <= 0)
+
+MK_FUN (i8, gt, > 0)
+MK_FUN (i16, gt, > 0)
+MK_FUN (i24, gt, > 0)
+MK_FUN (i32, gt, > 0)
+
+
+int main (void)
+{
+  for (i8 a = -5; a <= 5; ++a)
+    {
+      for (i8 b = -5; b <= 5; ++b)
+	{
+	  test_i8_ge (a, b);
+	  test_i16_ge (a, b);
+	  test_i24_ge (a, b);
+	  test_i32_ge (a, b);
+
+	  test_i8_lt (a, b);
+	  test_i16_lt (a, b);
+	  test_i24_lt (a, b);
+	  test_i32_lt (a, b);
+
+	  test_i8_gt (a, b);
+	  test_i16_gt (a, b);
+	  test_i24_gt (a, b);
+	  test_i32_gt (a, b);
+
+	  test_i8_le (a, b);
+	  test_i16_le (a, b);
+	  test_i24_le (a, b);
+	  test_i32_le (a, b);
+	}
+    }
+
+  return 0;
+}
