This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFC/RFT] Tree-level lowering of generic vectors (take 2)


Paolo Bonzini wrote:

This updated patch fixes the issues that were found during review, and fixes several bugs dealing with vector types that have no corresponding vector mode. In particular, there were several such assumptions in the expander and in the C front-end.

In addition, this adds support for breaking a big vector into smaller hardware-supported vectors (e.g. V16QI into two V8QI elements). This needed an extension to CONSTRUCTORs for VECTOR_TYPEs, whereby an element that is itself a N-sized vector counts as N separate elements: so a V4SF can be initialized with a CONSTRUCTOR (v1, v2) where v1 and V2 are V2SF.

To simplify the latter change, I split the cases for ARRAY_TYPE and VECTOR_TYPE in store_constructor.

Again, bootstrapped/regtested on i686-pc-linux-gnu but could benefit from wider testing.

And here's the patch.


Paolo
2004-07-19  Paolo Bonzini  <bonzini@gnu.org>

	* Makefile.in (tree_complex.o): Update dependencies.
	(tree.o): Depend on regs.h.
	* c-common.c (handle_vector_size_attribute): Update for
	vector types without corresponding vector modes.
	(vector_types_convertible_p): Likewise
	* c-typeck.c (build_binary_op): Do not use RDIV_EXPR for
	integer vectors.
	* convert.c (convert_to_integer): Use vector types' TYPE_SIZE.
	(convert_to_vector): Likewise.
	* expr.c (store_constructor): Split ARRAY_TYPE and VECTOR_TYPE.
	Allow a VECTOR_TYPE initializer to be made of several vectors.
	For ARRAY_TYPEs and VECTOR_TYPES, simplify a bit the handling
	of cleared and need_to_clear, and use fold_convert.
	(expand_expr): Treat VECTOR_CST's like CONSTRUCTORS if
	a corresponding vector mode is not available.
	* fold-const.c (fold_convert): Likewise.
	* 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.
	* tree-complex.c (build_word_mode_vector_type, tree_vec_extract,
	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 t->type.maxval field.
	(TYPE_VECTOR_SUBPARTS_TREE): New.
	(make_vector): Remove declaration.
	* varasm.c (output_constant): Update for
	vector types without corresponding vector modes.

	* machmode.def: Remove vector modes.
	* config/alpha/alpha-modes.def: Add required vector modes.
	* config/arm/arm-modes.def: Likewise.
	* config/frv/frv-modes.def: Likewise.
	* config/i386/i386-modes.def: Likewise.
	* config/rs6000/rs6000-modes.def: Likewise.
	* config/sh/sh-modes.def: Likewise.

cp/ChangeLog:
2004-07-15  Paolo Bonzini  <bonzini@gnu.org>

	* typeck.c (build_binary_op): Do not use RDIV_EXPR for
	integer vectors.

Index: gcc/Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.1329
diff -u -p -r1.1329 Makefile.in
--- gcc/Makefile.in	18 Jul 2004 15:29:08 -0000	1.1329
+++ gcc/Makefile.in	19 Jul 2004 14:12:41 -0000
@@ -1572,7 +1572,7 @@ langhooks.o : langhooks.c $(CONFIG_H) $(
    $(LANGHOOKS_DEF_H) $(FLAGS_H) $(GGC_H) diagnostic.h
 tree.o : tree.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(FLAGS_H) function.h \
    toplev.h $(GGC_H) $(HASHTAB_H) $(TARGET_H) output.h $(TM_P_H) langhooks.h \
-   real.h gt-tree.h tree-iterator.h $(BASIC_BLOCK_H) $(TREE_FLOW_H)
+   real.h gt-tree.h tree-iterator.h $(BASIC_BLOCK_H) $(TREE_FLOW_H) $(REGS_H)
 tree-dump.o: tree-dump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
    $(C_TREE_H) $(FLAGS_H) langhooks.h toplev.h output.h c-pragma.h $(RTL_H) \
    $(GGC_H) $(EXPR_H) $(SPLAY_TREE_H) $(TREE_DUMP_H) tree-iterator.h
@@ -1922,7 +1922,8 @@ tree-sra.o : tree-sra.c $(CONFIG_H) syst
     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: gcc/c-common.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.c,v
retrieving revision 1.531
diff -u -p -r1.531 c-common.c
--- gcc/c-common.c	18 Jul 2004 23:57:27 -0000	1.531
+++ gcc/c-common.c	19 Jul 2004 14:12:42 -0000
@@ -963,7 +963,9 @@ vector_types_convertible_p (tree t1, tre
 {
   return targetm.vector_opaque_p (t1)
 	 || targetm.vector_opaque_p (t2)
-	 || TYPE_MODE (t1) == TYPE_MODE (t2);
+         || (tree_int_cst_equal (TYPE_SIZE (t1), TYPE_SIZE (t2))
+	     && INTEGRAL_TYPE_P (TREE_TYPE (t1))
+		== INTEGRAL_TYPE_P (TREE_TYPE (t2)));
 }
 
 /* Convert EXPR to TYPE, warning about conversion problems with constants.
@@ -4704,7 +4706,7 @@ handle_vector_size_attribute (tree *node
 			      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;
@@ -4753,28 +4755,13 @@ handle_vector_size_attribute (tree *node
 
   /* 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: gcc/c-typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-typeck.c,v
retrieving revision 1.340
diff -u -p -r1.340 c-typeck.c
--- gcc/c-typeck.c	17 Jul 2004 09:20:45 -0000	1.340
+++ gcc/c-typeck.c	19 Jul 2004 14:12:43 -0000
@@ -6941,6 +6941,11 @@ build_binary_op (enum tree_code code, tr
 	  && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
 	      || code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE))
 	{
+	  if (code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE)
+	    code0 = TREE_CODE (TREE_TYPE (TREE_TYPE (op0)));
+	  if (code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE)
+	    code1 = TREE_CODE (TREE_TYPE (TREE_TYPE (op1)));
+
 	  if (!(code0 == INTEGER_TYPE && code1 == INTEGER_TYPE))
 	    resultcode = RDIV_EXPR;
 	  else
Index: gcc/convert.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/convert.c,v
retrieving revision 1.47
diff -u -p -r1.47 convert.c
--- gcc/convert.c	23 Jun 2004 20:42:45 -0000	1.47
+++ gcc/convert.c	19 Jul 2004 14:12:47 -0000
@@ -677,8 +677,7 @@ convert_to_integer (tree type, tree expr
 				    TREE_TYPE (TREE_TYPE (expr)), expr)));
 
     case VECTOR_TYPE:
-      if (GET_MODE_SIZE (TYPE_MODE (type))
-	  != GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr))))
+      if (!tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (TREE_TYPE (expr))))
 	{
 	  error ("can't convert between vector values of different size");
 	  return error_mark_node;
@@ -755,8 +754,7 @@ convert_to_vector (tree type, tree expr)
     {
     case INTEGER_TYPE:
     case VECTOR_TYPE:
-      if (GET_MODE_SIZE (TYPE_MODE (type))
-	  != GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr))))
+      if (!tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (TREE_TYPE (expr))))
 	{
 	  error ("can't convert between vector values of different size");
 	  return error_mark_node;
Index: gcc/expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.685
diff -u -p -r1.685 expr.c
--- gcc/expr.c	17 Jul 2004 00:31:06 -0000	1.685
+++ gcc/expr.c	19 Jul 2004 14:12:48 -0000
@@ -4554,8 +4554,8 @@ store_constructor (tree exp, rtx target,
 				   get_alias_set (TREE_TYPE (field)));
 	}
     }
-  else if (TREE_CODE (type) == ARRAY_TYPE
-	   || TREE_CODE (type) == VECTOR_TYPE)
+
+  else if (TREE_CODE (type) == ARRAY_TYPE)
     {
       tree elt;
       int i;
@@ -4565,39 +4565,8 @@ store_constructor (tree exp, rtx target,
       int const_bounds_p;
       HOST_WIDE_INT minelt = 0;
       HOST_WIDE_INT maxelt = 0;
-      int icode = 0;
-      rtx *vector = NULL;
-      int elt_size = 0;
-      unsigned n_elts = 0;
-
-      if (TREE_CODE (type) == ARRAY_TYPE)
-	domain = TYPE_DOMAIN (type);
-      else
-	/* Vectors do not have domains; look up the domain of
-	   the array embedded in the debug representation type.
-	   FIXME Would probably be more efficient to treat vectors
-	   separately from arrays.  */
-	{
-	  domain = TYPE_DEBUG_REPRESENTATION_TYPE (type);
-	  domain = TYPE_DOMAIN (TREE_TYPE (TYPE_FIELDS (domain)));
-	  if (REG_P (target) && VECTOR_MODE_P (GET_MODE (target)))
-	    {
-	      enum machine_mode mode = GET_MODE (target);
-
-	      icode = (int) vec_init_optab->handlers[mode].insn_code;
-	      if (icode != CODE_FOR_nothing)
-		{
-		  unsigned int i;
-
-		  elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
-		  n_elts = (GET_MODE_SIZE (mode) / elt_size);
-		  vector = alloca (n_elts);
-		  for (i = 0; i < n_elts; i++)
-		    vector [i] = CONST0_RTX (GET_MODE_INNER (mode));
-		}
-	    }
-	}
 
+      domain = TYPE_DOMAIN (type);
       const_bounds_p = (TYPE_MIN_VALUE (domain)
 			&& TYPE_MAX_VALUE (domain)
 			&& host_integerp (TYPE_MIN_VALUE (domain), 0)
@@ -4613,7 +4582,9 @@ store_constructor (tree exp, rtx target,
       /* If the constructor has fewer elements than the array,
          clear the whole array first.  Similarly if this is
          static constructor of a non-BLKmode object.  */
-      if (cleared || (REG_P (target) && TREE_STATIC (exp)))
+      if (cleared)
+	need_to_clear = 0;
+      else if (REG_P (target) && TREE_STATIC (exp))
 	need_to_clear = 1;
       else
 	{
@@ -4660,18 +4631,16 @@ store_constructor (tree exp, rtx target,
 	    need_to_clear = 1;
 	}
 
-      if (need_to_clear && size > 0 && !vector)
+      if (need_to_clear && size > 0)
 	{
-	  if (! cleared)
-	    {
-	      if (REG_P (target))
-		emit_move_insn (target,  CONST0_RTX (GET_MODE (target)));
-	      else
-		clear_storage (target, GEN_INT (size));
-	    }
+	  if (REG_P (target))
+	    emit_move_insn (target,  CONST0_RTX (GET_MODE (target)));
+	  else
+	    clear_storage (target, GEN_INT (size));
 	  cleared = 1;
 	}
-      else if (REG_P (target))
+
+      if (!cleared && REG_P (target))
 	/* Inform later passes that the old value is dead.  */
 	emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
 
@@ -4710,9 +4679,6 @@ store_constructor (tree exp, rtx target,
 	      HOST_WIDE_INT lo, hi, count;
 	      tree position;
 
-	      if (vector)
-		abort ();
-
 	      /* If the range is constant and "small", unroll the loop.  */
 	      if (const_bounds_p
 		  && host_integerp (lo_index, 0)
@@ -4807,16 +4773,13 @@ store_constructor (tree exp, rtx target,
 	    {
 	      tree position;
 
-	      if (vector)
-		abort ();
-
 	      if (index == 0)
 		index = ssize_int (1);
 
 	      if (minelt)
-		index = convert (ssizetype,
-				 fold (build (MINUS_EXPR, index,
-					      TYPE_MIN_VALUE (domain))));
+		index = fold_convert (ssizetype,
+				      fold (build (MINUS_EXPR, index,
+						   TYPE_MIN_VALUE (domain))));
 
 	      position = size_binop (MULT_EXPR, index,
 				     convert (ssizetype,
@@ -4827,16 +4790,6 @@ store_constructor (tree exp, rtx target,
 	      xtarget = adjust_address (xtarget, mode, 0);
 	      store_expr (value, xtarget, 0);
 	    }
-	  else if (vector)
-	    {
-	      int pos;
-
-	      if (index != 0)
-		pos = tree_low_cst (index, 0) - minelt;
-	      else
-		pos = i;
-	      vector[pos] = expand_expr (value, NULL_RTX, VOIDmode, 0);
-	    }
 	  else
 	    {
 	      if (index != 0)
@@ -4856,12 +4809,128 @@ store_constructor (tree exp, rtx target,
 				       type, cleared, get_alias_set (elttype));
 	    }
 	}
-      if (vector)
+    }
+
+  else if (TREE_CODE (type) == VECTOR_TYPE)
+    {
+      tree elt;
+      int i;
+      int need_to_clear;
+      int icode = 0;
+      tree elttype = TREE_TYPE (type);
+      int elt_size = tree_low_cst (TYPE_SIZE (elttype), 1);
+      enum machine_mode mode = TYPE_MODE (elttype);
+      HOST_WIDE_INT bitsize;
+      HOST_WIDE_INT bitpos;
+      rtx *vector = NULL;
+      unsigned n_elts;
+
+      if (mode == BLKmode)
+	abort ();
+
+      n_elts = TYPE_VECTOR_SUBPARTS (type);
+      if (REG_P (target) && VECTOR_MODE_P (GET_MODE (target)))
 	{
-	  emit_insn (GEN_FCN (icode) (target,
-				      gen_rtx_PARALLEL (GET_MODE (target),
-						        gen_rtvec_v (n_elts, vector))));
+	  enum machine_mode mode = GET_MODE (target);
+	  
+	  icode = (int) vec_init_optab->handlers[mode].insn_code;
+	  if (icode != CODE_FOR_nothing)
+	    {
+	      unsigned int i;
+	      
+	      vector = alloca (n_elts);
+	      for (i = 0; i < n_elts; i++)
+		vector [i] = CONST0_RTX (GET_MODE_INNER (mode));
+	    }
 	}
+
+      /* If the constructor has fewer elements than the vector,
+         clear the whole array first.  Similarly if this is
+         static constructor of a non-BLKmode object.  */
+      if (cleared)
+	need_to_clear = 0;
+      else if (REG_P (target) && TREE_STATIC (exp))
+	need_to_clear = 1;
+      else
+	{
+	  unsigned HOST_WIDE_INT count = 0, zero_count = 0;
+
+	  for (elt = CONSTRUCTOR_ELTS (exp);
+	       elt != NULL_TREE;
+	       elt = TREE_CHAIN (elt))
+	    {
+	      int n_elts_here =
+		tree_low_cst (
+		  int_const_binop (TRUNC_DIV_EXPR,
+				   TYPE_SIZE (TREE_TYPE (TREE_VALUE (elt))),
+				   TYPE_SIZE (elttype), 0), 1);
+
+	      count += n_elts_here;
+	      if (mostly_zeros_p (TREE_VALUE (elt)))
+	        zero_count += n_elts_here;
+	    }
+
+	  /* Clear the entire vector first if there are any missing elements,
+	     or if the incidence of zero elements is >= 75%.  */
+	  need_to_clear = (count < n_elts || 4 * zero_count >= 3 * count);
+	}
+
+      if (need_to_clear && size > 0 && !vector)
+	{
+	  if (REG_P (target))
+	    emit_move_insn (target,  CONST0_RTX (GET_MODE (target)));
+	  else
+	    clear_storage (target, GEN_INT (size));
+	  cleared = 1;
+	}
+
+      if (!cleared && REG_P (target))
+	/* Inform later passes that the old value is dead.  */
+	emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
+
+      /* Store each element of the constructor into the corresponding
+	 element of TARGET, determined by counting the elements.  */
+      for (elt = CONSTRUCTOR_ELTS (exp), i = 0;
+	   elt;
+	   elt = TREE_CHAIN (elt), i += bitsize / elt_size)
+	{
+	  tree value = TREE_VALUE (elt);
+	  tree index = TREE_PURPOSE (elt);
+	  HOST_WIDE_INT eltpos;
+
+	  bitsize = tree_low_cst (TYPE_SIZE (TREE_TYPE (value)), 1);
+	  if (cleared && initializer_zerop (value))
+	    continue;
+
+	  if (index != 0)
+	    eltpos = tree_low_cst (index, 1);
+	  else
+	    eltpos = i;
+
+	  if (vector)
+	    {
+	      /* Vector CONSTRUCTORs should only be built from smaller
+		 vectors in the case of BLKmode vectors.  */
+	      if (TREE_CODE (TREE_TYPE (value)) == VECTOR_TYPE)
+		abort ();
+	      vector[eltpos] = expand_expr (value, NULL_RTX, VOIDmode, 0);
+	    }
+	  else
+	    {
+	      enum machine_mode value_mode =
+		TREE_CODE (TREE_TYPE (value)) == VECTOR_TYPE
+		  ? TYPE_MODE (TREE_TYPE (value))
+		  : mode;
+	      bitpos = eltpos * elt_size;
+	      store_constructor_field (target, bitsize, bitpos, value_mode, value,
+				       type, cleared, get_alias_set (elttype));
+	    }
+	}
+
+      if (vector)
+	emit_insn (GEN_FCN (icode) (target,
+				    gen_rtx_PARALLEL (GET_MODE (target),
+						      gen_rtvec_v (n_elts, vector))));
     }
 
   /* Set constructor assignments.  */
@@ -6430,7 +6499,13 @@ expand_expr_real_1 (tree exp, rtx target
       return temp;
 
     case VECTOR_CST:
-      return const_vector_from_tree (exp);
+      if (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (exp))) == MODE_VECTOR_INT
+	  || GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (exp))) == MODE_VECTOR_FLOAT)
+	return const_vector_from_tree (exp);
+      else 
+	return expand_expr (build1 (CONSTRUCTOR, TREE_TYPE (exp),
+				    TREE_VECTOR_CST_ELTS (exp)),
+			    ignore ? const0_rtx : target, tmode, modifier);
 
     case CONST_DECL:
       return expand_expr (DECL_INITIAL (exp), target, VOIDmode, modifier);
Index: gcc/fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.424
diff -u -p -r1.424 fold-const.c
--- gcc/fold-const.c	11 Jul 2004 21:56:37 -0000	1.424
+++ gcc/fold-const.c	19 Jul 2004 14:12:49 -0000
@@ -1930,8 +1930,7 @@ fold_convert (tree type, tree arg)
 	  return fold_convert (type, tem);
 	}
       if (TREE_CODE (orig) == VECTOR_TYPE
-	  && GET_MODE_SIZE (TYPE_MODE (type))
-	     == GET_MODE_SIZE (TYPE_MODE (orig)))
+	  && tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (orig)))
 	return fold (build1 (NOP_EXPR, type, arg));
     }
   else if (TREE_CODE (type) == REAL_TYPE)
@@ -1990,12 +1989,10 @@ fold_convert (tree type, tree arg)
   else if (TREE_CODE (type) == VECTOR_TYPE)
     {
       if ((INTEGRAL_TYPE_P (orig) || POINTER_TYPE_P (orig))
-	  && GET_MODE_SIZE (TYPE_MODE (type))
-	     == GET_MODE_SIZE (TYPE_MODE (orig)))
+	  && tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (orig)))
 	return fold (build1 (NOP_EXPR, type, arg));
       if (TREE_CODE (orig) == VECTOR_TYPE
-	  && GET_MODE_SIZE (TYPE_MODE (type))
-	     == GET_MODE_SIZE (TYPE_MODE (orig)))
+	  && tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (orig)))
 	return fold (build1 (NOP_EXPR, type, arg));
     }
   else if (VOID_TYPE_P (type))
Index: gcc/machmode.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/machmode.def,v
retrieving revision 1.27
diff -u -p -r1.27 machmode.def
--- gcc/machmode.def	6 Nov 2003 08:38:50 -0000	1.27
+++ gcc/machmode.def	19 Jul 2004 14:12:49 -0000
@@ -186,36 +186,6 @@ CC_MODE (CC);
 COMPLEX_MODES (INT);
 COMPLEX_MODES (FLOAT);
 
-/* Vector modes.  */
-VECTOR_MODES (INT, 2);        /*                 V2QI */
-VECTOR_MODES (INT, 4);        /*            V4QI V2HI */
-VECTOR_MODES (INT, 8);        /*       V8QI V4HI V2SI */
-VECTOR_MODES (INT, 16);       /* V16QI V8HI V4SI V2DI */
-/* VECTOR_MODES (INT, 32);             V8SI V4DI      */
-/* VECTOR_MODES (INT, 64);             V8DI           */
-
-VECTOR_MODE (INT, SI, 8)
-VECTOR_MODE (INT, DI, 4);
-VECTOR_MODE (INT, DI, 8);
-
-/* PPC uses this to distinguish between DImode passed in
-   float registers and DImode passed in vector registers.
-   It would be in rs6000-modes.def but it's referenced in
-   c-common.c.  FIXME.  */
-
-VECTOR_MODE (INT, DI, 1);
-
-VECTOR_MODES (FLOAT, 4);      /*                 V2HF */
-VECTOR_MODES (FLOAT, 8);      /*            V4HF V2SF */
-VECTOR_MODES (FLOAT, 16);     /*       V8HF V4SF V2DF */
-/* VECTOR_MODES (FLOAT, 32);           V8SF V4DF      */
-/* VECTOR_MODES (FLOAT, 64);     V16SF V8DF           */
-
-VECTOR_MODE (FLOAT, SF, 8);
-VECTOR_MODE (FLOAT, SF, 16);
-VECTOR_MODE (FLOAT, DF, 4);
-VECTOR_MODE (FLOAT, DF, 8);
-
 /* The symbol Pmode stands for one of the above machine modes (usually SImode).
    The tm.h file specifies which one.  It is not a distinct mode.  */
 
Index: gcc/optabs.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/optabs.c,v
retrieving revision 1.230
diff -u -p -r1.230 optabs.c
--- gcc/optabs.c	14 Jul 2004 07:30:19 -0000	1.230
+++ gcc/optabs.c	19 Jul 2004 14:12:50 -0000
@@ -628,6 +628,89 @@ expand_cmplxdiv_wide (rtx real0, rtx rea
   return 1;
 }
 
+/* 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;
+    }
+}
+
+
 /* Wrapper around expand_binop which takes an rtx code to specify
    the operation to perform, not an optab pointer.  All other
    arguments are the same.  */
Index: gcc/optabs.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/optabs.h,v
retrieving revision 1.30
diff -u -p -r1.30 optabs.h
--- gcc/optabs.h	7 Jul 2004 19:24:00 -0000	1.30
+++ gcc/optabs.h	19 Jul 2004 14:12:50 -0000
@@ -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: gcc/print-tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/print-tree.c,v
retrieving revision 1.91
diff -u -p -r1.91 print-tree.c
--- gcc/print-tree.c	15 Jul 2004 07:33:01 -0000	1.91
+++ gcc/print-tree.c	19 Jul 2004 14:12:51 -0000
@@ -537,6 +537,8 @@ print_node (FILE *file, const char *pref
 	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: gcc/regclass.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/regclass.c,v
retrieving revision 1.190
diff -u -p -r1.190 regclass.c
--- gcc/regclass.c	9 Jul 2004 03:29:34 -0000	1.190
+++ gcc/regclass.c	19 Jul 2004 14:12:51 -0000
@@ -191,6 +191,10 @@ const char * reg_names[] = REGISTER_NAME
 
 enum machine_mode reg_raw_mode[FIRST_PSEUDO_REGISTER];
 
+/* 1 if there is a register of given mode.  */
+
+char 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: gcc/regs.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/regs.h,v
retrieving revision 1.34
diff -u -p -r1.34 regs.h
--- gcc/regs.h	13 May 2004 06:39:45 -0000	1.34
+++ gcc/regs.h	19 Jul 2004 14:12:51 -0000
@@ -163,6 +163,10 @@ extern char regs_ever_live[FIRST_PSEUDO_
 
 extern char regs_asm_clobbered[FIRST_PSEUDO_REGISTER];
 
+/* Vector indexed by machine mode saying whether there are regs of that mode.  */
+
+extern char 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: gcc/tree-complex.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-complex.c,v
retrieving revision 2.5
diff -u -p -r2.5 tree-complex.c
--- gcc/tree-complex.c	9 Jun 2004 15:07:01 -0000	2.5
+++ gcc/tree-complex.c	19 Jul 2004 14:12:52 -0000
@@ -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 - S
 #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"
@@ -517,17 +474,423 @@ expand_complex_operations_1 (block_stmt_
       abort ();
     }
 }
+
+/* Build a constant of type TYPE, made of VALUE's bits replicated
+   to fit TYPE's size.  */
+static tree
+build_replicated_const (tree type, tree inner_type, HOST_WIDE_INT value)
+{
+  int width = TYPE_PRECISION (inner_type);
+  int n = HOST_BITS_PER_WIDE_INT / width;
+  unsigned HOST_WIDE_INT low, high, mask;
+  tree ret;
+
+  if (n == 0)
+    abort ();
+
+  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;
+  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)
+{
+  /* All powers of two <= 32 give a different result modulo 37.  */
+  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));
+  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 == NEGATE_EXPR ? MINUS_EXPR : code, 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 (compute_type == type)
+    {
+      if ((GET_MODE_CLASS (compute_mode) == MODE_VECTOR_INT
+	   || GET_MODE_CLASS (compute_mode) == MODE_VECTOR_FLOAT)
+	  && op
+	  && op->handlers[compute_mode].insn_code != CODE_FOR_nothing)
+	{
+	  /* If there is an handler in the optab, we have nothing to do
+	     unless we are breaking a BLKmode vector into smaller pieces.  */
+	  if (compute_type == type)
+	    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));
+}
+
+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 +901,28 @@ 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);
+
+	  /* When not optimizing, only lower complex arithmetic.  This is so
+	     that the loop optimizers do not waste time on lowered vectors,
+	     and more importantly they can create generic vector code.
+
+	     Since optimizations are not run if there are errors, also
+	     lower vectors if there are errors, otherwise the expander might
+	     crash.  */
+	  if (!optimize || errorcount || sorrycount)
+	    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 +931,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: gcc/tree-nested.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-nested.c,v
retrieving revision 2.9
diff -u -p -r2.31 tree-optimize.c
--- gcc/tree-optimize.c	17 Jul 2004 00:31:10 -0000	2.31
+++ gcc/tree-optimize.c	19 Jul 2004 14:12:53 -0000
@@ -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));
@@ -343,6 +343,7 @@ init_tree_optimization_passes (void)
   NEXT_PASS (pass_loop);
   NEXT_PASS (DUP_PASS (pass_dominator));
   NEXT_PASS (DUP_PASS (pass_redundant_phi));
+  NEXT_PASS (pass_lower_vector_ssa);
   NEXT_PASS (pass_cd_dce);
   NEXT_PASS (DUP_PASS (pass_dse));
   NEXT_PASS (DUP_PASS (pass_forwprop));
Index: gcc/tree-pass.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-pass.h,v
retrieving revision 2.5
diff -u -p -r2.5 tree-pass.h
--- gcc/tree-pass.h	10 Jul 2004 04:57:54 -0000	2.5
+++ gcc/tree-pass.h	19 Jul 2004 14:12:53 -0000
@@ -120,7 +120,8 @@ extern struct tree_opt_pass pass_may_ali
 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: gcc/tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.c,v
retrieving revision 1.397
diff -u -p -r1.397 tree.c
--- gcc/tree.c	15 Jul 2004 00:02:29 -0000	1.397
+++ gcc/tree.c	19 Jul 2004 14:12:54 -0000
@@ -48,6 +48,7 @@ Software Foundation, 59 Temple Place - S
 #include "tree-iterator.h"
 #include "basic-block.h"
 #include "tree-flow.h"
+#include "regs.h"
 
 /* obstack.[ch] explicitly declined to prototype this.  */
 extern int _obstack_allocated_p (struct obstack *h, void *obj);
@@ -114,7 +115,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);
@@ -5306,18 +5307,29 @@ tree_operand_check_failed (int idx, enum
 }
 #endif /* ENABLE_TREE_CHECKING */
 
-/* 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)
 {
-  layout_type (t);
+  tree t = make_node (VECTOR_TYPE);
+  tree nunits_tree = build_int_2 (nunits, 0);
+
+  TREE_TYPE (t) = innertype;
+  TYPE_VECTOR_SUBPARTS (t) = nunits;
+  TYPE_MODE (t) = mode;
+  TYPE_UNSIGNED (t) = TYPE_UNSIGNED (innertype);
+  TYPE_SIZE_UNIT (t) = int_const_binop (MULT_EXPR, TYPE_SIZE_UNIT (innertype),
+					nunits_tree, 0);
+  TYPE_SIZE (t) = int_const_binop (MULT_EXPR, TYPE_SIZE (innertype),
+				   nunits_tree, 0);
 
+  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);
@@ -5330,6 +5342,8 @@ finish_vector_type (tree t)
        numbers equal.  */
     TYPE_UID (rt) = TYPE_UID (t);
   }
+
+  return t;
 }
 
 static tree
@@ -5548,19 +5562,30 @@ reconstruct_complex_type (tree type, tre
   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;
+
+  if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
+      || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
+    nunits = GET_MODE_NUNITS (mode);
+  else
+    nunits = GET_MODE_BITSIZE (mode) / TREE_INT_CST_LOW (TYPE_SIZE (innertype));
+
+  /* Check that the mode is correct, and that (if it is a scalar mode)
+     there are no leftover bits.  */
+  if (GET_MODE_BITSIZE (mode) !=
+      nunits * TREE_INT_CST_LOW (TYPE_SIZE (innertype)))
+    abort ();
+
+  return make_vector_type (innertype, nunits, mode);
 }
 
-/* Similarly, but takes inner type and units.  */
+/* 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)
@@ -5568,16 +5593,30 @@ build_vector_type (tree innertype, int n
   enum machine_mode innermode = TYPE_MODE (innertype);
   enum machine_mode mode;
 
+  if (nunits & (nunits - 1))
+    abort ();
+
   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)
-      return build_vector_type_for_mode (innertype, mode);
+    if (GET_MODE_NUNITS (mode) == nunits
+	&& GET_MODE_INNER (mode) == innermode
+	&& VECTOR_MODE_SUPPORTED_P (mode))
+      break;
 
-  return NULL_TREE;
+  /* 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])
+    mode = BLKmode;
+
+  return make_vector_type (innertype, nunits, mode);
 }
 
 /* Given an initializer INIT, return TRUE if INIT is zero or some
Index: gcc/tree.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.def,v
retrieving revision 1.93
diff -u -p -r1.93 tree.def
--- gcc/tree.def	16 Jul 2004 21:13:04 -0000	1.93
+++ gcc/tree.def	19 Jul 2004 14:12:54 -0000
@@ -151,7 +151,8 @@ DEFTREECODE (REAL_TYPE, "real_type", 't'
 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: gcc/tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.562
diff -u -p -r1.562 tree.h
--- gcc/tree.h	18 Jul 2004 05:44:11 -0000	1.562
+++ gcc/tree.h	19 Jul 2004 14:12:55 -0000
@@ -1511,7 +1511,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.  */
@@ -3475,7 +3475,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);
Index: gcc/varasm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/varasm.c,v
retrieving revision 1.433
diff -u -p -r1.433 varasm.c
--- gcc/varasm.c	9 Jul 2004 03:29:35 -0000	1.433
+++ gcc/varasm.c	19 Jul 2004 14:12:55 -0000
@@ -3615,10 +3615,10 @@ output_constant (tree exp, unsigned HOST
 	  unsigned int nalign;
 	  enum machine_mode inner;
 
-	  inner = GET_MODE_INNER (TYPE_MODE (TREE_TYPE (exp)));
+	  inner = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
 	  nalign = MIN (align, GET_MODE_ALIGNMENT (inner));
 
-	  elt_size = GET_MODE_UNIT_SIZE (TYPE_MODE (TREE_TYPE (exp)));
+	  elt_size = GET_MODE_SIZE (inner);
 
 	  link = TREE_VECTOR_CST_ELTS (exp);
 	  output_constant (TREE_VALUE (link), elt_size, align);
Index: gcc/config/alpha/alpha-modes.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/alpha/alpha-modes.def,v
retrieving revision 1.2
diff -u -p -r1.2 alpha-modes.def
--- gcc/config/alpha/alpha-modes.def	25 Dec 2003 15:17:34 -0000	1.2
+++ gcc/config/alpha/alpha-modes.def	19 Jul 2004 14:12:56 -0000
@@ -21,3 +21,8 @@ Boston, MA 02111-1307, USA.  */
 /* 128-bit floating point.  This gets reset in alpha_override_options
    if VAX float format is in use.  */
 FLOAT_MODE (TF, 16, ieee_quad_format);
+
+/* Vector modes.  */
+VECTOR_MODES (INT, 8);        /*       V8QI V4HI V2SI */
+VECTOR_MODE (INT, QI, 4);     /*                 V4QI */
+VECTOR_MODE (INT, QI, 2);     /*                 V2QI */
Index: gcc/config/arm/arm-modes.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm-modes.def,v
retrieving revision 1.5
diff -u -p -r1.5 arm-modes.def
--- gcc/config/arm/arm-modes.def	25 Dec 2003 15:17:36 -0000	1.5
+++ gcc/config/arm/arm-modes.def	19 Jul 2004 14:12:56 -0000
@@ -50,3 +50,10 @@ CC_MODE (CC_DGEU);
 CC_MODE (CC_DGTU);
 CC_MODE (CC_C);
 CC_MODE (CC_N);
+
+/* Vector modes.  */
+VECTOR_MODES (INT, 8);        /*       V8QI V4HI V2SI */
+VECTOR_MODES (INT, 16);       /* V16QI V8HI V4SI V2DI */
+VECTOR_MODES (FLOAT, 8);      /*            V4HF V2SF */
+VECTOR_MODES (FLOAT, 16);     /*       V8HF V4SF V2DF */
+
Index: gcc/config/frv/frv-modes.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/frv/frv-modes.def,v
retrieving revision 1.3
diff -u -p -r1.3 frv-modes.def
--- gcc/config/frv/frv-modes.def	13 Oct 2003 21:16:26 -0000	1.3
+++ gcc/config/frv/frv-modes.def	19 Jul 2004 14:12:57 -0000
@@ -28,3 +28,6 @@ Boston, MA 02111-1307, USA.  */
 CC_MODE (CC_UNS);
 CC_MODE (CC_FP);
 CC_MODE (CC_CCR);
+
+VECTOR_MODE (INT, QI, 4);     /*                 V4QI */
+VECTOR_MODE (INT, SI, 4);     /*                 V4SI */
Index: gcc/config/i386/i386-modes.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386-modes.def,v
retrieving revision 1.6
diff -u -p -r1.6 i386-modes.def
--- gcc/config/i386/i386-modes.def	30 Oct 2003 23:27:30 -0000	1.6
+++ gcc/config/i386/i386-modes.def	19 Jul 2004 14:12:57 -0000
@@ -60,3 +60,15 @@ CC_MODE (CCNO);
 CC_MODE (CCZ);
 CC_MODE (CCFP);
 CC_MODE (CCFPU);
+
+/* Vector modes.  */
+VECTOR_MODES (INT, 4);        /*            V4QI V2HI */
+VECTOR_MODES (INT, 8);        /*       V8QI V4HI V2SI */
+VECTOR_MODES (INT, 16);       /* V16QI V8HI V4SI V2DI */
+VECTOR_MODES (FLOAT, 8);      /*            V4HF V2SF */
+VECTOR_MODES (FLOAT, 16);     /*       V8HF V4SF V2DF */
+VECTOR_MODE (INT, DI, 4);     /*                 V4DI */
+VECTOR_MODE (INT, SI, 8);     /*                 V8SI */
+
+/* The symbol Pmode stands for one of the above machine modes (usually SImode).
+   The tm.h file specifies which one.  It is not a distinct mode.  */
Index: gcc/config/rs6000/rs6000-modes.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000-modes.def,v
retrieving revision 1.4
diff -u -p -r1.4 rs6000-modes.def
--- gcc/config/rs6000/rs6000-modes.def	31 Dec 2003 00:25:51 -0000	1.4
+++ gcc/config/rs6000/rs6000-modes.def	19 Jul 2004 14:12:58 -0000
@@ -38,3 +38,10 @@ PARTIAL_INT_MODE (SI);
 CC_MODE (CCUNS);
 CC_MODE (CCFP);
 CC_MODE (CCEQ);
+
+/* Vector modes.  */
+VECTOR_MODES (INT, 8);        /*       V8QI V4HI V2SI */
+VECTOR_MODES (INT, 16);       /* V16QI V8HI V4SI V2DI */
+VECTOR_MODE (INT, DI, 1);
+VECTOR_MODES (FLOAT, 8);      /*            V4HF V2SF */
+VECTOR_MODES (FLOAT, 16);     /*       V8HF V4SF V2DF */
Index: gcc/config/sh/sh-modes.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/sh/sh-modes.def,v
retrieving revision 1.1
diff -u -p -r1.1 sh-modes.def
--- gcc/config/sh/sh-modes.def	13 Oct 2003 21:16:32 -0000	1.1
+++ gcc/config/sh/sh-modes.def	19 Jul 2004 14:12:58 -0000
@@ -21,3 +21,12 @@ Boston, MA 02111-1307, USA.  */
 /* The SH uses a partial integer mode to represent the FPSCR register.  */
 PARTIAL_INT_MODE (SI);
 
+/* Vector modes.  */
+VECTOR_MODES (INT, 4);        /*            V4QI V2HI */
+VECTOR_MODES (INT, 8);        /*       V8QI V4HI V2SI */
+VECTOR_MODES (INT, 16);       /* V16QI V8HI V4SI V2DI */
+VECTOR_MODES (FLOAT, 8);      /*            V4HF V2SF */
+VECTOR_MODES (FLOAT, 16);     /*       V8HF V4SF V2DF */
+VECTOR_MODE (INT, DI, 4);     /*                 V4DI */
+VECTOR_MODE (INT, DI, 8);     /*                 V8DI */
+VECTOR_MODE (FLOAT, SF, 16);  /*                V16SF */
Index: gcc/cp/typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck.c,v
retrieving revision 1.562
diff -u -p -r1.562 typeck.c
--- gcc/cp/typeck.c	18 Jul 2004 12:37:55 -0000	1.562
+++ gcc/cp/typeck.c	19 Jul 2004 14:12:59 -0000
@@ -2869,15 +2869,20 @@ build_binary_op (enum tree_code code, tr
     case ROUND_DIV_EXPR:
     case EXACT_DIV_EXPR:
       if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
-	   || code0 == COMPLEX_TYPE)
+	   || code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE)
 	  && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
-	      || code1 == COMPLEX_TYPE))
+	      || code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE))
 	{
 	  if (TREE_CODE (op1) == INTEGER_CST && integer_zerop (op1))
 	    warning ("division by zero in `%E / 0'", op0);
 	  else if (TREE_CODE (op1) == REAL_CST && real_zerop (op1))
 	    warning ("division by zero in `%E / 0.'", op0);
 	      
+	  if (code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE)
+	    code0 = TREE_CODE (TREE_TYPE (TREE_TYPE (op0)));
+	  if (code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE)
+	    code1 = TREE_CODE (TREE_TYPE (TREE_TYPE (op1)));
+
 	  if (!(code0 == INTEGER_TYPE && code1 == INTEGER_TYPE))
 	    resultcode = RDIV_EXPR;
 	  else

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]