X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fconfig%2Frs6000%2Frs6000.md;h=89836d7d63213990a49562cff5066996a2d6d193;hb=024261446b840a6da5526ba42b83a56818ff32ce;hp=0ef7e98d9e5325c73a305b50d9c4746e078d57ba;hpb=e5ec04203e0108c234b385e7f24233f5fd2a8b01;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 0ef7e98d9e5..89836d7d632 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -1,6 +1,6 @@ ;; Machine description for IBM RISC System 6000 (POWER) for GNU C compiler ;; Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, -;; 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 +;; 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 ;; Free Software Foundation, Inc. ;; Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu) @@ -53,70 +53,77 @@ ;; UNSPEC usage ;; -(define_constants - [(UNSPEC_FRSP 0) ; frsp for POWER machines - (UNSPEC_PROBE_STACK 4) ; probe stack memory reference - (UNSPEC_TIE 5) ; tie stack contents and stack pointer - (UNSPEC_TOCPTR 6) ; address of a word pointing to the TOC - (UNSPEC_TOC 7) ; address of the TOC (more-or-less) - (UNSPEC_MOVSI_GOT 8) - (UNSPEC_MV_CR_OV 9) ; move_from_CR_ov_bit - (UNSPEC_FCTIWZ 10) - (UNSPEC_FRIM 11) - (UNSPEC_FRIN 12) - (UNSPEC_FRIP 13) - (UNSPEC_FRIZ 14) - (UNSPEC_LD_MPIC 15) ; load_macho_picbase - (UNSPEC_MPIC_CORRECT 16) ; macho_correct_pic - (UNSPEC_TLSGD 17) - (UNSPEC_TLSLD 18) - (UNSPEC_MOVESI_FROM_CR 19) - (UNSPEC_MOVESI_TO_CR 20) - (UNSPEC_TLSDTPREL 21) - (UNSPEC_TLSDTPRELHA 22) - (UNSPEC_TLSDTPRELLO 23) - (UNSPEC_TLSGOTDTPREL 24) - (UNSPEC_TLSTPREL 25) - (UNSPEC_TLSTPRELHA 26) - (UNSPEC_TLSTPRELLO 27) - (UNSPEC_TLSGOTTPREL 28) - (UNSPEC_TLSTLS 29) - (UNSPEC_FIX_TRUNC_TF 30) ; fadd, rounding towards zero - (UNSPEC_MV_CR_GT 31) ; move_from_CR_gt_bit - (UNSPEC_STFIWX 32) - (UNSPEC_POPCNTB 33) - (UNSPEC_FRES 34) - (UNSPEC_SP_SET 35) - (UNSPEC_SP_TEST 36) - (UNSPEC_SYNC 37) - (UNSPEC_LWSYNC 38) - (UNSPEC_ISYNC 39) - (UNSPEC_SYNC_OP 40) - (UNSPEC_ATOMIC 41) - (UNSPEC_CMPXCHG 42) - (UNSPEC_XCHG 43) - (UNSPEC_AND 44) - (UNSPEC_DLMZB 45) - (UNSPEC_DLMZB_CR 46) - (UNSPEC_DLMZB_STRLEN 47) - (UNSPEC_RSQRT 48) - (UNSPEC_TOCREL 49) - (UNSPEC_MACHOPIC_OFFSET 50) - (UNSPEC_BPERM 51) - (UNSPEC_COPYSIGN 52) - (UNSPEC_PARITY 53) +(define_c_enum "unspec" + [UNSPEC_FRSP ; frsp for POWER machines + UNSPEC_PROBE_STACK ; probe stack memory reference + UNSPEC_TIE ; tie stack contents and stack pointer + UNSPEC_TOCPTR ; address of a word pointing to the TOC + UNSPEC_TOC ; address of the TOC (more-or-less) + UNSPEC_MOVSI_GOT + UNSPEC_MV_CR_OV ; move_from_CR_ov_bit + UNSPEC_FCTIWZ + UNSPEC_FRIM + UNSPEC_FRIN + UNSPEC_FRIP + UNSPEC_FRIZ + UNSPEC_LD_MPIC ; load_macho_picbase + UNSPEC_MPIC_CORRECT ; macho_correct_pic + UNSPEC_TLSGD + UNSPEC_TLSLD + UNSPEC_MOVESI_FROM_CR + UNSPEC_MOVESI_TO_CR + UNSPEC_TLSDTPREL + UNSPEC_TLSDTPRELHA + UNSPEC_TLSDTPRELLO + UNSPEC_TLSGOTDTPREL + UNSPEC_TLSTPREL + UNSPEC_TLSTPRELHA + UNSPEC_TLSTPRELLO + UNSPEC_TLSGOTTPREL + UNSPEC_TLSTLS + UNSPEC_FIX_TRUNC_TF ; fadd, rounding towards zero + UNSPEC_MV_CR_GT ; move_from_CR_gt_bit + UNSPEC_STFIWX + UNSPEC_POPCNTB + UNSPEC_FRES + UNSPEC_SP_SET + UNSPEC_SP_TEST + UNSPEC_SYNC + UNSPEC_SYNC_OP + UNSPEC_ATOMIC + UNSPEC_CMPXCHG + UNSPEC_XCHG + UNSPEC_AND + UNSPEC_DLMZB + UNSPEC_DLMZB_CR + UNSPEC_DLMZB_STRLEN + UNSPEC_RSQRT + UNSPEC_TOCREL + UNSPEC_MACHOPIC_OFFSET + UNSPEC_BPERM + UNSPEC_COPYSIGN + UNSPEC_PARITY + UNSPEC_FCTIW + UNSPEC_FCTID + UNSPEC_LFIWAX + UNSPEC_LFIWZX + UNSPEC_FCTIWUZ ]) ;; ;; UNSPEC_VOLATILE usage ;; -(define_constants - [(UNSPECV_BLOCK 0) - (UNSPECV_LL 1) ; load-locked - (UNSPECV_SC 2) ; store-conditional - (UNSPECV_EH_RR 9) ; eh_reg_restore +(define_c_enum "unspecv" + [UNSPECV_BLOCK + UNSPECV_LL ; load-locked + UNSPECV_SC ; store-conditional + UNSPECV_PROBE_STACK_RANGE ; probe range of stack addresses + UNSPECV_EH_RR ; eh_reg_restore + UNSPECV_ISYNC ; isync instruction + UNSPECV_LWSYNC ; lwsync ]) + ;; Define an insn type attribute. This is used in function unit delay ;; computations. @@ -220,6 +227,16 @@ (DD "TARGET_DFP") (TD "TARGET_DFP")]) +; Any fma capable floating-point mode. +(define_mode_iterator FMA_F [ + (SF "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT") + (DF "(TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT) + || VECTOR_UNIT_VSX_P (DFmode)") + (V2SF "TARGET_PAIRED_FLOAT") + (V4SF "VECTOR_UNIT_ALTIVEC_OR_VSX_P (V4SFmode)") + (V2DF "VECTOR_UNIT_ALTIVEC_OR_VSX_P (V2DFmode)") + ]) + ; These modes do not fit in integer registers in 32-bit mode. ; but on e500v2, the gpr are 64 bit registers (define_mode_iterator DIFD [DI (DF "!TARGET_E500_DOUBLE") DD]) @@ -251,13 +268,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")]) @@ -5616,7 +5639,7 @@ (define_expand "rsqrt2" [(match_operand:RECIPF 0 "gpc_reg_operand" "") (match_operand:RECIPF 1 "gpc_reg_operand" "")] - "RS6000_RECIP_HAVE_RSQRT_P (mode)" + "RS6000_RECIP_HAVE_RSQRTE_P (mode)" { rs6000_emit_swrsqrt (operands[0], operands[1]); DONE; @@ -5832,128 +5855,63 @@ "fres %0,%1" [(set_attr "type" "fp")]) -(define_insn "*fmaddsf4_powerpc" - [(set (match_operand:SF 0 "gpc_reg_operand" "=f") - (plus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f") - (match_operand:SF 2 "gpc_reg_operand" "f")) - (match_operand:SF 3 "gpc_reg_operand" "f")))] - "TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS - && TARGET_SINGLE_FLOAT && TARGET_FUSED_MADD" - "fmadds %0,%1,%2,%3" - [(set_attr "type" "fp") - (set_attr "fp_type" "fp_maddsub_s")]) - -(define_insn "*fmaddsf4_power" - [(set (match_operand:SF 0 "gpc_reg_operand" "=f") - (plus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f") - (match_operand:SF 2 "gpc_reg_operand" "f")) - (match_operand:SF 3 "gpc_reg_operand" "f")))] - "! TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD" - "{fma|fmadd} %0,%1,%2,%3" - [(set_attr "type" "dmul")]) - -(define_insn "*fmsubsf4_powerpc" +; builtin fmaf support +(define_insn "*fmasf4_fpr" [(set (match_operand:SF 0 "gpc_reg_operand" "=f") - (minus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f") - (match_operand:SF 2 "gpc_reg_operand" "f")) - (match_operand:SF 3 "gpc_reg_operand" "f")))] - "TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS - && TARGET_SINGLE_FLOAT && TARGET_FUSED_MADD" - "fmsubs %0,%1,%2,%3" - [(set_attr "type" "fp") - (set_attr "fp_type" "fp_maddsub_s")]) - -(define_insn "*fmsubsf4_power" - [(set (match_operand:SF 0 "gpc_reg_operand" "=f") - (minus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f") - (match_operand:SF 2 "gpc_reg_operand" "f")) - (match_operand:SF 3 "gpc_reg_operand" "f")))] - "! TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD" - "{fms|fmsub} %0,%1,%2,%3" - [(set_attr "type" "dmul")]) - -(define_insn "*fnmaddsf4_powerpc_1" - [(set (match_operand:SF 0 "gpc_reg_operand" "=f") - (neg:SF (plus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f") - (match_operand:SF 2 "gpc_reg_operand" "f")) - (match_operand:SF 3 "gpc_reg_operand" "f"))))] - "TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD - && TARGET_SINGLE_FLOAT" - "fnmadds %0,%1,%2,%3" + (fma:SF (match_operand:SF 1 "gpc_reg_operand" "f") + (match_operand:SF 2 "gpc_reg_operand" "f") + (match_operand:SF 3 "gpc_reg_operand" "f")))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT" +{ + return (TARGET_POWERPC + ? "fmadds %0,%1,%2,%3" + : "{fma|fmadd} %0,%1,%2,%3"); +} [(set_attr "type" "fp") (set_attr "fp_type" "fp_maddsub_s")]) -(define_insn "*fnmaddsf4_powerpc_2" +(define_insn "*fmssf4_fpr" [(set (match_operand:SF 0 "gpc_reg_operand" "=f") - (minus:SF (mult:SF (neg:SF (match_operand:SF 1 "gpc_reg_operand" "f")) - (match_operand:SF 2 "gpc_reg_operand" "f")) - (match_operand:SF 3 "gpc_reg_operand" "f")))] - "TARGET_POWERPC && TARGET_SINGLE_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD - && ! HONOR_SIGNED_ZEROS (SFmode)" - "fnmadds %0,%1,%2,%3" + (fma:SF (match_operand:SF 1 "gpc_reg_operand" "f") + (match_operand:SF 2 "gpc_reg_operand" "f") + (neg:SF (match_operand:SF 3 "gpc_reg_operand" "f"))))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT" +{ + return (TARGET_POWERPC + ? "fmsubs %0,%1,%2,%3" + : "{fms|fmsub} %0,%1,%2,%3"); +} [(set_attr "type" "fp") (set_attr "fp_type" "fp_maddsub_s")]) -(define_insn "*fnmaddsf4_power_1" - [(set (match_operand:SF 0 "gpc_reg_operand" "=f") - (neg:SF (plus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f") - (match_operand:SF 2 "gpc_reg_operand" "f")) - (match_operand:SF 3 "gpc_reg_operand" "f"))))] - "! TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD" - "{fnma|fnmadd} %0,%1,%2,%3" - [(set_attr "type" "dmul")]) - -(define_insn "*fnmaddsf4_power_2" - [(set (match_operand:SF 0 "gpc_reg_operand" "=f") - (minus:SF (mult:SF (neg:SF (match_operand:SF 1 "gpc_reg_operand" "f")) - (match_operand:SF 2 "gpc_reg_operand" "f")) - (match_operand:SF 3 "gpc_reg_operand" "f")))] - "! TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD - && ! HONOR_SIGNED_ZEROS (SFmode)" - "{fnma|fnmadd} %0,%1,%2,%3" - [(set_attr "type" "dmul")]) - -(define_insn "*fnmsubsf4_powerpc_1" +(define_insn "*nfmasf4_fpr" [(set (match_operand:SF 0 "gpc_reg_operand" "=f") - (neg:SF (minus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f") - (match_operand:SF 2 "gpc_reg_operand" "f")) - (match_operand:SF 3 "gpc_reg_operand" "f"))))] - "TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD - && TARGET_SINGLE_FLOAT" - "fnmsubs %0,%1,%2,%3" + (neg:SF (fma:SF (match_operand:SF 1 "gpc_reg_operand" "f") + (match_operand:SF 2 "gpc_reg_operand" "f") + (match_operand:SF 3 "gpc_reg_operand" "f"))))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT" +{ + return (TARGET_POWERPC + ? "fnmadds %0,%1,%2,%3" + : "{fnma|fnmadd} %0,%1,%2,%3"); +} [(set_attr "type" "fp") (set_attr "fp_type" "fp_maddsub_s")]) -(define_insn "*fnmsubsf4_powerpc_2" +(define_insn "*nfmssf4_fpr" [(set (match_operand:SF 0 "gpc_reg_operand" "=f") - (minus:SF (match_operand:SF 3 "gpc_reg_operand" "f") - (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f") - (match_operand:SF 2 "gpc_reg_operand" "f"))))] - "TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD - && TARGET_SINGLE_FLOAT && ! HONOR_SIGNED_ZEROS (SFmode)" - "fnmsubs %0,%1,%2,%3" + (neg:SF (fma:SF (match_operand:SF 1 "gpc_reg_operand" "f") + (match_operand:SF 2 "gpc_reg_operand" "f") + (neg:SF (match_operand:SF 3 "gpc_reg_operand" "f")))))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT" +{ + return (TARGET_POWERPC + ? "fnmsubs %0,%1,%2,%3" + : "{fnms|fnmsub} %0,%1,%2,%3"); +} [(set_attr "type" "fp") (set_attr "fp_type" "fp_maddsub_s")]) -(define_insn "*fnmsubsf4_power_1" - [(set (match_operand:SF 0 "gpc_reg_operand" "=f") - (neg:SF (minus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f") - (match_operand:SF 2 "gpc_reg_operand" "f")) - (match_operand:SF 3 "gpc_reg_operand" "f"))))] - "! TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD" - "{fnms|fnmsub} %0,%1,%2,%3" - [(set_attr "type" "dmul")]) - -(define_insn "*fnmsubsf4_power_2" - [(set (match_operand:SF 0 "gpc_reg_operand" "=f") - (minus:SF (match_operand:SF 3 "gpc_reg_operand" "f") - (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f") - (match_operand:SF 2 "gpc_reg_operand" "f"))))] - "! TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD - && ! HONOR_SIGNED_ZEROS (SFmode)" - "{fnms|fnmsub} %0,%1,%2,%3" - [(set_attr "type" "dmul")]) - (define_expand "sqrtsf2" [(set (match_operand:SF 0 "gpc_reg_operand" "") (sqrt:SF (match_operand:SF 1 "gpc_reg_operand" "")))] @@ -6114,6 +6072,38 @@ [(set_attr "type" "isel") (set_attr "length" "4")]) +;; These patterns can be useful for combine; they let combine know that +;; isel can handle reversed comparisons so long as the operands are +;; registers. + +(define_insn "*isel_reversed_signed_" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") + (if_then_else:GPR + (match_operator 1 "scc_rev_comparison_operator" + [(match_operand:CC 4 "cc_reg_operand" "y") + (const_int 0)]) + (match_operand:GPR 2 "gpc_reg_operand" "b") + (match_operand:GPR 3 "gpc_reg_operand" "b")))] + "TARGET_ISEL" + "* +{ return output_isel (operands); }" + [(set_attr "type" "isel") + (set_attr "length" "4")]) + +(define_insn "*isel_reversed_unsigned_" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") + (if_then_else:GPR + (match_operator 1 "scc_rev_comparison_operator" + [(match_operand:CCUNS 4 "cc_reg_operand" "y") + (const_int 0)]) + (match_operand:GPR 2 "gpc_reg_operand" "b") + (match_operand:GPR 3 "gpc_reg_operand" "b")))] + "TARGET_ISEL" + "* +{ return output_isel (operands); }" + [(set_attr "type" "isel") + (set_attr "length" "4")]) + (define_expand "movsfcc" [(set (match_operand:SF 0 "gpc_reg_operand" "") (if_then_else:SF (match_operand 1 "comparison_operator" "") @@ -6268,71 +6258,50 @@ "frsqrte %0,%1" [(set_attr "type" "fp")]) -(define_insn "*fmadddf4_fpr" - [(set (match_operand:DF 0 "gpc_reg_operand" "=d") - (plus:DF (mult:DF (match_operand:DF 1 "gpc_reg_operand" "%d") - (match_operand:DF 2 "gpc_reg_operand" "d")) - (match_operand:DF 3 "gpc_reg_operand" "d")))] - "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD && TARGET_DOUBLE_FLOAT +; builtin fma support +(define_insn "*fmadf4_fpr" + [(set (match_operand:DF 0 "gpc_reg_operand" "=f") + (fma:DF (match_operand:DF 1 "gpc_reg_operand" "f") + (match_operand:DF 2 "gpc_reg_operand" "f") + (match_operand:DF 3 "gpc_reg_operand" "f")))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && VECTOR_UNIT_NONE_P (DFmode)" "{fma|fmadd} %0,%1,%2,%3" - [(set_attr "type" "dmul") - (set_attr "fp_type" "fp_maddsub_d")]) + [(set_attr "type" "fp") + (set_attr "fp_type" "fp_maddsub_s")]) -(define_insn "*fmsubdf4_fpr" - [(set (match_operand:DF 0 "gpc_reg_operand" "=d") - (minus:DF (mult:DF (match_operand:DF 1 "gpc_reg_operand" "%d") - (match_operand:DF 2 "gpc_reg_operand" "d")) - (match_operand:DF 3 "gpc_reg_operand" "d")))] - "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD && TARGET_DOUBLE_FLOAT +(define_insn "*fmsdf4_fpr" + [(set (match_operand:DF 0 "gpc_reg_operand" "=f") + (fma:DF (match_operand:DF 1 "gpc_reg_operand" "f") + (match_operand:DF 2 "gpc_reg_operand" "f") + (neg:DF (match_operand:DF 3 "gpc_reg_operand" "f"))))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && VECTOR_UNIT_NONE_P (DFmode)" "{fms|fmsub} %0,%1,%2,%3" - [(set_attr "type" "dmul") - (set_attr "fp_type" "fp_maddsub_d")]) + [(set_attr "type" "fp") + (set_attr "fp_type" "fp_maddsub_s")]) -(define_insn "*fnmadddf4_fpr_1" - [(set (match_operand:DF 0 "gpc_reg_operand" "=d") - (neg:DF (plus:DF (mult:DF (match_operand:DF 1 "gpc_reg_operand" "%d") - (match_operand:DF 2 "gpc_reg_operand" "d")) - (match_operand:DF 3 "gpc_reg_operand" "d"))))] - "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD && TARGET_DOUBLE_FLOAT +(define_insn "*nfmadf4_fpr" + [(set (match_operand:DF 0 "gpc_reg_operand" "=f") + (neg:DF (fma:DF (match_operand:DF 1 "gpc_reg_operand" "f") + (match_operand:DF 2 "gpc_reg_operand" "f") + (match_operand:DF 3 "gpc_reg_operand" "f"))))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && VECTOR_UNIT_NONE_P (DFmode)" "{fnma|fnmadd} %0,%1,%2,%3" - [(set_attr "type" "dmul") - (set_attr "fp_type" "fp_maddsub_d")]) - -(define_insn "*fnmadddf4_fpr_2" - [(set (match_operand:DF 0 "gpc_reg_operand" "=d") - (minus:DF (mult:DF (neg:DF (match_operand:DF 1 "gpc_reg_operand" "d")) - (match_operand:DF 2 "gpc_reg_operand" "d")) - (match_operand:DF 3 "gpc_reg_operand" "d")))] - "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD && TARGET_DOUBLE_FLOAT - && ! HONOR_SIGNED_ZEROS (DFmode) && VECTOR_UNIT_NONE_P (DFmode)" - "{fnma|fnmadd} %0,%1,%2,%3" - [(set_attr "type" "dmul") - (set_attr "fp_type" "fp_maddsub_d")]) + [(set_attr "type" "fp") + (set_attr "fp_type" "fp_maddsub_s")]) -(define_insn "*fnmsubdf4_fpr_1" - [(set (match_operand:DF 0 "gpc_reg_operand" "=d") - (neg:DF (minus:DF (mult:DF (match_operand:DF 1 "gpc_reg_operand" "%d") - (match_operand:DF 2 "gpc_reg_operand" "d")) - (match_operand:DF 3 "gpc_reg_operand" "d"))))] - "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD && TARGET_DOUBLE_FLOAT +(define_insn "*nfmsdf4_fpr" + [(set (match_operand:DF 0 "gpc_reg_operand" "=f") + (neg:DF (fma:DF (match_operand:DF 1 "gpc_reg_operand" "f") + (match_operand:DF 2 "gpc_reg_operand" "f") + (neg:DF (match_operand:DF 3 "gpc_reg_operand" "f")))))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && VECTOR_UNIT_NONE_P (DFmode)" "{fnms|fnmsub} %0,%1,%2,%3" - [(set_attr "type" "dmul") - (set_attr "fp_type" "fp_maddsub_d")]) - -(define_insn "*fnmsubdf4_fpr_2" - [(set (match_operand:DF 0 "gpc_reg_operand" "=d") - (minus:DF (match_operand:DF 3 "gpc_reg_operand" "d") - (mult:DF (match_operand:DF 1 "gpc_reg_operand" "%d") - (match_operand:DF 2 "gpc_reg_operand" "d"))))] - "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD && TARGET_DOUBLE_FLOAT - && ! HONOR_SIGNED_ZEROS (DFmode) && VECTOR_UNIT_NONE_P (DFmode)" - "{fnms|fnmsub} %0,%1,%2,%3" - [(set_attr "type" "dmul") - (set_attr "fp_type" "fp_maddsub_d")]) + [(set_attr "type" "fp") + (set_attr "fp_type" "fp_maddsub_s")]) (define_expand "sqrtdf2" [(set (match_operand:DF 0 "gpc_reg_operand" "") @@ -6423,29 +6392,154 @@ ;; 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")]) + +; This split must be run before register allocation because it allocates the +; memory slot that is needed to move values to/from the FPR. We don't allocate +; it earlier to allow for the combiner to merge insns together where it might +; not be needed and also in case the insns are deleted as dead code. + +(define_insn_and_split "floatsi2_lfiwax" + [(set (match_operand:SFDF 0 "gpc_reg_operand" "=d") + (float:SFDF (match_operand:SI 1 "nonimmediate_operand" "r"))) + (clobber (match_scratch:DI 2 "=d"))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWAX + && && can_create_pseudo_p ()" + "#" + "" + [(pc)] + " +{ + rtx dest = operands[0]; + rtx src = operands[1]; + rtx tmp; -(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" - "") + if (!MEM_P (src) && TARGET_MFPGPR && TARGET_POWERPC64) + tmp = convert_to_mode (DImode, src, false); + else + { + tmp = operands[2]; + if (GET_CODE (tmp) == SCRATCH) + tmp = gen_reg_rtx (DImode); + if (MEM_P (src)) + { + src = rs6000_address_for_fpconvert (src); + emit_insn (gen_lfiwax (tmp, src)); + } + else + { + rtx stack = rs6000_allocate_stack_temp (SImode, false, true); + emit_move_insn (stack, src); + emit_insn (gen_lfiwax (tmp, stack)); + } + } + emit_insn (gen_floatdi2 (dest, tmp)); + DONE; +}" + [(set_attr "length" "12") + (set_attr "type" "fpload")]) + +(define_insn_and_split "floatsi2_lfiwax_mem" + [(set (match_operand:SFDF 0 "gpc_reg_operand" "=d,") + (float:SFDF + (sign_extend:DI + (match_operand:SI 1 "memory_operand" "Z,Z")))) + (clobber (match_scratch:DI 2 "=0,d"))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWAX + && " + "#" + "" + [(pc)] + " +{ + operands[1] = rs6000_address_for_fpconvert (operands[1]); + if (GET_CODE (operands[2]) == SCRATCH) + operands[2] = gen_reg_rtx (DImode); + emit_insn (gen_lfiwax (operands[2], operands[1])); + emit_insn (gen_floatdi2 (operands[0], operands[2])); + DONE; +}" + [(set_attr "length" "8") + (set_attr "type" "fpload")]) -(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 "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 "floatunssi2_lfiwzx" + [(set (match_operand:SFDF 0 "gpc_reg_operand" "=d") + (unsigned_float:SFDF (match_operand:SI 1 "nonimmediate_operand" "r"))) + (clobber (match_scratch:DI 2 "=d"))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWZX + && " + "#" + "" + [(pc)] + " +{ + rtx dest = operands[0]; + rtx src = operands[1]; + rtx tmp; -(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" - "") + if (!MEM_P (src) && TARGET_MFPGPR && TARGET_POWERPC64) + tmp = convert_to_mode (DImode, src, true); + else + { + tmp = operands[2]; + if (GET_CODE (tmp) == SCRATCH) + tmp = gen_reg_rtx (DImode); + if (MEM_P (src)) + { + src = rs6000_address_for_fpconvert (src); + emit_insn (gen_lfiwzx (tmp, src)); + } + else + { + rtx stack = rs6000_allocate_stack_temp (SImode, false, true); + emit_move_insn (stack, src); + emit_insn (gen_lfiwzx (tmp, stack)); + } + } + emit_insn (gen_floatdi2 (dest, tmp)); + DONE; +}" + [(set_attr "length" "12") + (set_attr "type" "fpload")]) + +(define_insn_and_split "floatunssi2_lfiwzx_mem" + [(set (match_operand:SFDF 0 "gpc_reg_operand" "=d,") + (unsigned_float:SFDF + (zero_extend:DI + (match_operand:SI 1 "memory_operand" "Z,Z")))) + (clobber (match_scratch:DI 2 "=0,d"))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWZX + && " + "#" + "" + [(pc)] + " +{ + operands[1] = rs6000_address_for_fpconvert (operands[1]); + if (GET_CODE (operands[2]) == SCRATCH) + operands[2] = gen_reg_rtx (DImode); + emit_insn (gen_lfiwzx (operands[2], operands[1])); + emit_insn (gen_floatdi2 (operands[0], operands[2])); + DONE; +}" + [(set_attr "length" "8") + (set_attr "type" "fpload")]) ; 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 @@ -6454,7 +6548,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)) @@ -6466,19 +6560,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) { - rtx x = convert_to_mode (DImode, operands[1], 0); - emit_insn (gen_floatdidf2 (operands[0], x)); + emit_insn (gen_floatsidf2_lfiwax (operands[0], operands[1])); + DONE; + } + else if (TARGET_FCFID) + { + 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); }") @@ -6491,7 +6597,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)] @@ -6515,39 +6621,82 @@ emit_insn (gen_subdf3 (operands[0], operands[5], operands[3])); DONE; }" - [(set_attr "length" "24")]) + [(set_attr "length" "24") + (set_attr "type" "fp")]) +;; 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) + { + emit_insn (gen_floatunssisf2_lfiwzx (operands[0], operands[1])); + 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)); + emit_insn (gen_floatunssidf2_lfiwzx (operands[0], operands[1])); + 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); }") @@ -6558,7 +6707,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)] @@ -6580,50 +6730,83 @@ emit_insn (gen_subdf3 (operands[0], operands[5], operands[3])); DONE; }" - [(set_attr "length" "20")]) + [(set_attr "length" "20") + (set_attr "type" "fp")]) -(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_truncsi2" + [(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 && ) || )" " { - if (TARGET_E500_DOUBLE) + if (!) { - emit_insn (gen_spe_fix_truncdfsi2 (operands[0], operands[1])); - DONE; + rtx tmp, stack; + + if (TARGET_STFIWX) + emit_insn (gen_fix_truncsi2_stfiwx (operands[0], operands[1])); + else + { + tmp = gen_reg_rtx (DImode); + stack = rs6000_allocate_stack_temp (DImode, true, false); + emit_insn (gen_fix_truncsi2_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]))) +}") + +; Like the convert to float patterns, this insn must be split before +; register allocation so that it can allocate the memory slot if it +; needed +(define_insn_and_split "fix_truncsi2_stfiwx" + [(set (match_operand:SI 0 "general_operand" "=rm") + (fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "d"))) + (clobber (match_scratch:DI 2 "=d"))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && (mode != SFmode || TARGET_SINGLE_FLOAT) + && TARGET_STFIWX && can_create_pseudo_p ()" + "#" + "" + [(pc)] +{ + rtx dest = operands[0]; + rtx src = operands[1]; + rtx tmp = operands[2]; + + if (GET_CODE (tmp) == SCRATCH) + tmp = gen_reg_rtx (DImode); + + emit_insn (gen_fctiwz_ (tmp, src)); + if (MEM_P (dest)) { - operands[3] = gen_reg_rtx (DImode); - emit_insn (gen_fix_truncdfsi2_mfpgpr (operands[0], operands[1], - operands[2], operands[3])); + dest = rs6000_address_for_fpconvert (dest); + emit_insn (gen_stfiwx (dest, tmp)); DONE; } - if (TARGET_PPC_GFXOPT) + else if (TARGET_MFPGPR && TARGET_POWERPC64) { - 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]); + dest = gen_lowpart (DImode, dest); + emit_move_insn (dest, tmp); DONE; } - operands[3] = assign_stack_temp (DImode, GET_MODE_SIZE (DImode), 0); -}") - -(define_insn_and_split "*fix_truncdfsi2_internal" - [(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 "offsettable_mem_operand" "=o"))] + else + { + rtx stack = rs6000_allocate_stack_temp (SImode, false, true); + emit_insn (gen_stfiwx (stack, tmp)); + emit_move_insn (dest, stack); + DONE; + } +} + [(set_attr "length" "12") + (set_attr "type" "fp")]) + +(define_insn_and_split "fix_truncsi2_internal" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,?r") + (fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "d,"))) + (clobber (match_operand:DI 2 "gpc_reg_operand" "=1,d")) + (clobber (match_operand:DI 3 "offsettable_mem_operand" "=o,o"))] "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT" "#" @@ -6635,143 +6818,269 @@ 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_ (operands[2], operands[1])); emit_move_insn (operands[3], operands[2]); emit_move_insn (operands[0], lowword); DONE; }" - [(set_attr "length" "16")]) + [(set_attr "length" "16") + (set_attr "type" "fp")]) -(define_insn_and_split "fix_truncdfsi2_internal_gfxopt" - [(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" - "#" - "&& 1" - [(pc)] +(define_expand "fix_truncdi2" + [(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_truncdi2_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)" + "fctidz %0,%1" + [(set_attr "type" "fp")]) + +(define_expand "fixuns_truncsi2" + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (unsigned_fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "")))] + "TARGET_HARD_FLOAT + && ((TARGET_FPRS && && TARGET_FCTIWUZ && TARGET_STFIWX) + || )" " { - emit_insn (gen_fctiwz (operands[2], operands[1])); - emit_insn (gen_stfiwx (operands[0], operands[2])); - DONE; -}" - [(set_attr "length" "16")]) + if (!) + { + emit_insn (gen_fixuns_truncsi2_stfiwx (operands[0], operands[1])); + DONE; + } +}") -(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" +(define_insn_and_split "fixuns_truncsi2_stfiwx" + [(set (match_operand:SI 0 "general_operand" "=rm") + (unsigned_fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "d"))) + (clobber (match_scratch:DI 2 "=d"))] + "TARGET_HARD_FLOAT && TARGET_FPRS && && TARGET_FCTIWUZ + && TARGET_STFIWX && can_create_pseudo_p ()" "#" - "&& 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")]) + [(pc)] +{ + rtx dest = operands[0]; + rtx src = operands[1]; + rtx tmp = operands[2]; + + if (GET_CODE (tmp) == SCRATCH) + tmp = gen_reg_rtx (DImode); + + emit_insn (gen_fctiwuz_ (tmp, src)); + if (MEM_P (dest)) + { + dest = rs6000_address_for_fpconvert (dest); + emit_insn (gen_stfiwx (dest, tmp)); + DONE; + } + else if (TARGET_MFPGPR && TARGET_POWERPC64) + { + dest = gen_lowpart (DImode, dest); + emit_move_insn (dest, tmp); + DONE; + } + else + { + rtx stack = rs6000_allocate_stack_temp (SImode, false, true); + emit_insn (gen_stfiwx (stack, tmp)); + emit_move_insn (dest, stack); + DONE; + } +} + [(set_attr "length" "12") + (set_attr "type" "fp")]) + +(define_expand "fixuns_truncdi2" + [(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))" + "") + +(define_insn "*fixuns_truncdi2_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)" + "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_" [(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 "fctiwuz_" + [(set (match_operand:DI 0 "gpc_reg_operand" "=d") + (unspec:DI [(unsigned_fix:SI + (match_operand:SFDF 1 "gpc_reg_operand" ""))] + UNSPEC_FCTIWUZ))] + "TARGET_HARD_FLOAT && TARGET_FPRS && && TARGET_FCTIWUZ" + "fctiwuz %0,%1" + [(set_attr "type" "fp")]) -(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)" +;; Only optimize (float (fix x)) -> frz if we are in fast-math mode, since +;; since the friz instruction does not truncate the value if the floating +;; point value is < LONG_MIN or > LONG_MAX. +(define_insn "*friz" + [(set (match_operand:DF 0 "gpc_reg_operand" "=d") + (float:DF (fix:DI (match_operand:DF 1 "gpc_reg_operand" "d"))))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_FPRND + && !VECTOR_UNIT_VSX_P (DFmode) && flag_unsafe_math_optimizations + && !flag_trapping_math && TARGET_FRIZ" "friz %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" +;; Since FCTIWZ doesn't sign extend the upper bits, we have to do a store and a +;; load to properly sign extend the value, but at least doing a store, load +;; into a GPR to sign extend, a store from the GPR and a load back into the FPR +;; if we have 32-bit memory ops +(define_insn_and_split "*round322_fprs" + [(set (match_operand:SFDF 0 "gpc_reg_operand" "=d") + (float:SFDF + (fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "d")))) + (clobber (match_scratch:DI 2 "=d")) + (clobber (match_scratch:DI 3 "=d"))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && && TARGET_LFIWAX && TARGET_STFIWX && TARGET_FCFID + && can_create_pseudo_p ()" + "#" + "" + [(pc)] +{ + rtx dest = operands[0]; + rtx src = operands[1]; + rtx tmp1 = operands[2]; + rtx tmp2 = operands[3]; + rtx stack = rs6000_allocate_stack_temp (SImode, false, true); + + if (GET_CODE (tmp1) == SCRATCH) + tmp1 = gen_reg_rtx (DImode); + if (GET_CODE (tmp2) == SCRATCH) + tmp2 = gen_reg_rtx (DImode); + + emit_insn (gen_fctiwz_ (tmp1, src)); + emit_insn (gen_stfiwx (stack, tmp1)); + emit_insn (gen_lfiwax (tmp2, stack)); + emit_insn (gen_floatdi2 (dest, tmp2)); + DONE; +} + [(set_attr "type" "fpload") + (set_attr "length" "16")]) + +(define_insn_and_split "*roundu322_fprs" + [(set (match_operand:SFDF 0 "gpc_reg_operand" "=d") + (unsigned_float:SFDF + (unsigned_fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "d")))) + (clobber (match_scratch:DI 2 "=d")) + (clobber (match_scratch:DI 3 "=d"))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && TARGET_LFIWZX && TARGET_STFIWX && TARGET_FCFIDU + && can_create_pseudo_p ()" + "#" + "" + [(pc)] +{ + rtx dest = operands[0]; + rtx src = operands[1]; + rtx tmp1 = operands[2]; + rtx tmp2 = operands[3]; + rtx stack = rs6000_allocate_stack_temp (SImode, false, true); + + if (GET_CODE (tmp1) == SCRATCH) + tmp1 = gen_reg_rtx (DImode); + if (GET_CODE (tmp2) == SCRATCH) + tmp2 = gen_reg_rtx (DImode); + + emit_insn (gen_fctiwuz_ (tmp1, src)); + emit_insn (gen_stfiwx (stack, tmp1)); + emit_insn (gen_lfiwzx (tmp2, stack)); + emit_insn (gen_floatdi2 (dest, tmp2)); + DONE; +} + [(set_attr "type" "fpload") + (set_attr "length" "16")]) + +;; No VSX equivalent to fctid +(define_insn "lrintdi2" + [(set (match_operand:DI 0 "gpc_reg_operand" "=d") + (unspec:DI [(match_operand:SFDF 1 "gpc_reg_operand" "")] + UNSPEC_FCTID))] + "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && " + "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 "btrunc2" + [(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 && " "") -(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 "*btrunc2_fpr" + [(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 && + && !VECTOR_UNIT_VSX_P (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 "ceil2" + [(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 && " + "") + +(define_insn "*ceil2_fpr" + [(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 && + && !VECTOR_UNIT_VSX_P (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 "floor2" + [(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 && " "") -(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 "*floor2_fpr" + [(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 && + && !VECTOR_UNIT_VSX_P (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 "round2" + [(set (match_operand:SFDF 0 "gpc_reg_operand" "=") + (unspec:SFDF [(match_operand:SFDF 1 "gpc_reg_operand" "")] + UNSPEC_FRIN))] + "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && " "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") @@ -6781,83 +7090,173 @@ "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) + { + emit_insn (gen_floatsisf2_lfiwax (operands[0], operands[1])); + DONE; + } + else if (TARGET_FCFID && TARGET_LFIWAX) + { + rtx dfreg = gen_reg_rtx (DFmode); + emit_insn (gen_floatsidf2_lfiwax (dfreg, operands[1])); + emit_insn (gen_truncdfsf2 (operands[0], dfreg)); + 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") + (set_attr "type" "fpload")]) + (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_HARD_FLOAT && (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_HARD_FLOAT && 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_HARD_FLOAT && (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") + (set_attr "type" "fpload")]) (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. +;; Instead of creating a new cpu type for two FP operations, just use fp (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) (float:DF (match_dup 1))) (set (match_dup 0) (float_truncate:SF (match_dup 2)))] - "") + "" + [(set_attr "length" "8") + (set_attr "type" "fp")]) ;; Twiddles bits to avoid double rounding. ;; Bits that might be truncated when converting to DFmode are replaced @@ -6890,6 +7289,39 @@ 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") + (set_attr "type" "fpload")]) ;; Define the DImode operations that can be done in a small number ;; of instructions. The & constraints are to prevent the register @@ -9213,6 +9645,27 @@ [(set_attr "type" "two,load,store,*,*,*") (set_attr "length" "8,8,8,8,12,16")]) +;; Reload patterns to support gpr load/store with misaligned mem. +(define_expand "reload_di_store" + [(parallel [(match_operand 0 "memory_operand" "=m") + (match_operand 1 "gpc_reg_operand" "r") + (match_operand:DI 2 "register_operand" "=&b")])] + "TARGET_POWERPC64" +{ + rs6000_secondary_reload_ppc64 (operands[1], operands[0], operands[2], true); + DONE; +}) + +(define_expand "reload_di_load" + [(parallel [(match_operand 0 "gpc_reg_operand" "=r") + (match_operand 1 "memory_operand" "m") + (match_operand:DI 2 "register_operand" "=b")])] + "TARGET_POWERPC64" +{ + rs6000_secondary_reload_ppc64 (operands[0], operands[1], operands[2], false); + DONE; +}) + ; ld/std require word-aligned displacements -> 'Y' constraint. ; List Y->r and r->Y before r->r for reload. (define_insn "*movdf_hardfloat64_mfpgpr" @@ -9539,7 +9992,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; @@ -9621,8 +10074,8 @@ ; List r->r after r->"o<>", otherwise reload will try to reload a ; non-offsettable address by using r->r which won't make progress. (define_insn "*movdi_internal32" - [(set (match_operand:DI 0 "rs6000_nonimmediate_operand" "=o<>,r,r,*d,*d,m,r") - (match_operand:DI 1 "input_operand" "r,r,m,d,m,d,IJKnGHF"))] + [(set (match_operand:DI 0 "rs6000_nonimmediate_operand" "=o<>,r,r,*d,*d,m,r,?wa") + (match_operand:DI 1 "input_operand" "r,r,m,d,m,d,IJKnGHF,O"))] "! TARGET_POWERPC64 && (gpc_reg_operand (operands[0], DImode) || gpc_reg_operand (operands[1], DImode))" @@ -9633,13 +10086,15 @@ fmr %0,%1 lfd%U1%X1 %0,%1 stfd%U0%X0 %1,%0 - #" - [(set_attr "type" "load,*,store,fp,fpload,fpstore,*")]) + # + xxlxor %x0,%x0,%x0" + [(set_attr "type" "load,*,store,fp,fpload,fpstore,*,vecsimple")]) (define_split [(set (match_operand:DI 0 "gpc_reg_operand" "") (match_operand:DI 1 "const_int_operand" ""))] - "! TARGET_POWERPC64 && reload_completed" + "! TARGET_POWERPC64 && reload_completed + && gpr_or_gpr_p (operands[0], operands[1])" [(set (match_dup 2) (match_dup 4)) (set (match_dup 3) (match_dup 1))] " @@ -9691,8 +10146,8 @@ (set_attr "length" "4,4,4,4,4,20,4,4,4,4,4,4,4,4,4")]) (define_insn "*movdi_internal64" - [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,r,r,r,r,*d,*d,m,r,*h,*h") - (match_operand:DI 1 "input_operand" "r,m,r,I,L,nF,R,d,m,d,*h,r,0"))] + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,r,r,r,r,*d,*d,m,r,*h,*h,?wa") + (match_operand:DI 1 "input_operand" "r,m,r,I,L,nF,R,d,m,d,*h,r,0,O"))] "TARGET_POWERPC64 && (!TARGET_MFPGPR || !TARGET_HARD_FLOAT || !TARGET_FPRS) && (gpc_reg_operand (operands[0], DImode) || gpc_reg_operand (operands[1], DImode))" @@ -9709,9 +10164,10 @@ stfd%U0%X0 %1,%0 mf%1 %0 mt%0 %1 - {cror 0,0,0|nop}" - [(set_attr "type" "*,load,store,*,*,*,*,fp,fpload,fpstore,mfjmpr,mtjmpr,*") - (set_attr "length" "4,4,4,4,4,20,4,4,4,4,4,4,4")]) + {cror 0,0,0|nop} + xxlxor %x0,%x0,%x0" + [(set_attr "type" "*,load,store,*,*,*,*,fp,fpload,fpstore,mfjmpr,mtjmpr,*,vecsimple") + (set_attr "length" "4,4,4,4,4,20,4,4,4,4,4,4,4,4")]) ;; immediate value valid for a single instruction hiding in a const_double (define_insn "" @@ -11628,8 +12084,8 @@ [(set_attr "type" "load")]) (define_insn "load_toc_v4_PIC_3b" - [(set (match_operand:SI 0 "gpc_reg_operand" "=b") - (plus:SI (match_operand:SI 1 "gpc_reg_operand" "r") + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (plus:SI (match_operand:SI 1 "gpc_reg_operand" "b") (high:SI (minus:SI (match_operand:SI 2 "symbol_ref_operand" "s") (match_operand:SI 3 "symbol_ref_operand" "s")))))] @@ -12663,6 +13119,15 @@ "{st%U0%X0|stw%U0%X0} 0,%0" [(set_attr "type" "store") (set_attr "length" "4")]) + +(define_insn "probe_stack_range" + [(set (match_operand:P 0 "register_operand" "=r") + (unspec_volatile:P [(match_operand:P 1 "register_operand" "0") + (match_operand:P 2 "register_operand" "r")] + UNSPECV_PROBE_STACK_RANGE))] + "" + "* return output_probe_stack_range (operands[0], operands[2]);" + [(set_attr "type" "three")]) ;; Compare insns are next. Note that the RS/6000 has two types of compares, ;; signed & unsigned, and one type of branch. @@ -15666,6 +16131,73 @@ [(set_attr "type" "integer")]) +;; Builtin fma support. Handle +;; Note that the conditions for expansion are in the FMA_F iterator. + +(define_expand "fma4" + [(set (match_operand:FMA_F 0 "register_operand" "") + (fma:FMA_F + (match_operand:FMA_F 1 "register_operand" "") + (match_operand:FMA_F 2 "register_operand" "") + (match_operand:FMA_F 3 "register_operand" "")))] + "" + "") + +; Altivec only has fma and nfms. +(define_expand "fms4" + [(set (match_operand:FMA_F 0 "register_operand" "") + (fma:FMA_F + (match_operand:FMA_F 1 "register_operand" "") + (match_operand:FMA_F 2 "register_operand" "") + (neg:FMA_F (match_operand:FMA_F 3 "register_operand" ""))))] + "!VECTOR_UNIT_ALTIVEC_P (mode)" + "") + +;; If signed zeros are ignored, -(a * b - c) = -a * b + c. +(define_expand "fnma4" + [(set (match_operand:FMA_F 0 "register_operand" "") + (neg:FMA_F + (fma:FMA_F + (match_operand:FMA_F 1 "register_operand" "") + (match_operand:FMA_F 2 "register_operand" "") + (neg:FMA_F (match_operand:FMA_F 3 "register_operand" "")))))] + "!HONOR_SIGNED_ZEROS (mode)" + "") + +;; If signed zeros are ignored, -(a * b + c) = -a * b - c. +(define_expand "fnms4" + [(set (match_operand:FMA_F 0 "register_operand" "") + (neg:FMA_F + (fma:FMA_F + (match_operand:FMA_F 1 "register_operand" "") + (match_operand:FMA_F 2 "register_operand" "") + (match_operand:FMA_F 3 "register_operand" ""))))] + "!HONOR_SIGNED_ZEROS (mode) && !VECTOR_UNIT_ALTIVEC_P (mode)" + "") + +; Not an official optab name, but used from builtins. +(define_expand "nfma4" + [(set (match_operand:FMA_F 0 "register_operand" "") + (neg:FMA_F + (fma:FMA_F + (match_operand:FMA_F 1 "register_operand" "") + (match_operand:FMA_F 2 "register_operand" "") + (match_operand:FMA_F 3 "register_operand" ""))))] + "!VECTOR_UNIT_ALTIVEC_P (mode)" + "") + +; Not an official optab name, but used from builtins. +(define_expand "nfms4" + [(set (match_operand:FMA_F 0 "register_operand" "") + (neg:FMA_F + (fma:FMA_F + (match_operand:FMA_F 1 "register_operand" "") + (match_operand:FMA_F 2 "register_operand" "") + (neg:FMA_F (match_operand:FMA_F 3 "register_operand" "")))))] + "" + "") + + (include "sync.md") (include "vector.md")