[MIPS] GCC: Fix Loongson3 LLSC Errata

Message ID CAKjxQHkGuM7V-e78-SyRypL8rYdQ2-mXLfYaK1au8x=LNnGgBA@mail.gmail.com
State New
Headers show
Series
  • [MIPS] GCC: Fix Loongson3 LLSC Errata
Related show

Commit Message

Paul Hua Nov. 30, 2018, 12:45 p.m.
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 also add a configure options
--with-mips-fix-loongson3-llsc=[yes|no] to enable fix-loongson3-llsc
by config.

Comments

YunQiang Su Dec. 3, 2018, 7:11 a.m. | #1
Paul Hua <paul.hua.gm@gmail.com> 于2018年11月30日周五 下午8:46写道:
>

> 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'.


Since it is not only about gcc, and also about as,
I guess we should check whether as support the new added option,
if so, we can call it with that option.

>

> This patch also add a configure options

> --with-mips-fix-loongson3-llsc=[yes|no] to enable fix-loongson3-llsc

> by config.


Should we add a predefined macro?
some manully writen asm code need some adjustment, such as linux kernel.

It need adjustment the label address if a `sync' is inserted.

https://patchwork.linux-mips.org/patch/21134/

- "1: "user_ll("%1", "%4")" # __futex_atomic_op\n" \
+ "1: # __futex_atomic_op\n" \
+ __WAR_LLSC_MB \
+ " "user_ll("%1", "%4")" \n" \
  " .set pop \n" \
  " " insn " \n" \
  " .set "MIPS_ISA_ARCH_LEVEL" \n" \
@@ -70,8 +72,9 @@
  " j 3b \n" \
  " .previous \n" \
  " .section __ex_table,\"a\" \n" \
- " "__UA_ADDR "\t1b, 4b \n" \
- " "__UA_ADDR "\t2b, 4b \n" \
+ " "__UA_ADDR "\t(1b + 0), 4b \n" \
+ " "__UA_ADDR "\t(1b + 4), 4b \n" \
+ " "__UA_ADDR "\t(2b + 0), 4b \n" \
Jiaxun Yang Sept. 30, 2019, 9:59 a.m. | #2
On 2018/11/30 下午8:45, Paul Hua wrote:
> 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'.


Hi all,

Any update about this patch?

As this workaround is the last barrier for generic MIPS distros to run 
on Loongson systems.

Btw, I heard from Loongson guys that type A (adding a sync before ll/lld 
instruction) of this errata only exist on pre-3A2000 (GS464) processors 
while type B exist on all processors. Is that true?

If so, then they should have different naming in flags to prevent 
confusing. I saw that you are using "LLTGT" and "LLSYNC" in cpucfg bit 
domin of 3A4000, should we also use that naming in toolchain?


Thanks.

--

Jiaxun Yang

> This patch also add a configure options

> --with-mips-fix-loongson3-llsc=[yes|no] to enable fix-loongson3-llsc

> by config.

>

> >From 16f0fd9e32d2098637dc0eb3e576444c48c43f22 Mon Sep 17 00:00:00 2001

> From: Chenghua Xu <paul.hua.gm@gmail.com>

> Date: Fri, 30 Nov 2018 19:57:38 +0800

> Subject: [PATCH] [MIPS][GCC]  Fix Loongson3 LLSC Errata.

>

> 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.

> 	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                        |  4 +++-

>   gcc/config/mips/mips.opt                      |  4 ++++

>   gcc/doc/install.texi                          |  4 ++++

>   gcc/doc/invoke.texi                           |  8 ++++++++

>   .../gcc.target/mips/fix-loongson3-llsc.c      | 10 ++++++++++

>   gcc/testsuite/gcc.target/mips/mips.exp        |  1 +

>   8 files changed, 58 insertions(+), 5 deletions(-)

>   create mode 100644 gcc/testsuite/gcc.target/mips/fix-loongson3-llsc.c

Patch

From 16f0fd9e32d2098637dc0eb3e576444c48c43f22 Mon Sep 17 00:00:00 2001
From: Chenghua Xu <paul.hua.gm@gmail.com>
Date: Fri, 30 Nov 2018 19:57:38 +0800
Subject: [PATCH] [MIPS][GCC]  Fix Loongson3 LLSC Errata.

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.
	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                        |  4 +++-
 gcc/config/mips/mips.opt                      |  4 ++++
 gcc/doc/install.texi                          |  4 ++++
 gcc/doc/invoke.texi                           |  8 ++++++++
 .../gcc.target/mips/fix-loongson3-llsc.c      | 10 ++++++++++
 gcc/testsuite/gcc.target/mips/mips.exp        |  1 +
 8 files changed, 58 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/mips/fix-loongson3-llsc.c

diff --git a/gcc/config.gcc b/gcc/config.gcc
index f6162ed496e..9887b43dc87 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -4323,7 +4323,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)
@@ -4476,6 +4476,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*-*-*)
@@ -4995,7 +5010,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 55b44078518..717f3d03292 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 d2205f08972..c445f5ab24b 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -890,7 +890,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,
diff --git a/gcc/config/mips/mips.opt b/gcc/config/mips/mips.opt
index 75332100435..6a7567a4e59 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/doc/install.texi b/gcc/doc/install.texi
index 19adb7ef870..1d5c64f9c97 100644
--- a/gcc/doc/install.texi
+++ b/gcc/doc/install.texi
@@ -1411,6 +1411,10 @@  These features are extensions to the traditional
 SVR4-based MIPS ABIs and require support from GNU binutils
 and the runtime C library.
 
+@item --with-fix-loongson3-llsc
+On MIPS Loongson3 targets, make @option{-mfix-loongson3-llsc} the default when no
+@option{-mno-fix-loongson3-llsc} option is passed.
+
 @item --with-stack-clash-protection-guard-size=@var{size}
 On certain targets this option sets the default stack clash protection guard
 size as a power of two in bytes.  On AArch64 @var{size} is required to be either
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 3b6912ea1cc..84b0b864360 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -953,6 +953,7 @@  Objective-C and Objective-C++ Dialects}.
 -mfix-r10000  -mno-fix-r10000  -mfix-rm7000  -mno-fix-rm7000 @gol
 -mfix-vr4120  -mno-fix-vr4120 @gol
 -mfix-vr4130  -mno-fix-vr4130  -mfix-sb1  -mno-fix-sb1 @gol
+-mfix-loongson3-llsc  -mno-fix-loongson3-llsc @gol
 -mflush-func=@var{func}  -mno-flush-func @gol
 -mbranch-cost=@var{num}  -mbranch-likely  -mno-branch-likely @gol
 -mcompact-branches=@var{policy} @gol
@@ -22211,6 +22212,13 @@  controls GCC's implementation of this workaround.  It assumes that
 aborted accesses to any byte in the following regions does not have
 side effects:
 
+@item -mfix-loongson3-llsc
+@opindex mfix-loongson3-llsc
+Work around the Loongson3 @code{ll}/@code{sc} errata.  The workarounds
+are implemented by the GCC and the assembler.  The GCC added
+@code{sync} before branch target that between @code{ll}/@code{sc}.
+The assembler added @code{sync} before @code{ll}.
+
 @enumerate
 @item
 the memory occupied by the current function's stack frame;
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 00000000000..f82e39a47ef
--- /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 002cc280e30..975c51f82b3 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
-- 
2.18.0