From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 24164 invoked by alias); 28 Jul 2011 23:52:43 -0000 Received: (qmail 24144 invoked by uid 22791); 28 Jul 2011 23:52:36 -0000 X-SWARE-Spam-Status: No, hits=-2.2 required=5.0 tests=AWL,BAYES_00,RP_MATCHES_RCVD,TW_BZ,TW_FX,TW_XD,TW_XF X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (38.113.113.100) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 28 Jul 2011 23:52:17 +0000 Received: (qmail 23834 invoked from network); 28 Jul 2011 23:52:15 -0000 Received: from unknown (HELO tp.orcam.me.uk) (macro@127.0.0.2) by mail.codesourcery.com with ESMTPA; 28 Jul 2011 23:52:15 -0000 Date: Fri, 29 Jul 2011 00:58:00 -0000 From: "Maciej W. Rozycki" To: Richard Sandiford cc: binutils@sourceware.org, Chao-ying Fu , Rich Fuhler , David Lau , Kevin Mills , Ilie Garbacea , Catherine Moore , Nathan Sidwell , Joseph Myers Subject: Re: [PATCH] MIPS: microMIPS ASE support In-Reply-To: Message-ID: References: <87y6fa9u3t.fsf@firetop.home> <876302kqvu.fsf@firetop.home> <8739pb1qs5.fsf@firetop.home> <87r5abs7ak.fsf@firetop.home> <87ipqrwyf4.fsf@firetop.home> User-Agent: Alpine 1.10 (DEB 962 2008-03-14) MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Mailing-List: contact binutils-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: binutils-owner@sourceware.org X-SW-Source: 2011-07/txt/msg00262.txt.bz2 Hi Richard, On Tue, 26 Jul 2011, Maciej W. Rozycki wrote: > > and I gather from an off-list discussion a couple of months ago that > > there were indeed some things that you didn't like. But I think it'd > > be easier to deal with them as follow-ups. Please feel free to send > > patches against trunk. Or, if you tell me what it is you disagree with, > > I can try to fix it myself. > > I guess I'll just send off the e-mail I had been writing but never > actually completed. My current state of the changes includes all my > updates that reflect the points made, but now I'll have to regenerate > them, possibly by reverting yours, applying mine on top and figuring out > what differences to the original remain. Oh well... Here's what I have come up with as a result of merging your changes into my code base. There are plenty of small changes, so I have decided not to put too much effort into straightening them up (or not) lest you are unhappy with the outcome anyway. Instead, I'm giving you (and the others) an opportunity to review my code in its current shape. The result generally reflects my concerns as expressed earlier this week, in response to your comments back in March. Note there are a couple of bug fixes, some optimisations and one functional improvement too -- see the change log for details. > > I'm sure there are things that we've both missed, but again, > > we can deal with them as follow-ups. > > There's a whole lot of important linker relaxation fixes that I reckon > were not included in the original series plus several bug fixes. I'll work on these fixes now -- there are quite a few and at least one still requires some work not to be considered a dirty hack -- and will be back with you shortly. Comments, questions? 2011-07-28 Maciej W. Rozycki bfd/ * elfxx-mips.c: Adjust comments throughout. (mips_elf_relax_delete_bytes): Reshape code. (bz_insn_16): Correct opcode mask. (check_br32): Fix return type. (check_4byte_branch): Remove function. (check_bzc): New function. (_bfd_mips_elf_relax_section): Permit the relaxation of LUI instructions that immediately follow a compact branch instruction. Remove check for R_MICROMIPS_GPREL16 relocations. Reshape code. gas/ * config/tc-mips.c: Adjust comments throughout. (reglist_lookup): Reshape code. (jmp_reloc_p, jalr_reloc_p): Reformat. (got16_reloc_p, hi16_reloc_p, lo16_reloc_p): Handle microMIPS relocations. (gpr_mod_mask): Remove unused variable. Reshape code. (gpr_read_mask, gpr_write_mask): Reshape code. (fpr_read_mask, fpr_write_mask): Likewise. (nops_for_vr4130): Ensure non-microMIPS mode. (can_swap_branch_p): Correct pinfo2 reference. Reshape code. (append_insn): Skip Loongson 2F workaround in MIPS16 mode. Use the outermost operator of a compound relocation to determines the relocated field. Reshape code. (md_convert_frag): Reshape code. include/opcode/ * mips.h: Clarify the description of microMIPS instruction manipulation macros. (MICROMIPSOP_MASK_MAJOR, MICROMIPSOP_SH_MAJOR): Remove macros. Maciej r-binutils-20110225-umips-fix.diff Index: binutils-fsf-trunk-quilt/gas/config/tc-mips.c =================================================================== --- binutils-fsf-trunk-quilt.orig/gas/config/tc-mips.c 2011-07-28 23:18:50.000000000 +0100 +++ binutils-fsf-trunk-quilt/gas/config/tc-mips.c 2011-07-28 23:30:26.000000000 +0100 @@ -483,7 +483,7 @@ static int mips_32bitmode = 0; (strncmp (TARGET_CPU, "mips16", sizeof ("mips16") - 1) == 0 \ || strncmp (TARGET_CANONICAL, "mips-lsi-elf", sizeof ("mips-lsi-elf") - 1) == 0) -/* Return true if the given CPU supports microMIPS. */ +/* Return true if the given CPU supports the microMIPS ASE. */ #define CPU_HAS_MICROMIPS(cpu) 0 /* True if CPU has a dror instruction. */ @@ -2141,7 +2141,7 @@ reg_lookup (char **s, unsigned int types As a special exception if one of s0-s7 registers is specified as the range's lower delimiter and s8 (fp) is its upper one, then no registers whose numbers place them between s7 and s8 (i.e. $24-$29) - are selected; they have to be named separately if needed. */ + are selected; they have to be listed separately if needed. */ static int reglist_lookup (char **s, unsigned int types, unsigned int *reglistp) @@ -2150,9 +2150,9 @@ reglist_lookup (char **s, unsigned int t unsigned int lastregno; bfd_boolean ok = TRUE; unsigned int regmask; - unsigned int regno; + char *s_endlist = *s; char *s_reset = *s; - char *s_end_of_list = *s; + unsigned int regno; while (reg_lookup (s, types, ®no)) { @@ -2177,14 +2177,14 @@ reglist_lookup (char **s, unsigned int t regmask ^= (1 << regno) - 1; reglist |= regmask; - s_end_of_list = *s; + s_endlist = *s; if (**s != ',') break; (*s)++; } if (ok) - *s = s_end_of_list; + *s = s_endlist; else *s = s_reset; if (reglistp) @@ -2663,41 +2663,36 @@ micromips_reloc_p (bfd_reloc_code_real_t } static inline bfd_boolean +jmp_reloc_p (bfd_reloc_code_real_type reloc) +{ + return reloc == BFD_RELOC_MIPS_JMP || reloc == BFD_RELOC_MICROMIPS_JMP; +} + +static inline bfd_boolean got16_reloc_p (bfd_reloc_code_real_type reloc) { - return (reloc == BFD_RELOC_MIPS_GOT16 - || reloc == BFD_RELOC_MIPS16_GOT16 + return (reloc == BFD_RELOC_MIPS_GOT16 || reloc == BFD_RELOC_MIPS16_GOT16 || reloc == BFD_RELOC_MICROMIPS_GOT16); } static inline bfd_boolean hi16_reloc_p (bfd_reloc_code_real_type reloc) { - return (reloc == BFD_RELOC_HI16_S - || reloc == BFD_RELOC_MIPS16_HI16_S + return (reloc == BFD_RELOC_HI16_S || reloc == BFD_RELOC_MIPS16_HI16_S || reloc == BFD_RELOC_MICROMIPS_HI16_S); } static inline bfd_boolean lo16_reloc_p (bfd_reloc_code_real_type reloc) { - return (reloc == BFD_RELOC_LO16 - || reloc == BFD_RELOC_MIPS16_LO16 + return (reloc == BFD_RELOC_LO16 || reloc == BFD_RELOC_MIPS16_LO16 || reloc == BFD_RELOC_MICROMIPS_LO16); } static inline bfd_boolean -jmp_reloc_p (bfd_reloc_code_real_type reloc) -{ - return (reloc == BFD_RELOC_MIPS_JMP - || reloc == BFD_RELOC_MICROMIPS_JMP); -} - -static inline bfd_boolean jalr_reloc_p (bfd_reloc_code_real_type reloc) { - return (reloc == BFD_RELOC_MIPS_JALR - || reloc == BFD_RELOC_MICROMIPS_JALR); + return reloc == BFD_RELOC_MIPS_JALR || reloc == BFD_RELOC_MICROMIPS_JALR; } /* Return true if the given relocation might need a matching %lo(). @@ -2893,18 +2888,21 @@ relax_end (void) mips_relax.sequence = 0; } -/* Return the mask of core registers that instruction IP may - read or write. */ +/* Return the mask of core registers that IP reads or writes. */ static unsigned int gpr_mod_mask (const struct mips_cl_insn *ip) { - unsigned long pinfo, pinfo2; + unsigned long pinfo2; unsigned int mask; mask = 0; - pinfo = ip->insn_mo->pinfo; pinfo2 = ip->insn_mo->pinfo2; + if (!mips_opts.mips16) + { + if (pinfo2 & INSN2_MOD_SP) + mask |= 1 << SP; + } if (mips_opts.micromips) { if (pinfo2 & INSN2_MOD_GPR_MB) @@ -2934,8 +2932,6 @@ gpr_mod_mask (const struct mips_cl_insn mask |= 1 << EXTRACT_OPERAND (1, MP, *ip); if (pinfo2 & INSN2_MOD_GPR_MQ) mask |= 1 << micromips_to_32_reg_q_map[EXTRACT_OPERAND (1, MQ, *ip)]; - if (pinfo2 & INSN2_MOD_SP) - mask |= 1 << SP; } return mask; } @@ -2969,27 +2965,20 @@ gpr_read_mask (const struct mips_cl_insn if (pinfo & MIPS16_INSN_READ_GPR_X) mask |= 1 << MIPS16_EXTRACT_OPERAND (REGR32, *ip); } - else if (mips_opts.micromips) - { - if (pinfo & INSN_READ_GPR_T) - mask |= 1 << EXTRACT_OPERAND (1, RT, *ip); - if (pinfo & INSN_READ_GPR_S) - mask |= 1 << EXTRACT_OPERAND (1, RS, *ip); - if (pinfo2 & INSN2_READ_GPR_31) - mask |= 1 << RA; - if (pinfo2 & INSN2_READ_GP) - mask |= 1 << GP; - } else { if (pinfo2 & INSN2_READ_GPR_D) - mask |= 1 << EXTRACT_OPERAND (0, RD, *ip); + mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RD, *ip); if (pinfo & INSN_READ_GPR_T) - mask |= 1 << EXTRACT_OPERAND (0, RT, *ip); + mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RT, *ip); if (pinfo & INSN_READ_GPR_S) - mask |= 1 << EXTRACT_OPERAND (0, RS, *ip); + mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RS, *ip); + if (pinfo2 & INSN2_READ_GP) + mask |= 1 << GP; + if (pinfo2 & INSN2_READ_GPR_31) + mask |= 1 << RA; if (pinfo2 & INSN2_READ_GPR_Z) - mask |= 1 << EXTRACT_OPERAND (0, RZ, *ip); + mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RZ, *ip); } /* Don't include register 0. */ return mask & ~1; @@ -3023,23 +3012,14 @@ gpr_write_mask (const struct mips_cl_ins if (pinfo & MIPS16_INSN_WRITE_GPR_Y) mask |= 1 << MIPS16OP_EXTRACT_REG32R (ip->insn_opcode); } - else if (mips_opts.micromips) - { - if (pinfo & INSN_WRITE_GPR_D) - mask |= 1 << EXTRACT_OPERAND (1, RD, *ip); - if (pinfo & INSN_WRITE_GPR_T) - mask |= 1 << EXTRACT_OPERAND (1, RT, *ip); - if (pinfo2 & INSN2_WRITE_GPR_S) - mask |= 1 << EXTRACT_OPERAND (1, RS, *ip); - if (pinfo & INSN_WRITE_GPR_31) - mask |= 1 << RA; - } else { if (pinfo & INSN_WRITE_GPR_D) mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RD, *ip); if (pinfo & INSN_WRITE_GPR_T) mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RT, *ip); + if (pinfo2 & INSN2_WRITE_GPR_S) + mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RS, *ip); if (pinfo & INSN_WRITE_GPR_31) mask |= 1 << RA; if (pinfo2 & INSN2_WRITE_GPR_Z) @@ -3060,19 +3040,10 @@ fpr_read_mask (const struct mips_cl_insn mask = 0; pinfo = ip->insn_mo->pinfo; pinfo2 = ip->insn_mo->pinfo2; - if (mips_opts.micromips) + if (!mips_opts.mips16) { if (pinfo2 & INSN2_READ_FPR_D) - mask |= 1 << EXTRACT_OPERAND (1, FD, *ip); - if (pinfo & INSN_READ_FPR_S) - mask |= 1 << EXTRACT_OPERAND (1, FS, *ip); - if (pinfo & INSN_READ_FPR_T) - mask |= 1 << EXTRACT_OPERAND (1, FT, *ip); - if (pinfo & INSN_READ_FPR_R) - mask |= 1 << EXTRACT_OPERAND (1, FR, *ip); - } - else if (!mips_opts.mips16) - { + mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FD, *ip); if (pinfo & INSN_READ_FPR_S) mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FS, *ip); if (pinfo & INSN_READ_FPR_T) @@ -3100,16 +3071,7 @@ fpr_write_mask (const struct mips_cl_ins mask = 0; pinfo = ip->insn_mo->pinfo; pinfo2 = ip->insn_mo->pinfo2; - if (mips_opts.micromips) - { - if (pinfo2 & INSN_WRITE_FPR_D) - mask |= 1 << EXTRACT_OPERAND (1, FD, *ip); - if (pinfo & INSN_WRITE_FPR_S) - mask |= 1 << EXTRACT_OPERAND (1, FS, *ip); - if (pinfo & INSN_WRITE_FPR_T) - mask |= 1 << EXTRACT_OPERAND (1, FT, *ip); - } - else if (!mips_opts.mips16) + if (!mips_opts.mips16) { if (pinfo & INSN_WRITE_FPR_D) mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FD, *ip); @@ -3316,6 +3278,7 @@ nops_for_vr4130 (int ignore, const struc if (MF_HILO_INSN (hist[i].insn_mo->pinfo)) { /* Extract the destination register. */ + gas_assert (!mips_opts.micromips); mask = gpr_write_mask (&hist[i]); /* No nops are needed if INSN reads that register. */ @@ -3720,8 +3683,9 @@ can_swap_branch_p (struct mips_cl_insn * return FALSE; /* If the previous instruction is in a variant frag other than this - branch's one, we cannot do the swap. This does not apply to the - mips16, which uses variant frags for different purposes. */ + branch's one, we cannot do the swap. This does not apply to + MIPS16/microMIPS code, which uses variant frags for different + purposes. */ if (!HAVE_CODE_COMPRESSION && history[0].frag && history[0].frag->fr_type == rs_machine_dependent) @@ -3781,17 +3745,16 @@ can_swap_branch_p (struct mips_cl_insn * /* If the previous instruction has an incorrect size for a fixed branch delay slot in microMIPS mode, we cannot swap. */ - if (mips_opts.micromips) - { - pinfo2 = ip->insn_mo->pinfo; - if ((pinfo2 & INSN2_BRANCH_DELAY_16BIT) - && insn_length (history) != 2) - return FALSE; + pinfo2 = ip->insn_mo->pinfo2; + if (mips_opts.micromips + && (pinfo2 & INSN2_BRANCH_DELAY_16BIT) + && insn_length (history) != 2) + return FALSE; + if (mips_opts.micromips + && (pinfo2 & INSN2_BRANCH_DELAY_32BIT) + && insn_length (history) != 4) + return FALSE; - if ((pinfo2 & INSN2_BRANCH_DELAY_32BIT) - && insn_length (history) != 4) - return FALSE; - } return TRUE; } @@ -3984,10 +3947,10 @@ append_insn (struct mips_cl_insn *ip, ex { unsigned long prev_pinfo, prev_pinfo2, pinfo, pinfo2; bfd_boolean relaxed_branch = FALSE; - bfd_boolean relax32; enum append_method method; + bfd_boolean relax32; - if (mips_fix_loongson2f && !mips_opts.micromips) + if (mips_fix_loongson2f && !HAVE_CODE_COMPRESSION) fix_loongson2f (ip); mips_mark_labels (); @@ -4014,10 +3977,11 @@ append_insn (struct mips_cl_insn *ip, ex else if (*reloc_type <= BFD_RELOC_UNUSED && address_expr->X_op == O_constant) { + bfd_reloc_code_real_type orig_reloc = *reloc_type; unsigned int tmp; ip->complete_p = 1; - switch (*reloc_type) + switch (orig_reloc) { case BFD_RELOC_32: ip->insn_opcode |= address_expr->X_add_number; @@ -4192,9 +4156,9 @@ append_insn (struct mips_cl_insn *ip, ex If the instruction produced is a branch that we will swap with the preceding instruction, then we add the displacement by which the branch will be moved backwards. This is more appropriate - and for MIPS16/microMIPS code also prevents a debugger from placing - a breakpoint in the middle of the branch (and corrupting code if - software breakpoints are used). */ + and for MIPS16/microMIPS code also prevents a debugger from + placing a breakpoint in the middle of the branch (and corrupting + code if software breakpoints are used). */ dwarf2_emit_insn ((HAVE_CODE_COMPRESSION ? -1 : 0) + (method == APPEND_SWAP ? insn_length (history) : 0)); #endif @@ -4329,60 +4293,66 @@ append_insn (struct mips_cl_insn *ip, ex if (!ip->complete_p && *reloc_type < BFD_RELOC_UNUSED) { + bfd_reloc_code_real_type orig_reloc = *reloc_type; bfd_reloc_code_real_type final_type[3]; + reloc_howto_type *howto0; reloc_howto_type *howto; + int n; int i; /* Perform any necessary conversion to microMIPS relocations - and find out how many relocations there actually are. */ - for (i = 0; i < 3 && reloc_type[i] != BFD_RELOC_UNUSED; i++) - final_type[i] = micromips_map_reloc (reloc_type[i]); + and find out how many relocations there actually are. */ + for (n = 0; n < 3 && reloc_type[n] != BFD_RELOC_UNUSED; n++) + final_type[n] = micromips_map_reloc (reloc_type[n]); /* In a compound relocation, it is the final (outermost) operator that determines the relocated field. */ - howto = bfd_reloc_type_lookup (stdoutput, final_type[i - 1]); + howto = howto0 = bfd_reloc_type_lookup (stdoutput, final_type[n - 1]); + if (howto == NULL) { /* To reproduce this failure try assembling gas/testsuites/ gas/mips/mips16-intermix.s with a mips-ecoff targeted assembler. */ as_bad (_("Unsupported MIPS relocation number %d"), - final_type[i - 1]); + final_type[n - 1]); howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16); } - - howto = bfd_reloc_type_lookup (stdoutput, final_type[0]); + + if (n > 1) + howto0 = bfd_reloc_type_lookup (stdoutput, final_type[0]); ip->fixp[0] = fix_new_exp (ip->frag, ip->where, bfd_get_reloc_size (howto), address_expr, - howto->pc_relative, final_type[0]); + howto0 && howto0->pc_relative, + final_type[0]); /* Tag symbols that have a R_MIPS16_26 relocation against them. */ - if (reloc_type[0] == BFD_RELOC_MIPS16_JMP - && ip->fixp[0]->fx_addsy) + if (final_type[0] == BFD_RELOC_MIPS16_JMP && ip->fixp[0]->fx_addsy) *symbol_get_tc (ip->fixp[0]->fx_addsy) = 1; /* These relocations can have an addend that won't fit in - 4 octets for 64bit assembly. */ + 4 octets for 64bit assembly. We cheat and check orig_reloc + here as this has fewer choices than reloc. */ if (HAVE_64BIT_GPRS && ! howto->partial_inplace - && (reloc_type[0] == BFD_RELOC_16 - || reloc_type[0] == BFD_RELOC_32 - || reloc_type[0] == BFD_RELOC_MIPS_JMP - || reloc_type[0] == BFD_RELOC_GPREL16 - || reloc_type[0] == BFD_RELOC_MIPS_LITERAL - || reloc_type[0] == BFD_RELOC_GPREL32 - || reloc_type[0] == BFD_RELOC_64 - || reloc_type[0] == BFD_RELOC_CTOR - || reloc_type[0] == BFD_RELOC_MIPS_SUB - || reloc_type[0] == BFD_RELOC_MIPS_HIGHEST - || reloc_type[0] == BFD_RELOC_MIPS_HIGHER - || reloc_type[0] == BFD_RELOC_MIPS_SCN_DISP - || reloc_type[0] == BFD_RELOC_MIPS_REL16 - || reloc_type[0] == BFD_RELOC_MIPS_RELGOT - || reloc_type[0] == BFD_RELOC_MIPS16_GPREL - || hi16_reloc_p (reloc_type[0]) - || lo16_reloc_p (reloc_type[0]))) + && (orig_reloc == BFD_RELOC_16 + || orig_reloc == BFD_RELOC_32 + || orig_reloc == BFD_RELOC_MIPS_JMP + || orig_reloc == BFD_RELOC_GPREL16 + || orig_reloc == BFD_RELOC_MIPS_LITERAL + || orig_reloc == BFD_RELOC_GPREL32 + || orig_reloc == BFD_RELOC_64 + || orig_reloc == BFD_RELOC_CTOR + || orig_reloc == BFD_RELOC_MIPS_SUB + || orig_reloc == BFD_RELOC_MIPS_HIGHEST + || orig_reloc == BFD_RELOC_MIPS_HIGHER + || orig_reloc == BFD_RELOC_MIPS_SCN_DISP + || orig_reloc == BFD_RELOC_MIPS_REL16 + || orig_reloc == BFD_RELOC_MIPS_RELGOT + || orig_reloc == BFD_RELOC_MIPS16_GPREL + || hi16_reloc_p (orig_reloc) + || lo16_reloc_p (orig_reloc))) ip->fixp[0]->fx_no_overflow = 1; if (mips_relax.sequence) @@ -4390,7 +4360,7 @@ append_insn (struct mips_cl_insn *ip, ex if (mips_relax.first_fixup == 0) mips_relax.first_fixup = ip->fixp[0]; } - else if (reloc_needs_lo_p (*reloc_type)) + else if (reloc_needs_lo_p (final_type[0])) { struct mips_hi_fixup *hi_fixup; @@ -4413,17 +4383,16 @@ append_insn (struct mips_cl_insn *ip, ex against RSS_UNDEF, RSS_GP, RSS_GP0 or RSS_LOC. At the moment we only use RSS_UNDEF, but we could add support for the others if it ever becomes necessary. */ - for (i = 1; i < 3; i++) - if (reloc_type[i] != BFD_RELOC_UNUSED) - { - ip->fixp[i] = fix_new (ip->frag, ip->where, - ip->fixp[0]->fx_size, NULL, 0, - FALSE, final_type[i]); + for (i = 1; i < n; i++) + { + ip->fixp[i] = fix_new (ip->frag, ip->where, + ip->fixp[0]->fx_size, NULL, 0, + FALSE, final_type[i]); - /* Use fx_tcbit to mark compound relocs. */ - ip->fixp[0]->fx_tcbit = 1; - ip->fixp[i]->fx_tcbit = 1; - } + /* Use fx_tcbit to mark compound relocs. */ + ip->fixp[0]->fx_tcbit = 1; + ip->fixp[i]->fx_tcbit = 1; + } } install_insn (ip); @@ -17800,8 +17769,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU bfd_boolean compact = RELAX_MICROMIPS_COMPACT (fragp->fr_subtype); bfd_boolean al = RELAX_MICROMIPS_LINK (fragp->fr_subtype); int type = RELAX_MICROMIPS_TYPE (fragp->fr_subtype); - unsigned long jal, jalr, jr; - + bfd_boolean short_ds; unsigned long insn; expressionS exp; fixS *fixp; @@ -17812,7 +17780,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU fragp->fr_fix += fragp->fr_var; - /* Handle 16-bit branches that fit or are forced to fit. */ + /* Handle 16-bit branches that fit or forced to fit. */ if (type != 0 && !RELAX_MICROMIPS_TOOFAR16 (fragp->fr_subtype)) { /* We generate a fixup instead of applying it right now, @@ -17841,7 +17809,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU return; } - /* Handle 32-bit branches that fit or forced to fit. */ + /* Handle 32-bit branches that fit or are forced to fit. */ if (!RELAX_MICROMIPS_RELAX32 (fragp->fr_subtype) || !RELAX_MICROMIPS_TOOFAR32 (fragp->fr_subtype)) { @@ -17914,18 +17882,8 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU as_warn_where (fragp->fr_file, fragp->fr_line, _("Relaxed out-of-range branch into a jump")); - /* Check the short-delay-slot bit. */ - if (al && (insn & 0x02000000) != 0) - { - jal = 0x74000000; /* jals */ - jalr = 0x45e0; /* jalrs */ - } - else - { - jal = 0xf4000000; /* jal */ - jalr = 0x45c0; /* jalr */ - } - jr = compact ? 0x45a0 : 0x4580; /* jr/c */ + /* Set the short-delay-slot bit. */ + short_ds = al && (insn & 0x02000000) != 0; if (!RELAX_MICROMIPS_UNCOND (fragp->fr_subtype)) { @@ -17995,6 +17953,8 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU if (mips_pic == NO_PIC) { + unsigned long jal = short_ds ? 0x74000000 : 0xf4000000; /* jal/s */ + /* j/jal/jals R_MICROMIPS_26_S1 */ insn = al ? jal : 0xd4000000; @@ -18019,6 +17979,8 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU else { unsigned long at = RELAX_MICROMIPS_AT (fragp->fr_subtype); + unsigned long jalr = short_ds ? 0x45e0 : 0x45c0; /* jalr/s */ + unsigned long jr = compact ? 0x45a0 : 0x4580; /* jr/c */ /* lw/ld $at, ($gp) R_MICROMIPS_GOT16 */ insn = HAVE_64BIT_ADDRESSES ? 0xdc1c0000 : 0xfc1c0000; Index: binutils-fsf-trunk-quilt/bfd/elfxx-mips.c =================================================================== --- binutils-fsf-trunk-quilt.orig/bfd/elfxx-mips.c 2011-07-28 23:18:50.000000000 +0100 +++ binutils-fsf-trunk-quilt/bfd/elfxx-mips.c 2011-07-28 23:30:26.000000000 +0100 @@ -11910,8 +11910,7 @@ mips_elf_relax_delete_bytes (bfd *abfd, symtab_hdr = &elf_tdata (abfd)->symtab_hdr; isym = (Elf_Internal_Sym *) symtab_hdr->contents; for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++) - if (isym->st_shndx == sec_shndx - && isym->st_value > addr) + if (isym->st_shndx == sec_shndx && isym->st_value > addr) isym->st_value -= count; /* Now adjust the global symbols defined in this section. */ @@ -11928,9 +11927,8 @@ mips_elf_relax_delete_bytes (bfd *abfd, || sym_hash->root.type == bfd_link_hash_defweak) && sym_hash->root.u.def.section == sec) { - bfd_vma value; + bfd_vma value = sym_hash->root.u.def.value; - value = sym_hash->root.u.def.value; if (ELF_ST_IS_MICROMIPS (sym_hash->other)) value &= MINUS_TWO; if (value > addr) @@ -11989,7 +11987,7 @@ static const struct opcode_descriptor b_ { /* "b", "mD", */ 0xcc00, 0xfc00 }; static const struct opcode_descriptor bz_insn_16 = - { /* "b(eq|ne)z", "md,mE", */ 0x8c00, 0xac00 }; + { /* "b(eq|ne)z", "md,mE", */ 0x8c00, 0xdc00 }; /* 32-bit and 16-bit branch EQ and NE zero. */ @@ -12241,7 +12239,7 @@ check_br16 (bfd *abfd, bfd_byte *ptr, un /* If PTR points to a 32-bit branch or jump that doesn't fiddle with REG, then return TRUE, otherwise FALSE. */ -static int +static bfd_boolean check_br32 (bfd *abfd, bfd_byte *ptr, unsigned long reg) { unsigned long opcode; @@ -12266,32 +12264,37 @@ check_br32 (bfd *abfd, bfd_byte *ptr, un return FALSE; } -/* Bitsize checking. */ -#define IS_BITSIZE(val, N) \ - (((((val) & ((1ULL << (N)) - 1)) ^ (1ULL << ((N) - 1))) \ - - (1ULL << ((N) - 1))) == (val)) - -/* See if relocations [INTERNAL_RELOCS, IRELEND) confirm that there - is a 4-byte branch at offset OFFSET. */ +/* If the instruction encoding at PTR and relocations [INTERNAL_RELOCS, + IRELEND) at OFFSET indicate that it is a compact branch there, then + return TRUE, otherwise FALSE. */ static bfd_boolean -check_4byte_branch (Elf_Internal_Rela *internal_relocs, - Elf_Internal_Rela *irelend, bfd_vma offset) +check_bzc (bfd *abfd, const bfd_byte *ptr, bfd_vma offset, + const Elf_Internal_Rela *internal_relocs, + const Elf_Internal_Rela *irelend) { - Elf_Internal_Rela *irel; - unsigned long r_type; + const Elf_Internal_Rela *irel; + unsigned long opcode; + + opcode = bfd_get_16 (abfd, ptr); + opcode <<= 16; + opcode |= bfd_get_16 (abfd, ptr + 2); + if (find_match (opcode, bzc_insns_32) < 0) + return FALSE; for (irel = internal_relocs; irel < irelend; irel++) - if (irel->r_offset == offset) - { - r_type = ELF32_R_TYPE (irel->r_info); - if (r_type == R_MICROMIPS_26_S1 - || r_type == R_MICROMIPS_PC16_S1 - || r_type == R_MICROMIPS_JALR) - return TRUE; - } + if (irel->r_offset == offset + && ELF32_R_TYPE (irel->r_info) == R_MICROMIPS_PC16_S1) + return TRUE; + return FALSE; } + +/* Bitsize checking. */ +#define IS_BITSIZE(val, N) \ + (((((val) & ((1ULL << (N)) - 1)) ^ (1ULL << ((N) - 1))) \ + - (1ULL << ((N) - 1))) == (val)) + bfd_boolean _bfd_mips_elf_relax_section (bfd *abfd, asection *sec, @@ -12336,6 +12339,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, unsigned long opcode; bfd_vma symval; bfd_vma pcrval; + bfd_byte *ptr; int fndopc; /* The number of bytes to delete for relaxation and from where @@ -12347,8 +12351,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, this reloc. */ if (r_type != R_MICROMIPS_HI16 && r_type != R_MICROMIPS_PC16_S1 - && r_type != R_MICROMIPS_26_S1 - && r_type != R_MICROMIPS_GPREL16) + && r_type != R_MICROMIPS_26_S1) continue; /* Get the section contents if we haven't done so already. */ @@ -12361,6 +12364,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, else if (!bfd_malloc_and_get_section (abfd, sec, &contents)) goto error_return; } + ptr = contents + irel->r_offset; /* Read this BFD's local symbols if we haven't done so already. */ if (isymbuf == NULL && symtab_hdr->sh_info != 0) @@ -12432,8 +12436,8 @@ _bfd_mips_elf_relax_section (bfd *abfd, if (irel->r_offset + 4 > sec->size) continue; - opcode = bfd_get_16 (abfd, contents + irel->r_offset ) << 16; - opcode |= bfd_get_16 (abfd, contents + irel->r_offset + 2); + opcode = bfd_get_16 (abfd, ptr ) << 16; + opcode |= bfd_get_16 (abfd, ptr + 2); /* This is the pc-relative distance from the instruction the relocation is applied to, to the symbol referred. */ @@ -12452,6 +12456,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, out the offset). */ if (r_type == R_MICROMIPS_HI16 && MATCH (opcode, lui_insn)) { + bfd_boolean bzc = FALSE; unsigned long nextopc; unsigned long reg; bfd_vma offset; @@ -12475,19 +12480,19 @@ _bfd_mips_elf_relax_section (bfd *abfd, && ELF32_R_SYM (irel[2].r_info) == r_symndx) continue; - /* See if the LUI instruction *might* be in a branch delay slot. */ + /* See if the LUI instruction *might* be in a branch delay slot. + We check whether what looks like a 16-bit branch or jump is + actually an immediate argument to a compact branch, and let + it through if so. */ if (irel->r_offset >= 2 - && check_br16_dslot (abfd, contents + irel->r_offset - 2) > 0 + && check_br16_dslot (abfd, ptr - 2) && !(irel->r_offset >= 4 - /* If the instruction is actually a 4-byte branch, - the value of check_br16_dslot doesn't matter. - We should use check_br32_dslot to check whether - the branch has a delay slot. */ - && check_4byte_branch (internal_relocs, irelend, - irel->r_offset - 4))) + && (bzc = check_bzc (abfd, ptr - 4, irel->r_offset - 4, + internal_relocs, irelend)))) continue; if (irel->r_offset >= 4 - && check_br32_dslot (abfd, contents + irel->r_offset - 4) > 0) + && !bzc + && check_br32_dslot (abfd, ptr - 4)) continue; reg = OP32_SREG (opcode); @@ -12502,11 +12507,11 @@ _bfd_mips_elf_relax_section (bfd *abfd, case 0: break; case 2: - if (check_br16 (abfd, contents + irel->r_offset + 4, reg)) + if (check_br16 (abfd, ptr + 4, reg)) break; continue; case 4: - if (check_br32 (abfd, contents + irel->r_offset + 4, reg)) + if (check_br32 (abfd, ptr + 4, reg)) break; continue; default: @@ -12581,8 +12586,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, && irel->r_offset + 5 < sec->size && ((fndopc = find_match (opcode, bz_rs_insns_32)) >= 0 || (fndopc = find_match (opcode, bz_rt_insns_32)) >= 0) - && MATCH (bfd_get_16 (abfd, contents + irel->r_offset + 4), - nop_insn_16)) + && MATCH (bfd_get_16 (abfd, ptr + 4), nop_insn_16)) { unsigned long reg; @@ -12593,10 +12597,8 @@ _bfd_mips_elf_relax_section (bfd *abfd, | BZC32_REG_FIELD (reg) | (opcode & 0xffff)); /* Addend value. */ - bfd_put_16 (abfd, (opcode >> 16) & 0xffff, - contents + irel->r_offset); - bfd_put_16 (abfd, opcode & 0xffff, - contents + irel->r_offset + 2); + bfd_put_16 (abfd, (opcode >> 16) & 0xffff, ptr); + bfd_put_16 (abfd, opcode & 0xffff, ptr + 2); /* Delete the 16-bit delay slot NOP: two bytes from irel->offset + 4. */ @@ -12617,7 +12619,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, bfd_put_16 (abfd, (b_insn_16.match | (opcode & 0x3ff)), /* Addend value. */ - contents + irel->r_offset); + ptr); /* Delete 2 bytes from irel->r_offset + 2. */ delcnt = 2; @@ -12645,7 +12647,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, (bz_insns_16[fndopc].match | BZ16_REG_FIELD (reg) | (opcode & 0x7f)), /* Addend value. */ - contents + irel->r_offset); + ptr); /* Delete 2 bytes from irel->r_offset + 2. */ delcnt = 2; @@ -12661,14 +12663,13 @@ _bfd_mips_elf_relax_section (bfd *abfd, unsigned long n32opc; bfd_boolean relaxed = FALSE; - n32opc = bfd_get_16 (abfd, contents + irel->r_offset + 4) << 16; - n32opc |= bfd_get_16 (abfd, contents + irel->r_offset + 6); + n32opc = bfd_get_16 (abfd, ptr + 4) << 16; + n32opc |= bfd_get_16 (abfd, ptr + 6); if (MATCH (n32opc, nop_insn_32)) { /* Replace delay slot 32-bit NOP with a 16-bit NOP. */ - bfd_put_16 (abfd, nop_insn_16.match, - contents + irel->r_offset + 4); + bfd_put_16 (abfd, nop_insn_16.match, ptr + 4); relaxed = TRUE; } @@ -12679,7 +12680,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, (move_insn_16.match | MOVE16_RD_FIELD (MOVE32_RD (n32opc)) | MOVE16_RS_FIELD (MOVE32_RS (n32opc))), - contents + irel->r_offset + 4); + ptr + 4); relaxed = TRUE; } @@ -12691,9 +12692,9 @@ _bfd_mips_elf_relax_section (bfd *abfd, /* JAL with 32-bit delay slot that is changed to a JALS with 16-bit delay slot. */ bfd_put_16 (abfd, (jal_insn_32_bd16.match >> 16) & 0xffff, - contents + irel->r_offset); + ptr); bfd_put_16 (abfd, jal_insn_32_bd16.match & 0xffff, - contents + irel->r_offset + 2); + ptr + 2); /* Delete 2 bytes from irel->r_offset + 6. */ delcnt = 2; Index: binutils-fsf-trunk-quilt/include/opcode/mips.h =================================================================== --- binutils-fsf-trunk-quilt.orig/include/opcode/mips.h 2011-07-28 23:29:25.000000000 +0100 +++ binutils-fsf-trunk-quilt/include/opcode/mips.h 2011-07-28 23:30:26.000000000 +0100 @@ -1332,13 +1332,10 @@ extern int bfd_mips_num_opcodes; extern const struct mips_opcode mips16_opcodes[]; extern const int bfd_mips16_num_opcodes; -/* These are the bitmasks and shift counts used for the different - fields in the instruction formats. Other than MAJOR, no masks are - provided for the fixed portions of an instruction, since they are - not needed. */ +/* These are the bit masks and shift counts used for the different fields + in the microMIPS instruction formats. No masks are provided for the + fixed portions of an instruction, since they are not needed. */ -#define MICROMIPSOP_MASK_MAJOR 0x3f -#define MICROMIPSOP_SH_MAJOR 26 #define MICROMIPSOP_MASK_IMMEDIATE 0xffff #define MICROMIPSOP_SH_IMMEDIATE 0 #define MICROMIPSOP_MASK_DELTA 0xffff