* [PATCH] MIPS: microMIPS and MCU ASE instruction set support
@ 2010-05-18 18:19 Maciej W. Rozycki
2010-05-23 21:38 ` Richard Sandiford
` (2 more replies)
0 siblings, 3 replies; 41+ messages in thread
From: Maciej W. Rozycki @ 2010-05-18 18:19 UTC (permalink / raw)
To: binutils
Cc: Chao-ying Fu, Ilie Garbacea, Joseph Myers, Catherine Moore,
Daniel Jacobowitz
[-- Attachment #1: Type: TEXT/PLAIN, Size: 27908 bytes --]
Hi,
This is a change to add support for the microMIPS and MCU ASE
instructions as implemented by some recent MIPS processors. The microMIPS
ASE is a reencoding of the complete MIPS64r2 instruction set (the MIPS32r2
set on 32-bit processors) using variable-length instructions, currently
either 16-bit or 32-bit, with space reserved for future 48-bit ones.
There are a number of instructions where both a 16-bit and a 32-bit
variation of the same operation exist, usually differing by the width of
the immediate operand. This is in some sense similar to what the MIPS16
ASE implements with the EXTEND prefix and likewise the tools are prepared
to choose the smallest encoding possible.
The whole instruction set is meant to be source-level compatible with the
MIPS64r2/MIPS32r2 set as appropriate, assuming the ".set macro" mode of
assembly (offset fields of some less often used instructions have been
shortened and an auxiliary register, usually $at, is needed to access the
whole address range) and no dependency of code on instruction lengths
(e.g. no computed GOTOs using hardcoded constants).
The MCU ASE adds a couple of further instructions on top of standard MIPS
and microMIPS instruction sets.
There's a lot of infrastructure added, including some changes to standard
MIPS and MIPS16 support code for consistency, and the testsuite has been
modified for easy reuse of the existing tests for microMIPS assembly
(there's a potential to use these features elsewhere too, e.g. to extend
tests that are now limited to the MIPS1 ISA because of load delay slots to
all the ISAs).
The patch itself is attached compressed, due to its size.
Regression-tested successfully with the mips-sde-elf and mips-linux-gnu
targets.
Comments?
Maciej
bfd/
2010-05-18 Chao-ying Fu <fu@mips.com>
Ilie Garbacea <ilie@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
Joseph Myers <joseph@codesourcery.com>
Catherine Moore <clm@codesourcery.com>
* archures.c (bfd_mach_mips_micromips): New macro.
* cpu-mips.c (I_micromips): New enum value.
(arch_info_struct): Add bfd_mach_mips_micromips.
* elf32-mips.c (elf_micromips_howto_table_rel): New variable.
(_bfd_mips_elf32_gprel16_reloc): Handle microMIPS.
(mips_elf_gprel32_reloc): Update comment.
(micromips_reloc_map): New variable.
(bfd_elf32_bfd_reloc_type_lookup): Handle microMIPS.
(mips_elf32_rtype_to_howto): Likewise.
(mips_info_to_howto_rel): Likewise.
(elf32_mips_relax_delete_bytes): New function.
(opcode_descriptor): New structure.
(b_insns_32, b_insn_16): New variables.
(BZ32_REG, BZ32_REG_FIELD): New macros.
(bz_insns_32, bzc_insns_32, bz_insns_16): New variables.
(BZ16_VALID_REG, BZ16_REG_FIELD): New macros.
(jal_insn_32_bd16, jal_insn_32_bd32): New variables.
(jalr_insn_32_bd16, jalr_insn_32_bd32): Likewise.
(ds_insns_32_bd16, ds_insns_32_bd32): Likewise.
(jalr_insn_16_bd16, jalr_insn_16_bd32): Likewise.
(ds_insns_16_bd16): Likewise.
(lui_insn, addiu_insn, addiupc_insn): Likewise.
(ADDIU_REG, ADDIUPC_VALID_REG, ADDIUPC_REG_FIELD): New macros.
(lwgp_insn_32, lwgp_insn_16): New functions.
(LWGP32_REG, LWGP16_VALID_REG, LWGP16_REG_FIELD): New macros.
(MOVE32_RD, MOVE32_RS): Likewise.
(MOVE16_RD_FIELD, MOVE16_RS_FIELD): Likewise.
(move_insns_32, move_insns_16): New variables.
(nop_insn_32, nop_insn_16): Likewise.
(MATCH): New macro.
(find_match): New function.
(relax_delay_slot): Likewise.
(IS_BITSIZE): New macro.
(elf32_mips_relax_section): New function.
(bfd_elf32_bfd_relax_section): Define.
* elf64-mips.c (micromips_elf64_howto_table_rel): New variable.
(micromips_elf64_howto_table_rela): Likewise.
(micromips_reloc_map): Likewise.
(bfd_elf64_bfd_reloc_type_lookup): Handle microMIPS.
(bfd_elf64_bfd_reloc_name_lookup): Likewise.
(mips_elf64_rtype_to_howto): Likewise.
* elfn32-mips.c (elf_micromips_howto_table_rel): New variable.
(elf_micromips_howto_table_rela): Likewise.
(micromips_reloc_map): Likewise.
(bfd_elf32_bfd_reloc_type_lookup): Handle microMIPS.
(bfd_elf32_bfd_reloc_name_lookup): Likewise.
(mips_elf_n32_rtype_to_howto): Likewise.
* elfxx-mips.c (micromips_reloc_shuffle_p): New function.
(TLS_RELOC_P): Handle microMIPS.
(got16_reloc_p, call16_reloc_p): Likewise.
(hi16_reloc_p, lo16_reloc_p): Likewise.
(_bfd_mips16_elf_reloc_unshuffle): Likewise.
(_bfd_mips16_elf_reloc_shuffle): Likewise.
(_bfd_mips_elf_lo16_reloc): Likewise.
(mips_tls_got_index, mips_elf_got_page): Likewise.
(mips_elf_create_local_got_entry): Likewise.
(mips_elf_relocation_needs_la25_stub): Likewise.
(mips_elf_calculate_relocation): Likewise.
(mips_elf_perform_relocation): Likewise.
(_bfd_mips_elf_symbol_processing): Likewise.
(_bfd_mips_elf_add_symbol_hook): Likewise.
(_bfd_mips_elf_link_output_symbol_hook): Likewise.
(mips_elf_add_lo16_rel_addend): Likewise.
(_bfd_mips_elf_check_relocs): Likewise.
(mips_elf_adjust_addend): Likewise.
(_bfd_mips_elf_relocate_section): Likewise.
(_bfd_mips_vxworks_finish_dynamic_symbol): Likewise.
(_bfd_mips_elf_gc_sweep_hook): Likewise.
(_bfd_mips_elf_print_private_bfd_data): Likewise.
* reloc.c (BFD_RELOC_MICROMIPS_16): New relocation.
(BFD_RELOC_MICROMIPS_7_PCREL_S1): Likewise.
(BFD_RELOC_MICROMIPS_10_PCREL_S1): Likewise.
(BFD_RELOC_MICROMIPS_16_PCREL_S1): Likewise.
(BFD_RELOC_MICROMIPS_GPREL16): Likewise.
(BFD_RELOC_MICROMIPS_JMP, BFD_RELOC_MICROMIPS_HI16): Likewise.
(BFD_RELOC_MICROMIPS_HI16_S): Likewise.
(BFD_RELOC_MICROMIPS_LO16): Likewise.
(BFD_RELOC_MICROMIPS_LITERAL): Likewise.
(BFD_RELOC_MICROMIPS_GOT16): Likewise.
(BFD_RELOC_MICROMIPS_CALL16): Likewise.
(BFD_RELOC_MICROMIPS_GOT_HI16): Likewise.
(BFD_RELOC_MICROMIPS_GOT_LO16): Likewise.
(BFD_RELOC_MICROMIPS_CALL_HI16): Likewise.
(BFD_RELOC_MICROMIPS_CALL_LO16): Likewise.
(BFD_RELOC_MICROMIPS_SUB): Likewise.
(BFD_RELOC_MICROMIPS_GOT_PAGE): Likewise.
(BFD_RELOC_MICROMIPS_GOT_OFST): Likewise.
(BFD_RELOC_MICROMIPS_GOT_DISP): Likewise.
(BFD_RELOC_MICROMIPS_HIGHEST): Likewise.
(BFD_RELOC_MICROMIPS_HIGHER): Likewise.
(BFD_RELOC_MICROMIPS_SCN_DISP): Likewise.
(BFD_RELOC_MICROMIPS_JALR): Likewise.
(BFD_RELOC_MICROMIPS_TLS_GD): Likewise.
(BFD_RELOC_MICROMIPS_TLS_LDM): Likewise.
(BFD_RELOC_MICROMIPS_TLS_DTPREL_HI16): Likewise.
(BFD_RELOC_MICROMIPS_TLS_DTPREL_LO16): Likewise.
(BFD_RELOC_MICROMIPS_TLS_GOTTPREL): Likewise.
(BFD_RELOC_MICROMIPS_TLS_TPREL_HI16): Likewise.
(BFD_RELOC_MICROMIPS_TLS_TPREL_LO16): Likewise.
* bfd-in2.h: Regenerate.
* libbfd.h: Regenerate.
* elfxx-mips.c (mips_elf_calculate_relocation): Do not mark
calls to undefined weak functions as needing jalx.
* elfxx-mips.c (LA25_LUI_MICROMIPS_1, LA25_LUI_MICROMIPS_2,
LA25_J_MICROMIPS_1, LA25_J_MICROMIPS_2, LA25_ADDIU_MICROMIPS_1,
LA25_ADDIU_MICROMIPS_2): Define.
(mips_elf_add_la25_intro, mips_elf_add_la25_trampoline): Adjust
value of stub symbol if target is a microMIPS function.
(mips_elf_create_la25_stub): Create microMIPS stub if target is
a microMIPS function.
* elfxx-mips.c (mips_elf_calculate_relocation): Expect low bit
of $t9 to be set of microMIPS _gp_disp relocations.
binutils/
2010-05-18 Chao-ying Fu <fu@mips.com>
* readelf.c (get_machine_flags): Handle microMIPS.
(get_mips_symbol_other): Likewise.
gas/
2010-05-18 Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
Daniel Jacobowitz <dan@codesourcery.com>
* config/tc-mips.h (mips_segment_info): Add one bit for
microMIPS.
* config/tc-mips.c (emit_branch_likely_macro): New variable.
(mips_set_options): Add micromips.
(mips_opts): Initialise micromips to -1.
(file_ase_micromips): New variable.
(CPU_HAS_MICROMIPS): New macro.
(micromips_op_hash): New variable.
(micromips_nop16_insn, micromips_nop32_insn): New variables.
(NOP_INSN): Handle microMIPS.
(mips32_to_micromips_reg_b_map): New macro.
(mips32_to_micromips_reg_c_map): Likewise.
(mips32_to_micromips_reg_d_map): Likewise.
(mips32_to_micromips_reg_e_map): Likewise.
(mips32_to_micromips_reg_f_map): Likewise.
(mips32_to_micromips_reg_g_map): Likewise.
(mips32_to_micromips_reg_l_map): Likewise.
(mips32_to_micromips_reg_q_map): New variable.
(micromips_to_32_reg_b_map): New macro.
(micromips_to_32_reg_c_map): Likewise.
(micromips_to_32_reg_d_map): Likewise.
(micromips_to_32_reg_e_map): Likewise.
(micromips_to_32_reg_f_map): Likewise.
(micromips_to_32_reg_g_map): Likewise.
(micromips_to_32_reg_l_map): Likewise.
(micromips_to_32_reg_q_map): New variable.
(micromips_imm_b_map, micromips_imm_c_map): New macros.
(RELAX_DELAY_SLOT_SIZE_ERROR_FIRST): New macro.
(RELAX_DELAY_SLOT_SIZE_ERROR_SECOND): Likewise.
(RELAX_MICROMIPS_ENCODE, RELAX_MICROMIPS_P): New macros.
(RELAX_MICROMIPS_TYPE, RELAX_MICROMIPS_USER_16BIT): Likewise.
(RELAX_MICROMIPS_UNCOND, RELAX_MICROMIPS_LINK): Likewise.
(RELAX_MICROMIPS_TOOFAR, RELAX_MICROMIPS_MARK_TOOFAR): Likewise.
(RELAX_MICROMIPS_CLEAR_TOOFAR): Likewise.
(RELAX_MICROMIPS_EXTENDED): Likewise.
(RELAX_MICROMIPS_MARK_EXTENDED): Likewise.
(RELAX_MICROMIPS_CLEAR_EXTENDED): Likewise.
(MICROMIPS_INSERT_OPERAND, MICROMIPS_EXTRACT_OPERAND): New
macros.
(A_BFD_RELOC_HI16_S, A_BFD_RELOC_HI16, A_BFD_RELOC_LO16): New
relocation wrapper macros.
(A_BFD_RELOC_GPREL16): Likewise.
(A_BFD_RELOC_MIPS_GOT16, A_BFD_RELOC_MIPS_GOT_HI16): Likewise.
(A_BFD_RELOC_MIPS_GOT_LO16, A_BFD_RELOC_MIPS_HIGHEST): Likewise.
(A_BFD_RELOC_MIPS_HIGHER, A_BFD_RELOC_MIPS_GOT_DISP): Likewise.
(A_BFD_RELOC_MIPS_GOT_PAGE, A_BFD_RELOC_MIPS_GOT_OFST): Likewise.
(A_BFD_RELOC_MIPS_SUB, A_BFD_RELOC_MIPS_JALR): Likewise.
(mips_macro_warning): Add delay_slot_16bit_p, delay_slot_32bit_p,
and num_insns.
(micromips_16, micromips_32): New variables.
(is_micromips_16bit_p, is_micromips_32bit_p): New functions.
(insn_length): Return the length of microMIPS instructions.
(mips_record_mips16_mode): Rename to...
(mips_record_mips16_micromips_mode): ... this. Handle microMIPS.
(install_insn): Handle microMIPS.
(is_opcode_valid): Likewise.
(md_begin): Likewise.
(md_assemble): Likewise.
(micromips_reloc_p): New function.
(got16_reloc_p): Handle microMIPS.
(hi16_reloc_p): Likewise.
(lo16_reloc_p): Likewise.
(matching_lo_reloc): Likewise.
(mips_move_labels): Likewise.
(mips16_mark_labels): Rename to...
(mips16_micromips_mark_labels): ... this. Handle microMIPS.
(insns_between): Handle microMIPS.
(MICROMIPS_TARGET, MICROMIPS_TARGET_LABEL): New macros.
(micromips_add_number_label): New function.
(append_insn): Handle microMIPS.
(start_noreorder, end_noreorder): Likewise.
(macro_start, macro_warning, macro_end): Likewise.
(macro_build): Likewise.
(macro_build_jalr): Likewise.
(macro_build_lui): Likewise.
(macro_build_ldst_constoffset): Use relocation wrappers.
(set_at): Likewise.
(load_register): Likewise.
(load_address): Likewise.
(move_register): Handle microMIPS.
(load_got_offset): Use relocation wrappers.
(add_got_offset): Likewise.
(add_got_offset_hilo): Likewise.
(macro): Handle microMIPS.
(validate_micromips_insn): New function.
(micromips_percent_op): New variable.
(parse_relocation): Handle microMIPS.
(my_getExpression): Likewise.
(options): Add OPTION_MICROMIPS and OPTION_NO_MICROMIPS.
(md_longopts): Add mmicromips and mno-micromips.
(md_parse_option): Handle OPTION_MICROMIPS and
OPTION_NO_MICROMIPS.
(mips_after_parse_args): Handle microMIPS.
(md_pcrel_from): Handle microMIPS relocations.
(mips_force_relocation): Likewise.
(md_apply_fix): Likewise.
(mips_align): Handle microMIPS.
(s_mipsset): Likewise.
(s_cpload, s_cpsetup, s_cpreturn): Use relocation wrappers.
(s_dtprel_internal): Likewise.
(s_gpword, s_gpdword): Likewise.
(s_insn): Handle microMIPS.
(s_mips_stab): Likewise.
(relaxed_micromips_32bit_branch_length): New function.
(relaxed_micromips_16bit_branch_length): New function.
(md_estimate_size_before_relax): Handle microMIPS.
(mips_fix_adjustable): Likewise.
(tc_gen_reloc): Handle microMIPS relocations.
(mips_relax_frag): Handle microMIPS.
(md_convert_frag): Likewise.
(mips_frob_file_after_relocs): Likewise.
(mips_elf_final_processing): Likewise.
(mips_nop_opcode): Likewise.
(mips_handle_align): Likewise.
(md_show_usage): Handle microMIPS options.
(micromips_ip): New function.
(micromips_macro_build): Likewise.
(micromips_macro): Likewise.
* doc/as.texinfo (Target MIPS options): Add -mmicromips and
-mno-micromips.
(-mmicromips, -mno-micromips): New options.
* doc/c-mips.texi (-mmicromips, -mno-micromips): New options.
(MIPS ISA): Document .set micromips and .set nomicromips.
* config/tc-mips.c (mips_set_options): Add ase_mcu.
(mips_opts): Initialise ase_mcu to -1.
(ISA_SUPPORTS_MCU_ASE): New macro.
(MIPS_CPU_ASE_MCU): Likewise.
(is_opcode_valid): Handle MCU.
(macro_build): Likewise.
(macro): Likewise.
(validate_mips_insn): Likewise.
(mips_ip): Likewise.
(options): Add OPTION_MCU and OPTION_NO_MCU.
(md_longopts): Add mmcu and mno-mcu.
(md_parse_option): Handle OPTION_MCU and OPTION_NO_MCU.
(mips_after_parse_args): Handle MCU.
(s_mipsset): Likewise.
(md_show_usage): Handle MCU options.
* doc/as.texinfo: Document -mmcu and -mno-mcu options.
* doc/c-mips.texi: Likewise, and document ".set mcu" and
".set nomcu" directives.
* config/tc-mips.c (nops_for_insn_or_target): Replace
MIPS16_INSN_BRANCH with MIPS16_INSN_UNCOND_BRANCH and
MIPS16_INSN_COND_BRANCH.
* config/tc-mips.c (append_insn): Replace INSN2_MOD_31 with
INSN2_READ_GPR_31. Merge with code to handle INSN_WRITE_GPR_31.
* config/tc-mips.c (mips_cpu_info_table): Add "m14k".
* doc/c-mips.texi (MIPS architecture options): Add "m14k" to the
list of -march options.
* config/tc-mips.c (mips32_to_micromips_reg_h_map): New
variable.
(mips32_to_micromips_reg_m_map): Likewise.
(mips32_to_micromips_reg_n_map): New macro.
(micromips_to_32_reg_h_map): New variable.
(micromips_to_32_reg_i_map): Likewise.
(micromips_to_32_reg_m_map): Likewise.
(micromips_to_32_reg_n_map): New macro.
(append_insn): Handle microMIPS "mh", "mi", "mm" and "mn"
operands.
* config/tc-mips.c (mips_cpu_info_table): Add "m14kc".
* doc/c-mips.texi (MIPS architecture options): Add "m14kc" to the
list of -march options.
gas/testsuite/
2010-05-18 Maciej W. Rozycki <macro@codesourcery.com>
Chao-ying Fu <fu@mips.com>
* gas/mips/beq.d: Reformat.
* gas/mips/bge.d, gas/mips/bgeu.d: Likewise.
* gas/mips/blt.d, gas/mips/bltu.d: Likewise.
* gas/mips/mips4-fp.d: Reformat.
* gas/mips/beq.d, gas/mips/beq.s: Remove checks for
branch-likely instructions and place them...
* gas/mips/bge.d, gas/mips/bge.s: Likewise.
* gas/mips/bgeu.d, gas/mips/bgeu.s: Likewise.
* gas/mips/blt.d, gas/mips/blt.s: Likewise.
* gas/mips/bltu.d, gas/mips/bltu.s: Likewise.
* gas/mips/branch-likely.d, gas/mips/branch-likely.s: ... in
this new test.
* gas/mips/mips.exp: Run the new test and update the
constraints for the upated tests to include MIPS I.
* gas/mips/mips4-fp.d, gas/mips/mips4-fp.s: Remove checks for
branch-likely instructions and place them...
* gas/mips/mips4-fp.l: Update accordingly.
* gas/mips/mips4-branch-likely.d, gas/mips/mips4-branch-likely.s:
... in this new test.
* gas/mips/mips4-branch-likely.l: New stderr output for the new
test.
* gas/mips/mips.exp (mips4-branch-likely): Run a dump test and
list tests matching branch-likely and mips4-fp tests
appropriately.
* gas/mips/micromips.d: New test.
* gas/mips/micromips-trap.d: Likewise.
* gas/mips/micromips-branch-relax-pic.d: Likewise.
* gas/mips/micromips-branch-relax-pic.d: Likewise.
* gas/mips/micromips.l: New stderr output.
* gas/mips/micromips-branch-relax.l: Likewise.
* gas/mips/micromips-branch-relax-pic.l: Likewise.
* gas/mips/micromips.s: New test source.
* gas/mips/micromips-branch-relax.s: Likewise.
* gas/mips/mips.exp: Run the new tests.
* gas/mips/mips.exp (run_dump_test_arch): Check for the presence
of an architecture-specific test first and use it if found,
before falling back to the generic one.
* gas/mips/micromips@abs.d: New test.
* gas/mips/micromips@add.d: Likewise.
* gas/mips/micromips@and.d: Likewise.
* gas/mips/micromips@beq.d: Likewise.
* gas/mips/micromips@bge.d: Likewise.
* gas/mips/micromips@bgeu.d: Likewise.
* gas/mips/micromips@blt.d: Likewise.
* gas/mips/micromips@bltu.d: Likewise.
* gas/mips/micromips@branch-likely.d: Likewise.
* gas/mips/micromips@branch-misc-1.d: Likewise.
* gas/mips/micromips@branch-misc-2-64.d: Likewise.
* gas/mips/micromips@branch-misc-2.d: Likewise.
* gas/mips/micromips@branch-misc-2pic-64.d: Likewise.
* gas/mips/micromips@branch-misc-2pic.d: Likewise.
* gas/mips/micromips@dli.d: Likewise.
* gas/mips/micromips@elf-jal.d: Likewise.
* gas/mips/micromips@elf-rel2.d: Likewise.
* gas/mips/micromips@elf-rel4.d: Likewise.
* gas/mips/micromips@lb-svr4pic-ilocks.d: Likewise.
* gas/mips/micromips@li.d: Likewise.
* gas/mips/micromips@mips1-fp.d: Likewise.
* gas/mips/micromips@mips32-cp2.d: Likewise.
* gas/mips/micromips@mips32-imm.d: Likewise.
* gas/mips/micromips@mips32-sf32.d: Likewise.
* gas/mips/micromips@mips32.d: Likewise.
* gas/mips/micromips@mips32r2-cp2.d: Likewise.
* gas/mips/micromips@mips32r2-fp32.d: Likewise.
* gas/mips/micromips@mips32r2.d: Likewise.
* gas/mips/micromips@mips4-branch-likely.d: Likewise.
* gas/mips/micromips@mips4-fp.d: Likewise.
* gas/mips/micromips@mips4.d: Likewise.
* gas/mips/micromips@mips5.d: Likewise.
* gas/mips/micromips@mips64-cp2.d: Likewise.
* gas/mips/micromips@mips64.d: Likewise.
* gas/mips/micromips@mips64r2.d: Likewise.
* gas/mips/micromips@rol-hw.d: Likewise.
* gas/mips/micromips@uld2-eb.d: Likewise.
* gas/mips/micromips@uld2-el.d: Likewise.
* gas/mips/micromips@ulh2-eb.d: Likewise.
* gas/mips/micromips@ulh2-el.d: Likewise.
* gas/mips/micromips@ulw2-eb-ilocks.d: Likewise.
* gas/mips/micromips@ulw2-el-ilocks.d: Likewise.
* gas/mips/mips32-imm.d: Likewise.
* gas/mips/mips32.d: Update immediates.
* gas/mips/micromips@mips32-cp2.s: New test source.
* gas/mips/micromips@mips32-imm.s: Likewise.
* gas/mips/micromips@mips32r2-cp2.s: Likewise.
* gas/mips/micromips@mips64-cp2.s: Likewise.
* gas/mips/mips32-imm.s: Likewise.
* gas/mips/mips32.s: Handle microMIPS.
* gas/mips/mips.exp: Add the micromips arch. Exclude mips16e
from micromips. Run mips32-imm.
* gas/mips/micromips@mcu.d: New test.
* gas/mips/mcu.d: Likewise.
* gas/mips/mcu.s: New test source.
* gas/mips/mips.exp: Run the new tests.
* gas/mips/jal-mask-11.d: New test.
* gas/mips/jal-mask-12.d: Likewise.
* gas/mips/micromips@jal-mask-11.d: Likewise.
* gas/mips/jal-mask-1.s: Source for the new tests.
* gas/mips/jal-mask-21.d: New test.
* gas/mips/jal-mask-22.d: Likewise.
* gas/mips/micromips@jal-mask-12.d: Likewise.
* gas/mips/jal-mask-2.s: Source for the new tests.
* gas/mips/mips.exp: Run the new tests.
include/elf/
2010-05-18 Chao-ying Fu <fu@mips.com>
* mips.h (R_MICROMIPS_min, R_MICROMIPS_16): New relocations.
(R_MICROMIPS_26_S1): Likewise.
(R_MICROMIPS_HI16, R_MICROMIPS_LO16): Likewise.
(R_MICROMIPS_GPREL16, R_MICROMIPS_LITERAL): Likewise.
(R_MICROMIPS_GOT16, R_MICROMIPS_PC7_S1): Likewise.
(R_MICROMIPS_PC10_S1, R_MICROMIPS_PC16_S1): Likewise.
(R_MICROMIPS_CALL16, R_MICROMIPS_GOT_DISP): Likewise.
(R_MICROMIPS_GOT_PAGE, R_MICROMIPS_GOT_OFST): Likewise.
(R_MICROMIPS_GOT_HI16, R_MICROMIPS_GOT_LO16): Likewise.
(R_MICROMIPS_SUB, R_MICROMIPS_HIGHER): Likewise.
(R_MICROMIPS_HIGHEST, R_MICROMIPS_CALL_HI16): Likewise.
(R_MICROMIPS_CALL_LO16, R_MICROMIPS_SCN_DISP): Likewise.
(R_MICROMIPS_JALR, R_MICROMIPS_HI0_LO16): Likewise.
(R_MICROMIPS_TLS_GD, R_MICROMIPS_TLS_LDM): Likewise.
(R_MICROMIPS_TLS_DTPREL_HI, R_MICROMIPS_TLS_DTPREL_LO): Likewise.
(R_MICROMIPS_TLS_GOTTPREL): Likewise.
(R_MICROMIPS_TLS_TPREL_HI16): Likewise.
(R_MICROMIPS_TLS_TPREL_LO16): Likewise.
(R_MICROMIPS_GPREL7_S2, R_MICROMIPS_PC23_S2): Likewise.
(R_MICROMIPS_max): Likewise.
(EF_MIPS_ARCH_ASE_MICROMIPS): New macro.
(ELF_ST_IS_MIPS_PLT): Likewise.
(STO_MICROMIPS): Likewise.
(ELF_ST_IS_MICROMIPS, ELF_ST_MICROMIPS, ELF_ST_SET_MICROMIPS):
Likewise.
(ELF_ST_IS_MIPS_PIC, ELF_ST_SET_MIPS_PIC): Handle microMIPS.
include/opcode/
2010-05-18 Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* mips.h
(INSN2_BRANCH_DELAY_16BIT, INSN2_BRANCH_DELAY_32BIT): New macros.
(INSN2_WRITE_GPR_S, INSN2_READ_FPR_D): Likewise.
(INSN2_MOD_GPR_MB, INSN2_MOD_GPR_MC, INSN2_MOD_GPR_MD): Likewise.
(INSN2_MOD_GPR_ME, INSN2_MOD_GPR_MF, INSN2_MOD_GPR_MG): Likewise.
(INSN2_MOD_GPR_MJ, INSN2_MOD_GPR_MP, INSN2_MOD_GPR_MQ): Likewise.
(INSN2_MOD_SP, INSN2_MOD_31): Likewise.
(INSN2_READ_GP, INSN2_READ_PC): Likewise.
(CPU_MICROMIPS): New macro.
(M_BC1FL, M_BC1TL, M_BC2FL, M_BC2TL, M_BEQL, M_BGEZL): New enum
values.
(M_BGEZALL, M_BGTZL, M_BLEZL, M_BLTZL, M_BLTZALL): Likewise.
(M_CACHE_OB, M_LDC2_OB, M_LDL_OB, M_LDM_AB, M_LDM_OB): Likewise.
(M_LDP_AB, M_LDP_OB, M_LDR_OB, M_LL_OB, M_LLD_OB): Likewise.
(M_LWC2_OB, M_LWL_OB, M_LWM_AB, M_LWP_AB, M_LWP_OB): Likewise.
(M_LWR_OB, M_LWU_OB, M_PREF_OB, M_SC_OB, M_SCD_OB): Likewise.
(M_SDC2_OB, M_SDL_OB, M_SDM_AB, M_SDM_OB, M_SDP_AB): Likewise.
(M_SDP_OB, M_SDR_OB, M_SWC2_OB, M_SWL_OB, M_SWM_AB): Likewise.
(M_SWM_OB, M_SWP_AB, M_SWP_OB, M_SWR_OB): Likewise.
(MICROMIPSOP_MASK_MAJOR, MICROMIPSOP_SH_MAJOR): New macros.
(MICROMIPSOP_MASK_IMMEDIATE, MICROMIPSOP_SH_IMMEDIATE): Likewise.
(MICROMIPSOP_MASK_DELTA, MICROMIPSOP_SH_DELTA): Likewise.
(MICROMIPSOP_MASK_CODE10, MICROMIPSOP_SH_CODE10): Likewise.
(MICROMIPSOP_MASK_TRAP, MICROMIPSOP_SH_TRAP): Likewise.
(MICROMIPSOP_MASK_SHAMT, MICROMIPSOP_SH_SHAMT): Likewise.
(MICROMIPSOP_MASK_TARGET, MICROMIPSOP_SH_TARGET): Likewise.
(MICROMIPSOP_MASK_EXTLSB, MICROMIPSOP_SH_EXTLSB): Likewise.
(MICROMIPSOP_MASK_EXTMSBD, MICROMIPSOP_SH_EXTMSBD): Likewise.
(MICROMIPSOP_MASK_INSMSB, MICROMIPSOP_SH_INSMSB): Likewise.
(MICROMIPSOP_MASK_BREAKCODE, MICROMIPSOP_SH_BREAKCODE): Likewise.
(MICROMIPSOP_SH_BREAKCODE2): Likewise.
(MICROMIPSOP_MASK_CACHEOP, MICROMIPSOP_SH_CACHEOP): Likewise.
(MICROMIPSOP_MASK_COPSEL, MICROMIPSOP_SH_COPSEL): Likewise.
(MICROMIPSOP_MASK_OFFSET12, MICROMIPSOP_SH_OFFSET12): Likewise.
(MICROMIPSOP_MASK_3BITPOS, MICROMIPSOP_SH_3BITPOS): Likewise.
(MICROMIPSOP_MASK_STYPE, MICROMIPSOP_SH_STYPE): Likewise.
(MICROMIPSOP_MASK_OFFSET10, MICROMIPSOP_SH_OFFSET10): Likewise.
(MICROMIPSOP_MASK_RS, MICROMIPSOP_SH_RS): Likewise.
(MICROMIPSOP_MASK_RT, MICROMIPSOP_SH_RT): Likewise.
(MICROMIPSOP_MASK_RD, MICROMIPSOP_SH_RD): Likewise.
(MICROMIPSOP_MASK_FS, MICROMIPSOP_SH_FS): Likewise.
(MICROMIPSOP_MASK_FT, MICROMIPSOP_SH_FT): Likewise.
(MICROMIPSOP_MASK_FD, MICROMIPSOP_SH_FD): Likewise.
(MICROMIPSOP_MASK_FR, MICROMIPSOP_SH_FR): Likewise.
(MICROMIPSOP_MASK_RS3, MICROMIPSOP_SH_RS3): Likewise.
(MICROMIPSOP_MASK_PREFX, MICROMIPSOP_SH_PREFX): Likewise.
(MICROMIPSOP_MASK_BCC, MICROMIPSOP_SH_BCC): Likewise.
(MICROMIPSOP_MASK_CCC, MICROMIPSOP_SH_CCC): Likewise.
(MICROMIPSOP_MASK_COPZ, MICROMIPSOP_SH_COPZ): Likewise.
(MICROMIPSOP_MASK_MB, MICROMIPSOP_SH_MB): Likewise.
(MICROMIPSOP_MASK_MC, MICROMIPSOP_SH_MC): Likewise.
(MICROMIPSOP_MASK_MD, MICROMIPSOP_SH_MD): Likewise.
(MICROMIPSOP_MASK_ME, MICROMIPSOP_SH_ME): Likewise.
(MICROMIPSOP_MASK_MF, MICROMIPSOP_SH_MF): Likewise.
(MICROMIPSOP_MASK_MG, MICROMIPSOP_SH_MG): Likewise.
(MICROMIPSOP_MASK_MJ, MICROMIPSOP_SH_MJ): Likewise.
(MICROMIPSOP_MASK_ML, MICROMIPSOP_SH_ML): Likewise.
(MICROMIPSOP_MASK_MP, MICROMIPSOP_SH_MP): Likewise.
(MICROMIPSOP_MASK_MQ, MICROMIPSOP_SH_MQ): Likewise.
(MICROMIPSOP_MASK_MZ, MICROMIPSOP_SH_MZ): Likewise.
(MICROMIPSOP_MASK_IMMA, MICROMIPSOP_SH_IMMA): Likewise.
(MICROMIPSOP_MASK_IMMB, MICROMIPSOP_SH_IMMB): Likewise.
(MICROMIPSOP_MASK_IMMC, MICROMIPSOP_SH_IMMC): Likewise.
(MICROMIPSOP_MASK_IMMD, MICROMIPSOP_SH_IMMD): Likewise.
(MICROMIPSOP_MASK_IMME, MICROMIPSOP_SH_IMME): Likewise.
(MICROMIPSOP_MASK_IMMF, MICROMIPSOP_SH_IMMF): Likewise.
(MICROMIPSOP_MASK_IMMG, MICROMIPSOP_SH_IMMG): Likewise.
(MICROMIPSOP_MASK_IMMH, MICROMIPSOP_SH_IMMH): Likewise.
(MICROMIPSOP_MASK_IMMI, MICROMIPSOP_SH_IMMI): Likewise.
(MICROMIPSOP_MASK_IMMJ, MICROMIPSOP_SH_IMMJ): Likewise.
(MICROMIPSOP_MASK_IMML, MICROMIPSOP_SH_IMML): Likewise.
(MICROMIPSOP_MASK_IMMM, MICROMIPSOP_SH_IMMM): Likewise.
(MICROMIPSOP_MASK_IMMN, MICROMIPSOP_SH_IMMN): Likewise.
(MICROMIPSOP_MASK_IMMO, MICROMIPSOP_SH_IMMO): Likewise.
(MICROMIPSOP_MASK_IMMP, MICROMIPSOP_SH_IMMP): Likewise.
(MICROMIPSOP_MASK_IMMQ, MICROMIPSOP_SH_IMMQ): Likewise.
(MICROMIPSOP_MASK_IMMU, MICROMIPSOP_SH_IMMU): Likewise.
(MICROMIPSOP_MASK_IMMW, MICROMIPSOP_SH_IMMW): Likewise.
(MICROMIPSOP_MASK_IMMX, MICROMIPSOP_SH_IMMX): Likewise.
(MICROMIPSOP_MASK_IMMY, MICROMIPSOP_SH_IMMY): Likewise.
(micromips_opcodes): New declaration.
(bfd_micromips_num_opcodes): Likewise.
* mips.h (OP_MASK_3BITPOS, OP_SH_3BITPOS): New macros.
(OP_MASK_OFFSET12, OP_SH_OFFSET12): Likewise.
(INSN_ASE_MASK): Add the MCU bit.
(INSN_MCU): New macro.
(M_ACLR_AB, M_ACLR_OB, M_ASET_AB, M_ASET_OB): New enum values.
* mips.h (MIPS16_INSN_UNCOND_BRANCH): New macro.
(MIPS16_INSN_BRANCH): Rename to...
(MIPS16_INSN_COND_BRANCH): ... this.
* mips.h (INSN2_MOD_31): Rename to...
(INSN2_READ_GPR_31): ... this.
(INSN2_UNCOND_BRANCH, INSN2_COND_BRANCH): New macros.
* mips.h (INSN2_MOD_GPR_MHI): New macro.
(INSN2_MOD_GPR_MM, INSN2_MOD_GPR_MN): Likewise.
(MICROMIPSOP_MASK_MH, MICROMIPSOP_SH_MH): Likewise.
(MICROMIPSOP_MASK_MI, MICROMIPSOP_SH_MI): Likewise.
(MICROMIPSOP_MASK_MM, MICROMIPSOP_SH_MM): Likewise.
(MICROMIPSOP_MASK_MN, MICROMIPSOP_SH_MN): Likewise.
ld/testsuite/
2010-05-18 Catherine Moore <clm@codesourcery.com>
Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* ld-mips-elf/jalx-1.s: New test.
* ld-mips-elf/jalx-1.d: New test output.
* ld-mips-elf/jalx-1.ld: New test linker script.
* ld-mips-elf/mips-elf.exp: Run new test.
* ld-mips-elf/jalx-2-main.s: New.
* ld-mips-elf/jalx-2.dd: New.
* ld-mips-elf/jalx-2-ex.s: New.
* ld-mips-elf/jalx-2-printf.s: New.
* ld-mips-elf/mips-elf.exp: Run new test.
opcodes/
2010-05-18 Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* micromips-opc.c: New file.
* mips-dis.c (micromips_to_32_reg_b_map): New array.
(micromips_to_32_reg_c_map, micromips_to_32_reg_d_map): Likewise.
(micromips_to_32_reg_e_map, micromips_to_32_reg_f_map): Likewise.
(micromips_to_32_reg_g_map, micromips_to_32_reg_l_map): Likewise.
(micromips_to_32_reg_q_map): Likewise.
(micromips_imm_b_map, micromips_imm_c_map): Likewise.
(print_insn_micromips): New function.
(is_micromips_mode_p): New function.
(_print_insn_mips): Handle microMIPS instructions.
* Makefile.am (CFILES): Add micromips-opc.c.
(ALL_MACHINES): Add micromips-opc.lo.
(micromips-opc.lo): Add dependencies.
* configure.in (bfd_mips_arch): Add micromips-opc.lo.
* Makefile.in: Regenerate.
* configure: Regenerate.
* mips-dis.c (mips_arch_choices): Enable MCU for "mips32r2"
and "mips64r2".
(print_insn_args): Handle MCU.
* mips-opc.c (MC): New macro.
(mips_builtin_opcodes): Add "aclr", "aset" and "iret".
* mips-dis.c (print_mips16_insn_arg): Remove branch instruction
type and delay slot determination.
(print_insn_mips16): Extend branch instruction type and delay
slot determination to cover all instructions.
* mips16-opc.c (BR): Remove macro.
(UBR, CBR): New macros.
(mips16_opcodes): Update branch annotation for "b", "beqz",
"bnez", "bteqz" and "btnez". Add branch annotation for "jalrc"
and "jrc".
* mips-dis.c (print_insn_mips): Correct branch instruction type
determination.
* mips-dis.c (micromips_to_32_reg_h_map): New variable.
(micromips_to_32_reg_i_map): Likewise.
(micromips_to_32_reg_m_map): Likewise.
(micromips_to_32_reg_n_map): New macro.
[-- Attachment #2: Type: APPLICATION/octet-stream, Size: 132901 bytes --]
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS and MCU ASE instruction set support
2010-05-18 18:19 [PATCH] MIPS: microMIPS and MCU ASE instruction set support Maciej W. Rozycki
@ 2010-05-23 21:38 ` Richard Sandiford
2010-05-24 22:25 ` Fu, Chao-Ying
` (2 more replies)
2010-05-26 20:19 ` [PATCH] MIPS: microMIPS and MCU ASE instruction set support Richard Sandiford
2010-05-27 21:39 ` Richard Sandiford
2 siblings, 3 replies; 41+ messages in thread
From: Richard Sandiford @ 2010-05-23 21:38 UTC (permalink / raw)
To: Maciej W. Rozycki
Cc: binutils, Chao-ying Fu, Ilie Garbacea, Joseph Myers,
Catherine Moore, Daniel Jacobowitz
Big patch, so this review is only for the gas and ld/testsuite bits.
I'll try to look at the rest some
Generally looks good. It would have been better to submit the
ACE, m14kc and microMIPS support as three separate changes though.
Please can you do that for the follow-up?
From a usability perspective, it's a shame that:
.set micromips
.ent foo
foo:
b 1f
nop
.end foo
.ent bar
bar:
1: nop
.end bar
disassembles as:
00000000 <foo>:
0: cfff b 0 <foo>
0: R_MICROMIPS_PC10_S1 .L11
2: 0c00 nop
4: 0c00 nop
00000006 <bar>:
6: 0c00 nop
leaving the poor user with no idea what .L11 is.
The following:
.set micromips
.ent foo
foo:
ld $10,0x1000($11)
.end foo
generates an assertion failure:
Assertion failure in micromips_macro_build at gas/config/tc-mips.c line 19466.
Please report this bug.
on mipsisa64-elf with "-mips1 -mabi=32".
"Maciej W. Rozycki" <macro@codesourcery.com> writes:
> gas/
> 2010-05-18 Chao-ying Fu <fu@mips.com>
> Maciej W. Rozycki <macro@codesourcery.com>
> Daniel Jacobowitz <dan@codesourcery.com>
>
> * config/tc-mips.h (mips_segment_info): Add one bit for
> microMIPS.
> * config/tc-mips.c
How about having something like:
#define OOD_TEXT_LABELS (mips_opts.mips16 || mips_opts.micromips)
?
> (A_BFD_RELOC_HI16_S, A_BFD_RELOC_HI16, A_BFD_RELOC_LO16): New
> relocation wrapper macros.
> (A_BFD_RELOC_GPREL16): Likewise.
> (A_BFD_RELOC_MIPS_GOT16, A_BFD_RELOC_MIPS_GOT_HI16): Likewise.
> (A_BFD_RELOC_MIPS_GOT_LO16, A_BFD_RELOC_MIPS_HIGHEST): Likewise.
> (A_BFD_RELOC_MIPS_HIGHER, A_BFD_RELOC_MIPS_GOT_DISP): Likewise.
> (A_BFD_RELOC_MIPS_GOT_PAGE, A_BFD_RELOC_MIPS_GOT_OFST): Likewise.
> (A_BFD_RELOC_MIPS_SUB, A_BFD_RELOC_MIPS_JALR): Likewise.
Did you consider doing the translation from non-microMIPS to
microMIPS in the macro_* functions, rather than in their callers?
I fear it'll be too easy to accidentally forget to use A_BFD_* in future.
> (mips_macro_warning): Add delay_slot_16bit_p, delay_slot_32bit_p,
> and num_insns.
> (micromips_16, micromips_32): New variables.
> (is_micromips_16bit_p, is_micromips_32bit_p): New functions.
> (insn_length): Return the length of microMIPS instructions.
> (mips_record_mips16_mode): Rename to...
> (mips_record_mips16_micromips_mode): ... this. Handle microMIPS.
> (install_insn): Handle microMIPS.
> (is_opcode_valid): Likewise.
> (md_begin): Likewise.
+ if (micromips_nop16_insn.insn_mo == NULL
+ && strcmp (name, "nop") == 0)
+ {
+ create_insn (µmips_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 (µmips_nop32_insn, micromips_opcodes + i);
+ micromips_nop32_insn.fixed_p = 1;
+ }
You seem to rely on the 16-bit nop being first. Wouldn't it be more
robust to call is_micromips_16bit_p and is_micromips_32bit_p?
> (MICROMIPS_TARGET, MICROMIPS_TARGET_LABEL): New macros.
> (micromips_add_number_label): New function.
+/* For microMIPS macros, we need to generate a local number label
+ as the target of branches. */
+#define MICROMIPS_TARGET "2147483647f"
+#define MICROMIPS_TARGET_LABEL 2147483647
+
+static void
+micromips_add_number_label (void)
+{
+ symbolS *s;
+ fb_label_instance_inc (MICROMIPS_TARGET_LABEL);
+ s = colon (fb_label_name (MICROMIPS_TARGET_LABEL, 0));
+ S_SET_OTHER (s, ELF_ST_SET_MICROMIPS (S_GET_OTHER (s)));
+}
+
Ugh, this is a bit hackish. There's nothing stopping a user using
2147483647f themselves.
> (append_insn): Handle microMIPS.
+ if (mips_opts.micromips)
+ {
+ if ((prev_pinfo2 & INSN2_BRANCH_DELAY_16BIT)
+ && !is_micromips_16bit_p (ip->insn_mo))
+ as_warn (_("instruction with wrong size in a branch delay slot that"
+ " requires a 16-bit instruction"));
+ if ((prev_pinfo2 & INSN2_BRANCH_DELAY_32BIT)
+ && !is_micromips_32bit_p (ip->insn_mo))
+ as_warn (_("instruction with wrong size in a branch delay slot that"
+ " requires a 32-bit instruction"));
+ }
+
Although not enforced as often as it should be, GAS convention is for
errors to start with a capital letter.
+ if (pinfo & INSN_COP)
+ {
+ /* We don't keep enough information to sort these cases out.
+ The itbl support does keep this information however, although
+ we currently don't support itbl fprmats as part of the cop
+ instruction. May want to add this support in the future. */
+ }
Assert?
+ /* For microMIPS, disable reordering. */
+ || (mips_opts.micromips)
Redundant (...)
- if (mips_relax.sequence)
- mips_relax.sizes[mips_relax.sequence - 1] += 4;
+ /* MicroMIPS nop is 2 bytes. */
+ if (mips_relax.sequence)
+ mips_relax.sizes[mips_relax.sequence - 1] +=
+ mips_opts.micromips ? micromips_nop_size : 4;
Confusing comment: the microMIPS nop may be 2 or 4 bytes.
Better to say nothing IMO.
> (start_noreorder, end_noreorder): Likewise.
+ frag_grow ((mips_opts.mips16 | mips_opts.micromips) ? nops * 2
+ : nops * 4);
How about a NOP_INSN_SIZE macro? (Or similar.)
> (macro_start, macro_warning, macro_end): Likewise.
+ else if ((subtype & RELAX_DELAY_SLOT_SIZE_ERROR_FIRST)
+ || (subtype & RELAX_DELAY_SLOT_SIZE_ERROR_SECOND))
+ return _("Macro instruction of the wrong size in a branch delay slot"
+ " that requires a 16-bit or 32-bit instruction");
Did you consider adding a flag to distinguish the 32-bit and 16-bit cases?
It'd be nice to be consistent with the non-relaxed error if possible.
+ /* If either one implementation contains one instruction, we need to check
+ the delay slot size requirement. */
"If either implementation"
+ /* If either one implementation contains one instruction, we need to check
+ the delay slot size requirement. */
+ if (mips_macro_warning.num_insns[0] == 1
+ || mips_macro_warning.num_insns[1] == 1)
+ {
+ if (mips_macro_warning.num_insns[0] == mips_macro_warning.num_insns[1]
+ && mips_macro_warning.sizes[0] == mips_macro_warning.sizes[1])
+ {
+ /* Either the macro has a single implementation or both
+ implementations are 1 instruction with the same size.
+ Emit the warning now. */
+ if ((mips_macro_warning.delay_slot_16bit_p
+ && mips_macro_warning.sizes[0] != 2)
+ || (mips_macro_warning.delay_slot_32bit_p
+ && mips_macro_warning.sizes[0] != 4))
+ {
+ const char *msg;
+ msg = macro_warning (RELAX_DELAY_SLOT_SIZE_ERROR_FIRST);
+ if (msg != 0)
+ as_warn (msg);
+ }
+ }
+ else
+ {
+ relax_substateT subtype;
+
+ /* Set up the relaxation warning flags. */
+ subtype = 0;
+ if (mips_macro_warning.delay_slot_16bit_p)
+ {
+ if (mips_macro_warning.num_insns[0] != 1
+ || mips_macro_warning.sizes[0] != 2)
+ subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
+ if (mips_macro_warning.num_insns[1] != 1
+ || mips_macro_warning.sizes[1] != 2)
+ subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
+ }
+ if (mips_macro_warning.delay_slot_32bit_p)
+ {
+ if (mips_macro_warning.num_insns[0] != 1
+ || mips_macro_warning.sizes[0] != 4)
+ subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
+ if (mips_macro_warning.num_insns[1] != 1
+ || mips_macro_warning.sizes[1] != 4)
+ subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
+ }
+
+ /* One implementation might need a warning but the other
+ definitely doesn't. */
+ mips_macro_warning.first_frag->fr_subtype |= subtype;
+ }
+ }
Why not work out the subtype, then check whether both ERROR_FIRST and
ERROR_SECOND are set?
+ if (mips_macro_warning.delay_slot_p)
+ {
+ if (mips_macro_warning.num_insns[0] > 1)
+ subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
+ if (mips_macro_warning.num_insns[1] > 1)
+ subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
+ }
I don't get why this hunk is needed. I thought ERROR_FIRST and ERROR_SECOND
controlled cases where a macro has a single-insn expansion that is the
wrong size, which ought to be handled by the block above. If the code
really is needed, you should add a comment explaining why.
> (macro_build): Likewise.
+ if (mips_opts.micromips)
+ {
+ if (strcmp (name, "lui") == 0)
+ micromips_macro_build (ep, name, "s,u", args);
+ else if (strcmp (fmt, "d,w,<") == 0)
+ micromips_macro_build (ep, name, "t,r,<", args);
+ else
+ micromips_macro_build (ep, name, fmt, args);
+ va_end (args);
+ return;
+ }
A bit of commentary might help explain the letter switch here.
> (macro_build_jalr): Likewise.
+ if (mips_opts.micromips)
+ {
+ if (HAVE_NEWABI)
+ macro_build (NULL, "jalr", "t,s", RA, PIC_CALL_REG);
+ else
+ macro_build (NULL, "jalr", "mj", PIC_CALL_REG);
+ }
+ else
+ macro_build (NULL, "jalr", "d,s", RA, PIC_CALL_REG);
Why HAVE_NEWABI? Do you want a 32-bit insn for R_MIPS_JALR?
If so, you should check MIPS_JALR_HINT_P (ep) instead.
> (load_register): Likewise.
- macro_build (&tmp, "ori", "t,r,i", reg, 0, BFD_RELOC_LO16);
+ macro_build (&tmp, "ori", "t,r,i", reg, 0, A_BFD_RELOC_LO16);
macro_build (NULL, (shift >= 32) ? "dsll32" : "dsll", "d,w,<",
- reg, reg, (shift >= 32) ? shift - 32 : shift);
+ reg, reg, (shift >= 32) ? shift - 32 : shift);
Last change looks bogus.
> (md_apply_fix): Likewise.
- gas_assert (fixP->fx_size == 4
+ gas_assert (fixP->fx_size == 2
+ || fixP->fx_size == 4
|| fixP->fx_r_type == BFD_RELOC_16
+ || fixP->fx_r_type == BFD_RELOC_MICROMIPS_16
|| fixP->fx_r_type == BFD_RELOC_64
|| fixP->fx_r_type == BFD_RELOC_CTOR
|| fixP->fx_r_type == BFD_RELOC_MIPS_SUB
+ || fixP->fx_r_type == BFD_RELOC_MICROMIPS_SUB
|| fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
|| fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
|| fixP->fx_r_type == BFD_RELOC_MIPS_TLS_DTPREL64);
+
buf = (bfd_byte *) (fixP->fx_frag->fr_literal + fixP->fx_where);
Last change is bogus.
+ case BFD_RELOC_MICROMIPS_7_PCREL_S1:
+ case BFD_RELOC_MICROMIPS_10_PCREL_S1:
+ case BFD_RELOC_MICROMIPS_16_PCREL_S1:
+ /* We adjust the offset back to even. */
+ if ((*valP & 0x1) != 0)
+ --(*valP);
+
+ if (! fixP->fx_done)
+ break;
+
+ /* Should never visit here, because we keep the relocation. */
+ abort ();
+ break;
I suppose this silently ignores branches to non-microMIPS code,
but there again, so does the MIPS16 equivalent...
> (mips_relax_frag): Handle microMIPS.
+ gas_assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2
+ || fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
+ || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1
+ || fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1);
+
+ /* For 7/10 PCREL_S1, we just need to use fixp->fx_addnumber. */
+ if (fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
+ || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1)
+ reloc->addend = fixp->fx_addnumber;
+ else
+ /* At this point, fx_addnumber is "symbol offset - pcrel address".
+ Relocations want only the symbol offset. */
+ reloc->addend = fixp->fx_addnumber + reloc->address;
A better comment is needed. _Why_ do you just need fx_addnumber?
> (md_convert_frag): Likewise.
- /* Possibly emit a warning if we've chosen the longer option. */
- if (((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
- == ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))
+ if (!(fragp->fr_subtype & RELAX_USE_SECOND))
+ {
+ /* Check if the size in branch delay slot is ok. */
+ if (fragp->fr_subtype & RELAX_DELAY_SLOT_SIZE_ERROR_FIRST)
+ {
+ const char *msg = macro_warning (fragp->fr_subtype);
+ if (msg != 0)
+ as_warn_where (fragp->fr_file, fragp->fr_line, msg);
+ }
+ }
+ else
{
- const char *msg = macro_warning (fragp->fr_subtype);
- if (msg != 0)
- as_warn_where (fragp->fr_file, fragp->fr_line, "%s", msg);
+ /* Check if the size in branch delay slot is ok.
+ Possibly emit a warning if we've chosen the longer option. */
+ if ((fragp->fr_subtype & RELAX_DELAY_SLOT_SIZE_ERROR_SECOND)
+ || (fragp->fr_subtype & RELAX_SECOND_LONGER))
+ {
+ const char *msg = macro_warning (fragp->fr_subtype);
+ if (msg != 0)
+ as_warn_where (fragp->fr_file, fragp->fr_line, msg);
+ }
}
This doesn't accurately preserve the previous:
if (((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
== ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))
behaviour.
> (mips_handle_align): Likewise.
/* If we're not inserting a whole number of instructions,
- pad the end of the fixed part of the frag with zeros. */
- memset (p, 0, excess);
+ pad the end of the fixed part of the frag with zeros.
+ But try to fit a short microMIPS nop too if applicable. */
+ if (excess < 2 || *p != 2)
+ memset (p, 0, excess);
+ else
+ {
+ memset (p, 0, excess - 2);
+ md_number_to_chars (p + excess - 2,
+ micromips_nop16_insn.insn_opcode, 2);
+ }
Not how it'd be written from scratch; the comment makes microMIPS sound
like an afterthought. Please handle the microMIPS case first and make
the comment treat it as a first-class citizen.
> (micromips_ip): New function.
+ /* Try to search "16" or "32" in the str. */
+ if ((t = strstr (str, "16")) != NULL && t < save_s)
+ {
+ /* Make sure "16" is before the first '.' if '.' exists. */
+ if ((s = strchr (str, '.')) != NULL && (t + 2 != s))
+ {
+ insn_error = "unrecognized opcode";
+ return;
+ }
+
+ /* Make sure "16" is at the end of insn name, if no '.'. */
+ if ((s = strchr (str, '.')) == NULL
+ && (!ISSPACE (*(t + 2)) && *(t + 2) != '\0'))
+ {
+ insn_error = "unrecognized opcode";
+ return;
+ }
+
+ micromips_16 = TRUE;
+ for (s = t + 2; *s != '\0'; ++s)
+ *(s - 2) = *s;
+ *(s - 2) = '\0';
+
+ for (s = t; *s != '\0' && !ISSPACE (*s); ++s)
+ continue;
+
+ if (ISSPACE (*s))
+ {
+ save_c = *s;
+ *s++ = '\0';
+ }
+
+ if ((insn = (struct mips_opcode *) hash_find (micromips_op_hash, str))
+ == NULL)
+ {
+ int i;
+ int length;
+ micromips_16 = FALSE;
+
+ /* Restore the character we overwrite above (if any). */
+ if (save_c)
+ *(--s) = save_c;
+
+ length = strlen (str);
+ for (i = length - 1; &str[i] >= t; i--)
+ {
+ str[i + 2] = str[i];
+ if (t == &str[i])
+ {
+ str[i + 1] = '6';
+ str[i] = '1';
+ str[length + 2] = '\0';
+ break;
+ }
+ }
+
+ insn_error = "unrecognized 16-bit version of microMIPS opcode";
+ return;
+ }
+ }
+ else if ((t = strstr (str, "32")) != NULL && t < save_s)
+ {
+ /* For some instruction names, we already have 32, so we need
+ to seek the second 32 to process. Ex: bposge3232, dsra3232. */
+ char *new_t;
+ if ((new_t = strstr (t + 2, "32")) != NULL && new_t < save_s)
+ t = new_t;
+
+ /* Make sure "32" is before the first '.' if '.' exists. */
+ if ((s = strchr (str, '.')) != NULL && (t + 2 != s))
+ {
+ insn_error = "unrecognized opcode";
+ return;
+ }
+
+ /* Make sure "32" is at the end of the name, if no '.'. */
+ if ((s = strchr (str, '.')) == NULL
+ && (!ISSPACE (*(t + 2)) && *(t + 2) != '\0'))
+ {
+ insn_error = "unrecognized opcode";
+ return;
+ }
+
+ micromips_32 = TRUE;
+ for (s = t + 2; *s != '\0'; ++s)
+ *(s - 2) = *s;
+ *(s - 2) = '\0';
+
+ for (s = t; *s != '\0' && !ISSPACE (*s); ++s)
+ continue;
+
+ if (ISSPACE (*s))
+ {
+ save_c = *s;
+ *s++ = '\0';
+ }
+
+ if ((insn = (struct mips_opcode *) hash_find (micromips_op_hash, str))
+ == NULL)
+ {
+ int i;
+ int length;
+ micromips_32 = FALSE;
+
+ /* Restore the character we overwrite above (if any). */
+ if (save_c)
+ *(--s) = save_c;
+
+ length = strlen (str);
+ for (i = length - 1; &str[i] >= t; i--)
+ {
+ str[i + 2] = str[i];
+ if (t == &str[i])
+ {
+ str[i + 1] = '2';
+ str[i] = '3';
+ str[length + 2] = '\0';
+ break;
+ }
+ }
+
+ insn_error = "unrecognized 32-bit version of microMIPS opcode";
+ return;
+ }
Far too much cut-&-paste between the "16" and "32" cases. Also:
+ if ((t = strstr (str, "16")) != NULL && t < save_s)
t < save_s must surely be true, since save_s is the null terminator.
+ /* Make sure "16" is before the first '.' if '.' exists. */
+ if ((s = strchr (str, '.')) != NULL && (t + 2 != s))
+ {
+ insn_error = "unrecognized opcode";
+ return;
+ }
+
+ /* Make sure "16" is at the end of insn name, if no '.'. */
+ if ((s = strchr (str, '.')) == NULL
+ && (!ISSPACE (*(t + 2)) && *(t + 2) != '\0'))
+ {
+ insn_error = "unrecognized opcode";
+ return;
+ }
Don't call strchr (str, '.') twice like that. Better would be:
s = strchr (str, '.');
followed by the two checks. Isn't the ISSPACE check redundant though,
given that you've terminated the string at the first space? I would
have thought:
if (t + 2 != (s ? s : save_s))
would be enough. Errors should start with a capital letter. Missing
internationalisation.
You could use alloca to create an opcode without the "16" or "32",
which would make the error-reporting code simpler. It's best not
to change the user's source line if we can help it.
+ if (!insn_error)
+ {
+ static char buf[100];
+ sprintf (buf,
+ _("opcode not supported on this processor: %s (%s)"),
+ mips_cpu_info_from_arch (mips_opts.arch)->name,
+ mips_cpu_info_from_isa (mips_opts.isa)->name);
+ insn_error = buf;
+ }
+ if (save_c)
+ *(--s) = save_c;
+
+ if (micromips_16 || micromips_32)
+ {
+ int i;
+ int length;
+
+ length = strlen (str);
+ for (i = length - 1; i >= 0; i--)
+ {
+ str[i + 2] = str[i];
+ if (t == &str[i])
+ break;
+ }
+ if (micromips_16)
+ {
+ insn_error =
+ "unrecognized 16-bit version of microMIPS opcode";
+ str[i + 1] = '6';
+ str[i] = '1';
+ }
+ else
+ {
+ insn_error =
+ "unrecognized 32-bit version of microMIPS opcode";
+ str[i + 1] = '2';
+ str[i] = '3';
+ }
+ str[length + 2] = '\0';
+ }
+ return;
Why override the insn_error unconditionally like this? E.g.:
jar16 $30,$26
Error: unrecognized 16-bit version of microMIPS opcode `jar16 $30,$26'
implies there's a 32-bit opcode. I'd also have thought that the
"opcode not supported on this processor" would triumph if it applies.
+do_lsb:
Not properly indented. A few other instances.
+ }
+ }
+ /* Now that we have assembled one operand, we use the args string
+ * to figure out where it goes in the instruction. */
+ switch (c)
+ {
Bogus indentation.
> (micromips_macro_build): Likewise.
> (micromips_macro): Likewise.
I'll look at micromips_ip and these two in more detail later.
> * ld-mips-elf/jalx-2-main.s: New.
> * ld-mips-elf/jalx-2.dd: New.
> * ld-mips-elf/jalx-2-ex.s: New.
> * ld-mips-elf/jalx-2-printf.s: New.
> * ld-mips-elf/mips-elf.exp: Run new test.
Please make the .dd output less susceptible to things like the number
of sections, size of program headers, etc. One way is to use a linker
script to place each section at a nice round address. Another is to
".*" out the addresses and instruction encodings and just reply on
the symbolic part of the disassembly. I think the former's better
here. There are quite a few existing examples.
Richard
^ permalink raw reply [flat|nested] 41+ messages in thread
* RE: [PATCH] MIPS: microMIPS and MCU ASE instruction set support
2010-05-23 21:38 ` Richard Sandiford
@ 2010-05-24 22:25 ` Fu, Chao-Ying
2010-05-26 19:47 ` Richard Sandiford
2010-06-01 14:21 ` Maciej W. Rozycki
2010-07-26 10:56 ` [PATCH] MIPS: microMIPS ASE support Maciej W. Rozycki
2 siblings, 1 reply; 41+ messages in thread
From: Fu, Chao-Ying @ 2010-05-24 22:25 UTC (permalink / raw)
To: Richard Sandiford, Maciej W. Rozycki
Cc: binutils, Garbacea, Ilie, Joseph Myers, Catherine Moore, dan
Richard Sandiford wrote:
> > (mips_relax_frag): Handle microMIPS.
>
> + gas_assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2
> + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
> + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1
> + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1);
> +
> + /* For 7/10 PCREL_S1, we just need to use
> fixp->fx_addnumber. */
> + if (fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
> + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1)
> + reloc->addend = fixp->fx_addnumber;
> + else
> + /* At this point, fx_addnumber is "symbol offset -
> pcrel address".
> + Relocations want only the symbol offset. */
> + reloc->addend = fixp->fx_addnumber + reloc->address;
>
> A better comment is needed. _Why_ do you just need fx_addnumber?
>
Thanks for the review! The explanation is in another place as
follows.
Maybe we need to copy the comment to tc_gen_reloc from md_pcrel_from.
Ex:
long
md_pcrel_from (fixS *fixP)
{
valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
switch (fixP->fx_r_type)
{
/* We don't add addr, because it will cause the error checking of
"addnumber" fail in write.c for *7/10_PCREL_S1.
In tc_gen_reloc, we just use fixp->fx_addnumber. */
case BFD_RELOC_MICROMIPS_7_PCREL_S1:
case BFD_RELOC_MICROMIPS_10_PCREL_S1:
/* Return the beginning of the delay slot from the current insn.
*/
return 2;
case BFD_RELOC_MICROMIPS_16_PCREL_S1:
case BFD_RELOC_MICROMIPS_JMP:
case BFD_RELOC_16_PCREL_S2:
case BFD_RELOC_MIPS_JMP:
/* Return the address of the delay slot. */
return addr + 4;
...
The field of *7/10_PCREL_S1 is limited in the 16-bit instructions.
If we add the "address", write.c will fail to check these two
relocations due to overflow or something (I kind of forgot). From
debugging, adding "address" is no use at all, because later "address" is
subtracted.
Maybe, we can do the same thing to *16_PCREL* by discarding address in
tc_gen_reloc() and md_pcrel_from(),
such that code looks cleaner and the same.
Thanks!
Regards,
Chao-ying
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS and MCU ASE instruction set support
2010-05-24 22:25 ` Fu, Chao-Ying
@ 2010-05-26 19:47 ` Richard Sandiford
0 siblings, 0 replies; 41+ messages in thread
From: Richard Sandiford @ 2010-05-26 19:47 UTC (permalink / raw)
To: Fu, Chao-Ying
Cc: Maciej W. Rozycki, binutils, Garbacea, Ilie, Joseph Myers,
Catherine Moore, dan
"Fu, Chao-Ying" <fu@mips.com> writes:
> Richard Sandiford wrote:
>> > (mips_relax_frag): Handle microMIPS.
>>
>> + gas_assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2
>> + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
>> + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1
>> + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1);
>> +
>> + /* For 7/10 PCREL_S1, we just need to use
>> fixp->fx_addnumber. */
>> + if (fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
>> + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1)
>> + reloc->addend = fixp->fx_addnumber;
>> + else
>> + /* At this point, fx_addnumber is "symbol offset -
>> pcrel address".
>> + Relocations want only the symbol offset. */
>> + reloc->addend = fixp->fx_addnumber + reloc->address;
>>
>> A better comment is needed. _Why_ do you just need fx_addnumber?
>>
>
> Thanks for the review! The explanation is in another place as
> follows.
> Maybe we need to copy the comment to tc_gen_reloc from md_pcrel_from.
> Ex:
> long
> md_pcrel_from (fixS *fixP)
> {
> valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
> switch (fixP->fx_r_type)
> {
> /* We don't add addr, because it will cause the error checking of
> "addnumber" fail in write.c for *7/10_PCREL_S1.
> In tc_gen_reloc, we just use fixp->fx_addnumber. */
> case BFD_RELOC_MICROMIPS_7_PCREL_S1:
> case BFD_RELOC_MICROMIPS_10_PCREL_S1:
> /* Return the beginning of the delay slot from the current insn.
> */
> return 2;
>
> case BFD_RELOC_MICROMIPS_16_PCREL_S1:
> case BFD_RELOC_MICROMIPS_JMP:
> case BFD_RELOC_16_PCREL_S2:
> case BFD_RELOC_MIPS_JMP:
> /* Return the address of the delay slot. */
> return addr + 4;
> ...
> The field of *7/10_PCREL_S1 is limited in the 16-bit instructions.
> If we add the "address", write.c will fail to check these two
> relocations due to overflow or something (I kind of forgot). From
> debugging, adding "address" is no use at all, because later "address" is
> subtracted.
Ah, thanks, that's a good explanation. Yeah, at least a cross-reference
would be useful if we keep things as they are. However...
...I think you mean this bit of write.c:
if (fixP->fx_size < sizeof (valueT) && 0)
{
valueT mask;
mask = 0;
mask--; /* Set all bits to one. */
mask <<= fixP->fx_size * 8 - (fixP->fx_signed ? 1 : 0);
if ((add_number & mask) != 0 && (add_number & mask) != mask)
{
char buf[50], buf2[50];
sprint_value (buf, fragP->fr_address + fixP->fx_where);
if (add_number > 1000)
sprint_value (buf2, add_number);
else
sprintf (buf2, "%ld", (long) add_number);
as_bad_where (fixP->fx_file, fixP->fx_line,
_("value of %s too large for field of %d bytes at %s"),
buf2, fixP->fx_size, buf);
} /* Generic error checking. */
}
That check's bogus for these relocations anyway, since it doesn't take
the implied shift into account. I think there's an argument to say
we should set fx_no_overflow for these relocations and leave the
overflow checking to bfd. You'll still get a "relocation overflow"
error if the final in-place addend really is too big.
Richard
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS and MCU ASE instruction set support
2010-05-18 18:19 [PATCH] MIPS: microMIPS and MCU ASE instruction set support Maciej W. Rozycki
2010-05-23 21:38 ` Richard Sandiford
@ 2010-05-26 20:19 ` Richard Sandiford
2010-05-27 21:39 ` Richard Sandiford
2 siblings, 0 replies; 41+ messages in thread
From: Richard Sandiford @ 2010-05-26 20:19 UTC (permalink / raw)
To: Maciej W. Rozycki
Cc: binutils, Chao-ying Fu, Ilie Garbacea, Joseph Myers,
Catherine Moore, Daniel Jacobowitz
Part 2 of the review.
This testcase:
.set micromips
.fill 0x80
b16 .-0x80
produces:
/tmp/foo.s: Assembler messages:
/tmp/foo.s:3: Error: unrecognized opcode `b16 .-0x80'
while:
.set micromips
.fill 0x80
b .-0x80
successfully produces a 16-bit insn.
@@ -14813,6 +16230,8 @@ mips_elf_final_processing (void)
file_ase_mt is true. */
if (file_ase_mips16)
elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_M16;
+ if (file_ase_micromips)
+ elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_MICROMIPS;
#if 0 /* XXX FIXME */
if (file_ase_mips3d)
elf_elfheader (stdoutput)->e_flags |= ???;
Do you really only want this flag to be set if -mmicromips was passed
on the command line? (Yes, the same concern applies to MIPS16 and MDMX.)
Lots of cases where a space is missing before "(".
Please be consistent about "str[n]cmp (...) == 0" vs '!str[n]cmp (...)':
use one or the other. (IMO the first is clearer.)
micromips_ip obviously started life as a cut-&-paste of mips_ip, and it
would have been nice to factor some code out. At least split out the
block beginning:
+ case 'F':
+ case 'L':
+ case 'f':
+ case 'l':
+ {
which is identical between the two, and far too subtle to copy wholesale.
There may be other good opportunities too.
+ case '(':
+ /* Handle optional base register.
+ Either the base register is omitted or
+ we must have a left paren. */
+ /* This is dependent on the next operand specifier
+ is a base register specification. */
+ gas_assert (args[1] == 'b'
+ || (args[1] == 'm'
+ && (args[2] == 'l' || args[2] == 'n'
+ || args[2] == 's' || args[2] == 'a')));
+ if (*s == '\0' && args[1] == 'b')
+ return;
+
+ case ')': /* these must match exactly */
+ case '[':
+ case ']':
+ if (*s++ == *args)
+ continue;
+ break;
Mark fallthrough.
+ case 'D': /* floating point destination register */
+ case 'S': /* floating point source register */
+ case 'T': /* floating point target register */
+ case 'R': /* floating point source register */
+ case 'V':
+ rtype = RTYPE_FPU;
+ s_reset = s;
+ if (reg_lookup (&s, rtype, ®no))
+ {
+ 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 < µmips_opcodes[bfd_micromips_num_opcodes] &&
+ !strcmp (insn->name, insn[1].name))
Misplaced "&&".
+ = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};;
Double ";".
+ macro_read_relocs (&args, r);
Not portable in this context (and doesn't build on x86_64-linux-gnu).
You're taking the address of a va_list argument rather than a va_list
local variable.
+ /* For microMIPS, we always use relocations for branches.
+ So, we should not resolve immediate values. */
Too many spaces.
+ if (ep->X_op == O_constant)
+ abort ();
+ else
+ *r = BFD_RELOC_MICROMIPS_16_PCREL_S1;
gcc_assert (ep->X_op != O_constant);
*r = BFD_RELOC_MICROMIPS_16_PCREL_S1;
The same cut-&-paste concerns apply to micromips_macro, which obviously
started out as a copy of macro(). I realise there are special cases
for micromips (such as the DADDI assymmetry and the lack of
branch-likely instructions, to name only a few), but most of the
basic decisions are the same.
As it stands, we have a new 3524 line function, of which I imagine at
least 90% is shared with macro(). I really think the new microMIPS
macro handling should be integrated into macro() instead. Don't be
afraid of factoring out code from macro() if it makes it easier to
integrate the microMIPS code.
#define CPU_MIPS5 5
#define CPU_MIPS64 64
#define CPU_MIPS64R2 65
+#define CPU_MICROMIPS 96
#define CPU_SB1 12310201 /* octal 'SB', 01. */
#define CPU_LOONGSON_2E 3001
#define CPU_LOONGSON_2F 3002
What's this for? It doesn't seem to be used.
+ "mA" 7-bit immediate (-63 .. 64) << 2 (MICROMIPSOP_*_IMMA)
Don't you mean (-64 .. 63)?
+ "mB" 3-bit immediate (0, -1, 1, 4, 8, 12, 16, 20, 24) (MICROMIPSOP_*_IMMB)
That's nine values. Should the 0 really be there?
@@ -630,15 +630,15 @@ proc strip_executable { prog flags test
remote_upload host ${copyfile} tmpdir/striprog
}
- set result [remote_load target tmpdir/striprog]
- set status [lindex $result 0]
- if { ![istarget $host_triplet] } {
- set status "pass"
- }
- if { $status != "pass" } {
- fail $test
- return
- }
+# set result [remote_load target tmpdir/striprog]
+# set status [lindex $result 0]
+# if { ![istarget $host_triplet] } {
+# set status "pass"
+# }
+# if { $status != "pass" } {
+# fail $test
+# return
+# }
set exec_output [binutils_run $NM "$NMFLAGS ${copyfile}"]
if ![string match "*: no symbols*" $exec_output] {
@@ -673,15 +673,15 @@ proc strip_executable_with_saving_a_symb
remote_upload host ${copyfile} tmpdir/striprog
}
- set result [remote_load target tmpdir/striprog]
- set status [lindex $result 0]
- if { ![istarget $host_triplet] } {
- set status "pass"
- }
- if { $status != "pass" } {
- fail $test
- return
- }
+# set result [remote_load target tmpdir/striprog]
+# set status [lindex $result 0]
+# if { ![istarget $host_triplet] } {
+# set status "pass"
+# }
+# if { $status != "pass" } {
+# fail $test
+# return
+# }
set exec_output [binutils_run $NM "$NMFLAGS ${copyfile}"]
if { [istarget mmix-knuth-mmixware] } {
Looks like these crept in unawares.
PLT entries and traditional MIPS lazy binding stubs. We mark the former
with STO_MIPS_PLT to distinguish them from the latter. */
#define STO_MIPS_PLT 0x8
+#define ELF_ST_IS_MIPS_PLT(OTHER) (((OTHER) & 0x8) == STO_MIPS_PLT)
...
#define STO_MIPS_PIC 0x20
#define ELF_ST_IS_MIPS_PIC(OTHER) \
- (((OTHER) & ~ELF_ST_VISIBILITY (-1)) == STO_MIPS_PIC)
+ (((OTHER) & ~ELF_ST_VISIBILITY (-1) & ~0xc0) == STO_MIPS_PIC)
#define ELF_ST_SET_MIPS_PIC(OTHER) \
- (STO_MIPS_PIC | ELF_ST_VISIBILITY (OTHER))
+ (STO_MIPS_PIC | ELF_ST_VISIBILITY (OTHER) | ELF_ST_MICROMIPS (OTHER))
...
case STO_OPTIONAL: return "OPTIONAL";
case STO_MIPS16: return "MIPS16";
- case STO_MIPS_PLT: return "MIPS PLT";
- case STO_MIPS_PIC: return "MIPS PIC";
- default: return NULL;
+ default:
+ if (ELF_ST_IS_MIPS_PLT (other))
+ {
+ if (ELF_ST_IS_MICROMIPS (other))
+ return "MICROMIPS, MIPS PLT";
+ else
+ return "MIPS PLT";
+ }
+ if (ELF_ST_IS_MIPS_PIC (other))
+ {
+ if (ELF_ST_IS_MICROMIPS (other))
+ return "MICROMIPS, MIPS PIC";
+ else
+ return "MIPS PIC";
+ }
+ if (ELF_ST_IS_MICROMIPS (other))
+ return "MICROMIPS";
+
+ return NULL;
You don't add support for microMIPS PLTs, so the "MICROMIPS, MIPS PLT"
thing appears to be dead code. I wouldn't mind, except that it makes
the code inconsistent with MIPS16: the changes above allow both
STO_MIPS16 | STO_MIPS_PLT
and
STO_MICROMIPS | STO_MIPS_PLT
neither of which are currently used, but you don't treat the two equally.
In other words, I'm happy with the STO_MIPS_PIC changes but not with
the STO_MIPS_PLT ones.
+ /* 16 bit relocation. */
+ HOWTO (R_MICROMIPS_16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ _bfd_mips_elf_lo16_reloc, /* special_function */
+ "R_MICROMIPS_16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
Is this relocation really a lo16 one? If so, it's not consistent
with R_MIPS_16 (which isn't).
+/*
+ * Delay slot size and relaxation support
+ */
+static unsigned long
+relax_delay_slot (bfd *abfd, bfd_byte *ptr, unsigned long* opcode_32)
+{
+ unsigned long bdsize = 0;
+
+ unsigned long fndopc;
+ unsigned long p16opc, p32opc;
+
+ /* Opcodes preceding the current instruction. */
+ p16opc = bfd_get_16 (abfd, ptr - 2);
+ p32opc = bfd_get_16 (abfd, ptr - 4) << 16;
You need to check the section bounds. The code appears to read off the
beginning of a section if that section starts with a relaxable LUI.
+ /* If this isn't something that can be relaxed, then ignore
+ this reloc. */
+ if (ELF32_R_TYPE (irel->r_info) != (int) R_MICROMIPS_HI16 &&
+ ELF32_R_TYPE (irel->r_info) != (int) R_MICROMIPS_LO16 &&
+ ELF32_R_TYPE (irel->r_info) != (int) R_MICROMIPS_PC16_S1 &&
+ ELF32_R_TYPE (irel->r_info) != (int) R_MICROMIPS_26_S1 &&
+ ELF32_R_TYPE (irel->r_info) != (int) R_MICROMIPS_GPREL16)
+ continue;
&&s at the beginning of lines.
+ /* Get the value of the symbol referred to by the reloc. */
+ if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
+ {
+ /* A local symbol. */
+ Elf_Internal_Sym *isym;
+ asection *sym_sec;
+
+ isym = isymbuf + ELF32_R_SYM (irel->r_info);
+ if (isym->st_shndx == SHN_UNDEF)
+ sym_sec = bfd_und_section_ptr;
+ else if (isym->st_shndx == SHN_ABS)
+ sym_sec = bfd_abs_section_ptr;
+ else if (isym->st_shndx == SHN_COMMON)
+ sym_sec = bfd_com_section_ptr;
+ else
+ sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
+ symval = (isym->st_value
+ + sym_sec->output_section->vma
+ + sym_sec->output_offset);
+ target_is_micromips_code_p = ELF_ST_IS_MICROMIPS (isym->st_other);
+ }
+ else
+ {
+ unsigned long indx;
+ struct elf_link_hash_entry *h;
+
+ /* An external symbol. */
+ indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
+ h = elf_sym_hashes (abfd)[indx];
+ BFD_ASSERT (h != NULL);
+
+ if (h->root.type != bfd_link_hash_defined
+ && h->root.type != bfd_link_hash_defweak)
+ /* This appears to be a reference to an undefined
+ symbol. Just ignore it -- it will be caught by the
+ regular reloc processing. */
+ continue;
+
+ symval = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+ }
Why not set target_is_micromips_code_p for locally-binding global
symbols too?
+ opcode = bfd_get_16 (abfd, contents + irel->r_offset ) << 16;
+ opcode |= (irel->r_offset + 2 < sec->size
+ ? bfd_get_16 (abfd, contents + irel->r_offset + 2) : 0);
Are there any relaxations we can actually do if irel->r_offset + 2
>= sec->size? I couldn't see any. If there aren't, continue instead.
+ /* R_MICROMIPS_HI16 / LUI relaxation to R_MICROMIPS_HI0_LO16 or
+ R_MICROMIPS_PC23_S2. The R_MICROMIPS_PC23_S2 condition is
+
+ (symval % 4 == 0 && IS_BITSIZE (pcrval, X, 25))
+
+ where the X adjustment compensate for R_MICROMIPS_HI16 and
+ R_MICROMIPS_LO16 being at most X bytes appart when the
+ distance to the target approaches 32 MB. */
Comment is slightly confusing: we don't relax the HI16 itself to a
H0_LO16 or PC32_S3. Rather we relax the LO16 (or, if you like,
the HI16/LO16 pair).
+ /* Assume is possible to delete the LUI instruction:
+ 4 bytes at irel->r_offset. */
s/Assume is/Assume it is/
+ /* Compact branch relaxation -- due to the multitude of macros
+ employed by the compiler/assembler, compact branches are not
+ aways generated. Obviously, this can/will be fixed elsewhere,
+ but there is no drawback in double checking it here. */
+ else if (ELF32_R_TYPE (irel->r_info) == (int) R_MICROMIPS_PC16_S1
+ && (fndopc = find_match (opcode, bz_insns_32)) != 0
+ && MATCH (bfd_get_16 (abfd, contents + irel->r_offset + 4),
+ nop_insn_16))
s/aways/always/. You should check the section size before reading
past the relocation. (I realise there ought to be a delay slot,
but we should be robust against brokenness.)
+ /* R_MICROMIPS_26_S1 -- JAL to JALS relaxation for microMIPS targets. */
+ else if (ELF32_R_TYPE (irel->r_info) == (int) R_MICROMIPS_26_S1
+ && target_is_micromips_code_p
+ && MATCH (opcode, jal_insn_32_bd32))
+ {
+ unsigned long n32opc;
+ bfd_boolean relaxed = FALSE;
+
+ n32opc =
+ bfd_get_16 (abfd, contents + irel->r_offset + 4 ) << 16;
+ n32opc |= irel->r_offset + 2 < sec->size?
+ bfd_get_16 (abfd, contents + irel->r_offset + 6): 0;
+
Here too you should check the size before reading n32opc. Second
condition looks bogus (did you mean +6?) although the same concerns
apply as for the "+ 2" above.
I'll try to review more soon.
Richard
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS and MCU ASE instruction set support
2010-05-18 18:19 [PATCH] MIPS: microMIPS and MCU ASE instruction set support Maciej W. Rozycki
2010-05-23 21:38 ` Richard Sandiford
2010-05-26 20:19 ` [PATCH] MIPS: microMIPS and MCU ASE instruction set support Richard Sandiford
@ 2010-05-27 21:39 ` Richard Sandiford
2 siblings, 0 replies; 41+ messages in thread
From: Richard Sandiford @ 2010-05-27 21:39 UTC (permalink / raw)
To: Maciej W. Rozycki
Cc: binutils, Chao-ying Fu, Ilie Garbacea, Joseph Myers,
Catherine Moore, Daniel Jacobowitz
Part 3 of 3.
the elf32-mips.c reloc questions in review 2 apply to elf64-mips.c
and elfn32-mips.c as well. Furthermore:
+static reloc_howto_type micromips_elf64_howto_table_rela[] =
+{
+ /* 16 bit relocation. */
+ HOWTO (R_MICROMIPS_16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ _bfd_mips_elf_lo16_reloc, /* special_function */
+ "R_MICROMIPS_16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
RELA relocations shouldn't be partial_inplace. Applies to the whole array.
Did you actually test this with n64, say with a gcc bootstrap? Same
comment goes for elfn32-mips.c.
Why only do the linker relaxation for elf32-mips.c (o32, o64 & EABI)?
Why not for n32 and n64 too?
+#define LA25_LUI_MICROMIPS_1(VAL) (0x41b9) /* lui t9,VAL */
+#define LA25_LUI_MICROMIPS_2(VAL) (VAL)
+#define LA25_J_MICROMIPS_1(VAL) (0xd400 | (((VAL) >> 17) & 0x3ff)) /* j VAL */
+#define LA25_J_MICROMIPS_2(VAL) (0xd4000000 | (((VAL) >> 1) & 0xffff))
+#define LA25_ADDIU_MICROMIPS_1(VAL) (0x3339) /* addiu t9,t9,VAL */
+#define LA25_ADDIU_MICROMIPS_2(VAL) (VAL)
LA25_J_MICROMIPS_2 is a 16-bit opcode, so the "0xd4000000 | ..."
thing is bogus. That said, why split these up? bfd_{get,put}_32
don't require aligned addresses.
+ value = s->size;
+ if (ELF_ST_IS_MICROMIPS (stub->h->root.other))
+ value |= 1;
+
/* Create a symbol for the stub. */
- mips_elf_create_stub_symbol (info, stub->h, ".pic.", s, s->size, 8);
+ mips_elf_create_stub_symbol (info, stub->h, ".pic.", s, value, 8);
Do this in mips_elf_create_stub_symbol rather than in each caller.
+ return r_type == R_MIPS_GOT16 || r_type == R_MIPS16_GOT16
+ || r_type == R_MICROMIPS_GOT16;
GNU indentation requires brackets here. Also, once it becomes too
long for one line, let's keep one item per line:
return (r_type == R_MIPS_GOT16
|| r_type == R_MIPS16_GOT16
|| r_type == R_MICROMIPS_GOT16);
Same for later functions.
- if (r_type == R_MIPS_TLS_GOTTPREL)
+ if (r_type == R_MIPS_TLS_GOTTPREL || r_type == R_MICROMIPS_TLS_GOTTPREL)
Hide these differences in analogues of the got16_reloc_p functions.
Same for all other relocs with MICROMIPS variants.
@@ -3187,8 +3244,12 @@ mips_elf_got_page (bfd *abfd, bfd *ibfd,
struct mips_got_entry *entry;
page = (value + 0x8000) & ~(bfd_vma) 0xffff;
- entry = mips_elf_create_local_got_entry (abfd, info, ibfd, page, 0,
- NULL, R_MIPS_GOT_PAGE);
+ if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS)
+ entry = mips_elf_create_local_got_entry (abfd, info, ibfd, page, 0,
+ NULL, R_MICROMIPS_GOT_PAGE);
+ else
+ entry = mips_elf_create_local_got_entry (abfd, info, ibfd, page, 0,
+ NULL, R_MIPS_GOT_PAGE);
if (!entry)
return MINUS_ONE;
Why is this necessary?
@@ -5127,12 +5200,26 @@ mips_elf_calculate_relocation (bfd *abfd
+ h->la25_stub->stub_section->output_offset
+ h->la25_stub->offset);
+ /* Make sure MIPS16 and microMIPS are not used together. */
+ if ((r_type == R_MIPS16_26 && target_is_micromips_code_p)
+ || (r_type == R_MICROMIPS_26_S1 && target_is_16_bit_code_p))
+ {
+ (*_bfd_error_handler)
+ (_("MIPS16 and microMIPS functions cannot call each other"));
+ return bfd_reloc_notsupported;
+ }
Should this be extended to check for branches too?
+ case R_MIPS_26:
+ /* Make sure the target of JALX is word-aligned.
+ Bit 0 must be 1 (MIPS16/microMIPS mode), and bit 1 must be 0. */
+ if (*cross_mode_jump_p == TRUE && (symbol & 3) != 1)
+ return bfd_reloc_outofrange;
== TRUE has been banned by act of parliament.
If we're checking alignment for R_MIPS_26 and R_MICROMIPS_26, we should
check it for R_MIPS16_26 too. Something like:
/* Make sure the target of JALX is word-aligned.
Bit 0 must be the correct ISA mode selector and bit 1 must be 0. */
if (*cross_mode_jump_p && (symbol & 3) != (r_type == R_MIPS_26))
return bfd_reloc_outofrange;
for both cases would be fine.
+ case R_MICROMIPS_26_S1:
+ /* Make sure the target of jalx is word-aligned. */
+ if (*cross_mode_jump_p == TRUE && (symbol & 3) != 0)
+ return bfd_reloc_outofrange;
+ if (local_p)
+ {
+ /* For jalx, the offset is shifted right by two bits. */
+ if (*cross_mode_jump_p == TRUE)
+ value = ((addend | ((p + 4) & 0xf0000000)) + symbol) >> 2;
+ else
+ value = ((addend | ((p + 4) & 0xf8000000)) + symbol) >> 1;
+ }
+ else
+ {
+ /* For jalx, the offset is shifted right by two bits. */
+ if (*cross_mode_jump_p == TRUE)
+ {
+ value = (_bfd_mips_elf_sign_extend (addend, 28) + symbol) >> 2;
+ if (h->root.root.type != bfd_link_hash_undefweak)
+ overflowed_p = (value >> 26) != ((p + 4) >> 28);
+ }
+ else
+ {
+ value = (_bfd_mips_elf_sign_extend (addend, 27) + symbol) >> 1;
+ if (h->root.root.type != bfd_link_hash_undefweak)
+ overflowed_p = (value >> 26) != ((p + 4) >> 27);
+ }
+ }
+ value &= howto->dst_mask;
+ break;
This is a strict extension of the R_MIPS_26 and R_MIPS16_26 behaviour,
so I'd prefer to see them integrated.
@@ -5372,6 +5516,9 @@ mips_elf_calculate_relocation (bfd *abfd
both reloc addends by 4. */
if (r_type == R_MIPS16_HI16)
value = mips_elf_high (addend + gp - p - 4);
+ else if (r_type == R_MICROMIPS_HI16)
+ /* The low bit of $t9 is set for microMIPS calls. */
+ value = mips_elf_high (addend + gp - p - 1);
else
value = mips_elf_high (addend + gp - p);
overflowed_p = mips_elf_overflow_p (value, 16);
This statement is also true for MIPS16, so in context, the comment
is a bit confusing on its own. How about:
/* The microMIPS .cpload sequence uses the same assembly
instructions as the traditional psABI version, but the
incoming $t9 has the low bit set. */
@@ -5486,8 +5647,38 @@ mips_elf_calculate_relocation (bfd *abfd
value &= howto->dst_mask;
break;
+ case R_MICROMIPS_PC7_S1:
+ value = symbol + _bfd_mips_elf_sign_extend (addend, 8) - p;
+ overflowed_p = mips_elf_overflow_p (value, 8);
+ value >>= howto->rightshift;
+ value &= howto->dst_mask;
+ break;
+
+ case R_MICROMIPS_PC10_S1:
+ value = symbol + _bfd_mips_elf_sign_extend (addend, 11) - p;
+ overflowed_p = mips_elf_overflow_p (value, 11);
+ value >>= howto->rightshift;
+ value &= howto->dst_mask;
+ break;
+
+ case R_MICROMIPS_PC16_S1:
+ value = symbol + _bfd_mips_elf_sign_extend (addend, 17) - p;
+ overflowed_p = mips_elf_overflow_p (value, 17);
+ value >>= howto->rightshift;
+ value &= howto->dst_mask;
+ break;
+
+ case R_MICROMIPS_PC23_S2:
+ value = symbol + _bfd_mips_elf_sign_extend (addend, 25) - (p & 0xfffffffc);
+ overflowed_p = mips_elf_overflow_p (value, 25);
+ value >>= howto->rightshift;
+ value &= howto->dst_mask;
+ break;
I realise you probably based this on R_MIPS_PC16 and R_MIPS_GNU_REL16_S2,
but even so, you're careful to check for underflow elsewhere but ignore
it here. Use of 0xfffffffc isn't portable for 64-bit addresses;
use "-4" or "~(bfd_vma) 3" instead.
@@ -6150,13 +6355,18 @@ _bfd_mips_elf_symbol_processing (bfd *ab
break;
}
- /* If this is an odd-valued function symbol, assume it's a MIPS16 one. */
+ /* If this is an odd-valued function symbol, assume it's a MIPS16
+ or microMIPS one. */
if (ELF_ST_TYPE (elfsym->internal_elf_sym.st_info) == STT_FUNC
&& (asym->value & 1) != 0)
{
asym->value--;
- elfsym->internal_elf_sym.st_other
- = ELF_ST_SET_MIPS16 (elfsym->internal_elf_sym.st_other);
+ if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS)
+ elfsym->internal_elf_sym.st_other
+ = ELF_ST_SET_MICROMIPS (elfsym->internal_elf_sym.st_other);
+ else
+ elfsym->internal_elf_sym.st_other
+ = ELF_ST_SET_MIPS16 (elfsym->internal_elf_sym.st_other);
}
}
\f
So a file can't mix MIPS16 and microMIPS code? We should probably
detect that explicitly. I'd like a clear statement of what the
interoperability restrictions are.
This goes back to the question of when EF_MIPS_ARCH_ASE_MICROMIPS
should be set (see previous reviews).
@@ -6865,7 +7075,8 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd
/* If this is a mips16 text symbol, add 1 to the value to make it
odd. This will cause something like .word SYM to come up with
the right value when it is loaded into the PC. */
- if (ELF_ST_IS_MIPS16 (sym->st_other))
+ if (ELF_ST_IS_MIPS16 (sym->st_other)
+ || ELF_ST_IS_MICROMIPS (sym->st_other))
++*valp;
return TRUE;
As with GAS, I'd like an ODD_SYMBOL_P or some-such.
@@ -7166,6 +7378,8 @@ mips_elf_add_lo16_rel_addend (bfd *abfd,
r_type = ELF_R_TYPE (abfd, rel->r_info);
if (mips16_reloc_p (r_type))
lo16_type = R_MIPS16_LO16;
+ else if (micromips_reloc_shuffle_p (r_type))
+ lo16_type = R_MICROMIPS_LO16;
else
lo16_type = R_MIPS_LO16;
Conceptually, this ought to be plain micromips_reloc_p. Whether we need
to shuffle or not isn't an issue here, even though I realise the shuffle
condition produces the right result.
@@ -9215,6 +9479,12 @@ _bfd_mips_elf_relocate_section (bfd *out
case bfd_reloc_ok:
break;
+ case bfd_reloc_outofrange:
+ msg = _("internal error: jalx jumps to not word-aligned address");
+ info->callbacks->warning
+ (info, msg, name, input_bfd, input_section, rel->r_offset);
+ return FALSE;
+
default:
abort ();
break;
Why's that an internal error? Surely it could be triggered by
badly-formed input, rather than just as a result of internal
confusion?
The error is more specific than the error code, so you should also add:
BFD_ASSERT (jal_reloc_p (howto->type));
@@ -976,7 +976,7 @@ bfd_install_relocation (bfd *abfd,
asection *reloc_target_output_section;
asymbol *symbol;
bfd_byte *data;
-
+
symbol = *(reloc_entry->sym_ptr_ptr);
if (bfd_is_abs_section (symbol->section))
{
Bogus change.
@@ -1652,6 +1652,8 @@ ENUMX
ENUMX
BFD_RELOC_16
ENUMX
+ BFD_RELOC_MICROMIPS_16
+ENUMX
BFD_RELOC_14
ENUMX
BFD_RELOC_8
Here and elsewhere, keep the MIPS-specific stuff separate from the
generic relocs. See the MIPS16 relocs for examples.
I'll take your word for it that micromips-opc.c is correct. ;-)
+ else if ((insn & 0x1c00) != 0x0400
+ && (insn & 0x1c00) != 0x0800
+ && (insn & 0x1c00) != 0x0c00)
+ {
+ /* This is a 32-bit microMIPS instruction. */
+ higher = insn;
+
+ status = (*info->read_memory_func) (memaddr + 2, buffer, 2, info);
+ if (status != 0)
+ {
+ (*info->fprintf_func) (info->stream, "micromips 0x%x",
+ (unsigned int) higher);
+ (*info->memory_error_func) (status, memaddr + 2, info);
+ return -1;
+ }
Why print "micromips " here but not in the 48-byte case? Also,
s/0x%02x/0x%x/ would be better IMO.
Watch your formatting in this function. There are lots of cases of
things like:
(*info->fprintf_func) (info->stream, "%s",
mips_gpr_names[lastregno]);
which isn't right. Arguments must be aligned to the column after
the "(". Don't be afraid to split lines into several statements
if it makes things look more natural.
The gas testsuite changes look very nice, thanks.
Richard
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS and MCU ASE instruction set support
2010-05-23 21:38 ` Richard Sandiford
2010-05-24 22:25 ` Fu, Chao-Ying
@ 2010-06-01 14:21 ` Maciej W. Rozycki
2010-06-01 14:39 ` Catherine Moore
` (3 more replies)
2010-07-26 10:56 ` [PATCH] MIPS: microMIPS ASE support Maciej W. Rozycki
2 siblings, 4 replies; 41+ messages in thread
From: Maciej W. Rozycki @ 2010-06-01 14:21 UTC (permalink / raw)
To: Richard Sandiford
Cc: binutils, Chao-ying Fu, Catherine Moore, Joseph S. Myers,
Daniel Jacobowitz
[-- Attachment #1: Type: TEXT/PLAIN, Size: 51813 bytes --]
Hi Richard,
> Big patch, so this review is only for the gas and ld/testsuite bits.
Thanks for the review, especially as I know it must have taken a lot of
effort. I hope we'll be able to sort out all issues gradually.
I'm placing notes throughout and I'll be asking people for explanations
where applicable. Chao-ying, would you please look into the few pieces of
code below I am a bit uncertain about? Catherine, there's one question
for you at the end as well.
> Generally looks good. It would have been better to submit the
> ACE, m14kc and microMIPS support as three separate changes though.
> Please can you do that for the follow-up?
I have done it now; the next version will comprise microMIPS ASE changes
only (the MCU ASE adds to both the MIPS ISA and the microMIPS ASE, so it
should be applied on top of the microMIPS change).
Stricly speaking some changes, while related, can be split off too (e.g.
some MIPS16 or testsuite changes), so I'll look into separating them too
-- perhaps that'll make the thing rolling sooner.
> From a usability perspective, it's a shame that:
>
> .set micromips
> .ent foo
> foo:
> b 1f
> nop
> .end foo
> .ent bar
> bar:
> 1: nop
> .end bar
>
> disassembles as:
>
> 00000000 <foo>:
> 0: cfff b 0 <foo>
> 0: R_MICROMIPS_PC10_S1 .L11
> 2: 0c00 nop
> 4: 0c00 nop
>
> 00000006 <bar>:
> 6: 0c00 nop
>
> leaving the poor user with no idea what .L11 is.
Indeed. This is a general limitation of `objdump' it would seem. This
is no different to what you get with:
$ cat b.s
.globl baz
.ent foo
foo:
b baz
nop
.end foo
.ent bar
baz:
bar:
1: nop
.end bar
$ mips-sde-elf-objdump -dr b.o
b.o: file format elf32-tradbigmips
Disassembly of section .text:
00000000 <foo>:
0: 1000ffff b 0 <foo>
0: R_MIPS_PC16 baz
4: 00000000 nop
8: 00000000 nop
0000000c <bar>:
c: 00000000 nop
I'd just recommend peeking at the symbol table (back to the first
program):
$ mips-sde-elf-objdump -t b.o
b.o: file format elf32-tradbigmips
SYMBOL TABLE:
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l d .reginfo 00000000 .reginfo
00000000 l d .pdr 00000000 .pdr
00000000 l F .text 00000006 0x80 foo
00000006 l F .text 00000002 0x80 bar
00000006 l .text 00000000 0x80 .L1\x021
Any other ideas, anyone?
> The following:
>
> .set micromips
> .ent foo
> foo:
> ld $10,0x1000($11)
> .end foo
>
> generates an assertion failure:
>
> Assertion failure in micromips_macro_build at gas/config/tc-mips.c line 19466.
> Please report this bug.
>
> on mipsisa64-elf with "-mips1 -mabi=32".
I can't reproduce it, sorry:
$ cat ld.s
.set micromips
.ent foo
foo:
ld $10,0x1000($11)
.end foo
$ mipsisa64-elf-as -mips1 -mabi=32 -o ld.o ld.s
$ mipsisa64-elf-objdump -d ld.o
ld.o: file format elf32-bigmips
Disassembly of section .text:
00000000 <foo>:
0: fd4b 1000 lw t2,4096(t3)
4: fd6b 1004 lw t3,4100(t3)
The assertion you're referring to is this piece of code from
micromips_macro_build():
case 'i':
case 'j':
case 'o':
macro_read_relocs (&args, r);
gas_assert (*r == BFD_RELOC_MICROMIPS_GPREL16
|| *r == BFD_RELOC_MICROMIPS_LITERAL
|| *r == BFD_RELOC_MICROMIPS_HIGHER
|| *r == BFD_RELOC_MICROMIPS_HI16_S
|| *r == BFD_RELOC_MICROMIPS_LO16
|| *r == BFD_RELOC_MICROMIPS_GOT16
|| *r == BFD_RELOC_MICROMIPS_CALL16
|| *r == BFD_RELOC_MICROMIPS_GOT_DISP
|| *r == BFD_RELOC_MICROMIPS_GOT_PAGE
|| *r == BFD_RELOC_MICROMIPS_GOT_OFST
|| *r == BFD_RELOC_MICROMIPS_GOT_LO16
|| *r == BFD_RELOC_MICROMIPS_CALL_LO16);
continue;
(indentation is wrong after s/assert/gas_assert/ it would seem, I have
fixed it up; this has to be done in upstream HEAD in a couple of places
too).
Can you debug it and see what the relocation type is that's causing it?
I wonder if that might be related to the varargs issue you referring to
below and depend on the host architecture, hmm...
> > gas/
> > 2010-05-18 Chao-ying Fu <fu@mips.com>
> > Maciej W. Rozycki <macro@codesourcery.com>
> > Daniel Jacobowitz <dan@codesourcery.com>
> >
> > * config/tc-mips.h (mips_segment_info): Add one bit for
> > microMIPS.
> > * config/tc-mips.c
>
> How about having something like:
>
> #define OOD_TEXT_LABELS (mips_opts.mips16 || mips_opts.micromips)
>
> ?
It sounds reasonable to me, except that condition is used in some other
contexts as well. I have made it HAVE_CODE_COMPRESSION thus and took the
opportunity to optimise code around mips16_micromips_mark_labels() too.
Finally I have renamed the function to mips_compressed_mark_labels() for
as the other sounds too complicated to me.
> > (A_BFD_RELOC_HI16_S, A_BFD_RELOC_HI16, A_BFD_RELOC_LO16): New
> > relocation wrapper macros.
> > (A_BFD_RELOC_GPREL16): Likewise.
> > (A_BFD_RELOC_MIPS_GOT16, A_BFD_RELOC_MIPS_GOT_HI16): Likewise.
> > (A_BFD_RELOC_MIPS_GOT_LO16, A_BFD_RELOC_MIPS_HIGHEST): Likewise.
> > (A_BFD_RELOC_MIPS_HIGHER, A_BFD_RELOC_MIPS_GOT_DISP): Likewise.
> > (A_BFD_RELOC_MIPS_GOT_PAGE, A_BFD_RELOC_MIPS_GOT_OFST): Likewise.
> > (A_BFD_RELOC_MIPS_SUB, A_BFD_RELOC_MIPS_JALR): Likewise.
>
> Did you consider doing the translation from non-microMIPS to
> microMIPS in the macro_* functions, rather than in their callers?
> I fear it'll be too easy to accidentally forget to use A_BFD_* in future.
Agreed, I didn't like the new macros from the very beginning. Chao-ying
-- any thoughts?
> > (mips_macro_warning): Add delay_slot_16bit_p, delay_slot_32bit_p,
> > and num_insns.
> > (micromips_16, micromips_32): New variables.
> > (is_micromips_16bit_p, is_micromips_32bit_p): New functions.
> > (insn_length): Return the length of microMIPS instructions.
> > (mips_record_mips16_mode): Rename to...
> > (mips_record_mips16_micromips_mode): ... this. Handle microMIPS.
> > (install_insn): Handle microMIPS.
> > (is_opcode_valid): Likewise.
> > (md_begin): Likewise.
>
> + if (micromips_nop16_insn.insn_mo == NULL
> + && strcmp (name, "nop") == 0)
> + {
> + create_insn (µmips_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 (µmips_nop32_insn, micromips_opcodes + i);
> + micromips_nop32_insn.fixed_p = 1;
> + }
>
> You seem to rely on the 16-bit nop being first. Wouldn't it be more
> robust to call is_micromips_16bit_p and is_micromips_32bit_p?
Agreed. I rewrote this piece entirely.
> > (MICROMIPS_TARGET, MICROMIPS_TARGET_LABEL): New macros.
> > (micromips_add_number_label): New function.
>
> +/* For microMIPS macros, we need to generate a local number label
> + as the target of branches. */
> +#define MICROMIPS_TARGET "2147483647f"
> +#define MICROMIPS_TARGET_LABEL 2147483647
> +
> +static void
> +micromips_add_number_label (void)
> +{
> + symbolS *s;
> + fb_label_instance_inc (MICROMIPS_TARGET_LABEL);
> + s = colon (fb_label_name (MICROMIPS_TARGET_LABEL, 0));
> + S_SET_OTHER (s, ELF_ST_SET_MICROMIPS (S_GET_OTHER (s)));
> +}
> +
>
> Ugh, this is a bit hackish. There's nothing stopping a user using
> 2147483647f themselves.
A local symbol with some magic characters would be better indeed. I'll
see if any existing approach could be reused.
> > (append_insn): Handle microMIPS.
>
> + if (mips_opts.micromips)
> + {
> + if ((prev_pinfo2 & INSN2_BRANCH_DELAY_16BIT)
> + && !is_micromips_16bit_p (ip->insn_mo))
> + as_warn (_("instruction with wrong size in a branch delay slot that"
> + " requires a 16-bit instruction"));
> + if ((prev_pinfo2 & INSN2_BRANCH_DELAY_32BIT)
> + && !is_micromips_32bit_p (ip->insn_mo))
> + as_warn (_("instruction with wrong size in a branch delay slot that"
> + " requires a 32-bit instruction"));
> + }
> +
>
> Although not enforced as often as it should be, GAS convention is for
> errors to start with a capital letter.
I'll be fixing these up as I come across them. If to be effective, then
upstream HEAD should be fixed up or otherwise people have no way not to
get confused. I didn't know of this rule for one. That shouldn't be a
lot effort, should it?
Some have to stay for now actually, because .l testsuite patterns are
commonly shared between standard MIPS and microMIPS tests, and should be
fixed separately.
> + if (pinfo & INSN_COP)
> + {
> + /* We don't keep enough information to sort these cases out.
> + The itbl support does keep this information however, although
> + we currently don't support itbl fprmats as part of the cop
> + instruction. May want to add this support in the future. */
> + }
>
> Assert?
Well, that's no different to the standard MIPS variant.
> + /* For microMIPS, disable reordering. */
> + || (mips_opts.micromips)
>
> Redundant (...)
Fixed.
> - if (mips_relax.sequence)
> - mips_relax.sizes[mips_relax.sequence - 1] += 4;
> + /* MicroMIPS nop is 2 bytes. */
> + if (mips_relax.sequence)
> + mips_relax.sizes[mips_relax.sequence - 1] +=
> + mips_opts.micromips ? micromips_nop_size : 4;
>
> Confusing comment: the microMIPS nop may be 2 or 4 bytes.
> Better to say nothing IMO.
Fixed.
> > (start_noreorder, end_noreorder): Likewise.
>
> + frag_grow ((mips_opts.mips16 | mips_opts.micromips) ? nops * 2
> + : nops * 4);
>
> How about a NOP_INSN_SIZE macro? (Or similar.)
Added. And found the third place where needed while making the
replacement.
> > (macro_start, macro_warning, macro_end): Likewise.
>
> + else if ((subtype & RELAX_DELAY_SLOT_SIZE_ERROR_FIRST)
> + || (subtype & RELAX_DELAY_SLOT_SIZE_ERROR_SECOND))
> + return _("Macro instruction of the wrong size in a branch delay slot"
> + " that requires a 16-bit or 32-bit instruction");
>
> Did you consider adding a flag to distinguish the 32-bit and 16-bit cases?
> It'd be nice to be consistent with the non-relaxed error if possible.
Chao-ying? I've had a look actually and flag may not be necessary to get
the functionality. I'm fixing this up elsewhere already.
> + /* If either one implementation contains one instruction, we need to check
> + the delay slot size requirement. */
>
> "If either implementation"
Fixed.
> + /* If either one implementation contains one instruction, we need to check
> + the delay slot size requirement. */
> + if (mips_macro_warning.num_insns[0] == 1
> + || mips_macro_warning.num_insns[1] == 1)
> + {
> + if (mips_macro_warning.num_insns[0] == mips_macro_warning.num_insns[1]
> + && mips_macro_warning.sizes[0] == mips_macro_warning.sizes[1])
> + {
> + /* Either the macro has a single implementation or both
> + implementations are 1 instruction with the same size.
> + Emit the warning now. */
> + if ((mips_macro_warning.delay_slot_16bit_p
> + && mips_macro_warning.sizes[0] != 2)
> + || (mips_macro_warning.delay_slot_32bit_p
> + && mips_macro_warning.sizes[0] != 4))
> + {
> + const char *msg;
> + msg = macro_warning (RELAX_DELAY_SLOT_SIZE_ERROR_FIRST);
> + if (msg != 0)
> + as_warn (msg);
> + }
> + }
> + else
> + {
> + relax_substateT subtype;
> +
> + /* Set up the relaxation warning flags. */
> + subtype = 0;
> + if (mips_macro_warning.delay_slot_16bit_p)
> + {
> + if (mips_macro_warning.num_insns[0] != 1
> + || mips_macro_warning.sizes[0] != 2)
> + subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
> + if (mips_macro_warning.num_insns[1] != 1
> + || mips_macro_warning.sizes[1] != 2)
> + subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
> + }
> + if (mips_macro_warning.delay_slot_32bit_p)
> + {
> + if (mips_macro_warning.num_insns[0] != 1
> + || mips_macro_warning.sizes[0] != 4)
> + subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
> + if (mips_macro_warning.num_insns[1] != 1
> + || mips_macro_warning.sizes[1] != 4)
> + subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
> + }
> +
> + /* One implementation might need a warning but the other
> + definitely doesn't. */
> + mips_macro_warning.first_frag->fr_subtype |= subtype;
> + }
> + }
>
> Why not work out the subtype, then check whether both ERROR_FIRST and
> ERROR_SECOND are set?
Chao-ying?
> + if (mips_macro_warning.delay_slot_p)
> + {
> + if (mips_macro_warning.num_insns[0] > 1)
> + subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
> + if (mips_macro_warning.num_insns[1] > 1)
> + subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
> + }
>
> I don't get why this hunk is needed. I thought ERROR_FIRST and ERROR_SECOND
> controlled cases where a macro has a single-insn expansion that is the
> wrong size, which ought to be handled by the block above. If the code
> really is needed, you should add a comment explaining why.
Chao-ying?
> > (macro_build): Likewise.
>
> + if (mips_opts.micromips)
> + {
> + if (strcmp (name, "lui") == 0)
> + micromips_macro_build (ep, name, "s,u", args);
> + else if (strcmp (fmt, "d,w,<") == 0)
> + micromips_macro_build (ep, name, "t,r,<", args);
> + else
> + micromips_macro_build (ep, name, fmt, args);
> + va_end (args);
> + return;
> + }
>
> A bit of commentary might help explain the letter switch here.
Chao-ying?
> > (macro_build_jalr): Likewise.
>
> + if (mips_opts.micromips)
> + {
> + if (HAVE_NEWABI)
> + macro_build (NULL, "jalr", "t,s", RA, PIC_CALL_REG);
> + else
> + macro_build (NULL, "jalr", "mj", PIC_CALL_REG);
> + }
> + else
> + macro_build (NULL, "jalr", "d,s", RA, PIC_CALL_REG);
>
> Why HAVE_NEWABI? Do you want a 32-bit insn for R_MIPS_JALR?
Chao-ying?
> If so, you should check MIPS_JALR_HINT_P (ep) instead.
I may have missed that while updating the change for the recent JALR hint
support, let me see...
> - macro_build (&tmp, "ori", "t,r,i", reg, 0, BFD_RELOC_LO16);
> + macro_build (&tmp, "ori", "t,r,i", reg, 0, A_BFD_RELOC_LO16);
> macro_build (NULL, (shift >= 32) ? "dsll32" : "dsll", "d,w,<",
> - reg, reg, (shift >= 32) ? shift - 32 : shift);
> + reg, reg, (shift >= 32) ? shift - 32 : shift);
>
> Last change looks bogus.
Fixed.
> - gas_assert (fixP->fx_size == 4
> + gas_assert (fixP->fx_size == 2
> + || fixP->fx_size == 4
> || fixP->fx_r_type == BFD_RELOC_16
> + || fixP->fx_r_type == BFD_RELOC_MICROMIPS_16
> || fixP->fx_r_type == BFD_RELOC_64
> || fixP->fx_r_type == BFD_RELOC_CTOR
> || fixP->fx_r_type == BFD_RELOC_MIPS_SUB
> + || fixP->fx_r_type == BFD_RELOC_MICROMIPS_SUB
> || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
> || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
> || fixP->fx_r_type == BFD_RELOC_MIPS_TLS_DTPREL64);
>
> +
> buf = (bfd_byte *) (fixP->fx_frag->fr_literal + fixP->fx_where);
>
> Last change is bogus.
Fixed.
> + case BFD_RELOC_MICROMIPS_7_PCREL_S1:
> + case BFD_RELOC_MICROMIPS_10_PCREL_S1:
> + case BFD_RELOC_MICROMIPS_16_PCREL_S1:
> + /* We adjust the offset back to even. */
> + if ((*valP & 0x1) != 0)
> + --(*valP);
> +
> + if (! fixP->fx_done)
> + break;
> +
> + /* Should never visit here, because we keep the relocation. */
> + abort ();
> + break;
>
> I suppose this silently ignores branches to non-microMIPS code,
> but there again, so does the MIPS16 equivalent...
Neither can work, so some diagnostics would be useful.
> > (mips_relax_frag): Handle microMIPS.
>
> + gas_assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2
> + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
> + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1
> + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1);
> +
> + /* For 7/10 PCREL_S1, we just need to use fixp->fx_addnumber. */
> + if (fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
> + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1)
> + reloc->addend = fixp->fx_addnumber;
> + else
> + /* At this point, fx_addnumber is "symbol offset - pcrel address".
> + Relocations want only the symbol offset. */
> + reloc->addend = fixp->fx_addnumber + reloc->address;
>
> A better comment is needed. _Why_ do you just need fx_addnumber?
Thanks, Chao-ying and Richard, for the feedback on this -- I'll see if I
can make something up from it.
> > (md_convert_frag): Likewise.
>
> - /* Possibly emit a warning if we've chosen the longer option. */
> - if (((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
> - == ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))
> + if (!(fragp->fr_subtype & RELAX_USE_SECOND))
> + {
> + /* Check if the size in branch delay slot is ok. */
> + if (fragp->fr_subtype & RELAX_DELAY_SLOT_SIZE_ERROR_FIRST)
> + {
> + const char *msg = macro_warning (fragp->fr_subtype);
> + if (msg != 0)
> + as_warn_where (fragp->fr_file, fragp->fr_line, msg);
> + }
> + }
> + else
> {
> - const char *msg = macro_warning (fragp->fr_subtype);
> - if (msg != 0)
> - as_warn_where (fragp->fr_file, fragp->fr_line, "%s", msg);
> + /* Check if the size in branch delay slot is ok.
> + Possibly emit a warning if we've chosen the longer option. */
> + if ((fragp->fr_subtype & RELAX_DELAY_SLOT_SIZE_ERROR_SECOND)
> + || (fragp->fr_subtype & RELAX_SECOND_LONGER))
> + {
> + const char *msg = macro_warning (fragp->fr_subtype);
> + if (msg != 0)
> + as_warn_where (fragp->fr_file, fragp->fr_line, msg);
> + }
> }
>
> This doesn't accurately preserve the previous:
>
> if (((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
> == ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))
>
> behaviour.
Chao-ying?
> > (mips_handle_align): Likewise.
>
> /* If we're not inserting a whole number of instructions,
> - pad the end of the fixed part of the frag with zeros. */
> - memset (p, 0, excess);
> + pad the end of the fixed part of the frag with zeros.
> + But try to fit a short microMIPS nop too if applicable. */
> + if (excess < 2 || *p != 2)
> + memset (p, 0, excess);
> + else
> + {
> + memset (p, 0, excess - 2);
> + md_number_to_chars (p + excess - 2,
> + micromips_nop16_insn.insn_opcode, 2);
> + }
>
> Not how it'd be written from scratch; the comment makes microMIPS sound
> like an afterthought. Please handle the microMIPS case first and make
> the comment treat it as a first-class citizen.
It was an afterthought indeed. :) I noticed this piece of code was
horrible just before submission while resolving a conflict with the recent
Loongson 2F erratum workaround. Now the result assembled is better, but I
think you're right this is not my best artwork. ;)
Calling memset() for a variable count (i.e. one that cannot be inlined)
that is at most three bytes seems an overkill to me; I have rewritten it
now with a switch() statement.
> > (micromips_ip): New function.
>
> + /* Try to search "16" or "32" in the str. */
> + if ((t = strstr (str, "16")) != NULL && t < save_s)
> + {
> + /* Make sure "16" is before the first '.' if '.' exists. */
> + if ((s = strchr (str, '.')) != NULL && (t + 2 != s))
> + {
> + insn_error = "unrecognized opcode";
> + return;
> + }
> +
> + /* Make sure "16" is at the end of insn name, if no '.'. */
> + if ((s = strchr (str, '.')) == NULL
> + && (!ISSPACE (*(t + 2)) && *(t + 2) != '\0'))
> + {
> + insn_error = "unrecognized opcode";
> + return;
> + }
> +
> + micromips_16 = TRUE;
> + for (s = t + 2; *s != '\0'; ++s)
> + *(s - 2) = *s;
> + *(s - 2) = '\0';
> +
> + for (s = t; *s != '\0' && !ISSPACE (*s); ++s)
> + continue;
> +
> + if (ISSPACE (*s))
> + {
> + save_c = *s;
> + *s++ = '\0';
> + }
> +
> + if ((insn = (struct mips_opcode *) hash_find (micromips_op_hash, str))
> + == NULL)
> + {
> + int i;
> + int length;
> + micromips_16 = FALSE;
> +
> + /* Restore the character we overwrite above (if any). */
> + if (save_c)
> + *(--s) = save_c;
> +
> + length = strlen (str);
> + for (i = length - 1; &str[i] >= t; i--)
> + {
> + str[i + 2] = str[i];
> + if (t == &str[i])
> + {
> + str[i + 1] = '6';
> + str[i] = '1';
> + str[length + 2] = '\0';
> + break;
> + }
> + }
> +
> + insn_error = "unrecognized 16-bit version of microMIPS opcode";
> + return;
> + }
> + }
> + else if ((t = strstr (str, "32")) != NULL && t < save_s)
> + {
> + /* For some instruction names, we already have 32, so we need
> + to seek the second 32 to process. Ex: bposge3232, dsra3232. */
> + char *new_t;
> + if ((new_t = strstr (t + 2, "32")) != NULL && new_t < save_s)
> + t = new_t;
> +
> + /* Make sure "32" is before the first '.' if '.' exists. */
> + if ((s = strchr (str, '.')) != NULL && (t + 2 != s))
> + {
> + insn_error = "unrecognized opcode";
> + return;
> + }
> +
> + /* Make sure "32" is at the end of the name, if no '.'. */
> + if ((s = strchr (str, '.')) == NULL
> + && (!ISSPACE (*(t + 2)) && *(t + 2) != '\0'))
> + {
> + insn_error = "unrecognized opcode";
> + return;
> + }
> +
> + micromips_32 = TRUE;
> + for (s = t + 2; *s != '\0'; ++s)
> + *(s - 2) = *s;
> + *(s - 2) = '\0';
> +
> + for (s = t; *s != '\0' && !ISSPACE (*s); ++s)
> + continue;
> +
> + if (ISSPACE (*s))
> + {
> + save_c = *s;
> + *s++ = '\0';
> + }
> +
> + if ((insn = (struct mips_opcode *) hash_find (micromips_op_hash, str))
> + == NULL)
> + {
> + int i;
> + int length;
> + micromips_32 = FALSE;
> +
> + /* Restore the character we overwrite above (if any). */
> + if (save_c)
> + *(--s) = save_c;
> +
> + length = strlen (str);
> + for (i = length - 1; &str[i] >= t; i--)
> + {
> + str[i + 2] = str[i];
> + if (t == &str[i])
> + {
> + str[i + 1] = '2';
> + str[i] = '3';
> + str[length + 2] = '\0';
> + break;
> + }
> + }
> +
> + insn_error = "unrecognized 32-bit version of microMIPS opcode";
> + return;
> + }
>
> Far too much cut-&-paste between the "16" and "32" cases. Also:
>
> + if ((t = strstr (str, "16")) != NULL && t < save_s)
>
> t < save_s must surely be true, since save_s is the null terminator.
>
> + /* Make sure "16" is before the first '.' if '.' exists. */
> + if ((s = strchr (str, '.')) != NULL && (t + 2 != s))
> + {
> + insn_error = "unrecognized opcode";
> + return;
> + }
> +
> + /* Make sure "16" is at the end of insn name, if no '.'. */
> + if ((s = strchr (str, '.')) == NULL
> + && (!ISSPACE (*(t + 2)) && *(t + 2) != '\0'))
> + {
> + insn_error = "unrecognized opcode";
> + return;
> + }
>
> Don't call strchr (str, '.') twice like that. Better would be:
>
> s = strchr (str, '.');
>
> followed by the two checks. Isn't the ISSPACE check redundant though,
> given that you've terminated the string at the first space? I would
> have thought:
>
> if (t + 2 != (s ? s : save_s))
>
> would be enough. Errors should start with a capital letter. Missing
> internationalisation.
Chao-ying?
> You could use alloca to create an opcode without the "16" or "32",
> which would make the error-reporting code simpler. It's best not
> to change the user's source line if we can help it.
Agreed.
> + if (!insn_error)
> + {
> + static char buf[100];
> + sprintf (buf,
> + _("opcode not supported on this processor: %s (%s)"),
> + mips_cpu_info_from_arch (mips_opts.arch)->name,
> + mips_cpu_info_from_isa (mips_opts.isa)->name);
> + insn_error = buf;
> + }
> + if (save_c)
> + *(--s) = save_c;
> +
> + if (micromips_16 || micromips_32)
> + {
> + int i;
> + int length;
> +
> + length = strlen (str);
> + for (i = length - 1; i >= 0; i--)
> + {
> + str[i + 2] = str[i];
> + if (t == &str[i])
> + break;
> + }
> + if (micromips_16)
> + {
> + insn_error =
> + "unrecognized 16-bit version of microMIPS opcode";
> + str[i + 1] = '6';
> + str[i] = '1';
> + }
> + else
> + {
> + insn_error =
> + "unrecognized 32-bit version of microMIPS opcode";
> + str[i + 1] = '2';
> + str[i] = '3';
> + }
> + str[length + 2] = '\0';
> + }
> + return;
>
> Why override the insn_error unconditionally like this? E.g.:
>
> jar16 $30,$26
>
> Error: unrecognized 16-bit version of microMIPS opcode `jar16 $30,$26'
>
> implies there's a 32-bit opcode. I'd also have thought that the
> "opcode not supported on this processor" would triumph if it applies.
The error you've seen comes from the previous hunk above rather than this
one which I think is unnecessary code duplication. It's all rather
over-complicated and I'm working on getting it polished. I've fixed this
piece of code:
.set micromips
.set noreorder
bltzall $2, bar
addiusp 256
producing this nonsense:
bltzall.s: Assembler messages:
bltzall.s:4: Error: opcode not supported on this processor: mips1 (mips1) `addiusp 256'
too. Also the original loop seems ill-formed to me, with most of code
intended to be executed at most once, after the loop's terminating
condition triggered -- i.e. that shouldn't be in the loop in the first
place.
> +do_lsb:
>
> Not properly indented. A few other instances.
Like the respective originals in mips_ip(). I have fixed up the new
labels, but upstream HEAD code should be adjusted the same way.
> + }
> + }
> + /* Now that we have assembled one operand, we use the args string
> + * to figure out where it goes in the instruction. */
> + switch (c)
> + {
>
> Bogus indentation.
Fixed.
> > (micromips_macro_build): Likewise.
> > (micromips_macro): Likewise.
>
> I'll look at micromips_ip and these two in more detail later.
Me too. ;)
> > * ld-mips-elf/jalx-2-main.s: New.
> > * ld-mips-elf/jalx-2.dd: New.
> > * ld-mips-elf/jalx-2-ex.s: New.
> > * ld-mips-elf/jalx-2-printf.s: New.
> > * ld-mips-elf/mips-elf.exp: Run new test.
>
> Please make the .dd output less susceptible to things like the number
> of sections, size of program headers, etc. One way is to use a linker
> script to place each section at a nice round address. Another is to
> ".*" out the addresses and instruction encodings and just reply on
> the symbolic part of the disassembly. I think the former's better
> here. There are quite a few existing examples.
Catherine, I reckon you were working on these?
I'll look into whatever's left yet. Here's the current version for a
reference, in case you or anyone else wanted to comment on what I have
modified so far (no obligation, of course!).
Maciej
bfd/
2010-06-01 Chao-ying Fu <fu@mips.com>
Ilie Garbacea <ilie@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
Joseph Myers <joseph@codesourcery.com>
Catherine Moore <clm@codesourcery.com>
* archures.c (bfd_mach_mips_micromips): New macro.
* cpu-mips.c (I_micromips): New enum value.
(arch_info_struct): Add bfd_mach_mips_micromips.
* elf32-mips.c (elf_micromips_howto_table_rel): New variable.
(_bfd_mips_elf32_gprel16_reloc): Handle microMIPS.
(mips_elf_gprel32_reloc): Update comment.
(micromips_reloc_map): New variable.
(bfd_elf32_bfd_reloc_type_lookup): Handle microMIPS.
(mips_elf32_rtype_to_howto): Likewise.
(mips_info_to_howto_rel): Likewise.
(elf32_mips_relax_delete_bytes): New function.
(opcode_descriptor): New structure.
(b_insns_32, b_insn_16): New variables.
(BZ32_REG, BZ32_REG_FIELD): New macros.
(bz_insns_32, bzc_insns_32, bz_insns_16): New variables.
(BZ16_VALID_REG, BZ16_REG_FIELD): New macros.
(jal_insn_32_bd16, jal_insn_32_bd32): New variables.
(jalr_insn_32_bd16, jalr_insn_32_bd32): Likewise.
(ds_insns_32_bd16, ds_insns_32_bd32): Likewise.
(jalr_insn_16_bd16, jalr_insn_16_bd32): Likewise.
(ds_insns_16_bd16): Likewise.
(lui_insn, addiu_insn, addiupc_insn): Likewise.
(ADDIU_REG, ADDIUPC_VALID_REG, ADDIUPC_REG_FIELD): New macros.
(lwgp_insn_32, lwgp_insn_16): New functions.
(LWGP32_REG, LWGP16_VALID_REG, LWGP16_REG_FIELD): New macros.
(MOVE32_RD, MOVE32_RS): Likewise.
(MOVE16_RD_FIELD, MOVE16_RS_FIELD): Likewise.
(move_insns_32, move_insns_16): New variables.
(nop_insn_32, nop_insn_16): Likewise.
(MATCH): New macro.
(find_match): New function.
(relax_delay_slot): Likewise.
(IS_BITSIZE): New macro.
(elf32_mips_relax_section): New function.
(bfd_elf32_bfd_relax_section): Define.
* elf64-mips.c (micromips_elf64_howto_table_rel): New variable.
(micromips_elf64_howto_table_rela): Likewise.
(micromips_reloc_map): Likewise.
(bfd_elf64_bfd_reloc_type_lookup): Handle microMIPS.
(bfd_elf64_bfd_reloc_name_lookup): Likewise.
(mips_elf64_rtype_to_howto): Likewise.
* elfn32-mips.c (elf_micromips_howto_table_rel): New variable.
(elf_micromips_howto_table_rela): Likewise.
(micromips_reloc_map): Likewise.
(bfd_elf32_bfd_reloc_type_lookup): Handle microMIPS.
(bfd_elf32_bfd_reloc_name_lookup): Likewise.
(mips_elf_n32_rtype_to_howto): Likewise.
* elfxx-mips.c (micromips_reloc_shuffle_p): New function.
(TLS_RELOC_P): Handle microMIPS.
(got16_reloc_p, call16_reloc_p): Likewise.
(hi16_reloc_p, lo16_reloc_p): Likewise.
(_bfd_mips16_elf_reloc_unshuffle): Likewise.
(_bfd_mips16_elf_reloc_shuffle): Likewise.
(_bfd_mips_elf_lo16_reloc): Likewise.
(mips_tls_got_index, mips_elf_got_page): Likewise.
(mips_elf_create_local_got_entry): Likewise.
(mips_elf_relocation_needs_la25_stub): Likewise.
(mips_elf_calculate_relocation): Likewise.
(mips_elf_perform_relocation): Likewise.
(_bfd_mips_elf_symbol_processing): Likewise.
(_bfd_mips_elf_add_symbol_hook): Likewise.
(_bfd_mips_elf_link_output_symbol_hook): Likewise.
(mips_elf_add_lo16_rel_addend): Likewise.
(_bfd_mips_elf_check_relocs): Likewise.
(mips_elf_adjust_addend): Likewise.
(_bfd_mips_elf_relocate_section): Likewise.
(_bfd_mips_vxworks_finish_dynamic_symbol): Likewise.
(_bfd_mips_elf_gc_sweep_hook): Likewise.
(_bfd_mips_elf_print_private_bfd_data): Likewise.
* reloc.c (BFD_RELOC_MICROMIPS_16): New relocation.
(BFD_RELOC_MICROMIPS_7_PCREL_S1): Likewise.
(BFD_RELOC_MICROMIPS_10_PCREL_S1): Likewise.
(BFD_RELOC_MICROMIPS_16_PCREL_S1): Likewise.
(BFD_RELOC_MICROMIPS_GPREL16): Likewise.
(BFD_RELOC_MICROMIPS_JMP, BFD_RELOC_MICROMIPS_HI16): Likewise.
(BFD_RELOC_MICROMIPS_HI16_S): Likewise.
(BFD_RELOC_MICROMIPS_LO16): Likewise.
(BFD_RELOC_MICROMIPS_LITERAL): Likewise.
(BFD_RELOC_MICROMIPS_GOT16): Likewise.
(BFD_RELOC_MICROMIPS_CALL16): Likewise.
(BFD_RELOC_MICROMIPS_GOT_HI16): Likewise.
(BFD_RELOC_MICROMIPS_GOT_LO16): Likewise.
(BFD_RELOC_MICROMIPS_CALL_HI16): Likewise.
(BFD_RELOC_MICROMIPS_CALL_LO16): Likewise.
(BFD_RELOC_MICROMIPS_SUB): Likewise.
(BFD_RELOC_MICROMIPS_GOT_PAGE): Likewise.
(BFD_RELOC_MICROMIPS_GOT_OFST): Likewise.
(BFD_RELOC_MICROMIPS_GOT_DISP): Likewise.
(BFD_RELOC_MICROMIPS_HIGHEST): Likewise.
(BFD_RELOC_MICROMIPS_HIGHER): Likewise.
(BFD_RELOC_MICROMIPS_SCN_DISP): Likewise.
(BFD_RELOC_MICROMIPS_JALR): Likewise.
(BFD_RELOC_MICROMIPS_TLS_GD): Likewise.
(BFD_RELOC_MICROMIPS_TLS_LDM): Likewise.
(BFD_RELOC_MICROMIPS_TLS_DTPREL_HI16): Likewise.
(BFD_RELOC_MICROMIPS_TLS_DTPREL_LO16): Likewise.
(BFD_RELOC_MICROMIPS_TLS_GOTTPREL): Likewise.
(BFD_RELOC_MICROMIPS_TLS_TPREL_HI16): Likewise.
(BFD_RELOC_MICROMIPS_TLS_TPREL_LO16): Likewise.
* bfd-in2.h: Regenerate.
* libbfd.h: Regenerate.
* elfxx-mips.c (mips_elf_calculate_relocation): Do not mark
calls to undefined weak functions as needing jalx.
* elfxx-mips.c (LA25_LUI_MICROMIPS_1, LA25_LUI_MICROMIPS_2,
LA25_J_MICROMIPS_1, LA25_J_MICROMIPS_2, LA25_ADDIU_MICROMIPS_1,
LA25_ADDIU_MICROMIPS_2): Define.
(mips_elf_add_la25_intro, mips_elf_add_la25_trampoline): Adjust
value of stub symbol if target is a microMIPS function.
(mips_elf_create_la25_stub): Create microMIPS stub if target is
a microMIPS function.
* elfxx-mips.c (mips_elf_calculate_relocation): Expect low bit
of $t9 to be set of microMIPS _gp_disp relocations.
binutils/
2010-06-01 Chao-ying Fu <fu@mips.com>
* readelf.c (get_machine_flags): Handle microMIPS.
(get_mips_symbol_other): Likewise.
gas/
2010-06-01 Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* config/tc-mips.h (mips_segment_info): Add one bit for
microMIPS.
* config/tc-mips.c (emit_branch_likely_macro): New variable.
(mips_set_options): Add micromips.
(mips_opts): Initialise micromips to -1.
(file_ase_micromips): New variable.
(CPU_HAS_MICROMIPS): New macro.
(HAVE_CODE_COMPRESSION): Likewise.
(micromips_op_hash): New variable.
(micromips_nop16_insn, micromips_nop32_insn): New variables.
(NOP_INSN): Handle microMIPS.
(mips32_to_micromips_reg_b_map): New macro.
(mips32_to_micromips_reg_c_map): Likewise.
(mips32_to_micromips_reg_d_map): Likewise.
(mips32_to_micromips_reg_e_map): Likewise.
(mips32_to_micromips_reg_f_map): Likewise.
(mips32_to_micromips_reg_g_map): Likewise.
(mips32_to_micromips_reg_l_map): Likewise.
(mips32_to_micromips_reg_q_map): New variable.
(micromips_to_32_reg_b_map): New macro.
(micromips_to_32_reg_c_map): Likewise.
(micromips_to_32_reg_d_map): Likewise.
(micromips_to_32_reg_e_map): Likewise.
(micromips_to_32_reg_f_map): Likewise.
(micromips_to_32_reg_g_map): Likewise.
(micromips_to_32_reg_l_map): Likewise.
(micromips_to_32_reg_q_map): New variable.
(micromips_imm_b_map, micromips_imm_c_map): New macros.
(RELAX_DELAY_SLOT_SIZE_ERROR_FIRST): New macro.
(RELAX_DELAY_SLOT_SIZE_ERROR_SECOND): Likewise.
(RELAX_MICROMIPS_ENCODE, RELAX_MICROMIPS_P): New macros.
(RELAX_MICROMIPS_TYPE, RELAX_MICROMIPS_USER_16BIT): Likewise.
(RELAX_MICROMIPS_UNCOND, RELAX_MICROMIPS_LINK): Likewise.
(RELAX_MICROMIPS_TOOFAR, RELAX_MICROMIPS_MARK_TOOFAR): Likewise.
(RELAX_MICROMIPS_CLEAR_TOOFAR): Likewise.
(RELAX_MICROMIPS_EXTENDED): Likewise.
(RELAX_MICROMIPS_MARK_EXTENDED): Likewise.
(RELAX_MICROMIPS_CLEAR_EXTENDED): Likewise.
(MICROMIPS_INSERT_OPERAND, MICROMIPS_EXTRACT_OPERAND): New
macros.
(A_BFD_RELOC_HI16_S, A_BFD_RELOC_HI16, A_BFD_RELOC_LO16): New
relocation wrapper macros.
(A_BFD_RELOC_GPREL16): Likewise.
(A_BFD_RELOC_MIPS_GOT16, A_BFD_RELOC_MIPS_GOT_HI16): Likewise.
(A_BFD_RELOC_MIPS_GOT_LO16, A_BFD_RELOC_MIPS_HIGHEST): Likewise.
(A_BFD_RELOC_MIPS_HIGHER, A_BFD_RELOC_MIPS_GOT_DISP): Likewise.
(A_BFD_RELOC_MIPS_GOT_PAGE, A_BFD_RELOC_MIPS_GOT_OFST): Likewise.
(A_BFD_RELOC_MIPS_SUB, A_BFD_RELOC_MIPS_JALR): Likewise.
(mips_macro_warning): Add delay_slot_16bit_p, delay_slot_32bit_p,
and num_insns.
(micromips_16, micromips_32): New variables.
(is_micromips_16bit_p, is_micromips_32bit_p): New functions.
(insn_length): Return the length of microMIPS instructions.
(mips_record_mips16_mode): Rename to...
(mips_record_mips16_micromips_mode): ... this. Handle microMIPS.
(install_insn): Handle microMIPS.
(is_size_valid, is_delay_slot_valid): New functions.
(md_begin): Handle microMIPS.
(md_assemble): Likewise.
(micromips_reloc_p): New function.
(got16_reloc_p): Handle microMIPS.
(hi16_reloc_p): Likewise.
(lo16_reloc_p): Likewise.
(matching_lo_reloc): Likewise.
(mips_move_labels): Likewise.
(mips_mark_labels): New function.
(mips16_mark_labels): Rename to...
(mips_compressed_mark_labels): ... this. Handle microMIPS.
(insns_between): Handle microMIPS.
(MICROMIPS_TARGET, MICROMIPS_TARGET_LABEL): New macros.
(micromips_add_number_label): New function.
(append_insn): Handle microMIPS.
(start_noreorder, end_noreorder): Likewise.
(macro_start, macro_warning, macro_end): Likewise.
(macro_build): Likewise.
(macro_build_jalr): Likewise.
(macro_build_lui): Likewise.
(macro_build_ldst_constoffset): Use relocation wrappers.
(set_at): Likewise.
(load_register): Likewise.
(load_address): Likewise.
(move_register): Handle microMIPS.
(load_got_offset): Use relocation wrappers.
(add_got_offset): Likewise.
(add_got_offset_hilo): Likewise.
(macro): Handle microMIPS.
(validate_micromips_insn): New function.
(micromips_percent_op): New variable.
(parse_relocation): Handle microMIPS.
(my_getExpression): Likewise.
(options): Add OPTION_MICROMIPS and OPTION_NO_MICROMIPS.
(md_longopts): Add mmicromips and mno-micromips.
(md_parse_option): Handle OPTION_MICROMIPS and
OPTION_NO_MICROMIPS.
(mips_after_parse_args): Handle microMIPS.
(md_pcrel_from): Handle microMIPS relocations.
(mips_force_relocation): Likewise.
(md_apply_fix): Likewise.
(mips_align): Handle microMIPS.
(s_mipsset): Likewise.
(s_cpload, s_cpsetup, s_cpreturn): Use relocation wrappers.
(s_dtprel_internal): Likewise.
(s_gpword, s_gpdword): Likewise.
(s_insn): Handle microMIPS.
(s_mips_stab): Likewise.
(relaxed_micromips_32bit_branch_length): New function.
(relaxed_micromips_16bit_branch_length): New function.
(md_estimate_size_before_relax): Handle microMIPS.
(mips_fix_adjustable): Likewise.
(tc_gen_reloc): Handle microMIPS relocations.
(mips_relax_frag): Handle microMIPS.
(md_convert_frag): Likewise.
(mips_frob_file_after_relocs): Likewise.
(mips_elf_final_processing): Likewise.
(mips_nop_opcode): Likewise.
(mips_handle_align): Likewise.
(md_show_usage): Handle microMIPS options.
(micromips_ip): New function.
(micromips_macro_build): Likewise.
(micromips_macro): Likewise.
* doc/as.texinfo (Target MIPS options): Add -mmicromips and
-mno-micromips.
(-mmicromips, -mno-micromips): New options.
* doc/c-mips.texi (-mmicromips, -mno-micromips): New options.
(MIPS ISA): Document .set micromips and .set nomicromips.
* config/tc-mips.c (nops_for_insn_or_target): Replace
MIPS16_INSN_BRANCH with MIPS16_INSN_UNCOND_BRANCH and
MIPS16_INSN_COND_BRANCH.
* config/tc-mips.c (append_insn): Replace INSN2_MOD_31 with
INSN2_READ_GPR_31. Merge with code to handle INSN_WRITE_GPR_31.
* config/tc-mips.c (mips32_to_micromips_reg_h_map): New
variable.
(mips32_to_micromips_reg_m_map): Likewise.
(mips32_to_micromips_reg_n_map): New macro.
(micromips_to_32_reg_h_map): New variable.
(micromips_to_32_reg_i_map): Likewise.
(micromips_to_32_reg_m_map): Likewise.
(micromips_to_32_reg_n_map): New macro.
(append_insn): Handle microMIPS "mh", "mi", "mm" and "mn"
operands.
gas/testsuite/
2010-06-01 Maciej W. Rozycki <macro@codesourcery.com>
Chao-ying Fu <fu@mips.com>
* gas/mips/beq.d: Reformat.
* gas/mips/bge.d, gas/mips/bgeu.d: Likewise.
* gas/mips/blt.d, gas/mips/bltu.d: Likewise.
* gas/mips/mips4-fp.d: Reformat.
* gas/mips/beq.d, gas/mips/beq.s: Remove checks for
branch-likely instructions and place them...
* gas/mips/bge.d, gas/mips/bge.s: Likewise.
* gas/mips/bgeu.d, gas/mips/bgeu.s: Likewise.
* gas/mips/blt.d, gas/mips/blt.s: Likewise.
* gas/mips/bltu.d, gas/mips/bltu.s: Likewise.
* gas/mips/branch-likely.d, gas/mips/branch-likely.s: ... in
this new test.
* gas/mips/mips.exp: Run the new test and update the
constraints for the upated tests to include MIPS I.
* gas/mips/mips4-fp.d, gas/mips/mips4-fp.s: Remove checks for
branch-likely instructions and place them...
* gas/mips/mips4-fp.l: Update accordingly.
* gas/mips/mips4-branch-likely.d, gas/mips/mips4-branch-likely.s:
... in this new test.
* gas/mips/mips4-branch-likely.l: New stderr output for the new
test.
* gas/mips/mips.exp (mips4-branch-likely): Run a dump test and
list tests matching branch-likely and mips4-fp tests
appropriately.
* gas/mips/micromips.d: New test.
* gas/mips/micromips-trap.d: Likewise.
* gas/mips/micromips-branch-relax-pic.d: Likewise.
* gas/mips/micromips-branch-relax-pic.d: Likewise.
* gas/mips/micromips.l: New stderr output.
* gas/mips/micromips-branch-relax.l: Likewise.
* gas/mips/micromips-branch-relax-pic.l: Likewise.
* gas/mips/micromips.s: New test source.
* gas/mips/micromips-branch-relax.s: Likewise.
* gas/mips/mips.exp: Run the new tests.
* gas/mips/mips.exp (run_dump_test_arch): Check for the presence
of an architecture-specific test first and use it if found,
before falling back to the generic one.
* gas/mips/micromips@abs.d: New test.
* gas/mips/micromips@add.d: Likewise.
* gas/mips/micromips@and.d: Likewise.
* gas/mips/micromips@beq.d: Likewise.
* gas/mips/micromips@bge.d: Likewise.
* gas/mips/micromips@bgeu.d: Likewise.
* gas/mips/micromips@blt.d: Likewise.
* gas/mips/micromips@bltu.d: Likewise.
* gas/mips/micromips@branch-likely.d: Likewise.
* gas/mips/micromips@branch-misc-1.d: Likewise.
* gas/mips/micromips@branch-misc-2-64.d: Likewise.
* gas/mips/micromips@branch-misc-2.d: Likewise.
* gas/mips/micromips@branch-misc-2pic-64.d: Likewise.
* gas/mips/micromips@branch-misc-2pic.d: Likewise.
* gas/mips/micromips@dli.d: Likewise.
* gas/mips/micromips@elf-jal.d: Likewise.
* gas/mips/micromips@elf-rel2.d: Likewise.
* gas/mips/micromips@elf-rel4.d: Likewise.
* gas/mips/micromips@lb-svr4pic-ilocks.d: Likewise.
* gas/mips/micromips@li.d: Likewise.
* gas/mips/micromips@mips1-fp.d: Likewise.
* gas/mips/micromips@mips32-cp2.d: Likewise.
* gas/mips/micromips@mips32-imm.d: Likewise.
* gas/mips/micromips@mips32-sf32.d: Likewise.
* gas/mips/micromips@mips32.d: Likewise.
* gas/mips/micromips@mips32r2-cp2.d: Likewise.
* gas/mips/micromips@mips32r2-fp32.d: Likewise.
* gas/mips/micromips@mips32r2.d: Likewise.
* gas/mips/micromips@mips4-branch-likely.d: Likewise.
* gas/mips/micromips@mips4-fp.d: Likewise.
* gas/mips/micromips@mips4.d: Likewise.
* gas/mips/micromips@mips5.d: Likewise.
* gas/mips/micromips@mips64-cp2.d: Likewise.
* gas/mips/micromips@mips64.d: Likewise.
* gas/mips/micromips@mips64r2.d: Likewise.
* gas/mips/micromips@rol-hw.d: Likewise.
* gas/mips/micromips@uld2-eb.d: Likewise.
* gas/mips/micromips@uld2-el.d: Likewise.
* gas/mips/micromips@ulh2-eb.d: Likewise.
* gas/mips/micromips@ulh2-el.d: Likewise.
* gas/mips/micromips@ulw2-eb-ilocks.d: Likewise.
* gas/mips/micromips@ulw2-el-ilocks.d: Likewise.
* gas/mips/mips32-imm.d: Likewise.
* gas/mips/mips32.d: Update immediates.
* gas/mips/micromips@mips32-cp2.s: New test source.
* gas/mips/micromips@mips32-imm.s: Likewise.
* gas/mips/micromips@mips32r2-cp2.s: Likewise.
* gas/mips/micromips@mips64-cp2.s: Likewise.
* gas/mips/mips32-imm.s: Likewise.
* gas/mips/mips32.s: Handle microMIPS.
* gas/mips/mips.exp: Add the micromips arch. Exclude mips16e
from micromips. Run mips32-imm.
* gas/mips/jal-mask-11.d: New test.
* gas/mips/jal-mask-12.d: Likewise.
* gas/mips/micromips@jal-mask-11.d: Likewise.
* gas/mips/jal-mask-1.s: Source for the new tests.
* gas/mips/jal-mask-21.d: New test.
* gas/mips/jal-mask-22.d: Likewise.
* gas/mips/micromips@jal-mask-12.d: Likewise.
* gas/mips/jal-mask-2.s: Source for the new tests.
* gas/mips/mips.exp: Run the new tests.
include/elf/
2010-06-01 Chao-ying Fu <fu@mips.com>
* mips.h (R_MICROMIPS_min, R_MICROMIPS_16): New relocations.
(R_MICROMIPS_26_S1): Likewise.
(R_MICROMIPS_HI16, R_MICROMIPS_LO16): Likewise.
(R_MICROMIPS_GPREL16, R_MICROMIPS_LITERAL): Likewise.
(R_MICROMIPS_GOT16, R_MICROMIPS_PC7_S1): Likewise.
(R_MICROMIPS_PC10_S1, R_MICROMIPS_PC16_S1): Likewise.
(R_MICROMIPS_CALL16, R_MICROMIPS_GOT_DISP): Likewise.
(R_MICROMIPS_GOT_PAGE, R_MICROMIPS_GOT_OFST): Likewise.
(R_MICROMIPS_GOT_HI16, R_MICROMIPS_GOT_LO16): Likewise.
(R_MICROMIPS_SUB, R_MICROMIPS_HIGHER): Likewise.
(R_MICROMIPS_HIGHEST, R_MICROMIPS_CALL_HI16): Likewise.
(R_MICROMIPS_CALL_LO16, R_MICROMIPS_SCN_DISP): Likewise.
(R_MICROMIPS_JALR, R_MICROMIPS_HI0_LO16): Likewise.
(R_MICROMIPS_TLS_GD, R_MICROMIPS_TLS_LDM): Likewise.
(R_MICROMIPS_TLS_DTPREL_HI, R_MICROMIPS_TLS_DTPREL_LO): Likewise.
(R_MICROMIPS_TLS_GOTTPREL): Likewise.
(R_MICROMIPS_TLS_TPREL_HI16): Likewise.
(R_MICROMIPS_TLS_TPREL_LO16): Likewise.
(R_MICROMIPS_GPREL7_S2, R_MICROMIPS_PC23_S2): Likewise.
(R_MICROMIPS_max): Likewise.
(EF_MIPS_ARCH_ASE_MICROMIPS): New macro.
(ELF_ST_IS_MIPS_PLT): Likewise.
(STO_MICROMIPS): Likewise.
(ELF_ST_IS_MICROMIPS, ELF_ST_MICROMIPS, ELF_ST_SET_MICROMIPS):
Likewise.
(ELF_ST_IS_MIPS_PIC, ELF_ST_SET_MIPS_PIC): Handle microMIPS.
include/opcode/
2010-06-01 Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* mips.h
(INSN2_BRANCH_DELAY_16BIT, INSN2_BRANCH_DELAY_32BIT): New macros.
(INSN2_WRITE_GPR_S, INSN2_READ_FPR_D): Likewise.
(INSN2_MOD_GPR_MB, INSN2_MOD_GPR_MC, INSN2_MOD_GPR_MD): Likewise.
(INSN2_MOD_GPR_ME, INSN2_MOD_GPR_MF, INSN2_MOD_GPR_MG): Likewise.
(INSN2_MOD_GPR_MJ, INSN2_MOD_GPR_MP, INSN2_MOD_GPR_MQ): Likewise.
(INSN2_MOD_SP, INSN2_MOD_31): Likewise.
(INSN2_READ_GP, INSN2_READ_PC): Likewise.
(CPU_MICROMIPS): New macro.
(M_BC1FL, M_BC1TL, M_BC2FL, M_BC2TL, M_BEQL, M_BGEZL): New enum
values.
(M_BGEZALL, M_BGTZL, M_BLEZL, M_BLTZL, M_BLTZALL): Likewise.
(M_CACHE_OB, M_LDC2_OB, M_LDL_OB, M_LDM_AB, M_LDM_OB): Likewise.
(M_LDP_AB, M_LDP_OB, M_LDR_OB, M_LL_OB, M_LLD_OB): Likewise.
(M_LWC2_OB, M_LWL_OB, M_LWM_AB, M_LWP_AB, M_LWP_OB): Likewise.
(M_LWR_OB, M_LWU_OB, M_PREF_OB, M_SC_OB, M_SCD_OB): Likewise.
(M_SDC2_OB, M_SDL_OB, M_SDM_AB, M_SDM_OB, M_SDP_AB): Likewise.
(M_SDP_OB, M_SDR_OB, M_SWC2_OB, M_SWL_OB, M_SWM_AB): Likewise.
(M_SWM_OB, M_SWP_AB, M_SWP_OB, M_SWR_OB): Likewise.
(MICROMIPSOP_MASK_MAJOR, MICROMIPSOP_SH_MAJOR): New macros.
(MICROMIPSOP_MASK_IMMEDIATE, MICROMIPSOP_SH_IMMEDIATE): Likewise.
(MICROMIPSOP_MASK_DELTA, MICROMIPSOP_SH_DELTA): Likewise.
(MICROMIPSOP_MASK_CODE10, MICROMIPSOP_SH_CODE10): Likewise.
(MICROMIPSOP_MASK_TRAP, MICROMIPSOP_SH_TRAP): Likewise.
(MICROMIPSOP_MASK_SHAMT, MICROMIPSOP_SH_SHAMT): Likewise.
(MICROMIPSOP_MASK_TARGET, MICROMIPSOP_SH_TARGET): Likewise.
(MICROMIPSOP_MASK_EXTLSB, MICROMIPSOP_SH_EXTLSB): Likewise.
(MICROMIPSOP_MASK_EXTMSBD, MICROMIPSOP_SH_EXTMSBD): Likewise.
(MICROMIPSOP_MASK_INSMSB, MICROMIPSOP_SH_INSMSB): Likewise.
(MICROMIPSOP_MASK_BREAKCODE, MICROMIPSOP_SH_BREAKCODE): Likewise.
(MICROMIPSOP_SH_BREAKCODE2): Likewise.
(MICROMIPSOP_MASK_CACHEOP, MICROMIPSOP_SH_CACHEOP): Likewise.
(MICROMIPSOP_MASK_COPSEL, MICROMIPSOP_SH_COPSEL): Likewise.
(MICROMIPSOP_MASK_OFFSET12, MICROMIPSOP_SH_OFFSET12): Likewise.
(MICROMIPSOP_MASK_3BITPOS, MICROMIPSOP_SH_3BITPOS): Likewise.
(MICROMIPSOP_MASK_STYPE, MICROMIPSOP_SH_STYPE): Likewise.
(MICROMIPSOP_MASK_OFFSET10, MICROMIPSOP_SH_OFFSET10): Likewise.
(MICROMIPSOP_MASK_RS, MICROMIPSOP_SH_RS): Likewise.
(MICROMIPSOP_MASK_RT, MICROMIPSOP_SH_RT): Likewise.
(MICROMIPSOP_MASK_RD, MICROMIPSOP_SH_RD): Likewise.
(MICROMIPSOP_MASK_FS, MICROMIPSOP_SH_FS): Likewise.
(MICROMIPSOP_MASK_FT, MICROMIPSOP_SH_FT): Likewise.
(MICROMIPSOP_MASK_FD, MICROMIPSOP_SH_FD): Likewise.
(MICROMIPSOP_MASK_FR, MICROMIPSOP_SH_FR): Likewise.
(MICROMIPSOP_MASK_RS3, MICROMIPSOP_SH_RS3): Likewise.
(MICROMIPSOP_MASK_PREFX, MICROMIPSOP_SH_PREFX): Likewise.
(MICROMIPSOP_MASK_BCC, MICROMIPSOP_SH_BCC): Likewise.
(MICROMIPSOP_MASK_CCC, MICROMIPSOP_SH_CCC): Likewise.
(MICROMIPSOP_MASK_COPZ, MICROMIPSOP_SH_COPZ): Likewise.
(MICROMIPSOP_MASK_MB, MICROMIPSOP_SH_MB): Likewise.
(MICROMIPSOP_MASK_MC, MICROMIPSOP_SH_MC): Likewise.
(MICROMIPSOP_MASK_MD, MICROMIPSOP_SH_MD): Likewise.
(MICROMIPSOP_MASK_ME, MICROMIPSOP_SH_ME): Likewise.
(MICROMIPSOP_MASK_MF, MICROMIPSOP_SH_MF): Likewise.
(MICROMIPSOP_MASK_MG, MICROMIPSOP_SH_MG): Likewise.
(MICROMIPSOP_MASK_MJ, MICROMIPSOP_SH_MJ): Likewise.
(MICROMIPSOP_MASK_ML, MICROMIPSOP_SH_ML): Likewise.
(MICROMIPSOP_MASK_MP, MICROMIPSOP_SH_MP): Likewise.
(MICROMIPSOP_MASK_MQ, MICROMIPSOP_SH_MQ): Likewise.
(MICROMIPSOP_MASK_MZ, MICROMIPSOP_SH_MZ): Likewise.
(MICROMIPSOP_MASK_IMMA, MICROMIPSOP_SH_IMMA): Likewise.
(MICROMIPSOP_MASK_IMMB, MICROMIPSOP_SH_IMMB): Likewise.
(MICROMIPSOP_MASK_IMMC, MICROMIPSOP_SH_IMMC): Likewise.
(MICROMIPSOP_MASK_IMMD, MICROMIPSOP_SH_IMMD): Likewise.
(MICROMIPSOP_MASK_IMME, MICROMIPSOP_SH_IMME): Likewise.
(MICROMIPSOP_MASK_IMMF, MICROMIPSOP_SH_IMMF): Likewise.
(MICROMIPSOP_MASK_IMMG, MICROMIPSOP_SH_IMMG): Likewise.
(MICROMIPSOP_MASK_IMMH, MICROMIPSOP_SH_IMMH): Likewise.
(MICROMIPSOP_MASK_IMMI, MICROMIPSOP_SH_IMMI): Likewise.
(MICROMIPSOP_MASK_IMMJ, MICROMIPSOP_SH_IMMJ): Likewise.
(MICROMIPSOP_MASK_IMML, MICROMIPSOP_SH_IMML): Likewise.
(MICROMIPSOP_MASK_IMMM, MICROMIPSOP_SH_IMMM): Likewise.
(MICROMIPSOP_MASK_IMMN, MICROMIPSOP_SH_IMMN): Likewise.
(MICROMIPSOP_MASK_IMMO, MICROMIPSOP_SH_IMMO): Likewise.
(MICROMIPSOP_MASK_IMMP, MICROMIPSOP_SH_IMMP): Likewise.
(MICROMIPSOP_MASK_IMMQ, MICROMIPSOP_SH_IMMQ): Likewise.
(MICROMIPSOP_MASK_IMMU, MICROMIPSOP_SH_IMMU): Likewise.
(MICROMIPSOP_MASK_IMMW, MICROMIPSOP_SH_IMMW): Likewise.
(MICROMIPSOP_MASK_IMMX, MICROMIPSOP_SH_IMMX): Likewise.
(MICROMIPSOP_MASK_IMMY, MICROMIPSOP_SH_IMMY): Likewise.
(micromips_opcodes): New declaration.
(bfd_micromips_num_opcodes): Likewise.
* mips.h (MIPS16_INSN_UNCOND_BRANCH): New macro.
(MIPS16_INSN_BRANCH): Rename to...
(MIPS16_INSN_COND_BRANCH): ... this.
* mips.h (INSN2_MOD_31): Rename to...
(INSN2_READ_GPR_31): ... this.
(INSN2_UNCOND_BRANCH, INSN2_COND_BRANCH): New macros.
* mips.h (INSN2_MOD_GPR_MHI): New macro.
(INSN2_MOD_GPR_MM, INSN2_MOD_GPR_MN): Likewise.
(MICROMIPSOP_MASK_MH, MICROMIPSOP_SH_MH): Likewise.
(MICROMIPSOP_MASK_MI, MICROMIPSOP_SH_MI): Likewise.
(MICROMIPSOP_MASK_MM, MICROMIPSOP_SH_MM): Likewise.
(MICROMIPSOP_MASK_MN, MICROMIPSOP_SH_MN): Likewise.
ld/testsuite/
2010-06-01 Catherine Moore <clm@codesourcery.com>
Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* ld-mips-elf/jalx-1.s: New test.
* ld-mips-elf/jalx-1.d: New test output.
* ld-mips-elf/jalx-1.ld: New test linker script.
* ld-mips-elf/mips-elf.exp: Run new test.
* ld-mips-elf/jalx-2-main.s: New.
* ld-mips-elf/jalx-2.dd: New.
* ld-mips-elf/jalx-2-ex.s: New.
* ld-mips-elf/jalx-2-printf.s: New.
* ld-mips-elf/mips-elf.exp: Run new test.
opcodes/
2010-06-01 Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* micromips-opc.c: New file.
* mips-dis.c (micromips_to_32_reg_b_map): New array.
(micromips_to_32_reg_c_map, micromips_to_32_reg_d_map): Likewise.
(micromips_to_32_reg_e_map, micromips_to_32_reg_f_map): Likewise.
(micromips_to_32_reg_g_map, micromips_to_32_reg_l_map): Likewise.
(micromips_to_32_reg_q_map): Likewise.
(micromips_imm_b_map, micromips_imm_c_map): Likewise.
(print_insn_micromips): New function.
(is_micromips_mode_p): New function.
(_print_insn_mips): Handle microMIPS instructions.
* Makefile.am (CFILES): Add micromips-opc.c.
* configure.in (bfd_mips_arch): Add micromips-opc.lo.
* Makefile.in: Regenerate.
* configure: Regenerate.
* mips-dis.c (print_mips16_insn_arg): Remove branch instruction
type and delay slot determination.
(print_insn_mips16): Extend branch instruction type and delay
slot determination to cover all instructions.
* mips16-opc.c (BR): Remove macro.
(UBR, CBR): New macros.
(mips16_opcodes): Update branch annotation for "b", "beqz",
"bnez", "bteqz" and "btnez". Add branch annotation for "jalrc"
and "jrc".
* mips-dis.c (print_insn_mips): Correct branch instruction type
determination.
* mips-dis.c (micromips_to_32_reg_h_map): New variable.
(micromips_to_32_reg_i_map): Likewise.
(micromips_to_32_reg_m_map): Likewise.
(micromips_to_32_reg_n_map): New macro.
[-- Attachment #2: Type: APPLICATION/octet-stream, Size: 128412 bytes --]
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS and MCU ASE instruction set support
2010-06-01 14:21 ` Maciej W. Rozycki
@ 2010-06-01 14:39 ` Catherine Moore
2010-06-01 22:04 ` Richard Sandiford
` (2 subsequent siblings)
3 siblings, 0 replies; 41+ messages in thread
From: Catherine Moore @ 2010-06-01 14:39 UTC (permalink / raw)
To: Maciej W. Rozycki
Cc: Richard Sandiford, binutils, Chao-ying Fu, Joseph S. Myers,
Daniel Jacobowitz
Maciej W. Rozycki wrote:
> Hi Richard,
>
>>> * ld-mips-elf/jalx-2-main.s: New.
>>> * ld-mips-elf/jalx-2.dd: New.
>>> * ld-mips-elf/jalx-2-ex.s: New.
>>> * ld-mips-elf/jalx-2-printf.s: New.
>>> * ld-mips-elf/mips-elf.exp: Run new test.
>> Please make the .dd output less susceptible to things like the number
>> of sections, size of program headers, etc. One way is to use a linker
>> script to place each section at a nice round address. Another is to
>> ".*" out the addresses and instruction encodings and just reply on
>> the symbolic part of the disassembly. I think the former's better
>> here. There are quite a few existing examples.
>
> Catherine, I reckon you were working on these?
>
I will make these testsuite revisions.
--catherine
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS and MCU ASE instruction set support
2010-06-01 14:21 ` Maciej W. Rozycki
2010-06-01 14:39 ` Catherine Moore
@ 2010-06-01 22:04 ` Richard Sandiford
2010-06-01 22:47 ` Fu, Chao-Ying
2010-06-05 9:17 ` Richard Sandiford
3 siblings, 0 replies; 41+ messages in thread
From: Richard Sandiford @ 2010-06-01 22:04 UTC (permalink / raw)
To: Maciej W. Rozycki
Cc: binutils, Chao-ying Fu, Catherine Moore, Joseph S. Myers,
Daniel Jacobowitz
"Maciej W. Rozycki" <macro@codesourcery.com> writes:
>> Generally looks good. It would have been better to submit the
>> ACE, m14kc and microMIPS support as three separate changes though.
>> Please can you do that for the follow-up?
>
> I have done it now; the next version will comprise microMIPS ASE changes
> only (the MCU ASE adds to both the MIPS ISA and the microMIPS ASE, so it
> should be applied on top of the microMIPS change).
Thanks. Thanks too for all the issues that you've addressed already,
and for the ones you said you'd sort out. Sounds like good progress!
> Stricly speaking some changes, while related, can be split off too (e.g.
> some MIPS16 or testsuite changes), so I'll look into separating them too
> -- perhaps that'll make the thing rolling sooner.
Yeah, thanks, that'd be a help if it's easy to do. It doesn't matter
too much, though. Most of the MIPS16 changes were consistent with the
microMIPS ones, so were easy to review as a unit.
>> From a usability perspective, it's a shame that:
>>
>> .set micromips
>> .ent foo
>> foo:
>> b 1f
>> nop
>> .end foo
>> .ent bar
>> bar:
>> 1: nop
>> .end bar
>>
>> disassembles as:
>>
>> 00000000 <foo>:
>> 0: cfff b 0 <foo>
>> 0: R_MICROMIPS_PC10_S1 .L11
>> 2: 0c00 nop
>> 4: 0c00 nop
>>
>> 00000006 <bar>:
>> 6: 0c00 nop
>>
>> leaving the poor user with no idea what .L11 is.
>
> Indeed. This is a general limitation of `objdump' it would seem. This
> is no different to what you get with:
>
> $ cat b.s
> .globl baz
> .ent foo
> foo:
> b baz
> nop
> .end foo
> .ent bar
> baz:
> bar:
> 1: nop
> .end bar
> $ mips-sde-elf-objdump -dr b.o
>
> b.o: file format elf32-tradbigmips
>
>
> Disassembly of section .text:
>
> 00000000 <foo>:
> 0: 1000ffff b 0 <foo>
> 0: R_MIPS_PC16 baz
> 4: 00000000 nop
> 8: 00000000 nop
>
> 0000000c <bar>:
> c: 00000000 nop
Well, it's a little different. The user has at least defined two
named symbols in this case, so they have a good chance of knowing
what "baz" means. In the microMIPS case we've invented a label
and are using it in preference to the user-defined one.
> I'd just recommend peeking at the symbol table (back to the first
> program):
>
> $ mips-sde-elf-objdump -t b.o
>
> b.o: file format elf32-tradbigmips
>
> SYMBOL TABLE:
> 00000000 l d .text 00000000 .text
> 00000000 l d .data 00000000 .data
> 00000000 l d .bss 00000000 .bss
> 00000000 l d .reginfo 00000000 .reginfo
> 00000000 l d .pdr 00000000 .pdr
> 00000000 l F .text 00000006 0x80 foo
> 00000006 l F .text 00000002 0x80 bar
> 00000006 l .text 00000000 0x80 .L1\x021
I suppose having a symbol with ^B in it is less than ideal too.
AIUI that name was chosen specifically because it wasn't supposed
to be written out.
It would be especially confusing if the user or compiler had a ".L11"
label (without the ^B).
>> The following:
>>
>> .set micromips
>> .ent foo
>> foo:
>> ld $10,0x1000($11)
>> .end foo
>>
>> generates an assertion failure:
>>
>> Assertion failure in micromips_macro_build at gas/config/tc-mips.c line 19466.
>> Please report this bug.
>>
>> on mipsisa64-elf with "-mips1 -mabi=32".
>
> I can't reproduce it, sorry:
> [...]
> Can you debug it and see what the relocation type is that's causing it?
> I wonder if that might be related to the varargs issue you referring to
> below and depend on the host architecture, hmm...
Yeah, you're right, sorry. I forgot to mention that in the later reviews.
This was with a x86_64-linux-gnu host and a botched attempt at working
around the varags issue. (I probably just added -Wno-error or something,
I can't remember now.)
I switched to a 32-bit host for parts 2 and 3 of the review, and yeah,
it doesn't reproduce there.
>> > gas/
>> > 2010-05-18 Chao-ying Fu <fu@mips.com>
>> > Maciej W. Rozycki <macro@codesourcery.com>
>> > Daniel Jacobowitz <dan@codesourcery.com>
>> >
>> > * config/tc-mips.h (mips_segment_info): Add one bit for
>> > microMIPS.
>> > * config/tc-mips.c
>>
>> How about having something like:
>>
>> #define OOD_TEXT_LABELS (mips_opts.mips16 || mips_opts.micromips)
>>
>> ?
>
> It sounds reasonable to me, except that condition is used in some other
> contexts as well. I have made it HAVE_CODE_COMPRESSION thus and took the
> opportunity to optimise code around mips16_micromips_mark_labels() too.
> Finally I have renamed the function to mips_compressed_mark_labels() for
> as the other sounds too complicated to me.
All these changes sound good, thanks.
>> > (append_insn): Handle microMIPS.
>>
>> + if (mips_opts.micromips)
>> + {
>> + if ((prev_pinfo2 & INSN2_BRANCH_DELAY_16BIT)
>> + && !is_micromips_16bit_p (ip->insn_mo))
>> + as_warn (_("instruction with wrong size in a branch delay slot that"
>> + " requires a 16-bit instruction"));
>> + if ((prev_pinfo2 & INSN2_BRANCH_DELAY_32BIT)
>> + && !is_micromips_32bit_p (ip->insn_mo))
>> + as_warn (_("instruction with wrong size in a branch delay slot that"
>> + " requires a 32-bit instruction"));
>> + }
>> +
>>
>> Although not enforced as often as it should be, GAS convention is for
>> errors to start with a capital letter.
>
> I'll be fixing these up as I come across them. If to be effective, then
> upstream HEAD should be fixed up or otherwise people have no way not to
> get confused. I didn't know of this rule for one. That shouldn't be a
> lot effort, should it?
Nope. It's just a question of time and priorities. ;-)
> Some have to stay for now actually, because .l testsuite patterns are
> commonly shared between standard MIPS and microMIPS tests, and should be
> fixed separately.
OK, that's fine.
>> + if (pinfo & INSN_COP)
>> + {
>> + /* We don't keep enough information to sort these cases out.
>> + The itbl support does keep this information however, although
>> + we currently don't support itbl fprmats as part of the cop
>> + instruction. May want to add this support in the future. */
>> + }
>>
>> Assert?
>
> Well, that's no different to the standard MIPS variant.
OK, fair enough, but I suppose I was judging the new code on its merits
as new code. Sticking to existing practice is an easier sell if the
code that implements it is being reused rather than copied...
>> +do_lsb:
>>
>> Not properly indented. A few other instances.
>
> Like the respective originals in mips_ip(). I have fixed up the new
> labels, but upstream HEAD code should be adjusted the same way.
Thanks. Yeah, sorting out the new code is all that's needed.
As before, I was judging the code on its own merits rather than
checking whether each dubious bit was new or from cut-&-paste.
It'll be a while before I have chance to go through the update
properly, but it looks good at first glance.
Richard
^ permalink raw reply [flat|nested] 41+ messages in thread
* RE: [PATCH] MIPS: microMIPS and MCU ASE instruction set support
2010-06-01 14:21 ` Maciej W. Rozycki
2010-06-01 14:39 ` Catherine Moore
2010-06-01 22:04 ` Richard Sandiford
@ 2010-06-01 22:47 ` Fu, Chao-Ying
2010-06-05 9:17 ` Richard Sandiford
3 siblings, 0 replies; 41+ messages in thread
From: Fu, Chao-Ying @ 2010-06-01 22:47 UTC (permalink / raw)
To: Maciej W. Rozycki, Richard Sandiford
Cc: binutils, Catherine Moore, Joseph S. Myers, dan
Maciej W. Rozycki wrote:
> I'm placing notes throughout and I'll be asking people for
> explanations
> where applicable. Chao-ying, would you please look into the
> few pieces of
> code below I am a bit uncertain about?
Yes.
>
> > > (A_BFD_RELOC_HI16_S, A_BFD_RELOC_HI16, A_BFD_RELOC_LO16): New
> > > relocation wrapper macros.
> > > (A_BFD_RELOC_GPREL16): Likewise.
> > > (A_BFD_RELOC_MIPS_GOT16, A_BFD_RELOC_MIPS_GOT_HI16): Likewise.
> > > (A_BFD_RELOC_MIPS_GOT_LO16, A_BFD_RELOC_MIPS_HIGHEST): Likewise.
> > > (A_BFD_RELOC_MIPS_HIGHER, A_BFD_RELOC_MIPS_GOT_DISP): Likewise.
> > > (A_BFD_RELOC_MIPS_GOT_PAGE, A_BFD_RELOC_MIPS_GOT_OFST):
> Likewise.
> > > (A_BFD_RELOC_MIPS_SUB, A_BFD_RELOC_MIPS_JALR): Likewise.
> >
> > Did you consider doing the translation from non-microMIPS to
> > microMIPS in the macro_* functions, rather than in their callers?
> > I fear it'll be too easy to accidentally forget to use
> A_BFD_* in future.
>
> Agreed, I didn't like the new macros from the very
> beginning. Chao-ying
> -- any thoughts?
I am fine. But the new method may be bigger than the A_BFD* method.
>
> > > (macro_start, macro_warning, macro_end): Likewise.
> >
> > + else if ((subtype & RELAX_DELAY_SLOT_SIZE_ERROR_FIRST)
> > + || (subtype & RELAX_DELAY_SLOT_SIZE_ERROR_SECOND))
> > + return _("Macro instruction of the wrong size in a
> branch delay slot"
> > + " that requires a 16-bit or 32-bit instruction");
> >
> > Did you consider adding a flag to distinguish the 32-bit
> and 16-bit cases?
> > It'd be nice to be consistent with the non-relaxed error if
> possible.
>
> Chao-ying? I've had a look actually and flag may not be
> necessary to get
> the functionality. I'm fixing this up elsewhere already.
I am fine with this functionality. Maybe passing one more parameter to
macro_warning() can help to distinguish two cases.
>
> > + /* If either one implementation contains one
> instruction, we need to check
> > + the delay slot size requirement. */
> > + if (mips_macro_warning.num_insns[0] == 1
> > + || mips_macro_warning.num_insns[1] == 1)
> > + {
> > + if (mips_macro_warning.num_insns[0] ==
> mips_macro_warning.num_insns[1]
> > + && mips_macro_warning.sizes[0] == mips_macro_warning.sizes[1])
> > + {
> > + /* Either the macro has a single implementation or both
> > + implementations are 1 instruction with the same size.
> > + Emit the warning now. */
> > + if ((mips_macro_warning.delay_slot_16bit_p
> > + && mips_macro_warning.sizes[0] != 2)
> > + || (mips_macro_warning.delay_slot_32bit_p
> > + && mips_macro_warning.sizes[0] != 4))
> > + {
> > + const char *msg;
> > + msg = macro_warning (RELAX_DELAY_SLOT_SIZE_ERROR_FIRST);
> > + if (msg != 0)
> > + as_warn (msg);
> > + }
> > + }
> > + else
> > + {
> > + relax_substateT subtype;
> > +
> > + /* Set up the relaxation warning flags. */
> > + subtype = 0;
> > + if (mips_macro_warning.delay_slot_16bit_p)
> > + {
> > + if (mips_macro_warning.num_insns[0] != 1
> > + || mips_macro_warning.sizes[0] != 2)
> > + subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
> > + if (mips_macro_warning.num_insns[1] != 1
> > + || mips_macro_warning.sizes[1] != 2)
> > + subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
> > + }
> > + if (mips_macro_warning.delay_slot_32bit_p)
> > + {
> > + if (mips_macro_warning.num_insns[0] != 1
> > + || mips_macro_warning.sizes[0] != 4)
> > + subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
> > + if (mips_macro_warning.num_insns[1] != 1
> > + || mips_macro_warning.sizes[1] != 4)
> > + subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
> > + }
> > +
> > + /* One implementation might need a warning but the other
> > + definitely doesn't. */
> > + mips_macro_warning.first_frag->fr_subtype |= subtype;
> > + }
> > + }
> >
> > Why not work out the subtype, then check whether both
> ERROR_FIRST and
> > ERROR_SECOND are set?
>
> Chao-ying?
Do you mean this kind of code?
Ex:
if (mips_macro_warning.num_insns[0] == 1
|| mips_macro_warning.num_insns[1] == 1)
{
if (mips_macro_warning.delay_slot_16bit_p)
{
if (mips_macro_warning.num_insns[0] != 1
|| mips_macro_warning.sizes[0] != 2)
subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
if (mips_macro_warning.num_insns[1] != 1
|| mips_macro_warning.sizes[1] != 2)
subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
}
else if (mips_macro_warning.delay_slot_32bit_p)
{
if (mips_macro_warning.num_insns[0] != 1
|| mips_macro_warning.sizes[0] != 4)
subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
if (mips_macro_warning.num_insns[1] != 1
|| mips_macro_warning.sizes[1] != 4)
subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
}
if ((subtype & RELAX_DELAY_SLOT_SIZE_ERROR_FIRST)
&& (subtype & RELAX_DELAY_SLOT_SIZE_ERROR_SECOND))
{
const char *msg;
msg = macro_warning (RELAX_DELAY_SLOT_SIZE_ERROR_FIRST); //
NEED TO PASS 16-bit or 32-bit info
if (msg != 0)
as_warn (msg);
}
else
{
/* One implementation might need a warning but the other
definitely doesn't. */
mips_macro_warning.first_frag->fr_subtype |= subtype;
}
}
>
> > + if (mips_macro_warning.delay_slot_p)
> > + {
> > + if (mips_macro_warning.num_insns[0] > 1)
> > + subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
> > + if (mips_macro_warning.num_insns[1] > 1)
> > + subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
> > + }
> >
> > I don't get why this hunk is needed. I thought ERROR_FIRST
> and ERROR_SECOND
> > controlled cases where a macro has a single-insn expansion
> that is the
> > wrong size, which ought to be handled by the block above.
> If the code
> > really is needed, you should add a comment explaining why.
>
> Chao-ying?
I agree. The delay_slot_p check is duplicated, and we can discard it
for
ERROR_FIRST and ERROR_SECOND when num_insns[]>1. My old code
double-checked the condition for
number of instructions in delay slots.
>
> > > (macro_build): Likewise.
> >
> > + if (mips_opts.micromips)
> > + {
> > + if (strcmp (name, "lui") == 0)
> > + micromips_macro_build (ep, name, "s,u", args);
> > + else if (strcmp (fmt, "d,w,<") == 0)
> > + micromips_macro_build (ep, name, "t,r,<", args);
> > + else
> > + micromips_macro_build (ep, name, fmt, args);
> > + va_end (args);
> > + return;
> > + }
> >
> > A bit of commentary might help explain the letter switch here.
>
> Chao-ying?
Because I didn't change all the code before calling LUI macro for
microMIPS, I need
to magically change the operand string for microMIPS to use "s,u" for
microMIPS LUI.
"d,w,<" is another case that we need to map it to "t,r,<" for microMIPS.
If we can search all the places and replace all calls with correct
operand strings for microMIPS,
this special code can be dropped.
>
> > > (macro_build_jalr): Likewise.
> >
> > + if (mips_opts.micromips)
> > + {
> > + if (HAVE_NEWABI)
> > + macro_build (NULL, "jalr", "t,s", RA, PIC_CALL_REG);
> > + else
> > + macro_build (NULL, "jalr", "mj", PIC_CALL_REG);
> > + }
> > + else
> > + macro_build (NULL, "jalr", "d,s", RA, PIC_CALL_REG);
> >
> > Why HAVE_NEWABI? Do you want a 32-bit insn for R_MIPS_JALR?
>
> Chao-ying?
OK. This code is done before I put the R_MIPS_JALR patch into GAS and
LD.
The new code is as follows.
Ex:
static void
macro_build_jalr (expressionS *ep)
{
char *f = NULL;
if (MIPS_JALR_HINT_P (ep))
{
frag_grow (8);
f = frag_more (0);
}
if (mips_opts.micromips)
macro_build (NULL, "jalr", "t,s", RA, PIC_CALL_REG);
else
macro_build (NULL, "jalr", "d,s", RA, PIC_CALL_REG);
if (MIPS_JALR_HINT_P (ep))
fix_new_exp (frag_now, f - frag_now->fr_literal,
4, ep, FALSE, A_BFD_RELOC_MIPS_JALR); // THIS MAY BE
FIXED BY A NEW METHOD.
}
And, we need to modify elfxx-mips.c to support
BFD_RELOC_MICROMIPS_JALR to convert jalr to bal for microMIPS.
>
> > If so, you should check MIPS_JALR_HINT_P (ep) instead.
>
> I may have missed that while updating the change for the
> recent JALR hint
> support, let me see...
>
> > > (md_convert_frag): Likewise.
> >
> > - /* Possibly emit a warning if we've chosen the
> longer option. */
> > - if (((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
> > - == ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))
> > + if (!(fragp->fr_subtype & RELAX_USE_SECOND))
> > + {
> > + /* Check if the size in branch delay slot is ok. */
> > + if (fragp->fr_subtype & RELAX_DELAY_SLOT_SIZE_ERROR_FIRST)
> > + {
> > + const char *msg = macro_warning (fragp->fr_subtype);
> > + if (msg != 0)
> > + as_warn_where (fragp->fr_file, fragp->fr_line, msg);
> > + }
> > + }
> > + else
> > {
> > - const char *msg = macro_warning (fragp->fr_subtype);
> > - if (msg != 0)
> > - as_warn_where (fragp->fr_file, fragp->fr_line, "%s", msg);
> > + /* Check if the size in branch delay slot is ok.
> > + Possibly emit a warning if we've chosen the longer
> option. */
> > + if ((fragp->fr_subtype & RELAX_DELAY_SLOT_SIZE_ERROR_SECOND)
> > + || (fragp->fr_subtype & RELAX_SECOND_LONGER))
> > + {
> > + const char *msg = macro_warning (fragp->fr_subtype);
> > + if (msg != 0)
> > + as_warn_where (fragp->fr_file, fragp->fr_line, msg);
> > + }
> > }
> >
> > This doesn't accurately preserve the previous:
> >
> > if (((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
> > == ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))
> >
> > behaviour.
>
> Chao-ying?
How about this?
Ex:
if ((((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
== ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))
|| (!(fragp->fr_subtype & RELAX_USE_SECOND)
&& (fragp->fr_subtype &
RELAX_DELAY_SLOT_SIZE_ERROR_FIRST))
|| ((fragp->fr_subtype & RELAX_USE_SECOND)
&& (fragp->fr_subtype &
RELAX_DELAY_SLOT_SIZE_ERROR_SECOND)))
{
const char *msg = macro_warning (fragp->fr_subtype); // MAY
NEED TO PASS 16-bit or 32-bit info
if (msg != 0)
as_warn_where (fragp->fr_file, fragp->fr_line, "%s", msg);
}
>
> > > (micromips_ip): New function.
> >
> > + /* Try to search "16" or "32" in the str. */
> > + if ((t = strstr (str, "16")) != NULL && t < save_s)
> > + {
> > + /* Make sure "16" is before the first '.' if '.' exists. */
> > + if ((s = strchr (str, '.')) != NULL && (t + 2 != s))
> > + {
> > + insn_error = "unrecognized opcode";
> > + return;
> > + }
> > +
> > + /* Make sure "16" is at the end of insn name, if no '.'. */
> > + if ((s = strchr (str, '.')) == NULL
> > + && (!ISSPACE (*(t + 2)) && *(t + 2) != '\0'))
> > + {
> > + insn_error = "unrecognized opcode";
> > + return;
> > + }
> > +
> > + micromips_16 = TRUE;
> > + for (s = t + 2; *s != '\0'; ++s)
> > + *(s - 2) = *s;
> > + *(s - 2) = '\0';
> > +
> > + for (s = t; *s != '\0' && !ISSPACE (*s); ++s)
> > + continue;
> > +
> > + if (ISSPACE (*s))
> > + {
> > + save_c = *s;
> > + *s++ = '\0';
> > + }
> > +
> > + if ((insn = (struct mips_opcode *) hash_find
> (micromips_op_hash, str))
> > + == NULL)
> > + {
> > + int i;
> > + int length;
> > + micromips_16 = FALSE;
> > +
> > + /* Restore the character we overwrite above (if any). */
> > + if (save_c)
> > + *(--s) = save_c;
> > +
> > + length = strlen (str);
> > + for (i = length - 1; &str[i] >= t; i--)
> > + {
> > + str[i + 2] = str[i];
> > + if (t == &str[i])
> > + {
> > + str[i + 1] = '6';
> > + str[i] = '1';
> > + str[length + 2] = '\0';
> > + break;
> > + }
> > + }
> > +
> > + insn_error = "unrecognized 16-bit version of
> microMIPS opcode";
> > + return;
> > + }
> > + }
> > + else if ((t = strstr (str, "32")) != NULL && t < save_s)
> > + {
> > + /* For some instruction names, we already have 32, so we need
> > + to seek the second 32 to process. Ex: bposge3232,
> dsra3232. */
> > + char *new_t;
> > + if ((new_t = strstr (t + 2, "32")) != NULL && new_t < save_s)
> > + t = new_t;
> > +
> > + /* Make sure "32" is before the first '.' if '.' exists. */
> > + if ((s = strchr (str, '.')) != NULL && (t + 2 != s))
> > + {
> > + insn_error = "unrecognized opcode";
> > + return;
> > + }
> > +
> > + /* Make sure "32" is at the end of the name, if no '.'. */
> > + if ((s = strchr (str, '.')) == NULL
> > + && (!ISSPACE (*(t + 2)) && *(t + 2) != '\0'))
> > + {
> > + insn_error = "unrecognized opcode";
> > + return;
> > + }
> > +
> > + micromips_32 = TRUE;
> > + for (s = t + 2; *s != '\0'; ++s)
> > + *(s - 2) = *s;
> > + *(s - 2) = '\0';
> > +
> > + for (s = t; *s != '\0' && !ISSPACE (*s); ++s)
> > + continue;
> > +
> > + if (ISSPACE (*s))
> > + {
> > + save_c = *s;
> > + *s++ = '\0';
> > + }
> > +
> > + if ((insn = (struct mips_opcode *) hash_find
> (micromips_op_hash, str))
> > + == NULL)
> > + {
> > + int i;
> > + int length;
> > + micromips_32 = FALSE;
> > +
> > + /* Restore the character we overwrite above (if any). */
> > + if (save_c)
> > + *(--s) = save_c;
> > +
> > + length = strlen (str);
> > + for (i = length - 1; &str[i] >= t; i--)
> > + {
> > + str[i + 2] = str[i];
> > + if (t == &str[i])
> > + {
> > + str[i + 1] = '2';
> > + str[i] = '3';
> > + str[length + 2] = '\0';
> > + break;
> > + }
> > + }
> > +
> > + insn_error = "unrecognized 32-bit version of
> microMIPS opcode";
> > + return;
> > + }
> >
> > Far too much cut-&-paste between the "16" and "32" cases. Also:
> >
> > + if ((t = strstr (str, "16")) != NULL && t < save_s)
> >
> > t < save_s must surely be true, since save_s is the null terminator.
Yes. I used t < save_s, because I don't know save_s points to NULL at
this point.
We can discard save_s now.
> >
> > + /* Make sure "16" is before the first '.' if '.' exists. */
> > + if ((s = strchr (str, '.')) != NULL && (t + 2 != s))
> > + {
> > + insn_error = "unrecognized opcode";
> > + return;
> > + }
> > +
> > + /* Make sure "16" is at the end of insn name, if no '.'. */
> > + if ((s = strchr (str, '.')) == NULL
> > + && (!ISSPACE (*(t + 2)) && *(t + 2) != '\0'))
> > + {
> > + insn_error = "unrecognized opcode";
> > + return;
> > + }
> >
> > Don't call strchr (str, '.') twice like that. Better would be:
> >
> > s = strchr (str, '.');
Yes.
> >
> > followed by the two checks. Isn't the ISSPACE check
> redundant though,
> > given that you've terminated the string at the first space? I would
> > have thought:
> >
> > if (t + 2 != (s ? s : save_s))
> >
> > would be enough. Errors should start with a capital
> letter. Missing
> > internationalisation.
>
> Chao-ying?
Yes. "if (t + 2 != (s ? s : save_s))" is enough.
>
> > You could use alloca to create an opcode without the "16" or "32",
> > which would make the error-reporting code simpler. It's best not
> > to change the user's source line if we can help it.
>
> Agreed.
Yes.
>
> > + if (!insn_error)
> > + {
> > + static char buf[100];
> > + sprintf (buf,
> > + _("opcode not supported on this
> processor: %s (%s)"),
> > + mips_cpu_info_from_arch
> (mips_opts.arch)->name,
> > + mips_cpu_info_from_isa
> (mips_opts.isa)->name);
> > + insn_error = buf;
> > + }
> > + if (save_c)
> > + *(--s) = save_c;
> > +
> > + if (micromips_16 || micromips_32)
> > + {
> > + int i;
> > + int length;
> > +
> > + length = strlen (str);
> > + for (i = length - 1; i >= 0; i--)
> > + {
> > + str[i + 2] = str[i];
> > + if (t == &str[i])
> > + break;
> > + }
> > + if (micromips_16)
> > + {
> > + insn_error =
> > + "unrecognized 16-bit version of
> microMIPS opcode";
> > + str[i + 1] = '6';
> > + str[i] = '1';
> > + }
> > + else
> > + {
> > + insn_error =
> > + "unrecognized 32-bit version of
> microMIPS opcode";
> > + str[i + 1] = '2';
> > + str[i] = '3';
> > + }
> > + str[length + 2] = '\0';
> > + }
> > + return;
> >
> > Why override the insn_error unconditionally like this? E.g.:
> >
> > jar16 $30,$26
> >
> > Error: unrecognized 16-bit version of microMIPS opcode
> `jar16 $30,$26'
> >
> > implies there's a 32-bit opcode. I'd also have thought that the
> > "opcode not supported on this processor" would triumph if
> it applies.
>
> The error you've seen comes from the previous hunk above
> rather than this
> one which I think is unnecessary code duplication. It's all rather
> over-complicated and I'm working on getting it polished.
> I've fixed this
> piece of code:
>
> .set micromips
> .set noreorder
> bltzall $2, bar
> addiusp 256
>
> producing this nonsense:
>
> bltzall.s: Assembler messages:
> bltzall.s:4: Error: opcode not supported on this processor:
> mips1 (mips1) `addiusp 256'
>
> too. Also the original loop seems ill-formed to me, with
> most of code
> intended to be executed at most once, after the loop's terminating
> condition triggered -- i.e. that shouldn't be in the loop in
> the first
> place.
>
What code in the loop do you refer to? I am not clear.
Thanks for updating the patch!
Regards,
Chao-ying
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS and MCU ASE instruction set support
2010-06-01 14:21 ` Maciej W. Rozycki
` (2 preceding siblings ...)
2010-06-01 22:47 ` Fu, Chao-Ying
@ 2010-06-05 9:17 ` Richard Sandiford
3 siblings, 0 replies; 41+ messages in thread
From: Richard Sandiford @ 2010-06-05 9:17 UTC (permalink / raw)
To: Maciej W. Rozycki
Cc: binutils, Chao-ying Fu, Catherine Moore, Joseph S. Myers,
Daniel Jacobowitz
"Maciej W. Rozycki" <macro@codesourcery.com> writes:
> I'll look into whatever's left yet. Here's the current version for a
> reference, in case you or anyone else wanted to comment on what I have
> modified so far (no obligation, of course!).
OK, finally got chance to have a proper read of the changes from
the previous patch, and they look good, thanks. I'm afraid most
of this is at the level of very minor niggly stuff:
+/* Whether code compression (either of the MIPS16 or the microMIPS ASEs has
s/ASEs has/ASEs) has/
+ if (mips_opts.micromips)
+ return is_micromips_16bit_p (insn->insn_mo)
+ ? 2 : (is_micromips_32bit_p (insn->insn_mo) ? 4 : 6);
This formatting isn't quite right because of the "emacs brackets" rule.
Should be:
return (is_micromips_16bit_p (insn->insn_mo)
? 2 : is_micromips_32bit_p (insn->insn_mo) ? 4 : 6);
or:
return (is_micromips_16bit_p (insn->insn_mo) ? 2
: is_micromips_32bit_p (insn->insn_mo) ? 4 : 6);
But I'd be happy with an if-return-if-return-return chain too.
See below about these insns though...
-+ if (!mips_opts.mips16 && !mips_opts.micromips)
++ if (! HAVE_CODE_COMPRESSION)
The GCC decision a few years back was that no space should be added
after a unary operator (as with pointer deference, etc). Not important
enough to do a sed on the whole source base, but we might as well avoid
changes that go the other way (from no space to space) in GAS.
+static bfd_boolean
+is_size_valid (const struct mips_opcode *mo)
+{
+ gas_assert (mips_opts.micromips);
+
+ if ((micromips_16 || micromips_32) && mo->pinfo == INSN_MACRO)
+ return FALSE;
+ if (micromips_16 && ! is_micromips_16bit_p (mo))
+ return FALSE;
+ if (micromips_32 && ! is_micromips_32bit_p (mo))
+ return FALSE;
+
+ return TRUE;
+}
Hmm, seeing this highlighted more makes me wonder whether
micromips_16 and micromips_32 shouldn't be combined into a
single variable that represents "the size the user set",
with 0 meaning "none". As it stands, we'll have checks like:
micromips_16 || micromips_32 || micromips_48
when any future 48-bit support is added. Having separate variables
also gives the impression that arbitrary combinations are possible.
Also, how about replacing is_micromips_XXbit_p with a function
that just returns the size of a micromips insn? We generally
deal with byte rather than bit lengths, so both this new function
and the combined "the size the user set" variable should probably
both be byte values.
Seems the code would be a fair bit clearer with those changes,
but maybe I'm wrong...
Maybe the mo->match assertions in is_micromips_XXbit_p are better
done in validate_micromips_insn -- especially if that makes the
changes above easier -- but I don't mind either way.
char
mips_nop_opcode (void)
{
if (seg_info (now_seg)->tc_segment_info_data.micromips)
return NOP_OPCODE_MICROMIPS;
return seg_info (now_seg)->tc_segment_info_data.mips16
? NOP_OPCODE_MIPS16 : NOP_OPCODE_MIPS;
}
Same "emacs brackets" thing here. Seems odd to treat microMIPS and MIPS16
differently like this, so I think if-return-if-return-return makes more
sense.
The new mips_handle_align looks very good, thanks. I'm afraid it's another
silly nitpick, but usual style is not to have the brackets in "*(p++)".
Richard
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2010-05-23 21:38 ` Richard Sandiford
2010-05-24 22:25 ` Fu, Chao-Ying
2010-06-01 14:21 ` Maciej W. Rozycki
@ 2010-07-26 10:56 ` Maciej W. Rozycki
2010-07-26 13:25 ` Nathan Froyd
2010-07-26 19:03 ` Richard Sandiford
2 siblings, 2 replies; 41+ messages in thread
From: Maciej W. Rozycki @ 2010-07-26 10:56 UTC (permalink / raw)
To: Richard Sandiford
Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers,
Nathan Froyd
[-- Attachment #1: Type: TEXT/PLAIN, Size: 99320 bytes --]
Hi Richard,
I'm combining a couple of e-mails together, quotations may come from
various people -- hopefully no one will get lost and hopefully I haven't
missed anything. ;) [FIXME] are my annotations for future reference.
NathanF, there's a QEMU question somewhere down the e-mail -- would you
care to answer it?
> > > > (A_BFD_RELOC_HI16_S, A_BFD_RELOC_HI16, A_BFD_RELOC_LO16): New
> > > > relocation wrapper macros.
> > > > (A_BFD_RELOC_GPREL16): Likewise.
> > > > (A_BFD_RELOC_MIPS_GOT16, A_BFD_RELOC_MIPS_GOT_HI16): Likewise.
> > > > (A_BFD_RELOC_MIPS_GOT_LO16, A_BFD_RELOC_MIPS_HIGHEST): Likewise.
> > > > (A_BFD_RELOC_MIPS_HIGHER, A_BFD_RELOC_MIPS_GOT_DISP): Likewise.
> > > > (A_BFD_RELOC_MIPS_GOT_PAGE, A_BFD_RELOC_MIPS_GOT_OFST):
> > Likewise.
> > > > (A_BFD_RELOC_MIPS_SUB, A_BFD_RELOC_MIPS_JALR): Likewise.
> > >
> > > Did you consider doing the translation from non-microMIPS to
> > > microMIPS in the macro_* functions, rather than in their callers?
> > > I fear it'll be too easy to accidentally forget to use
> > A_BFD_* in future.
> >
> > Agreed, I didn't like the new macros from the very
> > beginning. Chao-ying
> > -- any thoughts?
>
> I am fine. But the new method may be bigger than the A_BFD* method.
I have placed the translation in macro_map_reloc() now. That incurs an
O(n) performance penalty because all relocations in the microMIPS mode
have to be iterated over the table of mappings; regrettably BFD_RELOC_*
definitions are sparse so an O(1) lookup table cannot be used. By keeping
it sorted some time can be saved, but that's still O(n). This could be
reduced to O(log n) with a binary search, but I fear with the limited
number of relocs handled the overhead would kill the benefit.
And macro_build_jalr() and macro_build_lui() handle the stuff explicitly
now.
> > (MICROMIPS_TARGET, MICROMIPS_TARGET_LABEL): New macros.
> > (micromips_add_number_label): New function.
>
> +/* For microMIPS macros, we need to generate a local number label
> + as the target of branches. */
> +#define MICROMIPS_TARGET "2147483647f"
> +#define MICROMIPS_TARGET_LABEL 2147483647
> +
> +static void
> +micromips_add_number_label (void)
> +{
> + symbolS *s;
> + fb_label_instance_inc (MICROMIPS_TARGET_LABEL);
> + s = colon (fb_label_name (MICROMIPS_TARGET_LABEL, 0));
> + S_SET_OTHER (s, ELF_ST_SET_MICROMIPS (S_GET_OTHER (s)));
> +}
> +
>
> Ugh, this is a bit hackish. There's nothing stopping a user using
> 2147483647f themselves.
This is now handled by micromips_label_name(), micromips_label_expr(),
micromips_label_inc() and micromips_add_label() in a manner similar to
what dollar_label_name() and fb_label_name(), etc. do, except that the
special character used in symbols generated is ^_, avoiding a clash.
> > > > (macro_start, macro_warning, macro_end): Likewise.
> > >
> > > + else if ((subtype & RELAX_DELAY_SLOT_SIZE_ERROR_FIRST)
> > > + || (subtype & RELAX_DELAY_SLOT_SIZE_ERROR_SECOND))
> > > + return _("Macro instruction of the wrong size in a
> > branch delay slot"
> > > + " that requires a 16-bit or 32-bit instruction");
> > >
> > > Did you consider adding a flag to distinguish the 32-bit
> > and 16-bit cases?
> > > It'd be nice to be consistent with the non-relaxed error if
> > possible.
> >
> > Chao-ying? I've had a look actually and flag may not be
> > necessary to get
> > the functionality. I'm fixing this up elsewhere already.
>
> I am fine with this functionality. Maybe passing one more parameter to
> macro_warning() can help to distinguish two cases.
Done now. I have added RELAX_DELAY_SLOT_16BIT now.
OTOH, I don't think it is possible to get a macro to expand into a single
16-bit instruction that would be unsuitable for a 32-bit delay slot -- all
the 16-bit instructions that can be emitted by macros this way have a
32-bit counterpart that will be used instead. I think the extra message
is good for sanity though or in case things change in the future.
> > > + /* If either one implementation contains one
> > instruction, we need to check
> > > + the delay slot size requirement. */
> > > + if (mips_macro_warning.num_insns[0] == 1
> > > + || mips_macro_warning.num_insns[1] == 1)
> > > + {
> > > + if (mips_macro_warning.num_insns[0] ==
> > mips_macro_warning.num_insns[1]
> > > + && mips_macro_warning.sizes[0] == mips_macro_warning.sizes[1])
> > > + {
> > > + /* Either the macro has a single implementation or both
> > > + implementations are 1 instruction with the same size.
> > > + Emit the warning now. */
> > > + if ((mips_macro_warning.delay_slot_16bit_p
> > > + && mips_macro_warning.sizes[0] != 2)
> > > + || (mips_macro_warning.delay_slot_32bit_p
> > > + && mips_macro_warning.sizes[0] != 4))
> > > + {
> > > + const char *msg;
> > > + msg = macro_warning (RELAX_DELAY_SLOT_SIZE_ERROR_FIRST);
> > > + if (msg != 0)
> > > + as_warn (msg);
> > > + }
> > > + }
> > > + else
> > > + {
> > > + relax_substateT subtype;
> > > +
> > > + /* Set up the relaxation warning flags. */
> > > + subtype = 0;
> > > + if (mips_macro_warning.delay_slot_16bit_p)
> > > + {
> > > + if (mips_macro_warning.num_insns[0] != 1
> > > + || mips_macro_warning.sizes[0] != 2)
> > > + subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
> > > + if (mips_macro_warning.num_insns[1] != 1
> > > + || mips_macro_warning.sizes[1] != 2)
> > > + subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
> > > + }
> > > + if (mips_macro_warning.delay_slot_32bit_p)
> > > + {
> > > + if (mips_macro_warning.num_insns[0] != 1
> > > + || mips_macro_warning.sizes[0] != 4)
> > > + subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
> > > + if (mips_macro_warning.num_insns[1] != 1
> > > + || mips_macro_warning.sizes[1] != 4)
> > > + subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
> > > + }
> > > +
> > > + /* One implementation might need a warning but the other
> > > + definitely doesn't. */
> > > + mips_macro_warning.first_frag->fr_subtype |= subtype;
> > > + }
> > > + }
> > >
> > > Why not work out the subtype, then check whether both
> > ERROR_FIRST and
> > > ERROR_SECOND are set?
> >
> > Chao-ying?
>
> Do you mean this kind of code?
> Ex:
> if (mips_macro_warning.num_insns[0] == 1
> || mips_macro_warning.num_insns[1] == 1)
> {
> if (mips_macro_warning.delay_slot_16bit_p)
> {
> if (mips_macro_warning.num_insns[0] != 1
> || mips_macro_warning.sizes[0] != 2)
> subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
> if (mips_macro_warning.num_insns[1] != 1
> || mips_macro_warning.sizes[1] != 2)
> subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
> }
> else if (mips_macro_warning.delay_slot_32bit_p)
> {
> if (mips_macro_warning.num_insns[0] != 1
> || mips_macro_warning.sizes[0] != 4)
> subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
> if (mips_macro_warning.num_insns[1] != 1
> || mips_macro_warning.sizes[1] != 4)
> subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
> }
>
> if ((subtype & RELAX_DELAY_SLOT_SIZE_ERROR_FIRST)
> && (subtype & RELAX_DELAY_SLOT_SIZE_ERROR_SECOND))
> {
> const char *msg;
> msg = macro_warning (RELAX_DELAY_SLOT_SIZE_ERROR_FIRST); //
> NEED TO PASS 16-bit or 32-bit info
> if (msg != 0)
> as_warn (msg);
> }
> else
> {
> /* One implementation might need a warning but the other
> definitely doesn't. */
> mips_macro_warning.first_frag->fr_subtype |= subtype;
> }
> }
>
> >
> > > + if (mips_macro_warning.delay_slot_p)
> > > + {
> > > + if (mips_macro_warning.num_insns[0] > 1)
> > > + subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_FIRST;
> > > + if (mips_macro_warning.num_insns[1] > 1)
> > > + subtype |= RELAX_DELAY_SLOT_SIZE_ERROR_SECOND;
> > > + }
> > >
> > > I don't get why this hunk is needed. I thought ERROR_FIRST
> > and ERROR_SECOND
> > > controlled cases where a macro has a single-insn expansion
> > that is the
> > > wrong size, which ought to be handled by the block above.
> > If the code
> > > really is needed, you should add a comment explaining why.
> >
> > Chao-ying?
>
>
> I agree. The delay_slot_p check is duplicated, and we can discard it
> for
> ERROR_FIRST and ERROR_SECOND when num_insns[]>1. My old code
> double-checked the condition for
> number of instructions in delay slots.
I have rewritten macro_end() entirely now. I have changed the approach
such that if multiple instructions are emitted into a branch delay slot
and the first of these instructions is out of size, then two warnings are
produced.
The rationale is these are different classes of warnings -- the delay
slot size mismatch is fatal if the call is ever returned from. Multiple
instructions may or may not be a problem depending on the actual piece of
code and author's intentions. We had a discussion about it a few years
ago. ;)
To complete these changes I have modified the change to append_insn()
such that no warning is produced for a delay slot size mismatch if called
for a macro expansion as it would get in the way, especially in the case
of relaxation. The API of this function had to be modified in a trivial
way and all the callers adjusted accordingly.
> > > > (macro_build): Likewise.
> > >
> > > + if (mips_opts.micromips)
> > > + {
> > > + if (strcmp (name, "lui") == 0)
> > > + micromips_macro_build (ep, name, "s,u", args);
> > > + else if (strcmp (fmt, "d,w,<") == 0)
> > > + micromips_macro_build (ep, name, "t,r,<", args);
> > > + else
> > > + micromips_macro_build (ep, name, fmt, args);
> > > + va_end (args);
> > > + return;
> > > + }
> > >
> > > A bit of commentary might help explain the letter switch here.
> >
> > Chao-ying?
>
> Because I didn't change all the code before calling LUI macro for
> microMIPS, I need
> to magically change the operand string for microMIPS to use "s,u" for
> microMIPS LUI.
> "d,w,<" is another case that we need to map it to "t,r,<" for microMIPS.
> If we can search all the places and replace all calls with correct
> operand strings for microMIPS,
> this special code can be dropped.
I have fixed it up now with the introduction of lui_fmt[] and shft_fmt[].
> > > > (macro_build_jalr): Likewise.
> > >
> > > + if (mips_opts.micromips)
> > > + {
> > > + if (HAVE_NEWABI)
> > > + macro_build (NULL, "jalr", "t,s", RA, PIC_CALL_REG);
> > > + else
> > > + macro_build (NULL, "jalr", "mj", PIC_CALL_REG);
> > > + }
> > > + else
> > > + macro_build (NULL, "jalr", "d,s", RA, PIC_CALL_REG);
> > >
> > > Why HAVE_NEWABI? Do you want a 32-bit insn for R_MIPS_JALR?
> > > If so, you should check MIPS_JALR_HINT_P (ep) instead.
> >
> > Chao-ying?
>
> OK. This code is done before I put the R_MIPS_JALR patch into GAS and
> LD.
> The new code is as follows.
> Ex:
> static void
> macro_build_jalr (expressionS *ep)
> {
> char *f = NULL;
>
> if (MIPS_JALR_HINT_P (ep))
> {
> frag_grow (8);
> f = frag_more (0);
> }
> if (mips_opts.micromips)
> macro_build (NULL, "jalr", "t,s", RA, PIC_CALL_REG);
> else
> macro_build (NULL, "jalr", "d,s", RA, PIC_CALL_REG);
> if (MIPS_JALR_HINT_P (ep))
> fix_new_exp (frag_now, f - frag_now->fr_literal,
> 4, ep, FALSE, A_BFD_RELOC_MIPS_JALR); // THIS MAY BE
> FIXED BY A NEW METHOD.
> }
>
> And, we need to modify elfxx-mips.c to support
> BFD_RELOC_MICROMIPS_JALR to convert jalr to bal for microMIPS.
Per your suggestion, I have made this piece use MIPS_JALR_HINT_P() to
select the jump now. Also since for PIC the delay slot is always a NOP in
the reorder mode, I switched to the use of JALRS in this case.
> + case BFD_RELOC_MICROMIPS_7_PCREL_S1:
> + case BFD_RELOC_MICROMIPS_10_PCREL_S1:
> + case BFD_RELOC_MICROMIPS_16_PCREL_S1:
> + /* We adjust the offset back to even. */
> + if ((*valP & 0x1) != 0)
> + --(*valP);
> +
> + if (! fixP->fx_done)
> + break;
> +
> + /* Should never visit here, because we keep the relocation. */
> + abort ();
> + break;
>
> I suppose this silently ignores branches to non-microMIPS code,
> but there again, so does the MIPS16 equivalent...
As noted previously, some diagnostics would be useful, but let's call it
a future enhancement. [FIXME]
> >> > (mips_relax_frag): Handle microMIPS.
> >>
> >> + gas_assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2
> >> + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
> >> + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1
> >> + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1);
> >> +
> >> + /* For 7/10 PCREL_S1, we just need to use
> >> fixp->fx_addnumber. */
> >> + if (fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
> >> + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1)
> >> + reloc->addend = fixp->fx_addnumber;
> >> + else
> >> + /* At this point, fx_addnumber is "symbol offset -
> >> pcrel address".
> >> + Relocations want only the symbol offset. */
> >> + reloc->addend = fixp->fx_addnumber + reloc->address;
> >>
> >> A better comment is needed. _Why_ do you just need fx_addnumber?
> >>
> >
> > Thanks for the review! The explanation is in another place as
> > follows.
> > Maybe we need to copy the comment to tc_gen_reloc from md_pcrel_from.
> > Ex:
> > long
> > md_pcrel_from (fixS *fixP)
> > {
> > valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
> > switch (fixP->fx_r_type)
> > {
> > /* We don't add addr, because it will cause the error checking of
> > "addnumber" fail in write.c for *7/10_PCREL_S1.
> > In tc_gen_reloc, we just use fixp->fx_addnumber. */
> > case BFD_RELOC_MICROMIPS_7_PCREL_S1:
> > case BFD_RELOC_MICROMIPS_10_PCREL_S1:
> > /* Return the beginning of the delay slot from the current insn.
> > */
> > return 2;
> >
> > case BFD_RELOC_MICROMIPS_16_PCREL_S1:
> > case BFD_RELOC_MICROMIPS_JMP:
> > case BFD_RELOC_16_PCREL_S2:
> > case BFD_RELOC_MIPS_JMP:
> > /* Return the address of the delay slot. */
> > return addr + 4;
> > ...
> > The field of *7/10_PCREL_S1 is limited in the 16-bit instructions.
> > If we add the "address", write.c will fail to check these two
> > relocations due to overflow or something (I kind of forgot). From
> > debugging, adding "address" is no use at all, because later "address" is
> > subtracted.
>
> Ah, thanks, that's a good explanation. Yeah, at least a cross-reference
> would be useful if we keep things as they are. However...
>
> ...I think you mean this bit of write.c:
>
> if (fixP->fx_size < sizeof (valueT) && 0)
> {
> valueT mask;
>
> mask = 0;
> mask--; /* Set all bits to one. */
> mask <<= fixP->fx_size * 8 - (fixP->fx_signed ? 1 : 0);
> if ((add_number & mask) != 0 && (add_number & mask) != mask)
> {
> char buf[50], buf2[50];
> sprint_value (buf, fragP->fr_address + fixP->fx_where);
> if (add_number > 1000)
> sprint_value (buf2, add_number);
> else
> sprintf (buf2, "%ld", (long) add_number);
> as_bad_where (fixP->fx_file, fixP->fx_line,
> _("value of %s too large for field of %d bytes
> at %s"),
> buf2, fixP->fx_size, buf);
> } /* Generic error checking. */
> }
>
> That check's bogus for these relocations anyway, since it doesn't take
> the implied shift into account. I think there's an argument to say
> we should set fx_no_overflow for these relocations and leave the
> overflow checking to bfd. You'll still get a "relocation overflow"
> error if the final in-place addend really is too big.
After some investigation I decided to follow your suggestion. I have
removed this change and the corresponding one from tc_gen_reloc() and
adjusted md_convert_frag() instead.
My general conclusion is fixup_segment() code fragment you quoted is
essentially broken and has to be rewritten. For the MIPS target it works
by chance and does not perform any useful check. It shouldn't be checking
the size of the data chunk being relocated, but the size of the
relocatable field only and take the shift value into account. This is all
available from the associated HOWTO structure that can be easily obtained
here.
> > > > (md_convert_frag): Likewise.
> > >
> > > - /* Possibly emit a warning if we've chosen the
> > longer option. */
> > > - if (((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
> > > - == ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))
> > > + if (!(fragp->fr_subtype & RELAX_USE_SECOND))
> > > + {
> > > + /* Check if the size in branch delay slot is ok. */
> > > + if (fragp->fr_subtype & RELAX_DELAY_SLOT_SIZE_ERROR_FIRST)
> > > + {
> > > + const char *msg = macro_warning (fragp->fr_subtype);
> > > + if (msg != 0)
> > > + as_warn_where (fragp->fr_file, fragp->fr_line, msg);
> > > + }
> > > + }
> > > + else
> > > {
> > > - const char *msg = macro_warning (fragp->fr_subtype);
> > > - if (msg != 0)
> > > - as_warn_where (fragp->fr_file, fragp->fr_line, "%s", msg);
> > > + /* Check if the size in branch delay slot is ok.
> > > + Possibly emit a warning if we've chosen the longer
> > option. */
> > > + if ((fragp->fr_subtype & RELAX_DELAY_SLOT_SIZE_ERROR_SECOND)
> > > + || (fragp->fr_subtype & RELAX_SECOND_LONGER))
> > > + {
> > > + const char *msg = macro_warning (fragp->fr_subtype);
> > > + if (msg != 0)
> > > + as_warn_where (fragp->fr_file, fragp->fr_line, msg);
> > > + }
> > > }
> > >
> > > This doesn't accurately preserve the previous:
> > >
> > > if (((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
> > > == ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))
> > >
> > > behaviour.
> >
> > Chao-ying?
>
> How about this?
>
> Ex:
>
> if ((((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
> == ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))
> || (!(fragp->fr_subtype & RELAX_USE_SECOND)
> && (fragp->fr_subtype &
> RELAX_DELAY_SLOT_SIZE_ERROR_FIRST))
> || ((fragp->fr_subtype & RELAX_USE_SECOND)
> && (fragp->fr_subtype &
> RELAX_DELAY_SLOT_SIZE_ERROR_SECOND)))
> {
> const char *msg = macro_warning (fragp->fr_subtype); // MAY
> NEED TO PASS 16-bit or 32-bit info
> if (msg != 0)
> as_warn_where (fragp->fr_file, fragp->fr_line, "%s", msg);
> }
I have rewritten it entirely now, matching changes to macro_end(). Two
warnings are emitted if multiple instructions are emitted into a branch
delay slot and the first of these instruction is out of size like with
macro_end().
> > > > (micromips_ip): New function.
> > >
> > > + /* Try to search "16" or "32" in the str. */
> > > + if ((t = strstr (str, "16")) != NULL && t < save_s)
> > > + {
> > > + /* Make sure "16" is before the first '.' if '.' exists. */
> > > + if ((s = strchr (str, '.')) != NULL && (t + 2 != s))
> > > + {
> > > + insn_error = "unrecognized opcode";
> > > + return;
> > > + }
> > > +
> > > + /* Make sure "16" is at the end of insn name, if no '.'. */
> > > + if ((s = strchr (str, '.')) == NULL
> > > + && (!ISSPACE (*(t + 2)) && *(t + 2) != '\0'))
> > > + {
> > > + insn_error = "unrecognized opcode";
> > > + return;
> > > + }
> > > +
> > > + micromips_16 = TRUE;
> > > + for (s = t + 2; *s != '\0'; ++s)
> > > + *(s - 2) = *s;
> > > + *(s - 2) = '\0';
> > > +
> > > + for (s = t; *s != '\0' && !ISSPACE (*s); ++s)
> > > + continue;
> > > +
> > > + if (ISSPACE (*s))
> > > + {
> > > + save_c = *s;
> > > + *s++ = '\0';
> > > + }
> > > +
> > > + if ((insn = (struct mips_opcode *) hash_find
> > (micromips_op_hash, str))
> > > + == NULL)
> > > + {
> > > + int i;
> > > + int length;
> > > + micromips_16 = FALSE;
> > > +
> > > + /* Restore the character we overwrite above (if any). */
> > > + if (save_c)
> > > + *(--s) = save_c;
> > > +
> > > + length = strlen (str);
> > > + for (i = length - 1; &str[i] >= t; i--)
> > > + {
> > > + str[i + 2] = str[i];
> > > + if (t == &str[i])
> > > + {
> > > + str[i + 1] = '6';
> > > + str[i] = '1';
> > > + str[length + 2] = '\0';
> > > + break;
> > > + }
> > > + }
> > > +
> > > + insn_error = "unrecognized 16-bit version of
> > microMIPS opcode";
> > > + return;
> > > + }
> > > + }
> > > + else if ((t = strstr (str, "32")) != NULL && t < save_s)
> > > + {
> > > + /* For some instruction names, we already have 32, so we need
> > > + to seek the second 32 to process. Ex: bposge3232,
> > dsra3232. */
> > > + char *new_t;
> > > + if ((new_t = strstr (t + 2, "32")) != NULL && new_t < save_s)
> > > + t = new_t;
> > > +
> > > + /* Make sure "32" is before the first '.' if '.' exists. */
> > > + if ((s = strchr (str, '.')) != NULL && (t + 2 != s))
> > > + {
> > > + insn_error = "unrecognized opcode";
> > > + return;
> > > + }
> > > +
> > > + /* Make sure "32" is at the end of the name, if no '.'. */
> > > + if ((s = strchr (str, '.')) == NULL
> > > + && (!ISSPACE (*(t + 2)) && *(t + 2) != '\0'))
> > > + {
> > > + insn_error = "unrecognized opcode";
> > > + return;
> > > + }
> > > +
> > > + micromips_32 = TRUE;
> > > + for (s = t + 2; *s != '\0'; ++s)
> > > + *(s - 2) = *s;
> > > + *(s - 2) = '\0';
> > > +
> > > + for (s = t; *s != '\0' && !ISSPACE (*s); ++s)
> > > + continue;
> > > +
> > > + if (ISSPACE (*s))
> > > + {
> > > + save_c = *s;
> > > + *s++ = '\0';
> > > + }
> > > +
> > > + if ((insn = (struct mips_opcode *) hash_find
> > (micromips_op_hash, str))
> > > + == NULL)
> > > + {
> > > + int i;
> > > + int length;
> > > + micromips_32 = FALSE;
> > > +
> > > + /* Restore the character we overwrite above (if any). */
> > > + if (save_c)
> > > + *(--s) = save_c;
> > > +
> > > + length = strlen (str);
> > > + for (i = length - 1; &str[i] >= t; i--)
> > > + {
> > > + str[i + 2] = str[i];
> > > + if (t == &str[i])
> > > + {
> > > + str[i + 1] = '2';
> > > + str[i] = '3';
> > > + str[length + 2] = '\0';
> > > + break;
> > > + }
> > > + }
> > > +
> > > + insn_error = "unrecognized 32-bit version of
> > microMIPS opcode";
> > > + return;
> > > + }
> > >
> > > Far too much cut-&-paste between the "16" and "32" cases. Also:
> > >
> > > + if ((t = strstr (str, "16")) != NULL && t < save_s)
> > >
> > > t < save_s must surely be true, since save_s is the null terminator.
>
> Yes. I used t < save_s, because I don't know save_s points to NULL at
> this point.
> We can discard save_s now.
>
> > >
> > > + /* Make sure "16" is before the first '.' if '.' exists. */
> > > + if ((s = strchr (str, '.')) != NULL && (t + 2 != s))
> > > + {
> > > + insn_error = "unrecognized opcode";
> > > + return;
> > > + }
> > > +
> > > + /* Make sure "16" is at the end of insn name, if no '.'. */
> > > + if ((s = strchr (str, '.')) == NULL
> > > + && (!ISSPACE (*(t + 2)) && *(t + 2) != '\0'))
> > > + {
> > > + insn_error = "unrecognized opcode";
> > > + return;
> > > + }
> > >
> > > Don't call strchr (str, '.') twice like that. Better would be:
> > >
> > > s = strchr (str, '.');
>
> Yes.
>
> > >
> > > followed by the two checks. Isn't the ISSPACE check
> > redundant though,
> > > given that you've terminated the string at the first space? I would
> > > have thought:
> > >
> > > if (t + 2 != (s ? s : save_s))
> > >
> > > would be enough. Errors should start with a capital
> > letter. Missing
> > > internationalisation.
> >
> > Chao-ying?
>
> Yes. "if (t + 2 != (s ? s : save_s))" is enough.
>
> >
> > > You could use alloca to create an opcode without the "16" or "32",
> > > which would make the error-reporting code simpler. It's best not
> > > to change the user's source line if we can help it.
> >
> > Agreed.
>
> Yes.
>
> >
> > > + if (!insn_error)
> > > + {
> > > + static char buf[100];
> > > + sprintf (buf,
> > > + _("opcode not supported on this
> > processor: %s (%s)"),
> > > + mips_cpu_info_from_arch
> > (mips_opts.arch)->name,
> > > + mips_cpu_info_from_isa
> > (mips_opts.isa)->name);
> > > + insn_error = buf;
> > > + }
> > > + if (save_c)
> > > + *(--s) = save_c;
> > > +
> > > + if (micromips_16 || micromips_32)
> > > + {
> > > + int i;
> > > + int length;
> > > +
> > > + length = strlen (str);
> > > + for (i = length - 1; i >= 0; i--)
> > > + {
> > > + str[i + 2] = str[i];
> > > + if (t == &str[i])
> > > + break;
> > > + }
> > > + if (micromips_16)
> > > + {
> > > + insn_error =
> > > + "unrecognized 16-bit version of
> > microMIPS opcode";
> > > + str[i + 1] = '6';
> > > + str[i] = '1';
> > > + }
> > > + else
> > > + {
> > > + insn_error =
> > > + "unrecognized 32-bit version of
> > microMIPS opcode";
> > > + str[i + 1] = '2';
> > > + str[i] = '3';
> > > + }
> > > + str[length + 2] = '\0';
> > > + }
> > > + return;
> > >
> > > Why override the insn_error unconditionally like this? E.g.:
> > >
> > > jar16 $30,$26
> > >
> > > Error: unrecognized 16-bit version of microMIPS opcode
> > `jar16 $30,$26'
> > >
> > > implies there's a 32-bit opcode. I'd also have thought that the
> > > "opcode not supported on this processor" would triumph if
> > it applies.
> >
> > The error you've seen comes from the previous hunk above
> > rather than this
> > one which I think is unnecessary code duplication. It's all rather
> > over-complicated and I'm working on getting it polished.
I have rewritten it from scratch using alloca() as you suggested and
reducing the whole stuff to a small loop executed once or twice. This
enabled chunks of code to be shaved off elsewhere too.
Your JAR16 case is now handled correctly and I have put together test
cases to cover some of this stuff, hopefully exhaustively.
> > too. Also the original loop seems ill-formed to me, with
> > most of code
> > intended to be executed at most once, after the loop's terminating
> > condition triggered -- i.e. that shouldn't be in the loop in
> > the first
> > place.
>
> What code in the loop do you refer to? I am not clear.
One that follows "argsStart = s". My conclusion turned out unjustified
as there are "continue" statements throughout -- I got confused, sorry.
> > * ld-mips-elf/jalx-2-main.s: New.
> > * ld-mips-elf/jalx-2.dd: New.
> > * ld-mips-elf/jalx-2-ex.s: New.
> > * ld-mips-elf/jalx-2-printf.s: New.
> > * ld-mips-elf/mips-elf.exp: Run new test.
>
> Please make the .dd output less susceptible to things like the number
> of sections, size of program headers, etc. One way is to use a linker
> script to place each section at a nice round address. Another is to
> ".*" out the addresses and instruction encodings and just reply on
> the symbolic part of the disassembly. I think the former's better
> here. There are quite a few existing examples.
Fixed by Catherine -- thanks!
> > Stricly speaking some changes, while related, can be split off too (e.g.
> > some MIPS16 or testsuite changes), so I'll look into separating them too
> > -- perhaps that'll make the thing rolling sooner.
>
> Yeah, thanks, that'd be a help if it's easy to do. It doesn't matter
> too much, though. Most of the MIPS16 changes were consistent with the
> microMIPS ones, so were easy to review as a unit.
I was more concerned about grouping functionally independent changes
together. While it may be OK for the review, it often bites later on,
when someone makes excavations on the repository trying to figure out the
original change.
Anyway I did that as you know and it helped with the PIC JAL changes.
> >> From a usability perspective, it's a shame that:
> >>
> >> .set micromips
> >> .ent foo
> >> foo:
> >> b 1f
> >> nop
> >> .end foo
> >> .ent bar
> >> bar:
> >> 1: nop
> >> .end bar
> >>
> >> disassembles as:
> >>
> >> 00000000 <foo>:
> >> 0: cfff b 0 <foo>
> >> 0: R_MICROMIPS_PC10_S1 .L11
> >> 2: 0c00 nop
> >> 4: 0c00 nop
> >>
> >> 00000006 <bar>:
> >> 6: 0c00 nop
> >>
> >> leaving the poor user with no idea what .L11 is.
> >
> > Indeed. This is a general limitation of `objdump' it would seem. This
> > is no different to what you get with:
> >
> > $ cat b.s
> > .globl baz
> > .ent foo
> > foo:
> > b baz
> > nop
> > .end foo
> > .ent bar
> > baz:
> > bar:
> > 1: nop
> > .end bar
> > $ mips-sde-elf-objdump -dr b.o
> >
> > b.o: file format elf32-tradbigmips
> >
> >
> > Disassembly of section .text:
> >
> > 00000000 <foo>:
> > 0: 1000ffff b 0 <foo>
> > 0: R_MIPS_PC16 baz
> > 4: 00000000 nop
> > 8: 00000000 nop
> >
> > 0000000c <bar>:
> > c: 00000000 nop
>
> Well, it's a little different. The user has at least defined two
> named symbols in this case, so they have a good chance of knowing
> what "baz" means. In the microMIPS case we've invented a label
> and are using it in preference to the user-defined one.
That's unfortunate, indeed. [FIXME]
> > I'd just recommend peeking at the symbol table (back to the first
> > program):
> >
> > $ mips-sde-elf-objdump -t b.o
> >
> > b.o: file format elf32-tradbigmips
> >
> > SYMBOL TABLE:
> > 00000000 l d .text 00000000 .text
> > 00000000 l d .data 00000000 .data
> > 00000000 l d .bss 00000000 .bss
> > 00000000 l d .reginfo 00000000 .reginfo
> > 00000000 l d .pdr 00000000 .pdr
> > 00000000 l F .text 00000006 0x80 foo
> > 00000006 l F .text 00000002 0x80 bar
> > 00000006 l .text 00000000 0x80 .L1^B1
>
> I suppose having a symbol with ^B in it is less than ideal too.
> AIUI that name was chosen specifically because it wasn't supposed
> to be written out.
>
> It would be especially confusing if the user or compiler had a ".L11"
> label (without the ^B).
Actually this is a tough problem -- we need to emit a generated symbol
that does not clash with anything the user or GCC may have put in the
source. Any ideas? How is it done in other ports if anywhere?
> >> The following:
> >>
> >> .set micromips
> >> .ent foo
> >> foo:
> >> ld $10,0x1000($11)
> >> .end foo
> >>
> >> generates an assertion failure:
> >>
> >> Assertion failure in micromips_macro_build at gas/config/tc-mips.c line
> 19466.
> >> Please report this bug.
> >>
> >> on mipsisa64-elf with "-mips1 -mabi=32".
> >
> > I can't reproduce it, sorry:
> > [...]
> > Can you debug it and see what the relocation type is that's causing it?
> > I wonder if that might be related to the varargs issue you referring to
> > below and depend on the host architecture, hmm...
>
> Yeah, you're right, sorry. I forgot to mention that in the later reviews.
> This was with a x86_64-linux-gnu host and a botched attempt at working
> around the varags issue. (I probably just added -Wno-error or something,
> I can't remember now.)
>
> I switched to a 32-bit host for parts 2 and 3 of the review, and yeah,
> it doesn't reproduce there.
I have updated this code to pass varargs by a reference. Note that
mips16_macro_build() also attempts to pass them by value which I gather
from some discussions I have tracked down is a grey area of the C language
standard. Sent as separate patch.
> +/* Whether code compression (either of the MIPS16 or the microMIPS ASEs has
>
> s/ASEs has/ASEs) has/
Fixed.
> + if (mips_opts.micromips)
> + return is_micromips_16bit_p (insn->insn_mo)
> + ? 2 : (is_micromips_32bit_p (insn->insn_mo) ? 4 : 6);
>
> This formatting isn't quite right because of the "emacs brackets" rule.
Yeah, now that you mention it, I seem to recall there was something like
this...
> Should be:
>
> return (is_micromips_16bit_p (insn->insn_mo)
> ? 2 : is_micromips_32bit_p (insn->insn_mo) ? 4 : 6);
>
> or:
>
> return (is_micromips_16bit_p (insn->insn_mo) ? 2
> : is_micromips_32bit_p (insn->insn_mo) ? 4 : 6);
Fixed.
> But I'd be happy with an if-return-if-return-return chain too.
Conditional expressions seem to go with the spirit of this function. ;)
> See below about these insns though...
> -+ if (!mips_opts.mips16 && !mips_opts.micromips)
> ++ if (! HAVE_CODE_COMPRESSION)
>
> The GCC decision a few years back was that no space should be added
> after a unary operator (as with pointer deference, etc). Not important
> enough to do a sed on the whole source base, but we might as well avoid
> changes that go the other way (from no space to space) in GAS.
I didn't know it was standardised at one point. The justification for my
style is the exclamation mark may easily be missed by the reader if next
to a bracket (and she happens not to be eagle-eyed), but I have adjusted
changes accordingly now.
> +static bfd_boolean
> +is_size_valid (const struct mips_opcode *mo)
> +{
> + gas_assert (mips_opts.micromips);
> +
> + if ((micromips_16 || micromips_32) && mo->pinfo == INSN_MACRO)
> + return FALSE;
> + if (micromips_16 && ! is_micromips_16bit_p (mo))
> + return FALSE;
> + if (micromips_32 && ! is_micromips_32bit_p (mo))
> + return FALSE;
> +
> + return TRUE;
> +}
>
> Hmm, seeing this highlighted more makes me wonder whether
> micromips_16 and micromips_32 shouldn't be combined into a
> single variable that represents "the size the user set",
> with 0 meaning "none". As it stands, we'll have checks like:
>
> micromips_16 || micromips_32 || micromips_48
>
> when any future 48-bit support is added. Having separate variables
> also gives the impression that arbitrary combinations are possible.
Good point. I have merged these with mips16_small and mips16_ext and
replaced all of them with forced_insn_length.
> Also, how about replacing is_micromips_XXbit_p with a function
> that just returns the size of a micromips insn? We generally
> deal with byte rather than bit lengths, so both this new function
> and the combined "the size the user set" variable should probably
> both be byte values.
FYI, that's what I did when implementing GDB support (that'll follow
sometime in the future; obviously it depends on some changes to BFD and
opcode made here), so I see no reason why we shouldn't do that here
either, good point. I have merged these into micromips_insn_length() now.
> Seems the code would be a fair bit clearer with those changes,
> but maybe I'm wrong...
No, not a sausage. ;)
> Maybe the mo->match assertions in is_micromips_XXbit_p are better
> done in validate_micromips_insn -- especially if that makes the
> changes above easier -- but I don't mind either way.
Not necessarily any easier for micromips_insn_length(), but it looks like
the right place for these tests, so I moved them over, changing some
negative opcode match tests into positive ones, so as to no value escapes
by accident. Also the advertised argument check was missing from
validate_micromips_insn(), which I have now added, fixing a couple of bugs
throughout it diagnosed.
> char
> mips_nop_opcode (void)
> {
> if (seg_info (now_seg)->tc_segment_info_data.micromips)
> return NOP_OPCODE_MICROMIPS;
>
> return seg_info (now_seg)->tc_segment_info_data.mips16
> ? NOP_OPCODE_MIPS16 : NOP_OPCODE_MIPS;
> }
>
> Same "emacs brackets" thing here. Seems odd to treat microMIPS and MIPS16
> differently like this, so I think if-return-if-return-return makes more
> sense.
Agreed, this function looks better with conditional statements. Fixed.
> The new mips_handle_align looks very good, thanks. I'm afraid it's another
> silly nitpick, but usual style is not to have the brackets in "*(p++)".
I tend to add brackets where operator precedence is not immediately
obvious to the reader. In this case I would have to double-check with the
language standard, so I assumed so would have the reader.
The order of precedence seems natural here for processors with a
post-increment addressing mode, but not everyone has heard of those I
suppose. I removed the brackets anyway.
> Part 2 of the review.
>
> This testcase:
>
> .set micromips
> .fill 0x80
> b16 .-0x80
>
> produces:
>
> /tmp/foo.s: Assembler messages:
> /tmp/foo.s:3: Error: unrecognized opcode `b16 .-0x80'
>
> while:
>
> .set micromips
> .fill 0x80
> b .-0x80
>
> successfully produces a 16-bit insn.
Fixed as a result of earlier changes.
> @@ -14813,6 +16230,8 @@ mips_elf_final_processing (void)
> file_ase_mt is true. */
> if (file_ase_mips16)
> elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_M16;
> + if (file_ase_micromips)
> + elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_MICROMIPS;
> #if 0 /* XXX FIXME */
> if (file_ase_mips3d)
> elf_elfheader (stdoutput)->e_flags |= ???;
>
> Do you really only want this flag to be set if -mmicromips was passed
> on the command line? (Yes, the same concern applies to MIPS16 and MDMX.)
Fixing it up is easy, but I'm not sure what the original intent of these
flags has been. Do they mean:
1. I make use of the FOO feature and I assert it is available?
2. I make use of the FOO feature, but I may go and figure out if it's
available?
3. I make use of the FOO feature and want to prevent linking with any
incompatible ones?
Once we've determined the answer we may modify code accordingly or leave
it as it is. It looks to me the current approach matches #1 and the ELF
program loader may refuse to execute the program if it sees a flag for a
feature that is not supported by the processor to run on. Any .set
fragments within the program are guarded appropriately and hence they do
not need to set the flag (as it would be for #2). Then #3 is sort of
tangential to the two others, but it does matter in this context, hence I
mentioned it (i.e. if #3 was true, then I'd be much happier with #3 & #1
than #3 & #2; otherwise I don't have a strong preference between #1 and
#2).
Current arrangement is similar to that of file_mips_isa even though the
ISA can be overridden by .set too and I think it makes sense to keep all
these flags consistent.
Any thoughts, anyone?
> Lots of cases where a space is missing before "(".
I fix these kinds of errors as I notice them -- some must have obviously
escaped me, sorry. I find it easier to write properly formatted code from
the beginning than to fix it afterwards, but there you go.
Overall I think it would be a good idea to run `indent' over upstream
files we are concerned about at one point (there are plenty of small
problems throughout that sneaked in unnoticed and accumulated over the
time) and then fixing up most of such problems would amount to rerunning
`indent' with the patch in question applied -- without the problem of
reformatting half of the preexisting source code as a side effect.
At least `quilt' warns about trailing white space added (and has an
option to strip it automatically) -- I have cleaned up several places this
way.
> Please be consistent about "str[n]cmp (...) == 0" vs '!str[n]cmp (...)':
> use one or the other. (IMO the first is clearer.)
FWIW I agree first is clearer. I have fixed the couple of others -- they
looked like copied & pasted from existing code though.
> micromips_ip obviously started life as a cut-&-paste of mips_ip, and it
> would have been nice to factor some code out. At least split out the
> block beginning:
>
> + case 'F':
> + case 'L':
> + case 'f':
> + case 'l':
> + {
>
> which is identical between the two, and far too subtle to copy wholesale.
> There may be other good opportunities too.
Next time, I'm afraid. [FIXME]
> + case '(':
> + /* Handle optional base register.
> + Either the base register is omitted or
> + we must have a left paren. */
> + /* This is dependent on the next operand specifier
> + is a base register specification. */
> + gas_assert (args[1] == 'b'
> + || (args[1] == 'm'
> + && (args[2] == 'l' || args[2] == 'n'
> + || args[2] == 's' || args[2] == 'a')));
> + if (*s == '\0' && args[1] == 'b')
> + return;
> +
> + case ')': /* these must match exactly */
> + case '[':
> + case ']':
> + if (*s++ == *args)
> + continue;
> + break;
>
> Mark fallthrough.
Another copy & paste case -- fixed (and removed support for [] as
irrelevant).
> + case 'D': /* floating point destination register */
> + case 'S': /* floating point source register */
> + case 'T': /* floating point target register */
> + case 'R': /* floating point source register */
> + case 'V':
> + rtype = RTYPE_FPU;
> + s_reset = s;
> + if (reg_lookup (&s, rtype, ®no))
> + {
> + if ((regno & 1) != 0
> + && HAVE_32BIT_FPRS
> + && ! mips_oddfpreg_ok (ip->insn_mo, argnum))
> + as_warn (_("Float register should be even, was %d"),
> + regno);
> +
> + c = *args;
> + if (*s == ' ')
> + ++s;
> + if (args[1] != *s)
> + {
> + if (c == 'V' || c == 'W')
> + {
> + regno = lastregno;
> + s = s_reset;
> + ++args;
> + }
> + }
> + switch (c)
> + {
> + case 'D':
> + MICROMIPS_INSERT_OPERAND (FD, *ip, regno);
> + break;
> + case 'V':
> + case 'S':
> + MICROMIPS_INSERT_OPERAND (FS, *ip, regno);
> + break;
> +
> + case 'T':
> + MICROMIPS_INSERT_OPERAND (FT, *ip, regno);
> + break;
> +
> + case 'R':
> + MICROMIPS_INSERT_OPERAND (FR, *ip, regno);
> + break;
> + }
> + lastregno = regno;
> + continue;
> + }
> +
> + switch (*args++)
> + {
> + case 'V':
> + MICROMIPS_INSERT_OPERAND (FS, *ip, lastregno);
> + continue;
> + case 'W':
> + MICROMIPS_INSERT_OPERAND (FT, *ip, lastregno);
> + continue;
> + }
> + break;
>
> This block doesn't have a 'W' case (which doesn't seem to be used
> for micromips at all), so all the 'W' handling is dead code.
Fixed. There's some suspicious code around 'V' here and in mips_ip()
BTW -- it doesn't seem right to me to do args++ here even if it seems to
work. [FIXME]
> + case 4:
> + case 5:
> + case 6:
>
> Too many spaces.
Fixed.
> + if (insn + 1 < µmips_opcodes[bfd_micromips_num_opcodes] &&
> + !strcmp (insn->name, insn[1].name))
>
> Misplaced "&&".
Another copy & paste case -- fixed.
> + = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};;
>
> Double ";".
Fixed.
> + macro_read_relocs (&args, r);
>
> Not portable in this context (and doesn't build on x86_64-linux-gnu).
> You're taking the address of a va_list argument rather than a va_list
> local variable.
Fixed, as noted already.
> + /* For microMIPS, we always use relocations for branches.
> + So, we should not resolve immediate values. */
>
> Too many spaces.
Fixed.
> + if (ep->X_op == O_constant)
> + abort ();
> + else
> + *r = BFD_RELOC_MICROMIPS_16_PCREL_S1;
>
> gcc_assert (ep->X_op != O_constant);
> *r = BFD_RELOC_MICROMIPS_16_PCREL_S1;
Fixed.
> The same cut-&-paste concerns apply to micromips_macro, which obviously
> started out as a copy of macro(). I realise there are special cases
> for micromips (such as the DADDI assymmetry and the lack of
> branch-likely instructions, to name only a few), but most of the
> basic decisions are the same.
>
> As it stands, we have a new 3524 line function, of which I imagine at
> least 90% is shared with macro(). I really think the new microMIPS
> macro handling should be integrated into macro() instead. Don't be
> afraid of factoring out code from macro() if it makes it easier to
> integrate the microMIPS code.
Can we make it a follow-up patch sometime in the future? I'm not afraid
of factoring code out of anywhere (I'm speaking of myself only of course),
but at this point the effort is about the same as writing this whole stuff
from scratch. :( [FIXME]
> #define CPU_MIPS5 5
> #define CPU_MIPS64 64
> #define CPU_MIPS64R2 65
> +#define CPU_MICROMIPS 96
> #define CPU_SB1 12310201 /* octal 'SB', 01. */
> #define CPU_LOONGSON_2E 3001
> #define CPU_LOONGSON_2F 3002
>
> What's this for? It doesn't seem to be used.
Dumped. Whoever will need it can add it back.
> + "mA" 7-bit immediate (-63 .. 64) << 2 (MICROMIPSOP_*_IMMA)
>
> Don't you mean (-64 .. 63)?
Yes, this is for LWGP.
> + "mB" 3-bit immediate (0, -1, 1, 4, 8, 12, 16, 20, 24) (MICROMIPSOP_*_IMMB)
>
> That's nine values. Should the 0 really be there?
No, fixed (this is for ADDIUR2, so wasting a precious encoding of an
immediate would be a bad idea).
> @@ -630,15 +630,15 @@ proc strip_executable { prog flags test
> remote_upload host ${copyfile} tmpdir/striprog
> }
>
> - set result [remote_load target tmpdir/striprog]
> - set status [lindex $result 0]
> - if { ![istarget $host_triplet] } {
> - set status "pass"
> - }
> - if { $status != "pass" } {
> - fail $test
> - return
> - }
> +# set result [remote_load target tmpdir/striprog]
> +# set status [lindex $result 0]
> +# if { ![istarget $host_triplet] } {
> +# set status "pass"
> +# }
> +# if { $status != "pass" } {
> +# fail $test
> +# return
> +# }
>
> set exec_output [binutils_run $NM "$NMFLAGS ${copyfile}"]
> if ![string match "*: no symbols*" $exec_output] {
> @@ -673,15 +673,15 @@ proc strip_executable_with_saving_a_symb
> remote_upload host ${copyfile} tmpdir/striprog
> }
>
> - set result [remote_load target tmpdir/striprog]
> - set status [lindex $result 0]
> - if { ![istarget $host_triplet] } {
> - set status "pass"
> - }
> - if { $status != "pass" } {
> - fail $test
> - return
> - }
> +# set result [remote_load target tmpdir/striprog]
> +# set status [lindex $result 0]
> +# if { ![istarget $host_triplet] } {
> +# set status "pass"
> +# }
> +# if { $status != "pass" } {
> +# fail $test
> +# return
> +# }
>
> set exec_output [binutils_run $NM "$NMFLAGS ${copyfile}"]
> if { [istarget mmix-knuth-mmixware] } {
>
> Looks like these crept in unawares.
Indeed -- that's to avoid running stripped executables that breaks
semihosting. Sorry about that. I've now converted to `quilt'
temporarily, so such stuff will be dropped automatically.
> PLT entries and traditional MIPS lazy binding stubs. We mark the former
> with STO_MIPS_PLT to distinguish them from the latter. */
> #define STO_MIPS_PLT 0x8
> +#define ELF_ST_IS_MIPS_PLT(OTHER) (((OTHER) & 0x8) == STO_MIPS_PLT)
> ...
> #define STO_MIPS_PIC 0x20
> #define ELF_ST_IS_MIPS_PIC(OTHER) \
> - (((OTHER) & ~ELF_ST_VISIBILITY (-1)) == STO_MIPS_PIC)
> + (((OTHER) & ~ELF_ST_VISIBILITY (-1) & ~0xc0) == STO_MIPS_PIC)
> #define ELF_ST_SET_MIPS_PIC(OTHER) \
> - (STO_MIPS_PIC | ELF_ST_VISIBILITY (OTHER))
> + (STO_MIPS_PIC | ELF_ST_VISIBILITY (OTHER) | ELF_ST_MICROMIPS (OTHER))
> ...
> case STO_OPTIONAL: return "OPTIONAL";
> case STO_MIPS16: return "MIPS16";
> - case STO_MIPS_PLT: return "MIPS PLT";
> - case STO_MIPS_PIC: return "MIPS PIC";
> - default: return NULL;
> + default:
> + if (ELF_ST_IS_MIPS_PLT (other))
> + {
> + if (ELF_ST_IS_MICROMIPS (other))
> + return "MICROMIPS, MIPS PLT";
> + else
> + return "MIPS PLT";
> + }
> + if (ELF_ST_IS_MIPS_PIC (other))
> + {
> + if (ELF_ST_IS_MICROMIPS (other))
> + return "MICROMIPS, MIPS PIC";
> + else
> + return "MIPS PIC";
> + }
> + if (ELF_ST_IS_MICROMIPS (other))
> + return "MICROMIPS";
> +
> + return NULL;
>
> You don't add support for microMIPS PLTs, so the "MICROMIPS, MIPS PLT"
> thing appears to be dead code. I wouldn't mind, except that it makes
> the code inconsistent with MIPS16: the changes above allow both
>
> STO_MIPS16 | STO_MIPS_PLT
>
> and
>
> STO_MICROMIPS | STO_MIPS_PLT
>
> neither of which are currently used, but you don't treat the two equally.
>
> In other words, I'm happy with the STO_MIPS_PIC changes but not with
> the STO_MIPS_PLT ones.
I have rewritten both the relevant macro definitions and the piece of
code above. I have cleaned up some of the other STO_* macros too for
consistency and clarity.
> + /* 16 bit relocation. */
> + HOWTO (R_MICROMIPS_16, /* type */
> + 0, /* rightshift */
> + 2, /* size (0 = byte, 1 = short, 2 = long) */
> + 16, /* bitsize */
> + FALSE, /* pc_relative */
> + 0, /* bitpos */
> + complain_overflow_dont, /* complain_on_overflow */
> + _bfd_mips_elf_lo16_reloc, /* special_function */
> + "R_MICROMIPS_16", /* name */
> + TRUE, /* partial_inplace */
> + 0x0000ffff, /* src_mask */
> + 0x0000ffff, /* dst_mask */
> + FALSE), /* pcrel_offset */
>
> Is this relocation really a lo16 one? If so, it's not consistent
> with R_MIPS_16 (which isn't).
I don't think it's needed -- I have removed it. Nobody seems to use
%half() anyway and beside defining it in an odd way the ABI is unclear as
to what this is meant for.
> +/*
> + * Delay slot size and relaxation support
> + */
> +static unsigned long
> +relax_delay_slot (bfd *abfd, bfd_byte *ptr, unsigned long* opcode_32)
> +{
> + unsigned long bdsize = 0;
> +
> + unsigned long fndopc;
> + unsigned long p16opc, p32opc;
> +
> + /* Opcodes preceding the current instruction. */
> + p16opc = bfd_get_16 (abfd, ptr - 2);
> + p32opc = bfd_get_16 (abfd, ptr - 4) << 16;
>
> You need to check the section bounds. The code appears to read off the
> beginning of a section if that section starts with a relaxable LUI.
I've fixed the off-the-section accesses, but this function and
surrounding code was broken in design in the first place. With a
microMIPS instruction stream you can't just peek at a randomly picked
halfword, interpret it as an opcode apply make arbitrary transformations,
because the halfword may in fact be a lower half of 32-bit instruction.
Therefore I changed the function only to replace branch or jump encodings
that change the size of the delay slot if a relocation has been found at
that location. If no relocation has been found, then, conservatively,
only the LUI itself may be be changed and a heuristics is used to
determine if it might be in a delay slot of a fixed size. If no branch or
jump encoding has been found, then the LUI may be deleted altogether,
otherwise a NOP is substituted, that is 16-bit if the heuristics
determined the possible delay slot will accept such one or 32-bit (i.e.
the same width as the original LUI) otherwise.
Note that in particular means a JALR->JALRS conversion won't happen
unless there's a R_MIPS_JALR relocation against the call instruction; I
made no attempt to change GAS in any way to emit such a relocation in
cases it does not do already. [FIXME]
> + /* If this isn't something that can be relaxed, then ignore
> + this reloc. */
> + if (ELF32_R_TYPE (irel->r_info) != (int) R_MICROMIPS_HI16 &&
> + ELF32_R_TYPE (irel->r_info) != (int) R_MICROMIPS_LO16 &&
> + ELF32_R_TYPE (irel->r_info) != (int) R_MICROMIPS_PC16_S1 &&
> + ELF32_R_TYPE (irel->r_info) != (int) R_MICROMIPS_26_S1 &&
> + ELF32_R_TYPE (irel->r_info) != (int) R_MICROMIPS_GPREL16)
> + continue;
>
> &&s at the beginning of lines.
Fixed.
> + /* Get the value of the symbol referred to by the reloc. */
> + if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
> + {
> + /* A local symbol. */
> + Elf_Internal_Sym *isym;
> + asection *sym_sec;
> +
> + isym = isymbuf + ELF32_R_SYM (irel->r_info);
> + if (isym->st_shndx == SHN_UNDEF)
> + sym_sec = bfd_und_section_ptr;
> + else if (isym->st_shndx == SHN_ABS)
> + sym_sec = bfd_abs_section_ptr;
> + else if (isym->st_shndx == SHN_COMMON)
> + sym_sec = bfd_com_section_ptr;
> + else
> + sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
> + symval = (isym->st_value
> + + sym_sec->output_section->vma
> + + sym_sec->output_offset);
> + target_is_micromips_code_p = ELF_ST_IS_MICROMIPS (isym->st_other);
> + }
> + else
> + {
> + unsigned long indx;
> + struct elf_link_hash_entry *h;
> +
> + /* An external symbol. */
> + indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
> + h = elf_sym_hashes (abfd)[indx];
> + BFD_ASSERT (h != NULL);
> +
> + if (h->root.type != bfd_link_hash_defined
> + && h->root.type != bfd_link_hash_defweak)
> + /* This appears to be a reference to an undefined
> + symbol. Just ignore it -- it will be caught by the
> + regular reloc processing. */
> + continue;
> +
> + symval = (h->root.u.def.value
> + + h->root.u.def.section->output_section->vma
> + + h->root.u.def.section->output_offset);
> + }
>
> Why not set target_is_micromips_code_p for locally-binding global
> symbols too?
Globally-binding, that is. I see no reason -- Chao-ying?
I have changed it now anyway.
> + opcode = bfd_get_16 (abfd, contents + irel->r_offset ) << 16;
> + opcode |= (irel->r_offset + 2 < sec->size
> + ? bfd_get_16 (abfd, contents + irel->r_offset + 2) : 0);
>
> Are there any relaxations we can actually do if irel->r_offset + 2
> >= sec->size? I couldn't see any. If there aren't, continue instead.
Agreed -- all relaxations operate on 32-bit instructions (some also imply
access to the following instruction that wasn't guarded against the
section end and which I have fixed it now too) -- there's no point in
doing anything with half-an-instruction.
> + /* R_MICROMIPS_HI16 / LUI relaxation to R_MICROMIPS_HI0_LO16 or
> + R_MICROMIPS_PC23_S2. The R_MICROMIPS_PC23_S2 condition is
> +
> + (symval % 4 == 0 && IS_BITSIZE (pcrval, X, 25))
> +
> + where the X adjustment compensate for R_MICROMIPS_HI16 and
> + R_MICROMIPS_LO16 being at most X bytes appart when the
> + distance to the target approaches 32 MB. */
>
> Comment is slightly confusing: we don't relax the HI16 itself to a
> H0_LO16 or PC32_S3. Rather we relax the LO16 (or, if you like,
> the HI16/LO16 pair).
I have reworded the comment now.
> + /* Assume is possible to delete the LUI instruction:
> + 4 bytes at irel->r_offset. */
>
> s/Assume is/Assume it is/
Fixed.
> + /* Compact branch relaxation -- due to the multitude of macros
> + employed by the compiler/assembler, compact branches are not
> + aways generated. Obviously, this can/will be fixed elsewhere,
> + but there is no drawback in double checking it here. */
> + else if (ELF32_R_TYPE (irel->r_info) == (int) R_MICROMIPS_PC16_S1
> + && (fndopc = find_match (opcode, bz_insns_32)) != 0
> + && MATCH (bfd_get_16 (abfd, contents + irel->r_offset + 4),
> + nop_insn_16))
>
> s/aways/always/. You should check the section size before reading
> past the relocation. (I realise there ought to be a delay slot,
> but we should be robust against brokenness.)
Ah, you noticed that too -- fixed, as noted above.
> + /* R_MICROMIPS_26_S1 -- JAL to JALS relaxation for microMIPS targets. */
> + else if (ELF32_R_TYPE (irel->r_info) == (int) R_MICROMIPS_26_S1
> + && target_is_micromips_code_p
> + && MATCH (opcode, jal_insn_32_bd32))
> + {
> + unsigned long n32opc;
> + bfd_boolean relaxed = FALSE;
> +
> + n32opc =
> + bfd_get_16 (abfd, contents + irel->r_offset + 4 ) << 16;
> + n32opc |= irel->r_offset + 2 < sec->size?
> + bfd_get_16 (abfd, contents + irel->r_offset + 6): 0;
> +
>
> Here too you should check the size before reading n32opc. Second
> condition looks bogus (did you mean +6?) although the same concerns
> apply as for the "+ 2" above.
Fixed, as noted above.
I have fixed the rewrite of immediate addends throughout too as that
matters for REL targets. And fixed zillions of GNU Coding Standar
violations.
Overall I'm a bit concerned about all this linker relaxation stuff -- it
breaks -falign-jumps, -falign-labels and -falign-loops which may have a
severe performance penalty and should therefore be enabled conditionally
only, preferably where all the three options are set to 1 (meaning that
would be naturally implied by -Os). A linker option would be required an
set appropriately by the GCC driver. [FIXME]
> the elf32-mips.c reloc questions in review 2 apply to elf64-mips.c
> and elfn32-mips.c as well. Furthermore:
>
> +static reloc_howto_type micromips_elf64_howto_table_rela[] =
> +{
> + /* 16 bit relocation. */
> + HOWTO (R_MICROMIPS_16, /* type */
> + 0, /* rightshift */
> + 2, /* size (0 = byte, 1 = short, 2 = long) */
> + 16, /* bitsize */
> + FALSE, /* pc_relative */
> + 0, /* bitpos */
> + complain_overflow_dont, /* complain_on_overflow */
> + _bfd_mips_elf_lo16_reloc, /* special_function */
> + "R_MICROMIPS_16", /* name */
> + TRUE, /* partial_inplace */
> + 0x0000ffff, /* src_mask */
> + 0x0000ffff, /* dst_mask */
> + FALSE), /* pcrel_offset */
>
> RELA relocations shouldn't be partial_inplace. Applies to the whole array.
Could be my omission -- fixed, sorry. There were preexisting cases too,
sent as a separate patch.
> Did you actually test this with n64, say with a gcc bootstrap? Same
> comment goes for elfn32-mips.c.
>
> Why only do the linker relaxation for elf32-mips.c (o32, o64 & EABI)?
> Why not for n32 and n64 too?
The answer to all the questions is negative. There is no 64-bit
microMIPS hardware available at the moment. The best bet might be QEMU --
NathanF, have you implemented any of the 64-bit instructions in QEMU?
Otherwise there's probably no way do do any of 64-bit microMIPS testing
beside what's done in binutils. And no library work of any kind has
started for 64-bit microMIPS support AFAIK. Hence there has been little
incentive to attempt anything but rudimentary support for 64-bit ABIs.
I envisage all the relaxation stuff to be either moved over to
elfxx-mips.c or copied to elfn32-mips.c and elf64-mips.c, as applicable,
once we have real 64-bit support.
> +#define LA25_LUI_MICROMIPS_1(VAL) (0x41b9) /* lui t9,VAL */
> +#define LA25_LUI_MICROMIPS_2(VAL) (VAL)
> +#define LA25_J_MICROMIPS_1(VAL) (0xd400 | (((VAL) >> 17) & 0x3ff)) /* j VAL */
> +#define LA25_J_MICROMIPS_2(VAL) (0xd4000000 | (((VAL) >> 1) & 0xffff))
> +#define LA25_ADDIU_MICROMIPS_1(VAL) (0x3339) /* addiu t9,t9,VAL */
> +#define LA25_ADDIU_MICROMIPS_2(VAL) (VAL)
>
> LA25_J_MICROMIPS_2 is a 16-bit opcode, so the "0xd4000000 | ..."
> thing is bogus.
Fixed.
> That said, why split these up? bfd_{get,put}_32
> don't require aligned addresses.
I think it's easier and more readable this way as with bfd_{get,put}_32()
you'd have to halfword-swap the bit patterns produced based on the target
endianness.
> + value = s->size;
> + if (ELF_ST_IS_MICROMIPS (stub->h->root.other))
> + value |= 1;
> +
> /* Create a symbol for the stub. */
> - mips_elf_create_stub_symbol (info, stub->h, ".pic.", s, s->size, 8);
> + mips_elf_create_stub_symbol (info, stub->h, ".pic.", s, value, 8);
>
> Do this in mips_elf_create_stub_symbol rather than in each caller.
Fixed.
> + return r_type == R_MIPS_GOT16 || r_type == R_MIPS16_GOT16
> + || r_type == R_MICROMIPS_GOT16;
>
> GNU indentation requires brackets here. Also, once it becomes too
> long for one line, let's keep one item per line:
>
> return (r_type == R_MIPS_GOT16
> || r_type == R_MIPS16_GOT16
> || r_type == R_MICROMIPS_GOT16);
>
> Same for later functions.
Fixed.
> - if (r_type == R_MIPS_TLS_GOTTPREL)
> + if (r_type == R_MIPS_TLS_GOTTPREL || r_type == R_MICROMIPS_TLS_GOTTPREL)
>
> Hide these differences in analogues of the got16_reloc_p functions.
> Same for all other relocs with MICROMIPS variants.
Done. Found and fixed some MIPS16 bugs on the way.
> @@ -3187,8 +3244,12 @@ mips_elf_got_page (bfd *abfd, bfd *ibfd,
> struct mips_got_entry *entry;
>
> page = (value + 0x8000) & ~(bfd_vma) 0xffff;
> - entry = mips_elf_create_local_got_entry (abfd, info, ibfd, page, 0,
> - NULL, R_MIPS_GOT_PAGE);
> + if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS)
> + entry = mips_elf_create_local_got_entry (abfd, info, ibfd, page, 0,
> + NULL, R_MICROMIPS_GOT_PAGE);
> + else
> + entry = mips_elf_create_local_got_entry (abfd, info, ibfd, page, 0,
> + NULL, R_MIPS_GOT_PAGE);
>
> if (!entry)
> return MINUS_ONE;
>
> Why is this necessary?
This looks bogus to me -- most mips_elf_create_local_got_entry() cares
about is whether r_type is a TLS reloc or not. It does some further
checks for TLS relocs, but it doesn't bother otherwise. Removed.
> @@ -5127,12 +5200,26 @@ mips_elf_calculate_relocation (bfd *abfd
> + h->la25_stub->stub_section->output_offset
> + h->la25_stub->offset);
>
> + /* Make sure MIPS16 and microMIPS are not used together. */
> + if ((r_type == R_MIPS16_26 && target_is_micromips_code_p)
> + || (r_type == R_MICROMIPS_26_S1 && target_is_16_bit_code_p))
> + {
> + (*_bfd_error_handler)
> + (_("MIPS16 and microMIPS functions cannot call each other"));
> + return bfd_reloc_notsupported;
> + }
>
> Should this be extended to check for branches too?
That would be a useful improvement I suppose, but MIPS16 code doesn't
care either (you can't use a branch to switch the ISA mode). Overall I
think it's a corner case -- branches to external symbols are a rarity.
[FIXME]
> + case R_MIPS_26:
> + /* Make sure the target of JALX is word-aligned.
> + Bit 0 must be 1 (MIPS16/microMIPS mode), and bit 1 must be 0. */
> + if (*cross_mode_jump_p == TRUE && (symbol & 3) != 1)
> + return bfd_reloc_outofrange;
>
> == TRUE has been banned by act of parliament.
Fixed.
> If we're checking alignment for R_MIPS_26 and R_MICROMIPS_26, we should
> check it for R_MIPS16_26 too. Something like:
>
> /* Make sure the target of JALX is word-aligned.
> Bit 0 must be the correct ISA mode selector and bit 1 must be 0. */
> if (*cross_mode_jump_p && (symbol & 3) != (r_type == R_MIPS_26))
> return bfd_reloc_outofrange;
>
> for both cases would be fine.
>
> + case R_MICROMIPS_26_S1:
> + /* Make sure the target of jalx is word-aligned. */
> + if (*cross_mode_jump_p == TRUE && (symbol & 3) != 0)
> + return bfd_reloc_outofrange;
> + if (local_p)
> + {
> + /* For jalx, the offset is shifted right by two bits. */
> + if (*cross_mode_jump_p == TRUE)
> + value = ((addend | ((p + 4) & 0xf0000000)) + symbol) >> 2;
> + else
> + value = ((addend | ((p + 4) & 0xf8000000)) + symbol) >> 1;
> + }
> + else
> + {
> + /* For jalx, the offset is shifted right by two bits. */
> + if (*cross_mode_jump_p == TRUE)
> + {
> + value = (_bfd_mips_elf_sign_extend (addend, 28) + symbol) >> 2;
> + if (h->root.root.type != bfd_link_hash_undefweak)
> + overflowed_p = (value >> 26) != ((p + 4) >> 28);
> + }
> + else
> + {
> + value = (_bfd_mips_elf_sign_extend (addend, 27) + symbol) >> 1;
> + if (h->root.root.type != bfd_link_hash_undefweak)
> + overflowed_p = (value >> 26) != ((p + 4) >> 27);
> + }
> + }
> + value &= howto->dst_mask;
> + break;
>
> This is a strict extension of the R_MIPS_26 and R_MIPS16_26 behaviour,
> so I'd prefer to see them integrated.
I think R_MIPS_26 should be used for microMIPS JALX. I don't like the
idea of overloading R_MICROMIPS_26_S1 this way, especially given another
relocation already fits. What do you think? It is too late to fix the
ABI probably though; I'm thinking what the consequences might be...
I have merged this piece now and integrated your comment update.
> @@ -5372,6 +5516,9 @@ mips_elf_calculate_relocation (bfd *abfd
> both reloc addends by 4. */
> if (r_type == R_MIPS16_HI16)
> value = mips_elf_high (addend + gp - p - 4);
> + else if (r_type == R_MICROMIPS_HI16)
> + /* The low bit of $t9 is set for microMIPS calls. */
> + value = mips_elf_high (addend + gp - p - 1);
> else
> value = mips_elf_high (addend + gp - p);
> overflowed_p = mips_elf_overflow_p (value, 16);
>
> This statement is also true for MIPS16, so in context, the comment
> is a bit confusing on its own. How about:
>
> /* The microMIPS .cpload sequence uses the same assembly
> instructions as the traditional psABI version, but the
> incoming $t9 has the low bit set. */
Fine by me.
> @@ -5486,8 +5647,38 @@ mips_elf_calculate_relocation (bfd *abfd
> value &= howto->dst_mask;
> break;
>
> + case R_MICROMIPS_PC7_S1:
> + value = symbol + _bfd_mips_elf_sign_extend (addend, 8) - p;
> + overflowed_p = mips_elf_overflow_p (value, 8);
> + value >>= howto->rightshift;
> + value &= howto->dst_mask;
> + break;
> +
> + case R_MICROMIPS_PC10_S1:
> + value = symbol + _bfd_mips_elf_sign_extend (addend, 11) - p;
> + overflowed_p = mips_elf_overflow_p (value, 11);
> + value >>= howto->rightshift;
> + value &= howto->dst_mask;
> + break;
> +
> + case R_MICROMIPS_PC16_S1:
> + value = symbol + _bfd_mips_elf_sign_extend (addend, 17) - p;
> + overflowed_p = mips_elf_overflow_p (value, 17);
> + value >>= howto->rightshift;
> + value &= howto->dst_mask;
> + break;
> +
> + case R_MICROMIPS_PC23_S2:
> + value = symbol + _bfd_mips_elf_sign_extend (addend, 25) - (p &
> 0xfffffffc);
> + overflowed_p = mips_elf_overflow_p (value, 25);
> + value >>= howto->rightshift;
> + value &= howto->dst_mask;
> + break;
>
> I realise you probably based this on R_MIPS_PC16 and R_MIPS_GNU_REL16_S2,
> but even so, you're careful to check for underflow elsewhere but ignore
> it here.
I'm not sure what you mean. R_MICROMIPS_PC23_S2 is used for ADDIUPC so
you have to strip out the two LSBs.
> Use of 0xfffffffc isn't portable for 64-bit addresses;
> use "-4" or "~(bfd_vma) 3" instead.
I'm nasty enough to use (foo | 3) ^ 3 and avoid type width and promotion
dependencies altogether in such cases and hope for GCC to be smart and do
the right thing and combine the two ops.
> @@ -6150,13 +6355,18 @@ _bfd_mips_elf_symbol_processing (bfd *ab
> break;
> }
>
> - /* If this is an odd-valued function symbol, assume it's a MIPS16 one. */
> + /* If this is an odd-valued function symbol, assume it's a MIPS16
> + or microMIPS one. */
> if (ELF_ST_TYPE (elfsym->internal_elf_sym.st_info) == STT_FUNC
> && (asym->value & 1) != 0)
> {
> asym->value--;
> - elfsym->internal_elf_sym.st_other
> - = ELF_ST_SET_MIPS16 (elfsym->internal_elf_sym.st_other);
> + if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS)
> + elfsym->internal_elf_sym.st_other
> + = ELF_ST_SET_MICROMIPS (elfsym->internal_elf_sym.st_other);
> + else
> + elfsym->internal_elf_sym.st_other
> + = ELF_ST_SET_MIPS16 (elfsym->internal_elf_sym.st_other);
> }
> }
>
>
> So a file can't mix MIPS16 and microMIPS code? We should probably
> detect that explicitly. I'd like a clear statement of what the
> interoperability restrictions are.
>
> This goes back to the question of when EF_MIPS_ARCH_ASE_MICROMIPS
> should be set (see previous reviews).
Background information first -- you can't have a piece of MIPS hardware,
either real or simulated, with the MIPS16 ASE and the microMIPS ASE
implemented both at a time. This is a design assumption that allowed the
ISA bit to be overloaded.
That obviously does not mean -- in principle -- that you can't have an
executable (or one plus a mixture of shared libraries) where some
functions are MIPS16 code and some are microMIPS code, either of which
only called once the presence of the respective ASE has been determined.
While a valid configuration this is also a rare exotic corner case -- I
could imagine a piece of generic, processor-independent console/bootstrap
firmware like this for example, but little beyond that.
We had a discussion about it and the conclusion was from the user's
perspective the most beneficial configuration is one where mixing MIPS16
and microMIPS code within a single executable is forbidden by default.
The reason is a build-time error is always better than a run-time one
(especially when the device has been placed out there in the field
already; hopefully not an Ariane 5 rocket) and the case where mixing
MIPS16 and microMIPS code would almost always happen is when the user
picked the wrong library by mistake. It is therefore most productive to
fail at this point rather than later.
A future enhancement could add assembler and linker switches to override
this default and mix the two ASEs in a single executable. [FIXME]
> @@ -6865,7 +7075,8 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd
> /* If this is a mips16 text symbol, add 1 to the value to make it
> odd. This will cause something like .word SYM to come up with
> the right value when it is loaded into the PC. */
> - if (ELF_ST_IS_MIPS16 (sym->st_other))
> + if (ELF_ST_IS_MIPS16 (sym->st_other)
> + || ELF_ST_IS_MICROMIPS (sym->st_other))
> ++*valp;
>
> return TRUE;
>
> As with GAS, I'd like an ODD_SYMBOL_P or some-such.
ELF_ST_IS_COMPRESSED it is then, for consistency. Note it doesn't seem
possible to me to limit the macro to read its argument once only without
resorting to GNU extensions; I'll be happy to be proved wrong though.
> @@ -7166,6 +7378,8 @@ mips_elf_add_lo16_rel_addend (bfd *abfd,
> r_type = ELF_R_TYPE (abfd, rel->r_info);
> if (mips16_reloc_p (r_type))
> lo16_type = R_MIPS16_LO16;
> + else if (micromips_reloc_shuffle_p (r_type))
> + lo16_type = R_MICROMIPS_LO16;
> else
> lo16_type = R_MIPS_LO16;
>
> Conceptually, this ought to be plain micromips_reloc_p. Whether we need
> to shuffle or not isn't an issue here, even though I realise the shuffle
> condition produces the right result.
Of course.
> @@ -9215,6 +9479,12 @@ _bfd_mips_elf_relocate_section (bfd *out
> case bfd_reloc_ok:
> break;
>
> + case bfd_reloc_outofrange:
> + msg = _("internal error: jalx jumps to not word-aligned address");
> + info->callbacks->warning
> + (info, msg, name, input_bfd, input_section, rel->r_offset);
> + return FALSE;
> +
> default:
> abort ();
> break;
>
> Why's that an internal error? Surely it could be triggered by
> badly-formed input, rather than just as a result of internal
> confusion?
>
> The error is more specific than the error code, so you should also add:
>
> BFD_ASSERT (jal_reloc_p (howto->type));
I've made it a conditional instead. Preexisting cases of
bfd_reloc_outofrange will fall through to abort() below as they do now.
> @@ -976,7 +976,7 @@ bfd_install_relocation (bfd *abfd,
> asection *reloc_target_output_section;
> asymbol *symbol;
> bfd_byte *data;
> -
> +
> symbol = *(reloc_entry->sym_ptr_ptr);
> if (bfd_is_abs_section (symbol->section))
> {
>
> Bogus change.
Fixed.
> @@ -1652,6 +1652,8 @@ ENUMX
> ENUMX
> BFD_RELOC_16
> ENUMX
> + BFD_RELOC_MICROMIPS_16
> +ENUMX
> BFD_RELOC_14
> ENUMX
> BFD_RELOC_8
>
> Here and elsewhere, keep the MIPS-specific stuff separate from the
> generic relocs. See the MIPS16 relocs for examples.
I agree in principle, but no longer relevant as I have discarded the
reloc.
> I'll take your word for it that micromips-opc.c is correct. ;-)
There were a couple of problems with it, but I did my best to get it
right. :)
> + else if ((insn & 0x1c00) != 0x0400
> + && (insn & 0x1c00) != 0x0800
> + && (insn & 0x1c00) != 0x0c00)
> + {
> + /* This is a 32-bit microMIPS instruction. */
> + higher = insn;
> +
> + status = (*info->read_memory_func) (memaddr + 2, buffer, 2, info);
> + if (status != 0)
> + {
> + (*info->fprintf_func) (info->stream, "micromips 0x%x",
> + (unsigned int) higher);
> + (*info->memory_error_func) (status, memaddr + 2, info);
> + return -1;
> + }
>
> Why print "micromips " here but not in the 48-byte case?
It looks to me it's been modelled after the MIPS16 version where "extend
0x..." is printed in the case of a read error. I'm not sure if either
makes sense (.byte foo or suchlike that some other ports output in such a
case looks more reasonable to me), but at least it is consistent.
> Also,
> s/0x%02x/0x%x/ would be better IMO.
The highest byte is always 0x7c, so no need to care about leading zeroes.
I have rewritten pieces of this code so that all output available is
always produced in a single place.
> Watch your formatting in this function. There are lots of cases of
> things like:
>
> (*info->fprintf_func) (info->stream, "%s",
> mips_gpr_names[lastregno]);
>
> which isn't right. Arguments must be aligned to the column after
> the "(". Don't be afraid to split lines into several statements
> if it makes things look more natural.
Agreed, this was a horrible piece of unreadable code. I created some
auxiliary variables and a macro to compress the source (and, in the former
case, to get potentially better code), improving readablity and getting
rid of most indentation problems as a side effect.
The rule of thumb is if you have a problem with source code of your
program hitting the right margin on an 80-column terminal, then you're
probably putting too much in a single function. This rule isn't kept of
course in many places throughout binutils, but that does not mean it's not
a valid one.
> The gas testsuite changes look very nice, thanks.
You are welcome. :)
Thank you for the review -- I know it's been a lot effort. Here's a new
version of the change. Regression-tested succesfully on mips-sde-elf and
mips-linux-gnu targets. Changes for the MCU ASE and the M14K/c cores will
follow.
Maciej
bfd/
2010-07-26 Chao-ying Fu <fu@mips.com>
Ilie Garbacea <ilie@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
Joseph Myers <joseph@codesourcery.com>
Catherine Moore <clm@codesourcery.com>
* archures.c (bfd_mach_mips_micromips): New macro.
* cpu-mips.c (I_micromips): New enum value.
(arch_info_struct): Add bfd_mach_mips_micromips.
* elfxx-mips.h: (_bfd_mips16_elf_reloc_unshuffle): Rename to...
(_bfd_mips_elf_reloc_unshuffle): ... this. Handle microMIPS.
(_bfd_mips16_elf_reloc_shuffle): Rename to...
(_bfd_mips_elf_reloc_shuffle): ... this. Handle microMIPS.
(gprel16_reloc_p): Handle microMIPS.
(literal_reloc_p): New function.
* elf32-mips.c (elf_micromips_howto_table_rel): New variable.
(_bfd_mips_elf32_gprel16_reloc): Handle microMIPS.
(mips16_gprel_reloc): Update for _bfd_mips_elf_reloc_unshuffle
and _bfd_mips_elf_reloc_shuffle changes.
(mips_elf_gprel32_reloc): Update comment.
(micromips_reloc_map): New variable.
(bfd_elf32_bfd_reloc_type_lookup): Handle microMIPS.
(mips_elf32_rtype_to_howto): Likewise.
(mips_info_to_howto_rel): Likewise.
(elf32_mips_relax_delete_bytes): New function.
(opcode_descriptor): New structure.
(b_insns_32, b_insn_16): New variables.
(BZ32_REG, BZ32_REG_FIELD): New macros.
(bz_insns_32, bzc_insns_32, bz_insns_16): New variables.
(BZ16_VALID_REG, BZ16_REG_FIELD): New macros.
(jal_insn_32_bd16, jal_insn_32_bd32): New variables.
(call_insn_32_bd16, call_insn_32_bd32): Likewise.
(ds_insns_32_bd16, jalx_insn_32_bd32): Likewise.
(jalr_insn_16_bd16, jalr_insn_16_bd32): Likewise.
(ds_insns_16_bd16): Likewise.
(lui_insn, addiu_insn, addiupc_insn): Likewise.
(ADDIU_REG, ADDIUPC_VALID_REG, ADDIUPC_REG_FIELD): New macros.
(lwgp_insn_32, lwgp_insn_16): New functions.
(LWGP32_REG, LWGP16_VALID_REG, LWGP16_REG_FIELD): New macros.
(MOVE32_RD, MOVE32_RS): Likewise.
(MOVE16_RD_FIELD, MOVE16_RS_FIELD): Likewise.
(move_insns_32, move_insns_16): New variables.
(nop_insn_32, nop_insn_16): Likewise.
(MATCH): New macro.
(find_match): New function.
(relax_dslot_norel16, relax_dslot_norel32): Likewise.
(relax_dslot_rel): Likewise.
(IS_BITSIZE): New macro.
(elf32_mips_relax_section): New function.
(bfd_elf32_bfd_relax_section): Define.
* elf64-mips.c (micromips_elf64_howto_table_rel): New variable.
(micromips_elf64_howto_table_rela): Likewise.
(mips16_gprel_reloc): Update for _bfd_mips_elf_reloc_unshuffle
and _bfd_mips_elf_reloc_shuffle changes.
(micromips_reloc_map): Likewise.
(bfd_elf64_bfd_reloc_type_lookup): Handle microMIPS.
(bfd_elf64_bfd_reloc_name_lookup): Likewise.
(mips_elf64_rtype_to_howto): Likewise.
* elfn32-mips.c (elf_micromips_howto_table_rel): New variable.
(elf_micromips_howto_table_rela): Likewise.
(mips16_gprel_reloc): Update for _bfd_mips_elf_reloc_unshuffle
and _bfd_mips_elf_reloc_shuffle changes.
(micromips_reloc_map): Likewise.
(bfd_elf32_bfd_reloc_type_lookup): Handle microMIPS.
(bfd_elf32_bfd_reloc_name_lookup): Likewise.
(mips_elf_n32_rtype_to_howto): Likewise.
* elfxx-mips.c (LA25_LUI_MICROMIPS_1): New macro.
(LA25_LUI_MICROMIPS_2): Likewise.
(LA25_J_MICROMIPS_1, LA25_J_MICROMIPS_2): Likewise.
(LA25_ADDIU_MICROMIPS_1, LA25_ADDIU_MICROMIPS_2): Likewise.
(TLS_RELOC_P): Handle microMIPS.
(mips_elf_create_stub_symbol): Adjust value of stub symbol if
target is a microMIPS function.
(micromips_reloc_p): New function.
(micromips_reloc_shuffle_p): Likewise.
(got16_reloc_p, call16_reloc_p): Handle microMIPS.
(got_disp_reloc_p, got_page_reloc_p): New functions.
(got_ofst_reloc_p): Likewise.
(got_hi16_reloc_p, got_lo16_reloc_p): Likewise.
(call_hi16_reloc_p, call_lo16_reloc_p): Likewise.
(hi16_reloc_p, lo16_reloc_p, jal_reloc_p): Handle microMIPS.
(tls_gd_reloc_p, tls_ldm_reloc_p): New functions.
(tls_gottprel_reloc_p): Likewise.
(_bfd_mips16_elf_reloc_unshuffle): Rename to...
(_bfd_mips_elf_reloc_unshuffle): ... this. Handle microMIPS.
(_bfd_mips16_elf_reloc_shuffle): Rename to...
(_bfd_mips_elf_reloc_shuffle): ... this. Handle microMIPS.
(_bfd_mips_elf_lo16_reloc): Handle microMIPS.
(mips_tls_got_index, mips_elf_got_page): Likewise.
(mips_elf_create_local_got_entry): Likewise.
(mips_elf_relocation_needs_la25_stub): Likewise.
(mips_elf_calculate_relocation): Likewise.
(mips_elf_perform_relocation): Likewise.
(_bfd_mips_elf_symbol_processing): Likewise.
(_bfd_mips_elf_add_symbol_hook): Likewise.
(_bfd_mips_elf_link_output_symbol_hook): Likewise.
(mips_elf_add_lo16_rel_addend): Likewise.
(_bfd_mips_elf_check_relocs): Likewise.
(mips_elf_adjust_addend): Likewise.
(_bfd_mips_elf_relocate_section): Likewise.
(mips_elf_create_la25_stub): Likewise.
(_bfd_mips_vxworks_finish_dynamic_symbol): Likewise.
(_bfd_mips_elf_gc_sweep_hook): Likewise.
(_bfd_mips_elf_print_private_bfd_data): Likewise.
* reloc.c (BFD_RELOC_MICROMIPS_7_PCREL_S1): New relocation.
(BFD_RELOC_MICROMIPS_10_PCREL_S1): Likewise.
(BFD_RELOC_MICROMIPS_16_PCREL_S1): Likewise.
(BFD_RELOC_MICROMIPS_GPREL16): Likewise.
(BFD_RELOC_MICROMIPS_JMP, BFD_RELOC_MICROMIPS_HI16): Likewise.
(BFD_RELOC_MICROMIPS_HI16_S): Likewise.
(BFD_RELOC_MICROMIPS_LO16): Likewise.
(BFD_RELOC_MICROMIPS_LITERAL): Likewise.
(BFD_RELOC_MICROMIPS_GOT16): Likewise.
(BFD_RELOC_MICROMIPS_CALL16): Likewise.
(BFD_RELOC_MICROMIPS_GOT_HI16): Likewise.
(BFD_RELOC_MICROMIPS_GOT_LO16): Likewise.
(BFD_RELOC_MICROMIPS_CALL_HI16): Likewise.
(BFD_RELOC_MICROMIPS_CALL_LO16): Likewise.
(BFD_RELOC_MICROMIPS_SUB): Likewise.
(BFD_RELOC_MICROMIPS_GOT_PAGE): Likewise.
(BFD_RELOC_MICROMIPS_GOT_OFST): Likewise.
(BFD_RELOC_MICROMIPS_GOT_DISP): Likewise.
(BFD_RELOC_MICROMIPS_HIGHEST): Likewise.
(BFD_RELOC_MICROMIPS_HIGHER): Likewise.
(BFD_RELOC_MICROMIPS_SCN_DISP): Likewise.
(BFD_RELOC_MICROMIPS_JALR): Likewise.
(BFD_RELOC_MICROMIPS_TLS_GD): Likewise.
(BFD_RELOC_MICROMIPS_TLS_LDM): Likewise.
(BFD_RELOC_MICROMIPS_TLS_DTPREL_HI16): Likewise.
(BFD_RELOC_MICROMIPS_TLS_DTPREL_LO16): Likewise.
(BFD_RELOC_MICROMIPS_TLS_GOTTPREL): Likewise.
(BFD_RELOC_MICROMIPS_TLS_TPREL_HI16): Likewise.
(BFD_RELOC_MICROMIPS_TLS_TPREL_LO16): Likewise.
* bfd-in2.h: Regenerate.
* libbfd.h: Regenerate.
binutils/
2010-07-26 Chao-ying Fu <fu@mips.com>
* readelf.c (get_machine_flags): Handle microMIPS.
(get_mips_symbol_other): Likewise.
gas/
2010-07-26 Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* config/tc-mips.h (mips_segment_info): Add one bit for
microMIPS.
(TC_LABEL_IS_LOCAL): New macro.
(mips_label_is_local): New prototype.
* config/tc-mips.c (emit_branch_likely_macro): New variable.
(mips_set_options): Add micromips.
(mips_opts): Initialise micromips to -1.
(file_ase_micromips): New variable.
(CPU_HAS_MICROMIPS): New macro.
(HAVE_CODE_COMPRESSION): Likewise.
(micromips_op_hash): New variable.
(micromips_nop16_insn, micromips_nop32_insn): New variables.
(NOP_INSN): Handle microMIPS.
(mips32_to_micromips_reg_b_map): New macro.
(mips32_to_micromips_reg_c_map): Likewise.
(mips32_to_micromips_reg_d_map): Likewise.
(mips32_to_micromips_reg_e_map): Likewise.
(mips32_to_micromips_reg_f_map): Likewise.
(mips32_to_micromips_reg_g_map): Likewise.
(mips32_to_micromips_reg_l_map): Likewise.
(mips32_to_micromips_reg_n_map): Likewise.
(mips32_to_micromips_reg_h_map): New variable.
(mips32_to_micromips_reg_m_map): Likewise.
(mips32_to_micromips_reg_q_map): Likewise.
(micromips_to_32_reg_h_map): New variable.
(micromips_to_32_reg_i_map): Likewise.
(micromips_to_32_reg_m_map): Likewise.
(micromips_to_32_reg_q_map): Likewise.
(micromips_to_32_reg_b_map): New macro.
(micromips_to_32_reg_c_map): Likewise.
(micromips_to_32_reg_d_map): Likewise.
(micromips_to_32_reg_e_map): Likewise.
(micromips_to_32_reg_f_map): Likewise.
(micromips_to_32_reg_g_map): Likewise.
(micromips_to_32_reg_l_map): Likewise.
(micromips_to_32_reg_n_map): Likewise.
(micromips_imm_b_map, micromips_imm_c_map): New macros.
(RELAX_DELAY_SLOT_16BIT): New macro.
(RELAX_DELAY_SLOT_SIZE_FIRST): Likewise.
(RELAX_DELAY_SLOT_SIZE_SECOND): Likewise.
(RELAX_MICROMIPS_ENCODE, RELAX_MICROMIPS_P): New macros.
(RELAX_MICROMIPS_TYPE, RELAX_MICROMIPS_USER_16BIT): Likewise.
(RELAX_MICROMIPS_UNCOND, RELAX_MICROMIPS_LINK): Likewise.
(RELAX_MICROMIPS_TOOFAR, RELAX_MICROMIPS_MARK_TOOFAR): Likewise.
(RELAX_MICROMIPS_CLEAR_TOOFAR): Likewise.
(RELAX_MICROMIPS_EXTENDED): Likewise.
(RELAX_MICROMIPS_MARK_EXTENDED): Likewise.
(RELAX_MICROMIPS_CLEAR_EXTENDED): Likewise.
(MICROMIPS_INSERT_OPERAND, MICROMIPS_EXTRACT_OPERAND): New
macros.
(mips_macro_warning): Add delay_slot_16bit_p, delay_slot_32bit_p,
fsize and insns.
(mips16_small, mips16_ext): Remove variables, replacing with...
(forced_insn_size): ... this.
(append_insn, mips16_ip): Update accordingly.
(micromips_insn_length): New function.
(insn_length): Return the length of microMIPS instructions.
(mips_record_mips16_mode): Rename to...
(mips_record_mips16_micromips_mode): ... this. Handle
microMIPS.
(install_insn): Handle microMIPS.
(is_size_valid, is_delay_slot_valid): New functions.
(md_begin): Handle microMIPS.
(md_assemble): Likewise. Update for append_insn interface
change.
(micromips_reloc_p): New function.
(got16_reloc_p): Handle microMIPS.
(hi16_reloc_p): Likewise.
(lo16_reloc_p): Likewise.
(matching_lo_reloc): Likewise.
(mips_move_labels): Likewise.
(mips_mark_labels): New function.
(mips16_mark_labels): Rename to...
(mips_compressed_mark_labels): ... this. Handle microMIPS.
(insns_between): Handle microMIPS.
(MICROMIPS_LABEL_CHAR): New macro.
(micromips_target_label, micromips_target_name): New variables.
(micromips_label_name, micromips_label_expr): New functions.
(micromips_label_inc, micromips_add_label): Likewise.
(mips_label_is_local): Likewise.
(append_insn): Add expansionp argument. Handle microMIPS.
(start_noreorder, end_noreorder): Handle microMIPS.
(macro_start, macro_warning, macro_end): Likewise.
(lui_fmt, shft_fmt): New variables.
(LUI_FMT, SHFT_FMT): New macros.
(macro_map_reloc): New function.
(macro_build): Handle microMIPS. Update for append_insn
interface change.
(mips16_macro_build): Update for append_insn interface change.
(macro_build_jalr): Handle microMIPS.
(macro_build_lui): Likewise. Update for append_insn interface
change.
(macro_build_ldst_constoffset): Use relocation wrappers.
(set_at): Likewise.
(load_register): Likewise.
(load_address): Likewise.
(move_register): Handle microMIPS.
(load_got_offset): Use relocation wrappers.
(add_got_offset): Likewise.
(add_got_offset_hilo): Likewise.
(macro): Handle microMIPS.
(validate_micromips_insn): New function.
(micromips_percent_op): New variable.
(parse_relocation): Handle microMIPS.
(my_getExpression): Likewise.
(options): Add OPTION_MICROMIPS and OPTION_NO_MICROMIPS.
(md_longopts): Add mmicromips and mno-micromips.
(md_parse_option): Handle OPTION_MICROMIPS and
OPTION_NO_MICROMIPS.
(mips_after_parse_args): Handle microMIPS.
(md_pcrel_from): Handle microMIPS relocations.
(mips_force_relocation): Likewise.
(md_apply_fix): Likewise.
(mips_align): Handle microMIPS.
(s_mipsset): Likewise.
(s_cpload, s_cpsetup, s_cpreturn): Use relocation wrappers.
(s_dtprel_internal): Likewise.
(s_gpword, s_gpdword): Likewise.
(s_insn): Handle microMIPS.
(s_mips_stab): Likewise.
(relaxed_micromips_32bit_branch_length): New function.
(relaxed_micromips_16bit_branch_length): New function.
(md_estimate_size_before_relax): Handle microMIPS.
(mips_fix_adjustable): Likewise.
(tc_gen_reloc): Handle microMIPS relocations.
(mips_relax_frag): Handle microMIPS.
(md_convert_frag): Likewise.
(mips_frob_file_after_relocs): Likewise.
(mips_elf_final_processing): Likewise.
(mips_nop_opcode): Likewise.
(mips_handle_align): Likewise.
(md_show_usage): Handle microMIPS options.
(micromips_ip): New function.
(micromips_macro_build): Likewise.
(micromips_macro): Likewise.
* symbols.c (TC_LABEL_IS_LOCAL): New macro.
(S_IS_LOCAL): Add a TC_LABEL_IS_LOCAL check.
* doc/as.texinfo (Target MIPS options): Add -mmicromips and
-mno-micromips.
(-mmicromips, -mno-micromips): New options.
* doc/c-mips.texi (-mmicromips, -mno-micromips): New options.
(MIPS ISA): Document .set micromips and .set nomicromips.
gas/testsuite/
2010-07-26 Maciej W. Rozycki <macro@codesourcery.com>
Chao-ying Fu <fu@mips.com>
* gas/mips/micromips.d: New test.
* gas/mips/micromips-trap.d: Likewise.
* gas/mips/micromips-branch-relax-pic.d: Likewise.
* gas/mips/micromips-branch-relax-pic.d: Likewise.
* gas/mips/micromips.l: New stderr output.
* gas/mips/micromips-branch-relax.l: Likewise.
* gas/mips/micromips-branch-relax-pic.l: Likewise.
* gas/mips/micromips.s: New test source.
* gas/mips/micromips-branch-relax.s: Likewise.
* gas/mips/mips.exp: Run the new tests.
* gas/mips/micromips@abs.d: New test.
* gas/mips/micromips@add.d: Likewise.
* gas/mips/micromips@and.d: Likewise.
* gas/mips/micromips@beq.d: Likewise.
* gas/mips/micromips@bge.d: Likewise.
* gas/mips/micromips@bgeu.d: Likewise.
* gas/mips/micromips@blt.d: Likewise.
* gas/mips/micromips@bltu.d: Likewise.
* gas/mips/micromips@branch-likely.d: Likewise.
* gas/mips/micromips@branch-misc-1.d: Likewise.
* gas/mips/micromips@branch-misc-2-64.d: Likewise.
* gas/mips/micromips@branch-misc-2.d: Likewise.
* gas/mips/micromips@branch-misc-2pic-64.d: Likewise.
* gas/mips/micromips@branch-misc-2pic.d: Likewise.
* gas/mips/micromips@dli.d: Likewise.
* gas/mips/micromips@elf-jal.d: Likewise.
* gas/mips/micromips@elf-rel2.d: Likewise.
* gas/mips/micromips@elf-rel4.d: Likewise.
* gas/mips/micromips@lb-svr4pic-ilocks.d: Likewise.
* gas/mips/micromips@li.d: Likewise.
* gas/mips/micromips@mips1-fp.d: Likewise.
* gas/mips/micromips@mips32-cp2.d: Likewise.
* gas/mips/micromips@mips32-imm.d: Likewise.
* gas/mips/micromips@mips32-sf32.d: Likewise.
* gas/mips/micromips@mips32.d: Likewise.
* gas/mips/micromips@mips32r2-cp2.d: Likewise.
* gas/mips/micromips@mips32r2-fp32.d: Likewise.
* gas/mips/micromips@mips32r2.d: Likewise.
* gas/mips/micromips@mips4-branch-likely.d: Likewise.
* gas/mips/micromips@mips4-fp.d: Likewise.
* gas/mips/micromips@mips4.d: Likewise.
* gas/mips/micromips@mips5.d: Likewise.
* gas/mips/micromips@mips64-cp2.d: Likewise.
* gas/mips/micromips@mips64.d: Likewise.
* gas/mips/micromips@mips64r2.d: Likewise.
* gas/mips/micromips@rol-hw.d: Likewise.
* gas/mips/micromips@uld2-eb.d: Likewise.
* gas/mips/micromips@uld2-el.d: Likewise.
* gas/mips/micromips@ulh2-eb.d: Likewise.
* gas/mips/micromips@ulh2-el.d: Likewise.
* gas/mips/micromips@ulw2-eb-ilocks.d: Likewise.
* gas/mips/micromips@ulw2-el-ilocks.d: Likewise.
* gas/mips/mips32-imm.d: Likewise.
* gas/mips/mips32.d: Update immediates.
* gas/mips/micromips@mips32-cp2.s: New test source.
* gas/mips/micromips@mips32-imm.s: Likewise.
* gas/mips/micromips@mips32r2-cp2.s: Likewise.
* gas/mips/micromips@mips64-cp2.s: Likewise.
* gas/mips/mips32-imm.s: Likewise.
* gas/mips/mips32.s: Handle microMIPS.
* gas/mips/elf-rel27.d: Likewise.
* gas/mips/mips.exp: Add the micromips arch. Exclude mips16e
from micromips. Run mips32-imm.
* gas/mips/jal-mask-11.d: New test.
* gas/mips/jal-mask-12.d: Likewise.
* gas/mips/micromips@jal-mask-11.d: Likewise.
* gas/mips/jal-mask-1.s: Source for the new tests.
* gas/mips/jal-mask-21.d: New test.
* gas/mips/jal-mask-22.d: Likewise.
* gas/mips/micromips@jal-mask-12.d: Likewise.
* gas/mips/jal-mask-2.s: Source for the new tests.
* gas/mips/mips.exp: Run the new tests.
* gas/mips/and.s: Adjust padding.
* gas/mips/beq.s: Likewise.
* gas/mips/bge.s: Likewise.
* gas/mips/bgeu.s: Likewise.
* gas/mips/blt.s: Likewise.
* gas/mips/bltu.s: Likewise.
* gas/mips/branch-misc-2.s: Likewise.
* gas/mips/jal.s: Likewise.
* gas/mips/li.s: Likewise.
* gas/mips/mips1-fp.s: Likewise.
* gas/mips/mips32r2-fp32.s: Likewise.
* gas/mips/mips64.s: Likewise.
* gas/mips/mips4.s: Likewise.
* gas/mips/mips4-fp.s: Likewise.
* gas/mips/and.d: Update accordingly.
* gas/mips/elf-jal.d: Likewise.
* gas/mips/jal.d: Likewise.
* gas/mips/li.d: Likewise.
* gas/mips/mips1-fp.d: Likewise.
* gas/mips/mips32r2-fp32.d: Likewise.
* gas/mips/mips64.d: Likewise.
include/elf/
2010-07-26 Chao-ying Fu <fu@mips.com>
* mips.h (R_MICROMIPS_min): New relocations.
(R_MICROMIPS_26_S1): Likewise.
(R_MICROMIPS_HI16, R_MICROMIPS_LO16): Likewise.
(R_MICROMIPS_GPREL16, R_MICROMIPS_LITERAL): Likewise.
(R_MICROMIPS_GOT16, R_MICROMIPS_PC7_S1): Likewise.
(R_MICROMIPS_PC10_S1, R_MICROMIPS_PC16_S1): Likewise.
(R_MICROMIPS_CALL16, R_MICROMIPS_GOT_DISP): Likewise.
(R_MICROMIPS_GOT_PAGE, R_MICROMIPS_GOT_OFST): Likewise.
(R_MICROMIPS_GOT_HI16, R_MICROMIPS_GOT_LO16): Likewise.
(R_MICROMIPS_SUB, R_MICROMIPS_HIGHER): Likewise.
(R_MICROMIPS_HIGHEST, R_MICROMIPS_CALL_HI16): Likewise.
(R_MICROMIPS_CALL_LO16, R_MICROMIPS_SCN_DISP): Likewise.
(R_MICROMIPS_JALR, R_MICROMIPS_HI0_LO16): Likewise.
(R_MICROMIPS_TLS_GD, R_MICROMIPS_TLS_LDM): Likewise.
(R_MICROMIPS_TLS_DTPREL_HI, R_MICROMIPS_TLS_DTPREL_LO): Likewise.
(R_MICROMIPS_TLS_GOTTPREL): Likewise.
(R_MICROMIPS_TLS_TPREL_HI16): Likewise.
(R_MICROMIPS_TLS_TPREL_LO16): Likewise.
(R_MICROMIPS_GPREL7_S2, R_MICROMIPS_PC23_S2): Likewise.
(R_MICROMIPS_max): Likewise.
(EF_MIPS_ARCH_ASE_MICROMIPS): New macro.
(STO_MIPS_ISA, STO_MIPS_FLAGS): Likewise.
(ELF_ST_IS_MIPS_PLT, ELF_ST_SET_MIPS_PLT): Likewise.
(STO_MICROMIPS): Likewise.
(ELF_ST_IS_MICROMIPS, ELF_ST_SET_MICROMIPS): Likewise.
(ELF_ST_IS_COMPRESSED): Likewise.
(STO_MIPS_PLT, STO_MIPS_PIC): Rework.
(ELF_ST_IS_MIPS_PIC, ELF_ST_SET_MIPS_PIC): Likewise.
(STO_MIPS16, ELF_ST_IS_MIPS16, ELF_ST_SET_MIPS16): Likewise.
include/opcode/
2010-07-26 Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* mips.h
(INSN2_BRANCH_DELAY_16BIT, INSN2_BRANCH_DELAY_32BIT): New macros.
(INSN2_WRITE_GPR_S, INSN2_READ_FPR_D): Likewise.
(INSN2_MOD_GPR_MB, INSN2_MOD_GPR_MC, INSN2_MOD_GPR_MD): Likewise.
(INSN2_MOD_GPR_ME, INSN2_MOD_GPR_MF, INSN2_MOD_GPR_MG): Likewise.
(INSN2_MOD_GPR_MJ, INSN2_MOD_GPR_MP, INSN2_MOD_GPR_MQ): Likewise.
(INSN2_MOD_SP, INSN2_READ_GPR_31): Likewise.
(INSN2_READ_GP, INSN2_READ_PC): Likewise.
(CPU_MICROMIPS): New macro.
(M_BC1FL, M_BC1TL, M_BC2FL, M_BC2TL, M_BEQL, M_BGEZL): New enum
values.
(M_BGEZALL, M_BGTZL, M_BLEZL, M_BLTZL, M_BLTZALL): Likewise.
(M_CACHE_OB, M_LDC2_OB, M_LDL_OB, M_LDM_AB, M_LDM_OB): Likewise.
(M_LDP_AB, M_LDP_OB, M_LDR_OB, M_LL_OB, M_LLD_OB): Likewise.
(M_LWC2_OB, M_LWL_OB, M_LWM_AB, M_LWP_AB, M_LWP_OB): Likewise.
(M_LWR_OB, M_LWU_OB, M_PREF_OB, M_SC_OB, M_SCD_OB): Likewise.
(M_SDC2_OB, M_SDL_OB, M_SDM_AB, M_SDM_OB, M_SDP_AB): Likewise.
(M_SDP_OB, M_SDR_OB, M_SWC2_OB, M_SWL_OB, M_SWM_AB): Likewise.
(M_SWM_OB, M_SWP_AB, M_SWP_OB, M_SWR_OB): Likewise.
(MICROMIPSOP_MASK_MAJOR, MICROMIPSOP_SH_MAJOR): New macros.
(MICROMIPSOP_MASK_IMMEDIATE, MICROMIPSOP_SH_IMMEDIATE): Likewise.
(MICROMIPSOP_MASK_DELTA, MICROMIPSOP_SH_DELTA): Likewise.
(MICROMIPSOP_MASK_CODE10, MICROMIPSOP_SH_CODE10): Likewise.
(MICROMIPSOP_MASK_TRAP, MICROMIPSOP_SH_TRAP): Likewise.
(MICROMIPSOP_MASK_SHAMT, MICROMIPSOP_SH_SHAMT): Likewise.
(MICROMIPSOP_MASK_TARGET, MICROMIPSOP_SH_TARGET): Likewise.
(MICROMIPSOP_MASK_EXTLSB, MICROMIPSOP_SH_EXTLSB): Likewise.
(MICROMIPSOP_MASK_EXTMSBD, MICROMIPSOP_SH_EXTMSBD): Likewise.
(MICROMIPSOP_MASK_INSMSB, MICROMIPSOP_SH_INSMSB): Likewise.
(MICROMIPSOP_MASK_BREAKCODE, MICROMIPSOP_SH_BREAKCODE): Likewise.
(MICROMIPSOP_SH_BREAKCODE2): Likewise.
(MICROMIPSOP_MASK_CACHEOP, MICROMIPSOP_SH_CACHEOP): Likewise.
(MICROMIPSOP_MASK_COPSEL, MICROMIPSOP_SH_COPSEL): Likewise.
(MICROMIPSOP_MASK_OFFSET12, MICROMIPSOP_SH_OFFSET12): Likewise.
(MICROMIPSOP_MASK_3BITPOS, MICROMIPSOP_SH_3BITPOS): Likewise.
(MICROMIPSOP_MASK_STYPE, MICROMIPSOP_SH_STYPE): Likewise.
(MICROMIPSOP_MASK_OFFSET10, MICROMIPSOP_SH_OFFSET10): Likewise.
(MICROMIPSOP_MASK_RS, MICROMIPSOP_SH_RS): Likewise.
(MICROMIPSOP_MASK_RT, MICROMIPSOP_SH_RT): Likewise.
(MICROMIPSOP_MASK_RD, MICROMIPSOP_SH_RD): Likewise.
(MICROMIPSOP_MASK_FS, MICROMIPSOP_SH_FS): Likewise.
(MICROMIPSOP_MASK_FT, MICROMIPSOP_SH_FT): Likewise.
(MICROMIPSOP_MASK_FD, MICROMIPSOP_SH_FD): Likewise.
(MICROMIPSOP_MASK_FR, MICROMIPSOP_SH_FR): Likewise.
(MICROMIPSOP_MASK_RS3, MICROMIPSOP_SH_RS3): Likewise.
(MICROMIPSOP_MASK_PREFX, MICROMIPSOP_SH_PREFX): Likewise.
(MICROMIPSOP_MASK_BCC, MICROMIPSOP_SH_BCC): Likewise.
(MICROMIPSOP_MASK_CCC, MICROMIPSOP_SH_CCC): Likewise.
(MICROMIPSOP_MASK_COPZ, MICROMIPSOP_SH_COPZ): Likewise.
(MICROMIPSOP_MASK_MB, MICROMIPSOP_SH_MB): Likewise.
(MICROMIPSOP_MASK_MC, MICROMIPSOP_SH_MC): Likewise.
(MICROMIPSOP_MASK_MD, MICROMIPSOP_SH_MD): Likewise.
(MICROMIPSOP_MASK_ME, MICROMIPSOP_SH_ME): Likewise.
(MICROMIPSOP_MASK_MF, MICROMIPSOP_SH_MF): Likewise.
(MICROMIPSOP_MASK_MG, MICROMIPSOP_SH_MG): Likewise.
(MICROMIPSOP_MASK_MJ, MICROMIPSOP_SH_MJ): Likewise.
(MICROMIPSOP_MASK_ML, MICROMIPSOP_SH_ML): Likewise.
(MICROMIPSOP_MASK_MP, MICROMIPSOP_SH_MP): Likewise.
(MICROMIPSOP_MASK_MQ, MICROMIPSOP_SH_MQ): Likewise.
(MICROMIPSOP_MASK_MZ, MICROMIPSOP_SH_MZ): Likewise.
(MICROMIPSOP_MASK_IMMA, MICROMIPSOP_SH_IMMA): Likewise.
(MICROMIPSOP_MASK_IMMB, MICROMIPSOP_SH_IMMB): Likewise.
(MICROMIPSOP_MASK_IMMC, MICROMIPSOP_SH_IMMC): Likewise.
(MICROMIPSOP_MASK_IMMD, MICROMIPSOP_SH_IMMD): Likewise.
(MICROMIPSOP_MASK_IMME, MICROMIPSOP_SH_IMME): Likewise.
(MICROMIPSOP_MASK_IMMF, MICROMIPSOP_SH_IMMF): Likewise.
(MICROMIPSOP_MASK_IMMG, MICROMIPSOP_SH_IMMG): Likewise.
(MICROMIPSOP_MASK_IMMH, MICROMIPSOP_SH_IMMH): Likewise.
(MICROMIPSOP_MASK_IMMI, MICROMIPSOP_SH_IMMI): Likewise.
(MICROMIPSOP_MASK_IMMJ, MICROMIPSOP_SH_IMMJ): Likewise.
(MICROMIPSOP_MASK_IMML, MICROMIPSOP_SH_IMML): Likewise.
(MICROMIPSOP_MASK_IMMM, MICROMIPSOP_SH_IMMM): Likewise.
(MICROMIPSOP_MASK_IMMN, MICROMIPSOP_SH_IMMN): Likewise.
(MICROMIPSOP_MASK_IMMO, MICROMIPSOP_SH_IMMO): Likewise.
(MICROMIPSOP_MASK_IMMP, MICROMIPSOP_SH_IMMP): Likewise.
(MICROMIPSOP_MASK_IMMQ, MICROMIPSOP_SH_IMMQ): Likewise.
(MICROMIPSOP_MASK_IMMU, MICROMIPSOP_SH_IMMU): Likewise.
(MICROMIPSOP_MASK_IMMW, MICROMIPSOP_SH_IMMW): Likewise.
(MICROMIPSOP_MASK_IMMX, MICROMIPSOP_SH_IMMX): Likewise.
(MICROMIPSOP_MASK_IMMY, MICROMIPSOP_SH_IMMY): Likewise.
(micromips_opcodes): New declaration.
(bfd_micromips_num_opcodes): Likewise.
* mips.h (INSN2_UNCOND_BRANCH, INSN2_COND_BRANCH): New macros.
* mips.h (INSN2_MOD_GPR_MHI): New macro.
(INSN2_MOD_GPR_MM, INSN2_MOD_GPR_MN): Likewise.
(MICROMIPSOP_MASK_MH, MICROMIPSOP_SH_MH): Likewise.
(MICROMIPSOP_MASK_MI, MICROMIPSOP_SH_MI): Likewise.
(MICROMIPSOP_MASK_MM, MICROMIPSOP_SH_MM): Likewise.
(MICROMIPSOP_MASK_MN, MICROMIPSOP_SH_MN): Likewise.
ld/testsuite/
2010-07-26 Catherine Moore <clm@codesourcery.com>
Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* ld-mips-elf/jalx-1.s: New test source.
* ld-mips-elf/jalx-1.d: New test output.
* ld-mips-elf/jalx-1.ld: New test linker script.
* ld-mips-elf/jalx-2-main.s: New test source.
* ld-mips-elf/jalx-2-ex.s: Likewise.
* ld-mips-elf/jalx-2-printf.s: Likewise.
* ld-mips-elf/jalx-2.dd: New test output.
* ld-mips-elf/jalx-2.ld: New test linker script.
* ld-mips-elf/mips-elf.exp: Run the new tests
opcodes/
2010-07-26 Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* micromips-opc.c: New file.
* mips-dis.c (micromips_to_32_reg_b_map): New array.
(micromips_to_32_reg_c_map, micromips_to_32_reg_d_map): Likewise.
(micromips_to_32_reg_e_map, micromips_to_32_reg_f_map): Likewise.
(micromips_to_32_reg_g_map, micromips_to_32_reg_l_map): Likewise.
(micromips_to_32_reg_q_map): Likewise.
(micromips_imm_b_map, micromips_imm_c_map): Likewise.
(print_insn_micromips): New function.
(is_micromips_mode_p): New function.
(_print_insn_mips): Handle microMIPS instructions.
* Makefile.am (CFILES): Add micromips-opc.c.
* configure.in (bfd_mips_arch): Add micromips-opc.lo.
* Makefile.in: Regenerate.
* configure: Regenerate.
* mips-dis.c (micromips_to_32_reg_h_map): New variable.
(micromips_to_32_reg_i_map): Likewise.
(micromips_to_32_reg_m_map): Likewise.
(micromips_to_32_reg_n_map): New macro.
[-- Attachment #2: Type: APPLICATION/octet-stream, Size: 146364 bytes --]
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2010-07-26 10:56 ` [PATCH] MIPS: microMIPS ASE support Maciej W. Rozycki
@ 2010-07-26 13:25 ` Nathan Froyd
2010-07-26 13:53 ` Maciej W. Rozycki
2010-07-26 19:03 ` Richard Sandiford
1 sibling, 1 reply; 41+ messages in thread
From: Nathan Froyd @ 2010-07-26 13:25 UTC (permalink / raw)
To: Maciej W. Rozycki
Cc: Richard Sandiford, binutils, Chao-ying Fu, Rich Fuhler,
David Lau, Kevin Mills, Ilie Garbacea, Catherine Moore,
Nathan Sidwell, Joseph Myers
On Mon, Jul 26, 2010 at 11:55:20AM +0100, Maciej W. Rozycki wrote:
> > Did you actually test this with n64, say with a gcc bootstrap? Same
> > comment goes for elfn32-mips.c.
> >
> > Why only do the linker relaxation for elf32-mips.c (o32, o64 & EABI)?
> > Why not for n32 and n64 too?
>
> The answer to all the questions is negative. There is no 64-bit
> microMIPS hardware available at the moment. The best bet might be QEMU --
> NathanF, have you implemented any of the 64-bit instructions in QEMU?
I have implemented support for the 64-bit instructions in QEMU. I
haven't really tested whether the instruction translation works
correctly for those instructions. (It should; there's nothing unusual
about the codepaths the 64-bit instructions take vs. their 32-bit
counterparts...but you never know...)
-Nathan
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2010-07-26 13:25 ` Nathan Froyd
@ 2010-07-26 13:53 ` Maciej W. Rozycki
0 siblings, 0 replies; 41+ messages in thread
From: Maciej W. Rozycki @ 2010-07-26 13:53 UTC (permalink / raw)
To: Nathan Froyd
Cc: Richard Sandiford, binutils, Chao-ying Fu, Rich Fuhler,
David Lau, Kevin Mills, Ilie Garbacea, Catherine Moore,
Nathan Sidwell, Joseph Myers
On Mon, 26 Jul 2010, Nathan Froyd wrote:
> > > Did you actually test this with n64, say with a gcc bootstrap? Same
> > > comment goes for elfn32-mips.c.
> > >
> > > Why only do the linker relaxation for elf32-mips.c (o32, o64 & EABI)?
> > > Why not for n32 and n64 too?
> >
> > The answer to all the questions is negative. There is no 64-bit
> > microMIPS hardware available at the moment. The best bet might be QEMU --
> > NathanF, have you implemented any of the 64-bit instructions in QEMU?
>
> I have implemented support for the 64-bit instructions in QEMU. I
> haven't really tested whether the instruction translation works
> correctly for those instructions. (It should; there's nothing unusual
> about the codepaths the 64-bit instructions take vs. their 32-bit
> counterparts...but you never know...)
OK, thanks. That's a good starting point, but still some low-level
startup files will need to be updated or at least examined for correct
64-bit microMIPS support before we can link executables suitable for
run-time testing such as with the GCC testsuite, let alone a full native
GCC bootstrap.
Maciej
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2010-07-26 10:56 ` [PATCH] MIPS: microMIPS ASE support Maciej W. Rozycki
2010-07-26 13:25 ` Nathan Froyd
@ 2010-07-26 19:03 ` Richard Sandiford
2010-12-07 1:13 ` Maciej W. Rozycki
1 sibling, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2010-07-26 19:03 UTC (permalink / raw)
To: Maciej W. Rozycki
Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers,
Nathan Froyd
Hi Maciej,
Thanks for the huge effort in updating this patch. Aside from the
gas macro handling (see below) it's looking much better, and I don't
think there are many issues blocking it going in. I'll try to find
time to read over the patch properly in the next week or so.
"Maciej W. Rozycki" <macro@codesourcery.com> writes:
>> > > > (A_BFD_RELOC_HI16_S, A_BFD_RELOC_HI16, A_BFD_RELOC_LO16): New
>> > > > relocation wrapper macros.
>> > > > (A_BFD_RELOC_GPREL16): Likewise.
>> > > > (A_BFD_RELOC_MIPS_GOT16, A_BFD_RELOC_MIPS_GOT_HI16): Likewise.
>> > > > (A_BFD_RELOC_MIPS_GOT_LO16, A_BFD_RELOC_MIPS_HIGHEST): Likewise.
>> > > > (A_BFD_RELOC_MIPS_HIGHER, A_BFD_RELOC_MIPS_GOT_DISP): Likewise.
>> > > > (A_BFD_RELOC_MIPS_GOT_PAGE, A_BFD_RELOC_MIPS_GOT_OFST):
>> > Likewise.
>> > > > (A_BFD_RELOC_MIPS_SUB, A_BFD_RELOC_MIPS_JALR): Likewise.
>> > >
>> > > Did you consider doing the translation from non-microMIPS to
>> > > microMIPS in the macro_* functions, rather than in their callers?
>> > > I fear it'll be too easy to accidentally forget to use
>> > A_BFD_* in future.
>> >
>> > Agreed, I didn't like the new macros from the very
>> > beginning. Chao-ying
>> > -- any thoughts?
>>
>> I am fine. But the new method may be bigger than the A_BFD* method.
>
> I have placed the translation in macro_map_reloc() now. That incurs an
> O(n) performance penalty because all relocations in the microMIPS mode
> have to be iterated over the table of mappings; regrettably BFD_RELOC_*
> definitions are sparse so an O(1) lookup table cannot be used. By keeping
> it sorted some time can be saved, but that's still O(n). This could be
> reduced to O(log n) with a binary search, but I fear with the limited
> number of relocs handled the overhead would kill the benefit.
TBH, I think a case statement would be fine here. It's then up to
the compiler to pick the best implementation.
>> > (MICROMIPS_TARGET, MICROMIPS_TARGET_LABEL): New macros.
>> > (micromips_add_number_label): New function.
>>
>> +/* For microMIPS macros, we need to generate a local number label
>> + as the target of branches. */
>> +#define MICROMIPS_TARGET "2147483647f"
>> +#define MICROMIPS_TARGET_LABEL 2147483647
>> +
>> +static void
>> +micromips_add_number_label (void)
>> +{
>> + symbolS *s;
>> + fb_label_instance_inc (MICROMIPS_TARGET_LABEL);
>> + s = colon (fb_label_name (MICROMIPS_TARGET_LABEL, 0));
>> + S_SET_OTHER (s, ELF_ST_SET_MICROMIPS (S_GET_OTHER (s)));
>> +}
>> +
>>
>> Ugh, this is a bit hackish. There's nothing stopping a user using
>> 2147483647f themselves.
>
> This is now handled by micromips_label_name(), micromips_label_expr(),
> micromips_label_inc() and micromips_add_label() in a manner similar to
> what dollar_label_name() and fb_label_name(), etc. do, except that the
> special character used in symbols generated is ^_, avoiding a clash.
Thanks, this looks better at first glance.
> I have rewritten macro_end() entirely now. I have changed the approach
> such that if multiple instructions are emitted into a branch delay slot
> and the first of these instructions is out of size, then two warnings are
> produced.
>
> The rationale is these are different classes of warnings -- the delay
> slot size mismatch is fatal if the call is ever returned from. Multiple
> instructions may or may not be a problem depending on the actual piece of
> code and author's intentions. We had a discussion about it a few years
> ago. ;)
>
> To complete these changes I have modified the change to append_insn()
> such that no warning is produced for a delay slot size mismatch if called
> for a macro expansion as it would get in the way, especially in the case
> of relaxation. The API of this function had to be modified in a trivial
> way and all the callers adjusted accordingly.
I'll have to think about this a bit. And dig out that conversation ;-)
>> >> From a usability perspective, it's a shame that:
>> >>
>> >> .set micromips
>> >> .ent foo
>> >> foo:
>> >> b 1f
>> >> nop
>> >> .end foo
>> >> .ent bar
>> >> bar:
>> >> 1: nop
>> >> .end bar
>> >>
>> >> disassembles as:
>> >>
>> >> 00000000 <foo>:
>> >> 0: cfff b 0 <foo>
>> >> 0: R_MICROMIPS_PC10_S1 .L11
>> >> 2: 0c00 nop
>> >> 4: 0c00 nop
>> >>
>> >> 00000006 <bar>:
>> >> 6: 0c00 nop
>> >>
>> >> leaving the poor user with no idea what .L11 is.
>> >
>> > Indeed. This is a general limitation of `objdump' it would seem. This
>> > is no different to what you get with:
>> >
>> > $ cat b.s
>> > .globl baz
>> > .ent foo
>> > foo:
>> > b baz
>> > nop
>> > .end foo
>> > .ent bar
>> > baz:
>> > bar:
>> > 1: nop
>> > .end bar
>> > $ mips-sde-elf-objdump -dr b.o
>> >
>> > b.o: file format elf32-tradbigmips
>> >
>> >
>> > Disassembly of section .text:
>> >
>> > 00000000 <foo>:
>> > 0: 1000ffff b 0 <foo>
>> > 0: R_MIPS_PC16 baz
>> > 4: 00000000 nop
>> > 8: 00000000 nop
>> >
>> > 0000000c <bar>:
>> > c: 00000000 nop
>>
>> Well, it's a little different. The user has at least defined two
>> named symbols in this case, so they have a good chance of knowing
>> what "baz" means. In the microMIPS case we've invented a label
>> and are using it in preference to the user-defined one.
>
> That's unfortunate, indeed. [FIXME]
Have you looked into the work involved, before this gets dismissed
entirely as future work?
>> > I'd just recommend peeking at the symbol table (back to the first
>> > program):
>> >
>> > $ mips-sde-elf-objdump -t b.o
>> >
>> > b.o: file format elf32-tradbigmips
>> >
>> > SYMBOL TABLE:
>> > 00000000 l d .text 00000000 .text
>> > 00000000 l d .data 00000000 .data
>> > 00000000 l d .bss 00000000 .bss
>> > 00000000 l d .reginfo 00000000 .reginfo
>> > 00000000 l d .pdr 00000000 .pdr
>> > 00000000 l F .text 00000006 0x80 foo
>> > 00000006 l F .text 00000002 0x80 bar
>> > 00000006 l .text 00000000 0x80 .L1^B1
>>
>> I suppose having a symbol with ^B in it is less than ideal too.
>> AIUI that name was chosen specifically because it wasn't supposed
>> to be written out.
>>
>> It would be especially confusing if the user or compiler had a ".L11"
>> label (without the ^B).
>
> Actually this is a tough problem -- we need to emit a generated symbol
> that does not clash with anything the user or GCC may have put in the
> source. Any ideas? How is it done in other ports if anywhere?
None off-hand. Seggestions from others very welcome.
I'll try to think of something when I've got more time. For avoidance
of doubt, I think this does need to be fixed.
>> @@ -14813,6 +16230,8 @@ mips_elf_final_processing (void)
>> file_ase_mt is true. */
>> if (file_ase_mips16)
>> elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_M16;
>> + if (file_ase_micromips)
>> + elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_MICROMIPS;
>> #if 0 /* XXX FIXME */
>> if (file_ase_mips3d)
>> elf_elfheader (stdoutput)->e_flags |= ???;
>>
>> Do you really only want this flag to be set if -mmicromips was passed
>> on the command line? (Yes, the same concern applies to MIPS16 and MDMX.)
>
> Fixing it up is easy, but I'm not sure what the original intent of these
> flags has been. Do they mean:
>
> 1. I make use of the FOO feature and I assert it is available?
>
> 2. I make use of the FOO feature, but I may go and figure out if it's
> available?
>
> 3. I make use of the FOO feature and want to prevent linking with any
> incompatible ones?
>
> Once we've determined the answer we may modify code accordingly or leave
> it as it is. It looks to me the current approach matches #1 and the ELF
> program loader may refuse to execute the program if it sees a flag for a
> feature that is not supported by the processor to run on. Any .set
> fragments within the program are guarded appropriately and hence they do
> not need to set the flag (as it would be for #2). Then #3 is sort of
> tangential to the two others, but it does matter in this context, hence I
> mentioned it (i.e. if #3 was true, then I'd be much happier with #3 & #1
> than #3 & #2; otherwise I don't have a strong preference between #1 and
> #2).
>
> Current arrangement is similar to that of file_mips_isa even though the
> ISA can be overridden by .set too and I think it makes sense to keep all
> these flags consistent.
I think MIPS16 and microMIPS are fundamentally different from the ISA,
and even from MDMX. IMO, it's reasonable to assume that, if the user is
taking a MIPS III target as their base system, that they'll assemble
with a MIPS III ISA flag. I know others disagree, and think that such
things should always be specified by pseudo-ops. Even if you're of that
opinion, though, it's easy in principle to set the flags to the minimum
ISA required by the assembly source.
MIPS16 and microMIPS are different because they represent an operating
mode that the processor can switch in and out of. The fact that the
assembly source contains both MIPS16 and non-MIPS16 code isn't really a
good indicator that the code is designed to cope with non-MIPS16-capable
systems.
We could live without deciding between #1, #2 and #3 until now because
MIPS16 was the only feature like this. Now that we've got two
incompatible code-compression methods, I think it's more important.
I too would like to hear other opinions. I'm just not convinced by
the "it's similar to ISA selection" argument. More below.
>> micromips_ip obviously started life as a cut-&-paste of mips_ip, and it
>> would have been nice to factor some code out. At least split out the
>> block beginning:
>>
>> + case 'F':
>> + case 'L':
>> + case 'f':
>> + case 'l':
>> + {
>>
>> which is identical between the two, and far too subtle to copy wholesale.
>> There may be other good opportunities too.
>
> Next time, I'm afraid. [FIXME]
Next time == next iteration? If so, that's fine, but I think this
has to be fixed for the patch to be acceptable.
>> The same cut-&-paste concerns apply to micromips_macro, which obviously
>> started out as a copy of macro(). I realise there are special cases
>> for micromips (such as the DADDI assymmetry and the lack of
>> branch-likely instructions, to name only a few), but most of the
>> basic decisions are the same.
>>
>> As it stands, we have a new 3524 line function, of which I imagine at
>> least 90% is shared with macro(). I really think the new microMIPS
>> macro handling should be integrated into macro() instead. Don't be
>> afraid of factoring out code from macro() if it makes it easier to
>> integrate the microMIPS code.
>
> Can we make it a follow-up patch sometime in the future? I'm not afraid
> of factoring code out of anywhere (I'm speaking of myself only of course),
> but at this point the effort is about the same as writing this whole stuff
> from scratch. :( [FIXME]
Sorry, I know it's a pain, but I just don't think the patch can go
in as it stands. The fact that the amount of work is so daunting
means that (even with the best of intentions, which I realise yours
are), that follow-up is unlikely to happen. In the meantime we'll
have a 3524-line function (haven't recalculated ;-)) that has to be
kept in sync with another even bigger function (or pair of functions),
and it just won't be obvious whether the divergences are deliberate
microMIPS differences or whether they're cases where the two functions
haven't been updated in the same way.
I remember how painful it was replacing the old macro relaxation
code so that it could support arbitrary alternatives. This sort
of thing would double that pain.
And it's not just (or even principally) about cut-&-paste phobia.
microMIPS has been deliberately designed to provide a great deal
of source-level backwards compatibility, so it's no surprise that
the two modes require very similar code, and very similar decisions.
I think having a single function handling both is actually significantly
clearer, because it calls out which differences are deliberate,
hopefully with a helpful bit of commentary where necessary.
As things stand, it's already a bit of an archaeology exercise trying
to decide what the differences actually are.
> Overall I'm a bit concerned about all this linker relaxation stuff -- it
> breaks -falign-jumps, -falign-labels and -falign-loops which may have a
> severe performance penalty and should therefore be enabled conditionally
> only, preferably where all the three options are set to 1 (meaning that
> would be naturally implied by -Os). A linker option would be required an
> set appropriately by the GCC driver. [FIXME]
Yeah, I agree a bit more rigour would be nice here. Without it, though,
I think it's generally OK to assume that anyone using MIPS16 or microMIPS
is more of the -Os rather than -O2 mindset, so I agree this is at most a
FIXME.
>> Did you actually test this with n64, say with a gcc bootstrap? Same
>> comment goes for elfn32-mips.c.
>>
>> Why only do the linker relaxation for elf32-mips.c (o32, o64 & EABI)?
>> Why not for n32 and n64 too?
>
> The answer to all the questions is negative. There is no 64-bit
> microMIPS hardware available at the moment. The best bet might be QEMU --
> NathanF, have you implemented any of the 64-bit instructions in QEMU?
> Otherwise there's probably no way do do any of 64-bit microMIPS testing
> beside what's done in binutils. And no library work of any kind has
> started for 64-bit microMIPS support AFAIK. Hence there has been little
> incentive to attempt anything but rudimentary support for 64-bit ABIs.
OK, in that case, never mind about testing 64-bit ;-) However...
> I envisage all the relaxation stuff to be either moved over to
> elfxx-mips.c or copied to elfn32-mips.c and elf64-mips.c, as applicable,
> once we have real 64-bit support.
...I still think this stuff should start life in elfxx-mips.c, even if
it's only used by elf32-mips.c at first.
>> That said, why split these up? bfd_{get,put}_32
>> don't require aligned addresses.
>
> I think it's easier and more readable this way as with bfd_{get,put}_32()
> you'd have to halfword-swap the bit patterns produced based on the target
> endianness.
Hmm, good point ;-)
>> @@ -5127,12 +5200,26 @@ mips_elf_calculate_relocation (bfd *abfd
>> + h->la25_stub->stub_section->output_offset
>> + h->la25_stub->offset);
>>
>> + /* Make sure MIPS16 and microMIPS are not used together. */
>> + if ((r_type == R_MIPS16_26 && target_is_micromips_code_p)
>> + || (r_type == R_MICROMIPS_26_S1 && target_is_16_bit_code_p))
>> + {
>> + (*_bfd_error_handler)
>> + (_("MIPS16 and microMIPS functions cannot call each other"));
>> + return bfd_reloc_notsupported;
>> + }
>>
>> Should this be extended to check for branches too?
>
> That would be a useful improvement I suppose, but MIPS16 code doesn't
> care either (you can't use a branch to switch the ISA mode). Overall I
> think it's a corner case -- branches to external symbols are a rarity.
> [FIXME]
But it is (or feels like) something that people have asked about on many
occasions, before we decided to ignore the botched ABI definition of
R_MIPS_PC16.
If it was a lot of work, I'd be sympathetic, but I think this is
something that's easily done, and handling one pair of relocs without
the others seems inconsistent.
> I think R_MIPS_26 should be used for microMIPS JALX. I don't like the
> idea of overloading R_MICROMIPS_26_S1 this way, especially given another
> relocation already fits. What do you think? It is too late to fix the
> ABI probably though; I'm thinking what the consequences might be...
TBH, I quite like having a different reloc for the microMIPS version.
I agree it's probably moot though; the ABI has already been set.
>> Use of 0xfffffffc isn't portable for 64-bit addresses;
>> use "-4" or "~(bfd_vma) 3" instead.
>
> I'm nasty enough to use (foo | 3) ^ 3 and avoid type width and promotion
> dependencies altogether in such cases and hope for GCC to be smart and do
> the right thing and combine the two ops.
Hmm, well... TBH, I don't really see that as an improvement over the
other two -- C is C -- but I'll let it pass ;-)
>> - /* If this is an odd-valued function symbol, assume it's a MIPS16 one. */
>> + /* If this is an odd-valued function symbol, assume it's a MIPS16
>> + or microMIPS one. */
>> if (ELF_ST_TYPE (elfsym->internal_elf_sym.st_info) == STT_FUNC
>> && (asym->value & 1) != 0)
>> {
>> asym->value--;
>> - elfsym->internal_elf_sym.st_other
>> - = ELF_ST_SET_MIPS16 (elfsym->internal_elf_sym.st_other);
>> + if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS)
>> + elfsym->internal_elf_sym.st_other
>> + = ELF_ST_SET_MICROMIPS (elfsym->internal_elf_sym.st_other);
>> + else
>> + elfsym->internal_elf_sym.st_other
>> + = ELF_ST_SET_MIPS16 (elfsym->internal_elf_sym.st_other);
>> }
>> }
>>
>>
>> So a file can't mix MIPS16 and microMIPS code? We should probably
>> detect that explicitly. I'd like a clear statement of what the
>> interoperability restrictions are.
>>
>> This goes back to the question of when EF_MIPS_ARCH_ASE_MICROMIPS
>> should be set (see previous reviews).
>
> Background information first -- you can't have a piece of MIPS hardware,
> either real or simulated, with the MIPS16 ASE and the microMIPS ASE
> implemented both at a time. This is a design assumption that allowed the
> ISA bit to be overloaded.
>
> That obviously does not mean -- in principle -- that you can't have an
> executable (or one plus a mixture of shared libraries) where some
> functions are MIPS16 code and some are microMIPS code, either of which
> only called once the presence of the respective ASE has been determined.
> While a valid configuration this is also a rare exotic corner case -- I
> could imagine a piece of generic, processor-independent console/bootstrap
> firmware like this for example, but little beyond that.
>
> We had a discussion about it and the conclusion was from the user's
> perspective the most beneficial configuration is one where mixing MIPS16
> and microMIPS code within a single executable is forbidden by default.
> The reason is a build-time error is always better than a run-time one
> (especially when the device has been placed out there in the field
> already; hopefully not an Ariane 5 rocket) and the case where mixing
> MIPS16 and microMIPS code would almost always happen is when the user
> picked the wrong library by mistake. It is therefore most productive to
> fail at this point rather than later.
I agree. In that case, though, I think it's important that we go for #1
in your list above, otherwise this check doesn't really count for much.
I think having a way of forcing interpretation #2 fits into the same
category as...
> A future enhancement could add assembler and linker switches to override
> this default and mix the two ASEs in a single executable. [FIXME]
...this, which I agree is best left for future work.
>> + else if ((insn & 0x1c00) != 0x0400
>> + && (insn & 0x1c00) != 0x0800
>> + && (insn & 0x1c00) != 0x0c00)
>> + {
>> + /* This is a 32-bit microMIPS instruction. */
>> + higher = insn;
>> +
>> + status = (*info->read_memory_func) (memaddr + 2, buffer, 2, info);
>> + if (status != 0)
>> + {
>> + (*info->fprintf_func) (info->stream, "micromips 0x%x",
>> + (unsigned int) higher);
>> + (*info->memory_error_func) (status, memaddr + 2, info);
>> + return -1;
>> + }
>>
>> Why print "micromips " here but not in the 48-byte case?
>
> It looks to me it's been modelled after the MIPS16 version where "extend
> 0x..." is printed in the case of a read error. I'm not sure if either
> makes sense (.byte foo or suchlike that some other ports output in such a
> case looks more reasonable to me), but at least it is consistent.
Hmm, and MIPS16 doesn't print a prefix for unknown 4-byte ops.
OK, in that case, I agree the patch is right for consistency.
I agree with you about .byte being better in principle though,
as a possible future enhancement.
Richard
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2010-07-26 19:03 ` Richard Sandiford
@ 2010-12-07 1:13 ` Maciej W. Rozycki
2010-12-12 14:59 ` Richard Sandiford
2011-01-02 11:36 ` Richard Sandiford
0 siblings, 2 replies; 41+ messages in thread
From: Maciej W. Rozycki @ 2010-12-07 1:13 UTC (permalink / raw)
To: Richard Sandiford
Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers,
Nathan Froyd
[-- Attachment #1: Type: TEXT/PLAIN, Size: 49740 bytes --]
Hi Richard,
It's been a while, but time has been spent well and here's the next
update to the code. I believe I have addressed all your concerns. Some
detailed notes follow below.
> > I have placed the translation in macro_map_reloc() now. That incurs an
> > O(n) performance penalty because all relocations in the microMIPS mode
> > have to be iterated over the table of mappings; regrettably BFD_RELOC_*
> > definitions are sparse so an O(1) lookup table cannot be used. By keeping
> > it sorted some time can be saved, but that's still O(n). This could be
> > reduced to O(log n) with a binary search, but I fear with the limited
> > number of relocs handled the overhead would kill the benefit.
>
> TBH, I think a case statement would be fine here. It's then up to
> the compiler to pick the best implementation.
Hmm, maybe, maybe not. Anyway my proposal is semantically correct, so if
you'd like to improve it, then please feel free. ;)
> > I have rewritten macro_end() entirely now. I have changed the approach
> > such that if multiple instructions are emitted into a branch delay slot
> > and the first of these instructions is out of size, then two warnings are
> > produced.
> >
> > The rationale is these are different classes of warnings -- the delay
> > slot size mismatch is fatal if the call is ever returned from. Multiple
> > instructions may or may not be a problem depending on the actual piece of
> > code and author's intentions. We had a discussion about it a few years
> > ago. ;)
> >
> > To complete these changes I have modified the change to append_insn()
> > such that no warning is produced for a delay slot size mismatch if called
> > for a macro expansion as it would get in the way, especially in the case
> > of relaxation. The API of this function had to be modified in a trivial
> > way and all the callers adjusted accordingly.
>
> I'll have to think about this a bit. And dig out that conversation ;-)
Have you?
> >> >> From a usability perspective, it's a shame that:
> >> >>
> >> >> .set micromips
> >> >> .ent foo
> >> >> foo:
> >> >> b 1f
> >> >> nop
> >> >> .end foo
> >> >> .ent bar
> >> >> bar:
> >> >> 1: nop
> >> >> .end bar
> >> >>
> >> >> disassembles as:
> >> >>
> >> >> 00000000 <foo>:
> >> >> 0: cfff b 0 <foo>
> >> >> 0: R_MICROMIPS_PC10_S1 .L11
> >> >> 2: 0c00 nop
> >> >> 4: 0c00 nop
> >> >>
> >> >> 00000006 <bar>:
> >> >> 6: 0c00 nop
> >> >>
> >> >> leaving the poor user with no idea what .L11 is.
> >> >
> >> > Indeed. This is a general limitation of `objdump' it would seem. This
> >> > is no different to what you get with:
> >> >
> >> > $ cat b.s
> >> > .globl baz
> >> > .ent foo
> >> > foo:
> >> > b baz
> >> > nop
> >> > .end foo
> >> > .ent bar
> >> > baz:
> >> > bar:
> >> > 1: nop
> >> > .end bar
> >> > $ mips-sde-elf-objdump -dr b.o
> >> >
> >> > b.o: file format elf32-tradbigmips
> >> >
> >> >
> >> > Disassembly of section .text:
> >> >
> >> > 00000000 <foo>:
> >> > 0: 1000ffff b 0 <foo>
> >> > 0: R_MIPS_PC16 baz
> >> > 4: 00000000 nop
> >> > 8: 00000000 nop
> >> >
> >> > 0000000c <bar>:
> >> > c: 00000000 nop
> >>
> >> Well, it's a little different. The user has at least defined two
> >> named symbols in this case, so they have a good chance of knowing
> >> what "baz" means. In the microMIPS case we've invented a label
> >> and are using it in preference to the user-defined one.
> >
> > That's unfortunate, indeed. [FIXME]
>
> Have you looked into the work involved, before this gets dismissed
> entirely as future work?
Well, first we'd have to come up with a solution before we go and think
about implementation. As it is I fail to see one -- please propose one
if you can think of any.
The thing is we really have to report the right symbol in the relocation.
Doing otherwise is the wrong thing to do as it's not the purpose of the
tool to add any interpretation beyond what the ELF standard provides and
will also confuse the user, especially when the replacement symbol chosen
with an .o file resolves to a different location on the final link.
Then we have no reliable way to report the generated symbol, especially
when --prefix-addresses is used.
We still have -t as a workaround.
> >> > I'd just recommend peeking at the symbol table (back to the first
> >> > program):
> >> >
> >> > $ mips-sde-elf-objdump -t b.o
> >> >
> >> > b.o: file format elf32-tradbigmips
> >> >
> >> > SYMBOL TABLE:
> >> > 00000000 l d .text 00000000 .text
> >> > 00000000 l d .data 00000000 .data
> >> > 00000000 l d .bss 00000000 .bss
> >> > 00000000 l d .reginfo 00000000 .reginfo
> >> > 00000000 l d .pdr 00000000 .pdr
> >> > 00000000 l F .text 00000006 0x80 foo
> >> > 00000006 l F .text 00000002 0x80 bar
> >> > 00000006 l .text 00000000 0x80 .L1^B1
> >>
> >> I suppose having a symbol with ^B in it is less than ideal too.
> >> AIUI that name was chosen specifically because it wasn't supposed
> >> to be written out.
> >>
> >> It would be especially confusing if the user or compiler had a ".L11"
> >> label (without the ^B).
> >
> > Actually this is a tough problem -- we need to emit a generated symbol
> > that does not clash with anything the user or GCC may have put in the
> > source. Any ideas? How is it done in other ports if anywhere?
>
> None off-hand. Seggestions from others very welcome.
>
> I'll try to think of something when I've got more time. For avoidance
> of doubt, I think this does need to be fixed.
While looking into it I have implemented Joseph's suggestion to cover all
these generated symbols with the --special-syms option. This has actually
revealed this is a preexisting problem as MIPS16 code already generates
such symbols (see the relevant test suite updates included with the patch;
search for --special-syms). While I do agree this is a problem that needs
to be addressed one way or another, given this circumstance I don't think
you can reasonably reject this submission on the basis of this problem
staying unfixed.
> >> @@ -14813,6 +16230,8 @@ mips_elf_final_processing (void)
> >> file_ase_mt is true. */
> >> if (file_ase_mips16)
> >> elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_M16;
> >> + if (file_ase_micromips)
> >> + elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_MICROMIPS;
> >> #if 0 /* XXX FIXME */
> >> if (file_ase_mips3d)
> >> elf_elfheader (stdoutput)->e_flags |= ???;
> >>
> >> Do you really only want this flag to be set if -mmicromips was passed
> >> on the command line? (Yes, the same concern applies to MIPS16 and MDMX.)
> >
> > Fixing it up is easy, but I'm not sure what the original intent of these
> > flags has been. Do they mean:
> >
> > 1. I make use of the FOO feature and I assert it is available?
> >
> > 2. I make use of the FOO feature, but I may go and figure out if it's
> > available?
> >
> > 3. I make use of the FOO feature and want to prevent linking with any
> > incompatible ones?
> >
> > Once we've determined the answer we may modify code accordingly or leave
> > it as it is. It looks to me the current approach matches #1 and the ELF
> > program loader may refuse to execute the program if it sees a flag for a
> > feature that is not supported by the processor to run on. Any .set
> > fragments within the program are guarded appropriately and hence they do
> > not need to set the flag (as it would be for #2). Then #3 is sort of
> > tangential to the two others, but it does matter in this context, hence I
> > mentioned it (i.e. if #3 was true, then I'd be much happier with #3 & #1
> > than #3 & #2; otherwise I don't have a strong preference between #1 and
> > #2).
> >
> > Current arrangement is similar to that of file_mips_isa even though the
> > ISA can be overridden by .set too and I think it makes sense to keep all
> > these flags consistent.
>
> I think MIPS16 and microMIPS are fundamentally different from the ISA,
> and even from MDMX. IMO, it's reasonable to assume that, if the user is
> taking a MIPS III target as their base system, that they'll assemble
> with a MIPS III ISA flag. I know others disagree, and think that such
> things should always be specified by pseudo-ops. Even if you're of that
> opinion, though, it's easy in principle to set the flags to the minimum
> ISA required by the assembly source.
>
> MIPS16 and microMIPS are different because they represent an operating
> mode that the processor can switch in and out of. The fact that the
> assembly source contains both MIPS16 and non-MIPS16 code isn't really a
> good indicator that the code is designed to cope with non-MIPS16-capable
> systems.
>
> We could live without deciding between #1, #2 and #3 until now because
> MIPS16 was the only feature like this. Now that we've got two
> incompatible code-compression methods, I think it's more important.
>
> I too would like to hear other opinions. I'm just not convinced by
> the "it's similar to ISA selection" argument. More below.
Have you, actually? See below too.
> >> micromips_ip obviously started life as a cut-&-paste of mips_ip, and it
> >> would have been nice to factor some code out. At least split out the
> >> block beginning:
> >>
> >> + case 'F':
> >> + case 'L':
> >> + case 'f':
> >> + case 'l':
> >> + {
> >>
> >> which is identical between the two, and far too subtle to copy wholesale.
> >> There may be other good opportunities too.
> >
> > Next time, I'm afraid. [FIXME]
>
> Next time == next iteration? If so, that's fine, but I think this
> has to be fixed for the patch to be acceptable.
I have folded micromips_ip() into mips_ip() now. This revealed a couple
of preexisting problems that I fixed with some of the patches sent
previously. Likewise fixes for problems with new microMIPS code have been
included here.
> >> The same cut-&-paste concerns apply to micromips_macro, which obviously
> >> started out as a copy of macro(). I realise there are special cases
> >> for micromips (such as the DADDI assymmetry and the lack of
> >> branch-likely instructions, to name only a few), but most of the
> >> basic decisions are the same.
> >>
> >> As it stands, we have a new 3524 line function, of which I imagine at
> >> least 90% is shared with macro(). I really think the new microMIPS
> >> macro handling should be integrated into macro() instead. Don't be
> >> afraid of factoring out code from macro() if it makes it easier to
> >> integrate the microMIPS code.
> >
> > Can we make it a follow-up patch sometime in the future? I'm not afraid
> > of factoring code out of anywhere (I'm speaking of myself only of course),
> > but at this point the effort is about the same as writing this whole stuff
> > from scratch. :( [FIXME]
>
> Sorry, I know it's a pain, but I just don't think the patch can go
> in as it stands. The fact that the amount of work is so daunting
> means that (even with the best of intentions, which I realise yours
> are), that follow-up is unlikely to happen. In the meantime we'll
> have a 3524-line function (haven't recalculated ;-)) that has to be
> kept in sync with another even bigger function (or pair of functions),
> and it just won't be obvious whether the divergences are deliberate
> microMIPS differences or whether they're cases where the two functions
> haven't been updated in the same way.
>
> I remember how painful it was replacing the old macro relaxation
> code so that it could support arbitrary alternatives. This sort
> of thing would double that pain.
>
> And it's not just (or even principally) about cut-&-paste phobia.
> microMIPS has been deliberately designed to provide a great deal
> of source-level backwards compatibility, so it's no surprise that
> the two modes require very similar code, and very similar decisions.
> I think having a single function handling both is actually significantly
> clearer, because it calls out which differences are deliberate,
> hopefully with a helpful bit of commentary where necessary.
>
> As things stand, it's already a bit of an archaeology exercise trying
> to decide what the differences actually are.
Likewise, I have folded micromips_macro() into macro() and as a bonus
micromips_macro_build() into macro_build() as well. Again, this revealed
numerous problems that I fixed too.
> > Overall I'm a bit concerned about all this linker relaxation stuff -- it
> > breaks -falign-jumps, -falign-labels and -falign-loops which may have a
> > severe performance penalty and should therefore be enabled conditionally
> > only, preferably where all the three options are set to 1 (meaning that
> > would be naturally implied by -Os). A linker option would be required an
> > set appropriately by the GCC driver. [FIXME]
>
> Yeah, I agree a bit more rigour would be nice here. Without it, though,
> I think it's generally OK to assume that anyone using MIPS16 or microMIPS
> is more of the -Os rather than -O2 mindset, so I agree this is at most a
> FIXME.
Mindset aside, GCC has a documented behaviour that does not include
"maybe" in its definition. It might make sense to update GCC
documentation to warn the user at the very least.
> >> Did you actually test this with n64, say with a gcc bootstrap? Same
> >> comment goes for elfn32-mips.c.
> >>
> >> Why only do the linker relaxation for elf32-mips.c (o32, o64 & EABI)?
> >> Why not for n32 and n64 too?
> >
> > The answer to all the questions is negative. There is no 64-bit
> > microMIPS hardware available at the moment. The best bet might be QEMU --
> > NathanF, have you implemented any of the 64-bit instructions in QEMU?
> > Otherwise there's probably no way do do any of 64-bit microMIPS testing
> > beside what's done in binutils. And no library work of any kind has
> > started for 64-bit microMIPS support AFAIK. Hence there has been little
> > incentive to attempt anything but rudimentary support for 64-bit ABIs.
>
> OK, in that case, never mind about testing 64-bit ;-) However...
>
> > I envisage all the relaxation stuff to be either moved over to
> > elfxx-mips.c or copied to elfn32-mips.c and elf64-mips.c, as applicable,
> > once we have real 64-bit support.
>
> ...I still think this stuff should start life in elfxx-mips.c, even if
> it's only used by elf32-mips.c at first.
I have moved this piece now then, although care has to be taken about it
-- there are some assumptions about o32 hardcoded, e.g. the HI16/LO16
relaxation is certainly dangerous on n64 and may lead to broken code
(ADDIUPC has undefined semantics outside compatibility segments).
> >> @@ -5127,12 +5200,26 @@ mips_elf_calculate_relocation (bfd *abfd
> >> + h->la25_stub->stub_section->output_offset
> >> + h->la25_stub->offset);
> >>
> >> + /* Make sure MIPS16 and microMIPS are not used together. */
> >> + if ((r_type == R_MIPS16_26 && target_is_micromips_code_p)
> >> + || (r_type == R_MICROMIPS_26_S1 && target_is_16_bit_code_p))
> >> + {
> >> + (*_bfd_error_handler)
> >> + (_("MIPS16 and microMIPS functions cannot call each other"));
> >> + return bfd_reloc_notsupported;
> >> + }
> >>
> >> Should this be extended to check for branches too?
> >
> > That would be a useful improvement I suppose, but MIPS16 code doesn't
> > care either (you can't use a branch to switch the ISA mode). Overall I
> > think it's a corner case -- branches to external symbols are a rarity.
> > [FIXME]
>
> But it is (or feels like) something that people have asked about on many
> occasions, before we decided to ignore the botched ABI definition of
> R_MIPS_PC16.
>
> If it was a lot of work, I'd be sympathetic, but I think this is
> something that's easily done, and handling one pair of relocs without
> the others seems inconsistent.
Fixed, thanks for your point.
> >> - /* If this is an odd-valued function symbol, assume it's a MIPS16 one. */
> >> + /* If this is an odd-valued function symbol, assume it's a MIPS16
> >> + or microMIPS one. */
> >> if (ELF_ST_TYPE (elfsym->internal_elf_sym.st_info) == STT_FUNC
> >> && (asym->value & 1) != 0)
> >> {
> >> asym->value--;
> >> - elfsym->internal_elf_sym.st_other
> >> - = ELF_ST_SET_MIPS16 (elfsym->internal_elf_sym.st_other);
> >> + if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS)
> >> + elfsym->internal_elf_sym.st_other
> >> + = ELF_ST_SET_MICROMIPS (elfsym->internal_elf_sym.st_other);
> >> + else
> >> + elfsym->internal_elf_sym.st_other
> >> + = ELF_ST_SET_MIPS16 (elfsym->internal_elf_sym.st_other);
> >> }
> >> }
> >>
> >>
> >> So a file can't mix MIPS16 and microMIPS code? We should probably
> >> detect that explicitly. I'd like a clear statement of what the
> >> interoperability restrictions are.
> >>
> >> This goes back to the question of when EF_MIPS_ARCH_ASE_MICROMIPS
> >> should be set (see previous reviews).
> >
> > Background information first -- you can't have a piece of MIPS hardware,
> > either real or simulated, with the MIPS16 ASE and the microMIPS ASE
> > implemented both at a time. This is a design assumption that allowed the
> > ISA bit to be overloaded.
> >
> > That obviously does not mean -- in principle -- that you can't have an
> > executable (or one plus a mixture of shared libraries) where some
> > functions are MIPS16 code and some are microMIPS code, either of which
> > only called once the presence of the respective ASE has been determined.
> > While a valid configuration this is also a rare exotic corner case -- I
> > could imagine a piece of generic, processor-independent console/bootstrap
> > firmware like this for example, but little beyond that.
> >
> > We had a discussion about it and the conclusion was from the user's
> > perspective the most beneficial configuration is one where mixing MIPS16
> > and microMIPS code within a single executable is forbidden by default.
> > The reason is a build-time error is always better than a run-time one
> > (especially when the device has been placed out there in the field
> > already; hopefully not an Ariane 5 rocket) and the case where mixing
> > MIPS16 and microMIPS code would almost always happen is when the user
> > picked the wrong library by mistake. It is therefore most productive to
> > fail at this point rather than later.
>
> I agree. In that case, though, I think it's important that we go for #1
> in your list above, otherwise this check doesn't really count for much.
> I think having a way of forcing interpretation #2 fits into the same
> category as...
So I have changed the semantics of both flags now -- either of these is
only ever set if actual MIPS16 or microMIPS code have been generated.
Data does not count and neither does either the -mips16/-mmicromips option
or the .set mips16/micromips pseudo-op. Linking modules containing MIPS16
code together with ones containing microMIPS code has been forbidden. I
have added an LD test case to verify that.
> > A future enhancement could add assembler and linker switches to override
> > this default and mix the two ASEs in a single executable. [FIXME]
>
> ...this, which I agree is best left for future work.
So I did.
Beside the above I have made numerous bug fixes and applied less critical
clean-ups throughout the code. Tested as usually, with mips-sde-elf and
mips-linux-gnu. But I enabled NewABI tests this time too and (trivially)
adjusted the relevant test case matching patterns, i.e. there should be no
failures induced by the addition of microMIPS support with targets like
mips64*-linux-gnu either.
Maciej
binutils-20101207-umips.diff
[Patch attached compressed due to its size.]
bfd/
2010-12-07 Chao-ying Fu <fu@mips.com>
Ilie Garbacea <ilie@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
Joseph Myers <joseph@codesourcery.com>
Catherine Moore <clm@codesourcery.com>
* archures.c (bfd_mach_mips_micromips): New macro.
* cpu-mips.c (I_micromips): New enum value.
(arch_info_struct): Add bfd_mach_mips_micromips.
* elfxx-mips.h (_bfd_mips_elf_is_target_special_symbol): New
prototype.
(_bfd_mips_elf_relax_section): Likewise.
(_bfd_mips16_elf_reloc_unshuffle): Rename to...
(_bfd_mips_elf_reloc_unshuffle): ... this. Handle microMIPS
ASE.
(_bfd_mips16_elf_reloc_shuffle): Rename to...
(_bfd_mips_elf_reloc_shuffle): ... this. Handle microMIPS ASE.
(gprel16_reloc_p): Handle microMIPS ASE.
(literal_reloc_p): New function.
* elf32-mips.c (elf_micromips_howto_table_rel): New variable.
(_bfd_mips_elf32_gprel16_reloc): Handle microMIPS ASE.
(mips16_gprel_reloc): Update for _bfd_mips_elf_reloc_unshuffle
and _bfd_mips_elf_reloc_shuffle changes.
(mips_elf_gprel32_reloc): Update comment.
(micromips_reloc_map): New variable.
(bfd_elf32_bfd_reloc_type_lookup): Handle microMIPS ASE.
(mips_elf32_rtype_to_howto): Likewise.
(mips_info_to_howto_rel): Likewise.
(bfd_elf32_bfd_is_target_special_symbol): Define.
(bfd_elf32_bfd_relax_section): Likewise.
* elf64-mips.c (micromips_elf64_howto_table_rel): New variable.
(micromips_elf64_howto_table_rela): Likewise.
(mips16_gprel_reloc): Update for _bfd_mips_elf_reloc_unshuffle
and _bfd_mips_elf_reloc_shuffle changes.
(micromips_reloc_map): Likewise.
(bfd_elf64_bfd_reloc_type_lookup): Handle microMIPS ASE.
(bfd_elf64_bfd_reloc_name_lookup): Likewise.
(mips_elf64_rtype_to_howto): Likewise.
(bfd_elf64_bfd_is_target_special_symbol): Define.
* elfn32-mips.c (elf_micromips_howto_table_rel): New variable.
(elf_micromips_howto_table_rela): Likewise.
(mips16_gprel_reloc): Update for _bfd_mips_elf_reloc_unshuffle
and _bfd_mips_elf_reloc_shuffle changes.
(micromips_reloc_map): Likewise.
(bfd_elf32_bfd_reloc_type_lookup): Handle microMIPS ASE.
(bfd_elf32_bfd_reloc_name_lookup): Likewise.
(mips_elf_n32_rtype_to_howto): Likewise.
(bfd_elf32_bfd_is_target_special_symbol): Define.
* elfxx-mips.c (LA25_LUI_MICROMIPS_1): New macro.
(LA25_LUI_MICROMIPS_2): Likewise.
(LA25_J_MICROMIPS_1, LA25_J_MICROMIPS_2): Likewise.
(LA25_ADDIU_MICROMIPS_1, LA25_ADDIU_MICROMIPS_2): Likewise.
(TLS_RELOC_P): Handle microMIPS ASE.
(mips_elf_create_stub_symbol): Adjust value of stub symbol if
target is a microMIPS function.
(micromips_reloc_p): New function.
(micromips_reloc_shuffle_p): Likewise.
(got16_reloc_p, call16_reloc_p): Handle microMIPS ASE.
(got_disp_reloc_p, got_page_reloc_p): New functions.
(got_ofst_reloc_p): Likewise.
(got_hi16_reloc_p, got_lo16_reloc_p): Likewise.
(call_hi16_reloc_p, call_lo16_reloc_p): Likewise.
(hi16_reloc_p, lo16_reloc_p, jal_reloc_p): Handle microMIPS ASE.
(micromips_branch_reloc_p): New function.
(tls_gd_reloc_p, tls_ldm_reloc_p): Likewise.
(tls_gottprel_reloc_p): Likewise.
(_bfd_mips16_elf_reloc_unshuffle): Rename to...
(_bfd_mips_elf_reloc_unshuffle): ... this. Handle microMIPS
ASE.
(_bfd_mips16_elf_reloc_shuffle): Rename to...
(_bfd_mips_elf_reloc_shuffle): ... this. Handle microMIPS ASE.
(_bfd_mips_elf_lo16_reloc): Handle microMIPS ASE.
(mips_tls_got_index, mips_elf_got_page): Likewise.
(mips_elf_create_local_got_entry): Likewise.
(mips_elf_relocation_needs_la25_stub): Likewise.
(mips_elf_calculate_relocation): Likewise.
(mips_elf_perform_relocation): Likewise.
(_bfd_mips_elf_symbol_processing): Likewise.
(_bfd_mips_elf_add_symbol_hook): Likewise.
(_bfd_mips_elf_link_output_symbol_hook): Likewise.
(mips_elf_add_lo16_rel_addend): Likewise.
(_bfd_mips_elf_check_relocs): Likewise.
(mips_elf_adjust_addend): Likewise.
(_bfd_mips_elf_relocate_section): Likewise.
(mips_elf_create_la25_stub): Likewise.
(_bfd_mips_vxworks_finish_dynamic_symbol): Likewise.
(_bfd_mips_elf_gc_sweep_hook): Likewise.
(_bfd_mips_elf_is_target_special_symbol): New function.
(mips_elf_relax_delete_bytes): Likewise.
(opcode_descriptor): New structure.
(RA): New macro.
(OP32_SREG, OP32_TREG, OP16_VALID_REG): Likewise.
(b_insns_32, bc_insn_32, bz_insn_32, bzal_insn_32): New variables.
(beq_insn_32): Likewise.
(b_insn_16, bz_insn_16): New variables.
(BZ32_REG, BZ32_REG_FIELD): New macros.
(bz_insns_32, bzc_insns_32, bz_insns_16): New variables.
(BZ16_REG, BZ16_REG_FIELD): New macros.
(jal_insn_32_bd16, jal_insn_32_bd32): New variables.
(j_insn_32, jalr_insn_32): Likewise.
(JALR_SREG, JALR_TREG): New macros.
(call_insn_32_bd16, call_insn_32_bd32): New variables.
(ds_insns_32_bd16): Likewise.
(jalx_insn_32_bd32): Likewise.
(jalr_insn_16_bd16, jalr_insn_16_bd32, jr_insn_16): Likewise.
(JR16_REG): New macro.
(ds_insns_16_bd16): New variable.
(lui_insn): Likewise.
(addiu_insn, addiupc_insn): Likewise.
(ADDIUPC_REG_FIELD): New macro.
(MOVE32_RD, MOVE32_RS): Likewise.
(MOVE16_RD_FIELD, MOVE16_RS_FIELD): Likewise.
(move_insns_32, move_insns_16): New variables.
(nop_insn_32, nop_insn_16): Likewise.
(MATCH): New macro.
(find_match): New function.
(relax_dslot_norel16, relax_dslot_norel32): Likewise.
(relax_dslot_rel): Likewise.
(IS_BITSIZE): New macro.
(_bfd_mips_elf_relax_section): New function.
(_bfd_mips_elf_merge_private_bfd_data): Disallow linking MIPS16
and microMIPS modules together.
(_bfd_mips_elf_print_private_bfd_data): Handle microMIPS ASE.
* reloc.c (BFD_RELOC_MICROMIPS_7_PCREL_S1): New relocation.
(BFD_RELOC_MICROMIPS_10_PCREL_S1): Likewise.
(BFD_RELOC_MICROMIPS_16_PCREL_S1): Likewise.
(BFD_RELOC_MICROMIPS_GPREL16): Likewise.
(BFD_RELOC_MICROMIPS_JMP, BFD_RELOC_MICROMIPS_HI16): Likewise.
(BFD_RELOC_MICROMIPS_HI16_S): Likewise.
(BFD_RELOC_MICROMIPS_LO16): Likewise.
(BFD_RELOC_MICROMIPS_LITERAL): Likewise.
(BFD_RELOC_MICROMIPS_GOT16): Likewise.
(BFD_RELOC_MICROMIPS_CALL16): Likewise.
(BFD_RELOC_MICROMIPS_GOT_HI16): Likewise.
(BFD_RELOC_MICROMIPS_GOT_LO16): Likewise.
(BFD_RELOC_MICROMIPS_CALL_HI16): Likewise.
(BFD_RELOC_MICROMIPS_CALL_LO16): Likewise.
(BFD_RELOC_MICROMIPS_SUB): Likewise.
(BFD_RELOC_MICROMIPS_GOT_PAGE): Likewise.
(BFD_RELOC_MICROMIPS_GOT_OFST): Likewise.
(BFD_RELOC_MICROMIPS_GOT_DISP): Likewise.
(BFD_RELOC_MICROMIPS_HIGHEST): Likewise.
(BFD_RELOC_MICROMIPS_HIGHER): Likewise.
(BFD_RELOC_MICROMIPS_SCN_DISP): Likewise.
(BFD_RELOC_MICROMIPS_JALR): Likewise.
(BFD_RELOC_MICROMIPS_TLS_GD): Likewise.
(BFD_RELOC_MICROMIPS_TLS_LDM): Likewise.
(BFD_RELOC_MICROMIPS_TLS_DTPREL_HI16): Likewise.
(BFD_RELOC_MICROMIPS_TLS_DTPREL_LO16): Likewise.
(BFD_RELOC_MICROMIPS_TLS_GOTTPREL): Likewise.
(BFD_RELOC_MICROMIPS_TLS_TPREL_HI16): Likewise.
(BFD_RELOC_MICROMIPS_TLS_TPREL_LO16): Likewise.
* bfd-in2.h: Regenerate.
* libbfd.h: Regenerate.
binutils/
2010-12-07 Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* readelf.c (get_machine_flags): Handle microMIPS ASE.
(get_mips_symbol_other): Likewise.
gas/
2010-12-07 Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* config/tc-mips.h (mips_segment_info): Add one bit for
microMIPS.
(TC_LABEL_IS_LOCAL): New macro.
(mips_label_is_local): New prototype.
* config/tc-mips.c (emit_branch_likely_macro): New variable.
(mips_set_options): Add micromips.
(mips_opts): Initialise micromips to -1.
(file_ase_micromips): New variable.
(CPU_HAS_MICROMIPS): New macro.
(hilo_interlocks): Set for microMIPS too.
(gpr_interlocks): Likewise.
(cop_interlocks): Likewise.
(cop_mem_interlocks): Likewise.
(HAVE_CODE_COMPRESSION): New macro.
(micromips_op_hash): New variable.
(micromips_nop16_insn, micromips_nop32_insn): New variables.
(NOP_INSN): Handle microMIPS ASE.
(mips32_to_micromips_reg_b_map): New macro.
(mips32_to_micromips_reg_c_map): Likewise.
(mips32_to_micromips_reg_d_map): Likewise.
(mips32_to_micromips_reg_e_map): Likewise.
(mips32_to_micromips_reg_f_map): Likewise.
(mips32_to_micromips_reg_g_map): Likewise.
(mips32_to_micromips_reg_l_map): Likewise.
(mips32_to_micromips_reg_n_map): Likewise.
(mips32_to_micromips_reg_h_map): New variable.
(mips32_to_micromips_reg_m_map): Likewise.
(mips32_to_micromips_reg_q_map): Likewise.
(micromips_to_32_reg_h_map): New variable.
(micromips_to_32_reg_i_map): Likewise.
(micromips_to_32_reg_m_map): Likewise.
(micromips_to_32_reg_q_map): Likewise.
(micromips_to_32_reg_b_map): New macro.
(micromips_to_32_reg_c_map): Likewise.
(micromips_to_32_reg_d_map): Likewise.
(micromips_to_32_reg_e_map): Likewise.
(micromips_to_32_reg_f_map): Likewise.
(micromips_to_32_reg_g_map): Likewise.
(micromips_to_32_reg_l_map): Likewise.
(micromips_to_32_reg_n_map): Likewise.
(micromips_imm_b_map, micromips_imm_c_map): New macros.
(RELAX_DELAY_SLOT_16BIT): New macro.
(RELAX_DELAY_SLOT_SIZE_FIRST): Likewise.
(RELAX_DELAY_SLOT_SIZE_SECOND): Likewise.
(RELAX_MICROMIPS_ENCODE, RELAX_MICROMIPS_P): New macros.
(RELAX_MICROMIPS_TYPE, RELAX_MICROMIPS_USER_16BIT): Likewise.
(RELAX_MICROMIPS_UNCOND, RELAX_MICROMIPS_LINK): Likewise.
(RELAX_MICROMIPS_TOOFAR, RELAX_MICROMIPS_MARK_TOOFAR): Likewise.
(RELAX_MICROMIPS_CLEAR_TOOFAR): Likewise.
(RELAX_MICROMIPS_EXTENDED): Likewise.
(RELAX_MICROMIPS_MARK_EXTENDED): Likewise.
(RELAX_MICROMIPS_CLEAR_EXTENDED): Likewise.
(INSERT_OPERAND, EXTRACT_OPERAND): Handle microMIPS ASE.
(mips_macro_warning): Add delay_slot_16bit_p, delay_slot_32bit_p,
fsize and insns.
(mips_mark_labels): New function.
(mips16_small, mips16_ext): Remove variables, replacing with...
(forced_insn_size): ... this.
(append_insn, mips16_ip): Update accordingly.
(micromips_insn_length): New function.
(insn_length): Return the length of microMIPS instructions.
(mips_record_mips16_mode): Rename to...
(mips_record_compressed_mode): ... this. Handle microMIPS ASE.
(install_insn): Handle microMIPS ASE.
(is_size_valid, is_delay_slot_valid): New functions.
(md_begin): Handle microMIPS ASE.
(md_assemble): Likewise. Update for append_insn interface
change.
(micromips_reloc_p): New function.
(got16_reloc_p): Handle microMIPS ASE.
(hi16_reloc_p): Likewise.
(lo16_reloc_p): Likewise.
(matching_lo_reloc): Likewise.
(insn_uses_reg, reg_needs_delay): Likewise.
(mips_move_labels): Likewise.
(mips16_mark_labels): Rename to...
(mips_compressed_mark_labels): ... this. Handle microMIPS ASE.
(insns_between, nops_for_vr4130, nops_for_insn): Likewise.
(fix_loongson2f_nop, fix_loongson2f_jump): Likewise.
(MICROMIPS_LABEL_CHAR): New macro.
(micromips_target_label, micromips_target_name): New variables.
(micromips_label_name, micromips_label_expr): New functions.
(micromips_label_inc, micromips_add_label): Likewise.
(mips_label_is_local): Likewise.
(append_insn): Add expansionp argument. Handle microMIPS ASE.
(start_noreorder, end_noreorder): Handle microMIPS ASE.
(macro_start, macro_warning, macro_end): Likewise.
(brk_fmt, cop12_fmt, jalr_fmt, lui_fmt): New variables.
(mem12_fmt, mfhl_fmt, shft_fmt, trap_fmt): Likewise.
(BRK_FMT, COP12_FMT, JALR_FMT, LUI_FMT): New macros.
(MEM12_FMT, MFHL_FMT, SHFT_FMT, TRAP_FMT): Likewise.
(macro_map_reloc): New function.
(macro_build): Handle microMIPS ASE. Update for append_insn
interface change.
(mips16_macro_build): Update for append_insn interface change.
(macro_build_jalr): Handle microMIPS ASE.
(macro_build_lui): Likewise. Simplify.
(load_register): Handle microMIPS ASE.
(load_address): Likewise.
(move_register): Likewise.
(macro_build_branch_likely): New function.
(macro_build_branch_ccl): Likewise.
(macro_build_branch_rs): Likewise.
(macro_build_branch_rsrt): Likewise.
(macro): Handle microMIPS ASE.
(validate_micromips_insn): New function.
(SKIP_SPACE_TABS): Move earlier on.
(mips_ip): Handle microMIPS ASE.
(micromips_percent_op): New variable.
(parse_relocation): Handle microMIPS ASE.
(my_getExpression): Likewise.
(options): Add OPTION_MICROMIPS and OPTION_NO_MICROMIPS.
(md_longopts): Add mmicromips and mno-micromips.
(md_parse_option): Handle OPTION_MICROMIPS and
OPTION_NO_MICROMIPS.
(mips_after_parse_args): Handle microMIPS ASE.
(md_pcrel_from): Handle microMIPS relocations.
(mips_force_relocation): Likewise.
(md_apply_fix): Likewise.
(mips_align): Handle microMIPS ASE.
(s_mipsset): Likewise.
(s_cpload, s_cpsetup, s_cpreturn): Use relocation wrappers.
(s_dtprel_internal): Likewise.
(s_gpword, s_gpdword): Likewise.
(s_insn): Handle microMIPS ASE.
(s_mips_stab): Likewise.
(relaxed_micromips_32bit_branch_length): New function.
(relaxed_micromips_16bit_branch_length): New function.
(md_estimate_size_before_relax): Handle microMIPS ASE.
(mips_fix_adjustable): Likewise.
(tc_gen_reloc): Handle microMIPS relocations.
(mips_relax_frag): Handle microMIPS ASE.
(md_convert_frag): Likewise.
(mips_frob_file_after_relocs): Likewise.
(mips_elf_final_processing): Likewise.
(mips_nop_opcode): Likewise.
(mips_handle_align): Likewise.
(md_show_usage): Handle microMIPS options.
* symbols.c (TC_LABEL_IS_LOCAL): New macro.
(S_IS_LOCAL): Add a TC_LABEL_IS_LOCAL check.
* doc/as.texinfo (Target MIPS options): Add -mmicromips and
-mno-micromips.
(-mmicromips, -mno-micromips): New options.
* doc/c-mips.texi (-mmicromips, -mno-micromips): New options.
(MIPS ISA): Document .set micromips and .set nomicromips.
(MIPS insn): Update for microMIPS support.
gas/testsuite/
2010-12-07 Maciej W. Rozycki <macro@codesourcery.com>
Chao-ying Fu <fu@mips.com>
* gas/mips/micromips.d: New test.
* gas/mips/micromips-branch-delay.d: Likewise.
* gas/mips/micromips-branch-relax.d: Likewise.
* gas/mips/micromips-branch-relax-pic.d: Likewise.
* gas/mips/micromips-size-1.d: Likewise.
* gas/mips/micromips-trap.d: Likewise.
* gas/mips/micromips.l: New stderr output.
* gas/mips/micromips-branch-delay.l: Likewise.
* gas/mips/micromips-branch-relax.l: Likewise.
* gas/mips/micromips-branch-relax-pic.l: Likewise.
* gas/mips/micromips-size-0.l: New list test.
* gas/mips/micromips-size-1.l: New stderr output.
* gas/mips/micromips.s: New test source.
* gas/mips/micromips-branch-delay.s: Likewise.
* gas/mips/micromips-branch-relax.s: Likewise.
* gas/mips/micromips-size-0.s: Likewise.
* gas/mips/micromips-size-1.s: Likewise.
* gas/mips/mips.exp: Run the new tests.
* gas/mips/elf_ase_micromips.d: New test.
* gas/mips/elf_ase_micromips-1.d: Likewise.
* gas/mips/micromips@abs.d: Likewise.
* gas/mips/micromips@add.d: Likewise.
* gas/mips/micromips@and.d: Likewise.
* gas/mips/micromips@beq.d: Likewise.
* gas/mips/micromips@bge.d: Likewise.
* gas/mips/micromips@bgeu.d: Likewise.
* gas/mips/micromips@blt.d: Likewise.
* gas/mips/micromips@bltu.d: Likewise.
* gas/mips/micromips@branch-likely.d: Likewise.
* gas/mips/micromips@branch-misc-1.d: Likewise.
* gas/mips/micromips@branch-misc-2-64.d: Likewise.
* gas/mips/micromips@branch-misc-2.d: Likewise.
* gas/mips/micromips@branch-misc-2pic-64.d: Likewise.
* gas/mips/micromips@branch-misc-2pic.d: Likewise.
* gas/mips/micromips@branch-self.d: Likewise.
* gas/mips/micromips@dli.d: Likewise.
* gas/mips/micromips@elf-jal.d: Likewise.
* gas/mips/micromips@elf-rel2.d: Likewise.
* gas/mips/micromips@elf-rel4.d: Likewise.
* gas/mips/micromips@jal-svr4pic.d: Likewise.
* gas/mips/micromips@jal-svr4pic-noreorder.d: Likewise.
* gas/mips/micromips@lb-svr4pic-ilocks.d: Likewise.
* gas/mips/micromips@li.d: Likewise.
* gas/mips/micromips@mips1-fp.d: Likewise.
* gas/mips/micromips@mips32-cp2.d: Likewise.
* gas/mips/micromips@mips32-imm.d: Likewise.
* gas/mips/micromips@mips32-sf32.d: Likewise.
* gas/mips/micromips@mips32.d: Likewise.
* gas/mips/micromips@mips32r2-cp2.d: Likewise.
* gas/mips/micromips@mips32r2-fp32.d: Likewise.
* gas/mips/micromips@mips32r2.d: Likewise.
* gas/mips/micromips@mips4-branch-likely.d: Likewise.
* gas/mips/micromips@mips4-fp.d: Likewise.
* gas/mips/micromips@mips4.d: Likewise.
* gas/mips/micromips@mips5.d: Likewise.
* gas/mips/micromips@mips64-cp2.d: Likewise.
* gas/mips/micromips@mips64.d: Likewise.
* gas/mips/micromips@mips64r2.d: Likewise.
* gas/mips/micromips@rol-hw.d: Likewise.
* gas/mips/micromips@uld2-eb.d: Likewise.
* gas/mips/micromips@uld2-el.d: Likewise.
* gas/mips/micromips@ulh2-eb.d: Likewise.
* gas/mips/micromips@ulh2-el.d: Likewise.
* gas/mips/micromips@ulw2-eb-ilocks.d: Likewise.
* gas/mips/micromips@ulw2-el-ilocks.d: Likewise.
* gas/mips/mips32-imm.d: Likewise.
* gas/mips/elf-rel27.d: Handle microMIPS ASE.
* gas/mips/l_d.d: Likewise.
* gas/mips/l_d-n32.d: Likewise.
* gas/mips/l_d-n64.d: Likewise.
* gas/mips/ld.d: Likewise.
* gas/mips/ld-n32.d: Likewise.
* gas/mips/ld-n64.d: Likewise.
* gas/mips/s_d.d: Likewise.
* gas/mips/s_d-n32.d: Likewise.
* gas/mips/s_d-n64.d: Likewise.
* gas/mips/sd.d: Likewise.
* gas/mips/sd-n32.d: Likewise.
* gas/mips/sd-n64.d: Likewise.
* gas/mips/mips32.d: Update immediates.
* gas/mips/micromips@mips32-cp2.s: New test source.
* gas/mips/micromips@mips32-imm.s: Likewise.
* gas/mips/micromips@mips32r2-cp2.s: Likewise.
* gas/mips/micromips@mips64-cp2.s: Likewise.
* gas/mips/mips32-imm.s: Likewise.
* gas/mips/elf-rel4.s: Handle microMIPS ASE.
* gas/mips/lb-pic.s: Likewise.
* gas/mips/ld.s: Likewise.
* gas/mips/mips32.s: Likewise.
* gas/mips/mips.exp: Add the micromips arch. Exclude mips16e
from micromips. Run mips32-imm.
* gas/mips/jal-mask-11.d: New test.
* gas/mips/jal-mask-12.d: Likewise.
* gas/mips/micromips@jal-mask-11.d: Likewise.
* gas/mips/jal-mask-1.s: Source for the new tests.
* gas/mips/jal-mask-21.d: New test.
* gas/mips/jal-mask-22.d: Likewise.
* gas/mips/micromips@jal-mask-12.d: Likewise.
* gas/mips/jal-mask-2.s: Source for the new tests.
* gas/mips/mips.exp: Run the new tests.
* gas/mips/mips16-e.d: Add --special-syms to `objdump'.
* gas/mips/tmips16-e.d: Likewise.
* gas/mips/and.s: Adjust padding.
* gas/mips/beq.s: Likewise.
* gas/mips/bge.s: Likewise.
* gas/mips/bgeu.s: Likewise.
* gas/mips/blt.s: Likewise.
* gas/mips/bltu.s: Likewise.
* gas/mips/branch-misc-2.s: Likewise.
* gas/mips/jal.s: Likewise.
* gas/mips/li.s: Likewise.
* gas/mips/mips1-fp.s: Likewise.
* gas/mips/mips32r2-fp32.s: Likewise.
* gas/mips/mips64.s: Likewise.
* gas/mips/mips4.s: Likewise.
* gas/mips/mips4-fp.s: Likewise.
* gas/mips/and.d: Update accordingly.
* gas/mips/elf-jal.d: Likewise.
* gas/mips/jal.d: Likewise.
* gas/mips/li.d: Likewise.
* gas/mips/mips1-fp.d: Likewise.
* gas/mips/mips32r2-fp32.d: Likewise.
* gas/mips/mips64.d: Likewise.
include/elf/
2010-12-07 Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* mips.h (R_MICROMIPS_min): New relocations.
(R_MICROMIPS_26_S1): Likewise.
(R_MICROMIPS_HI16, R_MICROMIPS_LO16): Likewise.
(R_MICROMIPS_GPREL16, R_MICROMIPS_LITERAL): Likewise.
(R_MICROMIPS_GOT16, R_MICROMIPS_PC7_S1): Likewise.
(R_MICROMIPS_PC10_S1, R_MICROMIPS_PC16_S1): Likewise.
(R_MICROMIPS_CALL16, R_MICROMIPS_GOT_DISP): Likewise.
(R_MICROMIPS_GOT_PAGE, R_MICROMIPS_GOT_OFST): Likewise.
(R_MICROMIPS_GOT_HI16, R_MICROMIPS_GOT_LO16): Likewise.
(R_MICROMIPS_SUB, R_MICROMIPS_HIGHER): Likewise.
(R_MICROMIPS_HIGHEST, R_MICROMIPS_CALL_HI16): Likewise.
(R_MICROMIPS_CALL_LO16, R_MICROMIPS_SCN_DISP): Likewise.
(R_MICROMIPS_JALR, R_MICROMIPS_HI0_LO16): Likewise.
(R_MICROMIPS_TLS_GD, R_MICROMIPS_TLS_LDM): Likewise.
(R_MICROMIPS_TLS_DTPREL_HI, R_MICROMIPS_TLS_DTPREL_LO): Likewise.
(R_MICROMIPS_TLS_GOTTPREL): Likewise.
(R_MICROMIPS_TLS_TPREL_HI16): Likewise.
(R_MICROMIPS_TLS_TPREL_LO16): Likewise.
(R_MICROMIPS_GPREL7_S2, R_MICROMIPS_PC23_S2): Likewise.
(R_MICROMIPS_max): Likewise.
(EF_MIPS_ARCH_ASE_MICROMIPS): New macro.
(STO_MIPS_ISA, STO_MIPS_FLAGS): Likewise.
(ELF_ST_IS_MIPS_PLT, ELF_ST_SET_MIPS_PLT): Likewise.
(STO_MICROMIPS): Likewise.
(ELF_ST_IS_MICROMIPS, ELF_ST_SET_MICROMIPS): Likewise.
(ELF_ST_IS_COMPRESSED): Likewise.
(STO_MIPS_PLT, STO_MIPS_PIC): Rework.
(ELF_ST_IS_MIPS_PIC, ELF_ST_SET_MIPS_PIC): Likewise.
(STO_MIPS16, ELF_ST_IS_MIPS16, ELF_ST_SET_MIPS16): Likewise.
include/opcode/
2010-12-07 Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* mips.h (OP_MASK_EXTLSB, OP_SH_EXTLSB): New macros.
(OP_MASK_STYPE, OP_SH_STYPE): Likewise.
(OP_MASK_CODE10, OP_SH_CODE10): Likewise.
(OP_MASK_TRAP, OP_SH_TRAP): Likewise.
(OP_MASK_OFFSET12, OP_SH_OFFSET12): Likewise.
(OP_MASK_OFFSET10, OP_SH_OFFSET10): Likewise.
(OP_MASK_RS3, OP_SH_RS3): Likewise.
(OP_MASK_MB, OP_SH_MB, OP_MASK_MC, OP_SH_MC): Likewise.
(OP_MASK_MD, OP_SH_MD, OP_MASK_ME, OP_SH_ME): Likewise.
(OP_MASK_MF, OP_SH_MF, OP_MASK_MG, OP_SH_MG): Likewise.
(OP_MASK_MJ, OP_SH_MJ, OP_MASK_ML, OP_SH_ML): Likewise.
(OP_MASK_MP, OP_SH_MP, OP_MASK_MQ, OP_SH_MQ): Likewise.
(OP_MASK_IMMA, OP_SH_IMMA, OP_MASK_IMMB, OP_SH_IMMB): Likewise.
(OP_MASK_IMMC, OP_SH_IMMC, OP_MASK_IMMF, OP_SH_IMMF): Likewise.
(OP_MASK_IMMG, OP_SH_IMMG, OP_MASK_IMMH, OP_SH_IMMH): Likewise.
(OP_MASK_IMMI, OP_SH_IMMI, OP_MASK_IMMJ, OP_SH_IMMJ): Likewise.
(OP_MASK_IMML, OP_SH_IMML, OP_MASK_IMMM, OP_SH_IMMM): Likewise.
(OP_MASK_IMMN, OP_SH_IMMN, OP_MASK_IMMO, OP_SH_IMMO): Likewise.
(OP_MASK_IMMP, OP_SH_IMMP, OP_MASK_IMMQ, OP_SH_IMMQ): Likewise.
(OP_MASK_IMMU, OP_SH_IMMU, OP_MASK_IMMW, OP_SH_IMMW): Likewise.
(OP_MASK_IMMX, OP_SH_IMMX, OP_MASK_IMMY, OP_SH_IMMY): Likewise.
(INSN2_BRANCH_DELAY_16BIT, INSN2_BRANCH_DELAY_32BIT): New macros.
(INSN2_WRITE_GPR_S, INSN2_READ_FPR_D): Likewise.
(INSN2_MOD_GPR_MB, INSN2_MOD_GPR_MC, INSN2_MOD_GPR_MD): Likewise.
(INSN2_MOD_GPR_ME, INSN2_MOD_GPR_MF, INSN2_MOD_GPR_MG): Likewise.
(INSN2_MOD_GPR_MJ, INSN2_MOD_GPR_MP, INSN2_MOD_GPR_MQ): Likewise.
(INSN2_MOD_SP, INSN2_READ_GPR_31): Likewise.
(INSN2_READ_GP, INSN2_READ_PC): Likewise.
(CPU_MICROMIPS): New macro.
(M_BC1FL, M_BC1TL, M_BC2FL, M_BC2TL, M_BEQL, M_BGEZL): New enum
values.
(M_BGEZALL, M_BGTZL, M_BLEZL, M_BLTZL, M_BLTZALL): Likewise.
(M_CACHE_OB, M_LDC2_OB, M_LDL_OB, M_LDM_AB, M_LDM_OB): Likewise.
(M_LDP_AB, M_LDP_OB, M_LDR_OB, M_LL_OB, M_LLD_OB): Likewise.
(M_LWC2_OB, M_LWL_OB, M_LWM_AB, M_LWP_AB, M_LWP_OB): Likewise.
(M_LWR_OB, M_LWU_OB, M_PREF_OB, M_SC_OB, M_SCD_OB): Likewise.
(M_SDC2_OB, M_SDL_OB, M_SDM_AB, M_SDM_OB, M_SDP_AB): Likewise.
(M_SDP_OB, M_SDR_OB, M_SWC2_OB, M_SWL_OB, M_SWM_AB): Likewise.
(M_SWM_OB, M_SWP_AB, M_SWP_OB, M_SWR_OB): Likewise.
(MICROMIPSOP_MASK_MAJOR, MICROMIPSOP_SH_MAJOR): New macros.
(MICROMIPSOP_MASK_IMMEDIATE, MICROMIPSOP_SH_IMMEDIATE): Likewise.
(MICROMIPSOP_MASK_DELTA, MICROMIPSOP_SH_DELTA): Likewise.
(MICROMIPSOP_MASK_CODE10, MICROMIPSOP_SH_CODE10): Likewise.
(MICROMIPSOP_MASK_TRAP, MICROMIPSOP_SH_TRAP): Likewise.
(MICROMIPSOP_MASK_SHAMT, MICROMIPSOP_SH_SHAMT): Likewise.
(MICROMIPSOP_MASK_TARGET, MICROMIPSOP_SH_TARGET): Likewise.
(MICROMIPSOP_MASK_EXTLSB, MICROMIPSOP_SH_EXTLSB): Likewise.
(MICROMIPSOP_MASK_EXTMSBD, MICROMIPSOP_SH_EXTMSBD): Likewise.
(MICROMIPSOP_MASK_INSMSB, MICROMIPSOP_SH_INSMSB): Likewise.
(MICROMIPSOP_MASK_CODE, MICROMIPSOP_SH_CODE): Likewise.
(MICROMIPSOP_MASK_CODE2, MICROMIPSOP_SH_CODE2): Likewise.
(MICROMIPSOP_MASK_CACHE, MICROMIPSOP_SH_CACHE): Likewise.
(MICROMIPSOP_MASK_SEL, MICROMIPSOP_SH_SEL): Likewise.
(MICROMIPSOP_MASK_OFFSET12, MICROMIPSOP_SH_OFFSET12): Likewise.
(MICROMIPSOP_MASK_3BITPOS, MICROMIPSOP_SH_3BITPOS): Likewise.
(MICROMIPSOP_MASK_STYPE, MICROMIPSOP_SH_STYPE): Likewise.
(MICROMIPSOP_MASK_OFFSET10, MICROMIPSOP_SH_OFFSET10): Likewise.
(MICROMIPSOP_MASK_RS, MICROMIPSOP_SH_RS): Likewise.
(MICROMIPSOP_MASK_RT, MICROMIPSOP_SH_RT): Likewise.
(MICROMIPSOP_MASK_RD, MICROMIPSOP_SH_RD): Likewise.
(MICROMIPSOP_MASK_FS, MICROMIPSOP_SH_FS): Likewise.
(MICROMIPSOP_MASK_FT, MICROMIPSOP_SH_FT): Likewise.
(MICROMIPSOP_MASK_FD, MICROMIPSOP_SH_FD): Likewise.
(MICROMIPSOP_MASK_FR, MICROMIPSOP_SH_FR): Likewise.
(MICROMIPSOP_MASK_RS3, MICROMIPSOP_SH_RS3): Likewise.
(MICROMIPSOP_MASK_PREFX, MICROMIPSOP_SH_PREFX): Likewise.
(MICROMIPSOP_MASK_BCC, MICROMIPSOP_SH_BCC): Likewise.
(MICROMIPSOP_MASK_CCC, MICROMIPSOP_SH_CCC): Likewise.
(MICROMIPSOP_MASK_COPZ, MICROMIPSOP_SH_COPZ): Likewise.
(MICROMIPSOP_MASK_MB, MICROMIPSOP_SH_MB): Likewise.
(MICROMIPSOP_MASK_MC, MICROMIPSOP_SH_MC): Likewise.
(MICROMIPSOP_MASK_MD, MICROMIPSOP_SH_MD): Likewise.
(MICROMIPSOP_MASK_ME, MICROMIPSOP_SH_ME): Likewise.
(MICROMIPSOP_MASK_MF, MICROMIPSOP_SH_MF): Likewise.
(MICROMIPSOP_MASK_MG, MICROMIPSOP_SH_MG): Likewise.
(MICROMIPSOP_MASK_MJ, MICROMIPSOP_SH_MJ): Likewise.
(MICROMIPSOP_MASK_ML, MICROMIPSOP_SH_ML): Likewise.
(MICROMIPSOP_MASK_MP, MICROMIPSOP_SH_MP): Likewise.
(MICROMIPSOP_MASK_MQ, MICROMIPSOP_SH_MQ): Likewise.
(MICROMIPSOP_MASK_IMMA, MICROMIPSOP_SH_IMMA): Likewise.
(MICROMIPSOP_MASK_IMMB, MICROMIPSOP_SH_IMMB): Likewise.
(MICROMIPSOP_MASK_IMMC, MICROMIPSOP_SH_IMMC): Likewise.
(MICROMIPSOP_MASK_IMMD, MICROMIPSOP_SH_IMMD): Likewise.
(MICROMIPSOP_MASK_IMME, MICROMIPSOP_SH_IMME): Likewise.
(MICROMIPSOP_MASK_IMMF, MICROMIPSOP_SH_IMMF): Likewise.
(MICROMIPSOP_MASK_IMMG, MICROMIPSOP_SH_IMMG): Likewise.
(MICROMIPSOP_MASK_IMMH, MICROMIPSOP_SH_IMMH): Likewise.
(MICROMIPSOP_MASK_IMMI, MICROMIPSOP_SH_IMMI): Likewise.
(MICROMIPSOP_MASK_IMMJ, MICROMIPSOP_SH_IMMJ): Likewise.
(MICROMIPSOP_MASK_IMML, MICROMIPSOP_SH_IMML): Likewise.
(MICROMIPSOP_MASK_IMMM, MICROMIPSOP_SH_IMMM): Likewise.
(MICROMIPSOP_MASK_IMMN, MICROMIPSOP_SH_IMMN): Likewise.
(MICROMIPSOP_MASK_IMMO, MICROMIPSOP_SH_IMMO): Likewise.
(MICROMIPSOP_MASK_IMMP, MICROMIPSOP_SH_IMMP): Likewise.
(MICROMIPSOP_MASK_IMMQ, MICROMIPSOP_SH_IMMQ): Likewise.
(MICROMIPSOP_MASK_IMMU, MICROMIPSOP_SH_IMMU): Likewise.
(MICROMIPSOP_MASK_IMMW, MICROMIPSOP_SH_IMMW): Likewise.
(MICROMIPSOP_MASK_IMMX, MICROMIPSOP_SH_IMMX): Likewise.
(MICROMIPSOP_MASK_IMMY, MICROMIPSOP_SH_IMMY): Likewise.
(MICROMIPSOP_MASK_CODE, MICROMIPSOP_SH_CODE): Likewise.
(MICROMIPSOP_MASK_CODE2, MICROMIPSOP_SH_CODE2): Likewise.
(MICROMIPSOP_MASK_CACHE, MICROMIPSOP_SH_CACHE): Likewise.
(MICROMIPSOP_MASK_CODE20, MICROMIPSOP_SH_CODE20): Likewise.
(MICROMIPSOP_MASK_PERFREG, MICROMIPSOP_SH_PERFREG): Likewise.
(MICROMIPSOP_MASK_CODE19, MICROMIPSOP_SH_CODE19): Likewise.
(MICROMIPSOP_MASK_ALN, MICROMIPSOP_SH_ALN): Likewise.
(MICROMIPSOP_MASK_VECBYTE, MICROMIPSOP_SH_VECBYTE): Likewise.
(MICROMIPSOP_MASK_VECALIGN, MICROMIPSOP_SH_VECALIGN): Likewise.
(MICROMIPSOP_MASK_DSPACC, MICROMIPSOP_SH_DSPACC): Likewise.
(MICROMIPSOP_MASK_DSPACC_S, MICROMIPSOP_SH_DSPACC_S): Likewise.
(MICROMIPSOP_MASK_DSPSFT, MICROMIPSOP_SH_DSPSFT): Likewise.
(MICROMIPSOP_MASK_DSPSFT_7, MICROMIPSOP_SH_DSPSFT_7): Likewise.
(MICROMIPSOP_MASK_SA3, MICROMIPSOP_SH_SA3): Likewise.
(MICROMIPSOP_MASK_SA4, MICROMIPSOP_SH_SA4): Likewise.
(MICROMIPSOP_MASK_IMM8, MICROMIPSOP_SH_IMM8): Likewise.
(MICROMIPSOP_MASK_IMM10, MICROMIPSOP_SH_IMM10): Likewise.
(MICROMIPSOP_MASK_WRDSP, MICROMIPSOP_SH_WRDSP): Likewise.
(MICROMIPSOP_MASK_RDDSP, MICROMIPSOP_SH_RDDSP): Likewise.
(MICROMIPSOP_MASK_BP, MICROMIPSOP_SH_BP): Likewise.
(MICROMIPSOP_MASK_MT_U, MICROMIPSOP_SH_MT_U): Likewise.
(MICROMIPSOP_MASK_MT_H, MICROMIPSOP_SH_MT_H): Likewise.
(MICROMIPSOP_MASK_MTACC_T, MICROMIPSOP_SH_MTACC_T): Likewise.
(MICROMIPSOP_MASK_MTACC_D, MICROMIPSOP_SH_MTACC_D): Likewise.
(MICROMIPSOP_MASK_BBITIND, MICROMIPSOP_SH_BBITIND): Likewise.
(MICROMIPSOP_MASK_CINSPOS, MICROMIPSOP_SH_CINSPOS): Likewise.
(MICROMIPSOP_MASK_CINSLM1, MICROMIPSOP_SH_CINSLM1): Likewise.
(MICROMIPSOP_MASK_SEQI, MICROMIPSOP_SH_SEQI): Likewise.
(micromips_opcodes): New declaration.
(bfd_micromips_num_opcodes): Likewise.
* mips.h (INSN2_UNCOND_BRANCH, INSN2_COND_BRANCH): New macros.
* mips.h (INSN2_MOD_GPR_MHI): New macro.
(INSN2_MOD_GPR_MM, INSN2_MOD_GPR_MN): Likewise.
(MICROMIPSOP_MASK_MH, MICROMIPSOP_SH_MH): Likewise.
(MICROMIPSOP_MASK_MI, MICROMIPSOP_SH_MI): Likewise.
(MICROMIPSOP_MASK_MM, MICROMIPSOP_SH_MM): Likewise.
(MICROMIPSOP_MASK_MN, MICROMIPSOP_SH_MN): Likewise.
ld/testsuite/
2010-12-07 Catherine Moore <clm@codesourcery.com>
Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* lib/ld-lib.exp (run_dump_test): Support distinct assembler
flags for the same source named multiple times.
* ld-mips-elf/jalx-1.s: New test source.
* ld-mips-elf/jalx-1.d: New test output.
* ld-mips-elf/jalx-1.ld: New test linker script.
* ld-mips-elf/jalx-2-main.s: New test source.
* ld-mips-elf/jalx-2-ex.s: Likewise.
* ld-mips-elf/jalx-2-printf.s: Likewise.
* ld-mips-elf/jalx-2.dd: New test output.
* ld-mips-elf/jalx-2.ld: New test linker script.
* ld-mips-elf/mips16-and-micromips.d: New test.
* ld-mips-elf/mips-elf.exp: Run the new tests
opcodes/
2010-12-07 Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* micromips-opc.c: New file.
* mips-dis.c (micromips_to_32_reg_b_map): New array.
(micromips_to_32_reg_c_map, micromips_to_32_reg_d_map): Likewise.
(micromips_to_32_reg_e_map, micromips_to_32_reg_f_map): Likewise.
(micromips_to_32_reg_g_map, micromips_to_32_reg_l_map): Likewise.
(micromips_to_32_reg_q_map): Likewise.
(micromips_imm_b_map, micromips_imm_c_map): Likewise.
(micromips_ase): New variable.
(is_micromips): New function.
(set_default_mips_dis_options): Handle microMIPS ASE.
(print_insn_micromips): New function.
(is_compressed_mode_p): Likewise.
(_print_insn_mips): Handle microMIPS instructions.
* Makefile.am (CFILES): Add micromips-opc.c.
* configure.in (bfd_mips_arch): Add micromips-opc.lo.
* Makefile.in: Regenerate.
* configure: Regenerate.
* mips-dis.c (micromips_to_32_reg_h_map): New variable.
(micromips_to_32_reg_i_map): Likewise.
(micromips_to_32_reg_m_map): Likewise.
(micromips_to_32_reg_n_map): New macro.
[-- Attachment #2: Type: APPLICATION/octet-stream, Size: 157572 bytes --]
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2010-12-07 1:13 ` Maciej W. Rozycki
@ 2010-12-12 14:59 ` Richard Sandiford
2010-12-14 13:30 ` Maciej W. Rozycki
2011-01-02 11:36 ` Richard Sandiford
1 sibling, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2010-12-12 14:59 UTC (permalink / raw)
To: Maciej W. Rozycki
Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers,
Nathan Froyd
This is a review of everything up to the end of elfxx-mips.c. Not sure
when I'll be able to do the rest.
I think we're getting close, so could you post any updates as patches
relative to this one, rather than reposting the whole thing?
"Maciej W. Rozycki" <macro@codesourcery.com> writes:
> @@ -2372,7 +3002,14 @@ bfd_elf64_bfd_reloc_name_lookup (bfd *ab
> i++)
> if (mips16_elf64_howto_table_rela[i].name != NULL
> && strcasecmp (mips16_elf64_howto_table_rela[i].name, r_name) == 0)
> - return &mips16_elf64_howto_table_rela[i];
> +
> + for (i = 0;
> + i < (sizeof (micromips_elf64_howto_table_rela)
> + / sizeof (micromips_elf64_howto_table_rela[0]));
> + i++)
> + if (micromips_elf64_howto_table_rela[i].name != NULL
> + && strcasecmp (micromips_elf64_howto_table_rela[i].name, r_name) == 0)
> + return µmips_elf64_howto_table_rela[i];
>
> if (strcasecmp (elf_mips_gnu_vtinherit_howto.name, r_name) == 0)
> return &elf_mips_gnu_vtinherit_howto;
This hunk looks wrong. I doubt you meant to remove the mips16 line.
Same for elfn32-mips.c.
> @@ -5040,6 +5159,10 @@ mips_elf_calculate_relocation (bfd *abfd
> }
>
> target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (h->root.other);
> + /* If the output section is the PLT section,
> + then the target is not microMIPS. */
> + target_is_micromips_code_p = (htab->splt != sec)
> + && ELF_ST_IS_MICROMIPS (h->root.other);
> }
>
> /* If this is a reference to a 16-bit function with a stub, we need
Formatting nit:
/* If the output section is the PLT section,
then the target is not microMIPS. */
target_is_micromips_code_p = (htab->splt != sec
&& ELF_ST_IS_MICROMIPS (h->root.other));
More importantly, the comment isn't any help. When do we create
statically-resolved relocations against .plt?
> /* Calls from 16-bit code to 32-bit code and vice versa require the
> - mode change. */
> - *cross_mode_jump_p = !info->relocatable
> - && ((r_type == R_MIPS16_26 && !target_is_16_bit_code_p)
> - || ((r_type == R_MIPS_26 || r_type == R_MIPS_JALR)
> - && target_is_16_bit_code_p));
> + mode change. This is not required for calls to undefined weak
> + symbols, which should never be executed at runtime. */
But why do we need to go out of our way to check for them? I'm sure
there's a good reason, but the comment doesn't give much clue what it is.
> @@ -9223,6 +9499,16 @@ _bfd_mips_elf_relocate_section (bfd *out
> case bfd_reloc_ok:
> break;
>
> + case bfd_reloc_outofrange:
> + if (jal_reloc_p (howto->type))
> + {
> + msg = _("JALX to not a word-aligned address");
> + info->callbacks->warning
> + (info, msg, name, input_bfd, input_section, rel->r_offset);
> + return FALSE;
> + }
> + /* Fall through. */
> +
> default:
> abort ();
> break;
I suppose that should be something like "JALX to a non-word-aligned address".
> + /* microMIPS local and global symbols have the least significant bit
> + set. Because all values are either multiple of 2 or multiple of
> + 4, compensating for this bit is as simple as setting it in
> + comparisons. Just to be sure, check anyway before proceeding. */
> + BFD_ASSERT (addr % 2 == 0);
> + BFD_ASSERT (toaddr % 2 == 0);
> + BFD_ASSERT (count % 2 == 0);
I'm suspicious about the toaddr assert. You can create text sections
with odd-valued sizes:
.section .text.foo,"ax",@progbits
.byte 1
and as discussed elsewhere, asserts are really to double-check
conditions that we think must already hold.
> + addr |= 1;
> + toaddr |= 1;
> +
> + /* Adjust the local symbols defined in this section. */
> + symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
> + isym = (Elf_Internal_Sym *) symtab_hdr->contents;
> + for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
> + {
> + if (isym->st_shndx == sec_shndx
> + && isym->st_value > addr
> + && isym->st_value < toaddr)
> + isym->st_value -= count;
> + }
Hmm, microMIPS symbols created in the proper, blessed way (by proper,
blessed ways of defining MIPS16 labels in assembly) should be even in
the input object, and IIRC, the linker keeps local symbols that way
internally. Only symbols entered into the hash table are odd.
(c.f. mips_elf_calculate_relocation, where we have to add 1 to
local symbols.) So I would have expected the "|= 1"s to be applied
after this block rather than before it. Even then:
> + /* Now adjust the global symbols defined in this section. */
> + symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
> + - symtab_hdr->sh_info);
> + sym_hashes = start_hashes = elf_sym_hashes (abfd);
> + end_hashes = sym_hashes + symcount;
> +
> + for (; sym_hashes < end_hashes; sym_hashes++)
> + {
> + struct elf_link_hash_entry *sym_hash = *sym_hashes;
> +
> + if ((sym_hash->root.type == bfd_link_hash_defined
> + || sym_hash->root.type == bfd_link_hash_defweak)
> + && sym_hash->root.u.def.section == sec
> + && sym_hash->root.u.def.value > addr
> + && sym_hash->root.u.def.value < toaddr)
> + sym_hash->root.u.def.value -= count;
> + }
...if we're willing to extend the upper bound in this way, I wonder
whether there's really any point having an upper bound at all.
Then again, why doesn't the standard range (used by most targets)
include toaddr? If you define an end marker:
end_of_section:
# nothing after this
then wouldn't end_of_section == toaddr, and shouldn't it be included?
I see some targets rightly adjust st_size too. We should do
the same here.
> +static unsigned long
> +find_match (unsigned long opcode, const struct opcode_descriptor insn[])
> +{
> + unsigned long indx;
> +
> + /* First opcode_table[] entry is ignored. */
> + for (indx = 1; insn[indx].mask != 0; indx++)
> + if (MATCH (opcode, insn[indx]))
> + return indx;
> +
> + return 0;
> +}
But _why_ is the first entry ignored?
> +/* Check if there *might* be a 16-bit branch or jump at OFFSET
> + with a fixed or variable length delay slot. */
> +
> +static int
> +relax_dslot_norel16 (bfd *abfd, bfd_byte *ptr)
There's no parameter called "offset". How about:
/* If PTR is known to point to a 16-bit branch or jump, return the
minimum length of its delay slot, otherwise return 0. */
At least, that's what the code seems to do, since it returns 2 for
things like:
> + { /* "b(g|l)(e|t)z", "s,p", */ 0x40000000, 0xff200000 },
which as far as I can tell from the opcodes patch allows both 16-bit
and 32-bit delay slots. (IV-g doesn't seem to be public yet, so I can't
check the spec.) But from the way the function is used, it looks
like 0 really means "no size constraints", so why doesn't the function
return 0 for instructions like these?
Why are these routines checking for branches anyway? We don't support
branches without relocations when doing this kind of relaxation.
I'd have expected only indirect jumps to be handled here.
Likewise relax_dslot_norel32.
> + /* We don't have to do anything for a relocatable link, if
> + this section does not have relocs, or if this is not a
> + code section. */
> +
> + if (link_info->relocatable
> + || (sec->flags & SEC_RELOC) == 0
> + || sec->reloc_count == 0
> + || (sec->flags & SEC_CODE) == 0)
> + return TRUE;
Should we also check whether the micromips bit is set in the ELF
header flags?
> + nextopc = bfd_get_16 (abfd, contents + irel->r_offset + 4);
> + /* B16 */
> + if (MATCH (nextopc, b_insn_16))
> + break;
> + /* JR16 */
> + if (MATCH (nextopc, jr_insn_16) && reg != JR16_REG (nextopc))
> + break;
> + /* BEQZ16, BNEZ16 */
> + if (MATCH (nextopc, bz_insn_16) && reg != BZ16_REG (nextopc))
> + break;
> + /* JALR16 */
> + if (MATCH (nextopc, jalr_insn_16_bd32)
> + && reg != JR16_REG (nextopc) && reg != RA)
> + break;
> + continue;
I think this should be split out into a subfunction, like the relax_* ones.
/* PTR points to a 2-byte instruction. Return true if it is a 16-bit
branch that does not use register REG. */
static bfd_boolean
is_16bit_branch_p (bfd *abfd, bfd_byte *ptr, unsigned int reg)
Likewise for the 4-byte case.
> + /* Give up if not the same register used with both relocations. */
"Give up unless the same register is used with both relocations."
> + /* Now adjust pcrval, subtracting the offset to the LO16 reloc,
> + adding the size of the LUI instruction deleted and rounding
> + up to take masking of the two LSBs into account. */
> + pcrval = ((pcrval - offset + 4 + 3) | 3) ^ 3;
Maybe its just me, but since pcrval was calculated much earlier,
and hasn't been used since being set, I'd find it easier to understand
if we simply calculate the pcrval for irel[1] directly:
/* Calculate the pc-relative distance of the target from the LO16,
assuming that we can delete the 4-byte LUI. */
pcrval = (symval
- (sec->output_section->vma + sec->output_offset)
- (irel[1].r_offset - 4));
/* Round up to take the masking of the two LSBs into account. */
pcrval = (prcval + 3) & -4;
What happens when we can't delete the LUI, because of its being in
a branch delay slot?
> + int bdsize = -1;
[...]
> + /* See if there is a jump or a branch reloc preceding the
> + LUI instruction immediately. If so, then perform jump
> + or branch relaxation. */
> + for (ibrrel = internal_relocs; ibrrel < irelend; ibrrel++)
> + {
> + offset = irel->r_offset - ibrrel->r_offset;
> + if (offset != 2 && offset != 4)
> + continue;
> +
> + br_r_type = ELF32_R_TYPE (ibrrel->r_info);
> + if (offset == 2
> + && br_r_type != R_MICROMIPS_PC7_S1
> + && br_r_type != R_MICROMIPS_PC10_S1
> + && br_r_type != R_MICROMIPS_JALR)
> + continue;
> + if (offset == 4
> + && br_r_type != R_MICROMIPS_26_S1
> + && br_r_type != R_MICROMIPS_PC16_S1
> + && br_r_type != R_MICROMIPS_JALR)
> + continue;
> +
> + bdsize = relax_dslot_rel (abfd,
> + contents + ibrrel->r_offset, offset);
> + break;
> + }
> +
> + /* Otherwise see if the LUI instruction *might* be in a
> + branch delay slot. */
> + if (bdsize == -1)
> + {
> + bfd_byte *ptr = contents + ibrrel->r_offset;
> +
> + /* Assume the 32-bit LUI instruction is in a fixed delay slot
> + and cannot be optimised away. */
> + bdsize = 4;
> +
> + if (ibrrel->r_offset >= 2)
> + bdsize16 = relax_dslot_norel16 (abfd, ptr - 2);
> + if (ibrrel->r_offset >= 4)
> + bdsize32 = relax_dslot_norel32 (abfd, ptr - 4);
I think the "ibrrel"s in the last block should be "irel"s instead.
As best I can tell, "ibrrel" == "irelend" here. Is this case
covered by the testsuite?
I'm not sure whether I like the idea of making this function quadratic
simply to decide whether the preceding instruction is a branch,
but there's probably not much we can do about that.
Richard
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2010-12-12 14:59 ` Richard Sandiford
@ 2010-12-14 13:30 ` Maciej W. Rozycki
2010-12-14 14:51 ` Richard Sandiford
` (2 more replies)
0 siblings, 3 replies; 41+ messages in thread
From: Maciej W. Rozycki @ 2010-12-14 13:30 UTC (permalink / raw)
To: Richard Sandiford, Ilie Garbacea, Joseph Myers
Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
Catherine Moore, Nathan Sidwell, Nathan Froyd
Hello,
Ilie, Joseph: I have some questions for you below, please respond.
> This is a review of everything up to the end of elfxx-mips.c. Not sure
> when I'll be able to do the rest.
OK, thanks for your effort so far.
> I think we're getting close, so could you post any updates as patches
> relative to this one, rather than reposting the whole thing?
Yes, I think it will make it easier for us both to keep track of what has
been addressed and what not. I have no technical problem with including
further changes in a separate patch.
> > @@ -2372,7 +3002,14 @@ bfd_elf64_bfd_reloc_name_lookup (bfd *ab
> > i++)
> > if (mips16_elf64_howto_table_rela[i].name != NULL
> > && strcasecmp (mips16_elf64_howto_table_rela[i].name, r_name) == 0)
> > - return &mips16_elf64_howto_table_rela[i];
> > +
> > + for (i = 0;
> > + i < (sizeof (micromips_elf64_howto_table_rela)
> > + / sizeof (micromips_elf64_howto_table_rela[0]));
> > + i++)
> > + if (micromips_elf64_howto_table_rela[i].name != NULL
> > + && strcasecmp (micromips_elf64_howto_table_rela[i].name, r_name) == 0)
> > + return µmips_elf64_howto_table_rela[i];
> >
> > if (strcasecmp (elf_mips_gnu_vtinherit_howto.name, r_name) == 0)
> > return &elf_mips_gnu_vtinherit_howto;
>
> This hunk looks wrong. I doubt you meant to remove the mips16 line.
> Same for elfn32-mips.c.
I believe I fixed this problem with elf32-mips.c, but obviously must have
missed it here, thanks for spotting.
> > @@ -5040,6 +5159,10 @@ mips_elf_calculate_relocation (bfd *abfd
> > }
> >
> > target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (h->root.other);
> > + /* If the output section is the PLT section,
> > + then the target is not microMIPS. */
> > + target_is_micromips_code_p = (htab->splt != sec)
> > + && ELF_ST_IS_MICROMIPS (h->root.other);
> > }
> >
> > /* If this is a reference to a 16-bit function with a stub, we need
>
> Formatting nit:
>
> /* If the output section is the PLT section,
> then the target is not microMIPS. */
> target_is_micromips_code_p = (htab->splt != sec
> && ELF_ST_IS_MICROMIPS (h->root.other));
>
> More importantly, the comment isn't any help. When do we create
> statically-resolved relocations against .plt?
PLT entries are currently hardcoded to standard MIPS code -- this is
what the comment refers to. This has nothing to do with relocations
being static or dynamic. The implication is if jumping to the PLT from
microMIPS code then the usual JALX's restrictions apply (no sibling calls
and no short instructions in the delay slot).
I've fixed formatting, thanks -- there were so many of such errors I
could have easily missed one or two.
> > /* Calls from 16-bit code to 32-bit code and vice versa require the
> > - mode change. */
> > - *cross_mode_jump_p = !info->relocatable
> > - && ((r_type == R_MIPS16_26 && !target_is_16_bit_code_p)
> > - || ((r_type == R_MIPS_26 || r_type == R_MIPS_JALR)
> > - && target_is_16_bit_code_p));
> > + mode change. This is not required for calls to undefined weak
> > + symbols, which should never be executed at runtime. */
>
> But why do we need to go out of our way to check for them? I'm sure
> there's a good reason, but the comment doesn't give much clue what it is.
Undefined weak symbols are, well, undefined, so they have resolved to nil
and are meant never to be jumped to, so we don't want to error out on them
just because they do not have the ISA bit set and a JALX therefore
required could not be used for some reason, like the invocation being a
sibling call or because it would not satisfy the fixed delay slot
dependency.
So we decide never to make a cross-mode jump in this situation and leave
the original jump instruction (i.e. JAL, JALS or JR) in place. If the
instruction is indeed reached, then 1 will be written to the PC rather
than 0 that would "canonically" be required here, but the outcome will be
the same (assuming the zeroth page is unmapped), i.e. a segfault will
happen.
Joseph, I reckon you were involved with this piece -- did I get all the
context right here?
> > @@ -9223,6 +9499,16 @@ _bfd_mips_elf_relocate_section (bfd *out
> > case bfd_reloc_ok:
> > break;
> >
> > + case bfd_reloc_outofrange:
> > + if (jal_reloc_p (howto->type))
> > + {
> > + msg = _("JALX to not a word-aligned address");
> > + info->callbacks->warning
> > + (info, msg, name, input_bfd, input_section, rel->r_offset);
> > + return FALSE;
> > + }
> > + /* Fall through. */
> > +
> > default:
> > abort ();
> > break;
>
> I suppose that should be something like "JALX to a non-word-aligned address".
Updated, thanks.
> > + /* microMIPS local and global symbols have the least significant bit
> > + set. Because all values are either multiple of 2 or multiple of
> > + 4, compensating for this bit is as simple as setting it in
> > + comparisons. Just to be sure, check anyway before proceeding. */
> > + BFD_ASSERT (addr % 2 == 0);
> > + BFD_ASSERT (toaddr % 2 == 0);
> > + BFD_ASSERT (count % 2 == 0);
>
> I'm suspicious about the toaddr assert. You can create text sections
> with odd-valued sizes:
>
> .section .text.foo,"ax",@progbits
> .byte 1
>
> and as discussed elsewhere, asserts are really to double-check
> conditions that we think must already hold.
Will check that. [FIXME]
> > + addr |= 1;
> > + toaddr |= 1;
> > +
> > + /* Adjust the local symbols defined in this section. */
> > + symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
> > + isym = (Elf_Internal_Sym *) symtab_hdr->contents;
> > + for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
> > + {
> > + if (isym->st_shndx == sec_shndx
> > + && isym->st_value > addr
> > + && isym->st_value < toaddr)
> > + isym->st_value -= count;
> > + }
>
> Hmm, microMIPS symbols created in the proper, blessed way (by proper,
> blessed ways of defining MIPS16 labels in assembly) should be even in
> the input object, and IIRC, the linker keeps local symbols that way
> internally. Only symbols entered into the hash table are odd.
> (c.f. mips_elf_calculate_relocation, where we have to add 1 to
> local symbols.) So I would have expected the "|= 1"s to be applied
> after this block rather than before it. Even then:
>
> > + /* Now adjust the global symbols defined in this section. */
> > + symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
> > + - symtab_hdr->sh_info);
> > + sym_hashes = start_hashes = elf_sym_hashes (abfd);
> > + end_hashes = sym_hashes + symcount;
> > +
> > + for (; sym_hashes < end_hashes; sym_hashes++)
> > + {
> > + struct elf_link_hash_entry *sym_hash = *sym_hashes;
> > +
> > + if ((sym_hash->root.type == bfd_link_hash_defined
> > + || sym_hash->root.type == bfd_link_hash_defweak)
> > + && sym_hash->root.u.def.section == sec
> > + && sym_hash->root.u.def.value > addr
> > + && sym_hash->root.u.def.value < toaddr)
> > + sym_hash->root.u.def.value -= count;
> > + }
>
> ...if we're willing to extend the upper bound in this way, I wonder
> whether there's really any point having an upper bound at all.
>
> Then again, why doesn't the standard range (used by most targets)
> include toaddr? If you define an end marker:
>
> end_of_section:
> # nothing after this
>
> then wouldn't end_of_section == toaddr, and shouldn't it be included?
Ilie, I'm told you were responsible for this piece of code -- would you
please respond to these questions?
> I see some targets rightly adjust st_size too. We should do
> the same here.
Agreed. [FIXME]
> > +static unsigned long
> > +find_match (unsigned long opcode, const struct opcode_descriptor insn[])
> > +{
> > + unsigned long indx;
> > +
> > + /* First opcode_table[] entry is ignored. */
> > + for (indx = 1; insn[indx].mask != 0; indx++)
> > + if (MATCH (opcode, insn[indx]))
> > + return indx;
> > +
> > + return 0;
> > +}
>
> But _why_ is the first entry ignored?
There must be a reason, Ilie?
> > +/* Check if there *might* be a 16-bit branch or jump at OFFSET
> > + with a fixed or variable length delay slot. */
> > +
> > +static int
> > +relax_dslot_norel16 (bfd *abfd, bfd_byte *ptr)
>
> There's no parameter called "offset". How about:
Yes, that's my typo; it should have been PTR, not OFFSET.
> /* If PTR is known to point to a 16-bit branch or jump, return the
> minimum length of its delay slot, otherwise return 0. */
I'll keep the "*might*" because this is heuristics allowing possible
false positives. It may be the second half of another instruction and not
a branch at all. Otherwise OK, thanks.
> At least, that's what the code seems to do, since it returns 2 for
> things like:
>
> > + { /* "b(g|l)(e|t)z", "s,p", */ 0x40000000, 0xff200000 },
>
> which as far as I can tell from the opcodes patch allows both 16-bit
> and 32-bit delay slots. (IV-g doesn't seem to be public yet, so I can't
> check the spec.) But from the way the function is used, it looks
> like 0 really means "no size constraints", so why doesn't the function
> return 0 for instructions like these?
Only link variations of branches and jumps have a fixed-size delay slot
-- that's because the link register is set to a fixed offset from the
delay-slot instruction (either four as with JAL or two as with JALS). Of
all such jumps and branches only JALX does not have a JALXS counterpart
(regrettably, as it would have made life of software much, much easier).
I've explained the meaning of 0 below -- it's unsafe to return this value
for a variable-size delay slot.
BTW, I've just spotted and fixed a bug in relax_dslot_norel32 --
jal_insn_32_bd32 should be matched against instead of bz_insns_32
obviously. Hopefully you didn't get confused by that.
> Why are these routines checking for branches anyway? We don't support
> branches without relocations when doing this kind of relaxation.
> I'd have expected only indirect jumps to be handled here.
>
> Likewise relax_dslot_norel32.
They are checked for because a LUI cannot be deleted entirely if it is in
a delay slot as to do so would change the semantics of code being
modified. The implementation of relax_dslot_norel{16,32}() reflect this.
These functions return the minimum delay slot size required, i.e. 0 if
none, 2 if a fixed 16-bit or a variable-size delay slot is needed or 4 if
a fixed 32-bit delay slot is needed. In addition to this some branches
may be replaced with a compact (no-delay-slot) variation making the
deletion of the LUI possible (as in relax_dslot_rel()).
If the deletion of the LUI is not possible after all, then it's replaced
with a NOP according to the size of the delay slot.
Good point about the relocations -- perhaps the instruction tables used
for matching can be reduced to include jumps only (I'd keep absolute jumps
here too as they may legitimately appear in input with no relocation
associated and will normally cause no trouble even if moved around a bit,
i.e. unless they cross to another 27-bit region). I'll think about that.
Original code I received didn't check for branch relocations here at all
and relied purely on instruction decoding, sigh... :( [FIXME]
> > + /* We don't have to do anything for a relocatable link, if
> > + this section does not have relocs, or if this is not a
> > + code section. */
> > +
> > + if (link_info->relocatable
> > + || (sec->flags & SEC_RELOC) == 0
> > + || sec->reloc_count == 0
> > + || (sec->flags & SEC_CODE) == 0)
> > + return TRUE;
>
> Should we also check whether the micromips bit is set in the ELF
> header flags?
Yes, with my recent file ASE flag improvements this will definitely make
sense, thanks for the hint. [FIXME]
> > + nextopc = bfd_get_16 (abfd, contents + irel->r_offset + 4);
> > + /* B16 */
> > + if (MATCH (nextopc, b_insn_16))
> > + break;
> > + /* JR16 */
> > + if (MATCH (nextopc, jr_insn_16) && reg != JR16_REG (nextopc))
> > + break;
> > + /* BEQZ16, BNEZ16 */
> > + if (MATCH (nextopc, bz_insn_16) && reg != BZ16_REG (nextopc))
> > + break;
> > + /* JALR16 */
> > + if (MATCH (nextopc, jalr_insn_16_bd32)
> > + && reg != JR16_REG (nextopc) && reg != RA)
> > + break;
> > + continue;
>
> I think this should be split out into a subfunction, like the relax_* ones.
>
> /* PTR points to a 2-byte instruction. Return true if it is a 16-bit
> branch that does not use register REG. */
>
> static bfd_boolean
> is_16bit_branch_p (bfd *abfd, bfd_byte *ptr, unsigned int reg)
>
> Likewise for the 4-byte case.
Indeed, that should be possible. I'll look into it. [FIXME]
> > + /* Give up if not the same register used with both relocations. */
>
> "Give up unless the same register is used with both relocations."
Fixed, thanks.
> > + /* Now adjust pcrval, subtracting the offset to the LO16 reloc,
> > + adding the size of the LUI instruction deleted and rounding
> > + up to take masking of the two LSBs into account. */
> > + pcrval = ((pcrval - offset + 4 + 3) | 3) ^ 3;
>
> Maybe its just me, but since pcrval was calculated much earlier,
> and hasn't been used since being set, I'd find it easier to understand
> if we simply calculate the pcrval for irel[1] directly:
>
> /* Calculate the pc-relative distance of the target from the LO16,
> assuming that we can delete the 4-byte LUI. */
> pcrval = (symval
> - (sec->output_section->vma + sec->output_offset)
> - (irel[1].r_offset - 4));
>
> /* Round up to take the masking of the two LSBs into account. */
> pcrval = (prcval + 3) & -4;
>
> What happens when we can't delete the LUI, because of its being in
> a branch delay slot?
Hmm, that's a bug (although unlikely to trigger), thanks for spotting it.
I've fixed it by making sure the distance fits into ADDIUPC both with and
without the LUI deleted. It's a minimal pessimisation only for a boundary
case, so not worth any further improvement.
Recalculating pcrval looks to me like a waste of CPU time here -- we've
already calculated it for the other "if" clauses, so we just need to fetch
it from the local frame now.
> > + int bdsize = -1;
> [...]
> > + /* See if there is a jump or a branch reloc preceding the
> > + LUI instruction immediately. If so, then perform jump
> > + or branch relaxation. */
> > + for (ibrrel = internal_relocs; ibrrel < irelend; ibrrel++)
> > + {
> > + offset = irel->r_offset - ibrrel->r_offset;
> > + if (offset != 2 && offset != 4)
> > + continue;
> > +
> > + br_r_type = ELF32_R_TYPE (ibrrel->r_info);
> > + if (offset == 2
> > + && br_r_type != R_MICROMIPS_PC7_S1
> > + && br_r_type != R_MICROMIPS_PC10_S1
> > + && br_r_type != R_MICROMIPS_JALR)
> > + continue;
> > + if (offset == 4
> > + && br_r_type != R_MICROMIPS_26_S1
> > + && br_r_type != R_MICROMIPS_PC16_S1
> > + && br_r_type != R_MICROMIPS_JALR)
> > + continue;
> > +
> > + bdsize = relax_dslot_rel (abfd,
> > + contents + ibrrel->r_offset, offset);
> > + break;
> > + }
> > +
> > + /* Otherwise see if the LUI instruction *might* be in a
> > + branch delay slot. */
> > + if (bdsize == -1)
> > + {
> > + bfd_byte *ptr = contents + ibrrel->r_offset;
> > +
> > + /* Assume the 32-bit LUI instruction is in a fixed delay slot
> > + and cannot be optimised away. */
> > + bdsize = 4;
> > +
> > + if (ibrrel->r_offset >= 2)
> > + bdsize16 = relax_dslot_norel16 (abfd, ptr - 2);
> > + if (ibrrel->r_offset >= 4)
> > + bdsize32 = relax_dslot_norel32 (abfd, ptr - 4);
>
> I think the "ibrrel"s in the last block should be "irel"s instead.
> As best I can tell, "ibrrel" == "irelend" here. Is this case
> covered by the testsuite?
Correct and fixed, thanks.
There are no testcases addressing any of this linker relaxation I would
be aware of, sorry.
> I'm not sure whether I like the idea of making this function quadratic
> simply to decide whether the preceding instruction is a branch,
> but there's probably not much we can do about that.
Hmm, we could do this in two passes over the reloc table (still O(n)) and
first make a fast auxiliary data structure (e.g. a hash) to keep addresses
of branch and jump relocations. Given linker relaxation is off by default
I'd vote for this as a future improvement.
As a summary here's the patch resulting from the changes I made as noted
above. No regressions so far. Regrettably owing to higher priority
commitments I'll have to defer further work on issues marked with [FIXME]
above until a later date.
Maciej
binutils-umips-fix.diff
Index: binutils-fsf-trunk-quilt/bfd/elf64-mips.c
===================================================================
--- binutils-fsf-trunk-quilt.orig/bfd/elf64-mips.c 2010-12-13 15:20:06.000000000 +0000
+++ binutils-fsf-trunk-quilt/bfd/elf64-mips.c 2010-12-13 15:22:01.000000000 +0000
@@ -3002,6 +3002,7 @@ bfd_elf64_bfd_reloc_name_lookup (bfd *ab
i++)
if (mips16_elf64_howto_table_rela[i].name != NULL
&& strcasecmp (mips16_elf64_howto_table_rela[i].name, r_name) == 0)
+ return &mips16_elf64_howto_table_rela[i];
for (i = 0;
i < (sizeof (micromips_elf64_howto_table_rela)
Index: binutils-fsf-trunk-quilt/bfd/elfn32-mips.c
===================================================================
--- binutils-fsf-trunk-quilt.orig/bfd/elfn32-mips.c 2010-12-13 15:20:06.000000000 +0000
+++ binutils-fsf-trunk-quilt/bfd/elfn32-mips.c 2010-12-13 15:22:50.000000000 +0000
@@ -2820,6 +2820,7 @@ bfd_elf32_bfd_reloc_name_lookup (bfd *ab
i++)
if (elf_mips16_howto_table_rela[i].name != NULL
&& strcasecmp (elf_mips16_howto_table_rela[i].name, r_name) == 0)
+ return &elf_mips16_howto_table_rela[i];
for (i = 0;
i < (sizeof (elf_micromips_howto_table_rela)
Index: binutils-fsf-trunk-quilt/bfd/elfxx-mips.c
===================================================================
--- binutils-fsf-trunk-quilt.orig/bfd/elfxx-mips.c 2010-12-13 15:20:06.000000000 +0000
+++ binutils-fsf-trunk-quilt/bfd/elfxx-mips.c 2010-12-13 19:08:46.000000000 +0000
@@ -5161,8 +5161,8 @@ mips_elf_calculate_relocation (bfd *abfd
target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (h->root.other);
/* If the output section is the PLT section,
then the target is not microMIPS. */
- target_is_micromips_code_p = (htab->splt != sec)
- && ELF_ST_IS_MICROMIPS (h->root.other);
+ target_is_micromips_code_p = ((htab->splt != sec)
+ && ELF_ST_IS_MICROMIPS (h->root.other));
}
/* If this is a reference to a 16-bit function with a stub, we need
@@ -9502,7 +9502,7 @@ _bfd_mips_elf_relocate_section (bfd *out
case bfd_reloc_outofrange:
if (jal_reloc_p (howto->type))
{
- msg = _("JALX to not a word-aligned address");
+ msg = _("JALX to a non-word-aligned address");
info->callbacks->warning
(info, msg, name, input_bfd, input_section, rel->r_offset);
return FALSE;
@@ -12188,8 +12188,10 @@ find_match (unsigned long opcode, const
/* Delay slot size and relaxation support. */
-/* Check if there *might* be a 16-bit branch or jump at OFFSET
- with a fixed or variable length delay slot. */
+/* If PTR points to what *might* be a 16-bit branch or jump, then
+ return the minimum length of its delay slot, otherwise return 0.
+ Non-zero results are not definitive as we might be checking against
+ the second half of another instruction. */
static int
relax_dslot_norel16 (bfd *abfd, bfd_byte *ptr)
@@ -12212,8 +12214,10 @@ relax_dslot_norel16 (bfd *abfd, bfd_byte
return bdsize;
}
-/* Check if there *might* be a 32-bit branch or jump at OFFSET
- with a fixed or variable length delay slot. */
+/* If PTR points to what *might* be a 32-bit branch or jump, then
+ return the minimum length of its delay slot, otherwise return 0.
+ Non-zero results are not definitive as we might be checking against
+ the second half of another instruction. */
static int
relax_dslot_norel32 (bfd *abfd, bfd_byte *ptr)
@@ -12223,7 +12227,7 @@ relax_dslot_norel32 (bfd *abfd, bfd_byte
opcode = (bfd_get_16 (abfd, ptr) << 16) | bfd_get_16 (abfd, ptr + 2);
if (find_match (opcode, call_insns_32_bd32) != 0
- || find_match (opcode, bz_insns_32) != 0
+ || MATCH (opcode, jal_insn_32_bd32) != 0
|| MATCH (opcode, jalx_insn_32_bd32) != 0)
/* 32-bit branch/jump with a 32-bit delay slot. */
bdsize = 4;
@@ -12550,14 +12554,13 @@ _bfd_mips_elf_relax_section (bfd *abfd,
nextopc = bfd_get_16 (abfd, contents + irel[1].r_offset ) << 16;
nextopc |= bfd_get_16 (abfd, contents + irel[1].r_offset + 2);
- /* Give up if not the same register used with both relocations. */
+ /* Give up unless the same register used with both relocations. */
if (OP32_SREG (nextopc) != reg)
continue;
- /* Now adjust pcrval, subtracting the offset to the LO16 reloc,
- adding the size of the LUI instruction deleted and rounding
- up to take masking of the two LSBs into account. */
- pcrval = ((pcrval - offset + 4 + 3) | 3) ^ 3;
+ /* Now adjust pcrval, subtracting the offset to the LO16 reloc
+ and rounding up to take masking of the two LSBs into account. */
+ pcrval = ((pcrval - offset + 3) | 3) ^ 3;
/* R_MICROMIPS_LO16 relaxation to R_MICROMIPS_HI0_LO16. */
if (IS_BITSIZE (symval, 16))
@@ -12573,9 +12576,14 @@ _bfd_mips_elf_relax_section (bfd *abfd,
contents + irel[1].r_offset);
}
- /* R_MICROMIPS_LO16 / ADDIU relaxation to R_MICROMIPS_PC23_S2. */
+ /* R_MICROMIPS_LO16 / ADDIU relaxation to R_MICROMIPS_PC23_S2.
+ As we don't know at this stage if we'll be able to delete
+ the LUI in the end, we check both the original PC-relative
+ distance and one with 4 added to take LUI deletion into
+ account. */
else if (symval % 4 == 0
&& IS_BITSIZE (pcrval, 25)
+ && IS_BITSIZE (pcrval + 4, 25)
&& MATCH (nextopc, addiu_insn)
&& OP32_TREG (nextopc) == OP32_SREG (nextopc)
&& OP16_VALID_REG (OP32_TREG (nextopc)))
@@ -12627,15 +12635,15 @@ _bfd_mips_elf_relax_section (bfd *abfd,
branch delay slot. */
if (bdsize == -1)
{
- bfd_byte *ptr = contents + ibrrel->r_offset;
+ bfd_byte *ptr = contents + irel->r_offset;
/* Assume the 32-bit LUI instruction is in a fixed delay slot
and cannot be optimised away. */
bdsize = 4;
- if (ibrrel->r_offset >= 2)
+ if (irel->r_offset >= 2)
bdsize16 = relax_dslot_norel16 (abfd, ptr - 2);
- if (ibrrel->r_offset >= 4)
+ if (irel->r_offset >= 4)
bdsize32 = relax_dslot_norel32 (abfd, ptr - 4);
if (bdsize16 == -1 && bdsize32 == -1)
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2010-12-14 13:30 ` Maciej W. Rozycki
@ 2010-12-14 14:51 ` Richard Sandiford
2010-12-16 11:54 ` Maciej W. Rozycki
2010-12-14 17:56 ` Joseph S. Myers
2010-12-17 20:56 ` Fu, Chao-Ying
2 siblings, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2010-12-14 14:51 UTC (permalink / raw)
To: Maciej W. Rozycki
Cc: Ilie Garbacea, Joseph Myers, binutils, Chao-ying Fu, Rich Fuhler,
David Lau, Kevin Mills, Catherine Moore, Nathan Sidwell,
Nathan Froyd
"Maciej W. Rozycki" <macro@codesourcery.com> writes:
>> I think we're getting close, so could you post any updates as patches
>> relative to this one, rather than reposting the whole thing?
>
> Yes, I think it will make it easier for us both to keep track of what has
> been addressed and what not. I have no technical problem with including
> further changes in a separate patch.
Thanks. For avoidance of doubt, please make any updates (with the FIXMEs
fixed, for instance), relative to the original.
>> Formatting nit:
>>
>> /* If the output section is the PLT section,
>> then the target is not microMIPS. */
>> target_is_micromips_code_p = (htab->splt != sec
>> && ELF_ST_IS_MICROMIPS (h->root.other));
>>
>> More importantly, the comment isn't any help. When do we create
>> statically-resolved relocations against .plt?
Oops, ignore this, I was thinking "sec" was the section that contained
the relocation.
>> > /* Calls from 16-bit code to 32-bit code and vice versa require the
>> > - mode change. */
>> > - *cross_mode_jump_p = !info->relocatable
>> > - && ((r_type == R_MIPS16_26 && !target_is_16_bit_code_p)
>> > - || ((r_type == R_MIPS_26 || r_type == R_MIPS_JALR)
>> > - && target_is_16_bit_code_p));
>> > + mode change. This is not required for calls to undefined weak
>> > + symbols, which should never be executed at runtime. */
>>
>> But why do we need to go out of our way to check for them? I'm sure
>> there's a good reason, but the comment doesn't give much clue what it is.
>
> Undefined weak symbols are, well, undefined, so they have resolved to nil
> and are meant never to be jumped to, so we don't want to error out on them
> just because they do not have the ISA bit set and a JALX therefore
> required could not be used for some reason, like the invocation being a
> sibling call or because it would not satisfy the fixed delay slot
> dependency.
OK, makes sense. Please update the comment to something like:
/* Calls from 16-bit code to 32-bit code and vice versa require the
mode change. However, we can ignore calls to undefined weak symbols,
which should never be executed at runtime. This exception is important
because the assembly writer may have "known" that any definition of the
symbol would be 16-bit code, and that direct jumps were therefore
acceptable. */
>> At least, that's what the code seems to do, since it returns 2 for
>> things like:
>>
>> > + { /* "b(g|l)(e|t)z", "s,p", */ 0x40000000, 0xff200000 },
>>
>> which as far as I can tell from the opcodes patch allows both 16-bit
>> and 32-bit delay slots. (IV-g doesn't seem to be public yet, so I can't
>> check the spec.) But from the way the function is used, it looks
>> like 0 really means "no size constraints", so why doesn't the function
>> return 0 for instructions like these?
>
> Only link variations of branches and jumps have a fixed-size delay slot
> -- that's because the link register is set to a fixed offset from the
> delay-slot instruction (either four as with JAL or two as with JALS). Of
> all such jumps and branches only JALX does not have a JALXS counterpart
> (regrettably, as it would have made life of software much, much easier).
>
> I've explained the meaning of 0 below -- it's unsafe to return this value
> for a variable-size delay slot.
Hmm, I was thinking of the case where there was no branch _after_
the LUI, and where the instruction after the LUI could then become
the delay slot for a variable-length branch before the (deleted) LUI.
But yeah, I can see that 0 isn't correct if there is a branch immediately
after the LUI.
>> I'm not sure whether I like the idea of making this function quadratic
>> simply to decide whether the preceding instruction is a branch,
>> but there's probably not much we can do about that.
>
> Hmm, we could do this in two passes over the reloc table (still O(n)) and
> first make a fast auxiliary data structure (e.g. a hash) to keep addresses
> of branch and jump relocations. Given linker relaxation is off by default
> I'd vote for this as a future improvement.
Yeah, I'd wondered about that, but then we'd need to measure whether that
made things better or not. I'm OK with leaving it.
Richard
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2010-12-14 13:30 ` Maciej W. Rozycki
2010-12-14 14:51 ` Richard Sandiford
@ 2010-12-14 17:56 ` Joseph S. Myers
2010-12-16 15:28 ` Maciej W. Rozycki
2010-12-17 20:56 ` Fu, Chao-Ying
2 siblings, 1 reply; 41+ messages in thread
From: Joseph S. Myers @ 2010-12-14 17:56 UTC (permalink / raw)
To: Maciej W. Rozycki
Cc: Richard Sandiford, Ilie Garbacea, binutils, Chao-ying Fu,
Rich Fuhler, David Lau, Kevin Mills, Catherine Moore,
Nathan Sidwell, Nathan Froyd
On Tue, 14 Dec 2010, Maciej W. Rozycki wrote:
> > > /* Calls from 16-bit code to 32-bit code and vice versa require the
> > > - mode change. */
> > > - *cross_mode_jump_p = !info->relocatable
> > > - && ((r_type == R_MIPS16_26 && !target_is_16_bit_code_p)
> > > - || ((r_type == R_MIPS_26 || r_type == R_MIPS_JALR)
> > > - && target_is_16_bit_code_p));
> > > + mode change. This is not required for calls to undefined weak
> > > + symbols, which should never be executed at runtime. */
> >
> > But why do we need to go out of our way to check for them? I'm sure
> > there's a good reason, but the comment doesn't give much clue what it is.
>
> Undefined weak symbols are, well, undefined, so they have resolved to nil
> and are meant never to be jumped to, so we don't want to error out on them
> just because they do not have the ISA bit set and a JALX therefore
> required could not be used for some reason, like the invocation being a
> sibling call or because it would not satisfy the fixed delay slot
> dependency.
>
> So we decide never to make a cross-mode jump in this situation and leave
> the original jump instruction (i.e. JAL, JALS or JR) in place. If the
> instruction is indeed reached, then 1 will be written to the PC rather
> than 0 that would "canonically" be required here, but the outcome will be
> the same (assuming the zeroth page is unmapped), i.e. a segfault will
> happen.
>
> Joseph, I reckon you were involved with this piece -- did I get all the
> context right here?
Yes. A call to an undefined weak function is equally valid at compile and
link time and invalid at execution time if executed whether or not the
code is compiled in such a way as to support cross-mode jumps. Such a
call is a call to an undefined function, never a call to an other-mode
function, and so the linker should never give errors for cases such as
JALS where it cannot convert to a cross-mode jump. The original observed
problem case was statically linking sln with a call to
__nptl_deallocate_tsd that never gets executed in single-threaded
programs.
--
Joseph S. Myers
joseph@codesourcery.com
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2010-12-14 14:51 ` Richard Sandiford
@ 2010-12-16 11:54 ` Maciej W. Rozycki
2010-12-18 10:26 ` Richard Sandiford
0 siblings, 1 reply; 41+ messages in thread
From: Maciej W. Rozycki @ 2010-12-16 11:54 UTC (permalink / raw)
To: Richard Sandiford
Cc: Ilie Garbacea, Joseph Myers, binutils, Chao-ying Fu, Rich Fuhler,
David Lau, Kevin Mills, Catherine Moore, Nathan Sidwell,
Nathan Froyd
On Tue, 14 Dec 2010, Richard Sandiford wrote:
> > Yes, I think it will make it easier for us both to keep track of what has
> > been addressed and what not. I have no technical problem with including
> > further changes in a separate patch.
>
> Thanks. For avoidance of doubt, please make any updates (with the FIXMEs
> fixed, for instance), relative to the original.
Yes, this is what I assumed too.
> > Undefined weak symbols are, well, undefined, so they have resolved to nil
> > and are meant never to be jumped to, so we don't want to error out on them
> > just because they do not have the ISA bit set and a JALX therefore
> > required could not be used for some reason, like the invocation being a
> > sibling call or because it would not satisfy the fixed delay slot
> > dependency.
>
> OK, makes sense. Please update the comment to something like:
>
> /* Calls from 16-bit code to 32-bit code and vice versa require the
> mode change. However, we can ignore calls to undefined weak symbols,
> which should never be executed at runtime. This exception is important
> because the assembly writer may have "known" that any definition of the
> symbol would be 16-bit code, and that direct jumps were therefore
> acceptable. */
Done, thanks.
> > Only link variations of branches and jumps have a fixed-size delay slot
> > -- that's because the link register is set to a fixed offset from the
> > delay-slot instruction (either four as with JAL or two as with JALS). Of
> > all such jumps and branches only JALX does not have a JALXS counterpart
> > (regrettably, as it would have made life of software much, much easier).
> >
> > I've explained the meaning of 0 below -- it's unsafe to return this value
> > for a variable-size delay slot.
>
> Hmm, I was thinking of the case where there was no branch _after_
> the LUI, and where the instruction after the LUI could then become
> the delay slot for a variable-length branch before the (deleted) LUI.
> But yeah, I can see that 0 isn't correct if there is a branch immediately
> after the LUI.
Well, if we have code like this:
branch ...
LUI ...
insn [...]
(where for the purpose of this consideration BRANCH may also be a jump)
then LUI cannot be entirely deleted and INSN moved into the slot of BRANCH
no matter if INSN is a branch or an computational instruction. All we can
do in this case is to see if there is a corresponding BRANCHC instruction
and use it to swap BRANCH with and then delete the LUI if so, or otherwise
shrink the LUI to a 16-bit NOP if BRANCH permits or can be swapped with
BRANCHS to permit a 16-bit delay-slot instruction. If neither is
possible, then the LUI is merely substituted with a 32-bit NOP (although
the effect is purely cosmetical in this case; perhaps we should just back
out).
Also with the recent update to LUI relaxation code I think we should
simply disallow the optimisation if a LUI is in a delay slot of an
unconditional branch -- we have no way to verify the corresponding LO16
reloc really belongs to this LUI instruction in that case. This will let
us simplify code (which has become a little bit hairy by now IMO) a little
bit I would guess. [FIXME]
> > Hmm, we could do this in two passes over the reloc table (still O(n)) and
> > first make a fast auxiliary data structure (e.g. a hash) to keep addresses
> > of branch and jump relocations. Given linker relaxation is off by default
> > I'd vote for this as a future improvement.
>
> Yeah, I'd wondered about that, but then we'd need to measure whether that
> made things better or not. I'm OK with leaving it.
The breaking point may be high -- we'd have to benchmark a program with a
suitably high number of relocations to decide whether to go for that at
all. And then perhaps only enable the optimisation selectively at the run
time, based on the size of the reloc table and the expected density of
HI16/LO16 reloc pairs within. And even then, in a typical compilation
there are relatively few final links, so shaving a couple of seconds off a
compilation that otherwise takes half a dozen of minutes may be missing
the point.
Maciej
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2010-12-14 17:56 ` Joseph S. Myers
@ 2010-12-16 15:28 ` Maciej W. Rozycki
0 siblings, 0 replies; 41+ messages in thread
From: Maciej W. Rozycki @ 2010-12-16 15:28 UTC (permalink / raw)
To: Joseph S. Myers
Cc: Richard Sandiford, Ilie Garbacea, binutils, Chao-ying Fu,
Rich Fuhler, David Lau, Kevin Mills, Catherine Moore,
Nathan Sidwell, Nathan Froyd
On Tue, 14 Dec 2010, Joseph S. Myers wrote:
> > Joseph, I reckon you were involved with this piece -- did I get all the
> > context right here?
>
> Yes. A call to an undefined weak function is equally valid at compile and
> link time and invalid at execution time if executed whether or not the
> code is compiled in such a way as to support cross-mode jumps. Such a
> call is a call to an undefined function, never a call to an other-mode
> function, and so the linker should never give errors for cases such as
> JALS where it cannot convert to a cross-mode jump. The original observed
> problem case was statically linking sln with a call to
> __nptl_deallocate_tsd that never gets executed in single-threaded
> programs.
OK, thanks for confirmation.
Maciej
^ permalink raw reply [flat|nested] 41+ messages in thread
* RE: [PATCH] MIPS: microMIPS ASE support
2010-12-14 13:30 ` Maciej W. Rozycki
2010-12-14 14:51 ` Richard Sandiford
2010-12-14 17:56 ` Joseph S. Myers
@ 2010-12-17 20:56 ` Fu, Chao-Ying
2010-12-18 10:09 ` Richard Sandiford
2 siblings, 1 reply; 41+ messages in thread
From: Fu, Chao-Ying @ 2010-12-17 20:56 UTC (permalink / raw)
To: Maciej W. Rozycki, Richard Sandiford, Garbacea, Ilie, Joseph Myers
Cc: binutils, Fuhler, Rich, Lau, David, Mills, Kevin,
Catherine Moore, Nathan Sidwell, Nathan Froyd
> Hello,
>
> Ilie, Joseph: I have some questions for you below, please respond.
Ilie is on vacations.
> > > + /* Now adjust the global symbols defined in this section. */
> > > + symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
> > > + - symtab_hdr->sh_info);
> > > + sym_hashes = start_hashes = elf_sym_hashes (abfd);
> > > + end_hashes = sym_hashes + symcount;
> > > +
> > > + for (; sym_hashes < end_hashes; sym_hashes++)
> > > + {
> > > + struct elf_link_hash_entry *sym_hash = *sym_hashes;
> > > +
> > > + if ((sym_hash->root.type == bfd_link_hash_defined
> > > + || sym_hash->root.type == bfd_link_hash_defweak)
> > > + && sym_hash->root.u.def.section == sec
> > > + && sym_hash->root.u.def.value > addr
> > > + && sym_hash->root.u.def.value < toaddr)
> > > + sym_hash->root.u.def.value -= count;
> > > + }
> >
> > ...if we're willing to extend the upper bound in this way, I wonder
> > whether there's really any point having an upper bound at all.
> >
> > Then again, why doesn't the standard range (used by most targets)
> > include toaddr? If you define an end marker:
> >
> > end_of_section:
> > # nothing after this
> >
> > then wouldn't end_of_section == toaddr, and shouldn't it be
> included?
>
> Ilie, I'm told you were responsible for this piece of code
> -- would you
> please respond to these questions?
I think we should include "end_of_section == toaddr".
Ex:
&& sym_hash->root.u.def.value <= toaddr)
> > > +static unsigned long
> > > +find_match (unsigned long opcode, const struct
> opcode_descriptor insn[])
> > > +{
> > > + unsigned long indx;
> > > +
> > > + /* First opcode_table[] entry is ignored. */
> > > + for (indx = 1; insn[indx].mask != 0; indx++)
> > > + if (MATCH (opcode, insn[indx]))
> > > + return indx;
> > > +
> > > + return 0;
> > > +}
> >
> > But _why_ is the first entry ignored?
>
> There must be a reason, Ilie?
I guess Ilie tries to avoid passing a single-entry table into find_match().
But if we do pass a single-entry table into find_match(),
find_match() may not find the end marker and it will be wrong anyway.
Maybe we just delete all the { 1, 1 } entry in opcode_descriptor [] tables, and
find_match() doesn't ignore the first entry.
And we make sure that each table has end marker at the end.
Thanks!
Regards,
Chao-ying
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2010-12-17 20:56 ` Fu, Chao-Ying
@ 2010-12-18 10:09 ` Richard Sandiford
0 siblings, 0 replies; 41+ messages in thread
From: Richard Sandiford @ 2010-12-18 10:09 UTC (permalink / raw)
To: Fu, Chao-Ying
Cc: Maciej W. Rozycki, Garbacea, Ilie, Joseph Myers, binutils,
Fuhler, Rich, Lau, David, Mills, Kevin, Catherine Moore,
Nathan Sidwell, Nathan Froyd
"Fu, Chao-Ying" <fu@mips.com> writes:
>> > > + /* Now adjust the global symbols defined in this section. */
>> > > + symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
>> > > + - symtab_hdr->sh_info);
>> > > + sym_hashes = start_hashes = elf_sym_hashes (abfd);
>> > > + end_hashes = sym_hashes + symcount;
>> > > +
>> > > + for (; sym_hashes < end_hashes; sym_hashes++)
>> > > + {
>> > > + struct elf_link_hash_entry *sym_hash = *sym_hashes;
>> > > +
>> > > + if ((sym_hash->root.type == bfd_link_hash_defined
>> > > + || sym_hash->root.type == bfd_link_hash_defweak)
>> > > + && sym_hash->root.u.def.section == sec
>> > > + && sym_hash->root.u.def.value > addr
>> > > + && sym_hash->root.u.def.value < toaddr)
>> > > + sym_hash->root.u.def.value -= count;
>> > > + }
>> >
>> > ...if we're willing to extend the upper bound in this way, I wonder
>> > whether there's really any point having an upper bound at all.
>> >
>> > Then again, why doesn't the standard range (used by most targets)
>> > include toaddr? If you define an end marker:
>> >
>> > end_of_section:
>> > # nothing after this
>> >
>> > then wouldn't end_of_section == toaddr, and shouldn't it be
>> included?
>>
>> Ilie, I'm told you were responsible for this piece of code
>> -- would you
>> please respond to these questions?
>
> I think we should include "end_of_section == toaddr".
> Ex:
> && sym_hash->root.u.def.value <= toaddr)
I agree that's probably the best thing, although I admit the "Then again,"
question was really more general musing than a question about this patch.
To be more specific, the thing that worried me about this code was that:
- if the section ends with a microMIPS instruction and an end marker,
the "value < toaddr" won't include the end marker. (The end marker
would be odd.)
- if the section ends with a normal MIPS instruction and an end marker,
the "value < toaddr" _would_ include the end marker. (The end marker
would be even.)
That's the key difference between "toaddr |= 1 ... value < toaddr"
and "value &= -2 .... value < toaddr". I think the latter is more
consistent.
I suggest removing:
+ BFD_ASSERT (toaddr % 2 == 0);
+ addr |= 1;
+ toaddr |= 1;
and instead masking the low bit off the u.def.value. (Keep the other
two asserts though. I certainly found them useful when reviewing
the code.)
>> > > +static unsigned long
>> > > +find_match (unsigned long opcode, const struct
>> opcode_descriptor insn[])
>> > > +{
>> > > + unsigned long indx;
>> > > +
>> > > + /* First opcode_table[] entry is ignored. */
>> > > + for (indx = 1; insn[indx].mask != 0; indx++)
>> > > + if (MATCH (opcode, insn[indx]))
>> > > + return indx;
>> > > +
>> > > + return 0;
>> > > +}
>> >
>> > But _why_ is the first entry ignored?
>>
>> There must be a reason, Ilie?
>
> I guess Ilie tries to avoid passing a single-entry table into find_match().
> But if we do pass a single-entry table into find_match(),
> find_match() may not find the end marker and it will be wrong anyway.
> Maybe we just delete all the { 1, 1 } entry in opcode_descriptor [] tables, and
> find_match() doesn't ignore the first entry.
> And we make sure that each table has end marker at the end.
Yeah, I think that'd be better, thanks.
Richard
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2010-12-16 11:54 ` Maciej W. Rozycki
@ 2010-12-18 10:26 ` Richard Sandiford
0 siblings, 0 replies; 41+ messages in thread
From: Richard Sandiford @ 2010-12-18 10:26 UTC (permalink / raw)
To: Maciej W. Rozycki
Cc: Ilie Garbacea, Joseph Myers, binutils, Chao-ying Fu, Rich Fuhler,
David Lau, Kevin Mills, Catherine Moore, Nathan Sidwell,
Nathan Froyd
"Maciej W. Rozycki" <macro@codesourcery.com> writes:
>> > Only link variations of branches and jumps have a fixed-size delay slot
>> > -- that's because the link register is set to a fixed offset from the
>> > delay-slot instruction (either four as with JAL or two as with JALS). Of
>> > all such jumps and branches only JALX does not have a JALXS counterpart
>> > (regrettably, as it would have made life of software much, much easier).
>> >
>> > I've explained the meaning of 0 below -- it's unsafe to return this value
>> > for a variable-size delay slot.
>>
>> Hmm, I was thinking of the case where there was no branch _after_
>> the LUI, and where the instruction after the LUI could then become
>> the delay slot for a variable-length branch before the (deleted) LUI.
>> But yeah, I can see that 0 isn't correct if there is a branch immediately
>> after the LUI.
>
> Well, if we have code like this:
>
> branch ...
> LUI ...
> insn [...]
>
> (where for the purpose of this consideration BRANCH may also be a jump)
> then LUI cannot be entirely deleted and INSN moved into the slot of BRANCH
> no matter if INSN is a branch or an computational instruction. All we can
> do in this case is to see if there is a corresponding BRANCHC instruction
> and use it to swap BRANCH with and then delete the LUI if so, or otherwise
> shrink the LUI to a 16-bit NOP if BRANCH permits or can be swapped with
> BRANCHS to permit a 16-bit delay-slot instruction. If neither is
> possible, then the LUI is merely substituted with a 32-bit NOP (although
> the effect is purely cosmetical in this case; perhaps we should just back
> out).
Yeah, I see your point. I was thinking that the code claims to "know"
that the LUI and "insn" are both part of the same load address. So if
the branch was taken, the target of the LUI ought to be dead. However,
I agree that (even though the code does seem to assume that to some extent)
the assumption is wrong.
E.g. you could have:
beqz $2,1f
lui $4,%hi(foo) <-- A
addiu $4,$4,%lo(foo) <-- B
...
jr $31
2: ...
lui $4,%hi(foo) <-- C
...
1: addiu $4,$4,%lo(foo) <-- D
In this case, the LO16 reloc for D might follow the HI16 reloc for C,
and the LO16 reloc for B might follow the HI16 reloc for A. AIUI, we'd
consider relaxing A/B but not C/D. In this case, turning A into a NOP
is wrong, because $4 is still live at D. If you agree then...
> Also with the recent update to LUI relaxation code I think we should
> simply disallow the optimisation if a LUI is in a delay slot of an
> unconditional branch -- we have no way to verify the corresponding LO16
> reloc really belongs to this LUI instruction in that case. This will let
> us simplify code (which has become a little bit hairy by now IMO) a little
> bit I would guess. [FIXME]
...maybe it would be simpler to drop the optimisation if the LUI is any
kind of delay slot. I think this would simply the code, and I don't think
we'd then need to check for branch relocs. We'd just have *_norel-like
functions (although not called that any more) to check for every kind
of branch.
I obviously had a bit of a mental block when reviewing this delay slot
stuff, sorry.
Richard
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2010-12-07 1:13 ` Maciej W. Rozycki
2010-12-12 14:59 ` Richard Sandiford
@ 2011-01-02 11:36 ` Richard Sandiford
2011-02-21 15:35 ` Maciej W. Rozycki
1 sibling, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2011-01-02 11:36 UTC (permalink / raw)
To: Maciej W. Rozycki
Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers,
Nathan Froyd
This is the second and final part of the review.
First of all, thanks for the great effort you've made to integrate the
microMIPS macro code into macro(). This is much, much better than before,
and should be far less of a maintenance burden.
FWIW, I plan to review the follow-up patch based purely on whether
it deals with the review comments. Anything that we've collectively
missed this far (and there's bound to be something) will just have to
be fixed when someone trips over it.
I think the only change of any significant size that needs to be made
is to move the place where we convert to microMIPS relocs (see below).
Everything else is pretty small.
> @@ -1821,6 +1830,8 @@ the target word. These are used on the
> ENUM
> BFD_RELOC_GPREL16
> ENUMX
> + BFD_RELOC_MICROMIPS_GPREL16
> +ENUMX
> BFD_RELOC_GPREL32
> ENUMDOC
> For systems that allocate a Global Pointer register, these are
You've now moved most of the new relocs into MIPS-specific areas, thanks,
but some, like the one above, are still in generic lists. Let's put:
ENUM
BFD_RELOC_MICROMIPS_7_PCREL_S1
ENUMX
BFD_RELOC_MICROMIPS_10_PCREL_S1
ENUMX
BFD_RELOC_MICROMIPS_16_PCREL_S1
ENUMDOC
MicroMIPS PC-relative relocations.
before the main "MIPS ELF relocations." section, followed
by a new section:
ENUM
BFD_RELOC_MICROMIPS_GPREL16
ENUMX
BFD_RELOC_MICROMIPS_HI16
ENUMX
BFD_RELOC_MICROMIPS_HI16_S
ENUMX
BFD_RELOC_MICROMIPS_LO16
ENUMDOC
MicroMIPS versions of generic BFD relocs.
Also, let's combine this:
> @@ -2182,6 +2193,11 @@ ENUMDOC
> simple reloc otherwise.
>
> ENUM
> + BFD_RELOC_MICROMIPS_JMP
> +ENUMDOC
> + The microMIPS jump instruction.
> +
> +ENUM
> BFD_RELOC_MIPS16_JMP
> ENUMDOC
> The MIPS16 jump instruction.
with the MIPS_JMP entry, since you're doing the same with the other
microMIPS versions of MIPS relocs.
> + /* Whether we are assembling for the mipsMIPS processor. 0 if we are
> + not, 1 if we are, and -1 if the value has not been initialized.
> + Changed by `.set micromips' and `.set nomicromips', and the -mmicromips
> + and -mno-micromips command line options, and the default CPU. */
> + int micromips;
Blind cut-&-paste. "microMIPS ASE".
Let's leave the -1 case and:
> +/* Return true if the given CPU supports microMIPS. */
> +#define CPU_HAS_MICROMIPS(cpu) 0
out. I think the CPU_HAS_MIPS16 stuff is derived from the original LSI
TinyRisc support and wouldn't be used for ASEs.
> @@ -495,9 +515,11 @@ static int mips_32bitmode = 0;
> require nops to be inserted. This applies to instructions marked
> INSN_LOAD_MEMORY_DELAY. These nops are only required at MIPS ISA
> level I. */
> -#define gpr_interlocks \
> - (mips_opts.isa != ISA_MIPS1 \
> - || mips_opts.arch == CPU_R3900)
> +#define gpr_interlocks \
> + (mips_opts.isa != ISA_MIPS1 \
> + || mips_opts.arch == CPU_R3900 \
> + || mips_opts.micromips \
> + )
>
> /* Whether the processor uses hardware interlocks to avoid delays
> required by coprocessor instructions, and thus does not require
> @@ -512,6 +534,7 @@ static int mips_32bitmode = 0;
> && mips_opts.isa != ISA_MIPS2 \
> && mips_opts.isa != ISA_MIPS3) \
> || mips_opts.arch == CPU_R4300 \
> + || mips_opts.micromips \
> )
>
> /* Whether the processor uses hardware interlocks to protect reads
> @@ -519,7 +542,10 @@ static int mips_32bitmode = 0;
> thus does not require nops to be inserted. This applies to
> instructions marked INSN_COPROC_MEMORY_DELAY. These nops are only
> requires at MIPS ISA level I. */
> -#define cop_mem_interlocks (mips_opts.isa != ISA_MIPS1)
> +#define cop_mem_interlocks \
> + (mips_opts.isa != ISA_MIPS1 \
> + || mips_opts.micromips \
> + )
>
> /* Is this a mfhi or mflo instruction? */
> #define MF_HILO_INSN(PINFO) \
These changes are OK if they make life easier, but please add a comment
saying why they do.
> +#define RELAX_MICROMIPS_ENCODE(type, is_16bit, uncond, link, toofar) \
> + (0x40000000 \
> + | ((type) & 0xff) \
> + | ((is_16bit) ? 0x100 : 0) \
> + | ((uncond) ? 0x200 : 0) \
> + | ((link) ? 0x400 : 0) \
> + | ((toofar) ? 0x800 : 0))
> +#define RELAX_MICROMIPS_P(i) (((i) & 0xc0000000) == 0x40000000)
> +#define RELAX_MICROMIPS_TYPE(i) ((i) & 0xff)
> +#define RELAX_MICROMIPS_USER_16BIT(i) (((i) & 0x100) != 0)
> +#define RELAX_MICROMIPS_UNCOND(i) (((i) & 0x200) != 0)
> +#define RELAX_MICROMIPS_LINK(i) (((i) & 0x400) != 0)
> +#define RELAX_MICROMIPS_TOOFAR(i) (((i) & 0x800) != 0)
> +#define RELAX_MICROMIPS_MARK_TOOFAR(i) ((i) | 0x800)
> +#define RELAX_MICROMIPS_CLEAR_TOOFAR(i) ((i) & ~0x800)
Is there a need to create variant frags when the user has explicitly
specified the instruction size? I wouldn't have expected any relaxation
to be necessary in that case, and it looks like the relaxation code does
indeed return 2 whenever USER_16BIT is true.
If the bit really is needed, let's call the parameter "user_16bit"
rather than "is_16bit", to match the use.
Add a comment saying what RELAX_MICROMIPS_TYPE is. See the MIPS16
comment as an example.
> +#define RELAX_MICROMIPS_EXTENDED(i) (((i) & 0x10000) != 0)
> +#define RELAX_MICROMIPS_MARK_EXTENDED(i) ((i) | 0x10000)
> +#define RELAX_MICROMIPS_CLEAR_EXTENDED(i) ((i) & ~0x10000)
Any particular reason why 0x10000 rather than 0x1000, which seems
to be the first unused bit? I would prefer to pack the used bits
together so that it's easier to tell what's left.
> + /* True if the macro is in a 16-bit branch delay slot. */
> + bfd_boolean delay_slot_16bit_p;
> +
> + /* True if the macro is in a 32-bit branch delay slot. */
> + bfd_boolean delay_slot_32bit_p;
I think it would be cleaner to have:
/* If the macro is in a delay slot that requires a specific length
of instruction, this is that length, otherwise it is zero. */
unsigned int delay_slot_length;
> + /* For relaxable macros, fsize[0] is the length of the first instruction
> + of the first alternative in bytes and fsize[1] is the length of the
> + first instruction of the second alternative.
> + For non-relaxable macros, both elements give the length of the
> + first instruction in bytes. */
> + unsigned int fsize[2];
Rename to "first_insn_sizes" ("sizes" rather than "size" because the
plurality comes from having two alternatives). Also add:
The fields are zero if we haven't yet seen the first instruction.
> @@ -2374,22 +2736,21 @@ s_is_linkonce (symbolS *sym, segT from_s
> return linkonce;
> }
>
> -/* Mark instruction labels in mips16 mode. This permits the linker to
> - handle them specially, such as generating jalx instructions when
> - needed. We also make them odd for the duration of the assembly, in
> - order to generate the right sort of code. We will make them even
> +/* Mark instruction labels in MIPS16/microMIPS mode. This permits the
> + linker to handle them specially, such as generating jalx instructions
> + when needed. We also make them odd for the duration of the assembly,
> + in order to generate the right sort of code. We will make them even
> in the adjust_symtab routine, while leaving them marked. This is
> convenient for the debugger and the disassembler. The linker knows
> to make them odd again. */
>
> static void
> -mips16_mark_labels (void)
> +mips_compressed_mark_labels (void)
> {
> segment_info_type *si = seg_info (now_seg);
> struct insn_label_list *l;
>
> - if (!mips_opts.mips16)
> - return;
> + gas_assert (HAVE_CODE_COMPRESSION);
>
> for (l = si->label_list; l != NULL; l = l->next)
> {
> @@ -2397,16 +2758,22 @@ mips16_mark_labels (void)
>
> #if defined(OBJ_ELF) || defined(OBJ_MAYBE_ELF)
> if (IS_ELF)
> - S_SET_OTHER (label, ELF_ST_SET_MIPS16 (S_GET_OTHER (label)));
> + {
> + if (mips_opts.mips16)
> + S_SET_OTHER (label, ELF_ST_SET_MIPS16 (S_GET_OTHER (label)));
> + else if (mips_opts.micromips)
> + S_SET_OTHER (label, ELF_ST_SET_MICROMIPS (S_GET_OTHER (label)));
> + }
> #endif
> if ((S_GET_VALUE (label) & 1) == 0
> /* Don't adjust the address if the label is global or weak, or
> in a link-once section, since we'll be emitting symbol reloc
> references to it which will be patched up by the linker, and
> - the final value of the symbol may or may not be MIPS16. */
> + the final value of the symbol may or may not be MIPS16/microMIPS. */
> && ! S_IS_WEAK (label)
> && ! S_IS_EXTERNAL (label)
> - && ! s_is_linkonce (label, now_seg))
> + && ! s_is_linkonce (label, now_seg)
> + && HAVE_CODE_COMPRESSION)
> S_SET_VALUE (label, S_GET_VALUE (label) | 1);
> }
> }
Looks like the addition of HAVE_CODE_COMPRESSION is redundant here,
you've already asserted it in the previous hunk.
> +static char *
> +micromips_label_name (void)
> +{
> + char *p = micromips_target_name;
> + char symbol_name_temporary[24];
> + unsigned long l;
> + int i;
> +
> + if (*p)
> + return p;
> +
> + i = 0;
> + l = micromips_target_label;
> +#ifdef LOCAL_LABEL_PREFIX
> + *p++ = LOCAL_LABEL_PREFIX;
> +#endif
[...]
> +int
> +mips_label_is_local (const char *name)
> +{
> + return strchr (name, MICROMIPS_LABEL_CHAR) != NULL;
> +}
Why is this change needed? The default local-label detection should be
enough for ELF targets, which always have a LOCAL_LABEL_PREFIX.
If we do need TC_LABEL_IS_LOCAL for some reason, it should be documented
in internals.texi.
> @@ -2915,7 +3367,8 @@ append_insn (struct mips_cl_insn *ip, ex
> out that the branch was out-of-range, we'll get an error. */
> && !mips_opts.warn_about_macros
> && (mips_opts.at || mips_pic == NO_PIC)
> - && !mips_opts.mips16)
> + && !mips_opts.mips16
> + && !mips_opts.micromips)
> {
> relaxed_branch = TRUE;
> add_relaxed_insn (ip, (relaxed_branch_length
!HAVE_CODE_COMPRESSION
> + if (mips_relax.sequence)
> + abort ();
gas_assert (!mips_relax.sequence);
> + /* For microMIPS, disable reordering. */
> + || mips_opts.micromips
You should say whether this is for simplicity or by specification.
Either way, a bit more detail would be welcome. E.g. something like:
/* microMIPS assembly language does not allow the assembler
to reorder instructions, even in .set reorder mode.
Delay slots are always filled with nops when .set reorder
is in effect. */
(adjusted as appropriate if my guess is wrong).
> + /* If both delay slots are out of size, then emit the warning now. */
> + if ((subtype & (RELAX_DELAY_SLOT_SIZE_FIRST | RELAX_DELAY_SLOT_SIZE_SECOND))
> + == (RELAX_DELAY_SLOT_SIZE_FIRST | RELAX_DELAY_SLOT_SIZE_SECOND))
/* If both alternatives fail to fill a delay slot correctly,
emit the warning now. */
if ((subtype & RELAX_DELAY_SLOT_SIZE_FIRST) != 0
&& (subtype & RELAX_DELAY_SLOT_SIZE_SECOND) != 0)
> + hash = !mips_opts.micromips ? op_hash : micromips_op_hash;
hash = mips_opts.micromips ? micromips_op_hash : op_hash;
> @@ -3640,13 +4407,32 @@ macro_build (expressionS *ep, const char
> /* Search until we get a match for NAME. It is assumed here that
> macros will never generate MDMX, MIPS-3D, or MT instructions. */
> if (strcmp (fmt, mo->args) == 0
> - && mo->pinfo != INSN_MACRO
> - && is_opcode_valid (mo))
> - break;
> + && mo->pinfo != INSN_MACRO)
> + {
> + bfd_boolean ok;
> + bfd_boolean size_ok;
> + bfd_boolean delay_slot_ok;
> +
> + ok = is_opcode_valid (mo);
> + size_ok = is_size_valid (mo);
> + delay_slot_ok = is_delay_slot_valid (mo);
> + if (ok && size_ok && (delay_slot_ok || secondpass))
> + break;
> + if (!delay_slot_ok && !twopass)
> + {
> + firstmo = mo;
> + twopass = TRUE;
> + }
> + }
>
> ++mo;
> - gas_assert (mo->name);
> - gas_assert (strcmp (name, mo->name) == 0);
> + if (!mo->name || strcmp (name, mo->name) != 0)
> + {
> + gas_assert (twopass);
> + gas_assert (!secondpass);
> + secondpass = TRUE;
> + mo = firstmo;
> + }
> }
>
> create_insn (&insn, mo);
Do we really need to do two passes here? I would have expected
to see something like:
if (strcmp (fmt, mo->args) == 0
&& mo->pinfo != INSN_MACRO
&& is_opcode_valid (mo)
&& is_size_valid (mo))
{
if (is_delay_slot_valid (mo))
break;
else if (!reserve_mo)
reserve_mo = mo;
}
if (!mo->name || strcmp (name, mo->name) != 0)
{
/* All usable candidates violate the delay slot requirements
of the previous instruction. Pick the first such candidate
anyway; we will issue an appropriate warning later. */
gcc_assert (reserve_mo);
mo = reserve_mo;
break;
}
which IMO is simpler and clearer.
> + if (!mips_opts.micromips)
> + INSERT_OPERAND (0, RD, insn, va_arg (args, int));
> + else
> + INSERT_OPERAND (1, RS, insn, va_arg (args, int));
if (mips_opts.micromips)
INSERT_OPERAND (1, RS, insn, va_arg (args, int));
else
INSERT_OPERAND (0, RD, insn, va_arg (args, int));
> case 'i':
> case 'j':
> macro_read_relocs (&args, r);
> - gas_assert (*r == BFD_RELOC_GPREL16
> + gas_assert (mips_opts.micromips
> + || *r == BFD_RELOC_GPREL16
> || *r == BFD_RELOC_MIPS_HIGHER
> || *r == BFD_RELOC_HI16_S
> || *r == BFD_RELOC_LO16
> || *r == BFD_RELOC_MIPS_GOT_OFST);
> + gas_assert (!mips_opts.micromips
> + || *r == BFD_RELOC_MICROMIPS_GPREL16
> + || *r == BFD_RELOC_MICROMIPS_HIGHER
> + || *r == BFD_RELOC_MICROMIPS_HI16_S
> + || *r == BFD_RELOC_MICROMIPS_LO16
> + || *r == BFD_RELOC_MICROMIPS_GOT_OFST);
Let's move the macro_read_relocs stuff inside append_insn rather than
leaving the conversion to the callers. You could then make append_insn
keep a record of the original (non-microMIPS) reloc_type[0] too,
which would simply some of the logic. E.g. these changes would
no longer be needed:
> - /* Tag symbols that have a R_MIPS16_26 relocation against them. */
> - if (reloc_type[0] == BFD_RELOC_MIPS16_JMP
> + /* Tag symbols that have a R_MIPS16_26 or R_MICROMIPS_26_S1
> + relocation against them. */
> + if ((reloc_type[0] == BFD_RELOC_MIPS16_JMP
> + || reloc_type[0] == BFD_RELOC_MICROMIPS_JMP)
> && ip->fixp[0]->fx_addsy)
> *symbol_get_tc (ip->fixp[0]->fx_addsy) = 1;
> @@ -3105,6 +3638,13 @@ append_insn (struct mips_cl_insn *ip, ex
> || reloc_type[0] == BFD_RELOC_MIPS_SCN_DISP
> || reloc_type[0] == BFD_RELOC_MIPS_REL16
> || reloc_type[0] == BFD_RELOC_MIPS_RELGOT
> + || reloc_type[0] == BFD_RELOC_MICROMIPS_JMP
> + || reloc_type[0] == BFD_RELOC_MICROMIPS_GPREL16
> + || reloc_type[0] == BFD_RELOC_MICROMIPS_LITERAL
> + || reloc_type[0] == BFD_RELOC_MICROMIPS_SUB
> + || reloc_type[0] == BFD_RELOC_MICROMIPS_HIGHEST
> + || reloc_type[0] == BFD_RELOC_MICROMIPS_HIGHER
> + || reloc_type[0] == BFD_RELOC_MICROMIPS_SCN_DISP
> || reloc_type[0] == BFD_RELOC_MIPS16_GPREL
> || hi16_reloc_p (reloc_type[0])
> || lo16_reloc_p (reloc_type[0])))
You also wouldn't need micromips_percent_op.
Sorry, I know this isn't what I said first time round, but it was much
harder to see the wood for the trees before you'd integrated the macro
code properly.
> + /* For microMIPS, check if the current instruction is not in
> + a delay slot that requires a 32-bit instruction. */
> + if (mips_opts.micromips
> + && !(history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
/* Prefer to use a 16-bit microMIPS instruction unless the previous
instruction specifically requires a 32-bit one. */
> + if CALL is set. In the reorder mode the delay slot would be filled
> + with a nop anyway, so code produced is simply:
> + BR <args>, <sym>
Add an explicit nop, since the code does.
> +/* Emit a coprocessor branch macro specified by TYPE, using CC as
> + the condition code tested. EP specifies the branch target. */
"branch-likely macro".
> +/* Emit a two-argument branch macro specified by TYPE, using SREG as
> + the register tested. EP specifies the branch target. */
> +
> +static void
> +macro_build_branch_rs (int type, expressionS *ep, unsigned int sreg)
> +{
> + const char *brneg;
> + const char *br;
> + int likely = 0;
> + int call = 0;
> +
> + switch (type)
> + {
> + case M_BGEZ:
> + br = "bgez";
> + break;
> + case M_BGEZL:
> + br = mips_opts.micromips ? "bgez" : "bgezl";
> + brneg = "bltz";
> + likely = 1;
> + break;
> + case M_BGEZALL:
> + gas_assert (mips_opts.micromips);
> + br = "bgezals";
> + brneg = "bltz";
> + likely = 1;
> + call = 1;
> + break;
> + case M_BGTZ:
> + br = "bgtz";
> + break;
> + case M_BGTZL:
> + br = mips_opts.micromips ? "bgtz" : "bgtzl";
> + brneg = "blez";
> + likely = 1;
> + break;
> + case M_BLEZ:
> + br = "blez";
> + break;
> + case M_BLEZL:
> + br = mips_opts.micromips ? "blez" : "blezl";
> + brneg = "bgtz";
> + likely = 1;
> + break;
> + case M_BLTZ:
> + br = "bltz";
> + break;
> + case M_BLTZL:
> + br = mips_opts.micromips ? "bltz" : "bltzl";
> + brneg = "bgez";
> + likely = 1;
> + break;
> + case M_BLTZALL:
> + gas_assert (mips_opts.micromips);
> + br = "bltzals";
> + brneg = "bgez";
> + likely = 1;
> + call = 1;
> + break;
> + default:
> + abort ();
> + }
> + if (mips_opts.micromips && likely)
> + macro_build_branch_likely (br, brneg, call, ep, "s,p", sreg, ZERO);
> + else
> + macro_build (ep, br, "s,p", sreg);
> +}
No need for "likely". Just initialise "brneg" to NULL and check for that.
Same for macro_build_branch_rsrt.
> + if (!mips_opts.micromips)
> + label_expr.X_add_number = 8;
> + else
> + micromips_label_expr (&label_expr);
if (mips_opts.micromips)
micromips_label_expr (&label_expr);
else
label_expr.X_add_number = 8;
(several occurences)
> - macro_build (NULL, "jalr", "d,s", dreg, sreg);
> + s = (!mips_opts.micromips || (mips_opts.noreorder && !cprestore)
> + ? "jalr" : "jalrs");
> + if (mips_opts.micromips && dreg == RA)
> + macro_build (NULL, s, "mj", sreg);
> + else
> + macro_build (NULL, s, JALR_FMT, dreg, sreg);
Since we can use JALRS for mips_opts.noreorder && cprestore, I suppose
the cprestore nop:
if (mips_opts.noreorder)
macro_build (NULL, "nop", "");
ought to be conditional on !mips_opts.micromips.
> + /* A 12-bit offset field is too narrow to be used for a low-part
> + relocation, so use the auxiliary register to load the full
> + address provided if the A(b) format has been requested;
> + load_address will produce the necessary relocations as code
> + used with 16-bit offsets below would do. Otherwise the o(b)
> + format has been selected, so load the low part only and the
> + relocation requested will have already been provided in
> + offset_reloc, so just use that. */
/* A 12-bit offset field is too narrow to be used for a low-part
relocation, so load the whole address into the auxillary
register. In the case of "A(b)" addresses, we first load
absolute address "A" into the register and then add base
register "b". In the case of "o(b)" addresses, we simply
need to add 16-bit offset "o" to base register "b", and
offset_reloc already contains the relocations associated
with "o". */
> + hash = !mips_opts.micromips ? op_hash : micromips_op_hash;
> + past = (!mips_opts.micromips ? &mips_opcodes[NUMOPCODES]
> + : µmips_opcodes[bfd_micromips_num_opcodes]);
if (mips_opts.micromips)
{
hash = micromips_op_hash;
past = µmips_opcodes[bfd_micromips_num_opcodes];
}
else
{
hash = op_hash;
past = &mips_opcodes[NUMOPCODES];
}
> @@ -8688,32 +10234,50 @@ mips_ip (char *str, struct mips_cl_insn
> argsStart = s = str + end;
> for (;;)
> {
> + bfd_boolean delay_slot_ok;
> + bfd_boolean size_ok;
> bfd_boolean ok;
>
> gas_assert (strcmp (insn->name, name) == 0);
>
> ok = is_opcode_valid (insn);
> - if (! ok)
> + size_ok = is_size_valid (insn);
> + delay_slot_ok = is_delay_slot_valid (insn);
> + if (!delay_slot_ok && !twopass)
> {
> - if (insn + 1 < &mips_opcodes[NUMOPCODES]
> - && strcmp (insn->name, insn[1].name) == 0)
> + firstinsn = insn;
> + twopass = TRUE;
> + }
> + if (!ok || !size_ok || (!delay_slot_ok && !secondpass))
> + {
> + static char buf[256];
> +
> + if (insn + 1 < past && strcmp (insn->name, insn[1].name) == 0)
> {
> ++insn;
> continue;
> }
> - else
> + if (twopass && !secondpass)
> {
> - if (!insn_error)
> - {
> - static char buf[100];
> - sprintf (buf,
> - _("opcode not supported on this processor: %s (%s)"),
> - mips_cpu_info_from_arch (mips_opts.arch)->name,
> - mips_cpu_info_from_isa (mips_opts.isa)->name);
> - insn_error = buf;
> - }
> - return;
> + gas_assert (firstinsn);
> + secondpass = TRUE;
> + insn = firstinsn;
> + continue;
> }
> +
> + if (insn_error)
> + return;
> +
> + if (!ok)
> + sprintf (buf, _("opcode not supported on this processor: %s (%s)"),
> + mips_cpu_info_from_arch (mips_opts.arch)->name,
> + mips_cpu_info_from_isa (mips_opts.isa)->name);
> + else
> + sprintf (buf, _("Unrecognized %u-bit version of microMIPS opcode"),
> + 8 * forced_insn_length);
> + insn_error = buf;
> +
> + return;
> }
>
> create_insn (ip, insn);
Same two-pass comment as before.
> + unsigned long mask = (!mips_opts.micromips
> + ? OP_MASK_CODE
> + : MICROMIPSOP_MASK_CODE);
unsigned long mask = (mips_opts.micromips
? MICROMIPSOP_MASK_CODE
: OP_MASK_CODE);
Several other cases.
> + case 'J':
> + if (!mips_opts.micromips)
> + { /* 19-bit WAIT code. */
> + my_getExpression (&imm_expr, s);
> + check_absolute_expr (ip, &imm_expr);
> + if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE19)
> + {
> + as_warn (_("Illegal 19-bit code (%lu)"),
> + (unsigned long) imm_expr.X_add_number);
> + imm_expr.X_add_number &= OP_MASK_CODE19;
> + }
> + INSERT_OPERAND (0, CODE19, *ip, imm_expr.X_add_number);
> + imm_expr.X_op = O_absent;
> + s = expr_end;
> + continue;
> }
> - INSERT_OPERAND (CODE19, *ip, imm_expr.X_add_number);
> - imm_expr.X_op = O_absent;
> - s = expr_end;
> - continue;
> + goto do_reg; /* ALNV.PS source register. */
So 'J' is used for different things depending on micromips mode?
Couldn't we use a different letter instead?
> + if (!mips_opts.micromips)
> + INSERT_OPERAND (0, RD, *ip, regno);
> + else
> + INSERT_OPERAND (1, RS, *ip, regno);
if (mips_opts.micromips)
INSERT_OPERAND (1, RS, *ip, regno);
else
INSERT_OPERAND (0, RD, *ip, regno);
> + if (!ok)
> + {
> + switch (*args++)
I realise you've copied this from elsewhere, but why "++"?
The "for" loop increments "args", doesn't it?
> + if (c == 'e')
> + {
> + regno = lastregno;
> + s = s_reset;
> + ++args;
> + }
> + else if (c == 't')
> + {
> + s = s_reset;
> + ++args;
> + continue;
> + }
I don't really understand these "args" adjustments either.
> + i = my_getSmallExpression (&imm_expr, imm_reloc, s);
> + if ((i == 0 && (imm_expr.X_op != O_constant
> + || (imm_expr.X_add_number & 3) != 0
> + || imm_expr.X_add_number > (63 << 2)
> + || imm_expr.X_add_number < (-64 << 2)))
> + || i > 0)
> + {
> + imm_expr.X_op = O_absent;
> + break;
> + }
> + immed = imm_expr.X_add_number >> 2;
> + INSERT_OPERAND (1, IMMA, *ip, immed);
> + imm_expr.X_op = O_absent;
> + s = expr_end;
> + continue;
Why set X_op to O_absent when rejecting this alternative? What breaks
if you leave the constant in imm_expr? I couldn't see any similar
error-handling code in this function.
Also:
if (my_getSmallExpression (&imm_expr, imm_reloc, s) == 0
&& imm_expr.X_op == O_constant
&& (imm_expr.X_add_number & 3) == 0
&& imm_expr.X_add_number >= (-64 << 2)
&& imm_expr.X_add_number <= (63 << 2))
{
immed = imm_expr.X_add_number >> 2;
INSERT_OPERAND (1, IMMA, *ip, immed);
imm_expr.X_op = O_absent;
s = expr_end;
continue;
}
break;
seems more in keeping with other my_getSmallExpression users.
> + i = my_getSmallExpression (&imm_expr, imm_reloc, s);
> +
> + for (immb = 0; immb < 8; immb++)
> + {
> + if (micromips_imm_b_map[immb]
> + == imm_expr.X_add_number)
> + break;
> + }
> + if ((i == 0 && (imm_expr.X_op != O_constant || immb == 8))
> + || i > 0)
> + {
> + imm_expr.X_op = O_absent;
> + break;
> + }
> + INSERT_OPERAND (1, IMMB, *ip, immb);
> + imm_expr.X_op = O_absent;
> + s = expr_end;
> + continue;
Here too I'd prefer something like:
if (my_getSmallExpression (&imm_expr, imm_reloc, s) == 0
&& imm_expr.X_op == O_constant)
{
for (immb = 0; immb < 8; immb++)
if (micromips_imm_b_map[immb]
== imm_expr.X_add_number)
break;
if (immb < 8)
{
INSERT_OPERAND (1, IMMB, *ip, immb);
imm_expr.X_op = O_absent;
s = expr_end;
continue;
}
}
break;
which has the added benefit of only using X_add_number once we've
established that it's meaningful. Similar changes in the rest
of the function.
> + /* If users want relax branch and don't specify to use
> + 16-bit instructions, we will not match this pattern.
> + This will lead to matching 32-bit instructions, that
> + will be relaxed later. */
> + if (mips_relax_branch && forced_insn_length != 2)
> + break;
This seems a bit lame. It should be easy to relax the 16-bit form
in the same way as the 32-bit form. We could use a bit in the
relaxation opcode to say whether the extra relaxation should be
enabled or not, i.e. a bit to record the relevant parts of this
condition:
+ && (pinfo & INSN_UNCOND_BRANCH_DELAY
+ || pinfo & INSN_COND_BRANCH_DELAY)
+ && mips_relax_branch
+ /* Don't try branch relaxation within .set nomacro, or within
+ .set noat if we use $at for PIC computations. If it turns
+ out that the branch was out-of-range, we'll get an error. */
+ && !mips_opts.warn_about_macros
+ && (mips_opts.at || mips_pic == NO_PIC)
+ && mips_opts.micromips
+ /* Don't try branch relaxation, when users specify 16-bit/32-bit
+ instructions. */
+ && !forced_insn_length)
No need to do that as part of this patch, but let's at least put in
a FIXME.
> + case 'N': /* Register list for lwm and swm. */
> + {
> + unsigned int reg_list = 0;
> + int immed = 0;
> + unsigned int reg1 = 33;
Why 33 rather than 32? Seems INVALID_REG could be used here for a bit
of extra readability.
> + /* s0, ra
> + s0, s1, ra
> + s0, s1, s2, ra
> + s0, s1, s2, s3, ra
> + s0-s1, ra
> + s0-s2, ra
> + s0-s3, ra */
You also allow:
s1, ra, s2, s0
(rightly IMO), so I don't think we gain much by listing the split-out ranges.
Just:
/* s0, ra
s0-s1, ra
s0-s2, ra
s0-s3, ra */
would be OK.
> + s_reset = s;
> + SKIP_SPACE_TABS (s);
> + if (*s == ',')
> + {
> + reg1 = 33;
> + ++s;
> + }
> + else if (*s == '-')
> + {
> + reg1 = regno;
> + ++s;
> + }
> + SKIP_SPACE_TABS (s);
> + ok = reg_lookup (&s, RTYPE_NUM | RTYPE_GP, ®no);
> + if (!ok)
> + {
> + s = s_reset;
> + break;
> + }
Shouldn't we break out if *s isn't ',' or '-' and treat it as a syntax
error ("reg_list = 0; break;")?
> + if (regno <= reg1)
> + {
> + reg_list = 0;
> + break;
> + }
Add a comment saying that this is an error condition. But is there
really anything wrong with $4-$4 (regno == reg1)? The range is closed
after all.
> + }
> + if (i == 0 && imm_expr.X_op == O_constant
> + && (imm_expr.X_add_number & 3) == 0
> + && imm_expr.X_add_number >= (-4194304 << 2)
> + && imm_expr.X_add_number <= (4194303 << 2))
I'm ashamed to say this decimal number wasn't in my mental power-of-2 list.
Maybe a hex constant or (1 << n) would be better? Feel free to leave it
if you disagree though.
> + case 'n': /* Register list for 32-bit lwm and swm. */
> + gas_assert (mips_opts.micromips);
> + {
> + unsigned int reg_list = 0;
> + int immed = 0;
> + unsigned int reg1 = 33;
> +
This register-range code needs to be split out into a separate function.
It's the same as for 'N' above (except for the s8 handling, which would
be OK-but-redundant for 'n' too), has the same apparent bug regarding
syntax checking, and has the same questionable behaviour about
single-register ranges.
> + /* s0, ra
> + s0, s1, ra
> + s0, s1, s2, ra
> + s0, s1, s2, s3, ra
> + s0, s1, s2, s3, s4, ra
> + s0, s1, s2, s3, s4, s5, ra
> + s0, s1, s2, s3, s4, s5, s6, ra
> + s0, s1, s2, s3, s4, s5, s6, s7, ra
> + s0, s1, s2, s3, s4, s5, s6, s7, s8, ra
> + ra,
> + s0-s1, ra
> + s0-s2, ra
> + s0-s3, ra
> + s0-s4, ra
> + s0-s5, ra
> + s0-s6, ra
> + s0-s7, ra
> + s0-s8, ra */
I'm hampered by the spec not being public yet, but it looks from the
code as though RA's actually optional when S0 is present. The comment
implies otherwise. Also:
> + if (reg_list == 0x00010000)
> + immed = 1;
> + else if (reg_list == 0x00030000)
> + immed = 2;
> + else if (reg_list == 0x00070000)
> + immed = 3;
> + else if (reg_list == 0x000f0000)
> + immed = 4;
> + else if (reg_list == 0x001f0000)
> + immed = 5;
> + else if (reg_list == 0x003f0000)
> + immed = 6;
> + else if (reg_list == 0x007f0000)
> + immed = 7;
> + else if (reg_list == 0x00ff0000)
> + immed = 8;
> + else if (reg_list == 0x40ff0000)
> + immed = 9;
> + else if (reg_list == 0x80000000)
> + immed = 16;
> + else if (reg_list == 0x80010000)
> + immed = 17;
> + else if (reg_list == 0x80030000)
> + immed = 18;
> + else if (reg_list == 0x80070000)
> + immed = 19;
> + else if (reg_list == 0x800f0000)
> + immed = 20;
> + else if (reg_list == 0x801f0000)
> + immed = 21;
> + else if (reg_list == 0x803f0000)
> + immed = 22;
> + else if (reg_list == 0x807f0000)
> + immed = 23;
> + else if (reg_list == 0x80ff0000)
> + immed = 24;
> + else if (reg_list == 0xc0ff0000)
> + immed = 25;
> + else
> + break;
this could at least be simplified by testing the Sn and RA registers
separately, then rejecting immed == 0. But maybe the split-out function
could return the Sn range in a more easily digestible form.
> + /* For microMIPS we need to save the value to buf + 2. */
> + if (target_big_endian || fixP->fx_r_type == BFD_RELOC_MICROMIPS_LO16)
> buf += 2;
/* 32-bit microMIPS instructions are divided into two 16-bit pieces.
Relocations always refer to the second piece, regardless of
endianness. */
or something like that. I'm sure there's a better term than "piece" here,
what does the spec call it?
> + fragp->fr_subtype
> + = toofar ? RELAX_MICROMIPS_MARK_TOOFAR (fragp->fr_subtype)
> + : RELAX_MICROMIPS_CLEAR_TOOFAR (fragp->fr_subtype);
Non-standard alignment for ":"
fragp->fr_subtype = (toofar
? RELAX_MICROMIPS_MARK_TOOFAR (fragp->fr_subtype)
: RELAX_MICROMIPS_CLEAR_TOOFAR (fragp->fr_subtype);
> + /* 00000000 <test>:
> + 0: 405e 0006 bgez $30,10 <test+0x10>
> + 4: 0c00 nop
> + 6: fc3c 0002 lw $1,2($28)
> + 6: R_MIPS_GOT16 .text
> + a: 3021 0011 addiu $1,$1,17
> + a: R_MIPS_LO16 .text
> + e: 4721 jalr $1
> + ...
> +
> + 00020010 <test2>:
> + 20010: 0c00 nop
> + 20012: 0c00 nop
> + */
> +
> + if (!fragp && update > 0)
> + length += 6;
> +
> + if (mips_pic != NO_PIC)
> + {
> + /* Additional space for PIC loading of target address. */
> + length += 6;
> + }
> +
> + /* If branch is conditional. */
> + if (fragp ? !RELAX_MICROMIPS_UNCOND (fragp->fr_subtype) : (update >= 0))
> + length += 6;
> + }
This really isn't written very clearly. The comment has a single
long-branch form, while the code has three if statements. Say what
you're counting in each case.
> + /* For microMIPS PC relative relocations, we cannot convert it to
> + against a section. If we do, it will mess up the fixp->fx_offset. */
> if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
> - || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
> + || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY
> + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
> + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1
> + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1)
"to be against a section". That's not a helpful comment though.
_How_ will it mess up fixp->fx_offset? Give the reader a clue why
the problem applies to BFD_RELOC_MICROMIPS_16_PCREL_S1 but not
to something like BFD_RELOC_16_PCREL_S2.
> + if (RELAX_MICROMIPS_UNCOND (fragp->fr_subtype))
> + goto uncond_micromips;
Ugh. Either split out the code for unconditional branches into a subfunction,
or put intervening code into a:
if (!RELAX_MICROMIPS_UNCOND (fragp->fr_subtype))
block. (Yes, I know the current relaxation code has the same kind of goto,
but I would have raised just the same objection there. If cut-&-paste really
is necessary, the new code should still be defendable in its own right.)
Some of the comments below are also about code that has been
cut-&-pasted from the non-microMIPS branch relaxation. I haven't
flagged them up as such because it's irrelevant.
> + buf = (bfd_byte *)fragp->fr_literal + fragp->fr_fix;
Missing space before "fragp->fr_literal". A few other occurences.
> + if (RELAX_MICROMIPS_LINK (fragp->fr_subtype))
> + {
> + /* Clear the and-link bit. */
> + gas_assert ((insn & 0xffa00000) == 0x40200000);
> +
> + /* bltzal 0x04100000 bgezal 0x04110000 */
> + insn &= ~0x00200000;
> + }
Excess cut-&-paste. The opcodes in the comment are from the normal MIPS
encoding, not the microMIPS one. (Wondered at first why we were clearing
a bit that, according to the comment, wasn't supposed to be set in the
first place.)
> + /* How many bytes in instructions we've already emitted? */
> + i = buf - (bfd_byte *)fragp->fr_literal - fragp->fr_fix;
> + /* How many bytes in instructions from here to the end? */
> + i = fragp->fr_var - i;
I don't get this. "buf" still equals "fragp->fr_literal + fragp->fr_fix",
doesn't it? We haven't emitted anything yet. Seems to me that this is
(and should be) the same as "i = fragp->fr_var".
> + uncond_micromips:
> + if (mips_pic == NO_PIC)
> + {
> + /* j or jal. */
"j(al) <sym> R_MICROMIPS_26_S1"
to match the style of the other comments (and to give a bit more info).
> + /* lw/ld $at, <sym>($gp) R_MIPS_GOT16 */
> + insn = 0xfc3c0000;
> + exp.X_op = O_symbol;
> + exp.X_add_symbol = fragp->fr_symbol;
> + exp.X_add_number = fragp->fr_offset;
Add the "ld" case or fix the comment. Also s/R_MIPS_GOT16/R_MICROMIPS_LO16/.
> + /* d/addiu $at, $at, <sym> R_MIPS_LO16 */
> + insn = 0x30210000;
Likewise "daddiu".
> + gas_assert (buf == (bfd_byte *)fragp->fr_literal
> + + fragp->fr_fix + fragp->fr_var);
The "+" isn't indented far enough.
> Index: binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/mips1-fp.d
> ===================================================================
> --- binutils-fsf-trunk-quilt.orig/gas/testsuite/gas/mips/mips1-fp.d 2010-12-07 00:05:05.000000000 +0000
> +++ binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/mips1-fp.d 2010-12-07 00:14:47.000000000 +0000
> @@ -9,4 +9,4 @@
> [0-9a-f]+ <.*>:
> .*: 46041000 add.s \$f0,\$f2,\$f4
> .*: 44420000 cfc1 \$2,\$0
> -#pass
> + \.\.\.
> Index: binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/mips1-fp.s
> ===================================================================
> --- binutils-fsf-trunk-quilt.orig/gas/testsuite/gas/mips/mips1-fp.s 2010-12-07 00:05:05.000000000 +0000
> +++ binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/mips1-fp.s 2010-12-07 00:14:47.000000000 +0000
> @@ -5,3 +5,7 @@
> foo:
> add.s $f0,$f2,$f4
> cfc1 $2,$0
> +
> +# Force at least 8 (non-delay-slot) zero bytes, to make 'objdump' print ...
> + .align 2
> + .space 8
Leave out this kind of change. I realise it's not the style you prefer,
but what's there now is fine. Same for:
* gas/testsuite/gas/mips/mips32r2-fp32.d
* gas/testsuite/gas/mips/mips64.d
> msubu $11, $12
> mul $13, $14, $15
> pref 4, ($16)
> + .set at
> pref 4, 32767($17)
> pref 4, -32768($18)
> + .set noat
> ssnop
>
>
> # privileged instructions
>
> cache 5, ($1)
> + .set at
> cache 5, 32767($2)
> cache 5, -32768($3)
> - .set at
> cache 5, 32768($4)
> cache 5, -32769($5)
> cache 5, 32768
We should really have separate noat tests for the prefs and caches
that are no longer in a noat block (a bit like you did for the
wait and sdbbp tests whose immediates have changed).
> -#define STO_MIPS_PLT 0x8
> +#define STO_MIPS_PLT (1 << 3)
Don't change the definitions of the existing constants; use hex constants
for the new stuff instead.
> /* This value is used to mark PIC functions in an object that mixes
> - PIC and non-PIC. */
> -#define STO_MIPS_PIC 0x20
> -#define ELF_ST_IS_MIPS_PIC(OTHER) \
> - (((OTHER) & ~ELF_ST_VISIBILITY (-1)) == STO_MIPS_PIC)
> -#define ELF_ST_SET_MIPS_PIC(OTHER) \
> - (STO_MIPS_PIC | ELF_ST_VISIBILITY (OTHER))
> + PIC and non-PIC. Note this bit overlaps with STO_MIPS16. */
> +#define STO_MIPS_PIC (1 << 5)
> +#define ELF_ST_IS_MIPS_PIC(other) (((other) & STO_MIPS_FLAGS) == STO_MIPS_PIC)
> +#define ELF_ST_SET_MIPS_PIC(other) (((other) & ~STO_MIPS_FLAGS) | STO_MIPS_PIC)
/* This value is used to mark PIC functions in an object that mixes
PIC and non-PIC. Note that this bit overlaps with STO_MIPS16,
although MIPS16 symbols are never considered to be MIPS_PIC. */
> +/* Whether code compression (either of the MIPS16 or the microMIPS ASEs)
> + has been indicated for a .text symbol. */
> +#define ELF_ST_IS_COMPRESSED(other) \
> + (ELF_ST_IS_MIPS16(other) || ELF_ST_IS_MICROMIPS(other))
The last line is missing a space before each "(other)".
> +/* microMIPS placeholders. */
Should be a bit more descriptive. E.g.:
/* Every MICROMIPSOP_X definition requires a corresponding OP_X
definition, and vice versa. This simplifies various parts
of the operand handling in GAS. The fields below only exist in
the microMIPS encoding, so define each one to have an empty range. */
if indeed that's accurate.
> +/* These are the bitmasks and shift counts used for the different
> + fields in the instruction formats. Other than OP, no masks are
> + provided for the fixed portions of an instruction, since they are
> + not needed. */
Seems like too much cut-&-paste: there isn't an OP field here.
"Other than TARGET", perhaps, unless there are other opcode masks here.
> +/* MIPS placeholders. */
/* Placeholders for fields that only exist in the traditional 32-bit
instruction encoding; see the comment above for details. */
> + "mg" 3-bit MIPS registers 2-7, 16, 17 (MICROMIPSOP_*_MG) at bit 0
> + "mg" 3-bit MIPS registers 2-7, 16, 17 (MICROMIPSOP_*_MG) at bit 0
Doubled line.
> - Elf_Internal_Ehdr *header;
> + Elf_Internal_Ehdr *header = elf_elfheader (info->section->owner);
>
> - header = elf_elfheader (info->section->owner);
What's there now is fine.
> + else
> + iprintf (is, "UNKNOWN");
Excess indentation.
> + In microMIPS, we need to match instructions (mfc0, mtc0)
> + by hand. */
Something like:
The microMIPS encoding does not have a coprocessor
identifier field as such, so we must work out the
coprocessor number by looking at the opcode. */
might be more descriptive.
> +/* Return 1 if a symbol associated with the location being disassembled
> + indicates a compressed mode, either MIPS16 or microMIPS one. Otherwise,
> + return 0. */
Reads more naturally to me without "one".
> + for (i = 0; i < info->num_symbols; i++)
> + {
> + pos = info->symtab_pos + i;
> +
> + if (bfd_asymbol_flavour (info->symtab[pos]) != bfd_target_elf_flavour)
> + continue;
> +
> + symbol = (elf_symbol_type *) info->symtab[pos];
> + if ((!micromips_ase
> + && ELF_ST_IS_MIPS16 (symbol->internal_elf_sym.st_other))
> + || (micromips_ase
> + && ELF_ST_IS_MICROMIPS (symbol->internal_elf_sym.st_other)))
> + return 1;
> + }
Why is a search necessary here, when the previous code was happy to
look only at the first symbol? I'm not saying the code is wrong,
but a bit of commentary would be good.
What problem is the ld-lib.exp change fixing?
Richard
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2011-01-02 11:36 ` Richard Sandiford
@ 2011-02-21 15:35 ` Maciej W. Rozycki
2011-02-22 20:12 ` Fu, Chao-Ying
` (3 more replies)
0 siblings, 4 replies; 41+ messages in thread
From: Maciej W. Rozycki @ 2011-02-21 15:35 UTC (permalink / raw)
To: Richard Sandiford
Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers,
Nathan Froyd
[-- Attachment #1: Type: TEXT/PLAIN, Size: 95960 bytes --]
Hi Richard & all,
I am back at last with updates to the change and I have combined two
e-mails here again. I hope this covers all the outstanding concerns and
nothing from earlier correspondence has been lost unaddressed.
Chao-ying, there are a couple of questions for you throughout -- would
you please give them a thought? And anyone, of course, please feel free
to comment as you like.
> "Maciej W. Rozycki" <macro@codesourcery.com> writes:
> >
> > Well, if we have code like this:
> >
> > branch ...
> > LUI ...
> > insn [...]
> >
> > (where for the purpose of this consideration BRANCH may also be a jump)
> > then LUI cannot be entirely deleted and INSN moved into the slot of BRANCH
> > no matter if INSN is a branch or an computational instruction. All we can
> > do in this case is to see if there is a corresponding BRANCHC instruction
> > and use it to swap BRANCH with and then delete the LUI if so, or otherwise
> > shrink the LUI to a 16-bit NOP if BRANCH permits or can be swapped with
> > BRANCHS to permit a 16-bit delay-slot instruction. If neither is
> > possible, then the LUI is merely substituted with a 32-bit NOP (although
> > the effect is purely cosmetical in this case; perhaps we should just back
> > out).
>
> Yeah, I see your point. I was thinking that the code claims to "know"
> that the LUI and "insn" are both part of the same load address. So if
> the branch was taken, the target of the LUI ought to be dead. However,
> I agree that (even though the code does seem to assume that to some extent)
> the assumption is wrong.
>
> E.g. you could have:
>
> beqz $2,1f
> lui $4,%hi(foo) <-- A
>
> addiu $4,$4,%lo(foo) <-- B
> ...
> jr $31
> 2: ...
> lui $4,%hi(foo) <-- C
> ...
> 1: addiu $4,$4,%lo(foo) <-- D
>
> In this case, the LO16 reloc for D might follow the HI16 reloc for C,
> and the LO16 reloc for B might follow the HI16 reloc for A. AIUI, we'd
> consider relaxing A/B but not C/D. In this case, turning A into a NOP
> is wrong, because $4 is still live at D. If you agree then...
>
> > Also with the recent update to LUI relaxation code I think we should
> > simply disallow the optimisation if a LUI is in a delay slot of an
> > unconditional branch -- we have no way to verify the corresponding LO16
> > reloc really belongs to this LUI instruction in that case. This will let
> > us simplify code (which has become a little bit hairy by now IMO) a little
> > bit I would guess. [FIXME]
>
> ...maybe it would be simpler to drop the optimisation if the LUI is any
> kind of delay slot. I think this would simply the code, and I don't think
> we'd then need to check for branch relocs. We'd just have *_norel-like
> functions (although not called that any more) to check for every kind
> of branch.
I have implemented these changes now, dropping the unsafe part of
optimisation for the scenario you have listed. I still have two concerns
about this optimisation, but the optional nature of linker relaxation
makes them reasonably unimportant IMO:
1. The resulting change of alignment may cause the linker produce bad code
or abort the process if microMIPS and standard MIPS code is mixed in
one object file and the latter turns out to become unaligned, e.g.
.set micromips
.set noreorder
.align 2
.globl foo
.ent foo
foo:
beqz32 $4, 0f
nop16
0:
jalx bar
nop
.end foo
.set nomicromips
.align 2
.globl bar
.ent bar
bar:
nop
.end bar
The piece above will fail to link, because BEQZ will be converted to
a BEQZC and the 16-bit NOP from its delay slot taken out. As a result
bar() will become misaligned and the JALX will not be allowed. If
there was no JALX, then linking might succeed if there were only
indirect calls to bar(), but the function would not be properly aligned
for standard MIPS execution.
2. Broken code is produced for cases like this:
.set noreorder
lui $4, 0x1234
lui $2, %hi(foo)
bnez $3, 0f
addiu $2, %lo(foo)
...
lui $4, %hi(foo)
0:
jal bar
addiu $4, %lo(foo)
where the resulting code:
.set noreorder
lui $4, 0x1234
bnez $3, 0f
addiu $2, $pc, foo - .
...
0:
jal bar
addiu $4, $pc, foo - .
obviously not being the same. Such usage of HI16/LO16 relocations is
non-standard, but not disallowed. OTOH searching the symbol tables for
the label (we could disable this relaxation if there's one at the
instruction a LO16 relocation is against) is expensive.
What do you think? [FIXME]
On Sun, 2 Jan 2011, Richard Sandiford wrote:
> This is the second and final part of the review.
>
> First of all, thanks for the great effort you've made to integrate the
> microMIPS macro code into macro(). This is much, much better than before,
> and should be far less of a maintenance burden.
I hope so too and thanks for your extensive effort too.
> FWIW, I plan to review the follow-up patch based purely on whether
> it deals with the review comments. Anything that we've collectively
> missed this far (and there's bound to be something) will just have to
> be fixed when someone trips over it.
OK.
> I think the only change of any significant size that needs to be made
> is to move the place where we convert to microMIPS relocs (see below).
> Everything else is pretty small.
Honestly the reloc conversion change was probably the smallest of all
(barring formatting fixes). :/
> > @@ -1821,6 +1830,8 @@ the target word. These are used on the
> > ENUM
> > BFD_RELOC_GPREL16
> > ENUMX
> > + BFD_RELOC_MICROMIPS_GPREL16
> > +ENUMX
> > BFD_RELOC_GPREL32
> > ENUMDOC
> > For systems that allocate a Global Pointer register, these are
>
> You've now moved most of the new relocs into MIPS-specific areas, thanks,
> but some, like the one above, are still in generic lists. Let's put:
>
> ENUM
> BFD_RELOC_MICROMIPS_7_PCREL_S1
> ENUMX
> BFD_RELOC_MICROMIPS_10_PCREL_S1
> ENUMX
> BFD_RELOC_MICROMIPS_16_PCREL_S1
> ENUMDOC
> MicroMIPS PC-relative relocations.
>
> before the main "MIPS ELF relocations." section, followed
> by a new section:
>
> ENUM
> BFD_RELOC_MICROMIPS_GPREL16
> ENUMX
> BFD_RELOC_MICROMIPS_HI16
> ENUMX
> BFD_RELOC_MICROMIPS_HI16_S
> ENUMX
> BFD_RELOC_MICROMIPS_LO16
> ENUMDOC
> MicroMIPS versions of generic BFD relocs.
>
> Also, let's combine this:
>
> > @@ -2182,6 +2193,11 @@ ENUMDOC
> > simple reloc otherwise.
> >
> > ENUM
> > + BFD_RELOC_MICROMIPS_JMP
> > +ENUMDOC
> > + The microMIPS jump instruction.
> > +
> > +ENUM
> > BFD_RELOC_MIPS16_JMP
> > ENUMDOC
> > The MIPS16 jump instruction.
>
> with the MIPS_JMP entry, since you're doing the same with the other
> microMIPS versions of MIPS relocs.
OK, but I had to remove the original documentation note. The immediate
argument is only shifted left by one bit in the microMIPS mode.
> > + /* Whether we are assembling for the mipsMIPS processor. 0 if we are
> > + not, 1 if we are, and -1 if the value has not been initialized.
> > + Changed by `.set micromips' and `.set nomicromips', and the -mmicromips
> > + and -mno-micromips command line options, and the default CPU. */
> > + int micromips;
>
> Blind cut-&-paste. "microMIPS ASE".
>
> Let's leave the -1 case and:
>
> > +/* Return true if the given CPU supports microMIPS. */
> > +#define CPU_HAS_MICROMIPS(cpu) 0
>
> out. I think the CPU_HAS_MIPS16 stuff is derived from the original LSI
> TinyRisc support and wouldn't be used for ASEs.
The microMIPS ASE provides for processors that do not support the
standard MIPS instruction set. These I think should default to the
microMIPS mode. I suspect someone will eventually implement such a
processor as since we've got this code implemented here already I'd like
to leave it as a placeholder. I think it's not much of a burden, is it?
> > @@ -495,9 +515,11 @@ static int mips_32bitmode = 0;
> > require nops to be inserted. This applies to instructions marked
> > INSN_LOAD_MEMORY_DELAY. These nops are only required at MIPS ISA
> > level I. */
> > -#define gpr_interlocks \
> > - (mips_opts.isa != ISA_MIPS1 \
> > - || mips_opts.arch == CPU_R3900)
> > +#define gpr_interlocks \
> > + (mips_opts.isa != ISA_MIPS1 \
> > + || mips_opts.arch == CPU_R3900 \
> > + || mips_opts.micromips \
> > + )
> >
> > /* Whether the processor uses hardware interlocks to avoid delays
> > required by coprocessor instructions, and thus does not require
> > @@ -512,6 +534,7 @@ static int mips_32bitmode = 0;
> > && mips_opts.isa != ISA_MIPS2 \
> > && mips_opts.isa != ISA_MIPS3) \
> > || mips_opts.arch == CPU_R4300 \
> > + || mips_opts.micromips \
> > )
> >
> > /* Whether the processor uses hardware interlocks to protect reads
> > @@ -519,7 +542,10 @@ static int mips_32bitmode = 0;
> > thus does not require nops to be inserted. This applies to
> > instructions marked INSN_COPROC_MEMORY_DELAY. These nops are only
> > requires at MIPS ISA level I. */
> > -#define cop_mem_interlocks (mips_opts.isa != ISA_MIPS1)
> > +#define cop_mem_interlocks \
> > + (mips_opts.isa != ISA_MIPS1 \
> > + || mips_opts.micromips \
> > + )
> >
> > /* Is this a mfhi or mflo instruction? */
> > #define MF_HILO_INSN(PINFO) \
>
> These changes are OK if they make life easier, but please add a comment
> saying why they do.
No interlocks are ever needed for microMIPS code, even if building with
-mips1 (the default). I have added a note to this effect to the relevant
comments.
> > +#define RELAX_MICROMIPS_ENCODE(type, is_16bit, uncond, link, toofar) \
> > + (0x40000000 \
> > + | ((type) & 0xff) \
> > + | ((is_16bit) ? 0x100 : 0) \
> > + | ((uncond) ? 0x200 : 0) \
> > + | ((link) ? 0x400 : 0) \
> > + | ((toofar) ? 0x800 : 0))
> > +#define RELAX_MICROMIPS_P(i) (((i) & 0xc0000000) == 0x40000000)
> > +#define RELAX_MICROMIPS_TYPE(i) ((i) & 0xff)
> > +#define RELAX_MICROMIPS_USER_16BIT(i) (((i) & 0x100) != 0)
> > +#define RELAX_MICROMIPS_UNCOND(i) (((i) & 0x200) != 0)
> > +#define RELAX_MICROMIPS_LINK(i) (((i) & 0x400) != 0)
> > +#define RELAX_MICROMIPS_TOOFAR(i) (((i) & 0x800) != 0)
> > +#define RELAX_MICROMIPS_MARK_TOOFAR(i) ((i) | 0x800)
> > +#define RELAX_MICROMIPS_CLEAR_TOOFAR(i) ((i) & ~0x800)
>
> Is there a need to create variant frags when the user has explicitly
> specified the instruction size? I wouldn't have expected any relaxation
> to be necessary in that case, and it looks like the relaxation code does
> indeed return 2 whenever USER_16BIT is true.
I suspect this has been copied over from MIPS16 code.
RELAX_MIPS16_USER_SMALL seems to be used in a similar fashion. Do you
happen to know for sure why it has been implemented this way for MIPS16
assembly? My suspicion is we want to keep the relocation until the final
relaxation so that if the final value turns out to fit afterwards (but not
until then) in the forced-truncated immediate field of the instruction
nothing is lost.
> If the bit really is needed, let's call the parameter "user_16bit"
> rather than "is_16bit", to match the use.
Fixed.
> Add a comment saying what RELAX_MICROMIPS_TYPE is. See the MIPS16
> comment as an example.
>
> > +#define RELAX_MICROMIPS_EXTENDED(i) (((i) & 0x10000) != 0)
> > +#define RELAX_MICROMIPS_MARK_EXTENDED(i) ((i) | 0x10000)
> > +#define RELAX_MICROMIPS_CLEAR_EXTENDED(i) ((i) & ~0x10000)
>
> Any particular reason why 0x10000 rather than 0x1000, which seems
> to be the first unused bit? I would prefer to pack the used bits
> together so that it's easier to tell what's left.
These weren't used anywhere. I have discarded these macros.
> > + /* True if the macro is in a 16-bit branch delay slot. */
> > + bfd_boolean delay_slot_16bit_p;
> > +
> > + /* True if the macro is in a 32-bit branch delay slot. */
> > + bfd_boolean delay_slot_32bit_p;
>
> I think it would be cleaner to have:
>
> /* If the macro is in a delay slot that requires a specific length
> of instruction, this is that length, otherwise it is zero. */
> unsigned int delay_slot_length;
Yes, marginally. As this is similar to updates I have made elsewhere
already, I have implemented your suggestion now.
> > + /* For relaxable macros, fsize[0] is the length of the first instruction
> > + of the first alternative in bytes and fsize[1] is the length of the
> > + first instruction of the second alternative.
> > + For non-relaxable macros, both elements give the length of the
> > + first instruction in bytes. */
> > + unsigned int fsize[2];
>
> Rename to "first_insn_sizes" ("sizes" rather than "size" because the
> plurality comes from having two alternatives). Also add:
>
> The fields are zero if we haven't yet seen the first instruction.
Fixed.
> > @@ -2374,22 +2736,21 @@ s_is_linkonce (symbolS *sym, segT from_s
> > return linkonce;
> > }
> >
> > -/* Mark instruction labels in mips16 mode. This permits the linker to
> > - handle them specially, such as generating jalx instructions when
> > - needed. We also make them odd for the duration of the assembly, in
> > - order to generate the right sort of code. We will make them even
> > +/* Mark instruction labels in MIPS16/microMIPS mode. This permits the
> > + linker to handle them specially, such as generating jalx instructions
> > + when needed. We also make them odd for the duration of the assembly,
> > + in order to generate the right sort of code. We will make them even
> > in the adjust_symtab routine, while leaving them marked. This is
> > convenient for the debugger and the disassembler. The linker knows
> > to make them odd again. */
> >
> > static void
> > -mips16_mark_labels (void)
> > +mips_compressed_mark_labels (void)
> > {
> > segment_info_type *si = seg_info (now_seg);
> > struct insn_label_list *l;
> >
> > - if (!mips_opts.mips16)
> > - return;
> > + gas_assert (HAVE_CODE_COMPRESSION);
> >
> > for (l = si->label_list; l != NULL; l = l->next)
> > {
> > @@ -2397,16 +2758,22 @@ mips16_mark_labels (void)
> >
> > #if defined(OBJ_ELF) || defined(OBJ_MAYBE_ELF)
> > if (IS_ELF)
> > - S_SET_OTHER (label, ELF_ST_SET_MIPS16 (S_GET_OTHER (label)));
> > + {
> > + if (mips_opts.mips16)
> > + S_SET_OTHER (label, ELF_ST_SET_MIPS16 (S_GET_OTHER (label)));
> > + else if (mips_opts.micromips)
> > + S_SET_OTHER (label, ELF_ST_SET_MICROMIPS (S_GET_OTHER (label)));
> > + }
> > #endif
> > if ((S_GET_VALUE (label) & 1) == 0
> > /* Don't adjust the address if the label is global or weak, or
> > in a link-once section, since we'll be emitting symbol reloc
> > references to it which will be patched up by the linker, and
> > - the final value of the symbol may or may not be MIPS16. */
> > + the final value of the symbol may or may not be MIPS16/microMIPS. */
> > && ! S_IS_WEAK (label)
> > && ! S_IS_EXTERNAL (label)
> > - && ! s_is_linkonce (label, now_seg))
> > + && ! s_is_linkonce (label, now_seg)
> > + && HAVE_CODE_COMPRESSION)
> > S_SET_VALUE (label, S_GET_VALUE (label) | 1);
> > }
> > }
>
> Looks like the addition of HAVE_CODE_COMPRESSION is redundant here,
> you've already asserted it in the previous hunk.
Yes, cut & paste error, fixed.
> > +static char *
> > +micromips_label_name (void)
> > +{
> > + char *p = micromips_target_name;
> > + char symbol_name_temporary[24];
> > + unsigned long l;
> > + int i;
> > +
> > + if (*p)
> > + return p;
> > +
> > + i = 0;
> > + l = micromips_target_label;
> > +#ifdef LOCAL_LABEL_PREFIX
> > + *p++ = LOCAL_LABEL_PREFIX;
> > +#endif
> [...]
> > +int
> > +mips_label_is_local (const char *name)
> > +{
> > + return strchr (name, MICROMIPS_LABEL_CHAR) != NULL;
> > +}
>
> Why is this change needed? The default local-label detection should be
> enough for ELF targets, which always have a LOCAL_LABEL_PREFIX.
I fail to see a justification, so I have removed this function.
Chao-ying, do you have anything to add?
> > @@ -2915,7 +3367,8 @@ append_insn (struct mips_cl_insn *ip, ex
> > out that the branch was out-of-range, we'll get an error. */
> > && !mips_opts.warn_about_macros
> > && (mips_opts.at || mips_pic == NO_PIC)
> > - && !mips_opts.mips16)
> > + && !mips_opts.mips16
> > + && !mips_opts.micromips)
> > {
> > relaxed_branch = TRUE;
> > add_relaxed_insn (ip, (relaxed_branch_length
>
> !HAVE_CODE_COMPRESSION
Obviously.
> > + if (mips_relax.sequence)
> > + abort ();
>
> gas_assert (!mips_relax.sequence);
I sort of wonder why it is needed here in the first place, but not in
any of the other blocks throughout this conditional, hmm...
> > + /* For microMIPS, disable reordering. */
> > + || mips_opts.micromips
>
> You should say whether this is for simplicity or by specification.
> Either way, a bit more detail would be welcome. E.g. something like:
>
> /* microMIPS assembly language does not allow the assembler
> to reorder instructions, even in .set reorder mode.
> Delay slots are always filled with nops when .set reorder
> is in effect. */
>
> (adjusted as appropriate if my guess is wrong).
I believe the concerns are the same as with MIPS16 code -- so far we have
failed to develop means to update DWARF-2 records accordingly and if a
32-bit branch/jump is swapped with a 16-bit delay-slot instruction (or
vice versa as it's permitted in microMIPS code, though not in MIPS16 one)
then substandard debugging experience results from software breakpoints
placed mid-through an instruction.
So as much as we'd love to reorder we really can't without fixing GAS
elsewhere.
Hmm, it looks like the piece of code to disable MIPS16 reordering has
never made its way upstream. It should, unless we have a volunteer to fix
GAS immediately, so while holding my breath and hoping that people won't
fight over this challenge I extracted this piece now and updated this
change accordingly. It makes no sense to keep the two pieces separate.
It also looks to me we shouldn't be checking for INSN_SYNC (that's a
waste of one of the precious flags we're just running out of), INSN_ERET
and INSN_DERET here explicitly. These instructions should have their
INSN_TRAP flag set instead -- and the flag should be renamed as I said
previously to avoid confusion and reflect its actual meaning, i.e. "this
instruction is forbidden in a branch delay slot".
> > + /* If both delay slots are out of size, then emit the warning now. */
> > + if ((subtype & (RELAX_DELAY_SLOT_SIZE_FIRST | RELAX_DELAY_SLOT_SIZE_SECOND))
> > + == (RELAX_DELAY_SLOT_SIZE_FIRST | RELAX_DELAY_SLOT_SIZE_SECOND))
>
> /* If both alternatives fail to fill a delay slot correctly,
> emit the warning now. */
> if ((subtype & RELAX_DELAY_SLOT_SIZE_FIRST) != 0
> && (subtype & RELAX_DELAY_SLOT_SIZE_SECOND) != 0)
I expect that to produce marginally worse code, but I won't insist. The
comment update is OK of course.
> > + hash = !mips_opts.micromips ? op_hash : micromips_op_hash;
>
> hash = mips_opts.micromips ? micromips_op_hash : op_hash;
Applied.
> > @@ -3640,13 +4407,32 @@ macro_build (expressionS *ep, const char
> > /* Search until we get a match for NAME. It is assumed here that
> > macros will never generate MDMX, MIPS-3D, or MT instructions. */
> > if (strcmp (fmt, mo->args) == 0
> > - && mo->pinfo != INSN_MACRO
> > - && is_opcode_valid (mo))
> > - break;
> > + && mo->pinfo != INSN_MACRO)
> > + {
> > + bfd_boolean ok;
> > + bfd_boolean size_ok;
> > + bfd_boolean delay_slot_ok;
> > +
> > + ok = is_opcode_valid (mo);
> > + size_ok = is_size_valid (mo);
> > + delay_slot_ok = is_delay_slot_valid (mo);
> > + if (ok && size_ok && (delay_slot_ok || secondpass))
> > + break;
> > + if (!delay_slot_ok && !twopass)
> > + {
> > + firstmo = mo;
> > + twopass = TRUE;
> > + }
> > + }
> >
> > ++mo;
> > - gas_assert (mo->name);
> > - gas_assert (strcmp (name, mo->name) == 0);
> > + if (!mo->name || strcmp (name, mo->name) != 0)
> > + {
> > + gas_assert (twopass);
> > + gas_assert (!secondpass);
> > + secondpass = TRUE;
> > + mo = firstmo;
> > + }
> > }
> >
> > create_insn (&insn, mo);
>
> Do we really need to do two passes here? I would have expected
> to see something like:
>
> if (strcmp (fmt, mo->args) == 0
> && mo->pinfo != INSN_MACRO
> && is_opcode_valid (mo)
> && is_size_valid (mo))
> {
> if (is_delay_slot_valid (mo))
> break;
> else if (!reserve_mo)
> reserve_mo = mo;
> }
>
> if (!mo->name || strcmp (name, mo->name) != 0)
> {
> /* All usable candidates violate the delay slot requirements
> of the previous instruction. Pick the first such candidate
> anyway; we will issue an appropriate warning later. */
> gcc_assert (reserve_mo);
> mo = reserve_mo;
> break;
> }
>
> which IMO is simpler and clearer.
Good point. I have simplified it yet further though.
> > + if (!mips_opts.micromips)
> > + INSERT_OPERAND (0, RD, insn, va_arg (args, int));
> > + else
> > + INSERT_OPERAND (1, RS, insn, va_arg (args, int));
>
> if (mips_opts.micromips)
> INSERT_OPERAND (1, RS, insn, va_arg (args, int));
> else
> INSERT_OPERAND (0, RD, insn, va_arg (args, int));
You don't like negative statements, do you? ;)
> > case 'i':
> > case 'j':
> > macro_read_relocs (&args, r);
> > - gas_assert (*r == BFD_RELOC_GPREL16
> > + gas_assert (mips_opts.micromips
> > + || *r == BFD_RELOC_GPREL16
> > || *r == BFD_RELOC_MIPS_HIGHER
> > || *r == BFD_RELOC_HI16_S
> > || *r == BFD_RELOC_LO16
> > || *r == BFD_RELOC_MIPS_GOT_OFST);
> > + gas_assert (!mips_opts.micromips
> > + || *r == BFD_RELOC_MICROMIPS_GPREL16
> > + || *r == BFD_RELOC_MICROMIPS_HIGHER
> > + || *r == BFD_RELOC_MICROMIPS_HI16_S
> > + || *r == BFD_RELOC_MICROMIPS_LO16
> > + || *r == BFD_RELOC_MICROMIPS_GOT_OFST);
>
> Let's move the macro_read_relocs stuff inside append_insn rather than
> leaving the conversion to the callers. You could then make append_insn
> keep a record of the original (non-microMIPS) reloc_type[0] too,
> which would simply some of the logic. E.g. these changes would
> no longer be needed:
>
> > - /* Tag symbols that have a R_MIPS16_26 relocation against them. */
> > - if (reloc_type[0] == BFD_RELOC_MIPS16_JMP
> > + /* Tag symbols that have a R_MIPS16_26 or R_MICROMIPS_26_S1
> > + relocation against them. */
> > + if ((reloc_type[0] == BFD_RELOC_MIPS16_JMP
> > + || reloc_type[0] == BFD_RELOC_MICROMIPS_JMP)
> > && ip->fixp[0]->fx_addsy)
> > *symbol_get_tc (ip->fixp[0]->fx_addsy) = 1;
This actually would -- note that's BFD_RELOC_MIPS16_JMP and not
BFD_RELOC_MIPS_JMP there.
> > @@ -3105,6 +3638,13 @@ append_insn (struct mips_cl_insn *ip, ex
> > || reloc_type[0] == BFD_RELOC_MIPS_SCN_DISP
> > || reloc_type[0] == BFD_RELOC_MIPS_REL16
> > || reloc_type[0] == BFD_RELOC_MIPS_RELGOT
> > + || reloc_type[0] == BFD_RELOC_MICROMIPS_JMP
> > + || reloc_type[0] == BFD_RELOC_MICROMIPS_GPREL16
> > + || reloc_type[0] == BFD_RELOC_MICROMIPS_LITERAL
> > + || reloc_type[0] == BFD_RELOC_MICROMIPS_SUB
> > + || reloc_type[0] == BFD_RELOC_MICROMIPS_HIGHEST
> > + || reloc_type[0] == BFD_RELOC_MICROMIPS_HIGHER
> > + || reloc_type[0] == BFD_RELOC_MICROMIPS_SCN_DISP
> > || reloc_type[0] == BFD_RELOC_MIPS16_GPREL
> > || hi16_reloc_p (reloc_type[0])
> > || lo16_reloc_p (reloc_type[0])))
>
> You also wouldn't need micromips_percent_op.
Done. As this is a self-contained change and may possibly need further
tweaks, I have made it a separate patch to apply on top of the rest of the
fixes (and the original change).
BTW, do you happen to know what the issue about BFD_RELOC_MIPS_SCN_DISP
is? We refer to it in a couple of places throughout GAS, but never
actually generate it. I realise BFD may have to handle the reloc for
compatibility with other tools, but GAS?
> Sorry, I know this isn't what I said first time round, but it was much
> harder to see the wood for the trees before you'd integrated the macro
> code properly.
Hmm, what can I say?
> > + /* For microMIPS, check if the current instruction is not in
> > + a delay slot that requires a 32-bit instruction. */
> > + if (mips_opts.micromips
> > + && !(history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
>
> /* Prefer to use a 16-bit microMIPS instruction unless the previous
> instruction specifically requires a 32-bit one. */
OK.
> > + if CALL is set. In the reorder mode the delay slot would be filled
> > + with a nop anyway, so code produced is simply:
> > + BR <args>, <sym>
>
> Add an explicit nop, since the code does.
Good point.
> > +/* Emit a coprocessor branch macro specified by TYPE, using CC as
> > + the condition code tested. EP specifies the branch target. */
>
> "branch-likely macro".
OK.
> > +/* Emit a two-argument branch macro specified by TYPE, using SREG as
> > + the register tested. EP specifies the branch target. */
> > +
> > +static void
> > +macro_build_branch_rs (int type, expressionS *ep, unsigned int sreg)
> > +{
> > + const char *brneg;
> > + const char *br;
> > + int likely = 0;
> > + int call = 0;
> > +
> > + switch (type)
> > + {
> > + case M_BGEZ:
> > + br = "bgez";
> > + break;
> > + case M_BGEZL:
> > + br = mips_opts.micromips ? "bgez" : "bgezl";
> > + brneg = "bltz";
> > + likely = 1;
> > + break;
> > + case M_BGEZALL:
> > + gas_assert (mips_opts.micromips);
> > + br = "bgezals";
> > + brneg = "bltz";
> > + likely = 1;
> > + call = 1;
> > + break;
> > + case M_BGTZ:
> > + br = "bgtz";
> > + break;
> > + case M_BGTZL:
> > + br = mips_opts.micromips ? "bgtz" : "bgtzl";
> > + brneg = "blez";
> > + likely = 1;
> > + break;
> > + case M_BLEZ:
> > + br = "blez";
> > + break;
> > + case M_BLEZL:
> > + br = mips_opts.micromips ? "blez" : "blezl";
> > + brneg = "bgtz";
> > + likely = 1;
> > + break;
> > + case M_BLTZ:
> > + br = "bltz";
> > + break;
> > + case M_BLTZL:
> > + br = mips_opts.micromips ? "bltz" : "bltzl";
> > + brneg = "bgez";
> > + likely = 1;
> > + break;
> > + case M_BLTZALL:
> > + gas_assert (mips_opts.micromips);
> > + br = "bltzals";
> > + brneg = "bgez";
> > + likely = 1;
> > + call = 1;
> > + break;
> > + default:
> > + abort ();
> > + }
> > + if (mips_opts.micromips && likely)
> > + macro_build_branch_likely (br, brneg, call, ep, "s,p", sreg, ZERO);
> > + else
> > + macro_build (ep, br, "s,p", sreg);
> > +}
>
> No need for "likely". Just initialise "brneg" to NULL and check for that.
> Same for macro_build_branch_rsrt.
I'm not sure that is clearer, but I won't insist. Adjusted.
> > + if (!mips_opts.micromips)
> > + label_expr.X_add_number = 8;
> > + else
> > + micromips_label_expr (&label_expr);
>
> if (mips_opts.micromips)
> micromips_label_expr (&label_expr);
> else
> label_expr.X_add_number = 8;
>
> (several occurences)
Yes, same as somewhere above. I've swapped all the negative conditions I
could spot.
> > - macro_build (NULL, "jalr", "d,s", dreg, sreg);
> > + s = (!mips_opts.micromips || (mips_opts.noreorder && !cprestore)
> > + ? "jalr" : "jalrs");
> > + if (mips_opts.micromips && dreg == RA)
> > + macro_build (NULL, s, "mj", sreg);
> > + else
> > + macro_build (NULL, s, JALR_FMT, dreg, sreg);
>
> Since we can use JALRS for mips_opts.noreorder && cprestore, I suppose
> the cprestore nop:
>
> if (mips_opts.noreorder)
> macro_build (NULL, "nop", "");
>
> ought to be conditional on !mips_opts.micromips.
No, the delay slot always has to be explicitly filled here. Otherwise
you'll end up with LW $gp there (the instruction has a 16-bit variation
too) -- that I fixed not so long ago.
For the avoidance of doubt: all the call (linked jump/branch)
instructions have a fixed-length delay slot that takes either 4 bytes (as
with BGEZAL, BLTZAL, JAL, JALR and JALX instructions) or 2 bytes (as with
BGEZALS, BLTZALS, JALS and JALRS). All the other jump/branch instructions
have an any-length delay slot except from compact jump/branch instructions
that have none (these are BEQZC, BNEZC and JRC). Overall the "S" suffix
stands for a short delay slot and the "C" one means a compact jump/branch,
i.e. no delay slot.
> > + /* A 12-bit offset field is too narrow to be used for a low-part
> > + relocation, so use the auxiliary register to load the full
> > + address provided if the A(b) format has been requested;
> > + load_address will produce the necessary relocations as code
> > + used with 16-bit offsets below would do. Otherwise the o(b)
> > + format has been selected, so load the low part only and the
> > + relocation requested will have already been provided in
> > + offset_reloc, so just use that. */
>
> /* A 12-bit offset field is too narrow to be used for a low-part
> relocation, so load the whole address into the auxillary
> register. In the case of "A(b)" addresses, we first load
> absolute address "A" into the register and then add base
> register "b". In the case of "o(b)" addresses, we simply
> need to add 16-bit offset "o" to base register "b", and
> offset_reloc already contains the relocations associated
> with "o". */
OK.
> > + hash = !mips_opts.micromips ? op_hash : micromips_op_hash;
> > + past = (!mips_opts.micromips ? &mips_opcodes[NUMOPCODES]
> > + : µmips_opcodes[bfd_micromips_num_opcodes]);
>
> if (mips_opts.micromips)
> {
> hash = micromips_op_hash;
> past = µmips_opcodes[bfd_micromips_num_opcodes];
> }
> else
> {
> hash = op_hash;
> past = &mips_opcodes[NUMOPCODES];
> }
Not sure this is any better, but OK.
> > @@ -8688,32 +10234,50 @@ mips_ip (char *str, struct mips_cl_insn
> > argsStart = s = str + end;
> > for (;;)
> > {
> > + bfd_boolean delay_slot_ok;
> > + bfd_boolean size_ok;
> > bfd_boolean ok;
> >
> > gas_assert (strcmp (insn->name, name) == 0);
> >
> > ok = is_opcode_valid (insn);
> > - if (! ok)
> > + size_ok = is_size_valid (insn);
> > + delay_slot_ok = is_delay_slot_valid (insn);
> > + if (!delay_slot_ok && !twopass)
> > {
> > - if (insn + 1 < &mips_opcodes[NUMOPCODES]
> > - && strcmp (insn->name, insn[1].name) == 0)
> > + firstinsn = insn;
> > + twopass = TRUE;
> > + }
> > + if (!ok || !size_ok || (!delay_slot_ok && !secondpass))
> > + {
> > + static char buf[256];
> > +
> > + if (insn + 1 < past && strcmp (insn->name, insn[1].name) == 0)
> > {
> > ++insn;
> > continue;
> > }
> > - else
> > + if (twopass && !secondpass)
> > {
> > - if (!insn_error)
> > - {
> > - static char buf[100];
> > - sprintf (buf,
> > - _("opcode not supported on this processor: %s (%s)"),
> > - mips_cpu_info_from_arch (mips_opts.arch)->name,
> > - mips_cpu_info_from_isa (mips_opts.isa)->name);
> > - insn_error = buf;
> > - }
> > - return;
> > + gas_assert (firstinsn);
> > + secondpass = TRUE;
> > + insn = firstinsn;
> > + continue;
> > }
> > +
> > + if (insn_error)
> > + return;
> > +
> > + if (!ok)
> > + sprintf (buf, _("opcode not supported on this processor: %s (%s)"),
> > + mips_cpu_info_from_arch (mips_opts.arch)->name,
> > + mips_cpu_info_from_isa (mips_opts.isa)->name);
> > + else
> > + sprintf (buf, _("Unrecognized %u-bit version of microMIPS opcode"),
> > + 8 * forced_insn_length);
> > + insn_error = buf;
> > +
> > + return;
> > }
> >
> > create_insn (ip, insn);
>
> Same two-pass comment as before.
Obviously this case is different as we have to pass all the matching
instructions through the loop with the huge switch statement for argument
matching too. So it's not enough to pick the first one that does not meet
the delay slot requirement and get away with that. And the switch
statement in its current form is not designed to make two successful
parses possible.
But having written that, I agree there is some room for improvement here
even without redesigning the switch statement as in the second pass we do
not have to pass instructions to the loop that were already checked in the
firs pass. I have updated this piece accordingly.
> > + unsigned long mask = (!mips_opts.micromips
> > + ? OP_MASK_CODE
> > + : MICROMIPSOP_MASK_CODE);
>
>
> unsigned long mask = (mips_opts.micromips
> ? MICROMIPSOP_MASK_CODE
> : OP_MASK_CODE);
>
> Several other cases.
As above.
> > + case 'J':
> > + if (!mips_opts.micromips)
> > + { /* 19-bit WAIT code. */
> > + my_getExpression (&imm_expr, s);
> > + check_absolute_expr (ip, &imm_expr);
> > + if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE19)
> > + {
> > + as_warn (_("Illegal 19-bit code (%lu)"),
> > + (unsigned long) imm_expr.X_add_number);
> > + imm_expr.X_add_number &= OP_MASK_CODE19;
> > + }
> > + INSERT_OPERAND (0, CODE19, *ip, imm_expr.X_add_number);
> > + imm_expr.X_op = O_absent;
> > + s = expr_end;
> > + continue;
> > }
> > - INSERT_OPERAND (CODE19, *ip, imm_expr.X_add_number);
> > - imm_expr.X_op = O_absent;
> > - s = expr_end;
> > - continue;
> > + goto do_reg; /* ALNV.PS source register. */
>
> So 'J' is used for different things depending on micromips mode?
> Couldn't we use a different letter instead?
Picked 'y' then.
While doing this I noticed we have a bug. In a sequence like this:
alnv.ps $f0, $f1, $f2, $3
jalr $3, $2
the ALNV.PS will get reordered into the delay slot. This is obviously
wrong.
I'll post a trivial fix for standard MIPS code separately. For microMIPS
code we'd have to take one of the precious pinfo flags (which we've run
out of, although one can be reclaimed with the SYNC change I mentioned
above) for the purpose of this lone instruction and we don't do branch
swapping anyway, so I've just disabled ALNV.PS reordering altogether.
> > + if (!mips_opts.micromips)
> > + INSERT_OPERAND (0, RD, *ip, regno);
> > + else
> > + INSERT_OPERAND (1, RS, *ip, regno);
>
> if (mips_opts.micromips)
> INSERT_OPERAND (1, RS, *ip, regno);
> else
> INSERT_OPERAND (0, RD, *ip, regno);
Ditto.
> > + if (!ok)
> > + {
> > + switch (*args++)
>
> I realise you've copied this from elsewhere, but why "++"?
> The "for" loop increments "args", doesn't it?
This is the same as for 'r', etc. (i.e. a register that's optional in the
source if the destination is the same as the target). Otherwise code
like:
andi16 $7, 65535
addiu16 $31, 7
fails to assemble. The thing is once we get to "65535", we still have a
"," unconsumed in args. I have rewritten it more properly though, adding
a check for that "," too.
> > + if (c == 'e')
> > + {
> > + regno = lastregno;
> > + s = s_reset;
> > + ++args;
> > + }
> > + else if (c == 't')
> > + {
> > + s = s_reset;
> > + ++args;
> > + continue;
> > + }
>
> I don't really understand these "args" adjustments either.
Likewise:
subu16 $2, $3
xor16 $2, $3
> > + i = my_getSmallExpression (&imm_expr, imm_reloc, s);
> > + if ((i == 0 && (imm_expr.X_op != O_constant
> > + || (imm_expr.X_add_number & 3) != 0
> > + || imm_expr.X_add_number > (63 << 2)
> > + || imm_expr.X_add_number < (-64 << 2)))
> > + || i > 0)
> > + {
> > + imm_expr.X_op = O_absent;
> > + break;
> > + }
> > + immed = imm_expr.X_add_number >> 2;
> > + INSERT_OPERAND (1, IMMA, *ip, immed);
> > + imm_expr.X_op = O_absent;
> > + s = expr_end;
> > + continue;
>
> Why set X_op to O_absent when rejecting this alternative? What breaks
> if you leave the constant in imm_expr? I couldn't see any similar
> error-handling code in this function.
I believe the reason is if the offset does not fit for the purpose of
this 16-bit encoding, then we'll fall back to a 32-bit one that uses
offset_expr instead. So we have to mark imm_expr absent not to confuse
code elsewhere (in md_assemble(), presumably). Yeah, I know in this case
both should be equal, but it looks sloppy to me to use a stale value from
a previous pass. And obviously you wouldn't see this case before as no
standard MIPS instruction switches from imm_expr to offset_expr between
encodings.
That written, I have given it some thinking and decided to use local
variables instead removing any references to imm_expr and thus any issue
about its usage. We don't pass the results up to append_insn() from here
in any case.
> Also:
>
> if (my_getSmallExpression (&imm_expr, imm_reloc, s) == 0
> && imm_expr.X_op == O_constant
> && (imm_expr.X_add_number & 3) == 0
> && imm_expr.X_add_number >= (-64 << 2)
> && imm_expr.X_add_number <= (63 << 2))
> {
> immed = imm_expr.X_add_number >> 2;
> INSERT_OPERAND (1, IMMA, *ip, immed);
> imm_expr.X_op = O_absent;
> s = expr_end;
> continue;
> }
> break;
>
> seems more in keeping with other my_getSmallExpression users.
I disagree, see 'i'/'j', 'o', etc. The path of acceptance in almost all
the case selectors of this switch statement is fall-through. Any failure
breaks midway through.
I have adjusted this sequence slightly though and factored out
conditions around the expression as the pattern repeats on and on
throughout this switch statement. This has led to quite nice code IMO.
> > + i = my_getSmallExpression (&imm_expr, imm_reloc, s);
> > +
> > + for (immb = 0; immb < 8; immb++)
> > + {
> > + if (micromips_imm_b_map[immb]
> > + == imm_expr.X_add_number)
> > + break;
> > + }
> > + if ((i == 0 && (imm_expr.X_op != O_constant || immb == 8))
> > + || i > 0)
> > + {
> > + imm_expr.X_op = O_absent;
> > + break;
> > + }
> > + INSERT_OPERAND (1, IMMB, *ip, immb);
> > + imm_expr.X_op = O_absent;
> > + s = expr_end;
> > + continue;
>
> Here too I'd prefer something like:
>
> if (my_getSmallExpression (&imm_expr, imm_reloc, s) == 0
> && imm_expr.X_op == O_constant)
> {
> for (immb = 0; immb < 8; immb++)
> if (micromips_imm_b_map[immb]
> == imm_expr.X_add_number)
> break;
> if (immb < 8)
> {
> INSERT_OPERAND (1, IMMB, *ip, immb);
> imm_expr.X_op = O_absent;
> s = expr_end;
> continue;
> }
> }
> break;
>
> which has the added benefit of only using X_add_number once we've
> established that it's meaningful. Similar changes in the rest
> of the function.
Likewise. I agree about the imm_expr's usage and have taken it into
account.
> > + /* If users want relax branch and don't specify to use
> > + 16-bit instructions, we will not match this pattern.
> > + This will lead to matching 32-bit instructions, that
> > + will be relaxed later. */
> > + if (mips_relax_branch && forced_insn_length != 2)
> > + break;
>
> This seems a bit lame. It should be easy to relax the 16-bit form
> in the same way as the 32-bit form. We could use a bit in the
> relaxation opcode to say whether the extra relaxation should be
> enabled or not, i.e. a bit to record the relevant parts of this
> condition:
>
> + && (pinfo & INSN_UNCOND_BRANCH_DELAY
> + || pinfo & INSN_COND_BRANCH_DELAY)
> + && mips_relax_branch
> + /* Don't try branch relaxation within .set nomacro, or within
> + .set noat if we use $at for PIC computations. If it turns
> + out that the branch was out-of-range, we'll get an error. */
> + && !mips_opts.warn_about_macros
> + && (mips_opts.at || mips_pic == NO_PIC)
> + && mips_opts.micromips
> + /* Don't try branch relaxation, when users specify 16-bit/32-bit
> + instructions. */
> + && !forced_insn_length)
>
> No need to do that as part of this patch, but let's at least put in
> a FIXME.
Indeed; we have a preexisting bug here as well -- mips_opts.at may well
be != ATREG. (A similar bug is present in fix_loongson2f_jump() BTW).
Actually I've thought it's lame enough to implement it. In the course of
which I discovered (and fixed) other three bugs, so I think it was worth
the effort. Sent as a sepate patch for the same reasons as the reloc
change above.
> > + case 'N': /* Register list for lwm and swm. */
> > + {
> > + unsigned int reg_list = 0;
> > + int immed = 0;
> > + unsigned int reg1 = 33;
>
> Why 33 rather than 32? Seems INVALID_REG could be used here for a bit
> of extra readability.
No idea; this piece is now gone anyway.
> > + /* s0, ra
> > + s0, s1, ra
> > + s0, s1, s2, ra
> > + s0, s1, s2, s3, ra
> > + s0-s1, ra
> > + s0-s2, ra
> > + s0-s3, ra */
>
> You also allow:
>
> s1, ra, s2, s0
>
> (rightly IMO), so I don't think we gain much by listing the split-out ranges.
> Just:
>
> /* s0, ra
> s0-s1, ra
> s0-s2, ra
> s0-s3, ra */
>
> would be OK.
I have rewritten it adding an explanatory comment.
> > + s_reset = s;
> > + SKIP_SPACE_TABS (s);
> > + if (*s == ',')
> > + {
> > + reg1 = 33;
> > + ++s;
> > + }
> > + else if (*s == '-')
> > + {
> > + reg1 = regno;
> > + ++s;
> > + }
> > + SKIP_SPACE_TABS (s);
> > + ok = reg_lookup (&s, RTYPE_NUM | RTYPE_GP, ®no);
> > + if (!ok)
> > + {
> > + s = s_reset;
> > + break;
> > + }
>
> Shouldn't we break out if *s isn't ',' or '-' and treat it as a syntax
> error ("reg_list = 0; break;")?
We should break out, but that's not a syntax error as far as this handler
is concerned. It's up to code elsewhere to decide what the token to
follow, if any, has to be based on args. This is now handled properly.
> > + if (regno <= reg1)
> > + {
> > + reg_list = 0;
> > + break;
> > + }
>
> Add a comment saying that this is an error condition. But is there
> really anything wrong with $4-$4 (regno == reg1)? The range is closed
> after all.
Agreed, I have now allowed it under the "be liberal what you accept"
principle.
> > + }
> > + if (i == 0 && imm_expr.X_op == O_constant
> > + && (imm_expr.X_add_number & 3) == 0
> > + && imm_expr.X_add_number >= (-4194304 << 2)
> > + && imm_expr.X_add_number <= (4194303 << 2))
>
> I'm ashamed to say this decimal number wasn't in my mental power-of-2 list.
> Maybe a hex constant or (1 << n) would be better? Feel free to leave it
> if you disagree though.
I don't, actually. Offhand, the decimal value is meaningless to me too.
> > + case 'n': /* Register list for 32-bit lwm and swm. */
> > + gas_assert (mips_opts.micromips);
> > + {
> > + unsigned int reg_list = 0;
> > + int immed = 0;
> > + unsigned int reg1 = 33;
> > +
>
> This register-range code needs to be split out into a separate function.
> It's the same as for 'N' above (except for the s8 handling, which would
> be OK-but-redundant for 'n' too), has the same apparent bug regarding
> syntax checking, and has the same questionable behaviour about
> single-register ranges.
Agreed. I have now reimplemented is almost from scratch. While doing it
I have noticed the arguments are actually wiped of whitespace at this
point, so I have removed references to SKIP_SPACE_TABS(). It looks to me
the macro and its two references in mips16_ip() can be removed altogether.
> > + /* s0, ra
> > + s0, s1, ra
> > + s0, s1, s2, ra
> > + s0, s1, s2, s3, ra
> > + s0, s1, s2, s3, s4, ra
> > + s0, s1, s2, s3, s4, s5, ra
> > + s0, s1, s2, s3, s4, s5, s6, ra
> > + s0, s1, s2, s3, s4, s5, s6, s7, ra
> > + s0, s1, s2, s3, s4, s5, s6, s7, s8, ra
> > + ra,
> > + s0-s1, ra
> > + s0-s2, ra
> > + s0-s3, ra
> > + s0-s4, ra
> > + s0-s5, ra
> > + s0-s6, ra
> > + s0-s7, ra
> > + s0-s8, ra */
>
> I'm hampered by the spec not being public yet, but it looks from the
> code as though RA's actually optional when S0 is present. The comment
> implies otherwise. Also:
Both are optional, except at least one register has to be present and the
range of static registers has to start at s0 and be contiguous. (Though
as a side note I'm not sure why a single register is officially supported
by the ASE for this instruction at all -- being equivalent to LD/LW/SD/SW
it could well be a reserved encoding.)
> > + if (reg_list == 0x00010000)
> > + immed = 1;
> > + else if (reg_list == 0x00030000)
> > + immed = 2;
> > + else if (reg_list == 0x00070000)
> > + immed = 3;
> > + else if (reg_list == 0x000f0000)
> > + immed = 4;
> > + else if (reg_list == 0x001f0000)
> > + immed = 5;
> > + else if (reg_list == 0x003f0000)
> > + immed = 6;
> > + else if (reg_list == 0x007f0000)
> > + immed = 7;
> > + else if (reg_list == 0x00ff0000)
> > + immed = 8;
> > + else if (reg_list == 0x40ff0000)
> > + immed = 9;
> > + else if (reg_list == 0x80000000)
> > + immed = 16;
> > + else if (reg_list == 0x80010000)
> > + immed = 17;
> > + else if (reg_list == 0x80030000)
> > + immed = 18;
> > + else if (reg_list == 0x80070000)
> > + immed = 19;
> > + else if (reg_list == 0x800f0000)
> > + immed = 20;
> > + else if (reg_list == 0x801f0000)
> > + immed = 21;
> > + else if (reg_list == 0x803f0000)
> > + immed = 22;
> > + else if (reg_list == 0x807f0000)
> > + immed = 23;
> > + else if (reg_list == 0x80ff0000)
> > + immed = 24;
> > + else if (reg_list == 0xc0ff0000)
> > + immed = 25;
> > + else
> > + break;
>
> this could at least be simplified by testing the Sn and RA registers
> separately, then rejecting immed == 0. But maybe the split-out function
> could return the Sn range in a more easily digestible form.
No need to. This can be easily dealt with with ffs(), benefitting hosts
that have good support for this operation, such as MIPS architecture
processors and their CLZ instruction :) (x86 has BSF and we care even less
about any others, don't we?).
> > + /* For microMIPS we need to save the value to buf + 2. */
> > + if (target_big_endian || fixP->fx_r_type == BFD_RELOC_MICROMIPS_LO16)
> > buf += 2;
>
> /* 32-bit microMIPS instructions are divided into two 16-bit pieces.
> Relocations always refer to the second piece, regardless of
> endianness. */
>
> or something like that. I'm sure there's a better term than "piece" here,
> what does the spec call it?
Halfword.
> > + fragp->fr_subtype
> > + = toofar ? RELAX_MICROMIPS_MARK_TOOFAR (fragp->fr_subtype)
> > + : RELAX_MICROMIPS_CLEAR_TOOFAR (fragp->fr_subtype);
>
> Non-standard alignment for ":"
>
> fragp->fr_subtype = (toofar
> ? RELAX_MICROMIPS_MARK_TOOFAR (fragp->fr_subtype)
> : RELAX_MICROMIPS_CLEAR_TOOFAR (fragp->fr_subtype);
Fixed.
> > + /* 00000000 <test>:
> > + 0: 405e 0006 bgez $30,10 <test+0x10>
> > + 4: 0c00 nop
> > + 6: fc3c 0002 lw $1,2($28)
> > + 6: R_MIPS_GOT16 .text
> > + a: 3021 0011 addiu $1,$1,17
> > + a: R_MIPS_LO16 .text
> > + e: 4721 jalr $1
> > + ...
> > +
> > + 00020010 <test2>:
> > + 20010: 0c00 nop
> > + 20012: 0c00 nop
> > + */
> > +
> > + if (!fragp && update > 0)
> > + length += 6;
> > +
> > + if (mips_pic != NO_PIC)
> > + {
> > + /* Additional space for PIC loading of target address. */
> > + length += 6;
> > + }
> > +
> > + /* If branch is conditional. */
> > + if (fragp ? !RELAX_MICROMIPS_UNCOND (fragp->fr_subtype) : (update >= 0))
> > + length += 6;
> > + }
>
> This really isn't written very clearly. The comment has a single
> long-branch form, while the code has three if statements. Say what
> you're counting in each case.
The first conditional is bogus and also dead code. It looks like it was
copied from relaxed_branch_length() where it is used to handle
branch-likely relaxation, further adjusted towards removal and then left.
I have removed it altogether now.
I've cooked up some comments for the remaining cases. I decided to
switch to the source notation and quoted instruction byte counts
explicitly.
> > + /* For microMIPS PC relative relocations, we cannot convert it to
> > + against a section. If we do, it will mess up the fixp->fx_offset. */
> > if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
> > - || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
> > + || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY
> > + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
> > + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1
> > + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1)
>
> "to be against a section". That's not a helpful comment though.
> _How_ will it mess up fixp->fx_offset? Give the reader a clue why
> the problem applies to BFD_RELOC_MICROMIPS_16_PCREL_S1 but not
> to something like BFD_RELOC_16_PCREL_S2.
I have failed to spot any problems with this hunk reverted and I'm not
sure what I should be looking for. Therefore I feel a bit uneasy about
removing it and only rephrased the comment without actually changing its
meaning. Chao-ying, do you have anything to add?
> > + if (RELAX_MICROMIPS_UNCOND (fragp->fr_subtype))
> > + goto uncond_micromips;
>
> Ugh. Either split out the code for unconditional branches into a subfunction,
> or put intervening code into a:
>
> if (!RELAX_MICROMIPS_UNCOND (fragp->fr_subtype))
>
> block. (Yes, I know the current relaxation code has the same kind of goto,
> but I would have raised just the same objection there. If cut-&-paste really
> is necessary, the new code should still be defendable in its own right.)
Fixed.
> > + buf = (bfd_byte *)fragp->fr_literal + fragp->fr_fix;
>
> Missing space before "fragp->fr_literal". A few other occurences.
Fixed.
> > + if (RELAX_MICROMIPS_LINK (fragp->fr_subtype))
> > + {
> > + /* Clear the and-link bit. */
> > + gas_assert ((insn & 0xffa00000) == 0x40200000);
> > +
> > + /* bltzal 0x04100000 bgezal 0x04110000 */
> > + insn &= ~0x00200000;
> > + }
>
> Excess cut-&-paste. The opcodes in the comment are from the normal MIPS
> encoding, not the microMIPS one. (Wondered at first why we were clearing
> a bit that, according to the comment, wasn't supposed to be set in the
> first place.)
Worse yet, we don't handle BGEZALS and BLTZALS correctly. Fixed that as
well (and adjusted test cases to include these instructions).
> > + /* How many bytes in instructions we've already emitted? */
> > + i = buf - (bfd_byte *)fragp->fr_literal - fragp->fr_fix;
> > + /* How many bytes in instructions from here to the end? */
> > + i = fragp->fr_var - i;
>
> I don't get this. "buf" still equals "fragp->fr_literal + fragp->fr_fix",
> doesn't it? We haven't emitted anything yet. Seems to me that this is
> (and should be) the same as "i = fragp->fr_var".
We fail to use compact branches here and rely on linker relaxation to do
so. This is inferior (especially as linker relaxation is optional; it
doesn't handle all the cases either), but better than nothing. It relies
on the presence of relocations though, so I have rewritten this sequence
to emit labels and use them as branch targets instead, getting rid of this
piece you're questioning as a side effect altogether.
For compact branches to be used here I think we need to add another flag
to RELAX_MICROMIPS_ENCODE() so that
relaxed_micromips_32bit_branch_length() can calculate the correct length
(contrary to generic documentation the original opcode is not available in
md_relax_frag() on the MIPS target and when we get to md_convert_frag()
it's already too late for shrinking the frag.
The lack of use of compact branches here does not make code produced
incorrect though, so that makes it an option for future improvement and I
will not work on it now. [FIXME]
> > + uncond_micromips:
> > + if (mips_pic == NO_PIC)
> > + {
> > + /* j or jal. */
>
> "j(al) <sym> R_MICROMIPS_26_S1"
>
> to match the style of the other comments (and to give a bit more info).
Adjusted as reasonable (though I fail to see a consistent style
throughout this function).
> > + /* lw/ld $at, <sym>($gp) R_MIPS_GOT16 */
> > + insn = 0xfc3c0000;
> > + exp.X_op = O_symbol;
> > + exp.X_add_symbol = fragp->fr_symbol;
> > + exp.X_add_number = fragp->fr_offset;
>
> Add the "ld" case or fix the comment. Also s/R_MIPS_GOT16/R_MICROMIPS_LO16/.
>
> > + /* d/addiu $at, $at, <sym> R_MIPS_LO16 */
> > + insn = 0x30210000;
>
> Likewise "daddiu".
I have added the alternative encodings. Overall 64-bit support is quite
rudimentary at most.
> > + gas_assert (buf == (bfd_byte *)fragp->fr_literal
> > + + fragp->fr_fix + fragp->fr_var);
>
> The "+" isn't indented far enough.
There was a pair of brackets missing here actually.
> > Index: binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/mips1-fp.d
> > ===================================================================
> > --- binutils-fsf-trunk-quilt.orig/gas/testsuite/gas/mips/mips1-fp.d 2010-12-07 00:05:05.000000000 +0000
> > +++ binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/mips1-fp.d 2010-12-07 00:14:47.000000000 +0000
> > @@ -9,4 +9,4 @@
> > [0-9a-f]+ <.*>:
> > .*: 46041000 add.s \$f0,\$f2,\$f4
> > .*: 44420000 cfc1 \$2,\$0
> > -#pass
> > + \.\.\.
> > Index: binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/mips1-fp.s
> > ===================================================================
> > --- binutils-fsf-trunk-quilt.orig/gas/testsuite/gas/mips/mips1-fp.s 2010-12-07 00:05:05.000000000 +0000
> > +++ binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/mips1-fp.s 2010-12-07 00:14:47.000000000 +0000
> > @@ -5,3 +5,7 @@
> > foo:
> > add.s $f0,$f2,$f4
> > cfc1 $2,$0
> > +
> > +# Force at least 8 (non-delay-slot) zero bytes, to make 'objdump' print ...
> > + .align 2
> > + .space 8
>
> Leave out this kind of change. I realise it's not the style you prefer,
> but what's there now is fine. Same for:
>
> * gas/testsuite/gas/mips/mips32r2-fp32.d
> * gas/testsuite/gas/mips/mips64.d
Well, that's not merely a matter of style as #pass simply ignores any
following rubbish GAS may have produced. This forces a corresponding
update to gas/testsuite/gas/mips/micromips@mips1-fp.d as the results
differ between Linux and bare-iron targets. I'd prefer to avoid adding
new instances of #pass although I've just noticed the original change
included some other too, so I've applied your suggestion reluctantly.
These test cases should really be all audited and unjustified uses of
#pass removed -- I realise some people have difficulties following all
the details of and good ways to deal with subtleties in this area and
follow the path of least resistance, but we shouldn't be encouraging this
kind of behaviour. Especially as you seem to be quite picky elsewhere. ;)
> > msubu $11, $12
> > mul $13, $14, $15
> > pref 4, ($16)
> > + .set at
> > pref 4, 32767($17)
> > pref 4, -32768($18)
> > + .set noat
> > ssnop
> >
> >
> > # privileged instructions
> >
> > cache 5, ($1)
> > + .set at
> > cache 5, 32767($2)
> > cache 5, -32768($3)
> > - .set at
> > cache 5, 32768($4)
> > cache 5, -32769($5)
> > cache 5, 32768
>
> We should really have separate noat tests for the prefs and caches
> that are no longer in a noat block (a bit like you did for the
> wait and sdbbp tests whose immediates have changed).
>
> > -#define STO_MIPS_PLT 0x8
> > +#define STO_MIPS_PLT (1 << 3)
>
> Don't change the definitions of the existing constants; use hex constants
> for the new stuff instead.
Well, STO_OPTIONAL already uses a shifted bit and I find this notation
clearer. Since code is already inconsistent I have updated it not to
change the existing definitions, but kept newly-added ones as shifted
bitfields. I'm happy to keep code consistent, but if a piece is not, I
will choose the style that suits me better, sorry.
> > /* This value is used to mark PIC functions in an object that mixes
> > - PIC and non-PIC. */
> > -#define STO_MIPS_PIC 0x20
> > -#define ELF_ST_IS_MIPS_PIC(OTHER) \
> > - (((OTHER) & ~ELF_ST_VISIBILITY (-1)) == STO_MIPS_PIC)
> > -#define ELF_ST_SET_MIPS_PIC(OTHER) \
> > - (STO_MIPS_PIC | ELF_ST_VISIBILITY (OTHER))
> > + PIC and non-PIC. Note this bit overlaps with STO_MIPS16. */
> > +#define STO_MIPS_PIC (1 << 5)
> > +#define ELF_ST_IS_MIPS_PIC(other) (((other) & STO_MIPS_FLAGS) == STO_MIPS_PIC)
> > +#define ELF_ST_SET_MIPS_PIC(other) (((other) & ~STO_MIPS_FLAGS) | STO_MIPS_PIC)
>
> /* This value is used to mark PIC functions in an object that mixes
> PIC and non-PIC. Note that this bit overlaps with STO_MIPS16,
> although MIPS16 symbols are never considered to be MIPS_PIC. */
Applied.
> > +/* Whether code compression (either of the MIPS16 or the microMIPS ASEs)
> > + has been indicated for a .text symbol. */
> > +#define ELF_ST_IS_COMPRESSED(other) \
> > + (ELF_ST_IS_MIPS16(other) || ELF_ST_IS_MICROMIPS(other))
>
> The last line is missing a space before each "(other)".
Fixed.
> > +/* microMIPS placeholders. */
>
> Should be a bit more descriptive. E.g.:
>
> /* Every MICROMIPSOP_X definition requires a corresponding OP_X
> definition, and vice versa. This simplifies various parts
> of the operand handling in GAS. The fields below only exist in
> the microMIPS encoding, so define each one to have an empty range. */
>
> if indeed that's accurate.
Yes, thanks. Updated INSERT_OPERAND() and EXTRACT_OPERAND() macros rely
on these definitions for cases where the ISA selector is hardcoded as code
has to be syntactically correct even if optimised away.
> > +/* These are the bitmasks and shift counts used for the different
> > + fields in the instruction formats. Other than OP, no masks are
> > + provided for the fixed portions of an instruction, since they are
> > + not needed. */
>
> Seems like too much cut-&-paste: there isn't an OP field here.
> "Other than TARGET", perhaps, unless there are other opcode masks here.
This looks like copied verbatim from the MIPS16 part. The two parts are
functionally equivalent and my understanding of the comment is no masks
are provided for the non-operand parts of instruction. I've left the
comment as is; I'm not sure what TARGET might mean in this context, please
elaborate.
> > +/* MIPS placeholders. */
>
> /* Placeholders for fields that only exist in the traditional 32-bit
> instruction encoding; see the comment above for details. */
Thanks.
> > + "mg" 3-bit MIPS registers 2-7, 16, 17 (MICROMIPSOP_*_MG) at bit 0
> > + "mg" 3-bit MIPS registers 2-7, 16, 17 (MICROMIPSOP_*_MG) at bit 0
>
> Doubled line.
Fixed.
> > - Elf_Internal_Ehdr *header;
> > + Elf_Internal_Ehdr *header = elf_elfheader (info->section->owner);
> >
> > - header = elf_elfheader (info->section->owner);
>
> What's there now is fine.
Adjusted.
> > + else
> > + iprintf (is, "UNKNOWN");
>
> Excess indentation.
Fixed.
> > + In microMIPS, we need to match instructions (mfc0, mtc0)
> > + by hand. */
>
> Something like:
>
> The microMIPS encoding does not have a coprocessor
> identifier field as such, so we must work out the
> coprocessor number by looking at the opcode. */
>
> might be more descriptive.
OK, thanks.
> > +/* Return 1 if a symbol associated with the location being disassembled
> > + indicates a compressed mode, either MIPS16 or microMIPS one. Otherwise,
> > + return 0. */
>
> Reads more naturally to me without "one".
Both MIPS16 and microMIPS are adjectives; they need a noun or a pronoun.
I realise this requirement is not met everywhere, but that doesn't mean we
should add new such places IMO.
> > + for (i = 0; i < info->num_symbols; i++)
> > + {
> > + pos = info->symtab_pos + i;
> > +
> > + if (bfd_asymbol_flavour (info->symtab[pos]) != bfd_target_elf_flavour)
> > + continue;
> > +
> > + symbol = (elf_symbol_type *) info->symtab[pos];
> > + if ((!micromips_ase
> > + && ELF_ST_IS_MIPS16 (symbol->internal_elf_sym.st_other))
> > + || (micromips_ase
> > + && ELF_ST_IS_MICROMIPS (symbol->internal_elf_sym.st_other)))
> > + return 1;
> > + }
>
> Why is a search necessary here, when the previous code was happy to
> look only at the first symbol? I'm not saying the code is wrong,
> but a bit of commentary would be good.
My feeling is previous code was not "happy", but simply untested (or to
be more accurate, not tested satisfactorily).
Symbols sharing the same address are sorted alphabetically here which
becomes a problem when they include both objects and functions (or symbols
derived from standard MIPS functions defined elsewhere). Disassembly
shouldn't yield different results based merely on the names of symbols
chosen and given the semantics of the compressed annotation (it is only
added to a function symbol if a genuine instruction has been emitted
following immediately in the source code) I think it should take
precedence, so we check if any symbol has one.
Perhaps we should only check function symbols in case st_other is
overloaded for object symbols, but I think that would be overengineering.
Whoever adds any overlapping flags should be required to audit existing
code; that shouldn't be too difficult to do.
> What problem is the ld-lib.exp change fixing?
Currently you can't build the same source file multiple times with
different flags. See ld/testsuite/ld-mips-elf/mips16-and-micromips.d for
a use case (and try it with the ld-lib.exp piece reverted). I think the
framework shouldn't be limiting the developer like this and making a copy
of the source to work around the limitation sounds to me like the wrong
direction to go.
I made several adjustments and bug fixes as I saw fit on my own too and
for documentation purposes included a commented out microMIPS64 48-bit LI
instruction that takes a 32-bit signed immediate argument.
While support for 64-bit microMIPS is only rudimentary and I don't plan
to work on any improvement at the moment long-term we need to think about
how to handle this instruction; the most straightforward approach would be
to reliably extend match/mask to 64 bits. Our 64-bit integer type support
on 32-bit hosts seem to be lacking though and there are several places
throughout GAS where such values are truncated. It would increase the
amount of space taken by opcode tables noticeably on 32-bit hosts too (but
we already waste a lot of space by using a "long" type on 64-bit hosts
where unnecessary).
What fits best here are ISO C9x <stdint.h> types -- do you happen to know
if binutils maintainers ever plan to deploy them? We've been using
autoconf since the beginning of time and it has straightforward ways to
define replacement types of a required width and target code frequently
operates on quantities that have a predefined width so making use of
fixed-width types seems natural.
I have made several obvious changes to the original diff to address
modifications made to repository that are not included here as they were
required for the patch to apply at all after a tree update in the first
place. All of them were mechanical; most notably <opcode/mips.h> INSN2_*
have been renumbered according to additional flag consumption. As
mentioned earlier, we're running out of these flags now.
Finally, for a reference, I'm including updated ChangeLogs. They refer
to the whole set of changes combined as the updates are not meant to be
committed separately. None of the separate bug fixes mentioned throughout
are covered though; I'll be sending them with their corresponding entries
and descriptions on their own shortly.
Maciej
binutils-20110221-umips-fix.diff
binutils-20110221-umips-relax16.diff
binutils-20110221-umips-fix-reloc.diff
[Patches attached compressed due to their size.]
bfd/
2011-02-21 Chao-ying Fu <fu@mips.com>
Ilie Garbacea <ilie@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
Joseph Myers <joseph@codesourcery.com>
Catherine Moore <clm@codesourcery.com>
* archures.c (bfd_mach_mips_micromips): New macro.
* cpu-mips.c (I_micromips): New enum value.
(arch_info_struct): Add bfd_mach_mips_micromips.
* elfxx-mips.h (_bfd_mips_elf_is_target_special_symbol): New
prototype.
(_bfd_mips_elf_relax_section): Likewise.
(_bfd_mips16_elf_reloc_unshuffle): Rename to...
(_bfd_mips_elf_reloc_unshuffle): ... this. Handle microMIPS
ASE.
(_bfd_mips16_elf_reloc_shuffle): Rename to...
(_bfd_mips_elf_reloc_shuffle): ... this. Handle microMIPS ASE.
(gprel16_reloc_p): Handle microMIPS ASE.
(literal_reloc_p): New function.
* elf32-mips.c (elf_micromips_howto_table_rel): New variable.
(_bfd_mips_elf32_gprel16_reloc): Handle microMIPS ASE.
(mips16_gprel_reloc): Update for _bfd_mips_elf_reloc_unshuffle
and _bfd_mips_elf_reloc_shuffle changes.
(mips_elf_gprel32_reloc): Update comment.
(micromips_reloc_map): New variable.
(bfd_elf32_bfd_reloc_type_lookup): Handle microMIPS ASE.
(mips_elf32_rtype_to_howto): Likewise.
(mips_info_to_howto_rel): Likewise.
(bfd_elf32_bfd_is_target_special_symbol): Define.
(bfd_elf32_bfd_relax_section): Likewise.
* elf64-mips.c (micromips_elf64_howto_table_rel): New variable.
(micromips_elf64_howto_table_rela): Likewise.
(mips16_gprel_reloc): Update for _bfd_mips_elf_reloc_unshuffle
and _bfd_mips_elf_reloc_shuffle changes.
(micromips_reloc_map): Likewise.
(bfd_elf64_bfd_reloc_type_lookup): Handle microMIPS ASE.
(bfd_elf64_bfd_reloc_name_lookup): Likewise.
(mips_elf64_rtype_to_howto): Likewise.
(bfd_elf64_bfd_is_target_special_symbol): Define.
* elfn32-mips.c (elf_micromips_howto_table_rel): New variable.
(elf_micromips_howto_table_rela): Likewise.
(mips16_gprel_reloc): Update for _bfd_mips_elf_reloc_unshuffle
and _bfd_mips_elf_reloc_shuffle changes.
(micromips_reloc_map): Likewise.
(bfd_elf32_bfd_reloc_type_lookup): Handle microMIPS ASE.
(bfd_elf32_bfd_reloc_name_lookup): Likewise.
(mips_elf_n32_rtype_to_howto): Likewise.
(bfd_elf32_bfd_is_target_special_symbol): Define.
* elfxx-mips.c (LA25_LUI_MICROMIPS_1): New macro.
(LA25_LUI_MICROMIPS_2): Likewise.
(LA25_J_MICROMIPS_1, LA25_J_MICROMIPS_2): Likewise.
(LA25_ADDIU_MICROMIPS_1, LA25_ADDIU_MICROMIPS_2): Likewise.
(TLS_RELOC_P): Handle microMIPS ASE.
(mips_elf_create_stub_symbol): Adjust value of stub symbol if
target is a microMIPS function.
(micromips_reloc_p): New function.
(micromips_reloc_shuffle_p): Likewise.
(got16_reloc_p, call16_reloc_p): Handle microMIPS ASE.
(got_disp_reloc_p, got_page_reloc_p): New functions.
(got_ofst_reloc_p): Likewise.
(got_hi16_reloc_p, got_lo16_reloc_p): Likewise.
(call_hi16_reloc_p, call_lo16_reloc_p): Likewise.
(hi16_reloc_p, lo16_reloc_p, jal_reloc_p): Handle microMIPS ASE.
(micromips_branch_reloc_p): New function.
(tls_gd_reloc_p, tls_ldm_reloc_p): Likewise.
(tls_gottprel_reloc_p): Likewise.
(_bfd_mips16_elf_reloc_unshuffle): Rename to...
(_bfd_mips_elf_reloc_unshuffle): ... this. Handle microMIPS
ASE.
(_bfd_mips16_elf_reloc_shuffle): Rename to...
(_bfd_mips_elf_reloc_shuffle): ... this. Handle microMIPS ASE.
(_bfd_mips_elf_lo16_reloc): Handle microMIPS ASE.
(mips_tls_got_index, mips_elf_got_page): Likewise.
(mips_elf_create_local_got_entry): Likewise.
(mips_elf_relocation_needs_la25_stub): Likewise.
(mips_elf_calculate_relocation): Likewise.
(mips_elf_perform_relocation): Likewise.
(_bfd_mips_elf_symbol_processing): Likewise.
(_bfd_mips_elf_add_symbol_hook): Likewise.
(_bfd_mips_elf_link_output_symbol_hook): Likewise.
(mips_elf_add_lo16_rel_addend): Likewise.
(_bfd_mips_elf_check_relocs): Likewise.
(mips_elf_adjust_addend): Likewise.
(_bfd_mips_elf_relocate_section): Likewise.
(mips_elf_create_la25_stub): Likewise.
(_bfd_mips_vxworks_finish_dynamic_symbol): Likewise.
(_bfd_mips_elf_gc_sweep_hook): Likewise.
(_bfd_mips_elf_is_target_special_symbol): New function.
(mips_elf_relax_delete_bytes): Likewise.
(opcode_descriptor): New structure.
(RA): New macro.
(OP32_SREG, OP32_TREG, OP16_VALID_REG): Likewise.
(b_insns_32, bc_insn_32, bz_insn_32, bzal_insn_32): New variables.
(beq_insn_32): Likewise.
(b_insn_16, bz_insn_16): New variables.
(BZC32_REG_FIELD): New macro.
(bz_rs_insns_32, bz_rt_insns_32): New variables.
(bzc_insns_32, bz_insns_16):Likewise.
(BZ16_REG, BZ16_REG_FIELD): New macros.
(jal_insn_32_bd16, jal_insn_32_bd32): New variables.
(jal_x_insn_32_bd32): Likewise.
(j_insn_32, jalr_insn_32): Likewise.
(ds_insns_32_bd16, ds_insns_32_bd32): Likewise.
(jalr_insn_16_bd16, jalr_insn_16_bd32, jr_insn_16): Likewise.
(JR16_REG): New macro.
(ds_insns_16_bd16): New variable.
(lui_insn): Likewise.
(addiu_insn, addiupc_insn): Likewise.
(ADDIUPC_REG_FIELD): New macro.
(MOVE32_RD, MOVE32_RS): Likewise.
(MOVE16_RD_FIELD, MOVE16_RS_FIELD): Likewise.
(move_insns_32, move_insns_16): New variables.
(nop_insn_32, nop_insn_16): Likewise.
(MATCH): New macro.
(find_match): New function.
(check_br16_dslot, check_br32_dslot): Likewise.
(check_br16, check_br32): Likewise.
(IS_BITSIZE): New macro.
(_bfd_mips_elf_relax_section): New function.
(_bfd_mips_elf_merge_private_bfd_data): Disallow linking MIPS16
and microMIPS modules together.
(_bfd_mips_elf_print_private_bfd_data): Handle microMIPS ASE.
* reloc.c (BFD_RELOC_MICROMIPS_7_PCREL_S1): New relocation.
(BFD_RELOC_MICROMIPS_10_PCREL_S1): Likewise.
(BFD_RELOC_MICROMIPS_16_PCREL_S1): Likewise.
(BFD_RELOC_MICROMIPS_GPREL16): Likewise.
(BFD_RELOC_MICROMIPS_JMP, BFD_RELOC_MICROMIPS_HI16): Likewise.
(BFD_RELOC_MICROMIPS_HI16_S): Likewise.
(BFD_RELOC_MICROMIPS_LO16): Likewise.
(BFD_RELOC_MICROMIPS_LITERAL): Likewise.
(BFD_RELOC_MICROMIPS_GOT16): Likewise.
(BFD_RELOC_MICROMIPS_CALL16): Likewise.
(BFD_RELOC_MICROMIPS_GOT_HI16): Likewise.
(BFD_RELOC_MICROMIPS_GOT_LO16): Likewise.
(BFD_RELOC_MICROMIPS_CALL_HI16): Likewise.
(BFD_RELOC_MICROMIPS_CALL_LO16): Likewise.
(BFD_RELOC_MICROMIPS_SUB): Likewise.
(BFD_RELOC_MICROMIPS_GOT_PAGE): Likewise.
(BFD_RELOC_MICROMIPS_GOT_OFST): Likewise.
(BFD_RELOC_MICROMIPS_GOT_DISP): Likewise.
(BFD_RELOC_MICROMIPS_HIGHEST): Likewise.
(BFD_RELOC_MICROMIPS_HIGHER): Likewise.
(BFD_RELOC_MICROMIPS_SCN_DISP): Likewise.
(BFD_RELOC_MICROMIPS_JALR): Likewise.
(BFD_RELOC_MICROMIPS_TLS_GD): Likewise.
(BFD_RELOC_MICROMIPS_TLS_LDM): Likewise.
(BFD_RELOC_MICROMIPS_TLS_DTPREL_HI16): Likewise.
(BFD_RELOC_MICROMIPS_TLS_DTPREL_LO16): Likewise.
(BFD_RELOC_MICROMIPS_TLS_GOTTPREL): Likewise.
(BFD_RELOC_MICROMIPS_TLS_TPREL_HI16): Likewise.
(BFD_RELOC_MICROMIPS_TLS_TPREL_LO16): Likewise.
* bfd-in2.h: Regenerate.
* libbfd.h: Regenerate.
binutils/
2011-02-21 Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* readelf.c (get_machine_flags): Handle microMIPS ASE.
(get_mips_symbol_other): Likewise.
gas/
2011-02-21 Maciej W. Rozycki <macro@codesourcery.com>
Chao-ying Fu <fu@mips.com>
* config/tc-mips.h (mips_segment_info): Add one bit for
microMIPS.
(TC_LABEL_IS_LOCAL): New macro.
(mips_label_is_local): New prototype.
* config/tc-mips.c (S0, S7): New macros.
(emit_branch_likely_macro): New variable.
(mips_set_options): Add micromips.
(mips_opts): Initialise micromips to -1.
(file_ase_micromips): New variable.
(CPU_HAS_MICROMIPS): New macro.
(hilo_interlocks): Set for microMIPS too.
(gpr_interlocks): Likewise.
(cop_interlocks): Likewise.
(cop_mem_interlocks): Likewise.
(HAVE_CODE_COMPRESSION): New macro.
(micromips_op_hash): New variable.
(micromips_nop16_insn, micromips_nop32_insn): New variables.
(NOP_INSN): Handle microMIPS ASE.
(mips32_to_micromips_reg_b_map): New macro.
(mips32_to_micromips_reg_c_map): Likewise.
(mips32_to_micromips_reg_d_map): Likewise.
(mips32_to_micromips_reg_e_map): Likewise.
(mips32_to_micromips_reg_f_map): Likewise.
(mips32_to_micromips_reg_g_map): Likewise.
(mips32_to_micromips_reg_l_map): Likewise.
(mips32_to_micromips_reg_n_map): Likewise.
(mips32_to_micromips_reg_h_map): New variable.
(mips32_to_micromips_reg_m_map): Likewise.
(mips32_to_micromips_reg_q_map): Likewise.
(micromips_to_32_reg_h_map): New variable.
(micromips_to_32_reg_i_map): Likewise.
(micromips_to_32_reg_m_map): Likewise.
(micromips_to_32_reg_q_map): Likewise.
(micromips_to_32_reg_b_map): New macro.
(micromips_to_32_reg_c_map): Likewise.
(micromips_to_32_reg_d_map): Likewise.
(micromips_to_32_reg_e_map): Likewise.
(micromips_to_32_reg_f_map): Likewise.
(micromips_to_32_reg_g_map): Likewise.
(micromips_to_32_reg_l_map): Likewise.
(micromips_to_32_reg_n_map): Likewise.
(micromips_imm_b_map, micromips_imm_c_map): New macros.
(RELAX_DELAY_SLOT_16BIT): New macro.
(RELAX_DELAY_SLOT_SIZE_FIRST): Likewise.
(RELAX_DELAY_SLOT_SIZE_SECOND): Likewise.
(RELAX_MICROMIPS_ENCODE, RELAX_MICROMIPS_P): New macros.
(RELAX_MICROMIPS_TYPE, RELAX_MICROMIPS_AT): Likewise.
(RELAX_MICROMIPS_U16BIT, RELAX_MICROMIPS_UNCOND): Likewise.
(RELAX_MICROMIPS_COMPACT, RELAX_MICROMIPS_LINK): Likewise.
(RELAX_MICROMIPS_RELAX32, RELAX_MICROMIPS_TOOFAR16): Likewise.
(RELAX_MICROMIPS_MARK_TOOFAR16): Likewise.
(RELAX_MICROMIPS_CLEAR_TOOFAR16): Likewise.
(RELAX_MICROMIPS_TOOFAR32): Likewise.
(RELAX_MICROMIPS_MARK_TOOFAR32): Likewise.
(RELAX_MICROMIPS_CLEAR_TOOFAR32): Likewise.
(INSERT_OPERAND, EXTRACT_OPERAND): Handle microMIPS ASE.
(mips_macro_warning): Add delay_slot_16bit_p, delay_slot_32bit_p,
fsize and insns.
(mips_mark_labels): New function.
(mips16_small, mips16_ext): Remove variables, replacing with...
(forced_insn_size): ... this.
(append_insn, mips16_ip): Update accordingly.
(micromips_insn_length): New function.
(insn_length): Return the length of microMIPS instructions.
(mips_record_mips16_mode): Rename to...
(mips_record_compressed_mode): ... this. Handle microMIPS ASE.
(install_insn): Handle microMIPS ASE.
(reglist_lookup): New function.
(is_size_valid, is_delay_slot_valid): Likewise.
(md_begin): Handle microMIPS ASE.
(md_assemble): Likewise. Update for append_insn interface
change.
(micromips_reloc_p): New function.
(got16_reloc_p): Handle microMIPS ASE.
(hi16_reloc_p): Likewise.
(lo16_reloc_p): Likewise.
(matching_lo_reloc): Likewise.
(insn_uses_reg, reg_needs_delay): Likewise.
(mips_move_labels): Likewise.
(mips16_mark_labels): Rename to...
(mips_compressed_mark_labels): ... this. Handle microMIPS ASE.
(insns_between, nops_for_vr4130, nops_for_insn): Likewise.
(fix_loongson2f_nop, fix_loongson2f_jump): Likewise.
(MICROMIPS_LABEL_CHAR): New macro.
(micromips_target_label, micromips_target_name): New variables.
(micromips_label_name, micromips_label_expr): New functions.
(micromips_label_inc, micromips_add_label): Likewise.
(mips_label_is_local): Likewise.
(micromips_map_reloc): Likewise.
(append_insn): Add expansionp argument. Handle microMIPS ASE.
(start_noreorder, end_noreorder): Handle microMIPS ASE.
(macro_start, macro_warning, macro_end): Likewise.
(brk_fmt, cop12_fmt, jalr_fmt, lui_fmt): New variables.
(mem12_fmt, mfhl_fmt, shft_fmt, trap_fmt): Likewise.
(BRK_FMT, COP12_FMT, JALR_FMT, LUI_FMT): New macros.
(MEM12_FMT, MFHL_FMT, SHFT_FMT, TRAP_FMT): Likewise.
(macro_build): Handle microMIPS ASE. Update for append_insn
interface change.
(mips16_macro_build): Update for append_insn interface change.
(macro_build_jalr): Handle microMIPS ASE.
(macro_build_lui): Likewise. Simplify.
(load_register): Handle microMIPS ASE.
(load_address): Likewise.
(move_register): Likewise.
(macro_build_branch_likely): New function.
(macro_build_branch_ccl): Likewise.
(macro_build_branch_rs): Likewise.
(macro_build_branch_rsrt): Likewise.
(macro): Handle microMIPS ASE.
(validate_micromips_insn): New function.
(expr_const_in_range): Likewise.
(mips_ip): Handle microMIPS ASE.
(options): Add OPTION_MICROMIPS and OPTION_NO_MICROMIPS.
(md_longopts): Add mmicromips and mno-micromips.
(md_parse_option): Handle OPTION_MICROMIPS and
OPTION_NO_MICROMIPS.
(mips_after_parse_args): Handle microMIPS ASE.
(md_pcrel_from): Handle microMIPS relocations.
(mips_force_relocation): Likewise.
(md_apply_fix): Likewise.
(mips_align): Handle microMIPS ASE.
(s_mipsset): Likewise.
(s_cpload, s_cpsetup, s_cpreturn): Use relocation wrappers.
(s_dtprel_internal): Likewise.
(s_gpword, s_gpdword): Likewise.
(s_insn): Handle microMIPS ASE.
(s_mips_stab): Likewise.
(relaxed_micromips_32bit_branch_length): New function.
(relaxed_micromips_16bit_branch_length): New function.
(md_estimate_size_before_relax): Handle microMIPS ASE.
(mips_fix_adjustable): Likewise.
(tc_gen_reloc): Handle microMIPS relocations.
(mips_relax_frag): Handle microMIPS ASE.
(md_convert_frag): Likewise.
(mips_frob_file_after_relocs): Likewise.
(mips_elf_final_processing): Likewise.
(mips_nop_opcode): Likewise.
(mips_handle_align): Likewise.
(md_show_usage): Handle microMIPS options.
* symbols.c (TC_LABEL_IS_LOCAL): New macro.
(S_IS_LOCAL): Add a TC_LABEL_IS_LOCAL check.
* doc/as.texinfo (Target MIPS options): Add -mmicromips and
-mno-micromips.
(-mmicromips, -mno-micromips): New options.
* doc/c-mips.texi (-mmicromips, -mno-micromips): New options.
(MIPS ISA): Document .set micromips and .set nomicromips.
(MIPS insn): Update for microMIPS support.
gas/testsuite/
2011-02-21 Maciej W. Rozycki <macro@codesourcery.com>
Chao-ying Fu <fu@mips.com>
* gas/mips/micromips.d: New test.
* gas/mips/micromips-branch-delay.d: Likewise.
* gas/mips/micromips-branch-relax.d: Likewise.
* gas/mips/micromips-branch-relax-pic.d: Likewise.
* gas/mips/micromips-size-1.d: Likewise.
* gas/mips/micromips-trap.d: Likewise.
* gas/mips/micromips.l: New stderr output.
* gas/mips/micromips-branch-delay.l: Likewise.
* gas/mips/micromips-branch-relax.l: Likewise.
* gas/mips/micromips-branch-relax-pic.l: Likewise.
* gas/mips/micromips-size-0.l: New list test.
* gas/mips/micromips-size-1.l: New stderr output.
* gas/mips/micromips.s: New test source.
* gas/mips/micromips-branch-delay.s: Likewise.
* gas/mips/micromips-branch-relax.s: Likewise.
* gas/mips/micromips-size-0.s: Likewise.
* gas/mips/micromips-size-1.s: Likewise.
* gas/mips/mips.exp: Run the new tests.
* gas/mips/elf_ase_micromips.d: New test.
* gas/mips/elf_ase_micromips-2.d: Likewise.
* gas/mips/micromips@abs.d: Likewise.
* gas/mips/micromips@add.d: Likewise.
* gas/mips/micromips@and.d: Likewise.
* gas/mips/micromips@beq.d: Likewise.
* gas/mips/micromips@bge.d: Likewise.
* gas/mips/micromips@bgeu.d: Likewise.
* gas/mips/micromips@blt.d: Likewise.
* gas/mips/micromips@bltu.d: Likewise.
* gas/mips/micromips@branch-likely.d: Likewise.
* gas/mips/micromips@branch-misc-1.d: Likewise.
* gas/mips/micromips@branch-misc-2-64.d: Likewise.
* gas/mips/micromips@branch-misc-2.d: Likewise.
* gas/mips/micromips@branch-misc-2pic-64.d: Likewise.
* gas/mips/micromips@branch-misc-2pic.d: Likewise.
* gas/mips/micromips@branch-self.d: Likewise.
* gas/mips/micromips@cache.d: Likewise.
* gas/mips/micromips@daddi.d: Likewise.
* gas/mips/micromips@dli.d: Likewise.
* gas/mips/micromips@elf-jal.d: Likewise.
* gas/mips/micromips@elf-rel2.d: Likewise.
* gas/mips/micromips@elf-rel4.d: Likewise.
* gas/mips/micromips@jal-svr4pic.d: Likewise.
* gas/mips/micromips@jal-svr4pic-noreorder.d: Likewise.
* gas/mips/micromips@lb-svr4pic-ilocks.d: Likewise.
* gas/mips/micromips@li.d: Likewise.
* gas/mips/micromips@mips1-fp.d: Likewise.
* gas/mips/micromips@mips32-cp2.d: Likewise.
* gas/mips/micromips@mips32-imm.d: Likewise.
* gas/mips/micromips@mips32-sf32.d: Likewise.
* gas/mips/micromips@mips32.d: Likewise.
* gas/mips/micromips@mips32r2-cp2.d: Likewise.
* gas/mips/micromips@mips32r2-fp32.d: Likewise.
* gas/mips/micromips@mips32r2.d: Likewise.
* gas/mips/micromips@mips4-branch-likely.d: Likewise.
* gas/mips/micromips@mips4-fp.d: Likewise.
* gas/mips/micromips@mips4.d: Likewise.
* gas/mips/micromips@mips5.d: Likewise.
* gas/mips/micromips@mips64-cp2.d: Likewise.
* gas/mips/micromips@mips64.d: Likewise.
* gas/mips/micromips@mips64r2.d: Likewise.
* gas/mips/micromips@pref.d: Likewise.
* gas/mips/micromips@rol-hw.d: Likewise.
* gas/mips/micromips@uld2-eb.d: Likewise.
* gas/mips/micromips@uld2-el.d: Likewise.
* gas/mips/micromips@ulh2-eb.d: Likewise.
* gas/mips/micromips@ulh2-el.d: Likewise.
* gas/mips/micromips@ulw2-eb-ilocks.d: Likewise.
* gas/mips/micromips@ulw2-el-ilocks.d: Likewise.
* gas/mips/cache.d: Likewise.
* gas/mips/daddi.d: Likewise.
* gas/mips/mips32-imm.d: Likewise.
* gas/mips/pref.d: Likewise.
* gas/mips/elf-rel27.d: Handle microMIPS ASE.
* gas/mips/l_d.d: Likewise.
* gas/mips/l_d-n32.d: Likewise.
* gas/mips/l_d-n64.d: Likewise.
* gas/mips/ld.d: Likewise.
* gas/mips/ld-n32.d: Likewise.
* gas/mips/ld-n64.d: Likewise.
* gas/mips/s_d.d: Likewise.
* gas/mips/s_d-n32.d: Likewise.
* gas/mips/s_d-n64.d: Likewise.
* gas/mips/sd.d: Likewise.
* gas/mips/sd-n32.d: Likewise.
* gas/mips/sd-n64.d: Likewise.
* gas/mips/mips32.d: Update immediates.
* gas/mips/micromips@mips32-cp2.s: New test source.
* gas/mips/micromips@mips32-imm.s: Likewise.
* gas/mips/micromips@mips32r2-cp2.s: Likewise.
* gas/mips/micromips@mips64-cp2.s: Likewise.
* gas/mips/cache.s: Likewise.
* gas/mips/daddi.s: Likewise.
* gas/mips/mips32-imm.s: Likewise.
* gas/mips/elf-rel4.s: Handle microMIPS ASE.
* gas/mips/lb-pic.s: Likewise.
* gas/mips/ld.s: Likewise.
* gas/mips/mips32.s: Likewise.
* gas/mips/mips.exp: Add the micromips arch. Exclude mips16e
from micromips. Run mips32-imm.
* gas/mips/jal-mask-11.d: New test.
* gas/mips/jal-mask-12.d: Likewise.
* gas/mips/micromips@jal-mask-11.d: Likewise.
* gas/mips/jal-mask-1.s: Source for the new tests.
* gas/mips/jal-mask-21.d: New test.
* gas/mips/jal-mask-22.d: Likewise.
* gas/mips/micromips@jal-mask-12.d: Likewise.
* gas/mips/jal-mask-2.s: Source for the new tests.
* gas/mips/mips.exp: Run the new tests.
* gas/mips/mips16-e.d: Add --special-syms to `objdump'.
* gas/mips/tmips16-e.d: Likewise.
* gas/mips/and.s: Adjust padding.
* gas/mips/beq.s: Likewise.
* gas/mips/bge.s: Likewise.
* gas/mips/bgeu.s: Likewise.
* gas/mips/blt.s: Likewise.
* gas/mips/bltu.s: Likewise.
* gas/mips/branch-misc-2.s: Likewise.
* gas/mips/jal.s: Likewise.
* gas/mips/li.s: Likewise.
* gas/mips/mips1-fp.s: Likewise.
* gas/mips/mips32r2-fp32.s: Likewise.
* gas/mips/mips64.s: Likewise.
* gas/mips/mips4.s: Likewise.
* gas/mips/mips4-fp.s: Likewise.
* gas/mips/and.d: Update accordingly.
* gas/mips/elf-jal.d: Likewise.
* gas/mips/jal.d: Likewise.
* gas/mips/li.d: Likewise.
* gas/mips/mips1-fp.d: Likewise.
* gas/mips/mips32r2-fp32.d: Likewise.
* gas/mips/mips64.d: Likewise.
include/elf/
2011-02-21 Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* mips.h (R_MICROMIPS_min): New relocations.
(R_MICROMIPS_26_S1): Likewise.
(R_MICROMIPS_HI16, R_MICROMIPS_LO16): Likewise.
(R_MICROMIPS_GPREL16, R_MICROMIPS_LITERAL): Likewise.
(R_MICROMIPS_GOT16, R_MICROMIPS_PC7_S1): Likewise.
(R_MICROMIPS_PC10_S1, R_MICROMIPS_PC16_S1): Likewise.
(R_MICROMIPS_CALL16, R_MICROMIPS_GOT_DISP): Likewise.
(R_MICROMIPS_GOT_PAGE, R_MICROMIPS_GOT_OFST): Likewise.
(R_MICROMIPS_GOT_HI16, R_MICROMIPS_GOT_LO16): Likewise.
(R_MICROMIPS_SUB, R_MICROMIPS_HIGHER): Likewise.
(R_MICROMIPS_HIGHEST, R_MICROMIPS_CALL_HI16): Likewise.
(R_MICROMIPS_CALL_LO16, R_MICROMIPS_SCN_DISP): Likewise.
(R_MICROMIPS_JALR, R_MICROMIPS_HI0_LO16): Likewise.
(R_MICROMIPS_TLS_GD, R_MICROMIPS_TLS_LDM): Likewise.
(R_MICROMIPS_TLS_DTPREL_HI, R_MICROMIPS_TLS_DTPREL_LO): Likewise.
(R_MICROMIPS_TLS_GOTTPREL): Likewise.
(R_MICROMIPS_TLS_TPREL_HI16): Likewise.
(R_MICROMIPS_TLS_TPREL_LO16): Likewise.
(R_MICROMIPS_GPREL7_S2, R_MICROMIPS_PC23_S2): Likewise.
(R_MICROMIPS_max): Likewise.
(EF_MIPS_ARCH_ASE_MICROMIPS): New macro.
(STO_MIPS_ISA, STO_MIPS_FLAGS): Likewise.
(ELF_ST_IS_MIPS_PLT, ELF_ST_SET_MIPS_PLT): Likewise.
(STO_MICROMIPS): Likewise.
(ELF_ST_IS_MICROMIPS, ELF_ST_SET_MICROMIPS): Likewise.
(ELF_ST_IS_COMPRESSED): Likewise.
(STO_MIPS_PLT, STO_MIPS_PIC): Rework.
(ELF_ST_IS_MIPS_PIC, ELF_ST_SET_MIPS_PIC): Likewise.
(STO_MIPS16, ELF_ST_IS_MIPS16, ELF_ST_SET_MIPS16): Likewise.
include/opcode/
2011-02-21 Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* mips.h (OP_MASK_EXTLSB, OP_SH_EXTLSB): New macros.
(OP_MASK_STYPE, OP_SH_STYPE): Likewise.
(OP_MASK_CODE10, OP_SH_CODE10): Likewise.
(OP_MASK_TRAP, OP_SH_TRAP): Likewise.
(OP_MASK_OFFSET12, OP_SH_OFFSET12): Likewise.
(OP_MASK_OFFSET10, OP_SH_OFFSET10): Likewise.
(OP_MASK_RS3, OP_SH_RS3): Likewise.
(OP_MASK_MB, OP_SH_MB, OP_MASK_MC, OP_SH_MC): Likewise.
(OP_MASK_MD, OP_SH_MD, OP_MASK_ME, OP_SH_ME): Likewise.
(OP_MASK_MF, OP_SH_MF, OP_MASK_MG, OP_SH_MG): Likewise.
(OP_MASK_MJ, OP_SH_MJ, OP_MASK_ML, OP_SH_ML): Likewise.
(OP_MASK_MP, OP_SH_MP, OP_MASK_MQ, OP_SH_MQ): Likewise.
(OP_MASK_IMMA, OP_SH_IMMA, OP_MASK_IMMB, OP_SH_IMMB): Likewise.
(OP_MASK_IMMC, OP_SH_IMMC, OP_MASK_IMMF, OP_SH_IMMF): Likewise.
(OP_MASK_IMMG, OP_SH_IMMG, OP_MASK_IMMH, OP_SH_IMMH): Likewise.
(OP_MASK_IMMI, OP_SH_IMMI, OP_MASK_IMMJ, OP_SH_IMMJ): Likewise.
(OP_MASK_IMML, OP_SH_IMML, OP_MASK_IMMM, OP_SH_IMMM): Likewise.
(OP_MASK_IMMN, OP_SH_IMMN, OP_MASK_IMMO, OP_SH_IMMO): Likewise.
(OP_MASK_IMMP, OP_SH_IMMP, OP_MASK_IMMQ, OP_SH_IMMQ): Likewise.
(OP_MASK_IMMU, OP_SH_IMMU, OP_MASK_IMMW, OP_SH_IMMW): Likewise.
(OP_MASK_IMMX, OP_SH_IMMX, OP_MASK_IMMY, OP_SH_IMMY): Likewise.
(INSN2_BRANCH_DELAY_16BIT, INSN2_BRANCH_DELAY_32BIT): New macros.
(INSN2_WRITE_GPR_S, INSN2_READ_FPR_D): Likewise.
(INSN2_MOD_GPR_MB, INSN2_MOD_GPR_MC, INSN2_MOD_GPR_MD): Likewise.
(INSN2_MOD_GPR_ME, INSN2_MOD_GPR_MF, INSN2_MOD_GPR_MG): Likewise.
(INSN2_MOD_GPR_MJ, INSN2_MOD_GPR_MP, INSN2_MOD_GPR_MQ): Likewise.
(INSN2_MOD_SP, INSN2_READ_GPR_31): Likewise.
(INSN2_READ_GP, INSN2_READ_PC): Likewise.
(CPU_MICROMIPS): New macro.
(M_BC1FL, M_BC1TL, M_BC2FL, M_BC2TL): New enum values.
(M_BEQL, M_BGEZ, M_BGEZL, M_BGEZALL, M_BGTZ, M_BGTZL): Likewise.
(M_BLEZ, M_BLEZL, M_BLTZ, M_BLTZL, M_BLTZALL, M_BNEL): Likewise.
(M_CACHE_OB, M_JALS_1, M_JALS_2, M_JALS_A): Likewise.
(M_LDC2_OB, M_LDL_OB, M_LDM_AB, M_LDM_OB): Likewise.
(M_LDP_AB, M_LDP_OB, M_LDR_OB, M_LL_OB, M_LLD_OB): Likewise.
(M_LWC2_OB, M_LWL_OB, M_LWM_AB, M_LWM_OB): Likewise.
(M_LWP_AB, M_LWP_OB, M_LWR_OB): Likewise.
(M_LWU_OB, M_PREF_OB, M_SC_OB, M_SCD_OB): Likewise.
(M_SDC2_OB, M_SDL_OB, M_SDM_AB, M_SDM_OB): Likewise.
(M_SDP_AB, M_SDP_OB, M_SDR_OB): Likewise.
(M_SWC2_OB, M_SWL_OB, M_SWM_AB, M_SWM_OB): Likewise.
(M_SWP_AB, M_SWP_OB, M_SWR_OB): Likewise.
(MICROMIPSOP_MASK_MAJOR, MICROMIPSOP_SH_MAJOR): New macros.
(MICROMIPSOP_MASK_IMMEDIATE, MICROMIPSOP_SH_IMMEDIATE): Likewise.
(MICROMIPSOP_MASK_DELTA, MICROMIPSOP_SH_DELTA): Likewise.
(MICROMIPSOP_MASK_CODE10, MICROMIPSOP_SH_CODE10): Likewise.
(MICROMIPSOP_MASK_TRAP, MICROMIPSOP_SH_TRAP): Likewise.
(MICROMIPSOP_MASK_SHAMT, MICROMIPSOP_SH_SHAMT): Likewise.
(MICROMIPSOP_MASK_TARGET, MICROMIPSOP_SH_TARGET): Likewise.
(MICROMIPSOP_MASK_EXTLSB, MICROMIPSOP_SH_EXTLSB): Likewise.
(MICROMIPSOP_MASK_EXTMSBD, MICROMIPSOP_SH_EXTMSBD): Likewise.
(MICROMIPSOP_MASK_INSMSB, MICROMIPSOP_SH_INSMSB): Likewise.
(MICROMIPSOP_MASK_CODE, MICROMIPSOP_SH_CODE): Likewise.
(MICROMIPSOP_MASK_CODE2, MICROMIPSOP_SH_CODE2): Likewise.
(MICROMIPSOP_MASK_CACHE, MICROMIPSOP_SH_CACHE): Likewise.
(MICROMIPSOP_MASK_SEL, MICROMIPSOP_SH_SEL): Likewise.
(MICROMIPSOP_MASK_OFFSET12, MICROMIPSOP_SH_OFFSET12): Likewise.
(MICROMIPSOP_MASK_3BITPOS, MICROMIPSOP_SH_3BITPOS): Likewise.
(MICROMIPSOP_MASK_STYPE, MICROMIPSOP_SH_STYPE): Likewise.
(MICROMIPSOP_MASK_OFFSET10, MICROMIPSOP_SH_OFFSET10): Likewise.
(MICROMIPSOP_MASK_RS, MICROMIPSOP_SH_RS): Likewise.
(MICROMIPSOP_MASK_RT, MICROMIPSOP_SH_RT): Likewise.
(MICROMIPSOP_MASK_RD, MICROMIPSOP_SH_RD): Likewise.
(MICROMIPSOP_MASK_FS, MICROMIPSOP_SH_FS): Likewise.
(MICROMIPSOP_MASK_FT, MICROMIPSOP_SH_FT): Likewise.
(MICROMIPSOP_MASK_FD, MICROMIPSOP_SH_FD): Likewise.
(MICROMIPSOP_MASK_FR, MICROMIPSOP_SH_FR): Likewise.
(MICROMIPSOP_MASK_RS3, MICROMIPSOP_SH_RS3): Likewise.
(MICROMIPSOP_MASK_PREFX, MICROMIPSOP_SH_PREFX): Likewise.
(MICROMIPSOP_MASK_BCC, MICROMIPSOP_SH_BCC): Likewise.
(MICROMIPSOP_MASK_CCC, MICROMIPSOP_SH_CCC): Likewise.
(MICROMIPSOP_MASK_COPZ, MICROMIPSOP_SH_COPZ): Likewise.
(MICROMIPSOP_MASK_MB, MICROMIPSOP_SH_MB): Likewise.
(MICROMIPSOP_MASK_MC, MICROMIPSOP_SH_MC): Likewise.
(MICROMIPSOP_MASK_MD, MICROMIPSOP_SH_MD): Likewise.
(MICROMIPSOP_MASK_ME, MICROMIPSOP_SH_ME): Likewise.
(MICROMIPSOP_MASK_MF, MICROMIPSOP_SH_MF): Likewise.
(MICROMIPSOP_MASK_MG, MICROMIPSOP_SH_MG): Likewise.
(MICROMIPSOP_MASK_MJ, MICROMIPSOP_SH_MJ): Likewise.
(MICROMIPSOP_MASK_ML, MICROMIPSOP_SH_ML): Likewise.
(MICROMIPSOP_MASK_MP, MICROMIPSOP_SH_MP): Likewise.
(MICROMIPSOP_MASK_MQ, MICROMIPSOP_SH_MQ): Likewise.
(MICROMIPSOP_MASK_IMMA, MICROMIPSOP_SH_IMMA): Likewise.
(MICROMIPSOP_MASK_IMMB, MICROMIPSOP_SH_IMMB): Likewise.
(MICROMIPSOP_MASK_IMMC, MICROMIPSOP_SH_IMMC): Likewise.
(MICROMIPSOP_MASK_IMMD, MICROMIPSOP_SH_IMMD): Likewise.
(MICROMIPSOP_MASK_IMME, MICROMIPSOP_SH_IMME): Likewise.
(MICROMIPSOP_MASK_IMMF, MICROMIPSOP_SH_IMMF): Likewise.
(MICROMIPSOP_MASK_IMMG, MICROMIPSOP_SH_IMMG): Likewise.
(MICROMIPSOP_MASK_IMMH, MICROMIPSOP_SH_IMMH): Likewise.
(MICROMIPSOP_MASK_IMMI, MICROMIPSOP_SH_IMMI): Likewise.
(MICROMIPSOP_MASK_IMMJ, MICROMIPSOP_SH_IMMJ): Likewise.
(MICROMIPSOP_MASK_IMML, MICROMIPSOP_SH_IMML): Likewise.
(MICROMIPSOP_MASK_IMMM, MICROMIPSOP_SH_IMMM): Likewise.
(MICROMIPSOP_MASK_IMMN, MICROMIPSOP_SH_IMMN): Likewise.
(MICROMIPSOP_MASK_IMMO, MICROMIPSOP_SH_IMMO): Likewise.
(MICROMIPSOP_MASK_IMMP, MICROMIPSOP_SH_IMMP): Likewise.
(MICROMIPSOP_MASK_IMMQ, MICROMIPSOP_SH_IMMQ): Likewise.
(MICROMIPSOP_MASK_IMMU, MICROMIPSOP_SH_IMMU): Likewise.
(MICROMIPSOP_MASK_IMMW, MICROMIPSOP_SH_IMMW): Likewise.
(MICROMIPSOP_MASK_IMMX, MICROMIPSOP_SH_IMMX): Likewise.
(MICROMIPSOP_MASK_IMMY, MICROMIPSOP_SH_IMMY): Likewise.
(MICROMIPSOP_MASK_CODE, MICROMIPSOP_SH_CODE): Likewise.
(MICROMIPSOP_MASK_CODE2, MICROMIPSOP_SH_CODE2): Likewise.
(MICROMIPSOP_MASK_CACHE, MICROMIPSOP_SH_CACHE): Likewise.
(MICROMIPSOP_MASK_CODE20, MICROMIPSOP_SH_CODE20): Likewise.
(MICROMIPSOP_MASK_PERFREG, MICROMIPSOP_SH_PERFREG): Likewise.
(MICROMIPSOP_MASK_CODE19, MICROMIPSOP_SH_CODE19): Likewise.
(MICROMIPSOP_MASK_ALN, MICROMIPSOP_SH_ALN): Likewise.
(MICROMIPSOP_MASK_VECBYTE, MICROMIPSOP_SH_VECBYTE): Likewise.
(MICROMIPSOP_MASK_VECALIGN, MICROMIPSOP_SH_VECALIGN): Likewise.
(MICROMIPSOP_MASK_DSPACC, MICROMIPSOP_SH_DSPACC): Likewise.
(MICROMIPSOP_MASK_DSPACC_S, MICROMIPSOP_SH_DSPACC_S): Likewise.
(MICROMIPSOP_MASK_DSPSFT, MICROMIPSOP_SH_DSPSFT): Likewise.
(MICROMIPSOP_MASK_DSPSFT_7, MICROMIPSOP_SH_DSPSFT_7): Likewise.
(MICROMIPSOP_MASK_SA3, MICROMIPSOP_SH_SA3): Likewise.
(MICROMIPSOP_MASK_SA4, MICROMIPSOP_SH_SA4): Likewise.
(MICROMIPSOP_MASK_IMM8, MICROMIPSOP_SH_IMM8): Likewise.
(MICROMIPSOP_MASK_IMM10, MICROMIPSOP_SH_IMM10): Likewise.
(MICROMIPSOP_MASK_WRDSP, MICROMIPSOP_SH_WRDSP): Likewise.
(MICROMIPSOP_MASK_RDDSP, MICROMIPSOP_SH_RDDSP): Likewise.
(MICROMIPSOP_MASK_BP, MICROMIPSOP_SH_BP): Likewise.
(MICROMIPSOP_MASK_MT_U, MICROMIPSOP_SH_MT_U): Likewise.
(MICROMIPSOP_MASK_MT_H, MICROMIPSOP_SH_MT_H): Likewise.
(MICROMIPSOP_MASK_MTACC_T, MICROMIPSOP_SH_MTACC_T): Likewise.
(MICROMIPSOP_MASK_MTACC_D, MICROMIPSOP_SH_MTACC_D): Likewise.
(MICROMIPSOP_MASK_BBITIND, MICROMIPSOP_SH_BBITIND): Likewise.
(MICROMIPSOP_MASK_CINSPOS, MICROMIPSOP_SH_CINSPOS): Likewise.
(MICROMIPSOP_MASK_CINSLM1, MICROMIPSOP_SH_CINSLM1): Likewise.
(MICROMIPSOP_MASK_SEQI, MICROMIPSOP_SH_SEQI): Likewise.
(micromips_opcodes): New declaration.
(bfd_micromips_num_opcodes): Likewise.
* mips.h (INSN2_UNCOND_BRANCH, INSN2_COND_BRANCH): New macros.
* mips.h (INSN2_MOD_GPR_MHI): New macro.
(INSN2_MOD_GPR_MM, INSN2_MOD_GPR_MN): Likewise.
(MICROMIPSOP_MASK_MH, MICROMIPSOP_SH_MH): Likewise.
(MICROMIPSOP_MASK_MI, MICROMIPSOP_SH_MI): Likewise.
(MICROMIPSOP_MASK_MM, MICROMIPSOP_SH_MM): Likewise.
(MICROMIPSOP_MASK_MN, MICROMIPSOP_SH_MN): Likewise.
ld/testsuite/
2011-02-21 Catherine Moore <clm@codesourcery.com>
Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* lib/ld-lib.exp (run_dump_test): Support distinct assembler
flags for the same source named multiple times.
* ld-mips-elf/jalx-1.s: New test source.
* ld-mips-elf/jalx-1.d: New test output.
* ld-mips-elf/jalx-1.ld: New test linker script.
* ld-mips-elf/jalx-2-main.s: New test source.
* ld-mips-elf/jalx-2-ex.s: Likewise.
* ld-mips-elf/jalx-2-printf.s: Likewise.
* ld-mips-elf/jalx-2.dd: New test output.
* ld-mips-elf/jalx-2.ld: New test linker script.
* ld-mips-elf/mips16-and-micromips.d: New test.
* ld-mips-elf/mips-elf.exp: Run the new tests
opcodes/
2011-02-21 Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* micromips-opc.c: New file.
* mips-dis.c (micromips_to_32_reg_b_map): New array.
(micromips_to_32_reg_c_map, micromips_to_32_reg_d_map): Likewise.
(micromips_to_32_reg_e_map, micromips_to_32_reg_f_map): Likewise.
(micromips_to_32_reg_g_map, micromips_to_32_reg_l_map): Likewise.
(micromips_to_32_reg_q_map): Likewise.
(micromips_imm_b_map, micromips_imm_c_map): Likewise.
(micromips_ase): New variable.
(is_micromips): New function.
(set_default_mips_dis_options): Handle microMIPS ASE.
(print_insn_micromips): New function.
(is_compressed_mode_p): Likewise.
(_print_insn_mips): Handle microMIPS instructions.
* Makefile.am (CFILES): Add micromips-opc.c.
* configure.in (bfd_mips_arch): Add micromips-opc.lo.
* Makefile.in: Regenerate.
* configure: Regenerate.
* mips-dis.c (micromips_to_32_reg_h_map): New variable.
(micromips_to_32_reg_i_map): Likewise.
(micromips_to_32_reg_m_map): Likewise.
(micromips_to_32_reg_n_map): New macro.
[-- Attachment #2: Type: APPLICATION/octet-stream, Size: 31674 bytes --]
[-- Attachment #3: Type: APPLICATION/octet-stream, Size: 6994 bytes --]
[-- Attachment #4: Type: APPLICATION/octet-stream, Size: 4086 bytes --]
^ permalink raw reply [flat|nested] 41+ messages in thread
* RE: [PATCH] MIPS: microMIPS ASE support
2011-02-21 15:35 ` Maciej W. Rozycki
@ 2011-02-22 20:12 ` Fu, Chao-Ying
2011-02-22 20:19 ` Fu, Chao-Ying
` (2 subsequent siblings)
3 siblings, 0 replies; 41+ messages in thread
From: Fu, Chao-Ying @ 2011-02-22 20:12 UTC (permalink / raw)
To: Maciej W. Rozycki, Richard Sandiford
Cc: binutils, Fuhler, Rich, Lau, David, Mills, Kevin, Garbacea, Ilie,
Catherine Moore, Nathan Sidwell, Joseph Myers, Nathan Froyd
Maciej W. Rozycki wrote:
>
> Chao-ying, there are a couple of questions for you
> throughout -- would
> you please give them a thought? And anyone, of course,
> please feel free
> to comment as you like.
>
> > > +static char *
> > > +micromips_label_name (void)
> > > +{
> > > + char *p = micromips_target_name;
> > > + char symbol_name_temporary[24];
> > > + unsigned long l;
> > > + int i;
> > > +
> > > + if (*p)
> > > + return p;
> > > +
> > > + i = 0;
> > > + l = micromips_target_label;
> > > +#ifdef LOCAL_LABEL_PREFIX
> > > + *p++ = LOCAL_LABEL_PREFIX;
> > > +#endif
> > [...]
> > > +int
> > > +mips_label_is_local (const char *name)
> > > +{
> > > + return strchr (name, MICROMIPS_LABEL_CHAR) != NULL;
> > > +}
> >
> > Why is this change needed? The default local-label
> detection should be
> > enough for ELF targets, which always have a LOCAL_LABEL_PREFIX.
>
> I fail to see a justification, so I have removed this function.
> Chao-ying, do you have anything to add?
I don't recall that I wrote this code. So, you may remove it.
>
> > > + /* For microMIPS PC relative relocations, we cannot
> convert it to
> > > + against a section. If we do, it will mess up the
> fixp->fx_offset. */
> > > if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
> > > - || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
> > > + || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY
> > > + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
> > > + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1
> > > + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1)
> >
> > "to be against a section". That's not a helpful comment though.
> > _How_ will it mess up fixp->fx_offset? Give the reader a clue why
> > the problem applies to BFD_RELOC_MICROMIPS_16_PCREL_S1 but not
> > to something like BFD_RELOC_16_PCREL_S2.
>
> I have failed to spot any problems with this hunk reverted
> and I'm not
> sure what I should be looking for. Therefore I feel a bit
> uneasy about
> removing it and only rephrased the comment without actually
> changing its
> meaning. Chao-ying, do you have anything to add?
I added this code to avoid GAS errors when compiling Linux kernel for microMIPS.
Ex:
mipsisa32r2-linux-gnu-gcc -Wp,-MD,kernel/.rtmutex.o.d -nostdinc -isystem /hom
e/fu/dev/binutils3/build-linux-20090506/tools/lib/gcc/mipsisa32r2-linux-gnu/4.4.
0/include -D__KERNEL__ -Iinclude -include include/linux/autoconf.h -Wall -Wunde
f -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -O2 -mabi
=32 -G 0 -mno-abicalls -fno-pic -pipe -ffreestanding -EL -UMIPSEB -U_MIPSEB -U__
MIPSEB -U__MIPSEB__ -UMIPSEL -U_MIPSEL -U__MIPSEL -U__MIPSEL__ -DMIPSEL -D_MIPSE
L -D__MIPSEL -D__MIPSEL__ -march=mips32r2 -Wa,-mips32r2 -Wa,--trap -Iinclude/asm
-mips/mach-sim -Iinclude/asm-mips/mach-generic -mmicromips -fomit-frame-pointer
-g -fno-stack-protector -Wdeclaration-after-statement -Wno-pointer-sign -mmicro
mips -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(rtmutex)" -D"KBUILD_
MODNAME=KBUILD_STR(rtmutex)" -c -o kernel/.tmp_rtmutex.o kernel/rtmutex.c
{standard input}: Assembler messages:
{standard input}:3030: Error: relocation overflow
{standard input}:3125: Error: relocation overflow
{standard input}:3213: Error: relocation overflow
{standard input}:3408: Error: relocation overflow
make[1]: *** [kernel/rtmutex.o] Error 1
A simple case is as follows.
<597> # cat 2.s
.set push
.set noat
.set mips3
.space 1<<10
1: ll $6, 0($2) # __cmpxchg_u32
bne $6, $0, 2f
.set mips0
move $1, $3
.set mips3
sc $1, 0($2)
beqz $1, 3f
2:
.subsection 2
3: b 1b
.previous
.set pop
I kind of forgot my debug process to come out with the solution.
Maybe if we use the section as the target, R_MICROMIPS_PC7_S1 will lead to
incorrect checking for overflow.
Ex: (write.c)
static void
adjust_reloc_syms (bfd *abfd ATTRIBUTE_UNUSED,
asection *sec,
void *xxx ATTRIBUTE_UNUSED)
{
segment_info_type *seginfo = seg_info (sec);
fixS *fixp;
...
/* We refetch the segment when calling section_symbol, rather
than using symsec, because S_GET_VALUE may wind up changing
the section when it calls resolve_symbol_value. */
fixp->fx_offset += S_GET_VALUE (sym); <----- THIS WILL BE TOO BIG, if we use the section.
fixp->fx_addsy = section_symbol (S_GET_SEGMENT (sym));
#ifdef DEBUG5
fprintf (stderr, "\nadjusted fixup:\n");
print_fixup (fixp);
#endif
}
dump_section_relocs (abfd, sec, stderr);
}
Thanks!
Regards,
Chao-ying
^ permalink raw reply [flat|nested] 41+ messages in thread
* RE: [PATCH] MIPS: microMIPS ASE support
2011-02-21 15:35 ` Maciej W. Rozycki
2011-02-22 20:12 ` Fu, Chao-Ying
@ 2011-02-22 20:19 ` Fu, Chao-Ying
2011-02-24 10:46 ` Maciej W. Rozycki
2011-02-26 0:00 ` Maciej W. Rozycki
2011-02-26 11:36 ` Richard Sandiford
3 siblings, 1 reply; 41+ messages in thread
From: Fu, Chao-Ying @ 2011-02-22 20:19 UTC (permalink / raw)
To: Maciej W. Rozycki, Richard Sandiford
Cc: binutils, Fuhler, Rich, Lau, David, Mills, Kevin, Garbacea, Ilie,
Catherine Moore, Nathan Sidwell, Joseph Myers, Nathan Froyd
>
> > > > + /* For microMIPS PC relative relocations, we cannot
> > convert it to
> > > > + against a section. If we do, it will mess up the
> > fixp->fx_offset. */
> > > > if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
> > > > - || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
> > > > + || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY
> > > > + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
> > > > + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1
> > > > + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1)
> > >
> > > "to be against a section". That's not a helpful comment though.
> > > _How_ will it mess up fixp->fx_offset? Give the reader a clue why
> > > the problem applies to BFD_RELOC_MICROMIPS_16_PCREL_S1 but not
> > > to something like BFD_RELOC_16_PCREL_S2.
GAS resolves all MIPS pc-relative relocation types inside assembling, so there are no issues for
BFD_RELOC_16_PCREL_S2. For microMIPS, GAS leaves them to the linker, so we hit new issues for
microMIPS pc-relative relocation types. Thanks!
Regards,
Chao-ying
^ permalink raw reply [flat|nested] 41+ messages in thread
* RE: [PATCH] MIPS: microMIPS ASE support
2011-02-22 20:19 ` Fu, Chao-Ying
@ 2011-02-24 10:46 ` Maciej W. Rozycki
2011-02-26 11:41 ` Richard Sandiford
0 siblings, 1 reply; 41+ messages in thread
From: Maciej W. Rozycki @ 2011-02-24 10:46 UTC (permalink / raw)
To: Fu, Chao-Ying
Cc: Richard Sandiford, binutils, Fuhler, Rich, Lau, David, Mills,
Kevin, Garbacea, Ilie, Catherine Moore, Nathan Sidwell,
Joseph Myers, Nathan Froyd
On Tue, 22 Feb 2011, Fu, Chao-Ying wrote:
> > > > > + /* For microMIPS PC relative relocations, we cannot
> > > convert it to
> > > > > + against a section. If we do, it will mess up the
> > > fixp->fx_offset. */
> > > > > if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
> > > > > - || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
> > > > > + || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY
> > > > > + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
> > > > > + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1
> > > > > + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1)
> > > >
> > > > "to be against a section". That's not a helpful comment though.
> > > > _How_ will it mess up fixp->fx_offset? Give the reader a clue why
> > > > the problem applies to BFD_RELOC_MICROMIPS_16_PCREL_S1 but not
> > > > to something like BFD_RELOC_16_PCREL_S2.
>
> GAS resolves all MIPS pc-relative relocation types inside assembling, so there are no issues for
> BFD_RELOC_16_PCREL_S2. For microMIPS, GAS leaves them to the linker, so we hit new issues for
> microMIPS pc-relative relocation types. Thanks!
Thanks for the hint -- now I can see what's going on.
The problem is for REL targets we have a limited number of relocatable
bits in the instruction to store the in-place addend. The space does not
cover the whole address space and because these are PC-relative
relocations, if converted to section-relative ones, then they can overflow
even for legitimate symbol references.
As such the change belongs next to the check for BFD_RELOC_MIPS_JALR
relocations and likewise it does not apply to RELA targets. I have
updated the change accordingly.
Contrary to what you say the problem does apply to standard MIPS code
too, because BFD_RELOC_16_PCREL_S2 relocs against defined symbols are not
always resolved internally by GAS and R_MIPS_PC16 relocs are produced as
appropriate. Consider the following program:
$ cat bsec.s
.text
.space 0x40000
.Lbar:
addu $2, $3, $4
.section .init, "ax", @progbits
foo:
b .Lbar
As .Lbar is a local defined symbol from another section, a relocation is
placed into the output file for the static linker to resolve based on the
final section layout. The program does not build though:
$ mips-sde-elf-as -o bsec.o bsec.s
bsec.s: Assembler messages:
bsec.s:8: Error: relocation overflow
This is because .Lbar is too far into .text for the PC-relative offset to
fit into the relocatable field of the R_MIPS_PC16 reloc. Therefore this
reference shouldn't be made section-relative either. This observation
makes this change not specific to microMIPS relocations at all, so I have
separated it and I'm providing it below. I have removed the original hunk
from the microMIPS patch altogether now.
And for the record, MIPS16 branches produce no reloc at all (hence
excluded from the test case), even though they probably should.
2011-02-24 Maciej W. Rozycki <macro@codesourcery.com>
gas/
* config/tc-mips.c (mips_fix_adjustable): On REL targets also
reject PC-relative relocations.
gas/testsuite/
* gas/mips/branch-misc-2.d: Adjust for relocation change.
* gas/mips/branch-misc-2pic.d: Likewise.
* gas/mips/branch-misc-4.d: New test for PC-relative relocation
overflow.
* gas/mips/branch-misc-4-64.d: Likewise.
* gas/mips/branch-misc-4.s: Source for the new tests.
* testsuite/gas/mips/mips.exp: Run the new tests.
This change has been regression-tested for the mips-sde-elf and
mips-linux-gnu targets. OK to apply?
Maciej
binutils-gas-mips-fix-pc-rel.diff
Index: binutils-fsf-trunk-quilt/gas/config/tc-mips.c
===================================================================
--- binutils-fsf-trunk-quilt.orig/gas/config/tc-mips.c 2011-02-24 10:14:39.000000000 +0000
+++ binutils-fsf-trunk-quilt/gas/config/tc-mips.c 2011-02-24 10:22:22.000000000 +0000
@@ -14229,8 +14229,12 @@ mips_fix_adjustable (fixS *fixp)
&& (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_MERGE) != 0)
return 0;
- /* There is no place to store an in-place offset for JALR relocations. */
- if (fixp->fx_r_type == BFD_RELOC_MIPS_JALR && HAVE_IN_PLACE_ADDENDS)
+ /* There is no place to store an in-place offset for JALR relocations.
+ Likewise an in-range offset of PC-relative relocations may overflow
+ the in-place relocatable field if recalculated against the start
+ address of the symbol's containing section. */
+ if (HAVE_IN_PLACE_ADDENDS
+ && (fixp->fx_pcrel || fixp->fx_r_type == BFD_RELOC_MIPS_JALR))
return 0;
#ifdef OBJ_ELF
Index: binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/branch-misc-2.d
===================================================================
--- binutils-fsf-trunk-quilt.orig/gas/testsuite/gas/mips/branch-misc-2.d 2011-02-24 10:14:33.000000000 +0000
+++ binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/branch-misc-2.d 2011-02-24 10:20:45.000000000 +0000
@@ -39,6 +39,6 @@
[ ]*b0: R_MIPS_PC16 x2
0+00b4 <[^>]*> 00000000 nop
0+00b8 <[^>]*> 1000ffff b 000000b8 <g6\+0x10>
-[ ]*b8: R_MIPS_PC16 \.data
+[ ]*b8: R_MIPS_PC16 \.Ldata
0+00bc <[^>]*> 00000000 nop
\.\.\.
Index: binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/branch-misc-2pic.d
===================================================================
--- binutils-fsf-trunk-quilt.orig/gas/testsuite/gas/mips/branch-misc-2pic.d 2011-02-24 10:14:33.000000000 +0000
+++ binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/branch-misc-2pic.d 2011-02-24 10:20:45.000000000 +0000
@@ -40,6 +40,6 @@
[ ]*b0: R_MIPS_PC16 x2
0+00b4 <[^>]*> 00000000 nop
0+00b8 <[^>]*> 1000ffff b 000000b8 <g6\+0x10>
-[ ]*b8: R_MIPS_PC16 \.data
+[ ]*b8: R_MIPS_PC16 \.Ldata
0+00bc <[^>]*> 00000000 nop
\.\.\.
Index: binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/branch-misc-4.d
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/branch-misc-4.d 2011-02-24 10:22:59.000000000 +0000
@@ -0,0 +1,26 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: MIPS branch-misc-4
+#as: -32
+
+# Verify PC-relative relocations do not overflow.
+
+.*: +file format .*mips.*
+
+Disassembly of section \.text:
+ \.\.\.
+([0-9a-f]+) <[^>]*> 1000ffff b \1 <foo>
+[ ]*[0-9a-f]+: R_MIPS_PC16 bar
+[0-9a-f]+ <[^>]*> 00000000 nop
+([0-9a-f]+) <[^>]*> 1000ffff b \1 <\.Lfoo>
+[ ]*[0-9a-f]+: R_MIPS_PC16 \.Lbar
+[0-9a-f]+ <[^>]*> 00000000 nop
+ \.\.\.
+
+Disassembly of section \.init:
+([0-9a-f]+) <[^>]*> 1000ffff b \1 <bar>
+[ ]*[0-9a-f]+: R_MIPS_PC16 foo
+[0-9a-f]+ <[^>]*> 00000000 nop
+([0-9a-f]+) <[^>]*> 1000ffff b \1 <\.Lbar>
+[ ]*[0-9a-f]+: R_MIPS_PC16 \.Lfoo
+[0-9a-f]+ <[^>]*> 00000000 nop
+ \.\.\.
Index: binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/branch-misc-4.s
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/branch-misc-4.s 2011-02-24 10:14:40.000000000 +0000
@@ -0,0 +1,28 @@
+# Source file to verify PC-relative relocations do not overflow.
+
+ .text
+ .space 0x40000
+ .globl foo
+ .ent foo
+foo:
+ b bar
+.Lfoo:
+ b .Lbar
+ .end foo
+
+# Force at least 8 (non-delay-slot) zero bytes, to make 'objdump' print ...
+ .align 2
+ .space 8
+
+ .section .init, "ax", @progbits
+ .globl bar
+ .ent bar
+bar:
+ b foo
+.Lbar:
+ b .Lfoo
+ .end bar
+
+# Force at least 8 (non-delay-slot) zero bytes, to make 'objdump' print ...
+ .align 2
+ .space 8
Index: binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/mips.exp
===================================================================
--- binutils-fsf-trunk-quilt.orig/gas/testsuite/gas/mips/mips.exp 2011-02-24 10:14:39.000000000 +0000
+++ binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/mips.exp 2011-02-24 10:20:46.000000000 +0000
@@ -838,6 +838,10 @@ if { [istarget mips*-*-vxworks*] } {
run_dump_test_arches "loc-swap" [mips_arch_list_all]
run_dump_test_arches "loc-swap-dis" \
[mips_arch_list_all]
+ run_dump_test_arches "branch-misc-4" \
+ [mips_arch_list_matching mips1]
+ run_dump_test_arches "branch-misc-4-64" \
+ [mips_arch_list_matching mips3]
}
if $has_newabi {
Index: binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/branch-misc-4-64.d
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/branch-misc-4-64.d 2011-02-24 10:14:40.000000000 +0000
@@ -0,0 +1,35 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: MIPS branch-misc-4-64
+#as: -64
+#source: branch-misc-4.s
+
+# Verify PC-relative relocations do not overflow.
+
+.*: +file format .*mips.*
+
+Disassembly of section \.text:
+ \.\.\.
+[0-9a-f]+ <[^>]*> 10000000 b [0-9a-f]+ <foo\+0x[0-9a-f]+>
+[ ]*[0-9a-f]+: R_MIPS_PC16 bar\+0xf+fffc
+[ ]*[0-9a-f]+: R_MIPS_NONE \*ABS\*\+0xf+fffc
+[ ]*[0-9a-f]+: R_MIPS_NONE \*ABS\*\+0xf+fffc
+[0-9a-f]+ <[^>]*> 00000000 nop
+[0-9a-f]+ <[^>]*> 10000000 b [0-9a-f]+ <foo\+0x[0-9a-f]+>
+[ ]*[0-9a-f]+: R_MIPS_PC16 \.init\+0x4
+[ ]*[0-9a-f]+: R_MIPS_NONE \*ABS\*\+0x4
+[ ]*[0-9a-f]+: R_MIPS_NONE \*ABS\*\+0x4
+[0-9a-f]+ <[^>]*> 00000000 nop
+ \.\.\.
+
+Disassembly of section \.init:
+[0-9a-f]+ <[^>]*> 10000000 b [0-9a-f]+ <bar\+0x[0-9a-f]+>
+[ ]*[0-9a-f]+: R_MIPS_PC16 foo\+0xf+fffc
+[ ]*[0-9a-f]+: R_MIPS_NONE \*ABS\*\+0xf+fffc
+[ ]*[0-9a-f]+: R_MIPS_NONE \*ABS\*\+0xf+fffc
+[0-9a-f]+ <[^>]*> 00000000 nop
+[0-9a-f]+ <[^>]*> 10000000 b [0-9a-f]+ <bar\+0x[0-9a-f]+>
+[ ]*[0-9a-f]+: R_MIPS_PC16 \.text\+0x40004
+[ ]*[0-9a-f]+: R_MIPS_NONE \*ABS\*\+0x40004
+[ ]*[0-9a-f]+: R_MIPS_NONE \*ABS\*\+0x40004
+[0-9a-f]+ <[^>]*> 00000000 nop
+ \.\.\.
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2011-02-21 15:35 ` Maciej W. Rozycki
2011-02-22 20:12 ` Fu, Chao-Ying
2011-02-22 20:19 ` Fu, Chao-Ying
@ 2011-02-26 0:00 ` Maciej W. Rozycki
2011-03-13 9:23 ` Richard Sandiford
2011-02-26 11:36 ` Richard Sandiford
3 siblings, 1 reply; 41+ messages in thread
From: Maciej W. Rozycki @ 2011-02-26 0:00 UTC (permalink / raw)
To: Richard Sandiford
Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers,
Nathan Froyd
[-- Attachment #1: Type: TEXT/PLAIN, Size: 34439 bytes --]
Hi Richard,
As it has turned out in the course of sorting out some earlier concerns
the microMIPS change needs a couple of updates. For your reference I'm
sending the current version of the original patch as it had to be
regenerated. On top of this I'm sending the following updates:
- binutils-umips-fix.diff -- the original fix addressing your concerns and
some other issues, regenerated, and with some small bug fixes applied,
- binutils-umips-opcode-trap.diff -- a complementing microMIPS change to
the trap/no-delay slot annotation made to standard MIPS/MIPS16 code,
- binutils-gas-mips-fix-adjust-reloc.diff -- a fix for relocation handling
problems discovered while fixing the issue with PC-relative relocations
discussed earlier; a summary of the changes:
* BFD_RELOC_MICROMIPS_JALR relocs are now explicitly excluded like their
standard MIPS counterpart; this bug was covered by all microMIPS being
converted to section-relative ones,
* unlike MIPS16 code we don't have call stubs in the microMIPS mode and
therefore of the remaing relocs affecting microMIPS code only jump
relocations against microMIPS text symbols on REL targets are
converted to section-relative ones as the in-place relocatable field
strips out the ISA bit,
* therefore we don't have to tag symbols that have a microMIPS jump
relocation against them, because they're going to be handled just fine
as long as the symbol is not a microMIPS text one,
- binutils-umips-relax16.diff -- the original 16-bit->32-bit->out-of-range
branch relaxation change, regenerated,
- binutils-umips-fix-reloc.diff -- the original microMIPS relocation
handling divergence reduction change, regenerated,
- binutils-gas-umips-swap.diff -- branch delay slot scheduling support for
microMIPS code as the DWARF-2 line number adjustment fix I posted
earlier made it possible to enable it now. We lacked some
infrastructure here, so I have added the necessary register dependencies
tests, as well as checks that we don't reorder something unsuitable into
a slot of a fixed size (in theory we could do this anyway and flip the
delay-slot-size bit in the branch or jump instruction output, but that's
not as easy as it would seem at this point of instruction processing, so
I left it as a future enhancement [FIXME]). I believe we can't reorder
an ADDIUPC either as it would break offset calculation if a label at the
instruction was used (quite likely) that doesn't get moved with the
swap.
I have split some of the combined register access flags so that we can
avoid false negatives and reorder some frequent instructions, such as
16-bit MOVEs. Some of these flags actually turned out not to be
combined at all. I have joined the MM and MN flags as they are always
used together (by MOVEP) and therefore need not be separate. Given the
shortage of flags (I tried to avoid overloading) I have decided MD and
SP are the ones that can remain combined, the former because it's only
used to mark registers read with branches and these cannot be scheduled
into delay slots anyway, and the latter because the use of $sp as the
condition for branches is unusual. I have split them syntactically by
the usage throughout the opcode table though, so making them separate in
the future will be as easy as updating <opcode/mips.h> and any
references in GAS.
All these were regression-tested against mips-sde-elf and mips-gnu-linux.
An updated set of ChangeLog entries follows. Patches apply in the order
stated and require all the standard MIPS changes I submitted this week.
Maciej
binutils-20110225-umips.diff
binutils-20110225-umips-fix.diff
binutils-20110225-umips-opcode-trap.diff
binutils-20110225-gas-mips-fix-adjust-reloc.diff
binutils-20110225-umips-relax16.diff
binutils-20110225-umips-fix-reloc.diff
binutils-20110225-gas-umips-swap.diff
[Patches attached compressed due to their size.]
bfd/
2011-02-25 Chao-ying Fu <fu@mips.com>
Ilie Garbacea <ilie@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
Joseph Myers <joseph@codesourcery.com>
Catherine Moore <clm@codesourcery.com>
* archures.c (bfd_mach_mips_micromips): New macro.
* cpu-mips.c (I_micromips): New enum value.
(arch_info_struct): Add bfd_mach_mips_micromips.
* elfxx-mips.h (_bfd_mips_elf_is_target_special_symbol): New
prototype.
(_bfd_mips_elf_relax_section): Likewise.
(_bfd_mips16_elf_reloc_unshuffle): Rename to...
(_bfd_mips_elf_reloc_unshuffle): ... this. Handle microMIPS
ASE.
(_bfd_mips16_elf_reloc_shuffle): Rename to...
(_bfd_mips_elf_reloc_shuffle): ... this. Handle microMIPS ASE.
(gprel16_reloc_p): Handle microMIPS ASE.
(literal_reloc_p): New function.
* elf32-mips.c (elf_micromips_howto_table_rel): New variable.
(_bfd_mips_elf32_gprel16_reloc): Handle microMIPS ASE.
(mips16_gprel_reloc): Update for _bfd_mips_elf_reloc_unshuffle
and _bfd_mips_elf_reloc_shuffle changes.
(mips_elf_gprel32_reloc): Update comment.
(micromips_reloc_map): New variable.
(bfd_elf32_bfd_reloc_type_lookup): Handle microMIPS ASE.
(mips_elf32_rtype_to_howto): Likewise.
(mips_info_to_howto_rel): Likewise.
(bfd_elf32_bfd_is_target_special_symbol): Define.
(bfd_elf32_bfd_relax_section): Likewise.
* elf64-mips.c (micromips_elf64_howto_table_rel): New variable.
(micromips_elf64_howto_table_rela): Likewise.
(mips16_gprel_reloc): Update for _bfd_mips_elf_reloc_unshuffle
and _bfd_mips_elf_reloc_shuffle changes.
(micromips_reloc_map): Likewise.
(bfd_elf64_bfd_reloc_type_lookup): Handle microMIPS ASE.
(bfd_elf64_bfd_reloc_name_lookup): Likewise.
(mips_elf64_rtype_to_howto): Likewise.
(bfd_elf64_bfd_is_target_special_symbol): Define.
* elfn32-mips.c (elf_micromips_howto_table_rel): New variable.
(elf_micromips_howto_table_rela): Likewise.
(mips16_gprel_reloc): Update for _bfd_mips_elf_reloc_unshuffle
and _bfd_mips_elf_reloc_shuffle changes.
(micromips_reloc_map): Likewise.
(bfd_elf32_bfd_reloc_type_lookup): Handle microMIPS ASE.
(bfd_elf32_bfd_reloc_name_lookup): Likewise.
(mips_elf_n32_rtype_to_howto): Likewise.
(bfd_elf32_bfd_is_target_special_symbol): Define.
* elfxx-mips.c (LA25_LUI_MICROMIPS_1): New macro.
(LA25_LUI_MICROMIPS_2): Likewise.
(LA25_J_MICROMIPS_1, LA25_J_MICROMIPS_2): Likewise.
(LA25_ADDIU_MICROMIPS_1, LA25_ADDIU_MICROMIPS_2): Likewise.
(TLS_RELOC_P): Handle microMIPS ASE.
(mips_elf_create_stub_symbol): Adjust value of stub symbol if
target is a microMIPS function.
(micromips_reloc_p): New function.
(micromips_reloc_shuffle_p): Likewise.
(got16_reloc_p, call16_reloc_p): Handle microMIPS ASE.
(got_disp_reloc_p, got_page_reloc_p): New functions.
(got_ofst_reloc_p): Likewise.
(got_hi16_reloc_p, got_lo16_reloc_p): Likewise.
(call_hi16_reloc_p, call_lo16_reloc_p): Likewise.
(hi16_reloc_p, lo16_reloc_p, jal_reloc_p): Handle microMIPS ASE.
(micromips_branch_reloc_p): New function.
(tls_gd_reloc_p, tls_ldm_reloc_p): Likewise.
(tls_gottprel_reloc_p): Likewise.
(_bfd_mips16_elf_reloc_unshuffle): Rename to...
(_bfd_mips_elf_reloc_unshuffle): ... this. Handle microMIPS
ASE.
(_bfd_mips16_elf_reloc_shuffle): Rename to...
(_bfd_mips_elf_reloc_shuffle): ... this. Handle microMIPS ASE.
(_bfd_mips_elf_lo16_reloc): Handle microMIPS ASE.
(mips_tls_got_index, mips_elf_got_page): Likewise.
(mips_elf_create_local_got_entry): Likewise.
(mips_elf_relocation_needs_la25_stub): Likewise.
(mips_elf_calculate_relocation): Likewise.
(mips_elf_perform_relocation): Likewise.
(_bfd_mips_elf_symbol_processing): Likewise.
(_bfd_mips_elf_add_symbol_hook): Likewise.
(_bfd_mips_elf_link_output_symbol_hook): Likewise.
(mips_elf_add_lo16_rel_addend): Likewise.
(_bfd_mips_elf_check_relocs): Likewise.
(mips_elf_adjust_addend): Likewise.
(_bfd_mips_elf_relocate_section): Likewise.
(mips_elf_create_la25_stub): Likewise.
(_bfd_mips_vxworks_finish_dynamic_symbol): Likewise.
(_bfd_mips_elf_gc_sweep_hook): Likewise.
(_bfd_mips_elf_is_target_special_symbol): New function.
(mips_elf_relax_delete_bytes): Likewise.
(opcode_descriptor): New structure.
(RA): New macro.
(OP32_SREG, OP32_TREG, OP16_VALID_REG): Likewise.
(b_insns_32, bc_insn_32, bz_insn_32, bzal_insn_32): New variables.
(beq_insn_32): Likewise.
(b_insn_16, bz_insn_16): New variables.
(BZC32_REG_FIELD): New macro.
(bz_rs_insns_32, bz_rt_insns_32): New variables.
(bzc_insns_32, bz_insns_16):Likewise.
(BZ16_REG, BZ16_REG_FIELD): New macros.
(jal_insn_32_bd16, jal_insn_32_bd32): New variables.
(jal_x_insn_32_bd32): Likewise.
(j_insn_32, jalr_insn_32): Likewise.
(ds_insns_32_bd16, ds_insns_32_bd32): Likewise.
(jalr_insn_16_bd16, jalr_insn_16_bd32, jr_insn_16): Likewise.
(JR16_REG): New macro.
(ds_insns_16_bd16): New variable.
(lui_insn): Likewise.
(addiu_insn, addiupc_insn): Likewise.
(ADDIUPC_REG_FIELD): New macro.
(MOVE32_RD, MOVE32_RS): Likewise.
(MOVE16_RD_FIELD, MOVE16_RS_FIELD): Likewise.
(move_insns_32, move_insns_16): New variables.
(nop_insn_32, nop_insn_16): Likewise.
(MATCH): New macro.
(find_match): New function.
(check_br16_dslot, check_br32_dslot): Likewise.
(check_br16, check_br32): Likewise.
(IS_BITSIZE): New macro.
(_bfd_mips_elf_relax_section): New function.
(_bfd_mips_elf_merge_private_bfd_data): Disallow linking MIPS16
and microMIPS modules together.
(_bfd_mips_elf_print_private_bfd_data): Handle microMIPS ASE.
* reloc.c (BFD_RELOC_MICROMIPS_7_PCREL_S1): New relocation.
(BFD_RELOC_MICROMIPS_10_PCREL_S1): Likewise.
(BFD_RELOC_MICROMIPS_16_PCREL_S1): Likewise.
(BFD_RELOC_MICROMIPS_GPREL16): Likewise.
(BFD_RELOC_MICROMIPS_JMP, BFD_RELOC_MICROMIPS_HI16): Likewise.
(BFD_RELOC_MICROMIPS_HI16_S): Likewise.
(BFD_RELOC_MICROMIPS_LO16): Likewise.
(BFD_RELOC_MICROMIPS_LITERAL): Likewise.
(BFD_RELOC_MICROMIPS_GOT16): Likewise.
(BFD_RELOC_MICROMIPS_CALL16): Likewise.
(BFD_RELOC_MICROMIPS_GOT_HI16): Likewise.
(BFD_RELOC_MICROMIPS_GOT_LO16): Likewise.
(BFD_RELOC_MICROMIPS_CALL_HI16): Likewise.
(BFD_RELOC_MICROMIPS_CALL_LO16): Likewise.
(BFD_RELOC_MICROMIPS_SUB): Likewise.
(BFD_RELOC_MICROMIPS_GOT_PAGE): Likewise.
(BFD_RELOC_MICROMIPS_GOT_OFST): Likewise.
(BFD_RELOC_MICROMIPS_GOT_DISP): Likewise.
(BFD_RELOC_MICROMIPS_HIGHEST): Likewise.
(BFD_RELOC_MICROMIPS_HIGHER): Likewise.
(BFD_RELOC_MICROMIPS_SCN_DISP): Likewise.
(BFD_RELOC_MICROMIPS_JALR): Likewise.
(BFD_RELOC_MICROMIPS_TLS_GD): Likewise.
(BFD_RELOC_MICROMIPS_TLS_LDM): Likewise.
(BFD_RELOC_MICROMIPS_TLS_DTPREL_HI16): Likewise.
(BFD_RELOC_MICROMIPS_TLS_DTPREL_LO16): Likewise.
(BFD_RELOC_MICROMIPS_TLS_GOTTPREL): Likewise.
(BFD_RELOC_MICROMIPS_TLS_TPREL_HI16): Likewise.
(BFD_RELOC_MICROMIPS_TLS_TPREL_LO16): Likewise.
* bfd-in2.h: Regenerate.
* libbfd.h: Regenerate.
binutils/
2011-02-25 Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* readelf.c (get_machine_flags): Handle microMIPS ASE.
(get_mips_symbol_other): Likewise.
gas/
2011-02-25 Maciej W. Rozycki <macro@codesourcery.com>
Chao-ying Fu <fu@mips.com>
* config/tc-mips.h (mips_segment_info): Add one bit for
microMIPS.
(TC_LABEL_IS_LOCAL): New macro.
(mips_label_is_local): New prototype.
* config/tc-mips.c (S0, S7): New macros.
(emit_branch_likely_macro): New variable.
(mips_set_options): Add micromips.
(mips_opts): Initialise micromips to -1.
(file_ase_micromips): New variable.
(CPU_HAS_MICROMIPS): New macro.
(hilo_interlocks): Set for microMIPS too.
(gpr_interlocks): Likewise.
(cop_interlocks): Likewise.
(cop_mem_interlocks): Likewise.
(HAVE_CODE_COMPRESSION): New macro.
(micromips_op_hash): New variable.
(micromips_nop16_insn, micromips_nop32_insn): New variables.
(NOP_INSN): Handle microMIPS ASE.
(mips32_to_micromips_reg_b_map): New macro.
(mips32_to_micromips_reg_c_map): Likewise.
(mips32_to_micromips_reg_d_map): Likewise.
(mips32_to_micromips_reg_e_map): Likewise.
(mips32_to_micromips_reg_f_map): Likewise.
(mips32_to_micromips_reg_g_map): Likewise.
(mips32_to_micromips_reg_l_map): Likewise.
(mips32_to_micromips_reg_n_map): Likewise.
(mips32_to_micromips_reg_h_map): New variable.
(mips32_to_micromips_reg_m_map): Likewise.
(mips32_to_micromips_reg_q_map): Likewise.
(micromips_to_32_reg_h_map): New variable.
(micromips_to_32_reg_i_map): Likewise.
(micromips_to_32_reg_m_map): Likewise.
(micromips_to_32_reg_q_map): Likewise.
(micromips_to_32_reg_b_map): New macro.
(micromips_to_32_reg_c_map): Likewise.
(micromips_to_32_reg_d_map): Likewise.
(micromips_to_32_reg_e_map): Likewise.
(micromips_to_32_reg_f_map): Likewise.
(micromips_to_32_reg_g_map): Likewise.
(micromips_to_32_reg_l_map): Likewise.
(micromips_to_32_reg_n_map): Likewise.
(micromips_imm_b_map, micromips_imm_c_map): New macros.
(RELAX_DELAY_SLOT_16BIT): New macro.
(RELAX_DELAY_SLOT_SIZE_FIRST): Likewise.
(RELAX_DELAY_SLOT_SIZE_SECOND): Likewise.
(RELAX_MICROMIPS_ENCODE, RELAX_MICROMIPS_P): New macros.
(RELAX_MICROMIPS_TYPE, RELAX_MICROMIPS_AT): Likewise.
(RELAX_MICROMIPS_U16BIT, RELAX_MICROMIPS_UNCOND): Likewise.
(RELAX_MICROMIPS_COMPACT, RELAX_MICROMIPS_LINK): Likewise.
(RELAX_MICROMIPS_RELAX32, RELAX_MICROMIPS_TOOFAR16): Likewise.
(RELAX_MICROMIPS_MARK_TOOFAR16): Likewise.
(RELAX_MICROMIPS_CLEAR_TOOFAR16): Likewise.
(RELAX_MICROMIPS_TOOFAR32): Likewise.
(RELAX_MICROMIPS_MARK_TOOFAR32): Likewise.
(RELAX_MICROMIPS_CLEAR_TOOFAR32): Likewise.
(INSERT_OPERAND, EXTRACT_OPERAND): Handle microMIPS ASE.
(mips_macro_warning): Add delay_slot_16bit_p, delay_slot_32bit_p,
fsize and insns.
(mips_mark_labels): New function.
(mips16_small, mips16_ext): Remove variables, replacing with...
(forced_insn_size): ... this.
(append_insn, mips16_ip): Update accordingly.
(micromips_insn_length): New function.
(insn_length): Return the length of microMIPS instructions.
(mips_record_mips16_mode): Rename to...
(mips_record_compressed_mode): ... this. Handle microMIPS ASE.
(install_insn): Handle microMIPS ASE.
(reglist_lookup): New function.
(is_size_valid, is_delay_slot_valid): Likewise.
(md_begin): Handle microMIPS ASE.
(md_assemble): Likewise. Update for append_insn interface
change.
(micromips_reloc_p): New function.
(got16_reloc_p): Handle microMIPS ASE.
(hi16_reloc_p): Likewise.
(lo16_reloc_p): Likewise.
(matching_lo_reloc): Likewise.
(insn_uses_reg, reg_needs_delay): Likewise.
(mips_move_labels): Likewise.
(mips16_mark_labels): Rename to...
(mips_compressed_mark_labels): ... this. Handle microMIPS ASE.
(insns_between, nops_for_vr4130, nops_for_insn): Likewise.
(fix_loongson2f_nop, fix_loongson2f_jump): Likewise.
(MICROMIPS_LABEL_CHAR): New macro.
(micromips_target_label, micromips_target_name): New variables.
(micromips_label_name, micromips_label_expr): New functions.
(micromips_label_inc, micromips_add_label): Likewise.
(mips_label_is_local): Likewise.
(micromips_map_reloc): Likewise.
(append_insn): Add expansionp argument. Handle microMIPS ASE.
(start_noreorder, end_noreorder): Handle microMIPS ASE.
(macro_start, macro_warning, macro_end): Likewise.
(brk_fmt, cop12_fmt, jalr_fmt, lui_fmt): New variables.
(mem12_fmt, mfhl_fmt, shft_fmt, trap_fmt): Likewise.
(BRK_FMT, COP12_FMT, JALR_FMT, LUI_FMT): New macros.
(MEM12_FMT, MFHL_FMT, SHFT_FMT, TRAP_FMT): Likewise.
(macro_build): Handle microMIPS ASE. Update for append_insn
interface change.
(mips16_macro_build): Update for append_insn interface change.
(macro_build_jalr): Handle microMIPS ASE.
(macro_build_lui): Likewise. Simplify.
(load_register): Handle microMIPS ASE.
(load_address): Likewise.
(move_register): Likewise.
(macro_build_branch_likely): New function.
(macro_build_branch_ccl): Likewise.
(macro_build_branch_rs): Likewise.
(macro_build_branch_rsrt): Likewise.
(macro): Handle microMIPS ASE.
(validate_micromips_insn): New function.
(expr_const_in_range): Likewise.
(mips_ip): Handle microMIPS ASE.
(options): Add OPTION_MICROMIPS and OPTION_NO_MICROMIPS.
(md_longopts): Add mmicromips and mno-micromips.
(md_parse_option): Handle OPTION_MICROMIPS and
OPTION_NO_MICROMIPS.
(mips_after_parse_args): Handle microMIPS ASE.
(md_pcrel_from): Handle microMIPS relocations.
(mips_force_relocation): Likewise.
(md_apply_fix): Likewise.
(mips_align): Handle microMIPS ASE.
(s_mipsset): Likewise.
(s_cpload, s_cpsetup, s_cpreturn): Use relocation wrappers.
(s_dtprel_internal): Likewise.
(s_gpword, s_gpdword): Likewise.
(s_insn): Handle microMIPS ASE.
(s_mips_stab): Likewise.
(relaxed_micromips_32bit_branch_length): New function.
(relaxed_micromips_16bit_branch_length): New function.
(md_estimate_size_before_relax): Handle microMIPS ASE.
(mips_fix_adjustable): Likewise.
(tc_gen_reloc): Handle microMIPS relocations.
(mips_relax_frag): Handle microMIPS ASE.
(md_convert_frag): Likewise.
(mips_frob_file_after_relocs): Likewise.
(mips_elf_final_processing): Likewise.
(mips_nop_opcode): Likewise.
(mips_handle_align): Likewise.
(md_show_usage): Handle microMIPS options.
* symbols.c (TC_LABEL_IS_LOCAL): New macro.
(S_IS_LOCAL): Add a TC_LABEL_IS_LOCAL check.
* doc/as.texinfo (Target MIPS options): Add -mmicromips and
-mno-micromips.
(-mmicromips, -mno-micromips): New options.
* doc/c-mips.texi (-mmicromips, -mno-micromips): New options.
(MIPS ISA): Document .set micromips and .set nomicromips.
(MIPS insn): Update for microMIPS support.
gas/testsuite/
2011-02-25 Maciej W. Rozycki <macro@codesourcery.com>
Chao-ying Fu <fu@mips.com>
* gas/mips/micromips.d: New test.
* gas/mips/micromips-branch-delay.d: Likewise.
* gas/mips/micromips-branch-relax.d: Likewise.
* gas/mips/micromips-branch-relax-pic.d: Likewise.
* gas/mips/micromips-size-1.d: Likewise.
* gas/mips/micromips-trap.d: Likewise.
* gas/mips/micromips.l: New stderr output.
* gas/mips/micromips-branch-delay.l: Likewise.
* gas/mips/micromips-branch-relax.l: Likewise.
* gas/mips/micromips-branch-relax-pic.l: Likewise.
* gas/mips/micromips-size-0.l: New list test.
* gas/mips/micromips-size-1.l: New stderr output.
* gas/mips/micromips.s: New test source.
* gas/mips/micromips-branch-delay.s: Likewise.
* gas/mips/micromips-branch-relax.s: Likewise.
* gas/mips/micromips-size-0.s: Likewise.
* gas/mips/micromips-size-1.s: Likewise.
* gas/mips/mips.exp: Run the new tests.
* gas/mips/elf_ase_micromips.d: New test.
* gas/mips/elf_ase_micromips-2.d: Likewise.
* gas/mips/micromips@abs.d: Likewise.
* gas/mips/micromips@add.d: Likewise.
* gas/mips/micromips@alnv_ps-swap.d: Likewise.
* gas/mips/micromips@and.d: Likewise.
* gas/mips/micromips@beq.d: Likewise.
* gas/mips/micromips@bge.d: Likewise.
* gas/mips/micromips@bgeu.d: Likewise.
* gas/mips/micromips@blt.d: Likewise.
* gas/mips/micromips@bltu.d: Likewise.
* gas/mips/micromips@branch-likely.d: Likewise.
* gas/mips/micromips@branch-misc-1.d: Likewise.
* gas/mips/micromips@branch-misc-2-64.d: Likewise.
* gas/mips/micromips@branch-misc-2.d: Likewise.
* gas/mips/micromips@branch-misc-2pic-64.d: Likewise.
* gas/mips/micromips@branch-misc-2pic.d: Likewise.
* gas/mips/micromips@branch-misc-4-64.d: Likewise.
* gas/mips/micromips@branch-misc-4.d: Likewise.
* gas/mips/micromips@branch-self.d: Likewise.
* gas/mips/micromips@cache.d: Likewise.
* gas/mips/micromips@daddi.d: Likewise.
* gas/mips/micromips@dli.d: Likewise.
* gas/mips/micromips@elf-jal.d: Likewise.
* gas/mips/micromips@elf-rel2.d: Likewise.
* gas/mips/micromips@elf-rel4.d: Likewise.
* gas/mips/micromips@jal-svr4pic.d: Likewise.
* gas/mips/micromips@jal-svr4pic-noreorder.d: Likewise.
* gas/mips/micromips@lb-svr4pic-ilocks.d: Likewise.
* gas/mips/micromips@li.d: Likewise.
* gas/mips/micromips@loc-swap-dis.d: Likewise.
* gas/mips/micromips@loc-swap.d: Likewise.
* gas/mips/micromips@mips1-fp.d: Likewise.
* gas/mips/micromips@mips32-cp2.d: Likewise.
* gas/mips/micromips@mips32-imm.d: Likewise.
* gas/mips/micromips@mips32-sf32.d: Likewise.
* gas/mips/micromips@mips32.d: Likewise.
* gas/mips/micromips@mips32r2-cp2.d: Likewise.
* gas/mips/micromips@mips32r2-fp32.d: Likewise.
* gas/mips/micromips@mips32r2.d: Likewise.
* gas/mips/micromips@mips4-branch-likely.d: Likewise.
* gas/mips/micromips@mips4-fp.d: Likewise.
* gas/mips/micromips@mips4.d: Likewise.
* gas/mips/micromips@mips5.d: Likewise.
* gas/mips/micromips@mips64-cp2.d: Likewise.
* gas/mips/micromips@mips64.d: Likewise.
* gas/mips/micromips@mips64r2.d: Likewise.
* gas/mips/micromips@pref.d: Likewise.
* gas/mips/micromips@relax-at.d: Likewise.
* gas/mips/micromips@relax.d: Likewise.
* gas/mips/micromips@rol-hw.d: Likewise.
* gas/mips/micromips@uld2-eb.d: Likewise.
* gas/mips/micromips@uld2-el.d: Likewise.
* gas/mips/micromips@ulh2-eb.d: Likewise.
* gas/mips/micromips@ulh2-el.d: Likewise.
* gas/mips/micromips@ulw2-eb-ilocks.d: Likewise.
* gas/mips/micromips@ulw2-el-ilocks.d: Likewise.
* gas/mips/cache.d: Likewise.
* gas/mips/daddi.d: Likewise.
* gas/mips/mips32-imm.d: Likewise.
* gas/mips/pref.d: Likewise.
* gas/mips/elf-rel27.d: Handle microMIPS ASE.
* gas/mips/l_d.d: Likewise.
* gas/mips/l_d-n32.d: Likewise.
* gas/mips/l_d-n64.d: Likewise.
* gas/mips/ld.d: Likewise.
* gas/mips/ld-n32.d: Likewise.
* gas/mips/ld-n64.d: Likewise.
* gas/mips/s_d.d: Likewise.
* gas/mips/s_d-n32.d: Likewise.
* gas/mips/s_d-n64.d: Likewise.
* gas/mips/sd.d: Likewise.
* gas/mips/sd-n32.d: Likewise.
* gas/mips/sd-n64.d: Likewise.
* gas/mips/mips32.d: Update immediates.
* gas/mips/micromips@mips32-cp2.s: New test source.
* gas/mips/micromips@mips32-imm.s: Likewise.
* gas/mips/micromips@mips32r2-cp2.s: Likewise.
* gas/mips/micromips@mips64-cp2.s: Likewise.
* gas/mips/cache.s: Likewise.
* gas/mips/daddi.s: Likewise.
* gas/mips/mips32-imm.s: Likewise.
* gas/mips/elf-rel4.s: Handle microMIPS ASE.
* gas/mips/lb-pic.s: Likewise.
* gas/mips/ld.s: Likewise.
* gas/mips/mips32.s: Likewise.
* gas/mips/mips.exp: Add the micromips arch. Exclude mips16e
from micromips. Run mips32-imm.
* gas/mips/jal-mask-11.d: New test.
* gas/mips/jal-mask-12.d: Likewise.
* gas/mips/micromips@jal-mask-11.d: Likewise.
* gas/mips/jal-mask-1.s: Source for the new tests.
* gas/mips/jal-mask-21.d: New test.
* gas/mips/jal-mask-22.d: Likewise.
* gas/mips/micromips@jal-mask-12.d: Likewise.
* gas/mips/jal-mask-2.s: Source for the new tests.
* gas/mips/mips.exp: Run the new tests.
* gas/mips/mips16-e.d: Add --special-syms to `objdump'.
* gas/mips/tmips16-e.d: Likewise.
* gas/mips/and.s: Adjust padding.
* gas/mips/beq.s: Likewise.
* gas/mips/bge.s: Likewise.
* gas/mips/bgeu.s: Likewise.
* gas/mips/blt.s: Likewise.
* gas/mips/bltu.s: Likewise.
* gas/mips/branch-misc-2.s: Likewise.
* gas/mips/jal.s: Likewise.
* gas/mips/li.s: Likewise.
* gas/mips/mips4.s: Likewise.
* gas/mips/mips4-fp.s: Likewise.
* gas/mips/relax.s: Likewise.
* gas/mips/and.d: Update accordingly.
* gas/mips/elf-jal.d: Likewise.
* gas/mips/jal.d: Likewise.
* gas/mips/li.d: Likewise.
* gas/mips/relax-at.d: Likewise.
* gas/mips/relax.d: Likewise.
include/elf/
2011-02-25 Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* mips.h (R_MICROMIPS_min): New relocations.
(R_MICROMIPS_26_S1): Likewise.
(R_MICROMIPS_HI16, R_MICROMIPS_LO16): Likewise.
(R_MICROMIPS_GPREL16, R_MICROMIPS_LITERAL): Likewise.
(R_MICROMIPS_GOT16, R_MICROMIPS_PC7_S1): Likewise.
(R_MICROMIPS_PC10_S1, R_MICROMIPS_PC16_S1): Likewise.
(R_MICROMIPS_CALL16, R_MICROMIPS_GOT_DISP): Likewise.
(R_MICROMIPS_GOT_PAGE, R_MICROMIPS_GOT_OFST): Likewise.
(R_MICROMIPS_GOT_HI16, R_MICROMIPS_GOT_LO16): Likewise.
(R_MICROMIPS_SUB, R_MICROMIPS_HIGHER): Likewise.
(R_MICROMIPS_HIGHEST, R_MICROMIPS_CALL_HI16): Likewise.
(R_MICROMIPS_CALL_LO16, R_MICROMIPS_SCN_DISP): Likewise.
(R_MICROMIPS_JALR, R_MICROMIPS_HI0_LO16): Likewise.
(R_MICROMIPS_TLS_GD, R_MICROMIPS_TLS_LDM): Likewise.
(R_MICROMIPS_TLS_DTPREL_HI, R_MICROMIPS_TLS_DTPREL_LO): Likewise.
(R_MICROMIPS_TLS_GOTTPREL): Likewise.
(R_MICROMIPS_TLS_TPREL_HI16): Likewise.
(R_MICROMIPS_TLS_TPREL_LO16): Likewise.
(R_MICROMIPS_GPREL7_S2, R_MICROMIPS_PC23_S2): Likewise.
(R_MICROMIPS_max): Likewise.
(EF_MIPS_ARCH_ASE_MICROMIPS): New macro.
(STO_MIPS_ISA, STO_MIPS_FLAGS): Likewise.
(ELF_ST_IS_MIPS_PLT, ELF_ST_SET_MIPS_PLT): Likewise.
(STO_MICROMIPS): Likewise.
(ELF_ST_IS_MICROMIPS, ELF_ST_SET_MICROMIPS): Likewise.
(ELF_ST_IS_COMPRESSED): Likewise.
(STO_MIPS_PLT, STO_MIPS_PIC): Rework.
(ELF_ST_IS_MIPS_PIC, ELF_ST_SET_MIPS_PIC): Likewise.
(STO_MIPS16, ELF_ST_IS_MIPS16, ELF_ST_SET_MIPS16): Likewise.
include/opcode/
2011-02-25 Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* mips.h (OP_MASK_EXTLSB, OP_SH_EXTLSB): New macros.
(OP_MASK_STYPE, OP_SH_STYPE): Likewise.
(OP_MASK_CODE10, OP_SH_CODE10): Likewise.
(OP_MASK_TRAP, OP_SH_TRAP): Likewise.
(OP_MASK_OFFSET12, OP_SH_OFFSET12): Likewise.
(OP_MASK_OFFSET10, OP_SH_OFFSET10): Likewise.
(OP_MASK_RS3, OP_SH_RS3): Likewise.
(OP_MASK_MB, OP_SH_MB, OP_MASK_MC, OP_SH_MC): Likewise.
(OP_MASK_MD, OP_SH_MD, OP_MASK_ME, OP_SH_ME): Likewise.
(OP_MASK_MF, OP_SH_MF, OP_MASK_MG, OP_SH_MG): Likewise.
(OP_MASK_MJ, OP_SH_MJ, OP_MASK_ML, OP_SH_ML): Likewise.
(OP_MASK_MP, OP_SH_MP, OP_MASK_MQ, OP_SH_MQ): Likewise.
(OP_MASK_IMMA, OP_SH_IMMA, OP_MASK_IMMB, OP_SH_IMMB): Likewise.
(OP_MASK_IMMC, OP_SH_IMMC, OP_MASK_IMMF, OP_SH_IMMF): Likewise.
(OP_MASK_IMMG, OP_SH_IMMG, OP_MASK_IMMH, OP_SH_IMMH): Likewise.
(OP_MASK_IMMI, OP_SH_IMMI, OP_MASK_IMMJ, OP_SH_IMMJ): Likewise.
(OP_MASK_IMML, OP_SH_IMML, OP_MASK_IMMM, OP_SH_IMMM): Likewise.
(OP_MASK_IMMN, OP_SH_IMMN, OP_MASK_IMMO, OP_SH_IMMO): Likewise.
(OP_MASK_IMMP, OP_SH_IMMP, OP_MASK_IMMQ, OP_SH_IMMQ): Likewise.
(OP_MASK_IMMU, OP_SH_IMMU, OP_MASK_IMMW, OP_SH_IMMW): Likewise.
(OP_MASK_IMMX, OP_SH_IMMX, OP_MASK_IMMY, OP_SH_IMMY): Likewise.
(INSN_WRITE_GPR_S): New macro.
(INSN2_BRANCH_DELAY_16BIT, INSN2_BRANCH_DELAY_32BIT): Likewise.
(INSN2_READ_FPR_D): Likewise.
(INSN2_WRITE_GPR_MB, INSN2_READ_GPR_MC): Likewise.
(INSN2_MOD_GPR_MD, INSN2_READ_GPR_ME): Likewise.
(INSN2_WRITE_GPR_MF, INSN2_READ_GPR_MG): Likewise.
(INSN2_READ_GPR_MJ, INSN2_WRITE_GPR_MJ): Likewise.
(INSN2_READ_GPR_MP, INSN2_WRITE_GPR_MP): Likewise.
(INSN2_READ_GPR_MQ, INSN2_MOD_SP, INSN2_READ_GPR_31): Likewise.
(INSN2_READ_GP, INSN2_READ_PC): Likewise.
(INSN2_UNCOND_BRANCH, INSN2_COND_BRANCH): Likewise.
(INSN2_WRITE_GPR_MHI, INSN2_READ_GPR_MMN): Likewise.
(CPU_MICROMIPS): New macro.
(M_BC1FL, M_BC1TL, M_BC2FL, M_BC2TL): New enum values.
(M_BEQL, M_BGEZ, M_BGEZL, M_BGEZALL, M_BGTZ, M_BGTZL): Likewise.
(M_BLEZ, M_BLEZL, M_BLTZ, M_BLTZL, M_BLTZALL, M_BNEL): Likewise.
(M_CACHE_OB, M_JALS_1, M_JALS_2, M_JALS_A): Likewise.
(M_LDC2_OB, M_LDL_OB, M_LDM_AB, M_LDM_OB): Likewise.
(M_LDP_AB, M_LDP_OB, M_LDR_OB, M_LL_OB, M_LLD_OB): Likewise.
(M_LWC2_OB, M_LWL_OB, M_LWM_AB, M_LWM_OB): Likewise.
(M_LWP_AB, M_LWP_OB, M_LWR_OB): Likewise.
(M_LWU_OB, M_PREF_OB, M_SC_OB, M_SCD_OB): Likewise.
(M_SDC2_OB, M_SDL_OB, M_SDM_AB, M_SDM_OB): Likewise.
(M_SDP_AB, M_SDP_OB, M_SDR_OB): Likewise.
(M_SWC2_OB, M_SWL_OB, M_SWM_AB, M_SWM_OB): Likewise.
(M_SWP_AB, M_SWP_OB, M_SWR_OB): Likewise.
(MICROMIPSOP_MASK_MAJOR, MICROMIPSOP_SH_MAJOR): New macros.
(MICROMIPSOP_MASK_IMMEDIATE, MICROMIPSOP_SH_IMMEDIATE): Likewise.
(MICROMIPSOP_MASK_DELTA, MICROMIPSOP_SH_DELTA): Likewise.
(MICROMIPSOP_MASK_CODE10, MICROMIPSOP_SH_CODE10): Likewise.
(MICROMIPSOP_MASK_TRAP, MICROMIPSOP_SH_TRAP): Likewise.
(MICROMIPSOP_MASK_SHAMT, MICROMIPSOP_SH_SHAMT): Likewise.
(MICROMIPSOP_MASK_TARGET, MICROMIPSOP_SH_TARGET): Likewise.
(MICROMIPSOP_MASK_EXTLSB, MICROMIPSOP_SH_EXTLSB): Likewise.
(MICROMIPSOP_MASK_EXTMSBD, MICROMIPSOP_SH_EXTMSBD): Likewise.
(MICROMIPSOP_MASK_INSMSB, MICROMIPSOP_SH_INSMSB): Likewise.
(MICROMIPSOP_MASK_CODE, MICROMIPSOP_SH_CODE): Likewise.
(MICROMIPSOP_MASK_CODE2, MICROMIPSOP_SH_CODE2): Likewise.
(MICROMIPSOP_MASK_CACHE, MICROMIPSOP_SH_CACHE): Likewise.
(MICROMIPSOP_MASK_SEL, MICROMIPSOP_SH_SEL): Likewise.
(MICROMIPSOP_MASK_OFFSET12, MICROMIPSOP_SH_OFFSET12): Likewise.
(MICROMIPSOP_MASK_3BITPOS, MICROMIPSOP_SH_3BITPOS): Likewise.
(MICROMIPSOP_MASK_STYPE, MICROMIPSOP_SH_STYPE): Likewise.
(MICROMIPSOP_MASK_OFFSET10, MICROMIPSOP_SH_OFFSET10): Likewise.
(MICROMIPSOP_MASK_RS, MICROMIPSOP_SH_RS): Likewise.
(MICROMIPSOP_MASK_RT, MICROMIPSOP_SH_RT): Likewise.
(MICROMIPSOP_MASK_RD, MICROMIPSOP_SH_RD): Likewise.
(MICROMIPSOP_MASK_FS, MICROMIPSOP_SH_FS): Likewise.
(MICROMIPSOP_MASK_FT, MICROMIPSOP_SH_FT): Likewise.
(MICROMIPSOP_MASK_FD, MICROMIPSOP_SH_FD): Likewise.
(MICROMIPSOP_MASK_FR, MICROMIPSOP_SH_FR): Likewise.
(MICROMIPSOP_MASK_RS3, MICROMIPSOP_SH_RS3): Likewise.
(MICROMIPSOP_MASK_PREFX, MICROMIPSOP_SH_PREFX): Likewise.
(MICROMIPSOP_MASK_BCC, MICROMIPSOP_SH_BCC): Likewise.
(MICROMIPSOP_MASK_CCC, MICROMIPSOP_SH_CCC): Likewise.
(MICROMIPSOP_MASK_COPZ, MICROMIPSOP_SH_COPZ): Likewise.
(MICROMIPSOP_MASK_MB, MICROMIPSOP_SH_MB): Likewise.
(MICROMIPSOP_MASK_MC, MICROMIPSOP_SH_MC): Likewise.
(MICROMIPSOP_MASK_MD, MICROMIPSOP_SH_MD): Likewise.
(MICROMIPSOP_MASK_ME, MICROMIPSOP_SH_ME): Likewise.
(MICROMIPSOP_MASK_MF, MICROMIPSOP_SH_MF): Likewise.
(MICROMIPSOP_MASK_MG, MICROMIPSOP_SH_MG): Likewise.
(MICROMIPSOP_MASK_MH, MICROMIPSOP_SH_MH): Likewise.
(MICROMIPSOP_MASK_MI, MICROMIPSOP_SH_MI): Likewise.
(MICROMIPSOP_MASK_MJ, MICROMIPSOP_SH_MJ): Likewise.
(MICROMIPSOP_MASK_ML, MICROMIPSOP_SH_ML): Likewise.
(MICROMIPSOP_MASK_MM, MICROMIPSOP_SH_MM): Likewise.
(MICROMIPSOP_MASK_MN, MICROMIPSOP_SH_MN): Likewise.
(MICROMIPSOP_MASK_MP, MICROMIPSOP_SH_MP): Likewise.
(MICROMIPSOP_MASK_MQ, MICROMIPSOP_SH_MQ): Likewise.
(MICROMIPSOP_MASK_IMMA, MICROMIPSOP_SH_IMMA): Likewise.
(MICROMIPSOP_MASK_IMMB, MICROMIPSOP_SH_IMMB): Likewise.
(MICROMIPSOP_MASK_IMMC, MICROMIPSOP_SH_IMMC): Likewise.
(MICROMIPSOP_MASK_IMMD, MICROMIPSOP_SH_IMMD): Likewise.
(MICROMIPSOP_MASK_IMME, MICROMIPSOP_SH_IMME): Likewise.
(MICROMIPSOP_MASK_IMMF, MICROMIPSOP_SH_IMMF): Likewise.
(MICROMIPSOP_MASK_IMMG, MICROMIPSOP_SH_IMMG): Likewise.
(MICROMIPSOP_MASK_IMMH, MICROMIPSOP_SH_IMMH): Likewise.
(MICROMIPSOP_MASK_IMMI, MICROMIPSOP_SH_IMMI): Likewise.
(MICROMIPSOP_MASK_IMMJ, MICROMIPSOP_SH_IMMJ): Likewise.
(MICROMIPSOP_MASK_IMML, MICROMIPSOP_SH_IMML): Likewise.
(MICROMIPSOP_MASK_IMMM, MICROMIPSOP_SH_IMMM): Likewise.
(MICROMIPSOP_MASK_IMMN, MICROMIPSOP_SH_IMMN): Likewise.
(MICROMIPSOP_MASK_IMMO, MICROMIPSOP_SH_IMMO): Likewise.
(MICROMIPSOP_MASK_IMMP, MICROMIPSOP_SH_IMMP): Likewise.
(MICROMIPSOP_MASK_IMMQ, MICROMIPSOP_SH_IMMQ): Likewise.
(MICROMIPSOP_MASK_IMMU, MICROMIPSOP_SH_IMMU): Likewise.
(MICROMIPSOP_MASK_IMMW, MICROMIPSOP_SH_IMMW): Likewise.
(MICROMIPSOP_MASK_IMMX, MICROMIPSOP_SH_IMMX): Likewise.
(MICROMIPSOP_MASK_IMMY, MICROMIPSOP_SH_IMMY): Likewise.
(MICROMIPSOP_MASK_CODE, MICROMIPSOP_SH_CODE): Likewise.
(MICROMIPSOP_MASK_CODE2, MICROMIPSOP_SH_CODE2): Likewise.
(MICROMIPSOP_MASK_CACHE, MICROMIPSOP_SH_CACHE): Likewise.
(MICROMIPSOP_MASK_CODE20, MICROMIPSOP_SH_CODE20): Likewise.
(MICROMIPSOP_MASK_PERFREG, MICROMIPSOP_SH_PERFREG): Likewise.
(MICROMIPSOP_MASK_CODE19, MICROMIPSOP_SH_CODE19): Likewise.
(MICROMIPSOP_MASK_ALN, MICROMIPSOP_SH_ALN): Likewise.
(MICROMIPSOP_MASK_VECBYTE, MICROMIPSOP_SH_VECBYTE): Likewise.
(MICROMIPSOP_MASK_VECALIGN, MICROMIPSOP_SH_VECALIGN): Likewise.
(MICROMIPSOP_MASK_DSPACC, MICROMIPSOP_SH_DSPACC): Likewise.
(MICROMIPSOP_MASK_DSPACC_S, MICROMIPSOP_SH_DSPACC_S): Likewise.
(MICROMIPSOP_MASK_DSPSFT, MICROMIPSOP_SH_DSPSFT): Likewise.
(MICROMIPSOP_MASK_DSPSFT_7, MICROMIPSOP_SH_DSPSFT_7): Likewise.
(MICROMIPSOP_MASK_SA3, MICROMIPSOP_SH_SA3): Likewise.
(MICROMIPSOP_MASK_SA4, MICROMIPSOP_SH_SA4): Likewise.
(MICROMIPSOP_MASK_IMM8, MICROMIPSOP_SH_IMM8): Likewise.
(MICROMIPSOP_MASK_IMM10, MICROMIPSOP_SH_IMM10): Likewise.
(MICROMIPSOP_MASK_WRDSP, MICROMIPSOP_SH_WRDSP): Likewise.
(MICROMIPSOP_MASK_RDDSP, MICROMIPSOP_SH_RDDSP): Likewise.
(MICROMIPSOP_MASK_BP, MICROMIPSOP_SH_BP): Likewise.
(MICROMIPSOP_MASK_MT_U, MICROMIPSOP_SH_MT_U): Likewise.
(MICROMIPSOP_MASK_MT_H, MICROMIPSOP_SH_MT_H): Likewise.
(MICROMIPSOP_MASK_MTACC_T, MICROMIPSOP_SH_MTACC_T): Likewise.
(MICROMIPSOP_MASK_MTACC_D, MICROMIPSOP_SH_MTACC_D): Likewise.
(MICROMIPSOP_MASK_BBITIND, MICROMIPSOP_SH_BBITIND): Likewise.
(MICROMIPSOP_MASK_CINSPOS, MICROMIPSOP_SH_CINSPOS): Likewise.
(MICROMIPSOP_MASK_CINSLM1, MICROMIPSOP_SH_CINSLM1): Likewise.
(MICROMIPSOP_MASK_SEQI, MICROMIPSOP_SH_SEQI): Likewise.
(micromips_opcodes): New declaration.
(bfd_micromips_num_opcodes): Likewise.
ld/testsuite/
2011-02-25 Catherine Moore <clm@codesourcery.com>
Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* lib/ld-lib.exp (run_dump_test): Support distinct assembler
flags for the same source named multiple times.
* ld-mips-elf/jalx-1.s: New test source.
* ld-mips-elf/jalx-1.d: New test output.
* ld-mips-elf/jalx-1.ld: New test linker script.
* ld-mips-elf/jalx-2-main.s: New test source.
* ld-mips-elf/jalx-2-ex.s: Likewise.
* ld-mips-elf/jalx-2-printf.s: Likewise.
* ld-mips-elf/jalx-2.dd: New test output.
* ld-mips-elf/jalx-2.ld: New test linker script.
* ld-mips-elf/mips16-and-micromips.d: New test.
* ld-mips-elf/mips-elf.exp: Run the new tests
opcodes/
2011-02-25 Chao-ying Fu <fu@mips.com>
Maciej W. Rozycki <macro@codesourcery.com>
* micromips-opc.c: New file.
* mips-dis.c (micromips_to_32_reg_b_map): New array.
(micromips_to_32_reg_c_map, micromips_to_32_reg_d_map): Likewise.
(micromips_to_32_reg_e_map, micromips_to_32_reg_f_map): Likewise.
(micromips_to_32_reg_g_map, micromips_to_32_reg_l_map): Likewise.
(micromips_to_32_reg_q_map): Likewise.
(micromips_imm_b_map, micromips_imm_c_map): Likewise.
(micromips_ase): New variable.
(is_micromips): New function.
(set_default_mips_dis_options): Handle microMIPS ASE.
(print_insn_micromips): New function.
(is_compressed_mode_p): Likewise.
(_print_insn_mips): Handle microMIPS instructions.
* Makefile.am (CFILES): Add micromips-opc.c.
* configure.in (bfd_mips_arch): Add micromips-opc.lo.
* Makefile.in: Regenerate.
* configure: Regenerate.
* mips-dis.c (micromips_to_32_reg_h_map): New variable.
(micromips_to_32_reg_i_map): Likewise.
(micromips_to_32_reg_m_map): Likewise.
(micromips_to_32_reg_n_map): New macro.
[-- Attachment #2: Type: APPLICATION/octet-stream, Size: 157623 bytes --]
[-- Attachment #3: Type: APPLICATION/octet-stream, Size: 36198 bytes --]
[-- Attachment #4: Type: APPLICATION/octet-stream, Size: 2047 bytes --]
[-- Attachment #5: Type: APPLICATION/octet-stream, Size: 3116 bytes --]
[-- Attachment #6: Type: APPLICATION/octet-stream, Size: 7589 bytes --]
[-- Attachment #7: Type: APPLICATION/octet-stream, Size: 4079 bytes --]
[-- Attachment #8: Type: APPLICATION/octet-stream, Size: 8309 bytes --]
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2011-02-21 15:35 ` Maciej W. Rozycki
` (2 preceding siblings ...)
2011-02-26 0:00 ` Maciej W. Rozycki
@ 2011-02-26 11:36 ` Richard Sandiford
2011-07-26 14:00 ` Maciej W. Rozycki
3 siblings, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2011-02-26 11:36 UTC (permalink / raw)
To: Maciej W. Rozycki
Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers,
Nathan Froyd
Thanks for the updates. I'll try to go through the patches in the next
couple of weeks (maybe later this weekend).
"Maciej W. Rozycki" <macro@codesourcery.com> writes:
>> "Maciej W. Rozycki" <macro@codesourcery.com> writes:
>> >
>> > Well, if we have code like this:
>> >
>> > branch ...
>> > LUI ...
>> > insn [...]
>> >
>> > (where for the purpose of this consideration BRANCH may also be a jump)
>> > then LUI cannot be entirely deleted and INSN moved into the slot of BRANCH
>> > no matter if INSN is a branch or an computational instruction. All we can
>> > do in this case is to see if there is a corresponding BRANCHC instruction
>> > and use it to swap BRANCH with and then delete the LUI if so, or otherwise
>> > shrink the LUI to a 16-bit NOP if BRANCH permits or can be swapped with
>> > BRANCHS to permit a 16-bit delay-slot instruction. If neither is
>> > possible, then the LUI is merely substituted with a 32-bit NOP (although
>> > the effect is purely cosmetical in this case; perhaps we should just back
>> > out).
>>
>> Yeah, I see your point. I was thinking that the code claims to "know"
>> that the LUI and "insn" are both part of the same load address. So if
>> the branch was taken, the target of the LUI ought to be dead. However,
>> I agree that (even though the code does seem to assume that to some extent)
>> the assumption is wrong.
>>
>> E.g. you could have:
>>
>> beqz $2,1f
>> lui $4,%hi(foo) <-- A
>>
>> addiu $4,$4,%lo(foo) <-- B
>> ...
>> jr $31
>> 2: ...
>> lui $4,%hi(foo) <-- C
>> ...
>> 1: addiu $4,$4,%lo(foo) <-- D
>>
>> In this case, the LO16 reloc for D might follow the HI16 reloc for C,
>> and the LO16 reloc for B might follow the HI16 reloc for A. AIUI, we'd
>> consider relaxing A/B but not C/D. In this case, turning A into a NOP
>> is wrong, because $4 is still live at D. If you agree then...
>>
>> > Also with the recent update to LUI relaxation code I think we should
>> > simply disallow the optimisation if a LUI is in a delay slot of an
>> > unconditional branch -- we have no way to verify the corresponding LO16
>> > reloc really belongs to this LUI instruction in that case. This will let
>> > us simplify code (which has become a little bit hairy by now IMO) a little
>> > bit I would guess. [FIXME]
>>
>> ...maybe it would be simpler to drop the optimisation if the LUI is any
>> kind of delay slot. I think this would simply the code, and I don't think
>> we'd then need to check for branch relocs. We'd just have *_norel-like
>> functions (although not called that any more) to check for every kind
>> of branch.
>
> I have implemented these changes now, dropping the unsafe part of
> optimisation for the scenario you have listed. I still have two concerns
> about this optimisation, but the optional nature of linker relaxation
> makes them reasonably unimportant IMO:
>
> 1. The resulting change of alignment may cause the linker produce bad code
> or abort the process if microMIPS and standard MIPS code is mixed in
> one object file and the latter turns out to become unaligned, e.g.
>
> .set micromips
> .set noreorder
> .align 2
> .globl foo
> .ent foo
> foo:
> beqz32 $4, 0f
> nop16
> 0:
> jalx bar
> nop
> .end foo
>
> .set nomicromips
> .align 2
> .globl bar
> .ent bar
> bar:
> nop
> .end bar
>
> The piece above will fail to link, because BEQZ will be converted to
> a BEQZC and the 16-bit NOP from its delay slot taken out. As a result
> bar() will become misaligned and the JALX will not be allowed. If
> there was no JALX, then linking might succeed if there were only
> indirect calls to bar(), but the function would not be properly aligned
> for standard MIPS execution.
>
> 2. Broken code is produced for cases like this:
>
> .set noreorder
> lui $4, 0x1234
> lui $2, %hi(foo)
> bnez $3, 0f
> addiu $2, %lo(foo)
> ...
>
> lui $4, %hi(foo)
> 0:
> jal bar
> addiu $4, %lo(foo)
>
> where the resulting code:
>
> .set noreorder
> lui $4, 0x1234
> bnez $3, 0f
> addiu $2, $pc, foo - .
> ...
>
> 0:
> jal bar
> addiu $4, $pc, foo - .
>
> obviously not being the same. Such usage of HI16/LO16 relocations is
> non-standard, but not disallowed. OTOH searching the symbol tables for
> the label (we could disable this relaxation if there's one at the
> instruction a LO16 relocation is against) is expensive.
>
> What do you think? [FIXME]
I agree that these are minor. At least with (1) we'll get an error
rather than silent wrong code, and like you say, if someone hits that error,
they can simply stop using relaxation.
I think it's fair for us to say that (2) is disallowed if you want to
use linker optimisations.
>> > + /* Whether we are assembling for the mipsMIPS processor. 0 if we are
>> > + not, 1 if we are, and -1 if the value has not been initialized.
>> > + Changed by `.set micromips' and `.set nomicromips', and the -mmicromips
>> > + and -mno-micromips command line options, and the default CPU. */
>> > + int micromips;
>>
>> Blind cut-&-paste. "microMIPS ASE".
>>
>> Let's leave the -1 case and:
>>
>> > +/* Return true if the given CPU supports microMIPS. */
>> > +#define CPU_HAS_MICROMIPS(cpu) 0
>>
>> out. I think the CPU_HAS_MIPS16 stuff is derived from the original LSI
>> TinyRisc support and wouldn't be used for ASEs.
>
> The microMIPS ASE provides for processors that do not support the
> standard MIPS instruction set. These I think should default to the
> microMIPS mode. I suspect someone will eventually implement such a
> processor as since we've got this code implemented here already I'd like
> to leave it as a placeholder. I think it's not much of a burden, is it?
Oh no, it wasn't any sense of burden that bothered me. It was more
the talk of "the microMIPS processor". "The MIPS16 processor" made
sense when the support was first added, but plain "microMIPS" makes
more sense here. (Or, reading further on, I suppose you won't agree.
Something other than "processor" though, if you want to treat
"microMIPS" as an adjective.)
I just thought that, if this was dead code, we might as well just
remove it rather than quibble about wording. Given what you say about
microMIPS-only processors being possible though, please just change the
comment instead.
>> > +#define RELAX_MICROMIPS_ENCODE(type, is_16bit, uncond, link, toofar) \
>> > + (0x40000000 \
>> > + | ((type) & 0xff) \
>> > + | ((is_16bit) ? 0x100 : 0) \
>> > + | ((uncond) ? 0x200 : 0) \
>> > + | ((link) ? 0x400 : 0) \
>> > + | ((toofar) ? 0x800 : 0))
>> > +#define RELAX_MICROMIPS_P(i) (((i) & 0xc0000000) == 0x40000000)
>> > +#define RELAX_MICROMIPS_TYPE(i) ((i) & 0xff)
>> > +#define RELAX_MICROMIPS_USER_16BIT(i) (((i) & 0x100) != 0)
>> > +#define RELAX_MICROMIPS_UNCOND(i) (((i) & 0x200) != 0)
>> > +#define RELAX_MICROMIPS_LINK(i) (((i) & 0x400) != 0)
>> > +#define RELAX_MICROMIPS_TOOFAR(i) (((i) & 0x800) != 0)
>> > +#define RELAX_MICROMIPS_MARK_TOOFAR(i) ((i) | 0x800)
>> > +#define RELAX_MICROMIPS_CLEAR_TOOFAR(i) ((i) & ~0x800)
>>
>> Is there a need to create variant frags when the user has explicitly
>> specified the instruction size? I wouldn't have expected any relaxation
>> to be necessary in that case, and it looks like the relaxation code does
>> indeed return 2 whenever USER_16BIT is true.
>
> I suspect this has been copied over from MIPS16 code.
> RELAX_MIPS16_USER_SMALL seems to be used in a similar fashion. Do you
> happen to know for sure why it has been implemented this way for MIPS16
> assembly?
Nope :-)
> My suspicion is we want to keep the relocation until the final
> relaxation so that if the final value turns out to fit afterwards (but not
> until then) in the forced-truncated immediate field of the instruction
> nothing is lost.
But that's true of all fixups, and should already be handled correctly.
E.g. if you had microMIPS code embedded in a larger MIPS function, you
might have normal MIPS branches that cross relaxable microMIPS instructions.
The same consideration would apply then, even if branch relaxation
wasn't enabled.
>> > +#define RELAX_MICROMIPS_EXTENDED(i) (((i) & 0x10000) != 0)
>> > +#define RELAX_MICROMIPS_MARK_EXTENDED(i) ((i) | 0x10000)
>> > +#define RELAX_MICROMIPS_CLEAR_EXTENDED(i) ((i) & ~0x10000)
>>
>> Any particular reason why 0x10000 rather than 0x1000, which seems
>> to be the first unused bit? I would prefer to pack the used bits
>> together so that it's easier to tell what's left.
>
> These weren't used anywhere. I have discarded these macros.
Thanks, missed that.
>> > + /* For microMIPS, disable reordering. */
>> > + || mips_opts.micromips
>>
>> You should say whether this is for simplicity or by specification.
>> Either way, a bit more detail would be welcome. E.g. something like:
>>
>> /* microMIPS assembly language does not allow the assembler
>> to reorder instructions, even in .set reorder mode.
>> Delay slots are always filled with nops when .set reorder
>> is in effect. */
>>
>> (adjusted as appropriate if my guess is wrong).
>
> I believe the concerns are the same as with MIPS16 code -- so far we have
> failed to develop means to update DWARF-2 records accordingly and if a
> 32-bit branch/jump is swapped with a 16-bit delay-slot instruction (or
> vice versa as it's permitted in microMIPS code, though not in MIPS16 one)
> then substandard debugging experience results from software breakpoints
> placed mid-through an instruction.
>
> So as much as we'd love to reorder we really can't without fixing GAS
> elsewhere.
>
> Hmm, it looks like the piece of code to disable MIPS16 reordering has
> never made its way upstream. It should, unless we have a volunteer to fix
> GAS immediately, so while holding my breath and hoping that people won't
> fight over this challenge I extracted this piece now and updated this
> change accordingly. It makes no sense to keep the two pieces separate.
Thanks, the new version is much more descriptive.
>> > case 'i':
>> > case 'j':
>> > macro_read_relocs (&args, r);
>> > - gas_assert (*r == BFD_RELOC_GPREL16
>> > + gas_assert (mips_opts.micromips
>> > + || *r == BFD_RELOC_GPREL16
>> > || *r == BFD_RELOC_MIPS_HIGHER
>> > || *r == BFD_RELOC_HI16_S
>> > || *r == BFD_RELOC_LO16
>> > || *r == BFD_RELOC_MIPS_GOT_OFST);
>> > + gas_assert (!mips_opts.micromips
>> > + || *r == BFD_RELOC_MICROMIPS_GPREL16
>> > + || *r == BFD_RELOC_MICROMIPS_HIGHER
>> > + || *r == BFD_RELOC_MICROMIPS_HI16_S
>> > + || *r == BFD_RELOC_MICROMIPS_LO16
>> > + || *r == BFD_RELOC_MICROMIPS_GOT_OFST);
>>
>> Let's move the macro_read_relocs stuff inside append_insn rather than
>> leaving the conversion to the callers. You could then make append_insn
>> keep a record of the original (non-microMIPS) reloc_type[0] too,
>> which would simply some of the logic. E.g. these changes would
>> no longer be needed:
>>
>> > - /* Tag symbols that have a R_MIPS16_26 relocation against them. */
>> > - if (reloc_type[0] == BFD_RELOC_MIPS16_JMP
>> > + /* Tag symbols that have a R_MIPS16_26 or R_MICROMIPS_26_S1
>> > + relocation against them. */
>> > + if ((reloc_type[0] == BFD_RELOC_MIPS16_JMP
>> > + || reloc_type[0] == BFD_RELOC_MICROMIPS_JMP)
>> > && ip->fixp[0]->fx_addsy)
>> > *symbol_get_tc (ip->fixp[0]->fx_addsy) = 1;
>
> This actually would -- note that's BFD_RELOC_MIPS16_JMP and not
> BFD_RELOC_MIPS_JMP there.
Oops, yes.
> BTW, do you happen to know what the issue about BFD_RELOC_MIPS_SCN_DISP
> is? We refer to it in a couple of places throughout GAS, but never
> actually generate it. I realise BFD may have to handle the reloc for
> compatibility with other tools, but GAS?
In a word, no.
>> > - macro_build (NULL, "jalr", "d,s", dreg, sreg);
>> > + s = (!mips_opts.micromips || (mips_opts.noreorder && !cprestore)
>> > + ? "jalr" : "jalrs");
>> > + if (mips_opts.micromips && dreg == RA)
>> > + macro_build (NULL, s, "mj", sreg);
>> > + else
>> > + macro_build (NULL, s, JALR_FMT, dreg, sreg);
>>
>> Since we can use JALRS for mips_opts.noreorder && cprestore, I suppose
>> the cprestore nop:
>>
>> if (mips_opts.noreorder)
>> macro_build (NULL, "nop", "");
>>
>> ought to be conditional on !mips_opts.micromips.
>
> No, the delay slot always has to be explicitly filled here. Otherwise
> you'll end up with LW $gp there (the instruction has a 16-bit variation
> too) -- that I fixed not so long ago.
>
> For the avoidance of doubt: all the call (linked jump/branch)
> instructions have a fixed-length delay slot that takes either 4 bytes (as
> with BGEZAL, BLTZAL, JAL, JALR and JALX instructions) or 2 bytes (as with
> BGEZALS, BLTZALS, JALS and JALRS). All the other jump/branch instructions
> have an any-length delay slot except from compact jump/branch instructions
> that have none (these are BEQZC, BNEZC and JRC). Overall the "S" suffix
> stands for a short delay slot and the "C" one means a compact jump/branch,
> i.e. no delay slot.
Ah, yeah, sorry. As you'd guessed, I think I got "C" and "S" confused.
> While doing this I noticed we have a bug. In a sequence like this:
>
> alnv.ps $f0, $f1, $f2, $3
> jalr $3, $2
>
> the ALNV.PS will get reordered into the delay slot. This is obviously
> wrong.
Which answers my question in the other message. :-) Good catch.
>> > + if (!ok)
>> > + {
>> > + switch (*args++)
>>
>> I realise you've copied this from elsewhere, but why "++"?
>> The "for" loop increments "args", doesn't it?
>
> This is the same as for 'r', etc. (i.e. a register that's optional in the
> source if the destination is the same as the target). Otherwise code
> like:
>
> andi16 $7, 65535
> addiu16 $31, 7
>
> fails to assemble. The thing is once we get to "65535", we still have a
> "," unconsumed in args. I have rewritten it more properly though, adding
> a check for that "," too.
Thanks for the explanation and the change. The new version is much clearer.
>> > + i = my_getSmallExpression (&imm_expr, imm_reloc, s);
>> > + if ((i == 0 && (imm_expr.X_op != O_constant
>> > + || (imm_expr.X_add_number & 3) != 0
>> > + || imm_expr.X_add_number > (63 << 2)
>> > + || imm_expr.X_add_number < (-64 << 2)))
>> > + || i > 0)
>> > + {
>> > + imm_expr.X_op = O_absent;
>> > + break;
>> > + }
>> > + immed = imm_expr.X_add_number >> 2;
>> > + INSERT_OPERAND (1, IMMA, *ip, immed);
>> > + imm_expr.X_op = O_absent;
>> > + s = expr_end;
>> > + continue;
>>
>> Why set X_op to O_absent when rejecting this alternative? What breaks
>> if you leave the constant in imm_expr? I couldn't see any similar
>> error-handling code in this function.
>
> I believe the reason is if the offset does not fit for the purpose of
> this 16-bit encoding, then we'll fall back to a 32-bit one that uses
> offset_expr instead.
Ah, yeah, imm_expr trumps offset_expr.
> That written, I have given it some thinking and decided to use local
> variables instead removing any references to imm_expr and thus any issue
> about its usage. We don't pass the results up to append_insn() from here
> in any case.
Thanks, that's better.
>> > + /* If users want relax branch and don't specify to use
>> > + 16-bit instructions, we will not match this pattern.
>> > + This will lead to matching 32-bit instructions, that
>> > + will be relaxed later. */
>> > + if (mips_relax_branch && forced_insn_length != 2)
>> > + break;
>>
>> This seems a bit lame. It should be easy to relax the 16-bit form
>> in the same way as the 32-bit form. We could use a bit in the
>> relaxation opcode to say whether the extra relaxation should be
>> enabled or not, i.e. a bit to record the relevant parts of this
>> condition:
>>
>> + && (pinfo & INSN_UNCOND_BRANCH_DELAY
>> + || pinfo & INSN_COND_BRANCH_DELAY)
>> + && mips_relax_branch
>> + /* Don't try branch relaxation within .set nomacro, or within
>> + .set noat if we use $at for PIC computations. If it turns
>> + out that the branch was out-of-range, we'll get an error. */
>> + && !mips_opts.warn_about_macros
>> + && (mips_opts.at || mips_pic == NO_PIC)
>> + && mips_opts.micromips
>> + /* Don't try branch relaxation, when users specify 16-bit/32-bit
>> + instructions. */
>> + && !forced_insn_length)
>>
>> No need to do that as part of this patch, but let's at least put in
>> a FIXME.
>
> Indeed; we have a preexisting bug here as well -- mips_opts.at may well
> be != ATREG. (A similar bug is present in fix_loongson2f_jump() BTW).
I'm not particularly happy about the loongson workarounds TBH.
> Actually I've thought it's lame enough to implement it. In the course of
> which I discovered (and fixed) other three bugs, so I think it was worth
> the effort. Sent as a sepate patch for the same reasons as the reloc
> change above.
Thanks.
>> > + /* For microMIPS PC relative relocations, we cannot convert it to
>> > + against a section. If we do, it will mess up the fixp->fx_offset. */
>> > if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
>> > - || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
>> > + || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY
>> > + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
>> > + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1
>> > + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1)
>>
>> "to be against a section". That's not a helpful comment though.
>> _How_ will it mess up fixp->fx_offset? Give the reader a clue why
>> the problem applies to BFD_RELOC_MICROMIPS_16_PCREL_S1 but not
>> to something like BFD_RELOC_16_PCREL_S2.
>
> I have failed to spot any problems with this hunk reverted and I'm not
> sure what I should be looking for. Therefore I feel a bit uneasy about
> removing it and only rephrased the comment without actually changing its
> meaning. Chao-ying, do you have anything to add?
Thanks for the discussion and revision downthread. The final version makes
much more sense.
>> > Index: binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/mips1-fp.d
>> > ===================================================================
>> > --- binutils-fsf-trunk-quilt.orig/gas/testsuite/gas/mips/mips1-fp.d 2010-12-07 00:05:05.000000000 +0000
>> > +++ binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/mips1-fp.d 2010-12-07 00:14:47.000000000 +0000
>> > @@ -9,4 +9,4 @@
>> > [0-9a-f]+ <.*>:
>> > .*: 46041000 add.s \$f0,\$f2,\$f4
>> > .*: 44420000 cfc1 \$2,\$0
>> > -#pass
>> > + \.\.\.
>> > Index: binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/mips1-fp.s
>> > ===================================================================
>> > --- binutils-fsf-trunk-quilt.orig/gas/testsuite/gas/mips/mips1-fp.s 2010-12-07 00:05:05.000000000 +0000
>> > +++ binutils-fsf-trunk-quilt/gas/testsuite/gas/mips/mips1-fp.s 2010-12-07 00:14:47.000000000 +0000
>> > @@ -5,3 +5,7 @@
>> > foo:
>> > add.s $f0,$f2,$f4
>> > cfc1 $2,$0
>> > +
>> > +# Force at least 8 (non-delay-slot) zero bytes, to make 'objdump' print ...
>> > + .align 2
>> > + .space 8
>>
>> Leave out this kind of change. I realise it's not the style you prefer,
>> but what's there now is fine. Same for:
>>
>> * gas/testsuite/gas/mips/mips32r2-fp32.d
>> * gas/testsuite/gas/mips/mips64.d
>
> Well, that's not merely a matter of style as #pass simply ignores any
> following rubbish GAS may have produced. This forces a corresponding
> update to gas/testsuite/gas/mips/micromips@mips1-fp.d as the results
> differ between Linux and bare-iron targets. I'd prefer to avoid adding
> new instances of #pass although I've just noticed the original change
> included some other too, so I've applied your suggestion reluctantly.
>
> These test cases should really be all audited and unjustified uses of
> #pass removed -- I realise some people have difficulties following all
> the details of and good ways to deal with subtleties in this area and
> follow the path of least resistance, but we shouldn't be encouraging this
> kind of behaviour. Especially as you seem to be quite picky elsewhere. ;)
We'll just have to agree to disagree here. Both "#pass" and "insert
a set amount of padding at the end of each source file" have their
disadvantages. The former fails to catch cases where we emit extra
junk. The latter means that we never test source files that people
are actually likely to write, or that have instructions at the end
of the section. I think the former is at least as good as the latter.
>> > -#define STO_MIPS_PLT 0x8
>> > +#define STO_MIPS_PLT (1 << 3)
>>
>> Don't change the definitions of the existing constants; use hex constants
>> for the new stuff instead.
>
> Well, STO_OPTIONAL already uses a shifted bit and I find this notation
> clearer. Since code is already inconsistent I have updated it not to
> change the existing definitions, but kept newly-added ones as shifted
> bitfields. I'm happy to keep code consistent, but if a piece is not, I
> will choose the style that suits me better, sorry.
Fair enough.
>> > +/* These are the bitmasks and shift counts used for the different
>> > + fields in the instruction formats. Other than OP, no masks are
>> > + provided for the fixed portions of an instruction, since they are
>> > + not needed. */
>>
>> Seems like too much cut-&-paste: there isn't an OP field here.
>> "Other than TARGET", perhaps, unless there are other opcode masks here.
>
> This looks like copied verbatim from the MIPS16 part. The two parts are
> functionally equivalent and my understanding of the comment is no masks
> are provided for the non-operand parts of instruction. I've left the
> comment as is; I'm not sure what TARGET might mean in this context, please
> elaborate.
As you say, the MIPS16 comment is:
/* These are the bitmasks and shift counts used for the different
fields in the instruction formats. Other than OP, no masks are
provided for the fixed portions of an instruction, since they are
not needed.
OP in this case refers to the first field definition:
#define MIPS16OP_MASK_OP 0x1f
#define MIPS16OP_SH_OP 11
which is the opcode ("fixed portion"). There didn't seem to be
a corresponding MASK_OP and SH_OP for microMIPS.
I'm equally bemused as to where I'd got "TARGET" from...
>> > +/* Return 1 if a symbol associated with the location being disassembled
>> > + indicates a compressed mode, either MIPS16 or microMIPS one. Otherwise,
>> > + return 0. */
>>
>> Reads more naturally to me without "one".
>
> Both MIPS16 and microMIPS are adjectives; they need a noun or a pronoun.
> I realise this requirement is not met everywhere, but that doesn't mean we
> should add new such places IMO.
Really? I'd have thought they were nouns. If you want them to be
adjectives though, it should be "either the ...".
>> > + for (i = 0; i < info->num_symbols; i++)
>> > + {
>> > + pos = info->symtab_pos + i;
>> > +
>> > + if (bfd_asymbol_flavour (info->symtab[pos]) != bfd_target_elf_flavour)
>> > + continue;
>> > +
>> > + symbol = (elf_symbol_type *) info->symtab[pos];
>> > + if ((!micromips_ase
>> > + && ELF_ST_IS_MIPS16 (symbol->internal_elf_sym.st_other))
>> > + || (micromips_ase
>> > + && ELF_ST_IS_MICROMIPS (symbol->internal_elf_sym.st_other)))
>> > + return 1;
>> > + }
>>
>> Why is a search necessary here, when the previous code was happy to
>> look only at the first symbol? I'm not saying the code is wrong,
>> but a bit of commentary would be good.
>
> My feeling is previous code was not "happy", but simply untested (or to
> be more accurate, not tested satisfactorily).
>
> Symbols sharing the same address are sorted alphabetically here which
> becomes a problem when they include both objects and functions (or symbols
> derived from standard MIPS functions defined elsewhere). Disassembly
> shouldn't yield different results based merely on the names of symbols
> chosen and given the semantics of the compressed annotation (it is only
> added to a function symbol if a genuine instruction has been emitted
> following immediately in the source code) I think it should take
> precedence, so we check if any symbol has one.
Agreed, and like I say, I was willing to believe the new code was right.
Please put in a comment along these lines.
>> What problem is the ld-lib.exp change fixing?
>
> Currently you can't build the same source file multiple times with
> different flags. See ld/testsuite/ld-mips-elf/mips16-and-micromips.d for
> a use case (and try it with the ld-lib.exp piece reverted). I think the
> framework shouldn't be limiting the developer like this and making a copy
> of the source to work around the limitation sounds to me like the wrong
> direction to go.
OK, thanks, makes sense. The ld-lib.exp change is independently OK.
Please commit it separately.
Richard
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2011-02-24 10:46 ` Maciej W. Rozycki
@ 2011-02-26 11:41 ` Richard Sandiford
2011-02-28 16:41 ` Maciej W. Rozycki
0 siblings, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2011-02-26 11:41 UTC (permalink / raw)
To: Maciej W. Rozycki
Cc: Fu, Chao-Ying, binutils, Fuhler, Rich, Lau, David, Mills, Kevin,
Garbacea, Ilie, Catherine Moore, Nathan Sidwell, Joseph Myers,
Nathan Froyd
> 2011-02-24 Maciej W. Rozycki <macro@codesourcery.com>
>
> gas/
> * config/tc-mips.c (mips_fix_adjustable): On REL targets also
> reject PC-relative relocations.
>
> gas/testsuite/
> * gas/mips/branch-misc-2.d: Adjust for relocation change.
> * gas/mips/branch-misc-2pic.d: Likewise.
> * gas/mips/branch-misc-4.d: New test for PC-relative relocation
> overflow.
> * gas/mips/branch-misc-4-64.d: Likewise.
> * gas/mips/branch-misc-4.s: Source for the new tests.
> * testsuite/gas/mips/mips.exp: Run the new tests.
OK, thanks.
Richard
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2011-02-26 11:41 ` Richard Sandiford
@ 2011-02-28 16:41 ` Maciej W. Rozycki
0 siblings, 0 replies; 41+ messages in thread
From: Maciej W. Rozycki @ 2011-02-28 16:41 UTC (permalink / raw)
To: Richard Sandiford
Cc: Fu\, Chao-Ying, binutils\@sourceware.org, Fuhler\, Rich, Lau\,
David, Mills\, Kevin, Garbacea\,
Ilie, Catherine Moore, Nathan Sidwell, Joseph Myers,
Nathan Froyd
On Sat, 26 Feb 2011, Richard Sandiford wrote:
> > 2011-02-24 Maciej W. Rozycki <macro@codesourcery.com>
> >
> > gas/
> > * config/tc-mips.c (mips_fix_adjustable): On REL targets also
> > reject PC-relative relocations.
> >
> > gas/testsuite/
> > * gas/mips/branch-misc-2.d: Adjust for relocation change.
> > * gas/mips/branch-misc-2pic.d: Likewise.
> > * gas/mips/branch-misc-4.d: New test for PC-relative relocation
> > overflow.
> > * gas/mips/branch-misc-4-64.d: Likewise.
> > * gas/mips/branch-misc-4.s: Source for the new tests.
> > * testsuite/gas/mips/mips.exp: Run the new tests.
>
> OK, thanks.
And I've integrated this one too, thanks. I'll go through your new
comments in one run once you're done with the review. Thanks for your
effort.
Maciej
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2011-02-26 0:00 ` Maciej W. Rozycki
@ 2011-03-13 9:23 ` Richard Sandiford
2011-07-25 7:49 ` Richard Sandiford
0 siblings, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2011-03-13 9:23 UTC (permalink / raw)
To: Maciej W. Rozycki
Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers,
Nathan Froyd
"Maciej W. Rozycki" <macro@codesourcery.com> writes:
> As it has turned out in the course of sorting out some earlier concerns
> the microMIPS change needs a couple of updates. For your reference I'm
> sending the current version of the original patch as it had to be
> regenerated. On top of this I'm sending the following updates:
Everything except binutils-gas-umips-swap.diff is OK (as one commit,
like you say), with the changes below. If you don't agree with some
of the requested changes, let me know.
I thinkb inutils-gas-umips-swap.diff should go in as a separate commit,
and I'll review it separately.
> - binutils-umips-opcode-trap.diff -- a complementing microMIPS change to
> the trap/no-delay slot annotation made to standard MIPS/MIPS16 code,
Nit:
- target_is_micromips_code_p = (htab->splt != sec)
- && ELF_ST_IS_MICROMIPS (h->root.other);
+ target_is_micromips_code_p = ((htab->splt != sec)
+ && ELF_ST_IS_MICROMIPS (h->root.other));
should be:
target_is_micromips_code_p = (htab->splt != sec
&& ELF_ST_IS_MICROMIPS (h->root.other));
- if (isym->st_shndx == sec_shndx
- && isym->st_value > addr
- && isym->st_value < toaddr)
+ bfd_vma value;
+
+ if (isym->st_shndx != sec_shndx)
+ continue;
+
+ value = isym->st_value;
+ if (ELF_ST_IS_MICROMIPS (isym->st_other))
+ value &= MINUS_TWO;
+ if (value > addr)
isym->st_value -= count;
I still don't understand why we need to mask the low bit here.
As per the original review, aren't these symbols already even?
Only those entered into the hash table are odd. OK as:
if (isym->st_shndx == sec_shndx
&& isym->st_value > addr)
isym->st_value -= count;
if that's correct, but please let me know if it isn't.
@@ -11936,12 +11933,17 @@ mips_elf_relax_delete_bytes (bfd *abfd,
for (; sym_hashes < end_hashes; sym_hashes++)
{
struct elf_link_hash_entry *sym_hash = *sym_hashes;
+ bfd_vma value;
- if ((sym_hash->root.type == bfd_link_hash_defined
- || sym_hash->root.type == bfd_link_hash_defweak)
- && sym_hash->root.u.def.section == sec
- && sym_hash->root.u.def.value > addr
- && sym_hash->root.u.def.value < toaddr)
+ if ((sym_hash->root.type != bfd_link_hash_defined
+ && sym_hash->root.type != bfd_link_hash_defweak)
+ || sym_hash->root.u.def.section != sec)
+ continue;
+
+ value = sym_hash->root.u.def.value;
+ if (ELF_ST_IS_MICROMIPS (sym_hash->other))
+ value &= MINUS_TWO;
+ if (value > addr)
sym_hash->root.u.def.value -= count;
}
Very much nit stage, but "continue" seems overkill here. I preferred
the original style, which doesn't have the combination of positive
and negative tests. OK as:
if ((sym_hash->root.type == bfd_link_hash_defined
|| sym_hash->root.type == bfd_link_hash_defweak)
&& sym_hash->root.u.def.section == sec)
{
bfd_vma value;
value = sym_hash->root.u.def.value;
if (ELF_ST_IS_MICROMIPS (sym_hash->other))
value &= MINUS_TWO;
if (value > addr)
sym_hash->root.u.def.value -= count;
}
+ /* See if there is a jump or a branch reloc preceding the
+ LUI instruction immediately. */
+ for (ibrrel = internal_relocs; ibrrel < irelend; ibrrel++)
+ {
+ offset = irel->r_offset - ibrrel->r_offset;
+ if (offset != 2 && offset != 4)
+ continue;
+
+ br_r_type = ELF32_R_TYPE (ibrrel->r_info);
+ if (offset == 2
+ && (br_r_type == R_MICROMIPS_PC7_S1
+ || br_r_type == R_MICROMIPS_PC10_S1
+ || br_r_type == R_MICROMIPS_JALR))
+ break;
+ if (offset == 4
+ && (br_r_type == R_MICROMIPS_26_S1
+ || br_r_type == R_MICROMIPS_PC16_S1
+ || br_r_type == R_MICROMIPS_JALR))
+ {
+ bfd_byte *ptr = contents + ibrrel->r_offset;
+ unsigned long bropc;
+
+ bropc = bfd_get_16 (abfd, ptr);
+ bropc <<= 16;
+ bropc |= bfd_get_16 (abfd, ptr + 2);
+ /* Compact branches are OK. */
+ if (find_match (opcode, bzc_insns_32) >= 0)
+ brc = TRUE;
+ break;
+ }
+ }
+ /* A delay slot was found, give up, sigh... */
+ if (!brc && ibrrel < irelend)
+ continue;
+
+ /* Otherwise see if the LUI instruction *might* be in a
+ branch delay slot. */
+ if (!brc)
+ {
+ bfd_byte *ptr = contents + irel->r_offset;
+
+ if (irel->r_offset >= 2)
+ bdsize = check_br16_dslot (abfd, ptr - 2);
+ /* A branch possibly found, give up, sigh... */
+ if (bdsize > 0)
+ continue;
+ if (irel->r_offset >= 4)
+ bdsize = check_br32_dslot (abfd, ptr - 4);
+ /* A branch possibly found, give up, sigh... */
+ if (bdsize > 0)
+ continue;
+ }
ISTR discussing this before, but with the new approach, it ought not to
be necessary to check the relocations for this get-out:
/* A delay slot was found, give up, sigh... */
if (!brc && ibrrel < irelend)
continue;
because the following code ought to detect the same cases (and do
so much more cheaply). If you want to avoid this:
if (irel->r_offset >= 2)
bdsize = check_br16_dslot (abfd, ptr - 2);
/* A branch possibly found, give up, sigh... */
if (bdsize > 0)
continue;
triggering for cases where the relocs tell us that the instruction
is actually a BRC, then I think it would be better to split the
search out into a separate function and only use it when we would
otherwise continue. OK as:
/* See if relocations [INTERNAL_RELOCS, IRELEND) confirm that there
is a 4-byte branch at offset OFFSET. */
static boolean
check_4byte_branch (Elf_Internal_Rela *internal_relocs,
Elf_Internal_Rela *irelend, bfd_vma offset)
{
Elf_Internal_Rela *irel;
unsigned long r_type;
for (irel = internal_relocs; irel < irelend; irel++)
if (irel->r_offset == offset)
{
r_type = ELF32_R_TYPE (ibrrel->r_info);
if (br_r_type == R_MICROMIPS_26_S1
|| br_r_type == R_MICROMIPS_PC16_S1
|| br_r_type == R_MICROMIPS_JALR)
return TRUE;
}
return FALSE;
}
...
/* See if the LUI instruction *might* be in a branch delay slot. */
if (irel->r_offset >= 2
&& check_br16_dslot (abfd, ptr - 2) > 0
&& !(irel->r_offset >= 4
/* If the instruction is actually a 4-byte branch,
the value of check_br16_dslot doesn't matter.
We should use check_br32_dslot to check whether
the branch has a delay slot. */
&& check_4byte_branch (internal_relocs, irelend,
irel->r_offset - 4)))
continue;
if (irel->r_offset >= 4
&& check_br32_dslot (abfd, ptr - 4) > 0)
continue;
if that's correct (with trivial fixes to make it compile :-)),
otherwise please let me know.
Of course, this could be generalised so that if the relocations say
we have any type of 4-byte instruction, check_br16_dslot doesn't matter,
and vice versa. But even if you'd like to do that, it's follow-on material.
Let's get the current code in first.
bdsize should be dead after the changes above.
- /* Give up if not the same register used with both relocations. */
+ /* Give up unless the same register used with both relocations. */
Should be:
/* Give up unless the same register is used with both relocations. */
+/* Check if S points at a valid register list according to TYPES.
+ If so, then return 1, advance S to consume the list and store
+ the registers present on the list as a bitmask of ones in REGLISTP,
+ otherwise return 0. A valid list comprises a comma-separated
+ enumeration of valid single registers and/or dash-separated
+ contiguous register ranges as determined by their numbers.
+
+ As a special exception if one of s0-s7 registers is specified as
+ the range's lower delimiter and s8 (fp) is its upper one, then no
+ registers whose numbers place them between s7 and s8 (i.e. $24-$29)
+ are selected; they have to be named separately if needed. */
+
+static int
+reglist_lookup (char **s, unsigned int types, unsigned int *reglistp)
+{
+ unsigned int reglist = 0;
+ unsigned int lastregno;
+ bfd_boolean ok = TRUE;
+ unsigned int regmask;
+ unsigned int regno;
+ char *s_reset = *s;
+ char *s_comma = *s;
+
+ while (reg_lookup (s, types, ®no))
+ {
+ lastregno = regno;
+ if (**s == '-')
+ {
+ (*s)++;
+ ok = reg_lookup (s, types, &lastregno);
+ if (ok && lastregno < regno)
+ ok = FALSE;
+ if (!ok)
+ break;
+ }
+
+ if (lastregno == FP && regno >= S0 && regno <= S7)
+ {
+ lastregno = S7;
+ reglist |= 1 << FP;
+ }
+ regmask = 1 << lastregno;
+ regmask = (regmask << 1) - 1;
+ regmask ^= (1 << regno) - 1;
+ reglist |= regmask;
+
+ s_comma = *s;
+ if (**s != ',')
+ break;
+ (*s)++;
+ }
+
+ if (ok)
+ *s = s_comma;
+ else
+ *s = s_reset;
+ if (reglistp)
+ *reglistp = reglist;
+ return ok && reglist != 0;
+}
I found s_comma a confusing name for something that often doesn't
point to a comma. OK as "s_end_of_reglist", otherwise let me know.
+ /* If the previous instruction has an incorrect size for a fixed
+ branch delay slot in the microMIPS mode, we cannot swap. */
OK as "in microMIPS mode".
As discussed later, from the original patch:
+/* These are the bitmasks and shift counts used for the different
+ fields in the instruction formats. Other than OP, no masks are
+ provided for the fixed portions of an instruction, since they are
+ not needed. */
Just drop the "Other than OP, ".
> - binutils-gas-mips-fix-adjust-reloc.diff -- a fix for relocation handling
> problems discovered while fixing the issue with PC-relative relocations
> discussed earlier; a summary of the changes:
>
> * BFD_RELOC_MICROMIPS_JALR relocs are now explicitly excluded like their
> standard MIPS counterpart; this bug was covered by all microMIPS being
> converted to section-relative ones,
>
> * unlike MIPS16 code we don't have call stubs in the microMIPS mode and
> therefore of the remaing relocs affecting microMIPS code only jump
> relocations against microMIPS text symbols on REL targets are
> converted to section-relative ones as the in-place relocatable field
> strips out the ISA bit,
>
> * therefore we don't have to tag symbols that have a microMIPS jump
> relocation against them, because they're going to be handled just fine
> as long as the symbol is not a microMIPS text one,
Makes sense. OK as long as you split this:
@@ -17189,7 +17187,9 @@ mips_fix_adjustable (fixS *fixp)
+ || fixp->fx_r_type == BFD_RELOC_MIPS_JALR
+ || fixp->fx_r_type == BFD_RELOC_MICROMIPS_JALR))
into a jalr_reloc_p, which should be defined alongside the existing
*_reloc_p functions. Likewise:
+ && (fixp->fx_r_type == BFD_RELOC_MIPS_JMP
+ || fixp->fx_r_type == BFD_RELOC_MICROMIPS_JMP))))
and jmp_reloc_p. (I think you already use this condition elsewhere,
so please change those too.)
> - binutils-umips-relax16.diff -- the original 16-bit->32-bit->out-of-range
> branch relaxation change, regenerated,
+ fragp->fr_var= length;
Missing space.
+ /* Handle 32-bit branches that fit or forced to fit. */
"are forced to fit"
/* Check the short-delay-slot bit. */
if (al && (insn & 0x02000000) != 0)
{
jal = 0x74000000; /* jals */
jalr = 0x45e0; /* jalrs */
}
This is now quite far (and IMO confusingly far) from the code that sets
the default insns. OK if you replace:
+ unsigned long jal = 0xf4000000; /* jal */
+ unsigned long jalr = 0x45c0; /* jalr */
with:
+ unsigned long jal, jalr;
and add:
else
{
jal = 0xf4000000; /* jal */
jalr = 0x45c0; /* jalr */
}
to the condition above.
I think it'd be more consistent to set "jr" here too, but it's OK
either way.
> - binutils-umips-fix-reloc.diff -- the original microMIPS relocation
> handling divergence reduction change, regenerated,
+ {
+ bfd_reloc_code_real_type reloc;
+ int shift;
+
+ reloc = micromips_map_reloc (orig_reloc);
+ shift = reloc == BFD_RELOC_MICROMIPS_JMP ? 1 : 2;
+ if ((address_expr->X_add_number & ((1 << shift) - 1)) != 0)
+ as_bad (_("jump to misaligned address (0x%lx)"),
+ (unsigned long) address_expr->X_add_number);
+ ip->insn_opcode |= ((address_expr->X_add_number >> shift)
+ & 0x3ffffff);
+ }
OK if you replace:
+ reloc = micromips_map_reloc (orig_reloc);
+ shift = reloc == BFD_RELOC_MICROMIPS_JMP ? 1 : 2;
with:
+ shift = mips_opts.micromips ? 1 : 2;
Same for BFD_RELOC_16_PCREL_S2.
+ reloc = micromips_map_reloc (reloc_type[i - 1]);
+ howto = bfd_reloc_type_lookup (stdoutput, reloc);
if (howto == NULL)
{
/* To reproduce this failure try assembling gas/testsuites/
gas/mips/mips16-intermix.s with a mips-ecoff targeted
assembler. */
- as_bad (_("Unsupported MIPS relocation number %d"), reloc_type[i - 1]);
+ as_bad (_("Unsupported MIPS relocation number %d"), reloc);
howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16);
}
-
+
+ reloc = micromips_map_reloc (orig_reloc);
In the usual case, this calls micromips_map_reloc twice for the same thing.
Seems better IMO to replace:
/* In a compound relocation, it is the final (outermost)
operator that determines the relocated field. */
for (i = 1; i < 3; i++)
if (reloc_type[i] == BFD_RELOC_UNUSED)
break;
howto = bfd_reloc_type_lookup (stdoutput, reloc_type[i - 1]);
with:
bfd_reloc_code_real_type final_type[3];
/* Perform any necessary conversion to microMIPS relocations
and find out how many relocations there actually are. */
for (i = 0; i < 3 && reloc_type[i] != BFD_RELOC_UNUSED; i++)
final_type[i] = micromips_map_reloc (reloc_type[i]);
/* In a compound relocation, it is the final (outermost)
operator that determines the relocated field. */
howto = bfd_reloc_type_lookup (stdoutput, final_type[i - 1]);
Then use final_type instead of reloc_type. OK with that change,
otherwise please let me know.
Richard
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2011-03-13 9:23 ` Richard Sandiford
@ 2011-07-25 7:49 ` Richard Sandiford
2011-07-26 2:01 ` Maciej W. Rozycki
0 siblings, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2011-07-25 7:49 UTC (permalink / raw)
To: Maciej W. Rozycki
Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers,
Nathan Froyd
[-- Attachment #1: Type: text/plain, Size: 2104 bytes --]
Continuing this thread from March:
Richard Sandiford <rdsandiford@googlemail.com> writes:
> "Maciej W. Rozycki" <macro@codesourcery.com> writes:
>> As it has turned out in the course of sorting out some earlier concerns
>> the microMIPS change needs a couple of updates. For your reference I'm
>> sending the current version of the original patch as it had to be
>> regenerated. On top of this I'm sending the following updates:
>
> Everything except binutils-gas-umips-swap.diff is OK (as one commit,
> like you say), with the changes below.
It seemed a shame to get to the point of an approved version and not
actually commit it. I've now updated and regenerated the patch series,
made the changes from this approval, and applied a few other things I
noticed. I've attached the three patches separately.
Tested on
mips64-elf mips64el-unknown-kfreebsd-gnu mips64-linux-gnu
mips64octeon-linux-gnu mips64-unknown-kfreebsd-gnu
mipsel-unknown-kfreebsd-gnu mipsisa32el-linux-gnu mipsisa64-elf
mips-linux-gnu mips-unknown-kfreebsd-gnu mips-wrs-vxworks
Applied to trunk along with:
http://sourceware.org/ml/binutils/2010-12/msg00399.html
http://sourceware.org/ml/binutils/2011-02/msg00318.html
Maciej: I regenerated and updated each of your patches separately,
so if you'd like a copy of those individual patches, I can send them
privately.
I went on to say:
> If you don't agree with some of the requested changes, let me know.
and I gather from an off-list discussion a couple of months ago that
there were indeed some things that you didn't like. But I think it'd
be easier to deal with them as follow-ups. Please feel free to send
patches against trunk. Or, if you tell me what it is you disagree with,
I can try to fix it myself.
I'm sure there are things that we've both missed, but again,
we can deal with them as follow-ups.
Last, but not least, thanks for all your hard work on this series.
Thanks especially for perservering in the face of all my annoying
niggles. :-)
Richard
The regenerated version of your patch series (excluding umips-swap,
as per above):
[-- Attachment #2: combined.diff.bz2 --]
[-- Type: application/octet-stream, Size: 163019 bytes --]
[-- Attachment #3: Type: text/plain, Size: 27 bytes --]
The changes I asked for:
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: approval.diff --]
[-- Type: text/x-diff, Size: 15355 bytes --]
Index: bfd/elfxx-mips.c
===================================================================
--- bfd/elfxx-mips.c 2011-07-24 15:06:40.000000000 +0100
+++ bfd/elfxx-mips.c 2011-07-24 15:07:48.000000000 +0100
@@ -5162,7 +5162,7 @@ mips_elf_calculate_relocation (bfd *abfd
target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (h->root.other);
/* If the output section is the PLT section,
then the target is not microMIPS. */
- target_is_micromips_code_p = ((htab->splt != sec)
+ target_is_micromips_code_p = (htab->splt != sec
&& ELF_ST_IS_MICROMIPS (h->root.other));
}
@@ -11910,18 +11910,9 @@ mips_elf_relax_delete_bytes (bfd *abfd,
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
isym = (Elf_Internal_Sym *) symtab_hdr->contents;
for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
- {
- bfd_vma value;
-
- if (isym->st_shndx != sec_shndx)
- continue;
-
- value = isym->st_value;
- if (ELF_ST_IS_MICROMIPS (isym->st_other))
- value &= MINUS_TWO;
- if (value > addr)
- isym->st_value -= count;
- }
+ if (isym->st_shndx == sec_shndx
+ && isym->st_value > addr)
+ isym->st_value -= count;
/* Now adjust the global symbols defined in this section. */
symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
@@ -11932,18 +11923,19 @@ mips_elf_relax_delete_bytes (bfd *abfd,
for (; sym_hashes < end_hashes; sym_hashes++)
{
struct elf_link_hash_entry *sym_hash = *sym_hashes;
- bfd_vma value;
-
- if ((sym_hash->root.type != bfd_link_hash_defined
- && sym_hash->root.type != bfd_link_hash_defweak)
- || sym_hash->root.u.def.section != sec)
- continue;
- value = sym_hash->root.u.def.value;
- if (ELF_ST_IS_MICROMIPS (sym_hash->other))
- value &= MINUS_TWO;
- if (value > addr)
- sym_hash->root.u.def.value -= count;
+ if ((sym_hash->root.type == bfd_link_hash_defined
+ || sym_hash->root.type == bfd_link_hash_defweak)
+ && sym_hash->root.u.def.section == sec)
+ {
+ bfd_vma value;
+
+ value = sym_hash->root.u.def.value;
+ if (ELF_ST_IS_MICROMIPS (sym_hash->other))
+ value &= MINUS_TWO;
+ if (value > addr)
+ sym_hash->root.u.def.value -= count;
+ }
}
return TRUE;
@@ -12279,6 +12271,27 @@ #define IS_BITSIZE(val, N) \
(((((val) & ((1ULL << (N)) - 1)) ^ (1ULL << ((N) - 1))) \
- (1ULL << ((N) - 1))) == (val))
+/* See if relocations [INTERNAL_RELOCS, IRELEND) confirm that there
+ is a 4-byte branch at offset OFFSET. */
+
+static bfd_boolean
+check_4byte_branch (Elf_Internal_Rela *internal_relocs,
+ Elf_Internal_Rela *irelend, bfd_vma offset)
+{
+ Elf_Internal_Rela *irel;
+ unsigned long r_type;
+
+ for (irel = internal_relocs; irel < irelend; irel++)
+ if (irel->r_offset == offset)
+ {
+ r_type = ELF32_R_TYPE (irel->r_info);
+ if (r_type == R_MICROMIPS_26_S1
+ || r_type == R_MICROMIPS_PC16_S1
+ || r_type == R_MICROMIPS_JALR)
+ return TRUE;
+ }
+ return FALSE;
+}
\f
bfd_boolean
_bfd_mips_elf_relax_section (bfd *abfd, asection *sec,
@@ -12439,12 +12452,8 @@ _bfd_mips_elf_relax_section (bfd *abfd,
out the offset). */
if (r_type == R_MICROMIPS_HI16 && MATCH (opcode, lui_insn))
{
- Elf_Internal_Rela *ibrrel;
- bfd_boolean brc = FALSE;
- unsigned int br_r_type;
unsigned long nextopc;
unsigned long reg;
- int bdsize = -1;
bfd_vma offset;
/* Give up if the previous reloc was a HI16 against this symbol
@@ -12466,58 +12475,20 @@ _bfd_mips_elf_relax_section (bfd *abfd,
&& ELF32_R_SYM (irel[2].r_info) == r_symndx)
continue;
- /* See if there is a jump or a branch reloc preceding the
- LUI instruction immediately. */
- for (ibrrel = internal_relocs; ibrrel < irelend; ibrrel++)
- {
- offset = irel->r_offset - ibrrel->r_offset;
- if (offset != 2 && offset != 4)
- continue;
-
- br_r_type = ELF32_R_TYPE (ibrrel->r_info);
- if (offset == 2
- && (br_r_type == R_MICROMIPS_PC7_S1
- || br_r_type == R_MICROMIPS_PC10_S1
- || br_r_type == R_MICROMIPS_JALR))
- break;
- if (offset == 4
- && (br_r_type == R_MICROMIPS_26_S1
- || br_r_type == R_MICROMIPS_PC16_S1
- || br_r_type == R_MICROMIPS_JALR))
- {
- bfd_byte *ptr = contents + ibrrel->r_offset;
- unsigned long bropc;
-
- bropc = bfd_get_16 (abfd, ptr);
- bropc <<= 16;
- bropc |= bfd_get_16 (abfd, ptr + 2);
- /* Compact branches are OK. */
- if (find_match (opcode, bzc_insns_32) >= 0)
- brc = TRUE;
- break;
- }
- }
- /* A delay slot was found, give up, sigh... */
- if (!brc && ibrrel < irelend)
+ /* See if the LUI instruction *might* be in a branch delay slot. */
+ if (irel->r_offset >= 2
+ && check_br16_dslot (abfd, contents + irel->r_offset - 2) > 0
+ && !(irel->r_offset >= 4
+ /* If the instruction is actually a 4-byte branch,
+ the value of check_br16_dslot doesn't matter.
+ We should use check_br32_dslot to check whether
+ the branch has a delay slot. */
+ && check_4byte_branch (internal_relocs, irelend,
+ irel->r_offset - 4)))
+ continue;
+ if (irel->r_offset >= 4
+ && check_br32_dslot (abfd, contents + irel->r_offset - 4) > 0)
continue;
-
- /* Otherwise see if the LUI instruction *might* be in a
- branch delay slot. */
- if (!brc)
- {
- bfd_byte *ptr = contents + irel->r_offset;
-
- if (irel->r_offset >= 2)
- bdsize = check_br16_dslot (abfd, ptr - 2);
- /* A branch possibly found, give up, sigh... */
- if (bdsize > 0)
- continue;
- if (irel->r_offset >= 4)
- bdsize = check_br32_dslot (abfd, ptr - 4);
- /* A branch possibly found, give up, sigh... */
- if (bdsize > 0)
- continue;
- }
reg = OP32_SREG (opcode);
@@ -12545,7 +12516,8 @@ _bfd_mips_elf_relax_section (bfd *abfd,
nextopc = bfd_get_16 (abfd, contents + irel[1].r_offset ) << 16;
nextopc |= bfd_get_16 (abfd, contents + irel[1].r_offset + 2);
- /* Give up unless the same register used with both relocations. */
+ /* Give up unless the same register is used with both
+ relocations. */
if (OP32_SREG (nextopc) != reg)
continue;
Index: gas/config/tc-mips.c
===================================================================
--- gas/config/tc-mips.c 2011-07-24 15:07:45.000000000 +0100
+++ gas/config/tc-mips.c 2011-07-24 15:07:48.000000000 +0100
@@ -2150,7 +2150,7 @@ reglist_lookup (char **s, unsigned int t
unsigned int regmask;
unsigned int regno;
char *s_reset = *s;
- char *s_comma = *s;
+ char *s_end_of_list = *s;
while (reg_lookup (s, types, ®no))
{
@@ -2175,14 +2175,14 @@ reglist_lookup (char **s, unsigned int t
regmask ^= (1 << regno) - 1;
reglist |= regmask;
- s_comma = *s;
+ s_end_of_list = *s;
if (**s != ',')
break;
(*s)++;
}
if (ok)
- *s = s_comma;
+ *s = s_end_of_list;
else
*s = s_reset;
if (reglistp)
@@ -2663,24 +2663,41 @@ micromips_reloc_p (bfd_reloc_code_real_t
static inline bfd_boolean
got16_reloc_p (bfd_reloc_code_real_type reloc)
{
- return (reloc == BFD_RELOC_MIPS_GOT16 || reloc == BFD_RELOC_MIPS16_GOT16
+ return (reloc == BFD_RELOC_MIPS_GOT16
+ || reloc == BFD_RELOC_MIPS16_GOT16
|| reloc == BFD_RELOC_MICROMIPS_GOT16);
}
static inline bfd_boolean
hi16_reloc_p (bfd_reloc_code_real_type reloc)
{
- return (reloc == BFD_RELOC_HI16_S || reloc == BFD_RELOC_MIPS16_HI16_S
+ return (reloc == BFD_RELOC_HI16_S
+ || reloc == BFD_RELOC_MIPS16_HI16_S
|| reloc == BFD_RELOC_MICROMIPS_HI16_S);
}
static inline bfd_boolean
lo16_reloc_p (bfd_reloc_code_real_type reloc)
{
- return (reloc == BFD_RELOC_LO16 || reloc == BFD_RELOC_MIPS16_LO16
+ return (reloc == BFD_RELOC_LO16
+ || reloc == BFD_RELOC_MIPS16_LO16
|| reloc == BFD_RELOC_MICROMIPS_LO16);
}
+static inline bfd_boolean
+jmp_reloc_p (bfd_reloc_code_real_type reloc)
+{
+ return (reloc == BFD_RELOC_MIPS_JMP
+ || reloc == BFD_RELOC_MICROMIPS_JMP);
+}
+
+static inline bfd_boolean
+jalr_reloc_p (bfd_reloc_code_real_type reloc)
+{
+ return (reloc == BFD_RELOC_MIPS_JALR
+ || reloc == BFD_RELOC_MICROMIPS_JALR);
+}
+
/* Return true if the given relocation might need a matching %lo().
This is only "might" because SVR4 R_MIPS_GOT16 relocations only
need a matching %lo() when applied to local symbols. */
@@ -3761,7 +3778,7 @@ can_swap_branch_p (struct mips_cl_insn *
return FALSE;
/* If the previous instruction has an incorrect size for a fixed
- branch delay slot in the microMIPS mode, we cannot swap. */
+ branch delay slot in microMIPS mode, we cannot swap. */
if (mips_opts.micromips)
{
pinfo2 = ip->insn_mo->pinfo;
@@ -4030,11 +4047,9 @@ append_insn (struct mips_cl_insn *ip, ex
case BFD_RELOC_MIPS_JMP:
{
- bfd_reloc_code_real_type reloc;
int shift;
- reloc = micromips_map_reloc (*reloc_type);
- shift = reloc == BFD_RELOC_MICROMIPS_JMP ? 1 : 2;
+ shift = mips_opts.micromips ? 1 : 2;
if ((address_expr->X_add_number & ((1 << shift) - 1)) != 0)
as_bad (_("jump to misaligned address (0x%lx)"),
(unsigned long) address_expr->X_add_number);
@@ -4057,11 +4072,9 @@ append_insn (struct mips_cl_insn *ip, ex
case BFD_RELOC_16_PCREL_S2:
{
- bfd_reloc_code_real_type reloc;
int shift;
- reloc = micromips_map_reloc (*reloc_type);
- shift = reloc == BFD_RELOC_MICROMIPS_16_PCREL_S1 ? 1 : 2;
+ shift = mips_opts.micromips ? 1 : 2;
if ((address_expr->X_add_number & ((1 << shift) - 1)) != 0)
as_bad (_("branch to misaligned address (0x%lx)"),
(unsigned long) address_expr->X_add_number);
@@ -4313,32 +4326,32 @@ append_insn (struct mips_cl_insn *ip, ex
if (!ip->complete_p && *reloc_type < BFD_RELOC_UNUSED)
{
- bfd_reloc_code_real_type reloc;
+ bfd_reloc_code_real_type final_type[3];
reloc_howto_type *howto;
int i;
+ /* Perform any necessary conversion to microMIPS relocations
+ and find out how many relocations there actually are. */
+ for (i = 0; i < 3 && reloc_type[i] != BFD_RELOC_UNUSED; i++)
+ final_type[i] = micromips_map_reloc (reloc_type[i]);
+
/* In a compound relocation, it is the final (outermost)
operator that determines the relocated field. */
- for (i = 1; i < 3; i++)
- if (reloc_type[i] == BFD_RELOC_UNUSED)
- break;
-
- reloc = micromips_map_reloc (reloc_type[i - 1]);
- howto = bfd_reloc_type_lookup (stdoutput, reloc);
+ howto = bfd_reloc_type_lookup (stdoutput, final_type[i - 1]);
if (howto == NULL)
{
/* To reproduce this failure try assembling gas/testsuites/
gas/mips/mips16-intermix.s with a mips-ecoff targeted
assembler. */
- as_bad (_("Unsupported MIPS relocation number %d"), reloc);
+ as_bad (_("Unsupported MIPS relocation number %d"),
+ final_type[i - 1]);
howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16);
}
ip->fixp[0] = fix_new_exp (ip->frag, ip->where,
bfd_get_reloc_size (howto),
address_expr,
- howto->pc_relative,
- micromips_map_reloc (reloc_type[0]));
+ howto->pc_relative, final_type[0]);
/* Tag symbols that have a R_MIPS16_26 relocation against them. */
if (reloc_type[0] == BFD_RELOC_MIPS16_JMP
@@ -4352,7 +4365,6 @@ append_insn (struct mips_cl_insn *ip, ex
&& (reloc_type[0] == BFD_RELOC_16
|| reloc_type[0] == BFD_RELOC_32
|| reloc_type[0] == BFD_RELOC_MIPS_JMP
- || reloc_type[0] == BFD_RELOC_MICROMIPS_JMP
|| reloc_type[0] == BFD_RELOC_GPREL16
|| reloc_type[0] == BFD_RELOC_MIPS_LITERAL
|| reloc_type[0] == BFD_RELOC_GPREL32
@@ -4401,8 +4413,8 @@ append_insn (struct mips_cl_insn *ip, ex
if (reloc_type[i] != BFD_RELOC_UNUSED)
{
ip->fixp[i] = fix_new (ip->frag, ip->where,
- ip->fixp[0]->fx_size, NULL, 0, FALSE,
- micromips_map_reloc (reloc_type[i]));
+ ip->fixp[0]->fx_size, NULL, 0,
+ FALSE, final_type[i]);
/* Use fx_tcbit to mark compound relocs. */
ip->fixp[0]->fx_tcbit = 1;
@@ -17323,7 +17335,7 @@ md_estimate_size_before_relax (fragS *fr
length = relaxed_micromips_16bit_branch_length (fragp, segtype, FALSE);
if (length == 4 && RELAX_MICROMIPS_RELAX32 (fragp->fr_subtype))
length = relaxed_micromips_32bit_branch_length (fragp, segtype, FALSE);
- fragp->fr_var= length;
+ fragp->fr_var = length;
return length;
}
@@ -17385,9 +17397,7 @@ mips_fix_adjustable (fixS *fixp)
the in-place relocatable field if recalculated against the start
address of the symbol's containing section. */
if (HAVE_IN_PLACE_ADDENDS
- && (fixp->fx_pcrel
- || fixp->fx_r_type == BFD_RELOC_MIPS_JALR
- || fixp->fx_r_type == BFD_RELOC_MICROMIPS_JALR))
+ && (fixp->fx_pcrel || jalr_reloc_p (fixp->fx_r_type)))
return 0;
#ifdef OBJ_ELF
@@ -17439,8 +17449,7 @@ mips_fix_adjustable (fixS *fixp)
|| *symbol_get_tc (fixp->fx_addsy)
|| (HAVE_IN_PLACE_ADDENDS
&& ELF_ST_IS_MICROMIPS (S_GET_OTHER (fixp->fx_addsy))
- && (fixp->fx_r_type == BFD_RELOC_MIPS_JMP
- || fixp->fx_r_type == BFD_RELOC_MICROMIPS_JMP))))
+ && jmp_reloc_p (fixp->fx_r_type))))
return 0;
#endif
@@ -17781,12 +17790,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU
bfd_boolean compact = RELAX_MICROMIPS_COMPACT (fragp->fr_subtype);
bfd_boolean al = RELAX_MICROMIPS_LINK (fragp->fr_subtype);
int type = RELAX_MICROMIPS_TYPE (fragp->fr_subtype);
-
- /* Default to the long-delay-slot versions. */
- unsigned long jal = 0xf4000000; /* jal */
- unsigned long jalr = 0x45c0; /* jalr */
-
- unsigned long jr = compact ? 0x45a0 : 0x4580; /* jr/c */
+ unsigned long jal, jalr, jr;
unsigned long insn;
expressionS exp;
@@ -17798,7 +17802,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU
fragp->fr_fix += fragp->fr_var;
- /* Handle 16-bit branches that fit or forced to fit. */
+ /* Handle 16-bit branches that fit or are forced to fit. */
if (type != 0 && !RELAX_MICROMIPS_TOOFAR16 (fragp->fr_subtype))
{
/* We generate a fixup instead of applying it right now,
@@ -17906,6 +17910,12 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU
jal = 0x74000000; /* jals */
jalr = 0x45e0; /* jalrs */
}
+ else
+ {
+ jal = 0xf4000000; /* jal */
+ jalr = 0x45c0; /* jalr */
+ }
+ jr = compact ? 0x45a0 : 0x4580; /* jr/c */
if (!RELAX_MICROMIPS_UNCOND (fragp->fr_subtype))
{
Index: include/opcode/mips.h
===================================================================
--- include/opcode/mips.h 2011-07-24 15:06:40.000000000 +0100
+++ include/opcode/mips.h 2011-07-24 15:07:48.000000000 +0100
@@ -1330,7 +1330,7 @@ #define MIPS16_INSN_COND_BRANCH 0x0
extern const int bfd_mips16_num_opcodes;
/* These are the bitmasks and shift counts used for the different
- fields in the instruction formats. Other than OP, no masks are
+ fields in the instruction formats. Other than MAJOR, no masks are
provided for the fixed portions of an instruction, since they are
not needed. */
[-- Attachment #5: Type: text/plain, Size: 43 bytes --]
The other stuff I noticed while testing:
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #6: extra.diff --]
[-- Type: text/x-diff, Size: 16480 bytes --]
Index: gas/config/tc-mips.c
===================================================================
--- gas/config/tc-mips.c 2011-07-24 15:07:48.000000000 +0100
+++ gas/config/tc-mips.c 2011-07-24 15:07:51.000000000 +0100
@@ -203,9 +203,6 @@ static bfd_boolean mips_in_shared = TRUE
pseudo-op. We use a struct so that .set push and .set pop are more
reliable. */
-/* Whether or not we emit branch likely macros. */
-static bfd_boolean emit_branch_likely_macro = FALSE;
-
struct mips_set_options
{
/* MIPS ISA (Instruction Set Architecture) level. This is set to -1
@@ -644,7 +641,7 @@ static struct hash_control *op_hash = NU
/* The opcode hash table we use for the mips16. */
static struct hash_control *mips16_op_hash = NULL;
-/* The opcode hash table we use for the micromips. */
+/* The opcode hash table we use for the microMIPS ASE. */
static struct hash_control *micromips_op_hash = NULL;
/* This array holds the chars that always start a comment. If the
@@ -745,7 +742,7 @@ #define MAX_NOPS 4
#define NOP_INSN (mips_opts.mips16 ? &mips16_nop_insn \
: (mips_opts.micromips ? µmips_nop16_insn : &nop_insn))
-/* The number of bytes NOP takes for the current mode. */
+/* The size of NOP_INSN in bytes. */
#define NOP_INSN_SIZE (HAVE_CODE_COMPRESSION ? 2 : 4)
/* If this is set, it points to a frag holding nop instructions which
@@ -1251,6 +1248,9 @@ #define MIPS16_EXTRACT_OPERAND(FIELD, IN
MIPS16OP_MASK_##FIELD, \
MIPS16OP_SH_##FIELD)
\f
+/* Whether or not we are emitting a branch-likely macro. */
+static bfd_boolean emit_branch_likely_macro = FALSE;
+
/* Global variables used when generating relaxable macros. See the
comment above RELAX_ENCODE for more details about how relaxation
is used. */
@@ -1292,12 +1292,14 @@ #define MIPS16_EXTRACT_OPERAND(FIELD, IN
is the length of the first instruction of the second alternative.
For non-relaxable macros, both elements give the length of the first
instruction in bytes.
+
Set to zero if we haven't yet seen the first instruction. */
unsigned int first_insn_sizes[2];
/* For relaxable macros, insns[0] is the number of instructions for the
first alternative and insns[1] is the number of instructions for the
second alternative.
+
For non-relaxable macros, both elements give the number of
instructions for the macro. */
unsigned int insns[2];
@@ -1542,10 +1544,11 @@ mips_clear_insn_labels (void)
}
}
+/* Mark instruction labels in MIPS16/microMIPS mode. */
+
static inline void
mips_mark_labels (void)
{
- /* Mark instruction labels in MIPS16/microMIPS mode. */
if (HAVE_CODE_COMPRESSION)
mips_compressed_mark_labels ();
}
@@ -2071,7 +2074,6 @@ static const struct regname reg_names_n3
{0, 0}
};
-
/* Check if S points at a valid register specifier according to TYPES.
If so, then return 1, advance S to consume the specifier and store
the register's number in REGNOP, otherwise return 0. */
@@ -3973,7 +3975,8 @@ micromips_map_reloc (bfd_reloc_code_real
/* Output an instruction. IP is the instruction information.
ADDRESS_EXPR is an operand of the instruction to be used with
- RELOC_TYPE. */
+ RELOC_TYPE. EXPANSIONP is true if the instruction is part of
+ a macro expansion. */
static void
append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
@@ -4209,12 +4212,12 @@ append_insn (struct mips_cl_insn *ip, ex
16-bit/32-bit instructions. */
&& !forced_insn_length);
- if (address_expr
+ if (!HAVE_CODE_COMPRESSION
+ && address_expr
&& relax32
&& *reloc_type == BFD_RELOC_16_PCREL_S2
&& (pinfo & INSN_UNCOND_BRANCH_DELAY || pinfo & INSN_COND_BRANCH_DELAY
- || pinfo & INSN_COND_BRANCH_LIKELY)
- && !HAVE_CODE_COMPRESSION)
+ || pinfo & INSN_COND_BRANCH_LIKELY))
{
relaxed_branch = TRUE;
add_relaxed_insn (ip, (relaxed_branch_length
@@ -4232,14 +4235,14 @@ append_insn (struct mips_cl_insn *ip, ex
address_expr->X_add_number);
*reloc_type = BFD_RELOC_UNUSED;
}
- else if (address_expr
+ else if (mips_opts.micromips
+ && address_expr
&& ((relax32 && *reloc_type == BFD_RELOC_16_PCREL_S2)
|| *reloc_type > BFD_RELOC_UNUSED)
&& (pinfo & INSN_UNCOND_BRANCH_DELAY
|| pinfo & INSN_COND_BRANCH_DELAY
|| (pinfo2 & ~INSN2_ALIAS) == INSN2_UNCOND_BRANCH
- || pinfo2 & INSN2_COND_BRANCH)
- && mips_opts.micromips)
+ || pinfo2 & INSN2_COND_BRANCH))
{
bfd_boolean relax16 = *reloc_type > BFD_RELOC_UNUSED;
int type = relax16 ? *reloc_type - BFD_RELOC_UNUSED : 0;
@@ -4348,6 +4351,7 @@ append_insn (struct mips_cl_insn *ip, ex
howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16);
}
+ howto = bfd_reloc_type_lookup (stdoutput, final_type[0]);
ip->fixp[0] = fix_new_exp (ip->frag, ip->where,
bfd_get_reloc_size (howto),
address_expr,
@@ -4503,12 +4507,10 @@ append_insn (struct mips_cl_insn *ip, ex
&& (history[0].insn_mo->pinfo & MIPS16_INSN_UNCOND_BRANCH)))
mips_no_prev_insn ();
- /* For branch likely macro, we need to emit a label at the end. */
+ /* We need to emit a label at the end of branch-likely macros. */
if (emit_branch_likely_macro)
{
emit_branch_likely_macro = FALSE;
-
- /* We need to generate a label. */
micromips_add_label ();
}
@@ -4723,8 +4725,7 @@ macro_end (void)
relax_substateT s;
const char *msg;
- s = (subtype
- & (RELAX_SECOND_LONGER | RELAX_NOMACRO | RELAX_DELAY_SLOT));
+ s = subtype & (RELAX_SECOND_LONGER | RELAX_NOMACRO | RELAX_DELAY_SLOT);
msg = macro_warning (s);
if (msg != NULL)
as_warn ("%s", msg);
@@ -5259,7 +5260,7 @@ macro_build_jalr (expressionS *ep, int c
static const bfd_reloc_code_real_type jalr_relocs[2]
= { BFD_RELOC_MIPS_JALR, BFD_RELOC_MICROMIPS_JALR };
bfd_reloc_code_real_type jalr_reloc = jalr_relocs[mips_opts.micromips];
- const char *jalr = mips_opts.noreorder && !cprestore ? "jalr" : "jalrs";
+ const char *jalr;
char *f = NULL;
if (MIPS_JALR_HINT_P (ep))
@@ -5269,10 +5270,14 @@ macro_build_jalr (expressionS *ep, int c
}
if (!mips_opts.micromips)
macro_build (NULL, "jalr", "d,s", RA, PIC_CALL_REG);
- else if (MIPS_JALR_HINT_P (ep))
- macro_build (NULL, jalr, "t,s", RA, PIC_CALL_REG);
else
- macro_build (NULL, jalr, "mj", PIC_CALL_REG);
+ {
+ jalr = mips_opts.noreorder && !cprestore ? "jalr" : "jalrs";
+ if (MIPS_JALR_HINT_P (ep))
+ macro_build (NULL, jalr, "t,s", RA, PIC_CALL_REG);
+ else
+ macro_build (NULL, jalr, "mj", PIC_CALL_REG);
+ }
if (MIPS_JALR_HINT_P (ep))
fix_new_exp (frag_now, f - frag_now->fr_literal, 4, ep, FALSE, jalr_reloc);
}
@@ -6031,23 +6036,28 @@ add_got_offset_hilo (int dest, expressio
/* Emit a sequence of instructions to emulate a branch likely operation.
BR is an ordinary branch corresponding to one to be emulated. BRNEG
is its complementing branch with the original condition negated.
- CALL is set if the original branch specified the link operation. EP,
- FMT, SREG and TREG specify the usual macro_build() parameters.
+ CALL is set if the original branch specified the link operation.
+ EP, FMT, SREG and TREG specify the usual macro_build() parameters.
Code like this is produced in the noreorder mode:
+
BRNEG <args>, 1f
nop
b <sym>
delay slot (executed only if branch taken)
1:
- or:
+
+ or, if CALL is set:
+
BRNEG <args>, 1f
nop
bal <sym>
delay slot (executed only if branch taken)
1:
- if CALL is set. In the reorder mode the delay slot would be filled
- with a nop anyway, so code produced is simply:
+
+ In the reorder mode the delay slot would be filled with a nop anyway,
+ so code produced is simply:
+
BR <args>, <sym>
nop
Index: gas/testsuite/gas/mips/dli.s
===================================================================
--- gas/testsuite/gas/mips/dli.s 2011-07-24 15:01:44.000000000 +0100
+++ gas/testsuite/gas/mips/dli.s 2011-07-24 15:07:51.000000000 +0100
@@ -62,6 +62,4 @@ foo:
dli $4,0x003ffc03ffffc000
# Round to a 16 byte boundary, for ease in testing multiple targets.
- nop
- nop
- nop
+ .p2align 4
Index: gas/testsuite/gas/mips/micromips-trap.d
===================================================================
--- gas/testsuite/gas/mips/micromips-trap.d 2011-07-24 15:05:46.000000000 +0100
+++ gas/testsuite/gas/mips/micromips-trap.d 2011-07-24 15:07:52.000000000 +0100
@@ -1,6 +1,6 @@
#objdump: -dr --show-raw-insn
#name: microMIPS for MIPS32r2 (w/traps)
-#as: -mips32r2 -32 -trap -mfp64
+#as: -mips32r2 -32 -trap -mfp64 -EB
#stderr: micromips.l
#source: micromips.s
Index: gas/testsuite/gas/mips/micromips.d
===================================================================
--- gas/testsuite/gas/mips/micromips.d 2011-07-24 15:05:46.000000000 +0100
+++ gas/testsuite/gas/mips/micromips.d 2011-07-24 15:07:52.000000000 +0100
@@ -1,6 +1,6 @@
#objdump: -dr --show-raw-insn
#name: microMIPS for MIPS32r2
-#as: -mips32r2 -32 -mfp64
+#as: -mips32r2 -32 -mfp64 -EB
#stderr: micromips.l
#source: micromips.s
Index: gas/testsuite/gas/mips/micromips@dli.d
===================================================================
--- gas/testsuite/gas/mips/micromips@dli.d 2011-07-24 15:05:46.000000000 +0100
+++ gas/testsuite/gas/mips/micromips@dli.d 2011-07-24 15:07:51.000000000 +0100
@@ -113,7 +113,4 @@ Disassembly of section \.text:
[0-9a-f]+ <[^>]*> 5084 ffff ori a0,a0,0xffff
[0-9a-f]+ <[^>]*> 5884 8000 dsll a0,a0,0x10
[0-9a-f]+ <[^>]*> 5084 c000 ori a0,a0,0xc000
-[0-9a-f]+ <[^>]*> 0c00 nop
-[0-9a-f]+ <[^>]*> 0c00 nop
-[0-9a-f]+ <[^>]*> 0c00 nop
-[0-9a-f]+ <[^>]*> 0c00 nop
+ \.\.\.
Index: gas/testsuite/gas/mips/micromips@elfel-rel2.d
===================================================================
--- /dev/null 2011-07-24 10:34:17.994719526 +0100
+++ gas/testsuite/gas/mips/micromips@elfel-rel2.d 2011-07-24 15:07:52.000000000 +0100
@@ -0,0 +1,28 @@
+#objdump: -sr -j .text
+#name: MIPS ELF reloc 2
+#source: elf-rel2.s
+#as: -mabi=o64
+
+# Test the GPREL and LITERAL generation (microMIPS).
+# FIXME: really this should check that the contents of .sdata, .lit4,
+# and .lit8 are correct too.
+
+.*: +file format .*mips.*
+
+RELOCATION RECORDS FOR \[\.text\]:
+OFFSET [ ]+ TYPE VALUE
+0+0000000 R_MICROMIPS_LITERAL \.lit8
+0+0000004 R_MICROMIPS_LITERAL \.lit8
+0+0000008 R_MICROMIPS_LITERAL \.lit8
+0+000000c R_MICROMIPS_LITERAL \.lit4
+0+0000010 R_MICROMIPS_LITERAL \.lit4
+0+0000014 R_MICROMIPS_LITERAL \.lit4
+0+0000018 R_MICROMIPS_GPREL16 \.sdata
+0+000001c R_MICROMIPS_GPREL16 \.sdata
+0+0000020 R_MICROMIPS_GPREL16 \.sdata
+
+
+Contents of section \.text:
+ 0000 5cbc0000 5cbc0800 5cbc1000 5c9c0000 .*
+ 0010 5c9c0400 5c9c0800 5cfc0000 5cfc0400 .*
+ 0020 5cfc0800 .*
Index: gas/testsuite/gas/mips/micromips@mips4-branch-likely.d
===================================================================
--- gas/testsuite/gas/mips/micromips@mips4-branch-likely.d 2011-07-24 15:05:46.000000000 +0100
+++ gas/testsuite/gas/mips/micromips@mips4-branch-likely.d 2011-07-24 15:07:51.000000000 +0100
@@ -1,6 +1,7 @@
#objdump: -dr --prefix-addresses --show-raw-insn
#name: MIPS mips4 branch-likely instructions
#source: mips4-branch-likely.s
+#as: -32
# Test mips4 branch-likely instructions (microMIPS).
Index: gas/testsuite/gas/mips/micromips@mips4-fp.d
===================================================================
--- gas/testsuite/gas/mips/micromips@mips4-fp.d 2011-07-24 15:05:46.000000000 +0100
+++ gas/testsuite/gas/mips/micromips@mips4-fp.d 2011-07-24 15:07:51.000000000 +0100
@@ -1,6 +1,7 @@
#objdump: -dr --prefix-addresses --show-raw-insn
#name: MIPS mips4 fp
#source: mips4-fp.s
+#as: -32
# Test mips4 fp instructions (microMIPS).
Index: gas/testsuite/gas/mips/mips.exp
===================================================================
--- gas/testsuite/gas/mips/mips.exp 2011-07-24 15:06:40.000000000 +0100
+++ gas/testsuite/gas/mips/mips.exp 2011-07-24 15:07:51.000000000 +0100
@@ -489,21 +489,31 @@ if { [istarget mips*-*-vxworks*] } {
run_dump_test "eret-1"
run_dump_test "eret-2"
run_dump_test "eret-3"
- run_dump_test_arches "24k-branch-delay-1" [mips_arch_list_matching mips1]
+ run_dump_test_arches "24k-branch-delay-1" \
+ [mips_arch_list_matching mips1 !micromips]
run_dump_test_arches "24k-triple-stores-1" \
- [mips_arch_list_matching mips32r2 !octeon]
- run_dump_test_arches "24k-triple-stores-2" [mips_arch_list_matching mips2]
- run_dump_test_arches "24k-triple-stores-3" [mips_arch_list_matching mips3]
- run_dump_test_arches "24k-triple-stores-4" [mips_arch_list_matching mips2]
- run_dump_test_arches "24k-triple-stores-5" [mips_arch_list_matching mips1]
- run_dump_test_arches "24k-triple-stores-6" [mips_arch_list_matching mips2]
- run_dump_test_arches "24k-triple-stores-7" [mips_arch_list_matching mips2]
- run_dump_test_arches "24k-triple-stores-8" [mips_arch_list_matching mips1]
- run_dump_test_arches "24k-triple-stores-9" [mips_arch_list_matching mips1]
- run_dump_test_arches "24k-triple-stores-10" [mips_arch_list_matching mips1]
+ [mips_arch_list_matching mips32r2 !octeon !micromips]
+ run_dump_test_arches "24k-triple-stores-2" \
+ [mips_arch_list_matching mips2 !micromips]
+ run_dump_test_arches "24k-triple-stores-3" \
+ [mips_arch_list_matching mips3 !micromips]
+ run_dump_test_arches "24k-triple-stores-4" \
+ [mips_arch_list_matching mips2 !micromips]
+ run_dump_test_arches "24k-triple-stores-5" \
+ [mips_arch_list_matching mips1 !micromips]
+ run_dump_test_arches "24k-triple-stores-6" \
+ [mips_arch_list_matching mips2 !micromips]
+ run_dump_test_arches "24k-triple-stores-7" \
+ [mips_arch_list_matching mips2 !micromips]
+ run_dump_test_arches "24k-triple-stores-8" \
+ [mips_arch_list_matching mips1 !micromips]
+ run_dump_test_arches "24k-triple-stores-9" \
+ [mips_arch_list_matching mips1 !micromips]
+ run_dump_test_arches "24k-triple-stores-10" \
+ [mips_arch_list_matching mips1 !micromips]
if $elf {
run_dump_test_arches "24k-triple-stores-11" \
- [mips_arch_list_matching mips1]
+ [mips_arch_list_matching mips1 !micromips]
}
if $elf {
Index: gas/testsuite/gas/mips/mipsel16-e.d
===================================================================
--- gas/testsuite/gas/mips/mipsel16-e.d 2011-07-24 15:01:44.000000000 +0100
+++ gas/testsuite/gas/mips/mipsel16-e.d 2011-07-24 15:07:52.000000000 +0100
@@ -1,4 +1,4 @@
-#objdump: -rst -mips16
+#objdump: -rst --special-syms -mips16
#name: MIPS16 reloc
#as: -32 -mips16
#source: mips16-e.s
Index: gas/testsuite/gas/mips/tmipsel16-e.d
===================================================================
--- gas/testsuite/gas/mips/tmipsel16-e.d 2011-07-24 15:01:44.000000000 +0100
+++ gas/testsuite/gas/mips/tmipsel16-e.d 2011-07-24 15:07:52.000000000 +0100
@@ -1,4 +1,4 @@
-#objdump: -rst -mips16
+#objdump: -rst --special-syms -mips16
#name: MIPS16 reloc
#as: -32 -mips16
#source: mips16-e.s
Index: ld/testsuite/ld-mips-elf/mips-elf.exp
===================================================================
--- ld/testsuite/ld-mips-elf/mips-elf.exp 2011-07-24 15:05:46.000000000 +0100
+++ ld/testsuite/ld-mips-elf/mips-elf.exp 2011-07-24 15:07:51.000000000 +0100
@@ -129,19 +129,19 @@ run_dump_test "jalx-1"
if { $linux_gnu } {
run_ld_link_tests [list \
[list "Dummy shared library for JALX test 2" \
- "-shared -nostdlib" \
+ "-shared -nostdlib -melf32btsmip" \
"-G0 -EB -mmicromips -no-mdebug -mabi=32 -march=mips32r2 -KPIC" \
{ jalx-2-printf.s } \
{} \
"libjalx-2.so"] \
[list "Dummy external function for JALX test 2" \
- "-r" \
+ "-r -melf32btsmip" \
"-G0 -EB -no-mdebug -mabi=32 -march=mips32r2 -mno-shared -call_nonpic" \
{ jalx-2-ex.s } \
{} \
"jalx-2-ex.o.r"] \
[list "MIPS JALX test 2" \
- "-nostdlib -T jalx-2.ld tmpdir/libjalx-2.so tmpdir/jalx-2-ex.o.r" \
+ "-nostdlib -T jalx-2.ld tmpdir/libjalx-2.so tmpdir/jalx-2-ex.o.r -melf32btsmip" \
"-G0 -EB -mmicromips -no-mdebug -mabi=32 -march=mips32r2 -mno-shared -call_nonpic" \
{ jalx-2-main.s } \
{ { objdump -d jalx-2.dd } } \
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2011-07-25 7:49 ` Richard Sandiford
@ 2011-07-26 2:01 ` Maciej W. Rozycki
2011-07-29 0:58 ` Maciej W. Rozycki
0 siblings, 1 reply; 41+ messages in thread
From: Maciej W. Rozycki @ 2011-07-26 2:01 UTC (permalink / raw)
To: Richard Sandiford
Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers,
Nathan Froyd
On Sun, 24 Jul 2011, Richard Sandiford wrote:
> Continuing this thread from March:
>
> Richard Sandiford <rdsandiford@googlemail.com> writes:
> > "Maciej W. Rozycki" <macro@codesourcery.com> writes:
> >> As it has turned out in the course of sorting out some earlier concerns
> >> the microMIPS change needs a couple of updates. For your reference I'm
> >> sending the current version of the original patch as it had to be
> >> regenerated. On top of this I'm sending the following updates:
> >
> > Everything except binutils-gas-umips-swap.diff is OK (as one commit,
> > like you say), with the changes below.
>
> It seemed a shame to get to the point of an approved version and not
> actually commit it. I've now updated and regenerated the patch series,
> made the changes from this approval, and applied a few other things I
> noticed. I've attached the three patches separately.
Ouch, that'll cause me a lot of work to resolve merge conflicts. I have
updated all the patches independently before I went on holiday last week,
so that's duplicated work too. Plus there's some stuff accumulated
earlier on.
> Tested on
>
> mips64-elf mips64el-unknown-kfreebsd-gnu mips64-linux-gnu
> mips64octeon-linux-gnu mips64-unknown-kfreebsd-gnu
> mipsel-unknown-kfreebsd-gnu mipsisa32el-linux-gnu mipsisa64-elf
> mips-linux-gnu mips-unknown-kfreebsd-gnu mips-wrs-vxworks
>
> Applied to trunk along with:
>
> http://sourceware.org/ml/binutils/2010-12/msg00399.html
> http://sourceware.org/ml/binutils/2011-02/msg00318.html
My understanding has been you didn't consider the latter a complete
change (and frankly I did wholeheartedly agree).
> Maciej: I regenerated and updated each of your patches separately,
> so if you'd like a copy of those individual patches, I can send them
> privately.
Yes, please -- that'll save me a lot of hassle with conflict resolution,
though I fear that'll be painful anyway. :(
> I went on to say:
>
> > If you don't agree with some of the requested changes, let me know.
>
> and I gather from an off-list discussion a couple of months ago that
> there were indeed some things that you didn't like. But I think it'd
> be easier to deal with them as follow-ups. Please feel free to send
> patches against trunk. Or, if you tell me what it is you disagree with,
> I can try to fix it myself.
I guess I'll just send off the e-mail I had been writing but never
actually completed. My current state of the changes includes all my
updates that reflect the points made, but now I'll have to regenerate
them, possibly by reverting yours, applying mine on top and figuring out
what differences to the original remain. Oh well...
> I'm sure there are things that we've both missed, but again,
> we can deal with them as follow-ups.
There's a whole lot of important linker relaxation fixes that I reckon
were not included in the original series plus several bug fixes.
> Last, but not least, thanks for all your hard work on this series.
> Thanks especially for perservering in the face of all my annoying
> niggles. :-)
You are welcome.
Maciej
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2011-02-26 11:36 ` Richard Sandiford
@ 2011-07-26 14:00 ` Maciej W. Rozycki
0 siblings, 0 replies; 41+ messages in thread
From: Maciej W. Rozycki @ 2011-07-26 14:00 UTC (permalink / raw)
To: Richard Sandiford
Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers
Hi Richard,
> Thanks for the updates. I'll try to go through the patches in the next
> couple of weeks (maybe later this weekend).
I've been distracted for a while, but got back to this effort again.
Here's another update, combining your two replies. Thanks for your
ongoing review.
> >> > +/* Return true if the given CPU supports microMIPS. */
> >> > +#define CPU_HAS_MICROMIPS(cpu) 0
> >>
> >> out. I think the CPU_HAS_MIPS16 stuff is derived from the original LSI
> >> TinyRisc support and wouldn't be used for ASEs.
> >
> > The microMIPS ASE provides for processors that do not support the
> > standard MIPS instruction set. These I think should default to the
> > microMIPS mode. I suspect someone will eventually implement such a
> > processor as since we've got this code implemented here already I'd like
> > to leave it as a placeholder. I think it's not much of a burden, is it?
>
> Oh no, it wasn't any sense of burden that bothered me. It was more
> the talk of "the microMIPS processor". "The MIPS16 processor" made
> sense when the support was first added, but plain "microMIPS" makes
> more sense here. (Or, reading further on, I suppose you won't agree.
> Something other than "processor" though, if you want to treat
> "microMIPS" as an adjective.)
>
> I just thought that, if this was dead code, we might as well just
> remove it rather than quibble about wording. Given what you say about
> microMIPS-only processors being possible though, please just change the
> comment instead.
"Return true if the given CPU supports the microMIPS ASE." it is then.
> >> > +#define RELAX_MICROMIPS_ENCODE(type, is_16bit, uncond, link, toofar) \
> >> > + (0x40000000 \
> >> > + | ((type) & 0xff) \
> >> > + | ((is_16bit) ? 0x100 : 0) \
> >> > + | ((uncond) ? 0x200 : 0) \
> >> > + | ((link) ? 0x400 : 0) \
> >> > + | ((toofar) ? 0x800 : 0))
> >> > +#define RELAX_MICROMIPS_P(i) (((i) & 0xc0000000) == 0x40000000)
> >> > +#define RELAX_MICROMIPS_TYPE(i) ((i) & 0xff)
> >> > +#define RELAX_MICROMIPS_USER_16BIT(i) (((i) & 0x100) != 0)
> >> > +#define RELAX_MICROMIPS_UNCOND(i) (((i) & 0x200) != 0)
> >> > +#define RELAX_MICROMIPS_LINK(i) (((i) & 0x400) != 0)
> >> > +#define RELAX_MICROMIPS_TOOFAR(i) (((i) & 0x800) != 0)
> >> > +#define RELAX_MICROMIPS_MARK_TOOFAR(i) ((i) | 0x800)
> >> > +#define RELAX_MICROMIPS_CLEAR_TOOFAR(i) ((i) & ~0x800)
> >>
> >> Is there a need to create variant frags when the user has explicitly
> >> specified the instruction size? I wouldn't have expected any relaxation
> >> to be necessary in that case, and it looks like the relaxation code does
> >> indeed return 2 whenever USER_16BIT is true.
> >
> > I suspect this has been copied over from MIPS16 code.
> > RELAX_MIPS16_USER_SMALL seems to be used in a similar fashion. Do you
> > happen to know for sure why it has been implemented this way for MIPS16
> > assembly?
>
> Nope :-)
With a sudden insight I realised this is a workaround for the lack of
MIPS16 branch relocations. As no actual relocation can be encoded in
offset_expr, relaxation is used unconditionally instead and the definition
of the relocatable field carried through as a transformed argument code.
> > My suspicion is we want to keep the relocation until the final
> > relaxation so that if the final value turns out to fit afterwards (but not
> > until then) in the forced-truncated immediate field of the instruction
> > nothing is lost.
>
> But that's true of all fixups, and should already be handled correctly.
>
> E.g. if you had microMIPS code embedded in a larger MIPS function, you
> might have normal MIPS branches that cross relaxable microMIPS instructions.
> The same consideration would apply then, even if branch relaxation
> wasn't enabled.
Given the MIPS16 justification above, I have removed this extra bit from
type encoding and modified code to emit forced 16-bit branches straight
away. No regressions in the test suite.
> >> > +/* These are the bitmasks and shift counts used for the different
> >> > + fields in the instruction formats. Other than OP, no masks are
> >> > + provided for the fixed portions of an instruction, since they are
> >> > + not needed. */
> >>
> >> Seems like too much cut-&-paste: there isn't an OP field here.
> >> "Other than TARGET", perhaps, unless there are other opcode masks here.
> >
> > This looks like copied verbatim from the MIPS16 part. The two parts are
> > functionally equivalent and my understanding of the comment is no masks
> > are provided for the non-operand parts of instruction. I've left the
> > comment as is; I'm not sure what TARGET might mean in this context, please
> > elaborate.
>
> As you say, the MIPS16 comment is:
>
> /* These are the bitmasks and shift counts used for the different
> fields in the instruction formats. Other than OP, no masks are
> provided for the fixed portions of an instruction, since they are
> not needed.
>
> OP in this case refers to the first field definition:
>
> #define MIPS16OP_MASK_OP 0x1f
> #define MIPS16OP_SH_OP 11
>
> which is the opcode ("fixed portion"). There didn't seem to be
> a corresponding MASK_OP and SH_OP for microMIPS.
I see what you mean now, I have merely truncated the comment. I think
the mask combinations used for the various instructions are too diverse to
have them all listed here. Also I've dropped MICROMIPSOP_{MASK,SH}_MAJOR
that were unused (and were what OP would be referring to otherwise).
> >> > +/* Return 1 if a symbol associated with the location being disassembled
> >> > + indicates a compressed mode, either MIPS16 or microMIPS one. Otherwise,
> >> > + return 0. */
> >>
> >> Reads more naturally to me without "one".
> >
> > Both MIPS16 and microMIPS are adjectives; they need a noun or a pronoun.
> > I realise this requirement is not met everywhere, but that doesn't mean we
> > should add new such places IMO.
>
> Really? I'd have thought they were nouns. If you want them to be
> adjectives though, it should be "either the ...".
Well, that comes from US trademark law I'm told -- apparently you can't
defend a trademark that's grammatically not an adjective. Don't ask me
for further details (that's certainly language-specific too, for example
I've heard of no such restriction in Polish trademark law and Polish
trademarks are generally nouns, because the way the Polish grammar defines
how adjectives are made from other words, typically nouns, renders them
mostly useless for this purpose).
> >> > + for (i = 0; i < info->num_symbols; i++)
> >> > + {
> >> > + pos = info->symtab_pos + i;
> >> > +
> >> > + if (bfd_asymbol_flavour (info->symtab[pos]) != bfd_target_elf_flavour)
> >> > + continue;
> >> > +
> >> > + symbol = (elf_symbol_type *) info->symtab[pos];
> >> > + if ((!micromips_ase
> >> > + && ELF_ST_IS_MIPS16 (symbol->internal_elf_sym.st_other))
> >> > + || (micromips_ase
> >> > + && ELF_ST_IS_MICROMIPS (symbol->internal_elf_sym.st_other)))
> >> > + return 1;
> >> > + }
> >>
> >> Why is a search necessary here, when the previous code was happy to
> >> look only at the first symbol? I'm not saying the code is wrong,
> >> but a bit of commentary would be good.
> >
> > My feeling is previous code was not "happy", but simply untested (or to
> > be more accurate, not tested satisfactorily).
> >
> > Symbols sharing the same address are sorted alphabetically here which
> > becomes a problem when they include both objects and functions (or symbols
> > derived from standard MIPS functions defined elsewhere). Disassembly
> > shouldn't yield different results based merely on the names of symbols
> > chosen and given the semantics of the compressed annotation (it is only
> > added to a function symbol if a genuine instruction has been emitted
> > following immediately in the source code) I think it should take
> > precedence, so we check if any symbol has one.
>
> Agreed, and like I say, I was willing to believe the new code was right.
> Please put in a comment along these lines.
I have updated the comment; please see if the new version is good enough.
> >> What problem is the ld-lib.exp change fixing?
> >
> > Currently you can't build the same source file multiple times with
> > different flags. See ld/testsuite/ld-mips-elf/mips16-and-micromips.d for
> > a use case (and try it with the ld-lib.exp piece reverted). I think the
> > framework shouldn't be limiting the developer like this and making a copy
> > of the source to work around the limitation sounds to me like the wrong
> > direction to go.
>
> OK, thanks, makes sense. The ld-lib.exp change is independently OK.
> Please commit it separately.
Thanks, split off now.
> > As it has turned out in the course of sorting out some earlier concerns
> > the microMIPS change needs a couple of updates. For your reference I'm
> > sending the current version of the original patch as it had to be
> > regenerated. On top of this I'm sending the following updates:
>
> Everything except binutils-gas-umips-swap.diff is OK (as one commit,
> like you say), with the changes below. If you don't agree with some
> of the requested changes, let me know.
>
> I thinkb inutils-gas-umips-swap.diff should go in as a separate commit,
> and I'll review it separately.
It certainly makes sense to me.
> > - binutils-umips-opcode-trap.diff -- a complementing microMIPS change to
> > the trap/no-delay slot annotation made to standard MIPS/MIPS16 code,
>
> Nit:
>
> - target_is_micromips_code_p = (htab->splt != sec)
> - && ELF_ST_IS_MICROMIPS (h->root.other);
> + target_is_micromips_code_p = ((htab->splt != sec)
> + && ELF_ST_IS_MICROMIPS (h->root.other));
>
> should be:
>
> target_is_micromips_code_p = (htab->splt != sec
> && ELF_ST_IS_MICROMIPS (h->root.other));
Indeed, fixed.
> - if (isym->st_shndx == sec_shndx
> - && isym->st_value > addr
> - && isym->st_value < toaddr)
> + bfd_vma value;
> +
> + if (isym->st_shndx != sec_shndx)
> + continue;
> +
> + value = isym->st_value;
> + if (ELF_ST_IS_MICROMIPS (isym->st_other))
> + value &= MINUS_TWO;
> + if (value > addr)
> isym->st_value -= count;
>
> I still don't understand why we need to mask the low bit here.
> As per the original review, aren't these symbols already even?
> Only those entered into the hash table are odd. OK as:
>
> if (isym->st_shndx == sec_shndx
> && isym->st_value > addr)
> isym->st_value -= count;
>
> if that's correct, but please let me know if it isn't.
I think you're right. I hope GCC is smart enough not to read the memory
behind the pointer twice.
> @@ -11936,12 +11933,17 @@ mips_elf_relax_delete_bytes (bfd *abfd,
> for (; sym_hashes < end_hashes; sym_hashes++)
> {
> struct elf_link_hash_entry *sym_hash = *sym_hashes;
> + bfd_vma value;
>
> - if ((sym_hash->root.type == bfd_link_hash_defined
> - || sym_hash->root.type == bfd_link_hash_defweak)
> - && sym_hash->root.u.def.section == sec
> - && sym_hash->root.u.def.value > addr
> - && sym_hash->root.u.def.value < toaddr)
> + if ((sym_hash->root.type != bfd_link_hash_defined
> + && sym_hash->root.type != bfd_link_hash_defweak)
> + || sym_hash->root.u.def.section != sec)
> + continue;
> +
> + value = sym_hash->root.u.def.value;
> + if (ELF_ST_IS_MICROMIPS (sym_hash->other))
> + value &= MINUS_TWO;
> + if (value > addr)
> sym_hash->root.u.def.value -= count;
> }
>
> Very much nit stage, but "continue" seems overkill here. I preferred
> the original style, which doesn't have the combination of positive
> and negative tests. OK as:
>
> if ((sym_hash->root.type == bfd_link_hash_defined
> || sym_hash->root.type == bfd_link_hash_defweak)
> && sym_hash->root.u.def.section == sec)
> {
> bfd_vma value;
>
> value = sym_hash->root.u.def.value;
> if (ELF_ST_IS_MICROMIPS (sym_hash->other))
> value &= MINUS_TWO;
> if (value > addr)
> sym_hash->root.u.def.value -= count;
> }
I don't like having too much indentation, but I won't insist.
> + /* See if there is a jump or a branch reloc preceding the
> + LUI instruction immediately. */
> + for (ibrrel = internal_relocs; ibrrel < irelend; ibrrel++)
> + {
> + offset = irel->r_offset - ibrrel->r_offset;
> + if (offset != 2 && offset != 4)
> + continue;
> +
> + br_r_type = ELF32_R_TYPE (ibrrel->r_info);
> + if (offset == 2
> + && (br_r_type == R_MICROMIPS_PC7_S1
> + || br_r_type == R_MICROMIPS_PC10_S1
> + || br_r_type == R_MICROMIPS_JALR))
> + break;
> + if (offset == 4
> + && (br_r_type == R_MICROMIPS_26_S1
> + || br_r_type == R_MICROMIPS_PC16_S1
> + || br_r_type == R_MICROMIPS_JALR))
> + {
> + bfd_byte *ptr = contents + ibrrel->r_offset;
> + unsigned long bropc;
> +
> + bropc = bfd_get_16 (abfd, ptr);
> + bropc <<= 16;
> + bropc |= bfd_get_16 (abfd, ptr + 2);
> + /* Compact branches are OK. */
> + if (find_match (opcode, bzc_insns_32) >= 0)
> + brc = TRUE;
> + break;
> + }
> + }
> + /* A delay slot was found, give up, sigh... */
> + if (!brc && ibrrel < irelend)
> + continue;
> +
> + /* Otherwise see if the LUI instruction *might* be in a
> + branch delay slot. */
> + if (!brc)
> + {
> + bfd_byte *ptr = contents + irel->r_offset;
> +
> + if (irel->r_offset >= 2)
> + bdsize = check_br16_dslot (abfd, ptr - 2);
> + /* A branch possibly found, give up, sigh... */
> + if (bdsize > 0)
> + continue;
> + if (irel->r_offset >= 4)
> + bdsize = check_br32_dslot (abfd, ptr - 4);
> + /* A branch possibly found, give up, sigh... */
> + if (bdsize > 0)
> + continue;
> + }
>
> ISTR discussing this before, but with the new approach, it ought not to
> be necessary to check the relocations for this get-out:
>
> /* A delay slot was found, give up, sigh... */
> if (!brc && ibrrel < irelend)
> continue;
>
> because the following code ought to detect the same cases (and do
> so much more cheaply). If you want to avoid this:
>
> if (irel->r_offset >= 2)
> bdsize = check_br16_dslot (abfd, ptr - 2);
> /* A branch possibly found, give up, sigh... */
> if (bdsize > 0)
> continue;
>
> triggering for cases where the relocs tell us that the instruction
> is actually a BRC, then I think it would be better to split the
> search out into a separate function and only use it when we would
> otherwise continue. OK as:
>
> /* See if relocations [INTERNAL_RELOCS, IRELEND) confirm that there
> is a 4-byte branch at offset OFFSET. */
>
> static boolean
> check_4byte_branch (Elf_Internal_Rela *internal_relocs,
> Elf_Internal_Rela *irelend, bfd_vma offset)
> {
> Elf_Internal_Rela *irel;
> unsigned long r_type;
>
> for (irel = internal_relocs; irel < irelend; irel++)
> if (irel->r_offset == offset)
> {
> r_type = ELF32_R_TYPE (ibrrel->r_info);
> if (br_r_type == R_MICROMIPS_26_S1
> || br_r_type == R_MICROMIPS_PC16_S1
> || br_r_type == R_MICROMIPS_JALR)
> return TRUE;
> }
> return FALSE;
> }
> ...
>
> /* See if the LUI instruction *might* be in a branch delay slot. */
> if (irel->r_offset >= 2
> && check_br16_dslot (abfd, ptr - 2) > 0
> && !(irel->r_offset >= 4
> /* If the instruction is actually a 4-byte branch,
> the value of check_br16_dslot doesn't matter.
> We should use check_br32_dslot to check whether
> the branch has a delay slot. */
> && check_4byte_branch (internal_relocs, irelend,
> irel->r_offset - 4)))
> continue;
> if (irel->r_offset >= 4
> && check_br32_dslot (abfd, ptr - 4) > 0)
> continue;
>
> if that's correct (with trivial fixes to make it compile :-)),
> otherwise please let me know.
You are right, in principle, but actually we can check for compact branch
encodings first and only if that has succeded, then scan the relocations.
Which is what I did in the end.
Perhaps that's too much hassle for handling a corner case, but that's
just a couple of lines of code. Let me know if you'd rather I removed it
altogether.
> Of course, this could be generalised so that if the relocations say
> we have any type of 4-byte instruction, check_br16_dslot doesn't matter,
> and vice versa. But even if you'd like to do that, it's follow-on material.
> Let's get the current code in first.
Yeah, let's skip it for now, and if anyone ever gets back to it, then
they may rethink the compact branch special case too. :)
> bdsize should be dead after the changes above.
Yes, and a couple of others.
> - /* Give up if not the same register used with both relocations. */
> + /* Give up unless the same register used with both relocations. */
>
> Should be:
>
> /* Give up unless the same register is used with both relocations. */
OK.
> +/* Check if S points at a valid register list according to TYPES.
> + If so, then return 1, advance S to consume the list and store
> + the registers present on the list as a bitmask of ones in REGLISTP,
> + otherwise return 0. A valid list comprises a comma-separated
> + enumeration of valid single registers and/or dash-separated
> + contiguous register ranges as determined by their numbers.
> +
> + As a special exception if one of s0-s7 registers is specified as
> + the range's lower delimiter and s8 (fp) is its upper one, then no
> + registers whose numbers place them between s7 and s8 (i.e. $24-$29)
> + are selected; they have to be named separately if needed. */
> +
> +static int
> +reglist_lookup (char **s, unsigned int types, unsigned int *reglistp)
> +{
> + unsigned int reglist = 0;
> + unsigned int lastregno;
> + bfd_boolean ok = TRUE;
> + unsigned int regmask;
> + unsigned int regno;
> + char *s_reset = *s;
> + char *s_comma = *s;
> +
> + while (reg_lookup (s, types, ®no))
> + {
> + lastregno = regno;
> + if (**s == '-')
> + {
> + (*s)++;
> + ok = reg_lookup (s, types, &lastregno);
> + if (ok && lastregno < regno)
> + ok = FALSE;
> + if (!ok)
> + break;
> + }
> +
> + if (lastregno == FP && regno >= S0 && regno <= S7)
> + {
> + lastregno = S7;
> + reglist |= 1 << FP;
> + }
> + regmask = 1 << lastregno;
> + regmask = (regmask << 1) - 1;
> + regmask ^= (1 << regno) - 1;
> + reglist |= regmask;
> +
> + s_comma = *s;
> + if (**s != ',')
> + break;
> + (*s)++;
> + }
> +
> + if (ok)
> + *s = s_comma;
> + else
> + *s = s_reset;
> + if (reglistp)
> + *reglistp = reglist;
> + return ok && reglist != 0;
> +}
>
> I found s_comma a confusing name for something that often doesn't
> point to a comma. OK as "s_end_of_reglist", otherwise let me know.
Well, "s_comma" points to anything other than a comma for invalid syntax
only, but I think "s_endlist" sounds better indeed. Your proposal seems a
bit legthy and the number of letters we have available is at most
countable, so a bit of thrift won't hurt.
> + /* If the previous instruction has an incorrect size for a fixed
> + branch delay slot in the microMIPS mode, we cannot swap. */
>
> OK as "in microMIPS mode".
>
> As discussed later, from the original patch:
>
> +/* These are the bitmasks and shift counts used for the different
> + fields in the instruction formats. Other than OP, no masks are
> + provided for the fixed portions of an instruction, since they are
> + not needed. */
>
> Just drop the "Other than OP, ".
Yes, especially with the removal of MICROMIPSOP_{MASK,SH}_MAJOR.
> > - binutils-gas-mips-fix-adjust-reloc.diff -- a fix for relocation handling
> > problems discovered while fixing the issue with PC-relative relocations
> > discussed earlier; a summary of the changes:
> >
> > * BFD_RELOC_MICROMIPS_JALR relocs are now explicitly excluded like their
> > standard MIPS counterpart; this bug was covered by all microMIPS being
> > converted to section-relative ones,
> >
> > * unlike MIPS16 code we don't have call stubs in the microMIPS mode and
> > therefore of the remaing relocs affecting microMIPS code only jump
> > relocations against microMIPS text symbols on REL targets are
> > converted to section-relative ones as the in-place relocatable field
> > strips out the ISA bit,
> >
> > * therefore we don't have to tag symbols that have a microMIPS jump
> > relocation against them, because they're going to be handled just fine
> > as long as the symbol is not a microMIPS text one,
>
> Makes sense. OK as long as you split this:
>
> @@ -17189,7 +17187,9 @@ mips_fix_adjustable (fixS *fixp)
> + || fixp->fx_r_type == BFD_RELOC_MIPS_JALR
> + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_JALR))
>
> into a jalr_reloc_p, which should be defined alongside the existing
> *_reloc_p functions. Likewise:
>
> + && (fixp->fx_r_type == BFD_RELOC_MIPS_JMP
> + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_JMP))))
>
> and jmp_reloc_p. (I think you already use this condition elsewhere,
> so please change those too.)
Both are used once each only, but I'm fine with such a change. Some
other relocs might be handled like this too.
> > - binutils-umips-relax16.diff -- the original 16-bit->32-bit->out-of-range
> > branch relaxation change, regenerated,
>
> + fragp->fr_var= length;
>
> Missing space.
>
> + /* Handle 32-bit branches that fit or forced to fit. */
>
> "are forced to fit"
Fixed.
> /* Check the short-delay-slot bit. */
> if (al && (insn & 0x02000000) != 0)
> {
> jal = 0x74000000; /* jals */
> jalr = 0x45e0; /* jalrs */
> }
>
> This is now quite far (and IMO confusingly far) from the code that sets
> the default insns. OK if you replace:
>
> + unsigned long jal = 0xf4000000; /* jal */
> + unsigned long jalr = 0x45c0; /* jalr */
>
> with:
>
> + unsigned long jal, jalr;
>
> and add:
>
> else
> {
> jal = 0xf4000000; /* jal */
> jalr = 0x45c0; /* jalr */
> }
>
> to the condition above.
>
> I think it'd be more consistent to set "jr" here too, but it's OK
> either way.
So I've moved them close to their points of use instead.
> > - binutils-umips-fix-reloc.diff -- the original microMIPS relocation
> > handling divergence reduction change, regenerated,
>
> + {
> + bfd_reloc_code_real_type reloc;
> + int shift;
> +
> + reloc = micromips_map_reloc (orig_reloc);
> + shift = reloc == BFD_RELOC_MICROMIPS_JMP ? 1 : 2;
> + if ((address_expr->X_add_number & ((1 << shift) - 1)) != 0)
> + as_bad (_("jump to misaligned address (0x%lx)"),
> + (unsigned long) address_expr->X_add_number);
> + ip->insn_opcode |= ((address_expr->X_add_number >> shift)
> + & 0x3ffffff);
> + }
>
> OK if you replace:
>
> + reloc = micromips_map_reloc (orig_reloc);
> + shift = reloc == BFD_RELOC_MICROMIPS_JMP ? 1 : 2;
>
> with:
>
> + shift = mips_opts.micromips ? 1 : 2;
>
> Same for BFD_RELOC_16_PCREL_S2.
Adjusted.
> + reloc = micromips_map_reloc (reloc_type[i - 1]);
> + howto = bfd_reloc_type_lookup (stdoutput, reloc);
> if (howto == NULL)
> {
> /* To reproduce this failure try assembling gas/testsuites/
> gas/mips/mips16-intermix.s with a mips-ecoff targeted
> assembler. */
> - as_bad (_("Unsupported MIPS relocation number %d"), reloc_type[i -
> 1]);
> + as_bad (_("Unsupported MIPS relocation number %d"), reloc);
> howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16);
> }
> -
> +
> + reloc = micromips_map_reloc (orig_reloc);
>
> In the usual case, this calls micromips_map_reloc twice for the same thing.
> Seems better IMO to replace:
>
> /* In a compound relocation, it is the final (outermost)
> operator that determines the relocated field. */
> for (i = 1; i < 3; i++)
> if (reloc_type[i] == BFD_RELOC_UNUSED)
> break;
>
> howto = bfd_reloc_type_lookup (stdoutput, reloc_type[i - 1]);
>
> with:
>
> bfd_reloc_code_real_type final_type[3];
>
> /* Perform any necessary conversion to microMIPS relocations
> and find out how many relocations there actually are. */
> for (i = 0; i < 3 && reloc_type[i] != BFD_RELOC_UNUSED; i++)
> final_type[i] = micromips_map_reloc (reloc_type[i]);
>
> /* In a compound relocation, it is the final (outermost)
> operator that determines the relocated field. */
> howto = bfd_reloc_type_lookup (stdoutput, final_type[i - 1]);
>
> Then use final_type instead of reloc_type. OK with that change,
> otherwise please let me know.
Done.
I'm waiting for the patches you promised and will work on regenerating
changes described above against current trunk.
Maciej
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2011-07-26 2:01 ` Maciej W. Rozycki
@ 2011-07-29 0:58 ` Maciej W. Rozycki
2011-07-29 11:30 ` Richard Sandiford
0 siblings, 1 reply; 41+ messages in thread
From: Maciej W. Rozycki @ 2011-07-29 0:58 UTC (permalink / raw)
To: Richard Sandiford
Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers
Hi Richard,
On Tue, 26 Jul 2011, Maciej W. Rozycki wrote:
> > and I gather from an off-list discussion a couple of months ago that
> > there were indeed some things that you didn't like. But I think it'd
> > be easier to deal with them as follow-ups. Please feel free to send
> > patches against trunk. Or, if you tell me what it is you disagree with,
> > I can try to fix it myself.
>
> I guess I'll just send off the e-mail I had been writing but never
> actually completed. My current state of the changes includes all my
> updates that reflect the points made, but now I'll have to regenerate
> them, possibly by reverting yours, applying mine on top and figuring out
> what differences to the original remain. Oh well...
Here's what I have come up with as a result of merging your changes into
my code base. There are plenty of small changes, so I have decided not to
put too much effort into straightening them up (or not) lest you are
unhappy with the outcome anyway. Instead, I'm giving you (and the others)
an opportunity to review my code in its current shape. The result
generally reflects my concerns as expressed earlier this week, in response
to your comments back in March.
Note there are a couple of bug fixes, some optimisations and one
functional improvement too -- see the change log for details.
> > I'm sure there are things that we've both missed, but again,
> > we can deal with them as follow-ups.
>
> There's a whole lot of important linker relaxation fixes that I reckon
> were not included in the original series plus several bug fixes.
I'll work on these fixes now -- there are quite a few and at least one
still requires some work not to be considered a dirty hack -- and will be
back with you shortly.
Comments, questions?
2011-07-28 Maciej W. Rozycki <macro@codesourcery.com>
bfd/
* elfxx-mips.c: Adjust comments throughout.
(mips_elf_relax_delete_bytes): Reshape code.
(bz_insn_16): Correct opcode mask.
(check_br32): Fix return type.
(check_4byte_branch): Remove function.
(check_bzc): New function.
(_bfd_mips_elf_relax_section): Permit the relaxation of LUI
instructions that immediately follow a compact branch
instruction. Remove check for R_MICROMIPS_GPREL16 relocations.
Reshape code.
gas/
* config/tc-mips.c: Adjust comments throughout.
(reglist_lookup): Reshape code.
(jmp_reloc_p, jalr_reloc_p): Reformat.
(got16_reloc_p, hi16_reloc_p, lo16_reloc_p): Handle microMIPS
relocations.
(gpr_mod_mask): Remove unused variable. Reshape code.
(gpr_read_mask, gpr_write_mask): Reshape code.
(fpr_read_mask, fpr_write_mask): Likewise.
(nops_for_vr4130): Ensure non-microMIPS mode.
(can_swap_branch_p): Correct pinfo2 reference. Reshape code.
(append_insn): Skip Loongson 2F workaround in MIPS16 mode. Use
the outermost operator of a compound relocation to determines
the relocated field. Reshape code.
(md_convert_frag): Reshape code.
include/opcode/
* mips.h: Clarify the description of microMIPS instruction
manipulation macros.
(MICROMIPSOP_MASK_MAJOR, MICROMIPSOP_SH_MAJOR): Remove macros.
Maciej
r-binutils-20110225-umips-fix.diff
Index: binutils-fsf-trunk-quilt/gas/config/tc-mips.c
===================================================================
--- binutils-fsf-trunk-quilt.orig/gas/config/tc-mips.c 2011-07-28 23:18:50.000000000 +0100
+++ binutils-fsf-trunk-quilt/gas/config/tc-mips.c 2011-07-28 23:30:26.000000000 +0100
@@ -483,7 +483,7 @@ static int mips_32bitmode = 0;
(strncmp (TARGET_CPU, "mips16", sizeof ("mips16") - 1) == 0 \
|| strncmp (TARGET_CANONICAL, "mips-lsi-elf", sizeof ("mips-lsi-elf") - 1) == 0)
-/* Return true if the given CPU supports microMIPS. */
+/* Return true if the given CPU supports the microMIPS ASE. */
#define CPU_HAS_MICROMIPS(cpu) 0
/* True if CPU has a dror instruction. */
@@ -2141,7 +2141,7 @@ reg_lookup (char **s, unsigned int types
As a special exception if one of s0-s7 registers is specified as
the range's lower delimiter and s8 (fp) is its upper one, then no
registers whose numbers place them between s7 and s8 (i.e. $24-$29)
- are selected; they have to be named separately if needed. */
+ are selected; they have to be listed separately if needed. */
static int
reglist_lookup (char **s, unsigned int types, unsigned int *reglistp)
@@ -2150,9 +2150,9 @@ reglist_lookup (char **s, unsigned int t
unsigned int lastregno;
bfd_boolean ok = TRUE;
unsigned int regmask;
- unsigned int regno;
+ char *s_endlist = *s;
char *s_reset = *s;
- char *s_end_of_list = *s;
+ unsigned int regno;
while (reg_lookup (s, types, ®no))
{
@@ -2177,14 +2177,14 @@ reglist_lookup (char **s, unsigned int t
regmask ^= (1 << regno) - 1;
reglist |= regmask;
- s_end_of_list = *s;
+ s_endlist = *s;
if (**s != ',')
break;
(*s)++;
}
if (ok)
- *s = s_end_of_list;
+ *s = s_endlist;
else
*s = s_reset;
if (reglistp)
@@ -2663,41 +2663,36 @@ micromips_reloc_p (bfd_reloc_code_real_t
}
static inline bfd_boolean
+jmp_reloc_p (bfd_reloc_code_real_type reloc)
+{
+ return reloc == BFD_RELOC_MIPS_JMP || reloc == BFD_RELOC_MICROMIPS_JMP;
+}
+
+static inline bfd_boolean
got16_reloc_p (bfd_reloc_code_real_type reloc)
{
- return (reloc == BFD_RELOC_MIPS_GOT16
- || reloc == BFD_RELOC_MIPS16_GOT16
+ return (reloc == BFD_RELOC_MIPS_GOT16 || reloc == BFD_RELOC_MIPS16_GOT16
|| reloc == BFD_RELOC_MICROMIPS_GOT16);
}
static inline bfd_boolean
hi16_reloc_p (bfd_reloc_code_real_type reloc)
{
- return (reloc == BFD_RELOC_HI16_S
- || reloc == BFD_RELOC_MIPS16_HI16_S
+ return (reloc == BFD_RELOC_HI16_S || reloc == BFD_RELOC_MIPS16_HI16_S
|| reloc == BFD_RELOC_MICROMIPS_HI16_S);
}
static inline bfd_boolean
lo16_reloc_p (bfd_reloc_code_real_type reloc)
{
- return (reloc == BFD_RELOC_LO16
- || reloc == BFD_RELOC_MIPS16_LO16
+ return (reloc == BFD_RELOC_LO16 || reloc == BFD_RELOC_MIPS16_LO16
|| reloc == BFD_RELOC_MICROMIPS_LO16);
}
static inline bfd_boolean
-jmp_reloc_p (bfd_reloc_code_real_type reloc)
-{
- return (reloc == BFD_RELOC_MIPS_JMP
- || reloc == BFD_RELOC_MICROMIPS_JMP);
-}
-
-static inline bfd_boolean
jalr_reloc_p (bfd_reloc_code_real_type reloc)
{
- return (reloc == BFD_RELOC_MIPS_JALR
- || reloc == BFD_RELOC_MICROMIPS_JALR);
+ return reloc == BFD_RELOC_MIPS_JALR || reloc == BFD_RELOC_MICROMIPS_JALR;
}
/* Return true if the given relocation might need a matching %lo().
@@ -2893,18 +2888,21 @@ relax_end (void)
mips_relax.sequence = 0;
}
-/* Return the mask of core registers that instruction IP may
- read or write. */
+/* Return the mask of core registers that IP reads or writes. */
static unsigned int
gpr_mod_mask (const struct mips_cl_insn *ip)
{
- unsigned long pinfo, pinfo2;
+ unsigned long pinfo2;
unsigned int mask;
mask = 0;
- pinfo = ip->insn_mo->pinfo;
pinfo2 = ip->insn_mo->pinfo2;
+ if (!mips_opts.mips16)
+ {
+ if (pinfo2 & INSN2_MOD_SP)
+ mask |= 1 << SP;
+ }
if (mips_opts.micromips)
{
if (pinfo2 & INSN2_MOD_GPR_MB)
@@ -2934,8 +2932,6 @@ gpr_mod_mask (const struct mips_cl_insn
mask |= 1 << EXTRACT_OPERAND (1, MP, *ip);
if (pinfo2 & INSN2_MOD_GPR_MQ)
mask |= 1 << micromips_to_32_reg_q_map[EXTRACT_OPERAND (1, MQ, *ip)];
- if (pinfo2 & INSN2_MOD_SP)
- mask |= 1 << SP;
}
return mask;
}
@@ -2969,27 +2965,20 @@ gpr_read_mask (const struct mips_cl_insn
if (pinfo & MIPS16_INSN_READ_GPR_X)
mask |= 1 << MIPS16_EXTRACT_OPERAND (REGR32, *ip);
}
- else if (mips_opts.micromips)
- {
- if (pinfo & INSN_READ_GPR_T)
- mask |= 1 << EXTRACT_OPERAND (1, RT, *ip);
- if (pinfo & INSN_READ_GPR_S)
- mask |= 1 << EXTRACT_OPERAND (1, RS, *ip);
- if (pinfo2 & INSN2_READ_GPR_31)
- mask |= 1 << RA;
- if (pinfo2 & INSN2_READ_GP)
- mask |= 1 << GP;
- }
else
{
if (pinfo2 & INSN2_READ_GPR_D)
- mask |= 1 << EXTRACT_OPERAND (0, RD, *ip);
+ mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RD, *ip);
if (pinfo & INSN_READ_GPR_T)
- mask |= 1 << EXTRACT_OPERAND (0, RT, *ip);
+ mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RT, *ip);
if (pinfo & INSN_READ_GPR_S)
- mask |= 1 << EXTRACT_OPERAND (0, RS, *ip);
+ mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RS, *ip);
+ if (pinfo2 & INSN2_READ_GP)
+ mask |= 1 << GP;
+ if (pinfo2 & INSN2_READ_GPR_31)
+ mask |= 1 << RA;
if (pinfo2 & INSN2_READ_GPR_Z)
- mask |= 1 << EXTRACT_OPERAND (0, RZ, *ip);
+ mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RZ, *ip);
}
/* Don't include register 0. */
return mask & ~1;
@@ -3023,23 +3012,14 @@ gpr_write_mask (const struct mips_cl_ins
if (pinfo & MIPS16_INSN_WRITE_GPR_Y)
mask |= 1 << MIPS16OP_EXTRACT_REG32R (ip->insn_opcode);
}
- else if (mips_opts.micromips)
- {
- if (pinfo & INSN_WRITE_GPR_D)
- mask |= 1 << EXTRACT_OPERAND (1, RD, *ip);
- if (pinfo & INSN_WRITE_GPR_T)
- mask |= 1 << EXTRACT_OPERAND (1, RT, *ip);
- if (pinfo2 & INSN2_WRITE_GPR_S)
- mask |= 1 << EXTRACT_OPERAND (1, RS, *ip);
- if (pinfo & INSN_WRITE_GPR_31)
- mask |= 1 << RA;
- }
else
{
if (pinfo & INSN_WRITE_GPR_D)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RD, *ip);
if (pinfo & INSN_WRITE_GPR_T)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RT, *ip);
+ if (pinfo2 & INSN2_WRITE_GPR_S)
+ mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RS, *ip);
if (pinfo & INSN_WRITE_GPR_31)
mask |= 1 << RA;
if (pinfo2 & INSN2_WRITE_GPR_Z)
@@ -3060,19 +3040,10 @@ fpr_read_mask (const struct mips_cl_insn
mask = 0;
pinfo = ip->insn_mo->pinfo;
pinfo2 = ip->insn_mo->pinfo2;
- if (mips_opts.micromips)
+ if (!mips_opts.mips16)
{
if (pinfo2 & INSN2_READ_FPR_D)
- mask |= 1 << EXTRACT_OPERAND (1, FD, *ip);
- if (pinfo & INSN_READ_FPR_S)
- mask |= 1 << EXTRACT_OPERAND (1, FS, *ip);
- if (pinfo & INSN_READ_FPR_T)
- mask |= 1 << EXTRACT_OPERAND (1, FT, *ip);
- if (pinfo & INSN_READ_FPR_R)
- mask |= 1 << EXTRACT_OPERAND (1, FR, *ip);
- }
- else if (!mips_opts.mips16)
- {
+ mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FD, *ip);
if (pinfo & INSN_READ_FPR_S)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FS, *ip);
if (pinfo & INSN_READ_FPR_T)
@@ -3100,16 +3071,7 @@ fpr_write_mask (const struct mips_cl_ins
mask = 0;
pinfo = ip->insn_mo->pinfo;
pinfo2 = ip->insn_mo->pinfo2;
- if (mips_opts.micromips)
- {
- if (pinfo2 & INSN_WRITE_FPR_D)
- mask |= 1 << EXTRACT_OPERAND (1, FD, *ip);
- if (pinfo & INSN_WRITE_FPR_S)
- mask |= 1 << EXTRACT_OPERAND (1, FS, *ip);
- if (pinfo & INSN_WRITE_FPR_T)
- mask |= 1 << EXTRACT_OPERAND (1, FT, *ip);
- }
- else if (!mips_opts.mips16)
+ if (!mips_opts.mips16)
{
if (pinfo & INSN_WRITE_FPR_D)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FD, *ip);
@@ -3316,6 +3278,7 @@ nops_for_vr4130 (int ignore, const struc
if (MF_HILO_INSN (hist[i].insn_mo->pinfo))
{
/* Extract the destination register. */
+ gas_assert (!mips_opts.micromips);
mask = gpr_write_mask (&hist[i]);
/* No nops are needed if INSN reads that register. */
@@ -3720,8 +3683,9 @@ can_swap_branch_p (struct mips_cl_insn *
return FALSE;
/* If the previous instruction is in a variant frag other than this
- branch's one, we cannot do the swap. This does not apply to the
- mips16, which uses variant frags for different purposes. */
+ branch's one, we cannot do the swap. This does not apply to
+ MIPS16/microMIPS code, which uses variant frags for different
+ purposes. */
if (!HAVE_CODE_COMPRESSION
&& history[0].frag
&& history[0].frag->fr_type == rs_machine_dependent)
@@ -3781,17 +3745,16 @@ can_swap_branch_p (struct mips_cl_insn *
/* If the previous instruction has an incorrect size for a fixed
branch delay slot in microMIPS mode, we cannot swap. */
- if (mips_opts.micromips)
- {
- pinfo2 = ip->insn_mo->pinfo;
- if ((pinfo2 & INSN2_BRANCH_DELAY_16BIT)
- && insn_length (history) != 2)
- return FALSE;
+ pinfo2 = ip->insn_mo->pinfo2;
+ if (mips_opts.micromips
+ && (pinfo2 & INSN2_BRANCH_DELAY_16BIT)
+ && insn_length (history) != 2)
+ return FALSE;
+ if (mips_opts.micromips
+ && (pinfo2 & INSN2_BRANCH_DELAY_32BIT)
+ && insn_length (history) != 4)
+ return FALSE;
- if ((pinfo2 & INSN2_BRANCH_DELAY_32BIT)
- && insn_length (history) != 4)
- return FALSE;
- }
return TRUE;
}
@@ -3984,10 +3947,10 @@ append_insn (struct mips_cl_insn *ip, ex
{
unsigned long prev_pinfo, prev_pinfo2, pinfo, pinfo2;
bfd_boolean relaxed_branch = FALSE;
- bfd_boolean relax32;
enum append_method method;
+ bfd_boolean relax32;
- if (mips_fix_loongson2f && !mips_opts.micromips)
+ if (mips_fix_loongson2f && !HAVE_CODE_COMPRESSION)
fix_loongson2f (ip);
mips_mark_labels ();
@@ -4014,10 +3977,11 @@ append_insn (struct mips_cl_insn *ip, ex
else if (*reloc_type <= BFD_RELOC_UNUSED
&& address_expr->X_op == O_constant)
{
+ bfd_reloc_code_real_type orig_reloc = *reloc_type;
unsigned int tmp;
ip->complete_p = 1;
- switch (*reloc_type)
+ switch (orig_reloc)
{
case BFD_RELOC_32:
ip->insn_opcode |= address_expr->X_add_number;
@@ -4192,9 +4156,9 @@ append_insn (struct mips_cl_insn *ip, ex
If the instruction produced is a branch that we will swap with
the preceding instruction, then we add the displacement by which
the branch will be moved backwards. This is more appropriate
- and for MIPS16/microMIPS code also prevents a debugger from placing
- a breakpoint in the middle of the branch (and corrupting code if
- software breakpoints are used). */
+ and for MIPS16/microMIPS code also prevents a debugger from
+ placing a breakpoint in the middle of the branch (and corrupting
+ code if software breakpoints are used). */
dwarf2_emit_insn ((HAVE_CODE_COMPRESSION ? -1 : 0)
+ (method == APPEND_SWAP ? insn_length (history) : 0));
#endif
@@ -4329,60 +4293,66 @@ append_insn (struct mips_cl_insn *ip, ex
if (!ip->complete_p && *reloc_type < BFD_RELOC_UNUSED)
{
+ bfd_reloc_code_real_type orig_reloc = *reloc_type;
bfd_reloc_code_real_type final_type[3];
+ reloc_howto_type *howto0;
reloc_howto_type *howto;
+ int n;
int i;
/* Perform any necessary conversion to microMIPS relocations
- and find out how many relocations there actually are. */
- for (i = 0; i < 3 && reloc_type[i] != BFD_RELOC_UNUSED; i++)
- final_type[i] = micromips_map_reloc (reloc_type[i]);
+ and find out how many relocations there actually are. */
+ for (n = 0; n < 3 && reloc_type[n] != BFD_RELOC_UNUSED; n++)
+ final_type[n] = micromips_map_reloc (reloc_type[n]);
/* In a compound relocation, it is the final (outermost)
operator that determines the relocated field. */
- howto = bfd_reloc_type_lookup (stdoutput, final_type[i - 1]);
+ howto = howto0 = bfd_reloc_type_lookup (stdoutput, final_type[n - 1]);
+
if (howto == NULL)
{
/* To reproduce this failure try assembling gas/testsuites/
gas/mips/mips16-intermix.s with a mips-ecoff targeted
assembler. */
as_bad (_("Unsupported MIPS relocation number %d"),
- final_type[i - 1]);
+ final_type[n - 1]);
howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16);
}
-
- howto = bfd_reloc_type_lookup (stdoutput, final_type[0]);
+
+ if (n > 1)
+ howto0 = bfd_reloc_type_lookup (stdoutput, final_type[0]);
ip->fixp[0] = fix_new_exp (ip->frag, ip->where,
bfd_get_reloc_size (howto),
address_expr,
- howto->pc_relative, final_type[0]);
+ howto0 && howto0->pc_relative,
+ final_type[0]);
/* Tag symbols that have a R_MIPS16_26 relocation against them. */
- if (reloc_type[0] == BFD_RELOC_MIPS16_JMP
- && ip->fixp[0]->fx_addsy)
+ if (final_type[0] == BFD_RELOC_MIPS16_JMP && ip->fixp[0]->fx_addsy)
*symbol_get_tc (ip->fixp[0]->fx_addsy) = 1;
/* These relocations can have an addend that won't fit in
- 4 octets for 64bit assembly. */
+ 4 octets for 64bit assembly. We cheat and check orig_reloc
+ here as this has fewer choices than reloc. */
if (HAVE_64BIT_GPRS
&& ! howto->partial_inplace
- && (reloc_type[0] == BFD_RELOC_16
- || reloc_type[0] == BFD_RELOC_32
- || reloc_type[0] == BFD_RELOC_MIPS_JMP
- || reloc_type[0] == BFD_RELOC_GPREL16
- || reloc_type[0] == BFD_RELOC_MIPS_LITERAL
- || reloc_type[0] == BFD_RELOC_GPREL32
- || reloc_type[0] == BFD_RELOC_64
- || reloc_type[0] == BFD_RELOC_CTOR
- || reloc_type[0] == BFD_RELOC_MIPS_SUB
- || reloc_type[0] == BFD_RELOC_MIPS_HIGHEST
- || reloc_type[0] == BFD_RELOC_MIPS_HIGHER
- || reloc_type[0] == BFD_RELOC_MIPS_SCN_DISP
- || reloc_type[0] == BFD_RELOC_MIPS_REL16
- || reloc_type[0] == BFD_RELOC_MIPS_RELGOT
- || reloc_type[0] == BFD_RELOC_MIPS16_GPREL
- || hi16_reloc_p (reloc_type[0])
- || lo16_reloc_p (reloc_type[0])))
+ && (orig_reloc == BFD_RELOC_16
+ || orig_reloc == BFD_RELOC_32
+ || orig_reloc == BFD_RELOC_MIPS_JMP
+ || orig_reloc == BFD_RELOC_GPREL16
+ || orig_reloc == BFD_RELOC_MIPS_LITERAL
+ || orig_reloc == BFD_RELOC_GPREL32
+ || orig_reloc == BFD_RELOC_64
+ || orig_reloc == BFD_RELOC_CTOR
+ || orig_reloc == BFD_RELOC_MIPS_SUB
+ || orig_reloc == BFD_RELOC_MIPS_HIGHEST
+ || orig_reloc == BFD_RELOC_MIPS_HIGHER
+ || orig_reloc == BFD_RELOC_MIPS_SCN_DISP
+ || orig_reloc == BFD_RELOC_MIPS_REL16
+ || orig_reloc == BFD_RELOC_MIPS_RELGOT
+ || orig_reloc == BFD_RELOC_MIPS16_GPREL
+ || hi16_reloc_p (orig_reloc)
+ || lo16_reloc_p (orig_reloc)))
ip->fixp[0]->fx_no_overflow = 1;
if (mips_relax.sequence)
@@ -4390,7 +4360,7 @@ append_insn (struct mips_cl_insn *ip, ex
if (mips_relax.first_fixup == 0)
mips_relax.first_fixup = ip->fixp[0];
}
- else if (reloc_needs_lo_p (*reloc_type))
+ else if (reloc_needs_lo_p (final_type[0]))
{
struct mips_hi_fixup *hi_fixup;
@@ -4413,17 +4383,16 @@ append_insn (struct mips_cl_insn *ip, ex
against RSS_UNDEF, RSS_GP, RSS_GP0 or RSS_LOC. At the
moment we only use RSS_UNDEF, but we could add support
for the others if it ever becomes necessary. */
- for (i = 1; i < 3; i++)
- if (reloc_type[i] != BFD_RELOC_UNUSED)
- {
- ip->fixp[i] = fix_new (ip->frag, ip->where,
- ip->fixp[0]->fx_size, NULL, 0,
- FALSE, final_type[i]);
+ for (i = 1; i < n; i++)
+ {
+ ip->fixp[i] = fix_new (ip->frag, ip->where,
+ ip->fixp[0]->fx_size, NULL, 0,
+ FALSE, final_type[i]);
- /* Use fx_tcbit to mark compound relocs. */
- ip->fixp[0]->fx_tcbit = 1;
- ip->fixp[i]->fx_tcbit = 1;
- }
+ /* Use fx_tcbit to mark compound relocs. */
+ ip->fixp[0]->fx_tcbit = 1;
+ ip->fixp[i]->fx_tcbit = 1;
+ }
}
install_insn (ip);
@@ -17800,8 +17769,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU
bfd_boolean compact = RELAX_MICROMIPS_COMPACT (fragp->fr_subtype);
bfd_boolean al = RELAX_MICROMIPS_LINK (fragp->fr_subtype);
int type = RELAX_MICROMIPS_TYPE (fragp->fr_subtype);
- unsigned long jal, jalr, jr;
-
+ bfd_boolean short_ds;
unsigned long insn;
expressionS exp;
fixS *fixp;
@@ -17812,7 +17780,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU
fragp->fr_fix += fragp->fr_var;
- /* Handle 16-bit branches that fit or are forced to fit. */
+ /* Handle 16-bit branches that fit or forced to fit. */
if (type != 0 && !RELAX_MICROMIPS_TOOFAR16 (fragp->fr_subtype))
{
/* We generate a fixup instead of applying it right now,
@@ -17841,7 +17809,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU
return;
}
- /* Handle 32-bit branches that fit or forced to fit. */
+ /* Handle 32-bit branches that fit or are forced to fit. */
if (!RELAX_MICROMIPS_RELAX32 (fragp->fr_subtype)
|| !RELAX_MICROMIPS_TOOFAR32 (fragp->fr_subtype))
{
@@ -17914,18 +17882,8 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU
as_warn_where (fragp->fr_file, fragp->fr_line,
_("Relaxed out-of-range branch into a jump"));
- /* Check the short-delay-slot bit. */
- if (al && (insn & 0x02000000) != 0)
- {
- jal = 0x74000000; /* jals */
- jalr = 0x45e0; /* jalrs */
- }
- else
- {
- jal = 0xf4000000; /* jal */
- jalr = 0x45c0; /* jalr */
- }
- jr = compact ? 0x45a0 : 0x4580; /* jr/c */
+ /* Set the short-delay-slot bit. */
+ short_ds = al && (insn & 0x02000000) != 0;
if (!RELAX_MICROMIPS_UNCOND (fragp->fr_subtype))
{
@@ -17995,6 +17953,8 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU
if (mips_pic == NO_PIC)
{
+ unsigned long jal = short_ds ? 0x74000000 : 0xf4000000; /* jal/s */
+
/* j/jal/jals <sym> R_MICROMIPS_26_S1 */
insn = al ? jal : 0xd4000000;
@@ -18019,6 +17979,8 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU
else
{
unsigned long at = RELAX_MICROMIPS_AT (fragp->fr_subtype);
+ unsigned long jalr = short_ds ? 0x45e0 : 0x45c0; /* jalr/s */
+ unsigned long jr = compact ? 0x45a0 : 0x4580; /* jr/c */
/* lw/ld $at, <sym>($gp) R_MICROMIPS_GOT16 */
insn = HAVE_64BIT_ADDRESSES ? 0xdc1c0000 : 0xfc1c0000;
Index: binutils-fsf-trunk-quilt/bfd/elfxx-mips.c
===================================================================
--- binutils-fsf-trunk-quilt.orig/bfd/elfxx-mips.c 2011-07-28 23:18:50.000000000 +0100
+++ binutils-fsf-trunk-quilt/bfd/elfxx-mips.c 2011-07-28 23:30:26.000000000 +0100
@@ -11910,8 +11910,7 @@ mips_elf_relax_delete_bytes (bfd *abfd,
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
isym = (Elf_Internal_Sym *) symtab_hdr->contents;
for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
- if (isym->st_shndx == sec_shndx
- && isym->st_value > addr)
+ if (isym->st_shndx == sec_shndx && isym->st_value > addr)
isym->st_value -= count;
/* Now adjust the global symbols defined in this section. */
@@ -11928,9 +11927,8 @@ mips_elf_relax_delete_bytes (bfd *abfd,
|| sym_hash->root.type == bfd_link_hash_defweak)
&& sym_hash->root.u.def.section == sec)
{
- bfd_vma value;
+ bfd_vma value = sym_hash->root.u.def.value;
- value = sym_hash->root.u.def.value;
if (ELF_ST_IS_MICROMIPS (sym_hash->other))
value &= MINUS_TWO;
if (value > addr)
@@ -11989,7 +11987,7 @@ static const struct opcode_descriptor b_
{ /* "b", "mD", */ 0xcc00, 0xfc00 };
static const struct opcode_descriptor bz_insn_16 =
- { /* "b(eq|ne)z", "md,mE", */ 0x8c00, 0xac00 };
+ { /* "b(eq|ne)z", "md,mE", */ 0x8c00, 0xdc00 };
/* 32-bit and 16-bit branch EQ and NE zero. */
@@ -12241,7 +12239,7 @@ check_br16 (bfd *abfd, bfd_byte *ptr, un
/* If PTR points to a 32-bit branch or jump that doesn't fiddle with REG,
then return TRUE, otherwise FALSE. */
-static int
+static bfd_boolean
check_br32 (bfd *abfd, bfd_byte *ptr, unsigned long reg)
{
unsigned long opcode;
@@ -12266,32 +12264,37 @@ check_br32 (bfd *abfd, bfd_byte *ptr, un
return FALSE;
}
-/* Bitsize checking. */
-#define IS_BITSIZE(val, N) \
- (((((val) & ((1ULL << (N)) - 1)) ^ (1ULL << ((N) - 1))) \
- - (1ULL << ((N) - 1))) == (val))
-
-/* See if relocations [INTERNAL_RELOCS, IRELEND) confirm that there
- is a 4-byte branch at offset OFFSET. */
+/* If the instruction encoding at PTR and relocations [INTERNAL_RELOCS,
+ IRELEND) at OFFSET indicate that it is a compact branch there, then
+ return TRUE, otherwise FALSE. */
static bfd_boolean
-check_4byte_branch (Elf_Internal_Rela *internal_relocs,
- Elf_Internal_Rela *irelend, bfd_vma offset)
+check_bzc (bfd *abfd, const bfd_byte *ptr, bfd_vma offset,
+ const Elf_Internal_Rela *internal_relocs,
+ const Elf_Internal_Rela *irelend)
{
- Elf_Internal_Rela *irel;
- unsigned long r_type;
+ const Elf_Internal_Rela *irel;
+ unsigned long opcode;
+
+ opcode = bfd_get_16 (abfd, ptr);
+ opcode <<= 16;
+ opcode |= bfd_get_16 (abfd, ptr + 2);
+ if (find_match (opcode, bzc_insns_32) < 0)
+ return FALSE;
for (irel = internal_relocs; irel < irelend; irel++)
- if (irel->r_offset == offset)
- {
- r_type = ELF32_R_TYPE (irel->r_info);
- if (r_type == R_MICROMIPS_26_S1
- || r_type == R_MICROMIPS_PC16_S1
- || r_type == R_MICROMIPS_JALR)
- return TRUE;
- }
+ if (irel->r_offset == offset
+ && ELF32_R_TYPE (irel->r_info) == R_MICROMIPS_PC16_S1)
+ return TRUE;
+
return FALSE;
}
+
+/* Bitsize checking. */
+#define IS_BITSIZE(val, N) \
+ (((((val) & ((1ULL << (N)) - 1)) ^ (1ULL << ((N) - 1))) \
+ - (1ULL << ((N) - 1))) == (val))
+
\f
bfd_boolean
_bfd_mips_elf_relax_section (bfd *abfd, asection *sec,
@@ -12336,6 +12339,7 @@ _bfd_mips_elf_relax_section (bfd *abfd,
unsigned long opcode;
bfd_vma symval;
bfd_vma pcrval;
+ bfd_byte *ptr;
int fndopc;
/* The number of bytes to delete for relaxation and from where
@@ -12347,8 +12351,7 @@ _bfd_mips_elf_relax_section (bfd *abfd,
this reloc. */
if (r_type != R_MICROMIPS_HI16
&& r_type != R_MICROMIPS_PC16_S1
- && r_type != R_MICROMIPS_26_S1
- && r_type != R_MICROMIPS_GPREL16)
+ && r_type != R_MICROMIPS_26_S1)
continue;
/* Get the section contents if we haven't done so already. */
@@ -12361,6 +12364,7 @@ _bfd_mips_elf_relax_section (bfd *abfd,
else if (!bfd_malloc_and_get_section (abfd, sec, &contents))
goto error_return;
}
+ ptr = contents + irel->r_offset;
/* Read this BFD's local symbols if we haven't done so already. */
if (isymbuf == NULL && symtab_hdr->sh_info != 0)
@@ -12432,8 +12436,8 @@ _bfd_mips_elf_relax_section (bfd *abfd,
if (irel->r_offset + 4 > sec->size)
continue;
- opcode = bfd_get_16 (abfd, contents + irel->r_offset ) << 16;
- opcode |= bfd_get_16 (abfd, contents + irel->r_offset + 2);
+ opcode = bfd_get_16 (abfd, ptr ) << 16;
+ opcode |= bfd_get_16 (abfd, ptr + 2);
/* This is the pc-relative distance from the instruction the
relocation is applied to, to the symbol referred. */
@@ -12452,6 +12456,7 @@ _bfd_mips_elf_relax_section (bfd *abfd,
out the offset). */
if (r_type == R_MICROMIPS_HI16 && MATCH (opcode, lui_insn))
{
+ bfd_boolean bzc = FALSE;
unsigned long nextopc;
unsigned long reg;
bfd_vma offset;
@@ -12475,19 +12480,19 @@ _bfd_mips_elf_relax_section (bfd *abfd,
&& ELF32_R_SYM (irel[2].r_info) == r_symndx)
continue;
- /* See if the LUI instruction *might* be in a branch delay slot. */
+ /* See if the LUI instruction *might* be in a branch delay slot.
+ We check whether what looks like a 16-bit branch or jump is
+ actually an immediate argument to a compact branch, and let
+ it through if so. */
if (irel->r_offset >= 2
- && check_br16_dslot (abfd, contents + irel->r_offset - 2) > 0
+ && check_br16_dslot (abfd, ptr - 2)
&& !(irel->r_offset >= 4
- /* If the instruction is actually a 4-byte branch,
- the value of check_br16_dslot doesn't matter.
- We should use check_br32_dslot to check whether
- the branch has a delay slot. */
- && check_4byte_branch (internal_relocs, irelend,
- irel->r_offset - 4)))
+ && (bzc = check_bzc (abfd, ptr - 4, irel->r_offset - 4,
+ internal_relocs, irelend))))
continue;
if (irel->r_offset >= 4
- && check_br32_dslot (abfd, contents + irel->r_offset - 4) > 0)
+ && !bzc
+ && check_br32_dslot (abfd, ptr - 4))
continue;
reg = OP32_SREG (opcode);
@@ -12502,11 +12507,11 @@ _bfd_mips_elf_relax_section (bfd *abfd,
case 0:
break;
case 2:
- if (check_br16 (abfd, contents + irel->r_offset + 4, reg))
+ if (check_br16 (abfd, ptr + 4, reg))
break;
continue;
case 4:
- if (check_br32 (abfd, contents + irel->r_offset + 4, reg))
+ if (check_br32 (abfd, ptr + 4, reg))
break;
continue;
default:
@@ -12581,8 +12586,7 @@ _bfd_mips_elf_relax_section (bfd *abfd,
&& irel->r_offset + 5 < sec->size
&& ((fndopc = find_match (opcode, bz_rs_insns_32)) >= 0
|| (fndopc = find_match (opcode, bz_rt_insns_32)) >= 0)
- && MATCH (bfd_get_16 (abfd, contents + irel->r_offset + 4),
- nop_insn_16))
+ && MATCH (bfd_get_16 (abfd, ptr + 4), nop_insn_16))
{
unsigned long reg;
@@ -12593,10 +12597,8 @@ _bfd_mips_elf_relax_section (bfd *abfd,
| BZC32_REG_FIELD (reg)
| (opcode & 0xffff)); /* Addend value. */
- bfd_put_16 (abfd, (opcode >> 16) & 0xffff,
- contents + irel->r_offset);
- bfd_put_16 (abfd, opcode & 0xffff,
- contents + irel->r_offset + 2);
+ bfd_put_16 (abfd, (opcode >> 16) & 0xffff, ptr);
+ bfd_put_16 (abfd, opcode & 0xffff, ptr + 2);
/* Delete the 16-bit delay slot NOP: two bytes from
irel->offset + 4. */
@@ -12617,7 +12619,7 @@ _bfd_mips_elf_relax_section (bfd *abfd,
bfd_put_16 (abfd,
(b_insn_16.match
| (opcode & 0x3ff)), /* Addend value. */
- contents + irel->r_offset);
+ ptr);
/* Delete 2 bytes from irel->r_offset + 2. */
delcnt = 2;
@@ -12645,7 +12647,7 @@ _bfd_mips_elf_relax_section (bfd *abfd,
(bz_insns_16[fndopc].match
| BZ16_REG_FIELD (reg)
| (opcode & 0x7f)), /* Addend value. */
- contents + irel->r_offset);
+ ptr);
/* Delete 2 bytes from irel->r_offset + 2. */
delcnt = 2;
@@ -12661,14 +12663,13 @@ _bfd_mips_elf_relax_section (bfd *abfd,
unsigned long n32opc;
bfd_boolean relaxed = FALSE;
- n32opc = bfd_get_16 (abfd, contents + irel->r_offset + 4) << 16;
- n32opc |= bfd_get_16 (abfd, contents + irel->r_offset + 6);
+ n32opc = bfd_get_16 (abfd, ptr + 4) << 16;
+ n32opc |= bfd_get_16 (abfd, ptr + 6);
if (MATCH (n32opc, nop_insn_32))
{
/* Replace delay slot 32-bit NOP with a 16-bit NOP. */
- bfd_put_16 (abfd, nop_insn_16.match,
- contents + irel->r_offset + 4);
+ bfd_put_16 (abfd, nop_insn_16.match, ptr + 4);
relaxed = TRUE;
}
@@ -12679,7 +12680,7 @@ _bfd_mips_elf_relax_section (bfd *abfd,
(move_insn_16.match
| MOVE16_RD_FIELD (MOVE32_RD (n32opc))
| MOVE16_RS_FIELD (MOVE32_RS (n32opc))),
- contents + irel->r_offset + 4);
+ ptr + 4);
relaxed = TRUE;
}
@@ -12691,9 +12692,9 @@ _bfd_mips_elf_relax_section (bfd *abfd,
/* JAL with 32-bit delay slot that is changed to a JALS
with 16-bit delay slot. */
bfd_put_16 (abfd, (jal_insn_32_bd16.match >> 16) & 0xffff,
- contents + irel->r_offset);
+ ptr);
bfd_put_16 (abfd, jal_insn_32_bd16.match & 0xffff,
- contents + irel->r_offset + 2);
+ ptr + 2);
/* Delete 2 bytes from irel->r_offset + 6. */
delcnt = 2;
Index: binutils-fsf-trunk-quilt/include/opcode/mips.h
===================================================================
--- binutils-fsf-trunk-quilt.orig/include/opcode/mips.h 2011-07-28 23:29:25.000000000 +0100
+++ binutils-fsf-trunk-quilt/include/opcode/mips.h 2011-07-28 23:30:26.000000000 +0100
@@ -1332,13 +1332,10 @@ extern int bfd_mips_num_opcodes;
extern const struct mips_opcode mips16_opcodes[];
extern const int bfd_mips16_num_opcodes;
-/* These are the bitmasks and shift counts used for the different
- fields in the instruction formats. Other than MAJOR, no masks are
- provided for the fixed portions of an instruction, since they are
- not needed. */
+/* These are the bit masks and shift counts used for the different fields
+ in the microMIPS instruction formats. No masks are provided for the
+ fixed portions of an instruction, since they are not needed. */
-#define MICROMIPSOP_MASK_MAJOR 0x3f
-#define MICROMIPSOP_SH_MAJOR 26
#define MICROMIPSOP_MASK_IMMEDIATE 0xffff
#define MICROMIPSOP_SH_IMMEDIATE 0
#define MICROMIPSOP_MASK_DELTA 0xffff
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2011-07-29 0:58 ` Maciej W. Rozycki
@ 2011-07-29 11:30 ` Richard Sandiford
2011-07-29 22:52 ` Maciej W. Rozycki
0 siblings, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2011-07-29 11:30 UTC (permalink / raw)
To: Maciej W. Rozycki
Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers
"Maciej W. Rozycki" <macro@codesourcery.com> writes:
> Here's what I have come up with as a result of merging your changes into
> my code base. There are plenty of small changes, so I have decided not to
> put too much effort into straightening them up (or not) lest you are
> unhappy with the outcome anyway. Instead, I'm giving you (and the others)
> an opportunity to review my code in its current shape.
Thanks for doing it this way.
> On Tue, 26 Jul 2011, Maciej W. Rozycki wrote:
>> There's a whole lot of important linker relaxation fixes that I reckon
>> were not included in the original series plus several bug fixes.
>
> I'll work on these fixes now -- there are quite a few and at least one
> still requires some work not to be considered a dirty hack -- and will be
> back with you shortly.
Thanks. This is what I asked for in the first place: that anything we
hadn't caught should be dealt with as follow-ups, rather than folded
into the huge initial commit. (For reference, even the .tar.bz2 was
over 280k.) I still don't understand why you chose to ignore that.
The whole point of approving most of the submission with a few minor
changes (back in March) was that it would be quick to make those changes
and get the whole thing into CVS. It would then be much easier for me
to review any further changes you wanted to make. I also assumed that
it would be easier for you to submit them.
Anyway, on a more positive note, a lot of the hunks are OK to commit,
as follows:
> Index: binutils-fsf-trunk-quilt/gas/config/tc-mips.c
> ===================================================================
> --- binutils-fsf-trunk-quilt.orig/gas/config/tc-mips.c 2011-07-28 23:18:50.000000000 +0100
> +++ binutils-fsf-trunk-quilt/gas/config/tc-mips.c 2011-07-28 23:30:26.000000000 +0100
> @@ -483,7 +483,7 @@ static int mips_32bitmode = 0;
> (strncmp (TARGET_CPU, "mips16", sizeof ("mips16") - 1) == 0 \
> || strncmp (TARGET_CANONICAL, "mips-lsi-elf", sizeof ("mips-lsi-elf") - 1) == 0)
>
> -/* Return true if the given CPU supports microMIPS. */
> +/* Return true if the given CPU supports the microMIPS ASE. */
> #define CPU_HAS_MICROMIPS(cpu) 0
>
> /* True if CPU has a dror instruction. */
OK
> @@ -2141,7 +2141,7 @@ reg_lookup (char **s, unsigned int types
> As a special exception if one of s0-s7 registers is specified as
> the range's lower delimiter and s8 (fp) is its upper one, then no
> registers whose numbers place them between s7 and s8 (i.e. $24-$29)
> - are selected; they have to be named separately if needed. */
> + are selected; they have to be listed separately if needed. */
>
> static int
> reglist_lookup (char **s, unsigned int types, unsigned int *reglistp)
OK
> @@ -2893,18 +2888,21 @@ relax_end (void)
> mips_relax.sequence = 0;
> }
>
> -/* Return the mask of core registers that instruction IP may
> - read or write. */
> +/* Return the mask of core registers that IP reads or writes. */
>
> static unsigned int
> gpr_mod_mask (const struct mips_cl_insn *ip)
> {
> - unsigned long pinfo, pinfo2;
> + unsigned long pinfo2;
> unsigned int mask;
>
> mask = 0;
> - pinfo = ip->insn_mo->pinfo;
> pinfo2 = ip->insn_mo->pinfo2;
> + if (!mips_opts.mips16)
> + {
> + if (pinfo2 & INSN2_MOD_SP)
> + mask |= 1 << SP;
> + }
> if (mips_opts.micromips)
> {
> if (pinfo2 & INSN2_MOD_GPR_MB)
and:
> @@ -2934,8 +2932,6 @@ gpr_mod_mask (const struct mips_cl_insn
> mask |= 1 << EXTRACT_OPERAND (1, MP, *ip);
> if (pinfo2 & INSN2_MOD_GPR_MQ)
> mask |= 1 << micromips_to_32_reg_q_map[EXTRACT_OPERAND (1, MQ, *ip)];
> - if (pinfo2 & INSN2_MOD_SP)
> - mask |= 1 << SP;
> }
> return mask;
> }
*sigh* Have I introduced another write to an unused variable? :-(
I really should use a more modern compiler.
The removal of pinfo is OK, thanks. The rest of it doesn't look like
an improvement.
> @@ -2969,27 +2965,20 @@ gpr_read_mask (const struct mips_cl_insn
> if (pinfo & MIPS16_INSN_READ_GPR_X)
> mask |= 1 << MIPS16_EXTRACT_OPERAND (REGR32, *ip);
> }
> - else if (mips_opts.micromips)
> - {
> - if (pinfo & INSN_READ_GPR_T)
> - mask |= 1 << EXTRACT_OPERAND (1, RT, *ip);
> - if (pinfo & INSN_READ_GPR_S)
> - mask |= 1 << EXTRACT_OPERAND (1, RS, *ip);
> - if (pinfo2 & INSN2_READ_GPR_31)
> - mask |= 1 << RA;
> - if (pinfo2 & INSN2_READ_GP)
> - mask |= 1 << GP;
> - }
> else
> {
> if (pinfo2 & INSN2_READ_GPR_D)
> - mask |= 1 << EXTRACT_OPERAND (0, RD, *ip);
> + mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RD, *ip);
> if (pinfo & INSN_READ_GPR_T)
> - mask |= 1 << EXTRACT_OPERAND (0, RT, *ip);
> + mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RT, *ip);
> if (pinfo & INSN_READ_GPR_S)
> - mask |= 1 << EXTRACT_OPERAND (0, RS, *ip);
> + mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RS, *ip);
> + if (pinfo2 & INSN2_READ_GP)
> + mask |= 1 << GP;
> + if (pinfo2 & INSN2_READ_GPR_31)
> + mask |= 1 << RA;
> if (pinfo2 & INSN2_READ_GPR_Z)
> - mask |= 1 << EXTRACT_OPERAND (0, RZ, *ip);
> + mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RZ, *ip);
> }
> /* Don't include register 0. */
> return mask & ~1;
OK
> @@ -3023,23 +3012,14 @@ gpr_write_mask (const struct mips_cl_ins
> if (pinfo & MIPS16_INSN_WRITE_GPR_Y)
> mask |= 1 << MIPS16OP_EXTRACT_REG32R (ip->insn_opcode);
> }
> - else if (mips_opts.micromips)
> - {
> - if (pinfo & INSN_WRITE_GPR_D)
> - mask |= 1 << EXTRACT_OPERAND (1, RD, *ip);
> - if (pinfo & INSN_WRITE_GPR_T)
> - mask |= 1 << EXTRACT_OPERAND (1, RT, *ip);
> - if (pinfo2 & INSN2_WRITE_GPR_S)
> - mask |= 1 << EXTRACT_OPERAND (1, RS, *ip);
> - if (pinfo & INSN_WRITE_GPR_31)
> - mask |= 1 << RA;
> - }
> else
> {
> if (pinfo & INSN_WRITE_GPR_D)
> mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RD, *ip);
> if (pinfo & INSN_WRITE_GPR_T)
> mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RT, *ip);
> + if (pinfo2 & INSN2_WRITE_GPR_S)
> + mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RS, *ip);
> if (pinfo & INSN_WRITE_GPR_31)
> mask |= 1 << RA;
> if (pinfo2 & INSN2_WRITE_GPR_Z)
OK
> @@ -3060,19 +3040,10 @@ fpr_read_mask (const struct mips_cl_insn
> mask = 0;
> pinfo = ip->insn_mo->pinfo;
> pinfo2 = ip->insn_mo->pinfo2;
> - if (mips_opts.micromips)
> + if (!mips_opts.mips16)
> {
> if (pinfo2 & INSN2_READ_FPR_D)
> - mask |= 1 << EXTRACT_OPERAND (1, FD, *ip);
> - if (pinfo & INSN_READ_FPR_S)
> - mask |= 1 << EXTRACT_OPERAND (1, FS, *ip);
> - if (pinfo & INSN_READ_FPR_T)
> - mask |= 1 << EXTRACT_OPERAND (1, FT, *ip);
> - if (pinfo & INSN_READ_FPR_R)
> - mask |= 1 << EXTRACT_OPERAND (1, FR, *ip);
> - }
> - else if (!mips_opts.mips16)
> - {
> + mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FD, *ip);
> if (pinfo & INSN_READ_FPR_S)
> mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FS, *ip);
> if (pinfo & INSN_READ_FPR_T)
OK
> @@ -3100,16 +3071,7 @@ fpr_write_mask (const struct mips_cl_ins
> mask = 0;
> pinfo = ip->insn_mo->pinfo;
> pinfo2 = ip->insn_mo->pinfo2;
> - if (mips_opts.micromips)
> - {
> - if (pinfo2 & INSN_WRITE_FPR_D)
> - mask |= 1 << EXTRACT_OPERAND (1, FD, *ip);
> - if (pinfo & INSN_WRITE_FPR_S)
> - mask |= 1 << EXTRACT_OPERAND (1, FS, *ip);
> - if (pinfo & INSN_WRITE_FPR_T)
> - mask |= 1 << EXTRACT_OPERAND (1, FT, *ip);
> - }
> - else if (!mips_opts.mips16)
> + if (!mips_opts.mips16)
> {
> if (pinfo & INSN_WRITE_FPR_D)
> mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FD, *ip);
OK
> @@ -3720,8 +3683,9 @@ can_swap_branch_p (struct mips_cl_insn *
> return FALSE;
>
> /* If the previous instruction is in a variant frag other than this
> - branch's one, we cannot do the swap. This does not apply to the
> - mips16, which uses variant frags for different purposes. */
> + branch's one, we cannot do the swap. This does not apply to
> + MIPS16/microMIPS code, which uses variant frags for different
> + purposes. */
> if (!HAVE_CODE_COMPRESSION
> && history[0].frag
> && history[0].frag->fr_type == rs_machine_dependent)
OK
> ip->fixp[0] = fix_new_exp (ip->frag, ip->where,
> bfd_get_reloc_size (howto),
> address_expr,
> - howto->pc_relative, final_type[0]);
> + howto0 && howto0->pc_relative,
> + final_type[0]);
The howto0 variable and null check are OK. Please leave the rest as-is.
> Index: binutils-fsf-trunk-quilt/bfd/elfxx-mips.c
> ===================================================================
> --- binutils-fsf-trunk-quilt.orig/bfd/elfxx-mips.c 2011-07-28 23:18:50.000000000 +0100
> +++ binutils-fsf-trunk-quilt/bfd/elfxx-mips.c 2011-07-28 23:30:26.000000000 +0100
> @@ -11910,8 +11910,7 @@ mips_elf_relax_delete_bytes (bfd *abfd,
> symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
> isym = (Elf_Internal_Sym *) symtab_hdr->contents;
> for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
> - if (isym->st_shndx == sec_shndx
> - && isym->st_value > addr)
> + if (isym->st_shndx == sec_shndx && isym->st_value > addr)
> isym->st_value -= count;
>
> /* Now adjust the global symbols defined in this section. */
OK
> @@ -11989,7 +11987,7 @@ static const struct opcode_descriptor b_
> { /* "b", "mD", */ 0xcc00, 0xfc00 };
>
> static const struct opcode_descriptor bz_insn_16 =
> - { /* "b(eq|ne)z", "md,mE", */ 0x8c00, 0xac00 };
> + { /* "b(eq|ne)z", "md,mE", */ 0x8c00, 0xdc00 };
>
>
> /* 32-bit and 16-bit branch EQ and NE zero. */
I don't recall discussing this. Is it a separate thing you noticed?
OK regardless.
> @@ -12241,7 +12239,7 @@ check_br16 (bfd *abfd, bfd_byte *ptr, un
> /* If PTR points to a 32-bit branch or jump that doesn't fiddle with REG,
> then return TRUE, otherwise FALSE. */
>
> -static int
> +static bfd_boolean
> check_br32 (bfd *abfd, bfd_byte *ptr, unsigned long reg)
> {
> unsigned long opcode;
Likewise.
> @@ -12361,6 +12364,7 @@ _bfd_mips_elf_relax_section (bfd *abfd,
> else if (!bfd_malloc_and_get_section (abfd, sec, &contents))
> goto error_return;
> }
> + ptr = contents + irel->r_offset;
>
> /* Read this BFD's local symbols if we haven't done so already. */
> if (isymbuf == NULL && symtab_hdr->sh_info != 0)
OK
> @@ -12432,8 +12436,8 @@ _bfd_mips_elf_relax_section (bfd *abfd,
> if (irel->r_offset + 4 > sec->size)
> continue;
>
> - opcode = bfd_get_16 (abfd, contents + irel->r_offset ) << 16;
> - opcode |= bfd_get_16 (abfd, contents + irel->r_offset + 2);
> + opcode = bfd_get_16 (abfd, ptr ) << 16;
> + opcode |= bfd_get_16 (abfd, ptr + 2);
>
> /* This is the pc-relative distance from the instruction the
> relocation is applied to, to the symbol referred. */
OK
> @@ -12452,6 +12456,7 @@ _bfd_mips_elf_relax_section (bfd *abfd,
> out the offset). */
> if (r_type == R_MICROMIPS_HI16 && MATCH (opcode, lui_insn))
> {
> + bfd_boolean bzc = FALSE;
> unsigned long nextopc;
> unsigned long reg;
> bfd_vma offset;
and:
> @@ -12475,19 +12480,19 @@ _bfd_mips_elf_relax_section (bfd *abfd,
> && ELF32_R_SYM (irel[2].r_info) == r_symndx)
> continue;
>
> - /* See if the LUI instruction *might* be in a branch delay slot. */
> + /* See if the LUI instruction *might* be in a branch delay slot.
> + We check whether what looks like a 16-bit branch or jump is
> + actually an immediate argument to a compact branch, and let
> + it through if so. */
> if (irel->r_offset >= 2
> - && check_br16_dslot (abfd, contents + irel->r_offset - 2) > 0
> + && check_br16_dslot (abfd, ptr - 2)
> && !(irel->r_offset >= 4
> - /* If the instruction is actually a 4-byte branch,
> - the value of check_br16_dslot doesn't matter.
> - We should use check_br32_dslot to check whether
> - the branch has a delay slot. */
> - && check_4byte_branch (internal_relocs, irelend,
> - irel->r_offset - 4)))
> + && (bzc = check_bzc (abfd, ptr - 4, irel->r_offset - 4,
> + internal_relocs, irelend))))
> continue;
> if (irel->r_offset >= 4
> - && check_br32_dslot (abfd, contents + irel->r_offset - 4) > 0)
> + && !bzc
> + && check_br32_dslot (abfd, ptr - 4))
> continue;
>
> reg = OP32_SREG (opcode);
As regards what you were saying about straightening the patch up:
I think this is the one bit that ought to be split out separately
and treated as a separate patch. The bzc variable and !bzc check
look suspiciously redundant.
The use of "ptr" is OK now though.
> @@ -12502,11 +12507,11 @@ _bfd_mips_elf_relax_section (bfd *abfd,
> case 0:
> break;
> case 2:
> - if (check_br16 (abfd, contents + irel->r_offset + 4, reg))
> + if (check_br16 (abfd, ptr + 4, reg))
> break;
> continue;
> case 4:
> - if (check_br32 (abfd, contents + irel->r_offset + 4, reg))
> + if (check_br32 (abfd, ptr + 4, reg))
> break;
> continue;
> default:
OK
> @@ -12581,8 +12586,7 @@ _bfd_mips_elf_relax_section (bfd *abfd,
> && irel->r_offset + 5 < sec->size
> && ((fndopc = find_match (opcode, bz_rs_insns_32)) >= 0
> || (fndopc = find_match (opcode, bz_rt_insns_32)) >= 0)
> - && MATCH (bfd_get_16 (abfd, contents + irel->r_offset + 4),
> - nop_insn_16))
> + && MATCH (bfd_get_16 (abfd, ptr + 4), nop_insn_16))
> {
> unsigned long reg;
>
OK
> @@ -12593,10 +12597,8 @@ _bfd_mips_elf_relax_section (bfd *abfd,
> | BZC32_REG_FIELD (reg)
> | (opcode & 0xffff)); /* Addend value. */
>
> - bfd_put_16 (abfd, (opcode >> 16) & 0xffff,
> - contents + irel->r_offset);
> - bfd_put_16 (abfd, opcode & 0xffff,
> - contents + irel->r_offset + 2);
> + bfd_put_16 (abfd, (opcode >> 16) & 0xffff, ptr);
> + bfd_put_16 (abfd, opcode & 0xffff, ptr + 2);
>
> /* Delete the 16-bit delay slot NOP: two bytes from
> irel->offset + 4. */
OK
> @@ -12617,7 +12619,7 @@ _bfd_mips_elf_relax_section (bfd *abfd,
> bfd_put_16 (abfd,
> (b_insn_16.match
> | (opcode & 0x3ff)), /* Addend value. */
> - contents + irel->r_offset);
> + ptr);
>
> /* Delete 2 bytes from irel->r_offset + 2. */
> delcnt = 2;
OK
> @@ -12645,7 +12647,7 @@ _bfd_mips_elf_relax_section (bfd *abfd,
> (bz_insns_16[fndopc].match
> | BZ16_REG_FIELD (reg)
> | (opcode & 0x7f)), /* Addend value. */
> - contents + irel->r_offset);
> + ptr);
>
> /* Delete 2 bytes from irel->r_offset + 2. */
> delcnt = 2;
OK
> @@ -12661,14 +12663,13 @@ _bfd_mips_elf_relax_section (bfd *abfd,
> unsigned long n32opc;
> bfd_boolean relaxed = FALSE;
>
> - n32opc = bfd_get_16 (abfd, contents + irel->r_offset + 4) << 16;
> - n32opc |= bfd_get_16 (abfd, contents + irel->r_offset + 6);
> + n32opc = bfd_get_16 (abfd, ptr + 4) << 16;
> + n32opc |= bfd_get_16 (abfd, ptr + 6);
>
> if (MATCH (n32opc, nop_insn_32))
> {
> /* Replace delay slot 32-bit NOP with a 16-bit NOP. */
> - bfd_put_16 (abfd, nop_insn_16.match,
> - contents + irel->r_offset + 4);
> + bfd_put_16 (abfd, nop_insn_16.match, ptr + 4);
>
> relaxed = TRUE;
> }
OK
> @@ -12679,7 +12680,7 @@ _bfd_mips_elf_relax_section (bfd *abfd,
> (move_insn_16.match
> | MOVE16_RD_FIELD (MOVE32_RD (n32opc))
> | MOVE16_RS_FIELD (MOVE32_RS (n32opc))),
> - contents + irel->r_offset + 4);
> + ptr + 4);
>
> relaxed = TRUE;
> }
OK
> @@ -12691,9 +12692,9 @@ _bfd_mips_elf_relax_section (bfd *abfd,
> /* JAL with 32-bit delay slot that is changed to a JALS
> with 16-bit delay slot. */
> bfd_put_16 (abfd, (jal_insn_32_bd16.match >> 16) & 0xffff,
> - contents + irel->r_offset);
> + ptr);
> bfd_put_16 (abfd, jal_insn_32_bd16.match & 0xffff,
> - contents + irel->r_offset + 2);
> + ptr + 2);
>
> /* Delete 2 bytes from irel->r_offset + 6. */
> delcnt = 2;
OK
> Index: binutils-fsf-trunk-quilt/include/opcode/mips.h
> ===================================================================
> --- binutils-fsf-trunk-quilt.orig/include/opcode/mips.h 2011-07-28 23:29:25.000000000 +0100
> +++ binutils-fsf-trunk-quilt/include/opcode/mips.h 2011-07-28 23:30:26.000000000 +0100
> @@ -1332,13 +1332,10 @@ extern int bfd_mips_num_opcodes;
> extern const struct mips_opcode mips16_opcodes[];
> extern const int bfd_mips16_num_opcodes;
>
> -/* These are the bitmasks and shift counts used for the different
> - fields in the instruction formats. Other than MAJOR, no masks are
> - provided for the fixed portions of an instruction, since they are
> - not needed. */
> +/* These are the bit masks and shift counts used for the different fields
> + in the microMIPS instruction formats. No masks are provided for the
> + fixed portions of an instruction, since they are not needed. */
>
> -#define MICROMIPSOP_MASK_MAJOR 0x3f
> -#define MICROMIPSOP_SH_MAJOR 26
> #define MICROMIPSOP_MASK_IMMEDIATE 0xffff
> #define MICROMIPSOP_SH_IMMEDIATE 0
> #define MICROMIPSOP_MASK_DELTA 0xffff
OK
Thanks,
Richard
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] MIPS: microMIPS ASE support
2011-07-29 11:30 ` Richard Sandiford
@ 2011-07-29 22:52 ` Maciej W. Rozycki
0 siblings, 0 replies; 41+ messages in thread
From: Maciej W. Rozycki @ 2011-07-29 22:52 UTC (permalink / raw)
To: Richard Sandiford
Cc: binutils, Chao-ying Fu, Rich Fuhler, David Lau, Kevin Mills,
Ilie Garbacea, Catherine Moore, Nathan Sidwell, Joseph Myers
On Fri, 29 Jul 2011, Richard Sandiford wrote:
> >> There's a whole lot of important linker relaxation fixes that I reckon
> >> were not included in the original series plus several bug fixes.
> >
> > I'll work on these fixes now -- there are quite a few and at least one
> > still requires some work not to be considered a dirty hack -- and will be
> > back with you shortly.
>
> Thanks. This is what I asked for in the first place: that anything we
> hadn't caught should be dealt with as follow-ups, rather than folded
> into the huge initial commit. (For reference, even the .tar.bz2 was
> over 280k.) I still don't understand why you chose to ignore that.
Well, I believed this was really what I did -- with all these
binutils-ld-lib.diff, binutils-umips-fix.diff,
binutils-umips-opcode-trap.diff, binutils-umips-relax16.diff,
binutils-umips-fix-reloc.diff patches (and all the outstanding ones that
add up to six right now, but will probably become seven or eight) -- but
if that wasn't what you intended, then I apologise for misunderstanding.
> The whole point of approving most of the submission with a few minor
> changes (back in March) was that it would be quick to make those changes
> and get the whole thing into CVS. It would then be much easier for me
> to review any further changes you wanted to make. I also assumed that
> it would be easier for you to submit them.
The problem was I was pulled off to another project as a matter of
emergency -- apart from the update to take your recent register use
tracking changes into account I did last week, I haven't really touched
the pieces for a couple of months now. Sorry about that.
I'll go on to explain the bits you had anything but "OK" to say about,
commit the bits you are happy with and then we can continue with the rest.
> > @@ -2893,18 +2888,21 @@ relax_end (void)
> > mips_relax.sequence = 0;
> > }
> >
> > -/* Return the mask of core registers that instruction IP may
> > - read or write. */
> > +/* Return the mask of core registers that IP reads or writes. */
> >
> > static unsigned int
> > gpr_mod_mask (const struct mips_cl_insn *ip)
> > {
> > - unsigned long pinfo, pinfo2;
> > + unsigned long pinfo2;
> > unsigned int mask;
> >
> > mask = 0;
> > - pinfo = ip->insn_mo->pinfo;
> > pinfo2 = ip->insn_mo->pinfo2;
> > + if (!mips_opts.mips16)
> > + {
> > + if (pinfo2 & INSN2_MOD_SP)
> > + mask |= 1 << SP;
> > + }
> > if (mips_opts.micromips)
> > {
> > if (pinfo2 & INSN2_MOD_GPR_MB)
> and:
> > @@ -2934,8 +2932,6 @@ gpr_mod_mask (const struct mips_cl_insn
> > mask |= 1 << EXTRACT_OPERAND (1, MP, *ip);
> > if (pinfo2 & INSN2_MOD_GPR_MQ)
> > mask |= 1 << micromips_to_32_reg_q_map[EXTRACT_OPERAND (1, MQ, *ip)];
> > - if (pinfo2 & INSN2_MOD_SP)
> > - mask |= 1 << SP;
> > }
> > return mask;
> > }
>
> *sigh* Have I introduced another write to an unused variable? :-(
> I really should use a more modern compiler.
>
> The removal of pinfo is OK, thanks. The rest of it doesn't look like
> an improvement.
For the sake of consistency I put all the pinfo/2 flag interpretation
that does not involve microMIPS-specific structures (i.e.
micromips_to_32_reg_*_map) into (!mips_opts.mips16) rather than
(mips_opts.micromips) condition blocks under the assumption we don't have
to imply their microMIPS-ness here.
Obviously this includes the INSN2_MOD_SP flag as it's self-contained in
that it determines the register accessed itself, though it probably has
little chance to be useful for non-microMIPS code even with possible
future extensions to the base architecture. Therefore I won't insist on
this change even though it's consistent with the usage of INSN2_READ_GP
and INSN2_READ_GPR_31 flags in gpr_read_mask().
> > ip->fixp[0] = fix_new_exp (ip->frag, ip->where,
> > bfd_get_reloc_size (howto),
> > address_expr,
> > - howto->pc_relative, final_type[0]);
> > + howto0 && howto0->pc_relative,
> > + final_type[0]);
>
> The howto0 variable and null check are OK. Please leave the rest as-is.
There's no need to reiterate checking for non-BFD_RELOC_UNUSED that's
been already done earlier on. I'll split it off for further
consideration.
> > @@ -11989,7 +11987,7 @@ static const struct opcode_descriptor b_
> > { /* "b", "mD", */ 0xcc00, 0xfc00 };
> >
> > static const struct opcode_descriptor bz_insn_16 =
> > - { /* "b(eq|ne)z", "md,mE", */ 0x8c00, 0xac00 };
> > + { /* "b(eq|ne)z", "md,mE", */ 0x8c00, 0xdc00 };
> >
> >
> > /* 32-bit and 16-bit branch EQ and NE zero. */
>
> I don't recall discussing this. Is it a separate thing you noticed?
> OK regardless.
Well, there's nothing to discuss here -- it's a plain bug, the old mask
is wrong and there was no need to handle it separately -- in fact the
opposite was the case as it makes no sense to check in known-buggy code.
I'll split it off and commit separately for clarity.
> > @@ -12241,7 +12239,7 @@ check_br16 (bfd *abfd, bfd_byte *ptr, un
> > /* If PTR points to a 32-bit branch or jump that doesn't fiddle with REG,
> > then return TRUE, otherwise FALSE. */
> >
> > -static int
> > +static bfd_boolean
> > check_br32 (bfd *abfd, bfd_byte *ptr, unsigned long reg)
> > {
> > unsigned long opcode;
>
> Likewise.
I'll split it off too.
> > @@ -12452,6 +12456,7 @@ _bfd_mips_elf_relax_section (bfd *abfd,
> > out the offset). */
> > if (r_type == R_MICROMIPS_HI16 && MATCH (opcode, lui_insn))
> > {
> > + bfd_boolean bzc = FALSE;
> > unsigned long nextopc;
> > unsigned long reg;
> > bfd_vma offset;
> and:
> > @@ -12475,19 +12480,19 @@ _bfd_mips_elf_relax_section (bfd *abfd,
> > && ELF32_R_SYM (irel[2].r_info) == r_symndx)
> > continue;
> >
> > - /* See if the LUI instruction *might* be in a branch delay slot. */
> > + /* See if the LUI instruction *might* be in a branch delay slot.
> > + We check whether what looks like a 16-bit branch or jump is
> > + actually an immediate argument to a compact branch, and let
> > + it through if so. */
> > if (irel->r_offset >= 2
> > - && check_br16_dslot (abfd, contents + irel->r_offset - 2) > 0
> > + && check_br16_dslot (abfd, ptr - 2)
> > && !(irel->r_offset >= 4
> > - /* If the instruction is actually a 4-byte branch,
> > - the value of check_br16_dslot doesn't matter.
> > - We should use check_br32_dslot to check whether
> > - the branch has a delay slot. */
> > - && check_4byte_branch (internal_relocs, irelend,
> > - irel->r_offset - 4)))
> > + && (bzc = check_bzc (abfd, ptr - 4, irel->r_offset - 4,
> > + internal_relocs, irelend))))
> > continue;
> > if (irel->r_offset >= 4
> > - && check_br32_dslot (abfd, contents + irel->r_offset - 4) > 0)
> > + && !bzc
> > + && check_br32_dslot (abfd, ptr - 4))
> > continue;
> >
> > reg = OP32_SREG (opcode);
>
> As regards what you were saying about straightening the patch up:
> I think this is the one bit that ought to be split out separately
> and treated as a separate patch. The bzc variable and !bzc check
> look suspiciously redundant.
It's a small optimisation -- if we've established for sure the
instruction before is a compact branch, then there's no need to go through
the hoops and check if it's an ordinary branch too -- which it will never
be.
I'll split this change off of course.
Thanks for the quick review.
Maciej
^ permalink raw reply [flat|nested] 41+ messages in thread
end of thread, other threads:[~2011-07-29 17:40 UTC | newest]
Thread overview: 41+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-05-18 18:19 [PATCH] MIPS: microMIPS and MCU ASE instruction set support Maciej W. Rozycki
2010-05-23 21:38 ` Richard Sandiford
2010-05-24 22:25 ` Fu, Chao-Ying
2010-05-26 19:47 ` Richard Sandiford
2010-06-01 14:21 ` Maciej W. Rozycki
2010-06-01 14:39 ` Catherine Moore
2010-06-01 22:04 ` Richard Sandiford
2010-06-01 22:47 ` Fu, Chao-Ying
2010-06-05 9:17 ` Richard Sandiford
2010-07-26 10:56 ` [PATCH] MIPS: microMIPS ASE support Maciej W. Rozycki
2010-07-26 13:25 ` Nathan Froyd
2010-07-26 13:53 ` Maciej W. Rozycki
2010-07-26 19:03 ` Richard Sandiford
2010-12-07 1:13 ` Maciej W. Rozycki
2010-12-12 14:59 ` Richard Sandiford
2010-12-14 13:30 ` Maciej W. Rozycki
2010-12-14 14:51 ` Richard Sandiford
2010-12-16 11:54 ` Maciej W. Rozycki
2010-12-18 10:26 ` Richard Sandiford
2010-12-14 17:56 ` Joseph S. Myers
2010-12-16 15:28 ` Maciej W. Rozycki
2010-12-17 20:56 ` Fu, Chao-Ying
2010-12-18 10:09 ` Richard Sandiford
2011-01-02 11:36 ` Richard Sandiford
2011-02-21 15:35 ` Maciej W. Rozycki
2011-02-22 20:12 ` Fu, Chao-Ying
2011-02-22 20:19 ` Fu, Chao-Ying
2011-02-24 10:46 ` Maciej W. Rozycki
2011-02-26 11:41 ` Richard Sandiford
2011-02-28 16:41 ` Maciej W. Rozycki
2011-02-26 0:00 ` Maciej W. Rozycki
2011-03-13 9:23 ` Richard Sandiford
2011-07-25 7:49 ` Richard Sandiford
2011-07-26 2:01 ` Maciej W. Rozycki
2011-07-29 0:58 ` Maciej W. Rozycki
2011-07-29 11:30 ` Richard Sandiford
2011-07-29 22:52 ` Maciej W. Rozycki
2011-02-26 11:36 ` Richard Sandiford
2011-07-26 14:00 ` Maciej W. Rozycki
2010-05-26 20:19 ` [PATCH] MIPS: microMIPS and MCU ASE instruction set support Richard Sandiford
2010-05-27 21:39 ` Richard Sandiford
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).