tree-cfg.c (gimplify_val): Move from tree-complex.c.
authorPaolo Bonzini <bonzini@gnu.org>
Thu, 22 Jul 2004 08:20:40 +0000 (08:20 +0000)
committerPaolo Bonzini <bonzini@gcc.gnu.org>
Thu, 22 Jul 2004 08:20:40 +0000 (08:20 +0000)
2004-07-22  Paolo Bonzini  <bonzini@gnu.org>

* tree-cfg.c (gimplify_val): Move from tree-complex.c.
(gimplify_build1): Move from tree-complex.c do_unop.
(gimplify_build2): Move from tree-complex.c do_binop.
(gimplify_build3): New.
* tree-complex.c (gimplify_val, do_unop, do_binop): Remove.
Adjust throughout to call the functions above.
* tree-flow.h: Declare the functions above.
* tree-nested.c (gimplify_val): Rename to...
(tsi_gimplify_val): ... this.

* Makefile.in (tree_complex.o): Update dependencies.
(stor-layout.o): Depend on regs.h.
* c-common.c (handle_vector_size_attribute): Update for
vector types without corresponding vector modes.
* expr.c (expand_expr): Treat VECTOR_CST's like CONSTRUCTORS if
a corresponding vector mode is not available.
* print-tree.c (print_node): Print nunits for vector types
* regclass.c (have_regs_of_mode): New.
(init_reg_sets_1): Initialize it and use it instead
of allocatable_regs_of_mode.
* regs.h (have_regs_of_mode): Declare it.
* stor-layout.c (layout_type): Pick a mode for vector types.
* tree-complex.c (build_word_mode_vector_type, tree_vec_extract,
build_replicated_const, do_unop, do_binop, do_plus_minus,
do_negate, expand_vector_piecewise, expand_vector_parallel,
expand_vector_addition, expand_vector_operations_1,
expand_vector_operations, tree_lower_operations,
pass_lower_vector_ssa, pass_pre_expand): New.
(expand_complex_operations, pass_lower_complex): Remove.
* tree-optimize.c (init_tree_optimization_passes): Adjust
pass ordering for changes in tree-complex.c.
* tree-pass.h: Declare new passes.
* tree.c (finish_vector_type): Remove.
(make_vector_type): New.
(build_vector_type_for_mode, build_vector_type): Rewritten.
* tree.def (VECTOR_TYPE): Document where the number of
subparts is stored.
* tree.h (TYPE_VECTOR_SUBPARTS): Use TYPE_PRECISION field.
(make_vector): Remove declaration.

From-SVN: r85039

18 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/c-common.c
gcc/optabs.c
gcc/optabs.h
gcc/print-tree.c
gcc/regclass.c
gcc/regs.h
gcc/stor-layout.c
gcc/tree-cfg.c
gcc/tree-complex.c
gcc/tree-flow.h
gcc/tree-nested.c
gcc/tree-optimize.c
gcc/tree-pass.h
gcc/tree.c
gcc/tree.def
gcc/tree.h

index 02ba1037f21f3ae3a5dff130a12028796c1b1963..cdd99137bc89c94cf8ddf49d5cb6a9bb8fe80636 100644 (file)
@@ -1,3 +1,45 @@
+2004-07-22  Paolo Bonzini  <bonzini@gnu.org>
+
+       * tree-cfg.c (gimplify_val): Move from tree-complex.c.
+       (gimplify_build1): Move from tree-complex.c do_unop.
+       (gimplify_build2): Move from tree-complex.c do_binop.
+       (gimplify_build3): New.
+       * tree-complex.c (gimplify_val, do_unop, do_binop): Remove.
+       Adjust throughout to call the functions above.
+       * tree-flow.h: Declare the functions above.
+       * tree-nested.c (gimplify_val): Rename to...
+       (tsi_gimplify_val): ... this.
+
+       * Makefile.in (tree_complex.o): Update dependencies.
+       (stor-layout.o): Depend on regs.h.
+       * c-common.c (handle_vector_size_attribute): Update for
+       vector types without corresponding vector modes.
+       * expr.c (expand_expr): Treat VECTOR_CST's like CONSTRUCTORS if
+       a corresponding vector mode is not available.
+       * print-tree.c (print_node): Print nunits for vector types
+       * regclass.c (have_regs_of_mode): New.
+       (init_reg_sets_1): Initialize it and use it instead
+       of allocatable_regs_of_mode.
+       * regs.h (have_regs_of_mode): Declare it.
+       * stor-layout.c (layout_type): Pick a mode for vector types.
+       * tree-complex.c (build_word_mode_vector_type, tree_vec_extract,
+       build_replicated_const, do_unop, do_binop, do_plus_minus,
+       do_negate, expand_vector_piecewise, expand_vector_parallel,
+       expand_vector_addition, expand_vector_operations_1,
+       expand_vector_operations, tree_lower_operations,
+       pass_lower_vector_ssa, pass_pre_expand): New.
+       (expand_complex_operations, pass_lower_complex): Remove.
+       * tree-optimize.c (init_tree_optimization_passes): Adjust
+       pass ordering for changes in tree-complex.c.
+       * tree-pass.h: Declare new passes.
+       * tree.c (finish_vector_type): Remove.
+       (make_vector_type): New.
+       (build_vector_type_for_mode, build_vector_type): Rewritten.
+       * tree.def (VECTOR_TYPE): Document where the number of
+       subparts is stored.
+       * tree.h (TYPE_VECTOR_SUBPARTS): Use TYPE_PRECISION field.
+       (make_vector): Remove declaration.
+
 2004-07-21  Richard Henderson  <rth@redhat.com>
 
        * gimple-low.c (expand_var_p): Don't look at TREE_ADDRESSABLE,
index 8706bae3c72d0801104c0506b66d69e11d1e643f..32bb1fe513e73bf1136323b1d213a468e1b8c697 100644 (file)
@@ -1585,7 +1585,7 @@ print-tree.o : print-tree.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H
    $(GGC_H) langhooks.h real.h
 stor-layout.o : stor-layout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
    $(FLAGS_H) function.h $(EXPR_H) $(RTL_H) toplev.h $(GGC_H) $(TM_P_H) $(TARGET_H) \
-   langhooks.h
+   langhooks.h $(REGS_H)
 tree-alias-type.o: tree-alias-type.c tree-alias-type.h $(SYSTEM_H) $(CONFIG_H) \
    $(GGC_H) $(TM_H) coretypes.h $(VARRAY_H)
 tree-alias-ander.o: tree-alias-ander.c tree-alias-ander.h $(SYSTEM_H) \
@@ -1922,7 +1922,8 @@ tree-sra.o : tree-sra.c $(CONFIG_H) system.h errors.h $(TREE_H) $(RTL_H) \
     langhooks.h tree-pass.h $(FLAGS_H) $(EXPR_H)
 tree-complex.o : tree-complex.c $(CONFIG_H) system.h $(TREE_H) \
     $(TM_H) $(TREE_FLOW_H) $(TREE_GIMPLE_H) tree-iterator.h tree-pass.h \
-    $(FLAGS_H)
+    $(FLAGS_H) $(OPTABS_H) $(RTL_H) $(MACHMODE_H) $(EXPR_H) \
+    langhooks.h $(FLAGS_H) $(DIAGNOSTIC_H)
 df.o : df.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)
index 4d40922261573403fbad6ac727a77ff04431a906..2f9e2e24e78d80d4f5a8f1039d0e159aea1e66d5 100644 (file)
@@ -4783,7 +4783,7 @@ handle_vector_size_attribute (tree *node, tree name, tree args,
                              bool *no_add_attrs)
 {
   unsigned HOST_WIDE_INT vecsize, nunits;
-  enum machine_mode mode, orig_mode, new_mode;
+  enum machine_mode orig_mode;
   tree type = *node, new_type, size;
 
   *no_add_attrs = true;
@@ -4832,28 +4832,13 @@ handle_vector_size_attribute (tree *node, tree name, tree args,
 
   /* Calculate how many units fit in the vector.  */
   nunits = vecsize / tree_low_cst (TYPE_SIZE_UNIT (type), 1);
-
-  /* Find a suitably sized vector.  */
-  new_mode = VOIDmode;
-  for (mode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (orig_mode) == MODE_INT
-                                       ? MODE_VECTOR_INT
-                                       : MODE_VECTOR_FLOAT);
-       mode != VOIDmode;
-       mode = GET_MODE_WIDER_MODE (mode))
-    if (vecsize == GET_MODE_SIZE (mode)
-       && nunits == (unsigned HOST_WIDE_INT) GET_MODE_NUNITS (mode))
-      {
-       new_mode = mode;
-       break;
-      }
-
-  if (new_mode == VOIDmode)
+  if (nunits & (nunits - 1))
     {
-      error ("no vector mode with the size and type specified could be found");
+      error ("number of components of the vector not a power of two");
       return NULL_TREE;
     }
 
-  new_type = build_vector_type_for_mode (type, new_mode);
+  new_type = build_vector_type (type, nunits);
 
   /* Build back pointers if needed.  */
   *node = reconstruct_complex_type (*node, new_type);
index 2440a86dc9419edabd7b3762c6baf7ea01c509c1..1f013f37a6092192dd7716f5acb8f1a8cdedcc07 100644 (file)
@@ -627,6 +627,89 @@ expand_cmplxdiv_wide (rtx real0, rtx real1, rtx imag0, rtx imag1, rtx realr,
 
   return 1;
 }
+\f
+/* Return the optab used for computing the operation given by
+   the tree code, CODE.  This function is not always usable (for
+   example, it cannot give complete results for multiplication
+   or division) but probably ought to be relied on more widely
+   throughout the expander.  */
+optab
+optab_for_tree_code (enum tree_code code, tree type)
+{
+  bool trapv;
+  switch (code)
+    {
+    case BIT_AND_EXPR:
+      return and_optab;
+
+    case BIT_IOR_EXPR:
+      return ior_optab;
+
+    case BIT_NOT_EXPR:
+      return one_cmpl_optab;
+
+    case BIT_XOR_EXPR:
+      return xor_optab;
+
+    case TRUNC_MOD_EXPR:
+    case CEIL_MOD_EXPR:
+    case FLOOR_MOD_EXPR:
+    case ROUND_MOD_EXPR:
+      return TYPE_UNSIGNED (type) ? umod_optab : smod_optab;
+
+    case RDIV_EXPR:
+    case TRUNC_DIV_EXPR:
+    case CEIL_DIV_EXPR:
+    case FLOOR_DIV_EXPR:
+    case ROUND_DIV_EXPR:
+    case EXACT_DIV_EXPR:
+      return TYPE_UNSIGNED (type) ? udiv_optab : sdiv_optab;
+
+    case LSHIFT_EXPR:
+      return ashl_optab;
+
+    case RSHIFT_EXPR:
+      return TYPE_UNSIGNED (type) ? lshr_optab : ashr_optab;
+
+    case LROTATE_EXPR:
+      return rotl_optab;
+
+    case RROTATE_EXPR:
+      return rotr_optab;
+
+    case MAX_EXPR:
+      return TYPE_UNSIGNED (type) ? umax_optab : smax_optab;
+
+    case MIN_EXPR:
+      return TYPE_UNSIGNED (type) ? umin_optab : smin_optab;
+
+    default:
+      break;
+    }
+
+  trapv = flag_trapv && INTEGRAL_TYPE_P (type) && !TYPE_UNSIGNED (type);
+  switch (code)
+    {
+    case PLUS_EXPR:
+      return trapv ? addv_optab : add_optab;
+
+    case MINUS_EXPR:
+      return trapv ? subv_optab : sub_optab;
+
+    case MULT_EXPR:
+      return trapv ? smulv_optab : smul_optab;
+
+    case NEGATE_EXPR:
+      return trapv ? negv_optab : neg_optab;
+
+    case ABS_EXPR:
+      return trapv ? absv_optab : abs_optab;
+
+    default:
+      return NULL;
+    }
+}
+
 \f
 /* Wrapper around expand_binop which takes an rtx code to specify
    the operation to perform, not an optab pointer.  All other
@@ -2804,7 +2887,8 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
     }
 
   /* If there is no negate operation, try doing a subtract from zero.
-     The US Software GOFAST library needs this.  */
+     The US Software GOFAST library needs this.  FIXME: This is *wrong*
+     for floating-point operations due to negative zeros!  */
   if (unoptab->code == NEG)
     {
       rtx temp;
index 064d753269d49fefe8a89de4a300c897698c0d64..dec53d37e29e56db042038d19b426f8d248cd6f9 100644 (file)
@@ -454,6 +454,10 @@ enum can_compare_purpose
   ccp_store_flag
 };
 
+/* Return the optab used for computing the given operation on the type
+   given by the second argument.  */
+extern optab optab_for_tree_code (enum tree_code, tree);
+
 /* Nonzero if a compare of mode MODE can be done straightforwardly
    (without splitting it into pieces).  */
 extern int can_compare_p (enum rtx_code, enum machine_mode,
index 5d23a6e0d18ff85e04823a0efb418a847e81c9ef..3944842635da0f7d675960d8133b85972e511da8 100644 (file)
@@ -537,6 +537,8 @@ print_node (FILE *file, const char *prefix, tree node, int indent)
        print_node (file, "values", TYPE_VALUES (node), indent + 4);
       else if (TREE_CODE (node) == ARRAY_TYPE || TREE_CODE (node) == SET_TYPE)
        print_node (file, "domain", TYPE_DOMAIN (node), indent + 4);
+      else if (TREE_CODE (node) == VECTOR_TYPE)
+       fprintf (file, " nunits %d", (int) TYPE_VECTOR_SUBPARTS (node));
       else if (TREE_CODE (node) == RECORD_TYPE
               || TREE_CODE (node) == UNION_TYPE
               || TREE_CODE (node) == QUAL_UNION_TYPE)
index 5bc6cc8051fa1f6ad555f004715197876e6408c9..f341c39c2145609b76a2d22489be81c930bb2181 100644 (file)
@@ -191,6 +191,10 @@ const char * reg_names[] = REGISTER_NAMES;
 
 enum machine_mode reg_raw_mode[FIRST_PSEUDO_REGISTER];
 
+/* 1 if there is a register of given mode.  */
+
+bool have_regs_of_mode [MAX_MACHINE_MODE];
+
 /* 1 if class does contain register of given mode.  */
 
 static char contains_reg_of_mode [N_REG_CLASSES] [MAX_MACHINE_MODE];
@@ -305,7 +309,6 @@ init_reg_sets_1 (void)
 {
   unsigned int i, j;
   unsigned int /* enum machine_mode */ m;
-  char allocatable_regs_of_mode [MAX_MACHINE_MODE];
 
   /* This macro allows the fixed or call-used registers
      and the register classes to depend on target flags.  */
@@ -469,8 +472,8 @@ init_reg_sets_1 (void)
        SET_HARD_REG_BIT (regs_invalidated_by_call, i);
     }
 
+  memset (have_regs_of_mode, 0, sizeof (have_regs_of_mode));
   memset (contains_reg_of_mode, 0, sizeof (contains_reg_of_mode));
-  memset (allocatable_regs_of_mode, 0, sizeof (allocatable_regs_of_mode));
   for (m = 0; m < (unsigned int) MAX_MACHINE_MODE; m++)
     for (i = 0; i < N_REG_CLASSES; i++)
       if ((unsigned) CLASS_MAX_NREGS (i, m) <= reg_class_size[i])
@@ -479,7 +482,7 @@ init_reg_sets_1 (void)
              && HARD_REGNO_MODE_OK (j, m))
             {
               contains_reg_of_mode [i][m] = 1;
-              allocatable_regs_of_mode [m] = 1;
+              have_regs_of_mode [m] = 1;
               break;
             }
 
@@ -487,7 +490,7 @@ init_reg_sets_1 (void)
      and take the maximum cost of moving any subset to any other.  */
 
   for (m = 0; m < (unsigned int) MAX_MACHINE_MODE; m++)
-    if (allocatable_regs_of_mode [m])
+    if (have_regs_of_mode [m])
       {
        for (i = 0; i < N_REG_CLASSES; i++)
          if (contains_reg_of_mode [i][m])
index c100bdeabacee620ecac992500f3aa4835c50ba8..027b0e33c67e5570732301f8bceb1f6dea9a6c81 100644 (file)
@@ -163,6 +163,10 @@ extern char regs_ever_live[FIRST_PSEUDO_REGISTER];
 
 extern char regs_asm_clobbered[FIRST_PSEUDO_REGISTER];
 
+/* Vector indexed by machine mode saying whether there are regs of that mode.  */
+
+extern bool have_regs_of_mode [MAX_MACHINE_MODE];
+
 /* For each hard register, the widest mode object that it can contain.
    This will be a MODE_INT mode if the register can hold integers.  Otherwise
    it will be a MODE_FLOAT or a MODE_CC mode, whichever is valid for the
index 0ca26c238f766baafe5f8a9dcdf057fa3234418e..139ba510435766c22657e7e35cb539d195e6211c 100644 (file)
@@ -34,6 +34,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "ggc.h"
 #include "target.h"
 #include "langhooks.h"
+#include "regs.h"
 
 /* Set to one when set_sizetype has been called.  */
 static int sizetype_set;
@@ -1582,10 +1583,52 @@ layout_type (tree type)
       break;
 
     case VECTOR_TYPE:
-      TYPE_UNSIGNED (type) = TYPE_UNSIGNED (TREE_TYPE (type));
-      TYPE_SIZE (type) = bitsize_int (GET_MODE_BITSIZE (TYPE_MODE (type)));
-      TYPE_SIZE_UNIT (type) = size_int (GET_MODE_SIZE (TYPE_MODE (type)));
-      break;
+      {
+       int nunits = TYPE_VECTOR_SUBPARTS (type);
+       tree nunits_tree = build_int_2 (nunits, 0);
+       tree innertype = TREE_TYPE (type);
+
+       if (nunits & (nunits - 1))
+         abort ();
+
+       /* Find an appropriate mode for the vector type.  */
+       if (TYPE_MODE (type) == VOIDmode)
+         {
+           enum machine_mode innermode = TYPE_MODE (innertype);
+           enum machine_mode mode;
+
+           /* First, look for a supported vector type.  */
+           if (GET_MODE_CLASS (innermode) == MODE_FLOAT)
+             mode = MIN_MODE_VECTOR_FLOAT;
+           else
+             mode = MIN_MODE_VECTOR_INT;
+
+           for (; mode != VOIDmode ; mode = GET_MODE_WIDER_MODE (mode))
+             if (GET_MODE_NUNITS (mode) == nunits
+                 && GET_MODE_INNER (mode) == innermode
+                 && VECTOR_MODE_SUPPORTED_P (mode))
+               break;
+
+           /* For integers, try mapping it to a same-sized scalar mode.  */
+           if (mode == VOIDmode
+               && GET_MODE_CLASS (innermode) == MODE_INT)
+             mode = mode_for_size (nunits * GET_MODE_BITSIZE (innermode),
+                                   MODE_INT, 0);
+
+           if (mode == VOIDmode || !have_regs_of_mode[mode])
+             TYPE_MODE (type) = BLKmode;
+           else
+             TYPE_MODE (type) = mode;
+         }
+
+        TYPE_UNSIGNED (type) = TYPE_UNSIGNED (TREE_TYPE (type));
+       TYPE_SIZE_UNIT (type) = int_const_binop (MULT_EXPR,
+                                                TYPE_SIZE_UNIT (innertype),
+                                                nunits_tree, 0);
+       TYPE_SIZE (type) = int_const_binop (MULT_EXPR, TYPE_SIZE (innertype),
+                                           nunits_tree, 0);
+        break;
+      }
 
     case VOID_TYPE:
       /* This is an incomplete type and so doesn't have a size.  */
index c80dcf1d086c97cf3106dcd8e98c4fd543111d78..1c04e528cee5dab4be55d22df023bdd63baad3c6 100644 (file)
@@ -4793,6 +4793,79 @@ struct tree_opt_pass pass_split_crit_edges =
   0,                             /* todo_flags_start */
   TODO_dump_func,                             /* todo_flags_finish */
 };
+
+\f
+/* Return EXP if it is a valid GIMPLE rvalue, else gimplify it into
+   a temporary, make sure and register it to be renamed if necessary,
+   and finally return the temporary.  Put the statements to compute
+   EXP before the current statement in BSI.  */
+
+tree
+gimplify_val (block_stmt_iterator *bsi, tree type, tree exp)
+{
+  tree t, new_stmt, orig_stmt;
+
+  if (is_gimple_val (exp))
+    return exp;
+
+  t = make_rename_temp (type, NULL);
+  new_stmt = build (MODIFY_EXPR, type, t, exp);
+
+  orig_stmt = bsi_stmt (*bsi);
+  SET_EXPR_LOCUS (new_stmt, EXPR_LOCUS (orig_stmt));
+  TREE_BLOCK (new_stmt) = TREE_BLOCK (orig_stmt);
+
+  bsi_insert_before (bsi, new_stmt, BSI_SAME_STMT);
+
+  return t;
+}
+
+/* Build a ternary operation and gimplify it.  Emit code before BSI.
+   Return the gimple_val holding the result.  */
+
+tree
+gimplify_build3 (block_stmt_iterator *bsi, enum tree_code code,
+                tree type, tree a, tree b, tree c)
+{
+  tree ret;
+
+  ret = fold (build3 (code, type, a, b, c));
+  STRIP_NOPS (ret);
+
+  return gimplify_val (bsi, type, ret);
+}
+
+/* Build a binary operation and gimplify it.  Emit code before BSI.
+   Return the gimple_val holding the result.  */
+
+tree
+gimplify_build2 (block_stmt_iterator *bsi, enum tree_code code,
+                tree type, tree a, tree b)
+{
+  tree ret;
+
+  ret = fold (build2 (code, type, a, b));
+  STRIP_NOPS (ret);
+
+  return gimplify_val (bsi, type, ret);
+}
+
+/* Build a unary operation and gimplify it.  Emit code before BSI.
+   Return the gimple_val holding the result.  */
+
+tree
+gimplify_build1 (block_stmt_iterator *bsi, enum tree_code code, tree type,
+                tree a)
+{
+  tree ret;
+
+  ret = fold (build1 (code, type, a));
+  STRIP_NOPS (ret);
+
+  return gimplify_val (bsi, type, ret);
+}
+
+
 \f
 /* Emit return warnings.  */
 
index 0e6dab7e471392e74d122e2a0990303458387eaf..a960f92c42427b76bfa17426a978bffa9a6a103b 100644 (file)
@@ -1,4 +1,4 @@
-/* Lower complex operations to scalar operations.
+/* Lower complex number and vector operations to scalar operations.
    Copyright (C) 2004 Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -23,6 +23,13 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "coretypes.h"
 #include "tree.h"
 #include "tm.h"
+#include "rtl.h"
+#include "expr.h"
+#include "insn-codes.h"
+#include "diagnostic.h"
+#include "optabs.h"
+#include "machmode.h"
+#include "langhooks.h"
 #include "tree-flow.h"
 #include "tree-gimple.h"
 #include "tree-iterator.h"
@@ -30,28 +37,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "flags.h"
 
 
-/* Force EXP to be a gimple_val.  */
-
-static tree
-gimplify_val (block_stmt_iterator *bsi, tree type, tree exp)
-{
-  tree t, new_stmt, orig_stmt;
-
-  if (is_gimple_val (exp))
-    return exp;
-
-  t = make_rename_temp (type, NULL);
-  new_stmt = build (MODIFY_EXPR, type, t, exp);
-
-  orig_stmt = bsi_stmt (*bsi);
-  SET_EXPR_LOCUS (new_stmt, EXPR_LOCUS (orig_stmt));
-  TREE_BLOCK (new_stmt) = TREE_BLOCK (orig_stmt);
-
-  bsi_insert_before (bsi, new_stmt, BSI_SAME_STMT);
-
-  return t;
-}
-
 /* Extract the real or imaginary part of a complex variable or constant.
    Make sure that it's a proper gimple_val and gimplify it if not.
    Emit any new code before BSI.  */
@@ -85,35 +70,6 @@ extract_component (block_stmt_iterator *bsi, tree t, bool imagpart_p)
   return gimplify_val (bsi, inner_type, ret);
 }
 
-/* Build a binary operation and gimplify it.  Emit code before BSI.
-   Return the gimple_val holding the result.  */
-
-static tree
-do_binop (block_stmt_iterator *bsi, enum tree_code code,
-         tree type, tree a, tree b)
-{
-  tree ret;
-
-  ret = fold (build (code, type, a, b));
-  STRIP_NOPS (ret);
-
-  return gimplify_val (bsi, type, ret);
-}
-
-/* Build a unary operation and gimplify it.  Emit code before BSI.
-   Return the gimple_val holding the result.  */
-
-static tree
-do_unop (block_stmt_iterator *bsi, enum tree_code code, tree type, tree a)
-{
-  tree ret;
-
-  ret = fold (build1 (code, type, a));
-  STRIP_NOPS (ret);
-
-  return gimplify_val (bsi, type, ret);
-}
-
 /* Update an assignment to a complex variable in place.  */
 
 static void
@@ -142,8 +98,8 @@ expand_complex_addition (block_stmt_iterator *bsi, tree inner_type,
 {
   tree rr, ri;
 
-  rr = do_binop (bsi, code, inner_type, ar, br);
-  ri = do_binop (bsi, code, inner_type, ai, bi);
+  rr = gimplify_build2 (bsi, code, inner_type, ar, br);
+  ri = gimplify_build2 (bsi, code, inner_type, ai, bi);
 
   update_complex_assignment (bsi, rr, ri);
 }
@@ -158,19 +114,19 @@ expand_complex_multiplication (block_stmt_iterator *bsi, tree inner_type,
 {
   tree t1, t2, t3, t4, rr, ri;
 
-  t1 = do_binop (bsi, MULT_EXPR, inner_type, ar, br);
-  t2 = do_binop (bsi, MULT_EXPR, inner_type, ai, bi);
-  t3 = do_binop (bsi, MULT_EXPR, inner_type, ar, bi);
+  t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ar, br);
+  t2 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ai, bi);
+  t3 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ar, bi);
 
   /* Avoid expanding redundant multiplication for the common
      case of squaring a complex number.  */
   if (ar == br && ai == bi)
     t4 = t3;
   else
-    t4 = do_binop (bsi, MULT_EXPR, inner_type, ai, br);
+    t4 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ai, br);
 
-  rr = do_binop (bsi, MINUS_EXPR, inner_type, t1, t2);
-  ri = do_binop (bsi, PLUS_EXPR, inner_type, t3, t4);
+  rr = gimplify_build2 (bsi, MINUS_EXPR, inner_type, t1, t2);
+  ri = gimplify_build2 (bsi, PLUS_EXPR, inner_type, t3, t4);
 
   update_complex_assignment (bsi, rr, ri);
 }
@@ -187,19 +143,19 @@ expand_complex_div_straight (block_stmt_iterator *bsi, tree inner_type,
 {
   tree rr, ri, div, t1, t2, t3;
 
-  t1 = do_binop (bsi, MULT_EXPR, inner_type, br, br);
-  t2 = do_binop (bsi, MULT_EXPR, inner_type, bi, bi);
-  div = do_binop (bsi, PLUS_EXPR, inner_type, t1, t2);
+  t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, br, br);
+  t2 = gimplify_build2 (bsi, MULT_EXPR, inner_type, bi, bi);
+  div = gimplify_build2 (bsi, PLUS_EXPR, inner_type, t1, t2);
 
-  t1 = do_binop (bsi, MULT_EXPR, inner_type, ar, br);
-  t2 = do_binop (bsi, MULT_EXPR, inner_type, ai, bi);
-  t3 = do_binop (bsi, PLUS_EXPR, inner_type, t1, t2);
-  rr = do_binop (bsi, code, inner_type, t3, div);
+  t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ar, br);
+  t2 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ai, bi);
+  t3 = gimplify_build2 (bsi, PLUS_EXPR, inner_type, t1, t2);
+  rr = gimplify_build2 (bsi, code, inner_type, t3, div);
 
-  t1 = do_binop (bsi, MULT_EXPR, inner_type, ai, br);
-  t2 = do_binop (bsi, MULT_EXPR, inner_type, ar, bi);
-  t3 = do_binop (bsi, MINUS_EXPR, inner_type, t1, t2);
-  ri = do_binop (bsi, code, inner_type, t3, div);
+  t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ai, br);
+  t2 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ar, bi);
+  t3 = gimplify_build2 (bsi, MINUS_EXPR, inner_type, t1, t2);
+  ri = gimplify_build2 (bsi, code, inner_type, t3, div);
 
   update_complex_assignment (bsi, rr, ri);
 }
@@ -215,8 +171,8 @@ expand_complex_div_wide (block_stmt_iterator *bsi, tree inner_type,
   tree rr, ri, ratio, div, t1, t2, min, max, cond;
 
   /* Examine |br| < |bi|, and branch.  */
-  t1 = do_unop (bsi, ABS_EXPR, inner_type, br);
-  t2 = do_unop (bsi, ABS_EXPR, inner_type, bi);
+  t1 = gimplify_build1 (bsi, ABS_EXPR, inner_type, br);
+  t2 = gimplify_build1 (bsi, ABS_EXPR, inner_type, bi);
   cond = fold (build (LT_EXPR, boolean_type_node, t1, t2));
   STRIP_NOPS (cond);
 
@@ -292,20 +248,20 @@ expand_complex_div_wide (block_stmt_iterator *bsi, tree inner_type,
   
   /* Now we have MIN(|br|, |bi|) and MAX(|br|, |bi|).  We now use the
      ratio min/max to scale both the dividend and divisor.  */
-  ratio = do_binop (bsi, code, inner_type, min, max);
+  ratio = gimplify_build2 (bsi, code, inner_type, min, max);
 
   /* Calculate the divisor: min*ratio + max.  */
-  t1 = do_binop (bsi, MULT_EXPR, inner_type, min, ratio);
-  div = do_binop (bsi, PLUS_EXPR, inner_type, t1, max);
+  t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, min, ratio);
+  div = gimplify_build2 (bsi, PLUS_EXPR, inner_type, t1, max);
 
-  /* Result is now ((ar + ai*ratio)/div) + i((ai - ar*ratio)/div).  */
-  t1 = do_binop (bsi, MULT_EXPR, inner_type, ai, ratio);
-  t2 = do_binop (bsi, PLUS_EXPR, inner_type, ar, t1);
-  rr = do_binop (bsi, code, inner_type, t2, div);
+  /* Result is now ((ar + ai*ratio)/div) + i((ai - ar*ratio)/div). */
+  t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ai, ratio);
+  t2 = gimplify_build2 (bsi, PLUS_EXPR, inner_type, ar, t1);
+  rr = gimplify_build2 (bsi, code, inner_type, t2, div);
 
-  t1 = do_binop (bsi, MULT_EXPR, inner_type, ar, ratio);
-  t2 = do_binop (bsi, MINUS_EXPR, inner_type, ai, t1);
-  ri = do_binop (bsi, code, inner_type, t2, div);
+  t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ar, ratio);
+  t2 = gimplify_build2 (bsi, MINUS_EXPR, inner_type, ai, t1);
+  ri = gimplify_build2 (bsi, code, inner_type, t2, div);
 
   update_complex_assignment (bsi, rr, ri);
 }
@@ -343,8 +299,8 @@ expand_complex_negation (block_stmt_iterator *bsi, tree inner_type,
 {
   tree rr, ri;
 
-  rr = do_unop (bsi, NEGATE_EXPR, inner_type, ar);
-  ri = do_unop (bsi, NEGATE_EXPR, inner_type, ai);
+  rr = gimplify_build1 (bsi, NEGATE_EXPR, inner_type, ar);
+  ri = gimplify_build1 (bsi, NEGATE_EXPR, inner_type, ai);
 
   update_complex_assignment (bsi, rr, ri);
 }
@@ -359,7 +315,7 @@ expand_complex_conjugate (block_stmt_iterator *bsi, tree inner_type,
 {
   tree ri;
 
-  ri = do_unop (bsi, NEGATE_EXPR, inner_type, ai);
+  ri = gimplify_build1 (bsi, NEGATE_EXPR, inner_type, ai);
 
   update_complex_assignment (bsi, ar, ri);
 }
@@ -372,10 +328,11 @@ expand_complex_comparison (block_stmt_iterator *bsi, tree ar, tree ai,
 {
   tree cr, ci, cc, stmt, type;
 
-  cr = do_binop (bsi, code, boolean_type_node, ar, br);
-  ci = do_binop (bsi, code, boolean_type_node, ai, bi);
-  cc = do_binop (bsi, (code == EQ_EXPR ? TRUTH_AND_EXPR : TRUTH_OR_EXPR),
-                boolean_type_node, cr, ci);
+  cr = gimplify_build2 (bsi, code, boolean_type_node, ar, br);
+  ci = gimplify_build2 (bsi, code, boolean_type_node, ai, bi);
+  cc = gimplify_build2 (bsi,
+                       (code == EQ_EXPR ? TRUTH_AND_EXPR : TRUTH_OR_EXPR),
+                       boolean_type_node, cr, ci);
 
   stmt = bsi_stmt (*bsi);
   modify_stmt (stmt);
@@ -517,17 +474,434 @@ expand_complex_operations_1 (block_stmt_iterator *bsi)
       abort ();
     }
 }
+\f
+/* Build a constant of type TYPE, made of VALUE's bits replicated
+   every TYPE_SIZE (INNER_TYPE) bits to fit TYPE's precision.  */
+static tree
+build_replicated_const (tree type, tree inner_type, HOST_WIDE_INT value)
+{
+  int width = tree_low_cst (TYPE_SIZE (inner_type), 1);
+  int n = HOST_BITS_PER_WIDE_INT / width;
+  unsigned HOST_WIDE_INT low, high, mask;
+  tree ret;
+
+  if (n == 0)
+    abort ();
+
+  if (width == HOST_BITS_PER_WIDE_INT)
+    low = value;
+  else
+    {
+      mask = ((HOST_WIDE_INT)1 << width) - 1;
+      low = (unsigned HOST_WIDE_INT) ~0 / mask * (value & mask);
+    }
+
+  if (TYPE_PRECISION (type) < HOST_BITS_PER_WIDE_INT)
+    low &= ((HOST_WIDE_INT)1 << TYPE_PRECISION (type)) - 1, high = 0;
+  else if (TYPE_PRECISION (type) == HOST_BITS_PER_WIDE_INT)
+    high = 0;
+  else if (TYPE_PRECISION (type) == 2 * HOST_BITS_PER_WIDE_INT)
+    high = low;
+  else
+    abort ();
+
+  ret = build_int_2 (low, high);
+  TREE_TYPE (ret) = type;
+  return ret;
+}
 
-/* Main loop to process each statement.  */
-/* ??? Could use dominator bits to propagate from complex_expr at the
-   same time.  This might reveal more constants, particularly in cases
-   such as (complex = complex op scalar).  This may not be relevant
-   after SRA and subsequent cleanups.  Proof of this would be if we
-   verify that the code generated by expand_complex_div_wide is
-   simplified properly to straight-line code.  */
+/* Return a suitable vector types made of SUBPARTS units each of mode
+   "word_mode" (the global variable).  */
+static tree
+build_word_mode_vector_type (int nunits)
+{
+  static tree innertype;
+  static tree last;
+  static int last_nunits;
+
+  if (!innertype)
+    innertype = lang_hooks.types.type_for_mode (word_mode, 1);
+  else if (last_nunits == nunits)
+    return last;
+
+  /* We build a new type, but we canonicalize it nevertheless,
+     because it still saves some memory.  */
+  last_nunits = nunits;
+  last = type_hash_canon (nunits, build_vector_type (innertype, nunits));
+  return last;
+}
+
+typedef tree (*elem_op_func) (block_stmt_iterator *,
+                             tree, tree, tree, tree, tree, enum tree_code);
+
+static inline tree
+tree_vec_extract (block_stmt_iterator *bsi, tree type,
+                 tree t, tree bitsize, tree bitpos)
+{
+  if (bitpos)
+    return gimplify_build3 (bsi, BIT_FIELD_REF, type, t, bitsize, bitpos);
+  else
+    return gimplify_build1 (bsi, VIEW_CONVERT_EXPR, type, t);
+}
+
+static tree
+do_unop (block_stmt_iterator *bsi, tree inner_type, tree a,
+        tree b ATTRIBUTE_UNUSED, tree bitpos, tree bitsize,
+        enum tree_code code)
+{
+  a = tree_vec_extract (bsi, inner_type, a, bitsize, bitpos);
+  return gimplify_build1 (bsi, code, inner_type, a);
+}
+
+static tree
+do_binop (block_stmt_iterator *bsi, tree inner_type, tree a, tree b,
+         tree bitpos, tree bitsize, enum tree_code code)
+{
+  a = tree_vec_extract (bsi, inner_type, a, bitsize, bitpos);
+  b = tree_vec_extract (bsi, inner_type, b, bitsize, bitpos);
+  return gimplify_build2 (bsi, code, inner_type, a, b);
+}
+
+/* Expand vector addition to scalars.  This does bit twiddling
+   in order to increase parallelism:
+
+   a + b = (((int) a & 0x7f7f7f7f) + ((int) b & 0x7f7f7f7f)) ^
+           (a ^ b) & 0x80808080
+
+   a - b =  (((int) a | 0x80808080) - ((int) b & 0x7f7f7f7f)) ^
+            (a ^ ~b) & 0x80808080
+
+   -b = (0x80808080 - ((int) b & 0x7f7f7f7f)) ^ (~b & 0x80808080)
+
+   This optimization should be done only if 4 vector items or more
+   fit into a word.  */
+static tree
+do_plus_minus (block_stmt_iterator *bsi, tree word_type, tree a, tree b,
+              tree bitpos ATTRIBUTE_UNUSED, tree bitsize ATTRIBUTE_UNUSED,
+              enum tree_code code)
+{
+  tree inner_type = TREE_TYPE (TREE_TYPE (a));
+  unsigned HOST_WIDE_INT max;
+  tree low_bits, high_bits, a_low, b_low, result_low, signs;
+
+  max = GET_MODE_MASK (TYPE_MODE (inner_type));
+  low_bits = build_replicated_const (word_type, inner_type, max >> 1);
+  high_bits = build_replicated_const (word_type, inner_type, max & ~(max >> 1));
+
+  a = tree_vec_extract (bsi, word_type, a, bitsize, bitpos);
+  b = tree_vec_extract (bsi, word_type, b, bitsize, bitpos);
+
+  signs = gimplify_build2 (bsi, BIT_XOR_EXPR, word_type, a, b);
+  b_low = gimplify_build2 (bsi, BIT_AND_EXPR, word_type, b, low_bits);
+  if (code == PLUS_EXPR)
+    a_low = gimplify_build2 (bsi, BIT_AND_EXPR, word_type, a, low_bits);
+  else
+    {
+      a_low = gimplify_build2 (bsi, BIT_IOR_EXPR, word_type, a, high_bits);
+      signs = gimplify_build1 (bsi, BIT_NOT_EXPR, word_type, signs);
+    }
+
+  signs = gimplify_build2 (bsi, BIT_AND_EXPR, word_type, signs, high_bits);
+  result_low = gimplify_build2 (bsi, code, word_type, a_low, b_low);
+  return gimplify_build2 (bsi, BIT_XOR_EXPR, word_type, result_low, signs);
+}
+
+static tree
+do_negate (block_stmt_iterator *bsi, tree word_type, tree b,
+          tree unused ATTRIBUTE_UNUSED, tree bitpos ATTRIBUTE_UNUSED,
+          tree bitsize ATTRIBUTE_UNUSED,
+          enum tree_code code ATTRIBUTE_UNUSED)
+{
+  tree inner_type = TREE_TYPE (TREE_TYPE (b));
+  HOST_WIDE_INT max;
+  tree low_bits, high_bits, b_low, result_low, signs;
+
+  max = GET_MODE_MASK (TYPE_MODE (inner_type));
+  low_bits = build_replicated_const (word_type, inner_type, max >> 1);
+  high_bits = build_replicated_const (word_type, inner_type, max & ~(max >> 1));
+
+  b = tree_vec_extract (bsi, word_type, b, bitsize, bitpos);
+
+  b_low = gimplify_build2 (bsi, BIT_AND_EXPR, word_type, b, low_bits);
+  signs = gimplify_build1 (bsi, BIT_NOT_EXPR, word_type, b);
+  signs = gimplify_build2 (bsi, BIT_AND_EXPR, word_type, signs, high_bits);
+  result_low = gimplify_build2 (bsi, MINUS_EXPR, word_type, high_bits, b_low);
+  return gimplify_build2 (bsi, BIT_XOR_EXPR, word_type, result_low, signs);
+}
+
+/* Expand a vector operation to scalars, by using many operations
+   whose type is the vector type's inner type.  */
+static tree
+expand_vector_piecewise (block_stmt_iterator *bsi, elem_op_func f,
+                        tree type, tree inner_type,
+                        tree a, tree b, enum tree_code code)
+{
+  tree head, *chain = &head;
+  tree part_width = TYPE_SIZE (inner_type);
+  tree index = bitsize_int (0);
+  int nunits = TYPE_VECTOR_SUBPARTS (type);
+  int delta = tree_low_cst (part_width, 1)
+             / tree_low_cst (TYPE_SIZE (TREE_TYPE (type)), 1);
+  int i;
+
+  for (i = 0; i < nunits;
+       i += delta, index = int_const_binop (PLUS_EXPR, index, part_width, 0))
+    {
+      tree result = f (bsi, inner_type, a, b, index, part_width, code);
+      *chain = tree_cons (NULL_TREE, result, NULL_TREE);
+      chain = &TREE_CHAIN (*chain);
+    }
+
+  return build1 (CONSTRUCTOR, type, head);
+}
+
+/* Expand a vector operation to scalars with the freedom to use
+   a scalar integer type, or to use a different size for the items
+   in the vector type.  */
+static tree
+expand_vector_parallel (block_stmt_iterator *bsi, elem_op_func f, tree type,
+                       tree a, tree b,
+                       enum tree_code code)
+{
+  tree result, compute_type;
+  enum machine_mode mode;
+  int n_words = tree_low_cst (TYPE_SIZE_UNIT (type), 1) / UNITS_PER_WORD;
+
+  /* We have three strategies.  If the type is already correct, just do
+     the operation an element at a time.  Else, if the vector is wider than
+     one word, do it a word at a time; finally, if the vector is smaller
+     than one word, do it as a scalar.  */
+  if (TYPE_MODE (TREE_TYPE (type)) == word_mode)
+     return expand_vector_piecewise (bsi, f,
+                                    type, TREE_TYPE (type),
+                                    a, b, code);
+  else if (n_words > 1)
+    {
+      tree word_type = build_word_mode_vector_type (n_words);
+      result = expand_vector_piecewise (bsi, f,
+                                       word_type, TREE_TYPE (word_type),
+                                       a, b, code);
+      result = gimplify_val (bsi, word_type, result);
+    }
+  else
+    {
+      /* Use a single scalar operation with a mode no wider than word_mode.  */
+      mode = mode_for_size (tree_low_cst (TYPE_SIZE (type), 1), MODE_INT, 0);
+      compute_type = lang_hooks.types.type_for_mode (mode, 1);
+      result = f (bsi, compute_type, a, b, NULL_TREE, NULL_TREE, code);
+    }
+
+  return build1 (VIEW_CONVERT_EXPR, type, result);
+}
+
+/* Expand a vector operation to scalars; for integer types we can use
+   special bit twiddling tricks to do the sums a word at a time, using
+   function F_PARALLEL instead of F.  These tricks are done only if
+   they can process at least four items, that is, only if the vector
+   holds at least four items and if a word can hold four items.  */
+static tree
+expand_vector_addition (block_stmt_iterator *bsi,
+                       elem_op_func f, elem_op_func f_parallel,
+                       tree type, tree a, tree b, enum tree_code code)
+{
+  int parts_per_word = UNITS_PER_WORD
+                      / tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (type)), 1);
+
+  if (INTEGRAL_TYPE_P (TREE_TYPE (type))
+      && parts_per_word >= 4
+      && TYPE_VECTOR_SUBPARTS (type) >= 4)
+    return expand_vector_parallel (bsi, f_parallel,
+                                  type, a, b, code);
+  else
+    return expand_vector_piecewise (bsi, f,
+                                   type, TREE_TYPE (type),
+                                   a, b, code);
+}
+
+/* Return a type for the widest vector mode whose components are of mode
+   INNER_MODE, or NULL_TREE if none is found.  */
+static tree
+type_for_widest_vector_mode (enum machine_mode inner_mode, optab op)
+{
+  enum machine_mode best_mode = VOIDmode, mode;
+  int best_nunits = 0;
+
+  if (GET_MODE_CLASS (inner_mode) == MODE_FLOAT)
+    mode = MIN_MODE_VECTOR_FLOAT;
+  else
+    mode = MIN_MODE_VECTOR_INT;
+
+  for (; mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode))
+    if (GET_MODE_INNER (mode) == inner_mode
+        && GET_MODE_NUNITS (mode) > best_nunits
+       && op->handlers[mode].insn_code != CODE_FOR_nothing)
+      best_mode = mode, best_nunits = GET_MODE_NUNITS (mode);
+
+  if (best_mode == VOIDmode)
+    return NULL_TREE;
+  else
+    return lang_hooks.types.type_for_mode (best_mode, 1);
+}
+
+/* Process one statement.  If we identify a vector operation, expand it.  */
+
+static void
+expand_vector_operations_1 (block_stmt_iterator *bsi)
+{
+  tree stmt = bsi_stmt (*bsi);
+  tree *p_rhs, rhs, type, compute_type;
+  enum tree_code code;
+  enum machine_mode compute_mode;
+  optab op;
+
+  switch (TREE_CODE (stmt))
+    {
+    case RETURN_EXPR:
+      stmt = TREE_OPERAND (stmt, 0);
+      if (!stmt || TREE_CODE (stmt) != MODIFY_EXPR)
+       return;
+
+      /* FALLTHRU */
+
+    case MODIFY_EXPR:
+      p_rhs = &TREE_OPERAND (stmt, 1);
+      rhs = *p_rhs;
+      break;
+
+    default:
+      return;
+    }
+
+  type = TREE_TYPE (rhs);
+  if (TREE_CODE (type) != VECTOR_TYPE)
+    return;
+
+  code = TREE_CODE (rhs);
+  if (TREE_CODE_CLASS (code) != '1'
+      && TREE_CODE_CLASS (code) != '2')
+    return;
+
+  if (code == NOP_EXPR || code == VIEW_CONVERT_EXPR)
+    return;
+
+  if (code == CONVERT_EXPR)
+    abort ();
+
+  op = optab_for_tree_code (code, type);
+
+  /* Optabs will try converting a negation into a subtraction, so
+     look for it as well.  TODO: negation of floating-point vectors
+     might be turned into an exclusive OR toggling the sign bit.  */
+  if (op == NULL
+      && code == NEGATE_EXPR
+      && INTEGRAL_TYPE_P (TREE_TYPE (type)))
+    op = optab_for_tree_code (MINUS_EXPR, type);
+
+  /* For very wide vectors, try using a smaller vector mode.  */
+  compute_type = type;
+  if (TYPE_MODE (type) == BLKmode && op)
+    {
+      tree vector_compute_type
+        = type_for_widest_vector_mode (TYPE_MODE (TREE_TYPE (type)), op);
+      if (vector_compute_type != NULL_TREE)
+        compute_type = vector_compute_type;
+    }
+
+  compute_mode = TYPE_MODE (compute_type);
+
+  /* If we are breaking a BLKmode vector into smaller pieces,
+     type_for_widest_vector_mode has already looked into the optab,
+     so skip these checks.  */
+  if (compute_type == type)
+    {
+      if ((GET_MODE_CLASS (compute_mode) == MODE_VECTOR_INT
+          || GET_MODE_CLASS (compute_mode) == MODE_VECTOR_FLOAT)
+          && op != NULL
+         && op->handlers[compute_mode].insn_code != CODE_FOR_nothing)
+       return;
+      else
+       {
+         /* There is no operation in hardware, so fall back to scalars.  */
+         compute_type = TREE_TYPE (type);
+         compute_mode = TYPE_MODE (compute_type);
+       }
+    }
+
+  /* If the compute mode is not a vector mode (hence we are decomposing
+     a BLKmode vector to smaller, hardware-supported vectors), we may
+     want to expand the operations in parallel.  */
+  if (GET_MODE_CLASS (compute_mode) != MODE_VECTOR_INT
+      && GET_MODE_CLASS (compute_mode) != MODE_VECTOR_FLOAT)
+    switch (code)
+      {
+      case PLUS_EXPR:
+      case MINUS_EXPR:
+        if (TYPE_TRAP_SIGNED (type))
+         break;
+
+        *p_rhs = expand_vector_addition (bsi, do_binop, do_plus_minus, type,
+                                        TREE_OPERAND (rhs, 0),
+                                        TREE_OPERAND (rhs, 1), code);
+       modify_stmt (bsi_stmt (*bsi));
+        return;
+
+      case NEGATE_EXPR:
+        if (TYPE_TRAP_SIGNED (type))
+         break;
+
+        *p_rhs = expand_vector_addition (bsi, do_unop, do_negate, type,
+                                        TREE_OPERAND (rhs, 0),
+                                        NULL_TREE, code);
+       modify_stmt (bsi_stmt (*bsi));
+        return;
+
+      case BIT_AND_EXPR:
+      case BIT_IOR_EXPR:
+      case BIT_XOR_EXPR:
+        *p_rhs = expand_vector_parallel (bsi, do_binop, type,
+                                        TREE_OPERAND (rhs, 0),
+                                        TREE_OPERAND (rhs, 1), code);
+       modify_stmt (bsi_stmt (*bsi));
+        return;
+
+      case BIT_NOT_EXPR:
+        *p_rhs = expand_vector_parallel (bsi, do_unop, type,
+                                        TREE_OPERAND (rhs, 0),
+                                        NULL_TREE, code);
+       modify_stmt (bsi_stmt (*bsi));
+        return;
+
+      default:
+       break;
+      }
+
+  if (TREE_CODE_CLASS (code) == '1')
+    *p_rhs = expand_vector_piecewise (bsi, do_unop, type, compute_type,
+                                     TREE_OPERAND (rhs, 0),
+                                     NULL_TREE, code);
+  else
+    *p_rhs = expand_vector_piecewise (bsi, do_binop, type, compute_type,
+                                     TREE_OPERAND (rhs, 0),
+                                     TREE_OPERAND (rhs, 1), code);
+
+  modify_stmt (bsi_stmt (*bsi));
+}
+\f
+static void
+expand_vector_operations (void)
+{
+  block_stmt_iterator bsi;
+  basic_block bb;
+
+  FOR_EACH_BB (bb)
+    {
+      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+       expand_vector_operations_1 (&bsi);
+    }
+}
 
 static void
-expand_complex_operations (void)
+tree_lower_operations (void)
 {
   int old_last_basic_block = last_basic_block;
   block_stmt_iterator bsi;
@@ -538,15 +912,19 @@ expand_complex_operations (void)
       if (bb->index >= old_last_basic_block)
        continue;
       for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
-       expand_complex_operations_1 (&bsi);
+       {
+         expand_complex_operations_1 (&bsi);
+         expand_vector_operations_1 (&bsi);
+       }
     }
 }
 
-struct tree_opt_pass pass_lower_complex = 
+
+struct tree_opt_pass pass_lower_vector_ssa = 
 {
-  "complex",                           /* name */
+  "vector",                            /* name */
   NULL,                                        /* gate */
-  expand_complex_operations,           /* execute */
+  expand_vector_operations,            /* execute */
   NULL,                                        /* sub */
   NULL,                                        /* next */
   0,                                   /* static_pass_number */
@@ -555,7 +933,24 @@ struct tree_opt_pass pass_lower_complex =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func | TODO_rename_vars
+  TODO_dump_func | TODO_rename_vars    /* todo_flags_finish */
     | TODO_ggc_collect | TODO_verify_ssa
-    | TODO_verify_stmts | TODO_verify_flow /* todo_flags_finish */
+    | TODO_verify_stmts | TODO_verify_flow
+};
+
+struct tree_opt_pass pass_pre_expand = 
+{
+  "oplower",                           /* name */
+  0,                                   /* gate */
+  tree_lower_operations,               /* execute */
+  NULL,                                        /* sub */
+  NULL,                                        /* next */
+  0,                                   /* static_pass_number */
+  0,                                   /* tv_id */
+  PROP_cfg,                            /* properties_required */
+  0,                                   /* properties_provided */
+  0,                                   /* properties_destroyed */
+  0,                                   /* todo_flags_start */
+  TODO_dump_func | TODO_ggc_collect
+    | TODO_verify_stmts                        /* todo_flags_finish */
 };
index bd8bd4a8ba43f560b62ac7ea4f93b3e938a2c693..4d9a18f10ca248e10b6418bba8df60de1c9a5cf9 100644 (file)
@@ -496,6 +496,13 @@ extern tree tree_block_label (basic_block bb);
 extern void extract_true_false_edges_from_block (basic_block, edge *, edge *);
 extern bool tree_purge_dead_eh_edges (basic_block);
 extern bool tree_purge_all_dead_eh_edges (bitmap);
+extern tree gimplify_val (block_stmt_iterator *, tree, tree);
+extern tree gimplify_build1 (block_stmt_iterator *, enum tree_code,
+                            tree, tree);
+extern tree gimplify_build2 (block_stmt_iterator *, enum tree_code,
+                            tree, tree, tree);
+extern tree gimplify_build3 (block_stmt_iterator *, enum tree_code,
+                            tree, tree, tree, tree);
 
 /* In tree-pretty-print.c.  */
 extern void dump_generic_bb (FILE *, basic_block, int, int);
index 16db5cf815737af0b259718f44291e36bba9d296..e884260d2b3951c52bb66f9c7df7e45d34fa92b1 100644 (file)
@@ -373,7 +373,7 @@ init_tmp_var (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi)
 /* Similarly, but only do so to force EXP to satisfy is_gimple_val.  */
 
 static tree
-gimplify_val (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi)
+tsi_gimplify_val (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi)
 {
   if (is_gimple_val (exp))
     return exp;
@@ -790,7 +790,7 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
               where we only accept variables (and min_invariant, presumably),
               then compute the address into a temporary.  */
            if (save_val_only)
-             *tp = gimplify_val (wi->info, t, &wi->tsi);
+             *tp = tsi_gimplify_val (wi->info, t, &wi->tsi);
          }
       }
       break;
@@ -904,7 +904,7 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data)
            /* If we are in a context where we only accept values, then
               compute the address into a temporary.  */
            if (save_val_only)
-             *tp = gimplify_val (wi->info, t, &wi->tsi);
+             *tp = tsi_gimplify_val (wi->info, t, &wi->tsi);
          }
       }
       break;
@@ -1041,7 +1041,7 @@ convert_nl_goto_reference (tree *tp, int *walk_subtrees, void *data)
   field = get_nl_goto_field (i);
   x = get_frame_field (info, target_context, field, &wi->tsi);
   x = build_addr (x);
-  x = gimplify_val (info, x, &wi->tsi);
+  x = tsi_gimplify_val (info, x, &wi->tsi);
   arg = tree_cons (NULL, x, NULL);
   x = build_addr (new_label);
   arg = tree_cons (NULL, x, arg);
@@ -1139,7 +1139,7 @@ convert_tramp_reference (tree *tp, int *walk_subtrees, void *data)
       /* Compute the address of the field holding the trampoline.  */
       x = get_frame_field (info, target_context, x, &wi->tsi);
       x = build_addr (x);
-      x = gimplify_val (info, x, &wi->tsi);
+      x = tsi_gimplify_val (info, x, &wi->tsi);
       arg = tree_cons (NULL, x, NULL);
 
       /* Do machine-specific ugliness.  Normally this will involve
index bd4bb0d1885ed72593386f405b61bf10edafaa09..f2d98af7309e3ebc8d493a23fbb4fb1b9c7b6534 100644 (file)
@@ -299,6 +299,7 @@ init_tree_optimization_passes (void)
   NEXT_PASS (pass_lower_cf);
   NEXT_PASS (pass_lower_eh);
   NEXT_PASS (pass_build_cfg);
+  NEXT_PASS (pass_pre_expand);
   NEXT_PASS (pass_tree_profile);
   NEXT_PASS (pass_init_datastructures);
   NEXT_PASS (pass_all_optimizations);
@@ -325,7 +326,6 @@ init_tree_optimization_passes (void)
   NEXT_PASS (pass_tail_recursion);
   NEXT_PASS (pass_ch);
   NEXT_PASS (pass_profile);
-  NEXT_PASS (pass_lower_complex);
   NEXT_PASS (pass_sra);
   NEXT_PASS (DUP_PASS (pass_rename_ssa_copies));
   NEXT_PASS (DUP_PASS (pass_dominator));
index 93129100cefa69f101cbfd68ba247f09ef7bb0dd..1edff2df24eb09a4c2fb9d5d14d752b28c75a712 100644 (file)
@@ -120,7 +120,8 @@ extern struct tree_opt_pass pass_may_alias;
 extern struct tree_opt_pass pass_split_crit_edges;
 extern struct tree_opt_pass pass_pre;
 extern struct tree_opt_pass pass_profile;
-extern struct tree_opt_pass pass_lower_complex;
+extern struct tree_opt_pass pass_pre_expand;
+extern struct tree_opt_pass pass_lower_vector_ssa;
 extern struct tree_opt_pass pass_fold_builtins;
 extern struct tree_opt_pass pass_early_warn_uninitialized;
 extern struct tree_opt_pass pass_late_warn_uninitialized;
index 9122df5437f83384525b8df0199668e72e39f732..4ed3b6714a10f2e7906e20560e02d7282cb288ac 100644 (file)
@@ -111,7 +111,7 @@ static void set_type_quals (tree, int);
 static int type_hash_eq (const void *, const void *);
 static hashval_t type_hash_hash (const void *);
 static void print_type_hash_statistics (void);
-static void finish_vector_type (tree);
+static tree make_vector_type (tree, int, enum machine_mode);
 static int type_hash_marked_p (const void *);
 static unsigned int type_hash_list (tree, hashval_t);
 static unsigned int attribute_hash_list (tree, hashval_t);
@@ -5279,18 +5279,23 @@ tree_operand_check_failed (int idx, enum tree_code code, const char *file,
 }
 #endif /* ENABLE_TREE_CHECKING */
 \f
-/* For a new vector type node T, build the information necessary for
-   debugging output.  */
+/* Create a new vector type node holding SUBPARTS units of type INNERTYPE,
+   and mapped to the machine mode MODE.  Initialize its fields and build
+   the information necessary for debugging output.  */
 
-static void
-finish_vector_type (tree t)
+static tree
+make_vector_type (tree innertype, int nunits, enum machine_mode mode)
 {
+  tree t = make_node (VECTOR_TYPE);
+
+  TREE_TYPE (t) = innertype;
+  TYPE_VECTOR_SUBPARTS (t) = nunits;
+  TYPE_MODE (t) = mode;
   layout_type (t);
 
   {
-    tree index = build_int_2 (TYPE_VECTOR_SUBPARTS (t) - 1, 0);
-    tree array = build_array_type (TREE_TYPE (t),
-                                  build_index_type (index));
+    tree index = build_int_2 (nunits - 1, 0);
+    tree array = build_array_type (innertype, build_index_type (index));
     tree rt = make_node (RECORD_TYPE);
 
     TYPE_FIELDS (rt) = build_decl (FIELD_DECL, get_identifier ("f"), array);
@@ -5303,6 +5308,8 @@ finish_vector_type (tree t)
        numbers equal.  */
     TYPE_UID (rt) = TYPE_UID (t);
   }
+
+  return t;
 }
 
 static tree
@@ -5521,36 +5528,39 @@ reconstruct_complex_type (tree type, tree bottom)
   return outer;
 }
 
-/* Returns a vector tree node given a vector mode and inner type.  */
+/* Returns a vector tree node given a mode (integer, vector, or BLKmode) and
+   the inner type.  */
 tree
 build_vector_type_for_mode (tree innertype, enum machine_mode mode)
 {
-  tree t;
-  t = make_node (VECTOR_TYPE);
-  TREE_TYPE (t) = innertype;
-  TYPE_MODE (t) = mode;
-  finish_vector_type (t);
-  return t;
-}
+  int nunits;
 
-/* Similarly, but takes inner type and units.  */
+  if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
+      || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
+    nunits = GET_MODE_NUNITS (mode);
 
-tree
-build_vector_type (tree innertype, int nunits)
-{
-  enum machine_mode innermode = TYPE_MODE (innertype);
-  enum machine_mode mode;
+  else if (GET_MODE_CLASS (mode) == MODE_INT)
+    {
+      /* Check that there are no leftover bits.  */
+      if (GET_MODE_BITSIZE (mode) % TREE_INT_CST_LOW (TYPE_SIZE (innertype)))
+       abort ();
 
-  if (GET_MODE_CLASS (innermode) == MODE_FLOAT)
-    mode = MIN_MODE_VECTOR_FLOAT;
+      nunits = GET_MODE_BITSIZE (mode)
+              / TREE_INT_CST_LOW (TYPE_SIZE (innertype));
+    }
   else
-    mode = MIN_MODE_VECTOR_INT;
+    abort ();
 
-  for (; mode != VOIDmode ; mode = GET_MODE_WIDER_MODE (mode))
-    if (GET_MODE_NUNITS (mode) == nunits && GET_MODE_INNER (mode) == innermode)
-      return build_vector_type_for_mode (innertype, mode);
+  return make_vector_type (innertype, nunits, mode);
+}
 
-  return NULL_TREE;
+/* Similarly, but takes the inner type and number of units, which must be
+   a power of two.  */
+
+tree
+build_vector_type (tree innertype, int nunits)
+{
+  return make_vector_type (innertype, nunits, VOIDmode);
 }
 
 /* Given an initializer INIT, return TRUE if INIT is zero or some
index 65fd479cdb423400caa5711adbceafd401765913..80e42e0f86260f9cacab79ab1da7144487dc4396 100644 (file)
@@ -151,7 +151,8 @@ DEFTREECODE (REAL_TYPE, "real_type", 't', 0)
 DEFTREECODE (COMPLEX_TYPE, "complex_type", 't', 0)
 
 /* Vector types.  The TREE_TYPE field is the data type of the vector
-   elements.  */
+   elements.  The TYPE_PRECISION field is the number of subparts of
+   the vector.  */
 DEFTREECODE (VECTOR_TYPE, "vector_type", 't', 0)
 
 /* C enums.  The type node looks just like an INTEGER_TYPE node.
index ff5d5eaa72a009d41d51da81b770c2b2c4e13d89..41d967c3465678b8dddadf29e708b89a6a06cddf 100644 (file)
@@ -1516,7 +1516,7 @@ struct tree_block GTY(())
 
 /* For a VECTOR_TYPE, this is the number of sub-parts of the vector.  */
 #define TYPE_VECTOR_SUBPARTS(VECTOR_TYPE) \
-  GET_MODE_NUNITS (VECTOR_TYPE_CHECK (VECTOR_TYPE)->type.mode)
+  (VECTOR_TYPE_CHECK (VECTOR_TYPE)->type.precision)
 
 /* Indicates that objects of this type must be initialized by calling a
    function when they are created.  */
@@ -3480,7 +3480,6 @@ extern void expand_function_start (tree);
 extern void expand_pending_sizes (tree);
 extern void recompute_tree_invarant_for_addr_expr (tree);
 extern bool needs_to_live_in_memory (tree);
-extern tree make_vector (enum machine_mode, tree, int);
 extern tree reconstruct_complex_type (tree, tree);
 
 extern int real_onep (tree);