diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index 97f3561..b58db14 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -5152,16 +5152,95 @@
    (set_attr "isa" "eijmp")
    (set_attr "cc" "clobber")])
 
+; casesi for QI mode case values
+(define_expand "casesi_index_qi"
+  [(set (cc0)
+        (compare:QI (subreg:QI (match_dup 0) 0)
+                    (match_operand 2 "const_int_operand" "")))
 
-(define_expand "casesi"
-  [(parallel [(set (match_dup 6)
-                   (minus:HI (subreg:HI (match_operand:SI 0 "register_operand" "") 0)
-                             (match_operand:HI 1 "register_operand" "")))
-              (clobber (scratch:QI))])
-   (parallel [(set (cc0)
-                   (compare (match_dup 6)
-                            (match_operand:HI 2 "register_operand" "")))
-              (clobber (match_scratch:QI 9 ""))])
+   (set (pc)
+        (if_then_else (gtu (cc0)
+                           (const_int 0))
+                      (label_ref (match_operand 4 "" ""))
+                      (pc)))
+
+   (set (match_dup 9)
+        (match_dup 7))
+
+   (parallel [(set (pc)
+	               (unspec:HI [(match_dup 9)] UNSPEC_INDEX_JMP))
+              (use (label_ref (match_operand 3 "" "")))
+              (clobber (match_dup 9))
+              (clobber (match_dup 8))])]
+  ""
+  {
+    operands[5] = gen_reg_rtx (QImode);
+    unsigned int original_byte_number = 0;
+    /* if subreg, take out inner exp and byte number.
+       Later subreg shall use that byte number accordingly to
+       avoid list of nested SUBREGs.  */
+    if (SUBREG_P (operands[0]))
+      {
+        rtx original_index = operands[0];
+        original_index = SUBREG_REG (operands[0]);
+        original_byte_number = SUBREG_BYTE (operands[0]);
+        operands[0] = original_index;
+      }
+
+    /* jump to out_of_range label if any of the
+       higher 3 bytes of switch index is set.  */
+    emit_insn (gen_rtx_SET (operands[5], gen_rtx_IOR (QImode,
+                                           gen_rtx_SUBREG (QImode, operands[0], original_byte_number + 2),
+                                           gen_rtx_SUBREG (QImode, operands[0], original_byte_number + 3))));
+    emit_insn (gen_rtx_SET (operands[5], gen_rtx_IOR (QImode,
+                                           gen_rtx_SUBREG (QImode, operands[0], original_byte_number + 1),
+                                           operands[5])));
+    emit_insn (gen_rtx_SET (cc0_rtx,
+                 gen_rtx_COMPARE (QImode, operands[5], const0_rtx)));
+    emit_jump_insn (gen_rtx_SET (pc_rtx,
+        gen_rtx_IF_THEN_ELSE (VOIDmode,
+            gen_rtx_NE (VOIDmode, cc0_rtx, const0_rtx),
+            gen_rtx_LABEL_REF (VOIDmode, operands[4]),
+            pc_rtx)));
+
+    /* Subtract lower bound from index iff lower bound is not zero.  */
+    operands[6] = gen_rtx_SUBREG (HImode, operands[0], original_byte_number);
+    if (operands[1] != const0_rtx)
+      {
+        rtx reg = gen_reg_rtx (HImode);
+        emit_insn (gen_addhi3 (reg, operands[6],
+                     gen_int_mode (-INTVAL (operands[1]), HImode)));
+        operands[0] = reg;
+        operands[6] = operands[0];
+      }
+
+    if (!s8_operand (operands[2], QImode))
+      {
+        INTVAL (operands[2]) = -(256 - INTVAL (operands[2]));
+      }
+
+    if (AVR_HAVE_EIJMP_EICALL)
+      {
+        operands[7] = operands[6];
+        operands[8] = all_regs_rtx[24];
+        operands[9] = gen_rtx_REG (HImode, REG_Z);
+      }
+    else
+      {
+        operands[7] = gen_rtx_PLUS (HImode, operands[6],
+                                    gen_rtx_LABEL_REF (VOIDmode, operands[3]));
+        operands[8] = const0_rtx;
+        operands[9] = gen_reg_rtx (HImode);
+      }
+  }
+  )
+
+; casesi for HI mode case values
+(define_expand "casesi_index_hi"
+  [(parallel [(set (cc0)
+                   (compare (match_dup 0)
+                            (match_operand:HI 2 "const_int_operand" "")))
+              (clobber (match_scratch:QI 10 ""))])
 
    (set (pc)
         (if_then_else (gtu (cc0)
@@ -5169,31 +5248,148 @@
                       (label_ref (match_operand 4 "" ""))
                       (pc)))
 
-   (set (match_dup 10)
+   (set (match_dup 9)
         (match_dup 7))
 
    (parallel [(set (pc)
-                   (unspec:HI [(match_dup 10)] UNSPEC_INDEX_JMP))
-              (use (label_ref (match_dup 3)))
-              (clobber (match_dup 10))
+	               (unspec:HI [(match_dup 9)] UNSPEC_INDEX_JMP))
+              (use (label_ref (match_operand 3 "" "")))
+              (clobber (match_dup 9))
               (clobber (match_dup 8))])]
   ""
   {
-    operands[6] = gen_reg_rtx (HImode);
+    operands[5] = gen_reg_rtx (QImode);
+    unsigned int original_byte_number = 0;
+    /* if subreg, take out inner exp and byte number.
+       Later subreg shall use that byte number accordingly to
+       avoid list of nested SUBREGs.  */
+    if (SUBREG_P (operands[0]))
+      {
+        rtx original_index = operands[0];
+        original_index = SUBREG_REG (operands[0]);
+        original_byte_number = SUBREG_BYTE (operands[0]);
+        operands[0] = original_index;
+      }
+
+    /* jump to out_of_range label if any of the
+       higher 3 bytes of switch index is set.  */
+    emit_insn (gen_rtx_SET (operands[5], gen_rtx_IOR (QImode,
+                                           gen_rtx_SUBREG (QImode, operands[0], original_byte_number + 2),
+                                           gen_rtx_SUBREG (QImode, operands[0], original_byte_number + 3))));
+    emit_insn (gen_rtx_SET (cc0_rtx,
+                 gen_rtx_COMPARE (QImode, operands[5], const0_rtx)));
+    emit_jump_insn (gen_rtx_SET (pc_rtx,
+        gen_rtx_IF_THEN_ELSE (VOIDmode,
+            gen_rtx_NE (VOIDmode, cc0_rtx, const0_rtx),
+            gen_rtx_LABEL_REF (VOIDmode, operands[4]),
+            pc_rtx)));
+
+    /* Subtract lower bound from index iff lower bound is not zero.  */
+    operands[6] = gen_rtx_SUBREG (HImode, operands[0], original_byte_number);
+    if (operands[1] != const0_rtx)
+      {
+        rtx reg = gen_reg_rtx (HImode);
+        emit_insn (gen_addhi3 (reg, operands[6],
+                     gen_int_mode (-INTVAL (operands[1]), HImode)));
+        operands[0] = reg;
+        operands[6] = operands[0];
+      }
 
     if (AVR_HAVE_EIJMP_EICALL)
       {
         operands[7] = operands[6];
         operands[8] = all_regs_rtx[24];
-        operands[10] = gen_rtx_REG (HImode, REG_Z);
+        operands[9] = gen_rtx_REG (HImode, REG_Z);
       }
     else
       {
         operands[7] = gen_rtx_PLUS (HImode, operands[6],
                                     gen_rtx_LABEL_REF (VOIDmode, operands[3]));
         operands[8] = const0_rtx;
-        operands[10] = operands[6];
+        operands[9] = gen_reg_rtx (HImode);
+      }
+  }
+  )
+  
+; casesi for SI mode case values
+(define_expand "casesi_index_si"
+  [(parallel [(set (cc0)
+                   (compare (match_dup 0)
+                            (match_operand:SI 2 "const_int_operand" "")))
+              (clobber (match_scratch:QI 8 ""))])
+
+   (set (pc)
+        (if_then_else (gtu (cc0)
+                           (const_int 0))
+                      (label_ref (match_operand 4 "" ""))
+                      (pc)))
+
+   (set (match_dup 7)
+        (match_dup 5))
+
+   (parallel [(set (pc)
+	               (unspec:HI [(match_dup 7)] UNSPEC_INDEX_JMP))
+              (use (label_ref (match_operand 3 "" "")))
+              (clobber (match_dup 7))
+              (clobber (match_dup 6))])]
+  ""
+  {
+    /* Subtract lower bound from index iff lower bound is not zero.  */
+    if (operands[1] != const0_rtx)
+      {
+        rtx reg = gen_reg_rtx (SImode);
+        emit_insn (gen_addsi3 (reg, operands[0],
+                     gen_int_mode (-INTVAL (operands[1]), SImode)));
+        operands[0] = reg;
+      }
+
+    if (AVR_HAVE_EIJMP_EICALL)
+      {
+        operands[5] = simplify_gen_subreg (HImode, operands[0], SImode, 0);
+        operands[6] = all_regs_rtx[24];
+        operands[7] = gen_rtx_REG (HImode, REG_Z);
+      }
+    else
+      {
+        operands[5] = gen_rtx_PLUS (HImode, simplify_gen_subreg (HImode, operands[0], SImode, 0),
+                                    gen_rtx_LABEL_REF (VOIDmode, operands[3]));
+        operands[6] = const0_rtx;
+        operands[7] = gen_reg_rtx (HImode);
       }
+  }
+  )
+
+(define_expand "casesi"
+  [(match_operand:SI 0 "register_operand" "")  ; index to jump on
+   (match_operand    1 "const_int_operand" "") ; lower bound
+   (match_operand    2 "const_int_operand" "") ; total range
+   (match_operand    3 "" "")                  ; table label
+   (match_operand    4 "" "")]                 ; out of range label
+  ""
+  {
+    /* Can not handle the ranges greater than 16bit wide.  */
+    if (INTVAL (operands[2]) > UINT16_MAX)
+      gcc_unreachable ();
+
+    /* case values include negative or greater than HImode.  */
+    if ((INTVAL (operands[1]) < 0) ||
+        ((INTVAL (operands[1]) + INTVAL (operands[2])) > UINT16_MAX))
+      {
+        emit_insn (gen_casesi_index_si (operand0, operand1, operand2, operand3, operand4));
+      }
+    else if ((s8_operand (operands[1], QImode) || u8_operand (operands[1], QImode)) &&
+             (s8_operand (operands[2], QImode) || u8_operand (operands[2], QImode)))
+      {
+        emit_insn (gen_casesi_index_qi (operand0, operand1, operand2, operand3, operand4));
+      }
+    else
+      {
+        gcc_assert (s16_operand (operands[1], HImode) ||
+                    u16_operand (operands[1], HImode));
+
+        emit_insn (gen_casesi_index_hi (operand0, operand1, operand2, operand3, operand4));
+      }
+    DONE;
   })
 
 
diff --git a/gcc/testsuite/gcc.target/avr/pr71676-1.c b/gcc/testsuite/gcc.target/avr/pr71676-1.c
new file mode 100644
index 0000000..7315e03
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/pr71676-1.c
@@ -0,0 +1,332 @@
+/* { dg-do run } */
+/* { dg-options "-Os -Wno-overflow" } */
+
+#include "exit-abort.h"
+volatile unsigned char y;
+
+unsigned char __attribute__((noinline)) foo1 (char x)
+{
+    switch (x)
+    {
+      case (char)0x11: y = 7; break;
+      case (char)0x12: y = 4; break;
+      case (char)0x13: y = 8; break;
+      case (char)0x14: y = 21; break;
+      case (char)0x15: y = 65; break;
+      case (char)0x16: y = 27; break;
+      case (char)0x17: y = 72; break;
+      case (char)0x18: y = 39; break;
+      default: y=0;
+    }
+    return y;
+}
+
+unsigned char __attribute__((noinline)) foo2 (char x)
+{
+    switch (x)
+    {
+      case 0x01: y = 7; break;
+      case 0x02: y = 4; break;
+      case 0x03: y = 8; break;
+      case 0x04: y = 21; break;
+      case 0x05: y = 65; break;
+      case 0x06: y = 27; break;
+      case 0x07: y = 72; break;
+      case 0x08: y = 39; break;
+      default: y=0;
+    }
+    return y;
+}
+
+unsigned char __attribute__((noinline)) foo3 (char x)
+{
+    switch (x)
+    {
+      case 0x1000001L: y = 7; break;
+      case 0x1000002L: y = 4; break;
+      case 0x1000003L: y = 8; break;
+      case 0x1000004L: y = 21; break;
+      case 0x1000005L: y = 65; break;
+      case 0x1000006L: y = 27; break;
+      case 0x1000007L: y = 72; break;
+      case 0x1000008L: y = 39; break;
+      default: y=0;
+    }
+    return y;
+}
+
+unsigned char __attribute__((noinline)) foo4 (char x)
+{
+    switch (x)
+    {
+      case 0x100000001LL: y = 7; break;
+      case 0x100000002LL: y = 4; break;
+      case 0x100000003LL: y = 8; break;
+      case 0x100000004LL: y = 21; break;
+      case 0x100000005LL: y = 65; break;
+      case 0x100000006LL: y = 27; break;
+      case 0x100000007LL: y = 72; break;
+      case 0x100000008LL: y = 39; break;
+      default: y=0;
+    }
+    return y;
+}
+
+unsigned char __attribute__((noinline)) foo5 (int x)
+{
+    switch (x)
+    {
+      case (char)0x11: y = 7; break;
+      case (char)0x12: y = 4; break;
+      case (char)0x13: y = 8; break;
+      case (char)0x14: y = 21; break;
+      case (char)0x15: y = 65; break;
+      case (char)0x16: y = 27; break;
+      case (char)0x17: y = 72; break;
+      case (char)0x18: y = 39; break;
+      default: y=0;
+    }
+    return y;
+}
+
+unsigned char __attribute__((noinline)) foo6 (int x)
+{
+    switch (x)
+    {
+      case 0x101: y = 7; break;
+      case 0x102: y = 4; break;
+      case 0x103: y = 8; break;
+      case 0x104: y = 21; break;
+      case 0x105: y = 65; break;
+      case 0x106: y = 27; break;
+      case 0x107: y = 72; break;
+      case 0x108: y = 39; break;
+      default: y=0;
+    }
+    return y;
+}
+
+unsigned char __attribute__((noinline)) foo7 (int x)
+{
+    switch (x)
+    {
+      case 0x1000001L: y = 7; break;
+      case 0x1000002L: y = 4; break;
+      case 0x1000003L: y = 8; break;
+      case 0x1000004L: y = 21; break;
+      case 0x1000005L: y = 65; break;
+      case 0x1000006L: y = 27; break;
+      case 0x1000007L: y = 72; break;
+      case 0x1000008L: y = 39; break;
+      default: y=0;
+    }
+    return y;
+}
+
+unsigned char __attribute__((noinline)) foo8 (int x)
+{
+    switch (x)
+    {
+      case 0x100000001LL: y = 7; break;
+      case 0x100000002LL: y = 4; break;
+      case 0x100000003LL: y = 8; break;
+      case 0x100000004LL: y = 21; break;
+      case 0x100000005LL: y = 65; break;
+      case 0x100000006LL: y = 27; break;
+      case 0x100000007LL: y = 72; break;
+      case 0x100000008LL: y = 39; break;
+      default: y=0;
+    }
+    return y;
+}
+
+unsigned char __attribute__((noinline)) foo9 (long x)
+{
+    switch (x)
+    {
+      case (char)0x11: y = 7; break;
+      case (char)0x12: y = 4; break;
+      case (char)0x13: y = 8; break;
+      case (char)0x14: y = 21; break;
+      case (char)0x15: y = 65; break;
+      case (char)0x16: y = 27; break;
+      case (char)0x17: y = 72; break;
+      case (char)0x18: y = 39; break;
+      default: y=0;
+    }
+    return y;
+}
+
+unsigned char __attribute__((noinline)) foo10 (unsigned long x)
+{
+    switch (x)
+    {
+      case 0x100: y = 39; break;
+      case 0x101: y = 7; break;
+      case 0x102: y = 4; break;
+      case 0x103: y = 8; break;
+      case 0x104: y = 21; break;
+      case 0x105: y = 65; break;
+      case 0x106: y = 27; break;
+      case 0x107: y = 72; break;
+      default: y=0;
+    }
+    return y;
+}
+
+unsigned char __attribute__((noinline)) foo11 (long x)
+{
+    switch (x)
+    {
+      case 0x1000001L: y = 7; break;
+      case 0x1000002L: y = 4; break;
+      case 0x1000003L: y = 8; break;
+      case 0x1000004L: y = 21; break;
+      case 0x1000005L: y = 65; break;
+      case 0x1000006L: y = 27; break;
+      case 0x1000007L: y = 72; break;
+      case 0x1000008L: y = 39; break;
+      default: y=0;
+    }
+    return y;
+}
+
+unsigned char __attribute__((noinline)) foo12 (long x)
+{
+    switch (x)
+    {
+      case 0x100000001LL: y = 7; break;
+      case 0x100000002LL: y = 4; break;
+      case 0x100000003LL: y = 8; break;
+      case 0x100000004LL: y = 21; break;
+      case 0x100000005LL: y = 65; break;
+      case 0x100000006LL: y = 27; break;
+      case 0x100000007LL: y = 72; break;
+      case 0x100000008LL: y = 39; break;
+      default: y=0;
+    }
+    return y;
+}
+
+unsigned char __attribute__((noinline)) foo13 (long long x)
+{
+    switch (x)
+    {
+      case (char)0x11: y = 7; break;
+      case (char)0x12: y = 4; break;
+      case (char)0x13: y = 8; break;
+      case (char)0x14: y = 21; break;
+      case (char)0x15: y = 65; break;
+      case (char)0x16: y = 27; break;
+      case (char)0x17: y = 72; break;
+      case (char)0x18: y = 39; break;
+      default: y=0;
+    }
+    return y;
+}
+
+unsigned char __attribute__((noinline)) foo14 (long long x)
+{
+    switch (x)
+    {
+      case 0x101: y = 7; break;
+      case 0x102: y = 4; break;
+      case 0x103: y = 8; break;
+      case 0x104: y = 21; break;
+      case 0x105: y = 65; break;
+      case 0x106: y = 27; break;
+      case 0x107: y = 72; break;
+      case 0x108: y = 39; break;
+      default: y=0;
+    }
+    return y;
+}
+
+unsigned char __attribute__((noinline)) foo15 (long long x)
+{
+    switch (x)
+    {
+      case 0x1000001L: y = 7; break;
+      case 0x1000002L: y = 4; break;
+      case 0x1000003L: y = 8; break;
+      case 0x1000004L: y = 21; break;
+      case 0x1000005L: y = 65; break;
+      case 0x1000006L: y = 27; break;
+      case 0x1000007L: y = 72; break;
+      case 0x1000008L: y = 39; break;
+      default: y=0;
+    }
+    return y;
+}
+
+
+unsigned char __attribute__((noinline)) foo16 (long long x)
+{
+    switch (x)
+    {
+      case 0x100000001LL: y = 7; break;
+      case 0x100000002LL: y = 4; break;
+      case 0x100000003LL: y = 8; break;
+      case 0x100000004LL: y = 21; break;
+      case 0x100000005LL: y = 65; break;
+      case 0x100000006LL: y = 27; break;
+      case 0x100000007LL: y = 72; break;
+      case 0x100000008LL: y = 39; break;
+      default: y=0;
+    }
+    return y;
+}
+
+int main ()
+{
+	if (foo1 (0x13) != 8)
+	  abort();
+
+	if (foo2 (0x06) != 27)
+	  abort();
+
+	if (foo3 (0x02) != 4)
+	  abort();
+
+	if (foo4 (0x01) != 7)
+	  abort();
+
+	if (foo5 (0x15) != 65)
+	  abort();
+
+	if (foo6 (0x103) != 8)
+	  abort();
+
+	if (foo7 (0x04) != 21)
+	  abort();
+
+	if (foo8 (0x07) != 72)
+	  abort();
+
+	if (foo9 (0x10000011L) != 0)
+	  abort();
+
+	if (foo10 (0x1000105L) != 0)
+	  abort();
+
+	if (foo11 (0x1000008L) != 39)
+	  abort();
+
+	if (foo12 (0x1000004L) != 0)
+	  abort();
+
+	if (foo13 (0x13LL) != 8)
+	  abort();
+
+	if (foo14 (0x108LL) != 39)
+	  abort();
+
+	if (foo15 (0x1000001LL) != 7)
+	  abort();
+
+	if (foo16 (0x100000004LL) != 21)
+	  abort();
+
+    return 0;
+}
+
diff --git a/gcc/testsuite/gcc.target/avr/pr71676.c b/gcc/testsuite/gcc.target/avr/pr71676.c
new file mode 100644
index 0000000..d7a543a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/pr71676.c
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+/* { dg-options "-Os" } */
+
+#include "exit-abort.h"
+
+volatile unsigned char y;
+
+__attribute__((noinline,noclone))
+unsigned char foo (unsigned long x) 
+{
+    switch (x)
+    {
+        case 0:	y = 67; break;
+        case 1:	y = 20; break;
+        case 2:	y = 109; break;
+        case 3:	y = 33; break;
+        case 4:	y = 44; break;
+        case 5:	y = 37; break;
+        case 6:	y = 10; break;
+        case 7:	y = 98; break;
+    }
+    return y;
+}
+
+int main (void)
+{
+    if (0 != foo (7L + 0x10000L))
+        abort();
+    return 0;
+}
+
diff --git a/gcc/testsuite/gcc.target/avr/pr71678.c b/gcc/testsuite/gcc.target/avr/pr71678.c
new file mode 100644
index 0000000..290d6cc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/pr71678.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -fno-tree-switch-conversion" } */
+
+unsigned char foo (long long x) 
+{
+    unsigned char y = 0;
+    switch (x)
+    {
+        case 0: y = 67; break;
+        case 1: y = 20; break;
+        case 2: y = 109; break;
+        case 3: y = 33; break;
+        case 4: y = 44; break;
+        case 5: y = 37; break;
+        case 6: y = 10; break;
+        case 7: y = 11; break;
+    }
+    return y;
+}
+
