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
This commit is contained in:
Geoffrey Keating 2001-05-21 18:38:25 +00:00 committed by Geoffrey Keating
parent 0adc3c1971
commit 50a0b056d2
5 changed files with 297 additions and 205 deletions

View File

@ -1,3 +1,34 @@
2001-05-21 Geoff Keating <geoffk@redhat.com>
* 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.
2001-05-21 Mark Mitchell <mark@codesourcery.com>
* c-decl.c (finish_decl): Don't set DECL_C_HARD_REGISTER for

View File

@ -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));

View File

@ -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. */

View File

@ -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 */

View File

@ -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"