gcc/

2012-08-02  H.J. Lu  <hongjiu.lu@intel.com>

	PR rtl-optimization/54157
	* combine.c (make_extraction): Pass inner_mode to mode_for_extraction
	for operand 1, otherwise pass VOIDmode.
	(simplify_comparison): Pass VOIDmode to mode_for_extraction.

	* expmed.c (mode_for_extraction): Add a machine_mode argument
	and use it instead of word_mode if it isn't VOIDmode.
	(store_bit_field_1): Pass VOIDmode to mode_for_extraction.
	(store_bit_field): Likewise.

	* expr.h (mode_for_extraction): Add a machine_mode argument.

	* config/i386/i386.md (*jcc_btsi_mask_2): New insn_and_split
	pattern.

	* recog.c (simplify_while_replacing): Pass is_mode to
	mode_for_extraction.

gcc/testsuite/

2012-08-02  H.J. Lu  <hongjiu.lu@intel.com>

	PR rtl-optimization/54157
	* gcc.target/i386/pr54157.c: New file.

diff --git a/gcc/combine.c b/gcc/combine.c
index a07c046..035aeb9 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -7332,27 +7332,30 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
 
   /* Get the mode to use should INNER not be a MEM, the mode for the position,
      and the mode for the result.  */
-  if (in_dest && mode_for_extraction (EP_insv, -1) != MAX_MACHINE_MODE)
+  if (in_dest
+      && mode_for_extraction (EP_insv, -1, VOIDmode) != MAX_MACHINE_MODE)
     {
-      wanted_inner_reg_mode = mode_for_extraction (EP_insv, 0);
-      pos_mode = mode_for_extraction (EP_insv, 2);
-      extraction_mode = mode_for_extraction (EP_insv, 3);
+      wanted_inner_reg_mode = mode_for_extraction (EP_insv, 0, VOIDmode);
+      pos_mode = mode_for_extraction (EP_insv, 2, VOIDmode);
+      extraction_mode = mode_for_extraction (EP_insv, 3, VOIDmode);
     }
 
   if (! in_dest && unsignedp
-      && mode_for_extraction (EP_extzv, -1) != MAX_MACHINE_MODE)
+      && mode_for_extraction (EP_extzv, -1, VOIDmode) != MAX_MACHINE_MODE)
     {
-      wanted_inner_reg_mode = mode_for_extraction (EP_extzv, 1);
-      pos_mode = mode_for_extraction (EP_extzv, 3);
-      extraction_mode = mode_for_extraction (EP_extzv, 0);
+      wanted_inner_reg_mode = mode_for_extraction (EP_extzv, 1,
+						   inner_mode);
+      pos_mode = mode_for_extraction (EP_extzv, 3, VOIDmode);
+      extraction_mode = mode_for_extraction (EP_extzv, 0, VOIDmode);
     }
 
   if (! in_dest && ! unsignedp
-      && mode_for_extraction (EP_extv, -1) != MAX_MACHINE_MODE)
+      && mode_for_extraction (EP_extv, -1, VOIDmode) != MAX_MACHINE_MODE)
     {
-      wanted_inner_reg_mode = mode_for_extraction (EP_extv, 1);
-      pos_mode = mode_for_extraction (EP_extv, 3);
-      extraction_mode = mode_for_extraction (EP_extv, 0);
+      wanted_inner_reg_mode = mode_for_extraction (EP_extv, 1,
+						   inner_mode);
+      pos_mode = mode_for_extraction (EP_extv, 3, VOIDmode);
+      extraction_mode = mode_for_extraction (EP_extv, 0, VOIDmode);
     }
 
   /* Never narrow an object, since that might not be safe.  */
@@ -11294,7 +11297,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
 	      if (BITS_BIG_ENDIAN)
 		{
 		  enum machine_mode new_mode
-		    = mode_for_extraction (EP_extzv, 1);
+		    = mode_for_extraction (EP_extzv, 1, VOIDmode);
 		  if (new_mode == MAX_MACHINE_MODE)
 		    i = BITS_PER_WORD - 1 - i;
 		  else
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index ace3b6e..6835d31 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -11065,6 +11065,39 @@
 		      (pc)))]
   "PUT_CODE (operands[0], reverse_condition (GET_CODE (operands[0])));")
 
+(define_insn_and_split "*jcc_btsi_mask_2"
+  [(set (pc)
+  	(if_then_else
+	  (match_operator 0 "bt_comparison_operator"
+	    [(zero_extract:SI
+	       (match_operand:SI 1 "register_operand" "r")
+	       (const_int 1)
+	       (zero_extend:SI
+		 (subreg:QI
+		   (and:SI
+		     (match_operand:SI 2 "register_operand" "r")
+		     (match_operand:SI 3 "const_int_operand" "n")) 0)))
+	     (const_int 0)])
+	  (label_ref (match_operand 4))
+	  (pc)))
+   (clobber (reg:CC FLAGS_REG))]
+  "(TARGET_USE_BT || optimize_function_for_size_p (cfun))
+   && (INTVAL (operands[3]) & 0x1f) == 0x1f"
+  "#"
+  "&& 1"
+  [(set (reg:CCC FLAGS_REG)
+	(compare:CCC
+	  (zero_extract:SI
+	    (match_dup 1)
+	    (const_int 1)
+	    (match_dup 2))
+	  (const_int 0)))
+   (set (pc)
+	(if_then_else (match_op_dup 0 [(reg:CCC FLAGS_REG) (const_int 0)])
+		      (label_ref (match_dup 4))
+		      (pc)))]
+  "PUT_CODE (operands[0], reverse_condition (GET_CODE (operands[0])));")
+
 ;; Define combination compare-and-branch fp compare instructions to help
 ;; combine.
 
diff --git a/gcc/expmed.c b/gcc/expmed.c
index 1fe0034..367f94d 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -338,9 +338,12 @@ negate_rtx (enum machine_mode mode, rtx x)
 /* Report on the availability of insv/extv/extzv and the desired mode
    of each of their operands.  Returns MAX_MACHINE_MODE if HAVE_foo
    is false; else the mode of the specified operand.  If OPNO is -1,
-   all the caller cares about is whether the insn is available.  */
+   all the caller cares about is whether the insn is available.  Return
+   MODE instead of word_mode if it isn't VOIDmode.  */
+
 enum machine_mode
-mode_for_extraction (enum extraction_pattern pattern, int opno)
+mode_for_extraction (enum extraction_pattern pattern, int opno,
+		     enum machine_mode mode)
 {
   const struct insn_data_d *data;
 
@@ -380,7 +383,7 @@ mode_for_extraction (enum extraction_pattern pattern, int opno)
   /* Everyone who uses this function used to follow it with
      if (result == VOIDmode) result = word_mode; */
   if (data->operand[opno].mode == VOIDmode)
-    return word_mode;
+    return mode != VOIDmode ? mode : word_mode;
   return data->operand[opno].mode;
 }
 
@@ -406,7 +409,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
   int byte_offset;
   rtx orig_value;
 
-  enum machine_mode op_mode = mode_for_extraction (EP_insv, 3);
+  enum machine_mode op_mode = mode_for_extraction (EP_insv, 3, VOIDmode);
 
   while (GET_CODE (op0) == SUBREG)
     {
@@ -894,7 +897,7 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       enum machine_mode op_mode;
       unsigned HOST_WIDE_INT offset;
 
-      op_mode = mode_for_extraction (EP_insv, 3);
+      op_mode = mode_for_extraction (EP_insv, 3, VOIDmode);
       if (op_mode == MAX_MACHINE_MODE)
 	op_mode = VOIDmode;
 
@@ -1592,7 +1595,8 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
     }
 
   /* Now OFFSET is nonzero only for memory operands.  */
-  ext_mode = mode_for_extraction (unsignedp ? EP_extzv : EP_extv, 0);
+  ext_mode = mode_for_extraction (unsignedp ? EP_extzv : EP_extv, 0,
+				  VOIDmode);
   if (ext_mode != MAX_MACHINE_MODE
       && bitsize > 0
       && GET_MODE_BITSIZE (ext_mode) >= bitsize
diff --git a/gcc/expr.h b/gcc/expr.h
index 68cdb8d..588299c 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -687,7 +687,7 @@ extern rtx hard_libcall_value (enum machine_mode, rtx);
 
 enum extraction_pattern { EP_insv, EP_extv, EP_extzv };
 extern enum machine_mode
-mode_for_extraction (enum extraction_pattern, int);
+mode_for_extraction (enum extraction_pattern, int, enum machine_mode);
 
 extern void store_bit_field (rtx, unsigned HOST_WIDE_INT,
 			     unsigned HOST_WIDE_INT,
diff --git a/gcc/recog.c b/gcc/recog.c
index a05e8c6..2d1e4db 100644
--- a/gcc/recog.c
+++ b/gcc/recog.c
@@ -639,14 +639,14 @@ simplify_while_replacing (rtx *loc, rtx to, rtx object,
 	  if (GET_CODE (x) == ZERO_EXTRACT)
 	    {
 	      enum machine_mode new_mode
-		= mode_for_extraction (EP_extzv, 1);
+		= mode_for_extraction (EP_extzv, 1, is_mode);
 	      if (new_mode != MAX_MACHINE_MODE)
 		wanted_mode = new_mode;
 	    }
 	  else if (GET_CODE (x) == SIGN_EXTRACT)
 	    {
 	      enum machine_mode new_mode
-		= mode_for_extraction (EP_extv, 1);
+		= mode_for_extraction (EP_extv, 1, is_mode);
 	      if (new_mode != MAX_MACHINE_MODE)
 		wanted_mode = new_mode;
 	    }
diff --git a/gcc/testsuite/gcc.target/i386/pr54157.c b/gcc/testsuite/gcc.target/i386/pr54157.c
new file mode 100644
index 0000000..b5c4528
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr54157.c
@@ -0,0 +1,21 @@
+/* { dg-do compile { target { ! { ia32 } } } } */
+/* { dg-options "-O2 -mx32 -maddress-mode=long -ftree-vectorize" } */
+
+struct s2{
+  int n[24 -1][24 -1][24 -1];
+};
+
+struct test2{
+  struct s2 e;
+};
+
+struct test2 tmp2[4];
+
+void main1 ()
+{
+  int i,j;
+
+  for (i = 0; i < 24 -4; i++)
+      for (j = 0; j < 24 -4; j++)
+          tmp2[2].e.n[1][i][j] = 8;
+}
