From 66471b4708b84db82570b9747fb4e157c23f9804 Mon Sep 17 00:00:00 2001
From: David Daney <ddaney@avtrex.com>
Date: Tue, 11 Sep 2007 20:14:51 +0000
Subject: [PATCH] invoke.texi: Document new MIPS -mllsc and -mno-llsc options.

	* doc/invoke.texi: Document new MIPS -mllsc and -mno-llsc options.
	* doc/install.texi: Document new --with-llsc and --without-llsc
	options.
	* config.gcc: Handle --with-llsc and --without-llsc configure options.
	* config/mips/mips.md (sync, memory_barrier): Wrap sync instrunction
	in %| and %- operand codes.  Depend on GENERATE_SYNC instead of
	ISA_HAS_SYNC.
	(sync_compare_and_swap<mode>, sync_add<mode>, sync_sub<mode>,
	sync_old_add<mode>, sync_old_sub<mode>, sync_new_add<mode>,
	sync_new_sub<mode>, sync_<optab><mode>, sync_old_<optab><mode>,
	sync_new_<optab><mode>, sync_nand<mode>, sync_old_nand<mode>,
	sync_new_nand<mode>, sync_lock_test_and_set<mode>): Depend on
	GENERATE_LL_SC instead of ISA_HAS_LL_SC.
	* config/mips/mips.opt (mllsc): New option.
	* config/mips/mips.c (mips_llsc): Define variable.
	(mips_handle_option): Handle mllsc option.
	(override_options): Set mips_print_operand_punct for '|' and '-'.
	(print_operand): Add new %| and %- operand codes.
	* config/mips/mips.h (mips_llsc_setting): New enum type.
	(mips_llsc): Declare.
	(OPTION_DEFAULT_SPECS): Add llsc handling.
	(GENERATE_SYNC): New macro.
	(GENERATE_LL_SC): New macro.
	(MIPS_COMPARE_AND_SWAP, MIPS_SYNC_OP, MIPS_SYNC_OLD_OP,
	MIPS_SYNC_NEW_OP, MIPS_SYNC_NAND, MIPS_SYNC_OLD_NAND,
	MIPS_SYNC_NEW_NAND, MIPS_SYNC_EXCHANGE): Wrap instructions
	in %| and %- operand codes.

From-SVN: r128392
---
 gcc/ChangeLog            | 30 ++++++++++++++++++++++
 gcc/config.gcc           | 23 +++++++++++++++--
 gcc/config/mips/mips.c   | 26 +++++++++++++++++--
 gcc/config/mips/mips.h   | 55 +++++++++++++++++++++++++++-------------
 gcc/config/mips/mips.md  | 36 +++++++++++++-------------
 gcc/config/mips/mips.opt |  4 +++
 gcc/doc/install.texi     | 27 ++++++++++++++++++++
 gcc/doc/invoke.texi      | 18 ++++++++++++-
 8 files changed, 179 insertions(+), 40 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 3fff25df9b04..d1cf9dad2f2e 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,33 @@
+2007-09-11  David Daney  <ddaney@avtrex.com>
+
+	* doc/invoke.texi: Document new MIPS -mllsc and -mno-llsc options.
+	* doc/install.texi: Document new --with-llsc and --without-llsc
+	options.
+	* config.gcc: Handle --with-llsc and --without-llsc configure options.
+	* config/mips/mips.md (sync, memory_barrier): Wrap sync instrunction
+	in %| and %- operand codes.  Depend on GENERATE_SYNC instead of
+	ISA_HAS_SYNC.
+	(sync_compare_and_swap<mode>, sync_add<mode>, sync_sub<mode>,
+	sync_old_add<mode>, sync_old_sub<mode>, sync_new_add<mode>,
+	sync_new_sub<mode>, sync_<optab><mode>, sync_old_<optab><mode>,
+	sync_new_<optab><mode>, sync_nand<mode>, sync_old_nand<mode>,
+	sync_new_nand<mode>, sync_lock_test_and_set<mode>): Depend on
+	GENERATE_LL_SC instead of ISA_HAS_LL_SC.
+	* config/mips/mips.opt (mllsc): New option.
+	* config/mips/mips.c (mips_llsc): Define variable.
+	(mips_handle_option): Handle mllsc option.
+	(override_options): Set mips_print_operand_punct for '|' and '-'.
+	(print_operand): Add new %| and %- operand codes.
+	* config/mips/mips.h (mips_llsc_setting): New enum type.
+	(mips_llsc): Declare.
+	(OPTION_DEFAULT_SPECS): Add llsc handling.
+	(GENERATE_SYNC): New macro.
+	(GENERATE_LL_SC): New macro.
+	(MIPS_COMPARE_AND_SWAP, MIPS_SYNC_OP, MIPS_SYNC_OLD_OP,
+	MIPS_SYNC_NEW_OP, MIPS_SYNC_NAND, MIPS_SYNC_OLD_NAND,
+	MIPS_SYNC_NEW_NAND, MIPS_SYNC_EXCHANGE): Wrap instructions
+	in %| and %- operand codes.
+
 2007-09-11  Eric Botcazou  <ebotcazou@adacore.com>
 
 	* tree-ssa-structalias.c (push_fields_onto_fieldstack): Deal with
diff --git a/gcc/config.gcc b/gcc/config.gcc
index 18160f270ce0..b06334ce1414 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -1663,6 +1663,7 @@ mips64*-*-linux*)
 	tm_defines="${tm_defines} MIPS_ABI_DEFAULT=ABI_N32"
 	gnu_ld=yes
 	gas=yes
+	test x$with_llsc != x || with_llsc=yes
 	;;
 mips*-*-linux*)				# Linux MIPS, either endian.
         tm_file="dbxelf.h elfos.h svr4.h linux.h ${tm_file} mips/linux.h"
@@ -1672,6 +1673,7 @@ mips*-*-linux*)				# Linux MIPS, either endian.
 		tm_defines="${tm_defines} MIPS_ISA_DEFAULT=32"
                 ;;
         esac
+	test x$with_llsc != x || with_llsc=yes
 	;;
 mips*-*-openbsd*)
 	tm_defines="${tm_defines} OBSD_HAS_DECLARE_FUNCTION_NAME OBSD_HAS_DECLARE_OBJECT OBSD_HAS_CORRECT_SPECS"
@@ -3008,7 +3010,7 @@ case "${target}" in
 		;;
 
 	mips*-*-*)
-		supported_defaults="abi arch float tune divide"
+		supported_defaults="abi arch float tune divide llsc"
 
 		case ${with_float} in
 		"" | soft | hard)
@@ -3037,6 +3039,23 @@ case "${target}" in
 		*)
 			echo "Unknown division check type use in --with-divide=$with_divide" 1>&2
 			exit 1
+			;;
+		esac
+
+		case ${with_llsc} in
+		yes)
+			with_llsc=llsc
+			;;
+		no)
+			with_llsc="no-llsc"
+			;;
+		"")
+			# OK
+			;;
+		*)
+			echo "Unknown llsc type used in --with-llsc" 1>&2
+			exit 1
+			;;
 		esac
 		;;
 
@@ -3301,7 +3320,7 @@ case ${target} in
 esac
 
 t=
-all_defaults="abi cpu arch tune schedule float mode fpu divide"
+all_defaults="abi cpu arch tune schedule float mode fpu divide llsc"
 for option in $all_defaults
 do
 	eval "val=\$with_$option"
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index 289f46e18bc4..1a2cc0699db8 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -636,6 +636,9 @@ static GTY(()) int mips16_flipper;
 /* The -mtext-loads setting.  */
 enum mips_code_readable_setting mips_code_readable = CODE_READABLE_YES;
 
+/* The -mllsc setting.  */
+enum mips_llsc_setting mips_llsc = LLSC_DEFAULT;
+
 /* The architecture selected by -mipsN.  */
 static const struct mips_cpu_info *mips_isa_info;
 
@@ -5711,7 +5714,7 @@ mips_set_current_function (tree fndecl ATTRIBUTE_UNUSED)
 /* Implement TARGET_HANDLE_OPTION.  */
 
 static bool
-mips_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
+mips_handle_option (size_t code, const char *arg, int value)
 {
   switch (code)
     {
@@ -5753,6 +5756,10 @@ mips_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
 	return false;
       return true;
 
+    case OPT_mllsc:
+      mips_llsc = value ? LLSC_YES : LLSC_NO;
+      return true;
+
     default:
       return true;
     }
@@ -6015,6 +6022,8 @@ override_options (void)
   mips_print_operand_punct['$'] = 1;
   mips_print_operand_punct['+'] = 1;
   mips_print_operand_punct['~'] = 1;
+  mips_print_operand_punct['|'] = 1;
+  mips_print_operand_punct['-'] = 1;
 
   /* Set up array to map GCC register number to debug register number.
      Ignore the special purpose register numbers.  */
@@ -6377,7 +6386,10 @@ mips_strip_unspec_address (rtx op)
    '^'	Print the name of the pic call-through register (t9 or $25).
    '$'	Print the name of the stack pointer register (sp or $29).
    '+'	Print the name of the gp register (usually gp or $28).
-   '~'	Output a branch alignment to LABEL_ALIGN(NULL).  */
+   '~'	Output a branch alignment to LABEL_ALIGN(NULL).
+   '|'  Print .set push; .set mips2 if mips_llsc == LLSC_YES
+        && !ISA_HAS_LL_SC.
+   '-'  Print .set pop under the same conditions for '|'.  */
 
 void
 print_operand (FILE *file, rtx op, int letter)
@@ -6507,6 +6519,16 @@ print_operand (FILE *file, rtx op, int letter)
 	  }
 	  break;
 
+	case '|':
+	  if (!ISA_HAS_LL_SC)
+	    fputs (".set\tpush\n\t.set\tmips2\n\t", file);
+	  break;
+
+	case '-':
+	  if (!ISA_HAS_LL_SC)
+	    fputs ("\n\t.set\tpop", file);
+	  break;
+
 	default:
 	  error ("PRINT_OPERAND: unknown punctuation '%c'", letter);
 	  break;
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index ca534bf3ff63..7aa6aa83338d 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -121,6 +121,14 @@ enum mips_code_readable_setting {
   CODE_READABLE_YES
 };
 
+
+/* Enumerates the setting of the -mllsc option.  */
+enum mips_llsc_setting {
+  LLSC_DEFAULT,
+  LLSC_NO,
+  LLSC_YES
+};
+
 #ifndef USED_FOR_TARGET
 extern char mips_print_operand_punct[256]; /* print_operand punctuation chars */
 extern const char *current_function_file; /* filename current function is in */
@@ -145,6 +153,7 @@ extern const struct mips_cpu_info *mips_arch_info;
 extern const struct mips_cpu_info *mips_tune_info;
 extern const struct mips_rtx_cost_data *mips_cost;
 extern enum mips_code_readable_setting mips_code_readable;
+extern enum mips_llsc_setting mips_llsc;
 #endif
 
 /* Macros to silence warnings about numbers being signed in traditional
@@ -688,7 +697,8 @@ extern enum mips_code_readable_setting mips_code_readable;
   {"tune", "%{!mtune=*:-mtune=%(VALUE)}" }, \
   {"abi", "%{!mabi=*:-mabi=%(VALUE)}" }, \
   {"float", "%{!msoft-float:%{!mhard-float:-m%(VALUE)-float}}" }, \
-  {"divide", "%{!mdivide-traps:%{!mdivide-breaks:-mdivide-%(VALUE)}}" }
+  {"divide", "%{!mdivide-traps:%{!mdivide-breaks:-mdivide-%(VALUE)}}" }, \
+  {"llsc", "%{!mllsc:%{!mno-llsc:-m%(VALUE)}}" }
 
 
 #define GENERATE_DIVIDE_TRAPS (TARGET_DIVIDE_TRAPS \
@@ -893,11 +903,15 @@ extern enum mips_code_readable_setting mips_code_readable;
 
 /* ISA includes sync.  */
 #define ISA_HAS_SYNC ((mips_isa >= 2 || TARGET_MIPS3900) && !TARGET_MIPS16)
+#define GENERATE_SYNC (mips_llsc == LLSC_YES \
+		       || (mips_llsc == LLSC_DEFAULT && ISA_HAS_SYNC))
 
 /* ISA includes ll and sc.  Note that this implies ISA_HAS_SYNC
    because the expanders use both ISA_HAS_SYNC and ISA_HAS_LL_SC
    instructions.  */
 #define ISA_HAS_LL_SC (mips_isa >= 2 && !TARGET_MIPS16)
+#define GENERATE_LL_SC (mips_llsc == LLSC_YES \
+			|| (mips_llsc == LLSC_DEFAULT && ISA_HAS_LL_SC))
 
 /* Add -G xx support.  */
 
@@ -2913,11 +2927,12 @@ while (0)
    and OP is the instruction that should be used to load %3 into a
    register.  */
 #define MIPS_COMPARE_AND_SWAP(SUFFIX, OP)	\
-  "%(%<%[sync\n"				\
+  "%(%<%[%|sync\n"				\
   "1:\tll" SUFFIX "\t%0,%1\n"			\
   "\tbne\t%0,%2,2f\n"				\
   "\t" OP "\t%@,%3\n"				\
-  "\tsc" SUFFIX "\t%@,%1\n"			\
+  "\tsc" SUFFIX "\t%@,%1"			\
+  "%-\n"					\
   "\tbeq\t%@,%.,1b\n"				\
   "\tnop\n"					\
   "2:%]%>%)"
@@ -2929,10 +2944,11 @@ while (0)
    SUFFIX is the suffix that should be added to "ll" and "sc"
    instructions.  */
 #define MIPS_SYNC_OP(SUFFIX, INSN)		\
-  "%(%<%[sync\n"				\
+  "%(%<%[%|sync\n"				\
   "1:\tll" SUFFIX "\t%@,%0\n"			\
   "\t" INSN "\t%@,%@,%1\n"			\
-  "\tsc" SUFFIX "\t%@,%0\n"			\
+  "\tsc" SUFFIX "\t%@,%0"			\
+  "%-\n"					\
   "\tbeq\t%@,%.,1b\n"				\
   "\tnop%]%>%)"
 
@@ -2945,10 +2961,11 @@ while (0)
    SUFFIX is the suffix that should be added to "ll" and "sc"
    instructions.  */
 #define MIPS_SYNC_OLD_OP(SUFFIX, INSN)		\
-  "%(%<%[sync\n"				\
+  "%(%<%[%|sync\n"				\
   "1:\tll" SUFFIX "\t%0,%1\n"			\
   "\t" INSN "\t%@,%0,%2\n"			\
-  "\tsc" SUFFIX "\t%@,%1\n"			\
+  "\tsc" SUFFIX "\t%@,%1"			\
+  "%-\n"					\
   "\tbeq\t%@,%.,1b\n"				\
   "\tnop%]%>%)"
 
@@ -2961,10 +2978,11 @@ while (0)
    SUFFIX is the suffix that should be added to "ll" and "sc"
    instructions.  */
 #define MIPS_SYNC_NEW_OP(SUFFIX, INSN)		\
-  "%(%<%[sync\n"				\
+  "%(%<%[%|sync\n"				\
   "1:\tll" SUFFIX "\t%0,%1\n"			\
   "\t" INSN "\t%@,%0,%2\n"			\
-  "\tsc" SUFFIX "\t%@,%1\n"			\
+  "\tsc" SUFFIX "\t%@,%1"			\
+  "%-\n"					\
   "\tbeq\t%@,%.,1b\n"				\
   "\t" INSN "\t%0,%0,%2%]%>%)"
 
@@ -2976,11 +2994,12 @@ while (0)
    instructions.  INSN is the and instruction needed to and a register
    with %2.  */
 #define MIPS_SYNC_NAND(SUFFIX, INSN)		\
-  "%(%<%[sync\n"				\
+  "%(%<%[%|sync\n"				\
   "1:\tll" SUFFIX "\t%@,%0\n"			\
   "\tnor\t%@,%@,%.\n"				\
   "\t" INSN "\t%@,%@,%1\n"			\
-  "\tsc" SUFFIX "\t%@,%0\n"			\
+  "\tsc" SUFFIX "\t%@,%0"			\
+  "%-\n"					\
   "\tbeq\t%@,%.,1b\n"				\
   "\tnop%]%>%)"
 
@@ -2994,11 +3013,12 @@ while (0)
    instructions.  INSN is the and instruction needed to and a register
    with %2.  */
 #define MIPS_SYNC_OLD_NAND(SUFFIX, INSN)	\
-  "%(%<%[sync\n"				\
+  "%(%<%[%|sync\n"				\
   "1:\tll" SUFFIX "\t%0,%1\n"			\
   "\tnor\t%@,%0,%.\n"				\
   "\t" INSN "\t%@,%@,%2\n"			\
-  "\tsc" SUFFIX "\t%@,%1\n"			\
+  "\tsc" SUFFIX "\t%@,%1"			\
+  "%-\n"					\
   "\tbeq\t%@,%.,1b\n"				\
   "\tnop%]%>%)"
 
@@ -3012,11 +3032,12 @@ while (0)
    instructions.  INSN is the and instruction needed to and a register
    with %2.  */
 #define MIPS_SYNC_NEW_NAND(SUFFIX, INSN)	\
-  "%(%<%[sync\n"				\
+  "%(%<%[%|sync\n"				\
   "1:\tll" SUFFIX "\t%0,%1\n"			\
   "\tnor\t%0,%0,%.\n"				\
   "\t" INSN "\t%@,%0,%2\n"			\
-  "\tsc" SUFFIX "\t%@,%1\n"			\
+  "\tsc" SUFFIX "\t%@,%1"			\
+  "%-\n"					\
   "\tbeq\t%@,%.,1b\n"				\
   "\t" INSN "\t%0,%0,%2%]%>%)"
 
@@ -3030,11 +3051,11 @@ while (0)
    instructions.  OP is the and instruction that should be used to
    load %2 into a register.  */
 #define MIPS_SYNC_EXCHANGE(SUFFIX, OP)		\
-  "%(%<%[\n"					\
+  "%(%<%[%|\n"					\
   "1:\tll" SUFFIX "\t%0,%1\n"			\
   "\t" OP "\t%@,%2\n"				\
   "\tsc" SUFFIX "\t%@,%1\n"			\
   "\tbeq\t%@,%.,1b\n"				\
   "\tnop\n"					\
-  "\tsync%]%>%)"
+  "\tsync%-%]%>%)"
 
diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index c1cffb1bc04c..299980657ec3 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -4285,8 +4285,8 @@
 
 (define_insn "sync"
   [(unspec_volatile [(const_int 0)] UNSPEC_SYNC)]
-  "ISA_HAS_SYNC"
-  "sync")
+  "GENERATE_SYNC"
+  "%|sync%-")
 
 (define_insn "synci"
   [(unspec_volatile [(match_operand 0 "pmode_register_operand" "d")]
@@ -4323,8 +4323,8 @@
 (define_insn "memory_barrier"
   [(set (mem:BLK (scratch))
         (unspec:BLK [(const_int 0)] UNSPEC_MEMORY_BARRIER))]
-  "ISA_HAS_SYNC"
-  "sync")
+  "GENERATE_SYNC"
+  "%|sync%-")
 
 (define_insn "sync_compare_and_swap<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,d")
@@ -4333,7 +4333,7 @@
 	(unspec_volatile:GPR [(match_operand:GPR 2 "register_operand" "d,d")
 			      (match_operand:GPR 3 "arith_operand" "I,d")]
 	 UNSPEC_COMPARE_AND_SWAP))]
-  "ISA_HAS_LL_SC"
+  "GENERATE_LL_SC"
 {
   if (which_alternative == 0)
     return MIPS_COMPARE_AND_SWAP ("<d>", "li");
@@ -4348,7 +4348,7 @@
           [(plus:GPR (match_dup 0)
 			      (match_operand:GPR 1 "arith_operand" "I,d"))]
 	 UNSPEC_SYNC_OLD_OP))]
-  "ISA_HAS_LL_SC"
+  "GENERATE_LL_SC"
 {
   if (which_alternative == 0)
     return MIPS_SYNC_OP ("<d>", "<d>addiu");	
@@ -4363,7 +4363,7 @@
           [(minus:GPR (match_dup 0)
 			      (match_operand:GPR 1 "register_operand" "d"))]
 	 UNSPEC_SYNC_OLD_OP))]
-  "ISA_HAS_LL_SC"
+  "GENERATE_LL_SC"
 {
     return MIPS_SYNC_OP ("<d>", "<d>subu");	
 }
@@ -4377,7 +4377,7 @@
           [(plus:GPR (match_dup 1)
 		     (match_operand:GPR 2 "arith_operand" "I,d"))]
 	 UNSPEC_SYNC_OLD_OP))]
-  "ISA_HAS_LL_SC"
+  "GENERATE_LL_SC"
 {
   if (which_alternative == 0)
     return MIPS_SYNC_OLD_OP ("<d>", "<d>addiu");	
@@ -4394,7 +4394,7 @@
           [(minus:GPR (match_dup 1)
 		      (match_operand:GPR 2 "register_operand" "d"))]
 	 UNSPEC_SYNC_OLD_OP))]
-  "ISA_HAS_LL_SC"
+  "GENERATE_LL_SC"
 {
   return MIPS_SYNC_OLD_OP ("<d>", "<d>subu");	
 }
@@ -4408,7 +4408,7 @@
 	(unspec_volatile:GPR
 	  [(plus:GPR (match_dup 1) (match_dup 2))]
 	 UNSPEC_SYNC_NEW_OP))]
-  "ISA_HAS_LL_SC"
+  "GENERATE_LL_SC"
 {
   if (which_alternative == 0)
     return MIPS_SYNC_NEW_OP ("<d>", "<d>addiu");	
@@ -4425,7 +4425,7 @@
 	(unspec_volatile:GPR
 	  [(minus:GPR (match_dup 1) (match_dup 2))]
 	 UNSPEC_SYNC_NEW_OP))]
-  "ISA_HAS_LL_SC"
+  "GENERATE_LL_SC"
 {
   return MIPS_SYNC_NEW_OP ("<d>", "<d>subu");	
 }
@@ -4437,7 +4437,7 @@
           [(fetchop_bit:GPR (match_operand:GPR 1 "uns_arith_operand" "K,d")
 			      (match_dup 0))]
 	 UNSPEC_SYNC_OLD_OP))]
-  "ISA_HAS_LL_SC"
+  "GENERATE_LL_SC"
 {
   if (which_alternative == 0)
     return MIPS_SYNC_OP ("<d>", "<immediate_insn>");	
@@ -4454,7 +4454,7 @@
           [(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d")
 			    (match_dup 1))]
 	 UNSPEC_SYNC_OLD_OP))]
-  "ISA_HAS_LL_SC"
+  "GENERATE_LL_SC"
 {
   if (which_alternative == 0)
     return MIPS_SYNC_OLD_OP ("<d>", "<immediate_insn>");	
@@ -4471,7 +4471,7 @@
           [(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d")
 			    (match_dup 1))]
 	 UNSPEC_SYNC_NEW_OP))]
-  "ISA_HAS_LL_SC"
+  "GENERATE_LL_SC"
 {
   if (which_alternative == 0)
     return MIPS_SYNC_NEW_OP ("<d>", "<immediate_insn>");	
@@ -4484,7 +4484,7 @@
   [(set (match_operand:GPR 0 "memory_operand" "+R,R")
 	(unspec_volatile:GPR [(match_operand:GPR 1 "uns_arith_operand" "K,d")]
 	 UNSPEC_SYNC_OLD_OP))]
-  "ISA_HAS_LL_SC"
+  "GENERATE_LL_SC"
 {
   if (which_alternative == 0)
     return MIPS_SYNC_NAND ("<d>", "andi");	
@@ -4499,7 +4499,7 @@
    (set (match_dup 1)
         (unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")]
 	 UNSPEC_SYNC_OLD_OP))]
-  "ISA_HAS_LL_SC"
+  "GENERATE_LL_SC"
 {
   if (which_alternative == 0)
     return MIPS_SYNC_OLD_NAND ("<d>", "andi");	
@@ -4514,7 +4514,7 @@
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")]
 	 UNSPEC_SYNC_NEW_OP))]
-  "ISA_HAS_LL_SC"
+  "GENERATE_LL_SC"
 {
   if (which_alternative == 0)
     return MIPS_SYNC_NEW_NAND ("<d>", "andi");	
@@ -4529,7 +4529,7 @@
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")]
 	 UNSPEC_SYNC_EXCHANGE))]
-  "ISA_HAS_LL_SC"
+  "GENERATE_LL_SC"
 {
   if (which_alternative == 0)
     return MIPS_SYNC_EXCHANGE ("<d>", "li");
diff --git a/gcc/config/mips/mips.opt b/gcc/config/mips/mips.opt
index be00ee5d1b5f..bbbc305e39a9 100644
--- a/gcc/config/mips/mips.opt
+++ b/gcc/config/mips/mips.opt
@@ -176,6 +176,10 @@ mips3d
 Target Report RejectNegative Mask(MIPS3D)
 Use MIPS-3D instructions
 
+mllsc
+Target Report
+Use ll, sc and sync instructions
+
 mlocal-sdata
 Target Report Var(TARGET_LOCAL_SDATA) Init(1)
 Use -G for object-local data
diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi
index bac3bb20a55c..2517303260f7 100644
--- a/gcc/doc/install.texi
+++ b/gcc/doc/install.texi
@@ -1062,6 +1062,19 @@ systems that support conditional traps).
 Division by zero checks use the break instruction.
 @end table
 
+@c If you make --with-llsc the default for additional targets,
+@c update the --with-llsc description in the MIPS section below.
+
+@item --with-llsc
+On MIPS targets, make @option{-mllsc} the default when no
+@option{-mno-lsc} option is passed.  This is the default for
+Linux-based targets, as the kernel will emulate them if the ISA does
+not provide them.
+
+@item --without-llsc
+On MIPS targets, make @option{-mno-llsc} the default when no
+@option{-mllsc} option is passed.
+
 @item --enable-__cxa_atexit
 Define if you want to use __cxa_atexit, rather than atexit, to
 register C++ destructors for local statics and global objects.
@@ -3610,6 +3623,20 @@ configure for @samp{mipsel-elf} as a workaround.  The
 @samp{mips*-*-linux*} target continues to use the MIPS II routines.  More
 work on this is expected in future releases.
 
+@c If you make --with-llsc the default for another target, please also
+@c update the description of the --with-llsc option.
+
+The built-in @code{__sync_*} functions are available on MIPS II and
+later systems and others that support the @samp{ll}, @samp{sc} and
+@samp{sync} instructions.  This can be overridden by passing
+@option{--with-llsc} or @option{--without-llsc} when configuring GCC.
+Since the Linux kernel emulates these instructions if they are
+missing, the default for @samp{mips*-*-linux*} targets is
+@option{--with-llsc}.  The @option{--with-llsc} and
+@option{--without-llsc} configure options may be overridden at compile
+time by passing the @option{-mllsc} or @option{-mno-llsc} options to
+the compiler.
+
 MIPS systems check for division by zero (unless
 @option{-mno-check-zero-division} is passed to the compiler) by
 generating either a conditional trap or a break instruction.  Using
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 7413abd3ef33..f916b5050d31 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -627,7 +627,7 @@ Objective-C and Objective-C++ Dialects}.
 -msingle-float  -mdouble-float  -mdsp  -mno-dsp  -mdspr2  -mno-dspr2 @gol
 -msmartmips  -mno-smartmips @gol
 -mpaired-single  -mno-paired-single  -mdmx  -mno-mdmx @gol
--mips3d  -mno-mips3d  -mmt  -mno-mt @gol
+-mips3d  -mno-mips3d  -mmt  -mno-mt  -mllsc  -mno-llsc @gol
 -mlong64  -mlong32  -msym32  -mno-sym32 @gol
 -G@var{num}  -mlocal-sdata  -mno-local-sdata @gol
 -mextern-sdata  -mno-extern-sdata  -mgpopt  -mno-gopt @gol
@@ -11772,6 +11772,22 @@ operations.
 Assume that the floating-point coprocessor supports double-precision
 operations.  This is the default.
 
+@item -mllsc
+@itemx -mno-llsc
+@opindex mllsc
+@opindex mno-llsc
+Use (do not use) @samp{ll}, @samp{sc}, and @samp{sync} instructions to
+implement atomic memory built-in functions.  When neither option is
+specified, GCC will use the instructions if the target architecture
+supports them.
+
+@option{-mllsc} is useful if the runtime environment can emulate the
+instructions and @option{-mno-llsc} can be useful when compiling for
+nonstandard ISAs.  You can make either option the default by
+configuring GCC with @option{--with-llsc} and @option{--without-llsc}
+respectively.  @option{--with-llsc} is the default for some
+configurations; see the installation documentation for details.
+
 @item -mdsp
 @itemx -mno-dsp
 @opindex mdsp
-- 
GitLab