Discussion:
[PATCH] MIPS: microMIPS and MCU ASE instruction set support
(too old to reply)
Maciej W. Rozycki
2010-05-18 18:18:29 UTC
Permalink
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 <***@mips.com>
Ilie Garbacea <***@mips.com>
Maciej W. Rozycki <***@codesourcery.com>
Joseph Myers <***@codesourcery.com>
Catherine Moore <***@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 <***@mips.com>

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

gas/
2010-05-18 Chao-ying Fu <***@mips.com>
Maciej W. Rozycki <***@codesourcery.com>
Daniel Jacobowitz <***@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 <***@codesourcery.com>
Chao-ying 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/***@abs.d: New test.
* gas/mips/***@add.d: Likewise.
* gas/mips/***@and.d: Likewise.
* gas/mips/***@beq.d: Likewise.
* gas/mips/***@bge.d: Likewise.
* gas/mips/***@bgeu.d: Likewise.
* gas/mips/***@blt.d: Likewise.
* gas/mips/***@bltu.d: Likewise.
* gas/mips/***@branch-likely.d: Likewise.
* gas/mips/***@branch-misc-1.d: Likewise.
* gas/mips/***@branch-misc-2-64.d: Likewise.
* gas/mips/***@branch-misc-2.d: Likewise.
* gas/mips/***@branch-misc-2pic-64.d: Likewise.
* gas/mips/***@branch-misc-2pic.d: Likewise.
* gas/mips/***@dli.d: Likewise.
* gas/mips/***@elf-jal.d: Likewise.
* gas/mips/***@elf-rel2.d: Likewise.
* gas/mips/***@elf-rel4.d: Likewise.
* gas/mips/***@lb-svr4pic-ilocks.d: Likewise.
* gas/mips/***@li.d: Likewise.
* gas/mips/***@mips1-fp.d: Likewise.
* gas/mips/***@mips32-cp2.d: Likewise.
* gas/mips/***@mips32-imm.d: Likewise.
* gas/mips/***@mips32-sf32.d: Likewise.
* gas/mips/***@mips32.d: Likewise.
* gas/mips/***@mips32r2-cp2.d: Likewise.
* gas/mips/***@mips32r2-fp32.d: Likewise.
* gas/mips/***@mips32r2.d: Likewise.
* gas/mips/***@mips4-branch-likely.d: Likewise.
* gas/mips/***@mips4-fp.d: Likewise.
* gas/mips/***@mips4.d: Likewise.
* gas/mips/***@mips5.d: Likewise.
* gas/mips/***@mips64-cp2.d: Likewise.
* gas/mips/***@mips64.d: Likewise.
* gas/mips/***@mips64r2.d: Likewise.
* gas/mips/***@rol-hw.d: Likewise.
* gas/mips/***@uld2-eb.d: Likewise.
* gas/mips/***@uld2-el.d: Likewise.
* gas/mips/***@ulh2-eb.d: Likewise.
* gas/mips/***@ulh2-el.d: Likewise.
* gas/mips/***@ulw2-eb-ilocks.d: Likewise.
* gas/mips/***@ulw2-el-ilocks.d: Likewise.
* gas/mips/mips32-imm.d: Likewise.
* gas/mips/mips32.d: Update immediates.
* gas/mips/***@mips32-cp2.s: New test source.
* gas/mips/***@mips32-imm.s: Likewise.
* gas/mips/***@mips32r2-cp2.s: Likewise.
* gas/mips/***@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/***@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/***@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/***@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 <***@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 <***@mips.com>
Maciej W. Rozycki <***@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 <***@codesourcery.com>
Chao-ying Fu <***@mips.com>
Maciej W. Rozycki <***@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 <***@mips.com>
Maciej W. Rozycki <***@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.
Richard Sandiford
2010-05-23 21:38:30 UTC
Permalink
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?
.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".
Post by Maciej W. Rozycki
gas/
* 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)

?
Post by Maciej W. Rozycki
(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.
Post by Maciej W. Rozycki
(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?
Post by Maciej W. Rozycki
(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.
Post by Maciej W. Rozycki
(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.
Post by Maciej W. Rozycki
(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.)
Post by Maciej W. Rozycki
(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.
Post by Maciej W. Rozycki
(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.
Post by Maciej W. Rozycki
(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.
Post by Maciej W. Rozycki
(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.
Post by Maciej W. Rozycki
(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...
Post by Maciej W. Rozycki
(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?
Post by Maciej W. Rozycki
(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.
Post by Maciej W. Rozycki
(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.
Post by Maciej W. Rozycki
(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.
Post by Maciej W. Rozycki
(micromips_macro_build): Likewise.
(micromips_macro): Likewise.
I'll look at micromips_ip and these two in more detail later.
Post by Maciej W. Rozycki
* 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
Fu, Chao-Ying
2010-05-24 22:24:13 UTC
Permalink
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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
Richard Sandiford
2010-05-26 19:47:11 UTC
Permalink
Post by Fu, Chao-Ying
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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.
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. */
/* Return the beginning of the delay slot from the current insn.
*/
return 2;
/* 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
Maciej W. Rozycki
2010-06-01 14:19:24 UTC
Permalink
Hi Richard,
Post by Richard Sandiford
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.
Post by Richard Sandiford
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.
Post by Richard Sandiford
.set micromips
.ent foo
b 1f
nop
.end foo
.ent bar
1: nop
.end bar
0: cfff b 0 <foo>
0: R_MICROMIPS_PC10_S1 .L11
2: 0c00 nop
4: 0c00 nop
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 .L11

Any other ideas, anyone?
Post by Richard Sandiford
.set micromips
.ent foo
ld $10,0x1000($11)
.end foo
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...
Post by Richard Sandiford
Post by Maciej W. Rozycki
gas/
* config/tc-mips.h (mips_segment_info): Add one bit for
microMIPS.
* config/tc-mips.c
#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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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?
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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.
Post by Richard Sandiford
+ 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.
Post by Richard Sandiford
+ /* For microMIPS, disable reordering. */
+ || (mips_opts.micromips)
Redundant (...)
Fixed.
Post by Richard Sandiford
- 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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.
Post by Richard Sandiford
+ /* If either one implementation contains one instruction, we need to check
+ the delay slot size requirement. */
"If either implementation"
Fixed.
Post by Richard Sandiford
+ /* 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?
Post by Richard Sandiford
+ 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?
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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?
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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?
Post by Richard Sandiford
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...
Post by Richard Sandiford
- 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.
Post by Richard Sandiford
- 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.
Post by Richard Sandiford
+ /* 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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);
+ }
}
if (((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
== ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))
behaviour.
Chao-ying?
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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;
+ }
+ 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;
+ }
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
if (t + 2 != (s ? s : save_s))
would be enough. Errors should start with a capital letter. Missing
internationalisation.
Chao-ying?
Post by Richard Sandiford
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.
Post by Richard Sandiford
+ 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;
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.
Post by Richard Sandiford
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.
Post by Richard Sandiford
+ }
+ }
+ /* 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
(micromips_macro_build): Likewise.
(micromips_macro): Likewise.
I'll look at micromips_ip and these two in more detail later.
Me too. ;)
Post by Richard Sandiford
Post by Maciej W. Rozycki
* 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 <***@mips.com>
Ilie Garbacea <***@mips.com>
Maciej W. Rozycki <***@codesourcery.com>
Joseph Myers <***@codesourcery.com>
Catherine Moore <***@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 <***@mips.com>

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

gas/
2010-06-01 Chao-ying Fu <***@mips.com>
Maciej W. Rozycki <***@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 <***@codesourcery.com>
Chao-ying 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/***@abs.d: New test.
* gas/mips/***@add.d: Likewise.
* gas/mips/***@and.d: Likewise.
* gas/mips/***@beq.d: Likewise.
* gas/mips/***@bge.d: Likewise.
* gas/mips/***@bgeu.d: Likewise.
* gas/mips/***@blt.d: Likewise.
* gas/mips/***@bltu.d: Likewise.
* gas/mips/***@branch-likely.d: Likewise.
* gas/mips/***@branch-misc-1.d: Likewise.
* gas/mips/***@branch-misc-2-64.d: Likewise.
* gas/mips/***@branch-misc-2.d: Likewise.
* gas/mips/***@branch-misc-2pic-64.d: Likewise.
* gas/mips/***@branch-misc-2pic.d: Likewise.
* gas/mips/***@dli.d: Likewise.
* gas/mips/***@elf-jal.d: Likewise.
* gas/mips/***@elf-rel2.d: Likewise.
* gas/mips/***@elf-rel4.d: Likewise.
* gas/mips/***@lb-svr4pic-ilocks.d: Likewise.
* gas/mips/***@li.d: Likewise.
* gas/mips/***@mips1-fp.d: Likewise.
* gas/mips/***@mips32-cp2.d: Likewise.
* gas/mips/***@mips32-imm.d: Likewise.
* gas/mips/***@mips32-sf32.d: Likewise.
* gas/mips/***@mips32.d: Likewise.
* gas/mips/***@mips32r2-cp2.d: Likewise.
* gas/mips/***@mips32r2-fp32.d: Likewise.
* gas/mips/***@mips32r2.d: Likewise.
* gas/mips/***@mips4-branch-likely.d: Likewise.
* gas/mips/***@mips4-fp.d: Likewise.
* gas/mips/***@mips4.d: Likewise.
* gas/mips/***@mips5.d: Likewise.
* gas/mips/***@mips64-cp2.d: Likewise.
* gas/mips/***@mips64.d: Likewise.
* gas/mips/***@mips64r2.d: Likewise.
* gas/mips/***@rol-hw.d: Likewise.
* gas/mips/***@uld2-eb.d: Likewise.
* gas/mips/***@uld2-el.d: Likewise.
* gas/mips/***@ulh2-eb.d: Likewise.
* gas/mips/***@ulh2-el.d: Likewise.
* gas/mips/***@ulw2-eb-ilocks.d: Likewise.
* gas/mips/***@ulw2-el-ilocks.d: Likewise.
* gas/mips/mips32-imm.d: Likewise.
* gas/mips/mips32.d: Update immediates.
* gas/mips/***@mips32-cp2.s: New test source.
* gas/mips/***@mips32-imm.s: Likewise.
* gas/mips/***@mips32r2-cp2.s: Likewise.
* gas/mips/***@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/***@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/***@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 <***@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 <***@mips.com>
Maciej W. Rozycki <***@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 <***@codesourcery.com>
Chao-ying Fu <***@mips.com>
Maciej W. Rozycki <***@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 <***@mips.com>
Maciej W. Rozycki <***@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.
Catherine Moore
2010-06-01 14:35:19 UTC
Permalink
Post by Maciej W. Rozycki
Hi Richard,
Post by Richard Sandiford
Post by Maciej W. Rozycki
* 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
Richard Sandiford
2010-06-01 22:04:33 UTC
Permalink
Post by Maciej W. Rozycki
Post by Richard Sandiford
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!
Post by Maciej W. Rozycki
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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
.set micromips
.ent foo
b 1f
nop
.end foo
.ent bar
1: nop
.end bar
0: cfff b 0 <foo>
0: R_MICROMIPS_PC10_S1 .L11
2: 0c00 nop
4: 0c00 nop
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
$ cat b.s
.globl baz
.ent foo
b baz
nop
.end foo
.ent bar
1: nop
.end bar
$ mips-sde-elf-objdump -dr b.o
b.o: file format elf32-tradbigmips
0: 1000ffff b 0 <foo>
0: R_MIPS_PC16 baz
4: 00000000 nop
8: 00000000 nop
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.
Post by Maciej W. Rozycki
I'd just recommend peeking at the symbol table (back to the first
$ mips-sde-elf-objdump -t b.o
b.o: file format elf32-tradbigmips
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 .L11
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).
Post by Maciej W. Rozycki
Post by Richard Sandiford
.set micromips
.ent foo
ld $10,0x1000($11)
.end foo
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".
[...]
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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
gas/
* config/tc-mips.h (mips_segment_info): Add one bit for
microMIPS.
* config/tc-mips.c
#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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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. ;-)
Post by Maciej W. Rozycki
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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
+ 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...
Post by Maciej W. Rozycki
Post by Richard Sandiford
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
Fu, Chao-Ying
2010-06-01 22:45:36 UTC
Permalink
Post by Maciej W. Rozycki
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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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.
Likewise.
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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"
Post by Richard Sandiford
+ " that requires a 16-bit or 32-bit instruction");
Did you consider adding a flag to distinguish the 32-bit
and 16-bit cases?
Post by Richard Sandiford
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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
+ /* If either one implementation contains one
instruction, we need to check
Post by Richard Sandiford
+ 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]
Post by Richard Sandiford
+ && 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
Post by Richard Sandiford
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;
}
}
Post by Maciej W. Rozycki
Post by Richard Sandiford
+ 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
Post by Richard Sandiford
controlled cases where a macro has a single-insn expansion
that is the
Post by Richard Sandiford
wrong size, which ought to be handled by the block above.
If the code
Post by Richard Sandiford
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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
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...
Post by Richard Sandiford
Post by Maciej W. Rozycki
(md_convert_frag): Likewise.
- /* Possibly emit a warning if we've chosen the
longer option. */
Post by Richard Sandiford
- 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. */
Post by Richard Sandiford
+ 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);
+ }
}
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);
}
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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))
Post by Richard Sandiford
+ == 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";
Post by Richard Sandiford
+ 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. */
Post by Richard Sandiford
+ 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))
Post by Richard Sandiford
+ == 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";
Post by Richard Sandiford
+ return;
+ }
+ 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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
+ /* 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;
+ }
s = strchr (str, '.');
Yes.
Post by Maciej W. Rozycki
Post by Richard Sandiford
followed by the two checks. Isn't the ISSPACE check
redundant though,
Post by Richard Sandiford
given that you've terminated the string at the first space? I would
if (t + 2 != (s ? s : save_s))
would be enough. Errors should start with a capital
letter. Missing
Post by Richard Sandiford
internationalisation.
Chao-ying?
Yes. "if (t + 2 != (s ? s : save_s))" is enough.
Post by Maciej W. Rozycki
Post by Richard Sandiford
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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
+ if (!insn_error)
+ {
+ static char buf[100];
+ sprintf (buf,
+ _("opcode not supported on this
processor: %s (%s)"),
Post by Richard Sandiford
+ mips_cpu_info_from_arch
(mips_opts.arch)->name,
Post by Richard Sandiford
+ mips_cpu_info_from_isa
(mips_opts.isa)->name);
Post by Richard Sandiford
+ 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";
Post by Richard Sandiford
+ str[i + 1] = '6';
+ str[i] = '1';
+ }
+ else
+ {
+ insn_error =
+ "unrecognized 32-bit version of
microMIPS opcode";
Post by Richard Sandiford
+ str[i + 1] = '2';
+ str[i] = '3';
+ }
+ str[length + 2] = '\0';
+ }
+ return;
jar16 $30,$26
Error: unrecognized 16-bit version of microMIPS opcode
`jar16 $30,$26'
Post by Richard Sandiford
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
.set micromips
.set noreorder
bltzall $2, bar
addiusp 256
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
Richard Sandiford
2010-06-05 09:17:01 UTC
Permalink
Post by Maciej W. Rozycki
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
Maciej W. Rozycki
2010-07-26 10:55:20 UTC
Permalink
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?
Post by Fu, Chao-Ying
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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.
Likewise.
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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.
Post by Fu, Chao-Ying
Post by Maciej W. Rozycki
(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.
Post by Fu, Chao-Ying
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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"
Post by Richard Sandiford
+ " that requires a 16-bit or 32-bit instruction");
Did you consider adding a flag to distinguish the 32-bit
and 16-bit cases?
Post by Richard Sandiford
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.
Post by Fu, Chao-Ying
Post by Maciej W. Rozycki
Post by Richard Sandiford
+ /* If either one implementation contains one
instruction, we need to check
Post by Richard Sandiford
+ 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]
Post by Richard Sandiford
+ && 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
Post by Richard Sandiford
ERROR_SECOND are set?
Chao-ying?
Do you mean this kind of code?
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;
}
}
Post by Maciej W. Rozycki
Post by Richard Sandiford
+ 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
Post by Richard Sandiford
controlled cases where a macro has a single-insn expansion
that is the
Post by Richard Sandiford
wrong size, which ought to be handled by the block above.
If the code
Post by Richard Sandiford
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.
Post by Fu, Chao-Ying
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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[].
Post by Fu, Chao-Ying
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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.
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.
Post by Fu, Chao-Ying
+ /* 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]
Post by Fu, Chao-Ying
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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.
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. */
/* Return the beginning of the delay slot from the current insn.
*/
return 2;
/* 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...
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.
Post by Fu, Chao-Ying
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
(md_convert_frag): Likewise.
- /* Possibly emit a warning if we've chosen the
longer option. */
Post by Richard Sandiford
- 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. */
Post by Richard Sandiford
+ 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);
+ }
}
if (((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
== ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))
behaviour.
Chao-ying?
How about this?
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().
Post by Fu, Chao-Ying
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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))
Post by Richard Sandiford
+ == 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";
Post by Richard Sandiford
+ 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. */
Post by Richard Sandiford
+ 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))
Post by Richard Sandiford
+ == 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";
Post by Richard Sandiford
+ return;
+ }
+ 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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
+ /* 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;
+ }
s = strchr (str, '.');
Yes.
Post by Maciej W. Rozycki
Post by Richard Sandiford
followed by the two checks. Isn't the ISSPACE check
redundant though,
Post by Richard Sandiford
given that you've terminated the string at the first space? I would
if (t + 2 != (s ? s : save_s))
would be enough. Errors should start with a capital
letter. Missing
Post by Richard Sandiford
internationalisation.
Chao-ying?
Yes. "if (t + 2 != (s ? s : save_s))" is enough.
Post by Maciej W. Rozycki
Post by Richard Sandiford
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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
+ if (!insn_error)
+ {
+ static char buf[100];
+ sprintf (buf,
+ _("opcode not supported on this
processor: %s (%s)"),
Post by Richard Sandiford
+ mips_cpu_info_from_arch
(mips_opts.arch)->name,
Post by Richard Sandiford
+ mips_cpu_info_from_isa
(mips_opts.isa)->name);
Post by Richard Sandiford
+ 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";
Post by Richard Sandiford
+ str[i + 1] = '6';
+ str[i] = '1';
+ }
+ else
+ {
+ insn_error =
+ "unrecognized 32-bit version of
microMIPS opcode";
Post by Richard Sandiford
+ str[i + 1] = '2';
+ str[i] = '3';
+ }
+ str[length + 2] = '\0';
+ }
+ return;
jar16 $30,$26
Error: unrecognized 16-bit version of microMIPS opcode
`jar16 $30,$26'
Post by Richard Sandiford
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.
Post by Fu, Chao-Ying
Post by Maciej W. Rozycki
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.
Post by Fu, Chao-Ying
Post by Maciej W. Rozycki
* 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!
Post by Fu, Chao-Ying
Post by Maciej W. Rozycki
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.
Post by Fu, Chao-Ying
Post by Maciej W. Rozycki
Post by Richard Sandiford
.set micromips
.ent foo
b 1f
nop
.end foo
.ent bar
1: nop
.end bar
0: cfff b 0 <foo>
0: R_MICROMIPS_PC10_S1 .L11
2: 0c00 nop
4: 0c00 nop
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
$ cat b.s
.globl baz
.ent foo
b baz
nop
.end foo
.ent bar
1: nop
.end bar
$ mips-sde-elf-objdump -dr b.o
b.o: file format elf32-tradbigmips
0: 1000ffff b 0 <foo>
0: R_MIPS_PC16 baz
4: 00000000 nop
8: 00000000 nop
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]
Post by Fu, Chao-Ying
Post by Maciej W. Rozycki
I'd just recommend peeking at the symbol table (back to the first
$ mips-sde-elf-objdump -t b.o
b.o: file format elf32-tradbigmips
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?
Post by Fu, Chao-Ying
Post by Maciej W. Rozycki
Post by Richard Sandiford
.set micromips
.ent foo
ld $10,0x1000($11)
.end foo
Assertion failure in micromips_macro_build at gas/config/tc-mips.c line
19466.
Post by Maciej W. Rozycki
Post by Richard Sandiford
Please report this bug.
on mipsisa64-elf with "-mips1 -mabi=32".
[...]
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.
Post by Fu, Chao-Ying
+/* Whether code compression (either of the MIPS16 or the microMIPS ASEs has
s/ASEs has/ASEs) has/
Fixed.
Post by Fu, Chao-Ying
+ 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...
Post by Fu, Chao-Ying
return (is_micromips_16bit_p (insn->insn_mo)
? 2 : is_micromips_32bit_p (insn->insn_mo) ? 4 : 6);
return (is_micromips_16bit_p (insn->insn_mo) ? 2
: is_micromips_32bit_p (insn->insn_mo) ? 4 : 6);
Fixed.
Post by Fu, Chao-Ying
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. ;)
Post by Fu, Chao-Ying
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.
Post by Fu, Chao-Ying
+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",
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.
Post by Fu, Chao-Ying
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.
Post by Fu, Chao-Ying
Seems the code would be a fair bit clearer with those changes,
but maybe I'm wrong...
No, not a sausage. ;)
Post by Fu, Chao-Ying
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.
Post by Fu, Chao-Ying
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.
Post by Fu, Chao-Ying
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.
Post by Fu, Chao-Ying
Part 2 of the review.
.set micromips
.fill 0x80
b16 .-0x80
/tmp/foo.s:3: Error: unrecognized opcode `b16 .-0x80'
.set micromips
.fill 0x80
b .-0x80
successfully produces a 16-bit insn.
Fixed as a result of earlier changes.
Post by Fu, Chao-Ying
@@ -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?
Post by Fu, Chao-Ying
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.
Post by Fu, Chao-Ying
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.
Post by Fu, Chao-Ying
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
+ {
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]
Post by Fu, Chao-Ying
+ /* 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 */
+ if (*s++ == *args)
+ continue;
+ break;
Mark fallthrough.
Another copy & paste case -- fixed (and removed support for [] as
irrelevant).
Post by Fu, Chao-Ying
+ case 'D': /* floating point destination register */
+ case 'S': /* floating point source register */
+ case 'T': /* floating point target register */
+ case 'R': /* floating point source register */
+ 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)
+ {
+ MICROMIPS_INSERT_OPERAND (FD, *ip, regno);
+ break;
+ MICROMIPS_INSERT_OPERAND (FS, *ip, regno);
+ break;
+
+ MICROMIPS_INSERT_OPERAND (FT, *ip, regno);
+ break;
+
+ MICROMIPS_INSERT_OPERAND (FR, *ip, regno);
+ break;
+ }
+ lastregno = regno;
+ continue;
+ }
+
+ switch (*args++)
+ {
+ MICROMIPS_INSERT_OPERAND (FS, *ip, lastregno);
+ continue;
+ 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]
Post by Fu, Chao-Ying
Too many spaces.
Fixed.
Post by Fu, Chao-Ying
+ if (insn + 1 < &micromips_opcodes[bfd_micromips_num_opcodes] &&
+ !strcmp (insn->name, insn[1].name))
Misplaced "&&".
Another copy & paste case -- fixed.
Post by Fu, Chao-Ying
+ = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};;
Double ";".
Fixed.
Post by Fu, Chao-Ying
+ 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.
Post by Fu, Chao-Ying
+ /* For microMIPS, we always use relocations for branches.
+ So, we should not resolve immediate values. */
Too many spaces.
Fixed.
Post by Fu, Chao-Ying
+ 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.
Post by Fu, Chao-Ying
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]
Post by Fu, Chao-Ying
#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.
Post by Fu, Chao-Ying
+ "mA" 7-bit immediate (-63 .. 64) << 2 (MICROMIPSOP_*_IMMA)
Don't you mean (-64 .. 63)?
Yes, this is for LWGP.
Post by Fu, Chao-Ying
+ "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).
Post by Fu, Chao-Ying
@@ -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.
Post by Fu, Chao-Ying
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;
+ 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.
Post by Fu, Chao-Ying
+ /* 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.
Post by Fu, Chao-Ying
+/*
+ * 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]
Post by Fu, Chao-Ying
+ /* 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.
Post by Fu, Chao-Ying
+ /* 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.
Post by Fu, Chao-Ying
+ 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
Post by Maciej W. Rozycki
= 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.
Post by Fu, Chao-Ying
+ /* 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.
Post by Fu, Chao-Ying
+ 4 bytes at irel->r_offset. */
s/Assume is/Assume it is/
Fixed.
Post by Fu, Chao-Ying
+ /* 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.
Post by Fu, Chao-Ying
+ /* 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]
Post by Fu, Chao-Ying
the elf32-mips.c reloc questions in review 2 apply to elf64-mips.c
+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.
Post by Fu, Chao-Ying
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.
Post by Fu, Chao-Ying
+#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.
Post by Fu, Chao-Ying
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.
Post by Fu, Chao-Ying
+ 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.
Post by Fu, Chao-Ying
+ 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
return (r_type == R_MIPS_GOT16
|| r_type == R_MIPS16_GOT16
|| r_type == R_MICROMIPS_GOT16);
Same for later functions.
Fixed.
Post by Fu, Chao-Ying
- 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.
Post by Fu, Chao-Ying
@@ -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.
Post by Fu, Chao-Ying
@@ -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]
Post by Fu, Chao-Ying
+ /* 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.
Post by Fu, Chao-Ying
If we're checking alignment for R_MIPS_26 and R_MICROMIPS_26, we should
/* 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.
+ /* 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.
Post by Fu, Chao-Ying
@@ -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
/* 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.
Post by Fu, Chao-Ying
@@ -5486,8 +5647,38 @@ mips_elf_calculate_relocation (bfd *abfd
value &= howto->dst_mask;
break;
+ 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;
+
+ 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;
+
+ 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;
+
+ 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.
Post by Fu, Chao-Ying
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.
Post by Fu, Chao-Ying
@@ -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]
Post by Fu, Chao-Ying
@@ -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.
Post by Fu, Chao-Ying
@@ -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.
Post by Fu, Chao-Ying
@@ -9215,6 +9479,12 @@ _bfd_mips_elf_relocate_section (bfd *out
break;
+ 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;
+
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?
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.
Post by Fu, Chao-Ying
@@ -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.
Post by Fu, Chao-Ying
@@ -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.
Post by Fu, Chao-Ying
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. :)
Post by Fu, Chao-Ying
+ 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.
Post by Fu, Chao-Ying
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.
Post by Fu, Chao-Ying
Watch your formatting in this function. There are lots of cases of
(*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.
Post by Fu, Chao-Ying
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 <***@mips.com>
Ilie Garbacea <***@mips.com>
Maciej W. Rozycki <***@codesourcery.com>
Joseph Myers <***@codesourcery.com>
Catherine Moore <***@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 <***@mips.com>

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

gas/
2010-07-26 Chao-ying Fu <***@mips.com>
Maciej W. Rozycki <***@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 <***@codesourcery.com>
Chao-ying 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/***@abs.d: New test.
* gas/mips/***@add.d: Likewise.
* gas/mips/***@and.d: Likewise.
* gas/mips/***@beq.d: Likewise.
* gas/mips/***@bge.d: Likewise.
* gas/mips/***@bgeu.d: Likewise.
* gas/mips/***@blt.d: Likewise.
* gas/mips/***@bltu.d: Likewise.
* gas/mips/***@branch-likely.d: Likewise.
* gas/mips/***@branch-misc-1.d: Likewise.
* gas/mips/***@branch-misc-2-64.d: Likewise.
* gas/mips/***@branch-misc-2.d: Likewise.
* gas/mips/***@branch-misc-2pic-64.d: Likewise.
* gas/mips/***@branch-misc-2pic.d: Likewise.
* gas/mips/***@dli.d: Likewise.
* gas/mips/***@elf-jal.d: Likewise.
* gas/mips/***@elf-rel2.d: Likewise.
* gas/mips/***@elf-rel4.d: Likewise.
* gas/mips/***@lb-svr4pic-ilocks.d: Likewise.
* gas/mips/***@li.d: Likewise.
* gas/mips/***@mips1-fp.d: Likewise.
* gas/mips/***@mips32-cp2.d: Likewise.
* gas/mips/***@mips32-imm.d: Likewise.
* gas/mips/***@mips32-sf32.d: Likewise.
* gas/mips/***@mips32.d: Likewise.
* gas/mips/***@mips32r2-cp2.d: Likewise.
* gas/mips/***@mips32r2-fp32.d: Likewise.
* gas/mips/***@mips32r2.d: Likewise.
* gas/mips/***@mips4-branch-likely.d: Likewise.
* gas/mips/***@mips4-fp.d: Likewise.
* gas/mips/***@mips4.d: Likewise.
* gas/mips/***@mips5.d: Likewise.
* gas/mips/***@mips64-cp2.d: Likewise.
* gas/mips/***@mips64.d: Likewise.
* gas/mips/***@mips64r2.d: Likewise.
* gas/mips/***@rol-hw.d: Likewise.
* gas/mips/***@uld2-eb.d: Likewise.
* gas/mips/***@uld2-el.d: Likewise.
* gas/mips/***@ulh2-eb.d: Likewise.
* gas/mips/***@ulh2-el.d: Likewise.
* gas/mips/***@ulw2-eb-ilocks.d: Likewise.
* gas/mips/***@ulw2-el-ilocks.d: Likewise.
* gas/mips/mips32-imm.d: Likewise.
* gas/mips/mips32.d: Update immediates.
* gas/mips/***@mips32-cp2.s: New test source.
* gas/mips/***@mips32-imm.s: Likewise.
* gas/mips/***@mips32r2-cp2.s: Likewise.
* gas/mips/***@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/***@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/***@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 <***@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 <***@mips.com>
Maciej W. Rozycki <***@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 <***@codesourcery.com>
Chao-ying Fu <***@mips.com>
Maciej W. Rozycki <***@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 <***@mips.com>
Maciej W. Rozycki <***@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.
Nathan Froyd
2010-07-26 13:25:44 UTC
Permalink
Post by Maciej W. Rozycki
Post by Richard Sandiford
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
Maciej W. Rozycki
2010-07-26 13:53:03 UTC
Permalink
Post by Nathan Froyd
Post by Maciej W. Rozycki
Post by Richard Sandiford
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
Richard Sandiford
2010-07-26 19:03:01 UTC
Permalink
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.
Post by Maciej W. Rozycki
Post by Fu, Chao-Ying
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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.
Likewise.
Post by Richard Sandiford
Post by Maciej W. Rozycki
(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.
Post by Maciej W. Rozycki
Post by Fu, Chao-Ying
Post by Maciej W. Rozycki
(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.
Post by Maciej W. Rozycki
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 ;-)
Post by Maciej W. Rozycki
Post by Fu, Chao-Ying
Post by Maciej W. Rozycki
Post by Richard Sandiford
.set micromips
.ent foo
b 1f
nop
.end foo
.ent bar
1: nop
.end bar
0: cfff b 0 <foo>
0: R_MICROMIPS_PC10_S1 .L11
2: 0c00 nop
4: 0c00 nop
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
$ cat b.s
.globl baz
.ent foo
b baz
nop
.end foo
.ent bar
1: nop
.end bar
$ mips-sde-elf-objdump -dr b.o
b.o: file format elf32-tradbigmips
0: 1000ffff b 0 <foo>
0: R_MIPS_PC16 baz
4: 00000000 nop
8: 00000000 nop
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?
Post by Maciej W. Rozycki
Post by Fu, Chao-Ying
Post by Maciej W. Rozycki
I'd just recommend peeking at the symbol table (back to the first
$ mips-sde-elf-objdump -t b.o
b.o: file format elf32-tradbigmips
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.
Post by Maciej W. Rozycki
Post by Fu, Chao-Ying
@@ -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
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.
Post by Maciej W. Rozycki
Post by Fu, Chao-Ying
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
+ {
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.
Post by Maciej W. Rozycki
Post by Fu, Chao-Ying
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.
Post by Maciej W. Rozycki
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.
Post by Maciej W. Rozycki
Post by Fu, Chao-Ying
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...
Post by Maciej W. Rozycki
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.
Post by Maciej W. Rozycki
Post by Fu, Chao-Ying
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 ;-)
Post by Maciej W. Rozycki
Post by Fu, Chao-Ying
@@ -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.
Post by Maciej W. Rozycki
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.
Post by Maciej W. Rozycki
Post by Fu, Chao-Ying
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 ;-)
Post by Maciej W. Rozycki
Post by Fu, Chao-Ying
- /* 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...
Post by Maciej W. Rozycki
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.
Post by Maciej W. Rozycki
Post by Fu, Chao-Ying
+ 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
Maciej W. Rozycki
2010-12-07 01:12:30 UTC
Permalink
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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
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. ;)
Post by Richard Sandiford
Post by Maciej W. Rozycki
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?
Post by Richard Sandiford
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
Post by Richard Sandiford
.set micromips
.ent foo
b 1f
nop
.end foo
.ent bar
1: nop
.end bar
0: cfff b 0 <foo>
0: R_MICROMIPS_PC10_S1 .L11
2: 0c00 nop
4: 0c00 nop
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
$ cat b.s
.globl baz
.ent foo
b baz
nop
.end foo
.ent bar
1: nop
.end bar
$ mips-sde-elf-objdump -dr b.o
b.o: file format elf32-tradbigmips
0: 1000ffff b 0 <foo>
0: R_MIPS_PC16 baz
4: 00000000 nop
8: 00000000 nop
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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
I'd just recommend peeking at the symbol table (back to the first
$ mips-sde-elf-objdump -t b.o
b.o: file format elf32-tradbigmips
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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
Post by Richard Sandiford
@@ -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
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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
Post by Richard Sandiford
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
+ {
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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
Post by Richard Sandiford
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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
Post by Richard Sandiford
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...
Post by Maciej W. Rozycki
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).
Post by Richard Sandiford
Post by Maciej W. Rozycki
Post by Richard Sandiford
@@ -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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
Post by Richard Sandiford
- /* 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
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 <***@mips.com>
Ilie Garbacea <***@mips.com>
Maciej W. Rozycki <***@codesourcery.com>
Joseph Myers <***@codesourcery.com>
Catherine Moore <***@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 <***@mips.com>
Maciej W. Rozycki <***@codesourcery.com>

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

gas/
2010-12-07 Chao-ying Fu <***@mips.com>
Maciej W. Rozycki <***@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 <***@codesourcery.com>
Chao-ying 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/***@abs.d: Likewise.
* gas/mips/***@add.d: Likewise.
* gas/mips/***@and.d: Likewise.
* gas/mips/***@beq.d: Likewise.
* gas/mips/***@bge.d: Likewise.
* gas/mips/***@bgeu.d: Likewise.
* gas/mips/***@blt.d: Likewise.
* gas/mips/***@bltu.d: Likewise.
* gas/mips/***@branch-likely.d: Likewise.
* gas/mips/***@branch-misc-1.d: Likewise.
* gas/mips/***@branch-misc-2-64.d: Likewise.
* gas/mips/***@branch-misc-2.d: Likewise.
* gas/mips/***@branch-misc-2pic-64.d: Likewise.
* gas/mips/***@branch-misc-2pic.d: Likewise.
* gas/mips/***@branch-self.d: Likewise.
* gas/mips/***@dli.d: Likewise.
* gas/mips/***@elf-jal.d: Likewise.
* gas/mips/***@elf-rel2.d: Likewise.
* gas/mips/***@elf-rel4.d: Likewise.
* gas/mips/***@jal-svr4pic.d: Likewise.
* gas/mips/***@jal-svr4pic-noreorder.d: Likewise.
* gas/mips/***@lb-svr4pic-ilocks.d: Likewise.
* gas/mips/***@li.d: Likewise.
* gas/mips/***@mips1-fp.d: Likewise.
* gas/mips/***@mips32-cp2.d: Likewise.
* gas/mips/***@mips32-imm.d: Likewise.
* gas/mips/***@mips32-sf32.d: Likewise.
* gas/mips/***@mips32.d: Likewise.
* gas/mips/***@mips32r2-cp2.d: Likewise.
* gas/mips/***@mips32r2-fp32.d: Likewise.
* gas/mips/***@mips32r2.d: Likewise.
* gas/mips/***@mips4-branch-likely.d: Likewise.
* gas/mips/***@mips4-fp.d: Likewise.
* gas/mips/***@mips4.d: Likewise.
* gas/mips/***@mips5.d: Likewise.
* gas/mips/***@mips64-cp2.d: Likewise.
* gas/mips/***@mips64.d: Likewise.
* gas/mips/***@mips64r2.d: Likewise.
* gas/mips/***@rol-hw.d: Likewise.
* gas/mips/***@uld2-eb.d: Likewise.
* gas/mips/***@uld2-el.d: Likewise.
* gas/mips/***@ulh2-eb.d: Likewise.
* gas/mips/***@ulh2-el.d: Likewise.
* gas/mips/***@ulw2-eb-ilocks.d: Likewise.
* gas/mips/***@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/***@mips32-cp2.s: New test source.
* gas/mips/***@mips32-imm.s: Likewise.
* gas/mips/***@mips32r2-cp2.s: Likewise.
* gas/mips/***@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/***@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/***@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 <***@mips.com>
Maciej W. Rozycki <***@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 <***@mips.com>
Maciej W. Rozycki <***@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 <***@codesourcery.com>
Chao-ying Fu <***@mips.com>
Maciej W. Rozycki <***@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 <***@mips.com>
Maciej W. Rozycki <***@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.
Richard Sandiford
2010-12-12 13:04:21 UTC
Permalink
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?
@@ -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
break;
+ 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. */
+
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
+ /* 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
+ { /* "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
Maciej W. Rozycki
2010-12-14 12:06:04 UTC
Permalink
Hello,

Ilie, Joseph: I have some questions for you below, please respond.
Post by Richard Sandiford
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.
Post by Richard Sandiford
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.
Post by Richard Sandiford
@@ -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.
Post by Richard Sandiford
@@ -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
/* 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.
Post by Richard Sandiford
/* 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?
Post by Richard Sandiford
@@ -9223,6 +9499,16 @@ _bfd_mips_elf_relocate_section (bfd *out
break;
+ 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. */
+
abort ();
break;
I suppose that should be something like "JALX to a non-word-aligned address".
Updated, thanks.
Post by Richard Sandiford
+ /* 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
.byte 1
and as discussed elsewhere, asserts are really to double-check
conditions that we think must already hold.
Will check that. [FIXME]
Post by Richard Sandiford
+ 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
+ /* 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)
# 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?
Post by Richard Sandiford
I see some targets rightly adjust st_size too. We should do
the same here.
Agreed. [FIXME]
Post by Richard Sandiford
+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?
Post by Richard Sandiford
+/* 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)
Yes, that's my typo; it should have been PTR, not OFFSET.
Post by Richard Sandiford
/* 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.
Post by Richard Sandiford
At least, that's what the code seems to do, since it returns 2 for
+ { /* "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.
Post by Richard Sandiford
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]
Post by Richard Sandiford
+ /* 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]
Post by Richard Sandiford
+ 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]
Post by Richard Sandiford
+ /* Give up if not the same register used with both relocations. */
"Give up unless the same register is used with both relocations."
Fixed, thanks.
Post by Richard Sandiford
+ /* 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
/* 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.
Post by Richard Sandiford
+ 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.
Post by Richard Sandiford
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)
Richard Sandiford
2010-12-14 13:30:03 UTC
Permalink
Post by Maciej W. Rozycki
Post by Richard Sandiford
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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
/* 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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
/* 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. */
Post by Maciej W. Rozycki
Post by Richard Sandiford
At least, that's what the code seems to do, since it returns 2 for
+ { /* "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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
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
Maciej W. Rozycki
2010-12-16 11:16:23 UTC
Permalink
Post by Richard Sandiford
Post by Maciej W. Rozycki
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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
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.
/* 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
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]
Post by Richard Sandiford
Post by Maciej W. Rozycki
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
Richard Sandiford
2010-12-18 10:09:21 UTC
Permalink
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
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.
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...
Post by Maciej W. Rozycki
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
Joseph S. Myers
2010-12-14 17:05:01 UTC
Permalink
Post by Maciej W. Rozycki
Post by Richard Sandiford
/* 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
***@codesourcery.com
Maciej W. Rozycki
2010-12-16 13:21:04 UTC
Permalink
Post by Joseph S. Myers
Post by Maciej W. Rozycki
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
Fu, Chao-Ying
2010-12-17 19:55:44 UTC
Permalink
Post by Maciej W. Rozycki
Hello,
Ilie, Joseph: I have some questions for you below, please respond.
Ilie is on vacations.
Post by Maciej W. Rozycki
Post by Richard Sandiford
+ /* 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)
# 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)
Post by Maciej W. Rozycki
Post by Richard Sandiford
+static unsigned long
+find_match (unsigned long opcode, const struct
opcode_descriptor insn[])
Post by Richard Sandiford
+{
+ 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
Richard Sandiford
2010-12-18 09:47:02 UTC
Permalink
Post by Fu, Chao-Ying
Post by Richard Sandiford
Post by Richard Sandiford
+ /* 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)
# 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".
&& 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.)
Post by Fu, Chao-Ying
Post by Richard Sandiford
Post by Richard Sandiford
+static unsigned long
+find_match (unsigned long opcode, const struct
opcode_descriptor insn[])
Post by Richard Sandiford
+{
+ 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
Richard Sandiford
2011-01-02 11:36:10 UTC
Permalink
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.
@@ -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".
+/* 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));
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
- /* 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
+ 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)
+ {
+ br = "bgez";
+ break;
+ br = mips_opts.micromips ? "bgez" : "bgezl";
+ brneg = "bltz";
+ likely = 1;
+ break;
+ gas_assert (mips_opts.micromips);
+ br = "bgezals";
+ brneg = "bltz";
+ likely = 1;
+ call = 1;
+ break;
+ br = "bgtz";
+ break;
+ br = mips_opts.micromips ? "bgtz" : "bgtzl";
+ brneg = "blez";
+ likely = 1;
+ break;
+ br = "blez";
+ break;
+ br = mips_opts.micromips ? "blez" : "blezl";
+ brneg = "bgtz";
+ likely = 1;
+ break;
+ br = "bltz";
+ break;
+ br = mips_opts.micromips ? "bltz" : "bltzl";
+ brneg = "bgez";
+ likely = 1;
+ break;
+ gas_assert (mips_opts.micromips);
+ br = "bltzals";
+ brneg = "bgez";
+ likely = 1;
+ call = 1;
+ break;
+ 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.
+ 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
+ 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);
+ 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
+ ...
+
+ 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".
+ 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 @@
.*: 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 @@
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
Maciej W. Rozycki
2011-02-21 15:34:49 UTC
Permalink
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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
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.
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...
Post by Maciej W. Rozycki
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]
Post by Richard Sandiford
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.
Post by Richard Sandiford
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.
Post by Richard Sandiford
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). :/
Post by Richard Sandiford
Post by Maciej W. Rozycki
@@ -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,
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
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.
Post by Maciej W. Rozycki
@@ -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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ /* 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".
Post by Maciej W. Rozycki
+/* 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?
Post by Richard Sandiford
Post by Maciej W. Rozycki
@@ -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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+#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.
Post by Richard Sandiford
If the bit really is needed, let's call the parameter "user_16bit"
rather than "is_16bit", to match the use.
Fixed.
Post by Richard Sandiford
Add a comment saying what RELAX_MICROMIPS_TYPE is. See the MIPS16
comment as an example.
Post by Maciej W. Rozycki
+#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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ /* 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;
/* 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ /* 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
The fields are zero if we haven't yet seen the first instruction.
Fixed.
Post by Richard Sandiford
Post by Maciej W. Rozycki
@@ -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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+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
[...]
Post by Maciej W. Rozycki
+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?
Post by Richard Sandiford
Post by Maciej W. Rozycki
@@ -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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ 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...
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ /* For microMIPS, disable reordering. */
+ || mips_opts.micromips
You should say whether this is for simplicity or by specification.
/* 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".
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ /* 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ hash = !mips_opts.micromips ? op_hash : micromips_op_hash;
hash = mips_opts.micromips ? micromips_op_hash : op_hash;
Applied.
Post by Richard Sandiford
Post by Maciej W. Rozycki
@@ -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
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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ 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? ;)
Post by Richard Sandiford
Post by Maciej W. Rozycki
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
Post by Maciej W. Rozycki
- /* 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
@@ -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?
Post by Richard Sandiford
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?
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ /* 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ if CALL is set. In the reorder mode the delay slot would be filled
+ BR <args>, <sym>
Add an explicit nop, since the code does.
Good point.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+/* Emit a coprocessor branch macro specified by TYPE, using CC as
+ the condition code tested. EP specifies the branch target. */
"branch-likely macro".
OK.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+/* 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)
+ {
+ br = "bgez";
+ break;
+ br = mips_opts.micromips ? "bgez" : "bgezl";
+ brneg = "bltz";
+ likely = 1;
+ break;
+ gas_assert (mips_opts.micromips);
+ br = "bgezals";
+ brneg = "bltz";
+ likely = 1;
+ call = 1;
+ break;
+ br = "bgtz";
+ break;
+ br = mips_opts.micromips ? "bgtz" : "bgtzl";
+ brneg = "blez";
+ likely = 1;
+ break;
+ br = "blez";
+ break;
+ br = mips_opts.micromips ? "blez" : "blezl";
+ brneg = "bgtz";
+ likely = 1;
+ break;
+ br = "bltz";
+ break;
+ br = mips_opts.micromips ? "bltz" : "bltzl";
+ brneg = "bgez";
+ likely = 1;
+ break;
+ gas_assert (mips_opts.micromips);
+ br = "bltzals";
+ brneg = "bgez";
+ likely = 1;
+ call = 1;
+ break;
+ 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
- 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
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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ /* 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
@@ -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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ 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
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ 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.
Post by Richard Sandiford
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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ 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;
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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ /* 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
+ && (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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ /* s0, ra
+ s0, s1, ra
+ s0, s1, s2, ra
+ s0, s1, s2, s3, ra
+ s0-s1, ra
+ s0-s2, ra
+ s0-s3, ra */
s1, ra, s2, s0
(rightly IMO), so I don't think we gain much by listing the split-out ranges.
/* s0, ra
s0-s1, ra
s0-s2, ra
s0-s3, ra */
would be OK.
I have rewritten it adding an explanatory comment.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ }
+ 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ /* 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
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.)
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ 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?).
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ /* 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ 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
+ ...
+
+ 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ /* 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?
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ if (RELAX_MICROMIPS_UNCOND (fragp->fr_subtype))
+ goto uncond_micromips;
Ugh. Either split out the code for unconditional branches into a subfunction,
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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ buf = (bfd_byte *)fragp->fr_literal + fragp->fr_fix;
Missing space before "fragp->fr_literal". A few other occurences.
Fixed.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ 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).
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ /* 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]
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ 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).
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ /* 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/.
Post by Maciej W. Rozycki
+ /* 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
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 @@
.*: 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 @@
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,
* 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/***@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. ;)
Post by Richard Sandiford
Post by Maciej W. Rozycki
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).
Post by Maciej W. Rozycki
-#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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
/* 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+/* 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+/* microMIPS placeholders. */
/* 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+/* 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+/* MIPS placeholders. */
/* Placeholders for fields that only exist in the traditional 32-bit
instruction encoding; see the comment above for details. */
Thanks.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ "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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
- 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ else
+ iprintf (is, "UNKNOWN");
Excess indentation.
Fixed.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ In microMIPS, we need to match instructions (mfc0, mtc0)
+ by hand. */
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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+/* 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ 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.
Post by Richard Sandiford
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 <***@mips.com>
Ilie Garbacea <***@mips.com>
Maciej W. Rozycki <***@codesourcery.com>
Joseph Myers <***@codesourcery.com>
Catherine Moore <***@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 <***@mips.com>
Maciej W. Rozycki <***@codesourcery.com>

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

gas/
2011-02-21 Maciej W. Rozycki <***@codesourcery.com>
Chao-ying 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 <***@codesourcery.com>
Chao-ying 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/***@abs.d: Likewise.
* gas/mips/***@add.d: Likewise.
* gas/mips/***@and.d: Likewise.
* gas/mips/***@beq.d: Likewise.
* gas/mips/***@bge.d: Likewise.
* gas/mips/***@bgeu.d: Likewise.
* gas/mips/***@blt.d: Likewise.
* gas/mips/***@bltu.d: Likewise.
* gas/mips/***@branch-likely.d: Likewise.
* gas/mips/***@branch-misc-1.d: Likewise.
* gas/mips/***@branch-misc-2-64.d: Likewise.
* gas/mips/***@branch-misc-2.d: Likewise.
* gas/mips/***@branch-misc-2pic-64.d: Likewise.
* gas/mips/***@branch-misc-2pic.d: Likewise.
* gas/mips/***@branch-self.d: Likewise.
* gas/mips/***@cache.d: Likewise.
* gas/mips/***@daddi.d: Likewise.
* gas/mips/***@dli.d: Likewise.
* gas/mips/***@elf-jal.d: Likewise.
* gas/mips/***@elf-rel2.d: Likewise.
* gas/mips/***@elf-rel4.d: Likewise.
* gas/mips/***@jal-svr4pic.d: Likewise.
* gas/mips/***@jal-svr4pic-noreorder.d: Likewise.
* gas/mips/***@lb-svr4pic-ilocks.d: Likewise.
* gas/mips/***@li.d: Likewise.
* gas/mips/***@mips1-fp.d: Likewise.
* gas/mips/***@mips32-cp2.d: Likewise.
* gas/mips/***@mips32-imm.d: Likewise.
* gas/mips/***@mips32-sf32.d: Likewise.
* gas/mips/***@mips32.d: Likewise.
* gas/mips/***@mips32r2-cp2.d: Likewise.
* gas/mips/***@mips32r2-fp32.d: Likewise.
* gas/mips/***@mips32r2.d: Likewise.
* gas/mips/***@mips4-branch-likely.d: Likewise.
* gas/mips/***@mips4-fp.d: Likewise.
* gas/mips/***@mips4.d: Likewise.
* gas/mips/***@mips5.d: Likewise.
* gas/mips/***@mips64-cp2.d: Likewise.
* gas/mips/***@mips64.d: Likewise.
* gas/mips/***@mips64r2.d: Likewise.
* gas/mips/***@pref.d: Likewise.
* gas/mips/***@rol-hw.d: Likewise.
* gas/mips/***@uld2-eb.d: Likewise.
* gas/mips/***@uld2-el.d: Likewise.
* gas/mips/***@ulh2-eb.d: Likewise.
* gas/mips/***@ulh2-el.d: Likewise.
* gas/mips/***@ulw2-eb-ilocks.d: Likewise.
* gas/mips/***@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/***@mips32-cp2.s: New test source.
* gas/mips/***@mips32-imm.s: Likewise.
* gas/mips/***@mips32r2-cp2.s: Likewise.
* gas/mips/***@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/***@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/***@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 <***@mips.com>
Maciej W. Rozycki <***@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 <***@mips.com>
Maciej W. Rozycki <***@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 <***@codesourcery.com>
Chao-ying Fu <***@mips.com>
Maciej W. Rozycki <***@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 <***@mips.com>
Maciej W. Rozycki <***@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.
Fu, Chao-Ying
2011-02-22 20:12:11 UTC
Permalink
Post by Maciej W. Rozycki
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.
Post by Richard Sandiford
+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
Post by Richard Sandiford
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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
+ /* For microMIPS PC relative relocations, we cannot
convert it to
Post by Richard Sandiford
+ against a section. If we do, it will mess up the
fixp->fx_offset. */
Post by Richard Sandiford
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
Fu, Chao-Ying
2011-02-22 20:19:26 UTC
Permalink
Post by Richard Sandiford
+ /* For microMIPS PC relative relocations, we cannot
convert it to
Post by Richard Sandiford
+ against a section. If we do, it will mess up the
fixp->fx_offset. */
Post by Richard Sandiford
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
Maciej W. Rozycki
2011-02-24 10:45:40 UTC
Permalink
Post by Fu, Chao-Ying
Post by Richard Sandiford
+ /* For microMIPS PC relative relocations, we cannot
convert it to
Post by Richard Sandiford
+ against a section. If we do, it will mess up the
fixp->fx_offset. */
Post by Richard Sandiford
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 <***@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
+ \.\.\.
Richard Sandiford
2011-02-26 11:41:09 UTC
Permalink
Post by Maciej W. Rozycki
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
Maciej W. Rozycki
2011-02-28 16:41:28 UTC
Permalink
Post by Maciej W. Rozycki
Post by Maciej W. Rozycki
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
Maciej W. Rozycki
2011-02-25 23:59:23 UTC
Permalink
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 <***@mips.com>
Ilie Garbacea <***@mips.com>
Maciej W. Rozycki <***@codesourcery.com>
Joseph Myers <***@codesourcery.com>
Catherine Moore <***@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 <***@mips.com>
Maciej W. Rozycki <***@codesourcery.com>

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

gas/
2011-02-25 Maciej W. Rozycki <***@codesourcery.com>
Chao-ying 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 <***@codesourcery.com>
Chao-ying 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/***@abs.d: Likewise.
* gas/mips/***@add.d: Likewise.
* gas/mips/***@alnv_ps-swap.d: Likewise.
* gas/mips/***@and.d: Likewise.
* gas/mips/***@beq.d: Likewise.
* gas/mips/***@bge.d: Likewise.
* gas/mips/***@bgeu.d: Likewise.
* gas/mips/***@blt.d: Likewise.
* gas/mips/***@bltu.d: Likewise.
* gas/mips/***@branch-likely.d: Likewise.
* gas/mips/***@branch-misc-1.d: Likewise.
* gas/mips/***@branch-misc-2-64.d: Likewise.
* gas/mips/***@branch-misc-2.d: Likewise.
* gas/mips/***@branch-misc-2pic-64.d: Likewise.
* gas/mips/***@branch-misc-2pic.d: Likewise.
* gas/mips/***@branch-misc-4-64.d: Likewise.
* gas/mips/***@branch-misc-4.d: Likewise.
* gas/mips/***@branch-self.d: Likewise.
* gas/mips/***@cache.d: Likewise.
* gas/mips/***@daddi.d: Likewise.
* gas/mips/***@dli.d: Likewise.
* gas/mips/***@elf-jal.d: Likewise.
* gas/mips/***@elf-rel2.d: Likewise.
* gas/mips/***@elf-rel4.d: Likewise.
* gas/mips/***@jal-svr4pic.d: Likewise.
* gas/mips/***@jal-svr4pic-noreorder.d: Likewise.
* gas/mips/***@lb-svr4pic-ilocks.d: Likewise.
* gas/mips/***@li.d: Likewise.
* gas/mips/***@loc-swap-dis.d: Likewise.
* gas/mips/***@loc-swap.d: Likewise.
* gas/mips/***@mips1-fp.d: Likewise.
* gas/mips/***@mips32-cp2.d: Likewise.
* gas/mips/***@mips32-imm.d: Likewise.
* gas/mips/***@mips32-sf32.d: Likewise.
* gas/mips/***@mips32.d: Likewise.
* gas/mips/***@mips32r2-cp2.d: Likewise.
* gas/mips/***@mips32r2-fp32.d: Likewise.
* gas/mips/***@mips32r2.d: Likewise.
* gas/mips/***@mips4-branch-likely.d: Likewise.
* gas/mips/***@mips4-fp.d: Likewise.
* gas/mips/***@mips4.d: Likewise.
* gas/mips/***@mips5.d: Likewise.
* gas/mips/***@mips64-cp2.d: Likewise.
* gas/mips/***@mips64.d: Likewise.
* gas/mips/***@mips64r2.d: Likewise.
* gas/mips/***@pref.d: Likewise.
* gas/mips/***@relax-at.d: Likewise.
* gas/mips/***@relax.d: Likewise.
* gas/mips/***@rol-hw.d: Likewise.
* gas/mips/***@uld2-eb.d: Likewise.
* gas/mips/***@uld2-el.d: Likewise.
* gas/mips/***@ulh2-eb.d: Likewise.
* gas/mips/***@ulh2-el.d: Likewise.
* gas/mips/***@ulw2-eb-ilocks.d: Likewise.
* gas/mips/***@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/***@mips32-cp2.s: New test source.
* gas/mips/***@mips32-imm.s: Likewise.
* gas/mips/***@mips32r2-cp2.s: Likewise.
* gas/mips/***@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/***@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/***@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 <***@mips.com>
Maciej W. Rozycki <***@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 <***@mips.com>
Maciej W. Rozycki <***@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 <***@codesourcery.com>
Chao-ying Fu <***@mips.com>
Maciej W. Rozycki <***@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 <***@mips.com>
Maciej W. Rozycki <***@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.
Richard Sandiford
2011-03-13 09:23:31 UTC
Permalink
Post by Maciej W. Rozycki
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
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.
Post by Maciej W. Rozycki
- 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, ".
Post by Maciej W. Rozycki
- binutils-gas-mips-fix-adjust-reloc.diff -- a fix for relocation handling
problems discovered while fixing the issue with PC-relative relocations
* 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.)
Post by Maciej W. Rozycki
- 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.
Post by Maciej W. Rozycki
- 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
Richard Sandiford
2011-07-24 14:22:55 UTC
Permalink
Post by Richard Sandiford
Post by Maciej W. Rozycki
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
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.
Post by Richard Sandiford
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):
Maciej W. Rozycki
2011-07-26 01:19:04 UTC
Permalink
Post by Richard Sandiford
Post by Richard Sandiford
Post by Maciej W. Rozycki
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
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.
Post by Richard Sandiford
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
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).
Post by Richard Sandiford
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. :(
Post by Richard Sandiford
Post by Richard Sandiford
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...
Post by Richard Sandiford
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.
Post by Richard Sandiford
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
Maciej W. Rozycki
2011-07-28 23:52:03 UTC
Permalink
Hi Richard,
Post by Maciej W. Rozycki
Post by Richard Sandiford
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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
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 <***@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))
+

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
Richard Sandiford
2011-07-29 09:25:45 UTC
Permalink
Post by Maciej W. Rozycki
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.
Post by Maciej W. Rozycki
Post by Maciej W. Rozycki
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,
Post by Maciej W. Rozycki
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
Post by Maciej W. Rozycki
@@ -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
Post by Maciej W. Rozycki
@@ -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;
}
*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.
Post by Maciej W. Rozycki
@@ -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
Post by Maciej W. Rozycki
@@ -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
Post by Maciej W. Rozycki
@@ -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
Post by Maciej W. Rozycki
@@ -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
Post by Maciej W. Rozycki
@@ -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
Post by Maciej W. Rozycki
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.
Post by Maciej W. Rozycki
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
Post by Maciej W. Rozycki
@@ -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.
Post by Maciej W. Rozycki
@@ -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.
Post by Maciej W. Rozycki
@@ -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
Post by Maciej W. Rozycki
@@ -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
Post by Maciej W. Rozycki
@@ -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);
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.
Post by Maciej W. Rozycki
@@ -12502,11 +12507,11 @@ _bfd_mips_elf_relax_section (bfd *abfd,
break;
- if (check_br16 (abfd, contents + irel->r_offset + 4, reg))
+ if (check_br16 (abfd, ptr + 4, reg))
break;
continue;
- if (check_br32 (abfd, contents + irel->r_offset + 4, reg))
+ if (check_br32 (abfd, ptr + 4, reg))
break;
continue;
OK
Post by Maciej W. Rozycki
@@ -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
Post by Maciej W. Rozycki
@@ -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
Post by Maciej W. Rozycki
@@ -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
Post by Maciej W. Rozycki
@@ -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
Post by Maciej W. Rozycki
@@ -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
Post by Maciej W. Rozycki
@@ -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
Post by Maciej W. Rozycki
@@ -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
Post by Maciej W. Rozycki
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
Maciej W. Rozycki
2011-07-29 17:39:59 UTC
Permalink
Post by Richard Sandiford
Post by Maciej W. Rozycki
Post by Maciej W. Rozycki
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.
Post by Richard Sandiford
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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
@@ -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;
}
*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().
Post by Richard Sandiford
Post by Maciej W. Rozycki
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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
@@ -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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
@@ -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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
@@ -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);
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

Richard Sandiford
2011-02-26 11:36:00 UTC
Permalink
Thanks for the updates. I'll try to go through the patches in the next
couple of weeks (maybe later this weekend).
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
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.
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...
Post by Maciej W. Rozycki
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
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
beqz32 $4, 0f
nop16
jalx bar
nop
.end foo
.set nomicromips
.align 2
.globl bar
.ent 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.
.set noreorder
lui $4, 0x1234
lui $2, %hi(foo)
bnez $3, 0f
addiu $2, %lo(foo)
...
lui $4, %hi(foo)
jal bar
addiu $4, %lo(foo)
.set noreorder
lui $4, 0x1234
bnez $3, 0f
addiu $2, $pc, foo - .
...
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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ /* 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".
Post by Maciej W. Rozycki
+/* 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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
+#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 :-)
Post by Maciej W. Rozycki
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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
+#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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ /* For microMIPS, disable reordering. */
+ || mips_opts.micromips
You should say whether this is for simplicity or by specification.
/* 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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
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
Post by Maciej W. Rozycki
- /* 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.
Post by Maciej W. Rozycki
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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
- 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
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.
Post by Maciej W. Rozycki
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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ 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
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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ 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.
Post by Maciej W. Rozycki
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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ /* 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
+ && (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.
Post by Maciej W. Rozycki
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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ /* 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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
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 @@
.*: 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 @@
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,
* 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
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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
-#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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
+/* 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...
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
+/* 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 ...".
Post by Maciej W. Rozycki
Post by Richard Sandiford
Post by Maciej W. Rozycki
+ 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.
Post by Maciej W. Rozycki
Post by Richard Sandiford
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
Maciej W. Rozycki
2011-07-26 02:00:55 UTC
Permalink
Hi Richard,
Post by Richard Sandiford
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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
Post by Richard Sandiford
+/* 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
Post by Richard Sandiford
+#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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
Post by Richard Sandiford
+/* 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.
/* 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.
#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).
Post by Richard Sandiford
Post by Maciej W. Rozycki
Post by Richard Sandiford
+/* 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).
Post by Richard Sandiford
Post by Maciej W. Rozycki
Post by Richard Sandiford
+ 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
Post by Richard Sandiford
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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
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
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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
- binutils-umips-opcode-trap.diff -- a complementing microMIPS change to
the trap/no-delay slot annotation made to standard MIPS/MIPS16 code,
- 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));
target_is_micromips_code_p = (htab->splt != sec
&& ELF_ST_IS_MICROMIPS (h->root.other));
Indeed, fixed.
Post by Richard Sandiford
- 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?
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.
Post by Richard Sandiford
@@ -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
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.
Post by Richard Sandiford
+ /* 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
/* 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
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
/* 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.
Post by Richard Sandiford
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. :)
Post by Richard Sandiford
bdsize should be dead after the changes above.
Yes, and a couple of others.
Post by Richard Sandiford
- /* Give up if not the same register used with both relocations. */
+ /* Give up unless the same register used with both relocations. */
/* Give up unless the same register is used with both relocations. */
OK.
Post by Richard Sandiford
+/* 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.
Post by Richard Sandiford
+ /* 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".
+/* 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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
- binutils-gas-mips-fix-adjust-reloc.diff -- a fix for relocation handling
problems discovered while fixing the issue with PC-relative relocations
* 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,
@@ -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
+ && (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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
- 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.
Post by Richard Sandiford
/* 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
+ unsigned long jal = 0xf4000000; /* jal */
+ unsigned long jalr = 0x45c0; /* jalr */
+ unsigned long jal, jalr;
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.
Post by Richard Sandiford
Post by Maciej W. Rozycki
- 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);
+ }
+ reloc = micromips_map_reloc (orig_reloc);
+ shift = reloc == BFD_RELOC_MICROMIPS_JMP ? 1 : 2;
+ shift = mips_opts.micromips ? 1 : 2;
Same for BFD_RELOC_16_PCREL_S2.
Adjusted.
Post by Richard Sandiford
+ 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.
/* 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]);
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
Richard Sandiford
2010-05-26 20:19:07 UTC
Permalink
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
Richard Sandiford
2010-05-27 21:39:34 UTC
Permalink
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);
}
}


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
Continue reading on narkive:
Loading...