Commit 21316320 by Michael Meissner Committed by Michael Meissner

rs6000.c (rs6000_emit_p9_fp_minmax): New function for ISA 3.0 min/max support.

[gcc]
2016-05-26  Michael Meissner  <meissner@linux.vnet.ibm.com>

	* 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.
	(smax<mode>3): 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.
	(s<minmax><mode>3): Likewise.
	(smax<mode>3_vsx): Likewise.
	(smin<mode>3): Likewise.
	(s<minmax><mode>3_vsx): Likewise.
	(smin<mode>3_vsx): Likewise.
	(pre-VSX min/max splitters): Likewise.
	(s<minmax><mode>3_fpr): Likewise.
	(movsfcc): Rewrite floating point conditional moves to combine
	SFmode/DFmode into a single insn.
	(mov<mode>cc): Likewise.
	(movdfcc): Likewise.
	(fselsfsf4): Combine FSEL cases into a single insn, using SFDF and
	SFDF2 iterators to handle all combinations.
	(fseldfsf4): Likewise.
	(fsel<SFDF:mode><SFDF2:mode>4): Likewise.
	(fseldfdf4): Likewise.
	(fselsfdf4): Likewise.
	(mov<SFDF:mode><SFDF2:mode>cc_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<mode>): Likewise.
	(xxsel<mode>): 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  <meissner@linux.vnet.ibm.com>

	* 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
parent 7211a097
2016-05-26 Michael Meissner <meissner@linux.vnet.ibm.com>
* 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.
(smax<mode>3): 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.
(s<minmax><mode>3): Likewise.
(smax<mode>3_vsx): Likewise.
(smin<mode>3): Likewise.
(s<minmax><mode>3_vsx): Likewise.
(smin<mode>3_vsx): Likewise.
(pre-VSX min/max splitters): Likewise.
(s<minmax><mode>3_fpr): Likewise.
(movsfcc): Rewrite floating point conditional moves to combine
SFmode/DFmode into a single insn.
(mov<mode>cc): Likewise.
(movdfcc): Likewise.
(fselsfsf4): Combine FSEL cases into a single insn, using SFDF and
SFDF2 iterators to handle all combinations.
(fseldfsf4): Likewise.
(fsel<SFDF:mode><SFDF2:mode>4): Likewise.
(fseldfdf4): Likewise.
(fselsfdf4): Likewise.
(mov<SFDF:mode><SFDF2:mode>cc_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<mode>): Likewise.
(xxsel<mode>): 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 <amodra@gmail.com> 2016-05-27 Alan Modra <amodra@gmail.com>
PR rtl-optimization/71275 PR rtl-optimization/71275
......
...@@ -1109,10 +1109,6 @@ ...@@ -1109,10 +1109,6 @@
(define_special_predicate "equality_operator" (define_special_predicate "equality_operator"
(match_code "eq,ne")) (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 ;; 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. ;; instruction. We check the opcode against the mode of the CC value.
;; validate_condition_mode is an assertion. ;; validate_condition_mode is an assertion.
...@@ -1155,6 +1151,11 @@ ...@@ -1155,6 +1151,11 @@
(and (match_operand 0 "branch_comparison_operator") (and (match_operand 0 "branch_comparison_operator")
(match_code "ne,le,ge,leu,geu,ordered"))) (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 ;; 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. ;; insn, which is true if the corresponding bit in the CC register is set.
(define_predicate "branch_positive_comparison_operator" (define_predicate "branch_positive_comparison_operator"
......
...@@ -22643,6 +22643,101 @@ rs6000_emit_vector_cond_expr (rtx dest, rtx op_true, rtx op_false, ...@@ -22643,6 +22643,101 @@ rs6000_emit_vector_cond_expr (rtx dest, rtx op_true, rtx op_false,
return 1; 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 /* 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 operands of the last comparison is nonzero/true, FALSE_COND if it
is zero/false. Return 0 if the hardware has no such operation. */ 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) ...@@ -22669,6 +22764,18 @@ rs6000_emit_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
if (GET_MODE (false_cond) != result_mode) if (GET_MODE (false_cond) != result_mode)
return 0; 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 /* Don't allow using floating point comparisons for integer results for
now. */ now. */
if (FLOAT_MODE_P (compare_mode) && !FLOAT_MODE_P (result_mode)) if (FLOAT_MODE_P (compare_mode) && !FLOAT_MODE_P (result_mode))
...@@ -594,6 +594,15 @@ extern int rs6000_vector_align[]; ...@@ -594,6 +594,15 @@ extern int rs6000_vector_align[];
in the register. */ in the register. */
#define TARGET_NO_SDMODE_STACK (TARGET_LFIWZX && TARGET_STFIWX && TARGET_DFP) #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 /* In switching from using target_flags to using rs6000_isa_flags, the options
machinery creates OPTION_MASK_<xxx> instead of MASK_<xxx>. For now map machinery creates OPTION_MASK_<xxx> instead of MASK_<xxx>. For now map
OPTION_MASK_<xxx> back into MASK_<xxx>. */ OPTION_MASK_<xxx> back into MASK_<xxx>. */
......
2016-05-26 Michael Meissner <meissner@linux.vnet.ibm.com>
* 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 <jakub@redhat.com> 2016-05-26 Jakub Jelinek <jakub@redhat.com>
* c-c++-common/gomp/schedule-1.c: New test. * c-c++-common/gomp/schedule-1.c: New test.
......
/* { 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;
}
/* { 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment