forked from Imagelibrary/binutils-gdb
bfd/
* elfxx-mips.h (_bfd_mips_elf_insn32): New prototype. * elfxx-mips.c (mips_elf_link_hash_table): Add insn32 member. (STUB_MOVE32_MICROMIPS, STUB_JALR32_MICROMIPS): New macros. (MICROMIPS_INSN32_FUNCTION_STUB_NORMAL_SIZE): Likewise. (MICROMIPS_INSN32_FUNCTION_STUB_BIG_SIZE): Likewise. (micromips_insn32_o32_exec_plt0_entry): New variable. (micromips_insn32_o32_exec_plt_entry): Likewise. (_bfd_mips_elf_adjust_dynamic_symbol): Handle insn32 mode. (mips_elf_estimate_stub_size): Likewise. (_bfd_mips_elf_size_dynamic_sections): Likewise. (_bfd_mips_elf_finish_dynamic_symbol): Likewise. (mips_finish_exec_plt): Likewise. (_bfd_mips_elf_relax_section): Likewise. (_bfd_mips_elf_insn32): New function. (_bfd_mips_elf_get_synthetic_symtab): Handle insn32 PLT. gas/ * config/tc-mips.c (mips_set_options): Add insn32 member. (mips_opts): Initialize it. (NOP_INSN, NOP_INSN_SIZE): Handle insn32 mode. (options): Add OPTION_INSN32 and OPTION_NO_INSN32 enum values. (md_longopts): Add "minsn32" and "mno-insn32" options. (is_size_valid): Handle insn32 mode. (md_assemble): Pass instruction string down to macro. (brk_fmt): Add second dimension and insn32 mode initializers. (mfhl_fmt): Likewise. (BRK_FMT, MFHL_FMT): Handle insn32 mode. (macro_build) <'c'>: Handle microMIPS 32-bit BREAK encoding. (macro_build_jalr, move_register): Handle insn32 mode. (macro_build_branch_rs): Likewise. (macro): Handle insn32 mode. <M_JRADDIUSP>, <M_JRC>, <M_MOVEP>: New cases. (mips_ip): Handle insn32 mode. (md_parse_option): Handle OPTION_INSN32 and OPTION_NO_INSN32. (s_mipsset): Handle "insn32" and "noinsn32" pseudo-ops. (mips_handle_align): Handle insn32 mode. (md_show_usage): Add -minsn32 and -mno-insn32. * doc/as.texinfo (Target MIPS options): Add -minsn32 and -mno-insn32 options. (-minsn32, -mno-insn32): New options. * doc/c-mips.texi (MIPS Opts): Add -minsn32 and -mno-insn32 options. (MIPS assembly options): New node. Document .set insn32 and .set noinsn32. (MIPS-Dependent): List the new node. gas/testsuite/ * gas/mips/micromips-insn32.d: New test. * gas/mips/micromips-noinsn32.d: Likewise. * gas/mips/micromips.l: Rename to... * gas/mips/micromips-warn.l: ... this. * gas/mips/micromips.d: Update accordingly. * gas/mips/micromips-trap.d: Likewise. * gas/mips/micromips.l: New list test. * gas/mips/micromips.s: Add conditionals. * gas/mips/mips.exp: Run the new tests. include/opcode/ * mips.h: Add M_JRADDIUSP, M_JRC and M_MOVEP anonymous enum values. ld/ * emultempl/mipself.em (insn32): New variable. (mips_create_output_section_statements): Handle insn32 mode. (PARSE_AND_LIST_PROLOGUE): New macro. (PARSE_AND_LIST_LONGOPTS): Likewise. (PARSE_AND_LIST_OPTIONS): Likewise. * gen-doc.texi: Set MIPS. * ld.texinfo: Likewise. (Options specific to MIPS targets): New section. (ld and MIPS family): New node. (Top, Machine Dependent): List the new node. opcodes/ * micromips-opc.c (micromips_opcodes): Add "jraddiusp", "jrc" and "movep" macros.
This commit is contained in:
@@ -231,6 +231,10 @@ struct mips_set_options
|
||||
/* Non-zero if we should not autoextend mips16 instructions.
|
||||
Changed by `.set autoextend' and `.set noautoextend'. */
|
||||
int noautoextend;
|
||||
/* True if we should only emit 32-bit microMIPS instructions.
|
||||
Changed by `.set insn32' and `.set noinsn32', and the -minsn32
|
||||
and -mno-insn32 command line options. */
|
||||
bfd_boolean insn32;
|
||||
/* Restrict general purpose registers and floating point registers
|
||||
to 32 bit. This is initially determined when -mgp32 or -mfp32
|
||||
is passed but can changed if the assembler code uses .set mipsN. */
|
||||
@@ -272,8 +276,8 @@ static struct mips_set_options mips_opts =
|
||||
{
|
||||
/* isa */ ISA_UNKNOWN, /* ase */ 0, /* mips16 */ -1, /* micromips */ -1,
|
||||
/* noreorder */ 0, /* at */ ATREG, /* warn_about_macros */ 0,
|
||||
/* nomove */ 0, /* nobopt */ 0, /* noautoextend */ 0, /* gp32 */ 0,
|
||||
/* fp32 */ 0, /* arch */ CPU_UNKNOWN, /* sym32 */ FALSE,
|
||||
/* nomove */ 0, /* nobopt */ 0, /* noautoextend */ 0, /* insn32 */ FALSE,
|
||||
/* gp32 */ 0, /* fp32 */ 0, /* arch */ CPU_UNKNOWN, /* sym32 */ FALSE,
|
||||
/* soft_float */ FALSE, /* single_float */ FALSE
|
||||
};
|
||||
|
||||
@@ -686,11 +690,18 @@ static struct mips_cl_insn micromips_nop16_insn;
|
||||
static struct mips_cl_insn micromips_nop32_insn;
|
||||
|
||||
/* The appropriate nop for the current mode. */
|
||||
#define NOP_INSN (mips_opts.mips16 ? &mips16_nop_insn \
|
||||
: (mips_opts.micromips ? µmips_nop16_insn : &nop_insn))
|
||||
#define NOP_INSN (mips_opts.mips16 \
|
||||
? &mips16_nop_insn \
|
||||
: (mips_opts.micromips \
|
||||
? (mips_opts.insn32 \
|
||||
? µmips_nop32_insn \
|
||||
: µmips_nop16_insn) \
|
||||
: &nop_insn))
|
||||
|
||||
/* The size of NOP_INSN in bytes. */
|
||||
#define NOP_INSN_SIZE (HAVE_CODE_COMPRESSION ? 2 : 4)
|
||||
#define NOP_INSN_SIZE ((mips_opts.mips16 \
|
||||
|| (mips_opts.micromips && !mips_opts.insn32)) \
|
||||
? 2 : 4)
|
||||
|
||||
/* If this is set, it points to a frag holding nop instructions which
|
||||
were inserted before the start of a noreorder section. If those
|
||||
@@ -1276,7 +1287,7 @@ static void mips16_macro_build
|
||||
static void load_register (int, expressionS *, int);
|
||||
static void macro_start (void);
|
||||
static void macro_end (void);
|
||||
static void macro (struct mips_cl_insn * ip);
|
||||
static void macro (struct mips_cl_insn *ip, char *str);
|
||||
static void mips16_macro (struct mips_cl_insn * ip);
|
||||
static void mips_ip (char *str, struct mips_cl_insn * ip);
|
||||
static void mips16_ip (char *str, struct mips_cl_insn * ip);
|
||||
@@ -1418,6 +1429,8 @@ enum options
|
||||
OPTION_GP64,
|
||||
OPTION_RELAX_BRANCH,
|
||||
OPTION_NO_RELAX_BRANCH,
|
||||
OPTION_INSN32,
|
||||
OPTION_NO_INSN32,
|
||||
OPTION_MSHARED,
|
||||
OPTION_MNO_SHARED,
|
||||
OPTION_MSYM32,
|
||||
@@ -1524,6 +1537,8 @@ struct option md_longopts[] =
|
||||
{"mgp64", no_argument, NULL, OPTION_GP64},
|
||||
{"relax-branch", no_argument, NULL, OPTION_RELAX_BRANCH},
|
||||
{"no-relax-branch", no_argument, NULL, OPTION_NO_RELAX_BRANCH},
|
||||
{"minsn32", no_argument, NULL, OPTION_INSN32},
|
||||
{"mno-insn32", no_argument, NULL, OPTION_NO_INSN32},
|
||||
{"mshared", no_argument, NULL, OPTION_MSHARED},
|
||||
{"mno-shared", no_argument, NULL, OPTION_MNO_SHARED},
|
||||
{"msym32", no_argument, NULL, OPTION_MSYM32},
|
||||
@@ -2636,6 +2651,13 @@ is_size_valid (const struct mips_opcode *mo)
|
||||
if (!mips_opts.micromips)
|
||||
return TRUE;
|
||||
|
||||
if (mips_opts.insn32)
|
||||
{
|
||||
if (mo->pinfo != INSN_MACRO && micromips_insn_length (mo) != 4)
|
||||
return FALSE;
|
||||
if ((mo->pinfo2 & INSN2_BRANCH_DELAY_16BIT) != 0)
|
||||
return FALSE;
|
||||
}
|
||||
if (!forced_insn_length)
|
||||
return TRUE;
|
||||
if (mo->pinfo == INSN_MACRO)
|
||||
@@ -2966,7 +2988,7 @@ md_assemble (char *str)
|
||||
if (mips_opts.mips16)
|
||||
mips16_macro (&insn);
|
||||
else
|
||||
macro (&insn);
|
||||
macro (&insn, str);
|
||||
macro_end ();
|
||||
}
|
||||
else
|
||||
@@ -5209,21 +5231,21 @@ macro_end (void)
|
||||
/* Instruction operand formats used in macros that vary between
|
||||
standard MIPS and microMIPS code. */
|
||||
|
||||
static const char * const brk_fmt[2] = { "c", "mF" };
|
||||
static const char * const brk_fmt[2][2] = { { "c", "c" }, { "mF", "c" } };
|
||||
static const char * const cop12_fmt[2] = { "E,o(b)", "E,~(b)" };
|
||||
static const char * const jalr_fmt[2] = { "d,s", "t,s" };
|
||||
static const char * const lui_fmt[2] = { "t,u", "s,u" };
|
||||
static const char * const mem12_fmt[2] = { "t,o(b)", "t,~(b)" };
|
||||
static const char * const mfhl_fmt[2] = { "d", "mj" };
|
||||
static const char * const mfhl_fmt[2][2] = { { "d", "d" }, { "mj", "s" } };
|
||||
static const char * const shft_fmt[2] = { "d,w,<", "t,r,<" };
|
||||
static const char * const trap_fmt[2] = { "s,t,q", "s,t,|" };
|
||||
|
||||
#define BRK_FMT (brk_fmt[mips_opts.micromips])
|
||||
#define BRK_FMT (brk_fmt[mips_opts.micromips][mips_opts.insn32])
|
||||
#define COP12_FMT (cop12_fmt[mips_opts.micromips])
|
||||
#define JALR_FMT (jalr_fmt[mips_opts.micromips])
|
||||
#define LUI_FMT (lui_fmt[mips_opts.micromips])
|
||||
#define MEM12_FMT (mem12_fmt[mips_opts.micromips])
|
||||
#define MFHL_FMT (mfhl_fmt[mips_opts.micromips])
|
||||
#define MFHL_FMT (mfhl_fmt[mips_opts.micromips][mips_opts.insn32])
|
||||
#define SHFT_FMT (shft_fmt[mips_opts.micromips])
|
||||
#define TRAP_FMT (trap_fmt[mips_opts.micromips])
|
||||
|
||||
@@ -5382,8 +5404,7 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
|
||||
continue;
|
||||
|
||||
case 'c':
|
||||
gas_assert (!mips_opts.micromips);
|
||||
INSERT_OPERAND (0, CODE, insn, va_arg (args, int));
|
||||
INSERT_OPERAND (mips_opts.micromips, CODE, insn, va_arg (args, int));
|
||||
continue;
|
||||
|
||||
case 'W':
|
||||
@@ -5750,8 +5771,10 @@ macro_build_jalr (expressionS *ep, int cprestore)
|
||||
}
|
||||
if (mips_opts.micromips)
|
||||
{
|
||||
jalr = mips_opts.noreorder && !cprestore ? "jalr" : "jalrs";
|
||||
jalr = ((mips_opts.noreorder && !cprestore) || mips_opts.insn32
|
||||
? "jalr" : "jalrs");
|
||||
if (MIPS_JALR_HINT_P (ep)
|
||||
|| mips_opts.insn32
|
||||
|| (history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
|
||||
macro_build (NULL, jalr, "t,s", RA, PIC_CALL_REG);
|
||||
else
|
||||
@@ -6432,6 +6455,7 @@ move_register (int dest, int source)
|
||||
/* Prefer to use a 16-bit microMIPS instruction unless the previous
|
||||
instruction specifically requires a 32-bit one. */
|
||||
if (mips_opts.micromips
|
||||
&& !mips_opts.insn32
|
||||
&& !(history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
|
||||
macro_build (NULL, "move", "mp,mj", dest, source);
|
||||
else
|
||||
@@ -6628,7 +6652,7 @@ macro_build_branch_rs (int type, expressionS *ep, unsigned int sreg)
|
||||
break;
|
||||
case M_BGEZALL:
|
||||
gas_assert (mips_opts.micromips);
|
||||
br = "bgezals";
|
||||
br = mips_opts.insn32 ? "bgezal" : "bgezals";
|
||||
brneg = "bltz";
|
||||
call = 1;
|
||||
break;
|
||||
@@ -6655,7 +6679,7 @@ macro_build_branch_rs (int type, expressionS *ep, unsigned int sreg)
|
||||
break;
|
||||
case M_BLTZALL:
|
||||
gas_assert (mips_opts.micromips);
|
||||
br = "bltzals";
|
||||
br = mips_opts.insn32 ? "bltzal" : "bltzals";
|
||||
brneg = "bgez";
|
||||
call = 1;
|
||||
break;
|
||||
@@ -6727,7 +6751,7 @@ macro_build_branch_rsrt (int type, expressionS *ep,
|
||||
* we're missing.
|
||||
*/
|
||||
static void
|
||||
macro (struct mips_cl_insn *ip)
|
||||
macro (struct mips_cl_insn *ip, char *str)
|
||||
{
|
||||
unsigned int treg, sreg, dreg, breg;
|
||||
unsigned int tempreg;
|
||||
@@ -8149,6 +8173,11 @@ macro (struct mips_cl_insn *ip)
|
||||
/* Fall through. */
|
||||
case M_JALS_2:
|
||||
gas_assert (mips_opts.micromips);
|
||||
if (mips_opts.insn32)
|
||||
{
|
||||
as_bad (_("Opcode not supported in the `insn32' mode `%s'"), str);
|
||||
break;
|
||||
}
|
||||
jals = 1;
|
||||
goto jal;
|
||||
case M_JAL_1:
|
||||
@@ -8160,6 +8189,7 @@ macro (struct mips_cl_insn *ip)
|
||||
{
|
||||
s = jals ? "jalrs" : "jalr";
|
||||
if (mips_opts.micromips
|
||||
&& !mips_opts.insn32
|
||||
&& dreg == RA
|
||||
&& !(history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
|
||||
macro_build (NULL, s, "mj", sreg);
|
||||
@@ -8174,9 +8204,12 @@ macro (struct mips_cl_insn *ip)
|
||||
if (sreg != PIC_CALL_REG)
|
||||
as_warn (_("MIPS PIC call to register other than $25"));
|
||||
|
||||
s = (mips_opts.micromips && (!mips_opts.noreorder || cprestore)
|
||||
s = ((mips_opts.micromips
|
||||
&& !mips_opts.insn32
|
||||
&& (!mips_opts.noreorder || cprestore))
|
||||
? "jalrs" : "jalr");
|
||||
if (mips_opts.micromips
|
||||
&& !mips_opts.insn32
|
||||
&& dreg == RA
|
||||
&& !(history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
|
||||
macro_build (NULL, s, "mj", sreg);
|
||||
@@ -8215,6 +8248,11 @@ macro (struct mips_cl_insn *ip)
|
||||
|
||||
case M_JALS_A:
|
||||
gas_assert (mips_opts.micromips);
|
||||
if (mips_opts.insn32)
|
||||
{
|
||||
as_bad (_("Opcode not supported in the `insn32' mode `%s'"), str);
|
||||
break;
|
||||
}
|
||||
jals = 1;
|
||||
/* Fall through. */
|
||||
case M_JAL_A:
|
||||
@@ -9227,6 +9265,24 @@ macro (struct mips_cl_insn *ip)
|
||||
|
||||
break;
|
||||
|
||||
case M_JRADDIUSP:
|
||||
gas_assert (mips_opts.micromips);
|
||||
gas_assert (mips_opts.insn32);
|
||||
start_noreorder ();
|
||||
macro_build (NULL, "jr", "s", RA);
|
||||
expr1.X_add_number = EXTRACT_OPERAND (1, IMMP, *ip) << 2;
|
||||
macro_build (&expr1, "addiu", "t,r,j", SP, SP, BFD_RELOC_LO16);
|
||||
end_noreorder ();
|
||||
break;
|
||||
|
||||
case M_JRC:
|
||||
gas_assert (mips_opts.micromips);
|
||||
gas_assert (mips_opts.insn32);
|
||||
macro_build (NULL, "jr", "s", sreg);
|
||||
if (mips_opts.noreorder)
|
||||
macro_build (NULL, "nop", "");
|
||||
break;
|
||||
|
||||
case M_LI:
|
||||
case M_LI_S:
|
||||
load_register (treg, &imm_expr, 0);
|
||||
@@ -9784,6 +9840,17 @@ macro (struct mips_cl_insn *ip)
|
||||
move_register (dreg, sreg);
|
||||
break;
|
||||
|
||||
case M_MOVEP:
|
||||
gas_assert (mips_opts.micromips);
|
||||
gas_assert (mips_opts.insn32);
|
||||
dreg = micromips_to_32_reg_h_map[EXTRACT_OPERAND (1, MH, *ip)];
|
||||
breg = micromips_to_32_reg_i_map[EXTRACT_OPERAND (1, MI, *ip)];
|
||||
sreg = micromips_to_32_reg_m_map[EXTRACT_OPERAND (1, MM, *ip)];
|
||||
treg = micromips_to_32_reg_n_map[EXTRACT_OPERAND (1, MN, *ip)];
|
||||
move_register (dreg, sreg);
|
||||
move_register (breg, treg);
|
||||
break;
|
||||
|
||||
case M_DMUL:
|
||||
dbl = 1;
|
||||
case M_MUL:
|
||||
@@ -11343,6 +11410,8 @@ mips_ip (char *str, struct mips_cl_insn *ip)
|
||||
sprintf (buf, _("Opcode not supported on this processor: %s (%s)"),
|
||||
mips_cpu_info_from_arch (mips_opts.arch)->name,
|
||||
mips_cpu_info_from_isa (mips_opts.isa)->name);
|
||||
else if (mips_opts.insn32)
|
||||
sprintf (buf, _("Opcode not supported in the `insn32' mode"));
|
||||
else
|
||||
sprintf (buf, _("Unrecognized %u-bit version of microMIPS opcode"),
|
||||
8 * forced_insn_length);
|
||||
@@ -15135,6 +15204,14 @@ md_parse_option (int c, char *arg)
|
||||
mips_relax_branch = 0;
|
||||
break;
|
||||
|
||||
case OPTION_INSN32:
|
||||
mips_opts.insn32 = TRUE;
|
||||
break;
|
||||
|
||||
case OPTION_NO_INSN32:
|
||||
mips_opts.insn32 = FALSE;
|
||||
break;
|
||||
|
||||
case OPTION_MSHARED:
|
||||
mips_in_shared = TRUE;
|
||||
break;
|
||||
@@ -16547,6 +16624,10 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
|
||||
mips_opts.noautoextend = 0;
|
||||
else if (strcmp (name, "noautoextend") == 0)
|
||||
mips_opts.noautoextend = 1;
|
||||
else if (strcmp (name, "insn32") == 0)
|
||||
mips_opts.insn32 = TRUE;
|
||||
else if (strcmp (name, "noinsn32") == 0)
|
||||
mips_opts.insn32 = FALSE;
|
||||
else if (strcmp (name, "push") == 0)
|
||||
{
|
||||
struct mips_option_stack *s;
|
||||
@@ -18854,7 +18935,7 @@ mips_handle_align (fragS *fragp)
|
||||
*p++ = '\0';
|
||||
/* Fall through. */
|
||||
case 2:
|
||||
if (nop_opcode == NOP_OPCODE_MICROMIPS)
|
||||
if (nop_opcode == NOP_OPCODE_MICROMIPS && !mips_opts.insn32)
|
||||
{
|
||||
p = write_compressed_insn (p, micromips_nop16_insn.insn_opcode, 2);
|
||||
break;
|
||||
@@ -19580,6 +19661,9 @@ MIPS options:\n\
|
||||
-mvirt generate Virtualization instructions\n\
|
||||
-mno-virt do not generate Virtualization instructions\n"));
|
||||
fprintf (stream, _("\
|
||||
-minsn32 only generate 32-bit microMIPS instructions\n\
|
||||
-mno-insn32 generate all microMIPS instructions\n"));
|
||||
fprintf (stream, _("\
|
||||
-mfix-loongson2f-jump work around Loongson2F JUMP instructions\n\
|
||||
-mfix-loongson2f-nop work around Loongson2F NOP errata\n\
|
||||
-mfix-vr4120 work around certain VR4120 errata\n\
|
||||
|
||||
Reference in New Issue
Block a user