fsel patch for rs6000

Geoff Keating geoffk@geoffk.org
Mon May 21 11:29:00 GMT 2001


This patch fixes a number of problems with the use of the fsel
instruction in the rs6000 port:

- It was incorrectly performing some comparisons between Inf and Inf.
  Actually, there seemed to be a number of bugs.
- It was needlessly inefficient in handling certain cases.

This updates it.

Bootstrapped on powerpc-linux and tested with -mcpu=750 and -mcpu=750
-ffast-math.

-- 
- Geoffrey Keating <geoffk@geoffk.org>

===File ~/patches/cygnus/rs6000-fsel.patch==================
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.

Index: config/rs6000/rs6000-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000-protos.h,v
retrieving revision 1.18
diff -p -u -u -p -r1.18 rs6000-protos.h
--- rs6000-protos.h	2001/05/02 20:30:17	1.18
+++ rs6000-protos.h	2001/05/21 17:54:52
@@ -47,6 +47,7 @@ extern int got_operand PARAMS ((rtx, enu
 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 PARAM
 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_cond
 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));
Index: config/rs6000/rs6000.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.180
diff -p -u -u -p -r1.180 rs6000.c
--- rs6000.c	2001/05/15 19:27:11	1.180
+++ rs6000.c	2001/05/21 17:54:57
@@ -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
@@ -4725,6 +4749,181 @@ output_cbranch (op, label, reversed, ins
     }
 
   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
Index: config/rs6000/rs6000.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.h,v
retrieving revision 1.112
diff -p -u -u -p -r1.112 rs6000.h
--- rs6000.h	2001/05/14 03:40:04	1.112
+++ rs6000.h	2001/05/21 17:54:59
@@ -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 */
Index: config/rs6000/rs6000.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.md,v
retrieving revision 1.116
diff -p -u -u -p -r1.116 rs6000.md
--- rs6000.md	2001/05/15 19:27:13	1.116
+++ rs6000.md	2001/05/21 17:55:03
@@ -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" ""))]
-  "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)))]
-  "")
+	(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"
+  [(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,82 +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: case NE:
-      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]));
-	}
-      else if (code == NE)
-	{
-	  emit_insn (gen_negdf2 (temp, temp));
-	  emit_insn (gen_fseldfsf4 (operands[0], temp, operands[3], operands[0]));
-	}
-    }
+  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]));
-	}
-      else if (code == NE)
-	{
-	  emit_insn (gen_negsf2 (temp, temp));
-	  emit_insn (gen_fselsfsf4 (operands[0], temp, operands[3], operands[0]));
-	}
-    }
-  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"
@@ -5063,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" ""))]
-  "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)))]
-  "")
+	(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"
+  [(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" "")
@@ -5132,82 +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: case NE:
-      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]));
-	}
-      else if (code == NE)
-	{
-	  emit_insn (gen_negdf2 (temp, temp));
-	  emit_insn (gen_fseldfdf4 (operands[0], temp, operands[3], operands[0]));
-	}
-    }
+  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]));
-	}
-      else if (code == NE)
-	{
-	  emit_insn (gen_negsf2 (temp, temp));
-	  emit_insn (gen_fselsfdf4 (operands[0], temp, operands[3], operands[0]));
-	}
-    }
-  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"
============================================================



More information about the Gcc-patches mailing list