diff mbox series

[i386] : Fix PR 91188, strict_low_part operations do not work

Message ID CAFULd4bZN2VrwJxCMBeqV3KUbrMYe9eHprXOVPy6qRKGn_B97w@mail.gmail.com
State New
Headers show
Series [i386] : Fix PR 91188, strict_low_part operations do not work | expand

Commit Message

Uros Bizjak July 18, 2019, 5:23 p.m. UTC
Attached patch fixes several strict_low_part insn patterns to operate
only on register outputs. Also, the patch paves the was for patterns
to handle unmatched registers (once PR82524) is fixed, and allows
patterns to operate on HImode operands.

2019-07-18  Uroš Bizjak  <ubizjak@gmail.com>

    PR target/91188
    * config/i386/i386.md (*addqi_1_slp): Use register_operand predicate
    for operand 0.  Do not use (match_dup) to match operand 1 with
    operand 0.  Add check in insn constraint that either input operand
    matches operand 0.  Use SWI12 mode iterator to also handle
    HImode operands.
    (*and<mode>_1_slp): Ditto.
    (*<code>qi_1_slp): Ditto.
    (*sub<mode>_1_slp): Use register_operand predicate for operand 0.
    Do not use (match_dup) to match operand 1 with operand 0.  Add
    check in insn constraint that operand 1 matches operand 0.
    Use SWI12 mode iterator to also handle HImode operands.
    (*ashl<mode>3_1_slp): Ditto.
    (*<shift_insn><mode>3_1_slp): Ditto.
    (*<rotate_insn><mode>3_1_slp): Ditto.

testsuite/ChangeLog:

2019-07-18  Uroš Bizjak  <ubizjak@gmail.com>

    PR target/91188
    * gcc.target/i386/pr91188-1a.c: New test.
    * gcc.target/i386/pr91188-1b.c: Ditto.
    * gcc.target/i386/pr91188-1c.c: Ditto.
    * gcc.target/i386/pr91188-2a.c: Ditto.
    * gcc.target/i386/pr91188-2b.c: Ditto.
    * gcc.target/i386/pr91188-2c.c: Ditto.

Patch was bootstrapped and regression tested on x86_64-linux-gnu {,-m32}.

Committed to mainline SVN.

Uros.

Comments

Uros Bizjak July 18, 2019, 6:04 p.m. UTC | #1
On Thu, Jul 18, 2019 at 7:23 PM Uros Bizjak <ubizjak@gmail.com> wrote:
>
> Attached patch fixes several strict_low_part insn patterns to operate
> only on register outputs. Also, the patch paves the was for patterns
> to handle unmatched registers (once PR82524) is fixed, and allows
> patterns to operate on HImode operands.

Please note that variable shifts currently don't trigger this
optimization (but constant shift do) due to unnecessary promotion to
int, as reported in PR91202 [1].

[1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91202

Uros.
diff mbox series

Patch

Index: config/i386/i386.md
===================================================================
--- config/i386/i386.md	(revision 273573)
+++ config/i386/i386.md	(working copy)
@@ -5583,41 +5583,39 @@ 
 	      (symbol_ref "!TARGET_PARTIAL_REG_STALL")]
 	   (symbol_ref "true")))])
 
-(define_insn "*addqi_1_slp"
-  [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,q"))
-	(plus:QI (match_dup 0)
-		 (match_operand:QI 1 "general_operand" "qn,m")))
+(define_insn "*add<mode>_1_slp"
+  [(set (strict_low_part (match_operand:SWI12 0 "register_operand" "+<r>"))
+	(plus:SWI12 (match_operand:SWI12 1 "nonimmediate_operand" "%0")
+		    (match_operand:SWI12 2 "general_operand" "<r>mn")))
    (clobber (reg:CC FLAGS_REG))]
-  "(! TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun))
-   && !(MEM_P (operands[0]) && MEM_P (operands[1]))"
+  "(!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun))
+   /* FIXME: without this LRA can't reload this pattern, see PR82524.  */
+   && (rtx_equal_p (operands[0], operands[1])
+       || rtx_equal_p (operands[0], operands[2]))"
 {
   switch (get_attr_type (insn))
     {
     case TYPE_INCDEC:
-      if (operands[1] == const1_rtx)
-	return "inc{b}\t%0";
+      if (operands[2] == const1_rtx)
+	return "inc{<imodesuffix>}\t%0";
       else
 	{
-	  gcc_assert (operands[1] == constm1_rtx);
-	  return "dec{b}\t%0";
+	  gcc_assert (operands[2] == constm1_rtx);
+	  return "dec{<imodesuffix>}\t%0";
 	}
 
     default:
-      if (x86_maybe_negate_const_int (&operands[1], QImode))
-	return "sub{b}\t{%1, %0|%0, %1}";
+      if (x86_maybe_negate_const_int (&operands[2], QImode))
+	return "sub{<imodesuffix>}\t{%2, %0|%0, %2}";
 
-      return "add{b}\t{%1, %0|%0, %1}";
+      return "add{<imodesuffix>}\t{%2, %0|%0, %2}";
     }
 }
   [(set (attr "type")
-     (if_then_else (match_operand:QI 1 "incdec_operand")
+     (if_then_else (match_operand:QI 2 "incdec_operand")
 	(const_string "incdec")
-	(const_string "alu1")))
-   (set (attr "memory")
-     (if_then_else (match_operand 1 "memory_operand")
-        (const_string "load")
-        (const_string "none")))
-   (set_attr "mode" "QI")])
+	(const_string "alu")))
+   (set_attr "mode" "<MODE>")])
 
 ;; Split non destructive adds if we cannot use lea.
 (define_split
@@ -6345,16 +6343,17 @@ 
   [(set_attr "type" "alu")
    (set_attr "mode" "SI")])
 
-(define_insn "*subqi_1_slp"
-  [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,q"))
-	(minus:QI (match_dup 0)
-		  (match_operand:QI 1 "general_operand" "qn,m")))
+(define_insn "*sub<mode>_1_slp"
+  [(set (strict_low_part (match_operand:SWI12 0 "register_operand" "+<r>"))
+	(minus:SWI12 (match_operand:SWI12 1 "register_operand" "0")
+		     (match_operand:SWI12 2 "general_operand" "<r>mn")))
    (clobber (reg:CC FLAGS_REG))]
-  "(! TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun))
-   && !(MEM_P (operands[0]) && MEM_P (operands[1]))"
-  "sub{b}\t{%1, %0|%0, %1}"
-  [(set_attr "type" "alu1")
-   (set_attr "mode" "QI")])
+  "(!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun))
+   /* FIXME: without this LRA can't reload this pattern, see PR82524.  */
+   && rtx_equal_p (operands[0], operands[1])"
+  "sub{<imodesuffix>}\t{%2, %0|%0, %2}"
+  [(set_attr "type" "alu")
+   (set_attr "mode" "<MODE>")])
 
 (define_insn "*sub<mode>_2"
   [(set (reg FLAGS_REG)
@@ -8548,16 +8547,18 @@ 
 	      (symbol_ref "!TARGET_PARTIAL_REG_STALL")]
 	   (symbol_ref "true")))])
 
-(define_insn "*andqi_1_slp"
-  [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,q"))
-	(and:QI (match_dup 0)
-		(match_operand:QI 1 "general_operand" "qn,m")))
+(define_insn "*and<mode>_1_slp"
+  [(set (strict_low_part (match_operand:SWI12 0 "register_operand" "+<r>"))
+	(and:SWI12 (match_operand:SWI12 1 "nonimmediate_operand" "%0")
+		   (match_operand:SWI12 2 "general_operand" "<r>mn")))
    (clobber (reg:CC FLAGS_REG))]
   "(!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun))
-   && !(MEM_P (operands[0]) && MEM_P (operands[1]))"
-  "and{b}\t{%1, %0|%0, %1}"
-  [(set_attr "type" "alu1")
-   (set_attr "mode" "QI")])
+   /* FIXME: without this LRA can't reload this pattern, see PR82524.  */
+   && (rtx_equal_p (operands[0], operands[1])
+       || rtx_equal_p (operands[0], operands[2]))"
+  "and{<imodesuffix>}\t{%2, %0|%0, %2}"
+  [(set_attr "type" "alu")
+   (set_attr "mode" "<MODE>")])
 
 (define_split
   [(set (match_operand:SWI248 0 "register_operand")
@@ -9098,16 +9099,18 @@ 
 	      (symbol_ref "!TARGET_PARTIAL_REG_STALL")]
 	   (symbol_ref "true")))])
 
-(define_insn "*<code>qi_1_slp"
-  [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,q"))
-	(any_or:QI (match_dup 0)
-		   (match_operand:QI 1 "general_operand" "qn,m")))
+(define_insn "*<code><mode>_1_slp"
+  [(set (strict_low_part (match_operand:SWI12 0 "register_operand" "+<r>"))
+	(any_or:SWI12 (match_operand:SWI12 1 "nonimmediate_operand" "%0")
+		      (match_operand:SWI12 2 "general_operand" "<r>mn")))
    (clobber (reg:CC FLAGS_REG))]
   "(!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun))
-   && !(MEM_P (operands[0]) && MEM_P (operands[1]))"
-  "<logic>{b}\t{%1, %0|%0, %1}"
-  [(set_attr "type" "alu1")
-   (set_attr "mode" "QI")])
+   /* FIXME: without this LRA can't reload this pattern, see PR82524.  */
+   && (rtx_equal_p (operands[0], operands[1])
+       || rtx_equal_p (operands[0], operands[2]))"
+  "<logic>{<imodesuffix>}\t{%2, %0|%0, %2}"
+  [(set_attr "type" "alu")
+   (set_attr "mode" "<MODE>")])
 
 (define_insn "*<code><mode>_2"
   [(set (reg FLAGS_REG)
@@ -9162,7 +9165,7 @@ 
   "(!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun))
    && ix86_match_ccmode (insn, CCNOmode)
    && !(MEM_P (operands[0]) && MEM_P (operands[1]))"
-  "<logic>{b}\t{%1, %0|%0, %1}"
+  "<logic>{<imodesuffix>}\t{%2, %0|%0, %2}"
   [(set_attr "type" "alu1")
    (set_attr "mode" "QI")])
 
@@ -10318,48 +10321,45 @@ 
 	      (symbol_ref "!TARGET_PARTIAL_REG_STALL")]
 	   (symbol_ref "true")))])
 
-(define_insn "*ashlqi3_1_slp"
-  [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm"))
-	(ashift:QI (match_dup 0)
-		   (match_operand:QI 1 "nonmemory_operand" "cI")))
+(define_insn "*ashl<mode>3_1_slp"
+  [(set (strict_low_part (match_operand:SWI12 0 "register_operand" "+<r>"))
+	(ashift:SWI12 (match_operand:SWI12 1 "register_operand" "0")
+		      (match_operand:QI 2 "nonmemory_operand" "cI")))
    (clobber (reg:CC FLAGS_REG))]
-  "(optimize_function_for_size_p (cfun)
-    || !TARGET_PARTIAL_FLAG_REG_STALL
-    || (operands[1] == const1_rtx
-	&& (TARGET_SHIFT1
-	    || (TARGET_DOUBLE_WITH_ADD && REG_P (operands[0])))))"
+  "(!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun))
+   /* FIXME: without this LRA can't reload this pattern, see PR82524.  */
+   && rtx_equal_p (operands[0], operands[1])"
 {
   switch (get_attr_type (insn))
     {
-    case TYPE_ALU1:
-      gcc_assert (operands[1] == const1_rtx);
-      return "add{b}\t%0, %0";
+    case TYPE_ALU:
+      gcc_assert (operands[2] == const1_rtx);
+      return "add{<imodesuffix>}\t%0, %0";
 
     default:
-      if (operands[1] == const1_rtx
+      if (operands[2] == const1_rtx
 	  && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun)))
-	return "sal{b}\t%0";
+	return "sal{<imodesuffix>}\t%0";
       else
-	return "sal{b}\t{%1, %0|%0, %1}";
+	return "sal{<imodesuffix>}\t{%2, %0|%0, %2}";
     }
 }
   [(set (attr "type")
-     (cond [(and (and (match_test "TARGET_DOUBLE_WITH_ADD")
-		      (match_operand 0 "register_operand"))
-		 (match_operand 1 "const1_operand"))
-	      (const_string "alu1")
+     (cond [(and (match_test "TARGET_DOUBLE_WITH_ADD")
+		 (match_operand 2 "const1_operand"))
+	      (const_string "alu")
 	   ]
-	   (const_string "ishift1")))
+	   (const_string "ishift")))
    (set (attr "length_immediate")
      (if_then_else
-       (ior (eq_attr "type" "alu1")
-	    (and (eq_attr "type" "ishift1")
-		 (and (match_operand 1 "const1_operand")
+       (ior (eq_attr "type" "alu")
+	    (and (eq_attr "type" "ishift")
+		 (and (match_operand 2 "const1_operand")
 		      (ior (match_test "TARGET_SHIFT1")
 			   (match_test "optimize_function_for_size_p (cfun)")))))
        (const_string "0")
        (const_string "*")))
-   (set_attr "mode" "QI")])
+   (set_attr "mode" "<MODE>")])
 
 ;; Convert ashift to the lea pattern to avoid flags dependency.
 (define_split
@@ -10937,31 +10937,30 @@ 
        (const_string "*")))
    (set_attr "mode" "<MODE>")])
 
-(define_insn "*<shift_insn>qi3_1_slp"
-  [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm"))
-	(any_shiftrt:QI (match_dup 0)
-			(match_operand:QI 1 "nonmemory_operand" "cI")))
+(define_insn "*<shift_insn><mode>3_1_slp"
+  [(set (strict_low_part (match_operand:SWI12 0 "register_operand" "+<r>"))
+	(any_shiftrt:SWI12 (match_operand:SWI12 1 "register_operand" "0")
+			   (match_operand:QI 2 "nonmemory_operand" "cI")))
    (clobber (reg:CC FLAGS_REG))]
-  "(optimize_function_for_size_p (cfun)
-    || !TARGET_PARTIAL_REG_STALL
-    || (operands[1] == const1_rtx
-	&& TARGET_SHIFT1))"
+  "(!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun))
+   /* FIXME: without this LRA can't reload this pattern, see PR82524.  */
+   && rtx_equal_p (operands[0], operands[1])"
 {
-  if (operands[1] == const1_rtx
+  if (operands[2] == const1_rtx
       && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun)))
-    return "<shift>{b}\t%0";
+    return "<shift>{<imodesuffix>}\t%0";
   else
-    return "<shift>{b}\t{%1, %0|%0, %1}";
+    return "<shift>{<imodesuffix>}\t{%2, %0|%0, %2}";
 }
-  [(set_attr "type" "ishift1")
+  [(set_attr "type" "ishift")
    (set (attr "length_immediate")
      (if_then_else
-       (and (match_operand 1 "const1_operand")
+       (and (match_operand 2 "const1_operand")
 	    (ior (match_test "TARGET_SHIFT1")
 		 (match_test "optimize_function_for_size_p (cfun)")))
        (const_string "0")
        (const_string "*")))
-   (set_attr "mode" "QI")])
+   (set_attr "mode" "<MODE>")])
 
 ;; This pattern can't accept a variable shift count, since shifts by
 ;; zero don't affect the flags.  We assume that shifts by constant
@@ -11366,31 +11365,30 @@ 
        (const_string "*")))
    (set_attr "mode" "<MODE>")])
 
-(define_insn "*<rotate_insn>qi3_1_slp"
-  [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm"))
-	(any_rotate:QI (match_dup 0)
-		       (match_operand:QI 1 "nonmemory_operand" "cI")))
+(define_insn "*<rotate_insn><mode>3_1_slp"
+  [(set (strict_low_part (match_operand:SWI12 0 "register_operand" "+<r>"))
+	(any_rotate:SWI12 (match_operand:SWI12 1 "register_operand" "0")
+			  (match_operand:QI 2 "nonmemory_operand" "cI")))
    (clobber (reg:CC FLAGS_REG))]
-  "(optimize_function_for_size_p (cfun)
-    || !TARGET_PARTIAL_REG_STALL
-    || (operands[1] == const1_rtx
-	&& TARGET_SHIFT1))"
+  "(!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun))
+   /* FIXME: without this LRA can't reload this pattern, see PR82524.  */
+   && rtx_equal_p (operands[0], operands[1])"
 {
-  if (operands[1] == const1_rtx
+  if (operands[2] == const1_rtx
       && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun)))
-    return "<rotate>{b}\t%0";
+    return "<rotate>{<imodesuffix>}\t%0";
   else
-    return "<rotate>{b}\t{%1, %0|%0, %1}";
+    return "<rotate>{<imodesuffix>}\t{%2, %0|%0, %2}";
 }
-  [(set_attr "type" "rotate1")
+  [(set_attr "type" "rotate")
    (set (attr "length_immediate")
      (if_then_else
-       (and (match_operand 1 "const1_operand")
+       (and (match_operand 2 "const1_operand")
 	    (ior (match_test "TARGET_SHIFT1")
 		 (match_test "optimize_function_for_size_p (cfun)")))
        (const_string "0")
        (const_string "*")))
-   (set_attr "mode" "QI")])
+   (set_attr "mode" "<MODE>")])
 
 (define_split
  [(set (match_operand:HI 0 "QIreg_operand")
Index: testsuite/gcc.target/i386/pr91188-1a.c
===================================================================
--- testsuite/gcc.target/i386/pr91188-1a.c	(nonexistent)
+++ testsuite/gcc.target/i386/pr91188-1a.c	(working copy)
@@ -0,0 +1,63 @@ 
+/* PR target/91188 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -masm=att" } */
+/* { dg-additional-options "-mregparm=3" { target ia32 } } */
+/* { dg-final { scan-assembler-not "movzbl" } } */
+/* { dg-final { scan-assembler-not "movb" } } */
+
+struct S
+{
+  unsigned char val;
+  unsigned char pad1;
+  unsigned short pad2;
+};
+
+struct S
+test_and (struct S a, unsigned char b)
+{
+  a.val &= b;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]andb" } } */
+
+struct S
+test_or (struct S a, unsigned char b)
+{
+  a.val |= b;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]orb" } } */
+
+struct S
+test_xor (struct S a, unsigned char b)
+{
+  a.val ^= b;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]xorb" } } */
+
+struct S
+test_add (struct S a, unsigned char b)
+{
+  a.val += b;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]addb" } } */
+
+struct S
+test_sub (struct S a, unsigned char b)
+{
+  a.val -= b;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]subb" } } */
Index: testsuite/gcc.target/i386/pr91188-1b.c
===================================================================
--- testsuite/gcc.target/i386/pr91188-1b.c	(nonexistent)
+++ testsuite/gcc.target/i386/pr91188-1b.c	(working copy)
@@ -0,0 +1,65 @@ 
+/* PR target/91188 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -masm=att" } */
+/* { dg-additional-options "-mregparm=3" { target ia32 } } */
+/* { dg-final { scan-assembler-not "movzbl" } } */
+/* { dg-final { scan-assembler-not "movb" } } */
+
+struct S
+{
+  unsigned char val;
+  unsigned char pad1;
+  unsigned short pad2;
+};
+
+unsigned char b;
+
+struct S
+test_and (struct S a)
+{
+  a.val &= b;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]andb" } } */
+
+struct S
+test_or (struct S a)
+{
+  a.val |= b;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]orb" } } */
+
+struct S
+test_xor (struct S a)
+{
+  a.val ^= b;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]xorb" } } */
+
+struct S
+test_add (struct S a)
+{
+  a.val += b;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]addb" } } */
+
+struct S
+test_sub (struct S a)
+{
+  a.val -= b;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]subb" } } */
Index: testsuite/gcc.target/i386/pr91188-1c.c
===================================================================
--- testsuite/gcc.target/i386/pr91188-1c.c	(nonexistent)
+++ testsuite/gcc.target/i386/pr91188-1c.c	(working copy)
@@ -0,0 +1,113 @@ 
+/* PR target/91188 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -masm=att" } */
+/* { dg-additional-options "-mregparm=3" { target ia32 } } */
+/* { dg-final { scan-assembler-not "movzbl" } } */
+/* { dg-final { scan-assembler-not "movb" } } */
+
+struct S
+{
+  unsigned char val;
+  unsigned char pad1;
+  unsigned short pad2;
+};
+
+struct S
+test_and (struct S a)
+{
+  a.val &= 0x42;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]andb" } } */
+
+struct S
+test_or (struct S a)
+{
+  a.val |= 0x42;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]orb" } } */
+
+struct S
+test_xor (struct S a)
+{
+  a.val ^= 0x42;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]xorb" } } */
+
+struct S
+test_sal (struct S a)
+{
+  a.val <<= 3;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]salb" } } */
+
+struct S
+test_shr (struct S a)
+{
+  a.val >>= 3;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]shrb" } } */
+
+struct S
+test_sar (struct S a)
+{
+  a.val = (signed char) a.val >> 3;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]sarb" } } */
+
+struct S
+test_rol (struct S a)
+{
+  a.val = (a.val << 3 | a.val >> 5) ;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]rolb" } } */
+
+struct S
+test_ror (struct S a)
+{
+  a.val = (a.val >> 3 | a.val << 5) ;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]rorb" } } */
+
+struct S
+test_add (struct S a)
+{
+  a.val += 42;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]addb" } } */
+
+struct S
+test_sub (struct S a)
+{
+  a.val -= 42;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]subb" } } */
Index: testsuite/gcc.target/i386/pr91188-2a.c
===================================================================
--- testsuite/gcc.target/i386/pr91188-2a.c	(nonexistent)
+++ testsuite/gcc.target/i386/pr91188-2a.c	(working copy)
@@ -0,0 +1,62 @@ 
+/* PR target/91188 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -masm=att" } */
+/* { dg-additional-options "-mregparm=3" { target ia32 } } */
+/* { dg-final { scan-assembler-not "movzwl" } } */
+/* { dg-final { scan-assembler-not "movw" } } */
+
+struct S
+{
+  unsigned short val;
+  unsigned short pad;
+};
+
+struct S
+test_and (struct S a, unsigned short b)
+{
+  a.val &= b;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]andw" } } */
+
+struct S
+test_or (struct S a, unsigned short b)
+{
+  a.val |= b;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]orw" } } */
+
+struct S
+test_xor (struct S a, unsigned short b)
+{
+  a.val ^= b;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]xorw" } } */
+
+struct S
+test_add (struct S a, unsigned short b)
+{
+  a.val += b;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]addw" } } */
+
+struct S
+test_sub (struct S a, unsigned short b)
+{
+  a.val -= b;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]subw" } } */
Index: testsuite/gcc.target/i386/pr91188-2b.c
===================================================================
--- testsuite/gcc.target/i386/pr91188-2b.c	(nonexistent)
+++ testsuite/gcc.target/i386/pr91188-2b.c	(working copy)
@@ -0,0 +1,64 @@ 
+/* PR target/91188 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -masm=att" } */
+/* { dg-additional-options "-mregparm=3" { target ia32 } } */
+/* { dg-final { scan-assembler-not "movzwl" } } */
+/* { dg-final { scan-assembler-not "movw" } } */
+
+struct S
+{
+  unsigned short val;
+  unsigned short pad;
+};
+
+unsigned short b;
+
+struct S
+test_and (struct S a)
+{
+  a.val &= b;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]andw" } } */
+
+struct S
+test_or (struct S a)
+{
+  a.val |= b;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]orw" } } */
+
+struct S
+test_xor (struct S a)
+{
+  a.val ^= b;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]xorw" } } */
+
+struct S
+test_add (struct S a)
+{
+  a.val += b;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]addw" } } */
+
+struct S
+test_sub (struct S a)
+{
+  a.val -= b;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]subw" } } */
Index: testsuite/gcc.target/i386/pr91188-2c.c
===================================================================
--- testsuite/gcc.target/i386/pr91188-2c.c	(nonexistent)
+++ testsuite/gcc.target/i386/pr91188-2c.c	(working copy)
@@ -0,0 +1,112 @@ 
+/* PR target/91188 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -masm=att" } */
+/* { dg-additional-options "-mregparm=3" { target ia32 } } */
+/* { dg-final { scan-assembler-not "movzwl" } } */
+/* { dg-final { scan-assembler-not "movw" } } */
+
+struct S
+{
+  unsigned short val;
+  unsigned short pad;
+};
+
+struct S
+test_and (struct S a)
+{
+  a.val &= 0x42;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]andw" } } */
+
+struct S
+test_or (struct S a)
+{
+  a.val |= 0x42;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]orw" } } */
+
+struct S
+test_xor (struct S a)
+{
+  a.val ^= 0x42;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]xorw" } } */
+
+struct S
+test_sal (struct S a)
+{
+  a.val <<= 3;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]salw" } } */
+
+struct S
+test_shr (struct S a)
+{
+  a.val >>= 3;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]shrw" } } */
+
+struct S
+test_sar (struct S a)
+{
+  a.val = (signed short) a.val >> 3;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]sarw" } } */
+
+struct S
+test_rol (struct S a)
+{
+  a.val = (a.val << 3 | a.val >> 13) ;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]rolw" } } */
+
+struct S
+test_ror (struct S a)
+{
+  a.val = (a.val >> 3 | a.val << 13) ;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]rorw" } } */
+
+struct S
+test_add (struct S a)
+{
+  a.val += 42;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]addw" } } */
+
+struct S
+test_sub (struct S a)
+{
+  a.val -= 42;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]subw" } } */