Mercurial > hg > CbC > CbC_gcc
diff gcc/config/rs6000/rs6000.md @ 69:1b10fe6932e1
merge 69
author | Nobuyasu Oshiro <dimolto@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Sun, 21 Aug 2011 07:53:12 +0900 |
parents | 326d9e06c2e3 f6334be47118 |
children | ab0bcb71f44d |
line wrap: on
line diff
--- a/gcc/config/rs6000/rs6000.md Tue Dec 14 03:58:33 2010 +0900 +++ b/gcc/config/rs6000/rs6000.md Sun Aug 21 07:53:12 2011 +0900 @@ -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 +;; 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 ;; Free Software Foundation, Inc. ;; Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu) @@ -39,7 +39,7 @@ (CR6_REGNO 74) (CR7_REGNO 75) (MAX_CR_REGNO 75) - (XER_REGNO 76) + (CA_REGNO 76) (FIRST_ALTIVEC_REGNO 77) (LAST_ALTIVEC_REGNO 108) (VRSAVE_REGNO 109) @@ -103,6 +103,13 @@ (UNSPEC_TOCREL 49) (UNSPEC_MACHOPIC_OFFSET 50) (UNSPEC_BPERM 51) + (UNSPEC_COPYSIGN 52) + (UNSPEC_PARITY 53) + (UNSPEC_FCTIW 54) + (UNSPEC_FCTID 55) + (UNSPEC_LFIWAX 56) + (UNSPEC_LFIWZX 57) + (UNSPEC_FCTIWUZ 58) ]) ;; @@ -113,6 +120,7 @@ [(UNSPECV_BLOCK 0) (UNSPECV_LL 1) ; load-locked (UNSPECV_SC 2) ; store-conditional + (UNSPECV_PROBE_STACK_RANGE 3) ; probe range of stack addresses (UNSPECV_EH_RR 9) ; eh_reg_restore ]) @@ -140,7 +148,7 @@ ;; Processor type -- this attribute must exactly match the processor_type ;; enumeration in rs6000.h. -(define_attr "cpu" "rios1,rios2,rs64a,mpccore,ppc403,ppc405,ppc440,ppc476,ppc601,ppc603,ppc604,ppc604e,ppc620,ppc630,ppc750,ppc7400,ppc7450,ppc8540,ppce300c2,ppce300c3,ppce500mc,ppce500mc64,power4,power5,power6,power7,cell,ppca2" +(define_attr "cpu" "rios1,rios2,rs64a,mpccore,ppc403,ppc405,ppc440,ppc476,ppc601,ppc603,ppc604,ppc604e,ppc620,ppc630,ppc750,ppc7400,ppc7450,ppc8540,ppce300c2,ppce300c3,ppce500mc,ppce500mc64,power4,power5,power6,power7,cell,ppca2,titan" (const (symbol_ref "rs6000_cpu_attr"))) @@ -175,6 +183,7 @@ (include "cell.md") (include "xfpu.md") (include "a2.md") +(include "titan.md") (include "predicates.md") (include "constraints.md") @@ -201,7 +210,7 @@ (define_mode_iterator SDI [SI DI]) ; The size of a pointer. Also, the size of the value that a record-condition -; (one with a '.') will compare. +; (one with a '.') will compare; and the size used for arithmetic carries. (define_mode_iterator P [(SI "TARGET_32BIT") (DI "TARGET_64BIT")]) ; Any hardware-supported floating-point mode @@ -217,6 +226,26 @@ (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]) + +; Iterator for reciprocal estimate instructions +(define_mode_iterator RECIPF [SF DF V4SF V2DF]) + +; Iterator for just SF/DF +(define_mode_iterator SFDF [SF DF]) + ; Various instructions that come in SI and DI forms. ; A generic w/d attribute, for things like cmpw/cmpd. (define_mode_attr wd [(QI "b") (HI "h") (SI "w") (DI "d")]) @@ -237,6 +266,22 @@ (define_mode_attr mptrsize [(SI "si") (DI "di")]) +(define_mode_attr rreg [(SF "f") + (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")]) ;; Start with fixed-point load and store insns. Here we put only the more ;; complex forms. Basic data transfer is done later. @@ -2092,10 +2137,10 @@ (compare:CC (match_dup 1) (const_int 0))) (set (match_dup 0) - (if_then_else:GPR (ge (match_dup 3) + (if_then_else:GPR (lt (match_dup 3) (const_int 0)) - (match_dup 1) - (match_dup 2)))] + (match_dup 2) + (match_dup 1)))] "") (define_insn_and_split "nabs<mode>2_isel" @@ -2111,10 +2156,10 @@ (compare:CC (match_dup 1) (const_int 0))) (set (match_dup 0) - (if_then_else:GPR (ge (match_dup 3) + (if_then_else:GPR (lt (match_dup 3) (const_int 0)) - (match_dup 2) - (match_dup 1)))] + (match_dup 1) + (match_dup 2)))] "") (define_insn_and_split "abssi2_nopower" @@ -2259,17 +2304,11 @@ "TARGET_POPCNTB" "popcntb %0,%1") -(define_insn "popcntwsi2" - [(set (match_operand:SI 0 "gpc_reg_operand" "=r") - (popcount:SI (match_operand:SI 1 "gpc_reg_operand" "r")))] +(define_insn "popcntd<mode>2" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") + (popcount:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")))] "TARGET_POPCNTD" - "popcntw %0,%1") - -(define_insn "popcntddi2" - [(set (match_operand:DI 0 "gpc_reg_operand" "=r") - (popcount:DI (match_operand:DI 1 "gpc_reg_operand" "r")))] - "TARGET_POPCNTD && TARGET_POWERPC64" - "popcntd %0,%1") + "popcnt<wd> %0,%1") (define_expand "popcount<mode>2" [(set (match_operand:GPR 0 "gpc_reg_operand" "") @@ -2280,6 +2319,12 @@ DONE; }) +(define_insn "parity<mode>2_cmpb" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") + (unspec:GPR [(match_operand:GPR 1 "gpc_reg_operand" "r")] UNSPEC_PARITY))] + "TARGET_CMPB && TARGET_POPCNTB" + "prty<wd> %0,%1") + (define_expand "parity<mode>2" [(set (match_operand:GPR 0 "gpc_reg_operand" "") (parity:GPR (match_operand:GPR 1 "gpc_reg_operand" "")))] @@ -5560,6 +5605,45 @@ [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") (set_attr "length" "4,4,8,8")]) +;; Builtins to replace a division to generate FRE reciprocal estimate +;; instructions and the necessary fixup instructions +(define_expand "recip<mode>3" + [(match_operand:RECIPF 0 "gpc_reg_operand" "") + (match_operand:RECIPF 1 "gpc_reg_operand" "") + (match_operand:RECIPF 2 "gpc_reg_operand" "")] + "RS6000_RECIP_HAVE_RE_P (<MODE>mode)" +{ + rs6000_emit_swdiv (operands[0], operands[1], operands[2], false); + DONE; +}) + +;; Split to create division from FRE/FRES/etc. and fixup instead of the normal +;; hardware division. This is only done before register allocation and with +;; -ffast-math. This must appear before the divsf3/divdf3 insns. +(define_split + [(set (match_operand:RECIPF 0 "gpc_reg_operand" "") + (div:RECIPF (match_operand 1 "gpc_reg_operand" "") + (match_operand 2 "gpc_reg_operand" "")))] + "RS6000_RECIP_AUTO_RE_P (<MODE>mode) + && can_create_pseudo_p () && optimize_insn_for_speed_p () + && flag_finite_math_only && !flag_trapping_math && flag_reciprocal_math" + [(const_int 0)] +{ + rs6000_emit_swdiv (operands[0], operands[1], operands[2], true); + DONE; +}) + +;; Builtins to replace 1/sqrt(x) with instructions using RSQRTE and the +;; appropriate fixup. +(define_expand "rsqrt<mode>2" + [(match_operand:RECIPF 0 "gpc_reg_operand" "") + (match_operand:RECIPF 1 "gpc_reg_operand" "")] + "RS6000_RECIP_HAVE_RSQRTE_P (<MODE>mode)" +{ + rs6000_emit_swrsqrt (operands[0], operands[1]); + DONE; +}) + (define_split [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "") (compare:CC (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "") @@ -5763,147 +5847,70 @@ "{fd|fdiv} %0,%1,%2" [(set_attr "type" "ddiv")]) -(define_expand "recipsf3" - [(set (match_operand:SF 0 "gpc_reg_operand" "=f") - (unspec:SF [(match_operand:SF 1 "gpc_reg_operand" "f") - (match_operand:SF 2 "gpc_reg_operand" "f")] - UNSPEC_FRES))] - "TARGET_RECIP && TARGET_HARD_FLOAT && TARGET_PPC_GFXOPT && !optimize_size - && flag_finite_math_only && !flag_trapping_math" -{ - rs6000_emit_swdivsf (operands[0], operands[1], operands[2]); - DONE; -}) - (define_insn "fres" [(set (match_operand:SF 0 "gpc_reg_operand" "=f") (unspec:SF [(match_operand:SF 1 "gpc_reg_operand" "f")] UNSPEC_FRES))] - "TARGET_PPC_GFXOPT && flag_finite_math_only" + "TARGET_FRES" "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" +(define_insn "*nfmasf4_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_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" - [(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" "")))] @@ -5928,69 +5935,53 @@ "fsqrt %0,%1" [(set_attr "type" "dsqrt")]) -(define_expand "rsqrtsf2" - [(set (match_operand:SF 0 "gpc_reg_operand" "=f") - (unspec:SF [(match_operand:SF 1 "gpc_reg_operand" "f")] - UNSPEC_RSQRT))] - "TARGET_RECIP && TARGET_HARD_FLOAT && TARGET_PPC_GFXOPT && !optimize_size - && flag_finite_math_only && !flag_trapping_math" -{ - rs6000_emit_swrsqrtsf (operands[0], operands[1]); - DONE; -}) - -(define_insn "*rsqrt_internal1" +(define_insn "*rsqrtsf_internal1" [(set (match_operand:SF 0 "gpc_reg_operand" "=f") (unspec:SF [(match_operand:SF 1 "gpc_reg_operand" "f")] UNSPEC_RSQRT))] - "TARGET_HARD_FLOAT && TARGET_PPC_GFXOPT" - "frsqrte %0,%1" + "TARGET_FRSQRTES" + "frsqrtes %0,%1" [(set_attr "type" "fp")]) -(define_expand "copysignsf3" +(define_expand "copysign<mode>3" [(set (match_dup 3) - (abs:SF (match_operand:SF 1 "gpc_reg_operand" ""))) + (abs:SFDF (match_operand:SFDF 1 "gpc_reg_operand" ""))) (set (match_dup 4) - (neg:SF (abs:SF (match_dup 1)))) - (set (match_operand:SF 0 "gpc_reg_operand" "") - (if_then_else:SF (ge (match_operand:SF 2 "gpc_reg_operand" "") - (match_dup 5)) + (neg:SFDF (abs:SFDF (match_dup 1)))) + (set (match_operand:SFDF 0 "gpc_reg_operand" "") + (if_then_else:SFDF (ge (match_operand:SFDF 2 "gpc_reg_operand" "") + (match_dup 5)) (match_dup 3) (match_dup 4)))] - "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT - && !HONOR_NANS (SFmode) && !HONOR_SIGNED_ZEROS (SFmode)" - { - operands[3] = gen_reg_rtx (SFmode); - operands[4] = gen_reg_rtx (SFmode); - operands[5] = CONST0_RTX (SFmode); + "TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT> + && ((TARGET_PPC_GFXOPT + && !HONOR_NANS (<MODE>mode) + && !HONOR_SIGNED_ZEROS (<MODE>mode)) + || TARGET_CMPB + || VECTOR_UNIT_VSX_P (<MODE>mode))" +{ + if (TARGET_CMPB || VECTOR_UNIT_VSX_P (<MODE>mode)) + { + emit_insn (gen_copysign<mode>3_fcpsgn (operands[0], operands[1], + operands[2])); + DONE; + } + + operands[3] = gen_reg_rtx (<MODE>mode); + operands[4] = gen_reg_rtx (<MODE>mode); + operands[5] = CONST0_RTX (<MODE>mode); }) -(define_expand "copysigndf3" - [(set (match_dup 3) - (abs:DF (match_operand:DF 1 "gpc_reg_operand" ""))) - (set (match_dup 4) - (neg:DF (abs:DF (match_dup 1)))) - (set (match_operand:DF 0 "gpc_reg_operand" "") - (if_then_else:DF (ge (match_operand:DF 2 "gpc_reg_operand" "") - (match_dup 5)) - (match_dup 3) - (match_dup 4)))] - "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT - && ((TARGET_PPC_GFXOPT - && !HONOR_NANS (DFmode) - && !HONOR_SIGNED_ZEROS (DFmode)) - || VECTOR_UNIT_VSX_P (DFmode))" - { - if (VECTOR_UNIT_VSX_P (DFmode)) - { - emit_insn (gen_vsx_copysigndf3 (operands[0], operands[1], - operands[2], CONST0_RTX (DFmode))); - DONE; - } - operands[3] = gen_reg_rtx (DFmode); - operands[4] = gen_reg_rtx (DFmode); - operands[5] = CONST0_RTX (DFmode); - }) +;; Use an unspec rather providing an if-then-else in RTL, to prevent the +;; compiler from optimizing -0.0 +(define_insn "copysign<mode>3_fcpsgn" + [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>") + (unspec:SFDF [(match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>") + (match_operand:SFDF 2 "gpc_reg_operand" "<rreg2>")] + UNSPEC_COPYSIGN))] + "TARGET_CMPB && !VECTOR_UNIT_VSX_P (<MODE>mode)" + "fcpsgn %0,%2,%1" + [(set_attr "type" "fp")]) ;; For MIN, MAX, and conditional move, we use DEFINE_EXPAND's that involve a ;; fsel instruction and some auxiliary computations. Then we just have a @@ -6053,9 +6044,41 @@ ;; change the mode underneath our feet and then gets confused trying ;; to reload the value. (define_insn "isel_signed_<mode>" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r") + (if_then_else:GPR + (match_operator 1 "scc_comparison_operator" + [(match_operand:CC 4 "cc_reg_operand" "y,y") + (const_int 0)]) + (match_operand:GPR 2 "reg_or_cint_operand" "O,b") + (match_operand:GPR 3 "gpc_reg_operand" "r,r")))] + "TARGET_ISEL<sel>" + "* +{ return output_isel (operands); }" + [(set_attr "type" "isel") + (set_attr "length" "4")]) + +(define_insn "isel_unsigned_<mode>" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r") + (if_then_else:GPR + (match_operator 1 "scc_comparison_operator" + [(match_operand:CCUNS 4 "cc_reg_operand" "y,y") + (const_int 0)]) + (match_operand:GPR 2 "reg_or_cint_operand" "O,b") + (match_operand:GPR 3 "gpc_reg_operand" "r,r")))] + "TARGET_ISEL<sel>" + "* +{ return output_isel (operands); }" + [(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_<mode>" [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") (if_then_else:GPR - (match_operator 1 "comparison_operator" + (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") @@ -6066,10 +6089,10 @@ [(set_attr "type" "isel") (set_attr "length" "4")]) -(define_insn "isel_unsigned_<mode>" +(define_insn "*isel_reversed_unsigned_<mode>" [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") (if_then_else:GPR - (match_operator 1 "comparison_operator" + (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") @@ -6219,98 +6242,74 @@ "{fd|fdiv} %0,%1,%2" [(set_attr "type" "ddiv")]) -(define_expand "recipdf3" - [(set (match_operand:DF 0 "gpc_reg_operand" "=d") - (unspec:DF [(match_operand:DF 1 "gpc_reg_operand" "d") - (match_operand:DF 2 "gpc_reg_operand" "d")] - UNSPEC_FRES))] - "TARGET_RECIP && TARGET_HARD_FLOAT && TARGET_POPCNTB && !optimize_size - && flag_finite_math_only && !flag_trapping_math" -{ - rs6000_emit_swdivdf (operands[0], operands[1], operands[2]); - DONE; -}) - -(define_expand "fred" - [(set (match_operand:DF 0 "gpc_reg_operand" "=d") - (unspec:DF [(match_operand:DF 1 "gpc_reg_operand" "d")] UNSPEC_FRES))] - "(TARGET_POPCNTB || VECTOR_UNIT_VSX_P (DFmode)) && flag_finite_math_only" - "") - (define_insn "*fred_fpr" [(set (match_operand:DF 0 "gpc_reg_operand" "=f") (unspec:DF [(match_operand:DF 1 "gpc_reg_operand" "f")] UNSPEC_FRES))] - "TARGET_POPCNTB && flag_finite_math_only && !VECTOR_UNIT_VSX_P (DFmode)" + "TARGET_FRE && !VECTOR_UNIT_VSX_P (DFmode)" "fre %0,%1" [(set_attr "type" "fp")]) -(define_insn "*fmadddf4_fpr" +(define_insn "*rsqrtdf_internal1" [(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 + (unspec:DF [(match_operand:DF 1 "gpc_reg_operand" "d")] + UNSPEC_RSQRT))] + "TARGET_FRSQRTE && !VECTOR_UNIT_VSX_P (DFmode)" + "frsqrte %0,%1" + [(set_attr "type" "fp")]) + +; 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")]) - -(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 + [(set_attr "type" "fp") + (set_attr "fp_type" "fp_maddsub_s")]) + +(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")]) - -(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 + [(set_attr "type" "fp") + (set_attr "fp_type" "fp_maddsub_s")]) + +(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")]) - -(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 + [(set_attr "type" "fp") + (set_attr "fp_type" "fp_maddsub_s")]) + +(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")]) - -(define_insn "sqrtdf2" + [(set_attr "type" "fp") + (set_attr "fp_type" "fp_maddsub_s")]) + +(define_expand "sqrtdf2" + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (sqrt:DF (match_operand:DF 1 "gpc_reg_operand" "")))] + "(TARGET_PPC_GPOPT || TARGET_POWER2) && TARGET_HARD_FLOAT && TARGET_FPRS + && TARGET_DOUBLE_FLOAT" + "") + +(define_insn "*sqrtdf2_fpr" [(set (match_operand:DF 0 "gpc_reg_operand" "=d") (sqrt:DF (match_operand:DF 1 "gpc_reg_operand" "d")))] "(TARGET_PPC_GPOPT || TARGET_POWER2) && TARGET_HARD_FLOAT && TARGET_FPRS @@ -6392,29 +6391,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" - "") - -(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_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_expand "fixuns_truncdfdi2" - [(set (match_operand:DI 0 "register_operand" "") - (unsigned_fix:DI (match_operand:DF 1 "register_operand" "")))] - "TARGET_HARD_FLOAT && TARGET_VSX" - "") +; We don't define lfiwax/lfiwzx with the normal definition, because we +; don't want to support putting SImode in FPR registers. +(define_insn "lfiwax" + [(set (match_operand:DI 0 "gpc_reg_operand" "=d") + (unspec:DI [(match_operand:SI 1 "indexed_or_indirect_operand" "Z")] + UNSPEC_LFIWAX))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWAX" + "lfiwax %0,%y1" + [(set_attr "type" "fpload")]) + +; 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 "floatsi<mode>2_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 + && <SI_CONVERT_FP> && can_create_pseudo_p ()" + "#" + "" + [(pc)] + " +{ + rtx dest = operands[0]; + rtx src = operands[1]; + rtx tmp; + + 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_floatdi<mode>2 (dest, tmp)); + DONE; +}" + [(set_attr "length" "12") + (set_attr "type" "fpload")]) + +(define_insn_and_split "floatsi<mode>2_lfiwax_mem" + [(set (match_operand:SFDF 0 "gpc_reg_operand" "=d,<rreg2>") + (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 + && <SI_CONVERT_FP>" + "#" + "" + [(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_floatdi<mode>2 (operands[0], operands[2])); + DONE; +}" + [(set_attr "length" "8") + (set_attr "type" "fpload")]) + +(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" "=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 + && <SI_CONVERT_FP>" + "#" + "" + [(pc)] + " +{ + rtx dest = operands[0]; + rtx src = operands[1]; + rtx tmp; + + 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_floatdi<mode>2 (dest, tmp)); + DONE; +}" + [(set_attr "length" "12") + (set_attr "type" "fpload")]) + +(define_insn_and_split "floatunssi<mode>2_lfiwzx_mem" + [(set (match_operand:SFDF 0 "gpc_reg_operand" "=d,<rreg2>") + (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 + && <SI_CONVERT_FP>" + "#" + "" + [(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_floatdi<mode>2 (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 @@ -6423,7 +6547,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)) @@ -6435,19 +6559,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) - { - rtx x = convert_to_mode (DImode, operands[1], 0); - emit_insn (gen_floatdidf2 (operands[0], x)); + else if (TARGET_LFIWAX && TARGET_FCFID) + { + 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); }") @@ -6460,7 +6596,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)] @@ -6484,39 +6620,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) - { - rtx x = convert_to_mode (DImode, operands[1], 1); - emit_insn (gen_floatdidf2 (operands[0], x)); + else if (TARGET_LFIWZX && TARGET_FCFID) + { + 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); }") @@ -6527,7 +6706,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)] @@ -6549,50 +6729,83 @@ emit_insn (gen_subdf3 (operands[0], operands[5], operands[3])); DONE; }" - [(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)" - " -{ - if (TARGET_E500_DOUBLE) - { - emit_insn (gen_spe_fix_truncdfsi2 (operands[0], operands[1])); - 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]))) - { - operands[3] = gen_reg_rtx (DImode); - emit_insn (gen_fix_truncdfsi2_mfpgpr (operands[0], operands[1], - operands[2], operands[3])); + [(set_attr "length" "20") + (set_attr "type" "fp")]) + +(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 (!<E500_CONVERT>) + { + rtx tmp, stack; + + if (TARGET_STFIWX) + emit_insn (gen_fix_trunc<mode>si2_stfiwx (operands[0], operands[1])); + 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; } - if (TARGET_PPC_GFXOPT) - { - 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]); +}") + +; 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_trunc<mode>si2_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>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_<mode> (tmp, src)); + if (MEM_P (dest)) + { + dest = rs6000_address_for_fpconvert (dest); + emit_insn (gen_stfiwx (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 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_insn_and_split "fix_trunc<mode>si2_internal" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,?r") + (fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "d,<rreg>"))) + (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" "#" @@ -6604,143 +6817,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_<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" - [(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" + [(set_attr "length" "16") + (set_attr "type" "fp")]) + +(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>) + { + emit_insn (gen_fixuns_trunc<mode>si2_stfiwx (operands[0], operands[1])); + DONE; + } +}") + +(define_insn_and_split "fixuns_trunc<mode>si2_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_FLOAT> && TARGET_FCTIWUZ + && TARGET_STFIWX && can_create_pseudo_p ()" "#" - "&& 1" + "" [(pc)] - " -{ - emit_insn (gen_fctiwz (operands[2], operands[1])); - emit_insn (gen_stfiwx (operands[0], operands[2])); - DONE; -}" - [(set_attr "length" "16")]) - -(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")]) +{ + 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_<mode> (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_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" +(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")]) + +;; 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") - (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" - [(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" + (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_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_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" +;; 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 "*round32<mode>2_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 + && <SI_CONVERT_FP> && 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_<mode> (tmp1, src)); + emit_insn (gen_stfiwx (stack, tmp1)); + emit_insn (gen_lfiwax (tmp2, stack)); + emit_insn (gen_floatdi<mode>2 (dest, tmp2)); + DONE; +} + [(set_attr "type" "fpload") + (set_attr "length" "16")]) + +(define_insn_and_split "*roundu32<mode>2_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_<mode> (tmp1, src)); + emit_insn (gen_stfiwx (stack, tmp1)); + emit_insn (gen_lfiwzx (tmp2, stack)); + emit_insn (gen_floatdi<mode>2 (dest, tmp2)); + DONE; +} + [(set_attr "type" "fpload") + (set_attr "length" "16")]) + +;; 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_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 "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 "*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_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_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_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 "*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" +(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_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 " - "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") @@ -6750,83 +7089,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" - "") - -(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 "*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")]) + (unsigned_float:DF + (match_operand:DI 1 "gpc_reg_operand" "")))] + "TARGET_HARD_FLOAT && (TARGET_FCFIDU || VECTOR_UNIT_VSX_P (DFmode))" + "") + +(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_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 " - " -{ - 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)); + "TARGET_FCFID && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT + && (TARGET_FCFIDS || TARGET_POWERPC64 || flag_unsafe_math_optimizations)" + " +{ + if (!TARGET_FCFIDS) + { + 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; + } +}") + +(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 @@ -6859,6 +7288,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 @@ -9141,73 +9603,9 @@ default: gcc_unreachable (); case 0: - /* We normally copy the low-numbered register first. However, if - the first register operand 0 is the same as the second register - of operand 1, we must copy in the opposite order. */ - if (REGNO (operands[0]) == REGNO (operands[1]) + 1) - return \"mr %L0,%L1\;mr %0,%1\"; - else - return \"mr %0,%1\;mr %L0,%L1\"; case 1: - if (rs6000_offsettable_memref_p (operands[1]) - || (GET_CODE (operands[1]) == MEM - && (GET_CODE (XEXP (operands[1], 0)) == LO_SUM - || GET_CODE (XEXP (operands[1], 0)) == PRE_INC - || GET_CODE (XEXP (operands[1], 0)) == PRE_DEC - || GET_CODE (XEXP (operands[1], 0)) == PRE_MODIFY))) - { - /* If the low-address word is used in the address, we must load - it last. Otherwise, load it first. Note that we cannot have - auto-increment in that case since the address register is - known to be dead. */ - if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1, - operands[1], 0)) - return \"{l|lwz} %L0,%L1\;{l|lwz} %0,%1\"; - else - return \"{l%U1%X1|lwz%U1%X1} %0,%1\;{l|lwz} %L0,%L1\"; - } - else - { - rtx addreg; - - addreg = find_addr_reg (XEXP (operands[1], 0)); - if (refers_to_regno_p (REGNO (operands[0]), - REGNO (operands[0]) + 1, - operands[1], 0)) - { - output_asm_insn (\"{cal|la} %0,4(%0)\", &addreg); - output_asm_insn (\"{l%X1|lwz%X1} %L0,%1\", operands); - output_asm_insn (\"{cal|la} %0,-4(%0)\", &addreg); - return \"{l%X1|lwz%X1} %0,%1\"; - } - else - { - output_asm_insn (\"{l%X1|lwz%X1} %0,%1\", operands); - output_asm_insn (\"{cal|la} %0,4(%0)\", &addreg); - output_asm_insn (\"{l%X1|lwz%X1} %L0,%1\", operands); - output_asm_insn (\"{cal|la} %0,-4(%0)\", &addreg); - return \"\"; - } - } case 2: - if (rs6000_offsettable_memref_p (operands[0]) - || (GET_CODE (operands[0]) == MEM - && (GET_CODE (XEXP (operands[0], 0)) == LO_SUM - || GET_CODE (XEXP (operands[0], 0)) == PRE_INC - || GET_CODE (XEXP (operands[0], 0)) == PRE_DEC - || GET_CODE (XEXP (operands[0], 0)) == PRE_MODIFY))) - return \"{st%U0%X0|stw%U0%X0} %1,%0\;{st|stw} %L1,%L0\"; - else - { - rtx addreg; - - addreg = find_addr_reg (XEXP (operands[0], 0)); - output_asm_insn (\"{st%X0|stw%X0} %1,%0\", operands); - output_asm_insn (\"{cal|la} %0,4(%0)\", &addreg); - output_asm_insn (\"{st%X0|stw%X0} %L1,%0\", operands); - output_asm_insn (\"{cal|la} %0,-4(%0)\", &addreg); - return \"\"; - } + return \"#\"; case 3: case 4: return \"xxlor %x0,%x1,%x1\"; @@ -9242,38 +9640,7 @@ || TARGET_SOFT_FLOAT || TARGET_E500_SINGLE) && (gpc_reg_operand (operands[0], DFmode) || gpc_reg_operand (operands[1], DFmode))" - "* -{ - switch (which_alternative) - { - default: - gcc_unreachable (); - case 0: - /* We normally copy the low-numbered register first. However, if - the first register operand 0 is the same as the second register of - operand 1, we must copy in the opposite order. */ - if (REGNO (operands[0]) == REGNO (operands[1]) + 1) - return \"mr %L0,%L1\;mr %0,%1\"; - else - return \"mr %0,%1\;mr %L0,%L1\"; - case 1: - /* If the low-address word is used in the address, we must load - it last. Otherwise, load it first. Note that we cannot have - auto-increment in that case since the address register is - known to be dead. */ - if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1, - operands[1], 0)) - return \"{l|lwz} %L0,%L1\;{l|lwz} %0,%1\"; - else - return \"{l%U1%X1|lwz%U1%X1} %0,%1\;{l|lwz} %L0,%L1\"; - case 2: - return \"{st%U0%X0|stw%U0%X0} %1,%0\;{st|stw} %L1,%L0\"; - case 3: - case 4: - case 5: - return \"#\"; - } -}" + "#" [(set_attr "type" "two,load,store,*,*,*") (set_attr "length" "8,8,8,8,12,16")]) @@ -9603,7 +9970,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; @@ -9685,8 +10052,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))" @@ -9697,13 +10064,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))] " @@ -9722,8 +10091,8 @@ }") (define_split - [(set (match_operand:DI 0 "rs6000_nonimmediate_operand" "") - (match_operand:DI 1 "input_operand" ""))] + [(set (match_operand:DIFD 0 "rs6000_nonimmediate_operand" "") + (match_operand:DIFD 1 "input_operand" ""))] "reload_completed && !TARGET_POWERPC64 && gpr_or_gpr_p (operands[0], operands[1])" [(pc)] @@ -9755,8 +10124,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))" @@ -9773,9 +10142,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 "" @@ -11065,7 +11435,12 @@ UNSPEC_TLSGD) (clobber (reg:SI LR_REGNO))] "HAVE_AS_TLS && DEFAULT_ABI == ABI_AIX" - "addi %0,%1,%2@got@tlsgd\;bl %z3\;%." +{ + if (TARGET_CMODEL != CMODEL_SMALL) + return "addis %0,%1,%2@got@tlsgd@ha\;addi %0,%0,%2@got@tlsgd@l\;bl %z3\;%."; + else + return "addi %0,%1,%2@got@tlsgd\;bl %z3\;%."; +} "&& TARGET_TLS_MARKERS" [(set (match_dup 0) (unspec:TLSmode [(match_dup 1) @@ -11078,7 +11453,10 @@ (clobber (reg:SI LR_REGNO))])] "" [(set_attr "type" "two") - (set_attr "length" "12")]) + (set (attr "length") + (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL")) + (const_int 16) + (const_int 12)))]) (define_insn_and_split "tls_gd_sysv<TLSmode:tls_sysv_suffix>" [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") @@ -11114,13 +11492,47 @@ [(set_attr "type" "two") (set_attr "length" "8")]) -(define_insn "*tls_gd<TLSmode:tls_abi_suffix>" +(define_insn_and_split "*tls_gd<TLSmode:tls_abi_suffix>" [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b") (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] UNSPEC_TLSGD))] "HAVE_AS_TLS && TARGET_TLS_MARKERS" "addi %0,%1,%2@got@tlsgd" + "&& TARGET_CMODEL != CMODEL_SMALL" + [(set (match_dup 3) + (plus:TLSmode (match_dup 1) + (high:TLSmode + (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGD)))) + (set (match_dup 0) + (lo_sum:TLSmode (match_dup 3) + (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGD)))] + " +{ + operands[3] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode); +}" + [(set (attr "length") + (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL")) + (const_int 8) + (const_int 4)))]) + +(define_insn "*tls_gd_high<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") + (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b") + (high:TLSmode + (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSGD))))] + "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL" + "addis %0,%1,%2@got@tlsgd@ha" + [(set_attr "length" "4")]) + +(define_insn "*tls_gd_low<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") + (lo_sum:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b") + (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSGD)))] + "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL" + "addi %0,%1,%2@got@tlsgd@l" [(set_attr "length" "4")]) (define_insn "*tls_gd_call_aix<TLSmode:tls_abi_suffix>" @@ -11163,7 +11575,12 @@ UNSPEC_TLSLD) (clobber (reg:SI LR_REGNO))] "HAVE_AS_TLS && DEFAULT_ABI == ABI_AIX" - "addi %0,%1,%&@got@tlsld\;bl %z2\;%." +{ + if (TARGET_CMODEL != CMODEL_SMALL) + return "addis %0,%1,%&@got@tlsld@ha\;addi %0,%0,%&@got@tlsld@l\;bl %z2\;%."; + else + return "addi %0,%1,%&@got@tlsld\;bl %z2\;%."; +} "&& TARGET_TLS_MARKERS" [(set (match_dup 0) (unspec:TLSmode [(match_dup 1)] @@ -11174,7 +11591,11 @@ (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD) (clobber (reg:SI LR_REGNO))])] "" - [(set_attr "length" "12")]) + [(set_attr "type" "two") + (set (attr "length") + (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL")) + (const_int 16) + (const_int 12)))]) (define_insn_and_split "tls_ld_sysv<TLSmode:tls_sysv_suffix>" [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") @@ -11207,12 +11628,44 @@ "" [(set_attr "length" "8")]) -(define_insn "*tls_ld<TLSmode:tls_abi_suffix>" +(define_insn_and_split "*tls_ld<TLSmode:tls_abi_suffix>" [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")] UNSPEC_TLSLD))] "HAVE_AS_TLS && TARGET_TLS_MARKERS" "addi %0,%1,%&@got@tlsld" + "&& TARGET_CMODEL != CMODEL_SMALL" + [(set (match_dup 2) + (plus:TLSmode (match_dup 1) + (high:TLSmode + (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)))) + (set (match_dup 0) + (lo_sum:TLSmode (match_dup 2) + (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)))] + " +{ + operands[2] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode); +}" + [(set (attr "length") + (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL")) + (const_int 8) + (const_int 4)))]) + +(define_insn "*tls_ld_high<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") + (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b") + (high:TLSmode + (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD))))] + "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL" + "addis %0,%1,%&@got@tlsld@ha" + [(set_attr "length" "4")]) + +(define_insn "*tls_ld_low<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") + (lo_sum:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b") + (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)))] + "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL" + "addi %0,%1,%&@got@tlsld@l" [(set_attr "length" "4")]) (define_insn "*tls_ld_call_aix<TLSmode:tls_abi_suffix>" @@ -11269,13 +11722,48 @@ "HAVE_AS_TLS" "addi %0,%1,%2@dtprel@l") -(define_insn "tls_got_dtprel_<TLSmode:tls_abi_suffix>" +(define_insn_and_split "tls_got_dtprel_<TLSmode:tls_abi_suffix>" [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r") (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b") (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] UNSPEC_TLSGOTDTPREL))] "HAVE_AS_TLS" - "l<TLSmode:tls_insn_suffix> %0,%2@got@dtprel(%1)") + "l<TLSmode:tls_insn_suffix> %0,%2@got@dtprel(%1)" + "&& TARGET_CMODEL != CMODEL_SMALL" + [(set (match_dup 3) + (plus:TLSmode (match_dup 1) + (high:TLSmode + (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTDTPREL)))) + (set (match_dup 0) + (lo_sum:TLSmode (match_dup 3) + (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTDTPREL)))] + " +{ + operands[3] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode); +}" + [(set (attr "length") + (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL")) + (const_int 8) + (const_int 4)))]) + +(define_insn "*tls_got_dtprel_high<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") + (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b") + (high:TLSmode + (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSGOTDTPREL))))] + "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL" + "addis %0,%1,%2@got@dtprel@ha" + [(set_attr "length" "4")]) + +(define_insn "*tls_got_dtprel_low<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r") + (lo_sum:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b") + (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSGOTDTPREL)))] + "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL" + "l<TLSmode:tls_insn_suffix> %0,%2@got@dtprel@l(%1)" + [(set_attr "length" "4")]) (define_insn "tls_tprel_<TLSmode:tls_abi_suffix>" [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r") @@ -11304,13 +11792,48 @@ ;; "b" output constraint here and on tls_tls input to support linker tls ;; optimization. The linker may edit the instructions emitted by a ;; tls_got_tprel/tls_tls pair to addis,addi. -(define_insn "tls_got_tprel_<TLSmode:tls_abi_suffix>" +(define_insn_and_split "tls_got_tprel_<TLSmode:tls_abi_suffix>" [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b") (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] UNSPEC_TLSGOTTPREL))] "HAVE_AS_TLS" - "l<TLSmode:tls_insn_suffix> %0,%2@got@tprel(%1)") + "l<TLSmode:tls_insn_suffix> %0,%2@got@tprel(%1)" + "&& TARGET_CMODEL != CMODEL_SMALL" + [(set (match_dup 3) + (plus:TLSmode (match_dup 1) + (high:TLSmode + (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTTPREL)))) + (set (match_dup 0) + (lo_sum:TLSmode (match_dup 3) + (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTTPREL)))] + " +{ + operands[3] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode); +}" + [(set (attr "length") + (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL")) + (const_int 8) + (const_int 4)))]) + +(define_insn "*tls_got_tprel_high<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") + (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b") + (high:TLSmode + (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSGOTTPREL))))] + "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL" + "addis %0,%1,%2@got@tprel@ha" + [(set_attr "length" "4")]) + +(define_insn "*tls_got_tprel_low<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r") + (lo_sum:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b") + (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSGOTTPREL)))] + "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL" + "l<TLSmode:tls_insn_suffix> %0,%2@got@tprel@l(%1)" + [(set_attr "length" "4")]) (define_insn "tls_tls_<TLSmode:tls_abi_suffix>" [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r") @@ -11319,7 +11842,6 @@ UNSPEC_TLSTLS))] "HAVE_AS_TLS" "add %0,%1,%2@tls") - ;; Next come insns related to the calling sequence. ;; @@ -11521,10 +12043,12 @@ (define_insn "load_toc_v4_PIC_1b" [(set (reg:SI LR_REGNO) - (unspec:SI [(match_operand:SI 0 "immediate_operand" "s")] - UNSPEC_TOCPTR))] + (unspec:SI [(match_operand:SI 0 "immediate_operand" "s") + (label_ref (match_operand 1 "" ""))] + UNSPEC_TOCPTR)) + (match_dup 1)] "TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2" - "bcl 20,31,$+8\\n\\t.long %0-$" + "bcl 20,31,$+8\;.long %0-$" [(set_attr "type" "branch") (set_attr "length" "8")]) @@ -11538,8 +12062,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")))))] @@ -11607,6 +12131,21 @@ "@ {cal|la} %0,%2@l(%1) {ai|addic} %0,%1,%K2") + +;; Largetoc support +(define_insn "largetoc_high" + [(set (match_operand:DI 0 "gpc_reg_operand" "=b") + (plus:DI (match_operand:DI 1 "gpc_reg_operand" "b") + (high:DI (match_operand:DI 2 "" ""))))] + "TARGET_ELF && TARGET_CMODEL != CMODEL_SMALL" + "{cau|addis} %0,%1,%2@ha") + +(define_insn "largetoc_low" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (lo_sum:DI (match_operand:DI 1 "gpc_reg_operand" "b") + (match_operand:DI 2 "" "")))] + "TARGET_ELF && TARGET_CMODEL != CMODEL_SMALL" + "{cal %0,%2@l(%1)|addi %0,%1,%2@l}") ;; A function pointer under AIX is a pointer to a data area whose first word ;; contains the actual address of the function, whose second word contains a @@ -12587,6 +13126,15 @@ "{st%U0%X0|stw%U0%X0} 0,%0" [(set_attr "type" "store") (set_attr "length" "4")]) + +(define_insn "probe_stack_range<P:mode>" + [(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. @@ -12910,26 +13458,27 @@ (clobber (match_scratch:DF 7 "=d")) (clobber (match_scratch:DF 8 "=d")) (clobber (match_scratch:DF 9 "=d")) - (clobber (match_scratch:DF 10 "=d"))] + (clobber (match_scratch:DF 10 "=d")) + (clobber (match_scratch:GPR 11 "=b"))] "!TARGET_IEEEQUAD && TARGET_XL_COMPAT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LONG_DOUBLE_128" "#" "&& reload_completed" - [(set (match_dup 3) (match_dup 13)) - (set (match_dup 4) (match_dup 14)) + [(set (match_dup 3) (match_dup 14)) + (set (match_dup 4) (match_dup 15)) (set (match_dup 9) (abs:DF (match_dup 5))) (set (match_dup 0) (compare:CCFP (match_dup 9) (match_dup 3))) (set (pc) (if_then_else (ne (match_dup 0) (const_int 0)) - (label_ref (match_dup 11)) + (label_ref (match_dup 12)) (pc))) (set (match_dup 0) (compare:CCFP (match_dup 5) (match_dup 7))) - (set (pc) (label_ref (match_dup 12))) - (match_dup 11) + (set (pc) (label_ref (match_dup 13))) + (match_dup 12) (set (match_dup 10) (minus:DF (match_dup 5) (match_dup 7))) (set (match_dup 9) (minus:DF (match_dup 6) (match_dup 8))) (set (match_dup 9) (plus:DF (match_dup 10) (match_dup 9))) - (set (match_dup 0) (compare:CCFP (match_dup 7) (match_dup 4))) - (match_dup 12)] + (set (match_dup 0) (compare:CCFP (match_dup 9) (match_dup 4))) + (match_dup 13)] { REAL_VALUE_TYPE rv; const int lo_word = FLOAT_WORDS_BIG_ENDIAN ? GET_MODE_SIZE (DFmode) : 0; @@ -12939,22 +13488,23 @@ operands[6] = simplify_gen_subreg (DFmode, operands[1], TFmode, lo_word); operands[7] = simplify_gen_subreg (DFmode, operands[2], TFmode, hi_word); operands[8] = simplify_gen_subreg (DFmode, operands[2], TFmode, lo_word); - operands[11] = gen_label_rtx (); operands[12] = gen_label_rtx (); + operands[13] = gen_label_rtx (); real_inf (&rv); - operands[13] = force_const_mem (DFmode, + operands[14] = force_const_mem (DFmode, CONST_DOUBLE_FROM_REAL_VALUE (rv, DFmode)); - operands[14] = force_const_mem (DFmode, + operands[15] = force_const_mem (DFmode, CONST_DOUBLE_FROM_REAL_VALUE (dconst0, DFmode)); if (TARGET_TOC) { - operands[13] = gen_const_mem (DFmode, - create_TOC_reference (XEXP (operands[13], 0))); - operands[14] = gen_const_mem (DFmode, - create_TOC_reference (XEXP (operands[14], 0))); - set_mem_alias_set (operands[13], get_TOC_alias_set ()); + rtx tocref; + tocref = create_TOC_reference (XEXP (operands[14], 0), operands[11]); + operands[14] = gen_const_mem (DFmode, tocref); + tocref = create_TOC_reference (XEXP (operands[15], 0), operands[11]); + operands[15] = gen_const_mem (DFmode, tocref); set_mem_alias_set (operands[14], get_TOC_alias_set ()); + set_mem_alias_set (operands[15], get_TOC_alias_set ()); } }) @@ -15400,6 +15950,15 @@ "" [(set_attr "length" "0")]) +; Like stack_tie, but depend on both fp and sp based memory. +(define_insn "frame_tie" + [(set (match_operand:BLK 0 "memory_operand" "+m") + (unspec:BLK [(match_dup 0) + (match_operand:BLK 1 "memory_operand" "m")] UNSPEC_TIE))] + "" + "" + [(set_attr "length" "0")]) + (define_expand "epilogue" [(use (const_int 0))] @@ -15579,6 +16138,73 @@ [(set_attr "type" "integer")]) +;; Builtin fma support. Handle +;; Note that the conditions for expansion are in the FMA_F iterator. + +(define_expand "fma<mode>4" + [(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 "fms<mode>4" + [(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>mode)" + "") + +;; If signed zeros are ignored, -(a * b - c) = -a * b + c. +(define_expand "fnma<mode>4" + [(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>mode)" + "") + +;; If signed zeros are ignored, -(a * b + c) = -a * b - c. +(define_expand "fnms<mode>4" + [(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>mode) && !VECTOR_UNIT_ALTIVEC_P (<MODE>mode)" + "") + +; Not an official optab name, but used from builtins. +(define_expand "nfma<mode>4" + [(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>mode)" + "") + +; Not an official optab name, but used from builtins. +(define_expand "nfms<mode>4" + [(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")