Hi Richard & all, I am back at last with updates to the change and I have combined two e-mails here again. I hope this covers all the outstanding concerns and nothing from earlier correspondence has been lost unaddressed. Chao-ying, there are a couple of questions for you throughout -- would you please give them a thought? And anyone, of course, please feel free to comment as you like. > "Maciej W. Rozycki" writes: > > > > Well, if we have code like this: > > > > branch ... > > LUI ... > > insn [...] > > > > (where for the purpose of this consideration BRANCH may also be a jump) > > then LUI cannot be entirely deleted and INSN moved into the slot of BRANCH > > no matter if INSN is a branch or an computational instruction. All we can > > do in this case is to see if there is a corresponding BRANCHC instruction > > and use it to swap BRANCH with and then delete the LUI if so, or otherwise > > shrink the LUI to a 16-bit NOP if BRANCH permits or can be swapped with > > BRANCHS to permit a 16-bit delay-slot instruction. If neither is > > possible, then the LUI is merely substituted with a 32-bit NOP (although > > the effect is purely cosmetical in this case; perhaps we should just back > > out). > > Yeah, I see your point. I was thinking that the code claims to "know" > that the LUI and "insn" are both part of the same load address. So if > the branch was taken, the target of the LUI ought to be dead. However, > I agree that (even though the code does seem to assume that to some extent) > the assumption is wrong. > > E.g. you could have: > > beqz $2,1f > lui $4,%hi(foo) <-- A > > addiu $4,$4,%lo(foo) <-- B > ... > jr $31 > 2: ... > lui $4,%hi(foo) <-- C > ... > 1: addiu $4,$4,%lo(foo) <-- D > > In this case, the LO16 reloc for D might follow the HI16 reloc for C, > and the LO16 reloc for B might follow the HI16 reloc for A. AIUI, we'd > consider relaxing A/B but not C/D. In this case, turning A into a NOP > is wrong, because $4 is still live at D. If you agree then... > > > Also with the recent update to LUI relaxation code I think we should > > simply disallow the optimisation if a LUI is in a delay slot of an > > unconditional branch -- we have no way to verify the corresponding LO16 > > reloc really belongs to this LUI instruction in that case. This will let > > us simplify code (which has become a little bit hairy by now IMO) a little > > bit I would guess. [FIXME] > > ...maybe it would be simpler to drop the optimisation if the LUI is any > kind of delay slot. I think this would simply the code, and I don't think > we'd then need to check for branch relocs. We'd just have *_norel-like > functions (although not called that any more) to check for every kind > of branch. I have implemented these changes now, dropping the unsafe part of optimisation for the scenario you have listed. I still have two concerns about this optimisation, but the optional nature of linker relaxation makes them reasonably unimportant IMO: 1. The resulting change of alignment may cause the linker produce bad code or abort the process if microMIPS and standard MIPS code is mixed in one object file and the latter turns out to become unaligned, e.g. .set micromips .set noreorder .align 2 .globl foo .ent foo foo: beqz32 $4, 0f nop16 0: jalx bar nop .end foo .set nomicromips .align 2 .globl bar .ent bar bar: nop .end bar The piece above will fail to link, because BEQZ will be converted to a BEQZC and the 16-bit NOP from its delay slot taken out. As a result bar() will become misaligned and the JALX will not be allowed. If there was no JALX, then linking might succeed if there were only indirect calls to bar(), but the function would not be properly aligned for standard MIPS execution. 2. Broken code is produced for cases like this: .set noreorder lui $4, 0x1234 lui $2, %hi(foo) bnez $3, 0f addiu $2, %lo(foo) ... lui $4, %hi(foo) 0: jal bar addiu $4, %lo(foo) where the resulting code: .set noreorder lui $4, 0x1234 bnez $3, 0f addiu $2, $pc, foo - . ... 0: jal bar addiu $4, $pc, foo - . obviously not being the same. Such usage of HI16/LO16 relocations is non-standard, but not disallowed. OTOH searching the symbol tables for the label (we could disable this relaxation if there's one at the instruction a LO16 relocation is against) is expensive. What do you think? [FIXME] On Sun, 2 Jan 2011, Richard Sandiford wrote: > This is the second and final part of the review. > > First of all, thanks for the great effort you've made to integrate the > microMIPS macro code into macro(). This is much, much better than before, > and should be far less of a maintenance burden. I hope so too and thanks for your extensive effort too. > FWIW, I plan to review the follow-up patch based purely on whether > it deals with the review comments. Anything that we've collectively > missed this far (and there's bound to be something) will just have to > be fixed when someone trips over it. OK. > I think the only change of any significant size that needs to be made > is to move the place where we convert to microMIPS relocs (see below). > Everything else is pretty small. Honestly the reloc conversion change was probably the smallest of all (barring formatting fixes). :/ > > @@ -1821,6 +1830,8 @@ the target word. These are used on the > > ENUM > > BFD_RELOC_GPREL16 > > ENUMX > > + BFD_RELOC_MICROMIPS_GPREL16 > > +ENUMX > > BFD_RELOC_GPREL32 > > ENUMDOC > > For systems that allocate a Global Pointer register, these are > > You've now moved most of the new relocs into MIPS-specific areas, thanks, > but some, like the one above, are still in generic lists. Let's put: > > ENUM > BFD_RELOC_MICROMIPS_7_PCREL_S1 > ENUMX > BFD_RELOC_MICROMIPS_10_PCREL_S1 > ENUMX > BFD_RELOC_MICROMIPS_16_PCREL_S1 > ENUMDOC > MicroMIPS PC-relative relocations. > > before the main "MIPS ELF relocations." section, followed > by a new section: > > ENUM > BFD_RELOC_MICROMIPS_GPREL16 > ENUMX > BFD_RELOC_MICROMIPS_HI16 > ENUMX > BFD_RELOC_MICROMIPS_HI16_S > ENUMX > BFD_RELOC_MICROMIPS_LO16 > ENUMDOC > MicroMIPS versions of generic BFD relocs. > > Also, let's combine this: > > > @@ -2182,6 +2193,11 @@ ENUMDOC > > simple reloc otherwise. > > > > ENUM > > + BFD_RELOC_MICROMIPS_JMP > > +ENUMDOC > > + The microMIPS jump instruction. > > + > > +ENUM > > BFD_RELOC_MIPS16_JMP > > ENUMDOC > > The MIPS16 jump instruction. > > with the MIPS_JMP entry, since you're doing the same with the other > microMIPS versions of MIPS relocs. OK, but I had to remove the original documentation note. The immediate argument is only shifted left by one bit in the microMIPS mode. > > + /* Whether we are assembling for the mipsMIPS processor. 0 if we are > > + not, 1 if we are, and -1 if the value has not been initialized. > > + Changed by `.set micromips' and `.set nomicromips', and the -mmicromips > > + and -mno-micromips command line options, and the default CPU. */ > > + int micromips; > > Blind cut-&-paste. "microMIPS ASE". > > Let's leave the -1 case and: > > > +/* Return true if the given CPU supports microMIPS. */ > > +#define CPU_HAS_MICROMIPS(cpu) 0 > > out. I think the CPU_HAS_MIPS16 stuff is derived from the original LSI > TinyRisc support and wouldn't be used for ASEs. The microMIPS ASE provides for processors that do not support the standard MIPS instruction set. These I think should default to the microMIPS mode. I suspect someone will eventually implement such a processor as since we've got this code implemented here already I'd like to leave it as a placeholder. I think it's not much of a burden, is it? > > @@ -495,9 +515,11 @@ static int mips_32bitmode = 0; > > require nops to be inserted. This applies to instructions marked > > INSN_LOAD_MEMORY_DELAY. These nops are only required at MIPS ISA > > level I. */ > > -#define gpr_interlocks \ > > - (mips_opts.isa != ISA_MIPS1 \ > > - || mips_opts.arch == CPU_R3900) > > +#define gpr_interlocks \ > > + (mips_opts.isa != ISA_MIPS1 \ > > + || mips_opts.arch == CPU_R3900 \ > > + || mips_opts.micromips \ > > + ) > > > > /* Whether the processor uses hardware interlocks to avoid delays > > required by coprocessor instructions, and thus does not require > > @@ -512,6 +534,7 @@ static int mips_32bitmode = 0; > > && mips_opts.isa != ISA_MIPS2 \ > > && mips_opts.isa != ISA_MIPS3) \ > > || mips_opts.arch == CPU_R4300 \ > > + || mips_opts.micromips \ > > ) > > > > /* Whether the processor uses hardware interlocks to protect reads > > @@ -519,7 +542,10 @@ static int mips_32bitmode = 0; > > thus does not require nops to be inserted. This applies to > > instructions marked INSN_COPROC_MEMORY_DELAY. These nops are only > > requires at MIPS ISA level I. */ > > -#define cop_mem_interlocks (mips_opts.isa != ISA_MIPS1) > > +#define cop_mem_interlocks \ > > + (mips_opts.isa != ISA_MIPS1 \ > > + || mips_opts.micromips \ > > + ) > > > > /* Is this a mfhi or mflo instruction? */ > > #define MF_HILO_INSN(PINFO) \ > > These changes are OK if they make life easier, but please add a comment > saying why they do. No interlocks are ever needed for microMIPS code, even if building with -mips1 (the default). I have added a note to this effect to the relevant comments. > > +#define RELAX_MICROMIPS_ENCODE(type, is_16bit, uncond, link, toofar) \ > > + (0x40000000 \ > > + | ((type) & 0xff) \ > > + | ((is_16bit) ? 0x100 : 0) \ > > + | ((uncond) ? 0x200 : 0) \ > > + | ((link) ? 0x400 : 0) \ > > + | ((toofar) ? 0x800 : 0)) > > +#define RELAX_MICROMIPS_P(i) (((i) & 0xc0000000) == 0x40000000) > > +#define RELAX_MICROMIPS_TYPE(i) ((i) & 0xff) > > +#define RELAX_MICROMIPS_USER_16BIT(i) (((i) & 0x100) != 0) > > +#define RELAX_MICROMIPS_UNCOND(i) (((i) & 0x200) != 0) > > +#define RELAX_MICROMIPS_LINK(i) (((i) & 0x400) != 0) > > +#define RELAX_MICROMIPS_TOOFAR(i) (((i) & 0x800) != 0) > > +#define RELAX_MICROMIPS_MARK_TOOFAR(i) ((i) | 0x800) > > +#define RELAX_MICROMIPS_CLEAR_TOOFAR(i) ((i) & ~0x800) > > Is there a need to create variant frags when the user has explicitly > specified the instruction size? I wouldn't have expected any relaxation > to be necessary in that case, and it looks like the relaxation code does > indeed return 2 whenever USER_16BIT is true. I suspect this has been copied over from MIPS16 code. RELAX_MIPS16_USER_SMALL seems to be used in a similar fashion. Do you happen to know for sure why it has been implemented this way for MIPS16 assembly? My suspicion is we want to keep the relocation until the final relaxation so that if the final value turns out to fit afterwards (but not until then) in the forced-truncated immediate field of the instruction nothing is lost. > If the bit really is needed, let's call the parameter "user_16bit" > rather than "is_16bit", to match the use. Fixed. > Add a comment saying what RELAX_MICROMIPS_TYPE is. See the MIPS16 > comment as an example. > > > +#define RELAX_MICROMIPS_EXTENDED(i) (((i) & 0x10000) != 0) > > +#define RELAX_MICROMIPS_MARK_EXTENDED(i) ((i) | 0x10000) > > +#define RELAX_MICROMIPS_CLEAR_EXTENDED(i) ((i) & ~0x10000) > > Any particular reason why 0x10000 rather than 0x1000, which seems > to be the first unused bit? I would prefer to pack the used bits > together so that it's easier to tell what's left. These weren't used anywhere. I have discarded these macros. > > + /* True if the macro is in a 16-bit branch delay slot. */ > > + bfd_boolean delay_slot_16bit_p; > > + > > + /* True if the macro is in a 32-bit branch delay slot. */ > > + bfd_boolean delay_slot_32bit_p; > > I think it would be cleaner to have: > > /* If the macro is in a delay slot that requires a specific length > of instruction, this is that length, otherwise it is zero. */ > unsigned int delay_slot_length; Yes, marginally. As this is similar to updates I have made elsewhere already, I have implemented your suggestion now. > > + /* For relaxable macros, fsize[0] is the length of the first instruction > > + of the first alternative in bytes and fsize[1] is the length of the > > + first instruction of the second alternative. > > + For non-relaxable macros, both elements give the length of the > > + first instruction in bytes. */ > > + unsigned int fsize[2]; > > Rename to "first_insn_sizes" ("sizes" rather than "size" because the > plurality comes from having two alternatives). Also add: > > The fields are zero if we haven't yet seen the first instruction. Fixed. > > @@ -2374,22 +2736,21 @@ s_is_linkonce (symbolS *sym, segT from_s > > return linkonce; > > } > > > > -/* Mark instruction labels in mips16 mode. This permits the linker to > > - handle them specially, such as generating jalx instructions when > > - needed. We also make them odd for the duration of the assembly, in > > - order to generate the right sort of code. We will make them even > > +/* Mark instruction labels in MIPS16/microMIPS mode. This permits the > > + linker to handle them specially, such as generating jalx instructions > > + when needed. We also make them odd for the duration of the assembly, > > + in order to generate the right sort of code. We will make them even > > in the adjust_symtab routine, while leaving them marked. This is > > convenient for the debugger and the disassembler. The linker knows > > to make them odd again. */ > > > > static void > > -mips16_mark_labels (void) > > +mips_compressed_mark_labels (void) > > { > > segment_info_type *si = seg_info (now_seg); > > struct insn_label_list *l; > > > > - if (!mips_opts.mips16) > > - return; > > + gas_assert (HAVE_CODE_COMPRESSION); > > > > for (l = si->label_list; l != NULL; l = l->next) > > { > > @@ -2397,16 +2758,22 @@ mips16_mark_labels (void) > > > > #if defined(OBJ_ELF) || defined(OBJ_MAYBE_ELF) > > if (IS_ELF) > > - S_SET_OTHER (label, ELF_ST_SET_MIPS16 (S_GET_OTHER (label))); > > + { > > + if (mips_opts.mips16) > > + S_SET_OTHER (label, ELF_ST_SET_MIPS16 (S_GET_OTHER (label))); > > + else if (mips_opts.micromips) > > + S_SET_OTHER (label, ELF_ST_SET_MICROMIPS (S_GET_OTHER (label))); > > + } > > #endif > > if ((S_GET_VALUE (label) & 1) == 0 > > /* Don't adjust the address if the label is global or weak, or > > in a link-once section, since we'll be emitting symbol reloc > > references to it which will be patched up by the linker, and > > - the final value of the symbol may or may not be MIPS16. */ > > + the final value of the symbol may or may not be MIPS16/microMIPS. */ > > && ! S_IS_WEAK (label) > > && ! S_IS_EXTERNAL (label) > > - && ! s_is_linkonce (label, now_seg)) > > + && ! s_is_linkonce (label, now_seg) > > + && HAVE_CODE_COMPRESSION) > > S_SET_VALUE (label, S_GET_VALUE (label) | 1); > > } > > } > > Looks like the addition of HAVE_CODE_COMPRESSION is redundant here, > you've already asserted it in the previous hunk. Yes, cut & paste error, fixed. > > +static char * > > +micromips_label_name (void) > > +{ > > + char *p = micromips_target_name; > > + char symbol_name_temporary[24]; > > + unsigned long l; > > + int i; > > + > > + if (*p) > > + return p; > > + > > + i = 0; > > + l = micromips_target_label; > > +#ifdef LOCAL_LABEL_PREFIX > > + *p++ = LOCAL_LABEL_PREFIX; > > +#endif > [...] > > +int > > +mips_label_is_local (const char *name) > > +{ > > + return strchr (name, MICROMIPS_LABEL_CHAR) != NULL; > > +} > > Why is this change needed? The default local-label detection should be > enough for ELF targets, which always have a LOCAL_LABEL_PREFIX. I fail to see a justification, so I have removed this function. Chao-ying, do you have anything to add? > > @@ -2915,7 +3367,8 @@ append_insn (struct mips_cl_insn *ip, ex > > out that the branch was out-of-range, we'll get an error. */ > > && !mips_opts.warn_about_macros > > && (mips_opts.at || mips_pic == NO_PIC) > > - && !mips_opts.mips16) > > + && !mips_opts.mips16 > > + && !mips_opts.micromips) > > { > > relaxed_branch = TRUE; > > add_relaxed_insn (ip, (relaxed_branch_length > > !HAVE_CODE_COMPRESSION Obviously. > > + if (mips_relax.sequence) > > + abort (); > > gas_assert (!mips_relax.sequence); I sort of wonder why it is needed here in the first place, but not in any of the other blocks throughout this conditional, hmm... > > + /* For microMIPS, disable reordering. */ > > + || mips_opts.micromips > > You should say whether this is for simplicity or by specification. > Either way, a bit more detail would be welcome. E.g. something like: > > /* microMIPS assembly language does not allow the assembler > to reorder instructions, even in .set reorder mode. > Delay slots are always filled with nops when .set reorder > is in effect. */ > > (adjusted as appropriate if my guess is wrong). I believe the concerns are the same as with MIPS16 code -- so far we have failed to develop means to update DWARF-2 records accordingly and if a 32-bit branch/jump is swapped with a 16-bit delay-slot instruction (or vice versa as it's permitted in microMIPS code, though not in MIPS16 one) then substandard debugging experience results from software breakpoints placed mid-through an instruction. So as much as we'd love to reorder we really can't without fixing GAS elsewhere. Hmm, it looks like the piece of code to disable MIPS16 reordering has never made its way upstream. It should, unless we have a volunteer to fix GAS immediately, so while holding my breath and hoping that people won't fight over this challenge I extracted this piece now and updated this change accordingly. It makes no sense to keep the two pieces separate. It also looks to me we shouldn't be checking for INSN_SYNC (that's a waste of one of the precious flags we're just running out of), INSN_ERET and INSN_DERET here explicitly. These instructions should have their INSN_TRAP flag set instead -- and the flag should be renamed as I said previously to avoid confusion and reflect its actual meaning, i.e. "this instruction is forbidden in a branch delay slot". > > + /* If both delay slots are out of size, then emit the warning now. */ > > + if ((subtype & (RELAX_DELAY_SLOT_SIZE_FIRST | RELAX_DELAY_SLOT_SIZE_SECOND)) > > + == (RELAX_DELAY_SLOT_SIZE_FIRST | RELAX_DELAY_SLOT_SIZE_SECOND)) > > /* If both alternatives fail to fill a delay slot correctly, > emit the warning now. */ > if ((subtype & RELAX_DELAY_SLOT_SIZE_FIRST) != 0 > && (subtype & RELAX_DELAY_SLOT_SIZE_SECOND) != 0) I expect that to produce marginally worse code, but I won't insist. The comment update is OK of course. > > + hash = !mips_opts.micromips ? op_hash : micromips_op_hash; > > hash = mips_opts.micromips ? micromips_op_hash : op_hash; Applied. > > @@ -3640,13 +4407,32 @@ macro_build (expressionS *ep, const char > > /* Search until we get a match for NAME. It is assumed here that > > macros will never generate MDMX, MIPS-3D, or MT instructions. */ > > if (strcmp (fmt, mo->args) == 0 > > - && mo->pinfo != INSN_MACRO > > - && is_opcode_valid (mo)) > > - break; > > + && mo->pinfo != INSN_MACRO) > > + { > > + bfd_boolean ok; > > + bfd_boolean size_ok; > > + bfd_boolean delay_slot_ok; > > + > > + ok = is_opcode_valid (mo); > > + size_ok = is_size_valid (mo); > > + delay_slot_ok = is_delay_slot_valid (mo); > > + if (ok && size_ok && (delay_slot_ok || secondpass)) > > + break; > > + if (!delay_slot_ok && !twopass) > > + { > > + firstmo = mo; > > + twopass = TRUE; > > + } > > + } > > > > ++mo; > > - gas_assert (mo->name); > > - gas_assert (strcmp (name, mo->name) == 0); > > + if (!mo->name || strcmp (name, mo->name) != 0) > > + { > > + gas_assert (twopass); > > + gas_assert (!secondpass); > > + secondpass = TRUE; > > + mo = firstmo; > > + } > > } > > > > create_insn (&insn, mo); > > Do we really need to do two passes here? I would have expected > to see something like: > > if (strcmp (fmt, mo->args) == 0 > && mo->pinfo != INSN_MACRO > && is_opcode_valid (mo) > && is_size_valid (mo)) > { > if (is_delay_slot_valid (mo)) > break; > else if (!reserve_mo) > reserve_mo = mo; > } > > if (!mo->name || strcmp (name, mo->name) != 0) > { > /* All usable candidates violate the delay slot requirements > of the previous instruction. Pick the first such candidate > anyway; we will issue an appropriate warning later. */ > gcc_assert (reserve_mo); > mo = reserve_mo; > break; > } > > which IMO is simpler and clearer. Good point. I have simplified it yet further though. > > + if (!mips_opts.micromips) > > + INSERT_OPERAND (0, RD, insn, va_arg (args, int)); > > + else > > + INSERT_OPERAND (1, RS, insn, va_arg (args, int)); > > if (mips_opts.micromips) > INSERT_OPERAND (1, RS, insn, va_arg (args, int)); > else > INSERT_OPERAND (0, RD, insn, va_arg (args, int)); You don't like negative statements, do you? ;) > > case 'i': > > case 'j': > > macro_read_relocs (&args, r); > > - gas_assert (*r == BFD_RELOC_GPREL16 > > + gas_assert (mips_opts.micromips > > + || *r == BFD_RELOC_GPREL16 > > || *r == BFD_RELOC_MIPS_HIGHER > > || *r == BFD_RELOC_HI16_S > > || *r == BFD_RELOC_LO16 > > || *r == BFD_RELOC_MIPS_GOT_OFST); > > + gas_assert (!mips_opts.micromips > > + || *r == BFD_RELOC_MICROMIPS_GPREL16 > > + || *r == BFD_RELOC_MICROMIPS_HIGHER > > + || *r == BFD_RELOC_MICROMIPS_HI16_S > > + || *r == BFD_RELOC_MICROMIPS_LO16 > > + || *r == BFD_RELOC_MICROMIPS_GOT_OFST); > > Let's move the macro_read_relocs stuff inside append_insn rather than > leaving the conversion to the callers. You could then make append_insn > keep a record of the original (non-microMIPS) reloc_type[0] too, > which would simply some of the logic. E.g. these changes would > no longer be needed: > > > - /* Tag symbols that have a R_MIPS16_26 relocation against them. */ > > - if (reloc_type[0] == BFD_RELOC_MIPS16_JMP > > + /* Tag symbols that have a R_MIPS16_26 or R_MICROMIPS_26_S1 > > + relocation against them. */ > > + if ((reloc_type[0] == BFD_RELOC_MIPS16_JMP > > + || reloc_type[0] == BFD_RELOC_MICROMIPS_JMP) > > && ip->fixp[0]->fx_addsy) > > *symbol_get_tc (ip->fixp[0]->fx_addsy) = 1; This actually would -- note that's BFD_RELOC_MIPS16_JMP and not BFD_RELOC_MIPS_JMP there. > > @@ -3105,6 +3638,13 @@ append_insn (struct mips_cl_insn *ip, ex > > || 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_MICROMIPS_JMP > > + || reloc_type[0] == BFD_RELOC_MICROMIPS_GPREL16 > > + || reloc_type[0] == BFD_RELOC_MICROMIPS_LITERAL > > + || reloc_type[0] == BFD_RELOC_MICROMIPS_SUB > > + || reloc_type[0] == BFD_RELOC_MICROMIPS_HIGHEST > > + || reloc_type[0] == BFD_RELOC_MICROMIPS_HIGHER > > + || reloc_type[0] == BFD_RELOC_MICROMIPS_SCN_DISP > > || reloc_type[0] == BFD_RELOC_MIPS16_GPREL > > || hi16_reloc_p (reloc_type[0]) > > || lo16_reloc_p (reloc_type[0]))) > > You also wouldn't need micromips_percent_op. Done. As this is a self-contained change and may possibly need further tweaks, I have made it a separate patch to apply on top of the rest of the fixes (and the original change). BTW, do you happen to know what the issue about BFD_RELOC_MIPS_SCN_DISP is? We refer to it in a couple of places throughout GAS, but never actually generate it. I realise BFD may have to handle the reloc for compatibility with other tools, but GAS? > Sorry, I know this isn't what I said first time round, but it was much > harder to see the wood for the trees before you'd integrated the macro > code properly. Hmm, what can I say? > > + /* For microMIPS, check if the current instruction is not in > > + a delay slot that requires a 32-bit instruction. */ > > + if (mips_opts.micromips > > + && !(history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT)) > > /* Prefer to use a 16-bit microMIPS instruction unless the previous > instruction specifically requires a 32-bit one. */ OK. > > + if CALL is set. In the reorder mode the delay slot would be filled > > + with a nop anyway, so code produced is simply: > > + BR , > > Add an explicit nop, since the code does. Good point. > > +/* Emit a coprocessor branch macro specified by TYPE, using CC as > > + the condition code tested. EP specifies the branch target. */ > > "branch-likely macro". OK. > > +/* Emit a two-argument branch macro specified by TYPE, using SREG as > > + the register tested. EP specifies the branch target. */ > > + > > +static void > > +macro_build_branch_rs (int type, expressionS *ep, unsigned int sreg) > > +{ > > + const char *brneg; > > + const char *br; > > + int likely = 0; > > + int call = 0; > > + > > + switch (type) > > + { > > + case M_BGEZ: > > + br = "bgez"; > > + break; > > + case M_BGEZL: > > + br = mips_opts.micromips ? "bgez" : "bgezl"; > > + brneg = "bltz"; > > + likely = 1; > > + break; > > + case M_BGEZALL: > > + gas_assert (mips_opts.micromips); > > + br = "bgezals"; > > + brneg = "bltz"; > > + likely = 1; > > + call = 1; > > + break; > > + case M_BGTZ: > > + br = "bgtz"; > > + break; > > + case M_BGTZL: > > + br = mips_opts.micromips ? "bgtz" : "bgtzl"; > > + brneg = "blez"; > > + likely = 1; > > + break; > > + case M_BLEZ: > > + br = "blez"; > > + break; > > + case M_BLEZL: > > + br = mips_opts.micromips ? "blez" : "blezl"; > > + brneg = "bgtz"; > > + likely = 1; > > + break; > > + case M_BLTZ: > > + br = "bltz"; > > + break; > > + case M_BLTZL: > > + br = mips_opts.micromips ? "bltz" : "bltzl"; > > + brneg = "bgez"; > > + likely = 1; > > + break; > > + case M_BLTZALL: > > + gas_assert (mips_opts.micromips); > > + br = "bltzals"; > > + brneg = "bgez"; > > + likely = 1; > > + call = 1; > > + break; > > + default: > > + abort (); > > + } > > + if (mips_opts.micromips && likely) > > + macro_build_branch_likely (br, brneg, call, ep, "s,p", sreg, ZERO); > > + else > > + macro_build (ep, br, "s,p", sreg); > > +} > > No need for "likely". Just initialise "brneg" to NULL and check for that. > Same for macro_build_branch_rsrt. I'm not sure that is clearer, but I won't insist. Adjusted. > > + if (!mips_opts.micromips) > > + label_expr.X_add_number = 8; > > + else > > + micromips_label_expr (&label_expr); > > if (mips_opts.micromips) > micromips_label_expr (&label_expr); > else > label_expr.X_add_number = 8; > > (several occurences) Yes, same as somewhere above. I've swapped all the negative conditions I could spot. > > - macro_build (NULL, "jalr", "d,s", dreg, sreg); > > + s = (!mips_opts.micromips || (mips_opts.noreorder && !cprestore) > > + ? "jalr" : "jalrs"); > > + if (mips_opts.micromips && dreg == RA) > > + macro_build (NULL, s, "mj", sreg); > > + else > > + macro_build (NULL, s, JALR_FMT, dreg, sreg); > > Since we can use JALRS for mips_opts.noreorder && cprestore, I suppose > the cprestore nop: > > if (mips_opts.noreorder) > macro_build (NULL, "nop", ""); > > ought to be conditional on !mips_opts.micromips. No, the delay slot always has to be explicitly filled here. Otherwise you'll end up with LW $gp there (the instruction has a 16-bit variation too) -- that I fixed not so long ago. For the avoidance of doubt: all the call (linked jump/branch) instructions have a fixed-length delay slot that takes either 4 bytes (as with BGEZAL, BLTZAL, JAL, JALR and JALX instructions) or 2 bytes (as with BGEZALS, BLTZALS, JALS and JALRS). All the other jump/branch instructions have an any-length delay slot except from compact jump/branch instructions that have none (these are BEQZC, BNEZC and JRC). Overall the "S" suffix stands for a short delay slot and the "C" one means a compact jump/branch, i.e. no delay slot. > > + /* A 12-bit offset field is too narrow to be used for a low-part > > + relocation, so use the auxiliary register to load the full > > + address provided if the A(b) format has been requested; > > + load_address will produce the necessary relocations as code > > + used with 16-bit offsets below would do. Otherwise the o(b) > > + format has been selected, so load the low part only and the > > + relocation requested will have already been provided in > > + offset_reloc, so just use that. */ > > /* A 12-bit 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". */ OK. > > + hash = !mips_opts.micromips ? op_hash : micromips_op_hash; > > + past = (!mips_opts.micromips ? &mips_opcodes[NUMOPCODES] > > + : µmips_opcodes[bfd_micromips_num_opcodes]); > > if (mips_opts.micromips) > { > hash = micromips_op_hash; > past = µmips_opcodes[bfd_micromips_num_opcodes]; > } > else > { > hash = op_hash; > past = &mips_opcodes[NUMOPCODES]; > } Not sure this is any better, but OK. > > @@ -8688,32 +10234,50 @@ mips_ip (char *str, struct mips_cl_insn > > argsStart = s = str + end; > > for (;;) > > { > > + bfd_boolean delay_slot_ok; > > + bfd_boolean size_ok; > > bfd_boolean ok; > > > > gas_assert (strcmp (insn->name, name) == 0); > > > > ok = is_opcode_valid (insn); > > - if (! ok) > > + size_ok = is_size_valid (insn); > > + delay_slot_ok = is_delay_slot_valid (insn); > > + if (!delay_slot_ok && !twopass) > > { > > - if (insn + 1 < &mips_opcodes[NUMOPCODES] > > - && strcmp (insn->name, insn[1].name) == 0) > > + firstinsn = insn; > > + twopass = TRUE; > > + } > > + if (!ok || !size_ok || (!delay_slot_ok && !secondpass)) > > + { > > + static char buf[256]; > > + > > + if (insn + 1 < past && strcmp (insn->name, insn[1].name) == 0) > > { > > ++insn; > > continue; > > } > > - else > > + if (twopass && !secondpass) > > { > > - if (!insn_error) > > - { > > - static char buf[100]; > > - sprintf (buf, > > - _("opcode not supported on this processor: %s (%s)"), > > - mips_cpu_info_from_arch (mips_opts.arch)->name, > > - mips_cpu_info_from_isa (mips_opts.isa)->name); > > - insn_error = buf; > > - } > > - return; > > + gas_assert (firstinsn); > > + secondpass = TRUE; > > + insn = firstinsn; > > + continue; > > } > > + > > + if (insn_error) > > + return; > > + > > + if (!ok) > > + sprintf (buf, _("opcode not supported on this processor: %s (%s)"), > > + mips_cpu_info_from_arch (mips_opts.arch)->name, > > + mips_cpu_info_from_isa (mips_opts.isa)->name); > > + else > > + sprintf (buf, _("Unrecognized %u-bit version of microMIPS opcode"), > > + 8 * forced_insn_length); > > + insn_error = buf; > > + > > + return; > > } > > > > create_insn (ip, insn); > > Same two-pass comment as before. Obviously this case is different as we have to pass all the matching instructions through the loop with the huge switch statement for argument matching too. So it's not enough to pick the first one that does not meet the delay slot requirement and get away with that. And the switch statement in its current form is not designed to make two successful parses possible. But having written that, I agree there is some room for improvement here even without redesigning the switch statement as in the second pass we do not have to pass instructions to the loop that were already checked in the firs pass. I have updated this piece accordingly. > > + unsigned long mask = (!mips_opts.micromips > > + ? OP_MASK_CODE > > + : MICROMIPSOP_MASK_CODE); > > > unsigned long mask = (mips_opts.micromips > ? MICROMIPSOP_MASK_CODE > : OP_MASK_CODE); > > Several other cases. As above. > > + case 'J': > > + if (!mips_opts.micromips) > > + { /* 19-bit WAIT code. */ > > + my_getExpression (&imm_expr, s); > > + check_absolute_expr (ip, &imm_expr); > > + if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE19) > > + { > > + as_warn (_("Illegal 19-bit code (%lu)"), > > + (unsigned long) imm_expr.X_add_number); > > + imm_expr.X_add_number &= OP_MASK_CODE19; > > + } > > + INSERT_OPERAND (0, CODE19, *ip, imm_expr.X_add_number); > > + imm_expr.X_op = O_absent; > > + s = expr_end; > > + continue; > > } > > - INSERT_OPERAND (CODE19, *ip, imm_expr.X_add_number); > > - imm_expr.X_op = O_absent; > > - s = expr_end; > > - continue; > > + goto do_reg; /* ALNV.PS source register. */ > > So 'J' is used for different things depending on micromips mode? > Couldn't we use a different letter instead? Picked 'y' then. While doing this I noticed we have a bug. In a sequence like this: alnv.ps $f0, $f1, $f2, $3 jalr $3, $2 the ALNV.PS will get reordered into the delay slot. This is obviously wrong. I'll post a trivial fix for standard MIPS code separately. For microMIPS code we'd have to take one of the precious pinfo flags (which we've run out of, although one can be reclaimed with the SYNC change I mentioned above) for the purpose of this lone instruction and we don't do branch swapping anyway, so I've just disabled ALNV.PS reordering altogether. > > + if (!mips_opts.micromips) > > + INSERT_OPERAND (0, RD, *ip, regno); > > + else > > + INSERT_OPERAND (1, RS, *ip, regno); > > if (mips_opts.micromips) > INSERT_OPERAND (1, RS, *ip, regno); > else > INSERT_OPERAND (0, RD, *ip, regno); Ditto. > > + if (!ok) > > + { > > + switch (*args++) > > I realise you've copied this from elsewhere, but why "++"? > The "for" loop increments "args", doesn't it? This is the same as for 'r', etc. (i.e. a register that's optional in the source if the destination is the same as the target). Otherwise code like: andi16 $7, 65535 addiu16 $31, 7 fails to assemble. The thing is once we get to "65535", we still have a "," unconsumed in args. I have rewritten it more properly though, adding a check for that "," too. > > + if (c == 'e') > > + { > > + regno = lastregno; > > + s = s_reset; > > + ++args; > > + } > > + else if (c == 't') > > + { > > + s = s_reset; > > + ++args; > > + continue; > > + } > > I don't really understand these "args" adjustments either. Likewise: subu16 $2, $3 xor16 $2, $3 > > + i = my_getSmallExpression (&imm_expr, imm_reloc, s); > > + if ((i == 0 && (imm_expr.X_op != O_constant > > + || (imm_expr.X_add_number & 3) != 0 > > + || imm_expr.X_add_number > (63 << 2) > > + || imm_expr.X_add_number < (-64 << 2))) > > + || i > 0) > > + { > > + imm_expr.X_op = O_absent; > > + break; > > + } > > + immed = imm_expr.X_add_number >> 2; > > + INSERT_OPERAND (1, IMMA, *ip, immed); > > + imm_expr.X_op = O_absent; > > + s = expr_end; > > + continue; > > Why set X_op to O_absent when rejecting this alternative? What breaks > if you leave the constant in imm_expr? I couldn't see any similar > error-handling code in this function. I believe the reason is if the offset does not fit for the purpose of this 16-bit encoding, then we'll fall back to a 32-bit one that uses offset_expr instead. So we have to mark imm_expr absent not to confuse code elsewhere (in md_assemble(), presumably). Yeah, I know in this case both should be equal, but it looks sloppy to me to use a stale value from a previous pass. And obviously you wouldn't see this case before as no standard MIPS instruction switches from imm_expr to offset_expr between encodings. That written, I have given it some thinking and decided to use local variables instead removing any references to imm_expr and thus any issue about its usage. We don't pass the results up to append_insn() from here in any case. > Also: > > if (my_getSmallExpression (&imm_expr, imm_reloc, s) == 0 > && imm_expr.X_op == O_constant > && (imm_expr.X_add_number & 3) == 0 > && imm_expr.X_add_number >= (-64 << 2) > && imm_expr.X_add_number <= (63 << 2)) > { > immed = imm_expr.X_add_number >> 2; > INSERT_OPERAND (1, IMMA, *ip, immed); > imm_expr.X_op = O_absent; > s = expr_end; > continue; > } > break; > > seems more in keeping with other my_getSmallExpression users. I disagree, see 'i'/'j', 'o', etc. The path of acceptance in almost all the case selectors of this switch statement is fall-through. Any failure breaks midway through. I have adjusted this sequence slightly though and factored out conditions around the expression as the pattern repeats on and on throughout this switch statement. This has led to quite nice code IMO. > > + i = my_getSmallExpression (&imm_expr, imm_reloc, s); > > + > > + for (immb = 0; immb < 8; immb++) > > + { > > + if (micromips_imm_b_map[immb] > > + == imm_expr.X_add_number) > > + break; > > + } > > + if ((i == 0 && (imm_expr.X_op != O_constant || immb == 8)) > > + || i > 0) > > + { > > + imm_expr.X_op = O_absent; > > + break; > > + } > > + INSERT_OPERAND (1, IMMB, *ip, immb); > > + imm_expr.X_op = O_absent; > > + s = expr_end; > > + continue; > > Here too I'd prefer something like: > > if (my_getSmallExpression (&imm_expr, imm_reloc, s) == 0 > && imm_expr.X_op == O_constant) > { > for (immb = 0; immb < 8; immb++) > if (micromips_imm_b_map[immb] > == imm_expr.X_add_number) > break; > if (immb < 8) > { > INSERT_OPERAND (1, IMMB, *ip, immb); > imm_expr.X_op = O_absent; > s = expr_end; > continue; > } > } > break; > > which has the added benefit of only using X_add_number once we've > established that it's meaningful. Similar changes in the rest > of the function. Likewise. I agree about the imm_expr's usage and have taken it into account. > > + /* If users want relax branch and don't specify to use > > + 16-bit instructions, we will not match this pattern. > > + This will lead to matching 32-bit instructions, that > > + will be relaxed later. */ > > + if (mips_relax_branch && forced_insn_length != 2) > > + break; > > This seems a bit lame. It should be easy to relax the 16-bit form > in the same way as the 32-bit form. We could use a bit in the > relaxation opcode to say whether the extra relaxation should be > enabled or not, i.e. a bit to record the relevant parts of this > condition: > > + && (pinfo & INSN_UNCOND_BRANCH_DELAY > + || pinfo & INSN_COND_BRANCH_DELAY) > + && mips_relax_branch > + /* Don't try branch relaxation within .set nomacro, or within > + .set noat if we use $at for PIC computations. If it turns > + out that the branch was out-of-range, we'll get an error. */ > + && !mips_opts.warn_about_macros > + && (mips_opts.at || mips_pic == NO_PIC) > + && mips_opts.micromips > + /* Don't try branch relaxation, when users specify 16-bit/32-bit > + instructions. */ > + && !forced_insn_length) > > No need to do that as part of this patch, but let's at least put in > a FIXME. Indeed; we have a preexisting bug here as well -- mips_opts.at may well be != ATREG. (A similar bug is present in fix_loongson2f_jump() BTW). Actually I've thought it's lame enough to implement it. In the course of which I discovered (and fixed) other three bugs, so I think it was worth the effort. Sent as a sepate patch for the same reasons as the reloc change above. > > + case 'N': /* Register list for lwm and swm. */ > > + { > > + unsigned int reg_list = 0; > > + int immed = 0; > > + unsigned int reg1 = 33; > > Why 33 rather than 32? Seems INVALID_REG could be used here for a bit > of extra readability. No idea; this piece is now gone anyway. > > + /* s0, ra > > + s0, s1, ra > > + s0, s1, s2, ra > > + s0, s1, s2, s3, ra > > + s0-s1, ra > > + s0-s2, ra > > + s0-s3, ra */ > > You also allow: > > s1, ra, s2, s0 > > (rightly IMO), so I don't think we gain much by listing the split-out ranges. > Just: > > /* s0, ra > s0-s1, ra > s0-s2, ra > s0-s3, ra */ > > would be OK. I have rewritten it adding an explanatory comment. > > + s_reset = s; > > + SKIP_SPACE_TABS (s); > > + if (*s == ',') > > + { > > + reg1 = 33; > > + ++s; > > + } > > + else if (*s == '-') > > + { > > + reg1 = regno; > > + ++s; > > + } > > + SKIP_SPACE_TABS (s); > > + ok = reg_lookup (&s, RTYPE_NUM | RTYPE_GP, ®no); > > + if (!ok) > > + { > > + s = s_reset; > > + break; > > + } > > Shouldn't we break out if *s isn't ',' or '-' and treat it as a syntax > error ("reg_list = 0; break;")? We should break out, but that's not a syntax error as far as this handler is concerned. It's up to code elsewhere to decide what the token to follow, if any, has to be based on args. This is now handled properly. > > + if (regno <= reg1) > > + { > > + reg_list = 0; > > + break; > > + } > > Add a comment saying that this is an error condition. But is there > really anything wrong with $4-$4 (regno == reg1)? The range is closed > after all. Agreed, I have now allowed it under the "be liberal what you accept" principle. > > + } > > + if (i == 0 && imm_expr.X_op == O_constant > > + && (imm_expr.X_add_number & 3) == 0 > > + && imm_expr.X_add_number >= (-4194304 << 2) > > + && imm_expr.X_add_number <= (4194303 << 2)) > > I'm ashamed to say this decimal number wasn't in my mental power-of-2 list. > Maybe a hex constant or (1 << n) would be better? Feel free to leave it > if you disagree though. I don't, actually. Offhand, the decimal value is meaningless to me too. > > + case 'n': /* Register list for 32-bit lwm and swm. */ > > + gas_assert (mips_opts.micromips); > > + { > > + unsigned int reg_list = 0; > > + int immed = 0; > > + unsigned int reg1 = 33; > > + > > This register-range code needs to be split out into a separate function. > It's the same as for 'N' above (except for the s8 handling, which would > be OK-but-redundant for 'n' too), has the same apparent bug regarding > syntax checking, and has the same questionable behaviour about > single-register ranges. Agreed. I have now reimplemented is almost from scratch. While doing it I have noticed the arguments are actually wiped of whitespace at this point, so I have removed references to SKIP_SPACE_TABS(). It looks to me the macro and its two references in mips16_ip() can be removed altogether. > > + /* s0, ra > > + s0, s1, ra > > + s0, s1, s2, ra > > + s0, s1, s2, s3, ra > > + s0, s1, s2, s3, s4, ra > > + s0, s1, s2, s3, s4, s5, ra > > + s0, s1, s2, s3, s4, s5, s6, ra > > + s0, s1, s2, s3, s4, s5, s6, s7, ra > > + s0, s1, s2, s3, s4, s5, s6, s7, s8, ra > > + ra, > > + s0-s1, ra > > + s0-s2, ra > > + s0-s3, ra > > + s0-s4, ra > > + s0-s5, ra > > + s0-s6, ra > > + s0-s7, ra > > + s0-s8, ra */ > > I'm hampered by the spec not being public yet, but it looks from the > code as though RA's actually optional when S0 is present. The comment > implies otherwise. Also: Both are optional, except at least one register has to be present and the range of static registers has to start at s0 and be contiguous. (Though as a side note I'm not sure why a single register is officially supported by the ASE for this instruction at all -- being equivalent to LD/LW/SD/SW it could well be a reserved encoding.) > > + if (reg_list == 0x00010000) > > + immed = 1; > > + else if (reg_list == 0x00030000) > > + immed = 2; > > + else if (reg_list == 0x00070000) > > + immed = 3; > > + else if (reg_list == 0x000f0000) > > + immed = 4; > > + else if (reg_list == 0x001f0000) > > + immed = 5; > > + else if (reg_list == 0x003f0000) > > + immed = 6; > > + else if (reg_list == 0x007f0000) > > + immed = 7; > > + else if (reg_list == 0x00ff0000) > > + immed = 8; > > + else if (reg_list == 0x40ff0000) > > + immed = 9; > > + else if (reg_list == 0x80000000) > > + immed = 16; > > + else if (reg_list == 0x80010000) > > + immed = 17; > > + else if (reg_list == 0x80030000) > > + immed = 18; > > + else if (reg_list == 0x80070000) > > + immed = 19; > > + else if (reg_list == 0x800f0000) > > + immed = 20; > > + else if (reg_list == 0x801f0000) > > + immed = 21; > > + else if (reg_list == 0x803f0000) > > + immed = 22; > > + else if (reg_list == 0x807f0000) > > + immed = 23; > > + else if (reg_list == 0x80ff0000) > > + immed = 24; > > + else if (reg_list == 0xc0ff0000) > > + immed = 25; > > + else > > + break; > > this could at least be simplified by testing the Sn and RA registers > separately, then rejecting immed == 0. But maybe the split-out function > could return the Sn range in a more easily digestible form. No need to. This can be easily dealt with with ffs(), benefitting hosts that have good support for this operation, such as MIPS architecture processors and their CLZ instruction :) (x86 has BSF and we care even less about any others, don't we?). > > + /* For microMIPS we need to save the value to buf + 2. */ > > + if (target_big_endian || fixP->fx_r_type == BFD_RELOC_MICROMIPS_LO16) > > buf += 2; > > /* 32-bit microMIPS instructions are divided into two 16-bit pieces. > Relocations always refer to the second piece, regardless of > endianness. */ > > or something like that. I'm sure there's a better term than "piece" here, > what does the spec call it? Halfword. > > + fragp->fr_subtype > > + = toofar ? RELAX_MICROMIPS_MARK_TOOFAR (fragp->fr_subtype) > > + : RELAX_MICROMIPS_CLEAR_TOOFAR (fragp->fr_subtype); > > Non-standard alignment for ":" > > fragp->fr_subtype = (toofar > ? RELAX_MICROMIPS_MARK_TOOFAR (fragp->fr_subtype) > : RELAX_MICROMIPS_CLEAR_TOOFAR (fragp->fr_subtype); Fixed. > > + /* 00000000 : > > + 0: 405e 0006 bgez $30,10 > > + 4: 0c00 nop > > + 6: fc3c 0002 lw $1,2($28) > > + 6: R_MIPS_GOT16 .text > > + a: 3021 0011 addiu $1,$1,17 > > + a: R_MIPS_LO16 .text > > + e: 4721 jalr $1 > > + ... > > + > > + 00020010 : > > + 20010: 0c00 nop > > + 20012: 0c00 nop > > + */ > > + > > + if (!fragp && update > 0) > > + length += 6; > > + > > + if (mips_pic != NO_PIC) > > + { > > + /* Additional space for PIC loading of target address. */ > > + length += 6; > > + } > > + > > + /* If branch is conditional. */ > > + if (fragp ? !RELAX_MICROMIPS_UNCOND (fragp->fr_subtype) : (update >= 0)) > > + length += 6; > > + } > > This really isn't written very clearly. The comment has a single > long-branch form, while the code has three if statements. Say what > you're counting in each case. The first conditional is bogus and also dead code. It looks like it was copied from relaxed_branch_length() where it is used to handle branch-likely relaxation, further adjusted towards removal and then left. I have removed it altogether now. I've cooked up some comments for the remaining cases. I decided to switch to the source notation and quoted instruction byte counts explicitly. > > + /* For microMIPS PC relative relocations, we cannot convert it to > > + against a section. If we do, it will mess up the fixp->fx_offset. */ > > if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT > > - || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) > > + || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY > > + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1 > > + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1 > > + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1) > > "to be against a section". That's not a helpful comment though. > _How_ will it mess up fixp->fx_offset? Give the reader a clue why > the problem applies to BFD_RELOC_MICROMIPS_16_PCREL_S1 but not > to something like BFD_RELOC_16_PCREL_S2. I have failed to spot any problems with this hunk reverted and I'm not sure what I should be looking for. Therefore I feel a bit uneasy about removing it and only rephrased the comment without actually changing its meaning. Chao-ying, do you have anything to add? > > + if (RELAX_MICROMIPS_UNCOND (fragp->fr_subtype)) > > + goto uncond_micromips; > > Ugh. Either split out the code for unconditional branches into a subfunction, > or put intervening code into a: > > if (!RELAX_MICROMIPS_UNCOND (fragp->fr_subtype)) > > block. (Yes, I know the current relaxation code has the same kind of goto, > but I would have raised just the same objection there. If cut-&-paste really > is necessary, the new code should still be defendable in its own right.) Fixed. > > + buf = (bfd_byte *)fragp->fr_literal + fragp->fr_fix; > > Missing space before "fragp->fr_literal". A few other occurences. Fixed. > > + if (RELAX_MICROMIPS_LINK (fragp->fr_subtype)) > > + { > > + /* Clear the and-link bit. */ > > + gas_assert ((insn & 0xffa00000) == 0x40200000); > > + > > + /* bltzal 0x04100000 bgezal 0x04110000 */ > > + insn &= ~0x00200000; > > + } > > Excess cut-&-paste. The opcodes in the comment are from the normal MIPS > encoding, not the microMIPS one. (Wondered at first why we were clearing > a bit that, according to the comment, wasn't supposed to be set in the > first place.) Worse yet, we don't handle BGEZALS and BLTZALS correctly. Fixed that as well (and adjusted test cases to include these instructions). > > + /* How many bytes in instructions we've already emitted? */ > > + i = buf - (bfd_byte *)fragp->fr_literal - fragp->fr_fix; > > + /* How many bytes in instructions from here to the end? */ > > + i = fragp->fr_var - i; > > I don't get this. "buf" still equals "fragp->fr_literal + fragp->fr_fix", > doesn't it? We haven't emitted anything yet. Seems to me that this is > (and should be) the same as "i = fragp->fr_var". We fail to use compact branches here and rely on linker relaxation to do so. This is inferior (especially as linker relaxation is optional; it doesn't handle all the cases either), but better than nothing. It relies on the presence of relocations though, so I have rewritten this sequence to emit labels and use them as branch targets instead, getting rid of this piece you're questioning as a side effect altogether. For compact branches to be used here I think we need to add another flag to RELAX_MICROMIPS_ENCODE() so that relaxed_micromips_32bit_branch_length() can calculate the correct length (contrary to generic documentation the original opcode is not available in md_relax_frag() on the MIPS target and when we get to md_convert_frag() it's already too late for shrinking the frag. The lack of use of compact branches here does not make code produced incorrect though, so that makes it an option for future improvement and I will not work on it now. [FIXME] > > + uncond_micromips: > > + if (mips_pic == NO_PIC) > > + { > > + /* j or jal. */ > > "j(al) R_MICROMIPS_26_S1" > > to match the style of the other comments (and to give a bit more info). Adjusted as reasonable (though I fail to see a consistent style throughout this function). > > + /* lw/ld $at, ($gp) R_MIPS_GOT16 */ > > + insn = 0xfc3c0000; > > + exp.X_op = O_symbol; > > + exp.X_add_symbol = fragp->fr_symbol; > > + exp.X_add_number = fragp->fr_offset; > > Add the "ld" case or fix the comment. Also s/R_MIPS_GOT16/R_MICROMIPS_LO16/. > > > + /* d/addiu $at, $at, R_MIPS_LO16 */ > > + insn = 0x30210000; > > Likewise "daddiu". I have added the alternative encodings. Overall 64-bit support is quite rudimentary at most. > > + gas_assert (buf == (bfd_byte *)fragp->fr_literal > > + + fragp->fr_fix + fragp->fr_var); > > The "+" isn't indented far enough. There was a pair of brackets missing here actually. > > Index: binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/mips1-fp.d > > =================================================================== > > --- binutils-fsf-trunk-quilt.orig/gas/testsuite/gas/mips/mips1-fp.d 2010-12-07 00:05:05.000000000 +0000 > > +++ binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/mips1-fp.d 2010-12-07 00:14:47.000000000 +0000 > > @@ -9,4 +9,4 @@ > > [0-9a-f]+ <.*>: > > .*: 46041000 add.s \$f0,\$f2,\$f4 > > .*: 44420000 cfc1 \$2,\$0 > > -#pass > > + \.\.\. > > Index: binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/mips1-fp.s > > =================================================================== > > --- binutils-fsf-trunk-quilt.orig/gas/testsuite/gas/mips/mips1-fp.s 2010-12-07 00:05:05.000000000 +0000 > > +++ binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/mips1-fp.s 2010-12-07 00:14:47.000000000 +0000 > > @@ -5,3 +5,7 @@ > > foo: > > add.s $f0,$f2,$f4 > > cfc1 $2,$0 > > + > > +# Force at least 8 (non-delay-slot) zero bytes, to make 'objdump' print ... > > + .align 2 > > + .space 8 > > Leave out this kind of change. I realise it's not the style you prefer, > but what's there now is fine. Same for: > > * gas/testsuite/gas/mips/mips32r2-fp32.d > * gas/testsuite/gas/mips/mips64.d Well, that's not merely a matter of style as #pass simply ignores any following rubbish GAS may have produced. This forces a corresponding update to gas/testsuite/gas/mips/micromips@mips1-fp.d as the results differ between Linux and bare-iron targets. I'd prefer to avoid adding new instances of #pass although I've just noticed the original change included some other too, so I've applied your suggestion reluctantly. These test cases should really be all audited and unjustified uses of #pass removed -- I realise some people have difficulties following all the details of and good ways to deal with subtleties in this area and follow the path of least resistance, but we shouldn't be encouraging this kind of behaviour. Especially as you seem to be quite picky elsewhere. ;) > > msubu $11, $12 > > mul $13, $14, $15 > > pref 4, ($16) > > + .set at > > pref 4, 32767($17) > > pref 4, -32768($18) > > + .set noat > > ssnop > > > > > > # privileged instructions > > > > cache 5, ($1) > > + .set at > > cache 5, 32767($2) > > cache 5, -32768($3) > > - .set at > > cache 5, 32768($4) > > cache 5, -32769($5) > > cache 5, 32768 > > We should really have separate noat tests for the prefs and caches > that are no longer in a noat block (a bit like you did for the > wait and sdbbp tests whose immediates have changed). > > > -#define STO_MIPS_PLT 0x8 > > +#define STO_MIPS_PLT (1 << 3) > > Don't change the definitions of the existing constants; use hex constants > for the new stuff instead. Well, STO_OPTIONAL already uses a shifted bit and I find this notation clearer. Since code is already inconsistent I have updated it not to change the existing definitions, but kept newly-added ones as shifted bitfields. I'm happy to keep code consistent, but if a piece is not, I will choose the style that suits me better, sorry. > > /* This value is used to mark PIC functions in an object that mixes > > - PIC and non-PIC. */ > > -#define STO_MIPS_PIC 0x20 > > -#define ELF_ST_IS_MIPS_PIC(OTHER) \ > > - (((OTHER) & ~ELF_ST_VISIBILITY (-1)) == STO_MIPS_PIC) > > -#define ELF_ST_SET_MIPS_PIC(OTHER) \ > > - (STO_MIPS_PIC | ELF_ST_VISIBILITY (OTHER)) > > + PIC and non-PIC. Note this bit overlaps with STO_MIPS16. */ > > +#define STO_MIPS_PIC (1 << 5) > > +#define ELF_ST_IS_MIPS_PIC(other) (((other) & STO_MIPS_FLAGS) == STO_MIPS_PIC) > > +#define ELF_ST_SET_MIPS_PIC(other) (((other) & ~STO_MIPS_FLAGS) | STO_MIPS_PIC) > > /* This value is used to mark PIC functions in an object that mixes > PIC and non-PIC. Note that this bit overlaps with STO_MIPS16, > although MIPS16 symbols are never considered to be MIPS_PIC. */ Applied. > > +/* Whether code compression (either of the MIPS16 or the microMIPS ASEs) > > + has been indicated for a .text symbol. */ > > +#define ELF_ST_IS_COMPRESSED(other) \ > > + (ELF_ST_IS_MIPS16(other) || ELF_ST_IS_MICROMIPS(other)) > > The last line is missing a space before each "(other)". Fixed. > > +/* microMIPS placeholders. */ > > Should be a bit more descriptive. E.g.: > > /* Every MICROMIPSOP_X definition requires a corresponding OP_X > definition, and vice versa. This simplifies various parts > of the operand handling in GAS. The fields below only exist in > the microMIPS encoding, so define each one to have an empty range. */ > > if indeed that's accurate. Yes, thanks. Updated INSERT_OPERAND() and EXTRACT_OPERAND() macros rely on these definitions for cases where the ISA selector is hardcoded as code has to be syntactically correct even if optimised away. > > +/* These are the bitmasks and shift counts used for the different > > + fields in the instruction formats. Other than OP, no masks are > > + provided for the fixed portions of an instruction, since they are > > + not needed. */ > > Seems like too much cut-&-paste: there isn't an OP field here. > "Other than TARGET", perhaps, unless there are other opcode masks here. This looks like copied verbatim from the MIPS16 part. The two parts are functionally equivalent and my understanding of the comment is no masks are provided for the non-operand parts of instruction. I've left the comment as is; I'm not sure what TARGET might mean in this context, please elaborate. > > +/* MIPS placeholders. */ > > /* Placeholders for fields that only exist in the traditional 32-bit > instruction encoding; see the comment above for details. */ Thanks. > > + "mg" 3-bit MIPS registers 2-7, 16, 17 (MICROMIPSOP_*_MG) at bit 0 > > + "mg" 3-bit MIPS registers 2-7, 16, 17 (MICROMIPSOP_*_MG) at bit 0 > > Doubled line. Fixed. > > - Elf_Internal_Ehdr *header; > > + Elf_Internal_Ehdr *header = elf_elfheader (info->section->owner); > > > > - header = elf_elfheader (info->section->owner); > > What's there now is fine. Adjusted. > > + else > > + iprintf (is, "UNKNOWN"); > > Excess indentation. Fixed. > > + In microMIPS, we need to match instructions (mfc0, mtc0) > > + by hand. */ > > Something like: > > The microMIPS encoding does not have a coprocessor > identifier field as such, so we must work out the > coprocessor number by looking at the opcode. */ > > might be more descriptive. OK, thanks. > > +/* Return 1 if a symbol associated with the location being disassembled > > + indicates a compressed mode, either MIPS16 or microMIPS one. Otherwise, > > + return 0. */ > > Reads more naturally to me without "one". Both MIPS16 and microMIPS are adjectives; they need a noun or a pronoun. I realise this requirement is not met everywhere, but that doesn't mean we should add new such places IMO. > > + for (i = 0; i < info->num_symbols; i++) > > + { > > + pos = info->symtab_pos + i; > > + > > + if (bfd_asymbol_flavour (info->symtab[pos]) != bfd_target_elf_flavour) > > + continue; > > + > > + symbol = (elf_symbol_type *) info->symtab[pos]; > > + if ((!micromips_ase > > + && ELF_ST_IS_MIPS16 (symbol->internal_elf_sym.st_other)) > > + || (micromips_ase > > + && ELF_ST_IS_MICROMIPS (symbol->internal_elf_sym.st_other))) > > + return 1; > > + } > > Why is a search necessary here, when the previous code was happy to > look only at the first symbol? I'm not saying the code is wrong, > but a bit of commentary would be good. My feeling is previous code was not "happy", but simply untested (or to be more accurate, not tested satisfactorily). Symbols sharing the same address are sorted alphabetically here which becomes a problem when they include both objects and functions (or symbols derived from standard MIPS functions defined elsewhere). Disassembly shouldn't yield different results based merely on the names of symbols chosen and given the semantics of the compressed annotation (it is only added to a function symbol if a genuine instruction has been emitted following immediately in the source code) I think it should take precedence, so we check if any symbol has one. Perhaps we should only check function symbols in case st_other is overloaded for object symbols, but I think that would be overengineering. Whoever adds any overlapping flags should be required to audit existing code; that shouldn't be too difficult to do. > What problem is the ld-lib.exp change fixing? Currently you can't build the same source file multiple times with different flags. See ld/testsuite/ld-mips-elf/mips16-and-micromips.d for a use case (and try it with the ld-lib.exp piece reverted). I think the framework shouldn't be limiting the developer like this and making a copy of the source to work around the limitation sounds to me like the wrong direction to go. I made several adjustments and bug fixes as I saw fit on my own too and for documentation purposes included a commented out microMIPS64 48-bit LI instruction that takes a 32-bit signed immediate argument. While support for 64-bit microMIPS is only rudimentary and I don't plan to work on any improvement at the moment long-term we need to think about how to handle this instruction; the most straightforward approach would be to reliably extend match/mask to 64 bits. Our 64-bit integer type support on 32-bit hosts seem to be lacking though and there are several places throughout GAS where such values are truncated. It would increase the amount of space taken by opcode tables noticeably on 32-bit hosts too (but we already waste a lot of space by using a "long" type on 64-bit hosts where unnecessary). What fits best here are ISO C9x types -- do you happen to know if binutils maintainers ever plan to deploy them? We've been using autoconf since the beginning of time and it has straightforward ways to define replacement types of a required width and target code frequently operates on quantities that have a predefined width so making use of fixed-width types seems natural. I have made several obvious changes to the original diff to address modifications made to repository that are not included here as they were required for the patch to apply at all after a tree update in the first place. All of them were mechanical; most notably INSN2_* have been renumbered according to additional flag consumption. As mentioned earlier, we're running out of these flags now. Finally, for a reference, I'm including updated ChangeLogs. They refer to the whole set of changes combined as the updates are not meant to be committed separately. None of the separate bug fixes mentioned throughout are covered though; I'll be sending them with their corresponding entries and descriptions on their own shortly. Maciej binutils-20110221-umips-fix.diff binutils-20110221-umips-relax16.diff binutils-20110221-umips-fix-reloc.diff [Patches attached compressed due to their size.] bfd/ 2011-02-21 Chao-ying Fu Ilie Garbacea Maciej W. Rozycki Joseph Myers Catherine Moore * archures.c (bfd_mach_mips_micromips): New macro. * cpu-mips.c (I_micromips): New enum value. (arch_info_struct): Add bfd_mach_mips_micromips. * elfxx-mips.h (_bfd_mips_elf_is_target_special_symbol): New prototype. (_bfd_mips_elf_relax_section): Likewise. (_bfd_mips16_elf_reloc_unshuffle): Rename to... (_bfd_mips_elf_reloc_unshuffle): ... this. Handle microMIPS ASE. (_bfd_mips16_elf_reloc_shuffle): Rename to... (_bfd_mips_elf_reloc_shuffle): ... this. Handle microMIPS ASE. (gprel16_reloc_p): Handle microMIPS ASE. (literal_reloc_p): New function. * elf32-mips.c (elf_micromips_howto_table_rel): New variable. (_bfd_mips_elf32_gprel16_reloc): Handle microMIPS ASE. (mips16_gprel_reloc): Update for _bfd_mips_elf_reloc_unshuffle and _bfd_mips_elf_reloc_shuffle changes. (mips_elf_gprel32_reloc): Update comment. (micromips_reloc_map): New variable. (bfd_elf32_bfd_reloc_type_lookup): Handle microMIPS ASE. (mips_elf32_rtype_to_howto): Likewise. (mips_info_to_howto_rel): Likewise. (bfd_elf32_bfd_is_target_special_symbol): Define. (bfd_elf32_bfd_relax_section): Likewise. * elf64-mips.c (micromips_elf64_howto_table_rel): New variable. (micromips_elf64_howto_table_rela): Likewise. (mips16_gprel_reloc): Update for _bfd_mips_elf_reloc_unshuffle and _bfd_mips_elf_reloc_shuffle changes. (micromips_reloc_map): Likewise. (bfd_elf64_bfd_reloc_type_lookup): Handle microMIPS ASE. (bfd_elf64_bfd_reloc_name_lookup): Likewise. (mips_elf64_rtype_to_howto): Likewise. (bfd_elf64_bfd_is_target_special_symbol): Define. * elfn32-mips.c (elf_micromips_howto_table_rel): New variable. (elf_micromips_howto_table_rela): Likewise. (mips16_gprel_reloc): Update for _bfd_mips_elf_reloc_unshuffle and _bfd_mips_elf_reloc_shuffle changes. (micromips_reloc_map): Likewise. (bfd_elf32_bfd_reloc_type_lookup): Handle microMIPS ASE. (bfd_elf32_bfd_reloc_name_lookup): Likewise. (mips_elf_n32_rtype_to_howto): Likewise. (bfd_elf32_bfd_is_target_special_symbol): Define. * elfxx-mips.c (LA25_LUI_MICROMIPS_1): New macro. (LA25_LUI_MICROMIPS_2): Likewise. (LA25_J_MICROMIPS_1, LA25_J_MICROMIPS_2): Likewise. (LA25_ADDIU_MICROMIPS_1, LA25_ADDIU_MICROMIPS_2): Likewise. (TLS_RELOC_P): Handle microMIPS ASE. (mips_elf_create_stub_symbol): Adjust value of stub symbol if target is a microMIPS function. (micromips_reloc_p): New function. (micromips_reloc_shuffle_p): Likewise. (got16_reloc_p, call16_reloc_p): Handle microMIPS ASE. (got_disp_reloc_p, got_page_reloc_p): New functions. (got_ofst_reloc_p): Likewise. (got_hi16_reloc_p, got_lo16_reloc_p): Likewise. (call_hi16_reloc_p, call_lo16_reloc_p): Likewise. (hi16_reloc_p, lo16_reloc_p, jal_reloc_p): Handle microMIPS ASE. (micromips_branch_reloc_p): New function. (tls_gd_reloc_p, tls_ldm_reloc_p): Likewise. (tls_gottprel_reloc_p): Likewise. (_bfd_mips16_elf_reloc_unshuffle): Rename to... (_bfd_mips_elf_reloc_unshuffle): ... this. Handle microMIPS ASE. (_bfd_mips16_elf_reloc_shuffle): Rename to... (_bfd_mips_elf_reloc_shuffle): ... this. Handle microMIPS ASE. (_bfd_mips_elf_lo16_reloc): Handle microMIPS ASE. (mips_tls_got_index, mips_elf_got_page): Likewise. (mips_elf_create_local_got_entry): Likewise. (mips_elf_relocation_needs_la25_stub): Likewise. (mips_elf_calculate_relocation): Likewise. (mips_elf_perform_relocation): Likewise. (_bfd_mips_elf_symbol_processing): Likewise. (_bfd_mips_elf_add_symbol_hook): Likewise. (_bfd_mips_elf_link_output_symbol_hook): Likewise. (mips_elf_add_lo16_rel_addend): Likewise. (_bfd_mips_elf_check_relocs): Likewise. (mips_elf_adjust_addend): Likewise. (_bfd_mips_elf_relocate_section): Likewise. (mips_elf_create_la25_stub): Likewise. (_bfd_mips_vxworks_finish_dynamic_symbol): Likewise. (_bfd_mips_elf_gc_sweep_hook): Likewise. (_bfd_mips_elf_is_target_special_symbol): New function. (mips_elf_relax_delete_bytes): Likewise. (opcode_descriptor): New structure. (RA): New macro. (OP32_SREG, OP32_TREG, OP16_VALID_REG): Likewise. (b_insns_32, bc_insn_32, bz_insn_32, bzal_insn_32): New variables. (beq_insn_32): Likewise. (b_insn_16, bz_insn_16): New variables. (BZC32_REG_FIELD): New macro. (bz_rs_insns_32, bz_rt_insns_32): New variables. (bzc_insns_32, bz_insns_16):Likewise. (BZ16_REG, BZ16_REG_FIELD): New macros. (jal_insn_32_bd16, jal_insn_32_bd32): New variables. (jal_x_insn_32_bd32): Likewise. (j_insn_32, jalr_insn_32): Likewise. (ds_insns_32_bd16, ds_insns_32_bd32): Likewise. (jalr_insn_16_bd16, jalr_insn_16_bd32, jr_insn_16): Likewise. (JR16_REG): New macro. (ds_insns_16_bd16): New variable. (lui_insn): Likewise. (addiu_insn, addiupc_insn): Likewise. (ADDIUPC_REG_FIELD): New macro. (MOVE32_RD, MOVE32_RS): Likewise. (MOVE16_RD_FIELD, MOVE16_RS_FIELD): Likewise. (move_insns_32, move_insns_16): New variables. (nop_insn_32, nop_insn_16): Likewise. (MATCH): New macro. (find_match): New function. (check_br16_dslot, check_br32_dslot): Likewise. (check_br16, check_br32): Likewise. (IS_BITSIZE): New macro. (_bfd_mips_elf_relax_section): New function. (_bfd_mips_elf_merge_private_bfd_data): Disallow linking MIPS16 and microMIPS modules together. (_bfd_mips_elf_print_private_bfd_data): Handle microMIPS ASE. * reloc.c (BFD_RELOC_MICROMIPS_7_PCREL_S1): New relocation. (BFD_RELOC_MICROMIPS_10_PCREL_S1): Likewise. (BFD_RELOC_MICROMIPS_16_PCREL_S1): Likewise. (BFD_RELOC_MICROMIPS_GPREL16): Likewise. (BFD_RELOC_MICROMIPS_JMP, BFD_RELOC_MICROMIPS_HI16): Likewise. (BFD_RELOC_MICROMIPS_HI16_S): Likewise. (BFD_RELOC_MICROMIPS_LO16): Likewise. (BFD_RELOC_MICROMIPS_LITERAL): Likewise. (BFD_RELOC_MICROMIPS_GOT16): Likewise. (BFD_RELOC_MICROMIPS_CALL16): Likewise. (BFD_RELOC_MICROMIPS_GOT_HI16): Likewise. (BFD_RELOC_MICROMIPS_GOT_LO16): Likewise. (BFD_RELOC_MICROMIPS_CALL_HI16): Likewise. (BFD_RELOC_MICROMIPS_CALL_LO16): Likewise. (BFD_RELOC_MICROMIPS_SUB): Likewise. (BFD_RELOC_MICROMIPS_GOT_PAGE): Likewise. (BFD_RELOC_MICROMIPS_GOT_OFST): Likewise. (BFD_RELOC_MICROMIPS_GOT_DISP): Likewise. (BFD_RELOC_MICROMIPS_HIGHEST): Likewise. (BFD_RELOC_MICROMIPS_HIGHER): Likewise. (BFD_RELOC_MICROMIPS_SCN_DISP): Likewise. (BFD_RELOC_MICROMIPS_JALR): Likewise. (BFD_RELOC_MICROMIPS_TLS_GD): Likewise. (BFD_RELOC_MICROMIPS_TLS_LDM): Likewise. (BFD_RELOC_MICROMIPS_TLS_DTPREL_HI16): Likewise. (BFD_RELOC_MICROMIPS_TLS_DTPREL_LO16): Likewise. (BFD_RELOC_MICROMIPS_TLS_GOTTPREL): Likewise. (BFD_RELOC_MICROMIPS_TLS_TPREL_HI16): Likewise. (BFD_RELOC_MICROMIPS_TLS_TPREL_LO16): Likewise. * bfd-in2.h: Regenerate. * libbfd.h: Regenerate. binutils/ 2011-02-21 Chao-ying Fu Maciej W. Rozycki * readelf.c (get_machine_flags): Handle microMIPS ASE. (get_mips_symbol_other): Likewise. gas/ 2011-02-21 Maciej W. Rozycki Chao-ying Fu * config/tc-mips.h (mips_segment_info): Add one bit for microMIPS. (TC_LABEL_IS_LOCAL): New macro. (mips_label_is_local): New prototype. * config/tc-mips.c (S0, S7): New macros. (emit_branch_likely_macro): New variable. (mips_set_options): Add micromips. (mips_opts): Initialise micromips to -1. (file_ase_micromips): New variable. (CPU_HAS_MICROMIPS): New macro. (hilo_interlocks): Set for microMIPS too. (gpr_interlocks): Likewise. (cop_interlocks): Likewise. (cop_mem_interlocks): Likewise. (HAVE_CODE_COMPRESSION): New macro. (micromips_op_hash): New variable. (micromips_nop16_insn, micromips_nop32_insn): New variables. (NOP_INSN): Handle microMIPS ASE. (mips32_to_micromips_reg_b_map): New macro. (mips32_to_micromips_reg_c_map): Likewise. (mips32_to_micromips_reg_d_map): Likewise. (mips32_to_micromips_reg_e_map): Likewise. (mips32_to_micromips_reg_f_map): Likewise. (mips32_to_micromips_reg_g_map): Likewise. (mips32_to_micromips_reg_l_map): Likewise. (mips32_to_micromips_reg_n_map): Likewise. (mips32_to_micromips_reg_h_map): New variable. (mips32_to_micromips_reg_m_map): Likewise. (mips32_to_micromips_reg_q_map): Likewise. (micromips_to_32_reg_h_map): New variable. (micromips_to_32_reg_i_map): Likewise. (micromips_to_32_reg_m_map): Likewise. (micromips_to_32_reg_q_map): Likewise. (micromips_to_32_reg_b_map): New macro. (micromips_to_32_reg_c_map): Likewise. (micromips_to_32_reg_d_map): Likewise. (micromips_to_32_reg_e_map): Likewise. (micromips_to_32_reg_f_map): Likewise. (micromips_to_32_reg_g_map): Likewise. (micromips_to_32_reg_l_map): Likewise. (micromips_to_32_reg_n_map): Likewise. (micromips_imm_b_map, micromips_imm_c_map): New macros. (RELAX_DELAY_SLOT_16BIT): New macro. (RELAX_DELAY_SLOT_SIZE_FIRST): Likewise. (RELAX_DELAY_SLOT_SIZE_SECOND): Likewise. (RELAX_MICROMIPS_ENCODE, RELAX_MICROMIPS_P): New macros. (RELAX_MICROMIPS_TYPE, RELAX_MICROMIPS_AT): Likewise. (RELAX_MICROMIPS_U16BIT, RELAX_MICROMIPS_UNCOND): Likewise. (RELAX_MICROMIPS_COMPACT, RELAX_MICROMIPS_LINK): Likewise. (RELAX_MICROMIPS_RELAX32, RELAX_MICROMIPS_TOOFAR16): Likewise. (RELAX_MICROMIPS_MARK_TOOFAR16): Likewise. (RELAX_MICROMIPS_CLEAR_TOOFAR16): Likewise. (RELAX_MICROMIPS_TOOFAR32): Likewise. (RELAX_MICROMIPS_MARK_TOOFAR32): Likewise. (RELAX_MICROMIPS_CLEAR_TOOFAR32): Likewise. (INSERT_OPERAND, EXTRACT_OPERAND): Handle microMIPS ASE. (mips_macro_warning): Add delay_slot_16bit_p, delay_slot_32bit_p, fsize and insns. (mips_mark_labels): New function. (mips16_small, mips16_ext): Remove variables, replacing with... (forced_insn_size): ... this. (append_insn, mips16_ip): Update accordingly. (micromips_insn_length): New function. (insn_length): Return the length of microMIPS instructions. (mips_record_mips16_mode): Rename to... (mips_record_compressed_mode): ... this. Handle microMIPS ASE. (install_insn): Handle microMIPS ASE. (reglist_lookup): New function. (is_size_valid, is_delay_slot_valid): Likewise. (md_begin): Handle microMIPS ASE. (md_assemble): Likewise. Update for append_insn interface change. (micromips_reloc_p): New function. (got16_reloc_p): Handle microMIPS ASE. (hi16_reloc_p): Likewise. (lo16_reloc_p): Likewise. (matching_lo_reloc): Likewise. (insn_uses_reg, reg_needs_delay): Likewise. (mips_move_labels): Likewise. (mips16_mark_labels): Rename to... (mips_compressed_mark_labels): ... this. Handle microMIPS ASE. (insns_between, nops_for_vr4130, nops_for_insn): Likewise. (fix_loongson2f_nop, fix_loongson2f_jump): Likewise. (MICROMIPS_LABEL_CHAR): New macro. (micromips_target_label, micromips_target_name): New variables. (micromips_label_name, micromips_label_expr): New functions. (micromips_label_inc, micromips_add_label): Likewise. (mips_label_is_local): Likewise. (micromips_map_reloc): Likewise. (append_insn): Add expansionp argument. Handle microMIPS ASE. (start_noreorder, end_noreorder): Handle microMIPS ASE. (macro_start, macro_warning, macro_end): Likewise. (brk_fmt, cop12_fmt, jalr_fmt, lui_fmt): New variables. (mem12_fmt, mfhl_fmt, shft_fmt, trap_fmt): Likewise. (BRK_FMT, COP12_FMT, JALR_FMT, LUI_FMT): New macros. (MEM12_FMT, MFHL_FMT, SHFT_FMT, TRAP_FMT): Likewise. (macro_build): Handle microMIPS ASE. Update for append_insn interface change. (mips16_macro_build): Update for append_insn interface change. (macro_build_jalr): Handle microMIPS ASE. (macro_build_lui): Likewise. Simplify. (load_register): Handle microMIPS ASE. (load_address): Likewise. (move_register): Likewise. (macro_build_branch_likely): New function. (macro_build_branch_ccl): Likewise. (macro_build_branch_rs): Likewise. (macro_build_branch_rsrt): Likewise. (macro): Handle microMIPS ASE. (validate_micromips_insn): New function. (expr_const_in_range): Likewise. (mips_ip): Handle microMIPS ASE. (options): Add OPTION_MICROMIPS and OPTION_NO_MICROMIPS. (md_longopts): Add mmicromips and mno-micromips. (md_parse_option): Handle OPTION_MICROMIPS and OPTION_NO_MICROMIPS. (mips_after_parse_args): Handle microMIPS ASE. (md_pcrel_from): Handle microMIPS relocations. (mips_force_relocation): Likewise. (md_apply_fix): Likewise. (mips_align): Handle microMIPS ASE. (s_mipsset): Likewise. (s_cpload, s_cpsetup, s_cpreturn): Use relocation wrappers. (s_dtprel_internal): Likewise. (s_gpword, s_gpdword): Likewise. (s_insn): Handle microMIPS ASE. (s_mips_stab): Likewise. (relaxed_micromips_32bit_branch_length): New function. (relaxed_micromips_16bit_branch_length): New function. (md_estimate_size_before_relax): Handle microMIPS ASE. (mips_fix_adjustable): Likewise. (tc_gen_reloc): Handle microMIPS relocations. (mips_relax_frag): Handle microMIPS ASE. (md_convert_frag): Likewise. (mips_frob_file_after_relocs): Likewise. (mips_elf_final_processing): Likewise. (mips_nop_opcode): Likewise. (mips_handle_align): Likewise. (md_show_usage): Handle microMIPS options. * symbols.c (TC_LABEL_IS_LOCAL): New macro. (S_IS_LOCAL): Add a TC_LABEL_IS_LOCAL check. * doc/as.texinfo (Target MIPS options): Add -mmicromips and -mno-micromips. (-mmicromips, -mno-micromips): New options. * doc/c-mips.texi (-mmicromips, -mno-micromips): New options. (MIPS ISA): Document .set micromips and .set nomicromips. (MIPS insn): Update for microMIPS support. gas/testsuite/ 2011-02-21 Maciej W. Rozycki Chao-ying Fu * gas/mips/micromips.d: New test. * gas/mips/micromips-branch-delay.d: Likewise. * gas/mips/micromips-branch-relax.d: Likewise. * gas/mips/micromips-branch-relax-pic.d: Likewise. * gas/mips/micromips-size-1.d: Likewise. * gas/mips/micromips-trap.d: Likewise. * gas/mips/micromips.l: New stderr output. * gas/mips/micromips-branch-delay.l: Likewise. * gas/mips/micromips-branch-relax.l: Likewise. * gas/mips/micromips-branch-relax-pic.l: Likewise. * gas/mips/micromips-size-0.l: New list test. * gas/mips/micromips-size-1.l: New stderr output. * gas/mips/micromips.s: New test source. * gas/mips/micromips-branch-delay.s: Likewise. * gas/mips/micromips-branch-relax.s: Likewise. * gas/mips/micromips-size-0.s: Likewise. * gas/mips/micromips-size-1.s: Likewise. * gas/mips/mips.exp: Run the new tests. * gas/mips/elf_ase_micromips.d: New test. * gas/mips/elf_ase_micromips-2.d: Likewise. * gas/mips/micromips@abs.d: Likewise. * gas/mips/micromips@add.d: Likewise. * gas/mips/micromips@and.d: Likewise. * gas/mips/micromips@beq.d: Likewise. * gas/mips/micromips@bge.d: Likewise. * gas/mips/micromips@bgeu.d: Likewise. * gas/mips/micromips@blt.d: Likewise. * gas/mips/micromips@bltu.d: Likewise. * gas/mips/micromips@branch-likely.d: Likewise. * gas/mips/micromips@branch-misc-1.d: Likewise. * gas/mips/micromips@branch-misc-2-64.d: Likewise. * gas/mips/micromips@branch-misc-2.d: Likewise. * gas/mips/micromips@branch-misc-2pic-64.d: Likewise. * gas/mips/micromips@branch-misc-2pic.d: Likewise. * gas/mips/micromips@branch-self.d: Likewise. * gas/mips/micromips@cache.d: Likewise. * gas/mips/micromips@daddi.d: Likewise. * gas/mips/micromips@dli.d: Likewise. * gas/mips/micromips@elf-jal.d: Likewise. * gas/mips/micromips@elf-rel2.d: Likewise. * gas/mips/micromips@elf-rel4.d: Likewise. * gas/mips/micromips@jal-svr4pic.d: Likewise. * gas/mips/micromips@jal-svr4pic-noreorder.d: Likewise. * gas/mips/micromips@lb-svr4pic-ilocks.d: Likewise. * gas/mips/micromips@li.d: Likewise. * gas/mips/micromips@mips1-fp.d: Likewise. * gas/mips/micromips@mips32-cp2.d: Likewise. * gas/mips/micromips@mips32-imm.d: Likewise. * gas/mips/micromips@mips32-sf32.d: Likewise. * gas/mips/micromips@mips32.d: Likewise. * gas/mips/micromips@mips32r2-cp2.d: Likewise. * gas/mips/micromips@mips32r2-fp32.d: Likewise. * gas/mips/micromips@mips32r2.d: Likewise. * gas/mips/micromips@mips4-branch-likely.d: Likewise. * gas/mips/micromips@mips4-fp.d: Likewise. * gas/mips/micromips@mips4.d: Likewise. * gas/mips/micromips@mips5.d: Likewise. * gas/mips/micromips@mips64-cp2.d: Likewise. * gas/mips/micromips@mips64.d: Likewise. * gas/mips/micromips@mips64r2.d: Likewise. * gas/mips/micromips@pref.d: Likewise. * gas/mips/micromips@rol-hw.d: Likewise. * gas/mips/micromips@uld2-eb.d: Likewise. * gas/mips/micromips@uld2-el.d: Likewise. * gas/mips/micromips@ulh2-eb.d: Likewise. * gas/mips/micromips@ulh2-el.d: Likewise. * gas/mips/micromips@ulw2-eb-ilocks.d: Likewise. * gas/mips/micromips@ulw2-el-ilocks.d: Likewise. * gas/mips/cache.d: Likewise. * gas/mips/daddi.d: Likewise. * gas/mips/mips32-imm.d: Likewise. * gas/mips/pref.d: Likewise. * gas/mips/elf-rel27.d: Handle microMIPS ASE. * gas/mips/l_d.d: Likewise. * gas/mips/l_d-n32.d: Likewise. * gas/mips/l_d-n64.d: Likewise. * gas/mips/ld.d: Likewise. * gas/mips/ld-n32.d: Likewise. * gas/mips/ld-n64.d: Likewise. * gas/mips/s_d.d: Likewise. * gas/mips/s_d-n32.d: Likewise. * gas/mips/s_d-n64.d: Likewise. * gas/mips/sd.d: Likewise. * gas/mips/sd-n32.d: Likewise. * gas/mips/sd-n64.d: Likewise. * gas/mips/mips32.d: Update immediates. * gas/mips/micromips@mips32-cp2.s: New test source. * gas/mips/micromips@mips32-imm.s: Likewise. * gas/mips/micromips@mips32r2-cp2.s: Likewise. * gas/mips/micromips@mips64-cp2.s: Likewise. * gas/mips/cache.s: Likewise. * gas/mips/daddi.s: Likewise. * gas/mips/mips32-imm.s: Likewise. * gas/mips/elf-rel4.s: Handle microMIPS ASE. * gas/mips/lb-pic.s: Likewise. * gas/mips/ld.s: Likewise. * gas/mips/mips32.s: Likewise. * gas/mips/mips.exp: Add the micromips arch. Exclude mips16e from micromips. Run mips32-imm. * gas/mips/jal-mask-11.d: New test. * gas/mips/jal-mask-12.d: Likewise. * gas/mips/micromips@jal-mask-11.d: Likewise. * gas/mips/jal-mask-1.s: Source for the new tests. * gas/mips/jal-mask-21.d: New test. * gas/mips/jal-mask-22.d: Likewise. * gas/mips/micromips@jal-mask-12.d: Likewise. * gas/mips/jal-mask-2.s: Source for the new tests. * gas/mips/mips.exp: Run the new tests. * gas/mips/mips16-e.d: Add --special-syms to `objdump'. * gas/mips/tmips16-e.d: Likewise. * gas/mips/and.s: Adjust padding. * gas/mips/beq.s: Likewise. * gas/mips/bge.s: Likewise. * gas/mips/bgeu.s: Likewise. * gas/mips/blt.s: Likewise. * gas/mips/bltu.s: Likewise. * gas/mips/branch-misc-2.s: Likewise. * gas/mips/jal.s: Likewise. * gas/mips/li.s: Likewise. * gas/mips/mips1-fp.s: Likewise. * gas/mips/mips32r2-fp32.s: Likewise. * gas/mips/mips64.s: Likewise. * gas/mips/mips4.s: Likewise. * gas/mips/mips4-fp.s: Likewise. * gas/mips/and.d: Update accordingly. * gas/mips/elf-jal.d: Likewise. * gas/mips/jal.d: Likewise. * gas/mips/li.d: Likewise. * gas/mips/mips1-fp.d: Likewise. * gas/mips/mips32r2-fp32.d: Likewise. * gas/mips/mips64.d: Likewise. include/elf/ 2011-02-21 Chao-ying Fu Maciej W. Rozycki * mips.h (R_MICROMIPS_min): New relocations. (R_MICROMIPS_26_S1): Likewise. (R_MICROMIPS_HI16, R_MICROMIPS_LO16): Likewise. (R_MICROMIPS_GPREL16, R_MICROMIPS_LITERAL): Likewise. (R_MICROMIPS_GOT16, R_MICROMIPS_PC7_S1): Likewise. (R_MICROMIPS_PC10_S1, R_MICROMIPS_PC16_S1): Likewise. (R_MICROMIPS_CALL16, R_MICROMIPS_GOT_DISP): Likewise. (R_MICROMIPS_GOT_PAGE, R_MICROMIPS_GOT_OFST): Likewise. (R_MICROMIPS_GOT_HI16, R_MICROMIPS_GOT_LO16): Likewise. (R_MICROMIPS_SUB, R_MICROMIPS_HIGHER): Likewise. (R_MICROMIPS_HIGHEST, R_MICROMIPS_CALL_HI16): Likewise. (R_MICROMIPS_CALL_LO16, R_MICROMIPS_SCN_DISP): Likewise. (R_MICROMIPS_JALR, R_MICROMIPS_HI0_LO16): Likewise. (R_MICROMIPS_TLS_GD, R_MICROMIPS_TLS_LDM): Likewise. (R_MICROMIPS_TLS_DTPREL_HI, R_MICROMIPS_TLS_DTPREL_LO): Likewise. (R_MICROMIPS_TLS_GOTTPREL): Likewise. (R_MICROMIPS_TLS_TPREL_HI16): Likewise. (R_MICROMIPS_TLS_TPREL_LO16): Likewise. (R_MICROMIPS_GPREL7_S2, R_MICROMIPS_PC23_S2): Likewise. (R_MICROMIPS_max): Likewise. (EF_MIPS_ARCH_ASE_MICROMIPS): New macro. (STO_MIPS_ISA, STO_MIPS_FLAGS): Likewise. (ELF_ST_IS_MIPS_PLT, ELF_ST_SET_MIPS_PLT): Likewise. (STO_MICROMIPS): Likewise. (ELF_ST_IS_MICROMIPS, ELF_ST_SET_MICROMIPS): Likewise. (ELF_ST_IS_COMPRESSED): Likewise. (STO_MIPS_PLT, STO_MIPS_PIC): Rework. (ELF_ST_IS_MIPS_PIC, ELF_ST_SET_MIPS_PIC): Likewise. (STO_MIPS16, ELF_ST_IS_MIPS16, ELF_ST_SET_MIPS16): Likewise. include/opcode/ 2011-02-21 Chao-ying Fu Maciej W. Rozycki * mips.h (OP_MASK_EXTLSB, OP_SH_EXTLSB): New macros. (OP_MASK_STYPE, OP_SH_STYPE): Likewise. (OP_MASK_CODE10, OP_SH_CODE10): Likewise. (OP_MASK_TRAP, OP_SH_TRAP): Likewise. (OP_MASK_OFFSET12, OP_SH_OFFSET12): Likewise. (OP_MASK_OFFSET10, OP_SH_OFFSET10): Likewise. (OP_MASK_RS3, OP_SH_RS3): Likewise. (OP_MASK_MB, OP_SH_MB, OP_MASK_MC, OP_SH_MC): Likewise. (OP_MASK_MD, OP_SH_MD, OP_MASK_ME, OP_SH_ME): Likewise. (OP_MASK_MF, OP_SH_MF, OP_MASK_MG, OP_SH_MG): Likewise. (OP_MASK_MJ, OP_SH_MJ, OP_MASK_ML, OP_SH_ML): Likewise. (OP_MASK_MP, OP_SH_MP, OP_MASK_MQ, OP_SH_MQ): Likewise. (OP_MASK_IMMA, OP_SH_IMMA, OP_MASK_IMMB, OP_SH_IMMB): Likewise. (OP_MASK_IMMC, OP_SH_IMMC, OP_MASK_IMMF, OP_SH_IMMF): Likewise. (OP_MASK_IMMG, OP_SH_IMMG, OP_MASK_IMMH, OP_SH_IMMH): Likewise. (OP_MASK_IMMI, OP_SH_IMMI, OP_MASK_IMMJ, OP_SH_IMMJ): Likewise. (OP_MASK_IMML, OP_SH_IMML, OP_MASK_IMMM, OP_SH_IMMM): Likewise. (OP_MASK_IMMN, OP_SH_IMMN, OP_MASK_IMMO, OP_SH_IMMO): Likewise. (OP_MASK_IMMP, OP_SH_IMMP, OP_MASK_IMMQ, OP_SH_IMMQ): Likewise. (OP_MASK_IMMU, OP_SH_IMMU, OP_MASK_IMMW, OP_SH_IMMW): Likewise. (OP_MASK_IMMX, OP_SH_IMMX, OP_MASK_IMMY, OP_SH_IMMY): Likewise. (INSN2_BRANCH_DELAY_16BIT, INSN2_BRANCH_DELAY_32BIT): New macros. (INSN2_WRITE_GPR_S, INSN2_READ_FPR_D): Likewise. (INSN2_MOD_GPR_MB, INSN2_MOD_GPR_MC, INSN2_MOD_GPR_MD): Likewise. (INSN2_MOD_GPR_ME, INSN2_MOD_GPR_MF, INSN2_MOD_GPR_MG): Likewise. (INSN2_MOD_GPR_MJ, INSN2_MOD_GPR_MP, INSN2_MOD_GPR_MQ): Likewise. (INSN2_MOD_SP, INSN2_READ_GPR_31): Likewise. (INSN2_READ_GP, INSN2_READ_PC): Likewise. (CPU_MICROMIPS): New macro. (M_BC1FL, M_BC1TL, M_BC2FL, M_BC2TL): New enum values. (M_BEQL, M_BGEZ, M_BGEZL, M_BGEZALL, M_BGTZ, M_BGTZL): Likewise. (M_BLEZ, M_BLEZL, M_BLTZ, M_BLTZL, M_BLTZALL, M_BNEL): Likewise. (M_CACHE_OB, M_JALS_1, M_JALS_2, M_JALS_A): Likewise. (M_LDC2_OB, M_LDL_OB, M_LDM_AB, M_LDM_OB): Likewise. (M_LDP_AB, M_LDP_OB, M_LDR_OB, M_LL_OB, M_LLD_OB): Likewise. (M_LWC2_OB, M_LWL_OB, M_LWM_AB, M_LWM_OB): Likewise. (M_LWP_AB, M_LWP_OB, M_LWR_OB): Likewise. (M_LWU_OB, M_PREF_OB, M_SC_OB, M_SCD_OB): Likewise. (M_SDC2_OB, M_SDL_OB, M_SDM_AB, M_SDM_OB): Likewise. (M_SDP_AB, M_SDP_OB, M_SDR_OB): Likewise. (M_SWC2_OB, M_SWL_OB, M_SWM_AB, M_SWM_OB): Likewise. (M_SWP_AB, M_SWP_OB, M_SWR_OB): Likewise. (MICROMIPSOP_MASK_MAJOR, MICROMIPSOP_SH_MAJOR): New macros. (MICROMIPSOP_MASK_IMMEDIATE, MICROMIPSOP_SH_IMMEDIATE): Likewise. (MICROMIPSOP_MASK_DELTA, MICROMIPSOP_SH_DELTA): Likewise. (MICROMIPSOP_MASK_CODE10, MICROMIPSOP_SH_CODE10): Likewise. (MICROMIPSOP_MASK_TRAP, MICROMIPSOP_SH_TRAP): Likewise. (MICROMIPSOP_MASK_SHAMT, MICROMIPSOP_SH_SHAMT): Likewise. (MICROMIPSOP_MASK_TARGET, MICROMIPSOP_SH_TARGET): Likewise. (MICROMIPSOP_MASK_EXTLSB, MICROMIPSOP_SH_EXTLSB): Likewise. (MICROMIPSOP_MASK_EXTMSBD, MICROMIPSOP_SH_EXTMSBD): Likewise. (MICROMIPSOP_MASK_INSMSB, MICROMIPSOP_SH_INSMSB): Likewise. (MICROMIPSOP_MASK_CODE, MICROMIPSOP_SH_CODE): Likewise. (MICROMIPSOP_MASK_CODE2, MICROMIPSOP_SH_CODE2): Likewise. (MICROMIPSOP_MASK_CACHE, MICROMIPSOP_SH_CACHE): Likewise. (MICROMIPSOP_MASK_SEL, MICROMIPSOP_SH_SEL): Likewise. (MICROMIPSOP_MASK_OFFSET12, MICROMIPSOP_SH_OFFSET12): Likewise. (MICROMIPSOP_MASK_3BITPOS, MICROMIPSOP_SH_3BITPOS): Likewise. (MICROMIPSOP_MASK_STYPE, MICROMIPSOP_SH_STYPE): Likewise. (MICROMIPSOP_MASK_OFFSET10, MICROMIPSOP_SH_OFFSET10): Likewise. (MICROMIPSOP_MASK_RS, MICROMIPSOP_SH_RS): Likewise. (MICROMIPSOP_MASK_RT, MICROMIPSOP_SH_RT): Likewise. (MICROMIPSOP_MASK_RD, MICROMIPSOP_SH_RD): Likewise. (MICROMIPSOP_MASK_FS, MICROMIPSOP_SH_FS): Likewise. (MICROMIPSOP_MASK_FT, MICROMIPSOP_SH_FT): Likewise. (MICROMIPSOP_MASK_FD, MICROMIPSOP_SH_FD): Likewise. (MICROMIPSOP_MASK_FR, MICROMIPSOP_SH_FR): Likewise. (MICROMIPSOP_MASK_RS3, MICROMIPSOP_SH_RS3): Likewise. (MICROMIPSOP_MASK_PREFX, MICROMIPSOP_SH_PREFX): Likewise. (MICROMIPSOP_MASK_BCC, MICROMIPSOP_SH_BCC): Likewise. (MICROMIPSOP_MASK_CCC, MICROMIPSOP_SH_CCC): Likewise. (MICROMIPSOP_MASK_COPZ, MICROMIPSOP_SH_COPZ): Likewise. (MICROMIPSOP_MASK_MB, MICROMIPSOP_SH_MB): Likewise. (MICROMIPSOP_MASK_MC, MICROMIPSOP_SH_MC): Likewise. (MICROMIPSOP_MASK_MD, MICROMIPSOP_SH_MD): Likewise. (MICROMIPSOP_MASK_ME, MICROMIPSOP_SH_ME): Likewise. (MICROMIPSOP_MASK_MF, MICROMIPSOP_SH_MF): Likewise. (MICROMIPSOP_MASK_MG, MICROMIPSOP_SH_MG): Likewise. (MICROMIPSOP_MASK_MJ, MICROMIPSOP_SH_MJ): Likewise. (MICROMIPSOP_MASK_ML, MICROMIPSOP_SH_ML): Likewise. (MICROMIPSOP_MASK_MP, MICROMIPSOP_SH_MP): Likewise. (MICROMIPSOP_MASK_MQ, MICROMIPSOP_SH_MQ): Likewise. (MICROMIPSOP_MASK_IMMA, MICROMIPSOP_SH_IMMA): Likewise. (MICROMIPSOP_MASK_IMMB, MICROMIPSOP_SH_IMMB): Likewise. (MICROMIPSOP_MASK_IMMC, MICROMIPSOP_SH_IMMC): Likewise. (MICROMIPSOP_MASK_IMMD, MICROMIPSOP_SH_IMMD): Likewise. (MICROMIPSOP_MASK_IMME, MICROMIPSOP_SH_IMME): Likewise. (MICROMIPSOP_MASK_IMMF, MICROMIPSOP_SH_IMMF): Likewise. (MICROMIPSOP_MASK_IMMG, MICROMIPSOP_SH_IMMG): Likewise. (MICROMIPSOP_MASK_IMMH, MICROMIPSOP_SH_IMMH): Likewise. (MICROMIPSOP_MASK_IMMI, MICROMIPSOP_SH_IMMI): Likewise. (MICROMIPSOP_MASK_IMMJ, MICROMIPSOP_SH_IMMJ): Likewise. (MICROMIPSOP_MASK_IMML, MICROMIPSOP_SH_IMML): Likewise. (MICROMIPSOP_MASK_IMMM, MICROMIPSOP_SH_IMMM): Likewise. (MICROMIPSOP_MASK_IMMN, MICROMIPSOP_SH_IMMN): Likewise. (MICROMIPSOP_MASK_IMMO, MICROMIPSOP_SH_IMMO): Likewise. (MICROMIPSOP_MASK_IMMP, MICROMIPSOP_SH_IMMP): Likewise. (MICROMIPSOP_MASK_IMMQ, MICROMIPSOP_SH_IMMQ): Likewise. (MICROMIPSOP_MASK_IMMU, MICROMIPSOP_SH_IMMU): Likewise. (MICROMIPSOP_MASK_IMMW, MICROMIPSOP_SH_IMMW): Likewise. (MICROMIPSOP_MASK_IMMX, MICROMIPSOP_SH_IMMX): Likewise. (MICROMIPSOP_MASK_IMMY, MICROMIPSOP_SH_IMMY): Likewise. (MICROMIPSOP_MASK_CODE, MICROMIPSOP_SH_CODE): Likewise. (MICROMIPSOP_MASK_CODE2, MICROMIPSOP_SH_CODE2): Likewise. (MICROMIPSOP_MASK_CACHE, MICROMIPSOP_SH_CACHE): Likewise. (MICROMIPSOP_MASK_CODE20, MICROMIPSOP_SH_CODE20): Likewise. (MICROMIPSOP_MASK_PERFREG, MICROMIPSOP_SH_PERFREG): Likewise. (MICROMIPSOP_MASK_CODE19, MICROMIPSOP_SH_CODE19): Likewise. (MICROMIPSOP_MASK_ALN, MICROMIPSOP_SH_ALN): Likewise. (MICROMIPSOP_MASK_VECBYTE, MICROMIPSOP_SH_VECBYTE): Likewise. (MICROMIPSOP_MASK_VECALIGN, MICROMIPSOP_SH_VECALIGN): Likewise. (MICROMIPSOP_MASK_DSPACC, MICROMIPSOP_SH_DSPACC): Likewise. (MICROMIPSOP_MASK_DSPACC_S, MICROMIPSOP_SH_DSPACC_S): Likewise. (MICROMIPSOP_MASK_DSPSFT, MICROMIPSOP_SH_DSPSFT): Likewise. (MICROMIPSOP_MASK_DSPSFT_7, MICROMIPSOP_SH_DSPSFT_7): Likewise. (MICROMIPSOP_MASK_SA3, MICROMIPSOP_SH_SA3): Likewise. (MICROMIPSOP_MASK_SA4, MICROMIPSOP_SH_SA4): Likewise. (MICROMIPSOP_MASK_IMM8, MICROMIPSOP_SH_IMM8): Likewise. (MICROMIPSOP_MASK_IMM10, MICROMIPSOP_SH_IMM10): Likewise. (MICROMIPSOP_MASK_WRDSP, MICROMIPSOP_SH_WRDSP): Likewise. (MICROMIPSOP_MASK_RDDSP, MICROMIPSOP_SH_RDDSP): Likewise. (MICROMIPSOP_MASK_BP, MICROMIPSOP_SH_BP): Likewise. (MICROMIPSOP_MASK_MT_U, MICROMIPSOP_SH_MT_U): Likewise. (MICROMIPSOP_MASK_MT_H, MICROMIPSOP_SH_MT_H): Likewise. (MICROMIPSOP_MASK_MTACC_T, MICROMIPSOP_SH_MTACC_T): Likewise. (MICROMIPSOP_MASK_MTACC_D, MICROMIPSOP_SH_MTACC_D): Likewise. (MICROMIPSOP_MASK_BBITIND, MICROMIPSOP_SH_BBITIND): Likewise. (MICROMIPSOP_MASK_CINSPOS, MICROMIPSOP_SH_CINSPOS): Likewise. (MICROMIPSOP_MASK_CINSLM1, MICROMIPSOP_SH_CINSLM1): Likewise. (MICROMIPSOP_MASK_SEQI, MICROMIPSOP_SH_SEQI): Likewise. (micromips_opcodes): New declaration. (bfd_micromips_num_opcodes): Likewise. * mips.h (INSN2_UNCOND_BRANCH, INSN2_COND_BRANCH): New macros. * mips.h (INSN2_MOD_GPR_MHI): New macro. (INSN2_MOD_GPR_MM, INSN2_MOD_GPR_MN): Likewise. (MICROMIPSOP_MASK_MH, MICROMIPSOP_SH_MH): Likewise. (MICROMIPSOP_MASK_MI, MICROMIPSOP_SH_MI): Likewise. (MICROMIPSOP_MASK_MM, MICROMIPSOP_SH_MM): Likewise. (MICROMIPSOP_MASK_MN, MICROMIPSOP_SH_MN): Likewise. ld/testsuite/ 2011-02-21 Catherine Moore Chao-ying Fu Maciej W. Rozycki * lib/ld-lib.exp (run_dump_test): Support distinct assembler flags for the same source named multiple times. * ld-mips-elf/jalx-1.s: New test source. * ld-mips-elf/jalx-1.d: New test output. * ld-mips-elf/jalx-1.ld: New test linker script. * ld-mips-elf/jalx-2-main.s: New test source. * ld-mips-elf/jalx-2-ex.s: Likewise. * ld-mips-elf/jalx-2-printf.s: Likewise. * ld-mips-elf/jalx-2.dd: New test output. * ld-mips-elf/jalx-2.ld: New test linker script. * ld-mips-elf/mips16-and-micromips.d: New test. * ld-mips-elf/mips-elf.exp: Run the new tests opcodes/ 2011-02-21 Chao-ying Fu Maciej W. Rozycki * micromips-opc.c: New file. * mips-dis.c (micromips_to_32_reg_b_map): New array. (micromips_to_32_reg_c_map, micromips_to_32_reg_d_map): Likewise. (micromips_to_32_reg_e_map, micromips_to_32_reg_f_map): Likewise. (micromips_to_32_reg_g_map, micromips_to_32_reg_l_map): Likewise. (micromips_to_32_reg_q_map): Likewise. (micromips_imm_b_map, micromips_imm_c_map): Likewise. (micromips_ase): New variable. (is_micromips): New function. (set_default_mips_dis_options): Handle microMIPS ASE. (print_insn_micromips): New function. (is_compressed_mode_p): Likewise. (_print_insn_mips): Handle microMIPS instructions. * Makefile.am (CFILES): Add micromips-opc.c. * configure.in (bfd_mips_arch): Add micromips-opc.lo. * Makefile.in: Regenerate. * configure: Regenerate. * mips-dis.c (micromips_to_32_reg_h_map): New variable. (micromips_to_32_reg_i_map): Likewise. (micromips_to_32_reg_m_map): Likewise. (micromips_to_32_reg_n_map): New macro.