aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-mips.c
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@linux-mips.org>2013-06-25 18:02:34 +0000
committerMaciej W. Rozycki <macro@linux-mips.org>2013-06-25 18:02:34 +0000
commit833794fc12d98139fc33f6b0b85feb03471007b7 (patch)
treea7c2fa06414c50f6e0bb252a7f5593c0db4c2ff8 /gas/config/tc-mips.c
parent6e2048d3e3a50472e73d74d97ae031741464b756 (diff)
downloadgdb-833794fc12d98139fc33f6b0b85feb03471007b7.zip
gdb-833794fc12d98139fc33f6b0b85feb03471007b7.tar.gz
gdb-833794fc12d98139fc33f6b0b85feb03471007b7.tar.bz2
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.
Diffstat (limited to 'gas/config/tc-mips.c')
-rw-r--r--gas/config/tc-mips.c122
1 files changed, 103 insertions, 19 deletions
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
index dba8b21..595ab74 100644
--- a/gas/config/tc-mips.c
+++ b/gas/config/tc-mips.c
@@ -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 ? &micromips_nop16_insn : &nop_insn))
+#define NOP_INSN (mips_opts.mips16 \
+ ? &mips16_nop_insn \
+ : (mips_opts.micromips \
+ ? (mips_opts.insn32 \
+ ? &micromips_nop32_insn \
+ : &micromips_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\