OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / tree-vect-patterns.c
index 46d43ce..c3f24a1 100644 (file)
@@ -1,5 +1,5 @@
 /* Analysis Utilities for Loop Vectorization.
-   Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011
+   Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012
    Free Software Foundation, Inc.
    Contributed by Dorit Nuzman <dorit@il.ibm.com>
 
@@ -63,8 +63,8 @@ static vect_recog_func_ptr vect_vect_recog_func_ptrs[NUM_PATTERNS] = {
        vect_recog_widen_sum_pattern,
        vect_recog_dot_prod_pattern,
        vect_recog_pow_pattern,
-       vect_recog_over_widening_pattern,
        vect_recog_widen_shift_pattern,
+       vect_recog_over_widening_pattern,
        vect_recog_vector_vector_shift_pattern,
        vect_recog_sdivmod_pow2_pattern,
        vect_recog_mixed_size_cond_pattern,
@@ -84,6 +84,32 @@ new_pattern_def_seq (stmt_vec_info stmt_info, gimple stmt)
   append_pattern_def_seq (stmt_info, stmt);
 }
 
+/* If the LHS of DEF_STMT has a single use, and that statement is
+   in the same loop, return it.  */
+
+static gimple
+vect_single_imm_use (gimple def_stmt)
+{
+  stmt_vec_info stmt_vinfo = vinfo_for_stmt (def_stmt);
+  loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
+  struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
+  tree lhs = gimple_assign_lhs (def_stmt);
+  use_operand_p use_p;
+  gimple use_stmt;
+
+  if (!single_imm_use (lhs, &use_p, &use_stmt))
+    return NULL;
+
+  if (!gimple_bb (use_stmt))
+    return NULL;
+
+  if (!flow_bb_inside_loop_p (loop, gimple_bb (use_stmt)))
+    return NULL;
+
+  gcc_assert (vinfo_for_stmt (use_stmt));
+  return use_stmt;
+}
+
 /* Function widened_name_p
 
    Check whether NAME, an ssa-name used in USE_STMT,
@@ -109,7 +135,8 @@ widened_name_p (tree name, gimple use_stmt, tree *half_type, gimple *def_stmt,
   stmt_vinfo = vinfo_for_stmt (use_stmt);
   loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
 
-  if (!vect_is_simple_use (name, loop_vinfo, NULL, def_stmt, &def, &dt))
+  if (!vect_is_simple_use (name, use_stmt, loop_vinfo, NULL, def_stmt, &def,
+                          &dt))
     return false;
 
   if (dt != vect_internal_def
@@ -133,8 +160,8 @@ widened_name_p (tree name, gimple use_stmt, tree *half_type, gimple *def_stmt,
       || (TYPE_PRECISION (type) < (TYPE_PRECISION (*half_type) * 2)))
     return false;
 
-  if (!vect_is_simple_use (oprnd0, loop_vinfo, NULL, &dummy_gimple, &dummy,
-                           &dt))
+  if (!vect_is_simple_use (oprnd0, *def_stmt, loop_vinfo,
+                          NULL, &dummy_gimple, &dummy, &dt))
     return false;
 
   return true;
@@ -581,25 +608,15 @@ vect_recog_widen_mult_pattern (VEC (gimple, heap) **stmts,
      Use unsigned TYPE as the type for WIDEN_MULT_EXPR.  */
   if (TYPE_UNSIGNED (type) != TYPE_UNSIGNED (half_type0))
     {
-      tree lhs = gimple_assign_lhs (last_stmt), use_lhs;
-      imm_use_iterator imm_iter;
-      use_operand_p use_p;
-      int nuses = 0;
-      gimple use_stmt = NULL;
+      gimple use_stmt;
+      tree use_lhs;
       tree use_type;
 
       if (TYPE_UNSIGNED (type) == TYPE_UNSIGNED (half_type1))
         return NULL;
 
-      FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs)
-        {
-         if (is_gimple_debug (USE_STMT (use_p)))
-           continue;
-          use_stmt = USE_STMT (use_p);
-          nuses++;
-        }
-
-      if (nuses != 1 || !is_gimple_assign (use_stmt)
+      use_stmt = vect_single_imm_use (last_stmt);
+      if (!use_stmt || !is_gimple_assign (use_stmt)
           || gimple_assign_rhs_code (use_stmt) != NOP_EXPR)
         return NULL;
 
@@ -920,6 +937,11 @@ vect_operation_fits_smaller_type (gimple stmt, tree def, tree *new_type,
       || TREE_CODE (const_oprnd) != INTEGER_CST)
     return false;
 
+  /* If oprnd has other uses besides that in stmt we cannot mark it
+     as being part of a pattern only.  */
+  if (!has_single_use (oprnd))
+    return false;
+
   /* If we are in the middle of a sequence, we use DEF from a previous
      statement.  Otherwise, OPRND has to be a result of type promotion.  */
   if (*new_type)
@@ -1100,13 +1122,9 @@ vect_recog_over_widening_pattern (VEC (gimple, heap) **stmts,
 {
   gimple stmt = VEC_pop (gimple, *stmts);
   gimple pattern_stmt = NULL, new_def_stmt, prev_stmt = NULL, use_stmt = NULL;
-  tree op0, op1, vectype = NULL_TREE, lhs, use_lhs, use_type;
-  imm_use_iterator imm_iter;
-  use_operand_p use_p;
-  int nuses = 0;
+  tree op0, op1, vectype = NULL_TREE, use_lhs, use_type;
   tree var = NULL_TREE, new_type = NULL_TREE, tmp, new_oprnd;
   bool first;
-  struct loop *loop = (gimple_bb (stmt))->loop_father;
   tree type = NULL;
 
   first = true;
@@ -1128,19 +1146,8 @@ vect_recog_over_widening_pattern (VEC (gimple, heap) **stmts,
         }
 
       /* STMT can be performed on a smaller type.  Check its uses.  */
-      lhs = gimple_assign_lhs (stmt);
-      nuses = 0;
-      FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs)
-        {
-          if (is_gimple_debug (USE_STMT (use_p)))
-            continue;
-          use_stmt = USE_STMT (use_p);
-          nuses++;
-        }
-
-      if (nuses != 1 || !is_gimple_assign (use_stmt)
-          || !gimple_bb (use_stmt)
-          || !flow_bb_inside_loop_p (loop, gimple_bb (use_stmt)))
+      use_stmt = vect_single_imm_use (stmt);
+      if (!use_stmt || !is_gimple_assign (use_stmt))
         return NULL;
 
       /* Create pattern statement for STMT.  */
@@ -1186,13 +1193,15 @@ vect_recog_over_widening_pattern (VEC (gimple, heap) **stmts,
     {
       use_lhs = gimple_assign_lhs (use_stmt);
       use_type = TREE_TYPE (use_lhs);
-      /* Support only type promotion or signedess change.  Check that USE_TYPE
-        is not bigger than the original type.  */
+      /* Support only type demotion or signedess change.  */
       if (!INTEGRAL_TYPE_P (use_type)
-          || TYPE_PRECISION (new_type) > TYPE_PRECISION (use_type)
-         || TYPE_PRECISION (type) < TYPE_PRECISION (use_type))
+         || TYPE_PRECISION (type) <= TYPE_PRECISION (use_type))
         return NULL;
 
+      /* Check that NEW_TYPE is not bigger than the conversion result.  */
+      if (TYPE_PRECISION (new_type) > TYPE_PRECISION (use_type))
+       return NULL;
+
       if (TYPE_UNSIGNED (new_type) != TYPE_UNSIGNED (use_type)
           || TYPE_PRECISION (new_type) != TYPE_PRECISION (use_type))
         {
@@ -1251,16 +1260,20 @@ vect_recog_over_widening_pattern (VEC (gimple, heap) **stmts,
 
   where type 'TYPE' is at least double the size of type 'type'.
 
-  Also detect unsigned cases:
+  Also detect cases where the shift result is immediately converted
+  to another type 'result_type' that is no larger in size than 'TYPE'.
+  In those cases we perform a widen-shift that directly results in
+  'result_type', to avoid a possible over-widening situation:
 
-  unsigned type a_t;
-  unsigned TYPE u_res_T;
+  type a_t;
   TYPE a_T, res_T;
+  result_type res_result;
 
   S1 a_t = ;
   S2 a_T = (TYPE) a_t;
   S3 res_T = a_T << CONST;
-  S4 u_res_T = (unsigned TYPE) res_T;
+  S4 res_result = (result_type) res_T;
+      '--> res_result' = a_t w<< CONST;
 
   And a case when 'TYPE' is 4 times bigger than 'type'.  In that case we
   create an additional pattern stmt for S2 to create a variable of an
@@ -1301,59 +1314,20 @@ vect_recog_widen_shift_pattern (VEC (gimple, heap) **stmts,
   gimple def_stmt0;
   tree oprnd0, oprnd1;
   tree type, half_type0;
-  gimple pattern_stmt, orig_stmt = NULL;
+  gimple pattern_stmt;
   tree vectype, vectype_out = NULL_TREE;
   tree dummy;
   tree var;
   enum tree_code dummy_code;
   int dummy_int;
   VEC (tree, heap) * dummy_vec;
-  gimple use_stmt = NULL;
-  bool over_widen = false;
+  gimple use_stmt;
 
   if (!is_gimple_assign (last_stmt) || !vinfo_for_stmt (last_stmt))
     return NULL;
 
-  orig_stmt = last_stmt;
   if (STMT_VINFO_IN_PATTERN_P (vinfo_for_stmt (last_stmt)))
-    {
-      /* This statement was also detected as over-widening operation (it can't
-         be any other pattern, because only over-widening detects shifts).
-         LAST_STMT is the final type demotion statement, but its related
-         statement is shift.  We analyze the related statement to catch cases:
-
-         orig code:
-          type a_t;
-          itype res;
-          TYPE a_T, res_T;
-
-          S1 a_T = (TYPE) a_t;
-          S2 res_T = a_T << CONST;
-          S3 res = (itype)res_T;
-
-          (size of type * 2 <= size of itype
-           and size of itype * 2 <= size of TYPE)
-
-         code after over-widening pattern detection:
-
-          S1 a_T = (TYPE) a_t;
-               --> a_it = (itype) a_t;
-          S2 res_T = a_T << CONST;
-          S3 res = (itype)res_T;  <--- LAST_STMT
-               --> res = a_it << CONST;
-
-         after widen_shift:
-
-          S1 a_T = (TYPE) a_t;
-               --> a_it = (itype) a_t; - redundant
-          S2 res_T = a_T << CONST;
-          S3 res = (itype)res_T;
-               --> res = a_t w<< CONST;
-
-      i.e., we replace the three statements with res = a_t w<< CONST.  */
-      last_stmt = STMT_VINFO_RELATED_STMT (vinfo_for_stmt (last_stmt));
-      over_widen = true;
-    }
+    return NULL;
 
   if (gimple_assign_rhs_code (last_stmt) != LSHIFT_EXPR)
     return NULL;
@@ -1375,59 +1349,29 @@ vect_recog_widen_shift_pattern (VEC (gimple, heap) **stmts,
   oprnd0 = gimple_assign_rhs1 (def_stmt0);
   type = gimple_expr_type (last_stmt);
 
+  /* Check for subsequent conversion to another type.  */
+  use_stmt = vect_single_imm_use (last_stmt);
+  if (use_stmt && is_gimple_assign (use_stmt)
+      && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (use_stmt))
+      && !STMT_VINFO_IN_PATTERN_P (vinfo_for_stmt (use_stmt)))
+    {
+      tree use_lhs = gimple_assign_lhs (use_stmt);
+      tree use_type = TREE_TYPE (use_lhs);
+
+      if (INTEGRAL_TYPE_P (use_type)
+         && TYPE_PRECISION (use_type) <= TYPE_PRECISION (type))
+       {
+         last_stmt = use_stmt;
+         type = use_type;
+       }
+    }
+
   /* Check if this a widening operation.  */
   if (!vect_handle_widen_op_by_const (last_stmt, LSHIFT_EXPR, oprnd1,
                                              &oprnd0, stmts,
                                      type, &half_type0, def_stmt0))
     return NULL;
 
-  /* Handle unsigned case.  Look for
-     S4  u_res_T = (unsigned TYPE) res_T;
-     Use unsigned TYPE as the type for WIDEN_LSHIFT_EXPR.  */
-  if (TYPE_UNSIGNED (type) != TYPE_UNSIGNED (half_type0))
-    {
-      tree lhs = gimple_assign_lhs (last_stmt), use_lhs;
-      imm_use_iterator imm_iter;
-      use_operand_p use_p;
-      int nuses = 0;
-      tree use_type;
-
-      if (over_widen)
-        {
-          /* In case of over-widening pattern, S4 should be ORIG_STMT itself.
-             We check here that TYPE is the correct type for the operation,
-             i.e., it's the type of the original result.  */
-          tree orig_type = gimple_expr_type (orig_stmt);
-          if ((TYPE_UNSIGNED (type) != TYPE_UNSIGNED (orig_type))
-              || (TYPE_PRECISION (type) != TYPE_PRECISION (orig_type)))
-            return NULL;
-        }
-      else
-        {
-          FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs)
-            {
-             if (is_gimple_debug (USE_STMT (use_p)))
-               continue;
-             use_stmt = USE_STMT (use_p);
-             nuses++;
-            }
-
-          if (nuses != 1 || !is_gimple_assign (use_stmt)
-             || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (use_stmt)))
-           return NULL;
-
-          use_lhs = gimple_assign_lhs (use_stmt);
-          use_type = TREE_TYPE (use_lhs);
-
-          if (!INTEGRAL_TYPE_P (use_type)
-              || (TYPE_UNSIGNED (type) == TYPE_UNSIGNED (use_type))
-              || (TYPE_PRECISION (type) != TYPE_PRECISION (use_type)))
-            return NULL;
-
-          type = use_type;
-        }
-    }
-
   /* Pattern detected.  */
   if (vect_print_dump_info (REPORT_DETAILS))
     fprintf (vect_dump, "vect_recog_widen_shift_pattern: detected: ");
@@ -1456,11 +1400,6 @@ vect_recog_widen_shift_pattern (VEC (gimple, heap) **stmts,
   if (vect_print_dump_info (REPORT_DETAILS))
     print_gimple_stmt (vect_dump, pattern_stmt, 0, TDF_SLIM);
 
-  if (use_stmt)
-    last_stmt = use_stmt;
-  else
-    last_stmt = orig_stmt;
-
   VEC_safe_push (gimple, heap, *stmts, last_stmt);
   return pattern_stmt;
 }
@@ -1548,7 +1487,8 @@ vect_recog_vector_vector_shift_pattern (VEC (gimple, heap) **stmts,
         != TYPE_PRECISION (TREE_TYPE (oprnd0)))
     return NULL;
 
-  if (!vect_is_simple_use (oprnd1, loop_vinfo, NULL, &def_stmt, &def, &dt))
+  if (!vect_is_simple_use (oprnd1, last_stmt, loop_vinfo, NULL, &def_stmt,
+                          &def, &dt))
     return NULL;
 
   if (dt != vect_internal_def)
@@ -1924,7 +1864,7 @@ check_bool_pattern (tree var, loop_vec_info loop_vinfo)
   tree def, rhs1;
   enum tree_code rhs_code;
 
-  if (!vect_is_simple_use (var, loop_vinfo, NULL, &def_stmt, &def, &dt))
+  if (!vect_is_simple_use (var, NULL, loop_vinfo, NULL, &def_stmt, &def, &dt))
     return false;
 
   if (dt != vect_internal_def)
@@ -1965,6 +1905,11 @@ check_bool_pattern (tree var, loop_vec_info loop_vinfo)
        {
          tree vecitype, comp_vectype;
 
+         /* If the comparison can throw, then is_gimple_condexpr will be
+            false and we can't make a COND_EXPR/VEC_COND_EXPR out of it.  */
+         if (stmt_could_throw_p (def_stmt))
+           return false;
+
          comp_vectype = get_vectype_for_scalar_type (TREE_TYPE (rhs1));
          if (comp_vectype == NULL_TREE)
            return false;
@@ -2169,7 +2114,9 @@ adjust_bool_pattern (tree var, tree out_type, tree trueval,
     default:
       gcc_assert (TREE_CODE_CLASS (rhs_code) == tcc_comparison);
       if (TREE_CODE (TREE_TYPE (rhs1)) != INTEGER_TYPE
-         || !TYPE_UNSIGNED (TREE_TYPE (rhs1)))
+         || !TYPE_UNSIGNED (TREE_TYPE (rhs1))
+         || (TYPE_PRECISION (TREE_TYPE (rhs1))
+             != GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (rhs1)))))
        {
          enum machine_mode mode = TYPE_MODE (TREE_TYPE (rhs1));
          itype