return op == CONST0_RTX(mode);
})
+
+;; Return true if the floating point comparison operation
+;; given produces a canonical answer.
+(define_predicate "v850_float_z_comparison_operator"
+ (match_code "lt,le,eq,gt,ge")
+{
+ enum rtx_code code = GET_CODE (op);
+
+ if (GET_RTX_CLASS (code) != RTX_COMPARE
+ && GET_RTX_CLASS (code) != RTX_COMM_COMPARE)
+ return 0;
+
+ if (mode != GET_MODE (op) && mode != VOIDmode)
+ return 0;
+
+ if ((GET_CODE (XEXP (op, 0)) != REG
+ || REGNO (XEXP (op, 0)) != CC_REGNUM)
+ || XEXP (op, 1) != const0_rtx)
+ return 0;
+
+ if (GET_MODE (XEXP (op, 0)) == CC_FPU_LTmode)
+ return code == LT;
+ if (GET_MODE (XEXP (op, 0)) == CC_FPU_LEmode)
+ return code == LE;
+ if (GET_MODE (XEXP (op, 0)) == CC_FPU_EQmode)
+ return code == EQ;
+ if (GET_MODE (XEXP (op, 0)) == CC_FPU_GTmode)
+ return code == GT;
+ if (GET_MODE (XEXP (op, 0)) == CC_FPU_GEmode)
+ return code == GE;
+
+ /* Note we do not accept CC_FPU_NEmode here. See
+ v850_float_nz_comparison for the reason why. */
+ return 0;
+})
+
+;; Return true if the floating point comparison operation
+;; given produces an inverted answer.
+(define_predicate "v850_float_nz_comparison_operator"
+ (match_code "ne")
+{
+ enum rtx_code code = GET_CODE (op);
+
+ /* The V850E2V3 does not have a floating point NZ comparison operator.
+ Instead it is implemented as an EQ comparison and this function ensures
+ that the branch_nz_normal and set_nz_insn patterns are used to examine
+ (and invert) the result of the floating point comparison. */
+
+ if (GET_RTX_CLASS (code) != RTX_COMPARE
+ && GET_RTX_CLASS (code) != RTX_COMM_COMPARE)
+ return 0;
+
+ if (mode != GET_MODE (op) && mode != VOIDmode)
+ return 0;
+
+ if ((GET_CODE (XEXP (op, 0)) != REG
+ || REGNO (XEXP (op, 0)) != CC_REGNUM)
+ || XEXP (op, 1) != const0_rtx)
+ return 0;
+
+ if (GET_MODE (XEXP (op, 0)) == CC_FPU_NEmode)
+ return code == NE;
+
+ return 0;
+})
return "";
}
-/* Generate comparison code. */
-int
-v850_float_z_comparison_operator (rtx op, enum machine_mode mode)
-{
- enum rtx_code code = GET_CODE (op);
-
- if (GET_RTX_CLASS (code) != RTX_COMPARE
- && GET_RTX_CLASS (code) != RTX_COMM_COMPARE)
- return 0;
-
- if (mode != GET_MODE (op) && mode != VOIDmode)
- return 0;
-
- if ((GET_CODE (XEXP (op, 0)) != REG
- || REGNO (XEXP (op, 0)) != CC_REGNUM)
- || XEXP (op, 1) != const0_rtx)
- return 0;
-
- if (GET_MODE (XEXP (op, 0)) == CC_FPU_LTmode)
- return code == LT;
- if (GET_MODE (XEXP (op, 0)) == CC_FPU_LEmode)
- return code == LE;
- if (GET_MODE (XEXP (op, 0)) == CC_FPU_EQmode)
- return code == EQ;
-
- return 0;
-}
-
-int
-v850_float_nz_comparison_operator (rtx op, enum machine_mode mode)
-{
- enum rtx_code code = GET_CODE (op);
-
- if (GET_RTX_CLASS (code) != RTX_COMPARE
- && GET_RTX_CLASS (code) != RTX_COMM_COMPARE)
- return 0;
-
- if (mode != GET_MODE (op) && mode != VOIDmode)
- return 0;
-
- if ((GET_CODE (XEXP (op, 0)) != REG
- || REGNO (XEXP (op, 0)) != CC_REGNUM)
- || XEXP (op, 1) != const0_rtx)
- return 0;
-
- if (GET_MODE (XEXP (op, 0)) == CC_FPU_GTmode)
- return code == GT;
- if (GET_MODE (XEXP (op, 0)) == CC_FPU_GEmode)
- return code == GE;
- if (GET_MODE (XEXP (op, 0)) == CC_FPU_NEmode)
- return code == NE;
-
- return code == GT || code == GE || code == NE;
-}
-
enum machine_mode
v850_select_cc_mode (enum rtx_code cond, rtx op0, rtx op1 ATTRIBUTE_UNUSED)
{
case NE:
return CC_FPU_NEmode;
default:
- abort ();
+ gcc_unreachable ();
}
}
return CCmode;
enum machine_mode
v850_gen_float_compare (enum rtx_code cond, enum machine_mode mode ATTRIBUTE_UNUSED, rtx op0, rtx op1)
{
- if (GET_MODE(op0) == DFmode)
+ if (GET_MODE (op0) == DFmode)
{
switch (cond)
{
case GT:
emit_insn (gen_cmpdf_gt_insn (op0, op1));
break;
+ case NE:
+ /* Note: There is no NE comparison operator. So we
+ perform an EQ comparison and invert the branch.
+ See v850_float_nz_comparison for how this is done. */
case EQ:
emit_insn (gen_cmpdf_eq_insn (op0, op1));
break;
- case NE:
- emit_insn (gen_cmpdf_ne_insn (op0, op1));
- break;
default:
- abort ();
+ gcc_unreachable ();
}
}
- else if (GET_MODE(v850_compare_op0) == SFmode)
+ else if (GET_MODE (v850_compare_op0) == SFmode)
{
switch (cond)
{
case GT:
emit_insn (gen_cmpsf_gt_insn(op0, op1));
break;
+ case NE:
+ /* Note: There is no NE comparison operator. So we
+ perform an EQ comparison and invert the branch.
+ See v850_float_nz_comparison for how this is done. */
case EQ:
emit_insn (gen_cmpsf_eq_insn(op0, op1));
break;
- case NE:
- emit_insn (gen_cmpsf_ne_insn(op0, op1));
- break;
default:
- abort ();
+ gcc_unreachable ();
}
}
else
- {
- abort ();
- }
+ gcc_unreachable ();
return v850_select_cc_mode (cond, op0, op1);
}
[(set_attr "length" "2,2")
(set_attr "cc" "compare")])
+(define_expand "cbranchsf4"
+ [(set (pc)
+ (if_then_else (match_operator 0 "ordered_comparison_operator"
+ [(match_operand:SF 1 "register_operand")
+ (match_operand:SF 2 "register_operand")])
+ (label_ref (match_operand 3 ""))
+ (pc)))
+ (clobber (cc0))]
+ "TARGET_V850E2V3"
+{
+ v850_compare_op0 = operands[1];
+ v850_compare_op1 = operands[2];
+
+ enum rtx_code cond = GET_CODE(operands[0]);
+ enum machine_mode mode;
+ rtx fcc_reg;
+ rtx cc_reg;
+ rtx tmp;
+
+ if (GET_MODE_CLASS (GET_MODE (v850_compare_op0)) != MODE_FLOAT)
+ FAIL;
+
+ mode = v850_gen_float_compare (cond, VOIDmode, v850_compare_op0, v850_compare_op1);
+ fcc_reg = gen_rtx_REG (mode, FCC_REGNUM);
+ cc_reg = gen_rtx_REG (mode, CC_REGNUM);
+ emit_insn(gen_rtx_SET (mode, cc_reg, fcc_reg));
+ tmp = gen_rtx_fmt_ee (cond, mode, cc_reg, const0_rtx);
+ tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
+ gen_rtx_LABEL_REF (VOIDmode, operands[3]), pc_rtx);
+ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
+ DONE;
+})
+
+(define_insn "cstoresf4"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (match_operator:SI 1 "ordered_comparison_operator"
+ [(match_operand:SF 2 "register_operand" "r")
+ (match_operand:SF 3 "register_operand" "r")]))]
+ "TARGET_V850E2V3"
+{
+ if (GET_CODE (operands[1]) == GT || GET_CODE (operands[1]) == GE)
+ return "cmpf.s %c1, %z2, %z3 ; trfsr ; setf nz, %0";
+ if (GET_CODE (operands[1]) == LT || GET_CODE (operands[1]) == LE)
+ return "cmpf.s %c1, %z2, %z3 ; trfsr ; setf z, %0";
+ if (GET_CODE (operands[1]) == EQ)
+ return "cmpf.s eq, %z2, %z3 ; trfsr ; setf z, %0";
+ if (GET_CODE (operands[1]) == NE)
+ return "cmpf.s neq, %z2, %z3 ; trfsr ; setf nz, %0";
+ gcc_unreachable ();
+}
+ [(set_attr "length" "12")
+ (set_attr "type" "fpu")]
+)
+
+(define_expand "cbranchdf4"
+ [(set (pc)
+ (if_then_else (match_operator 0 "ordered_comparison_operator"
+ [(match_operand:DF 1 "even_reg_operand")
+ (match_operand:DF 2 "even_reg_operand")])
+ (label_ref (match_operand 3 ""))
+ (pc)))
+ (clobber (cc0))]
+ "TARGET_V850E2V3"
+{
+ v850_compare_op0 = operands[1];
+ v850_compare_op1 = operands[2];
+
+ enum rtx_code cond = GET_CODE(operands[0]);
+ enum machine_mode mode;
+ rtx fcc_reg;
+ rtx cc_reg;
+ rtx tmp;
+
+ if (GET_MODE_CLASS (GET_MODE (v850_compare_op0)) != MODE_FLOAT)
+ FAIL;
+
+ mode = v850_gen_float_compare (cond, VOIDmode, v850_compare_op0, v850_compare_op1);
+ fcc_reg = gen_rtx_REG (mode, FCC_REGNUM);
+ cc_reg = gen_rtx_REG (mode, CC_REGNUM);
+ emit_insn(gen_rtx_SET (mode, cc_reg, fcc_reg));
+ tmp = gen_rtx_fmt_ee (cond, mode, cc_reg, const0_rtx);
+ tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
+ gen_rtx_LABEL_REF (VOIDmode, operands[3]), pc_rtx);
+ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
+ DONE;
+})
+
+(define_insn "cstoredf4"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (match_operator:SI 1 "ordered_comparison_operator"
+ [(match_operand:DF 2 "even_reg_operand" "r")
+ (match_operand:DF 3 "even_reg_operand" "r")]))]
+ "TARGET_V850E2V3"
+{
+ if (GET_CODE (operands[1]) == GT || GET_CODE (operands[1]) == GE)
+ return "cmpf.d %c1, %z2, %z3 ; trfsr ; setf nz, %0";
+ if (GET_CODE (operands[1]) == LT || GET_CODE (operands[1]) == LE)
+ return "cmpf.d %c1, %z2, %z3 ; trfsr ; setf z, %0";
+ if (GET_CODE (operands[1]) == EQ)
+ return "cmpf.d eq, %z2, %z3 ; trfsr ; setf z ,%0";
+ if (GET_CODE (operands[1]) == NE)
+ return "cmpf.d neq, %z2, %z3 ; trfsr ; setf nz, %0";
+ gcc_unreachable ();
+}
+ [(set_attr "length" "12")
+ (set_attr "type" "fpu")]
+)
+
(define_expand "cmpsf"
[(set (reg:CC CC_REGNUM)
(compare (match_operand:SF 0 "register_operand" "r")
(match_operand:SI 3 "reg_or_const_operand" "rI")))]
"(TARGET_V850E || TARGET_V850E2_ALL)"
{
+ /* Make sure that we have an integer comparison... */
+ if (GET_MODE (XEXP (operands[1], 0)) != CCmode
+ && GET_MODE (XEXP (operands[1], 0)) != SImode)
+ FAIL;
+
if ((GET_CODE (operands[2]) == CONST_INT
&& GET_CODE (operands[3]) == CONST_INT))
{
(compare:CC_FPU_LE (match_operand:SF 0 "register_operand" "r")
(match_operand:SF 1 "register_operand" "r")))]
"TARGET_USE_FPU"
- "cmpf.s le,%z1,%z0"
+ "cmpf.s le, %z0, %z1"
[(set_attr "length" "4")
(set_attr "cc" "none_0hit")
(set_attr "type" "fpu")])
(compare:CC_FPU_LT (match_operand:SF 0 "register_operand" "r")
(match_operand:SF 1 "register_operand" "r")))]
"TARGET_USE_FPU"
- "cmpf.s lt,%z1,%z0"
+ "cmpf.s lt, %z0, %z1"
[(set_attr "length" "4")
(set_attr "cc" "none_0hit")
(set_attr "type" "fpu")])
(compare:CC_FPU_GE (match_operand:SF 0 "register_operand" "r")
(match_operand:SF 1 "register_operand" "r")))]
"TARGET_USE_FPU"
- "cmpf.s ge,%z1,%z0"
+ "cmpf.s le, %z1, %z0"
[(set_attr "length" "4")
(set_attr "cc" "none_0hit")
(set_attr "type" "fpu")])
(compare:CC_FPU_GT (match_operand:SF 0 "register_operand" "r")
(match_operand:SF 1 "register_operand" "r")))]
"TARGET_USE_FPU"
- "cmpf.s gt,%z1,%z0"
+ "cmpf.s lt, %z1, %z0"
[(set_attr "length" "4")
(set_attr "cc" "none_0hit")
(set_attr "type" "fpu")])
(compare:CC_FPU_EQ (match_operand:SF 0 "register_operand" "r")
(match_operand:SF 1 "register_operand" "r")))]
"TARGET_USE_FPU"
- "cmpf.s eq,%z1,%z0"
- [(set_attr "length" "4")
- (set_attr "cc" "none_0hit")
- (set_attr "type" "fpu")])
-
-(define_insn "cmpsf_ne_insn"
- [(set (reg:CC_FPU_NE FCC_REGNUM)
- (compare:CC_FPU_NE (match_operand:SF 0 "register_operand" "r")
- (match_operand:SF 1 "register_operand" "r")))]
- "TARGET_USE_FPU"
- "cmpf.s neq,%z1,%z0"
+ "cmpf.s eq, %z0, %z1"
[(set_attr "length" "4")
(set_attr "cc" "none_0hit")
(set_attr "type" "fpu")])
(compare:CC_FPU_LE (match_operand:DF 0 "even_reg_operand" "r")
(match_operand:DF 1 "even_reg_operand" "r")))]
"TARGET_USE_FPU"
- "cmpf.d le,%z1,%z0"
+ "cmpf.d le, %z0, %z1"
[(set_attr "length" "4")
(set_attr "cc" "none_0hit")
(set_attr "type" "fpu")])
(compare:CC_FPU_LT (match_operand:DF 0 "even_reg_operand" "r")
(match_operand:DF 1 "even_reg_operand" "r")))]
"TARGET_USE_FPU"
- "cmpf.d lt,%z1,%z0"
+ "cmpf.d lt, %z0, %z1"
[(set_attr "length" "4")
(set_attr "cc" "none_0hit")
(set_attr "type" "fpu")])
(compare:CC_FPU_GE (match_operand:DF 0 "even_reg_operand" "r")
(match_operand:DF 1 "even_reg_operand" "r")))]
"TARGET_USE_FPU"
- "cmpf.d ge,%z1,%z0"
+ "cmpf.d le, %z1, %z0"
[(set_attr "length" "4")
(set_attr "cc" "none_0hit")
(set_attr "type" "fpu")])
(define_insn "cmpdf_gt_insn"
[(set (reg:CC_FPU_GT FCC_REGNUM)
(compare:CC_FPU_GT (match_operand:DF 0 "even_reg_operand" "r")
- (match_operand:DF 1 "even_reg_operand" "r")))]
+ (match_operand:DF 1 "even_reg_operand" "r")))]
"TARGET_USE_FPU"
- "cmpf.d gt,%z1,%z0"
+ "cmpf.d lt, %z1, %z0"
[(set_attr "length" "4")
(set_attr "cc" "none_0hit")
(set_attr "type" "fpu")])
(compare:CC_FPU_EQ (match_operand:DF 0 "even_reg_operand" "r")
(match_operand:DF 1 "even_reg_operand" "r")))]
"TARGET_USE_FPU"
- "cmpf.d eq,%z1,%z0"
+ "cmpf.d eq, %z0, %z1"
[(set_attr "length" "4")
(set_attr "cc" "none_0hit")
(set_attr "type" "fpu")])
-(define_insn "cmpdf_ne_insn"
- [(set (reg:CC_FPU_NE FCC_REGNUM)
- (compare:CC_FPU_NE (match_operand:DF 0 "even_reg_operand" "r")
- (match_operand:DF 1 "even_reg_operand" "r")))]
- "TARGET_USE_FPU"
- "cmpf.d neq,%z1,%z0"
- [(set_attr "length" "4")
- (set_attr "cc" "none_0hit")
- (set_attr "type" "fpu")])
-
-
;;
;; Transfer a v850e2v3 fcc to the Z bit of CC0 (this is necessary to do a
;; conditional branch based on a floating-point compare)