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:
parent
0adc3c1971
commit
50a0b056d2
5 changed files with 297 additions and 205 deletions
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Add table
Reference in a new issue