This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[SPARC] Work around data cache nullify issues on LEON3


This enhances -mfix-ut699 to work around the data cache nullify issues recently 
uncovered on the LEON3 processor, as documented in the relevant errata sheet.

Tested on SPARC/Solaris, applied on the mainline.


2013-07-22  Eric Botcazou  <ebotcazou@adacore.com>

	* config.gcc (sparc*-*-*): Accept leon3 processor.
	(sparc-leon*-*): Merge with sparc*-*-* and add leon3 support.
	* doc/invoke.texi (SPARC Options): Adjust -mfix-ut699 entry.
	* config/sparc/sparc-opts.h (enum processor_type): Add PROCESSOR_LEON3.
	* config/sparc/sparc.opt (enum processor_type): Add leon3.
	(mfix-ut699): Adjust comment.
	* config/sparc/sparc.h (TARGET_CPU_leon3): New define.
	(CPP_CPU32_DEFAULT_SPEC): Add leon3 support.
	(CPP_CPU_SPEC): Likewise.
	(ASM_CPU_SPEC): Likewise.
	* config/sparc/sparc.c (leon3_cost): New constant.
	(sparc_option_override): Add leon3 support.
	(mem_ref): New function.
	(sparc_gate_work_around_errata): Return true if -mfix-ut699 is enabled.
	(sparc_do_work_around_errata): Look into the instruction in the delay
	slot and adjust accordingly.  Add fix for the data cache nullify issues
	of the UT699.  Change insertion position for the NOP.
	* config/sparc/leon.md (leon_fpalu, leon_fpmds, write_buf): Delete.
	(leon3_load): New reservation.
	(leon_store): Bump latency to 2.
	(grfpu): New automaton.
	(grfpu_alu): New unit.
	(grfpu_ds): Likewise.
	(leon_fp_alu): Adjust.
	(leon_fp_mult): Delete.
	(leon_fp_div): Split into leon_fp_divs and leon_fp_divd.
	(leon_fp_sqrt): Split into leon_fp_sqrts and leon_fp_sqrtd.
	* config/sparc/sparc.md (cpu): Add leon3.
	* config/sparc/sync.md (atomic_exchangesi): Disable if -mfix-ut699.
	(swapsi): Likewise.
	(atomic_test_and_set): Likewise.
	(ldstub): Likewise.


-- 
Eric Botcazou
Index: config.gcc
===================================================================
--- config.gcc	(revision 201053)
+++ config.gcc	(working copy)
@@ -3642,7 +3642,7 @@ case "${target}" in
 			case ${val} in
 			"" | sparc | sparcv9 | sparc64 \
 			| v7 | cypress \
-			| v8 | supersparc | hypersparc | leon \
+			| v8 | supersparc | hypersparc | leon | leon3 \
 			| sparclite | f930 | f934 | sparclite86x \
 			| sparclet | tsc701 \
 			| v9 | ultrasparc | ultrasparc3 | niagara | niagara2 \
@@ -3799,15 +3799,6 @@ case ${target} in
 		cxx_target_objs="${cxx_target_objs} sh-c.o"
 		;;
 
-	sparc-leon*-*)
-		if test x$with_tune = x ; then
-		  with_tune=leon;
-		fi
-
-		# The SPARC port checks this value at compile-time.
-		target_cpu_default2="TARGET_CPU_$with_cpu"
-		;;
-
 	sparc*-*-*)
 		# Some standard aliases.
 		case x$with_cpu in
@@ -3819,6 +3810,17 @@ case ${target} in
 			;;
 		esac
 
+		if test x$with_tune = x ; then
+		      case ${target} in
+		      *-leon-*)
+			  with_tune=leon
+			  ;;
+		      *-leon[3-9]*)
+			  with_tune=leon3
+			  ;;
+		      esac
+		fi
+
 		# The SPARC port checks this value at compile-time.
 		target_cpu_default2="TARGET_CPU_$with_cpu"
 		;;
Index: doc/invoke.texi
===================================================================
--- doc/invoke.texi	(revision 201053)
+++ doc/invoke.texi	(working copy)
@@ -19491,8 +19491,8 @@ processor (which corresponds to erratum
 
 @item -mfix-ut699
 @opindex mfix-ut699
-Enable the documented workarounds for the floating-point errata of the UT699
-processor.
+Enable the documented workarounds for the floating-point errata and the data
+cache nullify errata of the UT699 processor.
 @end table
 
 These @samp{-m} options are supported in addition to the above
Index: config/sparc/sparc.md
===================================================================
--- config/sparc/sparc.md	(revision 201053)
+++ config/sparc/sparc.md	(working copy)
@@ -206,7 +206,7 @@ (define_mode_iterator F [SF DF TF])
 ;; 'f' for all DF/TFmode values, including those that are specific to the v8.
 
 ;; Attribute for cpu type.
-;; These must match the values for enum processor_type in sparc.h.
+;; These must match the values of the enum processor_type in sparc-opts.h.
 (define_attr "cpu"
   "v7,
    cypress,
@@ -214,6 +214,7 @@ (define_attr "cpu"
    supersparc,
    hypersparc,
    leon,
+   leon3,
    sparclite,
    f930,
    f934,
Index: config/sparc/sparc.opt
===================================================================
--- config/sparc/sparc.opt	(revision 201053)
+++ config/sparc/sparc.opt	(working copy)
@@ -146,6 +146,9 @@ EnumValue
 Enum(sparc_processor_type) String(leon) Value(PROCESSOR_LEON)
 
 EnumValue
+Enum(sparc_processor_type) String(leon3) Value(PROCESSOR_LEON3)
+
+EnumValue
 Enum(sparc_processor_type) String(sparclite) Value(PROCESSOR_SPARCLITE)
 
 EnumValue
@@ -203,7 +206,7 @@ Enable workaround for single erratum of
 
 mfix-ut699
 Target Report RejectNegative Var(sparc_fix_ut699)
-Enable workarounds for the FP errata of the UT699 processor
+Enable workarounds for the errata of the UT699 processor
 
 Mask(LONG_DOUBLE_128)
 ;; Use 128-bit long double
Index: config/sparc/sync.md
===================================================================
--- config/sparc/sync.md	(revision 201053)
+++ config/sparc/sync.md	(working copy)
@@ -220,7 +220,7 @@ (define_expand "atomic_exchangesi"
    (match_operand:SI 1 "memory_operand" "")
    (match_operand:SI 2 "register_operand" "")
    (match_operand:SI 3 "const_int_operand" "")]
-  "TARGET_V8 || TARGET_V9"
+  "(TARGET_V8 || TARGET_V9) && !sparc_fix_ut699"
 {
   enum memmodel model = (enum memmodel) INTVAL (operands[3]);
 
@@ -236,7 +236,7 @@ (define_insn "swapsi"
 			    UNSPECV_SWAP))
    (set (match_dup 1)
 	(match_operand:SI 2 "register_operand" "0"))]
-  "TARGET_V8 || TARGET_V9"
+  "(TARGET_V8 || TARGET_V9) && !sparc_fix_ut699"
   "swap\t%1, %0"
   [(set_attr "type" "multi")])
 
@@ -244,7 +244,7 @@ (define_expand "atomic_test_and_set"
   [(match_operand:QI 0 "register_operand" "")
    (match_operand:QI 1 "memory_operand" "")
    (match_operand:SI 2 "const_int_operand" "")]
-  ""
+  "!sparc_fix_ut699"
 {
   enum memmodel model = (enum memmodel) INTVAL (operands[2]);
   rtx ret;
@@ -268,6 +268,6 @@ (define_insn "ldstub"
 	(unspec_volatile:QI [(match_operand:QI 1 "memory_operand" "+m")]
 			    UNSPECV_LDSTUB))
    (set (match_dup 1) (const_int -1))]
-  ""
+  "!sparc_fix_ut699"
   "ldstub\t%1, %0"
   [(set_attr "type" "multi")])
Index: config/sparc/sparc-opts.h
===================================================================
--- config/sparc/sparc-opts.h	(revision 201053)
+++ config/sparc/sparc-opts.h	(working copy)
@@ -30,6 +30,7 @@ enum processor_type {
   PROCESSOR_SUPERSPARC,
   PROCESSOR_HYPERSPARC,
   PROCESSOR_LEON,
+  PROCESSOR_LEON3,
   PROCESSOR_SPARCLITE,
   PROCESSOR_F930,
   PROCESSOR_F934,
Index: config/sparc/sparc.c
===================================================================
--- config/sparc/sparc.c	(revision 201053)
+++ config/sparc/sparc.c	(working copy)
@@ -227,6 +227,30 @@ struct processor_costs leon_costs = {
 };
 
 static const
+struct processor_costs leon3_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 (14), /* fdivs */
+  COSTS_N_INSNS (15), /* fdivd */
+  COSTS_N_INSNS (22), /* fsqrts */
+  COSTS_N_INSNS (23), /* fsqrtd */
+  COSTS_N_INSNS (5), /* imul */
+  COSTS_N_INSNS (5), /* imulX */
+  0, /* imul bit factor */
+  COSTS_N_INSNS (35), /* idiv */
+  COSTS_N_INSNS (35), /* idivX */
+  COSTS_N_INSNS (1), /* movcc/movr */
+  0, /* shift penalty */
+};
+
+static const
 struct processor_costs sparclet_costs = {
   COSTS_N_INSNS (3), /* int load */
   COSTS_N_INSNS (3), /* int signed load */
@@ -805,17 +829,31 @@ char sparc_hard_reg_printed[8];
 
 struct gcc_target targetm = TARGET_INITIALIZER;
 
+/* Return the memory reference contained in X if any, zero otherwise.  */
+
+static rtx
+mem_ref (rtx x)
+{
+  if (GET_CODE (x) == SIGN_EXTEND || GET_CODE (x) == ZERO_EXTEND)
+    x = XEXP (x, 0);
+
+  if (MEM_P (x))
+    return x;
+
+  return NULL_RTX;
+}
+
 /* 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
    to properly detect the various hazards.  Therefore, this machine specific
    pass runs as late as possible.  The pass is inserted in the pass pipeline
-   at the end of sparc_options_override.  */
+   at the end of sparc_option_override.  */
 
 static bool
 sparc_gate_work_around_errata (void)
 {
-  /* The only erratum we handle for now is that of the AT697F processor.  */
-  return sparc_fix_at697f != 0;
+  /* The only errata we handle are those of the AT697F and UT699.  */
+  return sparc_fix_at697f != 0 || sparc_fix_ut699 != 0;
 }
 
 static unsigned int
@@ -823,14 +861,22 @@ sparc_do_work_around_errata (void)
 {
   rtx insn, next;
 
+  /* Force all instructions to be split into their final form.  */
+  split_all_insns_noflow ();
+
   /* Now look for specific patterns in the insn stream.  */
   for (insn = get_insns (); insn; insn = next)
     {
       bool insert_nop = false;
       rtx set;
 
+      /* Look into the instruction in a delay slot.  */
+      if (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE)
+	insn = XVECEXP (PATTERN (insn), 0, 1);
+
       /* Look for a single-word load into an odd-numbered FP register.  */
-      if (NONJUMP_INSN_P (insn)
+      if (sparc_fix_at697f
+	  && NONJUMP_INSN_P (insn)
 	  && (set = single_set (insn)) != NULL_RTX
 	  && GET_MODE_SIZE (GET_MODE (SET_SRC (set))) == 4
 	  && MEM_P (SET_SRC (set))
@@ -845,13 +891,13 @@ sparc_do_work_around_errata (void)
 
 	  /* If the insn has a delay slot, then it cannot be problematic.  */
 	  next = next_active_insn (insn);
+	  if (!next)
+	    break;
 	  if (NONJUMP_INSN_P (next) && GET_CODE (PATTERN (next)) == SEQUENCE)
-	    code = -1;
-	  else
-	    {
-	      extract_insn (next);
-	      code = INSN_CODE (next);
-	    }
+	    continue;
+
+	  extract_insn (next);
+	  code = INSN_CODE (next);
 
 	  switch (code)
 	    {
@@ -897,12 +943,60 @@ sparc_do_work_around_errata (void)
 	      break;
 	    }
 	}
+
+      /* Look for a single-word load into an integer register.  */
+      else if (sparc_fix_ut699
+	       && NONJUMP_INSN_P (insn)
+	       && (set = single_set (insn)) != NULL_RTX
+	       && GET_MODE_SIZE (GET_MODE (SET_SRC (set))) <= 4
+	       && mem_ref (SET_SRC (set)) != NULL_RTX
+	       && REG_P (SET_DEST (set))
+	       && REGNO (SET_DEST (set)) < 32)
+	{
+	  /* There is no problem if the second memory access has a data
+	     dependency on the first single-cycle load.  */
+	  rtx x = SET_DEST (set);
+
+	  /* If the insn has a delay slot, then it cannot be problematic.  */
+	  next = next_active_insn (insn);
+	  if (!next)
+	    break;
+	  if (NONJUMP_INSN_P (next) && GET_CODE (PATTERN (next)) == SEQUENCE)
+	    continue;
+
+	  /* Look for a second memory access to/from an integer register.  */
+	  if ((set = single_set (next)) != NULL_RTX)
+	    {
+	      rtx src = SET_SRC (set);
+	      rtx dest = SET_DEST (set);
+	      rtx mem;
+
+	      /* LDD is affected.  */
+	      if ((mem = mem_ref (src)) != NULL_RTX
+		  && REG_P (dest)
+		  && REGNO (dest) < 32
+		  && !reg_mentioned_p (x, XEXP (mem, 0)))
+		insert_nop = true;
+
+	      /* STD is *not* affected.  */
+	      else if ((mem = mem_ref (dest)) != NULL_RTX
+		       && GET_MODE_SIZE (GET_MODE (mem)) <= 4
+		       && (src == const0_rtx
+			   || (REG_P (src)
+			       && REGNO (src) < 32
+			       && REGNO (src) != REGNO (x)))
+		       && !reg_mentioned_p (x, XEXP (mem, 0)))
+		insert_nop = true;
+	    }
+	}
+
       else
 	next = NEXT_INSN (insn);
 
       if (insert_nop)
-	emit_insn_after (gen_nop (), insn);
+	emit_insn_before (gen_nop (), next);
     }
+
   return 0;
 }
 
@@ -1019,6 +1113,7 @@ sparc_option_override (void)
     { TARGET_CPU_supersparc, PROCESSOR_SUPERSPARC },
     { TARGET_CPU_hypersparc, PROCESSOR_HYPERSPARC },
     { TARGET_CPU_leon, PROCESSOR_LEON },
+    { TARGET_CPU_leon3, PROCESSOR_LEON3 },
     { TARGET_CPU_sparclite, PROCESSOR_F930 },
     { TARGET_CPU_sparclite86x, PROCESSOR_SPARCLITE86X },
     { TARGET_CPU_sparclet, PROCESSOR_TSC701 },
@@ -1033,7 +1128,7 @@ sparc_option_override (void)
   };
   const struct cpu_default *def;
   /* Table of values for -m{cpu,tune}=.  This must match the order of
-     the PROCESSOR_* enumeration.  */
+     the enum processor_type in sparc-opts.h.  */
   static struct cpu_table {
     const char *const name;
     const int disable;
@@ -1047,6 +1142,7 @@ sparc_option_override (void)
     { "hypersparc",	MASK_ISA, MASK_V8|MASK_FPU },
     /* LEON */
     { "leon",		MASK_ISA, MASK_V8|MASK_FPU },
+    { "leon3",		MASK_ISA, MASK_V8|MASK_FPU },
     { "sparclite",	MASK_ISA, MASK_SPARCLITE },
     /* The Fujitsu MB86930 is the original sparclite chip, with no FPU.  */
     { "f930",		MASK_ISA|MASK_FPU, MASK_SPARCLITE },
@@ -1295,6 +1391,9 @@ sparc_option_override (void)
     case PROCESSOR_LEON:
       sparc_costs = &leon_costs;
       break;
+    case PROCESSOR_LEON3:
+      sparc_costs = &leon3_costs;
+      break;
     case PROCESSOR_SPARCLET:
     case PROCESSOR_TSC701:
       sparc_costs = &sparclet_costs;
Index: config/sparc/leon.md
===================================================================
--- config/sparc/leon.md	(revision 201053)
+++ config/sparc/leon.md	(working copy)
@@ -17,40 +17,48 @@
 ;; along with GCC; see the file COPYING3.  If not see
 ;; <http://www.gnu.org/licenses/>.
 
+;; Leon is a single-issue processor.
 
 (define_automaton "leon")
 
-(define_cpu_unit "leon_memory, leon_fpalu" "leon")
-(define_cpu_unit "leon_fpmds" "leon")
-(define_cpu_unit "write_buf" "leon")
+(define_cpu_unit "leon_memory" "leon")
 
 (define_insn_reservation "leon_load" 1
-  (and (eq_attr "cpu" "leon")
-    (eq_attr "type" "load,sload,fpload"))
+  (and (eq_attr "cpu" "leon") (eq_attr "type" "load,sload"))
   "leon_memory")
 
-(define_insn_reservation "leon_store" 1
-  (and (eq_attr "cpu" "leon")
-    (eq_attr "type" "store,fpstore"))
-  "leon_memory+write_buf")
-  
-(define_insn_reservation "leon_fp_alu" 1
-  (and (eq_attr "cpu" "leon")
-    (eq_attr "type" "fp,fpmove"))
-  "leon_fpalu, nothing")
-
-(define_insn_reservation "leon_fp_mult" 1
-  (and (eq_attr "cpu" "leon")
-    (eq_attr "type" "fpmul"))
-  "leon_fpmds, nothing")
-
-(define_insn_reservation "leon_fp_div" 16
-  (and (eq_attr "cpu" "leon")
-    (eq_attr "type" "fpdivs,fpdivd"))
-  "leon_fpmds, nothing*15")
-
-(define_insn_reservation "leon_fp_sqrt" 23
-  (and (eq_attr "cpu" "leon")
-    (eq_attr "type" "fpsqrts,fpsqrtd"))
-  "leon_fpmds, nothing*21")
+;; Use a double reservation to work around the load pipeline hazard on UT699.
+(define_insn_reservation "leon3_load" 1
+  (and (eq_attr "cpu" "leon3") (eq_attr "type" "load,sload"))
+  "leon_memory*2")
 
+(define_insn_reservation "leon_store" 2
+  (and (eq_attr "cpu" "leon,leon3") (eq_attr "type" "store"))
+  "leon_memory*2")
+
+;; This describes Gaisler Research's FPU
+
+(define_automaton "grfpu")
+
+(define_cpu_unit "grfpu_alu" "grfpu")
+(define_cpu_unit "grfpu_ds" "grfpu")
+
+(define_insn_reservation "leon_fp_alu" 4
+  (and (eq_attr "cpu" "leon,leon3") (eq_attr "type" "fp,fpcmp,fpmul"))
+  "grfpu_alu, nothing*3")
+
+(define_insn_reservation "leon_fp_divs" 16
+  (and (eq_attr "cpu" "leon,leon3") (eq_attr "type" "fpdivs"))
+  "grfpu_ds*14, nothing*2")
+
+(define_insn_reservation "leon_fp_divd" 17
+  (and (eq_attr "cpu" "leon,leon3") (eq_attr "type" "fpdivd"))
+  "grfpu_ds*15, nothing*2")
+
+(define_insn_reservation "leon_fp_sqrts" 24
+  (and (eq_attr "cpu" "leon,leon3") (eq_attr "type" "fpsqrts"))
+  "grfpu_ds*22, nothing*2")
+
+(define_insn_reservation "leon_fp_sqrtd" 25
+  (and (eq_attr "cpu" "leon,leon3") (eq_attr "type" "fpsqrtd"))
+  "grfpu_ds*23, nothing*2")
Index: config/sparc/sparc.h
===================================================================
--- config/sparc/sparc.h	(revision 201053)
+++ config/sparc/sparc.h	(working copy)
@@ -136,21 +136,22 @@ extern enum cmodel sparc_cmodel;
 #define TARGET_CPU_supersparc	2
 #define TARGET_CPU_hypersparc	3
 #define TARGET_CPU_leon		4
-#define TARGET_CPU_sparclite	5
-#define TARGET_CPU_f930		5       /* alias */
-#define TARGET_CPU_f934		5       /* alias */
-#define TARGET_CPU_sparclite86x	6
-#define TARGET_CPU_sparclet	7
-#define TARGET_CPU_tsc701	7       /* alias */
-#define TARGET_CPU_v9		8	/* generic v9 implementation */
-#define TARGET_CPU_sparcv9	8	/* alias */
-#define TARGET_CPU_sparc64	8	/* alias */
-#define TARGET_CPU_ultrasparc	9
-#define TARGET_CPU_ultrasparc3	10
-#define TARGET_CPU_niagara	11
-#define TARGET_CPU_niagara2	12
-#define TARGET_CPU_niagara3	13
-#define TARGET_CPU_niagara4	14
+#define TARGET_CPU_leon3	5
+#define TARGET_CPU_sparclite	6
+#define TARGET_CPU_f930		6       /* alias */
+#define TARGET_CPU_f934		6       /* alias */
+#define TARGET_CPU_sparclite86x	7
+#define TARGET_CPU_sparclet	8
+#define TARGET_CPU_tsc701	8       /* alias */
+#define TARGET_CPU_v9		9	/* generic v9 implementation */
+#define TARGET_CPU_sparcv9	9	/* alias */
+#define TARGET_CPU_sparc64	9	/* alias */
+#define TARGET_CPU_ultrasparc	10
+#define TARGET_CPU_ultrasparc3	11
+#define TARGET_CPU_niagara	12
+#define TARGET_CPU_niagara2	13
+#define TARGET_CPU_niagara3	14
+#define TARGET_CPU_niagara4	15
 
 #if TARGET_CPU_DEFAULT == TARGET_CPU_v9 \
  || TARGET_CPU_DEFAULT == TARGET_CPU_ultrasparc \
@@ -232,7 +233,8 @@ extern enum cmodel sparc_cmodel;
 #define ASM_CPU32_DEFAULT_SPEC ""
 #endif
 
-#if TARGET_CPU_DEFAULT == TARGET_CPU_leon
+#if TARGET_CPU_DEFAULT == TARGET_CPU_leon \
+ || TARGET_CPU_DEFAULT == TARGET_CPU_leon3
 #define CPP_CPU32_DEFAULT_SPEC "-D__leon__ -D__sparc_v8__"
 #define ASM_CPU32_DEFAULT_SPEC ""
 #endif
@@ -282,6 +284,7 @@ extern enum cmodel sparc_cmodel;
 %{mcpu=supersparc:-D__supersparc__ -D__sparc_v8__} \
 %{mcpu=hypersparc:-D__hypersparc__ -D__sparc_v8__} \
 %{mcpu=leon:-D__leon__ -D__sparc_v8__} \
+%{mcpu=leon3:-D__leon__ -D__sparc_v8__} \
 %{mcpu=v9:-D__sparc_v9__} \
 %{mcpu=ultrasparc:-D__sparc_v9__} \
 %{mcpu=ultrasparc3:-D__sparc_v9__} \
@@ -330,6 +333,7 @@ extern enum cmodel sparc_cmodel;
 %{mcpu=supersparc:-Av8} \
 %{mcpu=hypersparc:-Av8} \
 %{mcpu=leon:-Av8} \
+%{mcpu=leon3:-Av8} \
 %{mv8plus:-Av8plus} \
 %{mcpu=v9:-Av9} \
 %{mcpu=ultrasparc:%{!mv8plus:-Av9a}} \

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]