This is the mail archive of the gcc@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: We're out of tree codes; now what?


"Steven Bosscher" <stevenb.gcc@gmail.com> writes:

> On 3/20/07, Doug Gregor <doug.gregor@gmail.com> wrote:
> > > So the memory hit shouldn't be
> > > as big as e.g. going to 16 bit tree codes if that means increasing the size
> > > of most of the trees the compiler uses.
> >
> > Yes, this is true.
> 
> But this could be solved if all LANG_TREE_x bits could move to
> language specific trees, could it?

That might be the best paint color.  Move to 16-bit tree codes, and
move the lang specific flags to language specific structures.  I see
two difficulties.  First, we only have seven lang specific fields, so
we would have figure out what to do with the extra flag.  Second, we
would have to modify the C frontend to build a language specific
structure in places where it currently does not.

For what it's worth, last night I threw together a different approach:
use subcodes for the less common tree codes.  I started with the
vector operations.  I've attached what it looks like.  This is not
quite as bad as language specific codes, since relatively few places
have to deal with the vector codes.  Similar techniques could be
applied to other uncommon codes: e.g., put the specific type of
division/modulos into a subcode.  A disadvantage of this approach is
that it requires a field in tree_exp, but I believe that we would
prefer to eliminate the existing locus and block fields.

Anyhow, patch attached for amusement value.  Let's see if we can move
the lang_flag_x bits.

Ian

Index: tree-ssa-loop-im.c
===================================================================
--- tree-ssa-loop-im.c	(revision 122923)
+++ tree-ssa-loop-im.c	(working copy)
@@ -341,6 +341,7 @@ outermost_invariant_loop_expr (tree expr
 
   if (class != tcc_unary
       && class != tcc_binary
+      && class != tcc_binary_subcode
       && class != tcc_expression
       && class != tcc_vl_exp
       && class != tcc_comparison)
@@ -817,6 +818,7 @@ force_move_till_expr (tree expr, struct 
 
   if (class != tcc_unary
       && class != tcc_binary
+      && class != tcc_binary_subcode
       && class != tcc_expression
       && class != tcc_vl_exp
       && class != tcc_comparison)
Index: tree-dump.c
===================================================================
--- tree-dump.c	(revision 122923)
+++ tree-dump.c	(working copy)
@@ -247,19 +247,26 @@ dequeue_and_dump (dump_info_p di)
   dq->next = di->free_list;
   di->free_list = dq;
 
+  /* Figure out what kind of node this is.  */
+  code = TREE_CODE (t);
+  code_class = TREE_CODE_CLASS (code);
+
   /* Print the node index.  */
   dump_index (di, index);
   /* And the type of node this is.  */
   if (dni->binfo_p)
     code_name = "binfo";
   else
-    code_name = tree_code_name[(int) TREE_CODE (t)];
-  fprintf (di->stream, "%-16s ", code_name);
-  di->column = 25;
+    code_name = tree_code_name[(int) code];
+  if (code_class != tcc_binary_subcode)
+    fprintf (di->stream, "%-16s", code_name);
+  else
+    fprintf (di->stream, "%s/%*s", code_name,
+	     MIN (0, strlen (code_name) - 15),
+	     tree_subcode_name[TREE_SUBCODE (t)]);
 
-  /* Figure out what kind of node this is.  */
-  code = TREE_CODE (t);
-  code_class = TREE_CODE_CLASS (code);
+  fprintf (di->stream, " ");
+  di->column = 25;
 
   /* Although BINFOs are TREE_VECs, we dump them specially so as to be
      more informative.  */
@@ -311,6 +318,7 @@ dequeue_and_dump (dump_info_p di)
 	  break;
 
 	case tcc_binary:
+	case tcc_binary_subcode:
 	case tcc_comparison:
 	  dump_child ("op 0", TREE_OPERAND (t, 0));
 	  dump_child ("op 1", TREE_OPERAND (t, 1));
@@ -756,7 +764,7 @@ dump_node (tree t, int flags, FILE *stre
 
 
 /* Table of tree dump switches. This must be consistent with the
-   TREE_DUMP_INDEX enumeration in tree.h.  */
+   tree_dump_index enumeration in tree-pass.h.  */
 static struct dump_file_info dump_files[TDI_end] =
 {
   {NULL, NULL, NULL, 0, 0, 0, 0},
Index: tree-pretty-print.c
===================================================================
--- tree-pretty-print.c	(revision 122923)
+++ tree-pretty-print.c	(working copy)
@@ -37,7 +37,7 @@ Software Foundation, 51 Franklin Street,
 
 /* Local functions, macros and variables.  */
 static int op_prio (tree);
-static const char *op_symbol_1 (enum tree_code);
+static const char *op_symbol_1 (enum tree_code, unsigned int);
 static const char *op_symbol (tree);
 static void pretty_print_string (pretty_printer *, const char*);
 static void print_call_name (pretty_printer *, tree);
@@ -296,7 +296,8 @@ dump_omp_clause (pretty_printer *buffer,
 
     case OMP_CLAUSE_REDUCTION:
       pp_string (buffer, "reduction(");
-      pp_string (buffer, op_symbol_1 (OMP_CLAUSE_REDUCTION_CODE (clause)));
+      pp_string (buffer, op_symbol_1 (OMP_CLAUSE_REDUCTION_CODE (clause),
+				      INVALID_SUBCODE));
       pp_character (buffer, ':');
       dump_generic_node (buffer, OMP_CLAUSE_DECL (clause),
 	  spc, flags, false);
@@ -1238,8 +1239,6 @@ dump_generic_node (pretty_printer *buffe
     case RSHIFT_EXPR:
     case LROTATE_EXPR:
     case RROTATE_EXPR:
-    case VEC_LSHIFT_EXPR:
-    case VEC_RSHIFT_EXPR:
     case BIT_IOR_EXPR:
     case BIT_XOR_EXPR:
     case BIT_AND_EXPR:
@@ -1262,6 +1261,7 @@ dump_generic_node (pretty_printer *buffe
     case LTGT_EXPR:
     case ORDERED_EXPR:
     case UNORDERED_EXPR:
+    binop:
       {
 	const char *op = op_symbol (node);
 	op0 = TREE_OPERAND (node, 0);
@@ -1907,50 +1907,112 @@ dump_generic_node (pretty_printer *buffe
       pp_string (buffer, " > ");
       break;
 
-    case VEC_WIDEN_MULT_HI_EXPR:
-      pp_string (buffer, " VEC_WIDEN_MULT_HI_EXPR < ");
-      dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
-      pp_string (buffer, ", ");
-      dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false);
-      pp_string (buffer, " > ");
-      break;
+    case VEC_BINARY_EXPR:
+      switch (TREE_SUBCODE (node))
+	{
+	case VEC_LSHIFT_EXPR:
+	case VEC_RSHIFT_EXPR:
+	  goto binop;
+
+	case VEC_WIDEN_MULT_HI_EXPR:
+	  pp_string (buffer, " VEC_WIDEN_MULT_HI_EXPR < ");
+	  dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags,
+			     false);
+	  pp_string (buffer, ", ");
+	  dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags,
+			     false);
+	  pp_string (buffer, " > ");
+	  break;
 
-    case VEC_WIDEN_MULT_LO_EXPR:
-      pp_string (buffer, " VEC_WIDEN_MULT_LO_EXPR < ");
-      dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
-      pp_string (buffer, ", ");
-      dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false);
-      pp_string (buffer, " > ");
-      break;
+	case VEC_WIDEN_MULT_LO_EXPR:
+	  pp_string (buffer, " VEC_WIDEN_MULT_LO_EXPR < ");
+	  dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags,
+			     false);
+	  pp_string (buffer, ", ");
+	  dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags,
+			     false);
+	  pp_string (buffer, " > ");
+	  break;
 
-    case VEC_UNPACK_HI_EXPR:
-      pp_string (buffer, " VEC_UNPACK_HI_EXPR < ");
-      dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
-      pp_string (buffer, " > ");
-      break;
+	case VEC_UNPACK_HI_EXPR:
+	  pp_string (buffer, " VEC_UNPACK_HI_EXPR < ");
+	  dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags,
+			     false);
+	  pp_string (buffer, " > ");
+	  break;
 
-    case VEC_UNPACK_LO_EXPR:
-      pp_string (buffer, " VEC_UNPACK_LO_EXPR < ");
-      dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
-      pp_string (buffer, " > ");
-      break;
+	case VEC_UNPACK_LO_EXPR:
+	  pp_string (buffer, " VEC_UNPACK_LO_EXPR < ");
+	  dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags,
+			     false);
+	  pp_string (buffer, " > ");
+	  break;
 
-    case VEC_PACK_MOD_EXPR:
-      pp_string (buffer, " VEC_PACK_MOD_EXPR < ");
-      dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
-      pp_string (buffer, ", ");
-      dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false);
-      pp_string (buffer, " > ");
-      break;
-                                                                                
-    case VEC_PACK_SAT_EXPR:
-      pp_string (buffer, " VEC_PACK_SAT_EXPR < ");
-      dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
-      pp_string (buffer, ", ");
-      dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false);
-      pp_string (buffer, " > ");
+	case VEC_PACK_MOD_EXPR:
+	  pp_string (buffer, " VEC_PACK_MOD_EXPR < ");
+	  dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags,
+			     false);
+	  pp_string (buffer, ", ");
+	  dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags,
+			     false);
+	  pp_string (buffer, " > ");
+	  break;
+
+	case VEC_PACK_SAT_EXPR:
+	  pp_string (buffer, " VEC_PACK_SAT_EXPR < ");
+	  dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags,
+			     false);
+	  pp_string (buffer, ", ");
+	  dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags,
+			     false);
+	  pp_string (buffer, " > ");
+	  break;
+
+	case VEC_EXTRACT_EVEN_EXPR:
+	  pp_string (buffer, " VEC_EXTRACT_EVEN_EXPR < ");
+	  dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags,
+			     false);
+	  pp_string (buffer, ", ");
+	  dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags,
+			     false);
+	  pp_string (buffer, " > ");
+	  break;
+  
+	case VEC_EXTRACT_ODD_EXPR:
+	  pp_string (buffer, " VEC_EXTRACT_ODD_EXPR < ");
+	  dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags,
+			     false);
+	  pp_string (buffer, ", ");
+	  dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags,
+			     false);
+	  pp_string (buffer, " > ");
+	  break;
+
+	case VEC_INTERLEAVE_HIGH_EXPR:
+	  pp_string (buffer, " VEC_INTERLEAVE_HIGH_EXPR < ");
+	  dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags,
+			     false);
+	  pp_string (buffer, ", ");
+	  dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags,
+			     false);
+	  pp_string (buffer, " > ");
+	  break;
+
+	case VEC_INTERLEAVE_LOW_EXPR:
+	  pp_string (buffer, " VEC_INTERLEAVE_LOW_EXPR < ");
+	  dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags,
+			     false);
+	  pp_string (buffer, ", ");
+	  dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags,
+			     false);
+	  pp_string (buffer, " > ");
+	  break;
+
+	default:
+	  gcc_unreachable ();
+	}
       break;
-                                                                                
+
     case BLOCK:
       {
 	tree t;
@@ -2009,38 +2071,6 @@ dump_generic_node (pretty_printer *buffe
       }
     break;
 
-    case VEC_EXTRACT_EVEN_EXPR:
-      pp_string (buffer, " VEC_EXTRACT_EVEN_EXPR < ");
-      dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
-      pp_string (buffer, ", ");
-      dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false);
-      pp_string (buffer, " > ");
-      break;
-  
-    case VEC_EXTRACT_ODD_EXPR:
-      pp_string (buffer, " VEC_EXTRACT_ODD_EXPR < ");
-      dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
-      pp_string (buffer, ", ");
-      dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false);
-      pp_string (buffer, " > ");
-      break;
-
-    case VEC_INTERLEAVE_HIGH_EXPR:
-      pp_string (buffer, " VEC_INTERLEAVE_HIGH_EXPR < ");
-      dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
-      pp_string (buffer, ", ");
-      dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false);
-      pp_string (buffer, " > ");
-      break;
-
-    case VEC_INTERLEAVE_LOW_EXPR:
-      pp_string (buffer, " VEC_INTERLEAVE_LOW_EXPR < ");
-      dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
-      pp_string (buffer, ", ");
-      dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false);
-      pp_string (buffer, " > ");
-      break;
-
     default:
       NIY;
     }
@@ -2286,8 +2316,6 @@ op_prio (tree op)
     case MINUS_EXPR:
       return 12;
 
-    case VEC_WIDEN_MULT_HI_EXPR:
-    case VEC_WIDEN_MULT_LO_EXPR:
     case WIDEN_MULT_EXPR:
     case DOT_PROD_EXPR:
     case MULT_EXPR:
@@ -2336,14 +2364,33 @@ op_prio (tree op)
     case REDUC_MAX_EXPR:
     case REDUC_MIN_EXPR:
     case REDUC_PLUS_EXPR:
-    case VEC_LSHIFT_EXPR:
-    case VEC_RSHIFT_EXPR:
-    case VEC_UNPACK_HI_EXPR:
-    case VEC_UNPACK_LO_EXPR:
-    case VEC_PACK_MOD_EXPR:
-    case VEC_PACK_SAT_EXPR:
       return 16;
 
+    case VEC_BINARY_EXPR:
+      switch (TREE_SUBCODE (op))
+	{
+	case VEC_WIDEN_MULT_HI_EXPR:
+	case VEC_WIDEN_MULT_LO_EXPR:
+	  return 13;
+
+	case VEC_LSHIFT_EXPR:
+	case VEC_RSHIFT_EXPR:
+	case VEC_UNPACK_HI_EXPR:
+	case VEC_UNPACK_LO_EXPR:
+	case VEC_PACK_MOD_EXPR:
+	case VEC_PACK_SAT_EXPR:
+	  return 16;
+
+	case VEC_EXTRACT_EVEN_EXPR:
+	case VEC_EXTRACT_ODD_EXPR:
+	case VEC_INTERLEAVE_HIGH_EXPR:
+	case VEC_INTERLEAVE_LOW_EXPR:
+	  return 9999;
+
+	default:
+	  gcc_unreachable ();
+	}
+
     case SAVE_EXPR:
     case NON_LVALUE_EXPR:
       return op_prio (TREE_OPERAND (op, 0));
@@ -2359,7 +2406,7 @@ op_prio (tree op)
 /* Return the symbol associated with operator OP.  */
 
 static const char *
-op_symbol_1 (enum tree_code code)
+op_symbol_1 (enum tree_code code, unsigned int subcode)
 {
   switch (code)
     {
@@ -2434,11 +2481,16 @@ op_symbol_1 (enum tree_code code)
     case RROTATE_EXPR:
       return "r>>";
 
-    case VEC_LSHIFT_EXPR:
-      return "v<<";
+    case VEC_BINARY_EXPR:
+      switch (subcode)
+	{
+	case VEC_LSHIFT_EXPR:
+	  return "v<<";
 
-    case VEC_RSHIFT_EXPR:
-      return "v>>";
+	case VEC_RSHIFT_EXPR:
+	  return "v>>";
+	}
+      break;
  
     case PLUS_EXPR:
       return "+";
@@ -2519,14 +2571,19 @@ op_symbol_1 (enum tree_code code)
       return "min";
 
     default:
-      return "<<< ??? >>>";
+      break;
     }
+
+  return "<<< ??? >>>";
 }
 
 static const char *
 op_symbol (tree op)
 {
-  return op_symbol_1 (TREE_CODE (op));
+  return op_symbol_1 (TREE_CODE (op),
+		      (TREE_CODE_CLASS (TREE_CODE (op)) == tcc_binary_subcode
+		       ? TREE_SUBCODE (op)
+		       : INVALID_SUBCODE));
 }
 
 /* Prints the name of a CALL_EXPR.  */
Index: java/java-gimplify.c
===================================================================
--- java/java-gimplify.c	(revision 122923)
+++ java/java-gimplify.c	(working copy)
@@ -129,6 +129,7 @@ java_gimplify_expr (tree *expr_p, tree *
 	 the front end already generates SAVE_EXPRs.  */
 
       if (TREE_CODE_CLASS (code) == tcc_binary
+	  || TREE_CODE_CLASS (code) == tcc_binary_subcode
 	  || TREE_CODE_CLASS (code) == tcc_comparison)
 	{
 	  enum gimplify_status stat 
Index: optabs.c
===================================================================
--- optabs.c	(revision 122923)
+++ optabs.c	(working copy)
@@ -243,7 +243,7 @@ widen_operand (rtx op, enum machine_mode
    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)
+optab_for_tree_code (enum tree_code code, unsigned int subcode, tree type)
 {
   bool trapv;
   switch (code)
@@ -310,34 +310,44 @@ optab_for_tree_code (enum tree_code code
     case REDUC_PLUS_EXPR:
       return TYPE_UNSIGNED (type) ? reduc_uplus_optab : reduc_splus_optab;
 
-    case VEC_LSHIFT_EXPR:
-      return vec_shl_optab;
+    case VEC_BINARY_EXPR:
+      switch (subcode)
+	{
+	case VEC_LSHIFT_EXPR:
+	  return vec_shl_optab;
+
+	case VEC_RSHIFT_EXPR:
+	  return vec_shr_optab;
+
+	case VEC_WIDEN_MULT_HI_EXPR:
+	  return TYPE_UNSIGNED (type) ? 
+	    vec_widen_umult_hi_optab : vec_widen_smult_hi_optab;
+
+	case VEC_WIDEN_MULT_LO_EXPR:
+	  return TYPE_UNSIGNED (type) ? 
+	    vec_widen_umult_lo_optab : vec_widen_smult_lo_optab;
+
+	case VEC_UNPACK_HI_EXPR:
+	  return TYPE_UNSIGNED (type) ? 
+	    vec_unpacku_hi_optab : vec_unpacks_hi_optab;
 
-    case VEC_RSHIFT_EXPR:
-      return vec_shr_optab;
+	case VEC_UNPACK_LO_EXPR:
+	  return TYPE_UNSIGNED (type) ? 
+	    vec_unpacku_lo_optab : vec_unpacks_lo_optab;
+
+	case VEC_PACK_MOD_EXPR:
+	  return vec_pack_mod_optab;
+
+	case VEC_PACK_SAT_EXPR:
+	  return (TYPE_UNSIGNED (type)
+		  ? vec_pack_usat_optab
+		  : vec_pack_ssat_optab);
+
+	default:
+	  break;
+	}
+      break;
 
-    case VEC_WIDEN_MULT_HI_EXPR:
-      return TYPE_UNSIGNED (type) ? 
-	vec_widen_umult_hi_optab : vec_widen_smult_hi_optab;
-
-    case VEC_WIDEN_MULT_LO_EXPR:
-      return TYPE_UNSIGNED (type) ? 
-	vec_widen_umult_lo_optab : vec_widen_smult_lo_optab;
-
-    case VEC_UNPACK_HI_EXPR:
-      return TYPE_UNSIGNED (type) ? 
-	vec_unpacku_hi_optab : vec_unpacks_hi_optab;
-
-    case VEC_UNPACK_LO_EXPR:
-      return TYPE_UNSIGNED (type) ? 
-	vec_unpacku_lo_optab : vec_unpacks_lo_optab;
-
-    case VEC_PACK_MOD_EXPR:
-      return vec_pack_mod_optab;
-                                                                                
-    case VEC_PACK_SAT_EXPR:
-      return TYPE_UNSIGNED (type) ? vec_pack_usat_optab : vec_pack_ssat_optab;
-                                                                                
     default:
       break;
     }
@@ -360,21 +370,30 @@ optab_for_tree_code (enum tree_code code
     case ABS_EXPR:
       return trapv ? absv_optab : abs_optab;
 
-    case VEC_EXTRACT_EVEN_EXPR:
-      return vec_extract_even_optab;
+    case VEC_BINARY_EXPR:
+      switch (subcode)
+	{
+	case VEC_EXTRACT_EVEN_EXPR:
+	  return vec_extract_even_optab;
 
-    case VEC_EXTRACT_ODD_EXPR:
-      return vec_extract_odd_optab;
+	case VEC_EXTRACT_ODD_EXPR:
+	  return vec_extract_odd_optab;
 
-    case VEC_INTERLEAVE_HIGH_EXPR:
-      return vec_interleave_high_optab;
+	case VEC_INTERLEAVE_HIGH_EXPR:
+	  return vec_interleave_high_optab;
 
-    case VEC_INTERLEAVE_LOW_EXPR:
-      return vec_interleave_low_optab;
+	case VEC_INTERLEAVE_LOW_EXPR:
+	  return vec_interleave_low_optab;
+
+	default:
+	  break;
+	}
 
     default:
-      return NULL;
+      break;
     }
+
+  return NULL;
 }
 
 
@@ -415,7 +434,8 @@ expand_widen_pattern_expr (tree exp, rtx
   oprnd0 = TREE_OPERAND (exp, 0);
   tmode0 = TYPE_MODE (TREE_TYPE (oprnd0));
   widen_pattern_optab =
-        optab_for_tree_code (TREE_CODE (exp), TREE_TYPE (oprnd0));
+    optab_for_tree_code (TREE_CODE (exp), INVALID_SUBCODE,
+			 TREE_TYPE (oprnd0));
   icode = (int) widen_pattern_optab->handlers[(int) tmode0].insn_code;
   gcc_assert (icode != CODE_FOR_nothing);
   xmode0 = insn_data[icode].operand[1].mode;
@@ -658,7 +678,9 @@ expand_vec_shift_expr (tree vec_shift_ex
   optab shift_optab;
   rtx pat;
 
-  switch (TREE_CODE (vec_shift_expr))
+  gcc_assert (TREE_CODE (vec_shift_expr) == VEC_BINARY_EXPR);
+
+  switch (TREE_SUBCODE (vec_shift_expr))
     {
       case VEC_RSHIFT_EXPR:
 	shift_optab = vec_shr_optab;
Index: optabs.h
===================================================================
--- optabs.h	(revision 122923)
+++ optabs.h	(working copy)
@@ -622,8 +622,8 @@ enum can_compare_purpose
 };
 
 /* 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);
+   given by the third argument.  */
+extern optab optab_for_tree_code (enum tree_code, unsigned int, tree);
 
 /* Nonzero if a compare of mode MODE can be done straightforwardly
    (without splitting it into pieces).  */
Index: tree.c
===================================================================
--- tree.c	(revision 122923)
+++ tree.c	(working copy)
@@ -71,6 +71,24 @@ const char *const tree_code_class_string
   "gimple_stmt"
 };
 
+/* Must match tree_subcode in tree.h.  */
+
+const char *const tree_subcode_name[] = {
+  "invalid",
+  "vec_lshift_expr",
+  "vec_rshift_expr",
+  "vec_widen_mult_hi_expr",
+  "vec_widen_mult_lo_expr",
+  "vec_unpack_hi_expr",
+  "vec_unpack_lo_expr",
+  "vec_pack_mod_expr",
+  "vec_pack_sat_expr",
+  "vec_extract_even_expr",
+  "vec_extract_odd_expr",
+  "vec_interleave_high_expr",
+  "vec_interleave_low_expr"
+};
+
 /* obstack.[ch] explicitly declined to prototype this.  */
 extern int _obstack_allocated_p (struct obstack *h, void *obj);
 
@@ -388,6 +406,8 @@ tree_code_size (enum tree_code code)
     case tcc_comparison:  /* a comparison expression */
     case tcc_unary:       /* a unary arithmetic expression */
     case tcc_binary:      /* a binary arithmetic expression */
+    case tcc_binary_subcode: /* A binary arithmetic expression with a
+				subcode.  */
       return (sizeof (struct tree_exp)
 	      + (TREE_CODE_LENGTH (code) - 1) * sizeof (tree));
 
@@ -512,6 +532,7 @@ make_node_stat (enum tree_code code MEM_
     case tcc_comparison:  /* a comparison expression */
     case tcc_unary:  /* a unary arithmetic expression */
     case tcc_binary:  /* a binary arithmetic expression */
+    case tcc_binary_subcode: /* a binary arithmetic expression with subcode */
       kind = e_kind;
       break;
 
@@ -2168,6 +2189,7 @@ tree_node_structure (tree t)
     case tcc_comparison:
     case tcc_unary:
     case tcc_binary:
+    case tcc_binary_subcode:
     case tcc_expression:
     case tcc_statement:
     case tcc_vl_exp:
@@ -2239,6 +2261,7 @@ contains_placeholder_p (tree exp)
 
     case tcc_unary:
     case tcc_binary:
+    case tcc_binary_subcode:
     case tcc_comparison:
     case tcc_expression:
       switch (code)
@@ -2433,6 +2456,7 @@ substitute_in_expr (tree exp, tree f, tr
       case tcc_exceptional:
       case tcc_unary:
       case tcc_binary:
+      case tcc_binary_subcode:
       case tcc_comparison:
       case tcc_expression:
       case tcc_reference:
@@ -2589,6 +2613,7 @@ substitute_placeholder_in_expr (tree exp
       case tcc_exceptional:
       case tcc_unary:
       case tcc_binary:
+      case tcc_binary_subcode:
       case tcc_comparison:
       case tcc_expression:
       case tcc_reference:
@@ -2805,6 +2830,7 @@ stabilize_reference_1 (tree e)
       return e;
 
     case tcc_binary:
+    case tcc_binary_subcode:
       /* Division is slow and tends to be compiled with jumps,
 	 especially the division by powers of 2 that is often
 	 found inside of an array reference.  So do it just once.  */
@@ -3059,6 +3085,7 @@ build2_stat (enum tree_code code, tree t
   tree t;
 
   gcc_assert (TREE_CODE_LENGTH (code) == 2);
+  gcc_assert (TREE_CODE_CLASS (code) != tcc_binary_subcode);
 
 #if 1
   /* FIXME tuples: Statement's aren't expressions!  */
@@ -3099,6 +3126,46 @@ build2_stat (enum tree_code code, tree t
   return t;
 }
 
+/* Build a binary statement which uses a subcode.  */
+
+tree
+build2_subcode_stat (enum tree_code code, unsigned int subcode, tree tt,
+		     tree arg0, tree arg1 MEM_STAT_DECL)
+{
+  bool constant, read_only, side_effects, invariant;
+  tree t;
+
+  gcc_assert (TREE_CODE_LENGTH (code) == 2);
+  gcc_assert (TREE_CODE_CLASS (code) == tcc_binary_subcode);
+
+  t = make_node_stat (code PASS_MEM_STAT);
+  TREE_TYPE (t) = tt;
+  t->exp.u.subcode = subcode;
+
+  /* Below, we automatically set TREE_SIDE_EFFECTS and TREE_READONLY for the
+     result based on those same flags for the arguments.  But if the
+     arguments aren't really even `tree' expressions, we shouldn't be trying
+     to do this.  */
+
+  /* Expressions without side effects may be constant if their
+     arguments are as well.  */
+  constant = 1;
+  read_only = 1;
+  side_effects = TREE_SIDE_EFFECTS (t);
+  invariant = constant;
+
+  PROCESS_ARG(0);
+  PROCESS_ARG(1);
+
+  TREE_READONLY (t) = read_only;
+  TREE_CONSTANT (t) = constant;
+  TREE_INVARIANT (t) = invariant;
+  TREE_SIDE_EFFECTS (t) = side_effects;
+  TREE_THIS_VOLATILE (t) = 0;
+
+  return t;
+}
+
 
 /* Build a GIMPLE_MODIFY_STMT node.  This tree code doesn't have a
    type, so we can't use build2 (a.k.a. build2_stat).  */
@@ -3416,25 +3483,32 @@ expr_location (tree node)
 #ifdef USE_MAPPED_LOCATION
   if (GIMPLE_STMT_P (node))
     return GIMPLE_STMT_LOCUS (node);
-  return EXPR_P (node) ? node->exp.locus : UNKNOWN_LOCATION;
+  return ((EXPR_P (node)
+	   && TREE_CODE_CLASS (TREE_CODE (node)) != tcc_binary_subcode)
+	  ? node->exp.u.locus
+	  : UNKNOWN_LOCATION);
 #else
   if (GIMPLE_STMT_P (node))
     return EXPR_HAS_LOCATION (node)
       ? *GIMPLE_STMT_LOCUS (node) : UNKNOWN_LOCATION;
-  return EXPR_HAS_LOCATION (node) ? *node->exp.locus : UNKNOWN_LOCATION;
+  return ((EXPR_HAS_LOCATION (node)
+	   && TREE_CODE_CLASS (TREE_CODE (node)) != tcc_binary_subcode)
+	  ? *node->exp.u.locus
+	  : UNKNOWN_LOCATION);
 #endif
 }
 
 void
 set_expr_location (tree node, location_t locus)
 {
+  gcc_assert (TREE_CODE_CLASS (TREE_CODE (node)) != tcc_binary_subcode);
 #ifdef USE_MAPPED_LOCATION
   if (GIMPLE_STMT_P (node))
     GIMPLE_STMT_LOCUS (node) = locus;
   else
-    EXPR_CHECK (node)->exp.locus = locus;
+    EXPR_CHECK (node)->exp.u.locus = locus;
 #else
-      annotate_with_locus (node, locus);
+  annotate_with_locus (node, locus);
 #endif
 }
 
@@ -3458,13 +3532,19 @@ expr_locus (tree node)
 #ifdef USE_MAPPED_LOCATION
   if (GIMPLE_STMT_P (node))
     return &GIMPLE_STMT_LOCUS (node);
-  return EXPR_P (node) ? &node->exp.locus : (location_t *) NULL;
+  return ((EXPR_P (node)
+	   && TREE_CODE_CLASS (TREE_CODE (node)) != tcc_binary_subcode)
+	  ? &node->exp.u.locus
+	  : (location_t *) NULL);
 #else
   if (GIMPLE_STMT_P (node))
     return GIMPLE_STMT_LOCUS (node);
   /* ?? The cast below was originally "(location_t *)" in the macro,
      but that makes no sense.  ?? */
-  return EXPR_P (node) ? node->exp.locus : (source_locus) NULL;
+  return ((EXPR_P (node)
+	   && TREE_CODE_CLASS (TREE_CODE (node)) != tcc_binary_subcode)
+	  ? node->exp.u.locus
+	  : (source_locus) NULL);
 #endif
 }
 
@@ -3477,26 +3557,27 @@ set_expr_locus (tree node,
 #endif
 		)
 {
+  gcc_assert (TREE_CODE_CLASS (TREE_CODE (node)) != tcc_binary_subcode);
 #ifdef USE_MAPPED_LOCATION
   if (loc == NULL)
     {
       if (GIMPLE_STMT_P (node))
 	GIMPLE_STMT_LOCUS (node) = UNKNOWN_LOCATION;
       else
-	EXPR_CHECK (node)->exp.locus = UNKNOWN_LOCATION;
+	EXPR_CHECK (node)->exp.u.locus = UNKNOWN_LOCATION;
     }
   else
     {
       if (GIMPLE_STMT_P (node))
 	GIMPLE_STMT_LOCUS (node) = *loc;
       else
-	EXPR_CHECK (node)->exp.locus = *loc;
+	EXPR_CHECK (node)->exp.u.locus = *loc;
     }
 #else
   if (GIMPLE_STMT_P (node))
     GIMPLE_STMT_LOCUS (node) = loc;
   else
-    EXPR_CHECK (node)->exp.locus = loc;
+    EXPR_CHECK (node)->exp.u.locus = loc;
 #endif
 }
 
@@ -3506,11 +3587,11 @@ expr_filename (tree node)
 #ifdef USE_MAPPED_LOCATION
   if (GIMPLE_STMT_P (node))
     return &LOCATION_FILE (GIMPLE_STMT_LOCUS (node));
-  return &LOCATION_FILE (EXPR_CHECK (node)->exp.locus);
+  return &LOCATION_FILE (EXPR_CHECK (node)->exp.u.locus);
 #else
   if (GIMPLE_STMT_P (node))
     return &GIMPLE_STMT_LOCUS (node)->file;
-  return &(EXPR_CHECK (node)->exp.locus->file);
+  return &(EXPR_CHECK (node)->exp.u.locus->file);
 #endif
 }
 
@@ -3520,11 +3601,11 @@ expr_lineno (tree node)
 #ifdef USE_MAPPED_LOCATION
   if (GIMPLE_STMT_P (node))
     return &LOCATION_LINE (GIMPLE_STMT_LOCUS (node));
-  return &LOCATION_LINE (EXPR_CHECK (node)->exp.locus);
+  return &LOCATION_LINE (EXPR_CHECK (node)->exp.u.locus);
 #else
   if (GIMPLE_STMT_P (node))
     return &GIMPLE_STMT_LOCUS (node)->line;
-  return &EXPR_CHECK (node)->exp.locus->line;
+  return &EXPR_CHECK (node)->exp.u.locus->line;
 #endif
 }
 
@@ -5067,6 +5148,7 @@ simple_cst_equal (tree t1, tree t2)
     {
     case tcc_unary:
     case tcc_binary:
+    case tcc_binary_subcode:
     case tcc_comparison:
     case tcc_expression:
     case tcc_reference:
Index: tree.h
===================================================================
--- tree.h	(revision 122923)
+++ tree.h	(working copy)
@@ -62,6 +62,7 @@ enum tree_code_class {
   tcc_comparison,  /* A comparison expression.  */
   tcc_unary,       /* A unary arithmetic expression.  */
   tcc_binary,      /* A binary arithmetic expression.  */
+  tcc_binary_subcode, /* A binary arithmetic expression with a subcode.  */
   tcc_statement,   /* A statement expression, which have side effects
 		      but usually no interesting value.  */
   tcc_vl_exp,      /* A function call or other expression with a
@@ -144,7 +145,8 @@ extern const enum tree_code_class tree_c
 /* Nonzero if CODE represents a binary arithmetic expression.  */
 
 #define BINARY_CLASS_P(CODE)\
-	(TREE_CODE_CLASS (TREE_CODE (CODE)) == tcc_binary)
+	(TREE_CODE_CLASS (TREE_CODE (CODE)) == tcc_binary \
+	 || TREE_CODE_CLASS (TREE_CODE (CODE)) == tcc_binary_subcode)
 
 /* Nonzero if CODE represents a statement expression.  */
 
@@ -203,6 +205,7 @@ extern const unsigned char tree_code_len
 /* Names of tree components.  */
 
 extern const char *const tree_code_name[];
+extern const char *const tree_subcode_name[];
 
 /* A vectors of trees.  */
 DEF_VEC_P(tree);
@@ -802,6 +805,15 @@ enum tree_node_structure_enum {
 				 __FILE__, __LINE__, __FUNCTION__);	\
     &__t->exp.operands[__i]; }))
 
+/* Checks for subcodes.  */
+#define TREE_SUBCODE_CHECK(T) __extension__				\
+({ const tree __t = (T);						\
+   char const __c = TREE_CODE_CLASS (TREE_CODE (__t));			\
+   if (__c != tcc_binary_subcode)					\
+     tree_class_check_failed (__t, tcc_binary_subcode, __FILE__,	\
+			      __LINE__, __FUNCTION__);			\
+   __t->exp.u.subcode; })
+
 /* Special checks for GIMPLE_STMT_OPERANDs.  */
 #define GIMPLE_STMT_OPERAND_CHECK(T, I) __extension__			\
 (*({const tree __t = GIMPLE_STMT_CHECK (T);				\
@@ -907,6 +919,7 @@ extern void omp_clause_range_check_faile
 #define TREE_VEC_ELT_CHECK(T, I)		((T)->vec.a[I])
 #define TREE_OPERAND_CHECK(T, I)		((T)->exp.operands[I])
 #define TREE_OPERAND_CHECK_CODE(T, CODE, I)	((T)->exp.operands[I])
+#define TREE_SUBCODE_CHECK(T)			((T)->exp.u.subcode)
 #define GIMPLE_STMT_OPERAND_CHECK(T, I)		((T)->gstmt.operands[I])
 #define TREE_RTL_OPERAND_CHECK(T, CODE, I)  (*(rtx *) &((T)->exp.operands[I]))
 #define PHI_NODE_ELT_CHECK(T, i)	((T)->phi.a[i])
@@ -1754,15 +1767,75 @@ enum omp_clause_default_kind
 #define OMP_CLAUSE_DEFAULT_KIND(NODE) \
   (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DEFAULT)->omp_clause.subcode.default_kind)
 
+/* This structure is used for expressions: codes for which
+   IS_EXPR_CODE_CLASS returns true.  For tcc_binary_subcode
+   expressions, we use the subcode field; for those expressions we do
+   not store a locus.  */
+
 struct tree_exp GTY(())
 {
   struct tree_common common;
-  source_locus locus;
+  union locus_subcode
+  {
+    source_locus GTY ((tag ("0")))  locus;
+    unsigned int GTY ((tag ("1"))) subcode;
+  } GTY ((desc
+	  ("TREE_CODE_CLASS (TREE_CODE ((tree) &%0)) == tcc_binary_subcode")))
+      u;
   tree block;
   tree GTY ((special ("tree_exp"),
 	     desc ("TREE_CODE ((tree) &%0)")))
     operands[1];
 };
+
+/* Return a subcode.  */
+
+#define TREE_SUBCODE(NODE) TREE_SUBCODE_CHECK(NODE)
+
+/* Subcode values.  */
+
+enum tree_subcode
+{
+  INVALID_SUBCODE = 0,
+
+  /* Whole vector left/right shift in bits.
+     Operand 0 is a vector to be shifted.
+     Operand 1 is an integer shift amount in bits.  */
+  VEC_LSHIFT_EXPR,
+  VEC_RSHIFT_EXPR,
+
+  /* Widening vector multiplication.
+     The two operands are vectors with N elements of size S. Multiplying the
+     elements of the two vectors will result in N products of size 2*S.
+     VEC_WIDEN_MULT_HI_EXPR computes the N/2 high products.
+     VEC_WIDEN_MULT_LO_EXPR computes the N/2 low products.  */
+  VEC_WIDEN_MULT_HI_EXPR,
+  VEC_WIDEN_MULT_LO_EXPR,
+
+  /* Unpack (extract and promote/widen) the high/low elements of the
+     input vector into the output vector. The input vector has twice
+     as many elements as the output vector, that are half the size of
+     the elements of the output vector.  This is used to support type
+     promotion. */
+  VEC_UNPACK_HI_EXPR,
+  VEC_UNPACK_LO_EXPR,
+
+  /* Pack (demote/narrow and merge) the elements of the two input
+     vectors into the output vector, using modulo/saturating
+     arithmetic.  The elements of the input vectors are twice the size
+     of the elements of the output vector.  This is used to support
+     type demotion.  */
+  VEC_PACK_MOD_EXPR,
+  VEC_PACK_SAT_EXPR,
+
+  /* Extract even/odd fields from vectors.  */
+  VEC_EXTRACT_EVEN_EXPR,
+  VEC_EXTRACT_ODD_EXPR,
+
+  /* Merge input vectors interleaving their fields.  */
+  VEC_INTERLEAVE_HIGH_EXPR,
+  VEC_INTERLEAVE_LOW_EXPR
+};
 
 /* SSA_NAME accessors.  */
 
@@ -3703,6 +3776,10 @@ extern tree build1_stat (enum tree_code,
 #define build1(c,t1,t2) build1_stat (c,t1,t2 MEM_STAT_INFO)
 extern tree build2_stat (enum tree_code, tree, tree, tree MEM_STAT_DECL);
 #define build2(c,t1,t2,t3) build2_stat (c,t1,t2,t3 MEM_STAT_INFO)
+extern tree build2_subcode_stat (enum tree_code, unsigned int, tree, tree,
+				 tree MEM_STAT_DECL);
+#define build2_subcode(c,s,t1,t2,t3) \
+  build2_subcode_stat (c,s,t1,t2,t3 MEM_STAT_INFO)
 extern tree build3_stat (enum tree_code, tree, tree, tree, tree MEM_STAT_DECL);
 #define build3(c,t1,t2,t3,t4) build3_stat (c,t1,t2,t3,t4 MEM_STAT_INFO)
 extern tree build4_stat (enum tree_code, tree, tree, tree, tree,
Index: fold-const.c
===================================================================
--- fold-const.c	(revision 122923)
+++ fold-const.c	(working copy)
@@ -2856,6 +2856,7 @@ operand_equal_p (tree arg0, tree arg1, u
 
     case tcc_comparison:
     case tcc_binary:
+    case tcc_binary_subcode:
       if (OP_SAME (0) && OP_SAME (1))
 	return 1;
 
@@ -3084,6 +3085,7 @@ twoval_comparison_p (tree arg, tree *cva
       return twoval_comparison_p (TREE_OPERAND (arg, 0), cval1, cval2, save_p);
 
     case tcc_binary:
+    case tcc_binary_subcode:
       return (twoval_comparison_p (TREE_OPERAND (arg, 0), cval1, cval2, save_p)
 	      && twoval_comparison_p (TREE_OPERAND (arg, 1),
 				      cval1, cval2, save_p));
@@ -4042,9 +4044,11 @@ make_range (tree exp, int *pin_p, tree *
 	    arg0 = TREE_OPERAND (exp, 0);
 	  if (TREE_CODE_CLASS (code) == tcc_comparison
 	      || TREE_CODE_CLASS (code) == tcc_unary
-	      || TREE_CODE_CLASS (code) == tcc_binary)
+	      || TREE_CODE_CLASS (code) == tcc_binary
+	      || TREE_CODE_CLASS (code) == tcc_binary_subcode)
 	    arg0_type = TREE_TYPE (arg0);
 	  if (TREE_CODE_CLASS (code) == tcc_binary
+	      || TREE_CODE_CLASS (code) == tcc_binary_subcode
 	      || TREE_CODE_CLASS (code) == tcc_comparison
 	      || (TREE_CODE_CLASS (code) == tcc_expression
 		  && TREE_OPERAND_LENGTH (exp) > 1))
@@ -5659,7 +5663,8 @@ extract_muldiv_1 (tree t, tree c, enum t
   if (TREE_CODE_CLASS (tcode) == tcc_unary)
     op0 = TREE_OPERAND (t, 0);
 
-  if (TREE_CODE_CLASS (tcode) == tcc_binary)
+  if (TREE_CODE_CLASS (tcode) == tcc_binary
+      || TREE_CODE_CLASS (tcode) == tcc_binary_subcode)
     op0 = TREE_OPERAND (t, 0), op1 = TREE_OPERAND (t, 1);
 
   /* Note that we need not handle conditional operations here since fold
@@ -11802,7 +11807,7 @@ fold_binary (enum tree_code code, tree t
 		  if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1)))
 		    fold_overflow_warning (("assuming signed overflow does "
 					    "not occur when assuming that "
-					    "(X - c) >= X is always true"),
+					    "(X - c) >= X is always false"),
 					   WARN_STRICT_OVERFLOW_ALL);
 		  return constant_boolean_node (0, type);
 		}
@@ -12729,6 +12734,7 @@ recursive_label:
     case tcc_comparison:
     case tcc_unary:
     case tcc_binary:
+    case tcc_binary_subcode:
     case tcc_statement:
     case tcc_vl_exp:
       len = TREE_OPERAND_LENGTH (expr);
@@ -12850,6 +12856,8 @@ fold_build2_stat (enum tree_code code, t
   htab_empty (ht);
 #endif
 
+  gcc_assert (TREE_CODE_CLASS (code) != tcc_binary_subcode);
+
   tem = fold_binary (code, type, op0, op1);
   if (!tem)
     tem = build2_stat (code, type, op0, op1 PASS_MEM_STAT);
@@ -14249,6 +14257,7 @@ fold_ignored_result (tree t)
 	break;
 
       case tcc_binary:
+      case tcc_binary_subcode:
       case tcc_comparison:
 	if (!TREE_SIDE_EFFECTS (TREE_OPERAND (t, 1)))
 	  t = TREE_OPERAND (t, 0);
Index: ipa-reference.c
===================================================================
--- ipa-reference.c	(revision 122923)
+++ ipa-reference.c	(working copy)
@@ -501,7 +501,8 @@ scan_for_static_refs (tree *tp, 
 	/* Next check the operands on the rhs to see if they are ok. */
 	switch (TREE_CODE_CLASS (TREE_CODE (rhs))) 
 	  {
-	  case tcc_binary:	    
+	  case tcc_binary:
+	  case tcc_binary_subcode:
 	  case tcc_comparison:	    
  	    {
  	      tree op0 = TREE_OPERAND (rhs, 0);
Index: tree-gimple.c
===================================================================
--- tree-gimple.c	(revision 122923)
+++ tree-gimple.c	(working copy)
@@ -48,6 +48,7 @@ is_gimple_formal_tmp_rhs (tree t)
     {
     case tcc_unary:
     case tcc_binary:
+    case tcc_binary_subcode:
     case tcc_comparison:
       return true;
 
@@ -501,6 +502,7 @@ recalculate_side_effects (tree t)
     case tcc_comparison:  /* a comparison expression */
     case tcc_unary:       /* a unary arithmetic expression */
     case tcc_binary:      /* a binary arithmetic expression */
+    case tcc_binary_subcode: /* binary arithmetic with subcode */
     case tcc_reference:   /* a reference */
     case tcc_vl_exp:        /* a function call */
       TREE_SIDE_EFFECTS (t) = TREE_THIS_VOLATILE (t);
Index: cp/cvt.c
===================================================================
--- cp/cvt.c	(revision 122923)
+++ cp/cvt.c	(working copy)
@@ -971,7 +971,8 @@ convert_to_void (tree expr, const char *
 	      class = TREE_CODE_CLASS (code);
 	      if (class == tcc_comparison
 		   || class == tcc_unary
-		   || (class == tcc_binary
+		   || ((class == tcc_binary
+			|| class == tcc_binary_subcode)
 		       && !(code == MODIFY_EXPR
 			    || code == INIT_EXPR
 			    || code == PREDECREMENT_EXPR
Index: cp/tree.c
===================================================================
--- cp/tree.c	(revision 122923)
+++ cp/tree.c	(working copy)
@@ -1836,6 +1836,7 @@ cp_tree_equal (tree t1, tree t2)
     {
     case tcc_unary:
     case tcc_binary:
+    case tcc_binary_subcode:
     case tcc_comparison:
     case tcc_expression:
     case tcc_vl_exp:
Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 122923)
+++ cp/pt.c	(working copy)
@@ -14864,6 +14864,7 @@ value_dependent_expression_p (tree expre
 
 	case tcc_comparison:
 	case tcc_binary:
+	case tcc_binary_subcode:
 	  return ((value_dependent_expression_p
 		   (TREE_OPERAND (expression, 0)))
 		  || (value_dependent_expression_p
Index: tree-ssa-loop-ivopts.c
===================================================================
--- tree-ssa-loop-ivopts.c	(revision 122923)
+++ tree-ssa-loop-ivopts.c	(working copy)
@@ -656,6 +656,7 @@ contains_abnormal_ssa_name_p (tree expr)
   switch (class)
     {
     case tcc_binary:
+    case tcc_binary_subcode:
     case tcc_comparison:
       if (contains_abnormal_ssa_name_p (TREE_OPERAND (expr, 1)))
 	return true;
Index: ipa-pure-const.c
===================================================================
--- ipa-pure-const.c	(revision 122923)
+++ ipa-pure-const.c	(working copy)
@@ -420,7 +420,8 @@ scan_function (tree *tp, 
 	/* Next check the operands on the rhs to see if they are ok. */
 	switch (TREE_CODE_CLASS (TREE_CODE (rhs))) 
 	  {
-	  case tcc_binary:	    
+	  case tcc_binary:
+	  case tcc_binary_subcode:
  	    {
  	      tree op0 = TREE_OPERAND (rhs, 0);
  	      tree op1 = TREE_OPERAND (rhs, 1);
Index: tree-ssa-propagate.c
===================================================================
--- tree-ssa-propagate.c	(revision 122923)
+++ tree-ssa-propagate.c	(working copy)
@@ -582,6 +582,7 @@ set_rhs (tree *stmt_p, tree expr)
       break;
 
     case tcc_binary:
+    case tcc_binary_subcode:
     case tcc_comparison:
       if (!is_gimple_val (TREE_OPERAND (expr, 0))
 	  || !is_gimple_val (TREE_OPERAND (expr, 1)))
@@ -654,7 +655,8 @@ set_rhs (tree *stmt_p, tree expr)
 	  || GIMPLE_STMT_P (expr))
       && ! EXPR_HAS_LOCATION (expr)
       && TREE_SIDE_EFFECTS (expr)
-      && TREE_CODE (expr) != LABEL_EXPR)
+      && TREE_CODE (expr) != LABEL_EXPR
+      && TREE_CODE_CLASS (TREE_CODE (expr)) != tcc_binary_subcode)
     SET_EXPR_LOCATION (expr, EXPR_LOCATION (stmt));
 
   switch (TREE_CODE (stmt))
Index: expr.c
===================================================================
--- expr.c	(revision 122923)
+++ expr.c	(working copy)
@@ -6212,6 +6212,7 @@ safe_from_p (rtx x, tree exp, int top_p)
 	      || safe_from_p (x, DECL_INITIAL (DECL_EXPR_DECL (exp)), 0));
 
     case tcc_binary:
+    case tcc_binary_subcode:
     case tcc_comparison:
       if (!safe_from_p (x, TREE_OPERAND (exp, 1), 0))
 	return 0;
@@ -6898,6 +6899,7 @@ expand_expr_real_1 (tree exp, rtx target
 			    modifier);
 
       else if (TREE_CODE_CLASS (code) == tcc_binary
+	       || TREE_CODE_CLASS (code) == tcc_binary_subcode
 	       || TREE_CODE_CLASS (code) == tcc_comparison
 	       || code == ARRAY_REF || code == ARRAY_RANGE_REF)
 	{
@@ -8326,7 +8328,8 @@ expand_expr_real_1 (tree exp, rtx target
       if (modifier == EXPAND_STACK_PARM)
 	target = 0;
       temp = expand_unop (mode,
-      			  optab_for_tree_code (NEGATE_EXPR, type),
+      			  optab_for_tree_code (NEGATE_EXPR, INVALID_SUBCODE,
+					       type),
 			  op0, target, 0);
       gcc_assert (temp);
       return REDUCE_BIT_FIELD (temp);
@@ -8364,7 +8367,7 @@ expand_expr_real_1 (tree exp, rtx target
       /* First try to do it with a special MIN or MAX instruction.
 	 If that does not win, use a conditional jump to select the proper
 	 value.  */
-      this_optab = optab_for_tree_code (code, type);
+      this_optab = optab_for_tree_code (code, INVALID_SUBCODE, type);
       temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
 			   OPTAB_WIDEN);
       if (temp != 0)
@@ -8821,7 +8824,7 @@ expand_expr_real_1 (tree exp, rtx target
         tree oprnd2 = TREE_OPERAND (exp, 2);
         rtx op2;
 
-        this_optab = optab_for_tree_code (code, type);
+        this_optab = optab_for_tree_code (code, INVALID_SUBCODE, type);
         expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
         op2 = expand_normal (oprnd2);
         temp = expand_ternary_op (mode, this_optab, op0, op1, op2, 
@@ -8860,73 +8863,83 @@ expand_expr_real_1 (tree exp, rtx target
     case REDUC_PLUS_EXPR:
       {
         op0 = expand_normal (TREE_OPERAND (exp, 0));
-        this_optab = optab_for_tree_code (code, type);
+        this_optab = optab_for_tree_code (code, INVALID_SUBCODE, type);
         temp = expand_unop (mode, this_optab, op0, target, unsignedp);
         gcc_assert (temp);
         return temp;
       }
 
-    case VEC_EXTRACT_EVEN_EXPR:
-    case VEC_EXTRACT_ODD_EXPR:
-      {
-        expand_operands (TREE_OPERAND (exp, 0),  TREE_OPERAND (exp, 1),
-                         NULL_RTX, &op0, &op1, 0);
-        this_optab = optab_for_tree_code (code, type);
-        temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
-                             OPTAB_WIDEN);
-        gcc_assert (temp);
-        return temp;
-      }
+    case VEC_BINARY_EXPR:
+      switch (TREE_SUBCODE (exp))
+	{
+	case VEC_EXTRACT_EVEN_EXPR:
+	case VEC_EXTRACT_ODD_EXPR:
+	  {
+	    expand_operands (TREE_OPERAND (exp, 0),  TREE_OPERAND (exp, 1),
+			     NULL_RTX, &op0, &op1, 0);
+	    this_optab = optab_for_tree_code (code, TREE_SUBCODE (exp),
+					      type);
+	    temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
+				 OPTAB_WIDEN);
+	    gcc_assert (temp);
+	    return temp;
+	  }
 
-    case VEC_INTERLEAVE_HIGH_EXPR:
-    case VEC_INTERLEAVE_LOW_EXPR:
-      {
-        expand_operands (TREE_OPERAND (exp, 0),  TREE_OPERAND (exp, 1),
-                         NULL_RTX, &op0, &op1, 0);
-        this_optab = optab_for_tree_code (code, type);
-        temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
-                             OPTAB_WIDEN);
-        gcc_assert (temp);
-        return temp;
-      }
+	case VEC_INTERLEAVE_HIGH_EXPR:
+	case VEC_INTERLEAVE_LOW_EXPR:
+	  {
+	    expand_operands (TREE_OPERAND (exp, 0),  TREE_OPERAND (exp, 1),
+			     NULL_RTX, &op0, &op1, 0);
+	    this_optab = optab_for_tree_code (code, TREE_SUBCODE (exp),
+					      type);
+	    temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
+				 OPTAB_WIDEN);
+	    gcc_assert (temp);
+	    return temp;
+	  }
 
-    case VEC_LSHIFT_EXPR:
-    case VEC_RSHIFT_EXPR:
-      {
-	target = expand_vec_shift_expr (exp, target);
-	return target;
-      }
+	case VEC_LSHIFT_EXPR:
+	case VEC_RSHIFT_EXPR:
+	  {
+	    target = expand_vec_shift_expr (exp, target);
+	    return target;
+	  }
 
-    case VEC_UNPACK_HI_EXPR:
-    case VEC_UNPACK_LO_EXPR:
-      {
-	op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
-	this_optab = optab_for_tree_code (code, type);
-	temp = expand_widen_pattern_expr (exp, op0, NULL_RTX, NULL_RTX,
-					  target, unsignedp);
-	gcc_assert (temp);
-	return temp;
-      }
+	case VEC_UNPACK_HI_EXPR:
+	case VEC_UNPACK_LO_EXPR:
+	  {
+	    op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
+	    this_optab = optab_for_tree_code (code, TREE_SUBCODE (exp),
+					      type);
+	    temp = expand_widen_pattern_expr (exp, op0, NULL_RTX, NULL_RTX,
+					      target, unsignedp);
+	    gcc_assert (temp);
+	    return temp;
+	  }
 
-    case VEC_WIDEN_MULT_HI_EXPR:
-    case VEC_WIDEN_MULT_LO_EXPR:
-      {
-	tree oprnd0 = TREE_OPERAND (exp, 0);
-	tree oprnd1 = TREE_OPERAND (exp, 1);
+	case VEC_WIDEN_MULT_HI_EXPR:
+	case VEC_WIDEN_MULT_LO_EXPR:
+	  {
+	    tree oprnd0 = TREE_OPERAND (exp, 0);
+	    tree oprnd1 = TREE_OPERAND (exp, 1);
 
-	expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, 0);
-	target = expand_widen_pattern_expr (exp, op0, op1, NULL_RTX,
-					    target, unsignedp);
-	gcc_assert (target);
-	return target;
-      }
+	    expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, 0);
+	    target = expand_widen_pattern_expr (exp, op0, op1, NULL_RTX,
+						target, unsignedp);
+	    gcc_assert (target);
+	    return target;
+	  }
 
-    case VEC_PACK_MOD_EXPR:
-    case VEC_PACK_SAT_EXPR:
-      {
-	mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
-	goto binop;
-      }
+	case VEC_PACK_MOD_EXPR:
+	case VEC_PACK_SAT_EXPR:
+	  {
+	    mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
+	    goto binop;
+	  }
+
+	default:
+	  gcc_unreachable ();
+	}
 
     default:
       return lang_hooks.expand_expr (exp, original_target, tmode,
@@ -8938,7 +8951,7 @@ expand_expr_real_1 (tree exp, rtx target
   expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
 		   subtarget, &op0, &op1, 0);
  binop2:
-  this_optab = optab_for_tree_code (code, type);
+  this_optab = optab_for_tree_code (code, INVALID_SUBCODE, type);
  binop3:
   if (modifier == EXPAND_STACK_PARM)
     target = 0;
Index: ada/trans.c
===================================================================
--- ada/trans.c	(revision 122923)
+++ ada/trans.c	(working copy)
@@ -6154,6 +6154,7 @@ gnat_stabilize_reference_1 (tree e, bool
       return e;
 
     case tcc_binary:
+    case tcc_binary_subcode:
       /* Recursively stabilize each operand.  */
       result = build2 (code, type,
 		       gnat_stabilize_reference_1 (TREE_OPERAND (e, 0), force),
Index: ada/utils2.c
===================================================================
--- ada/utils2.c	(revision 122923)
+++ ada/utils2.c	(working copy)
@@ -294,6 +294,7 @@ contains_null_expr (tree exp)
 
     case tcc_comparison:
     case tcc_binary:
+    case tcc_binary_subcode:
       tem = contains_null_expr (TREE_OPERAND (exp, 0));
       if (tem)
 	return tem;
Index: tree-eh.c
===================================================================
--- tree-eh.c	(revision 122923)
+++ tree-eh.c	(working copy)
@@ -1848,7 +1848,8 @@ tree_could_trap_p (tree expr)
 
   if (TREE_CODE_CLASS (code) == tcc_comparison
       || TREE_CODE_CLASS (code) == tcc_unary
-      || TREE_CODE_CLASS (code) == tcc_binary)
+      || TREE_CODE_CLASS (code) == tcc_binary
+      || TREE_CODE_CLASS (code) == tcc_binary_subcode)
     {
       t = TREE_TYPE (expr);
       fp_operation = FLOAT_TYPE_P (t);
Index: tree-vectorizer.c
===================================================================
--- tree-vectorizer.c	(revision 122923)
+++ tree-vectorizer.c	(working copy)
@@ -1770,7 +1770,10 @@ vect_is_simple_use (tree operand, loop_v
 bool
 supportable_widening_operation (enum tree_code code, tree stmt, tree vectype,
                                 tree *decl1, tree *decl2,
-                                enum tree_code *code1, enum tree_code *code2)
+                                enum tree_code *code1,
+				unsigned int *subcode1,
+				enum tree_code *code2,
+				unsigned int *subcode2)
 {
   stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
   bool ordered_p;
@@ -1780,7 +1783,7 @@ supportable_widening_operation (enum tre
   tree expr = GIMPLE_STMT_OPERAND (stmt, 1);
   tree type = TREE_TYPE (expr);
   tree wide_vectype = get_vectype_for_scalar_type (type);
-  enum tree_code c1, c2;
+  unsigned int c1, c2;
 
   /* The result of a vectorized widening operation usually requires two vectors 
      (because the widened results do not fit int one vector). The generated 
@@ -1813,6 +1816,7 @@ supportable_widening_operation (enum tre
         fprintf (vect_dump, "Unordered widening operation detected.");
 
       *code1 = *code2 = CALL_EXPR;
+      *subcode1 = *subcode2 = INVALID_SUBCODE;
       *decl1 = targetm.vectorize.builtin_mul_widen_even (vectype);
       *decl2 = targetm.vectorize.builtin_mul_widen_odd (vectype);
       return true;
@@ -1850,10 +1854,12 @@ supportable_widening_operation (enum tre
       gcc_unreachable ();
     }
 
-  *code1 = c1;
-  *code2 = c2;
-  optab1 = optab_for_tree_code (c1, vectype);
-  optab2 = optab_for_tree_code (c2, vectype);
+  *code1 = VEC_BINARY_EXPR;
+  *subcode1 = c1;
+  *code2 = VEC_BINARY_EXPR;
+  *subcode2 = c2;
+  optab1 = optab_for_tree_code (VEC_BINARY_EXPR, c1, vectype);
+  optab2 = optab_for_tree_code (VEC_BINARY_EXPR, c2, vectype);
 
   if (!optab1 || !optab2)
     return false;
Index: tree-vectorizer.h
===================================================================
--- tree-vectorizer.h	(revision 122923)
+++ tree-vectorizer.h	(working copy)
@@ -393,7 +393,9 @@ extern enum dr_alignment_support vect_su
   (struct data_reference *);
 extern bool reduction_code_for_scalar_code (enum tree_code, enum tree_code *);
 extern bool supportable_widening_operation (enum tree_code, tree, tree,
-  tree *, tree *, enum tree_code *, enum tree_code *);
+					    tree *, tree *, enum tree_code *,
+					    unsigned int *, enum tree_code *,
+					    unsigned int *);
 /* Creation and deletion of loop and stmt info structs.  */
 extern loop_vec_info new_loop_vec_info (struct loop *loop);
 extern void destroy_loop_vec_info (loop_vec_info);
Index: ipa-type-escape.c
===================================================================
--- ipa-type-escape.c	(revision 122923)
+++ ipa-type-escape.c	(working copy)
@@ -1528,7 +1528,8 @@ scan_for_refs (tree *tp, int *walk_subtr
 	/* Next check the operands on the rhs to see if they are ok. */
 	switch (TREE_CODE_CLASS (TREE_CODE (rhs))) 
 	  {
-	  case tcc_binary:	    
+	  case tcc_binary:
+	  case tcc_binary_subcode:
  	    {
  	      tree op0 = TREE_OPERAND (rhs, 0);
 	      tree type0 = get_canon_type (TREE_TYPE (op0), false, false);
Index: alias.c
===================================================================
--- alias.c	(revision 122923)
+++ alias.c	(working copy)
@@ -424,6 +424,7 @@ find_base_decl (tree t)
       return find_base_decl (TREE_OPERAND (t, 0));
 
     case tcc_binary:
+    case tcc_binary_subcode:
       /* Return 0 if found in neither or both are the same.  */
       d0 = find_base_decl (TREE_OPERAND (t, 0));
       d1 = find_base_decl (TREE_OPERAND (t, 1));
Index: gimplify.c
===================================================================
--- gimplify.c	(revision 122923)
+++ gimplify.c	(working copy)
@@ -5180,6 +5180,7 @@ goa_stabilize_expr (tree *expr_p, tree *
   switch (TREE_CODE_CLASS (TREE_CODE (expr)))
     {
     case tcc_binary:
+    case tcc_binary_subcode:
       saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1), pre_p,
 				     lhs_addr, lhs_var);
     case tcc_unary:
@@ -5893,6 +5894,7 @@ gimplify_expr (tree *expr_p, tree *pre_p
 	      break;
 
 	    case tcc_binary:
+	    case tcc_binary_subcode:
 	    expr_2:
 	      {
 		enum gimplify_status r0, r1;
Index: tree.def
===================================================================
--- tree.def	(revision 122923)
+++ tree.def	(working copy)
@@ -1066,47 +1066,15 @@ DEFTREECODE (WIDEN_SUM_EXPR, "widen_sum_
    the arguments from type t1 to type t2, and then multiplying them.  */
 DEFTREECODE (WIDEN_MULT_EXPR, "widen_mult_expr", tcc_binary, 2)
 
-/* Whole vector left/right shift in bits.
-   Operand 0 is a vector to be shifted.
-   Operand 1 is an integer shift amount in bits.  */
-DEFTREECODE (VEC_LSHIFT_EXPR, "vec_lshift_expr", tcc_binary, 2)
-DEFTREECODE (VEC_RSHIFT_EXPR, "vec_rshift_expr", tcc_binary, 2)
+/* Binary vector operations.  The subcode indicates the actual
+   operation.  */
+DEFTREECODE (VEC_BINARY_EXPR, "vec", tcc_binary_subcode, 2)
 
 /* GIMPLE tree codes.  */
 
 /* Assignment expression.  Operand 0 is the what to set; 1, the new value.  */
 DEFTREECODE (GIMPLE_MODIFY_STMT, "gimple_modify_stmt", tcc_gimple_stmt, 2)
 
-/* Widening vector multiplication.
-   The two operands are vectors with N elements of size S. Multiplying the
-   elements of the two vectors will result in N products of size 2*S.
-   VEC_WIDEN_MULT_HI_EXPR computes the N/2 high products.
-   VEC_WIDEN_MULT_LO_EXPR computes the N/2 low products.  */
-DEFTREECODE (VEC_WIDEN_MULT_HI_EXPR, "widen_mult_hi_expr", tcc_binary, 2)
-DEFTREECODE (VEC_WIDEN_MULT_LO_EXPR, "widen_mult_hi_expr", tcc_binary, 2)
-
-/* Unpack (extract and promote/widen) the high/low elements of the input vector
-   into the output vector. The input vector has twice as many elements
-   as the output vector, that are half the size of the elements
-   of the output vector.  This is used to support type promotion. */
-DEFTREECODE (VEC_UNPACK_HI_EXPR, "vec_unpack_hi_expr", tcc_unary, 1)
-DEFTREECODE (VEC_UNPACK_LO_EXPR, "vec_unpack_lo_expr", tcc_unary, 1)
-
-/* Pack (demote/narrow and merge) the elements of the two input vectors
-   into the output vector, using modulo/saturating arithmetic.
-   The elements of the input vectors are twice the size of the elements of the
-   output vector.  This is used to support type demotion.  */
-DEFTREECODE (VEC_PACK_MOD_EXPR, "vec_pack_mod_expr", tcc_binary, 2)
-DEFTREECODE (VEC_PACK_SAT_EXPR, "vec_pack_sat_expr", tcc_binary, 2)
-                                                                                
-/* Extract even/odd fields from vectors.  */
-DEFTREECODE (VEC_EXTRACT_EVEN_EXPR, "vec_extracteven_expr", tcc_binary, 2)
-DEFTREECODE (VEC_EXTRACT_ODD_EXPR, "vec_extractodd_expr", tcc_binary, 2)
-
-/* Merge input vectors interleaving their fields.  */
-DEFTREECODE (VEC_INTERLEAVE_HIGH_EXPR, "vec_interleavehigh_expr", tcc_binary, 2)
-DEFTREECODE (VEC_INTERLEAVE_LOW_EXPR, "vec_interleavelow_expr", tcc_binary, 2)
-
 /*
 Local variables:
 mode:c
Index: tree-ssa-pre.c
===================================================================
--- tree-ssa-pre.c	(revision 122923)
+++ tree-ssa-pre.c	(working copy)
@@ -1212,6 +1212,7 @@ phi_translate (tree expr, bitmap_set_t s
       break;
 
     case tcc_binary:
+    case tcc_binary_subcode:
     case tcc_comparison:
       {
 	tree oldop1 = TREE_OPERAND (expr, 0);
@@ -1456,6 +1457,7 @@ valid_in_sets (bitmap_set_t set1, bitmap
  switch (TREE_CODE_CLASS (TREE_CODE (expr)))
     {
     case tcc_binary:
+    case tcc_binary_subcode:
     case tcc_comparison:
       {
 	tree op1 = TREE_OPERAND (expr, 0);
@@ -3206,6 +3208,7 @@ create_value_expr_from (tree expr, basic
 
   gcc_assert (TREE_CODE_CLASS (code) == tcc_unary
 	      || TREE_CODE_CLASS (code) == tcc_binary
+	      || TREE_CODE_CLASS (code) == tcc_binary_subcode
 	      || TREE_CODE_CLASS (code) == tcc_comparison
 	      || TREE_CODE_CLASS (code) == tcc_reference
 	      || TREE_CODE_CLASS (code) == tcc_expression
@@ -3217,7 +3220,8 @@ create_value_expr_from (tree expr, basic
     pool = unary_node_pool;
   else if (TREE_CODE_CLASS (code) == tcc_reference)
     pool = reference_node_pool;
-  else if (TREE_CODE_CLASS (code) == tcc_binary)
+  else if (TREE_CODE_CLASS (code) == tcc_binary
+	   || TREE_CODE_CLASS (code) == tcc_binary_subcode)
     pool = binary_node_pool;
   else if (TREE_CODE_CLASS (code) == tcc_comparison)
     pool = comparison_node_pool;
Index: print-tree.c
===================================================================
--- print-tree.c	(revision 122923)
+++ print-tree.c	(working copy)
@@ -229,6 +229,8 @@ print_node (FILE *file, const char *pref
 
   /* Print the slot this node is in, and its code, and address.  */
   fprintf (file, "%s <%s", prefix, tree_code_name[(int) TREE_CODE (node)]);
+  if (TREE_CODE_CLASS (TREE_CODE (node)) == tcc_binary_subcode)
+    fprintf (file, "/%s", tree_subcode_name[(int) TREE_SUBCODE (node)]);
   dump_addr (file, " ", node);
 
   /* Print the name, if any.  */
@@ -659,6 +661,7 @@ print_node (FILE *file, const char *pref
     case tcc_comparison:
     case tcc_unary:
     case tcc_binary:
+    case tcc_binary_subcode:
     case tcc_reference:
     case tcc_statement:
     case tcc_vl_exp:
Index: tree-vect-patterns.c
===================================================================
--- tree-vect-patterns.c	(revision 122923)
+++ tree-vect-patterns.c	(working copy)
@@ -348,6 +348,7 @@ vect_recog_widen_mult_pattern (tree last
   tree vectype;
   tree dummy;
   enum tree_code dummy_code;
+  unsigned int dummy_subcode;
 
   if (TREE_CODE (last_stmt) != GIMPLE_MODIFY_STMT)
     return NULL;
@@ -388,8 +389,9 @@ vect_recog_widen_mult_pattern (tree last
   vectype = get_vectype_for_scalar_type (half_type0);
   if (!vectype
       || !supportable_widening_operation (WIDEN_MULT_EXPR, last_stmt, vectype,
-                                       &dummy, &dummy, &dummy_code,
-                                       &dummy_code))
+					  &dummy, &dummy, &dummy_code,
+					  &dummy_subcode, &dummy_code,
+					  &dummy_subcode))
     return NULL;
 
   *type_in = vectype;
@@ -649,7 +651,8 @@ vect_pattern_recog_1 (
       if (!pattern_vectype)
         return;
 
-      optab = optab_for_tree_code (TREE_CODE (pattern_expr), pattern_vectype);
+      optab = optab_for_tree_code (TREE_CODE (pattern_expr), INVALID_SUBCODE,
+				   pattern_vectype);
       vec_mode = TYPE_MODE (pattern_vectype);
       if (!optab
           || (icode = optab->handlers[(int) vec_mode].insn_code) ==
Index: tree-inline.c
===================================================================
--- tree-inline.c	(revision 122923)
+++ tree-inline.c	(working copy)
@@ -2098,8 +2098,6 @@ estimate_num_insns_1 (tree *tp, int *wal
     case RSHIFT_EXPR:
     case LROTATE_EXPR:
     case RROTATE_EXPR:
-    case VEC_LSHIFT_EXPR:
-    case VEC_RSHIFT_EXPR:
 
     case BIT_IOR_EXPR:
     case BIT_XOR_EXPR:
@@ -2147,24 +2145,36 @@ estimate_num_insns_1 (tree *tp, int *wal
     case REDUC_PLUS_EXPR:
     case WIDEN_SUM_EXPR:
     case DOT_PROD_EXPR: 
-    case VEC_WIDEN_MULT_HI_EXPR:
-    case VEC_WIDEN_MULT_LO_EXPR:
-    case VEC_UNPACK_HI_EXPR:
-    case VEC_UNPACK_LO_EXPR:
-    case VEC_PACK_MOD_EXPR:
-    case VEC_PACK_SAT_EXPR:
 
     case WIDEN_MULT_EXPR:
 
-    case VEC_EXTRACT_EVEN_EXPR:
-    case VEC_EXTRACT_ODD_EXPR:
-    case VEC_INTERLEAVE_HIGH_EXPR:
-    case VEC_INTERLEAVE_LOW_EXPR:
-
     case RESX_EXPR:
       d->count += 1;
       break;
 
+    case VEC_BINARY_EXPR:
+      switch (TREE_SUBCODE (x))
+	{
+	case VEC_LSHIFT_EXPR:
+	case VEC_RSHIFT_EXPR:
+	case VEC_WIDEN_MULT_HI_EXPR:
+	case VEC_WIDEN_MULT_LO_EXPR:
+	case VEC_UNPACK_HI_EXPR:
+	case VEC_UNPACK_LO_EXPR:
+	case VEC_PACK_MOD_EXPR:
+	case VEC_PACK_SAT_EXPR:
+	case VEC_EXTRACT_EVEN_EXPR:
+	case VEC_EXTRACT_ODD_EXPR:
+	case VEC_INTERLEAVE_HIGH_EXPR:
+	case VEC_INTERLEAVE_LOW_EXPR:
+	  d->count += 1;
+	  break;
+
+	default:
+	  gcc_unreachable ();
+	}
+      break;
+
     case SWITCH_EXPR:
       /* TODO: Cost of a switch should be derived from the number of
 	 branches.  */
Index: tree-vect-transform.c
===================================================================
--- tree-vect-transform.c	(revision 122923)
+++ tree-vect-transform.c	(working copy)
@@ -1262,6 +1262,7 @@ vect_create_epilog_for_reduction (tree v
   else
     {
       enum tree_code shift_code = 0;
+      unsigned int shift_subcode;
       bool have_whole_vector_shift = true;
       int bit_offset;
       int element_bitsize = tree_low_cst (bitsize, 1);
@@ -1269,7 +1270,10 @@ vect_create_epilog_for_reduction (tree v
       tree vec_temp;
 
       if (vec_shr_optab->handlers[mode].insn_code != CODE_FOR_nothing)
-	shift_code = VEC_RSHIFT_EXPR;
+	{
+	  shift_code = VEC_BINARY_EXPR;
+	  shift_subcode = VEC_RSHIFT_EXPR;
+	}
       else
 	have_whole_vector_shift = false;
 
@@ -1283,7 +1287,7 @@ vect_create_epilog_for_reduction (tree v
 	have_whole_vector_shift = false;
       else
 	{
-	  optab optab = optab_for_tree_code (code, vectype);
+	  optab optab = optab_for_tree_code (code, INVALID_SUBCODE, vectype);
 	  if (optab->handlers[mode].insn_code == CODE_FOR_nothing)
 	    have_whole_vector_shift = false;
 	}
@@ -1308,7 +1312,8 @@ vect_create_epilog_for_reduction (tree v
 	       bit_offset /= 2)
 	    {
 	      tree bitpos = size_int (bit_offset);
-	      tree tmp = build2 (shift_code, vectype, new_temp, bitpos);
+	      tree tmp = build2_subcode (shift_code, shift_subcode,
+					 vectype, new_temp, bitpos);
 	      epilog_stmt = build_gimple_modify_stmt (vec_dest, tmp);
 	      new_name = make_ssa_name (vec_dest, epilog_stmt);
 	      GIMPLE_STMT_OPERAND (epilog_stmt, 0) = new_name;
@@ -1589,7 +1594,7 @@ vectorizable_reduction (tree stmt, block
   /* 4. Supportable by target?  */
 
   /* 4.1. check support for the operation in the loop  */
-  optab = optab_for_tree_code (code, vectype);
+  optab = optab_for_tree_code (code, INVALID_SUBCODE, vectype);
   if (!optab)
     {
       if (vect_print_dump_info (REPORT_DETAILS))
@@ -1670,7 +1675,8 @@ vectorizable_reduction (tree stmt, block
 
   if (!reduction_code_for_scalar_code (orig_code, &epilog_reduc_code))
     return false;
-  reduc_optab = optab_for_tree_code (epilog_reduc_code, vectype);
+  reduc_optab = optab_for_tree_code (epilog_reduc_code, INVALID_SUBCODE,
+				     vectype);
   if (!reduc_optab)
     {
       if (vect_print_dump_info (REPORT_DETAILS))
@@ -2266,7 +2272,7 @@ vectorizable_operation (tree stmt, block
 
   operation = GIMPLE_STMT_OPERAND (stmt, 1);
   code = TREE_CODE (operation);
-  optab = optab_for_tree_code (code, vectype);
+  optab = optab_for_tree_code (code, INVALID_SUBCODE, vectype);
 
   /* Support only unary or binary operations.  */
   op_type = TREE_OPERAND_LENGTH (operation);
@@ -2490,6 +2496,7 @@ vectorizable_type_demotion (tree stmt, b
   stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
   loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info);
   enum tree_code code;
+  unsigned int subcode;
   tree new_temp;
   tree def, def_stmt;
   enum vect_def_type dt0;
@@ -2559,8 +2566,9 @@ vectorizable_type_demotion (tree stmt, b
     }
                                                                                 
   /* Supportable by target?  */
-  code = VEC_PACK_MOD_EXPR;
-  optab = optab_for_tree_code (VEC_PACK_MOD_EXPR, vectype_in);
+  code = VEC_BINARY_EXPR;
+  subcode = VEC_PACK_MOD_EXPR;
+  optab = optab_for_tree_code (VEC_BINARY_EXPR, VEC_PACK_MOD_EXPR, vectype_in);
   if (!optab)
     return false;
                                                                                 
@@ -2605,7 +2613,8 @@ vectorizable_type_demotion (tree stmt, b
 	}
                                                                                 
       /* Arguments are ready. Create the new vector stmt.  */
-      expr = build2 (code, vectype_out, vec_oprnd0, vec_oprnd1);
+      expr = build2_subcode (code, subcode, vectype_out, vec_oprnd0,
+			     vec_oprnd1);
       new_stmt = build_gimple_modify_stmt (vec_dest, expr);
       new_temp = make_ssa_name (vec_dest, new_stmt);
       GIMPLE_STMT_OPERAND (new_stmt, 0) = new_temp;
@@ -2626,15 +2635,17 @@ vectorizable_type_demotion (tree stmt, b
 
 /* Function vect_gen_widened_results_half
 
-   Create a vector stmt whose code, type, number of arguments, and result
-   variable are CODE, VECTYPE, OP_TYPE, and VEC_DEST, and its arguments are 
-   VEC_OPRND0 and VEC_OPRND1. The new vector stmt is to be inserted at BSI.
-   In the case that CODE is a CALL_EXPR, this means that a call to DECL
-   needs to be created (DECL is a function-decl of a target-builtin).
-   STMT is the original scalar stmt that we are vectorizing.  */
+   Create a vector stmt whose code, subcode, type, number of
+   arguments, and result variable are CODE, SUBCODE, VECTYPE, OP_TYPE,
+   and VEC_DEST, and its arguments are VEC_OPRND0 and VEC_OPRND1. The
+   new vector stmt is to be inserted at BSI.  In the case that CODE is
+   a CALL_EXPR, this means that a call to DECL needs to be created
+   (DECL is a function-decl of a target-builtin).  STMT is the
+   original scalar stmt that we are vectorizing.  */
 
 static tree
-vect_gen_widened_results_half (enum tree_code code, tree vectype, tree decl,
+vect_gen_widened_results_half (enum tree_code code, unsigned int subcode,
+			       tree vectype, tree decl,
                                tree vec_oprnd0, tree vec_oprnd1, int op_type,
                                tree vec_dest, block_stmt_iterator *bsi,
 			       tree stmt)
@@ -2658,8 +2669,14 @@ vect_gen_widened_results_half (enum tree
     { 
       /* Generic support */ 
       gcc_assert (op_type == TREE_CODE_LENGTH (code)); 
-      if (op_type == binary_op) 
-        expr = build2 (code, vectype, vec_oprnd0, vec_oprnd1); 
+      if (op_type == binary_op)
+	{
+	  if (TREE_CODE_CLASS (code) != tcc_binary_subcode)
+	    expr = build2 (code, vectype, vec_oprnd0, vec_oprnd1);
+	  else
+	    expr = build2_subcode (code, subcode, vectype, vec_oprnd0,
+				   vec_oprnd1);
+	}
       else  
         expr = build1 (code, vectype, vec_oprnd0); 
     } 
@@ -2702,6 +2719,7 @@ vectorizable_type_promotion (tree stmt, 
   stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
   loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info);
   enum tree_code code, code1 = CODE_FOR_nothing, code2 = CODE_FOR_nothing;
+  unsigned int subcode1, subcode2;
   tree decl1 = NULL_TREE, decl2 = NULL_TREE;
   int op_type; 
   tree def, def_stmt;
@@ -2779,7 +2797,8 @@ vectorizable_type_promotion (tree stmt, 
 
   /* Supportable by target?  */
   if (!supportable_widening_operation (code, stmt, vectype_in,
-				       &decl1, &decl2, &code1, &code2))
+				       &decl1, &decl2, &code1, &subcode1,
+				       &code2, &subcode2))
     return false;
 
   STMT_VINFO_VECTYPE (stmt_info) = vectype_in;
@@ -2826,8 +2845,9 @@ vectorizable_type_promotion (tree stmt, 
          The vectorized stmt can be expressed as a call to a taregt builtin,
          or a using a tree-code.  */
       /* Generate first half of the widened result:  */
-      new_stmt = vect_gen_widened_results_half (code1, vectype_out, decl1, 
-                        vec_oprnd0, vec_oprnd1, op_type, vec_dest, bsi, stmt);
+      new_stmt = vect_gen_widened_results_half (code1, subcode1, vectype_out,
+						decl1, vec_oprnd0, vec_oprnd1,
+						op_type, vec_dest, bsi, stmt);
       if (j == 0)
         STMT_VINFO_VEC_STMT (stmt_info) = new_stmt;
       else
@@ -2835,8 +2855,9 @@ vectorizable_type_promotion (tree stmt, 
       prev_stmt_info = vinfo_for_stmt (new_stmt);
 
       /* Generate second half of the widened result:  */
-      new_stmt = vect_gen_widened_results_half (code2, vectype_out, decl2,
-                        vec_oprnd0, vec_oprnd1, op_type, vec_dest, bsi, stmt);
+      new_stmt = vect_gen_widened_results_half (code2, subcode2, vectype_out,
+						decl2, vec_oprnd0, vec_oprnd1,
+						op_type, vec_dest, bsi, stmt);
       STMT_VINFO_RELATED_STMT (prev_stmt_info) = new_stmt;
       prev_stmt_info = vinfo_for_stmt (new_stmt);
 
@@ -2861,9 +2882,11 @@ vect_strided_store_supported (tree vecty
   mode = (int) TYPE_MODE (vectype);
       
   /* Check that the operation is supported.  */
-  interleave_high_optab = optab_for_tree_code (VEC_INTERLEAVE_HIGH_EXPR, 
+  interleave_high_optab = optab_for_tree_code (VEC_BINARY_EXPR,
+					       VEC_INTERLEAVE_HIGH_EXPR, 
 					       vectype);
-  interleave_low_optab = optab_for_tree_code (VEC_INTERLEAVE_LOW_EXPR, 
+  interleave_low_optab = optab_for_tree_code (VEC_BINARY_EXPR,
+					      VEC_INTERLEAVE_LOW_EXPR, 
 					      vectype);
   if (!interleave_high_optab || !interleave_low_optab)
     {
@@ -2986,9 +3009,11 @@ vect_permute_store_chain (VEC(tree,heap)
 	  DECL_GIMPLE_REG_P (perm_dest) = 1;
 	  add_referenced_var (perm_dest);
           if (BYTES_BIG_ENDIAN)
-	    tmp = build2 (VEC_INTERLEAVE_HIGH_EXPR, vectype, vect1, vect2); 
+	    tmp = build2_subcode (VEC_BINARY_EXPR, VEC_INTERLEAVE_HIGH_EXPR,
+				  vectype, vect1, vect2); 
 	  else
-	    tmp = build2 (VEC_INTERLEAVE_LOW_EXPR, vectype, vect1, vect2);
+	    tmp = build2_subcode (VEC_BINARY_EXPR, VEC_INTERLEAVE_LOW_EXPR,
+				  vectype, vect1, vect2);
 	  perm_stmt = build_gimple_modify_stmt (perm_dest, tmp);
 	  high = make_ssa_name (perm_dest, perm_stmt);
 	  GIMPLE_STMT_OPERAND (perm_stmt, 0) = high;
@@ -3004,9 +3029,11 @@ vect_permute_store_chain (VEC(tree,heap)
 	  DECL_GIMPLE_REG_P (perm_dest) = 1;
 	  add_referenced_var (perm_dest);
 	  if (BYTES_BIG_ENDIAN)
-	    tmp = build2 (VEC_INTERLEAVE_LOW_EXPR, vectype, vect1, vect2);
+	    tmp = build2_subcode (VEC_BINARY_EXPR, VEC_INTERLEAVE_LOW_EXPR,
+				  vectype, vect1, vect2);
 	  else
-	    tmp = build2 (VEC_INTERLEAVE_HIGH_EXPR, vectype, vect1, vect2);
+	    tmp = build2_subcode (VEC_BINARY_EXPR, VEC_INTERLEAVE_HIGH_EXPR,
+				  vectype, vect1, vect2);
 	  perm_stmt = build_gimple_modify_stmt (perm_dest, tmp);
 	  low = make_ssa_name (perm_dest, perm_stmt);
 	  GIMPLE_STMT_OPERAND (perm_stmt, 0) = low;
@@ -3411,7 +3438,9 @@ vect_strided_load_supported (tree vectyp
 
   mode = (int) TYPE_MODE (vectype);
 
-  perm_even_optab = optab_for_tree_code (VEC_EXTRACT_EVEN_EXPR, vectype);
+  perm_even_optab = optab_for_tree_code (VEC_BINARY_EXPR,
+					 VEC_EXTRACT_EVEN_EXPR,
+					 vectype);
   if (!perm_even_optab)
     {
       if (vect_print_dump_info (REPORT_DETAILS))
@@ -3426,7 +3455,9 @@ vect_strided_load_supported (tree vectyp
       return false;
     }
 
-  perm_odd_optab = optab_for_tree_code (VEC_EXTRACT_ODD_EXPR, vectype);
+  perm_odd_optab = optab_for_tree_code (VEC_BINARY_EXPR,
+					VEC_EXTRACT_ODD_EXPR,
+					vectype);
   if (!perm_odd_optab)
     {
       if (vect_print_dump_info (REPORT_DETAILS))
@@ -3550,8 +3581,8 @@ vect_permute_load_chain (VEC(tree,heap) 
 	  DECL_GIMPLE_REG_P (perm_dest) = 1;
 	  add_referenced_var (perm_dest);
 
-	  tmp = build2 (VEC_EXTRACT_EVEN_EXPR, vectype,
-			first_vect, second_vect);
+	  tmp = build2_subcode (VEC_BINARY_EXPR, VEC_EXTRACT_EVEN_EXPR,
+				vectype, first_vect, second_vect);
 	  perm_stmt = build_gimple_modify_stmt (perm_dest, tmp);
 
 	  data_ref = make_ssa_name (perm_dest, perm_stmt);
@@ -3566,8 +3597,8 @@ vect_permute_load_chain (VEC(tree,heap) 
 	  DECL_GIMPLE_REG_P (perm_dest) = 1;
 	  add_referenced_var (perm_dest);
 
-	  tmp = build2 (VEC_EXTRACT_ODD_EXPR, vectype, 
-			first_vect, second_vect);
+	  tmp = build2_subcode (VEC_BINARY_EXPR, VEC_EXTRACT_ODD_EXPR,
+				vectype, first_vect, second_vect);
 	  perm_stmt = build_gimple_modify_stmt (perm_dest, tmp);
 	  data_ref = make_ssa_name (perm_dest, perm_stmt);
 	  GIMPLE_STMT_OPERAND (perm_stmt, 0) = data_ref;
Index: tree-vect-generic.c
===================================================================
--- tree-vect-generic.c	(revision 122923)
+++ tree-vect-generic.c	(working copy)
@@ -98,7 +98,8 @@ build_word_mode_vector_type (int nunits)
 }
 
 typedef tree (*elem_op_func) (block_stmt_iterator *,
-			      tree, tree, tree, tree, tree, enum tree_code);
+			      tree, tree, tree, tree, tree, enum tree_code,
+			      unsigned int);
 
 static inline tree
 tree_vec_extract (block_stmt_iterator *bsi, tree type,
@@ -113,7 +114,7 @@ tree_vec_extract (block_stmt_iterator *b
 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)
+	 enum tree_code code, unsigned int subcode ATTRIBUTE_UNUSED)
 {
   a = tree_vec_extract (bsi, inner_type, a, bitsize, bitpos);
   return gimplify_build1 (bsi, code, inner_type, a);
@@ -121,11 +122,14 @@ do_unop (block_stmt_iterator *bsi, tree 
 
 static tree
 do_binop (block_stmt_iterator *bsi, tree inner_type, tree a, tree b,
-	  tree bitpos, tree bitsize, enum tree_code code)
+	  tree bitpos, tree bitsize, enum tree_code code, unsigned int subcode)
 {
   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);
+  if (TREE_CODE_CLASS (code) != tcc_binary_subcode)
+    return gimplify_build2 (bsi, code, inner_type, a, b);
+  else
+    return gimplify_build2_subcode (bsi, code, subcode, inner_type, a, b);
 }
 
 /* Expand vector addition to scalars.  This does bit twiddling
@@ -144,7 +148,7 @@ do_binop (block_stmt_iterator *bsi, tree
 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)
+	       enum tree_code code, unsigned int subcode)
 {
   tree inner_type = TREE_TYPE (TREE_TYPE (a));
   unsigned HOST_WIDE_INT max;
@@ -168,7 +172,11 @@ do_plus_minus (block_stmt_iterator *bsi,
     }
 
   signs = gimplify_build2 (bsi, BIT_AND_EXPR, word_type, signs, high_bits);
-  result_low = gimplify_build2 (bsi, code, word_type, a_low, b_low);
+  if (TREE_CODE_CLASS (code) != tcc_binary_subcode)
+    result_low = gimplify_build2 (bsi, code, word_type, a_low, b_low);
+  else
+    result_low = gimplify_build2_subcode (bsi, code, subcode, word_type,
+					  a_low, b_low);
   return gimplify_build2 (bsi, BIT_XOR_EXPR, word_type, result_low, signs);
 }
 
@@ -200,7 +208,8 @@ do_negate (block_stmt_iterator *bsi, tre
 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 a, tree b, enum tree_code code,
+			 unsigned int subcode)
 {
   VEC(constructor_elt,gc) *v;
   tree part_width = TYPE_SIZE (inner_type);
@@ -214,7 +223,8 @@ expand_vector_piecewise (block_stmt_iter
   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);
+      tree result = f (bsi, inner_type, a, b, index, part_width, code,
+		       subcode);
       constructor_elt *ce = VEC_quick_push (constructor_elt, v, NULL);
       ce->index = NULL_TREE;
       ce->value = result;
@@ -242,13 +252,13 @@ expand_vector_parallel (block_stmt_itera
   if (TYPE_MODE (TREE_TYPE (type)) == word_mode)
      return expand_vector_piecewise (bsi, f,
 				     type, TREE_TYPE (type),
-				     a, b, code);
+				     a, b, code, INVALID_SUBCODE);
   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);
+					a, b, code, INVALID_SUBCODE);
       result = gimplify_val (bsi, word_type, result);
     }
   else
@@ -256,7 +266,8 @@ expand_vector_parallel (block_stmt_itera
       /* 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);
+      result = f (bsi, compute_type, a, b, NULL_TREE, NULL_TREE, code,
+		  INVALID_SUBCODE);
     }
 
   return result;
@@ -283,12 +294,12 @@ expand_vector_addition (block_stmt_itera
   else
     return expand_vector_piecewise (bsi, f,
 				    type, TREE_TYPE (type),
-				    a, b, code);
+				    a, b, code, INVALID_SUBCODE);
 }
 
 static tree
 expand_vector_operation (block_stmt_iterator *bsi, tree type, tree compute_type,
-			 tree rhs, enum tree_code code)
+			 tree rhs, enum tree_code code, unsigned int subcode)
 {
   enum machine_mode compute_mode = TYPE_MODE (compute_type);
 
@@ -333,11 +344,11 @@ expand_vector_operation (block_stmt_iter
   if (TREE_CODE_CLASS (code) == tcc_unary)
     return expand_vector_piecewise (bsi, do_unop, type, compute_type,
 				    TREE_OPERAND (rhs, 0),
-				    NULL_TREE, code);
+				    NULL_TREE, code, subcode);
   else
     return expand_vector_piecewise (bsi, do_binop, type, compute_type,
 				    TREE_OPERAND (rhs, 0),
-				    TREE_OPERAND (rhs, 1), code);
+				    TREE_OPERAND (rhs, 1), code, subcode);
 }
 
 /* Return a type for the widest vector mode whose components are of mode
@@ -373,6 +384,7 @@ expand_vector_operations_1 (block_stmt_i
   tree stmt = bsi_stmt (*bsi);
   tree *p_lhs, *p_rhs, lhs, rhs, type, compute_type;
   enum tree_code code;
+  unsigned int subcode;
   enum machine_mode compute_mode;
   optab op;
 
@@ -402,7 +414,8 @@ expand_vector_operations_1 (block_stmt_i
 
   code = TREE_CODE (rhs);
   if (TREE_CODE_CLASS (code) != tcc_unary
-      && TREE_CODE_CLASS (code) != tcc_binary)
+      && TREE_CODE_CLASS (code) != tcc_binary
+      && TREE_CODE_CLASS (code) != tcc_binary_subcode)
     return;
 
   if (code == NOP_EXPR 
@@ -411,18 +424,23 @@ expand_vector_operations_1 (block_stmt_i
       || code == VIEW_CONVERT_EXPR)
     return;
   
+  subcode = (TREE_CODE_CLASS (code) == tcc_binary_subcode
+	     ? TREE_SUBCODE (rhs)
+	     : INVALID_SUBCODE);
+
   gcc_assert (code != CONVERT_EXPR);
-  op = optab_for_tree_code (code, type);
+  op = optab_for_tree_code (code, subcode, type);
 
   /* For widening/narrowing vector operations, the relevant type is of the 
      arguments, not the widened result.  */
   if (code == WIDEN_SUM_EXPR
-      || code == VEC_WIDEN_MULT_HI_EXPR
-      || code == VEC_WIDEN_MULT_LO_EXPR
-      || code == VEC_UNPACK_HI_EXPR
-      || code == VEC_UNPACK_LO_EXPR
-      || code == VEC_PACK_MOD_EXPR
-      || code == VEC_PACK_SAT_EXPR)
+      || (code == VEC_BINARY_EXPR
+	  && (subcode == VEC_WIDEN_MULT_HI_EXPR
+	      || subcode == VEC_WIDEN_MULT_LO_EXPR
+	      || subcode == VEC_UNPACK_HI_EXPR
+	      || subcode == VEC_UNPACK_LO_EXPR
+	      || subcode == VEC_PACK_MOD_EXPR
+	      || subcode == VEC_PACK_SAT_EXPR)))
     type = TREE_TYPE (TREE_OPERAND (rhs, 0));
 
   /* Optabs will try converting a negation into a subtraction, so
@@ -431,7 +449,7 @@ expand_vector_operations_1 (block_stmt_i
   if (op == NULL
       && code == NEGATE_EXPR
       && INTEGRAL_TYPE_P (TREE_TYPE (type)))
-    op = optab_for_tree_code (MINUS_EXPR, type);
+    op = optab_for_tree_code (MINUS_EXPR, INVALID_SUBCODE, type);
 
   /* For very wide vectors, try using a smaller vector mode.  */
   compute_type = type;
@@ -459,8 +477,9 @@ expand_vector_operations_1 (block_stmt_i
 	compute_type = TREE_TYPE (type);
     }
 
-  gcc_assert (code != VEC_LSHIFT_EXPR && code != VEC_RSHIFT_EXPR);
-  rhs = expand_vector_operation (bsi, type, compute_type, rhs, code);
+  gcc_assert (code != VEC_BINARY_EXPR
+	      || (subcode != VEC_LSHIFT_EXPR && subcode != VEC_RSHIFT_EXPR));
+  rhs = expand_vector_operation (bsi, type, compute_type, rhs, code, subcode);
   if (lang_hooks.types_compatible_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
     *p_rhs = rhs;
   else
Index: tree-flow.h
===================================================================
--- tree-flow.h	(revision 122923)
+++ tree-flow.h	(working copy)
@@ -658,6 +658,8 @@ extern tree gimplify_build1 (block_stmt_
 			     tree, tree);
 extern tree gimplify_build2 (block_stmt_iterator *, enum tree_code,
 			     tree, tree, tree);
+extern tree gimplify_build2_subcode (block_stmt_iterator *, enum tree_code,
+				     unsigned int, tree, tree, tree);
 extern tree gimplify_build3 (block_stmt_iterator *, enum tree_code,
 			     tree, tree, tree, tree);
 extern void init_empty_tree_cfg (void);
Index: tree-ssa-structalias.c
===================================================================
--- tree-ssa-structalias.c	(revision 122923)
+++ tree-ssa-structalias.c	(working copy)
@@ -3474,6 +3474,7 @@ find_func_aliases (tree origt)
 		    break;
 
 		  case tcc_binary:
+		  case tcc_binary_subcode:
 		      {
 			/* For pointer arithmetic of the form
 			   PTR + CST, we can simply use PTR's
Index: tree-cfg.c
===================================================================
--- tree-cfg.c	(revision 122923)
+++ tree-cfg.c	(working copy)
@@ -5692,6 +5692,17 @@ gimplify_build2 (block_stmt_iterator *bs
   return gimplify_val (bsi, type, ret);
 }
 
+/* Build a binary operation with a subcode and gimplify it.  Emit code
+   before BSI.  Return the gimple_val holding the result.  */
+
+tree
+gimplify_build2_subcode (block_stmt_iterator *bsi, enum tree_code code,
+			 unsigned int subcode, tree type, tree a, tree b)
+{
+  return gimplify_val (bsi, type,
+		       build2_subcode (code, subcode, type, a, b));
+}
+
 /* Build a unary operation and gimplify it.  Emit code before BSI.
    Return the gimple_val holding the result.  */
 
Index: tree-ssa-operands.c
===================================================================
--- tree-ssa-operands.c	(revision 122923)
+++ tree-ssa-operands.c	(working copy)
@@ -2285,7 +2285,9 @@ get_expr_operands (tree stmt, tree *expr
     default:
       if (class == tcc_unary)
 	goto do_unary;
-      if (class == tcc_binary || class == tcc_comparison)
+      if (class == tcc_binary
+	  || class == tcc_comparison
+	  || class == tcc_binary_subcode)
 	goto do_binary;
       if (class == tcc_constant || class == tcc_type)
 	return;

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