char *singlemove_string ();
char *output_move_const_single ();
+char *output_fp_cc0_set ();
static char *hi_reg_name[] = HI_REGISTER_NAMES;
static char *qi_reg_name[] = QI_REGISTER_NAMES;
/* arg pointer */
INDEX_REGS
};
+
+/* Test and compare insns in i386.md store the information needed to
+ generate branch and scc insns here. */
+
+struct rtx_def *i386_compare_op0, *i386_compare_op1;
+struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)();
\f
/* Output an insn whose source is a 386 integer register. SRC is the
rtx for the register, and TEMPLATE is the op-code template. SRC may
CC_STATUS_INIT;
if (! stack_regs_mentioned_p (SET_SRC (XVECEXP (exp, 0, 0))))
cc_status.value1 = SET_SRC (XVECEXP (exp, 0, 0));
+
+ cc_status.flags |= CC_IN_80387;
return;
}
CC_STATUS_INIT;
\f
/* Output code for INSN to compare OPERANDS. The two operands might
not have the same mode: one might be within a FLOAT or FLOAT_EXTEND
- expression. */
+ expression. If the compare is in mode CCFPEQmode, use an opcode that
+ will not fault if a qNaN is present. */
char *
output_float_compare (insn, operands)
rtx *operands;
{
int stack_top_dies;
+ rtx body = XVECEXP (PATTERN (insn), 0, 0);
+ int unordered_compare = GET_MODE (SET_SRC (body)) == CCFPEQmode;
if (! STACK_TOP_P (operands[0]))
abort ();
is also a stack register that dies, then this must be a
`fcompp' float compare */
- output_asm_insn ("fcompp", operands);
+ if (unordered_compare)
+ output_asm_insn ("fucompp", operands);
+ else
+ output_asm_insn ("fcompp", operands);
}
else
{
static char buf[100];
- /* Decide if this is the integer or float compare opcode. */
+ /* Decide if this is the integer or float compare opcode, or the
+ unordered float compare. */
- if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_FLOAT)
+ if (unordered_compare)
+ strcpy (buf, "fucom");
+ else if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_FLOAT)
strcpy (buf, "fcom");
else
strcpy (buf, "ficom");
/* Now retrieve the condition code. */
- output_asm_insn (AS1 (fnsts%W2,%2), operands);
+ return output_fp_cc0_set (insn);
+}
+\f
+/* Output opcodes to transfer the results of FP compare or test INSN
+ from the FPU to the CPU flags. If TARGET_IEEE_FP, ensure that if the
+ result of the compare or test is unordered, no comparison operator
+ succeeds except NE. Return an output template, if any. */
+
+char *
+output_fp_cc0_set (insn)
+ rtx insn;
+{
+ rtx xops[3];
+ rtx unordered_label;
+ rtx next;
+ enum rtx_code code;
+
+ xops[0] = gen_rtx (REG, HImode, 0);
+ output_asm_insn (AS1 (fnsts%W0,%0), xops);
+
+ if (! TARGET_IEEE_FP)
+ return "sahf";
- cc_status.flags |= CC_IN_80387;
- return "sahf";
+ next = next_cc0_user (insn);
+
+ if (GET_CODE (next) == JUMP_INSN
+ && GET_CODE (PATTERN (next)) == SET
+ && SET_DEST (PATTERN (next)) == pc_rtx
+ && GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE)
+ {
+ code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0));
+ }
+ else if (GET_CODE (PATTERN (next)) == SET)
+ {
+ code = GET_CODE (SET_SRC (PATTERN (next)));
+ }
+ else
+ abort ();
+
+ xops[0] = gen_rtx (REG, QImode, 0);
+
+ switch (code)
+ {
+ case GT:
+ xops[1] = gen_rtx (CONST_INT, VOIDmode, 0x45);
+ output_asm_insn (AS2 (and%B0,%1,%h0), xops);
+ /* je label */
+ break;
+
+ case LT:
+ xops[1] = gen_rtx (CONST_INT, VOIDmode, 0x45);
+ xops[2] = gen_rtx (CONST_INT, VOIDmode, 0x01);
+ output_asm_insn (AS2 (and%B0,%1,%h0), xops);
+ output_asm_insn (AS2 (cmp%B0,%2,%h0), xops);
+ /* je label */
+ break;
+
+ case GE:
+ xops[1] = gen_rtx (CONST_INT, VOIDmode, 0x05);
+ output_asm_insn (AS2 (and%B0,%1,%h0), xops);
+ /* je label */
+ break;
+
+ case LE:
+ xops[1] = gen_rtx (CONST_INT, VOIDmode, 0x45);
+ xops[2] = gen_rtx (CONST_INT, VOIDmode, 0x40);
+ output_asm_insn (AS2 (and%B0,%1,%h0), xops);
+ output_asm_insn (AS1 (dec%B0,%h0), xops);
+ output_asm_insn (AS2 (cmp%B0,%2,%h0), xops);
+ /* jb label */
+ break;
+
+ case EQ:
+ xops[1] = gen_rtx (CONST_INT, VOIDmode, 0x45);
+ xops[2] = gen_rtx (CONST_INT, VOIDmode, 0x40);
+ output_asm_insn (AS2 (and%B0,%1,%h0), xops);
+ output_asm_insn (AS2 (cmp%B0,%2,%h0), xops);
+ /* je label */
+ break;
+
+ case NE:
+ xops[1] = gen_rtx (CONST_INT, VOIDmode, 0x44);
+ xops[2] = gen_rtx (CONST_INT, VOIDmode, 0x40);
+ output_asm_insn (AS2 (and%B0,%1,%h0), xops);
+ output_asm_insn (AS2 (xor%B0,%2,%h0), xops);
+ /* jne label */
+ break;
+
+ case GTU:
+ case LTU:
+ case GEU:
+ case LEU:
+ default:
+ abort ();
+ }
+ RET;
}
\f
#ifdef HANDLE_PRAGMA
;; (set (cc0) (const_int foo)) has no mode information. Such insns will
;; be folded while optimizing anyway.
-(define_insn "tstsi"
+;; All test insns have expanders that save the operands away without
+;; actually generating RTL. The bCOND or sCOND (emitted immediately
+;; after the tstM or cmp) will actually emit the tstM or cmpM.
+
+(define_insn "tstsi_cc"
[(set (cc0)
(match_operand:SI 0 "nonimmediate_operand" "rm"))]
""
return AS2 (cmp%L0,%1,%0);
}")
-(define_insn "tsthi"
+(define_expand "tstsi"
+ [(set (cc0)
+ (match_operand:SI 0 "nonimmediate_operand" ""))]
+ ""
+ "
+{
+ i386_compare_gen = gen_tstsi_cc;
+ i386_compare_op0 = operands[0];
+ DONE;
+}")
+
+(define_insn "tsthi_cc"
[(set (cc0)
(match_operand:HI 0 "nonimmediate_operand" "rm"))]
""
return AS2 (cmp%W0,%1,%0);
}")
-(define_insn "tstqi"
+(define_expand "tsthi"
+ [(set (cc0)
+ (match_operand:HI 0 "nonimmediate_operand" ""))]
+ ""
+ "
+{
+ i386_compare_gen = gen_tsthi_cc;
+ i386_compare_op0 = operands[0];
+ DONE;
+}")
+
+(define_insn "tstqi_cc"
[(set (cc0)
(match_operand:QI 0 "nonimmediate_operand" "qm"))]
""
return AS2 (cmp%B0,%1,%0);
}")
-(define_insn "tstsf"
+(define_expand "tstqi"
+ [(set (cc0)
+ (match_operand:QI 0 "nonimmediate_operand" ""))]
+ ""
+ "
+{
+ i386_compare_gen = gen_tstqi_cc;
+ i386_compare_op0 = operands[0];
+ DONE;
+}")
+
+(define_insn "tstsf_cc"
[(set (cc0)
(match_operand:SF 0 "register_operand" "f"))
(clobber (match_scratch:HI 1 "=a"))]
- "TARGET_80387"
+ "TARGET_80387 && ! TARGET_IEEE_FP"
"*
{
if (! STACK_TOP_P (operands[0]))
abort ();
output_asm_insn (\"ftst\", operands);
- cc_status.flags |= CC_IN_80387;
if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
output_asm_insn (AS1 (fstp,%y0), operands);
- output_asm_insn (AS1 (fnsts%W1,%1), operands);
+ return (char *) output_fp_cc0_set (insn);
+}")
+
+;; Don't generate tstsf if generating IEEE code, since the `ftst' opcode
+;; isn't IEEE compliant.
- return \"sahf\";
+(define_expand "tstsf"
+ [(parallel [(set (cc0)
+ (match_operand:SF 0 "register_operand" ""))
+ (clobber (match_scratch:HI 1 ""))])]
+ "TARGET_80387 && ! TARGET_IEEE_FP"
+ "
+{
+ i386_compare_gen = gen_tstsf_cc;
+ i386_compare_op0 = operands[0];
+ DONE;
}")
-(define_insn "tstdf"
+(define_insn "tstdf_cc"
[(set (cc0)
(match_operand:DF 0 "register_operand" "f"))
(clobber (match_scratch:HI 1 "=a"))]
- "TARGET_80387"
+ "TARGET_80387 && ! TARGET_IEEE_FP"
"*
{
if (! STACK_TOP_P (operands[0]))
abort ();
output_asm_insn (\"ftst\", operands);
- cc_status.flags |= CC_IN_80387;
if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
output_asm_insn (AS1 (fstp,%y0), operands);
- output_asm_insn (AS1 (fnsts%W1,%1), operands);
+ return (char *) output_fp_cc0_set (insn);
+}")
- return \"sahf\";
+;; Don't generate tstdf if generating IEEE code, since the `ftst' opcode
+;; isn't IEEE compliant.
+
+(define_expand "tstdf"
+ [(parallel [(set (cc0)
+ (match_operand:DF 0 "register_operand" ""))
+ (clobber (match_scratch:HI 1 ""))])]
+ "TARGET_80387 && ! TARGET_IEEE_FP"
+ "
+{
+ i386_compare_gen = gen_tstdf_cc;
+ i386_compare_op0 = operands[0];
+ DONE;
}")
\f
-;;- compare instructions
+;;- compare instructions. See comments above tstM patterns about
+;; expansion of these insns.
-(define_insn "cmpsi"
+(define_insn "cmpsi_cc"
[(set (cc0)
- (compare (match_operand:SI 0 "nonimmediate_operand" "mr,ri")
- (match_operand:SI 1 "general_operand" "ri,mr")))]
+ (compare:CC (match_operand:SI 0 "nonimmediate_operand" "mr,ri")
+ (match_operand:SI 1 "general_operand" "ri,mr")))]
""
"*
{
return AS2 (cmp%L0,%1,%0);
}")
-(define_insn "cmphi"
+(define_expand "cmpsi"
[(set (cc0)
- (compare (match_operand:HI 0 "nonimmediate_operand" "mr,ri")
- (match_operand:HI 1 "general_operand" "ri,mr")))]
+ (compare:CC (match_operand:SI 0 "nonimmediate_operand" "")
+ (match_operand:SI 1 "general_operand" "")))]
+ ""
+ "
+{
+ i386_compare_gen = gen_cmpsi_cc;
+ i386_compare_op0 = operands[0];
+ i386_compare_op1 = operands[1];
+ DONE;
+}")
+
+(define_insn "cmphi_cc"
+ [(set (cc0)
+ (compare:CC (match_operand:HI 0 "nonimmediate_operand" "mr,ri")
+ (match_operand:HI 1 "general_operand" "ri,mr")))]
""
"*
{
return AS2 (cmp%W0,%1,%0);
}")
-(define_insn "cmpqi"
+(define_expand "cmphi"
[(set (cc0)
- (compare (match_operand:QI 0 "nonimmediate_operand" "qn,mq")
- (match_operand:QI 1 "general_operand" "qm,nq")))]
+ (compare:CC (match_operand:HI 0 "nonimmediate_operand" "")
+ (match_operand:HI 1 "general_operand" "")))]
+ ""
+ "
+{
+ i386_compare_gen = gen_cmphi_cc;
+ i386_compare_op0 = operands[0];
+ i386_compare_op1 = operands[1];
+ DONE;
+}")
+
+(define_insn "cmpqi_cc"
+ [(set (cc0)
+ (compare:CC (match_operand:QI 0 "nonimmediate_operand" "qn,mq")
+ (match_operand:QI 1 "general_operand" "qm,nq")))]
""
"*
{
return AS2 (cmp%B0,%1,%0);
}")
+(define_expand "cmpqi"
+ [(set (cc0)
+ (compare:CC (match_operand:QI 0 "nonimmediate_operand" "")
+ (match_operand:QI 1 "general_operand" "")))]
+ ""
+ "
+{
+ i386_compare_gen = gen_cmpqi_cc;
+ i386_compare_op0 = operands[0];
+ i386_compare_op1 = operands[1];
+ DONE;
+}")
+
;; These implement float point compares. For each of DFmode and
;; SFmode, there is the normal insn, and an insn where the second operand
;; is converted to the desired mode.
-(define_expand "cmpdf"
- [(parallel [(set (cc0)
- (compare (match_operand:DF 0 "nonimmediate_operand" "")
- (match_operand:DF 1 "nonimmediate_operand" "")))
- (clobber (match_scratch:HI 2 ""))])]
+(define_insn "cmpdf_cc"
+ [(set (cc0)
+ (compare:CC (match_operand:DF 0 "register_operand" "f")
+ (match_operand:DF 1 "nonimmediate_operand" "fm")))
+ (clobber (match_scratch:HI 2 "=a"))]
"TARGET_80387"
- "")
+ "* return (char *) output_float_compare (insn, operands);")
-(define_expand "cmpsf"
- [(parallel [(set (cc0)
- (compare (match_operand:SF 0 "nonimmediate_operand" "")
- (match_operand:SF 1 "nonimmediate_operand" "")))
- (clobber (match_scratch:HI 2 ""))])]
+(define_insn ""
+ [(set (cc0)
+ (compare:CC (match_operand:DF 0 "register_operand" "f,f")
+ (float:DF
+ (match_operand:SI 1 "nonimmediate_operand" "m,!*r"))))
+ (clobber (match_scratch:HI 2 "=a,a"))]
"TARGET_80387"
- "")
+ "* return (char *) output_float_compare (insn, operands);")
-;; The `ble' and `blt' patterns can reverse a compare, so we must allow
-;; an immediate operand as operand 0 in the recognizers below.
+(define_insn ""
+ [(set (cc0)
+ (compare:CC (match_operand:DF 0 "register_operand" "f,f")
+ (float_extend:DF
+ (match_operand:SF 1 "nonimmediate_operand" "fm,!*r"))))
+ (clobber (match_scratch:HI 2 "=a,a"))]
+ "TARGET_80387"
+ "* return (char *) output_float_compare (insn, operands);")
(define_insn ""
[(set (cc0)
- (compare (match_operand:DF 0 "general_operand" "f")
- (match_operand:DF 1 "general_operand" "fm")))
+ (compare:CCFPEQ (match_operand:DF 0 "register_operand" "f")
+ (match_operand:DF 1 "register_operand" "f")))
(clobber (match_scratch:HI 2 "=a"))]
"TARGET_80387"
"* return (char *) output_float_compare (insn, operands);")
(define_insn ""
[(set (cc0)
- (compare (match_operand:DF 0 "general_operand" "f,f")
- (float:DF (match_operand:SI 1 "general_operand" "m,!*r"))))
- (clobber (match_scratch:HI 2 "=a,a"))]
+ (compare:CCFPEQ (match_operand:DF 0 "register_operand" "f")
+ (float_extend:DF
+ (match_operand:SF 1 "register_operand" "f"))))
+ (clobber (match_scratch:HI 2 "=a"))]
+ "TARGET_80387"
+ "* return (char *) output_float_compare (insn, operands);")
+
+(define_insn "cmpsf_cc"
+ [(set (cc0)
+ (compare:CC (match_operand:SF 0 "register_operand" "f")
+ (match_operand:SF 1 "nonimmediate_operand" "fm")))
+ (clobber (match_scratch:HI 2 "=a"))]
"TARGET_80387"
"* return (char *) output_float_compare (insn, operands);")
(define_insn ""
[(set (cc0)
- (compare (match_operand:DF 0 "general_operand" "f,f")
- (float_extend:DF
- (match_operand:SF 1 "general_operand" "fm,!*r"))))
+ (compare:CC (match_operand:SF 0 "register_operand" "f,f")
+ (float:SF
+ (match_operand:SI 1 "nonimmediate_operand" "m,!*r"))))
(clobber (match_scratch:HI 2 "=a,a"))]
"TARGET_80387"
"* return (char *) output_float_compare (insn, operands);")
(define_insn ""
[(set (cc0)
- (compare (match_operand:SF 0 "general_operand" "f")
- (match_operand:SF 1 "general_operand" "fm")))
+ (compare:CCFPEQ (match_operand:SF 0 "register_operand" "f")
+ (match_operand:SF 1 "register_operand" "f")))
(clobber (match_scratch:HI 2 "=a"))]
"TARGET_80387"
"* return (char *) output_float_compare (insn, operands);")
-(define_insn ""
+(define_expand "cmpdf"
[(set (cc0)
- (compare (match_operand:SF 0 "general_operand" "f,f")
- (float:SF (match_operand:SI 1 "general_operand" "m,!*r"))))
- (clobber (match_scratch:HI 2 "=a,a"))]
+ (compare:CC (match_operand:DF 0 "register_operand" "")
+ (match_operand:DF 1 "nonimmediate_operand" "")))]
"TARGET_80387"
- "* return (char *) output_float_compare (insn, operands);")
+ "
+{
+ i386_compare_gen = gen_cmpdf_cc;
+ i386_compare_gen_eq = gen_cmpdf_ccfpeq;
+ i386_compare_op0 = operands[0];
+ i386_compare_op1 = operands[1];
+ DONE;
+}")
+
+(define_expand "cmpsf"
+ [(set (cc0)
+ (compare:CC (match_operand:SF 0 "register_operand" "")
+ (match_operand:SF 1 "nonimmediate_operand" "")))]
+ "TARGET_80387"
+ "
+{
+ i386_compare_gen = gen_cmpsf_cc;
+ i386_compare_gen_eq = gen_cmpsf_ccfpeq;
+ i386_compare_op0 = operands[0];
+ i386_compare_op1 = operands[1];
+ DONE;
+}")
+
+(define_expand "cmpdf_ccfpeq"
+ [(parallel [(set (cc0)
+ (compare:CCFPEQ (match_operand:DF 0 "register_operand" "")
+ (match_operand:DF 1 "register_operand" "")))
+ (clobber (match_scratch:HI 2 ""))])]
+ "TARGET_80387"
+ "
+{
+ if (! register_operand (operands[1], DFmode))
+ operands[1] = copy_to_mode_reg (DFmode, operands[1]);
+}")
+
+(define_expand "cmpsf_ccfpeq"
+ [(parallel [(set (cc0)
+ (compare:CCFPEQ (match_operand:SF 0 "register_operand" "")
+ (match_operand:SF 1 "register_operand" "")))
+ (clobber (match_scratch:HI 2 ""))])]
+ "TARGET_80387"
+ "
+{
+ if (! register_operand (operands[1], SFmode))
+ operands[1] = copy_to_mode_reg (SFmode, operands[1]);
+}")
\f
;; logical compare
return AS3 (imul%L0,%2,%1,%0);
}")
-(define_insn "mulqihi3_1"
+(define_insn ""
[(set (match_operand:HI 0 "general_operand" "=a")
(mult:SI (zero_extend:HI
(match_operand:QI 1 "nonimmediate_operand" "%0"))
\f
;; Store-flag instructions.
-(define_insn "seq"
+;; For all sCOND expanders, also expand the compare or test insn that
+;; generates cc0. Generate an equality comparison if `seq' or `sne'.
+
+(define_expand "seq"
+ [(match_dup 1)
+ (set (match_operand:QI 0 "general_operand" "")
+ (eq:QI (cc0) (const_int 0)))]
+ ""
+ "
+{
+ if (TARGET_IEEE_FP
+ && GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT)
+ operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1);
+ else
+ operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);
+}")
+
+(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=qm")
(eq:QI (cc0) (const_int 0)))]
""
return AS1 (setnb,%0);
else
return AS1 (sete,%0);
-}
-")
+}")
-(define_insn "sne"
+(define_expand "sne"
+ [(match_dup 1)
+ (set (match_operand:QI 0 "general_operand" "")
+ (ne:QI (cc0) (const_int 0)))]
+ ""
+ "
+{
+ if (TARGET_IEEE_FP
+ && GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT)
+ operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1);
+ else
+ operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);
+}")
+
+(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=qm")
(ne:QI (cc0) (const_int 0)))]
""
}
")
-(define_insn "sgt"
+(define_expand "sgt"
+ [(match_dup 1)
+ (set (match_operand:QI 0 "general_operand" "")
+ (gt:QI (cc0) (const_int 0)))]
+ ""
+ "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
+
+(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=qm")
(gt:QI (cc0) (const_int 0)))]
""
- "* OUTPUT_JUMP (\"setg %0\", \"seta %0\", 0); ")
+ "*
+{
+ if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
+ return AS1 (sete,%0);
+
+ OUTPUT_JUMP (\"setg %0\", \"seta %0\", 0);
+}")
-(define_insn "sgtu"
+(define_expand "sgtu"
+ [(match_dup 1)
+ (set (match_operand:QI 0 "general_operand" "")
+ (gtu:QI (cc0) (const_int 0)))]
+ ""
+ "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
+
+(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=qm")
(gtu:QI (cc0) (const_int 0)))]
""
"* return \"seta %0\"; ")
-(define_insn "slt"
+(define_expand "slt"
+ [(match_dup 1)
+ (set (match_operand:QI 0 "general_operand" "")
+ (lt:QI (cc0) (const_int 0)))]
+ ""
+ "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
+
+(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=qm")
(lt:QI (cc0) (const_int 0)))]
""
- "* OUTPUT_JUMP (\"setl %0\", \"setb %0\", \"sets %0\"); ")
+ "*
+{
+ if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
+ return AS1 (sete,%0);
-(define_insn "sltu"
+ OUTPUT_JUMP (\"setl %0\", \"setb %0\", \"sets %0\");
+}")
+
+(define_expand "sltu"
+ [(match_dup 1)
+ (set (match_operand:QI 0 "general_operand" "")
+ (ltu:QI (cc0) (const_int 0)))]
+ ""
+ "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
+
+(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=qm")
(ltu:QI (cc0) (const_int 0)))]
""
"* return \"setb %0\"; ")
-(define_insn "sge"
+(define_expand "sge"
+ [(match_dup 1)
+ (set (match_operand:QI 0 "general_operand" "")
+ (ge:QI (cc0) (const_int 0)))]
+ ""
+ "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
+
+(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=qm")
(ge:QI (cc0) (const_int 0)))]
""
- "* OUTPUT_JUMP (\"setge %0\", \"setae %0\", \"setns %0\"); ")
+ "*
+{
+ if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
+ return AS1 (sete,%0);
-(define_insn "sgeu"
+ OUTPUT_JUMP (\"setge %0\", \"setae %0\", \"setns %0\");
+}")
+
+(define_expand "sgeu"
+ [(match_dup 1)
+ (set (match_operand:QI 0 "general_operand" "")
+ (geu:QI (cc0) (const_int 0)))]
+ ""
+ "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
+
+(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=qm")
(geu:QI (cc0) (const_int 0)))]
""
"* return \"setae %0\"; ")
-(define_insn "sle"
+(define_expand "sle"
+ [(match_dup 1)
+ (set (match_operand:QI 0 "general_operand" "")
+ (le:QI (cc0) (const_int 0)))]
+ ""
+ "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
+
+(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=qm")
(le:QI (cc0) (const_int 0)))]
""
- "* OUTPUT_JUMP (\"setle %0\", \"setbe %0\", 0); ")
+ "*
+{
+ if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
+ return AS1 (setb,%0);
+
+ OUTPUT_JUMP (\"setle %0\", \"setbe %0\", 0);
+}")
(define_insn "sleu"
[(set (match_operand:QI 0 "general_operand" "=qm")
;; Basic conditional jump instructions.
;; We ignore the overflow flag for signed branch instructions.
-(define_insn "beq"
+;; For all bCOND expanders, also expand the compare or test insn that
+;; generates cc0. Generate an equality comparison if `beq' or `bne'.
+
+(define_expand "beq"
+ [(match_dup 1)
+ (set (pc)
+ (if_then_else (eq (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{
+ if (TARGET_IEEE_FP
+ && GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT)
+ operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1);
+ else
+ operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);
+}")
+
+(define_insn ""
[(set (pc)
(if_then_else (eq (cc0)
(const_int 0))
return \"je %l0\";
}")
-(define_insn "bne"
+(define_expand "bne"
+ [(match_dup 1)
+ (set (pc)
+ (if_then_else (ne (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{
+ if (TARGET_IEEE_FP
+ && GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT)
+ operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1);
+ else
+ operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);
+}")
+
+(define_insn ""
[(set (pc)
(if_then_else (ne (cc0)
(const_int 0))
return \"jne %l0\";
}")
-(define_insn "bgt"
+(define_expand "bgt"
+ [(match_dup 1)
+ (set (pc)
+ (if_then_else (gt (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
+
+(define_insn ""
[(set (pc)
(if_then_else (gt (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "*OUTPUT_JUMP (\"jg %l0\", \"ja %l0\", 0)")
+ "*
+{
+ if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
+ return AS1 (je,%l0);
+
+ OUTPUT_JUMP (\"jg %l0\", \"ja %l0\", 0);
+}")
+
+(define_expand "bgtu"
+ [(match_dup 1)
+ (set (pc)
+ (if_then_else (gtu (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
-(define_insn "bgtu"
+(define_insn ""
[(set (pc)
(if_then_else (gtu (cc0)
(const_int 0))
""
"ja %l0")
-;; There is no jump insn to check for `<' on IEEE floats.
-;; Page 17-80 in the 80387 manual says jb, but that's wrong;
-;; jb checks for `not >='. So swap the operands and do `>'.
(define_expand "blt"
- [(set (pc)
+ [(match_dup 1)
+ (set (pc)
(if_then_else (lt (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "
-{
- rtx prev = get_last_insn_anywhere ();
- rtx body = PATTERN (prev);
- rtx comp;
- if (GET_CODE (body) == SET)
- comp = SET_SRC (body);
- else
- comp = SET_SRC (XVECEXP (body, 0, 0));
-
- if (GET_CODE (comp) == COMPARE
- ? GET_MODE_CLASS (GET_MODE (XEXP (comp, 0))) == MODE_FLOAT
- : GET_MODE_CLASS (GET_MODE (comp)) == MODE_FLOAT)
- {
- reverse_comparison (prev);
- emit_insn (gen_bgt (operands[0]));
- DONE;
- }
-}")
+ "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
(define_insn ""
[(set (pc)
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "*OUTPUT_JUMP (\"jl %l0\", \"jb %l0\", \"js %l0\")")
+ "*
+{
+ if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
+ return AS1 (je,%l0);
+
+ OUTPUT_JUMP (\"jl %l0\", \"jb %l0\", \"js %l0\");
+}")
-(define_insn "bltu"
+(define_expand "bltu"
+ [(match_dup 1)
+ (set (pc)
+ (if_then_else (ltu (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
+
+(define_insn ""
[(set (pc)
(if_then_else (ltu (cc0)
(const_int 0))
""
"jb %l0")
-(define_insn "bge"
+(define_expand "bge"
+ [(match_dup 1)
+ (set (pc)
+ (if_then_else (ge (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
+
+(define_insn ""
[(set (pc)
(if_then_else (ge (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "*OUTPUT_JUMP (\"jge %l0\", \"jae %l0\", \"jns %l0\")")
+ "*
+{
+ if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
+ return AS1 (je,%l0);
+
+ OUTPUT_JUMP (\"jge %l0\", \"jae %l0\", \"jns %l0\");
+}")
+
+(define_expand "bgeu"
+ [(match_dup 1)
+ (set (pc)
+ (if_then_else (geu (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
-(define_insn "bgeu"
+(define_insn ""
[(set (pc)
(if_then_else (geu (cc0)
(const_int 0))
""
"jae %l0")
-;; See comment on `blt', above.
(define_expand "ble"
- [(set (pc)
+ [(match_dup 1)
+ (set (pc)
(if_then_else (le (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "
-{
- rtx prev = get_last_insn_anywhere ();
- rtx body = PATTERN (prev);
- rtx comp;
- if (GET_CODE (body) == SET)
- comp = SET_SRC (body);
- else
- comp = SET_SRC (XVECEXP (body, 0, 0));
-
- if (GET_CODE (comp) == COMPARE
- ? GET_MODE_CLASS (GET_MODE (XEXP (comp, 0))) == MODE_FLOAT
- : GET_MODE_CLASS (GET_MODE (comp)) == MODE_FLOAT)
- {
- reverse_comparison (prev);
- emit_insn (gen_bge (operands[0]));
- DONE;
- }
-}")
+ "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
(define_insn ""
[(set (pc)
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "*OUTPUT_JUMP (\"jle %l0\", \"jbe %l0\", 0) ")
+ "*
+{
+ if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
+ return AS1 (jb,%l0);
+
+ OUTPUT_JUMP (\"jle %l0\", \"jbe %l0\", 0);
+}")
+
+(define_expand "bleu"
+ [(match_dup 1)
+ (set (pc)
+ (if_then_else (leu (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
-(define_insn "bleu"
+(define_insn ""
[(set (pc)
(if_then_else (leu (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
- "*OUTPUT_JUMP (\"jle %l0\", \"jbe %l0\", 0) ")
+ "*
+{
+ if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
+ return AS1 (jne,%l0);
+
+ OUTPUT_JUMP (\"jle %l0\", \"jbe %l0\", 0);
+}")
(define_insn ""
[(set (pc)
(pc)
(label_ref (match_operand 0 "" ""))))]
""
- "*OUTPUT_JUMP (\"jge %l0\", \"jae %l0\", \"jns %l0\")
-")
+ "*
+{
+ if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
+ return AS1 (jne,%l0);
+
+ OUTPUT_JUMP (\"jge %l0\", \"jae %l0\", \"jns %l0\");
+}")
(define_insn ""
[(set (pc)
(pc)
(label_ref (match_operand 0 "" ""))))]
""
- "*OUTPUT_JUMP (\"jl %l0\", \"jb %l0\", \"js %l0\")")
+ "*
+{
+ if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
+ return AS1 (jne,%l0);
+
+ OUTPUT_JUMP (\"jl %l0\", \"jb %l0\", \"js %l0\");
+}")
(define_insn ""
[(set (pc)
(pc)
(label_ref (match_operand 0 "" ""))))]
""
- "*OUTPUT_JUMP (\"jg %l0\", \"ja %l0\", 0)")
+ "*
+{
+ if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
+ return AS1 (jae,%l0);
+
+ OUTPUT_JUMP (\"jg %l0\", \"ja %l0\", 0);
+}")
(define_insn ""
[(set (pc)
(minus:SI (match_operand:SI 0 "general_operand" "")
(match_operand:SI 1 "general_operand" "")))
(set (cc0)
- (compare (match_dup 5)
- (match_operand:SI 2 "general_operand" "")))
+ (compare:CC (match_dup 5)
+ (match_operand:SI 2 "general_operand" "")))
(set (pc)
(if_then_else (gtu (cc0)
(const_int 0))
(define_expand "cmpstrsi"
[(parallel [(set (match_operand:QI 0 "general_operand" "")
- (compare
+ (compare:CC
(mem:BLK (match_operand:BLK 1 "general_operand" ""))
(mem:BLK (match_operand:BLK 2 "general_operand" ""))))
(use (match_operand:SI 3 "general_operand" ""))
(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=&q")
- (compare (mem:BLK (match_operand:SI 1 "general_operand" "S"))
- (mem:BLK (match_operand:SI 2 "general_operand" "D"))))
+ (compare:CC (mem:BLK (match_operand:SI 1 "general_operand" "S"))
+ (mem:BLK (match_operand:SI 2 "general_operand" "D"))))
(use (match_operand:SI 3 "general_operand" "c"))
(use (match_operand:SI 4 "immediate_operand" "i"))
(clobber (match_dup 1))
(define_insn ""
[(set (cc0)
- (compare (mem:BLK (match_operand:SI 0 "general_operand" "S"))
- (mem:BLK (match_operand:SI 1 "general_operand" "D"))))
+ (compare:CC (mem:BLK (match_operand:SI 0 "general_operand" "S"))
+ (mem:BLK (match_operand:SI 1 "general_operand" "D"))))
(use (match_operand:SI 2 "general_operand" "c"))
(use (match_operand:SI 3 "immediate_operand" "i"))
(clobber (match_dup 0))