diff options
author | Maciej W. Rozycki <macro@imgtec.com> | 2017-05-03 20:43:10 +0100 |
---|---|---|
committer | Maciej W. Rozycki <macro@imgtec.com> | 2017-05-03 20:47:40 +0100 |
commit | 8507b6e79772ffeb83a0142d12a63e02dcc44562 (patch) | |
tree | 0952e6c10d5abbb11afa9cb6cee1903b44ec30ba /gas/config | |
parent | 90cef2edd256c48d2ff9a03d4a6c1bcb575db07c (diff) | |
download | gdb-8507b6e79772ffeb83a0142d12a63e02dcc44562.zip gdb-8507b6e79772ffeb83a0142d12a63e02dcc44562.tar.gz gdb-8507b6e79772ffeb83a0142d12a63e02dcc44562.tar.bz2 |
MIPS16/GAS: Relax 32-bit non-PIC PC-relative synthetic instructions
Implement the relaxation of MIPS16 PC-relative synthetic LA, DLA, LW and
LD instructions to an equivalent sequence of instructions produced where
the address operand requested is out of range, absolute or requires
linker relocation, for ABIs that use 32-bit addressing and non-PIC code.
The sequence generated uses the register specified for the destination
operand as a temporary and begins with LI to load the high 16-bit part
of the address, then continues with SLL by 16 bits to move that part
into place and finally completes with a suitable operation corresponding
to the synthetic instruction used, one of: 2-argument ADDIU, 2-argument
DADDIU, absolute LW, and absolute LD respectively, providing the low
16-bit part of the address. All instructions use the extended encoding.
As a special exception accept absolute addresses for relaxation even in
PIC code.
For example:
la $2, 0x12345678
produces code as:
li $2, 0x1234
sll $2, $2, 16
addiu $2, 0x5678
would.
Where linker relocation is required emit an R_MIPS16_HI16 relocation on
the initial LI instruction and an R_MIPS16_LO16 relocation on the final
operation.
For example (where `foo' is not local):
lw $3, foo
produces code as:
li $3, %hi(foo)
sll $3, $3, 16
lw $3, %lo(foo)($3)
would.
Emit assembly warnings as appropriate where this new relaxation triggers
in the `nomacro' mode or for an instruction manually placed in a branch
delay slot in the `noreorder' mode. Refrain from relaxation where an
explicit instruction size suffix has been used and in the `noautoextend'
mode.
gas/
* config/tc-mips.c (RELAX_MIPS16_ENCODE): Add `pic', `sym32' and
`nomacro' flags.
(RELAX_MIPS16_PIC, RELAX_MIPS16_SYM32, RELAX_MIPS16_NOMACRO):
New macros.
(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): Shift bits.
(RELAX_MIPS16_MACRO, RELAX_MIPS16_MARK_MACRO)
(RELAX_MIPS16_CLEAR_MACRO): New macros.
(append_insn): Pass `mips_pic', HAVE_32BIT_SYMBOLS and
`mips_opts.warn_about_macros' settings to RELAX_MIPS16_ENCODE.
(mips16_macro_frag): New function.
(md_estimate_size_before_relax): Handle HI16/LO16 relaxation.
(mips_relax_frag): Likewise.
(md_convert_frag): Likewise.
* testsuite/gas/mips/mips16@relax-swap3.d: Remove error output,
add dump patterns.
* testsuite/gas/mips/mips16e@relax-swap3.d: New test
subarchitecture.
* testsuite/gas/mips/micromips@relax-swap3.d: Remove trailing
NOP padding.
* testsuite/gas/mips/mips16-pcrel-reloc-2.d: Remove error
output, add dump patterns.
* testsuite/gas/mips/mips16-pcrel-reloc-3.d: Remove error
output, add dump patterns.
* testsuite/gas/mips/mips16-pcrel-reloc-6.d: Remove error
output, add dump patterns.
* testsuite/gas/mips/mips16-pcrel-reloc-7.d: Remove error
output, add dump patterns.
* testsuite/gas/mips/mips16-pcrel-addend-2.d: Remove error
output, add dump patterns.
* testsuite/gas/mips/mips16-pcrel-addend-3.d: Remove error
output, add dump patterns.
* testsuite/gas/mips/mips16-pcrel-absolute.d: Remove error
output, add dump patterns.
* testsuite/gas/mips/mips16-pcrel-absolute-1.d: Remove error
output, add dump patterns.
* testsuite/gas/mips/mips16@relax-swap3.l: Remove file.
* testsuite/gas/mips/mips16-pcrel-reloc-2.l: Remove file.
* testsuite/gas/mips/mips16-pcrel-reloc-3.l: Remove file.
* testsuite/gas/mips/mips16-pcrel-reloc-6.l: Remove file.
* testsuite/gas/mips/mips16-pcrel-reloc-7.l: Remove file.
* testsuite/gas/mips/mips16-pcrel-addend-2.l: Remove file.
* testsuite/gas/mips/mips16-pcrel-addend-3.l: Remove file.
* testsuite/gas/mips/mips16-pcrel-absolute.l: Remove file.
* testsuite/gas/mips/mips16-pcrel-absolute-1.l: Remove file.
* testsuite/gas/mips/relax-swap3.s: Adjust trailing padding.
* testsuite/gas/mips/mips16-pcrel-0.d: New test.
* testsuite/gas/mips/mips16-pcrel-1.d: New test.
* testsuite/gas/mips/mips16-pcrel-2.d: New test.
* testsuite/gas/mips/mips16-pcrel-3.d: New test.
* testsuite/gas/mips/mips16-pcrel-4.d: New test.
* testsuite/gas/mips/mips16-pcrel-5.d: New test.
* testsuite/gas/mips/mips16-pcrel-pic-0.d: New test.
* testsuite/gas/mips/mips16-pcrel-pic-1.d: New test.
* testsuite/gas/mips/mips16-pcrel-n32-0.d: New test.
* testsuite/gas/mips/mips16-pcrel-n32-1.d: New test.
* testsuite/gas/mips/mips16-pcrel-n64-sym32-0.d: New test.
* testsuite/gas/mips/mips16-pcrel-n64-sym32-1.d: New test.
* testsuite/gas/mips/mips16-pcrel-n64-0.d: New test.
* testsuite/gas/mips/mips16-pcrel-n64-1.d: New test.
* testsuite/gas/mips/mips16-pcrel-delay-0.d: New test.
* testsuite/gas/mips/mips16-pcrel-delay-1.d: New test.
* testsuite/gas/mips/mips16-pcrel-addend-4.d: New test.
* testsuite/gas/mips/mips16-pcrel-addend-5.d: New test.
* testsuite/gas/mips/mips16-pcrel-addend-6.d: New test.
* testsuite/gas/mips/mips16-pcrel-addend-7.d: New test.
* testsuite/gas/mips/mips16-pcrel-addend-8.d: New test.
* testsuite/gas/mips/mips16-pcrel-addend-9.d: New test.
* testsuite/gas/mips/mips16-pcrel-addend-pic-8.d: New test.
* testsuite/gas/mips/mips16-pcrel-addend-pic-9.d: New test.
* testsuite/gas/mips/mips16-pcrel-addend-n32-8.d: New test.
* testsuite/gas/mips/mips16-pcrel-addend-n32-9.d: New test.
* testsuite/gas/mips/mips16-pcrel-addend-n64-sym32-8.d: New test.
* testsuite/gas/mips/mips16-pcrel-addend-n64-sym32-9.d: New test.
* testsuite/gas/mips/mips16-pcrel-addend-n64-8.d: New test.
* testsuite/gas/mips/mips16-pcrel-addend-n64-9.d: New test.
* testsuite/gas/mips/mips16-pcrel-absolute-2.d: New test.
* testsuite/gas/mips/mips16-pcrel-absolute-3.d: New test.
* testsuite/gas/mips/mips16-pcrel-absolute-4.d: New test.
* testsuite/gas/mips/mips16-pcrel-absolute-5.d: New test.
* testsuite/gas/mips/mips16-pcrel-absolute-6.d: New test.
* testsuite/gas/mips/mips16-pcrel-absolute-7.d: New test.
* testsuite/gas/mips/mips16-pcrel-absolute-pic-4.d: New test.
* testsuite/gas/mips/mips16-pcrel-absolute-pic-6.d: New test.
* testsuite/gas/mips/mips16-pcrel-absolute-n32-4.d: New test.
* testsuite/gas/mips/mips16-pcrel-absolute-n32-6.d: New test.
* testsuite/gas/mips/mips16-pcrel-absolute-n64-4.d: New test.
* testsuite/gas/mips/mips16-pcrel-absolute-n64-6.d: New test.
* testsuite/gas/mips/mips16-pcrel-absolute-n64-sym32-4.d: New
test.
* testsuite/gas/mips/mips16-pcrel-absolute-n64-sym32-6.d: New
test.
* testsuite/gas/mips/mips16-pcrel-absolute-pic-n32-4.d: New
test.
* testsuite/gas/mips/mips16-pcrel-absolute-pic-n32-6.d: New
test.
* testsuite/gas/mips/mips16-pcrel-absolute-pic-n64-4.d: New
test.
* testsuite/gas/mips/mips16-pcrel-absolute-pic-n64-6.d: New
test.
* testsuite/gas/mips/mips16-pcrel-absolute-pic-n64-sym32-4.d:
New test.
* testsuite/gas/mips/mips16-pcrel-absolute-pic-n64-sym32-6.d:
New test.
* testsuite/gas/mips/mips16-pcrel-0.l: New stderr output.
* testsuite/gas/mips/mips16-pcrel-1.l: New stderr output.
* testsuite/gas/mips/mips16-pcrel-2.l: New stderr output.
* testsuite/gas/mips/mips16-pcrel-3.l: New stderr output.
* testsuite/gas/mips/mips16-pcrel-4.l: New stderr output.
* testsuite/gas/mips/mips16-pcrel-5.l: New stderr output.
* testsuite/gas/mips/mips16-pcrel-delay-0.l: New stderr output.
* testsuite/gas/mips/mips16-pcrel-delay-1.l: New stderr output.
* testsuite/gas/mips/mips16-pcrel-addend-8.l: New stderr output.
* testsuite/gas/mips/mips16-pcrel-addend-9.l: New stderr output.
* testsuite/gas/mips/mips16-pcrel-absolute-4.l: New stderr
output.
* testsuite/gas/mips/mips16-pcrel-absolute-6.l: New stderr
output.
* testsuite/gas/mips/mips16-pcrel-0.s: New test source.
* testsuite/gas/mips/mips16-pcrel-1.s: New test source.
* testsuite/gas/mips/mips16-pcrel-2.s: New test source.
* testsuite/gas/mips/mips16-pcrel-3.s: New test source.
* testsuite/gas/mips/mips16-pcrel-4.s: New test source.
* testsuite/gas/mips/mips16-pcrel-5.s: New test source.
* testsuite/gas/mips/mips16-pcrel-delay-0.s: New test source.
* testsuite/gas/mips/mips16-pcrel-delay-1.s: New test source.
* testsuite/gas/mips/mips16-pcrel-addend-4.s: New test source.
* testsuite/gas/mips/mips16-pcrel-addend-5.s: New test source.
* testsuite/gas/mips/mips16-pcrel-addend-6.s: New test source.
* testsuite/gas/mips/mips16-pcrel-addend-7.s: New test source.
* testsuite/gas/mips/mips16-pcrel-addend-8.s: New test source.
* testsuite/gas/mips/mips16-pcrel-addend-9.s: New test source.
* testsuite/gas/mips/mips16-pcrel-absolute-2.s: New test.
* testsuite/gas/mips/mips16-pcrel-absolute-3.s: New test.
* testsuite/gas/mips/mips16-pcrel-absolute-4.s: New test.
* testsuite/gas/mips/mips16-pcrel-absolute-5.s: New test.
* testsuite/gas/mips/mips16-pcrel-absolute-6.s: New test.
* testsuite/gas/mips/mips16-pcrel-absolute-7.s: New test.
* testsuite/gas/mips/mips.exp: Run the new tests.
ld/
* testsuite/ld-mips-elf/mips16-pcrel-0.d: New test.
* testsuite/ld-mips-elf/mips16-pcrel-1.d: New test.
* testsuite/ld-mips-elf/mips16-pcrel-addend-2.d: New test.
* testsuite/ld-mips-elf/mips16-pcrel-addend-6.d: New test.
* testsuite/ld-mips-elf/mips16-pcrel-n32-0.d: New test.
* testsuite/ld-mips-elf/mips16-pcrel-n32-1.d: New test.
* testsuite/ld-mips-elf/mips16-pcrel-n64-sym32-0.d: New test.
* testsuite/ld-mips-elf/mips16-pcrel-n64-sym32-1.d: New test.
* testsuite/ld-mips-elf/mips-elf.exp: Run the new tests.
Diffstat (limited to 'gas/config')
-rw-r--r-- | gas/config/tc-mips.c | 312 |
1 files changed, 248 insertions, 64 deletions
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index 8c387ba..4ead209 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -1130,25 +1130,38 @@ 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, small, ext, dslot, jal_dslot) \ +#define RELAX_MIPS16_ENCODE(type, pic, sym32, nomacro, \ + small, ext, \ + dslot, jal_dslot) \ (0x80000000 \ | ((type) & 0xff) \ - | ((small) ? 0x100 : 0) \ - | ((ext) ? 0x200 : 0) \ - | ((dslot) ? 0x400 : 0) \ - | ((jal_dslot) ? 0x800 : 0)) + | ((pic) ? 0x100 : 0) \ + | ((sym32) ? 0x200 : 0) \ + | ((nomacro) ? 0x400 : 0) \ + | ((small) ? 0x800 : 0) \ + | ((ext) ? 0x1000 : 0) \ + | ((dslot) ? 0x2000 : 0) \ + | ((jal_dslot) ? 0x4000 : 0)) + #define RELAX_MIPS16_P(i) (((i) & 0xc0000000) == 0x80000000) #define RELAX_MIPS16_TYPE(i) ((i) & 0xff) -#define RELAX_MIPS16_USER_SMALL(i) (((i) & 0x100) != 0) -#define RELAX_MIPS16_USER_EXT(i) (((i) & 0x200) != 0) -#define RELAX_MIPS16_DSLOT(i) (((i) & 0x400) != 0) -#define RELAX_MIPS16_JAL_DSLOT(i) (((i) & 0x800) != 0) -#define RELAX_MIPS16_EXTENDED(i) (((i) & 0x1000) != 0) -#define RELAX_MIPS16_MARK_EXTENDED(i) ((i) | 0x1000) -#define RELAX_MIPS16_CLEAR_EXTENDED(i) ((i) &~ 0x1000) -#define RELAX_MIPS16_ALWAYS_EXTENDED(i) (((i) & 0x2000) != 0) -#define RELAX_MIPS16_MARK_ALWAYS_EXTENDED(i) ((i) | 0x2000) -#define RELAX_MIPS16_CLEAR_ALWAYS_EXTENDED(i) ((i) & ~0x2000) +#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) /* For microMIPS code, we use relaxation similar to one we use for MIPS16 code. Some instructions that take immediate values support @@ -7422,9 +7435,12 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, symbol_append (symbol, symbol_lastP, &symbol_rootP, &symbol_lastP); offset = 0; } - add_relaxed_insn (ip, 4, 0, + add_relaxed_insn (ip, 12, 0, RELAX_MIPS16_ENCODE (*reloc_type - BFD_RELOC_UNUSED, + mips_pic != NO_PIC, + HAVE_32BIT_SYMBOLS, + mips_opts.warn_about_macros, require_unextended, require_extended, delayed_branch_p (&history[0]), history[0].mips16_absolute_jump_p), @@ -17335,6 +17351,53 @@ mips16_extended_frag (fragS *fragp, asection *sec, long stretch) return !mips16_immed_in_range_p (operand, BFD_RELOC_UNUSED, val); } +/* Given a MIPS16 variant frag FRAGP, return non-zero if it needs + macro expansion. SEC is the section the frag is in. We only + support PC-relative instructions (LA, DLA, LW, LD) here, in + non-PIC code using 32-bit addressing. */ + +static int +mips16_macro_frag (fragS *fragp, asection *sec, long stretch) +{ + const struct mips_pcrel_operand *pcrel_op; + const struct mips_int_operand *operand; + offsetT val; + segT symsec; + int type; + + gas_assert (!RELAX_MIPS16_USER_SMALL (fragp->fr_subtype)); + + if (RELAX_MIPS16_USER_EXT (fragp->fr_subtype)) + return 0; + if (!RELAX_MIPS16_SYM32 (fragp->fr_subtype)) + return 0; + + type = RELAX_MIPS16_TYPE (fragp->fr_subtype); + switch (type) + { + case 'A': + case 'B': + case 'E': + symsec = S_GET_SEGMENT (fragp->fr_symbol); + if (bfd_is_abs_section (symsec)) + return 1; + if (RELAX_MIPS16_PIC (fragp->fr_subtype)) + return 0; + if (S_FORCE_RELOC (fragp->fr_symbol, TRUE) || sec != symsec) + return 1; + + operand = mips16_immed_operand (type, TRUE); + val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset; + pcrel_op = (const struct mips_pcrel_operand *) operand; + val = mips16_pcrel_val (fragp, pcrel_op, val, stretch); + + return !mips16_immed_in_range_p (operand, BFD_RELOC_UNUSED, val); + + default: + return 0; + } +} + /* Compute the length of a branch sequence, and adjust the RELAX_BRANCH_TOOFAR bit accordingly. If FRAGP is NULL, the worst-case length is computed, with UPDATE being used to indicate @@ -17614,9 +17677,14 @@ md_estimate_size_before_relax (fragS *fragp, asection *segtype) } if (RELAX_MIPS16_P (fragp->fr_subtype)) - /* 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(). */ - return (RELAX_MIPS16_EXTENDED (fragp->fr_subtype) ? 4 : 2); + { + /* 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; + else + return RELAX_MIPS16_EXTENDED (fragp->fr_subtype) ? 4 : 2; + } if (RELAX_MICROMIPS_P (fragp->fr_subtype)) { @@ -17866,19 +17934,52 @@ mips_relax_frag (asection *sec, fragS *fragp, long stretch) if (! RELAX_MIPS16_P (fragp->fr_subtype)) return 0; - if (mips16_extended_frag (fragp, sec, stretch)) + if (!mips16_extended_frag (fragp, sec, stretch)) { - if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype)) + if (RELAX_MIPS16_MACRO (fragp->fr_subtype)) + { + fragp->fr_subtype = RELAX_MIPS16_CLEAR_MACRO (fragp->fr_subtype); + return -10; + } + else if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype)) + { + fragp->fr_subtype = RELAX_MIPS16_CLEAR_EXTENDED (fragp->fr_subtype); + return -2; + } + else + return 0; + } + else if (!mips16_macro_frag (fragp, sec, stretch)) + { + if (RELAX_MIPS16_MACRO (fragp->fr_subtype)) + { + fragp->fr_subtype = RELAX_MIPS16_CLEAR_MACRO (fragp->fr_subtype); + fragp->fr_subtype = RELAX_MIPS16_MARK_EXTENDED (fragp->fr_subtype); + return -8; + } + else if (!RELAX_MIPS16_EXTENDED (fragp->fr_subtype)) + { + fragp->fr_subtype = RELAX_MIPS16_MARK_EXTENDED (fragp->fr_subtype); + return 2; + } + else return 0; - fragp->fr_subtype = RELAX_MIPS16_MARK_EXTENDED (fragp->fr_subtype); - return 2; } else { - if (! RELAX_MIPS16_EXTENDED (fragp->fr_subtype)) + if (RELAX_MIPS16_MACRO (fragp->fr_subtype)) return 0; - fragp->fr_subtype = RELAX_MIPS16_CLEAR_EXTENDED (fragp->fr_subtype); - return -2; + else if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype)) + { + fragp->fr_subtype = RELAX_MIPS16_CLEAR_EXTENDED (fragp->fr_subtype); + fragp->fr_subtype = RELAX_MIPS16_MARK_MACRO (fragp->fr_subtype); + return 8; + } + else + { + fragp->fr_subtype = RELAX_MIPS16_MARK_MACRO (fragp->fr_subtype); + return 10; + } } return 0; @@ -18373,25 +18474,27 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp) const struct mips_int_operand *operand; offsetT val; char *buf; - unsigned int user_length, length; + unsigned int user_length; bfd_boolean need_reloc; unsigned long insn; + bfd_boolean mac; bfd_boolean ext; segT symsec; type = RELAX_MIPS16_TYPE (fragp->fr_subtype); operand = mips16_immed_operand (type, FALSE); + mac = RELAX_MIPS16_MACRO (fragp->fr_subtype); ext = RELAX_MIPS16_EXTENDED (fragp->fr_subtype); val = resolve_symbol_value (fragp->fr_symbol) + fragp->fr_offset; symsec = S_GET_SEGMENT (fragp->fr_symbol); need_reloc = (S_FORCE_RELOC (fragp->fr_symbol, TRUE) - || (operand->root.type == OP_PCREL + || (operand->root.type == OP_PCREL && !mac ? asec != symsec : !bfd_is_abs_section (symsec))); - if (operand->root.type == OP_PCREL) + if (operand->root.type == OP_PCREL && !mac) { const struct mips_pcrel_operand *pcrel_op; @@ -18416,11 +18519,21 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp) record_alignment (asec, operand->shift); } - if (ext - && (RELAX_MIPS16_JAL_DSLOT (fragp->fr_subtype) - || RELAX_MIPS16_DSLOT (fragp->fr_subtype))) + if (RELAX_MIPS16_JAL_DSLOT (fragp->fr_subtype) + || RELAX_MIPS16_DSLOT (fragp->fr_subtype)) + { + if (mac) + as_warn_where (fragp->fr_file, fragp->fr_line, + _("macro instruction expanded into multiple " + "instructions in a branch delay slot")); + else if (ext) + as_warn_where (fragp->fr_file, fragp->fr_line, + _("extended instruction in a branch delay slot")); + } + else if (RELAX_MIPS16_NOMACRO (fragp->fr_subtype) && mac) as_warn_where (fragp->fr_file, fragp->fr_line, - _("extended instruction in delay slot")); + _("macro instruction expanded into multiple " + "instructions")); buf = fragp->fr_literal + fragp->fr_fix; @@ -18435,49 +18548,120 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp) else user_length = 0; - if (need_reloc) + if (mac) { - bfd_reloc_code_real_type reloc = BFD_RELOC_NONE; - expressionS exp; - fixS *fixp; + unsigned long reg; + unsigned long new; + unsigned long op; + + gas_assert (type == 'A' || type == 'B' || type == 'E'); + gas_assert (RELAX_MIPS16_SYM32 (fragp->fr_subtype)); - switch (type) + if (need_reloc) { - case 'p': - case 'q': - reloc = BFD_RELOC_MIPS16_16_PCREL_S1; + fixS *fixp; + + gas_assert (!RELAX_MIPS16_PIC (fragp->fr_subtype)); + + fixp = fix_new (fragp, buf - fragp->fr_literal, 4, + fragp->fr_symbol, fragp->fr_offset, + FALSE, BFD_RELOC_MIPS16_HI16_S); + fixp->fx_file = fragp->fr_file; + fixp->fx_line = fragp->fr_line; + + fixp = fix_new (fragp, buf - fragp->fr_literal + 8, 4, + fragp->fr_symbol, fragp->fr_offset, + FALSE, BFD_RELOC_MIPS16_LO16); + fixp->fx_file = fragp->fr_file; + fixp->fx_line = fragp->fr_line; + + val = 0; + } + + switch (insn & 0xf800) + { + case 0x0800: /* ADDIU */ + reg = (insn >> 8) & 0x7; + op = 0xf0004800 | (reg << 8); break; - default: - as_bad_where (fragp->fr_file, fragp->fr_line, - _("unsupported relocation")); + case 0xb000: /* LW */ + reg = (insn >> 8) & 0x7; + op = 0xf0009800 | (reg << 8) | (reg << 5); break; + case 0xf800: /* I64 */ + reg = (insn >> 5) & 0x7; + switch (insn & 0x0700) + { + case 0x0400: /* LD */ + op = 0xf0003800 | (reg << 8) | (reg << 5); + break; + case 0x0600: /* DADDIU */ + op = 0xf000fd00 | (reg << 5); + break; + default: + abort (); + } + break; + default: + abort (); } - if (reloc == BFD_RELOC_NONE) - ; - else if (ext) + + new = 0xf0006800 | (reg << 8); /* 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); + op |= mips16_immed_extend (val, 16); + buf = write_compressed_insn (buf, op, 4); + + fragp->fr_fix += 12; + } + else + { + unsigned int length = ext ? 4 : 2; + + if (need_reloc) { - exp.X_op = O_symbol; - exp.X_add_symbol = fragp->fr_symbol; - exp.X_add_number = fragp->fr_offset; + bfd_reloc_code_real_type reloc = BFD_RELOC_NONE; + expressionS exp; + fixS *fixp; - fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp, - TRUE, reloc); + switch (type) + { + case 'p': + case 'q': + reloc = BFD_RELOC_MIPS16_16_PCREL_S1; + break; + default: + break; + } + if (mac || reloc == BFD_RELOC_NONE) + as_bad_where (fragp->fr_file, fragp->fr_line, + _("unsupported relocation")); + else if (ext) + { + exp.X_op = O_symbol; + exp.X_add_symbol = fragp->fr_symbol; + exp.X_add_number = fragp->fr_offset; - fixp->fx_file = fragp->fr_file; - fixp->fx_line = fragp->fr_line; + fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp, + TRUE, reloc); + + fixp->fx_file = fragp->fr_file; + fixp->fx_line = fragp->fr_line; + } + else + as_bad_where (fragp->fr_file, fragp->fr_line, + _("invalid unextended operand value")); } else - as_bad_where (fragp->fr_file, fragp->fr_line, - _("invalid unextended operand value")); - } - else - mips16_immed (fragp->fr_file, fragp->fr_line, type, - BFD_RELOC_UNUSED, val, user_length, &insn); + mips16_immed (fragp->fr_file, fragp->fr_line, type, + BFD_RELOC_UNUSED, val, user_length, &insn); - length = (ext ? 4 : 2); - gas_assert (mips16_opcode_length (insn) == length); - write_compressed_insn (buf, insn, length); - fragp->fr_fix += length; + gas_assert (mips16_opcode_length (insn) == length); + write_compressed_insn (buf, insn, length); + fragp->fr_fix += length; + } } else { |