altivec.md (UNSPEC_VCMPBFP, [...]): New constant defines.
authorDevang Patel <dpatel@apple.com>
Thu, 7 Oct 2004 16:05:35 +0000 (09:05 -0700)
committerDevang Patel <dpatel@gcc.gnu.org>
Thu, 7 Oct 2004 16:05:35 +0000 (09:05 -0700)
        * rs6000/altivec.md (UNSPEC_VCMPBFP, UNSPEC_VCMPEQUB, UNSPEC_VCMPEQUH,
        UNSPEC_VCMPEQUW, UNSPEC_VCMPGEFP, UNSPEC_VCMPGTUB, UNSPEC_VCMPGTSB,
        UNSPEC_VCMPGTUH, UNSPEC_VCMPGTSH, UNSPEC_VCMPGTUW, UNSPEC_VCMPGTSW,
        UNSPEC_VCMPGTFP, UNSPEC_VSEL4SI, UNSPEC_VSEL4SF, UNSPEC_VSEL8HI,
        UNSPEC_VSEL16QI, UNSPEC_VCOND_V4SI, UNSPEC_VCOND_V4SF, UNSPEC_VCOND_V8HI,
        UNSPEC_VCOND_V16QI, UNSPEC_VCONDU_V4SI, UNSPEC_VCONDU_V8HI,
        UNSPEC_VCONDU_V16QI): New constant defines.
        (vcondv4si, vcondv4sf, vcondv8hi, vcondv16qi, vconduv4si, vconduv8hi,
        vconduv16qi): New patterns.
        * rs6000/rs6000-protos.h (rs6000_emit_vector_cond_expr): New function.
        * rs6000/rs6000.c (rs6000_emit_vector_cond_expr): New function.
        (get_vec_cmp_insn): Same.
        (get_vsel_insn): Same.
        (rs6000_emit_vector_compare): Same.
        (rs6000_emit_vector_select): Same.
        (INSN_NOT_AVAILABLE): New.

From-SVN: r88692

gcc/ChangeLog
gcc/config/rs6000/altivec.md
gcc/config/rs6000/rs6000-protos.h
gcc/config/rs6000/rs6000.c

index 1b6cb7cf11606dfe018e076c69fc48c6b523de07..369a058530358b723d5ef7e67977fc58ff48f209 100644 (file)
@@ -1,3 +1,22 @@
+2004-10-07  Devang Patel  <dpatel@apple.com>
+
+        * rs6000/altivec.md (UNSPEC_VCMPBFP, UNSPEC_VCMPEQUB, UNSPEC_VCMPEQUH,
+        UNSPEC_VCMPEQUW, UNSPEC_VCMPGEFP, UNSPEC_VCMPGTUB, UNSPEC_VCMPGTSB,
+        UNSPEC_VCMPGTUH, UNSPEC_VCMPGTSH, UNSPEC_VCMPGTUW, UNSPEC_VCMPGTSW,
+        UNSPEC_VCMPGTFP, UNSPEC_VSEL4SI, UNSPEC_VSEL4SF, UNSPEC_VSEL8HI,
+        UNSPEC_VSEL16QI, UNSPEC_VCOND_V4SI, UNSPEC_VCOND_V4SF, UNSPEC_VCOND_V8HI,
+        UNSPEC_VCOND_V16QI, UNSPEC_VCONDU_V4SI, UNSPEC_VCONDU_V8HI, 
+       UNSPEC_VCONDU_V16QI): New constant defines.
+        (vcondv4si, vcondv4sf, vcondv8hi, vcondv16qi, vconduv4si, vconduv8hi,
+       vconduv16qi): New patterns.
+        * rs6000/rs6000-protos.h (rs6000_emit_vector_cond_expr): New function.
+        * rs6000/rs6000.c (rs6000_emit_vector_cond_expr): New function.
+        (get_vec_cmp_insn): Same.
+        (get_vsel_insn): Same.
+        (rs6000_emit_vector_compare): Same.
+        (rs6000_emit_vector_select): Same.
+       (INSN_NOT_AVAILABLE): New.
+       
 2004-10-07  Zdenek Dvorak  <dvorakz@suse.cz>
 
        PR tree-optimization/17749
index 0eb29b1ea37b9c9eb6fb8acb63e4f7d23fd607c4..17866a9131e224f665095ae5c9a630dfa59fc2fb 100644 (file)
   [(UNSPEC_VSPLTISW    141)
    (UNSPEC_VSPLTISH    140)
    (UNSPEC_VSPLTISB    139)
+   (UNSPEC_VCMPBFP       50)
+   (UNSPEC_VCMPEQUB      51)
+   (UNSPEC_VCMPEQUH      52)
+   (UNSPEC_VCMPEQUW      53)
+   (UNSPEC_VCMPEQFP      54)
+   (UNSPEC_VCMPGEFP      55)
+   (UNSPEC_VCMPGTUB      56)
+   (UNSPEC_VCMPGTSB      57)
+   (UNSPEC_VCMPGTUH      58)
+   (UNSPEC_VCMPGTSH      59)
+   (UNSPEC_VCMPGTUW      60)
+   (UNSPEC_VCMPGTSW      61)
+   (UNSPEC_VCMPGTFP      62)
+   (UNSPEC_VSEL4SI      159)
+   (UNSPEC_VSEL4SF      160)
+   (UNSPEC_VSEL8HI      161)
+   (UNSPEC_VSEL16QI     162)
+   (UNSPEC_VCOND_V4SI   301)
+   (UNSPEC_VCOND_V4SF   302)
+   (UNSPEC_VCOND_V8HI   303)
+   (UNSPEC_VCOND_V16QI  304)
+   (UNSPEC_VCONDU_V4SI  305)
+   (UNSPEC_VCONDU_V8HI  306)
+   (UNSPEC_VCONDU_V16QI 307)
    ])
 
 ;; Generic LVX load instruction.
 (define_insn "altivec_vcmpbfp"
   [(set (match_operand:V4SI 0 "register_operand" "=v")
         (unspec:V4SI [(match_operand:V4SF 1 "register_operand" "v")
-                      (match_operand:V4SF 2 "register_operand" "v")] 50))]
+                      (match_operand:V4SF 2 "register_operand" "v")] 
+                      UNSPEC_VCMPBFP))]
   "TARGET_ALTIVEC"
   "vcmpbfp %0,%1,%2"
   [(set_attr "type" "veccmp")])
 (define_insn "altivec_vcmpequb"
   [(set (match_operand:V16QI 0 "register_operand" "=v")
         (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "v")
-                       (match_operand:V16QI 2 "register_operand" "v")] 51))]
+                       (match_operand:V16QI 2 "register_operand" "v")] 
+                       UNSPEC_VCMPEQUB))]
   "TARGET_ALTIVEC"
   "vcmpequb %0,%1,%2"
   [(set_attr "type" "vecsimple")])
 (define_insn "altivec_vcmpequh"
   [(set (match_operand:V8HI 0 "register_operand" "=v")
         (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "v")
-                      (match_operand:V8HI 2 "register_operand" "v")] 52))]
+                      (match_operand:V8HI 2 "register_operand" "v")] 
+                      UNSPEC_VCMPEQUH))]
   "TARGET_ALTIVEC"
   "vcmpequh %0,%1,%2"
   [(set_attr "type" "vecsimple")])
 (define_insn "altivec_vcmpequw"
   [(set (match_operand:V4SI 0 "register_operand" "=v")
         (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "v")
-                      (match_operand:V4SI 2 "register_operand" "v")] 53))]
+                      (match_operand:V4SI 2 "register_operand" "v")] 
+                     UNSPEC_VCMPEQUW))]
   "TARGET_ALTIVEC"
   "vcmpequw %0,%1,%2"
   [(set_attr "type" "vecsimple")])
 (define_insn "altivec_vcmpeqfp"
   [(set (match_operand:V4SI 0 "register_operand" "=v")
         (unspec:V4SI [(match_operand:V4SF 1 "register_operand" "v")
-                      (match_operand:V4SF 2 "register_operand" "v")] 54))]
+                      (match_operand:V4SF 2 "register_operand" "v")] 
+                     UNSPEC_VCMPEQFP))]
   "TARGET_ALTIVEC"
   "vcmpeqfp %0,%1,%2"
   [(set_attr "type" "veccmp")])
 (define_insn "altivec_vcmpgefp"
   [(set (match_operand:V4SI 0 "register_operand" "=v")
         (unspec:V4SI [(match_operand:V4SF 1 "register_operand" "v")
-                      (match_operand:V4SF 2 "register_operand" "v")] 55))]
+                      (match_operand:V4SF 2 "register_operand" "v")] 
+                      UNSPEC_VCMPGEFP))]
   "TARGET_ALTIVEC"
   "vcmpgefp %0,%1,%2"
   [(set_attr "type" "veccmp")])
 (define_insn "altivec_vcmpgtub"
   [(set (match_operand:V16QI 0 "register_operand" "=v")
         (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "v")
-                       (match_operand:V16QI 2 "register_operand" "v")] 56))]
+                       (match_operand:V16QI 2 "register_operand" "v")] 
+                       UNSPEC_VCMPGTUB))]
   "TARGET_ALTIVEC"
   "vcmpgtub %0,%1,%2"
   [(set_attr "type" "vecsimple")])
 (define_insn "altivec_vcmpgtsb"
   [(set (match_operand:V16QI 0 "register_operand" "=v")
         (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "v")
-                       (match_operand:V16QI 2 "register_operand" "v")] 57))]
+                       (match_operand:V16QI 2 "register_operand" "v")] 
+                       UNSPEC_VCMPGTSB))]
   "TARGET_ALTIVEC"
   "vcmpgtsb %0,%1,%2"
   [(set_attr "type" "vecsimple")])
 (define_insn "altivec_vcmpgtuh"
   [(set (match_operand:V8HI 0 "register_operand" "=v")
         (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "v")
-                      (match_operand:V8HI 2 "register_operand" "v")] 58))]
+                      (match_operand:V8HI 2 "register_operand" "v")] 
+                      UNSPEC_VCMPGTUH))]
   "TARGET_ALTIVEC"
   "vcmpgtuh %0,%1,%2"
   [(set_attr "type" "vecsimple")])
 (define_insn "altivec_vcmpgtsh"
   [(set (match_operand:V8HI 0 "register_operand" "=v")
         (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "v")
-                      (match_operand:V8HI 2 "register_operand" "v")] 59))]
+                      (match_operand:V8HI 2 "register_operand" "v")] 
+                      UNSPEC_VCMPGTSH))]
   "TARGET_ALTIVEC"
   "vcmpgtsh %0,%1,%2"
   [(set_attr "type" "vecsimple")])
 (define_insn "altivec_vcmpgtuw"
   [(set (match_operand:V4SI 0 "register_operand" "=v")
         (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "v")
-                      (match_operand:V4SI 2 "register_operand" "v")] 60))]
+                      (match_operand:V4SI 2 "register_operand" "v")] 
+                     UNSPEC_VCMPGTUW))]
   "TARGET_ALTIVEC"
   "vcmpgtuw %0,%1,%2"
   [(set_attr "type" "vecsimple")])
 (define_insn "altivec_vcmpgtsw"
   [(set (match_operand:V4SI 0 "register_operand" "=v")
         (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "v")
-                      (match_operand:V4SI 2 "register_operand" "v")] 61))]
+                      (match_operand:V4SI 2 "register_operand" "v")] 
+                     UNSPEC_VCMPGTSW))]
   "TARGET_ALTIVEC"
   "vcmpgtsw %0,%1,%2"
   [(set_attr "type" "vecsimple")])
 (define_insn "altivec_vcmpgtfp"
   [(set (match_operand:V4SI 0 "register_operand" "=v")
         (unspec:V4SI [(match_operand:V4SF 1 "register_operand" "v")
-                      (match_operand:V4SF 2 "register_operand" "v")] 62))]
+                      (match_operand:V4SF 2 "register_operand" "v")] 
+                     UNSPEC_VCMPGTFP))]
   "TARGET_ALTIVEC"
   "vcmpgtfp %0,%1,%2"
   [(set_attr "type" "veccmp")])
   "vrefp %0,%1"
   [(set_attr "type" "vecfloat")])
 
+(define_expand "vcondv4si"
+       [(set (match_operand:V4SI 0 "register_operand" "=v")
+             (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "v")
+              (match_operand:V4SI 2 "register_operand" "v")
+              (match_operand:V4SI 3 "comparison_operator" "")
+              (match_operand:V4SI 4 "register_operand" "v")
+              (match_operand:V4SI 5 "register_operand" "v")
+              ] UNSPEC_VCOND_V4SI))]
+       "TARGET_ALTIVEC"
+       "
+{
+       if (rs6000_emit_vector_cond_expr (operands[0], operands[1], operands[2],
+                                         operands[3], operands[4], operands[5]))
+       DONE;
+       else
+       FAIL;
+}
+       ")
+
+(define_expand "vconduv4si"
+       [(set (match_operand:V4SI 0 "register_operand" "=v")
+             (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "v")
+              (match_operand:V4SI 2 "register_operand" "v")
+              (match_operand:V4SI 3 "comparison_operator" "")
+              (match_operand:V4SI 4 "register_operand" "v")
+              (match_operand:V4SI 5 "register_operand" "v")
+              ] UNSPEC_VCONDU_V4SI))]
+       "TARGET_ALTIVEC"
+       "
+{
+       if (rs6000_emit_vector_cond_expr (operands[0], operands[1], operands[2],
+                                         operands[3], operands[4], operands[5]))
+       DONE;
+       else
+       FAIL;
+}
+       ")
+
+(define_expand "vcondv4sf"
+       [(set (match_operand:V4SF 0 "register_operand" "=v")
+             (unspec:V4SF [(match_operand:V4SI 1 "register_operand" "v")
+              (match_operand:V4SF 2 "register_operand" "v")
+              (match_operand:V4SF 3 "comparison_operator" "")
+              (match_operand:V4SF 4 "register_operand" "v")
+              (match_operand:V4SF 5 "register_operand" "v")
+              ] UNSPEC_VCOND_V4SF))]
+       "TARGET_ALTIVEC"
+       "
+{
+       if (rs6000_emit_vector_cond_expr (operands[0], operands[1], operands[2],
+                                         operands[3], operands[4], operands[5]))
+       DONE;
+       else
+       FAIL;
+}
+       ")
+
+(define_expand "vcondv8hi"
+       [(set (match_operand:V4SF 0 "register_operand" "=v")
+             (unspec:V8HI [(match_operand:V4SI 1 "register_operand" "v")
+              (match_operand:V8HI 2 "register_operand" "v")
+              (match_operand:V8HI 3 "comparison_operator" "")
+              (match_operand:V8HI 4 "register_operand" "v")
+              (match_operand:V8HI 5 "register_operand" "v")
+              ] UNSPEC_VCOND_V8HI))]
+       "TARGET_ALTIVEC"
+       "
+{
+       if (rs6000_emit_vector_cond_expr (operands[0], operands[1], operands[2],
+                                         operands[3], operands[4], operands[5]))
+       DONE;
+       else
+       FAIL;
+}
+       ")
+
+(define_expand "vconduv8hi"
+       [(set (match_operand:V4SF 0 "register_operand" "=v")
+             (unspec:V8HI [(match_operand:V4SI 1 "register_operand" "v")
+              (match_operand:V8HI 2 "register_operand" "v")
+              (match_operand:V8HI 3 "comparison_operator" "")
+              (match_operand:V8HI 4 "register_operand" "v")
+              (match_operand:V8HI 5 "register_operand" "v")
+              ] UNSPEC_VCONDU_V8HI))]
+       "TARGET_ALTIVEC"
+       "
+{
+       if (rs6000_emit_vector_cond_expr (operands[0], operands[1], operands[2],
+                                         operands[3], operands[4], operands[5]))
+       DONE;
+       else
+       FAIL;
+}
+       ")
+
+(define_expand "vcondv16qi"
+       [(set (match_operand:V4SF 0 "register_operand" "=v")
+             (unspec:V16QI [(match_operand:V4SI 1 "register_operand" "v")
+              (match_operand:V16QI 2 "register_operand" "v")
+              (match_operand:V16QI 3 "comparison_operator" "")
+              (match_operand:V16QI 4 "register_operand" "v")
+              (match_operand:V16QI 5 "register_operand" "v")
+              ] UNSPEC_VCOND_V16QI))]
+       "TARGET_ALTIVEC"
+       "
+{
+       if (rs6000_emit_vector_cond_expr (operands[0], operands[1], operands[2],
+                                         operands[3], operands[4], operands[5]))
+       DONE;
+       else
+       FAIL;
+}
+       ")
+
+(define_expand "vconduv16qi"
+       [(set (match_operand:V4SF 0 "register_operand" "=v")
+             (unspec:V16QI [(match_operand:V4SI 1 "register_operand" "v")
+              (match_operand:V16QI 2 "register_operand" "v")
+              (match_operand:V16QI 3 "comparison_operator" "")
+              (match_operand:V16QI 4 "register_operand" "v")
+              (match_operand:V16QI 5 "register_operand" "v")
+              ] UNSPEC_VCONDU_V16QI))]
+       "TARGET_ALTIVEC"
+       "
+{
+       if (rs6000_emit_vector_cond_expr (operands[0], operands[1], operands[2],
+                                         operands[3], operands[4], operands[5]))
+       DONE;
+       else
+       FAIL;
+}
+       ")
+
+
 (define_insn "altivec_vsel_4si"
   [(set (match_operand:V4SI 0 "register_operand" "=v")
         (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "v")
                       (match_operand:V4SI 2 "register_operand" "v")
-                      (match_operand:V4SI 3 "register_operand" "v")] 159))]
+                      (match_operand:V4SI 3 "register_operand" "v")] 
+                     UNSPEC_VSEL4SI))]
   "TARGET_ALTIVEC"
   "vsel %0,%1,%2,%3"
   [(set_attr "type" "vecperm")])
   [(set (match_operand:V4SF 0 "register_operand" "=v")
         (unspec:V4SF [(match_operand:V4SF 1 "register_operand" "v")
                       (match_operand:V4SF 2 "register_operand" "v")
-                      (match_operand:V4SI 3 "register_operand" "v")] 160))]
+                      (match_operand:V4SI 3 "register_operand" "v")] 
+                     UNSPEC_VSEL4SF))]
   "TARGET_ALTIVEC"
   "vsel %0,%1,%2,%3"
   [(set_attr "type" "vecperm")])
   [(set (match_operand:V8HI 0 "register_operand" "=v")
         (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "v")
                       (match_operand:V8HI 2 "register_operand" "v")
-                      (match_operand:V8HI 3 "register_operand" "v")] 161))]
+                      (match_operand:V8HI 3 "register_operand" "v")] 
+                     UNSPEC_VSEL8HI))]
   "TARGET_ALTIVEC"
   "vsel %0,%1,%2,%3"
   [(set_attr "type" "vecperm")])
   [(set (match_operand:V16QI 0 "register_operand" "=v")
         (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "v")
                        (match_operand:V16QI 2 "register_operand" "v")
-                       (match_operand:V16QI 3 "register_operand" "v")] 162))]
+                       (match_operand:V16QI 3 "register_operand" "v")] 
+                      UNSPEC_VSEL16QI))]
   "TARGET_ALTIVEC"
   "vsel %0,%1,%2,%3"
   [(set_attr "type" "vecperm")])
index 32034dedab79ab5015d12b11466a163328884a74..d3a3122ed5c2bb17c0bff780ae82ef9b3e8fec4e 100644 (file)
@@ -124,6 +124,7 @@ extern char * output_cbranch (rtx, const char *, int, rtx);
 extern char * output_e500_flip_eq_bit (rtx, rtx);
 extern rtx rs6000_emit_set_const (rtx, enum machine_mode, rtx, int);
 extern int rs6000_emit_cmove (rtx, rtx, rtx, rtx);
+extern int rs6000_emit_vector_cond_expr (rtx, rtx, rtx, rtx, rtx, rtx);
 extern void rs6000_emit_minmax (rtx, enum rtx_code, rtx, rtx);
 extern void output_toc (FILE *, rtx, int, enum machine_mode);
 extern void rs6000_initialize_trampoline (rtx, rtx, rtx);
index be377ebf4400a57c471ec28f0fc09df6205900b1..570357779fa0952a261567a4cdb383c548603498 100644 (file)
@@ -760,7 +760,15 @@ static tree rs6000_build_builtin_va_list (void);
 static tree rs6000_gimplify_va_arg (tree, tree, tree *, tree *);
 static bool rs6000_must_pass_in_stack (enum machine_mode, tree);
 static bool rs6000_vector_mode_supported_p (enum machine_mode);
+static int get_vec_cmp_insn (enum rtx_code, enum machine_mode, 
+                            enum machine_mode);
+static rtx rs6000_emit_vector_compare (enum rtx_code, rtx, rtx, 
+                                      enum machine_mode);
+static int get_vsel_insn (enum machine_mode);
+static void rs6000_emit_vector_select (rtx, rtx, rtx, rtx);
 
+
+const int INSN_NOT_AVAILABLE = -1;
 static enum machine_mode rs6000_eh_return_filter_mode (void);
 
 /* Hash table stuff for keeping track of TOC entries.  */
@@ -11202,6 +11210,271 @@ output_e500_flip_eq_bit (rtx dst, rtx src)
   return string;
 }
 
+/* Return insn index for the vector compare instruction for given CODE,
+   and DEST_MODE, OP_MODE. Return INSN_NOT_AVAILABLE if valid insn is
+   not available.  */
+
+static int
+get_vec_cmp_insn (enum rtx_code code, 
+                 enum machine_mode dest_mode,
+                 enum machine_mode op_mode)
+{
+  if (!TARGET_ALTIVEC)
+    return INSN_NOT_AVAILABLE;
+
+  switch (code)
+    {
+    case EQ:
+      if (dest_mode == V16QImode && op_mode == V16QImode)
+       return UNSPEC_VCMPEQUB;
+      if (dest_mode == V8HImode && op_mode == V8HImode)
+       return UNSPEC_VCMPEQUH;
+      if (dest_mode == V4SImode && op_mode == V4SImode)
+       return UNSPEC_VCMPEQUW;
+      if (dest_mode == V4SImode && op_mode == V4SFmode)
+       return UNSPEC_VCMPEQFP;
+      break;
+    case GE:
+      if (dest_mode == V4SImode && op_mode == V4SFmode)
+       return UNSPEC_VCMPGEFP;
+    case GT:
+      if (dest_mode == V16QImode && op_mode == V16QImode)
+       return UNSPEC_VCMPGTSB;
+      if (dest_mode == V8HImode && op_mode == V8HImode)
+       return UNSPEC_VCMPGTSH;
+      if (dest_mode == V4SImode && op_mode == V4SImode)
+       return UNSPEC_VCMPGTSW;
+      if (dest_mode == V4SImode && op_mode == V4SFmode)
+       return UNSPEC_VCMPGTFP;
+      break;
+    case GTU:
+      if (dest_mode == V16QImode && op_mode == V16QImode)
+       return UNSPEC_VCMPGTUB;
+      if (dest_mode == V8HImode && op_mode == V8HImode)
+       return UNSPEC_VCMPGTUH;
+      if (dest_mode == V4SImode && op_mode == V4SImode)
+       return UNSPEC_VCMPGTUW;
+      break;
+    default:
+      break;
+    }
+  return INSN_NOT_AVAILABLE;
+}
+
+/* Emit vector compare for operands OP0 and OP1 using code RCODE.
+   DMODE is expected destination mode. This is a recursive function.  */
+
+static rtx
+rs6000_emit_vector_compare (enum rtx_code rcode,
+                           rtx op0, rtx op1,
+                           enum machine_mode dmode)
+{
+  int vec_cmp_insn;
+  rtx mask;
+  enum machine_mode dest_mode;
+  enum machine_mode op_mode = GET_MODE (op1);
+
+#ifdef ENABLE_CHECKING
+  if (!TARGET_ALTIVEC)
+    abort ();
+
+  if (GET_MODE (op0) != GET_MODE (op1))
+    abort ();
+#endif
+
+  /* Floating point vector compare instructions uses destination V4SImode.
+     Move destination to appropriate mode later.  */
+  if (dmode == V4SFmode)
+    dest_mode = V4SImode;
+  else
+    dest_mode = dmode;
+
+  mask = gen_reg_rtx (dest_mode);
+  vec_cmp_insn = get_vec_cmp_insn (rcode, dest_mode, op_mode);
+
+  if (vec_cmp_insn == INSN_NOT_AVAILABLE)
+    {
+      bool swap_operands = false;
+      bool try_again = false;
+      switch (rcode)
+       {
+       case LT:
+         rcode = GT;
+         swap_operands = true;
+         try_again = true;
+         break;
+       case LTU:
+         rcode = GTU;
+         swap_operands = true;
+         try_again = true;
+         break;
+       case NE:
+         /* Treat A != B as ~(A==B).  */
+         {
+           enum insn_code nor_code;
+           rtx eq_rtx = rs6000_emit_vector_compare (EQ, op0, op1,
+                                                    dest_mode);
+           
+           nor_code = one_cmpl_optab->handlers[(int)dest_mode].insn_code;
+           if (nor_code == CODE_FOR_nothing)
+             abort ();
+           emit_insn (GEN_FCN (nor_code) (mask, eq_rtx));
+
+           if (dmode != dest_mode)
+             {
+               rtx temp = gen_reg_rtx (dest_mode);
+               convert_move (temp, mask, 0);
+               return temp;
+             }
+           return mask;
+         }
+         break;
+       case GE:
+       case GEU:
+       case LE:
+       case LEU:
+         /* Try GT/GTU/LT/LTU OR EQ */
+         {
+           rtx c_rtx, eq_rtx;
+           enum insn_code ior_code;
+           enum rtx_code new_code;
+
+           if (rcode == GE)
+             new_code = GT;
+           else if (rcode == GEU)
+             new_code = GTU;
+           else if (rcode == LE)
+             new_code = LT;
+           else if (rcode == LEU)
+             new_code = LTU;
+           else
+             abort ();
+
+           c_rtx = rs6000_emit_vector_compare (new_code,
+                                               op0, op1, dest_mode);
+           eq_rtx = rs6000_emit_vector_compare (EQ, op0, op1,
+                                                dest_mode);
+
+           ior_code = ior_optab->handlers[(int)dest_mode].insn_code;
+           if (ior_code == CODE_FOR_nothing)
+             abort ();
+           emit_insn (GEN_FCN (ior_code) (mask, c_rtx, eq_rtx));
+           if (dmode != dest_mode)
+             {
+               rtx temp = gen_reg_rtx (dest_mode);
+               convert_move (temp, mask, 0);
+               return temp;
+             }
+           return mask;
+         }
+         break;
+       default:
+         abort ();
+       }
+
+      if (try_again)
+       {
+         vec_cmp_insn = get_vec_cmp_insn (rcode, dest_mode, op_mode);
+         if (vec_cmp_insn == INSN_NOT_AVAILABLE)
+           /* You only get two chances.  */
+           abort ();
+       }
+
+      if (swap_operands)
+       {
+         rtx tmp;
+         tmp = op0;
+         op0 = op1;
+         op1 = tmp;
+       }
+    }
+
+  emit_insn (gen_rtx_fmt_ee (SET,
+                            VOIDmode,
+                            mask,
+                            gen_rtx_fmt_Ei (UNSPEC, dest_mode,
+                                            gen_rtvec (2, op0, op1),
+                                            vec_cmp_insn)));
+  if (dmode != dest_mode)
+    {
+      rtx temp = gen_reg_rtx (dest_mode);
+      convert_move (temp, mask, 0);
+      return temp;
+    }
+  return mask;
+}
+
+/* Return vector select instruction for MODE. Return INSN_NOT_AVAILABLE, if
+   valid insn doesn exist for given mode.  */
+
+static int
+get_vsel_insn (enum machine_mode mode)
+{
+  switch (mode)
+    {
+    case V4SImode:
+      return UNSPEC_VSEL4SI;
+      break;
+    case V4SFmode:
+      return UNSPEC_VSEL4SF;
+      break;
+    case V8HImode:
+      return UNSPEC_VSEL8HI;
+      break;
+    case V16QImode:
+      return UNSPEC_VSEL16QI;
+      break;
+    default:
+      return INSN_NOT_AVAILABLE;
+      break;
+    }
+  return INSN_NOT_AVAILABLE;
+}
+
+/* Emit vector select insn where DEST is destination using
+   operands OP1, OP2 and MASK.  */
+
+static void
+rs6000_emit_vector_select (rtx dest, rtx op1, rtx op2, rtx mask)
+{
+  rtx t, temp;
+  enum machine_mode dest_mode = GET_MODE (dest);
+  int vsel_insn_index  = get_vsel_insn (GET_MODE (dest));
+
+  temp = gen_reg_rtx (dest_mode);
+  
+  t = gen_rtx_fmt_ee (SET, VOIDmode, temp,
+                     gen_rtx_fmt_Ei (UNSPEC, dest_mode,
+                                     gen_rtvec (3, op1, op2, mask),
+                                     vsel_insn_index));
+  emit_insn (t);
+  emit_move_insn (dest, temp);
+  return;
+}
+
+/* Emit vector conditional expression.  
+   DEST is destination. OP1 and OP2 are two VEC_COND_EXPR operands.
+   CC_OP0 and CC_OP1 are the two operands for the relation operation COND.  */
+
+int
+rs6000_emit_vector_cond_expr (rtx dest, rtx op1, rtx op2,
+                             rtx cond, rtx cc_op0, rtx cc_op1)
+{
+  enum machine_mode dest_mode = GET_MODE (dest);
+  enum rtx_code rcode = GET_CODE (cond);
+  rtx mask;
+
+  if (!TARGET_ALTIVEC)
+    return 0;
+
+  /* Get the vector mask for the given relational operations.  */
+  mask = rs6000_emit_vector_compare (rcode, cc_op0, cc_op1, dest_mode);
+
+  rs6000_emit_vector_select (dest, op1, op2, mask);
+
+  return 1;
+}
+
 /* Emit a conditional move: move TRUE_COND to DEST if OP of the
    operands of the last comparison is nonzero/true, FALSE_COND if it
    is zero/false.  Return 0 if the hardware has no such operation.  */