diff options
author | Michael Meissner <meissner@linux.vnet.ibm.com> | 2010-08-27 21:32:44 +0000 |
---|---|---|
committer | Michael Meissner <meissner@gcc.gnu.org> | 2010-08-27 21:32:44 +0000 |
commit | 7042fe5ef83ff0585eb91144817105f26d566d4c (patch) | |
tree | c876d4485888c8a83ac11e08799a3252229a51c3 | |
parent | a3c85b749940a80efed069253b08c0673c817278 (diff) | |
download | gcc-7042fe5ef83ff0585eb91144817105f26d566d4c.zip gcc-7042fe5ef83ff0585eb91144817105f26d566d4c.tar.gz gcc-7042fe5ef83ff0585eb91144817105f26d566d4c.tar.bz2 |
Improve floating point conversions on powerpc
From-SVN: r163598
-rw-r--r-- | gcc/ChangeLog | 120 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000-protos.h | 3 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 149 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.h | 22 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.md | 776 | ||||
-rw-r--r-- | gcc/config/rs6000/vsx.md | 6 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 14 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/powerpc/ppc-fpconv-1.c | 50 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/powerpc/ppc-fpconv-2.c | 51 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/powerpc/ppc-fpconv-3.c | 51 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/powerpc/ppc-fpconv-4.c | 51 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/powerpc/ppc-fpconv-5.c | 22 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/powerpc/ppc-fpconv-6.c | 22 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/powerpc/ppc-fpconv-7.c | 22 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/powerpc/ppc-fpconv-8.c | 22 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/powerpc/ppc-fpconv-9.c | 11 |
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; } |