aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMichael Meissner <meissner@linux.vnet.ibm.com>2010-08-27 21:32:44 +0000
committerMichael Meissner <meissner@gcc.gnu.org>2010-08-27 21:32:44 +0000
commit7042fe5ef83ff0585eb91144817105f26d566d4c (patch)
treec876d4485888c8a83ac11e08799a3252229a51c3 /gcc
parenta3c85b749940a80efed069253b08c0673c817278 (diff)
downloadgcc-7042fe5ef83ff0585eb91144817105f26d566d4c.zip
gcc-7042fe5ef83ff0585eb91144817105f26d566d4c.tar.gz
gcc-7042fe5ef83ff0585eb91144817105f26d566d4c.tar.bz2
Improve floating point conversions on powerpc
From-SVN: r163598
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog120
-rw-r--r--gcc/config/rs6000/rs6000-protos.h3
-rw-r--r--gcc/config/rs6000/rs6000.c149
-rw-r--r--gcc/config/rs6000/rs6000.h22
-rw-r--r--gcc/config/rs6000/rs6000.md776
-rw-r--r--gcc/config/rs6000/vsx.md6
-rw-r--r--gcc/testsuite/ChangeLog14
-rw-r--r--gcc/testsuite/gcc.target/powerpc/ppc-fpconv-1.c50
-rw-r--r--gcc/testsuite/gcc.target/powerpc/ppc-fpconv-2.c51
-rw-r--r--gcc/testsuite/gcc.target/powerpc/ppc-fpconv-3.c51
-rw-r--r--gcc/testsuite/gcc.target/powerpc/ppc-fpconv-4.c51
-rw-r--r--gcc/testsuite/gcc.target/powerpc/ppc-fpconv-5.c22
-rw-r--r--gcc/testsuite/gcc.target/powerpc/ppc-fpconv-6.c22
-rw-r--r--gcc/testsuite/gcc.target/powerpc/ppc-fpconv-7.c22
-rw-r--r--gcc/testsuite/gcc.target/powerpc/ppc-fpconv-8.c22
-rw-r--r--gcc/testsuite/gcc.target/powerpc/ppc-fpconv-9.c11
16 files changed, 1183 insertions, 209 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 3206c38..b241022 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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>
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index 79370d8..0d26511 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -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
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index c5ed8d6..6bebca9 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -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,
}
}
+
+/* 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"
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index 5058fb5..3ce011f 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -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
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index c5e0ba1..5c68c3f 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -105,6 +105,11 @@
(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 @@
(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")])
@@ -6424,29 +6435,149 @@
;; 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
@@ -6455,7 +6586,7 @@
(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 +6598,31 @@
{
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 +6635,7 @@
(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 +6661,79 @@
}"
[(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);
}")
@@ -6559,7 +6744,8 @@
(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)]
@@ -6583,46 +6769,85 @@
}"
[(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
@@ -6636,143 +6861,194 @@
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")
@@ -6782,76 +7058,154 @@
"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 +7245,38 @@
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
@@ -9540,7 +9926,7 @@
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;
diff --git a/gcc/config/rs6000/vsx.md b/gcc/config/rs6000/vsx.md
index add969c..c6a126bb 100644
--- a/gcc/config/rs6000/vsx.md
+++ b/gcc/config/rs6000/vsx.md
@@ -1,5 +1,5 @@
;; VSX patterns.
-;; Copyright (C) 2009
+;; Copyright (C) 2009, 2010
;; Free Software Foundation, Inc.
;; Contributed by Michael Meissner <meissner@linux.vnet.ibm.com>
@@ -73,11 +73,11 @@
;; 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")
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 8fc8458..959f3fd 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..8a6cc08
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-1.c
@@ -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
index 0000000..f90a35b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-2.c
@@ -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
index 0000000..6196162
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-3.c
@@ -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
index 0000000..c4b9ea6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-4.c
@@ -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
index 0000000..a071fc1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-5.c
@@ -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
index 0000000..09ee188
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-6.c
@@ -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
index 0000000..007c864
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-7.c
@@ -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
index 0000000..b5410f6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-8.c
@@ -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
index 0000000..836c030
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/ppc-fpconv-9.c
@@ -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; }