aboutsummaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authorGeoffrey Keating <geoffk@redhat.com>2001-05-21 18:38:25 +0000
committerGeoffrey Keating <geoffk@gcc.gnu.org>2001-05-21 18:38:25 +0000
commit50a0b056d2d003872d0421710bfd3343fe5e3363 (patch)
tree667dbd661b4a10753314fb19f89f5ebbdf5dd998 /gcc/config
parent0adc3c19711068a5fc3a1f97e7e77cac98606ac4 (diff)
downloadgcc-50a0b056d2d003872d0421710bfd3343fe5e3363.zip
gcc-50a0b056d2d003872d0421710bfd3343fe5e3363.tar.gz
gcc-50a0b056d2d003872d0421710bfd3343fe5e3363.tar.bz2
rs6000.md (maxsf3): Use rs6000_emit_minmax.
* config/rs6000/rs6000.md (maxsf3): Use rs6000_emit_minmax. (maxsf3+1): Delete. (minsf3): Use rs6000_emit_minmax. (minsf3+1): Generalize to handle both SMIN and SMAX. Use rs6000_emit_minmax. (movsfcc): Use rs6000_emit_cmove. (fselsfsf4): Don't compare a CONST_INT with a floating-point value. Don't generate emit_fselsfsf4. (fseldfsf4): Likewise. (maxdf3): Use rs6000_emit_minmax. (maxdf3+1): Delete. (mindf3): Use rs6000_emit_minmax. (mindf3+1): Generalize to handle both SMIN and SMAX. Use rs6000_emit_minmax. (movdfcc): Use rs6000_emit_cmove. (fseldfdf4): Don't compare a CONST_INT with a floating-point value. Don't generate emit_fselsfsf4. (fselsfdf4): Likewise. * config/rs6000/rs6000.c (zero_fp_constant): New predicate. (min_max_operator): New predicate. (rs6000_emit_cmove): New function. (rs6000_emit_minmax): New function. * config/rs6000/rs6000-protos.h: Prototype new functions. * config/rs6000/rs6000.h (PREDICATE_CODES): Add zero_fp_constant and min_max_operator. * config/rs6000/rs6000.c (output_cbranch): Handle all conditional types in the switch statement. From-SVN: r42404
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/rs6000/rs6000-protos.h4
-rw-r--r--gcc/config/rs6000/rs6000.c211
-rw-r--r--gcc/config/rs6000/rs6000.h4
-rw-r--r--gcc/config/rs6000/rs6000.md252
4 files changed, 266 insertions, 205 deletions
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index 7e95c0b..6307503 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -47,6 +47,7 @@ extern int got_operand PARAMS ((rtx, enum machine_mode));
extern int got_no_const_operand PARAMS ((rtx, enum machine_mode));
extern int num_insns_constant PARAMS ((rtx, enum machine_mode));
extern int easy_fp_constant PARAMS ((rtx, enum machine_mode));
+extern int zero_fp_constant PARAMS ((rtx, enum machine_mode));
extern int volatile_mem_operand PARAMS ((rtx, enum machine_mode));
extern int offsettable_mem_operand PARAMS ((rtx, enum machine_mode));
extern int mem_or_easy_const_operand PARAMS ((rtx, enum machine_mode));
@@ -79,6 +80,7 @@ extern int scc_comparison_operator PARAMS ((rtx, enum machine_mode));
extern int trap_comparison_operator PARAMS ((rtx, enum machine_mode));
extern int boolean_operator PARAMS ((rtx, enum machine_mode));
extern int boolean_or_operator PARAMS ((rtx, enum machine_mode));
+extern int min_max_operator PARAMS ((rtx, enum machine_mode));
extern int includes_lshift_p PARAMS ((rtx, rtx));
extern int includes_rshift_p PARAMS ((rtx, rtx));
extern int includes_lshift64_p PARAMS ((rtx, rtx));
@@ -94,6 +96,8 @@ extern enum rtx_code rs6000_reverse_condition PARAMS ((enum machine_mode,
extern void rs6000_emit_sCOND PARAMS ((enum rtx_code, rtx));
extern void rs6000_emit_cbranch PARAMS ((enum rtx_code, rtx));
extern char * output_cbranch PARAMS ((rtx, const char *, int, rtx));
+extern int rs6000_emit_cmove PARAMS ((rtx, rtx, rtx, rtx));
+extern void rs6000_emit_minmax PARAMS ((rtx, enum rtx_code, rtx, rtx));
extern void output_toc PARAMS ((FILE *, rtx, int, enum machine_mode));
extern int rs6000_adjust_cost PARAMS ((rtx, rtx, rtx, int));
extern int rs6000_adjust_priority PARAMS ((rtx, int));
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 9376b2a..10b3b91 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -914,6 +914,15 @@ easy_fp_constant (op, mode)
abort ();
}
+/* Return 1 if the operand is 0.0. */
+int
+zero_fp_constant (op, mode)
+ register rtx op;
+ register enum machine_mode mode;
+{
+ return GET_MODE_CLASS (mode) == MODE_FLOAT && op == CONST0_RTX (mode);
+}
+
/* Return 1 if the operand is in volatile memory. Note that during the
RTL generation phase, memory_operand does not return TRUE for
volatile memory references. So this function allows us to
@@ -3440,6 +3449,15 @@ boolean_or_operator (op, mode)
enum rtx_code code = GET_CODE (op);
return (code == IOR || code == XOR);
}
+
+int
+min_max_operator (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ enum rtx_code code = GET_CODE (op);
+ return (code == SMIN || code == SMAX || code == UMIN || code == UMAX);
+}
/* Return 1 if ANDOP is a mask that has no bits on that are not in the
mask required to convert the result of a rotate insn into a shift
@@ -4676,12 +4694,18 @@ output_cbranch (op, label, reversed, insn)
{
/* Not all of these are actually distinct opcodes, but
we distinguish them for clarity of the resulting assembler. */
- case NE: ccode = "ne"; break;
- case EQ: ccode = "eq"; break;
- case GE: case GEU: ccode = "ge"; break;
- case GT: case GTU: ccode = "gt"; break;
- case LE: case LEU: ccode = "le"; break;
- case LT: case LTU: ccode = "lt"; break;
+ case NE: case LTGT:
+ ccode = "ne"; break;
+ case EQ: case UNEQ:
+ ccode = "eq"; break;
+ case GE: case GEU:
+ ccode = "ge"; break;
+ case GT: case GTU: case UNGT:
+ ccode = "gt"; break;
+ case LE: case LEU:
+ ccode = "le"; break;
+ case LT: case LTU: case UNLT:
+ ccode = "lt"; break;
case UNORDERED: ccode = "un"; break;
case ORDERED: ccode = "nu"; break;
case UNGE: ccode = "nl"; break;
@@ -4731,6 +4755,181 @@ output_cbranch (op, label, reversed, insn)
return string;
}
+
+/* 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. */
+int
+rs6000_emit_cmove (dest, op, true_cond, false_cond)
+ rtx dest;
+ rtx op;
+ rtx true_cond;
+ rtx false_cond;
+{
+ enum rtx_code code = GET_CODE (op);
+ rtx op0 = rs6000_compare_op0;
+ rtx op1 = rs6000_compare_op1;
+ REAL_VALUE_TYPE c1;
+ enum machine_mode mode = GET_MODE (op0);
+ rtx temp;
+
+ /* First, work out if the hardware can do this at all, or
+ if it's too slow... */
+ /* If the comparison is an integer one, since we only have fsel
+ it'll be cheaper to use a branch. */
+ if (! rs6000_compare_fp_p)
+ return 0;
+
+ /* Eliminate half of the comparisons by switching operands, this
+ makes the remaining code simpler. */
+ if (code == UNLT || code == UNGT || code == UNORDERED || code == NE
+ || code == LTGT || code == LT)
+ {
+ code = reverse_condition_maybe_unordered (code);
+ temp = true_cond;
+ true_cond = false_cond;
+ false_cond = temp;
+ }
+
+ /* UNEQ and LTGT take four instructions for a comparison with zero,
+ it'll probably be faster to use a branch here too. */
+ if (code == UNEQ)
+ return 0;
+
+ if (GET_CODE (op1) == CONST_DOUBLE)
+ REAL_VALUE_FROM_CONST_DOUBLE (c1, op1);
+
+ /* We're going to try to implement comparions by performing
+ a subtract, then comparing against zero. Unfortunately,
+ Inf - Inf is NaN which is not zero, and so if we don't
+ know that the the operand is finite and the comparison
+ would treat EQ different to UNORDERED, we can't do it. */
+ if (! flag_unsafe_math_optimizations
+ && code != GT && code != UNGE
+ && (GET_CODE (op1) != CONST_DOUBLE || target_isinf (c1))
+ /* Constructs of the form (a OP b ? a : b) are safe. */
+ && ((! rtx_equal_p (op0, false_cond) && ! rtx_equal_p (op1, false_cond))
+ || (! rtx_equal_p (op0, true_cond)
+ && ! rtx_equal_p (op1, true_cond))))
+ return 0;
+ /* At this point we know we can use fsel. */
+
+ /* Reduce the comparison to a comparison against zero. */
+ temp = gen_reg_rtx (mode);
+ emit_insn (gen_rtx_SET (VOIDmode, temp,
+ gen_rtx_MINUS (mode, op0, op1)));
+ op0 = temp;
+ op1 = CONST0_RTX (mode);
+
+ /* If we don't care about NaNs we can reduce some of the comparisons
+ down to faster ones. */
+ if (flag_unsafe_math_optimizations)
+ switch (code)
+ {
+ case GT:
+ code = LE;
+ temp = true_cond;
+ true_cond = false_cond;
+ false_cond = temp;
+ break;
+ case UNGE:
+ code = GE;
+ break;
+ case UNEQ:
+ code = EQ;
+ break;
+ default:
+ break;
+ }
+
+ /* Now, reduce everything down to a GE. */
+ switch (code)
+ {
+ case GE:
+ break;
+
+ case LE:
+ temp = gen_reg_rtx (mode);
+ emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_NEG (mode, op0)));
+ op0 = temp;
+ break;
+
+ case ORDERED:
+ temp = gen_reg_rtx (mode);
+ emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_ABS (mode, op0)));
+ op0 = temp;
+ break;
+
+ case EQ:
+ temp = gen_reg_rtx (mode);
+ emit_insn (gen_rtx_SET (VOIDmode, temp,
+ gen_rtx_NEG (mode,
+ gen_rtx_ABS (mode, op0))));
+ op0 = temp;
+ break;
+
+ case UNGE:
+ temp = gen_reg_rtx (mode);
+ emit_insn (gen_rtx_SET (VOIDmode, temp,
+ gen_rtx_IF_THEN_ELSE (mode,
+ gen_rtx_GE (VOIDmode,
+ op0, op1),
+ true_cond, false_cond)));
+ false_cond = temp;
+ true_cond = false_cond;
+
+ temp = gen_reg_rtx (mode);
+ emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_NEG (mode, op0)));
+ op0 = temp;
+ break;
+
+ case GT:
+ temp = gen_reg_rtx (mode);
+ emit_insn (gen_rtx_SET (VOIDmode, temp,
+ gen_rtx_IF_THEN_ELSE (mode,
+ gen_rtx_GE (VOIDmode,
+ op0, op1),
+ true_cond, false_cond)));
+ true_cond = temp;
+ false_cond = true_cond;
+
+ temp = gen_reg_rtx (mode);
+ emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_NEG (mode, op0)));
+ op0 = temp;
+ break;
+
+ default:
+ abort ();
+ }
+
+ emit_insn (gen_rtx_SET (VOIDmode, dest,
+ gen_rtx_IF_THEN_ELSE (mode,
+ gen_rtx_GE (VOIDmode,
+ op0, op1),
+ true_cond, false_cond)));
+ return 1;
+}
+
+void
+rs6000_emit_minmax (dest, code, op0, op1)
+ rtx dest;
+ enum rtx_code code;
+ rtx op0;
+ rtx op1;
+{
+ enum machine_mode mode = GET_MODE (op0);
+ rtx target;
+ if (code == SMAX || code == UMAX)
+ target = emit_conditional_move (dest, GE, op0, op1, mode,
+ op0, op1, mode, 0);
+ else
+ target = emit_conditional_move (dest, GE, op0, op1, mode,
+ op1, op0, mode, 0);
+ if (target == NULL_RTX)
+ abort ();
+ if (target != dest)
+ emit_move_insn (dest, target);
+}
/* This page contains routines that are used to determine what the function
prologue and epilogue code will do and write them out. */
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index 39c79c1..1de9c7d 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -2683,6 +2683,7 @@ do { \
{"got_operand", {SYMBOL_REF, CONST, LABEL_REF}}, \
{"got_no_const_operand", {SYMBOL_REF, LABEL_REF}}, \
{"easy_fp_constant", {CONST_DOUBLE}}, \
+ {"zero_fp_constant", {CONST_DOUBLE}}, \
{"reg_or_mem_operand", {SUBREG, MEM, REG}}, \
{"lwa_operand", {SUBREG, MEM, REG}}, \
{"volatile_mem_operand", {MEM}}, \
@@ -2718,7 +2719,8 @@ do { \
{"trap_comparison_operator", {EQ, NE, LE, LT, GE, \
GT, LEU, LTU, GEU, GTU}}, \
{"boolean_operator", {AND, IOR, XOR}}, \
- {"boolean_or_operator", {IOR, XOR}},
+ {"boolean_or_operator", {IOR, XOR}}, \
+ {"min_max_operator", {SMIN, SMAX, UMIN, UMAX}},
/* uncomment for disabling the corresponding default options */
/* #define MACHINE_no_sched_interblock */
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 442c1df..dd22359 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -4822,60 +4822,35 @@
;; single DEFINE_INSN for fsel and the define_splits to make them if made by
;; combine.
(define_expand "maxsf3"
- [(set (match_dup 3)
- (minus:SF (match_operand:SF 1 "gpc_reg_operand" "")
- (match_operand:SF 2 "gpc_reg_operand" "")))
- (set (match_operand:SF 0 "gpc_reg_operand" "")
- (if_then_else:SF (ge (match_dup 3)
- (const_int 0))
- (match_dup 1)
- (match_dup 2)))]
- "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
- "
-{ operands[3] = gen_reg_rtx (SFmode); }")
-
-(define_split
[(set (match_operand:SF 0 "gpc_reg_operand" "")
- (smax:SF (match_operand:SF 1 "gpc_reg_operand" "")
- (match_operand:SF 2 "gpc_reg_operand" "")))
- (clobber (match_operand:SF 3 "gpc_reg_operand" ""))]
- "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
- [(set (match_dup 3)
- (minus:SF (match_dup 1) (match_dup 2)))
- (set (match_dup 0)
- (if_then_else:SF (ge (match_dup 3)
- (const_int 0))
+ (if_then_else:SF (ge (match_operand:SF 1 "gpc_reg_operand" "")
+ (match_operand:SF 2 "gpc_reg_operand" ""))
(match_dup 1)
(match_dup 2)))]
- "")
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
+ "{ rs6000_emit_minmax (operands[0], SMAX, operands[1], operands[2]); DONE;}")
(define_expand "minsf3"
- [(set (match_dup 3)
- (minus:SF (match_operand:SF 2 "gpc_reg_operand" "")
- (match_operand:SF 1 "gpc_reg_operand" "")))
- (set (match_operand:SF 0 "gpc_reg_operand" "")
- (if_then_else:SF (ge (match_dup 3)
- (const_int 0))
- (match_dup 1)
- (match_dup 2)))]
+ [(set (match_operand:SF 0 "gpc_reg_operand" "")
+ (if_then_else:SF (ge (match_operand:SF 1 "gpc_reg_operand" "")
+ (match_operand:SF 2 "gpc_reg_operand" ""))
+ (match_dup 2)
+ (match_dup 1)))]
"TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
- "
-{ operands[3] = gen_reg_rtx (SFmode); }")
+ "{ rs6000_emit_minmax (operands[0], SMIN, operands[1], operands[2]); DONE;}")
(define_split
[(set (match_operand:SF 0 "gpc_reg_operand" "")
- (smin:SF (match_operand:SF 1 "gpc_reg_operand" "")
- (match_operand:SF 2 "gpc_reg_operand" "")))
- (clobber (match_operand:SF 3 "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"
- [(set (match_dup 3)
- (minus:SF (match_dup 2) (match_dup 1)))
- (set (match_dup 0)
- (if_then_else:SF (ge (match_dup 3)
- (const_int 0))
- (match_dup 1)
- (match_dup 2)))]
- "")
+ [(const_int 0)]
+ "
+{ rs6000_emit_minmax (operands[0], GET_CODE (operands[3]),
+ operands[1], operands[2]);
+ DONE;
+}")
(define_expand "movsfcc"
[(set (match_operand:SF 0 "gpc_reg_operand" "")
@@ -4885,72 +4860,26 @@
"TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
"
{
- rtx temp, op0, op1;
- enum rtx_code code = GET_CODE (operands[1]);
- if (! rs6000_compare_fp_p)
- FAIL;
- switch (code)
- {
- case GE: case EQ:
- op0 = rs6000_compare_op0;
- op1 = rs6000_compare_op1;
- break;
- case GT:
- op0 = rs6000_compare_op1;
- op1 = rs6000_compare_op0;
- temp = operands[2]; operands[2] = operands[3]; operands[3] = temp;
- break;
- case LE:
- op0 = rs6000_compare_op1;
- op1 = rs6000_compare_op0;
- break;
- case LT:
- op0 = rs6000_compare_op0;
- op1 = rs6000_compare_op1;
- temp = operands[2]; operands[2] = operands[3]; operands[3] = temp;
- break;
- default:
- FAIL;
- }
- if (GET_MODE (rs6000_compare_op0) == DFmode)
- {
- temp = gen_reg_rtx (DFmode);
- emit_insn (gen_subdf3 (temp, op0, op1));
- emit_insn (gen_fseldfsf4 (operands[0], temp, operands[2], operands[3]));
- if (code == EQ)
- {
- emit_insn (gen_negdf2 (temp, temp));
- emit_insn (gen_fseldfsf4 (operands[0], temp, operands[0], operands[3]));
- }
- }
+ if (rs6000_emit_cmove (operands[0], operands[1], operands[2], operands[3]))
+ DONE;
else
- {
- temp = gen_reg_rtx (SFmode);
- emit_insn (gen_subsf3 (temp, op0, op1));
- emit_insn (gen_fselsfsf4 (operands[0], temp, operands[2], operands[3]));
- if (code == EQ)
- {
- emit_insn (gen_negsf2 (temp, temp));
- emit_insn (gen_fselsfsf4 (operands[0], temp, operands[0], operands[3]));
- }
- }
- DONE;
+ FAIL;
}")
-(define_insn "fselsfsf4"
+(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")
- (const_int 0))
+ (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"
"fsel %0,%1,%2,%3"
[(set_attr "type" "fp")])
-(define_insn "fseldfsf4"
+(define_insn "*fseldfsf4"
[(set (match_operand:SF 0 "gpc_reg_operand" "=f")
(if_then_else:SF (ge (match_operand:DF 1 "gpc_reg_operand" "f")
- (const_int 0))
+ (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"
@@ -5053,66 +4982,39 @@
"fsqrt %0,%1"
[(set_attr "type" "dsqrt")])
-;; For MIN, MAX, and conditional move, we use DEFINE_EXPAND's that involve a
-;; fsel instruction and some auxiliary computations. Then we just have a
-;; single DEFINE_INSN for fsel and the define_splits to make them if made by
-;; combine.
+;; The conditional move instructions allow us to perform max and min
+;; operations even when
(define_expand "maxdf3"
- [(set (match_dup 3)
- (minus:DF (match_operand:DF 1 "gpc_reg_operand" "")
- (match_operand:DF 2 "gpc_reg_operand" "")))
- (set (match_operand:DF 0 "gpc_reg_operand" "")
- (if_then_else:DF (ge (match_dup 3)
- (const_int 0))
- (match_dup 1)
- (match_dup 2)))]
- "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
- "
-{ operands[3] = gen_reg_rtx (DFmode); }")
-
-(define_split
[(set (match_operand:DF 0 "gpc_reg_operand" "")
- (smax:DF (match_operand:DF 1 "gpc_reg_operand" "")
- (match_operand:DF 2 "gpc_reg_operand" "")))
- (clobber (match_operand:DF 3 "gpc_reg_operand" ""))]
- "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
- [(set (match_dup 3)
- (minus:DF (match_dup 1) (match_dup 2)))
- (set (match_dup 0)
- (if_then_else:DF (ge (match_dup 3)
- (const_int 0))
+ (if_then_else:DF (ge (match_operand:DF 1 "gpc_reg_operand" "")
+ (match_operand:DF 2 "gpc_reg_operand" ""))
(match_dup 1)
(match_dup 2)))]
- "")
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
+ "{ rs6000_emit_minmax (operands[0], SMAX, operands[1], operands[2]); DONE;}")
(define_expand "mindf3"
- [(set (match_dup 3)
- (minus:DF (match_operand:DF 2 "gpc_reg_operand" "")
- (match_operand:DF 1 "gpc_reg_operand" "")))
- (set (match_operand:DF 0 "gpc_reg_operand" "")
- (if_then_else:DF (ge (match_dup 3)
- (const_int 0))
- (match_dup 1)
- (match_dup 2)))]
+ [(set (match_operand:DF 0 "gpc_reg_operand" "")
+ (if_then_else:DF (ge (match_operand:DF 1 "gpc_reg_operand" "")
+ (match_operand:DF 2 "gpc_reg_operand" ""))
+ (match_dup 2)
+ (match_dup 1)))]
"TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
- "
-{ operands[3] = gen_reg_rtx (DFmode); }")
+ "{ rs6000_emit_minmax (operands[0], SMIN, operands[1], operands[2]); DONE;}")
(define_split
[(set (match_operand:DF 0 "gpc_reg_operand" "")
- (smin:DF (match_operand:DF 1 "gpc_reg_operand" "")
- (match_operand:DF 2 "gpc_reg_operand" "")))
- (clobber (match_operand:DF 3 "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"
- [(set (match_dup 3)
- (minus:DF (match_dup 2) (match_dup 1)))
- (set (match_dup 0)
- (if_then_else:DF (ge (match_dup 3)
- (const_int 0))
- (match_dup 1)
- (match_dup 2)))]
- "")
+ [(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" "")
@@ -5122,72 +5024,26 @@
"TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
"
{
- rtx temp, op0, op1;
- enum rtx_code code = GET_CODE (operands[1]);
- if (! rs6000_compare_fp_p)
- FAIL;
- switch (code)
- {
- case GE: case EQ:
- op0 = rs6000_compare_op0;
- op1 = rs6000_compare_op1;
- break;
- case GT:
- op0 = rs6000_compare_op1;
- op1 = rs6000_compare_op0;
- temp = operands[2]; operands[2] = operands[3]; operands[3] = temp;
- break;
- case LE:
- op0 = rs6000_compare_op1;
- op1 = rs6000_compare_op0;
- break;
- case LT:
- op0 = rs6000_compare_op0;
- op1 = rs6000_compare_op1;
- temp = operands[2]; operands[2] = operands[3]; operands[3] = temp;
- break;
- default:
- FAIL;
- }
- if (GET_MODE (rs6000_compare_op0) == DFmode)
- {
- temp = gen_reg_rtx (DFmode);
- emit_insn (gen_subdf3 (temp, op0, op1));
- emit_insn (gen_fseldfdf4 (operands[0], temp, operands[2], operands[3]));
- if (code == EQ)
- {
- emit_insn (gen_negdf2 (temp, temp));
- emit_insn (gen_fseldfdf4 (operands[0], temp, operands[0], operands[3]));
- }
- }
+ if (rs6000_emit_cmove (operands[0], operands[1], operands[2], operands[3]))
+ DONE;
else
- {
- temp = gen_reg_rtx (SFmode);
- emit_insn (gen_subsf3 (temp, op0, op1));
- emit_insn (gen_fselsfdf4 (operands[0], temp, operands[2], operands[3]));
- if (code == EQ)
- {
- emit_insn (gen_negsf2 (temp, temp));
- emit_insn (gen_fselsfdf4 (operands[0], temp, operands[0], operands[3]));
- }
- }
- DONE;
+ FAIL;
}")
-(define_insn "fseldfdf4"
+(define_insn "*fseldfdf4"
[(set (match_operand:DF 0 "gpc_reg_operand" "=f")
(if_then_else:DF (ge (match_operand:DF 1 "gpc_reg_operand" "f")
- (const_int 0))
+ (match_operand:DF 4 "zero_fp_constant" "F"))
(match_operand:DF 2 "gpc_reg_operand" "f")
(match_operand:DF 3 "gpc_reg_operand" "f")))]
"TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
"fsel %0,%1,%2,%3"
[(set_attr "type" "fp")])
-(define_insn "fselsfdf4"
+(define_insn "*fselsfdf4"
[(set (match_operand:DF 0 "gpc_reg_operand" "=f")
(if_then_else:DF (ge (match_operand:SF 1 "gpc_reg_operand" "f")
- (const_int 0))
+ (match_operand:SF 4 "zero_fp_constant" "F"))
(match_operand:DF 2 "gpc_reg_operand" "f")
(match_operand:DF 3 "gpc_reg_operand" "f")))]
"TARGET_PPC_GFXOPT"