alpha.c (alpha_emit_conditional_branch): Handle TFmode unordered compares properly.
authorRichard Henderson <rth@cygnus.com>
Mon, 25 Sep 2000 04:02:20 +0000 (21:02 -0700)
committerRichard Henderson <rth@gcc.gnu.org>
Mon, 25 Sep 2000 04:02:20 +0000 (21:02 -0700)
        * config/alpha/alpha.c (alpha_emit_conditional_branch): Handle
        TFmode unordered compares properly.  Revalidate integer compare
        operands.
        (alpha_emit_setcc): New.
        (alpha_emit_conditional_move): Revalidate integer compare operands.
        * config/alpha/alpha-protos.h: Update.
        * config/alpha/alpha.md (cmpdi): Allow general operands.
        (sne): Use alpha_emit_setcc.
        (seq, slt, sle, sgt, sge, sltu, sleu, sgtu, sgeu): Likewise.
        (sunordered, sordered): New.

From-SVN: r36598

gcc/ChangeLog
gcc/config/alpha/alpha-protos.h
gcc/config/alpha/alpha.c
gcc/config/alpha/alpha.md

index aa4a660fd41072bede02a564324730d338acbf95..0d8923e6bc90a1910cad7e812f664a91ed8d1022 100644 (file)
@@ -1,3 +1,16 @@
+2000-09-24  Richard Henderson  <rth@cygnus.com>
+
+       * config/alpha/alpha.c (alpha_emit_conditional_branch): Handle
+       TFmode unordered compares properly.  Revalidate integer compare
+       operands.
+       (alpha_emit_setcc): New.
+       (alpha_emit_conditional_move): Revalidate integer compare operands.
+       * config/alpha/alpha-protos.h: Update.
+       * config/alpha/alpha.md (cmpdi): Allow general operands.
+       (sne): Use alpha_emit_setcc.
+       (seq, slt, sle, sgt, sge, sltu, sleu, sgtu, sgeu): Likewise.
+       (sunordered, sordered): New.
+
 2000-09-24  Richard Henderson  <rth@cygnus.com>
 
        * config/ia64/ia64-protos.h: Update.
index 9bdf142ad5503d47577ddffc552600585eff5476..d70ac7fe821a9bdc00e84f14dcdfe6321579f52c 100644 (file)
@@ -83,6 +83,7 @@ extern rtx alpha_emit_set_long_const PARAMS ((rtx, HOST_WIDE_INT,
                                             HOST_WIDE_INT));
 extern void alpha_emit_floatuns PARAMS ((rtx[]));
 extern rtx alpha_emit_conditional_branch PARAMS ((enum rtx_code));
+extern rtx alpha_emit_setcc PARAMS ((enum rtx_code));
 extern rtx alpha_emit_conditional_move PARAMS ((rtx, enum machine_mode));
 extern int alpha_split_conditional_move PARAMS ((enum rtx_code, rtx, rtx,
                                                 rtx, rtx));
index 382f9358204d1776280ec592456f8fbf2265b984..20a494d3ccb152f25fd198371229b97a94c7df3f 100644 (file)
@@ -1620,10 +1620,21 @@ alpha_emit_conditional_branch (code)
            1  true
         Convert the compare against the raw return value.  */
 
-      op0 = alpha_emit_xfloating_compare (code, op0, op1);
+      if (code == UNORDERED || code == ORDERED)
+       cmp_code = EQ;
+      else
+       cmp_code = code;
+
+      op0 = alpha_emit_xfloating_compare (cmp_code, op0, op1);
       op1 = const0_rtx;
       alpha_compare.fp_p = 0;
-      code = GT;
+
+      if (code == UNORDERED)
+       code = LT;
+      else if (code == ORDERED)
+       code = GE;
+      else
+        code = GT;
     }
 
   /* The general case: fold the comparison code to the types of compares
@@ -1713,11 +1724,12 @@ alpha_emit_conditional_branch (code)
                }
            }
        }
-    }
 
-  /* Force op0 into a register.  */
-  if (GET_CODE (op0) != REG)
-    op0 = force_reg (cmp_mode, op0);
+      if (!reg_or_0_operand (op0, DImode))
+       op0 = force_reg (DImode, op0);
+      if (cmp_code != PLUS && !reg_or_8bit_operand (op1, DImode))
+       op1 = force_reg (DImode, op1);
+    }
 
   /* Emit an initial compare instruction, if necessary.  */
   tem = op0;
@@ -1734,6 +1746,111 @@ alpha_emit_conditional_branch (code)
   return gen_rtx_fmt_ee (branch_code, branch_mode, tem, CONST0_RTX (cmp_mode));
 }
 
+/* Certain simplifications can be done to make invalid setcc operations
+   valid.  Return the final comparison, or NULL if we can't work.  */
+
+rtx
+alpha_emit_setcc (code)
+     enum rtx_code code;
+{
+  enum rtx_code cmp_code;
+  rtx op0 = alpha_compare.op0, op1 = alpha_compare.op1;
+  int fp_p = alpha_compare.fp_p;
+  rtx tmp;
+
+  /* Zero the operands.  */
+  memset (&alpha_compare, 0, sizeof (alpha_compare));
+
+  if (fp_p && GET_MODE (op0) == TFmode)
+    {
+      if (! TARGET_HAS_XFLOATING_LIBS)
+       abort ();
+
+      /* X_floating library comparison functions return
+          -1  unordered
+           0  false
+           1  true
+        Convert the compare against the raw return value.  */
+
+      if (code == UNORDERED || code == ORDERED)
+       cmp_code = EQ;
+      else
+       cmp_code = code;
+
+      op0 = alpha_emit_xfloating_compare (cmp_code, op0, op1);
+      op1 = const0_rtx;
+      fp_p = 0;
+
+      if (code == UNORDERED)
+       code = LT;
+      else if (code == ORDERED)
+       code = GE;
+      else
+        code = GT;
+    }
+
+  if (fp_p && !TARGET_FIX)
+    return NULL_RTX;
+
+  /* The general case: fold the comparison code to the types of compares
+     that we have, choosing the branch as necessary.  */
+
+  cmp_code = NIL;
+  switch (code)
+    {
+    case EQ:  case LE:  case LT:  case LEU:  case LTU:
+    case UNORDERED:
+      /* We have these compares.  */
+      if (fp_p)
+       cmp_code = code, code = NE;
+      break;
+
+    case NE:
+      if (!fp_p && op1 == const0_rtx)
+       break;
+      /* FALLTHRU */
+
+    case ORDERED:
+      cmp_code = reverse_condition (code);
+      code = EQ;
+      break;
+
+    case GE:  case GT: case GEU:  case GTU:
+      code = swap_condition (code);
+      if (fp_p)
+       cmp_code = code, code = NE;
+      tmp = op0, op0 = op1, op1 = tmp;
+      break;
+
+    default:
+      abort ();
+    }
+
+  if (!fp_p)
+    {
+      if (!reg_or_0_operand (op0, DImode))
+       op0 = force_reg (DImode, op0);
+      if (!reg_or_8bit_operand (op1, DImode))
+       op1 = force_reg (DImode, op1);
+    }
+
+  /* Emit an initial compare instruction, if necessary.  */
+  if (cmp_code != NIL)
+    {
+      enum machine_mode mode = fp_p ? DFmode : DImode;
+
+      tmp = gen_reg_rtx (mode);
+      emit_insn (gen_rtx_SET (VOIDmode, tmp,
+                             gen_rtx_fmt_ee (cmp_code, mode, op0, op1)));
+
+      op0 = fp_p ? gen_lowpart (DImode, tmp) : tmp;
+      op1 = const0_rtx;
+    }
+
+  /* Return the setcc comparison.  */
+  return gen_rtx_fmt_ee (code, DImode, op0, op1);
+}
+
 
 /* Rewrite a comparison against zero CMP of the form
    (CODE (cc0) (const_int 0)) so it can be written validly in
@@ -1836,17 +1953,23 @@ alpha_emit_conditional_move (cmp, mode)
       break;
 
     case GE:  case GT:  case GEU:  case GTU:
-      /* These must be swapped.  Make sure the new first operand is in
-        a register.  */
+      /* These must be swapped.  */
       code = swap_condition (code);
       tem = op0, op0 = op1, op1 = tem;
-      op0 = force_reg (cmp_mode, op0);
       break;
 
     default:
       abort ();
     }
 
+  if (!fp_p)
+    {
+      if (!reg_or_0_operand (op0, DImode))
+       op0 = force_reg (DImode, op0);
+      if (!reg_or_8bit_operand (op1, DImode))
+       op1 = force_reg (DImode, op1);
+    }
+
   /* ??? We mark the branch mode to be CCmode to prevent the compare
      and cmov from being combined, since the compare insn follows IEEE
      rules that the cmov does not.  */
index 36d16c244c8ba9e22b8b84bddc653c8df66c507b..23d0365b5c37604548502b47c4a92bf6a7d3c14c 100644 (file)
 }")
 
 (define_expand "cmpdi"
-  [(set (cc0) (compare (match_operand:DI 0 "reg_or_0_operand" "")
-                      (match_operand:DI 1 "reg_or_8bit_operand" "")))]
+  [(set (cc0) (compare (match_operand:DI 0 "general_operand" "")
+                      (match_operand:DI 1 "general_operand" "")))]
   ""
   "
 {
   [(set (match_operand:DI 0 "register_operand" "")
        (match_dup 1))]
   ""
-  "
-{
-  if (alpha_compare.fp_p)
-    FAIL;
-
-  operands[1] = gen_rtx_EQ (DImode, alpha_compare.op0, alpha_compare.op1);
-  alpha_compare.op0 = alpha_compare.op1 = NULL_RTX;
-}")
+  "{ if ((operands[1] = alpha_emit_setcc (EQ)) == NULL_RTX) FAIL; }")
 
 (define_expand "sne"
   [(set (match_operand:DI 0 "register_operand" "")
-       (match_dup 1))
-   (set (match_dup 0) (xor:DI (match_dup 0) (const_int 1)))]
+       (match_dup 1))]
   ""
-  "
-{
-  if (alpha_compare.fp_p)
-    FAIL;
-
-  if (alpha_compare.op1 == const0_rtx)
-    {
-      operands[1] = gen_rtx_NE (DImode, alpha_compare.op0, alpha_compare.op1);
-      alpha_compare.op0 = alpha_compare.op1 = NULL_RTX;
-      emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
-      DONE;
-    }
-
-  operands[1] = gen_rtx_EQ (DImode, alpha_compare.op0, alpha_compare.op1);
-  alpha_compare.op0 = alpha_compare.op1 = NULL_RTX;
-}")
+  "{ if ((operands[1] = alpha_emit_setcc (NE)) == NULL_RTX) FAIL; }")
 
 (define_expand "slt"
   [(set (match_operand:DI 0 "register_operand" "")
        (match_dup 1))]
   ""
-  "
-{
-  if (alpha_compare.fp_p)
-    FAIL;
-
-  operands[1] = gen_rtx_LT (DImode, alpha_compare.op0, alpha_compare.op1);
-  alpha_compare.op0 = alpha_compare.op1 = NULL_RTX;
-}")
+  "{ if ((operands[1] = alpha_emit_setcc (LT)) == NULL_RTX) FAIL; }")
 
 (define_expand "sle"
   [(set (match_operand:DI 0 "register_operand" "")
        (match_dup 1))]
   ""
-  "
-{
-  if (alpha_compare.fp_p)
-    FAIL;
-
-  operands[1] = gen_rtx_LE (DImode, alpha_compare.op0, alpha_compare.op1);
-  alpha_compare.op0 = alpha_compare.op1 = NULL_RTX;
-}")
+  "{ if ((operands[1] = alpha_emit_setcc (LE)) == NULL_RTX) FAIL; }")
 
 (define_expand "sgt"
   [(set (match_operand:DI 0 "register_operand" "")
        (match_dup 1))]
   ""
-  "
-{
-  if (alpha_compare.fp_p)
-    FAIL;
-
-  operands[1] = gen_rtx_LT (DImode, force_reg (DImode, alpha_compare.op1),
-                           alpha_compare.op0);
-  alpha_compare.op0 = alpha_compare.op1 = NULL_RTX;
-}")
+  "{ if ((operands[1] = alpha_emit_setcc (GT)) == NULL_RTX) FAIL; }")
 
 (define_expand "sge"
   [(set (match_operand:DI 0 "register_operand" "")
        (match_dup 1))]
   ""
-  "
-{
-  if (alpha_compare.fp_p)
-    FAIL;
-
-  operands[1] = gen_rtx_LE (DImode, force_reg (DImode, alpha_compare.op1),
-                           alpha_compare.op0);
-  alpha_compare.op0 = alpha_compare.op1 = NULL_RTX;
-}")
+  "{ if ((operands[1] = alpha_emit_setcc (GE)) == NULL_RTX) FAIL; }")
 
 (define_expand "sltu"
   [(set (match_operand:DI 0 "register_operand" "")
        (match_dup 1))]
   ""
-  "
-{
-  if (alpha_compare.fp_p)
-    FAIL;
-
-  operands[1] = gen_rtx_LTU (DImode, alpha_compare.op0, alpha_compare.op1);
-  alpha_compare.op0 = alpha_compare.op1 = NULL_RTX;
-}")
+  "{ if ((operands[1] = alpha_emit_setcc (LTU)) == NULL_RTX) FAIL; }")
 
 (define_expand "sleu"
   [(set (match_operand:DI 0 "register_operand" "")
        (match_dup 1))]
   ""
-  "
-{
-  if (alpha_compare.fp_p)
-    FAIL;
-
-  operands[1] = gen_rtx_LEU (DImode, alpha_compare.op0, alpha_compare.op1);
-  alpha_compare.op0 = alpha_compare.op1 = NULL_RTX;
-}")
+  "{ if ((operands[1] = alpha_emit_setcc (LEU)) == NULL_RTX) FAIL; }")
 
 (define_expand "sgtu"
   [(set (match_operand:DI 0 "register_operand" "")
        (match_dup 1))]
   ""
-  "
-{
-  if (alpha_compare.fp_p)
-    FAIL;
-
-  operands[1] = gen_rtx_LTU (DImode, force_reg (DImode, alpha_compare.op1),
-                            alpha_compare.op0);
-  alpha_compare.op0 = alpha_compare.op1 = NULL_RTX;
-}")
+  "{ if ((operands[1] = alpha_emit_setcc (GTU)) == NULL_RTX) FAIL; }")
 
 (define_expand "sgeu"
   [(set (match_operand:DI 0 "register_operand" "")
        (match_dup 1))]
   ""
-  "
-{
-  if (alpha_compare.fp_p)
-    FAIL;
+  "{ if ((operands[1] = alpha_emit_setcc (GEU)) == NULL_RTX) FAIL; }")
 
-  operands[1] = gen_rtx_LEU (DImode, force_reg (DImode, alpha_compare.op1),
-                            alpha_compare.op0);
-  alpha_compare.op0 = alpha_compare.op1 = NULL_RTX;
-}")
+(define_expand "sunordered"
+  [(set (match_operand:DI 0 "register_operand" "")
+       (match_dup 1))]
+  ""
+  "{ if ((operands[1] = alpha_emit_setcc (UNORDERED)) == NULL_RTX) FAIL; }")
+
+(define_expand "sordered"
+  [(set (match_operand:DI 0 "register_operand" "")
+       (match_dup 1))]
+  ""
+  "{ if ((operands[1] = alpha_emit_setcc (ORDERED)) == NULL_RTX) FAIL; }")
 \f
 ;; These are the main define_expand's used to make conditional moves.