;; 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)
;; 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)
- (UNSPEC_FCTIW 54)
- (UNSPEC_FCTID 55)
- (UNSPEC_LFIWAX 56)
- (UNSPEC_LFIWZX 57)
- (UNSPEC_FCTIWUZ 58)
+(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_PROBE_STACK_RANGE 3) ; probe range of stack addresses
- (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
])
+
\f
;; Define an insn type attribute. This is used in function unit delay
;; computations.
(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])
(define_expand "rsqrt<mode>2"
[(match_operand:RECIPF 0 "gpc_reg_operand" "")
(match_operand:RECIPF 1 "gpc_reg_operand" "")]
- "RS6000_RECIP_HAVE_RSQRT_P (<MODE>mode)"
+ "RS6000_RECIP_HAVE_RSQRTE_P (<MODE>mode)"
{
rs6000_emit_swrsqrt (operands[0], operands[1]);
DONE;
[(set_attr "type" "fp")])
; builtin fmaf support
-; If the user explicitly uses the fma builtin, don't convert this to
-; (plus (mult op1 op2) op3)
-(define_expand "fmasf4"
- [(set (match_operand:SF 0 "gpc_reg_operand" "")
- (fma:SF (match_operand:SF 1 "gpc_reg_operand" "")
- (match_operand:SF 2 "gpc_reg_operand" "")
- (match_operand:SF 3 "gpc_reg_operand" "")))]
- "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT"
- "")
-
-(define_insn "fmasf4_fpr"
+(define_insn "*fmasf4_fpr"
[(set (match_operand:SF 0 "gpc_reg_operand" "=f")
(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\");
-}"
+ 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")])
(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\");
-}"
+ 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 "*fnmasf4_fpr"
+(define_insn "*nfmasf4_fpr"
[(set (match_operand:SF 0 "gpc_reg_operand" "=f")
(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\");
-}"
+ 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 "*fnmssf4_fpr"
+(define_insn "*nfmssf4_fpr"
[(set (match_operand:SF 0 "gpc_reg_operand" "=f")
(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")])
-
-; Fused multiply/add ops created by the combiner
-(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"
- [(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"
- [(set_attr "type" "fp")
- (set_attr "fp_type" "fp_maddsub_s")])
-
-(define_insn "*fnmaddsf4_powerpc_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_SINGLE_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD
- && ! HONOR_SIGNED_ZEROS (SFmode)"
- "fnmadds %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"
- [(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"
- [(set_attr "type" "fp")
- (set_attr "fp_type" "fp_maddsub_s")])
-
-(define_insn "*fnmsubsf4_powerpc_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
- && TARGET_SINGLE_FLOAT && ! HONOR_SIGNED_ZEROS (SFmode)"
- "fnmsubs %0,%1,%2,%3"
+ 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" "")))]
[(set_attr "type" "fp")])
; builtin fma support
-; If the user explicitly uses the fma builtin, don't convert this to
-; (plus (mult op1 op2) op3)
-(define_expand "fmadf4"
- [(set (match_operand:DF 0 "gpc_reg_operand" "")
- (fma:DF (match_operand:DF 1 "gpc_reg_operand" "")
- (match_operand:DF 2 "gpc_reg_operand" "")
- (match_operand:DF 3 "gpc_reg_operand" "")))]
- "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT"
- "")
-
-(define_insn "fmadf4_fpr"
+(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")
[(set_attr "type" "fp")
(set_attr "fp_type" "fp_maddsub_s")])
-(define_insn "*fnmadf4_fpr"
+(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")
[(set_attr "type" "fp")
(set_attr "fp_type" "fp_maddsub_s")])
-(define_insn "*fnmsdf4_fpr"
+(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")
[(set_attr "type" "fp")
(set_attr "fp_type" "fp_maddsub_s")])
-; Fused multiply/add ops created by the combiner
-(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
- && 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
- && 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
- && 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
- && 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_expand "sqrtdf2"
[(set (match_operand:DF 0 "gpc_reg_operand" "")
(sqrt:DF (match_operand:DF 1 "gpc_reg_operand" "")))]
"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" "=<rreg2>,<rreg2>")
- (float:SFDF (match_operand:SI 1 "nonimmediate_operand" "Z,r")))
- (clobber (match_operand:SI 2 "indexed_or_indirect_operand" "=Z,Z"))
- (clobber (match_operand:DI 3 "gpc_reg_operand" "=d,d"))]
+ [(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>"
+ && <SI_CONVERT_FP> && can_create_pseudo_p ()"
"#"
- "MEM_P (operands[1]) || reload_completed"
+ ""
[(pc)]
"
{
- if (MEM_P (operands[1]))
- {
- operands[1] = rs6000_address_for_fpconvert (operands[1]);
- emit_insn (gen_lfiwax (operands[3], operands[1]));
- }
+ 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
{
- emit_move_insn (operands[2], operands[1]);
- emit_insn (gen_lfiwax (operands[3], operands[2]));
+ 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 (operands[0], operands[3]));
+ emit_insn (gen_floatdi<mode>2 (dest, tmp));
DONE;
}"
- [(set_attr "length" "8,12")])
+ [(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" "=<rreg2>")
- (float:SFDF (match_operand:SI 1 "memory_operand" "Z")))
- (clobber (match_scratch:DI 2 "=d"))]
- "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWAX
- && <SI_CONVERT_FP>"
- "#"
- "&& reload_completed"
- [(pc)]
- "
-{
- emit_insn (gen_lfiwax (operands[2], operands[1]));
- emit_insn (gen_floatdi<mode>2 (operands[0], operands[2]));
- DONE;
-}"
- [(set_attr "length" "8")])
-
-(define_insn_and_split "floatsi<mode>2_lfiwax_mem2"
- [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>")
+ [(set (match_operand:SFDF 0 "gpc_reg_operand" "=d,<rreg2>")
(float:SFDF
(sign_extend:DI
- (match_operand:SI 1 "memory_operand" "Z"))))
- (clobber (match_scratch:DI 2 "=d"))]
+ (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>"
"#"
- "&& reload_completed"
+ ""
[(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 "length" "8")
+ (set_attr "type" "fpload")])
(define_insn "lfiwzx"
[(set (match_operand:DI 0 "gpc_reg_operand" "=d")
[(set_attr "type" "fpload")])
(define_insn_and_split "floatunssi<mode>2_lfiwzx"
- [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>,<rreg2>")
- (unsigned_float:SFDF (match_operand:SI 1 "gpc_reg_operand" "Z,r")))
- (clobber (match_operand:SI 2 "indexed_or_indirect_operand" "=Z,Z"))
- (clobber (match_operand:DI 3 "gpc_reg_operand" "=d,d"))]
+ [(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>"
"#"
- "MEM_P (operands[1]) || reload_completed"
+ ""
[(pc)]
"
{
- if (MEM_P (operands[1]))
- {
- operands[1] = rs6000_address_for_fpconvert (operands[1]);
- emit_insn (gen_lfiwzx (operands[3], operands[1]));
- }
+ 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
{
- emit_move_insn (operands[2], operands[1]);
- emit_insn (gen_lfiwzx (operands[3], operands[2]));
+ 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 (operands[0], operands[3]));
+ emit_insn (gen_floatdi<mode>2 (dest, tmp));
DONE;
}"
- [(set_attr "length" "8,12")])
+ [(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" "=<rreg2>")
- (unsigned_float:SFDF (match_operand:SI 1 "memory_operand" "Z")))
- (clobber (match_scratch:DI 2 "=d"))]
- "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWZX
- && <SI_CONVERT_FP>"
- "#"
- "&& reload_completed"
- [(pc)]
- "
-{
- emit_insn (gen_lfiwzx (operands[2], operands[1]));
- emit_insn (gen_floatdi<mode>2 (operands[0], operands[2]));
- DONE;
-}"
- [(set_attr "length" "8")])
-
-(define_insn_and_split "floatunssi<mode>2_lfiwzx_mem2"
- [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>")
+ [(set (match_operand:SFDF 0 "gpc_reg_operand" "=d,<rreg2>")
(unsigned_float:SFDF
(zero_extend:DI
- (match_operand:SI 1 "memory_operand" "Z"))))
- (clobber (match_scratch:DI 2 "=d"))]
+ (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>"
"#"
- "&& reload_completed"
+ ""
[(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 "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
}
else if (TARGET_LFIWAX && TARGET_FCFID)
{
- rs6000_expand_convert_si_to_sfdf (operands[0], operands[1], false);
+ emit_insn (gen_floatsidf2_lfiwax (operands[0], operands[1]));
DONE;
}
else if (TARGET_FCFID)
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
}
else if (TARGET_LFIWZX && TARGET_FCFIDUS)
{
- rs6000_expand_convert_si_to_sfdf (operands[0], operands[1], true);
+ emit_insn (gen_floatunssisf2_lfiwzx (operands[0], operands[1]));
DONE;
}
else
}
else if (TARGET_LFIWZX && TARGET_FCFID)
{
- rs6000_expand_convert_si_to_sfdf (operands[0], operands[1], true);
- DONE;
+ emit_insn (gen_floatunssidf2_lfiwzx (operands[0], operands[1]));
+ DONE;
}
else if (TARGET_FCFID)
{
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_trunc<mode>si2"
[(set (match_operand:SI 0 "gpc_reg_operand" "")
rtx tmp, stack;
if (TARGET_STFIWX)
- {
- tmp = gen_reg_rtx (DImode);
- stack = rs6000_allocate_stack_temp (SImode, false, true);
- emit_insn (gen_fix_trunc<mode>si2_stfiwx (operands[0], operands[1],
- tmp, stack));
- }
+ emit_insn (gen_fix_trunc<mode>si2_stfiwx (operands[0], operands[1]));
else
{
tmp = gen_reg_rtx (DImode);
}
}")
+; 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 "gpc_reg_operand" "=r")
- (fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>")))
- (clobber (match_operand:DI 2 "gpc_reg_operand" "=d"))
- (clobber (match_operand:SI 3 "indexed_or_indirect_operand" "=Z"))]
+ [(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"
+ && TARGET_STFIWX && can_create_pseudo_p ()"
"#"
- "&& reload_completed"
+ ""
[(pc)]
- "
{
- emit_insn (gen_fctiwz_<mode> (operands[2], operands[1]));
- if (TARGET_MFPGPR && TARGET_POWERPC64 && REG_P (operands[0])
- && INT_REGNO_P (REGNO (operands[0])))
+ 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))
{
- rtx reg = gen_lowpart (DImode, operands[0]);
- emit_move_insn (reg, operands[2]);
+ 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
{
- emit_insn (gen_stfiwx (operands[3], operands[2]));
- emit_move_insn (operands[0], operands[3]);
+ rtx stack = rs6000_allocate_stack_temp (SImode, false, true);
+ emit_insn (gen_stfiwx (stack, tmp));
+ emit_move_insn (dest, stack);
+ DONE;
}
- DONE;
-}"
- [(set_attr "length" "12")])
-
-(define_insn_and_split "*fix_trunc<mode>si2_mem"
- [(set (match_operand:SI 0 "memory_operand" "=Z")
- (fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>")))
- (clobber (match_scratch:DI 2 "=d"))]
- "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
- && (<MODE>mode != SFmode || TARGET_SINGLE_FLOAT)
- && TARGET_STFIWX"
- "#"
- "&& reload_completed"
- [(pc)]
- "
-{
- emit_insn (gen_fctiwz_<mode> (operands[2], operands[1]));
- emit_insn (gen_stfiwx (operands[0], operands[2]));
- DONE;
-}"
- [(set_attr "length" "8")])
+}
+ [(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")
- (fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "<rreg>")))
- (clobber (match_operand:DI 2 "gpc_reg_operand" "=d"))
- (clobber (match_operand:DI 3 "offsettable_mem_operand" "=o"))]
+ [(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"
"#"
emit_move_insn (operands[0], lowword);
DONE;
}"
- [(set_attr "length" "16")])
+ [(set_attr "length" "16")
+ (set_attr "type" "fp")])
(define_expand "fix_trunc<mode>di2"
[(set (match_operand:DI 0 "gpc_reg_operand" "")
{
if (!<E500_CONVERT>)
{
- rtx tmp = gen_reg_rtx (DImode);
- rtx stack = rs6000_allocate_stack_temp (SImode, false, true);
- emit_insn (gen_fixuns_trunc<mode>si2_stfiwx (operands[0], operands[1],
- tmp, stack));
+ 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 "gpc_reg_operand" "=r")
- (unsigned_fix:SI
- (match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>")))
- (clobber (match_operand:DI 2 "gpc_reg_operand" "=d"))
- (clobber (match_operand:SI 3 "indexed_or_indirect_operand" "=Z"))]
+ [(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"
+ && TARGET_STFIWX && can_create_pseudo_p ()"
"#"
- "&& reload_completed"
+ ""
[(pc)]
- "
{
- emit_insn (gen_fctiwuz_<mode> (operands[2], operands[1]));
- if (TARGET_MFPGPR && TARGET_POWERPC64 && REG_P (operands[0])
- && INT_REGNO_P (REGNO (operands[0])))
+ rtx 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))
{
- rtx reg = gen_lowpart (DImode, operands[0]);
- emit_move_insn (reg, operands[2]);
+ 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
{
- emit_insn (gen_stfiwx (operands[3], operands[2]));
- emit_move_insn (operands[0], operands[3]);
+ rtx stack = rs6000_allocate_stack_temp (SImode, false, true);
+ emit_insn (gen_stfiwx (stack, tmp));
+ emit_move_insn (dest, stack);
+ DONE;
}
- DONE;
-}"
- [(set_attr "length" "12")])
-
-(define_insn_and_split "*fixuns_trunc<mode>si2_mem"
- [(set (match_operand:SI 0 "memory_operand" "=Z")
- (unsigned_fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>")))
- (clobber (match_scratch:DI 2 "=d"))]
- "TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT> && TARGET_FCTIWUZ
- && TARGET_STFIWX"
- "#"
- "&& reload_completed"
- [(pc)]
- "
-{
- emit_insn (gen_fctiwuz_<mode> (operands[2], operands[1]));
- emit_insn (gen_stfiwx (operands[0], operands[2]));
- DONE;
-}"
- [(set_attr "length" "8")])
+}
+ [(set_attr "length" "12")
+ (set_attr "type" "fp")])
(define_expand "fixuns_trunc<mode>di2"
[(set (match_operand:DI 0 "register_operand" "")
(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_POPCNTB
+ "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")])
+;; 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")
}
else if (TARGET_FCFIDS && TARGET_LFIWAX)
{
- rs6000_expand_convert_si_to_sfdf (operands[0], operands[1], false);
+ 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
[(set (match_dup 2) (match_dup 1))
(set (match_dup 0) (float:DF (match_dup 2)))]
""
- [(set_attr "length" "8")])
+ [(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_FCFIDU || VECTOR_UNIT_VSX_P (DFmode)"
+ "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_FCFIDU && !VECTOR_UNIT_VSX_P (DFmode)"
+ "TARGET_HARD_FLOAT && TARGET_FCFIDU && !VECTOR_UNIT_VSX_P (DFmode)"
"fcfidu %0,%1"
[(set_attr "type" "fp")
(set_attr "length" "4")])
[(set (match_operand:DF 0 "gpc_reg_operand" "=d")
(unsigned_float:DF (match_operand:DI 1 "memory_operand" "m")))
(clobber (match_scratch:DI 2 "=d"))]
- "TARGET_FCFIDU || VECTOR_UNIT_VSX_P (DFmode)"
+ "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 "length" "8")
+ (set_attr "type" "fpload")])
(define_expand "floatdisf2"
[(set (match_operand:SF 0 "gpc_reg_operand" "")
;; 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")))
(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
emit_insn (gen_floatunsdisf2_fcfidus (operands[0], operands[2]));
DONE;
}"
- [(set_attr "length" "8")])
+ [(set_attr "length" "8")
+ (set_attr "type" "fpload")])
\f
;; Define the DImode operations that can be done in a small number
;; of instructions. The & constraints are to prevent the register
[(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"
; 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))"
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))]
"
li %0,%1
lis %0,%v1
#
- {cal|la} %0,%a1
+ la %0,%a1
fmr %0,%1
lfd%U1%X1 %0,%1
stfd%U0%X0 %1,%0
(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))"
li %0,%1
lis %0,%v1
#
- {cal|la} %0,%a1
+ la %0,%a1
fmr %0,%1
lfd%U1%X1 %0,%1
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 ""
"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))))
+ (const:TLSmode
+ (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)))]
(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))))]
+ (const:TLSmode
+ (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")])
"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))))
+ (const:TLSmode
+ (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)))]
(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))))]
+ (const:TLSmode
+ (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")])
"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))))
+ (const:TLSmode
+ (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)))]
(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))))]
+ (const:TLSmode
+ (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")])
"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))))
+ (const:TLSmode
+ (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)))]
(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))))]
+ (const:TLSmode
+ (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")])
;; 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 "" ""))))]
+ (const:DI
+ (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")
[(set_attr "type" "branch")
(set_attr "length" "4,8")])
-(define_insn "*sibcall_nonlocal_aix32"
- [(call (mem:SI (match_operand:SI 0 "symbol_ref_operand" "s"))
- (match_operand 1 "" "g"))
- (use (match_operand:SI 2 "immediate_operand" "O"))
- (use (reg:SI LR_REGNO))
- (return)]
- "TARGET_32BIT
- && DEFAULT_ABI == ABI_AIX
- && (INTVAL (operands[2]) & CALL_LONG) == 0"
- "b %z0"
- [(set_attr "type" "branch")
- (set_attr "length" "4")])
-
-(define_insn "*sibcall_nonlocal_aix64"
- [(call (mem:SI (match_operand:DI 0 "symbol_ref_operand" "s"))
- (match_operand 1 "" "g"))
- (use (match_operand:SI 2 "immediate_operand" "O"))
+(define_insn "*sibcall_nonlocal_aix<mode>"
+ [(call (mem:SI (match_operand:P 0 "call_operand" "s,c"))
+ (match_operand 1 "" "g,g"))
+ (use (match_operand:SI 2 "immediate_operand" "O,O"))
(use (reg:SI LR_REGNO))
(return)]
- "TARGET_64BIT
- && DEFAULT_ABI == ABI_AIX
+ "DEFAULT_ABI == ABI_AIX
&& (INTVAL (operands[2]) & CALL_LONG) == 0"
- "b %z0"
- [(set_attr "type" "branch")
- (set_attr "length" "4")])
-
-(define_insn "*sibcall_value_nonlocal_aix32"
- [(set (match_operand 0 "" "")
- (call (mem:SI (match_operand:SI 1 "symbol_ref_operand" "s"))
- (match_operand 2 "" "g")))
- (use (match_operand:SI 3 "immediate_operand" "O"))
- (use (reg:SI LR_REGNO))
- (return)]
- "TARGET_32BIT
- && DEFAULT_ABI == ABI_AIX
- && (INTVAL (operands[3]) & CALL_LONG) == 0"
- "b %z1"
+ "@
+ b %z0
+ b%T0"
[(set_attr "type" "branch")
(set_attr "length" "4")])
-(define_insn "*sibcall_value_nonlocal_aix64"
+(define_insn "*sibcall_value_nonlocal_aix<mode>"
[(set (match_operand 0 "" "")
- (call (mem:SI (match_operand:DI 1 "symbol_ref_operand" "s"))
- (match_operand 2 "" "g")))
- (use (match_operand:SI 3 "immediate_operand" "O"))
+ (call (mem:SI (match_operand:P 1 "call_operand" "s,c"))
+ (match_operand 2 "" "g,g")))
+ (use (match_operand:SI 3 "immediate_operand" "O,O"))
(use (reg:SI LR_REGNO))
(return)]
- "TARGET_64BIT
- && DEFAULT_ABI == ABI_AIX
+ "DEFAULT_ABI == ABI_AIX
&& (INTVAL (operands[3]) & CALL_LONG) == 0"
- "b %z1"
+ "@
+ b %z1
+ b%T1"
[(set_attr "type" "branch")
(set_attr "length" "4")])
(define_insn "*sibcall_nonlocal_sysv<mode>"
- [(call (mem:SI (match_operand:P 0 "symbol_ref_operand" "s,s"))
+ [(call (mem:SI (match_operand:P 0 "call_operand" "s,s,c,c"))
(match_operand 1 "" ""))
- (use (match_operand 2 "immediate_operand" "O,n"))
+ (use (match_operand 2 "immediate_operand" "O,n,O,n"))
(use (reg:SI LR_REGNO))
(return)]
"(DEFAULT_ABI == ABI_DARWIN
- || DEFAULT_ABI == ABI_V4)
+ || DEFAULT_ABI == ABI_V4)
&& (INTVAL (operands[2]) & CALL_LONG) == 0"
"*
{
else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
output_asm_insn (\"creqv 6,6,6\", operands);
- if (DEFAULT_ABI == ABI_V4 && flag_pic)
+ if (which_alternative >= 2)
+ return \"b%T0\";
+ else if (DEFAULT_ABI == ABI_V4 && flag_pic)
{
gcc_assert (!TARGET_SECURE_PLT);
return \"b %z0@plt\";
else
return \"b %z0\";
}"
- [(set_attr "type" "branch,branch")
- (set_attr "length" "4,8")])
+ [(set_attr "type" "branch")
+ (set_attr "length" "4,8,4,8")])
(define_expand "sibcall_value"
[(parallel [(set (match_operand 0 "register_operand" "")
(define_insn "*sibcall_value_nonlocal_sysv<mode>"
[(set (match_operand 0 "" "")
- (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s,s"))
+ (call (mem:SI (match_operand:P 1 "call_operand" "s,s,c,c"))
(match_operand 2 "" "")))
- (use (match_operand:SI 3 "immediate_operand" "O,n"))
+ (use (match_operand:SI 3 "immediate_operand" "O,n,O,n"))
(use (reg:SI LR_REGNO))
(return)]
"(DEFAULT_ABI == ABI_DARWIN
- || DEFAULT_ABI == ABI_V4)
+ || DEFAULT_ABI == ABI_V4)
&& (INTVAL (operands[3]) & CALL_LONG) == 0"
"*
{
- if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS)
+ if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
output_asm_insn (\"crxor 6,6,6\", operands);
- else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
+ else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
output_asm_insn (\"creqv 6,6,6\", operands);
- if (DEFAULT_ABI == ABI_V4 && flag_pic)
+ if (which_alternative >= 2)
+ return \"b%T1\";
+ else if (DEFAULT_ABI == ABI_V4 && flag_pic)
{
gcc_assert (!TARGET_SECURE_PLT);
return \"b %z1@plt\";
else
return \"b %z1\";
}"
- [(set_attr "type" "branch,branch")
- (set_attr "length" "4,8")])
+ [(set_attr "type" "branch")
+ (set_attr "length" "4,8,4,8")])
(define_expand "sibcall_epilogue"
[(use (const_int 0))]
"{stm|stmw} %2,%1"
[(set_attr "type" "store_ux")])
-(define_insn "*save_gpregs_<mode>"
+; The following comment applies to:
+; save_gpregs_*
+; save_fpregs_*
+; restore_gpregs*
+; return_and_restore_gpregs*
+; return_and_restore_fpregs*
+; return_and_restore_fpregs_aix*
+;
+; The out-of-line save / restore functions expects one input argument.
+; Since those are not standard call_insn's, we must avoid using
+; MATCH_OPERAND for that argument. That way the register rename
+; optimization will not try to rename this register.
+; Each pattern is repeated for each possible register number used in
+; various ABIs (r11, r1, and for some functions r12)
+
+(define_insn "*save_gpregs_<mode>_r11"
+ [(match_parallel 0 "any_parallel_operand"
+ [(clobber (reg:P 65))
+ (use (match_operand:P 1 "symbol_ref_operand" "s"))
+ (use (reg:P 11))
+ (set (match_operand:P 2 "memory_operand" "=m")
+ (match_operand:P 3 "gpc_reg_operand" "r"))])]
+ ""
+ "bl %1"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4")])
+
+(define_insn "*save_gpregs_<mode>_r12"
+ [(match_parallel 0 "any_parallel_operand"
+ [(clobber (reg:P 65))
+ (use (match_operand:P 1 "symbol_ref_operand" "s"))
+ (use (reg:P 12))
+ (set (match_operand:P 2 "memory_operand" "=m")
+ (match_operand:P 3 "gpc_reg_operand" "r"))])]
+ ""
+ "bl %1"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4")])
+
+(define_insn "*save_gpregs_<mode>_r1"
[(match_parallel 0 "any_parallel_operand"
[(clobber (reg:P 65))
(use (match_operand:P 1 "symbol_ref_operand" "s"))
- (use (match_operand:P 2 "gpc_reg_operand" "r"))
- (set (match_operand:P 3 "memory_operand" "=m")
- (match_operand:P 4 "gpc_reg_operand" "r"))])]
+ (use (reg:P 1))
+ (set (match_operand:P 2 "memory_operand" "=m")
+ (match_operand:P 3 "gpc_reg_operand" "r"))])]
""
"bl %1"
[(set_attr "type" "branch")
(set_attr "length" "4")])
-(define_insn "*save_fpregs_<mode>"
+(define_insn "*save_fpregs_<mode>_r11"
[(match_parallel 0 "any_parallel_operand"
[(clobber (reg:P 65))
(use (match_operand:P 1 "symbol_ref_operand" "s"))
- (use (match_operand:P 2 "gpc_reg_operand" "r"))
- (set (match_operand:DF 3 "memory_operand" "=m")
- (match_operand:DF 4 "gpc_reg_operand" "d"))])]
+ (use (reg:P 11))
+ (set (match_operand:DF 2 "memory_operand" "=m")
+ (match_operand:DF 3 "gpc_reg_operand" "d"))])]
+ ""
+ "bl %1"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4")])
+
+(define_insn "*save_fpregs_<mode>_r12"
+ [(match_parallel 0 "any_parallel_operand"
+ [(clobber (reg:P 65))
+ (use (match_operand:P 1 "symbol_ref_operand" "s"))
+ (use (reg:P 12))
+ (set (match_operand:DF 2 "memory_operand" "=m")
+ (match_operand:DF 3 "gpc_reg_operand" "d"))])]
+ ""
+ "bl %1"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4")])
+
+(define_insn "*save_fpregs_<mode>_r1"
+ [(match_parallel 0 "any_parallel_operand"
+ [(clobber (reg:P 65))
+ (use (match_operand:P 1 "symbol_ref_operand" "s"))
+ (use (reg:P 1))
+ (set (match_operand:DF 2 "memory_operand" "=m")
+ (match_operand:DF 3 "gpc_reg_operand" "d"))])]
""
"bl %1"
[(set_attr "type" "branch")
; FIXME: This would probably be somewhat simpler if the Cygnus sibcall
; stuff was in GCC. Oh, and "any_parallel_operand" is a bit flexible...
-(define_insn "*restore_gpregs_<mode>"
+; The following comment applies to:
+; save_gpregs_*
+; save_fpregs_*
+; restore_gpregs*
+; return_and_restore_gpregs*
+; return_and_restore_fpregs*
+; return_and_restore_fpregs_aix*
+;
+; The out-of-line save / restore functions expects one input argument.
+; Since those are not standard call_insn's, we must avoid using
+; MATCH_OPERAND for that argument. That way the register rename
+; optimization will not try to rename this register.
+; Each pattern is repeated for each possible register number used in
+; various ABIs (r11, r1, and for some functions r12)
+
+(define_insn "*restore_gpregs_<mode>_r11"
+ [(match_parallel 0 "any_parallel_operand"
+ [(clobber (match_operand:P 1 "register_operand" "=l"))
+ (use (match_operand:P 2 "symbol_ref_operand" "s"))
+ (use (reg:P 11))
+ (set (match_operand:P 3 "gpc_reg_operand" "=r")
+ (match_operand:P 4 "memory_operand" "m"))])]
+ ""
+ "bl %2"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4")])
+
+(define_insn "*restore_gpregs_<mode>_r12"
+ [(match_parallel 0 "any_parallel_operand"
+ [(clobber (match_operand:P 1 "register_operand" "=l"))
+ (use (match_operand:P 2 "symbol_ref_operand" "s"))
+ (use (reg:P 12))
+ (set (match_operand:P 3 "gpc_reg_operand" "=r")
+ (match_operand:P 4 "memory_operand" "m"))])]
+ ""
+ "bl %2"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4")])
+
+(define_insn "*restore_gpregs_<mode>_r1"
[(match_parallel 0 "any_parallel_operand"
[(clobber (match_operand:P 1 "register_operand" "=l"))
(use (match_operand:P 2 "symbol_ref_operand" "s"))
- (use (match_operand:P 3 "gpc_reg_operand" "r"))
- (set (match_operand:P 4 "gpc_reg_operand" "=r")
- (match_operand:P 5 "memory_operand" "m"))])]
+ (use (reg:P 1))
+ (set (match_operand:P 3 "gpc_reg_operand" "=r")
+ (match_operand:P 4 "memory_operand" "m"))])]
""
"bl %2"
[(set_attr "type" "branch")
(set_attr "length" "4")])
-(define_insn "*return_and_restore_gpregs_<mode>"
+(define_insn "*return_and_restore_gpregs_<mode>_r11"
+ [(match_parallel 0 "any_parallel_operand"
+ [(return)
+ (clobber (match_operand:P 1 "register_operand" "=l"))
+ (use (match_operand:P 2 "symbol_ref_operand" "s"))
+ (use (reg:P 11))
+ (set (match_operand:P 3 "gpc_reg_operand" "=r")
+ (match_operand:P 4 "memory_operand" "m"))])]
+ ""
+ "b %2"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4")])
+
+(define_insn "*return_and_restore_gpregs_<mode>_r12"
+ [(match_parallel 0 "any_parallel_operand"
+ [(return)
+ (clobber (match_operand:P 1 "register_operand" "=l"))
+ (use (match_operand:P 2 "symbol_ref_operand" "s"))
+ (use (reg:P 12))
+ (set (match_operand:P 3 "gpc_reg_operand" "=r")
+ (match_operand:P 4 "memory_operand" "m"))])]
+ ""
+ "b %2"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4")])
+
+(define_insn "*return_and_restore_gpregs_<mode>_r1"
+ [(match_parallel 0 "any_parallel_operand"
+ [(return)
+ (clobber (match_operand:P 1 "register_operand" "=l"))
+ (use (match_operand:P 2 "symbol_ref_operand" "s"))
+ (use (reg:P 1))
+ (set (match_operand:P 3 "gpc_reg_operand" "=r")
+ (match_operand:P 4 "memory_operand" "m"))])]
+ ""
+ "b %2"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4")])
+
+(define_insn "*return_and_restore_fpregs_<mode>_r11"
+ [(match_parallel 0 "any_parallel_operand"
+ [(return)
+ (clobber (match_operand:P 1 "register_operand" "=l"))
+ (use (match_operand:P 2 "symbol_ref_operand" "s"))
+ (use (reg:P 11))
+ (set (match_operand:DF 3 "gpc_reg_operand" "=d")
+ (match_operand:DF 4 "memory_operand" "m"))])]
+ ""
+ "b %2"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4")])
+
+(define_insn "*return_and_restore_fpregs_<mode>_r12"
[(match_parallel 0 "any_parallel_operand"
[(return)
(clobber (match_operand:P 1 "register_operand" "=l"))
(use (match_operand:P 2 "symbol_ref_operand" "s"))
- (use (match_operand:P 3 "gpc_reg_operand" "r"))
- (set (match_operand:P 4 "gpc_reg_operand" "=r")
- (match_operand:P 5 "memory_operand" "m"))])]
+ (use (reg:P 12))
+ (set (match_operand:DF 3 "gpc_reg_operand" "=d")
+ (match_operand:DF 4 "memory_operand" "m"))])]
""
"b %2"
[(set_attr "type" "branch")
(set_attr "length" "4")])
-(define_insn "*return_and_restore_fpregs_<mode>"
+(define_insn "*return_and_restore_fpregs_<mode>_r1"
[(match_parallel 0 "any_parallel_operand"
[(return)
(clobber (match_operand:P 1 "register_operand" "=l"))
(use (match_operand:P 2 "symbol_ref_operand" "s"))
- (use (match_operand:P 3 "gpc_reg_operand" "r"))
- (set (match_operand:DF 4 "gpc_reg_operand" "=d")
- (match_operand:DF 5 "memory_operand" "m"))])]
+ (use (reg:P 1))
+ (set (match_operand:DF 3 "gpc_reg_operand" "=d")
+ (match_operand:DF 4 "memory_operand" "m"))])]
""
"b %2"
[(set_attr "type" "branch")
(set_attr "length" "4")])
-(define_insn "*return_and_restore_fpregs_aix_<mode>"
+(define_insn "*return_and_restore_fpregs_aix_<mode>_r11"
[(match_parallel 0 "any_parallel_operand"
[(return)
(use (match_operand:P 1 "register_operand" "l"))
(use (match_operand:P 2 "symbol_ref_operand" "s"))
- (use (match_operand:P 3 "gpc_reg_operand" "r"))
- (set (match_operand:DF 4 "gpc_reg_operand" "=d")
- (match_operand:DF 5 "memory_operand" "m"))])]
+ (use (reg:P 11))
+ (set (match_operand:DF 3 "gpc_reg_operand" "=d")
+ (match_operand:DF 4 "memory_operand" "m"))])]
+ ""
+ "b %2"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4")])
+
+(define_insn "*return_and_restore_fpregs_aix_<mode>_r1"
+ [(match_parallel 0 "any_parallel_operand"
+ [(return)
+ (use (match_operand:P 1 "register_operand" "l"))
+ (use (match_operand:P 2 "symbol_ref_operand" "s"))
+ (use (reg:P 1))
+ (set (match_operand:DF 3 "gpc_reg_operand" "=d")
+ (match_operand:DF 4 "memory_operand" "m"))])]
""
"b %2"
[(set_attr "type" "branch")
[(set_attr "type" "integer")])
\f
+;; 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" "")))))]
+ ""
+ "")
+
+\f
(include "sync.md")
(include "vector.md")