From: Jakub Jelinek Date: Wed, 13 Mar 2002 19:48:29 +0000 (+0100) Subject: re PR target/5626 (gcc-3.1 on sparcv9 does not generate code for long jumps) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0b82d204c4533d773c8a38094cf82c7a04f17a61;p=gcc.git re PR target/5626 (gcc-3.1 on sparcv9 does not generate code for long jumps) PR target/5626 * config/sparc/sparc.md (normal_branch, inverted_branch, normal_fp_branch, inverted_fp_branch, normal_fpe_branch, inverted_fp_branch): Adjust calls to output_cbranch. Set length attribute. (normal_int_branch_sp64, inverted_int_branch_sp64): Adjust calls to output_v9branch. Set length attribute. * config/sparc/sparc.c (fcc0_reg_operand, noov_compare64_op): New predicates. (noov_compare_op): Handle CCX_NOOVmode the same way as CC_NOOVmode. (output_cbranch): Likewise. Handle far branches. (output_v9branch): Handle far branches. * config/sparc/sparc-protos.h (output_cbranch, output_v9branch): Adjust prototypes. * config/sparc/sparc.h (PREDICATE_CODES): Add fcc0_reg_operand and noov_compare64_op predicates. From-SVN: r50753 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c7ed555c992..4286a2112cb 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2002-03-13 Jakub Jelinek + + PR target/5626 + * config/sparc/sparc.md (normal_branch, inverted_branch, + normal_fp_branch, inverted_fp_branch, normal_fpe_branch, + inverted_fp_branch): Adjust calls to output_cbranch. + Set length attribute. + (normal_int_branch_sp64, inverted_int_branch_sp64): Adjust calls to + output_v9branch. Set length attribute. + * config/sparc/sparc.c (fcc0_reg_operand, noov_compare64_op): New + predicates. + (noov_compare_op): Handle CCX_NOOVmode the same way as CC_NOOVmode. + (output_cbranch): Likewise. Handle far branches. + (output_v9branch): Handle far branches. + * config/sparc/sparc-protos.h (output_cbranch, output_v9branch): + Adjust prototypes. + * config/sparc/sparc.h (PREDICATE_CODES): Add fcc0_reg_operand and + noov_compare64_op predicates. + 2002-03-13 Jason Merrill * gthr-posix.h (__gthread_active_p): Move __gthread_active_ptr diff --git a/gcc/config/sparc/sparc-protos.h b/gcc/config/sparc/sparc-protos.h index c0f3edce65d..682b7bdb853 100644 --- a/gcc/config/sparc/sparc-protos.h +++ b/gcc/config/sparc/sparc-protos.h @@ -85,10 +85,11 @@ extern void sparc_emit_set_const64 PARAMS ((rtx, rtx)); extern void sparc_emit_set_symbolic_const64 PARAMS ((rtx, rtx, rtx)); extern int sparc_splitdi_legitimate PARAMS ((rtx, rtx)); extern int sparc_absnegfloat_split_legitimate PARAMS ((rtx, rtx)); -extern char *output_cbranch PARAMS ((rtx, int, int, int, int, rtx)); +extern char *output_cbranch PARAMS ((rtx, rtx, int, int, int, int, rtx)); extern const char *output_return PARAMS ((rtx *)); extern const char *output_sibcall PARAMS ((rtx, rtx)); -extern char *output_v9branch PARAMS ((rtx, int, int, int, int, int, rtx)); +extern char *output_v9branch PARAMS ((rtx, rtx, int, int, int, int, int, + rtx)); extern void emit_v9_brxx_insn PARAMS ((enum rtx_code, rtx, rtx)); extern void print_operand PARAMS ((FILE *, rtx, int)); extern int mems_ok_for_ldd_peep PARAMS ((rtx, rtx, rtx)); diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index d678aa2a2f4..6f33bcc0cb9 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -608,6 +608,27 @@ fcc_reg_operand (op, mode) #endif } +/* Nonzero if OP is a floating point condition code fcc0 register. */ + +int +fcc0_reg_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + /* This can happen when recog is called from combine. Op may be a MEM. + Fail instead of calling abort in this case. */ + if (GET_CODE (op) != REG) + return 0; + + if (mode != VOIDmode && mode != GET_MODE (op)) + return 0; + if (mode == VOIDmode + && (GET_MODE (op) != CCFPmode && GET_MODE (op) != CCFPEmode)) + return 0; + + return REGNO (op) == SPARC_FCC_REG; +} + /* Nonzero if OP is an integer or floating point condition code register. */ int @@ -878,12 +899,35 @@ noov_compare_op (op, mode) if (GET_RTX_CLASS (code) != '<') return 0; - if (GET_MODE (XEXP (op, 0)) == CC_NOOVmode) + if (GET_MODE (XEXP (op, 0)) == CC_NOOVmode + || GET_MODE (XEXP (op, 0)) == CCX_NOOVmode) /* These are the only branches which work with CC_NOOVmode. */ return (code == EQ || code == NE || code == GE || code == LT); return 1; } +/* Return 1 if this is a 64-bit comparison operator. This allows the use of + MATCH_OPERATOR to recognize all the branch insns. */ + +int +noov_compare64_op (op, mode) + register rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + enum rtx_code code = GET_CODE (op); + + if (! TARGET_V9) + return 0; + + if (GET_RTX_CLASS (code) != '<') + return 0; + + if (GET_MODE (XEXP (op, 0)) == CCX_NOOVmode) + /* These are the only branches which work with CCX_NOOVmode. */ + return (code == EQ || code == NE || code == GE || code == LT); + return (GET_MODE (XEXP (op, 0)) == CCXmode); +} + /* Nonzero if OP is a comparison operator suitable for use in v9 conditional move or branch on register contents instructions. */ @@ -4996,25 +5040,43 @@ sparc_va_arg (valist, type) INSN, if set, is the insn. */ char * -output_cbranch (op, label, reversed, annul, noop, insn) - rtx op; +output_cbranch (op, dest, label, reversed, annul, noop, insn) + rtx op, dest; int label; int reversed, annul, noop; rtx insn; { - static char string[32]; + static char string[50]; enum rtx_code code = GET_CODE (op); rtx cc_reg = XEXP (op, 0); enum machine_mode mode = GET_MODE (cc_reg); - static char v8_labelno[] = "%lX"; - static char v9_icc_labelno[] = "%%icc, %lX"; - static char v9_xcc_labelno[] = "%%xcc, %lX"; - static char v9_fcc_labelno[] = "%%fccX, %lY"; - char *labelno; - const char *branch; - int labeloff, spaces = 8; + const char *labelno, *branch; + int spaces = 8, far; + char *p; + + /* v9 branches are limited to +-1MB. If it is too far away, + change + + bne,pt %xcc, .LC30 + + to + + be,pn %xcc, .+12 + nop + ba .LC30 + + and + + fbne,a,pn %fcc2, .LC29 - if (reversed) + to + + fbe,pt %fcc2, .+16 + nop + ba .LC29 */ + + far = get_attr_length (insn) >= 3; + if (reversed ^ far) { /* Reversal of FP compares takes care -- an ordered compare becomes an unordered compare and vice versa. */ @@ -5097,7 +5159,7 @@ output_cbranch (op, label, reversed, annul, noop, insn) branch = "be"; break; case GE: - if (mode == CC_NOOVmode) + if (mode == CC_NOOVmode || mode == CCX_NOOVmode) branch = "bpos"; else branch = "bge"; @@ -5109,7 +5171,7 @@ output_cbranch (op, label, reversed, annul, noop, insn) branch = "ble"; break; case LT: - if (mode == CC_NOOVmode) + if (mode == CC_NOOVmode || mode == CCX_NOOVmode) branch = "bneg"; else branch = "bl"; @@ -5133,54 +5195,89 @@ output_cbranch (op, label, reversed, annul, noop, insn) strcpy (string, branch); } spaces -= strlen (branch); + p = strchr (string, '\0'); /* Now add the annulling, the label, and a possible noop. */ - if (annul) + if (annul && ! far) { - strcat (string, ",a"); + strcpy (p, ",a"); + p += 2; spaces -= 2; } if (! TARGET_V9) - { - labeloff = 2; - labelno = v8_labelno; - } + labelno = ""; else { rtx note; + int v8 = 0; - if (insn && (note = find_reg_note (insn, REG_BR_PRED, NULL_RTX))) + if (! far && insn && INSN_ADDRESSES_SET_P ()) { - strcat (string, - INTVAL (XEXP (note, 0)) & ATTR_FLAG_likely ? ",pt" : ",pn"); - spaces -= 3; + int delta = (INSN_ADDRESSES (INSN_UID (dest)) + - INSN_ADDRESSES (INSN_UID (insn))); + /* Leave some instructions for "slop". */ + if (delta < -260000 || delta >= 260000) + v8 = 1; } - labeloff = 9; if (mode == CCFPmode || mode == CCFPEmode) { - labeloff = 10; - labelno = v9_fcc_labelno; + static char v9_fcc_labelno[] = "%%fccX, "; /* Set the char indicating the number of the fcc reg to use. */ - labelno[5] = REGNO (cc_reg) - SPARC_FIRST_V9_FCC_REG + '0'; + v9_fcc_labelno[5] = REGNO (cc_reg) - SPARC_FIRST_V9_FCC_REG + '0'; + labelno = v9_fcc_labelno; + if (v8) + { + if (REGNO (cc_reg) == SPARC_FCC_REG) + labelno = ""; + else + abort (); + } } else if (mode == CCXmode || mode == CCX_NOOVmode) - labelno = v9_xcc_labelno; + { + labelno = "%%xcc, "; + if (v8) + abort (); + } else - labelno = v9_icc_labelno; + { + labelno = "%%icc, "; + if (v8) + labelno = ""; + } + + if (*labelno && insn && (note = find_reg_note (insn, REG_BR_PRED, NULL_RTX))) + { + strcpy (p, + (((INTVAL (XEXP (note, 0)) & ATTR_FLAG_likely) != 0) ^ far) + ? ",pt" : ",pn"); + p += 3; + spaces -= 3; + } } - /* Set the char indicating the number of the operand containing the - label_ref. */ - labelno[labeloff] = label + '0'; if (spaces > 0) - strcat (string, "\t"); + *p++ = '\t'; else - strcat (string, " "); - strcat (string, labelno); - + *p++ = ' '; + strcpy (p, labelno); + p = strchr (p, '\0'); + if (far) + { + strcpy (p, ".+12\n\tnop\n\tb\t"); + if (annul || noop) + p[3] = '6'; + p += 13; + } + *p++ = '%'; + *p++ = 'l'; + /* Set the char indicating the number of the operand containing the + label_ref. */ + *p++ = label + '0'; + *p = '\0'; if (noop) - strcat (string, "\n\tnop"); + strcpy (p, "\n\tnop"); return string; } @@ -5338,22 +5435,45 @@ sparc_emit_float_lib_cmp (x, y, comparison) NOOP is non-zero if we have to follow this branch by a noop. */ char * -output_v9branch (op, reg, label, reversed, annul, noop, insn) - rtx op; +output_v9branch (op, dest, reg, label, reversed, annul, noop, insn) + rtx op, dest; int reg, label; int reversed, annul, noop; rtx insn; { - static char string[20]; + static char string[50]; enum rtx_code code = GET_CODE (op); enum machine_mode mode = GET_MODE (XEXP (op, 0)); - static char labelno[] = "%X, %lX"; rtx note; - int spaces = 8; + int far; + char *p; + + /* branch on register are limited to +-128KB. If it is too far away, + change + + brnz,pt %g1, .LC30 + + to + + brz,pn %g1, .+12 + nop + ba,pt %xcc, .LC30 + + and + + brgez,a,pn %o1, .LC29 + + to + + brlz,pt %o1, .+16 + nop + ba,pt %xcc, .LC29 */ + + far = get_attr_length (insn) >= 3; /* If not floating-point or if EQ or NE, we can just reverse the code. */ - if (reversed) - code = reverse_condition (code), reversed = 0; + if (reversed ^ far) + code = reverse_condition (code); /* Only 64 bit versions of these instructions exist. */ if (mode != DImode) @@ -5365,62 +5485,90 @@ output_v9branch (op, reg, label, reversed, annul, noop, insn) { case NE: strcpy (string, "brnz"); - spaces -= 4; break; case EQ: strcpy (string, "brz"); - spaces -= 3; break; case GE: strcpy (string, "brgez"); - spaces -= 5; break; case LT: strcpy (string, "brlz"); - spaces -= 4; break; case LE: strcpy (string, "brlez"); - spaces -= 5; break; case GT: strcpy (string, "brgz"); - spaces -= 4; break; default: abort (); } + p = strchr (string, '\0'); + /* Now add the annulling, reg, label, and nop. */ - if (annul) + if (annul && ! far) { - strcat (string, ",a"); - spaces -= 2; + strcpy (p, ",a"); + p += 2; } if (insn && (note = find_reg_note (insn, REG_BR_PRED, NULL_RTX))) { - strcat (string, - INTVAL (XEXP (note, 0)) & ATTR_FLAG_likely ? ",pt" : ",pn"); - spaces -= 3; + strcpy (p, + (((INTVAL (XEXP (note, 0)) & ATTR_FLAG_likely) != 0) ^ far) + ? ",pt" : ",pn"); + p += 3; } - labelno[1] = reg + '0'; - labelno[6] = label + '0'; - if (spaces > 0) - strcat (string, "\t"); - else - strcat (string, " "); - strcat (string, labelno); + *p = p < string + 8 ? '\t' : ' '; + p++; + *p++ = '%'; + *p++ = '0' + reg; + *p++ = ','; + *p++ = ' '; + if (far) + { + int veryfar = 1, delta; + + if (INSN_ADDRESSES_SET_P ()) + { + delta = (INSN_ADDRESSES (INSN_UID (dest)) + - INSN_ADDRESSES (INSN_UID (insn))); + /* Leave some instructions for "slop". */ + if (delta >= -260000 && delta < 260000) + veryfar = 0; + } + + strcpy (p, ".+12\n\tnop\n\t"); + if (annul || noop) + p[3] = '6'; + p += 11; + if (veryfar) + { + strcpy (p, "b\t"); + p += 2; + } + else + { + strcpy (p, "ba,pt\t%%xcc, "); + p += 13; + } + } + *p++ = '%'; + *p++ = 'l'; + *p++ = '0' + label; + *p = '\0'; if (noop) - strcat (string, "\n\tnop"); + strcpy (p, "\n\tnop"); return string; } diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h index 8caa9328acd..e765973c07d 100644 --- a/gcc/config/sparc/sparc.h +++ b/gcc/config/sparc/sparc.h @@ -2974,6 +2974,7 @@ do { \ {"fp_zero_operand", {CONST_DOUBLE}}, \ {"intreg_operand", {SUBREG, REG}}, \ {"fcc_reg_operand", {REG}}, \ +{"fcc0_reg_operand", {REG}}, \ {"icc_or_fcc_reg_operand", {REG}}, \ {"restore_operand", {REG}}, \ {"call_operand", {MEM}}, \ @@ -2991,6 +2992,7 @@ do { \ {"eq_or_neq", {EQ, NE}}, \ {"normal_comp_operator", {GE, GT, LE, LT, GTU, LEU}}, \ {"noov_compare_op", {NE, EQ, GE, GT, LE, LT, GEU, GTU, LEU, LTU}}, \ +{"noov_compare64_op", {NE, EQ, GE, GT, LE, LT, GEU, GTU, LEU, LTU}}, \ {"v9_regcmp_op", {EQ, NE, GE, LT, LE, GT}}, \ {"extend_op", {SIGN_EXTEND, ZERO_EXTEND}}, \ {"cc_arithop", {AND, IOR, XOR}}, \ diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index 18b2ba8f90f..c203e4fa892 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -1893,11 +1893,23 @@ "" "* { - return output_cbranch (operands[0], 1, 0, + return output_cbranch (operands[0], operands[1], 1, 0, final_sequence && INSN_ANNULLED_BRANCH_P (insn), ! final_sequence, insn); }" - [(set_attr "type" "branch")]) + [(set_attr "type" "branch") + (set (attr "length") + (if_then_else (match_operand 0 "noov_compare64_op" "") + (if_then_else (lt (pc) (match_dup 1)) + (if_then_else (lt (minus (match_dup 1) (pc)) + (const_int 260000)) + (const_int 1) + (const_int 3)) + (if_then_else (lt (minus (pc) (match_dup 1)) + (const_int 260000)) + (const_int 1) + (const_int 3))) + (const_int 1)))]) ;; XXX fpcmp nop braindamage (define_insn "*inverted_branch" @@ -1909,11 +1921,23 @@ "" "* { - return output_cbranch (operands[0], 1, 1, + return output_cbranch (operands[0], operands[1], 1, 1, final_sequence && INSN_ANNULLED_BRANCH_P (insn), ! final_sequence, insn); }" - [(set_attr "type" "branch")]) + [(set_attr "type" "branch") + (set (attr "length") + (if_then_else (match_operand 0 "noov_compare64_op" "") + (if_then_else (lt (pc) (match_dup 1)) + (if_then_else (lt (minus (match_dup 1) (pc)) + (const_int 260000)) + (const_int 1) + (const_int 3)) + (if_then_else (lt (minus (pc) (match_dup 1)) + (const_int 260000)) + (const_int 1) + (const_int 3))) + (const_int 1)))]) ;; XXX fpcmp nop braindamage (define_insn "*normal_fp_branch" @@ -1926,11 +1950,23 @@ "" "* { - return output_cbranch (operands[1], 2, 0, + return output_cbranch (operands[1], operands[2], 2, 0, final_sequence && INSN_ANNULLED_BRANCH_P (insn), ! final_sequence, insn); }" - [(set_attr "type" "branch")]) + [(set_attr "type" "branch") + (set (attr "length") + (if_then_else (match_operand 0 "fcc0_reg_operand" "") + (const_int 1) + (if_then_else (lt (pc) (match_dup 2)) + (if_then_else (lt (minus (match_dup 2) (pc)) + (const_int 260000)) + (const_int 1) + (const_int 3)) + (if_then_else (lt (minus (pc) (match_dup 2)) + (const_int 260000)) + (const_int 1) + (const_int 3)))))]) ;; XXX fpcmp nop braindamage (define_insn "*inverted_fp_branch" @@ -1943,11 +1979,23 @@ "" "* { - return output_cbranch (operands[1], 2, 1, + return output_cbranch (operands[1], operands[2], 2, 1, final_sequence && INSN_ANNULLED_BRANCH_P (insn), ! final_sequence, insn); }" - [(set_attr "type" "branch")]) + [(set_attr "type" "branch") + (set (attr "length") + (if_then_else (match_operand 0 "fcc0_reg_operand" "") + (const_int 1) + (if_then_else (lt (pc) (match_dup 2)) + (if_then_else (lt (minus (match_dup 2) (pc)) + (const_int 260000)) + (const_int 1) + (const_int 3)) + (if_then_else (lt (minus (pc) (match_dup 2)) + (const_int 260000)) + (const_int 1) + (const_int 3)))))]) ;; XXX fpcmp nop braindamage (define_insn "*normal_fpe_branch" @@ -1960,11 +2008,23 @@ "" "* { - return output_cbranch (operands[1], 2, 0, + return output_cbranch (operands[1], operands[2], 2, 0, final_sequence && INSN_ANNULLED_BRANCH_P (insn), ! final_sequence, insn); }" - [(set_attr "type" "branch")]) + [(set_attr "type" "branch") + (set (attr "length") + (if_then_else (match_operand 0 "fcc0_reg_operand" "") + (const_int 1) + (if_then_else (lt (pc) (match_dup 2)) + (if_then_else (lt (minus (match_dup 2) (pc)) + (const_int 260000)) + (const_int 1) + (const_int 3)) + (if_then_else (lt (minus (pc) (match_dup 2)) + (const_int 260000)) + (const_int 1) + (const_int 3)))))]) ;; XXX fpcmp nop braindamage (define_insn "*inverted_fpe_branch" @@ -1977,11 +2037,23 @@ "" "* { - return output_cbranch (operands[1], 2, 1, + return output_cbranch (operands[1], operands[2], 2, 1, final_sequence && INSN_ANNULLED_BRANCH_P (insn), ! final_sequence, insn); }" - [(set_attr "type" "branch")]) + [(set_attr "type" "branch") + (set (attr "length") + (if_then_else (match_operand 0 "fcc0_reg_operand" "") + (const_int 1) + (if_then_else (lt (pc) (match_dup 2)) + (if_then_else (lt (minus (match_dup 2) (pc)) + (const_int 260000)) + (const_int 1) + (const_int 3)) + (if_then_else (lt (minus (pc) (match_dup 2)) + (const_int 260000)) + (const_int 1) + (const_int 3)))))]) ;; Sparc V9-specific jump insns. None of these are guaranteed to be ;; in the architecture. @@ -1999,11 +2071,21 @@ "TARGET_ARCH64" "* { - return output_v9branch (operands[0], 1, 2, 0, + return output_v9branch (operands[0], operands[2], 1, 2, 0, final_sequence && INSN_ANNULLED_BRANCH_P (insn), ! final_sequence, insn); }" - [(set_attr "type" "branch")]) + [(set_attr "type" "branch") + (set (attr "length") + (if_then_else (lt (pc) (match_dup 2)) + (if_then_else (lt (minus (match_dup 2) (pc)) + (const_int 32000)) + (const_int 1) + (const_int 3)) + (if_then_else (lt (minus (pc) (match_dup 2)) + (const_int 32000)) + (const_int 1) + (const_int 3))))]) ;; XXX (define_insn "*inverted_int_branch_sp64" @@ -2016,11 +2098,21 @@ "TARGET_ARCH64" "* { - return output_v9branch (operands[0], 1, 2, 1, + return output_v9branch (operands[0], operands[2], 1, 2, 1, final_sequence && INSN_ANNULLED_BRANCH_P (insn), ! final_sequence, insn); }" - [(set_attr "type" "branch")]) + [(set_attr "type" "branch") + (set (attr "length") + (if_then_else (lt (pc) (match_dup 2)) + (if_then_else (lt (minus (match_dup 2) (pc)) + (const_int 32000)) + (const_int 1) + (const_int 3)) + (if_then_else (lt (minus (pc) (match_dup 2)) + (const_int 32000)) + (const_int 1) + (const_int 3))))]) ;; Load program counter insns.