Fix a potential deadlock in some older Loongson 3A1000 MIPS processors.
authorPaul Hua <paul.hua.gm@gmail.com>
Tue, 19 Feb 2019 17:57:16 +0000 (17:57 +0000)
committerNick Clifton <nickc@redhat.com>
Tue, 19 Feb 2019 17:57:16 +0000 (17:57 +0000)
* NEWS: Mention -m[no-]fix-loongson3-llsc.
* configure.ac: Add --enable-mips-fix-loongson3-llsc.
Define DEFAULT_MIPS_FIX_LOONGSON3_LLSC.
* config.in: Regenerated.
* configure: Likewise.
* config/tc-mips.c (sync_insn, mips_fix_loongson3_llsc):
New variables.
(options): New OPTION_FIX_LOONGSON3_LLSC,
OPTION_NO_FIX_LOONGSON3_LLSC.
(md_longopts): Add -m[no-]fix-loongson3-llsc.
(md_begin): Initialize sync insn.
(fix_loongson3_llsc): New.
(append_insn): Call fix_loongson3_llsc.
(md_parse_option): Handle OPTION_FIX_LOONGSON3_LLSC,
OPTION_NO_FIX_LOONGSON3_LLSC.
(md_show_usage): Display -m[no-]fix-loongson3-llsc.
* doc/c-mips.texi: Document -m[no-]fix-loongson3-llsc,
--enable-mips-fix-loongson3-llsc=[yes|no].

gas/ChangeLog
gas/NEWS
gas/config.in
gas/config/tc-mips.c
gas/configure
gas/configure.ac
gas/doc/c-mips.texi

index 04ad383e89dcc44f78566fa9f43c119ac5be1733..2a4f194814444775eee019e94a16e0e26e805740 100644 (file)
@@ -1,3 +1,24 @@
+2019-02-19  Paul Hua  <paul.hua.gm@gmail.com>
+
+       * NEWS: Mention -m[no-]fix-loongson3-llsc.
+       * configure.ac: Add --enable-mips-fix-loongson3-llsc.
+       Define DEFAULT_MIPS_FIX_LOONGSON3_LLSC.
+       * config.in: Regenerated.
+       * configure: Likewise.
+       * config/tc-mips.c (sync_insn, mips_fix_loongson3_llsc):
+       New variables.
+       (options): New OPTION_FIX_LOONGSON3_LLSC,
+       OPTION_NO_FIX_LOONGSON3_LLSC.
+       (md_longopts): Add -m[no-]fix-loongson3-llsc.
+       (md_begin): Initialize sync insn.
+       (fix_loongson3_llsc): New.
+       (append_insn): Call fix_loongson3_llsc.
+       (md_parse_option): Handle OPTION_FIX_LOONGSON3_LLSC,
+       OPTION_NO_FIX_LOONGSON3_LLSC.
+       (md_show_usage): Display -m[no-]fix-loongson3-llsc.
+       * doc/c-mips.texi: Document -m[no-]fix-loongson3-llsc,
+       --enable-mips-fix-loongson3-llsc=[yes|no].
+
 2019-02-10  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR gas/24165
 2019-02-10  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR gas/24165
index 3eecf71a5fba9047f4d8150e60cd1bc88240ba84..3903c383c191428f0e39cf4a036d8d6243e2552f 100644 (file)
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -1,5 +1,10 @@
 -*- text -*-
 
 -*- text -*-
 
+* For MIPS, Add -m[no-]fix-loongson3-llsc option to fix (or not) Loongson3 LLSC
+  Errata.  Add a --enable-mips-fix-loongson3-llsc=[yes|no] configure time option
+  to set the default behavior. Set the default if the configure option is not used
+  to "no".
+
 Changes in 2.32:
 
 * Add -mvexwig=[0|1] option to x86 assembler to control encoding of
 Changes in 2.32:
 
 * Add -mvexwig=[0|1] option to x86 assembler to control encoding of
index 88b215873bd85ec742b5568bd18ab65711776acf..8724eb153ae6a56ce5645025484cba15ebec3bc6 100644 (file)
@@ -50,6 +50,9 @@
 /* Define to 1 if you want to generate x86 relax relocations by default. */
 #undef DEFAULT_GENERATE_X86_RELAX_RELOCATIONS
 
 /* Define to 1 if you want to generate x86 relax relocations by default. */
 #undef DEFAULT_GENERATE_X86_RELAX_RELOCATIONS
 
+/* Define to 1 if you want to fix Loongson3 LLSC Errata by default. */
+#undef DEFAULT_MIPS_FIX_LOONGSON3_LLSC
+
 /* Define to 1 if you want to generate RISC-V arch attribute by default. */
 #undef DEFAULT_RISCV_ATTR
 
 /* Define to 1 if you want to generate RISC-V arch attribute by default. */
 #undef DEFAULT_RISCV_ATTR
 
index ae5590422941347825dc38af2791759436e7a422..81b729a295d13d7b240910eb0e2277b5ff3df6c0 100644 (file)
@@ -141,6 +141,12 @@ struct mips_cl_insn
      extension.  */
   unsigned long insn_opcode;
 
      extension.  */
   unsigned long insn_opcode;
 
+  /* The name if this is an label.  */
+  char label[16];
+
+  /* The target label name if this is an branch.  */
+  char target[16];
+
   /* The frag that contains the instruction.  */
   struct frag *frag;
 
   /* The frag that contains the instruction.  */
   struct frag *frag;
 
@@ -511,7 +517,7 @@ static int mips_32bitmode = 0;
 /* True if CPU has a ror instruction.  */
 #define CPU_HAS_ROR(CPU)       CPU_HAS_DROR (CPU)
 
 /* True if CPU has a ror instruction.  */
 #define CPU_HAS_ROR(CPU)       CPU_HAS_DROR (CPU)
 
-/* True if CPU is in the Octeon family */
+/* True if CPU is in the Octeon family */
 #define CPU_IS_OCTEON(CPU) ((CPU) == CPU_OCTEON || (CPU) == CPU_OCTEONP \
                            || (CPU) == CPU_OCTEON2 || (CPU) == CPU_OCTEON3)
 
 #define CPU_IS_OCTEON(CPU) ((CPU) == CPU_OCTEON || (CPU) == CPU_OCTEONP \
                            || (CPU) == CPU_OCTEON2 || (CPU) == CPU_OCTEON3)
 
@@ -660,7 +666,7 @@ static int g_switch_seen = 0;
    fixed it for the non-PIC mode.  KR 95/04/07  */
 static int nopic_need_relax (symbolS *, int);
 
    fixed it for the non-PIC mode.  KR 95/04/07  */
 static int nopic_need_relax (symbolS *, int);
 
-/* handle of the OPCODE hash table */
+/* Handle of the OPCODE hash table.  */
 static struct hash_control *op_hash = NULL;
 
 /* The opcode hash table we use for the mips16.  */
 static struct hash_control *op_hash = NULL;
 
 /* The opcode hash table we use for the mips16.  */
@@ -670,12 +676,12 @@ static struct hash_control *mips16_op_hash = NULL;
 static struct hash_control *micromips_op_hash = NULL;
 
 /* This array holds the chars that always start a comment.  If the
 static struct hash_control *micromips_op_hash = NULL;
 
 /* This array holds the chars that always start a comment.  If the
-    pre-processor is disabled, these aren't very useful */
+    pre-processor is disabled, these aren't very useful */
 const char comment_chars[] = "#";
 
 /* This array holds the chars that only start a comment at the beginning of
    a line.  If the line seems to have the form '# 123 filename'
 const char comment_chars[] = "#";
 
 /* This array holds the chars that only start a comment at the beginning of
    a line.  If the line seems to have the form '# 123 filename'
-   .line and .file directives will appear in the pre-processed output */
+   .line and .file directives will appear in the pre-processed output */
 /* Note that input_file.c hand checks for '#' at the beginning of the
    first line of the input file.  This is because the compiler outputs
    #NO_APP at the beginning of its output.  */
 /* Note that input_file.c hand checks for '#' at the beginning of the
    first line of the input file.  This is because the compiler outputs
    #NO_APP at the beginning of its output.  */
@@ -685,22 +691,22 @@ const char line_comment_chars[] = "#";
 /* This array holds machine specific line separator characters.  */
 const char line_separator_chars[] = ";";
 
 /* This array holds machine specific line separator characters.  */
 const char line_separator_chars[] = ";";
 
-/* Chars that can be used to separate mant from exp in floating point nums */
+/* Chars that can be used to separate mant from exp in floating point nums */
 const char EXP_CHARS[] = "eE";
 
 const char EXP_CHARS[] = "eE";
 
-/* Chars that mean this number is a floating point constant */
-/* As in 0f12.456 */
-/* or    0d1.2345e12 */
+/* Chars that mean this number is a floating point constant.
+   As in 0f12.456
+   or    0d1.2345e12.  */
 const char FLT_CHARS[] = "rRsSfFdDxXpP";
 
 /* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
    changed in read.c .  Ideally it shouldn't have to know about it at all,
 const char FLT_CHARS[] = "rRsSfFdDxXpP";
 
 /* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
    changed in read.c .  Ideally it shouldn't have to know about it at all,
-   but nothing is ideal around here.
- */
+   but nothing is ideal around here.  */
 
 /* Types of printf format used for instruction-related error messages.
 
 /* Types of printf format used for instruction-related error messages.
-   "I" means int ("%d") and "S" means string ("%s"). */
-enum mips_insn_error_format {
+   "I" means int ("%d") and "S" means string ("%s").  */
+enum mips_insn_error_format
+{
   ERR_FMT_PLAIN,
   ERR_FMT_I,
   ERR_FMT_SS,
   ERR_FMT_PLAIN,
   ERR_FMT_I,
   ERR_FMT_SS,
@@ -708,7 +714,8 @@ enum mips_insn_error_format {
 
 /* Information about an error that was found while assembling the current
    instruction.  */
 
 /* Information about an error that was found while assembling the current
    instruction.  */
-struct mips_insn_error {
+struct mips_insn_error
+{
   /* We sometimes need to match an instruction against more than one
      opcode table entry.  Errors found during this matching are reported
      against a particular syntactic argument rather than against the
   /* We sometimes need to match an instruction against more than one
      opcode table entry.  Errors found during this matching are reported
      against a particular syntactic argument rather than against the
@@ -727,7 +734,8 @@ struct mips_insn_error {
   /* The printf()-style message, including its format and arguments.  */
   enum mips_insn_error_format format;
   const char *msg;
   /* The printf()-style message, including its format and arguments.  */
   enum mips_insn_error_format format;
   const char *msg;
-  union {
+  union
+  {
     int i;
     const char *ss[2];
   } u;
     int i;
     const char *ss[2];
   } u;
@@ -786,16 +794,20 @@ static int mips_debug = 0;
 /* The maximum number of NOPs needed for any purpose.  */
 #define MAX_NOPS 4
 
 /* The maximum number of NOPs needed for any purpose.  */
 #define MAX_NOPS 4
 
+/* The maximum range of context length of ll/sc.  */
+#define MAX_LLSC_RANGE 20
+
 /* A list of previous instructions, with index 0 being the most recent.
    We need to look back MAX_NOPS instructions when filling delay slots
    or working around processor errata.  We need to look back one
    instruction further if we're thinking about using history[0] to
    fill a branch delay slot.  */
 /* A list of previous instructions, with index 0 being the most recent.
    We need to look back MAX_NOPS instructions when filling delay slots
    or working around processor errata.  We need to look back one
    instruction further if we're thinking about using history[0] to
    fill a branch delay slot.  */
-static struct mips_cl_insn history[1 + MAX_NOPS];
+static struct mips_cl_insn history[1 + MAX_NOPS + MAX_LLSC_RANGE];
 
 /* Arrays of operands for each instruction.  */
 #define MAX_OPERANDS 6
 
 /* Arrays of operands for each instruction.  */
 #define MAX_OPERANDS 6
-struct mips_operand_array {
+struct mips_operand_array
+{
   const struct mips_operand *operand[MAX_OPERANDS];
 };
 static struct mips_operand_array *mips_operands;
   const struct mips_operand *operand[MAX_OPERANDS];
 };
 static struct mips_operand_array *mips_operands;
@@ -808,6 +820,9 @@ static struct mips_cl_insn mips16_nop_insn;
 static struct mips_cl_insn micromips_nop16_insn;
 static struct mips_cl_insn micromips_nop32_insn;
 
 static struct mips_cl_insn micromips_nop16_insn;
 static struct mips_cl_insn micromips_nop32_insn;
 
+/* Sync instructions used by insert sync.  */
+static struct mips_cl_insn sync_insn;
+
 /* The appropriate nop for the current mode.  */
 #define NOP_INSN (mips_opts.mips16                                     \
                  ? &mips16_nop_insn                                    \
 /* The appropriate nop for the current mode.  */
 #define NOP_INSN (mips_opts.mips16                                     \
                  ? &mips16_nop_insn                                    \
@@ -943,6 +958,9 @@ static bfd_boolean mips_fix_cn63xxp1;
 static bfd_boolean mips_fix_r5900;
 static bfd_boolean mips_fix_r5900_explicit;
 
 static bfd_boolean mips_fix_r5900;
 static bfd_boolean mips_fix_r5900_explicit;
 
+/* ...likewise -mfix-loongson3-llsc.  */
+static bfd_boolean mips_fix_loongson3_llsc = DEFAULT_MIPS_FIX_LOONGSON3_LLSC;
+
 /* We don't relax branches by default, since this causes us to expand
    `la .l2 - .l1' if there's a branch between .l1 and .l2, because we
    fail to compute the offset before expanding the macro to the most
 /* We don't relax branches by default, since this causes us to expand
    `la .l2 - .l1' if there's a branch between .l1 and .l2, because we
    fail to compute the offset before expanding the macro to the most
@@ -1482,6 +1500,8 @@ enum options
     OPTION_NO_FIX_24K,
     OPTION_FIX_RM7000,
     OPTION_NO_FIX_RM7000,
     OPTION_NO_FIX_24K,
     OPTION_FIX_RM7000,
     OPTION_NO_FIX_RM7000,
+    OPTION_FIX_LOONGSON3_LLSC,
+    OPTION_NO_FIX_LOONGSON3_LLSC,
     OPTION_FIX_LOONGSON2F_JUMP,
     OPTION_NO_FIX_LOONGSON2F_JUMP,
     OPTION_FIX_LOONGSON2F_NOP,
     OPTION_FIX_LOONGSON2F_JUMP,
     OPTION_NO_FIX_LOONGSON2F_JUMP,
     OPTION_FIX_LOONGSON2F_NOP,
@@ -1628,6 +1648,8 @@ struct option md_longopts[] =
   {"mfix7000", no_argument, NULL, OPTION_M7000_HILO_FIX},
   {"no-fix-7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
   {"mno-fix7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
   {"mfix7000", no_argument, NULL, OPTION_M7000_HILO_FIX},
   {"no-fix-7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
   {"mno-fix7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
+  {"mfix-loongson3-llsc",   no_argument, NULL, OPTION_FIX_LOONGSON3_LLSC},
+  {"mno-fix-loongson3-llsc", no_argument, NULL, OPTION_NO_FIX_LOONGSON3_LLSC},
   {"mfix-loongson2f-jump", no_argument, NULL, OPTION_FIX_LOONGSON2F_JUMP},
   {"mno-fix-loongson2f-jump", no_argument, NULL, OPTION_NO_FIX_LOONGSON2F_JUMP},
   {"mfix-loongson2f-nop", no_argument, NULL, OPTION_FIX_LOONGSON2F_NOP},
   {"mfix-loongson2f-jump", no_argument, NULL, OPTION_FIX_LOONGSON2F_JUMP},
   {"mno-fix-loongson2f-jump", no_argument, NULL, OPTION_NO_FIX_LOONGSON2F_JUMP},
   {"mfix-loongson2f-nop", no_argument, NULL, OPTION_FIX_LOONGSON2F_NOP},
@@ -2774,7 +2796,7 @@ struct regname {
     {"$ta2",   RTYPE_GP | 14}, /* alias for $t6 */ \
     {"$ta3",   RTYPE_GP | 15}  /* alias for $t7 */
 
     {"$ta2",   RTYPE_GP | 14}, /* alias for $t6 */ \
     {"$ta3",   RTYPE_GP | 15}  /* alias for $t7 */
 
-/* Remaining symbolic register names */
+/* Remaining symbolic register names */
 #define SYMBOLIC_REGISTER_NAMES \
     {"$zero",  RTYPE_GP | 0},  \
     {"$at",    RTYPE_GP | 1},  \
 #define SYMBOLIC_REGISTER_NAMES \
     {"$zero",  RTYPE_GP | 0},  \
     {"$at",    RTYPE_GP | 1},  \
@@ -2809,8 +2831,8 @@ struct regname {
     {"$pc",    RTYPE_PC | 0}
 
 #define MDMX_VECTOR_REGISTER_NAMES \
     {"$pc",    RTYPE_PC | 0}
 
 #define MDMX_VECTOR_REGISTER_NAMES \
-    /* {"$v0", RTYPE_VEC | 0},  clash with REG 2 above */ \
-    /* {"$v1", RTYPE_VEC | 1},  clash with REG 3 above */ \
+    /* {"$v0", RTYPE_VEC | 0},  Clash with REG 2 above.  */ \
+    /* {"$v1", RTYPE_VEC | 1},  Clash with REG 3 above.  */ \
     {"$v2",    RTYPE_VEC | 2},  \
     {"$v3",    RTYPE_VEC | 3},  \
     {"$v4",    RTYPE_VEC | 4},  \
     {"$v2",    RTYPE_VEC | 2},  \
     {"$v3",    RTYPE_VEC | 3},  \
     {"$v4",    RTYPE_VEC | 4},  \
@@ -3671,6 +3693,7 @@ md_begin (void)
          if (!validate_mips_insn (&mips_opcodes[i], 0xffffffff,
                                   decode_mips_operand, &mips_operands[i]))
            broken = 1;
          if (!validate_mips_insn (&mips_opcodes[i], 0xffffffff,
                                   decode_mips_operand, &mips_operands[i]))
            broken = 1;
+
          if (nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0)
            {
              create_insn (&nop_insn, mips_opcodes + i);
          if (nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0)
            {
              create_insn (&nop_insn, mips_opcodes + i);
@@ -3678,6 +3701,10 @@ md_begin (void)
                nop_insn.insn_opcode = LOONGSON2F_NOP_INSN;
              nop_insn.fixed_p = 1;
            }
                nop_insn.insn_opcode = LOONGSON2F_NOP_INSN;
              nop_insn.fixed_p = 1;
            }
+
+          if (sync_insn.insn_mo == NULL && strcmp (name, "sync") == 0)
+           create_insn (&sync_insn, mips_opcodes + i);
+
          ++i;
        }
       while ((i < NUMOPCODES) && !strcmp (mips_opcodes[i].name, name));
          ++i;
        }
       while ((i < NUMOPCODES) && !strcmp (mips_opcodes[i].name, name));
@@ -3833,7 +3860,7 @@ md_begin (void)
 
     /* The ABI says this section should be loaded so that the
        running program can access it.  However, we don't load it
 
     /* The ABI says this section should be loaded so that the
        running program can access it.  However, we don't load it
-       if we are configured for an embedded target */
+       if we are configured for an embedded target */
     flags = SEC_READONLY | SEC_DATA;
     if (strncmp (TARGET_OS, "elf", 3) != 0)
       flags |= SEC_ALLOC | SEC_LOAD;
     flags = SEC_READONLY | SEC_DATA;
     if (strncmp (TARGET_OS, "elf", 3) != 0)
       flags |= SEC_ALLOC | SEC_LOAD;
@@ -6859,6 +6886,103 @@ fix_loongson2f (struct mips_cl_insn * ip)
     fix_loongson2f_jump (ip);
 }
 
     fix_loongson2f_jump (ip);
 }
 
+/* Fix loongson3 llsc errata: Insert sync before ll/lld. */
+
+static void
+fix_loongson3_llsc (struct mips_cl_insn * ip)
+{
+  gas_assert (!HAVE_CODE_COMPRESSION);
+
+  /* If is an local label and the insn is not sync,
+     look forward that whether an branch between ll/sc jump to here
+     if so, insert a sync.  */
+  if (seg_info (now_seg)->label_list
+      && S_IS_LOCAL (seg_info (now_seg)->label_list->label)
+      && (strcmp (ip->insn_mo->name, "sync") != 0))
+    {
+      const char *label_name = S_GET_NAME (seg_info (now_seg)->label_list->label);
+      unsigned long lookback = ARRAY_SIZE (history);
+      unsigned long i;
+
+      for (i = 0; i < lookback; i++)
+       {
+         if (streq (history[i].insn_mo->name, "ll")
+             || streq (history[i].insn_mo->name, "lld"))
+           break;
+
+         if (streq (history[i].insn_mo->name, "sc")
+             || streq (history[i].insn_mo->name, "scd"))
+           {
+             unsigned long j;
+
+             for (j = i + 1; j < lookback; j++)
+               {
+                 if (streq (history[i].insn_mo->name, "ll")
+                     || streq (history[i].insn_mo->name, "lld"))
+                   break;
+
+                 if (delayed_branch_p (&history[j]))
+                   {
+                     if (streq (history[j].target, label_name))
+                       {
+                         add_fixed_insn (&sync_insn);
+                         insert_into_history (0, 1, &sync_insn);
+                         i = lookback;
+                         break;
+                       }
+                   }
+               }
+           }
+       }
+    }
+  /* If we find a sc, we look forward to look for an branch insn,
+     and see whether it jump back and out of ll/sc.  */
+  else if (streq(ip->insn_mo->name, "sc") || streq(ip->insn_mo->name, "scd"))
+    {
+      unsigned long lookback = ARRAY_SIZE (history) - 1;
+      unsigned long i;
+
+      for (i = 0; i < lookback; i++)
+       {
+         if (streq (history[i].insn_mo->name, "ll")
+             || streq (history[i].insn_mo->name, "lld"))
+           break;
+
+         if (delayed_branch_p (&history[i]))
+           {
+             unsigned long j;
+
+             for (j = i + 1; j < lookback; j++)
+               {
+                 if (streq (history[j].insn_mo->name, "ll")
+                     || streq (history[i].insn_mo->name, "lld"))
+                   break;
+               }
+
+             for (; j < lookback; j++)
+               {
+                 if (history[j].label[0] != '\0'
+                     && streq (history[j].label, history[i].target)
+                     && strcmp (history[j+1].insn_mo->name, "sync") != 0)
+                   {
+                     add_fixed_insn (&sync_insn);
+                     insert_into_history (++j, 1, &sync_insn);
+                   }
+               }
+           }
+       }
+    }
+
+  /* Skip if there is a sync before ll/lld.  */
+  if ((strcmp (ip->insn_mo->name, "ll") == 0
+       || strcmp (ip->insn_mo->name, "lld") == 0)
+      && (strcmp (history[0].insn_mo->name, "sync") != 0))
+    {
+      add_fixed_insn (&sync_insn);
+      insert_into_history (0, 1, &sync_insn);
+    }
+}
+
 /* IP is a branch that has a delay slot, and we need to fill it
    automatically.   Return true if we can do that by swapping IP
    with the previous instruction.
 /* IP is a branch that has a delay slot, and we need to fill it
    automatically.   Return true if we can do that by swapping IP
    with the previous instruction.
@@ -7316,6 +7440,15 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
   if (mips_fix_loongson2f && !HAVE_CODE_COMPRESSION)
     fix_loongson2f (ip);
 
   if (mips_fix_loongson2f && !HAVE_CODE_COMPRESSION)
     fix_loongson2f (ip);
 
+  ip->target[0] = '\0';
+  if (offset_expr.X_op == O_symbol)
+    strncpy (ip->target, S_GET_NAME (offset_expr.X_add_symbol), 15);
+  ip->label[0] = '\0';
+  if (seg_info (now_seg)->label_list)
+    strncpy (ip->label, S_GET_NAME (seg_info (now_seg)->label_list->label), 15);
+  if (mips_fix_loongson3_llsc && !HAVE_CODE_COMPRESSION)
+    fix_loongson3_llsc (ip);
+
   file_ase_mips16 |= mips_opts.mips16;
   file_ase_micromips |= mips_opts.micromips;
 
   file_ase_mips16 |= mips_opts.mips16;
   file_ase_micromips |= mips_opts.micromips;
 
@@ -10361,7 +10494,7 @@ macro (struct mips_cl_insn *ip, char *str)
          break;
        }
       ++imm_expr.X_add_number;
          break;
        }
       ++imm_expr.X_add_number;
-      /* FALLTHROUGH */
+      /* Fall through.  */
     case M_BGE_I:
     case M_BGEL_I:
       if (mask == M_BGEL_I)
     case M_BGE_I:
     case M_BGEL_I:
       if (mask == M_BGEL_I)
@@ -10381,7 +10514,7 @@ macro (struct mips_cl_insn *ip, char *str)
       if (imm_expr.X_add_number <= GPR_SMIN)
        {
        do_true:
       if (imm_expr.X_add_number <= GPR_SMIN)
        {
        do_true:
-         /* result is always true */
+         /* Result is always true.  */
          as_warn (_("branch %s is always true"), ip->insn_mo->name);
          macro_build (&offset_expr, "b", "p");
          break;
          as_warn (_("branch %s is always true"), ip->insn_mo->name);
          macro_build (&offset_expr, "b", "p");
          break;
@@ -10419,7 +10552,7 @@ macro (struct mips_cl_insn *ip, char *str)
              && imm_expr.X_add_number == -1))
        goto do_false;
       ++imm_expr.X_add_number;
              && imm_expr.X_add_number == -1))
        goto do_false;
       ++imm_expr.X_add_number;
-      /* FALLTHROUGH */
+      /* Fall through.  */
     case M_BGEU_I:
     case M_BGEUL_I:
       if (mask == M_BGEUL_I)
     case M_BGEU_I:
     case M_BGEUL_I:
       if (mask == M_BGEUL_I)
@@ -10497,7 +10630,7 @@ macro (struct mips_cl_insn *ip, char *str)
       if (imm_expr.X_add_number >= GPR_SMAX)
        goto do_true;
       ++imm_expr.X_add_number;
       if (imm_expr.X_add_number >= GPR_SMAX)
        goto do_true;
       ++imm_expr.X_add_number;
-      /* FALLTHROUGH */
+      /* Fall through.  */
     case M_BLT_I:
     case M_BLTL_I:
       if (mask == M_BLTL_I)
     case M_BLT_I:
     case M_BLTL_I:
       if (mask == M_BLTL_I)
@@ -10542,7 +10675,7 @@ macro (struct mips_cl_insn *ip, char *str)
              && imm_expr.X_add_number == -1))
        goto do_true;
       ++imm_expr.X_add_number;
              && imm_expr.X_add_number == -1))
        goto do_true;
       ++imm_expr.X_add_number;
-      /* FALLTHROUGH */
+      /* Fall through.  */
     case M_BLTU_I:
     case M_BLTUL_I:
       if (mask == M_BLTUL_I)
     case M_BLTU_I:
     case M_BLTUL_I:
       if (mask == M_BLTUL_I)
@@ -12633,20 +12766,18 @@ macro (struct mips_cl_insn *ip, char *str)
          offset_reloc[2] = BFD_RELOC_UNUSED;
        }
       align = 8;
          offset_reloc[2] = BFD_RELOC_UNUSED;
        }
       align = 8;
-      /* Fall through */
+      /* Fall through */
 
     case M_L_DAB:
 
     case M_L_DAB:
-      /*
-       * The MIPS assembler seems to check for X_add_number not
-       * being double aligned and generating:
-       *       lui     at,%hi(foo+1)
-       *       addu    at,at,v1
-       *       addiu   at,at,%lo(foo+1)
-       *       lwc1    f2,0(at)
-       *       lwc1    f3,4(at)
-       * But, the resulting address is the same after relocation so why
-       * generate the extra instruction?
-       */
+      /* The MIPS assembler seems to check for X_add_number not
+         being double aligned and generating:
+               lui     at,%hi(foo+1)
+               addu    at,at,v1
+               addiu   at,at,%lo(foo+1)
+               lwc1    f2,0(at)
+               lwc1    f3,4(at)
+         But, the resulting address is the same after relocation so why
+         generate the extra instruction?  */
       /* Itbl support may require additional care here.  */
       coproc = 1;
       fmt = "T,o(b)";
       /* Itbl support may require additional care here.  */
       coproc = 1;
       fmt = "T,o(b)";
@@ -13369,7 +13500,7 @@ macro (struct mips_cl_insn *ip, char *str)
       macro_build (&expr1, "xori", "t,r,i", op[0], op[0], BFD_RELOC_LO16);
       break;
 
       macro_build (&expr1, "xori", "t,r,i", op[0], op[0], BFD_RELOC_LO16);
       break;
 
-    case M_SGE_I:      /* X >= I  <==>  not (X < I) */
+    case M_SGE_I:      /* X >= I  <==>  not (X < I) */
     case M_SGEU_I:
       if (imm_expr.X_add_number >= -0x8000
          && imm_expr.X_add_number < 0x8000)
     case M_SGEU_I:
       if (imm_expr.X_add_number >= -0x8000
          && imm_expr.X_add_number < 0x8000)
@@ -13385,7 +13516,7 @@ macro (struct mips_cl_insn *ip, char *str)
       macro_build (&expr1, "xori", "t,r,i", op[0], op[0], BFD_RELOC_LO16);
       break;
 
       macro_build (&expr1, "xori", "t,r,i", op[0], op[0], BFD_RELOC_LO16);
       break;
 
-    case M_SGT:                /* X > Y  <==>  Y < X */
+    case M_SGT:                /* X > Y  <==>  Y < X */
       s = "slt";
       goto sgt;
     case M_SGTU:
       s = "slt";
       goto sgt;
     case M_SGTU:
@@ -13394,7 +13525,7 @@ macro (struct mips_cl_insn *ip, char *str)
       macro_build (NULL, s, "d,v,t", op[0], op[2], op[1]);
       break;
 
       macro_build (NULL, s, "d,v,t", op[0], op[2], op[1]);
       break;
 
-    case M_SGT_I:      /* X > I  <==>  I < X */
+    case M_SGT_I:      /* X > I  <==>  I < X */
       s = "slt";
       goto sgti;
     case M_SGTU_I:
       s = "slt";
       goto sgti;
     case M_SGTU_I:
@@ -13405,7 +13536,7 @@ macro (struct mips_cl_insn *ip, char *str)
       macro_build (NULL, s, "d,v,t", op[0], AT, op[1]);
       break;
 
       macro_build (NULL, s, "d,v,t", op[0], AT, op[1]);
       break;
 
-    case M_SLE:                /* X <= Y  <==>  Y >= X  <==>  not (Y < X) */
+    case M_SLE:                /* X <= Y  <==>  Y >= X  <==>  not (Y < X) */
       s = "slt";
       goto sle;
     case M_SLEU:
       s = "slt";
       goto sle;
     case M_SLEU:
@@ -14731,6 +14862,14 @@ md_parse_option (int c, const char *arg)
       mips_fix_rm7000 = 0;
       break;
 
       mips_fix_rm7000 = 0;
       break;
 
+    case OPTION_FIX_LOONGSON3_LLSC:
+      mips_fix_loongson3_llsc = TRUE;
+      break;
+
+    case OPTION_NO_FIX_LOONGSON3_LLSC:
+      mips_fix_loongson3_llsc = FALSE;
+      break;
+
     case OPTION_FIX_LOONGSON2F_JUMP:
       mips_fix_loongson2f_jump = TRUE;
       break;
     case OPTION_FIX_LOONGSON2F_JUMP:
       mips_fix_loongson2f_jump = TRUE;
       break;
@@ -14999,7 +15138,7 @@ mips_after_parse_args (void)
   const struct mips_cpu_info *arch_info = 0;
   const struct mips_cpu_info *tune_info = 0;
 
   const struct mips_cpu_info *arch_info = 0;
   const struct mips_cpu_info *tune_info = 0;
 
-  /* GP relative stuff not working for PE */
+  /* GP relative stuff not working for PE */
   if (strncmp (TARGET_OS, "pe", 2) == 0)
     {
       if (g_switch_seen && g_switch_value != 0)
   if (strncmp (TARGET_OS, "pe", 2) == 0)
     {
       if (g_switch_seen && g_switch_value != 0)
@@ -15078,7 +15217,7 @@ mips_after_parse_args (void)
 void
 mips_init_after_args (void)
 {
 void
 mips_init_after_args (void)
 {
-  /* initialize opcodes */
+  /* Initialize opcodes.  */
   bfd_mips_num_opcodes = bfd_mips_num_builtin_opcodes;
   mips_opcodes = (struct mips_opcode *) mips_builtin_opcodes;
 }
   bfd_mips_num_opcodes = bfd_mips_num_builtin_opcodes;
   mips_opcodes = (struct mips_opcode *) mips_builtin_opcodes;
 }
@@ -15087,6 +15226,7 @@ long
 md_pcrel_from (fixS *fixP)
 {
   valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
 md_pcrel_from (fixS *fixP)
 {
   valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
+
   switch (fixP->fx_r_type)
     {
     case BFD_RELOC_MICROMIPS_7_PCREL_S1:
   switch (fixP->fx_r_type)
     {
     case BFD_RELOC_MICROMIPS_7_PCREL_S1:
@@ -19703,7 +19843,7 @@ s_mips_mask (int reg_type)
    gcc's mips_cpu_info_table[].  */
 static const struct mips_cpu_info mips_cpu_info_table[] =
 {
    gcc's mips_cpu_info_table[].  */
 static const struct mips_cpu_info mips_cpu_info_table[] =
 {
-  /* Entries for generic ISAs */
+  /* Entries for generic ISAs */
   { "mips1",          MIPS_CPU_IS_ISA, 0,      ISA_MIPS1,    CPU_R3000 },
   { "mips2",          MIPS_CPU_IS_ISA, 0,      ISA_MIPS2,    CPU_R6000 },
   { "mips3",          MIPS_CPU_IS_ISA, 0,      ISA_MIPS3,    CPU_R4000 },
   { "mips1",          MIPS_CPU_IS_ISA, 0,      ISA_MIPS1,    CPU_R3000 },
   { "mips2",          MIPS_CPU_IS_ISA, 0,      ISA_MIPS2,    CPU_R6000 },
   { "mips3",          MIPS_CPU_IS_ISA, 0,      ISA_MIPS3,    CPU_R4000 },
@@ -19742,7 +19882,7 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
   { "orion",          0, 0,                    ISA_MIPS3,    CPU_R4600 },
   { "r4650",          0, 0,                    ISA_MIPS3,    CPU_R4650 },
   { "r5900",          0, 0,                    ISA_MIPS3,    CPU_R5900 },
   { "orion",          0, 0,                    ISA_MIPS3,    CPU_R4600 },
   { "r4650",          0, 0,                    ISA_MIPS3,    CPU_R4650 },
   { "r5900",          0, 0,                    ISA_MIPS3,    CPU_R5900 },
-  /* ST Microelectronics Loongson 2E and 2F cores */
+  /* ST Microelectronics Loongson 2E and 2F cores */
   { "loongson2e",     0, 0,                    ISA_MIPS3,    CPU_LOONGSON_2E },
   { "loongson2f",     0, ASE_LOONGSON_MMI,     ISA_MIPS3,    CPU_LOONGSON_2F },
 
   { "loongson2e",     0, 0,                    ISA_MIPS3,    CPU_LOONGSON_2E },
   { "loongson2f",     0, ASE_LOONGSON_MMI,     ISA_MIPS3,    CPU_LOONGSON_2F },
 
@@ -19821,12 +19961,12 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
   { "1004kf2_1",      0, ASE_DSP | ASE_MT,     ISA_MIPS32R2, CPU_MIPS32R2 },
   { "1004kf",         0, ASE_DSP | ASE_MT,     ISA_MIPS32R2, CPU_MIPS32R2 },
   { "1004kf1_1",      0, ASE_DSP | ASE_MT,     ISA_MIPS32R2, CPU_MIPS32R2 },
   { "1004kf2_1",      0, ASE_DSP | ASE_MT,     ISA_MIPS32R2, CPU_MIPS32R2 },
   { "1004kf",         0, ASE_DSP | ASE_MT,     ISA_MIPS32R2, CPU_MIPS32R2 },
   { "1004kf1_1",      0, ASE_DSP | ASE_MT,     ISA_MIPS32R2, CPU_MIPS32R2 },
-  /* interaptiv is the new name for 1004kf */
+  /* interaptiv is the new name for 1004kf */
   { "interaptiv",     0, ASE_DSP | ASE_MT,     ISA_MIPS32R2, CPU_MIPS32R2 },
   { "interaptiv-mr2", 0,
     ASE_DSP | ASE_EVA | ASE_MT | ASE_MIPS16E2 | ASE_MIPS16E2_MT,
     ISA_MIPS32R3, CPU_INTERAPTIV_MR2 },
   { "interaptiv",     0, ASE_DSP | ASE_MT,     ISA_MIPS32R2, CPU_MIPS32R2 },
   { "interaptiv-mr2", 0,
     ASE_DSP | ASE_EVA | ASE_MT | ASE_MIPS16E2 | ASE_MIPS16E2_MT,
     ISA_MIPS32R3, CPU_INTERAPTIV_MR2 },
-  /* M5100 family */
+  /* M5100 family */
   { "m5100",          0, ASE_MCU,              ISA_MIPS32R5, CPU_MIPS32R5 },
   { "m5101",          0, ASE_MCU,              ISA_MIPS32R5, CPU_MIPS32R5 },
   /* P5600 with EVA and Virtualization ASEs, other ASEs are optional.  */
   { "m5100",          0, ASE_MCU,              ISA_MIPS32R5, CPU_MIPS32R5 },
   { "m5101",          0, ASE_MCU,              ISA_MIPS32R5, CPU_MIPS32R5 },
   /* P5600 with EVA and Virtualization ASEs, other ASEs are optional.  */
@@ -19838,14 +19978,14 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
   { "20kc",           0, ASE_MIPS3D,           ISA_MIPS64,   CPU_MIPS64 },
   { "25kf",           0, ASE_MIPS3D,           ISA_MIPS64,   CPU_MIPS64 },
 
   { "20kc",           0, ASE_MIPS3D,           ISA_MIPS64,   CPU_MIPS64 },
   { "25kf",           0, ASE_MIPS3D,           ISA_MIPS64,   CPU_MIPS64 },
 
-  /* Broadcom SB-1 CPU core */
+  /* Broadcom SB-1 CPU core */
   { "sb1",            0, ASE_MIPS3D | ASE_MDMX,        ISA_MIPS64,   CPU_SB1 },
   { "sb1",            0, ASE_MIPS3D | ASE_MDMX,        ISA_MIPS64,   CPU_SB1 },
-  /* Broadcom SB-1A CPU core */
+  /* Broadcom SB-1A CPU core */
   { "sb1a",           0, ASE_MIPS3D | ASE_MDMX,        ISA_MIPS64,   CPU_SB1 },
 
   { "sb1a",           0, ASE_MIPS3D | ASE_MDMX,        ISA_MIPS64,   CPU_SB1 },
 
-  /* MIPS 64 Release 2 */
-  /* Loongson CPU core */
-  /* -march=loongson3a is an alias of -march=gs464 for compatibility */
+  /* MIPS 64 Release 2 */
+  /* Loongson CPU core */
+  /* -march=loongson3a is an alias of -march=gs464 for compatibility */
   { "loongson3a",     0, ASE_LOONGSON_MMI | ASE_LOONGSON_CAM | ASE_LOONGSON_EXT,
      ISA_MIPS64R2,     CPU_GS464 },
   { "gs464",          0, ASE_LOONGSON_MMI | ASE_LOONGSON_CAM | ASE_LOONGSON_EXT,
   { "loongson3a",     0, ASE_LOONGSON_MMI | ASE_LOONGSON_CAM | ASE_LOONGSON_EXT,
      ISA_MIPS64R2,     CPU_GS464 },
   { "gs464",          0, ASE_LOONGSON_MMI | ASE_LOONGSON_CAM | ASE_LOONGSON_EXT,
@@ -19855,7 +19995,7 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
   { "gs264e",         0, ASE_LOONGSON_MMI | ASE_LOONGSON_CAM | ASE_LOONGSON_EXT
      | ASE_LOONGSON_EXT2 | ASE_MSA | ASE_MSA64,        ISA_MIPS64R2,   CPU_GS264E },
 
   { "gs264e",         0, ASE_LOONGSON_MMI | ASE_LOONGSON_CAM | ASE_LOONGSON_EXT
      | ASE_LOONGSON_EXT2 | ASE_MSA | ASE_MSA64,        ISA_MIPS64R2,   CPU_GS264E },
 
-  /* Cavium Networks Octeon CPU core */
+  /* Cavium Networks Octeon CPU core */
   { "octeon",        0, 0,                     ISA_MIPS64R2, CPU_OCTEON },
   { "octeon+",       0, 0,                     ISA_MIPS64R2, CPU_OCTEONP },
   { "octeon2",       0, 0,                     ISA_MIPS64R2, CPU_OCTEON2 },
   { "octeon",        0, 0,                     ISA_MIPS64R2, CPU_OCTEON },
   { "octeon+",       0, 0,                     ISA_MIPS64R2, CPU_OCTEONP },
   { "octeon2",       0, 0,                     ISA_MIPS64R2, CPU_OCTEON2 },
@@ -19869,11 +20009,11 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
      MIPS64R2 rather than MIPS64.  */
   { "xlp",           0, 0,                     ISA_MIPS64R2, CPU_XLR },
 
      MIPS64R2 rather than MIPS64.  */
   { "xlp",           0, 0,                     ISA_MIPS64R2, CPU_XLR },
 
-  /* MIPS 64 Release 6 */
+  /* MIPS 64 Release 6 */
   { "i6400",         0, ASE_MSA,               ISA_MIPS64R6, CPU_MIPS64R6},
   { "p6600",         0, ASE_VIRT | ASE_MSA,    ISA_MIPS64R6, CPU_MIPS64R6},
 
   { "i6400",         0, ASE_MSA,               ISA_MIPS64R6, CPU_MIPS64R6},
   { "p6600",         0, ASE_VIRT | ASE_MSA,    ISA_MIPS64R6, CPU_MIPS64R6},
 
-  /* End marker */
+  /* End marker */
   { NULL, 0, 0, 0, 0 }
 };
 
   { NULL, 0, 0, 0, 0 }
 };
 
@@ -20140,9 +20280,20 @@ MIPS options:\n\
   fprintf (stream, _("\
 -minsn32               only generate 32-bit microMIPS instructions\n\
 -mno-insn32            generate all microMIPS instructions\n"));
   fprintf (stream, _("\
 -minsn32               only generate 32-bit microMIPS instructions\n\
 -mno-insn32            generate all microMIPS instructions\n"));
+#if DEFAULT_MIPS_FIX_LOONGSON3_LLSC
+  fprintf (stream, _("\
+-mfix-loongson3-llsc   work around Loongson3 LL/SC errata, default\n\
+-mno-fix-loongson3-llsc        disable work around Loongson3 LL/SC errata\n"));
+#else
+  fprintf (stream, _("\
+-mfix-loongson3-llsc   work around Loongson3 LL/SC errata\n\
+-mno-fix-loongson3-llsc        disable work around Loongson3 LL/SC errata, default\n"));
+#endif
   fprintf (stream, _("\
 -mfix-loongson2f-jump  work around Loongson2F JUMP instructions\n\
 -mfix-loongson2f-nop   work around Loongson2F NOP errata\n\
   fprintf (stream, _("\
 -mfix-loongson2f-jump  work around Loongson2F JUMP instructions\n\
 -mfix-loongson2f-nop   work around Loongson2F NOP errata\n\
+-mfix-loongson3-llsc   work around Loongson3 LL/SC errata\n\
+-mno-fix-loongson3-llsc        disable work around Loongson3 LL/SC errata\n\
 -mfix-vr4120           work around certain VR4120 errata\n\
 -mfix-vr4130           work around VR4130 mflo/mfhi errata\n\
 -mfix-24k              insert a nop after ERET and DERET instructions\n\
 -mfix-vr4120           work around certain VR4120 errata\n\
 -mfix-vr4130           work around VR4130 mflo/mfhi errata\n\
 -mfix-24k              insert a nop after ERET and DERET instructions\n\
index 6f3307b46226a7d5d0dca8f068b6998a8100e0e6..1aafa6b31d7c8227c55d53db3974ad9b7e153343 100755 (executable)
@@ -808,6 +808,7 @@ enable_compressed_debug_sections
 enable_x86_relax_relocations
 enable_elf_stt_common
 enable_generate_build_notes
 enable_x86_relax_relocations
 enable_elf_stt_common
 enable_generate_build_notes
+enable_mips_fix_loongson3_llsc
 enable_x86_used_note
 enable_default_riscv_attribute
 enable_werror
 enable_x86_used_note
 enable_default_riscv_attribute
 enable_werror
@@ -1471,6 +1472,8 @@ Optional Features:
   --enable-generate-build-notes
                           generate GNU Build notes if none are provided by the
                           input
   --enable-generate-build-notes
                           generate GNU Build notes if none are provided by the
                           input
+  --enable-mips-fix-loongson3-llsc
+                          enable MIPS fix Loongson3 LLSC errata
   --enable-x86-used-note  generate GNU x86 used ISA and feature properties
   --enable-default-riscv-attribute
                           generate RISC-V arch attribute by default
   --enable-x86-used-note  generate GNU x86 used ISA and feature properties
   --enable-default-riscv-attribute
                           generate RISC-V arch attribute by default
@@ -11340,7 +11343,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11343 "configure"
+#line 11346 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11446,7 +11449,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11449 "configure"
+#line 11452 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12114,6 +12117,17 @@ if test "${enable_generate_build_notes+set}" = set; then :
 esac
 fi
 
 esac
 fi
 
+# Decide if the MIPS assembler should default to enable MIPS fix Loongson3
+# LLSC errata.
+ac_default_mips_fix_loongson3_llsc=unset
+# Provide a configuration option to override the default.
+# Check whether --enable-mips-fix-loongson3-llsc was given.
+if test "${enable_mips_fix_loongson3_llsc+set}" = set; then :
+  enableval=$enable_mips_fix_loongson3_llsc; case "${enableval}" in
+  yes)  ac_default_mips_fix_loongson3_llsc=1 ;;
+  no)   ac_default_mips_fix_loongson3_llsc=0 ;;
+esac
+fi
 
 # Decide if the x86 ELF assembler should default to generating GNU x86
 # used ISA and feature properties.
 
 # Decide if the x86 ELF assembler should default to generating GNU x86
 # used ISA and feature properties.
@@ -13131,6 +13145,15 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
 _ACEOF
 
 
+if test ${ac_default_mips_fix_loongson3_llsc} = unset; then
+  ac_default_mips_fix_loongson3_llsc=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_MIPS_FIX_LOONGSON3_LLSC $ac_default_mips_fix_loongson3_llsc
+_ACEOF
+
+
 if test x$ac_default_compressed_debug_sections = xyes ; then
 
 $as_echo "#define DEFAULT_FLAG_COMPRESS_DEBUG 1" >>confdefs.h
 if test x$ac_default_compressed_debug_sections = xyes ; then
 
 $as_echo "#define DEFAULT_FLAG_COMPRESS_DEBUG 1" >>confdefs.h
index cc4bae0957253c1a57f11da0c969855c68b5d86b..4b25b7ca36026b87724c97afb0d86e3d2f9807bd 100644 (file)
@@ -111,6 +111,17 @@ AC_ARG_ENABLE(generate_build_notes,
   no)   ac_default_generate_build_notes=0 ;;
 esac])dnl
 
   no)   ac_default_generate_build_notes=0 ;;
 esac])dnl
 
+# Decide if the MIPS assembler should default to enable MIPS fix Loongson3
+# LLSC errata.
+ac_default_mips_fix_loongson3_llsc=unset
+# Provide a configuration option to override the default.
+AC_ARG_ENABLE(mips-fix-loongson3-llsc,
+             AS_HELP_STRING([--enable-mips-fix-loongson3-llsc],
+             [enable MIPS fix Loongson3 LLSC errata]),
+[case "${enableval}" in
+  yes)  ac_default_mips_fix_loongson3_llsc=1 ;;
+  no)   ac_default_mips_fix_loongson3_llsc=0 ;;
+esac])dnl
 
 # Decide if the x86 ELF assembler should default to generating GNU x86
 # used ISA and feature properties.
 
 # Decide if the x86 ELF assembler should default to generating GNU x86
 # used ISA and feature properties.
@@ -687,6 +698,13 @@ AC_DEFINE_UNQUOTED(DEFAULT_RISCV_ATTR,
   $ac_default_generate_riscv_attr,
   [Define to 1 if you want to generate RISC-V arch attribute by default.])
 
   $ac_default_generate_riscv_attr,
   [Define to 1 if you want to generate RISC-V arch attribute by default.])
 
+if test ${ac_default_mips_fix_loongson3_llsc} = unset; then
+  ac_default_mips_fix_loongson3_llsc=0
+fi
+AC_DEFINE_UNQUOTED(DEFAULT_MIPS_FIX_LOONGSON3_LLSC,
+  $ac_default_mips_fix_loongson3_llsc,
+  [Define to 1 if you want to fix Loongson3 LLSC Errata by default.])
+
 if test x$ac_default_compressed_debug_sections = xyes ; then
   AC_DEFINE(DEFAULT_FLAG_COMPRESS_DEBUG, 1, [Define if you want compressed debug sections by default.])
 fi
 if test x$ac_default_compressed_debug_sections = xyes ; then
   AC_DEFINE(DEFAULT_FLAG_COMPRESS_DEBUG, 1, [Define if you want compressed debug sections by default.])
 fi
index 812280301142592fda290d2b6a09c80493d2296a..1ef289a0f4974919a4a98a4953885004f6f5369d 100644 (file)
@@ -308,6 +308,13 @@ Replace nops by @code{or at,at,zero} to work around the Loongson2F
 deadlock.  The issue has been solved in later Loongson2F batches, but
 this fix has no side effect to them.
 
 deadlock.  The issue has been solved in later Loongson2F batches, but
 this fix has no side effect to them.
 
+@item -mfix-loongson3-llsc
+@itemx -mno-fix-loongson3-llsc
+Insert @samp{sync} before @samp{ll} and @samp{lld} to work around
+Loongson3 LLSC errata.  Without it, under extrame cases, the CPU might
+deadlock. The default can be controlled by the
+@option{--enable-mips-fix-loongson3-llsc=[yes|no]} configure option.
+
 @item -mfix-vr4120
 @itemx -mno-fix-vr4120
 Insert nops to work around certain VR4120 errata.  This option is
 @item -mfix-vr4120
 @itemx -mno-fix-vr4120
 Insert nops to work around certain VR4120 errata.  This option is
This page took 0.044819 seconds and 4 git commands to generate.