Patchwork [powerpc] Improve floating point to integer conversions on powerpc

login
register
mail settings
Submitter Michael Meissner
Date Aug. 24, 2010, 6:53 p.m.
Message ID <20100824185338.GA24317@hungry-tiger.westford.ibm.com>
Download mbox | patch
Permalink /patch/62619/
State New
Headers show

Comments

Michael Meissner - Aug. 24, 2010, 6:53 p.m.
This is the second patch in terms improving floating point conversions on the
powerpc.

The changes here include:

    1)	Merge SF/DF patterns into a single combined insn;

    2)	Add missing power7 conversions;

    3)	Add combiner insns to reduce the cases where the target of the
	conversion is going to be stored in memory to prevent the compiler from
	storing the value into the stack, reloading it into a GPR, and then
	storing it to the destination.

    4)	Eliminate another case of pre-IRA register allocator constraints that
	doesn't work as well with IRA, and add extra round trips through memory
	and GPRs.

    5)	Generate code for the lrint builtin funciton (on 64-bit) and llrint (on
	both 32 and 64-bit).

As before, I bootstraped and did make check with no regressions.

I built SPE code for -mcpu=e500mc and -mcpu=e500mc64 with no differences.

I added 5 tests to test the basic functionality for different code models.

[gcc]
2010-08-24  Michael Meissner  <meissner@linux.vnet.ibm.com>

	* config/rs6000/rs6000.md (fixuns_truncsfsi2): Delete, merge into
	common pattern for both SF/DF.  Add power7 support.
	(fix_truncsfsi2): Ditto.
	(fixuns_truncdfsi2): Ditto.
	(fixuns_truncdfdi2): Ditto.
	(fix_truncdfsi2): Ditto.
	(fix_truncdfsi2_internal): Ditto.
	(fix_truncdfsi2_internal_gfxopt): Ditto.
	(fix_truncdfsi2_mfpgpr): Ditto.
	(fctiwz): Ditto.
	(btruncdf2): Ditto.
	(btruncdf2_fpr): Ditto.
	(btructsf2): Ditto.
	(ceildf2): Ditto.
	(ceildf2_fpr): Ditto.
	(ceilsf2): Ditto.
	(floordf2): Ditto.
	(floordf2_fpr): Ditto.
	(floorsf2): Ditto.
	(rounddf2): Ditto.
	(rounddf2_fpr): Ditto.
	(roundsf2): Ditto.
	(fix_trunc<mode>si2): Combine SF/DF conversion into one insn.
	(fix_trunc<mode>di2): Ditto.
	(fixuns_trunc<mode>si2): Ditto.
	(fixuns_trunc<mode>di2): Ditto.
	(fctiwz_<mode>): Ditto.
	(btrunc<mode>2): Ditto.
	(btrunc<mode>2_fpr): Ditto.
	(ceil<mode>2): Ditto.
	(ceil<mode>2_fpr): Ditto.
	(floor<mode>2): Ditto.
	(float<mode>2_fpr): Ditto.
	(round<mode>2): Ditto.
	(round<mode>2_fpr): Ditto.
	(fix_trunc<mode>si2_stfiwx): New insn for machines with STFIWX.
	(fixuns_trunc<mode>si2_stfiwx): Ditto.
	(fix_truncdfsi2_internal): Ditto.
	(fix_trunc<mode>si2_mem): Combiner pattern to eliminate storing
	converted value on stack, loaded into GPR, and then stored into
	the final destination.
	(fix_trunc<mode>di2_fctidz): New pattern for targets supporting
	FCTIDZ.
	(lrint<mode>di2): New insn, provide the lrint builtin functions.
	(ftruncdf2): Delete, unused.
	(fix_trunctfsi2_internal): Use gen_fctiwz_df, not gen_fctiwz.

	* config/rs6000/vsx.md (toplevel): Update copyright year.
	(VSr2): Use "ws" contraint for DFmode, not "!r#r".
	(VSr3): Ditto.

[gcc/testsuite]
2010-08-24  Michael Meissner  <meissner@linux.vnet.ibm.com>

	* gcc.target/powerpc/ppc-fpconv-5.c: New test for floating point
	to integer conversion code generation.
	* gcc.target/powerpc/ppc-fpconv-6.c: Ditto.
	* gcc.target/powerpc/ppc-fpconv-7.c: Ditto.
	* gcc.target/powerpc/ppc-fpconv-8.c: Ditto.
	* gcc.target/powerpc/ppc-fpconv-9.c: Ditto.
David Edelsohn - Aug. 27, 2010, 7:39 p.m.
On Tue, Aug 24, 2010 at 2:53 PM, Michael Meissner
<meissner@linux.vnet.ibm.com> wrote:
> This is the second patch in terms improving floating point conversions on the
> powerpc.
>
> The changes here include:
>
>    1)  Merge SF/DF patterns into a single combined insn;
>
>    2)  Add missing power7 conversions;
>
>    3)  Add combiner insns to reduce the cases where the target of the
>        conversion is going to be stored in memory to prevent the compiler from
>        storing the value into the stack, reloading it into a GPR, and then
>        storing it to the destination.
>
>    4)  Eliminate another case of pre-IRA register allocator constraints that
>        doesn't work as well with IRA, and add extra round trips through memory
>        and GPRs.
>
>    5)  Generate code for the lrint builtin funciton (on 64-bit) and llrint (on
>        both 32 and 64-bit).
>
> As before, I bootstraped and did make check with no regressions.
>
> I built SPE code for -mcpu=e500mc and -mcpu=e500mc64 with no differences.
>
> I added 5 tests to test the basic functionality for different code models.
>
> [gcc]
> 2010-08-24  Michael Meissner  <meissner@linux.vnet.ibm.com>
>
>        * config/rs6000/rs6000.md (fixuns_truncsfsi2): Delete, merge into
>        common pattern for both SF/DF.  Add power7 support.
>        (fix_truncsfsi2): Ditto.
>        (fixuns_truncdfsi2): Ditto.
>        (fixuns_truncdfdi2): Ditto.
>        (fix_truncdfsi2): Ditto.
>        (fix_truncdfsi2_internal): Ditto.
>        (fix_truncdfsi2_internal_gfxopt): Ditto.
>        (fix_truncdfsi2_mfpgpr): Ditto.
>        (fctiwz): Ditto.
>        (btruncdf2): Ditto.
>        (btruncdf2_fpr): Ditto.
>        (btructsf2): Ditto.
>        (ceildf2): Ditto.
>        (ceildf2_fpr): Ditto.
>        (ceilsf2): Ditto.
>        (floordf2): Ditto.
>        (floordf2_fpr): Ditto.
>        (floorsf2): Ditto.
>        (rounddf2): Ditto.
>        (rounddf2_fpr): Ditto.
>        (roundsf2): Ditto.
>        (fix_trunc<mode>si2): Combine SF/DF conversion into one insn.
>        (fix_trunc<mode>di2): Ditto.
>        (fixuns_trunc<mode>si2): Ditto.
>        (fixuns_trunc<mode>di2): Ditto.
>        (fctiwz_<mode>): Ditto.
>        (btrunc<mode>2): Ditto.
>        (btrunc<mode>2_fpr): Ditto.
>        (ceil<mode>2): Ditto.
>        (ceil<mode>2_fpr): Ditto.
>        (floor<mode>2): Ditto.
>        (float<mode>2_fpr): Ditto.
>        (round<mode>2): Ditto.
>        (round<mode>2_fpr): Ditto.
>        (fix_trunc<mode>si2_stfiwx): New insn for machines with STFIWX.
>        (fixuns_trunc<mode>si2_stfiwx): Ditto.
>        (fix_truncdfsi2_internal): Ditto.
>        (fix_trunc<mode>si2_mem): Combiner pattern to eliminate storing
>        converted value on stack, loaded into GPR, and then stored into
>        the final destination.
>        (fix_trunc<mode>di2_fctidz): New pattern for targets supporting
>        FCTIDZ.
>        (lrint<mode>di2): New insn, provide the lrint builtin functions.
>        (ftruncdf2): Delete, unused.
>        (fix_trunctfsi2_internal): Use gen_fctiwz_df, not gen_fctiwz.
>
>        * config/rs6000/vsx.md (toplevel): Update copyright year.
>        (VSr2): Use "ws" contraint for DFmode, not "!r#r".
>        (VSr3): Ditto.
>
> [gcc/testsuite]
> 2010-08-24  Michael Meissner  <meissner@linux.vnet.ibm.com>
>
>        * gcc.target/powerpc/ppc-fpconv-5.c: New test for floating point
>        to integer conversion code generation.
>        * gcc.target/powerpc/ppc-fpconv-6.c: Ditto.
>        * gcc.target/powerpc/ppc-fpconv-7.c: Ditto.
>        * gcc.target/powerpc/ppc-fpconv-8.c: Ditto.
>        * gcc.target/powerpc/ppc-fpconv-9.c: Ditto.

Okay.

Thanks, David

Patch

Index: gcc/config/rs6000/vsx.md
===================================================================
--- gcc/config/rs6000/vsx.md	(revision 163480)
+++ gcc/config/rs6000/vsx.md	(working copy)
@@ -1,5 +1,5 @@ 
 ;; VSX patterns.
-;; Copyright (C) 2009
+;; Copyright (C) 2009, 2010
 ;; Free Software Foundation, Inc.
 ;; Contributed by Michael Meissner <meissner@linux.vnet.ibm.com>
 
@@ -73,11 +73,11 @@  (define_mode_attr VSr	[(V16QI "v")
 ;; Map the register class used for float<->int conversions
 (define_mode_attr VSr2	[(V2DF  "wd")
 			 (V4SF  "wf")
-			 (DF    "!f#r")])
+			 (DF    "ws")])
 
 (define_mode_attr VSr3	[(V2DF  "wa")
 			 (V4SF  "wa")
-			 (DF    "!f#r")])
+			 (DF    "ws")])
 
 ;; Map the register class for sp<->dp float conversions, destination
 (define_mode_attr VSr4	[(SF	"ws")
Index: gcc/config/rs6000/rs6000.md
===================================================================
--- gcc/config/rs6000/rs6000.md	(revision 163480)
+++ gcc/config/rs6000/rs6000.md	(working copy)
@@ -6435,30 +6435,6 @@  (define_insn "*fselsfdf4"
 
 ;; Conversions to and from floating-point.
 
-(define_expand "fixuns_truncsfsi2"
-  [(set (match_operand:SI 0 "gpc_reg_operand" "")
-	(unsigned_fix:SI (match_operand:SF 1 "gpc_reg_operand" "")))]
-  "TARGET_HARD_FLOAT && !TARGET_FPRS && TARGET_SINGLE_FLOAT"
-  "")
-
-(define_expand "fix_truncsfsi2"
- [(set (match_operand:SI 0 "gpc_reg_operand" "")
-      (fix:SI (match_operand:SF 1 "gpc_reg_operand" "")))]
- "TARGET_HARD_FLOAT && !TARGET_FPRS && TARGET_SINGLE_FLOAT"
- "")
-
-(define_expand "fixuns_truncdfsi2"
-  [(set (match_operand:SI 0 "gpc_reg_operand" "")
-	(unsigned_fix:SI (match_operand:DF 1 "gpc_reg_operand" "")))]
-  "TARGET_HARD_FLOAT && TARGET_E500_DOUBLE"
-  "")
-
-(define_expand "fixuns_truncdfdi2"
-  [(set (match_operand:DI 0 "register_operand" "")
-	(unsigned_fix:DI (match_operand:DF 1 "register_operand" "")))]
-  "TARGET_HARD_FLOAT && TARGET_VSX"
-  "")
-
 ; We don't define lfiwax/lfiwzx with the normal definition, because we
 ; don't want to support putting SImode in FPR registers.
 (define_insn "lfiwax"
@@ -6793,46 +6769,85 @@  (define_insn_and_split "*floatunssidf2_i
 }"
   [(set_attr "length" "20")])
 
-(define_expand "fix_truncdfsi2"
-  [(parallel [(set (match_operand:SI 0 "fix_trunc_dest_operand" "")
-		   (fix:SI (match_operand:DF 1 "gpc_reg_operand" "")))
-	      (clobber (match_dup 2))
-	      (clobber (match_dup 3))])]
-  "(TARGET_POWER2 || TARGET_POWERPC)
-   && TARGET_HARD_FLOAT && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)"
+(define_expand "fix_trunc<mode>si2"
+  [(set (match_operand:SI 0 "gpc_reg_operand" "")
+	(fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "")))]
+  "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT
+   && ((TARGET_FPRS && <TARGET_FLOAT>) || <E500_CONVERT>)"
   "
 {
-  if (TARGET_E500_DOUBLE)
+  if (!<E500_CONVERT>)
     {
-     emit_insn (gen_spe_fix_truncdfsi2 (operands[0], operands[1]));
-     DONE;
-    }
-  operands[2] = gen_reg_rtx (DImode);
-  if (TARGET_POWERPC64 && TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS
-      && gpc_reg_operand(operands[0], GET_MODE (operands[0])))
-    {
-      operands[3] = gen_reg_rtx (DImode);
-      emit_insn (gen_fix_truncdfsi2_mfpgpr (operands[0], operands[1],
-					    operands[2], operands[3]));
+      rtx tmp, stack;
+
+      if (TARGET_STFIWX)
+	{
+	  tmp = gen_reg_rtx (DImode);
+	  stack = rs6000_allocate_stack_temp (SImode, false, true);
+	  emit_insn (gen_fix_trunc<mode>si2_stfiwx (operands[0], operands[1],
+						    tmp, stack));
+	}
+      else
+	{
+	  tmp = gen_reg_rtx (DImode);
+	  stack = rs6000_allocate_stack_temp (DImode, true, false);
+	  emit_insn (gen_fix_trunc<mode>si2_internal (operands[0], operands[1],
+						      tmp, stack));
+	}
       DONE;
     }
-  if (TARGET_PPC_GFXOPT)
+}")
+
+(define_insn_and_split "fix_trunc<mode>si2_stfiwx"
+  [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+	(fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>")))
+   (clobber (match_operand:DI 2 "gpc_reg_operand" "=d"))
+   (clobber (match_operand:SI 3 "indexed_or_indirect_operand" "=Z"))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+   && (<MODE>mode != SFmode || TARGET_SINGLE_FLOAT)
+   && TARGET_STFIWX"
+  "#"
+  "&& reload_completed"
+  [(pc)]
+  "
+{
+  emit_insn (gen_fctiwz_<mode> (operands[2], operands[1]));
+  if (TARGET_MFPGPR && TARGET_POWERPC64 && REG_P (operands[0])
+      && INT_REGNO_P (REGNO (operands[0])))
     {
-      rtx orig_dest = operands[0];
-      if (! memory_operand (orig_dest, GET_MODE (orig_dest)))
-	operands[0] = assign_stack_temp (SImode, GET_MODE_SIZE (SImode), 0);
-      emit_insn (gen_fix_truncdfsi2_internal_gfxopt (operands[0], operands[1],
-						     operands[2]));
-      if (operands[0] != orig_dest)
-	emit_move_insn (orig_dest, operands[0]);
-      DONE;
+      rtx reg = gen_lowpart (DImode, operands[0]);
+      emit_move_insn (reg, operands[2]);
     }
-  operands[3] = assign_stack_temp (DImode, GET_MODE_SIZE (DImode), 0);
-}")
+  else
+    {
+      emit_insn (gen_stfiwx (operands[3], operands[2]));
+      emit_move_insn (operands[0], operands[3]);
+    }
+  DONE;
+}"
+  [(set_attr "length" "12")])
+
+(define_insn_and_split "*fix_trunc<mode>si2_mem"
+  [(set (match_operand:SI 0 "memory_operand" "=Z")
+	(fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>")))
+   (clobber (match_scratch:DI 2 "=d"))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+   && (<MODE>mode != SFmode || TARGET_SINGLE_FLOAT)
+   && TARGET_STFIWX"
+  "#"
+  "&& reload_completed"
+  [(pc)]
+  "
+{
+  emit_insn (gen_fctiwz_<mode> (operands[2], operands[1]));
+  emit_insn (gen_stfiwx (operands[0], operands[2]));
+  DONE;
+}"
+  [(set_attr "length" "8")])
 
-(define_insn_and_split "*fix_truncdfsi2_internal"
+(define_insn_and_split "fix_trunc<mode>si2_internal"
   [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
-	(fix:SI (match_operand:DF 1 "gpc_reg_operand" "d")))
+	(fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "<rreg>")))
    (clobber (match_operand:DI 2 "gpc_reg_operand" "=d"))
    (clobber (match_operand:DI 3 "offsettable_mem_operand" "=o"))]
   "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT && TARGET_FPRS 
@@ -6846,143 +6861,194 @@  (define_insn_and_split "*fix_truncdfsi2_
   gcc_assert (MEM_P (operands[3]));
   lowword = adjust_address (operands[3], SImode, WORDS_BIG_ENDIAN ? 4 : 0);
 
-  emit_insn (gen_fctiwz (operands[2], operands[1]));
+  emit_insn (gen_fctiwz_<mode> (operands[2], operands[1]));
   emit_move_insn (operands[3], operands[2]);
   emit_move_insn (operands[0], lowword);
   DONE;
 }"
   [(set_attr "length" "16")])
 
-(define_insn_and_split "fix_truncdfsi2_internal_gfxopt"
+(define_expand "fix_trunc<mode>di2"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "")
+	(fix:DI (match_operand:SFDF 1 "gpc_reg_operand" "")))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS
+   && TARGET_FCFID"
+  "")
+
+(define_insn "*fix_trunc<mode>di2_fctidz"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=d")
+	(fix:DI (match_operand:SFDF 1 "gpc_reg_operand" "d")))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS
+    && TARGET_FCFID && !VECTOR_UNIT_VSX_P (<MODE>mode)"
+  "fctidz %0,%1"
+  [(set_attr "type" "fp")])
+
+(define_expand "fixuns_trunc<mode>si2"
+  [(set (match_operand:SI 0 "gpc_reg_operand" "")
+	(unsigned_fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "")))]
+  "TARGET_HARD_FLOAT
+   && ((TARGET_FPRS && <TARGET_FLOAT> && TARGET_FCTIWUZ && TARGET_STFIWX)
+       || <E500_CONVERT>)"
+  "
+{
+  if (!<E500_CONVERT>)
+    {
+      rtx tmp = gen_reg_rtx (DImode);
+      rtx stack = rs6000_allocate_stack_temp (SImode, false, true);
+      emit_insn (gen_fixuns_trunc<mode>si2_stfiwx (operands[0], operands[1],
+						   tmp, stack));
+      DONE;
+    }
+}")
+
+(define_insn_and_split "fixuns_trunc<mode>si2_stfiwx"
+  [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+	(unsigned_fix:SI
+	 (match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>")))
+   (clobber (match_operand:DI 2 "gpc_reg_operand" "=d"))
+   (clobber (match_operand:SI 3 "indexed_or_indirect_operand" "=Z"))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT> && TARGET_FCTIWUZ
+   && TARGET_STFIWX"
+  "#"
+  "&& reload_completed"
+  [(pc)]
+  "
+{
+  emit_insn (gen_fctiwuz_<mode> (operands[2], operands[1]));
+  if (TARGET_MFPGPR && TARGET_POWERPC64 && REG_P (operands[0])
+      && INT_REGNO_P (REGNO (operands[0])))
+    {
+      rtx reg = gen_lowpart (DImode, operands[0]);
+      emit_move_insn (reg, operands[2]);
+    }
+  else
+    {
+      emit_insn (gen_stfiwx (operands[3], operands[2]));
+      emit_move_insn (operands[0], operands[3]);
+    }
+  DONE;
+}"
+  [(set_attr "length" "12")])
+
+(define_insn_and_split "*fixuns_trunc<mode>si2_mem"
   [(set (match_operand:SI 0 "memory_operand" "=Z")
-	(fix:SI (match_operand:DF 1 "gpc_reg_operand" "d")))
-   (clobber (match_operand:DI 2 "gpc_reg_operand" "=d"))]
-  "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT && TARGET_FPRS 
-   && TARGET_DOUBLE_FLOAT 
-   && TARGET_PPC_GFXOPT"
+	(unsigned_fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>")))
+   (clobber (match_scratch:DI 2 "=d"))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT> && TARGET_FCTIWUZ
+   && TARGET_STFIWX"
   "#"
-  "&& 1"
+  "&& reload_completed"
   [(pc)]
   "
 {
-  emit_insn (gen_fctiwz (operands[2], operands[1]));
+  emit_insn (gen_fctiwuz_<mode> (operands[2], operands[1]));
   emit_insn (gen_stfiwx (operands[0], operands[2]));
   DONE;
 }"
-  [(set_attr "length" "16")])
+  [(set_attr "length" "8")])
 
-(define_insn_and_split "fix_truncdfsi2_mfpgpr"
-  [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
-	(fix:SI (match_operand:DF 1 "gpc_reg_operand" "d")))
-   (clobber (match_operand:DI 2 "gpc_reg_operand" "=d"))
-   (clobber (match_operand:DI 3 "gpc_reg_operand" "=r"))]
-  "TARGET_POWERPC64 && TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS 
-   && TARGET_DOUBLE_FLOAT"
-  "#"
-  "&& 1"
-  [(set (match_dup 2) (unspec:DI [(fix:SI (match_dup 1))] UNSPEC_FCTIWZ))
-   (set (match_dup 3) (match_dup 2))
-   (set (match_dup 0) (subreg:SI (match_dup 3) 4))]
-  ""
-  [(set_attr "length" "12")])
+(define_expand "fixuns_trunc<mode>di2"
+  [(set (match_operand:DI 0 "register_operand" "")
+	(unsigned_fix:DI (match_operand:SFDF 1 "register_operand" "")))]
+  "TARGET_HARD_FLOAT && (TARGET_FCTIDUZ || VECTOR_UNIT_VSX_P (<MODE>mode))"
+  "")
+
+(define_insn "*fixuns_trunc<mode>di2_fctiduz"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=d")
+	(unsigned_fix:DI (match_operand:SFDF 1 "gpc_reg_operand" "d")))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS
+    && TARGET_FCTIDUZ && !VECTOR_UNIT_VSX_P (<MODE>mode)"
+  "fctiduz %0,%1"
+  [(set_attr "type" "fp")])
 
 ; Here, we use (set (reg) (unspec:DI [(fix:SI ...)] UNSPEC_FCTIWZ))
 ; rather than (set (subreg:SI (reg)) (fix:SI ...))
 ; because the first makes it clear that operand 0 is not live
 ; before the instruction.
-(define_insn "fctiwz"
+(define_insn "fctiwz_<mode>"
   [(set (match_operand:DI 0 "gpc_reg_operand" "=d")
-	(unspec:DI [(fix:SI (match_operand:DF 1 "gpc_reg_operand" "d"))]
+	(unspec:DI [(fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "d"))]
 		   UNSPEC_FCTIWZ))]
   "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT && TARGET_FPRS 
    && TARGET_DOUBLE_FLOAT"
   "{fcirz|fctiwz} %0,%1"
   [(set_attr "type" "fp")])
 
-(define_expand "btruncdf2"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
-	(unspec:DF [(match_operand:DF 1 "gpc_reg_operand" "d")] UNSPEC_FRIZ))]
-  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT"
-  "")
-
-(define_insn "*btruncdf2_fpr"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
-	(unspec:DF [(match_operand:DF 1 "gpc_reg_operand" "f")] UNSPEC_FRIZ))]
-  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
-   && !VECTOR_UNIT_VSX_P (DFmode)"
-  "friz %0,%1"
+(define_insn "fctiwuz_<mode>"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=d")
+	(unspec:DI [(unsigned_fix:SI
+		     (match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>"))]
+		   UNSPEC_FCTIWUZ))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT> && TARGET_FCTIWUZ"
+  "fctiwuz %0,%1"
   [(set_attr "type" "fp")])
 
-(define_insn "btruncsf2"
-  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-	(unspec:SF [(match_operand:SF 1 "gpc_reg_operand" "f")] UNSPEC_FRIZ))]
-  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT"
-  "friz %0,%1"
+;; No VSX equivalent to fctid
+(define_insn "lrint<mode>di2"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=d")
+	(unspec:DI [(match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>")]
+		   UNSPEC_FCTID))]
+  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT>"
+  "fctid %0,%1"
   [(set_attr "type" "fp")])
 
-(define_expand "ceildf2"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "")
-	(unspec:DF [(match_operand:DF 1 "gpc_reg_operand" "")] UNSPEC_FRIP))]
-  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT"
+(define_expand "btrunc<mode>2"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "")
+	(unspec:SFDF [(match_operand:SFDF 1 "gpc_reg_operand" "")]
+		     UNSPEC_FRIZ))]
+  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT>"
   "")
 
-(define_insn "*ceildf2_fpr"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
-	(unspec:DF [(match_operand:DF 1 "gpc_reg_operand" "d")] UNSPEC_FRIP))]
-  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
-   && !VECTOR_UNIT_VSX_P (DFmode)"
-  "frip %0,%1"
+(define_insn "*btrunc<mode>2_fpr"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>")
+	(unspec:SFDF [(match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>")]
+		     UNSPEC_FRIZ))]
+  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT>
+   && !VECTOR_UNIT_VSX_P (<MODE>mode)"
+  "friz %0,%1"
   [(set_attr "type" "fp")])
 
-(define_insn "ceilsf2"
- [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-	(unspec:SF [(match_operand:SF 1 "gpc_reg_operand" "f")] UNSPEC_FRIP))]
-  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT "
+(define_expand "ceil<mode>2"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "")
+	(unspec:SFDF [(match_operand:SFDF 1 "gpc_reg_operand" "")]
+		     UNSPEC_FRIP))]
+  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT>"
+  "")
+
+(define_insn "*ceil<mode>2_fpr"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>")
+	(unspec:SFDF [(match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>")]
+		     UNSPEC_FRIP))]
+  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT>
+   && !VECTOR_UNIT_VSX_P (<MODE>mode)"
   "frip %0,%1"
   [(set_attr "type" "fp")])
 
-(define_expand "floordf2"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "")
-	(unspec:DF [(match_operand:DF 1 "gpc_reg_operand" "")] UNSPEC_FRIM))]
-  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT"
+(define_expand "floor<mode>2"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "")
+	(unspec:SFDF [(match_operand:SFDF 1 "gpc_reg_operand" "")]
+		     UNSPEC_FRIM))]
+  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT>"
   "")
 
-(define_insn "*floordf2_fpr"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
-	(unspec:DF [(match_operand:DF 1 "gpc_reg_operand" "d")] UNSPEC_FRIM))]
-  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
-   && !VECTOR_UNIT_VSX_P (DFmode)"
-  "frim %0,%1"
-  [(set_attr "type" "fp")])
-
-(define_insn "floorsf2"
-  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-	(unspec:SF [(match_operand:SF 1 "gpc_reg_operand" "f")] UNSPEC_FRIM))]
-  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT "
+(define_insn "*floor<mode>2_fpr"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>")
+	(unspec:SFDF [(match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>")]
+		     UNSPEC_FRIM))]
+  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT>
+   && !VECTOR_UNIT_VSX_P (<MODE>mode)"
   "frim %0,%1"
   [(set_attr "type" "fp")])
 
 ;; No VSX equivalent to frin
-(define_insn "rounddf2"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
-	(unspec:DF [(match_operand:DF 1 "gpc_reg_operand" "d")] UNSPEC_FRIN))]
-  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT"
-  "frin %0,%1"
-  [(set_attr "type" "fp")])
-
-(define_insn "roundsf2"
-  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-	(unspec:SF [(match_operand:SF 1 "gpc_reg_operand" "f")] UNSPEC_FRIN))]
-  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT "
+(define_insn "round<mode>2"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>")
+	(unspec:SFDF [(match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>")]
+		     UNSPEC_FRIN))]
+  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT>"
   "frin %0,%1"
   [(set_attr "type" "fp")])
 
-(define_expand "ftruncdf2"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "")
-  	(fix:DF (match_operand:DF 1 "gpc_reg_operand" "")))]
-  "VECTOR_UNIT_VSX_P (DFmode)"
-  "")
-
 ; An UNSPEC is used so we don't have to support SImode in FP registers.
 (define_insn "stfiwx"
   [(set (match_operand:SI 0 "memory_operand" "=Z")
@@ -9860,7 +9926,7 @@  (define_insn_and_split "*fix_trunctfsi2_
   gcc_assert (MEM_P (operands[5]));
   lowword = adjust_address (operands[5], SImode, WORDS_BIG_ENDIAN ? 4 : 0);
 
-  emit_insn (gen_fctiwz (operands[4], operands[2]));
+  emit_insn (gen_fctiwz_df (operands[4], operands[2]));
   emit_move_insn (operands[5], operands[4]);
   emit_move_insn (operands[0], lowword);
   DONE;
Index: gcc/testsuite/gcc.target/powerpc/ppc-fpconv-7.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/ppc-fpconv-7.c	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/ppc-fpconv-7.c	(revision 0)
@@ -0,0 +1,22 @@ 
+/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
+/* { dg-require-effective-target ilp32 } */
+/* { dg-options "-O3 -mcpu=power5 -ffast-math" } */
+/* { dg-final { scan-assembler-times "fctiwz" 2 } } */
+/* { dg-final { scan-assembler-not "fctiwuz" } } */
+/* { dg-final { scan-assembler-times "fctidz" 8 } } */
+/* { dg-final { scan-assembler-not "fctiduz" } } */
+/* { dg-final { scan-assembler-not "xscvdpsxds" } } */
+/* { dg-final { scan-assembler-not "xscvdpuxds" } } */
+
+void float_to_int  (int *dest, float  src) { *dest = (int) src; }
+void double_to_int (int *dest, double src) { *dest = (int) src; }
+
+void float_to_uint  (int *dest, float  src) { *dest = (unsigned int) src; }
+void double_to_uint (int *dest, double src) { *dest = (unsigned int) src; }
+
+void float_to_llong  (long long *dest, float  src) { *dest = (long long) src; }
+void double_to_llong (long long *dest, double src) { *dest = (long long) src; }
+
+void float_to_ullong  (unsigned long long *dest, float  src) { *dest = (unsigned long long) src; }
+void double_to_ullong (unsigned long long *dest, double src) { *dest = (unsigned long long) src; }
Index: gcc/testsuite/gcc.target/powerpc/ppc-fpconv-8.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/ppc-fpconv-8.c	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/ppc-fpconv-8.c	(revision 0)
@@ -0,0 +1,22 @@ 
+/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
+/* { dg-require-effective-target ilp32 } */
+/* { dg-options "-O3 -mcpu=750 -ffast-math" } */
+/* { dg-final { scan-assembler-times "fctiwz" 6 } } */
+/* { dg-final { scan-assembler-not "fctiwuz" } } */
+/* { dg-final { scan-assembler-not "fctidz" } } */
+/* { dg-final { scan-assembler-not "fctiduz" } } */
+/* { dg-final { scan-assembler-not "xscvdpsxds" } } */
+/* { dg-final { scan-assembler-not "xscvdpuxds" } } */
+
+void float_to_int  (int *dest, float  src) { *dest = (int) src; }
+void double_to_int (int *dest, double src) { *dest = (int) src; }
+
+void float_to_uint  (int *dest, float  src) { *dest = (unsigned int) src; }
+void double_to_uint (int *dest, double src) { *dest = (unsigned int) src; }
+
+void float_to_llong  (long long *dest, float  src) { *dest = (long long) src; }
+void double_to_llong (long long *dest, double src) { *dest = (long long) src; }
+
+void float_to_ullong  (unsigned long long *dest, float  src) { *dest = (unsigned long long) src; }
+void double_to_ullong (unsigned long long *dest, double src) { *dest = (unsigned long long) src; }
Index: gcc/testsuite/gcc.target/powerpc/ppc-fpconv-9.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/ppc-fpconv-9.c	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/ppc-fpconv-9.c	(revision 0)
@@ -0,0 +1,11 @@ 
+/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
+/* { dg-require-effective-target powerpc_vsx_ok } */
+/* { dg-options "-O3 -mcpu=power7 -ffast-math" } */
+/* { dg-final { scan-assembler-not "lwz" } } */
+/* { dg-final { scan-assembler-not "stw" } } */
+/* { dg-final { scan-assembler-not "ld " } } */
+/* { dg-final { scan-assembler-not "std" } } */
+
+void float_to_llong  (long long *dest, float  src) { *dest = (long long) src; }
+void double_to_llong (long long *dest, double src) { *dest = (long long) src; }
Index: gcc/testsuite/gcc.target/powerpc/ppc-fpconv-5.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/ppc-fpconv-5.c	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/ppc-fpconv-5.c	(revision 0)
@@ -0,0 +1,22 @@ 
+/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
+/* { dg-require-effective-target powerpc_vsx_ok } */
+/* { dg-options "-O3 -mcpu=power7 -ffast-math" } */
+/* { dg-final { scan-assembler-times "fctiwz" 2 } } */
+/* { dg-final { scan-assembler-times "fctiwuz" 2 } } */
+/* { dg-final { scan-assembler-times "fctidz" 1 } } */
+/* { dg-final { scan-assembler-times "fctiduz" 1 } } */
+/* { dg-final { scan-assembler-times "xscvdpsxds" 1 } } */
+/* { dg-final { scan-assembler-times "xscvdpuxds" 1 } } */
+
+void float_to_int  (int *dest, float  src) { *dest = (int) src; }
+void double_to_int (int *dest, double src) { *dest = (int) src; }
+
+void float_to_uint  (int *dest, float  src) { *dest = (unsigned int) src; }
+void double_to_uint (int *dest, double src) { *dest = (unsigned int) src; }
+
+void float_to_llong  (long long *dest, float  src) { *dest = (long long) src; }
+void double_to_llong (long long *dest, double src) { *dest = (long long) src; }
+
+void float_to_ullong  (unsigned long long *dest, float  src) { *dest = (unsigned long long) src; }
+void double_to_ullong (unsigned long long *dest, double src) { *dest = (unsigned long long) src; }
Index: gcc/testsuite/gcc.target/powerpc/ppc-fpconv-6.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/ppc-fpconv-6.c	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/ppc-fpconv-6.c	(revision 0)
@@ -0,0 +1,22 @@ 
+/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
+/* { dg-require-effective-target powerpc_vsx_ok } */
+/* { dg-options "-O3 -mcpu=power6 -ffast-math" } */
+/* { dg-final { scan-assembler-times "fctiwz" 2 } } */
+/* { dg-final { scan-assembler-not "fctiwuz" } } */
+/* { dg-final { scan-assembler-times "fctidz" 8 } } */
+/* { dg-final { scan-assembler-not "fctiduz" } } */
+/* { dg-final { scan-assembler-not "xscvdpsxds" } } */
+/* { dg-final { scan-assembler-not "xscvdpuxds" } } */
+
+void float_to_int  (int *dest, float  src) { *dest = (int) src; }
+void double_to_int (int *dest, double src) { *dest = (int) src; }
+
+void float_to_uint  (int *dest, float  src) { *dest = (unsigned int) src; }
+void double_to_uint (int *dest, double src) { *dest = (unsigned int) src; }
+
+void float_to_llong  (long long *dest, float  src) { *dest = (long long) src; }
+void double_to_llong (long long *dest, double src) { *dest = (long long) src; }
+
+void float_to_ullong  (unsigned long long *dest, float  src) { *dest = (unsigned long long) src; }
+void double_to_ullong (unsigned long long *dest, double src) { *dest = (unsigned long long) src; }