From 50a0b056d2d003872d0421710bfd3343fe5e3363 Mon Sep 17 00:00:00 2001 From: Geoffrey Keating Date: Mon, 21 May 2001 18:38:25 +0000 Subject: [PATCH] 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 --- gcc/ChangeLog | 31 ++++ gcc/config/rs6000/rs6000-protos.h | 4 + gcc/config/rs6000/rs6000.c | 211 ++++++++++++++++++++++++- gcc/config/rs6000/rs6000.h | 4 +- gcc/config/rs6000/rs6000.md | 252 +++++++----------------------- 5 files changed, 297 insertions(+), 205 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 569096215cc..8b5df1ce49c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,34 @@ +2001-05-21 Geoff Keating + + * 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 * c-decl.c (finish_decl): Don't set DECL_C_HARD_REGISTER for diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index 7e95c0bd7b6..63075035079 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 9376b2a97ea..10b3b91cba2 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 39c79c148ad..1de9c7d2590 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 442c1df538c..dd22359a8d5 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"