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