diff options
Diffstat (limited to 'gcc/config/rs6000/rs6000.md')
-rw-r--r-- | gcc/config/rs6000/rs6000.md | 411 |
1 files changed, 397 insertions, 14 deletions
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 49c5c98..1fdc7bb 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -143,6 +143,9 @@ UNSPEC_STACK_CHECK UNSPEC_FUSION_P9 UNSPEC_FUSION_ADDIS + UNSPEC_ROUND_TO_ODD + UNSPEC_IEEE128_MOVE + UNSPEC_IEEE128_CONVERT ]) ;; @@ -381,6 +384,8 @@ (V2SF "TARGET_PAIRED_FLOAT") (V4SF "VECTOR_UNIT_ALTIVEC_OR_VSX_P (V4SFmode)") (V2DF "VECTOR_UNIT_ALTIVEC_OR_VSX_P (V2DFmode)") + (KF "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (KFmode)") + (TF "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (TFmode)") ]) ; Floating point move iterators to combine binary and decimal moves @@ -485,10 +490,10 @@ (define_mode_attr Fvsx [(SF "sp") (DF "dp")]) ; SF/DF constraint for arithmetic on traditional floating point registers -(define_mode_attr Ff [(SF "f") (DF "d")]) +(define_mode_attr Ff [(SF "f") (DF "d") (DI "d")]) ; SF/DF constraint for arithmetic on VSX registers -(define_mode_attr Fv [(SF "wy") (DF "ws")]) +(define_mode_attr Fv [(SF "wy") (DF "ws") (DI "wi")]) ; SF/DF constraint for arithmetic on altivec registers (define_mode_attr Fa [(SF "wu") (DF "wv")]) @@ -510,9 +515,31 @@ (define_code_iterator iorxor [ior xor]) ; Signed/unsigned variants of ops. -(define_code_iterator any_extend [sign_extend zero_extend]) -(define_code_attr u [(sign_extend "") (zero_extend "u")]) -(define_code_attr su [(sign_extend "s") (zero_extend "u")]) +(define_code_iterator any_extend [sign_extend zero_extend]) +(define_code_iterator any_fix [fix unsigned_fix]) +(define_code_iterator any_float [float unsigned_float]) + +(define_code_attr u [(sign_extend "") + (zero_extend "u")]) + +(define_code_attr su [(sign_extend "s") + (zero_extend "u") + (fix "s") + (unsigned_fix "s") + (float "s") + (unsigned_float "u")]) + +(define_code_attr az [(sign_extend "a") + (zero_extend "z") + (fix "a") + (unsigned_fix "z") + (float "a") + (unsigned_float "z")]) + +(define_code_attr uns [(fix "") + (unsigned_fix "uns") + (float "") + (unsigned_float "uns")]) ; Various instructions that come in SI and DI forms. ; A generic w/d attribute, for things like cmpw/cmpd. @@ -2815,6 +2842,14 @@ DONE; }) +(define_insn "*maddld4" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (plus:DI (mult:DI (match_operand:DI 1 "gpc_reg_operand" "r") + (match_operand:DI 2 "gpc_reg_operand" "r")) + (match_operand:DI 3 "gpc_reg_operand" "r")))] + "TARGET_MADDLD" + "maddld %0,%1,%2,%3" + [(set_attr "type" "mul")]) (define_insn "udiv<mode>3" [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") @@ -7003,7 +7038,16 @@ { if (FLOAT128_IEEE_P (<MODE>mode)) { - if (TARGET_FLOAT128) + if (TARGET_FLOAT128_HW) + { + if (<MODE>mode == TFmode) + emit_insn (gen_negtf2_hw (operands[0], operands[1])); + else if (<MODE>mode == KFmode) + emit_insn (gen_negkf2_hw (operands[0], operands[1])); + else + gcc_unreachable (); + } + else if (TARGET_FLOAT128) { if (<MODE>mode == TFmode) emit_insn (gen_ieee_128bit_vsx_negtf2 (operands[0], operands[1])); @@ -7053,7 +7097,17 @@ if (FLOAT128_IEEE_P (<MODE>mode)) { - if (TARGET_FLOAT128) + if (TARGET_FLOAT128_HW) + { + if (<MODE>mode == TFmode) + emit_insn (gen_abstf2_hw (operands[0], operands[1])); + else if (<MODE>mode == KFmode) + emit_insn (gen_abskf2_hw (operands[0], operands[1])); + else + FAIL; + DONE; + } + else if (TARGET_FLOAT128) { if (<MODE>mode == TFmode) emit_insn (gen_ieee_128bit_vsx_abstf2 (operands[0], operands[1])); @@ -7140,7 +7194,7 @@ [(set (match_operand:IEEE128 0 "register_operand" "=wa") (neg:IEEE128 (match_operand:IEEE128 1 "register_operand" "wa"))) (clobber (match_scratch:V16QI 2 "=v"))] - "TARGET_FLOAT128" + "TARGET_FLOAT128 && !TARGET_FLOAT128_HW" "#" "&& 1" [(parallel [(set (match_dup 0) @@ -7160,7 +7214,7 @@ [(set (match_operand:IEEE128 0 "register_operand" "=wa") (neg:IEEE128 (match_operand:IEEE128 1 "register_operand" "wa"))) (use (match_operand:V16QI 2 "register_operand" "=v"))] - "TARGET_FLOAT128" + "TARGET_FLOAT128 && !TARGET_FLOAT128_HW" "xxlxor %x0,%x1,%x2" [(set_attr "type" "vecsimple")]) @@ -7169,7 +7223,7 @@ [(set (match_operand:IEEE128 0 "register_operand" "=wa") (abs:IEEE128 (match_operand:IEEE128 1 "register_operand" "wa"))) (clobber (match_scratch:V16QI 2 "=v"))] - "TARGET_FLOAT128 && FLOAT128_IEEE_P (<MODE>mode)" + "TARGET_FLOAT128 && !TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" "#" "&& 1" [(parallel [(set (match_dup 0) @@ -7189,7 +7243,7 @@ [(set (match_operand:IEEE128 0 "register_operand" "=wa") (abs:IEEE128 (match_operand:IEEE128 1 "register_operand" "wa"))) (use (match_operand:V16QI 2 "register_operand" "=v"))] - "TARGET_FLOAT128" + "TARGET_FLOAT128 && !TARGET_FLOAT128_HW" "xxlandc %x0,%x1,%x2" [(set_attr "type" "vecsimple")]) @@ -7200,7 +7254,7 @@ (abs:IEEE128 (match_operand:IEEE128 1 "register_operand" "wa")))) (clobber (match_scratch:V16QI 2 "=v"))] - "TARGET_FLOAT128 && FLOAT128_IEEE_P (<MODE>mode)" + "TARGET_FLOAT128 && !TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" "#" "&& 1" [(parallel [(set (match_dup 0) @@ -7222,7 +7276,7 @@ (abs:IEEE128 (match_operand:IEEE128 1 "register_operand" "wa")))) (use (match_operand:V16QI 2 "register_operand" "=v"))] - "TARGET_FLOAT128" + "TARGET_FLOAT128 && !TARGET_FLOAT128_HW" "xxlor %x0,%x1,%x2" [(set_attr "type" "vecsimple")]) @@ -7480,7 +7534,10 @@ (match_operand:FMOVE128_GPR 1 "input_operand" ""))] "reload_completed && (int_reg_operand (operands[0], <MODE>mode) - || int_reg_operand (operands[1], <MODE>mode))" + || int_reg_operand (operands[1], <MODE>mode)) + && (!TARGET_DIRECT_MOVE_128 + || (!vsx_register_operand (operands[0], <MODE>mode) + && !vsx_register_operand (operands[1], <MODE>mode)))" [(pc)] { rs6000_split_multireg_move (operands[0], operands[1]); DONE; }) @@ -12998,6 +13055,332 @@ +;; ISA 2.08 IEEE 128-bit floating point support. + +(define_insn "add<mode>3" + [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v") + (plus:IEEE128 + (match_operand:IEEE128 1 "altivec_register_operand" "v") + (match_operand:IEEE128 2 "altivec_register_operand" "v")))] + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" + "xsaddqp %0,%1,%2" + [(set_attr "type" "vecfloat")]) + +(define_insn "sub<mode>3" + [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v") + (minus:IEEE128 + (match_operand:IEEE128 1 "altivec_register_operand" "v") + (match_operand:IEEE128 2 "altivec_register_operand" "v")))] + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" + "xssubqp %0,%1,%2" + [(set_attr "type" "vecfloat")]) + +(define_insn "mul<mode>3" + [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v") + (mult:IEEE128 + (match_operand:IEEE128 1 "altivec_register_operand" "v") + (match_operand:IEEE128 2 "altivec_register_operand" "v")))] + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" + "xsmulqp %0,%1,%2" + [(set_attr "type" "vecfloat")]) + +(define_insn "div<mode>3" + [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v") + (div:IEEE128 + (match_operand:IEEE128 1 "altivec_register_operand" "v") + (match_operand:IEEE128 2 "altivec_register_operand" "v")))] + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" + "xsdivqp %0,%1,%2" + [(set_attr "type" "vecdiv")]) + +(define_insn "sqrt<mode>2" + [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v") + (sqrt:IEEE128 + (match_operand:IEEE128 1 "altivec_register_operand" "v")))] + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" + "xssqrtqp %0,%1" + [(set_attr "type" "vecdiv")]) + +(define_insn "copysign<mode>3" + [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v") + (unspec:IEEE128 + [(match_operand:IEEE128 1 "altivec_register_operand" "v") + (match_operand:IEEE128 2 "altivec_register_operand" "v")] + UNSPEC_COPYSIGN))] + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" + "xscpsgnqp %0,%2,%1" + [(set_attr "type" "vecsimple")]) + +(define_insn "neg<mode>2_hw" + [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v") + (neg:IEEE128 + (match_operand:IEEE128 1 "altivec_register_operand" "v")))] + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" + "xsnegqp %0,%1" + [(set_attr "type" "vecfloat")]) + + +(define_insn "abs<mode>2_hw" + [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v") + (abs:IEEE128 + (match_operand:IEEE128 1 "altivec_register_operand" "v")))] + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" + "xsabsqp %0,%1" + [(set_attr "type" "vecfloat")]) + + +(define_insn "*nabs<mode>2_hw" + [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v") + (neg:IEEE128 + (abs:IEEE128 + (match_operand:IEEE128 1 "altivec_register_operand" "v"))))] + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" + "xsnabsqp %0,%1" + [(set_attr "type" "vecfloat")]) + +;; Initially don't worry about doing fusion +(define_insn "*fma<mode>4_hw" + [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v") + (fma:IEEE128 + (match_operand:IEEE128 1 "altivec_register_operand" "%v") + (match_operand:IEEE128 2 "altivec_register_operand" "v") + (match_operand:IEEE128 3 "altivec_register_operand" "0")))] + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" + "xsmaddqp %0,%1,%2" + [(set_attr "type" "vecfloat")]) + +(define_insn "*fms<mode>4_hw" + [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v") + (fma:IEEE128 + (match_operand:IEEE128 1 "altivec_register_operand" "%v") + (match_operand:IEEE128 2 "altivec_register_operand" "v") + (neg:IEEE128 + (match_operand:IEEE128 3 "altivec_register_operand" "0"))))] + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" + "xsmsubqp %0,%1,%2" + [(set_attr "type" "vecfloat")]) + +(define_insn "*nfma<mode>4_hw" + [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v") + (neg:IEEE128 + (fma:IEEE128 + (match_operand:IEEE128 1 "altivec_register_operand" "%v") + (match_operand:IEEE128 2 "altivec_register_operand" "v") + (match_operand:IEEE128 3 "altivec_register_operand" "0"))))] + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" + "xsnmaddqp %0,%1,%2" + [(set_attr "type" "vecfloat")]) + +(define_insn "*nfms<mode>4_hw" + [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v") + (neg:IEEE128 + (fma:IEEE128 + (match_operand:IEEE128 1 "altivec_register_operand" "%v") + (match_operand:IEEE128 2 "altivec_register_operand" "v") + (neg:IEEE128 + (match_operand:IEEE128 3 "altivec_register_operand" "0")))))] + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" + "xsnmsubqp %0,%1,%2" + [(set_attr "type" "vecfloat")]) + +(define_insn "extend<SFDF:mode><IEEE128:mode>2_hw" + [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v") + (float_extend:IEEE128 + (match_operand:SFDF 1 "altivec_register_operand" "v")))] + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<IEEE128:MODE>mode)" + "xscvdpqp %0,%1" + [(set_attr "type" "vecfloat")]) + +(define_insn "trunc<mode>df2_hw" + [(set (match_operand:DF 0 "altivec_register_operand" "=v") + (float_truncate:DF + (match_operand:IEEE128 1 "altivec_register_operand" "v")))] + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" + "xscvqpdp %0,%1" + [(set_attr "type" "vecfloat")]) + +;; There is no KFmode -> SFmode instruction. Preserve the accuracy by doing +;; the KFmode -> DFmode conversion using round to odd rather than the normal +;; conversion +(define_insn_and_split "trunc<mode>sf2_hw" + [(set (match_operand:SF 0 "vsx_register_operand" "=wy") + (float_truncate:SF + (match_operand:IEEE128 1 "altivec_register_operand" "v"))) + (clobber (match_scratch:DF 2 "=v"))] + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" + "#" + "&& 1" + [(set (match_dup 2) + (unspec:DF [(match_dup 1)] UNSPEC_ROUND_TO_ODD)) + (set (match_dup 0) + (float_truncate:SF (match_dup 2)))] +{ + if (GET_CODE (operands[2]) == SCRATCH) + operands[2] = gen_reg_rtx (DFmode); +} + [(set_attr "type" "vecfloat") + (set_attr "length" "8")]) + +;; At present SImode is not allowed in VSX registers at all, and DImode is only +;; allowed in the traditional floating point registers. Use V2DImode so that +;; we can get a value in an Altivec register. + +(define_insn_and_split "fix<uns>_<mode>si2_hw" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,Z") + (any_fix:SI (match_operand:IEEE128 1 "altivec_register_operand" "v,v"))) + (clobber (match_scratch:V2DI 2 "=v,v"))] + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" + "#" + "&& 1" + [(pc)] +{ + convert_float128_to_int (operands, <CODE>); + DONE; +} + [(set_attr "length" "8") + (set_attr "type" "mftgpr,fpstore")]) + +(define_insn_and_split "fix<uns>_<mode>di2_hw" + [(set (match_operand:DI 0 "nonimmediate_operand" "=wr,wi,Z") + (any_fix:DI (match_operand:IEEE128 1 "altivec_register_operand" "v,v,v"))) + (clobber (match_scratch:V2DI 2 "=v,v,v"))] + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" + "#" + "&& 1" + [(pc)] +{ + convert_float128_to_int (operands, <CODE>); + DONE; +} + [(set_attr "length" "8") + (set_attr "type" "mftgpr,vecsimple,fpstore")]) + +(define_insn_and_split "float<uns>_<mode>si2_hw" + [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v,v") + (any_float:IEEE128 (match_operand:SI 1 "nonimmediate_operand" "r,Z"))) + (clobber (match_scratch:V2DI 2 "=v,v"))] + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" + "#" + "&& 1" + [(pc)] +{ + convert_int_to_float128 (operands, <CODE>); + DONE; +} + [(set_attr "length" "8") + (set_attr "type" "vecfloat")]) + +(define_insn_and_split "float<uns>_<mode>di2_hw" + [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v,v,v") + (any_float:IEEE128 (match_operand:DI 1 "nonimmediate_operand" "wi,wr,Z"))) + (clobber (match_scratch:V2DI 2 "=v,v,v"))] + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" + "#" + "&& 1" + [(pc)] +{ + convert_int_to_float128 (operands, <CODE>); + DONE; +} + [(set_attr "length" "8") + (set_attr "type" "vecfloat")]) + +;; Integer conversion instructions, using V2DImode to get an Altivec register +(define_insn "*xscvqp<su>wz_<mode>" + [(set (match_operand:V2DI 0 "altivec_register_operand" "=v") + (unspec:V2DI + [(any_fix:SI + (match_operand:IEEE128 1 "altivec_register_operand" "v"))] + UNSPEC_IEEE128_CONVERT))] + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" + "xscvqp<su>wz %0,%1" + [(set_attr "type" "vecfloat")]) + +(define_insn "*xscvqp<su>dz_<mode>" + [(set (match_operand:V2DI 0 "altivec_register_operand" "=v") + (unspec:V2DI + [(any_fix:DI + (match_operand:IEEE128 1 "altivec_register_operand" "v"))] + UNSPEC_IEEE128_CONVERT))] + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" + "xscvqp<su>dz %0,%1" + [(set_attr "type" "vecfloat")]) + +(define_insn "*xscv<su>dqp_<mode>" + [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v") + (any_float:IEEE128 + (unspec:DI [(match_operand:V2DI 1 "altivec_register_operand" "v")] + UNSPEC_IEEE128_CONVERT)))] + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" + "xscv<su>dqp %0,%1" + [(set_attr "type" "vecfloat")]) + +(define_insn "*ieee128_mfvsrd" + [(set (match_operand:DI 0 "reg_or_indexed_operand" "=wr,Z,wi") + (unspec:DI [(match_operand:V2DI 1 "altivec_register_operand" "v,v,v")] + UNSPEC_IEEE128_MOVE))] + "TARGET_FLOAT128_HW && TARGET_POWERPC64" + "@ + mfvsrd %0,%x1 + stxsdx %x1,%y0 + xxlor %x0,%x1,%x1" + [(set_attr "type" "mftgpr,vecsimple,fpstore")]) + +(define_insn "*ieee128_mfvsrwz" + [(set (match_operand:SI 0 "reg_or_indexed_operand" "=r,Z") + (unspec:SI [(match_operand:V2DI 1 "altivec_register_operand" "v,v")] + UNSPEC_IEEE128_MOVE))] + "TARGET_FLOAT128_HW" + "@ + mfvsrwz %0,%x1 + stxsiwx %x1,%y0" + [(set_attr "type" "mftgpr,fpstore")]) + +;; 0 says do sign-extension, 1 says zero-extension +(define_insn "*ieee128_mtvsrw" + [(set (match_operand:V2DI 0 "altivec_register_operand" "=v,v,v,v") + (unspec:V2DI [(match_operand:SI 1 "nonimmediate_operand" "r,Z,r,Z") + (match_operand:SI 2 "const_0_to_1_operand" "O,O,n,n")] + UNSPEC_IEEE128_MOVE))] + "TARGET_FLOAT128_HW" + "@ + mtvsrwa %x0,%1 + lxsiwax %x0,%y1 + mtvsrwz %x0,%1 + lxsiwzx %x0,%y1" + [(set_attr "type" "mffgpr,fpload,mffgpr,fpload")]) + + +(define_insn "*ieee128_mtvsrd" + [(set (match_operand:V2DI 0 "altivec_register_operand" "=v,v,v") + (unspec:V2DI [(match_operand:DI 1 "nonimmediate_operand" "wr,Z,wi")] + UNSPEC_IEEE128_MOVE))] + "TARGET_FLOAT128_HW" + "@ + mtvsrd %x0,%1 + lxsdx %x0,%y1 + xxlor %x0,%x1,%x1" + [(set_attr "type" "mffgpr,fpload,vecsimple")]) + +;; IEEE 128-bit instructions with round to odd semantics +(define_insn "*trunc<mode>df2_odd" + [(set (match_operand:DF 0 "vsx_register_operand" "=v") + (unspec:DF [(match_operand:IEEE128 1 "altivec_register_operand" "v")] + UNSPEC_ROUND_TO_ODD))] + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" + "xscvqpdpo %0,%1" + [(set_attr "type" "vecfloat")]) + +;; IEEE 128-bit comparisons +(define_insn "*cmp<mode>_hw" + [(set (match_operand:CCFP 0 "cc_reg_operand" "=y") + (compare:CCFP (match_operand:IEEE128 1 "altivec_register_operand" "v") + (match_operand:IEEE128 2 "altivec_register_operand" "v")))] + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)" + "xscmpuqp %0,%1,%2" + [(set_attr "type" "fpcompare")]) + + (include "sync.md") (include "vector.md") |