Improve floating point conversions on powerpc
authorMichael Meissner <meissner@linux.vnet.ibm.com>
Fri, 27 Aug 2010 21:32:44 +0000 (21:32 +0000)
committerMichael Meissner <meissner@gcc.gnu.org>
Fri, 27 Aug 2010 21:32:44 +0000 (21:32 +0000)
From-SVN: r163598

16 files changed:
gcc/ChangeLog
gcc/config/rs6000/rs6000-protos.h
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.h
gcc/config/rs6000/rs6000.md
gcc/config/rs6000/vsx.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/powerpc/ppc-fpconv-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/powerpc/ppc-fpconv-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/powerpc/ppc-fpconv-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/powerpc/ppc-fpconv-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/powerpc/ppc-fpconv-5.c [new file with mode: 0644]
gcc/testsuite/gcc.target/powerpc/ppc-fpconv-6.c [new file with mode: 0644]
gcc/testsuite/gcc.target/powerpc/ppc-fpconv-7.c [new file with mode: 0644]
gcc/testsuite/gcc.target/powerpc/ppc-fpconv-8.c [new file with mode: 0644]
gcc/testsuite/gcc.target/powerpc/ppc-fpconv-9.c [new file with mode: 0644]

index 3206c38..b241022 100644 (file)
@@ -1,3 +1,123 @@
+2010-08-23  Michael Meissner  <meissner@linux.vnet.ibm.com>
+
+       * config/rs6000/rs6000-protos.h (rs6000_address_for_fpconvert):
+       New declaration.
+       (rs6000_allocate_stack_temp): Ditto.
+       (rs6000_expand_convert_si_to_sfdf): Ditto.
+
+       * config/rs6000/rs6000.c (rs6000_override_options): Adjust long
+       line.  Update the options set if power6 or power7 server/embedded
+       type options are used.  If we give a warning for no vsx under
+       -mcpu=power7 -mno-altivec, mark -mvsx as an explicit option.
+       (rs6000_allocate_stack_temp): New function to allocate a stack
+       tempoary and adjust the address so it meets either REG+OFFSET or
+       REG+REG addressing requirements.
+       (rs6000_address_for_fpconvert): Adjust REG+OFFSET addresses so
+       that they can be used with the LFIWAX/LFIWZX instrucitons.
+       (rs6000_expand_convert_si_to_sfdf): New helper funciton for
+       converting signed/unsigned SImode to either SFmode/DFmode.
+
+       * config/rs6000/rs6000.h (TARGET_FCFID): New macros to determine
+       whether certain instructions can be generated.
+       (TARGET_FCTIDZ): Ditto.
+       (TARGET_STFIWX): Ditto.
+       (TARGET_LFIWAX): Ditto.
+       (TARGET_LFIWZX): Ditto.
+       (TARGET_FCFIDS): Ditto.
+       (TARGET_FCFIDU): Ditto.
+       (TARGET_FCFIDUS): Ditto.
+       (TARGET_FCTIDUZ): Ditto.
+       (TARGET_FCTIWUZ): Ditto.
+
+       * config/rs6000/rs6000.md (UNSPEC_FCTIW): New unspec constants.
+       (UNSPEC_FCTID): Ditto.
+       (UNSPEC_LFIWAX): Ditto.
+       (UNSPEC_LFIWZX): Ditto.
+       (UNSPEC_FCTIWUZ): Ditto.
+       (rreg): Use correct constraints.
+       (SI_CONVERT_FP): New mode attribute for floating point conversion
+       tests.
+       (E500_CONVERT): Ditto.
+       (lfiwax): New insns for converting from integer to floating point
+       utilizing newer instructions.  Attempt to optimize conversions
+       that come from memory so that we don't load the value into a GPR,
+       spill it to the stack and reload it into a FPR.
+       (floatsi<mode>2_lfiwax): Ditto.
+       (floatsi<mode>2_lfiwax_mem): Ditto.
+       (floatsi<mode>2_lfiwax_mem2): Ditto.
+       (lfiwzx): Ditto.
+       (floatunssi<mode>2_lfiwzx): Ditto.
+       (floatunssi<mode>2_lfiwzx_mem): Ditto.
+       (floatunssi<mode>2_lfiwzx_mem2): Ditto.
+       (floatdidf2_mem): Ditto.
+       (floatunsdidf2_fcfidu): Ditto.
+       (floatunsdidf2_mem): Ditto.
+       (floatunsdisf2): Ditto.
+       (floatunsdisf2_fcfidus): Ditto.
+       (floatunsdisf2_mem): Ditto.
+       (floatsidf2): Add support for LFIWAX/LFIWZX/FCFIDS/FCFIDU/FCFIDUS.
+       Use FCFID on 32-bit hosts that support it.
+       (floatsidf2_internal): Ditto.
+       (floatunssisf2): Ditto.
+       (floatunssidf2): Ditto.
+       (floatunssidf2_internal): Ditto.
+       (floatsisf2): Ditto.
+       (floatdidf2): Ditto.
+       (floatdidf2_fpr): Ditto.
+       (floatunsdidf2): Ditto.
+       (floatdisf2): Ditto.
+       (floatdisf2_fcfids): Ditto.
+       (floatdisf2_internal1): Ditto.
+       (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.
 
 2010-08-27  Basile Starynkevitch  <basile@starynkevitch.net>
             Jeremie Salvucci  <jeremie.salvucci@free.fr>
index 79370d8..0d26511 100644 (file)
@@ -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 c5ed8d6..6bebca9 100644 (file)
@@ -2510,10 +2510,10 @@ rs6000_override_options (const char *default_cpu)
          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},
@@ -2550,15 +2550,19 @@ rs6000_override_options (const char *default_cpu)
     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
@@ -2699,15 +2703,22 @@ rs6000_override_options (const char *default_cpu)
        {
          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);
 
@@ -26959,4 +26970,122 @@ rs6000_final_prescan_insn (rtx insn, rtx *operand ATTRIBUTE_UNUSED,
     }
 }
 
+\f
+/* 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 5058fb5..3ce011f 100644 (file)
@@ -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 c5e0ba1..5c68c3f 100644 (file)
    (UNSPEC_BPERM               51)
    (UNSPEC_COPYSIGN            52)
    (UNSPEC_PARITY              53)
+   (UNSPEC_FCTIW               54)
+   (UNSPEC_FCTID               55)
+   (UNSPEC_LFIWAX              56)
+   (UNSPEC_LFIWZX              57)
+   (UNSPEC_FCTIWUZ             58)
   ])
 
 ;;
                            (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")])
 \f
 \f
 ;; 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"
-  "")
+; 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_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_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_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_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_expand "fixuns_truncdfdi2"
-  [(set (match_operand:DI 0 "register_operand" "")
-       (unsigned_fix:DI (match_operand:DF 1 "register_operand" "")))]
-  "TARGET_HARD_FLOAT && TARGET_VSX"
-  "")
+(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
 
 (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))
 {
   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);
 }")
    (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)]
 }"
   [(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)
     {
-      rtx x = convert_to_mode (DImode, operands[1], 1);
-      emit_insn (gen_floatdidf2 (operands[0], x));
+       rs6000_expand_convert_si_to_sfdf (operands[0], operands[1], true);
+       DONE;
+    }
+  else if (TARGET_FCFID)
+    {
+      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);
 }")
 
    (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)]
 }"
   [(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;
+      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;
     }
-  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])))
+}")
+
+(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])))
     {
-      operands[3] = gen_reg_rtx (DImode);
-      emit_insn (gen_fix_truncdfsi2_mfpgpr (operands[0], operands[1],
-                                           operands[2], operands[3]));
-      DONE;
+      rtx reg = gen_lowpart (DImode, operands[0]);
+      emit_move_insn (reg, operands[2]);
     }
-  if (TARGET_PPC_GFXOPT)
+  else
     {
-      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;
+      emit_insn (gen_stfiwx (operands[3], operands[2]));
+      emit_move_insn (operands[0], operands[3]);
     }
-  operands[3] = assign_stack_temp (DImode, GET_MODE_SIZE (DImode), 0);
-}")
+  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 
   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")
   "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)
   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")])
 \f
 ;; Define the DImode operations that can be done in a small number
 ;; of instructions.  The & constraints are to prevent the register
   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 add969c..c6a126b 100644 (file)
@@ -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>
 
 ;; 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 8fc8458..959f3fd 100644 (file)
@@ -1,3 +1,17 @@
+2010-08-23  Michael Meissner  <meissner@linux.vnet.ibm.com>
+
+       * gcc.target/powerpc/ppc-fpconv-1.c: New test for integer to
+       floating point conversion code generation.
+       * gcc.target/powerpc/ppc-fpconv-2.c: Ditto.
+       * gcc.target/powerpc/ppc-fpconv-3.c: Ditto.
+       * gcc.target/powerpc/ppc-fpconv-4.c: Ditto.
+       * 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.
+
 2010-08-27  Francois-Xavier Coudert  <fxcoudert@gcc.gnu.org>
 
        PR fortran/32049
diff --git a/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-1.c b/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-1.c
new file mode 100644 (file)
index 0000000..8a6cc08
--- /dev/null
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-2.c b/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-2.c
new file mode 100644 (file)
index 0000000..f90a35b
--- /dev/null
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-3.c b/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-3.c
new file mode 100644 (file)
index 0000000..6196162
--- /dev/null
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-4.c b/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-4.c
new file mode 100644 (file)
index 0000000..c4b9ea6
--- /dev/null
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-5.c b/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-5.c
new file mode 100644 (file)
index 0000000..a071fc1
--- /dev/null
@@ -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; }
diff --git a/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-6.c b/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-6.c
new file mode 100644 (file)
index 0000000..09ee188
--- /dev/null
@@ -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; }
diff --git a/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-7.c b/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-7.c
new file mode 100644 (file)
index 0000000..007c864
--- /dev/null
@@ -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; }
diff --git a/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-8.c b/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-8.c
new file mode 100644 (file)
index 0000000..b5410f6
--- /dev/null
@@ -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; }
diff --git a/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-9.c b/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-9.c
new file mode 100644 (file)
index 0000000..836c030
--- /dev/null
@@ -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; }