OSDN Git Service

* config/rs6000/rs6000.md (andsi3): Add attribute "compare" for
[pf3gnuchains/gcc-fork.git] / gcc / optabs.c
index 864e813..cc0627b 100644 (file)
@@ -84,6 +84,12 @@ enum insn_code setcc_gen_code[NUM_RTX_CODE];
 enum insn_code movcc_gen_code[NUM_MACHINE_MODES];
 #endif
 
+/* Indexed by the machine mode, gives the insn code for vector conditional
+   operation.  */
+
+enum insn_code vcond_gen_code[NUM_MACHINE_MODES];
+enum insn_code vcondu_gen_code[NUM_MACHINE_MODES];
+
 /* The insn generating function can not take an rtx_code argument.
    TRAP_RTX is used as an rtx argument.  Its code is replaced with
    the code to be used in the trap insn and all other fields are ignored.  */
@@ -116,10 +122,12 @@ static void prepare_float_lib_cmp (rtx *, rtx *, enum rtx_code *,
                                   enum machine_mode *, int *);
 static rtx widen_clz (enum machine_mode, rtx, rtx);
 static rtx expand_parity (enum machine_mode, rtx, rtx);
+static enum rtx_code get_rtx_code (enum tree_code, bool);
+static rtx vector_compare_rtx (tree, bool, enum insn_code);
 
 #ifndef HAVE_conditional_trap
 #define HAVE_conditional_trap 0
-#define gen_conditional_trap(a,b) (gcc_unreachable (), NULL_RTX)
+#define gen_conditional_trap(a,b) (abort (), NULL_RTX)
 #endif
 \f
 /* Add a REG_EQUAL note to the last insn in INSNS.  TARGET is being set to
@@ -138,9 +146,10 @@ add_equal_note (rtx insns, rtx target, enum rtx_code code, rtx op0, rtx op1)
   rtx last_insn, insn, set;
   rtx note;
 
-  gcc_assert (insns);
-  gcc_assert (INSN_P (insns));
-  gcc_assert (NEXT_INSN (insns) != NULL_RTX);
+  if (! insns
+      || ! INSN_P (insns)
+      || NEXT_INSN (insns) == NULL_RTX)
+    abort ();
 
   if (GET_RTX_CLASS (code) != RTX_COMM_ARITH
       && GET_RTX_CLASS (code) != RTX_BIN_ARITH
@@ -285,6 +294,12 @@ optab_for_tree_code (enum tree_code code, tree type)
     case MIN_EXPR:
       return TYPE_UNSIGNED (type) ? umin_optab : smin_optab;
 
+    case REALIGN_STORE_EXPR:
+      return vec_realign_store_optab;
+
+    case REALIGN_LOAD_EXPR:
+      return vec_realign_load_optab;
+
     default:
       break;
     }
@@ -312,6 +327,88 @@ optab_for_tree_code (enum tree_code code, tree type)
     }
 }
 \f
+
+/* Generate code to perform an operation specified by TERNARY_OPTAB
+   on operands OP0, OP1 and OP2, with result having machine-mode MODE.
+
+   UNSIGNEDP is for the case where we have to widen the operands
+   to perform the operation.  It says to use zero-extension.
+
+   If TARGET is nonzero, the value
+   is generated there, if it is convenient to do so.
+   In all cases an rtx is returned for the locus of the value;
+   this may or may not be TARGET.  */
+
+rtx
+expand_ternary_op (enum machine_mode mode, optab ternary_optab, rtx op0, 
+                  rtx op1, rtx op2, rtx target, int unsignedp) 
+{
+  int icode = (int) ternary_optab->handlers[(int) mode].insn_code;
+  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
+  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
+  enum machine_mode mode2 = insn_data[icode].operand[3].mode;
+  rtx temp;
+  rtx pat;
+  rtx xop0 = op0, xop1 = op1, xop2 = op2;
+
+  if (ternary_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing)
+    abort ();
+
+  if (!target
+      || ! (*insn_data[icode].operand[0].predicate) (target, mode))
+    temp = gen_reg_rtx (mode);
+  else
+    temp = target;
+
+  /* In case the insn wants input operands in modes different from
+     those of the actual operands, convert the operands.  It would
+     seem that we don't need to convert CONST_INTs, but we do, so
+     that they're properly zero-extended, sign-extended or truncated
+     for their mode.  */
+
+  if (GET_MODE (op0) != mode0 && mode0 != VOIDmode)
+    xop0 = convert_modes (mode0,
+                          GET_MODE (op0) != VOIDmode
+                          ? GET_MODE (op0) 
+                          : mode,
+                          xop0, unsignedp);
+
+  if (GET_MODE (op1) != mode1 && mode1 != VOIDmode)
+    xop1 = convert_modes (mode1,
+                          GET_MODE (op1) != VOIDmode
+                          ? GET_MODE (op1)
+                          : mode,
+                          xop1, unsignedp);
+
+  if (GET_MODE (op2) != mode2 && mode2 != VOIDmode)
+    xop2 = convert_modes (mode2,
+                          GET_MODE (op2) != VOIDmode
+                          ? GET_MODE (op2)
+                          : mode,
+                          xop2, unsignedp);
+
+  /* Now, if insn's predicates don't allow our operands, put them into
+     pseudo regs.  */
+  
+  if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0)
+      && mode0 != VOIDmode) 
+    xop0 = copy_to_mode_reg (mode0, xop0);
+  
+  if (! (*insn_data[icode].operand[2].predicate) (xop1, mode1)
+      && mode1 != VOIDmode)
+    xop1 = copy_to_mode_reg (mode1, xop1);
+    
+  if (! (*insn_data[icode].operand[3].predicate) (xop2, mode2)
+      && mode2 != VOIDmode)
+    xop2 = copy_to_mode_reg (mode2, xop2);
+    
+  pat = GEN_FCN (icode) (temp, xop0, xop1, xop2);
+    
+  emit_insn (pat);
+  return temp; 
+}
+
+
 /* Like expand_binop, but return a constant rtx if the result can be
    calculated at compile time.  The arguments and return value are
    otherwise the same as for expand_binop.  */
@@ -406,7 +503,7 @@ expand_subword_shift (enum machine_mode op1_mode, optab binoptab,
     {
       /* We must avoid shifting by BITS_PER_WORD bits since that is either
         the same as a zero shift (if shift_mask == BITS_PER_WORD - 1) or
-        has unknown behaviour.  Do a single shift first, then shift by the
+        has unknown behavior.  Do a single shift first, then shift by the
         remainder.  It's OK to use ~OP1 as the remainder if shift counts
         are truncated to the mode size.  */
       carries = expand_binop (word_mode, reverse_unsigned_shift,
@@ -671,7 +768,8 @@ expand_simple_binop (enum machine_mode mode, enum rtx_code code, rtx op0,
                     enum optab_methods methods)
 {
   optab binop = code_to_optab[(int) code];
-  gcc_assert (binop != 0);
+  if (binop == 0)
+    abort ();
 
   return expand_binop (mode, binop, op0, op1, target, unsignedp, methods);
 }
@@ -736,11 +834,19 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
      force expensive constants into a register.  */
   if (CONSTANT_P (op0) && optimize
       && rtx_cost (op0, binoptab->code) > COSTS_N_INSNS (1))
-    op0 = force_reg (mode, op0);
+    {
+      if (GET_MODE (op0) != VOIDmode)
+       op0 = convert_modes (mode, VOIDmode, op0, unsignedp);
+      op0 = force_reg (mode, op0);
+    }
 
   if (CONSTANT_P (op1) && optimize
       && ! shift_op && rtx_cost (op1, binoptab->code) > COSTS_N_INSNS (1))
-    op1 = force_reg (mode, op1);
+    {
+      if (GET_MODE (op1) != VOIDmode)
+       op1 = convert_modes (mode, VOIDmode, op1, unsignedp);
+      op1 = force_reg (mode, op1);
+    }
 
   /* Record where to delete back to if we backtrack.  */
   last = get_last_insn ();
@@ -1710,8 +1816,9 @@ expand_twoval_unop (optab unoptab, rtx op0, rtx targ0, rtx targ1,
 
       /* We could handle this, but we should always be called with a pseudo
         for our targets and all insns should take them as outputs.  */
-      gcc_assert ((*insn_data[icode].operand[0].predicate) (targ0, mode));
-      gcc_assert ((*insn_data[icode].operand[1].predicate) (targ1, mode));
+      if (! (*insn_data[icode].operand[0].predicate) (targ0, mode)
+         || ! (*insn_data[icode].operand[1].predicate) (targ1, mode))
+       abort ();
 
       pat = GEN_FCN (icode) (targ0, targ1, xop0);
       if (pat)
@@ -1838,8 +1945,9 @@ expand_twoval_binop (optab binoptab, rtx op0, rtx op1, rtx targ0, rtx targ1,
 
       /* We could handle this, but we should always be called with a pseudo
         for our targets and all insns should take them as outputs.  */
-      gcc_assert ((*insn_data[icode].operand[0].predicate) (targ0, mode));
-      gcc_assert ((*insn_data[icode].operand[3].predicate) (targ1, mode));
+      if (! (*insn_data[icode].operand[0].predicate) (targ0, mode)
+         || ! (*insn_data[icode].operand[3].predicate) (targ1, mode))
+       abort ();
 
       pat = GEN_FCN (icode) (targ0, xop0, xop1, targ1);
       if (pat)
@@ -1902,7 +2010,8 @@ expand_twoval_binop_libfunc (optab binoptab, rtx op0, rtx op1,
   rtx insns;
 
   /* Exactly one of TARG0 or TARG1 should be non-NULL.  */
-  gcc_assert ((targ0 != NULL_RTX) ^ (targ1 != NULL_RTX));
+  if (!((targ0 != NULL_RTX) ^ (targ1 != NULL_RTX)))
+    abort ();
 
   mode = GET_MODE (op0);
   if (!binoptab->handlers[(int) mode].libfunc)
@@ -1939,7 +2048,8 @@ expand_simple_unop (enum machine_mode mode, enum rtx_code code, rtx op0,
                    rtx target, int unsignedp)
 {
   optab unop = code_to_optab[(int) code];
-  gcc_assert (unop != 0);
+  if (unop == 0)
+    abort ();
 
   return expand_unop (mode, unop, op0, target, unsignedp);
 }
@@ -2614,7 +2724,8 @@ emit_no_conflict_block (rtx insns, rtx target, rtx op0, rtx op1, rtx equiv)
              }
        }
 
-      gcc_assert (set != 0);
+      if (set == 0)
+       abort ();
 
       if (! reg_overlap_mentioned_p (target, SET_DEST (set)))
        {
@@ -2887,7 +2998,6 @@ can_compare_p (enum rtx_code code, enum machine_mode mode,
       if (purpose == ccp_store_flag
          && cstore_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
        return 1;
-
       mode = GET_MODE_WIDER_MODE (mode);
     }
   while (mode != VOIDmode);
@@ -2925,7 +3035,7 @@ prepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
 
   /* They could both be VOIDmode if both args are immediate constants,
      but we should fold that at an earlier stage.
-     With no special code here, this will assert out,
+     With no special code here, this will call abort,
      reminding the programmer to implement such folding.  */
 
   if (mode != BLKmode && flag_force_mem)
@@ -2954,10 +3064,11 @@ prepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
     y = force_reg (mode, y);
 
 #ifdef HAVE_cc0
-  /* Assert out if we have a non-canonical comparison.  The RTL documentation
+  /* Abort if we have a non-canonical comparison.  The RTL documentation
      states that canonical comparisons are required only for targets which
      have cc0.  */
-  gcc_assert (!CONSTANT_P (x) || CONSTANT_P (y));
+  if (CONSTANT_P (x) && ! CONSTANT_P (y))
+    abort ();
 #endif
 
   /* Don't let both operands fail to indicate the mode.  */
@@ -2976,7 +3087,8 @@ prepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
       rtx opalign
        = GEN_INT (MIN (MEM_ALIGN (x), MEM_ALIGN (y)) / BITS_PER_UNIT);
 
-      gcc_assert (size != 0);
+      if (size == 0)
+       abort ();
 
       /* Try to use a memory block compare insn - either cmpstr
         or cmpmem will do.  */
@@ -3073,8 +3185,11 @@ prepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
       return;
     }
 
-  gcc_assert (class == MODE_FLOAT);
-  prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp);
+  if (class == MODE_FLOAT)
+    prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp);
+
+  else
+    abort ();
 }
 
 /* Before emitting an insn with code ICODE, make sure that X, which is going
@@ -3114,7 +3229,7 @@ emit_cmp_and_jump_insn_1 (rtx x, rtx y, enum machine_mode mode,
   enum machine_mode wider_mode = mode;
 
   /* Try combined insns first.  */
-  for (;;)
+  do
     {
       enum insn_code icode;
       PUT_MODE (test, wider_mode);
@@ -3157,12 +3272,15 @@ emit_cmp_and_jump_insn_1 (rtx x, rtx y, enum machine_mode mode,
          return;
        }
 
-      gcc_assert (class == MODE_INT || class == MODE_FLOAT
-                 || class == MODE_COMPLEX_FLOAT);
+      if (class != MODE_INT && class != MODE_FLOAT
+         && class != MODE_COMPLEX_FLOAT)
+       break;
 
       wider_mode = GET_MODE_WIDER_MODE (wider_mode);
-      gcc_assert (wider_mode != VOIDmode);
     }
+  while (wider_mode != VOIDmode);
+
+  abort ();
 }
 
 /* Generate code to compare X with Y so that the condition codes are
@@ -3193,7 +3311,8 @@ emit_cmp_and_jump_insns (rtx x, rtx y, enum rtx_code comparison, rtx size,
     {
       /* If we're not emitting a branch, this means some caller
          is out of sync.  */
-      gcc_assert (label);
+      if (! label)
+       abort ();
 
       op0 = y, op1 = x;
       comparison = swap_condition (comparison);
@@ -3264,7 +3383,8 @@ prepare_float_lib_cmp (rtx *px, rtx *py, enum rtx_code *pcomparison,
        }
     }
 
-  gcc_assert (mode != VOIDmode);
+  if (mode == VOIDmode)
+    abort ();
 
   if (mode != orig_mode)
     {
@@ -3322,7 +3442,7 @@ prepare_float_lib_cmp (rtx *px, rtx *py, enum rtx_code *pcomparison,
              break;
 
            default:
-             gcc_unreachable ();
+             abort ();
            }
          equiv = simplify_gen_ternary (IF_THEN_ELSE, word_mode, word_mode,
                                        equiv, true_rtx, false_rtx);
@@ -3624,12 +3744,13 @@ gen_add2_insn (rtx x, rtx y)
 {
   int icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code;
 
-  gcc_assert ((*insn_data[icode].operand[0].predicate)
-              (x, insn_data[icode].operand[0].mode));
-  gcc_assert ((*insn_data[icode].operand[1].predicate)
-              (x, insn_data[icode].operand[1].mode));
-  gcc_assert ((*insn_data[icode].operand[2].predicate)
-              (y, insn_data[icode].operand[2].mode));
+  if (! ((*insn_data[icode].operand[0].predicate)
+        (x, insn_data[icode].operand[0].mode))
+      || ! ((*insn_data[icode].operand[1].predicate)
+           (x, insn_data[icode].operand[1].mode))
+      || ! ((*insn_data[icode].operand[2].predicate)
+           (y, insn_data[icode].operand[2].mode)))
+    abort ();
 
   return (GEN_FCN (icode) (x, x, y));
 }
@@ -3658,7 +3779,8 @@ have_add2_insn (rtx x, rtx y)
 {
   int icode;
 
-  gcc_assert (GET_MODE (x) != VOIDmode);
+  if (GET_MODE (x) == VOIDmode)
+    abort ();
 
   icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code;
 
@@ -3683,12 +3805,13 @@ gen_sub2_insn (rtx x, rtx y)
 {
   int icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code;
 
-  gcc_assert ((*insn_data[icode].operand[0].predicate)
-              (x, insn_data[icode].operand[0].mode));
-  gcc_assert ((*insn_data[icode].operand[1].predicate)
-              (x, insn_data[icode].operand[1].mode));
-  gcc_assert ((*insn_data[icode].operand[2].predicate)
-              (y, insn_data[icode].operand[2].mode));
+  if (! ((*insn_data[icode].operand[0].predicate)
+        (x, insn_data[icode].operand[0].mode))
+      || ! ((*insn_data[icode].operand[1].predicate)
+           (x, insn_data[icode].operand[1].mode))
+      || ! ((*insn_data[icode].operand[2].predicate)
+           (y, insn_data[icode].operand[2].mode)))
+    abort ();
 
   return (GEN_FCN (icode) (x, x, y));
 }
@@ -3717,7 +3840,8 @@ have_sub2_insn (rtx x, rtx y)
 {
   int icode;
 
-  gcc_assert (GET_MODE (x) != VOIDmode);
+  if (GET_MODE (x) == VOIDmode)
+    abort ();
 
   icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code;
 
@@ -3843,7 +3967,8 @@ expand_float (rtx to, rtx from, int unsignedp)
   enum machine_mode fmode, imode;
 
   /* Crash now, because we won't be able to decide which mode to use.  */
-  gcc_assert (GET_MODE (from) != VOIDmode);
+  if (GET_MODE (from) == VOIDmode)
+    abort ();
 
   /* Look for an insn to do the conversion.  Do it in the specified
      modes if possible; otherwise convert either input, output or both to
@@ -4004,7 +4129,8 @@ expand_float (rtx to, rtx from, int unsignedp)
        from = force_not_mem (from);
 
       libfunc = tab->handlers[GET_MODE (to)][GET_MODE (from)].libfunc;
-      gcc_assert (libfunc);
+      if (!libfunc)
+       abort ();
 
       start_sequence ();
 
@@ -4187,7 +4313,8 @@ expand_fix (rtx to, rtx from, int unsignedp)
 
       convert_optab tab = unsignedp ? ufix_optab : sfix_optab;
       libfunc = tab->handlers[GET_MODE (to)][GET_MODE (from)].libfunc;
-      gcc_assert (libfunc);
+      if (!libfunc)
+       abort ();
 
       if (flag_force_mem)
        from = force_not_mem (from);
@@ -4537,6 +4664,12 @@ init_optabs (void)
     movcc_gen_code[i] = CODE_FOR_nothing;
 #endif
 
+  for (i = 0; i < NUM_MACHINE_MODES; i++)
+    {
+      vcond_gen_code[i] = CODE_FOR_nothing;
+      vcondu_gen_code[i] = CODE_FOR_nothing;
+    }
+
   add_optab = init_optab (PLUS);
   addv_optab = init_optabv (PLUS);
   sub_optab = init_optab (MINUS);
@@ -4633,6 +4766,8 @@ init_optabs (void)
   vec_extract_optab = init_optab (UNKNOWN);
   vec_set_optab = init_optab (UNKNOWN);
   vec_init_optab = init_optab (UNKNOWN);
+  vec_realign_load_optab = init_optab (UNKNOWN);
+
   /* Conversions.  */
   sext_optab = init_convert_optab (SIGN_EXTEND);
   zext_optab = init_convert_optab (ZERO_EXTEND);
@@ -4800,7 +4935,8 @@ debug_optab_libfuncs (void)
        h = &o->handlers[j];
        if (h->libfunc)
          {
-           gcc_assert (GET_CODE (h->libfunc) == SYMBOL_REF);
+           if (GET_CODE (h->libfunc) != SYMBOL_REF)
+             abort ();
            fprintf (stderr, "%s\t%s:\t%s\n",
                     GET_RTX_NAME (o->code),
                     GET_MODE_NAME (j),
@@ -4820,7 +4956,8 @@ debug_optab_libfuncs (void)
          h = &o->handlers[j][k];
          if (h->libfunc)
            {
-             gcc_assert (GET_CODE (h->libfunc) == SYMBOL_REF);
+             if (GET_CODE (h->libfunc) != SYMBOL_REF)
+               abort ();
              fprintf (stderr, "%s\t%s\t%s:\t%s\n",
                       GET_RTX_NAME (o->code),
                       GET_MODE_NAME (j),
@@ -4876,4 +5013,168 @@ gen_cond_trap (enum rtx_code code ATTRIBUTE_UNUSED, rtx op1,
   return insn;
 }
 
+/* Return rtx code for TCODE. Use UNSIGNEDP to select signed
+   or unsigned operation code.  */
+
+static enum rtx_code
+get_rtx_code (enum tree_code tcode, bool unsignedp)
+{
+  enum rtx_code code;
+  switch (tcode)
+    {
+    case EQ_EXPR:
+      code = EQ;
+      break;
+    case NE_EXPR:
+      code = NE;
+      break;
+    case LT_EXPR:
+      code = unsignedp ? LTU : LT;
+      break;
+    case LE_EXPR:
+      code = unsignedp ? LEU : LE;
+      break;
+    case GT_EXPR:
+      code = unsignedp ? GTU : GT;
+      break;
+    case GE_EXPR:
+      code = unsignedp ? GEU : GE;
+      break;
+      
+    case UNORDERED_EXPR:
+      code = UNORDERED;
+      break;
+    case ORDERED_EXPR:
+      code = ORDERED;
+      break;
+    case UNLT_EXPR:
+      code = UNLT;
+      break;
+    case UNLE_EXPR:
+      code = UNLE;
+      break;
+    case UNGT_EXPR:
+      code = UNGT;
+      break;
+    case UNGE_EXPR:
+      code = UNGE;
+      break;
+    case UNEQ_EXPR:
+      code = UNEQ;
+      break;
+    case LTGT_EXPR:
+      code = LTGT;
+      break;
+
+    default:
+      abort ();
+    }
+  return code;
+}
+
+/* Return comparison rtx for COND. Use UNSIGNEDP to select signed or
+   unsigned operators. Do not generate compare instruction.  */
+
+static rtx
+vector_compare_rtx (tree cond, bool unsignedp, enum insn_code icode)
+{
+  enum rtx_code rcode;
+  tree t_op0, t_op1;
+  rtx rtx_op0, rtx_op1;
+
+  if (TREE_CODE_CLASS (TREE_CODE (cond)) != '<')
+    {
+      /* This is unlikely. While generating VEC_COND_EXPR,
+        auto vectorizer ensures that condition is a relational
+        operation.  */
+      abort ();
+    }
+  else
+    {
+      rcode = get_rtx_code (TREE_CODE (cond), unsignedp); 
+      t_op0 = TREE_OPERAND (cond, 0);
+      t_op1 = TREE_OPERAND (cond, 1);
+    }
+
+  /* Expand operands.  */
+  rtx_op0 = expand_expr (t_op0, NULL_RTX, TYPE_MODE (TREE_TYPE (t_op0)), 1);
+  rtx_op1 = expand_expr (t_op1, NULL_RTX, TYPE_MODE (TREE_TYPE (t_op1)), 1);
+
+  if (!(*insn_data[icode].operand[4].predicate) (rtx_op0, GET_MODE (rtx_op0))
+      && GET_MODE (rtx_op0) != VOIDmode)
+    rtx_op0 = force_reg (GET_MODE (rtx_op0), rtx_op0);
+  
+  if (!(*insn_data[icode].operand[5].predicate) (rtx_op1, GET_MODE (rtx_op1))
+      && GET_MODE (rtx_op1) != VOIDmode)
+    rtx_op1 = force_reg (GET_MODE (rtx_op1), rtx_op1);
+
+  return gen_rtx_fmt_ee (rcode, VOIDmode, rtx_op0, rtx_op1);
+}
+
+/* Return insn code for VEC_COND_EXPR EXPR.  */
+  
+static inline enum insn_code 
+get_vcond_icode (tree expr, enum machine_mode mode)
+{
+  enum insn_code icode = CODE_FOR_nothing;
+
+  if (TYPE_UNSIGNED (TREE_TYPE (expr)))
+    icode = vcondu_gen_code[mode];
+  else
+    icode = vcond_gen_code[mode];
+  return icode;
+}
+
+/* Return TRUE iff, appropriate vector insns are available
+   for vector cond expr expr in VMODE mode.  */
+
+bool
+expand_vec_cond_expr_p (tree expr, enum machine_mode vmode)
+{
+  if (get_vcond_icode (expr, vmode) == CODE_FOR_nothing)
+    return false;
+  return true;
+}
+
+/* Generate insns for VEC_COND_EXPR.  */
+
+rtx
+expand_vec_cond_expr (tree vec_cond_expr, rtx target)
+{
+  enum insn_code icode;
+  rtx comparison, rtx_op1, rtx_op2, cc_op0, cc_op1;
+  enum machine_mode mode = TYPE_MODE (TREE_TYPE (vec_cond_expr));
+  bool unsignedp = TYPE_UNSIGNED (TREE_TYPE (vec_cond_expr));
+
+  icode = get_vcond_icode (vec_cond_expr, mode);
+  if (icode == CODE_FOR_nothing)
+    return 0;
+
+  if (!target)
+    target = gen_reg_rtx (mode);
+
+  /* Get comparison rtx.  First expand both cond expr operands.  */
+  comparison = vector_compare_rtx (TREE_OPERAND (vec_cond_expr, 0), 
+                                  unsignedp, icode);
+  cc_op0 = XEXP (comparison, 0);
+  cc_op1 = XEXP (comparison, 1);
+  /* Expand both operands and force them in reg, if required.  */
+  rtx_op1 = expand_expr (TREE_OPERAND (vec_cond_expr, 1),
+                        NULL_RTX, VOIDmode, 1);
+  if (!(*insn_data[icode].operand[1].predicate) (rtx_op1, mode)
+      && mode != VOIDmode)
+    rtx_op1 = force_reg (mode, rtx_op1);
+
+  rtx_op2 = expand_expr (TREE_OPERAND (vec_cond_expr, 2),
+                        NULL_RTX, VOIDmode, 1);
+  if (!(*insn_data[icode].operand[2].predicate) (rtx_op2, mode)
+      && mode != VOIDmode)
+    rtx_op2 = force_reg (mode, rtx_op2);
+
+  /* Emit instruction! */
+  emit_insn (GEN_FCN (icode) (target, rtx_op1, rtx_op2, 
+                             comparison, cc_op0,  cc_op1));
+
+  return target;
+}
 #include "gt-optabs.h"