diff options
author | David S. Miller <davem@davemloft.net> | 2012-11-15 21:24:22 +0000 |
---|---|---|
committer | David S. Miller <davem@gcc.gnu.org> | 2012-11-15 13:24:22 -0800 |
commit | 8b98b5fd9f9e4edb38a6b7eeb91b5a77ad91d95c (patch) | |
tree | f03d2f8dce9c22de2316eabb57bfd128e7c91f42 /gcc/config | |
parent | 2bf33cdb91a46f5c8ead75a57ec11766f8e6863e (diff) | |
download | gcc-8b98b5fd9f9e4edb38a6b7eeb91b5a77ad91d95c.zip gcc-8b98b5fd9f9e4edb38a6b7eeb91b5a77ad91d95c.tar.gz gcc-8b98b5fd9f9e4edb38a6b7eeb91b5a77ad91d95c.tar.bz2 |
Add support for sparc fused compare-and-branch.
gcc/
2012-11-15 David S. Miller <davem@davemloft.net>
* configure.ac: Add check for assembler SPARC4 instruction
support.
* configure: Rebuild.
* config.in: Add HAVE_AS_SPARC4 section.
* config/sparc/sparc.opt (mcbcond): New option.
* doc/invoke.texi: Document it.
* config/sparc/constraints.md: New constraint 'A' for 5-bit signed
immediates.
* doc/md.texi: Document it.
* config/sparc/sparc.c (dump_target_flag_bits): Handle MASK_CBCOND.
(sparc_option_override): Likewise.
(emit_cbcond_insn): New function.
(emit_conditional_branch_insn): Call it.
(emit_cbcond_nop): New function.
(output_ubranch): Use cbcond, remove label arg.
(output_cbcond): New function.
* config/sparc/sparc-protos.h (output_ubranch): Update.
(output_cbcond): Declare it.
(emit_cbcond_nop): Likewise.
* config/sparc/sparc.md (type attribute): New types 'cbcond'
and uncond_cbcond.
(emit_cbcond_nop): New attribute.
(length attribute): Handle cbcond and uncond_cbcond.
(in_call_delay attribute): Reject cbcond and uncond_cbcond.
(in_branch_delay attribute): Likewise.
(in_uncond_branch_delay attribute): Likewise.
(in_annul_branch_delay attribute): Likewise.
(*cbcond_sp32, *cbcond_sp64): New insn patterns.
(jump): Rewrite into an expander.
(*jump_ubranch, *jump_cbcond): New patterns.
* config/sparc/niagara4.md: Match 'cbcond' in 'n4_cti'.
* config/sparc/sparc.h (AS_NIAGARA4_FLAG): New macro, use it
when target default is niagara4.
(SPARC_SIMM5_P): Define.
* config/sparc/sol2.h (AS_SPARC64_FLAG): Adjust.
(AS_SPARC32_FLAG): Define.
(ASM_CPU32_DEFAULT_SPEC, ASM_CPU64_DEFAULT_SPEC): Use
AS_NIAGARA4_FLAG as needed.
From-SVN: r193543
Diffstat (limited to 'gcc/config')
-rw-r--r-- | gcc/config/sparc/constraints.md | 7 | ||||
-rw-r--r-- | gcc/config/sparc/niagara4.md | 6 | ||||
-rw-r--r-- | gcc/config/sparc/predicates.md | 8 | ||||
-rw-r--r-- | gcc/config/sparc/sol2.h | 95 | ||||
-rw-r--r-- | gcc/config/sparc/sparc-protos.h | 4 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.c | 245 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.h | 13 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.md | 81 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.opt | 4 |
9 files changed, 401 insertions, 62 deletions
diff --git a/gcc/config/sparc/constraints.md b/gcc/config/sparc/constraints.md index 8963a31..525e3ac 100644 --- a/gcc/config/sparc/constraints.md +++ b/gcc/config/sparc/constraints.md @@ -18,7 +18,7 @@ ;; <http://www.gnu.org/licenses/>. ;;; Unused letters: -;;; AB +;;; B ;;; a jkl q tuv xyz @@ -58,6 +58,11 @@ ;; Integer constant constraints +(define_constraint "A" + "Signed 5-bit integer constant" + (and (match_code "const_int") + (match_test "SPARC_SIMM5_P (ival)"))) + (define_constraint "H" "Valid operand of double arithmetic operation" (and (match_code "const_double") diff --git a/gcc/config/sparc/niagara4.md b/gcc/config/sparc/niagara4.md index 272c8ff..26f2391 100644 --- a/gcc/config/sparc/niagara4.md +++ b/gcc/config/sparc/niagara4.md @@ -54,10 +54,10 @@ (eq_attr "type" "store,fpstore")) "(n4_slot0 | n4_slot2) + n4_load_store") -(define_insn_reservation "n4_cti" 2 +(define_insn_reservation "n4_cti" 1 (and (eq_attr "cpu" "niagara4") - (eq_attr "type" "branch,call,sibcall,call_no_delay_slot,uncond_branch,return")) - "n4_slot1, nothing") + (eq_attr "type" "cbcond,uncond_cbcond,branch,call,sibcall,call_no_delay_slot,uncond_branch,return")) + "n4_slot1") (define_insn_reservation "n4_fp" 11 (and (eq_attr "cpu" "niagara4") diff --git a/gcc/config/sparc/predicates.md b/gcc/config/sparc/predicates.md index 326524b..b64e109 100644 --- a/gcc/config/sparc/predicates.md +++ b/gcc/config/sparc/predicates.md @@ -391,6 +391,14 @@ (ior (match_operand 0 "register_operand") (match_operand 0 "uns_small_int_operand"))) +;; Return true if OP is a register, or is a CONST_INT that can fit in a +;; signed 5-bit immediate field. This is an acceptable second operand for +;; the cbcond instructions. +(define_predicate "arith5_operand" + (ior (match_operand 0 "register_operand") + (and (match_code "const_int") + (match_test "SPARC_SIMM5_P (INTVAL (op))")))) + ;; Predicates for miscellaneous instructions. diff --git a/gcc/config/sparc/sol2.h b/gcc/config/sparc/sol2.h index 90dfd89..25ff347 100644 --- a/gcc/config/sparc/sol2.h +++ b/gcc/config/sparc/sol2.h @@ -54,19 +54,56 @@ along with GCC; see the file COPYING3. If not see /* Supposedly the same as vanilla sparc svr4, except for the stuff below: */ -/* This is here rather than in sparc.h because it's not known what - other assemblers will accept. */ +/* If the assembler supports -xarch=sparc4, we switch to the explicit + word size selection mechanism available both in GNU as and Sun as, + for the Niagara4 and above configurations. */ +#ifdef HAVE_AS_SPARC4 + +#define AS_SPARC32_FLAG "" +#define AS_SPARC64_FLAG "" #ifndef USE_GAS -#define AS_SPARC64_FLAG "-xarch=v9" -#else -#define AS_SPARC64_FLAG "-TSO -64 -Av9" +#undef ASM_ARCH32_SPEC +#define ASM_ARCH32_SPEC "-m32" +#undef ASM_ARCH64_SPEC +#define ASM_ARCH64_SPEC "-m64" #endif +/* Both Sun as and GNU as understand -K PIC. */ +#undef ASM_SPEC +#define ASM_SPEC ASM_SPEC_BASE " %(asm_arch)" ASM_PIC_SPEC + +#else /* HAVE_AS_SPARC4 */ + +#define AS_SPARC32_FLAG "-xarch=v8plus" +#define AS_SPARC64_FLAG "-xarch=v9" + +#undef AS_NIAGARA4_FLAG +#define AS_NIAGARA4_FLAG AS_NIAGARA3_FLAG + +#undef ASM_ARCH32_SPEC +#define ASM_ARCH32_SPEC "" + +#undef ASM_ARCH64_SPEC +#define ASM_ARCH64_SPEC "" + +#undef ASM_ARCH_DEFAULT_SPEC +#define ASM_ARCH_DEFAULT_SPEC "" + +#undef ASM_ARCH_SPEC +#define ASM_ARCH_SPEC "" + +/* Both Sun as and GNU as understand -K PIC. */ +#undef ASM_SPEC +#define ASM_SPEC ASM_SPEC_BASE ASM_PIC_SPEC + +#endif /* HAVE_AS_SPARC4 */ + + #undef ASM_CPU32_DEFAULT_SPEC #define ASM_CPU32_DEFAULT_SPEC "" #undef ASM_CPU64_DEFAULT_SPEC -#define ASM_CPU64_DEFAULT_SPEC AS_SPARC64_FLAG +#define ASM_CPU64_DEFAULT_SPEC "-xarch=v9" #if TARGET_CPU_DEFAULT == TARGET_CPU_v9 #undef CPP_CPU64_DEFAULT_SPEC @@ -83,7 +120,7 @@ along with GCC; see the file COPYING3. If not see #undef ASM_CPU32_DEFAULT_SPEC #define ASM_CPU32_DEFAULT_SPEC "-xarch=v8plusa" #undef ASM_CPU64_DEFAULT_SPEC -#define ASM_CPU64_DEFAULT_SPEC AS_SPARC64_FLAG "a" +#define ASM_CPU64_DEFAULT_SPEC "-xarch=v9a" #undef ASM_CPU_DEFAULT_SPEC #define ASM_CPU_DEFAULT_SPEC ASM_CPU32_DEFAULT_SPEC #endif @@ -94,7 +131,7 @@ along with GCC; see the file COPYING3. If not see #undef ASM_CPU32_DEFAULT_SPEC #define ASM_CPU32_DEFAULT_SPEC "-xarch=v8plusb" #undef ASM_CPU64_DEFAULT_SPEC -#define ASM_CPU64_DEFAULT_SPEC AS_SPARC64_FLAG "b" +#define ASM_CPU64_DEFAULT_SPEC "-xarch=v9b" #undef ASM_CPU_DEFAULT_SPEC #define ASM_CPU_DEFAULT_SPEC ASM_CPU32_DEFAULT_SPEC #endif @@ -105,7 +142,7 @@ along with GCC; see the file COPYING3. If not see #undef ASM_CPU32_DEFAULT_SPEC #define ASM_CPU32_DEFAULT_SPEC "-xarch=v8plusb" #undef ASM_CPU64_DEFAULT_SPEC -#define ASM_CPU64_DEFAULT_SPEC AS_SPARC64_FLAG "b" +#define ASM_CPU64_DEFAULT_SPEC "-xarch=v9b" #undef ASM_CPU_DEFAULT_SPEC #define ASM_CPU_DEFAULT_SPEC ASM_CPU32_DEFAULT_SPEC #endif @@ -116,7 +153,7 @@ along with GCC; see the file COPYING3. If not see #undef ASM_CPU32_DEFAULT_SPEC #define ASM_CPU32_DEFAULT_SPEC "-xarch=v8plusb" #undef ASM_CPU64_DEFAULT_SPEC -#define ASM_CPU64_DEFAULT_SPEC AS_SPARC64_FLAG "b" +#define ASM_CPU64_DEFAULT_SPEC "-xarch=v9b" #undef ASM_CPU_DEFAULT_SPEC #define ASM_CPU_DEFAULT_SPEC ASM_CPU32_DEFAULT_SPEC #endif @@ -127,7 +164,7 @@ along with GCC; see the file COPYING3. If not see #undef ASM_CPU32_DEFAULT_SPEC #define ASM_CPU32_DEFAULT_SPEC "-xarch=v8plus" AS_NIAGARA3_FLAG #undef ASM_CPU64_DEFAULT_SPEC -#define ASM_CPU64_DEFAULT_SPEC AS_SPARC64_FLAG AS_NIAGARA3_FLAG +#define ASM_CPU64_DEFAULT_SPEC "-xarch=v9" AS_NIAGARA3_FLAG #undef ASM_CPU_DEFAULT_SPEC #define ASM_CPU_DEFAULT_SPEC ASM_CPU32_DEFAULT_SPEC #endif @@ -136,17 +173,13 @@ along with GCC; see the file COPYING3. If not see #undef CPP_CPU64_DEFAULT_SPEC #define CPP_CPU64_DEFAULT_SPEC "" #undef ASM_CPU32_DEFAULT_SPEC -#define ASM_CPU32_DEFAULT_SPEC "-xarch=v8plus" AS_NIAGARA3_FLAG +#define ASM_CPU32_DEFAULT_SPEC AS_SPARC32_FLAG AS_NIAGARA4_FLAG #undef ASM_CPU64_DEFAULT_SPEC -#define ASM_CPU64_DEFAULT_SPEC AS_SPARC64_FLAG AS_NIAGARA3_FLAG +#define ASM_CPU64_DEFAULT_SPEC AS_SPARC64_FLAG AS_NIAGARA4_FLAG #undef ASM_CPU_DEFAULT_SPEC #define ASM_CPU_DEFAULT_SPEC ASM_CPU32_DEFAULT_SPEC #endif -/* Both Sun as and GNU as understand -K PIC. */ -#undef ASM_SPEC -#define ASM_SPEC ASM_SPEC_BASE ASM_PIC_SPEC - #undef CPP_CPU_SPEC #define CPP_CPU_SPEC "\ %{mcpu=sparclet|mcpu=tsc701:-D__sparclet__} \ @@ -235,29 +268,17 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); #undef ASM_CPU_SPEC #define ASM_CPU_SPEC "\ -%{mcpu=v9:" DEF_ARCH32_SPEC("-xarch=v8plus") DEF_ARCH64_SPEC(AS_SPARC64_FLAG) "} \ -%{mcpu=ultrasparc:" DEF_ARCH32_SPEC("-xarch=v8plusa") DEF_ARCH64_SPEC(AS_SPARC64_FLAG "a") "} \ -%{mcpu=ultrasparc3:" DEF_ARCH32_SPEC("-xarch=v8plusb") DEF_ARCH64_SPEC(AS_SPARC64_FLAG "b") "} \ -%{mcpu=niagara:" DEF_ARCH32_SPEC("-xarch=v8plusb") DEF_ARCH64_SPEC(AS_SPARC64_FLAG "b") "} \ -%{mcpu=niagara2:" DEF_ARCH32_SPEC("-xarch=v8plusb") DEF_ARCH64_SPEC(AS_SPARC64_FLAG "b") "} \ -%{mcpu=niagara3:" DEF_ARCH32_SPEC("-xarch=v8plus" AS_NIAGARA3_FLAG) DEF_ARCH64_SPEC(AS_SPARC64_FLAG AS_NIAGARA3_FLAG) "} \ -%{mcpu=niagara4:" DEF_ARCH32_SPEC("-xarch=v8plus" AS_NIAGARA3_FLAG) DEF_ARCH64_SPEC(AS_SPARC64_FLAG AS_NIAGARA3_FLAG) "} \ -%{!mcpu=niagara4:%{!mcpu=niagara3:%{!mcpu=niagara2:%{!mcpu=niagara:%{!mcpu=ultrasparc3:%{!mcpu=ultrasparc:%{!mcpu=v9:%{mcpu*:" DEF_ARCH32_SPEC("-xarch=v8") DEF_ARCH64_SPEC(AS_SPARC64_FLAG) "}}}}}}}} \ +%{mcpu=v9:" DEF_ARCH32_SPEC("-xarch=v8plus") DEF_ARCH64_SPEC("-xarch=v9") "} \ +%{mcpu=ultrasparc:" DEF_ARCH32_SPEC("-xarch=v8plusa") DEF_ARCH64_SPEC("-xarch=v9a") "} \ +%{mcpu=ultrasparc3:" DEF_ARCH32_SPEC("-xarch=v8plusb") DEF_ARCH64_SPEC("-xarch=v9b") "} \ +%{mcpu=niagara:" DEF_ARCH32_SPEC("-xarch=v8plusb") DEF_ARCH64_SPEC("-xarch=v9b") "} \ +%{mcpu=niagara2:" DEF_ARCH32_SPEC("-xarch=v8plusb") DEF_ARCH64_SPEC("-xarch=v9b") "} \ +%{mcpu=niagara3:" DEF_ARCH32_SPEC("-xarch=v8plus" AS_NIAGARA3_FLAG) DEF_ARCH64_SPEC("-xarch=v9" AS_NIAGARA3_FLAG) "} \ +%{mcpu=niagara4:" DEF_ARCH32_SPEC(AS_SPARC32_FLAG AS_NIAGARA4_FLAG) DEF_ARCH64_SPEC(AS_SPARC64_FLAG AS_NIAGARA4_FLAG) "} \ +%{!mcpu=niagara4:%{!mcpu=niagara3:%{!mcpu=niagara2:%{!mcpu=niagara:%{!mcpu=ultrasparc3:%{!mcpu=ultrasparc:%{!mcpu=v9:%{mcpu*:" DEF_ARCH32_SPEC("-xarch=v8") DEF_ARCH64_SPEC("-xarch=v9") "}}}}}}}} \ %{!mcpu*:%(asm_cpu_default)} \ " -#undef ASM_ARCH32_SPEC -#define ASM_ARCH32_SPEC "" - -#undef ASM_ARCH64_SPEC -#define ASM_ARCH64_SPEC "" - -#undef ASM_ARCH_DEFAULT_SPEC -#define ASM_ARCH_DEFAULT_SPEC "" - -#undef ASM_ARCH_SPEC -#define ASM_ARCH_SPEC "" - #ifdef USE_GLD /* Since binutils 2.21, GNU ld supports new *_sol2 emulations to strictly follow the Solaris 2 ABI. Prefer them if present. */ diff --git a/gcc/config/sparc/sparc-protos.h b/gcc/config/sparc/sparc-protos.h index 97f6233..d5b2b1f 100644 --- a/gcc/config/sparc/sparc-protos.h +++ b/gcc/config/sparc/sparc-protos.h @@ -71,7 +71,7 @@ extern void sparc_emit_set_symbolic_const64 (rtx, rtx, rtx); extern int sparc_splitdi_legitimate (rtx, rtx); extern int sparc_split_regreg_legitimate (rtx, rtx); extern int sparc_absnegfloat_split_legitimate (rtx, rtx); -extern const char *output_ubranch (rtx, int, rtx); +extern const char *output_ubranch (rtx, rtx); extern const char *output_cbranch (rtx, rtx, int, int, int, rtx); extern const char *output_return (rtx); extern const char *output_sibcall (rtx, rtx); @@ -79,10 +79,12 @@ extern const char *output_v8plus_shift (rtx, rtx *, const char *); extern const char *output_v8plus_mult (rtx, rtx *, const char *); extern const char *output_v9branch (rtx, rtx, int, int, int, int, rtx); extern const char *output_probe_stack_range (rtx, rtx); +extern const char *output_cbcond (rtx, rtx, rtx); extern bool emit_scc_insn (rtx []); extern void emit_conditional_branch_insn (rtx []); extern int mems_ok_for_ldd_peep (rtx, rtx, rtx); extern int empty_delay_slot (rtx); +extern int emit_cbcond_nop (rtx); extern int eligible_for_return_delay (rtx); extern int eligible_for_sibcall_delay (rtx); extern int tls_call_delay (rtx); diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 272632e..4e9de98 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -840,6 +840,8 @@ dump_target_flag_bits (const int flags) fprintf (stderr, "VIS2 "); if (flags & MASK_VIS3) fprintf (stderr, "VIS3 "); + if (flags & MASK_CBCOND) + fprintf (stderr, "CBCOND "); if (flags & MASK_DEPRECATED_V8_INSNS) fprintf (stderr, "DEPRECATED_V8_INSNS "); if (flags & MASK_SPARCLET) @@ -946,7 +948,7 @@ sparc_option_override (void) MASK_V9|MASK_POPC|MASK_VIS2|MASK_VIS3|MASK_FMAF }, /* UltraSPARC T4 */ { "niagara4", MASK_ISA, - MASK_V9|MASK_POPC|MASK_VIS2|MASK_VIS3|MASK_FMAF }, + MASK_V9|MASK_POPC|MASK_VIS2|MASK_VIS3|MASK_FMAF|MASK_CBCOND }, }; const struct cpu_table *cpu; unsigned int i; @@ -1073,6 +1075,9 @@ sparc_option_override (void) #ifndef HAVE_AS_FMAF_HPC_VIS3 & ~(MASK_FMAF | MASK_VIS3) #endif +#ifndef HAVE_AS_SPARC4 + & ~MASK_CBCOND +#endif ); /* If -mfpu or -mno-fpu was explicitly used, don't override with @@ -1088,7 +1093,8 @@ sparc_option_override (void) if (TARGET_VIS3) target_flags |= MASK_VIS2 | MASK_VIS; - /* Don't allow -mvis, -mvis2, -mvis3, or -mfmaf if FPU is disabled. */ + /* Don't allow -mvis, -mvis2, -mvis3, or -mfmaf if FPU is + disabled. */ if (! TARGET_FPU) target_flags &= ~(MASK_VIS | MASK_VIS2 | MASK_VIS3 | MASK_FMAF); @@ -2660,6 +2666,24 @@ emit_v9_brxx_insn (enum rtx_code code, rtx op0, rtx label) pc_rtx))); } +/* Emit a conditional jump insn for the UA2011 architecture using + comparison code CODE and jump target LABEL. This function exists + to take advantage of the UA2011 Compare and Branch insns. */ + +static void +emit_cbcond_insn (enum rtx_code code, rtx op0, rtx op1, rtx label) +{ + rtx if_then_else; + + if_then_else = gen_rtx_IF_THEN_ELSE (VOIDmode, + gen_rtx_fmt_ee(code, GET_MODE(op0), + op0, op1), + gen_rtx_LABEL_REF (VOIDmode, label), + pc_rtx); + + emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, if_then_else)); +} + void emit_conditional_branch_insn (rtx operands[]) { @@ -2674,6 +2698,20 @@ emit_conditional_branch_insn (rtx operands[]) operands[2] = XEXP (operands[0], 1); } + /* If we can tell early on that the comparison is against a constant + that won't fit in the 5-bit signed immediate field of a cbcond, + use one of the other v9 conditional branch sequences. */ + if (TARGET_CBCOND + && GET_CODE (operands[1]) == REG + && (GET_MODE (operands[1]) == SImode + || (TARGET_ARCH64 && GET_MODE (operands[1]) == DImode)) + && (GET_CODE (operands[2]) != CONST_INT + || SPARC_SIMM5_P (INTVAL (operands[2])))) + { + emit_cbcond_insn (GET_CODE (operands[0]), operands[1], operands[2], operands[3]); + return; + } + if (TARGET_ARCH64 && operands[2] == const0_rtx && GET_CODE (operands[1]) == REG && GET_MODE (operands[1]) == DImode) @@ -3014,6 +3052,44 @@ empty_delay_slot (rtx insn) return 1; } +/* Return nonzero if we should emit a nop after a cbcond instruction. + The cbcond instruction does not have a delay slot, however there is + a severe performance penalty if a control transfer appears right + after a cbcond. Therefore we emit a nop when we detect this + situation. */ + +int +emit_cbcond_nop (rtx insn) +{ + rtx next = next_active_insn (insn); + + if (!next) + return 1; + + if (GET_CODE (next) == INSN + && GET_CODE (PATTERN (next)) == SEQUENCE) + next = XVECEXP (PATTERN (next), 0, 0); + else if (GET_CODE (next) == CALL_INSN + && GET_CODE (PATTERN (next)) == PARALLEL) + { + rtx delay = XVECEXP (PATTERN (next), 0, 1); + + if (GET_CODE (delay) == RETURN) + { + /* It's a sibling call. Do not emit the nop if we're going + to emit something other than the jump itself as the first + instruction of the sibcall sequence. */ + if (sparc_leaf_function_p || TARGET_FLAT) + return 0; + } + } + + if (NONJUMP_INSN_P (next)) + return 0; + + return 1; +} + /* Return nonzero if TRIAL can go into the call delay slot. */ int @@ -7102,19 +7178,49 @@ sparc_preferred_simd_mode (enum machine_mode mode) DEST is the destination insn (i.e. the label), INSN is the source. */ const char * -output_ubranch (rtx dest, int label, rtx insn) +output_ubranch (rtx dest, rtx insn) { static char string[64]; bool v9_form = false; + int delta; char *p; - if (TARGET_V9 && INSN_ADDRESSES_SET_P ()) + /* Even if we are trying to use cbcond for this, evaluate + whether we can use V9 branches as our backup plan. */ + + delta = 5000000; + if (INSN_ADDRESSES_SET_P ()) + delta = (INSN_ADDRESSES (INSN_UID (dest)) + - INSN_ADDRESSES (INSN_UID (insn))); + + /* Leave some instructions for "slop". */ + if (TARGET_V9 && delta >= -260000 && delta < 260000) + v9_form = true; + + if (TARGET_CBCOND) { - int delta = (INSN_ADDRESSES (INSN_UID (dest)) - - INSN_ADDRESSES (INSN_UID (insn))); - /* Leave some instructions for "slop". */ - if (delta >= -260000 && delta < 260000) - v9_form = true; + bool emit_nop = emit_cbcond_nop (insn); + bool far = false; + const char *rval; + + if (delta < -500 || delta > 500) + far = true; + + if (far) + { + if (v9_form) + rval = "ba,a,pt\t%%xcc, %l0"; + else + rval = "b,a\t%l0"; + } + else + { + if (emit_nop) + rval = "cwbe\t%%g0, %%g0, %l0\n\tnop"; + else + rval = "cwbe\t%%g0, %%g0, %l0"; + } + return rval; } if (v9_form) @@ -7125,7 +7231,7 @@ output_ubranch (rtx dest, int label, rtx insn) p = strchr (string, '\0'); *p++ = '%'; *p++ = 'l'; - *p++ = '0' + label; + *p++ = '0'; *p++ = '%'; *p++ = '('; *p = '\0'; @@ -7604,6 +7710,125 @@ sparc_emit_fixunsdi (rtx *operands, enum machine_mode mode) emit_label (donelab); } +/* Return the string to output a compare and branch instruction to DEST. + DEST is the destination insn (i.e. the label), INSN is the source, + and OP is the conditional expression. */ + +const char * +output_cbcond (rtx op, rtx dest, rtx insn) +{ + enum machine_mode mode = GET_MODE (XEXP (op, 0)); + enum rtx_code code = GET_CODE (op); + const char *cond_str, *tmpl; + int far, emit_nop, len; + static char string[64]; + char size_char; + + /* Compare and Branch is limited to +-2KB. If it is too far away, + change + + cxbne X, Y, .LC30 + + to + + cxbe X, Y, .+16 + nop + ba,pt xcc, .LC30 + nop */ + + len = get_attr_length (insn); + + far = len == 4; + emit_nop = len == 2; + + if (far) + code = reverse_condition (code); + + size_char = ((mode == SImode) ? 'w' : 'x'); + + switch (code) + { + case NE: + cond_str = "ne"; + break; + + case EQ: + cond_str = "e"; + break; + + case GE: + if (mode == CC_NOOVmode || mode == CCX_NOOVmode) + cond_str = "pos"; + else + cond_str = "ge"; + break; + + case GT: + cond_str = "g"; + break; + + case LE: + cond_str = "le"; + break; + + case LT: + if (mode == CC_NOOVmode || mode == CCX_NOOVmode) + cond_str = "neg"; + else + cond_str = "l"; + break; + + case GEU: + cond_str = "cc"; + break; + + case GTU: + cond_str = "gu"; + break; + + case LEU: + cond_str = "leu"; + break; + + case LTU: + cond_str = "cs"; + break; + + default: + gcc_unreachable (); + } + + 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; + } + + if (veryfar) + tmpl = "c%cb%s\t%%1, %%2, .+16\n\tnop\n\tb\t%%3\n\tnop"; + else + tmpl = "c%cb%s\t%%1, %%2, .+16\n\tnop\n\tba,pt\t%%%%xcc, %%3\n\tnop"; + } + else + { + if (emit_nop) + tmpl = "c%cb%s\t%%1, %%2, %%3\n\tnop"; + else + tmpl = "c%cb%s\t%%1, %%2, %%3"; + } + + snprintf (string, sizeof(string), tmpl, size_char, cond_str); + + return string; +} + /* Return the string to output a conditional branch to LABEL, testing register REG. LABEL is the operand number of the label; REG is the operand number of the reg. OP is the conditional expression. The mode diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h index 52e0828..57c5eac 100644 --- a/gcc/config/sparc/sparc.h +++ b/gcc/config/sparc/sparc.h @@ -195,7 +195,7 @@ extern enum cmodel sparc_cmodel; #endif #if TARGET_CPU_DEFAULT == TARGET_CPU_niagara4 #define CPP_CPU64_DEFAULT_SPEC "-D__sparc_v9__" -#define ASM_CPU64_DEFAULT_SPEC "-Av9" AS_NIAGARA3_FLAG +#define ASM_CPU64_DEFAULT_SPEC AS_NIAGARA4_FLAG #endif #else @@ -337,7 +337,7 @@ extern enum cmodel sparc_cmodel; %{mcpu=niagara:%{!mv8plus:-Av9b}} \ %{mcpu=niagara2:%{!mv8plus:-Av9b}} \ %{mcpu=niagara3:%{!mv8plus:-Av9" AS_NIAGARA3_FLAG "}} \ -%{mcpu=niagara4:%{!mv8plus:-Av9" AS_NIAGARA3_FLAG "}} \ +%{mcpu=niagara4:%{!mv8plus:" AS_NIAGARA4_FLAG "}} \ %{!mcpu*:%(asm_cpu_default)} \ " @@ -1006,7 +1006,8 @@ extern char leaf_reg_remap[]; /* Local macro to handle the two v9 classes of FP regs. */ #define FP_REG_CLASS_P(CLASS) ((CLASS) == FP_REGS || (CLASS) == EXTRA_FP_REGS) -/* Predicates for 10-bit, 11-bit and 13-bit signed constants. */ +/* Predicates for 5-bit, 10-bit, 11-bit and 13-bit signed constants. */ +#define SPARC_SIMM5_P(X) ((unsigned HOST_WIDE_INT) (X) + 0x10 < 0x20) #define SPARC_SIMM10_P(X) ((unsigned HOST_WIDE_INT) (X) + 0x200 < 0x400) #define SPARC_SIMM11_P(X) ((unsigned HOST_WIDE_INT) (X) + 0x400 < 0x800) #define SPARC_SIMM13_P(X) ((unsigned HOST_WIDE_INT) (X) + 0x1000 < 0x2000) @@ -1746,6 +1747,12 @@ extern int sparc_indent_opcode; #define AS_NIAGARA3_FLAG "b" #endif +#ifdef HAVE_AS_SPARC4 +#define AS_NIAGARA4_FLAG "-xarch=sparc4" +#else +#define AS_NIAGARA4_FLAG "-Av9" AS_NIAGARA3_FLAG +#endif + /* We use gcc _mcount for profiling. */ #define NO_PROFILE_COUNTERS 0 diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index f604f46..15ecdb4 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -257,6 +257,7 @@ "ialu,compare,shift, load,sload,store, uncond_branch,branch,call,sibcall,call_no_delay_slot,return, + cbcond,uncond_cbcond, imul,idiv, fpload,fpstore, fp,fpmove, @@ -275,6 +276,12 @@ (symbol_ref "(empty_delay_slot (insn) ? EMPTY_DELAY_SLOT_TRUE : EMPTY_DELAY_SLOT_FALSE)")) +;; True if we are making use of compare-and-branch instructions. +;; True if we should emit a nop after a cbcond instruction +(define_attr "emit_cbcond_nop" "false,true" + (symbol_ref "(emit_cbcond_nop (insn) + ? EMIT_CBCOND_NOP_TRUE : EMIT_CBCOND_NOP_FALSE)")) + (define_attr "branch_type" "none,icc,fcc,reg" (const_string "none")) @@ -377,6 +384,30 @@ (if_then_else (eq_attr "empty_delay_slot" "true") (const_int 4) (const_int 3)))) + (eq_attr "type" "cbcond") + (if_then_else (lt (pc) (match_dup 3)) + (if_then_else (lt (minus (match_dup 3) (pc)) (const_int 500)) + (if_then_else (eq_attr "emit_cbcond_nop" "true") + (const_int 2) + (const_int 1)) + (const_int 4)) + (if_then_else (lt (minus (pc) (match_dup 3)) (const_int 500)) + (if_then_else (eq_attr "emit_cbcond_nop" "true") + (const_int 2) + (const_int 1)) + (const_int 4))) + (eq_attr "type" "uncond_cbcond") + (if_then_else (lt (pc) (match_dup 0)) + (if_then_else (lt (minus (match_dup 0) (pc)) (const_int 500)) + (if_then_else (eq_attr "emit_cbcond_nop" "true") + (const_int 2) + (const_int 1)) + (const_int 1)) + (if_then_else (lt (minus (pc) (match_dup 0)) (const_int 500)) + (if_then_else (eq_attr "emit_cbcond_nop" "true") + (const_int 2) + (const_int 1)) + (const_int 1))) ] (const_int 1))) ;; FP precision. @@ -397,7 +428,7 @@ ? TLS_CALL_DELAY_TRUE : TLS_CALL_DELAY_FALSE)")) (define_attr "in_call_delay" "false,true" - (cond [(eq_attr "type" "uncond_branch,branch,call,sibcall,call_no_delay_slot,multi") + (cond [(eq_attr "type" "uncond_branch,branch,cbcond,uncond_cbcond,call,sibcall,call_no_delay_slot,multi") (const_string "false") (eq_attr "type" "load,fpload,store,fpstore") (if_then_else (eq_attr "length" "1") @@ -431,19 +462,19 @@ ;; because it prevents us from moving back the final store of inner loops. (define_attr "in_branch_delay" "false,true" - (if_then_else (and (eq_attr "type" "!uncond_branch,branch,call,sibcall,call_no_delay_slot,multi") + (if_then_else (and (eq_attr "type" "!uncond_branch,branch,cbcond,uncond_cbcond,call,sibcall,call_no_delay_slot,multi") (eq_attr "length" "1")) (const_string "true") (const_string "false"))) (define_attr "in_uncond_branch_delay" "false,true" - (if_then_else (and (eq_attr "type" "!uncond_branch,branch,call,sibcall,call_no_delay_slot,multi") + (if_then_else (and (eq_attr "type" "!uncond_branch,branch,cbcond,uncond_cbcond,call,sibcall,call_no_delay_slot,multi") (eq_attr "length" "1")) (const_string "true") (const_string "false"))) (define_attr "in_annul_branch_delay" "false,true" - (if_then_else (and (eq_attr "type" "!uncond_branch,branch,call,sibcall,call_no_delay_slot,multi") + (if_then_else (and (eq_attr "type" "!uncond_branch,branch,cbcond,uncond_cbcond,call,sibcall,call_no_delay_slot,multi") (eq_attr "length" "1")) (const_string "true") (const_string "false"))) @@ -1313,6 +1344,32 @@ ;; SPARC V9-specific jump insns. None of these are guaranteed to be ;; in the architecture. +(define_insn "*cbcond_sp32" + [(set (pc) + (if_then_else (match_operator 0 "noov_compare_operator" + [(match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith5_operand" "rA")]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "TARGET_CBCOND" +{ + return output_cbcond (operands[0], operands[3], insn); +} + [(set_attr "type" "cbcond")]) + +(define_insn "*cbcond_sp64" + [(set (pc) + (if_then_else (match_operator 0 "noov_compare_operator" + [(match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "arith5_operand" "rA")]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "TARGET_ARCH64 && TARGET_CBCOND" +{ + return output_cbcond (operands[0], operands[3], insn); +} + [(set_attr "type" "cbcond")]) + ;; There are no 32 bit brreg insns. ;; XXX @@ -6076,12 +6133,22 @@ ;; Unconditional and other jump instructions. -(define_insn "jump" +(define_expand "jump" [(set (pc) (label_ref (match_operand 0 "" "")))] - "" - "* return output_ubranch (operands[0], 0, insn);" + "") + +(define_insn "*jump_ubranch" + [(set (pc) (label_ref (match_operand 0 "" "")))] + "! TARGET_CBCOND" + "* return output_ubranch (operands[0], insn);" [(set_attr "type" "uncond_branch")]) +(define_insn "*jump_cbcond" + [(set (pc) (label_ref (match_operand 0 "" "")))] + "TARGET_CBCOND" + "* return output_ubranch (operands[0], insn);" + [(set_attr "type" "uncond_cbcond")]) + (define_expand "tablejump" [(parallel [(set (pc) (match_operand 0 "register_operand" "r")) (use (label_ref (match_operand 1 "" "")))])] diff --git a/gcc/config/sparc/sparc.opt b/gcc/config/sparc/sparc.opt index 58ba6b7..241cb07 100644 --- a/gcc/config/sparc/sparc.opt +++ b/gcc/config/sparc/sparc.opt @@ -73,6 +73,10 @@ mvis3 Target Report Mask(VIS3) Use UltraSPARC Visual Instruction Set version 3.0 extensions +mcbcond +Target Report Mask(CBCOND) +Use UltraSPARC Compare-and-Branch extensions + mfmaf Target Report Mask(FMAF) Use UltraSPARC Fused Multiply-Add extensions |