diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6226a1bfa63990aa392717ad011aa44829ecddbb..31aac2bdbf15c418bcac4e24f58a1621051f6152 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,14 @@
+2017-01-02  Uros Bizjak  <ubizjak@gmail.com>
+
+	PR target/78967
+	* config/i386/i386.md (UNSPEC_NOREX_MEM): New unspec.
+	(*insvqi_1): New insn pattern.
+	(*insvqi_1_mem_rex64): Ditto.
+	(*insvqi_2): Ditto.
+	(*insvqi_3): Rename from *insvqi.
+
+	(*extzvqi_mem_rex64): Add UNSPEC_NOREX_MEM tag.
+
 2017-01-02  Gerald Pfeifer  <gerald@pfeifer.com>
 
 	* doc/cfg.texi (Edges): Remove reference to Java.
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 511d3a77f2c521018b36f265fc62793b1776e1d8..c947955b9aa3631999f135ac3c97ae62e620f7ad 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -114,6 +114,7 @@
   UNSPEC_STOS
   UNSPEC_PEEPSIB
   UNSPEC_INSN_FALSE_DEP
+  UNSPEC_NOREX_MEM
 
   ;; For SSE/MMX support:
   UNSPEC_FIX_NOTRUNC
@@ -2819,7 +2820,8 @@
 	(subreg:QI
 	  (zero_extract:SI (match_operand 1 "ext_register_operand" "Q")
 			   (const_int 8)
-			   (const_int 8)) 0))]
+			   (const_int 8)) 0))
+   (unspec [(const_int 0)] UNSPEC_NOREX_MEM)]
   "TARGET_64BIT && reload_completed"
   "mov{b}\t{%h1, %0|%0, %h1}"
   [(set_attr "type" "imov")
@@ -2862,11 +2864,13 @@
    (set (match_operand:QI 2 "norex_memory_operand") (match_dup 0))]
   "TARGET_64BIT
    && peep2_reg_dead_p (2, operands[0])"
-  [(set (match_dup 2)
-	(subreg:QI
-	  (zero_extract:SI (match_dup 1)
-			   (const_int 8)
-			   (const_int 8)) 0))])
+  [(parallel
+     [(set (match_dup 2)
+	   (subreg:QI
+	     (zero_extract:SI (match_dup 1)
+			      (const_int 8)
+			      (const_int 8)) 0))
+      (unspec [(const_int 0)] UNSPEC_NOREX_MEM)])])
 
 (define_expand "insv<mode>"
   [(set (zero_extract:SWI248 (match_operand:SWI248 0 "register_operand")
@@ -2916,7 +2920,59 @@
    (set_attr "type" "imov")
    (set_attr "mode" "QI")])
 
-(define_insn "*insvqi"
+(define_insn "*insvqi_1_mem_rex64"
+  [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "+Q")
+			 (const_int 8)
+			 (const_int 8))
+	(subreg:SI
+	  (match_operand:QI 1 "norex_memory_operand" "Bn") 0))
+   (unspec [(const_int 0)] UNSPEC_NOREX_MEM)]
+  "TARGET_64BIT && reload_completed"
+  "mov{b}\t{%1, %h0|%h0, %1}"
+  [(set_attr "type" "imov")
+   (set_attr "mode" "QI")])
+
+(define_insn "*insvqi_1"
+  [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "+Q,Q")
+			 (const_int 8)
+			 (const_int 8))
+	(subreg:SI
+	  (match_operand:QI 1 "general_operand" "QnBc,m") 0))]
+  ""
+  "mov{b}\t{%1, %h0|%h0, %1}"
+  [(set_attr "isa" "*,nox64")
+   (set_attr "type" "imov")
+   (set_attr "mode" "QI")])
+
+(define_peephole2
+  [(set (match_operand:QI 0 "register_operand")
+	(match_operand:QI 1 "norex_memory_operand"))
+   (set (zero_extract:SI (match_operand 2 "ext_register_operand")
+			 (const_int 8)
+			 (const_int 8))
+	(subreg:SI (match_dup 0) 0))]
+  "TARGET_64BIT
+   && peep2_reg_dead_p (2, operands[0])"
+  [(parallel
+     [(set (zero_extract:SI (match_dup 2)
+			    (const_int 8)
+			    (const_int 8))
+	   (subreg:SI (match_dup 1) 0))
+      (unspec [(const_int 0)] UNSPEC_NOREX_MEM)])])
+
+(define_insn "*insvqi_2"
+  [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "+Q")
+			 (const_int 8)
+			 (const_int 8))
+	(zero_extract:SI (match_operand 1 "ext_register_operand" "Q")
+			 (const_int 8)
+			 (const_int 8)))]
+  ""
+  "mov{b}\t{%h1, %h0|%h0, %h1}"
+  [(set_attr "type" "imov")
+   (set_attr "mode" "QI")])
+
+(define_insn "*insvqi_3"
   [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "+Q")
 			 (const_int 8)
 			 (const_int 8))
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index f1d43c23b45f58da3fb0ea80ad330ca4238ce0da..8155754f847877b23300d8902f8774797dcdc21f 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,14 @@
+2017-01-02  Uros Bizjak  <ubizjak@gmail.com>
+
+	PR target/78967
+	* gcc.target/i386/pr78967-1.c: New test.
+	* gcc.target/i386/pr78967-2.c: Ditto.
+	* gcc.target/i386/pr78967-3.c: Ditto.
+
+	* gcc.target/i386/pr78904-2.c: Tighten scan-asm patterns.
+	* gcc.target/i386/pr78904-4.c: Ditto.
+	* gcc.target/i386/pr78904-6.c: Ditto.
+
 2017-01-01  Jan Hubicka  <hubicka@ucw.cz>
 
 	PR middle-end/77674
diff --git a/gcc/testsuite/gcc.target/i386/pr78904-2.c b/gcc/testsuite/gcc.target/i386/pr78904-2.c
index c7b161d6c80918b8d18f72bb812adc3b26622611..a8adfa1b717872daf39ada5953e7bdac83a9598f 100644
--- a/gcc/testsuite/gcc.target/i386/pr78904-2.c
+++ b/gcc/testsuite/gcc.target/i386/pr78904-2.c
@@ -18,7 +18,7 @@ struct S1 test_and (struct S1 a)
   return a;
 }
 
-/* { dg-final { scan-assembler "\[ \t\]andb\[^\n\r]*, %.h" } } */
+/* { dg-final { scan-assembler "\[ \t\]andb\[ \t\]+t\[^\n\r]*, %.h" } } */
 
 struct S1 test_or (struct S1 a)
 {
@@ -27,7 +27,7 @@ struct S1 test_or (struct S1 a)
   return a;
 }
 
-/* { dg-final { scan-assembler "\[ \t\]orb\[^\n\r]*, %.h" } } */
+/* { dg-final { scan-assembler "\[ \t\]orb\[ \t\]+t\[^\n\r]*, %.h" } } */
 
 struct S1 test_xor (struct S1 a)
 {
@@ -36,7 +36,7 @@ struct S1 test_xor (struct S1 a)
   return a;
 }
 
-/* { dg-final { scan-assembler "\[ \t\]xorb\[^\n\r]*, %.h" } } */
+/* { dg-final { scan-assembler "\[ \t\]xorb\[ \t\]+t\[^\n\r]*, %.h" } } */
 
 struct S1 test_add (struct S1 a)
 {
@@ -45,4 +45,4 @@ struct S1 test_add (struct S1 a)
   return a;
 }
 
-/* { dg-final { scan-assembler "\[ \t\]addb\[^\n\r]*, %.h" } } */
+/* { dg-final { scan-assembler "\[ \t\]addb\[ \t\]+t\[^\n\r]*, %.h" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr78904-4.c b/gcc/testsuite/gcc.target/i386/pr78904-4.c
index d110c2eec8631f3cf9eefe09135f303c96bc9e76..5d957926fff37f7ae85caf2666d1bc8c863edf3f 100644
--- a/gcc/testsuite/gcc.target/i386/pr78904-4.c
+++ b/gcc/testsuite/gcc.target/i386/pr78904-4.c
@@ -18,4 +18,4 @@ void foo (struct S1 a, size_t i)
   t[i] = a.val;
 }
 
-/* { dg-final { scan-assembler "\[ \t\]movb\[\t \]*%.h," } } */
+/* { dg-final { scan-assembler "\[ \t\]movb\[\t \]+%.h, t" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr78904-6.c b/gcc/testsuite/gcc.target/i386/pr78904-6.c
index 2fad2239a33f32386ee6a37764b69379155fa3c0..da241479787d02f01ffe47103a828b995062414c 100644
--- a/gcc/testsuite/gcc.target/i386/pr78904-6.c
+++ b/gcc/testsuite/gcc.target/i386/pr78904-6.c
@@ -18,4 +18,4 @@ void foo (struct S1 a, size_t i)
   t[i] = a.val;
 }
 
-/* { dg-final { scan-assembler "\[ \t\]movb\[\t \]*%.h," } } */
+/* { dg-final { scan-assembler "\[ \t\]movb\[\t \]*%.h, t" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr78967-1.c b/gcc/testsuite/gcc.target/i386/pr78967-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..79e3a35c464ec355c11b5e4aeb11bcbba5166918
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78967-1.c
@@ -0,0 +1,21 @@
+/* PR target/78967 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -masm=att" } */
+/* { dg-additional-options "-mregparm=3" { target ia32 } } */
+/* { dg-final { scan-assembler-not "movzbl" } } */
+
+struct S1
+{
+  unsigned char pad1;
+  unsigned char val;
+  unsigned short pad2;
+};
+
+struct S1 foo (struct S1 a, struct S1 b)
+{
+  a.val = b.val;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]movb\[ \t\]+%.h, %.h" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr78967-2.c b/gcc/testsuite/gcc.target/i386/pr78967-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..4f30ea7c52d39e88c7c1d01614f361e7b25fd904
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78967-2.c
@@ -0,0 +1,24 @@
+/* PR target/78967 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -masm=att" } */
+/* { dg-final { scan-assembler-not "movzbl" } } */
+
+typedef __SIZE_TYPE__ size_t;
+
+struct S1
+{
+  unsigned char pad1;
+  unsigned char val;
+  unsigned short pad2;
+};
+
+extern unsigned char t[256];
+
+struct S1 foo (struct S1 a, size_t i)
+{
+  a.val = t[i];
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]movb\[ \t\]+t\[^\n\r]*, %.h" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr78967-3.c b/gcc/testsuite/gcc.target/i386/pr78967-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..b69f409d7efdda3d3fdc0eda07479a372ce179b1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78967-3.c
@@ -0,0 +1,24 @@
+/* PR target/78967 */
+/* { dg-do assemble { target { ! ia32 } } } */
+/* { dg-options "-O2" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+struct S1
+{
+  unsigned char pad1;
+  unsigned char val;
+  unsigned short pad2;
+};
+
+extern unsigned char t[256];
+
+struct S1 foo (struct S1 a, size_t i)
+{
+  register size_t _i __asm ("r10") = i;
+
+  asm volatile ("" : "+r" (_i));
+  a.val = t[_i];
+
+  return a;
+}