rs6000-protos.h (rs6000_expand_float128_convert): Add declaration.
authorMichael Meissner <meissner@linux.vnet.ibm.com>
Wed, 26 Aug 2015 21:22:23 +0000 (21:22 +0000)
committerMichael Meissner <meissner@gcc.gnu.org>
Wed, 26 Aug 2015 21:22:23 +0000 (21:22 +0000)
2015-08-26  Michael Meissner  <meissner@linux.vnet.ibm.com>

* config/rs6000/rs6000-protos.h (rs6000_expand_float128_convert):
Add declaration.

* config/rs6000/rs6000.c (rs6000_emit_le_vsx_store): Fix a
comment.
(rs6000_cannot_change_mode_class): Add support for IEEE 128-bit
floating point in VSX registers.
(rs6000_output_move_128bit): Always print out the set insn if we
can't generate an appropriate 128-bit move.
(rs6000_generate_compare): Add support for IEEE 128-bit floating
point in VSX registers comparisons.
(rs6000_expand_float128_convert): Likewise.

* config/rs6000/predicates.md (int_reg_operand_not_pseudo): New
predicate for only GPR hard registers.

* config/rs6000/rs6000.md (FP): Add IEEE 128-bit floating point
modes to iterators. Add new iterators for moving 128-bit values in
scalar FPR registers and VSX registers.
(FMOVE128): Likewise.
(FMOVE128_FPR): Likewise.
(FMOVE128_GPR): Likewise.
(FMOVE128_VSX): Likewise.
(FLOAT128_SFDFTF): New iterators for IEEE 128-bit floating point
in VSX registers.
(IFKF): Likewise.
(IBM128): Likewise.
(TFIFKF): Likewise.
(RELOAD): Add IEEE 128-bit floating point modes.
(signbittf2): Convert TF insns to add support for new IEEE 128-bit
floating point in VSX registers modes.
(signbit<mode>2, IBM128 iterator): Likewise.
(mov<mode>_64bit_dm, FMOVE128_FPR iterator): Likewise.
(mov<mode>_32bit, FMOVE128_FPR iterator): Likewise.
(negtf2): Likewise.
(neg<mode>2, TFIFKF iterator): Likewise.
(negtf2_internal): Likewise.
(abstf2): Likewise.
(abs<mode>2, TFIFKF iterator): Likewise.
(ieee_128bit_negative_zero): New IEEE 128-bit floating point in
VSX insn support for negate, absolute value, and negative absolute
value.
(ieee_128bit_vsx_neg<mode>2): Likewise.
(ieee_128bit_vsx_neg<mode>2_internal): Likewise.
(ieee_128bit_vsx_abs<mode>2): Likewise.
(ieee_128bit_vsx_abs<mode>2_internal): Likewise.
(ieee_128bit_vsx_nabs<mode>2): Likewise.
(ieee_128bit_vsx_nabs<mode>2_internal): Likewise.
(FP128_64): Update pack/unpack 128-bit insns for IEEE 128-bit
floating point in VSX registers.
(unpack<mode>_dm): Likewise.
(unpack<mode>_nodm): Likewise.
(pack<mode>): Likewise.
(unpackv1ti): Likewise.
(unpack<mode>, FMOVE128_VSX iterator): Likewise.
(packv1ti): Likewise.
(pack<mode>, FMOVE128_VSX iterator): Likewise.
(extenddftf2): Add support for IEEE 128-bit floating point in VSX
registers.
(extenddftf2_internal): Likewise.
(trunctfdf2): Likewise.
(trunctfdf2_internal2): Likewise.
(fix_trunc_helper): Likewise.
(fix_trunctfdi2"): Likewise.
(floatditf2): Likewise.
(floatuns<mode>tf2): Likewise.
(extend<FLOAT128_SFDFTF:mode><IFKF:mode>2): Likewise.
(trunc<IFKF:mode><FLOAT128_SFDFTF:mode>2): Likewise.
(fix_trunc<IFKF:mode><SDI:mode>2): Likewise.
(fixuns_trunc<IFKF:mode><SDI:mode>2): Likewise.
(float<SDI:mode><IFKF:mode>2): Likewise.
(floatuns<SDI:mode><IFKF:mode>2): Likewise.

From-SVN: r227230

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

index c56f8ba11f52ac9f8cd31e360c51dcc0aca397a5..f38da546d0aa188395019f3202947b62fd1ebb74 100644 (file)
@@ -1,3 +1,79 @@
+2015-08-26  Michael Meissner  <meissner@linux.vnet.ibm.com>
+
+       * config/rs6000/rs6000-protos.h (rs6000_expand_float128_convert):
+       Add declaration.
+
+       * config/rs6000/rs6000.c (rs6000_emit_le_vsx_store): Fix a
+       comment.
+       (rs6000_cannot_change_mode_class): Add support for IEEE 128-bit
+       floating point in VSX registers.
+       (rs6000_output_move_128bit): Always print out the set insn if we
+       can't generate an appropriate 128-bit move.
+       (rs6000_generate_compare): Add support for IEEE 128-bit floating
+       point in VSX registers comparisons.
+       (rs6000_expand_float128_convert): Likewise.
+
+       * config/rs6000/predicates.md (int_reg_operand_not_pseudo): New
+       predicate for only GPR hard registers.
+
+       * config/rs6000/rs6000.md (FP): Add IEEE 128-bit floating point
+       modes to iterators. Add new iterators for moving 128-bit values in
+       scalar FPR registers and VSX registers.
+       (FMOVE128): Likewise.
+       (FMOVE128_FPR): Likewise.
+       (FMOVE128_GPR): Likewise.
+       (FMOVE128_VSX): Likewise.
+       (FLOAT128_SFDFTF): New iterators for IEEE 128-bit floating point
+       in VSX registers.
+       (IFKF): Likewise.
+       (IBM128): Likewise.
+       (TFIFKF): Likewise.
+       (RELOAD): Add IEEE 128-bit floating point modes.
+       (signbittf2): Convert TF insns to add support for new IEEE 128-bit
+       floating point in VSX registers modes.
+       (signbit<mode>2, IBM128 iterator): Likewise.
+       (mov<mode>_64bit_dm, FMOVE128_FPR iterator): Likewise.
+       (mov<mode>_32bit, FMOVE128_FPR iterator): Likewise.
+       (negtf2): Likewise.
+       (neg<mode>2, TFIFKF iterator): Likewise.
+       (negtf2_internal): Likewise.
+       (abstf2): Likewise.
+       (abs<mode>2, TFIFKF iterator): Likewise.
+       (ieee_128bit_negative_zero): New IEEE 128-bit floating point in
+       VSX insn support for negate, absolute value, and negative absolute
+       value.
+       (ieee_128bit_vsx_neg<mode>2): Likewise.
+       (ieee_128bit_vsx_neg<mode>2_internal): Likewise.
+       (ieee_128bit_vsx_abs<mode>2): Likewise.
+       (ieee_128bit_vsx_abs<mode>2_internal): Likewise.
+       (ieee_128bit_vsx_nabs<mode>2): Likewise.
+       (ieee_128bit_vsx_nabs<mode>2_internal): Likewise.
+       (FP128_64): Update pack/unpack 128-bit insns for IEEE 128-bit
+       floating point in VSX registers.
+       (unpack<mode>_dm): Likewise.
+       (unpack<mode>_nodm): Likewise.
+       (pack<mode>): Likewise.
+       (unpackv1ti): Likewise.
+       (unpack<mode>, FMOVE128_VSX iterator): Likewise.
+       (packv1ti): Likewise.
+       (pack<mode>, FMOVE128_VSX iterator): Likewise.
+       (extenddftf2): Add support for IEEE 128-bit floating point in VSX
+       registers.
+       (extenddftf2_internal): Likewise.
+       (trunctfdf2): Likewise.
+       (trunctfdf2_internal2): Likewise.
+       (fix_trunc_helper): Likewise.
+       (fix_trunctfdi2"): Likewise.
+       (floatditf2): Likewise.
+       (floatuns<mode>tf2): Likewise.
+       (extend<FLOAT128_SFDFTF:mode><IFKF:mode>2): Likewise.
+       (trunc<IFKF:mode><FLOAT128_SFDFTF:mode>2): Likewise.
+       (fix_trunc<IFKF:mode><SDI:mode>2): Likewise.
+       (fixuns_trunc<IFKF:mode><SDI:mode>2): Likewise.
+       (float<SDI:mode><IFKF:mode>2): Likewise.
+       (floatuns<SDI:mode><IFKF:mode>2): Likewise.
+
+
 2015-08-26  Renlin Li  <renlin.li@arm.com>
 
        * config/aarch64/aarch64.md (*aarch64_bfi<GPI:mode><ALLX:mode>4): New.
index ae74796849d7b6ca23fc3c17f03bf7f2c7b9d0b6..b111df62df887490e1b49bbc2c45d3512660ab55 100644 (file)
   return INT_REGNO_P (REGNO (op));
 })
 
+;; Like int_reg_operand, but don't return true for pseudo registers
+(define_predicate "int_reg_operand_not_pseudo"
+  (match_operand 0 "register_operand")
+{
+  if ((TARGET_E500_DOUBLE || TARGET_SPE) && invalid_e500_subreg (op, mode))
+    return 0;
+
+  if (GET_CODE (op) == SUBREG)
+    op = SUBREG_REG (op);
+
+  if (!REG_P (op))
+    return 0;
+
+  if (REGNO (op) >= FIRST_PSEUDO_REGISTER)
+    return 0;
+
+  return INT_REGNO_P (REGNO (op));
+})
+
 ;; Like int_reg_operand, but only return true for base registers
 (define_predicate "base_reg_operand"
   (match_operand 0 "int_reg_operand")
index 7262a1514388c789d7d976a0da2b377938176472..7be529fab4972004b09276ea3bbe95fedad7a183 100644 (file)
@@ -54,6 +54,7 @@ extern const char *output_vec_const_move (rtx *);
 extern const char *rs6000_output_move_128bit (rtx *);
 extern bool rs6000_move_128bit_ok_p (rtx []);
 extern bool rs6000_split_128bit_ok_p (rtx []);
+extern void rs6000_expand_float128_convert (rtx, rtx, bool);
 extern void rs6000_expand_vector_init (rtx, rtx);
 extern void paired_expand_vector_init (rtx, rtx);
 extern void rs6000_expand_vector_set (rtx, rtx, int);
index b4469564ca9682a8dc8c92cae8ba1e7fbaf14a8c..93fdece9a321caa27103d6a2613e39f51df0165a 100644 (file)
@@ -8485,7 +8485,7 @@ rs6000_emit_le_vsx_store (rtx dest, rtx source, machine_mode mode)
      during expand.  */
   gcc_assert (!reload_in_progress && !lra_in_progress && !reload_completed);
 
-  /* Use V2DImode to do swaps of types with 128-bit scalare parts (TImode,
+  /* Use V2DImode to do swaps of types with 128-bit scalar parts (TImode,
      V1TImode).  */
   if (mode == TImode || mode == V1TImode)
     {
@@ -18542,6 +18542,8 @@ rs6000_cannot_change_mode_class (machine_mode from,
        {
          unsigned to_nregs = hard_regno_nregs[FIRST_FPR_REGNO][to];
          unsigned from_nregs = hard_regno_nregs[FIRST_FPR_REGNO][from];
+         bool to_float128_vector_p = FLOAT128_VECTOR_P (to);
+         bool from_float128_vector_p = FLOAT128_VECTOR_P (from);
 
          /* Don't allow 64-bit types to overlap with 128-bit types that take a
             single register under VSX because the scalar part of the register
@@ -18550,7 +18552,10 @@ rs6000_cannot_change_mode_class (machine_mode from,
             IEEE floating point can't overlap, and neither can small
             values.  */
 
-         if (TARGET_IEEEQUAD && (to == TFmode || from == TFmode))
+         if (to_float128_vector_p && from_float128_vector_p)
+           return false;
+
+         else if (to_float128_vector_p || from_float128_vector_p)
            return true;
 
          /* TDmode in floating-mode registers must always go into a register
@@ -18578,6 +18583,8 @@ rs6000_cannot_change_mode_class (machine_mode from,
   if (TARGET_E500_DOUBLE
       && ((((to) == DFmode) + ((from) == DFmode)) == 1
          || (((to) == TFmode) + ((from) == TFmode)) == 1
+         || (((to) == IFmode) + ((from) == IFmode)) == 1
+         || (((to) == KFmode) + ((from) == KFmode)) == 1
          || (((to) == DDmode) + ((from) == DDmode)) == 1
          || (((to) == TDmode) + ((from) == TDmode)) == 1
          || (((to) == DImode) + ((from) == DImode)) == 1))
@@ -18774,13 +18781,7 @@ rs6000_output_move_128bit (rtx operands[])
        return output_vec_const_move (operands);
     }
 
-  if (TARGET_DEBUG_ADDR)
-    {
-      fprintf (stderr, "\n===== Bad 128 bit move:\n");
-      debug_rtx (gen_rtx_SET (dest, src));
-    }
-
-  gcc_unreachable ();
+  fatal_insn ("Bad 128-bit move", gen_rtx_SET (dest, src));
 }
 
 /* Validate a 128-bit move.  */
@@ -19824,6 +19825,8 @@ rs6000_generate_compare (rtx cmp, machine_mode mode)
              break;
 
            case TFmode:
+           case IFmode:
+           case KFmode:
              cmp = (flag_finite_math_only && !flag_trapping_math)
                ? gen_tsttfeq_gpr (compare_result, op0, op1)
                : gen_cmptfeq_gpr (compare_result, op0, op1);
@@ -19851,6 +19854,8 @@ rs6000_generate_compare (rtx cmp, machine_mode mode)
              break;
 
            case TFmode:
+           case IFmode:
+           case KFmode:
              cmp = (flag_finite_math_only && !flag_trapping_math)
                ? gen_tsttfgt_gpr (compare_result, op0, op1)
                : gen_cmptfgt_gpr (compare_result, op0, op1);
@@ -19878,6 +19883,8 @@ rs6000_generate_compare (rtx cmp, machine_mode mode)
              break;
 
            case TFmode:
+           case IFmode:
+           case KFmode:
              cmp = (flag_finite_math_only && !flag_trapping_math)
                ? gen_tsttflt_gpr (compare_result, op0, op1)
                : gen_cmptflt_gpr (compare_result, op0, op1);
@@ -19915,6 +19922,8 @@ rs6000_generate_compare (rtx cmp, machine_mode mode)
              break;
 
            case TFmode:
+           case IFmode:
+           case KFmode:
              cmp = (flag_finite_math_only && !flag_trapping_math)
                ? gen_tsttfeq_gpr (compare_result2, op0, op1)
                : gen_cmptfeq_gpr (compare_result2, op0, op1);
@@ -19937,14 +19946,117 @@ rs6000_generate_compare (rtx cmp, machine_mode mode)
 
       emit_insn (cmp);
     }
+
+  /* IEEE 128-bit support in VSX registers.  The comparison function (__cmpkf2)
+     returns 0..15 that is laid out the same way as the PowerPC CR register
+     would for a normal floating point comparison.  */
+  else if (FLOAT128_IEEE_P (mode))
+    {
+      rtx and_reg = gen_reg_rtx (SImode);
+      rtx dest = gen_reg_rtx (SImode);
+      rtx libfunc = optab_libfunc (cmp_optab, mode);
+      HOST_WIDE_INT mask_value = 0;
+
+      /* Values that __cmpkf2 returns.  */
+#define PPC_CMP_UNORDERED      0x1             /* isnan (a) || isnan (b).  */
+#define PPC_CMP_EQUAL          0x2             /* a == b.  */
+#define PPC_CMP_GREATER_THEN   0x4             /* a > b.  */
+#define PPC_CMP_LESS_THEN      0x8             /* a < b.  */
+
+      switch (code)
+       {
+       case EQ:
+         mask_value = PPC_CMP_EQUAL;
+         code = NE;
+         break;
+
+       case NE:
+         mask_value = PPC_CMP_EQUAL;
+         code = EQ;
+         break;
+
+       case GT:
+         mask_value = PPC_CMP_GREATER_THEN;
+         code = NE;
+         break;
+
+       case GE:
+         mask_value = PPC_CMP_GREATER_THEN | PPC_CMP_EQUAL;
+         code = NE;
+         break;
+
+       case LT:
+         mask_value = PPC_CMP_LESS_THEN;
+         code = NE;
+         break;
+
+       case LE:
+         mask_value = PPC_CMP_LESS_THEN | PPC_CMP_EQUAL;
+         code = NE;
+         break;
+
+       case UNLE:
+         mask_value = PPC_CMP_GREATER_THEN;
+         code = EQ;
+         break;
+
+       case UNLT:
+         mask_value = PPC_CMP_GREATER_THEN | PPC_CMP_EQUAL;
+         code = EQ;
+         break;
+
+       case UNGE:
+         mask_value = PPC_CMP_LESS_THEN;
+         code = EQ;
+         break;
+
+       case UNGT:
+         mask_value = PPC_CMP_LESS_THEN | PPC_CMP_EQUAL;
+         code = EQ;
+         break;
+
+       case UNEQ:
+         mask_value = PPC_CMP_EQUAL | PPC_CMP_UNORDERED;
+         code = NE;
+
+       case LTGT:
+         mask_value = PPC_CMP_EQUAL | PPC_CMP_UNORDERED;
+         code = EQ;
+         break;
+
+       case UNORDERED:
+         mask_value = PPC_CMP_UNORDERED;
+         code = NE;
+         break;
+
+       case ORDERED:
+         mask_value = PPC_CMP_UNORDERED;
+         code = EQ;
+         break;
+
+       default:
+         gcc_unreachable ();
+       }
+
+      gcc_assert (mask_value != 0);
+      and_reg = emit_library_call_value (libfunc, and_reg, LCT_CONST, SImode, 2,
+                                        op0, mode, op1, mode);
+
+      emit_insn (gen_andsi3 (dest, and_reg, GEN_INT (mask_value)));
+      compare_result = gen_reg_rtx (CCmode);
+      comp_mode = CCmode;
+
+      emit_insn (gen_rtx_SET (compare_result,
+                             gen_rtx_COMPARE (comp_mode, dest, const0_rtx)));
+    }
+
   else
     {
       /* Generate XLC-compatible TFmode compare as PARALLEL with extra
         CLOBBERs to match cmptf_internal2 pattern.  */
       if (comp_mode == CCFPmode && TARGET_XL_COMPAT
-         && GET_MODE (op0) == TFmode
-         && !TARGET_IEEEQUAD
-         && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128)
+         && FLOAT128_IBM_P (GET_MODE (op0))
+         && TARGET_HARD_FLOAT && TARGET_FPRS)
        emit_insn (gen_rtx_PARALLEL (VOIDmode,
          gen_rtvec (10,
                     gen_rtx_SET (compare_result,
@@ -19977,6 +20089,7 @@ rs6000_generate_compare (rtx cmp, machine_mode mode)
   /* Some kinds of FP comparisons need an OR operation;
      under flag_finite_math_only we don't bother.  */
   if (FLOAT_MODE_P (mode)
+      && !FLOAT128_IEEE_P (mode)
       && !flag_finite_math_only
       && !(TARGET_HARD_FLOAT && !TARGET_FPRS)
       && (code == LE || code == GE
@@ -20016,6 +20129,68 @@ rs6000_generate_compare (rtx cmp, machine_mode mode)
 }
 
 
+/* Expand floating point conversion to/from __float128 and __ibm128.  */
+
+void
+rs6000_expand_float128_convert (rtx dest, rtx src, bool unsigned_p)
+{
+  machine_mode dest_mode = GET_MODE (dest);
+  machine_mode src_mode = GET_MODE (src);
+  convert_optab cvt = unknown_optab;
+  rtx libfunc = NULL_RTX;
+  rtx dest2;
+
+  if (dest_mode == src_mode)
+    gcc_unreachable ();
+
+  if (FLOAT128_IEEE_P (dest_mode))
+    {
+      if (src_mode == SFmode
+         || src_mode == DFmode
+         || FLOAT128_IBM_P (src_mode))
+       cvt = sext_optab;
+
+      else if (GET_MODE_CLASS (src_mode) == MODE_INT)
+       cvt = (unsigned_p) ? ufloat_optab : sfloat_optab;
+
+      else if (FLOAT128_IEEE_P (src_mode))
+       emit_move_insn (dest, gen_lowpart (dest_mode, src));
+
+      else
+       gcc_unreachable ();
+    }
+
+  else if (FLOAT128_IEEE_P (src_mode))
+    {
+      if (dest_mode == SFmode
+         || dest_mode == DFmode
+         || FLOAT128_IBM_P (dest_mode))
+       cvt = trunc_optab;
+
+      else if (GET_MODE_CLASS (dest_mode) == MODE_INT)
+       cvt = (unsigned_p) ? ufix_optab : sfix_optab;
+
+      else
+       gcc_unreachable ();
+    }
+
+  else
+    gcc_unreachable ();
+
+  gcc_assert (cvt != unknown_optab);
+  libfunc = convert_optab_libfunc (cvt, dest_mode, src_mode);
+  gcc_assert (libfunc != NULL_RTX);
+
+  dest2 = emit_library_call_value (libfunc, dest, LCT_CONST, dest_mode, 1, src,
+                                  src_mode);
+
+  gcc_assert (dest != NULL_RTX);
+  if (!rtx_equal_p (dest, dest2))
+    emit_move_insn (dest, dest2);
+
+  return;
+}
+
 /* Emit the RTL for an sISEL pattern.  */
 
 void
index f7b3b4e3032f19dcfe67b18dcbece277c66b8f88..48abc26634956655e9eacbf7c0152a99d6ae9550 100644 (file)
    && TARGET_HARD_FLOAT
    && (TARGET_FPRS || TARGET_E500_DOUBLE)
    && TARGET_LONG_DOUBLE_128")
+  (IF "TARGET_FLOAT128")
+  (KF "TARGET_FLOAT128")
   (DD "TARGET_DFP")
   (TD "TARGET_DFP")])
 
 (define_mode_iterator FMOVE32 [SF SD])
 (define_mode_iterator FMOVE64 [DF DD])
 (define_mode_iterator FMOVE64X [DI DF DD])
-(define_mode_iterator FMOVE128 [(TF "!TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128")
+(define_mode_iterator FMOVE128 [(TF "TARGET_LONG_DOUBLE_128")
+                               (IF "TARGET_LONG_DOUBLE_128")
                                (TD "TARGET_HARD_FLOAT && TARGET_FPRS")])
 
+(define_mode_iterator FMOVE128_FPR [(TF "FLOAT128_2REG_P (TFmode)")
+                                   (IF "FLOAT128_2REG_P (IFmode)")
+                                   (TD "TARGET_HARD_FLOAT && TARGET_FPRS")])
+
 ; Iterators for 128 bit types for direct move
 (define_mode_iterator FMOVE128_GPR [(TI    "TARGET_VSX_TIMODE")
                                    (V16QI "")
                                    (V4SF  "")
                                    (V2DI  "")
                                    (V2DF  "")
-                                   (V1TI  "")])
+                                   (V1TI  "")
+                                   (KF    "")
+                                   (TF    "")
+                                   (IF    "")])
+
+; Iterator for 128-bit VSX types for pack/unpack
+(define_mode_iterator FMOVE128_VSX [V1TI KF])
 
 ; Whether a floating point move is ok, don't allow SD without hardware FP
 (define_mode_attr fmove_ok [(SF "")
 ; Iterator for just SF/DF
 (define_mode_iterator SFDF [SF DF])
 
+; Iterator for float128 floating conversions
+(define_mode_iterator FLOAT128_SFDFTF [
+    (SF "TARGET_FLOAT128")
+    (DF "TARGET_FLOAT128")
+    (TF "FLOAT128_IBM_P (TFmode)")
+    (IF "TARGET_FLOAT128")])
+
+; Iterator for special 128-bit floating point.  This is for non-default
+; conversions, so TFmode is not used here.
+(define_mode_iterator IFKF [IF KF])
+
+; Iterator for 128-bit floating point that uses the IBM double-double format
+(define_mode_iterator IBM128 [IF TF])
+
+; Iterator for 128-bit floating point
+(define_mode_iterator TFIFKF [(KF "TARGET_FLOAT128")
+                             (IF "TARGET_FLOAT128")
+                             (TF "TARGET_LONG_DOUBLE_128")])
+
 ; SF/DF suffix for traditional floating instructions
 (define_mode_attr Ftrad                [(SF "s") (DF "")])
 
 ;; Reload iterator for creating the function to allocate a base register to
 ;; supplement addressing modes.
 (define_mode_iterator RELOAD [V16QI V8HI V4SI V2DI V4SF V2DF V1TI
-                             SF SD SI DF DD DI TI PTI])
+                             SF SD SI DF DD DI TI PTI KF IF TF])
 
 \f
 ;; Start with fixed-point load and store insns.  Here we put only the more
 ;; This expander is here to avoid FLOAT_WORDS_BIGENDIAN tests in
 ;; builtins.c and optabs.c that are not correct for IBM long double
 ;; when little-endian.
-(define_expand "signbittf2"
+(define_expand "signbit<mode>2"
   [(set (match_dup 2)
-       (float_truncate:DF (match_operand:TF 1 "gpc_reg_operand" "")))
+       (float_truncate:DF (match_operand:IBM128 1 "gpc_reg_operand" "")))
    (set (match_dup 3)
        (subreg:DI (match_dup 2) 0))
    (set (match_dup 4)
        (match_dup 5))
    (set (match_operand:SI 0 "gpc_reg_operand" "")
        (match_dup 6))]
-  "!TARGET_IEEEQUAD
+  "FLOAT128_IBM_P (<MODE>mode)
    && TARGET_HARD_FLOAT
-   && (TARGET_FPRS || TARGET_E500_DOUBLE)
-   && TARGET_LONG_DOUBLE_128"
+   && (TARGET_FPRS || TARGET_E500_DOUBLE)"
 {
   operands[2] = gen_reg_rtx (DFmode);
   operands[3] = gen_reg_rtx (DImode);
 ;; problematical.  Don't allow direct move for this case.
 
 (define_insn_and_split "*mov<mode>_64bit_dm"
-  [(set (match_operand:FMOVE128 0 "nonimmediate_operand" "=m,d,d,ws,Y,r,r,r,wm")
-       (match_operand:FMOVE128 1 "input_operand" "d,m,d,j,r,jY,r,wm,r"))]
+  [(set (match_operand:FMOVE128_FPR 0 "nonimmediate_operand" "=m,d,d,ws,Y,r,r,r,wm")
+       (match_operand:FMOVE128_FPR 1 "input_operand" "d,m,d,j,r,jY,r,wm,r"))]
   "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_POWERPC64
+   && FLOAT128_2REG_P (<MODE>mode)
    && (<MODE>mode != TDmode || WORDS_BIG_ENDIAN)
    && (gpc_reg_operand (operands[0], <MODE>mode)
        || gpc_reg_operand (operands[1], <MODE>mode))"
   [(set_attr "length" "8,8,8,8,12,12,8")])
 
 (define_insn_and_split "*mov<mode>_32bit"
-  [(set (match_operand:FMOVE128 0 "nonimmediate_operand" "=m,d,d,ws,Y,r,r")
-       (match_operand:FMOVE128 1 "input_operand" "d,m,d,j,r,jY,r"))]
+  [(set (match_operand:FMOVE128_FPR 0 "nonimmediate_operand" "=m,d,d,ws,Y,r,r")
+       (match_operand:FMOVE128_FPR 1 "input_operand" "d,m,d,j,r,jY,r"))]
   "TARGET_HARD_FLOAT && TARGET_FPRS && !TARGET_POWERPC64
+   && (FLOAT128_2REG_P (<MODE>mode)
+       || int_reg_operand_not_pseudo (operands[0], <MODE>mode)
+       || int_reg_operand_not_pseudo (operands[1], <MODE>mode))
    && (gpc_reg_operand (operands[0], <MODE>mode)
        || gpc_reg_operand (operands[1], <MODE>mode))"
   "#"
 (define_expand "extenddftf2"
   [(set (match_operand:TF 0 "nonimmediate_operand" "")
        (float_extend:TF (match_operand:DF 1 "input_operand" "")))]
-  "!TARGET_IEEEQUAD
-   && TARGET_HARD_FLOAT
-   && (TARGET_FPRS || TARGET_E500_DOUBLE)
+  "TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE)
    && TARGET_LONG_DOUBLE_128"
 {
-  if (TARGET_E500_DOUBLE)
+  if (TARGET_IEEEQUAD)
+    rs6000_expand_float128_convert (operands[0], operands[1], false);
+  else if (TARGET_E500_DOUBLE)
     emit_insn (gen_spe_extenddftf2 (operands[0], operands[1]));
   else
     emit_insn (gen_extenddftf2_fprs (operands[0], operands[1]));
 (define_expand "extendsftf2"
   [(set (match_operand:TF 0 "nonimmediate_operand" "")
        (float_extend:TF (match_operand:SF 1 "gpc_reg_operand" "")))]
-  "!TARGET_IEEEQUAD
-   && TARGET_HARD_FLOAT
+  "TARGET_HARD_FLOAT
    && (TARGET_FPRS || TARGET_E500_DOUBLE)
    && TARGET_LONG_DOUBLE_128"
 {
-  rtx tmp = gen_reg_rtx (DFmode);
-  emit_insn (gen_extendsfdf2 (tmp, operands[1]));
-  emit_insn (gen_extenddftf2 (operands[0], tmp));
+  if (TARGET_IEEEQUAD)
+    rs6000_expand_float128_convert (operands[0], operands[1], false);
+  else
+    {
+      rtx tmp = gen_reg_rtx (DFmode);
+      emit_insn (gen_extendsfdf2 (tmp, operands[1]));
+      emit_insn (gen_extenddftf2 (operands[0], tmp));
+    }
   DONE;
 })
 
 (define_expand "trunctfdf2"
   [(set (match_operand:DF 0 "gpc_reg_operand" "")
        (float_truncate:DF (match_operand:TF 1 "gpc_reg_operand" "")))]
-  "!TARGET_IEEEQUAD
-   && TARGET_HARD_FLOAT
+  "TARGET_HARD_FLOAT
    && (TARGET_FPRS || TARGET_E500_DOUBLE)
    && TARGET_LONG_DOUBLE_128"
-  "")
+{
+  if (TARGET_IEEEQUAD)
+    {
+      rs6000_expand_float128_convert (operands[0], operands[1], false);
+      DONE;
+    }
+})
 
 (define_insn_and_split "trunctfdf2_internal1"
   [(set (match_operand:DF 0 "gpc_reg_operand" "=d,?d")
 (define_expand "trunctfsf2"
   [(set (match_operand:SF 0 "gpc_reg_operand" "")
        (float_truncate:SF (match_operand:TF 1 "gpc_reg_operand" "")))]
-  "!TARGET_IEEEQUAD
-   && TARGET_HARD_FLOAT
+  "TARGET_HARD_FLOAT
    && (TARGET_FPRS || TARGET_E500_DOUBLE)
    && TARGET_LONG_DOUBLE_128"
 {
-  if (TARGET_E500_DOUBLE)
+  if (TARGET_IEEEQUAD)
+    rs6000_expand_float128_convert (operands[0], operands[1], false);
+  else if (TARGET_E500_DOUBLE)
     emit_insn (gen_spe_trunctfsf2 (operands[0], operands[1]));
   else
     emit_insn (gen_trunctfsf2_fprs (operands[0], operands[1]));
 (define_expand "fix_trunctfsi2"
   [(set (match_operand:SI 0 "gpc_reg_operand" "")
        (fix:SI (match_operand:TF 1 "gpc_reg_operand" "")))]
-  "!TARGET_IEEEQUAD && TARGET_HARD_FLOAT
+  "TARGET_HARD_FLOAT
    && (TARGET_FPRS || TARGET_E500_DOUBLE) && TARGET_LONG_DOUBLE_128"
 {
-  if (TARGET_E500_DOUBLE)
+  if (TARGET_IEEEQUAD)
+    rs6000_expand_float128_convert (operands[0], operands[1], false);
+  else if (TARGET_E500_DOUBLE)
     emit_insn (gen_spe_fix_trunctfsi2 (operands[0], operands[1]));
   else
     emit_insn (gen_fix_trunctfsi2_fprs (operands[0], operands[1]));
   DONE;
 })
 
-(define_expand "negtf2"
-  [(set (match_operand:TF 0 "gpc_reg_operand" "")
-       (neg:TF (match_operand:TF 1 "gpc_reg_operand" "")))]
-  "!TARGET_IEEEQUAD
-   && TARGET_HARD_FLOAT
-   && (TARGET_FPRS || TARGET_E500_DOUBLE)
-   && TARGET_LONG_DOUBLE_128"
-  "")
+(define_expand "fix_trunctfdi2"
+  [(set (match_operand:DI 0 "nonimmediate_operand" "")
+       (fix:DI (match_operand:TF 1 "gpc_reg_operand" "")))]
+  "TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128"
+{
+  rs6000_expand_float128_convert (operands[0], operands[1], false);
+  DONE;
+})
+
+(define_expand "fixuns_trunctf<mode>2"
+  [(set (match_operand:SDI 0 "nonimmediate_operand" "")
+       (unsigned_fix:SDI (match_operand:TF 1 "gpc_reg_operand" "")))]
+  "TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128"
+{
+  rs6000_expand_float128_convert (operands[0], operands[1], true);
+  DONE;
+})
+
+(define_expand "floatditf2"
+  [(set (match_operand:TF 0 "nonimmediate_operand" "")
+       (float:TF (match_operand:DI 1 "gpc_reg_operand" "")))]
+  "TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128"
+{
+  rs6000_expand_float128_convert (operands[0], operands[1], false);
+  DONE;
+})
+
+(define_expand "floatuns<mode>tf2"
+  [(set (match_operand:TF 0 "nonimmediate_operand" "")
+       (unsigned_float:TF (match_operand:SDI 1 "gpc_reg_operand" "")))]
+  "TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128"
+{
+  rs6000_expand_float128_convert (operands[0], operands[1], true);
+  DONE;
+})
+
+(define_expand "neg<mode>2"
+  [(set (match_operand:TFIFKF 0 "gpc_reg_operand" "")
+       (neg:TFIFKF (match_operand:TFIFKF 1 "gpc_reg_operand" "")))]
+  "FLOAT128_IEEE_P (<MODE>mode)
+   || (FLOAT128_IBM_P (<MODE>mode)
+       && TARGET_HARD_FLOAT
+       && (TARGET_FPRS || TARGET_E500_DOUBLE))"
+  "
+{
+  if (FLOAT128_IEEE_P (<MODE>mode))
+    {
+      if (TARGET_FLOAT128)
+       emit_insn (gen_ieee_128bit_vsx_neg<mode>2 (operands[0], operands[1]));
+      else
+       {
+         rtx libfunc = optab_libfunc (neg_optab, <MODE>mode);
+         rtx target = emit_library_call_value (libfunc, operands[0], LCT_CONST,
+                                               <MODE>mode, 1,
+                                               operands[1], <MODE>mode);
+
+         if (target && !rtx_equal_p (target, operands[0]))
+           emit_move_insn (operands[0], target);
+       }
+      DONE;
+    }
+}")
 
 (define_insn "negtf2_internal"
   [(set (match_operand:TF 0 "gpc_reg_operand" "=d")
        (neg:TF (match_operand:TF 1 "gpc_reg_operand" "d")))]
-  "!TARGET_IEEEQUAD
-   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128"
+  "TARGET_HARD_FLOAT && TARGET_FPRS && FLOAT128_IBM_P (TFmode)"
   "*
 {
   if (REGNO (operands[0]) == REGNO (operands[1]) + 1)
   [(set_attr "type" "fp")
    (set_attr "length" "8")])
 
-(define_expand "abstf2"
-  [(set (match_operand:TF 0 "gpc_reg_operand" "")
-       (abs:TF (match_operand:TF 1 "gpc_reg_operand" "")))]
-  "!TARGET_IEEEQUAD
-   && TARGET_HARD_FLOAT
-   && (TARGET_FPRS || TARGET_E500_DOUBLE)
-   && TARGET_LONG_DOUBLE_128"
+(define_expand "abs<mode>2"
+  [(set (match_operand:TFIFKF 0 "gpc_reg_operand" "")
+       (abs:TFIFKF (match_operand:TFIFKF 1 "gpc_reg_operand" "")))]
+  "FLOAT128_IEEE_P (<MODE>mode)
+   || (FLOAT128_IBM_P (<MODE>mode)
+       && TARGET_HARD_FLOAT
+       && (TARGET_FPRS || TARGET_E500_DOUBLE))"
   "
 {
-  rtx label = gen_label_rtx ();
+  rtx label;
+
+  if (FLOAT128_IEEE_P (<MODE>mode))
+    {
+      if (TARGET_FLOAT128)
+       {
+         emit_insn (gen_ieee_128bit_vsx_abs<mode>2 (operands[0], operands[1]));
+         DONE;
+       }
+      else
+       FAIL;
+    }
+
+  label = gen_label_rtx ();
   if (TARGET_E500_DOUBLE)
     {
       if (flag_finite_math_only && !flag_trapping_math)
   operands[5] = simplify_gen_subreg (DFmode, operands[0], TFmode, hi_word);
   operands[6] = simplify_gen_subreg (DFmode, operands[0], TFmode, lo_word);
 }")
+
+\f
+;; Generate IEEE 128-bit -0.0 (0x80000000000000000000000000000000) in a vector
+;; register
+
+(define_expand "ieee_128bit_negative_zero"
+  [(set (match_operand:V16QI 0 "register_operand" "") (match_dup 1))]
+  "TARGET_FLOAT128"
+{
+  rtvec v = rtvec_alloc (16);
+  int i, high;
+
+  for (i = 0; i < 16; i++)
+    RTVEC_ELT (v, i) = const0_rtx;
+
+  high = (BYTES_BIG_ENDIAN) ? 0 : 15;
+  RTVEC_ELT (v, high) = GEN_INT (0x80);
+
+  rs6000_expand_vector_init (operands[0], gen_rtx_PARALLEL (V16QImode, v));
+  DONE;
+})
+
+;; IEEE 128-bit negate
+
+;; We have 2 insns here for negate and absolute value.  The first uses
+;; match_scratch so that phases like combine can recognize neg/abs as generic
+;; insns, and second insn after the first split pass loads up the bit to
+;; twiddle the sign bit.  Later GCSE passes can then combine multiple uses of
+;; neg/abs to create the constant just once.
+
+(define_insn_and_split "ieee_128bit_vsx_neg<mode>2"
+  [(set (match_operand:TFIFKF 0 "register_operand" "=wa")
+       (neg:TFIFKF (match_operand:TFIFKF 1 "register_operand" "wa")))
+   (clobber (match_scratch:V16QI 2 "=v"))]
+  "TARGET_FLOAT128 && FLOAT128_IEEE_P (<MODE>mode)"
+  "#"
+  "&& 1"
+  [(parallel [(set (match_dup 0)
+                  (neg:TFIFKF (match_dup 1)))
+             (use (match_dup 2))])]
+{
+  if (GET_CODE (operands[2]) == SCRATCH)
+    operands[2] = gen_reg_rtx (V16QImode);
+
+  operands[3] = gen_reg_rtx (V16QImode);
+  emit_insn (gen_ieee_128bit_negative_zero (operands[2]));
+}
+  [(set_attr "length" "8")
+   (set_attr "type" "vecsimple")])
+
+(define_insn "*ieee_128bit_vsx_neg<mode>2_internal"
+  [(set (match_operand:TFIFKF 0 "register_operand" "=wa")
+       (neg:TFIFKF (match_operand:TFIFKF 1 "register_operand" "wa")))
+   (use (match_operand:V16QI 2 "register_operand" "=v"))]
+  "TARGET_FLOAT128"
+  "xxlxor %x0,%x1,%x2"
+  [(set_attr "type" "vecsimple")])
+
+;; IEEE 128-bit absolute value
+(define_insn_and_split "ieee_128bit_vsx_abs<mode>2"
+  [(set (match_operand:TFIFKF 0 "register_operand" "=wa")
+       (abs:TFIFKF (match_operand:TFIFKF 1 "register_operand" "wa")))
+   (clobber (match_scratch:V16QI 2 "=v"))]
+  "TARGET_FLOAT128 && FLOAT128_IEEE_P (<MODE>mode)"
+  "#"
+  "&& 1"
+  [(parallel [(set (match_dup 0)
+                  (abs:TFIFKF (match_dup 1)))
+             (use (match_dup 2))])]
+{
+  if (GET_CODE (operands[2]) == SCRATCH)
+    operands[2] = gen_reg_rtx (V16QImode);
+
+  operands[3] = gen_reg_rtx (V16QImode);
+  emit_insn (gen_ieee_128bit_negative_zero (operands[2]));
+}
+  [(set_attr "length" "8")
+   (set_attr "type" "vecsimple")])
+
+(define_insn "*ieee_128bit_vsx_abs<mode>2_internal"
+  [(set (match_operand:TFIFKF 0 "register_operand" "=wa")
+       (abs:TFIFKF (match_operand:TFIFKF 1 "register_operand" "wa")))
+   (use (match_operand:V16QI 2 "register_operand" "=v"))]
+  "TARGET_FLOAT128"
+  "xxlandc %x0,%x1,%x2"
+  [(set_attr "type" "vecsimple")])
+
+;; IEEE 128-bit negative absolute value
+(define_insn_and_split "*ieee_128bit_vsx_nabs<mode>2"
+  [(set (match_operand:TFIFKF 0 "register_operand" "=wa")
+       (neg:TFIFKF
+        (abs:TFIFKF
+         (match_operand:TFIFKF 1 "register_operand" "wa"))))
+   (clobber (match_scratch:V16QI 2 "=v"))]
+  "TARGET_FLOAT128 && FLOAT128_IEEE_P (<MODE>mode)"
+  "#"
+  "&& 1"
+  [(parallel [(set (match_dup 0)
+                  (abs:TFIFKF (match_dup 1)))
+             (use (match_dup 2))])]
+{
+  if (GET_CODE (operands[2]) == SCRATCH)
+    operands[2] = gen_reg_rtx (V16QImode);
+
+  operands[3] = gen_reg_rtx (V16QImode);
+  emit_insn (gen_ieee_128bit_negative_zero (operands[2]));
+}
+  [(set_attr "length" "8")
+   (set_attr "type" "vecsimple")])
+
+(define_insn "*ieee_128bit_vsx_nabs<mode>2_internal"
+  [(set (match_operand:TFIFKF 0 "register_operand" "=wa")
+       (neg:TFIFKF
+        (abs:TFIFKF
+         (match_operand:TFIFKF 1 "register_operand" "wa"))))
+   (use (match_operand:V16QI 2 "register_operand" "=v"))]
+  "TARGET_FLOAT128"
+  "xxlor %x0,%x1,%x2"
+  [(set_attr "type" "vecsimple")])
+
+;; Float128 conversion functions.  These expand to library function calls.
+
+(define_expand "extend<FLOAT128_SFDFTF:mode><IFKF:mode>2"
+  [(set (match_operand:IFKF 0 "nonimmediate_operand" "")
+       (float_extend:IFKF
+        (match_operand:FLOAT128_SFDFTF 1 "gpc_reg_operand" "")))]
+  "TARGET_FLOAT128"
+{
+  rs6000_expand_float128_convert (operands[0], operands[1], false);
+  DONE;
+})
+
+(define_expand "trunc<IFKF:mode><FLOAT128_SFDFTF:mode>2"
+  [(set (match_operand:FLOAT128_SFDFTF 0 "nonimmediate_operand" "")
+       (float_truncate:FLOAT128_SFDFTF
+        (match_operand:IFKF 1 "gpc_reg_operand" "")))]
+  "TARGET_FLOAT128"
+{
+  rs6000_expand_float128_convert (operands[0], operands[1], false);
+  DONE;
+})
+
+(define_expand "fix_trunc<IFKF:mode><SDI:mode>2"
+  [(set (match_operand:SDI 0 "nonimmediate_operand" "")
+       (fix:SDI (match_operand:IFKF 1 "gpc_reg_operand" "")))]
+  "TARGET_FLOAT128"
+{
+  rs6000_expand_float128_convert (operands[0], operands[1], false);
+  DONE;
+})
+
+(define_expand "fixuns_trunc<IFKF:mode><SDI:mode>2"
+  [(set (match_operand:SDI 0 "nonimmediate_operand" "")
+       (unsigned_fix:SDI (match_operand:IFKF 1 "gpc_reg_operand" "")))]
+  "TARGET_FLOAT128"
+{
+  rs6000_expand_float128_convert (operands[0], operands[1], true);
+  DONE;
+})
+
+(define_expand "float<SDI:mode><IFKF:mode>2"
+  [(set (match_operand:IFKF 0 "nonimmediate_operand" "")
+       (float:KF (match_operand:SDI 1 "gpc_reg_operand" "")))]
+  "TARGET_FLOAT128"
+{
+  rs6000_expand_float128_convert (operands[0], operands[1], false);
+  DONE;
+})
+
+(define_expand "floatuns<SDI:mode><IFKF:mode>2"
+  [(set (match_operand:IFKF 0 "nonimmediate_operand" "")
+       (unsigned_float:IFKF (match_operand:SDI 1 "gpc_reg_operand" "")))]
+  "TARGET_FLOAT128"
+{
+  rs6000_expand_float128_convert (operands[0], operands[1], true);
+  DONE;
+})
+
 \f
 ;; Reload helper functions used by rs6000_secondary_reload.  The patterns all
 ;; must have 3 arguments, and scratch register constraint must be a single
 ;; Pack/unpack 128-bit floating point types that take 2 scalar registers
 
 ; Type of the 64-bit part when packing/unpacking 128-bit floating point types
-(define_mode_attr FP128_64 [(TF "DF") (TD "DI")])
+(define_mode_attr FP128_64 [(TF "DF")
+                           (IF "DF")
+                           (TD "DI")
+                           (KF "DI")])
 
 (define_expand "unpack<mode>"
   [(set (match_operand:<FP128_64> 0 "nonimmediate_operand" "")
         [(match_operand:FMOVE128 1 "register_operand" "")
          (match_operand:QI 2 "const_0_to_1_operand" "")]
         UNSPEC_UNPACK_128BIT))]
-  ""
+  "FLOAT128_2REG_P (<MODE>mode)"
   "")
 
 (define_insn_and_split "unpack<mode>_dm"
         [(match_operand:FMOVE128 1 "register_operand" "d,d,r,d,r")
          (match_operand:QI 2 "const_0_to_1_operand" "i,i,i,i,i")]
         UNSPEC_UNPACK_128BIT))]
-  "TARGET_POWERPC64 && TARGET_DIRECT_MOVE"
+  "TARGET_POWERPC64 && TARGET_DIRECT_MOVE && FLOAT128_2REG_P (<MODE>mode)"
   "#"
   "&& reload_completed"
   [(set (match_dup 0) (match_dup 3))]
         [(match_operand:FMOVE128 1 "register_operand" "d,d")
          (match_operand:QI 2 "const_0_to_1_operand" "i,i")]
         UNSPEC_UNPACK_128BIT))]
-  "!TARGET_POWERPC64 || !TARGET_DIRECT_MOVE"
+  "(!TARGET_POWERPC64 || !TARGET_DIRECT_MOVE) && FLOAT128_2REG_P (<MODE>mode)"
   "#"
   "&& reload_completed"
   [(set (match_dup 0) (match_dup 3))]
         [(match_operand:<FP128_64> 1 "register_operand" "0,d")
          (match_operand:<FP128_64> 2 "register_operand" "d,d")]
         UNSPEC_PACK_128BIT))]
-  ""
+  "FLOAT128_2REG_P (<MODE>mode)"
   "@
    fmr %L0,%2
    #"
   [(set_attr "type" "fp,fp")
    (set_attr "length" "4,8")])
 
-(define_insn "unpackv1ti"
+(define_insn "unpack<mode>"
   [(set (match_operand:DI 0 "register_operand" "=d,d")
-       (unspec:DI [(match_operand:V1TI 1 "register_operand" "0,wa")
+       (unspec:DI [(match_operand:FMOVE128_VSX 1 "register_operand" "0,wa")
                    (match_operand:QI 2 "const_0_to_1_operand" "O,i")]
         UNSPEC_UNPACK_128BIT))]
-  "TARGET_VSX"
+  "VECTOR_MEM_ALTIVEC_OR_VSX_P (<MODE>mode)"
 {
   if (REGNO (operands[0]) == REGNO (operands[1]) && INTVAL (operands[2]) == 0)
     return ASM_COMMENT_START " xxpermdi to same register";
   operands[3] = GEN_INT (INTVAL (operands[2]) == 0 ? 0 : 3);
   return "xxpermdi %x0,%x1,%x1,%3";
 }
-  [(set_attr "type" "vecperm")
-   (set_attr "length" "4")])
+  [(set_attr "type" "vecperm")])
 
-(define_insn "packv1ti"
-  [(set (match_operand:V1TI 0 "register_operand" "=wa")
-       (unspec:V1TI
+(define_insn "pack<mode>"
+  [(set (match_operand:FMOVE128_VSX 0 "register_operand" "=wa")
+       (unspec:FMOVE128_VSX
         [(match_operand:DI 1 "register_operand" "d")
          (match_operand:DI 2 "register_operand" "d")]
         UNSPEC_PACK_128BIT))]
   "TARGET_VSX"
   "xxpermdi %x0,%x1,%x2,0"
-  [(set_attr "type" "vecperm")
-   (set_attr "length" "4")])
+  [(set_attr "type" "vecperm")])
 
 \f