diff options
author | Richard Sandiford <rdsandiford@googlemail.com> | 2013-07-07 11:32:32 +0000 |
---|---|---|
committer | Richard Sandiford <rdsandiford@googlemail.com> | 2013-07-07 11:32:32 +0000 |
commit | f2ae14a1cc3f5349d6c99417c1cbe2ca3b0fabe5 (patch) | |
tree | c59b2486103f55a7f04726252e2ac9f11aab53c5 /gas/config/tc-mips.c | |
parent | d070d2a2539dd2bca2710172969e73ae2c5f43af (diff) | |
download | gdb-f2ae14a1cc3f5349d6c99417c1cbe2ca3b0fabe5.zip gdb-f2ae14a1cc3f5349d6c99417c1cbe2ca3b0fabe5.tar.gz gdb-f2ae14a1cc3f5349d6c99417c1cbe2ca3b0fabe5.tar.bz2 |
include/opcode/
* mips.h (M_ACLR_OB, M_ASET_OB, M_CACHE_OB, M_CACHEE_OB, M_L_DOB)
(M_LB_A, M_LBE_OB, M_LBU_A, M_LBUE_OB, M_LD_A, M_LD_OB, M_LDC2_OB)
(M_LDL_OB, M_LDM_OB, M_LDP_OB, M_LDR_OB, M_LH_A, M_LHE_OB, M_LHU_A)
(M_LHUE_OB, M_LL_OB, M_LLD_OB, M_LLE_OB, M_LS_A, M_LW_A, M_LWE_OB)
(M_LWC0_A, M_LWC1_A, M_LWC2_A, M_LWC2_OB, M_LWC3_A, M_LWL_A, M_LWL_OB)
(M_LWLE_OB, M_LWM_OB, M_LWP_OB, M_LWR_A, M_LWR_OB, M_LWRE_OB, M_LWU_OB)
(M_PREF_OB, M_PREFE_OB, M_S_DOB, M_SAA_OB, M_SAAD_OB, M_SC_OB)
(M_SCD_OB, M_SCE_OB, M_SD_A, M_SD_OB, M_SDC2_OB, M_SDL_OB, M_SDM_OB)
(M_SDP_OB, M_SDR_OB, M_SB_A, M_SBE_OB, M_SH_A, M_SHE_OB, M_SW_A)
(M_SWE_OB, M_SWC0_A, M_SWC1_A, M_SWC2_A, M_SWC2_OB, M_SWC3_A, M_SWL_A)
(M_SWL_OB, M_SWLE_OB, M_SWM_OB, M_SWP_OB, M_SWR_A, M_SWR_OB, M_SWRE_OB)
(M_ULD, M_ULH, M_ULHU, M_ULW, M_USH, M_USW, M_USD): Delete.
(M_ULD_A, M_ULH_A, M_ULHU_A, M_ULW_A, M_USH_A, M_USW_A, M_USD_A):
Rename to...
(M_ULD_AB, M_ULH_AB, M_ULHU_AB, M_ULW_AB, M_USH_AB, M_USW_AB)
(M_USD_AB): ...these.
opcodes/
* mips-opc.c (mips_builtin_opcodes): Remove o(b) macros. Move LD
and SD A(B) macros up.
* micromips-opc.c (micromips_opcodes): Likewise.
gas/
* config/tc-mips.c (gprel16_reloc_p): New function.
(macro_read_relocs): Assume BFD_RELOC_LO16 if all relocs are
BFD_RELOC_UNUSED.
(offset_high_part, small_offset_p): New functions.
(nacro): Use them. Remove *_OB and *_DOB cases. For single-
register load and store macros, handle the 16-bit offset case first.
If a 16-bit offset is not suitable for the instruction we're
generating, load it into the temporary register using
ADDRESS_ADDI_INSN. Make the M_LI_DD code fall through into the
M_L_DAB code once the address has been constructed. For double load
and store macros, again handle the 16-bit offset case first.
If the second register cannot be accessed from the same high
part as the first, load it into AT using ADDRESS_ADDI_INSN.
Fix the handling of LD in cases where the first register is the
same as the base. Also handle the case where the offset is
not 16 bits and the second register cannot be accessed from the
same high part as the first. For unaligned loads and stores,
fuse the offbits == 12 and old "ab" handling. Apply this handling
whenever the second offset needs a different high part from the first.
Construct the offset using ADDRESS_ADDI_INSN where possible,
for offbits == 16 as well as offbits == 12. Use offset_reloc
when constructing the individual loads and stores.
(mips_ip): Set up imm_expr, imm2_expr, offset_expr, imm_reloc
and offset_reloc before matching against a particular opcode.
Handle elided 'A' constants. Allow 'A' constants to use
relocation operators.
gas/testsuite/
* gas/mips/ldstla-32.d: Avoid "lui at,0x0" sequences for
truncated constants.
* gas/mips/ldstla-32-shared.d: Likewise.
* gas/mips/mcu.d: Use ADDIU in preference to LI+ADDU when adding
16-bit constants to the base.
* gas/mips/micromips@mcu.d: Likewise.
* gas/mips/micromips@cache.d: Likewise.
* gas/mips/micromips@pref.d: Likewise.
* gas/mips/micromips.d, gas/mips/micromips-insn32.d,
gas/mips/micromips-noinsn32.d, gas/mips/micromips-trap.d: Likewise.
Allow the full 16-bit offset range to be used for SB, LB and LBU in
USH and ULH sequences. Fix the expected output for LD and SD when
the two LW and SW offsets need different high parts.
* gas/mips/eva.s: Test PREFE with relocation operators.
* gas/mips/eva.d: Use ADDIU in preference to LI+ADDU for 16-bit
constants. Update after eva.s change.
* gas/mips/micromips@eva.d: Likewise.
* gas/mips/ld-reloc.s, gas/mips/ld-reloc.d, gas/mips/l_d-reloc.s,
gas/mips/l_d-reloc.d, gas/mips/ulw-reloc.s, gas/mips/ulw-reloc.d,
gas/mips/micromips@ulw-reloc.d, gas/mips/ulh-reloc.s,
gas/mips/ulh-reloc.d: New tests.
* gas/mips/mips.exp: Run them.
Diffstat (limited to 'gas/config/tc-mips.c')
-rw-r--r-- | gas/config/tc-mips.c | 562 |
1 files changed, 246 insertions, 316 deletions
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index 8fdb124..5c6424e 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -3096,6 +3096,13 @@ jalr_reloc_p (bfd_reloc_code_real_type reloc) return reloc == BFD_RELOC_MIPS_JALR || reloc == BFD_RELOC_MICROMIPS_JALR; } +static inline bfd_boolean +gprel16_reloc_p (bfd_reloc_code_real_type reloc) +{ + return (reloc == BFD_RELOC_GPREL16 || reloc == BFD_RELOC_MIPS16_GPREL + || reloc == BFD_RELOC_MICROMIPS_GPREL16); +} + /* Return true if RELOC is a PC-relative relocation that does not have full address range. */ @@ -5265,8 +5272,15 @@ macro_read_relocs (va_list *args, bfd_reloc_code_real_type *r) if (next >= 0) r[0] = (bfd_reloc_code_real_type) next; else - for (i = 0; i < 3; i++) - r[i] = (bfd_reloc_code_real_type) va_arg (*args, int); + { + for (i = 0; i < 3; i++) + r[i] = (bfd_reloc_code_real_type) va_arg (*args, int); + /* This function is only used for 16-bit relocation fields. + To make the macro code simpler, treat an unrelocated value + in the same way as BFD_RELOC_LO16. */ + if (r[0] == BFD_RELOC_UNUSED) + r[0] = BFD_RELOC_LO16; + } } /* Build an instruction created by a macro expansion. This is passed @@ -6734,6 +6748,48 @@ macro_build_branch_rsrt (int type, expressionS *ep, macro_build (ep, br, "s,t,p", sreg, treg); } +/* Return the high part that should be loaded in order to make the low + part of VALUE accessible using an offset of OFFBITS bits. */ + +static offsetT +offset_high_part (offsetT value, unsigned int offbits) +{ + offsetT bias; + addressT low_mask; + + if (offbits == 0) + return value; + bias = 1 << (offbits - 1); + low_mask = bias * 2 - 1; + return (value + bias) & ~low_mask; +} + +/* Return true if the value stored in offset_expr and offset_reloc + fits into a signed offset of OFFBITS bits. RANGE is the maximum + amount that the caller wants to add without inducing overflow + and ALIGN is the known alignment of the value in bytes. */ + +static bfd_boolean +small_offset_p (unsigned int range, unsigned int align, unsigned int offbits) +{ + if (offbits == 16) + { + /* Accept any relocation operator if overflow isn't a concern. */ + if (range < align && *offset_reloc != BFD_RELOC_UNUSED) + return TRUE; + + /* These relocations are guaranteed not to overflow in correct links. */ + if (*offset_reloc == BFD_RELOC_MIPS_LITERAL + || gprel16_reloc_p (*offset_reloc)) + return TRUE; + } + if (offset_expr.X_op == O_constant + && offset_high_part (offset_expr.X_add_number, offbits) == 0 + && offset_high_part (offset_expr.X_add_number + range, offbits) == 0) + return TRUE; + return FALSE; +} + /* * Build macros * This routine implements the seemingly endless macro or synthesized @@ -6774,10 +6830,10 @@ macro (struct mips_cl_insn *ip, char *str) int imm = 0; int ust = 0; int lp = 0; - int ab = 0; + bfd_boolean large_offset; int off; - bfd_reloc_code_real_type r; int hold_mips_optimize; + unsigned int align; gas_assert (! mips_opts.mips16); @@ -6795,6 +6851,7 @@ macro (struct mips_cl_insn *ip, char *str) expr1.X_op_symbol = NULL; expr1.X_add_symbol = NULL; expr1.X_add_number = 1; + align = 1; switch (mask) { @@ -7540,12 +7597,10 @@ macro (struct mips_cl_insn *ip, char *str) if (!dbl && HAVE_64BIT_OBJECTS) as_warn (_("la used to load 64-bit address")); - if (offset_expr.X_op == O_constant - && offset_expr.X_add_number >= -0x8000 - && offset_expr.X_add_number < 0x8000) + if (small_offset_p (0, align, 16)) { - macro_build (&offset_expr, ADDRESS_ADDI_INSN, - "t,r,j", treg, sreg, BFD_RELOC_LO16); + macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", treg, breg, + -1, offset_reloc[0], offset_reloc[1], offset_reloc[2]); break; } @@ -8397,146 +8452,108 @@ macro (struct mips_cl_insn *ip, char *str) break; case M_LBUE_AB: - ab = 1; - case M_LBUE_OB: s = "lbue"; fmt = "t,+j(b)"; offbits = 9; goto ld_st; case M_LHUE_AB: - ab = 1; - case M_LHUE_OB: s = "lhue"; fmt = "t,+j(b)"; offbits = 9; goto ld_st; case M_LBE_AB: - ab = 1; - case M_LBE_OB: s = "lbe"; fmt = "t,+j(b)"; offbits = 9; goto ld_st; case M_LHE_AB: - ab = 1; - case M_LHE_OB: s = "lhe"; fmt = "t,+j(b)"; offbits = 9; goto ld_st; case M_LLE_AB: - ab = 1; - case M_LLE_OB: s = "lle"; fmt = "t,+j(b)"; offbits = 9; goto ld_st; case M_LWE_AB: - ab = 1; - case M_LWE_OB: s = "lwe"; fmt = "t,+j(b)"; offbits = 9; goto ld_st; case M_LWLE_AB: - ab = 1; - case M_LWLE_OB: s = "lwle"; fmt = "t,+j(b)"; offbits = 9; goto ld_st; case M_LWRE_AB: - ab = 1; - case M_LWRE_OB: s = "lwre"; fmt = "t,+j(b)"; offbits = 9; goto ld_st; case M_SBE_AB: - ab = 1; - case M_SBE_OB: s = "sbe"; fmt = "t,+j(b)"; offbits = 9; goto ld_st; case M_SCE_AB: - ab = 1; - case M_SCE_OB: s = "sce"; fmt = "t,+j(b)"; offbits = 9; goto ld_st; case M_SHE_AB: - ab = 1; - case M_SHE_OB: s = "she"; fmt = "t,+j(b)"; offbits = 9; goto ld_st; case M_SWE_AB: - ab = 1; - case M_SWE_OB: s = "swe"; fmt = "t,+j(b)"; offbits = 9; goto ld_st; case M_SWLE_AB: - ab = 1; - case M_SWLE_OB: s = "swle"; fmt = "t,+j(b)"; offbits = 9; goto ld_st; case M_SWRE_AB: - ab = 1; - case M_SWRE_OB: s = "swre"; fmt = "t,+j(b)"; offbits = 9; goto ld_st; case M_ACLR_AB: - ab = 1; - case M_ACLR_OB: s = "aclr"; treg = EXTRACT_OPERAND (mips_opts.micromips, 3BITPOS, *ip); fmt = "\\,~(b)"; offbits = 12; goto ld_st; case M_ASET_AB: - ab = 1; - case M_ASET_OB: s = "aset"; treg = EXTRACT_OPERAND (mips_opts.micromips, 3BITPOS, *ip); fmt = "\\,~(b)"; offbits = 12; goto ld_st; case M_LB_AB: - ab = 1; s = "lb"; fmt = "t,o(b)"; goto ld; case M_LBU_AB: - ab = 1; s = "lbu"; fmt = "t,o(b)"; goto ld; case M_LH_AB: - ab = 1; s = "lh"; fmt = "t,o(b)"; goto ld; case M_LHU_AB: - ab = 1; s = "lhu"; fmt = "t,o(b)"; goto ld; case M_LW_AB: - ab = 1; s = "lw"; fmt = "t,o(b)"; goto ld; case M_LWC0_AB: - ab = 1; gas_assert (!mips_opts.micromips); s = "lwc0"; fmt = "E,o(b)"; @@ -8544,15 +8561,12 @@ macro (struct mips_cl_insn *ip, char *str) coproc = 1; goto ld_st; case M_LWC1_AB: - ab = 1; s = "lwc1"; fmt = "T,o(b)"; /* Itbl support may require additional care here. */ coproc = 1; goto ld_st; case M_LWC2_AB: - ab = 1; - case M_LWC2_OB: s = "lwc2"; fmt = COP12_FMT; offbits = (mips_opts.micromips ? 12 : 16); @@ -8560,7 +8574,6 @@ macro (struct mips_cl_insn *ip, char *str) coproc = 1; goto ld_st; case M_LWC3_AB: - ab = 1; gas_assert (!mips_opts.micromips); s = "lwc3"; fmt = "E,o(b)"; @@ -8568,29 +8581,22 @@ macro (struct mips_cl_insn *ip, char *str) coproc = 1; goto ld_st; case M_LWL_AB: - ab = 1; - case M_LWL_OB: s = "lwl"; fmt = MEM12_FMT; offbits = (mips_opts.micromips ? 12 : 16); goto ld_st; case M_LWR_AB: - ab = 1; - case M_LWR_OB: s = "lwr"; fmt = MEM12_FMT; offbits = (mips_opts.micromips ? 12 : 16); goto ld_st; case M_LDC1_AB: - ab = 1; s = "ldc1"; fmt = "T,o(b)"; /* Itbl support may require additional care here. */ coproc = 1; goto ld_st; case M_LDC2_AB: - ab = 1; - case M_LDC2_OB: s = "ldc2"; fmt = COP12_FMT; offbits = (mips_opts.micromips ? 12 : 16); @@ -8598,57 +8604,43 @@ macro (struct mips_cl_insn *ip, char *str) coproc = 1; goto ld_st; case M_LQC2_AB: - ab = 1; s = "lqc2"; fmt = "E,o(b)"; /* Itbl support may require additional care here. */ coproc = 1; goto ld_st; case M_LDC3_AB: - ab = 1; s = "ldc3"; fmt = "E,o(b)"; /* Itbl support may require additional care here. */ coproc = 1; goto ld_st; case M_LDL_AB: - ab = 1; - case M_LDL_OB: s = "ldl"; fmt = MEM12_FMT; offbits = (mips_opts.micromips ? 12 : 16); goto ld_st; case M_LDR_AB: - ab = 1; - case M_LDR_OB: s = "ldr"; fmt = MEM12_FMT; offbits = (mips_opts.micromips ? 12 : 16); goto ld_st; case M_LL_AB: - ab = 1; - case M_LL_OB: s = "ll"; fmt = MEM12_FMT; offbits = (mips_opts.micromips ? 12 : 16); goto ld; case M_LLD_AB: - ab = 1; - case M_LLD_OB: s = "lld"; fmt = MEM12_FMT; offbits = (mips_opts.micromips ? 12 : 16); goto ld; case M_LWU_AB: - ab = 1; - case M_LWU_OB: s = "lwu"; fmt = MEM12_FMT; offbits = (mips_opts.micromips ? 12 : 16); goto ld; case M_LWP_AB: - ab = 1; - case M_LWP_OB: gas_assert (mips_opts.micromips); s = "lwp"; fmt = "t,~(b)"; @@ -8656,8 +8648,6 @@ macro (struct mips_cl_insn *ip, char *str) lp = 1; goto ld; case M_LDP_AB: - ab = 1; - case M_LDP_OB: gas_assert (mips_opts.micromips); s = "ldp"; fmt = "t,~(b)"; @@ -8665,16 +8655,12 @@ macro (struct mips_cl_insn *ip, char *str) lp = 1; goto ld; case M_LWM_AB: - ab = 1; - case M_LWM_OB: gas_assert (mips_opts.micromips); s = "lwm"; fmt = "n,~(b)"; offbits = 12; goto ld_st; case M_LDM_AB: - ab = 1; - case M_LDM_OB: gas_assert (mips_opts.micromips); s = "ldm"; fmt = "n,~(b)"; @@ -8690,22 +8676,18 @@ macro (struct mips_cl_insn *ip, char *str) goto ld_noat; case M_SB_AB: - ab = 1; s = "sb"; fmt = "t,o(b)"; goto ld_st; case M_SH_AB: - ab = 1; s = "sh"; fmt = "t,o(b)"; goto ld_st; case M_SW_AB: - ab = 1; s = "sw"; fmt = "t,o(b)"; goto ld_st; case M_SWC0_AB: - ab = 1; gas_assert (!mips_opts.micromips); s = "swc0"; fmt = "E,o(b)"; @@ -8713,15 +8695,12 @@ macro (struct mips_cl_insn *ip, char *str) coproc = 1; goto ld_st; case M_SWC1_AB: - ab = 1; s = "swc1"; fmt = "T,o(b)"; /* Itbl support may require additional care here. */ coproc = 1; goto ld_st; case M_SWC2_AB: - ab = 1; - case M_SWC2_OB: s = "swc2"; fmt = COP12_FMT; offbits = (mips_opts.micromips ? 12 : 16); @@ -8729,7 +8708,6 @@ macro (struct mips_cl_insn *ip, char *str) coproc = 1; goto ld_st; case M_SWC3_AB: - ab = 1; gas_assert (!mips_opts.micromips); s = "swc3"; fmt = "E,o(b)"; @@ -8737,71 +8715,52 @@ macro (struct mips_cl_insn *ip, char *str) coproc = 1; goto ld_st; case M_SWL_AB: - ab = 1; - case M_SWL_OB: s = "swl"; fmt = MEM12_FMT; offbits = (mips_opts.micromips ? 12 : 16); goto ld_st; case M_SWR_AB: - ab = 1; - case M_SWR_OB: s = "swr"; fmt = MEM12_FMT; offbits = (mips_opts.micromips ? 12 : 16); goto ld_st; case M_SC_AB: - ab = 1; - case M_SC_OB: s = "sc"; fmt = MEM12_FMT; offbits = (mips_opts.micromips ? 12 : 16); goto ld_st; case M_SCD_AB: - ab = 1; - case M_SCD_OB: s = "scd"; fmt = MEM12_FMT; offbits = (mips_opts.micromips ? 12 : 16); goto ld_st; case M_CACHE_AB: - ab = 1; - case M_CACHE_OB: s = "cache"; fmt = mips_opts.micromips ? "k,~(b)" : "k,o(b)"; offbits = (mips_opts.micromips ? 12 : 16); goto ld_st; case M_CACHEE_AB: - ab = 1; - case M_CACHEE_OB: s = "cachee"; fmt = "k,+j(b)"; offbits = 9; goto ld_st; case M_PREF_AB: - ab = 1; - case M_PREF_OB: s = "pref"; fmt = !mips_opts.micromips ? "k,o(b)" : "k,~(b)"; offbits = (mips_opts.micromips ? 12 : 16); goto ld_st; case M_PREFE_AB: - ab = 1; - case M_PREFE_OB: s = "prefe"; fmt = "k,+j(b)"; offbits = 9; goto ld_st; case M_SDC1_AB: - ab = 1; s = "sdc1"; fmt = "T,o(b)"; coproc = 1; /* Itbl support may require additional care here. */ goto ld_st; case M_SDC2_AB: - ab = 1; - case M_SDC2_OB: s = "sdc2"; fmt = COP12_FMT; offbits = (mips_opts.micromips ? 12 : 16); @@ -8809,14 +8768,12 @@ macro (struct mips_cl_insn *ip, char *str) coproc = 1; goto ld_st; case M_SQC2_AB: - ab = 1; s = "sqc2"; fmt = "E,o(b)"; /* Itbl support may require additional care here. */ coproc = 1; goto ld_st; case M_SDC3_AB: - ab = 1; gas_assert (!mips_opts.micromips); s = "sdc3"; fmt = "E,o(b)"; @@ -8824,46 +8781,34 @@ macro (struct mips_cl_insn *ip, char *str) coproc = 1; goto ld_st; case M_SDL_AB: - ab = 1; - case M_SDL_OB: s = "sdl"; fmt = MEM12_FMT; offbits = (mips_opts.micromips ? 12 : 16); goto ld_st; case M_SDR_AB: - ab = 1; - case M_SDR_OB: s = "sdr"; fmt = MEM12_FMT; offbits = (mips_opts.micromips ? 12 : 16); goto ld_st; case M_SWP_AB: - ab = 1; - case M_SWP_OB: gas_assert (mips_opts.micromips); s = "swp"; fmt = "t,~(b)"; offbits = 12; goto ld_st; case M_SDP_AB: - ab = 1; - case M_SDP_OB: gas_assert (mips_opts.micromips); s = "sdp"; fmt = "t,~(b)"; offbits = 12; goto ld_st; case M_SWM_AB: - ab = 1; - case M_SWM_OB: gas_assert (mips_opts.micromips); s = "swm"; fmt = "n,~(b)"; offbits = 12; goto ld_st; case M_SDM_AB: - ab = 1; - case M_SDM_OB: gas_assert (mips_opts.micromips); s = "sdm"; fmt = "n,~(b)"; @@ -8871,8 +8816,41 @@ macro (struct mips_cl_insn *ip, char *str) ld_st: tempreg = AT; - used_at = 1; ld_noat: + if (small_offset_p (0, align, 16)) + { + /* The first case exists for M_LD_AB and M_SD_AB, which are + macros for o32 but which should act like normal instructions + otherwise. */ + if (offbits == 16) + macro_build (&offset_expr, s, fmt, treg, -1, offset_reloc[0], + offset_reloc[1], offset_reloc[2], breg); + else if (small_offset_p (0, align, offbits)) + { + if (offbits == 0) + macro_build (NULL, s, fmt, treg, breg); + else + macro_build (NULL, s, fmt, treg, + (unsigned long) offset_expr.X_add_number, breg); + } + else + { + if (tempreg == AT) + used_at = 1; + macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", + tempreg, breg, -1, offset_reloc[0], + offset_reloc[1], offset_reloc[2]); + if (offbits == 0) + macro_build (NULL, s, fmt, treg, tempreg); + else + macro_build (NULL, s, fmt, treg, 0L, tempreg); + } + break; + } + + if (tempreg == AT) + used_at = 1; + if (offset_expr.X_op != O_constant && offset_expr.X_op != O_symbol) { @@ -8893,79 +8871,40 @@ macro (struct mips_cl_insn *ip, char *str) is in non PIC code. */ if (offset_expr.X_op == O_constant) { - int hipart = 0; + expr1.X_add_number = offset_high_part (offset_expr.X_add_number, + offbits == 0 ? 16 : offbits); + offset_expr.X_add_number -= expr1.X_add_number; - expr1.X_add_number = offset_expr.X_add_number; - normalize_address_expr (&expr1); - if ((offbits == 0 || offbits == 16) - && !IS_SEXT_16BIT_NUM (expr1.X_add_number)) - { - expr1.X_add_number = ((expr1.X_add_number + 0x8000) - & ~(bfd_vma) 0xffff); - hipart = 1; - } - else if (offbits == 12 && !IS_SEXT_12BIT_NUM (expr1.X_add_number)) - { - expr1.X_add_number = ((expr1.X_add_number + 0x800) - & ~(bfd_vma) 0xfff); - hipart = 1; - } - else if (offbits == 9 && !IS_SEXT_9BIT_NUM (expr1.X_add_number)) - { - expr1.X_add_number = ((expr1.X_add_number + 0x100) - & ~(bfd_vma) 0x1ff); - hipart = 1; - } - if (hipart) - { - load_register (tempreg, &expr1, HAVE_64BIT_ADDRESSES); - if (breg != 0) - macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", - tempreg, tempreg, breg); - breg = tempreg; - } + load_register (tempreg, &expr1, HAVE_64BIT_ADDRESSES); + if (breg != 0) + macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", + tempreg, tempreg, breg); if (offbits == 0) { - if (offset_expr.X_add_number == 0) - tempreg = breg; - else + if (offset_expr.X_add_number != 0) macro_build (&offset_expr, ADDRESS_ADDI_INSN, - "t,r,j", tempreg, breg, BFD_RELOC_LO16); + "t,r,j", tempreg, tempreg, BFD_RELOC_LO16); macro_build (NULL, s, fmt, treg, tempreg); } else if (offbits == 16) - macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16, breg); + macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16, tempreg); else - macro_build (NULL, s, fmt, - treg, (unsigned long) offset_expr.X_add_number, breg); + macro_build (NULL, s, fmt, treg, + (unsigned long) offset_expr.X_add_number, tempreg); } else if (offbits != 16) { /* The offset field is too narrow to be used for a low-part relocation, so load the whole address into the auxillary - register. In the case of "A(b)" addresses, we first load - absolute address "A" into the register and then add base - register "b". In the case of "o(b)" addresses, we simply - need to add 16-bit offset "o" to base register "b", and - offset_reloc already contains the relocations associated - with "o". */ - if (ab) - { - load_address (tempreg, &offset_expr, &used_at); - if (breg != 0) - macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", - tempreg, tempreg, breg); - } - else - macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", - tempreg, breg, -1, - offset_reloc[0], offset_reloc[1], offset_reloc[2]); - expr1.X_add_number = 0; + register. */ + load_address (tempreg, &offset_expr, &used_at); + if (breg != 0) + macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", + tempreg, tempreg, breg); if (offbits == 0) macro_build (NULL, s, fmt, treg, tempreg); else - macro_build (NULL, s, fmt, - treg, (unsigned long) expr1.X_add_number, tempreg); + macro_build (NULL, s, fmt, treg, 0L, tempreg); } else if (mips_pic == NO_PIC) { @@ -9423,16 +9362,11 @@ macro (struct mips_cl_insn *ip, char *str) && offset_expr.X_add_number == 0); s = segment_name (S_GET_SEGMENT (offset_expr.X_add_symbol)); if (strcmp (s, ".lit8") == 0) - { - if (CPU_HAS_LDC1_SDC1 (mips_opts.arch) || mips_opts.micromips) - { - macro_build (&offset_expr, "ldc1", "T,o(b)", treg, - BFD_RELOC_MIPS_LITERAL, mips_gp_register); - break; - } - breg = mips_gp_register; - r = BFD_RELOC_MIPS_LITERAL; - goto dob; + { + breg = mips_gp_register; + offset_reloc[0] = BFD_RELOC_MIPS_LITERAL; + offset_reloc[1] = BFD_RELOC_UNUSED; + offset_reloc[2] = BFD_RELOC_UNUSED; } else { @@ -9447,47 +9381,15 @@ macro (struct mips_cl_insn *ip, char *str) macro_build_lui (&offset_expr, AT); } - if (CPU_HAS_LDC1_SDC1 (mips_opts.arch) || mips_opts.micromips) - { - macro_build (&offset_expr, "ldc1", "T,o(b)", - treg, BFD_RELOC_LO16, AT); - break; - } breg = AT; - r = BFD_RELOC_LO16; - goto dob; - } - - case M_L_DOB: - /* Even on a big endian machine $fn comes before $fn+1. We have - to adjust when loading from memory. */ - r = BFD_RELOC_LO16; - dob: - gas_assert (!mips_opts.micromips); - gas_assert (!CPU_HAS_LDC1_SDC1 (mips_opts.arch)); - macro_build (&offset_expr, "lwc1", "T,o(b)", - target_big_endian ? treg + 1 : treg, r, breg); - /* FIXME: A possible overflow which I don't know how to deal - with. */ - offset_expr.X_add_number += 4; - macro_build (&offset_expr, "lwc1", "T,o(b)", - target_big_endian ? treg : treg + 1, r, breg); - break; - - case M_S_DOB: - gas_assert (!mips_opts.micromips); - gas_assert (!CPU_HAS_LDC1_SDC1 (mips_opts.arch)); - /* Even on a big endian machine $fn comes before $fn+1. We have - to adjust when storing to memory. */ - macro_build (&offset_expr, "swc1", "T,o(b)", - target_big_endian ? treg + 1 : treg, BFD_RELOC_LO16, breg); - offset_expr.X_add_number += 4; - macro_build (&offset_expr, "swc1", "T,o(b)", - target_big_endian ? treg : treg + 1, BFD_RELOC_LO16, breg); - break; + offset_reloc[0] = BFD_RELOC_LO16; + offset_reloc[1] = BFD_RELOC_UNUSED; + offset_reloc[2] = BFD_RELOC_UNUSED; + } + align = 8; + /* Fall through */ case M_L_DAB: - gas_assert (!mips_opts.micromips); /* * The MIPS assembler seems to check for X_add_number not * being double aligned and generating: @@ -9553,6 +9455,51 @@ macro (struct mips_cl_insn *ip, char *str) s = "sw"; ldd_std: + /* Even on a big endian machine $fn comes before $fn+1. We have + to adjust when loading from memory. We set coproc if we must + load $fn+1 first. */ + /* Itbl support may require additional care here. */ + if (!target_big_endian) + coproc = 0; + + if (small_offset_p (0, align, 16)) + { + ep = &offset_expr; + if (!small_offset_p (4, align, 16)) + { + macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", AT, breg, + -1, offset_reloc[0], offset_reloc[1], + offset_reloc[2]); + expr1.X_add_number = 0; + ep = &expr1; + breg = AT; + used_at = 1; + offset_reloc[0] = BFD_RELOC_LO16; + offset_reloc[1] = BFD_RELOC_UNUSED; + offset_reloc[2] = BFD_RELOC_UNUSED; + } + if (strcmp (s, "lw") == 0 && treg == breg) + { + ep->X_add_number += 4; + macro_build (ep, s, fmt, treg + 1, -1, offset_reloc[0], + offset_reloc[1], offset_reloc[2], breg); + ep->X_add_number -= 4; + macro_build (ep, s, fmt, treg, -1, offset_reloc[0], + offset_reloc[1], offset_reloc[2], breg); + } + else + { + macro_build (ep, s, fmt, coproc ? treg + 1 : treg, -1, + offset_reloc[0], offset_reloc[1], offset_reloc[2], + breg); + ep->X_add_number += 4; + macro_build (ep, s, fmt, coproc ? treg : treg + 1, -1, + offset_reloc[0], offset_reloc[1], offset_reloc[2], + breg); + } + break; + } + if (offset_expr.X_op != O_symbol && offset_expr.X_op != O_constant) { @@ -9569,13 +9516,6 @@ macro (struct mips_cl_insn *ip, char *str) as_bad (_("Number (0x%s) larger than 32 bits"), value); } - /* Even on a big endian machine $fn comes before $fn+1. We have - to adjust when loading from memory. We set coproc if we must - load $fn+1 first. */ - /* Itbl support may require additional care here. */ - if (!target_big_endian) - coproc = 0; - if (mips_pic == NO_PIC || offset_expr.X_op == O_constant) { /* If this is a reference to a GP relative symbol, we want @@ -9628,7 +9568,15 @@ macro (struct mips_cl_insn *ip, char *str) offset_expr.X_add_number -= 4; } used_at = 1; - macro_build_lui (&offset_expr, AT); + if (offset_high_part (offset_expr.X_add_number, 16) + != offset_high_part (offset_expr.X_add_number + 4, 16)) + { + load_address (AT, &offset_expr, &used_at); + offset_expr.X_op = O_constant; + offset_expr.X_add_number = 0; + } + else + macro_build_lui (&offset_expr, AT); if (breg != 0) macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, breg, AT); /* Itbl support may require additional care here. */ @@ -9768,36 +9716,13 @@ macro (struct mips_cl_insn *ip, char *str) abort (); break; - - case M_LD_OB: - s = HAVE_64BIT_GPRS ? "ld" : "lw"; - goto sd_ob; - case M_SD_OB: - s = HAVE_64BIT_GPRS ? "sd" : "sw"; - sd_ob: - macro_build (&offset_expr, s, "t,o(b)", treg, - -1, offset_reloc[0], offset_reloc[1], offset_reloc[2], - breg); - if (!HAVE_64BIT_GPRS) - { - offset_expr.X_add_number += 4; - macro_build (&offset_expr, s, "t,o(b)", treg + 1, - -1, offset_reloc[0], offset_reloc[1], offset_reloc[2], - breg); - } - break; - case M_SAA_AB: - ab = 1; - case M_SAA_OB: s = "saa"; offbits = 0; fmt = "t,(b)"; goto ld_st; case M_SAAD_AB: - ab = 1; - case M_SAAD_OB: s = "saad"; offbits = 0; fmt = "t,(b)"; @@ -10453,56 +10378,42 @@ macro (struct mips_cl_insn *ip, char *str) end_noreorder (); break; - case M_ULH_A: - ab = 1; - case M_ULH: + case M_ULH_AB: s = "lb"; s2 = "lbu"; off = 1; goto uld_st; - case M_ULHU_A: - ab = 1; - case M_ULHU: + case M_ULHU_AB: s = "lbu"; s2 = "lbu"; off = 1; goto uld_st; - case M_ULW_A: - ab = 1; - case M_ULW: + case M_ULW_AB: s = "lwl"; s2 = "lwr"; offbits = (mips_opts.micromips ? 12 : 16); off = 3; goto uld_st; - case M_ULD_A: - ab = 1; - case M_ULD: + case M_ULD_AB: s = "ldl"; s2 = "ldr"; offbits = (mips_opts.micromips ? 12 : 16); off = 7; goto uld_st; - case M_USH_A: - ab = 1; - case M_USH: + case M_USH_AB: s = "sb"; s2 = "sb"; off = 1; ust = 1; goto uld_st; - case M_USW_A: - ab = 1; - case M_USW: + case M_USW_AB: s = "swl"; s2 = "swr"; offbits = (mips_opts.micromips ? 12 : 16); off = 3; ust = 1; goto uld_st; - case M_USD_A: - ab = 1; - case M_USD: + case M_USD_AB: s = "sdl"; s2 = "sdr"; offbits = (mips_opts.micromips ? 12 : 16); @@ -10510,32 +10421,26 @@ macro (struct mips_cl_insn *ip, char *str) ust = 1; uld_st: - if (!ab && offset_expr.X_add_number >= 0x8000 - off) - as_bad (_("Operand overflow")); - + large_offset = !small_offset_p (off, align, offbits); ep = &offset_expr; expr1.X_add_number = 0; - if (ab) + if (large_offset) { used_at = 1; tempreg = AT; - load_address (tempreg, ep, &used_at); - if (breg != 0) - macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", - tempreg, tempreg, breg); - breg = tempreg; - tempreg = treg; - ep = &expr1; - } - else if (offbits == 12 - && (offset_expr.X_op != O_constant - || !IS_SEXT_12BIT_NUM (offset_expr.X_add_number) - || !IS_SEXT_12BIT_NUM (offset_expr.X_add_number + off))) - { - used_at = 1; - tempreg = AT; - macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j", tempreg, breg, - -1, offset_reloc[0], offset_reloc[1], offset_reloc[2]); + if (small_offset_p (0, align, 16)) + macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j", tempreg, breg, -1, + offset_reloc[0], offset_reloc[1], offset_reloc[2]); + else + { + load_address (tempreg, ep, &used_at); + if (breg != 0) + macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", + tempreg, tempreg, breg); + } + offset_reloc[0] = BFD_RELOC_LO16; + offset_reloc[1] = BFD_RELOC_UNUSED; + offset_reloc[2] = BFD_RELOC_UNUSED; breg = tempreg; tempreg = treg; ep = &expr1; @@ -10553,21 +10458,23 @@ macro (struct mips_cl_insn *ip, char *str) if (!target_big_endian) ep->X_add_number += off; - if (offbits != 12) - macro_build (ep, s, "t,o(b)", tempreg, BFD_RELOC_LO16, breg); - else + if (offbits == 12) macro_build (NULL, s, "t,~(b)", tempreg, (unsigned long) ep->X_add_number, breg); + else + macro_build (ep, s, "t,o(b)", tempreg, -1, + offset_reloc[0], offset_reloc[1], offset_reloc[2], breg); if (!target_big_endian) ep->X_add_number -= off; else ep->X_add_number += off; - if (offbits != 12) - macro_build (ep, s2, "t,o(b)", tempreg, BFD_RELOC_LO16, breg); - else + if (offbits == 12) macro_build (NULL, s2, "t,~(b)", tempreg, (unsigned long) ep->X_add_number, breg); + else + macro_build (ep, s2, "t,o(b)", tempreg, -1, + offset_reloc[0], offset_reloc[1], offset_reloc[2], breg); /* If necessary, move the result in tempreg to the final destination. */ if (!ust && treg != tempreg) @@ -10582,14 +10489,15 @@ macro (struct mips_cl_insn *ip, char *str) used_at = 1; if (target_big_endian == ust) ep->X_add_number += off; - tempreg = ust || ab ? treg : AT; - macro_build (ep, s, "t,o(b)", tempreg, BFD_RELOC_LO16, breg); + tempreg = ust || large_offset ? treg : AT; + macro_build (ep, s, "t,o(b)", tempreg, -1, + offset_reloc[0], offset_reloc[1], offset_reloc[2], breg); /* For halfword transfers we need a temporary register to shuffle bytes. Unfortunately for M_USH_A we have none available before the next store as AT holds the base address. We deal with this case by clobbering TREG and then restoring it as with ULH. */ - tempreg = ust == ab ? treg : AT; + tempreg = ust == large_offset ? treg : AT; if (ust) macro_build (NULL, "srl", SHFT_FMT, tempreg, treg, 8); @@ -10597,21 +10505,23 @@ macro (struct mips_cl_insn *ip, char *str) ep->X_add_number -= off; else ep->X_add_number += off; - macro_build (ep, s2, "t,o(b)", tempreg, BFD_RELOC_LO16, breg); + macro_build (ep, s2, "t,o(b)", tempreg, -1, + offset_reloc[0], offset_reloc[1], offset_reloc[2], breg); /* For M_USH_A re-retrieve the LSB. */ - if (ust && ab) + if (ust && large_offset) { if (target_big_endian) ep->X_add_number += off; else ep->X_add_number -= off; - macro_build (&expr1, "lbu", "t,o(b)", AT, BFD_RELOC_LO16, AT); + macro_build (&expr1, "lbu", "t,o(b)", AT, -1, + offset_reloc[0], offset_reloc[1], offset_reloc[2], AT); } /* For ULH and M_USH_A OR the LSB in. */ - if (!ust || ab) + if (!ust || large_offset) { - tempreg = !ab ? AT : treg; + tempreg = !large_offset ? AT : treg; macro_build (NULL, "sll", SHFT_FMT, tempreg, tempreg, 8); macro_build (NULL, "or", "d,v,t", treg, treg, AT); } @@ -11416,6 +11326,16 @@ mips_ip (char *str, struct mips_cl_insn *ip) return; } + imm_expr.X_op = O_absent; + imm2_expr.X_op = O_absent; + offset_expr.X_op = O_absent; + imm_reloc[0] = BFD_RELOC_UNUSED; + imm_reloc[1] = BFD_RELOC_UNUSED; + imm_reloc[2] = BFD_RELOC_UNUSED; + offset_reloc[0] = BFD_RELOC_UNUSED; + offset_reloc[1] = BFD_RELOC_UNUSED; + offset_reloc[2] = BFD_RELOC_UNUSED; + create_insn (ip, insn); insn_error = NULL; argnum = 1; @@ -12782,10 +12702,20 @@ mips_ip (char *str, struct mips_cl_insn *ip) continue; case 'A': - my_getExpression (&offset_expr, s); - normalize_address_expr (&offset_expr); - *imm_reloc = BFD_RELOC_32; - s = expr_end; + /* If we expect a base register, check whether there is only + a single bracketed expression left. If so, it must be the + base register and the constant must be zero. */ + if (args[1] == '(' && *s == '(' && strchr (s + 1, '(') == 0) + { + offset_expr.X_op = O_constant; + offset_expr.X_add_number = 0; + } + else + { + my_getSmallExpression (&offset_expr, offset_reloc, s); + normalize_address_expr (&offset_expr); + s = expr_end; + } continue; case 'F': |