This patch adds support for the new floating point vector elements (SF and TF) introduced with arch12.
gcc/ChangeLog: 2017-03-24 Andreas Krebbel <kreb...@linux.vnet.ibm.com> * config/s390/s390.c (s390_expand_vec_compare): Support other vector floating point modes than just V2DF. (s390_expand_vcond): Likewise. (s390_hard_regno_mode_ok): Allow SFmode values in VRs. (s390_cannot_change_mode_class): Prevent mode changes between TF and V1TF in vector registers. * config/s390/s390.md (DF, SF): New mode attributes. ("*cmp<mode>_ccs", "add<mode>3", "sub<mode>3", "mul<mode>3") ("fma<mode>4", "fms<mode>4", "div<mode>3", "*neg<mode>2"): Add SFmode support for VRs. * config/s390/vector.md (V_HW, V_HW2, VT_HW, ti*, nonvec): Add new vector fp modes. (VFT, VF_HW): New mode iterators. (vw, sdx): New mode attributes. ("addv2df3", "subv2df3", "mulv2df3", "divv2df3", "sqrtv2df2") ("fmav2df4","fmsv2df4", "negv2df2", "absv2df2", "*negabsv2df2") ("smaxv2df3", "sminv2df3", "*vec_cmp<VFCMP_HW_OP:code>v2df_nocc") ("vec_cmpuneqv2df", "vec_cmpltgtv2df", "vec_orderedv2df") ("vec_unorderedv2df"): Adjust the v2df only patterns to support also the new vector floating point modes. Renaming to ... ("add<mode>3", "sub<mode>3", "mul<mode>3", "div<mode>3") ("sqrt<mode>2", "fma<mode>4", "fms<mode>4", "neg<mode>2") ("abs<mode>2", "negabs<mode>2", "smax<mode>3") ("smin<mode>3", "*vec_cmp<VFCMP_HW_OP:code><mode>_nocc") ("vec_cmpuneq<mode>", "vec_cmpltgt<mode>", "vec_ordered<mode>") ("vec_unordered<mode>"): ... these. ("neg_fma<mode>4", "neg_fms<mode>4", "*smax<mode>3_vxe") ("*smin<mode>3_vxe", "*sminv2df3_vx", "*vec_extendv4sf") ("*vec_extendv2df"): New insn definitions. gcc/testsuite/ChangeLog: 2017-03-24 Andreas Krebbel <kreb...@linux.vnet.ibm.com> * gcc.target/s390/vxe/negfma-1.c: New test. --- gcc/ChangeLog | 34 +++ gcc/config/s390/s390-builtins.def | 2 +- gcc/config/s390/s390.c | 13 +- gcc/config/s390/s390.md | 144 ++++++------ gcc/config/s390/vector.md | 313 ++++++++++++++++++--------- gcc/testsuite/ChangeLog | 4 + gcc/testsuite/gcc.target/s390/vxe/negfma-1.c | 49 +++++ 7 files changed, 388 insertions(+), 171 deletions(-) create mode 100644 gcc/testsuite/gcc.target/s390/vxe/negfma-1.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3753ad6..bd60982 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,39 @@ 2017-03-24 Andreas Krebbel <kreb...@linux.vnet.ibm.com> + * config/s390/s390.c (s390_expand_vec_compare): Support other + vector floating point modes than just V2DF. + (s390_expand_vcond): Likewise. + (s390_hard_regno_mode_ok): Allow SFmode values in VRs. + (s390_cannot_change_mode_class): Prevent mode changes between TF + and V1TF in vector registers. + * config/s390/s390.md (DF, SF): New mode attributes. + ("*cmp<mode>_ccs", "add<mode>3", "sub<mode>3", "mul<mode>3") + ("fma<mode>4", "fms<mode>4", "div<mode>3", "*neg<mode>2"): Add + SFmode support for VRs. + * config/s390/vector.md (V_HW, V_HW2, VT_HW, ti*, nonvec): Add new + vector fp modes. + (VFT, VF_HW): New mode iterators. + (vw, sdx): New mode attributes. + ("addv2df3", "subv2df3", "mulv2df3", "divv2df3", "sqrtv2df2") + ("fmav2df4","fmsv2df4", "negv2df2", "absv2df2", "*negabsv2df2") + ("smaxv2df3", "sminv2df3", "*vec_cmp<VFCMP_HW_OP:code>v2df_nocc") + ("vec_cmpuneqv2df", "vec_cmpltgtv2df", "vec_orderedv2df") + ("vec_unorderedv2df"): Adjust the v2df only patterns to support + also the new vector floating point modes. Renaming to ... + + ("add<mode>3", "sub<mode>3", "mul<mode>3", "div<mode>3") + ("sqrt<mode>2", "fma<mode>4", "fms<mode>4", "neg<mode>2") + ("abs<mode>2", "negabs<mode>2", "smax<mode>3") + ("smin<mode>3", "*vec_cmp<VFCMP_HW_OP:code><mode>_nocc") + ("vec_cmpuneq<mode>", "vec_cmpltgt<mode>", "vec_ordered<mode>") + ("vec_unordered<mode>"): ... these. + + ("neg_fma<mode>4", "neg_fms<mode>4", "*smax<mode>3_vxe") + ("*smin<mode>3_vxe", "*sminv2df3_vx", "*vec_extendv4sf") + ("*vec_extendv2df"): New insn definitions. + +2017-03-24 Andreas Krebbel <kreb...@linux.vnet.ibm.com> + * config/s390/s390.md ("*adddi3_sign", "*subdi3_sign", "mulditi3") ("mulditi3_2", "*muldi3_sign"): New patterns. ("muldi3", "*muldi3", "mulsi3", "*mulsi3"): Add an expander and diff --git a/gcc/config/s390/s390-builtins.def b/gcc/config/s390/s390-builtins.def index 27cb6a8..bb2d743 100644 --- a/gcc/config/s390/s390-builtins.def +++ b/gcc/config/s390/s390-builtins.def @@ -2496,7 +2496,7 @@ B_DEF (s390_vec_ctsl, vec_ctsl, 0, B_DEF (s390_vec_ctul, vec_ctul, 0, B_VX, O2_U3, BT_FN_UV2DI_V2DF_INT) /* vclgdb */ B_DEF (s390_vcgdb, vec_df_to_di_s64, 0, B_VX, O2_U3, BT_FN_V2DI_V2DF_INT) /* vcgdb */ B_DEF (s390_vclgdb, vec_df_to_di_u64, 0, B_VX, O2_U3, BT_FN_UV2DI_V2DF_INT) /* vclgdb */ -B_DEF (s390_vfidb, vfidb, 0, B_VX, O2_U4 | O3_U3, BT_FN_V2DF_V2DF_UCHAR_UCHAR) +B_DEF (s390_vfidb, vfiv2df, 0, B_VX, O2_U4 | O3_U3, BT_FN_V2DF_V2DF_UCHAR_UCHAR) B_DEF (s390_vec_ld2f, vec_ld2f, 0, B_VX, 0, BT_FN_V2DF_FLTCONSTPTR) /* vldeb */ B_DEF (s390_vec_st2f, vec_st2f, 0, B_VX, 0, BT_FN_VOID_V2DF_FLTPTR) /* vledb */ B_DEF (s390_vfmadb, fmav2df4, 0, B_VX, 0, BT_FN_V2DF_V2DF_V2DF_V2DF) diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c index e800323..1d26979 100644 --- a/gcc/config/s390/s390.c +++ b/gcc/config/s390/s390.c @@ -6201,7 +6201,7 @@ s390_expand_vec_compare (rtx target, enum rtx_code cond, bool neg_p = false, swap_p = false; rtx tmp; - if (GET_MODE (cmp_op1) == V2DFmode) + if (GET_MODE_CLASS (GET_MODE (cmp_op1)) == MODE_VECTOR_FLOAT) { switch (cond) { @@ -6447,7 +6447,8 @@ s390_expand_vcond (rtx target, rtx then, rtx els, /* We always use an integral type vector to hold the comparison result. */ - result_mode = cmp_mode == V2DFmode ? V2DImode : cmp_mode; + result_mode = mode_for_vector (int_mode_for_mode (GET_MODE_INNER (cmp_mode)), + GET_MODE_NUNITS (cmp_mode)); result_target = gen_reg_rtx (result_mode); /* We allow vector immediates as comparison operands that @@ -10112,6 +10113,7 @@ s390_hard_regno_mode_ok (unsigned int regno, machine_mode mode) return ((GET_MODE_CLASS (mode) == MODE_INT && s390_class_max_nregs (VEC_REGS, mode) == 1) || mode == DFmode + || (TARGET_VXE && mode == SFmode) || s390_vector_mode_supported_p (mode)); break; case FP_REGS: @@ -10256,6 +10258,13 @@ s390_cannot_change_mode_class (machine_mode from_mode, machine_mode small_mode; machine_mode big_mode; + /* V1TF and TF have different representations in vector + registers. */ + if (reg_classes_intersect_p (VEC_REGS, rclass) + && ((from_mode == V1TFmode && to_mode == TFmode) + || (from_mode == TFmode && to_mode == V1TFmode))) + return 1; + if (GET_MODE_SIZE (from_mode) == GET_MODE_SIZE (to_mode)) return 0; diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md index 93a0bc6..7e9add7 100644 --- a/gcc/config/s390/s390.md +++ b/gcc/config/s390/s390.md @@ -674,6 +674,12 @@ (define_mode_attr DFDI [(TF "0") (DF "*") (SF "0") (TD "0") (DD "0") (DD "0") (TI "0") (DI "*") (SI "0")]) +(define_mode_attr DF [(TF "0") (DF "*") (SF "0") + (TD "0") (DD "0") (DD "0") + (TI "0") (DI "0") (SI "0")]) +(define_mode_attr SF [(TF "0") (DF "0") (SF "*") + (TD "0") (DD "0") (DD "0") + (TI "0") (DI "0") (SI "0")]) ;; This attribute is used in the operand constraint list ;; for instructions dealing with the sign bit of 32 or 64bit fp values. @@ -1325,20 +1331,21 @@ }) -; cxtr, cdtr, cxbr, cdbr, cebr, cdb, ceb, wfcdb +; VX: TFmode in FPR pairs: use cxbr instead of wfcxb +; cxtr, cdtr, cxbr, cdbr, cebr, cdb, ceb, wfcsb, wfcdb (define_insn "*cmp<mode>_ccs" [(set (reg CC_REGNUM) - (compare (match_operand:FP 0 "register_operand" "f,f,v") - (match_operand:FP 1 "general_operand" "f,R,v")))] + (compare (match_operand:FP 0 "register_operand" "f,f,v,v") + (match_operand:FP 1 "general_operand" "f,R,v,v")))] "s390_match_ccmode(insn, CCSmode) && TARGET_HARD_FLOAT" "@ c<xde><bt>r\t%0,%1 c<xde>b\t%0,%1 - wfcdb\t%0,%1" - [(set_attr "op_type" "RRE,RXE,VRR") - (set_attr "cpu_facility" "*,*,vx") - (set_attr "enabled" "*,<DSF>,<DFDI>")]) - + wfcdb\t%0,%1 + wfcsb\t%0,%1" + [(set_attr "op_type" "RRE,RXE,VRR,VRR") + (set_attr "cpu_facility" "*,*,vx,vxe") + (set_attr "enabled" "*,<DSF>,<DF>,<SF>")]) ; Compare and Branch instructions @@ -5159,6 +5166,7 @@ ; extend(sf|df)(df|tf)2 instruction pattern(s). ; +; wflls (define_insn "*extendsfdf2_z13" [(set (match_operand:DF 0 "register_operand" "=f,f,v") (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "f,R,v")))] @@ -5811,20 +5819,21 @@ ; axbr, adbr, aebr, axb, adb, aeb, adtr, axtr ; FIXME: wfadb does not clobber cc (define_insn "add<mode>3" - [(set (match_operand:FP 0 "register_operand" "=f,f,f,v") - (plus:FP (match_operand:FP 1 "nonimmediate_operand" "%f,0,0,v") - (match_operand:FP 2 "general_operand" "f,f,R,v"))) + [(set (match_operand:FP 0 "register_operand" "=f,f,f,v,v") + (plus:FP (match_operand:FP 1 "nonimmediate_operand" "%f,0,0,v,v") + (match_operand:FP 2 "general_operand" "f,f,R,v,v"))) (clobber (reg:CC CC_REGNUM))] "TARGET_HARD_FLOAT" "@ a<xde>tr\t%0,%1,%2 a<xde>br\t%0,%2 a<xde>b\t%0,%2 - wfadb\t%v0,%v1,%v2" - [(set_attr "op_type" "RRF,RRE,RXE,VRR") + wfadb\t%v0,%v1,%v2 + wfasb\t%v0,%v1,%v2" + [(set_attr "op_type" "RRF,RRE,RXE,VRR,VRR") (set_attr "type" "fsimp<mode>") - (set_attr "cpu_facility" "*,*,*,vx") - (set_attr "enabled" "<nBFP>,<nDFP>,<DSF>,<DFDI>")]) + (set_attr "cpu_facility" "*,*,*,vx,vxe") + (set_attr "enabled" "<nBFP>,<nDFP>,<DSF>,<DF>,<SF>")]) ; axbr, adbr, aebr, axb, adb, aeb, adtr, axtr (define_insn "*add<mode>3_cc" @@ -6249,28 +6258,30 @@ ; sub(tf|df|sf|td|dd)3 instruction pattern(s). ; +; FIXME: (clobber (match_scratch:CC 3 "=c,c,c,X,X")) does not work - why? ; sxbr, sdbr, sebr, sdb, seb, sxtr, sdtr (define_insn "sub<mode>3" - [(set (match_operand:FP 0 "register_operand" "=f,f,f,v") - (minus:FP (match_operand:FP 1 "register_operand" "f,0,0,v") - (match_operand:FP 2 "general_operand" "f,f,R,v"))) + [(set (match_operand:FP 0 "register_operand" "=f,f,f,v,v") + (minus:FP (match_operand:FP 1 "register_operand" "f,0,0,v,v") + (match_operand:FP 2 "general_operand" "f,f,R,v,v"))) (clobber (reg:CC CC_REGNUM))] "TARGET_HARD_FLOAT" "@ s<xde>tr\t%0,%1,%2 s<xde>br\t%0,%2 s<xde>b\t%0,%2 - wfsdb\t%v0,%v1,%v2" - [(set_attr "op_type" "RRF,RRE,RXE,VRR") + wfsdb\t%v0,%v1,%v2 + wfssb\t%v0,%v1,%v2" + [(set_attr "op_type" "RRF,RRE,RXE,VRR,VRR") (set_attr "type" "fsimp<mode>") - (set_attr "cpu_facility" "*,*,*,vx") - (set_attr "enabled" "<nBFP>,<nDFP>,<DSF>,<DFDI>")]) + (set_attr "cpu_facility" "*,*,*,vx,vxe") + (set_attr "enabled" "<nBFP>,<nDFP>,<DSF>,<DF>,<SF>")]) ; sxbr, sdbr, sebr, sdb, seb, sxtr, sdtr (define_insn "*sub<mode>3_cc" [(set (reg CC_REGNUM) (compare (minus:FP (match_operand:FP 1 "nonimmediate_operand" "f,0,0") - (match_operand:FP 2 "general_operand" "f,f,R")) + (match_operand:FP 2 "general_operand" "f,f,R")) (match_operand:FP 3 "const0_operand" ""))) (set (match_operand:FP 0 "register_operand" "=f,f,f") (minus:FP (match_dup 1) (match_dup 2)))] @@ -6736,51 +6747,54 @@ ; mxbr, mdbr, meebr, mxb, mxb, meeb, mdtr, mxtr (define_insn "mul<mode>3" - [(set (match_operand:FP 0 "register_operand" "=f,f,f,v") - (mult:FP (match_operand:FP 1 "nonimmediate_operand" "%f,0,0,v") - (match_operand:FP 2 "general_operand" "f,f,R,v")))] + [(set (match_operand:FP 0 "register_operand" "=f,f,f,v,v") + (mult:FP (match_operand:FP 1 "nonimmediate_operand" "%f,0,0,v,v") + (match_operand:FP 2 "general_operand" "f,f,R,v,v")))] "TARGET_HARD_FLOAT" "@ m<xdee>tr\t%0,%1,%2 m<xdee>br\t%0,%2 m<xdee>b\t%0,%2 - wfmdb\t%v0,%v1,%v2" - [(set_attr "op_type" "RRF,RRE,RXE,VRR") + wfmdb\t%v0,%v1,%v2 + wfmsb\t%v0,%v1,%v2" + [(set_attr "op_type" "RRF,RRE,RXE,VRR,VRR") (set_attr "type" "fmul<mode>") - (set_attr "cpu_facility" "*,*,*,vx") - (set_attr "enabled" "<nBFP>,<nDFP>,<DSF>,<DFDI>")]) + (set_attr "cpu_facility" "*,*,*,vx,vxe") + (set_attr "enabled" "<nBFP>,<nDFP>,<DSF>,<DF>,<SF>")]) ; madbr, maebr, maxb, madb, maeb (define_insn "fma<mode>4" - [(set (match_operand:DSF 0 "register_operand" "=f,f,v") - (fma:DSF (match_operand:DSF 1 "nonimmediate_operand" "%f,f,v") - (match_operand:DSF 2 "nonimmediate_operand" "f,R,v") - (match_operand:DSF 3 "register_operand" "0,0,v")))] + [(set (match_operand:DSF 0 "register_operand" "=f,f,v,v") + (fma:DSF (match_operand:DSF 1 "nonimmediate_operand" "%f,f,v,v") + (match_operand:DSF 2 "nonimmediate_operand" "f,R,v,v") + (match_operand:DSF 3 "register_operand" "0,0,v,v")))] "TARGET_HARD_FLOAT" "@ ma<xde>br\t%0,%1,%2 ma<xde>b\t%0,%1,%2 - wfmadb\t%v0,%v1,%v2,%v3" - [(set_attr "op_type" "RRE,RXE,VRR") + wfmadb\t%v0,%v1,%v2,%v3 + wfmasb\t%v0,%v1,%v2,%v3" + [(set_attr "op_type" "RRE,RXE,VRR,VRR") (set_attr "type" "fmadd<mode>") - (set_attr "cpu_facility" "*,*,vx") - (set_attr "enabled" "*,*,<DFDI>")]) + (set_attr "cpu_facility" "*,*,vx,vxe") + (set_attr "enabled" "*,*,<DF>,<SF>")]) ; msxbr, msdbr, msebr, msxb, msdb, mseb (define_insn "fms<mode>4" - [(set (match_operand:DSF 0 "register_operand" "=f,f,v") - (fma:DSF (match_operand:DSF 1 "nonimmediate_operand" "%f,f,v") - (match_operand:DSF 2 "nonimmediate_operand" "f,R,v") - (neg:DSF (match_operand:DSF 3 "register_operand" "0,0,v"))))] + [(set (match_operand:DSF 0 "register_operand" "=f,f,v,v") + (fma:DSF (match_operand:DSF 1 "nonimmediate_operand" "%f,f,v,v") + (match_operand:DSF 2 "nonimmediate_operand" "f,R,v,v") + (neg:DSF (match_operand:DSF 3 "register_operand" "0,0,v,v"))))] "TARGET_HARD_FLOAT" "@ ms<xde>br\t%0,%1,%2 ms<xde>b\t%0,%1,%2 - wfmsdb\t%v0,%v1,%v2,%v3" - [(set_attr "op_type" "RRE,RXE,VRR") + wfmsdb\t%v0,%v1,%v2,%v3 + wfmssb\t%v0,%v1,%v2,%v3" + [(set_attr "op_type" "RRE,RXE,VRR,VRR") (set_attr "type" "fmadd<mode>") - (set_attr "cpu_facility" "*,*,vx") - (set_attr "enabled" "*,*,<DFDI>")]) + (set_attr "cpu_facility" "*,*,vx,vxe") + (set_attr "enabled" "*,*,<DF>,<SF>")]) ;; ;;- Divide and modulo instructions. @@ -7212,19 +7226,20 @@ ; dxbr, ddbr, debr, dxb, ddb, deb, ddtr, dxtr (define_insn "div<mode>3" - [(set (match_operand:FP 0 "register_operand" "=f,f,f,v") - (div:FP (match_operand:FP 1 "register_operand" "f,0,0,v") - (match_operand:FP 2 "general_operand" "f,f,R,v")))] + [(set (match_operand:FP 0 "register_operand" "=f,f,f,v,v") + (div:FP (match_operand:FP 1 "register_operand" "f,0,0,v,v") + (match_operand:FP 2 "general_operand" "f,f,R,v,v")))] "TARGET_HARD_FLOAT" "@ d<xde>tr\t%0,%1,%2 d<xde>br\t%0,%2 d<xde>b\t%0,%2 - wfddb\t%v0,%v1,%v2" - [(set_attr "op_type" "RRF,RRE,RXE,VRR") + wfddb\t%v0,%v1,%v2 + wfdsb\t%v0,%v1,%v2" + [(set_attr "op_type" "RRF,RRE,RXE,VRR,VRR") (set_attr "type" "fdiv<mode>") - (set_attr "cpu_facility" "*,*,*,vx") - (set_attr "enabled" "<nBFP>,<nDFP>,<DSF>,<DFDI>")]) + (set_attr "cpu_facility" "*,*,*,vx,vxe") + (set_attr "enabled" "<nBFP>,<nDFP>,<DSF>,<DF>,<SF>")]) ;; @@ -8423,11 +8438,10 @@ (define_expand "neg<mode>2" [(parallel - [(set (match_operand:BFP 0 "register_operand" "=f") - (neg:BFP (match_operand:BFP 1 "register_operand" "f"))) + [(set (match_operand:BFP 0 "register_operand") + (neg:BFP (match_operand:BFP 1 "register_operand"))) (clobber (reg:CC CC_REGNUM))])] - "TARGET_HARD_FLOAT" - "") + "TARGET_HARD_FLOAT") ; lcxbr, lcdbr, lcebr (define_insn "*neg<mode>2_cc" @@ -8463,18 +8477,20 @@ ; lcxbr, lcdbr, lcebr ; FIXME: wflcdb does not clobber cc +; FIXME: Does wflcdb ever match here? (define_insn "*neg<mode>2" - [(set (match_operand:BFP 0 "register_operand" "=f,v") - (neg:BFP (match_operand:BFP 1 "register_operand" "f,v"))) + [(set (match_operand:BFP 0 "register_operand" "=f,v,v") + (neg:BFP (match_operand:BFP 1 "register_operand" "f,v,v"))) (clobber (reg:CC CC_REGNUM))] "TARGET_HARD_FLOAT" "@ lc<xde>br\t%0,%1 - wflcdb\t%0,%1" - [(set_attr "op_type" "RRE,VRR") - (set_attr "cpu_facility" "*,vx") - (set_attr "type" "fsimp<mode>,*") - (set_attr "enabled" "*,<DFDI>")]) + wflcdb\t%0,%1 + wflcsb\t%0,%1" + [(set_attr "op_type" "RRE,VRR,VRR") + (set_attr "cpu_facility" "*,vx,vxe") + (set_attr "type" "fsimp<mode>,*,*") + (set_attr "enabled" "*,<DF>,<SF>")]) ;; diff --git a/gcc/config/s390/vector.md b/gcc/config/s390/vector.md index 6a726a3..7535b9d 100644 --- a/gcc/config/s390/vector.md +++ b/gcc/config/s390/vector.md @@ -26,16 +26,16 @@ [V1QI V2QI V4QI V8QI V16QI V1HI V2HI V4HI V8HI V1SI V2SI V4SI V1DI V2DI V1SF V2SF V4SF V1DF V2DF V1TF V1TI TI]) -; All vector modes directly supported by the hardware having full vector reg size +; All modes directly supported by the hardware having full vector reg size ; V_HW2 is duplicate of V_HW for having two iterators expanding ; independently e.g. vcond -(define_mode_iterator V_HW [V16QI V8HI V4SI V2DI V2DF]) -(define_mode_iterator V_HW2 [V16QI V8HI V4SI V2DI V2DF]) +(define_mode_iterator V_HW [V16QI V8HI V4SI V2DI V2DF (V4SF "TARGET_VXE") (V1TF "TARGET_VXE")]) +(define_mode_iterator V_HW2 [V16QI V8HI V4SI V2DI V2DF (V4SF "TARGET_VXE") (V1TF "TARGET_VXE")]) (define_mode_iterator V_HW_64 [V2DI V2DF]) ; Including TI for instructions that support it (va, vn, ...) -(define_mode_iterator VT_HW [V16QI V8HI V4SI V2DI V2DF V1TI TI]) +(define_mode_iterator VT_HW [V16QI V8HI V4SI V2DI V2DF V1TI TI (V4SF "TARGET_VXE") (V1TF "TARGET_VXE")]) ; All full size integer vector modes supported in a vector register + TImode (define_mode_iterator VIT_HW [V16QI V8HI V4SI V2DI V1TI TI]) @@ -51,6 +51,15 @@ (define_mode_iterator VI [V1QI V2QI V4QI V8QI V16QI V1HI V2HI V4HI V8HI V1SI V2SI V4SI V1DI V2DI]) (define_mode_iterator VI_QHS [V1QI V2QI V4QI V8QI V16QI V1HI V2HI V4HI V8HI V1SI V2SI V4SI]) +(define_mode_iterator VFT [(V1SF "TARGET_VXE") (V2SF "TARGET_VXE") (V4SF "TARGET_VXE") + V1DF V2DF + (V1TF "TARGET_VXE")]) + +; FP vector modes directly supported by the HW. This does not include +; vector modes using only part of a vector register and should be used +; for instructions which might trigger IEEE exceptions. +(define_mode_iterator VF_HW [(V4SF "TARGET_VXE") V2DF (V1TF "TARGET_VXE")]) + (define_mode_iterator V_8 [V1QI]) (define_mode_iterator V_16 [V2QI V1HI]) (define_mode_iterator V_32 [V4QI V2HI V1SI V1SF]) @@ -59,26 +68,30 @@ (define_mode_iterator V_128_NOSINGLE [V16QI V8HI V4SI V4SF V2DI V2DF]) -; A blank for vector modes and a * for TImode. This is used to hide -; the TImode expander name in case it is defined already. See addti3 -; for an example. -(define_mode_attr ti* [(V1QI "") (V2QI "") (V4QI "") (V8QI "") (V16QI "") - (V1HI "") (V2HI "") (V4HI "") (V8HI "") - (V1SI "") (V2SI "") (V4SI "") - (V1DI "") (V2DI "") - (V1TI "*") (TI "*")]) +; Empty string for all but TImode. This is used to hide the TImode +; expander name in case it is defined already. See addti3 for an +; example. +(define_mode_attr ti* [(V1QI "") (V2QI "") (V4QI "") (V8QI "") (V16QI "") + (V1HI "") (V2HI "") (V4HI "") (V8HI "") + (V1SI "") (V2SI "") (V4SI "") + (V1DI "") (V2DI "") + (V1TI "") (TI "*") + (V1SF "") (V2SF "") (V4SF "") + (V1DF "") (V2DF "") + (V1TF "") (TF "")]) ; The element type of the vector. (define_mode_attr non_vec[(V1QI "QI") (V2QI "QI") (V4QI "QI") (V8QI "QI") (V16QI "QI") (V1HI "HI") (V2HI "HI") (V4HI "HI") (V8HI "HI") (V1SI "SI") (V2SI "SI") (V4SI "SI") (V1DI "DI") (V2DI "DI") - (V1TI "TI") + (V1TI "TI") (TI "TI") (V1SF "SF") (V2SF "SF") (V4SF "SF") (V1DF "DF") (V2DF "DF") - (V1TF "TF")]) + (V1TF "TF") (TF "TF")]) -; The instruction suffix +; The instruction suffix for integer instructions and instructions +; which do not care about whether it is floating point or integer. (define_mode_attr bhfgq[(V1QI "b") (V2QI "b") (V4QI "b") (V8QI "b") (V16QI "b") (V1HI "h") (V2HI "h") (V4HI "h") (V8HI "h") (V1SI "f") (V2SI "f") (V4SI "f") @@ -105,6 +118,13 @@ (V1SF "V1SI") (V2SF "V2SI") (V4SF "V4SI") (V1DF "V1DI") (V2DF "V2DI") (V1TF "V1TI")]) +(define_mode_attr vw [(SF "w") (V1SF "w") (V2SF "v") (V4SF "v") + (DF "w") (V1DF "w") (V2DF "v") + (TF "w") (V1TF "w")]) + +(define_mode_attr sdx [(SF "s") (V1SF "s") (V2SF "s") (V4SF "s") + (DF "d") (V1DF "d") (V2DF "d") + (TF "x") (V1TF "x")]) ; Vector with doubled element size. (define_mode_attr vec_double [(V1QI "V1HI") (V2QI "V1HI") (V4QI "V2HI") (V8QI "V4HI") (V16QI "V8HI") @@ -1029,92 +1049,139 @@ ;; Vector floating point arithmetic instructions ;; -(define_insn "addv2df3" - [(set (match_operand:V2DF 0 "register_operand" "=v") - (plus:V2DF (match_operand:V2DF 1 "register_operand" "%v") - (match_operand:V2DF 2 "register_operand" "v")))] +; vfasb, vfadb, wfasb, wfadb, wfaxb +(define_insn "add<mode>3" + [(set (match_operand:VF_HW 0 "register_operand" "=v") + (plus:VF_HW (match_operand:VF_HW 1 "register_operand" "%v") + (match_operand:VF_HW 2 "register_operand" "v")))] "TARGET_VX" - "vfadb\t%v0,%v1,%v2" + "<vw>fa<sdx>b\t%v0,%v1,%v2" [(set_attr "op_type" "VRR")]) -(define_insn "subv2df3" - [(set (match_operand:V2DF 0 "register_operand" "=v") - (minus:V2DF (match_operand:V2DF 1 "register_operand" "%v") - (match_operand:V2DF 2 "register_operand" "v")))] +; vfssb, vfsdb, wfssb, wfsdb, wfsxb +(define_insn "sub<mode>3" + [(set (match_operand:VF_HW 0 "register_operand" "=v") + (minus:VF_HW (match_operand:VF_HW 1 "register_operand" "%v") + (match_operand:VF_HW 2 "register_operand" "v")))] "TARGET_VX" - "vfsdb\t%v0,%v1,%v2" + "<vw>fs<sdx>b\t%v0,%v1,%v2" [(set_attr "op_type" "VRR")]) -(define_insn "mulv2df3" - [(set (match_operand:V2DF 0 "register_operand" "=v") - (mult:V2DF (match_operand:V2DF 1 "register_operand" "%v") - (match_operand:V2DF 2 "register_operand" "v")))] +; vfmsb, vfmdb, wfmsb, wfmdb, wfmxb +(define_insn "mul<mode>3" + [(set (match_operand:VF_HW 0 "register_operand" "=v") + (mult:VF_HW (match_operand:VF_HW 1 "register_operand" "%v") + (match_operand:VF_HW 2 "register_operand" "v")))] "TARGET_VX" - "vfmdb\t%v0,%v1,%v2" + "<vw>fm<sdx>b\t%v0,%v1,%v2" [(set_attr "op_type" "VRR")]) -(define_insn "divv2df3" - [(set (match_operand:V2DF 0 "register_operand" "=v") - (div:V2DF (match_operand:V2DF 1 "register_operand" "v") - (match_operand:V2DF 2 "register_operand" "v")))] +; vfdsb, vfddb, wfdsb, wfddb, wfdxb +(define_insn "div<mode>3" + [(set (match_operand:VF_HW 0 "register_operand" "=v") + (div:VF_HW (match_operand:VF_HW 1 "register_operand" "v") + (match_operand:VF_HW 2 "register_operand" "v")))] "TARGET_VX" - "vfddb\t%v0,%v1,%v2" + "<vw>fd<sdx>b\t%v0,%v1,%v2" [(set_attr "op_type" "VRR")]) -(define_insn "sqrtv2df2" - [(set (match_operand:V2DF 0 "register_operand" "=v") - (sqrt:V2DF (match_operand:V2DF 1 "register_operand" "v")))] +; vfsqsb, vfsqdb, wfsqsb, wfsqdb, wfsqxb +(define_insn "sqrt<mode>2" + [(set (match_operand:VF_HW 0 "register_operand" "=v") + (sqrt:VF_HW (match_operand:VF_HW 1 "register_operand" "v")))] "TARGET_VX" - "vfsqdb\t%v0,%v1" + "<vw>fsq<sdx>b\t%v0,%v1" [(set_attr "op_type" "VRR")]) -(define_insn "fmav2df4" - [(set (match_operand:V2DF 0 "register_operand" "=v") - (fma:V2DF (match_operand:V2DF 1 "register_operand" "%v") - (match_operand:V2DF 2 "register_operand" "v") - (match_operand:V2DF 3 "register_operand" "v")))] +; vfmasb, vfmadb, wfmasb, wfmadb, wfmaxb +(define_insn "fma<mode>4" + [(set (match_operand:VF_HW 0 "register_operand" "=v") + (fma:VF_HW (match_operand:VF_HW 1 "register_operand" "%v") + (match_operand:VF_HW 2 "register_operand" "v") + (match_operand:VF_HW 3 "register_operand" "v")))] "TARGET_VX" - "vfmadb\t%v0,%v1,%v2,%v3" + "<vw>fma<sdx>b\t%v0,%v1,%v2,%v3" [(set_attr "op_type" "VRR")]) -(define_insn "fmsv2df4" - [(set (match_operand:V2DF 0 "register_operand" "=v") - (fma:V2DF (match_operand:V2DF 1 "register_operand" "%v") - (match_operand:V2DF 2 "register_operand" "v") - (neg:V2DF (match_operand:V2DF 3 "register_operand" "v"))))] +; vfmssb, vfmsdb, wfmssb, wfmsdb, wfmsxb +(define_insn "fms<mode>4" + [(set (match_operand:VF_HW 0 "register_operand" "=v") + (fma:VF_HW (match_operand:VF_HW 1 "register_operand" "%v") + (match_operand:VF_HW 2 "register_operand" "v") + (neg:VF_HW (match_operand:VF_HW 3 "register_operand" "v"))))] "TARGET_VX" - "vfmsdb\t%v0,%v1,%v2,%v3" + "<vw>fms<sdx>b\t%v0,%v1,%v2,%v3" + [(set_attr "op_type" "VRR")]) + +; vfnmasb, vfnmadb, wfnmasb, wfnmadb, wfnmaxb +(define_insn "neg_fma<mode>4" + [(set (match_operand:VF_HW 0 "register_operand" "=v") + (neg:VF_HW + (fma:VF_HW (match_operand:VF_HW 1 "register_operand" "%v") + (match_operand:VF_HW 2 "register_operand" "v") + (match_operand:VF_HW 3 "register_operand" "v"))))] + "TARGET_VXE" + "<vw>fnma<sdx>b\t%v0,%v1,%v2,%v3" + [(set_attr "op_type" "VRR")]) + +; vfnmssb, vfnmsdb, wfnmssb, wfnmsdb, wfnmsxb +(define_insn "neg_fms<mode>4" + [(set (match_operand:VF_HW 0 "register_operand" "=v") + (neg:VF_HW + (fma:VF_HW (match_operand:VF_HW 1 "register_operand" "%v") + (match_operand:VF_HW 2 "register_operand" "v") + (neg:VF_HW (match_operand:VF_HW 3 "register_operand" "v")))))] + "TARGET_VXE" + "<vw>fnms<sdx>b\t%v0,%v1,%v2,%v3" [(set_attr "op_type" "VRR")]) -(define_insn "negv2df2" - [(set (match_operand:V2DF 0 "register_operand" "=v") - (neg:V2DF (match_operand:V2DF 1 "register_operand" "v")))] +; vflcsb, vflcdb, wflcsb, wflcdb, wflcxb +(define_insn "neg<mode>2" + [(set (match_operand:VFT 0 "register_operand" "=v") + (neg:VFT (match_operand:VFT 1 "register_operand" "v")))] "TARGET_VX" - "vflcdb\t%v0,%v1" + "<vw>flc<sdx>b\t%v0,%v1" [(set_attr "op_type" "VRR")]) -(define_insn "absv2df2" - [(set (match_operand:V2DF 0 "register_operand" "=v") - (abs:V2DF (match_operand:V2DF 1 "register_operand" "v")))] +; vflpsb, vflpdb, wflpsb, wflpdb, wflpxb +(define_insn "abs<mode>2" + [(set (match_operand:VFT 0 "register_operand" "=v") + (abs:VFT (match_operand:VFT 1 "register_operand" "v")))] "TARGET_VX" - "vflpdb\t%v0,%v1" + "<vw>flp<sdx>b\t%v0,%v1" [(set_attr "op_type" "VRR")]) -(define_insn "*negabsv2df2" - [(set (match_operand:V2DF 0 "register_operand" "=v") - (neg:V2DF (abs:V2DF (match_operand:V2DF 1 "register_operand" "v"))))] +; vflnsb, vflndb, wflnsb, wflndb, wflnxb +(define_insn "negabs<mode>2" + [(set (match_operand:VFT 0 "register_operand" "=v") + (neg:VFT (abs:VFT (match_operand:VFT 1 "register_operand" "v"))))] "TARGET_VX" - "vflndb\t%v0,%v1" + "<vw>fln<sdx>b\t%v0,%v1" + [(set_attr "op_type" "VRR")]) + +(define_expand "smax<mode>3" + [(set (match_operand:VF_HW 0 "register_operand") + (smax:VF_HW (match_operand:VF_HW 1 "register_operand") + (match_operand:VF_HW 2 "register_operand")))] + "TARGET_VX") + +; vfmaxsb, vfmaxdb, wfmaxsb, wfmaxdb, wfmaxxb +(define_insn "*smax<mode>3_vxe" + [(set (match_operand:VF_HW 0 "register_operand" "=v") + (smax:VF_HW (match_operand:VF_HW 1 "register_operand" "%v") + (match_operand:VF_HW 2 "register_operand" "v")))] + "TARGET_VXE" + "<vw>fmax<sdx>b\t%v0,%v1,%v2,4" [(set_attr "op_type" "VRR")]) ; Emulate with compare + select -(define_insn_and_split "smaxv2df3" +(define_insn_and_split "*smaxv2df3_vx" [(set (match_operand:V2DF 0 "register_operand" "=v") (smax:V2DF (match_operand:V2DF 1 "register_operand" "%v") (match_operand:V2DF 2 "register_operand" "v")))] - "TARGET_VX" + "TARGET_VX && !TARGET_VXE" "#" - "" + "&& 1" [(set (match_dup 3) (gt:V2DI (match_dup 1) (match_dup 2))) (set (match_dup 0) @@ -1127,14 +1194,29 @@ operands[4] = CONST0_RTX (V2DImode); }) +(define_expand "smin<mode>3" + [(set (match_operand:VF_HW 0 "register_operand") + (smin:VF_HW (match_operand:VF_HW 1 "register_operand") + (match_operand:VF_HW 2 "register_operand")))] + "TARGET_VX") + +; vfminsb, vfmindb, wfminsb, wfmindb, wfminxb +(define_insn "*smin<mode>3_vxe" + [(set (match_operand:VF_HW 0 "register_operand" "=v") + (smin:VF_HW (match_operand:VF_HW 1 "register_operand" "%v") + (match_operand:VF_HW 2 "register_operand" "v")))] + "TARGET_VXE" + "<vw>fmin<sdx>b\t%v0,%v1,%v2,4" + [(set_attr "op_type" "VRR")]) + ; Emulate with compare + select -(define_insn_and_split "sminv2df3" +(define_insn_and_split "*sminv2df3_vx" [(set (match_operand:V2DF 0 "register_operand" "=v") (smin:V2DF (match_operand:V2DF 1 "register_operand" "%v") (match_operand:V2DF 2 "register_operand" "v")))] - "TARGET_VX" + "TARGET_VX && !TARGET_VXE" "#" - "" + "&& 1" [(set (match_dup 3) (gt:V2DI (match_dup 1) (match_dup 2))) (set (match_dup 0) @@ -1166,65 +1248,66 @@ ;; ; EQ, GT, GE -(define_insn "*vec_cmp<VFCMP_HW_OP:code>v2df_nocc" - [(set (match_operand:V2DI 0 "register_operand" "=v") - (VFCMP_HW_OP:V2DI (match_operand:V2DF 1 "register_operand" "v") - (match_operand:V2DF 2 "register_operand" "v")))] +; vfcesb, vfcedb, wfcexb, vfchsb, vfchdb, wfchxb, vfchesb, vfchedb, wfchexb +(define_insn "*vec_cmp<VFCMP_HW_OP:code><mode>_nocc" + [(set (match_operand:<tointvec> 0 "register_operand" "=v") + (VFCMP_HW_OP:<tointvec> (match_operand:VFT 1 "register_operand" "v") + (match_operand:VFT 2 "register_operand" "v")))] "TARGET_VX" - "vfc<VFCMP_HW_OP:asm_fcmp_op>db\t%v0,%v1,%v2" + "<vw>fc<VFCMP_HW_OP:asm_fcmp_op><sdx>b\t%v0,%v1,%v2" [(set_attr "op_type" "VRR")]) ; Expanders for not directly supported comparisons ; UNEQ a u== b -> !(a > b | b > a) -(define_expand "vec_cmpuneqv2df" - [(set (match_operand:V2DI 0 "register_operand" "=v") - (gt:V2DI (match_operand:V2DF 1 "register_operand" "v") - (match_operand:V2DF 2 "register_operand" "v"))) +(define_expand "vec_cmpuneq<mode>" + [(set (match_operand:<tointvec> 0 "register_operand" "=v") + (gt:<tointvec> (match_operand:VFT 1 "register_operand" "v") + (match_operand:VFT 2 "register_operand" "v"))) (set (match_dup 3) - (gt:V2DI (match_dup 2) (match_dup 1))) - (set (match_dup 0) (ior:V2DI (match_dup 0) (match_dup 3))) - (set (match_dup 0) (not:V2DI (match_dup 0)))] + (gt:<tointvec> (match_dup 2) (match_dup 1))) + (set (match_dup 0) (ior:<tointvec> (match_dup 0) (match_dup 3))) + (set (match_dup 0) (not:<tointvec> (match_dup 0)))] "TARGET_VX" { - operands[3] = gen_reg_rtx (V2DImode); + operands[3] = gen_reg_rtx (<tointvec>mode); }) ; LTGT a <> b -> a > b | b > a -(define_expand "vec_cmpltgtv2df" - [(set (match_operand:V2DI 0 "register_operand" "=v") - (gt:V2DI (match_operand:V2DF 1 "register_operand" "v") - (match_operand:V2DF 2 "register_operand" "v"))) - (set (match_dup 3) (gt:V2DI (match_dup 2) (match_dup 1))) - (set (match_dup 0) (ior:V2DI (match_dup 0) (match_dup 3)))] +(define_expand "vec_cmpltgt<mode>" + [(set (match_operand:<tointvec> 0 "register_operand" "=v") + (gt:<tointvec> (match_operand:VFT 1 "register_operand" "v") + (match_operand:VFT 2 "register_operand" "v"))) + (set (match_dup 3) (gt:<tointvec> (match_dup 2) (match_dup 1))) + (set (match_dup 0) (ior:<tointvec> (match_dup 0) (match_dup 3)))] "TARGET_VX" { - operands[3] = gen_reg_rtx (V2DImode); + operands[3] = gen_reg_rtx (<tointvec>mode); }) ; ORDERED (a, b): a >= b | b > a -(define_expand "vec_orderedv2df" - [(set (match_operand:V2DI 0 "register_operand" "=v") - (ge:V2DI (match_operand:V2DF 1 "register_operand" "v") - (match_operand:V2DF 2 "register_operand" "v"))) - (set (match_dup 3) (gt:V2DI (match_dup 2) (match_dup 1))) - (set (match_dup 0) (ior:V2DI (match_dup 0) (match_dup 3)))] +(define_expand "vec_ordered<mode>" + [(set (match_operand:<tointvec> 0 "register_operand" "=v") + (ge:<tointvec> (match_operand:VFT 1 "register_operand" "v") + (match_operand:VFT 2 "register_operand" "v"))) + (set (match_dup 3) (gt:<tointvec> (match_dup 2) (match_dup 1))) + (set (match_dup 0) (ior:<tointvec> (match_dup 0) (match_dup 3)))] "TARGET_VX" { - operands[3] = gen_reg_rtx (V2DImode); + operands[3] = gen_reg_rtx (<tointvec>mode); }) ; UNORDERED (a, b): !ORDERED (a, b) -(define_expand "vec_unorderedv2df" - [(set (match_operand:V2DI 0 "register_operand" "=v") - (ge:V2DI (match_operand:V2DF 1 "register_operand" "v") - (match_operand:V2DF 2 "register_operand" "v"))) - (set (match_dup 3) (gt:V2DI (match_dup 2) (match_dup 1))) - (set (match_dup 0) (ior:V2DI (match_dup 0) (match_dup 3))) - (set (match_dup 0) (not:V2DI (match_dup 0)))] +(define_expand "vec_unordered<mode>" + [(set (match_operand:<tointvec> 0 "register_operand" "=v") + (ge:<tointvec> (match_operand:VFT 1 "register_operand" "v") + (match_operand:VFT 2 "register_operand" "v"))) + (set (match_dup 3) (gt:<tointvec> (match_dup 2) (match_dup 1))) + (set (match_dup 0) (ior:<tointvec> (match_dup 0) (match_dup 3))) + (set (match_dup 0) (not:<tointvec> (match_dup 0)))] "TARGET_VX" { - operands[3] = gen_reg_rtx (V2DImode); + operands[3] = gen_reg_rtx (<tointvec>mode); }) (define_insn "*vec_load_pair<mode>" @@ -1563,6 +1646,28 @@ "vupllf\t%0,%1" [(set_attr "op_type" "VRR")]) +;; vector load lengthened + +; vflls +(define_insn "*vec_extendv4sf" + [(set (match_operand:V2DF 0 "register_operand" "=v") + (float_extend:V2DF + (vec_select:V2SF + (match_operand:V4SF 1 "register_operand" "v") + (parallel [(const_int 0) (const_int 2)]))))] + "TARGET_VX" + "vldeb\t%v0,%v1" + [(set_attr "op_type" "VRR")]) + +(define_insn "*vec_extendv2df" + [(set (match_operand:V1TF 0 "register_operand" "=v") + (float_extend:V1TF + (vec_select:V1DF + (match_operand:V2DF 1 "register_operand" "v") + (parallel [(const_int 0)]))))] + "TARGET_VXE" + "wflld\t%v0,%v1" + [(set_attr "op_type" "VRR")]) ; reduc_smin ; reduc_smax diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 9247f53..b843b78 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,9 @@ 2017-03-24 Andreas Krebbel <kreb...@linux.vnet.ibm.com> + * gcc.target/s390/vxe/negfma-1.c: New test. + +2017-03-24 Andreas Krebbel <kreb...@linux.vnet.ibm.com> + * gcc.target/s390/arch12/aghsghmgh-1.c: New test. * gcc.target/s390/arch12/mul-1.c: New test. * gcc.target/s390/arch12/mul-2.c: New test. diff --git a/gcc/testsuite/gcc.target/s390/vxe/negfma-1.c b/gcc/testsuite/gcc.target/s390/vxe/negfma-1.c new file mode 100644 index 0000000..4c976b0 --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/vxe/negfma-1.c @@ -0,0 +1,49 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -mzarch -march=arch12" } */ + +typedef float v4sf __attribute__((vector_size(16))); +typedef double v2df __attribute__((vector_size(16))); +typedef long double v1tf __attribute__((vector_size(16))); + +v4sf +neg_vfnmasb (v4sf a, v4sf b, v4sf c) +{ + return -(a * b + c); +} +/* { dg-final { scan-assembler-times "vfnmasb\t%v24,%v24,%v26,%v28" 1 } } */ + +v2df +neg_vfnmadb (v2df a, v2df b, v2df c) +{ + return -(a * b + c); +} +/* { dg-final { scan-assembler-times "vfnmadb\t%v24,%v24,%v26,%v28" 1 } } */ + +v1tf +neg_wfnmaxb (v1tf a, v1tf b, v1tf c) +{ + return -(a * b + c); +} +/* { dg-final { scan-assembler-times "wfnmaxb\t%v24,%v24,%v26,%v28" 1 } } */ + + +v4sf +neg_vfnmssb (v4sf a, v4sf b, v4sf c) +{ + return -(a * b - c); +} +/* { dg-final { scan-assembler-times "vfnmssb\t%v24,%v24,%v26,%v28" 1 } } */ + +v2df +neg_vfnmsdb (v2df a, v2df b, v2df c) +{ + return -(a * b - c); +} +/* { dg-final { scan-assembler-times "vfnmsdb\t%v24,%v24,%v26,%v28" 1 } } */ + +v1tf +neg_wfnmsxb (v1tf a, v1tf b, v1tf c) +{ + return -(a * b - c); +} +/* { dg-final { scan-assembler-times "wfnmsxb\t%v24,%v24,%v26,%v28" 1 } } */ -- 2.9.1