diff options
-rw-r--r-- | gcc/ChangeLog | 11 | ||||
-rw-r--r-- | gcc/config/sparc/sparc-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.c | 327 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.h | 10 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.md | 129 |
5 files changed, 340 insertions, 138 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index edc2475..46a83ac 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,16 @@ 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. diff --git a/gcc/config/sparc/sparc-protos.h b/gcc/config/sparc/sparc-protos.h index ff46790..c9c79a0 100644 --- a/gcc/config/sparc/sparc-protos.h +++ b/gcc/config/sparc/sparc-protos.h @@ -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)); diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index bacdfcd..f459832 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -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; - - /* 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) diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h index 09667ca..02f0116 100644 --- a/gcc/config/sparc/sparc.h +++ b/gcc/config/sparc/sparc.h @@ -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) diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index d704965..ac8f9aa 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -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. |