diff mbox

, PR target/78597, Fix PowerPC fp-int-convert-{float128-ieee,float64x}

Message ID 20170131012100.GA28913@ibm-tiger.the-meissners.org
State New
Headers show

Commit Message

Michael Meissner Jan. 31, 2017, 1:21 a.m. UTC
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  <meissner@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.

Comments

Segher Boessenkool Jan. 31, 2017, 11:07 a.m. UTC | #1
On Mon, Jan 30, 2017 at 08:21:00PM -0500, Michael Meissner wrote:
> 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.

Yes, it looks quite safe like this.  Thanks for the rework.

Just two very very minor things:

>  (define_expand "floatsi<mode>2"

> +  rtx op1 = operands[1]; 

Trailing space here.

> +;; Conersion between IEEE 128-bit and integer types
> +(define_insn "fix_<mode>di2_hw"

Typo (conversion).

Okay for trunk with those fixed.  Thanks!


Segher
diff mbox

Patch

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"