public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] MIPS: microMIPS and MCU ASE instruction set support
@ 2010-05-18 18:19 Maciej W. Rozycki
  2010-05-23 21:38 ` Richard Sandiford
                   ` (2 more replies)
  0 siblings, 3 replies; 41+ messages in thread
From: Maciej W. Rozycki @ 2010-05-18 18:19 UTC (permalink / raw)
  To: binutils
  Cc: Chao-ying Fu, Ilie Garbacea, Joseph Myers, Catherine Moore,
	Daniel Jacobowitz

[-- Attachment #1: Type: TEXT/PLAIN, Size: 27908 bytes --]

Hi,

 This is a change to add support for the microMIPS and MCU ASE 
instructions as implemented by some recent MIPS processors.  The microMIPS 
ASE is a reencoding of the complete MIPS64r2 instruction set (the MIPS32r2 
set on 32-bit processors) using variable-length instructions, currently 
either 16-bit or 32-bit, with space reserved for future 48-bit ones.  
There are a number of instructions where both a 16-bit and a 32-bit 
variation of the same operation exist, usually differing by the width of 
the immediate operand.  This is in some sense similar to what the MIPS16 
ASE implements with the EXTEND prefix and likewise the tools are prepared 
to choose the smallest encoding possible.

 The whole instruction set is meant to be source-level compatible with the 
MIPS64r2/MIPS32r2 set as appropriate, assuming the ".set macro" mode of 
assembly (offset fields of some less often used instructions have been 
shortened and an auxiliary register, usually $at, is needed to access the 
whole address range) and no dependency of code on instruction lengths 
(e.g. no computed GOTOs using hardcoded constants).

 The MCU ASE adds a couple of further instructions on top of standard MIPS 
and microMIPS instruction sets.

 There's a lot of infrastructure added, including some changes to standard 
MIPS and MIPS16 support code for consistency, and the testsuite has been 
modified for easy reuse of the existing tests for microMIPS assembly 
(there's a potential to use these features elsewhere too, e.g. to extend 
tests that are now limited to the MIPS1 ISA because of load delay slots to 
all the ISAs).

 The patch itself is attached compressed, due to its size.  
Regression-tested successfully with the mips-sde-elf and mips-linux-gnu 
targets.

 Comments?

  Maciej

bfd/
2010-05-18  Chao-ying Fu  <fu@mips.com>
            Ilie Garbacea  <ilie@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>
            Joseph Myers  <joseph@codesourcery.com>
            Catherine Moore  <clm@codesourcery.com>

	* archures.c (bfd_mach_mips_micromips): New macro.
	* cpu-mips.c (I_micromips): New enum value.
	(arch_info_struct): Add bfd_mach_mips_micromips.
	* elf32-mips.c (elf_micromips_howto_table_rel): New variable.
	(_bfd_mips_elf32_gprel16_reloc): Handle microMIPS.
	(mips_elf_gprel32_reloc): Update comment.
	(micromips_reloc_map): New variable.
	(bfd_elf32_bfd_reloc_type_lookup): Handle microMIPS.
	(mips_elf32_rtype_to_howto): Likewise.
	(mips_info_to_howto_rel): Likewise.
	(elf32_mips_relax_delete_bytes): New function.
	(opcode_descriptor): New structure.
	(b_insns_32, b_insn_16): New variables.
	(BZ32_REG, BZ32_REG_FIELD): New macros.
	(bz_insns_32, bzc_insns_32, bz_insns_16): New variables.
	(BZ16_VALID_REG, BZ16_REG_FIELD): New macros.
	(jal_insn_32_bd16, jal_insn_32_bd32): New variables.
	(jalr_insn_32_bd16, jalr_insn_32_bd32): Likewise.
	(ds_insns_32_bd16, ds_insns_32_bd32): Likewise.
	(jalr_insn_16_bd16, jalr_insn_16_bd32): Likewise.
	(ds_insns_16_bd16): Likewise.
	(lui_insn, addiu_insn, addiupc_insn): Likewise.
	(ADDIU_REG, ADDIUPC_VALID_REG, ADDIUPC_REG_FIELD): New macros.
	(lwgp_insn_32, lwgp_insn_16): New functions.
	(LWGP32_REG, LWGP16_VALID_REG, LWGP16_REG_FIELD): New macros.
	(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.
	(relax_delay_slot): Likewise.
	(IS_BITSIZE): New macro.
	(elf32_mips_relax_section): New function.
	(bfd_elf32_bfd_relax_section): Define.
	* elf64-mips.c (micromips_elf64_howto_table_rel): New variable.
	(micromips_elf64_howto_table_rela): Likewise.
	(micromips_reloc_map): Likewise.
	(bfd_elf64_bfd_reloc_type_lookup): Handle microMIPS.
	(bfd_elf64_bfd_reloc_name_lookup): Likewise.
	(mips_elf64_rtype_to_howto): Likewise.
	* elfn32-mips.c (elf_micromips_howto_table_rel): New variable.
	(elf_micromips_howto_table_rela): Likewise.
	(micromips_reloc_map): Likewise.
	(bfd_elf32_bfd_reloc_type_lookup): Handle microMIPS.
	(bfd_elf32_bfd_reloc_name_lookup): Likewise.
	(mips_elf_n32_rtype_to_howto): Likewise.
	* elfxx-mips.c (micromips_reloc_shuffle_p): New function.
	(TLS_RELOC_P): Handle microMIPS.
	(got16_reloc_p, call16_reloc_p): Likewise.
	(hi16_reloc_p, lo16_reloc_p): Likewise.
	(_bfd_mips16_elf_reloc_unshuffle): Likewise.
	(_bfd_mips16_elf_reloc_shuffle): Likewise.
	(_bfd_mips_elf_lo16_reloc): Likewise.
	(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.
	(_bfd_mips_vxworks_finish_dynamic_symbol): Likewise.
	(_bfd_mips_elf_gc_sweep_hook): Likewise.
	(_bfd_mips_elf_print_private_bfd_data):	Likewise.
	* reloc.c (BFD_RELOC_MICROMIPS_16): New relocation.
	(BFD_RELOC_MICROMIPS_7_PCREL_S1): Likewise.
	(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.

	* elfxx-mips.c (mips_elf_calculate_relocation): Do not mark
	calls to undefined weak functions as needing jalx.

	* elfxx-mips.c (LA25_LUI_MICROMIPS_1, LA25_LUI_MICROMIPS_2,
	LA25_J_MICROMIPS_1, LA25_J_MICROMIPS_2, LA25_ADDIU_MICROMIPS_1,
	LA25_ADDIU_MICROMIPS_2): Define.
	(mips_elf_add_la25_intro, mips_elf_add_la25_trampoline): Adjust
	value of stub symbol if target is a microMIPS function.
	(mips_elf_create_la25_stub): Create microMIPS stub if target is
	a microMIPS function.

	* elfxx-mips.c (mips_elf_calculate_relocation): Expect low bit
	of $t9 to be set of microMIPS _gp_disp relocations.

binutils/
2010-05-18  Chao-ying Fu  <fu@mips.com>

	* readelf.c (get_machine_flags): Handle microMIPS.
	(get_mips_symbol_other): Likewise.

gas/
2010-05-18  Chao-ying Fu  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>
            Daniel Jacobowitz  <dan@codesourcery.com>

	* config/tc-mips.h (mips_segment_info): Add one bit for
	microMIPS.
	* config/tc-mips.c (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.
	(micromips_op_hash): New variable.
	(micromips_nop16_insn, micromips_nop32_insn): New variables.
	(NOP_INSN): Handle microMIPS.
	(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_q_map): New variable.
	(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_q_map): New variable.
	(micromips_imm_b_map, micromips_imm_c_map): New macros.
	(RELAX_DELAY_SLOT_SIZE_ERROR_FIRST): New macro.
	(RELAX_DELAY_SLOT_SIZE_ERROR_SECOND): Likewise.
	(RELAX_MICROMIPS_ENCODE, RELAX_MICROMIPS_P): New macros.
	(RELAX_MICROMIPS_TYPE, RELAX_MICROMIPS_USER_16BIT): Likewise.
	(RELAX_MICROMIPS_UNCOND, RELAX_MICROMIPS_LINK): Likewise.
	(RELAX_MICROMIPS_TOOFAR, RELAX_MICROMIPS_MARK_TOOFAR): Likewise.
	(RELAX_MICROMIPS_CLEAR_TOOFAR): Likewise.
	(RELAX_MICROMIPS_EXTENDED): Likewise.
	(RELAX_MICROMIPS_MARK_EXTENDED): Likewise.
	(RELAX_MICROMIPS_CLEAR_EXTENDED): Likewise.
	(MICROMIPS_INSERT_OPERAND, MICROMIPS_EXTRACT_OPERAND): New
	macros.
	(A_BFD_RELOC_HI16_S, A_BFD_RELOC_HI16, A_BFD_RELOC_LO16): New
	relocation wrapper macros.
	(A_BFD_RELOC_GPREL16): Likewise.
	(A_BFD_RELOC_MIPS_GOT16, A_BFD_RELOC_MIPS_GOT_HI16): Likewise.
	(A_BFD_RELOC_MIPS_GOT_LO16, A_BFD_RELOC_MIPS_HIGHEST): Likewise.
	(A_BFD_RELOC_MIPS_HIGHER, A_BFD_RELOC_MIPS_GOT_DISP): Likewise.
	(A_BFD_RELOC_MIPS_GOT_PAGE, A_BFD_RELOC_MIPS_GOT_OFST): Likewise.
	(A_BFD_RELOC_MIPS_SUB, A_BFD_RELOC_MIPS_JALR): Likewise.
	(mips_macro_warning): Add delay_slot_16bit_p, delay_slot_32bit_p,
	and num_insns.
	(micromips_16, micromips_32): New variables.
	(is_micromips_16bit_p, is_micromips_32bit_p): New functions.
	(insn_length): Return the length of microMIPS instructions.
	(mips_record_mips16_mode): Rename to...
	(mips_record_mips16_micromips_mode): ... this.  Handle microMIPS.
	(install_insn): Handle microMIPS.
	(is_opcode_valid): Likewise.
	(md_begin): Likewise.
	(md_assemble): Likewise.
	(micromips_reloc_p): New function.
	(got16_reloc_p): Handle microMIPS.
	(hi16_reloc_p): Likewise.
	(lo16_reloc_p): Likewise.
	(matching_lo_reloc): Likewise.
	(mips_move_labels): Likewise.
	(mips16_mark_labels): Rename to...
	(mips16_micromips_mark_labels): ... this.  Handle microMIPS.
	(insns_between): Handle microMIPS.
	(MICROMIPS_TARGET, MICROMIPS_TARGET_LABEL): New macros.
	(micromips_add_number_label): New function.
	(append_insn): Handle microMIPS.
	(start_noreorder, end_noreorder): Likewise.
	(macro_start, macro_warning, macro_end): Likewise.
	(macro_build): Likewise.
	(macro_build_jalr): Likewise.
	(macro_build_lui): Likewise.
	(macro_build_ldst_constoffset): Use relocation wrappers.
	(set_at): Likewise.
	(load_register): Likewise.
	(load_address): Likewise.
	(move_register): Handle microMIPS.
	(load_got_offset): Use relocation wrappers.
	(add_got_offset): Likewise.
	(add_got_offset_hilo): Likewise.
	(macro): Handle microMIPS.
	(validate_micromips_insn): New function.
	(micromips_percent_op): New variable.
	(parse_relocation): Handle microMIPS.
	(my_getExpression): Likewise.
	(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.
	(md_pcrel_from): Handle microMIPS relocations.
	(mips_force_relocation): Likewise.
	(md_apply_fix): Likewise.
	(mips_align): Handle microMIPS.
	(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.
	(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.
	(mips_fix_adjustable): Likewise.
	(tc_gen_reloc): Handle microMIPS relocations.
	(mips_relax_frag): Handle microMIPS.
	(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.
	(micromips_ip): New function.
	(micromips_macro_build): Likewise.
	(micromips_macro): Likewise.

	* 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.

	* config/tc-mips.c (mips_set_options): Add ase_mcu.
	(mips_opts): Initialise ase_mcu to -1.
	(ISA_SUPPORTS_MCU_ASE): New macro.
	(MIPS_CPU_ASE_MCU): Likewise.
	(is_opcode_valid): Handle MCU.
	(macro_build): Likewise.
	(macro): Likewise.
	(validate_mips_insn): Likewise.
	(mips_ip): Likewise.
	(options): Add OPTION_MCU and OPTION_NO_MCU.
	(md_longopts): Add mmcu and mno-mcu.
	(md_parse_option): Handle OPTION_MCU and OPTION_NO_MCU.
	(mips_after_parse_args): Handle MCU.
	(s_mipsset): Likewise.
	(md_show_usage): Handle MCU options.

	* doc/as.texinfo: Document -mmcu and -mno-mcu options.
	* doc/c-mips.texi: Likewise, and document ".set mcu" and
	".set nomcu" directives.

	* config/tc-mips.c (nops_for_insn_or_target): Replace
	MIPS16_INSN_BRANCH with MIPS16_INSN_UNCOND_BRANCH and
	MIPS16_INSN_COND_BRANCH.

	* config/tc-mips.c (append_insn): Replace INSN2_MOD_31 with
	INSN2_READ_GPR_31.  Merge with code to handle INSN_WRITE_GPR_31.

	* config/tc-mips.c (mips_cpu_info_table): Add "m14k".
	* doc/c-mips.texi (MIPS architecture options): Add "m14k" to the
	list of -march options.

	* config/tc-mips.c (mips32_to_micromips_reg_h_map): New
	variable.
	(mips32_to_micromips_reg_m_map): Likewise.
	(mips32_to_micromips_reg_n_map): New macro.
	(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.
	(append_insn): Handle microMIPS "mh", "mi", "mm" and "mn"
	operands.

	* config/tc-mips.c (mips_cpu_info_table): Add "m14kc".
	* doc/c-mips.texi (MIPS architecture options): Add "m14kc" to the
	list of -march options.

gas/testsuite/
2010-05-18  Maciej W. Rozycki  <macro@codesourcery.com>
            Chao-ying Fu  <fu@mips.com>

	* gas/mips/beq.d: Reformat.
	* gas/mips/bge.d, gas/mips/bgeu.d: Likewise.
	* gas/mips/blt.d, gas/mips/bltu.d: Likewise.

	* gas/mips/mips4-fp.d: Reformat.

	* gas/mips/beq.d, gas/mips/beq.s: Remove checks for
	branch-likely instructions and place them...
	* gas/mips/bge.d, gas/mips/bge.s: Likewise.
	* gas/mips/bgeu.d, gas/mips/bgeu.s: Likewise.
	* gas/mips/blt.d, gas/mips/blt.s: Likewise.
	* gas/mips/bltu.d, gas/mips/bltu.s: Likewise.
	* gas/mips/branch-likely.d, gas/mips/branch-likely.s: ... in
	this new test.
	* gas/mips/mips.exp: Run the new test and update the
	constraints for the upated tests to include MIPS I.

	* gas/mips/mips4-fp.d, gas/mips/mips4-fp.s: Remove checks for
	branch-likely instructions and place them...
	* gas/mips/mips4-fp.l: Update accordingly.
	* gas/mips/mips4-branch-likely.d, gas/mips/mips4-branch-likely.s:
	... in this new test.
	* gas/mips/mips4-branch-likely.l: New stderr output for the new
	test.
	* gas/mips/mips.exp (mips4-branch-likely): Run a dump test and
	list tests matching branch-likely and mips4-fp tests
	appropriately.

	* gas/mips/micromips.d: New test.
	* gas/mips/micromips-trap.d: Likewise.
	* gas/mips/micromips-branch-relax-pic.d: Likewise.
	* gas/mips/micromips-branch-relax-pic.d: Likewise.
	* gas/mips/micromips.l: New stderr output.
	* gas/mips/micromips-branch-relax.l: Likewise.
	* gas/mips/micromips-branch-relax-pic.l: Likewise.
	* gas/mips/micromips.s: New test source.
	* gas/mips/micromips-branch-relax.s: Likewise.
	* gas/mips/mips.exp: Run the new tests.

	* gas/mips/mips.exp (run_dump_test_arch): Check for the presence
	of an architecture-specific test first and use it if found,
	before falling back to the generic one.

	* gas/mips/micromips@abs.d: New test.
	* 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@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@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@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/mips32-imm.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/mips32-imm.s: Likewise.
	* gas/mips/mips32.s: Handle microMIPS.
	* gas/mips/mips.exp: Add the micromips arch.  Exclude mips16e
	from micromips.  Run mips32-imm.

	* gas/mips/micromips@mcu.d: New test.
	* gas/mips/mcu.d: Likewise.
	* gas/mips/mcu.s: New test source.
	* gas/mips/mips.exp: Run the new tests.

	* 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.

include/elf/
2010-05-18  Chao-ying Fu  <fu@mips.com>

	* mips.h (R_MICROMIPS_min, R_MICROMIPS_16): 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.
	(ELF_ST_IS_MIPS_PLT): Likewise.
	(STO_MICROMIPS): Likewise.
	(ELF_ST_IS_MICROMIPS, ELF_ST_MICROMIPS, ELF_ST_SET_MICROMIPS):
	Likewise.
	(ELF_ST_IS_MIPS_PIC, ELF_ST_SET_MIPS_PIC): Handle microMIPS.

include/opcode/
2010-05-18  Chao-ying Fu  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* mips.h
	(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_MOD_31): Likewise.
	(INSN2_READ_GP, INSN2_READ_PC): Likewise.
	(CPU_MICROMIPS): New macro.
	(M_BC1FL, M_BC1TL, M_BC2FL, M_BC2TL, M_BEQL, M_BGEZL): New enum
	values.
	(M_BGEZALL, M_BGTZL, M_BLEZL, M_BLTZL, M_BLTZALL): Likewise.
	(M_CACHE_OB, 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_LWP_AB, M_LWP_OB): Likewise.
	(M_LWR_OB, 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, M_SDP_AB): Likewise.
	(M_SDP_OB, M_SDR_OB, M_SWC2_OB, M_SWL_OB, M_SWM_AB): Likewise.
	(M_SWM_OB, 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_BREAKCODE, MICROMIPSOP_SH_BREAKCODE): Likewise.
	(MICROMIPSOP_SH_BREAKCODE2): Likewise.
	(MICROMIPSOP_MASK_CACHEOP, MICROMIPSOP_SH_CACHEOP): Likewise.
	(MICROMIPSOP_MASK_COPSEL, MICROMIPSOP_SH_COPSEL): 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_MZ, MICROMIPSOP_SH_MZ): 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.
	(micromips_opcodes): New declaration.
	(bfd_micromips_num_opcodes): Likewise.

	* mips.h (OP_MASK_3BITPOS, OP_SH_3BITPOS): New macros.
	(OP_MASK_OFFSET12, OP_SH_OFFSET12): Likewise.
	(INSN_ASE_MASK): Add the MCU bit.
	(INSN_MCU): New macro.
	(M_ACLR_AB, M_ACLR_OB, M_ASET_AB, M_ASET_OB): New enum values.

	* mips.h (MIPS16_INSN_UNCOND_BRANCH): New macro.
	(MIPS16_INSN_BRANCH): Rename to...
	(MIPS16_INSN_COND_BRANCH): ... this.

	* mips.h (INSN2_MOD_31): Rename to...
	(INSN2_READ_GPR_31): ... this.
	(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/
2010-05-18  Catherine Moore  <clm@codesourcery.com>
            Chao-ying Fu  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* ld-mips-elf/jalx-1.s: New test.
	* ld-mips-elf/jalx-1.d: New test output.
	* ld-mips-elf/jalx-1.ld: New test linker script.
	* ld-mips-elf/mips-elf.exp: Run new test.

	* ld-mips-elf/jalx-2-main.s: New.
	* ld-mips-elf/jalx-2.dd: New.
	* ld-mips-elf/jalx-2-ex.s: New.
	* ld-mips-elf/jalx-2-printf.s: New.
	* ld-mips-elf/mips-elf.exp: Run new test.

opcodes/
2010-05-18  Chao-ying Fu  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>
	* 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.
	(print_insn_micromips): New function.
	(is_micromips_mode_p): New function.
	(_print_insn_mips): Handle microMIPS instructions.
	* Makefile.am (CFILES): Add micromips-opc.c.
	(ALL_MACHINES): Add micromips-opc.lo.
	(micromips-opc.lo): Add dependencies.
	* configure.in (bfd_mips_arch): Add micromips-opc.lo.
	* Makefile.in: Regenerate.
	* configure: Regenerate.

	* mips-dis.c (mips_arch_choices): Enable MCU for "mips32r2"
	and "mips64r2".
	(print_insn_args): Handle MCU.
	* mips-opc.c (MC): New macro.
	(mips_builtin_opcodes): Add "aclr", "aset" and "iret".

	* mips-dis.c (print_mips16_insn_arg): Remove branch instruction
	type and delay slot determination.
	(print_insn_mips16): Extend branch instruction type and delay
	slot determination to cover all instructions.
	* mips16-opc.c (BR): Remove macro.
	(UBR, CBR): New macros.
	(mips16_opcodes): Update branch annotation for "b", "beqz",
	"bnez", "bteqz" and "btnez".  Add branch annotation for "jalrc"
	and "jrc".

	* mips-dis.c (print_insn_mips): Correct branch instruction type
	determination.

	* 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.

[-- Attachment #2: Type: APPLICATION/octet-stream, Size: 132901 bytes --]

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS and MCU ASE instruction set support
  2010-05-18 18:19 [PATCH] MIPS: microMIPS and MCU ASE instruction set support Maciej W. Rozycki
@ 2010-05-23 21:38 ` Richard Sandiford
  2010-05-24 22:25   ` Fu, Chao-Ying
                     ` (2 more replies)
  2010-05-26 20:19 ` [PATCH] MIPS: microMIPS and MCU ASE instruction set support Richard Sandiford
  2010-05-27 21:39 ` Richard Sandiford
  2 siblings, 3 replies; 41+ messages in thread
From: Richard Sandiford @ 2010-05-23 21:38 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: binutils, Chao-ying Fu, Ilie Garbacea, Joseph Myers,
	Catherine Moore, Daniel Jacobowitz

Big patch, so this review is only for the gas and ld/testsuite bits.
I'll try to look at the rest some

Generally looks good.  It would have been better to submit the
ACE, m14kc and microMIPS support as three separate changes though.
Please can you do that for the follow-up?

From a usability perspective, it's a shame that:

	.set	micromips
	.ent	foo
foo:
	b	1f
	nop
	.end	foo
	.ent	bar
bar:
1:	nop
	.end	bar

disassembles as:

00000000 <foo>:
   0:   cfff            b       0 <foo>
                        0: R_MICROMIPS_PC10_S1  .L11
   2:   0c00            nop
   4:   0c00            nop

00000006 <bar>:
   6:   0c00            nop

leaving the poor user with no idea what .L11 is.

The following:

	.set	micromips
	.ent	foo
foo:
	ld	$10,0x1000($11)
	.end	foo

generates an assertion failure:

Assertion failure in micromips_macro_build at gas/config/tc-mips.c line 19466.
Please report this bug.

on mipsisa64-elf with "-mips1 -mabi=32".

"Maciej W. Rozycki" <macro@codesourcery.com> writes:
> gas/
> 2010-05-18  Chao-ying Fu  <fu@mips.com>
>             Maciej W. Rozycki  <macro@codesourcery.com>
>             Daniel Jacobowitz  <dan@codesourcery.com>
>
> 	* config/tc-mips.h (mips_segment_info): Add one bit for
> 	microMIPS.
> 	* config/tc-mips.c

How about having something like:

  #define OOD_TEXT_LABELS (mips_opts.mips16 || mips_opts.micromips)

?

> 	(A_BFD_RELOC_HI16_S, A_BFD_RELOC_HI16, A_BFD_RELOC_LO16): New
> 	relocation wrapper macros.
> 	(A_BFD_RELOC_GPREL16): Likewise.
> 	(A_BFD_RELOC_MIPS_GOT16, A_BFD_RELOC_MIPS_GOT_HI16): Likewise.
> 	(A_BFD_RELOC_MIPS_GOT_LO16, A_BFD_RELOC_MIPS_HIGHEST): Likewise.
> 	(A_BFD_RELOC_MIPS_HIGHER, A_BFD_RELOC_MIPS_GOT_DISP): Likewise.
> 	(A_BFD_RELOC_MIPS_GOT_PAGE, A_BFD_RELOC_MIPS_GOT_OFST): Likewise.
> 	(A_BFD_RELOC_MIPS_SUB, A_BFD_RELOC_MIPS_JALR): Likewise.

Did you consider doing the translation from non-microMIPS to
microMIPS in the macro_* functions, rather than in their callers?
I fear it'll be too easy to accidentally forget to use A_BFD_* in future.

> 	(mips_macro_warning): Add delay_slot_16bit_p, delay_slot_32bit_p,
> 	and num_insns.
> 	(micromips_16, micromips_32): New variables.
> 	(is_micromips_16bit_p, is_micromips_32bit_p): New functions.
> 	(insn_length): Return the length of microMIPS instructions.
> 	(mips_record_mips16_mode): Rename to...
> 	(mips_record_mips16_micromips_mode): ... this.  Handle microMIPS.
> 	(install_insn): Handle microMIPS.
> 	(is_opcode_valid): Likewise.
> 	(md_begin): Likewise.

+	      if (micromips_nop16_insn.insn_mo == NULL
+		  && strcmp (name, "nop") == 0)
+		{
+		  create_insn (&micromips_nop16_insn, micromips_opcodes + i);
+		  micromips_nop16_insn.fixed_p = 1;
+		}
+	      else if (micromips_nop32_insn.insn_mo == NULL
+		  && strcmp (name, "nop") == 0)
+		{
+		  create_insn (&micromips_nop32_insn, micromips_opcodes + i);
+		  micromips_nop32_insn.fixed_p = 1;
+		}

You seem to rely on the 16-bit nop being first.  Wouldn't it be more
robust to call is_micromips_16bit_p and is_micromips_32bit_p?

> 	(MICROMIPS_TARGET, MICROMIPS_TARGET_LABEL): New macros.
> 	(micromips_add_number_label): New function.

+/* For microMIPS macros, we need to generate a local number label
+   as the target of branches.  */
+#define MICROMIPS_TARGET	"2147483647f"
+#define MICROMIPS_TARGET_LABEL	2147483647
+
+static void
+micromips_add_number_label (void)
+{
+  symbolS *s;
+  fb_label_instance_inc (MICROMIPS_TARGET_LABEL);
+  s = colon (fb_label_name (MICROMIPS_TARGET_LABEL, 0));
+  S_SET_OTHER (s, ELF_ST_SET_MICROMIPS (S_GET_OTHER (s)));
+}
+

Ugh, this is a bit hackish.  There's nothing stopping a user using
2147483647f themselves.

> 	(append_insn): Handle microMIPS.

+  if (mips_opts.micromips)
+    {
+      if ((prev_pinfo2 & INSN2_BRANCH_DELAY_16BIT)
+	  && !is_micromips_16bit_p (ip->insn_mo))
+	as_warn (_("instruction with wrong size in a branch delay slot that"
+		   " requires a 16-bit instruction"));
+      if ((prev_pinfo2 & INSN2_BRANCH_DELAY_32BIT)
+	  && !is_micromips_32bit_p (ip->insn_mo))
+	as_warn (_("instruction with wrong size in a branch delay slot that"
+		   " requires a 32-bit instruction"));
+    }
+  

Although not enforced as often as it should be, GAS convention is for
errors to start with a capital letter.

+      if (pinfo & INSN_COP)
+	{
+	  /* We don't keep enough information to sort these cases out.
+	     The itbl support does keep this information however, although
+	     we currently don't support itbl fprmats as part of the cop
+	     instruction.  May want to add this support in the future.  */
+	}

Assert?

+	      /* For microMIPS, disable reordering.  */
+	      || (mips_opts.micromips)

Redundant (...)

-	      if (mips_relax.sequence)
-		mips_relax.sizes[mips_relax.sequence - 1] += 4;
+	      /* MicroMIPS nop is 2 bytes.  */
+  	      if (mips_relax.sequence)
+		mips_relax.sizes[mips_relax.sequence - 1] +=
+		  mips_opts.micromips ? micromips_nop_size : 4;

Confusing comment: the microMIPS nop may be 2 or 4 bytes.
Better to say nothing IMO.

> 	(start_noreorder, end_noreorder): Likewise.

+	      frag_grow ((mips_opts.mips16 | mips_opts.micromips) ? nops * 2
+								  : nops * 4);

How about a NOP_INSN_SIZE macro?  (Or similar.)

> 	(macro_start, macro_warning, macro_end): Likewise.

+  else if ((subtype & RELAX_DELAY_SLOT_SIZE_ERROR_FIRST)
+	   || (subtype & RELAX_DELAY_SLOT_SIZE_ERROR_SECOND))
+    return _("Macro instruction of the wrong size in a branch delay slot"
+	     " that requires a 16-bit or 32-bit instruction");

Did you consider adding a flag to distinguish the 32-bit and 16-bit cases?
It'd be nice to be consistent with the non-relaxed error if possible.

+  /* If either one implementation contains one instruction, we need to check
+     the delay slot size requirement.  */

"If either implementation"

+  /* If either one implementation contains one instruction, we need to check
+     the delay slot size requirement.  */
+  if (mips_macro_warning.num_insns[0] == 1
+      || mips_macro_warning.num_insns[1] == 1)
+    {
+      if (mips_macro_warning.num_insns[0] == mips_macro_warning.num_insns[1]
+	  && mips_macro_warning.sizes[0] == mips_macro_warning.sizes[1])
+	{
+	  /* Either the macro has a single implementation or both
+	     implementations are 1 instruction with the same size.
+	     Emit the warning now.  */
+	  if ((mips_macro_warning.delay_slot_16bit_p
+	       && mips_macro_warning.sizes[0] != 2)
+	      || (mips_macro_warning.delay_slot_32bit_p
+		  && mips_macro_warning.sizes[0] != 4))
+	    {
+	      const char *msg;
+	      msg = macro_warning (RELAX_DELAY_SLOT_SIZE_ERROR_FIRST);
+	      if (msg != 0)
+		as_warn (msg);
+	    }
+	}
+      else
+	{
+	  relax_substateT subtype;
+
+	  /* Set up the relaxation warning flags.  */
+	  subtype = 0;
+	  if (mips_macro_warning.delay_slot_16bit_p)
+	    {
+	      if (mips_macro_warning.num_insns[0] != 1
+		  || mips_macro_warning.sizes[0] != 2)
+		subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
+	      if (mips_macro_warning.num_insns[1] != 1
+		  || mips_macro_warning.sizes[1] != 2)
+		subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
+	    }
+	  if (mips_macro_warning.delay_slot_32bit_p)
+	    {
+	      if (mips_macro_warning.num_insns[0] != 1
+		  || mips_macro_warning.sizes[0] != 4)
+		subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
+	      if (mips_macro_warning.num_insns[1] != 1
+		  || mips_macro_warning.sizes[1] != 4)
+		subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
+	    }
+
+	  /* One implementation might need a warning but the other
+	     definitely doesn't.  */
+	  mips_macro_warning.first_frag->fr_subtype |= subtype;
+	}
+    }

Why not work out the subtype, then check whether both ERROR_FIRST and
ERROR_SECOND are set?

+	  if (mips_macro_warning.delay_slot_p)
+	    {
+	      if (mips_macro_warning.num_insns[0] > 1)
+		subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
+	      if (mips_macro_warning.num_insns[1] > 1)
+		subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
+	    }

I don't get why this hunk is needed.  I thought ERROR_FIRST and ERROR_SECOND
controlled cases where a macro has a single-insn expansion that is the
wrong size, which ought to be handled by the block above.  If the code
really is needed, you should add a comment explaining why.

> 	(macro_build): Likewise.

+  if (mips_opts.micromips)
+    {
+      if (strcmp (name, "lui") == 0)
+	micromips_macro_build (ep, name, "s,u", args);
+      else if (strcmp (fmt, "d,w,<") == 0)
+	micromips_macro_build (ep, name, "t,r,<", args);
+      else
+	micromips_macro_build (ep, name, fmt, args);
+      va_end (args);
+      return;
+    }

A bit of commentary might help explain the letter switch here.

> 	(macro_build_jalr): Likewise.

+  if (mips_opts.micromips)
+    {
+      if (HAVE_NEWABI)
+	macro_build (NULL, "jalr", "t,s", RA, PIC_CALL_REG);
+      else
+	macro_build (NULL, "jalr", "mj", PIC_CALL_REG);
+    }
+  else
+    macro_build (NULL, "jalr", "d,s", RA, PIC_CALL_REG);

Why HAVE_NEWABI?  Do you want a 32-bit insn for R_MIPS_JALR?
If so, you should check MIPS_JALR_HINT_P (ep) instead.

> 	(load_register): Likewise.

-	      macro_build (&tmp, "ori", "t,r,i", reg, 0, BFD_RELOC_LO16);
+	      macro_build (&tmp, "ori", "t,r,i", reg, 0, A_BFD_RELOC_LO16);
 	      macro_build (NULL, (shift >= 32) ? "dsll32" : "dsll", "d,w,<",
-			   reg, reg, (shift >= 32) ? shift - 32 : shift);
+				  reg, reg, (shift >= 32) ? shift - 32 : shift);

Last change looks bogus.

> 	(md_apply_fix): Likewise.

-  gas_assert (fixP->fx_size == 4
+  gas_assert (fixP->fx_size == 2
+	  || fixP->fx_size == 4
 	  || fixP->fx_r_type == BFD_RELOC_16
+	  || fixP->fx_r_type == BFD_RELOC_MICROMIPS_16
 	  || fixP->fx_r_type == BFD_RELOC_64
 	  || fixP->fx_r_type == BFD_RELOC_CTOR
 	  || fixP->fx_r_type == BFD_RELOC_MIPS_SUB
+	  || fixP->fx_r_type == BFD_RELOC_MICROMIPS_SUB
 	  || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
 	  || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
 	  || fixP->fx_r_type == BFD_RELOC_MIPS_TLS_DTPREL64);
 
+
   buf = (bfd_byte *) (fixP->fx_frag->fr_literal + fixP->fx_where);

Last change is bogus.

+    case BFD_RELOC_MICROMIPS_7_PCREL_S1:
+    case BFD_RELOC_MICROMIPS_10_PCREL_S1:
+    case BFD_RELOC_MICROMIPS_16_PCREL_S1:
+      /* We adjust the offset back to even.  */
+      if ((*valP & 0x1) != 0)
+	--(*valP);
+
+      if (! fixP->fx_done)
+	break;
+
+      /* Should never visit here, because we keep the relocation.  */
+      abort ();
+      break;

I suppose this silently ignores branches to non-microMIPS code,
but there again, so does the MIPS16 equivalent...

> 	(mips_relax_frag): Handle microMIPS.

+     gas_assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2
+	      || 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);
+
+      /* For 7/10 PCREL_S1, we just need to use fixp->fx_addnumber.  */
+      if (fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
+	  || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1)
+	reloc->addend = fixp->fx_addnumber;
+      else
+	/* At this point, fx_addnumber is "symbol offset - pcrel address".
+	   Relocations want only the symbol offset.  */
+	reloc->addend = fixp->fx_addnumber + reloc->address;

A better comment is needed.  _Why_ do you just need fx_addnumber?

> 	(md_convert_frag): Likewise.

-      /* Possibly emit a warning if we've chosen the longer option.  */
-      if (((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
-	  == ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))
+      if (!(fragp->fr_subtype & RELAX_USE_SECOND))
+  	{
+	  /* Check if the size in branch delay slot is ok.  */
+	  if (fragp->fr_subtype & RELAX_DELAY_SLOT_SIZE_ERROR_FIRST)
+	    {
+	      const char *msg = macro_warning (fragp->fr_subtype);
+	      if (msg != 0)
+		as_warn_where (fragp->fr_file, fragp->fr_line, msg);
+	    }
+	}
+      else
 	{
-	  const char *msg = macro_warning (fragp->fr_subtype);
-	  if (msg != 0)
-	    as_warn_where (fragp->fr_file, fragp->fr_line, "%s", msg);
+	  /* Check if the size in branch delay slot is ok.
+	     Possibly emit a warning if we've chosen the longer option.  */
+	  if ((fragp->fr_subtype & RELAX_DELAY_SLOT_SIZE_ERROR_SECOND)
+	      || (fragp->fr_subtype & RELAX_SECOND_LONGER))
+	    {
+	      const char *msg = macro_warning (fragp->fr_subtype);
+	      if (msg != 0)
+		as_warn_where (fragp->fr_file, fragp->fr_line, msg);
+	    }
 	}

This doesn't accurately preserve the previous:

      if (((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
	  == ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))

behaviour.

> 	(mips_handle_align): Likewise.

       /* If we're not inserting a whole number of instructions,
-	 pad the end of the fixed part of the frag with zeros.  */
-      memset (p, 0, excess);
+         pad the end of the fixed part of the frag with zeros.
+         But try to fit a short microMIPS nop too if applicable.  */
+      if (excess < 2 || *p != 2)
+	memset (p, 0, excess);
+      else
+	{
+	  memset (p, 0, excess - 2);
+	  md_number_to_chars (p + excess - 2,
+			      micromips_nop16_insn.insn_opcode, 2);
+	}

Not how it'd be written from scratch; the comment makes microMIPS sound
like an afterthought.  Please handle the microMIPS case first and make
the comment treat it as a first-class citizen.

> 	(micromips_ip): New function.

+      /* Try to search "16" or "32" in the str.  */
+      if ((t = strstr (str, "16")) != NULL && t < save_s)
+	{
+	  /* Make sure "16" is before the first '.' if '.' exists.  */
+	  if ((s = strchr (str, '.')) != NULL && (t + 2 != s))
+	    {
+	      insn_error = "unrecognized opcode";
+	      return;
+	    }
+
+	  /* Make sure "16" is at the end of insn name, if no '.'.  */
+	  if ((s = strchr (str, '.')) == NULL
+	      && (!ISSPACE (*(t + 2)) && *(t + 2) != '\0'))
+	    {
+	      insn_error = "unrecognized opcode";
+	      return;
+	    }
+
+	  micromips_16 = TRUE;
+	  for (s = t + 2; *s != '\0'; ++s)
+	    *(s - 2) = *s;
+	  *(s - 2) = '\0';
+
+	  for (s = t; *s != '\0' && !ISSPACE (*s); ++s)
+	    continue;
+
+	  if (ISSPACE (*s))
+	    {
+	      save_c = *s;
+	      *s++ = '\0';
+	    }
+
+	  if ((insn = (struct mips_opcode *) hash_find (micromips_op_hash, str))
+	      == NULL)
+	    {
+	      int i;
+	      int length;
+	      micromips_16 = FALSE;
+
+	      /* Restore the character we overwrite above (if any).  */
+	      if (save_c)
+		*(--s) = save_c;
+
+	      length = strlen (str);
+	      for (i = length - 1; &str[i] >= t; i--)
+		{
+		  str[i + 2] = str[i];
+		  if (t == &str[i])
+		    {
+		      str[i + 1] = '6';
+		      str[i] = '1';
+		      str[length + 2] = '\0';
+		      break;
+		    }
+		}
+
+	      insn_error = "unrecognized 16-bit version of microMIPS opcode";
+	      return;
+	    }
+	}
+      else if ((t = strstr (str, "32")) != NULL && t < save_s)
+	{
+	  /* For some instruction names, we already have 32, so we need
+	     to seek the second 32 to process.  Ex: bposge3232, dsra3232.  */
+	  char *new_t;
+	  if ((new_t = strstr (t + 2, "32")) != NULL && new_t < save_s)
+	    t = new_t;
+
+	  /* Make sure "32" is before the first '.' if '.' exists.  */
+	  if ((s = strchr (str, '.')) != NULL && (t + 2 != s))
+	    {
+	      insn_error = "unrecognized opcode";
+	      return;
+	    }
+
+	  /* Make sure "32" is at the end of the name, if no '.'.  */
+	  if ((s = strchr (str, '.')) == NULL
+	      && (!ISSPACE (*(t + 2)) && *(t + 2) != '\0'))
+	    {
+	      insn_error = "unrecognized opcode";
+	      return;
+	    }
+
+	  micromips_32 = TRUE;
+	  for (s = t + 2; *s != '\0'; ++s)
+	    *(s - 2) = *s;
+	  *(s - 2) = '\0';
+
+	  for (s = t; *s != '\0' && !ISSPACE (*s); ++s)
+	    continue;
+
+	  if (ISSPACE (*s))
+	    {
+	      save_c = *s;
+	      *s++ = '\0';
+	    }
+
+	  if ((insn = (struct mips_opcode *) hash_find (micromips_op_hash, str))
+	      == NULL)
+	    {
+	      int i;
+	      int length;
+	      micromips_32 = FALSE;
+
+	      /* Restore the character we overwrite above (if any).  */
+	      if (save_c)
+		*(--s) = save_c;
+
+	      length = strlen (str);
+	      for (i = length - 1; &str[i] >= t; i--)
+		{
+		  str[i + 2] = str[i];
+		  if (t == &str[i])
+		    {
+		      str[i + 1] = '2';
+		      str[i] = '3';
+		      str[length + 2] = '\0';
+		      break;
+		    }
+		}
+
+	      insn_error = "unrecognized 32-bit version of microMIPS opcode";
+	      return;
+	    }

Far too much cut-&-paste between the "16" and "32" cases.  Also:

+      if ((t = strstr (str, "16")) != NULL && t < save_s)

t < save_s must surely be true, since save_s is the null terminator.

+	  /* Make sure "16" is before the first '.' if '.' exists.  */
+	  if ((s = strchr (str, '.')) != NULL && (t + 2 != s))
+	    {
+	      insn_error = "unrecognized opcode";
+	      return;
+	    }
+
+	  /* Make sure "16" is at the end of insn name, if no '.'.  */
+	  if ((s = strchr (str, '.')) == NULL
+	      && (!ISSPACE (*(t + 2)) && *(t + 2) != '\0'))
+	    {
+	      insn_error = "unrecognized opcode";
+	      return;
+	    }

Don't call strchr (str, '.') twice like that.  Better would be:

	s = strchr (str, '.');

followed by the two checks.  Isn't the ISSPACE check redundant though,
given that you've terminated the string at the first space?  I would
have thought:

        if (t + 2 != (s ? s : save_s))

would be enough.  Errors should start with a capital letter.  Missing
internationalisation.

You could use alloca to create an opcode without the "16" or "32",
which would make the error-reporting code simpler.  It's best not
to change the user's source line if we can help it.

+	      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;
+		}
+	      if (save_c)
+		*(--s) = save_c;
+
+	      if (micromips_16 || micromips_32)
+		{
+		  int i;
+		  int length;
+
+		  length = strlen (str);
+		  for (i = length - 1; i >= 0; i--)
+		    {
+		      str[i + 2] = str[i];
+		      if (t == &str[i])
+			break;
+		    }
+		  if (micromips_16)
+		    {
+		      insn_error =
+			"unrecognized 16-bit version of microMIPS opcode";
+		      str[i + 1] = '6';
+		      str[i] = '1';
+		    }
+		  else
+		    {
+		      insn_error =
+			"unrecognized 32-bit version of microMIPS opcode";
+		      str[i + 1] = '2';
+		      str[i] = '3';
+		    }
+		  str[length + 2] = '\0';
+		}
+	      return;

Why override the insn_error unconditionally like this?  E.g.:

	jar16	$30,$26

    Error: unrecognized 16-bit version of microMIPS opcode `jar16 $30,$26'

implies there's a 32-bit opcode.  I'd also have thought that the
"opcode not supported on this processor" would triumph if it applies.

+do_lsb:

Not properly indented.  A few other instances.

+			}
+		    }
+	/* Now that we have assembled one operand, we use the args string
+	 * to figure out where it goes in the instruction.  */
+		  switch (c)
+		    {

Bogus indentation.

> 	(micromips_macro_build): Likewise.
> 	(micromips_macro): Likewise.

I'll look at micromips_ip and these two in more detail later.

> 	* ld-mips-elf/jalx-2-main.s: New.
> 	* ld-mips-elf/jalx-2.dd: New.
> 	* ld-mips-elf/jalx-2-ex.s: New.
> 	* ld-mips-elf/jalx-2-printf.s: New.
> 	* ld-mips-elf/mips-elf.exp: Run new test.

Please make the .dd output less susceptible to things like the number
of sections, size of program headers, etc.  One way is to use a linker
script to place each section at a nice round address.  Another is to
".*" out the addresses and instruction encodings and just reply on
the symbolic part of the disassembly.  I think the former's better
here.  There are quite a few existing examples.

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: [PATCH] MIPS: microMIPS and MCU ASE instruction set support
  2010-05-23 21:38 ` Richard Sandiford
@ 2010-05-24 22:25   ` Fu, Chao-Ying
  2010-05-26 19:47     ` Richard Sandiford
  2010-06-01 14:21   ` Maciej W. Rozycki
  2010-07-26 10:56   ` [PATCH] MIPS: microMIPS ASE support Maciej W. Rozycki
  2 siblings, 1 reply; 41+ messages in thread
From: Fu, Chao-Ying @ 2010-05-24 22:25 UTC (permalink / raw)
  To: Richard Sandiford, Maciej W. Rozycki
  Cc: binutils, Garbacea, Ilie, Joseph Myers, Catherine Moore, dan

Richard Sandiford wrote:

> > 	(mips_relax_frag): Handle microMIPS.
> 
> +     gas_assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2
> +	      || 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);
> +
> +      /* For 7/10 PCREL_S1, we just need to use 
> fixp->fx_addnumber.  */
> +      if (fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
> +	  || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1)
> +	reloc->addend = fixp->fx_addnumber;
> +      else
> +	/* At this point, fx_addnumber is "symbol offset - 
> pcrel address".
> +	   Relocations want only the symbol offset.  */
> +	reloc->addend = fixp->fx_addnumber + reloc->address;
> 
> A better comment is needed.  _Why_ do you just need fx_addnumber?
> 

  Thanks for the review!  The explanation is in another place as
follows.
Maybe we need to copy the comment to tc_gen_reloc from md_pcrel_from.
Ex:
long
md_pcrel_from (fixS *fixP)
{
  valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
  switch (fixP->fx_r_type)
    {
    /* We don't add addr, because it will cause the error checking of
       "addnumber" fail in write.c for *7/10_PCREL_S1.
        In tc_gen_reloc, we just use fixp->fx_addnumber.  */
    case BFD_RELOC_MICROMIPS_7_PCREL_S1:
    case BFD_RELOC_MICROMIPS_10_PCREL_S1:
      /* Return the beginning of the delay slot from the current insn.
*/
      return 2;

    case BFD_RELOC_MICROMIPS_16_PCREL_S1:
    case BFD_RELOC_MICROMIPS_JMP:
    case BFD_RELOC_16_PCREL_S2:
    case BFD_RELOC_MIPS_JMP:
      /* Return the address of the delay slot.  */
      return addr + 4;
...

  The field of *7/10_PCREL_S1 is limited in the 16-bit instructions.
If we add the "address", write.c will fail to check these two
relocations due to overflow or something (I kind of forgot). From
debugging, adding "address" is no use at all, because later "address" is
subtracted.
Maybe, we can do the same thing to *16_PCREL* by discarding address in
tc_gen_reloc() and md_pcrel_from(),
such that code looks cleaner and the same.
Thanks!

Regards,
Chao-ying

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS and MCU ASE instruction set support
  2010-05-24 22:25   ` Fu, Chao-Ying
@ 2010-05-26 19:47     ` Richard Sandiford
  0 siblings, 0 replies; 41+ messages in thread
From: Richard Sandiford @ 2010-05-26 19:47 UTC (permalink / raw)
  To: Fu, Chao-Ying
  Cc: Maciej W. Rozycki, binutils, Garbacea, Ilie, Joseph Myers,
	Catherine Moore, dan

"Fu, Chao-Ying" <fu@mips.com> writes:
> Richard Sandiford wrote:
>> > 	(mips_relax_frag): Handle microMIPS.
>> 
>> +     gas_assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2
>> +	      || 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);
>> +
>> +      /* For 7/10 PCREL_S1, we just need to use 
>> fixp->fx_addnumber.  */
>> +      if (fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
>> +	  || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1)
>> +	reloc->addend = fixp->fx_addnumber;
>> +      else
>> +	/* At this point, fx_addnumber is "symbol offset - 
>> pcrel address".
>> +	   Relocations want only the symbol offset.  */
>> +	reloc->addend = fixp->fx_addnumber + reloc->address;
>> 
>> A better comment is needed.  _Why_ do you just need fx_addnumber?
>> 
>
>   Thanks for the review!  The explanation is in another place as
> follows.
> Maybe we need to copy the comment to tc_gen_reloc from md_pcrel_from.
> Ex:
> long
> md_pcrel_from (fixS *fixP)
> {
>   valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
>   switch (fixP->fx_r_type)
>     {
>     /* We don't add addr, because it will cause the error checking of
>        "addnumber" fail in write.c for *7/10_PCREL_S1.
>         In tc_gen_reloc, we just use fixp->fx_addnumber.  */
>     case BFD_RELOC_MICROMIPS_7_PCREL_S1:
>     case BFD_RELOC_MICROMIPS_10_PCREL_S1:
>       /* Return the beginning of the delay slot from the current insn.
> */
>       return 2;
>
>     case BFD_RELOC_MICROMIPS_16_PCREL_S1:
>     case BFD_RELOC_MICROMIPS_JMP:
>     case BFD_RELOC_16_PCREL_S2:
>     case BFD_RELOC_MIPS_JMP:
>       /* Return the address of the delay slot.  */
>       return addr + 4;
> ...
>   The field of *7/10_PCREL_S1 is limited in the 16-bit instructions.
> If we add the "address", write.c will fail to check these two
> relocations due to overflow or something (I kind of forgot). From
> debugging, adding "address" is no use at all, because later "address" is
> subtracted.

Ah, thanks, that's a good explanation.  Yeah, at least a cross-reference
would be useful if we keep things as they are.  However...

...I think you mean this bit of write.c:

	  if (fixP->fx_size < sizeof (valueT) && 0)
	    {
	      valueT mask;

	      mask = 0;
	      mask--;		/* Set all bits to one.  */
	      mask <<= fixP->fx_size * 8 - (fixP->fx_signed ? 1 : 0);
	      if ((add_number & mask) != 0 && (add_number & mask) != mask)
		{
		  char buf[50], buf2[50];
		  sprint_value (buf, fragP->fr_address + fixP->fx_where);
		  if (add_number > 1000)
		    sprint_value (buf2, add_number);
		  else
		    sprintf (buf2, "%ld", (long) add_number);
		  as_bad_where (fixP->fx_file, fixP->fx_line,
				_("value of %s too large for field of %d bytes at %s"),
				buf2, fixP->fx_size, buf);
		} /* Generic error checking.  */
	    }

That check's bogus for these relocations anyway, since it doesn't take
the implied shift into account.  I think there's an argument to say
we should set fx_no_overflow for these relocations and leave the
overflow checking to bfd.  You'll still get a "relocation overflow"
error if the final in-place addend really is too big.

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS and MCU ASE instruction set support
  2010-05-18 18:19 [PATCH] MIPS: microMIPS and MCU ASE instruction set support Maciej W. Rozycki
  2010-05-23 21:38 ` Richard Sandiford
@ 2010-05-26 20:19 ` Richard Sandiford
  2010-05-27 21:39 ` Richard Sandiford
  2 siblings, 0 replies; 41+ messages in thread
From: Richard Sandiford @ 2010-05-26 20:19 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: binutils, Chao-ying Fu, Ilie Garbacea, Joseph Myers,
	Catherine Moore, Daniel Jacobowitz

Part 2 of the review.

This testcase:

	.set	micromips
	.fill	0x80
	b16	.-0x80

produces:

/tmp/foo.s: Assembler messages:
/tmp/foo.s:3: Error: unrecognized opcode `b16 .-0x80'

while:

	.set	micromips
	.fill	0x80
	b	.-0x80

successfully produces a 16-bit insn.

@@ -14813,6 +16230,8 @@ mips_elf_final_processing (void)
      file_ase_mt is true.  */
   if (file_ase_mips16)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_M16;
+  if (file_ase_micromips)
+    elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_MICROMIPS;
 #if 0 /* XXX FIXME */
   if (file_ase_mips3d)
     elf_elfheader (stdoutput)->e_flags |= ???;

Do you really only want this flag to be set if -mmicromips was passed
on the command line?  (Yes, the same concern applies to MIPS16 and MDMX.)

Lots of cases where a space is missing before "(".

Please be consistent about "str[n]cmp (...) == 0" vs '!str[n]cmp (...)':
use one or the other.  (IMO the first is clearer.)

micromips_ip obviously started life as a cut-&-paste of mips_ip, and it
would have been nice to factor some code out.  At least split out the
block beginning:

+	    case 'F':
+	    case 'L':
+	    case 'f':
+	    case 'l':
+	      {

which is identical between the two, and far too subtle to copy wholesale.
There may be other good opportunities too.

+	    case '(':
+	      /* Handle optional base register.
+		 Either the base register is omitted or
+		 we must have a left paren.  */
+	      /* This is dependent on the next operand specifier
+		 is a base register specification.  */
+	      gas_assert (args[1] == 'b'
+		      || (args[1] == 'm'
+			  && (args[2] == 'l' || args[2] == 'n'
+			      || args[2] == 's' || args[2] == 'a')));
+	      if (*s == '\0' && args[1] == 'b')
+		return;
+
+	    case ')':		/* these must match exactly */
+	    case '[':
+	    case ']':
+	      if (*s++ == *args)
+		continue;
+	      break;

Mark fallthrough.

+	    case 'D':		/* floating point destination register */
+	    case 'S':		/* floating point source register */
+	    case 'T':		/* floating point target register */
+	    case 'R':		/* floating point source register */
+	    case 'V':
+	      rtype = RTYPE_FPU;
+	      s_reset = s;
+	      if (reg_lookup (&s, rtype, &regno))
+		{
+		  if ((regno & 1) != 0
+		      && HAVE_32BIT_FPRS
+		      && ! mips_oddfpreg_ok (ip->insn_mo, argnum))
+		    as_warn (_("Float register should be even, was %d"),
+			     regno);
+
+		  c = *args;
+		  if (*s == ' ')
+		    ++s;
+		  if (args[1] != *s)
+		    {
+		      if (c == 'V' || c == 'W')
+			{
+			  regno = lastregno;
+			  s = s_reset;
+			  ++args;
+			}
+		    }
+		  switch (c)
+		    {
+		    case 'D':
+		      MICROMIPS_INSERT_OPERAND (FD, *ip, regno);
+		      break;
+		    case 'V':
+		    case 'S':
+		      MICROMIPS_INSERT_OPERAND (FS, *ip, regno);
+		      break;
+
+		    case 'T':
+		      MICROMIPS_INSERT_OPERAND (FT, *ip, regno);
+		      break;
+
+		    case 'R':
+		      MICROMIPS_INSERT_OPERAND (FR, *ip, regno);
+		      break;
+		    }
+		  lastregno = regno;
+		  continue;
+		}
+
+	      switch (*args++)
+		{
+		case 'V':
+		  MICROMIPS_INSERT_OPERAND (FS, *ip, lastregno);
+		  continue;
+		case 'W':
+		  MICROMIPS_INSERT_OPERAND (FT, *ip, lastregno);
+		  continue;
+		}
+	      break;

This block doesn't have a 'W' case (which doesn't seem to be used
for micromips at all), so all the 'W' handling is dead code.

+			    case  4:
+			    case  5:
+			    case  6:

Too many spaces.

+      if (insn + 1 < &micromips_opcodes[bfd_micromips_num_opcodes] &&
+	  !strcmp (insn->name, insn[1].name))

Misplaced "&&".

+    = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};;

Double ";".

+	  macro_read_relocs (&args, r);

Not portable in this context (and doesn't build on x86_64-linux-gnu).
You're taking the address of a va_list argument rather than a va_list
local variable.

+	  /*  For microMIPS, we always use relocations for branches.
+	      So, we should not resolve immediate values.  */

Too many spaces.

+	  if (ep->X_op == O_constant)
+	    abort ();
+	  else
+	    *r = BFD_RELOC_MICROMIPS_16_PCREL_S1;

gcc_assert (ep->X_op != O_constant);
*r = BFD_RELOC_MICROMIPS_16_PCREL_S1;

The same cut-&-paste concerns apply to micromips_macro, which obviously
started out as a copy of macro().  I realise there are special cases
for micromips (such as the DADDI assymmetry and the lack of
branch-likely instructions, to name only a few), but most of the
basic decisions are the same.

As it stands, we have a new 3524 line function, of which I imagine at
least 90% is shared with macro().  I really think the new microMIPS
macro handling should be integrated into macro() instead.  Don't be
afraid of factoring out code from macro() if it makes it easier to
integrate the microMIPS code.

 #define CPU_MIPS5       5
 #define CPU_MIPS64      64
 #define CPU_MIPS64R2	65
+#define CPU_MICROMIPS	96
 #define CPU_SB1         12310201        /* octal 'SB', 01.  */
 #define CPU_LOONGSON_2E 3001
 #define CPU_LOONGSON_2F 3002

What's this for?  It doesn't seem to be used.

+   "mA" 7-bit immediate (-63 .. 64) << 2 (MICROMIPSOP_*_IMMA)

Don't you mean (-64 .. 63)?

+   "mB" 3-bit immediate (0, -1, 1, 4, 8, 12, 16, 20, 24) (MICROMIPSOP_*_IMMB)

That's nine values.  Should the 0 really be there?

@@ -630,15 +630,15 @@ proc strip_executable { prog flags test 
 	remote_upload host ${copyfile} tmpdir/striprog
     }
 
-    set result [remote_load target tmpdir/striprog]
-    set status [lindex $result 0]
-    if { ![istarget $host_triplet] } {
-      set status "pass"
-    }
-    if { $status != "pass" } {
-	fail $test
-        return
-    }
+#    set result [remote_load target tmpdir/striprog]
+#    set status [lindex $result 0]
+#    if { ![istarget $host_triplet] } {
+#      set status "pass"
+#    }
+#    if { $status != "pass" } {
+#	fail $test
+#        return
+#    }
 
     set exec_output [binutils_run $NM "$NMFLAGS ${copyfile}"]
     if ![string match "*: no symbols*" $exec_output] {
@@ -673,15 +673,15 @@ proc strip_executable_with_saving_a_symb
 	remote_upload host ${copyfile} tmpdir/striprog
     }
 
-    set result [remote_load target tmpdir/striprog]
-    set status [lindex $result 0]
-    if { ![istarget $host_triplet] } {
-      set status "pass"
-    }
-    if { $status != "pass" } {
-	fail $test
-        return
-    }
+#    set result [remote_load target tmpdir/striprog]
+#    set status [lindex $result 0]
+#    if { ![istarget $host_triplet] } {
+#      set status "pass"
+#    }
+#    if { $status != "pass" } {
+#	fail $test
+#        return
+#    }
 
     set exec_output [binutils_run $NM "$NMFLAGS ${copyfile}"]
     if { [istarget mmix-knuth-mmixware] } {

Looks like these crept in unawares.

    PLT entries and traditional MIPS lazy binding stubs.  We mark the former
    with STO_MIPS_PLT to distinguish them from the latter.  */
 #define STO_MIPS_PLT		0x8
+#define ELF_ST_IS_MIPS_PLT(OTHER) (((OTHER) & 0x8) == STO_MIPS_PLT)
...
 #define STO_MIPS_PIC		0x20
 #define ELF_ST_IS_MIPS_PIC(OTHER) \
-  (((OTHER) & ~ELF_ST_VISIBILITY (-1)) == STO_MIPS_PIC)
+  (((OTHER) & ~ELF_ST_VISIBILITY (-1) & ~0xc0) == STO_MIPS_PIC)
 #define ELF_ST_SET_MIPS_PIC(OTHER) \
-  (STO_MIPS_PIC | ELF_ST_VISIBILITY (OTHER))
+  (STO_MIPS_PIC | ELF_ST_VISIBILITY (OTHER) | ELF_ST_MICROMIPS (OTHER))
...
     case STO_OPTIONAL:  return "OPTIONAL";
     case STO_MIPS16:    return "MIPS16";
-    case STO_MIPS_PLT:	return "MIPS PLT";
-    case STO_MIPS_PIC:	return "MIPS PIC";
-    default:      	return NULL;
+    default:
+	if (ELF_ST_IS_MIPS_PLT (other))
+	  {
+	    if (ELF_ST_IS_MICROMIPS (other))
+	      return "MICROMIPS, MIPS PLT";
+	    else
+	      return "MIPS PLT";
+	  }
+	if (ELF_ST_IS_MIPS_PIC (other))
+	  {
+	    if (ELF_ST_IS_MICROMIPS (other))
+	      return "MICROMIPS, MIPS PIC";
+	    else
+	      return "MIPS PIC";
+	  }
+	if (ELF_ST_IS_MICROMIPS (other))
+	  return "MICROMIPS";
+
+	return NULL;

You don't add support for microMIPS PLTs, so the "MICROMIPS, MIPS PLT"
thing appears to be dead code.  I wouldn't mind, except that it makes
the code inconsistent with MIPS16: the changes above allow both

  STO_MIPS16 | STO_MIPS_PLT

and

  STO_MICROMIPS | STO_MIPS_PLT

neither of which are currently used, but you don't treat the two equally.

In other words, I'm happy with the STO_MIPS_PIC changes but not with
the STO_MIPS_PLT ones.

+  /* 16 bit relocation.  */
+  HOWTO (R_MICROMIPS_16,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_lo16_reloc, /* special_function */
+	 "R_MICROMIPS_16",	/* name */
+	 TRUE,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */

Is this relocation really a lo16 one?  If so, it's not consistent
with R_MIPS_16 (which isn't).

+/*
+ *  Delay slot size and relaxation support
+ */
+static unsigned long
+relax_delay_slot (bfd *abfd, bfd_byte *ptr, unsigned long* opcode_32)
+{
+  unsigned long bdsize = 0;
+
+  unsigned long fndopc;
+  unsigned long p16opc, p32opc;
+
+  /* Opcodes preceding the current instruction.  */
+  p16opc  = bfd_get_16 (abfd, ptr - 2);
+  p32opc  = bfd_get_16 (abfd, ptr - 4) << 16;

You need to check the section bounds.  The code appears to read off the
beginning of a section if that section starts with a relaxable LUI.

+      /* If this isn't something that can be relaxed, then ignore
+	 this reloc.  */
+      if (ELF32_R_TYPE (irel->r_info) != (int) R_MICROMIPS_HI16 &&
+	  ELF32_R_TYPE (irel->r_info) != (int) R_MICROMIPS_LO16 &&
+	  ELF32_R_TYPE (irel->r_info) != (int) R_MICROMIPS_PC16_S1 &&
+	  ELF32_R_TYPE (irel->r_info) != (int) R_MICROMIPS_26_S1 &&
+	  ELF32_R_TYPE (irel->r_info) != (int) R_MICROMIPS_GPREL16)
+	continue;

&&s at the beginning of lines.

+      /* Get the value of the symbol referred to by the reloc.  */
+      if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
+	{
+	  /* A local symbol.  */
+	  Elf_Internal_Sym *isym;
+	  asection *sym_sec;
+
+	  isym = isymbuf + ELF32_R_SYM (irel->r_info);
+	  if (isym->st_shndx == SHN_UNDEF)
+	    sym_sec = bfd_und_section_ptr;
+	  else if (isym->st_shndx == SHN_ABS)
+	    sym_sec = bfd_abs_section_ptr;
+	  else if (isym->st_shndx == SHN_COMMON)
+	    sym_sec = bfd_com_section_ptr;
+	  else
+	    sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
+	  symval = (isym->st_value
+		    + sym_sec->output_section->vma
+		    + sym_sec->output_offset);
+	  target_is_micromips_code_p = ELF_ST_IS_MICROMIPS (isym->st_other);
+	}
+      else
+	{
+	  unsigned long indx;
+	  struct elf_link_hash_entry *h;
+
+	  /* An external symbol.  */
+	  indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
+	  h = elf_sym_hashes (abfd)[indx];
+	  BFD_ASSERT (h != NULL);
+
+	  if (h->root.type != bfd_link_hash_defined
+	      && h->root.type != bfd_link_hash_defweak)
+	    /* This appears to be a reference to an undefined
+	       symbol.  Just ignore it -- it will be caught by the
+	       regular reloc processing.  */
+	    continue;
+
+	  symval = (h->root.u.def.value
+		    + h->root.u.def.section->output_section->vma
+		    + h->root.u.def.section->output_offset);
+	}

Why not set target_is_micromips_code_p for locally-binding global
symbols too?

+      opcode  =   bfd_get_16 (abfd, contents + irel->r_offset    ) << 16;
+      opcode |= (irel->r_offset + 2 < sec->size
+		 ? bfd_get_16 (abfd, contents + irel->r_offset + 2) : 0);

Are there any relaxations we can actually do if irel->r_offset + 2
>= sec->size?  I couldn't see any.  If there aren't, continue instead.

+      /* R_MICROMIPS_HI16 / LUI relaxation to R_MICROMIPS_HI0_LO16 or
+         R_MICROMIPS_PC23_S2.  The R_MICROMIPS_PC23_S2 condition is
+
+           (symval % 4 == 0 && IS_BITSIZE (pcrval, X, 25))
+
+         where the X adjustment compensate for R_MICROMIPS_HI16 and
+         R_MICROMIPS_LO16 being at most X bytes appart when the
+         distance to the target approaches 32 MB.  */

Comment is slightly confusing: we don't relax the HI16 itself to a
H0_LO16 or PC32_S3.  Rather we relax the LO16 (or, if you like,
the HI16/LO16 pair).

+	  /* Assume is possible to delete the LUI instruction:
+	     4 bytes at irel->r_offset.  */

s/Assume is/Assume it is/

+      /* Compact branch relaxation -- due to the multitude of macros
+         employed by the compiler/assembler, compact branches are not
+         aways generated.  Obviously, this can/will be fixed elsewhere,
+         but there is no drawback in double checking it here.  */
+      else if (ELF32_R_TYPE (irel->r_info) == (int) R_MICROMIPS_PC16_S1
+	       && (fndopc = find_match (opcode, bz_insns_32)) != 0
+	       && MATCH (bfd_get_16 (abfd, contents + irel->r_offset + 4),
+			 nop_insn_16))

s/aways/always/.  You should check the section size before reading
past the relocation.  (I realise there ought to be a delay slot,
but we should be robust against brokenness.)

+      /* R_MICROMIPS_26_S1 -- JAL to JALS relaxation for microMIPS targets.  */
+      else if (ELF32_R_TYPE (irel->r_info) == (int) R_MICROMIPS_26_S1
+	       && target_is_micromips_code_p
+	       && MATCH (opcode, jal_insn_32_bd32))
+	{
+	  unsigned long n32opc;
+	  bfd_boolean relaxed = FALSE;
+
+	  n32opc  =
+	    bfd_get_16 (abfd, contents + irel->r_offset + 4    ) << 16;
+	  n32opc |= irel->r_offset + 2 < sec->size?
+	    bfd_get_16 (abfd, contents + irel->r_offset + 6): 0;
+

Here too you should check the size before reading n32opc.  Second
condition looks bogus (did you mean +6?) although the same concerns
apply as for the "+ 2" above.

I'll try to review more soon.

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS and MCU ASE instruction set support
  2010-05-18 18:19 [PATCH] MIPS: microMIPS and MCU ASE instruction set support Maciej W. Rozycki
  2010-05-23 21:38 ` Richard Sandiford
  2010-05-26 20:19 ` [PATCH] MIPS: microMIPS and MCU ASE instruction set support Richard Sandiford
@ 2010-05-27 21:39 ` Richard Sandiford
  2 siblings, 0 replies; 41+ messages in thread
From: Richard Sandiford @ 2010-05-27 21:39 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: binutils, Chao-ying Fu, Ilie Garbacea, Joseph Myers,
	Catherine Moore, Daniel Jacobowitz

Part 3 of 3.

the elf32-mips.c reloc questions in review 2 apply to elf64-mips.c
and elfn32-mips.c as well.  Furthermore:

+static reloc_howto_type micromips_elf64_howto_table_rela[] =
+{
+  /* 16 bit relocation.  */
+  HOWTO (R_MICROMIPS_16,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_lo16_reloc, /* special_function */
+	 "R_MICROMIPS_16",	/* name */
+	 TRUE,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */

RELA relocations shouldn't be partial_inplace.  Applies to the whole array.
Did you actually test this with n64, say with a gcc bootstrap?  Same
comment goes for elfn32-mips.c.

Why only do the linker relaxation for elf32-mips.c (o32, o64 & EABI)?
Why not for n32 and n64 too?

+#define LA25_LUI_MICROMIPS_1(VAL) (0x41b9)	/* lui t9,VAL */
+#define LA25_LUI_MICROMIPS_2(VAL) (VAL)
+#define LA25_J_MICROMIPS_1(VAL) (0xd400 | (((VAL) >> 17) & 0x3ff)) /* j VAL */
+#define LA25_J_MICROMIPS_2(VAL) (0xd4000000 | (((VAL) >> 1) & 0xffff))
+#define LA25_ADDIU_MICROMIPS_1(VAL) (0x3339)	/* addiu t9,t9,VAL */
+#define LA25_ADDIU_MICROMIPS_2(VAL) (VAL)

LA25_J_MICROMIPS_2 is a 16-bit opcode, so the "0xd4000000 | ..."
thing is bogus.  That said, why split these up?  bfd_{get,put}_32
don't require aligned addresses.

+  value = s->size;
+  if (ELF_ST_IS_MICROMIPS (stub->h->root.other))
+    value |= 1;
+
   /* Create a symbol for the stub.  */
-  mips_elf_create_stub_symbol (info, stub->h, ".pic.", s, s->size, 8);
+  mips_elf_create_stub_symbol (info, stub->h, ".pic.", s, value, 8);
 
Do this in mips_elf_create_stub_symbol rather than in each caller.

+  return r_type == R_MIPS_GOT16 || r_type == R_MIPS16_GOT16
+	 || r_type == R_MICROMIPS_GOT16;

GNU indentation requires brackets here.  Also, once it becomes too
long for one line, let's keep one item per line:

  return (r_type == R_MIPS_GOT16
	  || r_type == R_MIPS16_GOT16
	  || r_type == R_MICROMIPS_GOT16);

Same for later functions.

-  if (r_type == R_MIPS_TLS_GOTTPREL)
+  if (r_type == R_MIPS_TLS_GOTTPREL || r_type == R_MICROMIPS_TLS_GOTTPREL)

Hide these differences in analogues of the got16_reloc_p functions.
Same for all other relocs with MICROMIPS variants.

@@ -3187,8 +3244,12 @@ mips_elf_got_page (bfd *abfd, bfd *ibfd,
   struct mips_got_entry *entry;
 
   page = (value + 0x8000) & ~(bfd_vma) 0xffff;
-  entry = mips_elf_create_local_got_entry (abfd, info, ibfd, page, 0,
-					   NULL, R_MIPS_GOT_PAGE);
+  if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS)
+    entry = mips_elf_create_local_got_entry (abfd, info, ibfd, page, 0,
+					     NULL, R_MICROMIPS_GOT_PAGE);
+  else
+    entry = mips_elf_create_local_got_entry (abfd, info, ibfd, page, 0,
+					     NULL, R_MIPS_GOT_PAGE);
 
   if (!entry)
     return MINUS_ONE;

Why is this necessary?

@@ -5127,12 +5200,26 @@ mips_elf_calculate_relocation (bfd *abfd
 	      + h->la25_stub->stub_section->output_offset
 	      + h->la25_stub->offset);
 
+  /* Make sure MIPS16 and microMIPS are not used together.  */
+  if ((r_type == R_MIPS16_26 && target_is_micromips_code_p)
+      || (r_type == R_MICROMIPS_26_S1 && target_is_16_bit_code_p))
+   {
+      (*_bfd_error_handler)
+	(_("MIPS16 and microMIPS functions cannot call each other"));
+      return bfd_reloc_notsupported;
+   }

Should this be extended to check for branches too?

+    case R_MIPS_26:
+      /* Make sure the target of JALX is word-aligned.
+	 Bit 0 must be 1 (MIPS16/microMIPS mode), and bit 1 must be 0.  */
+      if (*cross_mode_jump_p == TRUE && (symbol & 3) != 1)
+	return bfd_reloc_outofrange;

== TRUE has been banned by act of parliament.

If we're checking alignment for R_MIPS_26 and R_MICROMIPS_26, we should
check it for R_MIPS16_26 too.  Something like:

      /* Make sure the target of JALX is word-aligned.
	 Bit 0 must be the correct ISA mode selector and bit 1 must be 0.  */
      if (*cross_mode_jump_p && (symbol & 3) != (r_type == R_MIPS_26))
	return bfd_reloc_outofrange;

for both cases would be fine.

+    case R_MICROMIPS_26_S1:
+      /* Make sure the target of jalx is word-aligned.  */
+      if (*cross_mode_jump_p == TRUE && (symbol & 3) != 0)
+	return bfd_reloc_outofrange;
+      if (local_p)
+	{
+	  /* For jalx, the offset is shifted right by two bits.  */
+	  if (*cross_mode_jump_p == TRUE)
+	    value = ((addend | ((p + 4) & 0xf0000000)) + symbol) >> 2;
+	  else
+	    value = ((addend | ((p + 4) & 0xf8000000)) + symbol) >> 1;
+	}
+      else
+	{
+	  /* For jalx, the offset is shifted right by two bits.  */
+	  if (*cross_mode_jump_p == TRUE)
+	    {
+	      value = (_bfd_mips_elf_sign_extend (addend, 28) + symbol) >> 2;
+	      if (h->root.root.type != bfd_link_hash_undefweak)
+		overflowed_p = (value >> 26) != ((p + 4) >> 28);
+	    }
+	  else
+	    {
+	      value = (_bfd_mips_elf_sign_extend (addend, 27) + symbol) >> 1;
+	      if (h->root.root.type != bfd_link_hash_undefweak)
+		overflowed_p = (value >> 26) != ((p + 4) >> 27);
+	    }
+	}
+      value &= howto->dst_mask;
+      break;

This is a strict extension of the R_MIPS_26 and R_MIPS16_26 behaviour,
so I'd prefer to see them integrated.

@@ -5372,6 +5516,9 @@ mips_elf_calculate_relocation (bfd *abfd
 	     both reloc addends by 4. */
 	  if (r_type == R_MIPS16_HI16)
 	    value = mips_elf_high (addend + gp - p - 4);
+	  else if (r_type == R_MICROMIPS_HI16)
+	    /* The low bit of $t9 is set for microMIPS calls.  */
+	    value = mips_elf_high (addend + gp - p - 1);
 	  else
 	    value = mips_elf_high (addend + gp - p);
 	  overflowed_p = mips_elf_overflow_p (value, 16);

This statement is also true for MIPS16, so in context, the comment
is a bit confusing on its own.  How about:

	    /* The microMIPS .cpload sequence uses the same assembly
	       instructions as the traditional psABI version, but the
	       incoming $t9 has the low bit set.  */

@@ -5486,8 +5647,38 @@ mips_elf_calculate_relocation (bfd *abfd
       value &= howto->dst_mask;
       break;
 
+    case R_MICROMIPS_PC7_S1:
+      value = symbol + _bfd_mips_elf_sign_extend (addend, 8) - p;
+      overflowed_p = mips_elf_overflow_p (value, 8);
+      value >>= howto->rightshift;
+      value &= howto->dst_mask;
+      break;
+
+    case R_MICROMIPS_PC10_S1:
+      value = symbol + _bfd_mips_elf_sign_extend (addend, 11) - p;
+      overflowed_p = mips_elf_overflow_p (value, 11);
+      value >>= howto->rightshift;
+      value &= howto->dst_mask;
+      break;
+
+    case R_MICROMIPS_PC16_S1:
+      value = symbol + _bfd_mips_elf_sign_extend (addend, 17) - p;
+      overflowed_p = mips_elf_overflow_p (value, 17);
+      value >>= howto->rightshift;
+      value &= howto->dst_mask;
+      break;
+
+    case R_MICROMIPS_PC23_S2:
+      value = symbol + _bfd_mips_elf_sign_extend (addend, 25) - (p & 0xfffffffc);
+      overflowed_p = mips_elf_overflow_p (value, 25);
+      value >>= howto->rightshift;
+      value &= howto->dst_mask;
+      break;

I realise you probably based this on R_MIPS_PC16 and R_MIPS_GNU_REL16_S2,
but even so, you're careful to check for underflow elsewhere but ignore
it here.  Use of 0xfffffffc isn't portable for 64-bit addresses;
use "-4" or "~(bfd_vma) 3" instead.

@@ -6150,13 +6355,18 @@ _bfd_mips_elf_symbol_processing (bfd *ab
       break;
     }
 
-  /* If this is an odd-valued function symbol, assume it's a MIPS16 one.  */
+  /* If this is an odd-valued function symbol, assume it's a MIPS16
+     or microMIPS one.  */
   if (ELF_ST_TYPE (elfsym->internal_elf_sym.st_info) == STT_FUNC
       && (asym->value & 1) != 0)
     {
       asym->value--;
-      elfsym->internal_elf_sym.st_other
-	= ELF_ST_SET_MIPS16 (elfsym->internal_elf_sym.st_other);
+      if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS)
+	elfsym->internal_elf_sym.st_other
+	  = ELF_ST_SET_MICROMIPS (elfsym->internal_elf_sym.st_other);
+      else
+	elfsym->internal_elf_sym.st_other
+	  = ELF_ST_SET_MIPS16 (elfsym->internal_elf_sym.st_other);
     }
 }
 \f

So a file can't mix MIPS16 and microMIPS code?  We should probably
detect that explicitly.  I'd like a clear statement of what the
interoperability restrictions are.

This goes back to the question of when EF_MIPS_ARCH_ASE_MICROMIPS
should be set (see previous reviews).

@@ -6865,7 +7075,8 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd
   /* If this is a mips16 text symbol, add 1 to the value to make it
      odd.  This will cause something like .word SYM to come up with
      the right value when it is loaded into the PC.  */
-  if (ELF_ST_IS_MIPS16 (sym->st_other))
+  if (ELF_ST_IS_MIPS16 (sym->st_other)
+      || ELF_ST_IS_MICROMIPS (sym->st_other))
     ++*valp;
 
   return TRUE;

As with GAS, I'd like an ODD_SYMBOL_P or some-such.

@@ -7166,6 +7378,8 @@ mips_elf_add_lo16_rel_addend (bfd *abfd,
   r_type = ELF_R_TYPE (abfd, rel->r_info);
   if (mips16_reloc_p (r_type))
     lo16_type = R_MIPS16_LO16;
+  else if (micromips_reloc_shuffle_p (r_type))
+    lo16_type = R_MICROMIPS_LO16;
   else
     lo16_type = R_MIPS_LO16;
 
Conceptually, this ought to be plain micromips_reloc_p.  Whether we need
to shuffle or not isn't an issue here, even though I realise the shuffle
condition produces the right result.

@@ -9215,6 +9479,12 @@ _bfd_mips_elf_relocate_section (bfd *out
 	case bfd_reloc_ok:
 	  break;
 
+	case bfd_reloc_outofrange:
+	  msg = _("internal error: jalx jumps to not word-aligned address");
+	  info->callbacks->warning
+	    (info, msg, name, input_bfd, input_section, rel->r_offset);
+	  return FALSE;
+
 	default:
 	  abort ();
 	  break;

Why's that an internal error?  Surely it could be triggered by
badly-formed input, rather than just as a result of internal
confusion?

The error is more specific than the error code, so you should also add:

      BFD_ASSERT (jal_reloc_p (howto->type));

@@ -976,7 +976,7 @@ bfd_install_relocation (bfd *abfd,
   asection *reloc_target_output_section;
   asymbol *symbol;
   bfd_byte *data;
-
+  
   symbol = *(reloc_entry->sym_ptr_ptr);
   if (bfd_is_abs_section (symbol->section))
     {

Bogus change.

@@ -1652,6 +1652,8 @@ ENUMX
 ENUMX
   BFD_RELOC_16
 ENUMX
+  BFD_RELOC_MICROMIPS_16
+ENUMX
   BFD_RELOC_14
 ENUMX
   BFD_RELOC_8

Here and elsewhere, keep the MIPS-specific stuff separate from the
generic relocs.  See the MIPS16 relocs for examples.

I'll take your word for it that micromips-opc.c is correct. ;-)

+  else if ((insn & 0x1c00) != 0x0400
+	   && (insn & 0x1c00) != 0x0800
+	   && (insn & 0x1c00) != 0x0c00)
+    {
+      /* This is a 32-bit microMIPS instruction.  */
+      higher = insn;
+
+      status = (*info->read_memory_func) (memaddr + 2, buffer, 2, info);
+      if (status != 0)
+	{
+	  (*info->fprintf_func) (info->stream, "micromips 0x%x",
+				 (unsigned int) higher);
+	  (*info->memory_error_func) (status, memaddr + 2, info);
+	  return -1;
+	}

Why print "micromips " here but not in the 48-byte case?  Also,
s/0x%02x/0x%x/ would be better IMO.

Watch your formatting in this function.  There are lots of cases of
things like:

		      (*info->fprintf_func) (info->stream, "%s",
			mips_gpr_names[lastregno]);

which isn't right.  Arguments must be aligned to the column after
the "(".  Don't be afraid to split lines into several statements
if it makes things look more natural.

The gas testsuite changes look very nice, thanks.

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS and MCU ASE instruction set support
  2010-05-23 21:38 ` Richard Sandiford
  2010-05-24 22:25   ` Fu, Chao-Ying
@ 2010-06-01 14:21   ` Maciej W. Rozycki
  2010-06-01 14:39     ` Catherine Moore
                       ` (3 more replies)
  2010-07-26 10:56   ` [PATCH] MIPS: microMIPS ASE support Maciej W. Rozycki
  2 siblings, 4 replies; 41+ messages in thread
From: Maciej W. Rozycki @ 2010-06-01 14:21 UTC (permalink / raw)
  To: Richard Sandiford
  Cc: binutils, Chao-ying Fu, Catherine Moore, Joseph S. Myers,
	Daniel Jacobowitz

[-- Attachment #1: Type: TEXT/PLAIN, Size: 51813 bytes --]

Hi Richard,

> Big patch, so this review is only for the gas and ld/testsuite bits.

 Thanks for the review, especially as I know it must have taken a lot of 
effort.  I hope we'll be able to sort out all issues gradually.

 I'm placing notes throughout and I'll be asking people for explanations 
where applicable.  Chao-ying, would you please look into the few pieces of 
code below I am a bit uncertain about?  Catherine, there's one question 
for you at the end as well.

> Generally looks good.  It would have been better to submit the
> ACE, m14kc and microMIPS support as three separate changes though.
> Please can you do that for the follow-up?

 I have done it now; the next version will comprise microMIPS ASE changes 
only (the MCU ASE adds to both the MIPS ISA and the microMIPS ASE, so it 
should be applied on top of the microMIPS change).

 Stricly speaking some changes, while related, can be split off too (e.g. 
some MIPS16 or testsuite changes), so I'll look into separating them too 
-- perhaps that'll make the thing rolling sooner.

> From a usability perspective, it's a shame that:
> 
> 	.set	micromips
> 	.ent	foo
> foo:
> 	b	1f
> 	nop
> 	.end	foo
> 	.ent	bar
> bar:
> 1:	nop
> 	.end	bar
> 
> disassembles as:
> 
> 00000000 <foo>:
>    0:   cfff            b       0 <foo>
>                         0: R_MICROMIPS_PC10_S1  .L11
>    2:   0c00            nop
>    4:   0c00            nop
> 
> 00000006 <bar>:
>    6:   0c00            nop
> 
> leaving the poor user with no idea what .L11 is.

 Indeed.  This is a general limitation of `objdump' it would seem.  This 
is no different to what you get with:

$ cat b.s
	.globl	baz
	.ent	foo
foo:
	b	baz
	nop
	.end	foo
	.ent	bar
baz:
bar:
1:	nop
	.end	bar
$ mips-sde-elf-objdump -dr b.o

b.o:     file format elf32-tradbigmips


Disassembly of section .text:

00000000 <foo>:
   0:	1000ffff 	b	0 <foo>
			0: R_MIPS_PC16	baz
   4:	00000000 	nop
   8:	00000000 	nop

0000000c <bar>:
   c:	00000000 	nop

I'd just recommend peeking at the symbol table (back to the first 
program):

$ mips-sde-elf-objdump -t b.o

b.o:     file format elf32-tradbigmips

SYMBOL TABLE:
00000000 l    d  .text	00000000 .text
00000000 l    d  .data	00000000 .data
00000000 l    d  .bss	00000000 .bss
00000000 l    d  .reginfo	00000000 .reginfo
00000000 l    d  .pdr	00000000 .pdr
00000000 l     F .text	00000006 0x80 foo
00000006 l     F .text	00000002 0x80 bar
00000006 l       .text	00000000 0x80 .L1\x021

Any other ideas, anyone?

> The following:
> 
> 	.set	micromips
> 	.ent	foo
> foo:
> 	ld	$10,0x1000($11)
> 	.end	foo
> 
> generates an assertion failure:
> 
> Assertion failure in micromips_macro_build at gas/config/tc-mips.c line 19466.
> Please report this bug.
> 
> on mipsisa64-elf with "-mips1 -mabi=32".

 I can't reproduce it, sorry:

$ cat ld.s
	.set	micromips
	.ent	foo
foo:
	ld	$10,0x1000($11)
	.end	foo
$ mipsisa64-elf-as -mips1 -mabi=32 -o ld.o ld.s
$ mipsisa64-elf-objdump -d ld.o

ld.o:     file format elf32-bigmips


Disassembly of section .text:

00000000 <foo>:
   0:	fd4b 1000 	lw	t2,4096(t3)
   4:	fd6b 1004 	lw	t3,4100(t3)

The assertion you're referring to is this piece of code from 
micromips_macro_build():

	case 'i':
	case 'j':
	case 'o':
	  macro_read_relocs (&args, r);
	  gas_assert (*r == BFD_RELOC_MICROMIPS_GPREL16
		  || *r == BFD_RELOC_MICROMIPS_LITERAL
		  || *r == BFD_RELOC_MICROMIPS_HIGHER
		  || *r == BFD_RELOC_MICROMIPS_HI16_S
		  || *r == BFD_RELOC_MICROMIPS_LO16
		  || *r == BFD_RELOC_MICROMIPS_GOT16
		  || *r == BFD_RELOC_MICROMIPS_CALL16
		  || *r == BFD_RELOC_MICROMIPS_GOT_DISP
		  || *r == BFD_RELOC_MICROMIPS_GOT_PAGE
		  || *r == BFD_RELOC_MICROMIPS_GOT_OFST
		  || *r == BFD_RELOC_MICROMIPS_GOT_LO16
		  || *r == BFD_RELOC_MICROMIPS_CALL_LO16);
	  continue;

(indentation is wrong after s/assert/gas_assert/ it would seem, I have 
fixed it up; this has to be done in upstream HEAD in a couple of places 
too).

 Can you debug it and see what the relocation type is that's causing it?  
I wonder if that might be related to the varargs issue you referring to 
below and depend on the host architecture, hmm...

> > gas/
> > 2010-05-18  Chao-ying Fu  <fu@mips.com>
> >             Maciej W. Rozycki  <macro@codesourcery.com>
> >             Daniel Jacobowitz  <dan@codesourcery.com>
> >
> > 	* config/tc-mips.h (mips_segment_info): Add one bit for
> > 	microMIPS.
> > 	* config/tc-mips.c
> 
> How about having something like:
> 
>   #define OOD_TEXT_LABELS (mips_opts.mips16 || mips_opts.micromips)
> 
> ?

 It sounds reasonable to me, except that condition is used in some other 
contexts as well.  I have made it HAVE_CODE_COMPRESSION thus and took the 
opportunity to optimise code around mips16_micromips_mark_labels() too.  
Finally I have renamed the function to mips_compressed_mark_labels() for 
as the other sounds too complicated to me.

> > 	(A_BFD_RELOC_HI16_S, A_BFD_RELOC_HI16, A_BFD_RELOC_LO16): New
> > 	relocation wrapper macros.
> > 	(A_BFD_RELOC_GPREL16): Likewise.
> > 	(A_BFD_RELOC_MIPS_GOT16, A_BFD_RELOC_MIPS_GOT_HI16): Likewise.
> > 	(A_BFD_RELOC_MIPS_GOT_LO16, A_BFD_RELOC_MIPS_HIGHEST): Likewise.
> > 	(A_BFD_RELOC_MIPS_HIGHER, A_BFD_RELOC_MIPS_GOT_DISP): Likewise.
> > 	(A_BFD_RELOC_MIPS_GOT_PAGE, A_BFD_RELOC_MIPS_GOT_OFST): Likewise.
> > 	(A_BFD_RELOC_MIPS_SUB, A_BFD_RELOC_MIPS_JALR): Likewise.
> 
> Did you consider doing the translation from non-microMIPS to
> microMIPS in the macro_* functions, rather than in their callers?
> I fear it'll be too easy to accidentally forget to use A_BFD_* in future.

 Agreed, I didn't like the new macros from the very beginning.  Chao-ying 
-- any thoughts?

> > 	(mips_macro_warning): Add delay_slot_16bit_p, delay_slot_32bit_p,
> > 	and num_insns.
> > 	(micromips_16, micromips_32): New variables.
> > 	(is_micromips_16bit_p, is_micromips_32bit_p): New functions.
> > 	(insn_length): Return the length of microMIPS instructions.
> > 	(mips_record_mips16_mode): Rename to...
> > 	(mips_record_mips16_micromips_mode): ... this.  Handle microMIPS.
> > 	(install_insn): Handle microMIPS.
> > 	(is_opcode_valid): Likewise.
> > 	(md_begin): Likewise.
> 
> +	      if (micromips_nop16_insn.insn_mo == NULL
> +		  && strcmp (name, "nop") == 0)
> +		{
> +		  create_insn (&micromips_nop16_insn, micromips_opcodes + i);
> +		  micromips_nop16_insn.fixed_p = 1;
> +		}
> +	      else if (micromips_nop32_insn.insn_mo == NULL
> +		  && strcmp (name, "nop") == 0)
> +		{
> +		  create_insn (&micromips_nop32_insn, micromips_opcodes + i);
> +		  micromips_nop32_insn.fixed_p = 1;
> +		}
> 
> You seem to rely on the 16-bit nop being first.  Wouldn't it be more
> robust to call is_micromips_16bit_p and is_micromips_32bit_p?

 Agreed.  I rewrote this piece entirely.

> > 	(MICROMIPS_TARGET, MICROMIPS_TARGET_LABEL): New macros.
> > 	(micromips_add_number_label): New function.
> 
> +/* For microMIPS macros, we need to generate a local number label
> +   as the target of branches.  */
> +#define MICROMIPS_TARGET	"2147483647f"
> +#define MICROMIPS_TARGET_LABEL	2147483647
> +
> +static void
> +micromips_add_number_label (void)
> +{
> +  symbolS *s;
> +  fb_label_instance_inc (MICROMIPS_TARGET_LABEL);
> +  s = colon (fb_label_name (MICROMIPS_TARGET_LABEL, 0));
> +  S_SET_OTHER (s, ELF_ST_SET_MICROMIPS (S_GET_OTHER (s)));
> +}
> +
> 
> Ugh, this is a bit hackish.  There's nothing stopping a user using
> 2147483647f themselves.

 A local symbol with some magic characters would be better indeed.  I'll 
see if any existing approach could be reused.

> > 	(append_insn): Handle microMIPS.
> 
> +  if (mips_opts.micromips)
> +    {
> +      if ((prev_pinfo2 & INSN2_BRANCH_DELAY_16BIT)
> +	  && !is_micromips_16bit_p (ip->insn_mo))
> +	as_warn (_("instruction with wrong size in a branch delay slot that"
> +		   " requires a 16-bit instruction"));
> +      if ((prev_pinfo2 & INSN2_BRANCH_DELAY_32BIT)
> +	  && !is_micromips_32bit_p (ip->insn_mo))
> +	as_warn (_("instruction with wrong size in a branch delay slot that"
> +		   " requires a 32-bit instruction"));
> +    }
> +  
> 
> Although not enforced as often as it should be, GAS convention is for
> errors to start with a capital letter.

 I'll be fixing these up as I come across them.  If to be effective, then 
upstream HEAD should be fixed up or otherwise people have no way not to 
get confused.  I didn't know of this rule for one.  That shouldn't be a 
lot effort, should it?

 Some have to stay for now actually, because .l testsuite patterns are 
commonly shared between standard MIPS and microMIPS tests, and should be 
fixed separately.

> +      if (pinfo & INSN_COP)
> +	{
> +	  /* We don't keep enough information to sort these cases out.
> +	     The itbl support does keep this information however, although
> +	     we currently don't support itbl fprmats as part of the cop
> +	     instruction.  May want to add this support in the future.  */
> +	}
> 
> Assert?

 Well, that's no different to the standard MIPS variant.

> +	      /* For microMIPS, disable reordering.  */
> +	      || (mips_opts.micromips)
> 
> Redundant (...)

 Fixed.

> -	      if (mips_relax.sequence)
> -		mips_relax.sizes[mips_relax.sequence - 1] += 4;
> +	      /* MicroMIPS nop is 2 bytes.  */
> +  	      if (mips_relax.sequence)
> +		mips_relax.sizes[mips_relax.sequence - 1] +=
> +		  mips_opts.micromips ? micromips_nop_size : 4;
> 
> Confusing comment: the microMIPS nop may be 2 or 4 bytes.
> Better to say nothing IMO.

 Fixed.

> > 	(start_noreorder, end_noreorder): Likewise.
> 
> +	      frag_grow ((mips_opts.mips16 | mips_opts.micromips) ? nops * 2
> +								  : nops * 4);
> 
> How about a NOP_INSN_SIZE macro?  (Or similar.)

 Added.  And found the third place where needed while making the 
replacement.

> > 	(macro_start, macro_warning, macro_end): Likewise.
> 
> +  else if ((subtype & RELAX_DELAY_SLOT_SIZE_ERROR_FIRST)
> +	   || (subtype & RELAX_DELAY_SLOT_SIZE_ERROR_SECOND))
> +    return _("Macro instruction of the wrong size in a branch delay slot"
> +	     " that requires a 16-bit or 32-bit instruction");
> 
> Did you consider adding a flag to distinguish the 32-bit and 16-bit cases?
> It'd be nice to be consistent with the non-relaxed error if possible.

 Chao-ying?  I've had a look actually and flag may not be necessary to get 
the functionality.  I'm fixing this up elsewhere already.

> +  /* If either one implementation contains one instruction, we need to check
> +     the delay slot size requirement.  */
> 
> "If either implementation"

 Fixed.

> +  /* If either one implementation contains one instruction, we need to check
> +     the delay slot size requirement.  */
> +  if (mips_macro_warning.num_insns[0] == 1
> +      || mips_macro_warning.num_insns[1] == 1)
> +    {
> +      if (mips_macro_warning.num_insns[0] == mips_macro_warning.num_insns[1]
> +	  && mips_macro_warning.sizes[0] == mips_macro_warning.sizes[1])
> +	{
> +	  /* Either the macro has a single implementation or both
> +	     implementations are 1 instruction with the same size.
> +	     Emit the warning now.  */
> +	  if ((mips_macro_warning.delay_slot_16bit_p
> +	       && mips_macro_warning.sizes[0] != 2)
> +	      || (mips_macro_warning.delay_slot_32bit_p
> +		  && mips_macro_warning.sizes[0] != 4))
> +	    {
> +	      const char *msg;
> +	      msg = macro_warning (RELAX_DELAY_SLOT_SIZE_ERROR_FIRST);
> +	      if (msg != 0)
> +		as_warn (msg);
> +	    }
> +	}
> +      else
> +	{
> +	  relax_substateT subtype;
> +
> +	  /* Set up the relaxation warning flags.  */
> +	  subtype = 0;
> +	  if (mips_macro_warning.delay_slot_16bit_p)
> +	    {
> +	      if (mips_macro_warning.num_insns[0] != 1
> +		  || mips_macro_warning.sizes[0] != 2)
> +		subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
> +	      if (mips_macro_warning.num_insns[1] != 1
> +		  || mips_macro_warning.sizes[1] != 2)
> +		subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
> +	    }
> +	  if (mips_macro_warning.delay_slot_32bit_p)
> +	    {
> +	      if (mips_macro_warning.num_insns[0] != 1
> +		  || mips_macro_warning.sizes[0] != 4)
> +		subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
> +	      if (mips_macro_warning.num_insns[1] != 1
> +		  || mips_macro_warning.sizes[1] != 4)
> +		subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
> +	    }
> +
> +	  /* One implementation might need a warning but the other
> +	     definitely doesn't.  */
> +	  mips_macro_warning.first_frag->fr_subtype |= subtype;
> +	}
> +    }
> 
> Why not work out the subtype, then check whether both ERROR_FIRST and
> ERROR_SECOND are set?

 Chao-ying?

> +	  if (mips_macro_warning.delay_slot_p)
> +	    {
> +	      if (mips_macro_warning.num_insns[0] > 1)
> +		subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
> +	      if (mips_macro_warning.num_insns[1] > 1)
> +		subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
> +	    }
> 
> I don't get why this hunk is needed.  I thought ERROR_FIRST and ERROR_SECOND
> controlled cases where a macro has a single-insn expansion that is the
> wrong size, which ought to be handled by the block above.  If the code
> really is needed, you should add a comment explaining why.

 Chao-ying?

> > 	(macro_build): Likewise.
> 
> +  if (mips_opts.micromips)
> +    {
> +      if (strcmp (name, "lui") == 0)
> +	micromips_macro_build (ep, name, "s,u", args);
> +      else if (strcmp (fmt, "d,w,<") == 0)
> +	micromips_macro_build (ep, name, "t,r,<", args);
> +      else
> +	micromips_macro_build (ep, name, fmt, args);
> +      va_end (args);
> +      return;
> +    }
> 
> A bit of commentary might help explain the letter switch here.

 Chao-ying?

> > 	(macro_build_jalr): Likewise.
> 
> +  if (mips_opts.micromips)
> +    {
> +      if (HAVE_NEWABI)
> +	macro_build (NULL, "jalr", "t,s", RA, PIC_CALL_REG);
> +      else
> +	macro_build (NULL, "jalr", "mj", PIC_CALL_REG);
> +    }
> +  else
> +    macro_build (NULL, "jalr", "d,s", RA, PIC_CALL_REG);
> 
> Why HAVE_NEWABI?  Do you want a 32-bit insn for R_MIPS_JALR?

 Chao-ying?

> If so, you should check MIPS_JALR_HINT_P (ep) instead.

 I may have missed that while updating the change for the recent JALR hint 
support, let me see...

> -	      macro_build (&tmp, "ori", "t,r,i", reg, 0, BFD_RELOC_LO16);
> +	      macro_build (&tmp, "ori", "t,r,i", reg, 0, A_BFD_RELOC_LO16);
>  	      macro_build (NULL, (shift >= 32) ? "dsll32" : "dsll", "d,w,<",
> -			   reg, reg, (shift >= 32) ? shift - 32 : shift);
> +				  reg, reg, (shift >= 32) ? shift - 32 : shift);
> 
> Last change looks bogus.

 Fixed.

> -  gas_assert (fixP->fx_size == 4
> +  gas_assert (fixP->fx_size == 2
> +	  || fixP->fx_size == 4
>  	  || fixP->fx_r_type == BFD_RELOC_16
> +	  || fixP->fx_r_type == BFD_RELOC_MICROMIPS_16
>  	  || fixP->fx_r_type == BFD_RELOC_64
>  	  || fixP->fx_r_type == BFD_RELOC_CTOR
>  	  || fixP->fx_r_type == BFD_RELOC_MIPS_SUB
> +	  || fixP->fx_r_type == BFD_RELOC_MICROMIPS_SUB
>  	  || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
>  	  || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
>  	  || fixP->fx_r_type == BFD_RELOC_MIPS_TLS_DTPREL64);
>  
> +
>    buf = (bfd_byte *) (fixP->fx_frag->fr_literal + fixP->fx_where);
> 
> Last change is bogus.

 Fixed.

> +    case BFD_RELOC_MICROMIPS_7_PCREL_S1:
> +    case BFD_RELOC_MICROMIPS_10_PCREL_S1:
> +    case BFD_RELOC_MICROMIPS_16_PCREL_S1:
> +      /* We adjust the offset back to even.  */
> +      if ((*valP & 0x1) != 0)
> +	--(*valP);
> +
> +      if (! fixP->fx_done)
> +	break;
> +
> +      /* Should never visit here, because we keep the relocation.  */
> +      abort ();
> +      break;
> 
> I suppose this silently ignores branches to non-microMIPS code,
> but there again, so does the MIPS16 equivalent...

 Neither can work, so some diagnostics would be useful.

> > 	(mips_relax_frag): Handle microMIPS.
> 
> +     gas_assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2
> +	      || 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);
> +
> +      /* For 7/10 PCREL_S1, we just need to use fixp->fx_addnumber.  */
> +      if (fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
> +	  || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1)
> +	reloc->addend = fixp->fx_addnumber;
> +      else
> +	/* At this point, fx_addnumber is "symbol offset - pcrel address".
> +	   Relocations want only the symbol offset.  */
> +	reloc->addend = fixp->fx_addnumber + reloc->address;
> 
> A better comment is needed.  _Why_ do you just need fx_addnumber?

 Thanks, Chao-ying and Richard, for the feedback on this -- I'll see if I 
can make something up from it.

> > 	(md_convert_frag): Likewise.
> 
> -      /* Possibly emit a warning if we've chosen the longer option.  */
> -      if (((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
> -	  == ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))
> +      if (!(fragp->fr_subtype & RELAX_USE_SECOND))
> +  	{
> +	  /* Check if the size in branch delay slot is ok.  */
> +	  if (fragp->fr_subtype & RELAX_DELAY_SLOT_SIZE_ERROR_FIRST)
> +	    {
> +	      const char *msg = macro_warning (fragp->fr_subtype);
> +	      if (msg != 0)
> +		as_warn_where (fragp->fr_file, fragp->fr_line, msg);
> +	    }
> +	}
> +      else
>  	{
> -	  const char *msg = macro_warning (fragp->fr_subtype);
> -	  if (msg != 0)
> -	    as_warn_where (fragp->fr_file, fragp->fr_line, "%s", msg);
> +	  /* Check if the size in branch delay slot is ok.
> +	     Possibly emit a warning if we've chosen the longer option.  */
> +	  if ((fragp->fr_subtype & RELAX_DELAY_SLOT_SIZE_ERROR_SECOND)
> +	      || (fragp->fr_subtype & RELAX_SECOND_LONGER))
> +	    {
> +	      const char *msg = macro_warning (fragp->fr_subtype);
> +	      if (msg != 0)
> +		as_warn_where (fragp->fr_file, fragp->fr_line, msg);
> +	    }
>  	}
> 
> This doesn't accurately preserve the previous:
> 
>       if (((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
> 	  == ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))
> 
> behaviour.

 Chao-ying?

> > 	(mips_handle_align): Likewise.
> 
>        /* If we're not inserting a whole number of instructions,
> -	 pad the end of the fixed part of the frag with zeros.  */
> -      memset (p, 0, excess);
> +         pad the end of the fixed part of the frag with zeros.
> +         But try to fit a short microMIPS nop too if applicable.  */
> +      if (excess < 2 || *p != 2)
> +	memset (p, 0, excess);
> +      else
> +	{
> +	  memset (p, 0, excess - 2);
> +	  md_number_to_chars (p + excess - 2,
> +			      micromips_nop16_insn.insn_opcode, 2);
> +	}
> 
> Not how it'd be written from scratch; the comment makes microMIPS sound
> like an afterthought.  Please handle the microMIPS case first and make
> the comment treat it as a first-class citizen.

 It was an afterthought indeed. :)  I noticed this piece of code was 
horrible just before submission while resolving a conflict with the recent 
Loongson 2F erratum workaround.  Now the result assembled is better, but I 
think you're right this is not my best artwork. ;)

 Calling memset() for a variable count (i.e. one that cannot be inlined) 
that is at most three bytes seems an overkill to me; I have rewritten it 
now with a switch() statement.

> > 	(micromips_ip): New function.
> 
> +      /* Try to search "16" or "32" in the str.  */
> +      if ((t = strstr (str, "16")) != NULL && t < save_s)
> +	{
> +	  /* Make sure "16" is before the first '.' if '.' exists.  */
> +	  if ((s = strchr (str, '.')) != NULL && (t + 2 != s))
> +	    {
> +	      insn_error = "unrecognized opcode";
> +	      return;
> +	    }
> +
> +	  /* Make sure "16" is at the end of insn name, if no '.'.  */
> +	  if ((s = strchr (str, '.')) == NULL
> +	      && (!ISSPACE (*(t + 2)) && *(t + 2) != '\0'))
> +	    {
> +	      insn_error = "unrecognized opcode";
> +	      return;
> +	    }
> +
> +	  micromips_16 = TRUE;
> +	  for (s = t + 2; *s != '\0'; ++s)
> +	    *(s - 2) = *s;
> +	  *(s - 2) = '\0';
> +
> +	  for (s = t; *s != '\0' && !ISSPACE (*s); ++s)
> +	    continue;
> +
> +	  if (ISSPACE (*s))
> +	    {
> +	      save_c = *s;
> +	      *s++ = '\0';
> +	    }
> +
> +	  if ((insn = (struct mips_opcode *) hash_find (micromips_op_hash, str))
> +	      == NULL)
> +	    {
> +	      int i;
> +	      int length;
> +	      micromips_16 = FALSE;
> +
> +	      /* Restore the character we overwrite above (if any).  */
> +	      if (save_c)
> +		*(--s) = save_c;
> +
> +	      length = strlen (str);
> +	      for (i = length - 1; &str[i] >= t; i--)
> +		{
> +		  str[i + 2] = str[i];
> +		  if (t == &str[i])
> +		    {
> +		      str[i + 1] = '6';
> +		      str[i] = '1';
> +		      str[length + 2] = '\0';
> +		      break;
> +		    }
> +		}
> +
> +	      insn_error = "unrecognized 16-bit version of microMIPS opcode";
> +	      return;
> +	    }
> +	}
> +      else if ((t = strstr (str, "32")) != NULL && t < save_s)
> +	{
> +	  /* For some instruction names, we already have 32, so we need
> +	     to seek the second 32 to process.  Ex: bposge3232, dsra3232.  */
> +	  char *new_t;
> +	  if ((new_t = strstr (t + 2, "32")) != NULL && new_t < save_s)
> +	    t = new_t;
> +
> +	  /* Make sure "32" is before the first '.' if '.' exists.  */
> +	  if ((s = strchr (str, '.')) != NULL && (t + 2 != s))
> +	    {
> +	      insn_error = "unrecognized opcode";
> +	      return;
> +	    }
> +
> +	  /* Make sure "32" is at the end of the name, if no '.'.  */
> +	  if ((s = strchr (str, '.')) == NULL
> +	      && (!ISSPACE (*(t + 2)) && *(t + 2) != '\0'))
> +	    {
> +	      insn_error = "unrecognized opcode";
> +	      return;
> +	    }
> +
> +	  micromips_32 = TRUE;
> +	  for (s = t + 2; *s != '\0'; ++s)
> +	    *(s - 2) = *s;
> +	  *(s - 2) = '\0';
> +
> +	  for (s = t; *s != '\0' && !ISSPACE (*s); ++s)
> +	    continue;
> +
> +	  if (ISSPACE (*s))
> +	    {
> +	      save_c = *s;
> +	      *s++ = '\0';
> +	    }
> +
> +	  if ((insn = (struct mips_opcode *) hash_find (micromips_op_hash, str))
> +	      == NULL)
> +	    {
> +	      int i;
> +	      int length;
> +	      micromips_32 = FALSE;
> +
> +	      /* Restore the character we overwrite above (if any).  */
> +	      if (save_c)
> +		*(--s) = save_c;
> +
> +	      length = strlen (str);
> +	      for (i = length - 1; &str[i] >= t; i--)
> +		{
> +		  str[i + 2] = str[i];
> +		  if (t == &str[i])
> +		    {
> +		      str[i + 1] = '2';
> +		      str[i] = '3';
> +		      str[length + 2] = '\0';
> +		      break;
> +		    }
> +		}
> +
> +	      insn_error = "unrecognized 32-bit version of microMIPS opcode";
> +	      return;
> +	    }
> 
> Far too much cut-&-paste between the "16" and "32" cases.  Also:
> 
> +      if ((t = strstr (str, "16")) != NULL && t < save_s)
> 
> t < save_s must surely be true, since save_s is the null terminator.
> 
> +	  /* Make sure "16" is before the first '.' if '.' exists.  */
> +	  if ((s = strchr (str, '.')) != NULL && (t + 2 != s))
> +	    {
> +	      insn_error = "unrecognized opcode";
> +	      return;
> +	    }
> +
> +	  /* Make sure "16" is at the end of insn name, if no '.'.  */
> +	  if ((s = strchr (str, '.')) == NULL
> +	      && (!ISSPACE (*(t + 2)) && *(t + 2) != '\0'))
> +	    {
> +	      insn_error = "unrecognized opcode";
> +	      return;
> +	    }
> 
> Don't call strchr (str, '.') twice like that.  Better would be:
> 
> 	s = strchr (str, '.');
> 
> followed by the two checks.  Isn't the ISSPACE check redundant though,
> given that you've terminated the string at the first space?  I would
> have thought:
> 
>         if (t + 2 != (s ? s : save_s))
> 
> would be enough.  Errors should start with a capital letter.  Missing
> internationalisation.

 Chao-ying?

> You could use alloca to create an opcode without the "16" or "32",
> which would make the error-reporting code simpler.  It's best not
> to change the user's source line if we can help it.

 Agreed.

> +	      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;
> +		}
> +	      if (save_c)
> +		*(--s) = save_c;
> +
> +	      if (micromips_16 || micromips_32)
> +		{
> +		  int i;
> +		  int length;
> +
> +		  length = strlen (str);
> +		  for (i = length - 1; i >= 0; i--)
> +		    {
> +		      str[i + 2] = str[i];
> +		      if (t == &str[i])
> +			break;
> +		    }
> +		  if (micromips_16)
> +		    {
> +		      insn_error =
> +			"unrecognized 16-bit version of microMIPS opcode";
> +		      str[i + 1] = '6';
> +		      str[i] = '1';
> +		    }
> +		  else
> +		    {
> +		      insn_error =
> +			"unrecognized 32-bit version of microMIPS opcode";
> +		      str[i + 1] = '2';
> +		      str[i] = '3';
> +		    }
> +		  str[length + 2] = '\0';
> +		}
> +	      return;
> 
> Why override the insn_error unconditionally like this?  E.g.:
> 
> 	jar16	$30,$26
> 
>     Error: unrecognized 16-bit version of microMIPS opcode `jar16 $30,$26'
> 
> implies there's a 32-bit opcode.  I'd also have thought that the
> "opcode not supported on this processor" would triumph if it applies.

 The error you've seen comes from the previous hunk above rather than this 
one which I think is unnecessary code duplication.  It's all rather 
over-complicated and I'm working on getting it polished.  I've fixed this 
piece of code:

	.set	micromips
	.set	noreorder
	bltzall	$2, bar
	 addiusp 256

producing this nonsense:

bltzall.s: Assembler messages:
bltzall.s:4: Error: opcode not supported on this processor: mips1 (mips1) `addiusp 256'

too.  Also the original loop seems ill-formed to me, with most of code 
intended to be executed at most once, after the loop's terminating 
condition triggered -- i.e. that shouldn't be in the loop in the first 
place.

> +do_lsb:
> 
> Not properly indented.  A few other instances.

 Like the respective originals in mips_ip().  I have fixed up the new 
labels, but upstream HEAD code should be adjusted the same way.

> +			}
> +		    }
> +	/* Now that we have assembled one operand, we use the args string
> +	 * to figure out where it goes in the instruction.  */
> +		  switch (c)
> +		    {
> 
> Bogus indentation.

 Fixed.

> > 	(micromips_macro_build): Likewise.
> > 	(micromips_macro): Likewise.
> 
> I'll look at micromips_ip and these two in more detail later.

 Me too. ;)

> > 	* ld-mips-elf/jalx-2-main.s: New.
> > 	* ld-mips-elf/jalx-2.dd: New.
> > 	* ld-mips-elf/jalx-2-ex.s: New.
> > 	* ld-mips-elf/jalx-2-printf.s: New.
> > 	* ld-mips-elf/mips-elf.exp: Run new test.
> 
> Please make the .dd output less susceptible to things like the number
> of sections, size of program headers, etc.  One way is to use a linker
> script to place each section at a nice round address.  Another is to
> ".*" out the addresses and instruction encodings and just reply on
> the symbolic part of the disassembly.  I think the former's better
> here.  There are quite a few existing examples.

 Catherine, I reckon you were working on these?

 I'll look into whatever's left yet.  Here's the current version for a 
reference, in case you or anyone else wanted to comment on what I have 
modified so far (no obligation, of course!).

  Maciej

bfd/
2010-06-01  Chao-ying Fu  <fu@mips.com>
            Ilie Garbacea  <ilie@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>
            Joseph Myers  <joseph@codesourcery.com>
            Catherine Moore  <clm@codesourcery.com>

	* archures.c (bfd_mach_mips_micromips): New macro.
	* cpu-mips.c (I_micromips): New enum value.
	(arch_info_struct): Add bfd_mach_mips_micromips.
	* elf32-mips.c (elf_micromips_howto_table_rel): New variable.
	(_bfd_mips_elf32_gprel16_reloc): Handle microMIPS.
	(mips_elf_gprel32_reloc): Update comment.
	(micromips_reloc_map): New variable.
	(bfd_elf32_bfd_reloc_type_lookup): Handle microMIPS.
	(mips_elf32_rtype_to_howto): Likewise.
	(mips_info_to_howto_rel): Likewise.
	(elf32_mips_relax_delete_bytes): New function.
	(opcode_descriptor): New structure.
	(b_insns_32, b_insn_16): New variables.
	(BZ32_REG, BZ32_REG_FIELD): New macros.
	(bz_insns_32, bzc_insns_32, bz_insns_16): New variables.
	(BZ16_VALID_REG, BZ16_REG_FIELD): New macros.
	(jal_insn_32_bd16, jal_insn_32_bd32): New variables.
	(jalr_insn_32_bd16, jalr_insn_32_bd32): Likewise.
	(ds_insns_32_bd16, ds_insns_32_bd32): Likewise.
	(jalr_insn_16_bd16, jalr_insn_16_bd32): Likewise.
	(ds_insns_16_bd16): Likewise.
	(lui_insn, addiu_insn, addiupc_insn): Likewise.
	(ADDIU_REG, ADDIUPC_VALID_REG, ADDIUPC_REG_FIELD): New macros.
	(lwgp_insn_32, lwgp_insn_16): New functions.
	(LWGP32_REG, LWGP16_VALID_REG, LWGP16_REG_FIELD): New macros.
	(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.
	(relax_delay_slot): Likewise.
	(IS_BITSIZE): New macro.
	(elf32_mips_relax_section): New function.
	(bfd_elf32_bfd_relax_section): Define.
	* elf64-mips.c (micromips_elf64_howto_table_rel): New variable.
	(micromips_elf64_howto_table_rela): Likewise.
	(micromips_reloc_map): Likewise.
	(bfd_elf64_bfd_reloc_type_lookup): Handle microMIPS.
	(bfd_elf64_bfd_reloc_name_lookup): Likewise.
	(mips_elf64_rtype_to_howto): Likewise.
	* elfn32-mips.c (elf_micromips_howto_table_rel): New variable.
	(elf_micromips_howto_table_rela): Likewise.
	(micromips_reloc_map): Likewise.
	(bfd_elf32_bfd_reloc_type_lookup): Handle microMIPS.
	(bfd_elf32_bfd_reloc_name_lookup): Likewise.
	(mips_elf_n32_rtype_to_howto): Likewise.
	* elfxx-mips.c (micromips_reloc_shuffle_p): New function.
	(TLS_RELOC_P): Handle microMIPS.
	(got16_reloc_p, call16_reloc_p): Likewise.
	(hi16_reloc_p, lo16_reloc_p): Likewise.
	(_bfd_mips16_elf_reloc_unshuffle): Likewise.
	(_bfd_mips16_elf_reloc_shuffle): Likewise.
	(_bfd_mips_elf_lo16_reloc): Likewise.
	(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.
	(_bfd_mips_vxworks_finish_dynamic_symbol): Likewise.
	(_bfd_mips_elf_gc_sweep_hook): Likewise.
	(_bfd_mips_elf_print_private_bfd_data):	Likewise.
	* reloc.c (BFD_RELOC_MICROMIPS_16): New relocation.
	(BFD_RELOC_MICROMIPS_7_PCREL_S1): Likewise.
	(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.

	* elfxx-mips.c (mips_elf_calculate_relocation): Do not mark
	calls to undefined weak functions as needing jalx.

	* elfxx-mips.c (LA25_LUI_MICROMIPS_1, LA25_LUI_MICROMIPS_2,
	LA25_J_MICROMIPS_1, LA25_J_MICROMIPS_2, LA25_ADDIU_MICROMIPS_1,
	LA25_ADDIU_MICROMIPS_2): Define.
	(mips_elf_add_la25_intro, mips_elf_add_la25_trampoline): Adjust
	value of stub symbol if target is a microMIPS function.
	(mips_elf_create_la25_stub): Create microMIPS stub if target is
	a microMIPS function.

	* elfxx-mips.c (mips_elf_calculate_relocation): Expect low bit
	of $t9 to be set of microMIPS _gp_disp relocations.

binutils/
2010-06-01  Chao-ying Fu  <fu@mips.com>

	* readelf.c (get_machine_flags): Handle microMIPS.
	(get_mips_symbol_other): Likewise.

gas/
2010-06-01  Chao-ying Fu  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* config/tc-mips.h (mips_segment_info): Add one bit for
	microMIPS.
	* config/tc-mips.c (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.
	(HAVE_CODE_COMPRESSION): Likewise.
	(micromips_op_hash): New variable.
	(micromips_nop16_insn, micromips_nop32_insn): New variables.
	(NOP_INSN): Handle microMIPS.
	(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_q_map): New variable.
	(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_q_map): New variable.
	(micromips_imm_b_map, micromips_imm_c_map): New macros.
	(RELAX_DELAY_SLOT_SIZE_ERROR_FIRST): New macro.
	(RELAX_DELAY_SLOT_SIZE_ERROR_SECOND): Likewise.
	(RELAX_MICROMIPS_ENCODE, RELAX_MICROMIPS_P): New macros.
	(RELAX_MICROMIPS_TYPE, RELAX_MICROMIPS_USER_16BIT): Likewise.
	(RELAX_MICROMIPS_UNCOND, RELAX_MICROMIPS_LINK): Likewise.
	(RELAX_MICROMIPS_TOOFAR, RELAX_MICROMIPS_MARK_TOOFAR): Likewise.
	(RELAX_MICROMIPS_CLEAR_TOOFAR): Likewise.
	(RELAX_MICROMIPS_EXTENDED): Likewise.
	(RELAX_MICROMIPS_MARK_EXTENDED): Likewise.
	(RELAX_MICROMIPS_CLEAR_EXTENDED): Likewise.
	(MICROMIPS_INSERT_OPERAND, MICROMIPS_EXTRACT_OPERAND): New
	macros.
	(A_BFD_RELOC_HI16_S, A_BFD_RELOC_HI16, A_BFD_RELOC_LO16): New
	relocation wrapper macros.
	(A_BFD_RELOC_GPREL16): Likewise.
	(A_BFD_RELOC_MIPS_GOT16, A_BFD_RELOC_MIPS_GOT_HI16): Likewise.
	(A_BFD_RELOC_MIPS_GOT_LO16, A_BFD_RELOC_MIPS_HIGHEST): Likewise.
	(A_BFD_RELOC_MIPS_HIGHER, A_BFD_RELOC_MIPS_GOT_DISP): Likewise.
	(A_BFD_RELOC_MIPS_GOT_PAGE, A_BFD_RELOC_MIPS_GOT_OFST): Likewise.
	(A_BFD_RELOC_MIPS_SUB, A_BFD_RELOC_MIPS_JALR): Likewise.
	(mips_macro_warning): Add delay_slot_16bit_p, delay_slot_32bit_p,
	and num_insns.
	(micromips_16, micromips_32): New variables.
	(is_micromips_16bit_p, is_micromips_32bit_p): New functions.
	(insn_length): Return the length of microMIPS instructions.
	(mips_record_mips16_mode): Rename to...
	(mips_record_mips16_micromips_mode): ... this.  Handle microMIPS.
	(install_insn): Handle microMIPS.
	(is_size_valid, is_delay_slot_valid): New functions.
	(md_begin): Handle microMIPS.
	(md_assemble): Likewise.
	(micromips_reloc_p): New function.
	(got16_reloc_p): Handle microMIPS.
	(hi16_reloc_p): Likewise.
	(lo16_reloc_p): Likewise.
	(matching_lo_reloc): Likewise.
	(mips_move_labels): Likewise.
	(mips_mark_labels): New function.
	(mips16_mark_labels): Rename to...
	(mips_compressed_mark_labels): ... this.  Handle microMIPS.
	(insns_between): Handle microMIPS.
	(MICROMIPS_TARGET, MICROMIPS_TARGET_LABEL): New macros.
	(micromips_add_number_label): New function.
	(append_insn): Handle microMIPS.
	(start_noreorder, end_noreorder): Likewise.
	(macro_start, macro_warning, macro_end): Likewise.
	(macro_build): Likewise.
	(macro_build_jalr): Likewise.
	(macro_build_lui): Likewise.
	(macro_build_ldst_constoffset): Use relocation wrappers.
	(set_at): Likewise.
	(load_register): Likewise.
	(load_address): Likewise.
	(move_register): Handle microMIPS.
	(load_got_offset): Use relocation wrappers.
	(add_got_offset): Likewise.
	(add_got_offset_hilo): Likewise.
	(macro): Handle microMIPS.
	(validate_micromips_insn): New function.
	(micromips_percent_op): New variable.
	(parse_relocation): Handle microMIPS.
	(my_getExpression): Likewise.
	(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.
	(md_pcrel_from): Handle microMIPS relocations.
	(mips_force_relocation): Likewise.
	(md_apply_fix): Likewise.
	(mips_align): Handle microMIPS.
	(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.
	(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.
	(mips_fix_adjustable): Likewise.
	(tc_gen_reloc): Handle microMIPS relocations.
	(mips_relax_frag): Handle microMIPS.
	(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.
	(micromips_ip): New function.
	(micromips_macro_build): Likewise.
	(micromips_macro): Likewise.

	* 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.

	* config/tc-mips.c (nops_for_insn_or_target): Replace
	MIPS16_INSN_BRANCH with MIPS16_INSN_UNCOND_BRANCH and
	MIPS16_INSN_COND_BRANCH.

	* config/tc-mips.c (append_insn): Replace INSN2_MOD_31 with
	INSN2_READ_GPR_31.  Merge with code to handle INSN_WRITE_GPR_31.

	* config/tc-mips.c (mips32_to_micromips_reg_h_map): New
	variable.
	(mips32_to_micromips_reg_m_map): Likewise.
	(mips32_to_micromips_reg_n_map): New macro.
	(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.
	(append_insn): Handle microMIPS "mh", "mi", "mm" and "mn"
	operands.

gas/testsuite/
2010-06-01  Maciej W. Rozycki  <macro@codesourcery.com>
            Chao-ying Fu  <fu@mips.com>

	* gas/mips/beq.d: Reformat.
	* gas/mips/bge.d, gas/mips/bgeu.d: Likewise.
	* gas/mips/blt.d, gas/mips/bltu.d: Likewise.

	* gas/mips/mips4-fp.d: Reformat.

	* gas/mips/beq.d, gas/mips/beq.s: Remove checks for
	branch-likely instructions and place them...
	* gas/mips/bge.d, gas/mips/bge.s: Likewise.
	* gas/mips/bgeu.d, gas/mips/bgeu.s: Likewise.
	* gas/mips/blt.d, gas/mips/blt.s: Likewise.
	* gas/mips/bltu.d, gas/mips/bltu.s: Likewise.
	* gas/mips/branch-likely.d, gas/mips/branch-likely.s: ... in
	this new test.
	* gas/mips/mips.exp: Run the new test and update the
	constraints for the upated tests to include MIPS I.

	* gas/mips/mips4-fp.d, gas/mips/mips4-fp.s: Remove checks for
	branch-likely instructions and place them...
	* gas/mips/mips4-fp.l: Update accordingly.
	* gas/mips/mips4-branch-likely.d, gas/mips/mips4-branch-likely.s:
	... in this new test.
	* gas/mips/mips4-branch-likely.l: New stderr output for the new
	test.
	* gas/mips/mips.exp (mips4-branch-likely): Run a dump test and
	list tests matching branch-likely and mips4-fp tests
	appropriately.

	* gas/mips/micromips.d: New test.
	* gas/mips/micromips-trap.d: Likewise.
	* gas/mips/micromips-branch-relax-pic.d: Likewise.
	* gas/mips/micromips-branch-relax-pic.d: Likewise.
	* gas/mips/micromips.l: New stderr output.
	* gas/mips/micromips-branch-relax.l: Likewise.
	* gas/mips/micromips-branch-relax-pic.l: Likewise.
	* gas/mips/micromips.s: New test source.
	* gas/mips/micromips-branch-relax.s: Likewise.
	* gas/mips/mips.exp: Run the new tests.

	* gas/mips/mips.exp (run_dump_test_arch): Check for the presence
	of an architecture-specific test first and use it if found,
	before falling back to the generic one.

	* gas/mips/micromips@abs.d: New test.
	* 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@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@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@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/mips32-imm.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/mips32-imm.s: Likewise.
	* gas/mips/mips32.s: Handle microMIPS.
	* 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.

include/elf/
2010-06-01  Chao-ying Fu  <fu@mips.com>

	* mips.h (R_MICROMIPS_min, R_MICROMIPS_16): 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.
	(ELF_ST_IS_MIPS_PLT): Likewise.
	(STO_MICROMIPS): Likewise.
	(ELF_ST_IS_MICROMIPS, ELF_ST_MICROMIPS, ELF_ST_SET_MICROMIPS):
	Likewise.
	(ELF_ST_IS_MIPS_PIC, ELF_ST_SET_MIPS_PIC): Handle microMIPS.

include/opcode/
2010-06-01  Chao-ying Fu  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* mips.h
	(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_MOD_31): Likewise.
	(INSN2_READ_GP, INSN2_READ_PC): Likewise.
	(CPU_MICROMIPS): New macro.
	(M_BC1FL, M_BC1TL, M_BC2FL, M_BC2TL, M_BEQL, M_BGEZL): New enum
	values.
	(M_BGEZALL, M_BGTZL, M_BLEZL, M_BLTZL, M_BLTZALL): Likewise.
	(M_CACHE_OB, 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_LWP_AB, M_LWP_OB): Likewise.
	(M_LWR_OB, 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, M_SDP_AB): Likewise.
	(M_SDP_OB, M_SDR_OB, M_SWC2_OB, M_SWL_OB, M_SWM_AB): Likewise.
	(M_SWM_OB, 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_BREAKCODE, MICROMIPSOP_SH_BREAKCODE): Likewise.
	(MICROMIPSOP_SH_BREAKCODE2): Likewise.
	(MICROMIPSOP_MASK_CACHEOP, MICROMIPSOP_SH_CACHEOP): Likewise.
	(MICROMIPSOP_MASK_COPSEL, MICROMIPSOP_SH_COPSEL): 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_MZ, MICROMIPSOP_SH_MZ): 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.
	(micromips_opcodes): New declaration.
	(bfd_micromips_num_opcodes): Likewise.

	* mips.h (MIPS16_INSN_UNCOND_BRANCH): New macro.
	(MIPS16_INSN_BRANCH): Rename to...
	(MIPS16_INSN_COND_BRANCH): ... this.

	* mips.h (INSN2_MOD_31): Rename to...
	(INSN2_READ_GPR_31): ... this.
	(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/
2010-06-01  Catherine Moore  <clm@codesourcery.com>
            Chao-ying Fu  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* ld-mips-elf/jalx-1.s: New test.
	* ld-mips-elf/jalx-1.d: New test output.
	* ld-mips-elf/jalx-1.ld: New test linker script.
	* ld-mips-elf/mips-elf.exp: Run new test.

	* ld-mips-elf/jalx-2-main.s: New.
	* ld-mips-elf/jalx-2.dd: New.
	* ld-mips-elf/jalx-2-ex.s: New.
	* ld-mips-elf/jalx-2-printf.s: New.
	* ld-mips-elf/mips-elf.exp: Run new test.

opcodes/
2010-06-01  Chao-ying Fu  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* 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.
	(print_insn_micromips): New function.
	(is_micromips_mode_p): New function.
	(_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 (print_mips16_insn_arg): Remove branch instruction
	type and delay slot determination.
	(print_insn_mips16): Extend branch instruction type and delay
	slot determination to cover all instructions.
	* mips16-opc.c (BR): Remove macro.
	(UBR, CBR): New macros.
	(mips16_opcodes): Update branch annotation for "b", "beqz",
	"bnez", "bteqz" and "btnez".  Add branch annotation for "jalrc"
	and "jrc".

	* mips-dis.c (print_insn_mips): Correct branch instruction type
	determination.

	* 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.

[-- Attachment #2: Type: APPLICATION/octet-stream, Size: 128412 bytes --]

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS and MCU ASE instruction set support
  2010-06-01 14:21   ` Maciej W. Rozycki
@ 2010-06-01 14:39     ` Catherine Moore
  2010-06-01 22:04     ` Richard Sandiford
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 41+ messages in thread
From: Catherine Moore @ 2010-06-01 14:39 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: Richard Sandiford, binutils, Chao-ying Fu, Joseph S. Myers,
	Daniel Jacobowitz

Maciej W. Rozycki wrote:
> Hi Richard,

> 
>>> 	* ld-mips-elf/jalx-2-main.s: New.
>>> 	* ld-mips-elf/jalx-2.dd: New.
>>> 	* ld-mips-elf/jalx-2-ex.s: New.
>>> 	* ld-mips-elf/jalx-2-printf.s: New.
>>> 	* ld-mips-elf/mips-elf.exp: Run new test.
>> Please make the .dd output less susceptible to things like the number
>> of sections, size of program headers, etc.  One way is to use a linker
>> script to place each section at a nice round address.  Another is to
>> ".*" out the addresses and instruction encodings and just reply on
>> the symbolic part of the disassembly.  I think the former's better
>> here.  There are quite a few existing examples.
> 
>  Catherine, I reckon you were working on these?
> 
   I will make these testsuite revisions.

   --catherine

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS and MCU ASE instruction set support
  2010-06-01 14:21   ` Maciej W. Rozycki
  2010-06-01 14:39     ` Catherine Moore
@ 2010-06-01 22:04     ` Richard Sandiford
  2010-06-01 22:47     ` Fu, Chao-Ying
  2010-06-05  9:17     ` Richard Sandiford
  3 siblings, 0 replies; 41+ messages in thread
From: Richard Sandiford @ 2010-06-01 22:04 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: binutils, Chao-ying Fu, Catherine Moore, Joseph S. Myers,
	Daniel Jacobowitz

"Maciej W. Rozycki" <macro@codesourcery.com> writes:
>> Generally looks good.  It would have been better to submit the
>> ACE, m14kc and microMIPS support as three separate changes though.
>> Please can you do that for the follow-up?
>
>  I have done it now; the next version will comprise microMIPS ASE changes 
> only (the MCU ASE adds to both the MIPS ISA and the microMIPS ASE, so it 
> should be applied on top of the microMIPS change).

Thanks.  Thanks too for all the issues that you've addressed already,
and for the ones you said you'd sort out.  Sounds like good progress!

>  Stricly speaking some changes, while related, can be split off too (e.g. 
> some MIPS16 or testsuite changes), so I'll look into separating them too 
> -- perhaps that'll make the thing rolling sooner.

Yeah, thanks, that'd be a help if it's easy to do.  It doesn't matter
too much, though.  Most of the MIPS16 changes were consistent with the
microMIPS ones, so were easy to review as a unit.

>> From a usability perspective, it's a shame that:
>> 
>> 	.set	micromips
>> 	.ent	foo
>> foo:
>> 	b	1f
>> 	nop
>> 	.end	foo
>> 	.ent	bar
>> bar:
>> 1:	nop
>> 	.end	bar
>> 
>> disassembles as:
>> 
>> 00000000 <foo>:
>>    0:   cfff            b       0 <foo>
>>                         0: R_MICROMIPS_PC10_S1  .L11
>>    2:   0c00            nop
>>    4:   0c00            nop
>> 
>> 00000006 <bar>:
>>    6:   0c00            nop
>> 
>> leaving the poor user with no idea what .L11 is.
>
>  Indeed.  This is a general limitation of `objdump' it would seem.  This 
> is no different to what you get with:
>
> $ cat b.s
> 	.globl	baz
> 	.ent	foo
> foo:
> 	b	baz
> 	nop
> 	.end	foo
> 	.ent	bar
> baz:
> bar:
> 1:	nop
> 	.end	bar
> $ mips-sde-elf-objdump -dr b.o
>
> b.o:     file format elf32-tradbigmips
>
>
> Disassembly of section .text:
>
> 00000000 <foo>:
>    0:	1000ffff 	b	0 <foo>
> 			0: R_MIPS_PC16	baz
>    4:	00000000 	nop
>    8:	00000000 	nop
>
> 0000000c <bar>:
>    c:	00000000 	nop

Well, it's a little different.  The user has at least defined two
named symbols in this case, so they have a good chance of knowing
what "baz" means.  In the microMIPS case we've invented a label
and are using it in preference to the user-defined one.

> I'd just recommend peeking at the symbol table (back to the first 
> program):
>
> $ mips-sde-elf-objdump -t b.o
>
> b.o:     file format elf32-tradbigmips
>
> SYMBOL TABLE:
> 00000000 l    d  .text	00000000 .text
> 00000000 l    d  .data	00000000 .data
> 00000000 l    d  .bss	00000000 .bss
> 00000000 l    d  .reginfo	00000000 .reginfo
> 00000000 l    d  .pdr	00000000 .pdr
> 00000000 l     F .text	00000006 0x80 foo
> 00000006 l     F .text	00000002 0x80 bar
> 00000006 l       .text	00000000 0x80 .L1\x021

I suppose having a symbol with ^B in it is less than ideal too.
AIUI that name was chosen specifically because it wasn't supposed
to be written out.

It would be especially confusing if the user or compiler had a ".L11"
label (without the ^B).

>> The following:
>> 
>> 	.set	micromips
>> 	.ent	foo
>> foo:
>> 	ld	$10,0x1000($11)
>> 	.end	foo
>> 
>> generates an assertion failure:
>> 
>> Assertion failure in micromips_macro_build at gas/config/tc-mips.c line 19466.
>> Please report this bug.
>> 
>> on mipsisa64-elf with "-mips1 -mabi=32".
>
>  I can't reproduce it, sorry:
> [...]
>  Can you debug it and see what the relocation type is that's causing it?  
> I wonder if that might be related to the varargs issue you referring to 
> below and depend on the host architecture, hmm...

Yeah, you're right, sorry.  I forgot to mention that in the later reviews.
This was with a x86_64-linux-gnu host and a botched attempt at working
around the varags issue.  (I probably just added -Wno-error or something,
I can't remember now.)

I switched to a 32-bit host for parts 2 and 3 of the review, and yeah,
it doesn't reproduce there.

>> > gas/
>> > 2010-05-18  Chao-ying Fu  <fu@mips.com>
>> >             Maciej W. Rozycki  <macro@codesourcery.com>
>> >             Daniel Jacobowitz  <dan@codesourcery.com>
>> >
>> > 	* config/tc-mips.h (mips_segment_info): Add one bit for
>> > 	microMIPS.
>> > 	* config/tc-mips.c
>> 
>> How about having something like:
>> 
>>   #define OOD_TEXT_LABELS (mips_opts.mips16 || mips_opts.micromips)
>> 
>> ?
>
>  It sounds reasonable to me, except that condition is used in some other 
> contexts as well.  I have made it HAVE_CODE_COMPRESSION thus and took the 
> opportunity to optimise code around mips16_micromips_mark_labels() too.  
> Finally I have renamed the function to mips_compressed_mark_labels() for 
> as the other sounds too complicated to me.

All these changes sound good, thanks.

>> > 	(append_insn): Handle microMIPS.
>> 
>> +  if (mips_opts.micromips)
>> +    {
>> +      if ((prev_pinfo2 & INSN2_BRANCH_DELAY_16BIT)
>> +	  && !is_micromips_16bit_p (ip->insn_mo))
>> +	as_warn (_("instruction with wrong size in a branch delay slot that"
>> +		   " requires a 16-bit instruction"));
>> +      if ((prev_pinfo2 & INSN2_BRANCH_DELAY_32BIT)
>> +	  && !is_micromips_32bit_p (ip->insn_mo))
>> +	as_warn (_("instruction with wrong size in a branch delay slot that"
>> +		   " requires a 32-bit instruction"));
>> +    }
>> +  
>> 
>> Although not enforced as often as it should be, GAS convention is for
>> errors to start with a capital letter.
>
>  I'll be fixing these up as I come across them.  If to be effective, then 
> upstream HEAD should be fixed up or otherwise people have no way not to 
> get confused.  I didn't know of this rule for one.  That shouldn't be a 
> lot effort, should it?

Nope.  It's just a question of time and priorities. ;-)

>  Some have to stay for now actually, because .l testsuite patterns are 
> commonly shared between standard MIPS and microMIPS tests, and should be 
> fixed separately.

OK, that's fine.

>> +      if (pinfo & INSN_COP)
>> +	{
>> +	  /* We don't keep enough information to sort these cases out.
>> +	     The itbl support does keep this information however, although
>> +	     we currently don't support itbl fprmats as part of the cop
>> +	     instruction.  May want to add this support in the future.  */
>> +	}
>> 
>> Assert?
>
>  Well, that's no different to the standard MIPS variant.

OK, fair enough, but I suppose I was judging the new code on its merits
as new code.  Sticking to existing practice is an easier sell if the
code that implements it is being reused rather than copied...

>> +do_lsb:
>> 
>> Not properly indented.  A few other instances.
>
>  Like the respective originals in mips_ip().  I have fixed up the new 
> labels, but upstream HEAD code should be adjusted the same way.

Thanks.  Yeah, sorting out the new code is all that's needed.
As before, I was judging the code on its own merits rather than
checking whether each dubious bit was new or from cut-&-paste.

It'll be a while before I have chance to go through the update
properly, but it looks good at first glance.

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: [PATCH] MIPS: microMIPS and MCU ASE instruction set support
  2010-06-01 14:21   ` Maciej W. Rozycki
  2010-06-01 14:39     ` Catherine Moore
  2010-06-01 22:04     ` Richard Sandiford
@ 2010-06-01 22:47     ` Fu, Chao-Ying
  2010-06-05  9:17     ` Richard Sandiford
  3 siblings, 0 replies; 41+ messages in thread
From: Fu, Chao-Ying @ 2010-06-01 22:47 UTC (permalink / raw)
  To: Maciej W. Rozycki, Richard Sandiford
  Cc: binutils, Catherine Moore, Joseph S. Myers, dan

Maciej W. Rozycki wrote:
>  I'm placing notes throughout and I'll be asking people for 
> explanations 
> where applicable.  Chao-ying, would you please look into the 
> few pieces of 
> code below I am a bit uncertain about?

  Yes.

> 
> > > 	(A_BFD_RELOC_HI16_S, A_BFD_RELOC_HI16, A_BFD_RELOC_LO16): New
> > > 	relocation wrapper macros.
> > > 	(A_BFD_RELOC_GPREL16): Likewise.
> > > 	(A_BFD_RELOC_MIPS_GOT16, A_BFD_RELOC_MIPS_GOT_HI16): Likewise.
> > > 	(A_BFD_RELOC_MIPS_GOT_LO16, A_BFD_RELOC_MIPS_HIGHEST): Likewise.
> > > 	(A_BFD_RELOC_MIPS_HIGHER, A_BFD_RELOC_MIPS_GOT_DISP): Likewise.
> > > 	(A_BFD_RELOC_MIPS_GOT_PAGE, A_BFD_RELOC_MIPS_GOT_OFST): 
> Likewise.
> > > 	(A_BFD_RELOC_MIPS_SUB, A_BFD_RELOC_MIPS_JALR): Likewise.
> > 
> > Did you consider doing the translation from non-microMIPS to
> > microMIPS in the macro_* functions, rather than in their callers?
> > I fear it'll be too easy to accidentally forget to use 
> A_BFD_* in future.
> 
>  Agreed, I didn't like the new macros from the very 
> beginning.  Chao-ying 
> -- any thoughts?

  I am fine.  But the new method may be bigger than the A_BFD* method.


> 
> > > 	(macro_start, macro_warning, macro_end): Likewise.
> > 
> > +  else if ((subtype & RELAX_DELAY_SLOT_SIZE_ERROR_FIRST)
> > +	   || (subtype & RELAX_DELAY_SLOT_SIZE_ERROR_SECOND))
> > +    return _("Macro instruction of the wrong size in a 
> branch delay slot"
> > +	     " that requires a 16-bit or 32-bit instruction");
> > 
> > Did you consider adding a flag to distinguish the 32-bit 
> and 16-bit cases?
> > It'd be nice to be consistent with the non-relaxed error if 
> possible.
> 
>  Chao-ying?  I've had a look actually and flag may not be 
> necessary to get 
> the functionality.  I'm fixing this up elsewhere already.

  I am fine with this functionality. Maybe passing one more parameter to
macro_warning() can help to distinguish two cases.

> 
> > +  /* If either one implementation contains one 
> instruction, we need to check
> > +     the delay slot size requirement.  */
> > +  if (mips_macro_warning.num_insns[0] == 1
> > +      || mips_macro_warning.num_insns[1] == 1)
> > +    {
> > +      if (mips_macro_warning.num_insns[0] == 
> mips_macro_warning.num_insns[1]
> > +	  && mips_macro_warning.sizes[0] == mips_macro_warning.sizes[1])
> > +	{
> > +	  /* Either the macro has a single implementation or both
> > +	     implementations are 1 instruction with the same size.
> > +	     Emit the warning now.  */
> > +	  if ((mips_macro_warning.delay_slot_16bit_p
> > +	       && mips_macro_warning.sizes[0] != 2)
> > +	      || (mips_macro_warning.delay_slot_32bit_p
> > +		  && mips_macro_warning.sizes[0] != 4))
> > +	    {
> > +	      const char *msg;
> > +	      msg = macro_warning (RELAX_DELAY_SLOT_SIZE_ERROR_FIRST);
> > +	      if (msg != 0)
> > +		as_warn (msg);
> > +	    }
> > +	}
> > +      else
> > +	{
> > +	  relax_substateT subtype;
> > +
> > +	  /* Set up the relaxation warning flags.  */
> > +	  subtype = 0;
> > +	  if (mips_macro_warning.delay_slot_16bit_p)
> > +	    {
> > +	      if (mips_macro_warning.num_insns[0] != 1
> > +		  || mips_macro_warning.sizes[0] != 2)
> > +		subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
> > +	      if (mips_macro_warning.num_insns[1] != 1
> > +		  || mips_macro_warning.sizes[1] != 2)
> > +		subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
> > +	    }
> > +	  if (mips_macro_warning.delay_slot_32bit_p)
> > +	    {
> > +	      if (mips_macro_warning.num_insns[0] != 1
> > +		  || mips_macro_warning.sizes[0] != 4)
> > +		subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
> > +	      if (mips_macro_warning.num_insns[1] != 1
> > +		  || mips_macro_warning.sizes[1] != 4)
> > +		subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
> > +	    }
> > +
> > +	  /* One implementation might need a warning but the other
> > +	     definitely doesn't.  */
> > +	  mips_macro_warning.first_frag->fr_subtype |= subtype;
> > +	}
> > +    }
> > 
> > Why not work out the subtype, then check whether both 
> ERROR_FIRST and
> > ERROR_SECOND are set?
> 
>  Chao-ying?

  Do you mean this kind of code?
Ex:
  if (mips_macro_warning.num_insns[0] == 1
      || mips_macro_warning.num_insns[1] == 1)
    {
      if (mips_macro_warning.delay_slot_16bit_p)
        {
          if (mips_macro_warning.num_insns[0] != 1
              || mips_macro_warning.sizes[0] != 2)
            subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
          if (mips_macro_warning.num_insns[1] != 1
              || mips_macro_warning.sizes[1] != 2)
            subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
        }
      else if (mips_macro_warning.delay_slot_32bit_p)
        {
          if (mips_macro_warning.num_insns[0] != 1
              || mips_macro_warning.sizes[0] != 4)
            subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
          if (mips_macro_warning.num_insns[1] != 1
              || mips_macro_warning.sizes[1] != 4)
            subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
        }

      if ((subtype & RELAX_DELAY_SLOT_SIZE_ERROR_FIRST)
           && (subtype & RELAX_DELAY_SLOT_SIZE_ERROR_SECOND))
        {
          const char *msg;
          msg = macro_warning (RELAX_DELAY_SLOT_SIZE_ERROR_FIRST); //
NEED TO PASS 16-bit or 32-bit info
          if (msg != 0)
             as_warn (msg);
        }
      else
        {
          /* One implementation might need a warning but the other
             definitely doesn't.  */
          mips_macro_warning.first_frag->fr_subtype |= subtype;
        }
    }

> 
> > +	  if (mips_macro_warning.delay_slot_p)
> > +	    {
> > +	      if (mips_macro_warning.num_insns[0] > 1)
> > +		subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
> > +	      if (mips_macro_warning.num_insns[1] > 1)
> > +		subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
> > +	    }
> > 
> > I don't get why this hunk is needed.  I thought ERROR_FIRST 
> and ERROR_SECOND
> > controlled cases where a macro has a single-insn expansion 
> that is the
> > wrong size, which ought to be handled by the block above.  
> If the code
> > really is needed, you should add a comment explaining why.
> 
>  Chao-ying?


  I agree.  The delay_slot_p check is duplicated, and we can discard it
for
ERROR_FIRST and ERROR_SECOND when num_insns[]>1.  My old code
double-checked the condition for 
number of instructions in delay slots.

> 
> > > 	(macro_build): Likewise.
> > 
> > +  if (mips_opts.micromips)
> > +    {
> > +      if (strcmp (name, "lui") == 0)
> > +	micromips_macro_build (ep, name, "s,u", args);
> > +      else if (strcmp (fmt, "d,w,<") == 0)
> > +	micromips_macro_build (ep, name, "t,r,<", args);
> > +      else
> > +	micromips_macro_build (ep, name, fmt, args);
> > +      va_end (args);
> > +      return;
> > +    }
> > 
> > A bit of commentary might help explain the letter switch here.
> 
>  Chao-ying?

  Because I didn't change all the code before calling LUI macro for
microMIPS, I need
to magically change the operand string for microMIPS to use "s,u" for
microMIPS LUI.
"d,w,<" is another case that we need to map it to "t,r,<" for microMIPS.
If we can search all the places and replace all calls with correct
operand strings for microMIPS,
this special code can be dropped.

> 
> > > 	(macro_build_jalr): Likewise.
> > 
> > +  if (mips_opts.micromips)
> > +    {
> > +      if (HAVE_NEWABI)
> > +	macro_build (NULL, "jalr", "t,s", RA, PIC_CALL_REG);
> > +      else
> > +	macro_build (NULL, "jalr", "mj", PIC_CALL_REG);
> > +    }
> > +  else
> > +    macro_build (NULL, "jalr", "d,s", RA, PIC_CALL_REG);
> > 
> > Why HAVE_NEWABI?  Do you want a 32-bit insn for R_MIPS_JALR?
> 
>  Chao-ying?

  OK.  This code is done before I put the R_MIPS_JALR patch into GAS and
LD.
The new code is as follows.
Ex:
static void
macro_build_jalr (expressionS *ep)
{
  char *f = NULL;

  if (MIPS_JALR_HINT_P (ep))
    {
      frag_grow (8);
      f = frag_more (0);
    }
  if (mips_opts.micromips)
    macro_build (NULL, "jalr", "t,s", RA, PIC_CALL_REG);
  else
    macro_build (NULL, "jalr", "d,s", RA, PIC_CALL_REG);
  if (MIPS_JALR_HINT_P (ep))
    fix_new_exp (frag_now, f - frag_now->fr_literal,
                 4, ep, FALSE, A_BFD_RELOC_MIPS_JALR); // THIS MAY BE
FIXED BY A NEW METHOD.
}

  And, we need to modify elfxx-mips.c to support
BFD_RELOC_MICROMIPS_JALR to convert jalr to bal for microMIPS.

> 
> > If so, you should check MIPS_JALR_HINT_P (ep) instead.
> 
>  I may have missed that while updating the change for the 
> recent JALR hint 
> support, let me see...
> 

> > > 	(md_convert_frag): Likewise.
> > 
> > -      /* Possibly emit a warning if we've chosen the 
> longer option.  */
> > -      if (((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
> > -	  == ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))
> > +      if (!(fragp->fr_subtype & RELAX_USE_SECOND))
> > +  	{
> > +	  /* Check if the size in branch delay slot is ok.  */
> > +	  if (fragp->fr_subtype & RELAX_DELAY_SLOT_SIZE_ERROR_FIRST)
> > +	    {
> > +	      const char *msg = macro_warning (fragp->fr_subtype);
> > +	      if (msg != 0)
> > +		as_warn_where (fragp->fr_file, fragp->fr_line, msg);
> > +	    }
> > +	}
> > +      else
> >  	{
> > -	  const char *msg = macro_warning (fragp->fr_subtype);
> > -	  if (msg != 0)
> > -	    as_warn_where (fragp->fr_file, fragp->fr_line, "%s", msg);
> > +	  /* Check if the size in branch delay slot is ok.
> > +	     Possibly emit a warning if we've chosen the longer 
> option.  */
> > +	  if ((fragp->fr_subtype & RELAX_DELAY_SLOT_SIZE_ERROR_SECOND)
> > +	      || (fragp->fr_subtype & RELAX_SECOND_LONGER))
> > +	    {
> > +	      const char *msg = macro_warning (fragp->fr_subtype);
> > +	      if (msg != 0)
> > +		as_warn_where (fragp->fr_file, fragp->fr_line, msg);
> > +	    }
> >  	}
> > 
> > This doesn't accurately preserve the previous:
> > 
> >       if (((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
> > 	  == ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))
> > 
> > behaviour.
> 
>  Chao-ying?

  How about this?

Ex:

      if ((((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
           == ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))
          || (!(fragp->fr_subtype & RELAX_USE_SECOND)
              && (fragp->fr_subtype &
RELAX_DELAY_SLOT_SIZE_ERROR_FIRST))
          || ((fragp->fr_subtype & RELAX_USE_SECOND)
              && (fragp->fr_subtype &
RELAX_DELAY_SLOT_SIZE_ERROR_SECOND)))
        {
          const char *msg = macro_warning (fragp->fr_subtype); // MAY
NEED TO PASS 16-bit or 32-bit info
          if (msg != 0)
            as_warn_where (fragp->fr_file, fragp->fr_line, "%s", msg);
        }



> 
> > > 	(micromips_ip): New function.
> > 
> > +      /* Try to search "16" or "32" in the str.  */
> > +      if ((t = strstr (str, "16")) != NULL && t < save_s)
> > +	{
> > +	  /* Make sure "16" is before the first '.' if '.' exists.  */
> > +	  if ((s = strchr (str, '.')) != NULL && (t + 2 != s))
> > +	    {
> > +	      insn_error = "unrecognized opcode";
> > +	      return;
> > +	    }
> > +
> > +	  /* Make sure "16" is at the end of insn name, if no '.'.  */
> > +	  if ((s = strchr (str, '.')) == NULL
> > +	      && (!ISSPACE (*(t + 2)) && *(t + 2) != '\0'))
> > +	    {
> > +	      insn_error = "unrecognized opcode";
> > +	      return;
> > +	    }
> > +
> > +	  micromips_16 = TRUE;
> > +	  for (s = t + 2; *s != '\0'; ++s)
> > +	    *(s - 2) = *s;
> > +	  *(s - 2) = '\0';
> > +
> > +	  for (s = t; *s != '\0' && !ISSPACE (*s); ++s)
> > +	    continue;
> > +
> > +	  if (ISSPACE (*s))
> > +	    {
> > +	      save_c = *s;
> > +	      *s++ = '\0';
> > +	    }
> > +
> > +	  if ((insn = (struct mips_opcode *) hash_find 
> (micromips_op_hash, str))
> > +	      == NULL)
> > +	    {
> > +	      int i;
> > +	      int length;
> > +	      micromips_16 = FALSE;
> > +
> > +	      /* Restore the character we overwrite above (if any).  */
> > +	      if (save_c)
> > +		*(--s) = save_c;
> > +
> > +	      length = strlen (str);
> > +	      for (i = length - 1; &str[i] >= t; i--)
> > +		{
> > +		  str[i + 2] = str[i];
> > +		  if (t == &str[i])
> > +		    {
> > +		      str[i + 1] = '6';
> > +		      str[i] = '1';
> > +		      str[length + 2] = '\0';
> > +		      break;
> > +		    }
> > +		}
> > +
> > +	      insn_error = "unrecognized 16-bit version of 
> microMIPS opcode";
> > +	      return;
> > +	    }
> > +	}
> > +      else if ((t = strstr (str, "32")) != NULL && t < save_s)
> > +	{
> > +	  /* For some instruction names, we already have 32, so we need
> > +	     to seek the second 32 to process.  Ex: bposge3232, 
> dsra3232.  */
> > +	  char *new_t;
> > +	  if ((new_t = strstr (t + 2, "32")) != NULL && new_t < save_s)
> > +	    t = new_t;
> > +
> > +	  /* Make sure "32" is before the first '.' if '.' exists.  */
> > +	  if ((s = strchr (str, '.')) != NULL && (t + 2 != s))
> > +	    {
> > +	      insn_error = "unrecognized opcode";
> > +	      return;
> > +	    }
> > +
> > +	  /* Make sure "32" is at the end of the name, if no '.'.  */
> > +	  if ((s = strchr (str, '.')) == NULL
> > +	      && (!ISSPACE (*(t + 2)) && *(t + 2) != '\0'))
> > +	    {
> > +	      insn_error = "unrecognized opcode";
> > +	      return;
> > +	    }
> > +
> > +	  micromips_32 = TRUE;
> > +	  for (s = t + 2; *s != '\0'; ++s)
> > +	    *(s - 2) = *s;
> > +	  *(s - 2) = '\0';
> > +
> > +	  for (s = t; *s != '\0' && !ISSPACE (*s); ++s)
> > +	    continue;
> > +
> > +	  if (ISSPACE (*s))
> > +	    {
> > +	      save_c = *s;
> > +	      *s++ = '\0';
> > +	    }
> > +
> > +	  if ((insn = (struct mips_opcode *) hash_find 
> (micromips_op_hash, str))
> > +	      == NULL)
> > +	    {
> > +	      int i;
> > +	      int length;
> > +	      micromips_32 = FALSE;
> > +
> > +	      /* Restore the character we overwrite above (if any).  */
> > +	      if (save_c)
> > +		*(--s) = save_c;
> > +
> > +	      length = strlen (str);
> > +	      for (i = length - 1; &str[i] >= t; i--)
> > +		{
> > +		  str[i + 2] = str[i];
> > +		  if (t == &str[i])
> > +		    {
> > +		      str[i + 1] = '2';
> > +		      str[i] = '3';
> > +		      str[length + 2] = '\0';
> > +		      break;
> > +		    }
> > +		}
> > +
> > +	      insn_error = "unrecognized 32-bit version of 
> microMIPS opcode";
> > +	      return;
> > +	    }
> > 
> > Far too much cut-&-paste between the "16" and "32" cases.  Also:
> > 
> > +      if ((t = strstr (str, "16")) != NULL && t < save_s)
> > 
> > t < save_s must surely be true, since save_s is the null terminator.

  Yes.  I used t < save_s, because I don't know save_s points to NULL at
this point.
We can discard save_s now.

> > 
> > +	  /* Make sure "16" is before the first '.' if '.' exists.  */
> > +	  if ((s = strchr (str, '.')) != NULL && (t + 2 != s))
> > +	    {
> > +	      insn_error = "unrecognized opcode";
> > +	      return;
> > +	    }
> > +
> > +	  /* Make sure "16" is at the end of insn name, if no '.'.  */
> > +	  if ((s = strchr (str, '.')) == NULL
> > +	      && (!ISSPACE (*(t + 2)) && *(t + 2) != '\0'))
> > +	    {
> > +	      insn_error = "unrecognized opcode";
> > +	      return;
> > +	    }
> > 
> > Don't call strchr (str, '.') twice like that.  Better would be:
> > 
> > 	s = strchr (str, '.');

  Yes.

> > 
> > followed by the two checks.  Isn't the ISSPACE check 
> redundant though,
> > given that you've terminated the string at the first space?  I would
> > have thought:
> > 
> >         if (t + 2 != (s ? s : save_s))
> > 
> > would be enough.  Errors should start with a capital 
> letter.  Missing
> > internationalisation.
> 
>  Chao-ying?

  Yes. "if (t + 2 != (s ? s : save_s))" is enough.

> 
> > You could use alloca to create an opcode without the "16" or "32",
> > which would make the error-reporting code simpler.  It's best not
> > to change the user's source line if we can help it.
> 
>  Agreed.

  Yes.

> 
> > +	      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;
> > +		}
> > +	      if (save_c)
> > +		*(--s) = save_c;
> > +
> > +	      if (micromips_16 || micromips_32)
> > +		{
> > +		  int i;
> > +		  int length;
> > +
> > +		  length = strlen (str);
> > +		  for (i = length - 1; i >= 0; i--)
> > +		    {
> > +		      str[i + 2] = str[i];
> > +		      if (t == &str[i])
> > +			break;
> > +		    }
> > +		  if (micromips_16)
> > +		    {
> > +		      insn_error =
> > +			"unrecognized 16-bit version of 
> microMIPS opcode";
> > +		      str[i + 1] = '6';
> > +		      str[i] = '1';
> > +		    }
> > +		  else
> > +		    {
> > +		      insn_error =
> > +			"unrecognized 32-bit version of 
> microMIPS opcode";
> > +		      str[i + 1] = '2';
> > +		      str[i] = '3';
> > +		    }
> > +		  str[length + 2] = '\0';
> > +		}
> > +	      return;
> > 
> > Why override the insn_error unconditionally like this?  E.g.:
> > 
> > 	jar16	$30,$26
> > 
> >     Error: unrecognized 16-bit version of microMIPS opcode 
> `jar16 $30,$26'
> > 
> > implies there's a 32-bit opcode.  I'd also have thought that the
> > "opcode not supported on this processor" would triumph if 
> it applies.
> 
>  The error you've seen comes from the previous hunk above 
> rather than this 
> one which I think is unnecessary code duplication.  It's all rather 
> over-complicated and I'm working on getting it polished.  
> I've fixed this 
> piece of code:
> 
> 	.set	micromips
> 	.set	noreorder
> 	bltzall	$2, bar
> 	 addiusp 256
> 
> producing this nonsense:
> 
> bltzall.s: Assembler messages:
> bltzall.s:4: Error: opcode not supported on this processor: 
> mips1 (mips1) `addiusp 256'
> 
> too.  Also the original loop seems ill-formed to me, with 
> most of code 
> intended to be executed at most once, after the loop's terminating 
> condition triggered -- i.e. that shouldn't be in the loop in 
> the first 
> place.
> 

  What code in the loop do you refer to?  I am not clear.

  Thanks for updating the patch!

Regards,
Chao-ying

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS and MCU ASE instruction set support
  2010-06-01 14:21   ` Maciej W. Rozycki
                       ` (2 preceding siblings ...)
  2010-06-01 22:47     ` Fu, Chao-Ying
@ 2010-06-05  9:17     ` Richard Sandiford
  3 siblings, 0 replies; 41+ messages in thread
From: Richard Sandiford @ 2010-06-05  9:17 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: binutils, Chao-ying Fu, Catherine Moore, Joseph S. Myers,
	Daniel Jacobowitz

"Maciej W. Rozycki" <macro@codesourcery.com> writes:
>  I'll look into whatever's left yet.  Here's the current version for a 
> reference, in case you or anyone else wanted to comment on what I have 
> modified so far (no obligation, of course!).

OK, finally got chance to have a proper read of the changes from
the previous patch, and they look good, thanks.  I'm afraid most
of this is at the level of very minor niggly stuff:

+/* Whether code compression (either of the MIPS16 or the microMIPS ASEs has

s/ASEs has/ASEs) has/

+  if (mips_opts.micromips)
+    return is_micromips_16bit_p (insn->insn_mo)
+         ? 2 : (is_micromips_32bit_p (insn->insn_mo) ? 4 : 6);

This formatting isn't quite right because of the "emacs brackets" rule.
Should be:

    return (is_micromips_16bit_p (insn->insn_mo)
            ? 2 : is_micromips_32bit_p (insn->insn_mo) ? 4 : 6);

or:

    return (is_micromips_16bit_p (insn->insn_mo) ? 2
            : is_micromips_32bit_p (insn->insn_mo) ? 4 : 6);

But I'd be happy with an if-return-if-return-return chain too.
See below about these insns though...

-+  if (!mips_opts.mips16 && !mips_opts.micromips)
++  if (! HAVE_CODE_COMPRESSION)

The GCC decision a few years back was that no space should be added
after a unary operator (as with pointer deference, etc).  Not important
enough to do a sed on the whole source base, but we might as well avoid
changes that go the other way (from no space to space) in GAS.

+static bfd_boolean
+is_size_valid (const struct mips_opcode *mo)
+{
+  gas_assert (mips_opts.micromips);
+
+  if ((micromips_16 || micromips_32) && mo->pinfo == INSN_MACRO)
+    return FALSE;
+  if (micromips_16 && ! is_micromips_16bit_p (mo))
+    return FALSE;
+  if (micromips_32 && ! is_micromips_32bit_p (mo))
+    return FALSE;
+
+  return TRUE;
+}

Hmm, seeing this highlighted more makes me wonder whether
micromips_16 and micromips_32 shouldn't be combined into a
single variable that represents "the size the user set",
with 0 meaning "none".  As it stands, we'll have checks like:

  micromips_16 || micromips_32 || micromips_48

when any future 48-bit support is added.  Having separate variables
also gives the impression that arbitrary combinations are possible.

Also, how about replacing is_micromips_XXbit_p with a function
that just returns the size of a micromips insn?  We generally
deal with byte rather than bit lengths, so both this new function
and the combined "the size the user set" variable should probably
both be byte values.

Seems the code would be a fair bit clearer with those changes,
but maybe I'm wrong...

Maybe the mo->match assertions in is_micromips_XXbit_p are better
done in validate_micromips_insn -- especially if that makes the
changes above easier -- but I don't mind either way.

char
mips_nop_opcode (void)
{
  if (seg_info (now_seg)->tc_segment_info_data.micromips)
    return NOP_OPCODE_MICROMIPS;
 
  return seg_info (now_seg)->tc_segment_info_data.mips16
        ? NOP_OPCODE_MIPS16 : NOP_OPCODE_MIPS;
}

Same "emacs brackets" thing here.  Seems odd to treat microMIPS and MIPS16
differently like this, so I think if-return-if-return-return makes more
sense.

The new mips_handle_align looks very good, thanks.  I'm afraid it's another
silly nitpick, but usual style is not to have the brackets in "*(p++)".

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2010-05-23 21:38 ` Richard Sandiford
  2010-05-24 22:25   ` Fu, Chao-Ying
  2010-06-01 14:21   ` Maciej W. Rozycki
@ 2010-07-26 10:56   ` Maciej W. Rozycki
  2010-07-26 13:25     ` Nathan Froyd
  2010-07-26 19:03     ` Richard Sandiford
  2 siblings, 2 replies; 41+ messages in thread
From: Maciej W. Rozycki @ 2010-07-26 10:56 UTC (permalink / raw)
  To: Richard Sandiford
  Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
	Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers,
	Nathan Froyd

[-- Attachment #1: Type: TEXT/PLAIN, Size: 99320 bytes --]

Hi Richard,

 I'm combining a couple of e-mails together, quotations may come from 
various people -- hopefully no one will get lost and hopefully I haven't 
missed anything. ;)  [FIXME] are my annotations for future reference.

 NathanF, there's a QEMU question somewhere down the e-mail -- would you 
care to answer it?

> > > > 	(A_BFD_RELOC_HI16_S, A_BFD_RELOC_HI16, A_BFD_RELOC_LO16): New
> > > > 	relocation wrapper macros.
> > > > 	(A_BFD_RELOC_GPREL16): Likewise.
> > > > 	(A_BFD_RELOC_MIPS_GOT16, A_BFD_RELOC_MIPS_GOT_HI16): Likewise.
> > > > 	(A_BFD_RELOC_MIPS_GOT_LO16, A_BFD_RELOC_MIPS_HIGHEST): Likewise.
> > > > 	(A_BFD_RELOC_MIPS_HIGHER, A_BFD_RELOC_MIPS_GOT_DISP): Likewise.
> > > > 	(A_BFD_RELOC_MIPS_GOT_PAGE, A_BFD_RELOC_MIPS_GOT_OFST): 
> > Likewise.
> > > > 	(A_BFD_RELOC_MIPS_SUB, A_BFD_RELOC_MIPS_JALR): Likewise.
> > > 
> > > Did you consider doing the translation from non-microMIPS to
> > > microMIPS in the macro_* functions, rather than in their callers?
> > > I fear it'll be too easy to accidentally forget to use 
> > A_BFD_* in future.
> > 
> >  Agreed, I didn't like the new macros from the very 
> > beginning.  Chao-ying 
> > -- any thoughts?
> 
>   I am fine.  But the new method may be bigger than the A_BFD* method.

 I have placed the translation in macro_map_reloc() now.  That incurs an 
O(n) performance penalty because all relocations in the microMIPS mode 
have to be iterated over the table of mappings; regrettably BFD_RELOC_* 
definitions are sparse so an O(1) lookup table cannot be used.  By keeping 
it sorted some time can be saved, but that's still O(n).  This could be 
reduced to O(log n) with a binary search, but I fear with the limited 
number of relocs handled the overhead would kill the benefit.

 And macro_build_jalr() and macro_build_lui() handle the stuff explicitly 
now.

> > 	(MICROMIPS_TARGET, MICROMIPS_TARGET_LABEL): New macros.
> > 	(micromips_add_number_label): New function.
> 
> +/* For microMIPS macros, we need to generate a local number label
> +   as the target of branches.  */
> +#define MICROMIPS_TARGET	"2147483647f"
> +#define MICROMIPS_TARGET_LABEL	2147483647
> +
> +static void
> +micromips_add_number_label (void)
> +{
> +  symbolS *s;
> +  fb_label_instance_inc (MICROMIPS_TARGET_LABEL);
> +  s = colon (fb_label_name (MICROMIPS_TARGET_LABEL, 0));
> +  S_SET_OTHER (s, ELF_ST_SET_MICROMIPS (S_GET_OTHER (s)));
> +}
> +
> 
> Ugh, this is a bit hackish.  There's nothing stopping a user using
> 2147483647f themselves.

 This is now handled by micromips_label_name(), micromips_label_expr(), 
micromips_label_inc() and micromips_add_label() in a manner similar to 
what dollar_label_name() and fb_label_name(), etc. do, except that the 
special character used in symbols generated is ^_, avoiding a clash.

> > > > 	(macro_start, macro_warning, macro_end): Likewise.
> > > 
> > > +  else if ((subtype & RELAX_DELAY_SLOT_SIZE_ERROR_FIRST)
> > > +	   || (subtype & RELAX_DELAY_SLOT_SIZE_ERROR_SECOND))
> > > +    return _("Macro instruction of the wrong size in a 
> > branch delay slot"
> > > +	     " that requires a 16-bit or 32-bit instruction");
> > > 
> > > Did you consider adding a flag to distinguish the 32-bit 
> > and 16-bit cases?
> > > It'd be nice to be consistent with the non-relaxed error if 
> > possible.
> > 
> >  Chao-ying?  I've had a look actually and flag may not be 
> > necessary to get 
> > the functionality.  I'm fixing this up elsewhere already.
> 
>   I am fine with this functionality. Maybe passing one more parameter to
> macro_warning() can help to distinguish two cases.
 
 Done now.  I have added RELAX_DELAY_SLOT_16BIT now.

 OTOH, I don't think it is possible to get a macro to expand into a single 
16-bit instruction that would be unsuitable for a 32-bit delay slot -- all 
the 16-bit instructions that can be emitted by macros this way have a 
32-bit counterpart that will be used instead.  I think the extra message 
is good for sanity though or in case things change in the future.

> > > +  /* If either one implementation contains one 
> > instruction, we need to check
> > > +     the delay slot size requirement.  */
> > > +  if (mips_macro_warning.num_insns[0] == 1
> > > +      || mips_macro_warning.num_insns[1] == 1)
> > > +    {
> > > +      if (mips_macro_warning.num_insns[0] == 
> > mips_macro_warning.num_insns[1]
> > > +	  && mips_macro_warning.sizes[0] == mips_macro_warning.sizes[1])
> > > +	{
> > > +	  /* Either the macro has a single implementation or both
> > > +	     implementations are 1 instruction with the same size.
> > > +	     Emit the warning now.  */
> > > +	  if ((mips_macro_warning.delay_slot_16bit_p
> > > +	       && mips_macro_warning.sizes[0] != 2)
> > > +	      || (mips_macro_warning.delay_slot_32bit_p
> > > +		  && mips_macro_warning.sizes[0] != 4))
> > > +	    {
> > > +	      const char *msg;
> > > +	      msg = macro_warning (RELAX_DELAY_SLOT_SIZE_ERROR_FIRST);
> > > +	      if (msg != 0)
> > > +		as_warn (msg);
> > > +	    }
> > > +	}
> > > +      else
> > > +	{
> > > +	  relax_substateT subtype;
> > > +
> > > +	  /* Set up the relaxation warning flags.  */
> > > +	  subtype = 0;
> > > +	  if (mips_macro_warning.delay_slot_16bit_p)
> > > +	    {
> > > +	      if (mips_macro_warning.num_insns[0] != 1
> > > +		  || mips_macro_warning.sizes[0] != 2)
> > > +		subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
> > > +	      if (mips_macro_warning.num_insns[1] != 1
> > > +		  || mips_macro_warning.sizes[1] != 2)
> > > +		subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
> > > +	    }
> > > +	  if (mips_macro_warning.delay_slot_32bit_p)
> > > +	    {
> > > +	      if (mips_macro_warning.num_insns[0] != 1
> > > +		  || mips_macro_warning.sizes[0] != 4)
> > > +		subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
> > > +	      if (mips_macro_warning.num_insns[1] != 1
> > > +		  || mips_macro_warning.sizes[1] != 4)
> > > +		subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
> > > +	    }
> > > +
> > > +	  /* One implementation might need a warning but the other
> > > +	     definitely doesn't.  */
> > > +	  mips_macro_warning.first_frag->fr_subtype |= subtype;
> > > +	}
> > > +    }
> > > 
> > > Why not work out the subtype, then check whether both 
> > ERROR_FIRST and
> > > ERROR_SECOND are set?
> > 
> >  Chao-ying?
> 
>   Do you mean this kind of code?
> Ex:
>   if (mips_macro_warning.num_insns[0] == 1
>       || mips_macro_warning.num_insns[1] == 1)
>     {
>       if (mips_macro_warning.delay_slot_16bit_p)
>         {
>           if (mips_macro_warning.num_insns[0] != 1
>               || mips_macro_warning.sizes[0] != 2)
>             subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
>           if (mips_macro_warning.num_insns[1] != 1
>               || mips_macro_warning.sizes[1] != 2)
>             subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
>         }
>       else if (mips_macro_warning.delay_slot_32bit_p)
>         {
>           if (mips_macro_warning.num_insns[0] != 1
>               || mips_macro_warning.sizes[0] != 4)
>             subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
>           if (mips_macro_warning.num_insns[1] != 1
>               || mips_macro_warning.sizes[1] != 4)
>             subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
>         }
> 
>       if ((subtype & RELAX_DELAY_SLOT_SIZE_ERROR_FIRST)
>            && (subtype & RELAX_DELAY_SLOT_SIZE_ERROR_SECOND))
>         {
>           const char *msg;
>           msg = macro_warning (RELAX_DELAY_SLOT_SIZE_ERROR_FIRST); //
> NEED TO PASS 16-bit or 32-bit info
>           if (msg != 0)
>              as_warn (msg);
>         }
>       else
>         {
>           /* One implementation might need a warning but the other
>              definitely doesn't.  */
>           mips_macro_warning.first_frag->fr_subtype |= subtype;
>         }
>     }
> 
> > 
> > > +	  if (mips_macro_warning.delay_slot_p)
> > > +	    {
> > > +	      if (mips_macro_warning.num_insns[0] > 1)
> > > +		subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
> > > +	      if (mips_macro_warning.num_insns[1] > 1)
> > > +		subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
> > > +	    }
> > > 
> > > I don't get why this hunk is needed.  I thought ERROR_FIRST 
> > and ERROR_SECOND
> > > controlled cases where a macro has a single-insn expansion 
> > that is the
> > > wrong size, which ought to be handled by the block above.  
> > If the code
> > > really is needed, you should add a comment explaining why.
> > 
> >  Chao-ying?
> 
> 
>   I agree.  The delay_slot_p check is duplicated, and we can discard it
> for
> ERROR_FIRST and ERROR_SECOND when num_insns[]>1.  My old code
> double-checked the condition for 
> number of instructions in delay slots.

 I have rewritten macro_end() entirely now.  I have changed the approach 
such that if multiple instructions are emitted into a branch delay slot 
and the first of these instructions is out of size, then two warnings are 
produced.

 The rationale is these are different classes of warnings -- the delay 
slot size mismatch is fatal if the call is ever returned from.  Multiple 
instructions may or may not be a problem depending on the actual piece of 
code and author's intentions.  We had a discussion about it a few years 
ago. ;)

 To complete these changes I have modified the change to append_insn() 
such that no warning is produced for a delay slot size mismatch if called 
for a macro expansion as it would get in the way, especially in the case 
of relaxation.  The API of this function had to be modified in a trivial 
way and all the callers adjusted accordingly.

> > > > 	(macro_build): Likewise.
> > > 
> > > +  if (mips_opts.micromips)
> > > +    {
> > > +      if (strcmp (name, "lui") == 0)
> > > +	micromips_macro_build (ep, name, "s,u", args);
> > > +      else if (strcmp (fmt, "d,w,<") == 0)
> > > +	micromips_macro_build (ep, name, "t,r,<", args);
> > > +      else
> > > +	micromips_macro_build (ep, name, fmt, args);
> > > +      va_end (args);
> > > +      return;
> > > +    }
> > > 
> > > A bit of commentary might help explain the letter switch here.
> > 
> >  Chao-ying?
> 
>   Because I didn't change all the code before calling LUI macro for
> microMIPS, I need
> to magically change the operand string for microMIPS to use "s,u" for
> microMIPS LUI.
> "d,w,<" is another case that we need to map it to "t,r,<" for microMIPS.
> If we can search all the places and replace all calls with correct
> operand strings for microMIPS,
> this special code can be dropped.

 I have fixed it up now with the introduction of lui_fmt[] and shft_fmt[].

> > > > 	(macro_build_jalr): Likewise.
> > > 
> > > +  if (mips_opts.micromips)
> > > +    {
> > > +      if (HAVE_NEWABI)
> > > +	macro_build (NULL, "jalr", "t,s", RA, PIC_CALL_REG);
> > > +      else
> > > +	macro_build (NULL, "jalr", "mj", PIC_CALL_REG);
> > > +    }
> > > +  else
> > > +    macro_build (NULL, "jalr", "d,s", RA, PIC_CALL_REG);
> > > 
> > > Why HAVE_NEWABI?  Do you want a 32-bit insn for R_MIPS_JALR?
> > > If so, you should check MIPS_JALR_HINT_P (ep) instead.
> > 
> >  Chao-ying?
> 
>   OK.  This code is done before I put the R_MIPS_JALR patch into GAS and
> LD.
> The new code is as follows.
> Ex:
> static void
> macro_build_jalr (expressionS *ep)
> {
>   char *f = NULL;
> 
>   if (MIPS_JALR_HINT_P (ep))
>     {
>       frag_grow (8);
>       f = frag_more (0);
>     }
>   if (mips_opts.micromips)
>     macro_build (NULL, "jalr", "t,s", RA, PIC_CALL_REG);
>   else
>     macro_build (NULL, "jalr", "d,s", RA, PIC_CALL_REG);
>   if (MIPS_JALR_HINT_P (ep))
>     fix_new_exp (frag_now, f - frag_now->fr_literal,
>                  4, ep, FALSE, A_BFD_RELOC_MIPS_JALR); // THIS MAY BE
> FIXED BY A NEW METHOD.
> }
> 
>   And, we need to modify elfxx-mips.c to support
> BFD_RELOC_MICROMIPS_JALR to convert jalr to bal for microMIPS.

 Per your suggestion, I have made this piece use MIPS_JALR_HINT_P() to 
select the jump now.  Also since for PIC the delay slot is always a NOP in 
the reorder mode, I switched to the use of JALRS in this case.

> +    case BFD_RELOC_MICROMIPS_7_PCREL_S1:
> +    case BFD_RELOC_MICROMIPS_10_PCREL_S1:
> +    case BFD_RELOC_MICROMIPS_16_PCREL_S1:
> +      /* We adjust the offset back to even.  */
> +      if ((*valP & 0x1) != 0)
> +	--(*valP);
> +
> +      if (! fixP->fx_done)
> +	break;
> +
> +      /* Should never visit here, because we keep the relocation.  */
> +      abort ();
> +      break;
> 
> I suppose this silently ignores branches to non-microMIPS code,
> but there again, so does the MIPS16 equivalent...

 As noted previously, some diagnostics would be useful, but let's call it 
a future enhancement.  [FIXME]

> >> > 	(mips_relax_frag): Handle microMIPS.
> >> 
> >> +     gas_assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2
> >> +	      || 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);
> >> +
> >> +      /* For 7/10 PCREL_S1, we just need to use 
> >> fixp->fx_addnumber.  */
> >> +      if (fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
> >> +	  || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1)
> >> +	reloc->addend = fixp->fx_addnumber;
> >> +      else
> >> +	/* At this point, fx_addnumber is "symbol offset - 
> >> pcrel address".
> >> +	   Relocations want only the symbol offset.  */
> >> +	reloc->addend = fixp->fx_addnumber + reloc->address;
> >> 
> >> A better comment is needed.  _Why_ do you just need fx_addnumber?
> >> 
> >
> >   Thanks for the review!  The explanation is in another place as
> > follows.
> > Maybe we need to copy the comment to tc_gen_reloc from md_pcrel_from.
> > Ex:
> > long
> > md_pcrel_from (fixS *fixP)
> > {
> >   valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
> >   switch (fixP->fx_r_type)
> >     {
> >     /* We don't add addr, because it will cause the error checking of
> >        "addnumber" fail in write.c for *7/10_PCREL_S1.
> >         In tc_gen_reloc, we just use fixp->fx_addnumber.  */
> >     case BFD_RELOC_MICROMIPS_7_PCREL_S1:
> >     case BFD_RELOC_MICROMIPS_10_PCREL_S1:
> >       /* Return the beginning of the delay slot from the current insn.
> > */
> >       return 2;
> >
> >     case BFD_RELOC_MICROMIPS_16_PCREL_S1:
> >     case BFD_RELOC_MICROMIPS_JMP:
> >     case BFD_RELOC_16_PCREL_S2:
> >     case BFD_RELOC_MIPS_JMP:
> >       /* Return the address of the delay slot.  */
> >       return addr + 4;
> > ...
> >   The field of *7/10_PCREL_S1 is limited in the 16-bit instructions.
> > If we add the "address", write.c will fail to check these two
> > relocations due to overflow or something (I kind of forgot). From
> > debugging, adding "address" is no use at all, because later "address" is
> > subtracted.
> 
> Ah, thanks, that's a good explanation.  Yeah, at least a cross-reference
> would be useful if we keep things as they are.  However...
> 
> ...I think you mean this bit of write.c:
> 
> 	  if (fixP->fx_size < sizeof (valueT) && 0)
> 	    {
> 	      valueT mask;
> 
> 	      mask = 0;
> 	      mask--;		/* Set all bits to one.  */
> 	      mask <<= fixP->fx_size * 8 - (fixP->fx_signed ? 1 : 0);
> 	      if ((add_number & mask) != 0 && (add_number & mask) != mask)
> 		{
> 		  char buf[50], buf2[50];
> 		  sprint_value (buf, fragP->fr_address + fixP->fx_where);
> 		  if (add_number > 1000)
> 		    sprint_value (buf2, add_number);
> 		  else
> 		    sprintf (buf2, "%ld", (long) add_number);
> 		  as_bad_where (fixP->fx_file, fixP->fx_line,
> 				_("value of %s too large for field of %d bytes
> at %s"),
> 				buf2, fixP->fx_size, buf);
> 		} /* Generic error checking.  */
> 	    }
> 
> That check's bogus for these relocations anyway, since it doesn't take
> the implied shift into account.  I think there's an argument to say
> we should set fx_no_overflow for these relocations and leave the
> overflow checking to bfd.  You'll still get a "relocation overflow"
> error if the final in-place addend really is too big.

 After some investigation I decided to follow your suggestion.  I have 
removed this change and the corresponding one from tc_gen_reloc() and 
adjusted md_convert_frag() instead.

 My general conclusion is fixup_segment() code fragment you quoted is 
essentially broken and has to be rewritten.  For the MIPS target it works 
by chance and does not perform any useful check.  It shouldn't be checking 
the size of the data chunk being relocated, but the size of the 
relocatable field only and take the shift value into account.  This is all 
available from the associated HOWTO structure that can be easily obtained 
here.

> > > > 	(md_convert_frag): Likewise.
> > > 
> > > -      /* Possibly emit a warning if we've chosen the 
> > longer option.  */
> > > -      if (((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
> > > -	  == ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))
> > > +      if (!(fragp->fr_subtype & RELAX_USE_SECOND))
> > > +  	{
> > > +	  /* Check if the size in branch delay slot is ok.  */
> > > +	  if (fragp->fr_subtype & RELAX_DELAY_SLOT_SIZE_ERROR_FIRST)
> > > +	    {
> > > +	      const char *msg = macro_warning (fragp->fr_subtype);
> > > +	      if (msg != 0)
> > > +		as_warn_where (fragp->fr_file, fragp->fr_line, msg);
> > > +	    }
> > > +	}
> > > +      else
> > >  	{
> > > -	  const char *msg = macro_warning (fragp->fr_subtype);
> > > -	  if (msg != 0)
> > > -	    as_warn_where (fragp->fr_file, fragp->fr_line, "%s", msg);
> > > +	  /* Check if the size in branch delay slot is ok.
> > > +	     Possibly emit a warning if we've chosen the longer 
> > option.  */
> > > +	  if ((fragp->fr_subtype & RELAX_DELAY_SLOT_SIZE_ERROR_SECOND)
> > > +	      || (fragp->fr_subtype & RELAX_SECOND_LONGER))
> > > +	    {
> > > +	      const char *msg = macro_warning (fragp->fr_subtype);
> > > +	      if (msg != 0)
> > > +		as_warn_where (fragp->fr_file, fragp->fr_line, msg);
> > > +	    }
> > >  	}
> > > 
> > > This doesn't accurately preserve the previous:
> > > 
> > >       if (((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
> > > 	  == ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))
> > > 
> > > behaviour.
> > 
> >  Chao-ying?
> 
>   How about this?
> 
> Ex:
> 
>       if ((((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
>            == ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))
>           || (!(fragp->fr_subtype & RELAX_USE_SECOND)
>               && (fragp->fr_subtype &
> RELAX_DELAY_SLOT_SIZE_ERROR_FIRST))
>           || ((fragp->fr_subtype & RELAX_USE_SECOND)
>               && (fragp->fr_subtype &
> RELAX_DELAY_SLOT_SIZE_ERROR_SECOND)))
>         {
>           const char *msg = macro_warning (fragp->fr_subtype); // MAY
> NEED TO PASS 16-bit or 32-bit info
>           if (msg != 0)
>             as_warn_where (fragp->fr_file, fragp->fr_line, "%s", msg);
>         }

 I have rewritten it entirely now, matching changes to macro_end().  Two 
warnings are emitted if multiple instructions are emitted into a branch 
delay slot and the first of these instruction is out of size like with 
macro_end().

> > > > 	(micromips_ip): New function.
> > > 
> > > +      /* Try to search "16" or "32" in the str.  */
> > > +      if ((t = strstr (str, "16")) != NULL && t < save_s)
> > > +	{
> > > +	  /* Make sure "16" is before the first '.' if '.' exists.  */
> > > +	  if ((s = strchr (str, '.')) != NULL && (t + 2 != s))
> > > +	    {
> > > +	      insn_error = "unrecognized opcode";
> > > +	      return;
> > > +	    }
> > > +
> > > +	  /* Make sure "16" is at the end of insn name, if no '.'.  */
> > > +	  if ((s = strchr (str, '.')) == NULL
> > > +	      && (!ISSPACE (*(t + 2)) && *(t + 2) != '\0'))
> > > +	    {
> > > +	      insn_error = "unrecognized opcode";
> > > +	      return;
> > > +	    }
> > > +
> > > +	  micromips_16 = TRUE;
> > > +	  for (s = t + 2; *s != '\0'; ++s)
> > > +	    *(s - 2) = *s;
> > > +	  *(s - 2) = '\0';
> > > +
> > > +	  for (s = t; *s != '\0' && !ISSPACE (*s); ++s)
> > > +	    continue;
> > > +
> > > +	  if (ISSPACE (*s))
> > > +	    {
> > > +	      save_c = *s;
> > > +	      *s++ = '\0';
> > > +	    }
> > > +
> > > +	  if ((insn = (struct mips_opcode *) hash_find 
> > (micromips_op_hash, str))
> > > +	      == NULL)
> > > +	    {
> > > +	      int i;
> > > +	      int length;
> > > +	      micromips_16 = FALSE;
> > > +
> > > +	      /* Restore the character we overwrite above (if any).  */
> > > +	      if (save_c)
> > > +		*(--s) = save_c;
> > > +
> > > +	      length = strlen (str);
> > > +	      for (i = length - 1; &str[i] >= t; i--)
> > > +		{
> > > +		  str[i + 2] = str[i];
> > > +		  if (t == &str[i])
> > > +		    {
> > > +		      str[i + 1] = '6';
> > > +		      str[i] = '1';
> > > +		      str[length + 2] = '\0';
> > > +		      break;
> > > +		    }
> > > +		}
> > > +
> > > +	      insn_error = "unrecognized 16-bit version of 
> > microMIPS opcode";
> > > +	      return;
> > > +	    }
> > > +	}
> > > +      else if ((t = strstr (str, "32")) != NULL && t < save_s)
> > > +	{
> > > +	  /* For some instruction names, we already have 32, so we need
> > > +	     to seek the second 32 to process.  Ex: bposge3232, 
> > dsra3232.  */
> > > +	  char *new_t;
> > > +	  if ((new_t = strstr (t + 2, "32")) != NULL && new_t < save_s)
> > > +	    t = new_t;
> > > +
> > > +	  /* Make sure "32" is before the first '.' if '.' exists.  */
> > > +	  if ((s = strchr (str, '.')) != NULL && (t + 2 != s))
> > > +	    {
> > > +	      insn_error = "unrecognized opcode";
> > > +	      return;
> > > +	    }
> > > +
> > > +	  /* Make sure "32" is at the end of the name, if no '.'.  */
> > > +	  if ((s = strchr (str, '.')) == NULL
> > > +	      && (!ISSPACE (*(t + 2)) && *(t + 2) != '\0'))
> > > +	    {
> > > +	      insn_error = "unrecognized opcode";
> > > +	      return;
> > > +	    }
> > > +
> > > +	  micromips_32 = TRUE;
> > > +	  for (s = t + 2; *s != '\0'; ++s)
> > > +	    *(s - 2) = *s;
> > > +	  *(s - 2) = '\0';
> > > +
> > > +	  for (s = t; *s != '\0' && !ISSPACE (*s); ++s)
> > > +	    continue;
> > > +
> > > +	  if (ISSPACE (*s))
> > > +	    {
> > > +	      save_c = *s;
> > > +	      *s++ = '\0';
> > > +	    }
> > > +
> > > +	  if ((insn = (struct mips_opcode *) hash_find 
> > (micromips_op_hash, str))
> > > +	      == NULL)
> > > +	    {
> > > +	      int i;
> > > +	      int length;
> > > +	      micromips_32 = FALSE;
> > > +
> > > +	      /* Restore the character we overwrite above (if any).  */
> > > +	      if (save_c)
> > > +		*(--s) = save_c;
> > > +
> > > +	      length = strlen (str);
> > > +	      for (i = length - 1; &str[i] >= t; i--)
> > > +		{
> > > +		  str[i + 2] = str[i];
> > > +		  if (t == &str[i])
> > > +		    {
> > > +		      str[i + 1] = '2';
> > > +		      str[i] = '3';
> > > +		      str[length + 2] = '\0';
> > > +		      break;
> > > +		    }
> > > +		}
> > > +
> > > +	      insn_error = "unrecognized 32-bit version of 
> > microMIPS opcode";
> > > +	      return;
> > > +	    }
> > > 
> > > Far too much cut-&-paste between the "16" and "32" cases.  Also:
> > > 
> > > +      if ((t = strstr (str, "16")) != NULL && t < save_s)
> > > 
> > > t < save_s must surely be true, since save_s is the null terminator.
> 
>   Yes.  I used t < save_s, because I don't know save_s points to NULL at
> this point.
> We can discard save_s now.
> 
> > > 
> > > +	  /* Make sure "16" is before the first '.' if '.' exists.  */
> > > +	  if ((s = strchr (str, '.')) != NULL && (t + 2 != s))
> > > +	    {
> > > +	      insn_error = "unrecognized opcode";
> > > +	      return;
> > > +	    }
> > > +
> > > +	  /* Make sure "16" is at the end of insn name, if no '.'.  */
> > > +	  if ((s = strchr (str, '.')) == NULL
> > > +	      && (!ISSPACE (*(t + 2)) && *(t + 2) != '\0'))
> > > +	    {
> > > +	      insn_error = "unrecognized opcode";
> > > +	      return;
> > > +	    }
> > > 
> > > Don't call strchr (str, '.') twice like that.  Better would be:
> > > 
> > > 	s = strchr (str, '.');
> 
>   Yes.
> 
> > > 
> > > followed by the two checks.  Isn't the ISSPACE check 
> > redundant though,
> > > given that you've terminated the string at the first space?  I would
> > > have thought:
> > > 
> > >         if (t + 2 != (s ? s : save_s))
> > > 
> > > would be enough.  Errors should start with a capital 
> > letter.  Missing
> > > internationalisation.
> > 
> >  Chao-ying?
> 
>   Yes. "if (t + 2 != (s ? s : save_s))" is enough.
> 
> > 
> > > You could use alloca to create an opcode without the "16" or "32",
> > > which would make the error-reporting code simpler.  It's best not
> > > to change the user's source line if we can help it.
> > 
> >  Agreed.
> 
>   Yes.
> 
> > 
> > > +	      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;
> > > +		}
> > > +	      if (save_c)
> > > +		*(--s) = save_c;
> > > +
> > > +	      if (micromips_16 || micromips_32)
> > > +		{
> > > +		  int i;
> > > +		  int length;
> > > +
> > > +		  length = strlen (str);
> > > +		  for (i = length - 1; i >= 0; i--)
> > > +		    {
> > > +		      str[i + 2] = str[i];
> > > +		      if (t == &str[i])
> > > +			break;
> > > +		    }
> > > +		  if (micromips_16)
> > > +		    {
> > > +		      insn_error =
> > > +			"unrecognized 16-bit version of 
> > microMIPS opcode";
> > > +		      str[i + 1] = '6';
> > > +		      str[i] = '1';
> > > +		    }
> > > +		  else
> > > +		    {
> > > +		      insn_error =
> > > +			"unrecognized 32-bit version of 
> > microMIPS opcode";
> > > +		      str[i + 1] = '2';
> > > +		      str[i] = '3';
> > > +		    }
> > > +		  str[length + 2] = '\0';
> > > +		}
> > > +	      return;
> > > 
> > > Why override the insn_error unconditionally like this?  E.g.:
> > > 
> > > 	jar16	$30,$26
> > > 
> > >     Error: unrecognized 16-bit version of microMIPS opcode 
> > `jar16 $30,$26'
> > > 
> > > implies there's a 32-bit opcode.  I'd also have thought that the
> > > "opcode not supported on this processor" would triumph if 
> > it applies.
> > 
> >  The error you've seen comes from the previous hunk above 
> > rather than this 
> > one which I think is unnecessary code duplication.  It's all rather 
> > over-complicated and I'm working on getting it polished.  

 I have rewritten it from scratch using alloca() as you suggested and 
reducing the whole stuff to a small loop executed once or twice.  This 
enabled chunks of code to be shaved off elsewhere too.

 Your JAR16 case is now handled correctly and I have put together test 
cases to cover some of this stuff, hopefully exhaustively.

> > too.  Also the original loop seems ill-formed to me, with 
> > most of code 
> > intended to be executed at most once, after the loop's terminating 
> > condition triggered -- i.e. that shouldn't be in the loop in 
> > the first 
> > place.
> 
>   What code in the loop do you refer to?  I am not clear.

 One that follows "argsStart = s".  My conclusion turned out unjustified 
as there are "continue" statements throughout -- I got confused, sorry.

> > 	* ld-mips-elf/jalx-2-main.s: New.
> > 	* ld-mips-elf/jalx-2.dd: New.
> > 	* ld-mips-elf/jalx-2-ex.s: New.
> > 	* ld-mips-elf/jalx-2-printf.s: New.
> > 	* ld-mips-elf/mips-elf.exp: Run new test.
> 
> Please make the .dd output less susceptible to things like the number
> of sections, size of program headers, etc.  One way is to use a linker
> script to place each section at a nice round address.  Another is to
> ".*" out the addresses and instruction encodings and just reply on
> the symbolic part of the disassembly.  I think the former's better
> here.  There are quite a few existing examples.

 Fixed by Catherine -- thanks!

> >  Stricly speaking some changes, while related, can be split off too (e.g. 
> > some MIPS16 or testsuite changes), so I'll look into separating them too 
> > -- perhaps that'll make the thing rolling sooner.
> 
> Yeah, thanks, that'd be a help if it's easy to do.  It doesn't matter
> too much, though.  Most of the MIPS16 changes were consistent with the
> microMIPS ones, so were easy to review as a unit.

 I was more concerned about grouping functionally independent changes 
together.  While it may be OK for the review, it often bites later on, 
when someone makes excavations on the repository trying to figure out the 
original change.

 Anyway I did that as you know and it helped with the PIC JAL changes.

> >> From a usability perspective, it's a shame that:
> >> 
> >> 	.set	micromips
> >> 	.ent	foo
> >> foo:
> >> 	b	1f
> >> 	nop
> >> 	.end	foo
> >> 	.ent	bar
> >> bar:
> >> 1:	nop
> >> 	.end	bar
> >> 
> >> disassembles as:
> >> 
> >> 00000000 <foo>:
> >>    0:   cfff            b       0 <foo>
> >>                         0: R_MICROMIPS_PC10_S1  .L11
> >>    2:   0c00            nop
> >>    4:   0c00            nop
> >> 
> >> 00000006 <bar>:
> >>    6:   0c00            nop
> >> 
> >> leaving the poor user with no idea what .L11 is.
> >
> >  Indeed.  This is a general limitation of `objdump' it would seem.  This 
> > is no different to what you get with:
> >
> > $ cat b.s
> > 	.globl	baz
> > 	.ent	foo
> > foo:
> > 	b	baz
> > 	nop
> > 	.end	foo
> > 	.ent	bar
> > baz:
> > bar:
> > 1:	nop
> > 	.end	bar
> > $ mips-sde-elf-objdump -dr b.o
> >
> > b.o:     file format elf32-tradbigmips
> >
> >
> > Disassembly of section .text:
> >
> > 00000000 <foo>:
> >    0:	1000ffff 	b	0 <foo>
> > 			0: R_MIPS_PC16	baz
> >    4:	00000000 	nop
> >    8:	00000000 	nop
> >
> > 0000000c <bar>:
> >    c:	00000000 	nop
> 
> Well, it's a little different.  The user has at least defined two
> named symbols in this case, so they have a good chance of knowing
> what "baz" means.  In the microMIPS case we've invented a label
> and are using it in preference to the user-defined one.

 That's unfortunate, indeed.  [FIXME]

> > I'd just recommend peeking at the symbol table (back to the first 
> > program):
> >
> > $ mips-sde-elf-objdump -t b.o
> >
> > b.o:     file format elf32-tradbigmips
> >
> > SYMBOL TABLE:
> > 00000000 l    d  .text	00000000 .text
> > 00000000 l    d  .data	00000000 .data
> > 00000000 l    d  .bss	00000000 .bss
> > 00000000 l    d  .reginfo	00000000 .reginfo
> > 00000000 l    d  .pdr	00000000 .pdr
> > 00000000 l     F .text	00000006 0x80 foo
> > 00000006 l     F .text	00000002 0x80 bar
> > 00000006 l       .text	00000000 0x80 .L1^B1
> 
> I suppose having a symbol with ^B in it is less than ideal too.
> AIUI that name was chosen specifically because it wasn't supposed
> to be written out.
> 
> It would be especially confusing if the user or compiler had a ".L11"
> label (without the ^B).

 Actually this is a tough problem -- we need to emit a generated symbol 
that does not clash with anything the user or GCC may have put in the 
source.  Any ideas?  How is it done in other ports if anywhere?

> >> The following:
> >> 
> >> 	.set	micromips
> >> 	.ent	foo
> >> foo:
> >> 	ld	$10,0x1000($11)
> >> 	.end	foo
> >> 
> >> generates an assertion failure:
> >> 
> >> Assertion failure in micromips_macro_build at gas/config/tc-mips.c line
> 19466.
> >> Please report this bug.
> >> 
> >> on mipsisa64-elf with "-mips1 -mabi=32".
> >
> >  I can't reproduce it, sorry:
> > [...]
> >  Can you debug it and see what the relocation type is that's causing it?  
> > I wonder if that might be related to the varargs issue you referring to 
> > below and depend on the host architecture, hmm...
> 
> Yeah, you're right, sorry.  I forgot to mention that in the later reviews.
> This was with a x86_64-linux-gnu host and a botched attempt at working
> around the varags issue.  (I probably just added -Wno-error or something,
> I can't remember now.)
> 
> I switched to a 32-bit host for parts 2 and 3 of the review, and yeah,
> it doesn't reproduce there.

 I have updated this code to pass varargs by a reference.  Note that 
mips16_macro_build() also attempts to pass them by value which I gather 
from some discussions I have tracked down is a grey area of the C language 
standard.  Sent as separate patch.

> +/* Whether code compression (either of the MIPS16 or the microMIPS ASEs has
> 
> s/ASEs has/ASEs) has/

 Fixed.

> +  if (mips_opts.micromips)
> +    return is_micromips_16bit_p (insn->insn_mo)
> +         ? 2 : (is_micromips_32bit_p (insn->insn_mo) ? 4 : 6);
> 
> This formatting isn't quite right because of the "emacs brackets" rule.

 Yeah, now that you mention it, I seem to recall there was something like
this...

> Should be:
> 
>     return (is_micromips_16bit_p (insn->insn_mo)
>             ? 2 : is_micromips_32bit_p (insn->insn_mo) ? 4 : 6);
> 
> or:
> 
>     return (is_micromips_16bit_p (insn->insn_mo) ? 2
>             : is_micromips_32bit_p (insn->insn_mo) ? 4 : 6);

 Fixed.

> But I'd be happy with an if-return-if-return-return chain too.

 Conditional expressions seem to go with the spirit of this function. ;)

> See below about these insns though...
> -+  if (!mips_opts.mips16 && !mips_opts.micromips)
> ++  if (! HAVE_CODE_COMPRESSION)
> 
> The GCC decision a few years back was that no space should be added
> after a unary operator (as with pointer deference, etc).  Not important
> enough to do a sed on the whole source base, but we might as well avoid
> changes that go the other way (from no space to space) in GAS.

 I didn't know it was standardised at one point.  The justification for my
style is the exclamation mark may easily be missed by the reader if next
to a bracket (and she happens not to be eagle-eyed), but I have adjusted
changes accordingly now.

> +static bfd_boolean
> +is_size_valid (const struct mips_opcode *mo)
> +{
> +  gas_assert (mips_opts.micromips);
> +
> +  if ((micromips_16 || micromips_32) && mo->pinfo == INSN_MACRO)
> +    return FALSE;
> +  if (micromips_16 && ! is_micromips_16bit_p (mo))
> +    return FALSE;
> +  if (micromips_32 && ! is_micromips_32bit_p (mo))
> +    return FALSE;
> +
> +  return TRUE;
> +}
> 
> Hmm, seeing this highlighted more makes me wonder whether
> micromips_16 and micromips_32 shouldn't be combined into a
> single variable that represents "the size the user set",
> with 0 meaning "none".  As it stands, we'll have checks like:
> 
>   micromips_16 || micromips_32 || micromips_48
> 
> when any future 48-bit support is added.  Having separate variables
> also gives the impression that arbitrary combinations are possible.

 Good point.  I have merged these with mips16_small and mips16_ext and 
replaced all of them with forced_insn_length.

> Also, how about replacing is_micromips_XXbit_p with a function
> that just returns the size of a micromips insn?  We generally
> deal with byte rather than bit lengths, so both this new function
> and the combined "the size the user set" variable should probably
> both be byte values.

 FYI, that's what I did when implementing GDB support (that'll follow
sometime in the future; obviously it depends on some changes to BFD and
opcode made here), so I see no reason why we shouldn't do that here
either, good point.  I have merged these into micromips_insn_length() now.

> Seems the code would be a fair bit clearer with those changes,
> but maybe I'm wrong...

 No, not a sausage. ;)

> Maybe the mo->match assertions in is_micromips_XXbit_p are better
> done in validate_micromips_insn -- especially if that makes the
> changes above easier -- but I don't mind either way.

 Not necessarily any easier for micromips_insn_length(), but it looks like 
the right place for these tests, so I moved them over, changing some 
negative opcode match tests into positive ones, so as to no value escapes 
by accident.  Also the advertised argument check was missing from 
validate_micromips_insn(), which I have now added, fixing a couple of bugs 
throughout it diagnosed.

> char
> mips_nop_opcode (void)
> {
>   if (seg_info (now_seg)->tc_segment_info_data.micromips)
>     return NOP_OPCODE_MICROMIPS;
>  
>   return seg_info (now_seg)->tc_segment_info_data.mips16
>         ? NOP_OPCODE_MIPS16 : NOP_OPCODE_MIPS;
> }
> 
> Same "emacs brackets" thing here.  Seems odd to treat microMIPS and MIPS16
> differently like this, so I think if-return-if-return-return makes more
> sense.

 Agreed, this function looks better with conditional statements.  Fixed.

> The new mips_handle_align looks very good, thanks.  I'm afraid it's another
> silly nitpick, but usual style is not to have the brackets in "*(p++)".

 I tend to add brackets where operator precedence is not immediately
obvious to the reader.  In this case I would have to double-check with the
language standard, so I assumed so would have the reader.

 The order of precedence seems natural here for processors with a
post-increment addressing mode, but not everyone has heard of those I
suppose.  I removed the brackets anyway.

> Part 2 of the review.
> 
> This testcase:
> 
> 	.set	micromips
> 	.fill	0x80
> 	b16	.-0x80
> 
> produces:
> 
> /tmp/foo.s: Assembler messages:
> /tmp/foo.s:3: Error: unrecognized opcode `b16 .-0x80'
> 
> while:
> 
> 	.set	micromips
> 	.fill	0x80
> 	b	.-0x80
> 
> successfully produces a 16-bit insn.

 Fixed as a result of earlier changes.

> @@ -14813,6 +16230,8 @@ mips_elf_final_processing (void)
>       file_ase_mt is true.  */
>    if (file_ase_mips16)
>      elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_M16;
> +  if (file_ase_micromips)
> +    elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_MICROMIPS;
>  #if 0 /* XXX FIXME */
>    if (file_ase_mips3d)
>      elf_elfheader (stdoutput)->e_flags |= ???;
> 
> Do you really only want this flag to be set if -mmicromips was passed
> on the command line?  (Yes, the same concern applies to MIPS16 and MDMX.)

 Fixing it up is easy, but I'm not sure what the original intent of these 
flags has been.  Do they mean:

1. I make use of the FOO feature and I assert it is available?

2. I make use of the FOO feature, but I may go and figure out if it's 
   available?

3. I make use of the FOO feature and want to prevent linking with any
   incompatible ones?

Once we've determined the answer we may modify code accordingly or leave 
it as it is.  It looks to me the current approach matches #1 and the ELF 
program loader may refuse to execute the program if it sees a flag for a 
feature that is not supported by the processor to run on.  Any .set 
fragments within the program are guarded appropriately and hence they do 
not need to set the flag (as it would be for #2).  Then #3 is sort of 
tangential to the two others, but it does matter in this context, hence I 
mentioned it (i.e. if #3 was true, then I'd be much happier with #3 & #1 
than #3 & #2; otherwise I don't have a strong preference between #1 and 
#2).

 Current arrangement is similar to that of file_mips_isa even though the 
ISA can be overridden by .set too and I think it makes sense to keep all 
these flags consistent.

 Any thoughts, anyone?

> Lots of cases where a space is missing before "(".

 I fix these kinds of errors as I notice them -- some must have obviously 
escaped me, sorry.  I find it easier to write properly formatted code from 
the beginning than to fix it afterwards, but there you go.

 Overall I think it would be a good idea to run `indent' over upstream 
files we are concerned about at one point (there are plenty of small 
problems throughout that sneaked in unnoticed and accumulated over the 
time) and then fixing up most of such problems would amount to rerunning 
`indent' with the patch in question applied -- without the problem of 
reformatting half of the preexisting source code as a side effect.

 At least `quilt' warns about trailing white space added (and has an 
option to strip it automatically) -- I have cleaned up several places this 
way.

> Please be consistent about "str[n]cmp (...) == 0" vs '!str[n]cmp (...)':
> use one or the other.  (IMO the first is clearer.)

 FWIW I agree first is clearer.  I have fixed the couple of others -- they 
looked like copied & pasted from existing code though.

> micromips_ip obviously started life as a cut-&-paste of mips_ip, and it
> would have been nice to factor some code out.  At least split out the
> block beginning:
> 
> +	    case 'F':
> +	    case 'L':
> +	    case 'f':
> +	    case 'l':
> +	      {
> 
> which is identical between the two, and far too subtle to copy wholesale.
> There may be other good opportunities too.

 Next time, I'm afraid. [FIXME]

> +	    case '(':
> +	      /* Handle optional base register.
> +		 Either the base register is omitted or
> +		 we must have a left paren.  */
> +	      /* This is dependent on the next operand specifier
> +		 is a base register specification.  */
> +	      gas_assert (args[1] == 'b'
> +		      || (args[1] == 'm'
> +			  && (args[2] == 'l' || args[2] == 'n'
> +			      || args[2] == 's' || args[2] == 'a')));
> +	      if (*s == '\0' && args[1] == 'b')
> +		return;
> +
> +	    case ')':		/* these must match exactly */
> +	    case '[':
> +	    case ']':
> +	      if (*s++ == *args)
> +		continue;
> +	      break;
> 
> Mark fallthrough.

 Another copy & paste case -- fixed (and removed support for [] as 
irrelevant).

> +	    case 'D':		/* floating point destination register */
> +	    case 'S':		/* floating point source register */
> +	    case 'T':		/* floating point target register */
> +	    case 'R':		/* floating point source register */
> +	    case 'V':
> +	      rtype = RTYPE_FPU;
> +	      s_reset = s;
> +	      if (reg_lookup (&s, rtype, &regno))
> +		{
> +		  if ((regno & 1) != 0
> +		      && HAVE_32BIT_FPRS
> +		      && ! mips_oddfpreg_ok (ip->insn_mo, argnum))
> +		    as_warn (_("Float register should be even, was %d"),
> +			     regno);
> +
> +		  c = *args;
> +		  if (*s == ' ')
> +		    ++s;
> +		  if (args[1] != *s)
> +		    {
> +		      if (c == 'V' || c == 'W')
> +			{
> +			  regno = lastregno;
> +			  s = s_reset;
> +			  ++args;
> +			}
> +		    }
> +		  switch (c)
> +		    {
> +		    case 'D':
> +		      MICROMIPS_INSERT_OPERAND (FD, *ip, regno);
> +		      break;
> +		    case 'V':
> +		    case 'S':
> +		      MICROMIPS_INSERT_OPERAND (FS, *ip, regno);
> +		      break;
> +
> +		    case 'T':
> +		      MICROMIPS_INSERT_OPERAND (FT, *ip, regno);
> +		      break;
> +
> +		    case 'R':
> +		      MICROMIPS_INSERT_OPERAND (FR, *ip, regno);
> +		      break;
> +		    }
> +		  lastregno = regno;
> +		  continue;
> +		}
> +
> +	      switch (*args++)
> +		{
> +		case 'V':
> +		  MICROMIPS_INSERT_OPERAND (FS, *ip, lastregno);
> +		  continue;
> +		case 'W':
> +		  MICROMIPS_INSERT_OPERAND (FT, *ip, lastregno);
> +		  continue;
> +		}
> +	      break;
> 
> This block doesn't have a 'W' case (which doesn't seem to be used
> for micromips at all), so all the 'W' handling is dead code.

 Fixed.  There's some suspicious code around 'V' here and in mips_ip() 
BTW -- it doesn't seem right to me to do args++ here even if it seems to 
work. [FIXME]

> +			    case  4:
> +			    case  5:
> +			    case  6:
> 
> Too many spaces.

 Fixed.

> +      if (insn + 1 < &micromips_opcodes[bfd_micromips_num_opcodes] &&
> +	  !strcmp (insn->name, insn[1].name))
> 
> Misplaced "&&".

 Another copy & paste case -- fixed.

> +    = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};;
> 
> Double ";".

 Fixed.

> +	  macro_read_relocs (&args, r);
> 
> Not portable in this context (and doesn't build on x86_64-linux-gnu).
> You're taking the address of a va_list argument rather than a va_list
> local variable.

 Fixed, as noted already.

> +	  /*  For microMIPS, we always use relocations for branches.
> +	      So, we should not resolve immediate values.  */
> 
> Too many spaces.

 Fixed.

> +	  if (ep->X_op == O_constant)
> +	    abort ();
> +	  else
> +	    *r = BFD_RELOC_MICROMIPS_16_PCREL_S1;
> 
> gcc_assert (ep->X_op != O_constant);
> *r = BFD_RELOC_MICROMIPS_16_PCREL_S1;

 Fixed.

> The same cut-&-paste concerns apply to micromips_macro, which obviously
> started out as a copy of macro().  I realise there are special cases
> for micromips (such as the DADDI assymmetry and the lack of
> branch-likely instructions, to name only a few), but most of the
> basic decisions are the same.
> 
> As it stands, we have a new 3524 line function, of which I imagine at
> least 90% is shared with macro().  I really think the new microMIPS
> macro handling should be integrated into macro() instead.  Don't be
> afraid of factoring out code from macro() if it makes it easier to
> integrate the microMIPS code.

 Can we make it a follow-up patch sometime in the future?  I'm not afraid 
of factoring code out of anywhere (I'm speaking of myself only of course), 
but at this point the effort is about the same as writing this whole stuff 
from scratch. :( [FIXME]

>  #define CPU_MIPS5       5
>  #define CPU_MIPS64      64
>  #define CPU_MIPS64R2	65
> +#define CPU_MICROMIPS	96
>  #define CPU_SB1         12310201        /* octal 'SB', 01.  */
>  #define CPU_LOONGSON_2E 3001
>  #define CPU_LOONGSON_2F 3002
> 
> What's this for?  It doesn't seem to be used.

 Dumped.  Whoever will need it can add it back.

> +   "mA" 7-bit immediate (-63 .. 64) << 2 (MICROMIPSOP_*_IMMA)
> 
> Don't you mean (-64 .. 63)?

 Yes, this is for LWGP.

> +   "mB" 3-bit immediate (0, -1, 1, 4, 8, 12, 16, 20, 24) (MICROMIPSOP_*_IMMB)
> 
> That's nine values.  Should the 0 really be there?

 No, fixed (this is for ADDIUR2, so wasting a precious encoding of an 
immediate would be a bad idea).

> @@ -630,15 +630,15 @@ proc strip_executable { prog flags test 
>  	remote_upload host ${copyfile} tmpdir/striprog
>      }
>  
> -    set result [remote_load target tmpdir/striprog]
> -    set status [lindex $result 0]
> -    if { ![istarget $host_triplet] } {
> -      set status "pass"
> -    }
> -    if { $status != "pass" } {
> -	fail $test
> -        return
> -    }
> +#    set result [remote_load target tmpdir/striprog]
> +#    set status [lindex $result 0]
> +#    if { ![istarget $host_triplet] } {
> +#      set status "pass"
> +#    }
> +#    if { $status != "pass" } {
> +#	fail $test
> +#        return
> +#    }
>  
>      set exec_output [binutils_run $NM "$NMFLAGS ${copyfile}"]
>      if ![string match "*: no symbols*" $exec_output] {
> @@ -673,15 +673,15 @@ proc strip_executable_with_saving_a_symb
>  	remote_upload host ${copyfile} tmpdir/striprog
>      }
>  
> -    set result [remote_load target tmpdir/striprog]
> -    set status [lindex $result 0]
> -    if { ![istarget $host_triplet] } {
> -      set status "pass"
> -    }
> -    if { $status != "pass" } {
> -	fail $test
> -        return
> -    }
> +#    set result [remote_load target tmpdir/striprog]
> +#    set status [lindex $result 0]
> +#    if { ![istarget $host_triplet] } {
> +#      set status "pass"
> +#    }
> +#    if { $status != "pass" } {
> +#	fail $test
> +#        return
> +#    }
>  
>      set exec_output [binutils_run $NM "$NMFLAGS ${copyfile}"]
>      if { [istarget mmix-knuth-mmixware] } {
> 
> Looks like these crept in unawares.

 Indeed -- that's to avoid running stripped executables that breaks 
semihosting.  Sorry about that.  I've now converted to `quilt' 
temporarily, so such stuff will be dropped automatically.

>     PLT entries and traditional MIPS lazy binding stubs.  We mark the former
>     with STO_MIPS_PLT to distinguish them from the latter.  */
>  #define STO_MIPS_PLT		0x8
> +#define ELF_ST_IS_MIPS_PLT(OTHER) (((OTHER) & 0x8) == STO_MIPS_PLT)
> ...
>  #define STO_MIPS_PIC		0x20
>  #define ELF_ST_IS_MIPS_PIC(OTHER) \
> -  (((OTHER) & ~ELF_ST_VISIBILITY (-1)) == STO_MIPS_PIC)
> +  (((OTHER) & ~ELF_ST_VISIBILITY (-1) & ~0xc0) == STO_MIPS_PIC)
>  #define ELF_ST_SET_MIPS_PIC(OTHER) \
> -  (STO_MIPS_PIC | ELF_ST_VISIBILITY (OTHER))
> +  (STO_MIPS_PIC | ELF_ST_VISIBILITY (OTHER) | ELF_ST_MICROMIPS (OTHER))
> ...
>      case STO_OPTIONAL:  return "OPTIONAL";
>      case STO_MIPS16:    return "MIPS16";
> -    case STO_MIPS_PLT:	return "MIPS PLT";
> -    case STO_MIPS_PIC:	return "MIPS PIC";
> -    default:      	return NULL;
> +    default:
> +	if (ELF_ST_IS_MIPS_PLT (other))
> +	  {
> +	    if (ELF_ST_IS_MICROMIPS (other))
> +	      return "MICROMIPS, MIPS PLT";
> +	    else
> +	      return "MIPS PLT";
> +	  }
> +	if (ELF_ST_IS_MIPS_PIC (other))
> +	  {
> +	    if (ELF_ST_IS_MICROMIPS (other))
> +	      return "MICROMIPS, MIPS PIC";
> +	    else
> +	      return "MIPS PIC";
> +	  }
> +	if (ELF_ST_IS_MICROMIPS (other))
> +	  return "MICROMIPS";
> +
> +	return NULL;
> 
> You don't add support for microMIPS PLTs, so the "MICROMIPS, MIPS PLT"
> thing appears to be dead code.  I wouldn't mind, except that it makes
> the code inconsistent with MIPS16: the changes above allow both
> 
>   STO_MIPS16 | STO_MIPS_PLT
> 
> and
> 
>   STO_MICROMIPS | STO_MIPS_PLT
> 
> neither of which are currently used, but you don't treat the two equally.
> 
> In other words, I'm happy with the STO_MIPS_PIC changes but not with
> the STO_MIPS_PLT ones.

 I have rewritten both the relevant macro definitions and the piece of 
code above.  I have cleaned up some of the other STO_* macros too for 
consistency and clarity.

> +  /* 16 bit relocation.  */
> +  HOWTO (R_MICROMIPS_16,	/* type */
> +	 0,			/* rightshift */
> +	 2,			/* size (0 = byte, 1 = short, 2 = long) */
> +	 16,			/* bitsize */
> +	 FALSE,			/* pc_relative */
> +	 0,			/* bitpos */
> +	 complain_overflow_dont, /* complain_on_overflow */
> +	 _bfd_mips_elf_lo16_reloc, /* special_function */
> +	 "R_MICROMIPS_16",	/* name */
> +	 TRUE,			/* partial_inplace */
> +	 0x0000ffff,		/* src_mask */
> +	 0x0000ffff,		/* dst_mask */
> +	 FALSE),		/* pcrel_offset */
> 
> Is this relocation really a lo16 one?  If so, it's not consistent
> with R_MIPS_16 (which isn't).

 I don't think it's needed -- I have removed it.  Nobody seems to use 
%half() anyway and beside defining it in an odd way the ABI is unclear as 
to what this is meant for.

> +/*
> + *  Delay slot size and relaxation support
> + */
> +static unsigned long
> +relax_delay_slot (bfd *abfd, bfd_byte *ptr, unsigned long* opcode_32)
> +{
> +  unsigned long bdsize = 0;
> +
> +  unsigned long fndopc;
> +  unsigned long p16opc, p32opc;
> +
> +  /* Opcodes preceding the current instruction.  */
> +  p16opc  = bfd_get_16 (abfd, ptr - 2);
> +  p32opc  = bfd_get_16 (abfd, ptr - 4) << 16;
> 
> You need to check the section bounds.  The code appears to read off the
> beginning of a section if that section starts with a relaxable LUI.

 I've fixed the off-the-section accesses, but this function and 
surrounding code was broken in design in the first place.  With a 
microMIPS instruction stream you can't just peek at a randomly picked 
halfword, interpret it as an opcode apply make arbitrary transformations, 
because the halfword may in fact be a lower half of 32-bit instruction.

 Therefore I changed the function only to replace branch or jump encodings 
that change the size of the delay slot if a relocation has been found at 
that location.  If no relocation has been found, then, conservatively, 
only the LUI itself may be be changed and a heuristics is used to 
determine if it might be in a delay slot of a fixed size.  If no branch or 
jump encoding has been found, then the LUI may be deleted altogether, 
otherwise a NOP is substituted, that is 16-bit if the heuristics 
determined the possible delay slot will accept such one or 32-bit (i.e. 
the same width as the original LUI) otherwise.

 Note that in particular means a JALR->JALRS conversion won't happen 
unless there's a R_MIPS_JALR relocation against the call instruction; I 
made no attempt to change GAS in any way to emit such a relocation in 
cases it does not do already. [FIXME]

> +      /* If this isn't something that can be relaxed, then ignore
> +	 this reloc.  */
> +      if (ELF32_R_TYPE (irel->r_info) != (int) R_MICROMIPS_HI16 &&
> +	  ELF32_R_TYPE (irel->r_info) != (int) R_MICROMIPS_LO16 &&
> +	  ELF32_R_TYPE (irel->r_info) != (int) R_MICROMIPS_PC16_S1 &&
> +	  ELF32_R_TYPE (irel->r_info) != (int) R_MICROMIPS_26_S1 &&
> +	  ELF32_R_TYPE (irel->r_info) != (int) R_MICROMIPS_GPREL16)
> +	continue;
> 
> &&s at the beginning of lines.

 Fixed.

> +      /* Get the value of the symbol referred to by the reloc.  */
> +      if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
> +	{
> +	  /* A local symbol.  */
> +	  Elf_Internal_Sym *isym;
> +	  asection *sym_sec;
> +
> +	  isym = isymbuf + ELF32_R_SYM (irel->r_info);
> +	  if (isym->st_shndx == SHN_UNDEF)
> +	    sym_sec = bfd_und_section_ptr;
> +	  else if (isym->st_shndx == SHN_ABS)
> +	    sym_sec = bfd_abs_section_ptr;
> +	  else if (isym->st_shndx == SHN_COMMON)
> +	    sym_sec = bfd_com_section_ptr;
> +	  else
> +	    sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
> +	  symval = (isym->st_value
> +		    + sym_sec->output_section->vma
> +		    + sym_sec->output_offset);
> +	  target_is_micromips_code_p = ELF_ST_IS_MICROMIPS (isym->st_other);
> +	}
> +      else
> +	{
> +	  unsigned long indx;
> +	  struct elf_link_hash_entry *h;
> +
> +	  /* An external symbol.  */
> +	  indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
> +	  h = elf_sym_hashes (abfd)[indx];
> +	  BFD_ASSERT (h != NULL);
> +
> +	  if (h->root.type != bfd_link_hash_defined
> +	      && h->root.type != bfd_link_hash_defweak)
> +	    /* This appears to be a reference to an undefined
> +	       symbol.  Just ignore it -- it will be caught by the
> +	       regular reloc processing.  */
> +	    continue;
> +
> +	  symval = (h->root.u.def.value
> +		    + h->root.u.def.section->output_section->vma
> +		    + h->root.u.def.section->output_offset);
> +	}
> 
> Why not set target_is_micromips_code_p for locally-binding global
> symbols too?

 Globally-binding, that is.  I see no reason -- Chao-ying?

 I have changed it now anyway.

> +      opcode  =   bfd_get_16 (abfd, contents + irel->r_offset    ) << 16;
> +      opcode |= (irel->r_offset + 2 < sec->size
> +		 ? bfd_get_16 (abfd, contents + irel->r_offset + 2) : 0);
> 
> Are there any relaxations we can actually do if irel->r_offset + 2
> >= sec->size?  I couldn't see any.  If there aren't, continue instead.

 Agreed -- all relaxations operate on 32-bit instructions (some also imply 
access to the following instruction that wasn't guarded against the 
section end and which I have fixed it now too) -- there's no point in 
doing anything with half-an-instruction.

> +      /* R_MICROMIPS_HI16 / LUI relaxation to R_MICROMIPS_HI0_LO16 or
> +         R_MICROMIPS_PC23_S2.  The R_MICROMIPS_PC23_S2 condition is
> +
> +           (symval % 4 == 0 && IS_BITSIZE (pcrval, X, 25))
> +
> +         where the X adjustment compensate for R_MICROMIPS_HI16 and
> +         R_MICROMIPS_LO16 being at most X bytes appart when the
> +         distance to the target approaches 32 MB.  */
> 
> Comment is slightly confusing: we don't relax the HI16 itself to a
> H0_LO16 or PC32_S3.  Rather we relax the LO16 (or, if you like,
> the HI16/LO16 pair).

 I have reworded the comment now.

> +	  /* Assume is possible to delete the LUI instruction:
> +	     4 bytes at irel->r_offset.  */
> 
> s/Assume is/Assume it is/

 Fixed.

> +      /* Compact branch relaxation -- due to the multitude of macros
> +         employed by the compiler/assembler, compact branches are not
> +         aways generated.  Obviously, this can/will be fixed elsewhere,
> +         but there is no drawback in double checking it here.  */
> +      else if (ELF32_R_TYPE (irel->r_info) == (int) R_MICROMIPS_PC16_S1
> +	       && (fndopc = find_match (opcode, bz_insns_32)) != 0
> +	       && MATCH (bfd_get_16 (abfd, contents + irel->r_offset + 4),
> +			 nop_insn_16))
> 
> s/aways/always/.  You should check the section size before reading
> past the relocation.  (I realise there ought to be a delay slot,
> but we should be robust against brokenness.)

 Ah, you noticed that too -- fixed, as noted above.

> +      /* R_MICROMIPS_26_S1 -- JAL to JALS relaxation for microMIPS targets.  */
> +      else if (ELF32_R_TYPE (irel->r_info) == (int) R_MICROMIPS_26_S1
> +	       && target_is_micromips_code_p
> +	       && MATCH (opcode, jal_insn_32_bd32))
> +	{
> +	  unsigned long n32opc;
> +	  bfd_boolean relaxed = FALSE;
> +
> +	  n32opc  =
> +	    bfd_get_16 (abfd, contents + irel->r_offset + 4    ) << 16;
> +	  n32opc |= irel->r_offset + 2 < sec->size?
> +	    bfd_get_16 (abfd, contents + irel->r_offset + 6): 0;
> +
> 
> Here too you should check the size before reading n32opc.  Second
> condition looks bogus (did you mean +6?) although the same concerns
> apply as for the "+ 2" above.

 Fixed, as noted above.

 I have fixed the rewrite of immediate addends throughout too as that 
matters for REL targets.  And fixed zillions of GNU Coding Standar 
violations.

 Overall I'm a bit concerned about all this linker relaxation stuff -- it 
breaks -falign-jumps, -falign-labels and -falign-loops which may have a 
severe performance penalty and should therefore be enabled conditionally 
only, preferably where all the three options are set to 1 (meaning that 
would be naturally implied by -Os).  A linker option would be required an 
set appropriately by the GCC driver. [FIXME]

> the elf32-mips.c reloc questions in review 2 apply to elf64-mips.c
> and elfn32-mips.c as well.  Furthermore:
> 
> +static reloc_howto_type micromips_elf64_howto_table_rela[] =
> +{
> +  /* 16 bit relocation.  */
> +  HOWTO (R_MICROMIPS_16,	/* type */
> +	 0,			/* rightshift */
> +	 2,			/* size (0 = byte, 1 = short, 2 = long) */
> +	 16,			/* bitsize */
> +	 FALSE,			/* pc_relative */
> +	 0,			/* bitpos */
> +	 complain_overflow_dont, /* complain_on_overflow */
> +	 _bfd_mips_elf_lo16_reloc, /* special_function */
> +	 "R_MICROMIPS_16",	/* name */
> +	 TRUE,			/* partial_inplace */
> +	 0x0000ffff,		/* src_mask */
> +	 0x0000ffff,		/* dst_mask */
> +	 FALSE),		/* pcrel_offset */
> 
> RELA relocations shouldn't be partial_inplace.  Applies to the whole array.

 Could be my omission -- fixed, sorry.  There were preexisting cases too, 
sent as a separate patch.

> Did you actually test this with n64, say with a gcc bootstrap?  Same
> comment goes for elfn32-mips.c.
> 
> Why only do the linker relaxation for elf32-mips.c (o32, o64 & EABI)?
> Why not for n32 and n64 too?

 The answer to all the questions is negative.  There is no 64-bit 
microMIPS hardware available at the moment.  The best bet might be QEMU -- 
NathanF, have you implemented any of the 64-bit instructions in QEMU?  
Otherwise there's probably no way do do any of 64-bit microMIPS testing 
beside what's done in binutils.  And no library work of any kind has 
started for 64-bit microMIPS support AFAIK.  Hence there has been little 
incentive to attempt anything but rudimentary support for 64-bit ABIs.

 I envisage all the relaxation stuff to be either moved over to 
elfxx-mips.c or copied to elfn32-mips.c and elf64-mips.c, as applicable, 
once we have real 64-bit support.

> +#define LA25_LUI_MICROMIPS_1(VAL) (0x41b9)	/* lui t9,VAL */
> +#define LA25_LUI_MICROMIPS_2(VAL) (VAL)
> +#define LA25_J_MICROMIPS_1(VAL) (0xd400 | (((VAL) >> 17) & 0x3ff)) /* j VAL */
> +#define LA25_J_MICROMIPS_2(VAL) (0xd4000000 | (((VAL) >> 1) & 0xffff))
> +#define LA25_ADDIU_MICROMIPS_1(VAL) (0x3339)	/* addiu t9,t9,VAL */
> +#define LA25_ADDIU_MICROMIPS_2(VAL) (VAL)
> 
> LA25_J_MICROMIPS_2 is a 16-bit opcode, so the "0xd4000000 | ..."
> thing is bogus.

 Fixed.

> That said, why split these up?  bfd_{get,put}_32
> don't require aligned addresses.

 I think it's easier and more readable this way as with bfd_{get,put}_32() 
you'd have to halfword-swap the bit patterns produced based on the target 
endianness.

> +  value = s->size;
> +  if (ELF_ST_IS_MICROMIPS (stub->h->root.other))
> +    value |= 1;
> +
>    /* Create a symbol for the stub.  */
> -  mips_elf_create_stub_symbol (info, stub->h, ".pic.", s, s->size, 8);
> +  mips_elf_create_stub_symbol (info, stub->h, ".pic.", s, value, 8);
>  
> Do this in mips_elf_create_stub_symbol rather than in each caller.

 Fixed.

> +  return r_type == R_MIPS_GOT16 || r_type == R_MIPS16_GOT16
> +	 || r_type == R_MICROMIPS_GOT16;
> 
> GNU indentation requires brackets here.  Also, once it becomes too
> long for one line, let's keep one item per line:
> 
>   return (r_type == R_MIPS_GOT16
> 	  || r_type == R_MIPS16_GOT16
> 	  || r_type == R_MICROMIPS_GOT16);
> 
> Same for later functions.

 Fixed.

> -  if (r_type == R_MIPS_TLS_GOTTPREL)
> +  if (r_type == R_MIPS_TLS_GOTTPREL || r_type == R_MICROMIPS_TLS_GOTTPREL)
> 
> Hide these differences in analogues of the got16_reloc_p functions.
> Same for all other relocs with MICROMIPS variants.

 Done.  Found and fixed some MIPS16 bugs on the way.

> @@ -3187,8 +3244,12 @@ mips_elf_got_page (bfd *abfd, bfd *ibfd,
>    struct mips_got_entry *entry;
>  
>    page = (value + 0x8000) & ~(bfd_vma) 0xffff;
> -  entry = mips_elf_create_local_got_entry (abfd, info, ibfd, page, 0,
> -					   NULL, R_MIPS_GOT_PAGE);
> +  if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS)
> +    entry = mips_elf_create_local_got_entry (abfd, info, ibfd, page, 0,
> +					     NULL, R_MICROMIPS_GOT_PAGE);
> +  else
> +    entry = mips_elf_create_local_got_entry (abfd, info, ibfd, page, 0,
> +					     NULL, R_MIPS_GOT_PAGE);
>  
>    if (!entry)
>      return MINUS_ONE;
> 
> Why is this necessary?

 This looks bogus to me -- most mips_elf_create_local_got_entry() cares 
about is whether r_type is a TLS reloc or not.  It does some further 
checks for TLS relocs, but it doesn't bother otherwise.  Removed.

> @@ -5127,12 +5200,26 @@ mips_elf_calculate_relocation (bfd *abfd
>  	      + h->la25_stub->stub_section->output_offset
>  	      + h->la25_stub->offset);
>  
> +  /* Make sure MIPS16 and microMIPS are not used together.  */
> +  if ((r_type == R_MIPS16_26 && target_is_micromips_code_p)
> +      || (r_type == R_MICROMIPS_26_S1 && target_is_16_bit_code_p))
> +   {
> +      (*_bfd_error_handler)
> +	(_("MIPS16 and microMIPS functions cannot call each other"));
> +      return bfd_reloc_notsupported;
> +   }
> 
> Should this be extended to check for branches too?

 That would be a useful improvement I suppose, but MIPS16 code doesn't 
care either (you can't use a branch to switch the ISA mode).  Overall I 
think it's a corner case -- branches to external symbols are a rarity. 
[FIXME]

> +    case R_MIPS_26:
> +      /* Make sure the target of JALX is word-aligned.
> +	 Bit 0 must be 1 (MIPS16/microMIPS mode), and bit 1 must be 0.  */
> +      if (*cross_mode_jump_p == TRUE && (symbol & 3) != 1)
> +	return bfd_reloc_outofrange;
> 
> == TRUE has been banned by act of parliament.

 Fixed.

> If we're checking alignment for R_MIPS_26 and R_MICROMIPS_26, we should
> check it for R_MIPS16_26 too.  Something like:
> 
>       /* Make sure the target of JALX is word-aligned.
> 	 Bit 0 must be the correct ISA mode selector and bit 1 must be 0.  */
>       if (*cross_mode_jump_p && (symbol & 3) != (r_type == R_MIPS_26))
> 	return bfd_reloc_outofrange;
> 
> for both cases would be fine.
> 
> +    case R_MICROMIPS_26_S1:
> +      /* Make sure the target of jalx is word-aligned.  */
> +      if (*cross_mode_jump_p == TRUE && (symbol & 3) != 0)
> +	return bfd_reloc_outofrange;
> +      if (local_p)
> +	{
> +	  /* For jalx, the offset is shifted right by two bits.  */
> +	  if (*cross_mode_jump_p == TRUE)
> +	    value = ((addend | ((p + 4) & 0xf0000000)) + symbol) >> 2;
> +	  else
> +	    value = ((addend | ((p + 4) & 0xf8000000)) + symbol) >> 1;
> +	}
> +      else
> +	{
> +	  /* For jalx, the offset is shifted right by two bits.  */
> +	  if (*cross_mode_jump_p == TRUE)
> +	    {
> +	      value = (_bfd_mips_elf_sign_extend (addend, 28) + symbol) >> 2;
> +	      if (h->root.root.type != bfd_link_hash_undefweak)
> +		overflowed_p = (value >> 26) != ((p + 4) >> 28);
> +	    }
> +	  else
> +	    {
> +	      value = (_bfd_mips_elf_sign_extend (addend, 27) + symbol) >> 1;
> +	      if (h->root.root.type != bfd_link_hash_undefweak)
> +		overflowed_p = (value >> 26) != ((p + 4) >> 27);
> +	    }
> +	}
> +      value &= howto->dst_mask;
> +      break;
> 
> This is a strict extension of the R_MIPS_26 and R_MIPS16_26 behaviour,
> so I'd prefer to see them integrated.

 I think R_MIPS_26 should be used for microMIPS JALX.  I don't like the 
idea of overloading R_MICROMIPS_26_S1 this way, especially given another 
relocation already fits.  What do you think?  It is too late to fix the 
ABI probably though; I'm thinking what the consequences might be...

 I have merged this piece now and integrated your comment update.

> @@ -5372,6 +5516,9 @@ mips_elf_calculate_relocation (bfd *abfd
>  	     both reloc addends by 4. */
>  	  if (r_type == R_MIPS16_HI16)
>  	    value = mips_elf_high (addend + gp - p - 4);
> +	  else if (r_type == R_MICROMIPS_HI16)
> +	    /* The low bit of $t9 is set for microMIPS calls.  */
> +	    value = mips_elf_high (addend + gp - p - 1);
>  	  else
>  	    value = mips_elf_high (addend + gp - p);
>  	  overflowed_p = mips_elf_overflow_p (value, 16);
> 
> This statement is also true for MIPS16, so in context, the comment
> is a bit confusing on its own.  How about:
> 
> 	    /* The microMIPS .cpload sequence uses the same assembly
> 	       instructions as the traditional psABI version, but the
> 	       incoming $t9 has the low bit set.  */

 Fine by me.

> @@ -5486,8 +5647,38 @@ mips_elf_calculate_relocation (bfd *abfd
>        value &= howto->dst_mask;
>        break;
>  
> +    case R_MICROMIPS_PC7_S1:
> +      value = symbol + _bfd_mips_elf_sign_extend (addend, 8) - p;
> +      overflowed_p = mips_elf_overflow_p (value, 8);
> +      value >>= howto->rightshift;
> +      value &= howto->dst_mask;
> +      break;
> +
> +    case R_MICROMIPS_PC10_S1:
> +      value = symbol + _bfd_mips_elf_sign_extend (addend, 11) - p;
> +      overflowed_p = mips_elf_overflow_p (value, 11);
> +      value >>= howto->rightshift;
> +      value &= howto->dst_mask;
> +      break;
> +
> +    case R_MICROMIPS_PC16_S1:
> +      value = symbol + _bfd_mips_elf_sign_extend (addend, 17) - p;
> +      overflowed_p = mips_elf_overflow_p (value, 17);
> +      value >>= howto->rightshift;
> +      value &= howto->dst_mask;
> +      break;
> +
> +    case R_MICROMIPS_PC23_S2:
> +      value = symbol + _bfd_mips_elf_sign_extend (addend, 25) - (p &
> 0xfffffffc);
> +      overflowed_p = mips_elf_overflow_p (value, 25);
> +      value >>= howto->rightshift;
> +      value &= howto->dst_mask;
> +      break;
> 
> I realise you probably based this on R_MIPS_PC16 and R_MIPS_GNU_REL16_S2,
> but even so, you're careful to check for underflow elsewhere but ignore
> it here.

 I'm not sure what you mean.  R_MICROMIPS_PC23_S2 is used for ADDIUPC so 
you have to strip out the two LSBs.

> Use of 0xfffffffc isn't portable for 64-bit addresses;
> use "-4" or "~(bfd_vma) 3" instead.

 I'm nasty enough to use (foo | 3) ^ 3 and avoid type width and promotion 
dependencies altogether in such cases and hope for GCC to be smart and do 
the right thing and combine the two ops.

> @@ -6150,13 +6355,18 @@ _bfd_mips_elf_symbol_processing (bfd *ab
>        break;
>      }
>  
> -  /* If this is an odd-valued function symbol, assume it's a MIPS16 one.  */
> +  /* If this is an odd-valued function symbol, assume it's a MIPS16
> +     or microMIPS one.  */
>    if (ELF_ST_TYPE (elfsym->internal_elf_sym.st_info) == STT_FUNC
>        && (asym->value & 1) != 0)
>      {
>        asym->value--;
> -      elfsym->internal_elf_sym.st_other
> -	= ELF_ST_SET_MIPS16 (elfsym->internal_elf_sym.st_other);
> +      if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS)
> +	elfsym->internal_elf_sym.st_other
> +	  = ELF_ST_SET_MICROMIPS (elfsym->internal_elf_sym.st_other);
> +      else
> +	elfsym->internal_elf_sym.st_other
> +	  = ELF_ST_SET_MIPS16 (elfsym->internal_elf_sym.st_other);
>      }
>  }
>  
> 
> So a file can't mix MIPS16 and microMIPS code?  We should probably
> detect that explicitly.  I'd like a clear statement of what the
> interoperability restrictions are.
> 
> This goes back to the question of when EF_MIPS_ARCH_ASE_MICROMIPS
> should be set (see previous reviews).

 Background information first -- you can't have a piece of MIPS hardware, 
either real or simulated, with the MIPS16 ASE and the microMIPS ASE 
implemented both at a time.  This is a design assumption that allowed the 
ISA bit to be overloaded.

 That obviously does not mean -- in principle -- that you can't have an 
executable (or one plus a mixture of shared libraries) where some 
functions are MIPS16 code and some are microMIPS code, either of which 
only called once the presence of the respective ASE has been determined.  
While a valid configuration this is also a rare exotic corner case -- I 
could imagine a piece of generic, processor-independent console/bootstrap 
firmware like this for example, but little beyond that.

 We had a discussion about it and the conclusion was from the user's 
perspective the most beneficial configuration is one where mixing MIPS16 
and microMIPS code within a single executable is forbidden by default.  
The reason is a build-time error is always better than a run-time one 
(especially when the device has been placed out there in the field 
already; hopefully not an Ariane 5 rocket) and the case where mixing 
MIPS16 and microMIPS code would almost always happen is when the user 
picked the wrong library by mistake.  It is therefore most productive to 
fail at this point rather than later.

 A future enhancement could add assembler and linker switches to override 
this default and mix the two ASEs in a single executable. [FIXME]

> @@ -6865,7 +7075,8 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd
>    /* If this is a mips16 text symbol, add 1 to the value to make it
>       odd.  This will cause something like .word SYM to come up with
>       the right value when it is loaded into the PC.  */
> -  if (ELF_ST_IS_MIPS16 (sym->st_other))
> +  if (ELF_ST_IS_MIPS16 (sym->st_other)
> +      || ELF_ST_IS_MICROMIPS (sym->st_other))
>      ++*valp;
>  
>    return TRUE;
> 
> As with GAS, I'd like an ODD_SYMBOL_P or some-such.

 ELF_ST_IS_COMPRESSED it is then, for consistency.  Note it doesn't seem 
possible to me to limit the macro to read its argument once only without 
resorting to GNU extensions; I'll be happy to be proved wrong though.

> @@ -7166,6 +7378,8 @@ mips_elf_add_lo16_rel_addend (bfd *abfd,
>    r_type = ELF_R_TYPE (abfd, rel->r_info);
>    if (mips16_reloc_p (r_type))
>      lo16_type = R_MIPS16_LO16;
> +  else if (micromips_reloc_shuffle_p (r_type))
> +    lo16_type = R_MICROMIPS_LO16;
>    else
>      lo16_type = R_MIPS_LO16;
>  
> Conceptually, this ought to be plain micromips_reloc_p.  Whether we need
> to shuffle or not isn't an issue here, even though I realise the shuffle
> condition produces the right result.

 Of course.

> @@ -9215,6 +9479,12 @@ _bfd_mips_elf_relocate_section (bfd *out
>  	case bfd_reloc_ok:
>  	  break;
>  
> +	case bfd_reloc_outofrange:
> +	  msg = _("internal error: jalx jumps to not word-aligned address");
> +	  info->callbacks->warning
> +	    (info, msg, name, input_bfd, input_section, rel->r_offset);
> +	  return FALSE;
> +
>  	default:
>  	  abort ();
>  	  break;
> 
> Why's that an internal error?  Surely it could be triggered by
> badly-formed input, rather than just as a result of internal
> confusion?
> 
> The error is more specific than the error code, so you should also add:
> 
>       BFD_ASSERT (jal_reloc_p (howto->type));

 I've made it a conditional instead.  Preexisting cases of 
bfd_reloc_outofrange will fall through to abort() below as they do now.

> @@ -976,7 +976,7 @@ bfd_install_relocation (bfd *abfd,
>    asection *reloc_target_output_section;
>    asymbol *symbol;
>    bfd_byte *data;
> -
> +  
>    symbol = *(reloc_entry->sym_ptr_ptr);
>    if (bfd_is_abs_section (symbol->section))
>      {
> 
> Bogus change.

 Fixed.

> @@ -1652,6 +1652,8 @@ ENUMX
>  ENUMX
>    BFD_RELOC_16
>  ENUMX
> +  BFD_RELOC_MICROMIPS_16
> +ENUMX
>    BFD_RELOC_14
>  ENUMX
>    BFD_RELOC_8
> 
> Here and elsewhere, keep the MIPS-specific stuff separate from the
> generic relocs.  See the MIPS16 relocs for examples.

 I agree in principle, but no longer relevant as I have discarded the 
reloc.

> I'll take your word for it that micromips-opc.c is correct. ;-)

 There were a couple of problems with it, but I did my best to get it 
right. :)

> +  else if ((insn & 0x1c00) != 0x0400
> +	   && (insn & 0x1c00) != 0x0800
> +	   && (insn & 0x1c00) != 0x0c00)
> +    {
> +      /* This is a 32-bit microMIPS instruction.  */
> +      higher = insn;
> +
> +      status = (*info->read_memory_func) (memaddr + 2, buffer, 2, info);
> +      if (status != 0)
> +	{
> +	  (*info->fprintf_func) (info->stream, "micromips 0x%x",
> +				 (unsigned int) higher);
> +	  (*info->memory_error_func) (status, memaddr + 2, info);
> +	  return -1;
> +	}
> 
> Why print "micromips " here but not in the 48-byte case?

 It looks to me it's been modelled after the MIPS16 version where "extend 
0x..." is printed in the case of a read error.  I'm not sure if either 
makes sense (.byte foo or suchlike that some other ports output in such a 
case looks more reasonable to me), but at least it is consistent.

> Also,
> s/0x%02x/0x%x/ would be better IMO.

 The highest byte is always 0x7c, so no need to care about leading zeroes.  
I have rewritten pieces of this code so that all output available is 
always produced in a single place.

> Watch your formatting in this function.  There are lots of cases of
> things like:
> 
> 		      (*info->fprintf_func) (info->stream, "%s",
> 			mips_gpr_names[lastregno]);
> 
> which isn't right.  Arguments must be aligned to the column after
> the "(".  Don't be afraid to split lines into several statements
> if it makes things look more natural.

 Agreed, this was a horrible piece of unreadable code.  I created some 
auxiliary variables and a macro to compress the source (and, in the former 
case, to get potentially better code), improving readablity and getting 
rid of most indentation problems as a side effect.

 The rule of thumb is if you have a problem with source code of your 
program hitting the right margin on an 80-column terminal, then you're 
probably putting too much in a single function.  This rule isn't kept of 
course in many places throughout binutils, but that does not mean it's not 
a valid one.

> The gas testsuite changes look very nice, thanks.

 You are welcome. :)

 Thank you for the review -- I know it's been a lot effort.  Here's a new 
version of the change.  Regression-tested succesfully on mips-sde-elf and 
mips-linux-gnu targets.  Changes for the MCU ASE and the M14K/c cores will 
follow.

  Maciej

bfd/
2010-07-26  Chao-ying Fu  <fu@mips.com>
            Ilie Garbacea  <ilie@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>
            Joseph Myers  <joseph@codesourcery.com>
            Catherine Moore  <clm@codesourcery.com>

	* 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_mips16_elf_reloc_unshuffle): Rename to...
	(_bfd_mips_elf_reloc_unshuffle): ... this.  Handle microMIPS.
	(_bfd_mips16_elf_reloc_shuffle): Rename to...
	(_bfd_mips_elf_reloc_shuffle): ... this.  Handle microMIPS.
	(gprel16_reloc_p): Handle microMIPS.
	(literal_reloc_p): New function.
	* elf32-mips.c (elf_micromips_howto_table_rel): New variable.
	(_bfd_mips_elf32_gprel16_reloc): Handle microMIPS.
	(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.
	(mips_elf32_rtype_to_howto): Likewise.
	(mips_info_to_howto_rel): Likewise.
	(elf32_mips_relax_delete_bytes): New function.
	(opcode_descriptor): New structure.
	(b_insns_32, b_insn_16): New variables.
	(BZ32_REG, BZ32_REG_FIELD): New macros.
	(bz_insns_32, bzc_insns_32, bz_insns_16): New variables.
	(BZ16_VALID_REG, BZ16_REG_FIELD): New macros.
	(jal_insn_32_bd16, jal_insn_32_bd32): New variables.
	(call_insn_32_bd16, call_insn_32_bd32): Likewise.
	(ds_insns_32_bd16, jalx_insn_32_bd32): Likewise.
	(jalr_insn_16_bd16, jalr_insn_16_bd32): Likewise.
	(ds_insns_16_bd16): Likewise.
	(lui_insn, addiu_insn, addiupc_insn): Likewise.
	(ADDIU_REG, ADDIUPC_VALID_REG, ADDIUPC_REG_FIELD): New macros.
	(lwgp_insn_32, lwgp_insn_16): New functions.
	(LWGP32_REG, LWGP16_VALID_REG, LWGP16_REG_FIELD): New macros.
	(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.
	(relax_dslot_norel16, relax_dslot_norel32): Likewise.
	(relax_dslot_rel): Likewise.
	(IS_BITSIZE): New macro.
	(elf32_mips_relax_section): New function.
	(bfd_elf32_bfd_relax_section): Define.
	* 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.
	(bfd_elf64_bfd_reloc_name_lookup): Likewise.
	(mips_elf64_rtype_to_howto): Likewise.
	* 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.
	(bfd_elf32_bfd_reloc_name_lookup): Likewise.
	(mips_elf_n32_rtype_to_howto): Likewise.
	* 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.
	(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.
	(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.
	(tls_gd_reloc_p, tls_ldm_reloc_p): New functions.
	(tls_gottprel_reloc_p): Likewise.
	(_bfd_mips16_elf_reloc_unshuffle): Rename to...
	(_bfd_mips_elf_reloc_unshuffle): ... this.  Handle microMIPS.
	(_bfd_mips16_elf_reloc_shuffle): Rename to...
	(_bfd_mips_elf_reloc_shuffle): ... this.  Handle microMIPS.
	(_bfd_mips_elf_lo16_reloc): Handle microMIPS.
	(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_print_private_bfd_data):	Likewise.
	* 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/
2010-07-26  Chao-ying Fu  <fu@mips.com>

	* readelf.c (get_machine_flags): Handle microMIPS.
	(get_mips_symbol_other): Likewise.

gas/
2010-07-26  Chao-ying Fu  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* 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 (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.
	(HAVE_CODE_COMPRESSION): Likewise.
	(micromips_op_hash): New variable.
	(micromips_nop16_insn, micromips_nop32_insn): New variables.
	(NOP_INSN): Handle microMIPS.
	(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_USER_16BIT): Likewise.
	(RELAX_MICROMIPS_UNCOND, RELAX_MICROMIPS_LINK): Likewise.
	(RELAX_MICROMIPS_TOOFAR, RELAX_MICROMIPS_MARK_TOOFAR): Likewise.
	(RELAX_MICROMIPS_CLEAR_TOOFAR): Likewise.
	(RELAX_MICROMIPS_EXTENDED): Likewise.
	(RELAX_MICROMIPS_MARK_EXTENDED): Likewise.
	(RELAX_MICROMIPS_CLEAR_EXTENDED): Likewise.
	(MICROMIPS_INSERT_OPERAND, MICROMIPS_EXTRACT_OPERAND): New
	macros.
	(mips_macro_warning): Add delay_slot_16bit_p, delay_slot_32bit_p,
	fsize and insns.
	(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_mips16_micromips_mode): ... this.  Handle
	microMIPS.
	(install_insn): Handle microMIPS.
	(is_size_valid, is_delay_slot_valid): New functions.
	(md_begin): Handle microMIPS.
	(md_assemble): Likewise.  Update for append_insn interface
	change.
	(micromips_reloc_p): New function.
	(got16_reloc_p): Handle microMIPS.
	(hi16_reloc_p): Likewise.
	(lo16_reloc_p): Likewise.
	(matching_lo_reloc): Likewise.
	(mips_move_labels): Likewise.
	(mips_mark_labels): New function.
	(mips16_mark_labels): Rename to...
	(mips_compressed_mark_labels): ... this.  Handle microMIPS.
	(insns_between): Handle microMIPS.
	(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.
	(append_insn): Add expansionp argument.  Handle microMIPS.
	(start_noreorder, end_noreorder): Handle microMIPS.
	(macro_start, macro_warning, macro_end): Likewise.
	(lui_fmt, shft_fmt): New variables.
	(LUI_FMT, SHFT_FMT): New macros.
	(macro_map_reloc): New function.
	(macro_build): Handle microMIPS.  Update for append_insn
	interface change.
	(mips16_macro_build): Update for append_insn interface change.
	(macro_build_jalr): Handle microMIPS.
	(macro_build_lui): Likewise.  Update for append_insn interface
	change.
	(macro_build_ldst_constoffset): Use relocation wrappers.
	(set_at): Likewise.
	(load_register): Likewise.
	(load_address): Likewise.
	(move_register): Handle microMIPS.
	(load_got_offset): Use relocation wrappers.
	(add_got_offset): Likewise.
	(add_got_offset_hilo): Likewise.
	(macro): Handle microMIPS.
	(validate_micromips_insn): New function.
	(micromips_percent_op): New variable.
	(parse_relocation): Handle microMIPS.
	(my_getExpression): Likewise.
	(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.
	(md_pcrel_from): Handle microMIPS relocations.
	(mips_force_relocation): Likewise.
	(md_apply_fix): Likewise.
	(mips_align): Handle microMIPS.
	(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.
	(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.
	(mips_fix_adjustable): Likewise.
	(tc_gen_reloc): Handle microMIPS relocations.
	(mips_relax_frag): Handle microMIPS.
	(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.
	(micromips_ip): New function.
	(micromips_macro_build): Likewise.
	(micromips_macro): Likewise.
	* 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.

gas/testsuite/
2010-07-26  Maciej W. Rozycki  <macro@codesourcery.com>
            Chao-ying Fu  <fu@mips.com>

	* gas/mips/micromips.d: New test.
	* gas/mips/micromips-trap.d: Likewise.
	* gas/mips/micromips-branch-relax-pic.d: Likewise.
	* gas/mips/micromips-branch-relax-pic.d: Likewise.
	* gas/mips/micromips.l: New stderr output.
	* gas/mips/micromips-branch-relax.l: Likewise.
	* gas/mips/micromips-branch-relax-pic.l: Likewise.
	* gas/mips/micromips.s: New test source.
	* gas/mips/micromips-branch-relax.s: Likewise.
	* gas/mips/mips.exp: Run the new tests.

	* gas/mips/micromips@abs.d: New test.
	* 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@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@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@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/mips32-imm.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/mips32-imm.s: Likewise.
	* gas/mips/mips32.s: Handle microMIPS.
	* gas/mips/elf-rel27.d: 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/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/
2010-07-26  Chao-ying Fu  <fu@mips.com>

	* 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/
2010-07-26  Chao-ying Fu  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* mips.h
	(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, M_BEQL, M_BGEZL): New enum
	values.
	(M_BGEZALL, M_BGTZL, M_BLEZL, M_BLTZL, M_BLTZALL): Likewise.
	(M_CACHE_OB, 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_LWP_AB, M_LWP_OB): Likewise.
	(M_LWR_OB, 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, M_SDP_AB): Likewise.
	(M_SDP_OB, M_SDR_OB, M_SWC2_OB, M_SWL_OB, M_SWM_AB): Likewise.
	(M_SWM_OB, 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_BREAKCODE, MICROMIPSOP_SH_BREAKCODE): Likewise.
	(MICROMIPSOP_SH_BREAKCODE2): Likewise.
	(MICROMIPSOP_MASK_CACHEOP, MICROMIPSOP_SH_CACHEOP): Likewise.
	(MICROMIPSOP_MASK_COPSEL, MICROMIPSOP_SH_COPSEL): 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_MZ, MICROMIPSOP_SH_MZ): 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.
	(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/
2010-07-26  Catherine Moore  <clm@codesourcery.com>
            Chao-ying Fu  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* 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/mips-elf.exp: Run the new tests

opcodes/
2010-07-26  Chao-ying Fu  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* 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.
	(print_insn_micromips): New function.
	(is_micromips_mode_p): New function.
	(_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.

[-- Attachment #2: Type: APPLICATION/octet-stream, Size: 146364 bytes --]

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2010-07-26 10:56   ` [PATCH] MIPS: microMIPS ASE support Maciej W. Rozycki
@ 2010-07-26 13:25     ` Nathan Froyd
  2010-07-26 13:53       ` Maciej W. Rozycki
  2010-07-26 19:03     ` Richard Sandiford
  1 sibling, 1 reply; 41+ messages in thread
From: Nathan Froyd @ 2010-07-26 13:25 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: Richard Sandiford, binutils, Chao-ying Fu, Rich Fuhler,
	David Lau, Kevin Mills, Ilie Garbacea, Catherine Moore,
	Nathan Sidwell, Joseph Myers

On Mon, Jul 26, 2010 at 11:55:20AM +0100, Maciej W. Rozycki wrote:
> > Did you actually test this with n64, say with a gcc bootstrap?  Same
> > comment goes for elfn32-mips.c.
> > 
> > Why only do the linker relaxation for elf32-mips.c (o32, o64 & EABI)?
> > Why not for n32 and n64 too?
> 
>  The answer to all the questions is negative.  There is no 64-bit 
> microMIPS hardware available at the moment.  The best bet might be QEMU -- 
> NathanF, have you implemented any of the 64-bit instructions in QEMU?  

I have implemented support for the 64-bit instructions in QEMU.  I
haven't really tested whether the instruction translation works
correctly for those instructions.  (It should; there's nothing unusual
about the codepaths the 64-bit instructions take vs. their 32-bit
counterparts...but you never know...)

-Nathan

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2010-07-26 13:25     ` Nathan Froyd
@ 2010-07-26 13:53       ` Maciej W. Rozycki
  0 siblings, 0 replies; 41+ messages in thread
From: Maciej W. Rozycki @ 2010-07-26 13:53 UTC (permalink / raw)
  To: Nathan Froyd
  Cc: Richard Sandiford, binutils, Chao-ying Fu, Rich Fuhler,
	David Lau, Kevin Mills, Ilie Garbacea, Catherine Moore,
	Nathan Sidwell, Joseph Myers

On Mon, 26 Jul 2010, Nathan Froyd wrote:

> > > Did you actually test this with n64, say with a gcc bootstrap?  Same
> > > comment goes for elfn32-mips.c.
> > > 
> > > Why only do the linker relaxation for elf32-mips.c (o32, o64 & EABI)?
> > > Why not for n32 and n64 too?
> > 
> >  The answer to all the questions is negative.  There is no 64-bit 
> > microMIPS hardware available at the moment.  The best bet might be QEMU -- 
> > NathanF, have you implemented any of the 64-bit instructions in QEMU?  
> 
> I have implemented support for the 64-bit instructions in QEMU.  I
> haven't really tested whether the instruction translation works
> correctly for those instructions.  (It should; there's nothing unusual
> about the codepaths the 64-bit instructions take vs. their 32-bit
> counterparts...but you never know...)

 OK, thanks.  That's a good starting point, but still some low-level
startup files will need to be updated or at least examined for correct
64-bit microMIPS support before we can link executables suitable for
run-time testing such as with the GCC testsuite, let alone a full native 
GCC bootstrap.

  Maciej

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2010-07-26 10:56   ` [PATCH] MIPS: microMIPS ASE support Maciej W. Rozycki
  2010-07-26 13:25     ` Nathan Froyd
@ 2010-07-26 19:03     ` Richard Sandiford
  2010-12-07  1:13       ` Maciej W. Rozycki
  1 sibling, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2010-07-26 19:03 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
	Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers,
	Nathan Froyd

Hi Maciej,

Thanks for the huge effort in updating this patch.  Aside from the
gas macro handling (see below) it's looking much better, and I don't
think there are many issues blocking it going in.  I'll try to find
time to read over the patch properly in the next week or so.

"Maciej W. Rozycki" <macro@codesourcery.com> writes:
>> > > > 	(A_BFD_RELOC_HI16_S, A_BFD_RELOC_HI16, A_BFD_RELOC_LO16): New
>> > > > 	relocation wrapper macros.
>> > > > 	(A_BFD_RELOC_GPREL16): Likewise.
>> > > > 	(A_BFD_RELOC_MIPS_GOT16, A_BFD_RELOC_MIPS_GOT_HI16): Likewise.
>> > > > 	(A_BFD_RELOC_MIPS_GOT_LO16, A_BFD_RELOC_MIPS_HIGHEST): Likewise.
>> > > > 	(A_BFD_RELOC_MIPS_HIGHER, A_BFD_RELOC_MIPS_GOT_DISP): Likewise.
>> > > > 	(A_BFD_RELOC_MIPS_GOT_PAGE, A_BFD_RELOC_MIPS_GOT_OFST): 
>> > Likewise.
>> > > > 	(A_BFD_RELOC_MIPS_SUB, A_BFD_RELOC_MIPS_JALR): Likewise.
>> > > 
>> > > Did you consider doing the translation from non-microMIPS to
>> > > microMIPS in the macro_* functions, rather than in their callers?
>> > > I fear it'll be too easy to accidentally forget to use 
>> > A_BFD_* in future.
>> > 
>> >  Agreed, I didn't like the new macros from the very 
>> > beginning.  Chao-ying 
>> > -- any thoughts?
>> 
>>   I am fine.  But the new method may be bigger than the A_BFD* method.
>
>  I have placed the translation in macro_map_reloc() now.  That incurs an 
> O(n) performance penalty because all relocations in the microMIPS mode 
> have to be iterated over the table of mappings; regrettably BFD_RELOC_* 
> definitions are sparse so an O(1) lookup table cannot be used.  By keeping 
> it sorted some time can be saved, but that's still O(n).  This could be 
> reduced to O(log n) with a binary search, but I fear with the limited 
> number of relocs handled the overhead would kill the benefit.

TBH, I think a case statement would be fine here.  It's then up to
the compiler to pick the best implementation.

>> > 	(MICROMIPS_TARGET, MICROMIPS_TARGET_LABEL): New macros.
>> > 	(micromips_add_number_label): New function.
>> 
>> +/* For microMIPS macros, we need to generate a local number label
>> +   as the target of branches.  */
>> +#define MICROMIPS_TARGET	"2147483647f"
>> +#define MICROMIPS_TARGET_LABEL	2147483647
>> +
>> +static void
>> +micromips_add_number_label (void)
>> +{
>> +  symbolS *s;
>> +  fb_label_instance_inc (MICROMIPS_TARGET_LABEL);
>> +  s = colon (fb_label_name (MICROMIPS_TARGET_LABEL, 0));
>> +  S_SET_OTHER (s, ELF_ST_SET_MICROMIPS (S_GET_OTHER (s)));
>> +}
>> +
>> 
>> Ugh, this is a bit hackish.  There's nothing stopping a user using
>> 2147483647f themselves.
>
>  This is now handled by micromips_label_name(), micromips_label_expr(), 
> micromips_label_inc() and micromips_add_label() in a manner similar to 
> what dollar_label_name() and fb_label_name(), etc. do, except that the 
> special character used in symbols generated is ^_, avoiding a clash.

Thanks, this looks better at first glance.

>  I have rewritten macro_end() entirely now.  I have changed the approach 
> such that if multiple instructions are emitted into a branch delay slot 
> and the first of these instructions is out of size, then two warnings are 
> produced.
>
>  The rationale is these are different classes of warnings -- the delay 
> slot size mismatch is fatal if the call is ever returned from.  Multiple 
> instructions may or may not be a problem depending on the actual piece of 
> code and author's intentions.  We had a discussion about it a few years 
> ago. ;)
>
>  To complete these changes I have modified the change to append_insn() 
> such that no warning is produced for a delay slot size mismatch if called 
> for a macro expansion as it would get in the way, especially in the case 
> of relaxation.  The API of this function had to be modified in a trivial 
> way and all the callers adjusted accordingly.

I'll have to think about this a bit.  And dig out that conversation ;-)

>> >> From a usability perspective, it's a shame that:
>> >> 
>> >> 	.set	micromips
>> >> 	.ent	foo
>> >> foo:
>> >> 	b	1f
>> >> 	nop
>> >> 	.end	foo
>> >> 	.ent	bar
>> >> bar:
>> >> 1:	nop
>> >> 	.end	bar
>> >> 
>> >> disassembles as:
>> >> 
>> >> 00000000 <foo>:
>> >>    0:   cfff            b       0 <foo>
>> >>                         0: R_MICROMIPS_PC10_S1  .L11
>> >>    2:   0c00            nop
>> >>    4:   0c00            nop
>> >> 
>> >> 00000006 <bar>:
>> >>    6:   0c00            nop
>> >> 
>> >> leaving the poor user with no idea what .L11 is.
>> >
>> >  Indeed.  This is a general limitation of `objdump' it would seem.  This 
>> > is no different to what you get with:
>> >
>> > $ cat b.s
>> > 	.globl	baz
>> > 	.ent	foo
>> > foo:
>> > 	b	baz
>> > 	nop
>> > 	.end	foo
>> > 	.ent	bar
>> > baz:
>> > bar:
>> > 1:	nop
>> > 	.end	bar
>> > $ mips-sde-elf-objdump -dr b.o
>> >
>> > b.o:     file format elf32-tradbigmips
>> >
>> >
>> > Disassembly of section .text:
>> >
>> > 00000000 <foo>:
>> >    0:	1000ffff 	b	0 <foo>
>> > 			0: R_MIPS_PC16	baz
>> >    4:	00000000 	nop
>> >    8:	00000000 	nop
>> >
>> > 0000000c <bar>:
>> >    c:	00000000 	nop
>> 
>> Well, it's a little different.  The user has at least defined two
>> named symbols in this case, so they have a good chance of knowing
>> what "baz" means.  In the microMIPS case we've invented a label
>> and are using it in preference to the user-defined one.
>
>  That's unfortunate, indeed.  [FIXME]

Have you looked into the work involved, before this gets dismissed
entirely as future work?

>> > I'd just recommend peeking at the symbol table (back to the first 
>> > program):
>> >
>> > $ mips-sde-elf-objdump -t b.o
>> >
>> > b.o:     file format elf32-tradbigmips
>> >
>> > SYMBOL TABLE:
>> > 00000000 l    d  .text	00000000 .text
>> > 00000000 l    d  .data	00000000 .data
>> > 00000000 l    d  .bss	00000000 .bss
>> > 00000000 l    d  .reginfo	00000000 .reginfo
>> > 00000000 l    d  .pdr	00000000 .pdr
>> > 00000000 l     F .text	00000006 0x80 foo
>> > 00000006 l     F .text	00000002 0x80 bar
>> > 00000006 l       .text	00000000 0x80 .L1^B1
>> 
>> I suppose having a symbol with ^B in it is less than ideal too.
>> AIUI that name was chosen specifically because it wasn't supposed
>> to be written out.
>> 
>> It would be especially confusing if the user or compiler had a ".L11"
>> label (without the ^B).
>
>  Actually this is a tough problem -- we need to emit a generated symbol 
> that does not clash with anything the user or GCC may have put in the 
> source.  Any ideas?  How is it done in other ports if anywhere?

None off-hand.  Seggestions from others very welcome.

I'll try to think of something when I've got more time.  For avoidance
of doubt, I think this does need to be fixed.

>> @@ -14813,6 +16230,8 @@ mips_elf_final_processing (void)
>>       file_ase_mt is true.  */
>>    if (file_ase_mips16)
>>      elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_M16;
>> +  if (file_ase_micromips)
>> +    elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_MICROMIPS;
>>  #if 0 /* XXX FIXME */
>>    if (file_ase_mips3d)
>>      elf_elfheader (stdoutput)->e_flags |= ???;
>> 
>> Do you really only want this flag to be set if -mmicromips was passed
>> on the command line?  (Yes, the same concern applies to MIPS16 and MDMX.)
>
>  Fixing it up is easy, but I'm not sure what the original intent of these 
> flags has been.  Do they mean:
>
> 1. I make use of the FOO feature and I assert it is available?
>
> 2. I make use of the FOO feature, but I may go and figure out if it's 
>    available?
>
> 3. I make use of the FOO feature and want to prevent linking with any
>    incompatible ones?
>
> Once we've determined the answer we may modify code accordingly or leave 
> it as it is.  It looks to me the current approach matches #1 and the ELF 
> program loader may refuse to execute the program if it sees a flag for a 
> feature that is not supported by the processor to run on.  Any .set 
> fragments within the program are guarded appropriately and hence they do 
> not need to set the flag (as it would be for #2).  Then #3 is sort of 
> tangential to the two others, but it does matter in this context, hence I 
> mentioned it (i.e. if #3 was true, then I'd be much happier with #3 & #1 
> than #3 & #2; otherwise I don't have a strong preference between #1 and 
> #2).
>
>  Current arrangement is similar to that of file_mips_isa even though the 
> ISA can be overridden by .set too and I think it makes sense to keep all 
> these flags consistent.

I think MIPS16 and microMIPS are fundamentally different from the ISA,
and even from MDMX.  IMO, it's reasonable to assume that, if the user is
taking a MIPS III target as their base system, that they'll assemble
with a MIPS III ISA flag.  I know others disagree, and think that such
things should always be specified by pseudo-ops.  Even if you're of that
opinion, though, it's easy in principle to set the flags to the minimum
ISA required by the assembly source.

MIPS16 and microMIPS are different because they represent an operating
mode that the processor can switch in and out of.  The fact that the
assembly source contains both MIPS16 and non-MIPS16 code isn't really a
good indicator that the code is designed to cope with non-MIPS16-capable
systems.

We could live without deciding between #1, #2 and #3 until now because
MIPS16 was the only feature like this.  Now that we've got two
incompatible code-compression methods, I think it's more important.

I too would like to hear other opinions.  I'm just not convinced by
the "it's similar to ISA selection" argument.  More below.

>> micromips_ip obviously started life as a cut-&-paste of mips_ip, and it
>> would have been nice to factor some code out.  At least split out the
>> block beginning:
>> 
>> +	    case 'F':
>> +	    case 'L':
>> +	    case 'f':
>> +	    case 'l':
>> +	      {
>> 
>> which is identical between the two, and far too subtle to copy wholesale.
>> There may be other good opportunities too.
>
>  Next time, I'm afraid. [FIXME]

Next time == next iteration?  If so, that's fine, but I think this
has to be fixed for the patch to be acceptable.

>> The same cut-&-paste concerns apply to micromips_macro, which obviously
>> started out as a copy of macro().  I realise there are special cases
>> for micromips (such as the DADDI assymmetry and the lack of
>> branch-likely instructions, to name only a few), but most of the
>> basic decisions are the same.
>> 
>> As it stands, we have a new 3524 line function, of which I imagine at
>> least 90% is shared with macro().  I really think the new microMIPS
>> macro handling should be integrated into macro() instead.  Don't be
>> afraid of factoring out code from macro() if it makes it easier to
>> integrate the microMIPS code.
>
>  Can we make it a follow-up patch sometime in the future?  I'm not afraid 
> of factoring code out of anywhere (I'm speaking of myself only of course), 
> but at this point the effort is about the same as writing this whole stuff 
> from scratch. :( [FIXME]

Sorry, I know it's a pain, but I just don't think the patch can go
in as it stands.   The fact that the amount of work is so daunting
means that (even with the best of intentions, which I realise yours
are), that follow-up is unlikely to happen.  In the meantime we'll
have a 3524-line function (haven't recalculated ;-)) that has to be
kept in sync with another even bigger function (or pair of functions),
and it just won't be obvious whether the divergences are deliberate
microMIPS differences or whether they're cases where the two functions
haven't been updated in the same way.

I remember how painful it was replacing the old macro relaxation
code so that it could support arbitrary alternatives.  This sort
of thing would double that pain.

And it's not just (or even principally) about cut-&-paste phobia.
microMIPS has been deliberately designed to provide a great deal
of source-level backwards compatibility, so it's no surprise that
the two modes require very similar code, and very similar decisions.
I think having a single function handling both is actually significantly
clearer, because it calls out which differences are deliberate,
hopefully with a helpful bit of commentary where necessary.

As things stand, it's already a bit of an archaeology exercise trying
to decide what the differences actually are.

>  Overall I'm a bit concerned about all this linker relaxation stuff -- it 
> breaks -falign-jumps, -falign-labels and -falign-loops which may have a 
> severe performance penalty and should therefore be enabled conditionally 
> only, preferably where all the three options are set to 1 (meaning that 
> would be naturally implied by -Os).  A linker option would be required an 
> set appropriately by the GCC driver. [FIXME]

Yeah, I agree a bit more rigour would be nice here.  Without it, though,
I think it's generally OK to assume that anyone using MIPS16 or microMIPS
is more of the -Os rather than -O2 mindset, so I agree this is at most a
FIXME.

>> Did you actually test this with n64, say with a gcc bootstrap?  Same
>> comment goes for elfn32-mips.c.
>> 
>> Why only do the linker relaxation for elf32-mips.c (o32, o64 & EABI)?
>> Why not for n32 and n64 too?
>
>  The answer to all the questions is negative.  There is no 64-bit 
> microMIPS hardware available at the moment.  The best bet might be QEMU -- 
> NathanF, have you implemented any of the 64-bit instructions in QEMU?  
> Otherwise there's probably no way do do any of 64-bit microMIPS testing 
> beside what's done in binutils.  And no library work of any kind has 
> started for 64-bit microMIPS support AFAIK.  Hence there has been little 
> incentive to attempt anything but rudimentary support for 64-bit ABIs.

OK, in that case, never mind about testing 64-bit ;-)  However...

>  I envisage all the relaxation stuff to be either moved over to 
> elfxx-mips.c or copied to elfn32-mips.c and elf64-mips.c, as applicable, 
> once we have real 64-bit support.

...I still think this stuff should start life in elfxx-mips.c, even if
it's only used by elf32-mips.c at first.

>> That said, why split these up?  bfd_{get,put}_32
>> don't require aligned addresses.
>
>  I think it's easier and more readable this way as with bfd_{get,put}_32() 
> you'd have to halfword-swap the bit patterns produced based on the target 
> endianness.

Hmm, good point ;-)

>> @@ -5127,12 +5200,26 @@ mips_elf_calculate_relocation (bfd *abfd
>>  	      + h->la25_stub->stub_section->output_offset
>>  	      + h->la25_stub->offset);
>>  
>> +  /* Make sure MIPS16 and microMIPS are not used together.  */
>> +  if ((r_type == R_MIPS16_26 && target_is_micromips_code_p)
>> +      || (r_type == R_MICROMIPS_26_S1 && target_is_16_bit_code_p))
>> +   {
>> +      (*_bfd_error_handler)
>> +	(_("MIPS16 and microMIPS functions cannot call each other"));
>> +      return bfd_reloc_notsupported;
>> +   }
>> 
>> Should this be extended to check for branches too?
>
>  That would be a useful improvement I suppose, but MIPS16 code doesn't 
> care either (you can't use a branch to switch the ISA mode).  Overall I 
> think it's a corner case -- branches to external symbols are a rarity. 
> [FIXME]

But it is (or feels like) something that people have asked about on many
occasions, before we decided to ignore the botched ABI definition of
R_MIPS_PC16.

If it was a lot of work, I'd be sympathetic, but I think this is
something that's easily done, and handling one pair of relocs without
the others seems inconsistent.

>  I think R_MIPS_26 should be used for microMIPS JALX.  I don't like the 
> idea of overloading R_MICROMIPS_26_S1 this way, especially given another 
> relocation already fits.  What do you think?  It is too late to fix the 
> ABI probably though; I'm thinking what the consequences might be...

TBH, I quite like having a different reloc for the microMIPS version.
I agree it's probably moot though; the ABI has already been set.

>> Use of 0xfffffffc isn't portable for 64-bit addresses;
>> use "-4" or "~(bfd_vma) 3" instead.
>
>  I'm nasty enough to use (foo | 3) ^ 3 and avoid type width and promotion 
> dependencies altogether in such cases and hope for GCC to be smart and do 
> the right thing and combine the two ops.

Hmm, well... TBH, I don't really see that as an improvement over the
other two -- C is C -- but I'll let it pass ;-)

>> -  /* If this is an odd-valued function symbol, assume it's a MIPS16 one.  */
>> +  /* If this is an odd-valued function symbol, assume it's a MIPS16
>> +     or microMIPS one.  */
>>    if (ELF_ST_TYPE (elfsym->internal_elf_sym.st_info) == STT_FUNC
>>        && (asym->value & 1) != 0)
>>      {
>>        asym->value--;
>> -      elfsym->internal_elf_sym.st_other
>> -	= ELF_ST_SET_MIPS16 (elfsym->internal_elf_sym.st_other);
>> +      if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS)
>> +	elfsym->internal_elf_sym.st_other
>> +	  = ELF_ST_SET_MICROMIPS (elfsym->internal_elf_sym.st_other);
>> +      else
>> +	elfsym->internal_elf_sym.st_other
>> +	  = ELF_ST_SET_MIPS16 (elfsym->internal_elf_sym.st_other);
>>      }
>>  }
>>  
>> 
>> So a file can't mix MIPS16 and microMIPS code?  We should probably
>> detect that explicitly.  I'd like a clear statement of what the
>> interoperability restrictions are.
>> 
>> This goes back to the question of when EF_MIPS_ARCH_ASE_MICROMIPS
>> should be set (see previous reviews).
>
>  Background information first -- you can't have a piece of MIPS hardware, 
> either real or simulated, with the MIPS16 ASE and the microMIPS ASE 
> implemented both at a time.  This is a design assumption that allowed the 
> ISA bit to be overloaded.
>
>  That obviously does not mean -- in principle -- that you can't have an 
> executable (or one plus a mixture of shared libraries) where some 
> functions are MIPS16 code and some are microMIPS code, either of which 
> only called once the presence of the respective ASE has been determined.  
> While a valid configuration this is also a rare exotic corner case -- I 
> could imagine a piece of generic, processor-independent console/bootstrap 
> firmware like this for example, but little beyond that.
>
>  We had a discussion about it and the conclusion was from the user's 
> perspective the most beneficial configuration is one where mixing MIPS16 
> and microMIPS code within a single executable is forbidden by default.  
> The reason is a build-time error is always better than a run-time one 
> (especially when the device has been placed out there in the field 
> already; hopefully not an Ariane 5 rocket) and the case where mixing 
> MIPS16 and microMIPS code would almost always happen is when the user 
> picked the wrong library by mistake.  It is therefore most productive to 
> fail at this point rather than later.

I agree.  In that case, though, I think it's important that we go for #1
in your list above, otherwise this check doesn't really count for much.
I think having a way of forcing interpretation #2 fits into the same
category as...

>  A future enhancement could add assembler and linker switches to override 
> this default and mix the two ASEs in a single executable. [FIXME]

...this, which I agree is best left for future work.

>> +  else if ((insn & 0x1c00) != 0x0400
>> +	   && (insn & 0x1c00) != 0x0800
>> +	   && (insn & 0x1c00) != 0x0c00)
>> +    {
>> +      /* This is a 32-bit microMIPS instruction.  */
>> +      higher = insn;
>> +
>> +      status = (*info->read_memory_func) (memaddr + 2, buffer, 2, info);
>> +      if (status != 0)
>> +	{
>> +	  (*info->fprintf_func) (info->stream, "micromips 0x%x",
>> +				 (unsigned int) higher);
>> +	  (*info->memory_error_func) (status, memaddr + 2, info);
>> +	  return -1;
>> +	}
>> 
>> Why print "micromips " here but not in the 48-byte case?
>
>  It looks to me it's been modelled after the MIPS16 version where "extend 
> 0x..." is printed in the case of a read error.  I'm not sure if either 
> makes sense (.byte foo or suchlike that some other ports output in such a 
> case looks more reasonable to me), but at least it is consistent.

Hmm, and MIPS16 doesn't print a prefix for unknown 4-byte ops.
OK, in that case, I agree the patch is right for consistency.
I agree with you about .byte being better in principle though,
as a possible future enhancement.

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2010-07-26 19:03     ` Richard Sandiford
@ 2010-12-07  1:13       ` Maciej W. Rozycki
  2010-12-12 14:59         ` Richard Sandiford
  2011-01-02 11:36         ` Richard Sandiford
  0 siblings, 2 replies; 41+ messages in thread
From: Maciej W. Rozycki @ 2010-12-07  1:13 UTC (permalink / raw)
  To: Richard Sandiford
  Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
	Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers,
	Nathan Froyd

[-- Attachment #1: Type: TEXT/PLAIN, Size: 49740 bytes --]

Hi Richard,

 It's been a while, but time has been spent well and here's the next 
update to the code.  I believe I have addressed all your concerns.  Some 
detailed notes follow below.

> >  I have placed the translation in macro_map_reloc() now.  That incurs an 
> > O(n) performance penalty because all relocations in the microMIPS mode 
> > have to be iterated over the table of mappings; regrettably BFD_RELOC_* 
> > definitions are sparse so an O(1) lookup table cannot be used.  By keeping 
> > it sorted some time can be saved, but that's still O(n).  This could be 
> > reduced to O(log n) with a binary search, but I fear with the limited 
> > number of relocs handled the overhead would kill the benefit.
> 
> TBH, I think a case statement would be fine here.  It's then up to
> the compiler to pick the best implementation.

 Hmm, maybe, maybe not.  Anyway my proposal is semantically correct, so if 
you'd like to improve it, then please feel free. ;)

> >  I have rewritten macro_end() entirely now.  I have changed the approach 
> > such that if multiple instructions are emitted into a branch delay slot 
> > and the first of these instructions is out of size, then two warnings are 
> > produced.
> >
> >  The rationale is these are different classes of warnings -- the delay 
> > slot size mismatch is fatal if the call is ever returned from.  Multiple 
> > instructions may or may not be a problem depending on the actual piece of 
> > code and author's intentions.  We had a discussion about it a few years 
> > ago. ;)
> >
> >  To complete these changes I have modified the change to append_insn() 
> > such that no warning is produced for a delay slot size mismatch if called 
> > for a macro expansion as it would get in the way, especially in the case 
> > of relaxation.  The API of this function had to be modified in a trivial 
> > way and all the callers adjusted accordingly.
> 
> I'll have to think about this a bit.  And dig out that conversation ;-)

 Have you?

> >> >> From a usability perspective, it's a shame that:
> >> >> 
> >> >> 	.set	micromips
> >> >> 	.ent	foo
> >> >> foo:
> >> >> 	b	1f
> >> >> 	nop
> >> >> 	.end	foo
> >> >> 	.ent	bar
> >> >> bar:
> >> >> 1:	nop
> >> >> 	.end	bar
> >> >> 
> >> >> disassembles as:
> >> >> 
> >> >> 00000000 <foo>:
> >> >>    0:   cfff            b       0 <foo>
> >> >>                         0: R_MICROMIPS_PC10_S1  .L11
> >> >>    2:   0c00            nop
> >> >>    4:   0c00            nop
> >> >> 
> >> >> 00000006 <bar>:
> >> >>    6:   0c00            nop
> >> >> 
> >> >> leaving the poor user with no idea what .L11 is.
> >> >
> >> >  Indeed.  This is a general limitation of `objdump' it would seem.  This 
> >> > is no different to what you get with:
> >> >
> >> > $ cat b.s
> >> > 	.globl	baz
> >> > 	.ent	foo
> >> > foo:
> >> > 	b	baz
> >> > 	nop
> >> > 	.end	foo
> >> > 	.ent	bar
> >> > baz:
> >> > bar:
> >> > 1:	nop
> >> > 	.end	bar
> >> > $ mips-sde-elf-objdump -dr b.o
> >> >
> >> > b.o:     file format elf32-tradbigmips
> >> >
> >> >
> >> > Disassembly of section .text:
> >> >
> >> > 00000000 <foo>:
> >> >    0:	1000ffff 	b	0 <foo>
> >> > 			0: R_MIPS_PC16	baz
> >> >    4:	00000000 	nop
> >> >    8:	00000000 	nop
> >> >
> >> > 0000000c <bar>:
> >> >    c:	00000000 	nop
> >> 
> >> Well, it's a little different.  The user has at least defined two
> >> named symbols in this case, so they have a good chance of knowing
> >> what "baz" means.  In the microMIPS case we've invented a label
> >> and are using it in preference to the user-defined one.
> >
> >  That's unfortunate, indeed.  [FIXME]
> 
> Have you looked into the work involved, before this gets dismissed
> entirely as future work?

 Well, first we'd have to come up with a solution before we go and think 
about implementation.  As it is I fail to see one -- please propose one 
if you can think of any.

 The thing is we really have to report the right symbol in the relocation.  
Doing otherwise is the wrong thing to do as it's not the purpose of the 
tool to add any interpretation beyond what the ELF standard provides and 
will also confuse the user, especially when the replacement symbol chosen 
with an .o file resolves to a different location on the final link.

 Then we have no reliable way to report the generated symbol, especially 
when --prefix-addresses is used.

 We still have -t as a workaround.

> >> > I'd just recommend peeking at the symbol table (back to the first 
> >> > program):
> >> >
> >> > $ mips-sde-elf-objdump -t b.o
> >> >
> >> > b.o:     file format elf32-tradbigmips
> >> >
> >> > SYMBOL TABLE:
> >> > 00000000 l    d  .text	00000000 .text
> >> > 00000000 l    d  .data	00000000 .data
> >> > 00000000 l    d  .bss	00000000 .bss
> >> > 00000000 l    d  .reginfo	00000000 .reginfo
> >> > 00000000 l    d  .pdr	00000000 .pdr
> >> > 00000000 l     F .text	00000006 0x80 foo
> >> > 00000006 l     F .text	00000002 0x80 bar
> >> > 00000006 l       .text	00000000 0x80 .L1^B1
> >> 
> >> I suppose having a symbol with ^B in it is less than ideal too.
> >> AIUI that name was chosen specifically because it wasn't supposed
> >> to be written out.
> >> 
> >> It would be especially confusing if the user or compiler had a ".L11"
> >> label (without the ^B).
> >
> >  Actually this is a tough problem -- we need to emit a generated symbol 
> > that does not clash with anything the user or GCC may have put in the 
> > source.  Any ideas?  How is it done in other ports if anywhere?
> 
> None off-hand.  Seggestions from others very welcome.
> 
> I'll try to think of something when I've got more time.  For avoidance
> of doubt, I think this does need to be fixed.

 While looking into it I have implemented Joseph's suggestion to cover all 
these generated symbols with the --special-syms option.  This has actually 
revealed this is a preexisting problem as MIPS16 code already generates 
such symbols (see the relevant test suite updates included with the patch; 
search for --special-syms).  While I do agree this is a problem that needs 
to be addressed one way or another, given this circumstance I don't think 
you can reasonably reject this submission on the basis of this problem 
staying unfixed.

> >> @@ -14813,6 +16230,8 @@ mips_elf_final_processing (void)
> >>       file_ase_mt is true.  */
> >>    if (file_ase_mips16)
> >>      elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_M16;
> >> +  if (file_ase_micromips)
> >> +    elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_MICROMIPS;
> >>  #if 0 /* XXX FIXME */
> >>    if (file_ase_mips3d)
> >>      elf_elfheader (stdoutput)->e_flags |= ???;
> >> 
> >> Do you really only want this flag to be set if -mmicromips was passed
> >> on the command line?  (Yes, the same concern applies to MIPS16 and MDMX.)
> >
> >  Fixing it up is easy, but I'm not sure what the original intent of these 
> > flags has been.  Do they mean:
> >
> > 1. I make use of the FOO feature and I assert it is available?
> >
> > 2. I make use of the FOO feature, but I may go and figure out if it's 
> >    available?
> >
> > 3. I make use of the FOO feature and want to prevent linking with any
> >    incompatible ones?
> >
> > Once we've determined the answer we may modify code accordingly or leave 
> > it as it is.  It looks to me the current approach matches #1 and the ELF 
> > program loader may refuse to execute the program if it sees a flag for a 
> > feature that is not supported by the processor to run on.  Any .set 
> > fragments within the program are guarded appropriately and hence they do 
> > not need to set the flag (as it would be for #2).  Then #3 is sort of 
> > tangential to the two others, but it does matter in this context, hence I 
> > mentioned it (i.e. if #3 was true, then I'd be much happier with #3 & #1 
> > than #3 & #2; otherwise I don't have a strong preference between #1 and 
> > #2).
> >
> >  Current arrangement is similar to that of file_mips_isa even though the 
> > ISA can be overridden by .set too and I think it makes sense to keep all 
> > these flags consistent.
> 
> I think MIPS16 and microMIPS are fundamentally different from the ISA,
> and even from MDMX.  IMO, it's reasonable to assume that, if the user is
> taking a MIPS III target as their base system, that they'll assemble
> with a MIPS III ISA flag.  I know others disagree, and think that such
> things should always be specified by pseudo-ops.  Even if you're of that
> opinion, though, it's easy in principle to set the flags to the minimum
> ISA required by the assembly source.
> 
> MIPS16 and microMIPS are different because they represent an operating
> mode that the processor can switch in and out of.  The fact that the
> assembly source contains both MIPS16 and non-MIPS16 code isn't really a
> good indicator that the code is designed to cope with non-MIPS16-capable
> systems.
> 
> We could live without deciding between #1, #2 and #3 until now because
> MIPS16 was the only feature like this.  Now that we've got two
> incompatible code-compression methods, I think it's more important.
> 
> I too would like to hear other opinions.  I'm just not convinced by
> the "it's similar to ISA selection" argument.  More below.

 Have you, actually?  See below too.

> >> micromips_ip obviously started life as a cut-&-paste of mips_ip, and it
> >> would have been nice to factor some code out.  At least split out the
> >> block beginning:
> >> 
> >> +	    case 'F':
> >> +	    case 'L':
> >> +	    case 'f':
> >> +	    case 'l':
> >> +	      {
> >> 
> >> which is identical between the two, and far too subtle to copy wholesale.
> >> There may be other good opportunities too.
> >
> >  Next time, I'm afraid. [FIXME]
> 
> Next time == next iteration?  If so, that's fine, but I think this
> has to be fixed for the patch to be acceptable.

 I have folded micromips_ip() into mips_ip() now.  This revealed a couple 
of preexisting problems that I fixed with some of the patches sent 
previously.  Likewise fixes for problems with new microMIPS code have been 
included here.

> >> The same cut-&-paste concerns apply to micromips_macro, which obviously
> >> started out as a copy of macro().  I realise there are special cases
> >> for micromips (such as the DADDI assymmetry and the lack of
> >> branch-likely instructions, to name only a few), but most of the
> >> basic decisions are the same.
> >> 
> >> As it stands, we have a new 3524 line function, of which I imagine at
> >> least 90% is shared with macro().  I really think the new microMIPS
> >> macro handling should be integrated into macro() instead.  Don't be
> >> afraid of factoring out code from macro() if it makes it easier to
> >> integrate the microMIPS code.
> >
> >  Can we make it a follow-up patch sometime in the future?  I'm not afraid 
> > of factoring code out of anywhere (I'm speaking of myself only of course), 
> > but at this point the effort is about the same as writing this whole stuff 
> > from scratch. :( [FIXME]
> 
> Sorry, I know it's a pain, but I just don't think the patch can go
> in as it stands.   The fact that the amount of work is so daunting
> means that (even with the best of intentions, which I realise yours
> are), that follow-up is unlikely to happen.  In the meantime we'll
> have a 3524-line function (haven't recalculated ;-)) that has to be
> kept in sync with another even bigger function (or pair of functions),
> and it just won't be obvious whether the divergences are deliberate
> microMIPS differences or whether they're cases where the two functions
> haven't been updated in the same way.
> 
> I remember how painful it was replacing the old macro relaxation
> code so that it could support arbitrary alternatives.  This sort
> of thing would double that pain.
> 
> And it's not just (or even principally) about cut-&-paste phobia.
> microMIPS has been deliberately designed to provide a great deal
> of source-level backwards compatibility, so it's no surprise that
> the two modes require very similar code, and very similar decisions.
> I think having a single function handling both is actually significantly
> clearer, because it calls out which differences are deliberate,
> hopefully with a helpful bit of commentary where necessary.
> 
> As things stand, it's already a bit of an archaeology exercise trying
> to decide what the differences actually are.

 Likewise, I have folded micromips_macro() into macro() and as a bonus 
micromips_macro_build() into macro_build() as well.  Again, this revealed 
numerous problems that I fixed too.

> >  Overall I'm a bit concerned about all this linker relaxation stuff -- it 
> > breaks -falign-jumps, -falign-labels and -falign-loops which may have a 
> > severe performance penalty and should therefore be enabled conditionally 
> > only, preferably where all the three options are set to 1 (meaning that 
> > would be naturally implied by -Os).  A linker option would be required an 
> > set appropriately by the GCC driver. [FIXME]
> 
> Yeah, I agree a bit more rigour would be nice here.  Without it, though,
> I think it's generally OK to assume that anyone using MIPS16 or microMIPS
> is more of the -Os rather than -O2 mindset, so I agree this is at most a
> FIXME.

 Mindset aside, GCC has a documented behaviour that does not include 
"maybe" in its definition.  It might make sense to update GCC 
documentation to warn the user at the very least.

> >> Did you actually test this with n64, say with a gcc bootstrap?  Same
> >> comment goes for elfn32-mips.c.
> >> 
> >> Why only do the linker relaxation for elf32-mips.c (o32, o64 & EABI)?
> >> Why not for n32 and n64 too?
> >
> >  The answer to all the questions is negative.  There is no 64-bit 
> > microMIPS hardware available at the moment.  The best bet might be QEMU -- 
> > NathanF, have you implemented any of the 64-bit instructions in QEMU?  
> > Otherwise there's probably no way do do any of 64-bit microMIPS testing 
> > beside what's done in binutils.  And no library work of any kind has 
> > started for 64-bit microMIPS support AFAIK.  Hence there has been little 
> > incentive to attempt anything but rudimentary support for 64-bit ABIs.
> 
> OK, in that case, never mind about testing 64-bit ;-)  However...
> 
> >  I envisage all the relaxation stuff to be either moved over to 
> > elfxx-mips.c or copied to elfn32-mips.c and elf64-mips.c, as applicable, 
> > once we have real 64-bit support.
> 
> ...I still think this stuff should start life in elfxx-mips.c, even if
> it's only used by elf32-mips.c at first.

 I have moved this piece now then, although care has to be taken about it 
-- there are some assumptions about o32 hardcoded, e.g. the HI16/LO16 
relaxation is certainly dangerous on n64 and may lead to broken code 
(ADDIUPC has undefined semantics outside compatibility segments).

> >> @@ -5127,12 +5200,26 @@ mips_elf_calculate_relocation (bfd *abfd
> >>  	      + h->la25_stub->stub_section->output_offset
> >>  	      + h->la25_stub->offset);
> >>  
> >> +  /* Make sure MIPS16 and microMIPS are not used together.  */
> >> +  if ((r_type == R_MIPS16_26 && target_is_micromips_code_p)
> >> +      || (r_type == R_MICROMIPS_26_S1 && target_is_16_bit_code_p))
> >> +   {
> >> +      (*_bfd_error_handler)
> >> +	(_("MIPS16 and microMIPS functions cannot call each other"));
> >> +      return bfd_reloc_notsupported;
> >> +   }
> >> 
> >> Should this be extended to check for branches too?
> >
> >  That would be a useful improvement I suppose, but MIPS16 code doesn't 
> > care either (you can't use a branch to switch the ISA mode).  Overall I 
> > think it's a corner case -- branches to external symbols are a rarity. 
> > [FIXME]
> 
> But it is (or feels like) something that people have asked about on many
> occasions, before we decided to ignore the botched ABI definition of
> R_MIPS_PC16.
> 
> If it was a lot of work, I'd be sympathetic, but I think this is
> something that's easily done, and handling one pair of relocs without
> the others seems inconsistent.

 Fixed, thanks for your point.

> >> -  /* If this is an odd-valued function symbol, assume it's a MIPS16 one.  */
> >> +  /* If this is an odd-valued function symbol, assume it's a MIPS16
> >> +     or microMIPS one.  */
> >>    if (ELF_ST_TYPE (elfsym->internal_elf_sym.st_info) == STT_FUNC
> >>        && (asym->value & 1) != 0)
> >>      {
> >>        asym->value--;
> >> -      elfsym->internal_elf_sym.st_other
> >> -	= ELF_ST_SET_MIPS16 (elfsym->internal_elf_sym.st_other);
> >> +      if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS)
> >> +	elfsym->internal_elf_sym.st_other
> >> +	  = ELF_ST_SET_MICROMIPS (elfsym->internal_elf_sym.st_other);
> >> +      else
> >> +	elfsym->internal_elf_sym.st_other
> >> +	  = ELF_ST_SET_MIPS16 (elfsym->internal_elf_sym.st_other);
> >>      }
> >>  }
> >>  
> >> 
> >> So a file can't mix MIPS16 and microMIPS code?  We should probably
> >> detect that explicitly.  I'd like a clear statement of what the
> >> interoperability restrictions are.
> >> 
> >> This goes back to the question of when EF_MIPS_ARCH_ASE_MICROMIPS
> >> should be set (see previous reviews).
> >
> >  Background information first -- you can't have a piece of MIPS hardware, 
> > either real or simulated, with the MIPS16 ASE and the microMIPS ASE 
> > implemented both at a time.  This is a design assumption that allowed the 
> > ISA bit to be overloaded.
> >
> >  That obviously does not mean -- in principle -- that you can't have an 
> > executable (or one plus a mixture of shared libraries) where some 
> > functions are MIPS16 code and some are microMIPS code, either of which 
> > only called once the presence of the respective ASE has been determined.  
> > While a valid configuration this is also a rare exotic corner case -- I 
> > could imagine a piece of generic, processor-independent console/bootstrap 
> > firmware like this for example, but little beyond that.
> >
> >  We had a discussion about it and the conclusion was from the user's 
> > perspective the most beneficial configuration is one where mixing MIPS16 
> > and microMIPS code within a single executable is forbidden by default.  
> > The reason is a build-time error is always better than a run-time one 
> > (especially when the device has been placed out there in the field 
> > already; hopefully not an Ariane 5 rocket) and the case where mixing 
> > MIPS16 and microMIPS code would almost always happen is when the user 
> > picked the wrong library by mistake.  It is therefore most productive to 
> > fail at this point rather than later.
> 
> I agree.  In that case, though, I think it's important that we go for #1
> in your list above, otherwise this check doesn't really count for much.
> I think having a way of forcing interpretation #2 fits into the same
> category as...

 So I have changed the semantics of both flags now -- either of these is 
only ever set if actual MIPS16 or microMIPS code have been generated.  
Data does not count and neither does either the -mips16/-mmicromips option 
or the .set mips16/micromips pseudo-op.  Linking modules containing MIPS16 
code together with ones containing microMIPS code has been forbidden.  I 
have added an LD test case to verify that.

> >  A future enhancement could add assembler and linker switches to override 
> > this default and mix the two ASEs in a single executable. [FIXME]
> 
> ...this, which I agree is best left for future work.

 So I did.

 Beside the above I have made numerous bug fixes and applied less critical 
clean-ups throughout the code.  Tested as usually, with mips-sde-elf and 
mips-linux-gnu.  But I enabled NewABI tests this time too and (trivially) 
adjusted the relevant test case matching patterns, i.e. there should be no 
failures induced by the addition of microMIPS support with targets like 
mips64*-linux-gnu either.

  Maciej

binutils-20101207-umips.diff
[Patch attached compressed due to its size.]

bfd/
2010-12-07  Chao-ying Fu  <fu@mips.com>
            Ilie Garbacea  <ilie@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>
            Joseph Myers  <joseph@codesourcery.com>
            Catherine Moore  <clm@codesourcery.com>

	* 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.
	(BZ32_REG, BZ32_REG_FIELD): New macros.
	(bz_insns_32, bzc_insns_32, bz_insns_16): New variables.
	(BZ16_REG, BZ16_REG_FIELD): New macros.
	(jal_insn_32_bd16, jal_insn_32_bd32): New variables.
	(j_insn_32, jalr_insn_32): Likewise.
	(JALR_SREG, JALR_TREG): New macros.
	(call_insn_32_bd16, call_insn_32_bd32): New variables.
	(ds_insns_32_bd16): Likewise.
	(jalx_insn_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.
	(relax_dslot_norel16, relax_dslot_norel32): Likewise.
	(relax_dslot_rel): 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/
2010-12-07  Chao-ying Fu  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* readelf.c (get_machine_flags): Handle microMIPS ASE.
	(get_mips_symbol_other): Likewise.

gas/
2010-12-07  Chao-ying Fu  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* 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 (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_USER_16BIT): Likewise.
	(RELAX_MICROMIPS_UNCOND, RELAX_MICROMIPS_LINK): Likewise.
	(RELAX_MICROMIPS_TOOFAR, RELAX_MICROMIPS_MARK_TOOFAR): Likewise.
	(RELAX_MICROMIPS_CLEAR_TOOFAR): Likewise.
	(RELAX_MICROMIPS_EXTENDED): Likewise.
	(RELAX_MICROMIPS_MARK_EXTENDED): Likewise.
	(RELAX_MICROMIPS_CLEAR_EXTENDED): 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.
	(is_size_valid, is_delay_slot_valid): New functions.
	(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.
	(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_map_reloc): New function.
	(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.
	(SKIP_SPACE_TABS): Move earlier on.
	(mips_ip): Handle microMIPS ASE.
	(micromips_percent_op): New variable.
	(parse_relocation): Handle microMIPS ASE.
	(my_getExpression): Likewise.
	(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/
2010-12-07  Maciej W. Rozycki  <macro@codesourcery.com>
            Chao-ying Fu  <fu@mips.com>

	* 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-1.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@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@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/mips32-imm.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/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/
2010-12-07  Chao-ying Fu  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* 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/
2010-12-07  Chao-ying Fu  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* 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, M_BEQL, M_BGEZL): New enum
	values.
	(M_BGEZALL, M_BGTZL, M_BLEZL, M_BLTZL, M_BLTZALL): Likewise.
	(M_CACHE_OB, 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_LWP_AB, M_LWP_OB): Likewise.
	(M_LWR_OB, 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, M_SDP_AB): Likewise.
	(M_SDP_OB, M_SDR_OB, M_SWC2_OB, M_SWL_OB, M_SWM_AB): Likewise.
	(M_SWM_OB, 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/
2010-12-07  Catherine Moore  <clm@codesourcery.com>
            Chao-ying Fu  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* 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/
2010-12-07  Chao-ying Fu  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* 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.

[-- Attachment #2: Type: APPLICATION/octet-stream, Size: 157572 bytes --]

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2010-12-07  1:13       ` Maciej W. Rozycki
@ 2010-12-12 14:59         ` Richard Sandiford
  2010-12-14 13:30           ` Maciej W. Rozycki
  2011-01-02 11:36         ` Richard Sandiford
  1 sibling, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2010-12-12 14:59 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
	Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers,
	Nathan Froyd

This is a review of everything up to the end of elfxx-mips.c.  Not sure
when I'll be able to do the rest.

I think we're getting close, so could you post any updates as patches
relative to this one, rather than reposting the whole thing?

"Maciej W. Rozycki" <macro@codesourcery.com> writes:
> @@ -2372,7 +3002,14 @@ bfd_elf64_bfd_reloc_name_lookup (bfd *ab
>         i++)
>      if (mips16_elf64_howto_table_rela[i].name != NULL
>  	&& strcasecmp (mips16_elf64_howto_table_rela[i].name, r_name) == 0)
> -      return &mips16_elf64_howto_table_rela[i];
> +
> +  for (i = 0;
> +       i < (sizeof (micromips_elf64_howto_table_rela)
> +	    / sizeof (micromips_elf64_howto_table_rela[0]));
> +       i++)
> +    if (micromips_elf64_howto_table_rela[i].name != NULL
> +	&& strcasecmp (micromips_elf64_howto_table_rela[i].name, r_name) == 0)
> +      return &micromips_elf64_howto_table_rela[i];
>  
>    if (strcasecmp (elf_mips_gnu_vtinherit_howto.name, r_name) == 0)
>      return &elf_mips_gnu_vtinherit_howto;

This hunk looks wrong.  I doubt you meant to remove the mips16 line.
Same for elfn32-mips.c.

> @@ -5040,6 +5159,10 @@ mips_elf_calculate_relocation (bfd *abfd
>  	}
>  
>        target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (h->root.other);
> +      /* If the output section is the PLT section,
> +         then the target is not microMIPS.  */
> +      target_is_micromips_code_p = (htab->splt != sec)
> +				    && ELF_ST_IS_MICROMIPS (h->root.other);
>      }
>  
>    /* If this is a reference to a 16-bit function with a stub, we need

Formatting nit:

      /* If the output section is the PLT section,
         then the target is not microMIPS.  */
      target_is_micromips_code_p = (htab->splt != sec
				    && ELF_ST_IS_MICROMIPS (h->root.other));

More importantly, the comment isn't any help.  When do we create
statically-resolved relocations against .plt?

>    /* Calls from 16-bit code to 32-bit code and vice versa require the
> -     mode change.  */
> -  *cross_mode_jump_p = !info->relocatable
> -		       && ((r_type == R_MIPS16_26 && !target_is_16_bit_code_p)
> -			   || ((r_type == R_MIPS_26 || r_type == R_MIPS_JALR)
> -			       && target_is_16_bit_code_p));
> +     mode change.  This is not required for calls to undefined weak
> +     symbols, which should never be executed at runtime.  */

But why do we need to go out of our way to check for them?  I'm sure
there's a good reason, but the comment doesn't give much clue what it is.

> @@ -9223,6 +9499,16 @@ _bfd_mips_elf_relocate_section (bfd *out
>  	case bfd_reloc_ok:
>  	  break;
>  
> +	case bfd_reloc_outofrange:
> +	  if (jal_reloc_p (howto->type))
> +	    {
> +	      msg = _("JALX to not a word-aligned address");
> +	      info->callbacks->warning
> +		(info, msg, name, input_bfd, input_section, rel->r_offset);
> +	      return FALSE;
> +	    }
> +	  /* Fall through.  */
> +
>  	default:
>  	  abort ();
>  	  break;

I suppose that should be something like "JALX to a non-word-aligned address".

> +  /* microMIPS local and global symbols have the least significant bit
> +     set.  Because all values are either multiple of 2 or multiple of
> +     4, compensating for this bit is as simple as setting it in
> +     comparisons. Just to be sure, check anyway before proceeding. */
> +  BFD_ASSERT (addr % 2 == 0);
> +  BFD_ASSERT (toaddr % 2 == 0);
> +  BFD_ASSERT (count % 2 == 0);

I'm suspicious about the toaddr assert.  You can create text sections
with odd-valued sizes:

	.section	.text.foo,"ax",@progbits
	.byte	1

and as discussed elsewhere, asserts are really to double-check
conditions that we think must already hold.

> +  addr |= 1;
> +  toaddr |= 1;
> +
> +  /* Adjust the local symbols defined in this section.  */
> +  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
> +  isym = (Elf_Internal_Sym *) symtab_hdr->contents;
> +  for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
> +    {
> +      if (isym->st_shndx == sec_shndx
> +	  && isym->st_value > addr
> +	  && isym->st_value < toaddr)
> +	isym->st_value -= count;
> +    }

Hmm, microMIPS symbols created in the proper, blessed way (by proper,
blessed ways of defining MIPS16 labels in assembly) should be even in
the input object, and IIRC, the linker keeps local symbols that way
internally.  Only symbols entered into the hash table are odd.
(c.f. mips_elf_calculate_relocation, where we have to add 1 to
local symbols.)  So I would have expected the "|= 1"s to be applied
after this block rather than before it.  Even then:

> +  /* Now adjust the global symbols defined in this section.  */
> +  symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
> +	      - symtab_hdr->sh_info);
> +  sym_hashes = start_hashes = elf_sym_hashes (abfd);
> +  end_hashes = sym_hashes + symcount;
> +
> +  for (; sym_hashes < end_hashes; sym_hashes++)
> +    {
> +      struct elf_link_hash_entry *sym_hash = *sym_hashes;
> +
> +      if ((sym_hash->root.type == bfd_link_hash_defined
> +	   || sym_hash->root.type == bfd_link_hash_defweak)
> +	  && sym_hash->root.u.def.section == sec
> +	  && sym_hash->root.u.def.value > addr
> +	  && sym_hash->root.u.def.value < toaddr)
> +	sym_hash->root.u.def.value -= count;
> +    }

...if we're willing to extend the upper bound in this way, I wonder
whether there's really any point having an upper bound at all.

Then again, why doesn't the standard range (used by most targets)
include toaddr?  If you define an end marker:

end_of_section:
	# nothing after this

then wouldn't end_of_section == toaddr, and shouldn't it be included?

I see some targets rightly adjust st_size too.  We should do
the same here.

> +static unsigned long
> +find_match (unsigned long opcode, const struct opcode_descriptor insn[])
> +{
> +    unsigned long indx;
> +
> +    /* First opcode_table[] entry is ignored.  */
> +    for (indx = 1; insn[indx].mask != 0; indx++)
> +      if (MATCH (opcode, insn[indx]))
> +	return indx;
> +
> +    return 0;
> +}

But _why_ is the first entry ignored?

> +/* Check if there *might* be a 16-bit branch or jump at OFFSET
> +   with a fixed or variable length delay slot.  */
> +
> +static int
> +relax_dslot_norel16 (bfd *abfd, bfd_byte *ptr)

There's no parameter called "offset".  How about:

/* If PTR is known to point to a 16-bit branch or jump, return the
   minimum length of its delay slot, otherwise return 0.  */

At least, that's what the code seems to do, since it returns 2 for
things like:

> +  { /* "b(g|l)(e|t)z", "s,p",	*/ 0x40000000, 0xff200000 },

which as far as I can tell from the opcodes patch allows both 16-bit
and 32-bit delay slots.  (IV-g doesn't seem to be public yet, so I can't
check the spec.)  But from the way the function is used, it looks
like 0 really means "no size constraints", so why doesn't the function
return 0 for instructions like these?

Why are these routines checking for branches anyway?  We don't support
branches without relocations when doing this kind of relaxation.
I'd have expected only indirect jumps to be handled here.

Likewise relax_dslot_norel32.

> +  /* We don't have to do anything for a relocatable link, if
> +     this section does not have relocs, or if this is not a
> +     code section.  */
> +
> +  if (link_info->relocatable
> +      || (sec->flags & SEC_RELOC) == 0
> +      || sec->reloc_count == 0
> +      || (sec->flags & SEC_CODE) == 0)
> +    return TRUE;

Should we also check whether the micromips bit is set in the ELF
header flags?

> +	      nextopc = bfd_get_16 (abfd, contents + irel->r_offset + 4);
> +	      /* B16  */
> +	      if (MATCH (nextopc, b_insn_16))
> +		break;
> +	      /* JR16  */
> +	      if (MATCH (nextopc, jr_insn_16) && reg != JR16_REG (nextopc))
> +		break;
> +	      /* BEQZ16, BNEZ16  */
> +	      if (MATCH (nextopc, bz_insn_16) && reg != BZ16_REG (nextopc))
> +		break;
> +	      /* JALR16  */
> +	      if (MATCH (nextopc, jalr_insn_16_bd32)
> +		  && reg != JR16_REG (nextopc) && reg != RA)
> +		break;
> +	      continue;

I think this should be split out into a subfunction, like the relax_* ones.

/* PTR points to a 2-byte instruction.  Return true if it is a 16-bit
   branch that does not use register REG.  */

static bfd_boolean
is_16bit_branch_p (bfd *abfd, bfd_byte *ptr, unsigned int reg)

Likewise for the 4-byte case.

> +	  /* Give up if not the same register used with both relocations.  */

"Give up unless the same register is used with both relocations."

> +	  /* Now adjust pcrval, subtracting the offset to the LO16 reloc,
> +	     adding the size of the LUI instruction deleted and rounding
> +	     up to take masking of the two LSBs into account.  */
> +	  pcrval = ((pcrval - offset + 4 + 3) | 3) ^ 3;

Maybe its just me, but since pcrval was calculated much earlier,
and hasn't been used since being set, I'd find it easier to understand
if we simply calculate the pcrval for irel[1] directly:

      /* Calculate the pc-relative distance of the target from the LO16,
	 assuming that we can delete the 4-byte LUI.  */
      pcrval = (symval
		- (sec->output_section->vma + sec->output_offset)
		- (irel[1].r_offset - 4));

      /* Round up to take the masking of the two LSBs into account.  */
      pcrval = (prcval + 3) & -4;

What happens when we can't delete the LUI, because of its being in
a branch delay slot?

> +	  int bdsize = -1;
[...]
> +	  /* See if there is a jump or a branch reloc preceding the
> +	     LUI instruction immediately.  If so, then perform jump
> +	     or branch relaxation.  */
> +	  for (ibrrel = internal_relocs; ibrrel < irelend; ibrrel++)
> +	    {
> +	      offset = irel->r_offset - ibrrel->r_offset;
> +	      if (offset != 2 && offset != 4)
> +		continue;
> +
> +	      br_r_type = ELF32_R_TYPE (ibrrel->r_info);
> +	      if (offset == 2
> +		  && br_r_type != R_MICROMIPS_PC7_S1
> +		  && br_r_type != R_MICROMIPS_PC10_S1
> +		  && br_r_type != R_MICROMIPS_JALR)
> +		continue;
> +	      if (offset == 4
> +		  && br_r_type != R_MICROMIPS_26_S1
> +		  && br_r_type != R_MICROMIPS_PC16_S1
> +		  && br_r_type != R_MICROMIPS_JALR)
> +		continue;
> +
> +	      bdsize = relax_dslot_rel (abfd,
> +					contents + ibrrel->r_offset, offset);
> +	      break;
> +	    }
> +
> +	  /* Otherwise see if the LUI instruction *might* be in a
> +	     branch delay slot.  */
> +	  if (bdsize == -1)
> +	    {
> +	      bfd_byte *ptr = contents + ibrrel->r_offset;
> +
> +	      /* Assume the 32-bit LUI instruction is in a fixed delay slot
> +	         and cannot be optimised away.  */
> +	      bdsize = 4;
> +
> +	      if (ibrrel->r_offset >= 2)
> +		bdsize16 = relax_dslot_norel16 (abfd, ptr - 2);
> +	      if (ibrrel->r_offset >= 4)
> +		bdsize32 = relax_dslot_norel32 (abfd, ptr - 4);

I think the "ibrrel"s in the last block should be "irel"s instead.
As best I can tell, "ibrrel" == "irelend" here.  Is this case
covered by the testsuite?

I'm not sure whether I like the idea of making this function quadratic
simply to decide whether the preceding instruction is a branch,
but there's probably not much we can do about that.

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2010-12-12 14:59         ` Richard Sandiford
@ 2010-12-14 13:30           ` Maciej W. Rozycki
  2010-12-14 14:51             ` Richard Sandiford
                               ` (2 more replies)
  0 siblings, 3 replies; 41+ messages in thread
From: Maciej W. Rozycki @ 2010-12-14 13:30 UTC (permalink / raw)
  To: Richard Sandiford, Ilie Garbacea, Joseph Myers
  Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
	Catherine Moore, Nathan Sidwell, Nathan Froyd

Hello,

 Ilie, Joseph: I have some questions for you below, please respond.

> This is a review of everything up to the end of elfxx-mips.c.  Not sure
> when I'll be able to do the rest.

 OK, thanks for your effort so far.

> I think we're getting close, so could you post any updates as patches
> relative to this one, rather than reposting the whole thing?

 Yes, I think it will make it easier for us both to keep track of what has 
been addressed and what not.  I have no technical problem with including 
further changes in a separate patch.

> > @@ -2372,7 +3002,14 @@ bfd_elf64_bfd_reloc_name_lookup (bfd *ab
> >         i++)
> >      if (mips16_elf64_howto_table_rela[i].name != NULL
> >  	&& strcasecmp (mips16_elf64_howto_table_rela[i].name, r_name) == 0)
> > -      return &mips16_elf64_howto_table_rela[i];
> > +
> > +  for (i = 0;
> > +       i < (sizeof (micromips_elf64_howto_table_rela)
> > +	    / sizeof (micromips_elf64_howto_table_rela[0]));
> > +       i++)
> > +    if (micromips_elf64_howto_table_rela[i].name != NULL
> > +	&& strcasecmp (micromips_elf64_howto_table_rela[i].name, r_name) == 0)
> > +      return &micromips_elf64_howto_table_rela[i];
> >  
> >    if (strcasecmp (elf_mips_gnu_vtinherit_howto.name, r_name) == 0)
> >      return &elf_mips_gnu_vtinherit_howto;
> 
> This hunk looks wrong.  I doubt you meant to remove the mips16 line.
> Same for elfn32-mips.c.

 I believe I fixed this problem with elf32-mips.c, but obviously must have 
missed it here, thanks for spotting.

> > @@ -5040,6 +5159,10 @@ mips_elf_calculate_relocation (bfd *abfd
> >  	}
> >  
> >        target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (h->root.other);
> > +      /* If the output section is the PLT section,
> > +         then the target is not microMIPS.  */
> > +      target_is_micromips_code_p = (htab->splt != sec)
> > +				    && ELF_ST_IS_MICROMIPS (h->root.other);
> >      }
> >  
> >    /* If this is a reference to a 16-bit function with a stub, we need
> 
> Formatting nit:
> 
>       /* If the output section is the PLT section,
>          then the target is not microMIPS.  */
>       target_is_micromips_code_p = (htab->splt != sec
> 				    && ELF_ST_IS_MICROMIPS (h->root.other));
> 
> More importantly, the comment isn't any help.  When do we create
> statically-resolved relocations against .plt?

 PLT entries are currently hardcoded to standard MIPS code -- this is 
what the comment refers to.  This has nothing to do with relocations 
being static or dynamic.  The implication is if jumping to the PLT from 
microMIPS code then the usual JALX's restrictions apply (no sibling calls 
and no short instructions in the delay slot).

 I've fixed formatting, thanks -- there were so many of such errors I 
could have easily missed one or two.

> >    /* Calls from 16-bit code to 32-bit code and vice versa require the
> > -     mode change.  */
> > -  *cross_mode_jump_p = !info->relocatable
> > -		       && ((r_type == R_MIPS16_26 && !target_is_16_bit_code_p)
> > -			   || ((r_type == R_MIPS_26 || r_type == R_MIPS_JALR)
> > -			       && target_is_16_bit_code_p));
> > +     mode change.  This is not required for calls to undefined weak
> > +     symbols, which should never be executed at runtime.  */
> 
> But why do we need to go out of our way to check for them?  I'm sure
> there's a good reason, but the comment doesn't give much clue what it is.

 Undefined weak symbols are, well, undefined, so they have resolved to nil 
and are meant never to be jumped to, so we don't want to error out on them 
just because they do not have the ISA bit set and a JALX therefore 
required could not be used for some reason, like the invocation being a 
sibling call or because it would not satisfy the fixed delay slot 
dependency.

 So we decide never to make a cross-mode jump in this situation and leave 
the original jump instruction (i.e. JAL, JALS or JR) in place.  If the 
instruction is indeed reached, then 1 will be written to the PC rather 
than 0 that would "canonically" be required here, but the outcome will be 
the same (assuming the zeroth page is unmapped), i.e. a segfault will 
happen.

 Joseph, I reckon you were involved with this piece -- did I get all the 
context right here?

> > @@ -9223,6 +9499,16 @@ _bfd_mips_elf_relocate_section (bfd *out
> >  	case bfd_reloc_ok:
> >  	  break;
> >  
> > +	case bfd_reloc_outofrange:
> > +	  if (jal_reloc_p (howto->type))
> > +	    {
> > +	      msg = _("JALX to not a word-aligned address");
> > +	      info->callbacks->warning
> > +		(info, msg, name, input_bfd, input_section, rel->r_offset);
> > +	      return FALSE;
> > +	    }
> > +	  /* Fall through.  */
> > +
> >  	default:
> >  	  abort ();
> >  	  break;
> 
> I suppose that should be something like "JALX to a non-word-aligned address".

 Updated, thanks.

> > +  /* microMIPS local and global symbols have the least significant bit
> > +     set.  Because all values are either multiple of 2 or multiple of
> > +     4, compensating for this bit is as simple as setting it in
> > +     comparisons. Just to be sure, check anyway before proceeding. */
> > +  BFD_ASSERT (addr % 2 == 0);
> > +  BFD_ASSERT (toaddr % 2 == 0);
> > +  BFD_ASSERT (count % 2 == 0);
> 
> I'm suspicious about the toaddr assert.  You can create text sections
> with odd-valued sizes:
> 
> 	.section	.text.foo,"ax",@progbits
> 	.byte	1
> 
> and as discussed elsewhere, asserts are really to double-check
> conditions that we think must already hold.

 Will check that.  [FIXME]

> > +  addr |= 1;
> > +  toaddr |= 1;
> > +
> > +  /* Adjust the local symbols defined in this section.  */
> > +  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
> > +  isym = (Elf_Internal_Sym *) symtab_hdr->contents;
> > +  for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
> > +    {
> > +      if (isym->st_shndx == sec_shndx
> > +	  && isym->st_value > addr
> > +	  && isym->st_value < toaddr)
> > +	isym->st_value -= count;
> > +    }
> 
> Hmm, microMIPS symbols created in the proper, blessed way (by proper,
> blessed ways of defining MIPS16 labels in assembly) should be even in
> the input object, and IIRC, the linker keeps local symbols that way
> internally.  Only symbols entered into the hash table are odd.
> (c.f. mips_elf_calculate_relocation, where we have to add 1 to
> local symbols.)  So I would have expected the "|= 1"s to be applied
> after this block rather than before it.  Even then:
> 
> > +  /* Now adjust the global symbols defined in this section.  */
> > +  symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
> > +	      - symtab_hdr->sh_info);
> > +  sym_hashes = start_hashes = elf_sym_hashes (abfd);
> > +  end_hashes = sym_hashes + symcount;
> > +
> > +  for (; sym_hashes < end_hashes; sym_hashes++)
> > +    {
> > +      struct elf_link_hash_entry *sym_hash = *sym_hashes;
> > +
> > +      if ((sym_hash->root.type == bfd_link_hash_defined
> > +	   || sym_hash->root.type == bfd_link_hash_defweak)
> > +	  && sym_hash->root.u.def.section == sec
> > +	  && sym_hash->root.u.def.value > addr
> > +	  && sym_hash->root.u.def.value < toaddr)
> > +	sym_hash->root.u.def.value -= count;
> > +    }
> 
> ...if we're willing to extend the upper bound in this way, I wonder
> whether there's really any point having an upper bound at all.
> 
> Then again, why doesn't the standard range (used by most targets)
> include toaddr?  If you define an end marker:
> 
> end_of_section:
> 	# nothing after this
> 
> then wouldn't end_of_section == toaddr, and shouldn't it be included?

 Ilie, I'm told you were responsible for this piece of code -- would you 
please respond to these questions?

> I see some targets rightly adjust st_size too.  We should do
> the same here.

 Agreed.  [FIXME]

> > +static unsigned long
> > +find_match (unsigned long opcode, const struct opcode_descriptor insn[])
> > +{
> > +    unsigned long indx;
> > +
> > +    /* First opcode_table[] entry is ignored.  */
> > +    for (indx = 1; insn[indx].mask != 0; indx++)
> > +      if (MATCH (opcode, insn[indx]))
> > +	return indx;
> > +
> > +    return 0;
> > +}
> 
> But _why_ is the first entry ignored?

 There must be a reason, Ilie?

> > +/* Check if there *might* be a 16-bit branch or jump at OFFSET
> > +   with a fixed or variable length delay slot.  */
> > +
> > +static int
> > +relax_dslot_norel16 (bfd *abfd, bfd_byte *ptr)
> 
> There's no parameter called "offset".  How about:

 Yes, that's my typo; it should have been PTR, not OFFSET.

> /* If PTR is known to point to a 16-bit branch or jump, return the
>    minimum length of its delay slot, otherwise return 0.  */

 I'll keep the "*might*" because this is heuristics allowing possible 
false positives.  It may be the second half of another instruction and not 
a branch at all.  Otherwise OK, thanks.

> At least, that's what the code seems to do, since it returns 2 for
> things like:
> 
> > +  { /* "b(g|l)(e|t)z", "s,p",	*/ 0x40000000, 0xff200000 },
> 
> which as far as I can tell from the opcodes patch allows both 16-bit
> and 32-bit delay slots.  (IV-g doesn't seem to be public yet, so I can't
> check the spec.)  But from the way the function is used, it looks
> like 0 really means "no size constraints", so why doesn't the function
> return 0 for instructions like these?

 Only link variations of branches and jumps have a fixed-size delay slot 
-- that's because the link register is set to a fixed offset from the 
delay-slot instruction (either four as with JAL or two as with JALS).  Of 
all such jumps and branches only JALX does not have a JALXS counterpart 
(regrettably, as it would have made life of software much, much easier).

 I've explained the meaning of 0 below -- it's unsafe to return this value 
for a variable-size delay slot.

 BTW, I've just spotted and fixed a bug in relax_dslot_norel32 -- 
jal_insn_32_bd32 should be matched against instead of bz_insns_32 
obviously.  Hopefully you didn't get confused by that.

> Why are these routines checking for branches anyway?  We don't support
> branches without relocations when doing this kind of relaxation.
> I'd have expected only indirect jumps to be handled here.
> 
> Likewise relax_dslot_norel32.

 They are checked for because a LUI cannot be deleted entirely if it is in 
a delay slot as to do so would change the semantics of code being 
modified.  The implementation of relax_dslot_norel{16,32}() reflect this.  
These functions return the minimum delay slot size required, i.e. 0 if 
none, 2 if a fixed 16-bit or a variable-size delay slot is needed or 4 if 
a fixed 32-bit delay slot is needed.  In addition to this some branches 
may be replaced with a compact (no-delay-slot) variation making the 
deletion of the LUI possible (as in relax_dslot_rel()).

 If the deletion of the LUI is not possible after all, then it's replaced 
with a NOP according to the size of the delay slot.

 Good point about the relocations -- perhaps the instruction tables used 
for matching can be reduced to include jumps only (I'd keep absolute jumps 
here too as they may legitimately appear in input with no relocation 
associated and will normally cause no trouble even if moved around a bit, 
i.e. unless they cross to another 27-bit region).  I'll think about that.  
Original code I received didn't check for branch relocations here at all 
and relied purely on instruction decoding, sigh... :(  [FIXME]

> > +  /* We don't have to do anything for a relocatable link, if
> > +     this section does not have relocs, or if this is not a
> > +     code section.  */
> > +
> > +  if (link_info->relocatable
> > +      || (sec->flags & SEC_RELOC) == 0
> > +      || sec->reloc_count == 0
> > +      || (sec->flags & SEC_CODE) == 0)
> > +    return TRUE;
> 
> Should we also check whether the micromips bit is set in the ELF
> header flags?

 Yes, with my recent file ASE flag improvements this will definitely make 
sense, thanks for the hint.  [FIXME]

> > +	      nextopc = bfd_get_16 (abfd, contents + irel->r_offset + 4);
> > +	      /* B16  */
> > +	      if (MATCH (nextopc, b_insn_16))
> > +		break;
> > +	      /* JR16  */
> > +	      if (MATCH (nextopc, jr_insn_16) && reg != JR16_REG (nextopc))
> > +		break;
> > +	      /* BEQZ16, BNEZ16  */
> > +	      if (MATCH (nextopc, bz_insn_16) && reg != BZ16_REG (nextopc))
> > +		break;
> > +	      /* JALR16  */
> > +	      if (MATCH (nextopc, jalr_insn_16_bd32)
> > +		  && reg != JR16_REG (nextopc) && reg != RA)
> > +		break;
> > +	      continue;
> 
> I think this should be split out into a subfunction, like the relax_* ones.
> 
> /* PTR points to a 2-byte instruction.  Return true if it is a 16-bit
>    branch that does not use register REG.  */
> 
> static bfd_boolean
> is_16bit_branch_p (bfd *abfd, bfd_byte *ptr, unsigned int reg)
> 
> Likewise for the 4-byte case.

 Indeed, that should be possible.  I'll look into it.  [FIXME]

> > +	  /* Give up if not the same register used with both relocations.  */
> 
> "Give up unless the same register is used with both relocations."

 Fixed, thanks.

> > +	  /* Now adjust pcrval, subtracting the offset to the LO16 reloc,
> > +	     adding the size of the LUI instruction deleted and rounding
> > +	     up to take masking of the two LSBs into account.  */
> > +	  pcrval = ((pcrval - offset + 4 + 3) | 3) ^ 3;
> 
> Maybe its just me, but since pcrval was calculated much earlier,
> and hasn't been used since being set, I'd find it easier to understand
> if we simply calculate the pcrval for irel[1] directly:
> 
>       /* Calculate the pc-relative distance of the target from the LO16,
> 	 assuming that we can delete the 4-byte LUI.  */
>       pcrval = (symval
> 		- (sec->output_section->vma + sec->output_offset)
> 		- (irel[1].r_offset - 4));
> 
>       /* Round up to take the masking of the two LSBs into account.  */
>       pcrval = (prcval + 3) & -4;
> 
> What happens when we can't delete the LUI, because of its being in
> a branch delay slot?

 Hmm, that's a bug (although unlikely to trigger), thanks for spotting it.  
I've fixed it by making sure the distance fits into ADDIUPC both with and 
without the LUI deleted.  It's a minimal pessimisation only for a boundary 
case, so not worth any further improvement.

 Recalculating pcrval looks to me like a waste of CPU time here -- we've 
already calculated it for the other "if" clauses, so we just need to fetch 
it from the local frame now.

> > +	  int bdsize = -1;
> [...]
> > +	  /* See if there is a jump or a branch reloc preceding the
> > +	     LUI instruction immediately.  If so, then perform jump
> > +	     or branch relaxation.  */
> > +	  for (ibrrel = internal_relocs; ibrrel < irelend; ibrrel++)
> > +	    {
> > +	      offset = irel->r_offset - ibrrel->r_offset;
> > +	      if (offset != 2 && offset != 4)
> > +		continue;
> > +
> > +	      br_r_type = ELF32_R_TYPE (ibrrel->r_info);
> > +	      if (offset == 2
> > +		  && br_r_type != R_MICROMIPS_PC7_S1
> > +		  && br_r_type != R_MICROMIPS_PC10_S1
> > +		  && br_r_type != R_MICROMIPS_JALR)
> > +		continue;
> > +	      if (offset == 4
> > +		  && br_r_type != R_MICROMIPS_26_S1
> > +		  && br_r_type != R_MICROMIPS_PC16_S1
> > +		  && br_r_type != R_MICROMIPS_JALR)
> > +		continue;
> > +
> > +	      bdsize = relax_dslot_rel (abfd,
> > +					contents + ibrrel->r_offset, offset);
> > +	      break;
> > +	    }
> > +
> > +	  /* Otherwise see if the LUI instruction *might* be in a
> > +	     branch delay slot.  */
> > +	  if (bdsize == -1)
> > +	    {
> > +	      bfd_byte *ptr = contents + ibrrel->r_offset;
> > +
> > +	      /* Assume the 32-bit LUI instruction is in a fixed delay slot
> > +	         and cannot be optimised away.  */
> > +	      bdsize = 4;
> > +
> > +	      if (ibrrel->r_offset >= 2)
> > +		bdsize16 = relax_dslot_norel16 (abfd, ptr - 2);
> > +	      if (ibrrel->r_offset >= 4)
> > +		bdsize32 = relax_dslot_norel32 (abfd, ptr - 4);
> 
> I think the "ibrrel"s in the last block should be "irel"s instead.
> As best I can tell, "ibrrel" == "irelend" here.  Is this case
> covered by the testsuite?

 Correct and fixed, thanks.

 There are no testcases addressing any of this linker relaxation I would 
be aware of, sorry.

> I'm not sure whether I like the idea of making this function quadratic
> simply to decide whether the preceding instruction is a branch,
> but there's probably not much we can do about that.

 Hmm, we could do this in two passes over the reloc table (still O(n)) and 
first make a fast auxiliary data structure (e.g. a hash) to keep addresses 
of branch and jump relocations.  Given linker relaxation is off by default 
I'd vote for this as a future improvement.

 As a summary here's the patch resulting from the changes I made as noted 
above.  No regressions so far.  Regrettably owing to higher priority 
commitments I'll have to defer further work on issues marked with [FIXME] 
above until a later date.

  Maciej

binutils-umips-fix.diff
Index: binutils-fsf-trunk-quilt/bfd/elf64-mips.c
===================================================================
--- binutils-fsf-trunk-quilt.orig/bfd/elf64-mips.c	2010-12-13 15:20:06.000000000 +0000
+++ binutils-fsf-trunk-quilt/bfd/elf64-mips.c	2010-12-13 15:22:01.000000000 +0000
@@ -3002,6 +3002,7 @@ bfd_elf64_bfd_reloc_name_lookup (bfd *ab
        i++)
     if (mips16_elf64_howto_table_rela[i].name != NULL
 	&& strcasecmp (mips16_elf64_howto_table_rela[i].name, r_name) == 0)
+      return &mips16_elf64_howto_table_rela[i];
 
   for (i = 0;
        i < (sizeof (micromips_elf64_howto_table_rela)
Index: binutils-fsf-trunk-quilt/bfd/elfn32-mips.c
===================================================================
--- binutils-fsf-trunk-quilt.orig/bfd/elfn32-mips.c	2010-12-13 15:20:06.000000000 +0000
+++ binutils-fsf-trunk-quilt/bfd/elfn32-mips.c	2010-12-13 15:22:50.000000000 +0000
@@ -2820,6 +2820,7 @@ bfd_elf32_bfd_reloc_name_lookup (bfd *ab
        i++)
     if (elf_mips16_howto_table_rela[i].name != NULL
 	&& strcasecmp (elf_mips16_howto_table_rela[i].name, r_name) == 0)
+      return &elf_mips16_howto_table_rela[i];
 
   for (i = 0;
        i < (sizeof (elf_micromips_howto_table_rela)
Index: binutils-fsf-trunk-quilt/bfd/elfxx-mips.c
===================================================================
--- binutils-fsf-trunk-quilt.orig/bfd/elfxx-mips.c	2010-12-13 15:20:06.000000000 +0000
+++ binutils-fsf-trunk-quilt/bfd/elfxx-mips.c	2010-12-13 19:08:46.000000000 +0000
@@ -5161,8 +5161,8 @@ mips_elf_calculate_relocation (bfd *abfd
       target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (h->root.other);
       /* If the output section is the PLT section,
          then the target is not microMIPS.  */
-      target_is_micromips_code_p = (htab->splt != sec)
-				    && ELF_ST_IS_MICROMIPS (h->root.other);
+      target_is_micromips_code_p = ((htab->splt != sec)
+				    && ELF_ST_IS_MICROMIPS (h->root.other));
     }
 
   /* If this is a reference to a 16-bit function with a stub, we need
@@ -9502,7 +9502,7 @@ _bfd_mips_elf_relocate_section (bfd *out
 	case bfd_reloc_outofrange:
 	  if (jal_reloc_p (howto->type))
 	    {
-	      msg = _("JALX to not a word-aligned address");
+	      msg = _("JALX to a non-word-aligned address");
 	      info->callbacks->warning
 		(info, msg, name, input_bfd, input_section, rel->r_offset);
 	      return FALSE;
@@ -12188,8 +12188,10 @@ find_match (unsigned long opcode, const 
 
 /* Delay slot size and relaxation support.  */
 
-/* Check if there *might* be a 16-bit branch or jump at OFFSET
-   with a fixed or variable length delay slot.  */
+/* If PTR points to what *might* be a 16-bit branch or jump, then
+   return the minimum length of its delay slot, otherwise return 0.
+   Non-zero results are not definitive as we might be checking against
+   the second half of another instruction.  */
 
 static int
 relax_dslot_norel16 (bfd *abfd, bfd_byte *ptr)
@@ -12212,8 +12214,10 @@ relax_dslot_norel16 (bfd *abfd, bfd_byte
   return bdsize;
 }
 
-/* Check if there *might* be a 32-bit branch or jump at OFFSET
-   with a fixed or variable length delay slot.  */
+/* If PTR points to what *might* be a 32-bit branch or jump, then
+   return the minimum length of its delay slot, otherwise return 0.
+   Non-zero results are not definitive as we might be checking against
+   the second half of another instruction.  */
 
 static int
 relax_dslot_norel32 (bfd *abfd, bfd_byte *ptr)
@@ -12223,7 +12227,7 @@ relax_dslot_norel32 (bfd *abfd, bfd_byte
 
   opcode = (bfd_get_16 (abfd, ptr) << 16) | bfd_get_16 (abfd, ptr + 2);
   if (find_match (opcode, call_insns_32_bd32) != 0
-      || find_match (opcode, bz_insns_32) != 0
+      || MATCH (opcode, jal_insn_32_bd32) != 0
       || MATCH (opcode, jalx_insn_32_bd32) != 0)
     /* 32-bit branch/jump with a 32-bit delay slot.  */
     bdsize = 4;
@@ -12550,14 +12554,13 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
 	  nextopc  = bfd_get_16 (abfd, contents + irel[1].r_offset    ) << 16;
 	  nextopc |= bfd_get_16 (abfd, contents + irel[1].r_offset + 2);
 
-	  /* Give up if not the same register used with both relocations.  */
+	  /* Give up unless the same register used with both relocations.  */
 	  if (OP32_SREG (nextopc) != reg)
 	    continue;
 
-	  /* Now adjust pcrval, subtracting the offset to the LO16 reloc,
-	     adding the size of the LUI instruction deleted and rounding
-	     up to take masking of the two LSBs into account.  */
-	  pcrval = ((pcrval - offset + 4 + 3) | 3) ^ 3;
+	  /* Now adjust pcrval, subtracting the offset to the LO16 reloc
+	     and rounding up to take masking of the two LSBs into account.  */
+	  pcrval = ((pcrval - offset + 3) | 3) ^ 3;
 
 	  /* R_MICROMIPS_LO16 relaxation to R_MICROMIPS_HI0_LO16.  */
 	  if (IS_BITSIZE (symval, 16))
@@ -12573,9 +12576,14 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
 			  contents + irel[1].r_offset);
 	    }
 
-	  /* R_MICROMIPS_LO16 / ADDIU relaxation to R_MICROMIPS_PC23_S2.  */
+	  /* R_MICROMIPS_LO16 / ADDIU relaxation to R_MICROMIPS_PC23_S2.
+	     As we don't know at this stage if we'll be able to delete
+	     the LUI in the end, we check both the original PC-relative
+	     distance and one with 4 added to take LUI deletion into
+	     account.  */
 	  else if (symval % 4 == 0
 		   && IS_BITSIZE (pcrval, 25)
+		   && IS_BITSIZE (pcrval + 4, 25)
 		   && MATCH (nextopc, addiu_insn)
 		   && OP32_TREG (nextopc) == OP32_SREG (nextopc)
 		   && OP16_VALID_REG (OP32_TREG (nextopc)))
@@ -12627,15 +12635,15 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
 	     branch delay slot.  */
 	  if (bdsize == -1)
 	    {
-	      bfd_byte *ptr = contents + ibrrel->r_offset;
+	      bfd_byte *ptr = contents + irel->r_offset;
 
 	      /* Assume the 32-bit LUI instruction is in a fixed delay slot
 	         and cannot be optimised away.  */
 	      bdsize = 4;
 
-	      if (ibrrel->r_offset >= 2)
+	      if (irel->r_offset >= 2)
 		bdsize16 = relax_dslot_norel16 (abfd, ptr - 2);
-	      if (ibrrel->r_offset >= 4)
+	      if (irel->r_offset >= 4)
 		bdsize32 = relax_dslot_norel32 (abfd, ptr - 4);
 
 	      if (bdsize16 == -1 && bdsize32 == -1)

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2010-12-14 13:30           ` Maciej W. Rozycki
@ 2010-12-14 14:51             ` Richard Sandiford
  2010-12-16 11:54               ` Maciej W. Rozycki
  2010-12-14 17:56             ` Joseph S. Myers
  2010-12-17 20:56             ` Fu, Chao-Ying
  2 siblings, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2010-12-14 14:51 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: Ilie Garbacea, Joseph Myers, binutils, Chao-ying Fu, Rich Fuhler,
	David Lau, Kevin Mills, Catherine Moore, Nathan Sidwell,
	Nathan Froyd

"Maciej W. Rozycki" <macro@codesourcery.com> writes:
>> I think we're getting close, so could you post any updates as patches
>> relative to this one, rather than reposting the whole thing?
>
>  Yes, I think it will make it easier for us both to keep track of what has 
> been addressed and what not.  I have no technical problem with including 
> further changes in a separate patch.

Thanks.  For avoidance of doubt, please make any updates (with the FIXMEs
fixed, for instance), relative to the original.

>> Formatting nit:
>> 
>>       /* If the output section is the PLT section,
>>          then the target is not microMIPS.  */
>>       target_is_micromips_code_p = (htab->splt != sec
>> 				    && ELF_ST_IS_MICROMIPS (h->root.other));
>> 
>> More importantly, the comment isn't any help.  When do we create
>> statically-resolved relocations against .plt?

Oops, ignore this, I was thinking "sec" was the section that contained
the relocation.

>> >    /* Calls from 16-bit code to 32-bit code and vice versa require the
>> > -     mode change.  */
>> > -  *cross_mode_jump_p = !info->relocatable
>> > -		       && ((r_type == R_MIPS16_26 && !target_is_16_bit_code_p)
>> > -			   || ((r_type == R_MIPS_26 || r_type == R_MIPS_JALR)
>> > -			       && target_is_16_bit_code_p));
>> > +     mode change.  This is not required for calls to undefined weak
>> > +     symbols, which should never be executed at runtime.  */
>> 
>> But why do we need to go out of our way to check for them?  I'm sure
>> there's a good reason, but the comment doesn't give much clue what it is.
>
>  Undefined weak symbols are, well, undefined, so they have resolved to nil 
> and are meant never to be jumped to, so we don't want to error out on them 
> just because they do not have the ISA bit set and a JALX therefore 
> required could not be used for some reason, like the invocation being a 
> sibling call or because it would not satisfy the fixed delay slot 
> dependency.

OK, makes sense.  Please update the comment to something like:

  /* Calls from 16-bit code to 32-bit code and vice versa require the
     mode change.  However, we can ignore calls to undefined weak symbols,
     which should never be executed at runtime.  This exception is important
     because the assembly writer may have "known" that any definition of the
     symbol would be 16-bit code, and that direct jumps were therefore
     acceptable.  */

>> At least, that's what the code seems to do, since it returns 2 for
>> things like:
>> 
>> > +  { /* "b(g|l)(e|t)z", "s,p",	*/ 0x40000000, 0xff200000 },
>> 
>> which as far as I can tell from the opcodes patch allows both 16-bit
>> and 32-bit delay slots.  (IV-g doesn't seem to be public yet, so I can't
>> check the spec.)  But from the way the function is used, it looks
>> like 0 really means "no size constraints", so why doesn't the function
>> return 0 for instructions like these?
>
>  Only link variations of branches and jumps have a fixed-size delay slot 
> -- that's because the link register is set to a fixed offset from the 
> delay-slot instruction (either four as with JAL or two as with JALS).  Of 
> all such jumps and branches only JALX does not have a JALXS counterpart 
> (regrettably, as it would have made life of software much, much easier).
>
>  I've explained the meaning of 0 below -- it's unsafe to return this value 
> for a variable-size delay slot.

Hmm, I was thinking of the case where there was no branch _after_
the LUI, and where the instruction after the LUI could then become
the delay slot for a variable-length branch before the (deleted) LUI.
But yeah, I can see that 0 isn't correct if there is a branch immediately
after the LUI.

>> I'm not sure whether I like the idea of making this function quadratic
>> simply to decide whether the preceding instruction is a branch,
>> but there's probably not much we can do about that.
>
>  Hmm, we could do this in two passes over the reloc table (still O(n)) and 
> first make a fast auxiliary data structure (e.g. a hash) to keep addresses 
> of branch and jump relocations.  Given linker relaxation is off by default 
> I'd vote for this as a future improvement.

Yeah, I'd wondered about that, but then we'd need to measure whether that
made things better or not.  I'm OK with leaving it.

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2010-12-14 13:30           ` Maciej W. Rozycki
  2010-12-14 14:51             ` Richard Sandiford
@ 2010-12-14 17:56             ` Joseph S. Myers
  2010-12-16 15:28               ` Maciej W. Rozycki
  2010-12-17 20:56             ` Fu, Chao-Ying
  2 siblings, 1 reply; 41+ messages in thread
From: Joseph S. Myers @ 2010-12-14 17:56 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: Richard Sandiford, Ilie Garbacea, binutils, Chao-ying Fu,
	Rich Fuhler, David Lau, Kevin Mills, Catherine Moore,
	Nathan Sidwell, Nathan Froyd

On Tue, 14 Dec 2010, Maciej W. Rozycki wrote:

> > >    /* Calls from 16-bit code to 32-bit code and vice versa require the
> > > -     mode change.  */
> > > -  *cross_mode_jump_p = !info->relocatable
> > > -		       && ((r_type == R_MIPS16_26 && !target_is_16_bit_code_p)
> > > -			   || ((r_type == R_MIPS_26 || r_type == R_MIPS_JALR)
> > > -			       && target_is_16_bit_code_p));
> > > +     mode change.  This is not required for calls to undefined weak
> > > +     symbols, which should never be executed at runtime.  */
> > 
> > But why do we need to go out of our way to check for them?  I'm sure
> > there's a good reason, but the comment doesn't give much clue what it is.
> 
>  Undefined weak symbols are, well, undefined, so they have resolved to nil 
> and are meant never to be jumped to, so we don't want to error out on them 
> just because they do not have the ISA bit set and a JALX therefore 
> required could not be used for some reason, like the invocation being a 
> sibling call or because it would not satisfy the fixed delay slot 
> dependency.
> 
>  So we decide never to make a cross-mode jump in this situation and leave 
> the original jump instruction (i.e. JAL, JALS or JR) in place.  If the 
> instruction is indeed reached, then 1 will be written to the PC rather 
> than 0 that would "canonically" be required here, but the outcome will be 
> the same (assuming the zeroth page is unmapped), i.e. a segfault will 
> happen.
> 
>  Joseph, I reckon you were involved with this piece -- did I get all the 
> context right here?

Yes.  A call to an undefined weak function is equally valid at compile and 
link time and invalid at execution time if executed whether or not the 
code is compiled in such a way as to support cross-mode jumps.  Such a 
call is a call to an undefined function, never a call to an other-mode 
function, and so the linker should never give errors for cases such as 
JALS where it cannot convert to a cross-mode jump.  The original observed 
problem case was statically linking sln with a call to 
__nptl_deallocate_tsd that never gets executed in single-threaded 
programs.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2010-12-14 14:51             ` Richard Sandiford
@ 2010-12-16 11:54               ` Maciej W. Rozycki
  2010-12-18 10:26                 ` Richard Sandiford
  0 siblings, 1 reply; 41+ messages in thread
From: Maciej W. Rozycki @ 2010-12-16 11:54 UTC (permalink / raw)
  To: Richard Sandiford
  Cc: Ilie Garbacea, Joseph Myers, binutils, Chao-ying Fu, Rich Fuhler,
	David Lau, Kevin Mills, Catherine Moore, Nathan Sidwell,
	Nathan Froyd

On Tue, 14 Dec 2010, Richard Sandiford wrote:

> >  Yes, I think it will make it easier for us both to keep track of what has 
> > been addressed and what not.  I have no technical problem with including 
> > further changes in a separate patch.
> 
> Thanks.  For avoidance of doubt, please make any updates (with the FIXMEs
> fixed, for instance), relative to the original.

 Yes, this is what I assumed too.

> >  Undefined weak symbols are, well, undefined, so they have resolved to nil 
> > and are meant never to be jumped to, so we don't want to error out on them 
> > just because they do not have the ISA bit set and a JALX therefore 
> > required could not be used for some reason, like the invocation being a 
> > sibling call or because it would not satisfy the fixed delay slot 
> > dependency.
> 
> OK, makes sense.  Please update the comment to something like:
> 
>   /* Calls from 16-bit code to 32-bit code and vice versa require the
>      mode change.  However, we can ignore calls to undefined weak symbols,
>      which should never be executed at runtime.  This exception is important
>      because the assembly writer may have "known" that any definition of the
>      symbol would be 16-bit code, and that direct jumps were therefore
>      acceptable.  */

 Done, thanks.

> >  Only link variations of branches and jumps have a fixed-size delay slot 
> > -- that's because the link register is set to a fixed offset from the 
> > delay-slot instruction (either four as with JAL or two as with JALS).  Of 
> > all such jumps and branches only JALX does not have a JALXS counterpart 
> > (regrettably, as it would have made life of software much, much easier).
> >
> >  I've explained the meaning of 0 below -- it's unsafe to return this value 
> > for a variable-size delay slot.
> 
> Hmm, I was thinking of the case where there was no branch _after_
> the LUI, and where the instruction after the LUI could then become
> the delay slot for a variable-length branch before the (deleted) LUI.
> But yeah, I can see that 0 isn't correct if there is a branch immediately
> after the LUI.

 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).

 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]

> >  Hmm, we could do this in two passes over the reloc table (still O(n)) and 
> > first make a fast auxiliary data structure (e.g. a hash) to keep addresses 
> > of branch and jump relocations.  Given linker relaxation is off by default 
> > I'd vote for this as a future improvement.
> 
> Yeah, I'd wondered about that, but then we'd need to measure whether that
> made things better or not.  I'm OK with leaving it.

 The breaking point may be high -- we'd have to benchmark a program with a 
suitably high number of relocations to decide whether to go for that at 
all.  And then perhaps only enable the optimisation selectively at the run 
time, based on the size of the reloc table and the expected density of 
HI16/LO16 reloc pairs within.  And even then, in a typical compilation 
there are relatively few final links, so shaving a couple of seconds off a 
compilation that otherwise takes half a dozen of minutes may be missing 
the point.

  Maciej

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2010-12-14 17:56             ` Joseph S. Myers
@ 2010-12-16 15:28               ` Maciej W. Rozycki
  0 siblings, 0 replies; 41+ messages in thread
From: Maciej W. Rozycki @ 2010-12-16 15:28 UTC (permalink / raw)
  To: Joseph S. Myers
  Cc: Richard Sandiford, Ilie Garbacea, binutils, Chao-ying Fu,
	Rich Fuhler, David Lau, Kevin Mills, Catherine Moore,
	Nathan Sidwell, Nathan Froyd

On Tue, 14 Dec 2010, Joseph S. Myers wrote:

> >  Joseph, I reckon you were involved with this piece -- did I get all the 
> > context right here?
> 
> Yes.  A call to an undefined weak function is equally valid at compile and 
> link time and invalid at execution time if executed whether or not the 
> code is compiled in such a way as to support cross-mode jumps.  Such a 
> call is a call to an undefined function, never a call to an other-mode 
> function, and so the linker should never give errors for cases such as 
> JALS where it cannot convert to a cross-mode jump.  The original observed 
> problem case was statically linking sln with a call to 
> __nptl_deallocate_tsd that never gets executed in single-threaded 
> programs.

 OK, thanks for confirmation.

  Maciej

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: [PATCH] MIPS: microMIPS ASE support
  2010-12-14 13:30           ` Maciej W. Rozycki
  2010-12-14 14:51             ` Richard Sandiford
  2010-12-14 17:56             ` Joseph S. Myers
@ 2010-12-17 20:56             ` Fu, Chao-Ying
  2010-12-18 10:09               ` Richard Sandiford
  2 siblings, 1 reply; 41+ messages in thread
From: Fu, Chao-Ying @ 2010-12-17 20:56 UTC (permalink / raw)
  To: Maciej W. Rozycki, Richard Sandiford, Garbacea, Ilie, Joseph Myers
  Cc: binutils, Fuhler, Rich, Lau, David, Mills, Kevin,
	Catherine Moore, Nathan Sidwell, Nathan Froyd

> Hello,
> 
>  Ilie, Joseph: I have some questions for you below, please respond.

  Ilie is on vacations.

> > > +  /* Now adjust the global symbols defined in this section.  */
> > > +  symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
> > > +	      - symtab_hdr->sh_info);
> > > +  sym_hashes = start_hashes = elf_sym_hashes (abfd);
> > > +  end_hashes = sym_hashes + symcount;
> > > +
> > > +  for (; sym_hashes < end_hashes; sym_hashes++)
> > > +    {
> > > +      struct elf_link_hash_entry *sym_hash = *sym_hashes;
> > > +
> > > +      if ((sym_hash->root.type == bfd_link_hash_defined
> > > +	   || sym_hash->root.type == bfd_link_hash_defweak)
> > > +	  && sym_hash->root.u.def.section == sec
> > > +	  && sym_hash->root.u.def.value > addr
> > > +	  && sym_hash->root.u.def.value < toaddr)
> > > +	sym_hash->root.u.def.value -= count;
> > > +    }
> > 
> > ...if we're willing to extend the upper bound in this way, I wonder
> > whether there's really any point having an upper bound at all.
> > 
> > Then again, why doesn't the standard range (used by most targets)
> > include toaddr?  If you define an end marker:
> > 
> > end_of_section:
> > 	# nothing after this
> > 
> > then wouldn't end_of_section == toaddr, and shouldn't it be 
> included?
> 
>  Ilie, I'm told you were responsible for this piece of code 
> -- would you 
> please respond to these questions?

  I think we should include "end_of_section == toaddr".
Ex:
	  && sym_hash->root.u.def.value <= toaddr)

> > > +static unsigned long
> > > +find_match (unsigned long opcode, const struct 
> opcode_descriptor insn[])
> > > +{
> > > +    unsigned long indx;
> > > +
> > > +    /* First opcode_table[] entry is ignored.  */
> > > +    for (indx = 1; insn[indx].mask != 0; indx++)
> > > +      if (MATCH (opcode, insn[indx]))
> > > +	return indx;
> > > +
> > > +    return 0;
> > > +}
> > 
> > But _why_ is the first entry ignored?
> 
>  There must be a reason, Ilie?

  I guess Ilie tries to avoid passing a single-entry table into find_match().
But if we do pass a single-entry table into find_match(), 
find_match() may not find the end marker and it will be wrong anyway.
Maybe we just delete all the { 1, 1 } entry in opcode_descriptor [] tables, and
find_match() doesn't ignore the first entry.
And we make sure that each table has end marker at the end.
Thanks!

Regards,
Chao-ying

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2010-12-17 20:56             ` Fu, Chao-Ying
@ 2010-12-18 10:09               ` Richard Sandiford
  0 siblings, 0 replies; 41+ messages in thread
From: Richard Sandiford @ 2010-12-18 10:09 UTC (permalink / raw)
  To: Fu, Chao-Ying
  Cc: Maciej W. Rozycki, Garbacea, Ilie, Joseph Myers, binutils,
	Fuhler, Rich, Lau, David, Mills, Kevin, Catherine Moore,
	Nathan Sidwell, Nathan Froyd

"Fu, Chao-Ying" <fu@mips.com> writes:
>> > > +  /* Now adjust the global symbols defined in this section.  */
>> > > +  symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
>> > > +	      - symtab_hdr->sh_info);
>> > > +  sym_hashes = start_hashes = elf_sym_hashes (abfd);
>> > > +  end_hashes = sym_hashes + symcount;
>> > > +
>> > > +  for (; sym_hashes < end_hashes; sym_hashes++)
>> > > +    {
>> > > +      struct elf_link_hash_entry *sym_hash = *sym_hashes;
>> > > +
>> > > +      if ((sym_hash->root.type == bfd_link_hash_defined
>> > > +	   || sym_hash->root.type == bfd_link_hash_defweak)
>> > > +	  && sym_hash->root.u.def.section == sec
>> > > +	  && sym_hash->root.u.def.value > addr
>> > > +	  && sym_hash->root.u.def.value < toaddr)
>> > > +	sym_hash->root.u.def.value -= count;
>> > > +    }
>> > 
>> > ...if we're willing to extend the upper bound in this way, I wonder
>> > whether there's really any point having an upper bound at all.
>> > 
>> > Then again, why doesn't the standard range (used by most targets)
>> > include toaddr?  If you define an end marker:
>> > 
>> > end_of_section:
>> > 	# nothing after this
>> > 
>> > then wouldn't end_of_section == toaddr, and shouldn't it be 
>> included?
>> 
>>  Ilie, I'm told you were responsible for this piece of code 
>> -- would you 
>> please respond to these questions?
>
>   I think we should include "end_of_section == toaddr".
> Ex:
> 	  && sym_hash->root.u.def.value <= toaddr)

I agree that's probably the best thing, although I admit the "Then again,"
question was really more general musing than a question about this patch.

To be more specific, the thing that worried me about this code was that:

- if the section ends with a microMIPS instruction and an end marker,
  the "value < toaddr" won't include the end marker.  (The end marker
  would be odd.)

- if the section ends with a normal MIPS instruction and an end marker,
  the "value < toaddr" _would_ include the end marker.  (The end marker
  would be even.)

That's the key difference between "toaddr |= 1 ... value < toaddr"
and "value &= -2 .... value < toaddr".  I think the latter is more
consistent.

I suggest removing:

+  BFD_ASSERT (toaddr % 2 == 0);
+  addr |= 1;
+  toaddr |= 1;

and instead masking the low bit off the u.def.value.  (Keep the other
two asserts though.  I certainly found them useful when reviewing
the code.)

>> > > +static unsigned long
>> > > +find_match (unsigned long opcode, const struct 
>> opcode_descriptor insn[])
>> > > +{
>> > > +    unsigned long indx;
>> > > +
>> > > +    /* First opcode_table[] entry is ignored.  */
>> > > +    for (indx = 1; insn[indx].mask != 0; indx++)
>> > > +      if (MATCH (opcode, insn[indx]))
>> > > +	return indx;
>> > > +
>> > > +    return 0;
>> > > +}
>> > 
>> > But _why_ is the first entry ignored?
>> 
>>  There must be a reason, Ilie?
>
>   I guess Ilie tries to avoid passing a single-entry table into find_match().
> But if we do pass a single-entry table into find_match(), 
> find_match() may not find the end marker and it will be wrong anyway.
> Maybe we just delete all the { 1, 1 } entry in opcode_descriptor [] tables, and
> find_match() doesn't ignore the first entry.
> And we make sure that each table has end marker at the end.

Yeah, I think that'd be better, thanks.

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2010-12-16 11:54               ` Maciej W. Rozycki
@ 2010-12-18 10:26                 ` Richard Sandiford
  0 siblings, 0 replies; 41+ messages in thread
From: Richard Sandiford @ 2010-12-18 10:26 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: Ilie Garbacea, Joseph Myers, binutils, Chao-ying Fu, Rich Fuhler,
	David Lau, Kevin Mills, Catherine Moore, Nathan Sidwell,
	Nathan Froyd

"Maciej W. Rozycki" <macro@codesourcery.com> writes:
>> >  Only link variations of branches and jumps have a fixed-size delay slot 
>> > -- that's because the link register is set to a fixed offset from the 
>> > delay-slot instruction (either four as with JAL or two as with JALS).  Of 
>> > all such jumps and branches only JALX does not have a JALXS counterpart 
>> > (regrettably, as it would have made life of software much, much easier).
>> >
>> >  I've explained the meaning of 0 below -- it's unsafe to return this value 
>> > for a variable-size delay slot.
>> 
>> Hmm, I was thinking of the case where there was no branch _after_
>> the LUI, and where the instruction after the LUI could then become
>> the delay slot for a variable-length branch before the (deleted) LUI.
>> But yeah, I can see that 0 isn't correct if there is a branch immediately
>> after the LUI.
>
>  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 obviously had a bit of a mental block when reviewing this delay slot
stuff, sorry.

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2010-12-07  1:13       ` Maciej W. Rozycki
  2010-12-12 14:59         ` Richard Sandiford
@ 2011-01-02 11:36         ` Richard Sandiford
  2011-02-21 15:35           ` Maciej W. Rozycki
  1 sibling, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2011-01-02 11:36 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
	Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers,
	Nathan Froyd

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.

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.

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.

> @@ -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.

> +  /* 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.

> @@ -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.

> +#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.

If the bit really is needed, let's call the parameter "user_16bit"
rather than "is_16bit", to match the use.

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.

> +  /* 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;

> +  /* 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.

> @@ -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.

> +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.

If we do need TC_LABEL_IS_LOCAL for some reason, it should be documented
in internals.texi.

> @@ -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

> +      if (mips_relax.sequence)
> +	abort ();

gas_assert (!mips_relax.sequence);

> +	      /* 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).

> +  /* 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)

> +  hash = !mips_opts.micromips ? op_hash : micromips_op_hash;

  hash = mips_opts.micromips ? micromips_op_hash : op_hash;

> @@ -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.

> +	  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));

>  	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;
> @@ -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.

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.

> +  /* 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.  */

> +   if CALL is set.  In the reorder mode the delay slot would be filled
> +   with a nop anyway, so code produced is simply:
> +	BR	<args>, <sym>

Add an explicit nop, since the code does.

> +/* Emit a coprocessor branch macro specified by TYPE, using CC as
> +   the condition code tested.  EP specifies the branch target.  */

"branch-likely macro".

> +/* 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.

> +      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)

> -	  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.

> +	  /* 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".  */

> +  hash = !mips_opts.micromips ? op_hash : micromips_op_hash;
> +  past = (!mips_opts.micromips ? &mips_opcodes[NUMOPCODES]
> +	  : &micromips_opcodes[bfd_micromips_num_opcodes]);

  if (mips_opts.micromips)
    {
      hash = micromips_op_hash;
      past = &micromips_opcodes[bfd_micromips_num_opcodes];
    }
  else
    {
      hash = op_hash;
      past = &mips_opcodes[NUMOPCODES];
    }

> @@ -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.

> +		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.

> +	    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?

> +		      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);

> +		  if (!ok)
> +		    {
> +		      switch (*args++)

I realise you've copied this from elsewhere, but why "++"?
The "for" loop increments "args", doesn't it?

> +		      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.

> +		    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.

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 = 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.

> +		  /* 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.

> +		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.

> +		    /* 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.

> +			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, &regno);
> +			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;")?

> +			    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.

> +		      }
> +		    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.

> +	    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.

> +		/* 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:

> +		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.

> +	  /* 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?

> +    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);

> +      /* 00000000 <test>:
> +            0:       405e 0006       bgez    $30,10 <test+0x10>
> +            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 <test2>:
> +            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.

> +  /* 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.

> +	  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.)

Some of the comments below are also about code that has been
cut-&-pasted from the non-microMIPS branch relaxation.  I haven't
flagged them up as such because it's irrelevant.

> +      buf = (bfd_byte *)fragp->fr_literal + fragp->fr_fix;

Missing space before "fragp->fr_literal".  A few other occurences.

> +	  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.)

> +	  /* 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".

> +	uncond_micromips:
> +	  if (mips_pic == NO_PIC)
> +	    {
> +	      /* j or jal.  */

"j(al) <sym>  R_MICROMIPS_26_S1"

to match the style of the other comments (and to give a bit more info).

> +	      /* lw/ld $at, <sym>($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, <sym>  R_MIPS_LO16 */
> +	      insn = 0x30210000;

Likewise "daddiu".

> +      gas_assert (buf == (bfd_byte *)fragp->fr_literal
> +			 + fragp->fr_fix + fragp->fr_var);

The "+" isn't indented far enough.

> 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

>        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.

>  /* 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.  */

> +/* 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)".

> +/* 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.

> +/* 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.

> +/* MIPS placeholders.  */

/* Placeholders for fields that only exist in the traditional 32-bit
   instruction encoding; see the comment above for details.  */

> +   "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.

> -      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.

> +			else
> +			    iprintf (is, "UNKNOWN");

Excess indentation.

> +		     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.

> +/* 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".

> +  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.

What problem is the ld-lib.exp change fixing?

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2011-01-02 11:36         ` Richard Sandiford
@ 2011-02-21 15:35           ` Maciej W. Rozycki
  2011-02-22 20:12             ` Fu, Chao-Ying
                               ` (3 more replies)
  0 siblings, 4 replies; 41+ messages in thread
From: Maciej W. Rozycki @ 2011-02-21 15:35 UTC (permalink / raw)
  To: Richard Sandiford
  Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
	Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers,
	Nathan Froyd

[-- Attachment #1: Type: TEXT/PLAIN, Size: 95960 bytes --]

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" <macro@codesourcery.com> 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	<args>, <sym>
> 
> 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]
> > +	  : &micromips_opcodes[bfd_micromips_num_opcodes]);
> 
>   if (mips_opts.micromips)
>     {
>       hash = micromips_op_hash;
>       past = &micromips_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, &regno);
> > +			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 <test>:
> > +            0:       405e 0006       bgez    $30,10 <test+0x10>
> > +            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 <test2>:
> > +            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) <sym>  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, <sym>($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, <sym>  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 <stdint.h> 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 <opcode/mips.h> 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  <fu@mips.com>
            Ilie Garbacea  <ilie@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>
            Joseph Myers  <joseph@codesourcery.com>
            Catherine Moore  <clm@codesourcery.com>

	* 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  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* readelf.c (get_machine_flags): Handle microMIPS ASE.
	(get_mips_symbol_other): Likewise.

gas/
2011-02-21  Maciej W. Rozycki  <macro@codesourcery.com>
            Chao-ying Fu  <fu@mips.com>

	* 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  <macro@codesourcery.com>
            Chao-ying Fu  <fu@mips.com>

	* 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  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* 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  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* 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  <clm@codesourcery.com>
            Chao-ying Fu  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* 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  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* 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.

[-- Attachment #2: Type: APPLICATION/octet-stream, Size: 31674 bytes --]

[-- Attachment #3: Type: APPLICATION/octet-stream, Size: 6994 bytes --]

[-- Attachment #4: Type: APPLICATION/octet-stream, Size: 4086 bytes --]

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: [PATCH] MIPS: microMIPS ASE support
  2011-02-21 15:35           ` Maciej W. Rozycki
@ 2011-02-22 20:12             ` Fu, Chao-Ying
  2011-02-22 20:19             ` Fu, Chao-Ying
                               ` (2 subsequent siblings)
  3 siblings, 0 replies; 41+ messages in thread
From: Fu, Chao-Ying @ 2011-02-22 20:12 UTC (permalink / raw)
  To: Maciej W. Rozycki, Richard Sandiford
  Cc: binutils, Fuhler, Rich, Lau, David, Mills, Kevin, Garbacea, Ilie,
	Catherine Moore, Nathan Sidwell, Joseph Myers, Nathan Froyd

Maciej W. Rozycki wrote:
> 
>  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.
> 
> > > +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?

  I don't recall that I wrote this code.  So, you may remove it.

> 
> > > +  /* 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?

  I added this code to avoid GAS errors when compiling Linux kernel for microMIPS.
Ex:
  mipsisa32r2-linux-gnu-gcc -Wp,-MD,kernel/.rtmutex.o.d  -nostdinc -isystem /hom
e/fu/dev/binutils3/build-linux-20090506/tools/lib/gcc/mipsisa32r2-linux-gnu/4.4.
0/include -D__KERNEL__ -Iinclude  -include include/linux/autoconf.h -Wall -Wunde
f -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -O2  -mabi
=32 -G 0 -mno-abicalls -fno-pic -pipe -ffreestanding -EL -UMIPSEB -U_MIPSEB -U__
MIPSEB -U__MIPSEB__ -UMIPSEL -U_MIPSEL -U__MIPSEL -U__MIPSEL__ -DMIPSEL -D_MIPSE
L -D__MIPSEL -D__MIPSEL__ -march=mips32r2 -Wa,-mips32r2 -Wa,--trap -Iinclude/asm
-mips/mach-sim -Iinclude/asm-mips/mach-generic -mmicromips -fomit-frame-pointer
-g  -fno-stack-protector -Wdeclaration-after-statement -Wno-pointer-sign -mmicro
mips    -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(rtmutex)"  -D"KBUILD_
MODNAME=KBUILD_STR(rtmutex)" -c -o kernel/.tmp_rtmutex.o kernel/rtmutex.c
{standard input}: Assembler messages:
{standard input}:3030: Error: relocation overflow
{standard input}:3125: Error: relocation overflow
{standard input}:3213: Error: relocation overflow
{standard input}:3408: Error: relocation overflow
make[1]: *** [kernel/rtmutex.o] Error 1

  A simple case is as follows.
<597> # cat 2.s
                .set    push
        .set    noat
        .set    mips3
        .space  1<<10
1:      ll      $6, 0($2)                       # __cmpxchg_u32
        bne     $6, $0, 2f
        .set    mips0
        move    $1, $3
        .set    mips3
        sc      $1, 0($2)
        beqz    $1, 3f
2:
        .subsection 2
3:      b       1b
        .previous
        .set    pop

  I kind of forgot my debug process to come out with the solution.
Maybe if we use the section as the target, R_MICROMIPS_PC7_S1 will lead to
incorrect checking for overflow.
Ex: (write.c)
static void
adjust_reloc_syms (bfd *abfd ATTRIBUTE_UNUSED,
                   asection *sec,
                   void *xxx ATTRIBUTE_UNUSED)
{
  segment_info_type *seginfo = seg_info (sec);
  fixS *fixp;
...
        /* We refetch the segment when calling section_symbol, rather
           than using symsec, because S_GET_VALUE may wind up changing
           the section when it calls resolve_symbol_value.  */
        fixp->fx_offset += S_GET_VALUE (sym); <----- THIS WILL BE TOO BIG, if we use the section.
        fixp->fx_addsy = section_symbol (S_GET_SEGMENT (sym));
#ifdef DEBUG5
        fprintf (stderr, "\nadjusted fixup:\n");
        print_fixup (fixp);
#endif
      }

  dump_section_relocs (abfd, sec, stderr);
}

  Thanks!

Regards,
Chao-ying

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: [PATCH] MIPS: microMIPS ASE support
  2011-02-21 15:35           ` Maciej W. Rozycki
  2011-02-22 20:12             ` Fu, Chao-Ying
@ 2011-02-22 20:19             ` Fu, Chao-Ying
  2011-02-24 10:46               ` Maciej W. Rozycki
  2011-02-26  0:00             ` Maciej W. Rozycki
  2011-02-26 11:36             ` Richard Sandiford
  3 siblings, 1 reply; 41+ messages in thread
From: Fu, Chao-Ying @ 2011-02-22 20:19 UTC (permalink / raw)
  To: Maciej W. Rozycki, Richard Sandiford
  Cc: binutils, Fuhler, Rich, Lau, David, Mills, Kevin, Garbacea, Ilie,
	Catherine Moore, Nathan Sidwell, Joseph Myers, Nathan Froyd

> 
> > > > +  /* 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.

  GAS resolves all MIPS pc-relative relocation types inside assembling, so there are no issues for
BFD_RELOC_16_PCREL_S2.  For microMIPS, GAS leaves them to the linker, so we hit new issues for
microMIPS pc-relative relocation types.  Thanks!

Regards,
Chao-ying

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: [PATCH] MIPS: microMIPS ASE support
  2011-02-22 20:19             ` Fu, Chao-Ying
@ 2011-02-24 10:46               ` Maciej W. Rozycki
  2011-02-26 11:41                 ` Richard Sandiford
  0 siblings, 1 reply; 41+ messages in thread
From: Maciej W. Rozycki @ 2011-02-24 10:46 UTC (permalink / raw)
  To: Fu, Chao-Ying
  Cc: Richard Sandiford, binutils, Fuhler, Rich, Lau, David, Mills,
	Kevin, Garbacea, Ilie, Catherine Moore, Nathan Sidwell,
	Joseph Myers, Nathan Froyd

On Tue, 22 Feb 2011, Fu, Chao-Ying wrote:

> > > > > +  /* 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.
> 
>   GAS resolves all MIPS pc-relative relocation types inside assembling, so there are no issues for
> BFD_RELOC_16_PCREL_S2.  For microMIPS, GAS leaves them to the linker, so we hit new issues for
> microMIPS pc-relative relocation types.  Thanks!

 Thanks for the hint -- now I can see what's going on.

 The problem is for REL targets we have a limited number of relocatable 
bits in the instruction to store the in-place addend.  The space does not 
cover the whole address space and because these are PC-relative 
relocations, if converted to section-relative ones, then they can overflow 
even for legitimate symbol references.

 As such the change belongs next to the check for BFD_RELOC_MIPS_JALR 
relocations and likewise it does not apply to RELA targets.  I have 
updated the change accordingly.

 Contrary to what you say the problem does apply to standard MIPS code 
too, because BFD_RELOC_16_PCREL_S2 relocs against defined symbols are not 
always resolved internally by GAS and R_MIPS_PC16 relocs are produced as 
appropriate.  Consider the following program:

$ cat bsec.s
	.text
	.space	0x40000
.Lbar:
	addu	$2, $3, $4

	.section .init, "ax", @progbits
foo:
	b	.Lbar

As .Lbar is a local defined symbol from another section, a relocation is 
placed into the output file for the static linker to resolve based on the 
final section layout.  The program does not build though:

$ mips-sde-elf-as -o bsec.o bsec.s
bsec.s: Assembler messages:
bsec.s:8: Error: relocation overflow

This is because .Lbar is too far into .text for the PC-relative offset to 
fit into the relocatable field of the R_MIPS_PC16 reloc.  Therefore this 
reference shouldn't be made section-relative either.  This observation 
makes this change not specific to microMIPS relocations at all, so I have 
separated it and I'm providing it below.  I have removed the original hunk 
from the microMIPS patch altogether now.

 And for the record, MIPS16 branches produce no reloc at all (hence 
excluded from the test case), even though they probably should.

2011-02-24  Maciej W. Rozycki  <macro@codesourcery.com>

	gas/
	* config/tc-mips.c (mips_fix_adjustable): On REL targets also 
	reject PC-relative relocations.

	gas/testsuite/
	* gas/mips/branch-misc-2.d: Adjust for relocation change.
	* gas/mips/branch-misc-2pic.d: Likewise.
	* gas/mips/branch-misc-4.d: New test for PC-relative relocation
	overflow.
	* gas/mips/branch-misc-4-64.d: Likewise.
	* gas/mips/branch-misc-4.s: Source for the new tests.
	* testsuite/gas/mips/mips.exp: Run the new tests.

 This change has been regression-tested for the mips-sde-elf and 
mips-linux-gnu targets.  OK to apply?

  Maciej

binutils-gas-mips-fix-pc-rel.diff
Index: binutils-fsf-trunk-quilt/gas/config/tc-mips.c
===================================================================
--- binutils-fsf-trunk-quilt.orig/gas/config/tc-mips.c	2011-02-24 10:14:39.000000000 +0000
+++ binutils-fsf-trunk-quilt/gas/config/tc-mips.c	2011-02-24 10:22:22.000000000 +0000
@@ -14229,8 +14229,12 @@ mips_fix_adjustable (fixS *fixp)
       && (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_MERGE) != 0)
     return 0;
 
-  /* There is no place to store an in-place offset for JALR relocations.  */
-  if (fixp->fx_r_type == BFD_RELOC_MIPS_JALR && HAVE_IN_PLACE_ADDENDS)
+  /* There is no place to store an in-place offset for JALR relocations.
+     Likewise an in-range offset of PC-relative relocations may overflow
+     the in-place relocatable field if recalculated against the start
+     address of the symbol's containing section.  */
+  if (HAVE_IN_PLACE_ADDENDS
+      && (fixp->fx_pcrel || fixp->fx_r_type == BFD_RELOC_MIPS_JALR))
     return 0;
 
 #ifdef OBJ_ELF
Index: binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/branch-misc-2.d
===================================================================
--- binutils-fsf-trunk-quilt.orig/gas/testsuite/gas/mips/branch-misc-2.d	2011-02-24 10:14:33.000000000 +0000
+++ binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/branch-misc-2.d	2011-02-24 10:20:45.000000000 +0000
@@ -39,6 +39,6 @@
 [ 	]*b0: R_MIPS_PC16	x2
 0+00b4 <[^>]*> 00000000 	nop
 0+00b8 <[^>]*> 1000ffff 	b	000000b8 <g6\+0x10>
-[ 	]*b8: R_MIPS_PC16	\.data
+[ 	]*b8: R_MIPS_PC16	\.Ldata
 0+00bc <[^>]*> 00000000 	nop
 	\.\.\.
Index: binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/branch-misc-2pic.d
===================================================================
--- binutils-fsf-trunk-quilt.orig/gas/testsuite/gas/mips/branch-misc-2pic.d	2011-02-24 10:14:33.000000000 +0000
+++ binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/branch-misc-2pic.d	2011-02-24 10:20:45.000000000 +0000
@@ -40,6 +40,6 @@
 [ 	]*b0: R_MIPS_PC16	x2
 0+00b4 <[^>]*> 00000000 	nop
 0+00b8 <[^>]*> 1000ffff 	b	000000b8 <g6\+0x10>
-[ 	]*b8: R_MIPS_PC16	\.data
+[ 	]*b8: R_MIPS_PC16	\.Ldata
 0+00bc <[^>]*> 00000000 	nop
 	\.\.\.
Index: binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/branch-misc-4.d
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/branch-misc-4.d	2011-02-24 10:22:59.000000000 +0000
@@ -0,0 +1,26 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: MIPS branch-misc-4
+#as: -32
+
+# Verify PC-relative relocations do not overflow.
+
+.*: +file format .*mips.*
+
+Disassembly of section \.text:
+	\.\.\.
+([0-9a-f]+) <[^>]*> 1000ffff 	b	\1 <foo>
+[ 	]*[0-9a-f]+: R_MIPS_PC16	bar
+[0-9a-f]+ <[^>]*> 00000000 	nop
+([0-9a-f]+) <[^>]*> 1000ffff 	b	\1 <\.Lfoo>
+[ 	]*[0-9a-f]+: R_MIPS_PC16	\.Lbar
+[0-9a-f]+ <[^>]*> 00000000 	nop
+	\.\.\.
+
+Disassembly of section \.init:
+([0-9a-f]+) <[^>]*> 1000ffff 	b	\1 <bar>
+[ 	]*[0-9a-f]+: R_MIPS_PC16	foo
+[0-9a-f]+ <[^>]*> 00000000 	nop
+([0-9a-f]+) <[^>]*> 1000ffff 	b	\1 <\.Lbar>
+[ 	]*[0-9a-f]+: R_MIPS_PC16	\.Lfoo
+[0-9a-f]+ <[^>]*> 00000000 	nop
+	\.\.\.
Index: binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/branch-misc-4.s
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/branch-misc-4.s	2011-02-24 10:14:40.000000000 +0000
@@ -0,0 +1,28 @@
+# Source file to verify PC-relative relocations do not overflow.
+
+	.text
+	.space	0x40000
+	.globl	foo
+	.ent	foo
+foo:
+	b	bar
+.Lfoo:
+	b	.Lbar
+	.end	foo
+
+# Force at least 8 (non-delay-slot) zero bytes, to make 'objdump' print ...
+	.align	2
+	.space	8
+
+	.section .init, "ax", @progbits
+	.globl	bar
+	.ent	bar
+bar:
+	b	foo
+.Lbar:
+	b	.Lfoo
+	.end	bar
+
+# Force at least 8 (non-delay-slot) zero bytes, to make 'objdump' print ...
+	.align	2
+	.space	8
Index: binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/mips.exp
===================================================================
--- binutils-fsf-trunk-quilt.orig/gas/testsuite/gas/mips/mips.exp	2011-02-24 10:14:39.000000000 +0000
+++ binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/mips.exp	2011-02-24 10:20:46.000000000 +0000
@@ -838,6 +838,10 @@ if { [istarget mips*-*-vxworks*] } {
 	run_dump_test_arches "loc-swap"	[mips_arch_list_all]
 	run_dump_test_arches "loc-swap-dis" \
 					[mips_arch_list_all]
+	run_dump_test_arches "branch-misc-4" \
+					[mips_arch_list_matching mips1]
+	run_dump_test_arches "branch-misc-4-64" \
+					[mips_arch_list_matching mips3]
     }
 
     if $has_newabi {
Index: binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/branch-misc-4-64.d
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/branch-misc-4-64.d	2011-02-24 10:14:40.000000000 +0000
@@ -0,0 +1,35 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: MIPS branch-misc-4-64
+#as: -64
+#source: branch-misc-4.s
+
+# Verify PC-relative relocations do not overflow.
+
+.*: +file format .*mips.*
+
+Disassembly of section \.text:
+	\.\.\.
+[0-9a-f]+ <[^>]*> 10000000 	b	[0-9a-f]+ <foo\+0x[0-9a-f]+>
+[ 	]*[0-9a-f]+: R_MIPS_PC16	bar\+0xf+fffc
+[ 	]*[0-9a-f]+: R_MIPS_NONE	\*ABS\*\+0xf+fffc
+[ 	]*[0-9a-f]+: R_MIPS_NONE	\*ABS\*\+0xf+fffc
+[0-9a-f]+ <[^>]*> 00000000 	nop
+[0-9a-f]+ <[^>]*> 10000000 	b	[0-9a-f]+ <foo\+0x[0-9a-f]+>
+[ 	]*[0-9a-f]+: R_MIPS_PC16	\.init\+0x4
+[ 	]*[0-9a-f]+: R_MIPS_NONE	\*ABS\*\+0x4
+[ 	]*[0-9a-f]+: R_MIPS_NONE	\*ABS\*\+0x4
+[0-9a-f]+ <[^>]*> 00000000 	nop
+	\.\.\.
+
+Disassembly of section \.init:
+[0-9a-f]+ <[^>]*> 10000000 	b	[0-9a-f]+ <bar\+0x[0-9a-f]+>
+[ 	]*[0-9a-f]+: R_MIPS_PC16	foo\+0xf+fffc
+[ 	]*[0-9a-f]+: R_MIPS_NONE	\*ABS\*\+0xf+fffc
+[ 	]*[0-9a-f]+: R_MIPS_NONE	\*ABS\*\+0xf+fffc
+[0-9a-f]+ <[^>]*> 00000000 	nop
+[0-9a-f]+ <[^>]*> 10000000 	b	[0-9a-f]+ <bar\+0x[0-9a-f]+>
+[ 	]*[0-9a-f]+: R_MIPS_PC16	\.text\+0x40004
+[ 	]*[0-9a-f]+: R_MIPS_NONE	\*ABS\*\+0x40004
+[ 	]*[0-9a-f]+: R_MIPS_NONE	\*ABS\*\+0x40004
+[0-9a-f]+ <[^>]*> 00000000 	nop
+	\.\.\.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2011-02-21 15:35           ` Maciej W. Rozycki
  2011-02-22 20:12             ` Fu, Chao-Ying
  2011-02-22 20:19             ` Fu, Chao-Ying
@ 2011-02-26  0:00             ` Maciej W. Rozycki
  2011-03-13  9:23               ` Richard Sandiford
  2011-02-26 11:36             ` Richard Sandiford
  3 siblings, 1 reply; 41+ messages in thread
From: Maciej W. Rozycki @ 2011-02-26  0:00 UTC (permalink / raw)
  To: Richard Sandiford
  Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
	Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers,
	Nathan Froyd

[-- Attachment #1: Type: TEXT/PLAIN, Size: 34439 bytes --]

Hi Richard,

 As it has turned out in the course of sorting out some earlier concerns 
the microMIPS change needs a couple of updates.  For your reference I'm 
sending the current version of the original patch as it had to be 
regenerated.  On top of this I'm sending the following updates:

- binutils-umips-fix.diff -- the original fix addressing your concerns and 
  some other issues, regenerated, and with some small bug fixes applied,

- binutils-umips-opcode-trap.diff -- a complementing microMIPS change to 
  the trap/no-delay slot annotation made to standard MIPS/MIPS16 code,

- binutils-gas-mips-fix-adjust-reloc.diff -- a fix for relocation handling 
  problems discovered while fixing the issue with PC-relative relocations 
  discussed earlier; a summary of the changes:

  * BFD_RELOC_MICROMIPS_JALR relocs are now explicitly excluded like their
    standard MIPS counterpart; this bug was covered by all microMIPS being 
    converted to section-relative ones,

  * unlike MIPS16 code we don't have call stubs in the microMIPS mode and 
    therefore of the remaing relocs affecting microMIPS code only jump 
    relocations against microMIPS text symbols on REL targets are 
    converted to section-relative ones as the in-place relocatable field 
    strips out the ISA bit,

  * therefore we don't have to tag symbols that have a microMIPS jump 
    relocation against them, because they're going to be handled just fine 
    as long as the symbol is not a microMIPS text one,

- binutils-umips-relax16.diff -- the original 16-bit->32-bit->out-of-range 
  branch relaxation change, regenerated,

- binutils-umips-fix-reloc.diff -- the original microMIPS relocation 
  handling divergence reduction change, regenerated,

- binutils-gas-umips-swap.diff -- branch delay slot scheduling support for 
  microMIPS code as the DWARF-2 line number adjustment fix I posted 
  earlier made it possible to enable it now.  We lacked some 
  infrastructure here, so I have added the necessary register dependencies 
  tests, as well as checks that we don't reorder something unsuitable into 
  a slot of a fixed size (in theory we could do this anyway and flip the 
  delay-slot-size bit in the branch or jump instruction output, but that's 
  not as easy as it would seem at this point of instruction processing, so 
  I left it as a future enhancement [FIXME]).  I believe we can't reorder 
  an ADDIUPC either as it would break offset calculation if a label at the 
  instruction was used (quite likely) that doesn't get moved with the 
  swap.

  I have split some of the combined register access flags so that we can 
  avoid false negatives and reorder some frequent instructions, such as 
  16-bit MOVEs.  Some of these flags actually turned out not to be 
  combined at all.  I have joined the MM and MN flags as they are always 
  used together (by MOVEP) and therefore need not be separate.  Given the 
  shortage of flags (I tried to avoid overloading) I have decided MD and 
  SP are the ones that can remain combined, the former because it's only 
  used to mark registers read with branches and these cannot be scheduled 
  into delay slots anyway, and the latter because the use of $sp as the 
  condition for branches is unusual.  I have split them syntactically by 
  the usage throughout the opcode table though, so making them separate in 
  the future will be as easy as updating <opcode/mips.h> and any 
  references in GAS.

 All these were regression-tested against mips-sde-elf and mips-gnu-linux.  
An updated set of ChangeLog entries follows.  Patches apply in the order 
stated and require all the standard MIPS changes I submitted this week.

  Maciej

binutils-20110225-umips.diff
binutils-20110225-umips-fix.diff
binutils-20110225-umips-opcode-trap.diff
binutils-20110225-gas-mips-fix-adjust-reloc.diff
binutils-20110225-umips-relax16.diff
binutils-20110225-umips-fix-reloc.diff
binutils-20110225-gas-umips-swap.diff
[Patches attached compressed due to their size.]

bfd/
2011-02-25  Chao-ying Fu  <fu@mips.com>
            Ilie Garbacea  <ilie@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>
            Joseph Myers  <joseph@codesourcery.com>
            Catherine Moore  <clm@codesourcery.com>

	* 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-25  Chao-ying Fu  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* readelf.c (get_machine_flags): Handle microMIPS ASE.
	(get_mips_symbol_other): Likewise.

gas/
2011-02-25  Maciej W. Rozycki  <macro@codesourcery.com>
            Chao-ying Fu  <fu@mips.com>

	* 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-25  Maciej W. Rozycki  <macro@codesourcery.com>
            Chao-ying Fu  <fu@mips.com>

	* 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@alnv_ps-swap.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-misc-4-64.d: Likewise.
	* gas/mips/micromips@branch-misc-4.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@loc-swap-dis.d: Likewise.
	* gas/mips/micromips@loc-swap.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@relax-at.d: Likewise.
	* gas/mips/micromips@relax.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/mips4.s: Likewise.
	* gas/mips/mips4-fp.s: Likewise.
	* gas/mips/relax.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/relax-at.d: Likewise.
	* gas/mips/relax.d: Likewise.

include/elf/
2011-02-25  Chao-ying Fu  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* 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-25  Chao-ying Fu  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* 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.
	(INSN_WRITE_GPR_S): New macro.
	(INSN2_BRANCH_DELAY_16BIT, INSN2_BRANCH_DELAY_32BIT): Likewise.
	(INSN2_READ_FPR_D): Likewise.
	(INSN2_WRITE_GPR_MB, INSN2_READ_GPR_MC): Likewise.
	(INSN2_MOD_GPR_MD, INSN2_READ_GPR_ME): Likewise.
	(INSN2_WRITE_GPR_MF, INSN2_READ_GPR_MG): Likewise.
	(INSN2_READ_GPR_MJ, INSN2_WRITE_GPR_MJ): Likewise.
	(INSN2_READ_GPR_MP, INSN2_WRITE_GPR_MP): Likewise.
	(INSN2_READ_GPR_MQ, INSN2_MOD_SP, INSN2_READ_GPR_31): Likewise.
	(INSN2_READ_GP, INSN2_READ_PC): Likewise.
	(INSN2_UNCOND_BRANCH, INSN2_COND_BRANCH): Likewise.
	(INSN2_WRITE_GPR_MHI, INSN2_READ_GPR_MMN): 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_MH, MICROMIPSOP_SH_MH): Likewise.
	(MICROMIPSOP_MASK_MI, MICROMIPSOP_SH_MI): Likewise.
	(MICROMIPSOP_MASK_MJ, MICROMIPSOP_SH_MJ): Likewise.
	(MICROMIPSOP_MASK_ML, MICROMIPSOP_SH_ML): Likewise.
	(MICROMIPSOP_MASK_MM, MICROMIPSOP_SH_MM): Likewise.
	(MICROMIPSOP_MASK_MN, MICROMIPSOP_SH_MN): 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.

ld/testsuite/
2011-02-25  Catherine Moore  <clm@codesourcery.com>
            Chao-ying Fu  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* 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-25  Chao-ying Fu  <fu@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	* 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.

[-- Attachment #2: Type: APPLICATION/octet-stream, Size: 157623 bytes --]

[-- Attachment #3: Type: APPLICATION/octet-stream, Size: 36198 bytes --]

[-- Attachment #4: Type: APPLICATION/octet-stream, Size: 2047 bytes --]

[-- Attachment #5: Type: APPLICATION/octet-stream, Size: 3116 bytes --]

[-- Attachment #6: Type: APPLICATION/octet-stream, Size: 7589 bytes --]

[-- Attachment #7: Type: APPLICATION/octet-stream, Size: 4079 bytes --]

[-- Attachment #8: Type: APPLICATION/octet-stream, Size: 8309 bytes --]

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2011-02-21 15:35           ` Maciej W. Rozycki
                               ` (2 preceding siblings ...)
  2011-02-26  0:00             ` Maciej W. Rozycki
@ 2011-02-26 11:36             ` Richard Sandiford
  2011-07-26 14:00               ` Maciej W. Rozycki
  3 siblings, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2011-02-26 11:36 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
	Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers,
	Nathan Froyd

Thanks for the updates.  I'll try to go through the patches in the next
couple of weeks (maybe later this weekend).

"Maciej W. Rozycki" <macro@codesourcery.com> writes:
>> "Maciej W. Rozycki" <macro@codesourcery.com> 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]

I agree that these are minor.  At least with (1) we'll get an error
rather than silent wrong code, and like you say, if someone hits that error,
they can simply stop using relaxation.

I think it's fair for us to say that (2) is disallowed if you want to
use linker optimisations.

>> > +  /* 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?

Oh no, it wasn't any sense of burden that bothered me.  It was more
the talk of "the microMIPS processor".  "The MIPS16 processor" made
sense when the support was first added, but plain "microMIPS" makes
more sense here.  (Or, reading further on, I suppose you won't agree.
Something other than "processor" though, if you want to treat
"microMIPS" as an adjective.)

I just thought that, if this was dead code, we might as well just
remove it rather than quibble about wording.  Given what you say about
microMIPS-only processors being possible though, please just change the
comment instead.

>> > +#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?

Nope :-)

> 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.

But that's true of all fixups, and should already be handled correctly.

E.g. if you had microMIPS code embedded in a larger MIPS function, you
might have normal MIPS branches that cross relaxable microMIPS instructions.
The same consideration would apply then, even if branch relaxation
wasn't enabled.

>> > +#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.

Thanks, missed that.

>> > +	      /* 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.

Thanks, the new version is much more descriptive.

>> >  	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.

Oops, yes.

>  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?

In a word, no.

>> > -	  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.

Ah, yeah, sorry.  As you'd guessed, I think I got "C" and "S" confused.

>  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.

Which answers my question in the other message. :-)  Good catch.

>> > +		  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.

Thanks for the explanation and the change.  The new version is much clearer.

>> > +		    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.

Ah, yeah, imm_expr trumps offset_expr.

>  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.

Thanks, that's better.

>> > +		  /* 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).

I'm not particularly happy about the loongson workarounds TBH.

>  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.

Thanks.

>> > +  /* 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?

Thanks for the discussion and revision downthread.  The final version makes
much more sense.

>> > 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. ;)

We'll just have to agree to disagree here.  Both "#pass" and "insert
a set amount of padding at the end of each source file" have their
disadvantages.  The former fails to catch cases where we emit extra
junk.  The latter means that we never test source files that people
are actually likely to write, or that have instructions at the end
of the section.  I think the former is at least as good as the latter.

>> > -#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.

Fair enough.

>> > +/* 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.

As you say, the MIPS16 comment is:

/* 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.

OP in this case refers to the first field definition:

#define MIPS16OP_MASK_OP	0x1f
#define MIPS16OP_SH_OP		11

which is the opcode ("fixed portion").  There didn't seem to be
a corresponding MASK_OP and SH_OP for microMIPS.

I'm equally bemused as to where I'd got "TARGET" from...

>> > +/* 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.

Really?  I'd have thought they were nouns.  If you want them to be
adjectives though, it should be "either the ...".

>> > +  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.

Agreed, and like I say, I was willing to believe the new code was right.
Please put in a comment along these lines.

>> 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.

OK, thanks, makes sense.  The ld-lib.exp change is independently OK.
Please commit it separately.

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2011-02-24 10:46               ` Maciej W. Rozycki
@ 2011-02-26 11:41                 ` Richard Sandiford
  2011-02-28 16:41                   ` Maciej W. Rozycki
  0 siblings, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2011-02-26 11:41 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: Fu, Chao-Ying, binutils, Fuhler, Rich, Lau, David, Mills, Kevin,
	Garbacea, Ilie, Catherine Moore, Nathan Sidwell, Joseph Myers,
	Nathan Froyd

> 2011-02-24  Maciej W. Rozycki  <macro@codesourcery.com>
>
> 	gas/
> 	* config/tc-mips.c (mips_fix_adjustable): On REL targets also 
> 	reject PC-relative relocations.
>
> 	gas/testsuite/
> 	* gas/mips/branch-misc-2.d: Adjust for relocation change.
> 	* gas/mips/branch-misc-2pic.d: Likewise.
> 	* gas/mips/branch-misc-4.d: New test for PC-relative relocation
> 	overflow.
> 	* gas/mips/branch-misc-4-64.d: Likewise.
> 	* gas/mips/branch-misc-4.s: Source for the new tests.
> 	* testsuite/gas/mips/mips.exp: Run the new tests.

OK, thanks.

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2011-02-26 11:41                 ` Richard Sandiford
@ 2011-02-28 16:41                   ` Maciej W. Rozycki
  0 siblings, 0 replies; 41+ messages in thread
From: Maciej W. Rozycki @ 2011-02-28 16:41 UTC (permalink / raw)
  To: Richard Sandiford
  Cc: Fu\, Chao-Ying, binutils\@sourceware.org, Fuhler\, Rich, Lau\,
	David, Mills\, Kevin, Garbacea\,
	Ilie, Catherine Moore, Nathan Sidwell, Joseph Myers,
	Nathan Froyd

On Sat, 26 Feb 2011, Richard Sandiford wrote:

> > 2011-02-24  Maciej W. Rozycki  <macro@codesourcery.com>
> >
> > 	gas/
> > 	* config/tc-mips.c (mips_fix_adjustable): On REL targets also 
> > 	reject PC-relative relocations.
> >
> > 	gas/testsuite/
> > 	* gas/mips/branch-misc-2.d: Adjust for relocation change.
> > 	* gas/mips/branch-misc-2pic.d: Likewise.
> > 	* gas/mips/branch-misc-4.d: New test for PC-relative relocation
> > 	overflow.
> > 	* gas/mips/branch-misc-4-64.d: Likewise.
> > 	* gas/mips/branch-misc-4.s: Source for the new tests.
> > 	* testsuite/gas/mips/mips.exp: Run the new tests.
> 
> OK, thanks.

 And I've integrated this one too, thanks.  I'll go through your new 
comments in one run once you're done with the review.  Thanks for your 
effort.

  Maciej

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2011-02-26  0:00             ` Maciej W. Rozycki
@ 2011-03-13  9:23               ` Richard Sandiford
  2011-07-25  7:49                 ` Richard Sandiford
  0 siblings, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2011-03-13  9:23 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
	Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers,
	Nathan Froyd

"Maciej W. Rozycki" <macro@codesourcery.com> writes:
>  As it has turned out in the course of sorting out some earlier concerns 
> the microMIPS change needs a couple of updates.  For your reference I'm 
> sending the current version of the original patch as it had to be 
> regenerated.  On top of this I'm sending the following updates:

Everything except binutils-gas-umips-swap.diff is OK (as one commit,
like you say), with the changes below.  If you don't agree with some
of the requested changes, let me know.

I thinkb inutils-gas-umips-swap.diff should go in as a separate commit,
and I'll review it separately.

> - binutils-umips-opcode-trap.diff -- a complementing microMIPS change to 
>   the trap/no-delay slot annotation made to standard MIPS/MIPS16 code,

Nit:

-      target_is_micromips_code_p = (htab->splt != sec)
-				    && ELF_ST_IS_MICROMIPS (h->root.other);
+      target_is_micromips_code_p = ((htab->splt != sec)
+				    && ELF_ST_IS_MICROMIPS (h->root.other));

should be:

      target_is_micromips_code_p = (htab->splt != sec
				    && ELF_ST_IS_MICROMIPS (h->root.other));

-      if (isym->st_shndx == sec_shndx
-	  && isym->st_value > addr
-	  && isym->st_value < toaddr)
+      bfd_vma value;
+
+      if (isym->st_shndx != sec_shndx)
+	continue;
+
+      value = isym->st_value;
+      if (ELF_ST_IS_MICROMIPS (isym->st_other))
+	value &= MINUS_TWO;
+      if (value > addr)
 	isym->st_value -= count;

I still don't understand why we need to mask the low bit here.
As per the original review, aren't these symbols already even?
Only those entered into the hash table are odd.  OK as:

      if (isym->st_shndx == sec_shndx
	  && isym->st_value > addr)
	isym->st_value -= count;

if that's correct, but please let me know if it isn't.

@@ -11936,12 +11933,17 @@ mips_elf_relax_delete_bytes (bfd *abfd,
   for (; sym_hashes < end_hashes; sym_hashes++)
     {
       struct elf_link_hash_entry *sym_hash = *sym_hashes;
+      bfd_vma value;
 
-      if ((sym_hash->root.type == bfd_link_hash_defined
-	   || sym_hash->root.type == bfd_link_hash_defweak)
-	  && sym_hash->root.u.def.section == sec
-	  && sym_hash->root.u.def.value > addr
-	  && sym_hash->root.u.def.value < toaddr)
+      if ((sym_hash->root.type != bfd_link_hash_defined
+	   && sym_hash->root.type != bfd_link_hash_defweak)
+	  || sym_hash->root.u.def.section != sec)
+	continue;
+
+      value = sym_hash->root.u.def.value;
+      if (ELF_ST_IS_MICROMIPS (sym_hash->other))
+	value &= MINUS_TWO;
+      if (value > addr)
 	sym_hash->root.u.def.value -= count;
     }

Very much nit stage, but "continue" seems overkill here.  I preferred
the original style, which doesn't have the combination of positive
and negative tests.  OK as:

      if ((sym_hash->root.type == bfd_link_hash_defined
	   || sym_hash->root.type == bfd_link_hash_defweak)
	  && sym_hash->root.u.def.section == sec)
	{
	  bfd_vma value;

	  value = sym_hash->root.u.def.value;
	  if (ELF_ST_IS_MICROMIPS (sym_hash->other))
	    value &= MINUS_TWO;
	  if (value > addr)
	    sym_hash->root.u.def.value -= count;
	}

+	  /* See if there is a jump or a branch reloc preceding the
+	     LUI instruction immediately.  */
+	  for (ibrrel = internal_relocs; ibrrel < irelend; ibrrel++)
+	    {
+	      offset = irel->r_offset - ibrrel->r_offset;
+	      if (offset != 2 && offset != 4)
+		continue;
+
+	      br_r_type = ELF32_R_TYPE (ibrrel->r_info);
+	      if (offset == 2
+		  && (br_r_type == R_MICROMIPS_PC7_S1
+		      || br_r_type == R_MICROMIPS_PC10_S1
+		      || br_r_type == R_MICROMIPS_JALR))
+		break;
+	      if (offset == 4
+		  && (br_r_type == R_MICROMIPS_26_S1
+		      || br_r_type == R_MICROMIPS_PC16_S1
+		      || br_r_type == R_MICROMIPS_JALR))
+		{
+		  bfd_byte *ptr = contents + ibrrel->r_offset;
+		  unsigned long bropc;
+
+		  bropc   = bfd_get_16 (abfd, ptr);
+		  bropc <<= 16;
+		  bropc  |= bfd_get_16 (abfd, ptr + 2);
+		  /* Compact branches are OK.  */
+		  if (find_match (opcode, bzc_insns_32) >= 0)
+		    brc = TRUE;
+		  break;
+		}
+	    }
+	  /* A delay slot was found, give up, sigh...  */
+	  if (!brc && ibrrel < irelend)
+	    continue;
+
+	  /* Otherwise see if the LUI instruction *might* be in a
+	     branch delay slot.  */
+	  if (!brc)
+	    {
+	      bfd_byte *ptr = contents + irel->r_offset;
+
+	      if (irel->r_offset >= 2)
+		bdsize = check_br16_dslot (abfd, ptr - 2);
+	      /* A branch possibly found, give up, sigh...  */
+	      if (bdsize > 0)
+		continue;
+	      if (irel->r_offset >= 4)
+		bdsize = check_br32_dslot (abfd, ptr - 4);
+	      /* A branch possibly found, give up, sigh...  */
+	      if (bdsize > 0)
+		continue;
+	    }

ISTR discussing this before, but with the new approach, it ought not to
be necessary to check the relocations for this get-out:

	  /* A delay slot was found, give up, sigh...  */
	  if (!brc && ibrrel < irelend)
	    continue;

because the following code ought to detect the same cases (and do
so much more cheaply).  If you want to avoid this:

	      if (irel->r_offset >= 2)
		bdsize = check_br16_dslot (abfd, ptr - 2);
	      /* A branch possibly found, give up, sigh...  */
	      if (bdsize > 0)
		continue;

triggering for cases where the relocs tell us that the instruction
is actually a BRC, then I think it would be better to split the
search out into a separate function and only use it when we would
otherwise continue.  OK as:

/* See if relocations [INTERNAL_RELOCS, IRELEND) confirm that there
   is a 4-byte branch at offset OFFSET.  */

static boolean
check_4byte_branch (Elf_Internal_Rela *internal_relocs,
		    Elf_Internal_Rela *irelend, bfd_vma offset)
{
  Elf_Internal_Rela *irel;
  unsigned long r_type;

  for (irel = internal_relocs; irel < irelend; irel++)
    if (irel->r_offset == offset)
      {
	r_type = ELF32_R_TYPE (ibrrel->r_info);
	if (br_r_type == R_MICROMIPS_26_S1
	    || br_r_type == R_MICROMIPS_PC16_S1
	    || br_r_type == R_MICROMIPS_JALR)
	  return TRUE;
      }
  return FALSE;
}
...

	  /* See if the LUI instruction *might* be in a branch delay slot.  */
	  if (irel->r_offset >= 2
	      && check_br16_dslot (abfd, ptr - 2) > 0
	      && !(irel->r_offset >= 4
		   /* If the instruction is actually a 4-byte branch,
		      the value of check_br16_dslot doesn't matter.
		      We should use check_br32_dslot to check whether
		      the branch has a delay slot.  */
		   && check_4byte_branch (internal_relocs, irelend,
					  irel->r_offset - 4)))
	    continue;
	  if (irel->r_offset >= 4
	      && check_br32_dslot (abfd, ptr - 4) > 0)
	    continue;

if that's correct (with trivial fixes to make it compile :-)),
otherwise please let me know.

Of course, this could be generalised so that if the relocations say
we have any type of 4-byte instruction, check_br16_dslot doesn't matter,
and vice versa.  But even if you'd like to do that, it's follow-on material.
Let's get the current code in first.

bdsize should be dead after the changes above.

-	  /* Give up if not the same register used with both relocations.  */
+	  /* Give up unless the same register used with both relocations.  */

Should be:

	  /* Give up unless the same register is used with both relocations.  */

+/* Check if S points at a valid register list according to TYPES.
+   If so, then return 1, advance S to consume the list and store
+   the registers present on the list as a bitmask of ones in REGLISTP,
+   otherwise return 0.  A valid list comprises a comma-separated
+   enumeration of valid single registers and/or dash-separated
+   contiguous register ranges as determined by their numbers.
+
+   As a special exception if one of s0-s7 registers is specified as
+   the range's lower delimiter and s8 (fp) is its upper one, then no
+   registers whose numbers place them between s7 and s8 (i.e. $24-$29)
+   are selected; they have to be named separately if needed.  */
+
+static int
+reglist_lookup (char **s, unsigned int types, unsigned int *reglistp)
+{
+  unsigned int reglist = 0;
+  unsigned int lastregno;
+  bfd_boolean ok = TRUE;
+  unsigned int regmask;
+  unsigned int regno;
+  char *s_reset = *s;
+  char *s_comma = *s;
+
+  while (reg_lookup (s, types, &regno))
+    {
+      lastregno = regno;
+      if (**s == '-')
+	{
+	  (*s)++;
+	  ok = reg_lookup (s, types, &lastregno);
+	  if (ok && lastregno < regno)
+	    ok = FALSE;
+	  if (!ok)
+	    break;
+	}
+
+      if (lastregno == FP && regno >= S0 && regno <= S7)
+	{
+	  lastregno = S7;
+	  reglist |= 1 << FP;
+	}
+      regmask = 1 << lastregno;
+      regmask = (regmask << 1) - 1;
+      regmask ^= (1 << regno) - 1;
+      reglist |= regmask;
+
+      s_comma = *s;
+      if (**s != ',')
+	break;
+      (*s)++;
+    }
+
+  if (ok)
+    *s = s_comma;
+  else
+    *s = s_reset;
+  if (reglistp)
+    *reglistp = reglist;
+  return ok && reglist != 0;
+}

I found s_comma a confusing name for something that often doesn't
point to a comma.  OK as "s_end_of_reglist", otherwise let me know.

+      /* If the previous instruction has an incorrect size for a fixed
+         branch delay slot in the microMIPS mode, we cannot swap.  */

OK as "in microMIPS mode".

As discussed later, from the original patch:

+/* 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.  */

Just drop the "Other than OP, ".

> - binutils-gas-mips-fix-adjust-reloc.diff -- a fix for relocation handling 
>   problems discovered while fixing the issue with PC-relative relocations 
>   discussed earlier; a summary of the changes:
>
>   * BFD_RELOC_MICROMIPS_JALR relocs are now explicitly excluded like their
>     standard MIPS counterpart; this bug was covered by all microMIPS being 
>     converted to section-relative ones,
>
>   * unlike MIPS16 code we don't have call stubs in the microMIPS mode and 
>     therefore of the remaing relocs affecting microMIPS code only jump 
>     relocations against microMIPS text symbols on REL targets are 
>     converted to section-relative ones as the in-place relocatable field 
>     strips out the ISA bit,
>
>   * therefore we don't have to tag symbols that have a microMIPS jump 
>     relocation against them, because they're going to be handled just fine 
>     as long as the symbol is not a microMIPS text one,

Makes sense.  OK as long as you split this:

@@ -17189,7 +17187,9 @@ mips_fix_adjustable (fixS *fixp)
+	  || fixp->fx_r_type == BFD_RELOC_MIPS_JALR
+	  || fixp->fx_r_type == BFD_RELOC_MICROMIPS_JALR))

into a jalr_reloc_p, which should be defined alongside the existing
*_reloc_p functions.  Likewise:

+	      && (fixp->fx_r_type == BFD_RELOC_MIPS_JMP
+		  || fixp->fx_r_type == BFD_RELOC_MICROMIPS_JMP))))

and jmp_reloc_p.  (I think you already use this condition elsewhere,
so please change those too.)

> - binutils-umips-relax16.diff -- the original 16-bit->32-bit->out-of-range 
>   branch relaxation change, regenerated,

+      fragp->fr_var= length;

Missing space.

+      /* Handle 32-bit branches that fit or forced to fit.  */

"are forced to fit"

      /* Check the short-delay-slot bit.  */
      if (al && (insn & 0x02000000) != 0)
 	{
	  jal = 0x74000000;				/* jals  */
	  jalr = 0x45e0;				/* jalrs  */
	}

This is now quite far (and IMO confusingly far) from the code that sets
the default insns.  OK if you replace:

+      unsigned long jal = 0xf4000000;			/* jal  */
+      unsigned long jalr = 0x45c0;			/* jalr  */

with:

+      unsigned long jal, jalr;

and add:

      else
	{
	  jal = 0xf4000000;				/* jal  */
	  jalr = 0x45c0;				/* jalr  */
	}

to the condition above.

I think it'd be more consistent to set "jr" here too, but it's OK
either way.

> - binutils-umips-fix-reloc.diff -- the original microMIPS relocation 
>   handling divergence reduction change, regenerated,

+	      {
+		bfd_reloc_code_real_type reloc;
+		int shift;
+
+		reloc = micromips_map_reloc (orig_reloc);
+		shift = reloc == BFD_RELOC_MICROMIPS_JMP ? 1 : 2;
+		if ((address_expr->X_add_number & ((1 << shift) - 1)) != 0)
+		  as_bad (_("jump to misaligned address (0x%lx)"),
+			  (unsigned long) address_expr->X_add_number);
+		ip->insn_opcode |= ((address_expr->X_add_number >> shift)
+				    & 0x3ffffff);
+	      }

OK if you replace:

+		reloc = micromips_map_reloc (orig_reloc);
+		shift = reloc == BFD_RELOC_MICROMIPS_JMP ? 1 : 2;

with:

+		shift = mips_opts.micromips ? 1 : 2;

Same for BFD_RELOC_16_PCREL_S2.

+	  reloc = micromips_map_reloc (reloc_type[i - 1]);
+	  howto = bfd_reloc_type_lookup (stdoutput, reloc);
 	  if (howto == NULL)
 	    {
 	      /* To reproduce this failure try assembling gas/testsuites/
 		 gas/mips/mips16-intermix.s with a mips-ecoff targeted
 		 assembler.  */
-	      as_bad (_("Unsupported MIPS relocation number %d"), reloc_type[i - 1]);
+	      as_bad (_("Unsupported MIPS relocation number %d"), reloc);
 	      howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16);
 	    }
-	  
+
+	  reloc = micromips_map_reloc (orig_reloc);

In the usual case, this calls micromips_map_reloc twice for the same thing.
Seems better IMO to replace:

	  /* In a compound relocation, it is the final (outermost)
	     operator that determines the relocated field.  */
	  for (i = 1; i < 3; i++)
	    if (reloc_type[i] == BFD_RELOC_UNUSED)
	      break;

	  howto = bfd_reloc_type_lookup (stdoutput, reloc_type[i - 1]);

with:

	  bfd_reloc_code_real_type final_type[3];

	  /* Perform any necessary conversion to microMIPS relocations
	     and find out how many relocations there actually are.  */
	  for (i = 0; i < 3 && reloc_type[i] != BFD_RELOC_UNUSED; i++)
	    final_type[i] = micromips_map_reloc (reloc_type[i]);

	  /* In a compound relocation, it is the final (outermost)
	     operator that determines the relocated field.  */
	  howto = bfd_reloc_type_lookup (stdoutput, final_type[i - 1]);

Then use final_type instead of reloc_type.  OK with that change,
otherwise please let me know.

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2011-03-13  9:23               ` Richard Sandiford
@ 2011-07-25  7:49                 ` Richard Sandiford
  2011-07-26  2:01                   ` Maciej W. Rozycki
  0 siblings, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2011-07-25  7:49 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
	Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers,
	Nathan Froyd

[-- Attachment #1: Type: text/plain, Size: 2104 bytes --]

Continuing this thread from March:

Richard Sandiford <rdsandiford@googlemail.com> writes:
> "Maciej W. Rozycki" <macro@codesourcery.com> writes:
>>  As it has turned out in the course of sorting out some earlier concerns 
>> the microMIPS change needs a couple of updates.  For your reference I'm 
>> sending the current version of the original patch as it had to be 
>> regenerated.  On top of this I'm sending the following updates:
>
> Everything except binutils-gas-umips-swap.diff is OK (as one commit,
> like you say), with the changes below.

It seemed a shame to get to the point of an approved version and not
actually commit it.  I've now updated and regenerated the patch series,
made the changes from this approval, and applied a few other things I
noticed.  I've attached the three patches separately.

Tested on 

  mips64-elf mips64el-unknown-kfreebsd-gnu mips64-linux-gnu
  mips64octeon-linux-gnu mips64-unknown-kfreebsd-gnu
  mipsel-unknown-kfreebsd-gnu mipsisa32el-linux-gnu mipsisa64-elf
  mips-linux-gnu mips-unknown-kfreebsd-gnu mips-wrs-vxworks

Applied to trunk along with:

  http://sourceware.org/ml/binutils/2010-12/msg00399.html
  http://sourceware.org/ml/binutils/2011-02/msg00318.html

Maciej: I regenerated and updated each of your patches separately,
so if you'd like a copy of those individual patches, I can send them
privately.

I went on to say:

> If you don't agree with some of the requested changes, let me know.

and I gather from an off-list discussion a couple of months ago that
there were indeed some things that you didn't like.  But I think it'd
be easier to deal with them as follow-ups.  Please feel free to send
patches against trunk.  Or, if you tell me what it is you disagree with,
I can try to fix it myself.

I'm sure there are things that we've both missed, but again,
we can deal with them as follow-ups.

Last, but not least, thanks for all your hard work on this series.
Thanks especially for perservering in the face of all my annoying
niggles. :-)

Richard


The regenerated version of your patch series (excluding umips-swap,
as per above):


[-- Attachment #2: combined.diff.bz2 --]
[-- Type: application/octet-stream, Size: 163019 bytes --]

[-- Attachment #3: Type: text/plain, Size: 27 bytes --]


The changes I asked for:


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: approval.diff --]
[-- Type: text/x-diff, Size: 15355 bytes --]

Index: bfd/elfxx-mips.c
===================================================================
--- bfd/elfxx-mips.c	2011-07-24 15:06:40.000000000 +0100
+++ bfd/elfxx-mips.c	2011-07-24 15:07:48.000000000 +0100
@@ -5162,7 +5162,7 @@ mips_elf_calculate_relocation (bfd *abfd
       target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (h->root.other);
       /* If the output section is the PLT section,
          then the target is not microMIPS.  */
-      target_is_micromips_code_p = ((htab->splt != sec)
+      target_is_micromips_code_p = (htab->splt != sec
 				    && ELF_ST_IS_MICROMIPS (h->root.other));
     }
 
@@ -11910,18 +11910,9 @@ mips_elf_relax_delete_bytes (bfd *abfd,
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   isym = (Elf_Internal_Sym *) symtab_hdr->contents;
   for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
-    {
-      bfd_vma value;
-
-      if (isym->st_shndx != sec_shndx)
-	continue;
-
-      value = isym->st_value;
-      if (ELF_ST_IS_MICROMIPS (isym->st_other))
-	value &= MINUS_TWO;
-      if (value > addr)
-	isym->st_value -= count;
-    }
+    if (isym->st_shndx == sec_shndx
+	&& isym->st_value > addr)
+      isym->st_value -= count;
 
   /* Now adjust the global symbols defined in this section.  */
   symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
@@ -11932,18 +11923,19 @@ mips_elf_relax_delete_bytes (bfd *abfd,
   for (; sym_hashes < end_hashes; sym_hashes++)
     {
       struct elf_link_hash_entry *sym_hash = *sym_hashes;
-      bfd_vma value;
-
-      if ((sym_hash->root.type != bfd_link_hash_defined
-	   && sym_hash->root.type != bfd_link_hash_defweak)
-	  || sym_hash->root.u.def.section != sec)
-	continue;
 
-      value = sym_hash->root.u.def.value;
-      if (ELF_ST_IS_MICROMIPS (sym_hash->other))
-	value &= MINUS_TWO;
-      if (value > addr)
-	sym_hash->root.u.def.value -= count;
+      if ((sym_hash->root.type == bfd_link_hash_defined
+	   || sym_hash->root.type == bfd_link_hash_defweak)
+	  && sym_hash->root.u.def.section == sec)
+	{
+	  bfd_vma value;
+
+	  value = sym_hash->root.u.def.value;
+	  if (ELF_ST_IS_MICROMIPS (sym_hash->other))
+	    value &= MINUS_TWO;
+	  if (value > addr)
+	    sym_hash->root.u.def.value -= count;
+	}
     }
 
   return TRUE;
@@ -12279,6 +12271,27 @@ #define IS_BITSIZE(val, N)						\
   (((((val) & ((1ULL << (N)) - 1)) ^ (1ULL << ((N) - 1)))		\
     - (1ULL << ((N) - 1))) == (val))
 
+/* See if relocations [INTERNAL_RELOCS, IRELEND) confirm that there
+   is a 4-byte branch at offset OFFSET.  */
+
+static bfd_boolean
+check_4byte_branch (Elf_Internal_Rela *internal_relocs,
+		    Elf_Internal_Rela *irelend, bfd_vma offset)
+{
+  Elf_Internal_Rela *irel;
+  unsigned long r_type;
+
+  for (irel = internal_relocs; irel < irelend; irel++)
+    if (irel->r_offset == offset)
+      {
+	r_type = ELF32_R_TYPE (irel->r_info);
+	if (r_type == R_MICROMIPS_26_S1
+	    || r_type == R_MICROMIPS_PC16_S1
+	    || r_type == R_MICROMIPS_JALR)
+	  return TRUE;
+      }
+  return FALSE;
+}
 \f
 bfd_boolean
 _bfd_mips_elf_relax_section (bfd *abfd, asection *sec,
@@ -12439,12 +12452,8 @@ _bfd_mips_elf_relax_section (bfd *abfd,
          out the offset).  */
       if (r_type == R_MICROMIPS_HI16 && MATCH (opcode, lui_insn))
 	{
-	  Elf_Internal_Rela *ibrrel;
-	  bfd_boolean brc = FALSE;
-	  unsigned int br_r_type;
 	  unsigned long nextopc;
 	  unsigned long reg;
-	  int bdsize = -1;
 	  bfd_vma offset;
 
 	  /* Give up if the previous reloc was a HI16 against this symbol
@@ -12466,58 +12475,20 @@ _bfd_mips_elf_relax_section (bfd *abfd,
 	      && ELF32_R_SYM (irel[2].r_info) == r_symndx)
 	    continue;
 
-	  /* See if there is a jump or a branch reloc preceding the
-	     LUI instruction immediately.  */
-	  for (ibrrel = internal_relocs; ibrrel < irelend; ibrrel++)
-	    {
-	      offset = irel->r_offset - ibrrel->r_offset;
-	      if (offset != 2 && offset != 4)
-		continue;
-
-	      br_r_type = ELF32_R_TYPE (ibrrel->r_info);
-	      if (offset == 2
-		  && (br_r_type == R_MICROMIPS_PC7_S1
-		      || br_r_type == R_MICROMIPS_PC10_S1
-		      || br_r_type == R_MICROMIPS_JALR))
-		break;
-	      if (offset == 4
-		  && (br_r_type == R_MICROMIPS_26_S1
-		      || br_r_type == R_MICROMIPS_PC16_S1
-		      || br_r_type == R_MICROMIPS_JALR))
-		{
-		  bfd_byte *ptr = contents + ibrrel->r_offset;
-		  unsigned long bropc;
-
-		  bropc   = bfd_get_16 (abfd, ptr);
-		  bropc <<= 16;
-		  bropc  |= bfd_get_16 (abfd, ptr + 2);
-		  /* Compact branches are OK.  */
-		  if (find_match (opcode, bzc_insns_32) >= 0)
-		    brc = TRUE;
-		  break;
-		}
-	    }
-	  /* A delay slot was found, give up, sigh...  */
-	  if (!brc && ibrrel < irelend)
+	  /* See if the LUI instruction *might* be in a branch delay slot.  */
+	  if (irel->r_offset >= 2
+	      && check_br16_dslot (abfd, contents + irel->r_offset - 2) > 0
+	      && !(irel->r_offset >= 4
+		   /* If the instruction is actually a 4-byte branch,
+		      the value of check_br16_dslot doesn't matter.
+		      We should use check_br32_dslot to check whether
+		      the branch has a delay slot.  */
+		   && check_4byte_branch (internal_relocs, irelend,
+					  irel->r_offset - 4)))
+	    continue;
+	  if (irel->r_offset >= 4
+	      && check_br32_dslot (abfd, contents + irel->r_offset - 4) > 0)
 	    continue;
-
-	  /* Otherwise see if the LUI instruction *might* be in a
-	     branch delay slot.  */
-	  if (!brc)
-	    {
-	      bfd_byte *ptr = contents + irel->r_offset;
-
-	      if (irel->r_offset >= 2)
-		bdsize = check_br16_dslot (abfd, ptr - 2);
-	      /* A branch possibly found, give up, sigh...  */
-	      if (bdsize > 0)
-		continue;
-	      if (irel->r_offset >= 4)
-		bdsize = check_br32_dslot (abfd, ptr - 4);
-	      /* A branch possibly found, give up, sigh...  */
-	      if (bdsize > 0)
-		continue;
-	    }
 
 	  reg = OP32_SREG (opcode);
 
@@ -12545,7 +12516,8 @@ _bfd_mips_elf_relax_section (bfd *abfd,
 	  nextopc  = bfd_get_16 (abfd, contents + irel[1].r_offset    ) << 16;
 	  nextopc |= bfd_get_16 (abfd, contents + irel[1].r_offset + 2);
 
-	  /* Give up unless the same register used with both relocations.  */
+	  /* Give up unless the same register is used with both
+	     relocations.  */
 	  if (OP32_SREG (nextopc) != reg)
 	    continue;
 
Index: gas/config/tc-mips.c
===================================================================
--- gas/config/tc-mips.c	2011-07-24 15:07:45.000000000 +0100
+++ gas/config/tc-mips.c	2011-07-24 15:07:48.000000000 +0100
@@ -2150,7 +2150,7 @@ reglist_lookup (char **s, unsigned int t
   unsigned int regmask;
   unsigned int regno;
   char *s_reset = *s;
-  char *s_comma = *s;
+  char *s_end_of_list = *s;
 
   while (reg_lookup (s, types, &regno))
     {
@@ -2175,14 +2175,14 @@ reglist_lookup (char **s, unsigned int t
       regmask ^= (1 << regno) - 1;
       reglist |= regmask;
 
-      s_comma = *s;
+      s_end_of_list = *s;
       if (**s != ',')
 	break;
       (*s)++;
     }
 
   if (ok)
-    *s = s_comma;
+    *s = s_end_of_list;
   else
     *s = s_reset;
   if (reglistp)
@@ -2663,24 +2663,41 @@ micromips_reloc_p (bfd_reloc_code_real_t
 static inline bfd_boolean
 got16_reloc_p (bfd_reloc_code_real_type reloc)
 {
-  return (reloc == BFD_RELOC_MIPS_GOT16 || reloc == BFD_RELOC_MIPS16_GOT16
+  return (reloc == BFD_RELOC_MIPS_GOT16
+	  || reloc == BFD_RELOC_MIPS16_GOT16
 	  || reloc == BFD_RELOC_MICROMIPS_GOT16);
 }
 
 static inline bfd_boolean
 hi16_reloc_p (bfd_reloc_code_real_type reloc)
 {
-  return (reloc == BFD_RELOC_HI16_S || reloc == BFD_RELOC_MIPS16_HI16_S
+  return (reloc == BFD_RELOC_HI16_S
+	  || reloc == BFD_RELOC_MIPS16_HI16_S
 	  || reloc == BFD_RELOC_MICROMIPS_HI16_S);
 }
 
 static inline bfd_boolean
 lo16_reloc_p (bfd_reloc_code_real_type reloc)
 {
-  return (reloc == BFD_RELOC_LO16 || reloc == BFD_RELOC_MIPS16_LO16
+  return (reloc == BFD_RELOC_LO16
+	  || reloc == BFD_RELOC_MIPS16_LO16
 	  || reloc == BFD_RELOC_MICROMIPS_LO16);
 }
 
+static inline bfd_boolean
+jmp_reloc_p (bfd_reloc_code_real_type reloc)
+{
+  return (reloc == BFD_RELOC_MIPS_JMP
+	  || reloc == BFD_RELOC_MICROMIPS_JMP);
+}
+
+static inline bfd_boolean
+jalr_reloc_p (bfd_reloc_code_real_type reloc)
+{
+  return (reloc == BFD_RELOC_MIPS_JALR
+	  || reloc == BFD_RELOC_MICROMIPS_JALR);
+}
+
 /* Return true if the given relocation might need a matching %lo().
    This is only "might" because SVR4 R_MIPS_GOT16 relocations only
    need a matching %lo() when applied to local symbols.  */
@@ -3761,7 +3778,7 @@ can_swap_branch_p (struct mips_cl_insn *
     return FALSE;
 
   /* If the previous instruction has an incorrect size for a fixed
-     branch delay slot in the microMIPS mode, we cannot swap.  */
+     branch delay slot in microMIPS mode, we cannot swap.  */
   if (mips_opts.micromips)
     {
       pinfo2 = ip->insn_mo->pinfo;
@@ -4030,11 +4047,9 @@ append_insn (struct mips_cl_insn *ip, ex
 
 	case BFD_RELOC_MIPS_JMP:
 	  {
-	    bfd_reloc_code_real_type reloc;
 	    int shift;
 
-	    reloc = micromips_map_reloc (*reloc_type);
-	    shift = reloc == BFD_RELOC_MICROMIPS_JMP ? 1 : 2;
+	    shift = mips_opts.micromips ? 1 : 2;
 	    if ((address_expr->X_add_number & ((1 << shift) - 1)) != 0)
 	      as_bad (_("jump to misaligned address (0x%lx)"),
 		      (unsigned long) address_expr->X_add_number);
@@ -4057,11 +4072,9 @@ append_insn (struct mips_cl_insn *ip, ex
 
 	case BFD_RELOC_16_PCREL_S2:
 	  {
-	    bfd_reloc_code_real_type reloc;
 	    int shift;
 
-	    reloc = micromips_map_reloc (*reloc_type);
-	    shift = reloc == BFD_RELOC_MICROMIPS_16_PCREL_S1 ? 1 : 2;
+	    shift = mips_opts.micromips ? 1 : 2;
 	    if ((address_expr->X_add_number & ((1 << shift) - 1)) != 0)
 	      as_bad (_("branch to misaligned address (0x%lx)"),
 		      (unsigned long) address_expr->X_add_number);
@@ -4313,32 +4326,32 @@ append_insn (struct mips_cl_insn *ip, ex
 
   if (!ip->complete_p && *reloc_type < BFD_RELOC_UNUSED)
     {
-      bfd_reloc_code_real_type reloc;
+      bfd_reloc_code_real_type final_type[3];
       reloc_howto_type *howto;
       int i;
 
+      /* Perform any necessary conversion to microMIPS relocations
+	 and find out how many relocations there actually are.  */
+      for (i = 0; i < 3 && reloc_type[i] != BFD_RELOC_UNUSED; i++)
+	final_type[i] = micromips_map_reloc (reloc_type[i]);
+
       /* In a compound relocation, it is the final (outermost)
 	 operator that determines the relocated field.  */
-      for (i = 1; i < 3; i++)
-	if (reloc_type[i] == BFD_RELOC_UNUSED)
-	  break;
-
-      reloc = micromips_map_reloc (reloc_type[i - 1]);
-      howto = bfd_reloc_type_lookup (stdoutput, reloc);
+      howto = bfd_reloc_type_lookup (stdoutput, final_type[i - 1]);
       if (howto == NULL)
 	{
 	  /* To reproduce this failure try assembling gas/testsuites/
 	     gas/mips/mips16-intermix.s with a mips-ecoff targeted
 	     assembler.  */
-	  as_bad (_("Unsupported MIPS relocation number %d"), reloc);
+	  as_bad (_("Unsupported MIPS relocation number %d"),
+		  final_type[i - 1]);
 	  howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16);
 	}
 	  
       ip->fixp[0] = fix_new_exp (ip->frag, ip->where,
 				 bfd_get_reloc_size (howto),
 				 address_expr,
-				 howto->pc_relative,
-				 micromips_map_reloc (reloc_type[0]));
+				 howto->pc_relative, final_type[0]);
 
       /* Tag symbols that have a R_MIPS16_26 relocation against them.  */
       if (reloc_type[0] == BFD_RELOC_MIPS16_JMP
@@ -4352,7 +4365,6 @@ append_insn (struct mips_cl_insn *ip, ex
 	  && (reloc_type[0] == BFD_RELOC_16
 	      || reloc_type[0] == BFD_RELOC_32
 	      || reloc_type[0] == BFD_RELOC_MIPS_JMP
-	      || reloc_type[0] == BFD_RELOC_MICROMIPS_JMP
 	      || reloc_type[0] == BFD_RELOC_GPREL16
 	      || reloc_type[0] == BFD_RELOC_MIPS_LITERAL
 	      || reloc_type[0] == BFD_RELOC_GPREL32
@@ -4401,8 +4413,8 @@ append_insn (struct mips_cl_insn *ip, ex
 	if (reloc_type[i] != BFD_RELOC_UNUSED)
 	  {
 	    ip->fixp[i] = fix_new (ip->frag, ip->where,
-				   ip->fixp[0]->fx_size, NULL, 0, FALSE,
-				   micromips_map_reloc (reloc_type[i]));
+				   ip->fixp[0]->fx_size, NULL, 0,
+				   FALSE, final_type[i]);
 
 	    /* Use fx_tcbit to mark compound relocs.  */
 	    ip->fixp[0]->fx_tcbit = 1;
@@ -17323,7 +17335,7 @@ md_estimate_size_before_relax (fragS *fr
 	length = relaxed_micromips_16bit_branch_length (fragp, segtype, FALSE);
       if (length == 4 && RELAX_MICROMIPS_RELAX32 (fragp->fr_subtype))
 	length = relaxed_micromips_32bit_branch_length (fragp, segtype, FALSE);
-      fragp->fr_var= length;
+      fragp->fr_var = length;
 
       return length;
     }
@@ -17385,9 +17397,7 @@ mips_fix_adjustable (fixS *fixp)
      the in-place relocatable field if recalculated against the start
      address of the symbol's containing section.  */
   if (HAVE_IN_PLACE_ADDENDS
-      && (fixp->fx_pcrel
-	  || fixp->fx_r_type == BFD_RELOC_MIPS_JALR
-	  || fixp->fx_r_type == BFD_RELOC_MICROMIPS_JALR))
+      && (fixp->fx_pcrel || jalr_reloc_p (fixp->fx_r_type)))
     return 0;
 
 #ifdef OBJ_ELF
@@ -17439,8 +17449,7 @@ mips_fix_adjustable (fixS *fixp)
 	  || *symbol_get_tc (fixp->fx_addsy)
 	  || (HAVE_IN_PLACE_ADDENDS
 	      && ELF_ST_IS_MICROMIPS (S_GET_OTHER (fixp->fx_addsy))
-	      && (fixp->fx_r_type == BFD_RELOC_MIPS_JMP
-		  || fixp->fx_r_type == BFD_RELOC_MICROMIPS_JMP))))
+	      && jmp_reloc_p (fixp->fx_r_type))))
     return 0;
 #endif
 
@@ -17781,12 +17790,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU
       bfd_boolean compact = RELAX_MICROMIPS_COMPACT (fragp->fr_subtype);
       bfd_boolean al = RELAX_MICROMIPS_LINK (fragp->fr_subtype);
       int type = RELAX_MICROMIPS_TYPE (fragp->fr_subtype);
-
-      /* Default to the long-delay-slot versions.  */
-      unsigned long jal = 0xf4000000;			/* jal  */
-      unsigned long jalr = 0x45c0;			/* jalr  */
-
-      unsigned long jr = compact ? 0x45a0 : 0x4580;	/* jr/c  */
+      unsigned long jal, jalr, jr;
 
       unsigned long insn;
       expressionS exp;
@@ -17798,7 +17802,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU
 
       fragp->fr_fix += fragp->fr_var;
 
-      /* Handle 16-bit branches that fit or forced to fit.  */
+      /* Handle 16-bit branches that fit or are forced to fit.  */
       if (type != 0 && !RELAX_MICROMIPS_TOOFAR16 (fragp->fr_subtype))
 	{
 	  /* We generate a fixup instead of applying it right now,
@@ -17906,6 +17910,12 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU
 	  jal = 0x74000000;				/* jals  */
 	  jalr = 0x45e0;				/* jalrs  */
 	}
+      else
+	{
+	  jal = 0xf4000000;				/* jal  */
+	  jalr = 0x45c0;				/* jalr  */
+	}
+      jr = compact ? 0x45a0 : 0x4580;			/* jr/c  */
 
       if (!RELAX_MICROMIPS_UNCOND (fragp->fr_subtype))
 	{
Index: include/opcode/mips.h
===================================================================
--- include/opcode/mips.h	2011-07-24 15:06:40.000000000 +0100
+++ include/opcode/mips.h	2011-07-24 15:07:48.000000000 +0100
@@ -1330,7 +1330,7 @@ #define MIPS16_INSN_COND_BRANCH		    0x0
 extern const int bfd_mips16_num_opcodes;
 
 /* These are the bitmasks and shift counts used for the different
-   fields in the instruction formats.  Other than OP, no masks are
+   fields in the instruction formats.  Other than MAJOR, no masks are
    provided for the fixed portions of an instruction, since they are
    not needed.  */
 

[-- Attachment #5: Type: text/plain, Size: 43 bytes --]


The other stuff I noticed while testing:


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #6: extra.diff --]
[-- Type: text/x-diff, Size: 16480 bytes --]

Index: gas/config/tc-mips.c
===================================================================
--- gas/config/tc-mips.c	2011-07-24 15:07:48.000000000 +0100
+++ gas/config/tc-mips.c	2011-07-24 15:07:51.000000000 +0100
@@ -203,9 +203,6 @@ static bfd_boolean mips_in_shared = TRUE
    pseudo-op.  We use a struct so that .set push and .set pop are more
    reliable.  */
 
-/* Whether or not we emit branch likely macros.  */
-static bfd_boolean emit_branch_likely_macro = FALSE;
-
 struct mips_set_options
 {
   /* MIPS ISA (Instruction Set Architecture) level.  This is set to -1
@@ -644,7 +641,7 @@ static struct hash_control *op_hash = NU
 /* The opcode hash table we use for the mips16.  */
 static struct hash_control *mips16_op_hash = NULL;
 
-/* The opcode hash table we use for the micromips.  */
+/* The opcode hash table we use for the microMIPS ASE.  */
 static struct hash_control *micromips_op_hash = NULL;
 
 /* This array holds the chars that always start a comment.  If the
@@ -745,7 +742,7 @@ #define MAX_NOPS 4
 #define NOP_INSN (mips_opts.mips16 ? &mips16_nop_insn \
 		  : (mips_opts.micromips ? &micromips_nop16_insn : &nop_insn))
 
-/* The number of bytes NOP takes for the current mode.  */
+/* The size of NOP_INSN in bytes.  */
 #define NOP_INSN_SIZE (HAVE_CODE_COMPRESSION ? 2 : 4)
 
 /* If this is set, it points to a frag holding nop instructions which
@@ -1251,6 +1248,9 @@ #define MIPS16_EXTRACT_OPERAND(FIELD, IN
 		MIPS16OP_MASK_##FIELD, \
 		MIPS16OP_SH_##FIELD)
 \f
+/* Whether or not we are emitting a branch-likely macro.  */
+static bfd_boolean emit_branch_likely_macro = FALSE;
+
 /* Global variables used when generating relaxable macros.  See the
    comment above RELAX_ENCODE for more details about how relaxation
    is used.  */
@@ -1292,12 +1292,14 @@ #define MIPS16_EXTRACT_OPERAND(FIELD, IN
      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.
+
      Set to zero if we haven't yet seen the first instruction.  */
   unsigned int first_insn_sizes[2];
 
   /* For relaxable macros, insns[0] is the number of instructions for the
      first alternative and insns[1] is the number of instructions for the
      second alternative.
+
      For non-relaxable macros, both elements give the number of
      instructions for the macro.  */
   unsigned int insns[2];
@@ -1542,10 +1544,11 @@ mips_clear_insn_labels (void)
     }
 }
 
+/* Mark instruction labels in MIPS16/microMIPS mode.  */
+
 static inline void
 mips_mark_labels (void)
 {
-  /* Mark instruction labels in MIPS16/microMIPS mode.  */
   if (HAVE_CODE_COMPRESSION)
     mips_compressed_mark_labels ();
 }
@@ -2071,7 +2074,6 @@ static const struct regname reg_names_n3
   {0, 0}
 };
 
-
 /* Check if S points at a valid register specifier according to TYPES.
    If so, then return 1, advance S to consume the specifier and store
    the register's number in REGNOP, otherwise return 0.  */
@@ -3973,7 +3975,8 @@ micromips_map_reloc (bfd_reloc_code_real
 
 /* Output an instruction.  IP is the instruction information.
    ADDRESS_EXPR is an operand of the instruction to be used with
-   RELOC_TYPE.  */
+   RELOC_TYPE.  EXPANSIONP is true if the instruction is part of
+   a macro expansion.  */
 
 static void
 append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
@@ -4209,12 +4212,12 @@ append_insn (struct mips_cl_insn *ip, ex
 	        16-bit/32-bit instructions.  */
 	     && !forced_insn_length);
 
-  if (address_expr
+  if (!HAVE_CODE_COMPRESSION
+      && address_expr
       && relax32
       && *reloc_type == BFD_RELOC_16_PCREL_S2
       && (pinfo & INSN_UNCOND_BRANCH_DELAY || pinfo & INSN_COND_BRANCH_DELAY
-	  || pinfo & INSN_COND_BRANCH_LIKELY)
-      && !HAVE_CODE_COMPRESSION)
+	  || pinfo & INSN_COND_BRANCH_LIKELY))
     {
       relaxed_branch = TRUE;
       add_relaxed_insn (ip, (relaxed_branch_length
@@ -4232,14 +4235,14 @@ append_insn (struct mips_cl_insn *ip, ex
 			address_expr->X_add_number);
       *reloc_type = BFD_RELOC_UNUSED;
     }
-  else if (address_expr
+  else if (mips_opts.micromips
+	   && address_expr
 	   && ((relax32 && *reloc_type == BFD_RELOC_16_PCREL_S2)
 	       || *reloc_type > BFD_RELOC_UNUSED)
 	   && (pinfo & INSN_UNCOND_BRANCH_DELAY
 	       || pinfo & INSN_COND_BRANCH_DELAY
 	       || (pinfo2 & ~INSN2_ALIAS) == INSN2_UNCOND_BRANCH
-	       || pinfo2 & INSN2_COND_BRANCH)
-	   && mips_opts.micromips)
+	       || pinfo2 & INSN2_COND_BRANCH))
     {
       bfd_boolean relax16 = *reloc_type > BFD_RELOC_UNUSED;
       int type = relax16 ? *reloc_type - BFD_RELOC_UNUSED : 0;
@@ -4348,6 +4351,7 @@ append_insn (struct mips_cl_insn *ip, ex
 	  howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16);
 	}
 	  
+      howto = bfd_reloc_type_lookup (stdoutput, final_type[0]);
       ip->fixp[0] = fix_new_exp (ip->frag, ip->where,
 				 bfd_get_reloc_size (howto),
 				 address_expr,
@@ -4503,12 +4507,10 @@ append_insn (struct mips_cl_insn *ip, ex
 	  && (history[0].insn_mo->pinfo & MIPS16_INSN_UNCOND_BRANCH)))
     mips_no_prev_insn ();
 
-  /* For branch likely macro, we need to emit a label at the end.  */
+  /* We need to emit a label at the end of branch-likely macros.  */
   if (emit_branch_likely_macro)
     {
       emit_branch_likely_macro = FALSE;
-
-      /* We need to generate a label.  */
       micromips_add_label ();
     }
 
@@ -4723,8 +4725,7 @@ macro_end (void)
       relax_substateT s;
       const char *msg;
 
-      s = (subtype
-	   & (RELAX_SECOND_LONGER | RELAX_NOMACRO | RELAX_DELAY_SLOT));
+      s = subtype & (RELAX_SECOND_LONGER | RELAX_NOMACRO | RELAX_DELAY_SLOT);
       msg = macro_warning (s);
       if (msg != NULL)
 	as_warn ("%s", msg);
@@ -5259,7 +5260,7 @@ macro_build_jalr (expressionS *ep, int c
   static const bfd_reloc_code_real_type jalr_relocs[2]
     = { BFD_RELOC_MIPS_JALR, BFD_RELOC_MICROMIPS_JALR };
   bfd_reloc_code_real_type jalr_reloc = jalr_relocs[mips_opts.micromips];
-  const char *jalr = mips_opts.noreorder && !cprestore ? "jalr" : "jalrs";
+  const char *jalr;
   char *f = NULL;
 
   if (MIPS_JALR_HINT_P (ep))
@@ -5269,10 +5270,14 @@ macro_build_jalr (expressionS *ep, int c
     }
   if (!mips_opts.micromips)
     macro_build (NULL, "jalr", "d,s", RA, PIC_CALL_REG);
-  else if (MIPS_JALR_HINT_P (ep))
-    macro_build (NULL, jalr, "t,s", RA, PIC_CALL_REG);
   else
-    macro_build (NULL, jalr, "mj", PIC_CALL_REG);
+    {
+      jalr = mips_opts.noreorder && !cprestore ? "jalr" : "jalrs";
+      if (MIPS_JALR_HINT_P (ep))
+	macro_build (NULL, jalr, "t,s", RA, PIC_CALL_REG);
+      else
+	macro_build (NULL, jalr, "mj", PIC_CALL_REG);
+    }
   if (MIPS_JALR_HINT_P (ep))
     fix_new_exp (frag_now, f - frag_now->fr_literal, 4, ep, FALSE, jalr_reloc);
 }
@@ -6031,23 +6036,28 @@ add_got_offset_hilo (int dest, expressio
 /* Emit a sequence of instructions to emulate a branch likely operation.
    BR is an ordinary branch corresponding to one to be emulated.  BRNEG
    is its complementing branch with the original condition negated.
-   CALL is set if the original branch specified the link operation.  EP,
-   FMT, SREG and TREG specify the usual macro_build() parameters.
+   CALL is set if the original branch specified the link operation.
+   EP, FMT, SREG and TREG specify the usual macro_build() parameters.
 
    Code like this is produced in the noreorder mode:
+
 	BRNEG	<args>, 1f
 	 nop
 	b	<sym>
 	 delay slot (executed only if branch taken)
     1:
-   or:
+
+   or, if CALL is set:
+
 	BRNEG	<args>, 1f
 	 nop
 	bal	<sym>
 	 delay slot (executed only if branch taken)
     1:
-   if CALL is set.  In the reorder mode the delay slot would be filled
-   with a nop anyway, so code produced is simply:
+
+   In the reorder mode the delay slot would be filled with a nop anyway,
+   so code produced is simply:
+
 	BR	<args>, <sym>
 	 nop
 
Index: gas/testsuite/gas/mips/dli.s
===================================================================
--- gas/testsuite/gas/mips/dli.s	2011-07-24 15:01:44.000000000 +0100
+++ gas/testsuite/gas/mips/dli.s	2011-07-24 15:07:51.000000000 +0100
@@ -62,6 +62,4 @@ foo:
 	dli	$4,0x003ffc03ffffc000
 
 # Round to a 16 byte boundary, for ease in testing multiple targets.
-	nop
-	nop
-	nop
+	.p2align 4
Index: gas/testsuite/gas/mips/micromips-trap.d
===================================================================
--- gas/testsuite/gas/mips/micromips-trap.d	2011-07-24 15:05:46.000000000 +0100
+++ gas/testsuite/gas/mips/micromips-trap.d	2011-07-24 15:07:52.000000000 +0100
@@ -1,6 +1,6 @@
 #objdump: -dr --show-raw-insn
 #name: microMIPS for MIPS32r2 (w/traps)
-#as: -mips32r2 -32 -trap -mfp64
+#as: -mips32r2 -32 -trap -mfp64 -EB
 #stderr: micromips.l
 #source: micromips.s
 
Index: gas/testsuite/gas/mips/micromips.d
===================================================================
--- gas/testsuite/gas/mips/micromips.d	2011-07-24 15:05:46.000000000 +0100
+++ gas/testsuite/gas/mips/micromips.d	2011-07-24 15:07:52.000000000 +0100
@@ -1,6 +1,6 @@
 #objdump: -dr --show-raw-insn
 #name: microMIPS for MIPS32r2
-#as: -mips32r2 -32 -mfp64
+#as: -mips32r2 -32 -mfp64 -EB
 #stderr: micromips.l
 #source: micromips.s
 
Index: gas/testsuite/gas/mips/micromips@dli.d
===================================================================
--- gas/testsuite/gas/mips/micromips@dli.d	2011-07-24 15:05:46.000000000 +0100
+++ gas/testsuite/gas/mips/micromips@dli.d	2011-07-24 15:07:51.000000000 +0100
@@ -113,7 +113,4 @@ Disassembly of section \.text:
 [0-9a-f]+ <[^>]*> 5084 ffff 	ori	a0,a0,0xffff
 [0-9a-f]+ <[^>]*> 5884 8000 	dsll	a0,a0,0x10
 [0-9a-f]+ <[^>]*> 5084 c000 	ori	a0,a0,0xc000
-[0-9a-f]+ <[^>]*> 0c00      	nop
-[0-9a-f]+ <[^>]*> 0c00      	nop
-[0-9a-f]+ <[^>]*> 0c00      	nop
-[0-9a-f]+ <[^>]*> 0c00      	nop
+	\.\.\.
Index: gas/testsuite/gas/mips/micromips@elfel-rel2.d
===================================================================
--- /dev/null	2011-07-24 10:34:17.994719526 +0100
+++ gas/testsuite/gas/mips/micromips@elfel-rel2.d	2011-07-24 15:07:52.000000000 +0100
@@ -0,0 +1,28 @@
+#objdump: -sr -j .text
+#name: MIPS ELF reloc 2
+#source: elf-rel2.s
+#as: -mabi=o64
+
+# Test the GPREL and LITERAL generation (microMIPS).
+# FIXME: really this should check that the contents of .sdata, .lit4,
+# and .lit8 are correct too.
+
+.*: +file format .*mips.*
+
+RELOCATION RECORDS FOR \[\.text\]:
+OFFSET [ ]+ TYPE              VALUE 
+0+0000000 R_MICROMIPS_LITERAL  \.lit8
+0+0000004 R_MICROMIPS_LITERAL  \.lit8
+0+0000008 R_MICROMIPS_LITERAL  \.lit8
+0+000000c R_MICROMIPS_LITERAL  \.lit4
+0+0000010 R_MICROMIPS_LITERAL  \.lit4
+0+0000014 R_MICROMIPS_LITERAL  \.lit4
+0+0000018 R_MICROMIPS_GPREL16  \.sdata
+0+000001c R_MICROMIPS_GPREL16  \.sdata
+0+0000020 R_MICROMIPS_GPREL16  \.sdata
+
+
+Contents of section \.text:
+ 0000 5cbc0000 5cbc0800 5cbc1000 5c9c0000  .*
+ 0010 5c9c0400 5c9c0800 5cfc0000 5cfc0400  .*
+ 0020 5cfc0800 .*
Index: gas/testsuite/gas/mips/micromips@mips4-branch-likely.d
===================================================================
--- gas/testsuite/gas/mips/micromips@mips4-branch-likely.d	2011-07-24 15:05:46.000000000 +0100
+++ gas/testsuite/gas/mips/micromips@mips4-branch-likely.d	2011-07-24 15:07:51.000000000 +0100
@@ -1,6 +1,7 @@
 #objdump: -dr --prefix-addresses --show-raw-insn
 #name: MIPS mips4 branch-likely instructions
 #source: mips4-branch-likely.s
+#as: -32
 
 # Test mips4 branch-likely instructions (microMIPS).
 
Index: gas/testsuite/gas/mips/micromips@mips4-fp.d
===================================================================
--- gas/testsuite/gas/mips/micromips@mips4-fp.d	2011-07-24 15:05:46.000000000 +0100
+++ gas/testsuite/gas/mips/micromips@mips4-fp.d	2011-07-24 15:07:51.000000000 +0100
@@ -1,6 +1,7 @@
 #objdump: -dr --prefix-addresses --show-raw-insn
 #name: MIPS mips4 fp
 #source: mips4-fp.s
+#as: -32
 
 # Test mips4 fp instructions (microMIPS).
 
Index: gas/testsuite/gas/mips/mips.exp
===================================================================
--- gas/testsuite/gas/mips/mips.exp	2011-07-24 15:06:40.000000000 +0100
+++ gas/testsuite/gas/mips/mips.exp	2011-07-24 15:07:51.000000000 +0100
@@ -489,21 +489,31 @@ if { [istarget mips*-*-vxworks*] } {
     run_dump_test "eret-1"
     run_dump_test "eret-2"
     run_dump_test "eret-3"
-    run_dump_test_arches "24k-branch-delay-1" [mips_arch_list_matching mips1]
+    run_dump_test_arches "24k-branch-delay-1" \
+	[mips_arch_list_matching mips1 !micromips]
     run_dump_test_arches "24k-triple-stores-1" \
-				    [mips_arch_list_matching mips32r2 !octeon]
-    run_dump_test_arches "24k-triple-stores-2" [mips_arch_list_matching mips2]
-    run_dump_test_arches "24k-triple-stores-3" [mips_arch_list_matching mips3]
-    run_dump_test_arches "24k-triple-stores-4" [mips_arch_list_matching mips2]
-    run_dump_test_arches "24k-triple-stores-5" [mips_arch_list_matching mips1]
-    run_dump_test_arches "24k-triple-stores-6" [mips_arch_list_matching mips2]
-    run_dump_test_arches "24k-triple-stores-7" [mips_arch_list_matching mips2]
-    run_dump_test_arches "24k-triple-stores-8" [mips_arch_list_matching mips1]
-    run_dump_test_arches "24k-triple-stores-9" [mips_arch_list_matching mips1]
-    run_dump_test_arches "24k-triple-stores-10" [mips_arch_list_matching mips1]
+	[mips_arch_list_matching mips32r2 !octeon !micromips]
+    run_dump_test_arches "24k-triple-stores-2" \
+	[mips_arch_list_matching mips2 !micromips]
+    run_dump_test_arches "24k-triple-stores-3" \
+	[mips_arch_list_matching mips3 !micromips]
+    run_dump_test_arches "24k-triple-stores-4" \
+	[mips_arch_list_matching mips2 !micromips]
+    run_dump_test_arches "24k-triple-stores-5" \
+	[mips_arch_list_matching mips1 !micromips]
+    run_dump_test_arches "24k-triple-stores-6" \
+	[mips_arch_list_matching mips2 !micromips]
+    run_dump_test_arches "24k-triple-stores-7" \
+	[mips_arch_list_matching mips2 !micromips]
+    run_dump_test_arches "24k-triple-stores-8" \
+	[mips_arch_list_matching mips1 !micromips]
+    run_dump_test_arches "24k-triple-stores-9" \
+	[mips_arch_list_matching mips1 !micromips]
+    run_dump_test_arches "24k-triple-stores-10" \
+	[mips_arch_list_matching mips1 !micromips]
     if $elf {
 	run_dump_test_arches "24k-triple-stores-11" \
-	    [mips_arch_list_matching mips1]
+	    [mips_arch_list_matching mips1 !micromips]
     }
 
     if $elf {
Index: gas/testsuite/gas/mips/mipsel16-e.d
===================================================================
--- gas/testsuite/gas/mips/mipsel16-e.d	2011-07-24 15:01:44.000000000 +0100
+++ gas/testsuite/gas/mips/mipsel16-e.d	2011-07-24 15:07:52.000000000 +0100
@@ -1,4 +1,4 @@
-#objdump: -rst -mips16
+#objdump: -rst --special-syms -mips16
 #name: MIPS16 reloc
 #as: -32 -mips16
 #source: mips16-e.s
Index: gas/testsuite/gas/mips/tmipsel16-e.d
===================================================================
--- gas/testsuite/gas/mips/tmipsel16-e.d	2011-07-24 15:01:44.000000000 +0100
+++ gas/testsuite/gas/mips/tmipsel16-e.d	2011-07-24 15:07:52.000000000 +0100
@@ -1,4 +1,4 @@
-#objdump: -rst -mips16
+#objdump: -rst --special-syms -mips16
 #name: MIPS16 reloc
 #as: -32 -mips16
 #source: mips16-e.s
Index: ld/testsuite/ld-mips-elf/mips-elf.exp
===================================================================
--- ld/testsuite/ld-mips-elf/mips-elf.exp	2011-07-24 15:05:46.000000000 +0100
+++ ld/testsuite/ld-mips-elf/mips-elf.exp	2011-07-24 15:07:51.000000000 +0100
@@ -129,19 +129,19 @@ run_dump_test "jalx-1"
 if { $linux_gnu } {
     run_ld_link_tests [list \
 	[list "Dummy shared library for JALX test 2" \
-	      "-shared -nostdlib" \
+	      "-shared -nostdlib -melf32btsmip" \
 	      "-G0 -EB -mmicromips -no-mdebug -mabi=32 -march=mips32r2 -KPIC" \
 	      { jalx-2-printf.s } \
 	      {} \
 	      "libjalx-2.so"] \
 	[list "Dummy external function for JALX test 2" \
-	      "-r" \
+	      "-r -melf32btsmip" \
 	      "-G0 -EB -no-mdebug -mabi=32 -march=mips32r2 -mno-shared -call_nonpic" \
 	      { jalx-2-ex.s } \
 	      {} \
 	      "jalx-2-ex.o.r"] \
 	[list "MIPS JALX test 2" \
-	      "-nostdlib -T jalx-2.ld tmpdir/libjalx-2.so tmpdir/jalx-2-ex.o.r" \
+	      "-nostdlib -T jalx-2.ld tmpdir/libjalx-2.so tmpdir/jalx-2-ex.o.r -melf32btsmip" \
 	      "-G0 -EB -mmicromips -no-mdebug -mabi=32 -march=mips32r2 -mno-shared -call_nonpic" \
 	      { jalx-2-main.s } \
 	      { { objdump -d jalx-2.dd } } \

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2011-07-25  7:49                 ` Richard Sandiford
@ 2011-07-26  2:01                   ` Maciej W. Rozycki
  2011-07-29  0:58                     ` Maciej W. Rozycki
  0 siblings, 1 reply; 41+ messages in thread
From: Maciej W. Rozycki @ 2011-07-26  2:01 UTC (permalink / raw)
  To: Richard Sandiford
  Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
	Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers,
	Nathan Froyd

On Sun, 24 Jul 2011, Richard Sandiford wrote:

> Continuing this thread from March:
> 
> Richard Sandiford <rdsandiford@googlemail.com> writes:
> > "Maciej W. Rozycki" <macro@codesourcery.com> writes:
> >>  As it has turned out in the course of sorting out some earlier concerns 
> >> the microMIPS change needs a couple of updates.  For your reference I'm 
> >> sending the current version of the original patch as it had to be 
> >> regenerated.  On top of this I'm sending the following updates:
> >
> > Everything except binutils-gas-umips-swap.diff is OK (as one commit,
> > like you say), with the changes below.
> 
> It seemed a shame to get to the point of an approved version and not
> actually commit it.  I've now updated and regenerated the patch series,
> made the changes from this approval, and applied a few other things I
> noticed.  I've attached the three patches separately.

 Ouch, that'll cause me a lot of work to resolve merge conflicts.  I have 
updated all the patches independently before I went on holiday last week, 
so that's duplicated work too.  Plus there's some stuff accumulated 
earlier on.

> Tested on 
> 
>   mips64-elf mips64el-unknown-kfreebsd-gnu mips64-linux-gnu
>   mips64octeon-linux-gnu mips64-unknown-kfreebsd-gnu
>   mipsel-unknown-kfreebsd-gnu mipsisa32el-linux-gnu mipsisa64-elf
>   mips-linux-gnu mips-unknown-kfreebsd-gnu mips-wrs-vxworks
> 
> Applied to trunk along with:
> 
>   http://sourceware.org/ml/binutils/2010-12/msg00399.html
>   http://sourceware.org/ml/binutils/2011-02/msg00318.html

 My understanding has been you didn't consider the latter a complete 
change (and frankly I did wholeheartedly agree).

> Maciej: I regenerated and updated each of your patches separately,
> so if you'd like a copy of those individual patches, I can send them
> privately.

 Yes, please -- that'll save me a lot of hassle with conflict resolution, 
though I fear that'll be painful anyway. :(

> I went on to say:
> 
> > If you don't agree with some of the requested changes, let me know.
> 
> and I gather from an off-list discussion a couple of months ago that
> there were indeed some things that you didn't like.  But I think it'd
> be easier to deal with them as follow-ups.  Please feel free to send
> patches against trunk.  Or, if you tell me what it is you disagree with,
> I can try to fix it myself.

 I guess I'll just send off the e-mail I had been writing but never 
actually completed.  My current state of the changes includes all my 
updates that reflect the points made, but now I'll have to regenerate 
them, possibly by reverting yours, applying mine on top and figuring out 
what differences to the original remain.  Oh well...

> I'm sure there are things that we've both missed, but again,
> we can deal with them as follow-ups.

 There's a whole lot of important linker relaxation fixes that I reckon 
were not included in the original series plus several bug fixes.

> Last, but not least, thanks for all your hard work on this series.
> Thanks especially for perservering in the face of all my annoying
> niggles. :-)

 You are welcome.

  Maciej

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2011-02-26 11:36             ` Richard Sandiford
@ 2011-07-26 14:00               ` Maciej W. Rozycki
  0 siblings, 0 replies; 41+ messages in thread
From: Maciej W. Rozycki @ 2011-07-26 14:00 UTC (permalink / raw)
  To: Richard Sandiford
  Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
	Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers

Hi Richard,

> Thanks for the updates.  I'll try to go through the patches in the next
> couple of weeks (maybe later this weekend).

 I've been distracted for a while, but got back to this effort again.  
Here's another update, combining your two replies.  Thanks for your 
ongoing review.

> >> > +/* 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?
> 
> Oh no, it wasn't any sense of burden that bothered me.  It was more
> the talk of "the microMIPS processor".  "The MIPS16 processor" made
> sense when the support was first added, but plain "microMIPS" makes
> more sense here.  (Or, reading further on, I suppose you won't agree.
> Something other than "processor" though, if you want to treat
> "microMIPS" as an adjective.)
> 
> I just thought that, if this was dead code, we might as well just
> remove it rather than quibble about wording.  Given what you say about
> microMIPS-only processors being possible though, please just change the
> comment instead.

 "Return true if the given CPU supports the microMIPS ASE." it is then.

> >> > +#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?
> 
> Nope :-)

 With a sudden insight I realised this is a workaround for the lack of 
MIPS16 branch relocations.  As no actual relocation can be encoded in 
offset_expr, relaxation is used unconditionally instead and the definition 
of the relocatable field carried through as a transformed argument code.

> > 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.
> 
> But that's true of all fixups, and should already be handled correctly.
> 
> E.g. if you had microMIPS code embedded in a larger MIPS function, you
> might have normal MIPS branches that cross relaxable microMIPS instructions.
> The same consideration would apply then, even if branch relaxation
> wasn't enabled.

 Given the MIPS16 justification above, I have removed this extra bit from 
type encoding and modified code to emit forced 16-bit branches straight 
away.  No regressions in the test suite.

> >> > +/* 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.
> 
> As you say, the MIPS16 comment is:
> 
> /* 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.
> 
> OP in this case refers to the first field definition:
> 
> #define MIPS16OP_MASK_OP	0x1f
> #define MIPS16OP_SH_OP		11
> 
> which is the opcode ("fixed portion").  There didn't seem to be
> a corresponding MASK_OP and SH_OP for microMIPS.

 I see what you mean now, I have merely truncated the comment.  I think 
the mask combinations used for the various instructions are too diverse to 
have them all listed here.  Also I've dropped MICROMIPSOP_{MASK,SH}_MAJOR 
that were unused (and were what OP would be referring to otherwise).

> >> > +/* 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.
> 
> Really?  I'd have thought they were nouns.  If you want them to be
> adjectives though, it should be "either the ...".

 Well, that comes from US trademark law I'm told -- apparently you can't 
defend a trademark that's grammatically not an adjective.  Don't ask me 
for further details (that's certainly language-specific too, for example 
I've heard of no such restriction in Polish trademark law and Polish 
trademarks are generally nouns, because the way the Polish grammar defines 
how adjectives are made from other words, typically nouns, renders them 
mostly useless for this purpose).

> >> > +  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.
> 
> Agreed, and like I say, I was willing to believe the new code was right.
> Please put in a comment along these lines.

 I have updated the comment; please see if the new version is good enough.

> >> 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.
> 
> OK, thanks, makes sense.  The ld-lib.exp change is independently OK.
> Please commit it separately.

 Thanks, split off now.

> >  As it has turned out in the course of sorting out some earlier concerns 
> > the microMIPS change needs a couple of updates.  For your reference I'm 
> > sending the current version of the original patch as it had to be 
> > regenerated.  On top of this I'm sending the following updates:
> 
> Everything except binutils-gas-umips-swap.diff is OK (as one commit,
> like you say), with the changes below.  If you don't agree with some
> of the requested changes, let me know.
> 
> I thinkb inutils-gas-umips-swap.diff should go in as a separate commit,
> and I'll review it separately.

 It certainly makes sense to me.

> > - binutils-umips-opcode-trap.diff -- a complementing microMIPS change to 
> >   the trap/no-delay slot annotation made to standard MIPS/MIPS16 code,
> 
> Nit:
> 
> -      target_is_micromips_code_p = (htab->splt != sec)
> -				    && ELF_ST_IS_MICROMIPS (h->root.other);
> +      target_is_micromips_code_p = ((htab->splt != sec)
> +				    && ELF_ST_IS_MICROMIPS (h->root.other));
> 
> should be:
> 
>       target_is_micromips_code_p = (htab->splt != sec
> 				    && ELF_ST_IS_MICROMIPS (h->root.other));

 Indeed, fixed.

> -      if (isym->st_shndx == sec_shndx
> -	  && isym->st_value > addr
> -	  && isym->st_value < toaddr)
> +      bfd_vma value;
> +
> +      if (isym->st_shndx != sec_shndx)
> +	continue;
> +
> +      value = isym->st_value;
> +      if (ELF_ST_IS_MICROMIPS (isym->st_other))
> +	value &= MINUS_TWO;
> +      if (value > addr)
>  	isym->st_value -= count;
> 
> I still don't understand why we need to mask the low bit here.
> As per the original review, aren't these symbols already even?
> Only those entered into the hash table are odd.  OK as:
> 
>       if (isym->st_shndx == sec_shndx
> 	  && isym->st_value > addr)
> 	isym->st_value -= count;
> 
> if that's correct, but please let me know if it isn't.

 I think you're right.  I hope GCC is smart enough not to read the memory 
behind the pointer twice.

> @@ -11936,12 +11933,17 @@ mips_elf_relax_delete_bytes (bfd *abfd,
>    for (; sym_hashes < end_hashes; sym_hashes++)
>      {
>        struct elf_link_hash_entry *sym_hash = *sym_hashes;
> +      bfd_vma value;
>  
> -      if ((sym_hash->root.type == bfd_link_hash_defined
> -	   || sym_hash->root.type == bfd_link_hash_defweak)
> -	  && sym_hash->root.u.def.section == sec
> -	  && sym_hash->root.u.def.value > addr
> -	  && sym_hash->root.u.def.value < toaddr)
> +      if ((sym_hash->root.type != bfd_link_hash_defined
> +	   && sym_hash->root.type != bfd_link_hash_defweak)
> +	  || sym_hash->root.u.def.section != sec)
> +	continue;
> +
> +      value = sym_hash->root.u.def.value;
> +      if (ELF_ST_IS_MICROMIPS (sym_hash->other))
> +	value &= MINUS_TWO;
> +      if (value > addr)
>  	sym_hash->root.u.def.value -= count;
>      }
> 
> Very much nit stage, but "continue" seems overkill here.  I preferred
> the original style, which doesn't have the combination of positive
> and negative tests.  OK as:
> 
>       if ((sym_hash->root.type == bfd_link_hash_defined
> 	   || sym_hash->root.type == bfd_link_hash_defweak)
> 	  && sym_hash->root.u.def.section == sec)
> 	{
> 	  bfd_vma value;
> 
> 	  value = sym_hash->root.u.def.value;
> 	  if (ELF_ST_IS_MICROMIPS (sym_hash->other))
> 	    value &= MINUS_TWO;
> 	  if (value > addr)
> 	    sym_hash->root.u.def.value -= count;
> 	}

 I don't like having too much indentation, but I won't insist.

> +	  /* See if there is a jump or a branch reloc preceding the
> +	     LUI instruction immediately.  */
> +	  for (ibrrel = internal_relocs; ibrrel < irelend; ibrrel++)
> +	    {
> +	      offset = irel->r_offset - ibrrel->r_offset;
> +	      if (offset != 2 && offset != 4)
> +		continue;
> +
> +	      br_r_type = ELF32_R_TYPE (ibrrel->r_info);
> +	      if (offset == 2
> +		  && (br_r_type == R_MICROMIPS_PC7_S1
> +		      || br_r_type == R_MICROMIPS_PC10_S1
> +		      || br_r_type == R_MICROMIPS_JALR))
> +		break;
> +	      if (offset == 4
> +		  && (br_r_type == R_MICROMIPS_26_S1
> +		      || br_r_type == R_MICROMIPS_PC16_S1
> +		      || br_r_type == R_MICROMIPS_JALR))
> +		{
> +		  bfd_byte *ptr = contents + ibrrel->r_offset;
> +		  unsigned long bropc;
> +
> +		  bropc   = bfd_get_16 (abfd, ptr);
> +		  bropc <<= 16;
> +		  bropc  |= bfd_get_16 (abfd, ptr + 2);
> +		  /* Compact branches are OK.  */
> +		  if (find_match (opcode, bzc_insns_32) >= 0)
> +		    brc = TRUE;
> +		  break;
> +		}
> +	    }
> +	  /* A delay slot was found, give up, sigh...  */
> +	  if (!brc && ibrrel < irelend)
> +	    continue;
> +
> +	  /* Otherwise see if the LUI instruction *might* be in a
> +	     branch delay slot.  */
> +	  if (!brc)
> +	    {
> +	      bfd_byte *ptr = contents + irel->r_offset;
> +
> +	      if (irel->r_offset >= 2)
> +		bdsize = check_br16_dslot (abfd, ptr - 2);
> +	      /* A branch possibly found, give up, sigh...  */
> +	      if (bdsize > 0)
> +		continue;
> +	      if (irel->r_offset >= 4)
> +		bdsize = check_br32_dslot (abfd, ptr - 4);
> +	      /* A branch possibly found, give up, sigh...  */
> +	      if (bdsize > 0)
> +		continue;
> +	    }
> 
> ISTR discussing this before, but with the new approach, it ought not to
> be necessary to check the relocations for this get-out:
> 
> 	  /* A delay slot was found, give up, sigh...  */
> 	  if (!brc && ibrrel < irelend)
> 	    continue;
> 
> because the following code ought to detect the same cases (and do
> so much more cheaply).  If you want to avoid this:
> 
> 	      if (irel->r_offset >= 2)
> 		bdsize = check_br16_dslot (abfd, ptr - 2);
> 	      /* A branch possibly found, give up, sigh...  */
> 	      if (bdsize > 0)
> 		continue;
> 
> triggering for cases where the relocs tell us that the instruction
> is actually a BRC, then I think it would be better to split the
> search out into a separate function and only use it when we would
> otherwise continue.  OK as:
> 
> /* See if relocations [INTERNAL_RELOCS, IRELEND) confirm that there
>    is a 4-byte branch at offset OFFSET.  */
> 
> static boolean
> check_4byte_branch (Elf_Internal_Rela *internal_relocs,
> 		    Elf_Internal_Rela *irelend, bfd_vma offset)
> {
>   Elf_Internal_Rela *irel;
>   unsigned long r_type;
> 
>   for (irel = internal_relocs; irel < irelend; irel++)
>     if (irel->r_offset == offset)
>       {
> 	r_type = ELF32_R_TYPE (ibrrel->r_info);
> 	if (br_r_type == R_MICROMIPS_26_S1
> 	    || br_r_type == R_MICROMIPS_PC16_S1
> 	    || br_r_type == R_MICROMIPS_JALR)
> 	  return TRUE;
>       }
>   return FALSE;
> }
> ...
> 
> 	  /* See if the LUI instruction *might* be in a branch delay slot.  */
> 	  if (irel->r_offset >= 2
> 	      && check_br16_dslot (abfd, ptr - 2) > 0
> 	      && !(irel->r_offset >= 4
> 		   /* If the instruction is actually a 4-byte branch,
> 		      the value of check_br16_dslot doesn't matter.
> 		      We should use check_br32_dslot to check whether
> 		      the branch has a delay slot.  */
> 		   && check_4byte_branch (internal_relocs, irelend,
> 					  irel->r_offset - 4)))
> 	    continue;
> 	  if (irel->r_offset >= 4
> 	      && check_br32_dslot (abfd, ptr - 4) > 0)
> 	    continue;
> 
> if that's correct (with trivial fixes to make it compile :-)),
> otherwise please let me know.

 You are right, in principle, but actually we can check for compact branch 
encodings first and only if that has succeded, then scan the relocations.  
Which is what I did in the end.

 Perhaps that's too much hassle for handling a corner case, but that's 
just a couple of lines of code.  Let me know if you'd rather I removed it 
altogether.

> Of course, this could be generalised so that if the relocations say
> we have any type of 4-byte instruction, check_br16_dslot doesn't matter,
> and vice versa.  But even if you'd like to do that, it's follow-on material.
> Let's get the current code in first.

 Yeah, let's skip it for now, and if anyone ever gets back to it, then 
they may rethink the compact branch special case too. :)

> bdsize should be dead after the changes above.

 Yes, and a couple of others.

> -	  /* Give up if not the same register used with both relocations.  */
> +	  /* Give up unless the same register used with both relocations.  */
> 
> Should be:
> 
> 	  /* Give up unless the same register is used with both relocations.  */

 OK.

> +/* Check if S points at a valid register list according to TYPES.
> +   If so, then return 1, advance S to consume the list and store
> +   the registers present on the list as a bitmask of ones in REGLISTP,
> +   otherwise return 0.  A valid list comprises a comma-separated
> +   enumeration of valid single registers and/or dash-separated
> +   contiguous register ranges as determined by their numbers.
> +
> +   As a special exception if one of s0-s7 registers is specified as
> +   the range's lower delimiter and s8 (fp) is its upper one, then no
> +   registers whose numbers place them between s7 and s8 (i.e. $24-$29)
> +   are selected; they have to be named separately if needed.  */
> +
> +static int
> +reglist_lookup (char **s, unsigned int types, unsigned int *reglistp)
> +{
> +  unsigned int reglist = 0;
> +  unsigned int lastregno;
> +  bfd_boolean ok = TRUE;
> +  unsigned int regmask;
> +  unsigned int regno;
> +  char *s_reset = *s;
> +  char *s_comma = *s;
> +
> +  while (reg_lookup (s, types, &regno))
> +    {
> +      lastregno = regno;
> +      if (**s == '-')
> +	{
> +	  (*s)++;
> +	  ok = reg_lookup (s, types, &lastregno);
> +	  if (ok && lastregno < regno)
> +	    ok = FALSE;
> +	  if (!ok)
> +	    break;
> +	}
> +
> +      if (lastregno == FP && regno >= S0 && regno <= S7)
> +	{
> +	  lastregno = S7;
> +	  reglist |= 1 << FP;
> +	}
> +      regmask = 1 << lastregno;
> +      regmask = (regmask << 1) - 1;
> +      regmask ^= (1 << regno) - 1;
> +      reglist |= regmask;
> +
> +      s_comma = *s;
> +      if (**s != ',')
> +	break;
> +      (*s)++;
> +    }
> +
> +  if (ok)
> +    *s = s_comma;
> +  else
> +    *s = s_reset;
> +  if (reglistp)
> +    *reglistp = reglist;
> +  return ok && reglist != 0;
> +}
> 
> I found s_comma a confusing name for something that often doesn't
> point to a comma.  OK as "s_end_of_reglist", otherwise let me know.

 Well, "s_comma" points to anything other than a comma for invalid syntax 
only, but I think "s_endlist" sounds better indeed.  Your proposal seems a 
bit legthy and the number of letters we have available is at most 
countable, so a bit of thrift won't hurt.

> +      /* If the previous instruction has an incorrect size for a fixed
> +         branch delay slot in the microMIPS mode, we cannot swap.  */
> 
> OK as "in microMIPS mode".
> 
> As discussed later, from the original patch:
> 
> +/* 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.  */
> 
> Just drop the "Other than OP, ".

 Yes, especially with the removal of MICROMIPSOP_{MASK,SH}_MAJOR.

> > - binutils-gas-mips-fix-adjust-reloc.diff -- a fix for relocation handling 
> >   problems discovered while fixing the issue with PC-relative relocations 
> >   discussed earlier; a summary of the changes:
> >
> >   * BFD_RELOC_MICROMIPS_JALR relocs are now explicitly excluded like their
> >     standard MIPS counterpart; this bug was covered by all microMIPS being 
> >     converted to section-relative ones,
> >
> >   * unlike MIPS16 code we don't have call stubs in the microMIPS mode and 
> >     therefore of the remaing relocs affecting microMIPS code only jump 
> >     relocations against microMIPS text symbols on REL targets are 
> >     converted to section-relative ones as the in-place relocatable field 
> >     strips out the ISA bit,
> >
> >   * therefore we don't have to tag symbols that have a microMIPS jump 
> >     relocation against them, because they're going to be handled just fine 
> >     as long as the symbol is not a microMIPS text one,
> 
> Makes sense.  OK as long as you split this:
> 
> @@ -17189,7 +17187,9 @@ mips_fix_adjustable (fixS *fixp)
> +	  || fixp->fx_r_type == BFD_RELOC_MIPS_JALR
> +	  || fixp->fx_r_type == BFD_RELOC_MICROMIPS_JALR))
> 
> into a jalr_reloc_p, which should be defined alongside the existing
> *_reloc_p functions.  Likewise:
> 
> +	      && (fixp->fx_r_type == BFD_RELOC_MIPS_JMP
> +		  || fixp->fx_r_type == BFD_RELOC_MICROMIPS_JMP))))
> 
> and jmp_reloc_p.  (I think you already use this condition elsewhere,
> so please change those too.)

 Both are used once each only, but I'm fine with such a change.  Some 
other relocs might be handled like this too.

> > - binutils-umips-relax16.diff -- the original 16-bit->32-bit->out-of-range 
> >   branch relaxation change, regenerated,
> 
> +      fragp->fr_var= length;
> 
> Missing space.
> 
> +      /* Handle 32-bit branches that fit or forced to fit.  */
> 
> "are forced to fit"

 Fixed.

>       /* Check the short-delay-slot bit.  */
>       if (al && (insn & 0x02000000) != 0)
>  	{
> 	  jal = 0x74000000;				/* jals  */
> 	  jalr = 0x45e0;				/* jalrs  */
> 	}
> 
> This is now quite far (and IMO confusingly far) from the code that sets
> the default insns.  OK if you replace:
> 
> +      unsigned long jal = 0xf4000000;			/* jal  */
> +      unsigned long jalr = 0x45c0;			/* jalr  */
> 
> with:
> 
> +      unsigned long jal, jalr;
> 
> and add:
> 
>       else
> 	{
> 	  jal = 0xf4000000;				/* jal  */
> 	  jalr = 0x45c0;				/* jalr  */
> 	}
> 
> to the condition above.
> 
> I think it'd be more consistent to set "jr" here too, but it's OK
> either way.

 So I've moved them close to their points of use instead.

> > - binutils-umips-fix-reloc.diff -- the original microMIPS relocation 
> >   handling divergence reduction change, regenerated,
> 
> +	      {
> +		bfd_reloc_code_real_type reloc;
> +		int shift;
> +
> +		reloc = micromips_map_reloc (orig_reloc);
> +		shift = reloc == BFD_RELOC_MICROMIPS_JMP ? 1 : 2;
> +		if ((address_expr->X_add_number & ((1 << shift) - 1)) != 0)
> +		  as_bad (_("jump to misaligned address (0x%lx)"),
> +			  (unsigned long) address_expr->X_add_number);
> +		ip->insn_opcode |= ((address_expr->X_add_number >> shift)
> +				    & 0x3ffffff);
> +	      }
> 
> OK if you replace:
> 
> +		reloc = micromips_map_reloc (orig_reloc);
> +		shift = reloc == BFD_RELOC_MICROMIPS_JMP ? 1 : 2;
> 
> with:
> 
> +		shift = mips_opts.micromips ? 1 : 2;
> 
> Same for BFD_RELOC_16_PCREL_S2.

 Adjusted.

> +	  reloc = micromips_map_reloc (reloc_type[i - 1]);
> +	  howto = bfd_reloc_type_lookup (stdoutput, reloc);
>  	  if (howto == NULL)
>  	    {
>  	      /* To reproduce this failure try assembling gas/testsuites/
>  		 gas/mips/mips16-intermix.s with a mips-ecoff targeted
>  		 assembler.  */
> -	      as_bad (_("Unsupported MIPS relocation number %d"), reloc_type[i -
> 1]);
> +	      as_bad (_("Unsupported MIPS relocation number %d"), reloc);
>  	      howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16);
>  	    }
> -	  
> +
> +	  reloc = micromips_map_reloc (orig_reloc);
> 
> In the usual case, this calls micromips_map_reloc twice for the same thing.
> Seems better IMO to replace:
> 
> 	  /* In a compound relocation, it is the final (outermost)
> 	     operator that determines the relocated field.  */
> 	  for (i = 1; i < 3; i++)
> 	    if (reloc_type[i] == BFD_RELOC_UNUSED)
> 	      break;
> 
> 	  howto = bfd_reloc_type_lookup (stdoutput, reloc_type[i - 1]);
> 
> with:
> 
> 	  bfd_reloc_code_real_type final_type[3];
> 
> 	  /* Perform any necessary conversion to microMIPS relocations
> 	     and find out how many relocations there actually are.  */
> 	  for (i = 0; i < 3 && reloc_type[i] != BFD_RELOC_UNUSED; i++)
> 	    final_type[i] = micromips_map_reloc (reloc_type[i]);
> 
> 	  /* In a compound relocation, it is the final (outermost)
> 	     operator that determines the relocated field.  */
> 	  howto = bfd_reloc_type_lookup (stdoutput, final_type[i - 1]);
> 
> Then use final_type instead of reloc_type.  OK with that change,
> otherwise please let me know.

 Done.

 I'm waiting for the patches you promised and will work on regenerating
changes described above against current trunk.

  Maciej

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2011-07-26  2:01                   ` Maciej W. Rozycki
@ 2011-07-29  0:58                     ` Maciej W. Rozycki
  2011-07-29 11:30                       ` Richard Sandiford
  0 siblings, 1 reply; 41+ messages in thread
From: Maciej W. Rozycki @ 2011-07-29  0:58 UTC (permalink / raw)
  To: Richard Sandiford
  Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
	Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers

Hi Richard,

On Tue, 26 Jul 2011, Maciej W. Rozycki wrote:

> > and I gather from an off-list discussion a couple of months ago that
> > there were indeed some things that you didn't like.  But I think it'd
> > be easier to deal with them as follow-ups.  Please feel free to send
> > patches against trunk.  Or, if you tell me what it is you disagree with,
> > I can try to fix it myself.
> 
>  I guess I'll just send off the e-mail I had been writing but never 
> actually completed.  My current state of the changes includes all my 
> updates that reflect the points made, but now I'll have to regenerate 
> them, possibly by reverting yours, applying mine on top and figuring out 
> what differences to the original remain.  Oh well...

 Here's what I have come up with as a result of merging your changes into 
my code base.  There are plenty of small changes, so I have decided not to 
put too much effort into straightening them up (or not) lest you are 
unhappy with the outcome anyway.  Instead, I'm giving you (and the others) 
an opportunity to review my code in its current shape.  The result 
generally reflects my concerns as expressed earlier this week, in response 
to your comments back in March.

 Note there are a couple of bug fixes, some optimisations and one 
functional improvement too -- see the change log for details.

> > I'm sure there are things that we've both missed, but again,
> > we can deal with them as follow-ups.
> 
>  There's a whole lot of important linker relaxation fixes that I reckon 
> were not included in the original series plus several bug fixes.

 I'll work on these fixes now -- there are quite a few and at least one 
still requires some work not to be considered a dirty hack -- and will be 
back with you shortly.

 Comments, questions?

2011-07-28  Maciej W. Rozycki  <macro@codesourcery.com>

	bfd/
	* elfxx-mips.c: Adjust comments throughout.
	(mips_elf_relax_delete_bytes): Reshape code.
	(bz_insn_16): Correct opcode mask.
	(check_br32): Fix return type.
	(check_4byte_branch): Remove function.
	(check_bzc): New function.
	(_bfd_mips_elf_relax_section): Permit the relaxation of LUI
	instructions that immediately follow a compact branch
	instruction.  Remove check for R_MICROMIPS_GPREL16 relocations.  
	Reshape code.

	gas/
	* config/tc-mips.c: Adjust comments throughout.
	(reglist_lookup): Reshape code.
	(jmp_reloc_p, jalr_reloc_p): Reformat.
	(got16_reloc_p, hi16_reloc_p, lo16_reloc_p): Handle microMIPS
	relocations.
	(gpr_mod_mask): Remove unused variable.  Reshape code.
	(gpr_read_mask, gpr_write_mask): Reshape code.
	(fpr_read_mask, fpr_write_mask): Likewise.
	(nops_for_vr4130): Ensure non-microMIPS mode.
	(can_swap_branch_p): Correct pinfo2 reference.  Reshape code.
	(append_insn): Skip Loongson 2F workaround in MIPS16 mode.  Use
	the outermost operator of a compound relocation to determines
	the relocated field.  Reshape code.
	(md_convert_frag): Reshape code.

	include/opcode/
	* mips.h: Clarify the description of microMIPS instruction
	manipulation macros.
	(MICROMIPSOP_MASK_MAJOR, MICROMIPSOP_SH_MAJOR): Remove macros.

  Maciej

r-binutils-20110225-umips-fix.diff
Index: binutils-fsf-trunk-quilt/gas/config/tc-mips.c
===================================================================
--- binutils-fsf-trunk-quilt.orig/gas/config/tc-mips.c	2011-07-28 23:18:50.000000000 +0100
+++ binutils-fsf-trunk-quilt/gas/config/tc-mips.c	2011-07-28 23:30:26.000000000 +0100
@@ -483,7 +483,7 @@ static int mips_32bitmode = 0;
    (strncmp (TARGET_CPU, "mips16", sizeof ("mips16") - 1) == 0		\
     || strncmp (TARGET_CANONICAL, "mips-lsi-elf", sizeof ("mips-lsi-elf") - 1) == 0)
 
-/* Return true if the given CPU supports microMIPS.  */
+/* Return true if the given CPU supports the microMIPS ASE.  */
 #define CPU_HAS_MICROMIPS(cpu)	0
 
 /* True if CPU has a dror instruction.  */
@@ -2141,7 +2141,7 @@ reg_lookup (char **s, unsigned int types
    As a special exception if one of s0-s7 registers is specified as
    the range's lower delimiter and s8 (fp) is its upper one, then no
    registers whose numbers place them between s7 and s8 (i.e. $24-$29)
-   are selected; they have to be named separately if needed.  */
+   are selected; they have to be listed separately if needed.  */
 
 static int
 reglist_lookup (char **s, unsigned int types, unsigned int *reglistp)
@@ -2150,9 +2150,9 @@ reglist_lookup (char **s, unsigned int t
   unsigned int lastregno;
   bfd_boolean ok = TRUE;
   unsigned int regmask;
-  unsigned int regno;
+  char *s_endlist = *s;
   char *s_reset = *s;
-  char *s_end_of_list = *s;
+  unsigned int regno;
 
   while (reg_lookup (s, types, &regno))
     {
@@ -2177,14 +2177,14 @@ reglist_lookup (char **s, unsigned int t
       regmask ^= (1 << regno) - 1;
       reglist |= regmask;
 
-      s_end_of_list = *s;
+      s_endlist = *s;
       if (**s != ',')
 	break;
       (*s)++;
     }
 
   if (ok)
-    *s = s_end_of_list;
+    *s = s_endlist;
   else
     *s = s_reset;
   if (reglistp)
@@ -2663,41 +2663,36 @@ micromips_reloc_p (bfd_reloc_code_real_t
 }
 
 static inline bfd_boolean
+jmp_reloc_p (bfd_reloc_code_real_type reloc)
+{
+  return reloc == BFD_RELOC_MIPS_JMP || reloc == BFD_RELOC_MICROMIPS_JMP;
+}
+
+static inline bfd_boolean
 got16_reloc_p (bfd_reloc_code_real_type reloc)
 {
-  return (reloc == BFD_RELOC_MIPS_GOT16
-	  || reloc == BFD_RELOC_MIPS16_GOT16
+  return (reloc == BFD_RELOC_MIPS_GOT16 || reloc == BFD_RELOC_MIPS16_GOT16
 	  || reloc == BFD_RELOC_MICROMIPS_GOT16);
 }
 
 static inline bfd_boolean
 hi16_reloc_p (bfd_reloc_code_real_type reloc)
 {
-  return (reloc == BFD_RELOC_HI16_S
-	  || reloc == BFD_RELOC_MIPS16_HI16_S
+  return (reloc == BFD_RELOC_HI16_S || reloc == BFD_RELOC_MIPS16_HI16_S
 	  || reloc == BFD_RELOC_MICROMIPS_HI16_S);
 }
 
 static inline bfd_boolean
 lo16_reloc_p (bfd_reloc_code_real_type reloc)
 {
-  return (reloc == BFD_RELOC_LO16
-	  || reloc == BFD_RELOC_MIPS16_LO16
+  return (reloc == BFD_RELOC_LO16 || reloc == BFD_RELOC_MIPS16_LO16
 	  || reloc == BFD_RELOC_MICROMIPS_LO16);
 }
 
 static inline bfd_boolean
-jmp_reloc_p (bfd_reloc_code_real_type reloc)
-{
-  return (reloc == BFD_RELOC_MIPS_JMP
-	  || reloc == BFD_RELOC_MICROMIPS_JMP);
-}
-
-static inline bfd_boolean
 jalr_reloc_p (bfd_reloc_code_real_type reloc)
 {
-  return (reloc == BFD_RELOC_MIPS_JALR
-	  || reloc == BFD_RELOC_MICROMIPS_JALR);
+  return reloc == BFD_RELOC_MIPS_JALR || reloc == BFD_RELOC_MICROMIPS_JALR;
 }
 
 /* Return true if the given relocation might need a matching %lo().
@@ -2893,18 +2888,21 @@ relax_end (void)
   mips_relax.sequence = 0;
 }
 
-/* Return the mask of core registers that instruction IP may
-   read or write.  */
+/* Return the mask of core registers that IP reads or writes.  */
 
 static unsigned int
 gpr_mod_mask (const struct mips_cl_insn *ip)
 {
-  unsigned long pinfo, pinfo2;
+  unsigned long pinfo2;
   unsigned int mask;
 
   mask = 0;
-  pinfo = ip->insn_mo->pinfo;
   pinfo2 = ip->insn_mo->pinfo2;
+  if (!mips_opts.mips16)
+    {
+      if (pinfo2 & INSN2_MOD_SP)
+	mask |= 1 << SP;
+    }
   if (mips_opts.micromips)
     {
       if (pinfo2 & INSN2_MOD_GPR_MB)
@@ -2934,8 +2932,6 @@ gpr_mod_mask (const struct mips_cl_insn 
 	mask |= 1 << EXTRACT_OPERAND (1, MP, *ip);
       if (pinfo2 & INSN2_MOD_GPR_MQ)
 	mask |= 1 << micromips_to_32_reg_q_map[EXTRACT_OPERAND (1, MQ, *ip)];
-      if (pinfo2 & INSN2_MOD_SP)
-	mask |= 1 << SP;
     }
   return mask;
 }
@@ -2969,27 +2965,20 @@ gpr_read_mask (const struct mips_cl_insn
       if (pinfo & MIPS16_INSN_READ_GPR_X)
 	mask |= 1 << MIPS16_EXTRACT_OPERAND (REGR32, *ip);
     }
-  else if (mips_opts.micromips)
-    {
-      if (pinfo & INSN_READ_GPR_T)
-	mask |= 1 << EXTRACT_OPERAND (1, RT, *ip);
-      if (pinfo & INSN_READ_GPR_S)
-	mask |= 1 << EXTRACT_OPERAND (1, RS, *ip);
-      if (pinfo2 & INSN2_READ_GPR_31)
-	mask |= 1 << RA;
-      if (pinfo2 & INSN2_READ_GP)
-	mask |= 1 << GP;
-    }
   else
     {
       if (pinfo2 & INSN2_READ_GPR_D)
-	mask |= 1 << EXTRACT_OPERAND (0, RD, *ip);
+	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RD, *ip);
       if (pinfo & INSN_READ_GPR_T)
-	mask |= 1 << EXTRACT_OPERAND (0, RT, *ip);
+	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RT, *ip);
       if (pinfo & INSN_READ_GPR_S)
-	mask |= 1 << EXTRACT_OPERAND (0, RS, *ip);
+	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RS, *ip);
+      if (pinfo2 & INSN2_READ_GP)
+	mask |= 1 << GP;
+      if (pinfo2 & INSN2_READ_GPR_31)
+	mask |= 1 << RA;
       if (pinfo2 & INSN2_READ_GPR_Z)
-	mask |= 1 << EXTRACT_OPERAND (0, RZ, *ip);
+	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RZ, *ip);
     }
   /* Don't include register 0.  */
   return mask & ~1;
@@ -3023,23 +3012,14 @@ gpr_write_mask (const struct mips_cl_ins
       if (pinfo & MIPS16_INSN_WRITE_GPR_Y)
 	mask |= 1 << MIPS16OP_EXTRACT_REG32R (ip->insn_opcode);
     }
-  else if (mips_opts.micromips)
-    {
-      if (pinfo & INSN_WRITE_GPR_D)
-	mask |= 1 << EXTRACT_OPERAND (1, RD, *ip);
-      if (pinfo & INSN_WRITE_GPR_T)
-	mask |= 1 << EXTRACT_OPERAND (1, RT, *ip);
-      if (pinfo2 & INSN2_WRITE_GPR_S)
-	mask |= 1 << EXTRACT_OPERAND (1, RS, *ip);
-      if (pinfo & INSN_WRITE_GPR_31)
-	mask |= 1 << RA;
-    }
   else
     {
       if (pinfo & INSN_WRITE_GPR_D)
 	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RD, *ip);
       if (pinfo & INSN_WRITE_GPR_T)
 	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RT, *ip);
+      if (pinfo2 & INSN2_WRITE_GPR_S)
+	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RS, *ip);
       if (pinfo & INSN_WRITE_GPR_31)
 	mask |= 1 << RA;
       if (pinfo2 & INSN2_WRITE_GPR_Z)
@@ -3060,19 +3040,10 @@ fpr_read_mask (const struct mips_cl_insn
   mask = 0;
   pinfo = ip->insn_mo->pinfo;
   pinfo2 = ip->insn_mo->pinfo2;
-  if (mips_opts.micromips)
+  if (!mips_opts.mips16)
     {
       if (pinfo2 & INSN2_READ_FPR_D)
-	mask |= 1 << EXTRACT_OPERAND (1, FD, *ip);
-      if (pinfo & INSN_READ_FPR_S)
-	mask |= 1 << EXTRACT_OPERAND (1, FS, *ip);
-      if (pinfo & INSN_READ_FPR_T)
-	mask |= 1 << EXTRACT_OPERAND (1, FT, *ip);
-      if (pinfo & INSN_READ_FPR_R)
-	mask |= 1 << EXTRACT_OPERAND (1, FR, *ip);
-    }
-  else if (!mips_opts.mips16)
-    {
+	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FD, *ip);
       if (pinfo & INSN_READ_FPR_S)
 	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FS, *ip);
       if (pinfo & INSN_READ_FPR_T)
@@ -3100,16 +3071,7 @@ fpr_write_mask (const struct mips_cl_ins
   mask = 0;
   pinfo = ip->insn_mo->pinfo;
   pinfo2 = ip->insn_mo->pinfo2;
-  if (mips_opts.micromips)
-    {
-      if (pinfo2 & INSN_WRITE_FPR_D)
-	mask |= 1 << EXTRACT_OPERAND (1, FD, *ip);
-      if (pinfo & INSN_WRITE_FPR_S)
-	mask |= 1 << EXTRACT_OPERAND (1, FS, *ip);
-      if (pinfo & INSN_WRITE_FPR_T)
-	mask |= 1 << EXTRACT_OPERAND (1, FT, *ip);
-    }
-  else if (!mips_opts.mips16)
+  if (!mips_opts.mips16)
     {
       if (pinfo & INSN_WRITE_FPR_D)
 	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FD, *ip);
@@ -3316,6 +3278,7 @@ nops_for_vr4130 (int ignore, const struc
     if (MF_HILO_INSN (hist[i].insn_mo->pinfo))
       {
 	/* Extract the destination register.  */
+	gas_assert (!mips_opts.micromips);
 	mask = gpr_write_mask (&hist[i]);
 
 	/* No nops are needed if INSN reads that register.  */
@@ -3720,8 +3683,9 @@ can_swap_branch_p (struct mips_cl_insn *
     return FALSE;
 
   /* If the previous instruction is in a variant frag other than this
-     branch's one, we cannot do the swap.  This does not apply to the
-     mips16, which uses variant frags for different purposes.  */
+     branch's one, we cannot do the swap.  This does not apply to
+     MIPS16/microMIPS code, which uses variant frags for different
+     purposes.  */
   if (!HAVE_CODE_COMPRESSION
       && history[0].frag
       && history[0].frag->fr_type == rs_machine_dependent)
@@ -3781,17 +3745,16 @@ can_swap_branch_p (struct mips_cl_insn *
 
   /* If the previous instruction has an incorrect size for a fixed
      branch delay slot in microMIPS mode, we cannot swap.  */
-  if (mips_opts.micromips)
-    {
-      pinfo2 = ip->insn_mo->pinfo;
-      if ((pinfo2 & INSN2_BRANCH_DELAY_16BIT)
-	  && insn_length (history) != 2)
-	return FALSE;
+  pinfo2 = ip->insn_mo->pinfo2;
+  if (mips_opts.micromips
+      && (pinfo2 & INSN2_BRANCH_DELAY_16BIT)
+      && insn_length (history) != 2)
+    return FALSE;
+  if (mips_opts.micromips
+      && (pinfo2 & INSN2_BRANCH_DELAY_32BIT)
+      && insn_length (history) != 4)
+    return FALSE;
 
-      if ((pinfo2 & INSN2_BRANCH_DELAY_32BIT)
-	  && insn_length (history) != 4)
-	return FALSE;
-    }
   return TRUE;
 }
 
@@ -3984,10 +3947,10 @@ append_insn (struct mips_cl_insn *ip, ex
 {
   unsigned long prev_pinfo, prev_pinfo2, pinfo, pinfo2;
   bfd_boolean relaxed_branch = FALSE;
-  bfd_boolean relax32;
   enum append_method method;
+  bfd_boolean relax32;
 
-  if (mips_fix_loongson2f && !mips_opts.micromips)
+  if (mips_fix_loongson2f && !HAVE_CODE_COMPRESSION)
     fix_loongson2f (ip);
 
   mips_mark_labels ();
@@ -4014,10 +3977,11 @@ append_insn (struct mips_cl_insn *ip, ex
   else if (*reloc_type <= BFD_RELOC_UNUSED
 	   && address_expr->X_op == O_constant)
     {
+      bfd_reloc_code_real_type orig_reloc = *reloc_type;
       unsigned int tmp;
 
       ip->complete_p = 1;
-      switch (*reloc_type)
+      switch (orig_reloc)
 	{
 	case BFD_RELOC_32:
 	  ip->insn_opcode |= address_expr->X_add_number;
@@ -4192,9 +4156,9 @@ append_insn (struct mips_cl_insn *ip, ex
      If the instruction produced is a branch that we will swap with
      the preceding instruction, then we add the displacement by which
      the branch will be moved backwards.  This is more appropriate
-     and for MIPS16/microMIPS code also prevents a debugger from placing
-     a breakpoint in the middle of the branch (and corrupting code if
-     software breakpoints are used).  */
+     and for MIPS16/microMIPS code also prevents a debugger from
+     placing a breakpoint in the middle of the branch (and corrupting
+     code if software breakpoints are used).  */
   dwarf2_emit_insn ((HAVE_CODE_COMPRESSION ? -1 : 0)
 		    + (method == APPEND_SWAP ? insn_length (history) : 0));
 #endif
@@ -4329,60 +4293,66 @@ append_insn (struct mips_cl_insn *ip, ex
 
   if (!ip->complete_p && *reloc_type < BFD_RELOC_UNUSED)
     {
+      bfd_reloc_code_real_type orig_reloc = *reloc_type;
       bfd_reloc_code_real_type final_type[3];
+      reloc_howto_type *howto0;
       reloc_howto_type *howto;
+      int n;
       int i;
 
       /* Perform any necessary conversion to microMIPS relocations
-	 and find out how many relocations there actually are.  */
-      for (i = 0; i < 3 && reloc_type[i] != BFD_RELOC_UNUSED; i++)
-	final_type[i] = micromips_map_reloc (reloc_type[i]);
+         and find out how many relocations there actually are.  */
+      for (n = 0; n < 3 && reloc_type[n] != BFD_RELOC_UNUSED; n++)
+	final_type[n] = micromips_map_reloc (reloc_type[n]);
 
       /* In a compound relocation, it is the final (outermost)
 	 operator that determines the relocated field.  */
-      howto = bfd_reloc_type_lookup (stdoutput, final_type[i - 1]);
+      howto = howto0 = bfd_reloc_type_lookup (stdoutput, final_type[n - 1]);
+
       if (howto == NULL)
 	{
 	  /* To reproduce this failure try assembling gas/testsuites/
 	     gas/mips/mips16-intermix.s with a mips-ecoff targeted
 	     assembler.  */
 	  as_bad (_("Unsupported MIPS relocation number %d"),
-		  final_type[i - 1]);
+		  final_type[n - 1]);
 	  howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16);
 	}
-	  
-      howto = bfd_reloc_type_lookup (stdoutput, final_type[0]);
+
+      if (n > 1)
+	howto0 = bfd_reloc_type_lookup (stdoutput, final_type[0]);
       ip->fixp[0] = fix_new_exp (ip->frag, ip->where,
 				 bfd_get_reloc_size (howto),
 				 address_expr,
-				 howto->pc_relative, final_type[0]);
+				 howto0 && howto0->pc_relative,
+				 final_type[0]);
 
       /* Tag symbols that have a R_MIPS16_26 relocation against them.  */
-      if (reloc_type[0] == BFD_RELOC_MIPS16_JMP
-	  && ip->fixp[0]->fx_addsy)
+      if (final_type[0] == BFD_RELOC_MIPS16_JMP && ip->fixp[0]->fx_addsy)
 	*symbol_get_tc (ip->fixp[0]->fx_addsy) = 1;
 
       /* These relocations can have an addend that won't fit in
-	 4 octets for 64bit assembly.  */
+         4 octets for 64bit assembly.  We cheat and check orig_reloc
+         here as this has fewer choices than reloc.  */
       if (HAVE_64BIT_GPRS
 	  && ! howto->partial_inplace
-	  && (reloc_type[0] == BFD_RELOC_16
-	      || reloc_type[0] == BFD_RELOC_32
-	      || reloc_type[0] == BFD_RELOC_MIPS_JMP
-	      || reloc_type[0] == BFD_RELOC_GPREL16
-	      || reloc_type[0] == BFD_RELOC_MIPS_LITERAL
-	      || reloc_type[0] == BFD_RELOC_GPREL32
-	      || reloc_type[0] == BFD_RELOC_64
-	      || reloc_type[0] == BFD_RELOC_CTOR
-	      || reloc_type[0] == BFD_RELOC_MIPS_SUB
-	      || reloc_type[0] == BFD_RELOC_MIPS_HIGHEST
-	      || reloc_type[0] == BFD_RELOC_MIPS_HIGHER
-	      || reloc_type[0] == BFD_RELOC_MIPS_SCN_DISP
-	      || reloc_type[0] == BFD_RELOC_MIPS_REL16
-	      || reloc_type[0] == BFD_RELOC_MIPS_RELGOT
-	      || reloc_type[0] == BFD_RELOC_MIPS16_GPREL
-	      || hi16_reloc_p (reloc_type[0])
-	      || lo16_reloc_p (reloc_type[0])))
+	  && (orig_reloc == BFD_RELOC_16
+	      || orig_reloc == BFD_RELOC_32
+	      || orig_reloc == BFD_RELOC_MIPS_JMP
+	      || orig_reloc == BFD_RELOC_GPREL16
+	      || orig_reloc == BFD_RELOC_MIPS_LITERAL
+	      || orig_reloc == BFD_RELOC_GPREL32
+	      || orig_reloc == BFD_RELOC_64
+	      || orig_reloc == BFD_RELOC_CTOR
+	      || orig_reloc == BFD_RELOC_MIPS_SUB
+	      || orig_reloc == BFD_RELOC_MIPS_HIGHEST
+	      || orig_reloc == BFD_RELOC_MIPS_HIGHER
+	      || orig_reloc == BFD_RELOC_MIPS_SCN_DISP
+	      || orig_reloc == BFD_RELOC_MIPS_REL16
+	      || orig_reloc == BFD_RELOC_MIPS_RELGOT
+	      || orig_reloc == BFD_RELOC_MIPS16_GPREL
+	      || hi16_reloc_p (orig_reloc)
+	      || lo16_reloc_p (orig_reloc)))
 	ip->fixp[0]->fx_no_overflow = 1;
 
       if (mips_relax.sequence)
@@ -4390,7 +4360,7 @@ append_insn (struct mips_cl_insn *ip, ex
 	  if (mips_relax.first_fixup == 0)
 	    mips_relax.first_fixup = ip->fixp[0];
 	}
-      else if (reloc_needs_lo_p (*reloc_type))
+      else if (reloc_needs_lo_p (final_type[0]))
 	{
 	  struct mips_hi_fixup *hi_fixup;
 
@@ -4413,17 +4383,16 @@ append_insn (struct mips_cl_insn *ip, ex
 	 against RSS_UNDEF, RSS_GP, RSS_GP0 or RSS_LOC.  At the
 	 moment we only use RSS_UNDEF, but we could add support
 	 for the others if it ever becomes necessary.  */
-      for (i = 1; i < 3; i++)
-	if (reloc_type[i] != BFD_RELOC_UNUSED)
-	  {
-	    ip->fixp[i] = fix_new (ip->frag, ip->where,
-				   ip->fixp[0]->fx_size, NULL, 0,
-				   FALSE, final_type[i]);
+      for (i = 1; i < n; i++)
+	{
+	  ip->fixp[i] = fix_new (ip->frag, ip->where,
+				 ip->fixp[0]->fx_size, NULL, 0,
+				 FALSE, final_type[i]);
 
-	    /* Use fx_tcbit to mark compound relocs.  */
-	    ip->fixp[0]->fx_tcbit = 1;
-	    ip->fixp[i]->fx_tcbit = 1;
-	  }
+	  /* Use fx_tcbit to mark compound relocs.  */
+	  ip->fixp[0]->fx_tcbit = 1;
+	  ip->fixp[i]->fx_tcbit = 1;
+	}
     }
   install_insn (ip);
 
@@ -17800,8 +17769,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU
       bfd_boolean compact = RELAX_MICROMIPS_COMPACT (fragp->fr_subtype);
       bfd_boolean al = RELAX_MICROMIPS_LINK (fragp->fr_subtype);
       int type = RELAX_MICROMIPS_TYPE (fragp->fr_subtype);
-      unsigned long jal, jalr, jr;
-
+      bfd_boolean short_ds;
       unsigned long insn;
       expressionS exp;
       fixS *fixp;
@@ -17812,7 +17780,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU
 
       fragp->fr_fix += fragp->fr_var;
 
-      /* Handle 16-bit branches that fit or are forced to fit.  */
+      /* Handle 16-bit branches that fit or forced to fit.  */
       if (type != 0 && !RELAX_MICROMIPS_TOOFAR16 (fragp->fr_subtype))
 	{
 	  /* We generate a fixup instead of applying it right now,
@@ -17841,7 +17809,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU
 	  return;
 	}
 
-      /* Handle 32-bit branches that fit or forced to fit.  */
+      /* Handle 32-bit branches that fit or are forced to fit.  */
       if (!RELAX_MICROMIPS_RELAX32 (fragp->fr_subtype)
 	  || !RELAX_MICROMIPS_TOOFAR32 (fragp->fr_subtype))
 	{
@@ -17914,18 +17882,8 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU
       as_warn_where (fragp->fr_file, fragp->fr_line,
 		     _("Relaxed out-of-range branch into a jump"));
 
-      /* Check the short-delay-slot bit.  */
-      if (al && (insn & 0x02000000) != 0)
-	{
-	  jal = 0x74000000;				/* jals  */
-	  jalr = 0x45e0;				/* jalrs  */
-	}
-      else
-	{
-	  jal = 0xf4000000;				/* jal  */
-	  jalr = 0x45c0;				/* jalr  */
-	}
-      jr = compact ? 0x45a0 : 0x4580;			/* jr/c  */
+      /* Set the short-delay-slot bit.  */
+      short_ds = al && (insn & 0x02000000) != 0;
 
       if (!RELAX_MICROMIPS_UNCOND (fragp->fr_subtype))
 	{
@@ -17995,6 +17953,8 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU
 
       if (mips_pic == NO_PIC)
 	{
+	  unsigned long jal = short_ds ? 0x74000000 : 0xf4000000; /* jal/s  */
+
 	  /* j/jal/jals <sym>  R_MICROMIPS_26_S1  */
 	  insn = al ? jal : 0xd4000000;
 
@@ -18019,6 +17979,8 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU
       else
 	{
 	  unsigned long at = RELAX_MICROMIPS_AT (fragp->fr_subtype);
+	  unsigned long jalr = short_ds ? 0x45e0 : 0x45c0;	/* jalr/s  */
+	  unsigned long jr = compact ? 0x45a0 : 0x4580;		/* jr/c  */
 
 	  /* lw/ld $at, <sym>($gp)  R_MICROMIPS_GOT16  */
 	  insn = HAVE_64BIT_ADDRESSES ? 0xdc1c0000 : 0xfc1c0000;
Index: binutils-fsf-trunk-quilt/bfd/elfxx-mips.c
===================================================================
--- binutils-fsf-trunk-quilt.orig/bfd/elfxx-mips.c	2011-07-28 23:18:50.000000000 +0100
+++ binutils-fsf-trunk-quilt/bfd/elfxx-mips.c	2011-07-28 23:30:26.000000000 +0100
@@ -11910,8 +11910,7 @@ mips_elf_relax_delete_bytes (bfd *abfd,
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   isym = (Elf_Internal_Sym *) symtab_hdr->contents;
   for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
-    if (isym->st_shndx == sec_shndx
-	&& isym->st_value > addr)
+    if (isym->st_shndx == sec_shndx && isym->st_value > addr)
       isym->st_value -= count;
 
   /* Now adjust the global symbols defined in this section.  */
@@ -11928,9 +11927,8 @@ mips_elf_relax_delete_bytes (bfd *abfd,
 	   || sym_hash->root.type == bfd_link_hash_defweak)
 	  && sym_hash->root.u.def.section == sec)
 	{
-	  bfd_vma value;
+	  bfd_vma value = sym_hash->root.u.def.value;
 
-	  value = sym_hash->root.u.def.value;
 	  if (ELF_ST_IS_MICROMIPS (sym_hash->other))
 	    value &= MINUS_TWO;
 	  if (value > addr)
@@ -11989,7 +11987,7 @@ static const struct opcode_descriptor b_
   { /* "b",	"mD",		*/ 0xcc00,     0xfc00 };
 
 static const struct opcode_descriptor bz_insn_16 =
-  { /* "b(eq|ne)z", "md,mE",	*/ 0x8c00,     0xac00 };
+  { /* "b(eq|ne)z", "md,mE",	*/ 0x8c00,     0xdc00 };
 
 
 /* 32-bit and 16-bit branch EQ and NE zero.  */
@@ -12241,7 +12239,7 @@ check_br16 (bfd *abfd, bfd_byte *ptr, un
 /* If PTR points to a 32-bit branch or jump that doesn't fiddle with REG,
    then return TRUE, otherwise FALSE.  */
 
-static int
+static bfd_boolean
 check_br32 (bfd *abfd, bfd_byte *ptr, unsigned long reg)
 {
   unsigned long opcode;
@@ -12266,32 +12264,37 @@ check_br32 (bfd *abfd, bfd_byte *ptr, un
   return FALSE;
 }
 
-/* Bitsize checking.  */
-#define IS_BITSIZE(val, N)						\
-  (((((val) & ((1ULL << (N)) - 1)) ^ (1ULL << ((N) - 1)))		\
-    - (1ULL << ((N) - 1))) == (val))
-
-/* See if relocations [INTERNAL_RELOCS, IRELEND) confirm that there
-   is a 4-byte branch at offset OFFSET.  */
+/* If the instruction encoding at PTR and relocations [INTERNAL_RELOCS,
+   IRELEND) at OFFSET indicate that it is a compact branch there, then
+   return TRUE, otherwise FALSE.  */
 
 static bfd_boolean
-check_4byte_branch (Elf_Internal_Rela *internal_relocs,
-		    Elf_Internal_Rela *irelend, bfd_vma offset)
+check_bzc (bfd *abfd, const bfd_byte *ptr, bfd_vma offset,
+	   const Elf_Internal_Rela *internal_relocs,
+	   const Elf_Internal_Rela *irelend)
 {
-  Elf_Internal_Rela *irel;
-  unsigned long r_type;
+  const Elf_Internal_Rela *irel;
+  unsigned long opcode;
+
+  opcode   = bfd_get_16 (abfd, ptr);
+  opcode <<= 16;
+  opcode  |= bfd_get_16 (abfd, ptr + 2);
+  if (find_match (opcode, bzc_insns_32) < 0)
+    return FALSE;
 
   for (irel = internal_relocs; irel < irelend; irel++)
-    if (irel->r_offset == offset)
-      {
-	r_type = ELF32_R_TYPE (irel->r_info);
-	if (r_type == R_MICROMIPS_26_S1
-	    || r_type == R_MICROMIPS_PC16_S1
-	    || r_type == R_MICROMIPS_JALR)
-	  return TRUE;
-      }
+    if (irel->r_offset == offset
+	&& ELF32_R_TYPE (irel->r_info) == R_MICROMIPS_PC16_S1)
+      return TRUE;
+
   return FALSE;
 }
+
+/* Bitsize checking.  */
+#define IS_BITSIZE(val, N)						\
+  (((((val) & ((1ULL << (N)) - 1)) ^ (1ULL << ((N) - 1)))		\
+    - (1ULL << ((N) - 1))) == (val))
+
 \f
 bfd_boolean
 _bfd_mips_elf_relax_section (bfd *abfd, asection *sec,
@@ -12336,6 +12339,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
       unsigned long opcode;
       bfd_vma symval;
       bfd_vma pcrval;
+      bfd_byte *ptr;
       int fndopc;
 
       /* The number of bytes to delete for relaxation and from where
@@ -12347,8 +12351,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
          this reloc.  */
       if (r_type != R_MICROMIPS_HI16
 	  && r_type != R_MICROMIPS_PC16_S1
-	  && r_type != R_MICROMIPS_26_S1
-	  && r_type != R_MICROMIPS_GPREL16)
+	  && r_type != R_MICROMIPS_26_S1)
 	continue;
 
       /* Get the section contents if we haven't done so already.  */
@@ -12361,6 +12364,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
 	  else if (!bfd_malloc_and_get_section (abfd, sec, &contents))
 	    goto error_return;
 	}
+      ptr = contents + irel->r_offset;
 
       /* Read this BFD's local symbols if we haven't done so already.  */
       if (isymbuf == NULL && symtab_hdr->sh_info != 0)
@@ -12432,8 +12436,8 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
       if (irel->r_offset + 4 > sec->size)
 	continue;
 
-      opcode  = bfd_get_16 (abfd, contents + irel->r_offset    ) << 16;
-      opcode |= bfd_get_16 (abfd, contents + irel->r_offset + 2);
+      opcode  = bfd_get_16 (abfd, ptr    ) << 16;
+      opcode |= bfd_get_16 (abfd, ptr + 2);
 
       /* This is the pc-relative distance from the instruction the
          relocation is applied to, to the symbol referred.  */
@@ -12452,6 +12456,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
          out the offset).  */
       if (r_type == R_MICROMIPS_HI16 && MATCH (opcode, lui_insn))
 	{
+	  bfd_boolean bzc = FALSE;
 	  unsigned long nextopc;
 	  unsigned long reg;
 	  bfd_vma offset;
@@ -12475,19 +12480,19 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
 	      && ELF32_R_SYM (irel[2].r_info) == r_symndx)
 	    continue;
 
-	  /* See if the LUI instruction *might* be in a branch delay slot.  */
+	  /* See if the LUI instruction *might* be in a branch delay slot.
+	     We check whether what looks like a 16-bit branch or jump is
+	     actually an immediate argument to a compact branch, and let
+	     it through if so.  */
 	  if (irel->r_offset >= 2
-	      && check_br16_dslot (abfd, contents + irel->r_offset - 2) > 0
+	      && check_br16_dslot (abfd, ptr - 2)
 	      && !(irel->r_offset >= 4
-		   /* If the instruction is actually a 4-byte branch,
-		      the value of check_br16_dslot doesn't matter.
-		      We should use check_br32_dslot to check whether
-		      the branch has a delay slot.  */
-		   && check_4byte_branch (internal_relocs, irelend,
-					  irel->r_offset - 4)))
+		   && (bzc = check_bzc (abfd, ptr - 4, irel->r_offset - 4,
+					internal_relocs, irelend))))
 	    continue;
 	  if (irel->r_offset >= 4
-	      && check_br32_dslot (abfd, contents + irel->r_offset - 4) > 0)
+	      && !bzc
+	      && check_br32_dslot (abfd, ptr - 4))
 	    continue;
 
 	  reg = OP32_SREG (opcode);
@@ -12502,11 +12507,11 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
 	    case 0:
 	      break;
 	    case 2:
-	      if (check_br16 (abfd, contents + irel->r_offset + 4, reg))
+	      if (check_br16 (abfd, ptr + 4, reg))
 		break;
 	      continue;
 	    case 4:
-	      if (check_br32 (abfd, contents + irel->r_offset + 4, reg))
+	      if (check_br32 (abfd, ptr + 4, reg))
 		break;
 	      continue;
 	    default:
@@ -12581,8 +12586,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
 	       && irel->r_offset + 5 < sec->size
 	       && ((fndopc = find_match (opcode, bz_rs_insns_32)) >= 0
 		   || (fndopc = find_match (opcode, bz_rt_insns_32)) >= 0)
-	       && MATCH (bfd_get_16 (abfd, contents + irel->r_offset + 4),
-			 nop_insn_16))
+	       && MATCH (bfd_get_16 (abfd, ptr + 4), nop_insn_16))
 	{
 	  unsigned long reg;
 
@@ -12593,10 +12597,8 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
 		    | BZC32_REG_FIELD (reg)
 		    | (opcode & 0xffff));		/* Addend value.  */
 
-	  bfd_put_16 (abfd, (opcode >> 16) & 0xffff,
-		      contents + irel->r_offset);
-	  bfd_put_16 (abfd,  opcode        & 0xffff,
-		      contents + irel->r_offset + 2);
+	  bfd_put_16 (abfd, (opcode >> 16) & 0xffff, ptr);
+	  bfd_put_16 (abfd,  opcode        & 0xffff, ptr + 2);
 
 	  /* Delete the 16-bit delay slot NOP: two bytes from
 	     irel->offset + 4.  */
@@ -12617,7 +12619,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
 	  bfd_put_16 (abfd,
 		      (b_insn_16.match
 		       | (opcode & 0x3ff)),		/* Addend value.  */
-		      contents + irel->r_offset);
+		      ptr);
 
 	  /* Delete 2 bytes from irel->r_offset + 2.  */
 	  delcnt = 2;
@@ -12645,7 +12647,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
 		      (bz_insns_16[fndopc].match
 		       | BZ16_REG_FIELD (reg)
 		       | (opcode & 0x7f)),		/* Addend value.  */
-		      contents + irel->r_offset);
+		      ptr);
 
 	  /* Delete 2 bytes from irel->r_offset + 2.  */
 	  delcnt = 2;
@@ -12661,14 +12663,13 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
 	  unsigned long n32opc;
 	  bfd_boolean relaxed = FALSE;
 
-	  n32opc  = bfd_get_16 (abfd, contents + irel->r_offset + 4) << 16;
-	  n32opc |= bfd_get_16 (abfd, contents + irel->r_offset + 6);
+	  n32opc  = bfd_get_16 (abfd, ptr + 4) << 16;
+	  n32opc |= bfd_get_16 (abfd, ptr + 6);
 
 	  if (MATCH (n32opc, nop_insn_32))
 	    {
 	      /* Replace delay slot 32-bit NOP with a 16-bit NOP.  */
-	      bfd_put_16 (abfd, nop_insn_16.match,
-			  contents + irel->r_offset + 4);
+	      bfd_put_16 (abfd, nop_insn_16.match, ptr + 4);
 
 	      relaxed = TRUE;
 	    }
@@ -12679,7 +12680,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
 			  (move_insn_16.match
 			   | MOVE16_RD_FIELD (MOVE32_RD (n32opc))
 			   | MOVE16_RS_FIELD (MOVE32_RS (n32opc))),
-			  contents + irel->r_offset + 4);
+			  ptr + 4);
 
 	      relaxed = TRUE;
 	    }
@@ -12691,9 +12692,9 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
 	      /* JAL with 32-bit delay slot that is changed to a JALS
 	         with 16-bit delay slot.  */
 	      bfd_put_16 (abfd, (jal_insn_32_bd16.match >> 16) & 0xffff,
-			  contents + irel->r_offset);
+			  ptr);
 	      bfd_put_16 (abfd,  jal_insn_32_bd16.match        & 0xffff,
-			  contents + irel->r_offset + 2);
+			  ptr + 2);
 
 	      /* Delete 2 bytes from irel->r_offset + 6.  */
 	      delcnt = 2;
Index: binutils-fsf-trunk-quilt/include/opcode/mips.h
===================================================================
--- binutils-fsf-trunk-quilt.orig/include/opcode/mips.h	2011-07-28 23:29:25.000000000 +0100
+++ binutils-fsf-trunk-quilt/include/opcode/mips.h	2011-07-28 23:30:26.000000000 +0100
@@ -1332,13 +1332,10 @@ extern int bfd_mips_num_opcodes;
 extern const struct mips_opcode mips16_opcodes[];
 extern const int bfd_mips16_num_opcodes;
 
-/* These are the bitmasks and shift counts used for the different
-   fields in the instruction formats.  Other than MAJOR, no masks are
-   provided for the fixed portions of an instruction, since they are
-   not needed.  */
+/* These are the bit masks and shift counts used for the different fields
+   in the microMIPS instruction formats.  No masks are provided for the
+   fixed portions of an instruction, since they are not needed.  */
 
-#define MICROMIPSOP_MASK_MAJOR		0x3f
-#define MICROMIPSOP_SH_MAJOR		26
 #define MICROMIPSOP_MASK_IMMEDIATE	0xffff
 #define MICROMIPSOP_SH_IMMEDIATE	0
 #define MICROMIPSOP_MASK_DELTA		0xffff

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2011-07-29  0:58                     ` Maciej W. Rozycki
@ 2011-07-29 11:30                       ` Richard Sandiford
  2011-07-29 22:52                         ` Maciej W. Rozycki
  0 siblings, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2011-07-29 11:30 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
	Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers

"Maciej W. Rozycki" <macro@codesourcery.com> writes:
>  Here's what I have come up with as a result of merging your changes into 
> my code base.  There are plenty of small changes, so I have decided not to 
> put too much effort into straightening them up (or not) lest you are 
> unhappy with the outcome anyway.  Instead, I'm giving you (and the others) 
> an opportunity to review my code in its current shape.

Thanks for doing it this way.

> On Tue, 26 Jul 2011, Maciej W. Rozycki wrote:
>>  There's a whole lot of important linker relaxation fixes that I reckon 
>> were not included in the original series plus several bug fixes.
>
>  I'll work on these fixes now -- there are quite a few and at least one 
> still requires some work not to be considered a dirty hack -- and will be 
> back with you shortly.

Thanks.  This is what I asked for in the first place: that anything we
hadn't caught should be dealt with as follow-ups, rather than folded
into the huge initial commit.  (For reference, even the .tar.bz2 was
over 280k.)  I still don't understand why you chose to ignore that.

The whole point of approving most of the submission with a few minor
changes (back in March) was that it would be quick to make those changes
and get the whole thing into CVS.  It would then be much easier for me
to review any further changes you wanted to make.  I also assumed that
it would be easier for you to submit them.

Anyway, on a more positive note, a lot of the hunks are OK to commit,
as follows:

> Index: binutils-fsf-trunk-quilt/gas/config/tc-mips.c
> ===================================================================
> --- binutils-fsf-trunk-quilt.orig/gas/config/tc-mips.c	2011-07-28 23:18:50.000000000 +0100
> +++ binutils-fsf-trunk-quilt/gas/config/tc-mips.c	2011-07-28 23:30:26.000000000 +0100
> @@ -483,7 +483,7 @@ static int mips_32bitmode = 0;
>     (strncmp (TARGET_CPU, "mips16", sizeof ("mips16") - 1) == 0		\
>      || strncmp (TARGET_CANONICAL, "mips-lsi-elf", sizeof ("mips-lsi-elf") - 1) == 0)
>  
> -/* Return true if the given CPU supports microMIPS.  */
> +/* Return true if the given CPU supports the microMIPS ASE.  */
>  #define CPU_HAS_MICROMIPS(cpu)	0
>  
>  /* True if CPU has a dror instruction.  */

OK

> @@ -2141,7 +2141,7 @@ reg_lookup (char **s, unsigned int types
>     As a special exception if one of s0-s7 registers is specified as
>     the range's lower delimiter and s8 (fp) is its upper one, then no
>     registers whose numbers place them between s7 and s8 (i.e. $24-$29)
> -   are selected; they have to be named separately if needed.  */
> +   are selected; they have to be listed separately if needed.  */
>  
>  static int
>  reglist_lookup (char **s, unsigned int types, unsigned int *reglistp)

OK

> @@ -2893,18 +2888,21 @@ relax_end (void)
>    mips_relax.sequence = 0;
>  }
>  
> -/* Return the mask of core registers that instruction IP may
> -   read or write.  */
> +/* Return the mask of core registers that IP reads or writes.  */
>  
>  static unsigned int
>  gpr_mod_mask (const struct mips_cl_insn *ip)
>  {
> -  unsigned long pinfo, pinfo2;
> +  unsigned long pinfo2;
>    unsigned int mask;
>  
>    mask = 0;
> -  pinfo = ip->insn_mo->pinfo;
>    pinfo2 = ip->insn_mo->pinfo2;
> +  if (!mips_opts.mips16)
> +    {
> +      if (pinfo2 & INSN2_MOD_SP)
> +	mask |= 1 << SP;
> +    }
>    if (mips_opts.micromips)
>      {
>        if (pinfo2 & INSN2_MOD_GPR_MB)
and:
> @@ -2934,8 +2932,6 @@ gpr_mod_mask (const struct mips_cl_insn 
>  	mask |= 1 << EXTRACT_OPERAND (1, MP, *ip);
>        if (pinfo2 & INSN2_MOD_GPR_MQ)
>  	mask |= 1 << micromips_to_32_reg_q_map[EXTRACT_OPERAND (1, MQ, *ip)];
> -      if (pinfo2 & INSN2_MOD_SP)
> -	mask |= 1 << SP;
>      }
>    return mask;
>  }

*sigh*  Have I introduced another write to an unused variable? :-(
I really should use a more modern compiler.

The removal of pinfo is OK, thanks.  The rest of it doesn't look like
an improvement.

> @@ -2969,27 +2965,20 @@ gpr_read_mask (const struct mips_cl_insn
>        if (pinfo & MIPS16_INSN_READ_GPR_X)
>  	mask |= 1 << MIPS16_EXTRACT_OPERAND (REGR32, *ip);
>      }
> -  else if (mips_opts.micromips)
> -    {
> -      if (pinfo & INSN_READ_GPR_T)
> -	mask |= 1 << EXTRACT_OPERAND (1, RT, *ip);
> -      if (pinfo & INSN_READ_GPR_S)
> -	mask |= 1 << EXTRACT_OPERAND (1, RS, *ip);
> -      if (pinfo2 & INSN2_READ_GPR_31)
> -	mask |= 1 << RA;
> -      if (pinfo2 & INSN2_READ_GP)
> -	mask |= 1 << GP;
> -    }
>    else
>      {
>        if (pinfo2 & INSN2_READ_GPR_D)
> -	mask |= 1 << EXTRACT_OPERAND (0, RD, *ip);
> +	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RD, *ip);
>        if (pinfo & INSN_READ_GPR_T)
> -	mask |= 1 << EXTRACT_OPERAND (0, RT, *ip);
> +	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RT, *ip);
>        if (pinfo & INSN_READ_GPR_S)
> -	mask |= 1 << EXTRACT_OPERAND (0, RS, *ip);
> +	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RS, *ip);
> +      if (pinfo2 & INSN2_READ_GP)
> +	mask |= 1 << GP;
> +      if (pinfo2 & INSN2_READ_GPR_31)
> +	mask |= 1 << RA;
>        if (pinfo2 & INSN2_READ_GPR_Z)
> -	mask |= 1 << EXTRACT_OPERAND (0, RZ, *ip);
> +	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RZ, *ip);
>      }
>    /* Don't include register 0.  */
>    return mask & ~1;

OK

> @@ -3023,23 +3012,14 @@ gpr_write_mask (const struct mips_cl_ins
>        if (pinfo & MIPS16_INSN_WRITE_GPR_Y)
>  	mask |= 1 << MIPS16OP_EXTRACT_REG32R (ip->insn_opcode);
>      }
> -  else if (mips_opts.micromips)
> -    {
> -      if (pinfo & INSN_WRITE_GPR_D)
> -	mask |= 1 << EXTRACT_OPERAND (1, RD, *ip);
> -      if (pinfo & INSN_WRITE_GPR_T)
> -	mask |= 1 << EXTRACT_OPERAND (1, RT, *ip);
> -      if (pinfo2 & INSN2_WRITE_GPR_S)
> -	mask |= 1 << EXTRACT_OPERAND (1, RS, *ip);
> -      if (pinfo & INSN_WRITE_GPR_31)
> -	mask |= 1 << RA;
> -    }
>    else
>      {
>        if (pinfo & INSN_WRITE_GPR_D)
>  	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RD, *ip);
>        if (pinfo & INSN_WRITE_GPR_T)
>  	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RT, *ip);
> +      if (pinfo2 & INSN2_WRITE_GPR_S)
> +	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RS, *ip);
>        if (pinfo & INSN_WRITE_GPR_31)
>  	mask |= 1 << RA;
>        if (pinfo2 & INSN2_WRITE_GPR_Z)

OK

> @@ -3060,19 +3040,10 @@ fpr_read_mask (const struct mips_cl_insn
>    mask = 0;
>    pinfo = ip->insn_mo->pinfo;
>    pinfo2 = ip->insn_mo->pinfo2;
> -  if (mips_opts.micromips)
> +  if (!mips_opts.mips16)
>      {
>        if (pinfo2 & INSN2_READ_FPR_D)
> -	mask |= 1 << EXTRACT_OPERAND (1, FD, *ip);
> -      if (pinfo & INSN_READ_FPR_S)
> -	mask |= 1 << EXTRACT_OPERAND (1, FS, *ip);
> -      if (pinfo & INSN_READ_FPR_T)
> -	mask |= 1 << EXTRACT_OPERAND (1, FT, *ip);
> -      if (pinfo & INSN_READ_FPR_R)
> -	mask |= 1 << EXTRACT_OPERAND (1, FR, *ip);
> -    }
> -  else if (!mips_opts.mips16)
> -    {
> +	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FD, *ip);
>        if (pinfo & INSN_READ_FPR_S)
>  	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FS, *ip);
>        if (pinfo & INSN_READ_FPR_T)

OK

> @@ -3100,16 +3071,7 @@ fpr_write_mask (const struct mips_cl_ins
>    mask = 0;
>    pinfo = ip->insn_mo->pinfo;
>    pinfo2 = ip->insn_mo->pinfo2;
> -  if (mips_opts.micromips)
> -    {
> -      if (pinfo2 & INSN_WRITE_FPR_D)
> -	mask |= 1 << EXTRACT_OPERAND (1, FD, *ip);
> -      if (pinfo & INSN_WRITE_FPR_S)
> -	mask |= 1 << EXTRACT_OPERAND (1, FS, *ip);
> -      if (pinfo & INSN_WRITE_FPR_T)
> -	mask |= 1 << EXTRACT_OPERAND (1, FT, *ip);
> -    }
> -  else if (!mips_opts.mips16)
> +  if (!mips_opts.mips16)
>      {
>        if (pinfo & INSN_WRITE_FPR_D)
>  	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FD, *ip);

OK

> @@ -3720,8 +3683,9 @@ can_swap_branch_p (struct mips_cl_insn *
>      return FALSE;
>  
>    /* If the previous instruction is in a variant frag other than this
> -     branch's one, we cannot do the swap.  This does not apply to the
> -     mips16, which uses variant frags for different purposes.  */
> +     branch's one, we cannot do the swap.  This does not apply to
> +     MIPS16/microMIPS code, which uses variant frags for different
> +     purposes.  */
>    if (!HAVE_CODE_COMPRESSION
>        && history[0].frag
>        && history[0].frag->fr_type == rs_machine_dependent)

OK

>        ip->fixp[0] = fix_new_exp (ip->frag, ip->where,
>  				 bfd_get_reloc_size (howto),
>  				 address_expr,
> -				 howto->pc_relative, final_type[0]);
> +				 howto0 && howto0->pc_relative,
> +				 final_type[0]);

The howto0 variable and null check are OK.  Please leave the rest as-is.

> Index: binutils-fsf-trunk-quilt/bfd/elfxx-mips.c
> ===================================================================
> --- binutils-fsf-trunk-quilt.orig/bfd/elfxx-mips.c	2011-07-28 23:18:50.000000000 +0100
> +++ binutils-fsf-trunk-quilt/bfd/elfxx-mips.c	2011-07-28 23:30:26.000000000 +0100
> @@ -11910,8 +11910,7 @@ mips_elf_relax_delete_bytes (bfd *abfd,
>    symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
>    isym = (Elf_Internal_Sym *) symtab_hdr->contents;
>    for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
> -    if (isym->st_shndx == sec_shndx
> -	&& isym->st_value > addr)
> +    if (isym->st_shndx == sec_shndx && isym->st_value > addr)
>        isym->st_value -= count;
>  
>    /* Now adjust the global symbols defined in this section.  */

OK

> @@ -11989,7 +11987,7 @@ static const struct opcode_descriptor b_
>    { /* "b",	"mD",		*/ 0xcc00,     0xfc00 };
>  
>  static const struct opcode_descriptor bz_insn_16 =
> -  { /* "b(eq|ne)z", "md,mE",	*/ 0x8c00,     0xac00 };
> +  { /* "b(eq|ne)z", "md,mE",	*/ 0x8c00,     0xdc00 };
>  
>  
>  /* 32-bit and 16-bit branch EQ and NE zero.  */

I don't recall discussing this.  Is it a separate thing you noticed?
OK regardless.

> @@ -12241,7 +12239,7 @@ check_br16 (bfd *abfd, bfd_byte *ptr, un
>  /* If PTR points to a 32-bit branch or jump that doesn't fiddle with REG,
>     then return TRUE, otherwise FALSE.  */
>  
> -static int
> +static bfd_boolean
>  check_br32 (bfd *abfd, bfd_byte *ptr, unsigned long reg)
>  {
>    unsigned long opcode;

Likewise.

> @@ -12361,6 +12364,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
>  	  else if (!bfd_malloc_and_get_section (abfd, sec, &contents))
>  	    goto error_return;
>  	}
> +      ptr = contents + irel->r_offset;
>  
>        /* Read this BFD's local symbols if we haven't done so already.  */
>        if (isymbuf == NULL && symtab_hdr->sh_info != 0)

OK

> @@ -12432,8 +12436,8 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
>        if (irel->r_offset + 4 > sec->size)
>  	continue;
>  
> -      opcode  = bfd_get_16 (abfd, contents + irel->r_offset    ) << 16;
> -      opcode |= bfd_get_16 (abfd, contents + irel->r_offset + 2);
> +      opcode  = bfd_get_16 (abfd, ptr    ) << 16;
> +      opcode |= bfd_get_16 (abfd, ptr + 2);
>  
>        /* This is the pc-relative distance from the instruction the
>           relocation is applied to, to the symbol referred.  */

OK

> @@ -12452,6 +12456,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
>           out the offset).  */
>        if (r_type == R_MICROMIPS_HI16 && MATCH (opcode, lui_insn))
>  	{
> +	  bfd_boolean bzc = FALSE;
>  	  unsigned long nextopc;
>  	  unsigned long reg;
>  	  bfd_vma offset;
and:
> @@ -12475,19 +12480,19 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
>  	      && ELF32_R_SYM (irel[2].r_info) == r_symndx)
>  	    continue;
>  
> -	  /* See if the LUI instruction *might* be in a branch delay slot.  */
> +	  /* See if the LUI instruction *might* be in a branch delay slot.
> +	     We check whether what looks like a 16-bit branch or jump is
> +	     actually an immediate argument to a compact branch, and let
> +	     it through if so.  */
>  	  if (irel->r_offset >= 2
> -	      && check_br16_dslot (abfd, contents + irel->r_offset - 2) > 0
> +	      && check_br16_dslot (abfd, ptr - 2)
>  	      && !(irel->r_offset >= 4
> -		   /* If the instruction is actually a 4-byte branch,
> -		      the value of check_br16_dslot doesn't matter.
> -		      We should use check_br32_dslot to check whether
> -		      the branch has a delay slot.  */
> -		   && check_4byte_branch (internal_relocs, irelend,
> -					  irel->r_offset - 4)))
> +		   && (bzc = check_bzc (abfd, ptr - 4, irel->r_offset - 4,
> +					internal_relocs, irelend))))
>  	    continue;
>  	  if (irel->r_offset >= 4
> -	      && check_br32_dslot (abfd, contents + irel->r_offset - 4) > 0)
> +	      && !bzc
> +	      && check_br32_dslot (abfd, ptr - 4))
>  	    continue;
>  
>  	  reg = OP32_SREG (opcode);

As regards what you were saying about straightening the patch up:
I think this is the one bit that ought to be split out separately
and treated as a separate patch.  The bzc variable and !bzc check
look suspiciously redundant.

The use of "ptr" is OK now though.

> @@ -12502,11 +12507,11 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
>  	    case 0:
>  	      break;
>  	    case 2:
> -	      if (check_br16 (abfd, contents + irel->r_offset + 4, reg))
> +	      if (check_br16 (abfd, ptr + 4, reg))
>  		break;
>  	      continue;
>  	    case 4:
> -	      if (check_br32 (abfd, contents + irel->r_offset + 4, reg))
> +	      if (check_br32 (abfd, ptr + 4, reg))
>  		break;
>  	      continue;
>  	    default:

OK

> @@ -12581,8 +12586,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
>  	       && irel->r_offset + 5 < sec->size
>  	       && ((fndopc = find_match (opcode, bz_rs_insns_32)) >= 0
>  		   || (fndopc = find_match (opcode, bz_rt_insns_32)) >= 0)
> -	       && MATCH (bfd_get_16 (abfd, contents + irel->r_offset + 4),
> -			 nop_insn_16))
> +	       && MATCH (bfd_get_16 (abfd, ptr + 4), nop_insn_16))
>  	{
>  	  unsigned long reg;
>  

OK

> @@ -12593,10 +12597,8 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
>  		    | BZC32_REG_FIELD (reg)
>  		    | (opcode & 0xffff));		/* Addend value.  */
>  
> -	  bfd_put_16 (abfd, (opcode >> 16) & 0xffff,
> -		      contents + irel->r_offset);
> -	  bfd_put_16 (abfd,  opcode        & 0xffff,
> -		      contents + irel->r_offset + 2);
> +	  bfd_put_16 (abfd, (opcode >> 16) & 0xffff, ptr);
> +	  bfd_put_16 (abfd,  opcode        & 0xffff, ptr + 2);
>  
>  	  /* Delete the 16-bit delay slot NOP: two bytes from
>  	     irel->offset + 4.  */

OK

> @@ -12617,7 +12619,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
>  	  bfd_put_16 (abfd,
>  		      (b_insn_16.match
>  		       | (opcode & 0x3ff)),		/* Addend value.  */
> -		      contents + irel->r_offset);
> +		      ptr);
>  
>  	  /* Delete 2 bytes from irel->r_offset + 2.  */
>  	  delcnt = 2;

OK

> @@ -12645,7 +12647,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
>  		      (bz_insns_16[fndopc].match
>  		       | BZ16_REG_FIELD (reg)
>  		       | (opcode & 0x7f)),		/* Addend value.  */
> -		      contents + irel->r_offset);
> +		      ptr);
>  
>  	  /* Delete 2 bytes from irel->r_offset + 2.  */
>  	  delcnt = 2;

OK

> @@ -12661,14 +12663,13 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
>  	  unsigned long n32opc;
>  	  bfd_boolean relaxed = FALSE;
>  
> -	  n32opc  = bfd_get_16 (abfd, contents + irel->r_offset + 4) << 16;
> -	  n32opc |= bfd_get_16 (abfd, contents + irel->r_offset + 6);
> +	  n32opc  = bfd_get_16 (abfd, ptr + 4) << 16;
> +	  n32opc |= bfd_get_16 (abfd, ptr + 6);
>  
>  	  if (MATCH (n32opc, nop_insn_32))
>  	    {
>  	      /* Replace delay slot 32-bit NOP with a 16-bit NOP.  */
> -	      bfd_put_16 (abfd, nop_insn_16.match,
> -			  contents + irel->r_offset + 4);
> +	      bfd_put_16 (abfd, nop_insn_16.match, ptr + 4);
>  
>  	      relaxed = TRUE;
>  	    }

OK

> @@ -12679,7 +12680,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
>  			  (move_insn_16.match
>  			   | MOVE16_RD_FIELD (MOVE32_RD (n32opc))
>  			   | MOVE16_RS_FIELD (MOVE32_RS (n32opc))),
> -			  contents + irel->r_offset + 4);
> +			  ptr + 4);
>  
>  	      relaxed = TRUE;
>  	    }

OK

> @@ -12691,9 +12692,9 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
>  	      /* JAL with 32-bit delay slot that is changed to a JALS
>  	         with 16-bit delay slot.  */
>  	      bfd_put_16 (abfd, (jal_insn_32_bd16.match >> 16) & 0xffff,
> -			  contents + irel->r_offset);
> +			  ptr);
>  	      bfd_put_16 (abfd,  jal_insn_32_bd16.match        & 0xffff,
> -			  contents + irel->r_offset + 2);
> +			  ptr + 2);
>  
>  	      /* Delete 2 bytes from irel->r_offset + 6.  */
>  	      delcnt = 2;

OK

> Index: binutils-fsf-trunk-quilt/include/opcode/mips.h
> ===================================================================
> --- binutils-fsf-trunk-quilt.orig/include/opcode/mips.h	2011-07-28 23:29:25.000000000 +0100
> +++ binutils-fsf-trunk-quilt/include/opcode/mips.h	2011-07-28 23:30:26.000000000 +0100
> @@ -1332,13 +1332,10 @@ extern int bfd_mips_num_opcodes;
>  extern const struct mips_opcode mips16_opcodes[];
>  extern const int bfd_mips16_num_opcodes;
>  
> -/* These are the bitmasks and shift counts used for the different
> -   fields in the instruction formats.  Other than MAJOR, no masks are
> -   provided for the fixed portions of an instruction, since they are
> -   not needed.  */
> +/* These are the bit masks and shift counts used for the different fields
> +   in the microMIPS instruction formats.  No masks are provided for the
> +   fixed portions of an instruction, since they are not needed.  */
>  
> -#define MICROMIPSOP_MASK_MAJOR		0x3f
> -#define MICROMIPSOP_SH_MAJOR		26
>  #define MICROMIPSOP_MASK_IMMEDIATE	0xffff
>  #define MICROMIPSOP_SH_IMMEDIATE	0
>  #define MICROMIPSOP_MASK_DELTA		0xffff

OK

Thanks,
Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] MIPS: microMIPS ASE support
  2011-07-29 11:30                       ` Richard Sandiford
@ 2011-07-29 22:52                         ` Maciej W. Rozycki
  0 siblings, 0 replies; 41+ messages in thread
From: Maciej W. Rozycki @ 2011-07-29 22:52 UTC (permalink / raw)
  To: Richard Sandiford
  Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
	Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers

On Fri, 29 Jul 2011, Richard Sandiford wrote:

> >>  There's a whole lot of important linker relaxation fixes that I reckon 
> >> were not included in the original series plus several bug fixes.
> >
> >  I'll work on these fixes now -- there are quite a few and at least one 
> > still requires some work not to be considered a dirty hack -- and will be 
> > back with you shortly.
> 
> Thanks.  This is what I asked for in the first place: that anything we
> hadn't caught should be dealt with as follow-ups, rather than folded
> into the huge initial commit.  (For reference, even the .tar.bz2 was
> over 280k.)  I still don't understand why you chose to ignore that.

 Well, I believed this was really what I did -- with all these 
binutils-ld-lib.diff, binutils-umips-fix.diff, 
binutils-umips-opcode-trap.diff, binutils-umips-relax16.diff, 
binutils-umips-fix-reloc.diff patches (and all the outstanding ones that 
add up to six right now, but will probably become seven or eight) -- but 
if that wasn't what you intended, then I apologise for misunderstanding.  

> The whole point of approving most of the submission with a few minor
> changes (back in March) was that it would be quick to make those changes
> and get the whole thing into CVS.  It would then be much easier for me
> to review any further changes you wanted to make.  I also assumed that
> it would be easier for you to submit them.

 The problem was I was pulled off to another project as a matter of 
emergency -- apart from the update to take your recent register use 
tracking changes into account I did last week, I haven't really touched 
the pieces for a couple of months now.  Sorry about that.

 I'll go on to explain the bits you had anything but "OK" to say about, 
commit the bits you are happy with and then we can continue with the rest.

> > @@ -2893,18 +2888,21 @@ relax_end (void)
> >    mips_relax.sequence = 0;
> >  }
> >  
> > -/* Return the mask of core registers that instruction IP may
> > -   read or write.  */
> > +/* Return the mask of core registers that IP reads or writes.  */
> >  
> >  static unsigned int
> >  gpr_mod_mask (const struct mips_cl_insn *ip)
> >  {
> > -  unsigned long pinfo, pinfo2;
> > +  unsigned long pinfo2;
> >    unsigned int mask;
> >  
> >    mask = 0;
> > -  pinfo = ip->insn_mo->pinfo;
> >    pinfo2 = ip->insn_mo->pinfo2;
> > +  if (!mips_opts.mips16)
> > +    {
> > +      if (pinfo2 & INSN2_MOD_SP)
> > +	mask |= 1 << SP;
> > +    }
> >    if (mips_opts.micromips)
> >      {
> >        if (pinfo2 & INSN2_MOD_GPR_MB)
> and:
> > @@ -2934,8 +2932,6 @@ gpr_mod_mask (const struct mips_cl_insn 
> >  	mask |= 1 << EXTRACT_OPERAND (1, MP, *ip);
> >        if (pinfo2 & INSN2_MOD_GPR_MQ)
> >  	mask |= 1 << micromips_to_32_reg_q_map[EXTRACT_OPERAND (1, MQ, *ip)];
> > -      if (pinfo2 & INSN2_MOD_SP)
> > -	mask |= 1 << SP;
> >      }
> >    return mask;
> >  }
> 
> *sigh*  Have I introduced another write to an unused variable? :-(
> I really should use a more modern compiler.
> 
> The removal of pinfo is OK, thanks.  The rest of it doesn't look like
> an improvement.

 For the sake of consistency I put all the pinfo/2 flag interpretation 
that does not involve microMIPS-specific structures (i.e. 
micromips_to_32_reg_*_map) into (!mips_opts.mips16) rather than 
(mips_opts.micromips) condition blocks under the assumption we don't have 
to imply their microMIPS-ness here.

 Obviously this includes the INSN2_MOD_SP flag as it's self-contained in 
that it determines the register accessed itself, though it probably has 
little chance to be useful for non-microMIPS code even with possible 
future extensions to the base architecture.  Therefore I won't insist on 
this change even though it's consistent with the usage of INSN2_READ_GP 
and INSN2_READ_GPR_31 flags in gpr_read_mask().

> >        ip->fixp[0] = fix_new_exp (ip->frag, ip->where,
> >  				 bfd_get_reloc_size (howto),
> >  				 address_expr,
> > -				 howto->pc_relative, final_type[0]);
> > +				 howto0 && howto0->pc_relative,
> > +				 final_type[0]);
> 
> The howto0 variable and null check are OK.  Please leave the rest as-is.

 There's no need to reiterate checking for non-BFD_RELOC_UNUSED that's 
been already done earlier on.  I'll split it off for further 
consideration.

> > @@ -11989,7 +11987,7 @@ static const struct opcode_descriptor b_
> >    { /* "b",	"mD",		*/ 0xcc00,     0xfc00 };
> >  
> >  static const struct opcode_descriptor bz_insn_16 =
> > -  { /* "b(eq|ne)z", "md,mE",	*/ 0x8c00,     0xac00 };
> > +  { /* "b(eq|ne)z", "md,mE",	*/ 0x8c00,     0xdc00 };
> >  
> >  
> >  /* 32-bit and 16-bit branch EQ and NE zero.  */
> 
> I don't recall discussing this.  Is it a separate thing you noticed?
> OK regardless.

 Well, there's nothing to discuss here -- it's a plain bug, the old mask 
is wrong and there was no need to handle it separately -- in fact the 
opposite was the case as it makes no sense to check in known-buggy code.

 I'll split it off and commit separately for clarity.

> > @@ -12241,7 +12239,7 @@ check_br16 (bfd *abfd, bfd_byte *ptr, un
> >  /* If PTR points to a 32-bit branch or jump that doesn't fiddle with REG,
> >     then return TRUE, otherwise FALSE.  */
> >  
> > -static int
> > +static bfd_boolean
> >  check_br32 (bfd *abfd, bfd_byte *ptr, unsigned long reg)
> >  {
> >    unsigned long opcode;
> 
> Likewise.

 I'll split it off too.

> > @@ -12452,6 +12456,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
> >           out the offset).  */
> >        if (r_type == R_MICROMIPS_HI16 && MATCH (opcode, lui_insn))
> >  	{
> > +	  bfd_boolean bzc = FALSE;
> >  	  unsigned long nextopc;
> >  	  unsigned long reg;
> >  	  bfd_vma offset;
> and:
> > @@ -12475,19 +12480,19 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
> >  	      && ELF32_R_SYM (irel[2].r_info) == r_symndx)
> >  	    continue;
> >  
> > -	  /* See if the LUI instruction *might* be in a branch delay slot.  */
> > +	  /* See if the LUI instruction *might* be in a branch delay slot.
> > +	     We check whether what looks like a 16-bit branch or jump is
> > +	     actually an immediate argument to a compact branch, and let
> > +	     it through if so.  */
> >  	  if (irel->r_offset >= 2
> > -	      && check_br16_dslot (abfd, contents + irel->r_offset - 2) > 0
> > +	      && check_br16_dslot (abfd, ptr - 2)
> >  	      && !(irel->r_offset >= 4
> > -		   /* If the instruction is actually a 4-byte branch,
> > -		      the value of check_br16_dslot doesn't matter.
> > -		      We should use check_br32_dslot to check whether
> > -		      the branch has a delay slot.  */
> > -		   && check_4byte_branch (internal_relocs, irelend,
> > -					  irel->r_offset - 4)))
> > +		   && (bzc = check_bzc (abfd, ptr - 4, irel->r_offset - 4,
> > +					internal_relocs, irelend))))
> >  	    continue;
> >  	  if (irel->r_offset >= 4
> > -	      && check_br32_dslot (abfd, contents + irel->r_offset - 4) > 0)
> > +	      && !bzc
> > +	      && check_br32_dslot (abfd, ptr - 4))
> >  	    continue;
> >  
> >  	  reg = OP32_SREG (opcode);
> 
> As regards what you were saying about straightening the patch up:
> I think this is the one bit that ought to be split out separately
> and treated as a separate patch.  The bzc variable and !bzc check
> look suspiciously redundant.

 It's a small optimisation -- if we've established for sure the 
instruction before is a compact branch, then there's no need to go through 
the hoops and check if it's an ordinary branch too -- which it will never 
be.

 I'll split this change off of course.

 Thanks for the quick review.

  Maciej

^ permalink raw reply	[flat|nested] 41+ messages in thread

end of thread, other threads:[~2011-07-29 17:40 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-05-18 18:19 [PATCH] MIPS: microMIPS and MCU ASE instruction set support Maciej W. Rozycki
2010-05-23 21:38 ` Richard Sandiford
2010-05-24 22:25   ` Fu, Chao-Ying
2010-05-26 19:47     ` Richard Sandiford
2010-06-01 14:21   ` Maciej W. Rozycki
2010-06-01 14:39     ` Catherine Moore
2010-06-01 22:04     ` Richard Sandiford
2010-06-01 22:47     ` Fu, Chao-Ying
2010-06-05  9:17     ` Richard Sandiford
2010-07-26 10:56   ` [PATCH] MIPS: microMIPS ASE support Maciej W. Rozycki
2010-07-26 13:25     ` Nathan Froyd
2010-07-26 13:53       ` Maciej W. Rozycki
2010-07-26 19:03     ` Richard Sandiford
2010-12-07  1:13       ` Maciej W. Rozycki
2010-12-12 14:59         ` Richard Sandiford
2010-12-14 13:30           ` Maciej W. Rozycki
2010-12-14 14:51             ` Richard Sandiford
2010-12-16 11:54               ` Maciej W. Rozycki
2010-12-18 10:26                 ` Richard Sandiford
2010-12-14 17:56             ` Joseph S. Myers
2010-12-16 15:28               ` Maciej W. Rozycki
2010-12-17 20:56             ` Fu, Chao-Ying
2010-12-18 10:09               ` Richard Sandiford
2011-01-02 11:36         ` Richard Sandiford
2011-02-21 15:35           ` Maciej W. Rozycki
2011-02-22 20:12             ` Fu, Chao-Ying
2011-02-22 20:19             ` Fu, Chao-Ying
2011-02-24 10:46               ` Maciej W. Rozycki
2011-02-26 11:41                 ` Richard Sandiford
2011-02-28 16:41                   ` Maciej W. Rozycki
2011-02-26  0:00             ` Maciej W. Rozycki
2011-03-13  9:23               ` Richard Sandiford
2011-07-25  7:49                 ` Richard Sandiford
2011-07-26  2:01                   ` Maciej W. Rozycki
2011-07-29  0:58                     ` Maciej W. Rozycki
2011-07-29 11:30                       ` Richard Sandiford
2011-07-29 22:52                         ` Maciej W. Rozycki
2011-02-26 11:36             ` Richard Sandiford
2011-07-26 14:00               ` Maciej W. Rozycki
2010-05-26 20:19 ` [PATCH] MIPS: microMIPS and MCU ASE instruction set support Richard Sandiford
2010-05-27 21:39 ` Richard Sandiford

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).