diff options
author | Ian Lance Taylor <iant@golang.org> | 2021-09-17 08:46:39 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2021-09-17 08:46:39 -0700 |
commit | a0791d0ed4f147ef347e83f4aedc7ad03f1a2008 (patch) | |
tree | 7b3526910798e4cff7a7200d684383046bac6225 /gcc/config/sparc | |
parent | e252b51ccde010cbd2a146485d8045103cd99533 (diff) | |
parent | 89be17a1b231ade643f28fbe616d53377e069da8 (diff) | |
download | gcc-a0791d0ed4f147ef347e83f4aedc7ad03f1a2008.zip gcc-a0791d0ed4f147ef347e83f4aedc7ad03f1a2008.tar.gz gcc-a0791d0ed4f147ef347e83f4aedc7ad03f1a2008.tar.bz2 |
Merge from trunk revision 89be17a1b231ade643f28fbe616d53377e069da8.
Diffstat (limited to 'gcc/config/sparc')
-rw-r--r-- | gcc/config/sparc/leon5.md | 103 | ||||
-rw-r--r-- | gcc/config/sparc/sparc-opts.h | 1 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.c | 183 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.h | 36 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.md | 12 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.opt | 3 |
6 files changed, 298 insertions, 40 deletions
diff --git a/gcc/config/sparc/leon5.md b/gcc/config/sparc/leon5.md new file mode 100644 index 0000000..6a065b1 --- /dev/null +++ b/gcc/config/sparc/leon5.md @@ -0,0 +1,103 @@ +;; Scheduling description for LEON5. +;; Copyright (C) 2021 Free Software Foundation, Inc. +;; +;; This file is part of GCC. +;; +;; GCC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. +;; +;; GCC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; <http://www.gnu.org/licenses/>. + + +;; The LEON5 can often dual issue instructions from the same 64-bit aligned +;; double word if there are no data dependencies. +;; +;; Avoid scheduling load/store, FPU, and multiply instructions back to +;; back, regardless of data dependencies. +;; +;; Push comparisons away from the associated branch instruction. +;; +;; Avoid scheduling ALU instructions with data dependencies back to back. +;; +;; Schedule three instructions between load and dependent instruction. + +(define_automaton "leon5") + +(define_cpu_unit "leon5_memory" "leon5") +(define_cpu_unit "leon5_mul" "leon5") +(define_cpu_unit "grfpu_d" "grfpu") +(define_cpu_unit "grfpu_s" "grfpu") + +(define_insn_reservation "leon5_load" 4 + (and (eq_attr "cpu" "leon5") + (eq_attr "type" "load,sload")) + "leon5_memory * 2, nothing * 2") + +(define_insn_reservation "leon5_fpload" 2 + (and (eq_attr "cpu" "leon5") + (eq_attr "type" "fpload")) + "leon5_memory * 2 + grfpu_alu * 2") + +(define_insn_reservation "leon5_store" 2 + (and (eq_attr "cpu" "leon5") + (eq_attr "type" "store")) + "leon5_memory * 2") + +(define_insn_reservation "leon5_fpstore" 2 + (and (eq_attr "cpu" "leon5") + (eq_attr "type" "fpstore")) + "leon5_memory * 2 + grfpu_alu * 2") + +(define_insn_reservation "leon5_ialu" 2 + (and (eq_attr "cpu" "leon5") + (eq_attr "type" "ialu, shift, ialuX")) + "nothing * 2") + +(define_insn_reservation "leon5_compare" 5 + (and (eq_attr "cpu" "leon5") + (eq_attr "type" "compare")) + "nothing * 5") + +(define_insn_reservation "leon5_imul" 4 + (and (eq_attr "cpu" "leon5") + (eq_attr "type" "imul")) + "leon5_mul * 2, nothing * 2") + +(define_insn_reservation "leon5_idiv" 35 + (and (eq_attr "cpu" "leon5") + (eq_attr "type" "imul")) + "nothing * 35") + +(define_insn_reservation "leon5_fp_alu" 5 + (and (eq_attr "cpu" "leon5") + (eq_attr "type" "fp,fpcmp,fpmul,fpmove")) + "grfpu_alu * 2, nothing*3") + +(define_insn_reservation "leon5_fp_divs" 17 + (and (eq_attr "cpu" "leon5") + (eq_attr "type" "fpdivs")) + "grfpu_alu * 2 + grfpu_d*16, nothing") + +(define_insn_reservation "leon5_fp_divd" 18 + (and (eq_attr "cpu" "leon5") + (eq_attr "type" "fpdivd")) + "grfpu_alu * 2 + grfpu_d*17, nothing") + +(define_insn_reservation "leon5_fp_sqrts" 25 + (and (eq_attr "cpu" "leon5") + (eq_attr "type" "fpsqrts")) + "grfpu_alu * 2 + grfpu_s*24, nothing") + +(define_insn_reservation "leon5_fp_sqrtd" 26 + (and (eq_attr "cpu" "leon5") + (eq_attr "type" "fpsqrtd")) + "grfpu_alu * 2 + grfpu_s*25, nothing") diff --git a/gcc/config/sparc/sparc-opts.h b/gcc/config/sparc/sparc-opts.h index 1af556e..9299cf6 100644 --- a/gcc/config/sparc/sparc-opts.h +++ b/gcc/config/sparc/sparc-opts.h @@ -31,6 +31,7 @@ enum sparc_processor_type { PROCESSOR_HYPERSPARC, PROCESSOR_LEON, PROCESSOR_LEON3, + PROCESSOR_LEON5, PROCESSOR_LEON3V7, PROCESSOR_SPARCLITE, PROCESSOR_F930, diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 06f41d7..6bc6f0a 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -270,6 +270,31 @@ struct processor_costs leon3_costs = { }; static const +struct processor_costs leon5_costs = { + COSTS_N_INSNS (1), /* int load */ + COSTS_N_INSNS (1), /* int signed load */ + COSTS_N_INSNS (1), /* int zeroed load */ + COSTS_N_INSNS (1), /* float load */ + COSTS_N_INSNS (1), /* fmov, fneg, fabs */ + COSTS_N_INSNS (1), /* fadd, fsub */ + COSTS_N_INSNS (1), /* fcmp */ + COSTS_N_INSNS (1), /* fmov, fmovr */ + COSTS_N_INSNS (1), /* fmul */ + COSTS_N_INSNS (17), /* fdivs */ + COSTS_N_INSNS (18), /* fdivd */ + COSTS_N_INSNS (25), /* fsqrts */ + COSTS_N_INSNS (26), /* fsqrtd */ + COSTS_N_INSNS (4), /* imul */ + COSTS_N_INSNS (4), /* imulX */ + 0, /* imul bit factor */ + COSTS_N_INSNS (35), /* idiv */ + COSTS_N_INSNS (35), /* idivX */ + COSTS_N_INSNS (1), /* movcc/movr */ + 0, /* shift penalty */ + 3 /* branch cost */ +}; + +static const struct processor_costs sparclet_costs = { COSTS_N_INSNS (3), /* int load */ COSTS_N_INSNS (3), /* int signed load */ @@ -575,6 +600,7 @@ static int function_arg_slotno (const CUMULATIVE_ARGS *, machine_mode, static int supersparc_adjust_cost (rtx_insn *, int, rtx_insn *, int); static int hypersparc_adjust_cost (rtx_insn *, int, rtx_insn *, int); +static int leon5_adjust_cost (rtx_insn *, int, rtx_insn *, int); static void sparc_emit_set_const32 (rtx, rtx); static void sparc_emit_set_const64 (rtx, rtx); @@ -1045,6 +1071,43 @@ atomic_insn_for_leon3_p (rtx_insn *insn) } } +/* True if INSN is a store instruction. */ + +static bool +store_insn_p (rtx_insn *insn) +{ + if (GET_CODE (PATTERN (insn)) != SET) + return false; + + switch (get_attr_type (insn)) + { + case TYPE_STORE: + case TYPE_FPSTORE: + return true; + default: + return false; + } +} + +/* True if INSN is a load instruction. */ + +static bool +load_insn_p (rtx_insn *insn) +{ + if (GET_CODE (PATTERN (insn)) != SET) + return false; + + switch (get_attr_type (insn)) + { + case TYPE_LOAD: + case TYPE_SLOAD: + case TYPE_FPLOAD: + return true; + default: + return false; + } +} + /* We use a machine specific pass to enable workarounds for errata. We need to have the (essentially) final form of the insn stream in order @@ -1057,10 +1120,29 @@ atomic_insn_for_leon3_p (rtx_insn *insn) && GET_CODE (PATTERN (INSN)) != USE \ && GET_CODE (PATTERN (INSN)) != CLOBBER) +rtx_insn * +next_active_non_empty_insn (rtx_insn *insn) +{ + insn = next_active_insn (insn); + + while (insn + && (GET_CODE (PATTERN (insn)) == UNSPEC_VOLATILE + || GET_CODE (PATTERN (insn)) == ASM_INPUT + || (USEFUL_INSN_P (insn) + && (asm_noperands (PATTERN (insn)) >= 0) + && !strcmp (decode_asm_operands (PATTERN (insn), + NULL, NULL, NULL, + NULL, NULL), "")))) + insn = next_active_insn (insn); + + return insn; +} + static unsigned int sparc_do_work_around_errata (void) { rtx_insn *insn, *next; + bool find_first_useful = true; /* Force all instructions to be split into their final form. */ split_all_insns_noflow (); @@ -1085,6 +1167,16 @@ sparc_do_work_around_errata (void) else jump = NULL; + /* Do not begin function with atomic instruction. */ + if (sparc_fix_ut700 + && find_first_useful + && USEFUL_INSN_P (insn)) + { + find_first_useful = false; + if (atomic_insn_for_leon3_p (insn)) + emit_insn_before (gen_nop (), insn); + } + /* Place a NOP at the branch target of an integer branch if it is a floating-point operation or a floating-point branch. */ if (sparc_fix_gr712rc @@ -1105,9 +1197,7 @@ sparc_do_work_around_errata (void) instruction at branch target. */ if (sparc_fix_ut700 && NONJUMP_INSN_P (insn) - && (set = single_set (insn)) != NULL_RTX - && mem_ref (SET_SRC (set)) - && REG_P (SET_DEST (set))) + && load_insn_p (insn)) { if (jump && jump_to_label_p (jump)) { @@ -1116,7 +1206,7 @@ sparc_do_work_around_errata (void) emit_insn_before (gen_nop (), target); } - next = next_active_insn (insn); + next = next_active_non_empty_insn (insn); if (!next) break; @@ -1212,30 +1302,19 @@ sparc_do_work_around_errata (void) if (sparc_fix_b2bst && NONJUMP_INSN_P (insn) && (set = single_set (insn)) != NULL_RTX - && MEM_P (SET_DEST (set))) + && store_insn_p (insn)) { /* Sequence B begins with a double-word store. */ bool seq_b = GET_MODE_SIZE (GET_MODE (SET_DEST (set))) == 8; rtx_insn *after; int i; - next = next_active_insn (insn); + next = next_active_non_empty_insn (insn); if (!next) break; for (after = next, i = 0; i < 2; i++) { - /* Skip empty assembly statements. */ - if ((GET_CODE (PATTERN (after)) == UNSPEC_VOLATILE) - || (USEFUL_INSN_P (after) - && (asm_noperands (PATTERN (after))>=0) - && !strcmp (decode_asm_operands (PATTERN (after), - NULL, NULL, NULL, - NULL, NULL), ""))) - after = next_active_insn (after); - if (!after) - break; - /* If the insn is a branch, then it cannot be problematic. */ if (!NONJUMP_INSN_P (after) || GET_CODE (PATTERN (after)) == SEQUENCE) @@ -1245,8 +1324,7 @@ sparc_do_work_around_errata (void) if (seq_b) { /* Add NOP if followed by a store. */ - if ((set = single_set (after)) != NULL_RTX - && MEM_P (SET_DEST (set))) + if (store_insn_p (after)) insert_nop = true; /* Otherwise it is ok. */ @@ -1261,15 +1339,14 @@ sparc_do_work_around_errata (void) && (MEM_P (SET_DEST (set)) || mem_ref (SET_SRC (set)))) break; - after = next_active_insn (after); + after = next_active_non_empty_insn (after); if (!after) break; } /* Add NOP if third instruction is a store. */ if (i == 1 - && (set = single_set (after)) != NULL_RTX - && MEM_P (SET_DEST (set))) + && store_insn_p (after)) insert_nop = true; } } @@ -1596,6 +1673,10 @@ dump_target_flag_bits (const int flags) fprintf (stderr, "CBCOND "); if (flags & MASK_DEPRECATED_V8_INSNS) fprintf (stderr, "DEPRECATED_V8_INSNS "); + if (flags & MASK_LEON) + fprintf (stderr, "LEON "); + if (flags & MASK_LEON3) + fprintf (stderr, "LEON3 "); if (flags & MASK_SPARCLET) fprintf (stderr, "SPARCLET "); if (flags & MASK_SPARCLITE) @@ -1632,6 +1713,7 @@ sparc_option_override (void) { TARGET_CPU_hypersparc, PROCESSOR_HYPERSPARC }, { TARGET_CPU_leon, PROCESSOR_LEON }, { TARGET_CPU_leon3, PROCESSOR_LEON3 }, + { TARGET_CPU_leon5, PROCESSOR_LEON5 }, { TARGET_CPU_leon3v7, PROCESSOR_LEON3V7 }, { TARGET_CPU_sparclite, PROCESSOR_F930 }, { TARGET_CPU_sparclite86x, PROCESSOR_SPARCLITE86X }, @@ -1663,6 +1745,7 @@ sparc_option_override (void) { "hypersparc", MASK_ISA, MASK_V8 }, { "leon", MASK_ISA|MASK_FSMULD, MASK_V8|MASK_LEON }, { "leon3", MASK_ISA, MASK_V8|MASK_LEON3 }, + { "leon5", MASK_ISA, MASK_V8|MASK_LEON3 }, { "leon3v7", MASK_ISA, MASK_LEON3 }, { "sparclite", MASK_ISA, MASK_SPARCLITE }, /* The Fujitsu MB86930 is the original sparclite chip, with no FPU. */ @@ -1973,6 +2056,9 @@ sparc_option_override (void) case PROCESSOR_LEON3V7: sparc_costs = &leon3_costs; break; + case PROCESSOR_LEON5: + sparc_costs = &leon5_costs; + break; case PROCESSOR_SPARCLET: case PROCESSOR_TSC701: sparc_costs = &sparclet_costs; @@ -10120,11 +10206,64 @@ hypersparc_adjust_cost (rtx_insn *insn, int dtype, rtx_insn *dep_insn, } static int +leon5_adjust_cost (rtx_insn *insn, int dtype, rtx_insn *dep_insn, + int cost) +{ + enum attr_type insn_type, dep_type; + rtx pat = PATTERN (insn); + rtx dep_pat = PATTERN (dep_insn); + + if (recog_memoized (insn) < 0 || recog_memoized (dep_insn) < 0) + return cost; + + insn_type = get_attr_type (insn); + dep_type = get_attr_type (dep_insn); + + switch (dtype) + { + case REG_DEP_TRUE: + /* Data dependency; DEP_INSN writes a register that INSN reads some + cycles later. */ + + switch (insn_type) + { + case TYPE_STORE: + /* Try to schedule three instructions between the store and + the ALU instruction that generated the data. */ + if (dep_type == TYPE_IALU || dep_type == TYPE_SHIFT) + { + if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET) + break; + + if (rtx_equal_p (SET_DEST (dep_pat), SET_SRC (pat))) + return 4; + } + break; + default: + break; + } + break; + case REG_DEP_ANTI: + /* Penalize anti-dependencies for FPU instructions. */ + if (fpop_insn_p (insn) || insn_type == TYPE_FPLOAD) + return 4; + break; + default: + break; + } + + return cost; +} + +static int sparc_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep, int cost, unsigned int) { switch (sparc_cpu) { + case PROCESSOR_LEON5: + cost = leon5_adjust_cost (insn, dep_type, dep, cost); + break; case PROCESSOR_SUPERSPARC: cost = supersparc_adjust_cost (insn, dep_type, dep, cost); break; diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h index 4da5a06..edafa99 100644 --- a/gcc/config/sparc/sparc.h +++ b/gcc/config/sparc/sparc.h @@ -120,21 +120,22 @@ along with GCC; see the file COPYING3. If not see #define TARGET_CPU_leon 4 #define TARGET_CPU_leon3 5 #define TARGET_CPU_leon3v7 6 -#define TARGET_CPU_sparclite 7 -#define TARGET_CPU_f930 7 /* alias */ -#define TARGET_CPU_f934 7 /* alias */ -#define TARGET_CPU_sparclite86x 8 -#define TARGET_CPU_sparclet 9 -#define TARGET_CPU_tsc701 9 /* alias */ -#define TARGET_CPU_v9 10 /* generic v9 implementation */ -#define TARGET_CPU_sparcv9 10 /* alias */ -#define TARGET_CPU_sparc64 10 /* alias */ -#define TARGET_CPU_ultrasparc 11 -#define TARGET_CPU_ultrasparc3 12 -#define TARGET_CPU_niagara 13 -#define TARGET_CPU_niagara2 14 -#define TARGET_CPU_niagara3 15 -#define TARGET_CPU_niagara4 16 +#define TARGET_CPU_leon5 7 +#define TARGET_CPU_sparclite 8 +#define TARGET_CPU_f930 8 /* alias */ +#define TARGET_CPU_f934 8 /* alias */ +#define TARGET_CPU_sparclite86x 9 +#define TARGET_CPU_sparclet 10 +#define TARGET_CPU_tsc701 10 /* alias */ +#define TARGET_CPU_v9 11 /* generic v9 implementation */ +#define TARGET_CPU_sparcv9 11 /* alias */ +#define TARGET_CPU_sparc64 11 /* alias */ +#define TARGET_CPU_ultrasparc 12 +#define TARGET_CPU_ultrasparc3 13 +#define TARGET_CPU_niagara 14 +#define TARGET_CPU_niagara2 15 +#define TARGET_CPU_niagara3 16 +#define TARGET_CPU_niagara4 17 #define TARGET_CPU_niagara7 19 #define TARGET_CPU_m8 20 @@ -229,7 +230,8 @@ along with GCC; see the file COPYING3. If not see #endif #if TARGET_CPU_DEFAULT == TARGET_CPU_leon \ - || TARGET_CPU_DEFAULT == TARGET_CPU_leon3 + || TARGET_CPU_DEFAULT == TARGET_CPU_leon3 \ + || TARGET_CPU_DEFAULT == TARGET_CPU_leon5 #define CPP_CPU32_DEFAULT_SPEC "-D__leon__ -D__sparc_v8__" #define ASM_CPU32_DEFAULT_SPEC AS_LEON_FLAG #endif @@ -285,6 +287,7 @@ along with GCC; see the file COPYING3. If not see %{mcpu=hypersparc:-D__hypersparc__ -D__sparc_v8__} \ %{mcpu=leon:-D__leon__ -D__sparc_v8__} \ %{mcpu=leon3:-D__leon__ -D__sparc_v8__} \ +%{mcpu=leon5:-D__leon__ -D__sparc_v8__} \ %{mcpu=leon3v7:-D__leon__} \ %{mcpu=v9:-D__sparc_v9__} \ %{mcpu=ultrasparc:-D__sparc_v9__} \ @@ -337,6 +340,7 @@ along with GCC; see the file COPYING3. If not see %{mcpu=hypersparc:-Av8} \ %{mcpu=leon:" AS_LEON_FLAG "} \ %{mcpu=leon3:" AS_LEON_FLAG "} \ +%{mcpu=leon5:" AS_LEON_FLAG "} \ %{mcpu=leon3v7:" AS_LEONV7_FLAG "} \ %{mv8plus:-Av8plus} \ %{mcpu=v9:-Av9} \ diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index 24b76e0..294c918 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -233,6 +233,7 @@ hypersparc, leon, leon3, + leon5, leon3v7, sparclite, f930, @@ -638,6 +639,7 @@ (include "supersparc.md") (include "hypersparc.md") (include "leon.md") +(include "leon5.md") (include "sparclet.md") (include "ultra1_2.md") (include "ultra3.md") @@ -8353,9 +8355,15 @@ visl") (unspec:SI [(match_operand:SI 1 "memory_operand" "m")] UNSPEC_SP_SET)) (set (match_scratch:SI 2 "=&r") (const_int 0))] "TARGET_ARCH32" - "ld\t%1, %2\;st\t%2, %0\;mov\t0, %2" +{ + if (sparc_fix_b2bst) + return "ld\t%1, %2\;st\t%2, %0\;mov\t0, %2\;nop"; + else + return "ld\t%1, %2\;st\t%2, %0\;mov\t0, %2"; +} [(set_attr "type" "multi") - (set_attr "length" "3")]) + (set (attr "length") (if_then_else (eq_attr "fix_b2bst" "true") + (const_int 4) (const_int 3)))]) (define_insn "stack_protect_set64" [(set (match_operand:DI 0 "memory_operand" "=m") diff --git a/gcc/config/sparc/sparc.opt b/gcc/config/sparc/sparc.opt index fb79267..658a187 100644 --- a/gcc/config/sparc/sparc.opt +++ b/gcc/config/sparc/sparc.opt @@ -176,6 +176,9 @@ EnumValue Enum(sparc_processor) String(leon3v7) Value(PROCESSOR_LEON3V7) EnumValue +Enum(sparc_processor) String(leon5) Value(PROCESSOR_LEON5) + +EnumValue Enum(sparc_processor) String(sparclite) Value(PROCESSOR_SPARCLITE) EnumValue |