diff mbox series

[v2,MIPS] GCC: Fix Loongson3 LLSC Errata

Message ID 20181214144657.3683-1-syq@debian.org
State New
Headers show
Series [v2,MIPS] GCC: Fix Loongson3 LLSC Errata | expand

Commit Message

YunQiang Su Dec. 14, 2018, 2:46 p.m. UTC
From: Paul Hua <paul.hua.gm@gmail.com>

In some older Loongson3 processors there is a LL/SC errata that can
cause the CPU to deadlock occasionally.  The details are very
complicated. We find a way to work around this errata by
 a) adding a sync before ll/lld instruction,
 b) adding a sync before branch target that between ll and sc.
The assembler do the jobs 'a', gcc do the jobs 'b'.

This patch add an option '-mfix-loongson3-llsc' option, and it will also
call 'as' with the same option. So if 'as' doesn't support this option,
an error will happen.

The macro '__mips_fix_loongson3_llsc' is predefined, when this option is
enabled, as some program, like linux kernel will need to aware this
option is used.

This patch also add a configure options
--with-mips-fix-loongson3-llsc=[yes|no] to enable fix-loongson3-llsc
by config.

v1 -> v2:
  * Predefine __mips_fix_loongson3_llsc.
  * Add to ASM_SPECS.

gcc/
        * config.gcc (supported_defaults): Add fix-loongson3-llsc
        (with_fix_loongson3_llsc): Add validation.
        (all_defaults): Add fix-loongson3-llsc.
        * config/mips/mips.c (mips_process_sync_loop): Add sync before
        branch target that between ll and sc.
        * config/mips/mips.h
        (OPTION_DEFAULT_SPECS): Add a default for fix-loongson3-llsc.
        (ASM_SPECS): Add a default for fix-loongson3-llsc.
        (TARGET_CPU_CPP_BUILTINS): Predefine __mips_fix_loongson3_llsc.
        gcc/config/mips/mips.opt: New option.
        * doc/install.texi (--with-fix-loongson3-llsc):Document the new
        option.
        * doc/invoke.texi (-mfix-loongson3-llsc):Document the new option.

gcc/testsuite/
        * gcc.target/mips/fix-loongson3-llsc.c: New test.
        * gcc.target/mips/mips.exp (option): Add fix-loongson3-llsc.
---
 gcc/config.gcc                                | 19 +++++++++++++++++--
 gcc/config/mips/mips.c                        | 13 +++++++++++--
 gcc/config/mips/mips.h                        |  7 ++++++-
 gcc/config/mips/mips.opt                      |  4 ++++
 .../gcc.target/mips/fix-loongson3-llsc.c      | 10 ++++++++++
 gcc/testsuite/gcc.target/mips/mips.exp        |  1 +
 6 files changed, 49 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/mips/fix-loongson3-llsc.c
diff mbox series

Patch

diff --git a/gcc/config.gcc b/gcc/config.gcc
index 3122a0ce2..72b94b1be 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -4265,7 +4265,7 @@  case "${target}" in
 		;;
 
 	mips*-*-*)
-		supported_defaults="abi arch arch_32 arch_64 float fpu nan fp_32 odd_spreg_32 tune tune_32 tune_64 divide llsc mips-plt synci lxc1-sxc1 madd4"
+		supported_defaults="abi arch arch_32 arch_64 float fpu nan fp_32 odd_spreg_32 tune tune_32 tune_64 divide llsc mips-plt synci lxc1-sxc1 madd4 fix-loongson3-llsc"
 
 		case ${with_float} in
 		"" | soft | hard)
@@ -4418,6 +4418,21 @@  case "${target}" in
 			exit 1
 			;;
 		esac
+
+		case ${with_fix_loongson3_llsc} in
+		yes)
+			with_fix_loongson3_llsc=fix-loongson3-llsc
+			;;
+		no)
+			with_fix_loongson3_llsc=no-fix-loongson3-llsc
+			;;
+		"")
+			;;
+		*)
+			echo "Unknown fix-loongson3-llsc type used in --with-fix-loongson3-llsc" 1>&2
+			exit 1
+			;;
+		esac
 		;;
 
 	nds32*-*-*)
@@ -4937,7 +4952,7 @@  case ${target} in
 esac
 
 t=
-all_defaults="abi cpu cpu_32 cpu_64 arch arch_32 arch_64 tune tune_32 tune_64 schedule float mode fpu nan fp_32 odd_spreg_32 divide llsc mips-plt synci tls lxc1-sxc1 madd4"
+all_defaults="abi cpu cpu_32 cpu_64 arch arch_32 arch_64 tune tune_32 tune_64 schedule float mode fpu nan fp_32 odd_spreg_32 divide llsc mips-plt synci tls lxc1-sxc1 madd4 fix-loongson3-llsc"
 for option in $all_defaults
 do
 	eval "val=\$with_"`echo $option | sed s/-/_/g`
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index 55b440785..717f3d032 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -14127,7 +14127,7 @@  mips_process_sync_loop (rtx_insn *insn, rtx *operands)
   mips_multi_start ();
 
   /* Output the release side of the memory barrier.  */
-  if (need_atomic_barrier_p (model, true))
+  if (need_atomic_barrier_p (model, true) && !FIX_LOONGSON3_LLSC)
     {
       if (required_oldval == 0 && TARGET_OCTEON)
 	{
@@ -14148,6 +14148,10 @@  mips_process_sync_loop (rtx_insn *insn, rtx *operands)
   /* Output the branch-back label.  */
   mips_multi_add_label ("1:");
 
+  /* Loongson3 target need sync before ll/lld.  */
+  if (need_atomic_barrier_p (model,  true) && FIX_LOONGSON3_LLSC)
+    mips_multi_add_insn ("sync", NULL);
+
   /* OLDVAL = *MEM.  */
   mips_multi_add_insn (is_64bit_p ? "lld\t%0,%1" : "ll\t%0,%1",
 		       oldval, mem, NULL);
@@ -14257,13 +14261,18 @@  mips_process_sync_loop (rtx_insn *insn, rtx *operands)
     mips_multi_add_insn ("li\t%0,1", cmp, NULL);
 
   /* Output the acquire side of the memory barrier.  */
-  if (TARGET_SYNC_AFTER_SC && need_atomic_barrier_p (model, false))
+  if (TARGET_SYNC_AFTER_SC && need_atomic_barrier_p (model, false)
+      && !FIX_LOONGSON3_LLSC)
     mips_multi_add_insn ("sync", NULL);
 
   /* Output the exit label, if needed.  */
   if (required_oldval)
     mips_multi_add_label ("2:");
 
+  /* Loongson3 need a sync before branch target that between ll and sc.  */
+  if (FIX_LOONGSON3_LLSC)
+    mips_multi_add_insn ("sync", NULL);
+
 #undef READ_OPERAND
 }
 
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index d2205f089..9605b4bb7 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -655,6 +655,8 @@  struct mips_cpu_info {
 	builtin_define ("__mips_no_lxc1_sxc1");				\
       if (!ISA_HAS_UNFUSED_MADD4 && !ISA_HAS_FUSED_MADD4)		\
 	builtin_define ("__mips_no_madd4");				\
+      if (FIX_LOONGSON3_LLSC)		\
+	builtin_define ("__mips_fix_loongson3_llsc");				\
     }									\
   while (0)
 
@@ -890,7 +892,9 @@  struct mips_cpu_info {
   {"mips-plt", "%{!mplt:%{!mno-plt:-m%(VALUE)}}" }, \
   {"synci", "%{!msynci:%{!mno-synci:-m%(VALUE)}}" },			\
   {"lxc1-sxc1", "%{!mlxc1-sxc1:%{!mno-lxc1-sxc1:-m%(VALUE)}}" }, \
-  {"madd4", "%{!mmadd4:%{!mno-madd4:-m%(VALUE)}}" } \
+  {"madd4", "%{!mmadd4:%{!mno-madd4:-m%(VALUE)}}" },  \
+  {"fix-loongson3-llsc", "%{!mfix-loongson3-llsc:   \
+			  %{!mno-fix-loongson3-llsc:-m%(VALUE)}}" }
 
 /* A spec that infers the:
    -mnan=2008 setting from a -mips argument,
@@ -1415,6 +1419,7 @@  struct mips_cpu_info {
 %{mfix-rm7000} %{mno-fix-rm7000} \
 %{mfix-vr4120} %{mfix-vr4130} \
 %{mfix-24k} \
+%{mfix-loongson3-llsc} %{mno-fix-loongson3-llsc} \
 %{noasmopt:-O0; O0|fno-delayed-branch:-O1; O*:-O2; :-O1} \
 %(subtarget_asm_debugging_spec) \
 %{mabi=*} %{!mabi=*: %(asm_abi_default_spec)} \
diff --git a/gcc/config/mips/mips.opt b/gcc/config/mips/mips.opt
index 753321004..6a7567a4e 100644
--- a/gcc/config/mips/mips.opt
+++ b/gcc/config/mips/mips.opt
@@ -193,6 +193,10 @@  mfix4300
 Target Report Var(TARGET_4300_MUL_FIX)
 Work around an early 4300 hardware bug.
 
+mfix-loongson3-llsc
+Target Report Var(FIX_LOONGSON3_LLSC)
+Work around an Loongson3 llsc errata.
+
 mfp-exceptions
 Target Report Var(TARGET_FP_EXCEPTIONS) Init(1)
 FP exceptions are enabled.
diff --git a/gcc/testsuite/gcc.target/mips/fix-loongson3-llsc.c b/gcc/testsuite/gcc.target/mips/fix-loongson3-llsc.c
new file mode 100644
index 000000000..f82e39a47
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/fix-loongson3-llsc.c
@@ -0,0 +1,10 @@ 
+/* { dg-do compile } */
+/* { dg-options "-mfix-loongson3-llsc" } */
+
+NOMIPS16 int foo (int *v)
+{
+  return  __sync_val_compare_and_swap (v, 0, 1);
+}
+
+/* { dg-final { scan-assembler "1:\n\tsync\n\tll" } } */
+/* { dg-final { scan-assembler "2:\n\tsync\n" } } */
diff --git a/gcc/testsuite/gcc.target/mips/mips.exp b/gcc/testsuite/gcc.target/mips/mips.exp
index 002cc280e..975c51f82 100644
--- a/gcc/testsuite/gcc.target/mips/mips.exp
+++ b/gcc/testsuite/gcc.target/mips/mips.exp
@@ -281,6 +281,7 @@  foreach option {
     fix-r4000
     fix-r10000
     fix-vr4130
+    fix-loongson3-llsc
     gpopt
     local-sdata
     long-calls