diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index 83dd15040b07..c2a1931733f8 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -9840,6 +9840,7 @@
    (clobber (reg:CC REG_CC))]
   "reload_completed"
   {
+    int ldi_ok = test_hard_reg_class (LD_REGS, operands[0]);
     int shift = <CODE> == ASHIFT ? INTVAL (operands[2]) : -INTVAL (operands[2]);
     int mask = GET_MODE_MASK (<MODE>mode) & INTVAL (operands[3]);
     // Position of the output / input bit, respectively.
@@ -9850,6 +9851,217 @@
     operands[3] = GEN_INT (obit);
     operands[2] = GEN_INT (ibit);
 
+    /* Special cases requiring MOV to low byte and ANDI.  */
+    if ((shift & 7) == 0 && ldi_ok)
+      {
+	if (IN_RANGE (obit, 0, 7))
+	  {
+	    if (shift == -8)
+	      {
+		if (<SIZE> == 2)
+		  return "mov %A0,%B1\;andi %A0,lo8(1<<%3)\;clr %B0";
+		if (<SIZE> == 3)
+		  return "mov %A0,%B1\;andi %A0,lo8(1<<%3)\;clr %B0\;clr %C0";
+		if (<SIZE> == 4 && !AVR_HAVE_MOVW)
+		  return "mov %A0,%B1\;andi %A0,lo8(1<<%3)\;"
+			 "clr %B0\;clr %C0\;clr %D0";
+	      }
+	    else if (shift == -16)
+	      {
+		if (<SIZE> == 3)
+		  return "mov %A0,%C1\;andi %A0,lo8(1<<%3)\;clr %B0\;clr %C0";
+		if (<SIZE> == 4 && !AVR_HAVE_MOVW)
+		  return "mov %A0,%C1\;andi %A0,lo8(1<<%3)\;"
+			 "clr %B0\;clr %C0\;clr %D0";
+	      }
+	    else if (shift == -24 && !AVR_HAVE_MOVW)
+	      return "mov %A0,%D1\;andi %A0,lo8(1<<%3)\;"
+		     "clr %B0\;clr %C0\;clr %D0";
+	  }
+
+	/* Special cases requiring MOV and ANDI.  */
+	else if (IN_RANGE (obit, 8, 15))
+	  {
+	    if (shift == 8)
+	      {
+		if (<SIZE> == 2)
+		  return "mov %B0,%A1\;andi %B0,lo8(1<<(%3-8))\;clr %A0";
+		if (<SIZE> == 3)
+		  return "mov %B0,%A1\;andi %B0,lo8(1<<(%3-8))\;"
+			 "clr %A0\;clr %C0";
+		if (<SIZE> == 4 && !AVR_HAVE_MOVW)
+		  return "mov %B0,%A1\;andi %B0,lo8(1<<(%3-8))\;"
+			 "clr %A0\;clr %C0\;clr %D0";
+	      }
+	    else if (shift == -8)
+	      {
+		if (<SIZE> == 3)
+		  return "mov %B0,%C1\;andi %B0,lo8(1<<(%3-8))\;"
+			 "clr %A0\;clr %C0";
+		if (<SIZE> == 4 && !AVR_HAVE_MOVW)
+		  return "mov %B0,%C1\;andi %B0,lo8(1<<(%3-8))\;"
+			 "clr %B0\;clr %C0\;clr %D0";
+	      }
+	    else if (shift == -16 && !AVR_HAVE_MOVW)
+	      return "mov %B0,%D1\;andi %B0,lo8(1<<(%3-8))\;"
+		     "clr %A0\;clr %C0\;clr %D0";
+	  }
+	else if (IN_RANGE (obit, 16, 23))
+	  {
+	    if (shift == 16)
+	      {
+		if (<SIZE> == 3)
+		  return "mov %C0,%A1\;andi %B0,lo8(1<<(%3-16))\;"
+			 "clr %A0\;clr %B0";
+		if (<SIZE> == 4 && !AVR_HAVE_MOVW)
+		  return "mov %C0,%A1\;andi %B0,lo8(1<<(%3-16))\;"
+			 "clr %A0\;clr %B0\;clr %D0";
+	      }
+	    else if (shift == 8)
+	      {
+		if (<SIZE> == 3)
+		  return "mov %C0,%B1\;andi %C0,lo8(1<<(%3-16))\;"
+			 "clr %A0\;clr %B0";
+		if (<SIZE> == 4 && !AVR_HAVE_MOVW)
+		  return "mov %C0,%B1\;andi %C0,lo8(1<<(%3-16))\;"
+			 "clr %A0\;clr %C0\;clr %D0";
+	      }
+	    else if (shift == -8 && !AVR_HAVE_MOVW)
+	      return "mov %C0,%D1\;andi %C0,lo8(1<<(%3-16))\;"
+		     "clr %A0\;clr %B0\;clr %D0";
+	  }
+	else if (IN_RANGE (obit, 24, 31) && !AVR_HAVE_MOVW)
+	  {
+	    if (shift == 8)
+	      return "mov %D0,%C1\;andi %D0,lo8(1<<(%3-24))\;"
+		     "clr %A0\;clr %B0\;clr %C0";
+	    if (shift == 16)
+	      return "mov %D0,%B1\;andi %D0,lo8(1<<(%3-24))\;"
+		     "clr %A0\;clr %B0\;clr %C0";
+	    if (shift == 24)
+	      return "mov %D0,%A1\;andi %D0,lo8(1<<(%3-24))\;"
+		     "clr %A0\;clr %B0\;clr %C0";
+	  }
+      }
+
+    /* Special cases where the byte is already in place.  */
+    if (REGNO (operands[0]) == REGNO (operands[1])
+	&& ldi_ok)
+      {
+	if (shift == 1)
+	  {
+	    if (IN_RANGE (obit, 0, 7))
+	      {
+		if (<SIZE> == 1)
+		  return "lsl %0\;andi %0,lo8(1<<%3)";
+		if (<SIZE> == 2)
+		  return "lsl %A0\;andi %A0,lo8(1<<%3)\;clr %B0";
+		if (<SIZE> == 3)
+		  return "lsl %A0\;andi %A0,lo8(1<<%3)\;clr %B0\;clr %C0";
+		if (!AVR_HAVE_MOVW)
+		  return "lsl %A0\;andi %A0,lo8(1<<%3)\;"
+			 "clr %B0\;clr %C0\;clr %D0";
+	      }
+	    else if (IN_RANGE (obit, 9, 15))
+	      {
+		if (<SIZE> == 2)
+		  return "lsl %B0\;andi %B0,lo8(1<<(%3-8))\;clr %A0";
+		if (<SIZE> == 3)
+		  return "lsl %B0\;andi %B0,lo8(1<<(%3-8))\;clr %A0\;clr %C0";
+		if (!AVR_HAVE_MOVW)
+		  return "lsl %B0\;andi %B0,lo8(1<<(%3-8))\;"
+			 "clr %A0\;clr %C0\;clr %D0";
+	      }
+	    else if (IN_RANGE (obit, 17, 23))
+	      {
+		if (<SIZE> == 3)
+		  return "lsl %C0\;andi %C0,lo8(1<<(%3-16))\;clr %A0\;clr %B0";
+		if (!AVR_HAVE_MOVW)
+		  return "lsl %C0\;andi %C0,lo8(1<<(%3-16))\;"
+			 "clr %A0\;clr %B0\;clr %D0";
+	      }
+	    else if (IN_RANGE (obit, 25, 31) && !AVR_HAVE_MOVW)
+	      return "lsl %D0\;andi %D0,lo8(1<<(%3-24))\;"
+		     "clr %A0\;clr %B0\;clr %C0";
+	  }
+
+	if (shift == -1)
+	  {
+	    if (IN_RANGE (obit, 0, 6))
+	      {
+		if (<SIZE> == 1)
+		  return "lsr %0\;andi %0,lo8(1<<%3)";
+		if (<SIZE> == 2)
+		  return "lsr %A0\;andi %A0,lo8(1<<%3)\;clr %B0";
+		if (<SIZE> == 3)
+		  return "lsr %A0\;andi %A0,lo8(1<<%3)\;clr %B0\;clr %C0";
+		if (!AVR_HAVE_MOVW)
+		  return "lsr %A0\;andi %A0,lo8(1<<%3)\;"
+			 "clr %B0\;clr %C0\;clr %D0";
+	      }
+	    else if (IN_RANGE (obit, 8, 14))
+	      {
+		if (<SIZE> == 2)
+		  return "lsr %B0\;andi %B0,lo8(1<<(%3-8))\;clr %A0";
+		if (<SIZE> == 3)
+		  return "lsr %B0\;andi %A0,lo8(1<<(%3-8))\;clr %A0\;clr %C0";
+		if (!AVR_HAVE_MOVW)
+		  return "lsr %B0\;andi %B0,lo8(1<<(%3-8))\;"
+			 "clr %A0\;clr %C0\;clr %D0";
+	      }
+	    else if (IN_RANGE (obit, 16, 22))
+	      {
+		if (<SIZE> == 3)
+		  return "lsr %C0\;andi %C0,lo8(1<<(%3-16))\;clr %A0\;clr %B0";
+		if (!AVR_HAVE_MOVW)
+		  return "lsr %C0\;andi %C0,lo8(1<<(%3-16))\;"
+			 "clr %A0\;clr %B0\;clr %D0";
+	      }
+	    else if (IN_RANGE (obit, 24, 30) && !AVR_HAVE_MOVW)
+	      return "lsr %D0\;andi %D0,lo8(1<<(%3-24))\;"
+		     "clr %A0\;clr %B0\;clr %C0";
+	  }
+
+	if ((shift == 4 && IN_RANGE (obit, 4, 7))
+	    || (shift == -4 && IN_RANGE (obit, 0, 3)))
+	  {
+	    if (<SIZE> == 1)
+	      return "swap %0\;andi %0,lo8(1<<%3)";
+	    if (<SIZE> == 2)
+	      return "swap %A0\;andi %A0,lo8(1<<%3)\;clr %B0";
+	    if (<SIZE> == 3)
+	      return "swap %A0\;andi %A0,lo8(1<<%3)\;clr %B0\;clr %C0";
+	    if (!AVR_HAVE_MOVW)
+	      return "swap %A0\;andi %A0,lo8(1<<%3)\;"
+		     "clr %B0\;clr %C0\;clr %D0";
+	  }
+	if ((shift == 4 && IN_RANGE (obit, 12, 15))
+	    || (shift == -4 && IN_RANGE (obit, 8, 11)))
+	  {
+	    if (<SIZE> == 2)
+	      return "swap %B0\;andi %B0,lo8(1<<(%3-8))\;clr %A0";
+	    if (<SIZE> == 3)
+	      return "swap %B0\;andi %B0,lo8(1<<(%3-8))\;clr %A0\;clr %C0";
+	    if (!AVR_HAVE_MOVW)
+	      return "swap %B0\;andi %B0,lo8(1<<(%3-8))\;"
+		     "clr %A0\;clr %C0\;clr %D0";
+	  }
+	if ((shift == 4 && IN_RANGE (obit, 20, 23))
+	    || (shift == -4 && IN_RANGE (obit, 16, 19)))
+	  {
+	    if (<SIZE> == 3)
+	      return "swap %C0\;andi %C0,lo8(1<<(%3-16))\;clr %A0\;clr %B0";
+	    if (!AVR_HAVE_MOVW)
+	      return "swap %C0\;andi %C0,lo8(1<<(%3-16))\;"
+		     "clr %A0\;clr %B0\;clr %D0";
+	  }
+	if (((shift == 4 && IN_RANGE (obit, 28, 31))
+	     || (shift == -4 && IN_RANGE (obit, 24, 27)))
+	    && !AVR_HAVE_MOVW)
+	  return "swap %D0\;andi %D0,lo8(1<<(%3-24))\;"
+		 "clr %A0\;clr %B0\;clr %C0";
+      }
+
     if (<SIZE> == 1) return "bst %T1%T2\;clr %0\;"                 "bld %T0%T3";
     if (<SIZE> == 2) return "bst %T1%T2\;clr %A0\;clr %B0\;"       "bld %T0%T3";
     if (<SIZE> == 3) return "bst %T1%T2\;clr %A0\;clr %B0\;clr %C0\;bld %T0%T3";
diff --git a/gcc/testsuite/gcc.target/avr/insvhi-1.c b/gcc/testsuite/gcc.target/avr/insvhi-1.c
new file mode 100644
index 000000000000..4468917b7696
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/insvhi-1.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+unsigned short foo(unsigned short x)
+{
+  return x & 1;
+}
+
+/* { dg-final { scan-assembler "andi r24,1" } } */
+/* { dg-final { scan-assembler "clr r25" } } */
diff --git a/gcc/testsuite/gcc.target/avr/insvhi-2.c b/gcc/testsuite/gcc.target/avr/insvhi-2.c
new file mode 100644
index 000000000000..6899fbd0b994
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/insvhi-2.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+unsigned short foo(unsigned short x)
+{
+  return (x >> 1) & 1;
+}
+
+/* { dg-final { scan-assembler "lsr r24" } } */
+/* { dg-final { scan-assembler "andi r24,lo8\\(1<<0\\)" } } */
+/* { dg-final { scan-assembler "clr r25" } } */
diff --git a/gcc/testsuite/gcc.target/avr/insvhi-3.c b/gcc/testsuite/gcc.target/avr/insvhi-3.c
new file mode 100644
index 000000000000..2d1d9f413dc5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/insvhi-3.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+unsigned short foo(unsigned short x)
+{
+  return (x >> 2) & 1;
+}
+
+/* { dg-final { scan-assembler "bst r24,2" } } */
+/* { dg-final { scan-assembler-times "clr r2\\d" 2 } } */
+/* { dg-final { scan-assembler "bld r24,0" } } */
diff --git a/gcc/testsuite/gcc.target/avr/insvhi-4.c b/gcc/testsuite/gcc.target/avr/insvhi-4.c
new file mode 100644
index 000000000000..6a36f4ca6112
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/insvhi-4.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+unsigned short foo(unsigned short x)
+{
+  return (x >> 4) & 1;
+}
+
+/* { dg-final { scan-assembler "swap r24" } } */
+/* { dg-final { scan-assembler "andi r24,lo8\\(1<<0\\)" } } */
+/* { dg-final { scan-assembler "clr r25" } } */
diff --git a/gcc/testsuite/gcc.target/avr/insvhi-5.c b/gcc/testsuite/gcc.target/avr/insvhi-5.c
new file mode 100644
index 000000000000..6a6e8684a2b2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/insvhi-5.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+unsigned short foo(unsigned short x)
+{
+  return (x >> 8) & 1;
+}
+
+/* { dg-final { scan-assembler "mov r24,r25" } } */
+/* { dg-final { scan-assembler "andi r24,1" } } */
+/* { dg-final { scan-assembler "ldi r25,0" } } */
diff --git a/gcc/testsuite/gcc.target/avr/insvqi-1.c b/gcc/testsuite/gcc.target/avr/insvqi-1.c
new file mode 100644
index 000000000000..32f53f226d81
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/insvqi-1.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+unsigned char foo(unsigned char x)
+{
+  return x & 1;
+}
+
+/* { dg-final { scan-assembler "andi r24,lo8\\(1\\)" } } */
diff --git a/gcc/testsuite/gcc.target/avr/insvqi-2.c b/gcc/testsuite/gcc.target/avr/insvqi-2.c
new file mode 100644
index 000000000000..b276b2b3b92f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/insvqi-2.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+unsigned char foo(unsigned char x)
+{
+  return (x>>1) & 1;
+}
+
+/* { dg-final { scan-assembler "lsr r24" } } */
+/* { dg-final { scan-assembler "andi r24,1" } } */
+
diff --git a/gcc/testsuite/gcc.target/avr/insvqi-3.c b/gcc/testsuite/gcc.target/avr/insvqi-3.c
new file mode 100644
index 000000000000..c28320f64c81
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/insvqi-3.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+unsigned char foo(unsigned char x)
+{
+  return (x>>2) & 1;
+}
+
+/* { dg-final { scan-assembler "bst r24,2" } } */
+/* { dg-final { scan-assembler "clr r24" } } */
+/* { dg-final { scan-assembler "bld r24,0" } } */
+
diff --git a/gcc/testsuite/gcc.target/avr/insvqi-4.c b/gcc/testsuite/gcc.target/avr/insvqi-4.c
new file mode 100644
index 000000000000..1ae7afe92a5b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/insvqi-4.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+unsigned char foo(unsigned char x)
+{
+  return (x>>4) & 1;
+}
+
+/* { dg-final { scan-assembler "swap r24" } } */
+/* { dg-final { scan-assembler "andi r24,1" } } */
+
diff --git a/gcc/testsuite/gcc.target/avr/insvsi-1.c b/gcc/testsuite/gcc.target/avr/insvsi-1.c
new file mode 100644
index 000000000000..e057a7a09183
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/insvsi-1.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+unsigned long foo(unsigned long x)
+{
+  return x & 1;
+}
+
+/* { dg-final { scan-assembler "andi r22,1" } } */
+/* { dg-final { scan-assembler-times "clr r2\\d" 3 } } */
diff --git a/gcc/testsuite/gcc.target/avr/insvsi-2.c b/gcc/testsuite/gcc.target/avr/insvsi-2.c
new file mode 100644
index 000000000000..518340322ce3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/insvsi-2.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+unsigned long foo(unsigned long x)
+{
+  return (x >> 1) & 1;
+}
+
+/* { dg-final { scan-assembler "lsr r22" } } */
+/* { dg-final { scan-assembler "andi r22,lo8\\(1<<0\\)" } } */
+/* { dg-final { scan-assembler-times "clr r2\\d" 3 } } */
diff --git a/gcc/testsuite/gcc.target/avr/insvsi-3.c b/gcc/testsuite/gcc.target/avr/insvsi-3.c
new file mode 100644
index 000000000000..c8d6e1a8ea23
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/insvsi-3.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+unsigned long foo(unsigned long x)
+{
+  return (x >> 2) & 1;
+}
+
+/* { dg-final { scan-assembler "bst r22,2" } } */
+/* { dg-final { scan-assembler-times "clr r2\\d" 4 } } */
+/* { dg-final { scan-assembler "bld r22,0" } } */
diff --git a/gcc/testsuite/gcc.target/avr/insvsi-4.c b/gcc/testsuite/gcc.target/avr/insvsi-4.c
new file mode 100644
index 000000000000..52a3a75203e2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/insvsi-4.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+unsigned long foo(unsigned long x)
+{
+  return (x >> 4) & 1;
+}
+
+/* { dg-final { scan-assembler "swap r22" } } */
+/* { dg-final { scan-assembler "andi r22,lo8\\(1<<0\\)" } } */
+/* { dg-final { scan-assembler-times "clr r2\\d" 3 } } */
diff --git a/gcc/testsuite/gcc.target/avr/insvsi-5.c b/gcc/testsuite/gcc.target/avr/insvsi-5.c
new file mode 100644
index 000000000000..627016a5ae66
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/insvsi-5.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+unsigned long foo(unsigned long x)
+{
+  return (x >> 8) & 1;
+}
+
+/* { dg-final { scan-assembler "mov r22,r23" } } */
+/* { dg-final { scan-assembler "andi r22,lo8\\(1<<0\\)" } } */
+/* { dg-final { scan-assembler-times "clr r2\\d" 3 } } */
diff --git a/gcc/testsuite/gcc.target/avr/insvsi-6.c b/gcc/testsuite/gcc.target/avr/insvsi-6.c
new file mode 100644
index 000000000000..6f72d6a74232
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/insvsi-6.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+unsigned long foo(unsigned long x)
+{
+  return (x >> 16) & 1;
+}
+
+/* { dg-final { scan-assembler "mov r22,r24" } } */
+/* { dg-final { scan-assembler "andi r22,lo8\\(1<<0\\)" } } */
+/* { dg-final { scan-assembler-times "clr r2\\d" 3 } } */
