diff options
Diffstat (limited to 'gas')
-rw-r--r-- | gas/ChangeLog | 48 | ||||
-rw-r--r-- | gas/config/tc-mips.c | 160 | ||||
-rw-r--r-- | gas/doc/as.texinfo | 7 | ||||
-rw-r--r-- | gas/doc/c-mips.texi | 16 |
4 files changed, 187 insertions, 44 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index c9ed98b..00b4742 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,4 +1,52 @@ 2017-05-15 Maciej W. Rozycki <macro@imgtec.com> + Matthew Fortune <matthew.fortune@imgtec.com> + Andrew Bennett <andrew.bennett@imgtec.com> + + * config/tc-mips.c (RELAX_MIPS16_ENCODE): Add `e2' flag. + (RELAX_MIPS16_E2): New macro. + (RELAX_MIPS16_PIC, RELAX_MIPS16_SYM32, RELAX_MIPS16_NOMACRO) + (RELAX_MIPS16_USER_SMALL, RELAX_MIPS16_USER_EXT) + (RELAX_MIPS16_DSLOT, RELAX_MIPS16_JAL_DSLOT) + (RELAX_MIPS16_EXTENDED, RELAX_MIPS16_MARK_EXTENDED) + (RELAX_MIPS16_CLEAR_EXTENDED, RELAX_MIPS16_ALWAYS_EXTENDED) + (RELAX_MIPS16_MARK_ALWAYS_EXTENDED) + (RELAX_MIPS16_CLEAR_ALWAYS_EXTENDED, RELAX_MIPS16_MACRO) + (RELAX_MIPS16_MARK_MACRO, RELAX_MIPS16_CLEAR_MACRO): Shift bits. + (mips16_immed_extend): New prototype. + (options): Add OPTION_MIPS16E2 and OPTION_NO_MIPS16E2 enum + values. + (md_longopts): Add "mmips16e2" and "mno-mips16e2" options. + (mips_ases): Add "mips16e2" entry. + (mips_set_ase): Handle MIPS16e2 ASE. + (insn_insert_operand): Explicitly handle immediates with MIPS16 + instructions that require 32-bit encoding. + (is_opcode_valid_16): Pass enabled ASE bitmask on to + `opcode_is_member'. + (validate_mips_insn): Explicitly handle immediates with MIPS16 + instructions that require 32-bit encoding. + (operand_reg_mask) <OP_REG28>: Add handler. + (match_reg28_operand): New function. + (match_operand) <OP_REG28>: Add handler. + (append_insn): Pass ASE_MIPS16E2 setting to RELAX_MIPS16_ENCODE. + (match_mips16_insn): Handle MIPS16 instructions that require + 32-bit encoding and `V' and `u' operand codes. + (mips16_ip): Allow any characters except from `.' in opcodes. + (mips16_immed_extend): Handle 9-bit immediates. Do not shuffle + immediates whose width is not one of these listed. + (md_estimate_size_before_relax): Handle MIPS16e2 relaxation. + (mips_relax_frag): Likewise. + (md_convert_frag): Likewise. + (mips_convert_ase_flags): Handle MIPS16e2 ASE. + + * doc/as.texinfo (Target MIPS options): Add `-mmips16e2' and + `-mno-mips16e2' options. + (-mmips16e2, -mno-mips16e2): New options. + * doc/c-mips.texi (MIPS Options): Add `-mmips16e2' and + `-mno-mips16e2' options. + (MIPS ASE Instruction Generation Overrides): Add `.set mips16e2' + and `.set nomips16e2'. + +2017-05-15 Maciej W. Rozycki <macro@imgtec.com> * config/tc-mips.c (match_int_operand): Call `match_out_of_range' before returning failure for 0x8000-0xffff diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index beb4d46..7e927b2 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -1130,38 +1130,40 @@ static bfd_boolean mips_ignore_branch_isa; store whether this is known to be a branch to a different section, whether we have tried to relax this frag yet, and whether we have ever extended a PC relative fragment because of a shift count. */ -#define RELAX_MIPS16_ENCODE(type, pic, sym32, nomacro, \ +#define RELAX_MIPS16_ENCODE(type, e2, pic, sym32, nomacro, \ small, ext, \ dslot, jal_dslot) \ (0x80000000 \ | ((type) & 0xff) \ - | ((pic) ? 0x100 : 0) \ - | ((sym32) ? 0x200 : 0) \ - | ((nomacro) ? 0x400 : 0) \ - | ((small) ? 0x800 : 0) \ - | ((ext) ? 0x1000 : 0) \ - | ((dslot) ? 0x2000 : 0) \ - | ((jal_dslot) ? 0x4000 : 0)) + | ((e2) ? 0x100 : 0) \ + | ((pic) ? 0x200 : 0) \ + | ((sym32) ? 0x400 : 0) \ + | ((nomacro) ? 0x800 : 0) \ + | ((small) ? 0x1000 : 0) \ + | ((ext) ? 0x2000 : 0) \ + | ((dslot) ? 0x4000 : 0) \ + | ((jal_dslot) ? 0x8000 : 0)) #define RELAX_MIPS16_P(i) (((i) & 0xc0000000) == 0x80000000) #define RELAX_MIPS16_TYPE(i) ((i) & 0xff) -#define RELAX_MIPS16_PIC(i) (((i) & 0x100) != 0) -#define RELAX_MIPS16_SYM32(i) (((i) & 0x200) != 0) -#define RELAX_MIPS16_NOMACRO(i) (((i) & 0x400) != 0) -#define RELAX_MIPS16_USER_SMALL(i) (((i) & 0x800) != 0) -#define RELAX_MIPS16_USER_EXT(i) (((i) & 0x1000) != 0) -#define RELAX_MIPS16_DSLOT(i) (((i) & 0x2000) != 0) -#define RELAX_MIPS16_JAL_DSLOT(i) (((i) & 0x4000) != 0) - -#define RELAX_MIPS16_EXTENDED(i) (((i) & 0x8000) != 0) -#define RELAX_MIPS16_MARK_EXTENDED(i) ((i) | 0x8000) -#define RELAX_MIPS16_CLEAR_EXTENDED(i) ((i) & ~0x8000) -#define RELAX_MIPS16_ALWAYS_EXTENDED(i) (((i) & 0x10000) != 0) -#define RELAX_MIPS16_MARK_ALWAYS_EXTENDED(i) ((i) | 0x10000) -#define RELAX_MIPS16_CLEAR_ALWAYS_EXTENDED(i) ((i) & ~0x10000) -#define RELAX_MIPS16_MACRO(i) (((i) & 0x20000) != 0) -#define RELAX_MIPS16_MARK_MACRO(i) ((i) | 0x20000) -#define RELAX_MIPS16_CLEAR_MACRO(i) ((i) & ~0x20000) +#define RELAX_MIPS16_E2(i) (((i) & 0x100) != 0) +#define RELAX_MIPS16_PIC(i) (((i) & 0x200) != 0) +#define RELAX_MIPS16_SYM32(i) (((i) & 0x400) != 0) +#define RELAX_MIPS16_NOMACRO(i) (((i) & 0x800) != 0) +#define RELAX_MIPS16_USER_SMALL(i) (((i) & 0x1000) != 0) +#define RELAX_MIPS16_USER_EXT(i) (((i) & 0x2000) != 0) +#define RELAX_MIPS16_DSLOT(i) (((i) & 0x4000) != 0) +#define RELAX_MIPS16_JAL_DSLOT(i) (((i) & 0x8000) != 0) + +#define RELAX_MIPS16_EXTENDED(i) (((i) & 0x10000) != 0) +#define RELAX_MIPS16_MARK_EXTENDED(i) ((i) | 0x10000) +#define RELAX_MIPS16_CLEAR_EXTENDED(i) ((i) & ~0x10000) +#define RELAX_MIPS16_ALWAYS_EXTENDED(i) (((i) & 0x20000) != 0) +#define RELAX_MIPS16_MARK_ALWAYS_EXTENDED(i) ((i) | 0x20000) +#define RELAX_MIPS16_CLEAR_ALWAYS_EXTENDED(i) ((i) & ~0x20000) +#define RELAX_MIPS16_MACRO(i) (((i) & 0x40000) != 0) +#define RELAX_MIPS16_MARK_MACRO(i) ((i) | 0x40000) +#define RELAX_MIPS16_CLEAR_MACRO(i) ((i) & ~0x40000) /* For microMIPS code, we use relaxation similar to one we use for MIPS16 code. Some instructions that take immediate values support @@ -1341,6 +1343,7 @@ 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); +static unsigned long mips16_immed_extend (offsetT, unsigned int); static void mips16_immed (const char *, unsigned int, int, bfd_reloc_code_real_type, offsetT, unsigned int, unsigned long *); @@ -1455,6 +1458,8 @@ enum options OPTION_NO_MICROMIPS, OPTION_MCU, OPTION_NO_MCU, + OPTION_MIPS16E2, + OPTION_NO_MIPS16E2, OPTION_COMPAT_ARCH_BASE, OPTION_M4650, OPTION_NO_M4650, @@ -1575,6 +1580,8 @@ struct option md_longopts[] = {"mno-msa", no_argument, NULL, OPTION_NO_MSA}, {"mxpa", no_argument, NULL, OPTION_XPA}, {"mno-xpa", no_argument, NULL, OPTION_NO_XPA}, + {"mmips16e2", no_argument, NULL, OPTION_MIPS16E2}, + {"mno-mips16e2", no_argument, NULL, OPTION_NO_MIPS16E2}, /* Old-style architecture options. Don't add more of these. */ {"m4650", no_argument, NULL, OPTION_M4650}, @@ -1757,6 +1764,11 @@ static const struct mips_ase mips_ases[] = { OPTION_XPA, OPTION_NO_XPA, 2, 2, -1, -1, -1 }, + + { "mips16e2", ASE_MIPS16E2, 0, + OPTION_MIPS16E2, OPTION_NO_MIPS16E2, + 2, 2, -1, -1, + 6 }, }; /* The set of ASEs that require -mfp64. */ @@ -2120,6 +2132,13 @@ mips_set_ase (const struct mips_ase *ase, struct mips_set_options *opts, opts->ase &= ~mask; if (enabled_p) opts->ase |= ase->flags; + + if ((opts->ase & (ASE_MIPS16E2 | ASE_MT)) == (ASE_MIPS16E2 | ASE_MT)) + { + opts->ase |= ASE_MIPS16E2_MT; + mask |= ASE_MIPS16E2_MT; + } + return mask; } @@ -2226,7 +2245,12 @@ static inline void insn_insert_operand (struct mips_cl_insn *insn, const struct mips_operand *operand, unsigned int uval) { - insn->insn_opcode = mips_insert_operand (operand, insn->insn_opcode, uval); + if (mips_opts.mips16 + && operand->type == OP_INT && operand->lsb == 0 + && mips_opcode_32bit_p (insn->insn_mo)) + insn->insn_opcode |= mips16_immed_extend (uval, operand->size); + else + insn->insn_opcode = mips_insert_operand (operand, insn->insn_opcode, uval); } /* Extract the value of OPERAND from INSN. */ @@ -3286,7 +3310,16 @@ is_opcode_valid (const struct mips_opcode *mo) static bfd_boolean is_opcode_valid_16 (const struct mips_opcode *mo) { - return opcode_is_member (mo, mips_opts.isa, 0, mips_opts.arch); + int isa = mips_opts.isa; + int ase = mips_opts.ase; + unsigned int i; + + if (ISA_HAS_64BIT_REGS (isa)) + for (i = 0; i < ARRAY_SIZE (mips_ases); i++) + if ((ase & mips_ases[i].flags) == mips_ases[i].flags) + ase |= mips_ases[i].flags64; + + return opcode_is_member (mo, isa, ase, mips_opts.arch); } /* Return TRUE if the size of the microMIPS opcode MO matches one @@ -3417,7 +3450,11 @@ validate_mips_insn (const struct mips_opcode *opcode, } gas_assert (opno < MAX_OPERANDS); operands->operand[opno] = operand; - if (operand && operand->type != OP_VU0_MATCH_SUFFIX) + if (!decode_operand && operand + && operand->type == OP_INT && operand->lsb == 0 + && mips_opcode_32bit_p (opcode)) + used_bits |= mips16_immed_extend (-1, operand->size); + else if (operand && operand->type != OP_VU0_MATCH_SUFFIX) { used_bits = mips_insert_operand (operand, used_bits, -1); if (operand->type == OP_MDMX_IMM_REG) @@ -4501,6 +4538,9 @@ operand_reg_mask (const struct mips_cl_insn *insn, case OP_IMM_INDEX: abort (); + case OP_REG28: + return 1 << 28; + case OP_REG: case OP_OPTIONAL_REG: { @@ -5795,6 +5835,23 @@ match_pc_operand (struct mips_arg_info *arg) return FALSE; } +/* OP_REG28 matcher. */ + +static bfd_boolean +match_reg28_operand (struct mips_arg_info *arg) +{ + unsigned int regno; + + if (arg->token->type == OT_REG + && match_regno (arg, OP_REG_GP, arg->token->u.regno, ®no) + && regno == GP) + { + ++arg->token; + return TRUE; + } + return FALSE; +} + /* OP_NON_ZERO_REG matcher. */ static bfd_boolean @@ -6079,6 +6136,9 @@ match_operand (struct mips_arg_info *arg, case OP_PC: return match_pc_operand (arg); + case OP_REG28: + return match_reg28_operand (arg); + case OP_VU0_SUFFIX: return match_vu0_suffix_operand (arg, operand, FALSE); @@ -7452,6 +7512,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, add_relaxed_insn (ip, 12, 0, RELAX_MIPS16_ENCODE (*reloc_type - BFD_RELOC_UNUSED, + mips_opts.ase & ASE_MIPS16E2, mips_pic != NO_PIC, HAVE_32BIT_SYMBOLS, mips_opts.warn_about_macros, @@ -8194,7 +8255,7 @@ match_mips16_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode, { if (required_insn_length == 2) set_insn_error (0, _("invalid unextended operand value")); - else + else if (!mips_opcode_32bit_p (opcode)) { forced_insn_length = 4; insn->insn_opcode |= MIPS16_EXTEND; @@ -8228,6 +8289,8 @@ match_mips16_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode, case 'A': case 'B': case 'E': + case 'V': + case 'u': relax_char = c; break; @@ -13923,7 +13986,7 @@ mips16_ip (char *str, struct mips_cl_insn *insn) struct mips_operand_token *tokens; unsigned int l; - for (s = str; ISLOWER (*s); ++s) + for (s = str; *s != '\0' && *s != '.' && *s != ' '; ++s) ; end = s; c = *end; @@ -13954,8 +14017,6 @@ mips16_ip (char *str, struct mips_cl_insn *insn) break; else if (*s++ == ' ') break; - /* Fall through. */ - default: set_insn_error (0, _("unrecognized opcode")); return; } @@ -13988,7 +14049,10 @@ static unsigned long mips16_immed_extend (offsetT val, unsigned int nbits) { int extval; - if (nbits == 16) + + extval = 0; + val &= (1U << nbits) - 1; + if (nbits == 16 || nbits == 9) { extval = ((val >> 11) & 0x1f) | (val & 0x7e0); val &= 0x1f; @@ -13998,7 +14062,7 @@ mips16_immed_extend (offsetT val, unsigned int nbits) extval = ((val >> 11) & 0xf) | (val & 0x7f0); val &= 0xf; } - else + else if (nbits == 6) { extval = ((val & 0x1f) << 6) | (val & 0x20); val = 0; @@ -17703,7 +17767,7 @@ md_estimate_size_before_relax (fragS *fragp, asection *segtype) /* We don't want to modify the EXTENDED bit here; it might get us into infinite loops. We change it only in mips_relax_frag(). */ if (RELAX_MIPS16_MACRO (fragp->fr_subtype)) - return 12; + return RELAX_MIPS16_E2 (fragp->fr_subtype) ? 8 : 12; else return RELAX_MIPS16_EXTENDED (fragp->fr_subtype) ? 4 : 2; } @@ -17961,7 +18025,7 @@ mips_relax_frag (asection *sec, fragS *fragp, long stretch) if (RELAX_MIPS16_MACRO (fragp->fr_subtype)) { fragp->fr_subtype = RELAX_MIPS16_CLEAR_MACRO (fragp->fr_subtype); - return -10; + return RELAX_MIPS16_E2 (fragp->fr_subtype) ? -6 : -10; } else if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype)) { @@ -17977,7 +18041,7 @@ mips_relax_frag (asection *sec, fragS *fragp, long stretch) { fragp->fr_subtype = RELAX_MIPS16_CLEAR_MACRO (fragp->fr_subtype); fragp->fr_subtype = RELAX_MIPS16_MARK_EXTENDED (fragp->fr_subtype); - return -8; + return RELAX_MIPS16_E2 (fragp->fr_subtype) ? -4 : -8; } else if (!RELAX_MIPS16_EXTENDED (fragp->fr_subtype)) { @@ -17995,12 +18059,12 @@ mips_relax_frag (asection *sec, fragS *fragp, long stretch) { fragp->fr_subtype = RELAX_MIPS16_CLEAR_EXTENDED (fragp->fr_subtype); fragp->fr_subtype = RELAX_MIPS16_MARK_MACRO (fragp->fr_subtype); - return 8; + return RELAX_MIPS16_E2 (fragp->fr_subtype) ? 4 : 8; } else { fragp->fr_subtype = RELAX_MIPS16_MARK_MACRO (fragp->fr_subtype); - return 10; + return RELAX_MIPS16_E2 (fragp->fr_subtype) ? 6 : 10; } } @@ -18575,10 +18639,13 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp) unsigned long reg; unsigned long new; unsigned long op; + bfd_boolean e2; gas_assert (type == 'A' || type == 'B' || type == 'E'); gas_assert (RELAX_MIPS16_SYM32 (fragp->fr_subtype)); + e2 = RELAX_MIPS16_E2 (fragp->fr_subtype); + if (need_reloc) { fixS *fixp; @@ -18591,7 +18658,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp) fixp->fx_file = fragp->fr_file; fixp->fx_line = fragp->fr_line; - fixp = fix_new (fragp, buf - fragp->fr_literal + 8, 4, + fixp = fix_new (fragp, buf - fragp->fr_literal + (e2 ? 4 : 8), 4, fragp->fr_symbol, fragp->fr_offset, FALSE, BFD_RELOC_MIPS16_LO16); fixp->fx_file = fragp->fr_file; @@ -18628,15 +18695,18 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp) abort (); } - new = 0xf0006800 | (reg << 8); /* LI */ + new = (e2 ? 0xf0006820 : 0xf0006800) | (reg << 8); /* LUI/LI */ new |= mips16_immed_extend ((val + 0x8000) >> 16, 16); buf = write_compressed_insn (buf, new, 4); - new = 0xf4003000 | (reg << 8) | (reg << 5); /* SLL */ - buf = write_compressed_insn (buf, new, 4); + if (!e2) + { + new = 0xf4003000 | (reg << 8) | (reg << 5); /* SLL */ + buf = write_compressed_insn (buf, new, 4); + } op |= mips16_immed_extend (val, 16); buf = write_compressed_insn (buf, op, 4); - fragp->fr_fix += 12; + fragp->fr_fix += e2 ? 8 : 12; } else { @@ -18866,6 +18936,8 @@ mips_convert_ase_flags (int ase) ext_ases |= AFL_ASE_MSA; if (ase & ASE_XPA) ext_ases |= AFL_ASE_XPA; + if (ase & ASE_MIPS16E2) + ext_ases |= file_ase_mips16 ? AFL_ASE_MIPS16E2 : 0; return ext_ases; } diff --git a/gas/doc/as.texinfo b/gas/doc/as.texinfo index 27d0c68..e0637c7 100644 --- a/gas/doc/as.texinfo +++ b/gas/doc/as.texinfo @@ -420,6 +420,7 @@ gcc(1), ld(1), and the Info entries for @file{binutils} and @file{ld}. [@b{-mnan=@var{encoding}}] [@b{-trap}] [@b{-no-break}] [@b{-break}] [@b{-no-trap}] [@b{-mips16}] [@b{-no-mips16}] + [@b{-mmips16e2}] [@b{-mno-mips16e2}] [@b{-mmicromips}] [@b{-mno-micromips}] [@b{-msmartmips}] [@b{-mno-smartmips}] [@b{-mips3d}] [@b{-no-mips3d}] @@ -1455,6 +1456,12 @@ Generate code for the MIPS 16 processor. This is equivalent to putting @code{.module mips16} at the start of the assembly file. @samp{-no-mips16} turns off this option. +@item -mmips16e2 +@itemx -mno-mips16e2 +Enable the use of MIPS16e2 instructions in MIPS16 mode. This is equivalent +to putting @code{.module mips16e2} at the start of the assembly file. +@samp{-mno-mips16e2} turns off this option. + @item -mmicromips @itemx -mno-micromips Generate code for the microMIPS processor. This is equivalent to putting diff --git a/gas/doc/c-mips.texi b/gas/doc/c-mips.texi index e5d00b2..c2d9b7a 100644 --- a/gas/doc/c-mips.texi +++ b/gas/doc/c-mips.texi @@ -151,6 +151,12 @@ Generate code for the MIPS 16 processor. This is equivalent to putting @code{.module mips16} at the start of the assembly file. @samp{-no-mips16} turns off this option. +@item -mmips16e2 +@itemx -mno-mips16e2 +Enable the use of MIPS16e2 instructions in MIPS16 mode. This is equivalent +to putting @code{.module mips16e2} at the start of the assembly file. +@samp{-mno-mips16e2} turns off this option. + @item -mmicromips @itemx -mno-micromips Generate code for the microMIPS processor. This is equivalent to putting @@ -1094,6 +1100,16 @@ The directive @code{.set xpa} makes the assembler accept instructions from the XPA Extension from that point on in the assembly. The @code{.set noxpa} directive prevents XPA instructions from being accepted. +@cindex MIPS16e2 instruction generation override +@kindex @code{.set mips16e2} +@kindex @code{.set nomips16e2} +The directive @code{.set mips16e2} makes the assembler accept instructions +from the MIPS16e2 Application Specific Extension from that point on in the +assembly, whenever in MIPS16 mode. The @code{.set nomips16e2} prevents +MIPS16e2 instructions from being accepted, in MIPS16 mode. Neither +directive affects the state of MIPS16 mode being active itself which has +separate controls. + Traditional MIPS assemblers do not support these directives. @node MIPS Floating-Point |