2
0
mirror of git://gcc.gnu.org/git/gcc.git synced 2024-12-21 14:09:44 +08:00

sparc-protos.h (select_cc_mode): Declare.

* sparc-protos.h (select_cc_mode): Declare.
        * sparc.c (select_cc_mode): New.  Handle unordered compares.
        (output_cbranch): Always reverse via code change.  Handle
        unordered compares.  Factor tests and string updates.
        * sparc.h (SELECT_CC_MODE): Split out to select_cc_mode.
        (REVERSIBLE_CC_MODE): Also exclude CCFPmode.
        * sparc.md (bunordered, bordered): New.
        (bungt, bunlt, buneq, bunge, bunle): New.

From-SVN: r31609
This commit is contained in:
Richard Henderson 2000-01-25 04:42:25 -08:00 committed by Richard Henderson
parent ddcc7cf6c8
commit e267e17731
5 changed files with 347 additions and 145 deletions

View File

@ -1,3 +1,14 @@
2000-01-25 Richard Henderson <rth@cygnus.com>
* sparc-protos.h (select_cc_mode): Declare.
* sparc.c (select_cc_mode): New. Handle unordered compares.
(output_cbranch): Always reverse via code change. Handle
unordered compares. Factor tests and string updates.
* sparc.h (SELECT_CC_MODE): Split out to select_cc_mode.
(REVERSIBLE_CC_MODE): Also exclude CCFPmode.
* sparc.md (bunordered, bordered): New.
(bungt, bunlt, buneq, bunge, bunle): New.
2000-01-25 Richard Henderson <rth@cygnus.com>
* dwarf2out.c (dwarf2out_init): Use ggc_add_rtx_varray_root.

View File

@ -77,6 +77,7 @@ extern void sparc_flat_save_restore PARAMS ((FILE *, const char *,
const char *, unsigned long));
#ifdef RTX_CODE
extern enum machine_mode select_cc_mode PARAMS ((enum rtx_code, rtx, rtx));
/* Define the function that build the compare insn for scc and bcc. */
extern rtx gen_compare_reg PARAMS ((enum rtx_code code, rtx, rtx));
extern void sparc_emit_float_lib_cmp PARAMS ((rtx, rtx, enum rtx_code));

View File

@ -2072,6 +2072,61 @@ sparc_emit_set_const64 (op0, op1)
sparc_emit_set_const64_longway (op0, temp, high_bits, low_bits);
}
/* 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,
CCFP[E]mode is used. CC_NOOVmode should be used when the first operand
is a PLUS, MINUS, NEG, or ASHIFT. CCmode should be used when no special
processing is needed. */
enum machine_mode
select_cc_mode (op, x, y)
enum rtx_code op;
rtx x;
rtx y ATTRIBUTE_UNUSED;
{
if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
{
switch (op)
{
case EQ:
case NE:
case UNORDERED:
case ORDERED:
case UNLT:
case UNLE:
case UNGT:
case UNGE:
case UNEQ:
case UNNE:
return CCFPmode;
case LT:
case LE:
case GT:
case GE:
return CCFPEmode;
default:
abort ();
}
}
else if (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS
|| GET_CODE (x) == NEG || GET_CODE (x) == ASHIFT)
{
if (TARGET_ARCH64 && GET_MODE (x) == DImode)
return CCX_NOOVmode;
else
return CC_NOOVmode;
}
else
{
if (TARGET_ARCH64 && GET_MODE (x) == DImode)
return CCXmode;
else
return CCmode;
}
}
/* X and Y are two things to compare using CODE. Emit the compare insn and
return the rtx for the cc reg in the proper mode. */
@ -4583,6 +4638,7 @@ output_cbranch (op, label, reversed, annul, noop, insn)
static char v9_xcc_labelno[] = "%%xcc, %lX";
static char v9_fcc_labelno[] = "%%fccX, %lY";
char *labelno;
const char *branch;
int labeloff, spaces = 8;
/* ??? !v9: FP branches cannot be preceded by another floating point insn.
@ -4594,147 +4650,158 @@ output_cbranch (op, label, reversed, annul, noop, insn)
else
string[0] = '\0';
/* If not floating-point or if EQ or NE, we can just reverse the code. */
if (reversed
&& ((mode != CCFPmode && mode != CCFPEmode) || code == EQ || code == NE))
code = reverse_condition (code), reversed = 0;
if (reversed)
{
/* Reversal of FP compares takes care -- an ordered compare
becomes an unordered compare and vice versa. */
if (mode == CCFPmode || mode == CCFPEmode)
{
switch (code)
{
case EQ:
code = NE;
break;
case NE:
code = EQ;
break;
case GE:
code = UNLT;
break;
case GT:
code = UNLE;
break;
case LE:
code = UNGT;
break;
case LT:
code = UNGE;
break;
case UNORDERED:
code = ORDERED;
break;
case ORDERED:
code = UNORDERED;
break;
case UNGT:
code = LE;
break;
case UNLT:
code = GE;
break;
case UNEQ:
/* ??? We don't have a "less or greater" rtx code. */
code = UNKNOWN;
break;
case UNGE:
code = LT;
break;
case UNLE:
code = GT;
break;
default:
abort ();
}
}
else
code = reverse_condition (code);
}
/* Start by writing the branch condition. */
switch (code)
{
case NE:
if (mode == CCFPmode || mode == CCFPEmode)
{
strcat (string, "fbne");
spaces -= 4;
}
else
{
strcpy (string, "bne");
spaces -= 3;
}
break;
if (mode == CCFPmode || mode == CCFPEmode)
switch (code)
{
case NE:
branch = "fbne";
break;
case EQ:
branch = "fbe";
break;
case GE:
branch = "fbge";
break;
case GT:
branch = "fbg";
break;
case LE:
branch = "fble";
break;
case LT:
branch = "fbl";
break;
case UNORDERED:
branch = "fbu";
break;
case ORDERED:
branch = "fbo";
break;
case UNGT:
branch = "fbug";
break;
case UNLT:
branch = "fbul";
break;
case UNEQ:
branch = "fbue";
break;
case UNGE:
branch = "fbuge";
break;
case UNLE:
branch = "fbule";
break;
case UNKNOWN:
branch = "fblg";
break;
case EQ:
if (mode == CCFPmode || mode == CCFPEmode)
{
strcat (string, "fbe");
spaces -= 3;
}
else
{
strcpy (string, "be");
spaces -= 2;
}
break;
default:
abort ();
}
else
switch (code)
{
case NE:
branch = "bne";
break;
case EQ:
branch = "be";
break;
case GE:
if (mode == CC_NOOVmode)
branch = "bpos";
else
branch = "bge";
break;
case GT:
branch = "bg";
break;
case LE:
branch = "ble";
break;
case LT:
if (mode == CC_NOOVmode)
branch = "bneg";
else
branch = "bl";
break;
case GEU:
branch = "bgeu";
break;
case GTU:
branch = "bgu";
break;
case LEU:
branch = "bleu";
break;
case LTU:
branch = "blu";
break;
case GE:
if (mode == CCFPmode || mode == CCFPEmode)
{
if (reversed)
strcat (string, "fbul");
else
strcat (string, "fbge");
spaces -= 4;
}
else if (mode == CC_NOOVmode)
{
strcpy (string, "bpos");
spaces -= 4;
}
else
{
strcpy (string, "bge");
spaces -= 3;
}
break;
case GT:
if (mode == CCFPmode || mode == CCFPEmode)
{
if (reversed)
{
strcat (string, "fbule");
spaces -= 5;
}
else
{
strcat (string, "fbg");
spaces -= 3;
}
}
else
{
strcpy (string, "bg");
spaces -= 2;
}
break;
case LE:
if (mode == CCFPmode || mode == CCFPEmode)
{
if (reversed)
strcat (string, "fbug");
else
strcat (string, "fble");
spaces -= 4;
}
else
{
strcpy (string, "ble");
spaces -= 3;
}
break;
case LT:
if (mode == CCFPmode || mode == CCFPEmode)
{
if (reversed)
{
strcat (string, "fbuge");
spaces -= 5;
}
else
{
strcat (string, "fbl");
spaces -= 3;
}
}
else if (mode == CC_NOOVmode)
{
strcpy (string, "bneg");
spaces -= 4;
}
else
{
strcpy (string, "bl");
spaces -= 2;
}
break;
case GEU:
strcpy (string, "bgeu");
spaces -= 4;
break;
case GTU:
strcpy (string, "bgu");
spaces -= 3;
break;
case LEU:
strcpy (string, "bleu");
spaces -= 4;
break;
case LTU:
strcpy (string, "blu");
spaces -= 3;
break;
default:
abort ();
}
default:
abort ();
}
strcpy (string, branch);
spaces -= strlen (branch);
/* Now add the annulling, the label, and a possible noop. */
if (annul)

View File

@ -2672,18 +2672,12 @@ do { \
CCFP[E]mode is used. CC_NOOVmode should be used when the first operand is a
PLUS, MINUS, NEG, or ASHIFT. CCmode should be used when no special
processing is needed. */
#define SELECT_CC_MODE(OP,X,Y) \
(GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT \
? ((OP == EQ || OP == NE) ? CCFPmode : CCFPEmode) \
: ((GET_CODE (X) == PLUS || GET_CODE (X) == MINUS \
|| GET_CODE (X) == NEG || GET_CODE (X) == ASHIFT) \
? (TARGET_ARCH64 && GET_MODE (X) == DImode ? CCX_NOOVmode : CC_NOOVmode) \
: ((TARGET_ARCH64 || TARGET_V8PLUS) && GET_MODE (X) == DImode ? CCXmode : CCmode)))
#define SELECT_CC_MODE(OP,X,Y) select_cc_mode ((OP), (X), (Y))
/* Return non-zero if SELECT_CC_MODE will never return MODE for a
floating point inequality comparison. */
#define REVERSIBLE_CC_MODE(MODE) ((MODE) != CCFPEmode)
#define REVERSIBLE_CC_MODE(MODE) ((MODE) != CCFPEmode && (MODE) != CCFPmode)
/* A function address in a call instruction
is a byte address (for indexing purposes)

View File

@ -1794,6 +1794,135 @@
"
{ operands[1] = gen_compare_reg (LEU, sparc_compare_op0, sparc_compare_op1);
}")
(define_expand "bunordered"
[(set (pc)
(if_then_else (unordered (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{
if (GET_MODE (sparc_compare_op0) == TFmode
&& TARGET_ARCH64 && ! TARGET_HARD_QUAD)
{
sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1,
UNORDERED);
emit_jump_insn (gen_bne (operands[0]));
DONE;
}
operands[1] = gen_compare_reg (UNORDERED, sparc_compare_op0,
sparc_compare_op1);
}")
(define_expand "bordered"
[(set (pc)
(if_then_else (ordered (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{
if (GET_MODE (sparc_compare_op0) == TFmode
&& TARGET_ARCH64 && ! TARGET_HARD_QUAD)
{
sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, ORDERED);
emit_jump_insn (gen_bne (operands[0]));
DONE;
}
operands[1] = gen_compare_reg (ORDERED, sparc_compare_op0,
sparc_compare_op1);
}")
(define_expand "bungt"
[(set (pc)
(if_then_else (ungt (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{
if (GET_MODE (sparc_compare_op0) == TFmode
&& TARGET_ARCH64 && ! TARGET_HARD_QUAD)
{
sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, UNGT);
emit_jump_insn (gen_bne (operands[0]));
DONE;
}
operands[1] = gen_compare_reg (UNGT, sparc_compare_op0, sparc_compare_op1);
}")
(define_expand "bunlt"
[(set (pc)
(if_then_else (unlt (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{
if (GET_MODE (sparc_compare_op0) == TFmode
&& TARGET_ARCH64 && ! TARGET_HARD_QUAD)
{
sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, UNLT);
emit_jump_insn (gen_bne (operands[0]));
DONE;
}
operands[1] = gen_compare_reg (UNLT, sparc_compare_op0, sparc_compare_op1);
}")
(define_expand "buneq"
[(set (pc)
(if_then_else (uneq (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{
if (GET_MODE (sparc_compare_op0) == TFmode
&& TARGET_ARCH64 && ! TARGET_HARD_QUAD)
{
sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, UNEQ);
emit_jump_insn (gen_bne (operands[0]));
DONE;
}
operands[1] = gen_compare_reg (UNEQ, sparc_compare_op0, sparc_compare_op1);
}")
(define_expand "bunge"
[(set (pc)
(if_then_else (unge (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{
if (GET_MODE (sparc_compare_op0) == TFmode
&& TARGET_ARCH64 && ! TARGET_HARD_QUAD)
{
sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, UNGE);
emit_jump_insn (gen_bne (operands[0]));
DONE;
}
operands[1] = gen_compare_reg (UNGE, sparc_compare_op0, sparc_compare_op1);
}")
(define_expand "bunle"
[(set (pc)
(if_then_else (unle (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{
if (GET_MODE (sparc_compare_op0) == TFmode
&& TARGET_ARCH64 && ! TARGET_HARD_QUAD)
{
sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, UNLE);
emit_jump_insn (gen_bne (operands[0]));
DONE;
}
operands[1] = gen_compare_reg (UNLE, sparc_compare_op0, sparc_compare_op1);
}")
;; Now match both normal and inverted jump.