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.
* ggc-common.c (ggc_add_rtx_varray_root): New.
(ggc_mark_rtx_varray): New.
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));
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. */
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.
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;
-
- /* Start by writing the branch condition. */
- switch (code)
+ if (reversed)
{
- case NE:
- if (mode == CCFPmode || mode == CCFPEmode)
- {
- strcat (string, "fbne");
- spaces -= 4;
- }
- else
- {
- strcpy (string, "bne");
- spaces -= 3;
- }
- break;
-
- case EQ:
- if (mode == CCFPmode || mode == CCFPEmode)
- {
- strcat (string, "fbe");
- spaces -= 3;
- }
- else
- {
- strcpy (string, "be");
- spaces -= 2;
- }
- break;
-
- case GE:
+ /* Reversal of FP compares takes care -- an ordered compare
+ becomes an unordered compare and vice versa. */
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)
+ switch (code)
{
- 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 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;
- case LT:
- if (mode == CCFPmode || mode == CCFPEmode)
- {
- if (reversed)
- {
- strcat (string, "fbuge");
- spaces -= 5;
+ default:
+ abort ();
}
- 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;
+ code = reverse_condition (code);
+ }
- case LEU:
- strcpy (string, "bleu");
- spaces -= 4;
- break;
+ /* Start by writing the branch condition. */
+ 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 LTU:
- strcpy (string, "blu");
- spaces -= 3;
- 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;
- default:
- abort ();
- }
+ default:
+ abort ();
+ }
+ strcpy (string, branch);
+ spaces -= strlen (branch);
/* Now add the annulling, the label, and a possible noop. */
if (annul)
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)
"
{ 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);
+}")
\f
;; Now match both normal and inverted jump.