i386: Fix mode of ZERO_EXTRACT RTXes, remove ext_register_operand predicate.

Message ID CAFULd4Y2WfdYdirr9_4Q1n_cb5rzWA_yS0Q385J3NJEcZgk73Q@mail.gmail.com
State New
Headers show
Series
  • i386: Fix mode of ZERO_EXTRACT RTXes, remove ext_register_operand predicate.
Related show

Commit Message

Jakub Jelinek via Gcc-patches June 18, 2020, 6:16 p.m.
The mode of ZERO_EXTRACT RTX should match the mode of its LOC register
operand.  The mode should be HI, SI or DImode to enable combine to synthesize
extractions from HImode and DImode operands, in addition to existing SImode.
Further, these changes tighten allowed modes for extv, extzv and insv
named patterns and finally enable removal of ext_register_operand
special predicate.

2020-18-06  UroŇ° Bizjak  <ubizjak@gmail.com>

gcc/ChangeLog:

    * config/i386/i386.md (*cmpqi_ext<mode>_1): Use SWI248 mode
    iterator instead of SImode for ZERO_EXTRACT RTX.  Use SWI248
    mode iterator for the first operand of ZERO_EXTRACT RTX.
    Change ext_register_operand predicate to register_operand.
    Rename from *cmpqi_ext_1.
    (*cmpqi_ext<mode>_2): Ditto.  Rename from *cmpqi_ext_2.
    (*cmpqi_ext<mode>_3): Ditto.  Rename from *cmpqi_ext_3.
    (*cmpqi_ext<mode>_4): Ditto.  Rename from *cmpqi_ext_4.
    (cmpi_ext_3): Use HImode instead of SImode for ZERO_EXTRACT RTX.
    (*extv<mode>): Use SWI24 mode iterator for the first operand
    of ZERO_EXTRACT RTX.  Change ext_register_operand predicate
    to register_operand.
    (*extzv<mode>): Use SWI248 mode iterator for the first operand
    of ZERO_EXTRACT RTX.  Change ext_register_operand predicate
    to register_operand.
    (*extzvqi): Use SWI248 mode iterator instead of SImode for
    ZERO_EXTRACT RTX.  Use SWI248 mode iterator for the first operand
    of ZERO_EXTRACT RTX.  Change ext_register_operand predicate to
    register_operand.
    (*extzvqi_mem_rex64 and corresponding peephole2):  Use SWI248 mode
    iterator instead of SImode for ZERO_EXTRACT RTX.  Use SWI248
    mode iterator for the first operand of ZERO_EXTRACT RTX.
    Change ext_register_operand predicate to register_operand.
    (@insv<mode>_1): Use SWI248 mode iterator for the first operand
    of ZERO_EXTRACT RTX.  Change ext_register_operand predicate to
    register_operand.
    (*insvqi_1): Use SWI248 mode iterator instead of SImode
    for ZERO_EXTRACT RTX.  Use SWI248 mode iterator for the
    first operand of ZERO_EXTRACT RTX.  Change ext_register_operand
    predicate to register_operand.
    (*insvqi_2): Ditto.
    (*insvqi_3): Ditto.
    (*insvqi_1_mem_rex64 and corresponding peephole2):  Use SWI248 mode
    iterator instead of SImode for ZERO_EXTRACT RTX.  Use SWI248
    mode iterator for the first operand of ZERO_EXTRACT RTX.
    Change ext_register_operand predicate to register_operand.
    (addqi_ext_1): New expander.
    (*addqi_ext<mode>_1): Use SWI248 mode iterator instead of SImode
    for ZERO_EXTRACT RTX.  Use SWI248 mode iterator for the first
    operand of ZERO_EXTRACT RTX.  Change ext_register_operand predicate
    to register_operand.  Rename from *addqi_ext_1.
    (*addqi_ext<mode>_2): Ditto. Rename from *addqi_ext_2.
    (divmodqi4): Use HImode instead of SImode for ZERO_EXTRACT RTX.
    (udivmodqi4): Ditto.
    (testqi_ext_1): Use HImode instead of SImode for ZERO_EXTRACT RTX.
    (*testqi_ext<mode>_1): Use SWI248 mode iterator instead of SImode
    for ZERO_EXTRACT RTX.  Use SWI248 mode iterator for the first
    operand of ZERO_EXTRACT RTX.  Change ext_register_operand predicate
    to register_operand.  Rename from *testqi_ext_1.
    (*testqi_ext<mode>_2): Ditto.  Rename from *testqi_ext_2.
    (andqi_ext_1): New expander.
    (*andqi_ext<mode>_1): Use SWI248 mode iterator instead of SImode
    for ZERO_EXTRACT RTX.  Use SWI248 mode iterator for the first
    operand of ZERO_EXTRACT RTX.  Change ext_register_operand predicate
    to register_operand.  Rename from andqi_ext_1.
    (*andqi_ext<mode>_1_cc): Ditto.  Rename from *andqi_ext_1_cc.
    (*andqi_ext<mode>_2): Ditto.  Rename from *andqi_ext_2.
    (*<code>qi_ext<mode>_1): Ditto.  Rename from *<code>qi_ext_1.
    (*<code>qi_ext<mode>_2): Ditto.  Rename from *<code>qi_ext_2.
    (xorqi_ext_1_cc): Use HImode instead of SImode for ZERO_EXTRACT RTX.
    (*xorqi_ext<mode>_1_cc):  Use SWI248 mode iterator instead of SImode
    for ZERO_EXTRACT RTX.  Use SWI248 mode iterator for the first
    operand of ZERO_EXTRACT RTX.  Change ext_register_operand predicate
    to register_operand.  Rename from *xorqi_ext_1_cc.
    * config/i386/i386-expand.c (ix86_split_idivmod): Emit ZERO_EXTRACT
    in mode, matching its first operand.
    (promote_duplicated_reg): Update for renamed insv<mode>_1.
    * config/i386/predicates.md (ext_register_operand): Remove predicate.

gcc/testsuite/ChangeLog:

    * gcc.target/i386/pr78904-1a.c: New test.
    * gcc.target/i386/pr78904-1b.c: Ditto.
    * gcc.target/i386/pr78904-2a.c: Ditto.
    * gcc.target/i386/pr78904-2b.c: Ditto.
    * gcc.target/i386/pr78904-3a.c: Ditto.
    * gcc.target/i386/pr78904-3b.c: Ditto.
    * gcc.target/i386/pr78904-4a.c: Ditto.
    * gcc.target/i386/pr78904-4b.c: Ditto.
    * gcc.target/i386/pr78904-5a.c: Ditto.
    * gcc.target/i386/pr78904-5b.c: Ditto.
    * gcc.target/i386/pr78904-6a.c: Ditto.
    * gcc.target/i386/pr78904-6b.c: Ditto.
    * gcc.target/i386/pr78967-1a.c: Ditto.
    * gcc.target/i386/pr78967-1b.c: Ditto.
    * gcc.target/i386/pr78967-2a.c: Ditto.
    * gcc.target/i386/pr78967-2b.c: Ditto.

Bootstrapped and regression tested on x86_64-linux-gnu {,-m32}.

Uros.

Patch

diff --git a/gcc/config/i386/i386-expand.c b/gcc/config/i386/i386-expand.c
index d7077980f9b..d81dd73f034 100644
--- a/gcc/config/i386/i386-expand.c
+++ b/gcc/config/i386/i386-expand.c
@@ -1179,9 +1179,8 @@  ix86_split_idivmod (machine_mode mode, rtx operands[],
   JUMP_LABEL (insn) = qimode_label;
 
   /* Generate original signed/unsigned divimod.  */
-  div = gen_divmod4_1 (operands[0], operands[1],
-		       operands[2], operands[3]);
-  emit_insn (div);
+  emit_insn (gen_divmod4_1 (operands[0], operands[1],
+			    operands[2], operands[3]));
 
   /* Branch to the end.  */
   emit_jump_insn (gen_jump (end_label));
@@ -1215,18 +1214,10 @@  ix86_split_idivmod (machine_mode mode, rtx operands[],
     }
 
   /* Extract remainder from AH.  */
-  tmp1 = gen_rtx_ZERO_EXTRACT (GET_MODE (operands[1]),
-			       tmp0, GEN_INT (8), GEN_INT (8));
-  if (REG_P (operands[1]))
-    insn = emit_move_insn (operands[1], tmp1);
-  else
-    {
-      /* Need a new scratch register since the old one has result
-	 of 8bit divide.  */
-      scratch = gen_reg_rtx (GET_MODE (operands[1]));
-      emit_move_insn (scratch, tmp1);
-      insn = emit_move_insn (operands[1], scratch);
-    }
+  scratch = gen_lowpart (GET_MODE (operands[1]), scratch);
+  tmp1 = gen_rtx_ZERO_EXTRACT (GET_MODE (operands[1]), scratch,
+			       GEN_INT (8), GEN_INT (8));
+  insn = emit_move_insn (operands[1], tmp1);
   set_unique_reg_note (insn, REG_EQUAL, mod);
 
   /* Zero extend quotient from AL.  */
@@ -7060,10 +7051,7 @@  promote_duplicated_reg (machine_mode mode, rtx val)
       rtx reg = convert_modes (mode, QImode, val, true);
 
       if (!TARGET_PARTIAL_REG_STALL)
-	if (mode == SImode)
-	  emit_insn (gen_insvsi_1 (reg, reg));
-	else
-	  emit_insn (gen_insvdi_1 (reg, reg));
+	emit_insn (gen_insv_1 (mode, reg, reg));
       else
 	{
 	  tmp = expand_simple_binop (mode, ASHIFT, reg, GEN_INT (8),
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 4d455584f09..d0ecd9eb6cf 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -1355,13 +1355,13 @@ 
   [(set_attr "type" "icmp")
    (set_attr "mode" "<MODE>")])
 
-(define_insn "*cmpqi_ext_1"
+(define_insn "*cmpqi_ext<mode>_1"
   [(set (reg FLAGS_REG)
 	(compare
 	  (match_operand:QI 0 "nonimmediate_operand" "QBc,m")
 	  (subreg:QI
-	    (zero_extract:SI
-	      (match_operand 1 "ext_register_operand" "Q,Q")
+	    (zero_extract:SWI248
+	      (match_operand:SWI248 1 "register_operand" "Q,Q")
 	      (const_int 8)
 	      (const_int 8)) 0)))]
   "ix86_match_ccmode (insn, CCmode)"
@@ -1370,12 +1370,12 @@ 
    (set_attr "type" "icmp")
    (set_attr "mode" "QI")])
 
-(define_insn "*cmpqi_ext_2"
+(define_insn "*cmpqi_ext<mode>_2"
   [(set (reg FLAGS_REG)
 	(compare
 	  (subreg:QI
-	    (zero_extract:SI
-	      (match_operand 0 "ext_register_operand" "Q")
+	    (zero_extract:SWI248
+	      (match_operand:SWI248 0 "register_operand" "Q")
 	      (const_int 8)
 	      (const_int 8)) 0)
 	  (match_operand:QI 1 "const0_operand")))]
@@ -1389,18 +1389,18 @@ 
   [(set (reg:CC FLAGS_REG)
 	(compare:CC
 	  (subreg:QI
-	    (zero_extract:SI
-	      (match_operand 0 "ext_register_operand")
+	    (zero_extract:HI
+	      (match_operand:HI 0 "register_operand")
 	      (const_int 8)
 	      (const_int 8)) 0)
 	  (match_operand:QI 1 "const_int_operand")))])
 
-(define_insn "*cmpqi_ext_3"
+(define_insn "*cmpqi_ext<mode>_3"
   [(set (reg FLAGS_REG)
 	(compare
 	  (subreg:QI
-	    (zero_extract:SI
-	      (match_operand 0 "ext_register_operand" "Q,Q")
+	    (zero_extract:SWI248
+	      (match_operand:SWI248 0 "register_operand" "Q,Q")
 	      (const_int 8)
 	      (const_int 8)) 0)
 	  (match_operand:QI 1 "general_operand" "QnBc,m")))]
@@ -1410,17 +1410,17 @@ 
    (set_attr "type" "icmp")
    (set_attr "mode" "QI")])
 
-(define_insn "*cmpqi_ext_4"
+(define_insn "*cmpqi_ext<mode>_4"
   [(set (reg FLAGS_REG)
 	(compare
 	  (subreg:QI
-	    (zero_extract:SI
-	      (match_operand 0 "ext_register_operand" "Q")
+	    (zero_extract:SWI248
+	      (match_operand:SWI248 0 "register_operand" "Q")
 	      (const_int 8)
 	      (const_int 8)) 0)
 	  (subreg:QI
-	    (zero_extract:SI
-	      (match_operand 1 "ext_register_operand" "Q")
+	    (zero_extract:SWI248
+	      (match_operand:SWI248 1 "register_operand" "Q")
 	      (const_int 8)
 	      (const_int 8)) 0)))]
   "ix86_match_ccmode (insn, CCmode)"
@@ -2775,7 +2775,7 @@ 
 
 (define_insn "*extv<mode>"
   [(set (match_operand:SWI24 0 "register_operand" "=R")
-	(sign_extract:SWI24 (match_operand 1 "ext_register_operand" "Q")
+	(sign_extract:SWI24 (match_operand:SWI24 1 "register_operand" "Q")
 			    (const_int 8)
 			    (const_int 8)))]
   ""
@@ -2807,9 +2807,10 @@ 
 (define_insn "*extzvqi_mem_rex64"
   [(set (match_operand:QI 0 "norex_memory_operand" "=Bn")
 	(subreg:QI
-	  (zero_extract:SI (match_operand 1 "ext_register_operand" "Q")
-			   (const_int 8)
-			   (const_int 8)) 0))]
+	  (zero_extract:SWI248
+	    (match_operand:SWI248 1 "register_operand" "Q")
+	    (const_int 8)
+	    (const_int 8)) 0))]
   "TARGET_64BIT && reload_completed"
   "mov{b}\t{%h1, %0|%0, %h1}"
   [(set_attr "type" "imov")
@@ -2817,7 +2818,7 @@ 
 
 (define_insn "*extzv<mode>"
   [(set (match_operand:SWI248 0 "register_operand" "=R")
-	(zero_extract:SWI248 (match_operand 1 "ext_register_operand" "Q")
+	(zero_extract:SWI248 (match_operand:SWI248 1 "register_operand" "Q")
 			     (const_int 8)
 			     (const_int 8)))]
   ""
@@ -2828,9 +2829,10 @@ 
 (define_insn "*extzvqi"
   [(set (match_operand:QI 0 "nonimmediate_operand" "=QBc,?R,m")
 	(subreg:QI
-	  (zero_extract:SI (match_operand 1 "ext_register_operand" "Q,Q,Q")
-			   (const_int 8)
-			   (const_int 8)) 0))]
+	  (zero_extract:SWI248
+	    (match_operand:SWI248 1 "register_operand" "Q,Q,Q")
+	    (const_int 8)
+	    (const_int 8)) 0))]
   ""
 {
   switch (get_attr_type (insn))
@@ -2856,17 +2858,17 @@ 
 (define_peephole2
   [(set (match_operand:QI 0 "register_operand")
 	(subreg:QI
-	  (zero_extract:SI (match_operand 1 "ext_register_operand")
-			   (const_int 8)
-			   (const_int 8)) 0))
+	  (zero_extract:SWI248 (match_operand:SWI248 1 "register_operand")
+			       (const_int 8)
+			       (const_int 8)) 0))
    (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))])
+	  (zero_extract:SWI248 (match_dup 1)
+			       (const_int 8)
+			       (const_int 8)) 0))])
 
 (define_expand "insv<mode>"
   [(set (zero_extract:SWI248 (match_operand:SWI248 0 "register_operand")
@@ -2892,7 +2894,7 @@ 
   else
     dst = operands[0];
 
-  emit_insn (gen_insv<mode>_1 (dst, operands[3]));
+  emit_insn (gen_insv_1 (<MODE>mode, dst, operands[3]));
 
   /* Fix up the destination if needed.  */
   if (dst != operands[0])
@@ -2902,20 +2904,22 @@ 
 })
 
 (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
+  [(set (zero_extract:SWI248
+	  (match_operand:SWI248 0 "register_operand" "+Q")
+	  (const_int 8)
+	  (const_int 8))
+	(subreg:SWI248
 	  (match_operand:QI 1 "norex_memory_operand" "Bn") 0))]
   "TARGET_64BIT && reload_completed"
   "mov{b}\t{%1, %h0|%h0, %1}"
   [(set_attr "type" "imov")
    (set_attr "mode" "QI")])
 
-(define_insn "insv<mode>_1"
-  [(set (zero_extract:SWI248 (match_operand 0 "ext_register_operand" "+Q,Q")
-			     (const_int 8)
-			     (const_int 8))
+(define_insn "@insv<mode>_1"
+  [(set (zero_extract:SWI248
+	  (match_operand:SWI248 0 "register_operand" "+Q,Q")
+	  (const_int 8)
+	  (const_int 8))
 	(match_operand:SWI248 1 "general_operand" "QnBc,m"))]
   ""
 {
@@ -2928,10 +2932,11 @@ 
    (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
+  [(set (zero_extract:SWI248
+	  (match_operand:SWI248 0 "register_operand" "+Q,Q")
+	  (const_int 8)
+	  (const_int 8))
+	(subreg:SWI248
 	  (match_operand:QI 1 "general_operand" "QnBc,m") 0))]
   ""
   "mov{b}\t{%1, %h0|%h0, %1}"
@@ -2942,37 +2947,41 @@ 
 (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))]
+   (set (zero_extract:SWI248 (match_operand:SWI248 2 "register_operand")
+			     (const_int 8)
+			     (const_int 8))
+	(subreg:SWI248 (match_dup 0) 0))]
   "TARGET_64BIT
    && peep2_reg_dead_p (2, operands[0])"
-  [(set (zero_extract:SI (match_dup 2)
-			 (const_int 8)
-			 (const_int 8))
-	   (subreg:SI (match_dup 1) 0))])
+  [(set (zero_extract:SWI248 (match_dup 2)
+			     (const_int 8)
+			     (const_int 8))
+	   (subreg:SWI248 (match_dup 1) 0))])
 
 (define_code_iterator any_extract [sign_extract zero_extract])
 
 (define_insn "*insvqi_2"
-  [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "+Q")
-			 (const_int 8)
-			 (const_int 8))
-	(any_extract:SI (match_operand 1 "ext_register_operand" "Q")
-			(const_int 8)
-			(const_int 8)))]
+  [(set (zero_extract:SWI248
+	  (match_operand:SWI248 0 "register_operand" "+Q")
+	  (const_int 8)
+	  (const_int 8))
+	(any_extract:SWI248
+	  (match_operand:SWI248 1 "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))
-	(any_shiftrt:SI (match_operand:SI 1 "register_operand" "Q")
-			(const_int 8)))]
+  [(set (zero_extract:SWI248
+	  (match_operand:SWI248 0 "register_operand" "+Q")
+	  (const_int 8)
+	  (const_int 8))
+	(any_shiftrt:SWI248
+	  (match_operand:SWI248 1 "register_operand" "Q")
+	  (const_int 8)))]
   ""
   "mov{b}\t{%h1, %h0|%h0, %h1}"
   [(set_attr "type" "imov")
@@ -5835,16 +5844,32 @@ 
 	(const_string "*")))
    (set_attr "mode" "<MODE>")])
 
-(define_insn "addqi_ext_1"
-  [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "+Q,Q")
-			 (const_int 8)
-			 (const_int 8))
-	(subreg:SI
+(define_expand "addqi_ext_1"
+  [(parallel
+     [(set (zero_extract:HI (match_operand:HI 0 "register_operand")
+			    (const_int 8)
+			    (const_int 8))
+	   (subreg:HI
+	     (plus:QI
+	       (subreg:QI
+		 (zero_extract:HI (match_operand:HI 1 "register_operand")
+				  (const_int 8)
+				  (const_int 8)) 0)
+	       (match_operand:QI 2 "const_int_operand")) 0))
+      (clobber (reg:CC FLAGS_REG))])])
+
+(define_insn "*addqi_ext<mode>_1"
+  [(set (zero_extract:SWI248
+	  (match_operand:SWI248 0 "register_operand" "+Q,Q")
+	  (const_int 8)
+	  (const_int 8))
+	(subreg:SWI248
 	  (plus:QI
 	    (subreg:QI
-	      (zero_extract:SI (match_operand 1 "ext_register_operand" "0,0")
-			       (const_int 8)
-			       (const_int 8)) 0)
+	      (zero_extract:SWI248
+	        (match_operand:SWI248 1 "register_operand" "0,0")
+		(const_int 8)
+		(const_int 8)) 0)
 	    (match_operand:QI 2 "general_operand" "QnBc,m")) 0))
    (clobber (reg:CC FLAGS_REG))]
   "/* FIXME: without this LRA can't reload this pattern, see PR82524.  */
@@ -5872,20 +5897,23 @@ 
 	(const_string "alu")))
    (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))
-	(subreg:SI
+(define_insn "*addqi_ext<mode>_2"
+  [(set (zero_extract:SWI248
+	  (match_operand:SWI248 0 "register_operand" "+Q")
+	  (const_int 8)
+	  (const_int 8))
+	(subreg:SWI248
 	  (plus:QI
 	    (subreg:QI
-	      (zero_extract:SI (match_operand 1 "ext_register_operand" "%0")
-			       (const_int 8)
-			       (const_int 8)) 0)
+	      (zero_extract:SWI248
+	        (match_operand:SWI248 1 "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))
+	      (zero_extract:SWI248
+	        (match_operand:SWI248 2 "register_operand" "Q")
+		(const_int 8)
+		(const_int 8)) 0)) 0))
   (clobber (reg:CC FLAGS_REG))]
   "/* FIXME: without this LRA can't reload this pattern, see PR82524.  */
    rtx_equal_p (operands[0], operands[1])
@@ -8556,8 +8584,8 @@ 
   emit_insn (gen_divmodhiqi3 (tmp0, tmp1, operands[2]));
 
   /* Extract remainder from AH.  */
-  tmp1 = gen_rtx_ZERO_EXTRACT (SImode, tmp0, GEN_INT (8), GEN_INT (8));
-  tmp1 = lowpart_subreg (QImode, tmp1, SImode);
+  tmp1 = gen_rtx_ZERO_EXTRACT (HImode, tmp0, GEN_INT (8), GEN_INT (8));
+  tmp1 = lowpart_subreg (QImode, tmp1, HImode);
   rtx_insn *insn = emit_move_insn (operands[3], tmp1);
 
   mod = gen_rtx_MOD (QImode, operands[1], operands[2]);
@@ -8593,8 +8621,8 @@ 
   emit_insn (gen_udivmodhiqi3 (tmp0, tmp1, operands[2]));
 
   /* Extract remainder from AH.  */
-  tmp1 = gen_rtx_ZERO_EXTRACT (SImode, tmp0, GEN_INT (8), GEN_INT (8));
-  tmp1 = lowpart_subreg (QImode, tmp1, SImode);
+  tmp1 = gen_rtx_ZERO_EXTRACT (HImode, tmp0, GEN_INT (8), GEN_INT (8));
+  tmp1 = lowpart_subreg (QImode, tmp1, HImode);
   rtx_insn *insn = emit_move_insn (operands[3], tmp1);
 
   mod = gen_rtx_UMOD (QImode, operands[1], operands[2]);
@@ -8740,20 +8768,22 @@ 
 	(compare:CCNO
 	  (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"))
+	      (zero_extract:HI
+	        (match_operand:HI 0 "register_operand")
+		(const_int 8)
+		(const_int 8)) 0)
+	      (match_operand:QI 1 "const_int_operand"))
 	  (const_int 0)))])
 
-(define_insn "*testqi_ext_1"
+(define_insn "*testqi_ext<mode>_1"
   [(set (reg FLAGS_REG)
 	(compare
 	  (and:QI
 	    (subreg:QI
-	      (zero_extract:SI (match_operand 0 "ext_register_operand" "Q,Q")
-			       (const_int 8)
-			       (const_int 8)) 0)
+	      (zero_extract:SWI248
+	        (match_operand:SWI248 0 "register_operand" "Q,Q")
+		(const_int 8)
+		(const_int 8)) 0)
 	    (match_operand:QI 1 "general_operand" "QnBc,m"))
 	  (const_int 0)))]
   "ix86_match_ccmode (insn, CCNOmode)"
@@ -8762,18 +8792,20 @@ 
    (set_attr "type" "test")
    (set_attr "mode" "QI")])
 
-(define_insn "*testqi_ext_2"
+(define_insn "*testqi_ext<mode>_2"
   [(set (reg FLAGS_REG)
 	(compare
 	  (and:QI
 	    (subreg:QI
-	      (zero_extract:SI (match_operand 0 "ext_register_operand" "Q")
-			       (const_int 8)
-			       (const_int 8)) 0)
+	      (zero_extract:SWI248
+	        (match_operand:SWI248 0 "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))
+	      (zero_extract:SWI248
+	        (match_operand:SWI248 1 "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}"
@@ -9312,16 +9344,32 @@ 
   [(set_attr "type" "alu")
    (set_attr "mode" "<MODE>")])
 
-(define_insn "andqi_ext_1"
-  [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "+Q,Q")
-			 (const_int 8)
-			 (const_int 8))
-	(subreg:SI
+(define_expand "andqi_ext_1"
+  [(parallel
+     [(set (zero_extract:HI (match_operand:HI 0 "register_operand")
+			    (const_int 8)
+			    (const_int 8))
+	   (subreg:HI
+	     (and:QI
+	       (subreg:QI
+		 (zero_extract:HI (match_operand:HI 1 "register_operand")
+				  (const_int 8)
+				  (const_int 8)) 0)
+	       (match_operand:QI 2 "const_int_operand")) 0))
+      (clobber (reg:CC FLAGS_REG))])])
+
+(define_insn "*andqi_ext<mode>_1"
+  [(set (zero_extract:SWI248
+	  (match_operand:SWI248 0 "register_operand" "+Q,Q")
+	  (const_int 8)
+	  (const_int 8))
+	(subreg:SWI248
 	  (and:QI
 	    (subreg:QI
-	      (zero_extract:SI (match_operand 1 "ext_register_operand" "0,0")
-			       (const_int 8)
-			       (const_int 8)) 0)
+	      (zero_extract:SWI248
+	        (match_operand:SWI248 1 "register_operand" "0,0")
+		(const_int 8)
+		(const_int 8)) 0)
 	    (match_operand:QI 2 "general_operand" "QnBc,m")) 0))
    (clobber (reg:CC FLAGS_REG))]
   "/* FIXME: without this LRA can't reload this pattern, see PR82524.  */
@@ -9333,25 +9381,28 @@ 
 
 ;; Generated by peephole translating test to and.  This shows up
 ;; often in fp comparisons.
-(define_insn "*andqi_ext_1_cc"
+(define_insn "*andqi_ext<mode>_1_cc"
   [(set (reg FLAGS_REG)
 	(compare
 	  (and:QI
 	    (subreg:QI
-	      (zero_extract:SI (match_operand 1 "ext_register_operand" "0,0")
-			       (const_int 8)
-			       (const_int 8)) 0)
+	      (zero_extract:SWI248
+	        (match_operand:SWI248 1 "register_operand" "0,0")
+		(const_int 8)
+		(const_int 8)) 0)
 	    (match_operand:QI 2 "general_operand" "QnBc,m"))
 	  (const_int 0)))
-   (set (zero_extract:SI (match_operand 0 "ext_register_operand" "+Q,Q")
-			 (const_int 8)
-			 (const_int 8))
-	(subreg:SI
+   (set (zero_extract:SWI248
+	  (match_operand:SWI248 0 "register_operand" "+Q,Q")
+	  (const_int 8)
+	  (const_int 8))
+	(subreg:SWI248
 	  (and:QI
 	    (subreg:QI
-	      (zero_extract:SI (match_dup 1)
-			       (const_int 8)
-			       (const_int 8)) 0)
+	      (zero_extract:SWI248
+	        (match_dup 1)
+		(const_int 8)
+		(const_int 8)) 0)
 	    (match_dup 2)) 0))]
   "ix86_match_ccmode (insn, CCNOmode)
    /* FIXME: without this LRA can't reload this pattern, see PR82524.  */
@@ -9361,20 +9412,23 @@ 
    (set_attr "type" "alu")
    (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))
-	(subreg:SI
+(define_insn "*andqi_ext<mode>_2"
+  [(set (zero_extract:SWI248
+	  (match_operand:SWI248 0 "register_operand" "+Q")
+	  (const_int 8)
+	  (const_int 8))
+	(subreg:SWI248
 	  (and:QI
 	    (subreg:QI
-	      (zero_extract:SI (match_operand 1 "ext_register_operand" "%0")
-			       (const_int 8)
-			       (const_int 8)) 0)
+	      (zero_extract:SWI248
+	        (match_operand:SWI248 1 "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))
+	      (zero_extract:SWI248
+	        (match_operand:SWI248 2 "register_operand" "Q")
+		(const_int 8)
+		(const_int 8)) 0)) 0))
    (clobber (reg:CC FLAGS_REG))]
   "/* FIXME: without this LRA can't reload this pattern, see PR82524.  */
    rtx_equal_p (operands[0], operands[1])
@@ -9743,16 +9797,18 @@ 
   [(set_attr "type" "alu")
    (set_attr "mode" "<MODE>")])
 
-(define_insn "*<code>qi_ext_1"
-  [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "+Q,Q")
-			 (const_int 8)
-			 (const_int 8))
-	(subreg:SI
+(define_insn "*<code>qi_ext<mode>_1"
+  [(set (zero_extract:SWI248
+	  (match_operand:SWI248 0 "register_operand" "+Q,Q")
+	  (const_int 8)
+	  (const_int 8))
+	(subreg:SWI248
 	  (any_or:QI
 	    (subreg:QI
-	      (zero_extract:SI (match_operand 1 "ext_register_operand" "0,0")
-			       (const_int 8)
-			       (const_int 8)) 0)
+	      (zero_extract:SWI248
+	        (match_operand:SWI248 1 "register_operand" "0,0")
+		(const_int 8)
+		(const_int 8)) 0)
 	    (match_operand:QI 2 "general_operand" "QnBc,m")) 0))
    (clobber (reg:CC FLAGS_REG))]
   "(!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun))
@@ -9763,20 +9819,23 @@ 
    (set_attr "type" "alu")
    (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))
-	(subreg:SI
+(define_insn "*<code>qi_ext<mode>_2"
+  [(set (zero_extract:SWI248
+	  (match_operand:SWI248 0 "register_operand" "+Q")
+	  (const_int 8)
+	  (const_int 8))
+	(subreg:SWI248
 	  (any_or:QI
 	    (subreg:QI
-	      (zero_extract:SI (match_operand 1 "ext_register_operand" "%0")
-			       (const_int 8)
-			       (const_int 8)) 0)
+	      (zero_extract:SWI248
+	        (match_operand:SWI248 1 "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))
+	      (zero_extract:SWI248
+	        (match_operand:SWI248 2 "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))
    /* FIXME: without this LRA can't reload this pattern, see PR82524.  */
@@ -9839,46 +9898,49 @@ 
 })
 
 (define_expand "xorqi_ext_1_cc"
-  [(parallel [
-     (set (reg:CCNO FLAGS_REG)
-	  (compare:CCNO
-	    (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))
-	  (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"
+  [(parallel
+     [(set (reg:CCNO FLAGS_REG)
+	   (compare:CCNO
+	     (xor:QI
+	       (subreg:QI
+		 (zero_extract:HI (match_operand:HI 1 "register_operand")
+				  (const_int 8)
+				  (const_int 8)) 0)
+	       (match_operand:QI 2 "const_int_operand"))
+	     (const_int 0)))
+      (set (zero_extract:HI (match_operand:HI 0 "register_operand")
+			    (const_int 8)
+			    (const_int 8))
+	   (subreg:HI
+	     (xor:QI
+	       (subreg:QI
+		 (zero_extract:HI (match_dup 1)
+				  (const_int 8)
+				  (const_int 8)) 0)
+	     (match_dup 2)) 0))])])
+
+(define_insn "*xorqi_ext<mode>_1_cc"
   [(set (reg FLAGS_REG)
 	(compare
 	  (xor:QI
 	    (subreg:QI
-	      (zero_extract:SI (match_operand 1 "ext_register_operand" "0,0")
-			       (const_int 8)
-			       (const_int 8)) 0)
+	      (zero_extract:SWI248
+	        (match_operand:SWI248 1 "register_operand" "0,0")
+		(const_int 8)
+		(const_int 8)) 0)
 	    (match_operand:QI 2 "general_operand" "QnBc,m"))
 	  (const_int 0)))
-   (set (zero_extract:SI (match_operand 0 "ext_register_operand" "+Q,Q")
-			 (const_int 8)
-			 (const_int 8))
-	(subreg:SI
+   (set (zero_extract:SWI248
+	  (match_operand:SWI248 0 "register_operand" "+Q,Q")
+	  (const_int 8)
+	  (const_int 8))
+	(subreg:SWI248
 	  (xor:QI
 	    (subreg:QI
-	      (zero_extract:SI (match_dup 1)
-			       (const_int 8)
-			       (const_int 8)) 0)
+	      (zero_extract:SWI248
+	        (match_dup 1)
+		(const_int 8)
+		(const_int 8)) 0)
 	  (match_dup 2)) 0))]
   "ix86_match_ccmode (insn, CCNOmode)
    /* FIXME: without this LRA can't reload this pattern, see PR82524.  */
@@ -19409,9 +19471,9 @@ 
 	(match_operator 1 "compare_operator"
 	  [(and:QI
 	     (subreg:QI
-	       (zero_extract:SI (match_operand 2 "QIreg_operand")
-				(const_int 8)
-				(const_int 8)) 0)
+	       (zero_extract:SWI248 (match_operand:SWI248 2 "QIreg_operand")
+				    (const_int 8)
+				    (const_int 8)) 0)
 	     (match_operand 3 "const_int_operand"))
 	   (const_int 0)]))]
   "! TARGET_PARTIAL_REG_STALL
@@ -19423,20 +19485,20 @@ 
 	   (match_op_dup 1
 	     [(and:QI
 		(subreg:QI
-		  (zero_extract:SI (match_dup 2)
-				   (const_int 8)
-				   (const_int 8)) 0)
+		  (zero_extract:SWI248 (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
+      (set (zero_extract:SWI248 (match_dup 2)
+				(const_int 8)
+				(const_int 8))
+	   (subreg:SWI248
 	     (and:QI
 	       (subreg:QI
-		 (zero_extract:SI (match_dup 2)
-				  (const_int 8)
-				  (const_int 8)) 0)
+		 (zero_extract:SWI248 (match_dup 2)
+				      (const_int 8)
+				      (const_int 8)) 0)
 	       (match_dup 3)) 0))])])
 
 ;; Don't do logical operations with memory inputs.
diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md
index 8d8bcb1a765..07e69d555c0 100644
--- a/gcc/config/i386/predicates.md
+++ b/gcc/config/i386/predicates.md
@@ -87,14 +87,6 @@ 
   (and (match_code "reg")
        (match_test "REGNO (op) == FLAGS_REG")))
 
-;; Match a DI, SI or HImode register for a zero_extract.
-(define_special_predicate "ext_register_operand"
-  (and (match_operand 0 "register_operand")
-       (ior (and (match_test "TARGET_64BIT")
-		 (match_test "GET_MODE (op) == DImode"))
-	    (match_test "GET_MODE (op) == SImode")
-	    (match_test "GET_MODE (op) == HImode"))))
-
 ;; Match a DI, SI, HI or QImode nonimmediate_operand.
 (define_special_predicate "int_nonimmediate_operand"
   (and (match_operand 0 "nonimmediate_operand")
diff --git a/gcc/testsuite/gcc.target/i386/pr78904-1a.c b/gcc/testsuite/gcc.target/i386/pr78904-1a.c
new file mode 100644
index 00000000000..7746477d745
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78904-1a.c
@@ -0,0 +1,47 @@ 
+/* 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;
+};
+
+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" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr78904-1b.c b/gcc/testsuite/gcc.target/i386/pr78904-1b.c
new file mode 100644
index 00000000000..20b677252ab
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78904-1b.c
@@ -0,0 +1,49 @@ 
+/* PR target/78904 */
+/* { dg-do compile { target { ! ia32 } } } */
+/* { 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;
+  unsigned int pad3;
+};
+
+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" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr78904-2a.c b/gcc/testsuite/gcc.target/i386/pr78904-2a.c
new file mode 100644
index 00000000000..41eaa259158
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78904-2a.c
@@ -0,0 +1,48 @@ 
+/* PR target/78904 */
+/* { dg-do compile } */
+/* { dg-require-effective-target nonpic } */
+/* { dg-options "-O2 -masm=att" } */
+
+struct S1
+{
+  unsigned char pad1;
+  unsigned char val;
+};
+
+extern struct S1 t;
+
+struct S1 test_and (struct S1 a)
+{
+  a.val &= t.val;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]andb\[ \t\]+t\[^\n\r]*, %.h" } } */
+
+struct S1 test_or (struct S1 a)
+{
+  a.val |= t.val;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]orb\[ \t\]+t\[^\n\r]*, %.h" } } */
+
+struct S1 test_xor (struct S1 a)
+{
+  a.val ^= t.val;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]xorb\[ \t\]+t\[^\n\r]*, %.h" } } */
+
+struct S1 test_add (struct S1 a)
+{
+  a.val += t.val;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]addb\[ \t\]+t\[^\n\r]*, %.h" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr78904-2b.c b/gcc/testsuite/gcc.target/i386/pr78904-2b.c
new file mode 100644
index 00000000000..23e975ac93e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78904-2b.c
@@ -0,0 +1,50 @@ 
+/* PR target/78904 */
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-require-effective-target nonpic } */
+/* { dg-options "-O2 -masm=att" } */
+
+struct S1
+{
+  unsigned char pad1;
+  unsigned char val;
+  unsigned short pad2;
+  unsigned int pad3;
+};
+
+extern struct S1 t;
+
+struct S1 test_and (struct S1 a)
+{
+  a.val &= t.val;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]andb\[ \t\]+t\[^\n\r]*, %.h" } } */
+
+struct S1 test_or (struct S1 a)
+{
+  a.val |= t.val;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]orb\[ \t\]+t\[^\n\r]*, %.h" } } */
+
+struct S1 test_xor (struct S1 a)
+{
+  a.val ^= t.val;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]xorb\[ \t\]+t\[^\n\r]*, %.h" } } */
+
+struct S1 test_add (struct S1 a)
+{
+  a.val += t.val;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]addb\[ \t\]+t\[^\n\r]*, %.h" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr78904-3a.c b/gcc/testsuite/gcc.target/i386/pr78904-3a.c
new file mode 100644
index 00000000000..2827b380b6c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78904-3a.c
@@ -0,0 +1,42 @@ 
+/* PR target/78904 */
+/* { dg-do assemble } */
+/* { dg-options "-O2" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+struct S1
+{
+  unsigned char pad1;
+  unsigned char val;
+  unsigned short pad2;
+};
+
+extern struct S1 t[256];
+
+struct S1 test_and (struct S1 a, size_t i)
+{
+  a.val &= t[i].val;
+
+  return a;
+}
+
+struct S1 test_or (struct S1 a, size_t i)
+{
+  a.val |= t[i].val;
+
+  return a;
+}
+
+struct S1 test_xor (struct S1 a, size_t i)
+{
+  a.val ^= t[i].val;
+
+  return a;
+}
+
+struct S1 test_add (struct S1 a, size_t i)
+{
+  a.val += t[i].val;
+
+  return a;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr78904-3b.c b/gcc/testsuite/gcc.target/i386/pr78904-3b.c
new file mode 100644
index 00000000000..0c73cbc2ec9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78904-3b.c
@@ -0,0 +1,43 @@ 
+/* PR target/78904 */
+/* { dg-do assemble { target { ! ia32 } } } */
+/* { dg-options "-O2" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+struct S1
+{
+  unsigned char pad1;
+  unsigned char val;
+  unsigned short pad2;
+  unsigned int pad3;
+};
+
+extern struct S1 t[256];
+
+struct S1 test_and (struct S1 a, size_t i)
+{
+  a.val &= t[i].val;
+
+  return a;
+}
+
+struct S1 test_or (struct S1 a, size_t i)
+{
+  a.val |= t[i].val;
+
+  return a;
+}
+
+struct S1 test_xor (struct S1 a, size_t i)
+{
+  a.val ^= t[i].val;
+
+  return a;
+}
+
+struct S1 test_add (struct S1 a, size_t i)
+{
+  a.val += t[i].val;
+
+  return a;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr78904-4a.c b/gcc/testsuite/gcc.target/i386/pr78904-4a.c
new file mode 100644
index 00000000000..5e6159a7648
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78904-4a.c
@@ -0,0 +1,21 @@ 
+/* PR target/78904 */
+/* { dg-do compile } */
+/* { dg-require-effective-target nonpic } */
+/* { dg-options "-O2 -masm=att" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+struct S1
+{
+  unsigned char pad1;
+  unsigned char val;
+};
+
+extern unsigned char t[256];
+
+void foo (struct S1 a, size_t i)
+{
+  t[i] = a.val;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]movb\[\t \]+%.h, t" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr78904-4b.c b/gcc/testsuite/gcc.target/i386/pr78904-4b.c
new file mode 100644
index 00000000000..ab7434f3de4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78904-4b.c
@@ -0,0 +1,23 @@ 
+/* PR target/78904 */
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-require-effective-target nonpic } */
+/* { dg-options "-O2 -masm=att" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+struct S1
+{
+  unsigned char pad1;
+  unsigned char val;
+  unsigned short pad2;
+  unsigned int pad3;
+};
+
+extern unsigned char t[256];
+
+void foo (struct S1 a, size_t i)
+{
+  t[i] = a.val;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]movb\[\t \]+%.h, t" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr78904-5a.c b/gcc/testsuite/gcc.target/i386/pr78904-5a.c
new file mode 100644
index 00000000000..d078d79b73a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78904-5a.c
@@ -0,0 +1,21 @@ 
+/* PR target/78904 */
+/* { dg-do assemble { target { ! ia32 } } } */
+/* { dg-options "-O2" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+struct S1
+{
+  unsigned char pad1;
+  unsigned char val;
+};
+
+extern unsigned char t[256];
+
+void foo (struct S1 a, size_t i)
+{
+  register size_t _i __asm ("r10") = i;
+
+  asm volatile ("" : "+r" (_i));
+  t[_i] = a.val;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr78904-5b.c b/gcc/testsuite/gcc.target/i386/pr78904-5b.c
new file mode 100644
index 00000000000..9490030d772
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78904-5b.c
@@ -0,0 +1,23 @@ 
+/* PR target/78904 */
+/* { dg-do assemble { target { ! ia32 } } } */
+/* { dg-options "-O2" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+struct S1
+{
+  unsigned char pad1;
+  unsigned char val;
+  unsigned short pad2;
+  unsigned int pad3;
+};
+
+extern unsigned char t[256];
+
+void foo (struct S1 a, size_t i)
+{
+  register size_t _i __asm ("r10") = i;
+
+  asm volatile ("" : "+r" (_i));
+  t[_i] = a.val;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr78904-6a.c b/gcc/testsuite/gcc.target/i386/pr78904-6a.c
new file mode 100644
index 00000000000..ab296a2e173
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78904-6a.c
@@ -0,0 +1,21 @@ 
+/* PR target/78904 */
+/* { dg-do compile } */
+/* { dg-require-effective-target nonpic } */
+/* { dg-options "-O2 -masm=att" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+struct S1
+{
+  char pad1;
+  char val;
+};
+
+extern char t[256];
+
+void foo (struct S1 a, size_t i)
+{
+  t[i] = a.val;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]movb\[\t \]*%.h, t" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr78904-6b.c b/gcc/testsuite/gcc.target/i386/pr78904-6b.c
new file mode 100644
index 00000000000..235bfe7d042
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78904-6b.c
@@ -0,0 +1,23 @@ 
+/* PR target/78904 */
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-require-effective-target nonpic } */
+/* { dg-options "-O2 -masm=att" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+struct S1
+{
+  char pad1;
+  char val;
+  short pad2;
+  int pad3;
+};
+
+extern char t[256];
+
+void foo (struct S1 a, size_t i)
+{
+  t[i] = a.val;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]movb\[\t \]*%.h, t" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr78967-1a.c b/gcc/testsuite/gcc.target/i386/pr78967-1a.c
new file mode 100644
index 00000000000..007c50646b6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78967-1a.c
@@ -0,0 +1,20 @@ 
+/* 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;
+};
+
+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-1b.c b/gcc/testsuite/gcc.target/i386/pr78967-1b.c
new file mode 100644
index 00000000000..7e7144379f3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78967-1b.c
@@ -0,0 +1,21 @@ 
+/* PR target/78967 */
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -masm=att" } */
+/* { dg-final { scan-assembler-not "movzbl" } } */
+
+struct S1
+{
+  unsigned char pad1;
+  unsigned char val;
+  unsigned short pad2;
+  unsigned int pad3;
+};
+
+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-2a.c b/gcc/testsuite/gcc.target/i386/pr78967-2a.c
new file mode 100644
index 00000000000..ce61cabf414
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78967-2a.c
@@ -0,0 +1,24 @@ 
+/* PR target/78967 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -masm=att" } */
+/* { dg-require-effective-target nonpic } */
+/* { dg-final { scan-assembler-not "movzbl" } } */
+
+typedef __SIZE_TYPE__ size_t;
+
+struct S1
+{
+  unsigned char pad1;
+  unsigned char val;
+};
+
+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-2b.c b/gcc/testsuite/gcc.target/i386/pr78967-2b.c
new file mode 100644
index 00000000000..ce38ac4d0bf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78967-2b.c
@@ -0,0 +1,26 @@ 
+/* PR target/78967 */
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -masm=att" } */
+/* { dg-require-effective-target nonpic } */
+/* { dg-final { scan-assembler-not "movzbl" } } */
+
+typedef __SIZE_TYPE__ size_t;
+
+struct S1
+{
+  unsigned char pad1;
+  unsigned char val;
+  unsigned short pad2;
+  unsigned int pad3;
+};
+
+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" } } */