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

login
register
mail settings
Submitter Michael Meissner
Date Aug. 24, 2010, 2:58 p.m.
Message ID <20100824145857.GA6425@hungry-tiger.westford.ibm.com>
Download mbox | patch
Permalink /patch/62600/
State New
Headers show

Comments

Michael Meissner - Aug. 24, 2010, 2:58 p.m.
(Something has futzed with my work email configuration, so I'm routing this
through my home email account).

This patch is the first of 3 patches that I wrote to improve floating point
conversions on modern powerpc's.  This patch improves the conversion of integer
types to binary floating point.  The second patch will improve the conversion
of binary floating point to integer types.  The third patch will add support
for patterns to optimize rounding conversions like (double)(int)x.  A few
defines and unspec constants are defined in this patch that won't be used until
the other patches are submitted.

The main changes in this patch are:

    1)	On newer machines, generate the FCFID instruction in 32-bit mode.  In
	older machines, the FCFID was only available in 64-bit mode.

    2)	Add support for ISA 2.05 (LFIWAX) and ISA 2.06 (LFIWZX, FCFIDS, FCFIDU,
	FCFIDUS) instructions.

    3)	Tweak the previous changes I had made to automatically set various
	options if one of the newer ISA switches is used.  Split embedded from
	server options.  If -mcpu=power7 -mno-altivec, note -mvsx is an
	explicit option.

    4)	Fix up the constraints in a mode attribute that previously was unused.

    5)	Add combiners for converting items from memory to optimize not loading
	the value into a GPR, then spilling it on the stack, and reloading it
	into a FPR for conversion.

    6)	Use "d" or "f" constraints, instead of !d#r, to reduce the spills
	generated by the compiler.

I did a bootstrap and make check.  There were no regressions with this patch.
In addition, the test gcc.target/powerpc/ppc64-double-1.c is now fixed.

I built an powerpc-eabispe compiler, and verified that the compiler with the
patches generates exactly the same code as the compiler without the patches for
-mcpu=e500mc and -mcpu=e500mc64.

I tested the code for -mcpu=750 in 32-bit, and verified that the code was the
same (i.e. no FCFID was generated in 32-bit mode).

I added 4 tests to test the code for various machines.

Are these patches ok to apply?
Nathan Froyd - Aug. 24, 2010, 7:03 p.m.
On Tue, Aug 24, 2010 at 10:58:57AM -0400, Michael Meissner wrote:
> I built an powerpc-eabispe compiler, and verified that the compiler with the
> patches generates exactly the same code as the compiler without the patches for
> -mcpu=e500mc and -mcpu=e500mc64.

This is kind of an odd combination, since the e500mc and the e500mc64
use "classic" floating-point, i.e. the same model as POWER* chips.  The
more interesting combination would be a powerpc-eabispe compiler with:

- -mcpu=8540 -mfloat-gprs=single (hard single, soft double)
- -mcpu=8548 -mfloat-gprs=double (hard single and double)

since that will exercise the E500 code paths a bit more.  You may also
want to check your new FP testcases with such a toolchain.  (Though I
think they will still pass, due to the explicit -mcpu.)

-Nathan
Michael Meissner - Aug. 24, 2010, 7:45 p.m.
On Tue, Aug 24, 2010 at 12:03:45PM -0700, Nathan Froyd wrote:
> On Tue, Aug 24, 2010 at 10:58:57AM -0400, Michael Meissner wrote:
> > I built an powerpc-eabispe compiler, and verified that the compiler with the
> > patches generates exactly the same code as the compiler without the patches for
> > -mcpu=e500mc and -mcpu=e500mc64.
> 
> This is kind of an odd combination, since the e500mc and the e500mc64
> use "classic" floating-point, i.e. the same model as POWER* chips.  The
> more interesting combination would be a powerpc-eabispe compiler with:
> 
> - -mcpu=8540 -mfloat-gprs=single (hard single, soft double)
> - -mcpu=8548 -mfloat-gprs=double (hard single and double)
> 
> since that will exercise the E500 code paths a bit more.  You may also
> want to check your new FP testcases with such a toolchain.  (Though I
> think they will still pass, due to the explicit -mcpu.)

Except for the .ident strings, they produce the same code for both sets of
options.  Thanks for pointing me it the right direction of options to use.
David Edelsohn - Aug. 27, 2010, 7:45 p.m.
On Tue, Aug 24, 2010 at 10:58 AM, Michael Meissner
<meissner@linux.vnet.ibm.com> wrote:

> This patch is the first of 3 patches that I wrote to improve floating point
> conversions on modern powerpc's.  This patch improves the conversion of integer
> types to binary floating point.  The second patch will improve the conversion
> of binary floating point to integer types.  The third patch will add support
> for patterns to optimize rounding conversions like (double)(int)x.  A few
> defines and unspec constants are defined in this patch that won't be used until
> the other patches are submitted.
>
> The main changes in this patch are:
>
>    1)  On newer machines, generate the FCFID instruction in 32-bit mode.  In
>        older machines, the FCFID was only available in 64-bit mode.
>
>    2)  Add support for ISA 2.05 (LFIWAX) and ISA 2.06 (LFIWZX, FCFIDS, FCFIDU,
>        FCFIDUS) instructions.
>
>    3)  Tweak the previous changes I had made to automatically set various
>        options if one of the newer ISA switches is used.  Split embedded from
>        server options.  If -mcpu=power7 -mno-altivec, note -mvsx is an
>        explicit option.
>
>    4)  Fix up the constraints in a mode attribute that previously was unused.
>
>    5)  Add combiners for converting items from memory to optimize not loading
>        the value into a GPR, then spilling it on the stack, and reloading it
>        into a FPR for conversion.
>
>    6)  Use "d" or "f" constraints, instead of !d#r, to reduce the spills
>        generated by the compiler.
>
> I did a bootstrap and make check.  There were no regressions with this patch.
> In addition, the test gcc.target/powerpc/ppc64-double-1.c is now fixed.
>
> I built an powerpc-eabispe compiler, and verified that the compiler with the
> patches generates exactly the same code as the compiler without the patches for
> -mcpu=e500mc and -mcpu=e500mc64.
>
> I tested the code for -mcpu=750 in 32-bit, and verified that the code was the
> same (i.e. no FCFID was generated in 32-bit mode).
>
> I added 4 tests to test the code for various machines.

Okay.

Thanks, David

Patch

Index: gcc/config/rs6000/rs6000-protos.h
===================================================================
--- gcc/config/rs6000/rs6000-protos.h	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 163471)
+++ gcc/config/rs6000/rs6000-protos.h	(working copy)
@@ -129,6 +129,9 @@  extern void rs6000_emit_parity (rtx, rtx
 
 extern rtx rs6000_machopic_legitimize_pic_address (rtx, enum machine_mode,
 						   rtx);
+extern rtx rs6000_address_for_fpconvert (rtx);
+extern rtx rs6000_allocate_stack_temp (enum machine_mode, bool, bool);
+extern void rs6000_expand_convert_si_to_sfdf (rtx, rtx, bool);
 #endif /* RTX_CODE */
 
 #ifdef TREE_CODE
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 163471)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -2501,10 +2501,10 @@  rs6000_override_options (const char *def
 	  POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_PPC_GFXOPT
 	  | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND | MASK_CMPB | MASK_DFP
 	  | MASK_MFPGPR | MASK_RECIP_PRECISION},
-	 {"power7", PROCESSOR_POWER7,
+	 {"power7", PROCESSOR_POWER7,   /* Don't add MASK_ISEL by default */
 	  POWERPC_7400_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_MFCRF
 	  | MASK_POPCNTB | MASK_FPRND | MASK_CMPB | MASK_DFP | MASK_POPCNTD
-	  | MASK_VSX| MASK_RECIP_PRECISION},	/* Don't add MASK_ISEL by default */
+	  | MASK_VSX | MASK_RECIP_PRECISION},
 	 {"powerpc", PROCESSOR_POWERPC, POWERPC_BASE_MASK},
 	 {"powerpc64", PROCESSOR_POWERPC64,
 	  POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
@@ -2541,15 +2541,19 @@  rs6000_override_options (const char *def
     ISA_2_1_MASKS = MASK_MFCRF,
     ISA_2_2_MASKS = (ISA_2_1_MASKS | MASK_POPCNTB | MASK_FPRND),
 
-    /* For ISA 2.05, do not add MFPGPR, since it isn't in ISA 2.06, and
-       don't add ALTIVEC, since in general it isn't a win on power6.  */
-    ISA_2_5_MASKS = (ISA_2_2_MASKS | MASK_CMPB | MASK_RECIP_PRECISION
-		     | MASK_DFP),
+    /* For ISA 2.05, do not add MFPGPR, since it isn't in ISA 2.06, and don't
+       add ALTIVEC, since in general it isn't a win on power6.  In ISA 2.04,
+       fsel, fre, fsqrt, etc. were no longer documented as optional.  Group
+       masks by server and embedded. */
+    ISA_2_5_MASKS_EMBEDDED = (ISA_2_2_MASKS | MASK_CMPB | MASK_RECIP_PRECISION
+			      | MASK_PPC_GFXOPT | MASK_PPC_GPOPT),
+    ISA_2_5_MASKS_SERVER = (ISA_2_5_MASKS_EMBEDDED | MASK_DFP),
 
     /* For ISA 2.06, don't add ISEL, since in general it isn't a win, but
        altivec is a win so enable it.  */
-    ISA_2_6_MASKS = (ISA_2_5_MASKS | MASK_ALTIVEC | MASK_POPCNTD
-		     | MASK_VSX | MASK_RECIP_PRECISION)
+    ISA_2_6_MASKS_EMBEDDED = (ISA_2_5_MASKS_EMBEDDED | MASK_POPCNTD),
+    ISA_2_6_MASKS_SERVER = (ISA_2_5_MASKS_SERVER | MASK_POPCNTD | MASK_ALTIVEC
+			    | MASK_VSX)
   };
 
   /* Numerous experiment shows that IRA based loop pressure
@@ -2690,15 +2694,22 @@  rs6000_override_options (const char *def
 	{
 	  warning (0, msg);
 	  target_flags &= ~ MASK_VSX;
+	  target_flags_explicit |= MASK_VSX;
 	}
     }
 
   /* For the newer switches (vsx, dfp, etc.) set some of the older options,
      unless the user explicitly used the -mno-<option> to disable the code.  */
   if (TARGET_VSX)
-    target_flags |= (ISA_2_6_MASKS & ~target_flags_explicit);
+    target_flags |= (ISA_2_6_MASKS_SERVER & ~target_flags_explicit);
+  else if (TARGET_POPCNTD)
+    target_flags |= (ISA_2_6_MASKS_EMBEDDED & ~target_flags_explicit);
   else if (TARGET_DFP)
-    target_flags |= (ISA_2_5_MASKS & ~target_flags_explicit);
+    target_flags |= (ISA_2_5_MASKS_SERVER & ~target_flags_explicit);
+  else if (TARGET_CMPB)
+    target_flags |= (ISA_2_5_MASKS_EMBEDDED & ~target_flags_explicit);
+  else if (TARGET_POPCNTB || TARGET_FPRND)
+    target_flags |= (ISA_2_2_MASKS & ~target_flags_explicit);
   else if (TARGET_ALTIVEC)
     target_flags |= (MASK_PPC_GFXOPT & ~target_flags_explicit);
 
@@ -26941,4 +26952,122 @@  rs6000_final_prescan_insn (rtx insn, rtx
     }
 }
 
+
+/* Allocate a stack temp and fixup the address so it meets the particular
+   memory requirements (either offetable or REG+REG addressing).  */
+
+rtx
+rs6000_allocate_stack_temp (enum machine_mode mode,
+			    bool offsettable_p,
+			    bool reg_reg_p)
+{
+  rtx stack = assign_stack_temp (mode, GET_MODE_SIZE (mode), 0);
+  rtx addr = XEXP (stack, 0);
+  int strict_p = (reload_in_progress || reload_completed);
+
+  if (!legitimate_indirect_address_p (addr, strict_p))
+    {
+      if (offsettable_p
+	  && !rs6000_legitimate_offset_address_p (mode, addr, strict_p))
+	stack = replace_equiv_address (stack, copy_addr_to_reg (addr));
+
+      else if (reg_reg_p && !legitimate_indexed_address_p (addr, strict_p))
+	stack = replace_equiv_address (stack, copy_addr_to_reg (addr));
+    }
+
+  return stack;
+}
+
+/* Given a memory reference, if it is not a reg or reg+reg addressing, convert
+   to such a form to deal with memory reference instructions like STFIWX that
+   only take reg+reg addressing.  */
+
+rtx
+rs6000_address_for_fpconvert (rtx x)
+{
+  int strict_p = (reload_in_progress || reload_completed);
+  rtx addr;
+
+  gcc_assert (MEM_P (x));
+  addr = XEXP (x, 0);
+  if (! legitimate_indirect_address_p (addr, strict_p)
+      && ! legitimate_indexed_address_p (addr, strict_p))
+    x = replace_equiv_address (x, copy_addr_to_reg (addr));
+
+  return x;
+}
+
+/* Expand 32-bit int -> floating point conversions.  Return true if
+   successful.  */
+
+void
+rs6000_expand_convert_si_to_sfdf (rtx dest, rtx src, bool unsigned_p)
+{
+  enum machine_mode dmode = GET_MODE (dest);
+  rtx (*func_si) (rtx, rtx, rtx, rtx);
+  rtx (*func_si_mem) (rtx, rtx);
+  rtx (*func_di) (rtx, rtx);
+  rtx reg, stack;
+
+  gcc_assert (GET_MODE (src) == SImode);
+
+  if (dmode == SFmode)
+    {
+      if (unsigned_p)
+	{
+	  gcc_assert (TARGET_FCFIDUS && TARGET_LFIWZX);
+	  func_si = gen_floatunssisf2_lfiwzx;
+	  func_si_mem = gen_floatunssisf2_lfiwzx_mem;
+	  func_di = gen_floatunsdisf2;
+	}
+      else
+	{
+	  gcc_assert (TARGET_FCFIDS && TARGET_LFIWAX);
+	  func_si = gen_floatsisf2_lfiwax;
+	  func_si_mem = gen_floatsisf2_lfiwax_mem;
+	  func_di = gen_floatdisf2;
+	}
+    }
+
+  else if (dmode == DFmode)
+    {
+      if (unsigned_p)
+	{
+	  gcc_assert (TARGET_FCFIDU && TARGET_LFIWZX);
+	  func_si = gen_floatunssidf2_lfiwzx;
+	  func_si_mem = gen_floatunssidf2_lfiwzx_mem;
+	  func_di = gen_floatunsdidf2;
+	}
+      else
+	{
+	  gcc_assert (TARGET_FCFID && TARGET_LFIWAX);
+	  func_si = gen_floatsidf2_lfiwax;
+	  func_si_mem = gen_floatsidf2_lfiwax_mem;
+	  func_di = gen_floatdidf2;
+	}
+    }
+
+  else
+    gcc_unreachable ();
+
+  if (MEM_P (src))
+    {
+      src = rs6000_address_for_fpconvert (src);
+      emit_insn (func_si_mem (dest, src));
+    }
+  else if (!TARGET_MFPGPR)
+    {
+      reg = gen_reg_rtx (DImode);
+      stack = rs6000_allocate_stack_temp (SImode, false, true);
+      emit_insn (func_si (dest, src, stack, reg));
+    }
+  else
+    {
+      if (!REG_P (src))
+	src = force_reg (SImode, src);
+      reg = convert_to_mode (DImode, src, unsigned_p);
+      emit_insn (func_di (dest, reg));
+    }
+}
+
 #include "gt-rs6000.h"
Index: gcc/config/rs6000/rs6000.md
===================================================================
--- gcc/config/rs6000/rs6000.md	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 163471)
+++ gcc/config/rs6000/rs6000.md	(working copy)
@@ -105,6 +105,11 @@  (define_constants
    (UNSPEC_BPERM		51)
    (UNSPEC_COPYSIGN		52)
    (UNSPEC_PARITY		53)
+   (UNSPEC_FCTIW		54)
+   (UNSPEC_FCTID		55)
+   (UNSPEC_LFIWAX		56)
+   (UNSPEC_LFIWZX		57)
+   (UNSPEC_FCTIWUZ		58)
   ])
 
 ;;
@@ -252,13 +257,19 @@  (define_mode_attr mptrsize [(SI "si")
 			    (DI "di")])
 
 (define_mode_attr rreg [(SF   "f")
-			(DF   "Ws")
-			(V4SF "Wf")
-			(V2DF "Wd")])
+			(DF   "ws")
+			(V4SF "wf")
+			(V2DF "wd")])
 
 (define_mode_attr rreg2 [(SF   "f")
 			 (DF   "d")])
 
+(define_mode_attr SI_CONVERT_FP [(SF "TARGET_FCFIDS")
+				 (DF "TARGET_FCFID")])
+
+(define_mode_attr E500_CONVERT [(SF "!TARGET_FPRS")
+				(DF "TARGET_E500_DOUBLE")])
+
 (define_mode_attr TARGET_FLOAT [(SF "TARGET_SINGLE_FLOAT")
 				(DF "TARGET_DOUBLE_FLOAT")])
 
@@ -6448,6 +6459,150 @@  (define_expand "fixuns_truncdfdi2"
   "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"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=d")
+	(unspec:DI [(match_operand:SI 1 "indexed_or_indirect_operand" "Z")]
+		   UNSPEC_LFIWAX))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWAX"
+  "lfiwax %0,%y1"
+  [(set_attr "type" "fpload")])
+
+(define_insn_and_split "floatsi<mode>2_lfiwax"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>,<rreg2>")
+	(float:SFDF (match_operand:SI 1 "nonimmediate_operand" "Z,r")))
+   (clobber (match_operand:SI 2 "indexed_or_indirect_operand" "=Z,Z"))
+   (clobber (match_operand:DI 3 "gpc_reg_operand" "=d,d"))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWAX
+   && <SI_CONVERT_FP>"
+  "#"
+  "MEM_P (operands[1]) || reload_completed"
+  [(pc)]
+  "
+{
+  if (MEM_P (operands[1]))
+    {
+      operands[1] = rs6000_address_for_fpconvert (operands[1]);
+      emit_insn (gen_lfiwax (operands[3], operands[1]));
+    }
+  else
+    {
+      emit_move_insn (operands[2], operands[1]);
+      emit_insn (gen_lfiwax (operands[3], operands[2]));
+    }
+  emit_insn (gen_floatdi<mode>2 (operands[0], operands[3]));
+  DONE;
+}"
+  [(set_attr "length" "8,12")])
+
+(define_insn_and_split "floatsi<mode>2_lfiwax_mem"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>")
+	(float:SFDF (match_operand:SI 1 "memory_operand" "Z")))
+   (clobber (match_scratch:DI 2 "=d"))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWAX
+   && <SI_CONVERT_FP>"
+  "#"
+  "&& reload_completed"
+  [(pc)]
+  "
+{
+  emit_insn (gen_lfiwax (operands[2], operands[1]));
+  emit_insn (gen_floatdi<mode>2 (operands[0], operands[2]));
+  DONE;
+}"
+  [(set_attr "length" "8")])
+
+(define_insn_and_split "floatsi<mode>2_lfiwax_mem2"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>")
+	(float:SFDF
+	 (sign_extend:DI
+	  (match_operand:SI 1 "memory_operand" "Z"))))
+   (clobber (match_scratch:DI 2 "=d"))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWAX
+   && <SI_CONVERT_FP>"
+  "#"
+  "&& reload_completed"
+  [(pc)]
+  "
+{
+  emit_insn (gen_lfiwax (operands[2], operands[1]));
+  emit_insn (gen_floatdi<mode>2 (operands[0], operands[2]));
+  DONE;
+}"
+  [(set_attr "length" "8")])
+
+(define_insn "lfiwzx"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=d")
+	(unspec:DI [(match_operand:SI 1 "indexed_or_indirect_operand" "Z")]
+		   UNSPEC_LFIWZX))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWZX"
+  "lfiwzx %0,%y1"
+  [(set_attr "type" "fpload")])
+
+(define_insn_and_split "floatunssi<mode>2_lfiwzx"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>,<rreg2>")
+	(unsigned_float:SFDF (match_operand:SI 1 "gpc_reg_operand" "Z,r")))
+   (clobber (match_operand:SI 2 "indexed_or_indirect_operand" "=Z,Z"))
+   (clobber (match_operand:DI 3 "gpc_reg_operand" "=d,d"))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWZX
+   && <SI_CONVERT_FP>"
+  "#"
+  "MEM_P (operands[1]) || reload_completed"
+  [(pc)]
+  "
+{
+  if (MEM_P (operands[1]))
+    {
+      operands[1] = rs6000_address_for_fpconvert (operands[1]);
+      emit_insn (gen_lfiwzx (operands[3], operands[1]));
+    }
+  else
+    {
+      emit_move_insn (operands[2], operands[1]);
+      emit_insn (gen_lfiwzx (operands[3], operands[2]));
+    }
+  emit_insn (gen_floatdi<mode>2 (operands[0], operands[3]));
+  DONE;
+}"
+  [(set_attr "length" "8,12")])
+
+(define_insn_and_split "floatunssi<mode>2_lfiwzx_mem"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>")
+	(unsigned_float:SFDF (match_operand:SI 1 "memory_operand" "Z")))
+   (clobber (match_scratch:DI 2 "=d"))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWZX
+   && <SI_CONVERT_FP>"
+  "#"
+  "&& reload_completed"
+  [(pc)]
+  "
+{
+  emit_insn (gen_lfiwzx (operands[2], operands[1]));
+  emit_insn (gen_floatdi<mode>2 (operands[0], operands[2]));
+  DONE;
+}"
+  [(set_attr "length" "8")])
+
+(define_insn_and_split "floatunssi<mode>2_lfiwzx_mem2"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>")
+	(unsigned_float:SFDF
+	 (zero_extend:DI
+	  (match_operand:SI 1 "memory_operand" "Z"))))
+   (clobber (match_scratch:DI 2 "=d"))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWZX
+   && <SI_CONVERT_FP>"
+  "#"
+  "&& reload_completed"
+  [(pc)]
+  "
+{
+  emit_insn (gen_lfiwzx (operands[2], operands[1]));
+  emit_insn (gen_floatdi<mode>2 (operands[0], operands[2]));
+  DONE;
+}"
+  [(set_attr "length" "8")])
+
 ; For each of these conversions, there is a define_expand, a define_insn
 ; with a '#' template, and a define_split (with C code).  The idea is
 ; to allow constant folding with the template of the define_insn,
@@ -6455,7 +6610,7 @@  (define_expand "fixuns_truncdfdi2"
 
 (define_expand "floatsidf2"
   [(parallel [(set (match_operand:DF 0 "gpc_reg_operand" "")
-		   (float:DF (match_operand:SI 1 "gpc_reg_operand" "")))
+		   (float:DF (match_operand:SI 1 "nonimmediate_operand" "")))
 	      (use (match_dup 2))
 	      (use (match_dup 3))
 	      (clobber (match_dup 4))
@@ -6467,19 +6622,31 @@  (define_expand "floatsidf2"
 {
   if (TARGET_E500_DOUBLE)
     {
+      if (!REG_P (operands[1]))
+	operands[1] = force_reg (SImode, operands[1]);
       emit_insn (gen_spe_floatsidf2 (operands[0], operands[1]));
       DONE;
     }
-  if (TARGET_POWERPC64)
+  else if (TARGET_LFIWAX && TARGET_FCFID)
+    {
+      rs6000_expand_convert_si_to_sfdf (operands[0], operands[1], false);
+      DONE;
+    }
+  else if (TARGET_FCFID)
     {
-      rtx x = convert_to_mode (DImode, operands[1], 0);
-      emit_insn (gen_floatdidf2 (operands[0], x));
+      rtx dreg = operands[1];
+      if (!REG_P (dreg))
+	dreg = force_reg (SImode, dreg);
+      dreg = convert_to_mode (DImode, dreg, false);
+      emit_insn (gen_floatdidf2 (operands[0], dreg));
       DONE;
     }
 
+  if (!REG_P (operands[1]))
+    operands[1] = force_reg (SImode, operands[1]);
   operands[2] = force_reg (SImode, GEN_INT (0x43300000));
   operands[3] = force_reg (DFmode, CONST_DOUBLE_ATOF (\"4503601774854144\", DFmode));
-  operands[4] = assign_stack_temp (DFmode, GET_MODE_SIZE (DFmode), 0);
+  operands[4] = rs6000_allocate_stack_temp (DFmode, true, false);
   operands[5] = gen_reg_rtx (DFmode);
   operands[6] = gen_reg_rtx (SImode);
 }")
@@ -6492,7 +6659,7 @@  (define_insn_and_split "*floatsidf2_inte
    (clobber (match_operand:DF 4 "offsettable_mem_operand" "=o"))
    (clobber (match_operand:DF 5 "gpc_reg_operand" "=&d"))
    (clobber (match_operand:SI 6 "gpc_reg_operand" "=&r"))]
-  "! TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT"
+  "! TARGET_FCFID && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT"
   "#"
   ""
   [(pc)]
@@ -6518,37 +6685,79 @@  (define_insn_and_split "*floatsidf2_inte
 }"
   [(set_attr "length" "24")])
 
+;; If we don't have a direct conversion to single precision, don't enable this
+;; conversion for 32-bit without fast math, because we don't have the insn to
+;; generate the fixup swizzle to avoid double rounding problems.
 (define_expand "floatunssisf2"
   [(set (match_operand:SF 0 "gpc_reg_operand" "")
-        (unsigned_float:SF (match_operand:SI 1 "gpc_reg_operand" "")))]
-  "TARGET_HARD_FLOAT && !TARGET_FPRS && TARGET_SINGLE_FLOAT"
-  "")
+        (unsigned_float:SF (match_operand:SI 1 "nonimmediate_operand" "")))]
+  "TARGET_HARD_FLOAT && TARGET_SINGLE_FLOAT
+   && (!TARGET_FPRS
+       || (TARGET_FPRS
+	   && ((TARGET_FCFIDUS && TARGET_LFIWZX)
+	       || (TARGET_DOUBLE_FLOAT && TARGET_FCFID
+		   && (TARGET_POWERPC64 || flag_unsafe_math_optimizations)))))"
+  "
+{
+  if (!TARGET_FPRS)
+    {
+      if (!REG_P (operands[1]))
+	operands[1] = force_reg (SImode, operands[1]);
+    }
+  else if (TARGET_LFIWZX && TARGET_FCFIDUS)
+    {
+      rs6000_expand_convert_si_to_sfdf (operands[0], operands[1], true);
+      DONE;
+    }
+  else
+    {
+      rtx dreg = operands[1];
+      if (!REG_P (dreg))
+	dreg = force_reg (SImode, dreg);
+      dreg = convert_to_mode (DImode, dreg, true);
+      emit_insn (gen_floatdisf2 (operands[0], dreg));
+      DONE;
+    }
+}")
 
 (define_expand "floatunssidf2"
   [(parallel [(set (match_operand:DF 0 "gpc_reg_operand" "")
-		   (unsigned_float:DF (match_operand:SI 1 "gpc_reg_operand" "")))
+		   (unsigned_float:DF (match_operand:SI 1 "nonimmediate_operand" "")))
 	      (use (match_dup 2))
 	      (use (match_dup 3))
 	      (clobber (match_dup 4))
 	      (clobber (match_dup 5))])]
-  "TARGET_HARD_FLOAT && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)"
+  "TARGET_HARD_FLOAT
+   && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)"
   "
 {
   if (TARGET_E500_DOUBLE)
     {
+      if (!REG_P (operands[1]))
+	operands[1] = force_reg (SImode, operands[1]);
       emit_insn (gen_spe_floatunssidf2 (operands[0], operands[1]));
       DONE;
     }
-  if (TARGET_POWERPC64)
+  else if (TARGET_LFIWZX && TARGET_FCFID)
+    {
+       rs6000_expand_convert_si_to_sfdf (operands[0], operands[1], true);
+       DONE;
+    }
+  else if (TARGET_FCFID)
     {
-      rtx x = convert_to_mode (DImode, operands[1], 1);
-      emit_insn (gen_floatdidf2 (operands[0], x));
+      rtx dreg = operands[1];
+      if (!REG_P (dreg))
+	dreg = force_reg (SImode, dreg);
+      dreg = convert_to_mode (DImode, dreg, true);
+      emit_insn (gen_floatdidf2 (operands[0], dreg));
       DONE;
     }
 
+  if (!REG_P (operands[1]))
+    operands[1] = force_reg (SImode, operands[1]);
   operands[2] = force_reg (SImode, GEN_INT (0x43300000));
   operands[3] = force_reg (DFmode, CONST_DOUBLE_ATOF (\"4503599627370496\", DFmode));
-  operands[4] = assign_stack_temp (DFmode, GET_MODE_SIZE (DFmode), 0);
+  operands[4] = rs6000_allocate_stack_temp (DFmode, true, false);
   operands[5] = gen_reg_rtx (DFmode);
 }")
 
@@ -6559,7 +6768,8 @@  (define_insn_and_split "*floatunssidf2_i
    (use (match_operand:DF 3 "gpc_reg_operand" "d"))
    (clobber (match_operand:DF 4 "offsettable_mem_operand" "=o"))
    (clobber (match_operand:DF 5 "gpc_reg_operand" "=&d"))]
-  "! TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT"
+  "! TARGET_FCFIDU && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+   && !(TARGET_FCFID && TARGET_POWERPC64)"
   "#"
   ""
   [(pc)]
@@ -6782,76 +6992,154 @@  (define_insn "stfiwx"
   "stfiwx %1,%y0"
   [(set_attr "type" "fpstore")])
 
+;; If we don't have a direct conversion to single precision, don't enable this
+;; conversion for 32-bit without fast math, because we don't have the insn to
+;; generate the fixup swizzle to avoid double rounding problems.
 (define_expand "floatsisf2"
   [(set (match_operand:SF 0 "gpc_reg_operand" "")
-        (float:SF (match_operand:SI 1 "gpc_reg_operand" "")))]
-  "TARGET_HARD_FLOAT && !TARGET_FPRS"
-  "")
+        (float:SF (match_operand:SI 1 "nonimmediate_operand" "")))]
+  "TARGET_HARD_FLOAT && TARGET_SINGLE_FLOAT
+   && (!TARGET_FPRS
+       || (TARGET_FPRS
+	   && ((TARGET_FCFIDS && TARGET_LFIWAX)
+	       || (TARGET_DOUBLE_FLOAT && TARGET_FCFID
+		   && (TARGET_POWERPC64 || flag_unsafe_math_optimizations)))))"
+  "
+{
+  if (!TARGET_FPRS)
+    {
+      if (!REG_P (operands[1]))
+	operands[1] = force_reg (SImode, operands[1]);
+    }
+  else if (TARGET_FCFIDS && TARGET_LFIWAX)
+    {
+      rs6000_expand_convert_si_to_sfdf (operands[0], operands[1], false);
+      DONE;
+    }
+  else
+    {
+      rtx dreg = operands[1];
+      if (!REG_P (dreg))
+	dreg = force_reg (SImode, dreg);
+      dreg = convert_to_mode (DImode, dreg, false);
+      emit_insn (gen_floatdisf2 (operands[0], dreg));
+      DONE;
+    }
+}")
 
 (define_expand "floatdidf2"
   [(set (match_operand:DF 0 "gpc_reg_operand" "")
 	(float:DF (match_operand:DI 1 "gpc_reg_operand" "")))]
-  "(TARGET_POWERPC64 || TARGET_XILINX_FPU || VECTOR_UNIT_VSX_P (DFmode))
-   && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS"
+  "TARGET_FCFID && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS"
   "")
 
 (define_insn "*floatdidf2_fpr"
   [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
-	(float:DF (match_operand:DI 1 "gpc_reg_operand" "!d#r")))]
-  "(TARGET_POWERPC64 || TARGET_XILINX_FPU)
-   && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS
+	(float:DF (match_operand:DI 1 "gpc_reg_operand" "d")))]
+  "TARGET_FCFID && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS
    && !VECTOR_UNIT_VSX_P (DFmode)"
   "fcfid %0,%1"
   [(set_attr "type" "fp")])
 
+; Allow the combiner to merge source memory operands to the conversion so that
+; the optimizer/register allocator doesn't try to load the value too early in a
+; GPR and then use store/load to move it to a FPR and suffer from a store-load
+; hit.  We will split after reload to avoid the trip through the GPRs
+
+(define_insn_and_split "*floatdidf2_mem"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+	(float:DF (match_operand:DI 1 "memory_operand" "m")))
+   (clobber (match_scratch:DI 2 "=d"))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS && TARGET_FCFID"
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 2) (match_dup 1))
+   (set (match_dup 0) (float:DF (match_dup 2)))]
+  ""
+  [(set_attr "length" "8")])
+
 (define_expand "floatunsdidf2"
   [(set (match_operand:DF 0 "gpc_reg_operand" "")
-	(unsigned_float:DF (match_operand:DI 1 "gpc_reg_operand" "")))]
-  "TARGET_VSX"
+	(unsigned_float:DF
+	 (match_operand:DI 1 "gpc_reg_operand" "")))]
+  "TARGET_FCFIDU || VECTOR_UNIT_VSX_P (DFmode)"
   "")
 
-(define_expand "fix_truncdfdi2"
-  [(set (match_operand:DI 0 "gpc_reg_operand" "")
-	(fix:DI (match_operand:DF 1 "gpc_reg_operand" "")))]
-  "(TARGET_POWERPC64 || TARGET_XILINX_FPU || VECTOR_UNIT_VSX_P (DFmode))
-    && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS"
-  "")
+(define_insn "*floatunsdidf2_fcfidu"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+	(unsigned_float:DF (match_operand:DI 1 "gpc_reg_operand" "d")))]
+  "TARGET_FCFIDU && !VECTOR_UNIT_VSX_P (DFmode)"
+  "fcfidu %0,%1"
+  [(set_attr "type" "fp")
+   (set_attr "length" "4")])
 
-(define_insn "*fix_truncdfdi2_fpr"
-  [(set (match_operand:DI 0 "gpc_reg_operand" "=!d#r")
-	(fix:DI (match_operand:DF 1 "gpc_reg_operand" "d")))]
-  "(TARGET_POWERPC64 || TARGET_XILINX_FPU)
-    && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS
-    && !VECTOR_UNIT_VSX_P (DFmode)"
-  "fctidz %0,%1"
-  [(set_attr "type" "fp")])
+(define_insn_and_split "*floatunsdidf2_mem"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+	(unsigned_float:DF (match_operand:DI 1 "memory_operand" "m")))
+   (clobber (match_scratch:DI 2 "=d"))]
+  "TARGET_FCFIDU || VECTOR_UNIT_VSX_P (DFmode)"
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 2) (match_dup 1))
+   (set (match_dup 0) (unsigned_float:DF (match_dup 2)))]
+  ""
+  [(set_attr "length" "8")])
 
 (define_expand "floatdisf2"
   [(set (match_operand:SF 0 "gpc_reg_operand" "")
         (float:SF (match_operand:DI 1 "gpc_reg_operand" "")))]
-  "TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT "
+  "TARGET_FCFID && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT
+   && (TARGET_FCFIDS || TARGET_POWERPC64 || flag_unsafe_math_optimizations)"
   "
 {
-  rtx val = operands[1];
-  if (!flag_unsafe_math_optimizations)
+  if (!TARGET_FCFIDS)
     {
-      rtx label = gen_label_rtx ();
-      val = gen_reg_rtx (DImode);
-      emit_insn (gen_floatdisf2_internal2 (val, operands[1], label));
-      emit_label (label);
+      rtx val = operands[1];
+      if (!flag_unsafe_math_optimizations)
+	{
+	  rtx label = gen_label_rtx ();
+	  val = gen_reg_rtx (DImode);
+	  emit_insn (gen_floatdisf2_internal2 (val, operands[1], label));
+	  emit_label (label);
+	}
+      emit_insn (gen_floatdisf2_internal1 (operands[0], val));
+      DONE;
     }
-  emit_insn (gen_floatdisf2_internal1 (operands[0], val));
-  DONE;
 }")
 
+(define_insn "floatdisf2_fcfids"
+  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+	(float:SF (match_operand:DI 1 "gpc_reg_operand" "d")))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT
+   && TARGET_DOUBLE_FLOAT && TARGET_FCFIDS"
+  "fcfids %0,%1"
+  [(set_attr "type" "fp")])
+
+(define_insn_and_split "*floatdisf2_mem"
+  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+	(float:SF (match_operand:DI 1 "memory_operand" "m")))
+   (clobber (match_scratch:DI 2 "=f"))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT
+   && TARGET_DOUBLE_FLOAT && TARGET_FCFIDS"
+  "#"
+  "&& reload_completed"
+  [(pc)]
+  "
+{
+  emit_move_insn (operands[2], operands[1]);
+  emit_insn (gen_floatdisf2_fcfids (operands[0], operands[2]));
+  DONE;
+}"
+  [(set_attr "length" "8")])
+
 ;; This is not IEEE compliant if rounding mode is "round to nearest".
 ;; If the DI->DF conversion is inexact, then it's possible to suffer
 ;; from double rounding.
 (define_insn_and_split "floatdisf2_internal1"
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-        (float:SF (match_operand:DI 1 "gpc_reg_operand" "!d#r")))
+        (float:SF (match_operand:DI 1 "gpc_reg_operand" "d")))
    (clobber (match_scratch:DF 2 "=d"))]
-  "TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT"
+  "TARGET_FCFID && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT"
   "#"
   "&& reload_completed"
   [(set (match_dup 2)
@@ -6891,6 +7179,38 @@  (define_expand "floatdisf2_internal2"
   operands[3] = gen_reg_rtx (DImode);
   operands[4] = gen_reg_rtx (CCUNSmode);
 }")
+
+(define_expand "floatunsdisf2"
+  [(set (match_operand:SF 0 "gpc_reg_operand" "")
+        (unsigned_float:SF (match_operand:DI 1 "gpc_reg_operand" "")))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT
+   && TARGET_DOUBLE_FLOAT && TARGET_FCFIDUS"
+  "")
+
+(define_insn "floatunsdisf2_fcfidus"
+  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+        (unsigned_float:SF (match_operand:DI 1 "gpc_reg_operand" "d")))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT
+   && TARGET_DOUBLE_FLOAT && TARGET_FCFIDUS"
+  "fcfidus %0,%1"
+  [(set_attr "type" "fp")])
+
+(define_insn_and_split "*floatunsdisf2_mem"
+  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+	(unsigned_float:SF (match_operand:DI 1 "memory_operand" "m")))
+   (clobber (match_scratch:DI 2 "=f"))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT
+   && TARGET_DOUBLE_FLOAT && TARGET_FCFIDUS"
+  "#"
+  "&& reload_completed"
+  [(pc)]
+  "
+{
+  emit_move_insn (operands[2], operands[1]);
+  emit_insn (gen_floatunsdisf2_fcfidus (operands[0], operands[2]));
+  DONE;
+}"
+  [(set_attr "length" "8")])
 
 ;; Define the DImode operations that can be done in a small number
 ;; of instructions.  The & constraints are to prevent the register
Index: gcc/config/rs6000/rs6000.h
===================================================================
--- gcc/config/rs6000/rs6000.h	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 163471)
+++ gcc/config/rs6000/rs6000.h	(working copy)
@@ -1,6 +1,7 @@ 
 /* Definitions of target machine for GNU compiler, for IBM RS/6000.
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+   2010
    Free Software Foundation, Inc.
    Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
 
@@ -554,6 +555,25 @@  extern int rs6000_vector_align[];
 #define TARGET_E500_DOUBLE 0
 #define CHECK_E500_OPTIONS do { } while (0)
 
+/* ISA 2.01 allowed FCFID to be done in 32-bit, previously it was 64-bit only.
+   Enable 32-bit fcfid's on any of the switches for newer ISA machines or
+   XILINX.  */
+#define TARGET_FCFID	(TARGET_POWERPC64 \
+			 || TARGET_POPCNTB	/* ISA 2.02 */ \
+			 || TARGET_CMPB		/* ISA 2.05 */ \
+			 || TARGET_POPCNTD	/* ISA 2.06 */ \
+			 || TARGET_XILINX_FPU)
+
+#define TARGET_FCTIDZ	TARGET_FCFID
+#define TARGET_STFIWX	TARGET_PPC_GFXOPT
+#define TARGET_LFIWAX	TARGET_CMPB
+#define TARGET_LFIWZX	TARGET_POPCNTD
+#define TARGET_FCFIDS	TARGET_POPCNTD
+#define TARGET_FCFIDU	TARGET_POPCNTD
+#define TARGET_FCFIDUS	TARGET_POPCNTD
+#define TARGET_FCTIDUZ	TARGET_POPCNTD
+#define TARGET_FCTIWUZ	TARGET_POPCNTD
+
 /* E500 processors only support plain "sync", not lwsync.  */
 #define TARGET_NO_LWSYNC TARGET_E500
 
Index: gcc/testsuite/gcc.target/powerpc/ppc-fpconv-1.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/ppc-fpconv-1.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk/gcc/testsuite/gcc.target/powerpc)	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/ppc-fpconv-1.c	(.../gcc/testsuite/gcc.target/powerpc)	(revision 163489)
@@ -0,0 +1,50 @@ 
+/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
+/* { dg-require-effective-target powerpc_vsx_ok } */
+/* { dg-options "-O2 -mcpu=power7 -ffast-math" } */
+/* { dg-final { scan-assembler-times "lfiwax" 2 } } */
+/* { dg-final { scan-assembler-times "lfiwzx" 2 } } */
+/* { dg-final { scan-assembler-times "fcfids" 3 } } */
+/* { dg-final { scan-assembler-times "fcfidus" 1 } } */
+/* { dg-final { scan-assembler-times "xscvsxddp" 3 } } */
+/* { dg-final { scan-assembler-times "xscvuxddp" 1 } } */
+
+void int_to_float (float *dest, int *src)
+{
+  *dest = (float) *src;
+}
+
+void int_to_double (double *dest, int *src)
+{
+  *dest = (double) *src;
+}
+
+void uint_to_float (float *dest, unsigned int *src)
+{
+  *dest = (float) *src;
+}
+
+void uint_to_double (double *dest, unsigned int *src)
+{
+  *dest = (double) *src;
+}
+
+void llong_to_float (float *dest, long long *src)
+{
+  *dest = (float) *src;
+}
+
+void llong_to_double (double *dest, long long *src)
+{
+  *dest = (double) *src;
+}
+
+void ullong_to_float (float *dest, unsigned long long *src)
+{
+  *dest = (float) *src;
+}
+
+void ullong_to_double (double *dest, unsigned long long *src)
+{
+  *dest = (double) *src;
+}
Index: gcc/testsuite/gcc.target/powerpc/ppc-fpconv-2.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/ppc-fpconv-2.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk/gcc/testsuite/gcc.target/powerpc)	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/ppc-fpconv-2.c	(.../gcc/testsuite/gcc.target/powerpc)	(revision 163489)
@@ -0,0 +1,51 @@ 
+/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
+/* { dg-require-effective-target powerpc_vsx_ok } */
+/* { dg-options "-O2 -mcpu=power6 -ffast-math" } */
+/* { dg-final { scan-assembler-times "lfiwax" 1 } } */
+/* { dg-final { scan-assembler-not "lfiwzx" } } */
+/* { dg-final { scan-assembler-times "fcfid " 10 } } */
+/* { dg-final { scan-assembler-not "fcfids" } } */
+/* { dg-final { scan-assembler-not "fcfidus" } } */
+/* { dg-final { scan-assembler-not "xscvsxddp" } } */
+/* { dg-final { scan-assembler-not "xscvuxddp" } } */
+
+void int_to_float (float *dest, int *src)
+{
+  *dest = (float) *src;
+}
+
+void int_to_double (double *dest, int *src)
+{
+  *dest = (double) *src;
+}
+
+void uint_to_float (float *dest, unsigned int *src)
+{
+  *dest = (float) *src;
+}
+
+void uint_to_double (double *dest, unsigned int *src)
+{
+  *dest = (double) *src;
+}
+
+void llong_to_float (float *dest, long long *src)
+{
+  *dest = (float) *src;
+}
+
+void llong_to_double (double *dest, long long *src)
+{
+  *dest = (double) *src;
+}
+
+void ullong_to_float (float *dest, unsigned long long *src)
+{
+  *dest = (float) *src;
+}
+
+void ullong_to_double (double *dest, unsigned long long *src)
+{
+  *dest = (double) *src;
+}
Index: gcc/testsuite/gcc.target/powerpc/ppc-fpconv-3.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/ppc-fpconv-3.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk/gcc/testsuite/gcc.target/powerpc)	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/ppc-fpconv-3.c	(.../gcc/testsuite/gcc.target/powerpc)	(revision 163489)
@@ -0,0 +1,51 @@ 
+/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
+/* { dg-require-effective-target ilp32 } */
+/* { dg-options "-O2 -mcpu=power5 -ffast-math" } */
+/* { dg-final { scan-assembler-not "lfiwax" } } */
+/* { dg-final { scan-assembler-not "lfiwzx" } } */
+/* { dg-final { scan-assembler-times "fcfid " 10 } } */
+/* { dg-final { scan-assembler-not "fcfids" } } */
+/* { dg-final { scan-assembler-not "fcfidus" } } */
+/* { dg-final { scan-assembler-not "xscvsxddp" } } */
+/* { dg-final { scan-assembler-not "xscvuxddp" } } */
+
+void int_to_float (float *dest, int *src)
+{
+  *dest = (float) *src;
+}
+
+void int_to_double (double *dest, int *src)
+{
+  *dest = (double) *src;
+}
+
+void uint_to_float (float *dest, unsigned int *src)
+{
+  *dest = (float) *src;
+}
+
+void uint_to_double (double *dest, unsigned int *src)
+{
+  *dest = (double) *src;
+}
+
+void llong_to_float (float *dest, long long *src)
+{
+  *dest = (float) *src;
+}
+
+void llong_to_double (double *dest, long long *src)
+{
+  *dest = (double) *src;
+}
+
+void ullong_to_float (float *dest, unsigned long long *src)
+{
+  *dest = (float) *src;
+}
+
+void ullong_to_double (double *dest, unsigned long long *src)
+{
+  *dest = (double) *src;
+}
Index: gcc/testsuite/gcc.target/powerpc/ppc-fpconv-4.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/ppc-fpconv-4.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk/gcc/testsuite/gcc.target/powerpc)	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/ppc-fpconv-4.c	(.../gcc/testsuite/gcc.target/powerpc)	(revision 163489)
@@ -0,0 +1,51 @@ 
+/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
+/* { dg-require-effective-target ilp32 } */
+/* { dg-options "-O2 -mcpu=750 -ffast-math" } */
+/* { dg-final { scan-assembler-not "lfiwax" } } */
+/* { dg-final { scan-assembler-not "lfiwzx" } } */
+/* { dg-final { scan-assembler-not "fcfid " } } */
+/* { dg-final { scan-assembler-not "fcfids" } } */
+/* { dg-final { scan-assembler-not "fcfidus" } } */
+/* { dg-final { scan-assembler-not "xscvsxddp" } } */
+/* { dg-final { scan-assembler-not "xscvuxddp" } } */
+
+void int_to_float (float *dest, int *src)
+{
+  *dest = (float) *src;
+}
+
+void int_to_double (double *dest, int *src)
+{
+  *dest = (double) *src;
+}
+
+void uint_to_float (float *dest, unsigned int *src)
+{
+  *dest = (float) *src;
+}
+
+void uint_to_double (double *dest, unsigned int *src)
+{
+  *dest = (double) *src;
+}
+
+void llong_to_float (float *dest, long long *src)
+{
+  *dest = (float) *src;
+}
+
+void llong_to_double (double *dest, long long *src)
+{
+  *dest = (double) *src;
+}
+
+void ullong_to_float (float *dest, unsigned long long *src)
+{
+  *dest = (float) *src;
+}
+
+void ullong_to_double (double *dest, unsigned long long *src)
+{
+  *dest = (double) *src;
+}