From 6f2117ba3892110badc65a7126b19cec211acfa2 Mon Sep 17 00:00:00 2001 From: Paul Hua Date: Tue, 19 Feb 2019 17:57:16 +0000 Subject: [PATCH] Fix a potential deadlock in some older Loongson 3A1000 MIPS processors. * 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 | 21 ++++ gas/NEWS | 5 + gas/config.in | 3 + gas/config/tc-mips.c | 261 ++++++++++++++++++++++++++++++++++--------- gas/configure | 27 ++++- gas/configure.ac | 18 +++ gas/doc/c-mips.texi | 7 ++ 7 files changed, 285 insertions(+), 57 deletions(-) diff --git a/gas/ChangeLog b/gas/ChangeLog index 04ad383e89d..2a4f1948144 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,24 @@ +2019-02-19 Paul Hua + + * 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 PR gas/24165 diff --git a/gas/NEWS b/gas/NEWS index 3eecf71a5fb..3903c383c19 100644 --- a/gas/NEWS +++ b/gas/NEWS @@ -1,5 +1,10 @@ -*- 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 diff --git a/gas/config.in b/gas/config.in index 88b215873bd..8724eb153ae 100644 --- a/gas/config.in +++ b/gas/config.in @@ -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 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 diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index ae559042294..81b729a295d 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -141,6 +141,12 @@ struct mips_cl_insn 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; @@ -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 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) @@ -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); -/* 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. */ @@ -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 - 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' - .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. */ @@ -685,22 +691,22 @@ const char line_comment_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"; -/* 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, - but nothing is ideal around here. - */ + but nothing is ideal around here. */ /* 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, @@ -708,7 +714,8 @@ enum mips_insn_error_format { /* 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 @@ -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; - union { + union + { 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 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. */ -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 -struct mips_operand_array { +struct mips_operand_array +{ 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; +/* 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 \ @@ -943,6 +958,9 @@ static bfd_boolean mips_fix_cn63xxp1; 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 @@ -1482,6 +1500,8 @@ enum options 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, @@ -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}, + {"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}, @@ -2774,7 +2796,7 @@ struct regname { {"$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}, \ @@ -2809,8 +2831,8 @@ struct regname { {"$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}, \ @@ -3671,6 +3693,7 @@ md_begin (void) 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); @@ -3678,6 +3701,10 @@ md_begin (void) 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)); @@ -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 - 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; @@ -6859,6 +6886,103 @@ fix_loongson2f (struct mips_cl_insn * 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. @@ -7316,6 +7440,15 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, 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; @@ -10361,7 +10494,7 @@ macro (struct mips_cl_insn *ip, char *str) break; } ++imm_expr.X_add_number; - /* FALLTHROUGH */ + /* Fall through. */ 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: - /* 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; @@ -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; - /* FALLTHROUGH */ + /* Fall through. */ 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; - /* FALLTHROUGH */ + /* Fall through. */ 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; - /* FALLTHROUGH */ + /* Fall through. */ 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; - /* Fall through */ + /* Fall through. */ 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)"; @@ -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; - 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) @@ -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; - case M_SGT: /* X > Y <==> Y < X */ + case M_SGT: /* X > Y <==> Y < X. */ 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; - case M_SGT_I: /* X > I <==> I < X */ + case M_SGT_I: /* X > I <==> I < X. */ 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; - 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: @@ -14731,6 +14862,14 @@ md_parse_option (int c, const char *arg) 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; @@ -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; - /* 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) @@ -15078,7 +15217,7 @@ mips_after_parse_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; } @@ -15087,6 +15226,7 @@ long 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: @@ -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[] = { - /* 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 }, @@ -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 }, - /* 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 }, @@ -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 }, - /* 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 }, - /* 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. */ @@ -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 }, - /* Broadcom SB-1 CPU core */ + /* Broadcom SB-1 CPU core. */ { "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 }, - /* 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, @@ -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 }, - /* 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 }, @@ -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 }, - /* 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}, - /* End marker */ + /* End marker. */ { 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")); +#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\ +-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\ diff --git a/gas/configure b/gas/configure index 6f3307b4622..1aafa6b31d7 100755 --- a/gas/configure +++ b/gas/configure @@ -808,6 +808,7 @@ enable_compressed_debug_sections 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 @@ -1471,6 +1472,8 @@ Optional Features: --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 @@ -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 -#line 11343 "configure" +#line 11346 "configure" #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 -#line 11449 "configure" +#line 11452 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -12114,6 +12117,17 @@ if test "${enable_generate_build_notes+set}" = set; then : 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. @@ -13131,6 +13145,15 @@ cat >>confdefs.h <<_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 diff --git a/gas/configure.ac b/gas/configure.ac index cc4bae09572..4b25b7ca360 100644 --- a/gas/configure.ac +++ b/gas/configure.ac @@ -111,6 +111,17 @@ AC_ARG_ENABLE(generate_build_notes, 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. @@ -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.]) +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 diff --git a/gas/doc/c-mips.texi b/gas/doc/c-mips.texi index 81228030114..1ef289a0f49 100644 --- a/gas/doc/c-mips.texi +++ b/gas/doc/c-mips.texi @@ -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. +@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 -- 2.30.2