aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/sparc
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2021-09-17 08:46:39 -0700
committerIan Lance Taylor <iant@golang.org>2021-09-17 08:46:39 -0700
commita0791d0ed4f147ef347e83f4aedc7ad03f1a2008 (patch)
tree7b3526910798e4cff7a7200d684383046bac6225 /gcc/config/sparc
parente252b51ccde010cbd2a146485d8045103cd99533 (diff)
parent89be17a1b231ade643f28fbe616d53377e069da8 (diff)
downloadgcc-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.md103
-rw-r--r--gcc/config/sparc/sparc-opts.h1
-rw-r--r--gcc/config/sparc/sparc.c183
-rw-r--r--gcc/config/sparc/sparc.h36
-rw-r--r--gcc/config/sparc/sparc.md12
-rw-r--r--gcc/config/sparc/sparc.opt3
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