From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 12723 invoked by alias); 8 Mar 2005 14:56:57 -0000 Mailing-List: contact binutils-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: binutils-owner@sources.redhat.com Received: (qmail 12447 invoked from network); 8 Mar 2005 14:56:41 -0000 Received: from unknown (HELO mx1.redhat.com) (66.187.233.31) by sourceware.org with SMTP; 8 Mar 2005 14:56:41 -0000 Received: from int-mx1.corp.redhat.com (int-mx1.corp.redhat.com [172.16.52.254]) by mx1.redhat.com (8.12.11/8.12.11) with ESMTP id j28Eufwa007357 for ; Tue, 8 Mar 2005 09:56:41 -0500 Received: from talisman.cambridge.redhat.com (talisman.cambridge.redhat.com [172.16.18.81]) by int-mx1.corp.redhat.com (8.11.6/8.11.6) with ESMTP id j28Euen10916 for ; Tue, 8 Mar 2005 09:56:40 -0500 Received: from talisman.cambridge.redhat.com (localhost.localdomain [127.0.0.1]) by talisman.cambridge.redhat.com (8.13.1/8.12.10) with ESMTP id j28EuYCL012248 for ; Tue, 8 Mar 2005 14:56:34 GMT Received: (from rsandifo@localhost) by talisman.cambridge.redhat.com (8.13.1/8.12.10/Submit) id j28EuTdU012247; Tue, 8 Mar 2005 14:56:29 GMT X-Authentication-Warning: talisman.cambridge.redhat.com: rsandifo set sender to rsandifo@redhat.com using -f To: binutils@sources.redhat.com Subject: Rework MIPS nop-insertion code, add -mfix-vr4130 [5/11] References: From: Richard Sandiford Date: Tue, 08 Mar 2005 14:56:00 -0000 In-Reply-To: (Richard Sandiford's message of "Tue, 08 Mar 2005 14:49:37 +0000") Message-ID: User-Agent: Gnus/5.1006 (Gnus v5.10.6) Emacs/21.3 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-SW-Source: 2005-03/txt/msg00217.txt.bz2 This patch introduces a new set of functions for handling mips_cl_insns and for manipulating the history buffer: - create_insn Initialise a mips_cl_insn from an opcode entry - install_insn Install a mips_cl_insn's opcode at the position specified by its frag and where fields. - move_insn Change the position of a mips_cl_insn. - add_fixed_insn Install a mips_cl_insn at the end of the current frag. - add_relaxed_insn Start a variant frag and install a mips_cl_insn at the start of the variant part. - insert_into_history Insert copies of a mips_cl_insn into the history buffer. - emit_nop Add a nop to the end of the current frag and record it in the history buffer. Most of this is just cleanup, but the new behaviour of emit_nop() is important. It means that append_insn() now adds nops to the history buffer at the same time as emitting the nops, not when emitting the instruction _after_ the nops. This simplified some later changes. Tested on mips64{,el}-linux-gnu and mipsisa64{,el}-elf. OK to install? Richard * config/tc-mips.c (dummy_opcode): Delete. (nop_insn, mips16_nop_insn): New variables. (NOP_INSN): New macro. (insn_length, create_insn, install_insn, move_insn, add_fixed_insn) (add_relaxed_insn, insert_into_history, emit_nop): New functions. (md_begin): Initialize nop_insn and mips16_nop_insn. (append_insn): Use the new emit_nop function to add nops, recording them in the history buffer. Use add_fixed_insn or add_relaxed_insn to reserve room for the instruction and install_insn to install the final form. Use insert_into_history to record the instruction in the history buffer. Use move_insn to do delay slot filling. (mips_emit_delays): Use add_fixed_insn instead of the emit_nop macro. (macro_build, mips16_macro_build, macro_build_lui, mips_ip) (mips16_ip): Use create_insn to initialize mips_cl_insns. diff -crpN gas.5/config/tc-mips.c gas/config/tc-mips.c *** gas.5/config/tc-mips.c 2005-03-08 10:19:44.469831745 +0000 --- gas/config/tc-mips.c 2005-03-08 10:30:43.161925269 +0000 *************** static int mips_debug = 0; *** 560,568 **** /* A list of previous instructions, with index 0 being the most recent. */ static struct mips_cl_insn history[2]; ! /* If we don't want information for a history[] entry, we ! point the insn_mo field at this dummy integer. */ ! static const struct mips_opcode dummy_opcode = { NULL, NULL, 0, 0, 0, 0, 0 }; /* If this is set, it points to a frag holding nop instructions which were inserted before the start of a noreorder section. If those --- 560,570 ---- /* A list of previous instructions, with index 0 being the most recent. */ static struct mips_cl_insn history[2]; ! /* Nop instructions used by emit_nop. */ ! static struct mips_cl_insn nop_insn, mips16_nop_insn; ! ! /* The appropriate nop for the current mode. */ ! #define NOP_INSN (mips_opts.mips16 ? &mips16_nop_insn : &nop_insn) /* If this is set, it points to a frag holding nop instructions which were inserted before the start of a noreorder section. If those *************** mips_target_format (void) *** 1159,1164 **** --- 1161,1290 ---- } } + /* Return the length of instruction INSN. */ + + static inline unsigned int + insn_length (const struct mips_cl_insn *insn) + { + if (!mips_opts.mips16) + return 4; + return insn->mips16_absolute_jump_p || insn->use_extend ? 4 : 2; + } + + /* Initialise INSN from opcode entry MO. Leave its position unspecified. */ + + static void + create_insn (struct mips_cl_insn *insn, const struct mips_opcode *mo) + { + size_t i; + + insn->insn_mo = mo; + insn->use_extend = FALSE; + insn->extend = 0; + insn->insn_opcode = mo->match; + insn->frag = NULL; + insn->where = 0; + for (i = 0; i < ARRAY_SIZE (insn->fixp); i++) + insn->fixp[i] = NULL; + insn->fixed_p = (mips_opts.noreorder > 0); + insn->noreorder_p = (mips_opts.noreorder > 0); + insn->mips16_absolute_jump_p = 0; + } + + /* Install INSN at the location specified by its "frag" and "where" fields. */ + + static void + install_insn (const struct mips_cl_insn *insn) + { + char *f = insn->frag->fr_literal + insn->where; + if (!mips_opts.mips16) + md_number_to_chars (f, insn->insn_opcode, 4); + else if (insn->mips16_absolute_jump_p) + { + md_number_to_chars (f, insn->insn_opcode >> 16, 2); + md_number_to_chars (f + 2, insn->insn_opcode & 0xffff, 2); + } + else + { + if (insn->use_extend) + { + md_number_to_chars (f, 0xf000 | insn->extend, 2); + f += 2; + } + md_number_to_chars (f, insn->insn_opcode, 2); + } + } + + /* Move INSN to offset WHERE in FRAG. Adjust the fixups accordingly + and install the opcode in the new location. */ + + static void + move_insn (struct mips_cl_insn *insn, fragS *frag, long where) + { + size_t i; + + insn->frag = frag; + insn->where = where; + for (i = 0; i < ARRAY_SIZE (insn->fixp); i++) + if (insn->fixp[i] != NULL) + { + insn->fixp[i]->fx_frag = frag; + insn->fixp[i]->fx_where = where; + } + install_insn (insn); + } + + /* Add INSN to the end of the output. */ + + static void + add_fixed_insn (struct mips_cl_insn *insn) + { + char *f = frag_more (insn_length (insn)); + move_insn (insn, frag_now, f - frag_now->fr_literal); + } + + /* Start a variant frag and move INSN to the start of the variant part, + marking it as fixed. The other arguments are as for frag_var. */ + + static void + add_relaxed_insn (struct mips_cl_insn *insn, int max_chars, int var, + relax_substateT subtype, symbolS *symbol, offsetT offset) + { + frag_grow (max_chars); + move_insn (insn, frag_now, frag_more (0) - frag_now->fr_literal); + insn->fixed_p = 1; + frag_var (rs_machine_dependent, max_chars, var, + subtype, symbol, offset, NULL); + } + + /* Insert N copies of INSN into the history buffer, starting at + position FIRST. Neither FIRST nor N need to be clipped. */ + + static void + insert_into_history (unsigned int first, unsigned int n, + const struct mips_cl_insn *insn) + { + if (mips_relax.sequence != 2) + { + unsigned int i; + + for (i = ARRAY_SIZE (history); i-- > first;) + if (i >= first + n) + history[i] = history[i - n]; + else + history[i] = *insn; + } + } + + /* Emit a nop instruction, recording it in the history buffer. */ + + static void + emit_nop (void) + { + add_fixed_insn (NOP_INSN); + insert_into_history (0, 1, NOP_INSN); + } + /* This function is called once, at assembler startup time. It should set up all the tables, etc. that the MD part of the assembler will need. */ *************** md_begin (void) *** 1192,1197 **** --- 1318,1328 ---- { if (!validate_mips_insn (&mips_opcodes[i])) broken = 1; + if (nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0) + { + create_insn (&nop_insn, mips_opcodes + i); + nop_insn.fixed_p = 1; + } } ++i; } *************** md_begin (void) *** 1219,1224 **** --- 1350,1360 ---- mips16_opcodes[i].name, mips16_opcodes[i].args); broken = 1; } + if (mips16_nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0) + { + create_insn (&mips16_nop_insn, mips16_opcodes + i); + mips16_nop_insn.fixed_p = 1; + } ++i; } while (i < bfd_mips16_num_opcodes *************** append_insn (struct mips_cl_insn *ip, ex *** 1646,1657 **** bfd_reloc_code_real_type *reloc_type) { register unsigned long prev_pinfo, pinfo; - char *f; - fixS *fixp[3]; int nops = 0; relax_stateT prev_insn_frag_type = 0; bfd_boolean relaxed_branch = FALSE; - bfd_boolean force_new_frag = FALSE; /* Mark instruction labels in mips16 mode. */ mips16_mark_labels (); --- 1782,1790 ---- *************** append_insn (struct mips_cl_insn *ip, ex *** 1684,1695 **** benefit hand written assembly code, and does not seem worth it. */ - /* This is how a NOP is emitted. */ - #define emit_nop() \ - (mips_opts.mips16 \ - ? md_number_to_chars (frag_more (2), 0x6500, 2) \ - : md_number_to_chars (frag_more (4), 0, 4)) - /* The previous insn might require a delay slot, depending upon the contents of the current insn. */ if (! mips_opts.mips16 --- 1817,1822 ---- *************** append_insn (struct mips_cl_insn *ip, ex *** 2061,2092 **** && !mips_opts.mips16) { relaxed_branch = TRUE; ! f = frag_var (rs_machine_dependent, ! relaxed_branch_length ! (NULL, NULL, ! (pinfo & INSN_UNCOND_BRANCH_DELAY) ? -1 ! : (pinfo & INSN_COND_BRANCH_LIKELY) ? 1 : 0), 4, ! RELAX_BRANCH_ENCODE ! (pinfo & INSN_UNCOND_BRANCH_DELAY, ! pinfo & INSN_COND_BRANCH_LIKELY, ! pinfo & INSN_WRITE_GPR_31, ! 0), ! address_expr->X_add_symbol, ! address_expr->X_add_number, ! 0); *reloc_type = BFD_RELOC_UNUSED; } else if (*reloc_type > BFD_RELOC_UNUSED) { /* We need to set up a variant frag. */ assert (mips_opts.mips16 && address_expr != NULL); ! f = frag_var (rs_machine_dependent, 4, 0, ! RELAX_MIPS16_ENCODE (*reloc_type - BFD_RELOC_UNUSED, ! mips16_small, mips16_ext, ! (prev_pinfo ! & INSN_UNCOND_BRANCH_DELAY), ! history[0].mips16_absolute_jump_p), ! make_expr_symbol (address_expr), 0, NULL); } else if (mips_opts.mips16 && ! ip->use_extend --- 2188,2218 ---- && !mips_opts.mips16) { relaxed_branch = TRUE; ! add_relaxed_insn (ip, (relaxed_branch_length ! (NULL, NULL, ! (pinfo & INSN_UNCOND_BRANCH_DELAY) ? -1 ! : (pinfo & INSN_COND_BRANCH_LIKELY) ? 1 ! : 0)), 4, ! RELAX_BRANCH_ENCODE ! (pinfo & INSN_UNCOND_BRANCH_DELAY, ! pinfo & INSN_COND_BRANCH_LIKELY, ! pinfo & INSN_WRITE_GPR_31, ! 0), ! address_expr->X_add_symbol, ! address_expr->X_add_number); *reloc_type = BFD_RELOC_UNUSED; } else if (*reloc_type > BFD_RELOC_UNUSED) { /* We need to set up a variant frag. */ assert (mips_opts.mips16 && address_expr != NULL); ! add_relaxed_insn (ip, 4, 0, ! RELAX_MIPS16_ENCODE ! (*reloc_type - BFD_RELOC_UNUSED, ! mips16_small, mips16_ext, ! prev_pinfo & INSN_UNCOND_BRANCH_DELAY, ! history[0].mips16_absolute_jump_p), ! make_expr_symbol (address_expr), 0); } else if (mips_opts.mips16 && ! ip->use_extend *************** append_insn (struct mips_cl_insn *ip, ex *** 2095,2101 **** /* Make sure there is enough room to swap this instruction with a following jump instruction. */ frag_grow (6); ! f = frag_more (2); } else { --- 2221,2227 ---- /* Make sure there is enough room to swap this instruction with a following jump instruction. */ frag_grow (6); ! add_fixed_insn (ip); } else { *************** append_insn (struct mips_cl_insn *ip, ex *** 2119,2128 **** if (mips_relax.sequence != 1) mips_macro_warning.sizes[1] += 4; ! f = frag_more (4); } - fixp[0] = fixp[1] = fixp[2] = NULL; if (address_expr != NULL && *reloc_type <= BFD_RELOC_UNUSED) { if (address_expr->X_op == O_constant) --- 2245,2258 ---- if (mips_relax.sequence != 1) mips_macro_warning.sizes[1] += 4; ! if (mips_opts.mips16) ! { ! ip->fixed_p = 1; ! ip->mips16_absolute_jump_p = (*reloc_type == BFD_RELOC_MIPS16_JMP); ! } ! add_fixed_insn (ip); } if (address_expr != NULL && *reloc_type <= BFD_RELOC_UNUSED) { if (address_expr->X_op == O_constant) *************** append_insn (struct mips_cl_insn *ip, ex *** 2203,2213 **** break; howto = bfd_reloc_type_lookup (stdoutput, reloc_type[i - 1]); ! fixp[0] = fix_new_exp (frag_now, f - frag_now->fr_literal, ! bfd_get_reloc_size(howto), ! address_expr, ! reloc_type[0] == BFD_RELOC_16_PCREL_S2, ! reloc_type[0]); /* These relocations can have an addend that won't fit in 4 octets for 64bit assembly. */ --- 2333,2343 ---- break; howto = bfd_reloc_type_lookup (stdoutput, reloc_type[i - 1]); ! ip->fixp[0] = fix_new_exp (ip->frag, ip->where, ! bfd_get_reloc_size (howto), ! address_expr, ! reloc_type[0] == BFD_RELOC_16_PCREL_S2, ! reloc_type[0]); /* These relocations can have an addend that won't fit in 4 octets for 64bit assembly. */ *************** append_insn (struct mips_cl_insn *ip, ex *** 2232,2243 **** || reloc_type[0] == BFD_RELOC_MIPS16_GPREL || reloc_type[0] == BFD_RELOC_MIPS16_HI16_S || reloc_type[0] == BFD_RELOC_MIPS16_LO16)) ! fixp[0]->fx_no_overflow = 1; if (mips_relax.sequence) { if (mips_relax.first_fixup == 0) ! mips_relax.first_fixup = fixp[0]; } else if (reloc_needs_lo_p (*reloc_type)) { --- 2362,2373 ---- || reloc_type[0] == BFD_RELOC_MIPS16_GPREL || reloc_type[0] == BFD_RELOC_MIPS16_HI16_S || reloc_type[0] == BFD_RELOC_MIPS16_LO16)) ! ip->fixp[0]->fx_no_overflow = 1; if (mips_relax.sequence) { if (mips_relax.first_fixup == 0) ! mips_relax.first_fixup = ip->fixp[0]; } else if (reloc_needs_lo_p (*reloc_type)) { *************** append_insn (struct mips_cl_insn *ip, ex *** 2253,2259 **** hi_fixup->next = mips_hi_fixup_list; mips_hi_fixup_list = hi_fixup; } ! hi_fixup->fixp = fixp[0]; hi_fixup->seg = now_seg; } --- 2383,2389 ---- hi_fixup->next = mips_hi_fixup_list; mips_hi_fixup_list = hi_fixup; } ! hi_fixup->fixp = ip->fixp[0]; hi_fixup->seg = now_seg; } *************** append_insn (struct mips_cl_insn *ip, ex *** 2265,2297 **** for (i = 1; i < 3; i++) if (reloc_type[i] != BFD_RELOC_UNUSED) { ! fixp[i] = fix_new (frag_now, fixp[0]->fx_where, ! fixp[0]->fx_size, NULL, 0, ! FALSE, reloc_type[i]); /* Use fx_tcbit to mark compound relocs. */ ! fixp[0]->fx_tcbit = 1; ! fixp[i]->fx_tcbit = 1; } } } ! ! if (! mips_opts.mips16) ! md_number_to_chars (f, ip->insn_opcode, 4); ! else if (*reloc_type == BFD_RELOC_MIPS16_JMP) ! { ! md_number_to_chars (f, ip->insn_opcode >> 16, 2); ! md_number_to_chars (f + 2, ip->insn_opcode & 0xffff, 2); ! } ! else ! { ! if (ip->use_extend) ! { ! md_number_to_chars (f, 0xf000 | ip->extend, 2); ! f += 2; ! } ! md_number_to_chars (f, ip->insn_opcode, 2); ! } /* Update the register mask information. */ if (! mips_opts.mips16) --- 2395,2411 ---- 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, reloc_type[i]); /* Use fx_tcbit to mark compound relocs. */ ! ip->fixp[0]->fx_tcbit = 1; ! ip->fixp[i]->fx_tcbit = 1; } } } ! install_insn (ip); /* Update the register mask information. */ if (! mips_opts.mips16) *************** append_insn (struct mips_cl_insn *ip, ex *** 2534,2696 **** portions of this object file; we could pick up the instruction at the destination, put it in the delay slot, and bump the destination address. */ emit_nop (); if (mips_relax.sequence) mips_relax.sizes[mips_relax.sequence - 1] += 4; - /* Update the previous insn information. */ - history[1].insn_mo = ip->insn_mo; - history[1].use_extend = ip->use_extend; - history[1].extend = ip->extend; - history[1].insn_opcode = ip->insn_opcode; - history[0].insn_mo = &dummy_opcode; } else { /* It looks like we can actually do the swap. */ ! if (! mips_opts.mips16) { ! char *prev_f; ! char temp[4]; ! ! prev_f = history[0].frag->fr_literal + history[0].where; ! if (!relaxed_branch) ! { ! /* If this is not a relaxed branch, then just ! swap the instructions. */ ! memcpy (temp, prev_f, 4); ! memcpy (prev_f, f, 4); ! memcpy (f, temp, 4); ! } ! else ! { ! /* If this is a relaxed branch, then we move the ! instruction to be placed in the delay slot to ! the current frag, shrinking the fixed part of ! the originating frag. If the branch occupies ! the tail of the latter, we move it backwards, ! into the space freed by the moved instruction. */ ! f = frag_more (4); ! memcpy (f, prev_f, 4); ! history[0].frag->fr_fix -= 4; ! if (history[0].frag->fr_type == rs_machine_dependent) ! memmove (prev_f, prev_f + 4, history[0].frag->fr_var); ! } ! ! if (history[0].fixp[0]) ! { ! history[0].fixp[0]->fx_frag = frag_now; ! history[0].fixp[0]->fx_where = f - frag_now->fr_literal; ! } ! if (history[0].fixp[1]) ! { ! history[0].fixp[1]->fx_frag = frag_now; ! history[0].fixp[1]->fx_where = f - frag_now->fr_literal; ! } ! if (history[0].fixp[2]) ! { ! history[0].fixp[2]->fx_frag = frag_now; ! history[0].fixp[2]->fx_where = f - frag_now->fr_literal; ! } ! if (history[0].fixp[0] && HAVE_NEWABI ! && history[0].frag != frag_now ! && (history[0].fixp[0]->fx_r_type ! == BFD_RELOC_MIPS_GOT_DISP ! || (history[0].fixp[0]->fx_r_type ! == BFD_RELOC_MIPS_CALL16))) ! { ! /* To avoid confusion in tc_gen_reloc, we must ! ensure that this does not become a variant ! frag. */ ! force_new_frag = TRUE; ! } ! ! if (!relaxed_branch) ! { ! if (fixp[0]) ! { ! fixp[0]->fx_frag = history[0].frag; ! fixp[0]->fx_where = history[0].where; ! } ! if (fixp[1]) ! { ! fixp[1]->fx_frag = history[0].frag; ! fixp[1]->fx_where = history[0].where; ! } ! if (fixp[2]) ! { ! fixp[2]->fx_frag = history[0].frag; ! fixp[2]->fx_where = history[0].where; ! } ! } ! else if (history[0].frag->fr_type == rs_machine_dependent) ! { ! if (fixp[0]) ! fixp[0]->fx_where -= 4; ! if (fixp[1]) ! fixp[1]->fx_where -= 4; ! if (fixp[2]) ! fixp[2]->fx_where -= 4; ! } } else { ! char *prev_f; ! char temp[2]; ! ! assert (history[0].fixp[0] == NULL); ! assert (history[0].fixp[1] == NULL); ! assert (history[0].fixp[2] == NULL); ! prev_f = history[0].frag->fr_literal + history[0].where; ! memcpy (temp, prev_f, 2); ! memcpy (prev_f, f, 2); ! if (*reloc_type != BFD_RELOC_MIPS16_JMP) ! { ! assert (*reloc_type == BFD_RELOC_UNUSED); ! memcpy (f, temp, 2); ! } ! else ! { ! memcpy (f, f + 2, 2); ! memcpy (f + 2, temp, 2); ! } ! if (fixp[0]) ! { ! fixp[0]->fx_frag = history[0].frag; ! fixp[0]->fx_where = history[0].where; ! } ! if (fixp[1]) ! { ! fixp[1]->fx_frag = history[0].frag; ! fixp[1]->fx_where = history[0].where; ! } ! if (fixp[2]) ! { ! fixp[2]->fx_frag = history[0].frag; ! fixp[2]->fx_where = history[0].where; ! } } ! ! /* Update the previous insn information; leave history[0] ! unchanged. */ ! history[1].insn_mo = ip->insn_mo; ! history[1].use_extend = ip->use_extend; ! history[1].extend = ip->extend; ! history[1].insn_opcode = ip->insn_opcode; } - history[0].fixed_p = 1; /* If that was an unconditional branch, forget the previous insn information. */ if (pinfo & INSN_UNCOND_BRANCH_DELAY) ! { ! history[1].insn_mo = &dummy_opcode; ! history[0].insn_mo = &dummy_opcode; ! } ! ! history[0].fixp[0] = NULL; ! history[0].fixp[1] = NULL; ! history[0].fixp[2] = NULL; ! history[0].mips16_absolute_jump_p = 0; } else if (pinfo & INSN_COND_BRANCH_LIKELY) { --- 2648,2693 ---- portions of this object file; we could pick up the instruction at the destination, put it in the delay slot, and bump the destination address. */ + insert_into_history (0, 1, ip); emit_nop (); if (mips_relax.sequence) mips_relax.sizes[mips_relax.sequence - 1] += 4; } else { /* It looks like we can actually do the swap. */ ! struct mips_cl_insn delay = history[0]; ! if (mips_opts.mips16) { ! know (delay.frag == ip->frag); ! move_insn (ip, delay.frag, delay.where); ! move_insn (&delay, ip->frag, ip->where + insn_length (ip)); ! } ! else if (relaxed_branch) ! { ! /* Add the delay slot instruction to the end of the ! current frag and shrink the fixed part of the ! original frag. If the branch occupies the tail of ! the latter, move it backwards to cover the gap. */ ! delay.frag->fr_fix -= 4; ! if (delay.frag == ip->frag) ! move_insn (ip, ip->frag, ip->where - 4); ! add_fixed_insn (&delay); } else { ! move_insn (&delay, ip->frag, ip->where); ! move_insn (ip, history[0].frag, history[0].where); } ! history[0] = *ip; ! delay.fixed_p = 1; ! insert_into_history (0, 1, &delay); } /* If that was an unconditional branch, forget the previous insn information. */ if (pinfo & INSN_UNCOND_BRANCH_DELAY) ! mips_no_prev_insn (FALSE); } else if (pinfo & INSN_COND_BRANCH_LIKELY) { *************** append_insn (struct mips_cl_insn *ip, ex *** 2698,2766 **** is look at the target, copy the instruction found there into the delay slot, and increment the branch to jump to the next instruction. */ emit_nop (); - /* Update the previous insn information. */ - history[1].insn_mo = ip->insn_mo; - history[1].use_extend = ip->use_extend; - history[1].extend = ip->extend; - history[1].insn_opcode = ip->insn_opcode; - history[0].insn_mo = &dummy_opcode; - history[0].fixp[0] = NULL; - history[0].fixp[1] = NULL; - history[0].fixp[2] = NULL; - history[0].mips16_absolute_jump_p = 0; - history[0].fixed_p = 1; } else ! { ! /* Update the previous insn information. */ ! if (nops > 0) ! history[1].insn_mo = &dummy_opcode; ! else ! { ! history[1].insn_mo = history[0].insn_mo; ! history[1].use_extend = history[0].use_extend; ! history[1].extend = history[0].extend; ! history[1].insn_opcode = history[0].insn_opcode; ! } ! history[0].insn_mo = ip->insn_mo; ! history[0].use_extend = ip->use_extend; ! history[0].extend = ip->extend; ! history[0].insn_opcode = ip->insn_opcode; ! history[0].fixed_p = (mips_opts.mips16 ! && (ip->use_extend ! || *reloc_type > BFD_RELOC_UNUSED)); ! history[0].fixp[0] = fixp[0]; ! history[0].fixp[1] = fixp[1]; ! history[0].fixp[2] = fixp[2]; ! history[0].mips16_absolute_jump_p = (reloc_type[0] ! == BFD_RELOC_MIPS16_JMP); ! } ! ! history[1].noreorder_p = history[0].noreorder_p; ! history[0].noreorder_p = 0; ! history[0].frag = frag_now; ! history[0].where = f - frag_now->fr_literal; ! } ! else if (mips_relax.sequence != 2) ! { ! /* We need to record a bit of information even when we are not ! reordering, in order to determine the base address for mips16 ! PC relative relocs. */ ! history[1].insn_mo = history[0].insn_mo; ! history[1].use_extend = history[0].use_extend; ! history[1].extend = history[0].extend; ! history[1].insn_opcode = history[0].insn_opcode; ! history[0].insn_mo = ip->insn_mo; ! history[0].use_extend = ip->use_extend; ! history[0].extend = ip->extend; ! history[0].insn_opcode = ip->insn_opcode; ! history[0].mips16_absolute_jump_p = (reloc_type[0] ! == BFD_RELOC_MIPS16_JMP); ! history[1].noreorder_p = history[0].noreorder_p; ! history[0].noreorder_p = 1; ! history[0].fixed_p = 1; } /* We just output an insn, so the next one doesn't have a label. */ mips_clear_insn_labels (); --- 2695,2708 ---- is look at the target, copy the instruction found there into the delay slot, and increment the branch to jump to the next instruction. */ + insert_into_history (0, 1, ip); emit_nop (); } else ! insert_into_history (0, 1, ip); } + else + insert_into_history (0, 1, ip); /* We just output an insn, so the next one doesn't have a label. */ mips_clear_insn_labels (); *************** append_insn (struct mips_cl_insn *ip, ex *** 2773,2791 **** static void mips_no_prev_insn (int preserve) { if (! preserve) { - history[0].insn_mo = &dummy_opcode; - history[1].insn_mo = &dummy_opcode; prev_nop_frag = NULL; prev_nop_frag_holds = 0; prev_nop_frag_required = 0; prev_nop_frag_since = 0; } ! history[0].fixed_p = 1; ! history[0].noreorder_p = 0; ! history[0].mips16_absolute_jump_p = 0; ! history[1].noreorder_p = 0; mips_clear_insn_labels (); } --- 2715,2738 ---- static void mips_no_prev_insn (int preserve) { + size_t i; + if (! preserve) { prev_nop_frag = NULL; prev_nop_frag_holds = 0; prev_nop_frag_required = 0; prev_nop_frag_since = 0; + for (i = 0; i < ARRAY_SIZE (history); i++) + history[i] = (mips_opts.mips16 ? mips16_nop_insn : nop_insn); } ! else ! for (i = 0; i < ARRAY_SIZE (history); i++) ! { ! history[i].fixed_p = 1; ! history[i].noreorder_p = 0; ! history[i].mips16_absolute_jump_p = 0; ! } mips_clear_insn_labels (); } *************** mips_emit_delays (bfd_boolean insns) *** 2874,2880 **** } for (; nops > 0; --nops) ! emit_nop (); if (insns) { --- 2821,2827 ---- } for (; nops > 0; --nops) ! add_fixed_insn (NOP_INSN); if (insns) { *************** macro_read_relocs (va_list *args, bfd_re *** 2997,3002 **** --- 2944,2950 ---- static void macro_build (expressionS *ep, const char *name, const char *fmt, ...) { + const struct mips_opcode *mo; struct mips_cl_insn insn; bfd_reloc_code_real_type r[3]; va_list args; *************** macro_build (expressionS *ep, const char *** 3013,3042 **** r[0] = BFD_RELOC_UNUSED; r[1] = BFD_RELOC_UNUSED; r[2] = BFD_RELOC_UNUSED; ! insn.insn_mo = (struct mips_opcode *) hash_find (op_hash, name); ! assert (insn.insn_mo); ! assert (strcmp (name, insn.insn_mo->name) == 0); ! ! /* Search until we get a match for NAME. */ ! while (1) ! { ! /* It is assumed here that macros will never generate ! MDMX or MIPS-3D instructions. */ ! if (strcmp (fmt, insn.insn_mo->args) == 0 ! && insn.insn_mo->pinfo != INSN_MACRO ! && OPCODE_IS_MEMBER (insn.insn_mo, ! (mips_opts.isa ! | (file_ase_mips16 ? INSN_MIPS16 : 0)), mips_opts.arch) ! && (mips_opts.arch != CPU_R4650 || (insn.insn_mo->pinfo & FP_D) == 0)) ! break; ! ! ++insn.insn_mo; ! assert (insn.insn_mo->name); ! assert (strcmp (name, insn.insn_mo->name) == 0); } ! insn.insn_opcode = insn.insn_mo->match; for (;;) { switch (*fmt++) --- 2961,2986 ---- r[0] = BFD_RELOC_UNUSED; r[1] = BFD_RELOC_UNUSED; r[2] = BFD_RELOC_UNUSED; ! mo = (struct mips_opcode *) hash_find (op_hash, name); ! assert (mo); ! assert (strcmp (name, mo->name) == 0); ! ! /* Search until we get a match for NAME. It is assumed here that ! macros will never generate MDMX or MIPS-3D instructions. */ ! while (strcmp (fmt, mo->args) != 0 ! || mo->pinfo == INSN_MACRO ! || !OPCODE_IS_MEMBER (mo, ! (mips_opts.isa ! | (file_ase_mips16 ? INSN_MIPS16 : 0)), mips_opts.arch) ! || (mips_opts.arch == CPU_R4650 && (mo->pinfo & FP_D) != 0)) ! { ! ++mo; ! assert (mo->name); ! assert (strcmp (name, mo->name) == 0); } ! create_insn (&insn, mo); for (;;) { switch (*fmt++) *************** static void *** 3219,3243 **** mips16_macro_build (expressionS *ep, const char *name, const char *fmt, va_list args) { struct mips_cl_insn insn; bfd_reloc_code_real_type r[3] = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED}; ! insn.insn_mo = (struct mips_opcode *) hash_find (mips16_op_hash, name); ! assert (insn.insn_mo); ! assert (strcmp (name, insn.insn_mo->name) == 0); ! ! while (strcmp (fmt, insn.insn_mo->args) != 0 ! || insn.insn_mo->pinfo == INSN_MACRO) ! { ! ++insn.insn_mo; ! assert (insn.insn_mo->name); ! assert (strcmp (name, insn.insn_mo->name) == 0); ! } ! insn.insn_opcode = insn.insn_mo->match; ! insn.use_extend = FALSE; for (;;) { int c; --- 3163,3185 ---- mips16_macro_build (expressionS *ep, const char *name, const char *fmt, va_list args) { + struct mips_opcode *mo; struct mips_cl_insn insn; bfd_reloc_code_real_type r[3] = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED}; ! mo = (struct mips_opcode *) hash_find (mips16_op_hash, name); ! assert (mo); ! assert (strcmp (name, mo->name) == 0); ! while (strcmp (fmt, mo->args) != 0 || mo->pinfo == INSN_MACRO) ! { ! ++mo; ! assert (mo->name); ! assert (strcmp (name, mo->name) == 0); ! } + create_insn (&insn, mo); for (;;) { int c; *************** static void *** 3363,3368 **** --- 3305,3311 ---- macro_build_lui (expressionS *ep, int regnum) { expressionS high_expr; + const struct mips_opcode *mo; struct mips_cl_insn insn; bfd_reloc_code_real_type r[3] = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED}; *************** macro_build_lui (expressionS *ep, int re *** 3394,3403 **** *r = BFD_RELOC_HI16_S; } ! insn.insn_mo = (struct mips_opcode *) hash_find (op_hash, name); ! assert (insn.insn_mo); ! assert (strcmp (name, insn.insn_mo->name) == 0); ! assert (strcmp (fmt, insn.insn_mo->args) == 0); insn.insn_opcode = insn.insn_mo->match; INSERT_OPERAND (RT, insn, regnum); --- 3337,3346 ---- *r = BFD_RELOC_HI16_S; } ! mo = hash_find (op_hash, name); ! assert (strcmp (name, mo->name) == 0); ! assert (strcmp (fmt, mo->args) == 0); ! create_insn (&insn, mo); insn.insn_opcode = insn.insn_mo->match; INSERT_OPERAND (RT, insn, regnum); *************** mips_ip (char *str, struct mips_cl_insn *** 8018,8025 **** } } ! ip->insn_mo = insn; ! ip->insn_opcode = insn->match; insn_error = NULL; for (args = insn->args;; ++args) { --- 7961,7967 ---- } } ! create_insn (ip, insn); insn_error = NULL; for (args = insn->args;; ++args) { *************** mips16_ip (char *str, struct mips_cl_ins *** 9123,9131 **** { assert (strcmp (insn->name, str) == 0); ! ip->insn_mo = insn; ! ip->insn_opcode = insn->match; ! ip->use_extend = FALSE; imm_expr.X_op = O_absent; imm_reloc[0] = BFD_RELOC_UNUSED; imm_reloc[1] = BFD_RELOC_UNUSED; --- 9065,9071 ---- { assert (strcmp (insn->name, str) == 0); ! create_insn (ip, insn); imm_expr.X_op = O_absent; imm_reloc[0] = BFD_RELOC_UNUSED; imm_reloc[1] = BFD_RELOC_UNUSED;