"fsqrt %0,%1"
[(set_attr "type" "dsqrt")])
-;; For SMIN, SMAX, UMIN, and UMAX, 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
+;; 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.
(define_expand "maxsf3"
[(set (match_dup 3)
(match_dup 2)))]
"")
-(define_insn ""
+(define_expand "movsfcc"
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (if_then_else:SF (match_operand 1 "comparison_operator" "")
+ (match_operand:SF 2 "gpc_reg_operand" "f")
+ (match_operand:SF 3 "gpc_reg_operand" "f")))]
+ "TARGET_PPC_GFXOPT"
+ "
+{
+ 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]));
+ }
+ if (code == NE)
+ {
+ emit_insn (gen_negdf2 (temp, temp));
+ emit_insn (gen_fseldfsf4 (operands[0], temp, operands[3], operands[0]));
+ }
+ }
+ 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]));
+ }
+ if (code == NE)
+ {
+ emit_insn (gen_negsf2 (temp, temp));
+ emit_insn (gen_fselsfsf4 (operands[0], temp, operands[3], operands[0]));
+ }
+ }
+ DONE;
+}")
+(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))
"fsel %0,%1,%2,%3"
[(set_attr "type" "fp")])
+(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 2 "gpc_reg_operand" "f")
+ (match_operand:SF 3 "gpc_reg_operand" "f")))]
+ "TARGET_PPC_GFXOPT"
+ "fsel %0,%1,%2,%3"
+ [(set_attr "type" "fp")])
(define_insn "negdf2"
[(set (match_operand:DF 0 "gpc_reg_operand" "=f")
(neg:DF (match_operand:DF 1 "gpc_reg_operand" "f")))]
"fsqrt %0,%1"
[(set_attr "type" "dsqrt")])
-;; For SMIN, SMAX, UMIN, and UMAX, 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
+;; 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.
(define_expand "maxdf3"
(match_dup 2)))]
"")
-(define_insn ""
+(define_expand "movdfcc"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+ (if_then_else:DF (match_operand 1 "comparison_operator" "")
+ (match_operand:DF 2 "gpc_reg_operand" "f")
+ (match_operand:DF 3 "gpc_reg_operand" "f")))]
+ "TARGET_PPC_GFXOPT"
+ "
+{
+ 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]));
+ }
+ if (code == NE)
+ {
+ emit_insn (gen_negdf2 (temp, temp));
+ emit_insn (gen_fseldfdf4 (operands[0], temp, operands[3], operands[0]));
+ }
+ }
+ 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]));
+ }
+ if (code == NE)
+ {
+ emit_insn (gen_negsf2 (temp, temp));
+ emit_insn (gen_fselsfdf4 (operands[0], temp, operands[3], operands[0]));
+ }
+ }
+ DONE;
+}")
+(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))
"TARGET_PPC_GFXOPT"
"fsel %0,%1,%2,%3"
[(set_attr "type" "fp")])
+(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:DF 2 "gpc_reg_operand" "f")
+ (match_operand:DF 3 "gpc_reg_operand" "f")))]
+ "TARGET_PPC_GFXOPT"
+ "fsel %0,%1,%2,%3"
+ [(set_attr "type" "fp")])
\f
;; Conversions to and from floating-point.
(define_expand "floatsidf2"