OSDN Git Service

Vector shuffling patch from Artem Shinkarov.
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 3 Oct 2011 15:13:26 +0000 (15:13 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 3 Oct 2011 15:13:26 +0000 (15:13 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@179462 138bc75d-0d04-0410-961f-82ee72b054a4

32 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/c-parser.c
gcc/c-tree.h
gcc/c-typeck.c
gcc/config/i386/i386-protos.h
gcc/config/i386/i386.c
gcc/config/i386/sse.md
gcc/doc/extend.texi
gcc/expr.c
gcc/genopinit.c
gcc/gimple-pretty-print.c
gcc/gimple.c
gcc/gimplify.c
gcc/optabs.c
gcc/optabs.h
gcc/passes.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/vect-shuffle-1.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/vect-shuffle-2.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/vect-shuffle-3.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/vect-shuffle-4.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/vect-shuffle-5.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/builtin-complex-err-1.c
gcc/tree-cfg.c
gcc/tree-inline.c
gcc/tree-pretty-print.c
gcc/tree-ssa-operands.c
gcc/tree-vect-generic.c
gcc/tree.def

index c39a1a7..028ce8e 100644 (file)
@@ -1,3 +1,51 @@
+2011-10-03  Artem Shinkarov  <artyom.shinkaroff@gmail.com>
+
+       * optabs.c (expand_vec_shuffle_expr_p): New function. Checks
+       if given expression can be expanded by the target.
+       (expand_vec_shuffle_expr): New function. Expand VEC_SHUFFLE_EXPR
+       using target vector instructions.
+       * optabs.h: New optab vshuffle.
+       (expand_vec_shuffle_expr_p): New prototype.
+       (expand_vec_shuffle_expr): New prototype.
+       (vshuffle_optab): New optab.
+       * genopinit.c: Adjust to support vecshuffle.
+       * c-tree.h (c_build_vec_shuffle_expr): New prototype.
+       * expr.c (expand_expr_real_2): Adjust.
+       * c-typeck.c: (c_build_vec_shuffle_expr): Build a VEC_SHUFFLE_EXPR
+       recognizing the cases of two and three arguments.
+       (convert_arguments) (build_binary_op)
+       (scalar_to_vector) (build_array_ref): Spurious whitespace.
+       * gimplify.c (gimplify_exp): Adjusted to support VEC_SHUFFLE_EXPR.
+       * tree.def: New tree code VEC_SHUFFLE_EXPR.
+       * tree-inline.c (estimate_operator_cost): Recognize VEC_SHUFFLE_EXPR.
+       * tree-vect-generic.c (vector_element): New function. Returns an
+       element of the vector at the given position.
+       (lower_vec_shuffle): Checks if VEC_SHUFLLE_EXPR is supported
+       by the backend or expand an expression piecewise.
+       (expand_vector_operations_1): Adjusted.
+       (gate_expand_vector_operations_noop): New gate function.
+       * Makefile.in (tree-vect-generic.o): New include.
+       * gimple.c (get_gimple_rhs_num_ops): Adjust.
+       * tree-cfg.c (verify_gimple_assign_trenary): Verify VEC_SHUFFLE_EXPR.
+       * passes.c: Move veclower down.
+       * tree-pretty-print.c (dump_generic_node): Recognize
+       VEC_SHUFFLE_EXPR as valid expression.
+       * c-parser.c (c_parser_get_builtin_args): Helper function for the
+       builtins with variable number of arguments.
+       (c_parser_postfix_expression): Use a new helper function for
+       RID_CHOOSE_EXPR, RID_BUILTIN_COMPLEX and RID_BUILTIN_SHUFFLE.
+       * tree-ssa-operands: Adjust.
+       * c-family/c-common.c: New __builtin_shuffle keyword.
+       * c-family/c-common.h: New __builtin_shuffle keyword.
+       * gcc/doc/extend.texi: Adjust.
+
+       * gcc/config/i386/sse.md: (sseshuffint) New mode_attr.  Correspondence
+       between the vector and the type of the mask when shuffling.
+       (vecshuffle<mode>): New expansion.
+       * gcc/config/i386/i386-protos.h (ix86_expand_vshuffle): New prototype.
+       * gcc/config/i386/i386.c (ix86_expand_vshuffle): New function.
+       (ix86_vectorize_builtin_vec_perm_ok): Adjust.
+
 2011-10-03  Jakub Jelinek  <jakub@redhat.com>
 
        PR tree-optimization/50587
index cca9c4b..baec5fe 100644 (file)
@@ -3193,7 +3193,7 @@ tree-vect-generic.o : tree-vect-generic.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) \
     $(TM_H) $(TREE_FLOW_H) $(GIMPLE_H) tree-iterator.h $(TREE_PASS_H) \
     $(FLAGS_H) $(OPTABS_H) $(MACHMODE_H) $(EXPR_H) \
     langhooks.h $(FLAGS_H) $(DIAGNOSTIC_H) gt-tree-vect-generic.h $(GGC_H) \
-    coretypes.h insn-codes.h
+    coretypes.h insn-codes.h $(DIAGNOSTIC_H)
 df-core.o : df-core.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    insn-config.h $(RECOG_H) $(FUNCTION_H) $(REGS_H) alloc-pool.h \
    hard-reg-set.h $(BASIC_BLOCK_H) $(DF_H) $(BITMAP_H) sbitmap.h $(TIMEVAR_H) \
index e2852b6..2c5a489 100644 (file)
@@ -425,6 +425,7 @@ const struct c_common_resword c_common_reswords[] =
   { "__attribute__",   RID_ATTRIBUTE,  0 },
   { "__builtin_choose_expr", RID_CHOOSE_EXPR, D_CONLY },
   { "__builtin_complex", RID_BUILTIN_COMPLEX, D_CONLY },
+  { "__builtin_shuffle", RID_BUILTIN_SHUFFLE, D_CONLY },
   { "__builtin_offsetof", RID_OFFSETOF, 0 },
   { "__builtin_types_compatible_p", RID_TYPES_COMPATIBLE_P, D_CONLY },
   { "__builtin_va_arg",        RID_VA_ARG,     0 },
index a1f7ebe..8996eef 100644 (file)
@@ -102,7 +102,7 @@ enum rid
   /* C extensions */
   RID_ASM,       RID_TYPEOF,   RID_ALIGNOF,  RID_ATTRIBUTE,  RID_VA_ARG,
   RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,      RID_CHOOSE_EXPR,
-  RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,
+  RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,         RID_BUILTIN_SHUFFLE,
   RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128,
   RID_FRACT, RID_ACCUM,
 
index ff376df..f94b872 100644 (file)
@@ -5989,6 +5989,46 @@ c_parser_alignof_expression (c_parser *parser)
     }
 }
 
+/* Helper function to read arguments of builtins which are interfaces
+   for the middle-end nodes like COMPLEX_EXPR, VEC_SHUFFLE_EXPR and
+   others.  The name of the builtin is passed using BNAME parameter.
+   Function returns true if there were no errors while parsing and
+   stores the arguments in EXPR_LIST.  List of original types can be
+   obtained by passing non NULL value to ORIG_TYPES.  */
+static bool
+c_parser_get_builtin_args (c_parser *parser, const char *bname,
+                          VEC(tree,gc) **expr_list,
+                          VEC(tree,gc) **orig_types)
+{
+  location_t loc = c_parser_peek_token (parser)->location;
+  *expr_list = NULL;
+
+  if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
+    {
+      error_at (loc, "cannot take address of %qs", bname);
+      return false;
+    }
+
+  c_parser_consume_token (parser);
+
+  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+    {
+      c_parser_consume_token (parser);
+      return true;
+    }
+    
+  if (orig_types)
+    *expr_list = c_parser_expr_list (parser, false, false, orig_types);
+  else
+    *expr_list = c_parser_expr_list (parser, false, false, NULL);
+
+  if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+    return false;
+
+  return true;
+}
+
+
 /* Parse a postfix expression (C90 6.3.1-6.3.2, C99 6.5.1-6.5.2).
 
    postfix-expression:
@@ -6027,6 +6067,10 @@ c_parser_alignof_expression (c_parser *parser)
                             assignment-expression )
      __builtin_types_compatible_p ( type-name , type-name )
      __builtin_complex ( assignment-expression , assignment-expression )
+     __builtin_shuffle ( assignment-expression , assignment-expression )
+     __builtin_shuffle ( assignment-expression , 
+                        assignment-expression ,
+                        assignment-expression, )
 
    offsetof-member-designator:
      identifier
@@ -6047,7 +6091,7 @@ c_parser_alignof_expression (c_parser *parser)
 static struct c_expr
 c_parser_postfix_expression (c_parser *parser)
 {
-  struct c_expr expr, e1, e2, e3;
+  struct c_expr expr, e1;
   struct c_type_name *t1, *t2;
   location_t loc = c_parser_peek_token (parser)->location;;
   expr.original_code = ERROR_MARK;
@@ -6333,45 +6377,55 @@ c_parser_postfix_expression (c_parser *parser)
          }
          break;
        case RID_CHOOSE_EXPR:
-         c_parser_consume_token (parser);
-         if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
-           {
-             expr.value = error_mark_node;
-             break;
-           }
-         loc = c_parser_peek_token (parser)->location;
-         e1 = c_parser_expr_no_commas (parser, NULL);
-         if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
-           {
-             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
-             expr.value = error_mark_node;
-             break;
-           }
-         e2 = c_parser_expr_no_commas (parser, NULL);
-         if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
-           {
-             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
-             expr.value = error_mark_node;
-             break;
-           }
-         e3 = c_parser_expr_no_commas (parser, NULL);
-         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
-                                    "expected %<)%>");
          {
-           tree c;
+           VEC(tree,gc) *expr_list;
+           VEC(tree,gc) *orig_types;
+           tree e1value, e2value, e3value, c;
 
-           c = e1.value;
-           mark_exp_read (e2.value);
-           mark_exp_read (e3.value);
+           c_parser_consume_token (parser);
+           if (!c_parser_get_builtin_args (parser,
+                                           "__builtin_choose_expr",
+                                           &expr_list, &orig_types))
+             {
+               expr.value = error_mark_node;
+               break;
+             }
+
+           if (VEC_length (tree, expr_list) != 3)
+             {
+               error_at (loc, "wrong number of arguments to "
+                              "%<__builtin_choose_expr%>");
+               expr.value = error_mark_node;
+               break;
+             }
+           
+           e1value = VEC_index (tree, expr_list, 0);
+           e2value = VEC_index (tree, expr_list, 1);
+           e3value = VEC_index (tree, expr_list, 2);
+
+           c = e1value;
+           mark_exp_read (e2value);
+           mark_exp_read (e3value);
            if (TREE_CODE (c) != INTEGER_CST
                || !INTEGRAL_TYPE_P (TREE_TYPE (c)))
              error_at (loc,
                        "first argument to %<__builtin_choose_expr%> not"
                        " a constant");
            constant_expression_warning (c);
-           expr = integer_zerop (c) ? e3 : e2;
+           
+           if (integer_zerop (c))
+             {
+               expr.value = e3value;
+               expr.original_type = VEC_index (tree, orig_types, 2);
+             }
+           else
+             {
+               expr.value = e2value;
+               expr.original_type = VEC_index (tree, orig_types, 1);
+             }
+
+           break;
          }
-         break;
        case RID_TYPES_COMPATIBLE_P:
          c_parser_consume_token (parser);
          if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
@@ -6410,57 +6464,96 @@ c_parser_postfix_expression (c_parser *parser)
          }
          break;
        case RID_BUILTIN_COMPLEX:
-         c_parser_consume_token (parser);
-         if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
-           {
-             expr.value = error_mark_node;
-             break;
-           }
-         loc = c_parser_peek_token (parser)->location;
-         e1 = c_parser_expr_no_commas (parser, NULL);
-         if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
-           {
-             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
-             expr.value = error_mark_node;
-             break;
-           }
-         e2 = c_parser_expr_no_commas (parser, NULL);
-         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
-                                    "expected %<)%>");
-         mark_exp_read (e1.value);
-         if (TREE_CODE (e1.value) == EXCESS_PRECISION_EXPR)
-           e1.value = convert (TREE_TYPE (e1.value),
-                               TREE_OPERAND (e1.value, 0));
-         mark_exp_read (e2.value);
-         if (TREE_CODE (e2.value) == EXCESS_PRECISION_EXPR)
-           e2.value = convert (TREE_TYPE (e2.value),
-                               TREE_OPERAND (e2.value, 0));
-         if (!SCALAR_FLOAT_TYPE_P (TREE_TYPE (e1.value))
-             || DECIMAL_FLOAT_TYPE_P (TREE_TYPE (e1.value))
-             || !SCALAR_FLOAT_TYPE_P (TREE_TYPE (e2.value))
-             || DECIMAL_FLOAT_TYPE_P (TREE_TYPE (e2.value)))
-           {
-             error_at (loc, "%<__builtin_complex%> operand "
-                       "not of real binary floating-point type");
-             expr.value = error_mark_node;
-             break;
-           }
-         if (TYPE_MAIN_VARIANT (TREE_TYPE (e1.value))
-             != TYPE_MAIN_VARIANT (TREE_TYPE (e2.value)))
-           {
-             error_at (loc,
-                       "%<__builtin_complex%> operands of different types");
-             expr.value = error_mark_node;
-             break;
-           }
-         if (!flag_isoc99)
-           pedwarn (loc, OPT_pedantic,
-                    "ISO C90 does not support complex types");
-         expr.value = build2 (COMPLEX_EXPR,
-                              build_complex_type (TYPE_MAIN_VARIANT
-                                                  (TREE_TYPE (e1.value))),
-                              e1.value, e2.value);
-         break;
+         { 
+           VEC(tree,gc) *expr_list;
+           tree e1value, e2value;
+           
+           c_parser_consume_token (parser);
+           if (!c_parser_get_builtin_args (parser,
+                                           "__builtin_complex",
+                                           &expr_list, NULL))
+             {
+               expr.value = error_mark_node;
+               break;
+             }
+
+           if (VEC_length (tree, expr_list) != 2)
+             {
+               error_at (loc, "wrong number of arguments to "
+                              "%<__builtin_complex%>");
+               expr.value = error_mark_node;
+               break;
+             }
+           
+           e1value = VEC_index (tree, expr_list, 0);
+           e2value = VEC_index (tree, expr_list, 1);
+
+           mark_exp_read (e1value);
+           if (TREE_CODE (e1value) == EXCESS_PRECISION_EXPR)
+             e1value = convert (TREE_TYPE (e1value),
+                                TREE_OPERAND (e1value, 0));
+           mark_exp_read (e2value);
+           if (TREE_CODE (e2value) == EXCESS_PRECISION_EXPR)
+             e2value = convert (TREE_TYPE (e2value),
+                                TREE_OPERAND (e2value, 0));
+           if (!SCALAR_FLOAT_TYPE_P (TREE_TYPE (e1value))
+               || DECIMAL_FLOAT_TYPE_P (TREE_TYPE (e1value))
+               || !SCALAR_FLOAT_TYPE_P (TREE_TYPE (e2value))
+               || DECIMAL_FLOAT_TYPE_P (TREE_TYPE (e2value)))
+             {
+               error_at (loc, "%<__builtin_complex%> operand "
+                         "not of real binary floating-point type");
+               expr.value = error_mark_node;
+               break;
+             }
+           if (TYPE_MAIN_VARIANT (TREE_TYPE (e1value))
+               != TYPE_MAIN_VARIANT (TREE_TYPE (e2value)))
+             {
+               error_at (loc,
+                         "%<__builtin_complex%> operands of different types");
+               expr.value = error_mark_node;
+               break;
+             }
+           if (!flag_isoc99)
+             pedwarn (loc, OPT_pedantic,
+                      "ISO C90 does not support complex types");
+           expr.value = build2 (COMPLEX_EXPR,
+                                build_complex_type (TYPE_MAIN_VARIANT
+                                                    (TREE_TYPE (e1value))),
+                                e1value, e2value);
+           break;
+         }
+       case RID_BUILTIN_SHUFFLE:
+         {
+           VEC(tree,gc) *expr_list;
+           
+           c_parser_consume_token (parser);
+           if (!c_parser_get_builtin_args (parser,
+                                           "__builtin_shuffle",
+                                           &expr_list, NULL))
+             {
+               expr.value = error_mark_node;
+               break;
+             }
+
+           if (VEC_length (tree, expr_list) == 2)
+             expr.value = c_build_vec_shuffle_expr
+                               (loc, VEC_index (tree, expr_list, 0),
+                                NULL_TREE,
+                                VEC_index (tree, expr_list, 1));
+           else if (VEC_length (tree, expr_list) == 3)
+             expr.value = c_build_vec_shuffle_expr
+                               (loc, VEC_index (tree, expr_list, 0),
+                                VEC_index (tree, expr_list, 1),
+                                VEC_index (tree, expr_list, 2));
+           else
+             {
+               error_at (loc, "wrong number of arguments to "
+                              "%<__builtin_shuffle%>");
+               expr.value = error_mark_node;
+             }
+           break;
+         }
        case RID_AT_SELECTOR:
          gcc_assert (c_dialect_objc ());
          c_parser_consume_token (parser);
index cda5d06..1948507 100644 (file)
@@ -579,6 +579,7 @@ extern tree c_begin_omp_task (void);
 extern tree c_finish_omp_task (location_t, tree, tree);
 extern tree c_finish_omp_clauses (tree);
 extern tree c_build_va_arg (location_t, tree, tree);
+extern tree c_build_vec_shuffle_expr (location_t, tree, tree, tree);
 
 /* Set to 0 at beginning of a function definition, set to 1 if
    a return statement that specifies a return value is seen.  */
index e1c17a2..96ef4a3 100644 (file)
@@ -2307,7 +2307,7 @@ build_array_ref (location_t loc, tree array, tree index)
       if (TREE_CODE (TREE_TYPE (index)) != ARRAY_TYPE
          && TREE_CODE (TREE_TYPE (index)) != POINTER_TYPE)
        {
-          error_at (loc, 
+          error_at (loc,
             "subscripted value is neither array nor pointer nor vector");
 
          return error_mark_node;
@@ -2339,8 +2339,8 @@ build_array_ref (location_t loc, tree array, tree index)
   index = default_conversion (index);
 
   gcc_assert (TREE_CODE (TREE_TYPE (index)) == INTEGER_TYPE);
-  
-  /* For vector[index], convert the vector to a 
+
+  /* For vector[index], convert the vector to a
      pointer of the underlying type.  */
   if (TREE_CODE (TREE_TYPE (array)) == VECTOR_TYPE)
     {
@@ -2348,11 +2348,11 @@ build_array_ref (location_t loc, tree array, tree index)
       tree type1;
 
       if (TREE_CODE (index) == INTEGER_CST)
-        if (!host_integerp (index, 1) 
-            || ((unsigned HOST_WIDE_INT) tree_low_cst (index, 1) 
+        if (!host_integerp (index, 1)
+            || ((unsigned HOST_WIDE_INT) tree_low_cst (index, 1)
                >= TYPE_VECTOR_SUBPARTS (TREE_TYPE (array))))
           warning_at (loc, OPT_Warray_bounds, "index value is out of bound");
-     
+
       c_common_mark_addressable_vec (array);
       type = build_qualified_type (TREE_TYPE (type), TYPE_QUALS (type));
       type = build_pointer_type (type);
@@ -2845,6 +2845,99 @@ build_function_call_vec (location_t loc, tree function, VEC(tree,gc) *params,
     }
   return require_complete_type (result);
 }
+
+/* Build a VEC_SHUFFLE_EXPR if V0, V1 and MASK are not error_mark_nodes
+   and have vector types, V0 has the same type as V1, and the number of
+   elements of V0, V1, MASK is the same.
+
+   In case V1 is a NULL_TREE it is assumed that __builtin_shuffle was
+   called with two arguments.  In this case implementation passes the
+   first argument twice in order to share the same tree code.  This fact
+   could enable the mask-values being twice the vector length.  This is
+   an implementation accident and this semantics is not guaranteed to
+   the user.  */
+tree
+c_build_vec_shuffle_expr (location_t loc, tree v0, tree v1, tree mask)
+{
+  tree vec_shuffle, tmp;
+  bool wrap = true;
+  bool maybe_const = false;
+  bool two_arguments;
+
+  if (v1 == NULL_TREE)
+    {
+      two_arguments = true;
+      v1 = v0;
+    }
+
+  if (v0 == error_mark_node || v1 == error_mark_node
+      || mask == error_mark_node)
+    return error_mark_node;
+
+  if (TREE_CODE (TREE_TYPE (mask)) != VECTOR_TYPE
+      || TREE_CODE (TREE_TYPE (TREE_TYPE (mask))) != INTEGER_TYPE)
+    {
+      error_at (loc, "__builtin_shuffle last argument must "
+                    "be an integer vector");
+      return error_mark_node;
+    }
+
+  if (TREE_CODE (TREE_TYPE (v0)) != VECTOR_TYPE
+      || TREE_CODE (TREE_TYPE (v1)) != VECTOR_TYPE)
+    {
+      error_at (loc, "__builtin_shuffle arguments must be vectors");
+      return error_mark_node;
+    }
+
+  if (TYPE_MAIN_VARIANT (TREE_TYPE (v0)) != TYPE_MAIN_VARIANT (TREE_TYPE (v1)))
+    {
+      error_at (loc, "__builtin_shuffle argument vectors must be of "
+                    "the same type");
+      return error_mark_node;
+    }
+
+  if (TYPE_VECTOR_SUBPARTS (TREE_TYPE (v0))
+      != TYPE_VECTOR_SUBPARTS (TREE_TYPE (mask))
+      && TYPE_VECTOR_SUBPARTS (TREE_TYPE (v1))
+        != TYPE_VECTOR_SUBPARTS (TREE_TYPE (mask)))
+    {
+      error_at (loc, "__builtin_shuffle number of elements of the "
+                    "argument vector(s) and the mask vector should "
+                    "be the same");
+      return error_mark_node;
+    }
+
+  if (GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (v0))))
+      != GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (mask)))))
+    {
+      error_at (loc, "__builtin_shuffle argument vector(s) inner type "
+                    "must have the same size as inner type of the mask");
+      return error_mark_node;
+    }
+
+  /* Avoid C_MAYBE_CONST_EXPRs inside VEC_SHUFFLE_EXPR.  */
+  tmp = c_fully_fold (v0, false, &maybe_const);
+  v0 = save_expr (tmp);
+  wrap &= maybe_const;
+
+  if (!two_arguments)
+    {
+      v1 = c_fully_fold (v1, false, &maybe_const);
+      wrap &= maybe_const;
+    }
+  else
+    v1 = v0;
+
+  mask = c_fully_fold (mask, false, &maybe_const);
+  wrap &= maybe_const;
+
+  vec_shuffle = build3 (VEC_SHUFFLE_EXPR, TREE_TYPE (v0), v0, v1, mask);
+
+  if (!wrap)
+    vec_shuffle = c_wrap_maybe_const (vec_shuffle, true);
+
+  return vec_shuffle;
+}
 \f
 /* Convert the argument expressions in the vector VALUES
    to the types in the list TYPELIST.
@@ -3167,7 +3260,7 @@ convert_arguments (tree typelist, VEC(tree,gc) *values,
 
   if (typetail != 0 && TREE_VALUE (typetail) != void_type_node)
     {
-      error_at (input_location, 
+      error_at (input_location,
                "too few arguments to function %qE", function);
       if (fundecl && !DECL_BUILT_IN (fundecl))
        inform (DECL_SOURCE_LOCATION (fundecl), "declared here");
@@ -3566,7 +3659,7 @@ build_unary_op (location_t location,
 
       /* Complain about anything that is not a true lvalue.  In
         Objective-C, skip this check for property_refs.  */
-      if (!objc_is_property_ref (arg) 
+      if (!objc_is_property_ref (arg)
          && !lvalue_or_else (location,
                              arg, ((code == PREINCREMENT_EXPR
                                     || code == POSTINCREMENT_EXPR)
@@ -3683,7 +3776,7 @@ build_unary_op (location_t location,
           need to ask Objective-C to build the increment or decrement
           expression for it.  */
        if (objc_is_property_ref (arg))
-         return objc_build_incr_expr_for_property_ref (location, code, 
+         return objc_build_incr_expr_for_property_ref (location, code,
                                                        arg, inc);
 
        /* Report a read-only lvalue.  */
@@ -5926,7 +6019,7 @@ void
 pedwarn_init (location_t location, int opt, const char *gmsgid)
 {
   char *ofwhat;
-  
+
   /* The gmsgid may be a format string with %< and %>. */
   pedwarn (location, opt, gmsgid);
   ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
@@ -9344,8 +9437,8 @@ scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1)
   tree type1 = TREE_TYPE (op1);
   bool integer_only_op = false;
   enum stv_conv ret = stv_firstarg;
-  
-  gcc_assert (TREE_CODE (type0) == VECTOR_TYPE 
+
+  gcc_assert (TREE_CODE (type0) == VECTOR_TYPE
              || TREE_CODE (type1) == VECTOR_TYPE);
   switch (code)
     {
@@ -9370,7 +9463,7 @@ scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1)
       case BIT_AND_EXPR:
        integer_only_op = true;
        /* ... fall through ...  */
-      
+
       case PLUS_EXPR:
       case MINUS_EXPR:
       case MULT_EXPR:
@@ -9387,7 +9480,7 @@ scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1)
          }
 
        if (TREE_CODE (type0) == INTEGER_TYPE
-           && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE) 
+           && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE)
          {
            if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
              {
@@ -9399,7 +9492,7 @@ scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1)
          }
        else if (!integer_only_op
                    /* Allow integer --> real conversion if safe.  */
-                && (TREE_CODE (type0) == REAL_TYPE 
+                && (TREE_CODE (type0) == REAL_TYPE
                     || TREE_CODE (type0) == INTEGER_TYPE)
                 && SCALAR_FLOAT_TYPE_P (TREE_TYPE (type1)))
          {
@@ -9414,7 +9507,7 @@ scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1)
       default:
        break;
     }
+
   return stv_nothing;
 }
 \f
@@ -9529,8 +9622,8 @@ build_binary_op (location_t location, enum tree_code code,
     int_const = int_const_or_overflow = false;
 
   /* Do not apply default conversion in mixed vector/scalar expression.  */
-  if (convert_p 
-      && !((TREE_CODE (TREE_TYPE (op0)) == VECTOR_TYPE) 
+  if (convert_p
+      && !((TREE_CODE (TREE_TYPE (op0)) == VECTOR_TYPE)
           != (TREE_CODE (TREE_TYPE (op1)) == VECTOR_TYPE)))
     {
       op0 = default_conversion (op0);
@@ -9608,7 +9701,7 @@ build_binary_op (location_t location, enum tree_code code,
   if ((code0 == VECTOR_TYPE) != (code1 == VECTOR_TYPE))
     {
       enum stv_conv convert_flag = scalar_to_vector (location, code, op0, op1);
-      
+
       switch (convert_flag)
        {
          case stv_error:
@@ -9974,7 +10067,7 @@ build_binary_op (location_t location, enum tree_code code,
            {
              if (code == EQ_EXPR)
                warning_at (location,
-                           OPT_Waddress, 
+                           OPT_Waddress,
                            "the comparison will always evaluate as %<false%> "
                            "for the address of %qD will never be NULL",
                            TREE_OPERAND (op1, 0));
index 707f217..99327ed 100644 (file)
@@ -123,6 +123,7 @@ extern bool ix86_expand_int_movcc (rtx[]);
 extern bool ix86_expand_fp_movcc (rtx[]);
 extern bool ix86_expand_fp_vcond (rtx[]);
 extern bool ix86_expand_int_vcond (rtx[]);
+extern bool ix86_expand_vshuffle (rtx[]);
 extern void ix86_expand_sse_unpack (rtx[], bool, bool);
 extern bool ix86_expand_int_addcc (rtx[]);
 extern rtx ix86_expand_call (rtx, rtx, rtx, rtx, rtx, bool);
index 7e89dbd..9b079af 100644 (file)
@@ -19254,6 +19254,147 @@ ix86_expand_int_vcond (rtx operands[])
   return true;
 }
 
+bool
+ix86_expand_vshuffle (rtx operands[])
+{
+  rtx target = operands[0];
+  rtx op0 = operands[1];
+  rtx op1 = operands[2];
+  rtx mask = operands[3];
+  rtx new_mask, vt, t1, t2, w_vector;
+  enum machine_mode mode = GET_MODE (op0);
+  enum machine_mode maskmode = GET_MODE (mask);
+  enum machine_mode maskinner = GET_MODE_INNER (mode);
+  rtx vec[16];
+  int w, i, j;
+  bool one_operand_shuffle = op0 == op1;
+
+  gcc_assert ((TARGET_SSSE3 || TARGET_AVX) && GET_MODE_BITSIZE (mode) == 128);
+
+  /* Number of elements in the vector.  */
+  w = GET_MODE_BITSIZE (maskmode) / GET_MODE_BITSIZE (maskinner);
+
+  /* generate w_vector = {w, w, ...}  */
+  for (i = 0; i < w; i++)
+    vec[i] = GEN_INT (w);
+  w_vector = gen_rtx_CONST_VECTOR (maskmode, gen_rtvec_v (w, vec));
+
+  /* mask = mask & {w-1, w-1, w-1,...} */
+  for (i = 0; i < w; i++)
+    vec[i] = GEN_INT (w - 1);
+
+  vt = gen_rtx_CONST_VECTOR (maskmode, gen_rtvec_v (w, vec));
+  new_mask = expand_simple_binop (maskmode, AND, mask, vt,
+                                 NULL_RTX, 0, OPTAB_DIRECT);
+
+  /* If the original vector mode is V16QImode, we can just
+     use pshufb directly.  */
+  if (mode == V16QImode && one_operand_shuffle)
+    {
+      t1 = gen_reg_rtx (V16QImode);
+      emit_insn (gen_ssse3_pshufbv16qi3 (t1, op0, new_mask));
+      emit_insn (gen_rtx_SET (VOIDmode, target, t1));
+      return true;
+    }
+  else if (mode == V16QImode)
+    {
+      rtx xops[6];
+
+      t1 = gen_reg_rtx (V16QImode);
+      t2 = gen_reg_rtx (V16QImode);
+      emit_insn (gen_ssse3_pshufbv16qi3 (t1, op0, new_mask));
+      emit_insn (gen_ssse3_pshufbv16qi3 (t2, op1, new_mask));
+
+      /* mask = mask & {w, w, ...}  */
+      mask = expand_simple_binop (V16QImode, AND, mask, w_vector,
+                                 NULL_RTX, 0, OPTAB_DIRECT);
+      xops[0] = target;
+      xops[1] = operands[1];
+      xops[2] = operands[2];
+      xops[3] = gen_rtx_EQ (mode, mask, w_vector);
+      xops[4] = t1;
+      xops[5] = t2;
+
+      return ix86_expand_int_vcond (xops);
+    }
+
+  /* mask = mask * {w, w, ...}  */
+  new_mask = expand_simple_binop (maskmode, MULT, new_mask, w_vector,
+                                 NULL_RTX, 0, OPTAB_DIRECT);
+
+  /* Convert mask to vector of chars.  */
+  new_mask = simplify_gen_subreg (V16QImode, new_mask, maskmode, 0);
+  new_mask = force_reg (V16QImode, new_mask);
+
+  /* Build a helper mask wich we will use in pshufb
+     (v4si) --> {0,0,0,0, 4,4,4,4, 8,8,8,8, 12,12,12,12}
+     (v8hi) --> {0,0, 2,2, 4,4, 6,6, ...}
+     ...  */
+  for (i = 0; i < w; i++)
+    for (j = 0; j < 16/w; j++)
+      vec[i*w+j] = GEN_INT (i*16/w);
+  vt = gen_rtx_CONST_VECTOR (V16QImode, gen_rtvec_v (16, vec));
+  vt = force_reg (V16QImode, vt);
+
+  t1 = gen_reg_rtx (V16QImode);
+  emit_insn (gen_ssse3_pshufbv16qi3 (t1, new_mask, vt));
+  new_mask = t1;
+
+  /* Convert it into the byte positions by doing
+     new_mask = new_mask + {0,1,..,16/w, 0,1,..,16/w, ...}  */
+  for (i = 0; i < w; i++)
+    for (j = 0; j < 16/w; j++)
+      vec[i*w+j] = GEN_INT (j);
+
+  vt = gen_rtx_CONST_VECTOR (V16QImode, gen_rtvec_v (16, vec));
+  new_mask = expand_simple_binop (V16QImode, PLUS, new_mask, vt,
+                                 NULL_RTX, 0, OPTAB_DIRECT);
+
+  t1 = gen_reg_rtx (V16QImode);
+
+  /* Convert OP0 to vector of chars.  */
+  op0 = simplify_gen_subreg (V16QImode, op0, mode, 0);
+  op0 = force_reg (V16QImode, op0);
+  emit_insn (gen_ssse3_pshufbv16qi3 (t1, op0, new_mask));
+
+  if (one_operand_shuffle)
+    {
+      /* Convert it back from vector of chars to the original mode.  */
+      t1 = simplify_gen_subreg (mode, t1, V16QImode, 0);
+      emit_insn (gen_rtx_SET (VOIDmode, target, t1));
+      return true;
+    }
+  else
+    {
+      rtx xops[6];
+
+      t2 = gen_reg_rtx (V16QImode);
+
+      /* Convert OP1 to vector of chars.  */
+      op1 = simplify_gen_subreg (V16QImode, op1, mode, 0);
+      op1 = force_reg (V16QImode, op1);
+      emit_insn (gen_ssse3_pshufbv16qi3 (t1, op1, new_mask));
+
+      /* mask = mask & {w, w, ...}  */
+      mask = expand_simple_binop (V16QImode, AND, mask, w_vector,
+                                 NULL_RTX, 0, OPTAB_DIRECT);
+
+      t1 = simplify_gen_subreg (mode, t1, V16QImode, 0);
+      t2 = simplify_gen_subreg (mode, t2, V16QImode, 0);
+
+      xops[0] = target;
+      xops[1] = operands[1];
+      xops[2] = operands[2];
+      xops[3] = gen_rtx_EQ (mode, mask, w_vector);
+      xops[4] = t1;
+      xops[5] = t2;
+
+      return ix86_expand_int_vcond (xops);
+    }
+
+  return false;
+}
+
 /* Unpack OP[1] into the next wider integer vector type.  UNSIGNED_P is
    true if we should do zero extension, else sign extension.  HIGH_P is
    true if we want the N/2 high elements, else the low elements.  */
@@ -31472,6 +31613,9 @@ struct expand_vec_perm_d
 
 static bool expand_vec_perm_1 (struct expand_vec_perm_d *d);
 static bool expand_vec_perm_broadcast_1 (struct expand_vec_perm_d *d);
+static int extract_vec_perm_cst (struct expand_vec_perm_d *, tree);
+static bool ix86_vectorize_builtin_vec_perm_ok (tree vec_type, tree mask);
+
 
 /* Get a vector mode of the same size as the original but with elements
    twice as wide.  This is only guaranteed to apply to integral vectors.  */
@@ -33103,7 +33247,7 @@ void ix86_emit_i387_round (rtx op0, rtx op1)
   res = gen_reg_rtx (outmode);
 
   half = CONST_DOUBLE_FROM_REAL_VALUE (dconsthalf, inmode);
-  
+
   /* round(a) = sgn(a) * floor(fabs(a) + 0.5) */
 
   /* scratch = fxam(op1) */
@@ -35262,10 +35406,10 @@ ix86_vectorize_builtin_vec_perm_ok (tree vec_type, tree mask)
 
   vec_mask = extract_vec_perm_cst (&d, mask);
 
-  /* This hook is cannot be called in response to something that the
-     user does (unlike the builtin expander) so we shouldn't ever see
-     an error generated from the extract.  */
-  gcc_assert (vec_mask > 0 && vec_mask <= 3);
+  /* Check whether the mask can be applied to the vector type.  */
+  if (vec_mask < 0 || vec_mask > 3)
+    return false;
+
   one_vec = (vec_mask != 3);
 
   /* Implementable with shufps or pshufd.  */
index baa22a6..251cdde 100644 (file)
    (V4SF "V4SF") (V2DF "V2DF")
    (TI "TI")])
 
+;; All 128bit vector modes
+(define_mode_attr sseshuffint
+  [(V16QI "V16QI") (V8HI "V8HI")
+   (V4SI "V4SI")  (V2DI "V2DI")
+   (V4SF "V4SI") (V2DF "V2DI")])
+
 ;; Mapping of vector float modes to an integer mode of the same size
 (define_mode_attr sseintvecmode
   [(V8SF "V8SI") (V4DF "V4DI")
   DONE;
 })
 
+(define_expand "vshuffle<mode>"
+  [(match_operand:V_128 0 "register_operand" "")
+   (match_operand:V_128 1 "register_operand" "")
+   (match_operand:V_128 2 "register_operand" "")
+   (match_operand:<sseshuffint> 3 "register_operand" "")]
+  "TARGET_SSSE3 || TARGET_AVX"
+{
+  bool ok = ix86_expand_vshuffle (operands);
+  gcc_assert (ok);
+  DONE;
+})
+
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;
 ;; Parallel bitwise logical operations
index 1c688dc..20ee772 100644 (file)
@@ -6584,6 +6584,32 @@ c = a >  b;     /* The result would be @{0, 0,-1, 0@}  */
 c = a == b;     /* The result would be @{0,-1, 0,-1@}  */
 @end smallexample
 
+Vector shuffling is available using functions
+@code{__builtin_shuffle (vec, mask)} and
+@code{__builtin_shuffle (vec0, vec1, mask)}. Both functions construct
+a permutation of elements from one or two vectors and return a vector
+of the same type as input vector(s). The mask is a vector of
+integer-typed elements. The size of each element of the mask must be
+the same as the size of each input vector element. The number of
+elements in input vector(s) and mask must be the same.
+
+The elements of the input vectors are numbered from left to right across
+one or both of the vectors. Each element in the mask specifies a number
+of element from the input vector(s). Consider the following example.
+
+@smallexample
+typedef int v4si __attribute__ ((vector_size (16)));
+
+v4si a = @{1,2,3,4@};
+v4si b = @{5,6,7,8@};
+v4si mask1 = @{0,1,1,3@};
+v4si mask2 = @{0,4,2,5@};
+v4si res;
+
+res = __builtin_shuffle (a, mask1);       /* res is @{1,2,2,4@}  */
+res = __builtin_shuffle (a, b, mask2);    /* res is @{1,5,3,6@}  */
+@end smallexample
+
 You can declare variables and use them in function calls and returns, as
 well as in assignments and some casts.  You can specify a vector type as
 a return type for a function.  Vector types can also be used as function
index 97edd46..d1807b0 100644 (file)
@@ -8605,6 +8605,10 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
     case VEC_PACK_FIX_TRUNC_EXPR:
       mode = TYPE_MODE (TREE_TYPE (treeop0));
       goto binop;
+    
+    case VEC_SHUFFLE_EXPR:
+      target = expand_vec_shuffle_expr (type, treeop0, treeop1, treeop2, target);
+      return target;
 
     case DOT_PROD_EXPR:
       {
@@ -10308,6 +10312,17 @@ do_store_flag (sepops ops, rtx target, enum machine_mode mode)
 
   STRIP_NOPS (arg0);
   STRIP_NOPS (arg1);
+  
+  /* For vector typed comparisons emit code to generate the desired
+     all-ones or all-zeros mask.  Conveniently use the VEC_COND_EXPR
+     expander for this.  */
+  if (TREE_CODE (ops->type) == VECTOR_TYPE)
+    {
+      tree ifexp = build2 (ops->code, ops->type, arg0, arg1);
+      tree if_true = constant_boolean_node (true, ops->type);
+      tree if_false = constant_boolean_node (false, ops->type);
+      return expand_vec_cond_expr (ops->type, ifexp, if_true, if_false, target);
+    }
 
   /* For vector typed comparisons emit code to generate the desired
      all-ones or all-zeros mask.  Conveniently use the VEC_COND_EXPR
index ec4a473..4672075 100644 (file)
@@ -253,6 +253,7 @@ static const char * const optabs[] =
   "set_optab_handler (vec_shl_optab, $A, CODE_FOR_$(vec_shl_$a$))",
   "set_optab_handler (vec_shr_optab, $A, CODE_FOR_$(vec_shr_$a$))",
   "set_optab_handler (vec_realign_load_optab, $A, CODE_FOR_$(vec_realign_load_$a$))",
+  "set_direct_optab_handler (vshuffle_optab, $A, CODE_FOR_$(vshuffle$a$))",
   "set_convert_optab_handler (vcond_optab, $A, $B, CODE_FOR_$(vcond$a$b$))",
   "set_convert_optab_handler (vcondu_optab, $A, $B, CODE_FOR_$(vcondu$a$b$))",
   "set_optab_handler (ssum_widen_optab, $A, CODE_FOR_$(widen_ssum$I$a3$))",
index 1f6efc9..2dbdebe 100644 (file)
@@ -417,6 +417,16 @@ dump_ternary_rhs (pretty_printer *buffer, gimple gs, int spc, int flags)
       dump_generic_node (buffer, gimple_assign_rhs3 (gs), spc, flags, false);
       pp_string (buffer, ">");
       break;
+    
+    case VEC_SHUFFLE_EXPR:
+      pp_string (buffer, "VEC_SHUFFLE_EXPR <");
+      dump_generic_node (buffer, gimple_assign_rhs1 (gs), spc, flags, false);
+      pp_string (buffer, ", ");
+      dump_generic_node (buffer, gimple_assign_rhs2 (gs), spc, flags, false);
+      pp_string (buffer, ", ");
+      dump_generic_node (buffer, gimple_assign_rhs3 (gs), spc, flags, false);
+      pp_string (buffer, ">");
+      break;
 
     case REALIGN_LOAD_EXPR:
       pp_string (buffer, "REALIGN_LOAD <");
index 9b8e1b1..e4dfd46 100644 (file)
@@ -2638,6 +2638,7 @@ get_gimple_rhs_num_ops (enum tree_code code)
       || (SYM) == DOT_PROD_EXPR                                                    \
       || (SYM) == REALIGN_LOAD_EXPR                                        \
       || (SYM) == VEC_COND_EXPR                                                    \
+      || (SYM) == VEC_SHUFFLE_EXPR                                          \
       || (SYM) == FMA_EXPR) ? GIMPLE_TERNARY_RHS                           \
    : ((SYM) == CONSTRUCTOR                                                 \
       || (SYM) == OBJ_TYPE_REF                                             \
index d7bc818..4c15f3a 100644 (file)
@@ -7286,6 +7286,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
          }
 
        case FMA_EXPR:
+       case VEC_SHUFFLE_EXPR:
          /* Classified as tcc_expression.  */
          goto expr_3;
 
index 5cdcd95..3a52fb0 100644 (file)
@@ -6620,6 +6620,94 @@ vector_compare_rtx (tree cond, bool unsignedp, enum insn_code icode)
   return gen_rtx_fmt_ee (rcode, VOIDmode, ops[0].value, ops[1].value);
 }
 
+/* Return true if VEC_SHUFFLE_EXPR can be expanded using SIMD extensions
+   of the CPU.  */
+bool
+expand_vec_shuffle_expr_p (enum machine_mode mode, tree v0, tree v1, tree mask)
+{
+  int v0_mode_s = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (v0))));
+  int mask_mode_s = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (mask))));
+
+  if (TREE_CODE (mask) == VECTOR_CST
+      && targetm.vectorize.builtin_vec_perm_ok (TREE_TYPE (v0), mask))
+    return true;
+
+  if (v0_mode_s != mask_mode_s
+      || TYPE_VECTOR_SUBPARTS (TREE_TYPE (v0))
+        != TYPE_VECTOR_SUBPARTS (TREE_TYPE (mask))
+      || TYPE_VECTOR_SUBPARTS (TREE_TYPE (v1))
+        != TYPE_VECTOR_SUBPARTS (TREE_TYPE (mask)))
+    return false;
+
+  return direct_optab_handler (vshuffle_optab, mode) != CODE_FOR_nothing;
+}
+
+/* Generate instructions for VEC_COND_EXPR given its type and three
+   operands.  */
+rtx
+expand_vec_shuffle_expr (tree type, tree v0, tree v1, tree mask, rtx target)
+{
+  struct expand_operand ops[4];
+  enum insn_code icode;
+  enum machine_mode mode = TYPE_MODE (type);
+  rtx rtx_v0, rtx_mask;
+
+  gcc_assert (expand_vec_shuffle_expr_p (mode, v0, v1, mask));
+
+  if (TREE_CODE (mask) == VECTOR_CST)
+    {
+      tree m_type, call;
+      tree fn = targetm.vectorize.builtin_vec_perm (TREE_TYPE (v0), &m_type);
+
+      if (!fn)
+       goto vshuffle;
+
+      if (m_type != TREE_TYPE (TREE_TYPE (mask)))
+       {
+         int units = TYPE_VECTOR_SUBPARTS (TREE_TYPE (mask));
+         tree cvt = build_vector_type (m_type, units);
+         mask = fold_convert (cvt, mask);
+       }
+
+      call = fold_build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
+      call = build_call_nary (type, call, 3, v0, v1, mask);
+
+      return expand_expr_real_1 (call, target, VOIDmode, EXPAND_NORMAL, NULL);
+    }
+
+vshuffle:
+  icode = direct_optab_handler (vshuffle_optab, mode);
+
+  if (icode == CODE_FOR_nothing)
+    return 0;
+
+  rtx_mask = expand_normal (mask);
+
+  create_output_operand (&ops[0], target, mode);
+  create_input_operand (&ops[3], rtx_mask, mode);
+
+  if (operand_equal_p (v0, v1, 0))
+    {
+      rtx_v0 = expand_normal (v0);
+      if (!insn_operand_matches(icode, 1, rtx_v0))
+        rtx_v0 = force_reg (mode, rtx_v0);
+
+      gcc_checking_assert(insn_operand_matches(icode, 2, rtx_v0));
+
+      create_fixed_operand (&ops[1], rtx_v0);
+      create_fixed_operand (&ops[2], rtx_v0);
+    }
+  else
+    {
+      create_input_operand (&ops[1], expand_normal (v0), mode);
+      create_input_operand (&ops[2], expand_normal (v1), mode);
+    }
+
+  expand_insn (icode, 4, ops);
+  return ops[0].value;
+}
+
+
 /* Return insn code for a conditional operator with a comparison in
    mode CMODE, unsigned if UNS is true, resulting in a value of mode VMODE.  */
 
index 56df671..5d5593b 100644 (file)
@@ -617,6 +617,7 @@ enum convert_optab_index
 #define vec_store_lanes_optab (&convert_optab_table[COI_vec_store_lanes])
 #define vcond_optab (&convert_optab_table[(int) COI_vcond])
 #define vcondu_optab (&convert_optab_table[(int) COI_vcondu])
+#define vshuffle_optab (&direct_optab_table[(int) DOI_vshuffle])
 
 /* Contains the optab used for each rtx code.  */
 extern optab code_to_optab[NUM_RTX_CODE + 1];
@@ -638,6 +639,9 @@ enum direct_optab_index
   DOI_reload_in,
   DOI_reload_out,
 
+  /* Vector shuffling.  */
+  DOI_vshuffle,
+
   /* Block move operation.  */
   DOI_movmem,
 
@@ -884,6 +888,12 @@ extern rtx expand_vec_cond_expr (tree, tree, tree, tree, rtx);
 /* Generate code for VEC_LSHIFT_EXPR and VEC_RSHIFT_EXPR.  */
 extern rtx expand_vec_shift_expr (sepops, rtx);
 
+/* Return tree if target supports vector operations for VEC_SHUFFLE_EXPR.  */
+bool expand_vec_shuffle_expr_p (enum machine_mode, tree, tree, tree);
+
+/* Generate code for VEC_SHUFFLE_EXPR.  */
+extern rtx expand_vec_shuffle_expr (tree, tree, tree, tree, rtx);
+
 /* Return the insn used to implement mode MODE of OP, or CODE_FOR_nothing
    if the target does not have such an insn.  */
 
index 4d8ca6e..887007f 100644 (file)
@@ -1355,7 +1355,6 @@ init_optimization_passes (void)
          NEXT_PASS (pass_vectorize);
            {
              struct opt_pass **p = &pass_vectorize.pass.sub;
-             NEXT_PASS (pass_lower_vector_ssa);
              NEXT_PASS (pass_dce_loop);
            }
           NEXT_PASS (pass_predcom);
@@ -1367,6 +1366,7 @@ init_optimization_passes (void)
          NEXT_PASS (pass_lim);
          NEXT_PASS (pass_tree_loop_done);
        }
+      NEXT_PASS (pass_lower_vector_ssa);
       NEXT_PASS (pass_cse_reciprocals);
       NEXT_PASS (pass_reassoc);
       NEXT_PASS (pass_vrp);
index 7a7794f..06df702 100644 (file)
@@ -1,3 +1,10 @@
+2011-10-03  Artem Shinkarov  <artyom.shinkaroff@gmail.com>
+
+       * gcc.c-torture/execute/vect-shuffle-2.c: New test.
+       * gcc.c-torture/execute/vect-shuffle-4.c: New test.
+       * gcc.c-torture/execute/vect-shuffle-1.c: New test.
+       * gcc.dg/builtin-complex-err-1.c: Adjust.
+
 2011-10-02  Jason Merrill  <jason@redhat.com>
 
        * g++.dg/cpp0x/range-for22.C: New.
diff --git a/gcc/testsuite/gcc.c-torture/execute/vect-shuffle-1.c b/gcc/testsuite/gcc.c-torture/execute/vect-shuffle-1.c
new file mode 100644 (file)
index 0000000..6664384
--- /dev/null
@@ -0,0 +1,92 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*(((type *) &(vec)) + idx))
+
+#define shufcompare(type, count, vres, v0, mask) \
+do { \
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx(type, vres, __i) != vidx(type, v0, vidx(type, mask, __i))) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+int main (int argc, char *argv[]) {
+    /*vector (8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector (8, short) v1 = {argc, 1,argc,3,4,5,argc,7};
+    vector (8, short) v2;
+   
+    vector (8, short) smask = {0,0,1,2,3,4,5,6};
+    
+    v2 = __builtin_shuffle (v0,  smask);
+    shufcompare (short, 8, v2, v0, smask);
+    v2 = __builtin_shuffle (v0, v1);
+    shufcompare (short, 8, v2, v0, v1);
+    v2 = __builtin_shuffle (smask, v0);
+    shufcompare (short, 8, v2, smask, v0);*/
+
+    vector (4, int) i0 = {argc, 1,2,3};
+    vector (4, int) i1 = {argc, 1, argc, 3};
+    vector (4, int) i2;
+
+    vector (4, int) imask = {0,3,2,1};
+
+    /*i2 = __builtin_shuffle (i0, imask);
+    shufcompare (int, 4, i2, i0, imask);*/
+    i2 = __builtin_shuffle (i0, i1);
+    shufcompare (int, 4, i2, i0, i1);
+    
+    i2 = __builtin_shuffle (imask, i0);
+    shufcompare (int, 4, i2, imask, i0);
+    
+    return 0;
+}
+
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*(((type *) &(vec)) + idx))
+
+#define shufcompare(type, count, vres, v0, mask) \
+do { \
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx(type, vres, __i) != vidx(type, v0, vidx(type, mask, __i))) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+int main (int argc, char *argv[]) {
+    /*vector (8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector (8, short) v1 = {argc, 1,argc,3,4,5,argc,7};
+    vector (8, short) v2;
+   
+    vector (8, short) smask = {0,0,1,2,3,4,5,6};
+    
+    v2 = __builtin_shuffle (v0,  smask);
+    shufcompare (short, 8, v2, v0, smask);
+    v2 = __builtin_shuffle (v0, v1);
+    shufcompare (short, 8, v2, v0, v1);
+    v2 = __builtin_shuffle (smask, v0);
+    shufcompare (short, 8, v2, smask, v0);*/
+
+    vector (4, int) i0 = {argc, 1,2,3};
+    vector (4, int) i1 = {argc, 1, argc, 3};
+    vector (4, int) i2;
+
+    vector (4, int) imask = {0,3,2,1};
+
+    /*i2 = __builtin_shuffle (i0, imask);
+    shufcompare (int, 4, i2, i0, imask);*/
+    i2 = __builtin_shuffle (i0, i1);
+    shufcompare (int, 4, i2, i0, i1);
+    
+    i2 = __builtin_shuffle (imask, i0);
+    shufcompare (int, 4, i2, imask, i0);
+    
+    return 0;
+}
+
diff --git a/gcc/testsuite/gcc.c-torture/execute/vect-shuffle-2.c b/gcc/testsuite/gcc.c-torture/execute/vect-shuffle-2.c
new file mode 100644 (file)
index 0000000..af3e08d
--- /dev/null
@@ -0,0 +1,88 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*(((type *) &(vec)) + idx))
+
+#define shuf2compare(type, count, vres, v0, v1, mask) \
+do { \
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx(type, vres, __i) != ((vidx(type, mask, __i) < count) ? \
+                          vidx(type, v0, vidx(type, mask, __i)) :  \
+                          vidx(type, v1, (vidx(type, mask, __i) - count)))) \
+            __builtin_abort (); \
+        } \
+} while (0)
+
+
+int main (int argc, char *argv[]) {
+    vector (8, short) v0 = {5, 5,5,5,5,5,argc,7};
+    vector (8, short) v1 = {argc, 1,8,8,4,9,argc,4};
+    vector (8, short) v2;
+
+    //vector (8, short) mask = {1,2,5,4,3,6,7};
+
+    vector (8, short) mask0 = {0,2,3,1,4,5,6,7};
+    vector (8, short) mask1 = {0,12,3,4,3,0,10,9};
+
+    vector (8, short) mask2 = {0,8,1,9,2,10,3,11};
+
+    v2 = __builtin_shuffle (v0, v1,  mask0);
+    shuf2compare (short, 8, v2, v0, v1, mask0);
+
+    v2 = __builtin_shuffle (v0, v1,  mask1);
+    shuf2compare (short, 8, v2, v0, v1, mask1);
+
+    v2 = __builtin_shuffle (v0, v1,  mask2);
+    shuf2compare (short, 8, v2, v0, v1, mask2);
+
+    v2 = __builtin_shuffle (mask0, mask0,  v0);
+    shuf2compare (short, 8, v2, mask0, mask0, v0);
+
+    return 0;
+}
+
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*(((type *) &(vec)) + idx))
+
+#define shuf2compare(type, count, vres, v0, v1, mask) \
+do { \
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx(type, vres, __i) != ((vidx(type, mask, __i) < count) ? \
+                          vidx(type, v0, vidx(type, mask, __i)) :  \
+                          vidx(type, v1, (vidx(type, mask, __i) - count)))) \
+            __builtin_abort (); \
+        } \
+} while (0)
+
+
+int main (int argc, char *argv[]) {
+    vector (8, short) v0 = {5, 5,5,5,5,5,argc,7};
+    vector (8, short) v1 = {argc, 1,8,8,4,9,argc,4};
+    vector (8, short) v2;
+
+    //vector (8, short) mask = {1,2,5,4,3,6,7};
+
+    vector (8, short) mask0 = {0,2,3,1,4,5,6,7};
+    vector (8, short) mask1 = {0,12,3,4,3,0,10,9};
+
+    vector (8, short) mask2 = {0,8,1,9,2,10,3,11};
+
+    v2 = __builtin_shuffle (v0, v1,  mask0);
+    shuf2compare (short, 8, v2, v0, v1, mask0);
+
+    v2 = __builtin_shuffle (v0, v1,  mask1);
+    shuf2compare (short, 8, v2, v0, v1, mask1);
+
+    v2 = __builtin_shuffle (v0, v1,  mask2);
+    shuf2compare (short, 8, v2, v0, v1, mask2);
+
+    v2 = __builtin_shuffle (mask0, mask0,  v0);
+    shuf2compare (short, 8, v2, mask0, mask0, v0);
+
+    return 0;
+}
+
diff --git a/gcc/testsuite/gcc.c-torture/execute/vect-shuffle-3.c b/gcc/testsuite/gcc.c-torture/execute/vect-shuffle-3.c
new file mode 100644 (file)
index 0000000..bd54713
--- /dev/null
@@ -0,0 +1,72 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*(((type *) &(vec)) + idx))
+
+#define shufcompare(type, count, vres, v0, mask) \
+do { \
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx(type, vres, __i) != vidx(type, v0, vidx(type, mask, __i))) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+vector (8, short) __attribute__ ((noinline))
+f (vector (8, short) x, vector (8, short) mask) {
+    return __builtin_shuffle (x, mask);
+}
+
+
+int main (int argc, char *argv[]) {
+    vector (8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector (8, short) v1 = {argc, 1,argc,3,4,5,argc,7};
+    vector (8, short) v2;
+
+    vector (8, short) mask = {0,0,1,2,3,4,5,6};
+    
+    v2 = f (v0,  mask);
+    shufcompare (short, 8, v2, v0, mask);
+
+    v2 = f (v0, v1);
+    shufcompare (short, 8, v2, v0, v1);
+
+    return 0;
+}
+
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*(((type *) &(vec)) + idx))
+
+#define shufcompare(type, count, vres, v0, mask) \
+do { \
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx(type, vres, __i) != vidx(type, v0, vidx(type, mask, __i))) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+vector (8, short) __attribute__ ((noinline))
+f (vector (8, short) x, vector (8, short) mask) {
+    return __builtin_shuffle (x, mask);
+}
+
+
+int main (int argc, char *argv[]) {
+    vector (8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector (8, short) v1 = {argc, 1,argc,3,4,5,argc,7};
+    vector (8, short) v2;
+
+    vector (8, short) mask = {0,0,1,2,3,4,5,6};
+    
+    v2 = f (v0,  mask);
+    shufcompare (short, 8, v2, v0, mask);
+
+    v2 = f (v0, v1);
+    shufcompare (short, 8, v2, v0, v1);
+
+    return 0;
+}
+
diff --git a/gcc/testsuite/gcc.c-torture/execute/vect-shuffle-4.c b/gcc/testsuite/gcc.c-torture/execute/vect-shuffle-4.c
new file mode 100644 (file)
index 0000000..7cf38d4
--- /dev/null
@@ -0,0 +1,100 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*(((type *) &(vec)) + idx))
+
+#define shuf2compare(type, count, vres, v0, v1, mask) \
+do { \
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx(type, vres, __i) != ((vidx(type, mask, __i) < count) ? \
+                          vidx(type, v0, vidx(type, mask, __i)) :  \
+                          vidx(type, v1, (vidx(type, mask, __i) - count)))) \
+            __builtin_abort (); \
+        } \
+} while (0)
+
+
+vector (8, short) __attribute__ ((noinline))
+f (vector (8, short) x, vector (8, short) y, vector (8, short) mask) {
+    return __builtin_shuffle (x, y, mask);
+}
+
+
+
+int main (int argc, char *argv[]) {
+    vector (8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector (8, short) v1 = {argc, 1,argc,3,4,5,argc,7};
+    vector (8, short) v2;
+
+    //vector (8, short) mask = {1,2,5,4,3,6,7};
+    
+    vector (8, short) mask0 = {0,2,3,1,4,5,6,7};
+    vector (8, short) mask1 = {0,12,3,4,3,0,10,9};
+    vector (8, short) mask2 = {0,8,1,9,2,10,3,11};
+
+    v2 = f (v0, v1,  mask0);
+    shuf2compare (short, 8, v2, v0, v1, mask0);
+    v2 = f (v0, v1,  mask1);
+    shuf2compare (short, 8, v2, v0, v1, mask1);
+
+    v2 = f (v0, v1,  mask2);
+    shuf2compare (short, 8, v2, v0, v1, mask2);
+
+    v2 = f (mask0, mask0,  v0);
+    shuf2compare (short, 8, v2, mask0, mask0, v0);
+
+    return 0; 
+}
+
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*(((type *) &(vec)) + idx))
+
+#define shuf2compare(type, count, vres, v0, v1, mask) \
+do { \
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx(type, vres, __i) != ((vidx(type, mask, __i) < count) ? \
+                          vidx(type, v0, vidx(type, mask, __i)) :  \
+                          vidx(type, v1, (vidx(type, mask, __i) - count)))) \
+            __builtin_abort (); \
+        } \
+} while (0)
+
+
+vector (8, short) __attribute__ ((noinline))
+f (vector (8, short) x, vector (8, short) y, vector (8, short) mask) {
+    return __builtin_shuffle (x, y, mask);
+}
+
+
+
+int main (int argc, char *argv[]) {
+    vector (8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector (8, short) v1 = {argc, 1,argc,3,4,5,argc,7};
+    vector (8, short) v2;
+
+    //vector (8, short) mask = {1,2,5,4,3,6,7};
+    
+    vector (8, short) mask0 = {0,2,3,1,4,5,6,7};
+    vector (8, short) mask1 = {0,12,3,4,3,0,10,9};
+    vector (8, short) mask2 = {0,8,1,9,2,10,3,11};
+
+    v2 = f (v0, v1,  mask0);
+    shuf2compare (short, 8, v2, v0, v1, mask0);
+    v2 = f (v0, v1,  mask1);
+    shuf2compare (short, 8, v2, v0, v1, mask1);
+
+    v2 = f (v0, v1,  mask2);
+    shuf2compare (short, 8, v2, v0, v1, mask2);
+
+    v2 = f (mask0, mask0,  v0);
+    shuf2compare (short, 8, v2, mask0, mask0, v0);
+
+    return 0; 
+}
+
diff --git a/gcc/testsuite/gcc.c-torture/execute/vect-shuffle-5.c b/gcc/testsuite/gcc.c-torture/execute/vect-shuffle-5.c
new file mode 100644 (file)
index 0000000..2b1a65c
--- /dev/null
@@ -0,0 +1,128 @@
+/* Test that different type variants are compatible within
+   vector shuffling.  */
+
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define shufcompare(count, vres, v0, mask) \
+do { \
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vres[__i] != v0[mask[__i]]) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+#define test_compat_mask(res, vec, mask) \
+  res = __builtin_shuffle (vec, mask); \
+  shufcompare(4, res, vec, mask); \
+  res = __builtin_shuffle (vec, c ## mask); \
+  shufcompare(4, res, vec, c ##  mask); \
+  res = __builtin_shuffle (vec, r ## mask); \
+  shufcompare(4, res, vec, r ##  mask); \
+  res = __builtin_shuffle (vec, d ## mask); \
+  shufcompare(4, res, vec, d ##  mask); \
+  res = __builtin_shuffle (vec, dc ## mask); \
+  shufcompare(4, res, vec, dc ##  mask); \
+
+#define test_compat_vec(res, vec, mask) \
+  test_compat_mask (res, vec, mask); \
+  test_compat_mask (res, c ## vec, mask); \
+  test_compat_mask (res, r ## vec, mask); \
+  test_compat_mask (res, d ## vec, mask); \
+  test_compat_mask (res, dc ## vec, mask); 
+
+#define test_compat(res, vec, mask) \
+  test_compat_vec (res, vec, mask); \
+  test_compat_vec (d ## res, vec, mask); \
+  test_compat_vec (r ## res, vec, mask);
+
+typedef vector (4, int) v4si;
+typedef const vector (4, int) v4sicst;
+
+int main (int argc, char *argv[]) {
+    vector (4, int) vec = {argc, 1,2,3};
+    const vector (4, int) cvec = {argc, 1,2,3};
+    register vector (4, int) rvec = {argc, 1,2,3};
+    v4si dvec = {argc, 1,2,3};
+    v4sicst dcvec = {argc, 1,2,3};
+    
+    vector (4, int) res; 
+    v4si dres;
+    register vector (4, int) rres;
+
+    vector (4, int) mask = {0,3,2,1};
+    const vector (4, int) cmask = {0,3,2,1};
+    register vector (4, int) rmask = {0,3,2,1};
+    v4si dmask = {0,3,2,1};
+    v4sicst dcmask = {0,3,2,1};
+
+    test_compat (res, vec, mask);
+
+    return 0;
+}
+
+/* Test that different type variants are compatible within
+   vector shuffling.  */
+
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define shufcompare(count, vres, v0, mask) \
+do { \
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vres[__i] != v0[mask[__i]]) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+#define test_compat_mask(res, vec, mask) \
+  res = __builtin_shuffle (vec, mask); \
+  shufcompare(4, res, vec, mask); \
+  res = __builtin_shuffle (vec, c ## mask); \
+  shufcompare(4, res, vec, c ##  mask); \
+  res = __builtin_shuffle (vec, r ## mask); \
+  shufcompare(4, res, vec, r ##  mask); \
+  res = __builtin_shuffle (vec, d ## mask); \
+  shufcompare(4, res, vec, d ##  mask); \
+  res = __builtin_shuffle (vec, dc ## mask); \
+  shufcompare(4, res, vec, dc ##  mask); \
+
+#define test_compat_vec(res, vec, mask) \
+  test_compat_mask (res, vec, mask); \
+  test_compat_mask (res, c ## vec, mask); \
+  test_compat_mask (res, r ## vec, mask); \
+  test_compat_mask (res, d ## vec, mask); \
+  test_compat_mask (res, dc ## vec, mask); 
+
+#define test_compat(res, vec, mask) \
+  test_compat_vec (res, vec, mask); \
+  test_compat_vec (d ## res, vec, mask); \
+  test_compat_vec (r ## res, vec, mask);
+
+typedef vector (4, int) v4si;
+typedef const vector (4, int) v4sicst;
+
+int main (int argc, char *argv[]) {
+    vector (4, int) vec = {argc, 1,2,3};
+    const vector (4, int) cvec = {argc, 1,2,3};
+    register vector (4, int) rvec = {argc, 1,2,3};
+    v4si dvec = {argc, 1,2,3};
+    v4sicst dcvec = {argc, 1,2,3};
+    
+    vector (4, int) res; 
+    v4si dres;
+    register vector (4, int) rres;
+
+    vector (4, int) mask = {0,3,2,1};
+    const vector (4, int) cmask = {0,3,2,1};
+    register vector (4, int) rmask = {0,3,2,1};
+    v4si dmask = {0,3,2,1};
+    v4sicst dcmask = {0,3,2,1};
+
+    test_compat (res, vec, mask);
+
+    return 0;
+}
+
index b9dab83..3ef50da 100644 (file)
@@ -19,8 +19,8 @@ _Complex float fc3 = __builtin_complex (1.0f, 1.0); /* { dg-error "different typ
 void
 f (void)
 {
-  __builtin_complex (0.0); /* { dg-error "expected" } */
-  __builtin_complex (0.0, 0.0, 0.0); /* { dg-error "expected" } */
+  __builtin_complex (0.0); /* { dg-error "wrong number of arguments" } */
+  __builtin_complex (0.0, 0.0, 0.0); /* { dg-error "wrong number of arguments" } */
 }
 
-void (*p) (void) = __builtin_complex; /* { dg-error "expected" } */
+void (*p) (void) = __builtin_complex; /* { dg-error "cannot take address" } */
index 5e5de8f..598ef2a 100644 (file)
@@ -3727,6 +3727,59 @@ verify_gimple_assign_ternary (gimple stmt)
        }
       break;
 
+    case VEC_SHUFFLE_EXPR:
+      if (!useless_type_conversion_p (lhs_type, rhs1_type)
+         || !useless_type_conversion_p (lhs_type, rhs2_type))
+       {
+         error ("type mismatch in vector shuffle expression");
+         debug_generic_expr (lhs_type);
+         debug_generic_expr (rhs1_type);
+         debug_generic_expr (rhs2_type);
+         debug_generic_expr (rhs3_type);
+         return true;
+       }
+
+      if (TREE_CODE (rhs1_type) != VECTOR_TYPE
+         || TREE_CODE (rhs2_type) != VECTOR_TYPE
+         || TREE_CODE (rhs3_type) != VECTOR_TYPE)
+       {
+         error ("vector types expected in vector shuffle expression");
+         debug_generic_expr (lhs_type);
+         debug_generic_expr (rhs1_type);
+         debug_generic_expr (rhs2_type);
+         debug_generic_expr (rhs3_type);
+         return true;
+       }
+
+      if (TYPE_VECTOR_SUBPARTS (rhs1_type) != TYPE_VECTOR_SUBPARTS (rhs2_type)
+         || TYPE_VECTOR_SUBPARTS (rhs2_type)
+            != TYPE_VECTOR_SUBPARTS (rhs3_type)
+         || TYPE_VECTOR_SUBPARTS (rhs3_type)
+            != TYPE_VECTOR_SUBPARTS (lhs_type))
+       {
+         error ("vectors with different element number found "
+                "in vector shuffle expression");
+         debug_generic_expr (lhs_type);
+         debug_generic_expr (rhs1_type);
+         debug_generic_expr (rhs2_type);
+         debug_generic_expr (rhs3_type);
+         return true;
+       }
+
+      if (TREE_CODE (TREE_TYPE (rhs3_type)) != INTEGER_TYPE
+         || GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (rhs3_type)))
+            != GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (rhs1_type))))
+       {
+         error ("invalid mask type in vector shuffle expression");
+         debug_generic_expr (lhs_type);
+         debug_generic_expr (rhs1_type);
+         debug_generic_expr (rhs2_type);
+         debug_generic_expr (rhs3_type);
+         return true;
+       }
+
+      return false;
+
     case DOT_PROD_EXPR:
     case REALIGN_LOAD_EXPR:
       /* FIXME.  */
index 3610289..8c60f4d 100644 (file)
@@ -3285,6 +3285,7 @@ estimate_operator_cost (enum tree_code code, eni_weights *weights,
        ??? We may consider mapping RTL costs to this.  */
     case COND_EXPR:
     case VEC_COND_EXPR:
+    case VEC_SHUFFLE_EXPR:
 
     case PLUS_EXPR:
     case POINTER_PLUS_EXPR:
index e30d60a..c61e901 100644 (file)
@@ -2069,6 +2069,16 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
       dump_generic_node (buffer, TREE_OPERAND (node, 2), spc, flags, false);
       pp_string (buffer, " > ");
       break;
+    
+    case VEC_SHUFFLE_EXPR:
+      pp_string (buffer, " VEC_SHUFFLE_EXPR < ");
+      dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
+      pp_string (buffer, " , ");
+      dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false);
+      pp_string (buffer, " , ");
+      dump_generic_node (buffer, TREE_OPERAND (node, 2), spc, flags, false);
+      pp_string (buffer, " > ");
+      break;
 
     case DOT_PROD_EXPR:
       pp_string (buffer, " DOT_PROD_EXPR < ");
index f27d5f0..d163037 100644 (file)
@@ -943,6 +943,7 @@ get_expr_operands (gimple stmt, tree *expr_p, int flags)
 
     case COND_EXPR:
     case VEC_COND_EXPR:
+    case VEC_SHUFFLE_EXPR:
       get_expr_operands (stmt, &TREE_OPERAND (expr, 0), uflags);
       get_expr_operands (stmt, &TREE_OPERAND (expr, 1), uflags);
       get_expr_operands (stmt, &TREE_OPERAND (expr, 2), uflags);
index 042d703..1a6d1f1 100644 (file)
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-pass.h"
 #include "flags.h"
 #include "ggc.h"
+#include "diagnostic.h"
 
 /* Need to include rtl.h, expr.h, etc. for optabs.  */
 #include "expr.h"
@@ -129,7 +130,6 @@ do_binop (gimple_stmt_iterator *gsi, tree inner_type, tree a, tree b,
   return gimplify_build2 (gsi, code, inner_type, a, b);
 }
 
-
 /* Construct expression (A[BITPOS] code B[BITPOS]) ? -1 : 0
 
    INNER_TYPE is the type of A and B elements
@@ -355,10 +355,10 @@ uniform_vector_p (tree vec)
         }
       if (i != TYPE_VECTOR_SUBPARTS (TREE_TYPE (vec)))
        return NULL_TREE;
-      
+
       return first;
     }
-  
+
   return NULL_TREE;
 }
 
@@ -498,6 +498,263 @@ type_for_widest_vector_mode (enum machine_mode inner_mode, optab op, int satp)
     }
 }
 
+
+/* Build a reference to the element of the vector VECT.  Function
+   returns either the element itself, either BIT_FIELD_REF, or an
+   ARRAY_REF expression.
+
+   GSI is requred to insert temporary variables while building a
+   refernece to the element of the vector VECT.
+
+   PTMPVEC is a pointer to the temporary variable for caching
+   purposes.  In case when PTMPVEC is NULL new temporary variable
+   will be created.  */
+static tree
+vector_element (gimple_stmt_iterator *gsi, tree vect, tree idx, tree *ptmpvec)
+{
+  tree type;
+  gimple asgn;
+  tree tmpvec;
+  tree arraytype;
+  bool need_asgn = true;
+
+  gcc_assert (TREE_CODE (TREE_TYPE (vect)) == VECTOR_TYPE);
+
+  type = TREE_TYPE (vect);
+  if (TREE_CODE (idx) == INTEGER_CST)
+    {
+      unsigned HOST_WIDE_INT index;
+
+      if (!host_integerp (idx, 1)
+           || (index = tree_low_cst (idx, 1)) > TYPE_VECTOR_SUBPARTS (type)-1)
+        return error_mark_node;
+
+      if (TREE_CODE (vect) == VECTOR_CST)
+        {
+         unsigned i;
+         tree vals = TREE_VECTOR_CST_ELTS (vect);
+         for (i = 0; vals; vals = TREE_CHAIN (vals), ++i)
+           if (i == index)
+              return TREE_VALUE (vals);
+         return error_mark_node;
+        }
+      else if (TREE_CODE (vect) == CONSTRUCTOR)
+        {
+          unsigned i;
+          VEC (constructor_elt, gc) *vals = CONSTRUCTOR_ELTS (vect);
+          constructor_elt *elt;
+
+          for (i = 0; VEC_iterate (constructor_elt, vals, i, elt); i++)
+            if (operand_equal_p (elt->index, idx, 0))
+              return elt->value;
+          return fold_convert (TREE_TYPE (type), integer_zero_node);
+        }
+      else if (TREE_CODE (vect) == SSA_NAME)
+        {
+         tree size = TYPE_SIZE (TREE_TYPE (type));
+          tree pos = fold_build2 (MULT_EXPR, TREE_TYPE (idx), idx, size);
+          return fold_build3 (BIT_FIELD_REF, TREE_TYPE (type), vect, size, pos);
+        }
+      else
+       return error_mark_node;
+    }
+
+  if (!ptmpvec)
+    tmpvec = create_tmp_var (TREE_TYPE (vect), "vectmp");
+  else if (!*ptmpvec)
+    tmpvec = *ptmpvec = create_tmp_var (TREE_TYPE (vect), "vectmp");
+  else
+    {
+      tmpvec = *ptmpvec;
+      need_asgn = false;
+    }
+
+  if (need_asgn)
+    {
+      TREE_ADDRESSABLE (tmpvec) = 1;
+      asgn = gimple_build_assign (tmpvec, vect);
+      gsi_insert_before (gsi, asgn, GSI_SAME_STMT);
+    }
+
+  arraytype = build_array_type_nelts (TREE_TYPE (type),
+                                     TYPE_VECTOR_SUBPARTS (TREE_TYPE (vect)));
+
+  return build4 (ARRAY_REF, TREE_TYPE (type),
+                 build1 (VIEW_CONVERT_EXPR, arraytype, tmpvec),
+                 idx, NULL_TREE, NULL_TREE);
+}
+
+/* Check if VEC_SHUFFLE_EXPR within the given setting is supported
+   by hardware, or lower it piecewise.  Function returns false when
+   the expression must be replaced with TRAP_RETURN, true otherwise.
+
+   When VEC_SHUFFLE_EXPR has the same first and second operands:
+   VEC_SHUFFLE_EXPR <v0, v0, mask> the lowered version would be
+   {v0[mask[0]], v0[mask[1]], ...}
+   MASK and V0 must have the same number of elements.
+
+   Otherwise VEC_SHUFFLE_EXPR <v0, v1, mask> is lowered to
+   {mask[0] < len(v0) ? v0[mask[0]] : v1[mask[0]], ...}
+   V0 and V1 must have the same type.  MASK, V0, V1 must have the
+   same number of arguments.  */
+static bool
+lower_vec_shuffle (gimple_stmt_iterator *gsi, location_t loc)
+{
+
+  gimple stmt = gsi_stmt (*gsi);
+  tree mask = gimple_assign_rhs3 (stmt);
+  tree vec0 = gimple_assign_rhs1 (stmt);
+  tree vec1 = gimple_assign_rhs2 (stmt);
+  unsigned els = TYPE_VECTOR_SUBPARTS (TREE_TYPE (mask));
+  tree type0 = TREE_TYPE (TREE_TYPE (vec0));
+  VEC(constructor_elt,gc) *v = NULL;
+  tree vectype, constr;
+  tree vec0tmp = NULL_TREE, masktmp = NULL_TREE;
+
+  if (expand_vec_shuffle_expr_p (TYPE_MODE (TREE_TYPE (vec0)), vec0, vec1, mask))
+    {
+      tree t;
+
+      t = gimplify_build3 (gsi, VEC_SHUFFLE_EXPR, TREE_TYPE (vec0),
+                          vec0, vec1, mask);
+      gimple_assign_set_rhs_from_tree (gsi, t);
+      /* Statement should be updated by callee.  */
+      return true;
+    }
+
+  if (operand_equal_p (vec0, vec1, 0))
+    {
+      unsigned i;
+      tree vec0tmp = NULL_TREE;
+
+      v = VEC_alloc (constructor_elt, gc, els);
+      for (i = 0; i < els; i++)
+        {
+          tree idxval, vecel, t;
+
+         idxval = vector_element (gsi, mask, size_int (i), &masktmp);
+          if (idxval == error_mark_node)
+            {
+              if (warning_at (loc, 0, "Invalid shuffling mask index %i", i))
+               inform (loc, "if this code is reached the programm will abort");
+             return false;
+            }
+
+         vecel = vector_element (gsi, vec0, idxval, &vec0tmp);
+          if (vecel == error_mark_node)
+            {
+              if (warning_at (loc, 0, "Invalid shuffling arguments"))
+               inform (loc, "if this code is reached the programm will abort");
+             return false;
+            }
+
+          t = force_gimple_operand_gsi (gsi, vecel, true,
+                                       NULL_TREE, true, GSI_SAME_STMT);
+          CONSTRUCTOR_APPEND_ELT (v, size_int (i), t);
+        }
+    }
+  else
+    {
+      unsigned i;
+      tree var = create_tmp_var (type0, "vecel");
+      tree vec1tmp = NULL_TREE;
+
+      v = VEC_alloc (constructor_elt, gc, els);
+      for (i = 0; i < els; i++)
+        {
+          tree idxval, idx1val, cond, elval0, elval1, condexpr, t, ssatmp;
+          tree vec0el, vec1el;
+          gimple asgn;
+
+          idxval = vector_element (gsi, mask, size_int (i), &masktmp);
+         if (idxval == error_mark_node)
+            {
+              if (warning_at (loc, 0, "Invalid shuffling mask index %i", i))
+               inform (loc, "if this code is reached the programm will abort");
+             return false;
+            }
+
+          if (TREE_CODE (idxval) == INTEGER_CST)
+            {
+              if (tree_int_cst_lt (idxval, size_int (els)))
+                {
+                  vec0el = vector_element (gsi, vec0, idxval, &vec0tmp);
+                  t = force_gimple_operand_gsi (gsi, vec0el,
+                                    true, NULL_TREE, true, GSI_SAME_STMT);
+                }
+              else if (tree_int_cst_lt (idxval, size_int (2*els)))
+                {
+                  idx1val = fold_build2 (MINUS_EXPR, TREE_TYPE (idxval),
+                        idxval, build_int_cst (TREE_TYPE (idxval), els));
+
+                  vec1el = vector_element (gsi, vec1, idx1val, &vec1tmp);
+                  t = force_gimple_operand_gsi (gsi, vec1el, true,
+                                               NULL_TREE, true, GSI_SAME_STMT);
+                }
+              else
+                {
+                  if (warning_at (loc, 0, "Invalid shuffling mask index %i", i))
+                   inform (loc, "if this code is reached the "
+                                 "programm will abort");
+                 return false;
+                }
+            }
+          else
+            {
+
+              idx1val = fold_build2 (MINUS_EXPR, TREE_TYPE (idxval),
+                            idxval, build_int_cst (TREE_TYPE (idxval), els));
+              idx1val = force_gimple_operand_gsi (gsi, idx1val,
+                                true, NULL_TREE, true, GSI_SAME_STMT);
+              cond = fold_build2 (GT_EXPR, boolean_type_node, \
+                             idxval, fold_convert (type0, size_int (els - 1)));
+
+             vec0el = vector_element (gsi, vec0, idxval, &vec0tmp);
+              if (vec0el == error_mark_node)
+                {
+                  if (warning_at (loc, 0, "Invalid shuffling arguments"))
+                   inform (loc, "if this code is reached the "
+                                "programm will abort");
+                 return false;
+                }
+
+              elval0 = force_gimple_operand_gsi (gsi, vec0el,
+                                true, NULL_TREE, true, GSI_SAME_STMT);
+
+             vec1el = vector_element (gsi, vec1, idx1val, &vec1tmp);
+              if (vec1el == error_mark_node)
+                {
+                  if (warning_at (loc, 0, "Invalid shuffling arguments"))
+                   inform (loc, "if this code is reached the "
+                                "programm will abort");
+                 return false;
+                }
+
+              elval1 = force_gimple_operand_gsi (gsi, vec1el,
+                                true, NULL_TREE, true, GSI_SAME_STMT);
+
+              condexpr = fold_build3 (COND_EXPR, type0, cond, \
+                                      elval1, elval0);
+
+              t = force_gimple_operand_gsi (gsi, condexpr, true, \
+                                        NULL_TREE, true, GSI_SAME_STMT);
+            }
+
+          asgn = gimple_build_assign (var, t);
+          ssatmp = make_ssa_name (var, asgn);
+          gimple_assign_set_lhs (asgn, ssatmp);
+          gsi_insert_before (gsi, asgn, GSI_SAME_STMT);
+          CONSTRUCTOR_APPEND_ELT (v, size_int (i), ssatmp);
+        }
+    }
+
+  vectype = build_vector_type (type0, els);
+  constr = build_constructor (vectype, v);
+  gimple_assign_set_rhs_from_tree (gsi, constr);
+  /* Statement should be updated by callee.  */
+  return true;
+}
+
 /* Process one statement.  If we identify a vector operation, expand it.  */
 
 static void
@@ -518,6 +775,25 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi)
   rhs_class = get_gimple_rhs_class (code);
   lhs = gimple_assign_lhs (stmt);
 
+  if (code == VEC_SHUFFLE_EXPR)
+    {
+      if (!lower_vec_shuffle (gsi, gimple_location (stmt)))
+       {
+         gimple new_stmt;
+         tree vec0;
+
+         vec0 = gimple_assign_rhs1 (stmt);
+         new_stmt = gimple_build_call (built_in_decls[BUILT_IN_TRAP], 0);
+         gsi_insert_before (gsi, new_stmt,  GSI_SAME_STMT);
+         split_block (gimple_bb (new_stmt), new_stmt);
+         new_stmt = gimple_build_assign (gimple_assign_lhs (stmt), vec0);
+         gsi_replace (gsi, new_stmt, false);
+       }
+
+      gimple_set_modified (gsi_stmt (*gsi), true);
+      update_stmt (gsi_stmt (*gsi));
+    }
+
   if (rhs_class != GIMPLE_UNARY_RHS && rhs_class != GIMPLE_BINARY_RHS)
     return;
 
@@ -551,9 +827,9 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi)
     {
       bool vector_scalar_shift;
       op = optab_for_tree_code (code, type, optab_scalar);
-      
+
       /* Vector/Scalar shift is supported.  */
-      vector_scalar_shift = (op && (optab_handler (op, TYPE_MODE (type)) 
+      vector_scalar_shift = (op && (optab_handler (op, TYPE_MODE (type))
                                    != CODE_FOR_nothing));
 
       /* If the 2nd argument is vector, we need a vector/vector shift.
@@ -566,10 +842,10 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi)
           /* Check whether we have vector <op> {x,x,x,x} where x
              could be a scalar variable or a constant. Transform
              vector <op> {x,x,x,x} ==> vector <op> scalar.  */
-          if (vector_scalar_shift 
+          if (vector_scalar_shift
               && ((TREE_CODE (rhs2) == VECTOR_CST
                   && (first = uniform_vector_p (rhs2)) != NULL_TREE)
-                 || (TREE_CODE (rhs2) == SSA_NAME 
+                 || (TREE_CODE (rhs2) == SSA_NAME
                      && (def_stmt = SSA_NAME_DEF_STMT (rhs2))
                      && gimple_assign_single_p (def_stmt)
                      && (first = uniform_vector_p
@@ -582,14 +858,14 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi)
           else
             op = optab_for_tree_code (code, type, optab_vector);
         }
-    
+
       /* Try for a vector/scalar shift, and if we don't have one, see if we
          have a vector/vector shift */
       else if (!vector_scalar_shift)
        {
          op = optab_for_tree_code (code, type, optab_vector);
 
-         if (op && (optab_handler (op, TYPE_MODE (type)) 
+         if (op && (optab_handler (op, TYPE_MODE (type))
                     != CODE_FOR_nothing))
            {
              /* Transform vector <op> scalar => vector <op> {x,x,x,x}.  */
@@ -684,9 +960,9 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi)
    if it may need the bit-twiddling tricks implemented in this file.  */
 
 static bool
-gate_expand_vector_operations (void)
+gate_expand_vector_operations_ssa (void)
 {
-  return flag_tree_vectorize != 0;
+  return optimize == 0;
 }
 
 static unsigned int
@@ -719,7 +995,7 @@ struct gimple_opt_pass pass_lower_vector =
  {
   GIMPLE_PASS,
   "veclower",                          /* name */
-  0,                                   /* gate */
+  gate_expand_vector_operations_ssa,    /* gate */
   expand_vector_operations,            /* execute */
   NULL,                                        /* sub */
   NULL,                                        /* next */
@@ -732,6 +1008,7 @@ struct gimple_opt_pass pass_lower_vector =
   TODO_update_ssa                      /* todo_flags_finish */
     | TODO_verify_ssa
     | TODO_verify_stmts | TODO_verify_flow
+    | TODO_cleanup_cfg
  }
 };
 
@@ -740,7 +1017,7 @@ struct gimple_opt_pass pass_lower_vector_ssa =
  {
   GIMPLE_PASS,
   "veclower2",                         /* name */
-  gate_expand_vector_operations,       /* gate */
+  0,                                   /* gate */
   expand_vector_operations,            /* execute */
   NULL,                                        /* sub */
   NULL,                                        /* next */
@@ -753,6 +1030,7 @@ struct gimple_opt_pass pass_lower_vector_ssa =
   TODO_update_ssa                      /* todo_flags_finish */
     | TODO_verify_ssa
     | TODO_verify_stmts | TODO_verify_flow
+    | TODO_cleanup_cfg
  }
 };
 
index ea255d5..44c4ee8 100644 (file)
@@ -497,6 +497,19 @@ DEFTREECODE (COND_EXPR, "cond_expr", tcc_expression, 3)
 */
 DEFTREECODE (VEC_COND_EXPR, "vec_cond_expr", tcc_expression, 3)
 
+/* Vector shuffle expression.  A = VEC_SHUFFLE_EXPR<v0, v1, mask>
+   means
+
+   foreach i in length (mask):
+     A = mask[i] < length (v0) ? v0[mask[i]] : v1[mask[i] - length (mask)]
+
+   V0 and V1 are vectors of the same type.  MASK is an integer-typed
+   vector.  The number of MASK elements must be the same with the
+   number of elements in V0 and V1.  The size of the inner type
+   of the MASK and of the V0 and V1 must be the same.
+*/
+DEFTREECODE (VEC_SHUFFLE_EXPR, "vec_shuffle_expr", tcc_expression, 3)
+
 /* Declare local variables, including making RTL and allocating space.
    BIND_EXPR_VARS is a chain of VAR_DECL nodes for the variables.
    BIND_EXPR_BODY is the body, the expression to be computed using