diff --git a/gcc/combine.c b/gcc/combine.c
index 1bee2c7..d3305cb 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -7277,22 +7277,21 @@ make_compound_operation (rtx x, enum rtx_code in_code)
       /* Call ourselves recursively on the inner expression.  If we are
 	 narrowing the object and it has a different RTL code from
 	 what it originally did, do this SUBREG as a force_to_mode.  */
-
-      tem = make_compound_operation (SUBREG_REG (x), in_code);
-
       {
-	rtx simplified = simplify_subreg (mode, tem, GET_MODE (SUBREG_REG (x)),
-					  SUBREG_BYTE (x));
+	rtx inner = SUBREG_REG (x), simplified;
+	
+	tem = make_compound_operation (inner, in_code);
 
+	simplified
+	  = simplify_subreg (mode, tem, GET_MODE (inner), SUBREG_BYTE (x));
 	if (simplified)
 	  tem = simplified;
 
-	if (GET_CODE (tem) != GET_CODE (SUBREG_REG (x))
-	    && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
+	if (GET_CODE (tem) != GET_CODE (inner)
+	    && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (inner))
 	    && subreg_lowpart_p (x))
 	  {
-	    rtx newer = force_to_mode (tem, mode, ~(HOST_WIDE_INT) 0,
-				       0);
+	    rtx newer = force_to_mode (tem, mode, ~(HOST_WIDE_INT) 0, 0);
 
 	    /* If we have something other than a SUBREG, we might have
 	       done an expansion, so rerun ourselves.  */
@@ -7300,9 +7299,16 @@ make_compound_operation (rtx x, enum rtx_code in_code)
 	      newer = make_compound_operation (newer, in_code);
 
 	    /* force_to_mode can expand compounds.  If it just re-expanded the
-	       compound use gen_lowpart instead to convert to the desired
-	       mode.  */
-	    if (rtx_equal_p (newer, x))
+	       compound, use gen_lowpart to convert to the desired mode.  */
+	    if (rtx_equal_p (newer, x)
+		/* Likewise if it re-expanded the compound only partially.
+		   This happens for SUBREG of ZERO_EXTRACT if they extract
+		   the same number of bits.  */
+		|| (GET_CODE (newer) == SUBREG
+		    && (GET_CODE (SUBREG_REG (newer)) == LSHIFTRT
+			|| GET_CODE (SUBREG_REG (newer)) == ASHIFTRT)
+		    && GET_CODE (inner) == AND
+		    && rtx_equal_p (SUBREG_REG (newer), XEXP (inner, 0))))
 	      return gen_lowpart (GET_MODE (x), tem);
 
 	    return newer;
diff --git a/gcc/testsuite/gcc.target/i386/extract-1.c b/gcc/testsuite/gcc.target/i386/extract-1.c
new file mode 100644
index 0000000..102beb2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/extract-1.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mtune=generic" } */
+
+int
+foo (unsigned char x, unsigned char y)
+{
+   return (x % y) != 0;
+}
+
+/* { dg-final { scan-assembler-not "test\[b\]?\[^\\n\]*%\[a-d\]l" } } */
diff --git a/gcc/testsuite/gcc.target/i386/extract-2.c b/gcc/testsuite/gcc.target/i386/extract-2.c
new file mode 100644
index 0000000..3bb5f15
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/extract-2.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mtune=generic" } */
+
+int
+foo (unsigned char x, unsigned char y)
+{
+   return (x % y) > 4;
+}
+
+/* { dg-final { scan-assembler-times "cmp\[b\]?\[^\\n\]*%\[a-d\]h" 1 } } */
+/* { dg-final { scan-assembler-not "cmp\[b\]?\[^\\n\]*%\[a-d\]l" } } */
diff --git a/gcc/testsuite/gcc.target/i386/extract-3.c b/gcc/testsuite/gcc.target/i386/extract-3.c
new file mode 100644
index 0000000..520bf3b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/extract-3.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mtune=generic" } */
+
+typedef struct
+{
+  unsigned char c1;
+  unsigned char c2;
+  unsigned char c3;
+  unsigned char c4;
+} foo_t;
+
+int
+#ifndef __x86_64__
+__attribute__((regparm(3)))
+#endif
+foo (foo_t x)
+{
+   return x.c2 != 0;
+}
+
+/* { dg-final { scan-assembler-not "test\[b\]?\[^\\n\]*%\[a-z0-9\]+l" } } */
diff --git a/gcc/testsuite/gcc.target/i386/extract-4.c b/gcc/testsuite/gcc.target/i386/extract-4.c
new file mode 100644
index 0000000..716ae22
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/extract-4.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mtune=generic" } */
+
+typedef struct
+{
+  unsigned char c1;
+  unsigned char c2;
+  unsigned char c3;
+  unsigned char c4;
+} foo_t;
+
+int
+#ifndef __x86_64__
+__attribute__((regparm(3)))
+#endif
+foo (foo_t x)
+{
+   return x.c2 > 4;
+}
+
+/* { dg-final { scan-assembler-times "cmp\[b\]?\[^\\n\]*%\[a-z0-9\]+h" 1 } } */
+/* { dg-final { scan-assembler-not "cmp\[b\]?\[^\\n\]*%\[a-z0-9\]+l" } } */
diff --git a/gcc/testsuite/gcc.target/i386/extract-5.c b/gcc/testsuite/gcc.target/i386/extract-5.c
new file mode 100644
index 0000000..a488daf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/extract-5.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mtune=generic" } */
+
+typedef struct
+{
+  unsigned int c1:8;
+  unsigned int c2:8;
+  unsigned int c3:8;
+  unsigned int c4:8;
+} foo_t;
+
+int
+#ifndef __x86_64__
+__attribute__((regparm(3)))
+#endif
+foo (foo_t x)
+{
+   return x.c2 != 0;
+}
+
+/* { dg-final { scan-assembler-not "test\[b\]?\[^\\n\]*%\[a-z0-9\]+l" } } */
diff --git a/gcc/testsuite/gcc.target/i386/extract-6.c b/gcc/testsuite/gcc.target/i386/extract-6.c
new file mode 100644
index 0000000..1440ec3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/extract-6.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mtune=generic" } */
+
+typedef struct
+{
+  unsigned int c1:8;
+  unsigned int c2:8;
+  unsigned int c3:8;
+  unsigned int c4:8;
+
+} foo_t;
+
+int
+#ifndef __x86_64__
+__attribute__((regparm(3)))
+#endif
+foo (foo_t x)
+{
+   return x.c2 > 4;
+}
+
+/* { dg-final { scan-assembler-times "cmp\[b\]?\[^\\n\]*%\[a-z0-9\]+h" 1 } } */
+/* { dg-final { scan-assembler-not "cmp\[b\]?\[^\\n\]*%\[a-z0-9\]+l" } } */
