From: James Van Artsdalen Date: Tue, 21 Apr 1992 05:40:51 +0000 (+0000) Subject: *** empty log message *** X-Git-Tag: misc/cutover-egcs-0~13123 X-Git-Url: https://gcc.gnu.org/git/?a=commitdiff_plain;h=c572e5ba687d4e4c7c380e47750ead7c84a8ef39;p=gcc.git *** empty log message *** From-SVN: r808 --- diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 3495d1da6b11..30858eaf8995 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -45,6 +45,7 @@ extern char *strcat (); 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; @@ -65,6 +66,12 @@ enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] = /* 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)(); /* 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 @@ -1353,6 +1360,8 @@ notice_update_cc (exp) 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; @@ -1679,7 +1688,8 @@ output_fix_trunc (insn, operands) /* 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) @@ -1687,6 +1697,8 @@ 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 (); @@ -1702,15 +1714,21 @@ output_float_compare (insn, operands) 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"); @@ -1728,10 +1746,102 @@ output_float_compare (insn, operands) /* Now retrieve the condition code. */ - output_asm_insn (AS1 (fnsts%W2,%2), operands); + return output_fp_cc0_set (insn); +} + +/* 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; } #ifdef HANDLE_PRAGMA diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index e689541b3938..e2a5cc9c44c4 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -61,6 +61,11 @@ extern int target_flags; Meaningful only on svr3. */ #define TARGET_SVR3_SHLIB (target_flags & 040) +/* Use IEEE floating point comparisons. These handle correctly the cases + where the result of a comparison is unordered. Normally SIGFPE is + generated in such cases, in which case this isn't needed. */ +#define TARGET_IEEE_FP (target_flags & 0100) + /* Macro to define tables used to set the flags. This is a list in braces of pairs in braces, each pair being { "NAME", VALUE } @@ -79,6 +84,8 @@ extern int target_flags; { "noregparm", -020}, \ { "svr3-shlib", 040}, \ { "nosvr3-shlib", -040}, \ + { "ieee-fp", 0100}, \ + { "noieee-fp", -0100}, \ { "", TARGET_DEFAULT}} /* target machine storage layout */ @@ -1146,6 +1153,33 @@ while (0) : REG_P (RTX) ? 1 \ : 2) +/* Add any extra modes needed to represent the condition code. + + For the i386, we need separate modes when floating-point equality + comparisons are being done. */ + +#define EXTRA_CC_MODES CCFPEQmode + +/* Define the names for the modes specified above. */ +#define EXTRA_CC_NAMES "CCFPEQ" + +/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, + return the mode to be used for the comparison. + + For floating-point equality comparisons, CCFPEQmode should be used. + VOIDmode should be used in all other cases. */ + +#define SELECT_CC_MODE(OP,X) \ + (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT \ + && ((OP) == EQ || (OP) == NE) ? CCFPEQmode : CCmode) + +/* Define the information needed to generate branch and scc insns. This is + stored from the compare operation. Note that we can't use "rtx" here + since it hasn't been defined! */ + +extern struct rtx_def *i386_compare_op0, *i386_compare_op1; +extern struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)(); + /* Tell final.c how to eliminate redundant test instructions. */ /* Here we define machine-dependent flags and fields in cc_status diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 561eb8f7173d..319a9342c070 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -62,7 +62,11 @@ ;; (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"))] "" @@ -75,7 +79,18 @@ 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"))] "" @@ -88,7 +103,18 @@ 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"))] "" @@ -101,54 +127,90 @@ 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; }") -;;- 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")))] "" "* { @@ -160,10 +222,23 @@ 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")))] "" "* { @@ -175,10 +250,23 @@ 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")))] "" "* { @@ -190,69 +278,142 @@ 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]); +}") ;; logical compare @@ -1454,7 +1615,7 @@ 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")) @@ -2645,7 +2806,24 @@ ;; 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)))] "" @@ -2655,10 +2833,23 @@ 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)))] "" @@ -2671,47 +2862,120 @@ } ") -(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") @@ -2722,7 +2986,27 @@ ;; 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)) @@ -2737,7 +3021,24 @@ 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)) @@ -2752,16 +3053,42 @@ 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)) @@ -2770,35 +3097,15 @@ "" "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) @@ -2807,9 +3114,25 @@ (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)) @@ -2818,16 +3141,42 @@ "" "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)) @@ -2836,33 +3185,15 @@ "" "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) @@ -2871,9 +3202,25 @@ (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)) @@ -2921,7 +3268,13 @@ (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) @@ -2939,8 +3292,13 @@ (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) @@ -2958,7 +3316,13 @@ (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) @@ -2976,7 +3340,13 @@ (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) @@ -3015,8 +3385,8 @@ (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)) @@ -3358,7 +3728,7 @@ (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" "")) @@ -3383,8 +3753,8 @@ (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)) @@ -3415,8 +3785,8 @@ (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)) diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index 00945c838a83..ad8089bec12c 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -1516,6 +1516,23 @@ prev_label (insn) } #ifdef HAVE_cc0 +/* INSN uses CC0 and is being moved into a delay slot. Set up REG_CC_SETTER + and REG_CC_USER notes so we can find it. */ + +void +link_cc0_insns (insn) + rtx insn; +{ + rtx user = next_nonnote_insn (insn); + + if (GET_CODE (user) == INSN && GET_CODE (PATTERN (user)) == SEQUENCE) + user = XVECEXP (PATTERN (user), 0, 0); + + REG_NOTES (user) = gen_rtx (INSN_LIST, REG_CC_SETTER, insn, + REG_NOTES (user)); + REG_NOTES (insn) = gen_rtx (INSN_LIST, REG_CC_USER, user, REG_NOTES (insn)); +} + /* Return the next insn that uses CC0 after INSN, which is assumed to set it. This is the inverse of prev_cc0_setter (i.e., prev_cc0_setter applied to the result of this function should yield INSN). diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c index 62a549d19a72..af7af39acb9e 100644 --- a/gcc/reg-stack.c +++ b/gcc/reg-stack.c @@ -1825,6 +1825,8 @@ compare_for_stack_reg (insn, regstack, pat) the case handled above. In all other cases, emit a separate pop and remove the death note from here. */ + link_cc0_insns (insn); + remove_regno_note (insn, REG_DEAD, REGNO (XEXP (src2_note, 0))); emit_pop_insn (insn, regstack, XEXP (src2_note, 0), diff --git a/gcc/reorg.c b/gcc/reorg.c index c7bb797a9e1c..ebd208e18638 100644 --- a/gcc/reorg.c +++ b/gcc/reorg.c @@ -779,25 +779,6 @@ add_to_delay_list (insn, delay_list) return delay_list; } - -#ifdef HAVE_cc0 -/* INSN uses CC0 and is being moved into a delay slot. Set up REG_CC_SETTER - and REG_CC_USER notes so we can find it. */ - -static void -link_cc0_insns (insn) - rtx insn; -{ - rtx user = next_nonnote_insn (insn); - - if (GET_CODE (user) == INSN && GET_CODE (PATTERN (user)) == SEQUENCE) - user = XVECEXP (PATTERN (user), 0, 0); - - REG_NOTES (user) = gen_rtx (INSN_LIST, REG_CC_SETTER, insn, - REG_NOTES (user)); - REG_NOTES (insn) = gen_rtx (INSN_LIST, REG_CC_USER, user, REG_NOTES (insn)); -} -#endif /* Delete INSN from the the delay slot of the insn that it is in. This may produce an insn without anything in its delay slots. */