diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index cdb6b5b1b580f57caab3135995e2082850b259b7..e7865bdf7b5ab69848854caaa8e1fe6a77a65f12 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,37 @@
+2016-12-26  Uros Bizjak  <ubizjak@gmail.com>
+
+	PR target/78904
+	* config/i386/i386.md (addqi_ext_1): Canonicalize insn pattern w.r.t.
+	zero_extract RTXes.
+	(*addqi_ext_2): Ditto.
+	(testqi_ext_ccno_0): Canonicalize expander w.r.t. zero_extract RTXes.
+	(testqi_ext_1_ccno): Rename from testqi_ext_ccno_0.
+	(*testqi_ext_0): Merge with *testqi_ext_1.
+	(*testqi_ext_1): Canonicalize insn pattern w.r.t. zero_extract RTXes.
+	Update corresponding splitter.
+	(*testqi_ext_2): Canonicalize insn pattern w.r.t. zero_extract RTXes.
+	(*andqi_ext_0): Merge with *andqi_ext_1.
+	(andqi_ext_1): Canonicalize insn pattern w.r.t. zero_extract RTXes.
+	Rename from *andqi_ext_1.  Update corresponding splitter and
+	peephole2 patterns.
+	(*andqi_ext_1_cc): Rename from *andqi_ext_0_cc.
+	(*andqi_ext_2): Canonicalize insn pattern w.r.t. zero_extract RTXes.
+	(*<any_or:code>qi_ext_0): Merge with *andqi_ext_1.
+	(*<any_or:code>qi_ext_1): Canonicalize insn pattern w.r.t.
+	zero_extract RTXes.  Update corresponding splitter.
+	(*<any_or:code>qi_ext_2): Canonicalize insn pattern w.r.t.
+	zero_extract RTXes.
+	(xorqi_cc_ext_1): Canonicalize expander w.r.t. zero_extract RTXes.
+	(xorqi_ext_1_cc): Rename from xorqi_cc_ext_1.
+	(*xorqi_cc_ext_1): Canonicalize insn pattern w.r.t. zero_extract RTXes.
+	Update corresponding splitter.
+	(*xorqi_ext_1_cc): Rename from *xorqi_cc_ext_1.
+	(isinfxf2): Update calls to renamed expanders.
+	(isinf<mode>2): Ditto.
+	* config/i386/i386.c (ix86_expand_fp_compare): Ditto.
+	(ix86_emit_fp_unordered_jump): Ditto.
+	(ix86_emit_i387_round): Ditto.
+
 2016-12-26  Eric Botcazou  <ebotcazou@adacore.com>
 
 	* doc/invoke.texi (SPARC options): Add missing documentation for -mlra.
@@ -89,7 +123,8 @@
 	(rs6000_option_optimization_table): Enable -fsched-pressure.
 	* config/rs6000/rs6000.c (TARGET_COMPUTE_PRESSURE_CLASSES): Define
 	target hook.
-	(rs6000_option_override_internal): Set default -fsched-pressure algorithm.
+	(rs6000_option_override_internal): Set default -fsched-pressure
+	algorithm.
 	(rs6000_compute_pressure_classes): Implement target hook.
 
 2016-12-21  Bill Seurer  <seurer@linux.vnet.ibm.com>
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 792e8ec232d29366c260efbceab67f65ea31e807..624f0699e660b18a8453eb46878cad5e094beb73 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -22585,12 +22585,12 @@ ix86_expand_fp_compare (enum rtx_code code, rtx op0, rtx op1, rtx scratch)
 	case UNGT:
 	  if (code == GT || !TARGET_IEEE_FP)
 	    {
-	      emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x45)));
+	      emit_insn (gen_testqi_ext_1_ccno (scratch, GEN_INT (0x45)));
 	      code = EQ;
 	    }
 	  else
 	    {
-	      emit_insn (gen_andqi_ext_0 (scratch, scratch, GEN_INT (0x45)));
+	      emit_insn (gen_andqi_ext_1 (scratch, scratch, GEN_INT (0x45)));
 	      emit_insn (gen_addqi_ext_1 (scratch, scratch, constm1_rtx));
 	      emit_insn (gen_cmpqi_ext_3 (scratch, GEN_INT (0x44)));
 	      intcmp_mode = CCmode;
@@ -22601,14 +22601,14 @@ ix86_expand_fp_compare (enum rtx_code code, rtx op0, rtx op1, rtx scratch)
 	case UNLT:
 	  if (code == LT && TARGET_IEEE_FP)
 	    {
-	      emit_insn (gen_andqi_ext_0 (scratch, scratch, GEN_INT (0x45)));
+	      emit_insn (gen_andqi_ext_1 (scratch, scratch, GEN_INT (0x45)));
 	      emit_insn (gen_cmpqi_ext_3 (scratch, const1_rtx));
 	      intcmp_mode = CCmode;
 	      code = EQ;
 	    }
 	  else
 	    {
-	      emit_insn (gen_testqi_ext_ccno_0 (scratch, const1_rtx));
+	      emit_insn (gen_testqi_ext_1_ccno (scratch, const1_rtx));
 	      code = NE;
 	    }
 	  break;
@@ -22616,13 +22616,13 @@ ix86_expand_fp_compare (enum rtx_code code, rtx op0, rtx op1, rtx scratch)
 	case UNGE:
 	  if (code == GE || !TARGET_IEEE_FP)
 	    {
-	      emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x05)));
+	      emit_insn (gen_testqi_ext_1_ccno (scratch, GEN_INT (0x05)));
 	      code = EQ;
 	    }
 	  else
 	    {
-	      emit_insn (gen_andqi_ext_0 (scratch, scratch, GEN_INT (0x45)));
-	      emit_insn (gen_xorqi_cc_ext_1 (scratch, scratch, const1_rtx));
+	      emit_insn (gen_andqi_ext_1 (scratch, scratch, GEN_INT (0x45)));
+	      emit_insn (gen_xorqi_ext_1_cc (scratch, scratch, const1_rtx));
 	      code = NE;
 	    }
 	  break;
@@ -22630,7 +22630,7 @@ ix86_expand_fp_compare (enum rtx_code code, rtx op0, rtx op1, rtx scratch)
 	case UNLE:
 	  if (code == LE && TARGET_IEEE_FP)
 	    {
-	      emit_insn (gen_andqi_ext_0 (scratch, scratch, GEN_INT (0x45)));
+	      emit_insn (gen_andqi_ext_1 (scratch, scratch, GEN_INT (0x45)));
 	      emit_insn (gen_addqi_ext_1 (scratch, scratch, constm1_rtx));
 	      emit_insn (gen_cmpqi_ext_3 (scratch, GEN_INT (0x40)));
 	      intcmp_mode = CCmode;
@@ -22638,7 +22638,7 @@ ix86_expand_fp_compare (enum rtx_code code, rtx op0, rtx op1, rtx scratch)
 	    }
 	  else
 	    {
-	      emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x45)));
+	      emit_insn (gen_testqi_ext_1_ccno (scratch, GEN_INT (0x45)));
 	      code = NE;
 	    }
 	  break;
@@ -22646,14 +22646,14 @@ ix86_expand_fp_compare (enum rtx_code code, rtx op0, rtx op1, rtx scratch)
 	case UNEQ:
 	  if (code == EQ && TARGET_IEEE_FP)
 	    {
-	      emit_insn (gen_andqi_ext_0 (scratch, scratch, GEN_INT (0x45)));
+	      emit_insn (gen_andqi_ext_1 (scratch, scratch, GEN_INT (0x45)));
 	      emit_insn (gen_cmpqi_ext_3 (scratch, GEN_INT (0x40)));
 	      intcmp_mode = CCmode;
 	      code = EQ;
 	    }
 	  else
 	    {
-	      emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x40)));
+	      emit_insn (gen_testqi_ext_1_ccno (scratch, GEN_INT (0x40)));
 	      code = NE;
 	    }
 	  break;
@@ -22661,24 +22661,24 @@ ix86_expand_fp_compare (enum rtx_code code, rtx op0, rtx op1, rtx scratch)
 	case LTGT:
 	  if (code == NE && TARGET_IEEE_FP)
 	    {
-	      emit_insn (gen_andqi_ext_0 (scratch, scratch, GEN_INT (0x45)));
-	      emit_insn (gen_xorqi_cc_ext_1 (scratch, scratch,
+	      emit_insn (gen_andqi_ext_1 (scratch, scratch, GEN_INT (0x45)));
+	      emit_insn (gen_xorqi_ext_1_cc (scratch, scratch,
 					     GEN_INT (0x40)));
 	      code = NE;
 	    }
 	  else
 	    {
-	      emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x40)));
+	      emit_insn (gen_testqi_ext_1_ccno (scratch, GEN_INT (0x40)));
 	      code = EQ;
 	    }
 	  break;
 
 	case UNORDERED:
-	  emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x04)));
+	  emit_insn (gen_testqi_ext_1_ccno (scratch, GEN_INT (0x04)));
 	  code = NE;
 	  break;
 	case ORDERED:
-	  emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x04)));
+	  emit_insn (gen_testqi_ext_1_ccno (scratch, GEN_INT (0x04)));
 	  code = EQ;
 	  break;
 
@@ -44370,7 +44370,7 @@ ix86_emit_fp_unordered_jump (rtx label)
     }
   else
     {
-      emit_insn (gen_testqi_ext_ccno_0 (reg, GEN_INT (0x04)));
+      emit_insn (gen_testqi_ext_1_ccno (reg, GEN_INT (0x04)));
 
       temp = gen_rtx_REG (CCNOmode, FLAGS_REG);
       temp = gen_rtx_NE (VOIDmode, temp, const0_rtx);
@@ -44528,7 +44528,7 @@ void ix86_emit_i387_round (rtx op0, rtx op1)
     }
 
   /* flags = signbit(a) */
-  emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x02)));
+  emit_insn (gen_testqi_ext_1_ccno (scratch, GEN_INT (0x02)));
 
   /* if (flags) then res = -res */
   tmp = gen_rtx_IF_THEN_ELSE (VOIDmode,
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index f50dbab42e9eb463b8544b9c2c29fefb61c7ee27..f3f358326ac446755c8811403527d57f3383e2a7 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -1345,7 +1345,6 @@
   "cmp{b}\t{%1, %h0|%h0, %1}"
   [(set_attr "isa" "*,nox64")
    (set_attr "type" "icmp")
-   (set_attr "modrm" "1")
    (set_attr "mode" "QI")])
 
 (define_insn "*cmpqi_ext_4"
@@ -6082,12 +6081,13 @@
   [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q,Q")
 			 (const_int 8)
 			 (const_int 8))
-	(plus:SI
-	  (zero_extract:SI
-	    (match_operand 1 "ext_register_operand" "0,0")
-	    (const_int 8)
-	    (const_int 8))
-	  (match_operand:QI 2 "general_x64nomem_operand" "Qn,m")))
+	(subreg:SI
+	  (plus:QI
+	    (subreg:QI
+	      (zero_extract:SI (match_operand 1 "ext_register_operand" "0,0")
+			       (const_int 8)
+			       (const_int 8)) 0)
+	    (match_operand:QI 2 "general_x64nomem_operand" "Qn,m")) 0))
    (clobber (reg:CC FLAGS_REG))]
   ""
 {
@@ -6111,23 +6111,23 @@
      (if_then_else (match_operand:QI 2 "incdec_operand")
 	(const_string "incdec")
 	(const_string "alu")))
-   (set_attr "modrm" "1")
    (set_attr "mode" "QI")])
 
 (define_insn "*addqi_ext_2"
   [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q")
 			 (const_int 8)
 			 (const_int 8))
-	(plus:SI
-	  (zero_extract:SI
-	    (match_operand 1 "ext_register_operand" "%0")
-	    (const_int 8)
-	    (const_int 8))
-	  (zero_extract:SI
-	    (match_operand 2 "ext_register_operand" "Q")
-	    (const_int 8)
-	    (const_int 8))))
-   (clobber (reg:CC FLAGS_REG))]
+	(subreg:SI
+	  (plus:QI
+	    (subreg:QI
+	      (zero_extract:SI (match_operand 1 "ext_register_operand" "%0")
+			       (const_int 8)
+			       (const_int 8)) 0)
+	    (subreg:QI
+	      (zero_extract:SI (match_operand 2 "ext_register_operand" "Q")
+			       (const_int 8)
+			       (const_int 8)) 0)) 0))
+  (clobber (reg:CC FLAGS_REG))]
   ""
   "add{b}\t{%h2, %h0|%h0, %h2}"
   [(set_attr "type" "alu")
@@ -7870,45 +7870,26 @@
    (set_attr "mode" "<MODE>")
    (set_attr "pent_pair" "uv,np,uv")])
 
-(define_expand "testqi_ext_ccno_0"
+(define_expand "testqi_ext_1_ccno"
   [(set (reg:CCNO FLAGS_REG)
 	(compare:CCNO
-	  (and:SI
-	    (zero_extract:SI
-	      (match_operand 0 "ext_register_operand")
-	      (const_int 8)
-	      (const_int 8))
-	    (match_operand 1 "const_int_operand"))
+	  (and:QI
+	    (subreg:QI
+	      (zero_extract:SI (match_operand 0 "ext_register_operand")
+			       (const_int 8)
+			       (const_int 8)) 0)
+	      (match_operand 1 "const_int_operand"))
 	  (const_int 0)))])
 
-(define_insn "*testqi_ext_0"
-  [(set (reg FLAGS_REG)
-	(compare
-	  (and:SI
-	    (zero_extract:SI
-	      (match_operand 0 "ext_register_operand" "Q")
-	      (const_int 8)
-	      (const_int 8))
-	    (match_operand 1 "const_int_operand" "n"))
-	  (const_int 0)))]
-  "ix86_match_ccmode (insn, CCNOmode)"
-  "test{b}\t{%1, %h0|%h0, %1}"
-  [(set_attr "type" "test")
-   (set_attr "mode" "QI")
-   (set_attr "length_immediate" "1")
-   (set_attr "modrm" "1")
-   (set_attr "pent_pair" "np")])
-
 (define_insn "*testqi_ext_1"
   [(set (reg FLAGS_REG)
 	(compare
-	  (and:SI
-	    (zero_extract:SI
-	      (match_operand 0 "ext_register_operand" "Q,Q")
-	      (const_int 8)
-	      (const_int 8))
-	    (zero_extend:SI
-	      (match_operand:QI 1 "nonimmediate_x64nomem_operand" "Q,m")))
+	  (and:QI
+	    (subreg:QI
+	      (zero_extract:SI (match_operand 0 "ext_register_operand" "Q,Q")
+			       (const_int 8)
+			       (const_int 8)) 0)
+	    (match_operand:QI 1 "general_x64nomem_operand" "Qn,m"))
 	  (const_int 0)))]
   "ix86_match_ccmode (insn, CCNOmode)"
   "test{b}\t{%1, %h0|%h0, %1}"
@@ -7919,15 +7900,15 @@
 (define_insn "*testqi_ext_2"
   [(set (reg FLAGS_REG)
 	(compare
-	  (and:SI
-	    (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)))
+	  (and:QI
+	    (subreg:QI
+	      (zero_extract:SI (match_operand 0 "ext_register_operand" "Q")
+			       (const_int 8)
+			       (const_int 8)) 0)
+	    (subreg:QI
+	      (zero_extract:SI (match_operand 1 "ext_register_operand" "Q")
+			       (const_int 8)
+			       (const_int 8)) 0))
 	  (const_int 0)))]
   "ix86_match_ccmode (insn, CCNOmode)"
   "test{b}\t{%h1, %h0|%h0, %h1}"
@@ -8029,12 +8010,16 @@
 	    && !(INTVAL (operands[3]) & ~(127 << 8))))"
   [(set (match_dup 0)
 	(match_op_dup 1
-	  [(and:SI (zero_extract:SI (match_dup 2) (const_int 8) (const_int 8))
-		   (match_dup 3))
+	  [(and:QI
+	     (subreg:QI
+	       (zero_extract:SI (match_dup 2)
+				(const_int 8)
+				(const_int 8)) 0)
+	     (match_dup 3))
 	   (const_int 0)]))]
 {
   operands[2] = gen_lowpart (SImode, operands[2]);
-  operands[3] = gen_int_mode (INTVAL (operands[3]) >> 8, SImode);
+  operands[3] = gen_int_mode (INTVAL (operands[3]) >> 8, QImode);
 })
 
 (define_split
@@ -8308,17 +8293,21 @@
    (clobber (reg:CC FLAGS_REG))]
   "(!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun))
    && reload_completed"
-  [(parallel [(set (zero_extract:SI (match_dup 0)
-				    (const_int 8)
-				    (const_int 8))
-		   (xor:SI
-		     (zero_extract:SI (match_dup 0)
-				      (const_int 8)
-				      (const_int 8))
-		     (zero_extract:SI (match_dup 0)
-				      (const_int 8)
-				      (const_int 8))))
-	      (clobber (reg:CC FLAGS_REG))])]
+  [(parallel
+     [(set (zero_extract:SI (match_dup 0)
+			    (const_int 8)
+			    (const_int 8))
+	   (subreg:SI
+	     (xor:QI
+	       (subreg:QI
+		 (zero_extract:SI (match_dup 0)
+				  (const_int 8)
+				  (const_int 8)) 0)
+	       (subreg:QI
+		 (zero_extract:SI (match_dup 0)
+				  (const_int 8)
+				  (const_int 8)) 0)) 0))
+      (clobber (reg:CC FLAGS_REG))])]
   "operands[0] = gen_lowpart (SImode, operands[0]);")
 
 (define_insn "*anddi_2"
@@ -8418,92 +8407,69 @@
   [(set_attr "type" "alu1")
    (set_attr "mode" "QI")])
 
-;; ??? A bug in recog prevents it from recognizing a const_int as an
-;; operand to zero_extend in andqi_ext_1.  It was checking explicitly
-;; for a QImode operand, which of course failed.
-(define_insn "andqi_ext_0"
-  [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q")
+(define_insn "andqi_ext_1"
+  [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q,Q")
 			 (const_int 8)
 			 (const_int 8))
-	(and:SI
-	  (zero_extract:SI
-	    (match_operand 1 "ext_register_operand" "0")
-	    (const_int 8)
-	    (const_int 8))
-	  (match_operand 2 "const_int_operand" "n")))
+	(subreg:SI
+	  (and:QI
+	    (subreg:QI
+	      (zero_extract:SI (match_operand 1 "ext_register_operand" "0,0")
+			       (const_int 8)
+			       (const_int 8)) 0)
+	    (match_operand:QI 2 "general_x64nomem_operand" "Qn,m")) 0))
    (clobber (reg:CC FLAGS_REG))]
   ""
   "and{b}\t{%2, %h0|%h0, %2}"
-  [(set_attr "type" "alu")
-   (set_attr "length_immediate" "1")
-   (set_attr "modrm" "1")
+  [(set_attr "isa" "*,nox64")
+   (set_attr "type" "alu")
    (set_attr "mode" "QI")])
 
 ;; Generated by peephole translating test to and.  This shows up
 ;; often in fp comparisons.
-(define_insn "*andqi_ext_0_cc"
+(define_insn "*andqi_ext_1_cc"
   [(set (reg FLAGS_REG)
 	(compare
-	  (and:SI
-	    (zero_extract:SI
-	      (match_operand 1 "ext_register_operand" "0")
-	      (const_int 8)
-	      (const_int 8))
+	  (and:QI
+	    (subreg:QI
+	      (zero_extract:SI (match_operand 1 "ext_register_operand" "0")
+			       (const_int 8)
+			       (const_int 8)) 0)
 	    (match_operand 2 "const_int_operand" "n"))
 	  (const_int 0)))
    (set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q")
 			 (const_int 8)
 			 (const_int 8))
-	(and:SI
-	  (zero_extract:SI
-	    (match_dup 1)
-	    (const_int 8)
-	    (const_int 8))
-	  (match_dup 2)))]
+	(subreg:SI
+	  (and:QI
+	    (subreg:QI
+	      (zero_extract:SI (match_dup 1)
+			       (const_int 8)
+			       (const_int 8)) 0)
+	    (match_dup 2)) 0))]
   "ix86_match_ccmode (insn, CCNOmode)"
   "and{b}\t{%2, %h0|%h0, %2}"
   [(set_attr "type" "alu")
-   (set_attr "length_immediate" "1")
-   (set_attr "modrm" "1")
-   (set_attr "mode" "QI")])
-
-(define_insn "*andqi_ext_1"
-  [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q,Q")
-			 (const_int 8)
-			 (const_int 8))
-	(and:SI
-	  (zero_extract:SI
-	    (match_operand 1 "ext_register_operand" "0,0")
-	    (const_int 8)
-	    (const_int 8))
-	  (zero_extend:SI
-	    (match_operand:QI 2 "nonimmediate_x64nomem_operand" "Q,m"))))
-   (clobber (reg:CC FLAGS_REG))]
-  ""
-  "and{b}\t{%2, %h0|%h0, %2}"
-  [(set_attr "isa" "*,nox64")
-   (set_attr "type" "alu")
-   (set_attr "length_immediate" "0")
    (set_attr "mode" "QI")])
 
 (define_insn "*andqi_ext_2"
   [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q")
 			 (const_int 8)
 			 (const_int 8))
-	(and:SI
-	  (zero_extract:SI
-	    (match_operand 1 "ext_register_operand" "%0")
-	    (const_int 8)
-	    (const_int 8))
-	  (zero_extract:SI
-	    (match_operand 2 "ext_register_operand" "Q")
-	    (const_int 8)
-	    (const_int 8))))
+	(subreg:SI
+	  (and:QI
+	    (subreg:QI
+	      (zero_extract:SI (match_operand 1 "ext_register_operand" "%0")
+			       (const_int 8)
+			       (const_int 8)) 0)
+	    (subreg:QI
+	      (zero_extract:SI (match_operand 2 "ext_register_operand" "Q")
+			       (const_int 8)
+			       (const_int 8)) 0)) 0))
    (clobber (reg:CC FLAGS_REG))]
   ""
   "and{b}\t{%h2, %h0|%h0, %h2}"
   [(set_attr "type" "alu")
-   (set_attr "length_immediate" "0")
    (set_attr "mode" "QI")])
 
 ;; Convert wide AND instructions with immediate operand to shorter QImode
@@ -8519,15 +8485,22 @@
    "reload_completed
     && (!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun))
     && !(~INTVAL (operands[2]) & ~(255 << 8))"
-  [(parallel [(set (zero_extract:SI (match_dup 0) (const_int 8) (const_int 8))
-		   (and:SI (zero_extract:SI (match_dup 1)
-					    (const_int 8) (const_int 8))
-			   (match_dup 2)))
-	      (clobber (reg:CC FLAGS_REG))])]
+  [(parallel
+     [(set (zero_extract:SI (match_dup 0)
+			    (const_int 8)
+			    (const_int 8))
+	   (subreg:SI
+	     (and:QI
+	       (subreg:QI
+		 (zero_extract:SI (match_dup 1)
+				  (const_int 8)
+				  (const_int 8)) 0)
+	       (match_dup 2)) 0))
+      (clobber (reg:CC FLAGS_REG))])]
 {
   operands[0] = gen_lowpart (SImode, operands[0]);
   operands[1] = gen_lowpart (SImode, operands[1]);
-  operands[2] = gen_int_mode ((INTVAL (operands[2]) >> 8) & 0xff, SImode);
+  operands[2] = gen_int_mode (INTVAL (operands[2]) >> 8, QImode);
 })
 
 ;; Since AND can be encoded with sign extended immediate, this is only
@@ -8820,59 +8793,42 @@
   [(set_attr "type" "alu")
    (set_attr "mode" "<MODE>")])
 
-(define_insn "*<code>qi_ext_0"
-  [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q")
-			 (const_int 8)
-			 (const_int 8))
-	(any_or:SI
-	  (zero_extract:SI
-	    (match_operand 1 "ext_register_operand" "0")
-	    (const_int 8)
-	    (const_int 8))
-	  (match_operand 2 "const_int_operand" "n")))
-   (clobber (reg:CC FLAGS_REG))]
-  "!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)"
-  "<logic>{b}\t{%2, %h0|%h0, %2}"
-  [(set_attr "type" "alu")
-   (set_attr "length_immediate" "1")
-   (set_attr "modrm" "1")
-   (set_attr "mode" "QI")])
-
 (define_insn "*<code>qi_ext_1"
   [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q,Q")
 			 (const_int 8)
 			 (const_int 8))
-	(any_or:SI
-	  (zero_extract:SI
-	    (match_operand 1 "ext_register_operand" "0,0")
-	    (const_int 8)
-	    (const_int 8))
-	  (zero_extend:SI
-	    (match_operand:QI 2 "nonimmediate_x64nomem_operand" "Q,m"))))
+	(subreg:SI
+	  (any_or:QI
+	    (subreg:QI
+	      (zero_extract:SI (match_operand 1 "ext_register_operand" "0,0")
+			       (const_int 8)
+			       (const_int 8)) 0)
+	    (match_operand:QI 2 "general_x64nomem_operand" "Qn,m")) 0))
    (clobber (reg:CC FLAGS_REG))]
   "!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)"
   "<logic>{b}\t{%2, %h0|%h0, %2}"
   [(set_attr "isa" "*,nox64")
    (set_attr "type" "alu")
-   (set_attr "length_immediate" "0")
    (set_attr "mode" "QI")])
 
 (define_insn "*<code>qi_ext_2"
   [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q")
 			 (const_int 8)
 			 (const_int 8))
-	(any_or:SI
-	  (zero_extract:SI (match_operand 1 "ext_register_operand" "0")
-	  		   (const_int 8)
-			   (const_int 8))
-	  (zero_extract:SI (match_operand 2 "ext_register_operand" "Q")
-	  		   (const_int 8)
-			   (const_int 8))))
+	(subreg:SI
+	  (any_or:QI
+	    (subreg:QI
+	      (zero_extract:SI (match_operand 1 "ext_register_operand" "%0")
+			       (const_int 8)
+			       (const_int 8)) 0)
+	    (subreg:QI
+	      (zero_extract:SI (match_operand 2 "ext_register_operand" "Q")
+			       (const_int 8)
+			       (const_int 8)) 0)) 0))
    (clobber (reg:CC FLAGS_REG))]
   "!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)"
   "<logic>{b}\t{%h2, %h0|%h0, %h2}"
   [(set_attr "type" "alu")
-   (set_attr "length_immediate" "0")
    (set_attr "mode" "QI")])
 
 ;; Convert wide OR instructions with immediate operand to shorter QImode
@@ -8888,15 +8844,22 @@
    "reload_completed
     && (!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun))
     && !(INTVAL (operands[2]) & ~(255 << 8))"
-  [(parallel [(set (zero_extract:SI (match_dup 0) (const_int 8) (const_int 8))
-		   (any_or:SI (zero_extract:SI (match_dup 1)
-					       (const_int 8) (const_int 8))
-			      (match_dup 2)))
-	      (clobber (reg:CC FLAGS_REG))])]
+  [(parallel
+     [(set (zero_extract:SI (match_dup 0)
+			    (const_int 8)
+			    (const_int 8))
+	   (subreg:SI
+	     (any_or:QI
+	       (subreg:QI
+		 (zero_extract:SI (match_dup 1)
+				  (const_int 8)
+				  (const_int 8)) 0)
+	       (match_dup 2)) 0))
+      (clobber (reg:CC FLAGS_REG))])]
 {
   operands[0] = gen_lowpart (SImode, operands[0]);
   operands[1] = gen_lowpart (SImode, operands[1]);
-  operands[2] = gen_int_mode ((INTVAL (operands[2]) >> 8) & 0xff, SImode);
+  operands[2] = gen_int_mode (INTVAL (operands[2]) >> 8, QImode);
 })
 
 ;; Since OR can be encoded with sign extended immediate, this is only
@@ -8920,51 +8883,52 @@
   operands[2] = gen_lowpart (QImode, operands[2]);
 })
 
-(define_expand "xorqi_cc_ext_1"
+(define_expand "xorqi_ext_1_cc"
   [(parallel [
      (set (reg:CCNO FLAGS_REG)
 	  (compare:CCNO
-	    (xor:SI
-	      (zero_extract:SI
-		(match_operand 1 "ext_register_operand")
-		(const_int 8)
-		(const_int 8))
-	      (match_operand:QI 2 "const_int_operand"))
+	    (xor:QI
+	      (subreg:QI
+		(zero_extract:SI (match_operand 1 "ext_register_operand")
+				 (const_int 8)
+				 (const_int 8)) 0)
+	      (match_operand 2 "const_int_operand"))
 	    (const_int 0)))
      (set (zero_extract:SI (match_operand 0 "ext_register_operand")
 			   (const_int 8)
 			   (const_int 8))
-	  (xor:SI
-	    (zero_extract:SI
-	     (match_dup 1)
-	     (const_int 8)
-	     (const_int 8))
-	    (match_dup 2)))])])
-
-(define_insn "*xorqi_cc_ext_1"
+	  (subreg:SI
+	    (xor:QI
+	      (subreg:QI
+		(zero_extract:SI (match_dup 1)
+				 (const_int 8)
+				 (const_int 8)) 0)
+	    (match_dup 2)) 0))])])
+
+(define_insn "*xorqi_ext_1_cc"
   [(set (reg FLAGS_REG)
 	(compare
-	  (xor:SI
-	    (zero_extract:SI
-	      (match_operand 1 "ext_register_operand" "0,0")
-	      (const_int 8)
-	      (const_int 8))
+	  (xor:QI
+	    (subreg:QI
+	      (zero_extract:SI (match_operand 1 "ext_register_operand" "0,0")
+			       (const_int 8)
+			       (const_int 8)) 0)
 	    (match_operand:QI 2 "general_x64nomem_operand" "Qn,m"))
 	  (const_int 0)))
    (set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q,Q")
 			 (const_int 8)
 			 (const_int 8))
-	(xor:SI
-	  (zero_extract:SI
-	   (match_dup 1)
-	   (const_int 8)
-	   (const_int 8))
-	  (match_dup 2)))]
+	(subreg:SI
+	  (xor:QI
+	    (subreg:QI
+	      (zero_extract:SI (match_dup 1)
+			       (const_int 8)
+			       (const_int 8)) 0)
+	  (match_dup 2)) 0))]
   "ix86_match_ccmode (insn, CCNOmode)"
   "xor{b}\t{%2, %h0|%h0, %2}"
   [(set_attr "isa" "*,nox64")
    (set_attr "type" "alu")
-   (set_attr "modrm" "1")
    (set_attr "mode" "QI")])
 
 ;; Negation instructions
@@ -16098,7 +16062,7 @@
 
   emit_insn (gen_fxamxf2_i387 (scratch, operands[1]));
 
-  emit_insn (gen_andqi_ext_0 (scratch, scratch, mask));
+  emit_insn (gen_andqi_ext_1 (scratch, scratch, mask));
   emit_insn (gen_cmpqi_ext_3 (scratch, val));
   ix86_expand_setcc (res, EQ,
 		     gen_rtx_REG (CCmode, FLAGS_REG), const0_rtx);
@@ -16130,7 +16094,7 @@
       emit_insn (gen_fxam<mode>2_i387_with_temp (scratch, temp));
     }
 
-  emit_insn (gen_andqi_ext_0 (scratch, scratch, mask));
+  emit_insn (gen_andqi_ext_1 (scratch, scratch, mask));
   emit_insn (gen_cmpqi_ext_3 (scratch, val));
   ix86_expand_setcc (res, EQ,
 		     gen_rtx_REG (CCmode, FLAGS_REG), const0_rtx);
@@ -17851,35 +17815,37 @@
 (define_peephole2
   [(set (match_operand 0 "flags_reg_operand")
 	(match_operator 1 "compare_operator"
-	  [(and:SI
-	     (zero_extract:SI
-	       (match_operand 2 "QIreg_operand")
-	       (const_int 8)
-	       (const_int 8))
+	  [(and:QI
+	     (subreg:QI
+	       (zero_extract:SI (match_operand 2 "QIreg_operand")
+				(const_int 8)
+				(const_int 8)) 0)
 	     (match_operand 3 "const_int_operand"))
 	   (const_int 0)]))]
   "! TARGET_PARTIAL_REG_STALL
    && ix86_match_ccmode (insn, CCNOmode)
    && REGNO (operands[2]) != AX_REG
    && peep2_reg_dead_p (1, operands[2])"
-  [(parallel [(set (match_dup 0)
-		   (match_op_dup 1
-		     [(and:SI
-			(zero_extract:SI
-			  (match_dup 2)
-			  (const_int 8)
-			  (const_int 8))
-			(match_dup 3))
-		      (const_int 0)]))
-	      (set (zero_extract:SI (match_dup 2)
-				    (const_int 8)
-				    (const_int 8))
-		   (and:SI
-		     (zero_extract:SI
-		       (match_dup 2)
-		       (const_int 8)
-		       (const_int 8))
-		     (match_dup 3)))])])
+  [(parallel
+     [(set (match_dup 0)
+	   (match_op_dup 1
+	     [(and:QI
+		(subreg:QI
+		  (zero_extract:SI (match_dup 2)
+				   (const_int 8)
+				   (const_int 8)) 0)
+		(match_dup 3))
+	      (const_int 0)]))
+      (set (zero_extract:SI (match_dup 2)
+			    (const_int 8)
+			    (const_int 8))
+		   (subreg:SI
+		     (and:QI
+		       (subreg:QI
+			 (zero_extract:SI (match_dup 2)
+		  	  	  	  (const_int 8)
+		  	  	  	  (const_int 8)) 0)
+		     (match_dup 3)) 0))])])
 
 ;; Don't do logical operations with memory inputs.
 (define_peephole2
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 969c896af40bb7983b61a5b1438fc8692c65fae3..31f0e4345839b8c066b37d2468ece6c7f921ec93 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2016-12-26  Uros Bizjak  <ubizjak@gmail.com>
+
+	PR target/78904
+	* gcc.target/i386/pr78904.c: New test.
+
 2016-12-23  Andre Vehreschild  <vehre@gcc.gnu.org>
 
 	* gfortran.dg/class_assign_1.f08: New test.
diff --git a/gcc/testsuite/gcc.target/i386/pr78904.c b/gcc/testsuite/gcc.target/i386/pr78904.c
new file mode 100644
index 0000000000000000000000000000000000000000..d27d7fd651d0d548e6ef5a1fcdf50345b51cd712
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78904.c
@@ -0,0 +1,48 @@
+/* PR target/78904 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -masm=att" } */
+/* { dg-final { scan-assembler-not "movzbl" } } */
+/* { dg-final { scan-assembler-not "movb" } } */
+
+struct S1
+{
+  unsigned char pad1;
+  unsigned char val;
+  unsigned short pad2;
+};
+
+struct S1 test_and (struct S1 a, struct S1 b)
+{
+  a.val &= b.val;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]andb" } } */
+
+struct S1 test_or (struct S1 a, struct S1 b)
+{
+  a.val |= b.val;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]orb" } } */
+
+struct S1 test_xor (struct S1 a, struct S1 b)
+{
+  a.val ^= b.val;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]xorb" } } */
+
+struct S1 test_add (struct S1 a, struct S1 b)
+{
+  a.val += b.val;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]addb" } } */