This patch fixes PR target/78597 on PowerPC.  The basic problem is conversion
between unsigned int and _Float128 fails for 0x80000000.  Both power{7,8} using
simulated IEEE 128-bit floating point and power9 using hardware IEEE 128-bit
failed in the same test.

I cut down the patches I had developed for 79038 that are waiting for GCC 8 to
open up to include the patches that fix the problem, but don't do additional
improvements (optimizing conversions between char/short and _Float128, and
optimizing converting _Float128 to int/short/char and storing the result).

This patch is a little on the big side, because I deleted the two functions
(convert_float128_to_int and (convert_int_to_float128) that were doing the
integer/_Float128 conversions, and instead implemented them directly.  I also
deleted the various insns that those two functions called.  It only affects
_Float128/__float128 conversions.

I have tested this on a little endian power8 system.  Bootstrap passes, and the
only changes in the test suite runs were the following tests now pass:

        gcc.dg/torture/fp-int-convert-float128-ieee.c
        gcc.dg/torture/fp-int-convert-float64x.c

I did not add any tests, because it was covered by existing tests.  Can I check
this into trunk?

2017-01-30  Michael Meissner  <meiss...@linux.vnet.ibm.com>

        PR target/78597
        PR target/79038
        * config/rs6000/rs6000-protos.h (convert_float128_to_int): Delete,
        no longer used.
        (convert_int_to_float128): Likewise.
        * config/rs6000/rs6000.c (convert_float128_to_int): Likewise.
        (convert_int_to_float128): Likewise.
        * config/rs6000/rs6000.md (UNSPEC_IEEE128_MOVE): Likewise.
        (UNSPEC_IEEE128_CONVERT): Likewise.
        (floatsi<mode>2, FLOAT128 iterator): Bypass calling
        rs6000_expand_float128_convert if we have IEEE 128-bit hardware.
        Use local variables for IBM extended format.
        (fix_trunc<mode>si2, FLOAT128 iterator): Likewise.
        (fix_trunc<mode>si2_fprs): Likewise.
        (fixuns_trunc<IEEE128:mode><SDI:mode>2): Likewise.
        (floatuns<IEEE128:mode>2, IEEE128 iterator): Likewise.
        (fix<uns>_<mode>si2_hw): Rework the IEEE 128-bt hardware support
        to know that we can now have integers of all sizes in vector
        registers.
        (fix<uns>_<mode>di2_hw): Likewise.
        (float<uns>_<mode>si2_hw): Likewise.
        (fix_<mode>si2_hw): Likewise.
        (fixuns_<mode>si2_hw): Likewise.
        (float<uns>_<mode>di2_hw): Likewise.
        (float_<mode>di2_hw): Likewise.
        (float_<mode>si2_hw): Likewise.
        (floatuns_<mode>di2_hw): Likewise.
        (floatuns_<mode>si2_hw): Likewise.
        (xscvqp<su>wz_<mode>): Delete, no longer used.
        (xscvqp<su>dz_<mode>): Likewise.
        (xscv<su>dqp_<mode>): Likewise.
        (ieee128_mfvsrd_64bit): Likewise.
        (ieee128_mfvsrd_32bit): Likewise.
        (ieee128_mfvsrwz): Likewise.
        (ieee128_mtvsrw): Likewise.
        (ieee128_mtvsrd_64bit): Likewise.
        (ieee128_mtvsrd_32bit): Likewise.

-- 
Michael Meissner, IBM
IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA
email: meiss...@linux.vnet.ibm.com, phone: +1 (978) 899-4797
Index: gcc/config/rs6000/rs6000-protos.h
===================================================================
--- gcc/config/rs6000/rs6000-protos.h   (revision 245036)
+++ gcc/config/rs6000/rs6000-protos.h   (working copy)
@@ -57,8 +57,6 @@ extern const char *rs6000_output_move_12
 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 convert_float128_to_int (rtx *, enum rtx_code);
-extern void convert_int_to_float128 (rtx *, enum rtx_code);
 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: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c  (revision 245036)
+++ gcc/config/rs6000/rs6000.c  (working copy)
@@ -24609,92 +24609,6 @@ rs6000_expand_float128_convert (rtx dest
   return;
 }
 
-/* Split a conversion from __float128 to an integer type into separate insns.
-   OPERANDS points to the destination, source, and V2DI temporary
-   register. CODE is either FIX or UNSIGNED_FIX.  */
-
-void
-convert_float128_to_int (rtx *operands, enum rtx_code code)
-{
-  rtx dest = operands[0];
-  rtx src = operands[1];
-  rtx tmp = operands[2];
-  rtx cvt;
-  rtvec cvt_vec;
-  rtx cvt_unspec;
-  rtvec move_vec;
-  rtx move_unspec;
-
-  if (GET_CODE (tmp) == SCRATCH)
-    tmp = gen_reg_rtx (V2DImode);
-
-  if (MEM_P (dest))
-    dest = rs6000_address_for_fpconvert (dest);
-
-  /* Generate the actual convert insn of the form:
-     (set (tmp) (unspec:V2DI [(fix:SI (reg:KF))] UNSPEC_IEEE128_CONVERT)).  */
-  cvt = gen_rtx_fmt_e (code, GET_MODE (dest), src);
-  cvt_vec = gen_rtvec (1, cvt);
-  cvt_unspec = gen_rtx_UNSPEC (V2DImode, cvt_vec, UNSPEC_IEEE128_CONVERT);
-  emit_insn (gen_rtx_SET (tmp, cvt_unspec));
-
-  /* Generate the move insn of the form:
-     (set (dest:SI) (unspec:SI [(tmp:V2DI))] UNSPEC_IEEE128_MOVE)).  */
-  move_vec = gen_rtvec (1, tmp);
-  move_unspec = gen_rtx_UNSPEC (GET_MODE (dest), move_vec, 
UNSPEC_IEEE128_MOVE);
-  emit_insn (gen_rtx_SET (dest, move_unspec));
-}
-
-/* Split a conversion from an integer type to __float128 into separate insns.
-   OPERANDS points to the destination, source, and V2DI temporary
-   register. CODE is either FLOAT or UNSIGNED_FLOAT.  */
-
-void
-convert_int_to_float128 (rtx *operands, enum rtx_code code)
-{
-  rtx dest = operands[0];
-  rtx src = operands[1];
-  rtx tmp = operands[2];
-  rtx cvt;
-  rtvec cvt_vec;
-  rtx cvt_unspec;
-  rtvec move_vec;
-  rtx move_unspec;
-  rtx unsigned_flag;
-
-  if (GET_CODE (tmp) == SCRATCH)
-    tmp = gen_reg_rtx (V2DImode);
-
-  if (MEM_P (src))
-    src = rs6000_address_for_fpconvert (src);
-
-  /* Generate the move of the integer into the Altivec register of the form:
-     (set (tmp:V2DI) (unspec:V2DI [(src:SI)
-                                  (const_int 0)] UNSPEC_IEEE128_MOVE)).
-
-     or:
-     (set (tmp:V2DI) (unspec:V2DI [(src:DI)] UNSPEC_IEEE128_MOVE)).  */
-
-  if (GET_MODE (src) == SImode)
-    {
-      unsigned_flag = (code == UNSIGNED_FLOAT) ? const1_rtx : const0_rtx;
-      move_vec = gen_rtvec (2, src, unsigned_flag);
-    }
-  else
-    move_vec = gen_rtvec (1, src);
-
-  move_unspec = gen_rtx_UNSPEC (V2DImode, move_vec, UNSPEC_IEEE128_MOVE);
-  emit_insn (gen_rtx_SET (tmp, move_unspec));
-
-  /* Generate the actual convert insn of the form:
-     (set (dest:KF) (float:KF (unspec:DI [(tmp:V2DI)]
-                                        UNSPEC_IEEE128_CONVERT))).  */
-  cvt_vec = gen_rtvec (1, tmp);
-  cvt_unspec = gen_rtx_UNSPEC (DImode, cvt_vec, UNSPEC_IEEE128_CONVERT);
-  cvt = gen_rtx_fmt_e (code, GET_MODE (dest), cvt_unspec);
-  emit_insn (gen_rtx_SET (dest, cvt));
-}
-
 
 /* Emit the RTL for an sISEL pattern.  */
 
Index: gcc/config/rs6000/rs6000.md
===================================================================
--- gcc/config/rs6000/rs6000.md (revision 245036)
+++ gcc/config/rs6000/rs6000.md (working copy)
@@ -146,8 +146,6 @@ (define_c_enum "unspec"
    UNSPEC_FUSION_P9
    UNSPEC_FUSION_ADDIS
    UNSPEC_ROUND_TO_ODD
-   UNSPEC_IEEE128_MOVE
-   UNSPEC_IEEE128_CONVERT
    UNSPEC_SIGNBIT
    UNSPEC_SF_FROM_SI
    UNSPEC_SI_FROM_SF
@@ -7661,26 +7659,35 @@ (define_insn_and_split "trunc<mode>sf2_f
   "")
 
 (define_expand "floatsi<mode>2"
-  [(set (match_operand:FLOAT128 0 "gpc_reg_operand" "")
-        (float:FLOAT128 (match_operand:SI 1 "gpc_reg_operand" "")))]
+  [(parallel [(set (match_operand:FLOAT128 0 "gpc_reg_operand")
+                  (float:FLOAT128 (match_operand:SI 1 "gpc_reg_operand")))
+             (clobber (match_scratch:DI 2))])]
   "TARGET_HARD_FLOAT
    && (TARGET_FPRS || TARGET_E500_DOUBLE)
    && TARGET_LONG_DOUBLE_128"
 {
-  if (FLOAT128_IEEE_P (<MODE>mode))
-    rs6000_expand_float128_convert (operands[0], operands[1], false);
+  rtx op0 = operands[0];
+  rtx op1 = operands[1]; 
+
+  if (TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode))
+    ;
+  else if (FLOAT128_IEEE_P (<MODE>mode))
+    {
+      rs6000_expand_float128_convert (op0, op1, false);
+      DONE;
+    }
   else
     {
       rtx tmp = gen_reg_rtx (DFmode);
-      expand_float (tmp, operands[1], false);
+      expand_float (tmp, op1, false);
       if (<MODE>mode == TFmode)
-       emit_insn (gen_extenddftf2 (operands[0], tmp));
+       emit_insn (gen_extenddftf2 (op0, tmp));
       else if (<MODE>mode == IFmode)
-       emit_insn (gen_extenddfif2 (operands[0], tmp));
+       emit_insn (gen_extenddfif2 (op0, tmp));
       else
        gcc_unreachable ();
+      DONE;
     }
-  DONE;
 })
 
 ; fadd, but rounding towards zero.
@@ -7702,17 +7709,25 @@ (define_expand "fix_trunc<mode>si2"
   "TARGET_HARD_FLOAT
    && (TARGET_FPRS || TARGET_E500_DOUBLE) && TARGET_LONG_DOUBLE_128"
 {
-  if (FLOAT128_IEEE_P (<MODE>mode))
-    rs6000_expand_float128_convert (operands[0], operands[1], false);
-  else if (TARGET_E500_DOUBLE && <MODE>mode == TFmode)
-    emit_insn (gen_spe_fix_trunctfsi2 (operands[0], operands[1]));
-  else if (<MODE>mode == TFmode)
-    emit_insn (gen_fix_trunctfsi2_fprs (operands[0], operands[1]));
-  else if (<MODE>mode == IFmode)
-    emit_insn (gen_fix_truncifsi2_fprs (operands[0], operands[1]));
+  rtx op0 = operands[0];
+  rtx op1 = operands[1];
+
+  if (TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode))
+    ;
   else
-    gcc_unreachable ();
-  DONE;
+    {
+      if (FLOAT128_IEEE_P (<MODE>mode))
+       rs6000_expand_float128_convert (op0, op1, false);
+      else if (TARGET_E500_DOUBLE && <MODE>mode == TFmode)
+       emit_insn (gen_spe_fix_trunctfsi2 (op0, op1));
+      else if (<MODE>mode == TFmode)
+       emit_insn (gen_fix_trunctfsi2_fprs (op0, op1));
+      else if (<MODE>mode == IFmode)
+       emit_insn (gen_fix_truncifsi2_fprs (op0, op1));
+      else
+       gcc_unreachable ();
+      DONE;
+    }
 })
 
 (define_expand "fix_trunc<mode>si2_fprs"
@@ -7760,8 +7775,11 @@ (define_expand "fix_trunc<mode>di2"
        (fix:DI (match_operand:IEEE128 1 "gpc_reg_operand" "")))]
   "TARGET_FLOAT128_TYPE"
 {
-  rs6000_expand_float128_convert (operands[0], operands[1], false);
-  DONE;
+  if (!TARGET_FLOAT128_HW)
+    {
+      rs6000_expand_float128_convert (operands[0], operands[1], false);
+      DONE;
+    }
 })
 
 (define_expand "fixuns_trunc<IEEE128:mode><SDI:mode>2"
@@ -7778,16 +7796,37 @@ (define_expand "floatdi<mode>2"
        (float:IEEE128 (match_operand:DI 1 "gpc_reg_operand" "")))]
   "TARGET_FLOAT128_TYPE"
 {
-  rs6000_expand_float128_convert (operands[0], operands[1], false);
-  DONE;
+  if (!TARGET_FLOAT128_HW)
+    {
+      rs6000_expand_float128_convert (operands[0], operands[1], false);
+      DONE;
+    }
 })
 
-(define_expand "floatuns<SDI:mode><IEEE128:mode>2"
+(define_expand "floatunsdi<IEEE128:mode>2"
   [(set (match_operand:IEEE128 0 "gpc_reg_operand" "")
-       (unsigned_float:IEEE128 (match_operand:SDI 1 "gpc_reg_operand" "")))]
+       (unsigned_float:IEEE128 (match_operand:DI 1 "gpc_reg_operand" "")))]
   "TARGET_FLOAT128_TYPE"
 {
-  rs6000_expand_float128_convert (operands[0], operands[1], true);
+  if (!TARGET_FLOAT128_HW)
+    {
+      rs6000_expand_float128_convert (operands[0], operands[1], true);
+      DONE;
+    }
+})
+
+(define_expand "floatuns<IEEE128:mode>2"
+  [(set (match_operand:IEEE128 0 "gpc_reg_operand" "")
+       (unsigned_float:IEEE128 (match_operand:SI 1 "gpc_reg_operand" "")))]
+  "TARGET_FLOAT128_TYPE"
+{
+  rtx op0 = operands[0];
+  rtx op1 = operands[1];
+
+  if (TARGET_FLOAT128_HW)
+    emit_insn (gen_floatuns_<IEEE128:mode>si2_hw (op0, op1));
+  else
+    rs6000_expand_float128_convert (op0, op1, true);
   DONE;
 })
 
@@ -14321,170 +14360,102 @@ (define_insn_and_split "trunc<mode>sf2_h
   [(set_attr "type" "vecfloat")
    (set_attr "length" "8")])
 
-;; At present SImode is not allowed in VSX registers at all, and DImode is only
-;; allowed in the traditional floating point registers. Use V2DImode so that
-;; we can get a value in an Altivec register.
-
-(define_insn_and_split "fix<uns>_<mode>si2_hw"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,Z")
-       (any_fix:SI (match_operand:IEEE128 1 "altivec_register_operand" "v,v")))
-   (clobber (match_scratch:V2DI 2 "=v,v"))]
+;; Conersion between IEEE 128-bit and integer types
+(define_insn "fix_<mode>di2_hw"
+  [(set (match_operand:DI 0 "altivec_register_operand" "=v")
+       (fix:DI (match_operand:IEEE128 1 "altivec_register_operand" "v")))]
   "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
-  "#"
-  "&& 1"
-  [(pc)]
-{
-  convert_float128_to_int (operands, <CODE>);
-  DONE;
-}
-  [(set_attr "length" "8")
-   (set_attr "type" "mftgpr,fpstore")])
+  "xscvqpsdz %0,%1"
+  [(set_attr "type" "vecfloat")
+   (set_attr "size" "128")])
 
-(define_insn_and_split "fix<uns>_<mode>di2_hw"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=wr,wi,Z")
-       (any_fix:DI (match_operand:IEEE128 1 "altivec_register_operand" 
"v,v,v")))
-   (clobber (match_scratch:V2DI 2 "=v,v,v"))]
+(define_insn "fixuns_<mode>di2_hw"
+  [(set (match_operand:DI 0 "altivec_register_operand" "=v")
+       (unsigned_fix:DI (match_operand:IEEE128 1 "altivec_register_operand" 
"v")))]
   "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
-  "#"
-  "&& 1"
-  [(pc)]
-{
-  convert_float128_to_int (operands, <CODE>);
-  DONE;
-}
-  [(set_attr "length" "8")
-   (set_attr "type" "mftgpr,vecsimple,fpstore")])
+  "xscvqpudz %0,%1"
+  [(set_attr "type" "vecfloat")
+   (set_attr "size" "128")])
 
-(define_insn_and_split "float<uns>_<mode>si2_hw"
-  [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v,v")
-       (any_float:IEEE128 (match_operand:SI 1 "nonimmediate_operand" "r,Z")))
-   (clobber (match_scratch:V2DI 2 "=v,v"))]
+(define_insn "fix_<mode>si2_hw"
+  [(set (match_operand:SI 0 "altivec_register_operand" "=v")
+       (fix:SI (match_operand:IEEE128 1 "altivec_register_operand" "v")))]
   "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
-  "#"
-  "&& 1"
-  [(pc)]
-{
-  convert_int_to_float128 (operands, <CODE>);
-  DONE;
-}
-  [(set_attr "length" "8")
-   (set_attr "type" "vecfloat")])
+  "xscvqpswz %0,%1"
+  [(set_attr "type" "vecfloat")
+   (set_attr "size" "128")])
+
+(define_insn "fixuns_<mode>si2_hw"
+  [(set (match_operand:SI 0 "altivec_register_operand" "=v")
+       (unsigned_fix:SI (match_operand:IEEE128 1 "altivec_register_operand" 
"v")))]
+  "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
+  "xscvqpuwz %0,%1"
+  [(set_attr "type" "vecfloat")
+   (set_attr "size" "128")])
 
-(define_insn_and_split "float<uns>_<mode>di2_hw"
-  [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v,v,v")
-       (any_float:IEEE128 (match_operand:DI 1 "nonimmediate_operand" 
"wi,wr,Z")))
-   (clobber (match_scratch:V2DI 2 "=v,v,v"))]
+;; Combiner pattern to prevent moving the result of converting an IEEE 128-bit
+;; floating point value to 32-bit integer to GPR in order to save it.
+(define_insn_and_split "*fix<uns>_<mode>_mem"
+  [(set (match_operand:SI 0 "memory_operand" "=Z")
+       (any_fix:SI (match_operand:IEEE128 1 "altivec_register_operand" "v")))
+   (clobber (match_scratch:SI 2 "=v"))]
   "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
   "#"
-  "&& 1"
-  [(pc)]
-{
-  convert_int_to_float128 (operands, <CODE>);
-  DONE;
-}
-  [(set_attr "length" "8")
-   (set_attr "type" "vecfloat")])
+  "&& reload_completed"
+  [(set (match_dup 2)
+       (any_fix:SI (match_dup 1)))
+   (set (match_dup 0)
+       (match_dup 2))])
 
-;; Integer conversion instructions, using V2DImode to get an Altivec register
-(define_insn "*xscvqp<su>wz_<mode>"
-  [(set (match_operand:V2DI 0 "altivec_register_operand" "=v")
-       (unspec:V2DI
-        [(any_fix:SI
-          (match_operand:IEEE128 1 "altivec_register_operand" "v"))]
-        UNSPEC_IEEE128_CONVERT))]
+(define_insn "float_<mode>di2_hw"
+  [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
+       (float:IEEE128 (match_operand:DI 1 "altivec_register_operand" "v")))]
   "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
-  "xscvqp<su>wz %0,%1"
+  "xscvsdqp %0,%1"
   [(set_attr "type" "vecfloat")
    (set_attr "size" "128")])
 
-(define_insn "*xscvqp<su>dz_<mode>"
-  [(set (match_operand:V2DI 0 "altivec_register_operand" "=v")
-       (unspec:V2DI
-        [(any_fix:DI
-          (match_operand:IEEE128 1 "altivec_register_operand" "v"))]
-        UNSPEC_IEEE128_CONVERT))]
+(define_insn_and_split "float_<mode>si2_hw"
+  [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
+       (float:IEEE128 (match_operand:SI 1 "nonimmediate_operand" "vrZ")))
+   (clobber (match_scratch:DI 2 "=v"))]
   "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
-  "xscvqp<su>dz %0,%1"
-  [(set_attr "type" "vecfloat")
-   (set_attr "size" "128")])
+  "#"
+  "&& 1"
+  [(set (match_dup 2)
+       (sign_extend:DI (match_dup 1)))
+   (set (match_dup 0)
+       (float:IEEE128 (match_dup 2)))]
+{
+  if (GET_CODE (operands[2]) == SCRATCH)
+    operands[2] = gen_reg_rtx (DImode);
+})
 
-(define_insn "*xscv<su>dqp_<mode>"
+(define_insn "floatuns_<mode>di2_hw"
   [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
-       (any_float:IEEE128
-        (unspec:DI [(match_operand:V2DI 1 "altivec_register_operand" "v")]
-                   UNSPEC_IEEE128_CONVERT)))]
+       (unsigned_float:IEEE128
+        (match_operand:DI 1 "altivec_register_operand" "v")))]
   "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
-  "xscv<su>dqp %0,%1"
+  "xscvudqp %0,%1"
   [(set_attr "type" "vecfloat")
    (set_attr "size" "128")])
 
-(define_insn "*ieee128_mfvsrd_64bit"
-  [(set (match_operand:DI 0 "reg_or_indexed_operand" "=wr,Z,wi")
-       (unspec:DI [(match_operand:V2DI 1 "altivec_register_operand" "v,v,v")]
-                  UNSPEC_IEEE128_MOVE))]
-  "TARGET_FLOAT128_HW && TARGET_POWERPC64"
-  "@
-   mfvsrd %0,%x1
-   stxsdx %x1,%y0
-   xxlor %x0,%x1,%x1"
-  [(set_attr "type" "mftgpr,fpstore,veclogical")])
-
-
-(define_insn "*ieee128_mfvsrd_32bit"
-  [(set (match_operand:DI 0 "reg_or_indexed_operand" "=Z,wi")
-       (unspec:DI [(match_operand:V2DI 1 "altivec_register_operand" "v,v")]
-                  UNSPEC_IEEE128_MOVE))]
-  "TARGET_FLOAT128_HW && !TARGET_POWERPC64"
-  "@
-   stxsdx %x1,%y0
-   xxlor %x0,%x1,%x1"
-  [(set_attr "type" "fpstore,veclogical")])
-
-(define_insn "*ieee128_mfvsrwz"
-  [(set (match_operand:SI 0 "reg_or_indexed_operand" "=r,Z")
-       (unspec:SI [(match_operand:V2DI 1 "altivec_register_operand" "v,v")]
-                  UNSPEC_IEEE128_MOVE))]
-  "TARGET_FLOAT128_HW"
-  "@
-   mfvsrwz %0,%x1
-   stxsiwx %x1,%y0"
-  [(set_attr "type" "mftgpr,fpstore")])
-
-;; 0 says do sign-extension, 1 says zero-extension
-(define_insn "*ieee128_mtvsrw"
-  [(set (match_operand:V2DI 0 "altivec_register_operand" "=v,v,v,v")
-       (unspec:V2DI [(match_operand:SI 1 "nonimmediate_operand" "r,Z,r,Z")
-                     (match_operand:SI 2 "const_0_to_1_operand" "O,O,n,n")]
-                    UNSPEC_IEEE128_MOVE))]
-  "TARGET_FLOAT128_HW"
-  "@
-   mtvsrwa %x0,%1
-   lxsiwax %x0,%y1
-   mtvsrwz %x0,%1
-   lxsiwzx %x0,%y1"
-  [(set_attr "type" "mffgpr,fpload,mffgpr,fpload")])
-
-
-(define_insn "*ieee128_mtvsrd_64bit"
-  [(set (match_operand:V2DI 0 "altivec_register_operand" "=v,v,v")
-       (unspec:V2DI [(match_operand:DI 1 "nonimmediate_operand" "wr,Z,wi")]
-                    UNSPEC_IEEE128_MOVE))]
-  "TARGET_FLOAT128_HW && TARGET_POWERPC64"
-  "@
-   mtvsrd %x0,%1
-   lxsdx %x0,%y1
-   xxlor %x0,%x1,%x1"
-  [(set_attr "type" "mffgpr,fpload,veclogical")])
-
-(define_insn "*ieee128_mtvsrd_32bit"
-  [(set (match_operand:V2DI 0 "altivec_register_operand" "=v,v")
-       (unspec:V2DI [(match_operand:DI 1 "nonimmediate_operand" "Z,wi")]
-                    UNSPEC_IEEE128_MOVE))]
-  "TARGET_FLOAT128_HW && !TARGET_POWERPC64"
-  "@
-   lxsdx %x0,%y1
-   xxlor %x0,%x1,%x1"
-  [(set_attr "type" "fpload,veclogical")])
+(define_insn_and_split "floatuns_<mode>si2_hw"
+  [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
+       (unsigned_float:IEEE128
+        (match_operand:SI 1 "nonimmediate_operand" "vrZ")))
+   (clobber (match_scratch:DI 2 "=v"))]
+  "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
+  "#"
+  "&& 1"
+  [(set (match_dup 2)
+       (zero_extend:DI (match_dup 1)))
+   (set (match_dup 0)
+       (float:IEEE128 (match_dup 2)))]
+{
+  if (GET_CODE (operands[2]) == SCRATCH)
+    operands[2] = gen_reg_rtx (DImode);
+})
 
 ;; IEEE 128-bit instructions with round to odd semantics
 (define_insn "*trunc<mode>df2_odd"

Reply via email to