From: Michael Meissner Date: Thu, 26 May 2016 21:38:19 +0000 (+0000) Subject: rs6000.c (rs6000_emit_p9_fp_minmax): New function for ISA 3.0 min/max support. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=2131632019af9fc851ef55a0351df196219feaf6;p=gcc.git rs6000.c (rs6000_emit_p9_fp_minmax): New function for ISA 3.0 min/max support. [gcc] 2016-05-26 Michael Meissner * config/rs6000/rs6000.c (rs6000_emit_p9_fp_minmax): New function for ISA 3.0 min/max support. (rs6000_emit_p9_fp_cmove): New function for ISA 3.0 floating point conditional move support. (rs6000_emit_cmove): Call rs6000_emit_p9_fp_minmax and rs6000_emit_p9_fp_cmove if the ISA 3.0 instructions are available. * config/rs6000/rs6000.md (SFDF2): New iterator to allow doing conditional moves where the comparison type is different from move type. (fp_minmax): New code iterator for smin/smax. (minmax): New code attributes for min/max. (SMINMAX): Likewise. (smax3): Combine min, max insns into one insn using the fp_minmax code iterator. Add support for ISA 3.0 min/max instructions that don't need -ffast-math. (s3): Likewise. (smax3_vsx): Likewise. (smin3): Likewise. (s3_vsx): Likewise. (smin3_vsx): Likewise. (pre-VSX min/max splitters): Likewise. (s3_fpr): Likewise. (movsfcc): Rewrite floating point conditional moves to combine SFmode/DFmode into a single insn. (movcc): Likewise. (movdfcc): Likewise. (fselsfsf4): Combine FSEL cases into a single insn, using SFDF and SFDF2 iterators to handle all combinations. (fseldfsf4): Likewise. (fsel4): Likewise. (fseldfdf4): Likewise. (fselsfdf4): Likewise. (movcc_p9): Add support for the ISA 3.0 comparison instructions that set a 0/-1 mask, and use it for floating point conditional move via XXSEL. (fpmask): Likewise. (xxsel): Likewise. * config/rs6000/predicates.md (min_max_operator): Delete, no longer used. (fpmask_comparison_operaton): New insn for ISA 3.0 comparison instructions that generate a 0/-1 mask for use with XXSEL. * config/rs6000/rs6000.h (TARGET_MINMAX_SF): New helper macros to say whether floating point min/max is available, either through FSEL, ISA 2.06 min/max, and ISA 3.0 min/max instrucitons. (TARGET_MINMAX_DF): Likewise. [gcc/testsuite] 2016-05-26 Michael Meissner * gcc.target/powerpc/p9-minmax-1.c: New tests for ISA 3.0 floating point min/max/comparison instructions. * gcc.target/powerpc/p9-minmax-2.c: Likewise. From-SVN: r236795 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 30c86158de8..ab5d2e92662 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,52 @@ +2016-05-26 Michael Meissner + + * config/rs6000/rs6000.c (rs6000_emit_p9_fp_minmax): New function + for ISA 3.0 min/max support. + (rs6000_emit_p9_fp_cmove): New function for ISA 3.0 floating point + conditional move support. + (rs6000_emit_cmove): Call rs6000_emit_p9_fp_minmax and + rs6000_emit_p9_fp_cmove if the ISA 3.0 instructions are + available. + * config/rs6000/rs6000.md (SFDF2): New iterator to allow doing + conditional moves where the comparison type is different from move + type. + (fp_minmax): New code iterator for smin/smax. + (minmax): New code attributes for min/max. + (SMINMAX): Likewise. + (smax3): Combine min, max insns into one insn using the + fp_minmax code iterator. Add support for ISA 3.0 min/max + instructions that don't need -ffast-math. + (s3): Likewise. + (smax3_vsx): Likewise. + (smin3): Likewise. + (s3_vsx): Likewise. + (smin3_vsx): Likewise. + (pre-VSX min/max splitters): Likewise. + (s3_fpr): Likewise. + (movsfcc): Rewrite floating point conditional moves to combine + SFmode/DFmode into a single insn. + (movcc): Likewise. + (movdfcc): Likewise. + (fselsfsf4): Combine FSEL cases into a single insn, using SFDF and + SFDF2 iterators to handle all combinations. + (fseldfsf4): Likewise. + (fsel4): Likewise. + (fseldfdf4): Likewise. + (fselsfdf4): Likewise. + (movcc_p9): Add support for the ISA 3.0 + comparison instructions that set a 0/-1 mask, and use it for + floating point conditional move via XXSEL. + (fpmask): Likewise. + (xxsel): Likewise. + * config/rs6000/predicates.md (min_max_operator): Delete, no + longer used. + (fpmask_comparison_operaton): New insn for ISA 3.0 comparison + instructions that generate a 0/-1 mask for use with XXSEL. + * config/rs6000/rs6000.h (TARGET_MINMAX_SF): New helper macros to + say whether floating point min/max is available, either through + FSEL, ISA 2.06 min/max, and ISA 3.0 min/max instrucitons. + (TARGET_MINMAX_DF): Likewise. + 2016-05-27 Alan Modra PR rtl-optimization/71275 diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md index 5b852a12c21..ed3e84ebb14 100644 --- a/gcc/config/rs6000/predicates.md +++ b/gcc/config/rs6000/predicates.md @@ -1109,10 +1109,6 @@ (define_special_predicate "equality_operator" (match_code "eq,ne")) -;; Return true if operand is MIN or MAX operator. -(define_predicate "min_max_operator" - (match_code "smin,smax,umin,umax")) - ;; Return 1 if OP is a comparison operation that is valid for a branch ;; instruction. We check the opcode against the mode of the CC value. ;; validate_condition_mode is an assertion. @@ -1155,6 +1151,11 @@ (and (match_operand 0 "branch_comparison_operator") (match_code "ne,le,ge,leu,geu,ordered"))) +;; Return 1 if OP is a comparison operator suitable for vector/scalar +;; comparisons that generate a -1/0 mask. +(define_predicate "fpmask_comparison_operator" + (match_code "eq,gt,ge")) + ;; Return 1 if OP is a comparison operation that is valid for a branch ;; insn, which is true if the corresponding bit in the CC register is set. (define_predicate "branch_positive_comparison_operator" diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index af897053d9c..c6b2b6ad4f4 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -22643,6 +22643,101 @@ rs6000_emit_vector_cond_expr (rtx dest, rtx op_true, rtx op_false, return 1; } +/* ISA 3.0 (power9) minmax subcase to emit a XSMAXCDP or XSMINCDP instruction + for SF/DF scalars. Move TRUE_COND to DEST if OP of the operands of the last + comparison is nonzero/true, FALSE_COND if it is zero/false. Return 0 if the + hardware has no such operation. */ + +static int +rs6000_emit_p9_fp_minmax (rtx dest, rtx op, rtx true_cond, rtx false_cond) +{ + enum rtx_code code = GET_CODE (op); + rtx op0 = XEXP (op, 0); + rtx op1 = XEXP (op, 1); + machine_mode compare_mode = GET_MODE (op0); + machine_mode result_mode = GET_MODE (dest); + bool max_p = false; + + if (result_mode != compare_mode) + return 0; + + if (code == GE || code == GT) + max_p = true; + else if (code == LE || code == LT) + max_p = false; + else + return 0; + + if (rtx_equal_p (op0, true_cond) && rtx_equal_p (op1, false_cond)) + ; + + else if (rtx_equal_p (op1, true_cond) && rtx_equal_p (op0, false_cond)) + max_p = !max_p; + + else + return 0; + + rs6000_emit_minmax (dest, max_p ? SMAX : SMIN, op0, op1); + return 1; +} + +/* ISA 3.0 (power9) conditional move subcase to emit XSCMP{EQ,GE,GT,NE}DP and + XXSEL instructions for SF/DF scalars. Move TRUE_COND to DEST if OP of the + operands of the last comparison is nonzero/true, FALSE_COND if it is + zero/false. Return 0 if the hardware has no such operation. */ + +static int +rs6000_emit_p9_fp_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond) +{ + enum rtx_code code = GET_CODE (op); + rtx op0 = XEXP (op, 0); + rtx op1 = XEXP (op, 1); + machine_mode result_mode = GET_MODE (dest); + rtx compare_rtx; + rtx cmove_rtx; + rtx clobber_rtx; + + if (!can_create_pseudo_p ()) + return 0; + + switch (code) + { + case EQ: + case GE: + case GT: + break; + + case NE: + case LT: + case LE: + code = swap_condition (code); + std::swap (op0, op1); + break; + + default: + return 0; + } + + /* Generate: [(parallel [(set (dest) + (if_then_else (op (cmp1) (cmp2)) + (true) + (false))) + (clobber (scratch))])]. */ + + compare_rtx = gen_rtx_fmt_ee (code, CCFPmode, op0, op1); + cmove_rtx = gen_rtx_SET (dest, + gen_rtx_IF_THEN_ELSE (result_mode, + compare_rtx, + true_cond, + false_cond)); + + clobber_rtx = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (V2DImode)); + emit_insn (gen_rtx_PARALLEL (VOIDmode, + gen_rtvec (2, cmove_rtx, clobber_rtx))); + + return 1; +} + /* Emit a conditional move: move TRUE_COND to DEST if OP of the operands of the last comparison is nonzero/true, FALSE_COND if it is zero/false. Return 0 if the hardware has no such operation. */ @@ -22669,6 +22764,18 @@ rs6000_emit_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond) if (GET_MODE (false_cond) != result_mode) return 0; + /* See if we can use the ISA 3.0 (power9) min/max/compare functions. */ + if (TARGET_P9_MINMAX + && (compare_mode == SFmode || compare_mode == DFmode) + && (result_mode == SFmode || result_mode == DFmode)) + { + if (rs6000_emit_p9_fp_minmax (dest, op, true_cond, false_cond)) + return 1; + + if (rs6000_emit_p9_fp_cmove (dest, op, true_cond, false_cond)) + return 1; + } + /* Don't allow using floating point comparisons for integer results for now. */ if (FLOAT_MODE_P (compare_mode) && !FLOAT_MODE_P (result_mode)) diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index a438bfb1b23..5f5510a6146 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -594,6 +594,15 @@ extern int rs6000_vector_align[]; in the register. */ #define TARGET_NO_SDMODE_STACK (TARGET_LFIWZX && TARGET_STFIWX && TARGET_DFP) +/* ISA 3.0 has new min/max functions that don't need fast math that are being + phased in. Min/max using FSEL or XSMAXDP/XSMINDP do not return the correct + answers if the arguments are not in the normal range. */ +#define TARGET_MINMAX_SF (TARGET_SF_FPR && TARGET_PPC_GFXOPT \ + && (TARGET_P9_MINMAX || !flag_trapping_math)) + +#define TARGET_MINMAX_DF (TARGET_DF_FPR && TARGET_PPC_GFXOPT \ + && (TARGET_P9_MINMAX || !flag_trapping_math)) + /* In switching from using target_flags to using rs6000_isa_flags, the options machinery creates OPTION_MASK_ instead of MASK_. For now map OPTION_MASK_ back into MASK_. */ diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 011acebd707..6628bc691f4 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -489,6 +489,10 @@ ; Iterator for just SF/DF (define_mode_iterator SFDF [SF DF]) +; Like SFDF, but a different name to match conditional move where the +; comparison operands may be a different mode than the input operands. +(define_mode_iterator SFDF2 [SF DF]) + ; Iterator for 128-bit floating point that uses the IBM double-double format (define_mode_iterator IBM128 [(IF "FLOAT128_IBM_P (IFmode)") (TF "FLOAT128_IBM_P (TFmode)")]) @@ -700,6 +704,15 @@ (define_mode_iterator RELOAD [V16QI V8HI V4SI V2DI V4SF V2DF V1TI SF SD SI DF DD DI TI PTI KF IF TF]) +;; Iterate over smin, smax +(define_code_iterator fp_minmax [smin smax]) + +(define_code_attr minmax [(smin "min") + (smax "max")]) + +(define_code_attr SMINMAX [(smin "SMIN") + (smax "SMAX")]) + ;; Start with fixed-point load and store insns. Here we put only the more ;; complex forms. Basic data transfer is done later. @@ -4629,74 +4642,45 @@ ;; On VSX, we only check for TARGET_VSX instead of checking for a vsx/p8 vector ;; to allow either DF/SF to use only traditional registers. -(define_expand "smax3" +(define_expand "s3" [(set (match_operand:SFDF 0 "gpc_reg_operand" "") - (if_then_else:SFDF (ge (match_operand:SFDF 1 "gpc_reg_operand" "") - (match_operand:SFDF 2 "gpc_reg_operand" "")) - (match_dup 1) - (match_dup 2)))] - "TARGET__FPR && TARGET_PPC_GFXOPT && !flag_trapping_math" + (fp_minmax:SFDF (match_operand:SFDF 1 "gpc_reg_operand" "") + (match_operand:SFDF 2 "gpc_reg_operand" "")))] + "TARGET_MINMAX_" { - rs6000_emit_minmax (operands[0], SMAX, operands[1], operands[2]); + rs6000_emit_minmax (operands[0], , operands[1], operands[2]); DONE; }) -(define_insn "*smax3_vsx" - [(set (match_operand:SFDF 0 "gpc_reg_operand" "=,") - (smax:SFDF (match_operand:SFDF 1 "gpc_reg_operand" "%,") - (match_operand:SFDF 2 "gpc_reg_operand" ",")))] - "TARGET__FPR && TARGET_VSX" - "xsmaxdp %x0,%x1,%x2" - [(set_attr "type" "fp")]) - -(define_expand "smin3" - [(set (match_operand:SFDF 0 "gpc_reg_operand" "") - (if_then_else:SFDF (ge (match_operand:SFDF 1 "gpc_reg_operand" "") - (match_operand:SFDF 2 "gpc_reg_operand" "")) - (match_dup 2) - (match_dup 1)))] - "TARGET__FPR && TARGET_PPC_GFXOPT && !flag_trapping_math" +(define_insn "*s3_vsx" + [(set (match_operand:SFDF 0 "vsx_register_operand" "=") + (fp_minmax:SFDF (match_operand:SFDF 1 "vsx_register_operand" "") + (match_operand:SFDF 2 "vsx_register_operand" "")))] + "TARGET_VSX && TARGET__FPR" { - rs6000_emit_minmax (operands[0], SMIN, operands[1], operands[2]); - DONE; -}) - -(define_insn "*smin3_vsx" - [(set (match_operand:SFDF 0 "gpc_reg_operand" "=,") - (smin:SFDF (match_operand:SFDF 1 "gpc_reg_operand" "%,") - (match_operand:SFDF 2 "gpc_reg_operand" ",")))] - "TARGET__FPR && TARGET_VSX" - "xsmindp %x0,%x1,%x2" + return (TARGET_P9_MINMAX + ? "xscdp %x0,%x1,%x2" + : "xsdp %x0,%x1,%x2"); +} [(set_attr "type" "fp")]) -(define_split +;; The conditional move instructions allow us to perform max and min operations +;; even when we don't have the appropriate max/min instruction using the FSEL +;; instruction. + +(define_insn_and_split "*s3_fpr" [(set (match_operand:SFDF 0 "gpc_reg_operand" "") - (match_operator:SFDF 3 "min_max_operator" - [(match_operand:SFDF 1 "gpc_reg_operand" "") - (match_operand:SFDF 2 "gpc_reg_operand" "")]))] - "TARGET__FPR && TARGET_PPC_GFXOPT && !flag_trapping_math - && !TARGET_VSX" + (fp_minmax:SFDF (match_operand:SFDF 1 "gpc_reg_operand" "") + (match_operand:SFDF 2 "gpc_reg_operand" "")))] + "!TARGET_VSX && TARGET_MINMAX_" + "#" + "&& 1" [(const_int 0)] { - rs6000_emit_minmax (operands[0], GET_CODE (operands[3]), operands[1], - operands[2]); + rs6000_emit_minmax (operands[0], , operands[1], operands[2]); DONE; }) -(define_split - [(set (match_operand:SF 0 "gpc_reg_operand" "") - (match_operator:SF 3 "min_max_operator" - [(match_operand:SF 1 "gpc_reg_operand" "") - (match_operand:SF 2 "gpc_reg_operand" "")]))] - "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS - && TARGET_SINGLE_FLOAT && !flag_trapping_math" - [(const_int 0)] - " -{ rs6000_emit_minmax (operands[0], GET_CODE (operands[3]), - operands[1], operands[2]); - DONE; -}") - (define_expand "movcc" [(set (match_operand:GPR 0 "gpc_reg_operand" "") (if_then_else:GPR (match_operand 1 "comparison_operator" "") @@ -4779,12 +4763,13 @@ [(set_attr "type" "isel") (set_attr "length" "4")]) -(define_expand "movsfcc" - [(set (match_operand:SF 0 "gpc_reg_operand" "") - (if_then_else:SF (match_operand 1 "comparison_operator" "") - (match_operand:SF 2 "gpc_reg_operand" "") - (match_operand:SF 3 "gpc_reg_operand" "")))] - "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT" +;; Floating point conditional move +(define_expand "movcc" + [(set (match_operand:SFDF 0 "gpc_reg_operand" "") + (if_then_else:SFDF (match_operand 1 "comparison_operator" "") + (match_operand:SFDF 2 "gpc_reg_operand" "") + (match_operand:SFDF 3 "gpc_reg_operand" "")))] + "TARGET__FPR && TARGET_PPC_GFXOPT" " { if (rs6000_emit_cmove (operands[0], operands[1], operands[2], operands[3])) @@ -4793,76 +4778,70 @@ FAIL; }") -(define_insn "*fselsfsf4" - [(set (match_operand:SF 0 "gpc_reg_operand" "=f") - (if_then_else:SF (ge (match_operand:SF 1 "gpc_reg_operand" "f") - (match_operand:SF 4 "zero_fp_constant" "F")) - (match_operand:SF 2 "gpc_reg_operand" "f") - (match_operand:SF 3 "gpc_reg_operand" "f")))] - "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT" +(define_insn "*fsel4" + [(set (match_operand:SFDF 0 "fpr_reg_operand" "=&") + (if_then_else:SFDF + (ge (match_operand:SFDF2 1 "fpr_reg_operand" "") + (match_operand:SFDF2 4 "zero_fp_constant" "F")) + (match_operand:SFDF 2 "fpr_reg_operand" "") + (match_operand:SFDF 3 "fpr_reg_operand" "")))] + "TARGET__FPR && TARGET_PPC_GFXOPT" "fsel %0,%1,%2,%3" [(set_attr "type" "fp")]) -(define_insn "*fseldfsf4" - [(set (match_operand:SF 0 "gpc_reg_operand" "=f") - (if_then_else:SF (ge (match_operand:DF 1 "gpc_reg_operand" "d") - (match_operand:DF 4 "zero_fp_constant" "F")) - (match_operand:SF 2 "gpc_reg_operand" "f") - (match_operand:SF 3 "gpc_reg_operand" "f")))] - "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_SINGLE_FLOAT" - "fsel %0,%1,%2,%3" - [(set_attr "type" "fp")]) - -;; The conditional move instructions allow us to perform max and min -;; operations even when - -(define_split - [(set (match_operand:DF 0 "gpc_reg_operand" "") - (match_operator:DF 3 "min_max_operator" - [(match_operand:DF 1 "gpc_reg_operand" "") - (match_operand:DF 2 "gpc_reg_operand" "")]))] - "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT - && !flag_trapping_math" - [(const_int 0)] - " -{ rs6000_emit_minmax (operands[0], GET_CODE (operands[3]), - operands[1], operands[2]); - DONE; -}") - -(define_expand "movdfcc" - [(set (match_operand:DF 0 "gpc_reg_operand" "") - (if_then_else:DF (match_operand 1 "comparison_operator" "") - (match_operand:DF 2 "gpc_reg_operand" "") - (match_operand:DF 3 "gpc_reg_operand" "")))] - "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT" - " +(define_insn_and_split "*movcc_p9" + [(set (match_operand:SFDF 0 "vsx_register_operand" "=&,") + (if_then_else:SFDF + (match_operator:CCFP 1 "fpmask_comparison_operator" + [(match_operand:SFDF2 2 "vsx_register_operand" ",") + (match_operand:SFDF2 3 "vsx_register_operand" ",")]) + (match_operand:SFDF 4 "vsx_register_operand" ",") + (match_operand:SFDF 5 "vsx_register_operand" ","))) + (clobber (match_scratch:V2DI 6 "=0,&wa"))] + "TARGET_P9_MINMAX" + "#" + "" + [(set (match_dup 6) + (if_then_else:V2DI (match_dup 1) + (match_dup 7) + (match_dup 8))) + (set (match_dup 0) + (if_then_else:SFDF (ne (match_dup 6) + (match_dup 8)) + (match_dup 4) + (match_dup 5)))] { - if (rs6000_emit_cmove (operands[0], operands[1], operands[2], operands[3])) - DONE; - else - FAIL; -}") + if (GET_CODE (operands[6]) == SCRATCH) + operands[6] = gen_reg_rtx (V2DImode); -(define_insn "*fseldfdf4" - [(set (match_operand:DF 0 "gpc_reg_operand" "=d") - (if_then_else:DF (ge (match_operand:DF 1 "gpc_reg_operand" "d") - (match_operand:DF 4 "zero_fp_constant" "F")) - (match_operand:DF 2 "gpc_reg_operand" "d") - (match_operand:DF 3 "gpc_reg_operand" "d")))] - "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT" - "fsel %0,%1,%2,%3" - [(set_attr "type" "fp")]) + operands[7] = CONSTM1_RTX (V2DImode); + operands[8] = CONST0_RTX (V2DImode); +} + [(set_attr "length" "8") + (set_attr "type" "vecperm")]) + +(define_insn "*fpmask" + [(set (match_operand:V2DI 0 "vsx_register_operand" "=wa") + (if_then_else:V2DI + (match_operator:CCFP 1 "fpmask_comparison_operator" + [(match_operand:SFDF 2 "vsx_register_operand" "") + (match_operand:SFDF 3 "vsx_register_operand" "")]) + (match_operand:V2DI 4 "all_ones_constant" "") + (match_operand:V2DI 5 "zero_constant" "")))] + "TARGET_P9_MINMAX" + "xscmp%V1dp %x0,%x2,%x3" + [(set_attr "type" "fpcompare")]) + +(define_insn "*xxsel" + [(set (match_operand:SFDF 0 "vsx_register_operand" "=") + (if_then_else:SFDF (ne (match_operand:V2DI 1 "vsx_register_operand" "wa") + (match_operand:V2DI 2 "zero_constant" "")) + (match_operand:SFDF 3 "vsx_register_operand" "") + (match_operand:SFDF 4 "vsx_register_operand" "")))] + "TARGET_P9_MINMAX" + "xxsel %x0,%x1,%x3,%x4" + [(set_attr "type" "vecperm")]) -(define_insn "*fselsfdf4" - [(set (match_operand:DF 0 "gpc_reg_operand" "=d") - (if_then_else:DF (ge (match_operand:SF 1 "gpc_reg_operand" "f") - (match_operand:SF 4 "zero_fp_constant" "F")) - (match_operand:DF 2 "gpc_reg_operand" "d") - (match_operand:DF 3 "gpc_reg_operand" "d")))] - "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_SINGLE_FLOAT" - "fsel %0,%1,%2,%3" - [(set_attr "type" "fp")]) ;; Conversions to and from floating-point. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f2a7a56bf05..f046e40c8d2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2016-05-26 Michael Meissner + + * gcc.target/powerpc/p9-minmax-1.c: New tests for ISA 3.0 + floating point min/max/comparison instructions. + * gcc.target/powerpc/p9-minmax-2.c: Likewise. + 2016-05-26 Jakub Jelinek * c-c++-common/gomp/schedule-1.c: New test. diff --git a/gcc/testsuite/gcc.target/powerpc/p9-minmax-1.c b/gcc/testsuite/gcc.target/powerpc/p9-minmax-1.c new file mode 100644 index 00000000000..c182da9470e --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/p9-minmax-1.c @@ -0,0 +1,171 @@ +/* { dg-do compile { target { powerpc*-*-* } } } */ +/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power9" } } */ +/* { dg-require-effective-target powerpc_p9vector_ok } */ +/* { dg-options "-mcpu=power9 -O2 -mpower9-minmax -ffast-math" } */ +/* { dg-final { scan-assembler-not "fsel" } } */ +/* { dg-final { scan-assembler "xscmpeqdp" } } */ +/* { dg-final { scan-assembler "xscmpgtdp" } } */ +/* { dg-final { scan-assembler "xscmpgedp" } } */ +/* { dg-final { scan-assembler-not "xscmpodp" } } */ +/* { dg-final { scan-assembler-not "xscmpudp" } } */ +/* { dg-final { scan-assembler "xsmaxcdp" } } */ +/* { dg-final { scan-assembler-not "xsmaxdp" } } */ +/* { dg-final { scan-assembler "xsmincdp" } } */ +/* { dg-final { scan-assembler-not "xsmindp" } } */ +/* { dg-final { scan-assembler "xxsel" } } */ + +double +dbl_max1 (double a, double b) +{ + return (a >= b) ? a : b; +} + +double +dbl_max2 (double a, double b) +{ + return (a > b) ? a : b; +} + +double +dbl_min1 (double a, double b) +{ + return (a < b) ? a : b; +} + +double +dbl_min2 (double a, double b) +{ + return (a <= b) ? a : b; +} + +double +dbl_cmp_eq (double a, double b, double c, double d) +{ + return (a == b) ? c : d; +} + +double +dbl_cmp_ne (double a, double b, double c, double d) +{ + return (a != b) ? c : d; +} + +double +dbl_cmp_gt (double a, double b, double c, double d) +{ + return (a > b) ? c : d; +} + +double +dbl_cmp_ge (double a, double b, double c, double d) +{ + return (a >= b) ? c : d; +} + +double +dbl_cmp_lt (double a, double b, double c, double d) +{ + return (a < b) ? c : d; +} + +double +dbl_cmp_le (double a, double b, double c, double d) +{ + return (a <= b) ? c : d; +} + +float +flt_max1 (float a, float b) +{ + return (a >= b) ? a : b; +} + +float +flt_max2 (float a, float b) +{ + return (a > b) ? a : b; +} + +float +flt_min1 (float a, float b) +{ + return (a < b) ? a : b; +} + +float +flt_min2 (float a, float b) +{ + return (a <= b) ? a : b; +} + +float +flt_cmp_eq (float a, float b, float c, float d) +{ + return (a == b) ? c : d; +} + +float +flt_cmp_ne (float a, float b, float c, float d) +{ + return (a != b) ? c : d; +} + +float +flt_cmp_gt (float a, float b, float c, float d) +{ + return (a > b) ? c : d; +} + +float +flt_cmp_ge (float a, float b, float c, float d) +{ + return (a >= b) ? c : d; +} + +float +flt_cmp_lt (float a, float b, float c, float d) +{ + return (a < b) ? c : d; +} + +float +flt_cmp_le (float a, float b, float c, float d) +{ + return (a <= b) ? c : d; +} + +double +dbl_flt_max1 (float a, float b) +{ + return (a > b) ? a : b; +} + +double +dbl_flt_max2 (double a, float b) +{ + return (a > b) ? a : b; +} + +double +dbl_flt_max3 (float a, double b) +{ + return (a > b) ? a : b; +} + +double +dbl_flt_min1 (float a, float b) +{ + return (a < b) ? a : b; +} + +double +dbl_flt_min2 (double a, float b) +{ + return (a < b) ? a : b; +} + +double +dbl_flt_min3 (float a, double b) +{ + return (a < b) ? a : b; +} diff --git a/gcc/testsuite/gcc.target/powerpc/p9-minmax-2.c b/gcc/testsuite/gcc.target/powerpc/p9-minmax-2.c new file mode 100644 index 00000000000..f6742142966 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/p9-minmax-2.c @@ -0,0 +1,191 @@ +/* { dg-do compile { target { powerpc*-*-* } } } */ +/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power9" } } */ +/* { dg-require-effective-target powerpc_p9vector_ok } */ +/* { dg-options "-mcpu=power9 -O2 -mpower9-minmax" } */ +/* { dg-final { scan-assembler-not "fsel" } } */ +/* { dg-final { scan-assembler "xscmpeqdp" } } */ +/* { dg-final { scan-assembler "xscmpgtdp" } } */ +/* { dg-final { scan-assembler-not "xscmpodp" } } */ +/* { dg-final { scan-assembler-not "xscmpudp" } } */ +/* { dg-final { scan-assembler "xsmaxcdp" } } */ +/* { dg-final { scan-assembler-not "xsmaxdp" } } */ +/* { dg-final { scan-assembler "xsmincdp" } } */ +/* { dg-final { scan-assembler-not "xsmindp" } } */ +/* { dg-final { scan-assembler "xxsel" } } */ + +/* Due to NaN support, <= and >= are not handled presently unless -ffast-math + is used. At some point this will be fixed and the xscmpgedp instruction can + be generated normally. The <= and >= tests are bracketed with + #ifdef DO_GE_LE. */ + +#ifdef DO_GE_LE +double +dbl_max1 (double a, double b) +{ + return (a >= b) ? a : b; +} +#endif + +double +dbl_max2 (double a, double b) +{ + return (a > b) ? a : b; +} + +double +dbl_min1 (double a, double b) +{ + return (a < b) ? a : b; +} + +#ifdef DO_GE_LE +double +dbl_min2 (double a, double b) +{ + return (a <= b) ? a : b; +} +#endif + +double +dbl_cmp_eq (double a, double b, double c, double d) +{ + return (a == b) ? c : d; +} + +double +dbl_cmp_ne (double a, double b, double c, double d) +{ + return (a != b) ? c : d; +} + +double +dbl_cmp_gt (double a, double b, double c, double d) +{ + return (a > b) ? c : d; +} + +#ifdef DO_GE_LE +double +dbl_cmp_ge (double a, double b, double c, double d) +{ + return (a >= b) ? c : d; +} +#endif + +double +dbl_cmp_lt (double a, double b, double c, double d) +{ + return (a < b) ? c : d; +} + +#ifdef DO_GE_LE +double +dbl_cmp_le (double a, double b, double c, double d) +{ + return (a <= b) ? c : d; +} +#endif + +#ifdef DO_GE_LE +float +flt_max1 (float a, float b) +{ + return (a >= b) ? a : b; +} +#endif + +float +flt_max2 (float a, float b) +{ + return (a > b) ? a : b; +} + +float +flt_min1 (float a, float b) +{ + return (a < b) ? a : b; +} + +#ifdef DO_GE_LE +float +flt_min2 (float a, float b) +{ + return (a <= b) ? a : b; +} +#endif + +float +flt_cmp_eq (float a, float b, float c, float d) +{ + return (a == b) ? c : d; +} + +float +flt_cmp_ne (float a, float b, float c, float d) +{ + return (a != b) ? c : d; +} + +float +flt_cmp_gt (float a, float b, float c, float d) +{ + return (a > b) ? c : d; +} + +#ifdef DO_GE_LE +float +flt_cmp_ge (float a, float b, float c, float d) +{ + return (a >= b) ? c : d; +} +#endif + +float +flt_cmp_lt (float a, float b, float c, float d) +{ + return (a < b) ? c : d; +} + +#ifdef DO_GE_LE +float +flt_cmp_le (float a, float b, float c, float d) +{ + return (a <= b) ? c : d; +} +#endif + +double +dbl_flt_max1 (float a, float b) +{ + return (a > b) ? a : b; +} + +double +dbl_flt_max2 (double a, float b) +{ + return (a > b) ? a : b; +} + +double +dbl_flt_max3 (float a, double b) +{ + return (a > b) ? a : b; +} + +double +dbl_flt_min1 (float a, float b) +{ + return (a < b) ? a : b; +} + +double +dbl_flt_min2 (double a, float b) +{ + return (a < b) ? a : b; +} + +double +dbl_flt_min3 (float a, double b) +{ + return (a < b) ? a : b; +}