OSDN Git Service

*** empty log message ***
authorjrv <jrv@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 21 Apr 1992 05:40:51 +0000 (05:40 +0000)
committerjrv <jrv@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 21 Apr 1992 05:40:51 +0000 (05:40 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@808 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/config/i386/i386.c
gcc/config/i386/i386.h
gcc/config/i386/i386.md
gcc/emit-rtl.c
gcc/reg-stack.c
gcc/reorg.c

index 3495d1d..30858ea 100644 (file)
@@ -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)();
 \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
@@ -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)
 \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)
@@ -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);
+}
+\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
index e689541..e2a5cc9 100644 (file)
@@ -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}}
 \f
 /* target machine storage layout */
@@ -1146,6 +1153,33 @@ while (0)
    : REG_P (RTX) ? 1                                           \
    : 2)
 \f
+/* 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
index 561eb8f..319a934 100644 (file)
 ;; (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))
index 00945c8..ad8089b 100644 (file)
@@ -1516,6 +1516,23 @@ prev_label (insn)
 }
 \f
 #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).
index 62a549d..af7af39 100644 (file)
@@ -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),
index c7bb797..ebd208e 100644 (file)
@@ -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
 \f
 /* 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.  */