alpha.c (alpha_emit_conditional_branch): Handle TFmode unordered compares properly.

* 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
This commit is contained in:
Richard Henderson 2000-09-24 21:02:20 -07:00 committed by Richard Henderson
parent 2ed4af6f2d
commit 9e49570050
4 changed files with 170 additions and 104 deletions

View 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.

View 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));

View 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. */

View File

@ -3349,8 +3349,8 @@
}")
(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" "")))]
""
"
{
@ -3460,144 +3460,73 @@
[(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; }")
;; These are the main define_expand's used to make conditional moves.