From: Bob Wilson Date: Fri, 8 Oct 2004 00:22:15 +0000 (+0000) Subject: bfd ChangeLog X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=43cd72b9aa3a95b0345587974c14b6d237f79a5f;p=binutils-gdb.git bfd ChangeLog * elf32-xtensa.c (elf32xtensa_size_opt): New global variable. (xtensa_default_isa): Global variable moved here from xtensa-isa.c. (elf32xtensa_no_literal_movement): New global variable. (elf_howto_table): Add entries for new relocations. (elf_xtensa_reloc_type_lookup): Handle new relocations. (property_table_compare): When addresses are equal, compare sizes and various property flags. (property_table_matches): New. (xtensa_read_table_entries): Extend to read new property tables. Add output_addr parameter to indicate that output addresses should be used. Use bfd_get_section_limit. (elf_xtensa_find_property_entry): New. (elf_xtensa_in_literal_pool): Use elf_xtensa_find_property_entry. (elf_xtensa_check_relocs): Handle new relocations. (elf_xtensa_do_reloc): Use bfd_get_section_limit. Handle new relocations. Use new xtensa-isa.h functions. (build_encoding_error_message): Remove encode_result parameter. Add new target_address parameter used to detect alignment errors. (elf_xtensa_relocate_section): Use bfd_get_section_limit. Clean up error handling. Use new is_operand_relocation function. (elf_xtensa_combine_prop_entries, elf_xtensa_merge_private_bfd_data): Use underbar macro for error messages. Formatting. (get_const16_opcode): New. (get_l32r_opcode): Add a separate flag for initialization. (get_relocation_opnd): Operand number is no longer explicit in the relocation. Change to decode the opcode and analyze its operands. (get_relocation_slot): New. (get_relocation_opcode): Add bfd parameter. Use bfd_get_section_limit. Use new xtensa-isa.h functions to handle multislot instructions. (is_l32r_relocation): Add bfd parameter. Use is_operand_relocation. (get_asm_simplify_size, is_alt_relocation, is_operand_relocation, insn_decode_len, insn_decode_opcode, check_branch_target_aligned, check_loop_aligned, check_branch_target_aligned_address, narrowable, widenable, narrow_instruction, widen_instruction, op_single_fmt_table, get_single_format, init_op_single_format_table): New. (elf_xtensa_do_asm_simplify): Add error_message parameter and use it instead of calling _bfd_error_handler. Use new xtensa-isa.h functions. (contract_asm_expansion): Add error_message parameter and pass it to elf_xtensa_do_asm_simplify. Replace use of R_XTENSA_OP0 relocation with R_XTENSA_SLOT0_OP. (get_expanded_call_opcode): Extend to handle either L32R or CONST16 instructions. Use new xtensa-isa.h functions. (r_reloc struct): Add new virtual_offset field. (r_reloc_init): Add contents and content_length parameters. Set virtual_offset field to zero. Add contents to target_offset field for partial_inplace relocations. (r_reloc_is_defined): Check for null. (print_r_reloc): New debug function. (source_reloc struct): Replace xtensa_operand field with pair of the opcode and the operand position. Add is_abs_literal field. (init_source_reloc): Specify operand by opcode/position pair. Set is_abs_literal field. (source_reloc_compare): When target_offsets are equal, compare other fields to make sorting predictable. (literal_value struct): Add is_abs_literal field. (value_map_hash_table struct): Add has_last_loc and last_loc fields. (init_literal_value): New. (is_same_value): Replace with ... (literal_value_equal): ... this function. Add comparisons of virtual_offset and is_abs_literal fields. (value_map_hash_table_init): Use bfd_zmalloc. Check for allocation failure. Initialize has_last_loc field. (value_map_hash_table_delete): New. (hash_literal_value): Rename to ... (literal_value_hash): ... this. Include is_abs_literal flag and virtual_offset field in the hash value. (get_cached_value): Rename to ... (value_map_get_cached_value): ... this. Update calls to literal_value_hash and literal_value_equal. (add_value_map): Check for allocation failure. Update calls to value_map_get_cached_value and literal_value_hash. (text_action, text_action_list, text_action_t): New types. (find_fill_action, compute_removed_action_diff, adjust_fill_action, text_action_add, text_action_add_literal, offset_with_removed_text, offset_with_removed_text_before_fill, find_insn_action, print_action_list, print_removed_literals): New. (offset_with_removed_literals): Delete. (xtensa_relax_info struct): Add is_relaxable_asm_section, action_list, fix_array, fix_array_count, allocated_relocs, relocs_count, and allocated_relocs_count fields. (init_xtensa_relax_info): Initialize new fields. (reloc_bfd_fix struct): Add new translated field. (reloc_bfd_fix_init): Add translated parameter and use it to set the translated field. (fix_compare, cache_fix_array): New. (get_bfd_fix): Remove fix_list parameter and get all relax_info for the section via get_xtensa_relax_info. Use cache_fix_array to set up sorted fix_array and use bsearch instead of linear search. (section_cache_t): New struct. (init_section_cache, section_cache_section, clear_section_cache): New. (ebb_t, ebb_target_enum, proposed_action, ebb_constraint): New types. (init_ebb_constraint, free_ebb_constraint, init_ebb, extend_ebb_bounds, extend_ebb_bounds_forward, extend_ebb_bounds_backward, insn_block_decodable_len, ebb_propose_action, ebb_add_proposed_action): New. (retrieve_contents): Use bfd_get_section_limit. (elf_xtensa_relax_section): Add relocations_analyzed flag. Update call to compute_removed_literals. Free value_map_hash_table when no longer needed. (analyze_relocations): Check is_relaxable_asm_section flag. Call compute_text_actions for all sections. (find_relaxable_sections): Mark sections as relaxable if they contain ASM_EXPAND relocations that can be optimized. Adjust r_reloc_init call. Increment relax_info src_count field only for appropriate relocation types. Remove is_literal_section check. (collect_source_relocs): Use bfd_get_section_limit. Adjust calls to r_reloc_init and find_associated_l32r_irel. Check is_relaxable_asm_section flag. Handle L32R instructions with absolute literals. Pass is_abs_literal flag to init_source_reloc. (is_resolvable_asm_expansion): Use bfd_get_section_limit. Check for CONST16 instructions. Adjust calls to r_reloc_init and pcrel_reloc_fits. Handle weak symbols conservatively. (find_associated_l32r_irel): Add bfd parameter and pass it to is_l32r_relocation. (compute_text_actions, compute_ebb_proposed_actions, compute_ebb_actions, check_section_ebb_pcrels_fit, check_section_ebb_reduces, text_action_add_proposed, compute_fill_extra_space): New. (remove_literals): Replace with ... (compute_removed_literals): ... this function. Call init_section_cache. Use bfd_get_section_limit. Sort internal_relocs. Call xtensa_read_table_entries to get the property table. Skip relocations other than R_XTENSA_32 and R_XTENSA_PLT. Use new is_removable_literal, remove_dead_literal, and identify_literal_placement functions. (get_irel_at_offset): Rewrite to use bsearch on sorted relocations instead of linear search. (is_removable_literal, remove_dead_literal, identify_literal_placement): New. (relocations_reach): Update check for literal not referenced by any PC-relative relocations. Adjust call to pcrel_reloc_fits. (coalesce_shared_literal, move_shared_literal): New. (relax_section): Use bfd_get_section_limit. Call translate_section_fixes. Update calls to r_reloc_init and offset_with_removed_text. Check new is_relaxable_asm_section flag. Add call to pin_internal_relocs. Add special handling for R_XTENSA_ASM_SIMPLIFY and R_XTENSA_DIFF* relocs. Use virtual_offset info to calculate new addend_displacement variable. Replace code for deleting literals with more general code to perform the actions determined by the action_list for the section. (translate_section_fixes, translate_reloc_bfd_fix): New. (translate_reloc): Check new is_relaxable_asm_section flag. Call find_removed_literal only if is_operand_relocation. Update call to offset_with_removed_text. Use new target_offset and removed_bytes variables. (move_literal): New. (relax_property_section): Use bfd_get_section_limit. Set new is_full_prop_section flag and handle new property tables. Update calls to r_reloc_init and offset_with_removed_text. Check is_relaxable_asm_section flag. Handle expansion of zero-sized unreachable entries, with use of offset_with_removed_text_before_fill. For relocatable links, combine entries only for literal tables. (relax_section_symbols): Check is_relaxable_asm_section flag. Update calls to offset_with_removed_text. Translate st_size field for function symbols. (do_fix_for_relocatable_link): Change to return bfd_boolean to indicate failure. Add contents parameter. Update call to get_bfd_fix. Update call to r_reloc_init. Call _bfd_error_handler and return FALSE for R_XTENSA_ASM_EXPAND relocs. (do_fix_for_final_link): Add input_bfd and contents parameters. Update call to get_bfd_fix. Include offset from contents for partial_inplace relocations. (is_reloc_sym_weak): New. (pcrel_reloc_fits): Use new xtensa-isa.h functions. (prop_sec_len): New. (xtensa_is_property_section): Handle new property sections. (is_literal_section): Delete. (internal_reloc_compare): When r_offset matches, compare r_info and r_addend to make sorting predictable. (internal_reloc_matches): New. (xtensa_get_property_section_name): Handle new property sections. (xtensa_get_property_predef_flags): New. (xtensa_callback_required_dependence): Use bfd_get_section_limit. Update calls to xtensa_isa_init, is_l32r_relocation, and r_reloc_init. * xtensa-isa.c (xtensa_default_isa): Moved to elf32-xtensa.c. (xtisa_errno, xtisa_error_msg): New variables. (xtensa_isa_errno, xtensa_isa_error_msg): New. (xtensa_insnbuf_alloc): Add error handling. (xtensa_insnbuf_to_chars): Add num_chars parameter. Update to use xtensa_format_decode. Add error handling. (xtensa_insnbuf_from_chars): Add num_chars parameter. Decode the instruction length to find the number of bytes to copy. (xtensa_isa_init): Add error handling. Replace calls to xtensa_load_isa and xtensa_extend_isa with code to initialize lookup tables in the xtensa_modules structure. (xtensa_check_isa_config, xtensa_add_isa, xtensa_load_isa, xtensa_extend_isa): Delete. (xtensa_isa_free): Change to only free lookup tables. (opname_lookup_compare): Replace with ... (xtensa_isa_name_compare): ... this function. Use strcasecmp. (xtensa_insn_maxlength): Rename to ... (xtensa_isa_maxlength): ... this. (xtensa_insn_length): Delete. (xtensa_insn_length_from_first_byte): Replace with ... (xtensa_isa_length_from_chars): ... this function. (xtensa_num_opcodes): Rename to ... (xtensa_isa_num_opcodes): ... this. (xtensa_isa_num_pipe_stages, xtensa_isa_num_formats, xtensa_isa_num_regfiles, xtensa_isa_num_stages, xtensa_isa_num_sysregs, xtensa_isa_num_interfaces, xtensa_isa_num_funcUnits, xtensa_format_name, xtensa_format_lookup, xtensa_format_decode, xtensa_format_encode, xtensa_format_length, xtensa_format_num_slots, xtensa_format_slot_nop_opcode, xtensa_format_get_slot, xtensa_format_set_slot): New functions. (xtensa_opcode_lookup): Add error handling. (xtensa_decode_insn): Replace with ... (xtensa_opcode_decode): ... this function, with new format and slot parameters. Add error handling. (xtensa_encode_insn): Replace with ... (xtensa_opcode_encode): ... this function, which does the encoding via one of the entries in the "encode_fns" array. Add error handling. (xtensa_opcode_name): Add error handling. (xtensa_opcode_is_branch, xtensa_opcode_is_jump, xtensa_opcode_is_loop, xtensa_opcode_is_call): New. (xtensa_num_operands): Replace with ... (xtensa_opcode_num_operands): ... this function. Add error handling. (xtensa_opcode_num_stateOperands, xtensa_opcode_num_interfaceOperands, xtensa_opcode_num_funcUnit_uses, xtensa_opcode_funcUnit_use, xtensa_operand_name, xtensa_operand_is_visible): New. (xtensa_get_operand, xtensa_operand_kind): Delete. (xtensa_operand_inout): Add error handling and special-case for "sout" operands. (xtensa_operand_get_field, xtensa_operand_set_field): Rewritten to operate on one slot of an instruction. Added error handling. (xtensa_operand_encode): Handle default operands with no encoding functions. Check for success by comparing against decoded value. Add error handling. (xtensa_operand_decode): Handle default operands. Return decoded value through argument pointer. Add error handling. (xtensa_operand_is_register, xtensa_operand_regfile, xtensa_operand_num_regs, xtensa_operand_is_known_reg): New. (xtensa_operand_isPCRelative): Rename to ... (xtensa_operand_is_PCrelative): ... this. Add error handling. (xtensa_operand_do_reloc, xtensa_operand_undo_reloc): Return value through argument pointer. Add error handling. (xtensa_stateOperand_state, xtensa_stateOperand_inout, xtensa_interfaceOperand_interface, xtensa_regfile_lookup, xtensa_regfile_lookup_shortname, xtensa_regfile_name, xtensa_regfile_shortname, xtensa_regfile_view_parent, xtensa_regfile_num_bits, xtensa_regfile_num_entries, xtensa_state_lookup, xtensa_state_name, xtensa_state_num_bits, xtensa_state_is_exported, xtensa_sysreg_lookup, xtensa_sysreg_lookup_name, xtensa_sysreg_name, xtensa_sysreg_number, xtensa_sysreg_is_user, xtensa_interface_lookup, xtensa_interface_name, xtensa_interface_num_bits, xtensa_interface_inout, xtensa_interface_has_side_effect, xtensa_funcUnit_lookup, xtensa_funcUnit_name, xtensa_funcUnit_num_copies): New. * xtensa-modules.c: Rewrite to use new data structures. * reloc.c (BFD_RELOC_XTENSA_DIFF8, BFD_RELOC_XTENSA_DIFF16, BFD_RELOC_XTENSA_DIFF32, BFD_RELOC_XTENSA_SLOT0_OP, BFD_RELOC_XTENSA_SLOT1_OP, BFD_RELOC_XTENSA_SLOT2_OP, BFD_RELOC_XTENSA_SLOT3_OP, BFD_RELOC_XTENSA_SLOT4_OP, BFD_RELOC_XTENSA_SLOT5_OP, BFD_RELOC_XTENSA_SLOT6_OP, BFD_RELOC_XTENSA_SLOT7_OP, BFD_RELOC_XTENSA_SLOT8_OP, BFD_RELOC_XTENSA_SLOT9_OP, BFD_RELOC_XTENSA_SLOT10_OP, BFD_RELOC_XTENSA_SLOT11_OP, BFD_RELOC_XTENSA_SLOT12_OP, BFD_RELOC_XTENSA_SLOT13_OP, BFD_RELOC_XTENSA_SLOT14_OP, BFD_RELOC_XTENSA_SLOT0_ALT, BFD_RELOC_XTENSA_SLOT1_ALT, BFD_RELOC_XTENSA_SLOT2_ALT, BFD_RELOC_XTENSA_SLOT3_ALT, BFD_RELOC_XTENSA_SLOT4_ALT, BFD_RELOC_XTENSA_SLOT5_ALT, BFD_RELOC_XTENSA_SLOT6_ALT, BFD_RELOC_XTENSA_SLOT7_ALT, BFD_RELOC_XTENSA_SLOT8_ALT, BFD_RELOC_XTENSA_SLOT9_ALT, BFD_RELOC_XTENSA_SLOT10_ALT, BFD_RELOC_XTENSA_SLOT11_ALT, BFD_RELOC_XTENSA_SLOT12_ALT, BFD_RELOC_XTENSA_SLOT13_ALT, BFD_RELOC_XTENSA_SLOT14_ALT): Add new relocations. * Makefile.am (xtensa-isa.lo, xtensa-modules.lo): Update dependencies. * Makefile.in: Regenerate. * bfd-in2.h: Likewise. * libbfd.h: Likewise. gas ChangeLog * config/tc-xtensa.c (absolute_literals_supported): New global flag. (UNREACHABLE_MAX_WIDTH): Define. (XTENSA_FETCH_WIDTH): Delete. (cur_vinsn, xtensa_fetch_width, xt_saved_debug_type, past_xtensa_end, prefer_const16, prefer_l32r): New global variables. (LIT4_SECTION_NAME): Define. (lit4_state struct): Add lit4_seg_name and lit4_seg fields. (XTENSA_PROP_*, GET_XTENSA_PROP_*, SET_XTENSA_PROP_*): Define. (frag_flags struct): New. (xtensa_block_info struct): Move from tc-xtensa.h. Add flags field. (subseg_map struct): Add cur_total_freq and cur_target_freq fields. (bitfield, bit_is_set, set_bit, clear_bit): Define. (MAX_FORMATS): Define. (op_placement_info struct, op_placement_table): New. (O_pltrel, O_hi16, O_lo16): Define. (directiveE enum): Rename directive_generics to directive_transform. Delete directive_relax. Add directive_schedule, directive_absolute_literals, and directive_last_directive. (directive_info): Rename "generics" to "transform". Delete "relax". Add "schedule" and "absolute-literals". (directive_state): Adjust entries to match changes in directive_info. (xtensa_relax_statesE, RELAX_IMMED_MAXSTEPS): Move to tc-xtensa.h. (xtensa_const16_opcode, xtensa_movi_opcode, xtensa_movi_n_opcode, xtensa_l32r_opcode, xtensa_nop_opcode, xtensa_rsr_lcount_opcode): New. (xtensa_j_opcode, xtensa_rsr_opcode): Delete. (align_only_targets, software_a0_b_retw_interlock, software_avoid_b_j_loop_end, maybe_has_b_j_loop_end, software_avoid_short_loop, software_avoid_close_loop_end, software_avoid_all_short_loops, specific_opcode): Delete. (warn_unaligned_branch_targets): New. (workaround_a0_b_retw, workaround_b_j_loop_end, workaround_short_loop, workaround_close_loop_end, workaround_all_short_loops): Default FALSE. (option_[no_]link_relax, option_[no_]transform, option_[no_]absolute_literals, option_warn_unaligned_targets, option_prefer_l32r, option_prefer_const16, option_target_hardware): New enum values. (option_[no_]align_only_targets, option_literal_section_name, option_text_section_name, option_data_section_name, option_bss_section_name, option_eb, option_el): Delete. (md_longopts): Add entries for: [no-]transform, [no-]absolute-literals, warn-unaligned-targets, prefer-l32r, prefer-const16, [no-]link-relax, and target-hardware. Delete entries for [no-]target-align-only, literal-section-name, text-section-name, data-section-name, and bss-section-name. (md_parse_option): Handle new options and remove old ones. Accept but ignore [no-]density options. Warn for [no-]generics and [no-]relax and treat them as [no-]transform. (md_show_usage): Add new options and remove old ones. (xtensa_setup_hw_workarounds): New. (md_pseudo_table): Change "word" entry to use xtensa_elf_cons. Add "long", "short", "loc" and "frequency" entries. (use_generics): Rename to ... (use_transform): ... this function. Add past_xtensa_end check. (use_longcalls): Add past_xtensa_end check. (code_density_available, can_relax): Delete. (do_align_targets): New. (get_directive): Accept dashes in directive names. Warn about [no-]generics and [no-]relax directives and treat them as [no-]transform. (xtensa_begin_directive): Call md_flush_pending_output only for some directives. Check for directives inside instruction bundles. Warn about deprecated ".begin literal" usage. Warn and ignore [no-]density directives. Handle new directives. Check generating_literals flag for literal_prefix. (xtensa_end_directive): Check for directives inside instruction bundles. Warn and ignore [no-]density directives. Handle new directives. Call xtensa_set_frag_assembly_state. (xtensa_loc_directive_seen, xtensa_dwarf2_directive_loc, xtensa_dwarf2_emit_insn): New. (xtensa_literal_position): Call md_flush_pending_output. Do not check use_literal_section flag. (xtensa_literal_pseudo): Call md_flush_pending_output. Handle absolute literals. Use xtensa_elf_cons to parse the expression. (xtensa_literal_prefix): Do not check use_literal_section. Support ".lit4" sections for absolute literals. Change prefix convention to replace ".text" (or ".t" in a linkonce section). No need to call subseg_set. (xtensa_frequency_pseudo, xtensa_elf_cons, xtensa_elf_suffix): New. (expression_end): Handle closing braces and colons. (PLT_SUFFIX, plt_suffix): Delete. (expression_maybe_register): Use new xtensa-isa.h functions. Use xtensa_elf_suffix instead of checking for plt suffix, and handle O_lo16 and O_hi16 expressions as well. (tokenize_arguments): Handle closing braces and colons. (parse_arguments): Use new xtensa-isa.h functions. Handle "invisible" operands and paired register syntax. (get_invisible_operands): New. (xg_translate_sysreg_op): Handle new Xtensa LX RSR/WSR/XSR syntax. Use new xtensa-isa.h functions. (xtensa_translate_old_userreg_ops, xtensa_translate_zero_immed): New. (xg_translate_idioms): Check if inside bundle. Use use_transform. Handle new Xtensa LX RSR/WSR/XSR syntax. Remove code to widen density instructions. Use xtensa_translate_zero_immed. (operand_is_immed, operand_is_pcrel_label): Delete. (get_relaxable_immed): Use new xtensa-isa.h functions. (get_opcode_from_buf): Add slot parameter. Use new xtensa-isa.h functions. (xtensa_print_insn_table, print_vliw_insn): New. (is_direct_call_opcode): Use new xtensa-isa.h functions. (is_call_opcode, is_loop_opcode, is_conditional_branch_opcode, is_branch_or_jump_opcode): Delete. (is_movi_opcode, decode_reloc, encode_reloc, encode_alt_reloc): New. (opnum_to_reloc, reloc_to_opnum): Delete. (xtensa_insnbuf_set_operand, xtensa_insnbuf_get_operand): Use new xtensa-isa.h functions. Operate on one slot of an instruction. (xtensa_insnbuf_set_immediate_field, is_negatable_branch, xg_get_insn_size): Delete. (xg_get_build_instr_size): Use xg_get_single_size. (xg_is_narrow_insn, xg_is_single_relaxable_insn): Update calls to xg_build_widen_table. Use xg_get_single_size. (xg_get_max_narrow_insn_size): Delete. (xg_get_max_insn_widen_size, xg_get_max_insn_widen_literal_size, xg_is_relaxable_insn): Update calls to xg_build_widen_table. Use xg_get_single_size. (xg_build_to_insn): Record the loc field. Handle OP_OPERAND_HI16U and OP_OPERAND_LOW16U. Check xg_valid_literal_expression. (xg_expand_to_stack, xg_expand_narrow): Update calls to xg_build_widen_table. Use xg_get_single_size. (xg_immeds_fit): Use new xtensa-isa.h functions. Update call to xg_check_operand. (xg_symbolic_immeds_fit): Likewise. Also handle O_lo16 and O_hi16, and treat weak symbols conservatively. (xg_check_operand): Use new xtensa-isa.h functions. (is_dnrange): Delete. (xg_assembly_relax): Inline previous calls to tinsn_copy. (xg_finish_frag): Specify separate relax states for the frag and slot0. (is_branch_jmp_to_next, xg_add_branch_and_loop_targets): Use new xtensa-isa.h functions. (xg_instruction_matches_option_term, xg_instruction_matches_or_options, xg_instruction_matches_options): New. (xg_instruction_matches_rule): Handle O_register expressions. Call xg_instruction_matches_options. (transition_rule_cmp): New. (xg_instruction_match): Update call to xg_build_simplify_table. (xg_build_token_insn): Record loc fields. (xg_simplify_insn): Check is_specific_opcode field and density_supported flag. (xg_expand_assembly_insn): Skip checking code_density_available. Use new xtensa-isa.h functions. Call use_transform instead of can_relax. (xg_assemble_literal): Add error handling for O_big. Call record_alignment. Handle O_pltrel. (xg_valid_literal_expression): New. (xg_assemble_literal_space): Add slot parameter. Remove call to set_expr_symbol_offset. Add call to record_alignment. Update call to xg_finish_frag. (xg_emit_insn): Delete. (xg_emit_insn_to_buf): Add format parameter. Update calls to xg_add_opcode_fix and xtensa_insnbuf_to_chars. (xg_add_opcode_fix): Change opcode parameter to tinsn and add format and slot parameters. Handle new "alternate" relocations for absolute literals and CONST16 instructions. Check for bad uses of O_lo16 and O_hi16. Use new xtensa-isa.h functions. (xg_assemble_tokens): Delete. (is_register_writer): Use new xtensa-isa.h functions. (is_bad_loopend_opcode): Check for xtensa_rsr_lcount_opcode instead of old-style RSR from LCOUNT. (next_frag_opcode): Delete. (next_frag_opcode_is_loop, next_frag_format_size, frag_format_size, update_next_frag_state): New. (update_next_frag_nop_state): Delete. (next_frag_pre_opcode_bytes): Use next_frag_opcode_is_loop. (xtensa_mark_literal_pool_location): Check use_literal_section flag and the state of the absolute-literals directive. Add calls to record_alignment and xtensa_set_frag_assembly_state. Call xtensa_switch_to_non_abs_literal_fragment instead of xtensa_switch_to_literal_fragment. (build_nop): New. (assemble_nop): Use build_nop. Update call to xtensa_insnbuf_to_chars. (get_expanded_loop_offset): Change check for undefined opcode to an assertion. (xtensa_set_frag_assembly_state, relaxable_section, xtensa_find_unmarked_state_frags, xtensa_find_unaligned_branch_targets, xtensa_find_unaligned_loops, xg_apply_tentative_value): New. (md_begin): Update call to xtensa_isa_init. Initialize linkrelax to 1. Set lit4_seg_name. Call xg_init_vinsn. Initialize new global opcodes. Call init_op_placement_info_table and xtensa_set_frag_assembly_state. (xtensa_init_fix_data): New. (xtensa_frob_label): Reset label symbol to the current frag. Check do_align_targets and generating_literals flag. Propagate frequency info to new alignment frag. Call xtensa_set_frag_assembly_state. (xtensa_unrecognized_line): New. (xtensa_flush_pending_output): Check if inside a bundle. Add a call to xtensa_set_frag_assembly_state. (error_reset_cur_vinsn): New. (md_assemble): Remove check for literal frag. Remove call to istack_init. Call use_transform instead of use_generics. Parse explicit instruction format specifiers. Move code for a0_b_retw_interlock workaround to xg_assemble_vliw_tokens. Call error_reset_cur_vinsn on errors. Add call to get_invisible_operands. Add dwarf2_where call. Remote automatic alignment for ENTRY instructions. Move call to xtensa_clear_insn_labels to the end. Rearrange to handle bundles. (xtensa_cons_fix_new): Delete. (xtensa_handle_align): New. (xtensa_frag_init): Call xtensa_set_frag_assembly_state. Remove assignment to is_no_density field. (md_pcrel_from): Use new xtensa-isa.h functions. Use decode_reloc instead of reloc_to_opnum. Handle "alternate" relocations. (xtensa_force_relocation, xtensa_check_inside_bundle, xtensa_elf_section_change_hook): New. (xtensa_symbol_new_hook): Delete. (xtensa_fix_adjustable): Check for difference of symbols with an offset. Check for external and weak symbols. (md_apply_fix3): Remove cases for XTENSA_OP{0,1,2} relocs. (md_estimate_size_before_relax): Return expansion for the first slot. (tc_gen_reloc): Handle difference of symbols by producing XTENSA_DIFF{8,16,32} relocs and by writing the value of the difference into the output. Handle new XTENSA_SLOT*_OP relocs by storing the tentative values into the output when linkrelax is set. (XTENSA_PROP_SEC_NAME): Define. (xtensa_post_relax_hook): Call xtensa_find_unmarked_state_frags. Create literal tables only if using literal sections. Create new property tables instead of old instruction tables. Check for unaligned branch targets and loops. (finish_vinsn, find_vinsn_conflicts, check_t1_t2_reads_and_writes, new_resource_table, clear_resource_table, resize_resource_table, resources_available, reserve_resources, release_resources, opcode_funcUnit_use_unit, opcode_funcUnit_use_stage, resources_conflict, xg_find_narrowest_format, relaxation_requirements, bundle_single_op, emit_single_op, xg_assemble_vliw_tokens): New. (xtensa_end): Call xtensa_flush_pending_output. Set past_xtensa_end flag. Update checks for workaround options. Call xtensa_mark_narrow_branches and xtensa_mark_zcl_first_insns. (xtensa_cleanup_align_frags): Add special case for branch targets. Check for and mark unreachable frags. (xtensa_fix_target_frags): Remove use of align_only_targets flag. Use RELAX_LOOP_END_BYTES in special case for negatable branch at the end of a zero-overhead loop body. (frag_can_negate_branch): Handle instructions with multiple slots. Use new xtensa-isa.h functions (xtensa_mark_narrow_branches, is_narrow_branch_guaranteed_in_range, xtensa_mark_zcl_first_insns): New. (xtensa_fix_a0_b_retw_frags, xtensa_fix_b_j_loop_end_frags): Error if transformations are disabled. (next_instrs_are_b_retw): Use new xtensa-isa.h functions. Handle multislot instructions. (xtensa_fix_close_loop_end_frags, xtensa_fix_short_loop_frags): Likewise. Also error if transformations are disabled. (unrelaxed_frag_max_size): New. (unrelaxed_frag_min_insn_count, unrelax_frag_has_b_j): Use new xtensa-isa.h functions. (xtensa_sanity_check, is_empty_loop, is_local_forward_loop): Use xtensa_opcode_is_loop instead of is_loop_opcode. (get_text_align_power): Replace as_fatal with assertion. (get_text_align_fill_size): Iterate instead of using modulus when use_nops is false. (get_noop_aligned_address): Assert that this is for a machine-dependent RELAX_ALIGN_NEXT_OPCODE frag. Use next_frag_opcode_is_loop, xg_get_single_size, and frag_format_size. (get_widen_aligned_address): Rename to ... (get_aligned_diff): ... this function. Add max_diff parameter. Remove handling of rs_align/rs_align_code frags. Use next_frag_format_size, get_text_align_power, get_text_align_fill_size, next_frag_opcode_is_loop, and xg_get_single_size. Compute max_diff and pass it back to caller. (xtensa_relax_frag): Use relax_frag_loop_align. Add code for new RELAX_SLOTS, RELAX_MAYBE_UNREACHABLE, RELAX_MAYBE_DESIRE_ALIGN, RELAX_FILL_NOP, and RELAX_UNREACHABLE frag types. Check relax_seen. (relax_frag_text_align): Rename to ... (relax_frag_loop_align): ... this function. Assume loops can only be in the first slot of an instruction. (relax_frag_add_nop): Use assemble_nop instead of constructing an OR instruction. Remove call to frag_wane. (relax_frag_narrow): Rename to ... (relax_frag_for_align): ... this function. Extend to handle RELAX_FILL_NOP and RELAX_UNREACHABLE, as well as RELAX_SLOTS with RELAX_NARROW for the first slot. (find_address_of_next_align_frag, bytes_to_stretch): New. (future_alignment_required): Use find_address_of_next_align_frag and bytes_to_stretch. Look ahead to subsequent frags to make smarter alignment decisions. (relax_frag_immed): Add format, slot, and estimate_only parameters. Check if transformations are enabled for b_j_loop_end workaround. Use new xtensa-isa.h functions and handle multislot instructions. Update call to xg_assembly_relax. (md_convert_frag): Handle new RELAX_SLOTS, RELAX_UNREACHABLE, RELAX_MAYBE_UNREACHABLE, RELAX_MAYBE_DESIRE_ALIGN, and RELAX_FILL_NOP frag types. (convert_frag_narrow): Add segP, format and slot parameters. Call convert_frag_immed for branch instructions. Adjust calls to tinsn_from_chars, tinsn_immed_from_frag, and xg_emit_insn_to_buf. Use xg_get_single_size and xg_get_single_format. (convert_frag_fill_nop): New. (convert_frag_immed): Add format and slot parameters. Handle multislot instructions and use new xtensa-isa.h functions. Update calls to tinsn_immed_from_frag and xg_assembly_relax. Check if transformations enabled for b_j_loop_end workaround. Use build_nop instead of assemble_nop. Check is_specific_opcode flag. Check for unreachable frags. Use xg_get_single_size. Handle O_pltrel. (fix_new_exp_in_seg): Remove check for old plt flag. (convert_frag_immed_finish_loop): Update calls to tinsn_from_chars and xtensa_insnbuf_to_chars. Call tinsn_immed_from_frag. Change check for loop opcode to an assertion. Mark all frags up to the end of the loop as not transformable. (get_last_insn_flags, set_last_insn_flags): Use get_subseg_info. (get_subseg_info): New. (xtensa_move_literals): Call xtensa_set_frag_assembly_state. Add null check for dest_seg. (xtensa_switch_to_literal_fragment): Rewrite to handle absolute literals and use xtensa_switch_to_non_abs_literal_fragment otherwise. (xtensa_switch_to_non_abs_literal_fragment): New. (cache_literal_section): Add is_code parameter and pass it through to retrieve_literal_seg. (retrieve_literal_seg): Add is_code parameter and use it to set the flags on the literal section. Handle case where head parameter is 0. (get_frag_is_no_transform, set_frag_is_specific_opcode, set_frag_is_no_transform): New. (xtensa_create_property_segments): Add end_property_function parameter and pass it through to add_xt_block_frags. Call bfd_get_section_flags and skip SEC_DEBUGGING and !SEC_ALLOC sections. (xtensa_create_xproperty_segments, section_has_xproperty): New. (add_xt_block_frags): Add end_property_function parameter and call it if it is non-zero. Call xtensa_frag_flags_init. (xtensa_frag_flags_is_empty, xtensa_frag_flags_init, get_frag_property_flags, frag_flags_to_number, xtensa_frag_flags_combinable, xt_block_aligned_size, xtensa_xt_block_combine, add_xt_prop_frags, init_op_placement_info_table, opcode_fits_format_slot, xg_get_single_size, xg_get_single_format): New. (istack_push): Inline call to tinsn_copy. (tinsn_copy): Delete. (tinsn_has_invalid_symbolic_operands): Handle O_hi16 and O_lo16 and CONST16 opcodes. Handle O_big, O_illegal, and O_absent. (tinsn_has_complex_operands): Handle O_hi16 and O_lo16. (tinsn_to_insnbuf): Use xg_get_single_format and new xtensa-isa.h functions. Handle invisible operands. (tinsn_to_slotbuf): New. (tinsn_check_arguments): Use new xtensa-isa.h functions. (tinsn_from_chars): Add slot parameter. Rewrite using xg_init_vinsn, vinsn_from_chars, and xg_free_vinsn. (tinsn_from_insnbuf): New. (tinsn_immed_from_frag): Add slot parameter and handle multislot instructions. Handle symbol differences. (get_num_stack_text_bytes): Use xg_get_single_size. (xg_init_vinsn, xg_clear_vinsn, vinsn_has_specific_opcodes, xg_free_vinsn, vinsn_to_insnbuf, vinsn_from_chars, expr_is_register, get_expr_register, set_expr_symbol_offset_diff): New. * config/tc-xtensa.h (MAX_SLOTS): Define. (xtensa_relax_statesE): Move from tc-xtensa.c. Add RELAX_CHECK_ALIGN_NEXT_OPCODE, RELAX_MAYBE_DESIRE_ALIGN, RELAX_SLOTS, RELAX_FILL_NOP, RELAX_UNREACHABLE, RELAX_MAYBE_UNREACHABLE, and RELAX_NONE types. (RELAX_IMMED_MAXSTEPS): Move from tc-xtensa.c. (xtensa_frag_type struct): Add is_assembly_state_set, use_absolute_literals, relax_seen, is_unreachable, is_specific_opcode, is_align, is_text_align, alignment, and is_first_loop_insn fields. Replace is_generics and is_relax fields by is_no_transform field. Delete is_text and is_longcalls fields. Change text_expansion and literal_expansion to arrays of MAX_SLOTS entries. Add arrays of per-slot information: literal_frags, slot_subtypes, slot_symbols, slot_sub_symbols, and slot_offsets. Add fr_prev field. (xtensa_fix_data struct): New. (xtensa_symfield_type struct): Delete plt field. (xtensa_block_info struct): Move definition to tc-xtensa.h. Add forward declaration here. (xt_section_type enum): Delete xt_insn_sec. Add xt_prop_sec. (XTENSA_SECTION_RENAME): Undefine. (TC_FIX_TYPE, TC_INIT_FIX_DATA, TC_FORCE_RELOCATION, NO_PSEUDO_DOT, tc_unrecognized_line, md_do_align, md_elf_section_change_hook, HANDLE_ALIGN, TC_LINKRELAX_FIXUP, SUB_SEGMENT_ALIGN): Define. (TC_CONS_FIX_NEW, tc_symbol_new_hook): Delete. (unit_num_copies_func, opcode_num_units_func, opcode_funcUnit_use_unit_func, opcode_funcUnit_use_stage_func): New. (resource_table struct): New. * config/xtensa-istack.h (MAX_INSN_ARGS): Increase from 6 to 10. (TInsn struct): Add keep_wide, loc, fixup, record_fix, subtype, literal_space, symbol, sub_symbol, offset, and literal_frag fields. (tinsn_copy): Delete prototype. (vliw_insn struct): New. * config/xtensa-relax.c (insn_pattern_struct): Add options field. (widen_spec_list): Add option conditions for density and boolean instructions. Add expansions using CONST16 and conditions for using CONST16 vs. L32R. Use new Xtensa LX RSR/WSR syntax. Add entries for predicted branches. (simplify_spec_list): Add option conditions for density instructions. Add entry for NOP instruction. (append_transition): Add cmp function pointer parameter and use it to insert the new entry in order. (operand_function_LOW16U, operand_function_HI16U): New. (xg_has_userdef_op_fn, xg_apply_userdef_op_fn): Handle OP_OPERAND_LOW16U and OP_OPERAND_HI16U. (enter_opname, split_string): Use xstrdup instead of strdup. (init_insn_pattern): Initialize new options field. (clear_req_or_option_list, clear_req_option_list, clone_req_or_option_list, clone_req_option_list, parse_option_cond): New. (parse_insn_pattern): Parse option conditions. (transition_applies): New. (build_transition): Use new xtensa-isa.h functions. Fix incorrectly swapped last arguments in calls to append_constant_value_condition. Call clone_req_option_list. Add warning about invalid opcode. Handle LOW16U and HI16U function names. (build_transition_table): Add cmp parameter and use it in calls to append_transition. Use new xtensa-isa.h functions. Check transition_applies before adding entries. (xg_build_widen_table, xg_build_simplify_table): Add cmp parameter and pass it through to build_transition_table. * config/xtensa-relax.h (ReqOrOptionList, ReqOrOption, ReqOptionList, ReqOption, transition_cmp_fn): New types. (OpType enum): Add OP_OPERAND_LOW16U and OP_OPERAND_HI16U. (transition_rule struct): Add options field. * doc/as.texinfo (Overview): Update Xtensa options. * doc/c-xtensa.texi (Xtensa Options): Delete --[no-]density, --[no-]relax, and --[no-]generics options. Update descriptions of --text-section-literals and --[no-]longcalls. Add --[no-]absolute-literals and --[no-]transform. (Xtensa Syntax): Add description of syntax for FLIX instructions. Remove use of "generic" and "specific" terminology for opcodes. (Xtensa Registers): Generalize the syntax description to include user-defined register files. (Xtensa Automatic Alignment): Update. (Xtensa Branch Relaxation): Mention limitation of unconditional jumps. (Xtensa Call Relaxation): Linker can now remove most of the overhead. (Xtensa Directives): Remove confusing rules about precedence. (Density Directive, Relax Directive): Delete. (Schedule Directive): New. (Generics Directive): Rename to ... (Transform Directive): ... this node. (Literal Directive): Update for absolute literals. Missing literal_position directive is now an error. (Literal Position Directive): Update for absolute literals. (Freeregs Directive): Delete. (Absolute Literals Directive): New. (Frame Directive): Minor editing. * Makefile.am (DEPTC_xtensa_elf, DEPOBJ_xtensa_elf, DEP_xtensa_elf): Update dependencies. * Makefile.in: Regenerate. gas/testsuite ChangeLog * gas/xtensa/all.exp: Adjust expected error message for j_too_far. Change entry_align test to expect an error. * gas/xtensa/entry_misalign2.s: Use no-transform instead of no-generics directives. include ChangeLog * xtensa-config.h (XSHAL_USE_ABSOLUTE_LITERALS, XCHAL_HAVE_PREDICTED_BRANCHES, XCHAL_INST_FETCH_WIDTH): New. (XCHAL_EXTRA_SA_SIZE, XCHAL_EXTRA_SA_ALIGN): Delete. * xtensa-isa-internal.h (ISA_INTERFACE_VERSION): Delete. (config_sturct struct): Delete. (XTENSA_OPERAND_IS_REGISTER, XTENSA_OPERAND_IS_PCRELATIVE, XTENSA_OPERAND_IS_INVISIBLE, XTENSA_OPERAND_IS_UNKNOWN, XTENSA_OPCODE_IS_BRANCH, XTENSA_OPCODE_IS_JUMP, XTENSA_OPCODE_IS_LOOP, XTENSA_OPCODE_IS_CALL, XTENSA_STATE_IS_EXPORTED, XTENSA_INTERFACE_HAS_SIDE_EFFECT): Define. (xtensa_format_encode_fn, xtensa_get_slot_fn, xtensa_set_slot_fn): New. (xtensa_insn_decode_fn): Rename to ... (xtensa_opcode_decode_fn): ... this. (xtensa_immed_decode_fn, xtensa_immed_encode_fn, xtensa_do_reloc_fn, xtensa_undo_reloc_fn): Update. (xtensa_encoding_template_fn): Delete. (xtensa_opcode_encode_fn, xtensa_format_decode_fn, xtensa_length_decode_fn): New. (xtensa_format_internal, xtensa_slot_internal): New types. (xtensa_operand_internal): Delete operand_kind, inout, isPCRelative, get_field, and set_field fields. Add name, field_id, regfile, num_regs, and flags fields. (xtensa_arg_internal): New type. (xtensa_iclass_internal): Change operands field to array of xtensa_arg_internal. Add num_stateOperands, stateOperands, num_interfaceOperands, and interfaceOperands fields. (xtensa_opcode_internal): Delete length, template, and iclass fields. Add iclass_id, flags, encode_fns, num_funcUnit_uses, and funcUnit_uses. (opname_lookup_entry): Delete. (xtensa_regfile_internal, xtensa_interface_internal, xtensa_funcUnit_internal, xtensa_state_internal, xtensa_sysreg_internal, xtensa_lookup_entry): New. (xtensa_isa_internal): Replace opcode_table field with opcodes field. Change type of opname_lookup_table. Delete num_modules, module_opcode_base, module_decode_fn, config, and has_density fields. Add num_formats, formats, format_decode_fn, length_decode_fn, num_slots, slots, num_fields, num_operands, operands, num_iclasses, iclasses, num_regfiles, regfiles, num_states, states, state_lookup_table, num_sysregs, sysregs, sysreg_lookup_table, max_sysreg_num, sysreg_table, num_interfaces, interfaces, interface_lookup_table, num_funcUnits, funcUnits and funcUnit_lookup_table fields. (xtensa_isa_module, xtensa_isa_modules): Delete. (xtensa_isa_name_compare): New prototype. (xtisa_errno, xtisa_error_msg): New. * xtensa-isa.h (XTENSA_ISA_VERSION): Define. (xtensa_isa): Change type. (xtensa_operand): Delete. (xtensa_format, xtensa_regfile, xtensa_state, xtensa_sysreg, xtensa_interface, xtensa_funcUnit, xtensa_isa_status, xtensa_funcUnit_use): New types. (libisa_module_specifier): Delete. (xtensa_isa_errno, xtensa_isa_error_msg): New prototypes. (xtensa_insnbuf_free, xtensa_insnbuf_to_chars, xtensa_insnbuf_from_chars): Update prototypes. (xtensa_load_isa, xtensa_extend_isa, xtensa_default_isa, xtensa_insn_maxlength, xtensa_num_opcodes, xtensa_decode_insn, xtensa_encode_insn, xtensa_insn_length, xtensa_insn_length_from_first_byte, xtensa_num_operands, xtensa_operand_kind, xtensa_encode_result, xtensa_operand_isPCRelative): Delete. (xtensa_isa_init, xtensa_operand_inout, xtensa_operand_get_field, xtensa_operand_set_field, xtensa_operand_encode, xtensa_operand_decode, xtensa_operand_do_reloc, xtensa_operand_undo_reloc): Update prototypes. (xtensa_isa_maxlength, xtensa_isa_length_from_chars, xtensa_isa_num_pipe_stages, xtensa_isa_num_formats, xtensa_isa_num_opcodes, xtensa_isa_num_regfiles, xtensa_isa_num_states, xtensa_isa_num_sysregs, xtensa_isa_num_interfaces, xtensa_isa_num_funcUnits, xtensa_format_name, xtensa_format_lookup, xtensa_format_decode, xtensa_format_encode, xtensa_format_length, xtensa_format_num_slots, xtensa_format_slot_nop_opcode, xtensa_format_get_slot, xtensa_format_set_slot, xtensa_opcode_decode, xtensa_opcode_encode, xtensa_opcode_is_branch, xtensa_opcode_is_jump, xtensa_opcode_is_loop, xtensa_opcode_is_call, xtensa_opcode_num_operands, xtensa_opcode_num_stateOperands, xtensa_opcode_num_interfaceOperands, xtensa_opcode_num_funcUnit_uses, xtensa_opcode_funcUnit_use, xtensa_operand_name, xtensa_operand_is_visible, xtensa_operand_is_register, xtensa_operand_regfile, xtensa_operand_num_regs, xtensa_operand_is_known_reg, xtensa_operand_is_PCrelative, xtensa_stateOperand_state, xtensa_stateOperand_inout, xtensa_interfaceOperand_interface, xtensa_regfile_lookup, xtensa_regfile_lookup_shortname, xtensa_regfile_name, xtensa_regfile_shortname, xtensa_regfile_view_parent, xtensa_regfile_num_bits, xtensa_regfile_num_entries, xtensa_state_lookup, xtensa_state_name, xtensa_state_num_bits, xtensa_state_is_exported, xtensa_sysreg_lookup, xtensa_sysreg_lookup_name, xtensa_sysreg_name, xtensa_sysreg_number, xtensa_sysreg_is_user, xtensa_interface_lookup, xtensa_interface_name, xtensa_interface_num_bits, xtensa_interface_inout, xtensa_interface_has_side_effect, xtensa_funcUnit_lookup, xtensa_funcUnit_name, xtensa_funcUnit_num_copies): New prototypes. * elf/xtensa.h (R_XTENSA_DIFF8, R_XTENSA_DIFF16, R_XTENSA_DIFF32, R_XTENSA_SLOT*_OP, R_XTENSA_SLOT*_ALT): New relocations. (XTENSA_PROP_SEC_NAME): Define. (property_table_entry): Add flags field. (XTENSA_PROP_*, GET_XTENSA_PROP_*, SET_XTENSA_PROP_*): Define. ld ChangeLog * ld.texinfo (Xtensa): Describe new linker relaxation to optimize assembler-generated longcall sequences. Describe new --size-opt option. * emulparams/elf32xtensa.sh (OTHER_SECTIONS): Add .xt.prop section. * emultempl/xtensaelf.em (remove_section, replace_insn_sec_with_prop_sec, replace_instruction_table_sections, elf_xtensa_after_open): New. (OPTION_OPT_SIZEOPT, OPTION_LITERAL_MOVEMENT, OPTION_NO_LITERAL_MOVEMENT): Define. (elf32xtensa_size_opt, elf32xtensa_no_literal_movement): New globals. (PARSE_AND_LIST_LONGOPTS): Add size-opt and [no-]literal-movement. (PARSE_AND_LIST_OPTIONS): Add --size-opt. (PARSE_AND_LIST_ARGS_CASES): Handle OPTION_OPT_SIZEOPT, OPTION_LITERAL_MOVEMENT, and OPTION_NO_LITERAL_MOVEMENT. (LDEMUL_AFTER_OPEN): Set to elf_xtensa_after_open. * scripttempl/elfxtensa.sc: Update with changes from elf.sc. * Makefile.am (eelf32xtensa.c): Update dependencies. * Makefile.in: Regenerate. ld/testsuite ChangeLog * ld-xtensa/lcall1.s: Use .literal directive. * ld-xtensa/lcall2.s: Align function entry. * ld-xtensa/coalesce2.s: Likewise. opcodes ChangeLog * xtensa-dis.c (state_names): Delete. (fetch_data): Use xtensa_isa_maxlength. (print_xtensa_operand): Replace operand parameter with opcode/operand pair. Remove print_sr_name parameter. Use new xtensa-isa.h functions. (print_insn_xtensa): Use new xtensa-isa.h functions. Handle multislot instruction bundles. Use xmalloc instead of malloc. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index eefb123fafb..df818211b2b 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,276 @@ +2004-10-07 Bob Wilson + + * elf32-xtensa.c (elf32xtensa_size_opt): New global variable. + (xtensa_default_isa): Global variable moved here from xtensa-isa.c. + (elf32xtensa_no_literal_movement): New global variable. + (elf_howto_table): Add entries for new relocations. + (elf_xtensa_reloc_type_lookup): Handle new relocations. + (property_table_compare): When addresses are equal, compare sizes and + various property flags. + (property_table_matches): New. + (xtensa_read_table_entries): Extend to read new property tables. Add + output_addr parameter to indicate that output addresses should be used. + Use bfd_get_section_limit. + (elf_xtensa_find_property_entry): New. + (elf_xtensa_in_literal_pool): Use elf_xtensa_find_property_entry. + (elf_xtensa_check_relocs): Handle new relocations. + (elf_xtensa_do_reloc): Use bfd_get_section_limit. Handle new + relocations. Use new xtensa-isa.h functions. + (build_encoding_error_message): Remove encode_result parameter. Add + new target_address parameter used to detect alignment errors. + (elf_xtensa_relocate_section): Use bfd_get_section_limit. Clean up + error handling. Use new is_operand_relocation function. + (elf_xtensa_combine_prop_entries, elf_xtensa_merge_private_bfd_data): + Use underbar macro for error messages. Formatting. + (get_const16_opcode): New. + (get_l32r_opcode): Add a separate flag for initialization. + (get_relocation_opnd): Operand number is no longer explicit in the + relocation. Change to decode the opcode and analyze its operands. + (get_relocation_slot): New. + (get_relocation_opcode): Add bfd parameter. Use bfd_get_section_limit. + Use new xtensa-isa.h functions to handle multislot instructions. + (is_l32r_relocation): Add bfd parameter. Use is_operand_relocation. + (get_asm_simplify_size, is_alt_relocation, is_operand_relocation, + insn_decode_len, insn_decode_opcode, check_branch_target_aligned, + check_loop_aligned, check_branch_target_aligned_address, narrowable, + widenable, narrow_instruction, widen_instruction, op_single_fmt_table, + get_single_format, init_op_single_format_table): New. + (elf_xtensa_do_asm_simplify): Add error_message parameter and use it + instead of calling _bfd_error_handler. Use new xtensa-isa.h functions. + (contract_asm_expansion): Add error_message parameter and pass it to + elf_xtensa_do_asm_simplify. Replace use of R_XTENSA_OP0 relocation + with R_XTENSA_SLOT0_OP. + (get_expanded_call_opcode): Extend to handle either L32R or CONST16 + instructions. Use new xtensa-isa.h functions. + (r_reloc struct): Add new virtual_offset field. + (r_reloc_init): Add contents and content_length parameters. Set + virtual_offset field to zero. Add contents to target_offset field for + partial_inplace relocations. + (r_reloc_is_defined): Check for null. + (print_r_reloc): New debug function. + (source_reloc struct): Replace xtensa_operand field with pair of the + opcode and the operand position. Add is_abs_literal field. + (init_source_reloc): Specify operand by opcode/position pair. Set + is_abs_literal field. + (source_reloc_compare): When target_offsets are equal, compare other + fields to make sorting predictable. + (literal_value struct): Add is_abs_literal field. + (value_map_hash_table struct): Add has_last_loc and last_loc fields. + (init_literal_value): New. + (is_same_value): Replace with ... + (literal_value_equal): ... this function. Add comparisons of + virtual_offset and is_abs_literal fields. + (value_map_hash_table_init): Use bfd_zmalloc. Check for allocation + failure. Initialize has_last_loc field. + (value_map_hash_table_delete): New. + (hash_literal_value): Rename to ... + (literal_value_hash): ... this. Include is_abs_literal flag and + virtual_offset field in the hash value. + (get_cached_value): Rename to ... + (value_map_get_cached_value): ... this. Update calls to + literal_value_hash and literal_value_equal. + (add_value_map): Check for allocation failure. Update calls to + value_map_get_cached_value and literal_value_hash. + (text_action, text_action_list, text_action_t): New types. + (find_fill_action, compute_removed_action_diff, adjust_fill_action, + text_action_add, text_action_add_literal, offset_with_removed_text, + offset_with_removed_text_before_fill, find_insn_action, + print_action_list, print_removed_literals): New. + (offset_with_removed_literals): Delete. + (xtensa_relax_info struct): Add is_relaxable_asm_section, action_list, + fix_array, fix_array_count, allocated_relocs, relocs_count, and + allocated_relocs_count fields. + (init_xtensa_relax_info): Initialize new fields. + (reloc_bfd_fix struct): Add new translated field. + (reloc_bfd_fix_init): Add translated parameter and use it to set the + translated field. + (fix_compare, cache_fix_array): New. + (get_bfd_fix): Remove fix_list parameter and get all relax_info for the + section via get_xtensa_relax_info. Use cache_fix_array to set up + sorted fix_array and use bsearch instead of linear search. + (section_cache_t): New struct. + (init_section_cache, section_cache_section, clear_section_cache): New. + (ebb_t, ebb_target_enum, proposed_action, ebb_constraint): New types. + (init_ebb_constraint, free_ebb_constraint, init_ebb, extend_ebb_bounds, + extend_ebb_bounds_forward, extend_ebb_bounds_backward, + insn_block_decodable_len, ebb_propose_action, ebb_add_proposed_action): + New. + (retrieve_contents): Use bfd_get_section_limit. + (elf_xtensa_relax_section): Add relocations_analyzed flag. Update call + to compute_removed_literals. Free value_map_hash_table when no longer + needed. + (analyze_relocations): Check is_relaxable_asm_section flag. Call + compute_text_actions for all sections. + (find_relaxable_sections): Mark sections as relaxable if they contain + ASM_EXPAND relocations that can be optimized. Adjust r_reloc_init + call. Increment relax_info src_count field only for appropriate + relocation types. Remove is_literal_section check. + (collect_source_relocs): Use bfd_get_section_limit. Adjust calls to + r_reloc_init and find_associated_l32r_irel. Check + is_relaxable_asm_section flag. Handle L32R instructions with absolute + literals. Pass is_abs_literal flag to init_source_reloc. + (is_resolvable_asm_expansion): Use bfd_get_section_limit. Check for + CONST16 instructions. Adjust calls to r_reloc_init and + pcrel_reloc_fits. Handle weak symbols conservatively. + (find_associated_l32r_irel): Add bfd parameter and pass it to + is_l32r_relocation. + (compute_text_actions, compute_ebb_proposed_actions, + compute_ebb_actions, check_section_ebb_pcrels_fit, + check_section_ebb_reduces, text_action_add_proposed, + compute_fill_extra_space): New. + (remove_literals): Replace with ... + (compute_removed_literals): ... this function. Call + init_section_cache. Use bfd_get_section_limit. Sort internal_relocs. + Call xtensa_read_table_entries to get the property table. Skip + relocations other than R_XTENSA_32 and R_XTENSA_PLT. Use new + is_removable_literal, remove_dead_literal, and + identify_literal_placement functions. + (get_irel_at_offset): Rewrite to use bsearch on sorted relocations + instead of linear search. + (is_removable_literal, remove_dead_literal, + identify_literal_placement): New. + (relocations_reach): Update check for literal not referenced by any + PC-relative relocations. Adjust call to pcrel_reloc_fits. + (coalesce_shared_literal, move_shared_literal): New. + (relax_section): Use bfd_get_section_limit. Call + translate_section_fixes. Update calls to r_reloc_init and + offset_with_removed_text. Check new is_relaxable_asm_section flag. + Add call to pin_internal_relocs. Add special handling for + R_XTENSA_ASM_SIMPLIFY and R_XTENSA_DIFF* relocs. Use virtual_offset + info to calculate new addend_displacement variable. Replace code for + deleting literals with more general code to perform the actions + determined by the action_list for the section. + (translate_section_fixes, translate_reloc_bfd_fix): New. + (translate_reloc): Check new is_relaxable_asm_section flag. Call + find_removed_literal only if is_operand_relocation. Update call to + offset_with_removed_text. Use new target_offset and removed_bytes + variables. + (move_literal): New. + (relax_property_section): Use bfd_get_section_limit. Set new + is_full_prop_section flag and handle new property tables. Update calls + to r_reloc_init and offset_with_removed_text. Check + is_relaxable_asm_section flag. Handle expansion of zero-sized + unreachable entries, with use of offset_with_removed_text_before_fill. + For relocatable links, combine entries only for literal tables. + (relax_section_symbols): Check is_relaxable_asm_section flag. Update + calls to offset_with_removed_text. Translate st_size field for + function symbols. + (do_fix_for_relocatable_link): Change to return bfd_boolean to indicate + failure. Add contents parameter. Update call to get_bfd_fix. Update + call to r_reloc_init. Call _bfd_error_handler and return FALSE for + R_XTENSA_ASM_EXPAND relocs. + (do_fix_for_final_link): Add input_bfd and contents parameters. Update + call to get_bfd_fix. Include offset from contents for partial_inplace + relocations. + (is_reloc_sym_weak): New. + (pcrel_reloc_fits): Use new xtensa-isa.h functions. + (prop_sec_len): New. + (xtensa_is_property_section): Handle new property sections. + (is_literal_section): Delete. + (internal_reloc_compare): When r_offset matches, compare r_info and + r_addend to make sorting predictable. + (internal_reloc_matches): New. + (xtensa_get_property_section_name): Handle new property sections. + (xtensa_get_property_predef_flags): New. + (xtensa_callback_required_dependence): Use bfd_get_section_limit. + Update calls to xtensa_isa_init, is_l32r_relocation, and r_reloc_init. + * xtensa-isa.c (xtensa_default_isa): Moved to elf32-xtensa.c. + (xtisa_errno, xtisa_error_msg): New variables. + (xtensa_isa_errno, xtensa_isa_error_msg): New. + (xtensa_insnbuf_alloc): Add error handling. + (xtensa_insnbuf_to_chars): Add num_chars parameter. Update to + use xtensa_format_decode. Add error handling. + (xtensa_insnbuf_from_chars): Add num_chars parameter. Decode the + instruction length to find the number of bytes to copy. + (xtensa_isa_init): Add error handling. Replace calls to + xtensa_load_isa and xtensa_extend_isa with code to initialize lookup + tables in the xtensa_modules structure. + (xtensa_check_isa_config, xtensa_add_isa, xtensa_load_isa, + xtensa_extend_isa): Delete. + (xtensa_isa_free): Change to only free lookup tables. + (opname_lookup_compare): Replace with ... + (xtensa_isa_name_compare): ... this function. Use strcasecmp. + (xtensa_insn_maxlength): Rename to ... + (xtensa_isa_maxlength): ... this. + (xtensa_insn_length): Delete. + (xtensa_insn_length_from_first_byte): Replace with ... + (xtensa_isa_length_from_chars): ... this function. + (xtensa_num_opcodes): Rename to ... + (xtensa_isa_num_opcodes): ... this. + (xtensa_isa_num_pipe_stages, xtensa_isa_num_formats, + xtensa_isa_num_regfiles, xtensa_isa_num_stages, + xtensa_isa_num_sysregs, xtensa_isa_num_interfaces, + xtensa_isa_num_funcUnits, xtensa_format_name, xtensa_format_lookup, + xtensa_format_decode, xtensa_format_encode, xtensa_format_length, + xtensa_format_num_slots, xtensa_format_slot_nop_opcode, + xtensa_format_get_slot, xtensa_format_set_slot): New functions. + (xtensa_opcode_lookup): Add error handling. + (xtensa_decode_insn): Replace with ... + (xtensa_opcode_decode): ... this function, with new format and + slot parameters. Add error handling. + (xtensa_encode_insn): Replace with ... + (xtensa_opcode_encode): ... this function, which does the encoding via + one of the entries in the "encode_fns" array. Add error handling. + (xtensa_opcode_name): Add error handling. + (xtensa_opcode_is_branch, xtensa_opcode_is_jump, xtensa_opcode_is_loop, + xtensa_opcode_is_call): New. + (xtensa_num_operands): Replace with ... + (xtensa_opcode_num_operands): ... this function. Add error handling. + (xtensa_opcode_num_stateOperands, + xtensa_opcode_num_interfaceOperands, xtensa_opcode_num_funcUnit_uses, + xtensa_opcode_funcUnit_use, xtensa_operand_name, + xtensa_operand_is_visible): New. + (xtensa_get_operand, xtensa_operand_kind): Delete. + (xtensa_operand_inout): Add error handling and special-case for + "sout" operands. + (xtensa_operand_get_field, xtensa_operand_set_field): Rewritten to + operate on one slot of an instruction. Added error handling. + (xtensa_operand_encode): Handle default operands with no encoding + functions. Check for success by comparing against decoded value. + Add error handling. + (xtensa_operand_decode): Handle default operands. Return decoded value + through argument pointer. Add error handling. + (xtensa_operand_is_register, xtensa_operand_regfile, + xtensa_operand_num_regs, xtensa_operand_is_known_reg): New. + (xtensa_operand_isPCRelative): Rename to ... + (xtensa_operand_is_PCrelative): ... this. Add error handling. + (xtensa_operand_do_reloc, xtensa_operand_undo_reloc): Return value + through argument pointer. Add error handling. + (xtensa_stateOperand_state, xtensa_stateOperand_inout, + xtensa_interfaceOperand_interface, xtensa_regfile_lookup, + xtensa_regfile_lookup_shortname, xtensa_regfile_name, + xtensa_regfile_shortname, xtensa_regfile_view_parent, + xtensa_regfile_num_bits, xtensa_regfile_num_entries, + xtensa_state_lookup, xtensa_state_name, xtensa_state_num_bits, + xtensa_state_is_exported, xtensa_sysreg_lookup, + xtensa_sysreg_lookup_name, xtensa_sysreg_name, xtensa_sysreg_number, + xtensa_sysreg_is_user, xtensa_interface_lookup, xtensa_interface_name, + xtensa_interface_num_bits, xtensa_interface_inout, + xtensa_interface_has_side_effect, xtensa_funcUnit_lookup, + xtensa_funcUnit_name, xtensa_funcUnit_num_copies): New. + * xtensa-modules.c: Rewrite to use new data structures. + * reloc.c (BFD_RELOC_XTENSA_DIFF8, BFD_RELOC_XTENSA_DIFF16, + BFD_RELOC_XTENSA_DIFF32, BFD_RELOC_XTENSA_SLOT0_OP, + BFD_RELOC_XTENSA_SLOT1_OP, BFD_RELOC_XTENSA_SLOT2_OP, + BFD_RELOC_XTENSA_SLOT3_OP, BFD_RELOC_XTENSA_SLOT4_OP, + BFD_RELOC_XTENSA_SLOT5_OP, BFD_RELOC_XTENSA_SLOT6_OP, + BFD_RELOC_XTENSA_SLOT7_OP, BFD_RELOC_XTENSA_SLOT8_OP, + BFD_RELOC_XTENSA_SLOT9_OP, BFD_RELOC_XTENSA_SLOT10_OP, + BFD_RELOC_XTENSA_SLOT11_OP, BFD_RELOC_XTENSA_SLOT12_OP, + BFD_RELOC_XTENSA_SLOT13_OP, BFD_RELOC_XTENSA_SLOT14_OP, + BFD_RELOC_XTENSA_SLOT0_ALT, BFD_RELOC_XTENSA_SLOT1_ALT, + BFD_RELOC_XTENSA_SLOT2_ALT, BFD_RELOC_XTENSA_SLOT3_ALT, + BFD_RELOC_XTENSA_SLOT4_ALT, BFD_RELOC_XTENSA_SLOT5_ALT, + BFD_RELOC_XTENSA_SLOT6_ALT, BFD_RELOC_XTENSA_SLOT7_ALT, + BFD_RELOC_XTENSA_SLOT8_ALT, BFD_RELOC_XTENSA_SLOT9_ALT, + BFD_RELOC_XTENSA_SLOT10_ALT, BFD_RELOC_XTENSA_SLOT11_ALT, + BFD_RELOC_XTENSA_SLOT12_ALT, BFD_RELOC_XTENSA_SLOT13_ALT, + BFD_RELOC_XTENSA_SLOT14_ALT): Add new relocations. + * Makefile.am (xtensa-isa.lo, xtensa-modules.lo): Update dependencies. + * Makefile.in: Regenerate. + * bfd-in2.h: Likewise. + * libbfd.h: Likewise. + 2004-10-07 Richard Sandiford * elf64-mips.c (mips_elf64_write_rel): Use STN_UNDEF for relocs diff --git a/bfd/Makefile.am b/bfd/Makefile.am index a7eabfc26bb..966aff3c86e 100644 --- a/bfd/Makefile.am +++ b/bfd/Makefile.am @@ -1557,10 +1557,9 @@ xcofflink.lo: xcofflink.c $(INCDIR)/filenames.h $(INCDIR)/bfdlink.h \ $(INCDIR)/coff/internal.h $(INCDIR)/coff/xcoff.h libcoff.h \ libxcoff.h xsym.lo: xsym.c xsym.h $(INCDIR)/filenames.h -xtensa-isa.lo: xtensa-isa.c $(INCDIR)/xtensa-isa.h \ - $(INCDIR)/xtensa-isa-internal.h -xtensa-modules.lo: xtensa-modules.c $(INCDIR)/xtensa-isa.h \ +xtensa-isa.lo: xtensa-isa.c $(INCDIR)/filenames.h $(INCDIR)/xtensa-isa.h \ $(INCDIR)/xtensa-isa-internal.h +xtensa-modules.lo: xtensa-modules.c $(INCDIR)/xtensa-isa-internal.h aix5ppc-core.lo: aix5ppc-core.c aout64.lo: aout64.c aoutx.h $(INCDIR)/filenames.h $(INCDIR)/safe-ctype.h \ $(INCDIR)/bfdlink.h libaout.h $(INCDIR)/aout/aout64.h \ diff --git a/bfd/Makefile.in b/bfd/Makefile.in index ac92e492535..5a551cdf7bb 100644 --- a/bfd/Makefile.in +++ b/bfd/Makefile.in @@ -2112,10 +2112,9 @@ xcofflink.lo: xcofflink.c $(INCDIR)/filenames.h $(INCDIR)/bfdlink.h \ $(INCDIR)/coff/internal.h $(INCDIR)/coff/xcoff.h libcoff.h \ libxcoff.h xsym.lo: xsym.c xsym.h $(INCDIR)/filenames.h -xtensa-isa.lo: xtensa-isa.c $(INCDIR)/xtensa-isa.h \ - $(INCDIR)/xtensa-isa-internal.h -xtensa-modules.lo: xtensa-modules.c $(INCDIR)/xtensa-isa.h \ +xtensa-isa.lo: xtensa-isa.c $(INCDIR)/filenames.h $(INCDIR)/xtensa-isa.h \ $(INCDIR)/xtensa-isa-internal.h +xtensa-modules.lo: xtensa-modules.c $(INCDIR)/xtensa-isa-internal.h aix5ppc-core.lo: aix5ppc-core.c aout64.lo: aout64.c aoutx.h $(INCDIR)/filenames.h $(INCDIR)/safe-ctype.h \ $(INCDIR)/bfdlink.h libaout.h $(INCDIR)/aout/aout64.h \ diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 6feb83e2d8b..2e851a9d950 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -3621,9 +3621,56 @@ to one of its own internal functions or data structures. */ PLT entries. Otherwise, this is just a generic 32-bit relocation. */ BFD_RELOC_XTENSA_PLT, -/* Generic Xtensa relocations. Only the operand number is encoded -in the relocation. The details are determined by extracting the -instruction opcode. */ +/* Xtensa relocations to mark the difference of two local symbols. +These are only needed to support linker relaxation and can be ignored +when not relaxing. The field is set to the value of the difference +assuming no relaxation. The relocation encodes the position of the +first symbol so the linker can determine whether to adjust the field +value. */ + BFD_RELOC_XTENSA_DIFF8, + BFD_RELOC_XTENSA_DIFF16, + BFD_RELOC_XTENSA_DIFF32, + +/* Generic Xtensa relocations for instruction operands. Only the slot +number is encoded in the relocation. The relocation applies to the +last PC-relative immediate operand, or if there are no PC-relative +immediates, to the last immediate operand. */ + BFD_RELOC_XTENSA_SLOT0_OP, + BFD_RELOC_XTENSA_SLOT1_OP, + BFD_RELOC_XTENSA_SLOT2_OP, + BFD_RELOC_XTENSA_SLOT3_OP, + BFD_RELOC_XTENSA_SLOT4_OP, + BFD_RELOC_XTENSA_SLOT5_OP, + BFD_RELOC_XTENSA_SLOT6_OP, + BFD_RELOC_XTENSA_SLOT7_OP, + BFD_RELOC_XTENSA_SLOT8_OP, + BFD_RELOC_XTENSA_SLOT9_OP, + BFD_RELOC_XTENSA_SLOT10_OP, + BFD_RELOC_XTENSA_SLOT11_OP, + BFD_RELOC_XTENSA_SLOT12_OP, + BFD_RELOC_XTENSA_SLOT13_OP, + BFD_RELOC_XTENSA_SLOT14_OP, + +/* Alternate Xtensa relocations. Only the slot is encoded in the +relocation. The meaning of these relocations is opcode-specific. */ + BFD_RELOC_XTENSA_SLOT0_ALT, + BFD_RELOC_XTENSA_SLOT1_ALT, + BFD_RELOC_XTENSA_SLOT2_ALT, + BFD_RELOC_XTENSA_SLOT3_ALT, + BFD_RELOC_XTENSA_SLOT4_ALT, + BFD_RELOC_XTENSA_SLOT5_ALT, + BFD_RELOC_XTENSA_SLOT6_ALT, + BFD_RELOC_XTENSA_SLOT7_ALT, + BFD_RELOC_XTENSA_SLOT8_ALT, + BFD_RELOC_XTENSA_SLOT9_ALT, + BFD_RELOC_XTENSA_SLOT10_ALT, + BFD_RELOC_XTENSA_SLOT11_ALT, + BFD_RELOC_XTENSA_SLOT12_ALT, + BFD_RELOC_XTENSA_SLOT13_ALT, + BFD_RELOC_XTENSA_SLOT14_ALT, + +/* Xtensa relocations for backward compatibility. These have all been +replaced by BFD_RELOC_XTENSA_SLOT0_OP. */ BFD_RELOC_XTENSA_OP0, BFD_RELOC_XTENSA_OP1, BFD_RELOC_XTENSA_OP2, diff --git a/bfd/elf32-xtensa.c b/bfd/elf32-xtensa.c index 0755e09d596..09ef0e1a563 100644 --- a/bfd/elf32-xtensa.c +++ b/bfd/elf32-xtensa.c @@ -35,13 +35,16 @@ #include "xtensa-isa.h" #include "xtensa-config.h" +#define XTENSA_NO_NOP_REMOVAL 0 + /* Main interface functions. */ static void elf_xtensa_info_to_howto_rela PARAMS ((bfd *, arelent *, Elf_Internal_Rela *)); static reloc_howto_type *elf_xtensa_reloc_type_lookup PARAMS ((bfd *abfd, bfd_reloc_code_real_type code)); extern int xtensa_read_table_entries - PARAMS ((bfd *, asection *, property_table_entry **, const char *)); + PARAMS ((bfd *, asection *, property_table_entry **, const char *, + bfd_boolean)); static bfd_boolean elf_xtensa_check_relocs PARAMS ((bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *)); @@ -103,6 +106,10 @@ static bfd_boolean xtensa_elf_dynamic_symbol_p PARAMS ((struct elf_link_hash_entry *, struct bfd_link_info *)); static int property_table_compare PARAMS ((const PTR, const PTR)); +static int property_table_matches + PARAMS ((const PTR, const PTR)); +static property_table_entry *elf_xtensa_find_property_entry + PARAMS ((property_table_entry *, int, bfd_vma)); static bfd_boolean elf_xtensa_in_literal_pool PARAMS ((property_table_entry *, int, bfd_vma)); static void elf_xtensa_make_sym_local @@ -123,13 +130,13 @@ static bfd_reloc_status_type elf_xtensa_do_reloc static char * vsprint_msg VPARAMS ((const char *, const char *, int, ...)); static char *build_encoding_error_message - PARAMS ((xtensa_opcode, xtensa_encode_result)); + PARAMS ((xtensa_opcode, bfd_vma)); static bfd_reloc_status_type bfd_elf_xtensa_reloc PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); -static void do_fix_for_relocatable_link - PARAMS ((Elf_Internal_Rela *, bfd *, asection *)); +static bfd_boolean do_fix_for_relocatable_link + PARAMS ((Elf_Internal_Rela *, bfd *, asection *, bfd_byte *)); static void do_fix_for_final_link - PARAMS ((Elf_Internal_Rela *, asection *, bfd_vma *)); + PARAMS ((Elf_Internal_Rela *, bfd *, asection *, bfd_byte *, bfd_vma *)); static bfd_vma elf_xtensa_create_plt_entry PARAMS ((bfd *, bfd *, unsigned)); static int elf_xtensa_combine_prop_entries @@ -148,27 +155,47 @@ static bfd_boolean is_direct_call_opcode PARAMS ((xtensa_opcode)); static bfd_boolean is_windowed_call_opcode PARAMS ((xtensa_opcode)); +static xtensa_opcode get_const16_opcode + PARAMS ((void)); static xtensa_opcode get_l32r_opcode PARAMS ((void)); static bfd_vma l32r_offset PARAMS ((bfd_vma, bfd_vma)); static int get_relocation_opnd - PARAMS ((Elf_Internal_Rela *)); + PARAMS ((xtensa_opcode, int)); +static int get_relocation_slot + PARAMS ((int)); static xtensa_opcode get_relocation_opcode - PARAMS ((asection *, bfd_byte *, Elf_Internal_Rela *)); + PARAMS ((bfd *, asection *, bfd_byte *, Elf_Internal_Rela *)); static bfd_boolean is_l32r_relocation - PARAMS ((asection *, bfd_byte *, Elf_Internal_Rela *)); + PARAMS ((bfd *, asection *, bfd_byte *, Elf_Internal_Rela *)); +static bfd_boolean is_alt_relocation + PARAMS ((int)); +static bfd_boolean is_operand_relocation + PARAMS ((int)); +static bfd_size_type insn_decode_len + PARAMS ((bfd_byte *, bfd_size_type, bfd_size_type)); +static xtensa_opcode insn_decode_opcode + PARAMS ((bfd_byte *, bfd_size_type, bfd_size_type, int)); +static bfd_boolean check_branch_target_aligned + PARAMS ((bfd_byte *, bfd_size_type, bfd_vma, bfd_vma)); +static bfd_boolean check_loop_aligned + PARAMS ((bfd_byte *, bfd_size_type, bfd_vma, bfd_vma)); +static bfd_boolean check_branch_target_aligned_address + PARAMS ((bfd_vma, int)); +static bfd_size_type get_asm_simplify_size + PARAMS ((bfd_byte *, bfd_size_type, bfd_size_type)); /* Functions for link-time code simplifications. */ -static bfd_reloc_status_type elf_xtensa_do_asm_simplify - PARAMS ((bfd_byte *, bfd_vma, bfd_vma)); +static bfd_reloc_status_type elf_xtensa_do_asm_simplify + PARAMS ((bfd_byte *, bfd_vma, bfd_vma, char **)); static bfd_reloc_status_type contract_asm_expansion - PARAMS ((bfd_byte *, bfd_vma, Elf_Internal_Rela *)); + PARAMS ((bfd_byte *, bfd_vma, Elf_Internal_Rela *, char **)); static xtensa_opcode swap_callx_for_call_opcode PARAMS ((xtensa_opcode)); static xtensa_opcode get_expanded_call_opcode - PARAMS ((bfd_byte *, int)); + PARAMS ((bfd_byte *, int, bfd_boolean *)); /* Access to internal relocations, section contents and symbols. */ @@ -199,18 +226,22 @@ static struct elf_link_hash_entry *get_elf_r_symndx_hash_entry PARAMS ((bfd *, unsigned long)); static bfd_vma get_elf_r_symndx_offset PARAMS ((bfd *, unsigned long)); +static bfd_boolean is_reloc_sym_weak + PARAMS ((bfd *, Elf_Internal_Rela *)); static bfd_boolean pcrel_reloc_fits - PARAMS ((xtensa_operand, bfd_vma, bfd_vma)); + PARAMS ((xtensa_opcode, int, bfd_vma, bfd_vma)); static bfd_boolean xtensa_is_property_section PARAMS ((asection *)); static bfd_boolean xtensa_is_littable_section PARAMS ((asection *)); -static bfd_boolean is_literal_section - PARAMS ((asection *)); static int internal_reloc_compare PARAMS ((const PTR, const PTR)); +static int internal_reloc_matches + PARAMS ((const PTR, const PTR)); extern char *xtensa_get_property_section_name PARAMS ((asection *, const char *)); +static flagword xtensa_get_property_predef_flags + PARAMS ((asection *)); /* Other functions called directly by the linker. */ @@ -221,9 +252,20 @@ extern bfd_boolean xtensa_callback_required_dependence deps_callback_t, PTR)); +/* Globally visible flag for choosing size optimization of NOP removal + instead of branch-target-aware minimization for NOP removal. + When nonzero, narrow all instructions and remove all NOPs possible + around longcall expansions. */ +int elf32xtensa_size_opt; + + +/* The "new_section_hook" is used to set up a per-section + "xtensa_relax_info" data structure with additional information used + during relaxation. */ typedef struct xtensa_relax_info_struct xtensa_relax_info; + /* Total count of PLT relocations seen during check_relocs. The actual PLT code must be split into multiple sections and all the sections have to be created before size_dynamic_sections, @@ -234,12 +276,25 @@ typedef struct xtensa_relax_info_struct xtensa_relax_info; static int plt_reloc_count = 0; +/* The GNU tools do not easily allow extending interfaces to pass around + the pointer to the Xtensa ISA information, so instead we add a global + variable here (in BFD) that can be used by any of the tools that need + this information. */ + +xtensa_isa xtensa_default_isa; + + /* When this is true, relocations may have been modified to refer to symbols from other input files. The per-section list of "fix" records needs to be checked when resolving relocations. */ static bfd_boolean relaxing_section = FALSE; +/* When this is true, during final links, literals that cannot be + coalesced and their relocations may be moved to other sections. */ + +int elf32xtensa_no_literal_movement = 1; + static reloc_howto_type elf_howto_table[] = { @@ -296,10 +351,115 @@ static reloc_howto_type elf_howto_table[] = /* GNU extension to record C++ vtable member usage. */ HOWTO (R_XTENSA_GNU_VTENTRY, 0, 2, 0, FALSE, 0, complain_overflow_dont, _bfd_elf_rel_vtable_reloc_fn, "R_XTENSA_GNU_VTENTRY", - FALSE, 0x00000000, 0x00000000, FALSE) + FALSE, 0x00000000, 0x00000000, FALSE), + + /* Relocations for supporting difference of symbols. */ + HOWTO (R_XTENSA_DIFF8, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, + bfd_elf_xtensa_reloc, "R_XTENSA_DIFF8", + FALSE, 0xffffffff, 0xffffffff, FALSE), + HOWTO (R_XTENSA_DIFF16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, + bfd_elf_xtensa_reloc, "R_XTENSA_DIFF16", + FALSE, 0xffffffff, 0xffffffff, FALSE), + HOWTO (R_XTENSA_DIFF32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_xtensa_reloc, "R_XTENSA_DIFF32", + FALSE, 0xffffffff, 0xffffffff, FALSE), + + /* General immediate operand relocations. */ + HOWTO (R_XTENSA_SLOT0_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT0_OP", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT1_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT1_OP", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT2_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT2_OP", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT3_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT3_OP", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT4_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT4_OP", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT5_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT5_OP", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT6_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT6_OP", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT7_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT7_OP", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT8_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT8_OP", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT9_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT9_OP", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT10_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT10_OP", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT11_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT11_OP", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT12_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT12_OP", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT13_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT13_OP", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT14_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT14_OP", + FALSE, 0x00000000, 0x00000000, TRUE), + + /* "Alternate" relocations. The meaning of these is opcode-specific. */ + HOWTO (R_XTENSA_SLOT0_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT0_ALT", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT1_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT1_ALT", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT2_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT2_ALT", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT3_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT3_ALT", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT4_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT4_ALT", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT5_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT5_ALT", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT6_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT6_ALT", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT7_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT7_ALT", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT8_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT8_ALT", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT9_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT9_ALT", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT10_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT10_ALT", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT11_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT11_ALT", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT12_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT12_ALT", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT13_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT13_ALT", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_SLOT14_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_SLOT14_ALT", + FALSE, 0x00000000, 0x00000000, TRUE) }; -#ifdef DEBUG_GEN_RELOC +#if DEBUG_GEN_RELOC #define TRACE(str) \ fprintf (stderr, "Xtensa bfd reloc lookup %d (%s)\n", code, str) #else @@ -321,6 +481,18 @@ elf_xtensa_reloc_type_lookup (abfd, code) TRACE ("BFD_RELOC_32"); return &elf_howto_table[(unsigned) R_XTENSA_32 ]; + case BFD_RELOC_XTENSA_DIFF8: + TRACE ("BFD_RELOC_XTENSA_DIFF8"); + return &elf_howto_table[(unsigned) R_XTENSA_DIFF8 ]; + + case BFD_RELOC_XTENSA_DIFF16: + TRACE ("BFD_RELOC_XTENSA_DIFF16"); + return &elf_howto_table[(unsigned) R_XTENSA_DIFF16 ]; + + case BFD_RELOC_XTENSA_DIFF32: + TRACE ("BFD_RELOC_XTENSA_DIFF32"); + return &elf_howto_table[(unsigned) R_XTENSA_DIFF32 ]; + case BFD_RELOC_XTENSA_RTLD: TRACE ("BFD_RELOC_XTENSA_RTLD"); return &elf_howto_table[(unsigned) R_XTENSA_RTLD ]; @@ -370,6 +542,22 @@ elf_xtensa_reloc_type_lookup (abfd, code) return &elf_howto_table[(unsigned) R_XTENSA_GNU_VTENTRY ]; default: + if (code >= BFD_RELOC_XTENSA_SLOT0_OP + && code <= BFD_RELOC_XTENSA_SLOT14_OP) + { + unsigned n = (R_XTENSA_SLOT0_OP + + (code - BFD_RELOC_XTENSA_SLOT0_OP)); + return &elf_howto_table[n]; + } + + if (code >= BFD_RELOC_XTENSA_SLOT0_ALT + && code <= BFD_RELOC_XTENSA_SLOT14_ALT) + { + unsigned n = (R_XTENSA_SLOT0_ALT + + (code - BFD_RELOC_XTENSA_SLOT0_ALT)); + return &elf_howto_table[n]; + } + break; } @@ -468,8 +656,48 @@ property_table_compare (ap, bp) const property_table_entry *a = (const property_table_entry *) ap; const property_table_entry *b = (const property_table_entry *) bp; - /* Check if one entry overlaps with the other; this shouldn't happen - except when searching for a match. */ + if (a->address == b->address) + { + /* The only circumstance where two entries may legitimately have the + same address is when one of them is a zero-size placeholder to + mark a place where fill can be inserted. The zero-size entry should + come first. */ + BFD_ASSERT ((a->size == 0 || b->size == 0)); + + if (a->size != b->size) + return (a->size - b->size); + + if ((a->flags & XTENSA_PROP_ALIGN) != (b->flags & XTENSA_PROP_ALIGN)) + return ((b->flags & XTENSA_PROP_ALIGN) + - (a->flags & XTENSA_PROP_ALIGN)); + + if ((a->flags & XTENSA_PROP_ALIGN) + && (GET_XTENSA_PROP_ALIGNMENT (a->flags) + != GET_XTENSA_PROP_ALIGNMENT (b->flags))) + return (GET_XTENSA_PROP_ALIGNMENT (a->flags) + - GET_XTENSA_PROP_ALIGNMENT (b->flags)); + + if ((a->flags & XTENSA_PROP_UNREACHABLE) + != (b->flags & XTENSA_PROP_UNREACHABLE)) + return ((b->flags & XTENSA_PROP_UNREACHABLE) + - (a->flags & XTENSA_PROP_UNREACHABLE)); + + return (a->flags - b->flags); + } + + return (a->address - b->address); +} + + +static int +property_table_matches (ap, bp) + const PTR ap; + const PTR bp; +{ + const property_table_entry *a = (const property_table_entry *) ap; + const property_table_entry *b = (const property_table_entry *) bp; + + /* Check if one entry overlaps with the other. */ if ((b->address >= a->address && b->address < (a->address + a->size)) || (a->address >= b->address && a->address < (b->address + b->size))) return 0; @@ -478,16 +706,17 @@ property_table_compare (ap, bp) } -/* Get the literal table or instruction table entries for the given - section. Sets TABLE_P and returns the number of entries. On error, - returns a negative value. */ +/* Get the literal table or property table entries for the given + section. Sets TABLE_P and returns the number of entries. On + error, returns a negative value. */ int -xtensa_read_table_entries (abfd, section, table_p, sec_name) +xtensa_read_table_entries (abfd, section, table_p, sec_name, output_addr) bfd *abfd; asection *section; property_table_entry **table_p; const char *sec_name; + bfd_boolean output_addr; { asection *table_section; char *table_section_name; @@ -498,27 +727,44 @@ xtensa_read_table_entries (abfd, section, table_p, sec_name) bfd_size_type num_records; Elf_Internal_Rela *internal_relocs; bfd_vma section_addr; + flagword predef_flags; + bfd_size_type table_entry_size; + + if (!section + || !(section->flags & SEC_ALLOC) + || (section->flags & SEC_DEBUGGING)) + { + *table_p = NULL; + return 0; + } - table_section_name = - xtensa_get_property_section_name (section, sec_name); + table_section_name = xtensa_get_property_section_name (section, sec_name); table_section = bfd_get_section_by_name (abfd, table_section_name); free (table_section_name); - if (table_section != NULL) + if (table_section) table_size = table_section->size; - + if (table_size == 0) { *table_p = NULL; return 0; } - num_records = table_size / 8; + predef_flags = xtensa_get_property_predef_flags (table_section); + table_entry_size = 12; + if (predef_flags) + table_entry_size -= 4; + + num_records = table_size / table_entry_size; table_data = retrieve_contents (abfd, table_section, TRUE); blocks = (property_table_entry *) bfd_malloc (num_records * sizeof (property_table_entry)); block_count = 0; - - section_addr = section->output_section->vma + section->output_offset; + + if (output_addr) + section_addr = section->output_section->vma + section->output_offset; + else + section_addr = section->vma; /* If the file has not yet been relocated, process the relocations and sort out the table entries that apply to the specified section. */ @@ -541,11 +787,18 @@ xtensa_read_table_entries (abfd, section, table_p, sec_name) if (get_elf_r_symndx_section (abfd, r_symndx) == section) { bfd_vma sym_off = get_elf_r_symndx_offset (abfd, r_symndx); + BFD_ASSERT (sym_off == 0); + BFD_ASSERT (rel->r_addend == 0); blocks[block_count].address = (section_addr + sym_off + rel->r_addend + bfd_get_32 (abfd, table_data + rel->r_offset)); blocks[block_count].size = bfd_get_32 (abfd, table_data + rel->r_offset + 4); + if (predef_flags) + blocks[block_count].flags = predef_flags; + else + blocks[block_count].flags = + bfd_get_32 (abfd, table_data + rel->r_offset + 8); block_count++; } } @@ -555,17 +808,23 @@ xtensa_read_table_entries (abfd, section, table_p, sec_name) /* The file has already been relocated and the addresses are already in the table. */ bfd_vma off; + bfd_size_type section_limit = bfd_get_section_limit (abfd, section); - for (off = 0; off < table_size; off += 8) + for (off = 0; off < table_size; off += table_entry_size) { bfd_vma address = bfd_get_32 (abfd, table_data + off); if (address >= section_addr - && address < section_addr + section->size) + && address < section_addr + section_limit) { blocks[block_count].address = address; blocks[block_count].size = bfd_get_32 (abfd, table_data + off + 4); + if (predef_flags) + blocks[block_count].flags = predef_flags; + else + blocks[block_count].flags = + bfd_get_32 (abfd, table_data + off + 8); block_count++; } } @@ -574,34 +833,47 @@ xtensa_read_table_entries (abfd, section, table_p, sec_name) release_contents (table_section, table_data); release_internal_relocs (table_section, internal_relocs); - if (block_count > 0) + if (block_count > 0) { /* Now sort them into address order for easy reference. */ qsort (blocks, block_count, sizeof (property_table_entry), property_table_compare); } - + *table_p = blocks; return block_count; } -static bfd_boolean -elf_xtensa_in_literal_pool (lit_table, lit_table_size, addr) - property_table_entry *lit_table; - int lit_table_size; +property_table_entry * +elf_xtensa_find_property_entry (property_table, property_table_size, addr) + property_table_entry *property_table; + int property_table_size; bfd_vma addr; { property_table_entry entry; + property_table_entry *rv; - if (lit_table_size == 0) - return FALSE; + if (property_table_size == 0) + return NULL; entry.address = addr; entry.size = 1; + entry.flags = 0; - if (bsearch (&entry, lit_table, lit_table_size, - sizeof (property_table_entry), property_table_compare)) + rv = bsearch (&entry, property_table, property_table_size, + sizeof (property_table_entry), property_table_matches); + return rv; +} + + +static bfd_boolean +elf_xtensa_in_literal_pool (lit_table, lit_table_size, addr) + property_table_entry *lit_table; + int lit_table_size; + bfd_vma addr; +{ + if (elf_xtensa_find_property_entry (lit_table, lit_table_size, addr)) return TRUE; return FALSE; @@ -714,8 +986,8 @@ elf_xtensa_check_relocs (abfd, info, sec, relocs) size = symtab_hdr->sh_info; size *= sizeof (bfd_signed_vma); - local_got_refcounts = ((bfd_signed_vma *) - bfd_zalloc (abfd, size)); + local_got_refcounts = + (bfd_signed_vma *) bfd_zalloc (abfd, size); if (local_got_refcounts == NULL) return FALSE; elf_local_got_refcounts (abfd) = local_got_refcounts; @@ -727,8 +999,41 @@ elf_xtensa_check_relocs (abfd, info, sec, relocs) case R_XTENSA_OP0: case R_XTENSA_OP1: case R_XTENSA_OP2: + case R_XTENSA_SLOT0_OP: + case R_XTENSA_SLOT1_OP: + case R_XTENSA_SLOT2_OP: + case R_XTENSA_SLOT3_OP: + case R_XTENSA_SLOT4_OP: + case R_XTENSA_SLOT5_OP: + case R_XTENSA_SLOT6_OP: + case R_XTENSA_SLOT7_OP: + case R_XTENSA_SLOT8_OP: + case R_XTENSA_SLOT9_OP: + case R_XTENSA_SLOT10_OP: + case R_XTENSA_SLOT11_OP: + case R_XTENSA_SLOT12_OP: + case R_XTENSA_SLOT13_OP: + case R_XTENSA_SLOT14_OP: + case R_XTENSA_SLOT0_ALT: + case R_XTENSA_SLOT1_ALT: + case R_XTENSA_SLOT2_ALT: + case R_XTENSA_SLOT3_ALT: + case R_XTENSA_SLOT4_ALT: + case R_XTENSA_SLOT5_ALT: + case R_XTENSA_SLOT6_ALT: + case R_XTENSA_SLOT7_ALT: + case R_XTENSA_SLOT8_ALT: + case R_XTENSA_SLOT9_ALT: + case R_XTENSA_SLOT10_ALT: + case R_XTENSA_SLOT11_ALT: + case R_XTENSA_SLOT12_ALT: + case R_XTENSA_SLOT13_ALT: + case R_XTENSA_SLOT14_ALT: case R_XTENSA_ASM_EXPAND: case R_XTENSA_ASM_SIMPLIFY: + case R_XTENSA_DIFF8: + case R_XTENSA_DIFF16: + case R_XTENSA_DIFF32: /* Nothing to do for these. */ break; @@ -1417,18 +1722,30 @@ elf_xtensa_do_reloc (howto, abfd, input_section, relocation, bfd_boolean is_weak_undef; char **error_message; { + xtensa_format fmt; xtensa_opcode opcode; - xtensa_operand operand; - xtensa_encode_result encode_result; xtensa_isa isa = xtensa_default_isa; - xtensa_insnbuf ibuff; - bfd_vma self_address; - int opnd; + static xtensa_insnbuf ibuff = NULL; + static xtensa_insnbuf sbuff = NULL; + bfd_vma self_address = 0; + bfd_size_type input_size; + int opnd, slot; uint32 newval; + if (!ibuff) + { + ibuff = xtensa_insnbuf_alloc (isa); + sbuff = xtensa_insnbuf_alloc (isa); + } + + input_size = bfd_get_section_limit (abfd, input_section); + switch (howto->type) { case R_XTENSA_NONE: + case R_XTENSA_DIFF8: + case R_XTENSA_DIFF16: + case R_XTENSA_DIFF32: return bfd_reloc_ok; case R_XTENSA_ASM_EXPAND: @@ -1437,14 +1754,14 @@ elf_xtensa_do_reloc (howto, abfd, input_section, relocation, /* Check for windowed CALL across a 1GB boundary. */ xtensa_opcode opcode = get_expanded_call_opcode (contents + address, - input_section->size - address); + input_size - address, 0); if (is_windowed_call_opcode (opcode)) { self_address = (input_section->output_section->vma + input_section->output_offset + address); - if ((self_address >> CALL_SEGMENT_BITS) != - (relocation >> CALL_SEGMENT_BITS)) + if ((self_address >> CALL_SEGMENT_BITS) + != (relocation >> CALL_SEGMENT_BITS)) { *error_message = "windowed longcall crosses 1GB boundary; " "return may fail"; @@ -1455,16 +1772,17 @@ elf_xtensa_do_reloc (howto, abfd, input_section, relocation, return bfd_reloc_ok; case R_XTENSA_ASM_SIMPLIFY: - { + { /* Convert the L32R/CALLX to CALL. */ - bfd_reloc_status_type retval = - elf_xtensa_do_asm_simplify (contents, address, input_section->size); + bfd_reloc_status_type retval = + elf_xtensa_do_asm_simplify (contents, address, input_size, + error_message); if (retval != bfd_reloc_ok) - return retval; + return bfd_reloc_dangerous; /* The CALL needs to be relocated. Continue below for that part. */ address += 3; - howto = &elf_howto_table[(unsigned) R_XTENSA_OP0 ]; + howto = &elf_howto_table[(unsigned) R_XTENSA_SLOT0_OP ]; } break; @@ -1479,67 +1797,125 @@ elf_xtensa_do_reloc (howto, abfd, input_section, relocation, return bfd_reloc_ok; } - /* Read the instruction into a buffer and decode the opcode. */ - ibuff = xtensa_insnbuf_alloc (isa); - xtensa_insnbuf_from_chars (isa, ibuff, contents + address); - opcode = xtensa_decode_insn (isa, ibuff); - - /* Determine which operand is being relocated. */ - if (opcode == XTENSA_UNDEFINED) + /* Only instruction slot-specific relocations handled below.... */ + slot = get_relocation_slot (howto->type); + if (slot == XTENSA_UNDEFINED) { - *error_message = "cannot decode instruction"; + *error_message = "unexpected relocation"; return bfd_reloc_dangerous; } - if (howto->type < R_XTENSA_OP0 || howto->type > R_XTENSA_OP2) + /* Read the instruction into a buffer and decode the opcode. */ + xtensa_insnbuf_from_chars (isa, ibuff, contents + address, + input_size - address); + fmt = xtensa_format_decode (isa, ibuff); + if (fmt == XTENSA_UNDEFINED) { - *error_message = "unexpected relocation"; + *error_message = "cannot decode instruction format"; return bfd_reloc_dangerous; } - opnd = howto->type - R_XTENSA_OP0; + xtensa_format_get_slot (isa, fmt, slot, ibuff, sbuff); - /* Calculate the PC address for this instruction. */ - if (!howto->pc_relative) + opcode = xtensa_opcode_decode (isa, fmt, slot, sbuff); + if (opcode == XTENSA_UNDEFINED) { - *error_message = "expected PC-relative relocation"; + *error_message = "cannot decode instruction opcode"; return bfd_reloc_dangerous; } - self_address = (input_section->output_section->vma - + input_section->output_offset - + address); + /* Check for opcode-specific "alternate" relocations. */ + if (is_alt_relocation (howto->type)) + { + if (opcode == get_l32r_opcode ()) + { + /* Handle the special-case of non-PC-relative L32R instructions. */ + bfd *output_bfd = input_section->output_section->owner; + asection *lit4_sec = bfd_get_section_by_name (output_bfd, ".lit4"); + if (!lit4_sec) + { + *error_message = "relocation references missing .lit4 section"; + return bfd_reloc_dangerous; + } + self_address = ((lit4_sec->vma & ~0xfff) + + 0x40000 - 3); /* -3 to compensate for do_reloc */ + newval = relocation; + opnd = 1; + } + else if (opcode == get_const16_opcode ()) + { + /* ALT used for high 16 bits. */ + newval = relocation >> 16; + opnd = 1; + } + else + { + /* No other "alternate" relocations currently defined. */ + *error_message = "unexpected relocation"; + return bfd_reloc_dangerous; + } + } + else /* Not an "alternate" relocation.... */ + { + if (opcode == get_const16_opcode ()) + { + newval = relocation & 0xffff; + opnd = 1; + } + else + { + /* ...normal PC-relative relocation.... */ + + /* Determine which operand is being relocated. */ + opnd = get_relocation_opnd (opcode, howto->type); + if (opnd == XTENSA_UNDEFINED) + { + *error_message = "unexpected relocation"; + return bfd_reloc_dangerous; + } + + if (!howto->pc_relative) + { + *error_message = "expected PC-relative relocation"; + return bfd_reloc_dangerous; + } - /* Apply the relocation. */ - operand = xtensa_get_operand (isa, opcode, opnd); - newval = xtensa_operand_do_reloc (operand, relocation, self_address); - encode_result = xtensa_operand_encode (operand, &newval); - xtensa_operand_set_field (operand, ibuff, newval); + /* Calculate the PC address for this instruction. */ + self_address = (input_section->output_section->vma + + input_section->output_offset + + address); - /* Write the modified instruction back out of the buffer. */ - xtensa_insnbuf_to_chars (isa, ibuff, contents + address); - free (ibuff); + newval = relocation; + } + } - if (encode_result != xtensa_encode_result_ok) + /* Apply the relocation. */ + if (xtensa_operand_do_reloc (isa, opcode, opnd, &newval, self_address) + || xtensa_operand_encode (isa, opcode, opnd, &newval) + || xtensa_operand_set_field (isa, opcode, opnd, fmt, slot, + sbuff, newval)) { - char *message = build_encoding_error_message (opcode, encode_result); - *error_message = message; + *error_message = build_encoding_error_message (opcode, relocation); return bfd_reloc_dangerous; } - /* Final check for call. */ + /* Check for calls across 1GB boundaries. */ if (is_direct_call_opcode (opcode) && is_windowed_call_opcode (opcode)) { - if ((self_address >> CALL_SEGMENT_BITS) != - (relocation >> CALL_SEGMENT_BITS)) + if ((self_address >> CALL_SEGMENT_BITS) + != (relocation >> CALL_SEGMENT_BITS)) { - *error_message = "windowed call crosses 1GB boundary; " - "return may fail"; + *error_message = + "windowed call crosses 1GB boundary; return may fail"; return bfd_reloc_dangerous; } } + /* Write the modified instruction back out of the buffer. */ + xtensa_format_set_slot (isa, fmt, slot, ibuff, sbuff); + xtensa_insnbuf_to_chars (isa, ibuff, contents + address, + input_size - address); return bfd_reloc_ok; } @@ -1575,55 +1951,29 @@ vsprint_msg VPARAMS ((const char *origmsg, const char *fmt, int arglen, ...)) static char * -build_encoding_error_message (opcode, encode_result) +build_encoding_error_message (opcode, target_address) xtensa_opcode opcode; - xtensa_encode_result encode_result; + bfd_vma target_address; { const char *opname = xtensa_opcode_name (xtensa_default_isa, opcode); - const char *msg = NULL; + const char *msg; - switch (encode_result) + msg = "cannot encode"; + if (is_direct_call_opcode (opcode)) { - case xtensa_encode_result_ok: - msg = "unexpected valid encoding"; - break; - case xtensa_encode_result_align: - msg = "misaligned encoding"; - break; - case xtensa_encode_result_not_in_table: - msg = "encoding not in lookup table"; - break; - case xtensa_encode_result_too_low: - msg = "encoding out of range: too low"; - break; - case xtensa_encode_result_too_high: - msg = "encoding out of range: too high"; - break; - case xtensa_encode_result_not_ok: - default: - msg = "could not encode"; - break; + if ((target_address & 0x3) != 0) + msg = "misaligned call target"; + else + msg = "call target out of range"; } - - if (is_direct_call_opcode (opcode) - && (encode_result == xtensa_encode_result_too_low - || encode_result == xtensa_encode_result_too_high)) - - msg = "direct call out of range"; - - else if (opcode == get_l32r_opcode ()) + else if (opcode == get_l32r_opcode ()) { - /* L32Rs have the strange interaction with encoding in that they - have an unsigned immediate field, so libisa returns "too high" - when the absolute value is out of range and never returns "too - low", but I leave the "too low" message in case anything - changes. */ - if (encode_result == xtensa_encode_result_too_low) - msg = "literal out of range"; - else if (encode_result == xtensa_encode_result_too_high) - msg = "literal placed after use"; + if ((target_address & 0x3) != 0) + msg = "misaligned literal target"; + else + msg = "literal target out of range"; } - + return vsprint_msg (opname, ": %s", strlen (msg) + 2, msg); } @@ -1709,7 +2059,7 @@ bfd_elf_xtensa_reloc (abfd, reloc_entry, symbol, data, input_section, to the reloc entry rather than the raw data. Everything except relocations against section symbols has already been handled above. */ - + BFD_ASSERT (symbol->flags & BSF_SECTION_SYM); reloc_entry->addend = relocation; reloc_entry->address += input_section->output_offset; @@ -1816,9 +2166,10 @@ elf_xtensa_relocate_section (output_bfd, info, input_bfd, property_table_entry *lit_table = 0; int ltblsize = 0; char *error_message = NULL; + bfd_size_type input_size; - if (xtensa_default_isa == NULL) - xtensa_isa_init (); + if (!xtensa_default_isa) + xtensa_default_isa = xtensa_isa_init (0, 0); dynobj = elf_hash_table (info)->dynobj; symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; @@ -1835,11 +2186,14 @@ elf_xtensa_relocate_section (output_bfd, info, input_bfd, if (elf_hash_table (info)->dynamic_sections_created) { ltblsize = xtensa_read_table_entries (input_bfd, input_section, - &lit_table, XTENSA_LIT_SEC_NAME); + &lit_table, XTENSA_LIT_SEC_NAME, + TRUE); if (ltblsize < 0) return FALSE; } + input_size = bfd_get_section_limit (input_bfd, input_section); + rel = relocs; relend = relocs + input_section->reloc_count; for (; rel < relend; rel++) @@ -1872,7 +2226,7 @@ elf_xtensa_relocate_section (output_bfd, info, input_bfd, if (info->relocatable) { - /* This is a relocatable link. + /* This is a relocatable link. 1) If the reloc is against a section symbol, adjust according to the output section. 2) If there is a new target for this relocation, @@ -1883,15 +2237,26 @@ elf_xtensa_relocate_section (output_bfd, info, input_bfd, if (relaxing_section) { /* Check if this references a section in another input file. */ - do_fix_for_relocatable_link (rel, input_bfd, input_section); + if (!do_fix_for_relocatable_link (rel, input_bfd, input_section, + contents)) + return FALSE; r_type = ELF32_R_TYPE (rel->r_info); } - if (r_type == R_XTENSA_ASM_SIMPLIFY) + if (r_type == R_XTENSA_ASM_SIMPLIFY) { + char *error_message = NULL; /* Convert ASM_SIMPLIFY into the simpler relocation so that they never escape a relaxing link. */ - contract_asm_expansion (contents, input_section->size, rel); + r = contract_asm_expansion (contents, input_size, rel, + &error_message); + if (r != bfd_reloc_ok) + { + if (!((*info->callbacks->reloc_dangerous) + (info, error_message, input_bfd, input_section, + rel->r_offset))) + return FALSE; + } r_type = ELF32_R_TYPE (rel->r_info); } @@ -1979,7 +2344,8 @@ elf_xtensa_relocate_section (output_bfd, info, input_bfd, if (relaxing_section) { /* Check if this references a section in another input file. */ - do_fix_for_final_link (rel, input_section, &relocation); + do_fix_for_final_link (rel, input_bfd, input_section, contents, + &relocation); /* Update some already cached values. */ r_type = ELF32_R_TYPE (rel->r_info); @@ -1987,9 +2353,12 @@ elf_xtensa_relocate_section (output_bfd, info, input_bfd, } /* Sanity check the address. */ - if (rel->r_offset >= bfd_get_section_limit (input_bfd, input_section) + if (rel->r_offset >= input_size && ELF32_R_TYPE (rel->r_info) != R_XTENSA_NONE) { + (*_bfd_error_handler) + (_("%B(%A+0x%lx): relocation offset out of range (size=0x%x)"), + input_bfd, input_section, rel->r_offset, input_size); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -1999,9 +2368,7 @@ elf_xtensa_relocate_section (output_bfd, info, input_bfd, { bfd_boolean dynamic_symbol = xtensa_elf_dynamic_symbol_p (h, info); - if (dynamic_symbol && (r_type == R_XTENSA_OP0 - || r_type == R_XTENSA_OP1 - || r_type == R_XTENSA_OP2)) + if (dynamic_symbol && is_operand_relocation (r_type)) { /* This is an error. The symbol's real value won't be known until runtime and it's likely to be out of range anyway. */ @@ -2073,7 +2440,7 @@ elf_xtensa_relocate_section (output_bfd, info, input_bfd, /* Create the PLT entry and set the initial contents of the literal entry to the address of the PLT entry. */ - relocation = + relocation = elf_xtensa_create_plt_entry (dynobj, output_bfd, srel->reloc_count); } @@ -2114,12 +2481,12 @@ elf_xtensa_relocate_section (output_bfd, info, input_bfd, relocation + rel->r_addend, contents, rel->r_offset, is_weak_undef, &error_message); - + if (r != bfd_reloc_ok && !warned) { const char *name; - BFD_ASSERT (r == bfd_reloc_dangerous); + BFD_ASSERT (r == bfd_reloc_dangerous || r == bfd_reloc_other); BFD_ASSERT (error_message != (char *) NULL); if (h != NULL) @@ -2132,8 +2499,16 @@ elf_xtensa_relocate_section (output_bfd, info, input_bfd, name = bfd_section_name (input_bfd, sec); } if (name) - error_message = vsprint_msg (error_message, ": %s", - strlen (name), name); + { + if (rel->r_addend == 0) + error_message = vsprint_msg (error_message, ": %s", + strlen (name) + 2, name); + else + error_message = vsprint_msg (error_message, ": (%s+0x%x)", + strlen (name) + 22, + name, rel->r_addend); + } + if (!((*info->callbacks->reloc_dangerous) (info, error_message, input_bfd, input_section, rel->r_offset))) @@ -2205,7 +2580,7 @@ elf_xtensa_combine_prop_entries (output_bfd, sxtlit, sgotloc) if (sgotloc_size != section_size) { (*_bfd_error_handler) - ("internal inconsistency in size of .got.loc section"); + (_("internal inconsistency in size of .got.loc section")); return -1; } @@ -2519,10 +2894,10 @@ elf_xtensa_merge_private_bfd_data (ibfd, obfd) out_mach = out_flag & EF_XTENSA_MACH; in_mach = in_flag & EF_XTENSA_MACH; - if (out_mach != in_mach) + if (out_mach != in_mach) { (*_bfd_error_handler) - ("%B: incompatible machine type. Output is 0x%x. Input is 0x%x", + (_("%B: incompatible machine type. Output is 0x%x. Input is 0x%x"), ibfd, out_mach, in_mach); bfd_set_error (bfd_error_wrong_format); return FALSE; @@ -2532,22 +2907,20 @@ elf_xtensa_merge_private_bfd_data (ibfd, obfd) { elf_flags_init (obfd) = TRUE; elf_elfheader (obfd)->e_flags = in_flag; - + if (bfd_get_arch (obfd) == bfd_get_arch (ibfd) && bfd_get_arch_info (obfd)->the_default) return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd)); - + return TRUE; } - if ((out_flag & EF_XTENSA_XT_INSN) != - (in_flag & EF_XTENSA_XT_INSN)) - elf_elfheader(obfd)->e_flags &= (~ EF_XTENSA_XT_INSN); + if ((out_flag & EF_XTENSA_XT_INSN) != (in_flag & EF_XTENSA_XT_INSN)) + elf_elfheader (obfd)->e_flags &= (~ EF_XTENSA_XT_INSN); - if ((out_flag & EF_XTENSA_XT_LIT) != - (in_flag & EF_XTENSA_XT_LIT)) - elf_elfheader(obfd)->e_flags &= (~ EF_XTENSA_XT_LIT); + if ((out_flag & EF_XTENSA_XT_LIT) != (in_flag & EF_XTENSA_XT_LIT)) + elf_elfheader (obfd)->e_flags &= (~ EF_XTENSA_XT_LIT); return TRUE; } @@ -2585,7 +2958,7 @@ elf_xtensa_print_private_bfd_data (abfd, farg) flagword e_flags = elf_elfheader (abfd)->e_flags; fprintf (f, "\nXtensa header:\n"); - if ((e_flags & EF_XTENSA_MACH) == E_XTENSA_MACH) + if ((e_flags & EF_XTENSA_MACH) == E_XTENSA_MACH) fprintf (f, "\nMachine = Base\n"); else fprintf (f, "\nMachine Id = 0x%x\n", e_flags & EF_XTENSA_MACH); @@ -2948,14 +3321,30 @@ is_windowed_call_opcode (opcode) } +static xtensa_opcode +get_const16_opcode (void) +{ + static bfd_boolean done_lookup = FALSE; + static xtensa_opcode const16_opcode = XTENSA_UNDEFINED; + if (!done_lookup) + { + const16_opcode = xtensa_opcode_lookup (xtensa_default_isa, "const16"); + done_lookup = TRUE; + } + return const16_opcode; +} + + static xtensa_opcode get_l32r_opcode (void) { static xtensa_opcode l32r_opcode = XTENSA_UNDEFINED; - if (l32r_opcode == XTENSA_UNDEFINED) + static bfd_boolean done_lookup = FALSE; + + if (!done_lookup) { l32r_opcode = xtensa_opcode_lookup (xtensa_default_isa, "l32r"); - BFD_ASSERT (l32r_opcode != XTENSA_UNDEFINED); + done_lookup = TRUE; } return l32r_opcode; } @@ -2976,1494 +3365,4157 @@ l32r_offset (addr, pc) } -/* Get the operand number for a PC-relative relocation. - If the relocation is not a PC-relative one, return (-1). */ - static int -get_relocation_opnd (irel) - Elf_Internal_Rela *irel; +get_relocation_opnd (opcode, r_type) + xtensa_opcode opcode; + int r_type; { - if (ELF32_R_TYPE (irel->r_info) < R_XTENSA_OP0 - || ELF32_R_TYPE (irel->r_info) >= R_XTENSA_max) - return -1; - return ELF32_R_TYPE (irel->r_info) - R_XTENSA_OP0; + xtensa_isa isa = xtensa_default_isa; + int last_immed, last_opnd, opi; + + if (opcode == XTENSA_UNDEFINED) + return XTENSA_UNDEFINED; + + /* Find the last visible PC-relative immediate operand for the opcode. + If there are no PC-relative immediates, then choose the last visible + immediate; otherwise, fail and return XTENSA_UNDEFINED. */ + last_immed = XTENSA_UNDEFINED; + last_opnd = xtensa_opcode_num_operands (isa, opcode); + for (opi = last_opnd - 1; opi >= 0; opi--) + { + if (xtensa_operand_is_visible (isa, opcode, opi) == 0) + continue; + if (xtensa_operand_is_PCrelative (isa, opcode, opi) == 1) + { + last_immed = opi; + break; + } + if (last_immed == XTENSA_UNDEFINED + && xtensa_operand_is_register (isa, opcode, opi) == 0) + last_immed = opi; + } + if (last_immed < 0) + return XTENSA_UNDEFINED; + + /* If the operand number was specified in an old-style relocation, + check for consistency with the operand computed above. */ + if (r_type >= R_XTENSA_OP0 && r_type <= R_XTENSA_OP2) + { + int reloc_opnd = r_type - R_XTENSA_OP0; + if (reloc_opnd != last_immed) + return XTENSA_UNDEFINED; + } + + return last_immed; +} + + +int +get_relocation_slot (r_type) + int r_type; +{ + switch (r_type) + { + case R_XTENSA_OP0: + case R_XTENSA_OP1: + case R_XTENSA_OP2: + return 0; + + default: + if (r_type >= R_XTENSA_SLOT0_OP && r_type <= R_XTENSA_SLOT14_OP) + return r_type - R_XTENSA_SLOT0_OP; + if (r_type >= R_XTENSA_SLOT0_ALT && r_type <= R_XTENSA_SLOT14_ALT) + return r_type - R_XTENSA_SLOT0_ALT; + break; + } + + return XTENSA_UNDEFINED; } /* Get the opcode for a relocation. */ static xtensa_opcode -get_relocation_opcode (sec, contents, irel) +get_relocation_opcode (abfd, sec, contents, irel) + bfd *abfd; asection *sec; bfd_byte *contents; Elf_Internal_Rela *irel; { static xtensa_insnbuf ibuff = NULL; + static xtensa_insnbuf sbuff = NULL; xtensa_isa isa = xtensa_default_isa; - - if (get_relocation_opnd (irel) == -1) - return XTENSA_UNDEFINED; + xtensa_format fmt; + int slot; if (contents == NULL) return XTENSA_UNDEFINED; - if (sec->size <= irel->r_offset) + if (bfd_get_section_limit (abfd, sec) <= irel->r_offset) return XTENSA_UNDEFINED; if (ibuff == NULL) - ibuff = xtensa_insnbuf_alloc (isa); - + { + ibuff = xtensa_insnbuf_alloc (isa); + sbuff = xtensa_insnbuf_alloc (isa); + } + /* Decode the instruction. */ - xtensa_insnbuf_from_chars (isa, ibuff, &contents[irel->r_offset]); - return xtensa_decode_insn (isa, ibuff); + xtensa_insnbuf_from_chars (isa, ibuff, &contents[irel->r_offset], + sec->size - irel->r_offset); + fmt = xtensa_format_decode (isa, ibuff); + slot = get_relocation_slot (ELF32_R_TYPE (irel->r_info)); + if (slot == XTENSA_UNDEFINED) + return XTENSA_UNDEFINED; + xtensa_format_get_slot (isa, fmt, slot, ibuff, sbuff); + return xtensa_opcode_decode (isa, fmt, slot, sbuff); } bfd_boolean -is_l32r_relocation (sec, contents, irel) +is_l32r_relocation (abfd, sec, contents, irel) + bfd *abfd; asection *sec; bfd_byte *contents; Elf_Internal_Rela *irel; { xtensa_opcode opcode; - - if (ELF32_R_TYPE (irel->r_info) != R_XTENSA_OP1) + if (!is_operand_relocation (ELF32_R_TYPE (irel->r_info))) return FALSE; - - opcode = get_relocation_opcode (sec, contents, irel); + opcode = get_relocation_opcode (abfd, sec, contents, irel); return (opcode == get_l32r_opcode ()); } - -/* Code for transforming CALLs at link-time. */ -static bfd_reloc_status_type -elf_xtensa_do_asm_simplify (contents, address, content_length) +static bfd_size_type +get_asm_simplify_size (contents, content_len, offset) bfd_byte *contents; - bfd_vma address; - bfd_vma content_length; + bfd_size_type content_len; + bfd_size_type offset; { - static xtensa_insnbuf insnbuf = NULL; - xtensa_opcode opcode; - xtensa_operand operand; - xtensa_opcode direct_call_opcode; - xtensa_isa isa = xtensa_default_isa; - bfd_byte *chbuf = contents + address; - int opn; + bfd_size_type insnlen, size = 0; - if (insnbuf == NULL) - insnbuf = xtensa_insnbuf_alloc (isa); + /* Decode the size of the next two instructions. */ + insnlen = insn_decode_len (contents, content_len, offset); + if (insnlen == 0) + return 0; - if (content_length < address) - { - (*_bfd_error_handler) - ("Attempt to convert L32R/CALLX to CALL failed"); - return bfd_reloc_other; - } - - opcode = get_expanded_call_opcode (chbuf, content_length - address); - direct_call_opcode = swap_callx_for_call_opcode (opcode); - if (direct_call_opcode == XTENSA_UNDEFINED) - { - (*_bfd_error_handler) - ("Attempt to convert L32R/CALLX to CALL failed"); - return bfd_reloc_other; - } + size += insnlen; - /* Assemble a NOP ("or a1, a1, a1") into the 0 byte offset. */ - opcode = xtensa_opcode_lookup (isa, "or"); - xtensa_encode_insn (isa, opcode, insnbuf); - for (opn = 0; opn < 3; opn++) - { - operand = xtensa_get_operand (isa, opcode, opn); - xtensa_operand_set_field (operand, insnbuf, 1); - } - xtensa_insnbuf_to_chars (isa, insnbuf, chbuf); + insnlen = insn_decode_len (contents, content_len, offset + size); + if (insnlen == 0) + return 0; - /* Assemble a CALL ("callN 0") into the 3 byte offset. */ - xtensa_encode_insn (isa, direct_call_opcode, insnbuf); - operand = xtensa_get_operand (isa, opcode, 0); - xtensa_operand_set_field (operand, insnbuf, 0); - xtensa_insnbuf_to_chars (isa, insnbuf, chbuf + 3); + size += insnlen; + return size; +} - return bfd_reloc_ok; + +bfd_boolean +is_alt_relocation (r_type) + int r_type; +{ + return (r_type >= R_XTENSA_SLOT0_ALT + && r_type <= R_XTENSA_SLOT14_ALT); } -static bfd_reloc_status_type -contract_asm_expansion (contents, content_length, irel) - bfd_byte *contents; - bfd_vma content_length; - Elf_Internal_Rela *irel; +bfd_boolean +is_operand_relocation (r_type) + int r_type; { - bfd_reloc_status_type retval = - elf_xtensa_do_asm_simplify (contents, irel->r_offset, content_length); + switch (r_type) + { + case R_XTENSA_OP0: + case R_XTENSA_OP1: + case R_XTENSA_OP2: + return TRUE; - if (retval != bfd_reloc_ok) - return retval; + default: + if (r_type >= R_XTENSA_SLOT0_OP && r_type <= R_XTENSA_SLOT14_OP) + return TRUE; + if (r_type >= R_XTENSA_SLOT0_ALT && r_type <= R_XTENSA_SLOT14_ALT) + return TRUE; + break; + } - /* Update the irel->r_offset field so that the right immediate and - the right instruction are modified during the relocation. */ - irel->r_offset += 3; - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_XTENSA_OP0); - return bfd_reloc_ok; + return FALSE; } + +#define MIN_INSN_LENGTH 2 -static xtensa_opcode -swap_callx_for_call_opcode (opcode) - xtensa_opcode opcode; +/* Return 0 if it fails to decode. */ + +bfd_size_type +insn_decode_len (contents, content_len, offset) + bfd_byte *contents; + bfd_size_type content_len; + bfd_size_type offset; { - init_call_opcodes (); + int insn_len; + xtensa_isa isa = xtensa_default_isa; + xtensa_format fmt; + static xtensa_insnbuf ibuff = NULL; - if (opcode == callx0_op) return call0_op; - if (opcode == callx4_op) return call4_op; - if (opcode == callx8_op) return call8_op; - if (opcode == callx12_op) return call12_op; + if (offset + MIN_INSN_LENGTH > content_len) + return 0; - /* Return XTENSA_UNDEFINED if the opcode is not an indirect call. */ - return XTENSA_UNDEFINED; + if (ibuff == NULL) + ibuff = xtensa_insnbuf_alloc (isa); + xtensa_insnbuf_from_chars (isa, ibuff, &contents[offset], + content_len - offset); + fmt = xtensa_format_decode (isa, ibuff); + if (fmt == XTENSA_UNDEFINED) + return 0; + insn_len = xtensa_format_length (isa, fmt); + if (insn_len == XTENSA_UNDEFINED) + return 0; + return insn_len; } -/* Check if "buf" is pointing to a "L32R aN; CALLX aN" sequence, and - if so, return the CALLX opcode. If not, return XTENSA_UNDEFINED. */ +/* Decode the opcode for a single slot instruction. + Return 0 if it fails to decode or the instruction is multi-slot. */ -#define L32R_TARGET_REG_OPERAND 0 -#define CALLN_SOURCE_OPERAND 0 - -static xtensa_opcode -get_expanded_call_opcode (buf, bufsize) - bfd_byte *buf; - int bufsize; +xtensa_opcode +insn_decode_opcode (contents, content_len, offset, slot) + bfd_byte *contents; + bfd_size_type content_len; + bfd_size_type offset; + int slot; { - static xtensa_insnbuf insnbuf = NULL; - xtensa_opcode opcode; - xtensa_operand operand; xtensa_isa isa = xtensa_default_isa; - uint32 regno, call_regno; - - /* Buffer must be at least 6 bytes. */ - if (bufsize < 6) + xtensa_format fmt; + static xtensa_insnbuf insnbuf = NULL; + static xtensa_insnbuf slotbuf = NULL; + + if (offset + MIN_INSN_LENGTH > content_len) return XTENSA_UNDEFINED; if (insnbuf == NULL) - insnbuf = xtensa_insnbuf_alloc (isa); - - xtensa_insnbuf_from_chars (isa, insnbuf, buf); - opcode = xtensa_decode_insn (isa, insnbuf); - - if (opcode != get_l32r_opcode ()) - return XTENSA_UNDEFINED; - - operand = xtensa_get_operand (isa, opcode, L32R_TARGET_REG_OPERAND); - regno = xtensa_operand_decode - (operand, xtensa_operand_get_field (operand, insnbuf)); - - /* Next instruction should be an CALLXn with operand 0 == regno. */ - xtensa_insnbuf_from_chars (isa, insnbuf, - buf + xtensa_insn_length (isa, opcode)); - opcode = xtensa_decode_insn (isa, insnbuf); - - if (!is_indirect_call_opcode (opcode)) + { + insnbuf = xtensa_insnbuf_alloc (isa); + slotbuf = xtensa_insnbuf_alloc (isa); + } + + xtensa_insnbuf_from_chars (isa, insnbuf, &contents[offset], + content_len - offset); + fmt = xtensa_format_decode (isa, insnbuf); + if (fmt == XTENSA_UNDEFINED) return XTENSA_UNDEFINED; - - operand = xtensa_get_operand (isa, opcode, CALLN_SOURCE_OPERAND); - call_regno = xtensa_operand_decode - (operand, xtensa_operand_get_field (operand, insnbuf)); - if (call_regno != regno) + + if (slot >= xtensa_format_num_slots (isa, fmt)) return XTENSA_UNDEFINED; - - return opcode; -} - -/* Data structures used during relaxation. */ + xtensa_format_get_slot (isa, fmt, slot, insnbuf, slotbuf); + return xtensa_opcode_decode (isa, fmt, slot, slotbuf); +} -/* r_reloc: relocation values. */ -/* Through the relaxation process, we need to keep track of the values - that will result from evaluating relocations. The standard ELF - relocation structure is not sufficient for this purpose because we're - operating on multiple input files at once, so we need to know which - input file a relocation refers to. The r_reloc structure thus - records both the input file (bfd) and ELF relocation. +/* The offset is the offset in the contents. + The address is the address of that offset. */ - For efficiency, an r_reloc also contains a "target_offset" field to - cache the target-section-relative offset value that is represented by - the relocation. */ +static bfd_boolean +check_branch_target_aligned (contents, content_length, offset, address) + bfd_byte *contents; + bfd_size_type content_length; + bfd_vma offset; + bfd_vma address; +{ + bfd_size_type insn_len = insn_decode_len (contents, content_length, offset); + if (insn_len == 0) + return FALSE; + return check_branch_target_aligned_address (address, insn_len); +} -typedef struct r_reloc_struct r_reloc; -struct r_reloc_struct +static bfd_boolean +check_loop_aligned (contents, content_length, offset, address) + bfd_byte *contents; + bfd_size_type content_length; + bfd_vma offset; + bfd_vma address; { - bfd *abfd; - Elf_Internal_Rela rela; - bfd_vma target_offset; -}; + bfd_size_type loop_len, insn_len; + xtensa_opcode opcode = + insn_decode_opcode (contents, content_length, offset, 0); + BFD_ASSERT (opcode != XTENSA_UNDEFINED); + if (opcode != XTENSA_UNDEFINED) + return FALSE; + BFD_ASSERT (xtensa_opcode_is_loop (xtensa_default_isa, opcode)); + if (!xtensa_opcode_is_loop (xtensa_default_isa, opcode)) + return FALSE; -static bfd_boolean r_reloc_is_const - PARAMS ((const r_reloc *)); -static void r_reloc_init - PARAMS ((r_reloc *, bfd *, Elf_Internal_Rela *)); -static bfd_vma r_reloc_get_target_offset - PARAMS ((const r_reloc *)); -static asection *r_reloc_get_section - PARAMS ((const r_reloc *)); -static bfd_boolean r_reloc_is_defined - PARAMS ((const r_reloc *)); -static struct elf_link_hash_entry *r_reloc_get_hash_entry - PARAMS ((const r_reloc *)); + loop_len = insn_decode_len (contents, content_length, offset); + BFD_ASSERT (loop_len != 0); + if (loop_len == 0) + return FALSE; + + insn_len = insn_decode_len (contents, content_length, offset + loop_len); + BFD_ASSERT (insn_len != 0); + if (insn_len == 0) + return FALSE; + return check_branch_target_aligned_address (address + loop_len, insn_len); +} -/* The r_reloc structure is included by value in literal_value, but not - every literal_value has an associated relocation -- some are simple - constants. In such cases, we set all the fields in the r_reloc - struct to zero. The r_reloc_is_const function should be used to - detect this case. */ static bfd_boolean -r_reloc_is_const (r_rel) - const r_reloc *r_rel; +check_branch_target_aligned_address (addr, len) + bfd_vma addr; + int len; { - return (r_rel->abfd == NULL); + if (len == 8) + return (addr % 8 == 0); + return ((addr >> 2) == ((addr + len - 1) >> 2)); } + +/* Instruction widening and narrowing. */ -static void -r_reloc_init (r_rel, abfd, irel) - r_reloc *r_rel; - bfd *abfd; - Elf_Internal_Rela *irel; -{ - if (irel != NULL) - { - r_rel->rela = *irel; - r_rel->abfd = abfd; - r_rel->target_offset = r_reloc_get_target_offset (r_rel); - } - else - memset (r_rel, 0, sizeof (r_reloc)); -} +static bfd_boolean narrow_instruction + PARAMS ((bfd_byte *, bfd_size_type, bfd_size_type, bfd_boolean)); +static bfd_boolean widen_instruction + PARAMS ((bfd_byte *, bfd_size_type, bfd_size_type, bfd_boolean)); +static xtensa_format get_single_format + PARAMS ((xtensa_opcode)); +static void init_op_single_format_table + PARAMS ((void)); -static bfd_vma -r_reloc_get_target_offset (r_rel) - const r_reloc *r_rel; +struct string_pair { - bfd_vma target_offset; - unsigned long r_symndx; + const char *wide; + const char *narrow; +}; - BFD_ASSERT (!r_reloc_is_const (r_rel)); - r_symndx = ELF32_R_SYM (r_rel->rela.r_info); - target_offset = get_elf_r_symndx_offset (r_rel->abfd, r_symndx); - return (target_offset + r_rel->rela.r_addend); -} +/* For the set of narrowable instructions we do NOT include the + narrowings beqz -> beqz.n or bnez -> bnez.n because of complexities + involved during linker relaxation that may require these to + re-expand in some conditions. Also, the narrowing "or" -> mov.n + requires special case code to ensure it only works when op1 == op2. */ -static struct elf_link_hash_entry * -r_reloc_get_hash_entry (r_rel) - const r_reloc *r_rel; +struct string_pair narrowable[] = { - unsigned long r_symndx = ELF32_R_SYM (r_rel->rela.r_info); - return get_elf_r_symndx_hash_entry (r_rel->abfd, r_symndx); -} - + { "add", "add.n" }, + { "addi", "addi.n" }, + { "addmi", "addi.n" }, + { "l32i", "l32i.n" }, + { "movi", "movi.n" }, + { "ret", "ret.n" }, + { "retw", "retw.n" }, + { "s32i", "s32i.n" }, + { "or", "mov.n" } /* special case only when op1 == op2 */ +}; -static asection * -r_reloc_get_section (r_rel) - const r_reloc *r_rel; +struct string_pair widenable[] = { - unsigned long r_symndx = ELF32_R_SYM (r_rel->rela.r_info); - return get_elf_r_symndx_section (r_rel->abfd, r_symndx); -} + { "add", "add.n" }, + { "addi", "addi.n" }, + { "addmi", "addi.n" }, + { "beqz", "beqz.n" }, + { "bnez", "bnez.n" }, + { "l32i", "l32i.n" }, + { "movi", "movi.n" }, + { "ret", "ret.n" }, + { "retw", "retw.n" }, + { "s32i", "s32i.n" }, + { "or", "mov.n" } /* special case only when op1 == op2 */ +}; +/* Attempt to narrow an instruction. Return true if the narrowing is + valid. If the do_it parameter is non-zero, then perform the action + in-place directly into the contents. Otherwise, do not modify the + contents. The set of valid narrowing are specified by a string table + but require some special case operand checks in some cases. */ + static bfd_boolean -r_reloc_is_defined (r_rel) - const r_reloc *r_rel; +narrow_instruction (contents, content_length, offset, do_it) + bfd_byte *contents; + bfd_size_type content_length; + bfd_size_type offset; + bfd_boolean do_it; { - asection *sec = r_reloc_get_section (r_rel); - if (sec == bfd_abs_section_ptr - || sec == bfd_com_section_ptr - || sec == bfd_und_section_ptr) - return FALSE; - return TRUE; -} + xtensa_opcode opcode; + bfd_size_type insn_len, opi; + xtensa_isa isa = xtensa_default_isa; + xtensa_format fmt, o_fmt; - -/* source_reloc: relocations that reference literal sections. */ + static xtensa_insnbuf insnbuf = NULL; + static xtensa_insnbuf slotbuf = NULL; + static xtensa_insnbuf o_insnbuf = NULL; + static xtensa_insnbuf o_slotbuf = NULL; -/* To determine whether literals can be coalesced, we need to first - record all the relocations that reference the literals. The - source_reloc structure below is used for this purpose. The - source_reloc entries are kept in a per-literal-section array, sorted - by offset within the literal section (i.e., target offset). + if (insnbuf == NULL) + { + insnbuf = xtensa_insnbuf_alloc (isa); + slotbuf = xtensa_insnbuf_alloc (isa); + o_insnbuf = xtensa_insnbuf_alloc (isa); + o_slotbuf = xtensa_insnbuf_alloc (isa); + } - The source_sec and r_rel.rela.r_offset fields identify the source of - the relocation. The r_rel field records the relocation value, i.e., - the offset of the literal being referenced. The opnd field is needed - to determine the range of the immediate field to which the relocation - applies, so we can determine whether another literal with the same - value is within range. The is_null field is true when the relocation - is being removed (e.g., when an L32R is being removed due to a CALLX - that is converted to a direct CALL). */ + BFD_ASSERT (offset < content_length); -typedef struct source_reloc_struct source_reloc; + if (content_length < 2) + return FALSE; -struct source_reloc_struct -{ - asection *source_sec; - r_reloc r_rel; - xtensa_operand opnd; - bfd_boolean is_null; -}; + /* We will hand-code a few of these for a little while. + These have all been specified in the assembler aleady. */ + xtensa_insnbuf_from_chars (isa, insnbuf, &contents[offset], + content_length - offset); + fmt = xtensa_format_decode (isa, insnbuf); + if (xtensa_format_num_slots (isa, fmt) != 1) + return FALSE; + if (xtensa_format_get_slot (isa, fmt, 0, insnbuf, slotbuf) != 0) + return FALSE; -static void init_source_reloc - PARAMS ((source_reloc *, asection *, const r_reloc *, xtensa_operand)); -static source_reloc *find_source_reloc - PARAMS ((source_reloc *, int, asection *, Elf_Internal_Rela *)); -static int source_reloc_compare - PARAMS ((const PTR, const PTR)); + opcode = xtensa_opcode_decode (isa, fmt, 0, slotbuf); + if (opcode == XTENSA_UNDEFINED) + return FALSE; + insn_len = xtensa_format_length (isa, fmt); + if (insn_len > content_length) + return FALSE; + for (opi = 0; opi < (sizeof (narrowable)/sizeof (struct string_pair)); ++opi) + { + bfd_boolean is_or = (strcmp ("or", narrowable[opi].wide) == 0); -static void -init_source_reloc (reloc, source_sec, r_rel, opnd) - source_reloc *reloc; - asection *source_sec; - const r_reloc *r_rel; - xtensa_operand opnd; -{ - reloc->source_sec = source_sec; - reloc->r_rel = *r_rel; - reloc->opnd = opnd; - reloc->is_null = FALSE; -} + if (opcode == xtensa_opcode_lookup (isa, narrowable[opi].wide)) + { + uint32 value, newval; + int i, operand_count, o_operand_count; + xtensa_opcode o_opcode; + /* Address does not matter in this case. We might need to + fix it to handle branches/jumps. */ + bfd_vma self_address = 0; -/* Find the source_reloc for a particular source offset and relocation - type. Note that the array is sorted by _target_ offset, so this is - just a linear search. */ + o_opcode = xtensa_opcode_lookup (isa, narrowable[opi].narrow); + if (o_opcode == XTENSA_UNDEFINED) + return FALSE; + o_fmt = get_single_format (o_opcode); + if (o_fmt == XTENSA_UNDEFINED) + return FALSE; -static source_reloc * -find_source_reloc (src_relocs, src_count, sec, irel) - source_reloc *src_relocs; - int src_count; - asection *sec; - Elf_Internal_Rela *irel; -{ - int i; + if (xtensa_format_length (isa, fmt) != 3 + || xtensa_format_length (isa, o_fmt) != 2) + return FALSE; - for (i = 0; i < src_count; i++) - { - if (src_relocs[i].source_sec == sec - && src_relocs[i].r_rel.rela.r_offset == irel->r_offset - && (ELF32_R_TYPE (src_relocs[i].r_rel.rela.r_info) - == ELF32_R_TYPE (irel->r_info))) - return &src_relocs[i]; - } + xtensa_format_encode (isa, o_fmt, o_slotbuf); + xtensa_format_encode (isa, o_fmt, o_insnbuf); + operand_count = xtensa_opcode_num_operands (isa, opcode); + o_operand_count = xtensa_opcode_num_operands (isa, o_opcode); - return NULL; -} + if (xtensa_opcode_encode (isa, o_fmt, 0, o_slotbuf, o_opcode) != 0) + return FALSE; + if (!is_or) + { + if (xtensa_opcode_num_operands (isa, o_opcode) != operand_count) + return FALSE; + } + else + { + uint32 rawval0, rawval1, rawval2; -static int -source_reloc_compare (ap, bp) - const PTR ap; - const PTR bp; -{ - const source_reloc *a = (const source_reloc *) ap; - const source_reloc *b = (const source_reloc *) bp; + if (o_operand_count + 1 != operand_count) + return FALSE; + if (xtensa_operand_get_field (isa, opcode, 0, + fmt, 0, slotbuf, &rawval0) != 0) + return FALSE; + if (xtensa_operand_get_field (isa, opcode, 1, + fmt, 0, slotbuf, &rawval1) != 0) + return FALSE; + if (xtensa_operand_get_field (isa, opcode, 2, + fmt, 0, slotbuf, &rawval2) != 0) + return FALSE; - return (a->r_rel.target_offset - b->r_rel.target_offset); -} + if (rawval1 != rawval2) + return FALSE; + if (rawval0 == rawval1) /* it is a nop */ + return FALSE; + } - -/* Literal values and value hash tables. */ + for (i = 0; i < o_operand_count; ++i) + { + if (xtensa_operand_get_field (isa, opcode, i, fmt, 0, + slotbuf, &value) + || xtensa_operand_decode (isa, opcode, i, &value)) + return FALSE; -/* Literals with the same value can be coalesced. The literal_value - structure records the value of a literal: the "r_rel" field holds the - information from the relocation on the literal (if there is one) and - the "value" field holds the contents of the literal word itself. + /* PC-relative branches need adjustment, but + the PC-rel operand will always have a relocation. */ + newval = value; + if (xtensa_operand_do_reloc (isa, o_opcode, i, &newval, + self_address) + || xtensa_operand_encode (isa, o_opcode, i, &newval) + || xtensa_operand_set_field (isa, o_opcode, i, o_fmt, 0, + o_slotbuf, newval)) + return FALSE; + } - The value_map structure records a literal value along with the - location of a literal holding that value. The value_map hash table - is indexed by the literal value, so that we can quickly check if a - particular literal value has been seen before and is thus a candidate - for coalescing. */ + if (xtensa_format_set_slot (isa, o_fmt, 0, + o_insnbuf, o_slotbuf) != 0) + return FALSE; -typedef struct literal_value_struct literal_value; -typedef struct value_map_struct value_map; -typedef struct value_map_hash_table_struct value_map_hash_table; + if (do_it) + xtensa_insnbuf_to_chars (isa, o_insnbuf, contents + offset, + content_length - offset); + return TRUE; + } + } + return FALSE; +} -struct literal_value_struct -{ - r_reloc r_rel; - unsigned long value; -}; -struct value_map_struct -{ - literal_value val; /* The literal value. */ - r_reloc loc; /* Location of the literal. */ - value_map *next; -}; +/* Attempt to widen an instruction. Return true if the widening is + valid. If the do_it parameter is non-zero, then the action should + be performed inplace into the contents. Otherwise, do not modify + the contents. The set of valid widenings are specified by a string + table but require some special case operand checks in some + cases. */ -struct value_map_hash_table_struct +static bfd_boolean +widen_instruction (contents, content_length, offset, do_it) + bfd_byte *contents; + bfd_size_type content_length; + bfd_size_type offset; + bfd_boolean do_it; { - unsigned bucket_count; - value_map **buckets; - unsigned count; -}; - + xtensa_opcode opcode; + bfd_size_type insn_len, opi; + xtensa_isa isa = xtensa_default_isa; + xtensa_format fmt, o_fmt; -static bfd_boolean is_same_value - PARAMS ((const literal_value *, const literal_value *, bfd_boolean)); -static value_map_hash_table *value_map_hash_table_init - PARAMS ((void)); -static unsigned hash_literal_value - PARAMS ((const literal_value *)); -static unsigned hash_bfd_vma - PARAMS ((bfd_vma)); -static value_map *get_cached_value - PARAMS ((value_map_hash_table *, const literal_value *, bfd_boolean)); -static value_map *add_value_map - PARAMS ((value_map_hash_table *, const literal_value *, const r_reloc *, - bfd_boolean)); + static xtensa_insnbuf insnbuf = NULL; + static xtensa_insnbuf slotbuf = NULL; + static xtensa_insnbuf o_insnbuf = NULL; + static xtensa_insnbuf o_slotbuf = NULL; + if (insnbuf == NULL) + { + insnbuf = xtensa_insnbuf_alloc (isa); + slotbuf = xtensa_insnbuf_alloc (isa); + o_insnbuf = xtensa_insnbuf_alloc (isa); + o_slotbuf = xtensa_insnbuf_alloc (isa); + } -static bfd_boolean -is_same_value (src1, src2, final_static_link) - const literal_value *src1; - const literal_value *src2; - bfd_boolean final_static_link; -{ - struct elf_link_hash_entry *h1, *h2; + BFD_ASSERT (offset < content_length); - if (r_reloc_is_const (&src1->r_rel) != r_reloc_is_const (&src2->r_rel)) + if (content_length < 2) return FALSE; - if (r_reloc_is_const (&src1->r_rel)) - return (src1->value == src2->value); - - if (ELF32_R_TYPE (src1->r_rel.rela.r_info) - != ELF32_R_TYPE (src2->r_rel.rela.r_info)) + /* We will hand code a few of these for a little while. + These have all been specified in the assembler aleady. */ + xtensa_insnbuf_from_chars (isa, insnbuf, &contents[offset], + content_length - offset); + fmt = xtensa_format_decode (isa, insnbuf); + if (xtensa_format_num_slots (isa, fmt) != 1) return FALSE; - if (r_reloc_get_target_offset (&src1->r_rel) - != r_reloc_get_target_offset (&src2->r_rel)) + if (xtensa_format_get_slot (isa, fmt, 0, insnbuf, slotbuf) != 0) return FALSE; - if (src1->value != src2->value) + opcode = xtensa_opcode_decode (isa, fmt, 0, slotbuf); + if (opcode == XTENSA_UNDEFINED) return FALSE; - - /* Now check for the same section (if defined) or the same elf_hash - (if undefined or weak). */ - h1 = r_reloc_get_hash_entry (&src1->r_rel); - h2 = r_reloc_get_hash_entry (&src2->r_rel); - if (r_reloc_is_defined (&src1->r_rel) - && (final_static_link - || ((!h1 || h1->root.type != bfd_link_hash_defweak) - && (!h2 || h2->root.type != bfd_link_hash_defweak)))) - { - if (r_reloc_get_section (&src1->r_rel) - != r_reloc_get_section (&src2->r_rel)) - return FALSE; - } - else + insn_len = xtensa_format_length (isa, fmt); + if (insn_len > content_length) + return FALSE; + + for (opi = 0; opi < (sizeof (widenable)/sizeof (struct string_pair)); ++opi) { - /* Require that the hash entries (i.e., symbols) be identical. */ - if (h1 != h2 || h1 == 0) - return FALSE; - } + bfd_boolean is_or = (strcmp ("or", widenable[opi].wide) == 0); + bfd_boolean is_branch = (strcmp ("beqz", widenable[opi].wide) == 0 + || strcmp ("bnez", widenable[opi].wide) == 0); - return TRUE; -} + if (opcode == xtensa_opcode_lookup (isa, widenable[opi].narrow)) + { + uint32 value, newval; + int i, operand_count, o_operand_count, check_operand_count; + xtensa_opcode o_opcode; + /* Address does not matter in this case. We might need to fix it + to handle branches/jumps. */ + bfd_vma self_address = 0; -/* Must be power of 2. */ -#define INITIAL_HASH_RELOC_BUCKET_COUNT 1024 + o_opcode = xtensa_opcode_lookup (isa, widenable[opi].wide); + if (o_opcode == XTENSA_UNDEFINED) + return FALSE; + o_fmt = get_single_format (o_opcode); + if (o_fmt == XTENSA_UNDEFINED) + return FALSE; -static value_map_hash_table * -value_map_hash_table_init () -{ - value_map_hash_table *values; + if (xtensa_format_length (isa, fmt) != 2 + || xtensa_format_length (isa, o_fmt) != 3) + return FALSE; - values = (value_map_hash_table *) - bfd_malloc (sizeof (value_map_hash_table)); + xtensa_format_encode (isa, o_fmt, o_slotbuf); + xtensa_format_encode (isa, o_fmt, o_insnbuf); + operand_count = xtensa_opcode_num_operands (isa, opcode); + o_operand_count = xtensa_opcode_num_operands (isa, o_opcode); + check_operand_count = o_operand_count; - values->bucket_count = INITIAL_HASH_RELOC_BUCKET_COUNT; - values->count = 0; - values->buckets = (value_map **) - bfd_zmalloc (sizeof (value_map *) * values->bucket_count); + if (xtensa_opcode_encode (isa, o_fmt, 0, o_slotbuf, o_opcode) != 0) + return FALSE; - return values; + if (!is_or) + { + if (xtensa_opcode_num_operands (isa, o_opcode) != operand_count) + return FALSE; + } + else + { + uint32 rawval0, rawval1; + + if (o_operand_count != operand_count + 1) + return FALSE; + if (xtensa_operand_get_field (isa, opcode, 0, + fmt, 0, slotbuf, &rawval0) != 0) + return FALSE; + if (xtensa_operand_get_field (isa, opcode, 1, + fmt, 0, slotbuf, &rawval1) != 0) + return FALSE; + if (rawval0 == rawval1) /* it is a nop */ + return FALSE; + } + if (is_branch) + check_operand_count--; + + for (i = 0; i < check_operand_count; ++i) + { + int new_i = i; + if (is_or && i == o_operand_count - 1) + new_i = i - 1; + if (xtensa_operand_get_field (isa, opcode, new_i, fmt, 0, + slotbuf, &value) + || xtensa_operand_decode (isa, opcode, new_i, &value)) + return FALSE; + + /* PC-relative branches need adjustment, but + the PC-rel operand will always have a relocation. */ + newval = value; + if (xtensa_operand_do_reloc (isa, o_opcode, i, &newval, + self_address) + || xtensa_operand_encode (isa, o_opcode, i, &newval) + || xtensa_operand_set_field (isa, o_opcode, i, o_fmt, 0, + o_slotbuf, newval)) + return FALSE; + } + + if (xtensa_format_set_slot (isa, o_fmt, 0, o_insnbuf, o_slotbuf)) + return FALSE; + + if (do_it) + xtensa_insnbuf_to_chars (isa, o_insnbuf, contents + offset, + content_length - offset); + return TRUE; + } + } + return FALSE; } -static unsigned -hash_bfd_vma (val) - bfd_vma val; +/* When FLIX is available we need to access certain instructions only + when they are 16-bit or 24-bit instructions. This table caches + information about such instructions by walking through all the + opcodes and finding the smallest single-slot format into which each + can be encoded. */ + +static xtensa_format *op_single_fmt_table = NULL; + + +static xtensa_format +get_single_format (opcode) + xtensa_opcode opcode; { - return (val >> 2) + (val >> 10); + init_op_single_format_table (); + return op_single_fmt_table[opcode]; } -static unsigned -hash_literal_value (src) - const literal_value *src; +static void +init_op_single_format_table () { - unsigned hash_val; + xtensa_isa isa = xtensa_default_isa; + xtensa_insnbuf ibuf; + xtensa_opcode opcode; + xtensa_format fmt; + int num_opcodes; - if (r_reloc_is_const (&src->r_rel)) - return hash_bfd_vma (src->value); + if (op_single_fmt_table != NULL) + return; - hash_val = (hash_bfd_vma (r_reloc_get_target_offset (&src->r_rel)) - + hash_bfd_vma (src->value)); - - /* Now check for the same section and the same elf_hash. */ - if (r_reloc_is_defined (&src->r_rel)) - hash_val += hash_bfd_vma ((bfd_vma) (unsigned) r_reloc_get_section (&src->r_rel)); - else - hash_val += hash_bfd_vma ((bfd_vma) (unsigned) r_reloc_get_hash_entry (&src->r_rel)); + ibuf = xtensa_insnbuf_alloc (isa); + num_opcodes = xtensa_isa_num_opcodes (isa); - return hash_val; + op_single_fmt_table = (xtensa_format *) + bfd_malloc (sizeof (xtensa_format) * num_opcodes); + for (opcode = 0; opcode < num_opcodes; opcode++) + { + op_single_fmt_table[opcode] = XTENSA_UNDEFINED; + for (fmt = 0; fmt < xtensa_isa_num_formats (isa); fmt++) + { + if (xtensa_format_num_slots (isa, fmt) == 1 + && xtensa_opcode_encode (isa, fmt, 0, ibuf, opcode) == 0) + { + xtensa_opcode old_fmt = op_single_fmt_table[opcode]; + int fmt_length = xtensa_format_length (isa, fmt); + if (old_fmt == XTENSA_UNDEFINED + || fmt_length < xtensa_format_length (isa, old_fmt)) + op_single_fmt_table[opcode] = fmt; + } + } + } + xtensa_insnbuf_free (isa, ibuf); } + +/* Code for transforming CALLs at link-time. */ -/* Check if the specified literal_value has been seen before. */ - -static value_map * -get_cached_value (map, val, final_static_link) - value_map_hash_table *map; - const literal_value *val; - bfd_boolean final_static_link; +static bfd_reloc_status_type +elf_xtensa_do_asm_simplify (contents, address, content_length, error_message) + bfd_byte *contents; + bfd_vma address; + bfd_vma content_length; + char **error_message; { - value_map *map_e; - value_map *bucket; - unsigned idx; + static xtensa_insnbuf insnbuf = NULL; + static xtensa_insnbuf slotbuf = NULL; + xtensa_format core_format = XTENSA_UNDEFINED; + xtensa_opcode opcode; + xtensa_opcode direct_call_opcode; + xtensa_isa isa = xtensa_default_isa; + bfd_byte *chbuf = contents + address; + int opn; - idx = hash_literal_value (val); - idx = idx & (map->bucket_count - 1); - bucket = map->buckets[idx]; - for (map_e = bucket; map_e; map_e = map_e->next) + if (insnbuf == NULL) { - if (is_same_value (&map_e->val, val, final_static_link)) - return map_e; + insnbuf = xtensa_insnbuf_alloc (isa); + slotbuf = xtensa_insnbuf_alloc (isa); } - return NULL; -} + if (content_length < address) + { + *error_message = _("Attempt to convert L32R/CALLX to CALL failed"); + return bfd_reloc_other; + } -/* Record a new literal value. It is illegal to call this if VALUE - already has an entry here. */ + opcode = get_expanded_call_opcode (chbuf, content_length - address, 0); + direct_call_opcode = swap_callx_for_call_opcode (opcode); + if (direct_call_opcode == XTENSA_UNDEFINED) + { + *error_message = _("Attempt to convert L32R/CALLX to CALL failed"); + return bfd_reloc_other; + } + + /* Assemble a NOP ("or a1, a1, a1") into the 0 byte offset. */ + core_format = xtensa_format_lookup (isa, "x24"); + opcode = xtensa_opcode_lookup (isa, "or"); + xtensa_opcode_encode (isa, core_format, 0, slotbuf, opcode); + for (opn = 0; opn < 3; opn++) + { + uint32 regno = 1; + xtensa_operand_encode (isa, opcode, opn, ®no); + xtensa_operand_set_field (isa, opcode, opn, core_format, 0, + slotbuf, regno); + } + xtensa_format_encode (isa, core_format, insnbuf); + xtensa_format_set_slot (isa, core_format, 0, insnbuf, slotbuf); + xtensa_insnbuf_to_chars (isa, insnbuf, chbuf, content_length - address); -static value_map * -add_value_map (map, val, loc, final_static_link) - value_map_hash_table *map; - const literal_value *val; - const r_reloc *loc; - bfd_boolean final_static_link; -{ - value_map **bucket_p; - unsigned idx; + /* Assemble a CALL ("callN 0") into the 3 byte offset. */ + xtensa_opcode_encode (isa, core_format, 0, slotbuf, direct_call_opcode); + xtensa_operand_set_field (isa, opcode, 0, core_format, 0, slotbuf, 0); - value_map *val_e = (value_map *) bfd_zmalloc (sizeof (value_map)); + xtensa_format_encode (isa, core_format, insnbuf); + xtensa_format_set_slot (isa, core_format, 0, insnbuf, slotbuf); + xtensa_insnbuf_to_chars (isa, insnbuf, chbuf + 3, + content_length - address - 3); - BFD_ASSERT (get_cached_value (map, val, final_static_link) == NULL); - val_e->val = *val; - val_e->loc = *loc; + return bfd_reloc_ok; +} - idx = hash_literal_value (val); - idx = idx & (map->bucket_count - 1); - bucket_p = &map->buckets[idx]; - val_e->next = *bucket_p; - *bucket_p = val_e; - map->count++; - /* FIXME: consider resizing the hash table if we get too many entries */ - - return val_e; -} +static bfd_reloc_status_type +contract_asm_expansion (contents, content_length, irel, error_message) + bfd_byte *contents; + bfd_vma content_length; + Elf_Internal_Rela *irel; + char **error_message; +{ + bfd_reloc_status_type retval = + elf_xtensa_do_asm_simplify (contents, irel->r_offset, content_length, + error_message); - -/* Lists of literals being coalesced or removed. */ + if (retval != bfd_reloc_ok) + return bfd_reloc_dangerous; -/* In the usual case, the literal identified by "from" is being - coalesced with another literal identified by "to". If the literal is - unused and is being removed altogether, "to.abfd" will be NULL. - The removed_literal entries are kept on a per-section list, sorted - by the "from" offset field. */ + /* Update the irel->r_offset field so that the right immediate and + the right instruction are modified during the relocation. */ + irel->r_offset += 3; + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_XTENSA_SLOT0_OP); + return bfd_reloc_ok; +} -typedef struct removed_literal_struct removed_literal; -typedef struct removed_literal_list_struct removed_literal_list; -struct removed_literal_struct +static xtensa_opcode +swap_callx_for_call_opcode (opcode) + xtensa_opcode opcode; { - r_reloc from; - r_reloc to; - removed_literal *next; -}; + init_call_opcodes (); -struct removed_literal_list_struct -{ - removed_literal *head; - removed_literal *tail; -}; + if (opcode == callx0_op) return call0_op; + if (opcode == callx4_op) return call4_op; + if (opcode == callx8_op) return call8_op; + if (opcode == callx12_op) return call12_op; + /* Return XTENSA_UNDEFINED if the opcode is not an indirect call. */ + return XTENSA_UNDEFINED; +} -static void add_removed_literal - PARAMS ((removed_literal_list *, const r_reloc *, const r_reloc *)); -static removed_literal *find_removed_literal - PARAMS ((removed_literal_list *, bfd_vma)); -static bfd_vma offset_with_removed_literals - PARAMS ((removed_literal_list *, bfd_vma)); +/* Check if "buf" is pointing to a "L32R aN; CALLX aN" or "CONST16 aN; + CONST16 aN; CALLX aN" sequence, and if so, return the CALLX opcode. + If not, return XTENSA_UNDEFINED. */ -/* Record that the literal at "from" is being removed. If "to" is not - NULL, the "from" literal is being coalesced with the "to" literal. */ +#define L32R_TARGET_REG_OPERAND 0 +#define CONST16_TARGET_REG_OPERAND 0 +#define CALLN_SOURCE_OPERAND 0 -static void -add_removed_literal (removed_list, from, to) - removed_literal_list *removed_list; - const r_reloc *from; - const r_reloc *to; +static xtensa_opcode +get_expanded_call_opcode (buf, bufsize, p_uses_l32r) + bfd_byte *buf; + int bufsize; + bfd_boolean *p_uses_l32r; { - removed_literal *r, *new_r, *next_r; - - new_r = (removed_literal *) bfd_zmalloc (sizeof (removed_literal)); + static xtensa_insnbuf insnbuf = NULL; + static xtensa_insnbuf slotbuf = NULL; + xtensa_format fmt; + xtensa_opcode opcode; + xtensa_isa isa = xtensa_default_isa; + uint32 regno, const16_regno, call_regno; + int offset = 0; - new_r->from = *from; - if (to) - new_r->to = *to; - else - new_r->to.abfd = NULL; - new_r->next = NULL; - - r = removed_list->head; - if (r == NULL) + if (insnbuf == NULL) { - removed_list->head = new_r; - removed_list->tail = new_r; + insnbuf = xtensa_insnbuf_alloc (isa); + slotbuf = xtensa_insnbuf_alloc (isa); } - /* Special check for common case of append. */ - else if (removed_list->tail->from.target_offset < from->target_offset) + + xtensa_insnbuf_from_chars (isa, insnbuf, buf, bufsize); + fmt = xtensa_format_decode (isa, insnbuf); + if (fmt == XTENSA_UNDEFINED + || xtensa_format_get_slot (isa, fmt, 0, insnbuf, slotbuf)) + return XTENSA_UNDEFINED; + + opcode = xtensa_opcode_decode (isa, fmt, 0, slotbuf); + if (opcode == XTENSA_UNDEFINED) + return XTENSA_UNDEFINED; + + if (opcode == get_l32r_opcode ()) { - removed_list->tail->next = new_r; - removed_list->tail = new_r; + if (p_uses_l32r) + *p_uses_l32r = TRUE; + if (xtensa_operand_get_field (isa, opcode, L32R_TARGET_REG_OPERAND, + fmt, 0, slotbuf, ®no) + || xtensa_operand_decode (isa, opcode, L32R_TARGET_REG_OPERAND, + ®no)) + return XTENSA_UNDEFINED; } - else + else if (opcode == get_const16_opcode ()) { - while (r->from.target_offset < from->target_offset - && r->next != NULL) - { - r = r->next; - } - next_r = r->next; - r->next = new_r; - new_r->next = next_r; - if (next_r == NULL) - removed_list->tail = new_r; + if (p_uses_l32r) + *p_uses_l32r = FALSE; + if (xtensa_operand_get_field (isa, opcode, CONST16_TARGET_REG_OPERAND, + fmt, 0, slotbuf, ®no) + || xtensa_operand_decode (isa, opcode, CONST16_TARGET_REG_OPERAND, + ®no)) + return XTENSA_UNDEFINED; + + /* Check that the next instruction is also CONST16. */ + offset += xtensa_format_length (isa, fmt); + xtensa_insnbuf_from_chars (isa, insnbuf, buf + offset, bufsize - offset); + fmt = xtensa_format_decode (isa, insnbuf); + if (fmt == XTENSA_UNDEFINED + || xtensa_format_get_slot (isa, fmt, 0, insnbuf, slotbuf)) + return XTENSA_UNDEFINED; + opcode = xtensa_opcode_decode (isa, fmt, 0, slotbuf); + if (opcode != get_const16_opcode ()) + return XTENSA_UNDEFINED; + + if (xtensa_operand_get_field (isa, opcode, CONST16_TARGET_REG_OPERAND, + fmt, 0, slotbuf, &const16_regno) + || xtensa_operand_decode (isa, opcode, CONST16_TARGET_REG_OPERAND, + &const16_regno) + || const16_regno != regno) + return XTENSA_UNDEFINED; } -} - + else + return XTENSA_UNDEFINED; -/* Check if the list of removed literals contains an entry for the - given address. Return the entry if found. */ + /* Next instruction should be an CALLXn with operand 0 == regno. */ + offset += xtensa_format_length (isa, fmt); + xtensa_insnbuf_from_chars (isa, insnbuf, buf + offset, bufsize - offset); + fmt = xtensa_format_decode (isa, insnbuf); + if (fmt == XTENSA_UNDEFINED + || xtensa_format_get_slot (isa, fmt, 0, insnbuf, slotbuf)) + return XTENSA_UNDEFINED; + opcode = xtensa_opcode_decode (isa, fmt, 0, slotbuf); + if (opcode == XTENSA_UNDEFINED + || !is_indirect_call_opcode (opcode)) + return XTENSA_UNDEFINED; -static removed_literal * -find_removed_literal (removed_list, addr) - removed_literal_list *removed_list; - bfd_vma addr; -{ - removed_literal *r = removed_list->head; - while (r && r->from.target_offset < addr) - r = r->next; - if (r && r->from.target_offset == addr) - return r; - return NULL; -} + if (xtensa_operand_get_field (isa, opcode, CALLN_SOURCE_OPERAND, + fmt, 0, slotbuf, &call_regno) + || xtensa_operand_decode (isa, opcode, CALLN_SOURCE_OPERAND, + &call_regno)) + return XTENSA_UNDEFINED; + if (call_regno != regno) + return XTENSA_UNDEFINED; -/* Adjust an offset in a section to compensate for literals that are - being removed. Search the list of removed literals and subtract - 4 bytes for every removed literal prior to the given address. */ + return opcode; +} -static bfd_vma -offset_with_removed_literals (removed_list, addr) - removed_literal_list *removed_list; - bfd_vma addr; -{ - removed_literal *r = removed_list->head; - unsigned num_bytes = 0; + +/* Data structures used during relaxation. */ - if (r == NULL) - return addr; +/* r_reloc: relocation values. */ - while (r && r->from.target_offset <= addr) - { - num_bytes += 4; - r = r->next; - } - if (num_bytes > addr) - return 0; - return (addr - num_bytes); -} +/* Through the relaxation process, we need to keep track of the values + that will result from evaluating relocations. The standard ELF + relocation structure is not sufficient for this purpose because we're + operating on multiple input files at once, so we need to know which + input file a relocation refers to. The r_reloc structure thus + records both the input file (bfd) and ELF relocation. - -/* Coalescing literals may require a relocation to refer to a section in - a different input file, but the standard relocation information - cannot express that. Instead, the reloc_bfd_fix structures are used - to "fix" the relocations that refer to sections in other input files. - These structures are kept on per-section lists. The "src_type" field - records the relocation type in case there are multiple relocations on - the same location. FIXME: This is ugly; an alternative might be to - add new symbols with the "owner" field to some other input file. */ + For efficiency, an r_reloc also contains a "target_offset" field to + cache the target-section-relative offset value that is represented by + the relocation. + + The r_reloc also contains a virtual offset that allows multiple + inserted literals to be placed at the same "address" with + different offsets. */ -typedef struct reloc_bfd_fix_struct reloc_bfd_fix; +typedef struct r_reloc_struct r_reloc; -struct reloc_bfd_fix_struct +struct r_reloc_struct { - asection *src_sec; - bfd_vma src_offset; - unsigned src_type; /* Relocation type. */ - - bfd *target_abfd; - asection *target_sec; + bfd *abfd; + Elf_Internal_Rela rela; bfd_vma target_offset; - - reloc_bfd_fix *next; + bfd_vma virtual_offset; }; +static bfd_boolean r_reloc_is_const + PARAMS ((const r_reloc *)); +static void r_reloc_init + PARAMS ((r_reloc *, bfd *, Elf_Internal_Rela *, bfd_byte *, bfd_size_type)); +static bfd_vma r_reloc_get_target_offset + PARAMS ((const r_reloc *)); +static asection *r_reloc_get_section + PARAMS ((const r_reloc *)); +static bfd_boolean r_reloc_is_defined + PARAMS ((const r_reloc *)); +static struct elf_link_hash_entry *r_reloc_get_hash_entry + PARAMS ((const r_reloc *)); +#if DEBUG +static void print_r_reloc + PARAMS ((FILE *fp, const r_reloc *r)); +#endif /* DEBUG */ -static reloc_bfd_fix *reloc_bfd_fix_init - PARAMS ((asection *, bfd_vma, unsigned, bfd *, asection *, bfd_vma)); -static reloc_bfd_fix *get_bfd_fix - PARAMS ((reloc_bfd_fix *, asection *, bfd_vma, unsigned)); +/* The r_reloc structure is included by value in literal_value, but not + every literal_value has an associated relocation -- some are simple + constants. In such cases, we set all the fields in the r_reloc + struct to zero. The r_reloc_is_const function should be used to + detect this case. */ -static reloc_bfd_fix * -reloc_bfd_fix_init (src_sec, src_offset, src_type, - target_abfd, target_sec, target_offset) - asection *src_sec; - bfd_vma src_offset; - unsigned src_type; - bfd *target_abfd; - asection *target_sec; - bfd_vma target_offset; +static bfd_boolean +r_reloc_is_const (r_rel) + const r_reloc *r_rel; { - reloc_bfd_fix *fix; - - fix = (reloc_bfd_fix *) bfd_malloc (sizeof (reloc_bfd_fix)); - fix->src_sec = src_sec; - fix->src_offset = src_offset; - fix->src_type = src_type; - fix->target_abfd = target_abfd; - fix->target_sec = target_sec; - fix->target_offset = target_offset; - - return fix; + return (r_rel->abfd == NULL); } -static reloc_bfd_fix * -get_bfd_fix (fix_list, sec, offset, type) - reloc_bfd_fix *fix_list; - asection *sec; - bfd_vma offset; - unsigned type; +static void +r_reloc_init (r_rel, abfd, irel, contents, content_length) + r_reloc *r_rel; + bfd *abfd; + Elf_Internal_Rela *irel; + bfd_byte *contents; + bfd_size_type content_length; { - reloc_bfd_fix *r; + int r_type; + reloc_howto_type *howto; - for (r = fix_list; r != NULL; r = r->next) + if (irel != NULL) { - if (r->src_sec == sec - && r->src_offset == offset - && r->src_type == type) - return r; + r_rel->rela = *irel; + r_rel->abfd = abfd; + r_rel->target_offset = r_reloc_get_target_offset (r_rel); + r_rel->virtual_offset = 0; + r_type = ELF32_R_TYPE (r_rel->rela.r_info); + howto = &elf_howto_table[r_type]; + if (howto->partial_inplace) + { + bfd_vma inplace_val; + BFD_ASSERT (r_rel->rela.r_offset < content_length); + + inplace_val = bfd_get_32 (abfd, &contents[r_rel->rela.r_offset]); + r_rel->target_offset += inplace_val; + } } - return NULL; + else + memset (r_rel, 0, sizeof (r_reloc)); } - -/* Per-section data for relaxation. */ -struct xtensa_relax_info_struct +static bfd_vma +r_reloc_get_target_offset (r_rel) + const r_reloc *r_rel; { - bfd_boolean is_relaxable_literal_section; - int visited; /* Number of times visited. */ - - source_reloc *src_relocs; /* Array[src_count]. */ - int src_count; - int src_next; /* Next src_relocs entry to assign. */ + bfd_vma target_offset; + unsigned long r_symndx; - removed_literal_list removed_list; + BFD_ASSERT (!r_reloc_is_const (r_rel)); + r_symndx = ELF32_R_SYM (r_rel->rela.r_info); + target_offset = get_elf_r_symndx_offset (r_rel->abfd, r_symndx); + return (target_offset + r_rel->rela.r_addend); +} - reloc_bfd_fix *fix_list; -}; -struct elf_xtensa_section_data +static struct elf_link_hash_entry * +r_reloc_get_hash_entry (r_rel) + const r_reloc *r_rel; { - struct bfd_elf_section_data elf; - xtensa_relax_info relax_info; -}; + unsigned long r_symndx = ELF32_R_SYM (r_rel->rela.r_info); + return get_elf_r_symndx_hash_entry (r_rel->abfd, r_symndx); +} -static void init_xtensa_relax_info - PARAMS ((asection *)); -static xtensa_relax_info *get_xtensa_relax_info - PARAMS ((asection *)); -static void add_fix - PARAMS ((asection *, reloc_bfd_fix *)); + +static asection * +r_reloc_get_section (r_rel) + const r_reloc *r_rel; +{ + unsigned long r_symndx = ELF32_R_SYM (r_rel->rela.r_info); + return get_elf_r_symndx_section (r_rel->abfd, r_symndx); +} static bfd_boolean -elf_xtensa_new_section_hook (abfd, sec) - bfd *abfd; - asection *sec; +r_reloc_is_defined (r_rel) + const r_reloc *r_rel; { - struct elf_xtensa_section_data *sdata; - bfd_size_type amt = sizeof (*sdata); - - sdata = (struct elf_xtensa_section_data *) bfd_zalloc (abfd, amt); - if (sdata == NULL) + asection *sec; + if (r_rel == NULL) return FALSE; - sec->used_by_bfd = (PTR) sdata; - return _bfd_elf_new_section_hook (abfd, sec); + sec = r_reloc_get_section (r_rel); + if (sec == bfd_abs_section_ptr + || sec == bfd_com_section_ptr + || sec == bfd_und_section_ptr) + return FALSE; + return TRUE; } +#if DEBUG + static void -init_xtensa_relax_info (sec) - asection *sec; +print_r_reloc (fp, r_rel) + FILE *fp; + const r_reloc *r_rel; { - xtensa_relax_info *relax_info = get_xtensa_relax_info (sec); + if (r_reloc_is_defined (r_rel)) + { + asection *sec = r_reloc_get_section (r_rel); + fprintf (fp, " %s(%s + ", sec->owner->filename, sec->name); + } + else if (r_reloc_get_hash_entry (r_rel)) + fprintf (fp, " %s + ", r_reloc_get_hash_entry (r_rel)->root.root.string); + else + fprintf (fp, " ?? + "); - relax_info->is_relaxable_literal_section = FALSE; - relax_info->visited = 0; + fprintf_vma (fp, r_rel->target_offset); + if (r_rel->virtual_offset) + { + fprintf (fp, " + "); + fprintf_vma (fp, r_rel->virtual_offset); + } + + fprintf (fp, ")"); +} - relax_info->src_relocs = NULL; - relax_info->src_count = 0; - relax_info->src_next = 0; +#endif /* DEBUG */ - relax_info->removed_list.head = NULL; - relax_info->removed_list.tail = NULL; + +/* source_reloc: relocations that reference literals. */ - relax_info->fix_list = NULL; -} +/* To determine whether literals can be coalesced, we need to first + record all the relocations that reference the literals. The + source_reloc structure below is used for this purpose. The + source_reloc entries are kept in a per-literal-section array, sorted + by offset within the literal section (i.e., target offset). + The source_sec and r_rel.rela.r_offset fields identify the source of + the relocation. The r_rel field records the relocation value, i.e., + the offset of the literal being referenced. The opnd field is needed + to determine the range of the immediate field to which the relocation + applies, so we can determine whether another literal with the same + value is within range. The is_null field is true when the relocation + is being removed (e.g., when an L32R is being removed due to a CALLX + that is converted to a direct CALL). */ -static xtensa_relax_info * -get_xtensa_relax_info (sec) - asection *sec; +typedef struct source_reloc_struct source_reloc; + +struct source_reloc_struct { - struct elf_xtensa_section_data *section_data; + asection *source_sec; + r_reloc r_rel; + xtensa_opcode opcode; + int opnd; + bfd_boolean is_null; + bfd_boolean is_abs_literal; +}; - /* No info available if no section or if it is an output section. */ - if (!sec || sec == sec->output_section) - return NULL; - section_data = (struct elf_xtensa_section_data *) elf_section_data (sec); - return §ion_data->relax_info; -} +static void init_source_reloc + PARAMS ((source_reloc *, asection *, const r_reloc *, + xtensa_opcode, int, bfd_boolean)); +static source_reloc *find_source_reloc + PARAMS ((source_reloc *, int, asection *, Elf_Internal_Rela *)); +static int source_reloc_compare + PARAMS ((const PTR, const PTR)); static void -add_fix (src_sec, fix) - asection *src_sec; - reloc_bfd_fix *fix; +init_source_reloc (reloc, source_sec, r_rel, opcode, opnd, is_abs_literal) + source_reloc *reloc; + asection *source_sec; + const r_reloc *r_rel; + xtensa_opcode opcode; + int opnd; + bfd_boolean is_abs_literal; { - xtensa_relax_info *relax_info; - - relax_info = get_xtensa_relax_info (src_sec); - fix->next = relax_info->fix_list; - relax_info->fix_list = fix; + reloc->source_sec = source_sec; + reloc->r_rel = *r_rel; + reloc->opcode = opcode; + reloc->opnd = opnd; + reloc->is_null = FALSE; + reloc->is_abs_literal = is_abs_literal; } - -/* Access to internal relocations, section contents and symbols. */ -/* During relaxation, we need to modify relocations, section contents, - and symbol definitions, and we need to keep the original values from - being reloaded from the input files, i.e., we need to "pin" the - modified values in memory. We also want to continue to observe the - setting of the "keep-memory" flag. The following functions wrap the - standard BFD functions to take care of this for us. */ +/* Find the source_reloc for a particular source offset and relocation + type. Note that the array is sorted by _target_ offset, so this is + just a linear search. */ -static Elf_Internal_Rela * -retrieve_internal_relocs (abfd, sec, keep_memory) - bfd *abfd; +static source_reloc * +find_source_reloc (src_relocs, src_count, sec, irel) + source_reloc *src_relocs; + int src_count; asection *sec; - bfd_boolean keep_memory; + Elf_Internal_Rela *irel; { - Elf_Internal_Rela *internal_relocs; + int i; - if ((sec->flags & SEC_LINKER_CREATED) != 0) - return NULL; + for (i = 0; i < src_count; i++) + { + if (src_relocs[i].source_sec == sec + && src_relocs[i].r_rel.rela.r_offset == irel->r_offset + && (ELF32_R_TYPE (src_relocs[i].r_rel.rela.r_info) + == ELF32_R_TYPE (irel->r_info))) + return &src_relocs[i]; + } - internal_relocs = elf_section_data (sec)->relocs; - if (internal_relocs == NULL) - internal_relocs = (_bfd_elf_link_read_relocs - (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL, - keep_memory)); - return internal_relocs; + return NULL; } -static void -pin_internal_relocs (sec, internal_relocs) - asection *sec; - Elf_Internal_Rela *internal_relocs; +static int +source_reloc_compare (ap, bp) + const PTR ap; + const PTR bp; { - elf_section_data (sec)->relocs = internal_relocs; -} + const source_reloc *a = (const source_reloc *) ap; + const source_reloc *b = (const source_reloc *) bp; + if (a->r_rel.target_offset != b->r_rel.target_offset) + return (a->r_rel.target_offset - b->r_rel.target_offset); -static void -release_internal_relocs (sec, internal_relocs) - asection *sec; - Elf_Internal_Rela *internal_relocs; -{ - if (internal_relocs - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); + /* We don't need to sort on these criteria for correctness, + but enforcing a more strict ordering prevents unstable qsort + from behaving differently with different implementations. + Without the code below we get correct but different results + on Solaris 2.7 and 2.8. We would like to always produce the + same results no matter the host. */ + + if ((!a->is_null) - (!b->is_null)) + return ((!a->is_null) - (!b->is_null)); + return internal_reloc_compare (&a->r_rel.rela, &b->r_rel.rela); } + +/* Literal values and value hash tables. */ -static bfd_byte * -retrieve_contents (abfd, sec, keep_memory) - bfd *abfd; - asection *sec; - bfd_boolean keep_memory; -{ - bfd_byte *contents; +/* Literals with the same value can be coalesced. The literal_value + structure records the value of a literal: the "r_rel" field holds the + information from the relocation on the literal (if there is one) and + the "value" field holds the contents of the literal word itself. - contents = elf_section_data (sec)->this_hdr.contents; - - if (contents == NULL && sec->size != 0) - { - if (!bfd_malloc_and_get_section (abfd, sec, &contents)) - { - if (contents != NULL) - free (contents); - return NULL; - } - if (keep_memory) - elf_section_data (sec)->this_hdr.contents = contents; - } - return contents; -} + The value_map structure records a literal value along with the + location of a literal holding that value. The value_map hash table + is indexed by the literal value, so that we can quickly check if a + particular literal value has been seen before and is thus a candidate + for coalescing. */ +typedef struct literal_value_struct literal_value; +typedef struct value_map_struct value_map; +typedef struct value_map_hash_table_struct value_map_hash_table; -static void -pin_contents (sec, contents) - asection *sec; - bfd_byte *contents; +struct literal_value_struct { - elf_section_data (sec)->this_hdr.contents = contents; -} + r_reloc r_rel; + unsigned long value; + bfd_boolean is_abs_literal; +}; + +struct value_map_struct +{ + literal_value val; /* The literal value. */ + r_reloc loc; /* Location of the literal. */ + value_map *next; +}; + +struct value_map_hash_table_struct +{ + unsigned bucket_count; + value_map **buckets; + unsigned count; + bfd_boolean has_last_loc; + r_reloc last_loc; +}; + + +static void init_literal_value + PARAMS ((literal_value *, const r_reloc *, unsigned long, bfd_boolean)); +static bfd_boolean literal_value_equal + PARAMS ((const literal_value *, const literal_value *, bfd_boolean)); +static value_map_hash_table *value_map_hash_table_init + PARAMS ((void)); +static void value_map_hash_table_delete + PARAMS ((value_map_hash_table *)); +static unsigned literal_value_hash + PARAMS ((const literal_value *)); +static unsigned hash_bfd_vma + PARAMS ((bfd_vma)); +static value_map *value_map_get_cached_value + PARAMS ((value_map_hash_table *, const literal_value *, bfd_boolean)); +static value_map *add_value_map + PARAMS ((value_map_hash_table *, const literal_value *, const r_reloc *, + bfd_boolean)); static void -release_contents (sec, contents) - asection *sec; - bfd_byte *contents; +init_literal_value (lit, r_rel, value, is_abs_literal) + literal_value *lit; + const r_reloc *r_rel; + unsigned long value; + bfd_boolean is_abs_literal; { - if (contents && - elf_section_data (sec)->this_hdr.contents != contents) - free (contents); + lit->r_rel = *r_rel; + lit->value = value; + lit->is_abs_literal = is_abs_literal; } -static Elf_Internal_Sym * -retrieve_local_syms (input_bfd) - bfd *input_bfd; +static bfd_boolean +literal_value_equal (src1, src2, final_static_link) + const literal_value *src1; + const literal_value *src2; + bfd_boolean final_static_link; { - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Sym *isymbuf; - size_t locsymcount; + struct elf_link_hash_entry *h1, *h2; - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - locsymcount = symtab_hdr->sh_info; + if (r_reloc_is_const (&src1->r_rel) != r_reloc_is_const (&src2->r_rel)) + return FALSE; - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL && locsymcount != 0) - isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, locsymcount, 0, - NULL, NULL, NULL); + if (r_reloc_is_const (&src1->r_rel)) + return (src1->value == src2->value); - /* Save the symbols for this input file so they won't be read again. */ - if (isymbuf && isymbuf != (Elf_Internal_Sym *) symtab_hdr->contents) - symtab_hdr->contents = (unsigned char *) isymbuf; + if (ELF32_R_TYPE (src1->r_rel.rela.r_info) + != ELF32_R_TYPE (src2->r_rel.rela.r_info)) + return FALSE; - return isymbuf; + if (src1->r_rel.target_offset != src2->r_rel.target_offset) + return FALSE; + + if (src1->r_rel.virtual_offset != src2->r_rel.virtual_offset) + return FALSE; + + if (src1->value != src2->value) + return FALSE; + + /* Now check for the same section (if defined) or the same elf_hash + (if undefined or weak). */ + h1 = r_reloc_get_hash_entry (&src1->r_rel); + h2 = r_reloc_get_hash_entry (&src2->r_rel); + if (r_reloc_is_defined (&src1->r_rel) + && (final_static_link + || ((!h1 || h1->root.type != bfd_link_hash_defweak) + && (!h2 || h2->root.type != bfd_link_hash_defweak)))) + { + if (r_reloc_get_section (&src1->r_rel) + != r_reloc_get_section (&src2->r_rel)) + return FALSE; + } + else + { + /* Require that the hash entries (i.e., symbols) be identical. */ + if (h1 != h2 || h1 == 0) + return FALSE; + } + + if (src1->is_abs_literal != src2->is_abs_literal) + return FALSE; + + return TRUE; } - -/* Code for link-time relaxation. */ -/* Local helper functions. */ -static bfd_boolean analyze_relocations - PARAMS ((struct bfd_link_info *)); -static bfd_boolean find_relaxable_sections - PARAMS ((bfd *, asection *, struct bfd_link_info *, bfd_boolean *)); -static bfd_boolean collect_source_relocs - PARAMS ((bfd *, asection *, struct bfd_link_info *)); -static bfd_boolean is_resolvable_asm_expansion - PARAMS ((bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, - struct bfd_link_info *, bfd_boolean *)); -static bfd_boolean remove_literals - PARAMS ((bfd *, asection *, struct bfd_link_info *, value_map_hash_table *)); -static bfd_boolean relax_section - PARAMS ((bfd *, asection *, struct bfd_link_info *)); -static bfd_boolean relax_property_section - PARAMS ((bfd *, asection *, struct bfd_link_info *)); -static bfd_boolean relax_section_symbols - PARAMS ((bfd *, asection *)); -static bfd_boolean relocations_reach - PARAMS ((source_reloc *, int, const r_reloc *)); -static void translate_reloc - PARAMS ((const r_reloc *, r_reloc *)); -static Elf_Internal_Rela *get_irel_at_offset - PARAMS ((asection *, Elf_Internal_Rela *, bfd_vma)); -static Elf_Internal_Rela *find_associated_l32r_irel - PARAMS ((asection *, bfd_byte *, Elf_Internal_Rela *, - Elf_Internal_Rela *)); -static void shrink_dynamic_reloc_sections - PARAMS ((struct bfd_link_info *, bfd *, asection *, Elf_Internal_Rela *)); +/* Must be power of 2. */ +#define INITIAL_HASH_RELOC_BUCKET_COUNT 1024 +static value_map_hash_table * +value_map_hash_table_init () +{ + value_map_hash_table *values; -static bfd_boolean -elf_xtensa_relax_section (abfd, sec, link_info, again) - bfd *abfd; - asection *sec; - struct bfd_link_info *link_info; - bfd_boolean *again; + values = (value_map_hash_table *) + bfd_zmalloc (sizeof (value_map_hash_table)); + values->bucket_count = INITIAL_HASH_RELOC_BUCKET_COUNT; + values->count = 0; + values->buckets = (value_map **) + bfd_zmalloc (sizeof (value_map *) * values->bucket_count); + if (values->buckets == NULL) + { + free (values); + return NULL; + } + values->has_last_loc = FALSE; + + return values; +} + + +static void +value_map_hash_table_delete (table) + value_map_hash_table *table; { - static value_map_hash_table *values = NULL; - xtensa_relax_info *relax_info; + free (table->buckets); + free (table); +} + + +static unsigned +hash_bfd_vma (val) + bfd_vma val; +{ + return (val >> 2) + (val >> 10); +} + + +static unsigned +literal_value_hash (src) + const literal_value *src; +{ + unsigned hash_val; - if (!values) + hash_val = hash_bfd_vma (src->value); + if (!r_reloc_is_const (&src->r_rel)) { - /* Do some overall initialization for relaxation. */ - values = value_map_hash_table_init (); - relaxing_section = TRUE; - if (!analyze_relocations (link_info)) - return FALSE; + void *sec_or_hash; + + hash_val += hash_bfd_vma (src->is_abs_literal * 1000); + hash_val += hash_bfd_vma (src->r_rel.target_offset); + hash_val += hash_bfd_vma (src->r_rel.virtual_offset); + + /* Now check for the same section and the same elf_hash. */ + if (r_reloc_is_defined (&src->r_rel)) + sec_or_hash = r_reloc_get_section (&src->r_rel); + else + sec_or_hash = r_reloc_get_hash_entry (&src->r_rel); + hash_val += hash_bfd_vma ((bfd_vma) (unsigned) sec_or_hash); } - *again = FALSE; + return hash_val; +} - /* Don't mess with linker-created sections. */ - if ((sec->flags & SEC_LINKER_CREATED) != 0) - return TRUE; - relax_info = get_xtensa_relax_info (sec); - BFD_ASSERT (relax_info != NULL); +/* Check if the specified literal_value has been seen before. */ - switch (relax_info->visited) +static value_map * +value_map_get_cached_value (map, val, final_static_link) + value_map_hash_table *map; + const literal_value *val; + bfd_boolean final_static_link; +{ + value_map *map_e; + value_map *bucket; + unsigned idx; + + idx = literal_value_hash (val); + idx = idx & (map->bucket_count - 1); + bucket = map->buckets[idx]; + for (map_e = bucket; map_e; map_e = map_e->next) { - case 0: - /* Note: It would be nice to fold this pass into - analyze_relocations, but it is important for this step that the - sections be examined in link order. */ - if (!remove_literals (abfd, sec, link_info, values)) - return FALSE; - *again = TRUE; - break; + if (literal_value_equal (&map_e->val, val, final_static_link)) + return map_e; + } + return NULL; +} - case 1: - if (!relax_section (abfd, sec, link_info)) - return FALSE; - *again = TRUE; - break; - case 2: - if (!relax_section_symbols (abfd, sec)) - return FALSE; - break; +/* Record a new literal value. It is illegal to call this if VALUE + already has an entry here. */ + +static value_map * +add_value_map (map, val, loc, final_static_link) + value_map_hash_table *map; + const literal_value *val; + const r_reloc *loc; + bfd_boolean final_static_link; +{ + value_map **bucket_p; + unsigned idx; + + value_map *val_e = (value_map *) bfd_zmalloc (sizeof (value_map)); + if (val_e == NULL) + { + bfd_set_error (bfd_error_no_memory); + return NULL; } - relax_info->visited++; - return TRUE; + BFD_ASSERT (!value_map_get_cached_value (map, val, final_static_link)); + val_e->val = *val; + val_e->loc = *loc; + + idx = literal_value_hash (val); + idx = idx & (map->bucket_count - 1); + bucket_p = &map->buckets[idx]; + + val_e->next = *bucket_p; + *bucket_p = val_e; + map->count++; + /* FIXME: Consider resizing the hash table if we get too many entries. */ + + return val_e; } -/* Initialization for relaxation. */ + +/* Lists of text actions (ta_) for narrowing, widening, longcall + conversion, space fill, code & literal removal, etc. */ + +/* The following text actions are generated: + + "ta_remove_insn" remove an instruction or instructions + "ta_remove_longcall" convert longcall to call + "ta_convert_longcall" convert longcall to nop/call + "ta_narrow_insn" narrow a wide instruction + "ta_widen" widen a narrow instruction + "ta_fill" add fill or remove fill + removed < 0 is a fill; branches to the fill address will be + changed to address + fill size (e.g., address - removed) + removed >= 0 branches to the fill address will stay unchanged + "ta_remove_literal" remove a literal; this action is + indicated when a literal is removed + or replaced. + "ta_add_literal" insert a new literal; this action is + indicated when a literal has been moved. + It may use a virtual_offset because + multiple literals can be placed at the + same location. + + For each of these text actions, we also record the number of bytes + removed by performing the text action. In the case of a "ta_widen" + or a "ta_fill" that adds space, the removed_bytes will be negative. */ + +typedef struct text_action_struct text_action; +typedef struct text_action_list_struct text_action_list; +typedef enum text_action_enum_t text_action_t; + +enum text_action_enum_t +{ + ta_none, + ta_remove_insn, /* removed = -size */ + ta_remove_longcall, /* removed = -size */ + ta_convert_longcall, /* removed = 0 */ + ta_narrow_insn, /* removed = -1 */ + ta_widen_insn, /* removed = +1 */ + ta_fill, /* removed = +size */ + ta_remove_literal, + ta_add_literal +}; -/* This function is called once at the start of relaxation. It scans - all the input sections and marks the ones that are relaxable (i.e., - literal sections with L32R relocations against them). It then - collect source_reloc information for all the relocations against - those relaxable sections. */ -static bfd_boolean -analyze_relocations (link_info) - struct bfd_link_info *link_info; +/* Structure for a text action record. */ +struct text_action_struct { - bfd *abfd; - asection *sec; - bfd_boolean is_relaxable = FALSE; + text_action_t action; + asection *sec; /* Optional */ + bfd_vma offset; + bfd_vma virtual_offset; /* Zero except for adding literals. */ + int removed_bytes; + literal_value value; /* Only valid when adding literals. */ - /* Initialize the per-section relaxation info. */ - for (abfd = link_info->input_bfds; abfd != NULL; abfd = abfd->link_next) - for (sec = abfd->sections; sec != NULL; sec = sec->next) - { - init_xtensa_relax_info (sec); - } + text_action *next; +}; - /* Mark relaxable sections (and count relocations against each one). */ - for (abfd = link_info->input_bfds; abfd != NULL; abfd = abfd->link_next) - for (sec = abfd->sections; sec != NULL; sec = sec->next) - { - if (!find_relaxable_sections (abfd, sec, link_info, &is_relaxable)) - return FALSE; - } - /* Bail out if there are no relaxable sections. */ - if (!is_relaxable) - return TRUE; +/* List of all of the actions taken on a text section. */ +struct text_action_list_struct +{ + text_action *head; +}; - /* Allocate space for source_relocs. */ - for (abfd = link_info->input_bfds; abfd != NULL; abfd = abfd->link_next) - for (sec = abfd->sections; sec != NULL; sec = sec->next) - { - xtensa_relax_info *relax_info; - relax_info = get_xtensa_relax_info (sec); - if (relax_info->is_relaxable_literal_section) - { - relax_info->src_relocs = (source_reloc *) - bfd_malloc (relax_info->src_count * sizeof (source_reloc)); - } - } +static text_action *find_fill_action + PARAMS ((text_action_list *, asection *, bfd_vma)); +static int compute_removed_action_diff + PARAMS ((const text_action *, asection *, bfd_vma, int, int)); +static void adjust_fill_action + PARAMS ((text_action *, int)); +static void text_action_add + PARAMS ((text_action_list *, text_action_t, asection *, bfd_vma, int)); +static void text_action_add_literal + PARAMS ((text_action_list *, text_action_t, const r_reloc *, + const literal_value *, int)); +static bfd_vma offset_with_removed_text + PARAMS ((text_action_list *, bfd_vma)); +static bfd_vma offset_with_removed_text_before_fill + PARAMS ((text_action_list *, bfd_vma)); +static text_action *find_insn_action + PARAMS ((text_action_list *, bfd_vma)); +#if DEBUG +static void print_action_list + PARAMS ((FILE *, text_action_list *)); +#endif + + +text_action * +find_fill_action (l, sec, offset) + text_action_list *l; + asection *sec; + bfd_vma offset; +{ + text_action **m_p; + + /* It is not necessary to fill at the end of a section. */ + if (sec->size == offset) + return NULL; + + for (m_p = &l->head; + *m_p != NULL && (*m_p)->offset <= offset; + m_p = &(*m_p)->next) + { + text_action *t = *m_p; + /* When the action is another fill at the same address, + just increase the size. */ + if (t->offset == offset && t->action == ta_fill) + return t; + } + return NULL; +} + + +static int +compute_removed_action_diff (ta, sec, offset, removed, removable_space) + const text_action *ta; + asection *sec; + bfd_vma offset; + int removed; + int removable_space; +{ + int new_removed; + int current_removed = 0; + + if (ta != NULL) + current_removed = ta->removed_bytes; + + BFD_ASSERT (ta == NULL || ta->offset == offset); + BFD_ASSERT (ta == NULL || ta->action == ta_fill); + + /* It is not necessary to fill at the end of a section. Clean this up. */ + if (sec->size == offset) + new_removed = removable_space - 0; + else + { + int space; + int added = -removed - current_removed; + /* Ignore multiples of the section alignment. */ + added = ((1 << sec->alignment_power) - 1) & added; + new_removed = (-added); + + /* Modify for removable. */ + space = removable_space - new_removed; + new_removed = (removable_space + - (((1 << sec->alignment_power) - 1) & space)); + } + return (new_removed - current_removed); +} + + +void +adjust_fill_action (ta, fill_diff) + text_action *ta; + int fill_diff; +{ + ta->removed_bytes += fill_diff; +} + + +/* Add a modification action to the text. For the case of adding or + removing space, modify any current fill and assume that + "unreachable_space" bytes can be freely contracted. Note that a + negative removed value is a fill. */ + +static void +text_action_add (l, action, sec, offset, removed) + text_action_list *l; + text_action_t action; + asection *sec; + bfd_vma offset; + int removed; +{ + text_action **m_p; + text_action *ta; + + /* It is not necessary to fill at the end of a section. */ + if (action == ta_fill && sec->size == offset) + return; + + /* It is not necessary to fill 0 bytes. */ + if (action == ta_fill && removed == 0) + return; + + for (m_p = &l->head; + *m_p != NULL && (*m_p)->offset <= offset; + m_p = &(*m_p)->next) + { + text_action *t = *m_p; + /* When the action is another fill at the same address, + just increase the size. */ + if (t->offset == offset && t->action == ta_fill && action == ta_fill) + { + t->removed_bytes += removed; + return; + } + } + + /* Create a new record and fill it up. */ + ta = (text_action *) bfd_zmalloc (sizeof (text_action)); + ta->action = action; + ta->sec = sec; + ta->offset = offset; + ta->removed_bytes = removed; + ta->next = (*m_p); + *m_p = ta; +} + + +static void +text_action_add_literal (l, action, loc, value, removed) + text_action_list *l; + text_action_t action; + const r_reloc *loc; + const literal_value *value; + int removed; +{ + text_action **m_p; + text_action *ta; + asection *sec = r_reloc_get_section (loc); + bfd_vma offset = loc->target_offset; + bfd_vma virtual_offset = loc->virtual_offset; + + BFD_ASSERT (action == ta_add_literal); + + for (m_p = &l->head; *m_p != NULL; m_p = &(*m_p)->next) + { + if ((*m_p)->offset > offset + && ((*m_p)->offset != offset + || (*m_p)->virtual_offset > virtual_offset)) + break; + } + + /* Create a new record and fill it up. */ + ta = (text_action *) bfd_zmalloc (sizeof (text_action)); + ta->action = action; + ta->sec = sec; + ta->offset = offset; + ta->virtual_offset = virtual_offset; + ta->value = *value; + ta->removed_bytes = removed; + ta->next = (*m_p); + *m_p = ta; +} + + +bfd_vma +offset_with_removed_text (action_list, offset) + text_action_list *action_list; + bfd_vma offset; +{ + text_action *r; + int removed = 0; + + for (r = action_list->head; r && r->offset <= offset; r = r->next) + { + if (r->offset < offset + || (r->action == ta_fill && r->removed_bytes < 0)) + removed += r->removed_bytes; + } + + return (offset - removed); +} + + +bfd_vma +offset_with_removed_text_before_fill (action_list, offset) + text_action_list *action_list; + bfd_vma offset; +{ + text_action *r; + int removed = 0; + + for (r = action_list->head; r && r->offset < offset; r = r->next) + removed += r->removed_bytes; + + return (offset - removed); +} + + +/* The find_insn_action routine will only find non-fill actions. */ + +text_action * +find_insn_action (action_list, offset) + text_action_list *action_list; + bfd_vma offset; +{ + text_action *t; + for (t = action_list->head; t; t = t->next) + { + if (t->offset == offset) + { + switch (t->action) + { + case ta_none: + case ta_fill: + break; + case ta_remove_insn: + case ta_remove_longcall: + case ta_convert_longcall: + case ta_narrow_insn: + case ta_widen_insn: + return t; + case ta_remove_literal: + case ta_add_literal: + BFD_ASSERT (0); + break; + } + } + } + return NULL; +} + + +#if DEBUG + +static void +print_action_list (fp, action_list) + FILE *fp; + text_action_list *action_list; +{ + text_action *r; + + fprintf (fp, "Text Action\n"); + for (r = action_list->head; r != NULL; r = r->next) + { + const char *t = "unknown"; + switch (r->action) + { + case ta_remove_insn: + t = "remove_insn"; break; + case ta_remove_longcall: + t = "remove_longcall"; break; + case ta_convert_longcall: + t = "remove_longcall"; break; + case ta_narrow_insn: + t = "narrow_insn"; break; + case ta_widen_insn: + t = "widen_insn"; break; + case ta_fill: + t = "fill"; break; + case ta_none: + t = "none"; break; + case ta_remove_literal: + t = "remove_literal"; break; + case ta_add_literal: + t = "add_literal"; break; + } + + fprintf (fp, "%s: %s[0x%lx] \"%s\" %d\n", + r->sec->owner->filename, + r->sec->name, r->offset, t, r->removed_bytes); + } +} + +#endif /* DEBUG */ + + +/* Lists of literals being coalesced or removed. */ + +/* In the usual case, the literal identified by "from" is being + coalesced with another literal identified by "to". If the literal is + unused and is being removed altogether, "to.abfd" will be NULL. + The removed_literal entries are kept on a per-section list, sorted + by the "from" offset field. */ + +typedef struct removed_literal_struct removed_literal; +typedef struct removed_literal_list_struct removed_literal_list; + +struct removed_literal_struct +{ + r_reloc from; + r_reloc to; + removed_literal *next; +}; + +struct removed_literal_list_struct +{ + removed_literal *head; + removed_literal *tail; +}; + + +static void add_removed_literal + PARAMS ((removed_literal_list *, const r_reloc *, const r_reloc *)); +static removed_literal *find_removed_literal + PARAMS ((removed_literal_list *, bfd_vma)); +#if DEBUG +static void print_removed_literals + PARAMS ((FILE *, removed_literal_list *)); +#endif /* DEBUG */ + + +/* Record that the literal at "from" is being removed. If "to" is not + NULL, the "from" literal is being coalesced with the "to" literal. */ + +static void +add_removed_literal (removed_list, from, to) + removed_literal_list *removed_list; + const r_reloc *from; + const r_reloc *to; +{ + removed_literal *r, *new_r, *next_r; + + new_r = (removed_literal *) bfd_zmalloc (sizeof (removed_literal)); + + new_r->from = *from; + if (to) + new_r->to = *to; + else + new_r->to.abfd = NULL; + new_r->next = NULL; + + r = removed_list->head; + if (r == NULL) + { + removed_list->head = new_r; + removed_list->tail = new_r; + } + /* Special check for common case of append. */ + else if (removed_list->tail->from.target_offset < from->target_offset) + { + removed_list->tail->next = new_r; + removed_list->tail = new_r; + } + else + { + while (r->from.target_offset < from->target_offset + && r->next != NULL) + { + r = r->next; + } + next_r = r->next; + r->next = new_r; + new_r->next = next_r; + if (next_r == NULL) + removed_list->tail = new_r; + } +} + + +/* Check if the list of removed literals contains an entry for the + given address. Return the entry if found. */ + +static removed_literal * +find_removed_literal (removed_list, addr) + removed_literal_list *removed_list; + bfd_vma addr; +{ + removed_literal *r = removed_list->head; + while (r && r->from.target_offset < addr) + r = r->next; + if (r && r->from.target_offset == addr) + return r; + return NULL; +} + + +#if DEBUG + +static void +print_removed_literals (fp, removed_list) + FILE *fp; + removed_literal_list *removed_list; +{ + removed_literal *r; + r = removed_list->head; + if (r) + fprintf (fp, "Removed Literals\n"); + for (; r != NULL; r = r->next) + { + print_r_reloc (fp, &r->from); + fprintf (fp, " => "); + if (r->to.abfd == NULL) + fprintf (fp, "REMOVED"); + else + print_r_reloc (fp, &r->to); + fprintf (fp, "\n"); + } +} + +#endif /* DEBUG */ + + +/* Per-section data for relaxation. */ + +typedef struct reloc_bfd_fix_struct reloc_bfd_fix; + +struct xtensa_relax_info_struct +{ + bfd_boolean is_relaxable_literal_section; + bfd_boolean is_relaxable_asm_section; + int visited; /* Number of times visited. */ + + source_reloc *src_relocs; /* Array[src_count]. */ + int src_count; + int src_next; /* Next src_relocs entry to assign. */ + + removed_literal_list removed_list; + text_action_list action_list; + + reloc_bfd_fix *fix_list; + reloc_bfd_fix *fix_array; + unsigned fix_array_count; + + /* Support for expanding the reloc array that is stored + in the section structure. If the relocations have been + reallocated, the newly allocated relocations will be referenced + here along with the actual size allocated. The relocation + count will always be found in the section structure. */ + Elf_Internal_Rela *allocated_relocs; + unsigned relocs_count; + unsigned allocated_relocs_count; +}; + +struct elf_xtensa_section_data +{ + struct bfd_elf_section_data elf; + xtensa_relax_info relax_info; +}; + +static void init_xtensa_relax_info + PARAMS ((asection *)); +static xtensa_relax_info *get_xtensa_relax_info + PARAMS ((asection *)); + + +static bfd_boolean +elf_xtensa_new_section_hook (abfd, sec) + bfd *abfd; + asection *sec; +{ + struct elf_xtensa_section_data *sdata; + bfd_size_type amt = sizeof (*sdata); + + sdata = (struct elf_xtensa_section_data *) bfd_zalloc (abfd, amt); + if (sdata == NULL) + return FALSE; + sec->used_by_bfd = (PTR) sdata; + + return _bfd_elf_new_section_hook (abfd, sec); +} + + +static void +init_xtensa_relax_info (sec) + asection *sec; +{ + xtensa_relax_info *relax_info = get_xtensa_relax_info (sec); + + relax_info->is_relaxable_literal_section = FALSE; + relax_info->is_relaxable_asm_section = FALSE; + relax_info->visited = 0; + + relax_info->src_relocs = NULL; + relax_info->src_count = 0; + relax_info->src_next = 0; + + relax_info->removed_list.head = NULL; + relax_info->removed_list.tail = NULL; + + relax_info->action_list.head = NULL; + + relax_info->fix_list = NULL; + relax_info->fix_array = NULL; + relax_info->fix_array_count = 0; + + relax_info->allocated_relocs = NULL; + relax_info->relocs_count = 0; + relax_info->allocated_relocs_count = 0; +} + + +static xtensa_relax_info * +get_xtensa_relax_info (sec) + asection *sec; +{ + struct elf_xtensa_section_data *section_data; + + /* No info available if no section or if it is an output section. */ + if (!sec || sec == sec->output_section) + return NULL; + + section_data = (struct elf_xtensa_section_data *) elf_section_data (sec); + return §ion_data->relax_info; +} + + +/* Coalescing literals may require a relocation to refer to a section in + a different input file, but the standard relocation information + cannot express that. Instead, the reloc_bfd_fix structures are used + to "fix" the relocations that refer to sections in other input files. + These structures are kept on per-section lists. The "src_type" field + records the relocation type in case there are multiple relocations on + the same location. FIXME: This is ugly; an alternative might be to + add new symbols with the "owner" field to some other input file. */ + +struct reloc_bfd_fix_struct +{ + asection *src_sec; + bfd_vma src_offset; + unsigned src_type; /* Relocation type. */ + + bfd *target_abfd; + asection *target_sec; + bfd_vma target_offset; + bfd_boolean translated; + + reloc_bfd_fix *next; +}; + + +static reloc_bfd_fix *reloc_bfd_fix_init + PARAMS ((asection *, bfd_vma, unsigned, bfd *, asection *, bfd_vma, + bfd_boolean)); +static void add_fix + PARAMS ((asection *, reloc_bfd_fix *)); +static int fix_compare + PARAMS ((const PTR, const PTR)); +static void cache_fix_array + PARAMS ((asection *)); +static reloc_bfd_fix *get_bfd_fix + PARAMS ((asection *, bfd_vma, unsigned)); + + +static reloc_bfd_fix * +reloc_bfd_fix_init (src_sec, src_offset, src_type, + target_abfd, target_sec, target_offset, translated) + asection *src_sec; + bfd_vma src_offset; + unsigned src_type; + bfd *target_abfd; + asection *target_sec; + bfd_vma target_offset; + bfd_boolean translated; +{ + reloc_bfd_fix *fix; + + fix = (reloc_bfd_fix *) bfd_malloc (sizeof (reloc_bfd_fix)); + fix->src_sec = src_sec; + fix->src_offset = src_offset; + fix->src_type = src_type; + fix->target_abfd = target_abfd; + fix->target_sec = target_sec; + fix->target_offset = target_offset; + fix->translated = translated; + + return fix; +} + + +static void +add_fix (src_sec, fix) + asection *src_sec; + reloc_bfd_fix *fix; +{ + xtensa_relax_info *relax_info; + + relax_info = get_xtensa_relax_info (src_sec); + fix->next = relax_info->fix_list; + relax_info->fix_list = fix; +} + + +static int +fix_compare (ap, bp) + const PTR ap; + const PTR bp; +{ + const reloc_bfd_fix *a = (const reloc_bfd_fix *) ap; + const reloc_bfd_fix *b = (const reloc_bfd_fix *) bp; + + if (a->src_offset != b->src_offset) + return (a->src_offset - b->src_offset); + return (a->src_type - b->src_type); +} + + +static void +cache_fix_array (sec) + asection *sec; +{ + unsigned i, count = 0; + reloc_bfd_fix *r; + xtensa_relax_info *relax_info = get_xtensa_relax_info (sec); + + if (relax_info == NULL) + return; + if (relax_info->fix_list == NULL) + return; + + for (r = relax_info->fix_list; r != NULL; r = r->next) + count++; + + relax_info->fix_array = + (reloc_bfd_fix *) bfd_malloc (sizeof (reloc_bfd_fix) * count); + relax_info->fix_array_count = count; + + r = relax_info->fix_list; + for (i = 0; i < count; i++, r = r->next) + { + relax_info->fix_array[count - 1 - i] = *r; + relax_info->fix_array[count - 1 - i].next = NULL; + } + + qsort (relax_info->fix_array, relax_info->fix_array_count, + sizeof (reloc_bfd_fix), fix_compare); +} + + +static reloc_bfd_fix * +get_bfd_fix (sec, offset, type) + asection *sec; + bfd_vma offset; + unsigned type; +{ + xtensa_relax_info *relax_info = get_xtensa_relax_info (sec); + reloc_bfd_fix *rv; + reloc_bfd_fix key; + + if (relax_info == NULL) + return NULL; + if (relax_info->fix_list == NULL) + return NULL; + + if (relax_info->fix_array == NULL) + cache_fix_array (sec); + + key.src_offset = offset; + key.src_type = type; + rv = bsearch (&key, relax_info->fix_array, relax_info->fix_array_count, + sizeof (reloc_bfd_fix), fix_compare); + return rv; +} + + +/* Section caching. */ + +typedef struct section_cache_struct section_cache_t; + +struct section_cache_struct +{ + asection *sec; + + bfd_byte *contents; /* Cache of the section contents. */ + bfd_size_type content_length; + + property_table_entry *ptbl; /* Cache of the section property table. */ + unsigned pte_count; + + Elf_Internal_Rela *relocs; /* Cache of the section relocations. */ + unsigned reloc_count; +}; + + +static void init_section_cache + PARAMS ((section_cache_t *)); +static bfd_boolean section_cache_section + PARAMS ((section_cache_t *, asection *, struct bfd_link_info *)); +static void clear_section_cache + PARAMS ((section_cache_t *)); + + +static void +init_section_cache (sec_cache) + section_cache_t *sec_cache; +{ + memset (sec_cache, 0, sizeof (*sec_cache)); +} + + +static bfd_boolean +section_cache_section (sec_cache, sec, link_info) + section_cache_t *sec_cache; + asection *sec; + struct bfd_link_info *link_info; +{ + bfd *abfd; + property_table_entry *prop_table = NULL; + int ptblsize = 0; + bfd_byte *contents = NULL; + Elf_Internal_Rela *internal_relocs = NULL; + bfd_size_type sec_size; + + if (sec == NULL) + return FALSE; + if (sec == sec_cache->sec) + return TRUE; + + abfd = sec->owner; + sec_size = bfd_get_section_limit (abfd, sec); + + /* Get the contents. */ + contents = retrieve_contents (abfd, sec, link_info->keep_memory); + if (contents == NULL && sec_size != 0) + goto err; + + /* Get the relocations. */ + internal_relocs = retrieve_internal_relocs (abfd, sec, + link_info->keep_memory); + + /* Get the entry table. */ + ptblsize = xtensa_read_table_entries (abfd, sec, &prop_table, + XTENSA_PROP_SEC_NAME, FALSE); + if (ptblsize < 0) + goto err; + + /* Fill in the new section cache. */ + clear_section_cache (sec_cache); + memset (sec_cache, 0, sizeof (sec_cache)); + + sec_cache->sec = sec; + sec_cache->contents = contents; + sec_cache->content_length = sec_size; + sec_cache->relocs = internal_relocs; + sec_cache->reloc_count = sec->reloc_count; + sec_cache->pte_count = ptblsize; + sec_cache->ptbl = prop_table; + + return TRUE; + + err: + release_contents (sec, contents); + release_internal_relocs (sec, internal_relocs); + if (prop_table) + free (prop_table); + return FALSE; +} + + +static void +clear_section_cache (sec_cache) + section_cache_t *sec_cache; +{ + if (sec_cache->sec) + { + release_contents (sec_cache->sec, sec_cache->contents); + release_internal_relocs (sec_cache->sec, sec_cache->relocs); + if (sec_cache->ptbl) + free (sec_cache->ptbl); + memset (sec_cache, 0, sizeof (sec_cache)); + } +} + + +/* Extended basic blocks. */ + +/* An ebb_struct represents an Extended Basic Block. Within this + range, we guarantee that all instructions are decodable, the + property table entries are contiguous, and no property table + specifies a segment that cannot have instructions moved. This + structure contains caches of the contents, property table and + relocations for the specified section for easy use. The range is + specified by ranges of indices for the byte offset, property table + offsets and relocation offsets. These must be consistent. */ + +typedef struct ebb_struct ebb_t; + +struct ebb_struct +{ + asection *sec; + + bfd_byte *contents; /* Cache of the section contents. */ + bfd_size_type content_length; + + property_table_entry *ptbl; /* Cache of the section property table. */ + unsigned pte_count; + + Elf_Internal_Rela *relocs; /* Cache of the section relocations. */ + unsigned reloc_count; + + bfd_vma start_offset; /* Offset in section. */ + unsigned start_ptbl_idx; /* Offset in the property table. */ + unsigned start_reloc_idx; /* Offset in the relocations. */ + + bfd_vma end_offset; + unsigned end_ptbl_idx; + unsigned end_reloc_idx; + + bfd_boolean ends_section; /* Is this the last ebb in a section? */ + + /* The unreachable property table at the end of this set of blocks; + NULL if the end is not an unreachable block. */ + property_table_entry *ends_unreachable; +}; + + +enum ebb_target_enum +{ + EBB_NO_ALIGN = 0, + EBB_DESIRE_TGT_ALIGN, + EBB_REQUIRE_TGT_ALIGN, + EBB_REQUIRE_LOOP_ALIGN, + EBB_REQUIRE_ALIGN +}; + + +/* proposed_action_struct is similar to the text_action_struct except + that is represents a potential transformation, not one that will + occur. We build a list of these for an extended basic block + and use them to compute the actual actions desired. We must be + careful that the entire set of actual actions we perform do not + break any relocations that would fit if the actions were not + performed. */ + +typedef struct proposed_action_struct proposed_action; + +struct proposed_action_struct +{ + enum ebb_target_enum align_type; /* for the target alignment */ + bfd_vma alignment_pow; + text_action_t action; + bfd_vma offset; + int removed_bytes; + bfd_boolean do_action; /* If false, then we will not perform the action. */ +}; + + +/* The ebb_constraint_struct keeps a set of proposed actions for an + extended basic block. */ + +typedef struct ebb_constraint_struct ebb_constraint; + +struct ebb_constraint_struct +{ + ebb_t ebb; + bfd_boolean start_movable; + + /* Bytes of extra space at the beginning if movable. */ + int start_extra_space; + + enum ebb_target_enum start_align; + + bfd_boolean end_movable; + + /* Bytes of extra space at the end if movable. */ + int end_extra_space; + + unsigned action_count; + unsigned action_allocated; + + /* Array of proposed actions. */ + proposed_action *actions; + + /* Action alignments -- one for each proposed action. */ + enum ebb_target_enum *action_aligns; +}; + + +static void init_ebb_constraint + PARAMS ((ebb_constraint *)); +static void free_ebb_constraint + PARAMS ((ebb_constraint *)); +static void init_ebb + PARAMS ((ebb_t *, asection *, bfd_byte *, bfd_size_type, + property_table_entry *, unsigned, Elf_Internal_Rela *, unsigned)); +static bfd_boolean extend_ebb_bounds + PARAMS ((ebb_t *)); +static bfd_boolean extend_ebb_bounds_forward + PARAMS ((ebb_t *)); +static bfd_boolean extend_ebb_bounds_backward + PARAMS ((ebb_t *)); +static bfd_size_type insn_block_decodable_len + PARAMS ((bfd_byte *, bfd_size_type, bfd_vma, bfd_size_type)); +static void ebb_propose_action + PARAMS ((ebb_constraint *, enum ebb_target_enum, bfd_vma, text_action_t, + bfd_vma, int, bfd_boolean)); +static void ebb_add_proposed_action + PARAMS ((ebb_constraint *, proposed_action *)); + + +static void +init_ebb_constraint (c) + ebb_constraint *c; +{ + memset (c, 0, sizeof (ebb_constraint)); +} + + +static void +free_ebb_constraint (c) + ebb_constraint *c; +{ + if (c->actions != NULL) + free (c->actions); +} + + +static void +init_ebb (ebb, sec, contents, content_length, prop_table, ptblsize, + internal_relocs, reloc_count) + ebb_t *ebb; + asection *sec; + bfd_byte *contents; + bfd_size_type content_length; + property_table_entry *prop_table; + unsigned ptblsize; + Elf_Internal_Rela *internal_relocs; + unsigned reloc_count; +{ + memset (ebb, 0, sizeof (ebb_t)); + ebb->sec = sec; + ebb->contents = contents; + ebb->content_length = content_length; + ebb->ptbl = prop_table; + ebb->pte_count = ptblsize; + ebb->relocs = internal_relocs; + ebb->reloc_count = reloc_count; + ebb->start_offset = 0; + ebb->end_offset = ebb->content_length - 1; + ebb->start_ptbl_idx = 0; + ebb->end_ptbl_idx = ptblsize; + ebb->start_reloc_idx = 0; + ebb->end_reloc_idx = reloc_count; +} + + +/* Extend the ebb to all decodable contiguous sections. The algorithm + for building a basic block around an instruction is to push it + forward until we hit the end of a section, an unreachable block or + a block that cannot be transformed. Then we push it backwards + searching for similar conditions. */ + +static bfd_boolean +extend_ebb_bounds (ebb) + ebb_t *ebb; +{ + if (!extend_ebb_bounds_forward (ebb)) + return FALSE; + if (!extend_ebb_bounds_backward (ebb)) + return FALSE; + return TRUE; +} + + +static bfd_boolean +extend_ebb_bounds_forward (ebb) + ebb_t *ebb; +{ + property_table_entry *the_entry, *new_entry; + + the_entry = &ebb->ptbl[ebb->end_ptbl_idx]; + + /* Stop when (1) we cannot decode an instruction, (2) we are at + the end of the property tables, (3) we hit a non-contiguous property + table entry, (4) we hit a NO_TRANSFORM region. */ + + while (1) + { + bfd_vma entry_end; + bfd_size_type insn_block_len; + + entry_end = the_entry->address - ebb->sec->vma + the_entry->size; + insn_block_len = + insn_block_decodable_len (ebb->contents, ebb->content_length, + ebb->end_offset, + entry_end - ebb->end_offset); + if (insn_block_len != (entry_end - ebb->end_offset)) + { + (*_bfd_error_handler) + (_("%B(%A+0x%lx): could not decode instruction; possible configuration mismatch"), + ebb->sec->owner, ebb->sec, ebb->end_offset + insn_block_len); + return FALSE; + } + ebb->end_offset += insn_block_len; + + if (ebb->end_offset == ebb->sec->size) + ebb->ends_section = TRUE; + + /* Update the reloc counter. */ + while (ebb->end_reloc_idx + 1 < ebb->reloc_count + && (ebb->relocs[ebb->end_reloc_idx + 1].r_offset + < ebb->end_offset)) + { + ebb->end_reloc_idx++; + } + + if (ebb->end_ptbl_idx + 1 == ebb->pte_count) + return TRUE; + + new_entry = &ebb->ptbl[ebb->end_ptbl_idx + 1]; + if (((new_entry->flags & XTENSA_PROP_INSN) == 0) + || ((new_entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM) != 0) + || ((the_entry->flags & XTENSA_PROP_ALIGN) != 0)) + break; + + if (the_entry->address + the_entry->size != new_entry->address) + break; + + the_entry = new_entry; + ebb->end_ptbl_idx++; + } + + /* Quick check for an unreachable or end of file just at the end. */ + if (ebb->end_ptbl_idx + 1 == ebb->pte_count) + { + if (ebb->end_offset == ebb->content_length) + ebb->ends_section = TRUE; + } + else + { + new_entry = &ebb->ptbl[ebb->end_ptbl_idx + 1]; + if ((new_entry->flags & XTENSA_PROP_UNREACHABLE) != 0 + && the_entry->address + the_entry->size == new_entry->address) + ebb->ends_unreachable = new_entry; + } + + /* Any other ending requires exact alignment. */ + return TRUE; +} + + +static bfd_boolean +extend_ebb_bounds_backward (ebb) + ebb_t *ebb; +{ + property_table_entry *the_entry, *new_entry; + + the_entry = &ebb->ptbl[ebb->start_ptbl_idx]; + + /* Stop when (1) we cannot decode the instructions in the current entry. + (2) we are at the beginning of the property tables, (3) we hit a + non-contiguous property table entry, (4) we hit a NO_TRANSFORM region. */ + + while (1) + { + bfd_vma block_begin; + bfd_size_type insn_block_len; + + block_begin = the_entry->address - ebb->sec->vma; + insn_block_len = + insn_block_decodable_len (ebb->contents, ebb->content_length, + block_begin, + ebb->start_offset - block_begin); + if (insn_block_len != ebb->start_offset - block_begin) + { + (*_bfd_error_handler) + (_("%B(%A+0x%lx): could not decode instruction; possible configuration mismatch"), + ebb->sec->owner, ebb->sec, ebb->end_offset + insn_block_len); + return FALSE; + } + ebb->start_offset -= insn_block_len; + + /* Update the reloc counter. */ + while (ebb->start_reloc_idx > 0 + && (ebb->relocs[ebb->start_reloc_idx - 1].r_offset + >= ebb->start_offset)) + { + ebb->start_reloc_idx--; + } + + if (ebb->start_ptbl_idx == 0) + return TRUE; + + new_entry = &ebb->ptbl[ebb->start_ptbl_idx - 1]; + if ((new_entry->flags & XTENSA_PROP_INSN) == 0 + || ((new_entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM) != 0) + || ((new_entry->flags & XTENSA_PROP_ALIGN) != 0)) + return TRUE; + if (new_entry->address + new_entry->size != the_entry->address) + return TRUE; + + the_entry = new_entry; + ebb->start_ptbl_idx--; + } + return TRUE; +} + + +static bfd_size_type +insn_block_decodable_len (contents, content_len, block_offset, block_len) + bfd_byte *contents; + bfd_size_type content_len; + bfd_vma block_offset; + bfd_size_type block_len; +{ + bfd_vma offset = block_offset; + + while (offset < block_offset + block_len) + { + bfd_size_type insn_len = 0; + + insn_len = insn_decode_len (contents, content_len, offset); + if (insn_len == 0) + return (offset - block_offset); + offset += insn_len; + } + return (offset - block_offset); +} + + +static void +ebb_propose_action (c, align_type, alignment_pow, action, offset, + removed_bytes, do_action) + ebb_constraint *c; + bfd_vma alignment_pow; + enum ebb_target_enum align_type; + text_action_t action; + bfd_vma offset; + int removed_bytes; + bfd_boolean do_action; +{ + proposed_action paction; + paction.align_type = align_type; + paction.alignment_pow = alignment_pow; + paction.action = action; + paction.offset = offset; + paction.removed_bytes = removed_bytes; + paction.do_action = do_action; + ebb_add_proposed_action (c, &paction); +} + + +static void +ebb_add_proposed_action (c, action) + ebb_constraint *c; + proposed_action *action; +{ + unsigned i; + if (c->action_allocated <= c->action_count) + { + unsigned new_allocated = (c->action_count + 2) * 2; + proposed_action *new_actions = (proposed_action *) + bfd_zmalloc (sizeof (proposed_action) * new_allocated); + + for (i = 0; i < c->action_count; i++) + new_actions[i] = c->actions[i]; + if (c->actions != NULL) + free (c->actions); + c->actions = new_actions; + c->action_allocated = new_allocated; + } + c->actions[c->action_count] = *action; + c->action_count++; +} + + +/* Access to internal relocations, section contents and symbols. */ + +/* During relaxation, we need to modify relocations, section contents, + and symbol definitions, and we need to keep the original values from + being reloaded from the input files, i.e., we need to "pin" the + modified values in memory. We also want to continue to observe the + setting of the "keep-memory" flag. The following functions wrap the + standard BFD functions to take care of this for us. */ + +static Elf_Internal_Rela * +retrieve_internal_relocs (abfd, sec, keep_memory) + bfd *abfd; + asection *sec; + bfd_boolean keep_memory; +{ + Elf_Internal_Rela *internal_relocs; + + if ((sec->flags & SEC_LINKER_CREATED) != 0) + return NULL; + + internal_relocs = elf_section_data (sec)->relocs; + if (internal_relocs == NULL) + internal_relocs = (_bfd_elf_link_read_relocs + (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL, + keep_memory)); + return internal_relocs; +} + + +static void +pin_internal_relocs (sec, internal_relocs) + asection *sec; + Elf_Internal_Rela *internal_relocs; +{ + elf_section_data (sec)->relocs = internal_relocs; +} + + +static void +release_internal_relocs (sec, internal_relocs) + asection *sec; + Elf_Internal_Rela *internal_relocs; +{ + if (internal_relocs + && elf_section_data (sec)->relocs != internal_relocs) + free (internal_relocs); +} + + +static bfd_byte * +retrieve_contents (abfd, sec, keep_memory) + bfd *abfd; + asection *sec; + bfd_boolean keep_memory; +{ + bfd_byte *contents; + bfd_size_type sec_size; + + sec_size = bfd_get_section_limit (abfd, sec); + contents = elf_section_data (sec)->this_hdr.contents; + + if (contents == NULL && sec_size != 0) + { + if (!bfd_malloc_and_get_section (abfd, sec, &contents)) + { + if (contents != NULL) + free (contents); + return NULL; + } + if (keep_memory) + elf_section_data (sec)->this_hdr.contents = contents; + } + return contents; +} + + +static void +pin_contents (sec, contents) + asection *sec; + bfd_byte *contents; +{ + elf_section_data (sec)->this_hdr.contents = contents; +} + + +static void +release_contents (sec, contents) + asection *sec; + bfd_byte *contents; +{ + if (contents && elf_section_data (sec)->this_hdr.contents != contents) + free (contents); +} + + +static Elf_Internal_Sym * +retrieve_local_syms (input_bfd) + bfd *input_bfd; +{ + Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Sym *isymbuf; + size_t locsymcount; + + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + locsymcount = symtab_hdr->sh_info; + + isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; + if (isymbuf == NULL && locsymcount != 0) + isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, locsymcount, 0, + NULL, NULL, NULL); + + /* Save the symbols for this input file so they won't be read again. */ + if (isymbuf && isymbuf != (Elf_Internal_Sym *) symtab_hdr->contents) + symtab_hdr->contents = (unsigned char *) isymbuf; + + return isymbuf; +} + + +/* Code for link-time relaxation. */ + +/* Initialization for relaxation: */ +static bfd_boolean analyze_relocations + PARAMS ((struct bfd_link_info *)); +static bfd_boolean find_relaxable_sections + PARAMS ((bfd *, asection *, struct bfd_link_info *, bfd_boolean *)); +static bfd_boolean collect_source_relocs + PARAMS ((bfd *, asection *, struct bfd_link_info *)); +static bfd_boolean is_resolvable_asm_expansion + PARAMS ((bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, + struct bfd_link_info *, bfd_boolean *)); +static Elf_Internal_Rela *find_associated_l32r_irel + PARAMS ((bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, + Elf_Internal_Rela *)); +static bfd_boolean compute_text_actions + PARAMS ((bfd *, asection *, struct bfd_link_info *)); +static bfd_boolean compute_ebb_proposed_actions + PARAMS ((ebb_constraint *)); +static bfd_boolean compute_ebb_actions + PARAMS ((ebb_constraint *)); +static bfd_boolean check_section_ebb_pcrels_fit + PARAMS ((bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, + const ebb_constraint *)); +static bfd_boolean check_section_ebb_reduces + PARAMS ((const ebb_constraint *)); +static void text_action_add_proposed + PARAMS ((text_action_list *, const ebb_constraint *, asection *)); +static int compute_fill_extra_space + PARAMS ((property_table_entry *)); + +/* First pass: */ +static bfd_boolean compute_removed_literals + PARAMS ((bfd *, asection *, struct bfd_link_info *, value_map_hash_table *)); +static Elf_Internal_Rela *get_irel_at_offset + PARAMS ((asection *, Elf_Internal_Rela *, bfd_vma)); +static bfd_boolean is_removable_literal + PARAMS ((const source_reloc *, int, const source_reloc *, int)); +static bfd_boolean remove_dead_literal + PARAMS ((bfd *, asection *, struct bfd_link_info *, Elf_Internal_Rela *, + Elf_Internal_Rela *, source_reloc *, property_table_entry *, int)); +static bfd_boolean identify_literal_placement + PARAMS ((bfd *, asection *, bfd_byte *, struct bfd_link_info *, + value_map_hash_table *, bfd_boolean *, Elf_Internal_Rela *, int, + source_reloc *, property_table_entry *, int, section_cache_t *, + bfd_boolean)); +static bfd_boolean relocations_reach + PARAMS ((source_reloc *, int, const r_reloc *)); +static bfd_boolean coalesce_shared_literal + PARAMS ((asection *, source_reloc *, property_table_entry *, int, + value_map *)); +static bfd_boolean move_shared_literal + PARAMS ((asection *, struct bfd_link_info *, source_reloc *, + property_table_entry *, int, const r_reloc *, + const literal_value *, section_cache_t *)); + +/* Second pass: */ +static bfd_boolean relax_section + PARAMS ((bfd *, asection *, struct bfd_link_info *)); +static bfd_boolean translate_section_fixes + PARAMS ((asection *)); +static bfd_boolean translate_reloc_bfd_fix + PARAMS ((reloc_bfd_fix *)); +static void translate_reloc + PARAMS ((const r_reloc *, r_reloc *)); +static void shrink_dynamic_reloc_sections + PARAMS ((struct bfd_link_info *, bfd *, asection *, Elf_Internal_Rela *)); +static bfd_boolean move_literal + PARAMS ((bfd *, struct bfd_link_info *, asection *, bfd_vma, bfd_byte *, + xtensa_relax_info *, Elf_Internal_Rela **, const literal_value *)); +static bfd_boolean relax_property_section + PARAMS ((bfd *, asection *, struct bfd_link_info *)); + +/* Third pass: */ +static bfd_boolean relax_section_symbols + PARAMS ((bfd *, asection *)); + + +static bfd_boolean +elf_xtensa_relax_section (abfd, sec, link_info, again) + bfd *abfd; + asection *sec; + struct bfd_link_info *link_info; + bfd_boolean *again; +{ + static value_map_hash_table *values = NULL; + static bfd_boolean relocations_analyzed = FALSE; + xtensa_relax_info *relax_info; + + if (!relocations_analyzed) + { + /* Do some overall initialization for relaxation. */ + values = value_map_hash_table_init (); + if (values == NULL) + return FALSE; + relaxing_section = TRUE; + if (!analyze_relocations (link_info)) + return FALSE; + relocations_analyzed = TRUE; + } + *again = FALSE; + + /* Don't mess with linker-created sections. */ + if ((sec->flags & SEC_LINKER_CREATED) != 0) + return TRUE; + + relax_info = get_xtensa_relax_info (sec); + BFD_ASSERT (relax_info != NULL); + + switch (relax_info->visited) + { + case 0: + /* Note: It would be nice to fold this pass into + analyze_relocations, but it is important for this step that the + sections be examined in link order. */ + if (!compute_removed_literals (abfd, sec, link_info, values)) + return FALSE; + *again = TRUE; + break; + + case 1: + if (values) + value_map_hash_table_delete (values); + values = NULL; + if (!relax_section (abfd, sec, link_info)) + return FALSE; + *again = TRUE; + break; + + case 2: + if (!relax_section_symbols (abfd, sec)) + return FALSE; + break; + } + + relax_info->visited++; + return TRUE; +} + + +/* Initialization for relaxation. */ + +/* This function is called once at the start of relaxation. It scans + all the input sections and marks the ones that are relaxable (i.e., + literal sections with L32R relocations against them), and then + collects source_reloc information for all the relocations against + those relaxable sections. During this process, it also detects + longcalls, i.e., calls relaxed by the assembler into indirect + calls, that can be optimized back into direct calls. Within each + extended basic block (ebb) containing an optimized longcall, it + computes a set of "text actions" that can be performed to remove + the L32R associated with the longcall while optionally preserving + branch target alignments. */ + +static bfd_boolean +analyze_relocations (link_info) + struct bfd_link_info *link_info; +{ + bfd *abfd; + asection *sec; + bfd_boolean is_relaxable = FALSE; + + /* Initialize the per-section relaxation info. */ + for (abfd = link_info->input_bfds; abfd != NULL; abfd = abfd->link_next) + for (sec = abfd->sections; sec != NULL; sec = sec->next) + { + init_xtensa_relax_info (sec); + } + + /* Mark relaxable sections (and count relocations against each one). */ + for (abfd = link_info->input_bfds; abfd != NULL; abfd = abfd->link_next) + for (sec = abfd->sections; sec != NULL; sec = sec->next) + { + if (!find_relaxable_sections (abfd, sec, link_info, &is_relaxable)) + return FALSE; + } + + /* Bail out if there are no relaxable sections. */ + if (!is_relaxable) + return TRUE; + + /* Allocate space for source_relocs. */ + for (abfd = link_info->input_bfds; abfd != NULL; abfd = abfd->link_next) + for (sec = abfd->sections; sec != NULL; sec = sec->next) + { + xtensa_relax_info *relax_info; + + relax_info = get_xtensa_relax_info (sec); + if (relax_info->is_relaxable_literal_section + || relax_info->is_relaxable_asm_section) + { + relax_info->src_relocs = (source_reloc *) + bfd_malloc (relax_info->src_count * sizeof (source_reloc)); + } + } + + /* Collect info on relocations against each relaxable section. */ + for (abfd = link_info->input_bfds; abfd != NULL; abfd = abfd->link_next) + for (sec = abfd->sections; sec != NULL; sec = sec->next) + { + if (!collect_source_relocs (abfd, sec, link_info)) + return FALSE; + } + + /* Compute the text actions. */ + for (abfd = link_info->input_bfds; abfd != NULL; abfd = abfd->link_next) + for (sec = abfd->sections; sec != NULL; sec = sec->next) + { + if (!compute_text_actions (abfd, sec, link_info)) + return FALSE; + } + + return TRUE; +} + + +/* Find all the sections that might be relaxed. The motivation for + this pass is that collect_source_relocs() needs to record _all_ the + relocations that target each relaxable section. That is expensive + and unnecessary unless the target section is actually going to be + relaxed. This pass identifies all such sections by checking if + they have L32Rs pointing to them. In the process, the total number + of relocations targeting each section is also counted so that we + know how much space to allocate for source_relocs against each + relaxable literal section. */ + +static bfd_boolean +find_relaxable_sections (abfd, sec, link_info, is_relaxable_p) + bfd *abfd; + asection *sec; + struct bfd_link_info *link_info; + bfd_boolean *is_relaxable_p; +{ + Elf_Internal_Rela *internal_relocs; + bfd_byte *contents; + bfd_boolean ok = TRUE; + unsigned i; + xtensa_relax_info *source_relax_info; + + internal_relocs = retrieve_internal_relocs (abfd, sec, + link_info->keep_memory); + if (internal_relocs == NULL) + return ok; + + contents = retrieve_contents (abfd, sec, link_info->keep_memory); + if (contents == NULL && sec->size != 0) + { + ok = FALSE; + goto error_return; + } + + source_relax_info = get_xtensa_relax_info (sec); + for (i = 0; i < sec->reloc_count; i++) + { + Elf_Internal_Rela *irel = &internal_relocs[i]; + r_reloc r_rel; + asection *target_sec; + xtensa_relax_info *target_relax_info; + + /* If this section has not already been marked as "relaxable", and + if it contains any ASM_EXPAND relocations (marking expanded + longcalls) that can be optimized into direct calls, then mark + the section as "relaxable". */ + if (source_relax_info + && !source_relax_info->is_relaxable_asm_section + && ELF32_R_TYPE (irel->r_info) == R_XTENSA_ASM_EXPAND) + { + bfd_boolean is_reachable = FALSE; + if (is_resolvable_asm_expansion (abfd, sec, contents, irel, + link_info, &is_reachable) + && is_reachable) + { + source_relax_info->is_relaxable_asm_section = TRUE; + *is_relaxable_p = TRUE; + } + } + + r_reloc_init (&r_rel, abfd, irel, contents, + bfd_get_section_limit (abfd, sec)); + + target_sec = r_reloc_get_section (&r_rel); + target_relax_info = get_xtensa_relax_info (target_sec); + if (!target_relax_info) + continue; + + /* Count PC-relative operand relocations against the target section. + Note: The conditions tested here must match the conditions under + which init_source_reloc is called in collect_source_relocs(). */ + if (is_operand_relocation (ELF32_R_TYPE (irel->r_info)) + && (!is_alt_relocation (ELF32_R_TYPE (irel->r_info)) + || is_l32r_relocation (abfd, sec, contents, irel))) + target_relax_info->src_count++; + + if (is_l32r_relocation (abfd, sec, contents, irel) + && r_reloc_is_defined (&r_rel)) + { + /* Mark the target section as relaxable. */ + target_relax_info->is_relaxable_literal_section = TRUE; + *is_relaxable_p = TRUE; + } + } + + error_return: + release_contents (sec, contents); + release_internal_relocs (sec, internal_relocs); + return ok; +} + + +/* Record _all_ the relocations that point to relaxable sections, and + get rid of ASM_EXPAND relocs by either converting them to + ASM_SIMPLIFY or by removing them. */ + +static bfd_boolean +collect_source_relocs (abfd, sec, link_info) + bfd *abfd; + asection *sec; + struct bfd_link_info *link_info; +{ + Elf_Internal_Rela *internal_relocs; + bfd_byte *contents; + bfd_boolean ok = TRUE; + unsigned i; + bfd_size_type sec_size; + + internal_relocs = retrieve_internal_relocs (abfd, sec, + link_info->keep_memory); + if (internal_relocs == NULL) + return ok; + + sec_size = bfd_get_section_limit (abfd, sec); + contents = retrieve_contents (abfd, sec, link_info->keep_memory); + if (contents == NULL && sec_size != 0) + { + ok = FALSE; + goto error_return; + } + + /* Record relocations against relaxable literal sections. */ + for (i = 0; i < sec->reloc_count; i++) + { + Elf_Internal_Rela *irel = &internal_relocs[i]; + r_reloc r_rel; + asection *target_sec; + xtensa_relax_info *target_relax_info; + + r_reloc_init (&r_rel, abfd, irel, contents, sec_size); + + target_sec = r_reloc_get_section (&r_rel); + target_relax_info = get_xtensa_relax_info (target_sec); + + if (target_relax_info + && (target_relax_info->is_relaxable_literal_section + || target_relax_info->is_relaxable_asm_section)) + { + xtensa_opcode opcode = XTENSA_UNDEFINED; + int opnd = -1; + bfd_boolean is_abs_literal = FALSE; + + if (is_alt_relocation (ELF32_R_TYPE (irel->r_info))) + { + /* None of the current alternate relocs are PC-relative, + and only PC-relative relocs matter here. However, we + still need to record the opcode for literal + coalescing. */ + opcode = get_relocation_opcode (abfd, sec, contents, irel); + if (opcode == get_l32r_opcode ()) + { + is_abs_literal = TRUE; + opnd = 1; + } + else + opcode = XTENSA_UNDEFINED; + } + else if (is_operand_relocation (ELF32_R_TYPE (irel->r_info))) + { + opcode = get_relocation_opcode (abfd, sec, contents, irel); + opnd = get_relocation_opnd (opcode, ELF32_R_TYPE (irel->r_info)); + } + + if (opcode != XTENSA_UNDEFINED) + { + int src_next = target_relax_info->src_next++; + source_reloc *s_reloc = &target_relax_info->src_relocs[src_next]; + + init_source_reloc (s_reloc, sec, &r_rel, opcode, opnd, + is_abs_literal); + } + } + } + + /* Now get rid of ASM_EXPAND relocations. At this point, the + src_relocs array for the target literal section may still be + incomplete, but it must at least contain the entries for the L32R + relocations associated with ASM_EXPANDs because they were just + added in the preceding loop over the relocations. */ + + for (i = 0; i < sec->reloc_count; i++) + { + Elf_Internal_Rela *irel = &internal_relocs[i]; + bfd_boolean is_reachable; + + if (!is_resolvable_asm_expansion (abfd, sec, contents, irel, link_info, + &is_reachable)) + continue; + + if (is_reachable) + { + Elf_Internal_Rela *l32r_irel; + r_reloc r_rel; + asection *target_sec; + xtensa_relax_info *target_relax_info; + + /* Mark the source_reloc for the L32R so that it will be + removed in compute_removed_literals(), along with the + associated literal. */ + l32r_irel = find_associated_l32r_irel (abfd, sec, contents, + irel, internal_relocs); + if (l32r_irel == NULL) + continue; + + r_reloc_init (&r_rel, abfd, l32r_irel, contents, sec_size); + + target_sec = r_reloc_get_section (&r_rel); + target_relax_info = get_xtensa_relax_info (target_sec); + + if (target_relax_info + && (target_relax_info->is_relaxable_literal_section + || target_relax_info->is_relaxable_asm_section)) + { + source_reloc *s_reloc; + + /* Search the source_relocs for the entry corresponding to + the l32r_irel. Note: The src_relocs array is not yet + sorted, but it wouldn't matter anyway because we're + searching by source offset instead of target offset. */ + s_reloc = find_source_reloc (target_relax_info->src_relocs, + target_relax_info->src_next, + sec, l32r_irel); + BFD_ASSERT (s_reloc); + s_reloc->is_null = TRUE; + } + + /* Convert this reloc to ASM_SIMPLIFY. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), + R_XTENSA_ASM_SIMPLIFY); + l32r_irel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE); + + pin_internal_relocs (sec, internal_relocs); + } + else + { + /* It is resolvable but doesn't reach. We resolve now + by eliminating the relocation -- the call will remain + expanded into L32R/CALLX. */ + irel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE); + pin_internal_relocs (sec, internal_relocs); + } + } + + error_return: + release_contents (sec, contents); + release_internal_relocs (sec, internal_relocs); + return ok; +} + + +/* Return TRUE if the asm expansion can be resolved. Generally it can + be resolved on a final link or when a partial link locates it in the + same section as the target. Set "is_reachable" flag if the target of + the call is within the range of a direct call, given the current VMA + for this section and the target section. */ + +bfd_boolean +is_resolvable_asm_expansion (abfd, sec, contents, irel, link_info, + is_reachable_p) + bfd *abfd; + asection *sec; + bfd_byte *contents; + Elf_Internal_Rela *irel; + struct bfd_link_info *link_info; + bfd_boolean *is_reachable_p; +{ + asection *target_sec; + bfd_vma target_offset; + r_reloc r_rel; + xtensa_opcode opcode, direct_call_opcode; + bfd_vma self_address; + bfd_vma dest_address; + bfd_boolean uses_l32r; + bfd_size_type sec_size; + + *is_reachable_p = FALSE; + + if (contents == NULL) + return FALSE; + + if (ELF32_R_TYPE (irel->r_info) != R_XTENSA_ASM_EXPAND) + return FALSE; + + sec_size = bfd_get_section_limit (abfd, sec); + opcode = get_expanded_call_opcode (contents + irel->r_offset, + sec_size - irel->r_offset, &uses_l32r); + /* Optimization of longcalls that use CONST16 is not yet implemented. */ + if (!uses_l32r) + return FALSE; + + direct_call_opcode = swap_callx_for_call_opcode (opcode); + if (direct_call_opcode == XTENSA_UNDEFINED) + return FALSE; + + /* Check and see that the target resolves. */ + r_reloc_init (&r_rel, abfd, irel, contents, sec_size); + if (!r_reloc_is_defined (&r_rel)) + return FALSE; + + target_sec = r_reloc_get_section (&r_rel); + target_offset = r_rel.target_offset; + + /* If the target is in a shared library, then it doesn't reach. This + isn't supposed to come up because the compiler should never generate + non-PIC calls on systems that use shared libraries, but the linker + shouldn't crash regardless. */ + if (!target_sec->output_section) + return FALSE; + + /* For relocatable sections, we can only simplify when the output + section of the target is the same as the output section of the + source. */ + if (link_info->relocatable + && (target_sec->output_section != sec->output_section + || is_reloc_sym_weak (abfd, irel))) + return FALSE; + + self_address = (sec->output_section->vma + + sec->output_offset + irel->r_offset + 3); + dest_address = (target_sec->output_section->vma + + target_sec->output_offset + target_offset); + + *is_reachable_p = pcrel_reloc_fits (direct_call_opcode, 0, + self_address, dest_address); + + if ((self_address >> CALL_SEGMENT_BITS) != + (dest_address >> CALL_SEGMENT_BITS)) + return FALSE; + + return TRUE; +} + + +static Elf_Internal_Rela * +find_associated_l32r_irel (abfd, sec, contents, other_irel, internal_relocs) + bfd *abfd; + asection *sec; + bfd_byte *contents; + Elf_Internal_Rela *other_irel; + Elf_Internal_Rela *internal_relocs; +{ + unsigned i; - /* Collect info on relocations against each relaxable section. */ - for (abfd = link_info->input_bfds; abfd != NULL; abfd = abfd->link_next) - for (sec = abfd->sections; sec != NULL; sec = sec->next) - { - if (!collect_source_relocs (abfd, sec, link_info)) - return FALSE; - } + for (i = 0; i < sec->reloc_count; i++) + { + Elf_Internal_Rela *irel = &internal_relocs[i]; - return TRUE; + if (irel == other_irel) + continue; + if (irel->r_offset != other_irel->r_offset) + continue; + if (is_l32r_relocation (abfd, sec, contents, irel)) + return irel; + } + + return NULL; } -/* Find all the literal sections that might be relaxed. The motivation - for this pass is that collect_source_relocs() needs to record _all_ - the relocations that target each relaxable section. That is - expensive and unnecessary unless the target section is actually going - to be relaxed. This pass identifies all such sections by checking if - they have L32Rs pointing to them. In the process, the total number - of relocations targeting each section is also counted so that we - know how much space to allocate for source_relocs against each - relaxable literal section. */ +/* The compute_text_actions function will build a list of potential + transformation actions for code in the extended basic block of each + longcall that is optimized to a direct call. From this list we + generate a set of actions to actually perform that optimizes for + space and, if not using size_opt, maintains branch target + alignments. -static bfd_boolean -find_relaxable_sections (abfd, sec, link_info, is_relaxable_p) + These actions to be performed are placed on a per-section list. + The actual changes are performed by relax_section() in the second + pass. */ + +bfd_boolean +compute_text_actions (abfd, sec, link_info) bfd *abfd; asection *sec; struct bfd_link_info *link_info; - bfd_boolean *is_relaxable_p; { - Elf_Internal_Rela *internal_relocs; + xtensa_relax_info *relax_info; bfd_byte *contents; + Elf_Internal_Rela *internal_relocs; bfd_boolean ok = TRUE; unsigned i; + property_table_entry *prop_table = 0; + int ptblsize = 0; + bfd_size_type sec_size; + static bfd_boolean no_insn_move = FALSE; + + if (no_insn_move) + return ok; + + /* Do nothing if the section contains no optimized longcalls. */ + relax_info = get_xtensa_relax_info (sec); + BFD_ASSERT (relax_info); + if (!relax_info->is_relaxable_asm_section) + return ok; internal_relocs = retrieve_internal_relocs (abfd, sec, link_info->keep_memory); - if (internal_relocs == NULL) - return ok; + if (internal_relocs) + qsort (internal_relocs, sec->reloc_count, sizeof (Elf_Internal_Rela), + internal_reloc_compare); + + sec_size = bfd_get_section_limit (abfd, sec); contents = retrieve_contents (abfd, sec, link_info->keep_memory); - if (contents == NULL && sec->size != 0) + if (contents == NULL && sec_size != 0) { ok = FALSE; goto error_return; } - for (i = 0; i < sec->reloc_count; i++) + ptblsize = xtensa_read_table_entries (abfd, sec, &prop_table, + XTENSA_PROP_SEC_NAME, FALSE); + if (ptblsize < 0) + { + ok = FALSE; + goto error_return; + } + + for (i = 0; i < sec->reloc_count; i++) { Elf_Internal_Rela *irel = &internal_relocs[i]; - r_reloc r_rel; - asection *target_sec; - xtensa_relax_info *target_relax_info; + bfd_vma r_offset; + property_table_entry *the_entry; + int ptbl_idx; + ebb_t *ebb; + ebb_constraint ebb_table; + bfd_size_type simplify_size; + + if (irel && ELF32_R_TYPE (irel->r_info) != R_XTENSA_ASM_SIMPLIFY) + continue; + r_offset = irel->r_offset; - r_reloc_init (&r_rel, abfd, irel); + simplify_size = get_asm_simplify_size (contents, sec_size, r_offset); + if (simplify_size == 0) + { + (*_bfd_error_handler) + (_("%B(%A+0x%lx): could not decode instruction for XTENSA_ASM_SIMPLIFY relocation; possible configuration mismatch"), + sec->owner, sec, r_offset); + continue; + } - target_sec = r_reloc_get_section (&r_rel); - target_relax_info = get_xtensa_relax_info (target_sec); - if (!target_relax_info) - continue; + /* If the instruction table is not around, then don't do this + relaxation. */ + the_entry = elf_xtensa_find_property_entry (prop_table, ptblsize, + sec->vma + irel->r_offset); + if (the_entry == NULL || XTENSA_NO_NOP_REMOVAL) + { + text_action_add (&relax_info->action_list, + ta_convert_longcall, sec, r_offset, + 0); + continue; + } + + /* If the next longcall happens to be at the same address as an + unreachable section of size 0, then skip forward. */ + ptbl_idx = the_entry - prop_table; + while ((the_entry->flags & XTENSA_PROP_UNREACHABLE) + && the_entry->size == 0 + && ptbl_idx + 1 < ptblsize + && (prop_table[ptbl_idx + 1].address + == prop_table[ptbl_idx].address)) + { + ptbl_idx++; + the_entry++; + } - /* Count relocations against the target section. */ - target_relax_info->src_count++; + if (the_entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM) + /* NO_REORDER is OK */ + continue; - if (is_literal_section (target_sec) - && is_l32r_relocation (sec, contents, irel) - && r_reloc_is_defined (&r_rel)) + init_ebb_constraint (&ebb_table); + ebb = &ebb_table.ebb; + init_ebb (ebb, sec, contents, sec_size, prop_table, ptblsize, + internal_relocs, sec->reloc_count); + ebb->start_offset = r_offset + simplify_size; + ebb->end_offset = r_offset + simplify_size; + ebb->start_ptbl_idx = ptbl_idx; + ebb->end_ptbl_idx = ptbl_idx; + ebb->start_reloc_idx = i; + ebb->end_reloc_idx = i; + + if (!extend_ebb_bounds (ebb) + || !compute_ebb_proposed_actions (&ebb_table) + || !compute_ebb_actions (&ebb_table) + || !check_section_ebb_pcrels_fit (abfd, sec, contents, + internal_relocs, &ebb_table) + || !check_section_ebb_reduces (&ebb_table)) { - /* Mark the target section as relaxable. */ - target_relax_info->is_relaxable_literal_section = TRUE; - *is_relaxable_p = TRUE; + /* If anything goes wrong or we get unlucky and something does + not fit, with our plan because of expansion between + critical branches, just convert to a NOP. */ + + text_action_add (&relax_info->action_list, + ta_convert_longcall, sec, r_offset, 0); + i = ebb_table.ebb.end_reloc_idx; + free_ebb_constraint (&ebb_table); + continue; } + + text_action_add_proposed (&relax_info->action_list, &ebb_table, sec); + + /* Update the index so we do not go looking at the relocations + we have already processed. */ + i = ebb_table.ebb.end_reloc_idx; + free_ebb_constraint (&ebb_table); } - error_return: +#if DEBUG + if (relax_info->action_list.head != NULL) + print_action_list (stderr, &relax_info->action_list); +#endif + +error_return: release_contents (sec, contents); release_internal_relocs (sec, internal_relocs); + if (prop_table) + free (prop_table); + return ok; } -/* Record _all_ the relocations that point to relaxable literal - sections, and get rid of ASM_EXPAND relocs by either converting them - to ASM_SIMPLIFY or by removing them. */ +/* Find all of the possible actions for an extended basic block. */ -static bfd_boolean -collect_source_relocs (abfd, sec, link_info) - bfd *abfd; - asection *sec; - struct bfd_link_info *link_info; +bfd_boolean +compute_ebb_proposed_actions (ebb_table) + ebb_constraint *ebb_table; { - Elf_Internal_Rela *internal_relocs; - bfd_byte *contents; - bfd_boolean ok = TRUE; - unsigned i; + const ebb_t *ebb = &ebb_table->ebb; + unsigned rel_idx = ebb->start_reloc_idx; + property_table_entry *entry, *start_entry, *end_entry; - internal_relocs = retrieve_internal_relocs (abfd, sec, - link_info->keep_memory); - if (internal_relocs == NULL) - return ok; + start_entry = &ebb->ptbl[ebb->start_ptbl_idx]; + end_entry = &ebb->ptbl[ebb->end_ptbl_idx]; - contents = retrieve_contents (abfd, sec, link_info->keep_memory); - if (contents == NULL && sec->size != 0) + for (entry = start_entry; entry <= end_entry; entry++) { - ok = FALSE; - goto error_return; - } + bfd_vma offset, start_offset, end_offset; + bfd_size_type insn_len; - /* Record relocations against relaxable literal sections. */ - for (i = 0; i < sec->reloc_count; i++) - { - Elf_Internal_Rela *irel = &internal_relocs[i]; - r_reloc r_rel; - asection *target_sec; - xtensa_relax_info *target_relax_info; + start_offset = entry->address - ebb->sec->vma; + end_offset = entry->address + entry->size - ebb->sec->vma; - r_reloc_init (&r_rel, abfd, irel); + if (entry == start_entry) + start_offset = ebb->start_offset; + if (entry == end_entry) + end_offset = ebb->end_offset; + offset = start_offset; - target_sec = r_reloc_get_section (&r_rel); - target_relax_info = get_xtensa_relax_info (target_sec); + if (offset == entry->address - ebb->sec->vma + && (entry->flags & XTENSA_PROP_INSN_BRANCH_TARGET) != 0) + { + enum ebb_target_enum align_type = EBB_DESIRE_TGT_ALIGN; + BFD_ASSERT (offset != end_offset); + if (offset == end_offset) + return FALSE; - if (target_relax_info - && target_relax_info->is_relaxable_literal_section) + insn_len = insn_decode_len (ebb->contents, ebb->content_length, + offset); + + /* Propose no actions for a section with an undecodable offset. */ + if (insn_len == 0) + { + (*_bfd_error_handler) + (_("%B(%A+0x%lx): could not decode instruction; possible configuration mismatch"), + ebb->sec->owner, ebb->sec, offset); + return FALSE; + } + if (check_branch_target_aligned_address (offset, insn_len)) + align_type = EBB_REQUIRE_TGT_ALIGN; + + ebb_propose_action (ebb_table, align_type, 0, + ta_none, offset, 0, TRUE); + } + + while (offset != end_offset) { + Elf_Internal_Rela *irel; xtensa_opcode opcode; - xtensa_operand opnd; - source_reloc *s_reloc; - int src_next; - src_next = target_relax_info->src_next++; - s_reloc = &target_relax_info->src_relocs[src_next]; + while (rel_idx < ebb->end_reloc_idx + && (ebb->relocs[rel_idx].r_offset < offset + || (ebb->relocs[rel_idx].r_offset == offset + && (ELF32_R_TYPE (ebb->relocs[rel_idx].r_info) + != R_XTENSA_ASM_SIMPLIFY)))) + rel_idx++; + + /* Check for longcall. */ + irel = &ebb->relocs[rel_idx]; + if (irel->r_offset == offset + && ELF32_R_TYPE (irel->r_info) == R_XTENSA_ASM_SIMPLIFY) + { + bfd_size_type simplify_size; - opcode = get_relocation_opcode (sec, contents, irel); - if (opcode == XTENSA_UNDEFINED) - opnd = NULL; - else - opnd = xtensa_get_operand (xtensa_default_isa, opcode, - get_relocation_opnd (irel)); + simplify_size = get_asm_simplify_size (ebb->contents, + ebb->content_length, + irel->r_offset); + if (simplify_size == 0) + { + (*_bfd_error_handler) + (_("%B(%A+0x%lx): could not decode instruction for XTENSA_ASM_SIMPLIFY relocation; possible configuration mismatch"), + ebb->sec->owner, ebb->sec, offset); + return FALSE; + } + + ebb_propose_action (ebb_table, EBB_NO_ALIGN, 0, + ta_convert_longcall, offset, 0, TRUE); + + offset += simplify_size; + continue; + } - init_source_reloc (s_reloc, sec, &r_rel, opnd); + insn_len = insn_decode_len (ebb->contents, ebb->content_length, + offset); + /* If the instruction is undecodable, then report an error. */ + if (insn_len == 0) + { + (*_bfd_error_handler) + (_("%B(%A+0x%lx): could not decode instruction; possible configuration mismatch"), + ebb->sec->owner, ebb->sec, offset); + return FALSE; + } + + if ((entry->flags & XTENSA_PROP_INSN_NO_DENSITY) == 0 + && (entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM) == 0 + && narrow_instruction (ebb->contents, ebb->content_length, + offset, FALSE)) + { + /* Add an instruction narrow action. */ + ebb_propose_action (ebb_table, EBB_NO_ALIGN, 0, + ta_narrow_insn, offset, 0, FALSE); + offset += insn_len; + continue; + } + if ((entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM) == 0 + && widen_instruction (ebb->contents, ebb->content_length, + offset, FALSE)) + { + /* Add an instruction widen action. */ + ebb_propose_action (ebb_table, EBB_NO_ALIGN, 0, + ta_widen_insn, offset, 0, FALSE); + offset += insn_len; + continue; + } + opcode = insn_decode_opcode (ebb->contents, ebb->content_length, + offset, 0); + if (xtensa_opcode_is_loop (xtensa_default_isa, opcode)) + { + /* Check for branch targets. */ + ebb_propose_action (ebb_table, EBB_REQUIRE_LOOP_ALIGN, 0, + ta_none, offset, 0, TRUE); + offset += insn_len; + continue; + } + + offset += insn_len; } } - /* Now get rid of ASM_EXPAND relocations. At this point, the - src_relocs array for the target literal section may still be - incomplete, but it must at least contain the entries for the L32R - relocations associated with ASM_EXPANDs because they were just - added in the preceding loop over the relocations. */ + if (ebb->ends_unreachable) + { + ebb_propose_action (ebb_table, EBB_NO_ALIGN, 0, + ta_fill, ebb->end_offset, 0, TRUE); + } - for (i = 0; i < sec->reloc_count; i++) + return TRUE; +} + + +/* After all of the information has collected about the + transformations possible in an EBB, compute the appropriate actions + here in compute_ebb_actions. We still must check later to make + sure that the actions do not break any relocations. The algorithm + used here is pretty greedy. Basically, it removes as many no-ops + as possible so that the end of the EBB has the same alignment + characteristics as the original. First, it uses narrowing, then + fill space at the end of the EBB, and finally widenings. If that + does not work, it tries again with one fewer no-op removed. The + optimization will only be performed if all of the branch targets + that were aligned before transformation are also aligned after the + transformation. + + When the size_opt flag is set, ignore the branch target alignments, + narrow all wide instructions, and remove all no-ops unless the end + of the EBB prevents it. */ + +bfd_boolean +compute_ebb_actions (ebb_table) + ebb_constraint *ebb_table; +{ + unsigned i = 0; + unsigned j; + int removed_bytes = 0; + ebb_t *ebb = &ebb_table->ebb; + unsigned seg_idx_start = 0; + unsigned seg_idx_end = 0; + + /* We perform this like the assembler relaxation algorithm: Start by + assuming all instructions are narrow and all no-ops removed; then + walk through.... */ + + /* For each segment of this that has a solid constraint, check to + see if there are any combinations that will keep the constraint. + If so, use it. */ + for (seg_idx_end = 0; seg_idx_end < ebb_table->action_count; seg_idx_end++) { - Elf_Internal_Rela *irel = &internal_relocs[i]; - bfd_boolean is_reachable; + bfd_boolean requires_text_end_align = FALSE; + unsigned longcall_count = 0; + unsigned longcall_convert_count = 0; + unsigned narrowable_count = 0; + unsigned narrowable_convert_count = 0; + unsigned widenable_count = 0; + unsigned widenable_convert_count = 0; - if (!is_resolvable_asm_expansion (abfd, sec, contents, irel, link_info, - &is_reachable)) - continue; + proposed_action *action = NULL; + int align = (1 << ebb_table->ebb.sec->alignment_power); - if (is_reachable) - { - Elf_Internal_Rela *l32r_irel; - r_reloc r_rel; - asection *target_sec; - xtensa_relax_info *target_relax_info; + seg_idx_start = seg_idx_end; - /* Mark the source_reloc for the L32R so that it will be - removed in remove_literals(), along with the associated - literal. */ - l32r_irel = find_associated_l32r_irel (sec, contents, - irel, internal_relocs); - if (l32r_irel == NULL) - continue; + for (i = seg_idx_start; i < ebb_table->action_count; i++) + { + action = &ebb_table->actions[i]; + if (action->action == ta_convert_longcall) + longcall_count++; + if (action->action == ta_narrow_insn) + narrowable_count++; + if (action->action == ta_widen_insn) + widenable_count++; + if (action->action == ta_fill) + break; + if (action->align_type == EBB_REQUIRE_LOOP_ALIGN) + break; + if (action->align_type == EBB_REQUIRE_TGT_ALIGN + && !elf32xtensa_size_opt) + break; + } + seg_idx_end = i; - r_reloc_init (&r_rel, abfd, l32r_irel); + if (seg_idx_end == ebb_table->action_count && !ebb->ends_unreachable) + requires_text_end_align = TRUE; - target_sec = r_reloc_get_section (&r_rel); - target_relax_info = get_xtensa_relax_info (target_sec); + if (elf32xtensa_size_opt && !requires_text_end_align + && action->align_type != EBB_REQUIRE_LOOP_ALIGN + && action->align_type != EBB_REQUIRE_TGT_ALIGN) + { + longcall_convert_count = longcall_count; + narrowable_convert_count = narrowable_count; + widenable_convert_count = 0; + } + else + { + /* There is a constraint. Convert the max number of longcalls. */ + narrowable_convert_count = 0; + longcall_convert_count = 0; + widenable_convert_count = 0; - if (target_relax_info - && target_relax_info->is_relaxable_literal_section) + for (j = 0; j < longcall_count; j++) { - source_reloc *s_reloc; + int removed = (longcall_count - j) * 3 & (align - 1); + unsigned desire_narrow = (align - removed) & (align - 1); + unsigned desire_widen = removed; + if (desire_narrow <= narrowable_count) + { + narrowable_convert_count = desire_narrow; + narrowable_convert_count += + (align * ((narrowable_count - narrowable_convert_count) + / align)); + longcall_convert_count = (longcall_count - j); + widenable_convert_count = 0; + break; + } + if (desire_widen <= widenable_count && !elf32xtensa_size_opt) + { + narrowable_convert_count = 0; + longcall_convert_count = longcall_count - j; + widenable_convert_count = desire_widen; + break; + } + } + } - /* Search the source_relocs for the entry corresponding to - the l32r_irel. Note: The src_relocs array is not yet - sorted, but it wouldn't matter anyway because we're - searching by source offset instead of target offset. */ - s_reloc = find_source_reloc (target_relax_info->src_relocs, - target_relax_info->src_next, - sec, l32r_irel); - BFD_ASSERT (s_reloc); - s_reloc->is_null = TRUE; + /* Now the number of conversions are saved. Do them. */ + for (i = seg_idx_start; i < seg_idx_end; i++) + { + action = &ebb_table->actions[i]; + switch (action->action) + { + case ta_convert_longcall: + if (longcall_convert_count != 0) + { + action->action = ta_remove_longcall; + action->do_action = TRUE; + action->removed_bytes += 3; + longcall_convert_count--; + } + break; + case ta_narrow_insn: + if (narrowable_convert_count != 0) + { + action->do_action = TRUE; + action->removed_bytes += 1; + narrowable_convert_count--; + } + break; + case ta_widen_insn: + if (widenable_convert_count != 0) + { + action->do_action = TRUE; + action->removed_bytes -= 1; + widenable_convert_count--; + } + break; + default: + break; } + } + } - /* Convert this reloc to ASM_SIMPLIFY. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_XTENSA_ASM_SIMPLIFY); - l32r_irel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE); + /* Now we move on to some local opts. Try to remove each of the + remaining longcalls. */ - pin_internal_relocs (sec, internal_relocs); - } - else + if (ebb_table->ebb.ends_section || ebb_table->ebb.ends_unreachable) + { + removed_bytes = 0; + for (i = 0; i < ebb_table->action_count; i++) { - /* It is resolvable but doesn't reach. We resolve now - by eliminating the relocation -- the call will remain - expanded into L32R/CALLX. */ - irel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE); - pin_internal_relocs (sec, internal_relocs); + int old_removed_bytes = removed_bytes; + proposed_action *action = &ebb_table->actions[i]; + + if (action->do_action && action->action == ta_convert_longcall) + { + bfd_boolean bad_alignment = FALSE; + removed_bytes += 3; + for (j = i + 1; j < ebb_table->action_count; j++) + { + proposed_action *new_action = &ebb_table->actions[j]; + bfd_vma offset = new_action->offset; + if (new_action->align_type == EBB_REQUIRE_TGT_ALIGN) + { + if (!check_branch_target_aligned + (ebb_table->ebb.contents, + ebb_table->ebb.content_length, + offset, offset - removed_bytes)) + { + bad_alignment = TRUE; + break; + } + } + if (new_action->align_type == EBB_REQUIRE_LOOP_ALIGN) + { + if (!check_loop_aligned (ebb_table->ebb.contents, + ebb_table->ebb.content_length, + offset, + offset - removed_bytes)) + { + bad_alignment = TRUE; + break; + } + } + if (new_action->action == ta_narrow_insn + && !new_action->do_action + && ebb_table->ebb.sec->alignment_power == 2) + { + /* Narrow an instruction and we are done. */ + new_action->do_action = TRUE; + new_action->removed_bytes += 1; + bad_alignment = FALSE; + break; + } + if (new_action->action == ta_widen_insn + && new_action->do_action + && ebb_table->ebb.sec->alignment_power == 2) + { + /* Narrow an instruction and we are done. */ + new_action->do_action = FALSE; + new_action->removed_bytes += 1; + bad_alignment = FALSE; + break; + } + } + if (!bad_alignment) + { + action->removed_bytes += 3; + action->action = ta_remove_longcall; + action->do_action = TRUE; + } + } + removed_bytes = old_removed_bytes; + if (action->do_action) + removed_bytes += action->removed_bytes; } } - error_return: - release_contents (sec, contents); - release_internal_relocs (sec, internal_relocs); - return ok; + removed_bytes = 0; + for (i = 0; i < ebb_table->action_count; ++i) + { + proposed_action *action = &ebb_table->actions[i]; + if (action->do_action) + removed_bytes += action->removed_bytes; + } + + if ((removed_bytes % (1 << ebb_table->ebb.sec->alignment_power)) != 0 + && ebb->ends_unreachable) + { + proposed_action *action; + int br; + int extra_space; + + BFD_ASSERT (ebb_table->action_count != 0); + action = &ebb_table->actions[ebb_table->action_count - 1]; + BFD_ASSERT (action->action == ta_fill); + BFD_ASSERT (ebb->ends_unreachable->flags & XTENSA_PROP_UNREACHABLE); + + extra_space = compute_fill_extra_space (ebb->ends_unreachable); + br = action->removed_bytes + removed_bytes + extra_space; + br = br & ((1 << ebb->sec->alignment_power ) - 1); + + action->removed_bytes = extra_space - br; + } + return TRUE; } -/* Return TRUE if the asm expansion can be resolved. Generally it can - be resolved on a final link or when a partial link locates it in the - same section as the target. Set "is_reachable" flag if the target of - the call is within the range of a direct call, given the current VMA - for this section and the target section. */ +/* Use check_section_ebb_pcrels_fit to make sure that all of the + relocations in a section will fit if a proposed set of actions + are performed. */ -bfd_boolean -is_resolvable_asm_expansion (abfd, sec, contents, irel, link_info, - is_reachable_p) +static bfd_boolean +check_section_ebb_pcrels_fit (abfd, sec, contents, internal_relocs, constraint) bfd *abfd; asection *sec; bfd_byte *contents; - Elf_Internal_Rela *irel; - struct bfd_link_info *link_info; - bfd_boolean *is_reachable_p; + Elf_Internal_Rela *internal_relocs; + const ebb_constraint *constraint; { - asection *target_sec; - bfd_vma target_offset; - r_reloc r_rel; - xtensa_opcode opcode, direct_call_opcode; - bfd_vma self_address; - bfd_vma dest_address; + unsigned i, j; + Elf_Internal_Rela *irel; + xtensa_relax_info *relax_info; - *is_reachable_p = FALSE; + relax_info = get_xtensa_relax_info (sec); - if (contents == NULL) - return FALSE; + for (i = 0; i < sec->reloc_count; i++) + { + r_reloc r_rel; + bfd_vma orig_self_offset, orig_target_offset; + bfd_vma self_offset, target_offset; + int r_type; + reloc_howto_type *howto; + int self_removed_bytes, target_removed_bytes; - if (ELF32_R_TYPE (irel->r_info) != R_XTENSA_ASM_EXPAND) - return FALSE; - - opcode = get_expanded_call_opcode (contents + irel->r_offset, - sec->size - irel->r_offset); - - direct_call_opcode = swap_callx_for_call_opcode (opcode); - if (direct_call_opcode == XTENSA_UNDEFINED) - return FALSE; + irel = &internal_relocs[i]; + r_type = ELF32_R_TYPE (irel->r_info); - /* Check and see that the target resolves. */ - r_reloc_init (&r_rel, abfd, irel); - if (!r_reloc_is_defined (&r_rel)) - return FALSE; + howto = &elf_howto_table[r_type]; + /* We maintain the required invariant: PC-relative relocations + that fit before linking must fit after linking. Thus we only + need to deal with relocations to the same section that are + PC-relative. */ + if (ELF32_R_TYPE (irel->r_info) == R_XTENSA_ASM_SIMPLIFY + || !howto->pc_relative) + continue; - target_sec = r_reloc_get_section (&r_rel); - target_offset = r_reloc_get_target_offset (&r_rel); + r_reloc_init (&r_rel, abfd, irel, contents, + bfd_get_section_limit (abfd, sec)); - /* If the target is in a shared library, then it doesn't reach. This - isn't supposed to come up because the compiler should never generate - non-PIC calls on systems that use shared libraries, but the linker - shouldn't crash regardless. */ - if (!target_sec->output_section) - return FALSE; - - /* For relocatable sections, we can only simplify when the output - section of the target is the same as the output section of the - source. */ - if (link_info->relocatable - && (target_sec->output_section != sec->output_section)) - return FALSE; + if (r_reloc_get_section (&r_rel) != sec) + continue; - self_address = (sec->output_section->vma - + sec->output_offset + irel->r_offset + 3); - dest_address = (target_sec->output_section->vma - + target_sec->output_offset + target_offset); - - *is_reachable_p = pcrel_reloc_fits - (xtensa_get_operand (xtensa_default_isa, direct_call_opcode, 0), - self_address, dest_address); + orig_self_offset = irel->r_offset; + orig_target_offset = r_rel.target_offset; - if ((self_address >> CALL_SEGMENT_BITS) != - (dest_address >> CALL_SEGMENT_BITS)) + self_offset = orig_self_offset; + target_offset = orig_target_offset; + + if (relax_info) + { + self_offset = offset_with_removed_text (&relax_info->action_list, + orig_self_offset); + target_offset = offset_with_removed_text (&relax_info->action_list, + orig_target_offset); + } + + self_removed_bytes = 0; + target_removed_bytes = 0; + + for (j = 0; j < constraint->action_count; ++j) + { + proposed_action *action = &constraint->actions[j]; + bfd_vma offset = action->offset; + int removed_bytes = action->removed_bytes; + if (offset < orig_self_offset + || (offset == orig_self_offset && action->action == ta_fill + && action->removed_bytes < 0)) + self_removed_bytes += removed_bytes; + if (offset < orig_target_offset + || (offset == orig_target_offset && action->action == ta_fill + && action->removed_bytes < 0)) + target_removed_bytes += removed_bytes; + } + self_offset -= self_removed_bytes; + target_offset -= target_removed_bytes; + + /* Try to encode it. Get the operand and check. */ + if (is_alt_relocation (ELF32_R_TYPE (irel->r_info))) + { + /* None of the current alternate relocs are PC-relative, + and only PC-relative relocs matter here. */ + } + else + { + xtensa_opcode opcode; + int opnum; + + opcode = get_relocation_opcode (abfd, sec, contents, irel); + if (opcode == XTENSA_UNDEFINED) + return FALSE; + + opnum = get_relocation_opnd (opcode, ELF32_R_TYPE (irel->r_info)); + if (opnum == XTENSA_UNDEFINED) + return FALSE; + + if (!pcrel_reloc_fits (opcode, opnum, self_offset, target_offset)) + return FALSE; + } + } + + return TRUE; +} + + +static bfd_boolean +check_section_ebb_reduces (constraint) + const ebb_constraint *constraint; +{ + int removed = 0; + unsigned i; + + for (i = 0; i < constraint->action_count; i++) + { + const proposed_action *action = &constraint->actions[i]; + if (action->do_action) + removed += action->removed_bytes; + } + if (removed < 0) return FALSE; return TRUE; } -static Elf_Internal_Rela * -find_associated_l32r_irel (sec, contents, other_irel, internal_relocs) +void +text_action_add_proposed (l, ebb_table, sec) + text_action_list *l; + const ebb_constraint *ebb_table; asection *sec; - bfd_byte *contents; - Elf_Internal_Rela *other_irel; - Elf_Internal_Rela *internal_relocs; { unsigned i; - for (i = 0; i < sec->reloc_count; i++) + for (i = 0; i < ebb_table->action_count; i++) { - Elf_Internal_Rela *irel = &internal_relocs[i]; + proposed_action *action = &ebb_table->actions[i]; - if (irel == other_irel) - continue; - if (irel->r_offset != other_irel->r_offset) + if (!action->do_action) continue; - if (is_l32r_relocation (sec, contents, irel)) - return irel; + switch (action->action) + { + case ta_remove_insn: + case ta_remove_longcall: + case ta_convert_longcall: + case ta_narrow_insn: + case ta_widen_insn: + case ta_fill: + case ta_remove_literal: + text_action_add (l, action->action, sec, action->offset, + action->removed_bytes); + break; + case ta_none: + break; + default: + BFD_ASSERT (0); + break; + } } +} - return NULL; + +int +compute_fill_extra_space (entry) + property_table_entry *entry; +{ + int fill_extra_space; + + if (!entry) + return 0; + + if ((entry->flags & XTENSA_PROP_UNREACHABLE) == 0) + return 0; + + fill_extra_space = entry->size; + if ((entry->flags & XTENSA_PROP_ALIGN) != 0) + { + /* Fill bytes for alignment: + (2**n)-1 - (addr + (2**n)-1) & (2**n -1) */ + int pow = GET_XTENSA_PROP_ALIGNMENT (entry->flags); + int nsm = (1 << pow) - 1; + bfd_vma addr = entry->address + entry->size; + bfd_vma align_fill = nsm - ((addr + nsm) & nsm); + fill_extra_space += align_fill; + } + return fill_extra_space; } + /* First relaxation pass. */ -/* If the section is relaxable (i.e., a literal section), check each - literal to see if it has the same value as another literal that has - already been seen, either in the current section or a previous one. - If so, add an entry to the per-section list of removed literals. The +/* If the section contains relaxable literals, check each literal to + see if it has the same value as another literal that has already + been seen, either in the current section or a previous one. If so, + add an entry to the per-section list of removed literals. The actual changes are deferred until the next pass. */ static bfd_boolean -remove_literals (abfd, sec, link_info, values) +compute_removed_literals (abfd, sec, link_info, values) bfd *abfd; asection *sec; struct bfd_link_info *link_info; @@ -4472,115 +7524,378 @@ remove_literals (abfd, sec, link_info, values) xtensa_relax_info *relax_info; bfd_byte *contents; Elf_Internal_Rela *internal_relocs; - source_reloc *src_relocs; - bfd_boolean final_static_link; + source_reloc *src_relocs, *rel; bfd_boolean ok = TRUE; - int i; + property_table_entry *prop_table = NULL; + int ptblsize; + int i, prev_i; + bfd_boolean last_loc_is_prev = FALSE; + bfd_vma last_target_offset = 0; + section_cache_t target_sec_cache; + bfd_size_type sec_size; + + init_section_cache (&target_sec_cache); /* Do nothing if it is not a relaxable literal section. */ relax_info = get_xtensa_relax_info (sec); BFD_ASSERT (relax_info); - if (!relax_info->is_relaxable_literal_section) return ok; internal_relocs = retrieve_internal_relocs (abfd, sec, link_info->keep_memory); + sec_size = bfd_get_section_limit (abfd, sec); contents = retrieve_contents (abfd, sec, link_info->keep_memory); - if (contents == NULL && sec->size != 0) + if (contents == NULL && sec_size != 0) { ok = FALSE; goto error_return; } - final_static_link = - (!link_info->relocatable - && !elf_hash_table (link_info)->dynamic_sections_created); - /* Sort the source_relocs by target offset. */ src_relocs = relax_info->src_relocs; qsort (src_relocs, relax_info->src_count, sizeof (source_reloc), source_reloc_compare); + qsort (internal_relocs, sec->reloc_count, sizeof (Elf_Internal_Rela), + internal_reloc_compare); + ptblsize = xtensa_read_table_entries (abfd, sec, &prop_table, + XTENSA_PROP_SEC_NAME, FALSE); + if (ptblsize < 0) + { + ok = FALSE; + goto error_return; + } + + prev_i = -1; for (i = 0; i < relax_info->src_count; i++) { - source_reloc *rel; Elf_Internal_Rela *irel = NULL; - literal_value val; - value_map *val_map; rel = &src_relocs[i]; + if (get_l32r_opcode () != rel->opcode) + continue; irel = get_irel_at_offset (sec, internal_relocs, rel->r_rel.target_offset); + /* If the relocation on this is not a simple R_XTENSA_32 or + R_XTENSA_PLT then do not consider it. This may happen when + the difference of two symbols is used in a literal. */ + if (irel && (ELF32_R_TYPE (irel->r_info) != R_XTENSA_32 + && ELF32_R_TYPE (irel->r_info) != R_XTENSA_PLT)) + continue; + /* If the target_offset for this relocation is the same as the previous relocation, then we've already considered whether the literal can be coalesced. Skip to the next one.... */ - if (i != 0 && (src_relocs[i-1].r_rel.target_offset - == rel->r_rel.target_offset)) + if (i != 0 && prev_i != -1 + && src_relocs[i-1].r_rel.target_offset == rel->r_rel.target_offset) continue; + prev_i = i; + + if (last_loc_is_prev && + last_target_offset + 4 != rel->r_rel.target_offset) + last_loc_is_prev = FALSE; /* Check if the relocation was from an L32R that is being removed because a CALLX was converted to a direct CALL, and check if there are no other relocations to the literal. */ - if (rel->is_null - && (i == relax_info->src_count - 1 - || (src_relocs[i+1].r_rel.target_offset - != rel->r_rel.target_offset))) + if (is_removable_literal (rel, i, src_relocs, relax_info->src_count)) { - /* Mark the unused literal so that it will be removed. */ - add_removed_literal (&relax_info->removed_list, &rel->r_rel, NULL); - - /* Zero out the relocation on this literal location. */ - if (irel) + if (!remove_dead_literal (abfd, sec, link_info, internal_relocs, + irel, rel, prop_table, ptblsize)) { - if (elf_hash_table (link_info)->dynamic_sections_created) - shrink_dynamic_reloc_sections (link_info, abfd, sec, irel); - - irel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE); + ok = FALSE; + goto error_return; } - + last_target_offset = rel->r_rel.target_offset; continue; } - /* Find the literal value. */ - r_reloc_init (&val.r_rel, abfd, irel); - BFD_ASSERT (rel->r_rel.target_offset < sec->size); - val.value = bfd_get_32 (abfd, contents + rel->r_rel.target_offset); - - /* Check if we've seen another literal with the same value. */ - val_map = get_cached_value (values, &val, final_static_link); - if (val_map != NULL) + if (!identify_literal_placement (abfd, sec, contents, link_info, + values, + &last_loc_is_prev, irel, + relax_info->src_count - i, rel, + prop_table, ptblsize, + &target_sec_cache, rel->is_abs_literal)) { - /* First check that THIS and all the other relocs to this - literal will FIT if we move them to the new address. */ + ok = FALSE; + goto error_return; + } + last_target_offset = rel->r_rel.target_offset; + } - if (relocations_reach (rel, relax_info->src_count - i, - &val_map->loc)) - { - /* Mark that the literal will be coalesced. */ - add_removed_literal (&relax_info->removed_list, - &rel->r_rel, &val_map->loc); - } - else +#if DEBUG + print_removed_literals (stderr, &relax_info->removed_list); + print_action_list (stderr, &relax_info->action_list); +#endif /* DEBUG */ + +error_return: + if (prop_table) free (prop_table); + clear_section_cache (&target_sec_cache); + + release_contents (sec, contents); + release_internal_relocs (sec, internal_relocs); + return ok; +} + + +static Elf_Internal_Rela * +get_irel_at_offset (sec, internal_relocs, offset) + asection *sec; + Elf_Internal_Rela *internal_relocs; + bfd_vma offset; +{ + unsigned i; + Elf_Internal_Rela *irel; + unsigned r_type; + Elf_Internal_Rela key; + + if (!internal_relocs) + return NULL; + + key.r_offset = offset; + irel = bsearch (&key, internal_relocs, sec->reloc_count, + sizeof (Elf_Internal_Rela), internal_reloc_matches); + if (!irel) + return NULL; + + /* bsearch does not guarantee which will be returned if there are + multiple matches. We need the first that is not an alignment. */ + i = irel - internal_relocs; + while (i > 0) + { + if (internal_relocs[i-1].r_offset != offset) + break; + i--; + } + for ( ; i < sec->reloc_count; i++) + { + irel = &internal_relocs[i]; + r_type = ELF32_R_TYPE (irel->r_info); + if (irel->r_offset == offset && r_type != R_XTENSA_NONE) + return irel; + } + + return NULL; +} + + +bfd_boolean +is_removable_literal (rel, i, src_relocs, src_count) + const source_reloc *rel; + int i; + const source_reloc *src_relocs; + int src_count; +{ + const source_reloc *curr_rel; + if (!rel->is_null) + return FALSE; + + for (++i; i < src_count; ++i) + { + curr_rel = &src_relocs[i]; + /* If all others have the same target offset.... */ + if (curr_rel->r_rel.target_offset != rel->r_rel.target_offset) + return TRUE; + + if (!curr_rel->is_null + && !xtensa_is_property_section (curr_rel->source_sec) + && !(curr_rel->source_sec->flags & SEC_DEBUGGING)) + return FALSE; + } + return TRUE; +} + + +bfd_boolean +remove_dead_literal (abfd, sec, link_info, internal_relocs, + irel, rel, prop_table, ptblsize) + bfd *abfd; + asection *sec; + struct bfd_link_info *link_info; + Elf_Internal_Rela *internal_relocs; + Elf_Internal_Rela *irel; + source_reloc *rel; + property_table_entry *prop_table; + int ptblsize; +{ + property_table_entry *entry; + xtensa_relax_info *relax_info; + + relax_info = get_xtensa_relax_info (sec); + if (!relax_info) + return FALSE; + + entry = elf_xtensa_find_property_entry (prop_table, ptblsize, + sec->vma + rel->r_rel.target_offset); + + /* Mark the unused literal so that it will be removed. */ + add_removed_literal (&relax_info->removed_list, &rel->r_rel, NULL); + + text_action_add (&relax_info->action_list, + ta_remove_literal, sec, rel->r_rel.target_offset, 4); + + /* If the section is 4-byte aligned, do not add fill. */ + if (sec->alignment_power > 2) + { + int fill_extra_space; + bfd_vma entry_sec_offset; + text_action *fa; + property_table_entry *the_add_entry; + int removed_diff; + + if (entry) + entry_sec_offset = entry->address - sec->vma + entry->size; + else + entry_sec_offset = rel->r_rel.target_offset + 4; + + /* If the literal range is at the end of the section, + do not add fill. */ + the_add_entry = elf_xtensa_find_property_entry (prop_table, ptblsize, + entry_sec_offset); + fill_extra_space = compute_fill_extra_space (the_add_entry); + + fa = find_fill_action (&relax_info->action_list, sec, entry_sec_offset); + removed_diff = compute_removed_action_diff (fa, sec, entry_sec_offset, + -4, fill_extra_space); + if (fa) + adjust_fill_action (fa, removed_diff); + else + text_action_add (&relax_info->action_list, + ta_fill, sec, entry_sec_offset, removed_diff); + } + + /* Zero out the relocation on this literal location. */ + if (irel) + { + if (elf_hash_table (link_info)->dynamic_sections_created) + shrink_dynamic_reloc_sections (link_info, abfd, sec, irel); + + irel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE); + pin_internal_relocs (sec, internal_relocs); + } + + /* Do not modify "last_loc_is_prev". */ + return TRUE; +} + + +bfd_boolean +identify_literal_placement (abfd, sec, contents, link_info, values, + last_loc_is_prev_p, irel, remaining_src_rels, + rel, prop_table, ptblsize, target_sec_cache, + is_abs_literal) + bfd *abfd; + asection *sec; + bfd_byte *contents; + struct bfd_link_info *link_info; + value_map_hash_table *values; + bfd_boolean *last_loc_is_prev_p; + Elf_Internal_Rela *irel; + int remaining_src_rels; + source_reloc *rel; + property_table_entry *prop_table; + int ptblsize; + section_cache_t *target_sec_cache; + bfd_boolean is_abs_literal; +{ + literal_value val; + value_map *val_map; + xtensa_relax_info *relax_info; + bfd_boolean literal_placed = FALSE; + r_reloc r_rel; + unsigned long value; + bfd_boolean final_static_link; + bfd_size_type sec_size; + + relax_info = get_xtensa_relax_info (sec); + if (!relax_info) + return FALSE; + + sec_size = bfd_get_section_limit (abfd, sec); + + final_static_link = + (!link_info->relocatable + && !elf_hash_table (link_info)->dynamic_sections_created); + + /* The placement algorithm first checks to see if the literal is + already in the value map. If so and the value map is reachable + from all uses, then the literal is moved to that location. If + not, then we identify the last location where a fresh literal was + placed. If the literal can be safely moved there, then we do so. + If not, then we assume that the literal is not to move and leave + the literal where it is, marking it as the last literal + location. */ + + /* Find the literal value. */ + value = 0; + r_reloc_init (&r_rel, abfd, irel, contents, sec_size); + if (!irel) + { + BFD_ASSERT (rel->r_rel.target_offset < sec_size); + value = bfd_get_32 (abfd, contents + rel->r_rel.target_offset); + } + init_literal_value (&val, &r_rel, value, is_abs_literal); + + /* Check if we've seen another literal with the same value that + is in the same output section. */ + val_map = value_map_get_cached_value (values, &val, final_static_link); + + if (val_map + && (r_reloc_get_section (&val_map->loc)->output_section + == sec->output_section) + && relocations_reach (rel, remaining_src_rels, &val_map->loc) + && coalesce_shared_literal (sec, rel, prop_table, ptblsize, val_map)) + { + /* No change to last_loc_is_prev. */ + literal_placed = TRUE; + } + + /* For relocatable links, do not try to move literals. To do it + correctly might increase the number of relocations in an input + section making the default relocatable linking fail. */ + if (!link_info->relocatable && !literal_placed + && values->has_last_loc && !(*last_loc_is_prev_p)) + { + asection *target_sec = r_reloc_get_section (&values->last_loc); + if (target_sec && target_sec->output_section == sec->output_section) + { + /* Increment the virtual offset. */ + r_reloc try_loc = values->last_loc; + try_loc.virtual_offset += 4; + + /* There is a last loc that was in the same output section. */ + if (relocations_reach (rel, remaining_src_rels, &try_loc) + && move_shared_literal (sec, link_info, rel, + prop_table, ptblsize, + &try_loc, &val, target_sec_cache)) { - /* Relocations do not reach -- do not remove this literal. */ - val_map->loc = rel->r_rel; + values->last_loc.virtual_offset += 4; + literal_placed = TRUE; + if (!val_map) + val_map = add_value_map (values, &val, &try_loc, + final_static_link); + else + val_map->loc = try_loc; } } + } + + if (!literal_placed) + { + /* Nothing worked, leave the literal alone but update the last loc. */ + values->has_last_loc = TRUE; + values->last_loc = rel->r_rel; + if (!val_map) + val_map = add_value_map (values, &val, &rel->r_rel, final_static_link); else - { - /* This is the first time we've seen this literal value. */ - BFD_ASSERT (sec == r_reloc_get_section (&rel->r_rel)); - add_value_map (values, &val, &rel->r_rel, final_static_link); - } + val_map->loc = rel->r_rel; + *last_loc_is_prev_p = TRUE; } -error_return: - release_contents (sec, contents); - release_internal_relocs (sec, internal_relocs); - return ok; + return TRUE; } @@ -4626,9 +7941,8 @@ relocations_reach (reloc, remaining_relocs, r_rel) != sec->output_section) return FALSE; - /* A NULL operand means it is not a PC-relative relocation, so - the literal can be moved anywhere. */ - if (reloc[i].opnd) + /* A literal with no PC-relative relocations can be moved anywhere. */ + if (reloc[i].opnd != -1) { /* Otherwise, check to see that it fits. */ source_address = (reloc[i].source_sec->output_section->vma @@ -4638,7 +7952,8 @@ relocations_reach (reloc, remaining_relocs, r_rel) + sec->output_offset + r_rel->target_offset); - if (!pcrel_reloc_fits (reloc[i].opnd, source_address, dest_address)) + if (!pcrel_reloc_fits (reloc[i].opcode, reloc[i].opnd, + source_address, dest_address)) return FALSE; } } @@ -4647,27 +7962,222 @@ relocations_reach (reloc, remaining_relocs, r_rel) } -/* WARNING: linear search here. If the relocation are in order by - address, we can use a faster binary search. ALSO, we assume that - there is only 1 non-NONE relocation per address. */ +/* Move a literal to another literal location because it is + the same as the other literal value. */ -static Elf_Internal_Rela * -get_irel_at_offset (sec, internal_relocs, offset) +static bfd_boolean +coalesce_shared_literal (sec, rel, prop_table, ptblsize, val_map) asection *sec; - Elf_Internal_Rela *internal_relocs; - bfd_vma offset; + source_reloc *rel; + property_table_entry *prop_table; + int ptblsize; + value_map *val_map; { - unsigned i; - if (!internal_relocs) - return NULL; - for (i = 0; i < sec->reloc_count; i++) + property_table_entry *entry; + text_action *fa; + property_table_entry *the_add_entry; + int removed_diff; + xtensa_relax_info *relax_info; + + relax_info = get_xtensa_relax_info (sec); + if (!relax_info) + return FALSE; + + entry = elf_xtensa_find_property_entry + (prop_table, ptblsize, sec->vma + rel->r_rel.target_offset); + if (entry && (entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM)) + return TRUE; + + /* Mark that the literal will be coalesced. */ + add_removed_literal (&relax_info->removed_list, &rel->r_rel, &val_map->loc); + + text_action_add (&relax_info->action_list, + ta_remove_literal, sec, rel->r_rel.target_offset, 4); + + /* If the section is 4-byte aligned, do not add fill. */ + if (sec->alignment_power > 2) { - Elf_Internal_Rela *irel = &internal_relocs[i]; - if (irel->r_offset == offset - && ELF32_R_TYPE (irel->r_info) != R_XTENSA_NONE) - return irel; + int fill_extra_space; + bfd_vma entry_sec_offset; + + if (entry) + entry_sec_offset = entry->address - sec->vma + entry->size; + else + entry_sec_offset = rel->r_rel.target_offset + 4; + + /* If the literal range is at the end of the section, + do not add fill. */ + fill_extra_space = 0; + the_add_entry = elf_xtensa_find_property_entry (prop_table, ptblsize, + entry_sec_offset); + if (the_add_entry && (the_add_entry->flags & XTENSA_PROP_UNREACHABLE)) + fill_extra_space = the_add_entry->size; + + fa = find_fill_action (&relax_info->action_list, sec, entry_sec_offset); + removed_diff = compute_removed_action_diff (fa, sec, entry_sec_offset, + -4, fill_extra_space); + if (fa) + adjust_fill_action (fa, removed_diff); + else + text_action_add (&relax_info->action_list, + ta_fill, sec, entry_sec_offset, removed_diff); } - return NULL; + + return TRUE; +} + + +/* Move a literal to another location. This may actually increase the + total amount of space used because of alignments so we need to do + this carefully. Also, it may make a branch go out of range. */ + +static bfd_boolean +move_shared_literal (sec, link_info, rel, prop_table, ptblsize, + target_loc, lit_value, target_sec_cache) + asection *sec; + struct bfd_link_info *link_info; + source_reloc *rel; + property_table_entry *prop_table; + int ptblsize; + const r_reloc *target_loc; + const literal_value *lit_value; + section_cache_t *target_sec_cache; +{ + property_table_entry *the_add_entry, *src_entry, *target_entry = NULL; + text_action *fa, *target_fa; + int removed_diff; + xtensa_relax_info *relax_info, *target_relax_info; + asection *target_sec; + ebb_t *ebb; + ebb_constraint ebb_table; + bfd_boolean relocs_fit; + + /* If this routine always returns FALSE, the literals that cannot be + coalesced will not be moved. */ + if (elf32xtensa_no_literal_movement) + return FALSE; + + relax_info = get_xtensa_relax_info (sec); + if (!relax_info) + return FALSE; + + target_sec = r_reloc_get_section (target_loc); + target_relax_info = get_xtensa_relax_info (target_sec); + + /* Literals to undefined sections may not be moved because they + must report an error. */ + if (bfd_is_und_section (target_sec)) + return FALSE; + + src_entry = elf_xtensa_find_property_entry + (prop_table, ptblsize, sec->vma + rel->r_rel.target_offset); + + if (!section_cache_section (target_sec_cache, target_sec, link_info)) + return FALSE; + + target_entry = elf_xtensa_find_property_entry + (target_sec_cache->ptbl, target_sec_cache->pte_count, + target_sec->vma + target_loc->target_offset); + + if (!target_entry) + return FALSE; + + /* Make sure that we have not broken any branches. */ + relocs_fit = FALSE; + + init_ebb_constraint (&ebb_table); + ebb = &ebb_table.ebb; + init_ebb (ebb, target_sec_cache->sec, target_sec_cache->contents, + target_sec_cache->content_length, + target_sec_cache->ptbl, target_sec_cache->pte_count, + target_sec_cache->relocs, target_sec_cache->reloc_count); + + /* Propose to add 4 bytes + worst-case alignment size increase to + destination. */ + ebb_propose_action (&ebb_table, EBB_NO_ALIGN, 0, + ta_fill, target_loc->target_offset, + -4 - (1 << target_sec->alignment_power), TRUE); + + /* Check all of the PC-relative relocations to make sure they still fit. */ + relocs_fit = check_section_ebb_pcrels_fit (target_sec->owner, target_sec, + target_sec_cache->contents, + target_sec_cache->relocs, + &ebb_table); + + if (!relocs_fit) + return FALSE; + + text_action_add_literal (&target_relax_info->action_list, + ta_add_literal, target_loc, lit_value, -4); + + if (target_sec->alignment_power > 2 && target_entry != src_entry) + { + /* May need to add or remove some fill to maintain alignment. */ + int fill_extra_space; + bfd_vma entry_sec_offset; + + entry_sec_offset = + target_entry->address - target_sec->vma + target_entry->size; + + /* If the literal range is at the end of the section, + do not add fill. */ + fill_extra_space = 0; + the_add_entry = + elf_xtensa_find_property_entry (target_sec_cache->ptbl, + target_sec_cache->pte_count, + entry_sec_offset); + if (the_add_entry && (the_add_entry->flags & XTENSA_PROP_UNREACHABLE)) + fill_extra_space = the_add_entry->size; + + target_fa = find_fill_action (&target_relax_info->action_list, + target_sec, entry_sec_offset); + removed_diff = compute_removed_action_diff (target_fa, target_sec, + entry_sec_offset, 4, + fill_extra_space); + if (target_fa) + adjust_fill_action (target_fa, removed_diff); + else + text_action_add (&target_relax_info->action_list, + ta_fill, target_sec, entry_sec_offset, removed_diff); + } + + /* Mark that the literal will be moved to the new location. */ + add_removed_literal (&relax_info->removed_list, &rel->r_rel, target_loc); + + /* Remove the literal. */ + text_action_add (&relax_info->action_list, + ta_remove_literal, sec, rel->r_rel.target_offset, 4); + + /* If the section is 4-byte aligned, do not add fill. */ + if (sec->alignment_power > 2 && target_entry != src_entry) + { + int fill_extra_space; + bfd_vma entry_sec_offset; + + if (src_entry) + entry_sec_offset = src_entry->address - sec->vma + src_entry->size; + else + entry_sec_offset = rel->r_rel.target_offset+4; + + /* If the literal range is at the end of the section, + do not add fill. */ + fill_extra_space = 0; + the_add_entry = elf_xtensa_find_property_entry (prop_table, ptblsize, + entry_sec_offset); + if (the_add_entry && (the_add_entry->flags & XTENSA_PROP_UNREACHABLE)) + fill_extra_space = the_add_entry->size; + + fa = find_fill_action (&relax_info->action_list, sec, entry_sec_offset); + removed_diff = compute_removed_action_diff (fa, sec, entry_sec_offset, + -4, fill_extra_space); + if (fa) + adjust_fill_action (fa, removed_diff); + else + text_action_add (&relax_info->action_list, + ta_fill, sec, entry_sec_offset, removed_diff); + } + + return TRUE; } @@ -4675,9 +8185,9 @@ get_irel_at_offset (sec, internal_relocs, offset) /* Modify all of the relocations to point to the right spot, and if this is a relaxable section, delete the unwanted literals and fix the - cooked_size. */ + section size. */ -bfd_boolean +bfd_boolean relax_section (abfd, sec, link_info) bfd *abfd; asection *sec; @@ -4688,10 +8198,17 @@ relax_section (abfd, sec, link_info) bfd_byte *contents; bfd_boolean ok = TRUE; unsigned i; + bfd_boolean rv = FALSE; + bfd_boolean virtual_action; + bfd_size_type sec_size; + sec_size = bfd_get_section_limit (abfd, sec); relax_info = get_xtensa_relax_info (sec); BFD_ASSERT (relax_info); + /* First translate any of the fixes that have been added already. */ + translate_section_fixes (sec); + /* Handle property sections (e.g., literal tables) specially. */ if (xtensa_is_property_section (sec)) { @@ -4699,118 +8216,522 @@ relax_section (abfd, sec, link_info) return relax_property_section (abfd, sec, link_info); } - internal_relocs = retrieve_internal_relocs (abfd, sec, - link_info->keep_memory); - contents = retrieve_contents (abfd, sec, link_info->keep_memory); - if (contents == NULL && sec->size != 0) - { - ok = FALSE; - goto error_return; - } + internal_relocs = retrieve_internal_relocs (abfd, sec, + link_info->keep_memory); + contents = retrieve_contents (abfd, sec, link_info->keep_memory); + if (contents == NULL && sec_size != 0) + { + ok = FALSE; + goto error_return; + } + + if (internal_relocs) + { + for (i = 0; i < sec->reloc_count; i++) + { + Elf_Internal_Rela *irel; + xtensa_relax_info *target_relax_info; + bfd_vma source_offset, old_source_offset; + r_reloc r_rel; + unsigned r_type; + asection *target_sec; + + /* Locally change the source address. + Translate the target to the new target address. + If it points to this section and has been removed, + NULLify it. + Write it back. */ + + irel = &internal_relocs[i]; + source_offset = irel->r_offset; + old_source_offset = source_offset; + + r_type = ELF32_R_TYPE (irel->r_info); + r_reloc_init (&r_rel, abfd, irel, contents, + bfd_get_section_limit (abfd, sec)); + + /* If this section could have changed then we may need to + change the relocation's offset. */ + + if (relax_info->is_relaxable_literal_section + || relax_info->is_relaxable_asm_section) + { + if (r_type != R_XTENSA_NONE + && find_removed_literal (&relax_info->removed_list, + irel->r_offset)) + { + /* Remove this relocation. */ + if (elf_hash_table (link_info)->dynamic_sections_created) + shrink_dynamic_reloc_sections (link_info, abfd, sec, irel); + irel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE); + irel->r_offset = offset_with_removed_text + (&relax_info->action_list, irel->r_offset); + pin_internal_relocs (sec, internal_relocs); + continue; + } + + if (r_type == R_XTENSA_ASM_SIMPLIFY) + { + text_action *action = + find_insn_action (&relax_info->action_list, + irel->r_offset); + if (action && (action->action == ta_convert_longcall + || action->action == ta_remove_longcall)) + { + bfd_reloc_status_type retval; + char *error_message = NULL; + + retval = contract_asm_expansion (contents, sec_size, + irel, &error_message); + if (retval != bfd_reloc_ok) + { + (*link_info->callbacks->reloc_dangerous) + (link_info, error_message, abfd, sec, + irel->r_offset); + goto error_return; + } + /* Update the action so that the code that moves + the contents will do the right thing. */ + if (action->action == ta_remove_longcall) + action->action = ta_remove_insn; + else + action->action = ta_none; + /* Refresh the info in the r_rel. */ + r_reloc_init (&r_rel, abfd, irel, contents, sec_size); + r_type = ELF32_R_TYPE (irel->r_info); + } + } + + source_offset = offset_with_removed_text + (&relax_info->action_list, irel->r_offset); + irel->r_offset = source_offset; + } + + /* If the target section could have changed then + we may need to change the relocation's target offset. */ + + target_sec = r_reloc_get_section (&r_rel); + target_relax_info = get_xtensa_relax_info (target_sec); + + if (target_relax_info + && (target_relax_info->is_relaxable_literal_section + || target_relax_info->is_relaxable_asm_section)) + { + r_reloc new_reloc; + reloc_bfd_fix *fix; + bfd_vma addend_displacement; + + translate_reloc (&r_rel, &new_reloc); + + if (r_type == R_XTENSA_DIFF8 + || r_type == R_XTENSA_DIFF16 + || r_type == R_XTENSA_DIFF32) + { + bfd_vma diff_value = 0, new_end_offset, diff_mask = 0; + + if (bfd_get_section_limit (abfd, sec) < old_source_offset) + { + (*link_info->callbacks->reloc_dangerous) + (link_info, _("invalid relocation address"), + abfd, sec, old_source_offset); + goto error_return; + } + + switch (r_type) + { + case R_XTENSA_DIFF8: + diff_value = + bfd_get_8 (abfd, &contents[old_source_offset]); + break; + case R_XTENSA_DIFF16: + diff_value = + bfd_get_16 (abfd, &contents[old_source_offset]); + break; + case R_XTENSA_DIFF32: + diff_value = + bfd_get_32 (abfd, &contents[old_source_offset]); + break; + } + + new_end_offset = offset_with_removed_text + (&target_relax_info->action_list, + r_rel.target_offset + diff_value); + diff_value = new_end_offset - new_reloc.target_offset; + + switch (r_type) + { + case R_XTENSA_DIFF8: + diff_mask = 0xff; + bfd_put_8 (abfd, diff_value, + &contents[old_source_offset]); + break; + case R_XTENSA_DIFF16: + diff_mask = 0xffff; + bfd_put_16 (abfd, diff_value, + &contents[old_source_offset]); + break; + case R_XTENSA_DIFF32: + diff_mask = 0xffffffff; + bfd_put_32 (abfd, diff_value, + &contents[old_source_offset]); + break; + } + + /* Check for overflow. */ + if ((diff_value & ~diff_mask) != 0) + { + (*link_info->callbacks->reloc_dangerous) + (link_info, _("overflow after relaxation"), + abfd, sec, old_source_offset); + goto error_return; + } + + pin_contents (sec, contents); + } + + /* FIXME: If the relocation still references a section in + the same input file, the relocation should be modified + directly instead of adding a "fix" record. */ + + addend_displacement = + new_reloc.target_offset + new_reloc.virtual_offset; + + fix = reloc_bfd_fix_init (sec, source_offset, r_type, 0, + r_reloc_get_section (&new_reloc), + addend_displacement, TRUE); + add_fix (sec, fix); + } + + pin_internal_relocs (sec, internal_relocs); + } + } + + if ((relax_info->is_relaxable_literal_section + || relax_info->is_relaxable_asm_section) + && relax_info->action_list.head) + { + /* Walk through the planned actions and build up a table + of move, copy and fill records. Use the move, copy and + fill records to perform the actions once. */ + + bfd_size_type size = sec->size; + int removed = 0; + bfd_size_type final_size, copy_size, orig_insn_size; + bfd_byte *scratch = NULL; + bfd_byte *dup_contents = NULL; + bfd_size_type orig_size = size; + bfd_vma orig_dot = 0; + bfd_vma orig_dot_copied = 0; /* Byte copied already from + orig dot in physical memory. */ + bfd_vma orig_dot_vo = 0; /* Virtual offset from orig_dot. */ + bfd_vma dup_dot = 0; + + text_action *action = relax_info->action_list.head; + + final_size = sec->size; + for (action = relax_info->action_list.head; action; + action = action->next) + { + final_size -= action->removed_bytes; + } + + scratch = (bfd_byte *) bfd_zmalloc (final_size); + dup_contents = (bfd_byte *) bfd_zmalloc (final_size); + + /* The dot is the current fill location. */ +#if DEBUG + print_action_list (stderr, &relax_info->action_list); +#endif + + for (action = relax_info->action_list.head; action; + action = action->next) + { + virtual_action = FALSE; + if (action->offset > orig_dot) + { + orig_dot += orig_dot_copied; + orig_dot_copied = 0; + orig_dot_vo = 0; + /* Out of the virtual world. */ + } + + if (action->offset > orig_dot) + { + copy_size = action->offset - orig_dot; + memmove (&dup_contents[dup_dot], &contents[orig_dot], copy_size); + orig_dot += copy_size; + dup_dot += copy_size; + BFD_ASSERT (action->offset == orig_dot); + } + else if (action->offset < orig_dot) + { + if (action->action == ta_fill + && action->offset - action->removed_bytes == orig_dot) + { + /* This is OK because the fill only effects the dup_dot. */ + } + else if (action->action == ta_add_literal) + { + /* TBD. Might need to handle this. */ + } + } + if (action->offset == orig_dot) + { + if (action->virtual_offset > orig_dot_vo) + { + if (orig_dot_vo == 0) + { + /* Need to copy virtual_offset bytes. Probably four. */ + copy_size = action->virtual_offset - orig_dot_vo; + memmove (&dup_contents[dup_dot], + &contents[orig_dot], copy_size); + orig_dot_copied = copy_size; + dup_dot += copy_size; + } + virtual_action = TRUE; + } + else + BFD_ASSERT (action->virtual_offset <= orig_dot_vo); + } + switch (action->action) + { + case ta_remove_literal: + case ta_remove_insn: + BFD_ASSERT (action->removed_bytes >= 0); + orig_dot += action->removed_bytes; + break; + + case ta_narrow_insn: + orig_insn_size = 3; + copy_size = 2; + memmove (scratch, &contents[orig_dot], orig_insn_size); + BFD_ASSERT (action->removed_bytes == 1); + rv = narrow_instruction (scratch, final_size, 0, TRUE); + BFD_ASSERT (rv); + memmove (&dup_contents[dup_dot], scratch, copy_size); + orig_dot += orig_insn_size; + dup_dot += copy_size; + break; + + case ta_fill: + if (action->removed_bytes >= 0) + orig_dot += action->removed_bytes; + else + { + /* Already zeroed in dup_contents. Just bump the + counters. */ + dup_dot += (-action->removed_bytes); + } + break; + + case ta_none: + BFD_ASSERT (action->removed_bytes == 0); + break; + + case ta_convert_longcall: + case ta_remove_longcall: + /* These will be removed or converted before we get here. */ + BFD_ASSERT (0); + break; + + case ta_widen_insn: + orig_insn_size = 2; + copy_size = 3; + memmove (scratch, &contents[orig_dot], orig_insn_size); + BFD_ASSERT (action->removed_bytes == -1); + rv = widen_instruction (scratch, final_size, 0, TRUE); + BFD_ASSERT (rv); + memmove (&dup_contents[dup_dot], scratch, copy_size); + orig_dot += orig_insn_size; + dup_dot += copy_size; + break; + + case ta_add_literal: + orig_insn_size = 0; + copy_size = 4; + BFD_ASSERT (action->removed_bytes == -4); + /* TBD -- place the literal value here and insert + into the table. */ + memset (&dup_contents[dup_dot], 0, 4); + pin_internal_relocs (sec, internal_relocs); + pin_contents (sec, contents); + + if (!move_literal (abfd, link_info, sec, dup_dot, dup_contents, + relax_info, &internal_relocs, &action->value)) + goto error_return; + + if (virtual_action) + orig_dot_vo += copy_size; + + orig_dot += orig_insn_size; + dup_dot += copy_size; + break; + + default: + /* Not implemented yet. */ + BFD_ASSERT (0); + break; + } + + size -= action->removed_bytes; + removed += action->removed_bytes; + BFD_ASSERT (dup_dot <= final_size); + BFD_ASSERT (orig_dot <= orig_size); + } + + orig_dot += orig_dot_copied; + orig_dot_copied = 0; + + if (orig_dot != orig_size) + { + copy_size = orig_size - orig_dot; + BFD_ASSERT (orig_size > orig_dot); + BFD_ASSERT (dup_dot + copy_size == final_size); + memmove (&dup_contents[dup_dot], &contents[orig_dot], copy_size); + orig_dot += copy_size; + dup_dot += copy_size; + } + BFD_ASSERT (orig_size == orig_dot); + BFD_ASSERT (final_size == dup_dot); + + /* Move the dup_contents back. */ + if (final_size > orig_size) + { + /* Contents need to be reallocated. Swap the dup_contents into + contents. */ + sec->contents = dup_contents; + free (contents); + contents = dup_contents; + pin_contents (sec, contents); + } + else + { + BFD_ASSERT (final_size <= orig_size); + memset (contents, 0, orig_size); + memcpy (contents, dup_contents, final_size); + free (dup_contents); + } + free (scratch); + pin_contents (sec, contents); + + sec->size = final_size; + } + + error_return: + release_internal_relocs (sec, internal_relocs); + release_contents (sec, contents); + return ok; +} + + +static bfd_boolean +translate_section_fixes (sec) + asection *sec; +{ + xtensa_relax_info *relax_info; + reloc_bfd_fix *r; + + relax_info = get_xtensa_relax_info (sec); + if (!relax_info) + return TRUE; + + for (r = relax_info->fix_list; r != NULL; r = r->next) + if (!translate_reloc_bfd_fix (r)) + return FALSE; - if (internal_relocs) - { - for (i = 0; i < sec->reloc_count; i++) - { - Elf_Internal_Rela *irel; - xtensa_relax_info *target_relax_info; - bfd_vma source_offset; - r_reloc r_rel; - unsigned r_type; - asection *target_sec; + return TRUE; +} - /* Locally change the source address. - Translate the target to the new target address. - If it points to this section and has been removed, - NULLify it. - Write it back. */ - irel = &internal_relocs[i]; - source_offset = irel->r_offset; +/* Translate a fix given the mapping in the relax info for the target + section. If it has already been translated, no work is required. */ - r_type = ELF32_R_TYPE (irel->r_info); - r_reloc_init (&r_rel, abfd, irel); - - if (relax_info->is_relaxable_literal_section) - { - if (r_type != R_XTENSA_NONE - && find_removed_literal (&relax_info->removed_list, - irel->r_offset)) - { - /* Remove this relocation. */ - if (elf_hash_table (link_info)->dynamic_sections_created) - shrink_dynamic_reloc_sections (link_info, abfd, sec, irel); - irel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE); - irel->r_offset = offset_with_removed_literals - (&relax_info->removed_list, irel->r_offset); - continue; - } - source_offset = - offset_with_removed_literals (&relax_info->removed_list, - irel->r_offset); - irel->r_offset = source_offset; - } +static bfd_boolean +translate_reloc_bfd_fix (fix) + reloc_bfd_fix *fix; +{ + reloc_bfd_fix new_fix; + asection *sec; + xtensa_relax_info *relax_info; + removed_literal *removed; + bfd_vma new_offset, target_offset; - target_sec = r_reloc_get_section (&r_rel); - target_relax_info = get_xtensa_relax_info (target_sec); + if (fix->translated) + return TRUE; - if (target_relax_info - && target_relax_info->is_relaxable_literal_section) - { - r_reloc new_rel; - reloc_bfd_fix *fix; + sec = fix->target_sec; + target_offset = fix->target_offset; - translate_reloc (&r_rel, &new_rel); + relax_info = get_xtensa_relax_info (sec); + if (!relax_info) + { + fix->translated = TRUE; + return TRUE; + } - /* FIXME: If the relocation still references a section in - the same input file, the relocation should be modified - directly instead of adding a "fix" record. */ + new_fix = *fix; - fix = reloc_bfd_fix_init (sec, source_offset, r_type, 0, - r_reloc_get_section (&new_rel), - new_rel.target_offset); - add_fix (sec, fix); - } + /* The fix does not need to be translated if the section cannot change. */ + if (!relax_info->is_relaxable_literal_section + && !relax_info->is_relaxable_asm_section) + { + fix->translated = TRUE; + return TRUE; + } - pin_internal_relocs (sec, internal_relocs); - } + /* If the literal has been moved and this relocation was on an + opcode, then the relocation should move to the new literal + location. Otherwise, the relocation should move within the + section. */ + + removed = FALSE; + if (is_operand_relocation (fix->src_type)) + { + /* Check if the original relocation is against a literal being + removed. */ + removed = find_removed_literal (&relax_info->removed_list, + target_offset); } - if (relax_info->is_relaxable_literal_section) + if (removed) { - /* Walk through the contents and delete literals that are not needed - anymore. */ + asection *new_sec; - unsigned long size = sec->size; - unsigned long removed = 0; + /* The fact that there is still a relocation to this literal indicates + that the literal is being coalesced, not simply removed. */ + BFD_ASSERT (removed->to.abfd != NULL); - removed_literal *reloc = relax_info->removed_list.head; - for (; reloc; reloc = reloc->next) + /* This was moved to some other address (possibly another section). */ + new_sec = r_reloc_get_section (&removed->to); + if (new_sec != sec) { - unsigned long upper = sec->size; - bfd_vma start = reloc->from.target_offset + 4; - if (reloc->next) - upper = reloc->next->from.target_offset; - if (upper - start != 0) + sec = new_sec; + relax_info = get_xtensa_relax_info (sec); + if (!relax_info || + (!relax_info->is_relaxable_literal_section + && !relax_info->is_relaxable_asm_section)) { - BFD_ASSERT (start <= upper); - memmove (contents + start - removed - 4, - contents + start, - upper - start ); - pin_contents (sec, contents); + target_offset = removed->to.target_offset; + new_fix.target_sec = new_sec; + new_fix.target_offset = target_offset; + new_fix.translated = TRUE; + *fix = new_fix; + return TRUE; } - removed += 4; - size -= 4; } - - /* Change the section size. */ - sec->size = size; + target_offset = removed->to.target_offset; + new_fix.target_sec = new_sec; } - - error_return: - release_internal_relocs (sec, internal_relocs); - release_contents (sec, contents); - return ok; + + /* The target address may have been moved within its section. */ + new_offset = offset_with_removed_text (&relax_info->action_list, + target_offset); + + new_fix.target_offset = new_offset; + new_fix.target_offset = new_offset; + new_fix.translated = TRUE; + *fix = new_fix; + return TRUE; } @@ -4824,7 +8745,7 @@ translate_reloc (orig_rel, new_rel) asection *sec; xtensa_relax_info *relax_info; removed_literal *removed; - unsigned long new_offset; + bfd_vma new_offset, target_offset, removed_bytes; *new_rel = *orig_rel; @@ -4835,13 +8756,21 @@ translate_reloc (orig_rel, new_rel) relax_info = get_xtensa_relax_info (sec); BFD_ASSERT (relax_info); - if (!relax_info->is_relaxable_literal_section) + if (!relax_info->is_relaxable_literal_section + && !relax_info->is_relaxable_asm_section) return; - /* Check if the original relocation is against a literal being removed. */ - removed = find_removed_literal (&relax_info->removed_list, - orig_rel->target_offset); - if (removed) + target_offset = orig_rel->target_offset; + + removed = FALSE; + if (is_operand_relocation (ELF32_R_TYPE (orig_rel->rela.r_info))) + { + /* Check if the original relocation is against a literal being + removed. */ + removed = find_removed_literal (&relax_info->removed_list, + target_offset); + } + if (removed && removed->to.abfd) { asection *new_sec; @@ -4849,25 +8778,30 @@ translate_reloc (orig_rel, new_rel) that the literal is being coalesced, not simply removed. */ BFD_ASSERT (removed->to.abfd != NULL); - /* This was moved to some other address (possibly in another section). */ + /* This was moved to some other address + (possibly in another section). */ *new_rel = removed->to; new_sec = r_reloc_get_section (new_rel); - if (new_sec != sec) + if (new_sec != sec) { sec = new_sec; relax_info = get_xtensa_relax_info (sec); - if (!relax_info || !relax_info->is_relaxable_literal_section) + if (!relax_info + || (!relax_info->is_relaxable_literal_section + && !relax_info->is_relaxable_asm_section)) return; } + target_offset = new_rel->target_offset; } /* ...and the target address may have been moved within its section. */ - new_offset = offset_with_removed_literals (&relax_info->removed_list, - new_rel->target_offset); + new_offset = offset_with_removed_text (&relax_info->action_list, + target_offset); /* Modify the offset and addend. */ + removed_bytes = target_offset - new_offset; new_rel->target_offset = new_offset; - new_rel->rela.r_addend += (new_offset - new_rel->target_offset); + new_rel->rela.r_addend -= removed_bytes; } @@ -4977,12 +8911,149 @@ shrink_dynamic_reloc_sections (info, abfd, input_section, rel) } +/* Take an r_rel and move it to another section. This usually + requires extending the interal_relocation array and pinning it. If + the original r_rel is from the same BFD, we can complete this here. + Otherwise, we add a fix record to let the final link fix the + appropriate address. Contents and internal relocations for the + section must be pinned after calling this routine. */ + +static bfd_boolean +move_literal (abfd, link_info, sec, offset, contents, relax_info, + internal_relocs_p, lit) + bfd *abfd; + struct bfd_link_info *link_info; + asection *sec; + bfd_vma offset; + bfd_byte *contents; + xtensa_relax_info *relax_info; + Elf_Internal_Rela **internal_relocs_p; + const literal_value *lit; +{ + Elf_Internal_Rela *new_relocs = NULL; + size_t new_relocs_count = 0; + Elf_Internal_Rela this_rela; + const r_reloc *r_rel; + + r_rel = &lit->r_rel; + BFD_ASSERT (elf_section_data (sec)->relocs == *internal_relocs_p); + + if (r_reloc_is_const (r_rel)) + bfd_put_32 (abfd, lit->value, contents + offset); + else + { + int r_type; + unsigned i; + asection *target_sec; + reloc_bfd_fix *fix; + unsigned insert_at; + + r_type = ELF32_R_TYPE (r_rel->rela.r_info); + target_sec = r_reloc_get_section (r_rel); + + /* This is the difficult case. We have to create a fix up. */ + this_rela.r_offset = offset; + this_rela.r_info = ELF32_R_INFO (0, r_type); + this_rela.r_addend = + r_rel->target_offset - r_reloc_get_target_offset (r_rel); + bfd_put_32 (abfd, lit->value, contents + offset); + + /* Currently, we cannot move relocations during a relocatable link. */ + BFD_ASSERT (!link_info->relocatable); + fix = reloc_bfd_fix_init (sec, offset, r_type, r_rel->abfd, + r_reloc_get_section (r_rel), + r_rel->target_offset + r_rel->virtual_offset, + FALSE); + /* We also need to mark that relocations are needed here. */ + sec->flags |= SEC_RELOC; + + translate_reloc_bfd_fix (fix); + /* This fix has not yet been translated. */ + add_fix (sec, fix); + + /* Add the relocation. If we have already allocated our own + space for the relocations and we have room for more, then use + it. Otherwise, allocate new space and move the literals. */ + insert_at = sec->reloc_count; + for (i = 0; i < sec->reloc_count; ++i) + { + if (this_rela.r_offset < (*internal_relocs_p)[i].r_offset) + { + insert_at = i; + break; + } + } + + if (*internal_relocs_p != relax_info->allocated_relocs + || sec->reloc_count + 1 > relax_info->allocated_relocs_count) + { + BFD_ASSERT (relax_info->allocated_relocs == NULL + || sec->reloc_count == relax_info->relocs_count); + + if (relax_info->allocated_relocs_count == 0) + new_relocs_count = (sec->reloc_count + 2) * 2; + else + new_relocs_count = (relax_info->allocated_relocs_count + 2) * 2; + + new_relocs = (Elf_Internal_Rela *) + bfd_zmalloc (sizeof (Elf_Internal_Rela) * (new_relocs_count)); + if (!new_relocs) + return FALSE; + + /* We could handle this more quickly by finding the split point. */ + if (insert_at != 0) + memcpy (new_relocs, *internal_relocs_p, + insert_at * sizeof (Elf_Internal_Rela)); + + new_relocs[insert_at] = this_rela; + + if (insert_at != sec->reloc_count) + memcpy (new_relocs + insert_at + 1, + (*internal_relocs_p) + insert_at, + (sec->reloc_count - insert_at) + * sizeof (Elf_Internal_Rela)); + + if (*internal_relocs_p != relax_info->allocated_relocs) + { + /* The first time we re-allocate, we can only free the + old relocs if they were allocated with bfd_malloc. + This is not true when keep_memory is in effect. */ + if (!link_info->keep_memory) + free (*internal_relocs_p); + } + else + free (*internal_relocs_p); + relax_info->allocated_relocs = new_relocs; + relax_info->allocated_relocs_count = new_relocs_count; + elf_section_data (sec)->relocs = new_relocs; + sec->reloc_count++; + relax_info->relocs_count = sec->reloc_count; + *internal_relocs_p = new_relocs; + } + else + { + if (insert_at != sec->reloc_count) + { + unsigned idx; + for (idx = sec->reloc_count; idx > insert_at; idx--) + (*internal_relocs_p)[idx] = (*internal_relocs_p)[idx-1]; + } + (*internal_relocs_p)[insert_at] = this_rela; + sec->reloc_count++; + if (relax_info->allocated_relocs) + relax_info->relocs_count = sec->reloc_count; + } + } + return TRUE; +} + + /* This is similar to relax_section except that when a target is moved, we shift addresses up. We also need to modify the size. This algorithm does NOT allow for relocations into the middle of the property sections. */ -static bfd_boolean +static bfd_boolean relax_property_section (abfd, sec, link_info) bfd *abfd; asection *sec; @@ -4992,25 +9063,36 @@ relax_property_section (abfd, sec, link_info) bfd_byte *contents; unsigned i, nexti; bfd_boolean ok = TRUE; + bfd_boolean is_full_prop_section; + size_t last_zfill_target_offset = 0; + asection *last_zfill_target_sec = NULL; + bfd_size_type sec_size; + sec_size = bfd_get_section_limit (abfd, sec); internal_relocs = retrieve_internal_relocs (abfd, sec, link_info->keep_memory); contents = retrieve_contents (abfd, sec, link_info->keep_memory); - if (contents == NULL && sec->size != 0) + if (contents == NULL && sec_size != 0) { ok = FALSE; goto error_return; } - if (internal_relocs) + is_full_prop_section = + ((strcmp (sec->name, XTENSA_PROP_SEC_NAME) == 0) + || (strncmp (sec->name, ".gnu.linkonce.prop.", + sizeof ".gnu.linkonce.prop." - 1) == 0)); + + if (internal_relocs) { - for (i = 0; i < sec->reloc_count; i++) + for (i = 0; i < sec->reloc_count; i++) { Elf_Internal_Rela *irel; xtensa_relax_info *target_relax_info; - r_reloc r_rel; unsigned r_type; asection *target_sec; + literal_value val; + bfd_byte *size_p, *flags_p; /* Locally change the source address. Translate the target to the new target address. @@ -5023,42 +9105,88 @@ relax_property_section (abfd, sec, link_info) if (r_type == R_XTENSA_NONE) continue; - r_reloc_init (&r_rel, abfd, irel); + /* Find the literal value. */ + r_reloc_init (&val.r_rel, abfd, irel, contents, sec_size); + size_p = &contents[irel->r_offset + 4]; + flags_p = NULL; + if (is_full_prop_section) + { + flags_p = &contents[irel->r_offset + 8]; + BFD_ASSERT (irel->r_offset + 12 <= sec_size); + } + else + BFD_ASSERT (irel->r_offset + 8 <= sec_size); - target_sec = r_reloc_get_section (&r_rel); + target_sec = r_reloc_get_section (&val.r_rel); target_relax_info = get_xtensa_relax_info (target_sec); if (target_relax_info - && target_relax_info->is_relaxable_literal_section) + && (target_relax_info->is_relaxable_literal_section + || target_relax_info->is_relaxable_asm_section )) { /* Translate the relocation's destination. */ - bfd_vma new_offset; - bfd_vma new_end_offset; - bfd_byte *size_p; + bfd_vma new_offset, new_end_offset; long old_size, new_size; - new_offset = - offset_with_removed_literals (&target_relax_info->removed_list, - r_rel.target_offset); + new_offset = offset_with_removed_text + (&target_relax_info->action_list, val.r_rel.target_offset); /* Assert that we are not out of bounds. */ - size_p = &contents[irel->r_offset + 4]; - old_size = bfd_get_32 (abfd, &contents[irel->r_offset + 4]); + old_size = bfd_get_32 (abfd, size_p); + + if (old_size == 0) + { + /* Only the first zero-sized unreachable entry is + allowed to expand. In this case the new offset + should be the offset before the fill and the new + size is the expansion size. For other zero-sized + entries the resulting size should be zero with an + offset before or after the fill address depending + on whether the expanding unreachable entry + preceeds it. */ + if (last_zfill_target_sec + && last_zfill_target_sec == target_sec + && last_zfill_target_offset == val.r_rel.target_offset) + new_end_offset = new_offset; + else + { + new_end_offset = new_offset; + new_offset = offset_with_removed_text_before_fill + (&target_relax_info->action_list, + val.r_rel.target_offset); + + /* If it is not unreachable and we have not yet + seen an unreachable at this address, place it + before the fill address. */ + if (!flags_p + || (bfd_get_32 (abfd, flags_p) + & XTENSA_PROP_UNREACHABLE) == 0) + new_end_offset = new_offset; + else + { + last_zfill_target_sec = target_sec; + last_zfill_target_offset = val.r_rel.target_offset; + } + } + } + else + { + new_end_offset = offset_with_removed_text_before_fill + (&target_relax_info->action_list, + val.r_rel.target_offset + old_size); + } - new_end_offset = - offset_with_removed_literals (&target_relax_info->removed_list, - r_rel.target_offset + old_size); - new_size = new_end_offset - new_offset; + if (new_size != old_size) { bfd_put_32 (abfd, new_size, size_p); pin_contents (sec, contents); } - - if (new_offset != r_rel.target_offset) + + if (new_offset != val.r_rel.target_offset) { - bfd_vma diff = new_offset - r_rel.target_offset; + bfd_vma diff = new_offset - val.r_rel.target_offset; irel->r_addend += diff; pin_internal_relocs (sec, internal_relocs); } @@ -5070,12 +9198,22 @@ relax_property_section (abfd, sec, link_info) finish_dynamic_sections() but at that point it's too late to reclaim the space in the output section, so we do this twice. */ - if (internal_relocs) + if (internal_relocs && (!link_info->relocatable + || strcmp (sec->name, XTENSA_LIT_SEC_NAME) == 0)) { Elf_Internal_Rela *last_irel = NULL; int removed_bytes = 0; bfd_vma offset, last_irel_offset; bfd_vma section_size; + bfd_size_type entry_size; + flagword predef_flags; + + if (is_full_prop_section) + entry_size = 12; + else + entry_size = 8; + + predef_flags = xtensa_get_property_predef_flags (sec); /* Walk over memory and irels at the same time. This REQUIRES that the internal_relocs be sorted by offset. */ @@ -5088,13 +9226,14 @@ relax_property_section (abfd, sec, link_info) last_irel_offset = (bfd_vma) -1; section_size = sec->size; - BFD_ASSERT (section_size % 8 == 0); + BFD_ASSERT (section_size % entry_size == 0); - for (offset = 0; offset < section_size; offset += 8) + for (offset = 0; offset < section_size; offset += entry_size) { Elf_Internal_Rela *irel, *next_irel; bfd_vma bytes_to_remove, size, actual_offset; bfd_boolean remove_this_irel; + flagword flags; irel = NULL; next_irel = NULL; @@ -5132,28 +9271,38 @@ relax_property_section (abfd, sec, link_info) actual_offset = offset - removed_bytes; size = bfd_get_32 (abfd, &contents[actual_offset + 4]); + if (is_full_prop_section) + flags = bfd_get_32 (abfd, &contents[actual_offset + 8]); + else + flags = predef_flags; + /* Check that the irels are sorted by offset, with only one per address. */ BFD_ASSERT (!irel || (int) irel->r_offset > (int) last_irel_offset); BFD_ASSERT (!next_irel || next_irel->r_offset > irel->r_offset); - /* Make sure there isn't a reloc on the size field. */ - if (irel && irel->r_offset == offset + 4) + /* Make sure there aren't relocs on the size or flag fields. */ + if ((irel && irel->r_offset == offset + 4) + || (is_full_prop_section + && irel && irel->r_offset == offset + 8)) { irel->r_offset -= removed_bytes; last_irel_offset = irel->r_offset; } - else if (next_irel && next_irel->r_offset == offset + 4) + else if (next_irel && (next_irel->r_offset == offset + 4 + || (is_full_prop_section + && next_irel->r_offset == offset + 8))) { nexti += 1; irel->r_offset -= removed_bytes; next_irel->r_offset -= removed_bytes; last_irel_offset = next_irel->r_offset; } - else if (size == 0) + else if (size == 0 && (flags & XTENSA_PROP_ALIGN) == 0 + && (flags & XTENSA_PROP_UNREACHABLE) == 0) { - /* Always remove entries with zero size. */ - bytes_to_remove = 8; + /* Always remove entries with zero size and no alignment. */ + bytes_to_remove = entry_size; if (irel && irel->r_offset == offset) { remove_this_irel = TRUE; @@ -5168,23 +9317,32 @@ relax_property_section (abfd, sec, link_info) { if (last_irel) { - bfd_vma old_size = + flagword old_flags; + bfd_vma old_size = bfd_get_32 (abfd, &contents[last_irel->r_offset + 4]); - bfd_vma old_address = - (last_irel->r_addend + bfd_vma old_address = + (last_irel->r_addend + bfd_get_32 (abfd, &contents[last_irel->r_offset])); - bfd_vma new_address = - (irel->r_addend + bfd_vma new_address = + (irel->r_addend + bfd_get_32 (abfd, &contents[actual_offset])); - - if ((ELF32_R_SYM (irel->r_info) == - ELF32_R_SYM (last_irel->r_info)) - && (old_address + old_size == new_address)) + if (is_full_prop_section) + old_flags = bfd_get_32 + (abfd, &contents[last_irel->r_offset + 8]); + else + old_flags = predef_flags; + + if ((ELF32_R_SYM (irel->r_info) + == ELF32_R_SYM (last_irel->r_info)) + && old_address + old_size == new_address + && old_flags == flags + && (old_flags & XTENSA_PROP_INSN_BRANCH_TARGET) == 0 + && (old_flags & XTENSA_PROP_INSN_LOOP_TARGET) == 0) { - /* fix the old size */ + /* Fix the old size. */ bfd_put_32 (abfd, old_size + size, &contents[last_irel->r_offset + 4]); - bytes_to_remove = 8; + bytes_to_remove = entry_size; remove_this_irel = TRUE; } else @@ -5207,14 +9365,14 @@ relax_property_section (abfd, sec, link_info) if (bytes_to_remove != 0) { removed_bytes += bytes_to_remove; - if (offset + 8 < section_size) + if (offset + bytes_to_remove < section_size) memmove (&contents[actual_offset], - &contents[actual_offset+8], - section_size - offset - 8); + &contents[actual_offset + bytes_to_remove], + section_size - offset - bytes_to_remove); } } - if (removed_bytes) + if (removed_bytes) { /* Clear the removed bytes. */ memset (&contents[section_size - removed_bytes], 0, removed_bytes); @@ -5246,7 +9404,7 @@ relax_property_section (abfd, sec, link_info) /* Change symbol values to account for removed literals. */ -bfd_boolean +bfd_boolean relax_section_symbols (abfd, sec) bfd *abfd; asection *sec; @@ -5260,7 +9418,8 @@ relax_section_symbols (abfd, sec) relax_info = get_xtensa_relax_info (sec); BFD_ASSERT (relax_info); - if (!relax_info->is_relaxable_literal_section) + if (!relax_info->is_relaxable_literal_section + && !relax_info->is_relaxable_asm_section) return TRUE; sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); @@ -5278,10 +9437,19 @@ relax_section_symbols (abfd, sec) if (isym->st_shndx == sec_shndx) { - bfd_vma new_address = offset_with_removed_literals - (&relax_info->removed_list, isym->st_value); - if (new_address != isym->st_value) - isym->st_value = new_address; + bfd_vma new_address = offset_with_removed_text + (&relax_info->action_list, isym->st_value); + bfd_vma new_size = isym->st_size; + + if (ELF32_ST_TYPE (isym->st_info) == STT_FUNC) + { + bfd_vma new_end = offset_with_removed_text + (&relax_info->action_list, isym->st_value + isym->st_size); + new_size = new_end - new_address; + } + + isym->st_value = new_address; + isym->st_size = new_size; } } @@ -5299,10 +9467,20 @@ relax_section_symbols (abfd, sec) || sym_hash->root.type == bfd_link_hash_defweak) && sym_hash->root.u.def.section == sec) { - bfd_vma new_address = offset_with_removed_literals - (&relax_info->removed_list, sym_hash->root.u.def.value); - if (new_address != sym_hash->root.u.def.value) - sym_hash->root.u.def.value = new_address; + bfd_vma new_address = offset_with_removed_text + (&relax_info->action_list, sym_hash->root.u.def.value); + bfd_vma new_size = sym_hash->size; + + if (sym_hash->type == STT_FUNC) + { + bfd_vma new_end = offset_with_removed_text + (&relax_info->action_list, + sym_hash->root.u.def.value + sym_hash->size); + new_size = new_end - new_address; + } + + sym_hash->root.u.def.value = new_address; + sym_hash->size = new_size; } } @@ -5312,37 +9490,41 @@ relax_section_symbols (abfd, sec) /* "Fix" handling functions, called while performing relocations. */ -static void -do_fix_for_relocatable_link (rel, input_bfd, input_section) +static bfd_boolean +do_fix_for_relocatable_link (rel, input_bfd, input_section, contents) Elf_Internal_Rela *rel; bfd *input_bfd; asection *input_section; + bfd_byte *contents; { r_reloc r_rel; asection *sec, *old_sec; bfd_vma old_offset; int r_type = ELF32_R_TYPE (rel->r_info); - reloc_bfd_fix *fix_list; reloc_bfd_fix *fix; if (r_type == R_XTENSA_NONE) - return; - - fix_list = (get_xtensa_relax_info (input_section))->fix_list; - if (fix_list == NULL) - return; + return TRUE; - fix = get_bfd_fix (fix_list, input_section, rel->r_offset, r_type); - if (fix == NULL) - return; + fix = get_bfd_fix (input_section, rel->r_offset, r_type); + if (!fix) + return TRUE; - r_reloc_init (&r_rel, input_bfd, rel); + r_reloc_init (&r_rel, input_bfd, rel, contents, + bfd_get_section_limit (input_bfd, input_section)); old_sec = r_reloc_get_section (&r_rel); - old_offset = r_reloc_get_target_offset (&r_rel); - - if (old_sec == NULL || !r_reloc_is_defined (&r_rel)) + old_offset = r_rel.target_offset; + + if (!old_sec || !r_reloc_is_defined (&r_rel)) { - BFD_ASSERT (r_type == R_XTENSA_ASM_EXPAND); + if (r_type != R_XTENSA_ASM_EXPAND) + { + (*_bfd_error_handler) + (_("%B(%A+0x%lx): unexpected fix for %s relocation"), + input_bfd, input_section, rel->r_offset, + elf_howto_table[r_type].name); + return FALSE; + } /* Leave it be. Resolution will happen in a later stage. */ } else @@ -5351,35 +9533,45 @@ do_fix_for_relocatable_link (rel, input_bfd, input_section) rel->r_addend += ((sec->output_offset + fix->target_offset) - (old_sec->output_offset + old_offset)); } + return TRUE; } static void -do_fix_for_final_link (rel, input_section, relocationp) +do_fix_for_final_link (rel, input_bfd, input_section, contents, relocationp) Elf_Internal_Rela *rel; + bfd *input_bfd; asection *input_section; + bfd_byte *contents; bfd_vma *relocationp; { asection *sec; int r_type = ELF32_R_TYPE (rel->r_info); - reloc_bfd_fix *fix_list; reloc_bfd_fix *fix; + bfd_vma fixup_diff; if (r_type == R_XTENSA_NONE) return; - fix_list = (get_xtensa_relax_info (input_section))->fix_list; - if (fix_list == NULL) - return; - - fix = get_bfd_fix (fix_list, input_section, rel->r_offset, r_type); - if (fix == NULL) + fix = get_bfd_fix (input_section, rel->r_offset, r_type); + if (!fix) return; sec = fix->target_sec; + + fixup_diff = rel->r_addend; + if (elf_howto_table[fix->src_type].partial_inplace) + { + bfd_vma inplace_val; + BFD_ASSERT (fix->src_offset + < bfd_get_section_limit (input_bfd, input_section)); + inplace_val = bfd_get_32 (input_bfd, &contents[fix->src_offset]); + fixup_diff += inplace_val; + } + *relocationp = (sec->output_section->vma + sec->output_offset - + fix->target_offset - rel->r_addend); + + fix->target_offset - fixup_diff); } @@ -5430,7 +9622,7 @@ get_elf_r_symndx_section (abfd, r_symndx) { Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr; asection *target_sec = NULL; - if (r_symndx < symtab_hdr->sh_info) + if (r_symndx < symtab_hdr->sh_info) { Elf_Internal_Sym *isymbuf; unsigned int section_index; @@ -5446,7 +9638,7 @@ get_elf_r_symndx_section (abfd, r_symndx) target_sec = bfd_abs_section_ptr; else if (section_index == SHN_COMMON) target_sec = bfd_com_section_ptr; - else + else /* Who knows? */ target_sec = NULL; } @@ -5492,7 +9684,7 @@ get_elf_r_symndx_hash_entry (abfd, r_symndx) if (r_symndx < symtab_hdr->sh_info) return NULL; - + indx = r_symndx - symtab_hdr->sh_info; h = elf_sym_hashes (abfd)[indx]; while (h->root.type == bfd_link_hash_indirect @@ -5512,7 +9704,7 @@ get_elf_r_symndx_offset (abfd, r_symndx) Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr; bfd_vma offset = 0; - if (r_symndx < symtab_hdr->sh_info) + if (r_symndx < symtab_hdr->sh_info) { Elf_Internal_Sym *isymbuf; isymbuf = retrieve_local_syms (abfd); @@ -5536,21 +9728,40 @@ get_elf_r_symndx_offset (abfd, r_symndx) static bfd_boolean -pcrel_reloc_fits (opnd, self_address, dest_address) - xtensa_operand opnd; +is_reloc_sym_weak (abfd, rel) + bfd *abfd; + Elf_Internal_Rela *rel; +{ + unsigned long r_symndx = ELF32_R_SYM (rel->r_info); + struct elf_link_hash_entry *h; + + h = get_elf_r_symndx_hash_entry (abfd, r_symndx); + if (h && h->root.type == bfd_link_hash_defweak) + return TRUE; + return FALSE; +} + + +static bfd_boolean +pcrel_reloc_fits (opc, opnd, self_address, dest_address) + xtensa_opcode opc; + int opnd; bfd_vma self_address; bfd_vma dest_address; { - uint32 new_address = - xtensa_operand_do_reloc (opnd, dest_address, self_address); - return (xtensa_operand_encode (opnd, &new_address) - == xtensa_encode_result_ok); + xtensa_isa isa = xtensa_default_isa; + uint32 valp = dest_address; + if (xtensa_operand_do_reloc (isa, opc, opnd, &valp, self_address) + || xtensa_operand_encode (isa, opc, opnd, &valp)) + return FALSE; + return TRUE; } static int linkonce_len = sizeof (".gnu.linkonce.") - 1; static int insn_sec_len = sizeof (XTENSA_INSN_SEC_NAME) - 1; static int lit_sec_len = sizeof (XTENSA_LIT_SEC_NAME) - 1; +static int prop_sec_len = sizeof (XTENSA_PROP_SEC_NAME) - 1; static bfd_boolean @@ -5558,13 +9769,14 @@ xtensa_is_property_section (sec) asection *sec; { if (strncmp (XTENSA_INSN_SEC_NAME, sec->name, insn_sec_len) == 0 - || strncmp (XTENSA_LIT_SEC_NAME, sec->name, lit_sec_len) == 0) + || strncmp (XTENSA_LIT_SEC_NAME, sec->name, lit_sec_len) == 0 + || strncmp (XTENSA_PROP_SEC_NAME, sec->name, prop_sec_len) == 0) return TRUE; if (strncmp (".gnu.linkonce.", sec->name, linkonce_len) == 0 - && (sec->name[linkonce_len] == 'x' - || sec->name[linkonce_len] == 'p') - && sec->name[linkonce_len + 1] == '.') + && (strncmp (&sec->name[linkonce_len], "x.", 2) == 0 + || strncmp (&sec->name[linkonce_len], "p.", 2) == 0 + || strncmp (&sec->name[linkonce_len], "prop.", 5) == 0)) return TRUE; return FALSE; @@ -5587,25 +9799,41 @@ xtensa_is_littable_section (sec) } -static bfd_boolean -is_literal_section (sec) - asection *sec; +static int +internal_reloc_compare (ap, bp) + const PTR ap; + const PTR bp; { - /* FIXME: the current definition of this leaves a lot to be desired.... */ - if (sec == NULL || sec->name == NULL) - return FALSE; - return (strstr (sec->name, "literal") != NULL); + const Elf_Internal_Rela *a = (const Elf_Internal_Rela *) ap; + const Elf_Internal_Rela *b = (const Elf_Internal_Rela *) bp; + + if (a->r_offset != b->r_offset) + return (a->r_offset - b->r_offset); + + /* We don't need to sort on these criteria for correctness, + but enforcing a more strict ordering prevents unstable qsort + from behaving differently with different implementations. + Without the code below we get correct but different results + on Solaris 2.7 and 2.8. We would like to always produce the + same results no matter the host. */ + + if (a->r_info != b->r_info) + return (a->r_info - b->r_info); + + return (a->r_addend - b->r_addend); } static int -internal_reloc_compare (ap, bp) +internal_reloc_matches (ap, bp) const PTR ap; const PTR bp; { const Elf_Internal_Rela *a = (const Elf_Internal_Rela *) ap; const Elf_Internal_Rela *b = (const Elf_Internal_Rela *) bp; + /* Check if one entry overlaps with the other; this shouldn't happen + except when searching for a match. */ return (a->r_offset - b->r_offset); } @@ -5619,26 +9847,28 @@ xtensa_get_property_section_name (sec, base_name) { char *prop_sec_name; const char *suffix; - char linkonce_kind = 0; + char *linkonce_kind = 0; if (strcmp (base_name, XTENSA_INSN_SEC_NAME) == 0) - linkonce_kind = 'x'; + linkonce_kind = "x"; else if (strcmp (base_name, XTENSA_LIT_SEC_NAME) == 0) - linkonce_kind = 'p'; + linkonce_kind = "p"; + else if (strcmp (base_name, XTENSA_PROP_SEC_NAME) == 0) + linkonce_kind = "prop."; else abort (); - prop_sec_name = (char *) bfd_malloc (strlen (sec->name) + 1); + prop_sec_name = (char *) bfd_malloc (strlen (sec->name) + + strlen (linkonce_kind) + 1); memcpy (prop_sec_name, ".gnu.linkonce.", linkonce_len); - prop_sec_name[linkonce_len] = linkonce_kind; - prop_sec_name[linkonce_len + 1] = '.'; + strcpy (prop_sec_name + linkonce_len, linkonce_kind); suffix = sec->name + linkonce_len; /* For backward compatibility, replace "t." instead of inserting - the new linkonce_kind. */ - if (strncmp (suffix, "t.", 2) == 0) - suffix += 2; - strcpy (prop_sec_name + linkonce_len + 2, suffix); + the new linkonce_kind (but not for "prop" sections). */ + if (strncmp (suffix, "t.", 2) == 0 && linkonce_kind[1] == '.') + suffix += 2; + strcat (prop_sec_name + linkonce_len, suffix); return prop_sec_name; } @@ -5646,6 +9876,26 @@ xtensa_get_property_section_name (sec, base_name) return strdup (base_name); } + +flagword +xtensa_get_property_predef_flags (sec) + asection *sec; +{ + if (strcmp (sec->name, XTENSA_INSN_SEC_NAME) == 0 + || strncmp (sec->name, ".gnu.linkonce.x.", + sizeof ".gnu.linkonce.x." - 1) == 0) + return (XTENSA_PROP_INSN + | XTENSA_PROP_INSN_NO_TRANSFORM + | XTENSA_PROP_INSN_NO_REORDER); + + if (xtensa_is_littable_section (sec)) + return (XTENSA_PROP_LITERAL + | XTENSA_PROP_INSN_NO_TRANSFORM + | XTENSA_PROP_INSN_NO_REORDER); + + return 0; +} + /* Other functions called directly by the linker. */ @@ -5661,6 +9911,9 @@ xtensa_callback_required_dependence (abfd, sec, link_info, callback, closure) bfd_byte *contents; unsigned i; bfd_boolean ok = TRUE; + bfd_size_type sec_size; + + sec_size = bfd_get_section_limit (abfd, sec); /* ".plt*" sections have no explicit relocations but they contain L32R instructions that reference the corresponding ".got.plt*" sections. */ @@ -5688,43 +9941,43 @@ xtensa_callback_required_dependence (abfd, sec, link_info, callback, closure) /* Assume worst-case offsets: L32R at the very end of the ".plt" section referencing a literal at the very beginning of ".got.plt". This is very close to the real dependence, anyway. */ - (*callback) (sec, sec->size, sgotplt, 0, closure); + (*callback) (sec, sec_size, sgotplt, 0, closure); } internal_relocs = retrieve_internal_relocs (abfd, sec, link_info->keep_memory); if (internal_relocs == NULL - || sec->reloc_count == 0) + || sec->reloc_count == 0) return ok; /* Cache the contents for the duration of this scan. */ contents = retrieve_contents (abfd, sec, link_info->keep_memory); - if (contents == NULL && sec->size != 0) + if (contents == NULL && sec_size != 0) { ok = FALSE; goto error_return; } - if (xtensa_default_isa == NULL) - xtensa_isa_init (); + if (!xtensa_default_isa) + xtensa_default_isa = xtensa_isa_init (0, 0); - for (i = 0; i < sec->reloc_count; i++) + for (i = 0; i < sec->reloc_count; i++) { Elf_Internal_Rela *irel = &internal_relocs[i]; - if (is_l32r_relocation (sec, contents, irel)) + if (is_l32r_relocation (abfd, sec, contents, irel)) { r_reloc l32r_rel; asection *target_sec; bfd_vma target_offset; - - r_reloc_init (&l32r_rel, abfd, irel); + + r_reloc_init (&l32r_rel, abfd, irel, contents, sec_size); target_sec = NULL; target_offset = 0; /* L32Rs must be local to the input file. */ if (r_reloc_is_defined (&l32r_rel)) { target_sec = r_reloc_get_section (&l32r_rel); - target_offset = r_reloc_get_target_offset (&l32r_rel); + target_offset = l32r_rel.target_offset; } (*callback) (sec, irel->r_offset, target_sec, target_offset, closure); @@ -5761,7 +10014,7 @@ static struct bfd_elf_special_section const elf_xtensa_special_sections[]= value so that pre-T1040 tools can read the files. As soon as we stop caring about pre-T1040 tools, the following two values should be swapped. At the same time, any other code that uses EM_XTENSA_OLD - (e.g., prep_headers() in elf.c) should be changed to use EM_XTENSA. */ + should be changed to use EM_XTENSA. */ #define ELF_MACHINE_CODE EM_XTENSA_OLD #define ELF_MACHINE_ALT1 EM_XTENSA diff --git a/bfd/libbfd.h b/bfd/libbfd.h index c079a6acaa8..c811de5be73 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -1650,6 +1650,39 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_XTENSA_JMP_SLOT", "BFD_RELOC_XTENSA_RELATIVE", "BFD_RELOC_XTENSA_PLT", + "BFD_RELOC_XTENSA_DIFF8", + "BFD_RELOC_XTENSA_DIFF16", + "BFD_RELOC_XTENSA_DIFF32", + "BFD_RELOC_XTENSA_SLOT0_OP", + "BFD_RELOC_XTENSA_SLOT1_OP", + "BFD_RELOC_XTENSA_SLOT2_OP", + "BFD_RELOC_XTENSA_SLOT3_OP", + "BFD_RELOC_XTENSA_SLOT4_OP", + "BFD_RELOC_XTENSA_SLOT5_OP", + "BFD_RELOC_XTENSA_SLOT6_OP", + "BFD_RELOC_XTENSA_SLOT7_OP", + "BFD_RELOC_XTENSA_SLOT8_OP", + "BFD_RELOC_XTENSA_SLOT9_OP", + "BFD_RELOC_XTENSA_SLOT10_OP", + "BFD_RELOC_XTENSA_SLOT11_OP", + "BFD_RELOC_XTENSA_SLOT12_OP", + "BFD_RELOC_XTENSA_SLOT13_OP", + "BFD_RELOC_XTENSA_SLOT14_OP", + "BFD_RELOC_XTENSA_SLOT0_ALT", + "BFD_RELOC_XTENSA_SLOT1_ALT", + "BFD_RELOC_XTENSA_SLOT2_ALT", + "BFD_RELOC_XTENSA_SLOT3_ALT", + "BFD_RELOC_XTENSA_SLOT4_ALT", + "BFD_RELOC_XTENSA_SLOT5_ALT", + "BFD_RELOC_XTENSA_SLOT6_ALT", + "BFD_RELOC_XTENSA_SLOT7_ALT", + "BFD_RELOC_XTENSA_SLOT8_ALT", + "BFD_RELOC_XTENSA_SLOT9_ALT", + "BFD_RELOC_XTENSA_SLOT10_ALT", + "BFD_RELOC_XTENSA_SLOT11_ALT", + "BFD_RELOC_XTENSA_SLOT12_ALT", + "BFD_RELOC_XTENSA_SLOT13_ALT", + "BFD_RELOC_XTENSA_SLOT14_ALT", "BFD_RELOC_XTENSA_OP0", "BFD_RELOC_XTENSA_OP1", "BFD_RELOC_XTENSA_OP2", diff --git a/bfd/reloc.c b/bfd/reloc.c index 0069841eda4..1df18408fee 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -4142,6 +4142,87 @@ ENUM ENUMDOC Xtensa relocation used in ELF object files for symbols that may require PLT entries. Otherwise, this is just a generic 32-bit relocation. +ENUM + BFD_RELOC_XTENSA_DIFF8 +ENUMX + BFD_RELOC_XTENSA_DIFF16 +ENUMX + BFD_RELOC_XTENSA_DIFF32 +ENUMDOC + Xtensa relocations to mark the difference of two local symbols. + These are only needed to support linker relaxation and can be ignored + when not relaxing. The field is set to the value of the difference + assuming no relaxation. The relocation encodes the position of the + first symbol so the linker can determine whether to adjust the field + value. +ENUM + BFD_RELOC_XTENSA_SLOT0_OP +ENUMX + BFD_RELOC_XTENSA_SLOT1_OP +ENUMX + BFD_RELOC_XTENSA_SLOT2_OP +ENUMX + BFD_RELOC_XTENSA_SLOT3_OP +ENUMX + BFD_RELOC_XTENSA_SLOT4_OP +ENUMX + BFD_RELOC_XTENSA_SLOT5_OP +ENUMX + BFD_RELOC_XTENSA_SLOT6_OP +ENUMX + BFD_RELOC_XTENSA_SLOT7_OP +ENUMX + BFD_RELOC_XTENSA_SLOT8_OP +ENUMX + BFD_RELOC_XTENSA_SLOT9_OP +ENUMX + BFD_RELOC_XTENSA_SLOT10_OP +ENUMX + BFD_RELOC_XTENSA_SLOT11_OP +ENUMX + BFD_RELOC_XTENSA_SLOT12_OP +ENUMX + BFD_RELOC_XTENSA_SLOT13_OP +ENUMX + BFD_RELOC_XTENSA_SLOT14_OP +ENUMDOC + Generic Xtensa relocations for instruction operands. Only the slot + number is encoded in the relocation. The relocation applies to the + last PC-relative immediate operand, or if there are no PC-relative + immediates, to the last immediate operand. +ENUM + BFD_RELOC_XTENSA_SLOT0_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT1_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT2_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT3_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT4_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT5_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT6_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT7_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT8_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT9_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT10_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT11_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT12_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT13_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT14_ALT +ENUMDOC + Alternate Xtensa relocations. Only the slot is encoded in the + relocation. The meaning of these relocations is opcode-specific. ENUM BFD_RELOC_XTENSA_OP0 ENUMX @@ -4149,9 +4230,8 @@ ENUMX ENUMX BFD_RELOC_XTENSA_OP2 ENUMDOC - Generic Xtensa relocations. Only the operand number is encoded - in the relocation. The details are determined by extracting the - instruction opcode. + Xtensa relocations for backward compatibility. These have all been + replaced by BFD_RELOC_XTENSA_SLOT0_OP. ENUM BFD_RELOC_XTENSA_ASM_EXPAND ENUMDOC diff --git a/bfd/xtensa-isa.c b/bfd/xtensa-isa.c index 761e5c6bb69..30ad80cfd6b 100644 --- a/bfd/xtensa-isa.c +++ b/bfd/xtensa-isa.c @@ -1,5 +1,5 @@ /* Configurable Xtensa ISA support. - Copyright 2003 Free Software Foundation, Inc. + Copyright 2003, 2004 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -17,577 +17,1725 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include -#include -#include -#include - +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" #include "xtensa-isa.h" #include "xtensa-isa-internal.h" -xtensa_isa xtensa_default_isa = NULL; +xtensa_isa_status xtisa_errno; +char xtisa_error_msg[1024]; + + +xtensa_isa_status +xtensa_isa_errno (xtensa_isa isa __attribute__ ((unused))) +{ + return xtisa_errno; +} + -static int -opname_lookup_compare (const void *v1, const void *v2) +char * +xtensa_isa_error_msg (xtensa_isa isa __attribute__ ((unused))) { - opname_lookup_entry *e1 = (opname_lookup_entry *)v1; - opname_lookup_entry *e2 = (opname_lookup_entry *)v2; + return xtisa_error_msg; +} - return strcmp (e1->key, e2->key); + +#define CHECK_ALLOC(MEM,ERRVAL) \ + do { \ + if ((MEM) == 0) \ + { \ + xtisa_errno = xtensa_isa_out_of_memory; \ + strcpy (xtisa_error_msg, "out of memory"); \ + return (ERRVAL); \ + } \ + } while (0) + +#define CHECK_ALLOC_FOR_INIT(MEM,ERRVAL,ERRNO_P,ERROR_MSG_P) \ + do { \ + if ((MEM) == 0) \ + { \ + xtisa_errno = xtensa_isa_out_of_memory; \ + strcpy (xtisa_error_msg, "out of memory"); \ + if (ERRNO_P) *(ERRNO_P) = xtisa_errno; \ + if (ERROR_MSG_P) *(ERROR_MSG_P) = xtisa_error_msg; \ + return (ERRVAL); \ + } \ + } while (0) + + +/* Instruction buffers. */ + +int +xtensa_insnbuf_size (xtensa_isa isa) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + return intisa->insnbuf_size; } +xtensa_insnbuf +xtensa_insnbuf_alloc (xtensa_isa isa) +{ + xtensa_insnbuf result = (xtensa_insnbuf) + malloc (xtensa_insnbuf_size (isa) * sizeof (xtensa_insnbuf_word)); + CHECK_ALLOC (result, 0); + return result; +} + + +void +xtensa_insnbuf_free (xtensa_isa isa __attribute__ ((unused)), + xtensa_insnbuf buf) +{ + free (buf); +} + + +/* Given , the index of a byte in a xtensa_insnbuf, our + internal representation of a xtensa instruction word, return the index of + its word and the bit index of its low order byte in the xtensa_insnbuf. */ + +static inline int +byte_to_word_index (int byte_index) +{ + return byte_index / sizeof (xtensa_insnbuf_word); +} + + +static inline int +byte_to_bit_index (int byte_index) +{ + return (byte_index & 0x3) * 8; +} + + +/* Copy an instruction in the 32-bit words pointed at by "insn" to + characters pointed at by "cp". This is more complicated than you + might think because we want 16-bit instructions in bytes 2 & 3 for + big-endian configurations. This function allows us to specify + which byte in "insn" to start with and which way to increment, + allowing trivial implementation for both big- and little-endian + configurations....and it seems to make pretty good code for + both. */ + +int +xtensa_insnbuf_to_chars (xtensa_isa isa, const xtensa_insnbuf insn, char *cp, + int num_chars) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + int insn_size = xtensa_isa_maxlength (isa); + int fence_post, start, increment, i, byte_count; + xtensa_format fmt; + + if (num_chars == 0) + num_chars = insn_size; + + if (intisa->is_big_endian) + { + start = insn_size - 1; + increment = -1; + } + else + { + start = 0; + increment = 1; + } + + /* Find the instruction format. Do nothing if the buffer does not contain + a valid instruction since we need to know how many bytes to copy. */ + fmt = xtensa_format_decode (isa, insn); + if (fmt == XTENSA_UNDEFINED) + return XTENSA_UNDEFINED; + + byte_count = xtensa_format_length (isa, fmt); + if (byte_count == XTENSA_UNDEFINED) + return XTENSA_UNDEFINED; + + if (byte_count > num_chars) + { + xtisa_errno = xtensa_isa_buffer_overflow; + strcpy (xtisa_error_msg, "output buffer too small for instruction"); + return XTENSA_UNDEFINED; + } + + fence_post = start + (byte_count * increment); + + for (i = start; i != fence_post; i += increment, ++cp) + { + int word_inx = byte_to_word_index (i); + int bit_inx = byte_to_bit_index (i); + + *cp = (insn[word_inx] >> bit_inx) & 0xff; + } + + return byte_count; +} + + +/* Inward conversion from byte stream to xtensa_insnbuf. See + xtensa_insnbuf_to_chars for a discussion of why this is complicated + by endianness. */ + +void +xtensa_insnbuf_from_chars (xtensa_isa isa, xtensa_insnbuf insn, const char *cp, + int num_chars) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + int max_size, insn_size, fence_post, start, increment, i; + + max_size = xtensa_isa_maxlength (isa); + + /* Decode the instruction length so we know how many bytes to read. */ + insn_size = (intisa->length_decode_fn) (cp); + if (insn_size == XTENSA_UNDEFINED) + { + /* This should never happen when the byte stream contains a + valid instruction. Just read the maximum number of bytes.... */ + insn_size = max_size; + } + + if (num_chars == 0 || num_chars > insn_size) + num_chars = insn_size; + + if (intisa->is_big_endian) + { + start = max_size - 1; + increment = -1; + } + else + { + start = 0; + increment = 1; + } + + fence_post = start + (num_chars * increment); + memset (insn, 0, xtensa_insnbuf_size (isa) * sizeof (xtensa_insnbuf_word)); + + for (i = start; i != fence_post; i += increment, ++cp) + { + int word_inx = byte_to_word_index (i); + int bit_inx = byte_to_bit_index (i); + + insn[word_inx] |= (*cp & 0xff) << bit_inx; + } +} + + + +/* ISA information. */ + +extern xtensa_isa_internal xtensa_modules; + xtensa_isa -xtensa_isa_init (void) +xtensa_isa_init (xtensa_isa_status *errno_p, char **error_msg_p) { - xtensa_isa isa; - int mod; + xtensa_isa_internal *isa = &xtensa_modules; + int n, is_user; + + /* Set up the opcode name lookup table. */ + isa->opname_lookup_table = + bfd_malloc (isa->num_opcodes * sizeof (xtensa_lookup_entry)); + CHECK_ALLOC_FOR_INIT (isa->opname_lookup_table, NULL, errno_p, error_msg_p); + for (n = 0; n < isa->num_opcodes; n++) + { + isa->opname_lookup_table[n].key = isa->opcodes[n].name; + isa->opname_lookup_table[n].u.opcode = n; + } + qsort (isa->opname_lookup_table, isa->num_opcodes, + sizeof (xtensa_lookup_entry), xtensa_isa_name_compare); - isa = xtensa_load_isa (0); - if (isa == 0) + /* Set up the state name lookup table. */ + isa->state_lookup_table = + bfd_malloc (isa->num_states * sizeof (xtensa_lookup_entry)); + CHECK_ALLOC_FOR_INIT (isa->state_lookup_table, NULL, errno_p, error_msg_p); + for (n = 0; n < isa->num_states; n++) { - fprintf (stderr, "Failed to initialize Xtensa base ISA module\n"); - return NULL; + isa->state_lookup_table[n].key = isa->states[n].name; + isa->state_lookup_table[n].u.state = n; + } + qsort (isa->state_lookup_table, isa->num_states, + sizeof (xtensa_lookup_entry), xtensa_isa_name_compare); + + /* Set up the sysreg name lookup table. */ + isa->sysreg_lookup_table = + bfd_malloc (isa->num_sysregs * sizeof (xtensa_lookup_entry)); + CHECK_ALLOC_FOR_INIT (isa->sysreg_lookup_table, NULL, errno_p, error_msg_p); + for (n = 0; n < isa->num_sysregs; n++) + { + isa->sysreg_lookup_table[n].key = isa->sysregs[n].name; + isa->sysreg_lookup_table[n].u.sysreg = n; + } + qsort (isa->sysreg_lookup_table, isa->num_sysregs, + sizeof (xtensa_lookup_entry), xtensa_isa_name_compare); + + /* Set up the user & system sysreg number tables. */ + for (is_user = 0; is_user < 2; is_user++) + { + isa->sysreg_table[is_user] = + bfd_malloc ((isa->max_sysreg_num[is_user] + 1) + * sizeof (xtensa_sysreg)); + CHECK_ALLOC_FOR_INIT (isa->sysreg_table[is_user], NULL, + errno_p, error_msg_p); + + for (n = 0; n <= isa->max_sysreg_num[is_user]; n++) + isa->sysreg_table[is_user][n] = XTENSA_UNDEFINED; + } + for (n = 0; n < isa->num_sysregs; n++) + { + xtensa_sysreg_internal *sreg = &isa->sysregs[n]; + is_user = sreg->is_user; + + isa->sysreg_table[is_user][sreg->number] = n; + } + + /* Set up the interface lookup table. */ + isa->interface_lookup_table = + bfd_malloc (isa->num_interfaces * sizeof (xtensa_lookup_entry)); + CHECK_ALLOC_FOR_INIT (isa->interface_lookup_table, NULL, errno_p, + error_msg_p); + for (n = 0; n < isa->num_interfaces; n++) + { + isa->interface_lookup_table[n].key = isa->interfaces[n].name; + isa->interface_lookup_table[n].u.intf = n; + } + qsort (isa->interface_lookup_table, isa->num_interfaces, + sizeof (xtensa_lookup_entry), xtensa_isa_name_compare); + + /* Set up the funcUnit lookup table. */ + isa->funcUnit_lookup_table = + bfd_malloc (isa->num_funcUnits * sizeof (xtensa_lookup_entry)); + CHECK_ALLOC_FOR_INIT (isa->funcUnit_lookup_table, NULL, errno_p, + error_msg_p); + for (n = 0; n < isa->num_funcUnits; n++) + { + isa->funcUnit_lookup_table[n].key = isa->funcUnits[n].name; + isa->funcUnit_lookup_table[n].u.fun = n; + } + qsort (isa->funcUnit_lookup_table, isa->num_funcUnits, + sizeof (xtensa_lookup_entry), xtensa_isa_name_compare); + + isa->insnbuf_size = ((isa->insn_size + sizeof (xtensa_insnbuf_word) - 1) / + sizeof (xtensa_insnbuf_word)); + + return (xtensa_isa) isa; +} + + +void +xtensa_isa_free (xtensa_isa isa) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + int n; + + /* With this version of the code, the xtensa_isa structure is not + dynamically allocated, so this function is not essential. Free + the memory allocated by xtensa_isa_init and restore the xtensa_isa + structure to its initial state. */ + + if (intisa->opname_lookup_table) + { + free (intisa->opname_lookup_table); + intisa->opname_lookup_table = 0; } - for (mod = 1; xtensa_isa_modules[mod].get_num_opcodes_fn; mod++) + if (intisa->state_lookup_table) { - if (!xtensa_extend_isa (isa, mod)) + free (intisa->state_lookup_table); + intisa->state_lookup_table = 0; + } + + if (intisa->sysreg_lookup_table) + { + free (intisa->sysreg_lookup_table); + intisa->sysreg_lookup_table = 0; + } + for (n = 0; n < 2; n++) + { + if (intisa->sysreg_table[n]) { - fprintf (stderr, "Failed to initialize Xtensa TIE ISA module\n"); - return NULL; + free (intisa->sysreg_table[n]); + intisa->sysreg_table[n] = 0; } } - - return isa; + + if (intisa->interface_lookup_table) + { + free (intisa->interface_lookup_table); + intisa->interface_lookup_table = 0; + } + + if (intisa->funcUnit_lookup_table) + { + free (intisa->funcUnit_lookup_table); + intisa->funcUnit_lookup_table = 0; + } +} + + +int +xtensa_isa_name_compare (const void *v1, const void *v2) +{ + xtensa_lookup_entry *e1 = (xtensa_lookup_entry *) v1; + xtensa_lookup_entry *e2 = (xtensa_lookup_entry *) v2; + + return strcasecmp (e1->key, e2->key); +} + + +int +xtensa_isa_maxlength (xtensa_isa isa) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + return intisa->insn_size; +} + + +int +xtensa_isa_length_from_chars (xtensa_isa isa, const char *cp) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + return (intisa->length_decode_fn) (cp); +} + + +int +xtensa_isa_num_pipe_stages (xtensa_isa isa) +{ + int num_opcodes, num_uses; + xtensa_opcode opcode; + xtensa_funcUnit_use *use; + int i, stage, max_stage = XTENSA_UNDEFINED; + + num_opcodes = xtensa_isa_num_opcodes (isa); + for (opcode = 0; opcode < num_opcodes; opcode++) + { + num_uses = xtensa_opcode_num_funcUnit_uses (isa, opcode); + for (i = 0; i < num_uses; i++) + { + use = xtensa_opcode_funcUnit_use (isa, opcode, i); + stage = use->stage; + if (stage > max_stage) + max_stage = stage; + } + } + + return max_stage + 1; +} + + +int +xtensa_isa_num_formats (xtensa_isa isa) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + return intisa->num_formats; +} + + +int +xtensa_isa_num_opcodes (xtensa_isa isa) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + return intisa->num_opcodes; +} + + +int +xtensa_isa_num_regfiles (xtensa_isa isa) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + return intisa->num_regfiles; +} + + +int +xtensa_isa_num_states (xtensa_isa isa) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + return intisa->num_states; +} + + +int +xtensa_isa_num_sysregs (xtensa_isa isa) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + return intisa->num_sysregs; +} + + +int +xtensa_isa_num_interfaces (xtensa_isa isa) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + return intisa->num_interfaces; +} + + +int +xtensa_isa_num_funcUnits (xtensa_isa isa) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + return intisa->num_funcUnits; +} + + + +/* Instruction formats. */ + + +#define CHECK_FORMAT(INTISA,FMT,ERRVAL) \ + do { \ + if ((FMT) < 0 || (FMT) >= (INTISA)->num_formats) \ + { \ + xtisa_errno = xtensa_isa_bad_format; \ + strcpy (xtisa_error_msg, "invalid format specifier"); \ + return (ERRVAL); \ + } \ + } while (0) + + +#define CHECK_SLOT(INTISA,FMT,SLOT,ERRVAL) \ + do { \ + if ((SLOT) < 0 || (SLOT) >= (INTISA)->formats[FMT].num_slots) \ + { \ + xtisa_errno = xtensa_isa_bad_slot; \ + strcpy (xtisa_error_msg, "invalid slot specifier"); \ + return (ERRVAL); \ + } \ + } while (0) + + +const char * +xtensa_format_name (xtensa_isa isa, xtensa_format fmt) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + CHECK_FORMAT (intisa, fmt, NULL); + return intisa->formats[fmt].name; +} + + +xtensa_format +xtensa_format_lookup (xtensa_isa isa, const char *fmtname) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + int fmt; + + if (!fmtname || !*fmtname) + { + xtisa_errno = xtensa_isa_bad_format; + strcpy (xtisa_error_msg, "invalid format name"); + return XTENSA_UNDEFINED; + } + + for (fmt = 0; fmt < intisa->num_formats; fmt++) + { + if (strcasecmp (fmtname, intisa->formats[fmt].name) == 0) + return fmt; + } + + xtisa_errno = xtensa_isa_bad_format; + sprintf (xtisa_error_msg, "format \"%s\" not recognized", fmtname); + return XTENSA_UNDEFINED; +} + + +xtensa_format +xtensa_format_decode (xtensa_isa isa, const xtensa_insnbuf insn) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + xtensa_format fmt; + + fmt = (intisa->format_decode_fn) (insn); + if (fmt != XTENSA_UNDEFINED) + return fmt; + + xtisa_errno = xtensa_isa_bad_format; + strcpy (xtisa_error_msg, "cannot decode instruction format"); + return XTENSA_UNDEFINED; +} + + +int +xtensa_format_encode (xtensa_isa isa, xtensa_format fmt, xtensa_insnbuf insn) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + CHECK_FORMAT (intisa, fmt, -1); + (*intisa->formats[fmt].encode_fn) (insn); + return 0; +} + + +int +xtensa_format_length (xtensa_isa isa, xtensa_format fmt) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + CHECK_FORMAT (intisa, fmt, XTENSA_UNDEFINED); + return intisa->formats[fmt].length; +} + + +int +xtensa_format_num_slots (xtensa_isa isa, xtensa_format fmt) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + CHECK_FORMAT (intisa, fmt, XTENSA_UNDEFINED); + return intisa->formats[fmt].num_slots; +} + + +xtensa_opcode +xtensa_format_slot_nop_opcode (xtensa_isa isa, xtensa_format fmt, int slot) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + int slot_id; + + CHECK_FORMAT (intisa, fmt, XTENSA_UNDEFINED); + CHECK_SLOT (intisa, fmt, slot, XTENSA_UNDEFINED); + + slot_id = intisa->formats[fmt].slot_id[slot]; + return xtensa_opcode_lookup (isa, intisa->slots[slot_id].nop_name); +} + + +int +xtensa_format_get_slot (xtensa_isa isa, xtensa_format fmt, int slot, + const xtensa_insnbuf insn, xtensa_insnbuf slotbuf) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + int slot_id; + + CHECK_FORMAT (intisa, fmt, -1); + CHECK_SLOT (intisa, fmt, slot, -1); + + slot_id = intisa->formats[fmt].slot_id[slot]; + (*intisa->slots[slot_id].get_fn) (insn, slotbuf); + return 0; +} + + +int +xtensa_format_set_slot (xtensa_isa isa, xtensa_format fmt, int slot, + xtensa_insnbuf insn, const xtensa_insnbuf slotbuf) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + int slot_id; + + CHECK_FORMAT (intisa, fmt, -1); + CHECK_SLOT (intisa, fmt, slot, -1); + + slot_id = intisa->formats[fmt].slot_id[slot]; + (*intisa->slots[slot_id].set_fn) (insn, slotbuf); + return 0; +} + + + +/* Opcode information. */ + + +#define CHECK_OPCODE(INTISA,OPC,ERRVAL) \ + do { \ + if ((OPC) < 0 || (OPC) >= (INTISA)->num_opcodes) \ + { \ + xtisa_errno = xtensa_isa_bad_opcode; \ + strcpy (xtisa_error_msg, "invalid opcode specifier"); \ + return (ERRVAL); \ + } \ + } while (0) + + +xtensa_opcode +xtensa_opcode_lookup (xtensa_isa isa, const char *opname) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + xtensa_lookup_entry entry, *result; + + if (!opname || !*opname) + { + xtisa_errno = xtensa_isa_bad_opcode; + strcpy (xtisa_error_msg, "invalid opcode name"); + return XTENSA_UNDEFINED; + } + + entry.key = opname; + result = bsearch (&entry, intisa->opname_lookup_table, intisa->num_opcodes, + sizeof (xtensa_lookup_entry), xtensa_isa_name_compare); + + if (!result) + { + xtisa_errno = xtensa_isa_bad_opcode; + sprintf (xtisa_error_msg, "opcode \"%s\" not recognized", opname); + return XTENSA_UNDEFINED; + } + + return result->u.opcode; +} + + +xtensa_opcode +xtensa_opcode_decode (xtensa_isa isa, xtensa_format fmt, int slot, + const xtensa_insnbuf slotbuf) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + int slot_id; + xtensa_opcode opc; + + CHECK_FORMAT (intisa, fmt, XTENSA_UNDEFINED); + CHECK_SLOT (intisa, fmt, slot, XTENSA_UNDEFINED); + + slot_id = intisa->formats[fmt].slot_id[slot]; + + opc = (intisa->slots[slot_id].opcode_decode_fn) (slotbuf); + if (opc == XTENSA_UNDEFINED) + { + xtisa_errno = xtensa_isa_bad_opcode; + strcpy (xtisa_error_msg, "cannot decode opcode"); + } + return opc; +} + + +int +xtensa_opcode_encode (xtensa_isa isa, xtensa_format fmt, int slot, + xtensa_insnbuf slotbuf, xtensa_opcode opc) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + int slot_id; + xtensa_opcode_encode_fn encode_fn; + + CHECK_FORMAT (intisa, fmt, -1); + CHECK_SLOT (intisa, fmt, slot, -1); + CHECK_OPCODE (intisa, opc, -1); + + slot_id = intisa->formats[fmt].slot_id[slot]; + encode_fn = intisa->opcodes[opc].encode_fns[slot_id]; + if (!encode_fn) + { + xtisa_errno = xtensa_isa_wrong_slot; + sprintf (xtisa_error_msg, + "opcode \"%s\" is not allowed in slot %d of format \"%s\"", + intisa->opcodes[opc].name, slot, intisa->formats[fmt].name); + return -1; + } + (*encode_fn) (slotbuf); + return 0; +} + + +const char * +xtensa_opcode_name (xtensa_isa isa, xtensa_opcode opc) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + CHECK_OPCODE (intisa, opc, NULL); + return intisa->opcodes[opc].name; +} + + +int +xtensa_opcode_is_branch (xtensa_isa isa, xtensa_opcode opc) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + CHECK_OPCODE (intisa, opc, XTENSA_UNDEFINED); + if ((intisa->opcodes[opc].flags & XTENSA_OPCODE_IS_BRANCH) != 0) + return 1; + return 0; +} + + +int +xtensa_opcode_is_jump (xtensa_isa isa, xtensa_opcode opc) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + CHECK_OPCODE (intisa, opc, XTENSA_UNDEFINED); + if ((intisa->opcodes[opc].flags & XTENSA_OPCODE_IS_JUMP) != 0) + return 1; + return 0; +} + + +int +xtensa_opcode_is_loop (xtensa_isa isa, xtensa_opcode opc) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + CHECK_OPCODE (intisa, opc, XTENSA_UNDEFINED); + if ((intisa->opcodes[opc].flags & XTENSA_OPCODE_IS_LOOP) != 0) + return 1; + return 0; +} + + +int +xtensa_opcode_is_call (xtensa_isa isa, xtensa_opcode opc) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + CHECK_OPCODE (intisa, opc, XTENSA_UNDEFINED); + if ((intisa->opcodes[opc].flags & XTENSA_OPCODE_IS_CALL) != 0) + return 1; + return 0; +} + + +int +xtensa_opcode_num_operands (xtensa_isa isa, xtensa_opcode opc) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + int iclass_id; + + CHECK_OPCODE (intisa, opc, XTENSA_UNDEFINED); + iclass_id = intisa->opcodes[opc].iclass_id; + return intisa->iclasses[iclass_id].num_operands; +} + + +int +xtensa_opcode_num_stateOperands (xtensa_isa isa, xtensa_opcode opc) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + int iclass_id; + + CHECK_OPCODE (intisa, opc, XTENSA_UNDEFINED); + iclass_id = intisa->opcodes[opc].iclass_id; + return intisa->iclasses[iclass_id].num_stateOperands; +} + + +int +xtensa_opcode_num_interfaceOperands (xtensa_isa isa, xtensa_opcode opc) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + int iclass_id; + + CHECK_OPCODE (intisa, opc, XTENSA_UNDEFINED); + iclass_id = intisa->opcodes[opc].iclass_id; + return intisa->iclasses[iclass_id].num_interfaceOperands; +} + + +int +xtensa_opcode_num_funcUnit_uses (xtensa_isa isa, xtensa_opcode opc) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + CHECK_OPCODE (intisa, opc, XTENSA_UNDEFINED); + return intisa->opcodes[opc].num_funcUnit_uses; +} + + +xtensa_funcUnit_use * +xtensa_opcode_funcUnit_use (xtensa_isa isa, xtensa_opcode opc, int u) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + CHECK_OPCODE (intisa, opc, NULL); + if (u < 0 || u >= intisa->opcodes[opc].num_funcUnit_uses) + { + xtisa_errno = xtensa_isa_bad_funcUnit; + sprintf (xtisa_error_msg, "invalid functional unit use number (%d); " + "opcode \"%s\" has %d", u, intisa->opcodes[opc].name, + intisa->opcodes[opc].num_funcUnit_uses); + return NULL; + } + return &intisa->opcodes[opc].funcUnit_uses[u]; +} + + + +/* Operand information. */ + + +#define CHECK_OPERAND(INTISA,OPC,ICLASS,OPND,ERRVAL) \ + do { \ + if ((OPND) < 0 || (OPND) >= (ICLASS)->num_operands) \ + { \ + xtisa_errno = xtensa_isa_bad_operand; \ + sprintf (xtisa_error_msg, "invalid operand number (%d); " \ + "opcode \"%s\" has %d operands", (OPND), \ + (INTISA)->opcodes[(OPC)].name, (ICLASS)->num_operands); \ + return (ERRVAL); \ + } \ + } while (0) + + +static xtensa_operand_internal * +get_operand (xtensa_isa_internal *intisa, xtensa_opcode opc, int opnd) +{ + xtensa_iclass_internal *iclass; + int iclass_id, operand_id; + + CHECK_OPCODE (intisa, opc, NULL); + iclass_id = intisa->opcodes[opc].iclass_id; + iclass = &intisa->iclasses[iclass_id]; + CHECK_OPERAND (intisa, opc, iclass, opnd, NULL); + operand_id = iclass->operands[opnd].u.operand_id; + return &intisa->operands[operand_id]; +} + + +const char * +xtensa_operand_name (xtensa_isa isa, xtensa_opcode opc, int opnd) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + xtensa_operand_internal *intop; + + intop = get_operand (intisa, opc, opnd); + if (!intop) return NULL; + return intop->name; +} + + +int +xtensa_operand_is_visible (xtensa_isa isa, xtensa_opcode opc, int opnd) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + xtensa_iclass_internal *iclass; + int iclass_id, operand_id; + xtensa_operand_internal *intop; + + CHECK_OPCODE (intisa, opc, XTENSA_UNDEFINED); + iclass_id = intisa->opcodes[opc].iclass_id; + iclass = &intisa->iclasses[iclass_id]; + CHECK_OPERAND (intisa, opc, iclass, opnd, XTENSA_UNDEFINED); + + /* Special case for "sout" operands. */ + if (iclass->operands[opnd].inout == 's') + return 0; + + operand_id = iclass->operands[opnd].u.operand_id; + intop = &intisa->operands[operand_id]; + + if ((intop->flags & XTENSA_OPERAND_IS_INVISIBLE) == 0) + return 1; + return 0; +} + + +char +xtensa_operand_inout (xtensa_isa isa, xtensa_opcode opc, int opnd) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + xtensa_iclass_internal *iclass; + int iclass_id; + char inout; + + CHECK_OPCODE (intisa, opc, 0); + iclass_id = intisa->opcodes[opc].iclass_id; + iclass = &intisa->iclasses[iclass_id]; + CHECK_OPERAND (intisa, opc, iclass, opnd, 0); + inout = iclass->operands[opnd].inout; + + /* Special case for "sout" operands. */ + if (inout == 's') + return 'o'; + + return inout; +} + + +int +xtensa_operand_get_field (xtensa_isa isa, xtensa_opcode opc, int opnd, + xtensa_format fmt, int slot, + const xtensa_insnbuf slotbuf, uint32 *valp) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + xtensa_operand_internal *intop; + int slot_id; + xtensa_get_field_fn get_fn; + + intop = get_operand (intisa, opc, opnd); + if (!intop) return -1; + + CHECK_FORMAT (intisa, fmt, -1); + CHECK_SLOT (intisa, fmt, slot, -1); + + slot_id = intisa->formats[fmt].slot_id[slot]; + if (intop->field_id == XTENSA_UNDEFINED) + { + xtisa_errno = xtensa_isa_no_field; + strcpy (xtisa_error_msg, "implicit operand has no field"); + return -1; + } + get_fn = intisa->slots[slot_id].get_field_fns[intop->field_id]; + if (!get_fn) + { + xtisa_errno = xtensa_isa_wrong_slot; + sprintf (xtisa_error_msg, + "operand \"%s\" does not exist in slot %d of format \"%s\"", + intop->name, slot, intisa->formats[fmt].name); + return -1; + } + *valp = (*get_fn) (slotbuf); + return 0; +} + + +int +xtensa_operand_set_field (xtensa_isa isa, xtensa_opcode opc, int opnd, + xtensa_format fmt, int slot, + xtensa_insnbuf slotbuf, uint32 val) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + xtensa_operand_internal *intop; + int slot_id; + xtensa_set_field_fn set_fn; + + intop = get_operand (intisa, opc, opnd); + if (!intop) return -1; + + CHECK_FORMAT (intisa, fmt, -1); + CHECK_SLOT (intisa, fmt, slot, -1); + + slot_id = intisa->formats[fmt].slot_id[slot]; + if (intop->field_id == XTENSA_UNDEFINED) + { + xtisa_errno = xtensa_isa_no_field; + strcpy (xtisa_error_msg, "implicit operand has no field"); + return -1; + } + set_fn = intisa->slots[slot_id].set_field_fns[intop->field_id]; + if (!set_fn) + { + xtisa_errno = xtensa_isa_wrong_slot; + sprintf (xtisa_error_msg, + "operand \"%s\" does not exist in slot %d of format \"%s\"", + intop->name, slot, intisa->formats[fmt].name); + return -1; + } + (*set_fn) (slotbuf, val); + return 0; } -/* ISA information. */ -static int -xtensa_check_isa_config (xtensa_isa_internal *isa, - struct config_struct *config_table) +int +xtensa_operand_encode (xtensa_isa isa, xtensa_opcode opc, int opnd, + uint32 *valp) { - int i, j; - - if (!config_table) - { - fprintf (stderr, "Error: Empty configuration table in ISA DLL\n"); - return 0; - } + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + xtensa_operand_internal *intop; + uint32 test_val, orig_val; - /* For the first module, save a pointer to the table and record the - specified endianness and availability of the density option. */ + intop = get_operand (intisa, opc, opnd); + if (!intop) return -1; - if (isa->num_modules == 0) + if (!intop->encode) { - int found_memory_order = 0; + /* This is a default operand for a field. How can we tell if the + value fits in the field? Write the value into the field, + read it back, and then make sure we get the same value. */ - isa->config = config_table; - isa->has_density = 1; /* Default to have density option. */ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + static xtensa_insnbuf tmpbuf = 0; + int slot_id; - for (i = 0; config_table[i].param_name; i++) + if (!tmpbuf) { - if (!strcmp (config_table[i].param_name, "IsaMemoryOrder")) - { - isa->is_big_endian = - (strcmp (config_table[i].param_value, "BigEndian") == 0); - found_memory_order = 1; - } - if (!strcmp (config_table[i].param_name, "IsaUseDensityInstruction")) - { - isa->has_density = atoi (config_table[i].param_value); - } + tmpbuf = xtensa_insnbuf_alloc (isa); + CHECK_ALLOC (tmpbuf, -1); } - if (!found_memory_order) + + /* A default operand is always associated with a field, + but check just to be sure.... */ + if (intop->field_id == XTENSA_UNDEFINED) { - fprintf (stderr, "Error: \"IsaMemoryOrder\" missing from " - "configuration table in ISA DLL\n"); - return 0; + xtisa_errno = xtensa_isa_internal_error; + strcpy (xtisa_error_msg, "operand has no field"); + return -1; } - return 1; - } - - /* For subsequent modules, check that the parameters match. Note: This - code is sufficient to handle the current model where there are never - more than 2 modules; we might at some point want to handle cases where - module N > 0 specifies some parameters not included in the base table, - and we would then add those to isa->config so that subsequent modules - would check against them. */ - - for (i = 0; config_table[i].param_name; i++) - { - for (j = 0; isa->config[j].param_name; j++) + /* Find some slot that includes the field. */ + for (slot_id = 0; slot_id < intisa->num_slots; slot_id++) { - if (!strcmp (config_table[i].param_name, isa->config[j].param_name)) + xtensa_get_field_fn get_fn = + intisa->slots[slot_id].get_field_fns[intop->field_id]; + xtensa_set_field_fn set_fn = + intisa->slots[slot_id].set_field_fns[intop->field_id]; + + if (get_fn && set_fn) { - int mismatch; - if (!strcmp (config_table[i].param_name, "IsaCoprocessorCount")) - { - /* Only require the coprocessor count to be <= the base. */ - int tiecnt = atoi (config_table[i].param_value); - int basecnt = atoi (isa->config[j].param_value); - mismatch = (tiecnt > basecnt); - } - else - mismatch = strcmp (config_table[i].param_value, - isa->config[j].param_value); - if (mismatch) - { -#define MISMATCH_MESSAGE \ -"Error: Configuration mismatch in the \"%s\" parameter:\n\ -the configuration used when the TIE file was compiled had a value of\n\ -\"%s\", while the current configuration has a value of\n\ -\"%s\". Please rerun the TIE compiler with a matching\n\ -configuration.\n" - fprintf (stderr, MISMATCH_MESSAGE, - config_table[i].param_name, - config_table[i].param_value, - isa->config[j].param_value); - return 0; - } - break; + (*set_fn) (tmpbuf, *valp); + return ((*get_fn) (tmpbuf) != *valp); } } + + /* Couldn't find any slot containing the field.... */ + xtisa_errno = xtensa_isa_no_field; + strcpy (xtisa_error_msg, "field does not exist in any slot"); + return -1; + } + + /* Encode the value. In some cases, the encoding function may detect + errors, but most of the time the only way to determine if the value + was successfully encoded is to decode it and check if it matches + the original value. */ + orig_val = *valp; + if ((*intop->encode) (valp) || + (test_val = *valp, (*intop->decode) (&test_val)) || + test_val != orig_val) + { + xtisa_errno = xtensa_isa_bad_value; + sprintf (xtisa_error_msg, "cannot encode operand value 0x%08x", *valp); + return -1; } - return 1; + return 0; } -static int -xtensa_add_isa (xtensa_isa_internal *isa, libisa_module_specifier libisa) +int +xtensa_operand_decode (xtensa_isa isa, xtensa_opcode opc, int opnd, + uint32 *valp) { - int (*get_num_opcodes_fn) (void); - struct config_struct *(*get_config_table_fn) (void); - xtensa_opcode_internal **(*get_opcodes_fn) (void); - int (*decode_insn_fn) (const xtensa_insnbuf); - xtensa_opcode_internal **opcodes; - int opc, insn_size, prev_num_opcodes, new_num_opcodes, this_module; - - get_num_opcodes_fn = xtensa_isa_modules[libisa].get_num_opcodes_fn; - get_opcodes_fn = xtensa_isa_modules[libisa].get_opcodes_fn; - decode_insn_fn = xtensa_isa_modules[libisa].decode_insn_fn; - get_config_table_fn = xtensa_isa_modules[libisa].get_config_table_fn; + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + xtensa_operand_internal *intop; - if (!get_num_opcodes_fn || !get_opcodes_fn || !decode_insn_fn - || (!get_config_table_fn && isa->num_modules == 0)) - return 0; + intop = get_operand (intisa, opc, opnd); + if (!intop) return -1; - if (get_config_table_fn - && !xtensa_check_isa_config (isa, get_config_table_fn ())) + /* Use identity function for "default" operands. */ + if (!intop->decode) return 0; - prev_num_opcodes = isa->num_opcodes; - new_num_opcodes = (*get_num_opcodes_fn) (); - - isa->num_opcodes += new_num_opcodes; - isa->opcode_table = (xtensa_opcode_internal **) - realloc (isa->opcode_table, isa->num_opcodes * - sizeof (xtensa_opcode_internal *)); - isa->opname_lookup_table = (opname_lookup_entry *) - realloc (isa->opname_lookup_table, isa->num_opcodes * - sizeof (opname_lookup_entry)); - - opcodes = (*get_opcodes_fn) (); - - insn_size = isa->insn_size; - for (opc = 0; opc < new_num_opcodes; opc++) + if ((*intop->decode) (valp)) { - xtensa_opcode_internal *intopc = opcodes[opc]; - int newopc = prev_num_opcodes + opc; - isa->opcode_table[newopc] = intopc; - isa->opname_lookup_table[newopc].key = intopc->name; - isa->opname_lookup_table[newopc].opcode = newopc; - if (intopc->length > insn_size) - insn_size = intopc->length; + xtisa_errno = xtensa_isa_bad_value; + sprintf (xtisa_error_msg, "cannot decode operand value 0x%08x", *valp); + return -1; } + return 0; +} - isa->insn_size = insn_size; - isa->insnbuf_size = ((isa->insn_size + sizeof (xtensa_insnbuf_word) - 1) / - sizeof (xtensa_insnbuf_word)); - qsort (isa->opname_lookup_table, isa->num_opcodes, - sizeof (opname_lookup_entry), opname_lookup_compare); +int +xtensa_operand_is_register (xtensa_isa isa, xtensa_opcode opc, int opnd) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + xtensa_operand_internal *intop; - /* Check for duplicate opcode names. */ - for (opc = 1; opc < isa->num_opcodes; opc++) - { - if (!opname_lookup_compare (&isa->opname_lookup_table[opc-1], - &isa->opname_lookup_table[opc])) - { - fprintf (stderr, "Error: Duplicate TIE opcode \"%s\"\n", - isa->opname_lookup_table[opc].key); - return 0; - } - } + intop = get_operand (intisa, opc, opnd); + if (!intop) return XTENSA_UNDEFINED; - this_module = isa->num_modules; - isa->num_modules += 1; + if ((intop->flags & XTENSA_OPERAND_IS_REGISTER) != 0) + return 1; + return 0; +} - isa->module_opcode_base = (int *) realloc (isa->module_opcode_base, - isa->num_modules * sizeof (int)); - isa->module_decode_fn = (xtensa_insn_decode_fn *) - realloc (isa->module_decode_fn, isa->num_modules * - sizeof (xtensa_insn_decode_fn)); - isa->module_opcode_base[this_module] = prev_num_opcodes; - isa->module_decode_fn[this_module] = decode_insn_fn; +xtensa_regfile +xtensa_operand_regfile (xtensa_isa isa, xtensa_opcode opc, int opnd) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + xtensa_operand_internal *intop; - xtensa_default_isa = isa; + intop = get_operand (intisa, opc, opnd); + if (!intop) return XTENSA_UNDEFINED; - return 1; /* Library was successfully added. */ + return intop->regfile; } -xtensa_isa -xtensa_load_isa (libisa_module_specifier libisa) +int +xtensa_operand_num_regs (xtensa_isa isa, xtensa_opcode opc, int opnd) { - xtensa_isa_internal *isa; + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + xtensa_operand_internal *intop; - isa = (xtensa_isa_internal *) malloc (sizeof (xtensa_isa_internal)); - memset (isa, 0, sizeof (xtensa_isa_internal)); - if (!xtensa_add_isa (isa, libisa)) - { - xtensa_isa_free (isa); - return NULL; - } - return (xtensa_isa) isa; + intop = get_operand (intisa, opc, opnd); + if (!intop) return XTENSA_UNDEFINED; + + return intop->num_regs; } int -xtensa_extend_isa (xtensa_isa isa, libisa_module_specifier libisa) +xtensa_operand_is_known_reg (xtensa_isa isa, xtensa_opcode opc, int opnd) { xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; - return xtensa_add_isa (intisa, libisa); + xtensa_operand_internal *intop; + + intop = get_operand (intisa, opc, opnd); + if (!intop) return XTENSA_UNDEFINED; + + if ((intop->flags & XTENSA_OPERAND_IS_UNKNOWN) == 0) + return 1; + return 0; } -void -xtensa_isa_free (xtensa_isa isa) +int +xtensa_operand_is_PCrelative (xtensa_isa isa, xtensa_opcode opc, int opnd) { xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; - if (intisa->opcode_table) - free (intisa->opcode_table); - if (intisa->opname_lookup_table) - free (intisa->opname_lookup_table); - if (intisa->module_opcode_base) - free (intisa->module_opcode_base); - if (intisa->module_decode_fn) - free (intisa->module_decode_fn); - free (intisa); + xtensa_operand_internal *intop; + + intop = get_operand (intisa, opc, opnd); + if (!intop) return XTENSA_UNDEFINED; + + if ((intop->flags & XTENSA_OPERAND_IS_PCRELATIVE) != 0) + return 1; + return 0; } int -xtensa_insn_maxlength (xtensa_isa isa) +xtensa_operand_do_reloc (xtensa_isa isa, xtensa_opcode opc, int opnd, + uint32 *valp, uint32 pc) { xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; - return intisa->insn_size; + xtensa_operand_internal *intop; + + intop = get_operand (intisa, opc, opnd); + if (!intop) return -1; + + if ((intop->flags & XTENSA_OPERAND_IS_PCRELATIVE) == 0) + return 0; + + if (!intop->do_reloc) + { + xtisa_errno = xtensa_isa_internal_error; + strcpy (xtisa_error_msg, "operand missing do_reloc function"); + return -1; + } + + if ((*intop->do_reloc) (valp, pc)) + { + xtisa_errno = xtensa_isa_bad_value; + sprintf (xtisa_error_msg, + "do_reloc failed for value 0x%08x at PC 0x%08x", *valp, pc); + return -1; + } + + return 0; } int -xtensa_insnbuf_size (xtensa_isa isa) +xtensa_operand_undo_reloc (xtensa_isa isa, xtensa_opcode opc, int opnd, + uint32 *valp, uint32 pc) { - xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; - return intisa->insnbuf_size; + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + xtensa_operand_internal *intop; + + intop = get_operand (intisa, opc, opnd); + if (!intop) return -1; + + if ((intop->flags & XTENSA_OPERAND_IS_PCRELATIVE) == 0) + return 0; + + if (!intop->undo_reloc) + { + xtisa_errno = xtensa_isa_internal_error; + strcpy (xtisa_error_msg, "operand missing undo_reloc function"); + return -1; + } + + if ((*intop->undo_reloc) (valp, pc)) + { + xtisa_errno = xtensa_isa_bad_value; + sprintf (xtisa_error_msg, + "undo_reloc failed for value 0x%08x at PC 0x%08x", *valp, pc); + return -1; + } + + return 0; } -int -xtensa_num_opcodes (xtensa_isa isa) + +/* State Operands. */ + + +#define CHECK_STATE_OPERAND(INTISA,OPC,ICLASS,STOP,ERRVAL) \ + do { \ + if ((STOP) < 0 || (STOP) >= (ICLASS)->num_stateOperands) \ + { \ + xtisa_errno = xtensa_isa_bad_operand; \ + sprintf (xtisa_error_msg, "invalid state operand number (%d); " \ + "opcode \"%s\" has %d state operands", (STOP), \ + (INTISA)->opcodes[(OPC)].name, (ICLASS)->num_stateOperands); \ + return (ERRVAL); \ + } \ + } while (0) + + +xtensa_state +xtensa_stateOperand_state (xtensa_isa isa, xtensa_opcode opc, int stOp) { xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; - return intisa->num_opcodes; + xtensa_iclass_internal *iclass; + int iclass_id; + + CHECK_OPCODE (intisa, opc, XTENSA_UNDEFINED); + iclass_id = intisa->opcodes[opc].iclass_id; + iclass = &intisa->iclasses[iclass_id]; + CHECK_STATE_OPERAND (intisa, opc, iclass, stOp, XTENSA_UNDEFINED); + return iclass->stateOperands[stOp].u.state; } -xtensa_opcode -xtensa_opcode_lookup (xtensa_isa isa, const char *opname) +char +xtensa_stateOperand_inout (xtensa_isa isa, xtensa_opcode opc, int stOp) { xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; - opname_lookup_entry entry, *result; + xtensa_iclass_internal *iclass; + int iclass_id; + + CHECK_OPCODE (intisa, opc, 0); + iclass_id = intisa->opcodes[opc].iclass_id; + iclass = &intisa->iclasses[iclass_id]; + CHECK_STATE_OPERAND (intisa, opc, iclass, stOp, 0); + return iclass->stateOperands[stOp].inout; +} - entry.key = opname; - result = bsearch (&entry, intisa->opname_lookup_table, intisa->num_opcodes, - sizeof (opname_lookup_entry), opname_lookup_compare); - if (!result) return XTENSA_UNDEFINED; - return result->opcode; + +/* Interface Operands. */ + + +#define CHECK_INTERFACE_OPERAND(INTISA,OPC,ICLASS,IFOP,ERRVAL) \ + do { \ + if ((IFOP) < 0 || (IFOP) >= (ICLASS)->num_interfaceOperands) \ + { \ + xtisa_errno = xtensa_isa_bad_operand; \ + sprintf (xtisa_error_msg, "invalid interface operand number (%d); " \ + "opcode \"%s\" has %d interface operands", (IFOP), \ + (INTISA)->opcodes[(OPC)].name, \ + (ICLASS)->num_interfaceOperands); \ + return (ERRVAL); \ + } \ + } while (0) + + +xtensa_interface +xtensa_interfaceOperand_interface (xtensa_isa isa, xtensa_opcode opc, + int ifOp) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + xtensa_iclass_internal *iclass; + int iclass_id; + + CHECK_OPCODE (intisa, opc, XTENSA_UNDEFINED); + iclass_id = intisa->opcodes[opc].iclass_id; + iclass = &intisa->iclasses[iclass_id]; + CHECK_INTERFACE_OPERAND (intisa, opc, iclass, ifOp, XTENSA_UNDEFINED); + return iclass->interfaceOperands[ifOp]; } -xtensa_opcode -xtensa_decode_insn (xtensa_isa isa, const xtensa_insnbuf insn) + +/* Register Files. */ + + +#define CHECK_REGFILE(INTISA,RF,ERRVAL) \ + do { \ + if ((RF) < 0 || (RF) >= (INTISA)->num_regfiles) \ + { \ + xtisa_errno = xtensa_isa_bad_regfile; \ + strcpy (xtisa_error_msg, "invalid regfile specifier"); \ + return (ERRVAL); \ + } \ + } while (0) + + +xtensa_regfile +xtensa_regfile_lookup (xtensa_isa isa, const char *name) { xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; - int n, opc; - for (n = 0; n < intisa->num_modules; n++) { - opc = (intisa->module_decode_fn[n]) (insn); - if (opc != XTENSA_UNDEFINED) - return intisa->module_opcode_base[n] + opc; - } + int n; + + if (!name || !*name) + { + xtisa_errno = xtensa_isa_bad_regfile; + strcpy (xtisa_error_msg, "invalid regfile name"); + return XTENSA_UNDEFINED; + } + + /* The expected number of regfiles is small; use a linear search. */ + for (n = 0; n < intisa->num_regfiles; n++) + { + if (!strcmp (intisa->regfiles[n].name, name)) + return n; + } + + xtisa_errno = xtensa_isa_bad_regfile; + sprintf (xtisa_error_msg, "regfile \"%s\" not recognized", name); return XTENSA_UNDEFINED; } -/* Opcode information. */ - -void -xtensa_encode_insn (xtensa_isa isa, xtensa_opcode opc, xtensa_insnbuf insn) +xtensa_regfile +xtensa_regfile_lookup_shortname (xtensa_isa isa, const char *shortname) { xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; - xtensa_insnbuf template = intisa->opcode_table[opc]->template(); - int len = intisa->opcode_table[opc]->length; int n; - /* Convert length to 32-bit words. */ - len = (len + 3) / 4; + if (!shortname || !*shortname) + { + xtisa_errno = xtensa_isa_bad_regfile; + strcpy (xtisa_error_msg, "invalid regfile shortname"); + return XTENSA_UNDEFINED; + } - /* Copy the template. */ - for (n = 0; n < len; n++) - insn[n] = template[n]; + /* The expected number of regfiles is small; use a linear search. */ + for (n = 0; n < intisa->num_regfiles; n++) + { + /* Ignore regfile views since they always have the same shortnames + as their parents. */ + if (intisa->regfiles[n].parent != n) + continue; + if (!strcmp (intisa->regfiles[n].shortname, shortname)) + return n; + } - /* Fill any unused buffer space with zeros. */ - for ( ; n < intisa->insnbuf_size; n++) - insn[n] = 0; + xtisa_errno = xtensa_isa_bad_regfile; + sprintf (xtisa_error_msg, "regfile shortname \"%s\" not recognized", + shortname); + return XTENSA_UNDEFINED; } const char * -xtensa_opcode_name (xtensa_isa isa, xtensa_opcode opc) +xtensa_regfile_name (xtensa_isa isa, xtensa_regfile rf) { xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; - return intisa->opcode_table[opc]->name; + CHECK_REGFILE (intisa, rf, NULL); + return intisa->regfiles[rf].name; } -int -xtensa_insn_length (xtensa_isa isa, xtensa_opcode opc) +const char * +xtensa_regfile_shortname (xtensa_isa isa, xtensa_regfile rf) { xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; - return intisa->opcode_table[opc]->length; + CHECK_REGFILE (intisa, rf, NULL); + return intisa->regfiles[rf].shortname; } -int -xtensa_insn_length_from_first_byte (xtensa_isa isa, char first_byte) +xtensa_regfile +xtensa_regfile_view_parent (xtensa_isa isa, xtensa_regfile rf) { xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; - int is_density = (first_byte & (intisa->is_big_endian ? 0x80 : 0x08)) != 0; - return (intisa->has_density && is_density ? 2 : 3); + CHECK_REGFILE (intisa, rf, XTENSA_UNDEFINED); + return intisa->regfiles[rf].parent; } int -xtensa_num_operands (xtensa_isa isa, xtensa_opcode opc) +xtensa_regfile_num_bits (xtensa_isa isa, xtensa_regfile rf) { xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; - return intisa->opcode_table[opc]->iclass->num_operands; + CHECK_REGFILE (intisa, rf, XTENSA_UNDEFINED); + return intisa->regfiles[rf].num_bits; } -xtensa_operand -xtensa_get_operand (xtensa_isa isa, xtensa_opcode opc, int opnd) +int +xtensa_regfile_num_entries (xtensa_isa isa, xtensa_regfile rf) { xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; - xtensa_iclass_internal *iclass = intisa->opcode_table[opc]->iclass; - if (opnd >= iclass->num_operands) - return NULL; - return (xtensa_operand) iclass->operands[opnd]; + CHECK_REGFILE (intisa, rf, XTENSA_UNDEFINED); + return intisa->regfiles[rf].num_entries; } + +/* Processor States. */ -/* Operand information. */ -char * -xtensa_operand_kind (xtensa_operand opnd) -{ - xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd; - return intop->operand_kind; -} +#define CHECK_STATE(INTISA,ST,ERRVAL) \ + do { \ + if ((ST) < 0 || (ST) >= (INTISA)->num_states) \ + { \ + xtisa_errno = xtensa_isa_bad_state; \ + strcpy (xtisa_error_msg, "invalid state specifier"); \ + return (ERRVAL); \ + } \ + } while (0) -char -xtensa_operand_inout (xtensa_operand opnd) +xtensa_state +xtensa_state_lookup (xtensa_isa isa, const char *name) { - xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd; - return intop->inout; -} + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + xtensa_lookup_entry entry, *result; + if (!name || !*name) + { + xtisa_errno = xtensa_isa_bad_state; + strcpy (xtisa_error_msg, "invalid state name"); + return XTENSA_UNDEFINED; + } -uint32 -xtensa_operand_get_field (xtensa_operand opnd, const xtensa_insnbuf insn) -{ - xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd; - return (*intop->get_field) (insn); -} + entry.key = name; + result = bsearch (&entry, intisa->state_lookup_table, intisa->num_states, + sizeof (xtensa_lookup_entry), xtensa_isa_name_compare); + if (!result) + { + xtisa_errno = xtensa_isa_bad_state; + sprintf (xtisa_error_msg, "state \"%s\" not recognized", name); + return XTENSA_UNDEFINED; + } -void -xtensa_operand_set_field (xtensa_operand opnd, xtensa_insnbuf insn, uint32 val) -{ - xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd; - return (*intop->set_field) (insn, val); + return result->u.state; } -xtensa_encode_result -xtensa_operand_encode (xtensa_operand opnd, uint32 *valp) +const char * +xtensa_state_name (xtensa_isa isa, xtensa_state st) { - xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd; - return (*intop->encode) (valp); + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + CHECK_STATE (intisa, st, NULL); + return intisa->states[st].name; } -uint32 -xtensa_operand_decode (xtensa_operand opnd, uint32 val) +int +xtensa_state_num_bits (xtensa_isa isa, xtensa_state st) { - xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd; - return (*intop->decode) (val); + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + CHECK_STATE (intisa, st, XTENSA_UNDEFINED); + return intisa->states[st].num_bits; } int -xtensa_operand_isPCRelative (xtensa_operand opnd) +xtensa_state_is_exported (xtensa_isa isa, xtensa_state st) { - xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd; - return intop->isPCRelative; + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + CHECK_STATE (intisa, st, XTENSA_UNDEFINED); + if ((intisa->states[st].flags & XTENSA_STATE_IS_EXPORTED) != 0) + return 1; + return 0; } + +/* Sysregs. */ + + +#define CHECK_SYSREG(INTISA,SYSREG,ERRVAL) \ + do { \ + if ((SYSREG) < 0 || (SYSREG) >= (INTISA)->num_sysregs) \ + { \ + xtisa_errno = xtensa_isa_bad_sysreg; \ + strcpy (xtisa_error_msg, "invalid sysreg specifier"); \ + return (ERRVAL); \ + } \ + } while (0) -uint32 -xtensa_operand_do_reloc (xtensa_operand opnd, uint32 addr, uint32 pc) + +xtensa_sysreg +xtensa_sysreg_lookup (xtensa_isa isa, int num, int is_user) { - xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd; - if (!intop->isPCRelative) - return addr; - return (*intop->do_reloc) (addr, pc); + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + + if (is_user != 0) + is_user = 1; + + if (num < 0 || num > intisa->max_sysreg_num[is_user] + || intisa->sysreg_table[is_user][num] == XTENSA_UNDEFINED) + { + xtisa_errno = xtensa_isa_bad_sysreg; + strcpy (xtisa_error_msg, "sysreg not recognized"); + return XTENSA_UNDEFINED; + } + + return intisa->sysreg_table[is_user][num]; } -uint32 -xtensa_operand_undo_reloc (xtensa_operand opnd, uint32 offset, uint32 pc) +xtensa_sysreg +xtensa_sysreg_lookup_name (xtensa_isa isa, const char *name) { - xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd; - if (!intop->isPCRelative) - return offset; - return (*intop->undo_reloc) (offset, pc); -} + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + xtensa_lookup_entry entry, *result; + if (!name || !*name) + { + xtisa_errno = xtensa_isa_bad_sysreg; + strcpy (xtisa_error_msg, "invalid sysreg name"); + return XTENSA_UNDEFINED; + } -/* Instruction buffers. */ + entry.key = name; + result = bsearch (&entry, intisa->sysreg_lookup_table, intisa->num_sysregs, + sizeof (xtensa_lookup_entry), xtensa_isa_name_compare); -xtensa_insnbuf -xtensa_insnbuf_alloc (xtensa_isa isa) -{ - return (xtensa_insnbuf) malloc (xtensa_insnbuf_size (isa) * - sizeof (xtensa_insnbuf_word)); + if (!result) + { + xtisa_errno = xtensa_isa_bad_sysreg; + sprintf (xtisa_error_msg, "sysreg \"%s\" not recognized", name); + return XTENSA_UNDEFINED; + } + + return result->u.sysreg; } -void -xtensa_insnbuf_free (xtensa_insnbuf buf) +const char * +xtensa_sysreg_name (xtensa_isa isa, xtensa_sysreg sysreg) { - free( buf ); + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + CHECK_SYSREG (intisa, sysreg, NULL); + return intisa->sysregs[sysreg].name; } -/* Given , the index of a byte in a xtensa_insnbuf, our - internal representation of a xtensa instruction word, return the index of - its word and the bit index of its low order byte in the xtensa_insnbuf. */ - -static inline int -byte_to_word_index (int byte_index) +int +xtensa_sysreg_number (xtensa_isa isa, xtensa_sysreg sysreg) { - return byte_index / sizeof (xtensa_insnbuf_word); + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + CHECK_SYSREG (intisa, sysreg, XTENSA_UNDEFINED); + return intisa->sysregs[sysreg].number; } -static inline int -byte_to_bit_index (int byte_index) +int +xtensa_sysreg_is_user (xtensa_isa isa, xtensa_sysreg sysreg) { - return (byte_index & 0x3) * 8; + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + CHECK_SYSREG (intisa, sysreg, XTENSA_UNDEFINED); + if (intisa->sysregs[sysreg].is_user) + return 1; + return 0; } + +/* Interfaces. */ -/* Copy an instruction in the 32 bit words pointed at by to characters - pointed at by . This is more complicated than you might think because - we want 16 bit instructions in bytes 2,3 for big endian. This function - allows us to specify which byte in to start with and which way to - increment, allowing trivial implementation for both big and little endian. - And it seems to make pretty good code for both. */ -void -xtensa_insnbuf_to_chars (xtensa_isa isa, const xtensa_insnbuf insn, char *cp) +#define CHECK_INTERFACE(INTISA,INTF,ERRVAL) \ + do { \ + if ((INTF) < 0 || (INTF) >= (INTISA)->num_interfaces) \ + { \ + xtisa_errno = xtensa_isa_bad_interface; \ + strcpy (xtisa_error_msg, "invalid interface specifier"); \ + return (ERRVAL); \ + } \ + } while (0) + + +xtensa_interface +xtensa_interface_lookup (xtensa_isa isa, const char *ifname) { xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; - int insn_size = xtensa_insn_maxlength (intisa); - int fence_post, start, increment, i, byte_count; - xtensa_opcode opc; + xtensa_lookup_entry entry, *result; - if (intisa->is_big_endian) + if (!ifname || !*ifname) { - start = insn_size - 1; - increment = -1; + xtisa_errno = xtensa_isa_bad_interface; + strcpy (xtisa_error_msg, "invalid interface name"); + return XTENSA_UNDEFINED; } - else + + entry.key = ifname; + result = bsearch (&entry, intisa->interface_lookup_table, + intisa->num_interfaces, + sizeof (xtensa_lookup_entry), xtensa_isa_name_compare); + + if (!result) { - start = 0; - increment = 1; + xtisa_errno = xtensa_isa_bad_interface; + sprintf (xtisa_error_msg, "interface \"%s\" not recognized", ifname); + return XTENSA_UNDEFINED; } - /* Find the opcode; do nothing if the buffer does not contain a valid - instruction since we need to know how many bytes to copy. */ - opc = xtensa_decode_insn (isa, insn); - if (opc == XTENSA_UNDEFINED) - return; + return result->u.intf; +} - byte_count = xtensa_insn_length (isa, opc); - fence_post = start + (byte_count * increment); - for (i = start; i != fence_post; i += increment, ++cp) - { - int word_inx = byte_to_word_index (i); - int bit_inx = byte_to_bit_index (i); +const char * +xtensa_interface_name (xtensa_isa isa, xtensa_interface intf) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + CHECK_INTERFACE (intisa, intf, NULL); + return intisa->interfaces[intf].name; +} - *cp = (insn[word_inx] >> bit_inx) & 0xff; - } + +int +xtensa_interface_num_bits (xtensa_isa isa, xtensa_interface intf) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + CHECK_INTERFACE (intisa, intf, XTENSA_UNDEFINED); + return intisa->interfaces[intf].num_bits; } -/* Inward conversion from byte stream to xtensa_insnbuf. See - xtensa_insnbuf_to_chars for a discussion of why this is - complicated by endianness. */ - -void -xtensa_insnbuf_from_chars (xtensa_isa isa, xtensa_insnbuf insn, const char* cp) + +char +xtensa_interface_inout (xtensa_isa isa, xtensa_interface intf) { xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; - int insn_size = xtensa_insn_maxlength (intisa); - int fence_post, start, increment, i; + CHECK_INTERFACE (intisa, intf, 0); + return intisa->interfaces[intf].inout; +} - if (intisa->is_big_endian) + +int +xtensa_interface_has_side_effect (xtensa_isa isa, xtensa_interface intf) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + CHECK_INTERFACE (intisa, intf, XTENSA_UNDEFINED); + if ((intisa->interfaces[intf].flags & XTENSA_INTERFACE_HAS_SIDE_EFFECT) != 0) + return 1; + return 0; +} + + +/* Functional Units. */ + + +#define CHECK_FUNCUNIT(INTISA,FUN,ERRVAL) \ + do { \ + if ((FUN) < 0 || (FUN) >= (INTISA)->num_funcUnits) \ + { \ + xtisa_errno = xtensa_isa_bad_funcUnit; \ + strcpy (xtisa_error_msg, "invalid functional unit specifier"); \ + return (ERRVAL); \ + } \ + } while (0) + + +xtensa_funcUnit +xtensa_funcUnit_lookup (xtensa_isa isa, const char *fname) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + xtensa_lookup_entry entry, *result; + + if (!fname || !*fname) { - start = insn_size - 1; - increment = -1; + xtisa_errno = xtensa_isa_bad_funcUnit; + strcpy (xtisa_error_msg, "invalid functional unit name"); + return XTENSA_UNDEFINED; } - else + + entry.key = fname; + result = bsearch (&entry, intisa->funcUnit_lookup_table, + intisa->num_funcUnits, + sizeof (xtensa_lookup_entry), xtensa_isa_name_compare); + + if (!result) { - start = 0; - increment = 1; + xtisa_errno = xtensa_isa_bad_funcUnit; + sprintf (xtisa_error_msg, + "functional unit \"%s\" not recognized", fname); + return XTENSA_UNDEFINED; } - fence_post = start + (insn_size * increment); - memset (insn, 0, xtensa_insnbuf_size (isa) * sizeof (xtensa_insnbuf_word)); + return result->u.fun; +} - for ( i = start; i != fence_post; i += increment, ++cp ) - { - int word_inx = byte_to_word_index (i); - int bit_inx = byte_to_bit_index (i); - insn[word_inx] |= (*cp & 0xff) << bit_inx; - } +const char * +xtensa_funcUnit_name (xtensa_isa isa, xtensa_funcUnit fun) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + CHECK_FUNCUNIT (intisa, fun, NULL); + return intisa->funcUnits[fun].name; +} + + +int +xtensa_funcUnit_num_copies (xtensa_isa isa, xtensa_funcUnit fun) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + CHECK_FUNCUNIT (intisa, fun, XTENSA_UNDEFINED); + return intisa->funcUnits[fun].num_copies; } diff --git a/bfd/xtensa-modules.c b/bfd/xtensa-modules.c index e5d7682f09a..bc0cf734c4c 100644 --- a/bfd/xtensa-modules.c +++ b/bfd/xtensa-modules.c @@ -1,6088 +1,9101 @@ /* Xtensa configuration-specific ISA information. - Copyright 2003 Free Software Foundation, Inc. + Copyright 2003, 2004 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ +#include "ansidecl.h" #include #include "xtensa-isa-internal.h" -#include "ansidecl.h" - -#define BPW 32 -#define WINDEX(_n) ((_n) / BPW) -#define BINDEX(_n) ((_n) %% BPW) - -static uint32 tie_do_reloc_l (uint32, uint32) ATTRIBUTE_UNUSED; -static uint32 tie_undo_reloc_l (uint32, uint32) ATTRIBUTE_UNUSED; - -static uint32 -tie_do_reloc_l (uint32 addr, uint32 pc) -{ - return (addr - pc); -} - -static uint32 -tie_undo_reloc_l (uint32 offset, uint32 pc) -{ - return (pc + offset); -} - -xtensa_opcode_internal** get_opcodes (void); -int get_num_opcodes (void); -int decode_insn (const xtensa_insnbuf); -int interface_version (void); - -uint32 get_bbi_field (const xtensa_insnbuf); -void set_bbi_field (xtensa_insnbuf, uint32); -uint32 get_bbi4_field (const xtensa_insnbuf); -void set_bbi4_field (xtensa_insnbuf, uint32); -uint32 get_i_field (const xtensa_insnbuf); -void set_i_field (xtensa_insnbuf, uint32); -uint32 get_imm12_field (const xtensa_insnbuf); -void set_imm12_field (xtensa_insnbuf, uint32); -uint32 get_imm12b_field (const xtensa_insnbuf); -void set_imm12b_field (xtensa_insnbuf, uint32); -uint32 get_imm16_field (const xtensa_insnbuf); -void set_imm16_field (xtensa_insnbuf, uint32); -uint32 get_imm4_field (const xtensa_insnbuf); -void set_imm4_field (xtensa_insnbuf, uint32); -uint32 get_imm6_field (const xtensa_insnbuf); -void set_imm6_field (xtensa_insnbuf, uint32); -uint32 get_imm6hi_field (const xtensa_insnbuf); -void set_imm6hi_field (xtensa_insnbuf, uint32); -uint32 get_imm6lo_field (const xtensa_insnbuf); -void set_imm6lo_field (xtensa_insnbuf, uint32); -uint32 get_imm7_field (const xtensa_insnbuf); -void set_imm7_field (xtensa_insnbuf, uint32); -uint32 get_imm7hi_field (const xtensa_insnbuf); -void set_imm7hi_field (xtensa_insnbuf, uint32); -uint32 get_imm7lo_field (const xtensa_insnbuf); -void set_imm7lo_field (xtensa_insnbuf, uint32); -uint32 get_imm8_field (const xtensa_insnbuf); -void set_imm8_field (xtensa_insnbuf, uint32); -uint32 get_m_field (const xtensa_insnbuf); -void set_m_field (xtensa_insnbuf, uint32); -uint32 get_mn_field (const xtensa_insnbuf); -void set_mn_field (xtensa_insnbuf, uint32); -uint32 get_n_field (const xtensa_insnbuf); -void set_n_field (xtensa_insnbuf, uint32); -uint32 get_none_field (const xtensa_insnbuf); -void set_none_field (xtensa_insnbuf, uint32); -uint32 get_offset_field (const xtensa_insnbuf); -void set_offset_field (xtensa_insnbuf, uint32); -uint32 get_op0_field (const xtensa_insnbuf); -void set_op0_field (xtensa_insnbuf, uint32); -uint32 get_op1_field (const xtensa_insnbuf); -void set_op1_field (xtensa_insnbuf, uint32); -uint32 get_op2_field (const xtensa_insnbuf); -void set_op2_field (xtensa_insnbuf, uint32); -uint32 get_r_field (const xtensa_insnbuf); -void set_r_field (xtensa_insnbuf, uint32); -uint32 get_s_field (const xtensa_insnbuf); -void set_s_field (xtensa_insnbuf, uint32); -uint32 get_sa4_field (const xtensa_insnbuf); -void set_sa4_field (xtensa_insnbuf, uint32); -uint32 get_sae_field (const xtensa_insnbuf); -void set_sae_field (xtensa_insnbuf, uint32); -uint32 get_sae4_field (const xtensa_insnbuf); -void set_sae4_field (xtensa_insnbuf, uint32); -uint32 get_sal_field (const xtensa_insnbuf); -void set_sal_field (xtensa_insnbuf, uint32); -uint32 get_sar_field (const xtensa_insnbuf); -void set_sar_field (xtensa_insnbuf, uint32); -uint32 get_sas_field (const xtensa_insnbuf); -void set_sas_field (xtensa_insnbuf, uint32); -uint32 get_sas4_field (const xtensa_insnbuf); -void set_sas4_field (xtensa_insnbuf, uint32); -uint32 get_sr_field (const xtensa_insnbuf); -void set_sr_field (xtensa_insnbuf, uint32); -uint32 get_t_field (const xtensa_insnbuf); -void set_t_field (xtensa_insnbuf, uint32); -uint32 get_thi3_field (const xtensa_insnbuf); -void set_thi3_field (xtensa_insnbuf, uint32); -uint32 get_z_field (const xtensa_insnbuf); -void set_z_field (xtensa_insnbuf, uint32); - -uint32 -get_bbi_field (const xtensa_insnbuf insn) + +/* Sysregs. */ + +static xtensa_sysreg_internal sysregs[] = { + { "LBEG", 0, 0 }, + { "LEND", 1, 0 }, + { "LCOUNT", 2, 0 }, + { "DDR", 104, 0 }, + { "176", 176, 0 }, + { "208", 208, 0 }, + { "INTERRUPT", 226, 0 }, + { "INTCLEAR", 227, 0 }, + { "CCOUNT", 234, 0 }, + { "PRID", 235, 0 }, + { "ICOUNT", 236, 0 }, + { "CCOMPARE0", 240, 0 }, + { "CCOMPARE1", 241, 0 }, + { "CCOMPARE2", 242, 0 }, + { "EPC1", 177, 0 }, + { "EPC2", 178, 0 }, + { "EPC3", 179, 0 }, + { "EPC4", 180, 0 }, + { "EXCSAVE1", 209, 0 }, + { "EXCSAVE2", 210, 0 }, + { "EXCSAVE3", 211, 0 }, + { "EXCSAVE4", 212, 0 }, + { "EPS2", 194, 0 }, + { "EPS3", 195, 0 }, + { "EPS4", 196, 0 }, + { "EXCCAUSE", 232, 0 }, + { "DEPC", 192, 0 }, + { "EXCVADDR", 238, 0 }, + { "WINDOWBASE", 72, 0 }, + { "WINDOWSTART", 73, 0 }, + { "SAR", 3, 0 }, + { "LITBASE", 5, 0 }, + { "PS", 230, 0 }, + { "MISC0", 244, 0 }, + { "MISC1", 245, 0 }, + { "INTENABLE", 228, 0 }, + { "DBREAKA0", 144, 0 }, + { "DBREAKC0", 160, 0 }, + { "DBREAKA1", 145, 0 }, + { "DBREAKC1", 161, 0 }, + { "IBREAKA0", 128, 0 }, + { "IBREAKA1", 129, 0 }, + { "IBREAKENABLE", 96, 0 }, + { "ICOUNTLEVEL", 237, 0 }, + { "DEBUGCAUSE", 233, 0 } +}; + +#define NUM_SYSREGS 45 +#define MAX_SPECIAL_REG 245 +#define MAX_USER_REG 0 + + +/* Processor states. */ + +static xtensa_state_internal states[] = { + { "LCOUNT", 32, 0 }, + { "PC", 32, 0 }, + { "ICOUNT", 32, 0 }, + { "DDR", 32, 0 }, + { "INTERRUPT", 17, 0 }, + { "CCOUNT", 32, 0 }, + { "XTSYNC", 1, 0 }, + { "EPC1", 32, 0 }, + { "EPC2", 32, 0 }, + { "EPC3", 32, 0 }, + { "EPC4", 32, 0 }, + { "EXCSAVE1", 32, 0 }, + { "EXCSAVE2", 32, 0 }, + { "EXCSAVE3", 32, 0 }, + { "EXCSAVE4", 32, 0 }, + { "EPS2", 13, 0 }, + { "EPS3", 13, 0 }, + { "EPS4", 13, 0 }, + { "EXCCAUSE", 6, 0 }, + { "PSINTLEVEL", 4, 0 }, + { "PSUM", 1, 0 }, + { "PSWOE", 1, 0 }, + { "PSEXCM", 1, 0 }, + { "DEPC", 32, 0 }, + { "EXCVADDR", 32, 0 }, + { "WindowBase", 4, 0 }, + { "WindowStart", 16, 0 }, + { "PSCALLINC", 2, 0 }, + { "PSOWB", 4, 0 }, + { "LBEG", 32, 0 }, + { "LEND", 32, 0 }, + { "SAR", 6, 0 }, + { "LITBADDR", 20, 0 }, + { "LITBEN", 1, 0 }, + { "MISC0", 32, 0 }, + { "MISC1", 32, 0 }, + { "InOCDMode", 1, 0 }, + { "INTENABLE", 17, 0 }, + { "DBREAKA0", 32, 0 }, + { "DBREAKC0", 8, 0 }, + { "DBREAKA1", 32, 0 }, + { "DBREAKC1", 8, 0 }, + { "IBREAKA0", 32, 0 }, + { "IBREAKA1", 32, 0 }, + { "IBREAKENABLE", 2, 0 }, + { "ICOUNTLEVEL", 4, 0 }, + { "DEBUGCAUSE", 6, 0 }, + { "DBNUM", 4, 0 }, + { "CCOMPARE0", 32, 0 }, + { "CCOMPARE1", 32, 0 }, + { "CCOMPARE2", 32, 0 } +}; + +#define NUM_STATES 51 + +/* Macros for xtensa_state numbers (for use in iclasses because the + state numbers are not available when the iclass table is generated). */ + +#define STATE_LCOUNT 0 +#define STATE_PC 1 +#define STATE_ICOUNT 2 +#define STATE_DDR 3 +#define STATE_INTERRUPT 4 +#define STATE_CCOUNT 5 +#define STATE_XTSYNC 6 +#define STATE_EPC1 7 +#define STATE_EPC2 8 +#define STATE_EPC3 9 +#define STATE_EPC4 10 +#define STATE_EXCSAVE1 11 +#define STATE_EXCSAVE2 12 +#define STATE_EXCSAVE3 13 +#define STATE_EXCSAVE4 14 +#define STATE_EPS2 15 +#define STATE_EPS3 16 +#define STATE_EPS4 17 +#define STATE_EXCCAUSE 18 +#define STATE_PSINTLEVEL 19 +#define STATE_PSUM 20 +#define STATE_PSWOE 21 +#define STATE_PSEXCM 22 +#define STATE_DEPC 23 +#define STATE_EXCVADDR 24 +#define STATE_WindowBase 25 +#define STATE_WindowStart 26 +#define STATE_PSCALLINC 27 +#define STATE_PSOWB 28 +#define STATE_LBEG 29 +#define STATE_LEND 30 +#define STATE_SAR 31 +#define STATE_LITBADDR 32 +#define STATE_LITBEN 33 +#define STATE_MISC0 34 +#define STATE_MISC1 35 +#define STATE_InOCDMode 36 +#define STATE_INTENABLE 37 +#define STATE_DBREAKA0 38 +#define STATE_DBREAKC0 39 +#define STATE_DBREAKA1 40 +#define STATE_DBREAKC1 41 +#define STATE_IBREAKA0 42 +#define STATE_IBREAKA1 43 +#define STATE_IBREAKENABLE 44 +#define STATE_ICOUNTLEVEL 45 +#define STATE_DEBUGCAUSE 46 +#define STATE_DBNUM 47 +#define STATE_CCOMPARE0 48 +#define STATE_CCOMPARE1 49 +#define STATE_CCOMPARE2 50 + + +/* Field definitions. */ + +static unsigned +Field_t_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 12) >> 28); + return tie_t; +} + +static void +Field_t_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0000) | (tie_t << 16); +} + +static unsigned +Field_s_Slot_inst_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0xf0000) >> 16) | - ((insn[0] & 0x100) >> 4); + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; } -void -set_bbi_field (xtensa_insnbuf insn, uint32 val) +static void +Field_s_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xfff0ffff) | ((val << 16) & 0xf0000); - insn[0] = (insn[0] & 0xfffffeff) | ((val << 4) & 0x100); + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); } -uint32 -get_bbi4_field (const xtensa_insnbuf insn) +static unsigned +Field_r_Slot_inst_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0x100) >> 8); + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; } -void -set_bbi4_field (xtensa_insnbuf insn, uint32 val) +static void +Field_r_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xfffffeff) | ((val << 8) & 0x100); + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); } -uint32 -get_i_field (const xtensa_insnbuf insn) +static unsigned +Field_op2_Slot_inst_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0x80000) >> 19); + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; } -void -set_i_field (xtensa_insnbuf insn, uint32 val) +static void +Field_op2_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xfff7ffff) | ((val << 19) & 0x80000); + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); } -uint32 -get_imm12_field (const xtensa_insnbuf insn) +static unsigned +Field_op1_Slot_inst_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0xfff)); + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; } -void -set_imm12_field (xtensa_insnbuf insn, uint32 val) +static void +Field_op1_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xfffff000) | (val & 0xfff); + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); } -uint32 -get_imm12b_field (const xtensa_insnbuf insn) +static unsigned +Field_op0_Slot_inst_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0xff)) | - ((insn[0] & 0xf000) >> 4); + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 8) >> 28); + return tie_t; } -void -set_imm12b_field (xtensa_insnbuf insn, uint32 val) +static void +Field_op0_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xffffff00) | (val & 0xff); - insn[0] = (insn[0] & 0xffff0fff) | ((val << 4) & 0xf000); + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00000) | (tie_t << 20); } -uint32 -get_imm16_field (const xtensa_insnbuf insn) +static unsigned +Field_n_Slot_inst_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0xffff)); + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 12) >> 30); + return tie_t; } -void -set_imm16_field (xtensa_insnbuf insn, uint32 val) +static void +Field_n_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xffff0000) | (val & 0xffff); + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0xc0000) | (tie_t << 18); } -uint32 -get_imm4_field (const xtensa_insnbuf insn) +static unsigned +Field_m_Slot_inst_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0xf00) >> 8); + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 14) >> 30); + return tie_t; } -void -set_imm4_field (xtensa_insnbuf insn, uint32 val) +static void +Field_m_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xfffff0ff) | ((val << 8) & 0xf00); + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x30000) | (tie_t << 16); } -uint32 -get_imm6_field (const xtensa_insnbuf insn) +static unsigned +Field_sr_Slot_inst_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0xf00) >> 8) | - ((insn[0] & 0x30000) >> 12); + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; } -void -set_imm6_field (xtensa_insnbuf insn, uint32 val) +static void +Field_sr_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xfffff0ff) | ((val << 8) & 0xf00); - insn[0] = (insn[0] & 0xfffcffff) | ((val << 12) & 0x30000); + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); } -uint32 -get_imm6hi_field (const xtensa_insnbuf insn) +static unsigned +Field_thi3_Slot_inst_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0x30000) >> 16); + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 12) >> 29); + return tie_t; } -void -set_imm6hi_field (xtensa_insnbuf insn, uint32 val) +static void +Field_thi3_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xfffcffff) | ((val << 16) & 0x30000); + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe0000) | (tie_t << 17); } -uint32 -get_imm6lo_field (const xtensa_insnbuf insn) +static unsigned +Field_op0_Slot_inst16a_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0xf00) >> 8); + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; } -void -set_imm6lo_field (xtensa_insnbuf insn, uint32 val) +static void +Field_op0_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xfffff0ff) | ((val << 8) & 0xf00); + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); } -uint32 -get_imm7_field (const xtensa_insnbuf insn) +static unsigned +Field_t_Slot_inst16b_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0xf00) >> 8) | - ((insn[0] & 0x70000) >> 12); + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; } -void -set_imm7_field (xtensa_insnbuf insn, uint32 val) +static void +Field_t_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xfffff0ff) | ((val << 8) & 0xf00); - insn[0] = (insn[0] & 0xfff8ffff) | ((val << 12) & 0x70000); + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); } -uint32 -get_imm7hi_field (const xtensa_insnbuf insn) +static unsigned +Field_r_Slot_inst16b_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0x70000) >> 16); + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; } -void -set_imm7hi_field (xtensa_insnbuf insn, uint32 val) +static void +Field_r_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xfff8ffff) | ((val << 16) & 0x70000); + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); } -uint32 -get_imm7lo_field (const xtensa_insnbuf insn) +static unsigned +Field_op0_Slot_inst16b_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0xf00) >> 8); + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; } -void -set_imm7lo_field (xtensa_insnbuf insn, uint32 val) +static void +Field_op0_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xfffff0ff) | ((val << 8) & 0xf00); + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); } -uint32 -get_imm8_field (const xtensa_insnbuf insn) +static unsigned +Field_z_Slot_inst16b_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0xff)); + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 21) >> 31); + return tie_t; } -void -set_imm8_field (xtensa_insnbuf insn, uint32 val) +static void +Field_z_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xffffff00) | (val & 0xff); + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x400) | (tie_t << 10); } -uint32 -get_m_field (const xtensa_insnbuf insn) +static unsigned +Field_i_Slot_inst16b_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0x30000) >> 16); + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 20) >> 31); + return tie_t; } -void -set_m_field (xtensa_insnbuf insn, uint32 val) +static void +Field_i_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xfffcffff) | ((val << 16) & 0x30000); + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x800) | (tie_t << 11); } -uint32 -get_mn_field (const xtensa_insnbuf insn) +static unsigned +Field_s_Slot_inst16b_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0x30000) >> 16) | - ((insn[0] & 0xc0000) >> 16); + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; } -void -set_mn_field (xtensa_insnbuf insn, uint32 val) +static void +Field_s_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xfffcffff) | ((val << 16) & 0x30000); - insn[0] = (insn[0] & 0xfff3ffff) | ((val << 16) & 0xc0000); + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); } -uint32 -get_n_field (const xtensa_insnbuf insn) +static unsigned +Field_t_Slot_inst16a_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0xc0000) >> 18); + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; } -void -set_n_field (xtensa_insnbuf insn, uint32 val) +static void +Field_t_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xfff3ffff) | ((val << 18) & 0xc0000); + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); } -uint32 -get_none_field (const xtensa_insnbuf insn) +static unsigned +Field_bbi4_Slot_inst_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0x0)); + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 23) >> 31); + return tie_t; } -void -set_none_field (xtensa_insnbuf insn, uint32 val) +static void +Field_bbi4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xffffffff) | (val & 0x0); + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x100) | (tie_t << 8); } -uint32 -get_offset_field (const xtensa_insnbuf insn) +static unsigned +Field_bbi_Slot_inst_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0x3ffff)); + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 23) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 12) >> 28); + return tie_t; } -void -set_offset_field (xtensa_insnbuf insn, uint32 val) +static void +Field_bbi_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xfffc0000) | (val & 0x3ffff); + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0000) | (tie_t << 16); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x100) | (tie_t << 8); } -uint32 -get_op0_field (const xtensa_insnbuf insn) +static unsigned +Field_imm12_Slot_inst_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0xf00000) >> 20); + unsigned tie_t = 0; + tie_t = (tie_t << 12) | ((insn[0] << 20) >> 20); + return tie_t; } -void -set_op0_field (xtensa_insnbuf insn, uint32 val) +static void +Field_imm12_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xff0fffff) | ((val << 20) & 0xf00000); + uint32 tie_t; + tie_t = (val << 20) >> 20; + insn[0] = (insn[0] & ~0xfff) | (tie_t << 0); } -uint32 -get_op1_field (const xtensa_insnbuf insn) +static unsigned +Field_imm8_Slot_inst_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0xf0) >> 4); + unsigned tie_t = 0; + tie_t = (tie_t << 8) | ((insn[0] << 24) >> 24); + return tie_t; } -void -set_op1_field (xtensa_insnbuf insn, uint32 val) +static void +Field_imm8_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xffffff0f) | ((val << 4) & 0xf0); + uint32 tie_t; + tie_t = (val << 24) >> 24; + insn[0] = (insn[0] & ~0xff) | (tie_t << 0); } -uint32 -get_op2_field (const xtensa_insnbuf insn) +static unsigned +Field_s_Slot_inst16a_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0xf)); + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; } -void -set_op2_field (xtensa_insnbuf insn, uint32 val) +static void +Field_s_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xfffffff0) | (val & 0xf); + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); } -uint32 -get_r_field (const xtensa_insnbuf insn) +static unsigned +Field_imm12b_Slot_inst_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0xf00) >> 8); + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + tie_t = (tie_t << 8) | ((insn[0] << 24) >> 24); + return tie_t; } -void -set_r_field (xtensa_insnbuf insn, uint32 val) +static void +Field_imm12b_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xfffff0ff) | ((val << 8) & 0xf00); + uint32 tie_t; + tie_t = (val << 24) >> 24; + insn[0] = (insn[0] & ~0xff) | (tie_t << 0); + tie_t = (val << 20) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); } -uint32 -get_s_field (const xtensa_insnbuf insn) +static unsigned +Field_imm16_Slot_inst_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0xf000) >> 12); + unsigned tie_t = 0; + tie_t = (tie_t << 16) | ((insn[0] << 16) >> 16); + return tie_t; } -void -set_s_field (xtensa_insnbuf insn, uint32 val) +static void +Field_imm16_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xffff0fff) | ((val << 12) & 0xf000); + uint32 tie_t; + tie_t = (val << 16) >> 16; + insn[0] = (insn[0] & ~0xffff) | (tie_t << 0); } -uint32 -get_sa4_field (const xtensa_insnbuf insn) +static unsigned +Field_offset_Slot_inst_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0x1)); + unsigned tie_t = 0; + tie_t = (tie_t << 18) | ((insn[0] << 14) >> 14); + return tie_t; } -void -set_sa4_field (xtensa_insnbuf insn, uint32 val) +static void +Field_offset_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xfffffffe) | (val & 0x1); + uint32 tie_t; + tie_t = (val << 14) >> 14; + insn[0] = (insn[0] & ~0x3ffff) | (tie_t << 0); } -uint32 -get_sae_field (const xtensa_insnbuf insn) +static unsigned +Field_r_Slot_inst16a_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0xf000) >> 12) | - ((insn[0] & 0x10)); + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; } -void -set_sae_field (xtensa_insnbuf insn, uint32 val) +static void +Field_r_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xffff0fff) | ((val << 12) & 0xf000); - insn[0] = (insn[0] & 0xffffffef) | (val & 0x10); + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); } -uint32 -get_sae4_field (const xtensa_insnbuf insn) +static unsigned +Field_sa4_Slot_inst_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0x10) >> 4); + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 31) >> 31); + return tie_t; } -void -set_sae4_field (xtensa_insnbuf insn, uint32 val) +static void +Field_sa4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xffffffef) | ((val << 4) & 0x10); + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x1) | (tie_t << 0); } -uint32 -get_sal_field (const xtensa_insnbuf insn) +static unsigned +Field_sae4_Slot_inst_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0xf0000) >> 16) | - ((insn[0] & 0x1) << 4); + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 27) >> 31); + return tie_t; } -void -set_sal_field (xtensa_insnbuf insn, uint32 val) +static void +Field_sae4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xfff0ffff) | ((val << 16) & 0xf0000); - insn[0] = (insn[0] & 0xfffffffe) | ((val >> 4) & 0x1); + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x10) | (tie_t << 4); } -uint32 -get_sar_field (const xtensa_insnbuf insn) +static unsigned +Field_sae_Slot_inst_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0xf000) >> 12) | - ((insn[0] & 0x1) << 4); + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 27) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; } -void -set_sar_field (xtensa_insnbuf insn, uint32 val) +static void +Field_sae_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xffff0fff) | ((val << 12) & 0xf000); - insn[0] = (insn[0] & 0xfffffffe) | ((val >> 4) & 0x1); + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x10) | (tie_t << 4); } -uint32 -get_sas_field (const xtensa_insnbuf insn) +static unsigned +Field_sal_Slot_inst_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0xf000) >> 12) | - ((insn[0] & 0x10000) >> 12); + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 31) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 12) >> 28); + return tie_t; } -void -set_sas_field (xtensa_insnbuf insn, uint32 val) +static void +Field_sal_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xffff0fff) | ((val << 12) & 0xf000); - insn[0] = (insn[0] & 0xfffeffff) | ((val << 12) & 0x10000); + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0000) | (tie_t << 16); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x1) | (tie_t << 0); } -uint32 -get_sas4_field (const xtensa_insnbuf insn) +static unsigned +Field_sargt_Slot_inst_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0x10000) >> 16); + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 31) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; } -void -set_sas4_field (xtensa_insnbuf insn, uint32 val) +static void +Field_sargt_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xfffeffff) | ((val << 16) & 0x10000); + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x1) | (tie_t << 0); } -uint32 -get_sr_field (const xtensa_insnbuf insn) +static unsigned +Field_sas4_Slot_inst_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0xf00) >> 8) | - ((insn[0] & 0xf000) >> 8); + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 15) >> 31); + return tie_t; } -void -set_sr_field (xtensa_insnbuf insn, uint32 val) +static void +Field_sas4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xfffff0ff) | ((val << 8) & 0xf00); - insn[0] = (insn[0] & 0xffff0fff) | ((val << 8) & 0xf000); + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x10000) | (tie_t << 16); } -uint32 -get_t_field (const xtensa_insnbuf insn) +static unsigned +Field_sas_Slot_inst_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0xf0000) >> 16); + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 15) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; } -void -set_t_field (xtensa_insnbuf insn, uint32 val) +static void +Field_sas_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xfff0ffff) | ((val << 16) & 0xf0000); + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x10000) | (tie_t << 16); } -uint32 -get_thi3_field (const xtensa_insnbuf insn) +static unsigned +Field_sr_Slot_inst16a_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0xe0000) >> 17); + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; } -void -set_thi3_field (xtensa_insnbuf insn, uint32 val) +static void +Field_sr_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) { - insn[0] = (insn[0] & 0xfff1ffff) | ((val << 17) & 0xe0000); + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); } -uint32 -get_z_field (const xtensa_insnbuf insn) +static unsigned +Field_sr_Slot_inst16b_get (const xtensa_insnbuf insn) { - return ((insn[0] & 0x40000) >> 18); + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; } -void -set_z_field (xtensa_insnbuf insn, uint32 val) -{ - insn[0] = (insn[0] & 0xfffbffff) | ((val << 18) & 0x40000); -} - -uint32 decode_b4constu (uint32); -xtensa_encode_result encode_b4constu (uint32 *); -uint32 decode_simm8x256 (uint32); -xtensa_encode_result encode_simm8x256 (uint32 *); -uint32 decode_soffset (uint32); -xtensa_encode_result encode_soffset (uint32 *); -uint32 decode_imm4 (uint32); -xtensa_encode_result encode_imm4 (uint32 *); -uint32 decode_op0 (uint32); -xtensa_encode_result encode_op0 (uint32 *); -uint32 decode_op1 (uint32); -xtensa_encode_result encode_op1 (uint32 *); -uint32 decode_imm6 (uint32); -xtensa_encode_result encode_imm6 (uint32 *); -uint32 decode_op2 (uint32); -xtensa_encode_result encode_op2 (uint32 *); -uint32 decode_imm7 (uint32); -xtensa_encode_result encode_imm7 (uint32 *); -uint32 decode_simm4 (uint32); -xtensa_encode_result encode_simm4 (uint32 *); -uint32 decode_ai4const (uint32); -xtensa_encode_result encode_ai4const (uint32 *); -uint32 decode_imm8 (uint32); -xtensa_encode_result encode_imm8 (uint32 *); -uint32 decode_sae (uint32); -xtensa_encode_result encode_sae (uint32 *); -uint32 decode_imm7lo (uint32); -xtensa_encode_result encode_imm7lo (uint32 *); -uint32 decode_simm7 (uint32); -xtensa_encode_result encode_simm7 (uint32 *); -uint32 decode_simm8 (uint32); -xtensa_encode_result encode_simm8 (uint32 *); -uint32 decode_uimm12x8 (uint32); -xtensa_encode_result encode_uimm12x8 (uint32 *); -uint32 decode_sal (uint32); -xtensa_encode_result encode_sal (uint32 *); -uint32 decode_uimm6 (uint32); -xtensa_encode_result encode_uimm6 (uint32 *); -uint32 decode_sas4 (uint32); -xtensa_encode_result encode_sas4 (uint32 *); -uint32 decode_uimm8 (uint32); -xtensa_encode_result encode_uimm8 (uint32 *); -uint32 decode_uimm16x4 (uint32); -xtensa_encode_result encode_uimm16x4 (uint32 *); -uint32 decode_sar (uint32); -xtensa_encode_result encode_sar (uint32 *); -uint32 decode_sa4 (uint32); -xtensa_encode_result encode_sa4 (uint32 *); -uint32 decode_sas (uint32); -xtensa_encode_result encode_sas (uint32 *); -uint32 decode_imm6hi (uint32); -xtensa_encode_result encode_imm6hi (uint32 *); -uint32 decode_bbi (uint32); -xtensa_encode_result encode_bbi (uint32 *); -uint32 decode_uimm8x2 (uint32); -xtensa_encode_result encode_uimm8x2 (uint32 *); -uint32 decode_uimm8x4 (uint32); -xtensa_encode_result encode_uimm8x4 (uint32 *); -uint32 decode_msalp32 (uint32); -xtensa_encode_result encode_msalp32 (uint32 *); -uint32 decode_bbi4 (uint32); -xtensa_encode_result encode_bbi4 (uint32 *); -uint32 decode_op2p1 (uint32); -xtensa_encode_result encode_op2p1 (uint32 *); -uint32 decode_soffsetx4 (uint32); -xtensa_encode_result encode_soffsetx4 (uint32 *); -uint32 decode_imm6lo (uint32); -xtensa_encode_result encode_imm6lo (uint32 *); -uint32 decode_imm12 (uint32); -xtensa_encode_result encode_imm12 (uint32 *); -uint32 decode_b4const (uint32); -xtensa_encode_result encode_b4const (uint32 *); -uint32 decode_i (uint32); -xtensa_encode_result encode_i (uint32 *); -uint32 decode_imm16 (uint32); -xtensa_encode_result encode_imm16 (uint32 *); -uint32 decode_mn (uint32); -xtensa_encode_result encode_mn (uint32 *); -uint32 decode_m (uint32); -xtensa_encode_result encode_m (uint32 *); -uint32 decode_n (uint32); -xtensa_encode_result encode_n (uint32 *); -uint32 decode_none (uint32); -xtensa_encode_result encode_none (uint32 *); -uint32 decode_imm12b (uint32); -xtensa_encode_result encode_imm12b (uint32 *); -uint32 decode_r (uint32); -xtensa_encode_result encode_r (uint32 *); -uint32 decode_s (uint32); -xtensa_encode_result encode_s (uint32 *); -uint32 decode_t (uint32); -xtensa_encode_result encode_t (uint32 *); -uint32 decode_thi3 (uint32); -xtensa_encode_result encode_thi3 (uint32 *); -uint32 decode_sae4 (uint32); -xtensa_encode_result encode_sae4 (uint32 *); -uint32 decode_offset (uint32); -xtensa_encode_result encode_offset (uint32 *); -uint32 decode_imm7hi (uint32); -xtensa_encode_result encode_imm7hi (uint32 *); -uint32 decode_uimm4x16 (uint32); -xtensa_encode_result encode_uimm4x16 (uint32 *); -uint32 decode_simm12b (uint32); -xtensa_encode_result encode_simm12b (uint32 *); -uint32 decode_lsi4x4 (uint32); -xtensa_encode_result encode_lsi4x4 (uint32 *); -uint32 decode_z (uint32); -xtensa_encode_result encode_z (uint32 *); -uint32 decode_simm12 (uint32); -xtensa_encode_result encode_simm12 (uint32 *); -uint32 decode_sr (uint32); -xtensa_encode_result encode_sr (uint32 *); -uint32 decode_nimm4x2 (uint32); -xtensa_encode_result encode_nimm4x2 (uint32 *); - - -static const uint32 b4constu_table[] = { - 32768, - 65536, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 10, - 12, - 16, - 32, - 64, - 128, - 256 -}; +static void +Field_sr_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); +} -uint32 -decode_b4constu (uint32 val) +static unsigned +Field_st_Slot_inst_get (const xtensa_insnbuf insn) { - val = b4constu_table[val]; - return val; + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 12) >> 28); + return tie_t; } -xtensa_encode_result -encode_b4constu (uint32 *valp) +static void +Field_st_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - uint32 val = *valp; - unsigned i; - for (i = 0; i < (1 << 4); i += 1) - if (b4constu_table[i] == val) goto found; - return xtensa_encode_result_not_in_table; - found: - val = i; - *valp = val; - return xtensa_encode_result_ok; + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0000) | (tie_t << 16); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); } -uint32 -decode_simm8x256 (uint32 val) +static unsigned +Field_st_Slot_inst16a_get (const xtensa_insnbuf insn) { - val = (val ^ 0x80) - 0x80; - val <<= 8; - return val; + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; } -xtensa_encode_result -encode_simm8x256 (uint32 *valp) +static void +Field_st_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) { - uint32 val = *valp; - if ((val & ((1 << 8) - 1)) != 0) - return xtensa_encode_result_align; - val = (signed int) val >> 8; - if (((val + (1 << 7)) >> 8) != 0) - { - if ((signed int) val > 0) - return xtensa_encode_result_too_high; - else - return xtensa_encode_result_too_low; - } - *valp = val; - return xtensa_encode_result_ok; + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); } -uint32 -decode_soffset (uint32 val) +static unsigned +Field_st_Slot_inst16b_get (const xtensa_insnbuf insn) { - val = (val ^ 0x20000) - 0x20000; - return val; + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; } -xtensa_encode_result -encode_soffset (uint32 *valp) +static void +Field_st_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) { - uint32 val = *valp; - if (((val + (1 << 17)) >> 18) != 0) - { - if ((signed int) val > 0) - return xtensa_encode_result_too_high; - else - return xtensa_encode_result_too_low; - } - *valp = val; - return xtensa_encode_result_ok; + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); } -uint32 -decode_imm4 (uint32 val) +static unsigned +Field_imm4_Slot_inst_get (const xtensa_insnbuf insn) { - return val; + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; } -xtensa_encode_result -encode_imm4 (uint32 *valp) +static void +Field_imm4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - uint32 val = *valp; - if ((val >> 4) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); } -uint32 -decode_op0 (uint32 val) +static unsigned +Field_imm4_Slot_inst16a_get (const xtensa_insnbuf insn) { - return val; + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; } -xtensa_encode_result -encode_op0 (uint32 *valp) +static void +Field_imm4_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) { - uint32 val = *valp; - if ((val >> 4) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); } -uint32 -decode_op1 (uint32 val) +static unsigned +Field_imm4_Slot_inst16b_get (const xtensa_insnbuf insn) { - return val; + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; } -xtensa_encode_result -encode_op1 (uint32 *valp) +static void +Field_imm4_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) { - uint32 val = *valp; - if ((val >> 4) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); } -uint32 -decode_imm6 (uint32 val) +static unsigned +Field_mn_Slot_inst_get (const xtensa_insnbuf insn) { - return val; + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 12) >> 30); + tie_t = (tie_t << 2) | ((insn[0] << 14) >> 30); + return tie_t; } -xtensa_encode_result -encode_imm6 (uint32 *valp) +static void +Field_mn_Slot_inst_set (xtensa_insnbuf insn, uint32 val) { - uint32 val = *valp; - if ((val >> 6) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x30000) | (tie_t << 16); + tie_t = (val << 28) >> 30; + insn[0] = (insn[0] & ~0xc0000) | (tie_t << 18); } -uint32 -decode_op2 (uint32 val) +static unsigned +Field_i_Slot_inst16a_get (const xtensa_insnbuf insn) { - return val; + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 20) >> 31); + return tie_t; } -xtensa_encode_result -encode_op2 (uint32 *valp) +static void +Field_i_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) { - uint32 val = *valp; - if ((val >> 4) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x800) | (tie_t << 11); } -uint32 -decode_imm7 (uint32 val) +static unsigned +Field_imm6lo_Slot_inst16a_get (const xtensa_insnbuf insn) { - return val; + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; } -xtensa_encode_result -encode_imm7 (uint32 *valp) +static void +Field_imm6lo_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) { - uint32 val = *valp; - if ((val >> 7) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); } -uint32 -decode_simm4 (uint32 val) +static unsigned +Field_imm6lo_Slot_inst16b_get (const xtensa_insnbuf insn) { - val = (val ^ 0x8) - 0x8; - return val; + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; } -xtensa_encode_result -encode_simm4 (uint32 *valp) +static void +Field_imm6lo_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) { - uint32 val = *valp; - if (((val + (1 << 3)) >> 4) != 0) - { - if ((signed int) val > 0) - return xtensa_encode_result_too_high; - else - return xtensa_encode_result_too_low; - } - *valp = val; - return xtensa_encode_result_ok; + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); } -static const uint32 ai4const_table[] = { - -1, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15 -}; +static unsigned +Field_imm6hi_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 22) >> 30); + return tie_t; +} -uint32 -decode_ai4const (uint32 val) +static void +Field_imm6hi_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) { - val = ai4const_table[val]; - return val; + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x300) | (tie_t << 8); } -xtensa_encode_result -encode_ai4const (uint32 *valp) +static unsigned +Field_imm6hi_Slot_inst16b_get (const xtensa_insnbuf insn) { - uint32 val = *valp; - unsigned i; - for (i = 0; i < (1 << 4); i += 1) - if (ai4const_table[i] == val) goto found; - return xtensa_encode_result_not_in_table; - found: - val = i; - *valp = val; - return xtensa_encode_result_ok; + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 22) >> 30); + return tie_t; } -uint32 -decode_imm8 (uint32 val) +static void +Field_imm6hi_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) { - return val; + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x300) | (tie_t << 8); } -xtensa_encode_result -encode_imm8 (uint32 *valp) +static unsigned +Field_imm7lo_Slot_inst16a_get (const xtensa_insnbuf insn) { - uint32 val = *valp; - if ((val >> 8) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; } -uint32 -decode_sae (uint32 val) +static void +Field_imm7lo_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) { - return val; + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); } -xtensa_encode_result -encode_sae (uint32 *valp) +static unsigned +Field_imm7lo_Slot_inst16b_get (const xtensa_insnbuf insn) { - uint32 val = *valp; - if ((val >> 5) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; } -uint32 -decode_imm7lo (uint32 val) +static void +Field_imm7lo_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) { - return val; + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); } -xtensa_encode_result -encode_imm7lo (uint32 *valp) +static unsigned +Field_imm7hi_Slot_inst16a_get (const xtensa_insnbuf insn) { - uint32 val = *valp; - if ((val >> 4) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 21) >> 29); + return tie_t; } -uint32 -decode_simm7 (uint32 val) +static void +Field_imm7hi_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) { - if (val > 95) - val |= -32; - return val; + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0x700) | (tie_t << 8); } -xtensa_encode_result -encode_simm7 (uint32 *valp) +static unsigned +Field_imm7hi_Slot_inst16b_get (const xtensa_insnbuf insn) { - uint32 val = *valp; - if ((signed int) val < -32) - return xtensa_encode_result_too_low; - if ((signed int) val > 95) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 21) >> 29); + return tie_t; } -uint32 -decode_simm8 (uint32 val) +static void +Field_imm7hi_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) { - val = (val ^ 0x80) - 0x80; - return val; + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0x700) | (tie_t << 8); } -xtensa_encode_result -encode_simm8 (uint32 *valp) +static unsigned +Field_z_Slot_inst16a_get (const xtensa_insnbuf insn) { - uint32 val = *valp; - if (((val + (1 << 7)) >> 8) != 0) - { - if ((signed int) val > 0) - return xtensa_encode_result_too_high; - else - return xtensa_encode_result_too_low; - } - *valp = val; - return xtensa_encode_result_ok; + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 21) >> 31); + return tie_t; } -uint32 -decode_uimm12x8 (uint32 val) +static void +Field_z_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) { - val <<= 3; - return val; + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x400) | (tie_t << 10); } -xtensa_encode_result -encode_uimm12x8 (uint32 *valp) +static unsigned +Field_imm6_Slot_inst16a_get (const xtensa_insnbuf insn) { - uint32 val = *valp; - if ((val & ((1 << 3) - 1)) != 0) - return xtensa_encode_result_align; - val = (signed int) val >> 3; - if ((val >> 12) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 22) >> 30); + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; } -uint32 -decode_sal (uint32 val) +static void +Field_imm6_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) { - return val; + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); + tie_t = (val << 26) >> 30; + insn[0] = (insn[0] & ~0x300) | (tie_t << 8); } -xtensa_encode_result -encode_sal (uint32 *valp) +static unsigned +Field_imm6_Slot_inst16b_get (const xtensa_insnbuf insn) { - uint32 val = *valp; - if ((val >> 5) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 22) >> 30); + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; } -uint32 -decode_uimm6 (uint32 val) +static void +Field_imm6_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) { - return val; + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); + tie_t = (val << 26) >> 30; + insn[0] = (insn[0] & ~0x300) | (tie_t << 8); } -xtensa_encode_result -encode_uimm6 (uint32 *valp) +static unsigned +Field_imm7_Slot_inst16a_get (const xtensa_insnbuf insn) { - uint32 val = *valp; - if ((val >> 6) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 21) >> 29); + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; } -uint32 -decode_sas4 (uint32 val) +static void +Field_imm7_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) { - return val; + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); + tie_t = (val << 25) >> 29; + insn[0] = (insn[0] & ~0x700) | (tie_t << 8); } -xtensa_encode_result -encode_sas4 (uint32 *valp) +static unsigned +Field_imm7_Slot_inst16b_get (const xtensa_insnbuf insn) { - uint32 val = *valp; - if ((val >> 1) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 21) >> 29); + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; } -uint32 -decode_uimm8 (uint32 val) +static void +Field_imm7_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) { - return val; + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); + tie_t = (val << 25) >> 29; + insn[0] = (insn[0] & ~0x700) | (tie_t << 8); } -xtensa_encode_result -encode_uimm8 (uint32 *valp) +static void +Implicit_Field_set (xtensa_insnbuf insn ATTRIBUTE_UNUSED, + uint32 val ATTRIBUTE_UNUSED) { - uint32 val = *valp; - if ((val >> 8) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + /* Do nothing. */ } -uint32 -decode_uimm16x4 (uint32 val) +static unsigned +Implicit_Field_ar0_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) { - val |= -1 << 16; - val <<= 2; - return val; + return 0; } -xtensa_encode_result -encode_uimm16x4 (uint32 *valp) +static unsigned +Implicit_Field_ar4_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) { - uint32 val = *valp; - if ((val & ((1 << 2) - 1)) != 0) - return xtensa_encode_result_align; - val = (signed int) val >> 2; - if ((signed int) val >> 16 != -1) - { - if ((signed int) val >= 0) - return xtensa_encode_result_too_high; - else - return xtensa_encode_result_too_low; - } - *valp = val; - return xtensa_encode_result_ok; + return 4; } -uint32 -decode_sar (uint32 val) +static unsigned +Implicit_Field_ar8_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) { - return val; + return 8; } -xtensa_encode_result -encode_sar (uint32 *valp) +static unsigned +Implicit_Field_ar12_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) { - uint32 val = *valp; - if ((val >> 5) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + return 12; } -uint32 -decode_sa4 (uint32 val) + +/* Functional units. */ + +static xtensa_funcUnit_internal funcUnits[] = { + +}; + + +/* Register files. */ + +static xtensa_regfile_internal regfiles[] = { + { "AR", "a", 0, 32, 64 } +}; + + +/* Interfaces. */ + +static xtensa_interface_internal interfaces[] = { + +}; + + +/* Constant tables. */ + +/* constant table ai4c */ +static const unsigned CONST_TBL_ai4c_0[] = { + 0xffffffff, + 0x1, + 0x2, + 0x3, + 0x4, + 0x5, + 0x6, + 0x7, + 0x8, + 0x9, + 0xa, + 0xb, + 0xc, + 0xd, + 0xe, + 0xf, + 0 +}; + +/* constant table b4c */ +static const unsigned CONST_TBL_b4c_0[] = { + 0xffffffff, + 0x1, + 0x2, + 0x3, + 0x4, + 0x5, + 0x6, + 0x7, + 0x8, + 0xa, + 0xc, + 0x10, + 0x20, + 0x40, + 0x80, + 0x100, + 0 +}; + +/* constant table b4cu */ +static const unsigned CONST_TBL_b4cu_0[] = { + 0x8000, + 0x10000, + 0x2, + 0x3, + 0x4, + 0x5, + 0x6, + 0x7, + 0x8, + 0xa, + 0xc, + 0x10, + 0x20, + 0x40, + 0x80, + 0x100, + 0 +}; + + +/* Instruction operands. */ + +static int +Operand_soffsetx4_decode (uint32 *valp) { - return val; + unsigned soffsetx4_0, offset_0; + offset_0 = *valp & 0x3ffff; + soffsetx4_0 = 0x4 + ((((int) offset_0 << 14) >> 14) << 2); + *valp = soffsetx4_0; + return 0; } -xtensa_encode_result -encode_sa4 (uint32 *valp) +static int +Operand_soffsetx4_encode (uint32 *valp) { - uint32 val = *valp; - if ((val >> 1) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned offset_0, soffsetx4_0; + soffsetx4_0 = *valp; + offset_0 = ((soffsetx4_0 - 0x4) >> 2) & 0x3ffff; + *valp = offset_0; + return 0; } -uint32 -decode_sas (uint32 val) +static int +Operand_soffsetx4_ator (uint32 *valp, uint32 pc) { - return val; + *valp -= (pc & ~0x3); + return 0; } -xtensa_encode_result -encode_sas (uint32 *valp) +static int +Operand_soffsetx4_rtoa (uint32 *valp, uint32 pc) { - uint32 val = *valp; - if ((val >> 5) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + *valp += (pc & ~0x3); + return 0; } -uint32 -decode_imm6hi (uint32 val) +static int +Operand_uimm12x8_decode (uint32 *valp) { - return val; + unsigned uimm12x8_0, imm12_0; + imm12_0 = *valp & 0xfff; + uimm12x8_0 = imm12_0 << 3; + *valp = uimm12x8_0; + return 0; } -xtensa_encode_result -encode_imm6hi (uint32 *valp) +static int +Operand_uimm12x8_encode (uint32 *valp) { - uint32 val = *valp; - if ((val >> 2) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned imm12_0, uimm12x8_0; + uimm12x8_0 = *valp; + imm12_0 = ((uimm12x8_0 >> 3) & 0xfff); + *valp = imm12_0; + return 0; } -uint32 -decode_bbi (uint32 val) +static int +Operand_simm4_decode (uint32 *valp) { - return val; + unsigned simm4_0, mn_0; + mn_0 = *valp & 0xf; + simm4_0 = ((int) mn_0 << 28) >> 28; + *valp = simm4_0; + return 0; } -xtensa_encode_result -encode_bbi (uint32 *valp) +static int +Operand_simm4_encode (uint32 *valp) { - uint32 val = *valp; - if ((val >> 5) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned mn_0, simm4_0; + simm4_0 = *valp; + mn_0 = (simm4_0 & 0xf); + *valp = mn_0; + return 0; } -uint32 -decode_uimm8x2 (uint32 val) +static int +Operand_arr_decode (uint32 *valp ATTRIBUTE_UNUSED) { - val <<= 1; - return val; + return 0; } -xtensa_encode_result -encode_uimm8x2 (uint32 *valp) +static int +Operand_arr_encode (uint32 *valp) { - uint32 val = *valp; - if ((val & ((1 << 1) - 1)) != 0) - return xtensa_encode_result_align; - val = (signed int) val >> 1; - if ((val >> 8) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + int error; + error = (*valp & ~0xf) != 0; + return error; } -uint32 -decode_uimm8x4 (uint32 val) +static int +Operand_ars_decode (uint32 *valp ATTRIBUTE_UNUSED) { - val <<= 2; - return val; + return 0; } -xtensa_encode_result -encode_uimm8x4 (uint32 *valp) +static int +Operand_ars_encode (uint32 *valp) { - uint32 val = *valp; - if ((val & ((1 << 2) - 1)) != 0) - return xtensa_encode_result_align; - val = (signed int) val >> 2; - if ((val >> 8) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + int error; + error = (*valp & ~0xf) != 0; + return error; } -static const uint32 mip32const_table[] = { - 32, - 31, - 30, - 29, - 28, - 27, - 26, - 25, - 24, - 23, - 22, - 21, - 20, - 19, - 18, - 17, - 16, - 15, - 14, - 13, - 12, - 11, - 10, - 9, - 8, - 7, - 6, - 5, - 4, - 3, - 2, - 1 -}; +static int +Operand_art_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} -uint32 -decode_msalp32 (uint32 val) +static int +Operand_art_encode (uint32 *valp) { - val = mip32const_table[val]; - return val; + int error; + error = (*valp & ~0xf) != 0; + return error; } -xtensa_encode_result -encode_msalp32 (uint32 *valp) +static int +Operand_ar0_decode (uint32 *valp ATTRIBUTE_UNUSED) { - uint32 val = *valp; - unsigned i; - for (i = 0; i < (1 << 5); i += 1) - if (mip32const_table[i] == val) goto found; - return xtensa_encode_result_not_in_table; - found: - val = i; - *valp = val; - return xtensa_encode_result_ok; + return 0; } -uint32 -decode_bbi4 (uint32 val) +static int +Operand_ar0_encode (uint32 *valp) { - return val; + int error; + error = (*valp & ~0x3f) != 0; + return error; } -xtensa_encode_result -encode_bbi4 (uint32 *valp) +static int +Operand_ar4_decode (uint32 *valp ATTRIBUTE_UNUSED) { - uint32 val = *valp; - if ((val >> 1) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + return 0; } -static const uint32 i4p1const_table[] = { - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16 -}; - -uint32 -decode_op2p1 (uint32 val) -{ - val = i4p1const_table[val]; - return val; -} - -xtensa_encode_result -encode_op2p1 (uint32 *valp) -{ - uint32 val = *valp; - unsigned i; - for (i = 0; i < (1 << 4); i += 1) - if (i4p1const_table[i] == val) goto found; - return xtensa_encode_result_not_in_table; - found: - val = i; - *valp = val; - return xtensa_encode_result_ok; -} - -uint32 -decode_soffsetx4 (uint32 val) -{ - val = (val ^ 0x20000) - 0x20000; - val <<= 2; - return val; -} - -xtensa_encode_result -encode_soffsetx4 (uint32 *valp) -{ - uint32 val = *valp; - if ((val & ((1 << 2) - 1)) != 0) - return xtensa_encode_result_align; - val = (signed int) val >> 2; - if (((val + (1 << 17)) >> 18) != 0) - { - if ((signed int) val > 0) - return xtensa_encode_result_too_high; - else - return xtensa_encode_result_too_low; - } - *valp = val; - return xtensa_encode_result_ok; +static int +Operand_ar4_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x3f) != 0; + return error; } -uint32 -decode_imm6lo (uint32 val) +static int +Operand_ar8_decode (uint32 *valp ATTRIBUTE_UNUSED) { - return val; + return 0; } -xtensa_encode_result -encode_imm6lo (uint32 *valp) +static int +Operand_ar8_encode (uint32 *valp) { - uint32 val = *valp; - if ((val >> 4) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + int error; + error = (*valp & ~0x3f) != 0; + return error; } -uint32 -decode_imm12 (uint32 val) +static int +Operand_ar12_decode (uint32 *valp ATTRIBUTE_UNUSED) { - return val; + return 0; } -xtensa_encode_result -encode_imm12 (uint32 *valp) +static int +Operand_ar12_encode (uint32 *valp) { - uint32 val = *valp; - if ((val >> 12) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + int error; + error = (*valp & ~0x3f) != 0; + return error; } -static const uint32 b4const_table[] = { - -1, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 10, - 12, - 16, - 32, - 64, - 128, - 256 -}; +static int +Operand_ars_entry_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} -uint32 -decode_b4const (uint32 val) +static int +Operand_ars_entry_encode (uint32 *valp) { - val = b4const_table[val]; - return val; + int error; + error = (*valp & ~0x3f) != 0; + return error; } -xtensa_encode_result -encode_b4const (uint32 *valp) +static int +Operand_immrx4_decode (uint32 *valp) { - uint32 val = *valp; - unsigned i; - for (i = 0; i < (1 << 4); i += 1) - if (b4const_table[i] == val) goto found; - return xtensa_encode_result_not_in_table; - found: - val = i; - *valp = val; - return xtensa_encode_result_ok; + unsigned immrx4_0, r_0; + r_0 = *valp & 0xf; + immrx4_0 = ((((0xfffffff)) << 4) | r_0) << 2; + *valp = immrx4_0; + return 0; } -uint32 -decode_i (uint32 val) +static int +Operand_immrx4_encode (uint32 *valp) { - return val; + unsigned r_0, immrx4_0; + immrx4_0 = *valp; + r_0 = ((immrx4_0 >> 2) & 0xf); + *valp = r_0; + return 0; } -xtensa_encode_result -encode_i (uint32 *valp) +static int +Operand_lsi4x4_decode (uint32 *valp) { - uint32 val = *valp; - if ((val >> 1) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned lsi4x4_0, r_0; + r_0 = *valp & 0xf; + lsi4x4_0 = r_0 << 2; + *valp = lsi4x4_0; + return 0; } -uint32 -decode_imm16 (uint32 val) +static int +Operand_lsi4x4_encode (uint32 *valp) { - return val; + unsigned r_0, lsi4x4_0; + lsi4x4_0 = *valp; + r_0 = ((lsi4x4_0 >> 2) & 0xf); + *valp = r_0; + return 0; } -xtensa_encode_result -encode_imm16 (uint32 *valp) +static int +Operand_simm7_decode (uint32 *valp) { - uint32 val = *valp; - if ((val >> 16) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned simm7_0, imm7_0; + imm7_0 = *valp & 0x7f; + simm7_0 = ((((-((((imm7_0 >> 6) & 1)) & (((imm7_0 >> 5) & 1)))) & 0x1ffffff)) << 7) | imm7_0; + *valp = simm7_0; + return 0; } -uint32 -decode_mn (uint32 val) +static int +Operand_simm7_encode (uint32 *valp) { - return val; + unsigned imm7_0, simm7_0; + simm7_0 = *valp; + imm7_0 = (simm7_0 & 0x7f); + *valp = imm7_0; + return 0; } -xtensa_encode_result -encode_mn (uint32 *valp) +static int +Operand_uimm6_decode (uint32 *valp) { - uint32 val = *valp; - if ((val >> 4) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned uimm6_0, imm6_0; + imm6_0 = *valp & 0x3f; + uimm6_0 = 0x4 + ((((0)) << 6) | imm6_0); + *valp = uimm6_0; + return 0; } -uint32 -decode_m (uint32 val) +static int +Operand_uimm6_encode (uint32 *valp) { - return val; + unsigned imm6_0, uimm6_0; + uimm6_0 = *valp; + imm6_0 = (uimm6_0 - 0x4) & 0x3f; + *valp = imm6_0; + return 0; } -xtensa_encode_result -encode_m (uint32 *valp) +static int +Operand_uimm6_ator (uint32 *valp, uint32 pc) { - uint32 val = *valp; - if ((val >> 2) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + *valp -= pc; + return 0; } -uint32 -decode_n (uint32 val) +static int +Operand_uimm6_rtoa (uint32 *valp, uint32 pc) { - return val; + *valp += pc; + return 0; } -xtensa_encode_result -encode_n (uint32 *valp) +static int +Operand_ai4const_decode (uint32 *valp) { - uint32 val = *valp; - if ((val >> 2) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned ai4const_0, t_0; + t_0 = *valp & 0xf; + ai4const_0 = CONST_TBL_ai4c_0[t_0 & 0xf]; + *valp = ai4const_0; + return 0; } -uint32 -decode_none (uint32 val) +static int +Operand_ai4const_encode (uint32 *valp) { - return val; + unsigned t_0, ai4const_0; + ai4const_0 = *valp; + switch (ai4const_0) + { + case 0xffffffff: t_0 = 0; break; + case 0x1: t_0 = 0x1; break; + case 0x2: t_0 = 0x2; break; + case 0x3: t_0 = 0x3; break; + case 0x4: t_0 = 0x4; break; + case 0x5: t_0 = 0x5; break; + case 0x6: t_0 = 0x6; break; + case 0x7: t_0 = 0x7; break; + case 0x8: t_0 = 0x8; break; + case 0x9: t_0 = 0x9; break; + case 0xa: t_0 = 0xa; break; + case 0xb: t_0 = 0xb; break; + case 0xc: t_0 = 0xc; break; + case 0xd: t_0 = 0xd; break; + case 0xe: t_0 = 0xe; break; + default: t_0 = 0xf; break; + } + *valp = t_0; + return 0; } -xtensa_encode_result -encode_none (uint32 *valp) +static int +Operand_b4const_decode (uint32 *valp) { - uint32 val = *valp; - if ((val >> 0) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned b4const_0, r_0; + r_0 = *valp & 0xf; + b4const_0 = CONST_TBL_b4c_0[r_0 & 0xf]; + *valp = b4const_0; + return 0; } -uint32 -decode_imm12b (uint32 val) +static int +Operand_b4const_encode (uint32 *valp) { - return val; + unsigned r_0, b4const_0; + b4const_0 = *valp; + switch (b4const_0) + { + case 0xffffffff: r_0 = 0; break; + case 0x1: r_0 = 0x1; break; + case 0x2: r_0 = 0x2; break; + case 0x3: r_0 = 0x3; break; + case 0x4: r_0 = 0x4; break; + case 0x5: r_0 = 0x5; break; + case 0x6: r_0 = 0x6; break; + case 0x7: r_0 = 0x7; break; + case 0x8: r_0 = 0x8; break; + case 0xa: r_0 = 0x9; break; + case 0xc: r_0 = 0xa; break; + case 0x10: r_0 = 0xb; break; + case 0x20: r_0 = 0xc; break; + case 0x40: r_0 = 0xd; break; + case 0x80: r_0 = 0xe; break; + default: r_0 = 0xf; break; + } + *valp = r_0; + return 0; } -xtensa_encode_result -encode_imm12b (uint32 *valp) +static int +Operand_b4constu_decode (uint32 *valp) { - uint32 val = *valp; - if ((val >> 12) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned b4constu_0, r_0; + r_0 = *valp & 0xf; + b4constu_0 = CONST_TBL_b4cu_0[r_0 & 0xf]; + *valp = b4constu_0; + return 0; } -uint32 -decode_r (uint32 val) +static int +Operand_b4constu_encode (uint32 *valp) { - return val; + unsigned r_0, b4constu_0; + b4constu_0 = *valp; + switch (b4constu_0) + { + case 0x8000: r_0 = 0; break; + case 0x10000: r_0 = 0x1; break; + case 0x2: r_0 = 0x2; break; + case 0x3: r_0 = 0x3; break; + case 0x4: r_0 = 0x4; break; + case 0x5: r_0 = 0x5; break; + case 0x6: r_0 = 0x6; break; + case 0x7: r_0 = 0x7; break; + case 0x8: r_0 = 0x8; break; + case 0xa: r_0 = 0x9; break; + case 0xc: r_0 = 0xa; break; + case 0x10: r_0 = 0xb; break; + case 0x20: r_0 = 0xc; break; + case 0x40: r_0 = 0xd; break; + case 0x80: r_0 = 0xe; break; + default: r_0 = 0xf; break; + } + *valp = r_0; + return 0; } -xtensa_encode_result -encode_r (uint32 *valp) +static int +Operand_uimm8_decode (uint32 *valp) { - uint32 val = *valp; - if ((val >> 4) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned uimm8_0, imm8_0; + imm8_0 = *valp & 0xff; + uimm8_0 = imm8_0; + *valp = uimm8_0; + return 0; } -uint32 -decode_s (uint32 val) +static int +Operand_uimm8_encode (uint32 *valp) { - return val; + unsigned imm8_0, uimm8_0; + uimm8_0 = *valp; + imm8_0 = (uimm8_0 & 0xff); + *valp = imm8_0; + return 0; } -xtensa_encode_result -encode_s (uint32 *valp) +static int +Operand_uimm8x2_decode (uint32 *valp) { - uint32 val = *valp; - if ((val >> 4) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned uimm8x2_0, imm8_0; + imm8_0 = *valp & 0xff; + uimm8x2_0 = imm8_0 << 1; + *valp = uimm8x2_0; + return 0; } -uint32 -decode_t (uint32 val) +static int +Operand_uimm8x2_encode (uint32 *valp) { - return val; + unsigned imm8_0, uimm8x2_0; + uimm8x2_0 = *valp; + imm8_0 = ((uimm8x2_0 >> 1) & 0xff); + *valp = imm8_0; + return 0; } -xtensa_encode_result -encode_t (uint32 *valp) +static int +Operand_uimm8x4_decode (uint32 *valp) { - uint32 val = *valp; - if ((val >> 4) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned uimm8x4_0, imm8_0; + imm8_0 = *valp & 0xff; + uimm8x4_0 = imm8_0 << 2; + *valp = uimm8x4_0; + return 0; } -uint32 -decode_thi3 (uint32 val) +static int +Operand_uimm8x4_encode (uint32 *valp) { - return val; + unsigned imm8_0, uimm8x4_0; + uimm8x4_0 = *valp; + imm8_0 = ((uimm8x4_0 >> 2) & 0xff); + *valp = imm8_0; + return 0; } -xtensa_encode_result -encode_thi3 (uint32 *valp) +static int +Operand_uimm4x16_decode (uint32 *valp) { - uint32 val = *valp; - if ((val >> 3) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned uimm4x16_0, op2_0; + op2_0 = *valp & 0xf; + uimm4x16_0 = op2_0 << 4; + *valp = uimm4x16_0; + return 0; } -uint32 -decode_sae4 (uint32 val) +static int +Operand_uimm4x16_encode (uint32 *valp) { - return val; + unsigned op2_0, uimm4x16_0; + uimm4x16_0 = *valp; + op2_0 = ((uimm4x16_0 >> 4) & 0xf); + *valp = op2_0; + return 0; } -xtensa_encode_result -encode_sae4 (uint32 *valp) +static int +Operand_simm8_decode (uint32 *valp) { - uint32 val = *valp; - if ((val >> 1) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned simm8_0, imm8_0; + imm8_0 = *valp & 0xff; + simm8_0 = ((int) imm8_0 << 24) >> 24; + *valp = simm8_0; + return 0; } -uint32 -decode_offset (uint32 val) +static int +Operand_simm8_encode (uint32 *valp) { - return val; + unsigned imm8_0, simm8_0; + simm8_0 = *valp; + imm8_0 = (simm8_0 & 0xff); + *valp = imm8_0; + return 0; } -xtensa_encode_result -encode_offset (uint32 *valp) +static int +Operand_simm8x256_decode (uint32 *valp) { - uint32 val = *valp; - if ((val >> 18) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned simm8x256_0, imm8_0; + imm8_0 = *valp & 0xff; + simm8x256_0 = (((int) imm8_0 << 24) >> 24) << 8; + *valp = simm8x256_0; + return 0; } -uint32 -decode_imm7hi (uint32 val) +static int +Operand_simm8x256_encode (uint32 *valp) { - return val; + unsigned imm8_0, simm8x256_0; + simm8x256_0 = *valp; + imm8_0 = ((simm8x256_0 >> 8) & 0xff); + *valp = imm8_0; + return 0; } -xtensa_encode_result -encode_imm7hi (uint32 *valp) +static int +Operand_simm12b_decode (uint32 *valp) { - uint32 val = *valp; - if ((val >> 3) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned simm12b_0, imm12b_0; + imm12b_0 = *valp & 0xfff; + simm12b_0 = ((int) imm12b_0 << 20) >> 20; + *valp = simm12b_0; + return 0; } -uint32 -decode_uimm4x16 (uint32 val) +static int +Operand_simm12b_encode (uint32 *valp) { - val <<= 4; - return val; + unsigned imm12b_0, simm12b_0; + simm12b_0 = *valp; + imm12b_0 = (simm12b_0 & 0xfff); + *valp = imm12b_0; + return 0; } -xtensa_encode_result -encode_uimm4x16 (uint32 *valp) +static int +Operand_msalp32_decode (uint32 *valp) { - uint32 val = *valp; - if ((val & ((1 << 4) - 1)) != 0) - return xtensa_encode_result_align; - val = (signed int) val >> 4; - if ((val >> 4) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned msalp32_0, sal_0; + sal_0 = *valp & 0x1f; + msalp32_0 = 0x20 - sal_0; + *valp = msalp32_0; + return 0; } -uint32 -decode_simm12b (uint32 val) +static int +Operand_msalp32_encode (uint32 *valp) { - val = (val ^ 0x800) - 0x800; - return val; + unsigned sal_0, msalp32_0; + msalp32_0 = *valp; + sal_0 = (0x20 - msalp32_0) & 0x1f; + *valp = sal_0; + return 0; } -xtensa_encode_result -encode_simm12b (uint32 *valp) +static int +Operand_op2p1_decode (uint32 *valp) { - uint32 val = *valp; - if (((val + (1 << 11)) >> 12) != 0) - { - if ((signed int) val > 0) - return xtensa_encode_result_too_high; - else - return xtensa_encode_result_too_low; - } - *valp = val; - return xtensa_encode_result_ok; + unsigned op2p1_0, op2_0; + op2_0 = *valp & 0xf; + op2p1_0 = op2_0 + 0x1; + *valp = op2p1_0; + return 0; } -uint32 -decode_lsi4x4 (uint32 val) +static int +Operand_op2p1_encode (uint32 *valp) { - val <<= 2; - return val; + unsigned op2_0, op2p1_0; + op2p1_0 = *valp; + op2_0 = (op2p1_0 - 0x1) & 0xf; + *valp = op2_0; + return 0; } -xtensa_encode_result -encode_lsi4x4 (uint32 *valp) +static int +Operand_label8_decode (uint32 *valp) { - uint32 val = *valp; - if ((val & ((1 << 2) - 1)) != 0) - return xtensa_encode_result_align; - val = (signed int) val >> 2; - if ((val >> 4) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + unsigned label8_0, imm8_0; + imm8_0 = *valp & 0xff; + label8_0 = 0x4 + (((int) imm8_0 << 24) >> 24); + *valp = label8_0; + return 0; } -uint32 -decode_z (uint32 val) +static int +Operand_label8_encode (uint32 *valp) { - return val; + unsigned imm8_0, label8_0; + label8_0 = *valp; + imm8_0 = (label8_0 - 0x4) & 0xff; + *valp = imm8_0; + return 0; } -xtensa_encode_result -encode_z (uint32 *valp) +static int +Operand_label8_ator (uint32 *valp, uint32 pc) { - uint32 val = *valp; - if ((val >> 1) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + *valp -= pc; + return 0; } -uint32 -decode_simm12 (uint32 val) +static int +Operand_label8_rtoa (uint32 *valp, uint32 pc) { - val = (val ^ 0x800) - 0x800; - return val; + *valp += pc; + return 0; } -xtensa_encode_result -encode_simm12 (uint32 *valp) +static int +Operand_ulabel8_decode (uint32 *valp) { - uint32 val = *valp; - if (((val + (1 << 11)) >> 12) != 0) - { - if ((signed int) val > 0) - return xtensa_encode_result_too_high; - else - return xtensa_encode_result_too_low; - } - *valp = val; - return xtensa_encode_result_ok; + unsigned ulabel8_0, imm8_0; + imm8_0 = *valp & 0xff; + ulabel8_0 = 0x4 + ((((0)) << 8) | imm8_0); + *valp = ulabel8_0; + return 0; } -uint32 -decode_sr (uint32 val) +static int +Operand_ulabel8_encode (uint32 *valp) { - return val; + unsigned imm8_0, ulabel8_0; + ulabel8_0 = *valp; + imm8_0 = (ulabel8_0 - 0x4) & 0xff; + *valp = imm8_0; + return 0; } -xtensa_encode_result -encode_sr (uint32 *valp) +static int +Operand_ulabel8_ator (uint32 *valp, uint32 pc) { - uint32 val = *valp; - if ((val >> 8) != 0) - return xtensa_encode_result_too_high; - *valp = val; - return xtensa_encode_result_ok; + *valp -= pc; + return 0; } -uint32 -decode_nimm4x2 (uint32 val) +static int +Operand_ulabel8_rtoa (uint32 *valp, uint32 pc) { - val |= -1 << 4; - val <<= 2; - return val; + *valp += pc; + return 0; } -xtensa_encode_result -encode_nimm4x2 (uint32 *valp) +static int +Operand_label12_decode (uint32 *valp) { - uint32 val = *valp; - if ((val & ((1 << 2) - 1)) != 0) - return xtensa_encode_result_align; - val = (signed int) val >> 2; - if ((signed int) val >> 4 != -1) - { - if ((signed int) val >= 0) - return xtensa_encode_result_too_high; - else - return xtensa_encode_result_too_low; - } - *valp = val; - return xtensa_encode_result_ok; + unsigned label12_0, imm12_0; + imm12_0 = *valp & 0xfff; + label12_0 = 0x4 + (((int) imm12_0 << 20) >> 20); + *valp = label12_0; + return 0; } +static int +Operand_label12_encode (uint32 *valp) +{ + unsigned imm12_0, label12_0; + label12_0 = *valp; + imm12_0 = (label12_0 - 0x4) & 0xfff; + *valp = imm12_0; + return 0; +} +static int +Operand_label12_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} -uint32 do_reloc_l (uint32, uint32); -uint32 undo_reloc_l (uint32, uint32); -uint32 do_reloc_L (uint32, uint32); -uint32 undo_reloc_L (uint32, uint32); -uint32 do_reloc_r (uint32, uint32); -uint32 undo_reloc_r (uint32, uint32); +static int +Operand_label12_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} +static int +Operand_soffset_decode (uint32 *valp) +{ + unsigned soffset_0, offset_0; + offset_0 = *valp & 0x3ffff; + soffset_0 = 0x4 + (((int) offset_0 << 14) >> 14); + *valp = soffset_0; + return 0; +} -uint32 -do_reloc_l (uint32 addr, uint32 pc) +static int +Operand_soffset_encode (uint32 *valp) { - return addr - pc - 4; + unsigned offset_0, soffset_0; + soffset_0 = *valp; + offset_0 = (soffset_0 - 0x4) & 0x3ffff; + *valp = offset_0; + return 0; } -uint32 -undo_reloc_l (uint32 offset, uint32 pc) +static int +Operand_soffset_ator (uint32 *valp, uint32 pc) { - return pc + offset + 4; + *valp -= pc; + return 0; } -uint32 -do_reloc_L (uint32 addr, uint32 pc) +static int +Operand_soffset_rtoa (uint32 *valp, uint32 pc) { - return addr - (pc & -4) - 4; + *valp += pc; + return 0; } -uint32 -undo_reloc_L (uint32 offset, uint32 pc) +static int +Operand_uimm16x4_decode (uint32 *valp) { - return (pc & -4) + offset + 4; + unsigned uimm16x4_0, imm16_0; + imm16_0 = *valp & 0xffff; + uimm16x4_0 = ((((0xffff)) << 16) | imm16_0) << 2; + *valp = uimm16x4_0; + return 0; } -uint32 -do_reloc_r (uint32 addr, uint32 pc) +static int +Operand_uimm16x4_encode (uint32 *valp) { - return addr - ((pc+3) & -4); + unsigned imm16_0, uimm16x4_0; + uimm16x4_0 = *valp; + imm16_0 = (uimm16x4_0 >> 2) & 0xffff; + *valp = imm16_0; + return 0; } -uint32 -undo_reloc_r (uint32 offset, uint32 pc) +static int +Operand_uimm16x4_ator (uint32 *valp, uint32 pc) { - return ((pc+3) & -4) + offset; + *valp -= ((pc + 3) & ~0x3); + return 0; } -static xtensa_operand_internal iib4const_operand = { - "i", - '<', - 0, - get_r_field, - set_r_field, - encode_b4const, - decode_b4const, - 0, - 0 +static int +Operand_uimm16x4_rtoa (uint32 *valp, uint32 pc) +{ + *valp += ((pc + 3) & ~0x3); + return 0; +} + +static int +Operand_immt_decode (uint32 *valp) +{ + unsigned immt_0, t_0; + t_0 = *valp & 0xf; + immt_0 = t_0; + *valp = immt_0; + return 0; +} + +static int +Operand_immt_encode (uint32 *valp) +{ + unsigned t_0, immt_0; + immt_0 = *valp; + t_0 = immt_0 & 0xf; + *valp = t_0; + return 0; +} + +static int +Operand_imms_decode (uint32 *valp) +{ + unsigned imms_0, s_0; + s_0 = *valp & 0xf; + imms_0 = s_0; + *valp = imms_0; + return 0; +} + +static int +Operand_imms_encode (uint32 *valp) +{ + unsigned s_0, imms_0; + imms_0 = *valp; + s_0 = imms_0 & 0xf; + *valp = s_0; + return 0; +} + +static xtensa_operand_internal operands[] = { + { "soffsetx4", 10, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_soffsetx4_encode, Operand_soffsetx4_decode, + Operand_soffsetx4_ator, Operand_soffsetx4_rtoa }, + { "uimm12x8", 3, -1, 0, + 0, + Operand_uimm12x8_encode, Operand_uimm12x8_decode, + 0, 0 }, + { "simm4", 26, -1, 0, + 0, + Operand_simm4_encode, Operand_simm4_decode, + 0, 0 }, + { "arr", 14, 0, 1, + XTENSA_OPERAND_IS_REGISTER, + Operand_arr_encode, Operand_arr_decode, + 0, 0 }, + { "ars", 5, 0, 1, + XTENSA_OPERAND_IS_REGISTER, + Operand_ars_encode, Operand_ars_decode, + 0, 0 }, + { "*ars_invisible", 5, 0, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_ars_encode, Operand_ars_decode, + 0, 0 }, + { "art", 0, 0, 1, + XTENSA_OPERAND_IS_REGISTER, + Operand_art_encode, Operand_art_decode, + 0, 0 }, + { "ar0", 35, 0, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_ar0_encode, Operand_ar0_decode, + 0, 0 }, + { "ar4", 36, 0, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_ar4_encode, Operand_ar4_decode, + 0, 0 }, + { "ar8", 37, 0, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_ar8_encode, Operand_ar8_decode, + 0, 0 }, + { "ar12", 38, 0, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_ar12_encode, Operand_ar12_decode, + 0, 0 }, + { "ars_entry", 5, 0, 1, + XTENSA_OPERAND_IS_REGISTER, + Operand_ars_entry_encode, Operand_ars_entry_decode, + 0, 0 }, + { "immrx4", 14, -1, 0, + 0, + Operand_immrx4_encode, Operand_immrx4_decode, + 0, 0 }, + { "lsi4x4", 14, -1, 0, + 0, + Operand_lsi4x4_encode, Operand_lsi4x4_decode, + 0, 0 }, + { "simm7", 34, -1, 0, + 0, + Operand_simm7_encode, Operand_simm7_decode, + 0, 0 }, + { "uimm6", 33, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_uimm6_encode, Operand_uimm6_decode, + Operand_uimm6_ator, Operand_uimm6_rtoa }, + { "ai4const", 0, -1, 0, + 0, + Operand_ai4const_encode, Operand_ai4const_decode, + 0, 0 }, + { "b4const", 14, -1, 0, + 0, + Operand_b4const_encode, Operand_b4const_decode, + 0, 0 }, + { "b4constu", 14, -1, 0, + 0, + Operand_b4constu_encode, Operand_b4constu_decode, + 0, 0 }, + { "uimm8", 4, -1, 0, + 0, + Operand_uimm8_encode, Operand_uimm8_decode, + 0, 0 }, + { "uimm8x2", 4, -1, 0, + 0, + Operand_uimm8x2_encode, Operand_uimm8x2_decode, + 0, 0 }, + { "uimm8x4", 4, -1, 0, + 0, + Operand_uimm8x4_encode, Operand_uimm8x4_decode, + 0, 0 }, + { "uimm4x16", 13, -1, 0, + 0, + Operand_uimm4x16_encode, Operand_uimm4x16_decode, + 0, 0 }, + { "simm8", 4, -1, 0, + 0, + Operand_simm8_encode, Operand_simm8_decode, + 0, 0 }, + { "simm8x256", 4, -1, 0, + 0, + Operand_simm8x256_encode, Operand_simm8x256_decode, + 0, 0 }, + { "simm12b", 6, -1, 0, + 0, + Operand_simm12b_encode, Operand_simm12b_decode, + 0, 0 }, + { "msalp32", 18, -1, 0, + 0, + Operand_msalp32_encode, Operand_msalp32_decode, + 0, 0 }, + { "op2p1", 13, -1, 0, + 0, + Operand_op2p1_encode, Operand_op2p1_decode, + 0, 0 }, + { "label8", 4, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_label8_encode, Operand_label8_decode, + Operand_label8_ator, Operand_label8_rtoa }, + { "ulabel8", 4, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_ulabel8_encode, Operand_ulabel8_decode, + Operand_ulabel8_ator, Operand_ulabel8_rtoa }, + { "label12", 3, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_label12_encode, Operand_label12_decode, + Operand_label12_ator, Operand_label12_rtoa }, + { "soffset", 10, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_soffset_encode, Operand_soffset_decode, + Operand_soffset_ator, Operand_soffset_rtoa }, + { "uimm16x4", 7, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_uimm16x4_encode, Operand_uimm16x4_decode, + Operand_uimm16x4_ator, Operand_uimm16x4_rtoa }, + { "immt", 0, -1, 0, + 0, + Operand_immt_encode, Operand_immt_decode, + 0, 0 }, + { "imms", 5, -1, 0, + 0, + Operand_imms_encode, Operand_imms_decode, + 0, 0 }, + { "t", 0, -1, 0, 0, 0, 0, 0, 0 }, + { "bbi4", 1, -1, 0, 0, 0, 0, 0, 0 }, + { "bbi", 2, -1, 0, 0, 0, 0, 0, 0 }, + { "imm12", 3, -1, 0, 0, 0, 0, 0, 0 }, + { "imm8", 4, -1, 0, 0, 0, 0, 0, 0 }, + { "s", 5, -1, 0, 0, 0, 0, 0, 0 }, + { "imm12b", 6, -1, 0, 0, 0, 0, 0, 0 }, + { "imm16", 7, -1, 0, 0, 0, 0, 0, 0 }, + { "m", 8, -1, 0, 0, 0, 0, 0, 0 }, + { "n", 9, -1, 0, 0, 0, 0, 0, 0 }, + { "offset", 10, -1, 0, 0, 0, 0, 0, 0 }, + { "op0", 11, -1, 0, 0, 0, 0, 0, 0 }, + { "op1", 12, -1, 0, 0, 0, 0, 0, 0 }, + { "op2", 13, -1, 0, 0, 0, 0, 0, 0 }, + { "r", 14, -1, 0, 0, 0, 0, 0, 0 }, + { "sa4", 15, -1, 0, 0, 0, 0, 0, 0 }, + { "sae4", 16, -1, 0, 0, 0, 0, 0, 0 }, + { "sae", 17, -1, 0, 0, 0, 0, 0, 0 }, + { "sal", 18, -1, 0, 0, 0, 0, 0, 0 }, + { "sargt", 19, -1, 0, 0, 0, 0, 0, 0 }, + { "sas4", 20, -1, 0, 0, 0, 0, 0, 0 }, + { "sas", 21, -1, 0, 0, 0, 0, 0, 0 }, + { "sr", 22, -1, 0, 0, 0, 0, 0, 0 }, + { "st", 23, -1, 0, 0, 0, 0, 0, 0 }, + { "thi3", 24, -1, 0, 0, 0, 0, 0, 0 }, + { "imm4", 25, -1, 0, 0, 0, 0, 0, 0 }, + { "mn", 26, -1, 0, 0, 0, 0, 0, 0 }, + { "i", 27, -1, 0, 0, 0, 0, 0, 0 }, + { "imm6lo", 28, -1, 0, 0, 0, 0, 0, 0 }, + { "imm6hi", 29, -1, 0, 0, 0, 0, 0, 0 }, + { "imm7lo", 30, -1, 0, 0, 0, 0, 0, 0 }, + { "imm7hi", 31, -1, 0, 0, 0, 0, 0, 0 }, + { "z", 32, -1, 0, 0, 0, 0, 0, 0 }, + { "imm6", 33, -1, 0, 0, 0, 0, 0, 0 }, + { "imm7", 34, -1, 0, 0, 0, 0, 0, 0 } +}; + + +/* Iclass table. */ + +static xtensa_arg_internal Iclass_xt_iclass_rfe_stateArgs[] = { + { { STATE_PSEXCM }, 'o' }, + { { STATE_EPC1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfde_stateArgs[] = { + { { STATE_DEPC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call12_args[] = { + { { 0 /* soffsetx4 */ }, 'i' }, + { { 10 /* ar12 */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call12_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call8_args[] = { + { { 0 /* soffsetx4 */ }, 'i' }, + { { 9 /* ar8 */ }, 'o' } }; -static xtensa_operand_internal iiuimm8_operand = { - "i", - '<', - 0, - get_imm8_field, - set_imm8_field, - encode_uimm8, - decode_uimm8, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_call8_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } }; -static xtensa_operand_internal lisoffsetx4_operand = { - "L", - '<', - 1, - get_offset_field, - set_offset_field, - encode_soffsetx4, - decode_soffsetx4, - do_reloc_L, - undo_reloc_L, +static xtensa_arg_internal Iclass_xt_iclass_call4_args[] = { + { { 0 /* soffsetx4 */ }, 'i' }, + { { 8 /* ar4 */ }, 'o' } }; -static xtensa_operand_internal iisimm8x256_operand = { - "i", - '<', - 0, - get_imm8_field, - set_imm8_field, - encode_simm8x256, - decode_simm8x256, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_call4_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } }; -static xtensa_operand_internal lisimm12_operand = { - "l", - '<', - 1, - get_imm12_field, - set_imm12_field, - encode_simm12, - decode_simm12, - do_reloc_l, - undo_reloc_l, +static xtensa_arg_internal Iclass_xt_iclass_callx12_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 10 /* ar12 */ }, 'o' } }; -static xtensa_operand_internal iiop2p1_operand = { - "i", - '<', - 0, - get_op2_field, - set_op2_field, - encode_op2p1, - decode_op2p1, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_callx12_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } }; -static xtensa_operand_internal iisae_operand = { - "i", - '<', - 0, - get_sae_field, - set_sae_field, - encode_sae, - decode_sae, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_callx8_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 9 /* ar8 */ }, 'o' } }; -static xtensa_operand_internal iis_operand = { - "i", - '<', - 0, - get_s_field, - set_s_field, - encode_s, - decode_s, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_callx8_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } }; -static xtensa_operand_internal iit_operand = { - "i", - '<', - 0, - get_t_field, - set_t_field, - encode_t, - decode_t, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_callx4_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 8 /* ar4 */ }, 'o' } }; -static xtensa_operand_internal iisimm12b_operand = { - "i", - '<', - 0, - get_imm12b_field, - set_imm12b_field, - encode_simm12b, - decode_simm12b, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_callx4_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } }; -static xtensa_operand_internal iinimm4x2_operand = { - "i", - '<', - 0, - get_imm4_field, - set_imm4_field, - encode_nimm4x2, - decode_nimm4x2, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_entry_args[] = { + { { 11 /* ars_entry */ }, 's' }, + { { 4 /* ars */ }, 'i' }, + { { 1 /* uimm12x8 */ }, 'i' } }; -static xtensa_operand_internal iiuimm4x16_operand = { - "i", - '<', - 0, - get_op2_field, - set_op2_field, - encode_uimm4x16, - decode_uimm4x16, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_entry_stateArgs[] = { + { { STATE_PSCALLINC }, 'i' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSWOE }, 'i' }, + { { STATE_WindowBase }, 'm' }, + { { STATE_WindowStart }, 'm' } }; -static xtensa_operand_internal abs_operand = { - "a", - '=', - 0, - get_s_field, - set_s_field, - encode_s, - decode_s, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_movsp_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' } }; -static xtensa_operand_internal iisar_operand = { - "i", - '<', - 0, - get_sar_field, - set_sar_field, - encode_sar, - decode_sar, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_movsp_stateArgs[] = { + { { STATE_WindowBase }, 'i' }, + { { STATE_WindowStart }, 'i' } }; -static xtensa_operand_internal abt_operand = { - "a", - '=', - 0, - get_t_field, - set_t_field, - encode_t, - decode_t, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_rotw_args[] = { + { { 2 /* simm4 */ }, 'i' } }; -static xtensa_operand_internal iisas_operand = { - "i", - '<', - 0, - get_sas_field, - set_sas_field, - encode_sas, - decode_sas, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_rotw_stateArgs[] = { + { { STATE_WindowBase }, 'm' } }; -static xtensa_operand_internal amr_operand = { - "a", - '=', - 0, - get_r_field, - set_r_field, - encode_r, - decode_r, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_retw_args[] = { + { { 5 /* *ars_invisible */ }, 'i' } }; -static xtensa_operand_internal iib4constu_operand = { - "i", - '<', - 0, - get_r_field, - set_r_field, - encode_b4constu, - decode_b4constu, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_retw_stateArgs[] = { + { { STATE_WindowBase }, 'm' }, + { { STATE_WindowStart }, 'm' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSWOE }, 'i' } }; -static xtensa_operand_internal iisr_operand = { - "i", - '<', - 0, - get_sr_field, - set_sr_field, - encode_sr, - decode_sr, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_rfwou_stateArgs[] = { + { { STATE_EPC1 }, 'i' }, + { { STATE_PSEXCM }, 'o' }, + { { STATE_WindowBase }, 'm' }, + { { STATE_WindowStart }, 'm' }, + { { STATE_PSOWB }, 'i' } }; -static xtensa_operand_internal iibbi_operand = { - "i", - '<', - 0, - get_bbi_field, - set_bbi_field, - encode_bbi, - decode_bbi, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_l32e_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 12 /* immrx4 */ }, 'i' } }; -static xtensa_operand_internal iiai4const_operand = { - "i", - '<', - 0, - get_t_field, - set_t_field, - encode_ai4const, - decode_ai4const, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_s32e_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' }, + { { 12 /* immrx4 */ }, 'i' } }; -static xtensa_operand_internal iiuimm12x8_operand = { - "i", - '<', - 0, - get_imm12_field, - set_imm12_field, - encode_uimm12x8, - decode_uimm12x8, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_rsr_windowbase_args[] = { + { { 6 /* art */ }, 'o' } }; -static xtensa_operand_internal riuimm16x4_operand = { - "r", - '<', - 1, - get_imm16_field, - set_imm16_field, - encode_uimm16x4, - decode_uimm16x4, - do_reloc_r, - undo_reloc_r, -}; - -static xtensa_operand_internal lisimm8_operand = { - "l", - '<', - 1, - get_imm8_field, - set_imm8_field, - encode_simm8, - decode_simm8, - do_reloc_l, - undo_reloc_l, -}; - -static xtensa_operand_internal iilsi4x4_operand = { - "i", - '<', - 0, - get_r_field, - set_r_field, - encode_lsi4x4, - decode_lsi4x4, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_rsr_windowbase_stateArgs[] = { + { { STATE_WindowBase }, 'i' } }; -static xtensa_operand_internal iiuimm8x2_operand = { - "i", - '<', - 0, - get_imm8_field, - set_imm8_field, - encode_uimm8x2, - decode_uimm8x2, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_wsr_windowbase_args[] = { + { { 6 /* art */ }, 'i' } }; -static xtensa_operand_internal iisimm4_operand = { - "i", - '<', - 0, - get_mn_field, - set_mn_field, - encode_simm4, - decode_simm4, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_wsr_windowbase_stateArgs[] = { + { { STATE_WindowBase }, 'o' } }; -static xtensa_operand_internal iimsalp32_operand = { - "i", - '<', - 0, - get_sal_field, - set_sal_field, - encode_msalp32, - decode_msalp32, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_xsr_windowbase_args[] = { + { { 6 /* art */ }, 'm' } }; -static xtensa_operand_internal liuimm6_operand = { - "l", - '<', - 1, - get_imm6_field, - set_imm6_field, - encode_uimm6, - decode_uimm6, - do_reloc_l, - undo_reloc_l, +static xtensa_arg_internal Iclass_xt_iclass_xsr_windowbase_stateArgs[] = { + { { STATE_WindowBase }, 'm' } }; -static xtensa_operand_internal iiuimm8x4_operand = { - "i", - '<', - 0, - get_imm8_field, - set_imm8_field, - encode_uimm8x4, - decode_uimm8x4, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_rsr_windowstart_args[] = { + { { 6 /* art */ }, 'o' } }; -static xtensa_operand_internal lisoffset_operand = { - "l", - '<', - 1, - get_offset_field, - set_offset_field, - encode_soffset, - decode_soffset, - do_reloc_l, - undo_reloc_l, +static xtensa_arg_internal Iclass_xt_iclass_rsr_windowstart_stateArgs[] = { + { { STATE_WindowStart }, 'i' } }; -static xtensa_operand_internal iisimm7_operand = { - "i", - '<', - 0, - get_imm7_field, - set_imm7_field, - encode_simm7, - decode_simm7, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_wsr_windowstart_args[] = { + { { 6 /* art */ }, 'i' } }; -static xtensa_operand_internal ais_operand = { - "a", - '<', - 0, - get_s_field, - set_s_field, - encode_s, - decode_s, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_wsr_windowstart_stateArgs[] = { + { { STATE_WindowStart }, 'o' } }; -static xtensa_operand_internal liuimm8_operand = { - "l", - '<', - 1, - get_imm8_field, - set_imm8_field, - encode_uimm8, - decode_uimm8, - do_reloc_l, - undo_reloc_l, +static xtensa_arg_internal Iclass_xt_iclass_xsr_windowstart_args[] = { + { { 6 /* art */ }, 'm' } }; -static xtensa_operand_internal ait_operand = { - "a", - '<', - 0, - get_t_field, - set_t_field, - encode_t, - decode_t, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_xsr_windowstart_stateArgs[] = { + { { STATE_WindowStart }, 'm' } }; -static xtensa_operand_internal iisimm8_operand = { - "i", - '<', - 0, - get_imm8_field, - set_imm8_field, - encode_simm8, - decode_simm8, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_add_n_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 6 /* art */ }, 'i' } }; -static xtensa_operand_internal aor_operand = { - "a", - '>', - 0, - get_r_field, - set_r_field, - encode_r, - decode_r, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_addi_n_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 16 /* ai4const */ }, 'i' } }; -static xtensa_operand_internal aos_operand = { - "a", - '>', - 0, - get_s_field, - set_s_field, - encode_s, - decode_s, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_bz6_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 15 /* uimm6 */ }, 'i' } }; -static xtensa_operand_internal aot_operand = { - "a", - '>', - 0, - get_t_field, - set_t_field, - encode_t, - decode_t, - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_loadi4_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 13 /* lsi4x4 */ }, 'i' } }; -static xtensa_iclass_internal nopn_iclass = { - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_mov_n_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' } }; -static xtensa_operand_internal *movi_operand_list[] = { - &aot_operand, - &iisimm12b_operand +static xtensa_arg_internal Iclass_xt_iclass_movi_n_args[] = { + { { 4 /* ars */ }, 'o' }, + { { 14 /* simm7 */ }, 'i' } }; -static xtensa_iclass_internal movi_iclass = { - 2, - &movi_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_retn_args[] = { + { { 5 /* *ars_invisible */ }, 'i' } }; -static xtensa_operand_internal *bsi8u_operand_list[] = { - &ais_operand, - &iib4constu_operand, - &lisimm8_operand +static xtensa_arg_internal Iclass_xt_iclass_storei4_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' }, + { { 13 /* lsi4x4 */ }, 'i' } }; -static xtensa_iclass_internal bsi8u_iclass = { - 3, - &bsi8u_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_addi_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 23 /* simm8 */ }, 'i' } }; -static xtensa_operand_internal *itlb_operand_list[] = { - &ais_operand +static xtensa_arg_internal Iclass_xt_iclass_addmi_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 24 /* simm8x256 */ }, 'i' } }; -static xtensa_iclass_internal itlb_iclass = { - 1, - &itlb_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_addsub_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 6 /* art */ }, 'i' } }; -static xtensa_operand_internal *shiftst_operand_list[] = { - &aor_operand, - &ais_operand, - &ait_operand +static xtensa_arg_internal Iclass_xt_iclass_bit_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 6 /* art */ }, 'i' } }; -static xtensa_iclass_internal shiftst_iclass = { - 3, - &shiftst_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_bsi8_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 17 /* b4const */ }, 'i' }, + { { 28 /* label8 */ }, 'i' } }; -static xtensa_operand_internal *l32r_operand_list[] = { - &aot_operand, - &riuimm16x4_operand +static xtensa_arg_internal Iclass_xt_iclass_bsi8b_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 37 /* bbi */ }, 'i' }, + { { 28 /* label8 */ }, 'i' } }; -static xtensa_iclass_internal l32r_iclass = { - 2, - &l32r_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_bsi8u_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 18 /* b4constu */ }, 'i' }, + { { 28 /* label8 */ }, 'i' } }; -static xtensa_iclass_internal rfe_iclass = { - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_bst8_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 6 /* art */ }, 'i' }, + { { 28 /* label8 */ }, 'i' } }; -static xtensa_operand_internal *wait_operand_list[] = { - &iis_operand +static xtensa_arg_internal Iclass_xt_iclass_bsz12_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 30 /* label12 */ }, 'i' } }; -static xtensa_iclass_internal wait_iclass = { - 1, - &wait_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_call0_args[] = { + { { 0 /* soffsetx4 */ }, 'i' }, + { { 7 /* ar0 */ }, 'o' } }; -static xtensa_operand_internal *rfi_operand_list[] = { - &iis_operand +static xtensa_arg_internal Iclass_xt_iclass_callx0_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 7 /* ar0 */ }, 'o' } }; -static xtensa_iclass_internal rfi_iclass = { - 1, - &rfi_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_exti_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 6 /* art */ }, 'i' }, + { { 52 /* sae */ }, 'i' }, + { { 27 /* op2p1 */ }, 'i' } }; -static xtensa_operand_internal *movz_operand_list[] = { - &amr_operand, - &ais_operand, - &ait_operand +static xtensa_arg_internal Iclass_xt_iclass_jump_args[] = { + { { 31 /* soffset */ }, 'i' } }; -static xtensa_iclass_internal movz_iclass = { - 3, - &movz_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_jumpx_args[] = { + { { 4 /* ars */ }, 'i' } }; -static xtensa_operand_internal *callx_operand_list[] = { - &ais_operand +static xtensa_arg_internal Iclass_xt_iclass_l16ui_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 20 /* uimm8x2 */ }, 'i' } }; -static xtensa_iclass_internal callx_iclass = { - 1, - &callx_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_l16si_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 20 /* uimm8x2 */ }, 'i' } }; -static xtensa_operand_internal *mov_n_operand_list[] = { - &aot_operand, - &ais_operand +static xtensa_arg_internal Iclass_xt_iclass_l32i_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 21 /* uimm8x4 */ }, 'i' } }; -static xtensa_iclass_internal mov_n_iclass = { - 2, - &mov_n_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_l32r_args[] = { + { { 6 /* art */ }, 'o' }, + { { 32 /* uimm16x4 */ }, 'i' } }; -static xtensa_operand_internal *loadi4_operand_list[] = { - &aot_operand, - &ais_operand, - &iilsi4x4_operand +static xtensa_arg_internal Iclass_xt_iclass_l32r_stateArgs[] = { + { { STATE_LITBADDR }, 'i' }, + { { STATE_LITBEN }, 'i' } }; -static xtensa_iclass_internal loadi4_iclass = { - 3, - &loadi4_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_l8i_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 19 /* uimm8 */ }, 'i' } }; -static xtensa_operand_internal *exti_operand_list[] = { - &aor_operand, - &ait_operand, - &iisae_operand, - &iiop2p1_operand +static xtensa_arg_internal Iclass_xt_iclass_loop_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 29 /* ulabel8 */ }, 'i' } }; -static xtensa_iclass_internal exti_iclass = { - 4, - &exti_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_loop_stateArgs[] = { + { { STATE_LBEG }, 'o' }, + { { STATE_LEND }, 'o' }, + { { STATE_LCOUNT }, 'o' } }; -static xtensa_operand_internal *break_operand_list[] = { - &iis_operand, - &iit_operand +static xtensa_arg_internal Iclass_xt_iclass_loopz_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 29 /* ulabel8 */ }, 'i' } }; -static xtensa_iclass_internal break_iclass = { - 2, - &break_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_loopz_stateArgs[] = { + { { STATE_LBEG }, 'o' }, + { { STATE_LEND }, 'o' }, + { { STATE_LCOUNT }, 'o' } }; -static xtensa_operand_internal *slli_operand_list[] = { - &aor_operand, - &ais_operand, - &iimsalp32_operand +static xtensa_arg_internal Iclass_xt_iclass_movi_args[] = { + { { 6 /* art */ }, 'o' }, + { { 25 /* simm12b */ }, 'i' } }; -static xtensa_iclass_internal slli_iclass = { - 3, - &slli_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_movz_args[] = { + { { 3 /* arr */ }, 'm' }, + { { 4 /* ars */ }, 'i' }, + { { 6 /* art */ }, 'i' } }; -static xtensa_operand_internal *s16i_operand_list[] = { - &ait_operand, - &ais_operand, - &iiuimm8x2_operand +static xtensa_arg_internal Iclass_xt_iclass_neg_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 6 /* art */ }, 'i' } }; -static xtensa_iclass_internal s16i_iclass = { - 3, - &s16i_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_return_args[] = { + { { 5 /* *ars_invisible */ }, 'i' } }; -static xtensa_operand_internal *call_operand_list[] = { - &lisoffsetx4_operand +static xtensa_arg_internal Iclass_xt_iclass_s16i_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' }, + { { 20 /* uimm8x2 */ }, 'i' } }; -static xtensa_iclass_internal call_iclass = { - 1, - &call_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_s32i_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' }, + { { 21 /* uimm8x4 */ }, 'i' } }; -static xtensa_operand_internal *shifts_operand_list[] = { - &aor_operand, - &ais_operand +static xtensa_arg_internal Iclass_xt_iclass_s8i_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' }, + { { 19 /* uimm8 */ }, 'i' } }; -static xtensa_iclass_internal shifts_iclass = { - 2, - &shifts_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_sar_args[] = { + { { 4 /* ars */ }, 'i' } }; -static xtensa_operand_internal *shiftt_operand_list[] = { - &aor_operand, - &ait_operand +static xtensa_arg_internal Iclass_xt_iclass_sar_stateArgs[] = { + { { STATE_SAR }, 'o' } }; -static xtensa_iclass_internal shiftt_iclass = { - 2, - &shiftt_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_sari_args[] = { + { { 56 /* sas */ }, 'i' } }; -static xtensa_operand_internal *rotw_operand_list[] = { - &iisimm4_operand +static xtensa_arg_internal Iclass_xt_iclass_sari_stateArgs[] = { + { { STATE_SAR }, 'o' } }; -static xtensa_iclass_internal rotw_iclass = { - 1, - &rotw_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_shifts_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' } }; -static xtensa_operand_internal *addsub_operand_list[] = { - &aor_operand, - &ais_operand, - &ait_operand +static xtensa_arg_internal Iclass_xt_iclass_shifts_stateArgs[] = { + { { STATE_SAR }, 'i' } }; -static xtensa_iclass_internal addsub_iclass = { - 3, - &addsub_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_shiftst_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 6 /* art */ }, 'i' } }; -static xtensa_operand_internal *l8i_operand_list[] = { - &aot_operand, - &ais_operand, - &iiuimm8_operand +static xtensa_arg_internal Iclass_xt_iclass_shiftst_stateArgs[] = { + { { STATE_SAR }, 'i' } }; -static xtensa_iclass_internal l8i_iclass = { - 3, - &l8i_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_shiftt_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 6 /* art */ }, 'i' } }; -static xtensa_operand_internal *sari_operand_list[] = { - &iisas_operand +static xtensa_arg_internal Iclass_xt_iclass_shiftt_stateArgs[] = { + { { STATE_SAR }, 'i' } }; -static xtensa_iclass_internal sari_iclass = { - 1, - &sari_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_slli_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 26 /* msalp32 */ }, 'i' } }; -static xtensa_operand_internal *xsr_operand_list[] = { - &abt_operand, - &iisr_operand +static xtensa_arg_internal Iclass_xt_iclass_srai_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 6 /* art */ }, 'i' }, + { { 54 /* sargt */ }, 'i' } }; -static xtensa_iclass_internal xsr_iclass = { - 2, - &xsr_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_srli_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 6 /* art */ }, 'i' }, + { { 40 /* s */ }, 'i' } }; -static xtensa_operand_internal *rsil_operand_list[] = { - &aot_operand, - &iis_operand +static xtensa_arg_internal Iclass_xt_iclass_sync_stateArgs[] = { + { { STATE_XTSYNC }, 'i' } }; -static xtensa_iclass_internal rsil_iclass = { - 2, - &rsil_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_rsil_args[] = { + { { 6 /* art */ }, 'o' }, + { { 40 /* s */ }, 'i' } }; -static xtensa_operand_internal *bst8_operand_list[] = { - &ais_operand, - &ait_operand, - &lisimm8_operand +static xtensa_arg_internal Iclass_xt_iclass_rsil_stateArgs[] = { + { { STATE_PSWOE }, 'i' }, + { { STATE_PSCALLINC }, 'i' }, + { { STATE_PSOWB }, 'i' }, + { { STATE_PSUM }, 'i' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'm' } }; -static xtensa_iclass_internal bst8_iclass = { - 3, - &bst8_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_rsr_lend_args[] = { + { { 6 /* art */ }, 'o' } }; -static xtensa_operand_internal *addi_operand_list[] = { - &aot_operand, - &ais_operand, - &iisimm8_operand +static xtensa_arg_internal Iclass_xt_iclass_rsr_lend_stateArgs[] = { + { { STATE_LEND }, 'i' } }; -static xtensa_iclass_internal addi_iclass = { - 3, - &addi_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_wsr_lend_args[] = { + { { 6 /* art */ }, 'i' } }; -static xtensa_operand_internal *callx12_operand_list[] = { - &ais_operand +static xtensa_arg_internal Iclass_xt_iclass_wsr_lend_stateArgs[] = { + { { STATE_LEND }, 'o' } }; -static xtensa_iclass_internal callx12_iclass = { - 1, - &callx12_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_xsr_lend_args[] = { + { { 6 /* art */ }, 'm' } }; -static xtensa_operand_internal *bsi8_operand_list[] = { - &ais_operand, - &iib4const_operand, - &lisimm8_operand +static xtensa_arg_internal Iclass_xt_iclass_xsr_lend_stateArgs[] = { + { { STATE_LEND }, 'm' } }; -static xtensa_iclass_internal bsi8_iclass = { - 3, - &bsi8_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_rsr_lcount_args[] = { + { { 6 /* art */ }, 'o' } }; -static xtensa_operand_internal *jumpx_operand_list[] = { - &ais_operand +static xtensa_arg_internal Iclass_xt_iclass_rsr_lcount_stateArgs[] = { + { { STATE_LCOUNT }, 'i' } }; -static xtensa_iclass_internal jumpx_iclass = { - 1, - &jumpx_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_wsr_lcount_args[] = { + { { 6 /* art */ }, 'i' } }; -static xtensa_iclass_internal retn_iclass = { - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_wsr_lcount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_LCOUNT }, 'o' } }; -static xtensa_operand_internal *nsa_operand_list[] = { - &aot_operand, - &ais_operand +static xtensa_arg_internal Iclass_xt_iclass_xsr_lcount_args[] = { + { { 6 /* art */ }, 'm' } }; -static xtensa_iclass_internal nsa_iclass = { - 2, - &nsa_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_xsr_lcount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_LCOUNT }, 'm' } }; -static xtensa_operand_internal *storei4_operand_list[] = { - &ait_operand, - &ais_operand, - &iilsi4x4_operand +static xtensa_arg_internal Iclass_xt_iclass_rsr_lbeg_args[] = { + { { 6 /* art */ }, 'o' } }; -static xtensa_iclass_internal storei4_iclass = { - 3, - &storei4_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_rsr_lbeg_stateArgs[] = { + { { STATE_LBEG }, 'i' } }; -static xtensa_operand_internal *wtlb_operand_list[] = { - &ait_operand, - &ais_operand +static xtensa_arg_internal Iclass_xt_iclass_wsr_lbeg_args[] = { + { { 6 /* art */ }, 'i' } }; -static xtensa_iclass_internal wtlb_iclass = { - 2, - &wtlb_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_wsr_lbeg_stateArgs[] = { + { { STATE_LBEG }, 'o' } }; -static xtensa_operand_internal *dce_operand_list[] = { - &ais_operand, - &iiuimm4x16_operand +static xtensa_arg_internal Iclass_xt_iclass_xsr_lbeg_args[] = { + { { 6 /* art */ }, 'm' } }; -static xtensa_iclass_internal dce_iclass = { - 2, - &dce_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_xsr_lbeg_stateArgs[] = { + { { STATE_LBEG }, 'm' } }; -static xtensa_operand_internal *l16i_operand_list[] = { - &aot_operand, - &ais_operand, - &iiuimm8x2_operand +static xtensa_arg_internal Iclass_xt_iclass_rsr_sar_args[] = { + { { 6 /* art */ }, 'o' } }; -static xtensa_iclass_internal l16i_iclass = { - 3, - &l16i_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_rsr_sar_stateArgs[] = { + { { STATE_SAR }, 'i' } }; -static xtensa_operand_internal *callx4_operand_list[] = { - &ais_operand +static xtensa_arg_internal Iclass_xt_iclass_wsr_sar_args[] = { + { { 6 /* art */ }, 'i' } }; -static xtensa_iclass_internal callx4_iclass = { - 1, - &callx4_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_wsr_sar_stateArgs[] = { + { { STATE_SAR }, 'o' }, + { { STATE_XTSYNC }, 'o' } }; -static xtensa_operand_internal *callx8_operand_list[] = { - &ais_operand +static xtensa_arg_internal Iclass_xt_iclass_xsr_sar_args[] = { + { { 6 /* art */ }, 'm' } }; -static xtensa_iclass_internal callx8_iclass = { - 1, - &callx8_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_xsr_sar_stateArgs[] = { + { { STATE_SAR }, 'm' } }; -static xtensa_operand_internal *movsp_operand_list[] = { - &aot_operand, - &ais_operand +static xtensa_arg_internal Iclass_xt_iclass_rsr_litbase_args[] = { + { { 6 /* art */ }, 'o' } }; -static xtensa_iclass_internal movsp_iclass = { - 2, - &movsp_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_rsr_litbase_stateArgs[] = { + { { STATE_LITBADDR }, 'i' }, + { { STATE_LITBEN }, 'i' } }; -static xtensa_operand_internal *wsr_operand_list[] = { - &ait_operand, - &iisr_operand +static xtensa_arg_internal Iclass_xt_iclass_wsr_litbase_args[] = { + { { 6 /* art */ }, 'i' } }; -static xtensa_iclass_internal wsr_iclass = { - 2, - &wsr_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_wsr_litbase_stateArgs[] = { + { { STATE_LITBADDR }, 'o' }, + { { STATE_LITBEN }, 'o' } }; -static xtensa_operand_internal *call12_operand_list[] = { - &lisoffsetx4_operand +static xtensa_arg_internal Iclass_xt_iclass_xsr_litbase_args[] = { + { { 6 /* art */ }, 'm' } }; -static xtensa_iclass_internal call12_iclass = { - 1, - &call12_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_xsr_litbase_stateArgs[] = { + { { STATE_LITBADDR }, 'm' }, + { { STATE_LITBEN }, 'm' } }; -static xtensa_operand_internal *call4_operand_list[] = { - &lisoffsetx4_operand +static xtensa_arg_internal Iclass_xt_iclass_rsr_176_args[] = { + { { 6 /* art */ }, 'o' } }; -static xtensa_iclass_internal call4_iclass = { - 1, - &call4_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_rsr_208_args[] = { + { { 6 /* art */ }, 'o' } }; -static xtensa_operand_internal *addmi_operand_list[] = { - &aot_operand, - &ais_operand, - &iisimm8x256_operand +static xtensa_arg_internal Iclass_xt_iclass_rsr_ps_args[] = { + { { 6 /* art */ }, 'o' } }; -static xtensa_iclass_internal addmi_iclass = { - 3, - &addmi_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_rsr_ps_stateArgs[] = { + { { STATE_PSWOE }, 'i' }, + { { STATE_PSCALLINC }, 'i' }, + { { STATE_PSOWB }, 'i' }, + { { STATE_PSUM }, 'i' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'i' } }; -static xtensa_operand_internal *bit_operand_list[] = { - &aor_operand, - &ais_operand, - &ait_operand +static xtensa_arg_internal Iclass_xt_iclass_wsr_ps_args[] = { + { { 6 /* art */ }, 'i' } }; -static xtensa_iclass_internal bit_iclass = { - 3, - &bit_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_wsr_ps_stateArgs[] = { + { { STATE_PSWOE }, 'o' }, + { { STATE_PSCALLINC }, 'o' }, + { { STATE_PSOWB }, 'o' }, + { { STATE_PSUM }, 'o' }, + { { STATE_PSEXCM }, 'o' }, + { { STATE_PSINTLEVEL }, 'o' } }; -static xtensa_operand_internal *call8_operand_list[] = { - &lisoffsetx4_operand +static xtensa_arg_internal Iclass_xt_iclass_xsr_ps_args[] = { + { { 6 /* art */ }, 'm' } }; -static xtensa_iclass_internal call8_iclass = { - 1, - &call8_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_xsr_ps_stateArgs[] = { + { { STATE_PSWOE }, 'm' }, + { { STATE_PSCALLINC }, 'm' }, + { { STATE_PSOWB }, 'm' }, + { { STATE_PSUM }, 'm' }, + { { STATE_PSEXCM }, 'm' }, + { { STATE_PSINTLEVEL }, 'm' } }; -static xtensa_iclass_internal itlba_iclass = { - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc1_args[] = { + { { 6 /* art */ }, 'o' } }; -static xtensa_operand_internal *break_n_operand_list[] = { - &iis_operand +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc1_stateArgs[] = { + { { STATE_EPC1 }, 'i' } }; -static xtensa_iclass_internal break_n_iclass = { - 1, - &break_n_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc1_args[] = { + { { 6 /* art */ }, 'i' } }; -static xtensa_operand_internal *sar_operand_list[] = { - &ais_operand +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc1_stateArgs[] = { + { { STATE_EPC1 }, 'o' } }; -static xtensa_iclass_internal sar_iclass = { - 1, - &sar_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc1_args[] = { + { { 6 /* art */ }, 'm' } }; -static xtensa_operand_internal *s32e_operand_list[] = { - &ait_operand, - &ais_operand, - &iinimm4x2_operand +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc1_stateArgs[] = { + { { STATE_EPC1 }, 'm' } }; -static xtensa_iclass_internal s32e_iclass = { - 3, - &s32e_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave1_args[] = { + { { 6 /* art */ }, 'o' } }; -static xtensa_operand_internal *bz6_operand_list[] = { - &ais_operand, - &liuimm6_operand +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave1_stateArgs[] = { + { { STATE_EXCSAVE1 }, 'i' } }; -static xtensa_iclass_internal bz6_iclass = { - 2, - &bz6_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave1_args[] = { + { { 6 /* art */ }, 'i' } }; -static xtensa_operand_internal *loop_operand_list[] = { - &ais_operand, - &liuimm8_operand +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave1_stateArgs[] = { + { { STATE_EXCSAVE1 }, 'o' } }; -static xtensa_iclass_internal loop_iclass = { - 2, - &loop_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave1_args[] = { + { { 6 /* art */ }, 'm' } }; -static xtensa_operand_internal *rsr_operand_list[] = { - &aot_operand, - &iisr_operand +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave1_stateArgs[] = { + { { STATE_EXCSAVE1 }, 'm' } }; -static xtensa_iclass_internal rsr_iclass = { - 2, - &rsr_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc2_args[] = { + { { 6 /* art */ }, 'o' } }; -static xtensa_operand_internal *icache_operand_list[] = { - &ais_operand, - &iiuimm8x4_operand +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc2_stateArgs[] = { + { { STATE_EPC2 }, 'i' } }; -static xtensa_iclass_internal icache_iclass = { - 2, - &icache_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc2_args[] = { + { { 6 /* art */ }, 'i' } }; -static xtensa_operand_internal *s8i_operand_list[] = { - &ait_operand, - &ais_operand, - &iiuimm8_operand +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc2_stateArgs[] = { + { { STATE_EPC2 }, 'o' } }; -static xtensa_iclass_internal s8i_iclass = { - 3, - &s8i_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc2_args[] = { + { { 6 /* art */ }, 'm' } }; -static xtensa_iclass_internal return_iclass = { - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc2_stateArgs[] = { + { { STATE_EPC2 }, 'm' } }; -static xtensa_operand_internal *dcache_operand_list[] = { - &ais_operand, - &iiuimm8x4_operand +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave2_args[] = { + { { 6 /* art */ }, 'o' } }; -static xtensa_iclass_internal dcache_iclass = { - 2, - &dcache_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave2_stateArgs[] = { + { { STATE_EXCSAVE2 }, 'i' } }; -static xtensa_operand_internal *s32i_operand_list[] = { - &ait_operand, - &ais_operand, - &iiuimm8x4_operand +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave2_args[] = { + { { 6 /* art */ }, 'i' } }; -static xtensa_iclass_internal s32i_iclass = { - 3, - &s32i_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave2_stateArgs[] = { + { { STATE_EXCSAVE2 }, 'o' } }; -static xtensa_operand_internal *jump_operand_list[] = { - &lisoffset_operand +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave2_args[] = { + { { 6 /* art */ }, 'm' } }; -static xtensa_iclass_internal jump_iclass = { - 1, - &jump_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave2_stateArgs[] = { + { { STATE_EXCSAVE2 }, 'm' } }; -static xtensa_operand_internal *addi_n_operand_list[] = { - &aor_operand, - &ais_operand, - &iiai4const_operand +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc3_args[] = { + { { 6 /* art */ }, 'o' } }; -static xtensa_iclass_internal addi_n_iclass = { - 3, - &addi_n_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc3_stateArgs[] = { + { { STATE_EPC3 }, 'i' } }; -static xtensa_iclass_internal sync_iclass = { - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc3_args[] = { + { { 6 /* art */ }, 'i' } }; -static xtensa_operand_internal *neg_operand_list[] = { - &aor_operand, - &ait_operand +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc3_stateArgs[] = { + { { STATE_EPC3 }, 'o' } }; -static xtensa_iclass_internal neg_iclass = { - 2, - &neg_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc3_args[] = { + { { 6 /* art */ }, 'm' } }; -static xtensa_iclass_internal syscall_iclass = { - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc3_stateArgs[] = { + { { STATE_EPC3 }, 'm' } }; -static xtensa_operand_internal *bsz12_operand_list[] = { - &ais_operand, - &lisimm12_operand +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave3_args[] = { + { { 6 /* art */ }, 'o' } }; -static xtensa_iclass_internal bsz12_iclass = { - 2, - &bsz12_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave3_stateArgs[] = { + { { STATE_EXCSAVE3 }, 'i' } }; -static xtensa_iclass_internal excw_iclass = { - 0, - 0 +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave3_args[] = { + { { 6 /* art */ }, 'i' } }; -static xtensa_operand_internal *movi_n_operand_list[] = { - &aos_operand, - &iisimm7_operand +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave3_stateArgs[] = { + { { STATE_EXCSAVE3 }, 'o' } }; -static xtensa_iclass_internal movi_n_iclass = { - 2, - &movi_n_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave3_args[] = { + { { 6 /* art */ }, 'm' } }; -static xtensa_operand_internal *rtlb_operand_list[] = { - &aot_operand, - &ais_operand +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave3_stateArgs[] = { + { { STATE_EXCSAVE3 }, 'm' } }; -static xtensa_iclass_internal rtlb_iclass = { - 2, - &rtlb_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc4_args[] = { + { { 6 /* art */ }, 'o' } }; -static xtensa_operand_internal *actl_operand_list[] = { - &aot_operand, - &ais_operand +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc4_stateArgs[] = { + { { STATE_EPC4 }, 'i' } }; -static xtensa_iclass_internal actl_iclass = { - 2, - &actl_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc4_args[] = { + { { 6 /* art */ }, 'i' } }; -static xtensa_operand_internal *srli_operand_list[] = { - &aor_operand, - &ait_operand, - &iis_operand +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc4_stateArgs[] = { + { { STATE_EPC4 }, 'o' } }; -static xtensa_iclass_internal srli_iclass = { - 3, - &srli_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc4_args[] = { + { { 6 /* art */ }, 'm' } }; -static xtensa_operand_internal *bsi8b_operand_list[] = { - &ais_operand, - &iibbi_operand, - &lisimm8_operand +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc4_stateArgs[] = { + { { STATE_EPC4 }, 'm' } }; -static xtensa_iclass_internal bsi8b_iclass = { - 3, - &bsi8b_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave4_args[] = { + { { 6 /* art */ }, 'o' } }; -static xtensa_operand_internal *acts_operand_list[] = { - &ait_operand, - &ais_operand +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave4_stateArgs[] = { + { { STATE_EXCSAVE4 }, 'i' } }; -static xtensa_iclass_internal acts_iclass = { - 2, - &acts_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave4_args[] = { + { { 6 /* art */ }, 'i' } }; -static xtensa_operand_internal *add_n_operand_list[] = { - &aor_operand, - &ais_operand, - &ait_operand +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave4_stateArgs[] = { + { { STATE_EXCSAVE4 }, 'o' } }; -static xtensa_iclass_internal add_n_iclass = { - 3, - &add_n_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave4_args[] = { + { { 6 /* art */ }, 'm' } }; -static xtensa_operand_internal *srai_operand_list[] = { - &aor_operand, - &ait_operand, - &iisar_operand +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave4_stateArgs[] = { + { { STATE_EXCSAVE4 }, 'm' } }; -static xtensa_iclass_internal srai_iclass = { - 3, - &srai_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps2_args[] = { + { { 6 /* art */ }, 'o' } }; -static xtensa_operand_internal *entry_operand_list[] = { - &abs_operand, - &iiuimm12x8_operand +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps2_stateArgs[] = { + { { STATE_EPS2 }, 'i' } }; -static xtensa_iclass_internal entry_iclass = { - 2, - &entry_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps2_args[] = { + { { 6 /* art */ }, 'i' } }; -static xtensa_operand_internal *l32e_operand_list[] = { - &aot_operand, - &ais_operand, - &iinimm4x2_operand +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps2_stateArgs[] = { + { { STATE_EPS2 }, 'o' } }; -static xtensa_iclass_internal l32e_iclass = { - 3, - &l32e_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps2_args[] = { + { { 6 /* art */ }, 'm' } }; -static xtensa_operand_internal *dpf_operand_list[] = { - &ais_operand, - &iiuimm8x4_operand +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps2_stateArgs[] = { + { { STATE_EPS2 }, 'm' } }; -static xtensa_iclass_internal dpf_iclass = { - 2, - &dpf_operand_list[0] +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps3_args[] = { + { { 6 /* art */ }, 'o' } }; -static xtensa_operand_internal *l32i_operand_list[] = { - &aot_operand, - &ais_operand, - &iiuimm8x4_operand +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps3_stateArgs[] = { + { { STATE_EPS3 }, 'i' } }; -static xtensa_iclass_internal l32i_iclass = { - 3, - &l32i_operand_list[0] -}; - -static xtensa_insnbuf abs_template (void); -static xtensa_insnbuf add_template (void); -static xtensa_insnbuf add_n_template (void); -static xtensa_insnbuf addi_template (void); -static xtensa_insnbuf addi_n_template (void); -static xtensa_insnbuf addmi_template (void); -static xtensa_insnbuf addx2_template (void); -static xtensa_insnbuf addx4_template (void); -static xtensa_insnbuf addx8_template (void); -static xtensa_insnbuf and_template (void); -static xtensa_insnbuf ball_template (void); -static xtensa_insnbuf bany_template (void); -static xtensa_insnbuf bbc_template (void); -static xtensa_insnbuf bbci_template (void); -static xtensa_insnbuf bbs_template (void); -static xtensa_insnbuf bbsi_template (void); -static xtensa_insnbuf beq_template (void); -static xtensa_insnbuf beqi_template (void); -static xtensa_insnbuf beqz_template (void); -static xtensa_insnbuf beqz_n_template (void); -static xtensa_insnbuf bge_template (void); -static xtensa_insnbuf bgei_template (void); -static xtensa_insnbuf bgeu_template (void); -static xtensa_insnbuf bgeui_template (void); -static xtensa_insnbuf bgez_template (void); -static xtensa_insnbuf blt_template (void); -static xtensa_insnbuf blti_template (void); -static xtensa_insnbuf bltu_template (void); -static xtensa_insnbuf bltui_template (void); -static xtensa_insnbuf bltz_template (void); -static xtensa_insnbuf bnall_template (void); -static xtensa_insnbuf bne_template (void); -static xtensa_insnbuf bnei_template (void); -static xtensa_insnbuf bnez_template (void); -static xtensa_insnbuf bnez_n_template (void); -static xtensa_insnbuf bnone_template (void); -static xtensa_insnbuf break_template (void); -static xtensa_insnbuf break_n_template (void); -static xtensa_insnbuf call0_template (void); -static xtensa_insnbuf call12_template (void); -static xtensa_insnbuf call4_template (void); -static xtensa_insnbuf call8_template (void); -static xtensa_insnbuf callx0_template (void); -static xtensa_insnbuf callx12_template (void); -static xtensa_insnbuf callx4_template (void); -static xtensa_insnbuf callx8_template (void); -static xtensa_insnbuf dhi_template (void); -static xtensa_insnbuf dhwb_template (void); -static xtensa_insnbuf dhwbi_template (void); -static xtensa_insnbuf dii_template (void); -static xtensa_insnbuf diwb_template (void); -static xtensa_insnbuf diwbi_template (void); -static xtensa_insnbuf dpfr_template (void); -static xtensa_insnbuf dpfro_template (void); -static xtensa_insnbuf dpfw_template (void); -static xtensa_insnbuf dpfwo_template (void); -static xtensa_insnbuf dsync_template (void); -static xtensa_insnbuf entry_template (void); -static xtensa_insnbuf esync_template (void); -static xtensa_insnbuf excw_template (void); -static xtensa_insnbuf extui_template (void); -static xtensa_insnbuf idtlb_template (void); -static xtensa_insnbuf idtlba_template (void); -static xtensa_insnbuf ihi_template (void); -static xtensa_insnbuf iii_template (void); -static xtensa_insnbuf iitlb_template (void); -static xtensa_insnbuf iitlba_template (void); -static xtensa_insnbuf ipf_template (void); -static xtensa_insnbuf isync_template (void); -static xtensa_insnbuf j_template (void); -static xtensa_insnbuf jx_template (void); -static xtensa_insnbuf l16si_template (void); -static xtensa_insnbuf l16ui_template (void); -static xtensa_insnbuf l32e_template (void); -static xtensa_insnbuf l32i_template (void); -static xtensa_insnbuf l32i_n_template (void); -static xtensa_insnbuf l32r_template (void); -static xtensa_insnbuf l8ui_template (void); -static xtensa_insnbuf ldct_template (void); -static xtensa_insnbuf lict_template (void); -static xtensa_insnbuf licw_template (void); -static xtensa_insnbuf loop_template (void); -static xtensa_insnbuf loopgtz_template (void); -static xtensa_insnbuf loopnez_template (void); -static xtensa_insnbuf memw_template (void); -static xtensa_insnbuf mov_n_template (void); -static xtensa_insnbuf moveqz_template (void); -static xtensa_insnbuf movgez_template (void); -static xtensa_insnbuf movi_template (void); -static xtensa_insnbuf movi_n_template (void); -static xtensa_insnbuf movltz_template (void); -static xtensa_insnbuf movnez_template (void); -static xtensa_insnbuf movsp_template (void); -static xtensa_insnbuf neg_template (void); -static xtensa_insnbuf nop_n_template (void); -static xtensa_insnbuf nsa_template (void); -static xtensa_insnbuf nsau_template (void); -static xtensa_insnbuf or_template (void); -static xtensa_insnbuf pdtlb_template (void); -static xtensa_insnbuf pitlb_template (void); -static xtensa_insnbuf rdtlb0_template (void); -static xtensa_insnbuf rdtlb1_template (void); -static xtensa_insnbuf ret_template (void); -static xtensa_insnbuf ret_n_template (void); -static xtensa_insnbuf retw_template (void); -static xtensa_insnbuf retw_n_template (void); -static xtensa_insnbuf rfde_template (void); -static xtensa_insnbuf rfe_template (void); -static xtensa_insnbuf rfi_template (void); -static xtensa_insnbuf rfwo_template (void); -static xtensa_insnbuf rfwu_template (void); -static xtensa_insnbuf ritlb0_template (void); -static xtensa_insnbuf ritlb1_template (void); -static xtensa_insnbuf rotw_template (void); -static xtensa_insnbuf rsil_template (void); -static xtensa_insnbuf rsr_template (void); -static xtensa_insnbuf rsync_template (void); -static xtensa_insnbuf s16i_template (void); -static xtensa_insnbuf s32e_template (void); -static xtensa_insnbuf s32i_template (void); -static xtensa_insnbuf s32i_n_template (void); -static xtensa_insnbuf s8i_template (void); -static xtensa_insnbuf sdct_template (void); -static xtensa_insnbuf sict_template (void); -static xtensa_insnbuf sicw_template (void); -static xtensa_insnbuf simcall_template (void); -static xtensa_insnbuf sll_template (void); -static xtensa_insnbuf slli_template (void); -static xtensa_insnbuf sra_template (void); -static xtensa_insnbuf srai_template (void); -static xtensa_insnbuf src_template (void); -static xtensa_insnbuf srl_template (void); -static xtensa_insnbuf srli_template (void); -static xtensa_insnbuf ssa8b_template (void); -static xtensa_insnbuf ssa8l_template (void); -static xtensa_insnbuf ssai_template (void); -static xtensa_insnbuf ssl_template (void); -static xtensa_insnbuf ssr_template (void); -static xtensa_insnbuf sub_template (void); -static xtensa_insnbuf subx2_template (void); -static xtensa_insnbuf subx4_template (void); -static xtensa_insnbuf subx8_template (void); -static xtensa_insnbuf syscall_template (void); -static xtensa_insnbuf waiti_template (void); -static xtensa_insnbuf wdtlb_template (void); -static xtensa_insnbuf witlb_template (void); -static xtensa_insnbuf wsr_template (void); -static xtensa_insnbuf xor_template (void); -static xtensa_insnbuf xsr_template (void); - -static xtensa_insnbuf -abs_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00001006 }; - return &template[0]; -} - -static xtensa_insnbuf -add_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000008 }; - return &template[0]; -} - -static xtensa_insnbuf -add_n_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00a00000 }; - return &template[0]; -} +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps3_args[] = { + { { 6 /* art */ }, 'i' } +}; -static xtensa_insnbuf -addi_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00200c00 }; - return &template[0]; -} +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps3_stateArgs[] = { + { { STATE_EPS3 }, 'o' } +}; -static xtensa_insnbuf -addi_n_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00b00000 }; - return &template[0]; -} +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps3_args[] = { + { { 6 /* art */ }, 'm' } +}; -static xtensa_insnbuf -addmi_template (void) +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps3_stateArgs[] = { + { { STATE_EPS3 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps4_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps4_stateArgs[] = { + { { STATE_EPS4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps4_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps4_stateArgs[] = { + { { STATE_EPS4 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps4_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps4_stateArgs[] = { + { { STATE_EPS4 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excvaddr_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excvaddr_stateArgs[] = { + { { STATE_EXCVADDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excvaddr_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excvaddr_stateArgs[] = { + { { STATE_EXCVADDR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excvaddr_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excvaddr_stateArgs[] = { + { { STATE_EXCVADDR }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_depc_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_depc_stateArgs[] = { + { { STATE_DEPC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_depc_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_depc_stateArgs[] = { + { { STATE_DEPC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_depc_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_depc_stateArgs[] = { + { { STATE_DEPC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_exccause_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_exccause_stateArgs[] = { + { { STATE_EXCCAUSE }, 'i' }, + { { STATE_XTSYNC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_exccause_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_exccause_stateArgs[] = { + { { STATE_EXCCAUSE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_exccause_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_exccause_stateArgs[] = { + { { STATE_EXCCAUSE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_misc0_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_misc0_stateArgs[] = { + { { STATE_MISC0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_misc0_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_misc0_stateArgs[] = { + { { STATE_MISC0 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_misc0_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_misc0_stateArgs[] = { + { { STATE_MISC0 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_misc1_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_misc1_stateArgs[] = { + { { STATE_MISC1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_misc1_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_misc1_stateArgs[] = { + { { STATE_MISC1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_misc1_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_misc1_stateArgs[] = { + { { STATE_MISC1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_prid_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfi_args[] = { + { { 40 /* s */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfi_stateArgs[] = { + { { STATE_PSWOE }, 'o' }, + { { STATE_PSCALLINC }, 'o' }, + { { STATE_PSOWB }, 'o' }, + { { STATE_PSUM }, 'o' }, + { { STATE_PSEXCM }, 'o' }, + { { STATE_PSINTLEVEL }, 'o' }, + { { STATE_EPC1 }, 'i' }, + { { STATE_EPC2 }, 'i' }, + { { STATE_EPC3 }, 'i' }, + { { STATE_EPC4 }, 'i' }, + { { STATE_EPS2 }, 'i' }, + { { STATE_EPS3 }, 'i' }, + { { STATE_EPS4 }, 'i' }, + { { STATE_InOCDMode }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wait_args[] = { + { { 40 /* s */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wait_stateArgs[] = { + { { STATE_PSINTLEVEL }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_interrupt_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_interrupt_stateArgs[] = { + { { STATE_INTERRUPT }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intset_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intset_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intclear_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intclear_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_intenable_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_intenable_stateArgs[] = { + { { STATE_INTENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intenable_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intenable_stateArgs[] = { + { { STATE_INTENABLE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_intenable_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_intenable_stateArgs[] = { + { { STATE_INTENABLE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_args[] = { + { { 34 /* imms */ }, 'i' }, + { { 33 /* immt */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_n_args[] = { + { { 34 /* imms */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_n_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreaka0_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreaka0_stateArgs[] = { + { { STATE_DBREAKA0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreaka0_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreaka0_stateArgs[] = { + { { STATE_DBREAKA0 }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreaka0_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreaka0_stateArgs[] = { + { { STATE_DBREAKA0 }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreakc0_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreakc0_stateArgs[] = { + { { STATE_DBREAKC0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreakc0_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreakc0_stateArgs[] = { + { { STATE_DBREAKC0 }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreakc0_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreakc0_stateArgs[] = { + { { STATE_DBREAKC0 }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreaka1_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreaka1_stateArgs[] = { + { { STATE_DBREAKA1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreaka1_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreaka1_stateArgs[] = { + { { STATE_DBREAKA1 }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreaka1_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreaka1_stateArgs[] = { + { { STATE_DBREAKA1 }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreakc1_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreakc1_stateArgs[] = { + { { STATE_DBREAKC1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreakc1_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreakc1_stateArgs[] = { + { { STATE_DBREAKC1 }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreakc1_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreakc1_stateArgs[] = { + { { STATE_DBREAKC1 }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreaka0_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreaka0_stateArgs[] = { + { { STATE_IBREAKA0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreaka0_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreaka0_stateArgs[] = { + { { STATE_IBREAKA0 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreaka0_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreaka0_stateArgs[] = { + { { STATE_IBREAKA0 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreaka1_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreaka1_stateArgs[] = { + { { STATE_IBREAKA1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreaka1_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreaka1_stateArgs[] = { + { { STATE_IBREAKA1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreaka1_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreaka1_stateArgs[] = { + { { STATE_IBREAKA1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreakenable_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreakenable_stateArgs[] = { + { { STATE_IBREAKENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreakenable_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreakenable_stateArgs[] = { + { { STATE_IBREAKENABLE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreakenable_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreakenable_stateArgs[] = { + { { STATE_IBREAKENABLE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_debugcause_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_debugcause_stateArgs[] = { + { { STATE_DEBUGCAUSE }, 'i' }, + { { STATE_DBNUM }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_debugcause_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_debugcause_stateArgs[] = { + { { STATE_DEBUGCAUSE }, 'o' }, + { { STATE_DBNUM }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_debugcause_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_debugcause_stateArgs[] = { + { { STATE_DEBUGCAUSE }, 'm' }, + { { STATE_DBNUM }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icount_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icount_stateArgs[] = { + { { STATE_ICOUNT }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icount_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_ICOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icount_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_ICOUNT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icountlevel_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icountlevel_stateArgs[] = { + { { STATE_ICOUNTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icountlevel_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icountlevel_stateArgs[] = { + { { STATE_ICOUNTLEVEL }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icountlevel_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icountlevel_stateArgs[] = { + { { STATE_ICOUNTLEVEL }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ddr_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ddr_stateArgs[] = { + { { STATE_DDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ddr_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ddr_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_DDR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ddr_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ddr_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_DDR }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfdo_stateArgs[] = { + { { STATE_InOCDMode }, 'm' }, + { { STATE_EPC4 }, 'i' }, + { { STATE_PSWOE }, 'o' }, + { { STATE_PSCALLINC }, 'o' }, + { { STATE_PSOWB }, 'o' }, + { { STATE_PSUM }, 'o' }, + { { STATE_PSEXCM }, 'o' }, + { { STATE_PSINTLEVEL }, 'o' }, + { { STATE_EPS4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfdd_stateArgs[] = { + { { STATE_InOCDMode }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccount_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccount_stateArgs[] = { + { { STATE_CCOUNT }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccount_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_CCOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccount_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_CCOUNT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare0_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare0_stateArgs[] = { + { { STATE_CCOMPARE0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare0_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare0_stateArgs[] = { + { { STATE_CCOMPARE0 }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare0_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare0_stateArgs[] = { + { { STATE_CCOMPARE0 }, 'm' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare1_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare1_stateArgs[] = { + { { STATE_CCOMPARE1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare1_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare1_stateArgs[] = { + { { STATE_CCOMPARE1 }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare1_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare1_stateArgs[] = { + { { STATE_CCOMPARE1 }, 'm' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare2_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare2_stateArgs[] = { + { { STATE_CCOMPARE2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare2_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare2_stateArgs[] = { + { { STATE_CCOMPARE2 }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare2_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare2_stateArgs[] = { + { { STATE_CCOMPARE2 }, 'm' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_icache_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 21 /* uimm8x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_icache_inv_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 21 /* uimm8x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_licx_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sicx_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dcache_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 21 /* uimm8x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dcache_ind_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 22 /* uimm4x16 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dcache_inv_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 21 /* uimm8x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dpf_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 21 /* uimm8x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sdct_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_ldct_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_idtlb_args[] = { + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_idtlb_stateArgs[] = { + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rdtlb_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wdtlb_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wdtlb_stateArgs[] = { + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_iitlb_args[] = { + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_ritlb_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_witlb_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_nsa_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_iclass_internal iclasses[] = { + { 0, 0 /* xt_iclass_excw */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_rfe */, + 2, Iclass_xt_iclass_rfe_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_rfde */, + 1, Iclass_xt_iclass_rfde_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_syscall */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_simcall */, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_call12_args, + 1, Iclass_xt_iclass_call12_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_call8_args, + 1, Iclass_xt_iclass_call8_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_call4_args, + 1, Iclass_xt_iclass_call4_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_callx12_args, + 1, Iclass_xt_iclass_callx12_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_callx8_args, + 1, Iclass_xt_iclass_callx8_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_callx4_args, + 1, Iclass_xt_iclass_callx4_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_entry_args, + 5, Iclass_xt_iclass_entry_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_movsp_args, + 2, Iclass_xt_iclass_movsp_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rotw_args, + 1, Iclass_xt_iclass_rotw_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_retw_args, + 4, Iclass_xt_iclass_retw_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_rfwou */, + 5, Iclass_xt_iclass_rfwou_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_l32e_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s32e_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_windowbase_args, + 1, Iclass_xt_iclass_rsr_windowbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_windowbase_args, + 1, Iclass_xt_iclass_wsr_windowbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_windowbase_args, + 1, Iclass_xt_iclass_xsr_windowbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_windowstart_args, + 1, Iclass_xt_iclass_rsr_windowstart_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_windowstart_args, + 1, Iclass_xt_iclass_wsr_windowstart_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_windowstart_args, + 1, Iclass_xt_iclass_xsr_windowstart_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_add_n_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_addi_n_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_bz6_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_ill_n */, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_loadi4_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_mov_n_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_movi_n_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_nopn */, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_retn_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_storei4_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_addi_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_addmi_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_addsub_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bit_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bsi8_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bsi8b_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bsi8u_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bst8_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_bsz12_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_call0_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_callx0_args, + 0, 0, 0, 0 }, + { 4, Iclass_xt_iclass_exti_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_ill */, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_jump_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_jumpx_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_l16ui_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_l16si_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_l32i_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_l32r_args, + 2, Iclass_xt_iclass_l32r_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_l8i_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_loop_args, + 3, Iclass_xt_iclass_loop_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_loopz_args, + 3, Iclass_xt_iclass_loopz_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_movi_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_movz_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_neg_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_nop */, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_return_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s16i_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s32i_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s8i_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_sar_args, + 1, Iclass_xt_iclass_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_sari_args, + 1, Iclass_xt_iclass_sari_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_shifts_args, + 1, Iclass_xt_iclass_shifts_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_shiftst_args, + 1, Iclass_xt_iclass_shiftst_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_shiftt_args, + 1, Iclass_xt_iclass_shiftt_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_slli_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_srai_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_srli_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_memw */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_extw */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_isync */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_sync */, + 1, Iclass_xt_iclass_sync_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_rsil_args, + 6, Iclass_xt_iclass_rsil_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_lend_args, + 1, Iclass_xt_iclass_rsr_lend_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_lend_args, + 1, Iclass_xt_iclass_wsr_lend_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_lend_args, + 1, Iclass_xt_iclass_xsr_lend_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_lcount_args, + 1, Iclass_xt_iclass_rsr_lcount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_lcount_args, + 2, Iclass_xt_iclass_wsr_lcount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_lcount_args, + 2, Iclass_xt_iclass_xsr_lcount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_lbeg_args, + 1, Iclass_xt_iclass_rsr_lbeg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_lbeg_args, + 1, Iclass_xt_iclass_wsr_lbeg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_lbeg_args, + 1, Iclass_xt_iclass_xsr_lbeg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_sar_args, + 1, Iclass_xt_iclass_rsr_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_sar_args, + 2, Iclass_xt_iclass_wsr_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_sar_args, + 1, Iclass_xt_iclass_xsr_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_litbase_args, + 2, Iclass_xt_iclass_rsr_litbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_litbase_args, + 2, Iclass_xt_iclass_wsr_litbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_litbase_args, + 2, Iclass_xt_iclass_xsr_litbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_176_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_208_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ps_args, + 6, Iclass_xt_iclass_rsr_ps_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ps_args, + 6, Iclass_xt_iclass_wsr_ps_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ps_args, + 6, Iclass_xt_iclass_xsr_ps_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc1_args, + 1, Iclass_xt_iclass_rsr_epc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc1_args, + 1, Iclass_xt_iclass_wsr_epc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc1_args, + 1, Iclass_xt_iclass_xsr_epc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave1_args, + 1, Iclass_xt_iclass_rsr_excsave1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave1_args, + 1, Iclass_xt_iclass_wsr_excsave1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave1_args, + 1, Iclass_xt_iclass_xsr_excsave1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc2_args, + 1, Iclass_xt_iclass_rsr_epc2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc2_args, + 1, Iclass_xt_iclass_wsr_epc2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc2_args, + 1, Iclass_xt_iclass_xsr_epc2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave2_args, + 1, Iclass_xt_iclass_rsr_excsave2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave2_args, + 1, Iclass_xt_iclass_wsr_excsave2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave2_args, + 1, Iclass_xt_iclass_xsr_excsave2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc3_args, + 1, Iclass_xt_iclass_rsr_epc3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc3_args, + 1, Iclass_xt_iclass_wsr_epc3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc3_args, + 1, Iclass_xt_iclass_xsr_epc3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave3_args, + 1, Iclass_xt_iclass_rsr_excsave3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave3_args, + 1, Iclass_xt_iclass_wsr_excsave3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave3_args, + 1, Iclass_xt_iclass_xsr_excsave3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc4_args, + 1, Iclass_xt_iclass_rsr_epc4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc4_args, + 1, Iclass_xt_iclass_wsr_epc4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc4_args, + 1, Iclass_xt_iclass_xsr_epc4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave4_args, + 1, Iclass_xt_iclass_rsr_excsave4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave4_args, + 1, Iclass_xt_iclass_wsr_excsave4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave4_args, + 1, Iclass_xt_iclass_xsr_excsave4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps2_args, + 1, Iclass_xt_iclass_rsr_eps2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps2_args, + 1, Iclass_xt_iclass_wsr_eps2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps2_args, + 1, Iclass_xt_iclass_xsr_eps2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps3_args, + 1, Iclass_xt_iclass_rsr_eps3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps3_args, + 1, Iclass_xt_iclass_wsr_eps3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps3_args, + 1, Iclass_xt_iclass_xsr_eps3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps4_args, + 1, Iclass_xt_iclass_rsr_eps4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps4_args, + 1, Iclass_xt_iclass_wsr_eps4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps4_args, + 1, Iclass_xt_iclass_xsr_eps4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excvaddr_args, + 1, Iclass_xt_iclass_rsr_excvaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excvaddr_args, + 1, Iclass_xt_iclass_wsr_excvaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excvaddr_args, + 1, Iclass_xt_iclass_xsr_excvaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_depc_args, + 1, Iclass_xt_iclass_rsr_depc_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_depc_args, + 1, Iclass_xt_iclass_wsr_depc_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_depc_args, + 1, Iclass_xt_iclass_xsr_depc_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_exccause_args, + 2, Iclass_xt_iclass_rsr_exccause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_exccause_args, + 1, Iclass_xt_iclass_wsr_exccause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_exccause_args, + 1, Iclass_xt_iclass_xsr_exccause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_misc0_args, + 1, Iclass_xt_iclass_rsr_misc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_misc0_args, + 1, Iclass_xt_iclass_wsr_misc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_misc0_args, + 1, Iclass_xt_iclass_xsr_misc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_misc1_args, + 1, Iclass_xt_iclass_rsr_misc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_misc1_args, + 1, Iclass_xt_iclass_wsr_misc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_misc1_args, + 1, Iclass_xt_iclass_xsr_misc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_prid_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_rfi_args, + 14, Iclass_xt_iclass_rfi_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wait_args, + 1, Iclass_xt_iclass_wait_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_interrupt_args, + 1, Iclass_xt_iclass_rsr_interrupt_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_intset_args, + 2, Iclass_xt_iclass_wsr_intset_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_intclear_args, + 2, Iclass_xt_iclass_wsr_intclear_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_intenable_args, + 1, Iclass_xt_iclass_rsr_intenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_intenable_args, + 1, Iclass_xt_iclass_wsr_intenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_intenable_args, + 1, Iclass_xt_iclass_xsr_intenable_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_break_args, + 2, Iclass_xt_iclass_break_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_break_n_args, + 2, Iclass_xt_iclass_break_n_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dbreaka0_args, + 1, Iclass_xt_iclass_rsr_dbreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dbreaka0_args, + 2, Iclass_xt_iclass_wsr_dbreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dbreaka0_args, + 2, Iclass_xt_iclass_xsr_dbreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dbreakc0_args, + 1, Iclass_xt_iclass_rsr_dbreakc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dbreakc0_args, + 2, Iclass_xt_iclass_wsr_dbreakc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dbreakc0_args, + 2, Iclass_xt_iclass_xsr_dbreakc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dbreaka1_args, + 1, Iclass_xt_iclass_rsr_dbreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dbreaka1_args, + 2, Iclass_xt_iclass_wsr_dbreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dbreaka1_args, + 2, Iclass_xt_iclass_xsr_dbreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dbreakc1_args, + 1, Iclass_xt_iclass_rsr_dbreakc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dbreakc1_args, + 2, Iclass_xt_iclass_wsr_dbreakc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dbreakc1_args, + 2, Iclass_xt_iclass_xsr_dbreakc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ibreaka0_args, + 1, Iclass_xt_iclass_rsr_ibreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ibreaka0_args, + 1, Iclass_xt_iclass_wsr_ibreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ibreaka0_args, + 1, Iclass_xt_iclass_xsr_ibreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ibreaka1_args, + 1, Iclass_xt_iclass_rsr_ibreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ibreaka1_args, + 1, Iclass_xt_iclass_wsr_ibreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ibreaka1_args, + 1, Iclass_xt_iclass_xsr_ibreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ibreakenable_args, + 1, Iclass_xt_iclass_rsr_ibreakenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ibreakenable_args, + 1, Iclass_xt_iclass_wsr_ibreakenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ibreakenable_args, + 1, Iclass_xt_iclass_xsr_ibreakenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_debugcause_args, + 2, Iclass_xt_iclass_rsr_debugcause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_debugcause_args, + 2, Iclass_xt_iclass_wsr_debugcause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_debugcause_args, + 2, Iclass_xt_iclass_xsr_debugcause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_icount_args, + 1, Iclass_xt_iclass_rsr_icount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_icount_args, + 2, Iclass_xt_iclass_wsr_icount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_icount_args, + 2, Iclass_xt_iclass_xsr_icount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_icountlevel_args, + 1, Iclass_xt_iclass_rsr_icountlevel_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_icountlevel_args, + 1, Iclass_xt_iclass_wsr_icountlevel_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_icountlevel_args, + 1, Iclass_xt_iclass_xsr_icountlevel_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ddr_args, + 1, Iclass_xt_iclass_rsr_ddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ddr_args, + 2, Iclass_xt_iclass_wsr_ddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ddr_args, + 2, Iclass_xt_iclass_xsr_ddr_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_rfdo */, + 9, Iclass_xt_iclass_rfdo_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_rfdd */, + 1, Iclass_xt_iclass_rfdd_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ccount_args, + 1, Iclass_xt_iclass_rsr_ccount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ccount_args, + 2, Iclass_xt_iclass_wsr_ccount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ccount_args, + 2, Iclass_xt_iclass_xsr_ccount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ccompare0_args, + 1, Iclass_xt_iclass_rsr_ccompare0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ccompare0_args, + 2, Iclass_xt_iclass_wsr_ccompare0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ccompare0_args, + 2, Iclass_xt_iclass_xsr_ccompare0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ccompare1_args, + 1, Iclass_xt_iclass_rsr_ccompare1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ccompare1_args, + 2, Iclass_xt_iclass_wsr_ccompare1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ccompare1_args, + 2, Iclass_xt_iclass_xsr_ccompare1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ccompare2_args, + 1, Iclass_xt_iclass_rsr_ccompare2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ccompare2_args, + 2, Iclass_xt_iclass_wsr_ccompare2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ccompare2_args, + 2, Iclass_xt_iclass_xsr_ccompare2_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_icache_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_icache_inv_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_licx_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_sicx_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_dcache_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_dcache_ind_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_dcache_inv_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_dpf_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_sdct_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_ldct_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_idtlb_args, + 1, Iclass_xt_iclass_idtlb_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_rdtlb_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_wdtlb_args, + 1, Iclass_xt_iclass_wdtlb_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_iitlb_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_ritlb_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_witlb_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_nsa_args, + 0, 0, 0, 0 } +}; + + +/* Opcode encodings. */ + +static void +Opcode_excw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x80200; +} + +static void +Opcode_rfe_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x300; +} + +static void +Opcode_rfde_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2300; +} + +static void +Opcode_syscall_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x500; +} + +static void +Opcode_simcall_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1500; +} + +static void +Opcode_call12_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5c0000; +} + +static void +Opcode_call8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x580000; +} + +static void +Opcode_call4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x540000; +} + +static void +Opcode_callx12_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf0000; +} + +static void +Opcode_callx8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb0000; +} + +static void +Opcode_callx4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x70000; +} + +static void +Opcode_entry_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6c0000; +} + +static void +Opcode_movsp_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x100; +} + +static void +Opcode_rotw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x804; +} + +static void +Opcode_retw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x60000; +} + +static void +Opcode_retw_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd10f; +} + +static void +Opcode_rfwo_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4300; +} + +static void +Opcode_rfwu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5300; +} + +static void +Opcode_l32e_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x90; +} + +static void +Opcode_s32e_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x94; +} + +static void +Opcode_rsr_windowbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4830; +} + +static void +Opcode_wsr_windowbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4831; +} + +static void +Opcode_xsr_windowbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4816; +} + +static void +Opcode_rsr_windowstart_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4930; +} + +static void +Opcode_wsr_windowstart_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4931; +} + +static void +Opcode_xsr_windowstart_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4916; +} + +static void +Opcode_add_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa000; +} + +static void +Opcode_addi_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb000; +} + +static void +Opcode_beqz_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc800; +} + +static void +Opcode_bnez_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xcc00; +} + +static void +Opcode_ill_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd60f; +} + +static void +Opcode_l32i_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8000; +} + +static void +Opcode_mov_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd000; +} + +static void +Opcode_movi_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc000; +} + +static void +Opcode_nop_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd30f; +} + +static void +Opcode_ret_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd00f; +} + +static void +Opcode_s32i_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9000; +} + +static void +Opcode_addi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200c00; +} + +static void +Opcode_addmi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200d00; +} + +static void +Opcode_add_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8; +} + +static void +Opcode_sub_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc; +} + +static void +Opcode_addx2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9; +} + +static void +Opcode_addx4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa; +} + +static void +Opcode_addx8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb; +} + +static void +Opcode_subx2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd; +} + +static void +Opcode_subx4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe; +} + +static void +Opcode_subx8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf; +} + +static void +Opcode_and_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1; +} + +static void +Opcode_or_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2; +} + +static void +Opcode_xor_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3; +} + +static void +Opcode_beqi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x680000; +} + +static void +Opcode_bnei_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x690000; +} + +static void +Opcode_bgei_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6b0000; +} + +static void +Opcode_blti_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6a0000; +} + +static void +Opcode_bbci_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700600; +} + +static void +Opcode_bbsi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700e00; +} + +static void +Opcode_bgeui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6f0000; +} + +static void +Opcode_bltui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6e0000; +} + +static void +Opcode_beq_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700100; +} + +static void +Opcode_bne_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700900; +} + +static void +Opcode_bge_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700a00; +} + +static void +Opcode_blt_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700200; +} + +static void +Opcode_bgeu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700b00; +} + +static void +Opcode_bltu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700300; +} + +static void +Opcode_bany_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700800; +} + +static void +Opcode_bnone_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700000; +} + +static void +Opcode_ball_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700400; +} + +static void +Opcode_bnall_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700c00; +} + +static void +Opcode_bbc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700500; +} + +static void +Opcode_bbs_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700d00; +} + +static void +Opcode_beqz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x640000; +} + +static void +Opcode_bnez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x650000; +} + +static void +Opcode_bgez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x670000; +} + +static void +Opcode_bltz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x660000; +} + +static void +Opcode_call0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x500000; +} + +static void +Opcode_callx0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30000; +} + +static void +Opcode_extui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x40; +} + +static void +Opcode_ill_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0; +} + +static void +Opcode_j_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x600000; +} + +static void +Opcode_jx_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa0000; +} + +static void +Opcode_l16ui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200100; +} + +static void +Opcode_l16si_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200900; +} + +static void +Opcode_l32i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200200; +} + +static void +Opcode_l32r_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x100000; +} + +static void +Opcode_l8ui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200000; +} + +static void +Opcode_loop_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6d0800; +} + +static void +Opcode_loopnez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6d0900; +} + +static void +Opcode_loopgtz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6d0a00; +} + +static void +Opcode_movi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200a00; +} + +static void +Opcode_moveqz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x38; +} + +static void +Opcode_movnez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x39; +} + +static void +Opcode_movltz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3a; +} + +static void +Opcode_movgez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b; +} + +static void +Opcode_neg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6; +} + +static void +Opcode_abs_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1006; +} + +static void +Opcode_nop_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf0200; +} + +static void +Opcode_ret_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x20000; +} + +static void +Opcode_s16i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200500; +} + +static void +Opcode_s32i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200600; +} + +static void +Opcode_s8i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200400; +} + +static void +Opcode_ssr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4; +} + +static void +Opcode_ssl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x104; +} + +static void +Opcode_ssa8l_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x204; +} + +static void +Opcode_ssa8b_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x304; +} + +static void +Opcode_ssai_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x404; +} + +static void +Opcode_sll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1a; +} + +static void +Opcode_src_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x18; +} + +static void +Opcode_srl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x19; +} + +static void +Opcode_sra_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1b; +} + +static void +Opcode_slli_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x10; +} + +static void +Opcode_srai_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x12; +} + +static void +Opcode_srli_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x14; +} + +static void +Opcode_memw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc0200; +} + +static void +Opcode_extw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd0200; +} + +static void +Opcode_isync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200; +} + +static void +Opcode_rsync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x10200; +} + +static void +Opcode_esync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x20200; +} + +static void +Opcode_dsync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30200; +} + +static void +Opcode_rsil_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x600; +} + +static void +Opcode_rsr_lend_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x130; +} + +static void +Opcode_wsr_lend_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x131; +} + +static void +Opcode_xsr_lend_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x116; +} + +static void +Opcode_rsr_lcount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x230; +} + +static void +Opcode_wsr_lcount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x231; +} + +static void +Opcode_xsr_lcount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x216; +} + +static void +Opcode_rsr_lbeg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30; +} + +static void +Opcode_wsr_lbeg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x31; +} + +static void +Opcode_xsr_lbeg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x16; +} + +static void +Opcode_rsr_sar_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x330; +} + +static void +Opcode_wsr_sar_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x331; +} + +static void +Opcode_xsr_sar_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x316; +} + +static void +Opcode_rsr_litbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x530; +} + +static void +Opcode_wsr_litbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x531; +} + +static void +Opcode_xsr_litbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x516; +} + +static void +Opcode_rsr_176_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb030; +} + +static void +Opcode_rsr_208_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd030; +} + +static void +Opcode_rsr_ps_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe630; +} + +static void +Opcode_wsr_ps_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe631; +} + +static void +Opcode_xsr_ps_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe616; +} + +static void +Opcode_rsr_epc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb130; +} + +static void +Opcode_wsr_epc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb131; +} + +static void +Opcode_xsr_epc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb116; +} + +static void +Opcode_rsr_excsave1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd130; +} + +static void +Opcode_wsr_excsave1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd131; +} + +static void +Opcode_xsr_excsave1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd116; +} + +static void +Opcode_rsr_epc2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb230; +} + +static void +Opcode_wsr_epc2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb231; +} + +static void +Opcode_xsr_epc2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb216; +} + +static void +Opcode_rsr_excsave2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd230; +} + +static void +Opcode_wsr_excsave2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd231; +} + +static void +Opcode_xsr_excsave2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd216; +} + +static void +Opcode_rsr_epc3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb330; +} + +static void +Opcode_wsr_epc3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb331; +} + +static void +Opcode_xsr_epc3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb316; +} + +static void +Opcode_rsr_excsave3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd330; +} + +static void +Opcode_wsr_excsave3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd331; +} + +static void +Opcode_xsr_excsave3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd316; +} + +static void +Opcode_rsr_epc4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb430; +} + +static void +Opcode_wsr_epc4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb431; +} + +static void +Opcode_xsr_epc4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb416; +} + +static void +Opcode_rsr_excsave4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd430; +} + +static void +Opcode_wsr_excsave4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd431; +} + +static void +Opcode_xsr_excsave4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd416; +} + +static void +Opcode_rsr_eps2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc230; +} + +static void +Opcode_wsr_eps2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc231; +} + +static void +Opcode_xsr_eps2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc216; +} + +static void +Opcode_rsr_eps3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc330; +} + +static void +Opcode_wsr_eps3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc331; +} + +static void +Opcode_xsr_eps3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc316; +} + +static void +Opcode_rsr_eps4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc430; +} + +static void +Opcode_wsr_eps4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc431; +} + +static void +Opcode_xsr_eps4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc416; +} + +static void +Opcode_rsr_excvaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xee30; +} + +static void +Opcode_wsr_excvaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xee31; +} + +static void +Opcode_xsr_excvaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xee16; +} + +static void +Opcode_rsr_depc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc030; +} + +static void +Opcode_wsr_depc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc031; +} + +static void +Opcode_xsr_depc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc016; +} + +static void +Opcode_rsr_exccause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe830; +} + +static void +Opcode_wsr_exccause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe831; +} + +static void +Opcode_xsr_exccause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe816; +} + +static void +Opcode_rsr_misc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf430; +} + +static void +Opcode_wsr_misc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf431; +} + +static void +Opcode_xsr_misc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf416; +} + +static void +Opcode_rsr_misc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf530; +} + +static void +Opcode_wsr_misc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf531; +} + +static void +Opcode_xsr_misc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf516; +} + +static void +Opcode_rsr_prid_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xeb30; +} + +static void +Opcode_rfi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x10300; +} + +static void +Opcode_waiti_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700; +} + +static void +Opcode_rsr_interrupt_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe230; +} + +static void +Opcode_wsr_intset_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe231; +} + +static void +Opcode_wsr_intclear_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe331; +} + +static void +Opcode_rsr_intenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe430; +} + +static void +Opcode_wsr_intenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe431; +} + +static void +Opcode_xsr_intenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe416; +} + +static void +Opcode_break_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00200d00 }; - return &template[0]; + slotbuf[0] = 0x400; } -static xtensa_insnbuf -addx2_template (void) +static void +Opcode_break_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00000009 }; - return &template[0]; + slotbuf[0] = 0xd20f; } -static xtensa_insnbuf -addx4_template (void) +static void +Opcode_rsr_dbreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x0000000a }; - return &template[0]; + slotbuf[0] = 0x9030; } -static xtensa_insnbuf -addx8_template (void) +static void +Opcode_wsr_dbreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x0000000b }; - return &template[0]; + slotbuf[0] = 0x9031; } -static xtensa_insnbuf -and_template (void) +static void +Opcode_xsr_dbreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00000001 }; - return &template[0]; + slotbuf[0] = 0x9016; } -static xtensa_insnbuf -ball_template (void) +static void +Opcode_rsr_dbreakc0_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00700400 }; - return &template[0]; + slotbuf[0] = 0xa030; } -static xtensa_insnbuf -bany_template (void) +static void +Opcode_wsr_dbreakc0_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00700800 }; - return &template[0]; + slotbuf[0] = 0xa031; } -static xtensa_insnbuf -bbc_template (void) +static void +Opcode_xsr_dbreakc0_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00700500 }; - return &template[0]; + slotbuf[0] = 0xa016; } -static xtensa_insnbuf -bbci_template (void) +static void +Opcode_rsr_dbreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00700600 }; - return &template[0]; + slotbuf[0] = 0x9130; } -static xtensa_insnbuf -bbs_template (void) +static void +Opcode_wsr_dbreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00700d00 }; - return &template[0]; + slotbuf[0] = 0x9131; } -static xtensa_insnbuf -bbsi_template (void) +static void +Opcode_xsr_dbreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00700e00 }; - return &template[0]; + slotbuf[0] = 0x9116; } -static xtensa_insnbuf -beq_template (void) +static void +Opcode_rsr_dbreakc1_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00700100 }; - return &template[0]; + slotbuf[0] = 0xa130; } -static xtensa_insnbuf -beqi_template (void) +static void +Opcode_wsr_dbreakc1_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00680000 }; - return &template[0]; + slotbuf[0] = 0xa131; } -static xtensa_insnbuf -beqz_template (void) +static void +Opcode_xsr_dbreakc1_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00640000 }; - return &template[0]; + slotbuf[0] = 0xa116; } -static xtensa_insnbuf -beqz_n_template (void) +static void +Opcode_rsr_ibreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00c80000 }; - return &template[0]; + slotbuf[0] = 0x8030; } -static xtensa_insnbuf -bge_template (void) +static void +Opcode_wsr_ibreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00700a00 }; - return &template[0]; + slotbuf[0] = 0x8031; } -static xtensa_insnbuf -bgei_template (void) +static void +Opcode_xsr_ibreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x006b0000 }; - return &template[0]; + slotbuf[0] = 0x8016; } -static xtensa_insnbuf -bgeu_template (void) +static void +Opcode_rsr_ibreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00700b00 }; - return &template[0]; + slotbuf[0] = 0x8130; } -static xtensa_insnbuf -bgeui_template (void) +static void +Opcode_wsr_ibreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x006f0000 }; - return &template[0]; + slotbuf[0] = 0x8131; } -static xtensa_insnbuf -bgez_template (void) +static void +Opcode_xsr_ibreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00670000 }; - return &template[0]; + slotbuf[0] = 0x8116; } -static xtensa_insnbuf -blt_template (void) +static void +Opcode_rsr_ibreakenable_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00700200 }; - return &template[0]; + slotbuf[0] = 0x6030; } -static xtensa_insnbuf -blti_template (void) +static void +Opcode_wsr_ibreakenable_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x006a0000 }; - return &template[0]; + slotbuf[0] = 0x6031; } -static xtensa_insnbuf -bltu_template (void) +static void +Opcode_xsr_ibreakenable_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00700300 }; - return &template[0]; + slotbuf[0] = 0x6016; } -static xtensa_insnbuf -bltui_template (void) +static void +Opcode_rsr_debugcause_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x006e0000 }; - return &template[0]; + slotbuf[0] = 0xe930; } -static xtensa_insnbuf -bltz_template (void) +static void +Opcode_wsr_debugcause_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00660000 }; - return &template[0]; + slotbuf[0] = 0xe931; } -static xtensa_insnbuf -bnall_template (void) +static void +Opcode_xsr_debugcause_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00700c00 }; - return &template[0]; + slotbuf[0] = 0xe916; } -static xtensa_insnbuf -bne_template (void) +static void +Opcode_rsr_icount_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00700900 }; - return &template[0]; + slotbuf[0] = 0xec30; } -static xtensa_insnbuf -bnei_template (void) +static void +Opcode_wsr_icount_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00690000 }; - return &template[0]; + slotbuf[0] = 0xec31; } -static xtensa_insnbuf -bnez_template (void) +static void +Opcode_xsr_icount_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00650000 }; - return &template[0]; + slotbuf[0] = 0xec16; } -static xtensa_insnbuf -bnez_n_template (void) +static void +Opcode_rsr_icountlevel_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00cc0000 }; - return &template[0]; + slotbuf[0] = 0xed30; } -static xtensa_insnbuf -bnone_template (void) +static void +Opcode_wsr_icountlevel_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00700000 }; - return &template[0]; + slotbuf[0] = 0xed31; } -static xtensa_insnbuf -break_template (void) +static void +Opcode_xsr_icountlevel_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00000400 }; - return &template[0]; + slotbuf[0] = 0xed16; } -static xtensa_insnbuf -break_n_template (void) +static void +Opcode_rsr_ddr_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00d20f00 }; - return &template[0]; + slotbuf[0] = 0x6830; } -static xtensa_insnbuf -call0_template (void) +static void +Opcode_wsr_ddr_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00500000 }; - return &template[0]; + slotbuf[0] = 0x6831; } -static xtensa_insnbuf -call12_template (void) +static void +Opcode_xsr_ddr_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x005c0000 }; - return &template[0]; + slotbuf[0] = 0x6816; } -static xtensa_insnbuf -call4_template (void) +static void +Opcode_rfdo_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00540000 }; - return &template[0]; + slotbuf[0] = 0xe1f; } -static xtensa_insnbuf -call8_template (void) +static void +Opcode_rfdd_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00580000 }; - return &template[0]; + slotbuf[0] = 0x10e1f; } -static xtensa_insnbuf -callx0_template (void) +static void +Opcode_rsr_ccount_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00030000 }; - return &template[0]; + slotbuf[0] = 0xea30; } -static xtensa_insnbuf -callx12_template (void) +static void +Opcode_wsr_ccount_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x000f0000 }; - return &template[0]; + slotbuf[0] = 0xea31; } -static xtensa_insnbuf -callx4_template (void) +static void +Opcode_xsr_ccount_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00070000 }; - return &template[0]; + slotbuf[0] = 0xea16; } -static xtensa_insnbuf -callx8_template (void) +static void +Opcode_rsr_ccompare0_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x000b0000 }; - return &template[0]; + slotbuf[0] = 0xf030; } -static xtensa_insnbuf -dhi_template (void) +static void +Opcode_wsr_ccompare0_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00260700 }; - return &template[0]; + slotbuf[0] = 0xf031; } -static xtensa_insnbuf -dhwb_template (void) +static void +Opcode_xsr_ccompare0_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00240700 }; - return &template[0]; + slotbuf[0] = 0xf016; } -static xtensa_insnbuf -dhwbi_template (void) +static void +Opcode_rsr_ccompare1_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00250700 }; - return &template[0]; + slotbuf[0] = 0xf130; } -static xtensa_insnbuf -dii_template (void) +static void +Opcode_wsr_ccompare1_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00270700 }; - return &template[0]; + slotbuf[0] = 0xf131; } -static xtensa_insnbuf -diwb_template (void) +static void +Opcode_xsr_ccompare1_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00280740 }; - return &template[0]; + slotbuf[0] = 0xf116; } -static xtensa_insnbuf -diwbi_template (void) +static void +Opcode_rsr_ccompare2_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00280750 }; - return &template[0]; + slotbuf[0] = 0xf230; } -static xtensa_insnbuf -dpfr_template (void) +static void +Opcode_wsr_ccompare2_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00200700 }; - return &template[0]; + slotbuf[0] = 0xf231; } -static xtensa_insnbuf -dpfro_template (void) +static void +Opcode_xsr_ccompare2_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00220700 }; - return &template[0]; + slotbuf[0] = 0xf216; } -static xtensa_insnbuf -dpfw_template (void) +static void +Opcode_ipf_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00210700 }; - return &template[0]; + slotbuf[0] = 0x2c0700; } -static xtensa_insnbuf -dpfwo_template (void) +static void +Opcode_ihi_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00230700 }; - return &template[0]; + slotbuf[0] = 0x2e0700; } -static xtensa_insnbuf -dsync_template (void) +static void +Opcode_iii_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00030200 }; - return &template[0]; + slotbuf[0] = 0x2f0700; } -static xtensa_insnbuf -entry_template (void) +static void +Opcode_lict_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x006c0000 }; - return &template[0]; + slotbuf[0] = 0x1f; } -static xtensa_insnbuf -esync_template (void) +static void +Opcode_licw_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00020200 }; - return &template[0]; + slotbuf[0] = 0x21f; } -static xtensa_insnbuf -excw_template (void) +static void +Opcode_sict_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00080200 }; - return &template[0]; + slotbuf[0] = 0x11f; } -static xtensa_insnbuf -extui_template (void) +static void +Opcode_sicw_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00000040 }; - return &template[0]; + slotbuf[0] = 0x31f; } -static xtensa_insnbuf -idtlb_template (void) +static void +Opcode_dhwb_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00000c05 }; - return &template[0]; + slotbuf[0] = 0x240700; } -static xtensa_insnbuf -idtlba_template (void) +static void +Opcode_dhwbi_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00000805 }; - return &template[0]; + slotbuf[0] = 0x250700; } -static xtensa_insnbuf -ihi_template (void) +static void +Opcode_diwb_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x002e0700 }; - return &template[0]; + slotbuf[0] = 0x280740; } -static xtensa_insnbuf -iii_template (void) +static void +Opcode_diwbi_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x002f0700 }; - return &template[0]; + slotbuf[0] = 0x280750; } -static xtensa_insnbuf -iitlb_template (void) +static void +Opcode_dhi_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00000405 }; - return &template[0]; + slotbuf[0] = 0x260700; } -static xtensa_insnbuf -iitlba_template (void) +static void +Opcode_dii_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00000005 }; - return &template[0]; + slotbuf[0] = 0x270700; } -static xtensa_insnbuf -ipf_template (void) +static void +Opcode_dpfr_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x002c0700 }; - return &template[0]; + slotbuf[0] = 0x200700; } -static xtensa_insnbuf -isync_template (void) +static void +Opcode_dpfw_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00000200 }; - return &template[0]; + slotbuf[0] = 0x210700; } -static xtensa_insnbuf -j_template (void) +static void +Opcode_dpfro_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00600000 }; - return &template[0]; + slotbuf[0] = 0x220700; } -static xtensa_insnbuf -jx_template (void) +static void +Opcode_dpfwo_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x000a0000 }; - return &template[0]; + slotbuf[0] = 0x230700; } -static xtensa_insnbuf -l16si_template (void) +static void +Opcode_sdct_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00200900 }; - return &template[0]; + slotbuf[0] = 0x91f; } -static xtensa_insnbuf -l16ui_template (void) +static void +Opcode_ldct_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00200100 }; - return &template[0]; + slotbuf[0] = 0x81f; } -static xtensa_insnbuf -l32e_template (void) +static void +Opcode_idtlb_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00000090 }; - return &template[0]; + slotbuf[0] = 0xc05; } -static xtensa_insnbuf -l32i_template (void) +static void +Opcode_pdtlb_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00200200 }; - return &template[0]; + slotbuf[0] = 0xd05; } -static xtensa_insnbuf -l32i_n_template (void) +static void +Opcode_rdtlb0_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00800000 }; - return &template[0]; + slotbuf[0] = 0xb05; } -static xtensa_insnbuf -l32r_template (void) +static void +Opcode_rdtlb1_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00100000 }; - return &template[0]; + slotbuf[0] = 0xf05; } -static xtensa_insnbuf -l8ui_template (void) +static void +Opcode_wdtlb_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x00200000 }; - return &template[0]; + slotbuf[0] = 0xe05; } -static xtensa_insnbuf -ldct_template (void) +static void +Opcode_iitlb_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x0000081f }; - return &template[0]; + slotbuf[0] = 0x405; } -static xtensa_insnbuf -lict_template (void) +static void +Opcode_pitlb_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x0000001f }; - return &template[0]; + slotbuf[0] = 0x505; } -static xtensa_insnbuf -licw_template (void) +static void +Opcode_ritlb0_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x0000021f }; - return &template[0]; + slotbuf[0] = 0x305; } -static xtensa_insnbuf -loop_template (void) +static void +Opcode_ritlb1_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x006d0800 }; - return &template[0]; + slotbuf[0] = 0x705; } -static xtensa_insnbuf -loopgtz_template (void) +static void +Opcode_witlb_Slot_inst_encode (xtensa_insnbuf slotbuf) { - static xtensa_insnbuf_word template[] = { 0x006d0a00 }; - return &template[0]; + slotbuf[0] = 0x605; } -static xtensa_insnbuf -loopnez_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x006d0900 }; - return &template[0]; -} +static void +Opcode_nsa_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe04; +} + +static void +Opcode_nsau_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf04; +} + +xtensa_opcode_encode_fn Opcode_excw_encode_fns[] = { + Opcode_excw_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_rfe_encode_fns[] = { + Opcode_rfe_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_rfde_encode_fns[] = { + Opcode_rfde_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_syscall_encode_fns[] = { + Opcode_syscall_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_simcall_encode_fns[] = { + Opcode_simcall_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_call12_encode_fns[] = { + Opcode_call12_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_call8_encode_fns[] = { + Opcode_call8_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_call4_encode_fns[] = { + Opcode_call4_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_callx12_encode_fns[] = { + Opcode_callx12_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_callx8_encode_fns[] = { + Opcode_callx8_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_callx4_encode_fns[] = { + Opcode_callx4_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_entry_encode_fns[] = { + Opcode_entry_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_movsp_encode_fns[] = { + Opcode_movsp_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_rotw_encode_fns[] = { + Opcode_rotw_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_retw_encode_fns[] = { + Opcode_retw_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_retw_n_encode_fns[] = { + 0, 0, Opcode_retw_n_Slot_inst16b_encode +}; + +xtensa_opcode_encode_fn Opcode_rfwo_encode_fns[] = { + Opcode_rfwo_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_rfwu_encode_fns[] = { + Opcode_rfwu_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_l32e_encode_fns[] = { + Opcode_l32e_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_s32e_encode_fns[] = { + Opcode_s32e_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_rsr_windowbase_encode_fns[] = { + Opcode_rsr_windowbase_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_wsr_windowbase_encode_fns[] = { + Opcode_wsr_windowbase_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_xsr_windowbase_encode_fns[] = { + Opcode_xsr_windowbase_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_rsr_windowstart_encode_fns[] = { + Opcode_rsr_windowstart_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_wsr_windowstart_encode_fns[] = { + Opcode_wsr_windowstart_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_xsr_windowstart_encode_fns[] = { + Opcode_xsr_windowstart_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_add_n_encode_fns[] = { + 0, Opcode_add_n_Slot_inst16a_encode, 0 +}; + +xtensa_opcode_encode_fn Opcode_addi_n_encode_fns[] = { + 0, Opcode_addi_n_Slot_inst16a_encode, 0 +}; + +xtensa_opcode_encode_fn Opcode_beqz_n_encode_fns[] = { + 0, 0, Opcode_beqz_n_Slot_inst16b_encode +}; + +xtensa_opcode_encode_fn Opcode_bnez_n_encode_fns[] = { + 0, 0, Opcode_bnez_n_Slot_inst16b_encode +}; + +xtensa_opcode_encode_fn Opcode_ill_n_encode_fns[] = { + 0, 0, Opcode_ill_n_Slot_inst16b_encode +}; + +xtensa_opcode_encode_fn Opcode_l32i_n_encode_fns[] = { + 0, Opcode_l32i_n_Slot_inst16a_encode, 0 +}; + +xtensa_opcode_encode_fn Opcode_mov_n_encode_fns[] = { + 0, 0, Opcode_mov_n_Slot_inst16b_encode +}; + +xtensa_opcode_encode_fn Opcode_movi_n_encode_fns[] = { + 0, 0, Opcode_movi_n_Slot_inst16b_encode +}; + +xtensa_opcode_encode_fn Opcode_nop_n_encode_fns[] = { + 0, 0, Opcode_nop_n_Slot_inst16b_encode +}; + +xtensa_opcode_encode_fn Opcode_ret_n_encode_fns[] = { + 0, 0, Opcode_ret_n_Slot_inst16b_encode +}; + +xtensa_opcode_encode_fn Opcode_s32i_n_encode_fns[] = { + 0, Opcode_s32i_n_Slot_inst16a_encode, 0 +}; + +xtensa_opcode_encode_fn Opcode_addi_encode_fns[] = { + Opcode_addi_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_addmi_encode_fns[] = { + Opcode_addmi_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_add_encode_fns[] = { + Opcode_add_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_sub_encode_fns[] = { + Opcode_sub_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_addx2_encode_fns[] = { + Opcode_addx2_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_addx4_encode_fns[] = { + Opcode_addx4_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_addx8_encode_fns[] = { + Opcode_addx8_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_subx2_encode_fns[] = { + Opcode_subx2_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_subx4_encode_fns[] = { + Opcode_subx4_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_subx8_encode_fns[] = { + Opcode_subx8_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_and_encode_fns[] = { + Opcode_and_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_or_encode_fns[] = { + Opcode_or_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_xor_encode_fns[] = { + Opcode_xor_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_beqi_encode_fns[] = { + Opcode_beqi_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_bnei_encode_fns[] = { + Opcode_bnei_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_bgei_encode_fns[] = { + Opcode_bgei_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_blti_encode_fns[] = { + Opcode_blti_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_bbci_encode_fns[] = { + Opcode_bbci_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_bbsi_encode_fns[] = { + Opcode_bbsi_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_bgeui_encode_fns[] = { + Opcode_bgeui_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_bltui_encode_fns[] = { + Opcode_bltui_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_beq_encode_fns[] = { + Opcode_beq_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_bne_encode_fns[] = { + Opcode_bne_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_bge_encode_fns[] = { + Opcode_bge_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_blt_encode_fns[] = { + Opcode_blt_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -memw_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x000c0200 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_bgeu_encode_fns[] = { + Opcode_bgeu_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -mov_n_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00d00000 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_bltu_encode_fns[] = { + Opcode_bltu_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -moveqz_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000038 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_bany_encode_fns[] = { + Opcode_bany_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -movgez_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x0000003b }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_bnone_encode_fns[] = { + Opcode_bnone_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -movi_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00200a00 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_ball_encode_fns[] = { + Opcode_ball_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -movi_n_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00c00000 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_bnall_encode_fns[] = { + Opcode_bnall_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -movltz_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x0000003a }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_bbc_encode_fns[] = { + Opcode_bbc_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -movnez_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000039 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_bbs_encode_fns[] = { + Opcode_bbs_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -movsp_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000100 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_beqz_encode_fns[] = { + Opcode_beqz_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -neg_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000006 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_bnez_encode_fns[] = { + Opcode_bnez_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -nop_n_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00d30f00 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_bgez_encode_fns[] = { + Opcode_bgez_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -nsa_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000e04 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_bltz_encode_fns[] = { + Opcode_bltz_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -nsau_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000f04 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_call0_encode_fns[] = { + Opcode_call0_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -or_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000002 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_callx0_encode_fns[] = { + Opcode_callx0_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -pdtlb_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000d05 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_extui_encode_fns[] = { + Opcode_extui_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -pitlb_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000505 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_ill_encode_fns[] = { + Opcode_ill_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -rdtlb0_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000b05 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_j_encode_fns[] = { + Opcode_j_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -rdtlb1_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000f05 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_jx_encode_fns[] = { + Opcode_jx_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -ret_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00020000 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_l16ui_encode_fns[] = { + Opcode_l16ui_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -ret_n_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00d00f00 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_l16si_encode_fns[] = { + Opcode_l16si_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -retw_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00060000 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_l32i_encode_fns[] = { + Opcode_l32i_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -retw_n_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00d10f00 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_l32r_encode_fns[] = { + Opcode_l32r_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -rfde_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00002300 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_l8ui_encode_fns[] = { + Opcode_l8ui_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -rfe_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000300 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_loop_encode_fns[] = { + Opcode_loop_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -rfi_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00010300 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_loopnez_encode_fns[] = { + Opcode_loopnez_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -rfwo_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00004300 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_loopgtz_encode_fns[] = { + Opcode_loopgtz_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -rfwu_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00005300 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_movi_encode_fns[] = { + Opcode_movi_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -ritlb0_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000305 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_moveqz_encode_fns[] = { + Opcode_moveqz_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -ritlb1_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000705 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_movnez_encode_fns[] = { + Opcode_movnez_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -rotw_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000804 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_movltz_encode_fns[] = { + Opcode_movltz_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -rsil_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000600 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_movgez_encode_fns[] = { + Opcode_movgez_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -rsr_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000030 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_neg_encode_fns[] = { + Opcode_neg_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -rsync_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00010200 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_abs_encode_fns[] = { + Opcode_abs_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -s16i_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00200500 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_nop_encode_fns[] = { + Opcode_nop_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -s32e_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000094 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_ret_encode_fns[] = { + Opcode_ret_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -s32i_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00200600 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_s16i_encode_fns[] = { + Opcode_s16i_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -s32i_n_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00900000 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_s32i_encode_fns[] = { + Opcode_s32i_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -s8i_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00200400 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_s8i_encode_fns[] = { + Opcode_s8i_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -sdct_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x0000091f }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_ssr_encode_fns[] = { + Opcode_ssr_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -sict_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x0000011f }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_ssl_encode_fns[] = { + Opcode_ssl_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -sicw_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x0000031f }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_ssa8l_encode_fns[] = { + Opcode_ssa8l_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -simcall_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00001500 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_ssa8b_encode_fns[] = { + Opcode_ssa8b_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -sll_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x0000001a }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_ssai_encode_fns[] = { + Opcode_ssai_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -slli_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000010 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_sll_encode_fns[] = { + Opcode_sll_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -sra_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x0000001b }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_src_encode_fns[] = { + Opcode_src_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -srai_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000012 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_srl_encode_fns[] = { + Opcode_srl_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -src_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000018 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_sra_encode_fns[] = { + Opcode_sra_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -srl_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000019 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_slli_encode_fns[] = { + Opcode_slli_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -srli_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000014 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_srai_encode_fns[] = { + Opcode_srai_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -ssa8b_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000304 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_srli_encode_fns[] = { + Opcode_srli_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -ssa8l_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000204 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_memw_encode_fns[] = { + Opcode_memw_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -ssai_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000404 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_extw_encode_fns[] = { + Opcode_extw_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -ssl_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000104 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_isync_encode_fns[] = { + Opcode_isync_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -ssr_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000004 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_rsync_encode_fns[] = { + Opcode_rsync_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -sub_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x0000000c }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_esync_encode_fns[] = { + Opcode_esync_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -subx2_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x0000000d }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_dsync_encode_fns[] = { + Opcode_dsync_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -subx4_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x0000000e }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_rsil_encode_fns[] = { + Opcode_rsil_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -subx8_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x0000000f }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_rsr_lend_encode_fns[] = { + Opcode_rsr_lend_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -syscall_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000500 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_wsr_lend_encode_fns[] = { + Opcode_wsr_lend_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -waiti_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000700 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_xsr_lend_encode_fns[] = { + Opcode_xsr_lend_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -wdtlb_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000e05 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_rsr_lcount_encode_fns[] = { + Opcode_rsr_lcount_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -witlb_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000605 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_wsr_lcount_encode_fns[] = { + Opcode_wsr_lcount_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -wsr_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000031 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_xsr_lcount_encode_fns[] = { + Opcode_xsr_lcount_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -xor_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000003 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_rsr_lbeg_encode_fns[] = { + Opcode_rsr_lbeg_Slot_inst_encode, 0, 0 +}; -static xtensa_insnbuf -xsr_template (void) -{ - static xtensa_insnbuf_word template[] = { 0x00000016 }; - return &template[0]; -} +xtensa_opcode_encode_fn Opcode_wsr_lbeg_encode_fns[] = { + Opcode_wsr_lbeg_Slot_inst_encode, 0, 0 +}; -static xtensa_opcode_internal abs_opcode = { - "abs", - 3, - abs_template, - &neg_iclass +xtensa_opcode_encode_fn Opcode_xsr_lbeg_encode_fns[] = { + Opcode_xsr_lbeg_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal add_opcode = { - "add", - 3, - add_template, - &addsub_iclass +xtensa_opcode_encode_fn Opcode_rsr_sar_encode_fns[] = { + Opcode_rsr_sar_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal add_n_opcode = { - "add.n", - 2, - add_n_template, - &add_n_iclass +xtensa_opcode_encode_fn Opcode_wsr_sar_encode_fns[] = { + Opcode_wsr_sar_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal addi_opcode = { - "addi", - 3, - addi_template, - &addi_iclass +xtensa_opcode_encode_fn Opcode_xsr_sar_encode_fns[] = { + Opcode_xsr_sar_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal addi_n_opcode = { - "addi.n", - 2, - addi_n_template, - &addi_n_iclass +xtensa_opcode_encode_fn Opcode_rsr_litbase_encode_fns[] = { + Opcode_rsr_litbase_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal addmi_opcode = { - "addmi", - 3, - addmi_template, - &addmi_iclass +xtensa_opcode_encode_fn Opcode_wsr_litbase_encode_fns[] = { + Opcode_wsr_litbase_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal addx2_opcode = { - "addx2", - 3, - addx2_template, - &addsub_iclass +xtensa_opcode_encode_fn Opcode_xsr_litbase_encode_fns[] = { + Opcode_xsr_litbase_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal addx4_opcode = { - "addx4", - 3, - addx4_template, - &addsub_iclass +xtensa_opcode_encode_fn Opcode_rsr_176_encode_fns[] = { + Opcode_rsr_176_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal addx8_opcode = { - "addx8", - 3, - addx8_template, - &addsub_iclass +xtensa_opcode_encode_fn Opcode_rsr_208_encode_fns[] = { + Opcode_rsr_208_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal and_opcode = { - "and", - 3, - and_template, - &bit_iclass +xtensa_opcode_encode_fn Opcode_rsr_ps_encode_fns[] = { + Opcode_rsr_ps_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal ball_opcode = { - "ball", - 3, - ball_template, - &bst8_iclass +xtensa_opcode_encode_fn Opcode_wsr_ps_encode_fns[] = { + Opcode_wsr_ps_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal bany_opcode = { - "bany", - 3, - bany_template, - &bst8_iclass +xtensa_opcode_encode_fn Opcode_xsr_ps_encode_fns[] = { + Opcode_xsr_ps_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal bbc_opcode = { - "bbc", - 3, - bbc_template, - &bst8_iclass +xtensa_opcode_encode_fn Opcode_rsr_epc1_encode_fns[] = { + Opcode_rsr_epc1_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal bbci_opcode = { - "bbci", - 3, - bbci_template, - &bsi8b_iclass +xtensa_opcode_encode_fn Opcode_wsr_epc1_encode_fns[] = { + Opcode_wsr_epc1_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal bbs_opcode = { - "bbs", - 3, - bbs_template, - &bst8_iclass +xtensa_opcode_encode_fn Opcode_xsr_epc1_encode_fns[] = { + Opcode_xsr_epc1_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal bbsi_opcode = { - "bbsi", - 3, - bbsi_template, - &bsi8b_iclass +xtensa_opcode_encode_fn Opcode_rsr_excsave1_encode_fns[] = { + Opcode_rsr_excsave1_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal beq_opcode = { - "beq", - 3, - beq_template, - &bst8_iclass +xtensa_opcode_encode_fn Opcode_wsr_excsave1_encode_fns[] = { + Opcode_wsr_excsave1_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal beqi_opcode = { - "beqi", - 3, - beqi_template, - &bsi8_iclass +xtensa_opcode_encode_fn Opcode_xsr_excsave1_encode_fns[] = { + Opcode_xsr_excsave1_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal beqz_opcode = { - "beqz", - 3, - beqz_template, - &bsz12_iclass +xtensa_opcode_encode_fn Opcode_rsr_epc2_encode_fns[] = { + Opcode_rsr_epc2_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal beqz_n_opcode = { - "beqz.n", - 2, - beqz_n_template, - &bz6_iclass +xtensa_opcode_encode_fn Opcode_wsr_epc2_encode_fns[] = { + Opcode_wsr_epc2_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal bge_opcode = { - "bge", - 3, - bge_template, - &bst8_iclass +xtensa_opcode_encode_fn Opcode_xsr_epc2_encode_fns[] = { + Opcode_xsr_epc2_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal bgei_opcode = { - "bgei", - 3, - bgei_template, - &bsi8_iclass +xtensa_opcode_encode_fn Opcode_rsr_excsave2_encode_fns[] = { + Opcode_rsr_excsave2_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal bgeu_opcode = { - "bgeu", - 3, - bgeu_template, - &bst8_iclass +xtensa_opcode_encode_fn Opcode_wsr_excsave2_encode_fns[] = { + Opcode_wsr_excsave2_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal bgeui_opcode = { - "bgeui", - 3, - bgeui_template, - &bsi8u_iclass +xtensa_opcode_encode_fn Opcode_xsr_excsave2_encode_fns[] = { + Opcode_xsr_excsave2_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal bgez_opcode = { - "bgez", - 3, - bgez_template, - &bsz12_iclass +xtensa_opcode_encode_fn Opcode_rsr_epc3_encode_fns[] = { + Opcode_rsr_epc3_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal blt_opcode = { - "blt", - 3, - blt_template, - &bst8_iclass +xtensa_opcode_encode_fn Opcode_wsr_epc3_encode_fns[] = { + Opcode_wsr_epc3_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal blti_opcode = { - "blti", - 3, - blti_template, - &bsi8_iclass +xtensa_opcode_encode_fn Opcode_xsr_epc3_encode_fns[] = { + Opcode_xsr_epc3_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal bltu_opcode = { - "bltu", - 3, - bltu_template, - &bst8_iclass +xtensa_opcode_encode_fn Opcode_rsr_excsave3_encode_fns[] = { + Opcode_rsr_excsave3_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal bltui_opcode = { - "bltui", - 3, - bltui_template, - &bsi8u_iclass +xtensa_opcode_encode_fn Opcode_wsr_excsave3_encode_fns[] = { + Opcode_wsr_excsave3_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal bltz_opcode = { - "bltz", - 3, - bltz_template, - &bsz12_iclass +xtensa_opcode_encode_fn Opcode_xsr_excsave3_encode_fns[] = { + Opcode_xsr_excsave3_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal bnall_opcode = { - "bnall", - 3, - bnall_template, - &bst8_iclass +xtensa_opcode_encode_fn Opcode_rsr_epc4_encode_fns[] = { + Opcode_rsr_epc4_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal bne_opcode = { - "bne", - 3, - bne_template, - &bst8_iclass +xtensa_opcode_encode_fn Opcode_wsr_epc4_encode_fns[] = { + Opcode_wsr_epc4_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal bnei_opcode = { - "bnei", - 3, - bnei_template, - &bsi8_iclass +xtensa_opcode_encode_fn Opcode_xsr_epc4_encode_fns[] = { + Opcode_xsr_epc4_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal bnez_opcode = { - "bnez", - 3, - bnez_template, - &bsz12_iclass +xtensa_opcode_encode_fn Opcode_rsr_excsave4_encode_fns[] = { + Opcode_rsr_excsave4_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal bnez_n_opcode = { - "bnez.n", - 2, - bnez_n_template, - &bz6_iclass +xtensa_opcode_encode_fn Opcode_wsr_excsave4_encode_fns[] = { + Opcode_wsr_excsave4_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal bnone_opcode = { - "bnone", - 3, - bnone_template, - &bst8_iclass +xtensa_opcode_encode_fn Opcode_xsr_excsave4_encode_fns[] = { + Opcode_xsr_excsave4_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal break_opcode = { - "break", - 3, - break_template, - &break_iclass +xtensa_opcode_encode_fn Opcode_rsr_eps2_encode_fns[] = { + Opcode_rsr_eps2_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal break_n_opcode = { - "break.n", - 2, - break_n_template, - &break_n_iclass +xtensa_opcode_encode_fn Opcode_wsr_eps2_encode_fns[] = { + Opcode_wsr_eps2_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal call0_opcode = { - "call0", - 3, - call0_template, - &call_iclass +xtensa_opcode_encode_fn Opcode_xsr_eps2_encode_fns[] = { + Opcode_xsr_eps2_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal call12_opcode = { - "call12", - 3, - call12_template, - &call12_iclass +xtensa_opcode_encode_fn Opcode_rsr_eps3_encode_fns[] = { + Opcode_rsr_eps3_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal call4_opcode = { - "call4", - 3, - call4_template, - &call4_iclass +xtensa_opcode_encode_fn Opcode_wsr_eps3_encode_fns[] = { + Opcode_wsr_eps3_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal call8_opcode = { - "call8", - 3, - call8_template, - &call8_iclass +xtensa_opcode_encode_fn Opcode_xsr_eps3_encode_fns[] = { + Opcode_xsr_eps3_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal callx0_opcode = { - "callx0", - 3, - callx0_template, - &callx_iclass +xtensa_opcode_encode_fn Opcode_rsr_eps4_encode_fns[] = { + Opcode_rsr_eps4_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal callx12_opcode = { - "callx12", - 3, - callx12_template, - &callx12_iclass +xtensa_opcode_encode_fn Opcode_wsr_eps4_encode_fns[] = { + Opcode_wsr_eps4_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal callx4_opcode = { - "callx4", - 3, - callx4_template, - &callx4_iclass +xtensa_opcode_encode_fn Opcode_xsr_eps4_encode_fns[] = { + Opcode_xsr_eps4_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal callx8_opcode = { - "callx8", - 3, - callx8_template, - &callx8_iclass +xtensa_opcode_encode_fn Opcode_rsr_excvaddr_encode_fns[] = { + Opcode_rsr_excvaddr_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal dhi_opcode = { - "dhi", - 3, - dhi_template, - &dcache_iclass +xtensa_opcode_encode_fn Opcode_wsr_excvaddr_encode_fns[] = { + Opcode_wsr_excvaddr_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal dhwb_opcode = { - "dhwb", - 3, - dhwb_template, - &dcache_iclass +xtensa_opcode_encode_fn Opcode_xsr_excvaddr_encode_fns[] = { + Opcode_xsr_excvaddr_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal dhwbi_opcode = { - "dhwbi", - 3, - dhwbi_template, - &dcache_iclass +xtensa_opcode_encode_fn Opcode_rsr_depc_encode_fns[] = { + Opcode_rsr_depc_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal dii_opcode = { - "dii", - 3, - dii_template, - &dcache_iclass +xtensa_opcode_encode_fn Opcode_wsr_depc_encode_fns[] = { + Opcode_wsr_depc_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal diwb_opcode = { - "diwb", - 3, - diwb_template, - &dce_iclass +xtensa_opcode_encode_fn Opcode_xsr_depc_encode_fns[] = { + Opcode_xsr_depc_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal diwbi_opcode = { - "diwbi", - 3, - diwbi_template, - &dce_iclass +xtensa_opcode_encode_fn Opcode_rsr_exccause_encode_fns[] = { + Opcode_rsr_exccause_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal dpfr_opcode = { - "dpfr", - 3, - dpfr_template, - &dpf_iclass +xtensa_opcode_encode_fn Opcode_wsr_exccause_encode_fns[] = { + Opcode_wsr_exccause_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal dpfro_opcode = { - "dpfro", - 3, - dpfro_template, - &dpf_iclass +xtensa_opcode_encode_fn Opcode_xsr_exccause_encode_fns[] = { + Opcode_xsr_exccause_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal dpfw_opcode = { - "dpfw", - 3, - dpfw_template, - &dpf_iclass +xtensa_opcode_encode_fn Opcode_rsr_misc0_encode_fns[] = { + Opcode_rsr_misc0_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal dpfwo_opcode = { - "dpfwo", - 3, - dpfwo_template, - &dpf_iclass +xtensa_opcode_encode_fn Opcode_wsr_misc0_encode_fns[] = { + Opcode_wsr_misc0_Slot_inst_encode, 0, 0 +}; + +xtensa_opcode_encode_fn Opcode_xsr_misc0_encode_fns[] = { + Opcode_xsr_misc0_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal dsync_opcode = { - "dsync", - 3, - dsync_template, - &sync_iclass +xtensa_opcode_encode_fn Opcode_rsr_misc1_encode_fns[] = { + Opcode_rsr_misc1_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal entry_opcode = { - "entry", - 3, - entry_template, - &entry_iclass +xtensa_opcode_encode_fn Opcode_wsr_misc1_encode_fns[] = { + Opcode_wsr_misc1_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal esync_opcode = { - "esync", - 3, - esync_template, - &sync_iclass +xtensa_opcode_encode_fn Opcode_xsr_misc1_encode_fns[] = { + Opcode_xsr_misc1_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal excw_opcode = { - "excw", - 3, - excw_template, - &excw_iclass +xtensa_opcode_encode_fn Opcode_rsr_prid_encode_fns[] = { + Opcode_rsr_prid_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal extui_opcode = { - "extui", - 3, - extui_template, - &exti_iclass +xtensa_opcode_encode_fn Opcode_rfi_encode_fns[] = { + Opcode_rfi_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal idtlb_opcode = { - "idtlb", - 3, - idtlb_template, - &itlb_iclass +xtensa_opcode_encode_fn Opcode_waiti_encode_fns[] = { + Opcode_waiti_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal idtlba_opcode = { - "idtlba", - 3, - idtlba_template, - &itlba_iclass +xtensa_opcode_encode_fn Opcode_rsr_interrupt_encode_fns[] = { + Opcode_rsr_interrupt_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal ihi_opcode = { - "ihi", - 3, - ihi_template, - &icache_iclass +xtensa_opcode_encode_fn Opcode_wsr_intset_encode_fns[] = { + Opcode_wsr_intset_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal iii_opcode = { - "iii", - 3, - iii_template, - &icache_iclass +xtensa_opcode_encode_fn Opcode_wsr_intclear_encode_fns[] = { + Opcode_wsr_intclear_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal iitlb_opcode = { - "iitlb", - 3, - iitlb_template, - &itlb_iclass +xtensa_opcode_encode_fn Opcode_rsr_intenable_encode_fns[] = { + Opcode_rsr_intenable_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal iitlba_opcode = { - "iitlba", - 3, - iitlba_template, - &itlba_iclass +xtensa_opcode_encode_fn Opcode_wsr_intenable_encode_fns[] = { + Opcode_wsr_intenable_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal ipf_opcode = { - "ipf", - 3, - ipf_template, - &icache_iclass +xtensa_opcode_encode_fn Opcode_xsr_intenable_encode_fns[] = { + Opcode_xsr_intenable_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal isync_opcode = { - "isync", - 3, - isync_template, - &sync_iclass +xtensa_opcode_encode_fn Opcode_break_encode_fns[] = { + Opcode_break_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal j_opcode = { - "j", - 3, - j_template, - &jump_iclass +xtensa_opcode_encode_fn Opcode_break_n_encode_fns[] = { + 0, 0, Opcode_break_n_Slot_inst16b_encode }; -static xtensa_opcode_internal jx_opcode = { - "jx", - 3, - jx_template, - &jumpx_iclass +xtensa_opcode_encode_fn Opcode_rsr_dbreaka0_encode_fns[] = { + Opcode_rsr_dbreaka0_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal l16si_opcode = { - "l16si", - 3, - l16si_template, - &l16i_iclass +xtensa_opcode_encode_fn Opcode_wsr_dbreaka0_encode_fns[] = { + Opcode_wsr_dbreaka0_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal l16ui_opcode = { - "l16ui", - 3, - l16ui_template, - &l16i_iclass +xtensa_opcode_encode_fn Opcode_xsr_dbreaka0_encode_fns[] = { + Opcode_xsr_dbreaka0_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal l32e_opcode = { - "l32e", - 3, - l32e_template, - &l32e_iclass +xtensa_opcode_encode_fn Opcode_rsr_dbreakc0_encode_fns[] = { + Opcode_rsr_dbreakc0_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal l32i_opcode = { - "l32i", - 3, - l32i_template, - &l32i_iclass +xtensa_opcode_encode_fn Opcode_wsr_dbreakc0_encode_fns[] = { + Opcode_wsr_dbreakc0_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal l32i_n_opcode = { - "l32i.n", - 2, - l32i_n_template, - &loadi4_iclass +xtensa_opcode_encode_fn Opcode_xsr_dbreakc0_encode_fns[] = { + Opcode_xsr_dbreakc0_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal l32r_opcode = { - "l32r", - 3, - l32r_template, - &l32r_iclass +xtensa_opcode_encode_fn Opcode_rsr_dbreaka1_encode_fns[] = { + Opcode_rsr_dbreaka1_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal l8ui_opcode = { - "l8ui", - 3, - l8ui_template, - &l8i_iclass +xtensa_opcode_encode_fn Opcode_wsr_dbreaka1_encode_fns[] = { + Opcode_wsr_dbreaka1_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal ldct_opcode = { - "ldct", - 3, - ldct_template, - &actl_iclass +xtensa_opcode_encode_fn Opcode_xsr_dbreaka1_encode_fns[] = { + Opcode_xsr_dbreaka1_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal lict_opcode = { - "lict", - 3, - lict_template, - &actl_iclass +xtensa_opcode_encode_fn Opcode_rsr_dbreakc1_encode_fns[] = { + Opcode_rsr_dbreakc1_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal licw_opcode = { - "licw", - 3, - licw_template, - &actl_iclass +xtensa_opcode_encode_fn Opcode_wsr_dbreakc1_encode_fns[] = { + Opcode_wsr_dbreakc1_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal loop_opcode = { - "loop", - 3, - loop_template, - &loop_iclass +xtensa_opcode_encode_fn Opcode_xsr_dbreakc1_encode_fns[] = { + Opcode_xsr_dbreakc1_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal loopgtz_opcode = { - "loopgtz", - 3, - loopgtz_template, - &loop_iclass +xtensa_opcode_encode_fn Opcode_rsr_ibreaka0_encode_fns[] = { + Opcode_rsr_ibreaka0_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal loopnez_opcode = { - "loopnez", - 3, - loopnez_template, - &loop_iclass +xtensa_opcode_encode_fn Opcode_wsr_ibreaka0_encode_fns[] = { + Opcode_wsr_ibreaka0_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal memw_opcode = { - "memw", - 3, - memw_template, - &sync_iclass +xtensa_opcode_encode_fn Opcode_xsr_ibreaka0_encode_fns[] = { + Opcode_xsr_ibreaka0_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal mov_n_opcode = { - "mov.n", - 2, - mov_n_template, - &mov_n_iclass +xtensa_opcode_encode_fn Opcode_rsr_ibreaka1_encode_fns[] = { + Opcode_rsr_ibreaka1_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal moveqz_opcode = { - "moveqz", - 3, - moveqz_template, - &movz_iclass +xtensa_opcode_encode_fn Opcode_wsr_ibreaka1_encode_fns[] = { + Opcode_wsr_ibreaka1_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal movgez_opcode = { - "movgez", - 3, - movgez_template, - &movz_iclass +xtensa_opcode_encode_fn Opcode_xsr_ibreaka1_encode_fns[] = { + Opcode_xsr_ibreaka1_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal movi_opcode = { - "movi", - 3, - movi_template, - &movi_iclass +xtensa_opcode_encode_fn Opcode_rsr_ibreakenable_encode_fns[] = { + Opcode_rsr_ibreakenable_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal movi_n_opcode = { - "movi.n", - 2, - movi_n_template, - &movi_n_iclass +xtensa_opcode_encode_fn Opcode_wsr_ibreakenable_encode_fns[] = { + Opcode_wsr_ibreakenable_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal movltz_opcode = { - "movltz", - 3, - movltz_template, - &movz_iclass +xtensa_opcode_encode_fn Opcode_xsr_ibreakenable_encode_fns[] = { + Opcode_xsr_ibreakenable_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal movnez_opcode = { - "movnez", - 3, - movnez_template, - &movz_iclass +xtensa_opcode_encode_fn Opcode_rsr_debugcause_encode_fns[] = { + Opcode_rsr_debugcause_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal movsp_opcode = { - "movsp", - 3, - movsp_template, - &movsp_iclass +xtensa_opcode_encode_fn Opcode_wsr_debugcause_encode_fns[] = { + Opcode_wsr_debugcause_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal neg_opcode = { - "neg", - 3, - neg_template, - &neg_iclass +xtensa_opcode_encode_fn Opcode_xsr_debugcause_encode_fns[] = { + Opcode_xsr_debugcause_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal nop_n_opcode = { - "nop.n", - 2, - nop_n_template, - &nopn_iclass +xtensa_opcode_encode_fn Opcode_rsr_icount_encode_fns[] = { + Opcode_rsr_icount_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal nsa_opcode = { - "nsa", - 3, - nsa_template, - &nsa_iclass +xtensa_opcode_encode_fn Opcode_wsr_icount_encode_fns[] = { + Opcode_wsr_icount_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal nsau_opcode = { - "nsau", - 3, - nsau_template, - &nsa_iclass +xtensa_opcode_encode_fn Opcode_xsr_icount_encode_fns[] = { + Opcode_xsr_icount_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal or_opcode = { - "or", - 3, - or_template, - &bit_iclass +xtensa_opcode_encode_fn Opcode_rsr_icountlevel_encode_fns[] = { + Opcode_rsr_icountlevel_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal pdtlb_opcode = { - "pdtlb", - 3, - pdtlb_template, - &rtlb_iclass +xtensa_opcode_encode_fn Opcode_wsr_icountlevel_encode_fns[] = { + Opcode_wsr_icountlevel_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal pitlb_opcode = { - "pitlb", - 3, - pitlb_template, - &rtlb_iclass +xtensa_opcode_encode_fn Opcode_xsr_icountlevel_encode_fns[] = { + Opcode_xsr_icountlevel_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal rdtlb0_opcode = { - "rdtlb0", - 3, - rdtlb0_template, - &rtlb_iclass +xtensa_opcode_encode_fn Opcode_rsr_ddr_encode_fns[] = { + Opcode_rsr_ddr_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal rdtlb1_opcode = { - "rdtlb1", - 3, - rdtlb1_template, - &rtlb_iclass +xtensa_opcode_encode_fn Opcode_wsr_ddr_encode_fns[] = { + Opcode_wsr_ddr_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal ret_opcode = { - "ret", - 3, - ret_template, - &return_iclass +xtensa_opcode_encode_fn Opcode_xsr_ddr_encode_fns[] = { + Opcode_xsr_ddr_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal ret_n_opcode = { - "ret.n", - 2, - ret_n_template, - &retn_iclass +xtensa_opcode_encode_fn Opcode_rfdo_encode_fns[] = { + Opcode_rfdo_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal retw_opcode = { - "retw", - 3, - retw_template, - &return_iclass +xtensa_opcode_encode_fn Opcode_rfdd_encode_fns[] = { + Opcode_rfdd_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal retw_n_opcode = { - "retw.n", - 2, - retw_n_template, - &retn_iclass +xtensa_opcode_encode_fn Opcode_rsr_ccount_encode_fns[] = { + Opcode_rsr_ccount_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal rfde_opcode = { - "rfde", - 3, - rfde_template, - &rfe_iclass +xtensa_opcode_encode_fn Opcode_wsr_ccount_encode_fns[] = { + Opcode_wsr_ccount_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal rfe_opcode = { - "rfe", - 3, - rfe_template, - &rfe_iclass +xtensa_opcode_encode_fn Opcode_xsr_ccount_encode_fns[] = { + Opcode_xsr_ccount_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal rfi_opcode = { - "rfi", - 3, - rfi_template, - &rfi_iclass +xtensa_opcode_encode_fn Opcode_rsr_ccompare0_encode_fns[] = { + Opcode_rsr_ccompare0_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal rfwo_opcode = { - "rfwo", - 3, - rfwo_template, - &rfe_iclass +xtensa_opcode_encode_fn Opcode_wsr_ccompare0_encode_fns[] = { + Opcode_wsr_ccompare0_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal rfwu_opcode = { - "rfwu", - 3, - rfwu_template, - &rfe_iclass +xtensa_opcode_encode_fn Opcode_xsr_ccompare0_encode_fns[] = { + Opcode_xsr_ccompare0_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal ritlb0_opcode = { - "ritlb0", - 3, - ritlb0_template, - &rtlb_iclass +xtensa_opcode_encode_fn Opcode_rsr_ccompare1_encode_fns[] = { + Opcode_rsr_ccompare1_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal ritlb1_opcode = { - "ritlb1", - 3, - ritlb1_template, - &rtlb_iclass +xtensa_opcode_encode_fn Opcode_wsr_ccompare1_encode_fns[] = { + Opcode_wsr_ccompare1_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal rotw_opcode = { - "rotw", - 3, - rotw_template, - &rotw_iclass +xtensa_opcode_encode_fn Opcode_xsr_ccompare1_encode_fns[] = { + Opcode_xsr_ccompare1_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal rsil_opcode = { - "rsil", - 3, - rsil_template, - &rsil_iclass +xtensa_opcode_encode_fn Opcode_rsr_ccompare2_encode_fns[] = { + Opcode_rsr_ccompare2_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal rsr_opcode = { - "rsr", - 3, - rsr_template, - &rsr_iclass +xtensa_opcode_encode_fn Opcode_wsr_ccompare2_encode_fns[] = { + Opcode_wsr_ccompare2_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal rsync_opcode = { - "rsync", - 3, - rsync_template, - &sync_iclass +xtensa_opcode_encode_fn Opcode_xsr_ccompare2_encode_fns[] = { + Opcode_xsr_ccompare2_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal s16i_opcode = { - "s16i", - 3, - s16i_template, - &s16i_iclass +xtensa_opcode_encode_fn Opcode_ipf_encode_fns[] = { + Opcode_ipf_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal s32e_opcode = { - "s32e", - 3, - s32e_template, - &s32e_iclass +xtensa_opcode_encode_fn Opcode_ihi_encode_fns[] = { + Opcode_ihi_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal s32i_opcode = { - "s32i", - 3, - s32i_template, - &s32i_iclass +xtensa_opcode_encode_fn Opcode_iii_encode_fns[] = { + Opcode_iii_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal s32i_n_opcode = { - "s32i.n", - 2, - s32i_n_template, - &storei4_iclass +xtensa_opcode_encode_fn Opcode_lict_encode_fns[] = { + Opcode_lict_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal s8i_opcode = { - "s8i", - 3, - s8i_template, - &s8i_iclass +xtensa_opcode_encode_fn Opcode_licw_encode_fns[] = { + Opcode_licw_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal sdct_opcode = { - "sdct", - 3, - sdct_template, - &acts_iclass +xtensa_opcode_encode_fn Opcode_sict_encode_fns[] = { + Opcode_sict_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal sict_opcode = { - "sict", - 3, - sict_template, - &acts_iclass +xtensa_opcode_encode_fn Opcode_sicw_encode_fns[] = { + Opcode_sicw_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal sicw_opcode = { - "sicw", - 3, - sicw_template, - &acts_iclass +xtensa_opcode_encode_fn Opcode_dhwb_encode_fns[] = { + Opcode_dhwb_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal simcall_opcode = { - "simcall", - 3, - simcall_template, - &syscall_iclass +xtensa_opcode_encode_fn Opcode_dhwbi_encode_fns[] = { + Opcode_dhwbi_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal sll_opcode = { - "sll", - 3, - sll_template, - &shifts_iclass +xtensa_opcode_encode_fn Opcode_diwb_encode_fns[] = { + Opcode_diwb_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal slli_opcode = { - "slli", - 3, - slli_template, - &slli_iclass +xtensa_opcode_encode_fn Opcode_diwbi_encode_fns[] = { + Opcode_diwbi_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal sra_opcode = { - "sra", - 3, - sra_template, - &shiftt_iclass +xtensa_opcode_encode_fn Opcode_dhi_encode_fns[] = { + Opcode_dhi_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal srai_opcode = { - "srai", - 3, - srai_template, - &srai_iclass +xtensa_opcode_encode_fn Opcode_dii_encode_fns[] = { + Opcode_dii_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal src_opcode = { - "src", - 3, - src_template, - &shiftst_iclass +xtensa_opcode_encode_fn Opcode_dpfr_encode_fns[] = { + Opcode_dpfr_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal srl_opcode = { - "srl", - 3, - srl_template, - &shiftt_iclass +xtensa_opcode_encode_fn Opcode_dpfw_encode_fns[] = { + Opcode_dpfw_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal srli_opcode = { - "srli", - 3, - srli_template, - &srli_iclass +xtensa_opcode_encode_fn Opcode_dpfro_encode_fns[] = { + Opcode_dpfro_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal ssa8b_opcode = { - "ssa8b", - 3, - ssa8b_template, - &sar_iclass +xtensa_opcode_encode_fn Opcode_dpfwo_encode_fns[] = { + Opcode_dpfwo_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal ssa8l_opcode = { - "ssa8l", - 3, - ssa8l_template, - &sar_iclass +xtensa_opcode_encode_fn Opcode_sdct_encode_fns[] = { + Opcode_sdct_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal ssai_opcode = { - "ssai", - 3, - ssai_template, - &sari_iclass +xtensa_opcode_encode_fn Opcode_ldct_encode_fns[] = { + Opcode_ldct_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal ssl_opcode = { - "ssl", - 3, - ssl_template, - &sar_iclass +xtensa_opcode_encode_fn Opcode_idtlb_encode_fns[] = { + Opcode_idtlb_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal ssr_opcode = { - "ssr", - 3, - ssr_template, - &sar_iclass +xtensa_opcode_encode_fn Opcode_pdtlb_encode_fns[] = { + Opcode_pdtlb_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal sub_opcode = { - "sub", - 3, - sub_template, - &addsub_iclass +xtensa_opcode_encode_fn Opcode_rdtlb0_encode_fns[] = { + Opcode_rdtlb0_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal subx2_opcode = { - "subx2", - 3, - subx2_template, - &addsub_iclass +xtensa_opcode_encode_fn Opcode_rdtlb1_encode_fns[] = { + Opcode_rdtlb1_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal subx4_opcode = { - "subx4", - 3, - subx4_template, - &addsub_iclass +xtensa_opcode_encode_fn Opcode_wdtlb_encode_fns[] = { + Opcode_wdtlb_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal subx8_opcode = { - "subx8", - 3, - subx8_template, - &addsub_iclass +xtensa_opcode_encode_fn Opcode_iitlb_encode_fns[] = { + Opcode_iitlb_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal syscall_opcode = { - "syscall", - 3, - syscall_template, - &syscall_iclass +xtensa_opcode_encode_fn Opcode_pitlb_encode_fns[] = { + Opcode_pitlb_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal waiti_opcode = { - "waiti", - 3, - waiti_template, - &wait_iclass +xtensa_opcode_encode_fn Opcode_ritlb0_encode_fns[] = { + Opcode_ritlb0_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal wdtlb_opcode = { - "wdtlb", - 3, - wdtlb_template, - &wtlb_iclass +xtensa_opcode_encode_fn Opcode_ritlb1_encode_fns[] = { + Opcode_ritlb1_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal witlb_opcode = { - "witlb", - 3, - witlb_template, - &wtlb_iclass +xtensa_opcode_encode_fn Opcode_witlb_encode_fns[] = { + Opcode_witlb_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal wsr_opcode = { - "wsr", - 3, - wsr_template, - &wsr_iclass +xtensa_opcode_encode_fn Opcode_nsa_encode_fns[] = { + Opcode_nsa_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal xor_opcode = { - "xor", - 3, - xor_template, - &bit_iclass +xtensa_opcode_encode_fn Opcode_nsau_encode_fns[] = { + Opcode_nsau_Slot_inst_encode, 0, 0 }; -static xtensa_opcode_internal xsr_opcode = { - "xsr", - 3, - xsr_template, - &xsr_iclass -}; - -static xtensa_opcode_internal * opcodes[149] = { - &abs_opcode, - &add_opcode, - &add_n_opcode, - &addi_opcode, - &addi_n_opcode, - &addmi_opcode, - &addx2_opcode, - &addx4_opcode, - &addx8_opcode, - &and_opcode, - &ball_opcode, - &bany_opcode, - &bbc_opcode, - &bbci_opcode, - &bbs_opcode, - &bbsi_opcode, - &beq_opcode, - &beqi_opcode, - &beqz_opcode, - &beqz_n_opcode, - &bge_opcode, - &bgei_opcode, - &bgeu_opcode, - &bgeui_opcode, - &bgez_opcode, - &blt_opcode, - &blti_opcode, - &bltu_opcode, - &bltui_opcode, - &bltz_opcode, - &bnall_opcode, - &bne_opcode, - &bnei_opcode, - &bnez_opcode, - &bnez_n_opcode, - &bnone_opcode, - &break_opcode, - &break_n_opcode, - &call0_opcode, - &call12_opcode, - &call4_opcode, - &call8_opcode, - &callx0_opcode, - &callx12_opcode, - &callx4_opcode, - &callx8_opcode, - &dhi_opcode, - &dhwb_opcode, - &dhwbi_opcode, - &dii_opcode, - &diwb_opcode, - &diwbi_opcode, - &dpfr_opcode, - &dpfro_opcode, - &dpfw_opcode, - &dpfwo_opcode, - &dsync_opcode, - &entry_opcode, - &esync_opcode, - &excw_opcode, - &extui_opcode, - &idtlb_opcode, - &idtlba_opcode, - &ihi_opcode, - &iii_opcode, - &iitlb_opcode, - &iitlba_opcode, - &ipf_opcode, - &isync_opcode, - &j_opcode, - &jx_opcode, - &l16si_opcode, - &l16ui_opcode, - &l32e_opcode, - &l32i_opcode, - &l32i_n_opcode, - &l32r_opcode, - &l8ui_opcode, - &ldct_opcode, - &lict_opcode, - &licw_opcode, - &loop_opcode, - &loopgtz_opcode, - &loopnez_opcode, - &memw_opcode, - &mov_n_opcode, - &moveqz_opcode, - &movgez_opcode, - &movi_opcode, - &movi_n_opcode, - &movltz_opcode, - &movnez_opcode, - &movsp_opcode, - &neg_opcode, - &nop_n_opcode, - &nsa_opcode, - &nsau_opcode, - &or_opcode, - &pdtlb_opcode, - &pitlb_opcode, - &rdtlb0_opcode, - &rdtlb1_opcode, - &ret_opcode, - &ret_n_opcode, - &retw_opcode, - &retw_n_opcode, - &rfde_opcode, - &rfe_opcode, - &rfi_opcode, - &rfwo_opcode, - &rfwu_opcode, - &ritlb0_opcode, - &ritlb1_opcode, - &rotw_opcode, - &rsil_opcode, - &rsr_opcode, - &rsync_opcode, - &s16i_opcode, - &s32e_opcode, - &s32i_opcode, - &s32i_n_opcode, - &s8i_opcode, - &sdct_opcode, - &sict_opcode, - &sicw_opcode, - &simcall_opcode, - &sll_opcode, - &slli_opcode, - &sra_opcode, - &srai_opcode, - &src_opcode, - &srl_opcode, - &srli_opcode, - &ssa8b_opcode, - &ssa8l_opcode, - &ssai_opcode, - &ssl_opcode, - &ssr_opcode, - &sub_opcode, - &subx2_opcode, - &subx4_opcode, - &subx8_opcode, - &syscall_opcode, - &waiti_opcode, - &wdtlb_opcode, - &witlb_opcode, - &wsr_opcode, - &xor_opcode, - &xsr_opcode -}; - -xtensa_opcode_internal ** -get_opcodes (void) -{ - return &opcodes[0]; -} - -int -get_num_opcodes (void) -{ - return 149; -} - -#define xtensa_abs_op 0 -#define xtensa_add_op 1 -#define xtensa_add_n_op 2 -#define xtensa_addi_op 3 -#define xtensa_addi_n_op 4 -#define xtensa_addmi_op 5 -#define xtensa_addx2_op 6 -#define xtensa_addx4_op 7 -#define xtensa_addx8_op 8 -#define xtensa_and_op 9 -#define xtensa_ball_op 10 -#define xtensa_bany_op 11 -#define xtensa_bbc_op 12 -#define xtensa_bbci_op 13 -#define xtensa_bbs_op 14 -#define xtensa_bbsi_op 15 -#define xtensa_beq_op 16 -#define xtensa_beqi_op 17 -#define xtensa_beqz_op 18 -#define xtensa_beqz_n_op 19 -#define xtensa_bge_op 20 -#define xtensa_bgei_op 21 -#define xtensa_bgeu_op 22 -#define xtensa_bgeui_op 23 -#define xtensa_bgez_op 24 -#define xtensa_blt_op 25 -#define xtensa_blti_op 26 -#define xtensa_bltu_op 27 -#define xtensa_bltui_op 28 -#define xtensa_bltz_op 29 -#define xtensa_bnall_op 30 -#define xtensa_bne_op 31 -#define xtensa_bnei_op 32 -#define xtensa_bnez_op 33 -#define xtensa_bnez_n_op 34 -#define xtensa_bnone_op 35 -#define xtensa_break_op 36 -#define xtensa_break_n_op 37 -#define xtensa_call0_op 38 -#define xtensa_call12_op 39 -#define xtensa_call4_op 40 -#define xtensa_call8_op 41 -#define xtensa_callx0_op 42 -#define xtensa_callx12_op 43 -#define xtensa_callx4_op 44 -#define xtensa_callx8_op 45 -#define xtensa_dhi_op 46 -#define xtensa_dhwb_op 47 -#define xtensa_dhwbi_op 48 -#define xtensa_dii_op 49 -#define xtensa_diwb_op 50 -#define xtensa_diwbi_op 51 -#define xtensa_dpfr_op 52 -#define xtensa_dpfro_op 53 -#define xtensa_dpfw_op 54 -#define xtensa_dpfwo_op 55 -#define xtensa_dsync_op 56 -#define xtensa_entry_op 57 -#define xtensa_esync_op 58 -#define xtensa_excw_op 59 -#define xtensa_extui_op 60 -#define xtensa_idtlb_op 61 -#define xtensa_idtlba_op 62 -#define xtensa_ihi_op 63 -#define xtensa_iii_op 64 -#define xtensa_iitlb_op 65 -#define xtensa_iitlba_op 66 -#define xtensa_ipf_op 67 -#define xtensa_isync_op 68 -#define xtensa_j_op 69 -#define xtensa_jx_op 70 -#define xtensa_l16si_op 71 -#define xtensa_l16ui_op 72 -#define xtensa_l32e_op 73 -#define xtensa_l32i_op 74 -#define xtensa_l32i_n_op 75 -#define xtensa_l32r_op 76 -#define xtensa_l8ui_op 77 -#define xtensa_ldct_op 78 -#define xtensa_lict_op 79 -#define xtensa_licw_op 80 -#define xtensa_loop_op 81 -#define xtensa_loopgtz_op 82 -#define xtensa_loopnez_op 83 -#define xtensa_memw_op 84 -#define xtensa_mov_n_op 85 -#define xtensa_moveqz_op 86 -#define xtensa_movgez_op 87 -#define xtensa_movi_op 88 -#define xtensa_movi_n_op 89 -#define xtensa_movltz_op 90 -#define xtensa_movnez_op 91 -#define xtensa_movsp_op 92 -#define xtensa_neg_op 93 -#define xtensa_nop_n_op 94 -#define xtensa_nsa_op 95 -#define xtensa_nsau_op 96 -#define xtensa_or_op 97 -#define xtensa_pdtlb_op 98 -#define xtensa_pitlb_op 99 -#define xtensa_rdtlb0_op 100 -#define xtensa_rdtlb1_op 101 -#define xtensa_ret_op 102 -#define xtensa_ret_n_op 103 -#define xtensa_retw_op 104 -#define xtensa_retw_n_op 105 -#define xtensa_rfde_op 106 -#define xtensa_rfe_op 107 -#define xtensa_rfi_op 108 -#define xtensa_rfwo_op 109 -#define xtensa_rfwu_op 110 -#define xtensa_ritlb0_op 111 -#define xtensa_ritlb1_op 112 -#define xtensa_rotw_op 113 -#define xtensa_rsil_op 114 -#define xtensa_rsr_op 115 -#define xtensa_rsync_op 116 -#define xtensa_s16i_op 117 -#define xtensa_s32e_op 118 -#define xtensa_s32i_op 119 -#define xtensa_s32i_n_op 120 -#define xtensa_s8i_op 121 -#define xtensa_sdct_op 122 -#define xtensa_sict_op 123 -#define xtensa_sicw_op 124 -#define xtensa_simcall_op 125 -#define xtensa_sll_op 126 -#define xtensa_slli_op 127 -#define xtensa_sra_op 128 -#define xtensa_srai_op 129 -#define xtensa_src_op 130 -#define xtensa_srl_op 131 -#define xtensa_srli_op 132 -#define xtensa_ssa8b_op 133 -#define xtensa_ssa8l_op 134 -#define xtensa_ssai_op 135 -#define xtensa_ssl_op 136 -#define xtensa_ssr_op 137 -#define xtensa_sub_op 138 -#define xtensa_subx2_op 139 -#define xtensa_subx4_op 140 -#define xtensa_subx8_op 141 -#define xtensa_syscall_op 142 -#define xtensa_waiti_op 143 -#define xtensa_wdtlb_op 144 -#define xtensa_witlb_op 145 -#define xtensa_wsr_op 146 -#define xtensa_xor_op 147 -#define xtensa_xsr_op 148 - -int -decode_insn (const xtensa_insnbuf insn) -{ - switch (get_op0_field (insn)) { - case 0: /* QRST: op0=0000 */ - switch (get_op1_field (insn)) { - case 3: /* RST3: op1=0011 */ - switch (get_op2_field (insn)) { - case 8: /* MOVEQZ: op2=1000 */ - return xtensa_moveqz_op; - case 9: /* MOVNEZ: op2=1001 */ - return xtensa_movnez_op; - case 10: /* MOVLTZ: op2=1010 */ - return xtensa_movltz_op; - case 11: /* MOVGEZ: op2=1011 */ - return xtensa_movgez_op; - case 0: /* RSR: op2=0000 */ - return xtensa_rsr_op; - case 1: /* WSR: op2=0001 */ - return xtensa_wsr_op; - } + +/* Opcode table. */ + +static xtensa_opcode_internal opcodes[] = { + { "excw", 0 /* xt_iclass_excw */, + 0, + Opcode_excw_encode_fns, 0, 0 }, + { "rfe", 1 /* xt_iclass_rfe */, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfe_encode_fns, 0, 0 }, + { "rfde", 2 /* xt_iclass_rfde */, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfde_encode_fns, 0, 0 }, + { "syscall", 3 /* xt_iclass_syscall */, + 0, + Opcode_syscall_encode_fns, 0, 0 }, + { "simcall", 4 /* xt_iclass_simcall */, + 0, + Opcode_simcall_encode_fns, 0, 0 }, + { "call12", 5 /* xt_iclass_call12 */, + XTENSA_OPCODE_IS_CALL, + Opcode_call12_encode_fns, 0, 0 }, + { "call8", 6 /* xt_iclass_call8 */, + XTENSA_OPCODE_IS_CALL, + Opcode_call8_encode_fns, 0, 0 }, + { "call4", 7 /* xt_iclass_call4 */, + XTENSA_OPCODE_IS_CALL, + Opcode_call4_encode_fns, 0, 0 }, + { "callx12", 8 /* xt_iclass_callx12 */, + XTENSA_OPCODE_IS_CALL, + Opcode_callx12_encode_fns, 0, 0 }, + { "callx8", 9 /* xt_iclass_callx8 */, + XTENSA_OPCODE_IS_CALL, + Opcode_callx8_encode_fns, 0, 0 }, + { "callx4", 10 /* xt_iclass_callx4 */, + XTENSA_OPCODE_IS_CALL, + Opcode_callx4_encode_fns, 0, 0 }, + { "entry", 11 /* xt_iclass_entry */, + 0, + Opcode_entry_encode_fns, 0, 0 }, + { "movsp", 12 /* xt_iclass_movsp */, + 0, + Opcode_movsp_encode_fns, 0, 0 }, + { "rotw", 13 /* xt_iclass_rotw */, + 0, + Opcode_rotw_encode_fns, 0, 0 }, + { "retw", 14 /* xt_iclass_retw */, + XTENSA_OPCODE_IS_JUMP, + Opcode_retw_encode_fns, 0, 0 }, + { "retw.n", 14 /* xt_iclass_retw */, + XTENSA_OPCODE_IS_JUMP, + Opcode_retw_n_encode_fns, 0, 0 }, + { "rfwo", 15 /* xt_iclass_rfwou */, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfwo_encode_fns, 0, 0 }, + { "rfwu", 15 /* xt_iclass_rfwou */, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfwu_encode_fns, 0, 0 }, + { "l32e", 16 /* xt_iclass_l32e */, + 0, + Opcode_l32e_encode_fns, 0, 0 }, + { "s32e", 17 /* xt_iclass_s32e */, + 0, + Opcode_s32e_encode_fns, 0, 0 }, + { "rsr.windowbase", 18 /* xt_iclass_rsr.windowbase */, + 0, + Opcode_rsr_windowbase_encode_fns, 0, 0 }, + { "wsr.windowbase", 19 /* xt_iclass_wsr.windowbase */, + 0, + Opcode_wsr_windowbase_encode_fns, 0, 0 }, + { "xsr.windowbase", 20 /* xt_iclass_xsr.windowbase */, + 0, + Opcode_xsr_windowbase_encode_fns, 0, 0 }, + { "rsr.windowstart", 21 /* xt_iclass_rsr.windowstart */, + 0, + Opcode_rsr_windowstart_encode_fns, 0, 0 }, + { "wsr.windowstart", 22 /* xt_iclass_wsr.windowstart */, + 0, + Opcode_wsr_windowstart_encode_fns, 0, 0 }, + { "xsr.windowstart", 23 /* xt_iclass_xsr.windowstart */, + 0, + Opcode_xsr_windowstart_encode_fns, 0, 0 }, + { "add.n", 24 /* xt_iclass_add.n */, + 0, + Opcode_add_n_encode_fns, 0, 0 }, + { "addi.n", 25 /* xt_iclass_addi.n */, + 0, + Opcode_addi_n_encode_fns, 0, 0 }, + { "beqz.n", 26 /* xt_iclass_bz6 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beqz_n_encode_fns, 0, 0 }, + { "bnez.n", 26 /* xt_iclass_bz6 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnez_n_encode_fns, 0, 0 }, + { "ill.n", 27 /* xt_iclass_ill.n */, + 0, + Opcode_ill_n_encode_fns, 0, 0 }, + { "l32i.n", 28 /* xt_iclass_loadi4 */, + 0, + Opcode_l32i_n_encode_fns, 0, 0 }, + { "mov.n", 29 /* xt_iclass_mov.n */, + 0, + Opcode_mov_n_encode_fns, 0, 0 }, + { "movi.n", 30 /* xt_iclass_movi.n */, + 0, + Opcode_movi_n_encode_fns, 0, 0 }, + { "nop.n", 31 /* xt_iclass_nopn */, + 0, + Opcode_nop_n_encode_fns, 0, 0 }, + { "ret.n", 32 /* xt_iclass_retn */, + XTENSA_OPCODE_IS_JUMP, + Opcode_ret_n_encode_fns, 0, 0 }, + { "s32i.n", 33 /* xt_iclass_storei4 */, + 0, + Opcode_s32i_n_encode_fns, 0, 0 }, + { "addi", 34 /* xt_iclass_addi */, + 0, + Opcode_addi_encode_fns, 0, 0 }, + { "addmi", 35 /* xt_iclass_addmi */, + 0, + Opcode_addmi_encode_fns, 0, 0 }, + { "add", 36 /* xt_iclass_addsub */, + 0, + Opcode_add_encode_fns, 0, 0 }, + { "sub", 36 /* xt_iclass_addsub */, + 0, + Opcode_sub_encode_fns, 0, 0 }, + { "addx2", 36 /* xt_iclass_addsub */, + 0, + Opcode_addx2_encode_fns, 0, 0 }, + { "addx4", 36 /* xt_iclass_addsub */, + 0, + Opcode_addx4_encode_fns, 0, 0 }, + { "addx8", 36 /* xt_iclass_addsub */, + 0, + Opcode_addx8_encode_fns, 0, 0 }, + { "subx2", 36 /* xt_iclass_addsub */, + 0, + Opcode_subx2_encode_fns, 0, 0 }, + { "subx4", 36 /* xt_iclass_addsub */, + 0, + Opcode_subx4_encode_fns, 0, 0 }, + { "subx8", 36 /* xt_iclass_addsub */, + 0, + Opcode_subx8_encode_fns, 0, 0 }, + { "and", 37 /* xt_iclass_bit */, + 0, + Opcode_and_encode_fns, 0, 0 }, + { "or", 37 /* xt_iclass_bit */, + 0, + Opcode_or_encode_fns, 0, 0 }, + { "xor", 37 /* xt_iclass_bit */, + 0, + Opcode_xor_encode_fns, 0, 0 }, + { "beqi", 38 /* xt_iclass_bsi8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beqi_encode_fns, 0, 0 }, + { "bnei", 38 /* xt_iclass_bsi8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnei_encode_fns, 0, 0 }, + { "bgei", 38 /* xt_iclass_bsi8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgei_encode_fns, 0, 0 }, + { "blti", 38 /* xt_iclass_bsi8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_blti_encode_fns, 0, 0 }, + { "bbci", 39 /* xt_iclass_bsi8b */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbci_encode_fns, 0, 0 }, + { "bbsi", 39 /* xt_iclass_bsi8b */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbsi_encode_fns, 0, 0 }, + { "bgeui", 40 /* xt_iclass_bsi8u */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgeui_encode_fns, 0, 0 }, + { "bltui", 40 /* xt_iclass_bsi8u */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bltui_encode_fns, 0, 0 }, + { "beq", 41 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beq_encode_fns, 0, 0 }, + { "bne", 41 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bne_encode_fns, 0, 0 }, + { "bge", 41 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bge_encode_fns, 0, 0 }, + { "blt", 41 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_blt_encode_fns, 0, 0 }, + { "bgeu", 41 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgeu_encode_fns, 0, 0 }, + { "bltu", 41 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bltu_encode_fns, 0, 0 }, + { "bany", 41 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bany_encode_fns, 0, 0 }, + { "bnone", 41 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnone_encode_fns, 0, 0 }, + { "ball", 41 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_ball_encode_fns, 0, 0 }, + { "bnall", 41 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnall_encode_fns, 0, 0 }, + { "bbc", 41 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbc_encode_fns, 0, 0 }, + { "bbs", 41 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbs_encode_fns, 0, 0 }, + { "beqz", 42 /* xt_iclass_bsz12 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beqz_encode_fns, 0, 0 }, + { "bnez", 42 /* xt_iclass_bsz12 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnez_encode_fns, 0, 0 }, + { "bgez", 42 /* xt_iclass_bsz12 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgez_encode_fns, 0, 0 }, + { "bltz", 42 /* xt_iclass_bsz12 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bltz_encode_fns, 0, 0 }, + { "call0", 43 /* xt_iclass_call0 */, + XTENSA_OPCODE_IS_CALL, + Opcode_call0_encode_fns, 0, 0 }, + { "callx0", 44 /* xt_iclass_callx0 */, + XTENSA_OPCODE_IS_CALL, + Opcode_callx0_encode_fns, 0, 0 }, + { "extui", 45 /* xt_iclass_exti */, + 0, + Opcode_extui_encode_fns, 0, 0 }, + { "ill", 46 /* xt_iclass_ill */, + 0, + Opcode_ill_encode_fns, 0, 0 }, + { "j", 47 /* xt_iclass_jump */, + XTENSA_OPCODE_IS_JUMP, + Opcode_j_encode_fns, 0, 0 }, + { "jx", 48 /* xt_iclass_jumpx */, + XTENSA_OPCODE_IS_JUMP, + Opcode_jx_encode_fns, 0, 0 }, + { "l16ui", 49 /* xt_iclass_l16ui */, + 0, + Opcode_l16ui_encode_fns, 0, 0 }, + { "l16si", 50 /* xt_iclass_l16si */, + 0, + Opcode_l16si_encode_fns, 0, 0 }, + { "l32i", 51 /* xt_iclass_l32i */, + 0, + Opcode_l32i_encode_fns, 0, 0 }, + { "l32r", 52 /* xt_iclass_l32r */, + 0, + Opcode_l32r_encode_fns, 0, 0 }, + { "l8ui", 53 /* xt_iclass_l8i */, + 0, + Opcode_l8ui_encode_fns, 0, 0 }, + { "loop", 54 /* xt_iclass_loop */, + XTENSA_OPCODE_IS_LOOP, + Opcode_loop_encode_fns, 0, 0 }, + { "loopnez", 55 /* xt_iclass_loopz */, + XTENSA_OPCODE_IS_LOOP, + Opcode_loopnez_encode_fns, 0, 0 }, + { "loopgtz", 55 /* xt_iclass_loopz */, + XTENSA_OPCODE_IS_LOOP, + Opcode_loopgtz_encode_fns, 0, 0 }, + { "movi", 56 /* xt_iclass_movi */, + 0, + Opcode_movi_encode_fns, 0, 0 }, + { "moveqz", 57 /* xt_iclass_movz */, + 0, + Opcode_moveqz_encode_fns, 0, 0 }, + { "movnez", 57 /* xt_iclass_movz */, + 0, + Opcode_movnez_encode_fns, 0, 0 }, + { "movltz", 57 /* xt_iclass_movz */, + 0, + Opcode_movltz_encode_fns, 0, 0 }, + { "movgez", 57 /* xt_iclass_movz */, + 0, + Opcode_movgez_encode_fns, 0, 0 }, + { "neg", 58 /* xt_iclass_neg */, + 0, + Opcode_neg_encode_fns, 0, 0 }, + { "abs", 58 /* xt_iclass_neg */, + 0, + Opcode_abs_encode_fns, 0, 0 }, + { "nop", 59 /* xt_iclass_nop */, + 0, + Opcode_nop_encode_fns, 0, 0 }, + { "ret", 60 /* xt_iclass_return */, + XTENSA_OPCODE_IS_JUMP, + Opcode_ret_encode_fns, 0, 0 }, + { "s16i", 61 /* xt_iclass_s16i */, + 0, + Opcode_s16i_encode_fns, 0, 0 }, + { "s32i", 62 /* xt_iclass_s32i */, + 0, + Opcode_s32i_encode_fns, 0, 0 }, + { "s8i", 63 /* xt_iclass_s8i */, + 0, + Opcode_s8i_encode_fns, 0, 0 }, + { "ssr", 64 /* xt_iclass_sar */, + 0, + Opcode_ssr_encode_fns, 0, 0 }, + { "ssl", 64 /* xt_iclass_sar */, + 0, + Opcode_ssl_encode_fns, 0, 0 }, + { "ssa8l", 64 /* xt_iclass_sar */, + 0, + Opcode_ssa8l_encode_fns, 0, 0 }, + { "ssa8b", 64 /* xt_iclass_sar */, + 0, + Opcode_ssa8b_encode_fns, 0, 0 }, + { "ssai", 65 /* xt_iclass_sari */, + 0, + Opcode_ssai_encode_fns, 0, 0 }, + { "sll", 66 /* xt_iclass_shifts */, + 0, + Opcode_sll_encode_fns, 0, 0 }, + { "src", 67 /* xt_iclass_shiftst */, + 0, + Opcode_src_encode_fns, 0, 0 }, + { "srl", 68 /* xt_iclass_shiftt */, + 0, + Opcode_srl_encode_fns, 0, 0 }, + { "sra", 68 /* xt_iclass_shiftt */, + 0, + Opcode_sra_encode_fns, 0, 0 }, + { "slli", 69 /* xt_iclass_slli */, + 0, + Opcode_slli_encode_fns, 0, 0 }, + { "srai", 70 /* xt_iclass_srai */, + 0, + Opcode_srai_encode_fns, 0, 0 }, + { "srli", 71 /* xt_iclass_srli */, + 0, + Opcode_srli_encode_fns, 0, 0 }, + { "memw", 72 /* xt_iclass_memw */, + 0, + Opcode_memw_encode_fns, 0, 0 }, + { "extw", 73 /* xt_iclass_extw */, + 0, + Opcode_extw_encode_fns, 0, 0 }, + { "isync", 74 /* xt_iclass_isync */, + 0, + Opcode_isync_encode_fns, 0, 0 }, + { "rsync", 75 /* xt_iclass_sync */, + 0, + Opcode_rsync_encode_fns, 0, 0 }, + { "esync", 75 /* xt_iclass_sync */, + 0, + Opcode_esync_encode_fns, 0, 0 }, + { "dsync", 75 /* xt_iclass_sync */, + 0, + Opcode_dsync_encode_fns, 0, 0 }, + { "rsil", 76 /* xt_iclass_rsil */, + 0, + Opcode_rsil_encode_fns, 0, 0 }, + { "rsr.lend", 77 /* xt_iclass_rsr.lend */, + 0, + Opcode_rsr_lend_encode_fns, 0, 0 }, + { "wsr.lend", 78 /* xt_iclass_wsr.lend */, + 0, + Opcode_wsr_lend_encode_fns, 0, 0 }, + { "xsr.lend", 79 /* xt_iclass_xsr.lend */, + 0, + Opcode_xsr_lend_encode_fns, 0, 0 }, + { "rsr.lcount", 80 /* xt_iclass_rsr.lcount */, + 0, + Opcode_rsr_lcount_encode_fns, 0, 0 }, + { "wsr.lcount", 81 /* xt_iclass_wsr.lcount */, + 0, + Opcode_wsr_lcount_encode_fns, 0, 0 }, + { "xsr.lcount", 82 /* xt_iclass_xsr.lcount */, + 0, + Opcode_xsr_lcount_encode_fns, 0, 0 }, + { "rsr.lbeg", 83 /* xt_iclass_rsr.lbeg */, + 0, + Opcode_rsr_lbeg_encode_fns, 0, 0 }, + { "wsr.lbeg", 84 /* xt_iclass_wsr.lbeg */, + 0, + Opcode_wsr_lbeg_encode_fns, 0, 0 }, + { "xsr.lbeg", 85 /* xt_iclass_xsr.lbeg */, + 0, + Opcode_xsr_lbeg_encode_fns, 0, 0 }, + { "rsr.sar", 86 /* xt_iclass_rsr.sar */, + 0, + Opcode_rsr_sar_encode_fns, 0, 0 }, + { "wsr.sar", 87 /* xt_iclass_wsr.sar */, + 0, + Opcode_wsr_sar_encode_fns, 0, 0 }, + { "xsr.sar", 88 /* xt_iclass_xsr.sar */, + 0, + Opcode_xsr_sar_encode_fns, 0, 0 }, + { "rsr.litbase", 89 /* xt_iclass_rsr.litbase */, + 0, + Opcode_rsr_litbase_encode_fns, 0, 0 }, + { "wsr.litbase", 90 /* xt_iclass_wsr.litbase */, + 0, + Opcode_wsr_litbase_encode_fns, 0, 0 }, + { "xsr.litbase", 91 /* xt_iclass_xsr.litbase */, + 0, + Opcode_xsr_litbase_encode_fns, 0, 0 }, + { "rsr.176", 92 /* xt_iclass_rsr.176 */, + 0, + Opcode_rsr_176_encode_fns, 0, 0 }, + { "rsr.208", 93 /* xt_iclass_rsr.208 */, + 0, + Opcode_rsr_208_encode_fns, 0, 0 }, + { "rsr.ps", 94 /* xt_iclass_rsr.ps */, + 0, + Opcode_rsr_ps_encode_fns, 0, 0 }, + { "wsr.ps", 95 /* xt_iclass_wsr.ps */, + 0, + Opcode_wsr_ps_encode_fns, 0, 0 }, + { "xsr.ps", 96 /* xt_iclass_xsr.ps */, + 0, + Opcode_xsr_ps_encode_fns, 0, 0 }, + { "rsr.epc1", 97 /* xt_iclass_rsr.epc1 */, + 0, + Opcode_rsr_epc1_encode_fns, 0, 0 }, + { "wsr.epc1", 98 /* xt_iclass_wsr.epc1 */, + 0, + Opcode_wsr_epc1_encode_fns, 0, 0 }, + { "xsr.epc1", 99 /* xt_iclass_xsr.epc1 */, + 0, + Opcode_xsr_epc1_encode_fns, 0, 0 }, + { "rsr.excsave1", 100 /* xt_iclass_rsr.excsave1 */, + 0, + Opcode_rsr_excsave1_encode_fns, 0, 0 }, + { "wsr.excsave1", 101 /* xt_iclass_wsr.excsave1 */, + 0, + Opcode_wsr_excsave1_encode_fns, 0, 0 }, + { "xsr.excsave1", 102 /* xt_iclass_xsr.excsave1 */, + 0, + Opcode_xsr_excsave1_encode_fns, 0, 0 }, + { "rsr.epc2", 103 /* xt_iclass_rsr.epc2 */, + 0, + Opcode_rsr_epc2_encode_fns, 0, 0 }, + { "wsr.epc2", 104 /* xt_iclass_wsr.epc2 */, + 0, + Opcode_wsr_epc2_encode_fns, 0, 0 }, + { "xsr.epc2", 105 /* xt_iclass_xsr.epc2 */, + 0, + Opcode_xsr_epc2_encode_fns, 0, 0 }, + { "rsr.excsave2", 106 /* xt_iclass_rsr.excsave2 */, + 0, + Opcode_rsr_excsave2_encode_fns, 0, 0 }, + { "wsr.excsave2", 107 /* xt_iclass_wsr.excsave2 */, + 0, + Opcode_wsr_excsave2_encode_fns, 0, 0 }, + { "xsr.excsave2", 108 /* xt_iclass_xsr.excsave2 */, + 0, + Opcode_xsr_excsave2_encode_fns, 0, 0 }, + { "rsr.epc3", 109 /* xt_iclass_rsr.epc3 */, + 0, + Opcode_rsr_epc3_encode_fns, 0, 0 }, + { "wsr.epc3", 110 /* xt_iclass_wsr.epc3 */, + 0, + Opcode_wsr_epc3_encode_fns, 0, 0 }, + { "xsr.epc3", 111 /* xt_iclass_xsr.epc3 */, + 0, + Opcode_xsr_epc3_encode_fns, 0, 0 }, + { "rsr.excsave3", 112 /* xt_iclass_rsr.excsave3 */, + 0, + Opcode_rsr_excsave3_encode_fns, 0, 0 }, + { "wsr.excsave3", 113 /* xt_iclass_wsr.excsave3 */, + 0, + Opcode_wsr_excsave3_encode_fns, 0, 0 }, + { "xsr.excsave3", 114 /* xt_iclass_xsr.excsave3 */, + 0, + Opcode_xsr_excsave3_encode_fns, 0, 0 }, + { "rsr.epc4", 115 /* xt_iclass_rsr.epc4 */, + 0, + Opcode_rsr_epc4_encode_fns, 0, 0 }, + { "wsr.epc4", 116 /* xt_iclass_wsr.epc4 */, + 0, + Opcode_wsr_epc4_encode_fns, 0, 0 }, + { "xsr.epc4", 117 /* xt_iclass_xsr.epc4 */, + 0, + Opcode_xsr_epc4_encode_fns, 0, 0 }, + { "rsr.excsave4", 118 /* xt_iclass_rsr.excsave4 */, + 0, + Opcode_rsr_excsave4_encode_fns, 0, 0 }, + { "wsr.excsave4", 119 /* xt_iclass_wsr.excsave4 */, + 0, + Opcode_wsr_excsave4_encode_fns, 0, 0 }, + { "xsr.excsave4", 120 /* xt_iclass_xsr.excsave4 */, + 0, + Opcode_xsr_excsave4_encode_fns, 0, 0 }, + { "rsr.eps2", 121 /* xt_iclass_rsr.eps2 */, + 0, + Opcode_rsr_eps2_encode_fns, 0, 0 }, + { "wsr.eps2", 122 /* xt_iclass_wsr.eps2 */, + 0, + Opcode_wsr_eps2_encode_fns, 0, 0 }, + { "xsr.eps2", 123 /* xt_iclass_xsr.eps2 */, + 0, + Opcode_xsr_eps2_encode_fns, 0, 0 }, + { "rsr.eps3", 124 /* xt_iclass_rsr.eps3 */, + 0, + Opcode_rsr_eps3_encode_fns, 0, 0 }, + { "wsr.eps3", 125 /* xt_iclass_wsr.eps3 */, + 0, + Opcode_wsr_eps3_encode_fns, 0, 0 }, + { "xsr.eps3", 126 /* xt_iclass_xsr.eps3 */, + 0, + Opcode_xsr_eps3_encode_fns, 0, 0 }, + { "rsr.eps4", 127 /* xt_iclass_rsr.eps4 */, + 0, + Opcode_rsr_eps4_encode_fns, 0, 0 }, + { "wsr.eps4", 128 /* xt_iclass_wsr.eps4 */, + 0, + Opcode_wsr_eps4_encode_fns, 0, 0 }, + { "xsr.eps4", 129 /* xt_iclass_xsr.eps4 */, + 0, + Opcode_xsr_eps4_encode_fns, 0, 0 }, + { "rsr.excvaddr", 130 /* xt_iclass_rsr.excvaddr */, + 0, + Opcode_rsr_excvaddr_encode_fns, 0, 0 }, + { "wsr.excvaddr", 131 /* xt_iclass_wsr.excvaddr */, + 0, + Opcode_wsr_excvaddr_encode_fns, 0, 0 }, + { "xsr.excvaddr", 132 /* xt_iclass_xsr.excvaddr */, + 0, + Opcode_xsr_excvaddr_encode_fns, 0, 0 }, + { "rsr.depc", 133 /* xt_iclass_rsr.depc */, + 0, + Opcode_rsr_depc_encode_fns, 0, 0 }, + { "wsr.depc", 134 /* xt_iclass_wsr.depc */, + 0, + Opcode_wsr_depc_encode_fns, 0, 0 }, + { "xsr.depc", 135 /* xt_iclass_xsr.depc */, + 0, + Opcode_xsr_depc_encode_fns, 0, 0 }, + { "rsr.exccause", 136 /* xt_iclass_rsr.exccause */, + 0, + Opcode_rsr_exccause_encode_fns, 0, 0 }, + { "wsr.exccause", 137 /* xt_iclass_wsr.exccause */, + 0, + Opcode_wsr_exccause_encode_fns, 0, 0 }, + { "xsr.exccause", 138 /* xt_iclass_xsr.exccause */, + 0, + Opcode_xsr_exccause_encode_fns, 0, 0 }, + { "rsr.misc0", 139 /* xt_iclass_rsr.misc0 */, + 0, + Opcode_rsr_misc0_encode_fns, 0, 0 }, + { "wsr.misc0", 140 /* xt_iclass_wsr.misc0 */, + 0, + Opcode_wsr_misc0_encode_fns, 0, 0 }, + { "xsr.misc0", 141 /* xt_iclass_xsr.misc0 */, + 0, + Opcode_xsr_misc0_encode_fns, 0, 0 }, + { "rsr.misc1", 142 /* xt_iclass_rsr.misc1 */, + 0, + Opcode_rsr_misc1_encode_fns, 0, 0 }, + { "wsr.misc1", 143 /* xt_iclass_wsr.misc1 */, + 0, + Opcode_wsr_misc1_encode_fns, 0, 0 }, + { "xsr.misc1", 144 /* xt_iclass_xsr.misc1 */, + 0, + Opcode_xsr_misc1_encode_fns, 0, 0 }, + { "rsr.prid", 145 /* xt_iclass_rsr.prid */, + 0, + Opcode_rsr_prid_encode_fns, 0, 0 }, + { "rfi", 146 /* xt_iclass_rfi */, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfi_encode_fns, 0, 0 }, + { "waiti", 147 /* xt_iclass_wait */, + 0, + Opcode_waiti_encode_fns, 0, 0 }, + { "rsr.interrupt", 148 /* xt_iclass_rsr.interrupt */, + 0, + Opcode_rsr_interrupt_encode_fns, 0, 0 }, + { "wsr.intset", 149 /* xt_iclass_wsr.intset */, + 0, + Opcode_wsr_intset_encode_fns, 0, 0 }, + { "wsr.intclear", 150 /* xt_iclass_wsr.intclear */, + 0, + Opcode_wsr_intclear_encode_fns, 0, 0 }, + { "rsr.intenable", 151 /* xt_iclass_rsr.intenable */, + 0, + Opcode_rsr_intenable_encode_fns, 0, 0 }, + { "wsr.intenable", 152 /* xt_iclass_wsr.intenable */, + 0, + Opcode_wsr_intenable_encode_fns, 0, 0 }, + { "xsr.intenable", 153 /* xt_iclass_xsr.intenable */, + 0, + Opcode_xsr_intenable_encode_fns, 0, 0 }, + { "break", 154 /* xt_iclass_break */, + 0, + Opcode_break_encode_fns, 0, 0 }, + { "break.n", 155 /* xt_iclass_break.n */, + 0, + Opcode_break_n_encode_fns, 0, 0 }, + { "rsr.dbreaka0", 156 /* xt_iclass_rsr.dbreaka0 */, + 0, + Opcode_rsr_dbreaka0_encode_fns, 0, 0 }, + { "wsr.dbreaka0", 157 /* xt_iclass_wsr.dbreaka0 */, + 0, + Opcode_wsr_dbreaka0_encode_fns, 0, 0 }, + { "xsr.dbreaka0", 158 /* xt_iclass_xsr.dbreaka0 */, + 0, + Opcode_xsr_dbreaka0_encode_fns, 0, 0 }, + { "rsr.dbreakc0", 159 /* xt_iclass_rsr.dbreakc0 */, + 0, + Opcode_rsr_dbreakc0_encode_fns, 0, 0 }, + { "wsr.dbreakc0", 160 /* xt_iclass_wsr.dbreakc0 */, + 0, + Opcode_wsr_dbreakc0_encode_fns, 0, 0 }, + { "xsr.dbreakc0", 161 /* xt_iclass_xsr.dbreakc0 */, + 0, + Opcode_xsr_dbreakc0_encode_fns, 0, 0 }, + { "rsr.dbreaka1", 162 /* xt_iclass_rsr.dbreaka1 */, + 0, + Opcode_rsr_dbreaka1_encode_fns, 0, 0 }, + { "wsr.dbreaka1", 163 /* xt_iclass_wsr.dbreaka1 */, + 0, + Opcode_wsr_dbreaka1_encode_fns, 0, 0 }, + { "xsr.dbreaka1", 164 /* xt_iclass_xsr.dbreaka1 */, + 0, + Opcode_xsr_dbreaka1_encode_fns, 0, 0 }, + { "rsr.dbreakc1", 165 /* xt_iclass_rsr.dbreakc1 */, + 0, + Opcode_rsr_dbreakc1_encode_fns, 0, 0 }, + { "wsr.dbreakc1", 166 /* xt_iclass_wsr.dbreakc1 */, + 0, + Opcode_wsr_dbreakc1_encode_fns, 0, 0 }, + { "xsr.dbreakc1", 167 /* xt_iclass_xsr.dbreakc1 */, + 0, + Opcode_xsr_dbreakc1_encode_fns, 0, 0 }, + { "rsr.ibreaka0", 168 /* xt_iclass_rsr.ibreaka0 */, + 0, + Opcode_rsr_ibreaka0_encode_fns, 0, 0 }, + { "wsr.ibreaka0", 169 /* xt_iclass_wsr.ibreaka0 */, + 0, + Opcode_wsr_ibreaka0_encode_fns, 0, 0 }, + { "xsr.ibreaka0", 170 /* xt_iclass_xsr.ibreaka0 */, + 0, + Opcode_xsr_ibreaka0_encode_fns, 0, 0 }, + { "rsr.ibreaka1", 171 /* xt_iclass_rsr.ibreaka1 */, + 0, + Opcode_rsr_ibreaka1_encode_fns, 0, 0 }, + { "wsr.ibreaka1", 172 /* xt_iclass_wsr.ibreaka1 */, + 0, + Opcode_wsr_ibreaka1_encode_fns, 0, 0 }, + { "xsr.ibreaka1", 173 /* xt_iclass_xsr.ibreaka1 */, + 0, + Opcode_xsr_ibreaka1_encode_fns, 0, 0 }, + { "rsr.ibreakenable", 174 /* xt_iclass_rsr.ibreakenable */, + 0, + Opcode_rsr_ibreakenable_encode_fns, 0, 0 }, + { "wsr.ibreakenable", 175 /* xt_iclass_wsr.ibreakenable */, + 0, + Opcode_wsr_ibreakenable_encode_fns, 0, 0 }, + { "xsr.ibreakenable", 176 /* xt_iclass_xsr.ibreakenable */, + 0, + Opcode_xsr_ibreakenable_encode_fns, 0, 0 }, + { "rsr.debugcause", 177 /* xt_iclass_rsr.debugcause */, + 0, + Opcode_rsr_debugcause_encode_fns, 0, 0 }, + { "wsr.debugcause", 178 /* xt_iclass_wsr.debugcause */, + 0, + Opcode_wsr_debugcause_encode_fns, 0, 0 }, + { "xsr.debugcause", 179 /* xt_iclass_xsr.debugcause */, + 0, + Opcode_xsr_debugcause_encode_fns, 0, 0 }, + { "rsr.icount", 180 /* xt_iclass_rsr.icount */, + 0, + Opcode_rsr_icount_encode_fns, 0, 0 }, + { "wsr.icount", 181 /* xt_iclass_wsr.icount */, + 0, + Opcode_wsr_icount_encode_fns, 0, 0 }, + { "xsr.icount", 182 /* xt_iclass_xsr.icount */, + 0, + Opcode_xsr_icount_encode_fns, 0, 0 }, + { "rsr.icountlevel", 183 /* xt_iclass_rsr.icountlevel */, + 0, + Opcode_rsr_icountlevel_encode_fns, 0, 0 }, + { "wsr.icountlevel", 184 /* xt_iclass_wsr.icountlevel */, + 0, + Opcode_wsr_icountlevel_encode_fns, 0, 0 }, + { "xsr.icountlevel", 185 /* xt_iclass_xsr.icountlevel */, + 0, + Opcode_xsr_icountlevel_encode_fns, 0, 0 }, + { "rsr.ddr", 186 /* xt_iclass_rsr.ddr */, + 0, + Opcode_rsr_ddr_encode_fns, 0, 0 }, + { "wsr.ddr", 187 /* xt_iclass_wsr.ddr */, + 0, + Opcode_wsr_ddr_encode_fns, 0, 0 }, + { "xsr.ddr", 188 /* xt_iclass_xsr.ddr */, + 0, + Opcode_xsr_ddr_encode_fns, 0, 0 }, + { "rfdo", 189 /* xt_iclass_rfdo */, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfdo_encode_fns, 0, 0 }, + { "rfdd", 190 /* xt_iclass_rfdd */, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfdd_encode_fns, 0, 0 }, + { "rsr.ccount", 191 /* xt_iclass_rsr.ccount */, + 0, + Opcode_rsr_ccount_encode_fns, 0, 0 }, + { "wsr.ccount", 192 /* xt_iclass_wsr.ccount */, + 0, + Opcode_wsr_ccount_encode_fns, 0, 0 }, + { "xsr.ccount", 193 /* xt_iclass_xsr.ccount */, + 0, + Opcode_xsr_ccount_encode_fns, 0, 0 }, + { "rsr.ccompare0", 194 /* xt_iclass_rsr.ccompare0 */, + 0, + Opcode_rsr_ccompare0_encode_fns, 0, 0 }, + { "wsr.ccompare0", 195 /* xt_iclass_wsr.ccompare0 */, + 0, + Opcode_wsr_ccompare0_encode_fns, 0, 0 }, + { "xsr.ccompare0", 196 /* xt_iclass_xsr.ccompare0 */, + 0, + Opcode_xsr_ccompare0_encode_fns, 0, 0 }, + { "rsr.ccompare1", 197 /* xt_iclass_rsr.ccompare1 */, + 0, + Opcode_rsr_ccompare1_encode_fns, 0, 0 }, + { "wsr.ccompare1", 198 /* xt_iclass_wsr.ccompare1 */, + 0, + Opcode_wsr_ccompare1_encode_fns, 0, 0 }, + { "xsr.ccompare1", 199 /* xt_iclass_xsr.ccompare1 */, + 0, + Opcode_xsr_ccompare1_encode_fns, 0, 0 }, + { "rsr.ccompare2", 200 /* xt_iclass_rsr.ccompare2 */, + 0, + Opcode_rsr_ccompare2_encode_fns, 0, 0 }, + { "wsr.ccompare2", 201 /* xt_iclass_wsr.ccompare2 */, + 0, + Opcode_wsr_ccompare2_encode_fns, 0, 0 }, + { "xsr.ccompare2", 202 /* xt_iclass_xsr.ccompare2 */, + 0, + Opcode_xsr_ccompare2_encode_fns, 0, 0 }, + { "ipf", 203 /* xt_iclass_icache */, + 0, + Opcode_ipf_encode_fns, 0, 0 }, + { "ihi", 203 /* xt_iclass_icache */, + 0, + Opcode_ihi_encode_fns, 0, 0 }, + { "iii", 204 /* xt_iclass_icache_inv */, + 0, + Opcode_iii_encode_fns, 0, 0 }, + { "lict", 205 /* xt_iclass_licx */, + 0, + Opcode_lict_encode_fns, 0, 0 }, + { "licw", 205 /* xt_iclass_licx */, + 0, + Opcode_licw_encode_fns, 0, 0 }, + { "sict", 206 /* xt_iclass_sicx */, + 0, + Opcode_sict_encode_fns, 0, 0 }, + { "sicw", 206 /* xt_iclass_sicx */, + 0, + Opcode_sicw_encode_fns, 0, 0 }, + { "dhwb", 207 /* xt_iclass_dcache */, + 0, + Opcode_dhwb_encode_fns, 0, 0 }, + { "dhwbi", 207 /* xt_iclass_dcache */, + 0, + Opcode_dhwbi_encode_fns, 0, 0 }, + { "diwb", 208 /* xt_iclass_dcache_ind */, + 0, + Opcode_diwb_encode_fns, 0, 0 }, + { "diwbi", 208 /* xt_iclass_dcache_ind */, + 0, + Opcode_diwbi_encode_fns, 0, 0 }, + { "dhi", 209 /* xt_iclass_dcache_inv */, + 0, + Opcode_dhi_encode_fns, 0, 0 }, + { "dii", 209 /* xt_iclass_dcache_inv */, + 0, + Opcode_dii_encode_fns, 0, 0 }, + { "dpfr", 210 /* xt_iclass_dpf */, + 0, + Opcode_dpfr_encode_fns, 0, 0 }, + { "dpfw", 210 /* xt_iclass_dpf */, + 0, + Opcode_dpfw_encode_fns, 0, 0 }, + { "dpfro", 210 /* xt_iclass_dpf */, + 0, + Opcode_dpfro_encode_fns, 0, 0 }, + { "dpfwo", 210 /* xt_iclass_dpf */, + 0, + Opcode_dpfwo_encode_fns, 0, 0 }, + { "sdct", 211 /* xt_iclass_sdct */, + 0, + Opcode_sdct_encode_fns, 0, 0 }, + { "ldct", 212 /* xt_iclass_ldct */, + 0, + Opcode_ldct_encode_fns, 0, 0 }, + { "idtlb", 213 /* xt_iclass_idtlb */, + 0, + Opcode_idtlb_encode_fns, 0, 0 }, + { "pdtlb", 214 /* xt_iclass_rdtlb */, + 0, + Opcode_pdtlb_encode_fns, 0, 0 }, + { "rdtlb0", 214 /* xt_iclass_rdtlb */, + 0, + Opcode_rdtlb0_encode_fns, 0, 0 }, + { "rdtlb1", 214 /* xt_iclass_rdtlb */, + 0, + Opcode_rdtlb1_encode_fns, 0, 0 }, + { "wdtlb", 215 /* xt_iclass_wdtlb */, + 0, + Opcode_wdtlb_encode_fns, 0, 0 }, + { "iitlb", 216 /* xt_iclass_iitlb */, + 0, + Opcode_iitlb_encode_fns, 0, 0 }, + { "pitlb", 217 /* xt_iclass_ritlb */, + 0, + Opcode_pitlb_encode_fns, 0, 0 }, + { "ritlb0", 217 /* xt_iclass_ritlb */, + 0, + Opcode_ritlb0_encode_fns, 0, 0 }, + { "ritlb1", 217 /* xt_iclass_ritlb */, + 0, + Opcode_ritlb1_encode_fns, 0, 0 }, + { "witlb", 218 /* xt_iclass_witlb */, + 0, + Opcode_witlb_encode_fns, 0, 0 }, + { "nsa", 219 /* xt_iclass_nsa */, + 0, + Opcode_nsa_encode_fns, 0, 0 }, + { "nsau", 219 /* xt_iclass_nsa */, + 0, + Opcode_nsau_encode_fns, 0, 0 } +}; + + +/* Slot-specific opcode decode functions. */ + +static int +Slot_inst_decode (const xtensa_insnbuf insn) +{ + switch (Field_op0_Slot_inst_get (insn)) + { + case 0: + switch (Field_op1_Slot_inst_get (insn)) + { + case 0: + switch (Field_op2_Slot_inst_get (insn)) + { + case 0: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + switch (Field_m_Slot_inst_get (insn)) + { + case 0: + return 77; /* ill */ + case 2: + switch (Field_n_Slot_inst_get (insn)) + { + case 0: + return 96; /* ret */ + case 1: + return 14; /* retw */ + case 2: + return 79; /* jx */ + } + break; + case 3: + switch (Field_n_Slot_inst_get (insn)) + { + case 0: + return 75; /* callx0 */ + case 1: + return 10; /* callx4 */ + case 2: + return 9; /* callx8 */ + case 3: + return 8; /* callx12 */ + } + break; + } + break; + case 1: + return 12; /* movsp */ + case 2: + if (Field_s_Slot_inst_get (insn) == 0) + { + switch (Field_t_Slot_inst_get (insn)) + { + case 0: + return 114; /* isync */ + case 1: + return 115; /* rsync */ + case 2: + return 116; /* esync */ + case 3: + return 117; /* dsync */ + case 8: + return 0; /* excw */ + case 12: + return 112; /* memw */ + case 13: + return 113; /* extw */ + case 15: + return 95; /* nop */ + } + } + break; + case 3: + switch (Field_t_Slot_inst_get (insn)) + { + case 0: + switch (Field_s_Slot_inst_get (insn)) + { + case 0: + return 1; /* rfe */ + case 2: + return 2; /* rfde */ + case 4: + return 16; /* rfwo */ + case 5: + return 17; /* rfwu */ + } + break; + case 1: + return 188; /* rfi */ + } + break; + case 4: + return 196; /* break */ + case 5: + switch (Field_s_Slot_inst_get (insn)) + { + case 0: + if (Field_t_Slot_inst_get (insn) == 0) + return 3; /* syscall */ + break; + case 1: + if (Field_t_Slot_inst_get (insn) == 0) + return 4; /* simcall */ + break; + } + break; + case 6: + return 118; /* rsil */ + case 7: + if (Field_t_Slot_inst_get (insn) == 0) + return 189; /* waiti */ + break; + } + break; + case 1: + return 47; /* and */ + case 2: + return 48; /* or */ + case 3: + return 49; /* xor */ + case 4: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + if (Field_t_Slot_inst_get (insn) == 0) + return 100; /* ssr */ + break; + case 1: + if (Field_t_Slot_inst_get (insn) == 0) + return 101; /* ssl */ + break; + case 2: + if (Field_t_Slot_inst_get (insn) == 0) + return 102; /* ssa8l */ + break; + case 3: + if (Field_t_Slot_inst_get (insn) == 0) + return 103; /* ssa8b */ + break; + case 4: + if (Field_thi3_Slot_inst_get (insn) == 0) + return 104; /* ssai */ + break; + case 8: + if (Field_s_Slot_inst_get (insn) == 0) + return 13; /* rotw */ + break; + case 14: + return 274; /* nsa */ + case 15: + return 275; /* nsau */ + } + break; + case 5: + switch (Field_r_Slot_inst_get (insn)) + { + case 3: + return 271; /* ritlb0 */ + case 4: + return 269; /* iitlb */ + case 5: + return 270; /* pitlb */ + case 6: + return 273; /* witlb */ + case 7: + return 272; /* ritlb1 */ + case 11: + return 266; /* rdtlb0 */ + case 12: + return 264; /* idtlb */ + case 13: + return 265; /* pdtlb */ + case 14: + return 268; /* wdtlb */ + case 15: + return 267; /* rdtlb1 */ + } + break; + case 6: + switch (Field_s_Slot_inst_get (insn)) + { + case 0: + return 93; /* neg */ + case 1: + return 94; /* abs */ + } + break; + case 8: + return 39; /* add */ + case 9: + return 41; /* addx2 */ + case 10: + return 42; /* addx4 */ + case 11: + return 43; /* addx8 */ + case 12: + return 40; /* sub */ + case 13: + return 44; /* subx2 */ + case 14: + return 45; /* subx4 */ + case 15: + return 46; /* subx8 */ + } + break; + case 1: + switch (Field_op2_Slot_inst_get (insn)) + { + case 0: + case 1: + return 109; /* slli */ + case 2: + case 3: + return 110; /* srai */ + case 4: + return 111; /* srli */ + case 6: + switch (Field_sr_Slot_inst_get (insn)) + { + case 0: + return 127; /* xsr.lbeg */ + case 1: + return 121; /* xsr.lend */ + case 2: + return 124; /* xsr.lcount */ + case 3: + return 130; /* xsr.sar */ + case 5: + return 133; /* xsr.litbase */ + case 72: + return 22; /* xsr.windowbase */ + case 73: + return 25; /* xsr.windowstart */ + case 96: + return 218; /* xsr.ibreakenable */ + case 104: + return 230; /* xsr.ddr */ + case 128: + return 212; /* xsr.ibreaka0 */ + case 129: + return 215; /* xsr.ibreaka1 */ + case 144: + return 200; /* xsr.dbreaka0 */ + case 145: + return 206; /* xsr.dbreaka1 */ + case 160: + return 203; /* xsr.dbreakc0 */ + case 161: + return 209; /* xsr.dbreakc1 */ + case 177: + return 141; /* xsr.epc1 */ + case 178: + return 147; /* xsr.epc2 */ + case 179: + return 153; /* xsr.epc3 */ + case 180: + return 159; /* xsr.epc4 */ + case 192: + return 177; /* xsr.depc */ + case 194: + return 165; /* xsr.eps2 */ + case 195: + return 168; /* xsr.eps3 */ + case 196: + return 171; /* xsr.eps4 */ + case 209: + return 144; /* xsr.excsave1 */ + case 210: + return 150; /* xsr.excsave2 */ + case 211: + return 156; /* xsr.excsave3 */ + case 212: + return 162; /* xsr.excsave4 */ + case 228: + return 195; /* xsr.intenable */ + case 230: + return 138; /* xsr.ps */ + case 232: + return 180; /* xsr.exccause */ + case 233: + return 221; /* xsr.debugcause */ + case 234: + return 235; /* xsr.ccount */ + case 236: + return 224; /* xsr.icount */ + case 237: + return 227; /* xsr.icountlevel */ + case 238: + return 174; /* xsr.excvaddr */ + case 240: + return 238; /* xsr.ccompare0 */ + case 241: + return 241; /* xsr.ccompare1 */ + case 242: + return 244; /* xsr.ccompare2 */ + case 244: + return 183; /* xsr.misc0 */ + case 245: + return 186; /* xsr.misc1 */ + } + break; + case 8: + return 106; /* src */ + case 9: + if (Field_s_Slot_inst_get (insn) == 0) + return 107; /* srl */ + break; + case 10: + if (Field_t_Slot_inst_get (insn) == 0) + return 105; /* sll */ + break; + case 11: + if (Field_s_Slot_inst_get (insn) == 0) + return 108; /* sra */ + break; + case 15: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + return 248; /* lict */ + case 1: + return 250; /* sict */ + case 2: + return 249; /* licw */ + case 3: + return 251; /* sicw */ + case 8: + return 263; /* ldct */ + case 9: + return 262; /* sdct */ + case 14: + if (Field_t_Slot_inst_get (insn) == 0) + return 231; /* rfdo */ + if (Field_t_Slot_inst_get (insn) == 1) + return 232; /* rfdd */ + break; + } + break; + } + break; + case 3: + switch (Field_op2_Slot_inst_get (insn)) + { + case 0: + switch (Field_sr_Slot_inst_get (insn)) + { + case 0: + return 125; /* rsr.lbeg */ + case 1: + return 119; /* rsr.lend */ + case 2: + return 122; /* rsr.lcount */ + case 3: + return 128; /* rsr.sar */ + case 5: + return 131; /* rsr.litbase */ + case 72: + return 20; /* rsr.windowbase */ + case 73: + return 23; /* rsr.windowstart */ + case 96: + return 216; /* rsr.ibreakenable */ + case 104: + return 228; /* rsr.ddr */ + case 128: + return 210; /* rsr.ibreaka0 */ + case 129: + return 213; /* rsr.ibreaka1 */ + case 144: + return 198; /* rsr.dbreaka0 */ + case 145: + return 204; /* rsr.dbreaka1 */ + case 160: + return 201; /* rsr.dbreakc0 */ + case 161: + return 207; /* rsr.dbreakc1 */ + case 176: + return 134; /* rsr.176 */ + case 177: + return 139; /* rsr.epc1 */ + case 178: + return 145; /* rsr.epc2 */ + case 179: + return 151; /* rsr.epc3 */ + case 180: + return 157; /* rsr.epc4 */ + case 192: + return 175; /* rsr.depc */ + case 194: + return 163; /* rsr.eps2 */ + case 195: + return 166; /* rsr.eps3 */ + case 196: + return 169; /* rsr.eps4 */ + case 208: + return 135; /* rsr.208 */ + case 209: + return 142; /* rsr.excsave1 */ + case 210: + return 148; /* rsr.excsave2 */ + case 211: + return 154; /* rsr.excsave3 */ + case 212: + return 160; /* rsr.excsave4 */ + case 226: + return 190; /* rsr.interrupt */ + case 228: + return 193; /* rsr.intenable */ + case 230: + return 136; /* rsr.ps */ + case 232: + return 178; /* rsr.exccause */ + case 233: + return 219; /* rsr.debugcause */ + case 234: + return 233; /* rsr.ccount */ + case 235: + return 187; /* rsr.prid */ + case 236: + return 222; /* rsr.icount */ + case 237: + return 225; /* rsr.icountlevel */ + case 238: + return 172; /* rsr.excvaddr */ + case 240: + return 236; /* rsr.ccompare0 */ + case 241: + return 239; /* rsr.ccompare1 */ + case 242: + return 242; /* rsr.ccompare2 */ + case 244: + return 181; /* rsr.misc0 */ + case 245: + return 184; /* rsr.misc1 */ + } + break; + case 1: + switch (Field_sr_Slot_inst_get (insn)) + { + case 0: + return 126; /* wsr.lbeg */ + case 1: + return 120; /* wsr.lend */ + case 2: + return 123; /* wsr.lcount */ + case 3: + return 129; /* wsr.sar */ + case 5: + return 132; /* wsr.litbase */ + case 72: + return 21; /* wsr.windowbase */ + case 73: + return 24; /* wsr.windowstart */ + case 96: + return 217; /* wsr.ibreakenable */ + case 104: + return 229; /* wsr.ddr */ + case 128: + return 211; /* wsr.ibreaka0 */ + case 129: + return 214; /* wsr.ibreaka1 */ + case 144: + return 199; /* wsr.dbreaka0 */ + case 145: + return 205; /* wsr.dbreaka1 */ + case 160: + return 202; /* wsr.dbreakc0 */ + case 161: + return 208; /* wsr.dbreakc1 */ + case 177: + return 140; /* wsr.epc1 */ + case 178: + return 146; /* wsr.epc2 */ + case 179: + return 152; /* wsr.epc3 */ + case 180: + return 158; /* wsr.epc4 */ + case 192: + return 176; /* wsr.depc */ + case 194: + return 164; /* wsr.eps2 */ + case 195: + return 167; /* wsr.eps3 */ + case 196: + return 170; /* wsr.eps4 */ + case 209: + return 143; /* wsr.excsave1 */ + case 210: + return 149; /* wsr.excsave2 */ + case 211: + return 155; /* wsr.excsave3 */ + case 212: + return 161; /* wsr.excsave4 */ + case 226: + return 191; /* wsr.intset */ + case 227: + return 192; /* wsr.intclear */ + case 228: + return 194; /* wsr.intenable */ + case 230: + return 137; /* wsr.ps */ + case 232: + return 179; /* wsr.exccause */ + case 233: + return 220; /* wsr.debugcause */ + case 234: + return 234; /* wsr.ccount */ + case 236: + return 223; /* wsr.icount */ + case 237: + return 226; /* wsr.icountlevel */ + case 238: + return 173; /* wsr.excvaddr */ + case 240: + return 237; /* wsr.ccompare0 */ + case 241: + return 240; /* wsr.ccompare1 */ + case 242: + return 243; /* wsr.ccompare2 */ + case 244: + return 182; /* wsr.misc0 */ + case 245: + return 185; /* wsr.misc1 */ + } + break; + case 8: + return 89; /* moveqz */ + case 9: + return 90; /* movnez */ + case 10: + return 91; /* movltz */ + case 11: + return 92; /* movgez */ + } + break; + case 4: + case 5: + return 76; /* extui */ + case 9: + switch (Field_op2_Slot_inst_get (insn)) + { + case 0: + return 18; /* l32e */ + case 4: + return 19; /* s32e */ + } + break; + } break; - case 9: /* LSI4: op1=1001 */ - switch (get_op2_field (insn)) { - case 4: /* S32E: op2=0100 */ - return xtensa_s32e_op; - case 0: /* L32E: op2=0000 */ - return xtensa_l32e_op; - } + case 1: + return 83; /* l32r */ + case 2: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + return 84; /* l8ui */ + case 1: + return 80; /* l16ui */ + case 2: + return 82; /* l32i */ + case 4: + return 99; /* s8i */ + case 5: + return 97; /* s16i */ + case 6: + return 98; /* s32i */ + case 7: + switch (Field_t_Slot_inst_get (insn)) + { + case 0: + return 258; /* dpfr */ + case 1: + return 259; /* dpfw */ + case 2: + return 260; /* dpfro */ + case 3: + return 261; /* dpfwo */ + case 4: + return 252; /* dhwb */ + case 5: + return 253; /* dhwbi */ + case 6: + return 256; /* dhi */ + case 7: + return 257; /* dii */ + case 8: + switch (Field_op1_Slot_inst_get (insn)) + { + case 4: + return 254; /* diwb */ + case 5: + return 255; /* diwbi */ + } + break; + case 12: + return 245; /* ipf */ + case 14: + return 246; /* ihi */ + case 15: + return 247; /* iii */ + } + break; + case 9: + return 81; /* l16si */ + case 10: + return 88; /* movi */ + case 12: + return 37; /* addi */ + case 13: + return 38; /* addmi */ + } break; - case 4: /* EXTUI: op1=010x */ - case 5: /* EXTUI: op1=010x */ - return xtensa_extui_op; - case 0: /* RST0: op1=0000 */ - switch (get_op2_field (insn)) { - case 15: /* SUBX8: op2=1111 */ - return xtensa_subx8_op; - case 0: /* ST0: op2=0000 */ - switch (get_r_field (insn)) { - case 0: /* SNM0: r=0000 */ - switch (get_m_field (insn)) { - case 2: /* JR: m=10 */ - switch (get_n_field (insn)) { - case 0: /* RET: n=00 */ - return xtensa_ret_op; - case 1: /* RETW: n=01 */ - return xtensa_retw_op; - case 2: /* JX: n=10 */ - return xtensa_jx_op; - } - break; - case 3: /* CALLX: m=11 */ - switch (get_n_field (insn)) { - case 0: /* CALLX0: n=00 */ - return xtensa_callx0_op; - case 1: /* CALLX4: n=01 */ - return xtensa_callx4_op; - case 2: /* CALLX8: n=10 */ - return xtensa_callx8_op; - case 3: /* CALLX12: n=11 */ - return xtensa_callx12_op; - } - break; - } - break; - case 1: /* MOVSP: r=0001 */ - return xtensa_movsp_op; - case 2: /* SYNC: r=0010 */ - switch (get_s_field (insn)) { - case 0: /* SYNCT: s=0000 */ - switch (get_t_field (insn)) { - case 2: /* ESYNC: t=0010 */ - return xtensa_esync_op; - case 3: /* DSYNC: t=0011 */ - return xtensa_dsync_op; - case 8: /* EXCW: t=1000 */ - return xtensa_excw_op; - case 12: /* MEMW: t=1100 */ - return xtensa_memw_op; - case 0: /* ISYNC: t=0000 */ - return xtensa_isync_op; - case 1: /* RSYNC: t=0001 */ - return xtensa_rsync_op; - } - break; - } - break; - case 4: /* BREAK: r=0100 */ - return xtensa_break_op; - case 3: /* RFEI: r=0011 */ - switch (get_t_field (insn)) { - case 0: /* RFET: t=0000 */ - switch (get_s_field (insn)) { - case 2: /* RFDE: s=0010 */ - return xtensa_rfde_op; - case 4: /* RFWO: s=0100 */ - return xtensa_rfwo_op; - case 5: /* RFWU: s=0101 */ - return xtensa_rfwu_op; - case 0: /* RFE: s=0000 */ - return xtensa_rfe_op; - } - break; - case 1: /* RFI: t=0001 */ - return xtensa_rfi_op; - } - break; - case 5: /* SCALL: r=0101 */ - switch (get_s_field (insn)) { - case 0: /* SYSCALL: s=0000 */ - return xtensa_syscall_op; - case 1: /* SIMCALL: s=0001 */ - return xtensa_simcall_op; - } - break; - case 6: /* RSIL: r=0110 */ - return xtensa_rsil_op; - case 7: /* WAITI: r=0111 */ - return xtensa_waiti_op; - } - break; - case 1: /* AND: op2=0001 */ - return xtensa_and_op; - case 2: /* OR: op2=0010 */ - return xtensa_or_op; - case 3: /* XOR: op2=0011 */ - return xtensa_xor_op; - case 4: /* ST1: op2=0100 */ - switch (get_r_field (insn)) { - case 15: /* NSAU: r=1111 */ - return xtensa_nsau_op; - case 0: /* SSR: r=0000 */ - return xtensa_ssr_op; - case 1: /* SSL: r=0001 */ - return xtensa_ssl_op; - case 2: /* SSA8L: r=0010 */ - return xtensa_ssa8l_op; - case 3: /* SSA8B: r=0011 */ - return xtensa_ssa8b_op; - case 4: /* SSAI: r=0100 */ - return xtensa_ssai_op; - case 8: /* ROTW: r=1000 */ - return xtensa_rotw_op; - case 14: /* NSA: r=1110 */ - return xtensa_nsa_op; - } - break; - case 8: /* ADD: op2=1000 */ - return xtensa_add_op; - case 5: /* ST4: op2=0101 */ - switch (get_r_field (insn)) { - case 15: /* RDTLB1: r=1111 */ - return xtensa_rdtlb1_op; - case 0: /* IITLBA: r=0000 */ - return xtensa_iitlba_op; - case 3: /* RITLB0: r=0011 */ - return xtensa_ritlb0_op; - case 4: /* IITLB: r=0100 */ - return xtensa_iitlb_op; - case 8: /* IDTLBA: r=1000 */ - return xtensa_idtlba_op; - case 5: /* PITLB: r=0101 */ - return xtensa_pitlb_op; - case 6: /* WITLB: r=0110 */ - return xtensa_witlb_op; - case 7: /* RITLB1: r=0111 */ - return xtensa_ritlb1_op; - case 11: /* RDTLB0: r=1011 */ - return xtensa_rdtlb0_op; - case 12: /* IDTLB: r=1100 */ - return xtensa_idtlb_op; - case 13: /* PDTLB: r=1101 */ - return xtensa_pdtlb_op; - case 14: /* WDTLB: r=1110 */ - return xtensa_wdtlb_op; - } - break; - case 6: /* RT0: op2=0110 */ - switch (get_s_field (insn)) { - case 0: /* NEG: s=0000 */ - return xtensa_neg_op; - case 1: /* ABS: s=0001 */ - return xtensa_abs_op; - } - break; - case 9: /* ADDX2: op2=1001 */ - return xtensa_addx2_op; - case 10: /* ADDX4: op2=1010 */ - return xtensa_addx4_op; - case 11: /* ADDX8: op2=1011 */ - return xtensa_addx8_op; - case 12: /* SUB: op2=1100 */ - return xtensa_sub_op; - case 13: /* SUBX2: op2=1101 */ - return xtensa_subx2_op; - case 14: /* SUBX4: op2=1110 */ - return xtensa_subx4_op; - } + case 5: + switch (Field_n_Slot_inst_get (insn)) + { + case 0: + return 74; /* call0 */ + case 1: + return 7; /* call4 */ + case 2: + return 6; /* call8 */ + case 3: + return 5; /* call12 */ + } break; - case 1: /* RST1: op1=0001 */ - switch (get_op2_field (insn)) { - case 15: /* IMP: op2=1111 */ - switch (get_r_field (insn)) { - case 0: /* LICT: r=0000 */ - return xtensa_lict_op; - case 1: /* SICT: r=0001 */ - return xtensa_sict_op; - case 2: /* LICW: r=0010 */ - return xtensa_licw_op; - case 3: /* SICW: r=0011 */ - return xtensa_sicw_op; - case 8: /* LDCT: r=1000 */ - return xtensa_ldct_op; - case 9: /* SDCT: r=1001 */ - return xtensa_sdct_op; - } - break; - case 0: /* SLLI: op2=000x */ - case 1: /* SLLI: op2=000x */ - return xtensa_slli_op; - case 2: /* SRAI: op2=001x */ - case 3: /* SRAI: op2=001x */ - return xtensa_srai_op; - case 4: /* SRLI: op2=0100 */ - return xtensa_srli_op; - case 8: /* SRC: op2=1000 */ - return xtensa_src_op; - case 9: /* SRL: op2=1001 */ - return xtensa_srl_op; - case 6: /* XSR: op2=0110 */ - return xtensa_xsr_op; - case 10: /* SLL: op2=1010 */ - return xtensa_sll_op; - case 11: /* SRA: op2=1011 */ - return xtensa_sra_op; - } + case 6: + switch (Field_n_Slot_inst_get (insn)) + { + case 0: + return 78; /* j */ + case 1: + switch (Field_m_Slot_inst_get (insn)) + { + case 0: + return 70; /* beqz */ + case 1: + return 71; /* bnez */ + case 2: + return 73; /* bltz */ + case 3: + return 72; /* bgez */ + } + break; + case 2: + switch (Field_m_Slot_inst_get (insn)) + { + case 0: + return 50; /* beqi */ + case 1: + return 51; /* bnei */ + case 2: + return 53; /* blti */ + case 3: + return 52; /* bgei */ + } + break; + case 3: + switch (Field_m_Slot_inst_get (insn)) + { + case 0: + return 11; /* entry */ + case 1: + switch (Field_r_Slot_inst_get (insn)) + { + case 8: + return 85; /* loop */ + case 9: + return 86; /* loopnez */ + case 10: + return 87; /* loopgtz */ + } + break; + case 2: + return 57; /* bltui */ + case 3: + return 56; /* bgeui */ + } + break; + } break; - } - break; - case 1: /* L32R: op0=0001 */ - return xtensa_l32r_op; - case 2: /* LSAI: op0=0010 */ - switch (get_r_field (insn)) { - case 0: /* L8UI: r=0000 */ - return xtensa_l8ui_op; - case 1: /* L16UI: r=0001 */ - return xtensa_l16ui_op; - case 2: /* L32I: r=0010 */ - return xtensa_l32i_op; - case 4: /* S8I: r=0100 */ - return xtensa_s8i_op; - case 5: /* S16I: r=0101 */ - return xtensa_s16i_op; - case 9: /* L16SI: r=1001 */ - return xtensa_l16si_op; - case 6: /* S32I: r=0110 */ - return xtensa_s32i_op; - case 7: /* CACHE: r=0111 */ - switch (get_t_field (insn)) { - case 15: /* III: t=1111 */ - return xtensa_iii_op; - case 0: /* DPFR: t=0000 */ - return xtensa_dpfr_op; - case 1: /* DPFW: t=0001 */ - return xtensa_dpfw_op; - case 2: /* DPFRO: t=0010 */ - return xtensa_dpfro_op; - case 4: /* DHWB: t=0100 */ - return xtensa_dhwb_op; - case 3: /* DPFWO: t=0011 */ - return xtensa_dpfwo_op; - case 8: /* DCE: t=1000 */ - switch (get_op1_field (insn)) { - case 4: /* DIWB: op1=0100 */ - return xtensa_diwb_op; - case 5: /* DIWBI: op1=0101 */ - return xtensa_diwbi_op; - } - break; - case 5: /* DHWBI: t=0101 */ - return xtensa_dhwbi_op; - case 6: /* DHI: t=0110 */ - return xtensa_dhi_op; - case 7: /* DII: t=0111 */ - return xtensa_dii_op; - case 12: /* IPF: t=1100 */ - return xtensa_ipf_op; - case 14: /* IHI: t=1110 */ - return xtensa_ihi_op; - } + case 7: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + return 65; /* bnone */ + case 1: + return 58; /* beq */ + case 2: + return 61; /* blt */ + case 3: + return 63; /* bltu */ + case 4: + return 66; /* ball */ + case 5: + return 68; /* bbc */ + case 6: + case 7: + return 54; /* bbci */ + case 8: + return 64; /* bany */ + case 9: + return 59; /* bne */ + case 10: + return 60; /* bge */ + case 11: + return 62; /* bgeu */ + case 12: + return 67; /* bnall */ + case 13: + return 69; /* bbs */ + case 14: + case 15: + return 55; /* bbsi */ + } break; - case 10: /* MOVI: r=1010 */ - return xtensa_movi_op; - case 12: /* ADDI: r=1100 */ - return xtensa_addi_op; - case 13: /* ADDMI: r=1101 */ - return xtensa_addmi_op; } - break; - case 8: /* L32I.N: op0=1000 */ - return xtensa_l32i_n_op; - case 5: /* CALL: op0=0101 */ - switch (get_n_field (insn)) { - case 0: /* CALL0: n=00 */ - return xtensa_call0_op; - case 1: /* CALL4: n=01 */ - return xtensa_call4_op; - case 2: /* CALL8: n=10 */ - return xtensa_call8_op; - case 3: /* CALL12: n=11 */ - return xtensa_call12_op; - } - break; - case 6: /* SI: op0=0110 */ - switch (get_n_field (insn)) { - case 0: /* J: n=00 */ - return xtensa_j_op; - case 1: /* BZ: n=01 */ - switch (get_m_field (insn)) { - case 0: /* BEQZ: m=00 */ - return xtensa_beqz_op; - case 1: /* BNEZ: m=01 */ - return xtensa_bnez_op; - case 2: /* BLTZ: m=10 */ - return xtensa_bltz_op; - case 3: /* BGEZ: m=11 */ - return xtensa_bgez_op; - } - break; - case 2: /* BI0: n=10 */ - switch (get_m_field (insn)) { - case 0: /* BEQI: m=00 */ - return xtensa_beqi_op; - case 1: /* BNEI: m=01 */ - return xtensa_bnei_op; - case 2: /* BLTI: m=10 */ - return xtensa_blti_op; - case 3: /* BGEI: m=11 */ - return xtensa_bgei_op; - } - break; - case 3: /* BI1: n=11 */ - switch (get_m_field (insn)) { - case 0: /* ENTRY: m=00 */ - return xtensa_entry_op; - case 1: /* B1: m=01 */ - switch (get_r_field (insn)) { - case 8: /* LOOP: r=1000 */ - return xtensa_loop_op; - case 9: /* LOOPNEZ: r=1001 */ - return xtensa_loopnez_op; - case 10: /* LOOPGTZ: r=1010 */ - return xtensa_loopgtz_op; - } - break; - case 2: /* BLTUI: m=10 */ - return xtensa_bltui_op; - case 3: /* BGEUI: m=11 */ - return xtensa_bgeui_op; - } + return 0; +} + +static int +Slot_inst16b_decode (const xtensa_insnbuf insn) +{ + switch (Field_op0_Slot_inst16b_get (insn)) + { + case 12: + switch (Field_i_Slot_inst16b_get (insn)) + { + case 0: + return 33; /* movi.n */ + case 1: + switch (Field_z_Slot_inst16b_get (insn)) + { + case 0: + return 28; /* beqz.n */ + case 1: + return 29; /* bnez.n */ + } + break; + } break; - } - break; - case 9: /* S32I.N: op0=1001 */ - return xtensa_s32i_n_op; - case 10: /* ADD.N: op0=1010 */ - return xtensa_add_n_op; - case 7: /* B: op0=0111 */ - switch (get_r_field (insn)) { - case 6: /* BBCI: r=011x */ - case 7: /* BBCI: r=011x */ - return xtensa_bbci_op; - case 0: /* BNONE: r=0000 */ - return xtensa_bnone_op; - case 1: /* BEQ: r=0001 */ - return xtensa_beq_op; - case 2: /* BLT: r=0010 */ - return xtensa_blt_op; - case 4: /* BALL: r=0100 */ - return xtensa_ball_op; - case 14: /* BBSI: r=111x */ - case 15: /* BBSI: r=111x */ - return xtensa_bbsi_op; - case 3: /* BLTU: r=0011 */ - return xtensa_bltu_op; - case 5: /* BBC: r=0101 */ - return xtensa_bbc_op; - case 8: /* BANY: r=1000 */ - return xtensa_bany_op; - case 9: /* BNE: r=1001 */ - return xtensa_bne_op; - case 10: /* BGE: r=1010 */ - return xtensa_bge_op; - case 11: /* BGEU: r=1011 */ - return xtensa_bgeu_op; - case 12: /* BNALL: r=1100 */ - return xtensa_bnall_op; - case 13: /* BBS: r=1101 */ - return xtensa_bbs_op; - } - break; - case 11: /* ADDI.N: op0=1011 */ - return xtensa_addi_n_op; - case 12: /* ST2: op0=1100 */ - switch (get_i_field (insn)) { - case 0: /* MOVI.N: i=0 */ - return xtensa_movi_n_op; - case 1: /* BZ6: i=1 */ - switch (get_z_field (insn)) { - case 0: /* BEQZ.N: z=0 */ - return xtensa_beqz_n_op; - case 1: /* BNEZ.N: z=1 */ - return xtensa_bnez_n_op; - } + case 13: + switch (Field_r_Slot_inst16b_get (insn)) + { + case 0: + return 32; /* mov.n */ + case 15: + switch (Field_t_Slot_inst16b_get (insn)) + { + case 0: + return 35; /* ret.n */ + case 1: + return 15; /* retw.n */ + case 2: + return 197; /* break.n */ + case 3: + if (Field_s_Slot_inst16b_get (insn) == 0) + return 34; /* nop.n */ + break; + case 6: + return 30; /* ill.n */ + } + break; + } break; } - break; - case 13: /* ST3: op0=1101 */ - switch (get_r_field (insn)) { - case 15: /* S3: r=1111 */ - switch (get_t_field (insn)) { - case 0: /* RET.N: t=0000 */ - return xtensa_ret_n_op; - case 1: /* RETW.N: t=0001 */ - return xtensa_retw_n_op; - case 2: /* BREAK.N: t=0010 */ - return xtensa_break_n_op; - case 3: /* NOP.N: t=0011 */ - return xtensa_nop_n_op; - } - break; - case 0: /* MOV.N: r=0000 */ - return xtensa_mov_n_op; + return 0; +} + +static int +Slot_inst16a_decode (const xtensa_insnbuf insn) +{ + switch (Field_op0_Slot_inst16a_get (insn)) + { + case 8: + return 31; /* l32i.n */ + case 9: + return 36; /* s32i.n */ + case 10: + return 26; /* add.n */ + case 11: + return 27; /* addi.n */ } - break; - } - return XTENSA_UNDEFINED; + return 0; +} + + +/* Instruction slots. */ + +static void +Slot_x24_Format_inst_0_get (const xtensa_insnbuf insn, + xtensa_insnbuf slotbuf) +{ + slotbuf[0] = (insn[0] & 0xffffff); +} + +static void +Slot_x24_Format_inst_0_set (xtensa_insnbuf insn, + const xtensa_insnbuf slotbuf) +{ + insn[0] = (insn[0] & ~0xffffff) | (slotbuf[0] & 0xffffff); +} + +static void +Slot_x16a_Format_inst16a_0_get (const xtensa_insnbuf insn, + xtensa_insnbuf slotbuf) +{ + slotbuf[0] = ((insn[0] & 0xffff00) >> 8); +} + +static void +Slot_x16a_Format_inst16a_0_set (xtensa_insnbuf insn, + const xtensa_insnbuf slotbuf) +{ + insn[0] = (insn[0] & ~0xffff00) | ((slotbuf[0] & 0xffff) << 8); +} + +static void +Slot_x16b_Format_inst16b_0_get (const xtensa_insnbuf insn, + xtensa_insnbuf slotbuf) +{ + slotbuf[0] = ((insn[0] & 0xffff00) >> 8); +} + +static void +Slot_x16b_Format_inst16b_0_set (xtensa_insnbuf insn, + const xtensa_insnbuf slotbuf) +{ + insn[0] = (insn[0] & ~0xffff00) | ((slotbuf[0] & 0xffff) << 8); +} + +static xtensa_get_field_fn +Slot_inst_get_field_fns[] = { + Field_t_Slot_inst_get, + Field_bbi4_Slot_inst_get, + Field_bbi_Slot_inst_get, + Field_imm12_Slot_inst_get, + Field_imm8_Slot_inst_get, + Field_s_Slot_inst_get, + Field_imm12b_Slot_inst_get, + Field_imm16_Slot_inst_get, + Field_m_Slot_inst_get, + Field_n_Slot_inst_get, + Field_offset_Slot_inst_get, + Field_op0_Slot_inst_get, + Field_op1_Slot_inst_get, + Field_op2_Slot_inst_get, + Field_r_Slot_inst_get, + Field_sa4_Slot_inst_get, + Field_sae4_Slot_inst_get, + Field_sae_Slot_inst_get, + Field_sal_Slot_inst_get, + Field_sargt_Slot_inst_get, + Field_sas4_Slot_inst_get, + Field_sas_Slot_inst_get, + Field_sr_Slot_inst_get, + Field_st_Slot_inst_get, + Field_thi3_Slot_inst_get, + Field_imm4_Slot_inst_get, + Field_mn_Slot_inst_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Implicit_Field_ar0_get, + Implicit_Field_ar4_get, + Implicit_Field_ar8_get, + Implicit_Field_ar12_get +}; + +static xtensa_set_field_fn +Slot_inst_set_field_fns[] = { + Field_t_Slot_inst_set, + Field_bbi4_Slot_inst_set, + Field_bbi_Slot_inst_set, + Field_imm12_Slot_inst_set, + Field_imm8_Slot_inst_set, + Field_s_Slot_inst_set, + Field_imm12b_Slot_inst_set, + Field_imm16_Slot_inst_set, + Field_m_Slot_inst_set, + Field_n_Slot_inst_set, + Field_offset_Slot_inst_set, + Field_op0_Slot_inst_set, + Field_op1_Slot_inst_set, + Field_op2_Slot_inst_set, + Field_r_Slot_inst_set, + Field_sa4_Slot_inst_set, + Field_sae4_Slot_inst_set, + Field_sae_Slot_inst_set, + Field_sal_Slot_inst_set, + Field_sargt_Slot_inst_set, + Field_sas4_Slot_inst_set, + Field_sas_Slot_inst_set, + Field_sr_Slot_inst_set, + Field_st_Slot_inst_set, + Field_thi3_Slot_inst_set, + Field_imm4_Slot_inst_set, + Field_mn_Slot_inst_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set +}; + +static xtensa_get_field_fn +Slot_inst16a_get_field_fns[] = { + Field_t_Slot_inst16a_get, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16a_get, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16a_get, + 0, + 0, + Field_r_Slot_inst16a_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16a_get, + Field_st_Slot_inst16a_get, + 0, + Field_imm4_Slot_inst16a_get, + 0, + Field_i_Slot_inst16a_get, + Field_imm6lo_Slot_inst16a_get, + Field_imm6hi_Slot_inst16a_get, + Field_imm7lo_Slot_inst16a_get, + Field_imm7hi_Slot_inst16a_get, + Field_z_Slot_inst16a_get, + Field_imm6_Slot_inst16a_get, + Field_imm7_Slot_inst16a_get, + Implicit_Field_ar0_get, + Implicit_Field_ar4_get, + Implicit_Field_ar8_get, + Implicit_Field_ar12_get +}; + +static xtensa_set_field_fn +Slot_inst16a_set_field_fns[] = { + Field_t_Slot_inst16a_set, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16a_set, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16a_set, + 0, + 0, + Field_r_Slot_inst16a_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16a_set, + Field_st_Slot_inst16a_set, + 0, + Field_imm4_Slot_inst16a_set, + 0, + Field_i_Slot_inst16a_set, + Field_imm6lo_Slot_inst16a_set, + Field_imm6hi_Slot_inst16a_set, + Field_imm7lo_Slot_inst16a_set, + Field_imm7hi_Slot_inst16a_set, + Field_z_Slot_inst16a_set, + Field_imm6_Slot_inst16a_set, + Field_imm7_Slot_inst16a_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set +}; + +static xtensa_get_field_fn +Slot_inst16b_get_field_fns[] = { + Field_t_Slot_inst16b_get, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16b_get, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16b_get, + 0, + 0, + Field_r_Slot_inst16b_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16b_get, + Field_st_Slot_inst16b_get, + 0, + Field_imm4_Slot_inst16b_get, + 0, + Field_i_Slot_inst16b_get, + Field_imm6lo_Slot_inst16b_get, + Field_imm6hi_Slot_inst16b_get, + Field_imm7lo_Slot_inst16b_get, + Field_imm7hi_Slot_inst16b_get, + Field_z_Slot_inst16b_get, + Field_imm6_Slot_inst16b_get, + Field_imm7_Slot_inst16b_get, + Implicit_Field_ar0_get, + Implicit_Field_ar4_get, + Implicit_Field_ar8_get, + Implicit_Field_ar12_get +}; + +static xtensa_set_field_fn +Slot_inst16b_set_field_fns[] = { + Field_t_Slot_inst16b_set, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16b_set, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16b_set, + 0, + 0, + Field_r_Slot_inst16b_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16b_set, + Field_st_Slot_inst16b_set, + 0, + Field_imm4_Slot_inst16b_set, + 0, + Field_i_Slot_inst16b_set, + Field_imm6lo_Slot_inst16b_set, + Field_imm6hi_Slot_inst16b_set, + Field_imm7lo_Slot_inst16b_set, + Field_imm7hi_Slot_inst16b_set, + Field_z_Slot_inst16b_set, + Field_imm6_Slot_inst16b_set, + Field_imm7_Slot_inst16b_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set +}; + +static xtensa_slot_internal slots[] = { + { "Inst", "x24", 0, + Slot_x24_Format_inst_0_get, Slot_x24_Format_inst_0_set, + Slot_inst_get_field_fns, Slot_inst_set_field_fns, + Slot_inst_decode, "nop" }, + { "Inst16a", "x16a", 0, + Slot_x16a_Format_inst16a_0_get, Slot_x16a_Format_inst16a_0_set, + Slot_inst16a_get_field_fns, Slot_inst16a_set_field_fns, + Slot_inst16a_decode, "" }, + { "Inst16b", "x16b", 0, + Slot_x16b_Format_inst16b_0_get, Slot_x16b_Format_inst16b_0_set, + Slot_inst16b_get_field_fns, Slot_inst16b_set_field_fns, + Slot_inst16b_decode, "nop.n" } +}; + + +/* Instruction formats. */ + +static void +Format_x24_encode (xtensa_insnbuf insn) +{ + insn[0] = 0; +} + +static void +Format_x16a_encode (xtensa_insnbuf insn) +{ + insn[0] = 0x800000; } -int -interface_version (void) +static void +Format_x16b_encode (xtensa_insnbuf insn) { - return 3; + insn[0] = 0xc00000; } -static struct config_struct config_table[] = { - {"IsaMemoryOrder", "BigEndian"}, - {"PIFReadDataBits", "128"}, - {"PIFWriteDataBits", "128"}, - {"IsaCoprocessorCount", "0"}, - {"IsaUseBooleans", "0"}, - {"IsaUseDensityInstruction", "1"}, - {0, 0} +static int Format_x24_slots[] = { 0 }; + +static int Format_x16a_slots[] = { 1 }; + +static int Format_x16b_slots[] = { 2 }; + +static xtensa_format_internal formats[] = { + { "x24", 3, Format_x24_encode, 1, Format_x24_slots }, + { "x16a", 2, Format_x16a_encode, 1, Format_x16a_slots }, + { "x16b", 2, Format_x16b_encode, 1, Format_x16b_slots } }; -struct config_struct * get_config_table (void); -struct config_struct * -get_config_table (void) +static int +format_decoder (const xtensa_insnbuf insn) { - return config_table; + if ((insn[0] & 0x800000) == 0) + return 0; /* x24 */ + if ((insn[0] & 0xc00000) == 0x800000) + return 1; /* x16a */ + if ((insn[0] & 0xe00000) == 0xc00000) + return 2; /* x16b */ + return -1; } -xtensa_isa_module xtensa_isa_modules[] = { - { get_num_opcodes, get_opcodes, decode_insn, get_config_table }, - { 0, 0, 0, 0 } +static int length_table[16] = { + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -1 +}; + +static int +length_decoder (const char *insn) +{ + int op0 = (insn[0] >> 4) & 0xf; + return length_table[op0]; +} + + +/* Top-level ISA structure. */ + +xtensa_isa_internal xtensa_modules = { + 1 /* big-endian */, + 3 /* insn_size */, 0, + 3, formats, format_decoder, length_decoder, + 3, slots, + 39 /* num_fields */, + 70, operands, + 220, iclasses, + 276, opcodes, 0, + 1, regfiles, + NUM_STATES, states, 0, + NUM_SYSREGS, sysregs, 0, + { MAX_SPECIAL_REG, MAX_USER_REG }, { 0, 0 }, + 0, interfaces, 0, + 0, funcUnits, 0 }; diff --git a/gas/ChangeLog b/gas/ChangeLog index 9778bd03f09..3afe1b4635f 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,433 @@ +2004-10-07 Bob Wilson + + * config/tc-xtensa.c (absolute_literals_supported): New global flag. + (UNREACHABLE_MAX_WIDTH): Define. + (XTENSA_FETCH_WIDTH): Delete. + (cur_vinsn, xtensa_fetch_width, xt_saved_debug_type, past_xtensa_end, + prefer_const16, prefer_l32r): New global variables. + (LIT4_SECTION_NAME): Define. + (lit4_state struct): Add lit4_seg_name and lit4_seg fields. + (XTENSA_PROP_*, GET_XTENSA_PROP_*, SET_XTENSA_PROP_*): Define. + (frag_flags struct): New. + (xtensa_block_info struct): Move from tc-xtensa.h. Add flags field. + (subseg_map struct): Add cur_total_freq and cur_target_freq fields. + (bitfield, bit_is_set, set_bit, clear_bit): Define. + (MAX_FORMATS): Define. + (op_placement_info struct, op_placement_table): New. + (O_pltrel, O_hi16, O_lo16): Define. + (directiveE enum): Rename directive_generics to directive_transform. + Delete directive_relax. Add directive_schedule, + directive_absolute_literals, and directive_last_directive. + (directive_info): Rename "generics" to "transform". Delete "relax". + Add "schedule" and "absolute-literals". + (directive_state): Adjust entries to match changes in directive_info. + (xtensa_relax_statesE, RELAX_IMMED_MAXSTEPS): Move to tc-xtensa.h. + (xtensa_const16_opcode, xtensa_movi_opcode, xtensa_movi_n_opcode, + xtensa_l32r_opcode, xtensa_nop_opcode, xtensa_rsr_lcount_opcode): New. + (xtensa_j_opcode, xtensa_rsr_opcode): Delete. + (align_only_targets, software_a0_b_retw_interlock, + software_avoid_b_j_loop_end, maybe_has_b_j_loop_end, + software_avoid_short_loop, software_avoid_close_loop_end, + software_avoid_all_short_loops, specific_opcode): Delete. + (warn_unaligned_branch_targets): New. + (workaround_a0_b_retw, workaround_b_j_loop_end, workaround_short_loop, + workaround_close_loop_end, workaround_all_short_loops): Default FALSE. + (option_[no_]link_relax, option_[no_]transform, + option_[no_]absolute_literals, option_warn_unaligned_targets, + option_prefer_l32r, option_prefer_const16, option_target_hardware): + New enum values. + (option_[no_]align_only_targets, option_literal_section_name, + option_text_section_name, option_data_section_name, + option_bss_section_name, option_eb, option_el): Delete. + (md_longopts): Add entries for: [no-]transform, [no-]absolute-literals, + warn-unaligned-targets, prefer-l32r, prefer-const16, [no-]link-relax, + and target-hardware. Delete entries for [no-]target-align-only, + literal-section-name, text-section-name, data-section-name, and + bss-section-name. + (md_parse_option): Handle new options and remove old ones. Accept but + ignore [no-]density options. Warn for [no-]generics and [no-]relax + and treat them as [no-]transform. + (md_show_usage): Add new options and remove old ones. + (xtensa_setup_hw_workarounds): New. + (md_pseudo_table): Change "word" entry to use xtensa_elf_cons. Add + "long", "short", "loc" and "frequency" entries. + (use_generics): Rename to ... + (use_transform): ... this function. Add past_xtensa_end check. + (use_longcalls): Add past_xtensa_end check. + (code_density_available, can_relax): Delete. + (do_align_targets): New. + (get_directive): Accept dashes in directive names. Warn about + [no-]generics and [no-]relax directives and treat them as + [no-]transform. + (xtensa_begin_directive): Call md_flush_pending_output only for some + directives. Check for directives inside instruction bundles. Warn + about deprecated ".begin literal" usage. Warn and ignore [no-]density + directives. Handle new directives. Check generating_literals flag + for literal_prefix. + (xtensa_end_directive): Check for directives inside instruction + bundles. Warn and ignore [no-]density directives. Handle new + directives. Call xtensa_set_frag_assembly_state. + (xtensa_loc_directive_seen, xtensa_dwarf2_directive_loc, + xtensa_dwarf2_emit_insn): New. + (xtensa_literal_position): Call md_flush_pending_output. Do not check + use_literal_section flag. + (xtensa_literal_pseudo): Call md_flush_pending_output. Handle absolute + literals. Use xtensa_elf_cons to parse the expression. + (xtensa_literal_prefix): Do not check use_literal_section. Support + ".lit4" sections for absolute literals. Change prefix convention to + replace ".text" (or ".t" in a linkonce section). No need to call + subseg_set. + (xtensa_frequency_pseudo, xtensa_elf_cons, xtensa_elf_suffix): New. + (expression_end): Handle closing braces and colons. + (PLT_SUFFIX, plt_suffix): Delete. + (expression_maybe_register): Use new xtensa-isa.h functions. Use + xtensa_elf_suffix instead of checking for plt suffix, and handle O_lo16 + and O_hi16 expressions as well. + (tokenize_arguments): Handle closing braces and colons. + (parse_arguments): Use new xtensa-isa.h functions. Handle "invisible" + operands and paired register syntax. + (get_invisible_operands): New. + (xg_translate_sysreg_op): Handle new Xtensa LX RSR/WSR/XSR syntax. Use + new xtensa-isa.h functions. + (xtensa_translate_old_userreg_ops, xtensa_translate_zero_immed): New. + (xg_translate_idioms): Check if inside bundle. Use use_transform. + Handle new Xtensa LX RSR/WSR/XSR syntax. Remove code to widen density + instructions. Use xtensa_translate_zero_immed. + (operand_is_immed, operand_is_pcrel_label): Delete. + (get_relaxable_immed): Use new xtensa-isa.h functions. + (get_opcode_from_buf): Add slot parameter. Use new xtensa-isa.h + functions. + (xtensa_print_insn_table, print_vliw_insn): New. + (is_direct_call_opcode): Use new xtensa-isa.h functions. + (is_call_opcode, is_loop_opcode, is_conditional_branch_opcode, + is_branch_or_jump_opcode): Delete. + (is_movi_opcode, decode_reloc, encode_reloc, encode_alt_reloc): New. + (opnum_to_reloc, reloc_to_opnum): Delete. + (xtensa_insnbuf_set_operand, xtensa_insnbuf_get_operand): Use new + xtensa-isa.h functions. Operate on one slot of an instruction. + (xtensa_insnbuf_set_immediate_field, is_negatable_branch, + xg_get_insn_size): Delete. + (xg_get_build_instr_size): Use xg_get_single_size. + (xg_is_narrow_insn, xg_is_single_relaxable_insn): Update calls to + xg_build_widen_table. Use xg_get_single_size. + (xg_get_max_narrow_insn_size): Delete. + (xg_get_max_insn_widen_size, xg_get_max_insn_widen_literal_size, + xg_is_relaxable_insn): Update calls to xg_build_widen_table. Use + xg_get_single_size. + (xg_build_to_insn): Record the loc field. Handle OP_OPERAND_HI16U and + OP_OPERAND_LOW16U. Check xg_valid_literal_expression. + (xg_expand_to_stack, xg_expand_narrow): Update calls to + xg_build_widen_table. Use xg_get_single_size. + (xg_immeds_fit): Use new xtensa-isa.h functions. Update call to + xg_check_operand. + (xg_symbolic_immeds_fit): Likewise. Also handle O_lo16 and O_hi16, and + treat weak symbols conservatively. + (xg_check_operand): Use new xtensa-isa.h functions. + (is_dnrange): Delete. + (xg_assembly_relax): Inline previous calls to tinsn_copy. + (xg_finish_frag): Specify separate relax states for the frag and slot0. + (is_branch_jmp_to_next, xg_add_branch_and_loop_targets): Use new + xtensa-isa.h functions. + (xg_instruction_matches_option_term, xg_instruction_matches_or_options, + xg_instruction_matches_options): New. + (xg_instruction_matches_rule): Handle O_register expressions. Call + xg_instruction_matches_options. + (transition_rule_cmp): New. + (xg_instruction_match): Update call to xg_build_simplify_table. + (xg_build_token_insn): Record loc fields. + (xg_simplify_insn): Check is_specific_opcode field and + density_supported flag. + (xg_expand_assembly_insn): Skip checking code_density_available. Use + new xtensa-isa.h functions. Call use_transform instead of can_relax. + (xg_assemble_literal): Add error handling for O_big. Call + record_alignment. Handle O_pltrel. + (xg_valid_literal_expression): New. + (xg_assemble_literal_space): Add slot parameter. Remove call to + set_expr_symbol_offset. Add call to record_alignment. Update call to + xg_finish_frag. + (xg_emit_insn): Delete. + (xg_emit_insn_to_buf): Add format parameter. Update calls to + xg_add_opcode_fix and xtensa_insnbuf_to_chars. + (xg_add_opcode_fix): Change opcode parameter to tinsn and add format + and slot parameters. Handle new "alternate" relocations for absolute + literals and CONST16 instructions. Check for bad uses of O_lo16 and + O_hi16. Use new xtensa-isa.h functions. + (xg_assemble_tokens): Delete. + (is_register_writer): Use new xtensa-isa.h functions. + (is_bad_loopend_opcode): Check for xtensa_rsr_lcount_opcode instead of + old-style RSR from LCOUNT. + (next_frag_opcode): Delete. + (next_frag_opcode_is_loop, next_frag_format_size, frag_format_size, + update_next_frag_state): New. + (update_next_frag_nop_state): Delete. + (next_frag_pre_opcode_bytes): Use next_frag_opcode_is_loop. + (xtensa_mark_literal_pool_location): Check use_literal_section flag and + the state of the absolute-literals directive. Add calls to + record_alignment and xtensa_set_frag_assembly_state. Call + xtensa_switch_to_non_abs_literal_fragment instead of + xtensa_switch_to_literal_fragment. + (build_nop): New. + (assemble_nop): Use build_nop. Update call to xtensa_insnbuf_to_chars. + (get_expanded_loop_offset): Change check for undefined opcode to an + assertion. + (xtensa_set_frag_assembly_state, relaxable_section, + xtensa_find_unmarked_state_frags, xtensa_find_unaligned_branch_targets, + xtensa_find_unaligned_loops, xg_apply_tentative_value): New. + (md_begin): Update call to xtensa_isa_init. Initialize linkrelax to 1. + Set lit4_seg_name. Call xg_init_vinsn. Initialize new global opcodes. + Call init_op_placement_info_table and xtensa_set_frag_assembly_state. + (xtensa_init_fix_data): New. + (xtensa_frob_label): Reset label symbol to the current frag. Check + do_align_targets and generating_literals flag. Propagate frequency + info to new alignment frag. Call xtensa_set_frag_assembly_state. + (xtensa_unrecognized_line): New. + (xtensa_flush_pending_output): Check if inside a bundle. Add a call + to xtensa_set_frag_assembly_state. + (error_reset_cur_vinsn): New. + (md_assemble): Remove check for literal frag. Remove call to + istack_init. Call use_transform instead of use_generics. Parse + explicit instruction format specifiers. Move code for + a0_b_retw_interlock workaround to xg_assemble_vliw_tokens. Call + error_reset_cur_vinsn on errors. Add call to get_invisible_operands. + Add dwarf2_where call. Remote automatic alignment for ENTRY + instructions. Move call to xtensa_clear_insn_labels to the end. + Rearrange to handle bundles. + (xtensa_cons_fix_new): Delete. + (xtensa_handle_align): New. + (xtensa_frag_init): Call xtensa_set_frag_assembly_state. Remove + assignment to is_no_density field. + (md_pcrel_from): Use new xtensa-isa.h functions. Use decode_reloc + instead of reloc_to_opnum. Handle "alternate" relocations. + (xtensa_force_relocation, xtensa_check_inside_bundle, + xtensa_elf_section_change_hook): New. + (xtensa_symbol_new_hook): Delete. + (xtensa_fix_adjustable): Check for difference of symbols with an + offset. Check for external and weak symbols. + (md_apply_fix3): Remove cases for XTENSA_OP{0,1,2} relocs. + (md_estimate_size_before_relax): Return expansion for the first slot. + (tc_gen_reloc): Handle difference of symbols by producing + XTENSA_DIFF{8,16,32} relocs and by writing the value of the difference + into the output. Handle new XTENSA_SLOT*_OP relocs by storing the + tentative values into the output when linkrelax is set. + (XTENSA_PROP_SEC_NAME): Define. + (xtensa_post_relax_hook): Call xtensa_find_unmarked_state_frags. + Create literal tables only if using literal sections. Create new + property tables instead of old instruction tables. Check for unaligned + branch targets and loops. + (finish_vinsn, find_vinsn_conflicts, check_t1_t2_reads_and_writes, + new_resource_table, clear_resource_table, resize_resource_table, + resources_available, reserve_resources, release_resources, + opcode_funcUnit_use_unit, opcode_funcUnit_use_stage, + resources_conflict, xg_find_narrowest_format, relaxation_requirements, + bundle_single_op, emit_single_op, xg_assemble_vliw_tokens): New. + (xtensa_end): Call xtensa_flush_pending_output. Set past_xtensa_end + flag. Update checks for workaround options. Call + xtensa_mark_narrow_branches and xtensa_mark_zcl_first_insns. + (xtensa_cleanup_align_frags): Add special case for branch targets. + Check for and mark unreachable frags. + (xtensa_fix_target_frags): Remove use of align_only_targets flag. + Use RELAX_LOOP_END_BYTES in special case for negatable branch at the + end of a zero-overhead loop body. + (frag_can_negate_branch): Handle instructions with multiple slots. + Use new xtensa-isa.h functions + (xtensa_mark_narrow_branches, is_narrow_branch_guaranteed_in_range, + xtensa_mark_zcl_first_insns): New. + (xtensa_fix_a0_b_retw_frags, xtensa_fix_b_j_loop_end_frags): Error if + transformations are disabled. + (next_instrs_are_b_retw): Use new xtensa-isa.h functions. Handle + multislot instructions. + (xtensa_fix_close_loop_end_frags, xtensa_fix_short_loop_frags): + Likewise. Also error if transformations are disabled. + (unrelaxed_frag_max_size): New. + (unrelaxed_frag_min_insn_count, unrelax_frag_has_b_j): Use new + xtensa-isa.h functions. + (xtensa_sanity_check, is_empty_loop, is_local_forward_loop): Use + xtensa_opcode_is_loop instead of is_loop_opcode. + (get_text_align_power): Replace as_fatal with assertion. + (get_text_align_fill_size): Iterate instead of using modulus when + use_nops is false. + (get_noop_aligned_address): Assert that this is for a machine-dependent + RELAX_ALIGN_NEXT_OPCODE frag. Use next_frag_opcode_is_loop, + xg_get_single_size, and frag_format_size. + (get_widen_aligned_address): Rename to ... + (get_aligned_diff): ... this function. Add max_diff parameter. + Remove handling of rs_align/rs_align_code frags. Use + next_frag_format_size, get_text_align_power, get_text_align_fill_size, + next_frag_opcode_is_loop, and xg_get_single_size. Compute max_diff + and pass it back to caller. + (xtensa_relax_frag): Use relax_frag_loop_align. Add code for new + RELAX_SLOTS, RELAX_MAYBE_UNREACHABLE, RELAX_MAYBE_DESIRE_ALIGN, + RELAX_FILL_NOP, and RELAX_UNREACHABLE frag types. Check relax_seen. + (relax_frag_text_align): Rename to ... + (relax_frag_loop_align): ... this function. Assume loops can only be + in the first slot of an instruction. + (relax_frag_add_nop): Use assemble_nop instead of constructing an OR + instruction. Remove call to frag_wane. + (relax_frag_narrow): Rename to ... + (relax_frag_for_align): ... this function. Extend to handle + RELAX_FILL_NOP and RELAX_UNREACHABLE, as well as RELAX_SLOTS with + RELAX_NARROW for the first slot. + (find_address_of_next_align_frag, bytes_to_stretch): New. + (future_alignment_required): Use find_address_of_next_align_frag and + bytes_to_stretch. Look ahead to subsequent frags to make smarter + alignment decisions. + (relax_frag_immed): Add format, slot, and estimate_only parameters. + Check if transformations are enabled for b_j_loop_end workaround. + Use new xtensa-isa.h functions and handle multislot instructions. + Update call to xg_assembly_relax. + (md_convert_frag): Handle new RELAX_SLOTS, RELAX_UNREACHABLE, + RELAX_MAYBE_UNREACHABLE, RELAX_MAYBE_DESIRE_ALIGN, and RELAX_FILL_NOP + frag types. + (convert_frag_narrow): Add segP, format and slot parameters. Call + convert_frag_immed for branch instructions. Adjust calls to + tinsn_from_chars, tinsn_immed_from_frag, and xg_emit_insn_to_buf. Use + xg_get_single_size and xg_get_single_format. + (convert_frag_fill_nop): New. + (convert_frag_immed): Add format and slot parameters. Handle multislot + instructions and use new xtensa-isa.h functions. Update calls to + tinsn_immed_from_frag and xg_assembly_relax. Check if transformations + enabled for b_j_loop_end workaround. Use build_nop instead of + assemble_nop. Check is_specific_opcode flag. Check for unreachable + frags. Use xg_get_single_size. Handle O_pltrel. + (fix_new_exp_in_seg): Remove check for old plt flag. + (convert_frag_immed_finish_loop): Update calls to tinsn_from_chars and + xtensa_insnbuf_to_chars. Call tinsn_immed_from_frag. Change check + for loop opcode to an assertion. Mark all frags up to the end of the + loop as not transformable. + (get_last_insn_flags, set_last_insn_flags): Use get_subseg_info. + (get_subseg_info): New. + (xtensa_move_literals): Call xtensa_set_frag_assembly_state. Add null + check for dest_seg. + (xtensa_switch_to_literal_fragment): Rewrite to handle absolute + literals and use xtensa_switch_to_non_abs_literal_fragment otherwise. + (xtensa_switch_to_non_abs_literal_fragment): New. + (cache_literal_section): Add is_code parameter and pass it through to + retrieve_literal_seg. + (retrieve_literal_seg): Add is_code parameter and use it to set the + flags on the literal section. Handle case where head parameter is 0. + (get_frag_is_no_transform, set_frag_is_specific_opcode, + set_frag_is_no_transform): New. + (xtensa_create_property_segments): Add end_property_function parameter + and pass it through to add_xt_block_frags. Call bfd_get_section_flags + and skip SEC_DEBUGGING and !SEC_ALLOC sections. + (xtensa_create_xproperty_segments, section_has_xproperty): New. + (add_xt_block_frags): Add end_property_function parameter and call it + if it is non-zero. Call xtensa_frag_flags_init. + (xtensa_frag_flags_is_empty, xtensa_frag_flags_init, + get_frag_property_flags, frag_flags_to_number, + xtensa_frag_flags_combinable, xt_block_aligned_size, + xtensa_xt_block_combine, add_xt_prop_frags, + init_op_placement_info_table, opcode_fits_format_slot, + xg_get_single_size, xg_get_single_format): New. + (istack_push): Inline call to tinsn_copy. + (tinsn_copy): Delete. + (tinsn_has_invalid_symbolic_operands): Handle O_hi16 and O_lo16 and + CONST16 opcodes. Handle O_big, O_illegal, and O_absent. + (tinsn_has_complex_operands): Handle O_hi16 and O_lo16. + (tinsn_to_insnbuf): Use xg_get_single_format and new xtensa-isa.h + functions. Handle invisible operands. + (tinsn_to_slotbuf): New. + (tinsn_check_arguments): Use new xtensa-isa.h functions. + (tinsn_from_chars): Add slot parameter. Rewrite using xg_init_vinsn, + vinsn_from_chars, and xg_free_vinsn. + (tinsn_from_insnbuf): New. + (tinsn_immed_from_frag): Add slot parameter and handle multislot + instructions. Handle symbol differences. + (get_num_stack_text_bytes): Use xg_get_single_size. + (xg_init_vinsn, xg_clear_vinsn, vinsn_has_specific_opcodes, + xg_free_vinsn, vinsn_to_insnbuf, vinsn_from_chars, expr_is_register, + get_expr_register, set_expr_symbol_offset_diff): New. + * config/tc-xtensa.h (MAX_SLOTS): Define. + (xtensa_relax_statesE): Move from tc-xtensa.c. Add + RELAX_CHECK_ALIGN_NEXT_OPCODE, RELAX_MAYBE_DESIRE_ALIGN, RELAX_SLOTS, + RELAX_FILL_NOP, RELAX_UNREACHABLE, RELAX_MAYBE_UNREACHABLE, and + RELAX_NONE types. + (RELAX_IMMED_MAXSTEPS): Move from tc-xtensa.c. + (xtensa_frag_type struct): Add is_assembly_state_set, + use_absolute_literals, relax_seen, is_unreachable, is_specific_opcode, + is_align, is_text_align, alignment, and is_first_loop_insn fields. + Replace is_generics and is_relax fields by is_no_transform field. + Delete is_text and is_longcalls fields. Change text_expansion and + literal_expansion to arrays of MAX_SLOTS entries. Add arrays of + per-slot information: literal_frags, slot_subtypes, slot_symbols, + slot_sub_symbols, and slot_offsets. Add fr_prev field. + (xtensa_fix_data struct): New. + (xtensa_symfield_type struct): Delete plt field. + (xtensa_block_info struct): Move definition to tc-xtensa.h. Add + forward declaration here. + (xt_section_type enum): Delete xt_insn_sec. Add xt_prop_sec. + (XTENSA_SECTION_RENAME): Undefine. + (TC_FIX_TYPE, TC_INIT_FIX_DATA, TC_FORCE_RELOCATION, NO_PSEUDO_DOT, + tc_unrecognized_line, md_do_align, md_elf_section_change_hook, + HANDLE_ALIGN, TC_LINKRELAX_FIXUP, SUB_SEGMENT_ALIGN): Define. + (TC_CONS_FIX_NEW, tc_symbol_new_hook): Delete. + (unit_num_copies_func, opcode_num_units_func, + opcode_funcUnit_use_unit_func, opcode_funcUnit_use_stage_func): New. + (resource_table struct): New. + * config/xtensa-istack.h (MAX_INSN_ARGS): Increase from 6 to 10. + (TInsn struct): Add keep_wide, loc, fixup, record_fix, subtype, + literal_space, symbol, sub_symbol, offset, and literal_frag fields. + (tinsn_copy): Delete prototype. + (vliw_insn struct): New. + * config/xtensa-relax.c (insn_pattern_struct): Add options field. + (widen_spec_list): Add option conditions for density and boolean + instructions. Add expansions using CONST16 and conditions for using + CONST16 vs. L32R. Use new Xtensa LX RSR/WSR syntax. Add entries for + predicted branches. + (simplify_spec_list): Add option conditions for density instructions. + Add entry for NOP instruction. + (append_transition): Add cmp function pointer parameter and use it to + insert the new entry in order. + (operand_function_LOW16U, operand_function_HI16U): New. + (xg_has_userdef_op_fn, xg_apply_userdef_op_fn): Handle + OP_OPERAND_LOW16U and OP_OPERAND_HI16U. + (enter_opname, split_string): Use xstrdup instead of strdup. + (init_insn_pattern): Initialize new options field. + (clear_req_or_option_list, clear_req_option_list, + clone_req_or_option_list, clone_req_option_list, parse_option_cond): + New. + (parse_insn_pattern): Parse option conditions. + (transition_applies): New. + (build_transition): Use new xtensa-isa.h functions. Fix incorrectly + swapped last arguments in calls to append_constant_value_condition. + Call clone_req_option_list. Add warning about invalid opcode. + Handle LOW16U and HI16U function names. + (build_transition_table): Add cmp parameter and use it in calls to + append_transition. Use new xtensa-isa.h functions. Check + transition_applies before adding entries. + (xg_build_widen_table, xg_build_simplify_table): Add cmp parameter and + pass it through to build_transition_table. + * config/xtensa-relax.h (ReqOrOptionList, ReqOrOption, ReqOptionList, + ReqOption, transition_cmp_fn): New types. + (OpType enum): Add OP_OPERAND_LOW16U and OP_OPERAND_HI16U. + (transition_rule struct): Add options field. + * doc/as.texinfo (Overview): Update Xtensa options. + * doc/c-xtensa.texi (Xtensa Options): Delete --[no-]density, + --[no-]relax, and --[no-]generics options. Update descriptions of + --text-section-literals and --[no-]longcalls. Add + --[no-]absolute-literals and --[no-]transform. + (Xtensa Syntax): Add description of syntax for FLIX instructions. + Remove use of "generic" and "specific" terminology for opcodes. + (Xtensa Registers): Generalize the syntax description to include + user-defined register files. + (Xtensa Automatic Alignment): Update. + (Xtensa Branch Relaxation): Mention limitation of unconditional jumps. + (Xtensa Call Relaxation): Linker can now remove most of the overhead. + (Xtensa Directives): Remove confusing rules about precedence. + (Density Directive, Relax Directive): Delete. + (Schedule Directive): New. + (Generics Directive): Rename to ... + (Transform Directive): ... this node. + (Literal Directive): Update for absolute literals. Missing + literal_position directive is now an error. + (Literal Position Directive): Update for absolute literals. + (Freeregs Directive): Delete. + (Absolute Literals Directive): New. + (Frame Directive): Minor editing. + * Makefile.am (DEPTC_xtensa_elf, DEPOBJ_xtensa_elf, DEP_xtensa_elf): + Update dependencies. + * Makefile.in: Regenerate. + 2004-10-07 Richard Sandiford * config/tc-mips.c (append_insn): Use fix_new rather than fix_new_exp diff --git a/gas/Makefile.am b/gas/Makefile.am index e00c6235d77..bf77d459d21 100644 --- a/gas/Makefile.am +++ b/gas/Makefile.am @@ -1552,9 +1552,9 @@ DEPTC_xstormy16_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \ DEPTC_xtensa_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \ $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-xtensa.h \ - $(INCDIR)/xtensa-config.h sb.h $(INCDIR)/safe-ctype.h \ - subsegs.h $(INCDIR)/obstack.h $(srcdir)/config/xtensa-relax.h \ - $(INCDIR)/xtensa-isa.h $(srcdir)/config/xtensa-istack.h \ + $(INCDIR)/xtensa-isa.h $(INCDIR)/xtensa-config.h sb.h \ + $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \ + $(srcdir)/config/xtensa-relax.h $(srcdir)/config/xtensa-istack.h \ dwarf2dbg.h struc-symbol.h DEPTC_z8k_coff = $(INCDIR)/symcat.h $(srcdir)/config/obj-coff.h \ $(srcdir)/config/tc-z8k.h $(INCDIR)/coff/internal.h \ @@ -2074,8 +2074,9 @@ DEPOBJ_xstormy16_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \ DEPOBJ_xtensa_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \ $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-xtensa.h \ - $(INCDIR)/xtensa-config.h $(INCDIR)/safe-ctype.h subsegs.h \ - $(INCDIR)/obstack.h struc-symbol.h dwarf2dbg.h $(INCDIR)/aout/aout64.h + $(INCDIR)/xtensa-isa.h $(INCDIR)/xtensa-config.h $(INCDIR)/safe-ctype.h \ + subsegs.h $(INCDIR)/obstack.h struc-symbol.h dwarf2dbg.h \ + $(INCDIR)/aout/aout64.h DEPOBJ_z8k_coff = $(INCDIR)/symcat.h $(srcdir)/config/obj-coff.h \ $(srcdir)/config/tc-z8k.h $(INCDIR)/coff/internal.h \ $(INCDIR)/coff/z8k.h $(INCDIR)/coff/external.h $(BFDDIR)/libcoff.h \ @@ -2423,7 +2424,7 @@ DEP_xstormy16_elf = $(srcdir)/config/obj-elf.h $(INCDIR)/symcat.h \ DEP_xtensa_elf = $(srcdir)/config/obj-elf.h $(INCDIR)/symcat.h \ $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-xtensa.h \ - $(INCDIR)/xtensa-config.h + $(INCDIR)/xtensa-isa.h $(INCDIR)/xtensa-config.h DEP_z8k_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-z8k.h \ $(INCDIR)/symcat.h $(INCDIR)/coff/internal.h $(INCDIR)/coff/z8k.h \ $(INCDIR)/coff/external.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h diff --git a/gas/Makefile.in b/gas/Makefile.in index e8700a20b47..ad488bee98b 100644 --- a/gas/Makefile.in +++ b/gas/Makefile.in @@ -1443,9 +1443,9 @@ DEPTC_xstormy16_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \ DEPTC_xtensa_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \ $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-xtensa.h \ - $(INCDIR)/xtensa-config.h sb.h $(INCDIR)/safe-ctype.h \ - subsegs.h $(INCDIR)/obstack.h $(srcdir)/config/xtensa-relax.h \ - $(INCDIR)/xtensa-isa.h $(srcdir)/config/xtensa-istack.h \ + $(INCDIR)/xtensa-isa.h $(INCDIR)/xtensa-config.h sb.h \ + $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \ + $(srcdir)/config/xtensa-relax.h $(srcdir)/config/xtensa-istack.h \ dwarf2dbg.h struc-symbol.h DEPTC_z8k_coff = $(INCDIR)/symcat.h $(srcdir)/config/obj-coff.h \ @@ -2084,8 +2084,9 @@ DEPOBJ_xstormy16_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \ DEPOBJ_xtensa_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \ $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-xtensa.h \ - $(INCDIR)/xtensa-config.h $(INCDIR)/safe-ctype.h subsegs.h \ - $(INCDIR)/obstack.h struc-symbol.h dwarf2dbg.h $(INCDIR)/aout/aout64.h + $(INCDIR)/xtensa-isa.h $(INCDIR)/xtensa-config.h $(INCDIR)/safe-ctype.h \ + subsegs.h $(INCDIR)/obstack.h struc-symbol.h dwarf2dbg.h \ + $(INCDIR)/aout/aout64.h DEPOBJ_z8k_coff = $(INCDIR)/symcat.h $(srcdir)/config/obj-coff.h \ $(srcdir)/config/tc-z8k.h $(INCDIR)/coff/internal.h \ @@ -2550,7 +2551,7 @@ DEP_xstormy16_elf = $(srcdir)/config/obj-elf.h $(INCDIR)/symcat.h \ DEP_xtensa_elf = $(srcdir)/config/obj-elf.h $(INCDIR)/symcat.h \ $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-xtensa.h \ - $(INCDIR)/xtensa-config.h + $(INCDIR)/xtensa-isa.h $(INCDIR)/xtensa-config.h DEP_z8k_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-z8k.h \ $(INCDIR)/symcat.h $(INCDIR)/coff/internal.h $(INCDIR)/coff/z8k.h \ diff --git a/gas/config/tc-xtensa.c b/gas/config/tc-xtensa.c index 5d5ccea5dac..ab626a4b015 100644 --- a/gas/config/tc-xtensa.c +++ b/gas/config/tc-xtensa.c @@ -1,5 +1,5 @@ /* tc-xtensa.c -- Assemble Xtensa instructions. - Copyright 2003 Free Software Foundation, Inc. + Copyright 2003, 2004 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -15,10 +15,11 @@ You should have received a copy of the GNU General Public License along with GAS; see the file COPYING. If not, write to - the Free Software Foundation, 59 Temple Place - Suite 330, Boston, + the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include +#include #include "as.h" #include "sb.h" #include "safe-ctype.h" @@ -40,13 +41,6 @@ /* Notes: - There are 3 forms for instructions, - 1) the MEMORY format -- this is the encoding 2 or 3 byte instruction - 2) the TInsn -- handles instructions/labels and literals; - all operands are assumed to be expressions - 3) the IStack -- a stack of TInsn. this allows us to - reason about the generated expansion instructions - Naming conventions (used somewhat inconsistently): The xtensa_ functions are exported The xg_ functions are internal @@ -71,17 +65,26 @@ const char EXP_CHARS[] = "eE"; const char FLT_CHARS[] = "rRsSfFdDxXpP"; -/* Flag to indicate whether the hardware supports the density option. - If not, enabling density instructions (via directives or --density flag) - is illegal. */ +/* Flags to indicate whether the hardware supports the density and + absolute literals options. */ -#if STATIC_LIBISA bfd_boolean density_supported = XCHAL_HAVE_DENSITY; -#else -bfd_boolean density_supported = TRUE; -#endif +bfd_boolean absolute_literals_supported = XSHAL_USE_ABSOLUTE_LITERALS; + +/* Maximum width we would pad an unreachable frag to get alignment. */ +#define UNREACHABLE_MAX_WIDTH 8 -#define XTENSA_FETCH_WIDTH 4 +static void error_reset_cur_vinsn PARAMS ((void)); +static vliw_insn cur_vinsn; + +size_t xtensa_fetch_width = XCHAL_INST_FETCH_WIDTH; + +static enum debug_info_type xt_saved_debug_type = DEBUG_NONE; + +/* Some functions are only valid in the front end. This variable + allows us to assert that we haven't crossed over into the + back end. */ +static bfd_boolean past_xtensa_end = FALSE; /* Flags for properties of the last instruction in a segment. */ #define FLAG_IS_A0_WRITER 0x1 @@ -94,21 +97,24 @@ bfd_boolean density_supported = TRUE; their own special .fini.literal and .init.literal sections. */ #define LITERAL_SECTION_NAME xtensa_section_rename (".literal") +#define LIT4_SECTION_NAME xtensa_section_rename (".lit4") #define FINI_SECTION_NAME xtensa_section_rename (".fini") #define INIT_SECTION_NAME xtensa_section_rename (".init") #define FINI_LITERAL_SECTION_NAME xtensa_section_rename (".fini.literal") #define INIT_LITERAL_SECTION_NAME xtensa_section_rename (".init.literal") -/* This type is used for the directive_stack to keep track of the +/* This type is used for the directive_stack to keep track of the state of the literal collection pools. */ typedef struct lit_state_struct { const char *lit_seg_name; + const char *lit4_seg_name; const char *init_lit_seg_name; const char *fini_lit_seg_name; segT lit_seg; + segT lit4_seg; segT init_lit_seg; segT fini_lit_seg; } lit_state; @@ -153,9 +159,145 @@ static sym_list *saved_insn_labels = NULL; static sym_list *literal_syms; +/* Flags to determine whether to prefer const16 or l32r + if both options are available. */ +int prefer_const16 = 0; +int prefer_l32r = 0; + /* Global flag to indicate when we are emitting literals. */ int generating_literals = 0; +/* The following PROPERTY table definitions are copied from + and must be kept in sync with the code there. */ + +/* Flags in the property tables to specify whether blocks of memory + are literals, instructions, data, or unreachable. For + instructions, blocks that begin loop targets and branch targets are + designated. Blocks that do not allow density, instruction + reordering or transformation are also specified. Finally, for + branch targets, branch target alignment priority is included. + Alignment of the next block is specified in the current block + and the size of the current block does not include any fill required + to align to the next block. */ + +#define XTENSA_PROP_LITERAL 0x00000001 +#define XTENSA_PROP_INSN 0x00000002 +#define XTENSA_PROP_DATA 0x00000004 +#define XTENSA_PROP_UNREACHABLE 0x00000008 +/* Instruction only properties at beginning of code. */ +#define XTENSA_PROP_INSN_LOOP_TARGET 0x00000010 +#define XTENSA_PROP_INSN_BRANCH_TARGET 0x00000020 +/* Instruction only properties about code. */ +#define XTENSA_PROP_INSN_NO_DENSITY 0x00000040 +#define XTENSA_PROP_INSN_NO_REORDER 0x00000080 +#define XTENSA_PROP_INSN_NO_TRANSFORM 0x00000100 + +/* Branch target alignment information. This transmits information + to the linker optimization about the priority of aligning a + particular block for branch target alignment: None, low priority, + high priority, or required. These only need to be checked in + instruction blocks marked as XTENSA_PROP_INSN_BRANCH_TARGET. + Common usage is + + switch (GET_XTENSA_PROP_BT_ALIGN (flags)) + case XTENSA_PROP_BT_ALIGN_NONE: + case XTENSA_PROP_BT_ALIGN_LOW: + case XTENSA_PROP_BT_ALIGN_HIGH: + case XTENSA_PROP_BT_ALIGN_REQUIRE: +*/ +#define XTENSA_PROP_BT_ALIGN_MASK 0x00000600 + +/* No branch target alignment. */ +#define XTENSA_PROP_BT_ALIGN_NONE 0x0 +/* Low priority branch target alignment. */ +#define XTENSA_PROP_BT_ALIGN_LOW 0x1 +/* High priority branch target alignment. */ +#define XTENSA_PROP_BT_ALIGN_HIGH 0x2 +/* Required branch target alignment. */ +#define XTENSA_PROP_BT_ALIGN_REQUIRE 0x3 + +#define GET_XTENSA_PROP_BT_ALIGN(flag) \ + (((unsigned) ((flag) & (XTENSA_PROP_BT_ALIGN_MASK))) >> 9) +#define SET_XTENSA_PROP_BT_ALIGN(flag, align) \ + (((flag) & (~XTENSA_PROP_BT_ALIGN_MASK)) | \ + (((align) << 9) & XTENSA_PROP_BT_ALIGN_MASK)) + + +/* Alignment is specified in the block BEFORE the one that needs + alignment. Up to 5 bits. Use GET_XTENSA_PROP_ALIGNMENT(flags) to + get the required alignment specified as a power of 2. Use + SET_XTENSA_PROP_ALIGNMENT(flags, pow2) to set the required + alignment. Be careful of side effects since the SET will evaluate + flags twice. Also, note that the SIZE of a block in the property + table does not include the alignment size, so the alignment fill + must be calculated to determine if two blocks are contiguous. + TEXT_ALIGN is not currently implemented but is a placeholder for a + possible future implementation. */ + +#define XTENSA_PROP_ALIGN 0x00000800 + +#define XTENSA_PROP_ALIGNMENT_MASK 0x0001f000 + +#define GET_XTENSA_PROP_ALIGNMENT(flag) \ + (((unsigned) ((flag) & (XTENSA_PROP_ALIGNMENT_MASK))) >> 12) +#define SET_XTENSA_PROP_ALIGNMENT(flag, align) \ + (((flag) & (~XTENSA_PROP_ALIGNMENT_MASK)) | \ + (((align) << 12) & XTENSA_PROP_ALIGNMENT_MASK)) + +#define XTENSA_PROP_INSN_ABSLIT 0x00020000 + + +/* Structure for saving instruction and alignment per-fragment data + that will be written to the object file. This structure is + equivalent to the actual data that will be written out to the file + but is easier to use. We provide a conversion to file flags + in frag_flags_to_number. */ + +typedef struct frag_flags_struct frag_flags; + +struct frag_flags_struct +{ + /* is_literal should only be used after xtensa_move_literals. + If you need to check if you are generating a literal fragment, + then use the generating_literals global. */ + + unsigned is_literal : 1; + unsigned is_insn : 1; + unsigned is_data : 1; + unsigned is_unreachable : 1; + + struct + { + unsigned is_loop_target : 1; + unsigned is_branch_target : 1; /* Branch targets have a priority. */ + unsigned bt_align_priority : 2; + + unsigned is_no_density : 1; + /* no_longcalls flag does not need to be placed in the object file. */ + /* is_specific_opcode implies no_transform. */ + unsigned is_no_transform : 1; + + unsigned is_no_reorder : 1; + + /* Uses absolute literal addressing for l32r. */ + unsigned is_abslit : 1; + } insn; + unsigned is_align : 1; + unsigned alignment : 5; +}; + + +/* Structure for saving information about a block of property data + for frags that have the same flags. */ +struct xtensa_block_info_struct +{ + segT sec; + bfd_vma offset; + size_t size; + frag_flags flags; + struct xtensa_block_info_struct *next; +}; + /* Structure for saving the current state before emitting literals. */ typedef struct emit_state_struct @@ -167,6 +309,82 @@ typedef struct emit_state_struct } emit_state; +/* A map that keeps information on a per-subsegment basis. This is + maintained during initial assembly, but is invalid once the + subsegments are smashed together. I.E., it cannot be used during + the relaxation. */ + +typedef struct subseg_map_struct +{ + /* the key */ + segT seg; + subsegT subseg; + + /* the data */ + unsigned flags; + /* the fall-through frequency + the branch target frequency + typically used for the instruction after a call */ + float cur_total_freq; + /* the branch target frequency alone */ + float cur_target_freq; + + struct subseg_map_struct *next; +} subseg_map; + + +/* Opcode placement information */ + +typedef unsigned long long bitfield; +#define bit_is_set(bit, bf) ((bf) & (0x01ll << (bit))) +#define set_bit(bit, bf) ((bf) |= (0x01ll << (bit))) +#define clear_bit(bit, bf) ((bf) &= ~(0x01ll << (bit))) + +#define MAX_FORMATS 32 + +typedef struct op_placement_info_struct +{ + int num_formats; + /* A number describing how restrictive the issue is for this + opcode. For example, an opcode that fits lots of different + formats has a high freedom, as does an opcode that fits + only one format but many slots in that format. The most + restrictive is the opcode that fits only one slot in one + format. */ + int issuef; + /* The single format (i.e., if the op can live in a bundle by itself), + narrowest format, and widest format the op can be bundled in + and their sizes: */ + xtensa_format single; + xtensa_format narrowest; + xtensa_format widest; + char narrowest_size; + char widest_size; + char single_size; + + /* formats is a bitfield with the Nth bit set + if the opcode fits in the Nth xtensa_format. */ + bitfield formats; + + /* slots[N]'s Mth bit is set if the op fits in the + Mth slot of the Nth xtensa_format. */ + bitfield slots[MAX_FORMATS]; + + /* A count of the number of slots in a given format + an op can fit (i.e., the bitcount of the slot field above). */ + char slots_in_format[MAX_FORMATS]; + +} op_placement_info, *op_placement_info_table; + +op_placement_info_table op_placement_table; + + +/* Extra expression types. */ + +#define O_pltrel O_md1 /* like O_symbol but use a PLT reloc */ +#define O_hi16 O_md2 /* use high 16 bits of symbolic value */ +#define O_lo16 O_md3 /* use low 16 bits of symbolic value */ + + /* Directives. */ typedef enum @@ -174,11 +392,13 @@ typedef enum directive_none = 0, directive_literal, directive_density, - directive_generics, - directive_relax, + directive_transform, directive_freeregs, directive_longcalls, - directive_literal_prefix + directive_literal_prefix, + directive_schedule, + directive_absolute_literals, + directive_last_directive } directiveE; typedef struct @@ -189,143 +409,51 @@ typedef struct const directive_infoS directive_info[] = { - {"none", FALSE}, - {"literal", FALSE}, - {"density", TRUE}, - {"generics", TRUE}, - {"relax", TRUE}, - {"freeregs", FALSE}, - {"longcalls", TRUE}, - {"literal_prefix", FALSE} + { "none", FALSE }, + { "literal", FALSE }, + { "density", TRUE }, + { "transform", TRUE }, + { "freeregs", FALSE }, + { "longcalls", TRUE }, + { "literal_prefix", FALSE }, + { "schedule", TRUE }, + { "absolute-literals", TRUE } }; bfd_boolean directive_state[] = { FALSE, /* none */ FALSE, /* literal */ -#if STATIC_LIBISA && !XCHAL_HAVE_DENSITY +#if !XCHAL_HAVE_DENSITY FALSE, /* density */ #else TRUE, /* density */ #endif - TRUE, /* generics */ - TRUE, /* relax */ + TRUE, /* transform */ FALSE, /* freeregs */ FALSE, /* longcalls */ - FALSE /* literal_prefix */ -}; - - -enum xtensa_relax_statesE -{ - RELAX_ALIGN_NEXT_OPCODE, - /* Use the first opcode of the next fragment to determine the - alignment requirements. This is ONLY used for LOOPS - currently. */ - - RELAX_DESIRE_ALIGN_IF_TARGET, - /* These are placed in front of labels. They will all be converted - to RELAX_DESIRE_ALIGN / RELAX_LOOP_END or rs_fill of 0 before - relaxation begins. */ - - RELAX_ADD_NOP_IF_A0_B_RETW, - /* These are placed in front of conditional branches. It will be - turned into a NOP (using a1) if the branch is immediately - followed by a RETW or RETW.N. Otherwise it will be turned into - an rs_fill of 0 before relaxation begins. */ - - RELAX_ADD_NOP_IF_PRE_LOOP_END, - /* These are placed after JX instructions. It will be turned into a - NOP if there is one instruction before a loop end label. - Otherwise it will be turned into an rs_fill of 0 before - relaxation begins. This is used to avoid a hardware TIE - interlock issue prior to T1040. */ - - RELAX_ADD_NOP_IF_SHORT_LOOP, - /* These are placed after LOOP instructions. It will be turned into - a NOP when: (1) there are less than 3 instructions in the loop; - we place 2 of these in a row to add up to 2 NOPS in short loops; - or (2) The instructions in the loop do not include a branch or - jump. Otherwise it will be turned into an rs_fill of 0 before - relaxation begins. This is used to avoid hardware bug - PR3830. */ - - RELAX_ADD_NOP_IF_CLOSE_LOOP_END, - /* These are placed after LOOP instructions. It will be turned into - a NOP if there are less than 12 bytes to the end of some other - loop's end. Otherwise it will be turned into an rs_fill of 0 - before relaxation begins. This is used to avoid hardware bug - PR3830. */ - - RELAX_DESIRE_ALIGN, - /* The next fragment like its first instruction to NOT cross a - 4-byte boundary. */ - - RELAX_LOOP_END, - /* This will be turned into a NOP or NOP.N if the previous - instruction is expanded to negate a loop. */ - - RELAX_LOOP_END_ADD_NOP, - /* When the code density option is available, this will generate a - NOP.N marked RELAX_NARROW. Otherwise, it will create an rs_fill - fragment with a NOP in it. */ - - RELAX_LITERAL, - /* Another fragment could generate an expansion here but has not yet. */ - - RELAX_LITERAL_NR, - /* Expansion has been generated by an instruction that generates a - literal. However, the stretch has NOT been reported yet in this - fragment. */ - - RELAX_LITERAL_FINAL, - /* Expansion has been generated by an instruction that generates a - literal. */ - - RELAX_LITERAL_POOL_BEGIN, - RELAX_LITERAL_POOL_END, - /* Technically these are not relaxations at all, but mark a location - to store literals later. Note that fr_var stores the frchain for - BEGIN frags and fr_var stores now_seg for END frags. */ - - RELAX_NARROW, - /* The last instruction in this fragment (at->fr_opcode) can be - freely replaced with a single wider instruction if a future - alignment desires or needs it. */ - - RELAX_IMMED, - /* The last instruction in this fragment (at->fr_opcode) contains - the value defined by fr_symbol (fr_offset = 0). If the value - does not fit, use the specified expansion. This is similar to - "NARROW", except that these may not be expanded in order to align - code. */ - - RELAX_IMMED_STEP1, - /* The last instruction in this fragment (at->fr_opcode) contains a - literal. It has already been expanded at least 1 step. */ - - RELAX_IMMED_STEP2 - /* The last instruction in this fragment (at->fr_opcode) contains a - literal. It has already been expanded at least 2 steps. */ + FALSE, /* literal_prefix */ + TRUE, /* schedule */ +#if XSHAL_USE_ABSOLUTE_LITERALS + TRUE /* absolute_literals */ +#else + FALSE /* absolute_literals */ +#endif }; -/* This is used as a stopper to bound the number of steps that - can be taken. */ -#define RELAX_IMMED_MAXSTEPS (RELAX_IMMED_STEP2 - RELAX_IMMED) - - typedef bfd_boolean (*frag_predicate) (const fragS *); +typedef void (*frag_flags_fn) (const fragS *, frag_flags *); +/* Command-line option functions. */ +static void xtensa_setup_hw_workarounds PARAMS ((int, int)); /* Directive functions. */ -static bfd_boolean use_generics +static bfd_boolean use_transform PARAMS ((void)); static bfd_boolean use_longcalls PARAMS ((void)); -static bfd_boolean code_density_available - PARAMS ((void)); -static bfd_boolean can_relax +static bfd_boolean do_align_targets PARAMS ((void)); static void directive_push PARAMS ((directiveE, bfd_boolean, const void *)); @@ -342,12 +470,22 @@ static void xtensa_begin_directive PARAMS ((int)); static void xtensa_end_directive PARAMS ((int)); +static void xtensa_dwarf2_directive_loc + PARAMS ((int)); +static void xtensa_dwarf2_emit_insn + PARAMS ((int, struct dwarf2_line_info *)); static void xtensa_literal_prefix PARAMS ((char const *, int)); static void xtensa_literal_position PARAMS ((int)); static void xtensa_literal_pseudo PARAMS ((int)); +static void xtensa_frequency_pseudo + PARAMS ((int)); +static void xtensa_elf_cons + PARAMS ((int)); +static bfd_reloc_code_real_type xtensa_elf_suffix + PARAMS ((char **, expressionS *)); /* Parsing and Idiom Translation Functions. */ @@ -356,15 +494,21 @@ static const char *expression_end static unsigned tc_get_register PARAMS ((const char *)); static void expression_maybe_register - PARAMS ((xtensa_operand, expressionS *)); + PARAMS ((xtensa_opcode, int, expressionS *)); static int tokenize_arguments PARAMS ((char **, char *)); static bfd_boolean parse_arguments PARAMS ((TInsn *, int, char **)); +static int get_invisible_operands + PARAMS ((TInsn *)); static int xg_translate_idioms PARAMS ((char **, int *, char **)); static int xg_translate_sysreg_op PARAMS ((char **, int *, char **)); +static int xtensa_translate_old_userreg_ops + PARAMS ((char **)); +static int xtensa_translate_zero_immed + PARAMS ((char *, char *, char **, int *, char **)); static void xg_reverse_shift_count PARAMS ((char **)); static int xg_arg_is_constant @@ -376,21 +520,21 @@ static int xg_check_num_args /* Functions for dealing with the Xtensa ISA. */ -static bfd_boolean operand_is_immed - PARAMS ((xtensa_operand)); -static bfd_boolean operand_is_pcrel_label - PARAMS ((xtensa_operand)); static int get_relaxable_immed PARAMS ((xtensa_opcode)); static xtensa_opcode get_opcode_from_buf - PARAMS ((const char *)); + PARAMS ((const char *, int)); +#ifdef TENSILICA_DEBUG +static void xtensa_print_insn_table + PARAMS ((void)); +static void print_vliw_insn + PARAMS ((xtensa_insnbuf)); +#endif static bfd_boolean is_direct_call_opcode PARAMS ((xtensa_opcode)); -static bfd_boolean is_call_opcode - PARAMS ((xtensa_opcode)); static bfd_boolean is_entry_opcode PARAMS ((xtensa_opcode)); -static bfd_boolean is_loop_opcode +static bfd_boolean is_movi_opcode PARAMS ((xtensa_opcode)); static bfd_boolean is_the_loop_opcode PARAMS ((xtensa_opcode)); @@ -398,39 +542,28 @@ static bfd_boolean is_jx_opcode PARAMS ((xtensa_opcode)); static bfd_boolean is_windowed_return_opcode PARAMS ((xtensa_opcode)); -static bfd_boolean is_conditional_branch_opcode - PARAMS ((xtensa_opcode)); -static bfd_boolean is_branch_or_jump_opcode - PARAMS ((xtensa_opcode)); -static bfd_reloc_code_real_type opnum_to_reloc +static int decode_reloc + PARAMS ((bfd_reloc_code_real_type, int *, bfd_boolean *)); +static bfd_reloc_code_real_type encode_reloc + PARAMS ((int)); +static bfd_reloc_code_real_type encode_alt_reloc PARAMS ((int)); -static int reloc_to_opnum - PARAMS ((bfd_reloc_code_real_type)); static void xtensa_insnbuf_set_operand - PARAMS ((xtensa_insnbuf, xtensa_opcode, xtensa_operand, int32, + PARAMS ((xtensa_insnbuf, xtensa_format, int, xtensa_opcode, int, uint32, const char *, unsigned int)); static uint32 xtensa_insnbuf_get_operand - PARAMS ((xtensa_insnbuf, xtensa_opcode, int)); -static void xtensa_insnbuf_set_immediate_field - PARAMS ((xtensa_opcode, xtensa_insnbuf, int32, const char *, - unsigned int)); -static bfd_boolean is_negatable_branch - PARAMS ((TInsn *)); + PARAMS ((xtensa_insnbuf, xtensa_format, int, xtensa_opcode, int)); /* Various Other Internal Functions. */ static bfd_boolean is_unique_insn_expansion PARAMS ((TransitionRule *)); -static int xg_get_insn_size - PARAMS ((TInsn *)); static int xg_get_build_instr_size PARAMS ((BuildInstr *)); static bfd_boolean xg_is_narrow_insn PARAMS ((TInsn *)); static bfd_boolean xg_is_single_relaxable_insn PARAMS ((TInsn *)); -static int xg_get_max_narrow_insn_size - PARAMS ((xtensa_opcode)); static int xg_get_max_insn_widen_size PARAMS ((xtensa_opcode)); static int xg_get_max_insn_widen_literal_size @@ -454,23 +587,30 @@ static bfd_boolean xg_immeds_fit static bfd_boolean xg_symbolic_immeds_fit PARAMS ((const TInsn *, segT, fragS *, offsetT, long)); static bfd_boolean xg_check_operand - PARAMS ((int32, xtensa_operand)); -static int is_dnrange - PARAMS ((fragS *, symbolS *, long)); + PARAMS ((int32, xtensa_opcode, int)); static int xg_assembly_relax PARAMS ((IStack *, TInsn *, segT, fragS *, offsetT, int, long)); static void xg_force_frag_space PARAMS ((int)); static void xg_finish_frag - PARAMS ((char *, enum xtensa_relax_statesE, int, bfd_boolean)); + PARAMS ((char *, enum xtensa_relax_statesE, enum xtensa_relax_statesE, + int, bfd_boolean)); static bfd_boolean is_branch_jmp_to_next PARAMS ((TInsn *, fragS *)); static void xg_add_branch_and_loop_targets PARAMS ((TInsn *)); +static bfd_boolean xg_instruction_matches_options + PARAMS ((TInsn *, const ReqOption *)); +static bfd_boolean xg_instruction_matches_or_options + PARAMS ((TInsn *, const ReqOrOptionList *)); +static bfd_boolean xg_instruction_matches_option_term + PARAMS ((TInsn *, const ReqOrOption *)); static bfd_boolean xg_instruction_matches_rule PARAMS ((TInsn *, TransitionRule *)); static TransitionRule *xg_instruction_match PARAMS ((TInsn *)); +static int transition_rule_cmp + PARAMS ((const TransitionRule *, const TransitionRule *)); static bfd_boolean xg_build_token_insn PARAMS ((BuildInstr *, TInsn *, TInsn *)); static bfd_boolean xg_simplify_insn @@ -479,8 +619,10 @@ static bfd_boolean xg_expand_assembly_insn PARAMS ((IStack *, TInsn *)); static symbolS *xg_assemble_literal PARAMS ((TInsn *)); +static bfd_boolean xg_valid_literal_expression + PARAMS ((const expressionS *)); static void xg_assemble_literal_space - PARAMS ((int)); + PARAMS ((int, int)); static symbolS *xtensa_create_literal_symbol PARAMS ((segT, fragS *)); static void xtensa_add_literal_sym @@ -491,18 +633,14 @@ static void xtensa_clear_insn_labels PARAMS ((void)); static bfd_boolean get_is_linkonce_section PARAMS ((bfd *, segT)); -static bfd_boolean xg_emit_insn - PARAMS ((TInsn *, bfd_boolean)); static bfd_boolean xg_emit_insn_to_buf - PARAMS ((TInsn *, char *, fragS *, offsetT, bfd_boolean)); + PARAMS ((TInsn *, xtensa_format, char *, fragS *, offsetT, bfd_boolean)); static bfd_boolean xg_add_opcode_fix - PARAMS ((xtensa_opcode, int, expressionS *, fragS *, offsetT)); + PARAMS ((TInsn *, int, xtensa_format, int, expressionS *, fragS *, offsetT)); static void xg_resolve_literals PARAMS ((TInsn *, symbolS *)); static void xg_resolve_labels PARAMS ((TInsn *, symbolS *)); -static void xg_assemble_tokens - PARAMS ((TInsn *)); static bfd_boolean is_register_writer PARAMS ((const TInsn *, const char *, int)); static bfd_boolean is_bad_loopend_opcode @@ -511,10 +649,14 @@ static bfd_boolean is_unaligned_label PARAMS ((symbolS *)); static fragS *next_non_empty_frag PARAMS ((const fragS *)); -static xtensa_opcode next_frag_opcode +static bfd_boolean next_frag_opcode_is_loop + PARAMS ((const fragS *, xtensa_opcode *)); +static int next_frag_format_size PARAMS ((const fragS *)); -static void update_next_frag_nop_state - PARAMS ((fragS *)); +static int frag_format_size + PARAMS ((const fragS *)); +static void update_next_frag_state + PARAMS ((fragS *, bfd_boolean)); static bfd_boolean next_frag_is_branch_target PARAMS ((const fragS *)); static bfd_boolean next_frag_is_loop_target @@ -529,12 +671,44 @@ static void xtensa_move_labels PARAMS ((fragS *, valueT, bfd_boolean)); static void assemble_nop PARAMS ((size_t, char *)); +static void build_nop + PARAMS ((TInsn *, int)); static addressT get_expanded_loop_offset PARAMS ((xtensa_opcode)); static fragS *get_literal_pool_location PARAMS ((segT)); static void set_literal_pool_location PARAMS ((segT, fragS *)); +static void xtensa_set_frag_assembly_state + PARAMS ((fragS *)); +static bfd_boolean relaxable_section + PARAMS ((asection *)); +static void xtensa_find_unmarked_state_frags + PARAMS ((void)); +static void xtensa_find_unaligned_branch_targets + PARAMS ((bfd *, asection *, PTR)); +static void xtensa_find_unaligned_loops + PARAMS ((bfd *, asection *, PTR)); +static void xg_apply_tentative_value + PARAMS ((fixS *, valueT)); +static void finish_vinsn + PARAMS ((vliw_insn *)); +static bfd_boolean find_vinsn_conflicts + PARAMS ((vliw_insn *)); +static char check_t1_t2_reads_and_writes + PARAMS ((TInsn *, TInsn *)); +static bfd_boolean resources_conflict + PARAMS ((vliw_insn *)); +static xtensa_format xg_find_narrowest_format + PARAMS ((vliw_insn *)); +static int relaxation_requirements + PARAMS ((vliw_insn *)); +static void bundle_single_op + PARAMS ((TInsn *)); +static bfd_boolean emit_single_op + PARAMS ((TInsn *)); +static void xg_assemble_vliw_tokens + PARAMS ((vliw_insn *)); /* Helpers for xtensa_end(). */ @@ -544,6 +718,12 @@ static void xtensa_fix_target_frags PARAMS ((void)); static bfd_boolean frag_can_negate_branch PARAMS ((fragS *)); +static void xtensa_mark_narrow_branches + PARAMS ((void)); +static bfd_boolean is_narrow_branch_guaranteed_in_range + PARAMS ((fragS *, TInsn *)); +static void xtensa_mark_zcl_first_insns + PARAMS ((void)); static void xtensa_fix_a0_b_retw_frags PARAMS ((void)); static bfd_boolean next_instrs_are_b_retw @@ -558,6 +738,8 @@ static size_t min_bytes_to_other_loop_end PARAMS ((fragS *, fragS *, offsetT, size_t)); static size_t unrelaxed_frag_min_size PARAMS ((fragS *)); +static size_t unrelaxed_frag_max_size + PARAMS ((fragS *)); static void xtensa_fix_short_loop_frags PARAMS ((void)); static size_t count_insns_to_loop_end @@ -589,30 +771,36 @@ static size_t get_text_align_nth_nop_size PARAMS ((size_t, size_t, bfd_boolean)); static addressT get_noop_aligned_address PARAMS ((fragS *, addressT)); -static addressT get_widen_aligned_address - PARAMS ((fragS *, addressT)); +static addressT get_aligned_diff + PARAMS ((fragS *, addressT, addressT *)); /* Helpers for xtensa_relax_frag(). */ -static long relax_frag_text_align +static long relax_frag_loop_align PARAMS ((fragS *, long)); static long relax_frag_add_nop PARAMS ((fragS *)); -static long relax_frag_narrow +static long relax_frag_for_align PARAMS ((fragS *, long)); -static bfd_boolean future_alignment_required +static long future_alignment_required PARAMS ((fragS *, long)); +static addressT find_address_of_next_align_frag + PARAMS ((fragS **, int *, int *, int *, bfd_boolean *)); +static long bytes_to_stretch + PARAMS ((fragS *, int, int, int, int)); static long relax_frag_immed - PARAMS ((segT, fragS *, long, int, int *)); + PARAMS ((segT, fragS *, long, int, xtensa_format, int, int *, bfd_boolean)); /* Helpers for md_convert_frag(). */ static void convert_frag_align_next_opcode PARAMS ((fragS *)); static void convert_frag_narrow + PARAMS ((segT, fragS *, xtensa_format, int)); +static void convert_frag_fill_nop PARAMS ((fragS *)); static void convert_frag_immed - PARAMS ((segT, fragS *, int)); + PARAMS ((segT, fragS *, int, xtensa_format, int)); static fixS *fix_new_exp_in_seg PARAMS ((segT, subsegT, fragS *, int, int, expressionS *, int, bfd_reloc_code_real_type)); @@ -636,6 +824,8 @@ static void xtensa_insert_section PARAMS ((segT, segT)); static void xtensa_move_seg_list_to_beginning PARAMS ((seg_list *)); +static subseg_map *get_subseg_info + PARAMS ((segT, subsegT)); static void xtensa_move_literals PARAMS ((void)); static void mark_literal_frags @@ -648,41 +838,82 @@ static segT get_last_sec PARAMS ((void)); static void xtensa_switch_to_literal_fragment PARAMS ((emit_state *)); +static void xtensa_switch_to_non_abs_literal_fragment + PARAMS ((emit_state *)); static void xtensa_switch_section_emit_state PARAMS ((emit_state *, segT, subsegT)); static void xtensa_restore_emit_state PARAMS ((emit_state *)); static void cache_literal_section - PARAMS ((seg_list *, const char *, segT *)); + PARAMS ((seg_list *, const char *, segT *, bfd_boolean)); static segT retrieve_literal_seg - PARAMS ((seg_list *, const char *)); + PARAMS ((seg_list *, const char *, bfd_boolean)); static segT seg_present PARAMS ((const char *)); static void add_seg_list PARAMS ((seg_list *, segT)); -/* Property Table (e.g., ".xt.insn" and ".xt.lit") Functions. */ +/* Property flags on fragments and conversion to object file flags. */ +static bfd_boolean get_frag_is_literal + PARAMS ((const fragS *)); +static bfd_boolean get_frag_is_insn + PARAMS ((const fragS *)); +static bfd_boolean get_frag_is_no_transform + PARAMS ((fragS *)); +static void set_frag_is_specific_opcode + PARAMS ((fragS *, bfd_boolean)); +static void set_frag_is_no_transform + PARAMS ((fragS *, bfd_boolean)); static void xtensa_create_property_segments - PARAMS ((frag_predicate, const char *, xt_section_type)); + PARAMS ((frag_predicate, frag_predicate, const char *, xt_section_type)); +static void xtensa_create_xproperty_segments + PARAMS ((frag_flags_fn, const char *, xt_section_type)); static segment_info_type *retrieve_segment_info PARAMS ((segT)); static segT retrieve_xtensa_section PARAMS ((char *)); static bfd_boolean section_has_property - PARAMS ((segT sec, frag_predicate)); + PARAMS ((segT, frag_predicate)); +static bfd_boolean section_has_xproperty + PARAMS ((segT, frag_flags_fn)); static void add_xt_block_frags - PARAMS ((segT, segT, xtensa_block_info **, frag_predicate)); -static bfd_boolean get_frag_is_literal - PARAMS ((const fragS *)); -static bfd_boolean get_frag_is_insn - PARAMS ((const fragS *)); + PARAMS ((segT, segT, xtensa_block_info **, frag_predicate, frag_predicate)); +static bfd_boolean xtensa_frag_flags_is_empty + PARAMS ((const frag_flags *)); +static void xtensa_frag_flags_init + PARAMS ((frag_flags *)); +static void get_frag_property_flags + PARAMS ((const fragS *, frag_flags *)); +static bfd_vma frag_flags_to_number + PARAMS ((const frag_flags *)); +static bfd_boolean xtensa_frag_flags_combinable + PARAMS ((const frag_flags *, const frag_flags *)); +static bfd_vma xt_block_aligned_size + PARAMS ((const xtensa_block_info *)); +static bfd_boolean xtensa_xt_block_combine + PARAMS ((xtensa_block_info *, const xtensa_block_info *)); +static void add_xt_prop_frags + PARAMS ((segT, segT, xtensa_block_info **, frag_flags_fn)); /* Import from elf32-xtensa.c in BFD library. */ + extern char *xtensa_get_property_section_name PARAMS ((asection *, const char *)); +/* op_placement_info functions. */ + +static void init_op_placement_info_table + PARAMS ((void)); +extern bfd_boolean opcode_fits_format_slot + PARAMS ((xtensa_opcode, xtensa_format, int)); +static int xg_get_single_size + PARAMS ((xtensa_opcode)); +static xtensa_format xg_get_single_format + PARAMS ((xtensa_opcode)); + /* TInsn and IStack functions. */ + static bfd_boolean tinsn_has_symbolic_operands PARAMS ((const TInsn *)); static bfd_boolean tinsn_has_invalid_symbolic_operands @@ -691,26 +922,52 @@ static bfd_boolean tinsn_has_complex_operands PARAMS ((const TInsn *)); static bfd_boolean tinsn_to_insnbuf PARAMS ((TInsn *, xtensa_insnbuf)); +static bfd_boolean tinsn_to_slotbuf + PARAMS ((xtensa_format, int, TInsn *, xtensa_insnbuf)); static bfd_boolean tinsn_check_arguments PARAMS ((const TInsn *)); static void tinsn_from_chars - PARAMS ((TInsn *, char *)); + PARAMS ((TInsn *, char *, int)); +static void tinsn_from_insnbuf + PARAMS ((TInsn *, xtensa_insnbuf, xtensa_format, int)); static void tinsn_immed_from_frag - PARAMS ((TInsn *, fragS *)); + PARAMS ((TInsn *, fragS *, int)); static int get_num_stack_text_bytes PARAMS ((IStack *)); static int get_num_stack_literal_bytes PARAMS ((IStack *)); +/* vliw_insn functions. */ + +static void xg_init_vinsn + PARAMS ((vliw_insn *)); +static void xg_clear_vinsn + PARAMS ((vliw_insn *)); +static bfd_boolean vinsn_has_specific_opcodes + PARAMS ((vliw_insn *)); +static void xg_free_vinsn + PARAMS ((vliw_insn *)); +static bfd_boolean vinsn_to_insnbuf + PARAMS ((vliw_insn *, char *, fragS *, bfd_boolean)); +static void vinsn_from_chars + PARAMS ((vliw_insn *, char *)); + /* Expression Utilities. */ + bfd_boolean expr_is_const PARAMS ((const expressionS *)); offsetT get_expr_const PARAMS ((const expressionS *)); void set_expr_const PARAMS ((expressionS *, offsetT)); +bfd_boolean expr_is_register + PARAMS ((const expressionS *)); +offsetT get_expr_register + PARAMS ((const expressionS *)); void set_expr_symbol_offset PARAMS ((expressionS *, symbolS *, offsetT)); +static void set_expr_symbol_offset_diff + PARAMS ((expressionS *, symbolS *, symbolS *, offsetT)); bfd_boolean expr_is_equal PARAMS ((expressionS *, expressionS *)); static void copy_expr @@ -739,20 +996,24 @@ static xtensa_opcode xtensa_callx0_opcode; static xtensa_opcode xtensa_callx4_opcode; static xtensa_opcode xtensa_callx8_opcode; static xtensa_opcode xtensa_callx12_opcode; +static xtensa_opcode xtensa_const16_opcode; static xtensa_opcode xtensa_entry_opcode; +static xtensa_opcode xtensa_movi_opcode; +static xtensa_opcode xtensa_movi_n_opcode; static xtensa_opcode xtensa_isync_opcode; -static xtensa_opcode xtensa_j_opcode; static xtensa_opcode xtensa_jx_opcode; +static xtensa_opcode xtensa_l32r_opcode; static xtensa_opcode xtensa_loop_opcode; static xtensa_opcode xtensa_loopnez_opcode; static xtensa_opcode xtensa_loopgtz_opcode; +static xtensa_opcode xtensa_nop_opcode; static xtensa_opcode xtensa_nop_n_opcode; static xtensa_opcode xtensa_or_opcode; static xtensa_opcode xtensa_ret_opcode; static xtensa_opcode xtensa_ret_n_opcode; static xtensa_opcode xtensa_retw_opcode; static xtensa_opcode xtensa_retw_n_opcode; -static xtensa_opcode xtensa_rsr_opcode; +static xtensa_opcode xtensa_rsr_lcount_opcode; static xtensa_opcode xtensa_waiti_opcode; @@ -760,34 +1021,22 @@ static xtensa_opcode xtensa_waiti_opcode; bfd_boolean use_literal_section = TRUE; static bfd_boolean align_targets = TRUE; -static bfd_boolean align_only_targets = FALSE; -static bfd_boolean software_a0_b_retw_interlock = TRUE; +static bfd_boolean warn_unaligned_branch_targets = FALSE; static bfd_boolean has_a0_b_retw = FALSE; -static bfd_boolean workaround_a0_b_retw = TRUE; - -static bfd_boolean software_avoid_b_j_loop_end = TRUE; -static bfd_boolean workaround_b_j_loop_end = TRUE; -static bfd_boolean maybe_has_b_j_loop_end = FALSE; - -static bfd_boolean software_avoid_short_loop = TRUE; -static bfd_boolean workaround_short_loop = TRUE; +static bfd_boolean workaround_a0_b_retw = FALSE; +static bfd_boolean workaround_b_j_loop_end = FALSE; +static bfd_boolean workaround_short_loop = FALSE; static bfd_boolean maybe_has_short_loop = FALSE; - -static bfd_boolean software_avoid_close_loop_end = TRUE; -static bfd_boolean workaround_close_loop_end = TRUE; +static bfd_boolean workaround_close_loop_end = FALSE; static bfd_boolean maybe_has_close_loop_end = FALSE; -/* When avoid_short_loops is true, all loops with early exits must - have at least 3 instructions. avoid_all_short_loops is a modifier - to the avoid_short_loop flag. In addition to the avoid_short_loop - actions, all straightline loopgtz and loopnez must have at least 3 - instructions. */ - -static bfd_boolean software_avoid_all_short_loops = TRUE; -static bfd_boolean workaround_all_short_loops = TRUE; +/* When workaround_short_loops is TRUE, all loops with early exits must + have at least 3 instructions. workaround_all_short_loops is a modifier + to the workaround_short_loop flag. In addition to the + workaround_short_loop actions, all straightline loopgtz and loopnez + must have at least 3 instructions. */ -/* This is on a per-instruction basis. */ -static bfd_boolean specific_opcode = FALSE; +static bfd_boolean workaround_all_short_loops = FALSE; enum { @@ -797,17 +1046,25 @@ enum option_relax, option_no_relax, + option_link_relax, + option_no_link_relax, + option_generics, option_no_generics, + option_transform, + option_no_transform, + option_text_section_literals, option_no_text_section_literals, + option_absolute_literals, + option_no_absolute_literals, + option_align_targets, option_no_align_targets, - option_align_only_targets, - option_no_align_only_targets, + option_warn_unaligned_targets, option_longcalls, option_no_longcalls, @@ -830,88 +1087,84 @@ enum option_no_workarounds, #ifdef XTENSA_SECTION_RENAME - option_literal_section_name, - option_text_section_name, - option_data_section_name, - option_bss_section_name, option_rename_section_name, #endif - option_eb, - option_el + option_prefer_l32r, + option_prefer_const16, + + option_target_hardware }; const char *md_shortopts = ""; struct option md_longopts[] = { - {"density", no_argument, NULL, option_density}, - {"no-density", no_argument, NULL, option_no_density}, - /* At least as early as alameda, --[no-]relax didn't work as - documented, so as of albany, --[no-]relax is equivalent to - --[no-]generics. Both of these will be deprecated in - BearValley. */ - {"relax", no_argument, NULL, option_generics}, - {"no-relax", no_argument, NULL, option_no_generics}, - {"generics", no_argument, NULL, option_generics}, - {"no-generics", no_argument, NULL, option_no_generics}, - {"text-section-literals", no_argument, NULL, option_text_section_literals}, - {"no-text-section-literals", no_argument, NULL, - option_no_text_section_literals}, + { "density", no_argument, NULL, option_density }, + { "no-density", no_argument, NULL, option_no_density }, + + /* Both "relax" and "generics" are deprecated and treated as equivalent + to the "transform" option. */ + { "relax", no_argument, NULL, option_relax }, + { "no-relax", no_argument, NULL, option_no_relax }, + { "generics", no_argument, NULL, option_generics }, + { "no-generics", no_argument, NULL, option_no_generics }, + + { "transform", no_argument, NULL, option_transform }, + { "no-transform", no_argument, NULL, option_no_transform }, + { "text-section-literals", no_argument, NULL, option_text_section_literals }, + { "no-text-section-literals", no_argument, NULL, + option_no_text_section_literals }, + { "absolute-literals", no_argument, NULL, option_absolute_literals }, + { "no-absolute-literals", no_argument, NULL, option_no_absolute_literals }, /* This option was changed from -align-target to -target-align because it conflicted with the "-al" option. */ - {"target-align", no_argument, NULL, option_align_targets}, - {"no-target-align", no_argument, NULL, - option_no_align_targets}, -#if 0 - /* This option should do a better job aligning targets because - it will only attempt to align targets that are the target of a - branch. */ - { "target-align-only", no_argument, NULL, option_align_only_targets }, - { "no-target-align-only", no_argument, NULL, option_no_align_only_targets }, -#endif /* 0 */ - {"longcalls", no_argument, NULL, option_longcalls}, - {"no-longcalls", no_argument, NULL, option_no_longcalls}, - - {"no-workaround-a0-b-retw", no_argument, NULL, - option_no_workaround_a0_b_retw}, - {"workaround-a0-b-retw", no_argument, NULL, option_workaround_a0_b_retw}, - - {"no-workaround-b-j-loop-end", no_argument, NULL, - option_no_workaround_b_j_loop_end}, - {"workaround-b-j-loop-end", no_argument, NULL, - option_workaround_b_j_loop_end}, - - {"no-workaround-short-loops", no_argument, NULL, - option_no_workaround_short_loop}, - {"workaround-short-loops", no_argument, NULL, option_workaround_short_loop}, + { "target-align", no_argument, NULL, option_align_targets }, + { "no-target-align", no_argument, NULL, + option_no_align_targets }, + { "warn-unaligned-targets", no_argument, NULL, option_warn_unaligned_targets }, + { "longcalls", no_argument, NULL, option_longcalls }, + { "no-longcalls", no_argument, NULL, option_no_longcalls }, + + { "no-workaround-a0-b-retw", no_argument, NULL, + option_no_workaround_a0_b_retw }, + { "workaround-a0-b-retw", no_argument, NULL, option_workaround_a0_b_retw }, - {"no-workaround-all-short-loops", no_argument, NULL, - option_no_workaround_all_short_loops}, - {"workaround-all-short-loop", no_argument, NULL, - option_workaround_all_short_loops}, + { "no-workaround-b-j-loop-end", no_argument, NULL, + option_no_workaround_b_j_loop_end }, + { "workaround-b-j-loop-end", no_argument, NULL, + option_workaround_b_j_loop_end }, - {"no-workaround-close-loop-end", no_argument, NULL, - option_no_workaround_close_loop_end}, - {"workaround-close-loop-end", no_argument, NULL, - option_workaround_close_loop_end}, + { "no-workaround-short-loops", no_argument, NULL, + option_no_workaround_short_loop }, + { "workaround-short-loops", no_argument, NULL, option_workaround_short_loop }, - {"no-workarounds", no_argument, NULL, option_no_workarounds}, + { "no-workaround-all-short-loops", no_argument, NULL, + option_no_workaround_all_short_loops }, + { "workaround-all-short-loop", no_argument, NULL, + option_workaround_all_short_loops }, + + { "prefer-l32r", no_argument, NULL, option_prefer_l32r }, + { "prefer-const16", no_argument, NULL, option_prefer_const16 }, + + { "no-workarounds", no_argument, NULL, option_no_workarounds }, + + { "no-workaround-close-loop-end", no_argument, NULL, + option_no_workaround_close_loop_end }, + { "workaround-close-loop-end", no_argument, NULL, + option_workaround_close_loop_end }, #ifdef XTENSA_SECTION_RENAME - {"literal-section-name", required_argument, NULL, - option_literal_section_name}, - {"text-section-name", required_argument, NULL, - option_text_section_name}, - {"data-section-name", required_argument, NULL, - option_data_section_name}, - {"rename-section", required_argument, NULL, - option_rename_section_name}, - {"bss-section-name", required_argument, NULL, - option_bss_section_name}, + { "rename-section", required_argument, NULL, + option_rename_section_name }, #endif /* XTENSA_SECTION_RENAME */ - {NULL, no_argument, NULL, 0} + { "link-relax", no_argument, NULL, option_link_relax }, + { "no-link-relax", no_argument, NULL, option_no_link_relax }, + + { "target-hardware", required_argument, NULL, option_target_hardware }, + + { NULL, no_argument, NULL, 0 } }; size_t md_longopts_size = sizeof md_longopts; @@ -925,23 +1178,29 @@ md_parse_option (c, arg) switch (c) { case option_density: - if (!density_supported) - { - as_bad (_("'--density' option not supported in this Xtensa " - "configuration")); - return 0; - } - directive_state[directive_density] = TRUE; + as_warn (_("--density option is ignored")); return 1; case option_no_density: - directive_state[directive_density] = FALSE; + as_warn (_("--no-density option is ignored")); return 1; - case option_generics: - directive_state[directive_generics] = TRUE; + case option_link_relax: + linkrelax = 1; return 1; - case option_no_generics: - directive_state[directive_generics] = FALSE; + case option_no_link_relax: + linkrelax = 0; return 1; + case option_generics: + as_warn (_("--generics is deprecated; use --transform instead")); + return md_parse_option (option_transform, arg); + case option_no_generics: + as_warn (_("--no-generics is deprecated; use --no-transform instead")); + return md_parse_option (option_no_transform, arg); + case option_relax: + as_warn (_("--relax is deprecated; use --transform instead")); + return md_parse_option (option_transform, arg); + case option_no_relax: + as_warn (_("--no-relax is deprecated; use --no-transform instead")); + return md_parse_option (option_no_transform, arg); case option_longcalls: directive_state[directive_longcalls] = TRUE; return 1; @@ -954,63 +1213,60 @@ md_parse_option (c, arg) case option_no_text_section_literals: use_literal_section = TRUE; return 1; + case option_absolute_literals: + if (!absolute_literals_supported) + { + as_fatal (_("--absolute-literals option not supported in this Xtensa configuration")); + return 0; + } + directive_state[directive_absolute_literals] = TRUE; + return 1; + case option_no_absolute_literals: + directive_state[directive_absolute_literals] = FALSE; + return 1; + case option_workaround_a0_b_retw: workaround_a0_b_retw = TRUE; - software_a0_b_retw_interlock = TRUE; return 1; case option_no_workaround_a0_b_retw: workaround_a0_b_retw = FALSE; - software_a0_b_retw_interlock = FALSE; return 1; case option_workaround_b_j_loop_end: workaround_b_j_loop_end = TRUE; - software_avoid_b_j_loop_end = TRUE; return 1; case option_no_workaround_b_j_loop_end: workaround_b_j_loop_end = FALSE; - software_avoid_b_j_loop_end = FALSE; return 1; case option_workaround_short_loop: workaround_short_loop = TRUE; - software_avoid_short_loop = TRUE; return 1; case option_no_workaround_short_loop: workaround_short_loop = FALSE; - software_avoid_short_loop = FALSE; return 1; case option_workaround_all_short_loops: workaround_all_short_loops = TRUE; - software_avoid_all_short_loops = TRUE; return 1; case option_no_workaround_all_short_loops: workaround_all_short_loops = FALSE; - software_avoid_all_short_loops = FALSE; return 1; case option_workaround_close_loop_end: workaround_close_loop_end = TRUE; - software_avoid_close_loop_end = TRUE; return 1; case option_no_workaround_close_loop_end: workaround_close_loop_end = FALSE; - software_avoid_close_loop_end = FALSE; return 1; case option_no_workarounds: workaround_a0_b_retw = FALSE; - software_a0_b_retw_interlock = FALSE; workaround_b_j_loop_end = FALSE; - software_avoid_b_j_loop_end = FALSE; workaround_short_loop = FALSE; - software_avoid_short_loop = FALSE; workaround_all_short_loops = FALSE; - software_avoid_all_short_loops = FALSE; workaround_close_loop_end = FALSE; - software_avoid_close_loop_end = FALSE; return 1; - + case option_align_targets: align_targets = TRUE; return 1; @@ -1018,38 +1274,11 @@ md_parse_option (c, arg) align_targets = FALSE; return 1; - case option_align_only_targets: - align_only_targets = TRUE; - return 1; - case option_no_align_only_targets: - align_only_targets = FALSE; + case option_warn_unaligned_targets: + warn_unaligned_branch_targets = TRUE; return 1; #ifdef XTENSA_SECTION_RENAME - case option_literal_section_name: - add_section_rename (".literal", arg); - as_warn (_("'--literal-section-name' is deprecated; " - "use '--rename-section .literal=NEWNAME'")); - return 1; - - case option_text_section_name: - add_section_rename (".text", arg); - as_warn (_("'--text-section-name' is deprecated; " - "use '--rename-section .text=NEWNAME'")); - return 1; - - case option_data_section_name: - add_section_rename (".data", arg); - as_warn (_("'--data-section-name' is deprecated; " - "use '--rename-section .data=NEWNAME'")); - return 1; - - case option_bss_section_name: - add_section_rename (".bss", arg); - as_warn (_("'--bss-section-name' is deprecated; " - "use '--rename-section .bss=NEWNAME'")); - return 1; - case option_rename_section_name: build_section_rename (arg); return 1; @@ -1060,6 +1289,56 @@ md_parse_option (c, arg) should be emitted or not. FIXME: Not implemented. */ return 1; + case option_prefer_l32r: + if (prefer_const16) + as_fatal (_("prefer-l32r conflicts with prefer-const16")); + prefer_l32r = 1; + return 1; + + case option_prefer_const16: + if (prefer_l32r) + as_fatal (_("prefer-const16 conflicts with prefer-l32r")); + prefer_const16 = 1; + return 1; + + case option_target_hardware: + { + int earliest, latest = 0; + if (*arg == 0 || *arg == '-') + as_fatal (_("invalid target hardware version")); + + earliest = strtol (arg, &arg, 0); + + if (*arg == 0) + latest = earliest; + else if (*arg == '-') + { + if (*++arg == 0) + as_fatal (_("invalid target hardware version")); + latest = strtol (arg, &arg, 0); + } + if (*arg != 0) + as_fatal (_("invalid target hardware version")); + + xtensa_setup_hw_workarounds (earliest, latest); + return 1; + } + + case option_transform: + /* This option has no affect other than to use the defaults, + which are already set. */ + return 1; + + case option_no_transform: + /* This option turns off all transformations of any kind. + However, because we want to preserve the state of other + directives, we only change its own field. Thus, before + you perform any transformation, always check if transform + is available. If you use the functions we provide for this + purpose, you will be ok. */ + directive_state[directive_transform] = FALSE; + return 1; + default: return 0; } @@ -1070,27 +1349,42 @@ void md_show_usage (stream) FILE *stream; { - fputs ("\nXtensa options:\n" - "--[no-]density [Do not] emit density instructions\n" - "--[no-]relax [Do not] perform branch relaxation\n" - "--[no-]generics [Do not] transform instructions\n" - "--[no-]longcalls [Do not] emit 32-bit call sequences\n" - "--[no-]target-align [Do not] try to align branch targets\n" - "--[no-]text-section-literals\n" - " [Do not] put literals in the text section\n" - "--no-workarounds Do not use any Xtensa workarounds\n" + fputs ("\n\ +Xtensa options:\n\ +--[no-]text-section-literals\n\ + [Do not] put literals in the text section\n\ +--[no-]absolute-literals\n\ + [Do not] default to use non-PC-relative literals\n\ +--[no-]target-align [Do not] try to align branch targets\n\ +--[no-]longcalls [Do not] emit 32-bit call sequences\n\ +--[no-]transform [Do not] transform instructions\n" #ifdef XTENSA_SECTION_RENAME - "--rename-section old=new(:old1=new1)*\n" - " Rename section 'old' to 'new'\n" - "\nThe following Xtensa options are deprecated\n" - "--literal-section-name Name of literal section (default .literal)\n" - "--text-section-name Name of text section (default .text)\n" - "--data-section-name Name of data section (default .data)\n" - "--bss-section-name Name of bss section (default .bss)\n" -#endif +"--rename-section old=new(:old1=new1)*\n\ + Rename section 'old' to 'new'\n" +#endif /* XTENSA_SECTION_RENAME */ , stream); } + +static void +xtensa_setup_hw_workarounds (earliest, latest) + int earliest; + int latest; +{ + if (earliest > latest) + as_fatal (_("illegal range of target hardware versions")); + + /* Enable all workarounds for pre-T1050.0 hardware. */ + if (earliest < 105000 || latest < 105000) + { + workaround_a0_b_retw |= TRUE; + workaround_b_j_loop_end |= TRUE; + workaround_short_loop |= TRUE; + workaround_close_loop_end |= TRUE; + workaround_all_short_loops |= TRUE; + } +} + /* Directive data and functions. */ @@ -1109,42 +1403,48 @@ state_stackS *directive_state_stack; const pseudo_typeS md_pseudo_table[] = { - {"align", s_align_bytes, 0}, /* Defaulting is invalid (0) */ - {"literal_position", xtensa_literal_position, 0}, - {"frame", s_ignore, 0}, /* formerly used for STABS debugging */ - {"word", cons, 4}, - {"begin", xtensa_begin_directive, 0}, - {"end", xtensa_end_directive, 0}, - {"literal", xtensa_literal_pseudo, 0}, - {NULL, 0, 0}, + { "align", s_align_bytes, 0 }, /* Defaulting is invalid (0). */ + { "literal_position", xtensa_literal_position, 0 }, + { "frame", s_ignore, 0 }, /* Formerly used for STABS debugging. */ + { "long", xtensa_elf_cons, 4 }, + { "word", xtensa_elf_cons, 4 }, + { "short", xtensa_elf_cons, 2 }, + { "begin", xtensa_begin_directive, 0 }, + { "end", xtensa_end_directive, 0 }, + { "loc", xtensa_dwarf2_directive_loc, 0 }, + { "literal", xtensa_literal_pseudo, 0 }, + { "frequency", xtensa_frequency_pseudo, 0 }, + { NULL, 0, 0 }, }; bfd_boolean -use_generics () +use_transform () { - return directive_state[directive_generics]; + /* After md_end, you should be checking frag by frag, rather + than state directives. */ + assert (!past_xtensa_end); + return directive_state[directive_transform]; } bfd_boolean use_longcalls () { - return directive_state[directive_longcalls]; -} - - -bfd_boolean -code_density_available () -{ - return directive_state[directive_density]; + /* After md_end, you should be checking frag by frag, rather + than state directives. */ + assert (!past_xtensa_end); + return directive_state[directive_longcalls] && use_transform (); } bfd_boolean -can_relax () +do_align_targets () { - return use_generics (); + /* After md_end, you should be checking frag by frag, rather + than state directives. */ + assert (!past_xtensa_end); + return align_targets && use_transform (); } @@ -1238,6 +1538,7 @@ get_directive (directive, negated) { int len; unsigned i; + char *directive_string; if (strncmp (input_line_pointer, "no-", 3) != 0) *negated = FALSE; @@ -1248,16 +1549,33 @@ get_directive (directive, negated) } len = strspn (input_line_pointer, - "abcdefghijklmnopqrstuvwxyz_/0123456789."); + "abcdefghijklmnopqrstuvwxyz_-/0123456789."); + + /* This code is a hack to make .begin [no-][generics|relax] exactly + equivalent to .begin [no-]transform. We should remove it when + we stop accepting those options. */ + + if (strncmp (input_line_pointer, "generics", strlen ("generics")) == 0) + { + as_warn (_("[no-]generics is deprecated; use [no-]transform instead")); + directive_string = "transform"; + } + else if (strncmp (input_line_pointer, "relax", strlen ("relax")) == 0) + { + as_warn (_("[no-]relax is deprecated; use [no-]transform instead")); + directive_string = "transform"; + } + else + directive_string = input_line_pointer; for (i = 0; i < sizeof (directive_info) / sizeof (*directive_info); ++i) { - if (strncmp (input_line_pointer, directive_info[i].name, len) == 0) + if (strncmp (directive_string, directive_info[i].name, len) == 0) { input_line_pointer += len; *directive = (directiveE) i; if (*negated && !directive_info[i].can_be_negated) - as_bad (_("directive %s can't be negated"), + as_bad (_("directive %s cannot be negated"), directive_info[i].name); return; } @@ -1278,8 +1596,6 @@ xtensa_begin_directive (ignore) int len; lit_state *ls; - md_flush_pending_output (); - get_directive (&directive, &negated); if (directive == (directiveE) XTENSA_UNDEFINED) { @@ -1287,6 +1603,9 @@ xtensa_begin_directive (ignore) return; } + if (cur_vinsn.inside_bundle) + as_bad (_("directives are not valid inside bundles")); + switch (directive) { case directive_literal: @@ -1297,15 +1616,19 @@ xtensa_begin_directive (ignore) saved_insn_labels = insn_labels; insn_labels = NULL; } + as_warn (_(".begin literal is deprecated; use .literal instead")); state = (emit_state *) xmalloc (sizeof (emit_state)); xtensa_switch_to_literal_fragment (state); directive_push (directive_literal, negated, state); break; case directive_literal_prefix: + /* Have to flush pending output because a movi relaxed to an l32r + might produce a literal. */ + md_flush_pending_output (); /* Check to see if the current fragment is a literal fragment. If it is, then this operation is not allowed. */ - if (frag_now->tc_frag_data.is_literal) + if (generating_literals) { as_bad (_("cannot set literal_prefix inside literal fragment")); return; @@ -1341,15 +1664,32 @@ xtensa_begin_directive (ignore) directive_push (directive_freeregs, negated, 0); break; + case directive_schedule: + md_flush_pending_output (); + frag_var (rs_fill, 0, 0, frag_now->fr_subtype, + frag_now->fr_symbol, frag_now->fr_offset, NULL); + directive_push (directive_schedule, negated, 0); + xtensa_set_frag_assembly_state (frag_now); + break; + case directive_density: - if (!density_supported && !negated) + as_warn (_(".begin [no-]density is ignored")); + break; + + case directive_absolute_literals: + md_flush_pending_output (); + if (!absolute_literals_supported && !negated) { - as_warn (_("Xtensa density option not supported; ignored")); + as_warn (_("Xtensa absolute literals option not supported; ignored")); break; } - /* fall through */ + xtensa_set_frag_assembly_state (frag_now); + directive_push (directive, negated, 0); + break; default: + md_flush_pending_output (); + xtensa_set_frag_assembly_state (frag_now); directive_push (directive, negated, 0); break; } @@ -1367,26 +1707,43 @@ xtensa_end_directive (ignore) const char *file; unsigned int line; emit_state *state; + emit_state **state_ptr; lit_state *s; - md_flush_pending_output (); + if (cur_vinsn.inside_bundle) + as_bad (_("directives are not valid inside bundles")); get_directive (&end_directive, &end_negated); - if (end_directive == (directiveE) XTENSA_UNDEFINED) + + md_flush_pending_output (); + + switch (end_directive) { + case (directiveE) XTENSA_UNDEFINED: discard_rest_of_line (); return; - } - if (end_directive == directive_density && !density_supported && !end_negated) - { - as_warn (_("Xtensa density option not supported; ignored")); + case directive_density: + as_warn (_(".end [no-]density is ignored")); demand_empty_rest_of_line (); - return; + break; + + case directive_absolute_literals: + if (!absolute_literals_supported && !end_negated) + { + as_warn (_("Xtensa absolute literals option not supported; ignored")); + demand_empty_rest_of_line (); + return; + } + break; + + default: + break; } + state_ptr = &state; /* use state_ptr to avoid type-punning warning */ directive_pop (&begin_directive, &begin_negated, &file, &line, - (const void **) &state); + (const void **) state_ptr); if (begin_directive != directive_none) { @@ -1403,6 +1760,7 @@ xtensa_end_directive (ignore) case directive_literal: frag_var (rs_fill, 0, 0, 0, NULL, 0, NULL); xtensa_restore_emit_state (state); + xtensa_set_frag_assembly_state (frag_now); free (state); if (!inside_directive (directive_literal)) { @@ -1412,9 +1770,6 @@ xtensa_end_directive (ignore) } break; - case directive_freeregs: - break; - case directive_literal_prefix: /* Restore the default collection sections from saved state. */ s = (lit_state *) state; @@ -1427,7 +1782,12 @@ xtensa_end_directive (ignore) free (s); break; + case directive_schedule: + case directive_freeregs: + break; + default: + xtensa_set_frag_assembly_state (frag_now); break; } } @@ -1437,23 +1797,49 @@ xtensa_end_directive (ignore) } +/* Wrap dwarf2 functions so that we correctly support the .loc directive. */ + +static bfd_boolean xtensa_loc_directive_seen = FALSE; + +static void +xtensa_dwarf2_directive_loc (x) + int x; +{ + xtensa_loc_directive_seen = TRUE; + dwarf2_directive_loc (x); +} + + +static void +xtensa_dwarf2_emit_insn (size, loc) + int size; + struct dwarf2_line_info *loc; +{ + if (debug_type != DEBUG_DWARF2 && ! xtensa_loc_directive_seen) + return; + xtensa_loc_directive_seen = FALSE; + dwarf2_gen_line_info (frag_now_fix () - size, loc); +} + + /* Place an aligned literal fragment at the current location. */ static void xtensa_literal_position (ignore) int ignore ATTRIBUTE_UNUSED; { + md_flush_pending_output (); + if (inside_directive (directive_literal)) as_warn (_(".literal_position inside literal directive; ignoring")); - else if (!use_literal_section) - xtensa_mark_literal_pool_location (); + xtensa_mark_literal_pool_location (); demand_empty_rest_of_line (); xtensa_clear_insn_labels (); } -/* Support .literal label, value@plt + offset. */ +/* Support .literal label, expr, ... */ static void xtensa_literal_pseudo (ignored) @@ -1462,7 +1848,6 @@ xtensa_literal_pseudo (ignored) emit_state state; char *p, *base_name; char c; - expressionS expP; segT dest_seg; if (inside_directive (directive_literal)) @@ -1472,6 +1857,8 @@ xtensa_literal_pseudo (ignored) return; } + md_flush_pending_output (); + /* Previous labels go with whatever follows this directive, not with the literal, so save them now. */ saved_insn_labels = insn_labels; @@ -1484,14 +1871,14 @@ xtensa_literal_pseudo (ignored) xtensa_switch_to_literal_fragment (&state); - /* ...but if we aren't using text-section-literals, then we + /* ...but if we aren't using text-section-literals, then we need to put them in the section we just switched to. */ - if (use_literal_section) + if (use_literal_section || directive_state[directive_absolute_literals]) dest_seg = now_seg; - /* All literals are aligned to four-byte boundaries - which is handled by switch to literal fragment. */ - /* frag_align (2, 0, 0); */ + /* All literals are aligned to four-byte boundaries. */ + frag_align (2, 0, 0); + record_alignment (now_seg, 2); c = get_symbol_end (); /* Just after name is now '\0'. */ @@ -1511,20 +1898,10 @@ xtensa_literal_pseudo (ignored) colon (base_name); - do - { - input_line_pointer++; /* skip ',' or ':' */ - - expr (0, &expP); - - /* We only support 4-byte literals with .literal. */ - emit_expr (&expP, 4); - } - while (*input_line_pointer == ','); - *p = c; + input_line_pointer++; /* skip ',' or ':' */ - demand_empty_rest_of_line (); + xtensa_elf_cons (4); xtensa_restore_emit_state (&state); @@ -1539,17 +1916,9 @@ xtensa_literal_prefix (start, len) char const *start; int len; { - segT s_now; /* Storage for the current seg and subseg. */ - subsegT ss_now; - char *name; /* Pointer to the name itself. */ - char *newname; - - if (!use_literal_section) - return; - - /* Store away the current section and subsection. */ - s_now = now_seg; - ss_now = now_subseg; + char *name, *linkonce_suffix; + char *newname, *newname4; + size_t linkonce_len; /* Get a null-terminated copy of the name. */ name = xmalloc (len + 1); @@ -1560,24 +1929,217 @@ xtensa_literal_prefix (start, len) /* Allocate the sections (interesting note: the memory pointing to the name is actually used for the name by the new section). */ + newname = xmalloc (len + strlen (".literal") + 1); - strcpy (newname, name); - strcpy (newname + len, ".literal"); + newname4 = xmalloc (len + strlen (".lit4") + 1); - /* Note that retrieve_literal_seg does not create a segment if - it already exists. */ - default_lit_sections.lit_seg = NULL; /* retrieved on demand */ + linkonce_len = sizeof (".gnu.linkonce.") - 1; + if (strncmp (name, ".gnu.linkonce.", linkonce_len) == 0 + && (linkonce_suffix = strchr (name + linkonce_len, '.')) != 0) + { + strcpy (newname, ".gnu.linkonce.literal"); + strcpy (newname4, ".gnu.linkonce.lit4"); - /* Canonicalizing section names allows renaming literal + strcat (newname, linkonce_suffix); + strcat (newname4, linkonce_suffix); + } + else + { + int suffix_pos = len; + + /* If the section name ends with ".text", then replace that suffix + instead of appending an additional suffix. */ + if (len >= 5 && strcmp (name + len - 5, ".text") == 0) + suffix_pos -= 5; + + strcpy (newname, name); + strcpy (newname4, name); + + strcpy (newname + suffix_pos, ".literal"); + strcpy (newname4 + suffix_pos, ".lit4"); + } + + /* Note that retrieve_literal_seg does not create a segment if + it already exists. */ + default_lit_sections.lit_seg = NULL; + default_lit_sections.lit4_seg = NULL; + + /* Canonicalizing section names allows renaming literal sections to occur correctly. */ - default_lit_sections.lit_seg_name = - tc_canonicalize_symbol_name (newname); + default_lit_sections.lit_seg_name = tc_canonicalize_symbol_name (newname); + default_lit_sections.lit4_seg_name = tc_canonicalize_symbol_name (newname4); free (name); +} + + +/* Support ".frequency branch_target_frequency fall_through_frequency". */ + +static void +xtensa_frequency_pseudo (ignored) + int ignored ATTRIBUTE_UNUSED; +{ + float fall_through_f, target_f; + subseg_map *seginfo; + + fall_through_f = (float) strtod (input_line_pointer, &input_line_pointer); + if (fall_through_f < 0) + { + as_bad (_("fall through frequency must be greater than 0")); + ignore_rest_of_line (); + return; + } + + target_f = (float) strtod (input_line_pointer, &input_line_pointer); + if (target_f < 0) + { + as_bad (_("branch target frequency must be greater than 0")); + ignore_rest_of_line (); + return; + } + + seginfo = get_subseg_info (now_seg, now_subseg); + seginfo->cur_target_freq = target_f; + seginfo->cur_total_freq = target_f + fall_through_f; + + demand_empty_rest_of_line (); +} + + +/* Like normal .long/.short/.word, except support @plt, etc. + Clobbers input_line_pointer, checks end-of-line. */ + +static void +xtensa_elf_cons (nbytes) + int nbytes; +{ + expressionS exp; + bfd_reloc_code_real_type reloc; + + md_flush_pending_output (); + + if (cur_vinsn.inside_bundle) + as_bad (_("directives are not valid inside bundles")); + + if (is_it_end_of_statement ()) + { + demand_empty_rest_of_line (); + return; + } + + do + { + expression (&exp); + if (exp.X_op == O_symbol + && *input_line_pointer == '@' + && ((reloc = xtensa_elf_suffix (&input_line_pointer, &exp)) + != BFD_RELOC_NONE)) + { + reloc_howto_type *reloc_howto = + bfd_reloc_type_lookup (stdoutput, reloc); + + if (reloc == BFD_RELOC_UNUSED || !reloc_howto) + as_bad (_("unsupported relocation")); + else if ((reloc >= BFD_RELOC_XTENSA_SLOT0_OP + && reloc <= BFD_RELOC_XTENSA_SLOT14_OP) + || (reloc >= BFD_RELOC_XTENSA_SLOT0_ALT + && reloc <= BFD_RELOC_XTENSA_SLOT14_ALT)) + as_bad (_("opcode-specific %s relocation used outside " + "an instruction"), reloc_howto->name); + else if (nbytes != (int) bfd_get_reloc_size (reloc_howto)) + as_bad (_("%s relocations do not fit in %d bytes"), + reloc_howto->name, nbytes); + else + { + char *p = frag_more ((int) nbytes); + xtensa_set_frag_assembly_state (frag_now); + fix_new_exp (frag_now, p - frag_now->fr_literal, + nbytes, &exp, 0, reloc); + } + } + else + emit_expr (&exp, (unsigned int) nbytes); + } + while (*input_line_pointer++ == ','); + + input_line_pointer--; /* Put terminator back into stream. */ + demand_empty_rest_of_line (); +} + + +/* Parse @plt, etc. and return the desired relocation. */ +static bfd_reloc_code_real_type +xtensa_elf_suffix (str_p, exp_p) + char **str_p; + expressionS *exp_p; +{ + struct map_bfd + { + char *string; + int length; + bfd_reloc_code_real_type reloc; + }; + + char ident[20]; + char *str = *str_p; + char *str2; + int ch; + int len; + struct map_bfd *ptr; + +#define MAP(str,reloc) { str, sizeof (str) - 1, reloc } - /* Restore the current section and subsection and set the - generation into the old segment. */ - subseg_set (s_now, ss_now); + static struct map_bfd mapping[] = + { + MAP ("l", BFD_RELOC_LO16), + MAP ("h", BFD_RELOC_HI16), + MAP ("plt", BFD_RELOC_XTENSA_PLT), + { (char *) 0, 0, BFD_RELOC_UNUSED } + }; + + if (*str++ != '@') + return BFD_RELOC_NONE; + + for (ch = *str, str2 = ident; + (str2 < ident + sizeof (ident) - 1 + && (ISALNUM (ch) || ch == '@')); + ch = *++str) + { + *str2++ = (ISLOWER (ch)) ? ch : TOLOWER (ch); + } + + *str2 = '\0'; + len = str2 - ident; + + ch = ident[0]; + for (ptr = &mapping[0]; ptr->length > 0; ptr++) + if (ch == ptr->string[0] + && len == ptr->length + && memcmp (ident, ptr->string, ptr->length) == 0) + { + /* Now check for "identifier@suffix+constant". */ + if (*str == '-' || *str == '+') + { + char *orig_line = input_line_pointer; + expressionS new_exp; + + input_line_pointer = str; + expression (&new_exp); + if (new_exp.X_op == O_constant) + { + exp_p->X_add_number += new_exp.X_add_number; + str = input_line_pointer; + } + + if (&input_line_pointer != str_p) + input_line_pointer = orig_line; + } + + *str_p = str; + return ptr->reloc; + } + + return BFD_RELOC_UNUSED; } @@ -1591,9 +2153,11 @@ expression_end (name) { switch (*name) { + case '}': case ';': case '\0': case ',': + case ':': return name; case ' ': case '\t': @@ -1664,45 +2228,67 @@ tc_get_register (prefix) } -#define PLT_SUFFIX "@PLT" -#define plt_suffix "@plt" - static void -expression_maybe_register (opnd, tok) - xtensa_operand opnd; +expression_maybe_register (opc, opnd, tok) + xtensa_opcode opc; + int opnd; expressionS *tok; { - char *kind = xtensa_operand_kind (opnd); + xtensa_isa isa = xtensa_default_isa; - if ((strlen (kind) == 1) - && (*kind == 'l' || *kind == 'L' || *kind == 'i' || *kind == 'r')) + /* Check if this is an immediate operand. */ + if (xtensa_operand_is_register (isa, opc, opnd) == 0) { + bfd_reloc_code_real_type reloc; segT t = expression (tok); - if (t == absolute_section && operand_is_pcrel_label (opnd)) + if (t == absolute_section + && xtensa_operand_is_PCrelative (isa, opc, opnd) == 1) { assert (tok->X_op == O_constant); tok->X_op = O_symbol; tok->X_add_symbol = &abs_symbol; } - if (tok->X_op == O_symbol - && (!strncmp (input_line_pointer, PLT_SUFFIX, - strlen (PLT_SUFFIX) - 1) - || !strncmp (input_line_pointer, plt_suffix, - strlen (plt_suffix) - 1))) + + if ((tok->X_op == O_constant || tok->X_op == O_symbol) + && (reloc = xtensa_elf_suffix (&input_line_pointer, tok)) + && (reloc != BFD_RELOC_NONE)) { - symbol_get_tc (tok->X_add_symbol)->plt = 1; - input_line_pointer += strlen (plt_suffix); + switch (reloc) + { + default: + case BFD_RELOC_UNUSED: + as_bad (_("unsupported relocation")); + break; + + case BFD_RELOC_XTENSA_PLT: + tok->X_op = O_pltrel; + break; + + case BFD_RELOC_LO16: + if (tok->X_op == O_constant) + tok->X_add_number &= 0xffff; + else + tok->X_op = O_lo16; + break; + + case BFD_RELOC_HI16: + if (tok->X_op == O_constant) + tok->X_add_number = ((unsigned) tok->X_add_number) >> 16; + else + tok->X_op = O_hi16; + break; + } } } else { - unsigned reg = tc_get_register (kind); + xtensa_regfile opnd_rf = xtensa_operand_regfile (isa, opc, opnd); + unsigned reg = tc_get_register (xtensa_regfile_shortname (isa, opnd_rf)); if (reg != ERROR_REG_NUM) /* Already errored */ { uint32 buf = reg; - if ((xtensa_operand_encode (opnd, &buf) != xtensa_encode_result_ok) - || (reg != xtensa_operand_decode (opnd, buf))) + if (xtensa_operand_encode (isa, opc, opnd, &buf)) as_bad (_("register number out of range")); } @@ -1723,11 +2309,12 @@ tokenize_arguments (args, str) char *old_input_line_pointer; bfd_boolean saw_comma = FALSE; bfd_boolean saw_arg = FALSE; + bfd_boolean saw_colon = FALSE; int num_args = 0; char *arg_end, *arg; int arg_len; - - /* Save and restore input_line_pointer around this function. */ + + /* Save and restore input_line_pointer around this function. */ old_input_line_pointer = input_line_pointer; input_line_pointer = str; @@ -1737,51 +2324,70 @@ tokenize_arguments (args, str) switch (*input_line_pointer) { case '\0': + case '}': goto fini; + case ':': + input_line_pointer++; + if (saw_comma || saw_colon || !saw_arg) + goto err; + saw_colon = TRUE; + break; + case ',': input_line_pointer++; - if (saw_comma || !saw_arg) + if (saw_comma || saw_colon || !saw_arg) goto err; saw_comma = TRUE; break; default: - if (!saw_comma && saw_arg) + if (!saw_comma && !saw_colon && saw_arg) goto err; arg_end = input_line_pointer + 1; while (!expression_end (arg_end)) arg_end += 1; - + arg_len = arg_end - input_line_pointer; - arg = (char *) xmalloc (arg_len + 1); + arg = (char *) xmalloc ((saw_colon ? 1 : 0) + arg_len + 1); args[num_args] = arg; + if (saw_colon) + *arg++ = ':'; strncpy (arg, input_line_pointer, arg_len); arg[arg_len] = '\0'; - + input_line_pointer = arg_end; num_args += 1; saw_comma = FALSE; + saw_colon = FALSE; saw_arg = TRUE; break; } } fini: - if (saw_comma) + if (saw_comma || saw_colon) goto err; input_line_pointer = old_input_line_pointer; return num_args; err: + if (saw_comma) + as_bad (_("extra comma")); + else if (saw_colon) + as_bad (_("extra colon")); + else if (!saw_arg) + as_bad (_("missing argument")); + else + as_bad (_("missing comma or colon")); input_line_pointer = old_input_line_pointer; return -1; } -/* Parse the arguments to an opcode. Return true on error. */ +/* Parse the arguments to an opcode. Return TRUE on error. */ static bfd_boolean parse_arguments (insn, num_args, arg_strings) @@ -1789,55 +2395,170 @@ parse_arguments (insn, num_args, arg_strings) int num_args; char **arg_strings; { - expressionS *tok = insn->tok; + expressionS *tok, *last_tok; xtensa_opcode opcode = insn->opcode; bfd_boolean had_error = TRUE; - xtensa_isa isa = xtensa_default_isa; - int n; + xtensa_isa isa = xtensa_default_isa; + int n, num_regs = 0; int opcode_operand_count; - int actual_operand_count = 0; - xtensa_operand opnd = NULL; + int opnd_cnt, last_opnd_cnt; + unsigned int next_reg = 0; char *old_input_line_pointer; if (insn->insn_type == ITYPE_LITERAL) opcode_operand_count = 1; else - opcode_operand_count = xtensa_num_operands (isa, opcode); + opcode_operand_count = xtensa_opcode_num_operands (isa, opcode); + tok = insn->tok; memset (tok, 0, sizeof (*tok) * MAX_INSN_ARGS); /* Save and restore input_line_pointer around this function. */ - old_input_line_pointer = input_line_pointer; + old_input_line_pointer = input_line_pointer; + + last_tok = 0; + last_opnd_cnt = -1; + opnd_cnt = 0; + + /* Skip invisible operands. */ + while (xtensa_operand_is_visible (isa, opcode, opnd_cnt) == 0) + { + opnd_cnt += 1; + tok++; + } for (n = 0; n < num_args; n++) - { + { input_line_pointer = arg_strings[n]; + if (*input_line_pointer == ':') + { + xtensa_regfile opnd_rf; + input_line_pointer++; + if (num_regs == 0) + goto err; + assert (opnd_cnt > 0); + num_regs--; + opnd_rf = xtensa_operand_regfile (isa, opcode, last_opnd_cnt); + if (next_reg + != tc_get_register (xtensa_regfile_shortname (isa, opnd_rf))) + as_warn (_("incorrect register number, ignoring")); + next_reg++; + } + else + { + if (opnd_cnt >= opcode_operand_count) + { + as_warn (_("too many arguments")); + goto err; + } + assert (opnd_cnt < MAX_INSN_ARGS); + + expression_maybe_register (opcode, opnd_cnt, tok); + next_reg = tok->X_add_number + 1; + + if (tok->X_op == O_illegal || tok->X_op == O_absent) + goto err; + if (xtensa_operand_is_register (isa, opcode, opnd_cnt) == 1) + { + num_regs = xtensa_operand_num_regs (isa, opcode, opnd_cnt) - 1; + /* minus 1 because we are seeing one right now */ + } + else + num_regs = 0; - if (actual_operand_count >= opcode_operand_count) - { - as_warn (_("too many arguments")); - goto err; - } - assert (actual_operand_count < MAX_INSN_ARGS); + last_tok = tok; + last_opnd_cnt = opnd_cnt; - opnd = xtensa_get_operand (isa, opcode, actual_operand_count); - expression_maybe_register (opnd, tok); + do + { + opnd_cnt += 1; + tok++; + } + while (xtensa_operand_is_visible (isa, opcode, opnd_cnt) == 0); + } + } - if (tok->X_op == O_illegal || tok->X_op == O_absent) - goto err; - actual_operand_count++; - tok++; - } + if (num_regs > 0 && ((int) next_reg != last_tok->X_add_number + 1)) + goto err; insn->ntok = tok - insn->tok; had_error = FALSE; err: - input_line_pointer = old_input_line_pointer; + input_line_pointer = old_input_line_pointer; return had_error; } +static int +get_invisible_operands (insn) + TInsn *insn; +{ + xtensa_isa isa = xtensa_default_isa; + static xtensa_insnbuf slotbuf = NULL; + xtensa_format fmt; + xtensa_opcode opc = insn->opcode; + int slot, opnd, fmt_found; + unsigned val; + + if (!slotbuf) + slotbuf = xtensa_insnbuf_alloc (isa); + + /* Find format/slot where this can be encoded. */ + fmt_found = 0; + slot = 0; + for (fmt = 0; fmt < xtensa_isa_num_formats (isa); fmt++) + { + for (slot = 0; slot < xtensa_format_num_slots (isa, fmt); slot++) + { + if (xtensa_opcode_encode (isa, fmt, slot, slotbuf, opc) == 0) + { + fmt_found = 1; + break; + } + } + if (fmt_found) break; + } + + if (!fmt_found) + { + as_bad (_("cannot encode opcode \"%s\""), xtensa_opcode_name (isa, opc)); + return -1; + } + + /* First encode all the visible operands + (to deal with shared field operands). */ + for (opnd = 0; opnd < insn->ntok; opnd++) + { + if (xtensa_operand_is_visible (isa, opc, opnd) == 1 + && (insn->tok[opnd].X_op == O_register + || insn->tok[opnd].X_op == O_constant)) + { + val = insn->tok[opnd].X_add_number; + xtensa_operand_encode (isa, opc, opnd, &val); + xtensa_operand_set_field (isa, opc, opnd, fmt, slot, slotbuf, val); + } + } + + /* Then pull out the values for the invisible ones. */ + for (opnd = 0; opnd < insn->ntok; opnd++) + { + if (xtensa_operand_is_visible (isa, opc, opnd) == 0) + { + xtensa_operand_get_field (isa, opc, opnd, fmt, slot, slotbuf, &val); + xtensa_operand_decode (isa, opc, opnd, &val); + insn->tok[opnd].X_add_number = val; + if (xtensa_operand_is_register (isa, opc, opnd) == 1) + insn->tok[opnd].X_op = O_register; + else + insn->tok[opnd].X_op = O_constant; + } + } + + return 0; +} + + static void xg_reverse_shift_count (cnt_argp) char **cnt_argp; @@ -1893,13 +2614,13 @@ xg_replace_opname (popname, newop) static int xg_check_num_args (pnum_args, expected_num, opname, arg_strings) int *pnum_args; - int expected_num; + int expected_num; char *opname; char **arg_strings; { int num_args = *pnum_args; - if (num_args < expected_num) + if (num_args < expected_num) { as_bad (_("not enough operands (%d) for '%s'; expected %d"), num_args, opname, expected_num); @@ -1923,14 +2644,20 @@ xg_check_num_args (pnum_args, expected_num, opname, arg_strings) } +/* If the register is not specified as part of the opcode, + then get it from the operand and move it to the opcode. */ + static int xg_translate_sysreg_op (popname, pnum_args, arg_strings) char **popname; int *pnum_args; char **arg_strings; { + xtensa_isa isa = xtensa_default_isa; + xtensa_sysreg sr; char *opname, *new_opname; - offsetT val; + const char *sr_name; + int is_user, is_write; bfd_boolean has_underbar = FALSE; opname = *popname; @@ -1939,40 +2666,148 @@ xg_translate_sysreg_op (popname, pnum_args, arg_strings) has_underbar = TRUE; opname += 1; } + is_user = (opname[1] == 'u'); + is_write = (opname[0] == 'w'); - /* Opname == [rw]ur... */ - - if (opname[3] == '\0') - { - /* If the register is not specified as part of the opcode, - then get it from the operand and move it to the opcode. */ + /* Opname == [rw]ur or [rwx]sr... */ - if (xg_check_num_args (pnum_args, 2, opname, arg_strings)) - return -1; + if (xg_check_num_args (pnum_args, 2, opname, arg_strings)) + return -1; + /* Check if the argument is a symbolic register name. */ + sr = xtensa_sysreg_lookup_name (isa, arg_strings[1]); + /* Handle WSR to "INTSET" as a special case. */ + if (sr == XTENSA_UNDEFINED && is_write && !is_user + && !strcasecmp (arg_strings[1], "intset")) + sr = xtensa_sysreg_lookup_name (isa, "interrupt"); + if (sr == XTENSA_UNDEFINED + || (xtensa_sysreg_is_user (isa, sr) == 1) != is_user) + { + /* Maybe it's a register number.... */ + offsetT val; if (!xg_arg_is_constant (arg_strings[1], &val)) { - as_bad (_("register number for `%s' is not a constant"), opname); + as_bad (_("invalid register '%s' for '%s' instruction"), + arg_strings[1], opname); return -1; } - if ((unsigned) val > 255) + sr = xtensa_sysreg_lookup (isa, val, is_user); + if (sr == XTENSA_UNDEFINED) { - as_bad (_("register number (%ld) for `%s' is out of range"), + as_bad (_("invalid register number (%ld) for '%s' instruction"), val, opname); return -1; } + } - /* Remove the last argument, which is now part of the opcode. */ - free (arg_strings[1]); - arg_strings[1] = 0; - *pnum_args = 1; + /* Remove the last argument, which is now part of the opcode. */ + free (arg_strings[1]); + arg_strings[1] = 0; + *pnum_args = 1; + + /* Translate the opcode. */ + sr_name = xtensa_sysreg_name (isa, sr); + /* Another special case for "WSR.INTSET".... */ + if (is_write && !is_user && !strcasecmp ("interrupt", sr_name)) + sr_name = "intset"; + new_opname = (char *) xmalloc (strlen (sr_name) + 6); + sprintf (new_opname, "%s%s.%s", (has_underbar ? "_" : ""), + *popname, sr_name); + free (*popname); + *popname = new_opname; + + return 0; +} + + +static int +xtensa_translate_old_userreg_ops (popname) + char **popname; +{ + xtensa_isa isa = xtensa_default_isa; + xtensa_sysreg sr; + char *opname, *new_opname; + const char *sr_name; + bfd_boolean has_underbar = FALSE; + + opname = *popname; + if (opname[0] == '_') + { + has_underbar = TRUE; + opname += 1; + } + + sr = xtensa_sysreg_lookup_name (isa, opname + 1); + if (sr != XTENSA_UNDEFINED) + { + /* The new default name ("nnn") is different from the old default + name ("URnnn"). The old default is handled below, and we don't + want to recognize [RW]nnn, so do nothing if the name is the (new) + default. */ + static char namebuf[10]; + sprintf (namebuf, "%d", xtensa_sysreg_number (isa, sr)); + if (strcmp (namebuf, opname + 1) == 0) + return 0; + } + else + { + offsetT val; + char *end; + + /* Only continue if the reg name is "URnnn". */ + if (opname[1] != 'u' || opname[2] != 'r') + return 0; + val = strtoul (opname + 3, &end, 10); + if (*end != '\0') + return 0; + + sr = xtensa_sysreg_lookup (isa, val, 1); + if (sr == XTENSA_UNDEFINED) + { + as_bad (_("invalid register number (%ld) for '%s'"), + val, opname); + return -1; + } + } + + /* Translate the opcode. */ + sr_name = xtensa_sysreg_name (isa, sr); + new_opname = (char *) xmalloc (strlen (sr_name) + 6); + sprintf (new_opname, "%s%cur.%s", (has_underbar ? "_" : ""), + opname[0], sr_name); + free (*popname); + *popname = new_opname; + + return 0; +} + + +static int +xtensa_translate_zero_immed (old_op, new_op, popname, pnum_args, arg_strings) + char *old_op; + char *new_op; + char **popname; + int *pnum_args; + char **arg_strings; +{ + char *opname; + offsetT val; + + opname = *popname; + assert (opname[0] != '_'); + + if (strcmp (opname, old_op) != 0) + return 0; - /* Translate the opcode. */ - new_opname = (char *) xmalloc (8); - sprintf (new_opname, "%s%cur%u", (has_underbar ? "_" : ""), - opname[0], (unsigned) val); - free (*popname); - *popname = new_opname; + if (xg_check_num_args (pnum_args, 3, opname, arg_strings)) + return -1; + if (xg_arg_is_constant (arg_strings[1], &val) && val == 0) + { + xg_replace_opname (popname, new_op); + free (arg_strings[1]); + arg_strings[1] = arg_strings[2]; + arg_strings[2] = 0; + *pnum_args = 2; } return 0; @@ -1991,6 +2826,9 @@ xg_translate_idioms (popname, pnum_args, arg_strings) char *opname = *popname; bfd_boolean has_underbar = FALSE; + if (cur_vinsn.inside_bundle) + return 0; + if (*opname == '_') { has_underbar = TRUE; @@ -1999,7 +2837,7 @@ xg_translate_idioms (popname, pnum_args, arg_strings) if (strcmp (opname, "mov") == 0) { - if (!has_underbar && code_density_available ()) + if (use_transform () && !has_underbar && density_supported) xg_replace_opname (popname, "mov.n"); else { @@ -2033,9 +2871,10 @@ xg_translate_idioms (popname, pnum_args, arg_strings) return 0; } - if (strcmp (opname, "nop") == 0) + if (xtensa_nop_opcode == XTENSA_UNDEFINED + && strcmp (opname, "nop") == 0) { - if (!has_underbar && code_density_available ()) + if (use_transform () && !has_underbar && density_supported) xg_replace_opname (popname, "nop.n"); else { @@ -2053,210 +2892,209 @@ xg_translate_idioms (popname, pnum_args, arg_strings) return 0; } - if ((opname[0] == 'r' || opname[0] == 'w') - && opname[1] == 'u' - && opname[2] == 'r') + /* Recognize [RW]UR and [RWX]SR. */ + if ((((opname[0] == 'r' || opname[0] == 'w') + && (opname[1] == 'u' || opname[1] == 's')) + || (opname[0] == 'x' && opname[1] == 's')) + && opname[2] == 'r' + && opname[3] == '\0') return xg_translate_sysreg_op (popname, pnum_args, arg_strings); + /* Backward compatibility for RUR and WUR: Recognize [RW]UR and + [RW] if is the non-default name of a user register. */ + if ((opname[0] == 'r' || opname[0] == 'w') + && xtensa_opcode_lookup (xtensa_default_isa, opname) == XTENSA_UNDEFINED) + return xtensa_translate_old_userreg_ops (popname); - /* WIDENING DENSITY OPCODES - - questionable relaxations (widening) from old "tai" idioms: - - ADD.N --> ADD - BEQZ.N --> BEQZ - RET.N --> RET - RETW.N --> RETW - MOVI.N --> MOVI - MOV.N --> MOV - NOP.N --> NOP + /* Relax branches that don't allow comparisons against an immediate value + of zero to the corresponding branches with implicit zero immediates. */ + if (!has_underbar && use_transform ()) + { + if (xtensa_translate_zero_immed ("bnei", "bnez", popname, + pnum_args, arg_strings)) + return -1; - Note: this incomplete list was imported to match the "tai" - behavior; other density opcodes are not handled. + if (xtensa_translate_zero_immed ("beqi", "beqz", popname, + pnum_args, arg_strings)) + return -1; - The xtensa-relax code may know how to do these but it doesn't do - anything when these density opcodes appear inside a no-density - region. Somehow GAS should either print an error when that happens - or do the widening. The old "tai" behavior was to do the widening. - For now, I'll make it widen but print a warning. + if (xtensa_translate_zero_immed ("bgei", "bgez", popname, + pnum_args, arg_strings)) + return -1; - FIXME: GAS needs to detect density opcodes inside no-density - regions and treat them as errors. This code should be removed - when that is done. */ + if (xtensa_translate_zero_immed ("blti", "bltz", popname, + pnum_args, arg_strings)) + return -1; + } - if (use_generics () - && !has_underbar - && density_supported - && !code_density_available ()) - { - if (strcmp (opname, "add.n") == 0) - xg_replace_opname (popname, "add"); + return 0; +} - else if (strcmp (opname, "beqz.n") == 0) - xg_replace_opname (popname, "beqz"); + +/* Functions for dealing with the Xtensa ISA. */ - else if (strcmp (opname, "ret.n") == 0) - xg_replace_opname (popname, "ret"); +/* Currently the assembler only allows us to use a single target per + fragment. Because of this, only one operand for a given + instruction may be symbolic. If there is a PC-relative operand, + the last one is chosen. Otherwise, the result is the number of the + last immediate operand, and if there are none of those, we fail and + return -1. */ - else if (strcmp (opname, "retw.n") == 0) - xg_replace_opname (popname, "retw"); +int +get_relaxable_immed (opcode) + xtensa_opcode opcode; +{ + int last_immed = -1; + int noperands, opi; - else if (strcmp (opname, "movi.n") == 0) - xg_replace_opname (popname, "movi"); + if (opcode == XTENSA_UNDEFINED) + return -1; - else if (strcmp (opname, "mov.n") == 0) - { - if (xg_check_num_args (pnum_args, 2, opname, arg_strings)) - return -1; - xg_replace_opname (popname, "or"); - arg_strings[2] = (char *) xmalloc (strlen (arg_strings[1]) + 1); - strcpy (arg_strings[2], arg_strings[1]); - *pnum_args = 3; - } - - else if (strcmp (opname, "nop.n") == 0) - { - if (xg_check_num_args (pnum_args, 0, opname, arg_strings)) - return -1; - xg_replace_opname (popname, "or"); - arg_strings[0] = (char *) xmalloc (3); - arg_strings[1] = (char *) xmalloc (3); - arg_strings[2] = (char *) xmalloc (3); - strcpy (arg_strings[0], "a1"); - strcpy (arg_strings[1], "a1"); - strcpy (arg_strings[2], "a1"); - *pnum_args = 3; - } + noperands = xtensa_opcode_num_operands (xtensa_default_isa, opcode); + for (opi = noperands - 1; opi >= 0; opi--) + { + if (xtensa_operand_is_visible (xtensa_default_isa, opcode, opi) == 0) + continue; + if (xtensa_operand_is_PCrelative (xtensa_default_isa, opcode, opi) == 1) + return opi; + if (last_immed == -1 + && xtensa_operand_is_register (xtensa_default_isa, opcode, opi) == 0) + last_immed = opi; } - - return 0; + return last_immed; } - -/* Functions for dealing with the Xtensa ISA. */ - -/* Return true if the given operand is an immed or target instruction, - i.e., has a reloc associated with it. Currently, this is only true - if the operand kind is "i, "l" or "L". */ -static bfd_boolean -operand_is_immed (opnd) - xtensa_operand opnd; +static xtensa_opcode +get_opcode_from_buf (buf, slot) + const char *buf; + int slot; { - const char *opkind = xtensa_operand_kind (opnd); - if (opkind[0] == '\0' || opkind[1] != '\0') - return FALSE; - switch (opkind[0]) + static xtensa_insnbuf insnbuf = NULL; + static xtensa_insnbuf slotbuf = NULL; + xtensa_isa isa = xtensa_default_isa; + xtensa_format fmt; + + if (!insnbuf) { - case 'i': - case 'l': - case 'L': - return TRUE; + insnbuf = xtensa_insnbuf_alloc (isa); + slotbuf = xtensa_insnbuf_alloc (isa); } - return FALSE; -} + xtensa_insnbuf_from_chars (isa, insnbuf, buf, 0); + fmt = xtensa_format_decode (isa, insnbuf); + if (fmt == XTENSA_UNDEFINED) + return XTENSA_UNDEFINED; -/* Return true if the given operand is a pc-relative label. This is - true for "l", "L", and "r" operand kinds. */ + if (slot >= xtensa_format_num_slots (isa, fmt)) + return XTENSA_UNDEFINED; -bfd_boolean -operand_is_pcrel_label (opnd) - xtensa_operand opnd; -{ - const char *opkind = xtensa_operand_kind (opnd); - if (opkind[0] == '\0' || opkind[1] != '\0') - return FALSE; - switch (opkind[0]) - { - case 'r': - case 'l': - case 'L': - return TRUE; - } - return FALSE; + xtensa_format_get_slot (isa, fmt, slot, insnbuf, slotbuf); + return xtensa_opcode_decode (isa, fmt, slot, slotbuf); } -/* Currently the assembler only allows us to use a single target per - fragment. Because of this, only one operand for a given - instruction may be symbolic. If there is an operand of kind "lrL", - the last one is chosen. Otherwise, the result is the number of the - last operand of type "i", and if there are none of those, we fail - and return -1. */ +#ifdef TENSILICA_DEBUG -int -get_relaxable_immed (opcode) - xtensa_opcode opcode; -{ - int last_immed = -1; - int noperands, opi; - xtensa_operand operand; +/* For debugging, print out the mapping of opcode numbers to opcodes. */ - if (opcode == XTENSA_UNDEFINED) - return -1; +void +xtensa_print_insn_table () +{ + int num_opcodes, num_operands; + xtensa_opcode opcode; + xtensa_isa isa = xtensa_default_isa; - noperands = xtensa_num_operands (xtensa_default_isa, opcode); - for (opi = noperands - 1; opi >= 0; opi--) + num_opcodes = xtensa_isa_num_opcodes (xtensa_default_isa); + for (opcode = 0; opcode < num_opcodes; opcode++) { - operand = xtensa_get_operand (xtensa_default_isa, opcode, opi); - if (operand_is_pcrel_label (operand)) - return opi; - if (last_immed == -1 && operand_is_immed (operand)) - last_immed = opi; + int opn; + fprintf (stderr, "%d: %s: ", opcode, xtensa_opcode_name (isa, opcode)); + num_operands = xtensa_opcode_num_operands (isa, opcode); + for (opn = 0; opn < num_operands; opn++) + { + if (xtensa_operand_is_visible (isa, opcode, opn) == 0) + continue; + if (xtensa_operand_is_register (isa, opcode, opn) == 1) + { + xtensa_regfile opnd_rf = + xtensa_operand_regfile (isa, opcode, opn); + fprintf (stderr, "%s ", xtensa_regfile_shortname (isa, opnd_rf)); + } + else if (xtensa_operand_is_PCrelative (isa, opcode, opn) == 1) + fputs ("[lLr] ", stderr); + else + fputs ("i ", stderr); + } + fprintf (stderr, "\n"); } - return last_immed; } -xtensa_opcode -get_opcode_from_buf (buf) - const char *buf; +static void +print_vliw_insn (vbuf) + xtensa_insnbuf vbuf; { - static xtensa_insnbuf insnbuf = NULL; - xtensa_opcode opcode; xtensa_isa isa = xtensa_default_isa; - if (!insnbuf) - insnbuf = xtensa_insnbuf_alloc (isa); - - xtensa_insnbuf_from_chars (isa, insnbuf, buf); - opcode = xtensa_decode_insn (isa, insnbuf); - return opcode; -} - + xtensa_format f = xtensa_format_decode (isa, vbuf); + xtensa_insnbuf sbuf = xtensa_insnbuf_alloc (isa); + int op; -static bfd_boolean -is_direct_call_opcode (opcode) - xtensa_opcode opcode; -{ - if (opcode == XTENSA_UNDEFINED) - return FALSE; + fprintf (stderr, "format = %d\n", f); - return (opcode == xtensa_call0_opcode - || opcode == xtensa_call4_opcode - || opcode == xtensa_call8_opcode - || opcode == xtensa_call12_opcode); + for (op = 0; op < xtensa_format_num_slots (isa, f); op++) + { + xtensa_opcode opcode; + const char *opname; + int operands; + + xtensa_format_get_slot (isa, f, op, vbuf, sbuf); + opcode = xtensa_opcode_decode (isa, f, op, sbuf); + opname = xtensa_opcode_name (isa, opcode); + + fprintf (stderr, "op in slot %i is %s;\n", op, opname); + fprintf (stderr, " operands = "); + for (operands = 0; + operands < xtensa_opcode_num_operands (isa, opcode); + operands++) + { + unsigned int val; + if (xtensa_operand_is_visible (isa, opcode, operands) == 0) + continue; + xtensa_operand_get_field (isa, opcode, operands, f, op, sbuf, &val); + xtensa_operand_decode (isa, opcode, operands, &val); + fprintf (stderr, "%d ", val); + } + fprintf (stderr, "\n"); + } + xtensa_insnbuf_free (isa, sbuf); } +#endif /* TENSILICA_DEBUG */ + static bfd_boolean -is_call_opcode (opcode) +is_direct_call_opcode (opcode) xtensa_opcode opcode; { - if (is_direct_call_opcode (opcode)) - return TRUE; + xtensa_isa isa = xtensa_default_isa; + int n, num_operands; - if (opcode == XTENSA_UNDEFINED) + if (xtensa_opcode_is_call (isa, opcode) == 0) return FALSE; - return (opcode == xtensa_callx0_opcode - || opcode == xtensa_callx4_opcode - || opcode == xtensa_callx8_opcode - || opcode == xtensa_callx12_opcode); + num_operands = xtensa_opcode_num_operands (isa, opcode); + for (n = 0; n < num_operands; n++) + { + if (xtensa_operand_is_register (isa, opcode, n) == 0 + && xtensa_operand_is_PCrelative (isa, opcode, n) == 1) + return TRUE; + } + return FALSE; } -/* Return true if the opcode is an entry opcode. This is used because +/* Return TRUE if the opcode is an entry opcode. This is used because "entry" adds an implicit ".align 4" and also the entry instruction has an extra check for an operand value. */ @@ -2271,20 +3109,18 @@ is_entry_opcode (opcode) } -/* Return true if it is one of the loop opcodes. Loops are special - because they need automatic alignment and they have a relaxation so - complex that we hard-coded it. */ +/* Return TRUE if the opcode is a movi or movi.n opcode. This is + so we can relax "movi aX, foo" in the front end. */ static bfd_boolean -is_loop_opcode (opcode) +is_movi_opcode (opcode) xtensa_opcode opcode; { if (opcode == XTENSA_UNDEFINED) return FALSE; - return (opcode == xtensa_loop_opcode - || opcode == xtensa_loopnez_opcode - || opcode == xtensa_loopgtz_opcode); + return (opcode == xtensa_movi_opcode) + || (opcode == xtensa_movi_n_opcode); } @@ -2310,7 +3146,7 @@ is_jx_opcode (opcode) } -/* Return true if the opcode is a retw or retw.n. +/* Return TRUE if the opcode is a retw or retw.n. Needed to add nops to avoid a hardware interlock issue. */ static bfd_boolean @@ -2324,198 +3160,109 @@ is_windowed_return_opcode (opcode) } -/* Return true if the opcode type is "l" and the opcode is NOT a jump. */ +/* Convert from BFD relocation type code to slot and operand number. + Returns non-zero on failure. */ -static bfd_boolean -is_conditional_branch_opcode (opcode) - xtensa_opcode opcode; +static int +decode_reloc (reloc, slot, is_alt) + bfd_reloc_code_real_type reloc; + int *slot; + bfd_boolean *is_alt; { - xtensa_isa isa = xtensa_default_isa; - int num_ops, i; - - if (opcode == xtensa_j_opcode && opcode != XTENSA_UNDEFINED) - return FALSE; - - num_ops = xtensa_num_operands (isa, opcode); - for (i = 0; i < num_ops; i++) + if (reloc >= BFD_RELOC_XTENSA_SLOT0_OP + && reloc <= BFD_RELOC_XTENSA_SLOT14_OP) { - xtensa_operand operand = xtensa_get_operand (isa, opcode, i); - if (strcmp (xtensa_operand_kind (operand), "l") == 0) - return TRUE; + *slot = reloc - BFD_RELOC_XTENSA_SLOT0_OP; + *is_alt = FALSE; } - return FALSE; -} - - -/* Return true if the given opcode is a conditional branch - instruction, i.e., currently this is true if the instruction - is a jx or has an operand with 'l' type and is not a loop. */ - -bfd_boolean -is_branch_or_jump_opcode (opcode) - xtensa_opcode opcode; -{ - int opn, op_count; - - if (opcode == XTENSA_UNDEFINED) - return FALSE; - - if (is_loop_opcode (opcode)) - return FALSE; - - if (is_jx_opcode (opcode)) - return TRUE; - - op_count = xtensa_num_operands (xtensa_default_isa, opcode); - for (opn = 0; opn < op_count; opn++) + else if (reloc >= BFD_RELOC_XTENSA_SLOT0_ALT + && reloc <= BFD_RELOC_XTENSA_SLOT14_ALT) { - xtensa_operand opnd = - xtensa_get_operand (xtensa_default_isa, opcode, opn); - const char *opkind = xtensa_operand_kind (opnd); - if (opkind && opkind[0] == 'l' && opkind[1] == '\0') - return TRUE; + *slot = reloc - BFD_RELOC_XTENSA_SLOT0_ALT; + *is_alt = TRUE; } - return FALSE; + else + return -1; + + return 0; } -/* Convert from operand numbers to BFD relocation type code. - Return BFD_RELOC_NONE on failure. */ +/* Convert from slot number to BFD relocation type code for the + standard PC-relative relocations. Return BFD_RELOC_NONE on + failure. */ -bfd_reloc_code_real_type -opnum_to_reloc (opnum) - int opnum; +static bfd_reloc_code_real_type +encode_reloc (slot) + int slot; { - switch (opnum) - { - case 0: - return BFD_RELOC_XTENSA_OP0; - case 1: - return BFD_RELOC_XTENSA_OP1; - case 2: - return BFD_RELOC_XTENSA_OP2; - default: - break; - } - return BFD_RELOC_NONE; + if (slot < 0 || slot > 14) + return BFD_RELOC_NONE; + + return BFD_RELOC_XTENSA_SLOT0_OP + slot; } -/* Convert from BFD relocation type code to operand number. - Return -1 on failure. */ +/* Convert from slot numbers to BFD relocation type code for the + "alternate" relocations. Return BFD_RELOC_NONE on failure. */ -int -reloc_to_opnum (reloc) - bfd_reloc_code_real_type reloc; +static bfd_reloc_code_real_type +encode_alt_reloc (slot) + int slot; { - switch (reloc) - { - case BFD_RELOC_XTENSA_OP0: - return 0; - case BFD_RELOC_XTENSA_OP1: - return 1; - case BFD_RELOC_XTENSA_OP2: - return 2; - default: - break; - } - return -1; + if (slot < 0 || slot > 14) + return BFD_RELOC_NONE; + + return BFD_RELOC_XTENSA_SLOT0_ALT + slot; } static void -xtensa_insnbuf_set_operand (insnbuf, opcode, operand, value, file, line) - xtensa_insnbuf insnbuf; +xtensa_insnbuf_set_operand (slotbuf, fmt, slot, opcode, operand, value, + file, line) + xtensa_insnbuf slotbuf; + xtensa_format fmt; + int slot; xtensa_opcode opcode; - xtensa_operand operand; - int32 value; + int operand; + uint32 value; const char *file; unsigned int line; { - xtensa_encode_result encode_result; uint32 valbuf = value; - encode_result = xtensa_operand_encode (operand, &valbuf); - - switch (encode_result) + if (xtensa_operand_encode (xtensa_default_isa, opcode, operand, &valbuf)) { - case xtensa_encode_result_ok: - break; - case xtensa_encode_result_align: - as_bad_where ((char *) file, line, - _("operand %d not properly aligned for '%s'"), - value, xtensa_opcode_name (xtensa_default_isa, opcode)); - break; - case xtensa_encode_result_not_in_table: - as_bad_where ((char *) file, line, - _("operand %d not in immediate table for '%s'"), - value, xtensa_opcode_name (xtensa_default_isa, opcode)); - break; - case xtensa_encode_result_too_high: - as_bad_where ((char *) file, line, - _("operand %d too large for '%s'"), value, - xtensa_opcode_name (xtensa_default_isa, opcode)); - break; - case xtensa_encode_result_too_low: - as_bad_where ((char *) file, line, - _("operand %d too small for '%s'"), value, - xtensa_opcode_name (xtensa_default_isa, opcode)); - break; - case xtensa_encode_result_not_ok: - as_bad_where ((char *) file, line, - _("operand %d is invalid for '%s'"), value, - xtensa_opcode_name (xtensa_default_isa, opcode)); - break; - default: - abort (); + if (xtensa_operand_is_PCrelative (xtensa_default_isa, opcode, operand) + == 1) + as_bad_where ((char *) file, line, + _("operand %u is out of range for '%s'"), value, + xtensa_opcode_name (xtensa_default_isa, opcode)); + else + as_bad_where ((char *) file, line, + _("operand %u is invalid for '%s'"), value, + xtensa_opcode_name (xtensa_default_isa, opcode)); + return; } - xtensa_operand_set_field (operand, insnbuf, valbuf); + xtensa_operand_set_field (xtensa_default_isa, opcode, operand, fmt, slot, + slotbuf, valbuf); } static uint32 -xtensa_insnbuf_get_operand (insnbuf, opcode, opnum) - xtensa_insnbuf insnbuf; +xtensa_insnbuf_get_operand (slotbuf, fmt, slot, opcode, opnum) + xtensa_insnbuf slotbuf; + xtensa_format fmt; + int slot; xtensa_opcode opcode; int opnum; { - xtensa_operand op = xtensa_get_operand (xtensa_default_isa, opcode, opnum); - return xtensa_operand_decode (op, xtensa_operand_get_field (op, insnbuf)); -} - - -static void -xtensa_insnbuf_set_immediate_field (opcode, insnbuf, value, file, line) - xtensa_opcode opcode; - xtensa_insnbuf insnbuf; - int32 value; - const char *file; - unsigned int line; -{ - xtensa_isa isa = xtensa_default_isa; - int last_opnd = xtensa_num_operands (isa, opcode) - 1; - xtensa_operand operand = xtensa_get_operand (isa, opcode, last_opnd); - xtensa_insnbuf_set_operand (insnbuf, opcode, operand, value, file, line); -} - - -static bfd_boolean -is_negatable_branch (insn) - TInsn *insn; -{ - xtensa_isa isa = xtensa_default_isa; - int i; - int num_ops = xtensa_num_operands (isa, insn->opcode); - - for (i = 0; i < num_ops; i++) - { - xtensa_operand opnd = xtensa_get_operand (isa, insn->opcode, i); - char *kind = xtensa_operand_kind (opnd); - if (strlen (kind) == 1 && *kind == 'l') - return TRUE; - } - return FALSE; + uint32 val = 0; + (void) xtensa_operand_get_field (xtensa_default_isa, opcode, opnum, + fmt, slot, slotbuf, &val); + (void) xtensa_operand_decode (xtensa_default_isa, opcode, opnum, &val); + return val; } @@ -2533,21 +3280,12 @@ is_unique_insn_expansion (r) } -static int -xg_get_insn_size (insn) - TInsn *insn; -{ - assert (insn->insn_type == ITYPE_INSN); - return xtensa_insn_length (xtensa_default_isa, insn->opcode); -} - - static int xg_get_build_instr_size (insn) BuildInstr *insn; { assert (insn->typ == INSTR_INSTR); - return xtensa_insn_length (xtensa_default_isa, insn->opcode); + return xg_get_single_size (insn->opcode); } @@ -2555,7 +3293,7 @@ bfd_boolean xg_is_narrow_insn (insn) TInsn *insn; { - TransitionTable *table = xg_build_widen_table (); + TransitionTable *table = xg_build_widen_table (&transition_rule_cmp); TransitionList *l; int num_match = 0; assert (insn->insn_type == ITYPE_INSN); @@ -2571,7 +3309,7 @@ xg_is_narrow_insn (insn) /* It only generates one instruction... */ assert (insn->insn_type == ITYPE_INSN); /* ...and it is a larger instruction. */ - if (xg_get_insn_size (insn) + if (xg_get_single_size (insn->opcode) < xg_get_build_instr_size (rule->to_instr)) { num_match++; @@ -2588,7 +3326,7 @@ bfd_boolean xg_is_single_relaxable_insn (insn) TInsn *insn; { - TransitionTable *table = xg_build_widen_table (); + TransitionTable *table = xg_build_widen_table (&transition_rule_cmp); TransitionList *l; int num_match = 0; assert (insn->insn_type == ITYPE_INSN); @@ -2601,9 +3339,10 @@ xg_is_single_relaxable_insn (insn) if (xg_instruction_matches_rule (insn, rule) && is_unique_insn_expansion (rule)) { + /* It only generates one instruction... */ assert (insn->insn_type == ITYPE_INSN); /* ... and it is a larger instruction. */ - if (xg_get_insn_size (insn) + if (xg_get_single_size (insn->opcode) <= xg_get_build_instr_size (rule->to_instr)) { num_match++; @@ -2616,50 +3355,15 @@ xg_is_single_relaxable_insn (insn) } -/* Return the largest size instruction that this instruction can - expand to. Currently, in all cases, this is 3 bytes. Of course we - could just calculate this once and generate a table. */ - -int -xg_get_max_narrow_insn_size (opcode) - xtensa_opcode opcode; -{ - /* Go ahead and compute it, but it better be 3. */ - TransitionTable *table = xg_build_widen_table (); - TransitionList *l; - int old_size = xtensa_insn_length (xtensa_default_isa, opcode); - assert (opcode < table->num_opcodes); - - /* Actually we can do better. Check to see of Only one applies. */ - for (l = table->table[opcode]; l != NULL; l = l->next) - { - TransitionRule *rule = l->rule; - - /* If it only generates one instruction. */ - if (is_unique_insn_expansion (rule)) - { - int new_size = xtensa_insn_length (xtensa_default_isa, - rule->to_instr->opcode); - if (new_size > old_size) - { - assert (new_size == 3); - return 3; - } - } - } - return old_size; -} - - /* Return the maximum number of bytes this opcode can expand to. */ int xg_get_max_insn_widen_size (opcode) xtensa_opcode opcode; { - TransitionTable *table = xg_build_widen_table (); + TransitionTable *table = xg_build_widen_table (&transition_rule_cmp); TransitionList *l; - int max_size = xtensa_insn_length (xtensa_default_isa, opcode); + int max_size = xg_get_single_size (opcode); assert (opcode < table->num_opcodes); @@ -2683,9 +3387,7 @@ xg_get_max_insn_widen_size (opcode) switch (build_list->typ) { case INSTR_INSTR: - this_size += xtensa_insn_length (xtensa_default_isa, - build_list->opcode); - + this_size += xg_get_single_size (build_list->opcode); break; case INSTR_LITERAL_DEF: case INSTR_LABEL_DEF: @@ -2706,7 +3408,7 @@ int xg_get_max_insn_widen_literal_size (opcode) xtensa_opcode opcode; { - TransitionTable *table = xg_build_widen_table (); + TransitionTable *table = xg_build_widen_table (&transition_rule_cmp); TransitionList *l; int max_size = 0; @@ -2732,7 +3434,7 @@ xg_get_max_insn_widen_literal_size (opcode) switch (build_list->typ) { case INSTR_LITERAL_DEF: - /* hard coded 4-byte literal. */ + /* Hard-coded 4-byte literal. */ this_size += 4; break; case INSTR_INSTR: @@ -2754,7 +3456,7 @@ xg_is_relaxable_insn (insn, lateral_steps) int lateral_steps; { int steps_taken = 0; - TransitionTable *table = xg_build_widen_table (); + TransitionTable *table = xg_build_widen_table (&transition_rule_cmp); TransitionList *l; assert (insn->insn_type == ITYPE_INSN); @@ -2797,7 +3499,7 @@ get_special_label_symbol () } -/* Return true on success. */ +/* Return TRUE on success. */ bfd_boolean xg_build_to_insn (targ, insn, bi) @@ -2809,6 +3511,7 @@ xg_build_to_insn (targ, insn, bi) symbolS *sym; memset (targ, 0, sizeof (TInsn)); + targ->loc = insn->loc; switch (bi->typ) { case INSTR_INSTR: @@ -2844,6 +3547,38 @@ xg_build_to_insn (targ, insn, bi) sym = get_special_label_symbol (); set_expr_symbol_offset (&targ->tok[op_num], sym, 0); break; + case OP_OPERAND_HI16U: + case OP_OPERAND_LOW16U: + assert (op_data < insn->ntok); + if (expr_is_const (&insn->tok[op_data])) + { + long val; + copy_expr (&targ->tok[op_num], &insn->tok[op_data]); + val = xg_apply_userdef_op_fn (op->typ, + targ->tok[op_num]. + X_add_number); + targ->tok[op_num].X_add_number = val; + } + else + { + /* For const16 we can create relocations for these. */ + if (targ->opcode == XTENSA_UNDEFINED + || (targ->opcode != xtensa_const16_opcode)) + return FALSE; + assert (op_data < insn->ntok); + /* Need to build a O_lo16 or O_hi16. */ + copy_expr (&targ->tok[op_num], &insn->tok[op_data]); + if (targ->tok[op_num].X_op == O_symbol) + { + if (op->typ == OP_OPERAND_HI16U) + targ->tok[op_num].X_op = O_hi16; + else if (op->typ == OP_OPERAND_LOW16U) + targ->tok[op_num].X_op = O_lo16; + else + return FALSE; + } + } + break; default: /* currently handles: OP_OPERAND_LOW8 @@ -2889,6 +3624,9 @@ xg_build_to_insn (targ, insn, bi) { case OP_OPERAND: assert (op_data < insn->ntok); + /* We can only pass resolvable literals through. */ + if (!xg_valid_literal_expression (&insn->tok[op_data])) + return FALSE; copy_expr (&targ->tok[op_num], &insn->tok[op_data]); break; case OP_LITERAL: @@ -2906,7 +3644,7 @@ xg_build_to_insn (targ, insn, bi) targ->opcode = XTENSA_UNDEFINED; targ->insn_type = ITYPE_LABEL; targ->is_specific_opcode = FALSE; - /* Literal with no ops. is a label? */ + /* Literal with no ops is a label? */ assert (op == NULL); break; @@ -2918,7 +3656,7 @@ xg_build_to_insn (targ, insn, bi) } -/* Return true on success. */ +/* Return TRUE on success. */ bfd_boolean xg_build_to_stack (istack, insn, bi) @@ -2937,7 +3675,7 @@ xg_build_to_stack (istack, insn, bi) } -/* Return true on valid expansion. */ +/* Return TRUE on valid expansion. */ bfd_boolean xg_expand_to_stack (istack, insn, lateral_steps) @@ -2947,7 +3685,7 @@ xg_expand_to_stack (istack, insn, lateral_steps) { int stack_size = istack->ninsn; int steps_taken = 0; - TransitionTable *table = xg_build_widen_table (); + TransitionTable *table = xg_build_widen_table (&transition_rule_cmp); TransitionList *l; assert (insn->insn_type == ITYPE_INSN); @@ -2994,7 +3732,7 @@ xg_expand_narrow (targ, insn) TInsn *targ; TInsn *insn; { - TransitionTable *table = xg_build_widen_table (); + TransitionTable *table = xg_build_widen_table (&transition_rule_cmp); TransitionList *l; assert (insn->insn_type == ITYPE_INSN); @@ -3007,7 +3745,7 @@ xg_expand_narrow (targ, insn) && is_unique_insn_expansion (rule)) { /* Is it a larger instruction? */ - if (xg_get_insn_size (insn) + if (xg_get_single_size (insn->opcode) <= xg_get_build_instr_size (rule->to_instr)) { xg_build_to_insn (targ, insn, rule->to_instr); @@ -3020,12 +3758,13 @@ xg_expand_narrow (targ, insn) /* Assumes: All immeds are constants. Check that all constants fit - into their immeds; return false if not. */ + into their immeds; return FALSE if not. */ static bfd_boolean xg_immeds_fit (insn) const TInsn *insn; { + xtensa_isa isa = xtensa_default_isa; int i; int n = insn->ntok; @@ -3033,20 +3772,17 @@ xg_immeds_fit (insn) for (i = 0; i < n; ++i) { const expressionS *expr = &insn->tok[i]; - xtensa_operand opnd = xtensa_get_operand (xtensa_default_isa, - insn->opcode, i); - if (!operand_is_immed (opnd)) + if (xtensa_operand_is_register (isa, insn->opcode, i) == 1) continue; switch (expr->X_op) { case O_register: case O_constant: - { - if (xg_check_operand (expr->X_add_number, opnd)) - return FALSE; - } + if (xg_check_operand (expr->X_add_number, insn->opcode, i)) + return FALSE; break; + default: /* The symbol should have a fixup associated with it. */ assert (FALSE); @@ -3068,8 +3804,11 @@ xg_symbolic_immeds_fit (insn, pc_seg, pc_frag, pc_offset, stretch) offsetT pc_offset; long stretch; { + xtensa_isa isa = xtensa_default_isa; symbolS *symbolP; - offsetT target, pc, new_offset; + fragS *sym_frag; + offsetT target, pc; + uint32 new_offset; int i; int n = insn->ntok; @@ -3078,16 +3817,21 @@ xg_symbolic_immeds_fit (insn, pc_seg, pc_frag, pc_offset, stretch) for (i = 0; i < n; ++i) { const expressionS *expr = &insn->tok[i]; - xtensa_operand opnd = xtensa_get_operand (xtensa_default_isa, - insn->opcode, i); - if (!operand_is_immed (opnd)) + if (xtensa_operand_is_register (isa, insn->opcode, i) == 1) continue; switch (expr->X_op) { case O_register: case O_constant: - if (xg_check_operand (expr->X_add_number, opnd)) + if (xg_check_operand (expr->X_add_number, insn->opcode, i)) + return FALSE; + break; + + case O_lo16: + case O_hi16: + /* Check for the worst case. */ + if (xg_check_operand (0xffff, insn->opcode, i)) return FALSE; break; @@ -3097,13 +3841,21 @@ xg_symbolic_immeds_fit (insn, pc_seg, pc_frag, pc_offset, stretch) if (pc_frag == 0) return FALSE; - /* If it is PC-relative and the symbol is in the same segment as - the PC.... */ - if (!xtensa_operand_isPCRelative (opnd) + /* If it is PC-relative and the symbol is not in the same + segment as the PC.... */ + if (xtensa_operand_is_PCrelative (isa, insn->opcode, i) == 0 || S_GET_SEGMENT (expr->X_add_symbol) != pc_seg) return FALSE; + /* If it is a weak symbol, then assume it won't reach. This will + only affect calls when longcalls are enabled, because if + longcalls are disabled, then the call is marked as a specific + opcode. */ + if (S_IS_WEAK (expr->X_add_symbol)) + return FALSE; + symbolP = expr->X_add_symbol; + sym_frag = symbol_get_frag (symbolP); target = S_GET_VALUE (symbolP) + expr->X_add_number; pc = pc_frag->fr_address + pc_offset; @@ -3113,11 +3865,16 @@ xg_symbolic_immeds_fit (insn, pc_seg, pc_frag, pc_offset, stretch) force another pass. Beware zero-length frags. There should be a faster way to do this. */ - if (stretch && is_dnrange (pc_frag, symbolP, stretch)) - target += stretch; - - new_offset = xtensa_operand_do_reloc (opnd, target, pc); - if (xg_check_operand (new_offset, opnd)) + if (stretch != 0 + && sym_frag->relax_marker != pc_frag->relax_marker + && S_GET_SEGMENT (symbolP) == pc_seg) + { + target += stretch; + } + + new_offset = target; + xtensa_operand_do_reloc (isa, insn->opcode, i, &new_offset, pc); + if (xg_check_operand (new_offset, insn->opcode, i)) return FALSE; break; @@ -3132,82 +3889,24 @@ xg_symbolic_immeds_fit (insn, pc_seg, pc_frag, pc_offset, stretch) /* This will check to see if the value can be converted into the - operand type. It will return true if it does not fit. */ + operand type. It will return TRUE if it does not fit. */ static bfd_boolean -xg_check_operand (value, operand) +xg_check_operand (value, opcode, operand) int32 value; - xtensa_operand operand; + xtensa_opcode opcode; + int operand; { uint32 valbuf = value; - return (xtensa_operand_encode (operand, &valbuf) != xtensa_encode_result_ok); + if (xtensa_operand_encode (xtensa_default_isa, opcode, operand, &valbuf)) + return TRUE; + return FALSE; } + -/* Check if a symbol is pointing to somewhere after - the start frag, given that the segment has stretched - by stretch during relaxation. - - This is more complicated than it might appear at first blush - because of the stretching that goes on. Here is how the check - works: - - If the symbol and the frag are in the same segment, then - the symbol could be down range. Note that this function - assumes that start_frag is in now_seg. - - If the symbol is pointing to a frag with an address greater than - than the start_frag's address, then it _could_ be down range. - - The problem comes because target_frag may or may not have had - stretch bytes added to its address already, depending on if it is - before or after start frag. (And if we knew that, then we wouldn't - need this function.) start_frag has definitely already had stretch - bytes added to its address. - - If target_frag's address hasn't been adjusted yet, then to - determine if it comes after start_frag, we need to subtract - stretch from start_frag's address. - - If target_frag's address has been adjusted, then it might have - been adjusted such that it comes after start_frag's address minus - stretch bytes. - - So, in that case, we scan for it down stream to within - stretch bytes. We could search to the end of the fr_chain, but - that ends up taking too much time (over a minute on some gnu - tests). */ - -int -is_dnrange (start_frag, sym, stretch) - fragS *start_frag; - symbolS *sym; - long stretch; -{ - if (S_GET_SEGMENT (sym) == now_seg) - { - fragS *cur_frag = symbol_get_frag (sym); - - if (cur_frag->fr_address >= start_frag->fr_address - stretch) - { - int distance = stretch; - - while (cur_frag && distance >= 0) - { - distance -= cur_frag->fr_fix; - if (cur_frag == start_frag) - return 0; - cur_frag = cur_frag->fr_next; - } - return 1; - } - } - return 0; -} - - -/* Relax the assembly instruction at least "min_steps". - Return the number of steps taken. */ +/* Relax the assembly instruction at least "min_steps". + Return the number of steps taken. */ int xg_assembly_relax (istack, insn, pc_seg, pc_frag, pc_offset, min_steps, @@ -3215,10 +3914,10 @@ xg_assembly_relax (istack, insn, pc_seg, pc_frag, pc_offset, min_steps, IStack *istack; TInsn *insn; segT pc_seg; - fragS *pc_frag; /* If pc_frag == 0, then no pc-relative. */ - offsetT pc_offset; /* Offset in fragment. */ - int min_steps; /* Minimum number of conversion steps. */ - long stretch; /* Number of bytes stretched so far. */ + fragS *pc_frag; /* if pc_frag == 0, then no pc-relative */ + offsetT pc_offset; /* offset in fragment */ + int min_steps; /* minimum number of conversion steps */ + long stretch; /* number of bytes stretched so far */ { int steps_taken = 0; @@ -3240,7 +3939,7 @@ xg_assembly_relax (istack, insn, pc_seg, pc_frag, pc_offset, min_steps, istack_push (istack, insn); return steps_taken; } - tinsn_copy (¤t_insn, insn); + current_insn = *insn; /* Walk through all of the single instruction expansions. */ while (xg_is_single_relaxable_insn (¤t_insn)) @@ -3259,7 +3958,7 @@ xg_assembly_relax (istack, insn, pc_seg, pc_frag, pc_offset, min_steps, return steps_taken; } } - tinsn_copy (¤t_insn, &single_target); + current_insn = single_target; } /* Now check for a multi-instruction expansion. */ @@ -3302,9 +4001,10 @@ xg_force_frag_space (size) void -xg_finish_frag (last_insn, state, max_growth, is_insn) +xg_finish_frag (last_insn, frag_state, slot0_state, max_growth, is_insn) char *last_insn; - enum xtensa_relax_statesE state; + enum xtensa_relax_statesE frag_state; + enum xtensa_relax_statesE slot0_state; int max_growth; bfd_boolean is_insn; { @@ -3314,6 +4014,7 @@ xg_finish_frag (last_insn, state, max_growth, is_insn) beginning of the growth area. */ fragS *old_frag; + xg_force_frag_space (max_growth); old_frag = frag_now; @@ -3323,7 +4024,10 @@ xg_finish_frag (last_insn, state, max_growth, is_insn) frag_now->tc_frag_data.is_insn = TRUE; frag_var (rs_machine_dependent, max_growth, max_growth, - state, frag_now->fr_symbol, frag_now->fr_offset, last_insn); + frag_state, frag_now->fr_symbol, frag_now->fr_offset, last_insn); + + old_frag->tc_frag_data.slot_subtypes[0] = slot0_state; + xtensa_set_frag_assembly_state (frag_now); /* Just to make sure that we did not split it up. */ assert (old_frag->fr_next == frag_now); @@ -3337,19 +4041,18 @@ is_branch_jmp_to_next (insn, fragP) { xtensa_isa isa = xtensa_default_isa; int i; - int num_ops = xtensa_num_operands (isa, insn->opcode); + int num_ops = xtensa_opcode_num_operands (isa, insn->opcode); int target_op = -1; symbolS *sym; fragS *target_frag; - if (is_loop_opcode (insn->opcode)) + if (xtensa_opcode_is_branch (isa, insn->opcode) == 0 + && xtensa_opcode_is_jump (isa, insn->opcode) == 0) return FALSE; for (i = 0; i < num_ops; i++) { - xtensa_operand opnd = xtensa_get_operand (isa, insn->opcode, i); - char *kind = xtensa_operand_kind (opnd); - if (strlen (kind) == 1 && *kind == 'l') + if (xtensa_operand_is_PCrelative (isa, insn->opcode, i) == 1) { target_op = i; break; @@ -3388,32 +4091,25 @@ xg_add_branch_and_loop_targets (insn) TInsn *insn; { xtensa_isa isa = xtensa_default_isa; - int num_ops = xtensa_num_operands (isa, insn->opcode); + int num_ops = xtensa_opcode_num_operands (isa, insn->opcode); - if (is_loop_opcode (insn->opcode)) + if (xtensa_opcode_is_loop (isa, insn->opcode) == 1) { int i = 1; - xtensa_operand opnd = xtensa_get_operand (isa, insn->opcode, i); - char *kind = xtensa_operand_kind (opnd); - if (strlen (kind) == 1 && *kind == 'l') - if (insn->tok[i].X_op == O_symbol) - symbol_get_tc (insn->tok[i].X_add_symbol)->is_loop_target = TRUE; + if (xtensa_operand_is_PCrelative (isa, insn->opcode, i) == 1 + && insn->tok[i].X_op == O_symbol) + symbol_get_tc (insn->tok[i].X_add_symbol)->is_loop_target = TRUE; return; } - /* Currently, we do not add branch targets. This is an optimization - for later that tries to align only branch targets, not just any - label in a text section. */ - - if (align_only_targets) + if (xtensa_opcode_is_branch (isa, insn->opcode) == 1 + || xtensa_opcode_is_loop (isa, insn->opcode) == 1) { int i; for (i = 0; i < insn->ntok && i < num_ops; i++) { - xtensa_operand opnd = xtensa_get_operand (isa, insn->opcode, i); - char *kind = xtensa_operand_kind (opnd); - if (strlen (kind) == 1 && *kind == 'l' + if (xtensa_operand_is_PCrelative (isa, insn->opcode, i) == 1 && insn->tok[i].X_op == O_symbol) { symbolS *sym = insn->tok[i].X_add_symbol; @@ -3426,6 +4122,68 @@ xg_add_branch_and_loop_targets (insn) } +/* The routine xg_instruction_matches_option_term must return TRUE + when a given option term is true. The meaning of all of the option + terms is given interpretation by this function. This is needed when + an option depends on the state of a directive, but there are no such + options in use right now. */ + +bfd_boolean +xg_instruction_matches_option_term (insn, option) + TInsn *insn ATTRIBUTE_UNUSED; + const ReqOrOption *option; +{ + if (strcmp (option->option_name, "realnop") == 0 + || strncmp (option->option_name, "IsaUse", 6) == 0) + { + /* These conditions were evaluated statically when building the + relaxation table. There's no need to reevaluate them now. */ + return TRUE; + } + else + { + as_fatal (_("internal error: unknown option name '%s'"), + option->option_name); + } +} + + +bfd_boolean +xg_instruction_matches_or_options (insn, or_option) + TInsn *insn; + const ReqOrOptionList *or_option; +{ + const ReqOrOption *option; + /* Must match each of the AND terms. */ + for (option = or_option; option != NULL; option = option->next) + { + if (xg_instruction_matches_option_term (insn, option)) + return TRUE; + } + return FALSE; +} + + +bfd_boolean +xg_instruction_matches_options (insn, options) + TInsn *insn; + const ReqOptionList *options; +{ + const ReqOption *req_options; + /* Must match each of the AND terms. */ + for (req_options = options; + req_options != NULL; + req_options = req_options->next) + { + /* Must match one of the OR clauses. */ + if (!xg_instruction_matches_or_options (insn, + req_options->or_option_terms)) + return FALSE; + } + return TRUE; +} + + /* Return the transition rule that matches or NULL if none matches. */ bfd_boolean @@ -3452,19 +4210,40 @@ xg_instruction_matches_rule (insn, rule) /* The expression must be the constant. */ assert (cond->op_num < insn->ntok); exp1 = &insn->tok[cond->op_num]; - if (!expr_is_const (exp1)) - return FALSE; - switch (cond->cmp) + if (expr_is_const (exp1)) { - case OP_EQUAL: - if (get_expr_const (exp1) != cond->op_data) - return FALSE; - break; - case OP_NOTEQUAL: - if (get_expr_const (exp1) == cond->op_data) - return FALSE; - break; + switch (cond->cmp) + { + case OP_EQUAL: + if (get_expr_const (exp1) != cond->op_data) + return FALSE; + break; + case OP_NOTEQUAL: + if (get_expr_const (exp1) == cond->op_data) + return FALSE; + break; + default: + return FALSE; + } + } + else if (expr_is_register (exp1)) + { + switch (cond->cmp) + { + case OP_EQUAL: + if (get_expr_register (exp1) != cond->op_data) + return FALSE; + break; + case OP_NOTEQUAL: + if (get_expr_register (exp1) == cond->op_data) + return FALSE; + break; + default: + return FALSE; + } } + else + return FALSE; break; case OP_OPERAND: @@ -3492,15 +4271,87 @@ xg_instruction_matches_rule (insn, rule) return FALSE; } } + if (!xg_instruction_matches_options (insn, rule->options)) + return FALSE; + return TRUE; } +static int +transition_rule_cmp (a, b) + const TransitionRule *a; + const TransitionRule *b; +{ + bfd_boolean a_greater = FALSE; + bfd_boolean b_greater = FALSE; + + ReqOptionList *l_a = a->options; + ReqOptionList *l_b = b->options; + + /* We only care if they both are the same except for + a const16 vs. an l32r. */ + + while (l_a && l_b && ((l_a->next == NULL) == (l_b->next == NULL))) + { + ReqOrOptionList *l_or_a = l_a->or_option_terms; + ReqOrOptionList *l_or_b = l_b->or_option_terms; + while (l_or_a && l_or_b && ((l_a->next == NULL) == (l_b->next == NULL))) + { + if (l_or_a->is_true != l_or_b->is_true) + return 0; + if (strcmp (l_or_a->option_name, l_or_b->option_name) != 0) + { + /* This is the case we care about. */ + if (strcmp (l_or_a->option_name, "IsaUseConst16") == 0 + && strcmp (l_or_b->option_name, "IsaUseL32R") == 0) + { + if (prefer_const16) + a_greater = TRUE; + else + b_greater = TRUE; + } + else if (strcmp (l_or_a->option_name, "IsaUseL32R") == 0 + && strcmp (l_or_b->option_name, "IsaUseConst16") == 0) + { + if (prefer_const16) + b_greater = TRUE; + else + a_greater = TRUE; + } + else + return 0; + } + l_or_a = l_or_a->next; + l_or_b = l_or_b->next; + } + if (l_or_a || l_or_b) + return 0; + + l_a = l_a->next; + l_b = l_b->next; + } + if (l_a || l_b) + return 0; + + /* Incomparable if the substitution was used differently in two cases. */ + if (a_greater && b_greater) + return 0; + + if (b_greater) + return 1; + if (a_greater) + return -1; + + return 0; +} + + TransitionRule * xg_instruction_match (insn) TInsn *insn; { - TransitionTable *table = xg_build_simplify_table (); + TransitionTable *table = xg_build_simplify_table (&transition_rule_cmp); TransitionList *l; assert (insn->opcode < table->num_opcodes); @@ -3515,7 +4366,7 @@ xg_instruction_match (insn) } -/* Return false if no error. */ +/* Return FALSE if no error. */ bfd_boolean xg_build_token_insn (instr_spec, old_insn, new_insn) @@ -3532,11 +4383,13 @@ xg_build_token_insn (instr_spec, old_insn, new_insn) new_insn->insn_type = ITYPE_INSN; new_insn->opcode = instr_spec->opcode; new_insn->is_specific_opcode = FALSE; + new_insn->loc = old_insn->loc; break; case INSTR_LITERAL_DEF: new_insn->insn_type = ITYPE_LITERAL; new_insn->opcode = XTENSA_UNDEFINED; new_insn->is_specific_opcode = FALSE; + new_insn->loc = old_insn->loc; break; case INSTR_LABEL_DEF: as_bad (_("INSTR_LABEL_DEF not supported yet")); @@ -3582,15 +4435,20 @@ xg_build_token_insn (instr_spec, old_insn, new_insn) } -/* Return true if it was simplified. */ +/* Return TRUE if it was simplified. */ bfd_boolean xg_simplify_insn (old_insn, new_insn) TInsn *old_insn; TInsn *new_insn; { - TransitionRule *rule = xg_instruction_match (old_insn); + TransitionRule *rule; BuildInstr *insn_spec; + + if (old_insn->is_specific_opcode || !density_supported) + return FALSE; + + rule = xg_instruction_match (old_insn); if (rule == NULL) return FALSE; @@ -3610,7 +4468,7 @@ xg_simplify_insn (old_insn, new_insn) /* xg_expand_assembly_insn: (1) Simplify the instruction, i.e., l32i -> l32i.n. (2) Check the number of operands. (3) Place the instruction tokens into the stack or if we can relax it at assembly time, place - multiple instructions/literals onto the stack. Return false if no + multiple instructions/literals onto the stack. Return FALSE if no error. */ static bfd_boolean @@ -3622,15 +4480,13 @@ xg_expand_assembly_insn (istack, orig_insn) TInsn new_insn; memset (&new_insn, 0, sizeof (TInsn)); - /* On return, we will be using the "use_tokens" with "use_ntok". - This will reduce things like addi to addi.n. */ - if (code_density_available () && !orig_insn->is_specific_opcode) - { - if (xg_simplify_insn (orig_insn, &new_insn)) - orig_insn = &new_insn; - } + /* Narrow it if we can. xg_simplify_insn now does all the + appropriate checking (e.g., for the density option). */ + if (xg_simplify_insn (orig_insn, &new_insn)) + orig_insn = &new_insn; - noperands = xtensa_num_operands (xtensa_default_isa, orig_insn->opcode); + noperands = xtensa_opcode_num_operands (xtensa_default_isa, + orig_insn->opcode); if (orig_insn->ntok < noperands) { as_bad (_("found %d operands for '%s': Expected %d"), @@ -3645,12 +4501,12 @@ xg_expand_assembly_insn (istack, orig_insn) xtensa_opcode_name (xtensa_default_isa, orig_insn->opcode), noperands); - /* If there are not enough operands, we will assert above. If there + /* If there are not enough operands, we will assert above. If there are too many, just cut out the extras here. */ orig_insn->ntok = noperands; - /* Cases: + /* Cases: Instructions with all constant immeds: Assemble them and relax the instruction if possible. @@ -3658,20 +4514,20 @@ xg_expand_assembly_insn (istack, orig_insn) Instructions with symbolic immeds: Assemble them with a Fix up (that may cause instruction expansion). - Also close out the fragment if the fixup may cause instruction expansion. - + Also close out the fragment if the fixup may cause instruction expansion. + There are some other special cases where we need alignment. 1) before certain instructions with required alignment (OPCODE_ALIGN) 2) before labels that have jumps (LABEL_ALIGN) 3) after call instructions (RETURN_ALIGN) - Multiple of these may be possible on the same fragment. - If so, make sure to satisfy the required alignment. + Multiple of these may be possible on the same fragment. + If so, make sure to satisfy the required alignment. Then try to get the desired alignment. */ if (tinsn_has_invalid_symbolic_operands (orig_insn)) return TRUE; - if (orig_insn->is_specific_opcode || !can_relax ()) + if (orig_insn->is_specific_opcode || !use_transform ()) { istack_push (istack, orig_insn); return FALSE; @@ -3692,14 +4548,6 @@ xg_expand_assembly_insn (istack, orig_insn) xg_assembly_relax (istack, orig_insn, 0, 0, 0, 0, 0); } -#if 0 - for (i = 0; i < istack->ninsn; i++) - { - if (xg_simplify_insn (&new_insn, &istack->insn[i])) - istack->insn[i] = new_insn; - } -#endif - return FALSE; } @@ -3718,6 +4566,8 @@ xg_assemble_literal (insn) offsetT litsize = 4; offsetT litalign = 2; /* 2^2 = 4 */ expressionS saved_loc; + expressionS * emit_val; + set_expr_symbol_offset (&saved_loc, frag_now->fr_symbol, frag_now_fix ()); assert (insn->insn_type == ITYPE_LITERAL); @@ -3725,12 +4575,39 @@ xg_assemble_literal (insn) xtensa_switch_to_literal_fragment (&state); + emit_val = &insn->tok[0]; + if (emit_val->X_op == O_big) + { + int size = emit_val->X_add_number * CHARS_PER_LITTLENUM; + if (size > litsize) + { + /* This happens when someone writes a "movi a2, big_number". */ + as_bad_where (frag_now->fr_file, frag_now->fr_line, + _("invalid immediate")); + xtensa_restore_emit_state (&state); + return NULL; + } + } + /* Force a 4-byte align here. Note that this opens a new frag, so all literals done with this function have a frag to themselves. That's important for the way text section literals work. */ frag_align (litalign, 0, 0); + record_alignment (now_seg, litalign); - emit_expr (&insn->tok[0], litsize); + if (emit_val->X_op == O_pltrel) + { + char *p = frag_more (litsize); + xtensa_set_frag_assembly_state (frag_now); + if (emit_val->X_add_symbol) + emit_val->X_op = O_symbol; + else + emit_val->X_op = O_constant; + fix_new_exp (frag_now, p - frag_now->fr_literal, + litsize, emit_val, 0, BFD_RELOC_XTENSA_PLT); + } + else + emit_expr (emit_val, litsize); assert (frag_now->tc_frag_data.literal_frag == NULL); frag_now->tc_frag_data.literal_frag = get_literal_pool_location (now_seg); @@ -3744,25 +4621,43 @@ xg_assemble_literal (insn) } +bfd_boolean +xg_valid_literal_expression (exp) + const expressionS *exp; +{ + switch (exp->X_op) + { + case O_constant: + case O_symbol: + case O_big: + case O_uminus: + case O_subtract: + case O_pltrel: + return TRUE; + default: + return FALSE; + } +} + + static void -xg_assemble_literal_space (size) +xg_assemble_literal_space (size, slot) /* const */ int size; + int slot; { emit_state state; - /* We might have to do something about this alignment. It only + /* We might have to do something about this alignment. It only takes effect if something is placed here. */ offsetT litalign = 2; /* 2^2 = 4 */ fragS *lit_saved_frag; - expressionS saved_loc; - assert (size % 4 == 0); - set_expr_symbol_offset (&saved_loc, frag_now->fr_symbol, frag_now_fix ()); xtensa_switch_to_literal_fragment (&state); /* Force a 4-byte align here. */ frag_align (litalign, 0, 0); + record_alignment (now_seg, litalign); xg_force_frag_space (size); @@ -3770,11 +4665,11 @@ xg_assemble_literal_space (size) frag_now->tc_frag_data.literal_frag = get_literal_pool_location (now_seg); frag_now->tc_frag_data.is_literal = TRUE; frag_now->fr_symbol = xtensa_create_literal_symbol (now_seg, frag_now); - xg_finish_frag (0, RELAX_LITERAL, size, FALSE); + xg_finish_frag (0, RELAX_LITERAL, 0, size, FALSE); /* Go back. */ xtensa_restore_emit_state (&state); - frag_now->tc_frag_data.literal_frag = lit_saved_frag; + frag_now->tc_frag_data.literal_frags[slot] = lit_saved_frag; } @@ -3854,7 +4749,7 @@ xtensa_clear_insn_labels (void) } -/* Return true if the section flags are marked linkonce +/* Return TRUE if the section flags are marked linkonce or the name is .gnu.linkonce*. */ bfd_boolean @@ -3879,113 +4774,10 @@ get_is_linkonce_section (abfd, sec) } -/* Emit an instruction to the current fragment. If record_fix is true, - then this instruction will not change and we can go ahead and record - the fixup. If record_fix is false, then the instruction may change - and we are going to close out this fragment. Go ahead and set the - fr_symbol and fr_offset instead of adding a fixup. */ - -static bfd_boolean -xg_emit_insn (t_insn, record_fix) - TInsn *t_insn; - bfd_boolean record_fix; -{ - bfd_boolean ok = TRUE; - xtensa_isa isa = xtensa_default_isa; - xtensa_opcode opcode = t_insn->opcode; - bfd_boolean has_fixup = FALSE; - int noperands; - int i, byte_count; - fragS *oldfrag; - size_t old_size; - char *f; - static xtensa_insnbuf insnbuf = NULL; - - /* Use a static pointer to the insn buffer so we don't have to call - malloc each time through. */ - if (!insnbuf) - insnbuf = xtensa_insnbuf_alloc (xtensa_default_isa); - - has_fixup = tinsn_to_insnbuf (t_insn, insnbuf); - - noperands = xtensa_num_operands (isa, opcode); - assert (noperands == t_insn->ntok); - - byte_count = xtensa_insn_length (isa, opcode); - oldfrag = frag_now; - /* This should NEVER cause us to jump into a new frag; - we've already reserved space. */ - old_size = frag_now_fix (); - f = frag_more (byte_count); - assert (oldfrag == frag_now); - - /* This needs to generate a record that lists the parts that are - instructions. */ - if (!frag_now->tc_frag_data.is_insn) - { - /* If we are at the beginning of a fragment, switch this - fragment to an instruction fragment. */ - if (now_seg != absolute_section && old_size != 0) - as_warn (_("instruction fragment may contain data")); - frag_now->tc_frag_data.is_insn = TRUE; - } - - xtensa_insnbuf_to_chars (isa, insnbuf, f); - - dwarf2_emit_insn (byte_count); - - /* Now spit out the opcode fixup.... */ - if (!has_fixup) - return !ok; - - for (i = 0; i < noperands; ++i) - { - expressionS *expr = &t_insn->tok[i]; - switch (expr->X_op) - { - case O_symbol: - if (get_relaxable_immed (opcode) == i) - { - if (record_fix) - { - if (!xg_add_opcode_fix (opcode, i, expr, frag_now, - f - frag_now->fr_literal)) - ok = FALSE; - } - else - { - /* Write it to the fr_offset, fr_symbol. */ - frag_now->fr_symbol = expr->X_add_symbol; - frag_now->fr_offset = expr->X_add_number; - } - } - else - { - as_bad (_("invalid operand %d on '%s'"), - i, xtensa_opcode_name (isa, opcode)); - ok = FALSE; - } - break; - - case O_constant: - case O_register: - break; - - default: - as_bad (_("invalid expression for operand %d on '%s'"), - i, xtensa_opcode_name (isa, opcode)); - ok = FALSE; - break; - } - } - - return !ok; -} - - static bfd_boolean -xg_emit_insn_to_buf (t_insn, buf, fragP, offset, build_fix) - TInsn *t_insn; +xg_emit_insn_to_buf (tinsn, fmt, buf, fragP, offset, build_fix) + TInsn *tinsn; + xtensa_format fmt; char *buf; fragS *fragP; offsetT offset; @@ -3997,63 +4789,109 @@ xg_emit_insn_to_buf (t_insn, buf, fragP, offset, build_fix) if (!insnbuf) insnbuf = xtensa_insnbuf_alloc (xtensa_default_isa); - has_symbolic_immed = tinsn_to_insnbuf (t_insn, insnbuf); + has_symbolic_immed = tinsn_to_insnbuf (tinsn, insnbuf); if (has_symbolic_immed && build_fix) { /* Add a fixup. */ - int opnum = get_relaxable_immed (t_insn->opcode); - expressionS *exp = &t_insn->tok[opnum]; + int opnum = get_relaxable_immed (tinsn->opcode); + expressionS *exp = &tinsn->tok[opnum]; - if (!xg_add_opcode_fix (t_insn->opcode, - opnum, exp, fragP, offset)) + if (!xg_add_opcode_fix (tinsn, opnum, fmt, 0, exp, fragP, offset)) ok = FALSE; } fragP->tc_frag_data.is_insn = TRUE; - xtensa_insnbuf_to_chars (xtensa_default_isa, insnbuf, buf); + xtensa_insnbuf_to_chars (xtensa_default_isa, insnbuf, buf, 0); return ok; } /* Put in a fixup record based on the opcode. - Return true on success. */ + Return TRUE on success. */ bfd_boolean -xg_add_opcode_fix (opcode, opnum, expr, fragP, offset) - xtensa_opcode opcode; +xg_add_opcode_fix (tinsn, opnum, fmt, slot, expr, fragP, offset) + TInsn *tinsn; int opnum; + xtensa_format fmt; + int slot; expressionS *expr; fragS *fragP; offsetT offset; -{ - bfd_reloc_code_real_type reloc; - reloc_howto_type *howto; - int insn_length; +{ + xtensa_opcode opcode = tinsn->opcode; + bfd_reloc_code_real_type reloc; + reloc_howto_type *howto; + int fmt_length; fixS *the_fix; - reloc = opnum_to_reloc (opnum); - if (reloc == BFD_RELOC_NONE) + reloc = BFD_RELOC_NONE; + + /* First try the special cases for "alternate" relocs. */ + if (opcode == xtensa_l32r_opcode) + { + if (fragP->tc_frag_data.use_absolute_literals) + reloc = encode_alt_reloc (slot); + } + else if (opcode == xtensa_const16_opcode) + { + if (expr->X_op == O_lo16) + { + reloc = encode_reloc (slot); + expr->X_op = O_symbol; + } + else if (expr->X_op == O_hi16) + { + reloc = encode_alt_reloc (slot); + expr->X_op = O_symbol; + } + } + + if (opnum != get_relaxable_immed (opcode)) { - as_bad (_("invalid relocation operand %i on '%s'"), + as_bad (_("invalid relocation for operand %i of '%s'"), opnum, xtensa_opcode_name (xtensa_default_isa, opcode)); return FALSE; } - howto = bfd_reloc_type_lookup (stdoutput, reloc); + /* Handle erroneous "@h" and "@l" expressions here before they propagate + into the symbol table where the generic portions of the assembler + won't know what to do with them. */ + if (expr->X_op == O_lo16 || expr->X_op == O_hi16) + { + as_bad (_("invalid expression for operand %i of '%s'"), + opnum, xtensa_opcode_name (xtensa_default_isa, opcode)); + return FALSE; + } + + /* Next try the generic relocs. */ + if (reloc == BFD_RELOC_NONE) + reloc = encode_reloc (slot); + if (reloc == BFD_RELOC_NONE) + { + as_bad (_("invalid relocation in instruction slot %i"), slot); + return FALSE; + } + howto = bfd_reloc_type_lookup (stdoutput, reloc); if (!howto) { - as_bad (_("undefined symbol for opcode \"%s\"."), + as_bad (_("undefined symbol for opcode \"%s\""), xtensa_opcode_name (xtensa_default_isa, opcode)); return FALSE; } - insn_length = xtensa_insn_length (xtensa_default_isa, opcode); - the_fix = fix_new_exp (fragP, offset, insn_length, expr, + fmt_length = xtensa_format_length (xtensa_default_isa, fmt); + the_fix = fix_new_exp (fragP, offset, fmt_length, expr, howto->pc_relative, reloc); - if (expr->X_add_symbol && - (S_IS_EXTERNAL (expr->X_add_symbol) || S_IS_WEAK (expr->X_add_symbol))) + if (expr->X_add_symbol + && (S_IS_EXTERNAL (expr->X_add_symbol) + || S_IS_WEAK (expr->X_add_symbol))) the_fix->fx_plt = TRUE; + + the_fix->tc_fix_data.X_add_symbol = expr->X_add_symbol; + the_fix->tc_fix_data.X_add_number = expr->X_add_number; + the_fix->tc_fix_data.slot = slot; return TRUE; } @@ -4083,7 +4921,7 @@ xg_resolve_labels (insn, label_sym) { symbolS *sym = get_special_label_symbol (); int i; - /* assert(!insn->is_literal); */ + /* assert (!insn->is_literal); */ for (i = 0; i < insn->ntok; i++) if (insn->tok[i].X_add_symbol == sym) insn->tok[i].X_add_symbol = label_sym; @@ -4091,157 +4929,7 @@ xg_resolve_labels (insn, label_sym) } -static void -xg_assemble_tokens (insn) - /*const */ TInsn *insn; -{ - /* By the time we get here, there's not too much left to do. - 1) Check our assumptions. - 2) Check if the current instruction is "narrow". - If so, then finish the frag, create another one. - We could also go back to change some previous - "narrow" frags into no-change ones if we have more than - MAX_NARROW_ALIGNMENT of them without alignment restrictions - between them. - - Cases: - 1) It has constant operands and doesn't fit. - Go ahead and assemble it so it will fail. - 2) It has constant operands that fit. - If narrow and !is_specific_opcode, - assemble it and put in a relocation - else - assemble it. - 3) It has a symbolic immediate operand - a) Find the worst-case relaxation required - b) Find the worst-case literal pool space required. - Insert appropriate alignment & space in the literal. - Assemble it. - Add the relocation. */ - - assert (insn->insn_type == ITYPE_INSN); - - if (!tinsn_has_symbolic_operands (insn)) - { - if (xg_is_narrow_insn (insn) && !insn->is_specific_opcode) - { - /* assemble it but add max required space */ - int max_size = xg_get_max_narrow_insn_size (insn->opcode); - int min_size = xg_get_insn_size (insn); - char *last_insn; - assert (max_size == 3); - /* make sure we have enough space to widen it */ - xg_force_frag_space (max_size); - /* Output the instruction. It may cause an error if some - operands do not fit. */ - last_insn = frag_more (0); - if (xg_emit_insn (insn, TRUE)) - as_warn (_("instruction with constant operands does not fit")); - xg_finish_frag (last_insn, RELAX_NARROW, max_size - min_size, TRUE); - } - else - { - /* Assemble it. No relocation needed. */ - int max_size = xg_get_insn_size (insn); - xg_force_frag_space (max_size); - if (xg_emit_insn (insn, FALSE)) - as_warn (_("instruction with constant operands does not " - "fit without widening")); - /* frag_more (max_size); */ - - /* Special case for jx. If the jx is the next to last - instruction in a loop, we will add a NOP after it. This - avoids a hardware issue that could occur if the jx jumped - to the next instruction. */ - if (software_avoid_b_j_loop_end - && is_jx_opcode (insn->opcode)) - { - maybe_has_b_j_loop_end = TRUE; - /* add 2 of these */ - frag_now->tc_frag_data.is_insn = TRUE; - frag_var (rs_machine_dependent, 4, 4, - RELAX_ADD_NOP_IF_PRE_LOOP_END, - frag_now->fr_symbol, frag_now->fr_offset, NULL); - } - } - } - else - { - /* Need to assemble it with space for the relocation. */ - if (!insn->is_specific_opcode) - { - /* Assemble it but add max required space. */ - char *last_insn; - int min_size = xg_get_insn_size (insn); - int max_size = xg_get_max_insn_widen_size (insn->opcode); - int max_literal_size = - xg_get_max_insn_widen_literal_size (insn->opcode); - -#if 0 - symbolS *immed_sym = xg_get_insn_immed_symbol (insn); - set_frag_segment (frag_now, now_seg); -#endif /* 0 */ - - /* Make sure we have enough space to widen the instruction. - This may open a new fragment. */ - xg_force_frag_space (max_size); - if (max_literal_size != 0) - xg_assemble_literal_space (max_literal_size); - - /* Output the instruction. It may cause an error if some - operands do not fit. Emit the incomplete instruction. */ - last_insn = frag_more (0); - xg_emit_insn (insn, FALSE); - - xg_finish_frag (last_insn, RELAX_IMMED, max_size - min_size, TRUE); - - /* Special cases for loops: - close_loop_end should be inserted AFTER short_loop. - Make sure that CLOSE loops are processed BEFORE short_loops - when converting them. */ - - /* "short_loop": add a NOP if the loop is < 4 bytes. */ - if (software_avoid_short_loop - && is_loop_opcode (insn->opcode)) - { - maybe_has_short_loop = TRUE; - frag_now->tc_frag_data.is_insn = TRUE; - frag_var (rs_machine_dependent, 4, 4, - RELAX_ADD_NOP_IF_SHORT_LOOP, - frag_now->fr_symbol, frag_now->fr_offset, NULL); - frag_now->tc_frag_data.is_insn = TRUE; - frag_var (rs_machine_dependent, 4, 4, - RELAX_ADD_NOP_IF_SHORT_LOOP, - frag_now->fr_symbol, frag_now->fr_offset, NULL); - } - - /* "close_loop_end": Add up to 12 bytes of NOPs to keep a - loop at least 12 bytes away from another loop's loop - end. */ - if (software_avoid_close_loop_end - && is_loop_opcode (insn->opcode)) - { - maybe_has_close_loop_end = TRUE; - frag_now->tc_frag_data.is_insn = TRUE; - frag_var (rs_machine_dependent, 12, 12, - RELAX_ADD_NOP_IF_CLOSE_LOOP_END, - frag_now->fr_symbol, frag_now->fr_offset, NULL); - } - } - else - { - /* Assemble it in place. No expansion will be required, - but we'll still need a relocation record. */ - int max_size = xg_get_insn_size (insn); - xg_force_frag_space (max_size); - if (xg_emit_insn (insn, TRUE)) - as_warn (_("instruction's constant operands do not fit")); - } - } -} - - -/* Return true if the instruction can write to the specified +/* Return TRUE if the instruction can write to the specified integer register. */ static bfd_boolean @@ -4254,16 +4942,18 @@ is_register_writer (insn, regset, regnum) int num_ops; xtensa_isa isa = xtensa_default_isa; - num_ops = xtensa_num_operands (isa, insn->opcode); + num_ops = xtensa_opcode_num_operands (isa, insn->opcode); for (i = 0; i < num_ops; i++) { - xtensa_operand operand = xtensa_get_operand (isa, insn->opcode, i); - char inout = xtensa_operand_inout (operand); - - if (inout == '>' || inout == '=') + char inout; + inout = xtensa_operand_inout (isa, insn->opcode, i); + if ((inout == 'o' || inout == 'm') + && xtensa_operand_is_register (isa, insn->opcode, i) == 1) { - if (strcmp (xtensa_operand_kind (operand), regset) == 0) + xtensa_regfile opnd_rf = + xtensa_operand_regfile (isa, insn->opcode, i); + if (!strcmp (xtensa_regfile_shortname (isa, opnd_rf), regset)) { if ((insn->tok[i].X_op == O_register) && (insn->tok[i].X_add_number == regnum)) @@ -4297,16 +4987,10 @@ is_bad_loopend_opcode (tinsn) || opcode == xtensa_ret_n_opcode || opcode == xtensa_retw_opcode || opcode == xtensa_retw_n_opcode - || opcode == xtensa_waiti_opcode) + || opcode == xtensa_waiti_opcode + || opcode == xtensa_rsr_lcount_opcode) return TRUE; - /* An RSR of LCOUNT is illegal as the last opcode in a loop. */ - if (opcode == xtensa_rsr_opcode - && tinsn->ntok >= 2 - && tinsn->tok[1].X_op == O_constant - && tinsn->tok[1].X_add_number == 2) - return TRUE; - return FALSE; } @@ -4317,8 +5001,8 @@ is_bad_loopend_opcode (tinsn) not be aligned: FAKE_LABEL_NAME . {"F", "L", "endfunc"}. */ bfd_boolean -is_unaligned_label (sym) - symbolS *sym; +is_unaligned_label (sym) + symbolS *sym; { const char *name = S_GET_NAME (sym); static size_t fake_size = 0; @@ -4332,7 +5016,7 @@ is_unaligned_label (sym) if (fake_size == 0) fake_size = strlen (FAKE_LABEL_NAME); - if (name + if (name && strncmp (FAKE_LABEL_NAME, name, fake_size) == 0 && (name[fake_size] == 'F' || name[fake_size] == 'L' @@ -4362,26 +5046,93 @@ next_non_empty_frag (fragP) } -xtensa_opcode -next_frag_opcode (fragP) - const fragS * fragP; +static bfd_boolean +next_frag_opcode_is_loop (fragP, opcode) + const fragS *fragP; + xtensa_opcode *opcode; +{ + xtensa_opcode out_opcode; + const fragS *next_fragP = next_non_empty_frag (fragP); + + if (next_fragP == NULL) + return FALSE; + + out_opcode = get_opcode_from_buf (next_fragP->fr_literal, 0); + if (xtensa_opcode_is_loop (xtensa_default_isa, out_opcode) == 1) + { + *opcode = out_opcode; + return TRUE; + } + return FALSE; +} + + +static int +next_frag_format_size (fragP) + const fragS *fragP; { const fragS *next_fragP = next_non_empty_frag (fragP); + return frag_format_size (next_fragP); +} + + +static int +frag_format_size (fragP) + const fragS * fragP; +{ static xtensa_insnbuf insnbuf = NULL; xtensa_isa isa = xtensa_default_isa; + xtensa_format fmt; + int fmt_size; if (!insnbuf) insnbuf = xtensa_insnbuf_alloc (isa); - if (next_fragP == NULL) + if (fragP == NULL) + return XTENSA_UNDEFINED; + + xtensa_insnbuf_from_chars (isa, insnbuf, fragP->fr_literal, 0); + + fmt = xtensa_format_decode (isa, insnbuf); + if (fmt == XTENSA_UNDEFINED) return XTENSA_UNDEFINED; + fmt_size = xtensa_format_length (isa, fmt); + + /* If the next format won't be changing due to relaxation, just + return the length of the first format. */ + if (fragP->fr_opcode != fragP->fr_literal) + return fmt_size; + + /* If during relaxation we have to pull an instruction out of a + multi-slot instruction, we will return the more conservative + number. This works because alignment on bigger instructions + is more restrictive than alignment on smaller instructions. + This is more conservative than we would like, but it happens + infrequently. */ + + if (xtensa_format_num_slots (xtensa_default_isa, fmt) > 1) + return fmt_size; + + /* If we aren't doing one of our own relaxations or it isn't + slot-based, then the insn size won't change. */ + if (fragP->fr_type != rs_machine_dependent) + return fmt_size; + if (fragP->fr_subtype != RELAX_SLOTS) + return fmt_size; + + /* If an instruction is about to grow, return the longer size. */ + if (fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED_STEP1 + || fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED_STEP2) + return 3; + + if (fragP->tc_frag_data.slot_subtypes[0] == RELAX_NARROW) + return 2 + fragP->tc_frag_data.text_expansion[0]; - xtensa_insnbuf_from_chars (isa, insnbuf, next_fragP->fr_literal); - return xtensa_decode_insn (isa, insnbuf); + return fmt_size; } -/* Return true if the target frag is one of the next non-empty frags. */ +/* Return TRUE if the target frag is one of the next non-empty frags. */ bfd_boolean is_next_frag_target (fragP, target) @@ -4413,20 +5164,66 @@ is_next_frag_target (fragP, target) switch its state so it will instantiate a NOP. */ static void -update_next_frag_nop_state (fragP) +update_next_frag_state (fragP, unreachable) fragS *fragP; + bfd_boolean unreachable; { fragS *next_fragP = fragP->fr_next; + fragS *new_target = NULL; - while (next_fragP && next_fragP->fr_fix == 0) + if (align_targets) + { + /* We are guaranteed there will be one of these... */ + while (!(next_fragP->fr_type == rs_machine_dependent + && (next_fragP->fr_subtype == RELAX_MAYBE_UNREACHABLE + || next_fragP->fr_subtype == RELAX_UNREACHABLE))) + next_fragP = next_fragP->fr_next; + + assert (next_fragP->fr_type == rs_machine_dependent + && (next_fragP->fr_subtype == RELAX_MAYBE_UNREACHABLE + || next_fragP->fr_subtype == RELAX_UNREACHABLE)); + + /* ...and one of these. */ + new_target = next_fragP->fr_next; + while (!(new_target->fr_type == rs_machine_dependent + && (new_target->fr_subtype == RELAX_MAYBE_DESIRE_ALIGN + || new_target->fr_subtype == RELAX_DESIRE_ALIGN))) + new_target = new_target->fr_next; + + assert (new_target->fr_type == rs_machine_dependent + && (new_target->fr_subtype == RELAX_MAYBE_DESIRE_ALIGN + || new_target->fr_subtype == RELAX_DESIRE_ALIGN)); + } + if (unreachable) { - if (next_fragP->fr_type == rs_machine_dependent - && next_fragP->fr_subtype == RELAX_LOOP_END) + if (align_targets) { - next_fragP->fr_subtype = RELAX_LOOP_END_ADD_NOP; - return; + next_fragP->fr_subtype = RELAX_UNREACHABLE; + next_fragP->tc_frag_data.is_unreachable = TRUE; + new_target->fr_subtype = RELAX_DESIRE_ALIGN; + new_target->tc_frag_data.is_branch_target = TRUE; + } + while (next_fragP && next_fragP->fr_fix == 0) + { + if (next_fragP->fr_type == rs_machine_dependent + && next_fragP->fr_subtype == RELAX_LOOP_END) + { + next_fragP->fr_subtype = RELAX_LOOP_END_ADD_NOP; + return; + } + + next_fragP = next_fragP->fr_next; + } + } + else + { + if (align_targets) + { + next_fragP->fr_subtype = RELAX_MAYBE_UNREACHABLE; + next_fragP->tc_frag_data.is_unreachable = FALSE; + new_target->fr_subtype = RELAX_MAYBE_DESIRE_ALIGN; + new_target->tc_frag_data.is_branch_target = FALSE; } - next_fragP = next_fragP->fr_next; } } @@ -4435,7 +5232,7 @@ static bfd_boolean next_frag_is_branch_target (fragP) const fragS *fragP; { - /* Sometimes an empty will end up here due storage allocation issues, + /* Sometimes an empty will end up here due to storage allocation issues, so we have to skip until we find something legit. */ for (fragP = fragP->fr_next; fragP; fragP = fragP->fr_next) { @@ -4470,13 +5267,13 @@ next_frag_pre_opcode_bytes (fragp) const fragS *fragp; { const fragS *next_fragp = fragp->fr_next; + xtensa_opcode next_opcode; - xtensa_opcode next_opcode = next_frag_opcode (fragp); - if (!is_loop_opcode (next_opcode)) + if (!next_frag_opcode_is_loop (fragp, &next_opcode)) return 0; - /* Sometimes an empty will end up here due storage allocation issues. - So we have to skip until we find something legit. */ + /* Sometimes an empty will end up here due to storage allocation issues, + so we have to skip until we find something legit. */ while (next_fragp->fr_fix == 0) next_fragp = next_fragp->fr_next; @@ -4485,8 +5282,9 @@ next_frag_pre_opcode_bytes (fragp) /* There is some implicit knowledge encoded in here. The LOOP instructions that are NOT RELAX_IMMED have - been relaxed. */ - if (next_fragp->fr_subtype > RELAX_IMMED) + been relaxed. Note that we can assume that the LOOP + instruction is in slot 0 because loops aren't bundleable. */ + if (next_fragp->tc_frag_data.slot_subtypes[0] > RELAX_IMMED) return get_expanded_loop_offset (next_opcode); return 0; @@ -4505,27 +5303,37 @@ xtensa_mark_literal_pool_location () emit_state s; fragS *pool_location; + if (use_literal_section && !directive_state[directive_absolute_literals]) + return; + frag_align (2, 0, 0); + record_alignment (now_seg, 2); /* We stash info in the fr_var of these frags - so we can later move the literal's fixes into this + so we can later move the literal's fixes into this frchain's fix list. We can use fr_var because fr_var's interpretation depends solely on the fr_type and subtype. */ pool_location = frag_now; - frag_variant (rs_machine_dependent, 0, (int) frchain_now, + frag_variant (rs_machine_dependent, 0, (int) frchain_now, RELAX_LITERAL_POOL_BEGIN, NULL, 0, NULL); - frag_variant (rs_machine_dependent, 0, (int) now_seg, + xtensa_set_frag_assembly_state (frag_now); + frag_variant (rs_machine_dependent, 0, (int) now_seg, RELAX_LITERAL_POOL_END, NULL, 0, NULL); + xtensa_set_frag_assembly_state (frag_now); /* Now put a frag into the literal pool that points to this location. */ set_literal_pool_location (now_seg, pool_location); - xtensa_switch_to_literal_fragment (&s); + xtensa_switch_to_non_abs_literal_fragment (&s); + frag_align (2, 0, 0); + record_alignment (now_seg, 2); /* Close whatever frag is there. */ frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL); + xtensa_set_frag_assembly_state (frag_now); frag_now->tc_frag_data.literal_frag = pool_location; frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL); xtensa_restore_emit_state (&s); + xtensa_set_frag_assembly_state (frag_now); } @@ -4564,7 +5372,7 @@ xtensa_move_labels (new_frag, new_offset, loops_ok) for (lit = insn_labels; lit; lit = lit->next) { symbolS *lit_sym = lit->sym; - if (loops_ok || symbol_get_tc (lit_sym)->is_loop_target == 0) + if (loops_ok || ! symbol_get_tc (lit_sym)->is_loop_target) { S_SET_VALUE (lit_sym, new_offset); symbol_set_frag (lit_sym, new_frag); @@ -4573,6 +5381,40 @@ xtensa_move_labels (new_frag, new_offset, loops_ok) } +/* Build a nop of the correct size into tinsn. */ + +static void +build_nop (tinsn, size) + TInsn *tinsn; + int size; +{ + tinsn_init (tinsn); + switch (size) + { + case 2: + tinsn->opcode = xtensa_nop_n_opcode; + tinsn->ntok = 0; + if (tinsn->opcode == XTENSA_UNDEFINED) + as_fatal (_("opcode 'NOP.N' unavailable in this configuration")); + break; + + case 3: + if (xtensa_nop_opcode == XTENSA_UNDEFINED) + { + tinsn->opcode = xtensa_or_opcode; + set_expr_const (&tinsn->tok[0], 1); + set_expr_const (&tinsn->tok[1], 1); + set_expr_const (&tinsn->tok[2], 1); + tinsn->ntok = 3; + } + else + tinsn->opcode = xtensa_nop_opcode; + + assert (tinsn->opcode != XTENSA_UNDEFINED); + } +} + + /* Assemble a NOP of the requested size in the buffer. User must have allocated "buf" with at least "size" bytes. */ @@ -4582,38 +5424,15 @@ assemble_nop (size, buf) char *buf; { static xtensa_insnbuf insnbuf = NULL; - TInsn t_insn; - if (!insnbuf) - insnbuf = xtensa_insnbuf_alloc (xtensa_default_isa); + TInsn tinsn; - tinsn_init (&t_insn); - switch (size) - { - case 2: - t_insn.opcode = xtensa_nop_n_opcode; - t_insn.ntok = 0; - if (t_insn.opcode == XTENSA_UNDEFINED) - as_fatal (_("opcode 'NOP.N' unavailable in this configuration")); - tinsn_to_insnbuf (&t_insn, insnbuf); - xtensa_insnbuf_to_chars (xtensa_default_isa, insnbuf, buf); - break; + build_nop (&tinsn, size); - case 3: - t_insn.opcode = xtensa_or_opcode; - assert (t_insn.opcode != XTENSA_UNDEFINED); - if (t_insn.opcode == XTENSA_UNDEFINED) - as_fatal (_("opcode 'OR' unavailable in this configuration")); - set_expr_const (&t_insn.tok[0], 1); - set_expr_const (&t_insn.tok[1], 1); - set_expr_const (&t_insn.tok[2], 1); - t_insn.ntok = 3; - tinsn_to_insnbuf (&t_insn, insnbuf); - xtensa_insnbuf_to_chars (xtensa_default_isa, insnbuf, buf); - break; + if (!insnbuf) + insnbuf = xtensa_insnbuf_alloc (xtensa_default_isa); - default: - as_fatal (_("invalid %d-byte NOP requested"), size); - } + tinsn_to_insnbuf (&tinsn, insnbuf); + xtensa_insnbuf_to_chars (xtensa_default_isa, insnbuf, buf, 0); } @@ -4631,8 +5450,7 @@ get_expanded_loop_offset (opcode) /* This is the OFFSET of the loop instruction in the expanded loop. This MUST correspond directly to the specification of the loop expansion. It will be validated on fragment conversion. */ - if (opcode == XTENSA_UNDEFINED) - as_fatal (_("get_expanded_loop_offset: undefined opcode")); + assert (opcode != XTENSA_UNDEFINED); if (opcode == xtensa_loop_opcode) return 0; if (opcode == xtensa_loopnez_opcode) @@ -4660,6 +5478,219 @@ set_literal_pool_location (seg, literal_pool_loc) seg_info (seg)->tc_segment_info_data.literal_pool_loc = literal_pool_loc; } + +/* Set frag assembly state should be called when a new frag is + opened and after a frag has been closed. */ + +void +xtensa_set_frag_assembly_state (fragP) + fragS *fragP; +{ + if (!density_supported) + fragP->tc_frag_data.is_no_density = TRUE; + + /* This function is called from subsegs_finish, which is called + after xtensa_end, so we can't use "use_transform" or + "use_schedule" here. */ + if (!directive_state[directive_transform]) + fragP->tc_frag_data.is_no_transform = TRUE; + fragP->tc_frag_data.use_absolute_literals = + directive_state[directive_absolute_literals]; + fragP->tc_frag_data.is_assembly_state_set = TRUE; +} + + +bfd_boolean +relaxable_section (sec) + asection *sec; +{ + return (sec->flags & SEC_DEBUGGING) == 0; +} + + +static void +xtensa_find_unmarked_state_frags () +{ + segT *seclist; + + /* Walk over each fragment of all of the current segments. For each + unmarked fragment, mark it with the same info as the previous + fragment. */ + for (seclist = &stdoutput->sections; + seclist && *seclist; + seclist = &(*seclist)->next) + { + segT sec = *seclist; + segment_info_type *seginfo; + fragS *fragP; + flagword flags; + flags = bfd_get_section_flags (stdoutput, sec); + if (flags & SEC_DEBUGGING) + continue; + if (!(flags & SEC_ALLOC)) + continue; + + seginfo = seg_info (sec); + if (seginfo && seginfo->frchainP) + { + fragS *last_fragP = 0; + for (fragP = seginfo->frchainP->frch_root; fragP; + fragP = fragP->fr_next) + { + if (fragP->fr_fix != 0 + && !fragP->tc_frag_data.is_assembly_state_set) + { + if (last_fragP == 0) + { + as_warn_where (fragP->fr_file, fragP->fr_line, + _("assembly state not set for first frag in section %s"), + sec->name); + } + else + { + fragP->tc_frag_data.is_assembly_state_set = TRUE; + fragP->tc_frag_data.is_no_density = + last_fragP->tc_frag_data.is_no_density; + fragP->tc_frag_data.is_no_transform = + last_fragP->tc_frag_data.is_no_transform; + fragP->tc_frag_data.use_absolute_literals = + last_fragP->tc_frag_data.use_absolute_literals; + } + } + if (fragP->tc_frag_data.is_assembly_state_set) + last_fragP = fragP; + } + } + } +} + + +static void +xtensa_find_unaligned_branch_targets (abfd, sec, unused) + bfd *abfd ATTRIBUTE_UNUSED; + asection *sec; + PTR unused ATTRIBUTE_UNUSED; +{ + flagword flags = bfd_get_section_flags (abfd, sec); + segment_info_type *seginfo = seg_info (sec); + fragS *frag = seginfo->frchainP->frch_root; + + if (flags & SEC_CODE) + { + xtensa_isa isa = xtensa_default_isa; + xtensa_insnbuf insnbuf = xtensa_insnbuf_alloc (isa); + while (frag != NULL) + { + if (frag->tc_frag_data.is_branch_target) + { + int op_size; + int frag_addr; + xtensa_format fmt; + + xtensa_insnbuf_from_chars (isa, insnbuf, frag->fr_literal, 0); + fmt = xtensa_format_decode (isa, insnbuf); + op_size = xtensa_format_length (isa, fmt); + frag_addr = frag->fr_address % xtensa_fetch_width; + if (frag_addr + op_size > (int) xtensa_fetch_width) + as_warn_where (frag->fr_file, frag->fr_line, + _("unaligned branch target: %d bytes at 0x%lx"), + op_size, frag->fr_address); + } + frag = frag->fr_next; + } + xtensa_insnbuf_free (isa, insnbuf); + } +} + + +static void +xtensa_find_unaligned_loops (abfd, sec, unused) + bfd *abfd ATTRIBUTE_UNUSED; + asection *sec; + PTR unused ATTRIBUTE_UNUSED; +{ + flagword flags = bfd_get_section_flags (abfd, sec); + segment_info_type *seginfo = seg_info (sec); + fragS *frag = seginfo->frchainP->frch_root; + xtensa_isa isa = xtensa_default_isa; + + if (flags & SEC_CODE) + { + xtensa_insnbuf insnbuf = xtensa_insnbuf_alloc (isa); + while (frag != NULL) + { + if (frag->tc_frag_data.is_first_loop_insn) + { + int op_size; + int frag_addr; + xtensa_format fmt; + + xtensa_insnbuf_from_chars (isa, insnbuf, frag->fr_literal, 0); + fmt = xtensa_format_decode (isa, insnbuf); + op_size = xtensa_format_length (isa, fmt); + frag_addr = frag->fr_address % xtensa_fetch_width; + + if (frag_addr + op_size > (signed) xtensa_fetch_width) + as_warn_where (frag->fr_file, frag->fr_line, + _("unaligned loop: %d bytes at 0x%lx"), + op_size, frag->fr_address); + } + frag = frag->fr_next; + } + xtensa_insnbuf_free (isa, insnbuf); + } +} + + +void +xg_apply_tentative_value (fixP, val) + fixS *fixP; + valueT val; +{ + xtensa_isa isa = xtensa_default_isa; + static xtensa_insnbuf insnbuf = NULL; + static xtensa_insnbuf slotbuf = NULL; + xtensa_format fmt; + int slot; + bfd_boolean alt_reloc; + xtensa_opcode opcode; + char *const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where; + + (void) decode_reloc (fixP->fx_r_type, &slot, &alt_reloc); + if (alt_reloc) + as_fatal (_("unexpected fix")); + + if (!insnbuf) + { + insnbuf = xtensa_insnbuf_alloc (isa); + slotbuf = xtensa_insnbuf_alloc (isa); + } + + xtensa_insnbuf_from_chars (isa, insnbuf, fixpos, 0); + fmt = xtensa_format_decode (isa, insnbuf); + if (fmt == XTENSA_UNDEFINED) + as_fatal (_("undecodable fix")); + xtensa_format_get_slot (isa, fmt, slot, insnbuf, slotbuf); + opcode = xtensa_opcode_decode (isa, fmt, slot, slotbuf); + if (opcode == XTENSA_UNDEFINED) + as_fatal (_("undecodable fix")); + + /* CONST16 immediates are not PC-relative, despite the fact that we + reuse the normal PC-relative operand relocations for the low part + of a CONST16 operand. The code in tc_gen_reloc does not decode + the opcodes so it is more convenient to detect this special case + here. */ + if (opcode == xtensa_const16_opcode) + return; + + xtensa_insnbuf_set_operand (slotbuf, fmt, slot, opcode, + get_relaxable_immed (opcode), val, + fixP->fx_file, fixP->fx_line); + + xtensa_format_set_slot (isa, fmt, slot, insnbuf, slotbuf); + xtensa_insnbuf_to_chars (isa, insnbuf, fixpos, 0); +} + /* External Functions and Other GAS Hooks. */ @@ -4702,21 +5733,22 @@ md_begin () int current_subsec = now_subseg; xtensa_isa isa; -#if STATIC_LIBISA - isa = xtensa_isa_init (); -#else - /* ISA was already initialized by xtensa_init(). */ + xtensa_default_isa = xtensa_isa_init (0, 0); isa = xtensa_default_isa; -#endif - /* Set up the .literal, .fini.literal and .init.literal sections. */ + linkrelax = 1; + + /* Set up the .literal, .fini.literal and .init.literal sections. */ memset (&default_lit_sections, 0, sizeof (default_lit_sections)); default_lit_sections.init_lit_seg_name = INIT_LITERAL_SECTION_NAME; default_lit_sections.fini_lit_seg_name = FINI_LITERAL_SECTION_NAME; default_lit_sections.lit_seg_name = LITERAL_SECTION_NAME; + default_lit_sections.lit4_seg_name = LIT4_SECTION_NAME; subseg_set (current_section, current_subsec); + xg_init_vinsn (&cur_vinsn); + xtensa_addi_opcode = xtensa_opcode_lookup (isa, "addi"); xtensa_addmi_opcode = xtensa_opcode_lookup (isa, "addmi"); xtensa_call0_opcode = xtensa_opcode_lookup (isa, "call0"); @@ -4727,21 +5759,43 @@ md_begin () xtensa_callx4_opcode = xtensa_opcode_lookup (isa, "callx4"); xtensa_callx8_opcode = xtensa_opcode_lookup (isa, "callx8"); xtensa_callx12_opcode = xtensa_opcode_lookup (isa, "callx12"); + xtensa_const16_opcode = xtensa_opcode_lookup (isa, "const16"); xtensa_entry_opcode = xtensa_opcode_lookup (isa, "entry"); + xtensa_movi_opcode = xtensa_opcode_lookup (isa, "movi"); + xtensa_movi_n_opcode = xtensa_opcode_lookup (isa, "movi.n"); xtensa_isync_opcode = xtensa_opcode_lookup (isa, "isync"); - xtensa_j_opcode = xtensa_opcode_lookup (isa, "j"); xtensa_jx_opcode = xtensa_opcode_lookup (isa, "jx"); + xtensa_l32r_opcode = xtensa_opcode_lookup (isa, "l32r"); xtensa_loop_opcode = xtensa_opcode_lookup (isa, "loop"); xtensa_loopnez_opcode = xtensa_opcode_lookup (isa, "loopnez"); xtensa_loopgtz_opcode = xtensa_opcode_lookup (isa, "loopgtz"); + xtensa_nop_opcode = xtensa_opcode_lookup (isa, "nop"); xtensa_nop_n_opcode = xtensa_opcode_lookup (isa, "nop.n"); xtensa_or_opcode = xtensa_opcode_lookup (isa, "or"); xtensa_ret_opcode = xtensa_opcode_lookup (isa, "ret"); xtensa_ret_n_opcode = xtensa_opcode_lookup (isa, "ret.n"); xtensa_retw_opcode = xtensa_opcode_lookup (isa, "retw"); xtensa_retw_n_opcode = xtensa_opcode_lookup (isa, "retw.n"); - xtensa_rsr_opcode = xtensa_opcode_lookup (isa, "rsr"); + xtensa_rsr_lcount_opcode = xtensa_opcode_lookup (isa, "rsr.lcount"); xtensa_waiti_opcode = xtensa_opcode_lookup (isa, "waiti"); + + init_op_placement_info_table (); + + /* Set up the assembly state. */ + if (!frag_now->tc_frag_data.is_assembly_state_set) + xtensa_set_frag_assembly_state (frag_now); +} + + +/* TC_INIT_FIX_DATA hook */ + +void +xtensa_init_fix_data (x) + fixS *x; +{ + x->tc_fix_data.slot = 0; + x->tc_fix_data.X_add_symbol = NULL; + x->tc_fix_data.X_add_number = 0; } @@ -4751,6 +5805,11 @@ void xtensa_frob_label (sym) symbolS *sym; { + /* Since the label was already attached to a frag associated with the + previous basic block, it now needs to be reset to the current frag. */ + symbol_set_frag (sym, frag_now); + S_SET_VALUE (sym, (valueT) frag_now_fix ()); + if (generating_literals) xtensa_add_literal_sym (sym); else @@ -4763,26 +5822,93 @@ xtensa_frob_label (sym) /* No target aligning in the absolute section. */ if (now_seg != absolute_section - && align_targets + && do_align_targets () && !is_unaligned_label (sym) - && !frag_now->tc_frag_data.is_literal) - { - /* frag_now->tc_frag_data.is_insn = TRUE; */ - frag_var (rs_machine_dependent, 4, 4, + && !generating_literals) + { + float freq = get_subseg_info (now_seg, now_subseg)->cur_target_freq; + xtensa_set_frag_assembly_state (frag_now); + + /* The only time this type of frag grows is when there is a + negatable branch that needs to be relaxed as the last + instruction in a zero-overhead loop. Because alignment frags + are so common, marking them all as possibly growing four + bytes makes any worst-case analysis appear much worse than it + is. So, we make fr_var not actually reflect the amount of + memory allocated at the end of this frag, but rather the + amount of memory this frag might grow. The "4, 0" below + allocates four bytes at the end of the frag for room to grow + if we need to relax a loop end with a NOP. Frags prior to + this one might grow to align this one, but the frag itself + won't grow unless it meets the condition above. */ + +#define RELAX_LOOP_END_BYTES 4 + + frag_var (rs_machine_dependent, + RELAX_LOOP_END_BYTES, (int) freq, RELAX_DESIRE_ALIGN_IF_TARGET, frag_now->fr_symbol, frag_now->fr_offset, NULL); + xtensa_set_frag_assembly_state (frag_now); xtensa_move_labels (frag_now, 0, TRUE); + } + + /* We need to mark the following properties even if we aren't aligning. */ + + /* If the label is already known to be a branch target, i.e., a + forward branch, mark the frag accordingly. Backward branches + are handled by xg_add_branch_and_loop_targets. */ + if (symbol_get_tc (sym)->is_branch_target) + symbol_get_frag (sym)->tc_frag_data.is_branch_target = TRUE; + + /* Loops only go forward, so they can be identified here. */ + if (symbol_get_tc (sym)->is_loop_target) + symbol_get_frag (sym)->tc_frag_data.is_loop_target = TRUE; +} + + +/* tc_unrecognized_line hook */ + +int +xtensa_unrecognized_line (ch) + int ch; +{ + switch (ch) + { + case '{' : + if (cur_vinsn.inside_bundle == 0) + { + /* PR8110: Cannot emit line number info inside a FLIX bundle + when using --gstabs. Temporarily disable debug info. */ + generate_lineno_debug (); + if (debug_type == DEBUG_STABS) + { + xt_saved_debug_type = debug_type; + debug_type = DEBUG_NONE; + } - /* If the label is already known to be a branch target, i.e., a - forward branch, mark the frag accordingly. Backward branches - are handled by xg_add_branch_and_loop_targets. */ - if (symbol_get_tc (sym)->is_branch_target) - symbol_get_frag (sym)->tc_frag_data.is_branch_target = TRUE; + cur_vinsn.inside_bundle = 1; + } + else + { + as_bad (_("extra opening brace")); + return 0; + } + break; - /* Loops only go forward, so they can be identified here. */ - if (symbol_get_tc (sym)->is_loop_target) - symbol_get_frag (sym)->tc_frag_data.is_loop_target = TRUE; + case '}' : + if (cur_vinsn.inside_bundle) + finish_vinsn (&cur_vinsn); + else + { + as_bad (_("extra closing brace")); + return 0; + } + break; + default: + as_bad (_("syntax error")); + return 0; } + return 1; } @@ -4791,11 +5917,15 @@ xtensa_frob_label (sym) void xtensa_flush_pending_output () { + if (cur_vinsn.inside_bundle) + as_bad (_("missing closing brace")); + /* If there is a non-zero instruction fragment, close it. */ if (frag_now_fix () != 0 && frag_now->tc_frag_data.is_insn) { frag_wane (frag_now); frag_new (0); + xtensa_set_frag_assembly_state (frag_now); } frag_now->tc_frag_data.is_insn = FALSE; @@ -4803,6 +5933,25 @@ xtensa_flush_pending_output () } +/* We had an error while parsing an instruction. The string might look + like this: "insn arg1, arg2 }". If so, we need to see the closing + brace and reset some fields. Otherwise, the vinsn never gets closed + and the num_slots field will grow past the end of the array of slots, + and bad things happen. */ + +static void +error_reset_cur_vinsn () +{ + if (cur_vinsn.inside_bundle) + { + if (*input_line_pointer == '}' + || *(input_line_pointer - 1) == '}' + || *(input_line_pointer - 2) == '}') + xg_clear_vinsn (&cur_vinsn); + } +} + + void md_assemble (str) char *str; @@ -4811,25 +5960,10 @@ md_assemble (str) char *opname; unsigned opnamelen; bfd_boolean has_underbar = FALSE; - char *arg_strings[MAX_INSN_ARGS]; + char *arg_strings[MAX_INSN_ARGS]; int num_args; - IStack istack; /* Put instructions into here. */ TInsn orig_insn; /* Original instruction from the input. */ - int i; - symbolS *lit_sym = NULL; - - if (frag_now->tc_frag_data.is_literal) - { - static bfd_boolean reported = 0; - if (reported < 4) - as_bad (_("cannot assemble '%s' into a literal fragment"), str); - if (reported == 3) - as_bad (_("...")); - reported++; - return; - } - istack_init (&istack); tinsn_init (&orig_insn); /* Split off the opcode. */ @@ -4857,43 +5991,33 @@ md_assemble (str) orig_insn.insn_type = ITYPE_INSN; orig_insn.ntok = 0; - orig_insn.is_specific_opcode = (has_underbar || !use_generics ()); - specific_opcode = orig_insn.is_specific_opcode; + orig_insn.is_specific_opcode = (has_underbar || !use_transform ()); orig_insn.opcode = xtensa_opcode_lookup (isa, opname); if (orig_insn.opcode == XTENSA_UNDEFINED) { - as_bad (_("unknown opcode %s"), opname); + xtensa_format fmt = xtensa_format_lookup (isa, opname); + if (fmt == XTENSA_UNDEFINED) + { + as_bad (_("unknown opcode or format name '%s'"), opname); + error_reset_cur_vinsn (); + return; + } + if (!cur_vinsn.inside_bundle) + { + as_bad (_("format names only valid inside bundles")); + error_reset_cur_vinsn (); + return; + } + if (cur_vinsn.format != XTENSA_UNDEFINED) + as_warn (_("multiple formats specified for one bundle; using '%s'"), + opname); + cur_vinsn.format = fmt; + free (has_underbar ? opname - 1 : opname); + error_reset_cur_vinsn (); return; } - if (frag_now_fix () != 0 && !frag_now->tc_frag_data.is_insn) - { - frag_wane (frag_now); - frag_new (0); - } - - if (software_a0_b_retw_interlock) - { - if ((get_last_insn_flags (now_seg, now_subseg) & FLAG_IS_A0_WRITER) != 0 - && is_conditional_branch_opcode (orig_insn.opcode)) - { - has_a0_b_retw = TRUE; - - /* Mark this fragment with the special RELAX_ADD_NOP_IF_A0_B_RETW. - After the first assembly pass we will check all of them and - add a nop if needed. */ - frag_now->tc_frag_data.is_insn = TRUE; - frag_var (rs_machine_dependent, 4, 4, - RELAX_ADD_NOP_IF_A0_B_RETW, - frag_now->fr_symbol, frag_now->fr_offset, NULL); - frag_now->tc_frag_data.is_insn = TRUE; - frag_var (rs_machine_dependent, 4, 4, - RELAX_ADD_NOP_IF_A0_B_RETW, - frag_now->fr_symbol, frag_now->fr_offset, NULL); - } - } - /* Special case: The call instructions should be marked "specific opcode" to keep them from expanding. */ if (!use_longcalls () && is_direct_call_opcode (orig_insn.opcode)) @@ -4903,6 +6027,7 @@ md_assemble (str) if (parse_arguments (&orig_insn, num_args, arg_strings)) { as_bad (_("syntax error")); + error_reset_cur_vinsn (); return; } @@ -4912,40 +6037,31 @@ md_assemble (str) while (num_args-- > 0) free (arg_strings[num_args]); + /* Get expressions for invisible operands. */ + if (get_invisible_operands (&orig_insn)) + { + error_reset_cur_vinsn (); + return; + } + /* Check for the right number and type of arguments. */ if (tinsn_check_arguments (&orig_insn)) - return; - - /* See if the instruction implies an aligned section. */ - if (is_entry_opcode (orig_insn.opcode) || is_loop_opcode (orig_insn.opcode)) - record_alignment (now_seg, 2); - - xg_add_branch_and_loop_targets (&orig_insn); - - /* Special cases for instructions that force an alignment... */ - if (!orig_insn.is_specific_opcode && is_loop_opcode (orig_insn.opcode)) { - size_t max_fill; - - frag_now->tc_frag_data.is_insn = TRUE; - frag_now->tc_frag_data.is_no_density = !code_density_available (); - max_fill = get_text_align_max_fill_size - (get_text_align_power (XTENSA_FETCH_WIDTH), - TRUE, frag_now->tc_frag_data.is_no_density); - frag_var (rs_machine_dependent, max_fill, max_fill, - RELAX_ALIGN_NEXT_OPCODE, frag_now->fr_symbol, - frag_now->fr_offset, NULL); - - xtensa_move_labels (frag_now, 0, FALSE); + error_reset_cur_vinsn (); + return; } + dwarf2_where (&orig_insn.loc); + + xg_add_branch_and_loop_targets (&orig_insn); + /* Special-case for "entry" instruction. */ if (is_entry_opcode (orig_insn.opcode)) { - /* Check that the second opcode (#1) is >= 16. */ - if (orig_insn.ntok >= 2) + /* Check that the third opcode (#2) is >= 16. */ + if (orig_insn.ntok >= 3) { - expressionS *exp = &orig_insn.tok[1]; + expressionS *exp = &orig_insn.tok[2]; switch (exp->X_op) { case O_constant: @@ -4957,117 +6073,63 @@ md_assemble (str) as_warn (_("entry instruction with non-constant decrement")); } } - - if (!orig_insn.is_specific_opcode) - { - xtensa_mark_literal_pool_location (); - - /* Automatically align ENTRY instructions. */ - xtensa_move_labels (frag_now, 0, TRUE); - frag_align (2, 0, 0); - } } - /* Any extra alignment frags have been inserted now, and we're about to - emit a new instruction so clear the list of labels. */ - xtensa_clear_insn_labels (); - - if (software_a0_b_retw_interlock) - set_last_insn_flags (now_seg, now_subseg, FLAG_IS_A0_WRITER, - is_register_writer (&orig_insn, "a", 0)); - - set_last_insn_flags (now_seg, now_subseg, FLAG_IS_BAD_LOOPEND, - is_bad_loopend_opcode (&orig_insn)); - /* Finish it off: - assemble_tokens (opcode, tok, ntok); - expand the tokens from the orig_insn into the - stack of instructions that will not expand + assemble_tokens (opcode, tok, ntok); + expand the tokens from the orig_insn into the + stack of instructions that will not expand unless required at relaxation time. */ - if (xg_expand_assembly_insn (&istack, &orig_insn)) - return; - for (i = 0; i < istack.ninsn; i++) + if (!cur_vinsn.inside_bundle) + emit_single_op (&orig_insn); + else /* We are inside a bundle. */ { - TInsn *insn = &istack.insn[i]; - if (insn->insn_type == ITYPE_LITERAL) - { - assert (lit_sym == NULL); - lit_sym = xg_assemble_literal (insn); - } - else - { - if (lit_sym) - xg_resolve_literals (insn, lit_sym); - xg_assemble_tokens (insn); - } + cur_vinsn.slots[cur_vinsn.num_slots] = orig_insn; + cur_vinsn.num_slots++; + if (*input_line_pointer == '}' + || *(input_line_pointer - 1) == '}' + || *(input_line_pointer - 2) == '}') + finish_vinsn (&cur_vinsn); } - /* Now, if the original opcode was a call... */ - if (align_targets && is_call_opcode (orig_insn.opcode)) - { - frag_now->tc_frag_data.is_insn = TRUE; - frag_var (rs_machine_dependent, 4, 4, - RELAX_DESIRE_ALIGN, - frag_now->fr_symbol, - frag_now->fr_offset, - NULL); - } + /* We've just emitted a new instruction so clear the list of labels. */ + xtensa_clear_insn_labels (); } -/* TC_CONS_FIX_NEW hook: Check for "@PLT" suffix on symbol references. - If found, use an XTENSA_PLT reloc for 4-byte values. Otherwise, this - is the same as the standard code in read.c. */ +/* HANDLE_ALIGN hook */ -void -xtensa_cons_fix_new (frag, where, size, exp) - fragS *frag; - int where; - int size; - expressionS *exp; -{ - bfd_reloc_code_real_type r; - bfd_boolean plt = FALSE; +/* For a .align directive, we mark the previous block with the alignment + information. This will be placed in the object file in the + property section corresponding to this section. */ - if (*input_line_pointer == '@') +void +xtensa_handle_align (fragP) + fragS *fragP; +{ + if (linkrelax + && !get_frag_is_literal (fragP) + && (fragP->fr_type == rs_align + || fragP->fr_type == rs_align_code) + && fragP->fr_address + fragP->fr_fix > 0 + && fragP->fr_offset > 0 + && now_seg != bss_section) { - if (!strncmp (input_line_pointer, PLT_SUFFIX, strlen (PLT_SUFFIX) - 1) - && !strncmp (input_line_pointer, plt_suffix, - strlen (plt_suffix) - 1)) - { - as_bad (_("undefined @ suffix '%s', expected '%s'"), - input_line_pointer, plt_suffix); - ignore_rest_of_line (); - return; - } - - input_line_pointer += strlen (plt_suffix); - plt = TRUE; + fragP->tc_frag_data.is_align = TRUE; + fragP->tc_frag_data.alignment = fragP->fr_offset; } - switch (size) + if (fragP->fr_type == rs_align_test) { - case 1: - r = BFD_RELOC_8; - break; - case 2: - r = BFD_RELOC_16; - break; - case 4: - r = plt ? BFD_RELOC_XTENSA_PLT : BFD_RELOC_32; - break; - case 8: - r = BFD_RELOC_64; - break; - default: - as_bad (_("unsupported BFD relocation size %u"), size); - r = BFD_RELOC_32; - break; + int count; + count = fragP->fr_next->fr_address - fragP->fr_address - fragP->fr_fix; + if (count != 0) + as_bad_where (fragP->fr_file, fragP->fr_line, + _("unaligned entry instruction")); } - fix_new_exp (frag, where, size, exp, 0, r); } - + /* TC_FRAG_INIT hook */ @@ -5075,7 +6137,7 @@ void xtensa_frag_init (frag) fragS *frag; { - frag->tc_frag_data.is_no_density = !code_density_available (); + xtensa_set_frag_assembly_state (frag); } @@ -5104,11 +6166,15 @@ md_pcrel_from (fixP) { char *insn_p; static xtensa_insnbuf insnbuf = NULL; + static xtensa_insnbuf slotbuf = NULL; int opnum; - xtensa_operand operand; + uint32 opnd_value; xtensa_opcode opcode; + xtensa_format fmt; + int slot; xtensa_isa isa = xtensa_default_isa; valueT addr = fixP->fx_where + fixP->fx_frag->fr_address; + bfd_boolean alt_reloc; if (fixP->fx_done) return addr; @@ -5117,31 +6183,38 @@ md_pcrel_from (fixP) return addr; if (!insnbuf) - insnbuf = xtensa_insnbuf_alloc (isa); + { + insnbuf = xtensa_insnbuf_alloc (isa); + slotbuf = xtensa_insnbuf_alloc (isa); + } insn_p = &fixP->fx_frag->fr_literal[fixP->fx_where]; - xtensa_insnbuf_from_chars (isa, insnbuf, insn_p); - opcode = xtensa_decode_insn (isa, insnbuf); - - opnum = reloc_to_opnum (fixP->fx_r_type); - - if (opnum < 0) - as_fatal (_("invalid operand relocation for '%s' instruction"), - xtensa_opcode_name (isa, opcode)); - if (opnum >= xtensa_num_operands (isa, opcode)) - as_fatal (_("invalid relocation for operand %d in '%s' instruction"), - opnum, xtensa_opcode_name (isa, opcode)); - operand = xtensa_get_operand (isa, opcode, opnum); - if (!operand) - { - as_warn_where (fixP->fx_file, - fixP->fx_line, - _("invalid relocation type %d for %s instruction"), - fixP->fx_r_type, xtensa_opcode_name (isa, opcode)); + xtensa_insnbuf_from_chars (isa, insnbuf, insn_p, 0); + fmt = xtensa_format_decode (isa, insnbuf); + + if (fmt == XTENSA_UNDEFINED) + as_fatal (_("bad instruction format")); + + if (decode_reloc (fixP->fx_r_type, &slot, &alt_reloc) != 0) + as_fatal (_("invalid relocation")); + + xtensa_format_get_slot (isa, fmt, slot, insnbuf, slotbuf); + opcode = xtensa_opcode_decode (isa, fmt, slot, slotbuf); + + /* Check for "alternate" relocation (operand not specified). */ + if (alt_reloc || opcode == xtensa_const16_opcode) + { + if (opcode != xtensa_l32r_opcode + && opcode != xtensa_const16_opcode) + as_fatal (_("invalid relocation for '%s' instruction"), + xtensa_opcode_name (isa, opcode)); return addr; } - if (!operand_is_pcrel_label (operand)) + opnum = get_relaxable_immed (opcode); + opnd_value = 0; + if (xtensa_operand_is_PCrelative (isa, opcode, opnum) != 1 + || xtensa_operand_do_reloc (isa, opcode, opnum, &opnd_value, addr)) { as_bad_where (fixP->fx_file, fixP->fx_line, @@ -5149,27 +6222,74 @@ md_pcrel_from (fixP) opnum, xtensa_opcode_name (isa, opcode)); return addr; } - if (!xtensa_operand_isPCRelative (operand)) - { - as_warn_where (fixP->fx_file, - fixP->fx_line, - _("non-PCREL relocation operand %d for '%s': %s"), - opnum, xtensa_opcode_name (isa, opcode), - bfd_get_reloc_code_name (fixP->fx_r_type)); - return addr; + return 0 - opnd_value; +} + + +/* TC_FORCE_RELOCATION hook */ + +int +xtensa_force_relocation (fix) + fixS *fix; +{ + switch (fix->fx_r_type) + { + case BFD_RELOC_XTENSA_SLOT0_ALT: + case BFD_RELOC_XTENSA_SLOT1_ALT: + case BFD_RELOC_XTENSA_SLOT2_ALT: + case BFD_RELOC_XTENSA_SLOT3_ALT: + case BFD_RELOC_XTENSA_SLOT4_ALT: + case BFD_RELOC_XTENSA_SLOT5_ALT: + case BFD_RELOC_XTENSA_SLOT6_ALT: + case BFD_RELOC_XTENSA_SLOT7_ALT: + case BFD_RELOC_XTENSA_SLOT8_ALT: + case BFD_RELOC_XTENSA_SLOT9_ALT: + case BFD_RELOC_XTENSA_SLOT10_ALT: + case BFD_RELOC_XTENSA_SLOT11_ALT: + case BFD_RELOC_XTENSA_SLOT12_ALT: + case BFD_RELOC_XTENSA_SLOT13_ALT: + case BFD_RELOC_XTENSA_SLOT14_ALT: + case BFD_RELOC_VTABLE_INHERIT: + case BFD_RELOC_VTABLE_ENTRY: + return 1; + default: + break; } - return 0 - xtensa_operand_do_reloc (operand, 0, addr); + if (linkrelax && fix->fx_addsy + && relaxable_section (S_GET_SEGMENT (fix->fx_addsy))) + return 1; + + return generic_force_reloc (fix); +} + + +/* NO_PSEUDO_DOT hook */ + +/* This function has nothing to do with pseudo dots, but this is the + nearest macro to where the check needs to take place. FIXME: This + seems wrong. */ + +bfd_boolean +xtensa_check_inside_bundle () +{ + if (cur_vinsn.inside_bundle && input_line_pointer[-1] == '.') + as_bad (_("directives are not valid inside bundles")); + + /* This function must always return FALSE because it is called via a + macro that has nothing to do with bundling. */ + return FALSE; } -/* tc_symbol_new_hook */ +/* md_elf_section_change_hook */ void -xtensa_symbol_new_hook (symbolP) - symbolS *symbolP; +xtensa_elf_section_change_hook () { - symbol_get_tc (symbolP)->plt = 0; + /* Set up the assembly state. */ + if (!frag_now->tc_frag_data.is_assembly_state_set) + xtensa_set_frag_assembly_state (frag_now); } @@ -5179,12 +6299,34 @@ bfd_boolean xtensa_fix_adjustable (fixP) fixS *fixP; { + /* An offset is not allowed in combination with the difference of two + symbols, but that cannot be easily detected after a local symbol + has been adjusted to a (section+offset) form. Return 0 so that such + an fix will not be adjusted. */ + if (fixP->fx_subsy && fixP->fx_addsy && fixP->fx_offset + && relaxable_section (S_GET_SEGMENT (fixP->fx_subsy))) + return 0; + /* We need the symbol name for the VTABLE entries. */ if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) return 0; + if (fixP->fx_addsy + && (S_IS_EXTERNAL (fixP->fx_addsy) || S_IS_WEAK (fixP->fx_addsy))) + return 0; + +#if 0 + /* We may someday want to enable this code to preserve relocations for + non-PC-relative fixes, possibly under control of a PIC flag. */ + return (fixP->fx_pcrel + || (fixP->fx_subsy != NULL + && (S_GET_SEGMENT (fixP->fx_subsy) + == S_GET_SEGMENT (fixP->fx_addsy))) + || S_IS_LOCAL (fixP->fx_addsy)); +#else return 1; +#endif } @@ -5196,14 +6338,7 @@ md_apply_fix3 (fixP, valP, seg) { if (fixP->fx_pcrel == 0 && fixP->fx_addsy == 0) { - /* This happens when the relocation is within the current section. - It seems this implies a PCREL operation. We'll catch it and error - if not. */ - char *const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where; - static xtensa_insnbuf insnbuf = NULL; - xtensa_opcode opcode; - xtensa_isa isa; switch (fixP->fx_r_type) { @@ -5224,26 +6359,6 @@ md_apply_fix3 (fixP, valP, seg) fixP->fx_done = 1; break; - case BFD_RELOC_XTENSA_OP0: - case BFD_RELOC_XTENSA_OP1: - case BFD_RELOC_XTENSA_OP2: - isa = xtensa_default_isa; - if (!insnbuf) - insnbuf = xtensa_insnbuf_alloc (isa); - - xtensa_insnbuf_from_chars (isa, insnbuf, fixpos); - opcode = xtensa_decode_insn (isa, insnbuf); - if (opcode == XTENSA_UNDEFINED) - as_fatal (_("undecodable FIX")); - - xtensa_insnbuf_set_immediate_field (opcode, insnbuf, *valP, - fixP->fx_file, fixP->fx_line); - - fixP->fx_frag->tc_frag_data.is_insn = TRUE; - xtensa_insnbuf_to_chars (isa, insnbuf, fixpos); - fixP->fx_done = 1; - break; - case BFD_RELOC_VTABLE_INHERIT: case BFD_RELOC_VTABLE_ENTRY: fixP->fx_done = 0; @@ -5308,7 +6423,7 @@ md_estimate_size_before_relax (fragP, seg) fragS *fragP; segT seg ATTRIBUTE_UNUSED; { - return fragP->tc_frag_data.text_expansion; + return fragP->tc_frag_data.text_expansion[0]; } @@ -5317,10 +6432,11 @@ md_estimate_size_before_relax (fragP, seg) arelent * tc_gen_reloc (section, fixp) - asection *section ATTRIBUTE_UNUSED; + asection *section; fixS *fixp; { arelent *reloc; + bfd_boolean apply_tentative_value = FALSE; reloc = (arelent *) xmalloc (sizeof (arelent)); reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); @@ -5331,116 +6447,1434 @@ tc_gen_reloc (section, fixp) They'd better have been fully resolved by this point. */ assert ((int) fixp->fx_r_type > 0); + if (linkrelax && fixp->fx_subsy + && (fixp->fx_r_type == BFD_RELOC_8 + || fixp->fx_r_type == BFD_RELOC_16 + || fixp->fx_r_type == BFD_RELOC_32)) + { + int diff_size = 0; + bfd_vma diff_value, diff_mask = 0; + + switch (fixp->fx_r_type) + { + case BFD_RELOC_8: + fixp->fx_r_type = BFD_RELOC_XTENSA_DIFF8; + diff_size = 1; + diff_mask = 0xff; + break; + case BFD_RELOC_16: + fixp->fx_r_type = BFD_RELOC_XTENSA_DIFF16; + diff_size = 2; + diff_mask = 0xffff; + break; + case BFD_RELOC_32: + fixp->fx_r_type = BFD_RELOC_XTENSA_DIFF32; + diff_size = 4; + diff_mask = 0xffffffff; + break; + default: + break; + } + + /* An offset is only allowed when it results from adjusting a local + symbol into a section-relative offset. If the offset came from the + original expression, tc_fix_adjustable will have prevented the fix + from being converted to a section-relative form so that we can flag + the error here. */ + if (fixp->fx_offset != 0 && !symbol_section_p (fixp->fx_addsy)) + { + as_bad_where (fixp->fx_file, fixp->fx_line, + _("cannot represent subtraction with an offset")); + free (reloc->sym_ptr_ptr); + free (reloc); + return NULL; + } + + assert (S_GET_SEGMENT (fixp->fx_addsy) + == S_GET_SEGMENT (fixp->fx_subsy)); + + diff_value = (S_GET_VALUE (fixp->fx_addsy) + fixp->fx_offset + - S_GET_VALUE (fixp->fx_subsy)); + + /* Check for overflow. */ + if ((diff_value & ~diff_mask) != 0) + { + as_bad_where (fixp->fx_file, fixp->fx_line, + _("value of %ld too large"), diff_value); + free (reloc->sym_ptr_ptr); + free (reloc); + return NULL; + } + + md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where, + diff_value, diff_size); + reloc->addend = fixp->fx_offset - diff_value; + } + else + { + reloc->addend = fixp->fx_offset; + + switch (fixp->fx_r_type) + { + case BFD_RELOC_XTENSA_SLOT0_OP: + case BFD_RELOC_XTENSA_SLOT1_OP: + case BFD_RELOC_XTENSA_SLOT2_OP: + case BFD_RELOC_XTENSA_SLOT3_OP: + case BFD_RELOC_XTENSA_SLOT4_OP: + case BFD_RELOC_XTENSA_SLOT5_OP: + case BFD_RELOC_XTENSA_SLOT6_OP: + case BFD_RELOC_XTENSA_SLOT7_OP: + case BFD_RELOC_XTENSA_SLOT8_OP: + case BFD_RELOC_XTENSA_SLOT9_OP: + case BFD_RELOC_XTENSA_SLOT10_OP: + case BFD_RELOC_XTENSA_SLOT11_OP: + case BFD_RELOC_XTENSA_SLOT12_OP: + case BFD_RELOC_XTENSA_SLOT13_OP: + case BFD_RELOC_XTENSA_SLOT14_OP: + /* As a special case, the immediate value for a CONST16 opcode + should not be applied, since this kind of relocation is + handled specially for CONST16 and is not really PC-relative. + Rather than decode the opcode here, just wait and handle it + in xg_apply_tentative_value. */ + apply_tentative_value = TRUE; + break; + + case BFD_RELOC_XTENSA_SLOT0_ALT: + case BFD_RELOC_XTENSA_SLOT1_ALT: + case BFD_RELOC_XTENSA_SLOT2_ALT: + case BFD_RELOC_XTENSA_SLOT3_ALT: + case BFD_RELOC_XTENSA_SLOT4_ALT: + case BFD_RELOC_XTENSA_SLOT5_ALT: + case BFD_RELOC_XTENSA_SLOT6_ALT: + case BFD_RELOC_XTENSA_SLOT7_ALT: + case BFD_RELOC_XTENSA_SLOT8_ALT: + case BFD_RELOC_XTENSA_SLOT9_ALT: + case BFD_RELOC_XTENSA_SLOT10_ALT: + case BFD_RELOC_XTENSA_SLOT11_ALT: + case BFD_RELOC_XTENSA_SLOT12_ALT: + case BFD_RELOC_XTENSA_SLOT13_ALT: + case BFD_RELOC_XTENSA_SLOT14_ALT: + case BFD_RELOC_XTENSA_ASM_EXPAND: + case BFD_RELOC_32: + case BFD_RELOC_XTENSA_PLT: + case BFD_RELOC_VTABLE_INHERIT: + case BFD_RELOC_VTABLE_ENTRY: + break; + + case BFD_RELOC_XTENSA_ASM_SIMPLIFY: + as_warn (_("emitting simplification relocation")); + break; + + default: + as_warn (_("emitting unknown relocation")); + } + } + reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); if (reloc->howto == NULL) { as_bad_where (fixp->fx_file, fixp->fx_line, _("cannot represent `%s' relocation in object file"), bfd_get_reloc_code_name (fixp->fx_r_type)); + free (reloc->sym_ptr_ptr); + free (reloc); return NULL; } if (!fixp->fx_pcrel != !reloc->howto->pc_relative) - { - as_fatal (_("internal error? cannot generate `%s' relocation"), - bfd_get_reloc_code_name (fixp->fx_r_type)); - } - assert (!fixp->fx_pcrel == !reloc->howto->pc_relative); + as_fatal (_("internal error? cannot generate `%s' relocation"), + bfd_get_reloc_code_name (fixp->fx_r_type)); - reloc->addend = fixp->fx_offset; + /* Write the tentative value of a PC-relative relocation to a local symbol + into the instruction. The value will be ignored by the linker, and it + makes the object file disassembly readable when the linkrelax flag is + set and all branch targets are encoded in relocations. */ - switch (fixp->fx_r_type) + if (linkrelax && apply_tentative_value && fixp->fx_pcrel) { - case BFD_RELOC_XTENSA_OP0: - case BFD_RELOC_XTENSA_OP1: - case BFD_RELOC_XTENSA_OP2: - case BFD_RELOC_XTENSA_ASM_EXPAND: - case BFD_RELOC_32: - case BFD_RELOC_XTENSA_PLT: - case BFD_RELOC_VTABLE_INHERIT: - case BFD_RELOC_VTABLE_ENTRY: - break; - - case BFD_RELOC_XTENSA_ASM_SIMPLIFY: - as_warn (_("emitting simplification relocation")); - break; - - default: - as_warn (_("emitting unknown relocation")); + valueT val; + assert (fixp->fx_addsy); + if (S_GET_SEGMENT (fixp->fx_addsy) == section && !fixp->fx_plt + && !S_FORCE_RELOC (fixp->fx_addsy, 1)) + { + val = (S_GET_VALUE (fixp->fx_addsy) + fixp->fx_offset + - md_pcrel_from (fixp)); + xg_apply_tentative_value (fixp, val); + } } return reloc; } - + +/* md_post_relax_hook */ + +#define XTENSA_INSN_SEC_NAME ".xt.insn" +#define XTENSA_LIT_SEC_NAME ".xt.lit" +#define XTENSA_PROP_SEC_NAME ".xt.prop" + void -xtensa_end () +xtensa_post_relax_hook () { - directive_balance (); - xtensa_move_literals (); - - xtensa_reorder_segments (); - xtensa_cleanup_align_frags (); - xtensa_fix_target_frags (); - if (software_a0_b_retw_interlock && has_a0_b_retw) - xtensa_fix_a0_b_retw_frags (); - if (software_avoid_b_j_loop_end && maybe_has_b_j_loop_end) - xtensa_fix_b_j_loop_end_frags (); + xtensa_move_seg_list_to_beginning (literal_head); + xtensa_move_seg_list_to_beginning (init_literal_head); + xtensa_move_seg_list_to_beginning (fini_literal_head); - /* "close_loop_end" should be processed BEFORE "short_loop". */ - if (software_avoid_close_loop_end && maybe_has_close_loop_end) - xtensa_fix_close_loop_end_frags (); + xtensa_find_unmarked_state_frags (); - if (software_avoid_short_loop && maybe_has_short_loop) - xtensa_fix_short_loop_frags (); + if (use_literal_section) + xtensa_create_property_segments (get_frag_is_literal, + NULL, + XTENSA_LIT_SEC_NAME, + xt_literal_sec); + xtensa_create_xproperty_segments (get_frag_property_flags, + XTENSA_PROP_SEC_NAME, + xt_prop_sec); - xtensa_sanity_check (); + if (warn_unaligned_branch_targets) + bfd_map_over_sections (stdoutput, xtensa_find_unaligned_branch_targets, 0); + bfd_map_over_sections (stdoutput, xtensa_find_unaligned_loops, 0); } +/* We have reached the end of a bundle; emit into the frag. */ + static void -xtensa_cleanup_align_frags () +finish_vinsn (vinsn) + vliw_insn *vinsn; { - frchainS *frchP; + IStack slotstack; + int i; + char *file_name; + int line; - for (frchP = frchain_root; frchP; frchP = frchP->frch_next) + if (find_vinsn_conflicts (vinsn)) + return; + + /* First, find a format that works. */ + if (vinsn->format == XTENSA_UNDEFINED) + vinsn->format = xg_find_narrowest_format (vinsn); + + if (vinsn->format == XTENSA_UNDEFINED) + { + as_where (&file_name, &line); + as_bad_where (file_name, line, + _("couldn't find a valid instruction format")); + fprintf (stderr, _(" ops were: ")); + for (i = 0; i < vinsn->num_slots; i++) + fprintf (stderr, _(" %s;"), + xtensa_opcode_name (xtensa_default_isa, + vinsn->slots[i].opcode)); + fprintf (stderr, _("\n")); + xg_clear_vinsn (vinsn); + return; + } + + if (vinsn->num_slots + != xtensa_format_num_slots (xtensa_default_isa, vinsn->format)) { - fragS *fragP; + as_bad (_("format '%s' allows %d slots, but there are %d opcodes"), + xtensa_format_name (xtensa_default_isa, vinsn->format), + xtensa_format_num_slots (xtensa_default_isa, vinsn->format), + vinsn->num_slots); + xg_clear_vinsn (vinsn); + return; + } - /* Walk over all of the fragments in a subsection. */ - for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next) + if (resources_conflict (vinsn)) + { + as_where (&file_name, &line); + as_bad_where (file_name, line, _("illegal resource usage in bundle")); + fprintf (stderr, " ops were: "); + for (i = 0; i < vinsn->num_slots; i++) + fprintf (stderr, " %s;", + xtensa_opcode_name (xtensa_default_isa, + vinsn->slots[i].opcode)); + fprintf (stderr, "\n"); + xg_clear_vinsn (vinsn); + return; + } + + for (i = 0; i < vinsn->num_slots; i++) + { + if (vinsn->slots[i].opcode != XTENSA_UNDEFINED) { - if ((fragP->fr_type == rs_align - || fragP->fr_type == rs_align_code - || (fragP->fr_type == rs_machine_dependent - && (fragP->fr_subtype == RELAX_DESIRE_ALIGN - || fragP->fr_subtype == RELAX_DESIRE_ALIGN_IF_TARGET))) - && fragP->fr_fix == 0) + symbolS *lit_sym = NULL; + int j; + bfd_boolean e = FALSE; + bfd_boolean saved_density = density_supported; + + /* We don't want to narrow ops inside multi-slot bundles. */ + if (vinsn->num_slots > 1) + density_supported = FALSE; + + istack_init (&slotstack); + if (vinsn->slots[i].opcode == xtensa_nop_opcode) { - fragS * next = fragP->fr_next; + vinsn->slots[i].opcode = + xtensa_format_slot_nop_opcode (xtensa_default_isa, + vinsn->format, i); + vinsn->slots[i].ntok = 0; + } - while (next - && next->fr_type == rs_machine_dependent - && next->fr_subtype == RELAX_DESIRE_ALIGN_IF_TARGET) - { - frag_wane (next); - next = next->fr_next; - } + if (xg_expand_assembly_insn (&slotstack, &vinsn->slots[i])) + { + e = TRUE; + continue; } - } - } -} + density_supported = saved_density; -/* Re-process all of the fragments looking to convert all of the - RELAX_DESIRE_ALIGN_IF_TARGET fragments. If there is a branch - target in the next fragment, convert this to RELAX_DESIRE_ALIGN. - If the next fragment starts with a loop target, AND the previous - fragment can be expanded to negate the branch, convert this to a - RELAX_LOOP_END. Otherwise, convert to a .fill 0. */ + if (e) + { + xg_clear_vinsn (vinsn); + return; + } -static void -xtensa_fix_target_frags () + for (j = 0; j < slotstack.ninsn - 1; j++) + { + TInsn *insn = &slotstack.insn[j]; + if (insn->insn_type == ITYPE_LITERAL) + { + assert (lit_sym == NULL); + lit_sym = xg_assemble_literal (insn); + } + else + { + if (lit_sym) + xg_resolve_literals (insn, lit_sym); + emit_single_op (insn); + } + } + + if (vinsn->num_slots > 1) + { + if (opcode_fits_format_slot + (slotstack.insn[slotstack.ninsn - 1].opcode, + vinsn->format, i)) + { + vinsn->slots[i] = slotstack.insn[slotstack.ninsn - 1]; + } + else + { + bundle_single_op (&slotstack.insn[slotstack.ninsn - 1]); + if (vinsn->format == XTENSA_UNDEFINED) + vinsn->slots[i].opcode = xtensa_nop_opcode; + else + vinsn->slots[i].opcode + = xtensa_format_slot_nop_opcode (xtensa_default_isa, + vinsn->format, i); + + vinsn->slots[i].ntok = 0; + } + } + else + { + vinsn->slots[0] = slotstack.insn[slotstack.ninsn - 1]; + vinsn->format = XTENSA_UNDEFINED; + } + } + } + + /* Now check resource conflicts on the modified bundle. */ + if (resources_conflict (vinsn)) + { + as_where (&file_name, &line); + as_bad_where (file_name, line, _("illegal resource usage in bundle")); + fprintf (stderr, " ops were: "); + for (i = 0; i < vinsn->num_slots; i++) + fprintf (stderr, " %s;", + xtensa_opcode_name (xtensa_default_isa, + vinsn->slots[i].opcode)); + fprintf (stderr, "\n"); + xg_clear_vinsn (vinsn); + return; + } + + /* First, find a format that works. */ + if (vinsn->format == XTENSA_UNDEFINED) + vinsn->format = xg_find_narrowest_format (vinsn); + + xg_assemble_vliw_tokens (vinsn); + + xg_clear_vinsn (vinsn); +} + + +/* Given an vliw instruction, what conflicts are there in register + usage and in writes to states and queues? + + This function does two things: + 1. Reports an error when a vinsn contains illegal combinations + of writes to registers states or queues. + 2. Marks individual tinsns as not relaxable if the combination + contains antidependencies. + + Job 2 handles things like swap semantics in instructions that need + to be relaxed. For example, + + addi a0, a1, 100000 + + normally would be relaxed to + + l32r a0, some_label + add a0, a1, a0 + + _but_, if the above instruction is bundled with an a0 reader, e.g., + + { addi a0, a1, 10000 ; add a2, a0, a4 ; } + + then we can't relax it into + + l32r a0, some_label + { add a0, a1, a0 ; add a2, a0, a4 ; } + + because the value of a0 is trashed before the second add can read it. */ + +static bfd_boolean +find_vinsn_conflicts (vinsn) + vliw_insn *vinsn; +{ + int i, j; + int branches = 0; + xtensa_isa isa = xtensa_default_isa; + + assert (!past_xtensa_end); + + for (i = 0 ; i < vinsn->num_slots; i++) + { + TInsn *op1 = &vinsn->slots[i]; + if (op1->is_specific_opcode) + op1->keep_wide = TRUE; + else + op1->keep_wide = FALSE; + } + + for (i = 0 ; i < vinsn->num_slots; i++) + { + TInsn *op1 = &vinsn->slots[i]; + + if (xtensa_opcode_is_branch (isa, op1->opcode) == 1) + branches++; + + for (j = 0; j < vinsn->num_slots; j++) + { + if (i != j) + { + TInsn *op2 = &vinsn->slots[j]; + char conflict_type = check_t1_t2_reads_and_writes (op1, op2); + switch (conflict_type) + { + case 'c': + as_bad (_("opcodes '%s' (slot %d) and '%s' (slot %d) write the same register"), + xtensa_opcode_name (isa, op1->opcode), i, + xtensa_opcode_name (isa, op2->opcode), j); + return TRUE; + case 'd': + as_bad (_("opcodes '%s' (slot %d) and '%s' (slot %d) write the same state"), + xtensa_opcode_name (isa, op1->opcode), i, + xtensa_opcode_name (isa, op2->opcode), j); + return TRUE; + case 'e': + as_bad (_("opcodes '%s' (slot %d) and '%s' (slot %d) write the same queue"), + xtensa_opcode_name (isa, op1->opcode), i, + xtensa_opcode_name (isa, op2->opcode), j); + return TRUE; + case 'f': + as_bad (_("opcodes '%s' (slot %d) and '%s' (slot %d) both have volatile queue accesses"), + xtensa_opcode_name (isa, op1->opcode), i, + xtensa_opcode_name (isa, op2->opcode), j); + return TRUE; + default: + /* Everything is OK. */ + break; + } + op2->is_specific_opcode = (op2->is_specific_opcode + || conflict_type == 'a'); + } + } + } + + if (branches > 1) + { + as_bad (_("multiple branches or jumps in the same bundle")); + return TRUE; + } + + return FALSE; +} + + +/* Check how the result registers of t1 and t2 relate. + Cases found are: + + case A: t1 reads a register t2 writes (an antidependency within a bundle) + case B: no relationship between what is read and written (both could + read the same reg though) + case C: t1 writes a register t2 writes (a register conflict within a + bundle) + case D: t1 writes a state that t2 also writes + case E: t1 writes a tie queue that t2 also writes + case F: two volatile queue writes +*/ + +static char +check_t1_t2_reads_and_writes (t1, t2) + TInsn *t1; + TInsn *t2; +{ + xtensa_isa isa = xtensa_default_isa; + xtensa_regfile t1_regfile, t2_regfile; + int t1_reg, t2_reg; + int t1_base_reg, t1_last_reg; + int t2_base_reg, t2_last_reg; + char t1_inout, t2_inout; + int i, j; + char conflict = 'b'; + int t1_states; + int t2_states; + int t1_interfaces; + int t2_interfaces; + bfd_boolean t1_volatile = FALSE; + bfd_boolean t2_volatile = FALSE; + + /* Check registers. */ + for (j = 0; j < t2->ntok; j++) + { + if (xtensa_operand_is_register (isa, t2->opcode, j) != 1) + continue; + + t2_regfile = xtensa_operand_regfile (isa, t2->opcode, j); + t2_base_reg = t2->tok[j].X_add_number; + t2_last_reg = t2_base_reg + xtensa_operand_num_regs (isa, t2->opcode, j); + + for (i = 0; i < t1->ntok; i++) + { + if (xtensa_operand_is_register (isa, t1->opcode, i) != 1) + continue; + + t1_regfile = xtensa_operand_regfile (isa, t1->opcode, i); + + if (t1_regfile != t2_regfile) + continue; + + t1_inout = xtensa_operand_inout (isa, t1->opcode, i); + t2_inout = xtensa_operand_inout (isa, t2->opcode, j); + + if (xtensa_operand_is_known_reg (isa, t1->opcode, i) == 0 + || xtensa_operand_is_known_reg (isa, t2->opcode, j) == 0) + { + if (t1_inout == 'm' || t1_inout == 'o' + || t2_inout == 'm' || t2_inout == 'o') + { + conflict = 'a'; + continue; + } + } + + t1_base_reg = t1->tok[i].X_add_number; + t1_last_reg = (t1_base_reg + + xtensa_operand_num_regs (isa, t1->opcode, i)); + + for (t1_reg = t1_base_reg; t1_reg < t1_last_reg; t1_reg++) + { + for (t2_reg = t2_base_reg; t2_reg < t2_last_reg; t2_reg++) + { + if (t1_reg != t2_reg) + continue; + + if (t2_inout == 'i' && (t1_inout == 'm' || t1_inout == 'o')) + { + conflict = 'a'; + continue; + } + + if (t1_inout == 'i' && (t2_inout == 'm' || t2_inout == 'o')) + { + conflict = 'a'; + continue; + } + + if (t1_inout != 'i' && t2_inout != 'i') + return 'c'; + } + } + } + } + + /* Check states. */ + t1_states = xtensa_opcode_num_stateOperands (isa, t1->opcode); + t2_states = xtensa_opcode_num_stateOperands (isa, t2->opcode); + for (j = 0; j < t2_states; j++) + { + xtensa_state t2_so = xtensa_stateOperand_state (isa, t2->opcode, j); + t2_inout = xtensa_stateOperand_inout (isa, t2->opcode, j); + for (i = 0; i < t1_states; i++) + { + xtensa_state t1_so = xtensa_stateOperand_state (isa, t1->opcode, i); + t1_inout = xtensa_stateOperand_inout (isa, t1->opcode, i); + if (t1_so != t2_so) + continue; + + if (t2_inout == 'i' && (t1_inout == 'm' || t1_inout == 'o')) + { + conflict = 'a'; + continue; + } + + if (t1_inout == 'i' && (t2_inout == 'm' || t2_inout == 'o')) + { + conflict = 'a'; + continue; + } + + if (t1_inout != 'i' && t2_inout != 'i') + return 'd'; + } + } + + /* Check tieports. */ + t1_interfaces = xtensa_opcode_num_interfaceOperands (isa, t1->opcode); + t2_interfaces = xtensa_opcode_num_interfaceOperands (isa, t2->opcode); + for (j = 0; j < t2_interfaces; j++) + { + xtensa_interface t2_int + = xtensa_interfaceOperand_interface (isa, t2->opcode, j); + t2_inout = xtensa_interface_inout (isa, j); + if (xtensa_interface_has_side_effect (isa, t2_int) == 1 + && t2_inout != 'i') + t2_volatile = TRUE; + for (i = 0; i < t1_interfaces; i++) + { + xtensa_interface t1_int + = xtensa_interfaceOperand_interface (isa, t1->opcode, j); + t1_inout = xtensa_interface_inout (isa, i); + if (xtensa_interface_has_side_effect (isa, t1_int) == 1 + && t1_inout != 'i') + t1_volatile = TRUE; + + if (t1_int != t2_int) + continue; + + if (t2_inout == 'i' && t1_inout == 'o') + { + conflict = 'a'; + continue; + } + + if (t1_inout == 'i' && t2_inout == 'o') + { + conflict = 'a'; + continue; + } + + if (t1_inout != 'i' && t2_inout != 'i') + return 'e'; + } + } + + if (t1_volatile && t2_volatile) + return 'f'; + + return conflict; +} + + +/* The func unit stuff could be implemented as bit-vectors rather + than the iterative approach here. If it ends up being too + slow, we will switch it. */ + +resource_table * +new_resource_table (data, cycles, nu, uncf, onuf, ouuf, ousf) + void *data; + int cycles; + int nu; + unit_num_copies_func uncf; + opcode_num_units_func onuf; + opcode_funcUnit_use_unit_func ouuf; + opcode_funcUnit_use_stage_func ousf; +{ + int i; + resource_table *rt = (resource_table *) xmalloc (sizeof (resource_table)); + rt->data = data; + rt->cycles = cycles; + rt->allocated_cycles = cycles; + rt->num_units = nu; + rt->unit_num_copies = uncf; + rt->opcode_num_units = onuf; + rt->opcode_unit_use = ouuf; + rt->opcode_unit_stage = ousf; + + rt->units = (char **) xcalloc (cycles, sizeof (char *)); + for (i = 0; i < cycles; i++) + rt->units[i] = (char *) xcalloc (nu, sizeof (char)); + + return rt; +} + + +void +clear_resource_table (rt) + resource_table *rt; +{ + int i, j; + for (i = 0; i < rt->allocated_cycles; i++) + for (j = 0; j < rt->num_units; j++) + rt->units[i][j] = 0; +} + + +/* We never shrink it, just fake it into thinking so. */ + +void +resize_resource_table (rt, cycles) + resource_table *rt; + int cycles; +{ + int i, old_cycles; + + rt->cycles = cycles; + if (cycles <= rt->allocated_cycles) + return; + + old_cycles = rt->allocated_cycles; + rt->allocated_cycles = cycles; + + rt->units = xrealloc (rt->units, sizeof (char *) * rt->allocated_cycles); + for (i = 0; i < old_cycles; i++) + rt->units[i] = xrealloc (rt->units[i], sizeof (char) * rt->num_units); + for (i = old_cycles; i < cycles; i++) + rt->units[i] = xcalloc (rt->num_units, sizeof (char)); +} + + +bfd_boolean +resources_available (rt, opcode, cycle) + resource_table *rt; + xtensa_opcode opcode; + int cycle; +{ + int i; + int uses = (rt->opcode_num_units) (rt->data, opcode); + + for (i = 0; i < uses; i++) + { + xtensa_funcUnit unit = (rt->opcode_unit_use) (rt->data, opcode, i); + int stage = (rt->opcode_unit_stage) (rt->data, opcode, i); + int copies_in_use = rt->units[stage + cycle][unit]; + int copies = (rt->unit_num_copies) (rt->data, unit); + if (copies_in_use >= copies) + return FALSE; + } + return TRUE; +} + + +void +reserve_resources (rt, opcode, cycle) + resource_table *rt; + xtensa_opcode opcode; + int cycle; +{ + int i; + int uses = (rt->opcode_num_units) (rt->data, opcode); + + for (i = 0; i < uses; i++) + { + xtensa_funcUnit unit = (rt->opcode_unit_use) (rt->data, opcode, i); + int stage = (rt->opcode_unit_stage) (rt->data, opcode, i); + /* Note that this allows resources to be oversubscribed. That's + essential to the way the optional scheduler works. + resources_available reports when a resource is over-subscribed, + so it's easy to tell. */ + rt->units[stage + cycle][unit]++; + } +} + + +void +release_resources (rt, opcode, cycle) + resource_table *rt; + xtensa_opcode opcode; + int cycle; +{ + int i; + int uses = (rt->opcode_num_units) (rt->data, opcode); + + for (i = 0; i < uses; i++) + { + xtensa_funcUnit unit = (rt->opcode_unit_use) (rt->data, opcode, i); + int stage = (rt->opcode_unit_stage) (rt->data, opcode, i); + rt->units[stage + cycle][unit]--; + assert (rt->units[stage + cycle][unit] >= 0); + } +} + + +/* Wrapper functions make parameterized resource reservation + more convenient. */ + +int +opcode_funcUnit_use_unit (data, opcode, idx) + void *data; + xtensa_opcode opcode; + int idx; +{ + xtensa_funcUnit_use *use = xtensa_opcode_funcUnit_use (data, opcode, idx); + return use->unit; +} + + +int +opcode_funcUnit_use_stage (data, opcode, idx) + void *data; + xtensa_opcode opcode; + int idx; +{ + xtensa_funcUnit_use *use = xtensa_opcode_funcUnit_use (data, opcode, idx); + return use->stage; +} + + +/* Note that this function does not check issue constraints, but + solely whether the hardware is available to execute the given + instructions together. It also doesn't check if the tinsns + write the same state, or access the same tieports. That is + checked by check_t1_t2_read_write. */ + +static bfd_boolean +resources_conflict (vinsn) + vliw_insn *vinsn; +{ + int i; + static resource_table *rt = NULL; + + /* This is the most common case by far. Optimize it. */ + if (vinsn->num_slots == 1) + return FALSE; + + if (rt == NULL) + { + xtensa_isa isa = xtensa_default_isa; + rt = new_resource_table + (isa, xtensa_isa_num_pipe_stages (isa), + xtensa_isa_num_funcUnits (isa), + (unit_num_copies_func) xtensa_funcUnit_num_copies, + (opcode_num_units_func) xtensa_opcode_num_funcUnit_uses, + opcode_funcUnit_use_unit, + opcode_funcUnit_use_stage); + } + + clear_resource_table (rt); + + for (i = 0; i < vinsn->num_slots; i++) + { + if (!resources_available (rt, vinsn->slots[i].opcode, 0)) + return TRUE; + reserve_resources (rt, vinsn->slots[i].opcode, 0); + } + + return FALSE; +} + + +static xtensa_format +xg_find_narrowest_format (vinsn) + vliw_insn *vinsn; +{ + /* Right now we assume that the ops within the vinsn are properly + ordered for the slots that the programmer wanted them in. In + other words, we don't rearrange the ops in hopes of finding a + better format. The scheduler handles that. */ + + xtensa_isa isa = xtensa_default_isa; + xtensa_format format; + vliw_insn v_copy = *vinsn; + xtensa_opcode nop_opcode = xtensa_nop_opcode; + + for (format = 0; format < xtensa_isa_num_formats (isa); format++) + { + v_copy = *vinsn; + if (xtensa_format_num_slots (isa, format) == v_copy.num_slots) + { + int slot; + int fit = 0; + for (slot = 0; slot < v_copy.num_slots; slot++) + { + if (v_copy.slots[slot].opcode == nop_opcode) + { + v_copy.slots[slot].opcode = + xtensa_format_slot_nop_opcode (isa, format, slot); + v_copy.slots[slot].ntok = 0; + } + + if (opcode_fits_format_slot (v_copy.slots[slot].opcode, + format, slot)) + fit++; + else + { + if (v_copy.num_slots > 1) + { + TInsn widened; + /* Try the widened version. */ + if (!v_copy.slots[slot].keep_wide + && !v_copy.slots[slot].is_specific_opcode + && xg_is_narrow_insn (&v_copy.slots[slot]) + && !xg_expand_narrow (&widened, &v_copy.slots[slot]) + && opcode_fits_format_slot (widened.opcode, + format, slot)) + { + /* The xg_is_narrow clause requires some explanation: + + addi can be "widened" to an addmi, which is then + expanded to an addmi/addi pair if the immediate + requires it, but here we must have a single widen + only. + + xg_is_narrow tells us that addi isn't really + narrow. The widen_spec_list says that there are + other cases. */ + + v_copy.slots[slot] = widened; + fit++; + } + } + } + } + if (fit == v_copy.num_slots) + { + *vinsn = v_copy; + xtensa_format_encode (isa, format, vinsn->insnbuf); + vinsn->format = format; + break; + } + } + } + + if (format == xtensa_isa_num_formats (isa)) + return XTENSA_UNDEFINED; + + return format; +} + + +/* Return the additional space needed in a frag + for possible relaxations of any ops in a VLIW insn. + Also fill out the relaxations that might be required of + each tinsn in the vinsn. */ + +static int +relaxation_requirements (vinsn) + vliw_insn *vinsn; +{ + int extra_space = 0; + int slot; + + for (slot = 0; slot < vinsn->num_slots; slot++) + { + TInsn *tinsn = &vinsn->slots[slot]; + if (!tinsn_has_symbolic_operands (tinsn)) + { + /* A narrow instruction could be widened later to help + alignment issues. */ + if (xg_is_narrow_insn (tinsn) + && !tinsn->is_specific_opcode + && vinsn->num_slots == 1) + { + /* Difference in bytes between narrow and wide insns... */ + extra_space += 1; + tinsn->subtype = RELAX_NARROW; + tinsn->record_fix = TRUE; + break; + } + else + { + tinsn->record_fix = FALSE; + /* No extra_space needed. */ + } + } + else + { + if (workaround_b_j_loop_end && is_jx_opcode (tinsn->opcode) + && use_transform ()) + { + /* Add 2 of these. */ + extra_space += 3; /* for the nop size */ + tinsn->subtype = RELAX_ADD_NOP_IF_PRE_LOOP_END; + } + + /* Need to assemble it with space for the relocation. */ + if (xg_is_relaxable_insn (tinsn, 0) + && !tinsn->is_specific_opcode) + { + int max_size = xg_get_max_insn_widen_size (tinsn->opcode); + int max_literal_size = + xg_get_max_insn_widen_literal_size (tinsn->opcode); + + tinsn->literal_space = max_literal_size; + + tinsn->subtype = RELAX_IMMED; + tinsn->record_fix = FALSE; + extra_space += max_size; + } + else + { + tinsn->record_fix = TRUE; + /* No extra space needed. */ + } + } + } + return extra_space; +} + + +static void +bundle_single_op (orig_insn) + TInsn *orig_insn; +{ + xtensa_isa isa = xtensa_default_isa; + vliw_insn v; + int slot; + + xg_init_vinsn (&v); + v.format = op_placement_table[orig_insn->opcode].narrowest; + assert (v.format != XTENSA_UNDEFINED); + v.num_slots = xtensa_format_num_slots (isa, v.format); + + for (slot = 0; + !opcode_fits_format_slot (orig_insn->opcode, v.format, slot); + slot++) + { + v.slots[slot].opcode = + xtensa_format_slot_nop_opcode (isa, v.format, slot); + v.slots[slot].ntok = 0; + v.slots[slot].insn_type = ITYPE_INSN; + } + + v.slots[slot] = *orig_insn; + slot++; + + for ( ; slot < v.num_slots; slot++) + { + v.slots[slot].opcode = + xtensa_format_slot_nop_opcode (isa, v.format, slot); + v.slots[slot].ntok = 0; + v.slots[slot].insn_type = ITYPE_INSN; + } + + finish_vinsn (&v); + xg_free_vinsn (&v); +} + + +static bfd_boolean +emit_single_op (orig_insn) + TInsn *orig_insn; +{ + int i; + IStack istack; /* put instructions into here */ + symbolS *lit_sym = NULL; + symbolS *label_sym = NULL; + + istack_init (&istack); + + /* Special-case for "movi aX, foo" which is guaranteed to need relaxing. + Because the scheduling and bundling characteristics of movi and + l32r or const16 are so different, we can do much better if we relax + it prior to scheduling and bundling, rather than after. */ + if (is_movi_opcode (orig_insn->opcode) && !cur_vinsn.inside_bundle + && (orig_insn->tok[1].X_op == O_symbol + || orig_insn->tok[1].X_op == O_pltrel)) + xg_assembly_relax (&istack, orig_insn, now_seg, frag_now, 0, 1, 0); + else + if (xg_expand_assembly_insn (&istack, orig_insn)) + return TRUE; + + for (i = 0; i < istack.ninsn; i++) + { + TInsn *insn = &istack.insn[i]; + switch (insn->insn_type) + { + case ITYPE_LITERAL: + assert (lit_sym == NULL); + lit_sym = xg_assemble_literal (insn); + break; + case ITYPE_LABEL: + { + static int relaxed_sym_idx = 0; + char *label = xmalloc (strlen (FAKE_LABEL_NAME) + 12); + sprintf (label, "%s_rl_%x", FAKE_LABEL_NAME, relaxed_sym_idx++); + colon (label); + assert (label_sym == NULL); + label_sym = symbol_find_or_make (label); + assert (label_sym); + free (label); + } + break; + case ITYPE_INSN: + if (lit_sym) + xg_resolve_literals (insn, lit_sym); + if (label_sym) + xg_resolve_labels (insn, label_sym); + bundle_single_op (insn); + break; + default: + assert (0); + break; + } + } + return FALSE; +} + + +/* Emit a vliw instruction to the current fragment. */ + +void +xg_assemble_vliw_tokens (vinsn) + vliw_insn *vinsn; +{ + bfd_boolean finish_frag = FALSE; + bfd_boolean is_jump = FALSE; + bfd_boolean is_branch = FALSE; + xtensa_isa isa = xtensa_default_isa; + int i; + int insn_size; + int extra_space; + char *f = NULL; + int slot; + struct dwarf2_line_info best_loc; + + best_loc.line = INT_MAX; + + if (generating_literals) + { + static int reported = 0; + if (reported < 4) + as_bad_where (frag_now->fr_file, frag_now->fr_line, + _("cannot assemble into a literal fragment")); + if (reported == 3) + as_bad (_("...")); + reported++; + return; + } + + if (frag_now_fix () != 0 + && (!get_frag_is_insn (frag_now) + || (vinsn_has_specific_opcodes (vinsn) && use_transform ()) + || !use_transform () != get_frag_is_no_transform (frag_now) + || (directive_state[directive_absolute_literals] + != frag_now->tc_frag_data.use_absolute_literals))) + { + frag_wane (frag_now); + frag_new (0); + xtensa_set_frag_assembly_state (frag_now); + } + + if (workaround_a0_b_retw + && vinsn->num_slots == 1 + && (get_last_insn_flags (now_seg, now_subseg) & FLAG_IS_A0_WRITER) != 0 + && xtensa_opcode_is_branch (isa, vinsn->slots[0].opcode) == 1 + && use_transform ()) + { + has_a0_b_retw = TRUE; + + /* Mark this fragment with the special RELAX_ADD_NOP_IF_A0_B_RETW. + After the first assembly pass we will check all of them and + add a nop if needed. */ + frag_now->tc_frag_data.is_insn = TRUE; + frag_var (rs_machine_dependent, 4, 4, + RELAX_ADD_NOP_IF_A0_B_RETW, + frag_now->fr_symbol, + frag_now->fr_offset, + NULL); + xtensa_set_frag_assembly_state (frag_now); + frag_now->tc_frag_data.is_insn = TRUE; + frag_var (rs_machine_dependent, 4, 4, + RELAX_ADD_NOP_IF_A0_B_RETW, + frag_now->fr_symbol, + frag_now->fr_offset, + NULL); + xtensa_set_frag_assembly_state (frag_now); + } + + for (i = 0; i < vinsn->num_slots; i++) + { + /* See if the instruction implies an aligned section. */ + if (xtensa_opcode_is_loop (isa, vinsn->slots[i].opcode) == 1) + record_alignment (now_seg, 2); + + /* Also determine the best line number for debug info. */ + best_loc = vinsn->slots[i].loc.line < best_loc.line + ? vinsn->slots[i].loc : best_loc; + } + + /* Special cases for instructions that force an alignment... */ + /* None of these opcodes are bundle-able. */ + if (xtensa_opcode_is_loop (isa, vinsn->slots[0].opcode) == 1) + { + size_t max_fill; + + xtensa_set_frag_assembly_state (frag_now); + frag_now->tc_frag_data.is_insn = TRUE; + + max_fill = get_text_align_max_fill_size + (get_text_align_power (xtensa_fetch_width), + TRUE, frag_now->tc_frag_data.is_no_density); + + if (use_transform ()) + frag_var (rs_machine_dependent, max_fill, max_fill, + RELAX_ALIGN_NEXT_OPCODE, + frag_now->fr_symbol, + frag_now->fr_offset, + NULL); + else + frag_var (rs_machine_dependent, 0, 0, + RELAX_CHECK_ALIGN_NEXT_OPCODE, 0, 0, NULL); + xtensa_set_frag_assembly_state (frag_now); + + xtensa_move_labels (frag_now, 0, FALSE); + } + + if (is_entry_opcode (vinsn->slots[0].opcode) + && !vinsn->slots[0].is_specific_opcode) + { + xtensa_mark_literal_pool_location (); + xtensa_move_labels (frag_now, 0, TRUE); + frag_var (rs_align_test, 1, 1, 0, NULL, 2, NULL); + } + + if (vinsn->num_slots == 1) + { + if (workaround_a0_b_retw && use_transform ()) + set_last_insn_flags (now_seg, now_subseg, FLAG_IS_A0_WRITER, + is_register_writer (&vinsn->slots[0], "a", 0)); + + set_last_insn_flags (now_seg, now_subseg, FLAG_IS_BAD_LOOPEND, + is_bad_loopend_opcode (&vinsn->slots[0])); + } + else + set_last_insn_flags (now_seg, now_subseg, FLAG_IS_BAD_LOOPEND, FALSE); + + insn_size = xtensa_format_length (isa, vinsn->format); + + extra_space = relaxation_requirements (vinsn); + + /* vinsn_to_insnbuf will produce the error. */ + if (vinsn->format != XTENSA_UNDEFINED) + { + f = (char *) frag_more (insn_size + extra_space); + xtensa_set_frag_assembly_state (frag_now); + frag_now->tc_frag_data.is_insn = TRUE; + } + + vinsn_to_insnbuf (vinsn, f, frag_now, TRUE); + if (vinsn->format == XTENSA_UNDEFINED) + return; + + xtensa_insnbuf_to_chars (isa, vinsn->insnbuf, f, 0); + + xtensa_dwarf2_emit_insn (insn_size - extra_space, &best_loc); + + for (slot = 0; slot < vinsn->num_slots; slot++) + { + TInsn *tinsn = &vinsn->slots[slot]; + frag_now->tc_frag_data.slot_subtypes[slot] = tinsn->subtype; + frag_now->tc_frag_data.slot_symbols[slot] = tinsn->symbol; + frag_now->tc_frag_data.slot_sub_symbols[slot] = tinsn->sub_symbol; + frag_now->tc_frag_data.slot_offsets[slot] = tinsn->offset; + frag_now->tc_frag_data.literal_frags[slot] = tinsn->literal_frag; + if (tinsn->literal_space != 0) + xg_assemble_literal_space (tinsn->literal_space, slot); + + if (tinsn->subtype == RELAX_NARROW) + assert (vinsn->num_slots == 1); + if (xtensa_opcode_is_jump (isa, tinsn->opcode) == 1) + is_jump = TRUE; + if (xtensa_opcode_is_branch (isa, tinsn->opcode) == 1) + is_branch = TRUE; + + if (tinsn->subtype || tinsn->symbol || tinsn->record_fix + || tinsn->offset || tinsn->literal_frag || is_jump || is_branch) + finish_frag = TRUE; + } + + if (vinsn_has_specific_opcodes (vinsn) && use_transform ()) + set_frag_is_specific_opcode (frag_now, TRUE); + + if (finish_frag) + { + frag_variant (rs_machine_dependent, + extra_space, extra_space, RELAX_SLOTS, + frag_now->fr_symbol, frag_now->fr_offset, f); + xtensa_set_frag_assembly_state (frag_now); + } + + /* Special cases for loops: + close_loop_end should be inserted AFTER short_loop. + Make sure that CLOSE loops are processed BEFORE short_loops + when converting them. */ + + /* "short_loop": Add a NOP if the loop is < 4 bytes. */ + if (xtensa_opcode_is_loop (isa, vinsn->slots[0].opcode) + && !vinsn->slots[0].is_specific_opcode) + { + if (workaround_short_loop && use_transform ()) + { + maybe_has_short_loop = TRUE; + frag_now->tc_frag_data.is_insn = TRUE; + frag_var (rs_machine_dependent, 4, 4, + RELAX_ADD_NOP_IF_SHORT_LOOP, + frag_now->fr_symbol, frag_now->fr_offset, NULL); + frag_now->tc_frag_data.is_insn = TRUE; + frag_var (rs_machine_dependent, 4, 4, + RELAX_ADD_NOP_IF_SHORT_LOOP, + frag_now->fr_symbol, frag_now->fr_offset, NULL); + } + + /* "close_loop_end": Add up to 12 bytes of NOPs to keep a + loop at least 12 bytes away from another loop's end. */ + if (workaround_close_loop_end && use_transform ()) + { + maybe_has_close_loop_end = TRUE; + frag_now->tc_frag_data.is_insn = TRUE; + frag_var (rs_machine_dependent, 12, 12, + RELAX_ADD_NOP_IF_CLOSE_LOOP_END, + frag_now->fr_symbol, frag_now->fr_offset, NULL); + } + } + + if (use_transform ()) + { + if (is_jump) + { + assert (finish_frag); + frag_var (rs_machine_dependent, + UNREACHABLE_MAX_WIDTH, UNREACHABLE_MAX_WIDTH, + RELAX_UNREACHABLE, + frag_now->fr_symbol, frag_now->fr_offset, NULL); + xtensa_set_frag_assembly_state (frag_now); + } + else if (is_branch && align_targets) + { + assert (finish_frag); + frag_var (rs_machine_dependent, + UNREACHABLE_MAX_WIDTH, UNREACHABLE_MAX_WIDTH, + RELAX_MAYBE_UNREACHABLE, + frag_now->fr_symbol, frag_now->fr_offset, NULL); + xtensa_set_frag_assembly_state (frag_now); + frag_var (rs_machine_dependent, + 0, 0, + RELAX_MAYBE_DESIRE_ALIGN, + frag_now->fr_symbol, frag_now->fr_offset, NULL); + xtensa_set_frag_assembly_state (frag_now); + } + } + + /* Now, if the original opcode was a call... */ + if (do_align_targets () + && xtensa_opcode_is_call (isa, vinsn->slots[0].opcode) == 1) + { + float freq = get_subseg_info (now_seg, now_subseg)->cur_total_freq; + frag_now->tc_frag_data.is_insn = TRUE; + frag_var (rs_machine_dependent, 4, (int) freq, RELAX_DESIRE_ALIGN, + frag_now->fr_symbol, frag_now->fr_offset, NULL); + xtensa_set_frag_assembly_state (frag_now); + } + + if (vinsn_has_specific_opcodes (vinsn) && use_transform ()) + { + frag_wane (frag_now); + frag_new (0); + xtensa_set_frag_assembly_state (frag_now); + } +} + + +void +xtensa_end () +{ + directive_balance (); + xtensa_flush_pending_output (); + + past_xtensa_end = TRUE; + + xtensa_move_literals (); + + xtensa_reorder_segments (); + xtensa_cleanup_align_frags (); + xtensa_fix_target_frags (); + if (workaround_a0_b_retw && has_a0_b_retw) + xtensa_fix_a0_b_retw_frags (); + if (workaround_b_j_loop_end) + xtensa_fix_b_j_loop_end_frags (); + + /* "close_loop_end" should be processed BEFORE "short_loop". */ + if (workaround_close_loop_end && maybe_has_close_loop_end) + xtensa_fix_close_loop_end_frags (); + + if (workaround_short_loop && maybe_has_short_loop) + xtensa_fix_short_loop_frags (); + xtensa_mark_narrow_branches (); + xtensa_mark_zcl_first_insns (); + + xtensa_sanity_check (); +} + + +static void +xtensa_cleanup_align_frags () +{ + frchainS *frchP; + + for (frchP = frchain_root; frchP; frchP = frchP->frch_next) + { + fragS *fragP; + /* Walk over all of the fragments in a subsection. */ + for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next) + { + if ((fragP->fr_type == rs_align + || fragP->fr_type == rs_align_code + || (fragP->fr_type == rs_machine_dependent + && (fragP->fr_subtype == RELAX_DESIRE_ALIGN + || fragP->fr_subtype == RELAX_DESIRE_ALIGN_IF_TARGET))) + && fragP->fr_fix == 0) + { + fragS *next = fragP->fr_next; + + while (next + && next->fr_fix == 0 + && next->fr_type == rs_machine_dependent + && next->fr_subtype == RELAX_DESIRE_ALIGN_IF_TARGET) + { + frag_wane (next); + next = next->fr_next; + } + } + /* If we don't widen branch targets, then they + will be easier to align. */ + if (fragP->tc_frag_data.is_branch_target + && fragP->fr_opcode == fragP->fr_literal + && fragP->fr_type == rs_machine_dependent + && fragP->fr_subtype == RELAX_SLOTS + && fragP->tc_frag_data.slot_subtypes[0] == RELAX_NARROW) + frag_wane (fragP); + if (fragP->fr_type == rs_machine_dependent + && fragP->fr_subtype == RELAX_UNREACHABLE) + fragP->tc_frag_data.is_unreachable = TRUE; + } + } +} + + +/* Re-process all of the fragments looking to convert all of the + RELAX_DESIRE_ALIGN_IF_TARGET fragments. If there is a branch + target in the next fragment, convert this to RELAX_DESIRE_ALIGN. + If the next fragment starts with a loop target, AND the previous + fragment can be expanded to negate the branch, convert this to a + RELAX_LOOP_END. Otherwise, convert to a .fill 0. */ + +static void +xtensa_fix_target_frags () { frchainS *frchP; @@ -5460,18 +7894,21 @@ xtensa_fix_target_frags () if (next_frag_is_loop_target (fragP)) { if (prev_frag_can_negate_branch) - fragP->fr_subtype = RELAX_LOOP_END; + { + fragP->fr_subtype = RELAX_LOOP_END; + /* See the comment near the frag_var with a + RELAX_DESIRE_ALIGN to see why we do this. */ + fragP->fr_var = RELAX_LOOP_END_BYTES; + } else { - if (!align_only_targets || - next_frag_is_branch_target (fragP)) + if (next_frag_is_branch_target (fragP)) fragP->fr_subtype = RELAX_DESIRE_ALIGN; else frag_wane (fragP); } } - else if (!align_only_targets - || next_frag_is_branch_target (fragP)) + else if (next_frag_is_branch_target (fragP)) fragP->fr_subtype = RELAX_DESIRE_ALIGN; else frag_wane (fragP); @@ -5489,18 +7926,142 @@ static bfd_boolean frag_can_negate_branch (fragP) fragS *fragP; { - if (fragP->fr_type == rs_machine_dependent - && fragP->fr_subtype == RELAX_IMMED) + xtensa_isa isa = xtensa_default_isa; + vliw_insn vinsn; + int slot; + + if (fragP->fr_type != rs_machine_dependent + || fragP->fr_subtype != RELAX_SLOTS) + return FALSE; + + vinsn_from_chars (&vinsn, fragP->fr_opcode); + + for (slot = 0; slot < xtensa_format_num_slots (isa, vinsn.format); slot++) { - TInsn t_insn; - tinsn_from_chars (&t_insn, fragP->fr_opcode); - if (is_negatable_branch (&t_insn)) + if ((fragP->tc_frag_data.slot_subtypes[slot] == RELAX_IMMED) + && xtensa_opcode_is_branch (isa, vinsn.slots[slot].opcode) == 1) return TRUE; } + + return FALSE; +} + + +static void +xtensa_mark_narrow_branches () +{ + frchainS *frchP; + + for (frchP = frchain_root; frchP; frchP = frchP->frch_next) + { + fragS *fragP; + /* Walk over all of the fragments in a subsection. */ + for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next) + { + if (fragP->fr_type == rs_machine_dependent + && fragP->fr_subtype == RELAX_SLOTS + && fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED) + { + vliw_insn vinsn; + const expressionS *expr; + symbolS *symbolP; + + vinsn_from_chars (&vinsn, fragP->fr_opcode); + tinsn_immed_from_frag (&vinsn.slots[0], fragP, 0); + + expr = &vinsn.slots[0].tok[1]; + symbolP = expr->X_add_symbol; + + if (vinsn.num_slots == 1 + && xtensa_opcode_is_branch (xtensa_default_isa, + vinsn.slots[0].opcode) + && xg_get_single_size (vinsn.slots[0].opcode) == 2 + && is_narrow_branch_guaranteed_in_range (fragP, + &vinsn.slots[0])) + { + fragP->fr_subtype = RELAX_SLOTS; + fragP->tc_frag_data.slot_subtypes[0] = RELAX_NARROW; + } + } + } + } +} + + +/* A branch is typically widened only when its target is out of + range. However, we would like to widen them to align a subsequent + branch target when possible. + + Because the branch relaxation code is so convoluted, the optimal solution + (combining the two cases) is difficult to get right in all circumstances. + We therefore go with an "almost as good" solution, where we only + use for alignment narrow branches that definitely will not expand to a + jump and a branch. These functions find and mark these cases. */ + +/* the range in bytes of a bnez.n and beqz.n */ +#define MAX_IMMED6 68 + +static bfd_boolean +is_narrow_branch_guaranteed_in_range (fragP, tinsn) + fragS *fragP; + TInsn *tinsn; +{ + const expressionS *expr = &tinsn->tok[1]; + symbolS *symbolP = expr->X_add_symbol; + fragS *target_frag = symbol_get_frag (symbolP); + size_t max_distance = expr->X_add_number; + max_distance += (S_GET_VALUE (symbolP) - target_frag->fr_address); + if (is_branch_jmp_to_next (tinsn, fragP)) + return FALSE; + + /* The branch doesn't branch over it's own frag, + but over the subsequent ones. */ + fragP = fragP->fr_next; + while (fragP != NULL && fragP != target_frag && max_distance <= MAX_IMMED6) + { + max_distance += unrelaxed_frag_max_size (fragP); + fragP = fragP->fr_next; + } + if (max_distance <= MAX_IMMED6 && fragP == target_frag) + return TRUE; return FALSE; } +static void +xtensa_mark_zcl_first_insns () +{ + frchainS *frchP; + + for (frchP = frchain_root; frchP; frchP = frchP->frch_next) + { + fragS *fragP; + /* Walk over all of the fragments in a subsection. */ + for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next) + { + if (fragP->fr_type == rs_machine_dependent + && (fragP->fr_subtype == RELAX_ALIGN_NEXT_OPCODE + || fragP->fr_subtype == RELAX_CHECK_ALIGN_NEXT_OPCODE)) + { + /* Find the loop frag. */ + fragS *targ_frag = next_non_empty_frag (fragP); + /* Find the first insn frag. */ + targ_frag = next_non_empty_frag (targ_frag); + + /* Of course, sometimes (mostly for toy test cases) a + zero-cost loop instruction is the last in a section. */ + if (targ_frag) + { + targ_frag->tc_frag_data.is_first_loop_insn = TRUE; + if (fragP->fr_subtype == RELAX_CHECK_ALIGN_NEXT_OPCODE) + frag_wane (fragP); + } + } + } + } +} + + /* Re-process all of the fragments looking to convert all of the RELAX_ADD_NOP_IF_A0_B_RETW. If the next instruction is a conditional branch or a retw/retw.n, convert this frag to one that @@ -5524,9 +8085,13 @@ xtensa_fix_a0_b_retw_frags () && fragP->fr_subtype == RELAX_ADD_NOP_IF_A0_B_RETW) { if (next_instrs_are_b_retw (fragP)) - relax_frag_add_nop (fragP); - else - frag_wane (fragP); + { + if (get_frag_is_no_transform (fragP)) + as_bad (_("instruction sequence (write a0, branch, retw) may trigger hardware errata")); + else + relax_frag_add_nop (fragP); + } + frag_wane (fragP); } } } @@ -5535,42 +8100,71 @@ xtensa_fix_a0_b_retw_frags () bfd_boolean next_instrs_are_b_retw (fragP) - fragS * fragP; + fragS *fragP; { xtensa_opcode opcode; + xtensa_format fmt; const fragS *next_fragP = next_non_empty_frag (fragP); static xtensa_insnbuf insnbuf = NULL; + static xtensa_insnbuf slotbuf = NULL; xtensa_isa isa = xtensa_default_isa; int offset = 0; + int slot; + bfd_boolean branch_seen = FALSE; if (!insnbuf) - insnbuf = xtensa_insnbuf_alloc (isa); + { + insnbuf = xtensa_insnbuf_alloc (isa); + slotbuf = xtensa_insnbuf_alloc (isa); + } if (next_fragP == NULL) return FALSE; /* Check for the conditional branch. */ - xtensa_insnbuf_from_chars (isa, insnbuf, &next_fragP->fr_literal[offset]); - opcode = xtensa_decode_insn (isa, insnbuf); + xtensa_insnbuf_from_chars (isa, insnbuf, &next_fragP->fr_literal[offset], 0); + fmt = xtensa_format_decode (isa, insnbuf); + if (fmt == XTENSA_UNDEFINED) + return FALSE; + + for (slot = 0; slot < xtensa_format_num_slots (isa, fmt); slot++) + { + xtensa_format_get_slot (isa, fmt, slot, insnbuf, slotbuf); + opcode = xtensa_opcode_decode (isa, fmt, slot, slotbuf); + + branch_seen = (branch_seen + || xtensa_opcode_is_branch (isa, opcode) == 1); + } - if (!is_conditional_branch_opcode (opcode)) + if (!branch_seen) return FALSE; - offset += xtensa_insn_length (isa, opcode); + offset += xtensa_format_length (isa, fmt); if (offset == next_fragP->fr_fix) { next_fragP = next_non_empty_frag (next_fragP); offset = 0; } + if (next_fragP == NULL) return FALSE; /* Check for the retw/retw.n. */ - xtensa_insnbuf_from_chars (isa, insnbuf, &next_fragP->fr_literal[offset]); - opcode = xtensa_decode_insn (isa, insnbuf); + xtensa_insnbuf_from_chars (isa, insnbuf, &next_fragP->fr_literal[offset], 0); + fmt = xtensa_format_decode (isa, insnbuf); + + /* Because RETW[.N] is not bundleable, a VLIW bundle here means that we + have no problems. */ + if (fmt == XTENSA_UNDEFINED + || xtensa_format_num_slots (isa, fmt) != 1) + return FALSE; + + xtensa_format_get_slot (isa, fmt, 0, insnbuf, slotbuf); + opcode = xtensa_opcode_decode (isa, fmt, 0, slotbuf); if (is_windowed_return_opcode (opcode)) return TRUE; + return FALSE; } @@ -5598,9 +8192,13 @@ xtensa_fix_b_j_loop_end_frags () && fragP->fr_subtype == RELAX_ADD_NOP_IF_PRE_LOOP_END) { if (next_instr_is_loop_end (fragP)) - relax_frag_add_nop (fragP); - else - frag_wane (fragP); + { + if (get_frag_is_no_transform (fragP)) + as_bad (_("branching or jumping to a loop end may trigger hardware errata")); + else + relax_frag_add_nop (fragP); + } + frag_wane (fragP); } } } @@ -5656,21 +8254,22 @@ xtensa_fix_close_loop_end_frags () for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next) { if (fragP->fr_type == rs_machine_dependent - && fragP->fr_subtype == RELAX_IMMED) + && ((fragP->fr_subtype == RELAX_IMMED) + || ((fragP->fr_subtype == RELAX_SLOTS) + && (fragP->tc_frag_data.slot_subtypes[0] + == RELAX_IMMED)))) { /* Read it. If the instruction is a loop, get the target. */ - xtensa_opcode opcode = get_opcode_from_buf (fragP->fr_opcode); - if (is_loop_opcode (opcode)) + TInsn t_insn; + tinsn_from_chars (&t_insn, fragP->fr_opcode, 0); + if (xtensa_opcode_is_loop (xtensa_default_isa, + t_insn.opcode) == 1) { - TInsn t_insn; - - tinsn_from_chars (&t_insn, fragP->fr_opcode); - tinsn_immed_from_frag (&t_insn, fragP); - /* Get the current fragment target. */ - if (fragP->fr_symbol) + if (fragP->tc_frag_data.slot_symbols[0]) { - current_target = symbol_get_frag (fragP->fr_symbol); + symbolS *sym = fragP->tc_frag_data.slot_symbols[0]; + current_target = symbol_get_frag (sym); current_offset = fragP->fr_offset; } } @@ -5691,32 +8290,39 @@ xtensa_fix_close_loop_end_frags () if (min_bytes < REQUIRED_LOOP_DIVIDING_BYTES) { - while (min_bytes + bytes_added - < REQUIRED_LOOP_DIVIDING_BYTES) + if (get_frag_is_no_transform (fragP)) + as_bad (_("loop end too close to another loop end may trigger hardware errata")); + else { - int length = 3; - - if (fragP->fr_var < length) - as_warn (_("fr_var %lu < length %d; ignoring"), - fragP->fr_var, length); - else + while (min_bytes + bytes_added + < REQUIRED_LOOP_DIVIDING_BYTES) { - assemble_nop (length, - fragP->fr_literal + fragP->fr_fix); - fragP->fr_fix += length; - fragP->fr_var -= length; + int length = 3; + + if (fragP->fr_var < length) + as_fatal (_("fr_var %lu < length %d"), + fragP->fr_var, length); + else + { + assemble_nop (length, + fragP->fr_literal + fragP->fr_fix); + fragP->fr_fix += length; + fragP->fr_var -= length; + } + bytes_added += length; } - bytes_added += length; } } frag_wane (fragP); } + assert (fragP->fr_type != rs_machine_dependent + || fragP->fr_subtype != RELAX_ADD_NOP_IF_CLOSE_LOOP_END); } } } -size_t +static size_t min_bytes_to_other_loop_end (fragP, current_target, current_offset, max_size) fragS *fragP; fragS *current_target; @@ -5743,9 +8349,9 @@ min_bytes_to_other_loop_end (fragP, current_target, current_offset, max_size) } -size_t +static size_t unrelaxed_frag_min_size (fragP) - fragS * fragP; + fragS *fragP; { size_t size = fragP->fr_fix; @@ -5757,6 +8363,44 @@ unrelaxed_frag_min_size (fragP) } +static size_t +unrelaxed_frag_max_size (fragP) + fragS *fragP; +{ + size_t size = fragP->fr_fix; + switch (fragP->fr_type) + { + case 0: + /* Empty frags created by the obstack allocation scheme + end up with type 0. */ + break; + case rs_fill: + case rs_org: + case rs_space: + size += fragP->fr_offset; + break; + case rs_align: + case rs_align_code: + case rs_align_test: + case rs_leb128: + case rs_cfa: + case rs_dwarf2dbg: + /* No further adjustments needed. */ + break; + case rs_machine_dependent: + if (fragP->fr_subtype != RELAX_DESIRE_ALIGN) + size += fragP->fr_var; + break; + default: + /* We had darn well better know how big it is. */ + assert (0); + break; + } + + return size; +} + + /* Re-process all of the fragments looking to convert all of the RELAX_ADD_NOP_IF_SHORT_LOOP. If: @@ -5766,7 +8410,7 @@ unrelaxed_frag_min_size (fragP) 2) loop has a jump or branch in it or B) - 1) software_avoid_all_short_loops is true + 1) workaround_all_short_loops is TRUE 2) The generating loop was a 'loopgtz' or 'loopnez' 3) the instruction size count to the loop end label is too short (<= 2 instructions) @@ -5790,25 +8434,27 @@ xtensa_fix_short_loop_frags () /* Walk over all of the fragments in a subsection. */ for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next) { - /* check on the current loop */ + /* Check on the current loop. */ if (fragP->fr_type == rs_machine_dependent - && fragP->fr_subtype == RELAX_IMMED) + && ((fragP->fr_subtype == RELAX_IMMED) + || ((fragP->fr_subtype == RELAX_SLOTS) + && (fragP->tc_frag_data.slot_subtypes[0] + == RELAX_IMMED)))) { + TInsn t_insn; + /* Read it. If the instruction is a loop, get the target. */ - xtensa_opcode opcode = get_opcode_from_buf (fragP->fr_opcode); - if (is_loop_opcode (opcode)) + tinsn_from_chars (&t_insn, fragP->fr_opcode, 0); + if (xtensa_opcode_is_loop (xtensa_default_isa, + t_insn.opcode) == 1) { - TInsn t_insn; - - tinsn_from_chars (&t_insn, fragP->fr_opcode); - tinsn_immed_from_frag (&t_insn, fragP); - /* Get the current fragment target. */ - if (fragP->fr_symbol) + if (fragP->tc_frag_data.slot_symbols[0]) { - current_target = symbol_get_frag (fragP->fr_symbol); + symbolS *sym = fragP->tc_frag_data.slot_symbols[0]; + current_target = symbol_get_frag (sym); current_offset = fragP->fr_offset; - current_opcode = opcode; + current_opcode = t_insn.opcode; } } } @@ -5820,19 +8466,23 @@ xtensa_fix_short_loop_frags () count_insns_to_loop_end (fragP->fr_next, TRUE, 3); if (insn_count < 3 && (branch_before_loop_end (fragP->fr_next) - || (software_avoid_all_short_loops + || (workaround_all_short_loops && current_opcode != XTENSA_UNDEFINED && !is_the_loop_opcode (current_opcode)))) - relax_frag_add_nop (fragP); - else - frag_wane (fragP); + { + if (get_frag_is_no_transform (fragP)) + as_bad (_("loop containing less than three instructions may trigger hardware errata")); + else + relax_frag_add_nop (fragP); + } + frag_wane (fragP); } } } } -size_t +static size_t count_insns_to_loop_end (base_fragP, count_relax_add, max_count) fragS *base_fragP; bfd_boolean count_relax_add; @@ -5867,26 +8517,35 @@ count_insns_to_loop_end (base_fragP, count_relax_add, max_count) } -size_t +static size_t unrelaxed_frag_min_insn_count (fragP) fragS *fragP; { + xtensa_isa isa = xtensa_default_isa; + static xtensa_insnbuf insnbuf = NULL; size_t insn_count = 0; int offset = 0; if (!fragP->tc_frag_data.is_insn) return insn_count; + if (!insnbuf) + insnbuf = xtensa_insnbuf_alloc (isa); + /* Decode the fixed instructions. */ while (offset < fragP->fr_fix) { - xtensa_opcode opcode = get_opcode_from_buf (fragP->fr_literal + offset); - if (opcode == XTENSA_UNDEFINED) + xtensa_format fmt; + + xtensa_insnbuf_from_chars (isa, insnbuf, fragP->fr_literal + offset, 0); + fmt = xtensa_format_decode (isa, insnbuf); + + if (fmt == XTENSA_UNDEFINED) { as_fatal (_("undecodable instruction in instruction frag")); return insn_count; } - offset += xtensa_insn_length (xtensa_default_isa, opcode); + offset += xtensa_format_length (isa, fmt); insn_count++; } @@ -5894,7 +8553,7 @@ unrelaxed_frag_min_insn_count (fragP) } -bfd_boolean +static bfd_boolean branch_before_loop_end (base_fragP) fragS *base_fragP; { @@ -5911,28 +8570,40 @@ branch_before_loop_end (base_fragP) } -bfd_boolean +static bfd_boolean unrelaxed_frag_has_b_j (fragP) fragS *fragP; { - size_t insn_count = 0; + static xtensa_insnbuf insnbuf = NULL; + xtensa_isa isa = xtensa_default_isa; int offset = 0; if (!fragP->tc_frag_data.is_insn) return FALSE; + if (!insnbuf) + insnbuf = xtensa_insnbuf_alloc (isa); + /* Decode the fixed instructions. */ while (offset < fragP->fr_fix) { - xtensa_opcode opcode = get_opcode_from_buf (fragP->fr_literal + offset); - if (opcode == XTENSA_UNDEFINED) + xtensa_format fmt; + int slot; + + xtensa_insnbuf_from_chars (isa, insnbuf, fragP->fr_literal + offset, 0); + fmt = xtensa_format_decode (isa, insnbuf); + if (fmt == XTENSA_UNDEFINED) + return FALSE; + + for (slot = 0; slot < xtensa_format_num_slots (isa, fmt); slot++) { - as_fatal (_("undecodable instruction in instruction frag")); - return insn_count; + xtensa_opcode opcode = + get_opcode_from_buf (fragP->fr_literal + offset, slot); + if (xtensa_opcode_is_branch (isa, opcode) == 1 + || xtensa_opcode_is_jump (isa, opcode) == 1) + return TRUE; } - if (is_branch_or_jump_opcode (opcode)) - return TRUE; - offset += xtensa_insn_length (xtensa_default_isa, opcode); + offset += xtensa_format_length (isa, fmt); } return FALSE; } @@ -5967,10 +8638,11 @@ xtensa_sanity_check () { if (!insnbuf) insnbuf = xtensa_insnbuf_alloc (xtensa_default_isa); - tinsn_from_chars (&t_insn, fragP->fr_opcode); - tinsn_immed_from_frag (&t_insn, fragP); + tinsn_from_chars (&t_insn, fragP->fr_opcode, 0); + tinsn_immed_from_frag (&t_insn, fragP, 0); - if (is_loop_opcode (t_insn.opcode)) + if (xtensa_opcode_is_loop (xtensa_default_isa, + t_insn.opcode) == 1) { if (is_empty_loop (&t_insn, fragP)) { @@ -5994,7 +8666,7 @@ xtensa_sanity_check () #define LOOP_IMMED_OPN 1 -/* Return true if the loop target is the next non-zero fragment. */ +/* Return TRUE if the loop target is the next non-zero fragment. */ bfd_boolean is_empty_loop (insn, fragP) @@ -6008,7 +8680,7 @@ is_empty_loop (insn, fragP) if (insn->insn_type != ITYPE_INSN) return FALSE; - if (!is_loop_opcode (insn->opcode)) + if (xtensa_opcode_is_loop (xtensa_default_isa, insn->opcode) != 1) return FALSE; if (insn->ntok <= LOOP_IMMED_OPN) @@ -6031,6 +8703,7 @@ is_empty_loop (insn, fragP) /* Walk through the zero-size fragments from this one. If we find the target fragment, then this is a zero-size loop. */ + for (next_fragP = fragP->fr_next; next_fragP != NULL; next_fragP = next_fragP->fr_next) @@ -6056,7 +8729,7 @@ is_local_forward_loop (insn, fragP) if (insn->insn_type != ITYPE_INSN) return FALSE; - if (!is_loop_opcode (insn->opcode)) + if (xtensa_opcode_is_loop (xtensa_default_isa, insn->opcode) == 0) return FALSE; if (insn->ntok <= LOOP_IMMED_OPN) @@ -6076,11 +8749,14 @@ is_local_forward_loop (insn, fragP) /* Walk through fragments until we find the target. If we do not find the target, then this is an invalid loop. */ + for (next_fragP = fragP->fr_next; next_fragP != NULL; next_fragP = next_fragP->fr_next) - if (next_fragP == symbol_get_frag (symbolP)) - return TRUE; + { + if (next_fragP == symbol_get_frag (symbolP)) + return TRUE; + } return FALSE; } @@ -6088,7 +8764,7 @@ is_local_forward_loop (insn, fragP) /* Alignment Functions. */ -size_t +static size_t get_text_align_power (target_size) int target_size; { @@ -6098,12 +8774,12 @@ get_text_align_power (target_size) if (target_size <= (1 << i)) return i; } - as_fatal (_("get_text_align_power: argument too large")); + assert (0); return 0; } -addressT +static addressT get_text_align_max_fill_size (align_pow, use_nops, use_no_density) int align_pow; bfd_boolean use_nops; @@ -6119,7 +8795,7 @@ get_text_align_max_fill_size (align_pow, use_nops, use_no_density) /* get_text_align_fill_size () - + Desired alignments: give the address target_size = size of next instruction @@ -6129,6 +8805,7 @@ get_text_align_max_fill_size (align_pow, use_nops, use_no_density) Loop alignments: address = current address + loop instruction size; target_size = 3 (for 2 or 3 byte target) + = 4 (for 4 byte target) = 8 (for 8 byte target) align_pow = get_text_align_power (target_size); use_nops = 1 @@ -6140,7 +8817,7 @@ get_text_align_max_fill_size (align_pow, use_nops, use_no_density) use_nops = 0 use_no_density = 0. */ -addressT +static addressT get_text_align_fill_size (address, align_pow, target_size, use_nops, use_no_density) addressT address; @@ -6156,25 +8833,41 @@ get_text_align_fill_size (address, align_pow, target_size, target_size: alignment must allow the new_address and new_address+target_size-1. - use_nops: if true, then we can only use 2 or 3 byte nops. + use_nops: if TRUE, then we can only use 2- or 3-byte nops. use_no_density: if use_nops and use_no_density, we can only use 3-byte nops. - Usually, for non-zero target_size, the align_pow is the power of 2 - that is greater than or equal to the target_size. This handles the - 2-byte, 3-byte and 8-byte instructions. */ + Usually the align_pow is the power of 2 that is greater than + or equal to the target_size. This handles the 2-byte, 3-byte + and 8-byte instructions. + + Two cases: + + (1) aligning an instruction properly, but without using NOPs. + E.G.: a 3-byte instruction can go on any address where address mod 4 + is zero or one. The aligner uses this case to find the optimal + number of fill bytes for relax_frag_for_align. + + (2) aligning an instruction properly, but where we might need to use + extra NOPs. E.G.: when the aligner couldn't find enough widenings + or similar to get the optimal location. */ size_t alignment = (1 << align_pow); + + assert (target_size != 0); + if (!use_nops) { - /* This is the easy case. */ - size_t mod; - mod = address % alignment; - if (mod != 0) - mod = alignment - mod; - assert ((address + mod) % alignment == 0); - return mod; + unsigned fill_bytes; + for (fill_bytes = 0; fill_bytes < alignment; fill_bytes++) + { + addressT end_address = address + target_size - 1 + fill_bytes; + addressT start_address = address + fill_bytes; + if ((end_address >> align_pow) == (start_address >> align_pow)) + return fill_bytes; + } + assert (0); } /* This is the slightly harder case. */ @@ -6187,8 +8880,8 @@ get_text_align_fill_size (address, align_pow, target_size, { if (i == 1) continue; - if ((address + i) >> align_pow == - (address + i + target_size - 1) >> align_pow) + if ((address + i) >> align_pow + == (address + i + target_size - 1) >> align_pow) return i; } } @@ -6199,8 +8892,8 @@ get_text_align_fill_size (address, align_pow, target_size, /* Can only fill multiples of 3. */ for (i = 0; i <= alignment * 3; i += 3) { - if ((address + i) >> align_pow == - (address + i + target_size - 1) >> align_pow) + if ((address + i) >> align_pow + == (address + i + target_size - 1) >> align_pow) return i; } } @@ -6274,212 +8967,154 @@ get_noop_aligned_address (fragP, address) fragS *fragP; addressT address; { - static xtensa_insnbuf insnbuf = NULL; + /* The rule is: get next fragment's FIRST instruction. Find + the smallest number of bytes that need to be added to + ensure that the next fragment's FIRST instruction will fit + in a single word. + + E.G., 2 bytes : 0, 1, 2 mod 4 + 3 bytes: 0, 1 mod 4 + + If the FIRST instruction MIGHT be relaxed, + assume that it will become a 3-byte instruction. + + Note again here that LOOP instructions are not bundleable, + and this relaxation only applies to LOOP opcodes. */ + size_t fill_size = 0; + int first_insn_size; + int loop_insn_size; + addressT pre_opcode_bytes; + size_t alignment; + fragS *first_insn; + xtensa_opcode opcode; + bfd_boolean is_loop; - if (!insnbuf) - insnbuf = xtensa_insnbuf_alloc (xtensa_default_isa); - - switch (fragP->fr_type) - { - case rs_machine_dependent: - if (fragP->fr_subtype == RELAX_ALIGN_NEXT_OPCODE) - { - /* The rule is: get next fragment's FIRST instruction. Find - the smallest number of bytes that need to be added to - ensure that the next fragment's FIRST instruction will fit - in a single word. - - E.G., 2 bytes : 0, 1, 2 mod 4 - 3 bytes: 0, 1 mod 4 - - If the FIRST instruction MIGHT be relaxed, - assume that it will become a 3 byte instruction. */ - - int target_insn_size; - xtensa_opcode opcode = next_frag_opcode (fragP); - addressT pre_opcode_bytes; + assert (fragP->fr_type == rs_machine_dependent); + assert (fragP->fr_subtype == RELAX_ALIGN_NEXT_OPCODE); - if (opcode == XTENSA_UNDEFINED) - { - as_bad_where (fragP->fr_file, fragP->fr_line, - _("invalid opcode for RELAX_ALIGN_NEXT_OPCODE")); - as_fatal (_("cannot continue")); - } + /* Find the loop frag. */ + first_insn = next_non_empty_frag (fragP); + /* Now find the first insn frag. */ + first_insn = next_non_empty_frag (first_insn); - target_insn_size = xtensa_insn_length (xtensa_default_isa, opcode); + is_loop = next_frag_opcode_is_loop (fragP, &opcode); + assert (is_loop); + loop_insn_size = xg_get_single_size (opcode); - pre_opcode_bytes = next_frag_pre_opcode_bytes (fragP); + pre_opcode_bytes = next_frag_pre_opcode_bytes (fragP); + pre_opcode_bytes += loop_insn_size; - if (is_loop_opcode (opcode)) - { - /* next_fragP should be the loop. */ - const fragS *next_fragP = next_non_empty_frag (fragP); - xtensa_opcode next_opcode = next_frag_opcode (next_fragP); - size_t alignment; + /* For loops, the alignment depends on the size of the + instruction following the loop, not the LOOP instruction. */ - pre_opcode_bytes += target_insn_size; + if (first_insn == NULL) + return address; - /* For loops, the alignment depends on the size of the - instruction following the loop, not the loop instruction. */ - if (next_opcode == XTENSA_UNDEFINED) - target_insn_size = 3; - else - { - target_insn_size = - xtensa_insn_length (xtensa_default_isa, next_opcode); + assert (first_insn->tc_frag_data.is_first_loop_insn); - if (target_insn_size == 2) - target_insn_size = 3; /* ISA specifies this. */ - } + first_insn_size = frag_format_size (first_insn); - /* If it was 8, then we'll need a larger alignment - for the section. */ - alignment = get_text_align_power (target_insn_size); + if (first_insn_size == 2 || first_insn_size == XTENSA_UNDEFINED) + first_insn_size = 3; /* ISA specifies this */ - /* Is Now_seg valid */ - record_alignment (now_seg, alignment); - } - else - as_fatal (_("expected loop opcode in relax align next target")); + /* If it was 8, then we'll need a larger alignment for the section. */ + alignment = get_text_align_power (first_insn_size); - fill_size = get_text_align_fill_size - (address + pre_opcode_bytes, - get_text_align_power (target_insn_size), - target_insn_size, TRUE, fragP->tc_frag_data.is_no_density); - } - break; -#if 0 - case rs_align: - case rs_align_code: - fill_size = get_text_align_fill_size - (address, fragP->fr_offset, 1, TRUE, - fragP->tc_frag_data.is_no_density); - break; -#endif - default: - as_fatal (_("expected align_code or RELAX_ALIGN_NEXT_OPCODE")); - } + /* Is now_seg valid? */ + record_alignment (now_seg, alignment); + + fill_size = get_text_align_fill_size + (address + pre_opcode_bytes, + get_text_align_power (first_insn_size), + first_insn_size, TRUE, fragP->tc_frag_data.is_no_density); return address + fill_size; } -/* 3 mechanisms for relaxing an alignment: - - Align to a power of 2. - Align so the next fragment's instruction does not cross a word boundary. - Align the current instruction so that if the next instruction - were 3 bytes, it would not cross a word boundary. - +/* 3 mechanisms for relaxing an alignment: + + Align to a power of 2. + Align so the next fragment's instruction does not cross a word boundary. + Align the current instruction so that if the next instruction + were 3 bytes, it would not cross a word boundary. + We can align with: - zeros - This is easy; always insert zeros. - nops - 3 and 2 byte instructions - 2 - 2 byte nop - 3 - 3 byte nop - 4 - 2, 2-byte nops - >=5 : 3 byte instruction + fn(n-3) + zeros - This is easy; always insert zeros. + nops - 3-byte and 2-byte instructions + 2 - 2-byte nop + 3 - 3-byte nop + 4 - 2 2-byte nops + >=5 : 3-byte instruction + fn (n-3) widening - widen previous instructions. */ static addressT -get_widen_aligned_address (fragP, address) +get_aligned_diff (fragP, address, max_diff) fragS *fragP; addressT address; + addressT *max_diff; { - addressT align_pow, new_address, loop_insn_offset; - fragS *next_frag; - int insn_size; - xtensa_opcode opcode, next_opcode; - static xtensa_insnbuf insnbuf = NULL; - - if (!insnbuf) - insnbuf = xtensa_insnbuf_alloc (xtensa_default_isa); + addressT target_address, loop_insn_offset; + int target_size; + xtensa_opcode loop_opcode; + bfd_boolean is_loop; + int text_align_power; + addressT opt_diff; - if (fragP->fr_type == rs_align || fragP->fr_type == rs_align_code) - { - align_pow = fragP->fr_offset; - new_address = ((address + ((1 << align_pow) - 1)) - << align_pow) >> align_pow; - return new_address; - } - - if (fragP->fr_type == rs_machine_dependent) + assert (fragP->fr_type == rs_machine_dependent); + switch (fragP->fr_subtype) { - switch (fragP->fr_subtype) - { - case RELAX_DESIRE_ALIGN: - - /* The rule is: get the next fragment's FIRST instruction. - Find the smallest number of bytes needed to be added - in order to ensure that the next fragment is FIRST - instruction will fit in a single word. - i.e. 2 bytes : 0, 1, 2. mod 4 - 3 bytes: 0, 1 mod 4 - If the FIRST instruction MIGHT be relaxed, - assume that it will become a 3-byte instruction. */ - - insn_size = 3; - /* Check to see if it might be 2 bytes. */ - next_opcode = next_frag_opcode (fragP); - if (next_opcode != XTENSA_UNDEFINED - && xtensa_insn_length (xtensa_default_isa, next_opcode) == 2) - insn_size = 2; - - assert (insn_size <= 4); - for (new_address = address; new_address < address + 4; new_address++) - { - if (new_address >> 2 == (new_address + insn_size - 1) >> 2) - return new_address; - } - as_bad (_("internal error aligning")); - return address; - - case RELAX_ALIGN_NEXT_OPCODE: - /* The rule is: get next fragment's FIRST instruction. - Find the smallest number of bytes needed to be added - in order to ensure that the next fragment's FIRST - instruction will fit in a single word. - i.e. 2 bytes : 0, 1, 2. mod 4 - 3 bytes: 0, 1 mod 4 - If the FIRST instruction MIGHT be relaxed, - assume that it will become a 3 byte instruction. */ - - opcode = next_frag_opcode (fragP); - if (opcode == XTENSA_UNDEFINED) - { - as_bad_where (fragP->fr_file, fragP->fr_line, - _("invalid opcode for RELAX_ALIGN_NEXT_OPCODE")); - as_fatal (_("cannot continue")); - } - insn_size = xtensa_insn_length (xtensa_default_isa, opcode); - assert (insn_size <= 4); - assert (is_loop_opcode (opcode)); - - loop_insn_offset = 0; - next_frag = next_non_empty_frag (fragP); - - /* If the loop has been expanded then the loop - instruction could be at an offset from this fragment. */ - if (next_frag->fr_subtype != RELAX_IMMED) - loop_insn_offset = get_expanded_loop_offset (opcode); + case RELAX_DESIRE_ALIGN: + target_size = next_frag_format_size (fragP); + if (target_size == XTENSA_UNDEFINED) + target_size = 3; + text_align_power = get_text_align_power (xtensa_fetch_width); + opt_diff = get_text_align_fill_size (address, text_align_power, + target_size, FALSE, FALSE); + + *max_diff = opt_diff + xtensa_fetch_width + - (target_size + ((address + opt_diff) % xtensa_fetch_width)); + assert (*max_diff >= opt_diff); + return opt_diff; - for (new_address = address; new_address < address + 4; new_address++) - { - if ((new_address + loop_insn_offset + insn_size) >> 2 == - (new_address + loop_insn_offset + insn_size + 2) >> 2) - return new_address; - } - as_bad (_("internal error aligning")); - return address; + case RELAX_ALIGN_NEXT_OPCODE: + target_size = next_frag_format_size (fragP); + loop_insn_offset = 0; + is_loop = next_frag_opcode_is_loop (fragP, &loop_opcode); + assert (is_loop); + + /* If the loop has been expanded then the LOOP instruction + could be at an offset from this fragment. */ + if (next_non_empty_frag(fragP)->tc_frag_data.slot_subtypes[0] + != RELAX_IMMED) + loop_insn_offset = get_expanded_loop_offset (loop_opcode); + + if (target_size == 2) + target_size = 3; /* ISA specifies this */ + + /* In an ideal world, which is what we are shooting for here, + we wouldn't need to use any NOPs immediately prior to the + LOOP instruction. If this approach fails, relax_frag_loop_align + will call get_noop_aligned_address. */ + target_address = + address + loop_insn_offset + xg_get_single_size (loop_opcode); + text_align_power = get_text_align_power (target_size), + opt_diff = get_text_align_fill_size (target_address, text_align_power, + target_size, FALSE, FALSE); + + *max_diff = xtensa_fetch_width + - ((target_address + opt_diff) % xtensa_fetch_width) + - target_size + opt_diff; + assert (*max_diff >= opt_diff); + return opt_diff; - default: - as_bad (_("internal error aligning")); - return address; - } + default: + break; } - as_bad (_("internal error aligning")); - return address; + assert (0); + return 0; } @@ -6494,10 +9129,14 @@ xtensa_relax_frag (fragP, stretch, stretched_p) long stretch; int *stretched_p; { + xtensa_isa isa = xtensa_default_isa; int unreported = fragP->tc_frag_data.unreported_expansion; long new_stretch = 0; char *file_name; int line, lit_size; + static xtensa_insnbuf vbuf = NULL; + int slot, num_slots; + xtensa_format fmt; as_where (&file_name, &line); new_logical_line (fragP->fr_file, fragP->fr_line); @@ -6508,7 +9147,8 @@ xtensa_relax_frag (fragP, stretch, stretched_p) { case RELAX_ALIGN_NEXT_OPCODE: /* Always convert. */ - new_stretch = relax_frag_text_align (fragP, stretch); + if (fragP->tc_frag_data.relax_seen) + new_stretch = relax_frag_loop_align (fragP, stretch); break; case RELAX_LOOP_END: @@ -6518,11 +9158,11 @@ xtensa_relax_frag (fragP, stretch, stretched_p) case RELAX_LOOP_END_ADD_NOP: /* Add a NOP and switch to .fill 0. */ new_stretch = relax_frag_add_nop (fragP); + frag_wane (fragP); break; case RELAX_DESIRE_ALIGN: - /* We REALLY want to change the relaxation order here. This - should do NOTHING. The narrowing before it will either align + /* Do nothing. The narrowing before this frag will either align it or not. */ break; @@ -6540,35 +9180,71 @@ xtensa_relax_frag (fragP, stretch, stretched_p) new_stretch = 4; break; - case RELAX_NARROW: - new_stretch = relax_frag_narrow (fragP, stretch); - break; + case RELAX_SLOTS: + if (vbuf == NULL) + vbuf = xtensa_insnbuf_alloc (isa); + + xtensa_insnbuf_from_chars (isa, vbuf, fragP->fr_opcode, 0); + fmt = xtensa_format_decode (isa, vbuf); + num_slots = xtensa_format_num_slots (isa, fmt); - case RELAX_IMMED: - case RELAX_IMMED_STEP1: - case RELAX_IMMED_STEP2: - /* Place the immediate. */ - new_stretch = relax_frag_immed (now_seg, fragP, stretch, - fragP->fr_subtype - RELAX_IMMED, - stretched_p); + for (slot = 0; slot < num_slots; slot++) + { + switch (fragP->tc_frag_data.slot_subtypes[slot]) + { + case RELAX_NARROW: + if (fragP->tc_frag_data.relax_seen) + new_stretch += relax_frag_for_align (fragP, stretch); + break; + + case RELAX_IMMED: + case RELAX_IMMED_STEP1: + case RELAX_IMMED_STEP2: + /* Place the immediate. */ + new_stretch += relax_frag_immed + (now_seg, fragP, stretch, + fragP->tc_frag_data.slot_subtypes[slot] - RELAX_IMMED, + fmt, slot, stretched_p, FALSE); + break; + + default: + /* This is OK; see the note in xg_assemble_vliw_tokens. */ + break; + } + } break; case RELAX_LITERAL_POOL_BEGIN: case RELAX_LITERAL_POOL_END: + case RELAX_MAYBE_UNREACHABLE: + case RELAX_MAYBE_DESIRE_ALIGN: /* No relaxation required. */ break; + case RELAX_FILL_NOP: + case RELAX_UNREACHABLE: + if (fragP->tc_frag_data.relax_seen) + new_stretch += relax_frag_for_align (fragP, stretch); + break; + default: as_bad (_("bad relaxation state")); } + /* Tell gas we need another relaxation pass. */ + if (! fragP->tc_frag_data.relax_seen) + { + fragP->tc_frag_data.relax_seen = TRUE; + *stretched_p = 1; + } + new_logical_line (file_name, line); return new_stretch; } static long -relax_frag_text_align (fragP, stretch) +relax_frag_loop_align (fragP, stretch) fragS *fragP; long stretch; { @@ -6576,18 +9252,14 @@ relax_frag_text_align (fragP, stretch) addressT new_address, new_next_address, new_size; addressT growth; - /* Overview of the relaxation procedure for alignment - inside an executable section: - - The old size is stored in the tc_frag_data.text_expansion field. - - Calculate the new address, fix up the text_expansion and - return the growth. */ + /* All the frags with relax_frag_for_alignment prior to this one in the + section have been done, hopefully eliminating the need for a NOP here. + But, this will put it in if necessary. */ /* Calculate the old address of this fragment and the next fragment. */ old_address = fragP->fr_address - stretch; old_next_address = (fragP->fr_address - stretch + fragP->fr_fix + - fragP->tc_frag_data.text_expansion); + fragP->tc_frag_data.text_expansion[0]); old_size = old_next_address - old_address; /* Calculate the new address of this fragment and the next fragment. */ @@ -6599,198 +9271,521 @@ relax_frag_text_align (fragP, stretch) growth = new_size - old_size; /* Fix up the text_expansion field and return the new growth. */ - fragP->tc_frag_data.text_expansion += growth; + fragP->tc_frag_data.text_expansion[0] += growth; return growth; } -/* Add a NOP (i.e., "or a1, a1, a1"). Use the 3-byte one because we - don't know about the availability of density yet. TODO: When the - flags are stored per fragment, use NOP.N when possible. */ +/* Add a NOP instruction. */ static long relax_frag_add_nop (fragP) fragS *fragP; { - static xtensa_insnbuf insnbuf = NULL; - TInsn t_insn; char *nop_buf = fragP->fr_literal + fragP->fr_fix; - int length; - if (!insnbuf) - insnbuf = xtensa_insnbuf_alloc (xtensa_default_isa); - - tinsn_init (&t_insn); - t_insn.opcode = xtensa_or_opcode; - assert (t_insn.opcode != XTENSA_UNDEFINED); - - t_insn.ntok = 3; - set_expr_const (&t_insn.tok[0], 1); - set_expr_const (&t_insn.tok[1], 1); - set_expr_const (&t_insn.tok[2], 1); - - tinsn_to_insnbuf (&t_insn, insnbuf); + int length = fragP->tc_frag_data.is_no_density ? 3 : 2; + assemble_nop (length, nop_buf); fragP->tc_frag_data.is_insn = TRUE; - xtensa_insnbuf_to_chars (xtensa_default_isa, insnbuf, nop_buf); - length = xtensa_insn_length (xtensa_default_isa, t_insn.opcode); if (fragP->fr_var < length) { - as_warn (_("fr_var (%ld) < length (%d); ignoring"), - fragP->fr_var, length); - frag_wane (fragP); + as_fatal (_("fr_var (%ld) < length (%d)"), fragP->fr_var, length); return 0; } fragP->fr_fix += length; fragP->fr_var -= length; - frag_wane (fragP); return length; } static long -relax_frag_narrow (fragP, stretch) +relax_frag_for_align (fragP, stretch) fragS *fragP; long stretch; { - /* Overview of the relaxation procedure for alignment inside an - executable section: Find the number of widenings required and the - number of nop bytes required. Store the number of bytes ALREADY - widened. If there are enough instructions to widen (must go back - ONLY through NARROW fragments), mark each of the fragments as TO BE - widened, recalculate the fragment addresses. */ + /* Overview of the relaxation procedure for alignment: + We can widen with NOPs or by widening instructions or by filling + bytes after jump instructions. Find the opportune places and widen + them if necessary. */ + + long stretch_me; + long diff; - assert (fragP->fr_type == rs_machine_dependent - && fragP->fr_subtype == RELAX_NARROW); + assert (fragP->fr_subtype == RELAX_FILL_NOP + || fragP->fr_subtype == RELAX_UNREACHABLE + || (fragP->fr_subtype == RELAX_SLOTS + && fragP->tc_frag_data.slot_subtypes[0] == RELAX_NARROW)); + + stretch_me = future_alignment_required (fragP, stretch); + diff = stretch_me - fragP->tc_frag_data.text_expansion[0]; + if (diff == 0) + return 0; - if (!future_alignment_required (fragP, 0)) + if (diff < 0) { - /* If already expanded but no longer needed because of a prior - stretch, it is SAFE to unexpand because the next fragment will - NEVER start at an address > the previous time through the - relaxation. */ - if (fragP->tc_frag_data.text_expansion) + /* We expanded on a previous pass. Can we shrink now? */ + long shrink = fragP->tc_frag_data.text_expansion[0] - stretch_me; + if (shrink <= stretch && stretch > 0) { - if (stretch > 0) - { - fragP->tc_frag_data.text_expansion = 0; - return -1; - } - /* Otherwise we have to live with this bad choice. */ - return 0; + fragP->tc_frag_data.text_expansion[0] = stretch_me; + return -shrink; } return 0; } - if (fragP->tc_frag_data.text_expansion == 0) - { - fragP->tc_frag_data.text_expansion = 1; - return 1; - } + /* Below here, diff > 0. */ + fragP->tc_frag_data.text_expansion[0] = stretch_me; - return 0; + return diff; } -static bfd_boolean -future_alignment_required (fragP, stretch) - fragS *fragP; - long stretch; +/* Return the address of the next frag that should be aligned. + + By "address" we mean the address it _would_ be at if there + is no action taken to align it between here and the target frag. + In other words, if no narrows and no fill nops are used between + here and the frag to align, _even_if_ some of the frags we use + to align targets have already expanded on a previous relaxation + pass. + + Also, count each frag that may be used to help align the target. + + Return 0 if there are no frags left in the chain that need to be + aligned. */ + +static addressT +find_address_of_next_align_frag (fragPP, wide_nops, narrow_nops, + widens, paddable) + fragS **fragPP; + int *wide_nops; + int *narrow_nops; + int *widens; + bfd_boolean *paddable; { - long address = fragP->fr_address + stretch; - int num_widens = 0; - addressT aligned_address; - offsetT desired_diff; + fragS *fragP = *fragPP; + addressT address = fragP->fr_address; + + /* Do not reset the counts to 0. */ while (fragP) { /* Limit this to a small search. */ - if (num_widens > 8) - return FALSE; + if (*widens > 8) + { + *fragPP = fragP; + return 0; + } address += fragP->fr_fix; - switch (fragP->fr_type) + if (fragP->fr_type == rs_fill) + address += fragP->fr_offset * fragP->fr_var; + else if (fragP->fr_type == rs_machine_dependent) { - case rs_fill: - address += fragP->fr_offset * fragP->fr_var; - break; - - case rs_machine_dependent: switch (fragP->fr_subtype) { - case RELAX_NARROW: - /* address += fragP->fr_fix; */ - num_widens++; + case RELAX_UNREACHABLE: + *paddable = TRUE; + break; + + case RELAX_FILL_NOP: + (*wide_nops)++; + if (!fragP->tc_frag_data.is_no_density) + (*narrow_nops)++; + break; + + case RELAX_SLOTS: + if (fragP->tc_frag_data.slot_subtypes[0] == RELAX_NARROW) + { + (*widens)++; + break; + } + /* FIXME: shouldn't this add the expansion of all slots? */ + address += fragP->tc_frag_data.text_expansion[0]; break; case RELAX_IMMED: - address += (/* fragP->fr_fix + */ - fragP->tc_frag_data.text_expansion); + address += fragP->tc_frag_data.text_expansion[0]; break; case RELAX_ALIGN_NEXT_OPCODE: case RELAX_DESIRE_ALIGN: - /* address += fragP->fr_fix; */ - aligned_address = get_widen_aligned_address (fragP, address); - desired_diff = aligned_address - address; - assert (desired_diff >= 0); - /* If there are enough wideners in between do it. */ - /* return (num_widens == desired_diff); */ - if (num_widens == desired_diff) - return TRUE; - if (fragP->fr_subtype == RELAX_ALIGN_NEXT_OPCODE) - return FALSE; + *fragPP = fragP; + return address; + + case RELAX_MAYBE_UNREACHABLE: + case RELAX_MAYBE_DESIRE_ALIGN: + /* Do nothing. */ break; default: - return FALSE; + /* Just punt if we don't know the type. */ + *fragPP = fragP; + return 0; } - break; + } + else + { + /* Just punt if we don't know the type. */ + *fragPP = fragP; + return 0; + } + fragP = fragP->fr_next; + } + + *fragPP = fragP; + return 0; +} + + +/* Undefine LOOKAHEAD_ALIGNER to get the older behavior. + I'll leave this in until I am more confident this works. */ + +#define LOOKAHEAD_ALIGNER 1 + +static long +future_alignment_required (fragP, stretch) + fragS *fragP; + long stretch ATTRIBUTE_UNUSED; +{ + fragS *this_frag = fragP; + long address; + int num_widens = 0; + int wide_nops = 0; + int narrow_nops = 0; + bfd_boolean paddable = FALSE; + offsetT local_opt_diff; + offsetT opt_diff; + offsetT max_diff; + int stretch_amount = 0; + int local_stretch_amount; + int global_stretch_amount; + + address + = find_address_of_next_align_frag (&fragP, &wide_nops, &narrow_nops, + &num_widens, &paddable); + + if (address) + { + local_opt_diff = get_aligned_diff (fragP, address, &max_diff); + opt_diff = local_opt_diff; + assert (opt_diff >= 0); + assert (max_diff >= opt_diff); + if (max_diff == 0) + return 0; +#ifdef LOOKAHEAD_ALIGNER + if (fragP) + fragP = fragP->fr_next; + + while (fragP && opt_diff < max_diff && address) + { + /* We only use these to determine if we can exit early + because there will be plenty of ways to align future + align frags. */ + unsigned int glob_widens = 0; + int dnn = 0; + int dw = 0; + bfd_boolean glob_pad = 0; + address = + find_address_of_next_align_frag (&fragP, &glob_widens, + &dnn, &dw, &glob_pad); + /* If there is a padable portion, then skip. */ + if (glob_pad || (glob_widens >= xtensa_fetch_width)) + break; + + if (address) + { + offsetT next_m_diff; + offsetT next_o_diff; + + /* Downrange frags haven't had stretch added to them yet. */ + address += stretch; + + /* The address also includes any text expansion from this + frag in a previous pass, but we don't want that. */ + address -= this_frag->tc_frag_data.text_expansion[0]; + + /* Assume we are going to move at least opt_diff. In + reality, we might not be able to, but assuming that + we will helps catch cases where moving opt_diff pushes + the next target from aligned to unaligned. */ + address += opt_diff; + + next_o_diff = get_aligned_diff (fragP, address, &next_m_diff); + + /* Now cleanup for the adjustments to address. */ + next_o_diff += opt_diff; + next_m_diff += opt_diff; + if (next_o_diff <= max_diff && next_o_diff > opt_diff) + opt_diff = next_o_diff; + if (next_m_diff < max_diff) + max_diff = next_m_diff; + fragP = fragP->fr_next; + } + } +#endif /* LOOKAHEAD_ALIGNER */ + /* If there are enough wideners in between, do it. */ + if (paddable) + { + if (this_frag->fr_subtype == RELAX_UNREACHABLE) + { + assert (opt_diff <= UNREACHABLE_MAX_WIDTH); + return opt_diff; + } + return 0; + } + local_stretch_amount + = bytes_to_stretch (this_frag, wide_nops, narrow_nops, + num_widens, local_opt_diff); +#ifdef LOOKAHEAD_ALIGNER + global_stretch_amount + = bytes_to_stretch (this_frag, wide_nops, narrow_nops, + num_widens, opt_diff); + /* If the condition below is true, then the frag couldn't + stretch the correct amount for the global case, so we just + optimize locally. We'll rely on the subsequent frags to get + the correct alignment in the global case. */ + if (global_stretch_amount < local_stretch_amount) + stretch_amount = local_stretch_amount; + else + stretch_amount = global_stretch_amount; +#else /* ! LOOKAHEAD_ALIGNER */ + stretch_amount = local_stretch_amount; +#endif /* ! LOOKAHEAD_ALIGNER */ + if (this_frag->fr_subtype == RELAX_SLOTS + && this_frag->tc_frag_data.slot_subtypes[0] == RELAX_NARROW) + assert (stretch_amount <= 1); + else if (this_frag->fr_subtype == RELAX_FILL_NOP) + { + if (this_frag->tc_frag_data.is_no_density) + assert (stretch_amount == 3 || stretch_amount == 0); + else + assert (stretch_amount <= 3); + } + } + return stretch_amount; +} + + +/* The idea: widen everything you can to get a target or loop aligned, + then start using NOPs. + + When we must have a NOP, here is a table of how we decide + (so you don't have to fight through the control flow below): + + wide_nops = the number of wide NOPs available for aligning + narrow_nops = the number of narrow NOPs available for aligning + (a subset of wide_nops) + widens = the number of narrow instructions that should be widened + + Desired wide narrow + Diff nop nop widens + 1 0 0 1 + 2 0 1 0 + 3a 1 0 0 + b 0 1 1 (case 3a makes this case unnecessary) + 4a 1 0 1 + b 0 2 0 + c 0 1 2 (case 4a makes this case unnecessary) + 5a 1 0 2 + b 1 1 0 + c 0 2 1 (case 5b makes this case unnecessary) + 6a 2 0 0 + b 1 0 3 + c 0 1 4 (case 6b makes this case unneccesary) + d 1 1 1 (case 6a makes this case unnecessary) + e 0 2 2 (case 6a makes this case unnecessary) + f 0 3 0 (case 6a makes this case unnecessary) + 7a 1 0 4 + b 2 0 1 + c 1 1 2 (case 7b makes this case unnecessary) + d 0 1 5 (case 7a makes this case unnecessary) + e 0 2 3 (case 7b makes this case unnecessary) + f 0 3 1 (case 7b makes this case unnecessary) + g 1 2 1 (case 7b makes this case unnecessary) +*/ + +static long +bytes_to_stretch (this_frag, wide_nops, narrow_nops, num_widens, desired_diff) + fragS *this_frag; + int wide_nops; + int narrow_nops; + int num_widens; + int desired_diff; +{ + int bytes_short = desired_diff - num_widens; + + assert (desired_diff >= 0 && desired_diff < 8); + if (desired_diff == 0) + return 0; + + assert (wide_nops > 0 || num_widens > 0); + /* Always prefer widening to NOP-filling. */ + if (bytes_short < 0) + { + /* There are enough RELAX_NARROW frags after this one + to align the target without widening this frag in any way. */ + return 0; + } + + if (bytes_short == 0) + { + /* Widen every narrow between here and the align target + and the align target will be properly aligned. */ + if (this_frag->fr_subtype == RELAX_FILL_NOP) + return 0; + else + return 1; + } + + /* From here we will need at least one NOP to get an alignment. + However, we may not be able to align at all, in which case, + don't widen. */ + if (this_frag->fr_subtype == RELAX_FILL_NOP) + { + switch (desired_diff) + { + case 1: + return 0; + case 2: + if (!this_frag->tc_frag_data.is_no_density && narrow_nops == 1) + return 2; /* case 2 */ + return 0; + case 3: + if (wide_nops > 1) + return 0; + else + return 3; /* case 3a */ + case 4: + if (num_widens >= 1 && wide_nops == 1) + return 3; /* case 4a */ + if (!this_frag->tc_frag_data.is_no_density && narrow_nops == 2) + return 2; /* case 4b */ + return 0; + case 5: + if (num_widens >= 2 && wide_nops == 1) + return 3; /* case 5a */ + /* We will need two nops. Are there enough nops + between here and the align target? */ + if (wide_nops < 2 || narrow_nops == 0) + return 0; + /* Are there other nops closer that can serve instead? */ + if (wide_nops > 2 && narrow_nops > 1) + return 0; + /* Take the density one first, because there might not be + another density one available. */ + if (!this_frag->tc_frag_data.is_no_density) + return 2; /* case 5b narrow */ + else + return 3; /* case 5b wide */ + return 0; + case 6: + if (wide_nops == 2) + return 3; /* case 6a */ + else if (num_widens >= 3 && wide_nops == 1) + return 3; /* case 6b */ + return 0; + case 7: + if (wide_nops == 1 && num_widens >= 4) + return 3; /* case 7a */ + else if (wide_nops == 2 && num_widens >= 1) + return 3; /* case 7b */ + return 0; default: - return FALSE; + assert (0); } - fragP = fragP->fr_next; } + else + { + /* We will need a NOP no matter what, but should we widen + this instruction to help? - return FALSE; + This is a RELAX_FRAG_NARROW frag. */ + switch (desired_diff) + { + case 1: + assert (0); + return 0; + case 2: + case 3: + return 0; + case 4: + if (wide_nops >= 1 && num_widens == 1) + return 1; /* case 4a */ + return 0; + case 5: + if (wide_nops >= 1 && num_widens == 2) + return 1; /* case 5a */ + return 0; + case 6: + if (wide_nops >= 2) + return 0; /* case 6a */ + else if (wide_nops >= 1 && num_widens == 3) + return 1; /* case 6b */ + return 0; + case 7: + if (wide_nops >= 1 && num_widens == 4) + return 1; /* case 7a */ + else if (wide_nops >= 2 && num_widens == 1) + return 1; /* case 7b */ + return 0; + default: + assert (0); + return 0; + } + } + assert (0); + return 0; } static long -relax_frag_immed (segP, fragP, stretch, min_steps, stretched_p) +relax_frag_immed (segP, fragP, stretch, min_steps, fmt, slot, stretched_p, + estimate_only) segT segP; fragS *fragP; long stretch; int min_steps; + xtensa_format fmt; + int slot; int *stretched_p; + bfd_boolean estimate_only; { - static xtensa_insnbuf insnbuf = NULL; - TInsn t_insn; + TInsn tinsn; + vliw_insn orig_vinsn; int old_size; bfd_boolean negatable_branch = FALSE; bfd_boolean branch_jmp_to_next = FALSE; + bfd_boolean wide_insn = FALSE; + xtensa_isa isa = xtensa_default_isa; IStack istack; offsetT frag_offset; int num_steps; fragS *lit_fragP; int num_text_bytes, num_literal_bytes; - int literal_diff, text_diff; + int literal_diff, total_text_diff, this_text_diff, first; assert (fragP->fr_opcode != NULL); - if (!insnbuf) - insnbuf = xtensa_insnbuf_alloc (xtensa_default_isa); + xg_init_vinsn (&orig_vinsn); + vinsn_from_chars (&orig_vinsn, fragP->fr_opcode); + if (xtensa_format_num_slots (isa, fmt) > 1) + wide_insn = TRUE; + + tinsn = orig_vinsn.slots[slot]; + tinsn_immed_from_frag (&tinsn, fragP, slot); - tinsn_from_chars (&t_insn, fragP->fr_opcode); - tinsn_immed_from_frag (&t_insn, fragP); + if (estimate_only && xtensa_opcode_is_loop (isa, tinsn.opcode)) + return 0; - negatable_branch = is_negatable_branch (&t_insn); + if (workaround_b_j_loop_end && !get_frag_is_no_transform (fragP)) + branch_jmp_to_next = is_branch_jmp_to_next (&tinsn, fragP); - old_size = xtensa_insn_length (xtensa_default_isa, t_insn.opcode); + negatable_branch = (xtensa_opcode_is_branch (isa, tinsn.opcode) == 1); - if (software_avoid_b_j_loop_end) - branch_jmp_to_next = is_branch_jmp_to_next (&t_insn, fragP); + old_size = xtensa_format_length (isa, fmt); /* Special case: replace a branch to the next instruction with a NOP. This is required to work around a hardware bug in T1040.0 and also @@ -6807,7 +9802,7 @@ relax_frag_immed (segP, fragP, stretch, min_steps, stretched_p) frag_offset = fragP->fr_opcode - fragP->fr_literal; istack_init (&istack); - num_steps = xg_assembly_relax (&istack, &t_insn, segP, fragP, frag_offset, + num_steps = xg_assembly_relax (&istack, &tinsn, segP, fragP, frag_offset, min_steps, stretch); if (num_steps < min_steps) { @@ -6821,26 +9816,40 @@ relax_frag_immed (segP, fragP, stretch, min_steps, stretched_p) return 0; } - fragP->fr_subtype = (int) RELAX_IMMED + num_steps; + fragP->tc_frag_data.slot_subtypes[slot] = (int) RELAX_IMMED + num_steps; /* Figure out the number of bytes needed. */ lit_fragP = 0; - num_text_bytes = get_num_stack_text_bytes (&istack) - old_size; num_literal_bytes = get_num_stack_literal_bytes (&istack); - literal_diff = num_literal_bytes - fragP->tc_frag_data.literal_expansion; - text_diff = num_text_bytes - fragP->tc_frag_data.text_expansion; + literal_diff = + num_literal_bytes - fragP->tc_frag_data.literal_expansion[slot]; + first = 0; + while (istack.insn[first].opcode == XTENSA_UNDEFINED) + first++; + num_text_bytes = get_num_stack_text_bytes (&istack); + if (wide_insn) + { + num_text_bytes += old_size; + if (opcode_fits_format_slot (istack.insn[first].opcode, fmt, slot)) + num_text_bytes -= xg_get_single_size (istack.insn[first].opcode); + } + total_text_diff = num_text_bytes - old_size; + this_text_diff = total_text_diff - fragP->tc_frag_data.text_expansion[slot]; /* It MUST get larger. If not, we could get an infinite loop. */ - know (num_text_bytes >= 0); - know (literal_diff >= 0 && text_diff >= 0); + assert (num_text_bytes >= 0); + assert (literal_diff >= 0); + assert (total_text_diff >= 0); - fragP->tc_frag_data.text_expansion = num_text_bytes; - fragP->tc_frag_data.literal_expansion = num_literal_bytes; + fragP->tc_frag_data.text_expansion[slot] = total_text_diff; + fragP->tc_frag_data.literal_expansion[slot] = num_literal_bytes; + assert (fragP->tc_frag_data.text_expansion[slot] >= 0); + assert (fragP->tc_frag_data.literal_expansion[slot] >= 0); /* Find the associated expandable literal for this. */ if (literal_diff != 0) { - lit_fragP = fragP->tc_frag_data.literal_frag; + lit_fragP = fragP->tc_frag_data.literal_frags[slot]; if (lit_fragP) { assert (literal_diff == 4); @@ -6858,16 +9867,15 @@ relax_frag_immed (segP, fragP, stretch, min_steps, stretched_p) } } - /* This implicitly uses the assumption that a branch is negated - when the size of the output increases by at least 2 bytes. */ - - if (negatable_branch && num_text_bytes >= 2) - { - /* If next frag is a loop end, then switch it to add a NOP. */ - update_next_frag_nop_state (fragP); - } + /* FIXME: When a negatable branch expands and then contracts in a + subsequent pass, update_next_frag_state correctly updates the + type of the frag to RELAX_MAYBE_UNREACHABLE, but it doesn't undo + any expansion relax_frag_for_align may have expected it to. For + now, change back to only call it when the branch expands. */ + if (negatable_branch && istack.ninsn > 1) + update_next_frag_state (fragP, FALSE /* istack.ninsn > 1 */); - return text_diff; + return this_text_diff; } @@ -6879,6 +9887,11 @@ md_convert_frag (abfd, sec, fragp) segT sec; fragS *fragp; { + static xtensa_insnbuf vbuf = NULL; + xtensa_isa isa = xtensa_default_isa; + int slot; + int num_slots; + xtensa_format fmt; char *file_name; int line; @@ -6896,20 +9909,58 @@ md_convert_frag (abfd, sec, fragp) /* Do nothing. If not aligned already, too bad. */ break; - case RELAX_LITERAL: - case RELAX_LITERAL_FINAL: + case RELAX_LITERAL: + case RELAX_LITERAL_FINAL: + break; + + case RELAX_SLOTS: + if (vbuf == NULL) + vbuf = xtensa_insnbuf_alloc (isa); + + xtensa_insnbuf_from_chars (isa, vbuf, fragp->fr_opcode, 0); + fmt = xtensa_format_decode (isa, vbuf); + num_slots = xtensa_format_num_slots (isa, fmt); + + for (slot = 0; slot < num_slots; slot++) + { + switch (fragp->tc_frag_data.slot_subtypes[slot]) + { + case RELAX_NARROW: + convert_frag_narrow (sec, fragp, fmt, slot); + break; + + case RELAX_IMMED: + case RELAX_IMMED_STEP1: + case RELAX_IMMED_STEP2: + /* Place the immediate. */ + convert_frag_immed + (sec, fragp, + fragp->tc_frag_data.slot_subtypes[slot] - RELAX_IMMED, + fmt, slot); + break; + + default: + /* This is OK because some slots could have + relaxations and others have none. */ + break; + } + } + break; + + case RELAX_UNREACHABLE: + memset (&fragp->fr_literal[fragp->fr_fix], 0, fragp->fr_var); + fragp->fr_fix += fragp->tc_frag_data.text_expansion[0]; + fragp->fr_var -= fragp->tc_frag_data.text_expansion[0]; + frag_wane (fragp); break; - case RELAX_NARROW: - /* No conversion. */ - convert_frag_narrow (fragp); + case RELAX_MAYBE_UNREACHABLE: + case RELAX_MAYBE_DESIRE_ALIGN: + frag_wane (fragp); break; - case RELAX_IMMED: - case RELAX_IMMED_STEP1: - case RELAX_IMMED_STEP2: - /* Place the immediate. */ - convert_frag_immed (sec, fragp, fragp->fr_subtype - RELAX_IMMED); + case RELAX_FILL_NOP: + convert_frag_fill_nop (fragp); break; case RELAX_LITERAL_NR: @@ -6979,15 +10030,30 @@ convert_frag_align_next_opcode (fragp) static void -convert_frag_narrow (fragP) +convert_frag_narrow (segP, fragP, fmt, slot) + segT segP; fragS *fragP; + xtensa_format fmt; + int slot; { - static xtensa_insnbuf insnbuf = NULL; - TInsn t_insn, single_target; + TInsn tinsn, single_target; + xtensa_format single_fmt; int size, old_size, diff, error_val; offsetT frag_offset; - if (fragP->tc_frag_data.text_expansion == 0) + assert (slot == 0); + tinsn_from_chars (&tinsn, fragP->fr_opcode, 0); + + if (xtensa_opcode_is_branch (xtensa_default_isa, tinsn.opcode) == 1) + { + assert (fragP->tc_frag_data.text_expansion[0] == 1 + || fragP->tc_frag_data.text_expansion[0] == 0); + convert_frag_immed (segP, fragP, fragP->tc_frag_data.text_expansion[0], + fmt, slot); + return; + } + + if (fragP->tc_frag_data.text_expansion[0] == 0) { /* No conversion. */ fragP->fr_var = 0; @@ -6996,25 +10062,28 @@ convert_frag_narrow (fragP) assert (fragP->fr_opcode != NULL); - if (!insnbuf) - insnbuf = xtensa_insnbuf_alloc (xtensa_default_isa); - - tinsn_from_chars (&t_insn, fragP->fr_opcode); - tinsn_immed_from_frag (&t_insn, fragP); + /* Frags in this relaxation state should only contain + single instruction bundles. */ + tinsn_immed_from_frag (&tinsn, fragP, 0); /* Just convert it to a wide form.... */ size = 0; - old_size = xtensa_insn_length (xtensa_default_isa, t_insn.opcode); + old_size = xg_get_single_size (tinsn.opcode); tinsn_init (&single_target); frag_offset = fragP->fr_opcode - fragP->fr_literal; - error_val = xg_expand_narrow (&single_target, &t_insn); + error_val = xg_expand_narrow (&single_target, &tinsn); if (error_val) - as_bad (_("unable to widen instruction")); + { + as_bad (_("unable to widen instruction")); + return; + } + + size = xg_get_single_size (single_target.opcode); + single_fmt = xg_get_single_format (single_target.opcode); - size = xtensa_insn_length (xtensa_default_isa, single_target.opcode); - xg_emit_insn_to_buf (&single_target, fragP->fr_opcode, + xg_emit_insn_to_buf (&single_target, single_fmt, fragP->fr_opcode, fragP, frag_offset, TRUE); diff = size - old_size; @@ -7029,81 +10098,129 @@ convert_frag_narrow (fragP) static void -convert_frag_immed (segP, fragP, min_steps) +convert_frag_fill_nop (fragP) + fragS *fragP; +{ + char *loc = &fragP->fr_literal[fragP->fr_fix]; + int size = fragP->tc_frag_data.text_expansion[0]; + assert ((unsigned) size == (fragP->fr_next->fr_address + - fragP->fr_address - fragP->fr_fix)); + if (size == 0) + { + /* No conversion. */ + fragP->fr_var = 0; + return; + } + assemble_nop (size, loc); + fragP->tc_frag_data.is_insn = TRUE; + fragP->fr_var -= size; + fragP->fr_fix += size; + frag_wane (fragP); +} + + +static void +convert_frag_immed (segP, fragP, min_steps, fmt, slot) segT segP; fragS *fragP; int min_steps; + xtensa_format fmt; + int slot; { char *immed_instr = fragP->fr_opcode; - static xtensa_insnbuf insnbuf = NULL; - TInsn orig_t_insn; + TInsn orig_tinsn; bfd_boolean expanded = FALSE; - char *fr_opcode = fragP->fr_opcode; bfd_boolean branch_jmp_to_next = FALSE; - int size; + char *fr_opcode = fragP->fr_opcode; + vliw_insn orig_vinsn; + xtensa_isa isa = xtensa_default_isa; + bfd_boolean wide_insn = FALSE; + int bytes; + bfd_boolean is_loop; - assert (fragP->fr_opcode != NULL); + assert (fr_opcode != NULL); - if (!insnbuf) - insnbuf = xtensa_insnbuf_alloc (xtensa_default_isa); + xg_init_vinsn (&orig_vinsn); - tinsn_from_chars (&orig_t_insn, fragP->fr_opcode); - tinsn_immed_from_frag (&orig_t_insn, fragP); + vinsn_from_chars (&orig_vinsn, fr_opcode); + if (xtensa_format_num_slots (isa, fmt) > 1) + wide_insn = TRUE; - /* Here is the fun stuff: Get the immediate field from this - instruction. If it fits, we're done. If not, find the next - instruction sequence that fits. */ + orig_tinsn = orig_vinsn.slots[slot]; + tinsn_immed_from_frag (&orig_tinsn, fragP, slot); + + is_loop = xtensa_opcode_is_loop (xtensa_default_isa, orig_tinsn.opcode) == 1; - if (software_avoid_b_j_loop_end) - branch_jmp_to_next = is_branch_jmp_to_next (&orig_t_insn, fragP); + if (workaround_b_j_loop_end && !get_frag_is_no_transform (fragP)) + branch_jmp_to_next = is_branch_jmp_to_next (&orig_tinsn, fragP); if (branch_jmp_to_next && !next_frag_is_loop_target (fragP)) { /* Conversion just inserts a NOP and marks the fix as completed. */ - size = xtensa_insn_length (xtensa_default_isa, orig_t_insn.opcode); - assemble_nop (size, fragP->fr_opcode); + bytes = xtensa_format_length (isa, fmt); + if (bytes >= 4) + { + orig_vinsn.slots[slot].opcode = + xtensa_format_slot_nop_opcode (isa, orig_vinsn.format, slot); + orig_vinsn.slots[slot].ntok = 0; + } + else + { + bytes += fragP->tc_frag_data.text_expansion[0]; + assert (bytes == 2 || bytes == 3); + build_nop (&orig_vinsn.slots[0], bytes); + fragP->fr_fix += fragP->tc_frag_data.text_expansion[0]; + } + vinsn_to_insnbuf (&orig_vinsn, fr_opcode, frag_now, FALSE); + xtensa_insnbuf_to_chars (isa, orig_vinsn.insnbuf, fr_opcode, 0); fragP->fr_var = 0; } - else + else if (!orig_tinsn.is_specific_opcode) { + /* Here is the fun stuff: Get the immediate field from this + instruction. If it fits, we're done. If not, find the next + instruction sequence that fits. */ + IStack istack; int i; symbolS *lit_sym = NULL; int total_size = 0; + int target_offset = 0; int old_size; int diff; symbolS *gen_label = NULL; offsetT frag_offset; + bfd_boolean first = TRUE; + bfd_boolean last_is_jump; - /* It does not fit. Find something that does and + /* It does not fit. Find something that does and convert immediately. */ - frag_offset = fragP->fr_opcode - fragP->fr_literal; + frag_offset = fr_opcode - fragP->fr_literal; istack_init (&istack); - xg_assembly_relax (&istack, &orig_t_insn, + xg_assembly_relax (&istack, &orig_tinsn, segP, fragP, frag_offset, min_steps, 0); - old_size = xtensa_insn_length (xtensa_default_isa, orig_t_insn.opcode); + old_size = xtensa_format_length (isa, fmt); /* Assemble this right inline. */ /* First, create the mapping from a label name to the REAL label. */ - total_size = 0; + target_offset = 0; for (i = 0; i < istack.ninsn; i++) { - TInsn *t_insn = &istack.insn[i]; - int size = 0; + TInsn *tinsn = &istack.insn[i]; fragS *lit_frag; - switch (t_insn->insn_type) + switch (tinsn->insn_type) { case ITYPE_LITERAL: if (lit_sym != NULL) as_bad (_("multiple literals in expansion")); /* First find the appropriate space in the literal pool. */ - lit_frag = fragP->tc_frag_data.literal_frag; + lit_frag = fragP->tc_frag_data.literal_frags[slot]; if (lit_frag == NULL) as_bad (_("no registered fragment for literal")); - if (t_insn->ntok != 1) + if (tinsn->ntok != 1) as_bad (_("number of literal tokens != 1")); /* Set the literal symbol and add a fixup. */ @@ -7111,53 +10228,148 @@ convert_frag_immed (segP, fragP, min_steps) break; case ITYPE_LABEL: + if (align_targets && !is_loop) + { + fragS *unreach = fragP->fr_next; + while (!(unreach->fr_type == rs_machine_dependent + && (unreach->fr_subtype == RELAX_MAYBE_UNREACHABLE + || unreach->fr_subtype == RELAX_UNREACHABLE))) + { + unreach = unreach->fr_next; + } + + assert (unreach->fr_type == rs_machine_dependent + && (unreach->fr_subtype == RELAX_MAYBE_UNREACHABLE + || unreach->fr_subtype == RELAX_UNREACHABLE)); + + target_offset += unreach->tc_frag_data.text_expansion[0]; + } assert (gen_label == NULL); gen_label = symbol_new (FAKE_LABEL_NAME, now_seg, - fragP->fr_opcode - fragP->fr_literal + - total_size, fragP); + fr_opcode - fragP->fr_literal + + target_offset, fragP); break; case ITYPE_INSN: - size = xtensa_insn_length (xtensa_default_isa, t_insn->opcode); - total_size += size; + if (first && wide_insn) + { + target_offset += xtensa_format_length (isa, fmt); + first = FALSE; + if (!opcode_fits_format_slot (tinsn->opcode, fmt, slot)) + target_offset += xg_get_single_size (tinsn->opcode); + } + else + target_offset += xg_get_single_size (tinsn->opcode); break; } } total_size = 0; + first = TRUE; + last_is_jump = FALSE; for (i = 0; i < istack.ninsn; i++) { - TInsn *t_insn = &istack.insn[i]; + TInsn *tinsn = &istack.insn[i]; fragS *lit_frag; int size; segT target_seg; + bfd_reloc_code_real_type reloc_type; - switch (t_insn->insn_type) + switch (tinsn->insn_type) { case ITYPE_LITERAL: - lit_frag = fragP->tc_frag_data.literal_frag; - /* already checked */ + lit_frag = fragP->tc_frag_data.literal_frags[slot]; + /* Already checked. */ assert (lit_frag != NULL); assert (lit_sym != NULL); - assert (t_insn->ntok == 1); - /* add a fixup */ + assert (tinsn->ntok == 1); + /* Add a fixup. */ target_seg = S_GET_SEGMENT (lit_sym); assert (target_seg); + if (tinsn->tok[0].X_op == O_pltrel) + reloc_type = BFD_RELOC_XTENSA_PLT; + else + reloc_type = BFD_RELOC_32; fix_new_exp_in_seg (target_seg, 0, lit_frag, 0, 4, - &t_insn->tok[0], FALSE, BFD_RELOC_32); + &tinsn->tok[0], FALSE, reloc_type); break; case ITYPE_LABEL: break; case ITYPE_INSN: - xg_resolve_labels (t_insn, gen_label); - xg_resolve_literals (t_insn, lit_sym); - size = xtensa_insn_length (xtensa_default_isa, t_insn->opcode); - total_size += size; - xg_emit_insn_to_buf (t_insn, immed_instr, fragP, - immed_instr - fragP->fr_literal, TRUE); + xg_resolve_labels (tinsn, gen_label); + xg_resolve_literals (tinsn, lit_sym); + if (wide_insn && first) + { + first = FALSE; + if (opcode_fits_format_slot (tinsn->opcode, fmt, slot)) + { + tinsn->record_fix = TRUE; + orig_vinsn.slots[slot] = *tinsn; + } + else + { + orig_vinsn.slots[slot].opcode = + xtensa_format_slot_nop_opcode (isa, fmt, slot); + orig_vinsn.slots[slot].ntok = 0; + orig_vinsn.slots[slot].record_fix = FALSE; + } + vinsn_to_insnbuf (&orig_vinsn, immed_instr, fragP, TRUE); + xtensa_insnbuf_to_chars (isa, orig_vinsn.insnbuf, + immed_instr, 0); + fragP->tc_frag_data.is_insn = TRUE; + size = xtensa_format_length (isa, fmt); + if (!opcode_fits_format_slot (tinsn->opcode, fmt, slot)) + { + xtensa_format single_fmt = + xg_get_single_format (tinsn->opcode); + + xg_emit_insn_to_buf + (tinsn, single_fmt, immed_instr + size, fragP, + immed_instr - fragP->fr_literal + size, TRUE); + size += xg_get_single_size (tinsn->opcode); + } + } + else + { + xtensa_format single_format; + size = xg_get_single_size (tinsn->opcode); + single_format = xg_get_single_format (tinsn->opcode); + xg_emit_insn_to_buf (tinsn, single_format, immed_instr, + fragP, + immed_instr - fragP->fr_literal, TRUE); +#if 0 + /* Code to recognize branch-around expansion + so the fragment is properly marked as ending in a + jump. */ + if ((((i == istack.ninsn - 2) + && (istack.insn[istack.ninsn-1].insn_type + == ITYPE_LABEL)) + || i == istack.ninsn -1) + && xtensa_opcode_is_jump (xtensa_default_isa, + tinsn->opcode) == 1 + && fragP->fr_next != NULL + && ! fragP->fr_next->tc_frag_data.is_unreachable) + { + /* Create a new unreachable frag of zero size. */ + size_t frag_size = sizeof (fragS); + fragS *new_fragP = (fragS *) xmalloc (frag_size); + memset (new_fragP, 0, frag_size); + new_fragP->fr_address = fragP->fr_next->fr_address; + new_fragP->fr_next = fragP->fr_next; + new_fragP->fr_fix = 0; + new_fragP->fr_var = 0; + new_fragP->fr_type = rs_fill; + new_fragP->tc_frag_data.is_unreachable = TRUE; + /* The rest are zeros.... */ + /* Link it in to the chain. */ + fragP->fr_next = new_fragP; + } +#endif + } immed_instr += size; + total_size += size; break; } } @@ -7172,19 +10384,19 @@ convert_frag_immed (segP, fragP, min_steps) } /* Clean it up. */ - fragP->fr_var = 0; + xg_free_vinsn (&orig_vinsn); /* Check for undefined immediates in LOOP instructions. */ - if (is_loop_opcode (orig_t_insn.opcode)) + if (is_loop) { symbolS *sym; - sym = orig_t_insn.tok[1].X_add_symbol; + sym = orig_tinsn.tok[1].X_add_symbol; if (sym != NULL && !S_IS_DEFINED (sym)) { as_bad (_("unresolved loop target symbol: %s"), S_GET_NAME (sym)); return; } - sym = orig_t_insn.tok[1].X_op_symbol; + sym = orig_tinsn.tok[1].X_op_symbol; if (sym != NULL && !S_IS_DEFINED (sym)) { as_bad (_("unresolved loop target symbol: %s"), S_GET_NAME (sym)); @@ -7192,16 +10404,15 @@ convert_frag_immed (segP, fragP, min_steps) } } - if (expanded && is_loop_opcode (orig_t_insn.opcode)) - convert_frag_immed_finish_loop (segP, fragP, &orig_t_insn); + if (expanded && xtensa_opcode_is_loop (isa, orig_tinsn.opcode) == 1) + convert_frag_immed_finish_loop (segP, fragP, &orig_tinsn); - if (expanded && is_direct_call_opcode (orig_t_insn.opcode)) + if (expanded && is_direct_call_opcode (orig_tinsn.opcode)) { /* Add an expansion note on the expanded instruction. */ fix_new_exp_in_seg (now_seg, 0, fragP, fr_opcode - fragP->fr_literal, 4, - &orig_t_insn.tok[0], TRUE, + &orig_tinsn.tok[0], TRUE, BFD_RELOC_XTENSA_ASM_EXPAND); - } } @@ -7224,43 +10435,38 @@ fix_new_exp_in_seg (new_seg, new_subseg, fixS *new_fix; segT seg = now_seg; subsegT subseg = now_subseg; + assert (new_seg != 0); subseg_set (new_seg, new_subseg); - if (r_type == BFD_RELOC_32 - && exp->X_add_symbol - && symbol_get_tc (exp->X_add_symbol)->plt == 1) - { - r_type = BFD_RELOC_XTENSA_PLT; - } - new_fix = fix_new_exp (frag, where, size, exp, pcrel, r_type); subseg_set (seg, subseg); return new_fix; } -/* Relax a loop instruction so that it can span loop >256 bytes. */ -/* - loop as, .L1 - .L0: - rsr as, LEND - wsr as, LBEG - addi as, as, lo8(label-.L1) - addmi as, as, mid8(label-.L1) - wsr as, LEND - isync - rsr as, LCOUNT - addi as, as, 1 - .L1: - <> - label: */ +/* Relax a loop instruction so that it can span loop >256 bytes. + + loop as, .L1 + .L0: + rsr as, LEND + wsr as, LBEG + addi as, as, lo8 (label-.L1) + addmi as, as, mid8 (label-.L1) + wsr as, LEND + isync + rsr as, LCOUNT + addi as, as, 1 + .L1: + <> + label: +*/ static void -convert_frag_immed_finish_loop (segP, fragP, t_insn) +convert_frag_immed_finish_loop (segP, fragP, tinsn) segT segP; fragS *fragP; - TInsn *t_insn; + TInsn *tinsn; { TInsn loop_insn; TInsn addi_insn; @@ -7272,26 +10478,27 @@ convert_frag_immed_finish_loop (segP, fragP, t_insn) addressT loop_offset; addressT addi_offset = 9; addressT addmi_offset = 12; + fragS *next_fragP; + size_t target_count; if (!insnbuf) insnbuf = xtensa_insnbuf_alloc (isa); /* Get the loop offset. */ - loop_offset = get_expanded_loop_offset (t_insn->opcode); - /* Validate that there really is a LOOP at the loop_offset. */ - tinsn_from_chars (&loop_insn, fragP->fr_opcode + loop_offset); + loop_offset = get_expanded_loop_offset (tinsn->opcode); - if (!is_loop_opcode (loop_insn.opcode)) - { - as_bad_where (fragP->fr_file, fragP->fr_line, - _("loop relaxation specification does not correspond")); - assert (0); - } + /* Validate that there really is a LOOP at the loop_offset. Because + loops are not bundleable, we can assume that the instruction will be + in slot 0. */ + tinsn_from_chars (&loop_insn, fragP->fr_opcode + loop_offset, 0); + tinsn_immed_from_frag (&loop_insn, fragP, 0); + + assert (xtensa_opcode_is_loop (isa, loop_insn.opcode) == 1); addi_offset += loop_offset; addmi_offset += loop_offset; - assert (t_insn->ntok == 2); - target = get_expression_value (segP, &t_insn->tok[1]); + assert (tinsn->ntok == 2); + target = get_expression_value (segP, &tinsn->tok[1]); know (symbolP); know (symbolP->sy_frag); @@ -7307,27 +10514,43 @@ convert_frag_immed_finish_loop (segP, fragP, t_insn) loop_length_hi += 256; } - /* Because addmi sign-extends the immediate, 'loop_length_hi' can be at most + /* Because addmi sign-extends the immediate, 'loop_length_hi' can be at most 32512. If the loop is larger than that, then we just fail. */ if (loop_length_hi > 32512) as_bad_where (fragP->fr_file, fragP->fr_line, _("loop too long for LOOP instruction")); - tinsn_from_chars (&addi_insn, fragP->fr_opcode + addi_offset); + tinsn_from_chars (&addi_insn, fragP->fr_opcode + addi_offset, 0); assert (addi_insn.opcode == xtensa_addi_opcode); - tinsn_from_chars (&addmi_insn, fragP->fr_opcode + addmi_offset); + tinsn_from_chars (&addmi_insn, fragP->fr_opcode + addmi_offset, 0); assert (addmi_insn.opcode == xtensa_addmi_opcode); set_expr_const (&addi_insn.tok[2], loop_length_lo); tinsn_to_insnbuf (&addi_insn, insnbuf); - + fragP->tc_frag_data.is_insn = TRUE; - xtensa_insnbuf_to_chars (isa, insnbuf, fragP->fr_opcode + addi_offset); + xtensa_insnbuf_to_chars (isa, insnbuf, fragP->fr_opcode + addi_offset, 0); set_expr_const (&addmi_insn.tok[2], loop_length_hi); tinsn_to_insnbuf (&addmi_insn, insnbuf); - xtensa_insnbuf_to_chars (isa, insnbuf, fragP->fr_opcode + addmi_offset); + xtensa_insnbuf_to_chars (isa, insnbuf, fragP->fr_opcode + addmi_offset, 0); + + /* Walk through all of the frags from here to the loop end + and mark them as no_transform to keep them from being modified + by the linker. If we ever have a relocation for the + addi/addmi of the difference of two symbols we can remove this. */ + + target_count = 0; + for (next_fragP = fragP; next_fragP != NULL; + next_fragP = next_fragP->fr_next) + { + set_frag_is_no_transform (next_fragP, TRUE); + if (next_fragP->tc_frag_data.is_loop_target) + target_count++; + if (target_count == 2) + break; + } } @@ -7353,23 +10576,6 @@ get_expression_value (segP, exp) } -/* A map that keeps information on a per-subsegment basis. This is - maintained during initial assembly, but is invalid once the - subsegments are smashed together. I.E., it cannot be used during - the relaxation. */ - -typedef struct subseg_map_struct -{ - /* the key */ - segT seg; - subsegT subseg; - - /* the data */ - unsigned flags; - - struct subseg_map_struct *next; -} subseg_map; - static subseg_map *sseg_map = NULL; @@ -7378,40 +10584,46 @@ get_last_insn_flags (seg, subseg) segT seg; subsegT subseg; { - subseg_map *subseg_e; - - for (subseg_e = sseg_map; subseg_e != NULL; subseg_e = subseg_e->next) - if (seg == subseg_e->seg && subseg == subseg_e->subseg) - return subseg_e->flags; - - return 0; + subseg_map *subseg_e = get_subseg_info (seg, subseg); + return subseg_e->flags; } -static void -set_last_insn_flags (seg, subseg, fl, val) +static subseg_map * +get_subseg_info (seg, subseg) segT seg; subsegT subseg; - unsigned fl; - bfd_boolean val; { subseg_map *subseg_e; for (subseg_e = sseg_map; subseg_e; subseg_e = subseg_e->next) - if (seg == subseg_e->seg && subseg == subseg_e->subseg) - break; - - if (!subseg_e) { - subseg_e = (subseg_map *) xmalloc (sizeof (subseg_map)); - memset (subseg_e, 0, sizeof (subseg_map)); - subseg_e->seg = seg; - subseg_e->subseg = subseg; - subseg_e->flags = 0; - subseg_e->next = sseg_map; - sseg_map = subseg_e; + if (seg == subseg_e->seg && subseg == subseg_e->subseg) + return subseg_e; } + + subseg_e = (subseg_map *) xmalloc (sizeof (subseg_map)); + memset (subseg_e, 0, sizeof (subseg_map)); + subseg_e->seg = seg; + subseg_e->subseg = subseg; + subseg_e->flags = 0; + /* Start off considering every branch target very important. */ + subseg_e->cur_target_freq = 1.0; + subseg_e->cur_total_freq = 1.0; + subseg_e->next = sseg_map; + sseg_map = subseg_e; + + return subseg_e; +} +static void +set_last_insn_flags (seg, subseg, fl, val) + segT seg; + subsegT subseg; + unsigned fl; + bfd_boolean val; +{ + subseg_map *subseg_e = get_subseg_info (seg, subseg); if (val) subseg_e->flags |= fl; else @@ -7519,31 +10731,33 @@ xtensa_move_literals () prevents us from making a segment with an frchain without any frags in it. */ frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL); + xtensa_set_frag_assembly_state (frag_now); last_frag = frag_now; frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL); + xtensa_set_frag_assembly_state (frag_now); - while (search_frag != frag_now) + while (search_frag != frag_now) { next_frag = search_frag->fr_next; - /* First, move the frag out of the literal section and + /* First, move the frag out of the literal section and to the appropriate place. */ if (search_frag->tc_frag_data.literal_frag) { literal_pool = search_frag->tc_frag_data.literal_frag; assert (literal_pool->fr_subtype == RELAX_LITERAL_POOL_BEGIN); - /* Note that we set this fr_var to be a fix + /* Note that we set this fr_var to be a fix chain when we created the literal pool location as RELAX_LITERAL_POOL_BEGIN. */ frchain_to = (frchainS *) literal_pool->fr_var; } insert_after = literal_pool; - + while (insert_after->fr_next->fr_subtype != RELAX_LITERAL_POOL_END) insert_after = insert_after->fr_next; dest_seg = (segT) insert_after->fr_next->fr_var; - + *frag_splice = next_frag; search_frag->fr_next = insert_after->fr_next; insert_after->fr_next = search_frag; @@ -7588,7 +10802,8 @@ xtensa_move_literals () { symbolS *lit_sym = lit->sym; segT dest_seg = symbol_get_frag (lit_sym)->tc_frag_data.lit_seg; - S_SET_SEGMENT (lit_sym, dest_seg); + if (dest_seg) + S_SET_SEGMENT (lit_sym, dest_seg); } } @@ -7689,6 +10904,26 @@ get_last_sec () void xtensa_switch_to_literal_fragment (result) emit_state *result; +{ + if (directive_state[directive_absolute_literals]) + { + cache_literal_section (0, default_lit_sections.lit4_seg_name, + &default_lit_sections.lit4_seg, FALSE); + xtensa_switch_section_emit_state (result, + default_lit_sections.lit4_seg, 0); + } + else + xtensa_switch_to_non_abs_literal_fragment (result); + + /* Do a 4-byte align here. */ + frag_align (2, 0, 0); + record_alignment (now_seg, 2); +} + + +void +xtensa_switch_to_non_abs_literal_fragment (result) + emit_state *result; { /* When we mark a literal pool location, we want to put a frag in the literal pool that points to it. But to do that, we want to @@ -7703,15 +10938,13 @@ xtensa_switch_to_literal_fragment (result) bfd_boolean is_fini = (now_seg && !strcmp (segment_name (now_seg), FINI_SECTION_NAME)); - - if (pool_location == NULL - && !use_literal_section + if (pool_location == NULL + && !use_literal_section && !recursive && !is_init && ! is_fini) { - as_warn (_("inlining literal pool; " - "specify location with .literal_position.")); + as_bad (_("literal pool location required for text-section-literals; specify with .literal_position")); recursive = TRUE; xtensa_mark_literal_pool_location (); recursive = FALSE; @@ -7725,7 +10958,7 @@ xtensa_switch_to_literal_fragment (result) { cache_literal_section (init_literal_head, default_lit_sections.init_lit_seg_name, - &default_lit_sections.init_lit_seg); + &default_lit_sections.init_lit_seg, TRUE); xtensa_switch_section_emit_state (result, default_lit_sections.init_lit_seg, 0); } @@ -7733,31 +10966,30 @@ xtensa_switch_to_literal_fragment (result) { cache_literal_section (fini_literal_head, default_lit_sections.fini_lit_seg_name, - &default_lit_sections.fini_lit_seg); + &default_lit_sections.fini_lit_seg, TRUE); xtensa_switch_section_emit_state (result, default_lit_sections.fini_lit_seg, 0); } - else + else { cache_literal_section (literal_head, default_lit_sections.lit_seg_name, - &default_lit_sections.lit_seg); + &default_lit_sections.lit_seg, TRUE); xtensa_switch_section_emit_state (result, default_lit_sections.lit_seg, 0); } - if (!use_literal_section && - !is_init && !is_fini && - get_literal_pool_location (now_seg) != pool_location) + if (!use_literal_section + && !is_init && !is_fini + && get_literal_pool_location (now_seg) != pool_location) { /* Close whatever frag is there. */ frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL); + xtensa_set_frag_assembly_state (frag_now); frag_now->tc_frag_data.literal_frag = pool_location; frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL); + xtensa_set_frag_assembly_state (frag_now); } - - /* Do a 4 byte align here. */ - frag_align (2, 0, 0); } @@ -7795,17 +11027,18 @@ xtensa_restore_emit_state (state) present, return it; otherwise, create a new one. */ static void -cache_literal_section (head, name, seg) +cache_literal_section (head, name, seg, is_code) seg_list *head; const char *name; segT *seg; + bfd_boolean is_code; { segT current_section = now_seg; int current_subsec = now_subseg; if (*seg != 0) return; - *seg = retrieve_literal_seg (head, name); + *seg = retrieve_literal_seg (head, name, is_code); subseg_set (current_section, current_subsec); } @@ -7814,21 +11047,22 @@ cache_literal_section (head, name, seg) present, return it; otherwise, create a new one. */ static segT -retrieve_literal_seg (head, name) +retrieve_literal_seg (head, name, is_code) seg_list *head; const char *name; + bfd_boolean is_code; { segT ret = 0; - assert (head); - ret = seg_present (name); if (!ret) { ret = subseg_new (name, (subsegT) 0); - add_seg_list (head, ret); + if (head) + add_seg_list (head, ret); bfd_set_section_flags (stdoutput, ret, SEC_HAS_CONTENTS | - SEC_READONLY | SEC_ALLOC | SEC_LOAD | SEC_CODE); + SEC_READONLY | SEC_ALLOC | SEC_LOAD + | (is_code ? SEC_CODE : SEC_DATA)); bfd_set_section_alignment (stdoutput, ret, 2); } @@ -7872,75 +11106,227 @@ add_seg_list (head, seg) head->next = n; } - -/* Set up Property Tables after Relaxation. */ + +/* Property Tables Stuff. */ + +/* This function is only meaningful after xtensa_move_literals. */ + +static bfd_boolean +get_frag_is_literal (fragP) + const fragS *fragP; +{ + assert (fragP != NULL); + return fragP->tc_frag_data.is_literal; +} + + +static bfd_boolean +get_frag_is_insn (fragP) + const fragS *fragP; +{ + assert (fragP != NULL); + return fragP->tc_frag_data.is_insn; +} + + +bfd_boolean +get_frag_is_no_transform (fragP) + fragS *fragP; +{ + return fragP->tc_frag_data.is_no_transform; +} + + +void +set_frag_is_specific_opcode (fragP, is_specific_opcode) + fragS *fragP; + bfd_boolean is_specific_opcode; +{ + fragP->tc_frag_data.is_specific_opcode = is_specific_opcode; +} + + +void +set_frag_is_no_transform (fragP, is_no_transform) + fragS *fragP; + bfd_boolean is_no_transform; +{ + fragP->tc_frag_data.is_no_transform = is_no_transform; +} + + +static void +xtensa_create_property_segments (property_function, end_property_function, + section_name_base, sec_type) + frag_predicate property_function; + frag_predicate end_property_function; + const char *section_name_base; + xt_section_type sec_type; +{ + segT *seclist; + + /* Walk over all of the current segments. + Walk over each fragment + For each non-empty fragment, + Build a property record (append where possible). */ + + for (seclist = &stdoutput->sections; + seclist && *seclist; + seclist = &(*seclist)->next) + { + segT sec = *seclist; + flagword flags; + + flags = bfd_get_section_flags (stdoutput, sec); + if (flags & SEC_DEBUGGING) + continue; + if (!(flags & SEC_ALLOC)) + continue; + + if (section_has_property (sec, property_function)) + { + char *property_section_name = + xtensa_get_property_section_name (sec, section_name_base); + segT insn_sec = retrieve_xtensa_section (property_section_name); + segment_info_type *xt_seg_info = retrieve_segment_info (insn_sec); + xtensa_block_info **xt_blocks = + &xt_seg_info->tc_segment_info_data.blocks[sec_type]; + /* Walk over all of the frchains here and add new sections. */ + add_xt_block_frags (sec, insn_sec, xt_blocks, property_function, + end_property_function); + } + } + + /* Now we fill them out.... */ + + for (seclist = &stdoutput->sections; + seclist && *seclist; + seclist = &(*seclist)->next) + { + segment_info_type *seginfo; + xtensa_block_info *block; + segT sec = *seclist; + + seginfo = seg_info (sec); + block = seginfo->tc_segment_info_data.blocks[sec_type]; + + if (block) + { + xtensa_block_info *cur_block; + /* This is a section with some data. */ + int num_recs = 0; + size_t rec_size; + + for (cur_block = block; cur_block; cur_block = cur_block->next) + num_recs++; + + rec_size = num_recs * 8; + bfd_set_section_size (stdoutput, sec, rec_size); + + /* In order to make this work with the assembler, we have to + build some frags and then build the "fixups" for it. It + would be easier to just set the contents then set the + arlents. */ + + if (num_recs) + { + /* Allocate a fragment and leak it. */ + fragS *fragP; + size_t frag_size; + fixS *fixes; + frchainS *frchainP; + int i; + char *frag_data; + + frag_size = sizeof (fragS) + rec_size; + fragP = (fragS *) xmalloc (frag_size); -#define XTENSA_INSN_SEC_NAME ".xt.insn" -#define XTENSA_LIT_SEC_NAME ".xt.lit" + memset (fragP, 0, frag_size); + fragP->fr_address = 0; + fragP->fr_next = NULL; + fragP->fr_fix = rec_size; + fragP->fr_var = 0; + fragP->fr_type = rs_fill; + /* The rest are zeros. */ -void -xtensa_post_relax_hook () -{ - xtensa_move_seg_list_to_beginning (literal_head); - xtensa_move_seg_list_to_beginning (init_literal_head); - xtensa_move_seg_list_to_beginning (fini_literal_head); + frchainP = seginfo->frchainP; + frchainP->frch_root = fragP; + frchainP->frch_last = fragP; - xtensa_create_property_segments (get_frag_is_insn, - XTENSA_INSN_SEC_NAME, - xt_insn_sec); - xtensa_create_property_segments (get_frag_is_literal, - XTENSA_LIT_SEC_NAME, - xt_literal_sec); -} + fixes = (fixS *) xmalloc (sizeof (fixS) * num_recs); + memset (fixes, 0, sizeof (fixS) * num_recs); + seginfo->fix_root = fixes; + seginfo->fix_tail = &fixes[num_recs - 1]; + cur_block = block; + frag_data = &fragP->fr_literal[0]; + for (i = 0; i < num_recs; i++) + { + fixS *fix = &fixes[i]; + assert (cur_block); -static bfd_boolean -get_frag_is_literal (fragP) - const fragS *fragP; -{ - assert (fragP != NULL); - return (fragP->tc_frag_data.is_literal); -} - + /* Write the fixup. */ + if (i != num_recs - 1) + fix->fx_next = &fixes[i + 1]; + else + fix->fx_next = NULL; + fix->fx_size = 4; + fix->fx_done = 0; + fix->fx_frag = fragP; + fix->fx_where = i * 8; + fix->fx_addsy = section_symbol (cur_block->sec); + fix->fx_offset = cur_block->offset; + fix->fx_r_type = BFD_RELOC_32; + fix->fx_file = "Internal Assembly"; + fix->fx_line = 0; -static bfd_boolean -get_frag_is_insn (fragP) - const fragS *fragP; -{ - assert (fragP != NULL); - return (fragP->tc_frag_data.is_insn); + /* Write the length. */ + md_number_to_chars (&frag_data[4 + 8 * i], + cur_block->size, 4); + cur_block = cur_block->next; + } + } + } + } } -static void -xtensa_create_property_segments (property_function, section_name_base, - sec_type) - frag_predicate property_function; - const char * section_name_base; +void +xtensa_create_xproperty_segments (flag_fn, section_name_base, sec_type) + frag_flags_fn flag_fn; + const char *section_name_base; xt_section_type sec_type; { segT *seclist; /* Walk over all of the current segments. - Walk over each fragment - For each fragment that has instructions - Build an instruction record (append where possible). */ + Walk over each fragment. + For each fragment that has instructions, + build an instruction record (append where possible). */ for (seclist = &stdoutput->sections; seclist && *seclist; seclist = &(*seclist)->next) { segT sec = *seclist; - if (section_has_property (sec, property_function)) + flagword flags; + + flags = bfd_get_section_flags (stdoutput, sec); + if (flags & SEC_DEBUGGING) + continue; + if (!(flags & SEC_ALLOC)) + continue; + + if (section_has_xproperty (sec, flag_fn)) { char *property_section_name = xtensa_get_property_section_name (sec, section_name_base); segT insn_sec = retrieve_xtensa_section (property_section_name); segment_info_type *xt_seg_info = retrieve_segment_info (insn_sec); - xtensa_block_info **xt_blocks = + xtensa_block_info **xt_blocks = &xt_seg_info->tc_segment_info_data.blocks[sec_type]; /* Walk over all of the frchains here and add new sections. */ - add_xt_block_frags (sec, insn_sec, xt_blocks, property_function); + add_xt_prop_frags (sec, insn_sec, xt_blocks, flag_fn); } } @@ -7953,6 +11339,7 @@ xtensa_create_property_segments (property_function, section_name_base, segment_info_type *seginfo; xtensa_block_info *block; segT sec = *seclist; + seginfo = seg_info (sec); block = seginfo->tc_segment_info_data.blocks[sec_type]; @@ -7960,28 +11347,29 @@ xtensa_create_property_segments (property_function, section_name_base, { xtensa_block_info *cur_block; /* This is a section with some data. */ - size_t num_recs = 0; + int num_recs = 0; size_t rec_size; for (cur_block = block; cur_block; cur_block = cur_block->next) num_recs++; - rec_size = num_recs * 8; + rec_size = num_recs * (8 + 4); bfd_set_section_size (stdoutput, sec, rec_size); - /* In order to make this work with the assembler, we have to - build some frags and then build the "fixups" for it. It - would be easier to just set the contents then set the - arlents. */ + /* elf_section_data (sec)->this_hdr.sh_entsize = 12; */ + + /* In order to make this work with the assembler, we have to build + some frags then build the "fixups" for it. It would be easier to + just set the contents then set the arlents. */ if (num_recs) { - /* Allocate a fragment and leak it. */ + /* Allocate a fragment and (unfortunately) leak it. */ fragS *fragP; size_t frag_size; fixS *fixes; frchainS *frchainP; - size_t i; + int i; char *frag_data; frag_size = sizeof (fragS) + rec_size; @@ -7993,7 +11381,7 @@ xtensa_create_property_segments (property_function, section_name_base, fragP->fr_fix = rec_size; fragP->fr_var = 0; fragP->fr_type = rs_fill; - /* the rest are zeros */ + /* The rest are zeros. */ frchainP = seginfo->frchainP; frchainP->frch_root = fragP; @@ -8019,7 +11407,7 @@ xtensa_create_property_segments (property_function, section_name_base, fix->fx_size = 4; fix->fx_done = 0; fix->fx_frag = fragP; - fix->fx_where = i * 8; + fix->fx_where = i * (8 + 4); fix->fx_addsy = section_symbol (cur_block->sec); fix->fx_offset = cur_block->offset; fix->fx_r_type = BFD_RELOC_32; @@ -8027,8 +11415,11 @@ xtensa_create_property_segments (property_function, section_name_base, fix->fx_line = 0; /* Write the length. */ - md_number_to_chars (&frag_data[4 + 8 * i], + md_number_to_chars (&frag_data[4 + (8+4) * i], cur_block->size, 4); + md_number_to_chars (&frag_data[8 + (8+4) * i], + frag_flags_to_number (&cur_block->flags), + 4); cur_block = cur_block->next; } } @@ -8132,14 +11523,38 @@ section_has_property (sec, property_function) } +bfd_boolean +section_has_xproperty (sec, property_function) + segT sec; + frag_flags_fn property_function; +{ + segment_info_type *seginfo = seg_info (sec); + fragS *fragP; + + if (seginfo && seginfo->frchainP) + { + for (fragP = seginfo->frchainP->frch_root; fragP; fragP = fragP->fr_next) + { + frag_flags prop_flags; + property_function (fragP, &prop_flags); + if (!xtensa_frag_flags_is_empty (&prop_flags)) + return TRUE; + } + } + return FALSE; +} + + /* Two types of block sections exist right now: literal and insns. */ void -add_xt_block_frags (sec, xt_block_sec, xt_block, property_function) +add_xt_block_frags (sec, xt_block_sec, xt_block, property_function, + end_property_function) segT sec; segT xt_block_sec; xtensa_block_info **xt_block; frag_predicate property_function; + frag_predicate end_property_function; { segment_info_type *seg_info; segment_info_type *xt_seg_info; @@ -8176,17 +11591,391 @@ add_xt_block_frags (sec, xt_block_sec, xt_block, property_function) } if (*xt_block == NULL) { - xtensa_block_info *new_block = (xtensa_block_info *) - xmalloc (sizeof (xtensa_block_info)); - new_block->sec = sec; - new_block->offset = fragP->fr_address; - new_block->size = fragP->fr_fix; - new_block->next = NULL; - *xt_block = new_block; + xtensa_block_info *new_block = (xtensa_block_info *) + xmalloc (sizeof (xtensa_block_info)); + new_block->sec = sec; + new_block->offset = fragP->fr_address; + new_block->size = fragP->fr_fix; + new_block->next = NULL; + xtensa_frag_flags_init (&new_block->flags); + *xt_block = new_block; + } + if (end_property_function + && end_property_function (fragP)) + { + xt_block = &((*xt_block)->next); + } + } + } + } +} + + +/* Break the encapsulation of add_xt_prop_frags here. */ + +bfd_boolean +xtensa_frag_flags_is_empty (prop_flags) + const frag_flags *prop_flags; +{ + if (prop_flags->is_literal + || prop_flags->is_insn + || prop_flags->is_data + || prop_flags->is_unreachable) + return FALSE; + return TRUE; +} + + +void +xtensa_frag_flags_init (prop_flags) + frag_flags *prop_flags; +{ + memset (prop_flags, 0, sizeof (frag_flags)); +} + + +void +get_frag_property_flags (fragP, prop_flags) + const fragS *fragP; + frag_flags *prop_flags; +{ + xtensa_frag_flags_init (prop_flags); + if (fragP->tc_frag_data.is_literal) + prop_flags->is_literal = TRUE; + if (fragP->tc_frag_data.is_unreachable) + { + prop_flags->is_unreachable = TRUE; + } + else if (fragP->tc_frag_data.is_insn) + { + prop_flags->is_insn = TRUE; + if (fragP->tc_frag_data.is_loop_target) + prop_flags->insn.is_loop_target = TRUE; + if (fragP->tc_frag_data.is_branch_target) + prop_flags->insn.is_branch_target = TRUE; + if (fragP->tc_frag_data.is_specific_opcode + || fragP->tc_frag_data.is_no_transform) + prop_flags->insn.is_no_transform = TRUE; + if (fragP->tc_frag_data.is_no_density) + prop_flags->insn.is_no_density = TRUE; + if (fragP->tc_frag_data.use_absolute_literals) + prop_flags->insn.is_abslit = TRUE; + } + if (fragP->tc_frag_data.is_align) + { + prop_flags->is_align = TRUE; + prop_flags->alignment = fragP->tc_frag_data.alignment; + if (xtensa_frag_flags_is_empty (prop_flags)) + prop_flags->is_data = TRUE; + } +} + + +bfd_vma +frag_flags_to_number (prop_flags) + const frag_flags *prop_flags; +{ + bfd_vma num = 0; + if (prop_flags->is_literal) + num |= XTENSA_PROP_LITERAL; + if (prop_flags->is_insn) + num |= XTENSA_PROP_INSN; + if (prop_flags->is_data) + num |= XTENSA_PROP_DATA; + if (prop_flags->is_unreachable) + num |= XTENSA_PROP_UNREACHABLE; + if (prop_flags->insn.is_loop_target) + num |= XTENSA_PROP_INSN_LOOP_TARGET; + if (prop_flags->insn.is_branch_target) + { + num |= XTENSA_PROP_INSN_BRANCH_TARGET; + num = SET_XTENSA_PROP_BT_ALIGN (num, prop_flags->insn.bt_align_priority); + } + + if (prop_flags->insn.is_no_density) + num |= XTENSA_PROP_INSN_NO_DENSITY; + if (prop_flags->insn.is_no_transform) + num |= XTENSA_PROP_INSN_NO_TRANSFORM; + if (prop_flags->insn.is_no_reorder) + num |= XTENSA_PROP_INSN_NO_REORDER; + if (prop_flags->insn.is_abslit) + num |= XTENSA_PROP_INSN_ABSLIT; + + if (prop_flags->is_align) + { + num |= XTENSA_PROP_ALIGN; + num = SET_XTENSA_PROP_ALIGNMENT (num, prop_flags->alignment); + } + + return num; +} + + +static bfd_boolean +xtensa_frag_flags_combinable (prop_flags_1, prop_flags_2) + const frag_flags *prop_flags_1; + const frag_flags *prop_flags_2; +{ + /* Cannot combine with an end marker. */ + + if (prop_flags_1->is_literal != prop_flags_2->is_literal) + return FALSE; + if (prop_flags_1->is_insn != prop_flags_2->is_insn) + return FALSE; + if (prop_flags_1->is_data != prop_flags_2->is_data) + return FALSE; + + if (prop_flags_1->is_insn) + { + /* Properties of the beginning of the frag. */ + if (prop_flags_2->insn.is_loop_target) + return FALSE; + if (prop_flags_2->insn.is_branch_target) + return FALSE; + if (prop_flags_1->insn.is_no_density != + prop_flags_2->insn.is_no_density) + return FALSE; + if (prop_flags_1->insn.is_no_transform != + prop_flags_2->insn.is_no_transform) + return FALSE; + if (prop_flags_1->insn.is_no_reorder != + prop_flags_2->insn.is_no_reorder) + return FALSE; + if (prop_flags_1->insn.is_abslit != + prop_flags_2->insn.is_abslit) + return FALSE; + } + + if (prop_flags_1->is_align) + return FALSE; + + return TRUE; +} + + +bfd_vma +xt_block_aligned_size (xt_block) + const xtensa_block_info *xt_block; +{ + bfd_vma end_addr; + size_t align_bits; + + if (!xt_block->flags.is_align) + return xt_block->size; + + end_addr = xt_block->offset + xt_block->size; + align_bits = xt_block->flags.alignment; + end_addr = ((end_addr + ((1 << align_bits) -1)) >> align_bits) << align_bits; + return end_addr - xt_block->offset; +} + + +static bfd_boolean +xtensa_xt_block_combine (xt_block, xt_block_2) + xtensa_block_info *xt_block; + const xtensa_block_info *xt_block_2; +{ + if (xt_block->sec != xt_block_2->sec) + return FALSE; + if (xt_block->offset + xt_block_aligned_size (xt_block) + != xt_block_2->offset) + return FALSE; + + if (xt_block_2->size == 0 + && (!xt_block_2->flags.is_unreachable + || xt_block->flags.is_unreachable)) + { + if (xt_block_2->flags.is_align + && xt_block->flags.is_align) + { + /* Nothing needed. */ + if (xt_block->flags.alignment >= xt_block_2->flags.alignment) + return TRUE; + } + else + { + if (xt_block_2->flags.is_align) + { + /* Push alignment to previous entry. */ + xt_block->flags.is_align = xt_block_2->flags.is_align; + xt_block->flags.alignment = xt_block_2->flags.alignment; + } + return TRUE; + } + } + if (!xtensa_frag_flags_combinable (&xt_block->flags, + &xt_block_2->flags)) + return FALSE; + + xt_block->size += xt_block_2->size; + + if (xt_block_2->flags.is_align) + { + xt_block->flags.is_align = TRUE; + xt_block->flags.alignment = xt_block_2->flags.alignment; + } + + return TRUE; +} + + +void +add_xt_prop_frags (sec, xt_block_sec, xt_block, property_function) + segT sec; + segT xt_block_sec; + xtensa_block_info **xt_block; + frag_flags_fn property_function; +{ + segment_info_type *seg_info; + segment_info_type *xt_seg_info; + bfd_vma seg_offset; + fragS *fragP; + + xt_seg_info = retrieve_segment_info (xt_block_sec); + seg_info = retrieve_segment_info (sec); + /* Build it if needed. */ + while (*xt_block != NULL) + { + xt_block = &(*xt_block)->next; + } + /* We are either at NULL at the beginning or at the end. */ + + /* Walk through the frags. */ + seg_offset = 0; + + if (seg_info->frchainP) + { + for (fragP = seg_info->frchainP->frch_root; fragP; + fragP = fragP->fr_next) + { + xtensa_block_info tmp_block; + tmp_block.sec = sec; + tmp_block.offset = fragP->fr_address; + tmp_block.size = fragP->fr_fix; + tmp_block.next = NULL; + property_function (fragP, &tmp_block.flags); + + if (!xtensa_frag_flags_is_empty (&tmp_block.flags)) + /* && fragP->fr_fix != 0) */ + { + if ((*xt_block) == NULL + || !xtensa_xt_block_combine (*xt_block, &tmp_block)) + { + xtensa_block_info *new_block; + if ((*xt_block) != NULL) + xt_block = &(*xt_block)->next; + new_block = (xtensa_block_info *) + xmalloc (sizeof (xtensa_block_info)); + *new_block = tmp_block; + *xt_block = new_block; + } + } + } + } +} + + +/* op_placement_info_table */ + +/* op_placement_info makes it easier to determine which + ops can go in which slots. */ + +static void +init_op_placement_info_table () +{ + xtensa_isa isa = xtensa_default_isa; + xtensa_insnbuf ibuf = xtensa_insnbuf_alloc (isa); + xtensa_opcode opcode; + xtensa_format fmt; + int slot; + int num_opcodes = xtensa_isa_num_opcodes (isa); + + op_placement_table = (op_placement_info_table) + xmalloc (sizeof (op_placement_info) * num_opcodes); + assert (xtensa_isa_num_formats (isa) < MAX_FORMATS); + + for (opcode = 0; opcode < num_opcodes; opcode++) + { + op_placement_info *opi = &op_placement_table[opcode]; + /* FIXME: Make tinsn allocation dynamic. */ + if (xtensa_opcode_num_operands (isa, opcode) >= MAX_INSN_ARGS) + as_fatal (_("too many operands in instruction")); + opi->single = XTENSA_UNDEFINED; + opi->single_size = 0; + opi->widest = XTENSA_UNDEFINED; + opi->widest_size = 0; + opi->narrowest = XTENSA_UNDEFINED; + opi->narrowest_size = 0x7F; + opi->formats = 0; + opi->num_formats = 0; + opi->issuef = 0; + for (fmt = 0; fmt < xtensa_isa_num_formats (isa); fmt++) + { + opi->slots[fmt] = 0; + for (slot = 0; slot < xtensa_format_num_slots (isa, fmt); slot++) + { + if (xtensa_opcode_encode (isa, fmt, slot, ibuf, opcode) == 0) + { + int fmt_length = xtensa_format_length (isa, fmt); + opi->issuef++; + set_bit (fmt, opi->formats); + set_bit (slot, opi->slots[fmt]); + /* opi->slot_count[fmt]++; */ + if (fmt_length < opi->narrowest_size) + { + opi->narrowest = fmt; + opi->narrowest_size = fmt_length; + } + if (fmt_length > opi->widest_size) + { + opi->widest = fmt; + opi->widest_size = fmt_length; + } + if (xtensa_format_num_slots (isa, fmt) == 1) + { + if (opi->single_size == 0 + || fmt_length < opi->single_size) + { + opi->single = fmt; + opi->single_size = fmt_length; + } + } } } + if (opi->formats) + opi->num_formats++; } } + xtensa_insnbuf_free (isa, ibuf); +} + + +bfd_boolean +opcode_fits_format_slot (opcode, fmt, slot) + xtensa_opcode opcode; + xtensa_format fmt; + int slot; +{ + return bit_is_set (slot, op_placement_table[opcode].slots[fmt]); +} + + +/* If the opcode is available in a single slot format, return its size. */ + +int +xg_get_single_size (opcode) + xtensa_opcode opcode; +{ + assert (op_placement_table[opcode].single != XTENSA_UNDEFINED); + return op_placement_table[opcode].single_size; +} + + +xtensa_format +xg_get_single_format (opcode) + xtensa_opcode opcode; +{ + return op_placement_table[opcode].single; } @@ -8218,7 +12007,7 @@ istack_full (stack) /* Return a pointer to the top IStack entry. - It is an error to call this if istack_empty () is true. */ + It is an error to call this if istack_empty () is TRUE. */ TInsn * istack_top (stack) @@ -8231,7 +12020,7 @@ istack_top (stack) /* Add a new TInsn to an IStack. - It is an error to call this if istack_full () is true. */ + It is an error to call this if istack_full () is TRUE. */ void istack_push (stack, insn) @@ -8240,13 +12029,13 @@ istack_push (stack, insn) { int rec = stack->ninsn; assert (!istack_full (stack)); - tinsn_copy (&stack->insn[rec], insn); + stack->insn[rec] = *insn; stack->ninsn++; } /* Clear space for the next TInsn on the IStack and return a pointer - to it. It is an error to call this if istack_full () is true. */ + to it. It is an error to call this if istack_full () is TRUE. */ TInsn * istack_push_space (stack) @@ -8263,7 +12052,7 @@ istack_push_space (stack) /* Remove the last pushed instruction. It is an error to call this if - istack_empty () returns true. */ + istack_empty () returns TRUE. */ void istack_pop (stack) @@ -8286,16 +12075,6 @@ tinsn_init (dst) } -void -tinsn_copy (dst, src) - TInsn *dst; - const TInsn *src; -{ - tinsn_init (dst); - memcpy (dst, src, sizeof (TInsn)); -} - - /* Get the ``num''th token of the TInsn. It is illegal to call this if num > insn->ntoks. */ @@ -8309,7 +12088,7 @@ tinsn_get_tok (insn, num) } -/* Return true if ANY of the operands in the insn are symbolic. */ +/* Return TRUE if ANY of the operands in the insn are symbolic. */ static bfd_boolean tinsn_has_symbolic_operands (insn) @@ -8339,6 +12118,7 @@ bfd_boolean tinsn_has_invalid_symbolic_operands (insn) const TInsn *insn; { + xtensa_isa isa = xtensa_default_isa; int i; int n = insn->ntok; @@ -8351,12 +12131,30 @@ tinsn_has_invalid_symbolic_operands (insn) case O_register: case O_constant: break; + case O_big: + case O_illegal: + case O_absent: + /* Errors for these types are caught later. */ + break; + case O_hi16: + case O_lo16: default: - if (i == get_relaxable_immed (insn->opcode)) - break; - as_bad (_("invalid symbolic operand %d on '%s'"), - i, xtensa_opcode_name (xtensa_default_isa, insn->opcode)); - return TRUE; + /* Symbolic immediates are only allowed on the last immediate + operand. At this time, CONST16 is the only opcode where we + support non-PC-relative relocations. (It isn't necessary + to complain about non-PC-relative relocations here, but + otherwise, no error is reported until the relocations are + generated, and the assembler won't get that far if there + are any other errors. It's nice to see all the problems + at once.) */ + if (i != get_relaxable_immed (insn->opcode) + || (xtensa_operand_is_PCrelative (isa, insn->opcode, i) != 1 + && insn->opcode != xtensa_const16_opcode)) + { + as_bad (_("invalid symbolic operand %d on '%s'"), + i, xtensa_opcode_name (isa, insn->opcode)); + return TRUE; + } } } return FALSE; @@ -8383,6 +12181,8 @@ tinsn_has_complex_operands (insn) case O_register: case O_constant: case O_symbol: + case O_lo16: + case O_hi16: break; default: return TRUE; @@ -8392,69 +12192,164 @@ tinsn_has_complex_operands (insn) } -/* Convert the constant operands in the t_insn to insnbuf. - Return true if there is a symbol in the immediate field. +/* Convert the constant operands in the tinsn to insnbuf. + Return TRUE if there is a symbol in the immediate field. - Before this is called, + Before this is called, 1) the number of operands are correct - 2) the t_insn is a ITYPE_INSN + 2) the tinsn is a ITYPE_INSN 3) ONLY the relaxable_ is built 4) All operands are O_constant, O_symbol. All constants fit The return value tells whether there are any remaining O_symbols. */ static bfd_boolean -tinsn_to_insnbuf (t_insn, insnbuf) - TInsn *t_insn; +tinsn_to_insnbuf (tinsn, insnbuf) + TInsn *tinsn; xtensa_insnbuf insnbuf; { + static xtensa_insnbuf slotbuf = 0; xtensa_isa isa = xtensa_default_isa; - xtensa_opcode opcode = t_insn->opcode; + xtensa_opcode opcode = tinsn->opcode; + xtensa_format fmt = xg_get_single_format (opcode); bfd_boolean has_fixup = FALSE; - int noperands = xtensa_num_operands (isa, opcode); + int noperands = xtensa_opcode_num_operands (isa, opcode); int i; uint32 opnd_value; char *file_name; int line; - assert (t_insn->insn_type == ITYPE_INSN); - if (noperands != t_insn->ntok) + if (!slotbuf) + slotbuf = xtensa_insnbuf_alloc (isa); + + assert (tinsn->insn_type == ITYPE_INSN); + if (noperands != tinsn->ntok) as_fatal (_("operand number mismatch")); - xtensa_encode_insn (isa, opcode, insnbuf); + if (xtensa_opcode_encode (isa, fmt, 0, slotbuf, opcode)) + as_fatal (_("cannot encode opcode")); for (i = 0; i < noperands; ++i) { - expressionS *expr = &t_insn->tok[i]; - xtensa_operand operand = xtensa_get_operand (isa, opcode, i); + expressionS *expr = &tinsn->tok[i]; switch (expr->X_op) { case O_register: - /* The register number has already been checked in + if (xtensa_operand_is_visible (isa, opcode, i) == 0) + break; + /* The register number has already been checked in expression_maybe_register, so we don't need to check here. */ opnd_value = expr->X_add_number; - (void) xtensa_operand_encode (operand, &opnd_value); - xtensa_operand_set_field (operand, insnbuf, opnd_value); + (void) xtensa_operand_encode (isa, opcode, i, &opnd_value); + xtensa_operand_set_field (isa, opcode, i, fmt, 0, + slotbuf, opnd_value); break; case O_constant: + if (xtensa_operand_is_visible (isa, opcode, i) == 0) + break; as_where (&file_name, &line); /* It is a constant and we called this function, then we have to try to fit it. */ - xtensa_insnbuf_set_operand (insnbuf, opcode, operand, + xtensa_insnbuf_set_operand (slotbuf, fmt, 0, opcode, i, + expr->X_add_number, file_name, line); + break; + + default: + has_fixup = TRUE; + break; + } + } + + xtensa_format_encode (isa, fmt, insnbuf); + xtensa_format_set_slot (isa, fmt, 0, insnbuf, slotbuf); + + return has_fixup; +} + + +/* Convert the constant operands in the tinsn to slotbuf. + Return TRUE if there is a symbol in the immediate field. + (Eventually this should replace tinsn_to_insnbuf.) */ + +/* Before this is called, + 1) the number of operands are correct + 2) the tinsn is a ITYPE_INSN + 3) ONLY the relaxable_ is built + 4) All operands are + O_constant, O_symbol + All constants fit + + The return value tells whether there are any remaining O_symbols. */ + +static bfd_boolean +tinsn_to_slotbuf (fmt, slot, tinsn, slotbuf) + xtensa_format fmt; + int slot; + TInsn *tinsn; + xtensa_insnbuf slotbuf; +{ + xtensa_isa isa = xtensa_default_isa; + xtensa_opcode opcode = tinsn->opcode; + bfd_boolean has_fixup = FALSE; + int noperands = xtensa_opcode_num_operands (isa, opcode); + int i; + + *((int *) &slotbuf[0]) = 0; + *((int *) &slotbuf[1]) = 0; + assert (tinsn->insn_type == ITYPE_INSN); + if (noperands != tinsn->ntok) + as_fatal (_("operand number mismatch")); + + if (xtensa_opcode_encode (isa, fmt, slot, slotbuf, opcode)) + { + as_bad (_("cannot encode opcode \"%s\" in the given format \"%s\""), + xtensa_opcode_name (isa, opcode), xtensa_format_name (isa, fmt)); + return FALSE; + } + + for (i = 0; i < noperands; i++) + { + expressionS *expr = &tinsn->tok[i]; + int rc, line; + char *file_name; + uint32 opnd_value; + + switch (expr->X_op) + { + case O_register: + if (xtensa_operand_is_visible (isa, opcode, i) == 0) + break; + /* The register number has already been checked in + expression_maybe_register, so we don't need to check here. */ + opnd_value = expr->X_add_number; + (void) xtensa_operand_encode (isa, opcode, i, &opnd_value); + rc = xtensa_operand_set_field (isa, opcode, i, fmt, slot, slotbuf, + opnd_value); + if (rc != 0) + as_warn (_("xtensa-isa failure: %s"), xtensa_isa_error_msg (isa)); + break; + + case O_constant: + if (xtensa_operand_is_visible (isa, opcode, i) == 0) + break; + as_where (&file_name, &line); + /* It is a constant and we called this function + then we have to try to fit it. */ + xtensa_insnbuf_set_operand (slotbuf, fmt, slot, opcode, i, expr->X_add_number, file_name, line); break; - case O_symbol: default: has_fixup = TRUE; break; } } + return has_fixup; } -/* Check the instruction arguments. Return true on failure. */ +/* Check the instruction arguments. Return TRUE on failure. */ bfd_boolean tinsn_check_arguments (insn) @@ -8469,13 +12364,13 @@ tinsn_check_arguments (insn) return TRUE; } - if (xtensa_num_operands (isa, opcode) > insn->ntok) + if (xtensa_opcode_num_operands (isa, opcode) > insn->ntok) { as_bad (_("too few operands")); return TRUE; } - if (xtensa_num_operands (isa, opcode) < insn->ntok) + if (xtensa_opcode_num_operands (isa, opcode) < insn->ntok) { as_bad (_("too many operands")); return TRUE; @@ -8487,31 +12382,42 @@ tinsn_check_arguments (insn) /* Load an instruction from its encoded form. */ static void -tinsn_from_chars (t_insn, f) - TInsn *t_insn; +tinsn_from_chars (tinsn, f, slot) + TInsn *tinsn; char *f; + int slot; { - static xtensa_insnbuf insnbuf = NULL; - int i; - xtensa_opcode opcode; - xtensa_isa isa = xtensa_default_isa; + vliw_insn vinsn; - if (!insnbuf) - insnbuf = xtensa_insnbuf_alloc (isa); + xg_init_vinsn (&vinsn); + vinsn_from_chars (&vinsn, f); + + *tinsn = vinsn.slots[slot]; + xg_free_vinsn (&vinsn); +} - xtensa_insnbuf_from_chars (isa, insnbuf, f); - opcode = xtensa_decode_insn (isa, insnbuf); + +static void +tinsn_from_insnbuf (tinsn, slotbuf, fmt, slot) + TInsn *tinsn; + xtensa_insnbuf slotbuf; + xtensa_format fmt; + int slot; +{ + int i; + xtensa_isa isa = xtensa_default_isa; /* Find the immed. */ - tinsn_init (t_insn); - t_insn->insn_type = ITYPE_INSN; - t_insn->is_specific_opcode = FALSE; /* Must not be specific. */ - t_insn->opcode = opcode; - t_insn->ntok = xtensa_num_operands (isa, opcode); - for (i = 0; i < t_insn->ntok; i++) + tinsn_init (tinsn); + tinsn->insn_type = ITYPE_INSN; + tinsn->is_specific_opcode = FALSE; /* must not be specific */ + tinsn->opcode = xtensa_opcode_decode (isa, fmt, slot, slotbuf); + tinsn->ntok = xtensa_opcode_num_operands (isa, tinsn->opcode); + for (i = 0; i < tinsn->ntok; i++) { - set_expr_const (&t_insn->tok[i], - xtensa_insnbuf_get_operand (insnbuf, opcode, i)); + set_expr_const (&tinsn->tok[i], + xtensa_insnbuf_get_operand (slotbuf, fmt, slot, + tinsn->opcode, i)); } } @@ -8519,18 +12425,33 @@ tinsn_from_chars (t_insn, f) /* Read the value of the relaxable immed from the fr_symbol and fr_offset. */ static void -tinsn_immed_from_frag (t_insn, fragP) - TInsn *t_insn; +tinsn_immed_from_frag (tinsn, fragP, slot) + TInsn *tinsn; fragS *fragP; + int slot; { - xtensa_opcode opcode = t_insn->opcode; + xtensa_opcode opcode = tinsn->opcode; int opnum; - if (fragP->fr_symbol) + if (fragP->tc_frag_data.slot_symbols[slot]) { opnum = get_relaxable_immed (opcode); - set_expr_symbol_offset (&t_insn->tok[opnum], - fragP->fr_symbol, fragP->fr_offset); + assert (opnum >= 0); + if (fragP->tc_frag_data.slot_sub_symbols[slot]) + { + set_expr_symbol_offset_diff + (&tinsn->tok[opnum], + fragP->tc_frag_data.slot_symbols[slot], + fragP->tc_frag_data.slot_sub_symbols[slot], + fragP->tc_frag_data.slot_offsets[slot]); + } + else + { + set_expr_symbol_offset + (&tinsn->tok[opnum], + fragP->tc_frag_data.slot_symbols[slot], + fragP->tc_frag_data.slot_offsets[slot]); + } } } @@ -8544,9 +12465,9 @@ get_num_stack_text_bytes (istack) for (i = 0; i < istack->ninsn; i++) { - TInsn *t_insn = &istack->insn[i]; - if (t_insn->insn_type == ITYPE_INSN) - text_bytes += xg_get_insn_size (t_insn); + TInsn *tinsn = &istack->insn[i]; + if (tinsn->insn_type == ITYPE_INSN) + text_bytes += xg_get_single_size (tinsn->opcode); } return text_bytes; } @@ -8561,18 +12482,234 @@ get_num_stack_literal_bytes (istack) for (i = 0; i < istack->ninsn; i++) { - TInsn *t_insn = &istack->insn[i]; - - if (t_insn->insn_type == ITYPE_LITERAL && t_insn->ntok == 1) + TInsn *tinsn = &istack->insn[i]; + if (tinsn->insn_type == ITYPE_LITERAL && tinsn->ntok == 1) lit_bytes += 4; } return lit_bytes; } + +/* vliw_insn functions. */ + +void +xg_init_vinsn (v) + vliw_insn *v; +{ + int i; + xtensa_isa isa = xtensa_default_isa; + + xg_clear_vinsn (v); + + v->insnbuf = xtensa_insnbuf_alloc (isa); + if (v->insnbuf == NULL) + as_fatal (_("out of memory")); + + for (i = 0; i < MAX_SLOTS; i++) + { + tinsn_init (&v->slots[i]); + v->slots[i].opcode = XTENSA_UNDEFINED; + v->slotbuf[i] = xtensa_insnbuf_alloc (isa); + if (v->slotbuf[i] == NULL) + as_fatal (_("out of memory")); + } +} + + +void +xg_clear_vinsn (v) + vliw_insn *v; +{ + int i; + v->format = XTENSA_UNDEFINED; + v->num_slots = 0; + v->inside_bundle = FALSE; + + if (xt_saved_debug_type != DEBUG_NONE) + debug_type = xt_saved_debug_type; + + for (i = 0; i < MAX_SLOTS; i++) + { + memset (&v->slots[i], 0, sizeof (TInsn)); + v->slots[i].opcode = XTENSA_UNDEFINED; + } +} + + +bfd_boolean +vinsn_has_specific_opcodes (v) + vliw_insn *v; +{ + int i; + + for (i = 0; i < v->num_slots; i++) + { + if (v->slots[i].is_specific_opcode) + return TRUE; + } + return FALSE; +} + + +void +xg_free_vinsn (v) + vliw_insn *v; +{ + int i; + xtensa_insnbuf_free (xtensa_default_isa, v->insnbuf); + for (i = 0; i < MAX_SLOTS; i++) + xtensa_insnbuf_free (xtensa_default_isa, v->slotbuf[i]); +} + + +/* Before this is called, we should have + filled out the following fields: + + 1) the number of operands for each opcode are correct + 2) the tinsn in the slots are ITYPE_INSN + 3) ONLY the relaxable_ is built + 4) All operands are + O_constant, O_symbol + All constants fit + + The return value tells whether there are any remaining O_symbols. */ + +static bfd_boolean +vinsn_to_insnbuf (vinsn, frag_offset, fragP, record_fixup) + vliw_insn *vinsn; + char *frag_offset; + fragS *fragP; + bfd_boolean record_fixup; +{ + xtensa_isa isa = xtensa_default_isa; + xtensa_format fmt = vinsn->format; + xtensa_insnbuf insnbuf = vinsn->insnbuf; + int slot; + bfd_boolean has_fixup = FALSE; + + xtensa_format_encode (isa, fmt, insnbuf); + + for (slot = 0; slot < vinsn->num_slots; slot++) + { + TInsn *tinsn = &vinsn->slots[slot]; + bfd_boolean tinsn_has_fixup = + tinsn_to_slotbuf (vinsn->format, slot, tinsn, + vinsn->slotbuf[slot]); + + xtensa_format_set_slot (isa, fmt, slot, + insnbuf, vinsn->slotbuf[slot]); + /* tinsn_has_fixup tracks if there is a fixup at all. + record_fixup controls globally. I.E., we use this + function from several places, some of which are after + fixups have already been recorded. Finally, + tinsn->record_fixup controls based on the individual ops, + which may or may not need it based on the relaxation + requirements. */ + if (tinsn_has_fixup && record_fixup) + { + int i; + xtensa_opcode opcode = tinsn->opcode; + int noperands = xtensa_opcode_num_operands (isa, opcode); + has_fixup = TRUE; + + for (i = 0; i < noperands; i++) + { + expressionS* expr = &tinsn->tok[i]; + switch (expr->X_op) + { + case O_symbol: + case O_lo16: + case O_hi16: + if (get_relaxable_immed (opcode) == i) + { + if (tinsn->record_fix || expr->X_op != O_symbol) + { + if (!xg_add_opcode_fix + (tinsn, i, fmt, slot, expr, fragP, + frag_offset - fragP->fr_literal)) + as_bad (_("instruction with constant operands does not fit")); + } + else + { + tinsn->symbol = expr->X_add_symbol; + tinsn->offset = expr->X_add_number; + } + } + else + as_bad (_("invalid operand %d on '%s'"), + i, xtensa_opcode_name (isa, opcode)); + break; + + case O_constant: + case O_register: + break; + + case O_subtract: + if (get_relaxable_immed (opcode) == i) + { + if (tinsn->record_fix) + as_bad (_("invalid subtract operand")); + else + { + tinsn->symbol = expr->X_add_symbol; + tinsn->sub_symbol = expr->X_op_symbol; + tinsn->offset = expr->X_add_number; + } + } + else + as_bad (_("invalid operand %d on '%s'"), + i, xtensa_opcode_name (isa, opcode)); + break; + + default: + as_bad (_("invalid expression for operand %d on '%s'"), + i, xtensa_opcode_name (isa, opcode)); + break; + } + } + } + } + + return has_fixup; +} + + +static void +vinsn_from_chars (vinsn, f) + vliw_insn *vinsn; + char *f; +{ + static xtensa_insnbuf insnbuf = NULL; + static xtensa_insnbuf slotbuf = NULL; + int i; + xtensa_format fmt; + xtensa_isa isa = xtensa_default_isa; + + if (!insnbuf) + { + insnbuf = xtensa_insnbuf_alloc (isa); + slotbuf = xtensa_insnbuf_alloc (isa); + } + + xtensa_insnbuf_from_chars (isa, insnbuf, f, 0); + fmt = xtensa_format_decode (isa, insnbuf); + if (fmt == XTENSA_UNDEFINED) + as_fatal (_("cannot decode instruction format")); + vinsn->format = fmt; + vinsn->num_slots = xtensa_format_num_slots (isa, fmt); + + for (i = 0; i < vinsn->num_slots; i++) + { + TInsn *tinsn = &vinsn->slots[i]; + xtensa_format_get_slot (isa, fmt, i, insnbuf, slotbuf); + tinsn_from_insnbuf (tinsn, slotbuf, fmt, i); + } +} + /* Expression utilities. */ -/* Return true if the expression is an integer constant. */ +/* Return TRUE if the expression is an integer constant. */ bfd_boolean expr_is_const (s) @@ -8583,7 +12720,7 @@ expr_is_const (s) /* Get the expression constant. - Calling this is illegal if expr_is_const () returns true. */ + Calling this is illegal if expr_is_const () returns TRUE. */ offsetT get_expr_const (s) @@ -8608,6 +12745,26 @@ set_expr_const (s, val) } +bfd_boolean +expr_is_register (s) + const expressionS *s; +{ + return (s->X_op == O_register); +} + + +/* Get the expression constant. + Calling this is illegal if expr_is_const () returns TRUE. */ + +offsetT +get_expr_register (s) + const expressionS *s; +{ + assert (expr_is_register (s)); + return s->X_add_number; +} + + /* Set the expression to a symbol + constant offset. */ void @@ -8623,6 +12780,24 @@ set_expr_symbol_offset (s, sym, offset) } +/* Set the expression to symbol - minus_sym + offset. */ + +void +set_expr_symbol_offset_diff (s, sym, minus_sym, offset) + expressionS *s; + symbolS *sym; + symbolS *minus_sym; + offsetT offset; +{ + s->X_op = O_subtract; + s->X_add_symbol = sym; + s->X_op_symbol = minus_sym; /* unused */ + s->X_add_number = offset; +} + + +/* Return TRUE if the two expressions are equal. */ + bfd_boolean expr_is_equal (s1, s2) expressionS *s1; @@ -8663,7 +12838,7 @@ struct rename_section_struct static struct rename_section_struct *section_rename; -/* Parse the string oldname=new_name:oldname2=new_name2 +/* Parse the string oldname=new_name:oldname2=new_name2 and call add_section_rename. */ void @@ -8741,8 +12916,10 @@ xtensa_section_rename (name) struct rename_section_struct *r = section_rename; for (r = section_rename; r != NULL; r = r->next) - if (strcmp (r->old_name, name) == 0) - return r->new_name; + { + if (strcmp (r->old_name, name) == 0) + return r->new_name; + } return name; } diff --git a/gas/config/tc-xtensa.h b/gas/config/tc-xtensa.h index cf4a3507b13..3be75c74f3b 100644 --- a/gas/config/tc-xtensa.h +++ b/gas/config/tc-xtensa.h @@ -1,5 +1,5 @@ /* tc-xtensa.h -- Header file for tc-xtensa.c. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -33,61 +33,250 @@ struct fix; #error Xtensa support requires ELF object format #endif +#include "xtensa-isa.h" #include "xtensa-config.h" #define TARGET_BYTES_BIG_ENDIAN XCHAL_HAVE_BE +/* Maximum number of opcode slots in a VLIW instruction. */ +#define MAX_SLOTS 31 + + +/* For all xtensa relax states except RELAX_DESIRE_ALIGN and + RELAX_DESIRE_ALIGN_IF_TARGET, the amount a frag might grow is stored + in the fr_var field. For the two exceptions, fr_var is a float value + that records the frequency with which the following instruction is + executed as a branch target. The aligner uses this information to + tell which targets are most important to be aligned. */ + +enum xtensa_relax_statesE +{ + RELAX_ALIGN_NEXT_OPCODE, + /* Use the first opcode of the next fragment to determine the + alignment requirements. This is ONLY used for LOOPs currently. */ + + RELAX_CHECK_ALIGN_NEXT_OPCODE, + /* The next non-empty frag contains a loop instruction. Check to see + if it is correctly aligned, but do not align it. */ + + RELAX_DESIRE_ALIGN_IF_TARGET, + /* These are placed in front of labels and converted to either + RELAX_DESIRE_ALIGN / RELAX_LOOP_END or rs_fill of 0 before + relaxation begins. */ + + RELAX_ADD_NOP_IF_A0_B_RETW, + /* These are placed in front of conditional branches. Before + relaxation begins, they are turned into either NOPs for branches + immediately followed by RETW or RETW.N or rs_fills of 0. This is + used to avoid a hardware bug in some early versions of the + processor. */ + + RELAX_ADD_NOP_IF_PRE_LOOP_END, + /* These are placed after JX instructions. Before relaxation begins, + they are turned into either NOPs, if the JX is one instruction + before a loop end label, or rs_fills of 0. This is used to avoid a + hardware interlock issue prior to Xtensa version T1040. */ + + RELAX_ADD_NOP_IF_SHORT_LOOP, + /* These are placed after LOOP instructions and turned into NOPs when: + (1) there are less than 3 instructions in the loop; we place 2 of + these in a row to add up to 2 NOPS in short loops; or (2) the + instructions in the loop do not include a branch or jump. + Otherwise they are turned into rs_fills of 0 before relaxation + begins. This is used to avoid hardware bug PR3830. */ + + RELAX_ADD_NOP_IF_CLOSE_LOOP_END, + /* These are placed after LOOP instructions and turned into NOPs if + there are less than 12 bytes to the end of some other loop's end. + Otherwise they are turned into rs_fills of 0 before relaxation + begins. This is used to avoid hardware bug PR3830. */ + + RELAX_DESIRE_ALIGN, + /* The next fragment would like its first instruction to NOT cross an + instruction fetch boundary. */ + + RELAX_MAYBE_DESIRE_ALIGN, + /* The next fragment might like its first instruction to NOT cross an + instruction fetch boundary. These are placed after a branch that + might be relaxed. If the branch is relaxed, then this frag will be + a branch target and this frag will be changed to RELAX_DESIRE_ALIGN + frag. */ + + RELAX_LOOP_END, + /* This will be turned into a NOP or NOP.N if the previous instruction + is expanded to negate a loop. */ + + RELAX_LOOP_END_ADD_NOP, + /* When the code density option is available, this will generate a + NOP.N marked RELAX_NARROW. Otherwise, it will create an rs_fill + fragment with a NOP in it. */ + + RELAX_LITERAL, + /* Another fragment could generate an expansion here but has not yet. */ + + RELAX_LITERAL_NR, + /* Expansion has been generated by an instruction that generates a + literal. However, the stretch has NOT been reported yet in this + fragment. */ + + RELAX_LITERAL_FINAL, + /* Expansion has been generated by an instruction that generates a + literal. */ + + RELAX_LITERAL_POOL_BEGIN, + RELAX_LITERAL_POOL_END, + /* Technically these are not relaxations at all but mark a location + to store literals later. Note that fr_var stores the frchain for + BEGIN frags and fr_var stores now_seg for END frags. */ + + RELAX_NARROW, + /* The last instruction in this fragment (at->fr_opcode) can be + freely replaced with a single wider instruction if a future + alignment desires or needs it. */ + + RELAX_IMMED, + /* The last instruction in this fragment (at->fr_opcode) contains + the value defined by fr_symbol (fr_offset = 0). If the value + does not fit, use the specified expansion. This is similar to + "NARROW", except that these may not be expanded in order to align + code. */ + + RELAX_IMMED_STEP1, + /* The last instruction in this fragment (at->fr_opcode) contains a + literal. It has already been expanded at least 1 step. */ + + RELAX_IMMED_STEP2, + /* The last instruction in this fragment (at->fr_opcode) contains a + literal. It has already been expanded at least 2 steps. */ + + RELAX_SLOTS, + /* There are instructions within the last VLIW instruction that need + relaxation. Find the relaxation based on the slot info in + xtensa_frag_type. Relaxations that deal with particular opcodes + are slot-based (e.g., converting a MOVI to an L32R). Relaxations + that deal with entire instructions, such as alignment, are not + slot-based. */ + + RELAX_FILL_NOP, + /* This marks the location of a pipeline stall. We can fill these guys + in for alignment of any size. */ + + RELAX_UNREACHABLE, + /* This marks the location as unreachable. The assembler may widen or + narrow this area to meet alignment requirements of nearby + instructions. */ + + RELAX_MAYBE_UNREACHABLE, + /* This marks the location as possibly unreachable. These are placed + after a branch that may be relaxed into a branch and jump. If the + branch is relaxed, then this frag will be converted to a + RELAX_UNREACHABLE frag. */ + + RELAX_NONE +}; + +/* This is used as a stopper to bound the number of steps that + can be taken. */ +#define RELAX_IMMED_MAXSTEPS (RELAX_IMMED_STEP2 - RELAX_IMMED) + struct xtensa_frag_type { - unsigned is_literal:1; - unsigned is_text:1; - unsigned is_loop_target:1; - unsigned is_branch_target:1; - unsigned is_insn:1; + /* Info about the current state of assembly, e.g., transform, + absolute_literals, etc. These need to be passed to the backend and + then to the object file. + + When is_assembly_state_set is false, the frag inherits some of the + state settings from the previous frag in this segment. Because it + is not possible to intercept all fragment closures (frag_more and + frag_append_1_char can close a frag), we use a pass after initial + assembly to fill in the assembly states. */ + + unsigned int is_assembly_state_set : 1; + unsigned int is_no_density : 1; + unsigned int is_no_transform : 1; + unsigned int use_absolute_literals : 1; + + /* Inhibits relaxation of machine-dependent alignment frags the + first time through a relaxation.... */ + unsigned int relax_seen : 1; + + /* Infomation that is needed in the object file and set when known. */ + unsigned int is_literal : 1; + unsigned int is_loop_target : 1; + unsigned int is_branch_target : 1; + unsigned int is_insn : 1; + unsigned int is_unreachable : 1; - /* Info about the current state of assembly, i.e., density, relax, - generics, freeregs, longcalls. These need to be passed to the - backend and then to the linking file. */ + unsigned int is_specific_opcode : 1; /* also implies no_transform */ - unsigned is_no_density:1; - unsigned is_relax:1; - unsigned is_generics:1; - unsigned is_longcalls:1; + unsigned int is_align : 1; + unsigned int is_text_align : 1; + unsigned int alignment : 5; + + /* A frag with this bit set is the first in a loop that actually + contains an instruction. */ + unsigned int is_first_loop_insn : 1; /* For text fragments that can generate literals at relax time, this variable points to the frag where the literal will be stored. For literal frags, this variable points to the nearest literal pool location frag. This literal frag will be moved to after this location. */ - fragS *literal_frag; /* The destination segment for literal frags. (Note that this is only valid after xtensa_move_literals. */ - segT lit_seg; /* For the relaxation scheme, some literal fragments can have their expansions modified by an instruction that relaxes. */ - - unsigned text_expansion; - unsigned literal_expansion; - unsigned unreported_expansion; + int text_expansion[MAX_SLOTS]; + int literal_expansion[MAX_SLOTS]; + int unreported_expansion; + + /* For text fragments that can generate literals at relax time: */ + fragS *literal_frags[MAX_SLOTS]; + enum xtensa_relax_statesE slot_subtypes[MAX_SLOTS]; + symbolS *slot_symbols[MAX_SLOTS]; + symbolS *slot_sub_symbols[MAX_SLOTS]; + offsetT slot_offsets[MAX_SLOTS]; + + /* The global aligner needs to walk backward through the list of + frags. This field is only valid after xtensa_end. */ + fragS *fr_prev; }; -typedef struct xtensa_block_info_struct + +/* For VLIW support, we need to know what slot a fixup applies to. */ +typedef struct xtensa_fix_data_struct +{ + int slot; + symbolS *X_add_symbol; + offsetT X_add_number; +} xtensa_fix_data; + + +/* Structure to record xtensa-specific symbol information. */ +typedef struct xtensa_symfield_type { - segT sec; - bfd_vma offset; - size_t size; - struct xtensa_block_info_struct *next; -} xtensa_block_info; + unsigned int is_loop_target : 1; + unsigned int is_branch_target : 1; +} xtensa_symfield_type; + + +/* Structure for saving information about a block of property data + for frags that have the same flags. The forward reference is + in this header file. The actual definition is in tc-xtensa.c. */ +struct xtensa_block_info_struct; +typedef struct xtensa_block_info_struct xtensa_block_info; + +/* Property section types. */ typedef enum { - xt_insn_sec, xt_literal_sec, + xt_prop_sec, max_xt_sec } xt_section_type; @@ -97,17 +286,9 @@ typedef struct xtensa_segment_info_struct xtensa_block_info *blocks[max_xt_sec]; } xtensa_segment_info; -typedef struct xtensa_symfield_type_struct -{ - unsigned int plt : 1; - unsigned int is_loop_target : 1; - unsigned int is_branch_target : 1; -} xtensa_symfield_type; - /* Section renaming is only supported in Tensilica's version of GAS. */ -#define XTENSA_SECTION_RENAME 1 -#ifdef XTENSA_SECTION_RENAME +#ifdef XTENSA_SECTION_RENAME extern const char *xtensa_section_rename PARAMS ((const char *)); #else @@ -118,10 +299,12 @@ extern const char *xtensa_section_rename extern const char *xtensa_target_format PARAMS ((void)); +extern void xtensa_init_fix_data + PARAMS ((struct fix *)); extern void xtensa_frag_init PARAMS ((fragS *)); -extern void xtensa_cons_fix_new - PARAMS ((fragS *, int, int, expressionS *)); +extern int xtensa_force_relocation + PARAMS ((struct fix *)); extern void xtensa_frob_label PARAMS ((struct symbol *)); extern void xtensa_end @@ -138,19 +321,32 @@ extern void xtensa_symbol_new_hook PARAMS ((symbolS *)); extern long xtensa_relax_frag PARAMS ((fragS *, long, int *)); +extern void xtensa_elf_section_change_hook + PARAMS ((void)); +extern int xtensa_unrecognized_line + PARAMS ((int)); +extern bfd_boolean xtensa_check_inside_bundle + PARAMS ((void)); +extern void xtensa_handle_align + PARAMS ((fragS *)); #define TARGET_FORMAT xtensa_target_format () #define TARGET_ARCH bfd_arch_xtensa #define TC_SEGMENT_INFO_TYPE xtensa_segment_info -#define TC_SYMFIELD_TYPE xtensa_symfield_type +#define TC_SYMFIELD_TYPE struct xtensa_symfield_type +#define TC_FIX_TYPE xtensa_fix_data +#define TC_INIT_FIX_DATA(x) xtensa_init_fix_data (x) #define TC_FRAG_TYPE struct xtensa_frag_type #define TC_FRAG_INIT(frag) xtensa_frag_init (frag) -#define TC_CONS_FIX_NEW xtensa_cons_fix_new +#define TC_FORCE_RELOCATION(fix) xtensa_force_relocation (fix) +#define NO_PSEUDO_DOT xtensa_check_inside_bundle () #define tc_canonicalize_symbol_name(s) xtensa_section_rename (s) #define tc_init_after_args() xtensa_file_arch_init (stdoutput) #define tc_fix_adjustable(fix) xtensa_fix_adjustable (fix) #define tc_frob_label(sym) xtensa_frob_label (sym) -#define tc_symbol_new_hook(s) xtensa_symbol_new_hook (s) +#define tc_unrecognized_line(ch) xtensa_unrecognized_line (ch) +#define md_do_align(a,b,c,d,e) xtensa_flush_pending_output () +#define md_elf_section_change_hook xtensa_elf_section_change_hook #define md_elf_section_rename(name) xtensa_section_rename (name) #define md_end xtensa_end #define md_flush_pending_output() xtensa_flush_pending_output () @@ -158,6 +354,7 @@ extern long xtensa_relax_frag #define TEXT_SECTION_NAME xtensa_section_rename (".text") #define DATA_SECTION_NAME xtensa_section_rename (".data") #define BSS_SECTION_NAME xtensa_section_rename (".bss") +#define HANDLE_ALIGN(fragP) xtensa_handle_align (fragP) /* The renumber_section function must be mapped over all the sections @@ -188,7 +385,66 @@ extern long xtensa_relax_frag #define DOUBLESLASH_LINE_COMMENTS #define TC_HANDLES_FX_DONE #define TC_FINALIZE_SYMS_BEFORE_SIZE_SEG 0 - +#define TC_LINKRELAX_FIXUP(SEG) 0 #define MD_APPLY_SYM_VALUE(FIX) 0 +#define SUB_SEGMENT_ALIGN(SEG, FRCHAIN) 0 + + +/* Resource reservation info functions. */ + +/* Returns the number of copies of a particular unit. */ +typedef int (*unit_num_copies_func) (void *, xtensa_funcUnit); + +/* Returns the number of units the opcode uses. */ +typedef int (*opcode_num_units_func) (void *, xtensa_opcode); + +/* Given an opcode and an index into the opcode's funcUnit list, + returns the unit used for the index. */ +typedef int (*opcode_funcUnit_use_unit_func) (void *, xtensa_opcode, int); + +/* Given an opcode and an index into the opcode's funcUnit list, + returns the cycle during which the unit is used. */ +typedef int (*opcode_funcUnit_use_stage_func) (void *, xtensa_opcode, int); + +/* The above typedefs parameterize the resource_table so that the + optional scheduler doesn't need its own resource reservation system. + + For simple resource checking, which is all that happens normally, + the functions will be as follows (with some wrapping to make the + interface more convenient): + + unit_num_copies_func = xtensa_funcUnit_num_copies + opcode_num_units_func = xtensa_opcode_num_funcUnit_uses + opcode_funcUnit_use_unit_func = xtensa_opcode_funcUnit_use->unit + opcode_funcUnit_use_stage_func = xtensa_opcode_funcUnit_use->stage + + Of course the optional scheduler has its own reservation table + and functions. */ + +int opcode_funcUnit_use_unit PARAMS ((void *, xtensa_opcode, int)); +int opcode_funcUnit_use_stage PARAMS ((void *, xtensa_opcode, int)); + +typedef struct +{ + void *data; + int cycles; + int allocated_cycles; + int num_units; + unit_num_copies_func unit_num_copies; + opcode_num_units_func opcode_num_units; + opcode_funcUnit_use_unit_func opcode_unit_use; + opcode_funcUnit_use_stage_func opcode_unit_stage; + char **units; +} resource_table; + +resource_table *new_resource_table + PARAMS ((void *, int, int, unit_num_copies_func, opcode_num_units_func, + opcode_funcUnit_use_unit_func, opcode_funcUnit_use_stage_func)); +void resize_resource_table PARAMS ((resource_table *, int)); +void clear_resource_table PARAMS ((resource_table *)); +bfd_boolean resources_available + PARAMS ((resource_table *, xtensa_opcode, int)); +void reserve_resources PARAMS ((resource_table *, xtensa_opcode, int)); +void release_resources PARAMS ((resource_table *, xtensa_opcode, int)); #endif /* TC_XTENSA */ diff --git a/gas/config/xtensa-istack.h b/gas/config/xtensa-istack.h index a1cca2ea702..bb9f989e374 100644 --- a/gas/config/xtensa-istack.h +++ b/gas/config/xtensa-istack.h @@ -1,5 +1,5 @@ /* Declarations for stacks of tokenized Xtensa instructions. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -21,10 +21,11 @@ #ifndef XTENSA_ISTACK_H #define XTENSA_ISTACK_H +#include "dwarf2dbg.h" #include "xtensa-isa.h" #define MAX_ISTACK 12 -#define MAX_INSN_ARGS 6 +#define MAX_INSN_ARGS 10 enum itype_enum { @@ -40,11 +41,25 @@ enum itype_enum typedef struct tinsn_struct { enum itype_enum insn_type; - - bfd_boolean is_specific_opcode; + xtensa_opcode opcode; /* Literals have an invalid opcode. */ + bfd_boolean is_specific_opcode; + bfd_boolean keep_wide; int ntok; expressionS tok[MAX_INSN_ARGS]; + struct dwarf2_line_info loc; + + struct fixP *fixup; + + /* Filled out by relaxation_requirements: */ + bfd_boolean record_fix; + enum xtensa_relax_statesE subtype; + int literal_space; + /* Filled out by vinsn_to_insnbuf: */ + symbolS *symbol; + symbolS *sub_symbol; + offsetT offset; + fragS *literal_frag; } TInsn; @@ -57,17 +72,29 @@ typedef struct tinsn_stack } IStack; -void istack_init PARAMS ((IStack *)); -bfd_boolean istack_empty PARAMS ((IStack *)); -bfd_boolean istack_full PARAMS ((IStack *)); -TInsn * istack_top PARAMS ((IStack *)); -void istack_push PARAMS ((IStack *, TInsn *)); -TInsn * istack_push_space PARAMS ((IStack *)); -void istack_pop PARAMS ((IStack *)); +void istack_init PARAMS ((IStack *)); +bfd_boolean istack_empty PARAMS ((IStack *)); +bfd_boolean istack_full PARAMS ((IStack *)); +TInsn *istack_top PARAMS ((IStack *)); +void istack_push PARAMS ((IStack *, TInsn *)); +TInsn *istack_push_space PARAMS ((IStack *)); +void istack_pop PARAMS ((IStack *)); /* TInsn utilities. */ -void tinsn_init PARAMS ((TInsn *)); -void tinsn_copy PARAMS ((TInsn *, const TInsn *)); -expressionS *tinsn_get_tok PARAMS ((TInsn *, int)); +void tinsn_init PARAMS ((TInsn *)); +expressionS *tinsn_get_tok PARAMS ((TInsn *, int)); + + +/* vliw_insn: bundles of TInsns. */ + +typedef struct vliw_insn +{ + xtensa_format format; + xtensa_insnbuf insnbuf; + int num_slots; + unsigned int inside_bundle; + TInsn slots[MAX_SLOTS]; + xtensa_insnbuf slotbuf[MAX_SLOTS]; +} vliw_insn; #endif /* !XTENSA_ISTACK_H */ diff --git a/gas/config/xtensa-relax.c b/gas/config/xtensa-relax.c index 49a93b20e05..4d2d01ac28f 100644 --- a/gas/config/xtensa-relax.c +++ b/gas/config/xtensa-relax.c @@ -1,5 +1,5 @@ /* Table of relaxations for Xtensa assembly. - Copyright 2003 Free Software Foundation, Inc. + Copyright 2003, 2004 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -23,20 +23,28 @@ Each action contains an instruction pattern to match and preconditions for the match as well as an expansion if the pattern matches. The preconditions can specify that two operands are the - same or an operand is a specific constant. The expansion uses the - bound variables from the pattern to specify that specific operands - from the pattern should be used in the result. + same or an operand is a specific constant or register. The expansion + uses the bound variables from the pattern to specify that specific + operands from the pattern should be used in the result. + + The code determines whether the condition applies to a constant or + a register depending on the type of the operand. You may get + unexpected results if you don't match the rule against the operand + type correctly. The patterns match a language like: - INSN_PATTERN ::= INSN_TEMPL ( '|' PRECOND )* + INSN_PATTERN ::= INSN_TEMPL ( '|' PRECOND )* ( '?' OPTIONPRED )* INSN_TEMPL ::= OPCODE ' ' [ OPERAND (',' OPERAND)* ] OPCODE ::= id OPERAND ::= CONSTANT | VARIABLE | SPECIALFN '(' VARIABLE ')' SPECIALFN ::= 'HI24S' | 'F32MINUS' | 'LOW8' + | 'HI16' | 'LOW16' VARIABLE ::= '%' id PRECOND ::= OPERAND CMPOP OPERAND CMPOP ::= '==' | '!=' + OPTIONPRED ::= OPTIONNAME ('+' OPTIONNAME) + OPTIONNAME ::= '"' id '"' The replacement language INSN_REPL ::= INSN_LABEL_LIT ( ';' INSN_LABEL_LIT )* @@ -47,6 +55,13 @@ The operands in a PRECOND must be constants or variables bound by the INSN_PATTERN. + The configuration options define a predicate on the availability of + options which must be TRUE for this rule to be valid. Examples are + requiring "density" for replacements with density instructions, + requiring "const16" for replacements that require const16 + instructions, etc. The names are interpreted by the assembler to a + truth value for a particular frag. + The operands in the INSN_REPL must be constants, variables bound in the associated INSN_PATTERN, special variables that are bound in the INSN_REPL by LABEL or LITERAL definitions, or special value @@ -84,11 +99,11 @@ #include "xtensa-isa.h" #include "xtensa-relax.h" #include +#include "xtensa-config.h" /* Imported from bfd. */ extern xtensa_isa xtensa_default_isa; - /* The opname_list is a small list of names that we use for opcode and operand variable names to simplify ownership of these commonly used strings. Strings entered in the table can be compared by pointer @@ -115,7 +130,7 @@ typedef struct opname_map_struct opname_map; struct opname_map_e_struct { const char *operand_name; /* If null, then use constant_value. */ - size_t operand_num; + int operand_num; unsigned constant_value; opname_map_e *next; }; @@ -173,6 +188,7 @@ struct insn_pattern_struct { insn_templ t; precond_list preconds; + ReqOptionList *options; }; @@ -202,7 +218,7 @@ typedef struct split_rec_struct split_rec; struct split_rec_struct { char **vec; - size_t count; + int count; }; /* The "string_pattern_pair" is a set of pairs containing instruction @@ -231,93 +247,113 @@ struct string_pattern_pair_struct static string_pattern_pair widen_spec_list[] = { - {"add.n %ar,%as,%at", "add %ar,%as,%at"}, - {"addi.n %ar,%as,%imm", "addi %ar,%as,%imm"}, - {"beqz.n %as,%label", "beqz %as,%label"}, - {"bnez.n %as,%label", "bnez %as,%label"}, - {"l32i.n %at,%as,%imm", "l32i %at,%as,%imm"}, - {"mov.n %at,%as", "or %at,%as,%as"}, - {"movi.n %as,%imm", "movi %as,%imm"}, - {"nop.n", "or 1,1,1"}, - {"ret.n", "ret"}, - {"retw.n", "retw"}, - {"s32i.n %at,%as,%imm", "s32i %at,%as,%imm"}, + {"add.n %ar,%as,%at ? IsaUseDensityInstruction", "add %ar,%as,%at"}, + {"addi.n %ar,%as,%imm ? IsaUseDensityInstruction", "addi %ar,%as,%imm"}, + {"beqz.n %as,%label ? IsaUseDensityInstruction", "beqz %as,%label"}, + {"bnez.n %as,%label ? IsaUseDensityInstruction", "bnez %as,%label"}, + {"l32i.n %at,%as,%imm ? IsaUseDensityInstruction", "l32i %at,%as,%imm"}, + {"mov.n %at,%as ? IsaUseDensityInstruction", "or %at,%as,%as"}, + {"movi.n %as,%imm ? IsaUseDensityInstruction", "movi %as,%imm"}, + {"nop.n ? IsaUseDensityInstruction ? realnop", "nop"}, + {"nop.n ? IsaUseDensityInstruction ? no-realnop", "or 1,1,1"}, + {"ret.n %as ? IsaUseDensityInstruction", "ret %as"}, + {"retw.n %as ? IsaUseDensityInstruction", "retw %as"}, + {"s32i.n %at,%as,%imm ? IsaUseDensityInstruction", "s32i %at,%as,%imm"}, {"srli %at,%as,%imm", "extui %at,%as,%imm,F32MINUS(%imm)"}, {"slli %ar,%as,0", "or %ar,%as,%as"}, - /* Widening with literals */ - {"movi %at,%imm", "LITERAL0 %imm; l32r %at,%LITERAL0"}, + + /* Widening with literals or const16. */ + {"movi %at,%imm ? IsaUseL32R ", + "LITERAL0 %imm; l32r %at,%LITERAL0"}, + {"movi %at,%imm ? IsaUseConst16", + "const16 %at,HI16U(%imm); const16 %at,LOW16U(%imm)"}, + {"addi %ar,%as,%imm", "addmi %ar,%as,%imm"}, /* LOW8 is the low 8 bits of the Immed MID8S is the middle 8 bits of the Immed */ {"addmi %ar,%as,%imm", "addmi %ar,%as,HI24S(%imm); addi %ar,%ar,LOW8(%imm)"}, - {"addmi %ar,%as,%imm | %ar!=%as", + + /* In the end convert to either an l32r or const16. */ + {"addmi %ar,%as,%imm | %ar!=%as ? IsaUseL32R", "LITERAL0 %imm; l32r %ar,%LITERAL0; add %ar,%as,%ar"}, + {"addmi %ar,%as,%imm | %ar!=%as ? IsaUseConst16", + "const16 %ar,HI16U(%imm); const16 %ar,LOW16U(%imm); add %ar,%as,%ar"}, /* Widening the load instructions with too-large immediates */ - {"l8ui %at,%as,%imm | %at!=%as", + {"l8ui %at,%as,%imm | %at!=%as ? IsaUseL32R", "LITERAL0 %imm; l32r %at,%LITERAL0; add %at,%at,%as; l8ui %at,%at,0"}, - {"l16si %at,%as,%imm | %at!=%as", + {"l16si %at,%as,%imm | %at!=%as ? IsaUseL32R", "LITERAL0 %imm; l32r %at,%LITERAL0; add %at,%at,%as; l16si %at,%at,0"}, - {"l16ui %at,%as,%imm | %at!=%as", + {"l16ui %at,%as,%imm | %at!=%as ? IsaUseL32R", "LITERAL0 %imm; l32r %at,%LITERAL0; add %at,%at,%as; l16ui %at,%at,0"}, + {"l32i %at,%as,%imm | %at!=%as ? IsaUseL32R", + "LITERAL0 %imm; l32r %at,%LITERAL0; add %at,%at,%as; l32i %at,%at,0"}, + + /* Widening load instructions with const16s. */ + {"l8ui %at,%as,%imm | %at!=%as ? IsaUseConst16", + "const16 %at,HI16U(%imm); const16 %at,LOW16U(%imm); add %at,%at,%as; l8ui %at,%at,0"}, + {"l16si %at,%as,%imm | %at!=%as ? IsaUseConst16", + "const16 %at,HI16U(%imm); const16 %at,LOW16U(%imm); add %at,%at,%as; l16si %at,%at,0"}, + {"l16ui %at,%as,%imm | %at!=%as ? IsaUseConst16", + "const16 %at,HI16U(%imm); const16 %at,LOW16U(%imm); add %at,%at,%as; l16ui %at,%at,0"}, + {"l32i %at,%as,%imm | %at!=%as ? IsaUseConst16", + "const16 %at,HI16U(%imm); const16 %at,LOW16U(%imm); add %at,%at,%as; l32i %at,%at,0"}, + #if 0 /* Xtensa Synchronization Option not yet available */ - {"l32ai %at,%as,%imm", + {"l32ai %at,%as,%imm ? IsaUseL32R", "LITERAL0 %imm; l32r %at,%LITERAL0; add.n %at,%at,%as; l32ai %at,%at,0"}, #endif #if 0 /* Xtensa Speculation Option not yet available */ - {"l32is %at,%as,%imm", + {"l32is %at,%as,%imm ? IsaUseL32R", "LITERAL0 %imm; l32r %at,%LITERAL0; add.n %at,%at,%as; l32is %at,%at,0"}, #endif - {"l32i %at,%as,%imm | %at!=%as", - "LITERAL0 %imm; l32r %at,%LITERAL0; add %at,%at,%as; l32i %at,%at,0"}, - /* This is only PART of the loop instruction. In addition, hard - coded into it's use is a modification of the final operand in the - instruction in bytes 9 and 12. */ - {"loop %as,%label", + /* This is only PART of the loop instruction. In addition, + hardcoded into its use is a modification of the final operand in + the instruction in bytes 9 and 12. */ + {"loop %as,%label | %as!=1 ? IsaUseLoops", "loop %as,%LABEL0;" - "rsr %as, 1;" /* LEND */ - "wsr %as, 0;" /* LBEG */ + "rsr.lend %as;" /* LEND */ + "wsr.lbeg %as;" /* LBEG */ "addi %as, %as, 0;" /* lo8(%label-%LABEL1) */ "addmi %as, %as, 0;" /* mid8(%label-%LABEL1) */ - "wsr %as, 1;" + "wsr.lend %as;" "isync;" - "rsr %as, 2;" /* LCOUNT */ + "rsr.lcount %as;" /* LCOUNT */ "addi %as, %as, 1;" /* density -> addi.n %as, %as, 1 */ "LABEL0"}, - {"loopgtz %as,%label", - "beqz %as,%label;" - "bltz %as,%label;" + {"loopgtz %as,%label | %as!=1 ? IsaUseLoops", + "beqz %as,%label;" + "bltz %as,%label;" "loopgtz %as,%LABEL0;" - "rsr %as, 1;" /* LEND */ - "wsr %as, 0;" /* LBEG */ + "rsr.lend %as;" /* LEND */ + "wsr.lbeg %as;" /* LBEG */ "addi %as, %as, 0;" /* lo8(%label-%LABEL1) */ "addmi %as, %as, 0;" /* mid8(%label-%LABEL1) */ - "wsr %as, 1;" + "wsr.lend %as;" "isync;" - "rsr %as, 2;" /* LCOUNT */ + "rsr.lcount %as;" /* LCOUNT */ "addi %as, %as, 1;" /* density -> addi.n %as, %as, 1 */ "LABEL0"}, - {"loopnez %as,%label", + {"loopnez %as,%label | %as!=1 ? IsaUseLoops", "beqz %as,%label;" "loopnez %as,%LABEL0;" - "rsr %as, 1;" /* LEND */ - "wsr %as, 0;" /* LBEG */ + "rsr.lend %as;" /* LEND */ + "wsr.lbeg %as;" /* LBEG */ "addi %as, %as, 0;" /* lo8(%label-%LABEL1) */ "addmi %as, %as, 0;" /* mid8(%label-%LABEL1) */ - "wsr %as, 1;" + "wsr.lend %as;" "isync;" - "rsr %as, 2;" /* LCOUNT */ + "rsr.lcount %as;" /* LCOUNT */ "addi %as, %as, 1;" /* density -> addi.n %as, %as, 1 */ "LABEL0"}, -#if 0 /* no mechanism here to determine if Density Option is available */ - {"beqz %as,%label", "bnez.n %as,%LABEL0;j %label;LABEL0"}, - {"bnez %as,%label", "beqz.n %as,%LABEL0;j %label;LABEL0"}, -#else + {"beqz %as,%label ? IsaUseDensityInstruction", "bnez.n %as,%LABEL0;j %label;LABEL0"}, + {"bnez %as,%label ? IsaUseDensityInstruction", "beqz.n %as,%LABEL0;j %label;LABEL0"}, {"beqz %as,%label", "bnez %as,%LABEL0;j %label;LABEL0"}, {"bnez %as,%label", "beqz %as,%LABEL0;j %label;LABEL0"}, -#endif + {"beqzt %as,%label ? IsaUsePredictedBranches", "bnez %as,%LABEL0;j %label;LABEL0"}, + {"bnezt %as,%label ? IsaUsePredictedBranches", "beqz %as,%LABEL0;j %label;LABEL0"}, {"bgez %as,%label", "bltz %as,%LABEL0;j %label;LABEL0"}, {"bltz %as,%label", "bgez %as,%LABEL0;j %label;LABEL0"}, @@ -331,24 +367,42 @@ static string_pattern_pair widen_spec_list[] = {"bbsi %as,%imm,%label", "bbci %as,%imm,%LABEL0;j %label;LABEL0"}, {"beq %as,%at,%label", "bne %as,%at,%LABEL0;j %label;LABEL0"}, {"bne %as,%at,%label", "beq %as,%at,%LABEL0;j %label;LABEL0"}, + {"beqt %as,%at,%label ? IsaUsePredictedBranches", "bne %as,%at,%LABEL0;j %label;LABEL0"}, + {"bnet %as,%at,%label ? IsaUsePredictedBranches", "beq %as,%at,%LABEL0;j %label;LABEL0"}, {"bge %as,%at,%label", "blt %as,%at,%LABEL0;j %label;LABEL0"}, {"blt %as,%at,%label", "bge %as,%at,%LABEL0;j %label;LABEL0"}, {"bgeu %as,%at,%label", "bltu %as,%at,%LABEL0;j %label;LABEL0"}, {"bltu %as,%at,%label", "bgeu %as,%at,%LABEL0;j %label;LABEL0"}, {"bany %as,%at,%label", "bnone %as,%at,%LABEL0;j %label;LABEL0"}, -#if 1 /* provide relaxations for Boolean Option */ - {"bt %bs,%label", "bf %bs,%LABEL0;j %label;LABEL0"}, - {"bf %bs,%label", "bt %bs,%LABEL0;j %label;LABEL0"}, -#endif + + {"bt %bs,%label ? IsaUseBooleans", "bf %bs,%LABEL0;j %label;LABEL0"}, + {"bf %bs,%label ? IsaUseBooleans", "bt %bs,%LABEL0;j %label;LABEL0"}, + {"bnone %as,%at,%label", "bany %as,%at,%LABEL0;j %label;LABEL0"}, {"ball %as,%at,%label", "bnall %as,%at,%LABEL0;j %label;LABEL0"}, {"bnall %as,%at,%label", "ball %as,%at,%LABEL0;j %label;LABEL0"}, {"bbc %as,%at,%label", "bbs %as,%at,%LABEL0;j %label;LABEL0"}, {"bbs %as,%at,%label", "bbc %as,%at,%LABEL0;j %label;LABEL0"}, - {"call0 %label", "LITERAL0 %label; l32r a0,%LITERAL0; callx0 a0"}, - {"call4 %label", "LITERAL0 %label; l32r a4,%LITERAL0; callx4 a4"}, - {"call8 %label", "LITERAL0 %label; l32r a8,%LITERAL0; callx8 a8"}, - {"call12 %label", "LITERAL0 %label; l32r a12,%LITERAL0; callx12 a12"} + + /* Expanding calls with literals. */ + {"call0 %label,%ar0 ? IsaUseL32R", + "LITERAL0 %label; l32r a0,%LITERAL0; callx0 a0,%ar0"}, + {"call4 %label,%ar4 ? IsaUseL32R", + "LITERAL0 %label; l32r a4,%LITERAL0; callx4 a4,%ar4"}, + {"call8 %label,%ar8 ? IsaUseL32R", + "LITERAL0 %label; l32r a8,%LITERAL0; callx8 a8,%ar8"}, + {"call12 %label,%ar12 ? IsaUseL32R", + "LITERAL0 %label; l32r a12,%LITERAL0; callx12 a12,%ar12"}, + + /* Expanding calls with const16. */ + {"call0 %label,%ar0 ? IsaUseConst16", + "const16 a0,HI16U(%label); const16 a0,LOW16U(%label); callx0 a0,%ar0"}, + {"call4 %label,%ar4 ? IsaUseConst16", + "const16 a4,HI16U(%label); const16 a4,LOW16U(%label); callx4 a4,%ar4"}, + {"call8 %label,%ar8 ? IsaUseConst16", + "const16 a8,HI16U(%label); const16 a8,LOW16U(%label); callx8 a8,%ar8"}, + {"call12 %label,%ar12 ? IsaUseConst16", + "const16 a12,HI16U(%label); const16 a12,LOW16U(%label); callx12 a12,%ar12"} }; #define WIDEN_COUNT (sizeof (widen_spec_list) / sizeof (string_pattern_pair)) @@ -366,20 +420,22 @@ static string_pattern_pair widen_spec_list[] = string_pattern_pair simplify_spec_list[] = { - {"add %ar,%as,%at", "add.n %ar,%as,%at"}, - {"addi.n %ar,%as,0", "mov.n %ar,%as"}, - {"addi %ar,%as,0", "mov.n %ar,%as"}, - {"addi %ar,%as,%imm", "addi.n %ar,%as,%imm"}, - {"addmi %ar,%as,%imm", "addi.n %ar,%as,%imm"}, - {"beqz %as,%label", "beqz.n %as,%label"}, - {"bnez %as,%label", "bnez.n %as,%label"}, - {"l32i %at,%as,%imm", "l32i.n %at,%as,%imm"}, - {"movi %as,%imm", "movi.n %as,%imm"}, - {"or %ar,%as,%at | %as==%at", "mov.n %ar,%as"}, - {"ret", "ret.n"}, - {"retw", "retw.n"}, - {"s32i %at,%as,%imm", "s32i.n %at,%as,%imm"}, - {"slli %ar,%as,0", "mov.n %ar,%as"} + {"add %ar,%as,%at ? IsaUseDensityInstruction", "add.n %ar,%as,%at"}, + {"addi.n %ar,%as,0 ? IsaUseDensityInstruction", "mov.n %ar,%as"}, + {"addi %ar,%as,0 ? IsaUseDensityInstruction", "mov.n %ar,%as"}, + {"addi %ar,%as,%imm ? IsaUseDensityInstruction", "addi.n %ar,%as,%imm"}, + {"addmi %ar,%as,%imm ? IsaUseDensityInstruction", "addi.n %ar,%as,%imm"}, + {"beqz %as,%label ? IsaUseDensityInstruction", "beqz.n %as,%label"}, + {"bnez %as,%label ? IsaUseDensityInstruction", "bnez.n %as,%label"}, + {"l32i %at,%as,%imm ? IsaUseDensityInstruction", "l32i.n %at,%as,%imm"}, + {"movi %as,%imm ? IsaUseDensityInstruction", "movi.n %as,%imm"}, + {"nop ? realnop ? IsaUseDensityInstruction", "nop.n"}, + {"or %ar,%as,%at | %ar==%as | %as==%at ? IsaUseDensityInstruction", "nop.n"}, + {"or %ar,%as,%at | %ar!=%as | %as==%at ? IsaUseDensityInstruction", "mov.n %ar,%as"}, + {"ret %as ? IsaUseDensityInstruction", "ret.n %as"}, + {"retw %as ? IsaUseDensityInstruction", "retw.n %as"}, + {"s32i %at,%as,%imm ? IsaUseDensityInstruction", "s32i.n %at,%as,%imm"}, + {"slli %ar,%as,0 ? IsaUseDensityInstruction", "mov.n %ar,%as"} }; #define SIMPLIFY_COUNT \ @@ -389,7 +445,8 @@ string_pattern_pair simplify_spec_list[] = /* Transition generation helpers. */ static void append_transition - PARAMS ((TransitionTable *, xtensa_opcode, TransitionRule *)); + PARAMS ((TransitionTable *, xtensa_opcode, TransitionRule *, + transition_cmp_fn)); static void append_condition PARAMS ((TransitionRule *, Precondition *)); static void append_value_condition @@ -416,6 +473,10 @@ static long operand_function_F32MINUS PARAMS ((long)); static long operand_function_LOW8 PARAMS ((long)); +static long operand_function_LOW16U + PARAMS ((long)); +static long operand_function_HI16U + PARAMS ((long)); /* Externally visible functions. */ @@ -427,7 +488,7 @@ extern long xg_apply_userdef_op_fn /* Parsing helpers. */ static const char *enter_opname_n - PARAMS ((const char *, size_t)); + PARAMS ((const char *, int)); static const char *enter_opname PARAMS ((const char *)); @@ -457,6 +518,14 @@ static void init_split_rec PARAMS ((split_rec *)); static void clear_split_rec PARAMS ((split_rec *)); +static void clear_req_or_option_list + PARAMS ((ReqOrOption **)); +static void clear_req_option_list + PARAMS ((ReqOption **)); +static ReqOrOption *clone_req_or_option_list + PARAMS ((ReqOrOption *)); +static ReqOption *clone_req_option_list + PARAMS ((ReqOption *)); /* Operand and insn_templ helpers. */ @@ -468,10 +537,10 @@ static bfd_boolean op_is_constant PARAMS ((const opname_map_e *)); static unsigned op_get_constant PARAMS ((const opname_map_e *)); -static size_t insn_templ_operand_count +static int insn_templ_operand_count PARAMS ((const insn_templ *)); -/* parsing helpers. */ +/* Parsing helpers. */ static const char *skip_white PARAMS ((const char *)); @@ -496,24 +565,29 @@ static bfd_boolean parse_constant PARAMS ((const char *, unsigned *)); static bfd_boolean parse_id_constant PARAMS ((const char *, const char *, unsigned *)); +static bfd_boolean parse_option_cond + PARAMS ((const char *, ReqOption *)); /* Transition table building code. */ +static bfd_boolean transition_applies + PARAMS ((insn_pattern *, const char *, const char *)); static TransitionRule *build_transition PARAMS ((insn_pattern *, insn_repl *, const char *, const char *)); static TransitionTable *build_transition_table - PARAMS ((const string_pattern_pair *, size_t)); + PARAMS ((const string_pattern_pair *, int, transition_cmp_fn)); void -append_transition (tt, opcode, t) +append_transition (tt, opcode, t, cmp) TransitionTable *tt; xtensa_opcode opcode; TransitionRule *t; + transition_cmp_fn cmp; { TransitionList *tl = (TransitionList *) xmalloc (sizeof (TransitionList)); TransitionList *prev; - TransitionList *nxt; + TransitionList **t_p; assert (tt != NULL); assert (opcode < tt->num_opcodes); @@ -525,13 +599,18 @@ append_transition (tt, opcode, t) tt->table[opcode] = tl; return; } - nxt = prev->next; - while (nxt != NULL) + + for (t_p = &tt->table[opcode]; (*t_p) != NULL; t_p = &(*t_p)->next) { - prev = nxt; - nxt = nxt->next; + if (cmp && cmp (t, (*t_p)->rule) < 0) + { + /* Insert it here. */ + tl->next = *t_p; + *t_p = tl; + return; + } } - prev->next = tl; + (*t_p) = tl; } @@ -759,6 +838,23 @@ operand_function_LOW8 (a) } +long +operand_function_LOW16U (a) + long a; +{ + return (a & 0xffff); +} + + +long +operand_function_HI16U (a) + long a; +{ + unsigned long b = a & 0xffff0000; + return (long) (b >> 16); +} + + bfd_boolean xg_has_userdef_op_fn (op) OpType op; @@ -768,6 +864,8 @@ xg_has_userdef_op_fn (op) case OP_OPERAND_F32MINUS: case OP_OPERAND_LOW8: case OP_OPERAND_HI24S: + case OP_OPERAND_LOW16U: + case OP_OPERAND_HI16U: return TRUE; default: break; @@ -789,6 +887,10 @@ xg_apply_userdef_op_fn (op, a) return operand_function_LOW8 (a); case OP_OPERAND_HI24S: return operand_function_HI24S (a); + case OP_OPERAND_LOW16U: + return operand_function_LOW16U (a); + case OP_OPERAND_HI16U: + return operand_function_HI16U (a); default: break; } @@ -801,13 +903,14 @@ xg_apply_userdef_op_fn (op, a) const char * enter_opname_n (name, len) const char *name; - size_t len; + int len; { opname_e *op; for (op = local_opnames; op != NULL; op = op->next) { - if (strlen (op->opname) == len && strncmp (op->opname, name, len) == 0) + if (strlen (op->opname) == (unsigned) len + && strncmp (op->opname, name, len) == 0) return op->opname; } op = (opname_e *) xmalloc (sizeof (opname_e)); @@ -830,7 +933,7 @@ enter_opname (name) return op->opname; } op = (opname_e *) xmalloc (sizeof (opname_e)); - op->opname = strdup (name); + op->opname = xstrdup (name); return op->opname; } @@ -952,6 +1055,7 @@ init_insn_pattern (p) { init_insn_templ (&p->t); init_precond_list (&p->preconds); + p->options = NULL; } @@ -989,14 +1093,14 @@ clear_insn_repl (r) } -static size_t +static int insn_templ_operand_count (t) const insn_templ *t; { - size_t i = 0; + int i = 0; const opname_map_e *op; - for (op = t->operand_map.head; op != NULL; op = op->next, ++i) + for (op = t->operand_map.head; op != NULL; op = op->next, i++) ; return i; } @@ -1131,8 +1235,8 @@ split_string (rec, in, c, elide_whitespace) char c; bfd_boolean elide_whitespace; { - size_t cnt = 0; - size_t i; + int cnt = 0; + int i; const char *p = in; while (p != NULL && *p != '\0') @@ -1156,7 +1260,7 @@ split_string (rec, in, c, elide_whitespace) for (i = 0; i < cnt; i++) { const char *q; - size_t len; + int len; q = p; if (elide_whitespace) @@ -1164,7 +1268,7 @@ split_string (rec, in, c, elide_whitespace) p = strchr (q, c); if (p == NULL) - rec->vec[i] = strdup (q); + rec->vec[i] = xstrdup (q); else { len = p - q; @@ -1184,9 +1288,9 @@ void clear_split_rec (rec) split_rec *rec; { - size_t i; + int i; - for (i = 0; i < rec->count; ++i) + for (i = 0; i < rec->count; i++) free (rec->vec[i]); if (rec->count > 0) @@ -1194,6 +1298,9 @@ clear_split_rec (rec) } +/* Initialize a split record. The split record must be initialized + before split_string is called. */ + void init_split_rec (rec) split_rec *rec; @@ -1211,10 +1318,11 @@ parse_insn_templ (s, t) insn_templ *t; { const char *p = s; - /* First find the first whitespace. */ - size_t insn_name_len; + int insn_name_len; split_rec oprec; - size_t i; + int i; + + /* First find the first whitespace. */ init_split_rec (&oprec); @@ -1277,7 +1385,7 @@ parse_precond (s, precond) to identify when density is available. */ const char *p = s; - size_t len; + int len; precond->opname1 = NULL; precond->opval1 = 0; precond->cmpop = OP_EQUAL; @@ -1322,34 +1430,170 @@ parse_precond (s, precond) } +void +clear_req_or_option_list (r_p) + ReqOrOption **r_p; +{ + if (*r_p == NULL) + return; + + free ((*r_p)->option_name); + clear_req_or_option_list (&(*r_p)->next); + *r_p = NULL; +} + + +void +clear_req_option_list (r_p) + ReqOption **r_p; +{ + if (*r_p == NULL) + return; + + clear_req_or_option_list (&(*r_p)->or_option_terms); + clear_req_option_list (&(*r_p)->next); + *r_p = NULL; +} + + +ReqOrOption * +clone_req_or_option_list (req_or_option) + ReqOrOption *req_or_option; +{ + ReqOrOption *new_req_or_option; + + if (req_or_option == NULL) + return NULL; + + new_req_or_option = (ReqOrOption *) xmalloc (sizeof (ReqOrOption)); + new_req_or_option->option_name = xstrdup (req_or_option->option_name); + new_req_or_option->is_true = req_or_option->is_true; + new_req_or_option->next = NULL; + new_req_or_option->next = clone_req_or_option_list (req_or_option->next); + return new_req_or_option; +} + + +ReqOption * +clone_req_option_list (req_option) + ReqOption *req_option; +{ + ReqOption *new_req_option; + + if (req_option == NULL) + return NULL; + + new_req_option = (ReqOption *) xmalloc (sizeof (ReqOption)); + new_req_option->or_option_terms = NULL; + new_req_option->next = NULL; + new_req_option->or_option_terms = + clone_req_or_option_list (req_option->or_option_terms); + new_req_option->next = clone_req_option_list (req_option->next); + return new_req_option; +} + + +bfd_boolean +parse_option_cond (s, option) + const char *s; + ReqOption *option; +{ + int i; + split_rec option_term_rec; + + /* All option or conditions are of the form: + optionA + no-optionB + ... + "Ands" are divided by "?". */ + + init_split_rec (&option_term_rec); + split_string (&option_term_rec, s, '+', TRUE); + + if (option_term_rec.count == 0) + { + clear_split_rec (&option_term_rec); + return FALSE; + } + + for (i = 0; i < option_term_rec.count; i++) + { + char *option_name = option_term_rec.vec[i]; + bfd_boolean is_true = TRUE; + ReqOrOption *req; + ReqOrOption **r_p; + + if (strncmp (option_name, "no-", 3) == 0) + { + option_name = xstrdup (&option_name[3]); + is_true = FALSE; + } + else + option_name = xstrdup (option_name); + + req = (ReqOrOption *) xmalloc (sizeof (ReqOrOption)); + req->option_name = option_name; + req->is_true = is_true; + req->next = NULL; + + /* Append to list. */ + for (r_p = &option->or_option_terms; (*r_p) != NULL; + r_p = &(*r_p)->next) + ; + (*r_p) = req; + } + return TRUE; +} + + /* Parse a string like: "insn op1, op2, op3, op4 | op1 != op2 | op2 == op3 | op4 == 1". I.E., instruction "insn" with 4 operands where operand 1 and 2 are not - the same and operand 2 and 3 are the same and operand 4 is 1. */ + the same and operand 2 and 3 are the same and operand 4 is 1. + + or: + + "insn op1 | op1 == 1 / density + boolean / no-useroption". + i.e. instruction "insn" with 1 operands where operand 1 is 1 + when "density" or "boolean" options are available and + "useroption" is not available. + + Because the current implementation of this parsing scheme uses + split_string, it requires that '|' and '?' are only used as + delimiters for predicates and required options. */ bfd_boolean parse_insn_pattern (in, insn) const char *in; insn_pattern *insn; { - split_rec rec; - size_t i; + split_rec optionrec; + int i; - init_split_rec (&rec); init_insn_pattern (insn); - split_string (&rec, in, '|', TRUE); + init_split_rec (&optionrec); + split_string (&optionrec, in, '?', TRUE); + if (optionrec.count == 0) + { + clear_split_rec (&optionrec); + return FALSE; + } + + init_split_rec (&rec); + + split_string (&rec, optionrec.vec[0], '|', TRUE); if (rec.count == 0) { clear_split_rec (&rec); + clear_split_rec (&optionrec); return FALSE; } if (!parse_insn_templ (rec.vec[0], &insn->t)) { clear_split_rec (&rec); + clear_split_rec (&optionrec); return FALSE; } @@ -1360,6 +1604,7 @@ parse_insn_pattern (in, insn) if (!parse_precond (rec.vec[i], cond)) { clear_split_rec (&rec); + clear_split_rec (&optionrec); clear_insn_pattern (insn); return FALSE; } @@ -1369,7 +1614,32 @@ parse_insn_pattern (in, insn) insn->preconds.tail = &cond->next; } + for (i = 1; i < optionrec.count; i++) + { + /* Handle the option conditions. */ + ReqOption **r_p; + ReqOption *req_option = (ReqOption *) xmalloc (sizeof (ReqOption)); + req_option->or_option_terms = NULL; + req_option->next = NULL; + + if (!parse_option_cond (optionrec.vec[i], req_option)) + { + clear_split_rec (&rec); + clear_split_rec (&optionrec); + clear_insn_pattern (insn); + clear_req_option_list (&req_option); + return FALSE; + } + + /* Append the condition. */ + for (r_p = &insn->options; (*r_p) != NULL; r_p = &(*r_p)->next) + ; + + (*r_p) = req_option; + } + clear_split_rec (&rec); + clear_split_rec (&optionrec); return TRUE; } @@ -1381,7 +1651,7 @@ parse_insn_repl (in, r_p) { /* This is a list of instruction templates separated by ';'. */ split_rec rec; - size_t i; + int i; split_string (&rec, in, ';', TRUE); @@ -1404,6 +1674,59 @@ parse_insn_repl (in, r_p) } +bfd_boolean +transition_applies (initial_insn, from_string, to_string) + insn_pattern *initial_insn; + const char *from_string ATTRIBUTE_UNUSED; + const char *to_string ATTRIBUTE_UNUSED; +{ + ReqOption *req_option; + + for (req_option = initial_insn->options; + req_option != NULL; + req_option = req_option->next) + { + ReqOrOption *req_or_option = req_option->or_option_terms; + + if (req_or_option == NULL + || req_or_option->next != NULL) + continue; + + if (strncmp (req_or_option->option_name, "IsaUse", 6) == 0) + { + bfd_boolean option_available = FALSE; + char *option_name = req_or_option->option_name + 6; + if (!strcmp (option_name, "DensityInstruction")) + option_available = (XCHAL_HAVE_DENSITY == 1); + else if (!strcmp (option_name, "L32R")) + option_available = (XCHAL_HAVE_L32R == 1); + else if (!strcmp (option_name, "Const16")) + option_available = (XCHAL_HAVE_CONST16 == 1); + else if (!strcmp (option_name, "Loops")) + option_available = (XCHAL_HAVE_LOOPS == 1); + else if (!strcmp (option_name, "PredictedBranches")) + option_available = (XCHAL_HAVE_PREDICTED_BRANCHES == 1); + else if (!strcmp (option_name, "Booleans")) + option_available = (XCHAL_HAVE_BOOLEANS == 1); + else + as_warn (_("invalid configuration option '%s' in transition rule '%s'"), + req_or_option->option_name, from_string); + if ((option_available ^ req_or_option->is_true) != 0) + return FALSE; + } + else if (strcmp (req_or_option->option_name, "realnop") == 0) + { + bfd_boolean nop_available = + (xtensa_opcode_lookup (xtensa_default_isa, "nop") + != XTENSA_UNDEFINED); + if ((nop_available ^ req_or_option->is_true) != 0) + return FALSE; + } + } + return TRUE; +} + + TransitionRule * build_transition (initial_insn, replace_insns, from_string, to_string) insn_pattern *initial_insn; @@ -1430,15 +1753,15 @@ build_transition (initial_insn, replace_insns, from_string, to_string) { /* It is OK to not be able to translate some of these opcodes. */ #if 0 - as_warn (_("Invalid opcode '%s' in transition rule '%s'\n"), - initial_insn->t.opcode_name, to_string); + as_warn (_("invalid opcode '%s' in transition rule '%s'"), + initial_insn->t.opcode_name, from_string); #endif return NULL; } - if (xtensa_num_operands (isa, opcode) - != (int) insn_templ_operand_count (&initial_insn->t)) + if (xtensa_opcode_num_operands (isa, opcode) + != insn_templ_operand_count (&initial_insn->t)) { /* This is also OK because there are opcodes that have different numbers of operands on different @@ -1531,12 +1854,14 @@ build_transition (initial_insn, replace_insns, from_string, to_string) op1->operand_num, op2->operand_num); else if (op2 == NULL) append_constant_value_condition (tr, precond->cmpop, - op1->operand_num, precond->opval1); + op1->operand_num, precond->opval2); else append_constant_value_condition (tr, precond->cmpop, - op2->operand_num, precond->opval2); + op2->operand_num, precond->opval1); } + tr->options = clone_req_option_list (initial_insn->options); + /* Generate the replacement instructions. Some of these "instructions" are actually labels and literals. The literals must be defined in order 0..n and a literal must be defined @@ -1549,7 +1874,7 @@ build_transition (initial_insn, replace_insns, from_string, to_string) { BuildInstr *bi; const char *opcode_name; - size_t operand_count; + int operand_count; opname_map_e *op; unsigned idnum = 0; const char *fn_name; @@ -1592,12 +1917,17 @@ build_transition (initial_insn, replace_insns, from_string, to_string) bi->typ = INSTR_INSTR; bi->opcode = xtensa_opcode_lookup (isa, r->t.opcode_name); if (bi->opcode == XTENSA_UNDEFINED) - return NULL; + { + as_warn (_("invalid opcode '%s' in transition rule '%s'"), + r->t.opcode_name, to_string); + return NULL; + } /* Check for the right number of ops. */ - if (xtensa_num_operands (isa, bi->opcode) + if (xtensa_opcode_num_operands (isa, bi->opcode) != (int) operand_count) as_fatal (_("opcode '%s': replacement does not have %d ops"), - opcode_name, xtensa_num_operands (isa, bi->opcode)); + opcode_name, + xtensa_opcode_num_operands (isa, bi->opcode)); } for (op = r->t.operand_map.head; op != NULL; op = op->next) @@ -1650,8 +1980,12 @@ build_transition (initial_insn, replace_insns, from_string, to_string) typ = OP_OPERAND_HI24S; else if (strcmp (fn_name, "F32MINUS") == 0) typ = OP_OPERAND_F32MINUS; + else if (strcmp (fn_name, "LOW16U") == 0) + typ = OP_OPERAND_LOW16U; + else if (strcmp (fn_name, "HI16U") == 0) + typ = OP_OPERAND_HI16U; else - as_fatal (_("unknown user defined function %s"), fn_name); + as_fatal (_("unknown user-defined function %s"), fn_name); orig_op = get_opmatch (&initial_insn->t.operand_map, operand_arg_name); @@ -1686,14 +2020,14 @@ build_transition (initial_insn, replace_insns, from_string, to_string) TransitionTable * -build_transition_table (transitions, transition_count) +build_transition_table (transitions, transition_count, cmp) const string_pattern_pair *transitions; - size_t transition_count; + int transition_count; + transition_cmp_fn cmp; { TransitionTable *table = NULL; - int num_opcodes = xtensa_num_opcodes (xtensa_default_isa); - int i; - size_t tnum; + int num_opcodes = xtensa_isa_num_opcodes (xtensa_default_isa); + int i, tnum; if (table != NULL) return table; @@ -1733,10 +2067,20 @@ build_transition_table (transitions, transition_count) continue; } - tr = build_transition (&initial_insn, &replace_insns, - from_string, to_string); - if (tr) - append_transition (table, tr->opcode, tr); + if (transition_applies (&initial_insn, from_string, to_string)) + { + tr = build_transition (&initial_insn, &replace_insns, + from_string, to_string); + if (tr) + append_transition (table, tr->opcode, tr, cmp); + else + { +#if TENSILICA_DEBUG + as_warn (_("could not build transition for %s => %s"), + from_string, to_string); +#endif + } + } clear_insn_repl (&replace_insns); clear_insn_pattern (&initial_insn); @@ -1746,20 +2090,22 @@ build_transition_table (transitions, transition_count) extern TransitionTable * -xg_build_widen_table () +xg_build_widen_table (cmp) + transition_cmp_fn cmp; { static TransitionTable *table = NULL; if (table == NULL) - table = build_transition_table (widen_spec_list, WIDEN_COUNT); + table = build_transition_table (widen_spec_list, WIDEN_COUNT, cmp); return table; } extern TransitionTable * -xg_build_simplify_table () +xg_build_simplify_table (cmp) + transition_cmp_fn cmp; { static TransitionTable *table = NULL; if (table == NULL) - table = build_transition_table (simplify_spec_list, SIMPLIFY_COUNT); + table = build_transition_table (simplify_spec_list, SIMPLIFY_COUNT, cmp); return table; } diff --git a/gas/config/xtensa-relax.h b/gas/config/xtensa-relax.h index 99bf77bfd8e..2a228bce321 100644 --- a/gas/config/xtensa-relax.h +++ b/gas/config/xtensa-relax.h @@ -1,5 +1,5 @@ /* Table of relaxations for Xtensa assembly. - Copyright 2003 Free Software Foundation, Inc. + Copyright 2003, 2004 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -33,6 +33,11 @@ typedef struct transition_rule TransitionRule; typedef struct precondition_list PreconditionList; typedef struct precondition Precondition; +typedef struct req_or_option_list ReqOrOptionList; +typedef struct req_or_option_list ReqOrOption; +typedef struct req_option_list ReqOptionList; +typedef struct req_option_list ReqOption; + struct transition_table { int num_opcodes; @@ -52,6 +57,38 @@ struct precondition_list }; +/* The required options for a rule are represented with a two-level + structure, with leaf expressions combined by logical ORs at the + lower level, and the results then combined by logical ANDs at the + top level. The AND terms are linked in a list, and each one can + contain a reference to a list of OR terms. The leaf expressions, + i.e., the OR options, can be negated by setting the is_true field + to FALSE. There are two classes of leaf expressions: (1) those + that are properties of the Xtensa configuration and can be + evaluated once when building the tables, and (2) those that depend + of the state of directives or other settings that may vary during + the assembly. The following expressions may be used in group (1): + + IsaUse*: Xtensa configuration settings. + realnop: TRUE if the instruction set includes a NOP instruction. + + There are currently no expressions in group (2), but they are still + supported since there is a good chance they'll be needed again for + something. */ + +struct req_option_list +{ + ReqOrOptionList *or_option_terms; + ReqOptionList *next; +}; + +struct req_or_option_list +{ + char *option_name; + bfd_boolean is_true; + ReqOrOptionList *next; +}; + /* Operand types and constraints on operands: */ typedef enum op_type OpType; @@ -62,9 +99,11 @@ enum op_type OP_CONSTANT, OP_OPERAND, OP_OPERAND_LOW8, /* Sign-extended low 8 bits of immed. */ - OP_OPERAND_HI24S, /* high 24 bits of immed, + OP_OPERAND_HI24S, /* High 24 bits of immed, plus 0x100 if low 8 bits are signed. */ OP_OPERAND_F32MINUS, /* 32 - immed. */ + OP_OPERAND_LOW16U, /* Low 16 bits of immed. */ + OP_OPERAND_HI16U, /* High 16 bits of immed. */ OP_LITERAL, OP_LABEL }; @@ -85,6 +124,7 @@ struct precondition int op_data; }; + typedef struct build_op BuildOp; struct build_op @@ -117,7 +157,7 @@ struct build_instr InstrType typ; unsigned id; /* LITERAL_DEF or LABEL_DEF: an ordinal to identify which one. */ - xtensa_opcode opcode; /* unused for LITERAL_DEF or LABEL_DEF. */ + xtensa_opcode opcode; /* Unused for LITERAL_DEF or LABEL_DEF. */ BuildOp *ops; BuildInstr *next; }; @@ -126,17 +166,17 @@ struct transition_rule { xtensa_opcode opcode; PreconditionList *conditions; + ReqOptionList *options; BuildInstr *to_instr; }; -extern TransitionTable *xg_build_simplify_table - PARAMS ((void)); -extern TransitionTable *xg_build_widen_table - PARAMS ((void)); +typedef int (*transition_cmp_fn) (const TransitionRule *, + const TransitionRule *); + +extern TransitionTable *xg_build_simplify_table PARAMS ((transition_cmp_fn)); +extern TransitionTable *xg_build_widen_table PARAMS ((transition_cmp_fn)); -extern bfd_boolean xg_has_userdef_op_fn - PARAMS ((OpType)); -extern long xg_apply_userdef_op_fn - PARAMS ((OpType, long)); +extern bfd_boolean xg_has_userdef_op_fn PARAMS ((OpType)); +extern long xg_apply_userdef_op_fn PARAMS ((OpType, long)); #endif /* !XTENSA_RELAX_H */ diff --git a/gas/doc/as.texinfo b/gas/doc/as.texinfo index 23de55fefa9..0ede21a6a29 100644 --- a/gas/doc/as.texinfo +++ b/gas/doc/as.texinfo @@ -420,9 +420,9 @@ gcc(1), ld(1), and the Info entries for @file{binutils} and @file{ld}. @ifset XTENSA @emph{Target Xtensa options:} - [@b{--[no-]density}] [@b{--[no-]relax}] [@b{--[no-]generics}] - [@b{--[no-]text-section-literals}] + [@b{--[no-]text-section-literals}] [@b{--[no-]absolute-literals}] [@b{--[no-]target-align}] [@b{--[no-]longcalls}] + [@b{--[no-]transform}] @end ifset @c man end @end smallexample @@ -1061,28 +1061,19 @@ The following options are available when @value{AS} is configured for an Xtensa processor. @table @gcctabopt -@item --density | --no-density -Enable or disable use of instructions from the Xtensa code density -option. This is enabled by default when the Xtensa processor supports -the code density option. - -@item --relax | --no-relax -Enable or disable instruction relaxation. This is enabled by default. -Note: In the current implementation, these options also control whether -assembler optimizations are performed, making these options equivalent -to @option{--generics} and @option{--no-generics}. - -@item --generics | --no-generics -Enable or disable all assembler transformations of Xtensa instructions. -The default is @option{--generics}; -@option{--no-generics} should be used only in the rare cases when the -instructions must be exactly as specified in the assembly source. - @item --text-section-literals | --no-text-section-literals With @option{--text-@-section-@-literals}, literal pools are interspersed in the text section. The default is @option{--no-@-text-@-section-@-literals}, which places literals in a -separate section in the output file. +separate section in the output file. These options only affect literals +referenced via PC-relative @code{L32R} instructions; literals for +absolute mode @code{L32R} instructions are handled separately. + +@item --absolute-literals | --no-absolute-literals +Indicate to the assembler whether @code{L32R} instructions use absolute +or PC-relative addressing. The default is to assume absolute addressing +if the Xtensa processor includes the absolute @code{L32R} addressing +option. Otherwise, only the PC-relative @code{L32R} mode can be used. @item --target-align | --no-target-align Enable or disable automatic alignment to reduce branch penalties at the @@ -1092,6 +1083,12 @@ expense of some code density. The default is @option{--target-@-align}. Enable or disable transformation of call instructions to allow calls across a greater range of addresses. The default is @option{--no-@-longcalls}. + +@item --transform | --no-transform +Enable or disable all assembler transformations of Xtensa instructions. +The default is @option{--transform}; +@option{--no-transform} should be used only in the rare cases when the +instructions must be exactly as specified in the assembly source. @end table @end ifset diff --git a/gas/doc/c-xtensa.texi b/gas/doc/c-xtensa.texi index 5e5f13aac8d..5101d3116b9 100644 --- a/gas/doc/c-xtensa.texi +++ b/gas/doc/c-xtensa.texi @@ -1,4 +1,4 @@ -@c Copyright (C) 2002 Free Software Foundation, Inc. +@c Copyright (C) 2002, 2004 Free Software Foundation, Inc. @c This is part of the GAS manual. @c For copying conditions, see the file as.texinfo. @c @@ -33,54 +33,30 @@ The Xtensa version of the @sc{gnu} assembler supports these special options: @table @code -@item --density | --no-density -@kindex --density -@kindex --no-density -@cindex Xtensa density option -@cindex density option, Xtensa -Enable or disable use of the Xtensa code density option (16-bit -instructions). @xref{Density Instructions, ,Using Density -Instructions}. If the processor is configured with the density option, -this is enabled by default; otherwise, it is always disabled. - -@item --relax | --no-relax -@kindex --relax -@kindex --no-relax -Enable or disable relaxation of instructions with immediate operands -that are outside the legal range for the instructions. @xref{Xtensa -Relaxation, ,Xtensa Relaxation}. The default is @samp{--relax} and this -default should almost always be used. If relaxation is disabled with -@samp{--no-relax}, instruction operands that are out of range will cause -errors. Note: In the current implementation, these options also control -whether assembler optimizations are performed, making these options -equivalent to @samp{--generics} and @samp{--no-generics}. - -@item --generics | --no-generics -@kindex --generics -@kindex --no-generics -Enable or disable all assembler transformations of Xtensa instructions, -including both relaxation and optimization. The default is -@samp{--generics}; @samp{--no-generics} should only be used in the rare -cases when the instructions must be exactly as specified in the assembly -source. -@c The @samp{--no-generics} option is like @samp{--no-relax} -@c except that it also disables assembler optimizations (@pxref{Xtensa -@c Optimizations}). -As with @samp{--no-relax}, using @samp{--no-generics} -causes out of range instruction operands to be errors. - @item --text-section-literals | --no-text-section-literals @kindex --text-section-literals @kindex --no-text-section-literals Control the treatment of literal pools. The default is @samp{--no-@-text-@-section-@-literals}, which places literals in a separate section in the output file. This allows the literal pool to be -placed in a data RAM/ROM, and it also allows the linker to combine literal -pools from separate object files to remove redundant literals and -improve code size. With @samp{--text-@-section-@-literals}, the +placed in a data RAM/ROM. With @samp{--text-@-section-@-literals}, the literals are interspersed in the text section in order to keep them as close as possible to their references. This may be necessary for large -assembly files. +assembly files, where the literals would otherwise be out of range of the +@code{L32R} instructions in the text section. These options only affect +literals referenced via PC-relative @code{L32R} instructions; literals +for absolute mode @code{L32R} instructions are handled separately. + +@item --absolute-literals | --no-absolute-literals +@kindex --absolute-literals +@kindex --no-absolute-literals +Indicate to the assembler whether @code{L32R} instructions use absolute +or PC-relative addressing. If the processor includes the absolute +addressing option, the default is to use absolute @code{L32R} +relocations. Otherwise, only the PC-relative @code{L32R} relocations +can be used. Literals referenced with absolute @code{L32R} relocations +are always placed in the @code{.lit4} section, independent of the +placement of PC-relative literals. @item --target-align | --no-target-align @kindex --target-align @@ -97,14 +73,27 @@ have fixed alignment requirements. Enable or disable transformation of call instructions to allow calls across a greater range of addresses. @xref{Xtensa Call Relaxation, ,Function Call Relaxation}. This option should be used when call -targets can potentially be out of range, but it degrades both code size -and performance. The default is @samp{--no-@-longcalls}. +targets can potentially be out of range. It may degrade both code size +and performance, but the linker can generally optimize away the +unnecessary overhead when a call ends up within range. The default is +@samp{--no-@-longcalls}. + +@item --transform | --no-transform +@kindex --transform +@kindex --no-transform +Enable or disable all assembler transformations of Xtensa instructions, +including both relaxation and optimization. The default is +@samp{--transform}; @samp{--no-transform} should only be used in the +rare cases when the instructions must be exactly as specified in the +assembly source. Using @samp{--no-transform} causes out of range +instruction operands to be errors. @end table @node Xtensa Syntax @section Assembler Syntax @cindex syntax, Xtensa assembler @cindex Xtensa assembler syntax +@cindex FLIX syntax Block comments are delimited by @samp{/*} and @samp{*/}. End of line comments may be introduced with either @samp{#} or @samp{//}. @@ -113,11 +102,45 @@ Instructions consist of a leading opcode or macro name followed by whitespace and an optional comma-separated list of operands: @smallexample -@var{opcode} [@var{operand},@dots{}] +@var{opcode} [@var{operand}, @dots{}] @end smallexample Instructions must be separated by a newline or semicolon. +FLIX instructions, which bundle multiple opcodes together in a single +instruction, are specified by enclosing the bundled opcodes inside +braces: + +@smallexample +@{ +[@var{format}] +@var{opcode0} [@var{operands}] +@var{opcode1} [@var{operands}] +@var{opcode2} [@var{operands}] +@dots{} +@} +@end smallexample + +The opcodes in a FLIX instruction are listed in the same order as the +corresponding instruction slots in the TIE format declaration. +Directives and labels are not allowed inside the braces of a FLIX +instruction. A particular TIE format name can optionally be specified +immediately after the opening brace, but this is usually unnecessary. +The assembler will automatically search for a format that can encode the +specified opcodes, so the format name need only be specified in rare +cases where there is more than one applicable format and where it +matters which of those formats is used. A FLIX instruction can also be +specified on a single line by separating the opcodes with semicolons: + +@smallexample +@{ [@var{format};] @var{opcode0} [@var{operands}]; @var{opcode1} [@var{operands}]; @var{opcode2} [@var{operands}]; @dots{} @} +@end smallexample + +The assembler can automatically bundle opcodes into FLIX instructions. +It encodes the opcodes in order, one at a time, +choosing the smallest format where each opcode can be encoded and +filling unused instruction slots with no-ops. + @menu * Xtensa Opcodes:: Opcode Naming Conventions. * Xtensa Registers:: Register Naming. @@ -126,41 +149,30 @@ Instructions must be separated by a newline or semicolon. @node Xtensa Opcodes @subsection Opcode Names @cindex Xtensa opcode names -@cindex opcode names, Xtenxa +@cindex opcode names, Xtensa See the @cite{Xtensa Instruction Set Architecture (ISA) Reference Manual} for a complete list of opcodes and descriptions of their semantics. -@cindex generic opcodes -@cindex specific opcodes @cindex _ opcode prefix -The Xtensa assembler distinguishes between @dfn{generic} and -@dfn{specific} opcodes. Specific opcodes correspond directly to Xtensa -machine instructions. Prefixing an opcode with an underscore character -(@samp{_}) identifies it as a specific opcode. Opcodes without a -leading underscore are generic, which means the assembler is required to -preserve their semantics but may not translate them directly to the -specific opcodes with the same names. Instead, the assembler may -optimize a generic opcode and select a better instruction to use in its -place (@pxref{Xtensa Optimizations, ,Xtensa Optimizations}), or the -assembler may relax the instruction to handle operands that are out of -range for the corresponding specific opcode (@pxref{Xtensa Relaxation, -,Xtensa Relaxation}). - -Only use specific opcodes when it is essential to select -the exact machine instructions produced by the assembler. -Using specific opcodes unnecessarily only makes the code less -efficient, by disabling assembler optimization, and less flexible, by -disabling relaxation. +If an opcode name is prefixed with an underscore character (@samp{_}), +@command{@value{AS}} will not transform that instruction in any way. The +underscore prefix disables both optimization (@pxref{Xtensa +Optimizations, ,Xtensa Optimizations}) and relaxation (@pxref{Xtensa +Relaxation, ,Xtensa Relaxation}) for that particular instruction. Only +use the underscore prefix when it is essential to select the exact +opcode produced by the assembler. Using this feature unnecessarily +makes the code less efficient by disabling assembler optimization and +less flexible by disabling relaxation. Note that this special handling of underscore prefixes only applies to Xtensa opcodes, not to either built-in macros or user-defined macros. -When an underscore prefix is used with a macro (e.g., @code{_NOP}), it +When an underscore prefix is used with a macro (e.g., @code{_MOV}), it refers to a different macro. The assembler generally provides built-in macros both with and without the underscore prefix, where the underscore versions behave as if the underscore carries through to the instructions -in the macros. For example, @code{_NOP} expands to @code{_OR a1,a1,a1}. +in the macros. For example, @code{_MOV} may expand to @code{_MOV.N}@. The underscore prefix only applies to individual instructions, not to series of instructions. For example, if a series of instructions have @@ -168,7 +180,7 @@ underscore prefixes, the assembler will not transform the individual instructions, but it may insert other instructions between them (e.g., to align a @code{LOOP} instruction). To prevent the assembler from modifying a series of instructions as a whole, use the -@code{no-generics} directive. @xref{Generics Directive, ,generics}. +@code{no-transform} directive. @xref{Transform Directive, ,transform}. @node Xtensa Registers @subsection Register Names @@ -176,20 +188,20 @@ modifying a series of instructions as a whole, use the @cindex register names, Xtensa @cindex sp register -An initial @samp{$} character is optional in all register names. -General purpose registers are named @samp{a0}@dots{}@samp{a15}. Additional -registers may be added by processor configuration options. In -particular, the @sc{mac16} option adds a @sc{mr} register bank. Its -registers are named @samp{m0}@dots{}@samp{m3}. - -As a special feature, @samp{sp} is also supported as a synonym for -@samp{a1}. +The assembly syntax for a register file entry is the ``short'' name for +a TIE register file followed by the index into that register file. For +example, the general-purpose @code{AR} register file has a short name of +@code{a}, so these registers are named @code{a0}@dots{}@code{a15}. +As a special feature, @code{sp} is also supported as a synonym for +@code{a1}. Additional registers may be added by processor configuration +options and by designer-defined TIE extensions. An initial @samp{$} +character is optional in all register names. @node Xtensa Optimizations @section Xtensa Optimizations @cindex optimizations -The optimizations currently supported by @code{@value{AS}} are +The optimizations currently supported by @command{@value{AS}} are generation of density instructions where appropriate and automatic branch target alignment. @@ -205,18 +217,18 @@ branch target alignment. The Xtensa instruction set has a code density option that provides 16-bit versions of some of the most commonly used opcodes. Use of these opcodes can significantly reduce code size. When possible, the -assembler automatically translates generic instructions from the core +assembler automatically translates instructions from the core Xtensa instruction set into equivalent instructions from the Xtensa code -density option. This translation can be disabled by using specific -opcodes (@pxref{Xtensa Opcodes, ,Opcode Names}), by using the -@samp{--no-density} command-line option (@pxref{Xtensa Options, ,Command -Line Options}), or by using the @code{no-density} directive -(@pxref{Density Directive, ,density}). +density option. This translation can be disabled by using underscore +prefixes (@pxref{Xtensa Opcodes, ,Opcode Names}), by using the +@samp{--no-transform} command-line option (@pxref{Xtensa Options, ,Command +Line Options}), or by using the @code{no-transform} directive +(@pxref{Transform Directive, ,transform}). It is a good idea @emph{not} to use the density instructions directly. The assembler will automatically select dense instructions where -possible. If you later need to avoid using the code density option, you -can disable it in the assembler without having to modify the code. +possible. If you later need to use an Xtensa processor without the code +density option, the same assembly code will then work without modification. @node Xtensa Automatic Alignment @subsection Automatic Instruction Alignment @@ -230,24 +242,42 @@ can disable it in the assembler without having to modify the code. The Xtensa assembler will automatically align certain instructions, both to optimize performance and to satisfy architectural requirements. -When the @code{--target-@-align} command-line option is enabled -(@pxref{Xtensa Options, ,Command Line Options}), the assembler attempts -to widen density instructions preceding a branch target so that the -target instruction does not cross a 4-byte boundary. Similarly, the -assembler also attempts to align each instruction following a call -instruction. If there are not enough preceding safe density -instructions to align a target, no widening will be performed. This -alignment has the potential to reduce branch penalties at some expense -in code size. The assembler will not attempt to align labels with the -prefixes @code{.Ln} and @code{.LM}, since these labels are used for -debugging information and are not typically branch targets. - -The @code{LOOP} family of instructions must be aligned on either a 1 or -2 mod 4 byte boundary. The assembler knows about this restriction and -inserts the minimal number of 2 or 3 byte no-op instructions -to satisfy it. When no-op instructions are added, any label immediately -preceding the original loop will be moved in order to refer to the loop -instruction, not the newly generated no-op instruction. +As an optimization to improve performance, the assembler attempts to +align branch targets so they do not cross instruction fetch boundaries. +(Xtensa processors can be configured with either 32-bit or 64-bit +instruction fetch widths.) An +instruction immediately following a call is treated as a branch target +in this context, because it will be the target of a return from the +call. This alignment has the potential to reduce branch penalties at +some expense in code size. The assembler will not attempt to align +labels with the prefixes @code{.Ln} and @code{.LM}, since these labels +are used for debugging information and are not typically branch targets. +This optimization is enabled by default. You can disable it with the +@samp{--no-target-@-align} command-line option (@pxref{Xtensa Options, +,Command Line Options}). + +The target alignment optimization is done without adding instructions +that could increase the execution time of the program. If there are +density instructions in the code preceding a target, the assembler can +change the target alignment by widening some of those instructions to +the equivalent 24-bit instructions. Extra bytes of padding can be +inserted immediately following unconditional jump and return +instructions. +This approach is usually successful in aligning many, but not all, +branch targets. + +The @code{LOOP} family of instructions must be aligned such that the +first instruction in the loop body does not cross an instruction fetch +boundary (e.g., with a 32-bit fetch width, a @code{LOOP} instruction +must be on either a 1 or 2 mod 4 byte boundary). The assembler knows +about this restriction and inserts the minimal number of 2 or 3 byte +no-op instructions to satisfy it. When no-op instructions are added, +any label immediately preceding the original loop will be moved in order +to refer to the loop instruction, not the newly generated no-op +instruction. To preserve binary compatibility across processors with +different fetch widths, the assembler conservatively assumes a 32-bit +fetch width when aligning @code{LOOP} instructions (except if the first +instruction in the loop is a 64-bit instruction). Similarly, the @code{ENTRY} instruction must be aligned on a 0 mod 4 byte boundary. The assembler satisfies this requirement by inserting @@ -260,7 +290,7 @@ location. @cindex relaxation When an instruction operand is outside the range allowed for that -particular instruction field, @code{@value{AS}} can transform the code +particular instruction field, @command{@value{AS}} can transform the code to use a functionally-equivalent instruction or sequence of instructions. This process is known as @dfn{relaxation}. This is typically done for branch instructions because the distance of the @@ -300,6 +330,19 @@ M: (The @code{BNEZ.N} instruction would be used in this example only if the density option is available. Otherwise, @code{BNEZ} would be used.) +This relaxation works well because the unconditional jump instruction +has a much larger offset range than the various conditional branches. +However, an error will occur if a branch target is beyond the range of a +jump instruction. @command{@value{AS}} cannot relax unconditional jumps. +Similarly, an error will occur if the original input contains an +unconditional jump to a target that is out of range. + +Branch relaxation is enabled by default. It can be disabled by using +underscore prefixes (@pxref{Xtensa Opcodes, ,Opcode Names}), the +@samp{--no-transform} command-line option (@pxref{Xtensa Options, +,Command Line Options}), or the @code{no-transform} directive +(@pxref{Transform Directive, ,transform}). + @node Xtensa Call Relaxation @subsection Function Call Relaxation @cindex relaxation of call instructions @@ -332,21 +375,27 @@ Because the addresses of targets of function calls are not generally known until link-time, the assembler must assume the worst and relax all the calls to functions in other source files, not just those that really will be out of range. The linker can recognize calls that were -unnecessarily relaxed, but it can only partially remove the overhead -introduced by the assembler. +unnecessarily relaxed, and it will remove the overhead introduced by the +assembler for those cases where direct calls are sufficient. -Call relaxation has a negative effect -on both code size and performance, so this relaxation is disabled by -default. If a program is too large and some of the calls are out of -range, function call relaxation can be enabled using the -@samp{--longcalls} command-line option or the @code{longcalls} directive -(@pxref{Longcalls Directive, ,longcalls}). +Call relaxation is disabled by default because it can have a negative +effect on both code size and performance, although the linker can +usually eliminate the unnecessary overhead. If a program is too large +and some of the calls are out of range, function call relaxation can be +enabled using the @samp{--longcalls} command-line option or the +@code{longcalls} directive (@pxref{Longcalls Directive, ,longcalls}). @node Xtensa Immediate Relaxation @subsection Other Immediate Field Relaxation @cindex immediate fields, relaxation @cindex relaxation of immediate fields +The assembler normally performs the following other relaxations. They +can be disabled by using underscore prefixes (@pxref{Xtensa Opcodes, +,Opcode Names}), the @samp{--no-transform} command-line option +(@pxref{Xtensa Options, ,Command Line Options}), or the +@code{no-transform} directive (@pxref{Transform Directive, ,transform}). + @cindex @code{MOVI} instructions, relaxation @cindex relaxation of @code{MOVI} instructions The @code{MOVI} machine instruction can only materialize values in the @@ -401,7 +450,7 @@ out-of-range offset causes an error. @cindex relaxation of @code{ADDI} instructions The Xtensa @code{ADDI} instruction only allows immediate operands in the range from -128 to 127. There are a number of alternate instruction -sequences for the generic @code{ADDI} operation. First, if the +sequences for the @code{ADDI} operation. First, if the immediate is 0, the @code{ADDI} will be turned into a @code{MOV.N} instruction (or the equivalent @code{OR} instruction if the code density option is not available). If the @code{ADDI} immediate is outside of @@ -456,87 +505,49 @@ change the state of the directive without having to be aware of its outer state. For example, consider: @smallexample - .begin no-density + .begin no-transform L: add a0, a1, a2 - .begin density + .begin transform M: add a0, a1, a2 - .end density + .end transform N: add a0, a1, a2 - .end no-density + .end no-transform @end smallexample -The generic @code{ADD} opcodes at @code{L} and @code{N} in the outer -@code{no-density} region both result in @code{ADD} machine instructions, -but the assembler selects an @code{ADD.N} instruction for the generic -@code{ADD} at @code{M} in the inner @code{density} region. +The @code{ADD} opcodes at @code{L} and @code{N} in the outer +@code{no-transform} region both result in @code{ADD} machine instructions, +but the assembler selects an @code{ADD.N} instruction for the +@code{ADD} at @code{M} in the inner @code{transform} region. The advantage of this style is that it works well inside macros which can preserve the context of their callers. -@cindex precedence of directives -@cindex directives, precedence -When command-line options and assembler directives are used at the same -time and conflict, the one that overrides a default behavior takes -precedence over one that is the same as the default. For example, if -the code density option is available, the default is to select density -instructions whenever possible. So, if the above is assembled with the -@samp{--no-density} flag, which overrides the default, all the generic -@code{ADD} instructions result in @code{ADD} machine instructions. If -assembled with the @samp{--density} flag, which is already the default, -the @code{no-density} directive takes precedence and only one of -the generic @code{ADD} instructions is optimized to be a @code{ADD.N} -machine instruction. An underscore prefix identifying a specific opcode -always takes precedence over directives and command-line flags. - The following directives are available: @menu -* Density Directive:: Disable Use of Density Instructions. -* Relax Directive:: Disable Assembler Relaxation. +* Schedule Directive:: Enable instruction scheduling. * Longcalls Directive:: Use Indirect Calls for Greater Range. -* Generics Directive:: Disable All Assembler Transformations. +* Transform Directive:: Disable All Assembler Transformations. * Literal Directive:: Intermix Literals with Instructions. * Literal Position Directive:: Specify Inline Literal Pool Locations. * Literal Prefix Directive:: Specify Literal Section Name Prefix. -* Freeregs Directive:: List Registers Available for Assembler Use. +* Absolute Literals Directive:: Control PC-Relative vs. Absolute Literals. * Frame Directive:: Describe a stack frame. @end menu -@node Density Directive -@subsection density -@cindex @code{density} directive -@cindex @code{no-density} directive +@node Schedule Directive +@subsection schedule +@cindex @code{schedule} directive +@cindex @code{no-schedule} directive -The @code{density} and @code{no-density} directives enable or disable -optimization of generic instructions into density instructions within -the region. @xref{Density Instructions, ,Using Density Instructions}. +The @code{schedule} directive is recognized only for compatibility with +Tensilica's assembler. @smallexample - .begin [no-]density - .end [no-]density + .begin [no-]schedule + .end [no-]schedule @end smallexample -This optimization is enabled by default unless the Xtensa configuration -does not support the code density option or the @samp{--no-density} -command-line option was specified. - -@node Relax Directive -@subsection relax -@cindex @code{relax} directive -@cindex @code{no-relax} directive - -The @code{relax} directive enables or disables relaxation -within the region. @xref{Xtensa Relaxation, ,Xtensa Relaxation}. -Note: In the current implementation, these directives also control -whether assembler optimizations are performed, making them equivalent to -the @code{generics} and @code{no-generics} directives. - -@smallexample - .begin [no-]relax - .end [no-]relax -@end smallexample - -Relaxation is enabled by default unless the @samp{--no-relax} -command-line option was specified. +This directive is ignored and has no effect on @command{@value{AS}}. @node Longcalls Directive @subsection longcalls @@ -552,27 +563,28 @@ relaxation. @xref{Xtensa Call Relaxation, ,Function Call Relaxation}. @end smallexample Call relaxation is disabled by default unless the @samp{--longcalls} -command-line option is specified. +command-line option is specified. The @code{longcalls} directive +overrides the default determined by the command-line options. -@node Generics Directive -@subsection generics -@cindex @code{generics} directive -@cindex @code{no-generics} directive +@node Transform Directive +@subsection transform +@cindex @code{transform} directive +@cindex @code{no-transform} directive This directive enables or disables all assembler transformation, including relaxation (@pxref{Xtensa Relaxation, ,Xtensa Relaxation}) and optimization (@pxref{Xtensa Optimizations, ,Xtensa Optimizations}). @smallexample - .begin [no-]generics - .end [no-]generics + .begin [no-]transform + .end [no-]transform @end smallexample -Disabling generics is roughly equivalent to adding an underscore prefix -to every opcode within the region, so that every opcode is treated as a -specific opcode. @xref{Xtensa Opcodes, ,Opcode Names}. In the current -implementation of @code{@value{AS}}, built-in macros are also disabled -within a @code{no-generics} region. +Transformations are enabled by default unless the @samp{--no-transform} +option is used. The @code{transform} directive overrides the default +determined by the command-line options. An underscore opcode prefix, +disabling transformation of that opcode, always takes precedence over +both directives and command-line flags. @node Literal Directive @subsection literal @@ -603,17 +615,19 @@ can be used to load a pointer to the symbol @code{sym} into register @code{ENTRY} and @code{L32R} instructions; instead, the assembler puts the data in a literal pool. -By default literal pools are placed in a separate section; however, when +Literal pools for absolute mode @code{L32R} instructions +(@pxref{Absolute Literals Directive}) are always placed in the +@code{.lit4} section. By default literal pools for PC-relative mode +@code{L32R} instructions are placed in a separate section; however, when using the @samp{--text-@-section-@-literals} option (@pxref{Xtensa Options, ,Command Line Options}), the literal pools are placed in the current section. These text section literal pools are created automatically before @code{ENTRY} instructions and manually after @samp{.literal_position} directives (@pxref{Literal Position Directive, ,literal_position}). If there are no preceding @code{ENTRY} -instructions or @code{.literal_position} directives, the assembler will -print a warning and place the literal pool at the beginning of the -current section. In such cases, explicit @code{.literal_position} -directives should be used to place the literal pools. +instructions, explicit @code{.literal_position} directives +must be used to place the text section literal pools; otherwise, +@command{@value{AS}} will report an error. @node Literal Position Directive @subsection literal_position @@ -628,7 +642,8 @@ can be used to mark a potential location for a literal pool. @end smallexample The @code{.literal_position} directive is ignored when the -@samp{--text-@-section-@-literals} option is not used. +@samp{--text-@-section-@-literals} option is not used or when +@code{L32R} instructions use the absolute addressing mode. The assembler will automatically place text section literal pools before @code{ENTRY} instructions, so the @code{.literal_position} @@ -642,7 +657,8 @@ place to put a literal pool. Moreover, the code for the interrupt vector must be at a specific starting address, so the literal pool cannot come before the start of the code. The literal pool for the vector must be explicitly positioned in the middle of the vector (before -any uses of the literals, of course). The @code{.literal_position} +any uses of the literals, due to the negative offsets used by +PC-relative @code{L32R} instructions). The @code{.literal_position} directive can be used to do this. In the following code, the literal for @samp{M} will automatically be aligned correctly and is placed after the unconditional jump. @@ -663,6 +679,9 @@ continue: The @code{literal_prefix} directive allows you to specify different sections to hold literals from different portions of an assembly file. +This directive only applies to literals referenced from PC-relative +@code{L32R} instructions; it has no effect for absolute literals +(@pxref{Absolute Literals Directive}). With this directive, a single assembly file can be used to generate code into multiple sections, including literals generated by the assembler. @@ -679,31 +698,40 @@ the ``default'' for the file. This default is usually @code{.literal} but can be changed with the @samp{--rename-section} command-line argument. -@node Freeregs Directive -@subsection freeregs -@cindex @code{freeregs} directive - -This directive tells the assembler that the given registers are unused -in the region. - -@smallexample - .begin freeregs @var{ri}[,@var{ri}@dots{}] - .end freeregs -@end smallexample - -This allows the assembler to use these registers for relaxations or -optimizations. (They are actually only for relaxations at present, but -the possibility of optimizations exists in the future.) +@node Absolute Literals Directive +@subsection absolute-literals +@cindex @code{absolute-literals} directive +@cindex @code{no-absolute-literals} directive -Nested @code{freeregs} directives can be used to add additional registers -to the list of those available to the assembler. For example: +The @code{absolute-@-literals} and @code{no-@-absolute-@-literals} +directives control the absolute vs.@: PC-relative mode for @code{L32R} +instructions. These are relevant only for Xtensa configurations that +include the absolute addressing option for @code{L32R} instructions. @smallexample - .begin freeregs a3, a4 - .begin freeregs a5 + .begin [no-]absolute-literals + .end [no-]absolute-literals @end smallexample -has the effect of declaring @code{a3}, @code{a4}, and @code{a5} all free. +These directives do not change the @code{L32R} mode---they only cause +the assembler to emit the appropriate kind of relocation for @code{L32R} +instructions and to place the literal values in the appropriate section. +To change the @code{L32R} mode, the program must write the +@code{LITBASE} special register. It is the programmer's responsibility +to keep track of the mode and indicate to the assembler which mode is +used in each region of code. + +Literals referenced with absolute @code{L32R} instructions are always +placed in the @code{.lit4} section. PC-relative literals may be placed +in the current text section or in a separate literal section, as +described elsewhere (@pxref{Literal Directive}). + +If the Xtensa configuration includes the absolute @code{L32R} addressing +option, the default is to assume absolute @code{L32R} addressing unless +the @samp{--no-@-absolute-@-literals} command-line option is specified. +Otherwise, the default is to assume PC-relative @code{L32R} addressing. +The @code{absolute-@-literals} directive can then be used to override +the default determined by the command-line options. @node Frame Directive @subsection frame @@ -719,9 +747,9 @@ debugger to locate a function's stack frame. The syntax is: where @var{reg} is the register used to hold the frame pointer (usually the same as the stack pointer) and @var{size} is the size in bytes of the stack frame. The @code{.frame} directive is typically placed -immediately after the @code{ENTRY} instruction for a function. +near the @code{ENTRY} instruction for a function. -In almost all circumstances, this information just duplicates the +In many circumstances, this information just duplicates the information given in the function's @code{ENTRY} instruction; however, there are two cases where this is not true: diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index 9351813325d..f171ef920c8 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2004-10-07 Bob Wilson + + * gas/xtensa/all.exp: Adjust expected error message for j_too_far. + Change entry_align test to expect an error. + * gas/xtensa/entry_misalign2.s: Use no-transform instead of + no-generics directives. + 2004-10-07 Richard Sandiford * gas/mips/elf-rel{23,24}.[sd]: New tests. diff --git a/gas/testsuite/gas/xtensa/all.exp b/gas/testsuite/gas/xtensa/all.exp index e01c4a395f0..207730102a6 100644 --- a/gas/testsuite/gas/xtensa/all.exp +++ b/gas/testsuite/gas/xtensa/all.exp @@ -9,7 +9,7 @@ if [istarget xtensa*-*-*] then { set x1 0 while 1 { expect { - -re ":4: Error:.*too large" { set x1 1 } + -re ":4: Error:.*out of range" { set x1 1 } timeout { perror "timeout\n"; break } eof { break } } @@ -47,19 +47,7 @@ if [istarget xtensa*-*-*] then { objdump_finish if [all_ones $x1] then { pass $testname } else { fail $testname } - gas_test "entry_align.s" "" "" "Xtensa autoalign entry" - set testname "entry_align.s: autoalign entry" - objdump_start_no_subdir "a.out" "-d -j .text" - set x1 0 - while 1 { - expect { - -re "^.*4:.*entry" { set x1 1 } - timeout { perror "timeout\n"; break } - eof { break } - } - } - objdump_finish - if [all_ones $x1] then { pass $testname } else { fail $testname } + gas_test_error "entry_align.s" "" "Xtensa entry alignment error" gas_test "loop_misalign.s" "" "" "Xtensa Loop misalignment" set testname "loop_misalign.s: Force loop misalignment" diff --git a/gas/testsuite/gas/xtensa/entry_misalign2.s b/gas/testsuite/gas/xtensa/entry_misalign2.s index 5d48b6c59b9..5a57815ab41 100644 --- a/gas/testsuite/gas/xtensa/entry_misalign2.s +++ b/gas/testsuite/gas/xtensa/entry_misalign2.s @@ -1,6 +1,6 @@ - .begin no-generics + .begin no-transform nop.n l4: entry a5,16 mov.n a4,a5 - .end no-generics + .end no-transform diff --git a/include/ChangeLog b/include/ChangeLog index 9ddcc72b228..eb2d804f5e5 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,104 @@ +2004-10-07 Bob Wilson + + * xtensa-config.h (XSHAL_USE_ABSOLUTE_LITERALS, + XCHAL_HAVE_PREDICTED_BRANCHES, XCHAL_INST_FETCH_WIDTH): New. + (XCHAL_EXTRA_SA_SIZE, XCHAL_EXTRA_SA_ALIGN): Delete. + * xtensa-isa-internal.h (ISA_INTERFACE_VERSION): Delete. + (config_sturct struct): Delete. + (XTENSA_OPERAND_IS_REGISTER, XTENSA_OPERAND_IS_PCRELATIVE, + XTENSA_OPERAND_IS_INVISIBLE, XTENSA_OPERAND_IS_UNKNOWN, + XTENSA_OPCODE_IS_BRANCH, XTENSA_OPCODE_IS_JUMP, + XTENSA_OPCODE_IS_LOOP, XTENSA_OPCODE_IS_CALL, + XTENSA_STATE_IS_EXPORTED, XTENSA_INTERFACE_HAS_SIDE_EFFECT): Define. + (xtensa_format_encode_fn, xtensa_get_slot_fn, xtensa_set_slot_fn): New. + (xtensa_insn_decode_fn): Rename to ... + (xtensa_opcode_decode_fn): ... this. + (xtensa_immed_decode_fn, xtensa_immed_encode_fn, xtensa_do_reloc_fn, + xtensa_undo_reloc_fn): Update. + (xtensa_encoding_template_fn): Delete. + (xtensa_opcode_encode_fn, xtensa_format_decode_fn, + xtensa_length_decode_fn): New. + (xtensa_format_internal, xtensa_slot_internal): New types. + (xtensa_operand_internal): Delete operand_kind, inout, isPCRelative, + get_field, and set_field fields. Add name, field_id, regfile, + num_regs, and flags fields. + (xtensa_arg_internal): New type. + (xtensa_iclass_internal): Change operands field to array of + xtensa_arg_internal. Add num_stateOperands, stateOperands, + num_interfaceOperands, and interfaceOperands fields. + (xtensa_opcode_internal): Delete length, template, and iclass fields. + Add iclass_id, flags, encode_fns, num_funcUnit_uses, and funcUnit_uses. + (opname_lookup_entry): Delete. + (xtensa_regfile_internal, xtensa_interface_internal, + xtensa_funcUnit_internal, xtensa_state_internal, + xtensa_sysreg_internal, xtensa_lookup_entry): New. + (xtensa_isa_internal): Replace opcode_table field with opcodes field. + Change type of opname_lookup_table. Delete num_modules, + module_opcode_base, module_decode_fn, config, and has_density fields. + Add num_formats, formats, format_decode_fn, length_decode_fn, + num_slots, slots, num_fields, num_operands, operands, num_iclasses, + iclasses, num_regfiles, regfiles, num_states, states, + state_lookup_table, num_sysregs, sysregs, sysreg_lookup_table, + max_sysreg_num, sysreg_table, num_interfaces, interfaces, + interface_lookup_table, num_funcUnits, funcUnits and + funcUnit_lookup_table fields. + (xtensa_isa_module, xtensa_isa_modules): Delete. + (xtensa_isa_name_compare): New prototype. + (xtisa_errno, xtisa_error_msg): New. + * xtensa-isa.h (XTENSA_ISA_VERSION): Define. + (xtensa_isa): Change type. + (xtensa_operand): Delete. + (xtensa_format, xtensa_regfile, xtensa_state, xtensa_sysreg, + xtensa_interface, xtensa_funcUnit, xtensa_isa_status, + xtensa_funcUnit_use): New types. + (libisa_module_specifier): Delete. + (xtensa_isa_errno, xtensa_isa_error_msg): New prototypes. + (xtensa_insnbuf_free, xtensa_insnbuf_to_chars, + xtensa_insnbuf_from_chars): Update prototypes. + (xtensa_load_isa, xtensa_extend_isa, xtensa_default_isa, + xtensa_insn_maxlength, xtensa_num_opcodes, xtensa_decode_insn, + xtensa_encode_insn, xtensa_insn_length, + xtensa_insn_length_from_first_byte, xtensa_num_operands, + xtensa_operand_kind, xtensa_encode_result, + xtensa_operand_isPCRelative): Delete. + (xtensa_isa_init, xtensa_operand_inout, xtensa_operand_get_field, + xtensa_operand_set_field, xtensa_operand_encode, + xtensa_operand_decode, xtensa_operand_do_reloc, + xtensa_operand_undo_reloc): Update prototypes. + (xtensa_isa_maxlength, xtensa_isa_length_from_chars, + xtensa_isa_num_pipe_stages, xtensa_isa_num_formats, + xtensa_isa_num_opcodes, xtensa_isa_num_regfiles, xtensa_isa_num_states, + xtensa_isa_num_sysregs, xtensa_isa_num_interfaces, + xtensa_isa_num_funcUnits, xtensa_format_name, xtensa_format_lookup, + xtensa_format_decode, xtensa_format_encode, xtensa_format_length, + xtensa_format_num_slots, xtensa_format_slot_nop_opcode, + xtensa_format_get_slot, xtensa_format_set_slot, xtensa_opcode_decode, + xtensa_opcode_encode, xtensa_opcode_is_branch, xtensa_opcode_is_jump, + xtensa_opcode_is_loop, xtensa_opcode_is_call, + xtensa_opcode_num_operands, xtensa_opcode_num_stateOperands, + xtensa_opcode_num_interfaceOperands, xtensa_opcode_num_funcUnit_uses, + xtensa_opcode_funcUnit_use, xtensa_operand_name, + xtensa_operand_is_visible, xtensa_operand_is_register, + xtensa_operand_regfile, xtensa_operand_num_regs, + xtensa_operand_is_known_reg, xtensa_operand_is_PCrelative, + xtensa_stateOperand_state, xtensa_stateOperand_inout, + xtensa_interfaceOperand_interface, xtensa_regfile_lookup, + xtensa_regfile_lookup_shortname, xtensa_regfile_name, + xtensa_regfile_shortname, xtensa_regfile_view_parent, + xtensa_regfile_num_bits, xtensa_regfile_num_entries, + xtensa_state_lookup, xtensa_state_name, xtensa_state_num_bits, + xtensa_state_is_exported, xtensa_sysreg_lookup, + xtensa_sysreg_lookup_name, xtensa_sysreg_name, xtensa_sysreg_number, + xtensa_sysreg_is_user, xtensa_interface_lookup, xtensa_interface_name, + xtensa_interface_num_bits, xtensa_interface_inout, + xtensa_interface_has_side_effect, xtensa_funcUnit_lookup, + xtensa_funcUnit_name, xtensa_funcUnit_num_copies): New prototypes. + * elf/xtensa.h (R_XTENSA_DIFF8, R_XTENSA_DIFF16, R_XTENSA_DIFF32, + R_XTENSA_SLOT*_OP, R_XTENSA_SLOT*_ALT): New relocations. + (XTENSA_PROP_SEC_NAME): Define. + (property_table_entry): Add flags field. + (XTENSA_PROP_*, GET_XTENSA_PROP_*, SET_XTENSA_PROP_*): Define. + 2004-10-07 Jeff Baker * bfdlink.h (bfd_link_info): Add bitfield: warn_shared_textrel. diff --git a/include/elf/xtensa.h b/include/elf/xtensa.h index 6c584c71515..14f99132299 100644 --- a/include/elf/xtensa.h +++ b/include/elf/xtensa.h @@ -1,5 +1,5 @@ /* Xtensa ELF support for BFD. - Copyright 2003 Free Software Foundation, Inc. + Copyright 2003, 2004 Free Software Foundation, Inc. Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica. This file is part of BFD, the Binary File Descriptor library. @@ -42,6 +42,39 @@ START_RELOC_NUMBERS (elf_xtensa_reloc_type) RELOC_NUMBER (R_XTENSA_ASM_SIMPLIFY, 12) RELOC_NUMBER (R_XTENSA_GNU_VTINHERIT, 15) RELOC_NUMBER (R_XTENSA_GNU_VTENTRY, 16) + RELOC_NUMBER (R_XTENSA_DIFF8, 17) + RELOC_NUMBER (R_XTENSA_DIFF16, 18) + RELOC_NUMBER (R_XTENSA_DIFF32, 19) + RELOC_NUMBER (R_XTENSA_SLOT0_OP, 20) + RELOC_NUMBER (R_XTENSA_SLOT1_OP, 21) + RELOC_NUMBER (R_XTENSA_SLOT2_OP, 22) + RELOC_NUMBER (R_XTENSA_SLOT3_OP, 23) + RELOC_NUMBER (R_XTENSA_SLOT4_OP, 24) + RELOC_NUMBER (R_XTENSA_SLOT5_OP, 25) + RELOC_NUMBER (R_XTENSA_SLOT6_OP, 26) + RELOC_NUMBER (R_XTENSA_SLOT7_OP, 27) + RELOC_NUMBER (R_XTENSA_SLOT8_OP, 28) + RELOC_NUMBER (R_XTENSA_SLOT9_OP, 29) + RELOC_NUMBER (R_XTENSA_SLOT10_OP, 30) + RELOC_NUMBER (R_XTENSA_SLOT11_OP, 31) + RELOC_NUMBER (R_XTENSA_SLOT12_OP, 32) + RELOC_NUMBER (R_XTENSA_SLOT13_OP, 33) + RELOC_NUMBER (R_XTENSA_SLOT14_OP, 34) + RELOC_NUMBER (R_XTENSA_SLOT0_ALT, 35) + RELOC_NUMBER (R_XTENSA_SLOT1_ALT, 36) + RELOC_NUMBER (R_XTENSA_SLOT2_ALT, 37) + RELOC_NUMBER (R_XTENSA_SLOT3_ALT, 38) + RELOC_NUMBER (R_XTENSA_SLOT4_ALT, 39) + RELOC_NUMBER (R_XTENSA_SLOT5_ALT, 40) + RELOC_NUMBER (R_XTENSA_SLOT6_ALT, 41) + RELOC_NUMBER (R_XTENSA_SLOT7_ALT, 42) + RELOC_NUMBER (R_XTENSA_SLOT8_ALT, 43) + RELOC_NUMBER (R_XTENSA_SLOT9_ALT, 44) + RELOC_NUMBER (R_XTENSA_SLOT10_ALT, 45) + RELOC_NUMBER (R_XTENSA_SLOT11_ALT, 46) + RELOC_NUMBER (R_XTENSA_SLOT12_ALT, 47) + RELOC_NUMBER (R_XTENSA_SLOT13_ALT, 48) + RELOC_NUMBER (R_XTENSA_SLOT14_ALT, 49) END_RELOC_NUMBERS (R_XTENSA_max) /* Processor-specific flags for the ELF header e_flags field. */ @@ -78,11 +111,88 @@ END_RELOC_NUMBERS (R_XTENSA_max) #define XTENSA_INSN_SEC_NAME ".xt.insn" #define XTENSA_LIT_SEC_NAME ".xt.lit" +#define XTENSA_PROP_SEC_NAME ".xt.prop" typedef struct property_table_entry_t { bfd_vma address; bfd_vma size; + flagword flags; } property_table_entry; +/* Flags in the property tables to specify whether blocks of memory are + literals, instructions, data, or unreachable. For instructions, + blocks that begin loop targets and branch targets are designated. + Blocks that do not allow density instructions, instruction reordering + or transformation are also specified. Finally, for branch targets, + branch target alignment priority is included. Alignment of the next + block is specified in the current block and the size of the current + block does not include any fill required to align to the next + block. */ + +#define XTENSA_PROP_LITERAL 0x00000001 +#define XTENSA_PROP_INSN 0x00000002 +#define XTENSA_PROP_DATA 0x00000004 +#define XTENSA_PROP_UNREACHABLE 0x00000008 +/* Instruction-only properties at beginning of code. */ +#define XTENSA_PROP_INSN_LOOP_TARGET 0x00000010 +#define XTENSA_PROP_INSN_BRANCH_TARGET 0x00000020 +/* Instruction-only properties about code. */ +#define XTENSA_PROP_INSN_NO_DENSITY 0x00000040 +#define XTENSA_PROP_INSN_NO_REORDER 0x00000080 +#define XTENSA_PROP_INSN_NO_TRANSFORM 0x00000100 + +/* Branch target alignment information. This transmits information + to the linker optimization about the priority of aligning a + particular block for branch target alignment: None, low priority, + high priority, or required. These only need to be checked in + instruction blocks marked as XTENSA_PROP_INSN_BRANCH_TARGET. + Common usage is: + + switch (GET_XTENSA_PROP_BT_ALIGN(flags)) + case XTENSA_PROP_BT_ALIGN_NONE: + case XTENSA_PROP_BT_ALIGN_LOW: + case XTENSA_PROP_BT_ALIGN_HIGH: + case XTENSA_PROP_BT_ALIGN_REQUIRE: +*/ +#define XTENSA_PROP_BT_ALIGN_MASK 0x00000600 + +/* No branch target alignment. */ +#define XTENSA_PROP_BT_ALIGN_NONE 0x0 +/* Low priority branch target alignment. */ +#define XTENSA_PROP_BT_ALIGN_LOW 0x1 +/* High priority branch target alignment. */ +#define XTENSA_PROP_BT_ALIGN_HIGH 0x2 +/* Required branch target alignment. */ +#define XTENSA_PROP_BT_ALIGN_REQUIRE 0x3 + +#define GET_XTENSA_PROP_BT_ALIGN(flag) \ + (((unsigned)((flag) & (XTENSA_PROP_BT_ALIGN_MASK))) >> 9) +#define SET_XTENSA_PROP_BT_ALIGN(flag, align) \ + (((flag) & (~XTENSA_PROP_BT_ALIGN_MASK)) | \ + (((align) << 9) & XTENSA_PROP_BT_ALIGN_MASK)) + +/* Alignment is specified in the block BEFORE the one that needs + alignment. Up to 5 bits. Use GET_XTENSA_PROP_ALIGNMENT(flags) to + get the required alignment specified as a power of 2. Use + SET_XTENSA_PROP_ALIGNMENT(flags, pow2) to set the required + alignment. Be careful of side effects since the SET will evaluate + flags twice. Also, note that the SIZE of a block in the property + table does not include the alignment size, so the alignment fill + must be calculated to determine if two blocks are contiguous. + TEXT_ALIGN is not currently implemented but is a placeholder for a + possible future implementation. */ + +#define XTENSA_PROP_ALIGN 0x00000800 + +#define XTENSA_PROP_ALIGNMENT_MASK 0x0001f000 + +#define GET_XTENSA_PROP_ALIGNMENT(flag) \ + (((unsigned)((flag) & (XTENSA_PROP_ALIGNMENT_MASK))) >> 12) +#define SET_XTENSA_PROP_ALIGNMENT(flag, align) \ + (((flag) & (~XTENSA_PROP_ALIGNMENT_MASK)) | \ + (((align) << 12) & XTENSA_PROP_ALIGNMENT_MASK)) + +#define XTENSA_PROP_INSN_ABSLIT 0x00020000 + #endif /* _ELF_XTENSA_H */ diff --git a/include/xtensa-config.h b/include/xtensa-config.h index 4191c368575..4ef5d64270f 100644 --- a/include/xtensa-config.h +++ b/include/xtensa-config.h @@ -1,5 +1,5 @@ /* Xtensa configuration settings. - Copyright (C) 2001,2002,2003 Free Software Foundation, Inc. + Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica. This program is free software; you can redistribute it and/or modify @@ -42,6 +42,9 @@ #undef XCHAL_HAVE_L32R #define XCHAL_HAVE_L32R 1 +#undef XSHAL_USE_ABSOLUTE_LITERALS +#define XSHAL_USE_ABSOLUTE_LITERALS 0 + #undef XCHAL_HAVE_MAC16 #define XCHAL_HAVE_MAC16 0 @@ -87,6 +90,9 @@ #undef XCHAL_HAVE_WINDOWED #define XCHAL_HAVE_WINDOWED 1 +#undef XCHAL_HAVE_PREDICTED_BRANCHES +#define XCHAL_HAVE_PREDICTED_BRANCHES 0 + #undef XCHAL_ICACHE_SIZE #define XCHAL_ICACHE_SIZE 8192 @@ -130,10 +136,7 @@ #define XCHAL_DEBUGLEVEL 4 -#undef XCHAL_EXTRA_SA_SIZE -#define XCHAL_EXTRA_SA_SIZE 0 - -#undef XCHAL_EXTRA_SA_ALIGN -#define XCHAL_EXTRA_SA_ALIGN 1 +#undef XCHAL_INST_FETCH_WIDTH +#define XCHAL_INST_FETCH_WIDTH 4 #endif /* !XTENSA_CONFIG_H */ diff --git a/include/xtensa-isa-internal.h b/include/xtensa-isa-internal.h index 7f221eae48e..50ac4781c37 100644 --- a/include/xtensa-isa-internal.h +++ b/include/xtensa-isa-internal.h @@ -1,5 +1,5 @@ /* Internal definitions for configurable Xtensa ISA support. - Copyright 2003 Free Software Foundation, Inc. + Copyright 2003, 2004 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -17,98 +17,215 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* Use the statically-linked version for the GNU tools. */ -#define STATIC_LIBISA 1 +#ifndef XTENSA_ISA_INTERNAL_H +#define XTENSA_ISA_INTERNAL_H -#define ISA_INTERFACE_VERSION 3 +/* Flags. */ -struct config_struct -{ - char *param_name; - char *param_value; -}; - -/* Encode/decode function types for immediate operands. */ -typedef uint32 (*xtensa_immed_decode_fn) (uint32); -typedef xtensa_encode_result (*xtensa_immed_encode_fn) (uint32 *); - -/* Field accessor function types. */ -typedef uint32 (*xtensa_get_field_fn) (const xtensa_insnbuf); -typedef void (*xtensa_set_field_fn) (xtensa_insnbuf, uint32); +#define XTENSA_OPERAND_IS_REGISTER 0x00000001 +#define XTENSA_OPERAND_IS_PCRELATIVE 0x00000002 +#define XTENSA_OPERAND_IS_INVISIBLE 0x00000004 +#define XTENSA_OPERAND_IS_UNKNOWN 0x00000008 -/* PC-relative relocation function types. */ -typedef uint32 (*xtensa_do_reloc_fn) (uint32, uint32); -typedef uint32 (*xtensa_undo_reloc_fn) (uint32, uint32); +#define XTENSA_OPCODE_IS_BRANCH 0x00000001 +#define XTENSA_OPCODE_IS_JUMP 0x00000002 +#define XTENSA_OPCODE_IS_LOOP 0x00000004 +#define XTENSA_OPCODE_IS_CALL 0x00000008 -/* Instruction decode function type. */ -typedef int (*xtensa_insn_decode_fn) (const xtensa_insnbuf); +#define XTENSA_STATE_IS_EXPORTED 0x00000001 -/* Instruction encoding template function type (each of these functions - returns a constant template; they exist only to make it easier for the - TIE compiler to generate endian-independent DLLs). */ -typedef xtensa_insnbuf (*xtensa_encoding_template_fn) (void); +#define XTENSA_INTERFACE_HAS_SIDE_EFFECT 0x00000001 +/* Function pointer typedefs */ +typedef void (*xtensa_format_encode_fn) (xtensa_insnbuf); +typedef void (*xtensa_get_slot_fn) (const xtensa_insnbuf, xtensa_insnbuf); +typedef void (*xtensa_set_slot_fn) (xtensa_insnbuf, const xtensa_insnbuf); +typedef int (*xtensa_opcode_decode_fn) (const xtensa_insnbuf); +typedef uint32 (*xtensa_get_field_fn) (const xtensa_insnbuf); +typedef void (*xtensa_set_field_fn) (xtensa_insnbuf, uint32); +typedef int (*xtensa_immed_decode_fn) (uint32 *); +typedef int (*xtensa_immed_encode_fn) (uint32 *); +typedef int (*xtensa_do_reloc_fn) (uint32 *, uint32); +typedef int (*xtensa_undo_reloc_fn) (uint32 *, uint32); +typedef void (*xtensa_opcode_encode_fn) (xtensa_insnbuf); +typedef int (*xtensa_format_decode_fn) (const xtensa_insnbuf); +typedef int (*xtensa_length_decode_fn) (const char *); + +typedef struct xtensa_format_internal_struct +{ + const char *name; /* Instruction format name. */ + int length; /* Instruction length in bytes. */ + xtensa_format_encode_fn encode_fn; + int num_slots; + int *slot_id; /* Array[num_slots] of slot IDs. */ +} xtensa_format_internal; + +typedef struct xtensa_slot_internal_struct +{ + const char *name; /* Not necessarily unique. */ + const char *format; + int position; + xtensa_get_slot_fn get_fn; + xtensa_set_slot_fn set_fn; + xtensa_get_field_fn *get_field_fns; /* Array[field_id]. */ + xtensa_set_field_fn *set_field_fns; /* Array[field_id]. */ + xtensa_opcode_decode_fn opcode_decode_fn; + const char *nop_name; +} xtensa_slot_internal; typedef struct xtensa_operand_internal_struct { - char *operand_kind; /* e.g., "a", "f", "i", "l".... */ - char inout; /* '<', '>', or '='. */ - char isPCRelative; /* Is this a PC-relative offset? */ - xtensa_get_field_fn get_field; /* Get encoded value of the field. */ - xtensa_set_field_fn set_field; /* Set field with an encoded value. */ + const char *name; + int field_id; + xtensa_regfile regfile; /* Register file. */ + int num_regs; /* Usually 1; 2 for reg pairs, etc. */ + uint32 flags; /* See XTENSA_OPERAND_* flags. */ xtensa_immed_encode_fn encode; /* Encode the operand value. */ xtensa_immed_decode_fn decode; /* Decode the value from the field. */ - xtensa_do_reloc_fn do_reloc; /* Perform a PC-relative relocation. */ + xtensa_do_reloc_fn do_reloc; /* Perform a PC-relative reloc. */ xtensa_undo_reloc_fn undo_reloc; /* Undo a PC-relative relocation. */ } xtensa_operand_internal; +typedef struct xtensa_arg_internal_struct +{ + union { + int operand_id; /* For normal operands. */ + xtensa_state state; /* For stateOperands. */ + } u; + char inout; /* Direction: 'i', 'o', or 'm'. */ +} xtensa_arg_internal; typedef struct xtensa_iclass_internal_struct { int num_operands; /* Size of "operands" array. */ - xtensa_operand_internal **operands; /* Array of operand structures. */ -} xtensa_iclass_internal; + xtensa_arg_internal *operands; /* Array[num_operands]. */ + int num_stateOperands; /* Size of "stateOperands" array. */ + xtensa_arg_internal *stateOperands; /* Array[num_stateOperands]. */ + + int num_interfaceOperands; /* Size of "interfaceOperands". */ + xtensa_interface *interfaceOperands; /* Array[num_interfaceOperands]. */ +} xtensa_iclass_internal; typedef struct xtensa_opcode_internal_struct { const char *name; /* Opcode mnemonic. */ - int length; /* Length in bytes of the insn. */ - xtensa_encoding_template_fn template; /* Fn returning encoding template. */ - xtensa_iclass_internal *iclass; /* Iclass for this opcode. */ + int iclass_id; /* Iclass for this opcode. */ + uint32 flags; /* See XTENSA_OPCODE_* flags. */ + xtensa_opcode_encode_fn *encode_fns; /* Array[slot_id]. */ + int num_funcUnit_uses; /* Number of funcUnit_use entries. */ + xtensa_funcUnit_use *funcUnit_uses; /* Array[num_funcUnit_uses]. */ } xtensa_opcode_internal; +typedef struct xtensa_regfile_internal_struct +{ + const char *name; /* Full name of the regfile. */ + const char *shortname; /* Abbreviated name. */ + xtensa_regfile parent; /* View parent (or identity). */ + int num_bits; /* Width of the registers. */ + int num_entries; /* Number of registers. */ +} xtensa_regfile_internal; + +typedef struct xtensa_interface_internal_struct +{ + const char *name; /* Interface name. */ + int num_bits; /* Width of the interface. */ + uint32 flags; /* See XTENSA_INTERFACE_* flags. */ + char inout; /* "i" or "o". */ +} xtensa_interface_internal; + +typedef struct xtensa_funcUnit_internal_struct +{ + const char *name; /* Functional unit name. */ + int num_copies; /* Number of instances. */ +} xtensa_funcUnit_internal; -typedef struct opname_lookup_entry_struct +typedef struct xtensa_state_internal_struct { - const char *key; /* Opcode mnemonic. */ - xtensa_opcode opcode; /* Internal opcode number. */ -} opname_lookup_entry; + const char *name; /* State name. */ + int num_bits; /* Number of state bits. */ + uint32 flags; /* See XTENSA_STATE_* flags. */ +} xtensa_state_internal; +typedef struct xtensa_sysreg_internal_struct +{ + const char *name; /* Register name. */ + int number; /* Register number. */ + int is_user; /* Non-zero if a "user register". */ +} xtensa_sysreg_internal; + +typedef struct xtensa_lookup_entry_struct +{ + const char *key; + union + { + xtensa_opcode opcode; /* Internal opcode number. */ + xtensa_sysreg sysreg; /* Internal sysreg number. */ + xtensa_state state; /* Internal state number. */ + xtensa_interface intf; /* Internal interface number. */ + xtensa_funcUnit fun; /* Internal funcUnit number. */ + } u; +} xtensa_lookup_entry; typedef struct xtensa_isa_internal_struct { int is_big_endian; /* Endianness. */ int insn_size; /* Maximum length in bytes. */ int insnbuf_size; /* Number of insnbuf_words. */ - int num_opcodes; /* Total number for all modules. */ - xtensa_opcode_internal **opcode_table;/* Indexed by internal opcode #. */ - int num_modules; /* Number of modules (DLLs) loaded. */ - int *module_opcode_base; /* Starting opcode # for each module. */ - xtensa_insn_decode_fn *module_decode_fn; /* Decode fn for each module. */ - opname_lookup_entry *opname_lookup_table; /* Lookup table for each module. */ - struct config_struct *config; /* Table of configuration parameters. */ - int has_density; /* Is density option available? */ -} xtensa_isa_internal; + int num_formats; + xtensa_format_internal *formats; + xtensa_format_decode_fn format_decode_fn; + xtensa_length_decode_fn length_decode_fn; -typedef struct xtensa_isa_module_struct -{ - int (*get_num_opcodes_fn) (void); - xtensa_opcode_internal **(*get_opcodes_fn) (void); - int (*decode_insn_fn) (const xtensa_insnbuf); - struct config_struct *(*get_config_table_fn) (void); -} xtensa_isa_module; + int num_slots; + xtensa_slot_internal *slots; + + int num_fields; + + int num_operands; + xtensa_operand_internal *operands; + + int num_iclasses; + xtensa_iclass_internal *iclasses; + + int num_opcodes; + xtensa_opcode_internal *opcodes; + xtensa_lookup_entry *opname_lookup_table; + + int num_regfiles; + xtensa_regfile_internal *regfiles; + + int num_states; + xtensa_state_internal *states; + xtensa_lookup_entry *state_lookup_table; + + int num_sysregs; + xtensa_sysreg_internal *sysregs; + xtensa_lookup_entry *sysreg_lookup_table; + + /* The current Xtensa ISA only supports 256 of each kind of sysreg so + we can get away with implementing lookups with tables indexed by + the register numbers. If we ever allow larger sysreg numbers, this + may have to be reimplemented. The first entry in the following + arrays corresponds to "special" registers and the second to "user" + registers. */ + int max_sysreg_num[2]; + xtensa_sysreg *sysreg_table[2]; + + int num_interfaces; + xtensa_interface_internal *interfaces; + xtensa_lookup_entry *interface_lookup_table; + + int num_funcUnits; + xtensa_funcUnit_internal *funcUnits; + xtensa_lookup_entry *funcUnit_lookup_table; + +} xtensa_isa_internal; + +extern int xtensa_isa_name_compare (const void *, const void *); -extern xtensa_isa_module xtensa_isa_modules[]; +extern xtensa_isa_status xtisa_errno; +extern char xtisa_error_msg[]; +#endif /* !XTENSA_ISA_INTERNAL_H */ diff --git a/include/xtensa-isa.h b/include/xtensa-isa.h index 54f750c9a1a..2dc11b924c0 100644 --- a/include/xtensa-isa.h +++ b/include/xtensa-isa.h @@ -1,5 +1,5 @@ /* Interface definition for configurable Xtensa ISA support. - Copyright 2003 Free Software Foundation, Inc. + Copyright 2003, 2004 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -20,209 +20,763 @@ #ifndef XTENSA_LIBISA_H #define XTENSA_LIBISA_H -/* Use the statically-linked version for the GNU tools. */ -#define STATIC_LIBISA 1 - #ifdef __cplusplus extern "C" { #endif +/* Use the statically-linked version for the GNU tools. */ +#define STATIC_LIBISA 1 + +/* Version number: This is intended to help support code that works with + versions of this library from multiple Xtensa releases. */ + +#define XTENSA_ISA_VERSION 7000 + #ifndef uint32 #define uint32 unsigned int #endif -/* This file defines the interface to the Xtensa ISA library. This library - contains most of the ISA-specific information for a particular Xtensa - processor. For example, the set of valid instructions, their opcode - encodings and operand fields are all included here. To support Xtensa's - configurability and user-defined instruction extensions (i.e., TIE), the - library is initialized by loading one or more dynamic libraries; only a - small set of interface code is present in the statically-linked portion - of the library. +/* This file defines the interface to the Xtensa ISA library. This + library contains most of the ISA-specific information for a + particular Xtensa processor. For example, the set of valid + instructions, their opcode encodings and operand fields are all + included here. - This interface basically defines four abstract data types. + This interface basically defines a number of abstract data types. . an instruction buffer - for holding the raw instruction bits . ISA info - information about the ISA as a whole - . opcode info - information about individual instructions - . operand info - information about specific instruction operands - - It would be nice to implement these as classes in C++, but the library is - implemented in C to match the expectations of the GNU tools. - Instead, the interface defines a set of functions to access each data - type. With the exception of the instruction buffer, the internal - representations of the data structures are hidden. All accesses must be - made through the functions defined here. */ + . instruction formats - instruction size and slot structure + . opcodes - information about individual instructions + . operands - information about register and immediate instruction operands + . stateOperands - information about processor state instruction operands + . interfaceOperands - information about interface instruction operands + . register files - register file information + . processor states - internal processor state information + . system registers - "special registers" and "user registers" + . interfaces - TIE interfaces that are external to the processor + . functional units - TIE shared functions + + The interface defines a set of functions to access each data type. + With the exception of the instruction buffer, the internal + representations of the data structures are hidden. All accesses must + be made through the functions defined here. */ + +typedef struct xtensa_isa_opaque { int unused; } *xtensa_isa; + + +/* Opcodes, formats, regfiles, states, sysregs, ctypes, and protos are + represented here using sequential integers beginning with 0. The + specific values are only fixed for a particular instantiation of an + xtensa_isa structure, so these values should only be used + internally. */ -typedef void* xtensa_isa; -typedef void* xtensa_operand; - - -/* Opcodes are represented here using sequential integers beginning with 0. - The specific value used for a particular opcode is only fixed for a - particular instantiation of an xtensa_isa structure, so these values - should only be used internally. */ typedef int xtensa_opcode; - -/* Define a unique value for undefined opcodes ("static const int" doesn't - seem to work for this because EGCS 1.0.3 on i686-Linux without -O won't - allow it to be used as an initializer). */ -#define XTENSA_UNDEFINED -1 +typedef int xtensa_format; +typedef int xtensa_regfile; +typedef int xtensa_state; +typedef int xtensa_sysreg; +typedef int xtensa_interface; +typedef int xtensa_funcUnit; -typedef int libisa_module_specifier; +/* Define a unique value for undefined items. */ -extern xtensa_isa xtensa_isa_init (void); +#define XTENSA_UNDEFINED -1 +/* Overview of using this interface to decode/encode instructions: + + Each Xtensa instruction is associated with a particular instruction + format, where the format defines a fixed number of slots for + operations. The formats for the core Xtensa ISA have only one slot, + but FLIX instructions may have multiple slots. Within each slot, + there is a single opcode and some number of associated operands. + + The encoding and decoding functions operate on instruction buffers, + not on the raw bytes of the instructions. The same instruction + buffer data structure is used for both entire instructions and + individual slots in those instructions -- the contents of a slot need + to be extracted from or inserted into the buffer for the instruction + as a whole. + + Decoding an instruction involves first finding the format, which + identifies the number of slots, and then decoding each slot + separately. A slot is decoded by finding the opcode and then using + the opcode to determine how many operands there are. For example: + + xtensa_insnbuf_from_chars + xtensa_format_decode + for each slot { + xtensa_format_get_slot + xtensa_opcode_decode + for each operand { + xtensa_operand_get_field + xtensa_operand_decode + } + } + + Encoding an instruction is roughly the same procedure in reverse: + + xtensa_format_encode + for each slot { + xtensa_opcode_encode + for each operand { + xtensa_operand_encode + xtensa_operand_set_field + } + xtensa_format_set_slot + } + xtensa_insnbuf_to_chars +*/ + + +/* Error handling. */ + +/* Error codes. The code for the most recent error condition can be + retrieved with the "errno" function. For any result other than + xtensa_isa_ok, an error message containing additional information + about the problem can be retrieved using the "error_msg" function. + The error messages are stored in an internal buffer, which should not + should be freed and may be overwritten by subsequent operations. */ + +typedef enum xtensa_isa_status_enum +{ + xtensa_isa_ok = 0, + xtensa_isa_bad_format, + xtensa_isa_bad_slot, + xtensa_isa_bad_opcode, + xtensa_isa_bad_operand, + xtensa_isa_bad_field, + xtensa_isa_bad_iclass, + xtensa_isa_bad_regfile, + xtensa_isa_bad_sysreg, + xtensa_isa_bad_state, + xtensa_isa_bad_interface, + xtensa_isa_bad_funcUnit, + xtensa_isa_wrong_slot, + xtensa_isa_no_field, + xtensa_isa_out_of_memory, + xtensa_isa_buffer_overflow, + xtensa_isa_internal_error, + xtensa_isa_bad_value +} xtensa_isa_status; + +extern xtensa_isa_status +xtensa_isa_errno (xtensa_isa isa); + +extern char * +xtensa_isa_error_msg (xtensa_isa isa); + + /* Instruction buffers. */ typedef uint32 xtensa_insnbuf_word; typedef xtensa_insnbuf_word *xtensa_insnbuf; -/* Get the size in words of the xtensa_insnbuf array. */ -extern int xtensa_insnbuf_size (xtensa_isa); -/* Allocate (with malloc) an xtensa_insnbuf of the right size. */ -extern xtensa_insnbuf xtensa_insnbuf_alloc (xtensa_isa); +/* Get the size in "insnbuf_words" of the xtensa_insnbuf array. */ -/* Release (with free) an xtensa_insnbuf of the right size. */ -extern void xtensa_insnbuf_free (xtensa_insnbuf); +extern int +xtensa_insnbuf_size (xtensa_isa isa); -/* Inward and outward conversion from memory images (byte streams) to our - internal instruction representation. */ -extern void xtensa_insnbuf_to_chars (xtensa_isa, const xtensa_insnbuf, - char *); -extern void xtensa_insnbuf_from_chars (xtensa_isa, xtensa_insnbuf, - const char *); +/* Allocate an xtensa_insnbuf of the right size. */ +extern xtensa_insnbuf +xtensa_insnbuf_alloc (xtensa_isa isa); -/* ISA information. */ -/* Load the ISA information from a shared library. If successful, this returns - a value which identifies the ISA for use in subsequent calls to the ISA - library; otherwise, it returns NULL. Multiple ISAs can be loaded to support - heterogeneous multiprocessor systems. */ -extern xtensa_isa xtensa_load_isa (libisa_module_specifier); +/* Release an xtensa_insnbuf. */ + +extern void +xtensa_insnbuf_free (xtensa_isa isa, xtensa_insnbuf buf); + -/* Extend an existing set of ISA information by loading an additional shared - library of ISA information. This is primarily intended for loading TIE - extensions. If successful, the return value is non-zero. */ -extern int xtensa_extend_isa (xtensa_isa, libisa_module_specifier); +/* Conversion between raw memory (char arrays) and our internal + instruction representation. This is complicated by the Xtensa ISA's + variable instruction lengths. When converting to chars, the buffer + must contain a valid instruction so we know how many bytes to copy; + thus, the "to_chars" function returns the number of bytes copied or + XTENSA_UNDEFINED on error. The "from_chars" function first reads the + minimal number of bytes required to decode the instruction length and + then proceeds to copy the entire instruction into the buffer; if the + memory does not contain a valid instruction, it copies the maximum + number of bytes required for the longest Xtensa instruction. The + "num_chars" argument may be used to limit the number of bytes that + can be read or written. Otherwise, if "num_chars" is zero, the + functions may read or write past the end of the code. */ -/* The default ISA. This variable is set automatically to the ISA most - recently loaded and is provided as a convenience. An exception is the GNU - opcodes library, where there is a fixed interface that does not allow - passing the ISA as a parameter and the ISA must be taken from this global - variable. (Note: Since this variable is just a convenience, it is not - exported when libisa is built as a DLL, due to the hassle of dealing with - declspecs.) */ -extern xtensa_isa xtensa_default_isa; +extern int +xtensa_insnbuf_to_chars (xtensa_isa isa, const xtensa_insnbuf insn, + char *cp, int num_chars); + +extern void +xtensa_insnbuf_from_chars (xtensa_isa isa, xtensa_insnbuf insn, + const char *cp, int num_chars); + + +/* ISA information. */ + +/* Initialize the ISA information. */ + +extern xtensa_isa +xtensa_isa_init (xtensa_isa_status *errno_p, char **error_msg_p); /* Deallocate an xtensa_isa structure. */ -extern void xtensa_isa_free (xtensa_isa); + +extern void +xtensa_isa_free (xtensa_isa isa); + /* Get the maximum instruction size in bytes. */ -extern int xtensa_insn_maxlength (xtensa_isa); -/* Get the total number of opcodes for this processor. */ -extern int xtensa_num_opcodes (xtensa_isa); +extern int +xtensa_isa_maxlength (xtensa_isa isa); + + +/* Decode the length in bytes of an instruction in raw memory (not an + insnbuf). This function reads only the minimal number of bytes + required to decode the instruction length. Returns + XTENSA_UNDEFINED on error. */ + +extern int +xtensa_isa_length_from_chars (xtensa_isa isa, const char *cp); + + +/* Get the number of stages in the processor's pipeline. The pipeline + stage values returned by other functions in this library will range + from 0 to N-1, where N is the value returned by this function. + Note that the stage numbers used here may not correspond to the + actual processor hardware, e.g., the hardware may have additional + stages before stage 0. Returns XTENSA_UNDEFINED on error. */ + +extern int +xtensa_isa_num_pipe_stages (xtensa_isa isa); + + +/* Get the number of various entities that are defined for this processor. */ + +extern int +xtensa_isa_num_formats (xtensa_isa isa); + +extern int +xtensa_isa_num_opcodes (xtensa_isa isa); + +extern int +xtensa_isa_num_regfiles (xtensa_isa isa); + +extern int +xtensa_isa_num_states (xtensa_isa isa); + +extern int +xtensa_isa_num_sysregs (xtensa_isa isa); + +extern int +xtensa_isa_num_interfaces (xtensa_isa isa); + +extern int +xtensa_isa_num_funcUnits (xtensa_isa isa); + + +/* Instruction formats. */ + +/* Get the name of a format. Returns null on error. */ + +extern const char * +xtensa_format_name (xtensa_isa isa, xtensa_format fmt); + + +/* Given a format name, return the format number. Returns + XTENSA_UNDEFINED if the name is not a valid format. */ + +extern xtensa_format +xtensa_format_lookup (xtensa_isa isa, const char *fmtname); + + +/* Decode the instruction format from a binary instruction buffer. + Returns XTENSA_UNDEFINED if the format is not recognized. */ + +extern xtensa_format +xtensa_format_decode (xtensa_isa isa, const xtensa_insnbuf insn); + + +/* Set the instruction format field(s) in a binary instruction buffer. + All the other fields are set to zero. Returns non-zero on error. */ + +extern int +xtensa_format_encode (xtensa_isa isa, xtensa_format fmt, xtensa_insnbuf insn); + + +/* Find the length (in bytes) of an instruction. Returns + XTENSA_UNDEFINED on error. */ + +extern int +xtensa_format_length (xtensa_isa isa, xtensa_format fmt); + + +/* Get the number of slots in an instruction. Returns XTENSA_UNDEFINED + on error. */ + +extern int +xtensa_format_num_slots (xtensa_isa isa, xtensa_format fmt); + + +/* Get the opcode for a no-op in a particular slot. + Returns XTENSA_UNDEFINED on error. */ + +extern xtensa_opcode +xtensa_format_slot_nop_opcode (xtensa_isa isa, xtensa_format fmt, int slot); + + +/* Get the bits for a specified slot out of an insnbuf for the + instruction as a whole and put them into an insnbuf for that one + slot, and do the opposite to set a slot. Return non-zero on error. */ + +extern int +xtensa_format_get_slot (xtensa_isa isa, xtensa_format fmt, int slot, + const xtensa_insnbuf insn, xtensa_insnbuf slotbuf); + +extern int +xtensa_format_set_slot (xtensa_isa isa, xtensa_format fmt, int slot, + xtensa_insnbuf insn, const xtensa_insnbuf slotbuf); + + +/* Opcode information. */ /* Translate a mnemonic name to an opcode. Returns XTENSA_UNDEFINED if the name is not a valid opcode mnemonic. */ -extern xtensa_opcode xtensa_opcode_lookup (xtensa_isa, const char *); -/* Decode a binary instruction buffer. Returns the opcode or - XTENSA_UNDEFINED if the instruction is illegal. */ -extern xtensa_opcode xtensa_decode_insn (xtensa_isa, const xtensa_insnbuf); +extern xtensa_opcode +xtensa_opcode_lookup (xtensa_isa isa, const char *opname); -/* Opcode information. */ +/* Decode the opcode for one instruction slot from a binary instruction + buffer. Returns the opcode or XTENSA_UNDEFINED if the opcode is + illegal. */ + +extern xtensa_opcode +xtensa_opcode_decode (xtensa_isa isa, xtensa_format fmt, int slot, + const xtensa_insnbuf slotbuf); + -/* Set the opcode field(s) in a binary instruction buffer. The operand - fields are set to zero. */ -extern void xtensa_encode_insn (xtensa_isa, xtensa_opcode, xtensa_insnbuf); +/* Set the opcode field(s) for an instruction slot. All other fields + in the slot are set to zero. Returns non-zero if the opcode cannot + be encoded. */ -/* Get the mnemonic name for an opcode. */ -extern const char * xtensa_opcode_name (xtensa_isa, xtensa_opcode); +extern int +xtensa_opcode_encode (xtensa_isa isa, xtensa_format fmt, int slot, + xtensa_insnbuf slotbuf, xtensa_opcode opc); -/* Find the length (in bytes) of an instruction. */ -extern int xtensa_insn_length (xtensa_isa, xtensa_opcode); -/* Find the length of an instruction by looking only at the first byte. */ -extern int xtensa_insn_length_from_first_byte (xtensa_isa, char); +/* Get the mnemonic name for an opcode. Returns null on error. */ -/* Find the number of operands for an instruction. */ -extern int xtensa_num_operands (xtensa_isa, xtensa_opcode); +extern const char * +xtensa_opcode_name (xtensa_isa isa, xtensa_opcode opc); -/* Get the information about operand number "opnd" of a particular opcode. */ -extern xtensa_operand xtensa_get_operand (xtensa_isa, xtensa_opcode, int); +/* Check various properties of opcodes. These functions return 0 if + the condition is false, 1 if the condition is true, and + XTENSA_UNDEFINED on error. The instructions are classified as + follows: + + branch: conditional branch; may fall through to next instruction (B*) + jump: unconditional branch (J, JX, RET*, RF*) + loop: zero-overhead loop (LOOP*) + call: unconditional call; control returns to next instruction (CALL*) + + For the opcodes that affect control flow in some way, the branch + target may be specified by an immediate operand or it may be an + address stored in a register. You can distinguish these by + checking if the instruction has a PC-relative immediate + operand. */ + +extern int +xtensa_opcode_is_branch (xtensa_isa isa, xtensa_opcode opc); + +extern int +xtensa_opcode_is_jump (xtensa_isa isa, xtensa_opcode opc); + +extern int +xtensa_opcode_is_loop (xtensa_isa isa, xtensa_opcode opc); + +extern int +xtensa_opcode_is_call (xtensa_isa isa, xtensa_opcode opc); + + +/* Find the number of ordinary operands, state operands, and interface + operands for an instruction. These return XTENSA_UNDEFINED on + error. */ + +extern int +xtensa_opcode_num_operands (xtensa_isa isa, xtensa_opcode opc); + + +extern int +xtensa_opcode_num_stateOperands (xtensa_isa isa, xtensa_opcode opc); + +extern int +xtensa_opcode_num_interfaceOperands (xtensa_isa isa, xtensa_opcode opc); + + +/* Get functional unit usage requirements for an opcode. Each "use" + is identified by a pair. The + "num_funcUnit_uses" function returns the number of these "uses" or + XTENSA_UNDEFINED on error. The "funcUnit_use" function returns + a pointer to a "use" pair or null on error. */ + +typedef struct xtensa_funcUnit_use_struct +{ + xtensa_funcUnit unit; + int stage; +} xtensa_funcUnit_use; + +extern int +xtensa_opcode_num_funcUnit_uses (xtensa_isa isa, xtensa_opcode opc); + +extern xtensa_funcUnit_use * +xtensa_opcode_funcUnit_use (xtensa_isa isa, xtensa_opcode opc, int u); + + /* Operand information. */ -/* Find the kind of operand. There are three possibilities: - 1) PC-relative immediates (e.g., "l", "L"). These can be identified with - the xtensa_operand_isPCRelative function. - 2) non-PC-relative immediates ("i"). - 3) register-file short names (e.g., "a", "b", "m" and others defined - via TIE). */ -extern char * xtensa_operand_kind (xtensa_operand); +/* Get the name of an operand. Returns null on error. */ + +extern const char * +xtensa_operand_name (xtensa_isa isa, xtensa_opcode opc, int opnd); + + +/* Some operands are "invisible", i.e., not explicitly specified in + assembly language. When assembling an instruction, you need not set + the values of invisible operands, since they are either hardwired or + derived from other field values. The values of invisible operands + can be examined in the same way as other operands, but remember that + an invisible operand may get its value from another visible one, so + the entire instruction must be available before examining the + invisible operand values. This function returns 1 if an operand is + visible, 0 if it is invisible, or XTENSA_UNDEFINED on error. Note + that whether an operand is visible is orthogonal to whether it is + "implicit", i.e., whether it is encoded in a field in the + instruction. */ + +extern int +xtensa_operand_is_visible (xtensa_isa isa, xtensa_opcode opc, int opnd); -/* Check if an operand is an input ('<'), output ('>'), or inout ('=') + +/* Check if an operand is an input ('i'), output ('o'), or inout ('m') operand. Note: The output operand of a conditional assignment - (e.g., movnez) appears here as an inout ('=') even if it is declared - in the TIE code as an output ('>'); this allows the compiler to - properly handle register allocation for conditional assignments. */ -extern char xtensa_operand_inout (xtensa_operand); + (e.g., movnez) appears here as an inout ('m') even if it is declared + in the TIE code as an output ('o'); this allows the compiler to + properly handle register allocation for conditional assignments. + Returns 0 on error. */ + +extern char +xtensa_operand_inout (xtensa_isa isa, xtensa_opcode opc, int opnd); + /* Get and set the raw (encoded) value of the field for the specified operand. The "set" function does not check if the value fits in the - field; that is done by the "encode" function below. */ -extern uint32 xtensa_operand_get_field (xtensa_operand, const xtensa_insnbuf); + field; that is done by the "encode" function below. Both of these + functions return non-zero on error, e.g., if the field is not defined + for the specified slot. */ + +extern int +xtensa_operand_get_field (xtensa_isa isa, xtensa_opcode opc, int opnd, + xtensa_format fmt, int slot, + const xtensa_insnbuf slotbuf, uint32 *valp); -extern void xtensa_operand_set_field (xtensa_operand, xtensa_insnbuf, uint32); +extern int +xtensa_operand_set_field (xtensa_isa isa, xtensa_opcode opc, int opnd, + xtensa_format fmt, int slot, + xtensa_insnbuf slotbuf, uint32 val); -/* Encode and decode operands. The raw bits in the operand field - may be encoded in a variety of different ways. These functions hide the - details of that encoding. The encode function has a special return type - (xtensa_encode_result) to indicate success or the reason for failure; the - encoded value is returned through the argument pointer. The decode function - has no possibility of failure and returns the decoded value. */ +/* Encode and decode operands. The raw bits in the operand field may + be encoded in a variety of different ways. These functions hide + the details of that encoding. The result values are returned through + the argument pointer. The return value is non-zero on error. */ -typedef enum -{ - xtensa_encode_result_ok, - xtensa_encode_result_align, - xtensa_encode_result_not_in_table, - xtensa_encode_result_too_low, - xtensa_encode_result_too_high, - xtensa_encode_result_not_ok, - xtensa_encode_result_max = xtensa_encode_result_not_ok -} xtensa_encode_result; +extern int +xtensa_operand_encode (xtensa_isa isa, xtensa_opcode opc, int opnd, + uint32 *valp); + +extern int +xtensa_operand_decode (xtensa_isa isa, xtensa_opcode opc, int opnd, + uint32 *valp); + + +/* An operand may be either a register operand or an immediate of some + sort (e.g., PC-relative or not). The "is_register" function returns + 0 if the operand is an immediate, 1 if it is a register, and + XTENSA_UNDEFINED on error. The "regfile" function returns the + regfile for a register operand, or XTENSA_UNDEFINED on error. */ + +extern int +xtensa_operand_is_register (xtensa_isa isa, xtensa_opcode opc, int opnd); + +extern xtensa_regfile +xtensa_operand_regfile (xtensa_isa isa, xtensa_opcode opc, int opnd); + + +/* Register operands may span multiple consecutive registers, e.g., a + 64-bit data type may occupy two 32-bit registers. Only the first + register is encoded in the operand field. This function specifies + the number of consecutive registers occupied by this operand. For + non-register operands, the return value is undefined. Returns + XTENSA_UNDEFINED on error. */ + +extern int +xtensa_operand_num_regs (xtensa_isa isa, xtensa_opcode opc, int opnd); + + +/* Some register operands do not completely identify the register being + accessed. For example, the operand value may be added to an internal + state value. By definition, this implies that the corresponding + regfile is not allocatable. Unknown registers should generally be + treated with worst-case assumptions. The function returns 0 if the + register value is unknown, 1 if known, and XTENSA_UNDEFINED on + error. */ + +extern int +xtensa_operand_is_known_reg (xtensa_isa isa, xtensa_opcode opc, int opnd); + + +/* Check if an immediate operand is PC-relative. Returns 0 for register + operands and non-PC-relative immediates, 1 for PC-relative + immediates, and XTENSA_UNDEFINED on error. */ + +extern int +xtensa_operand_is_PCrelative (xtensa_isa isa, xtensa_opcode opc, int opnd); + + +/* For PC-relative offset operands, the interpretation of the offset may + vary between opcodes, e.g., is it relative to the current PC or that + of the next instruction? The following functions are defined to + perform PC-relative relocations and to undo them (as in the + disassembler). The "do_reloc" function takes the desired address + value and the PC of the current instruction and sets the value to the + corresponding PC-relative offset (which can then be encoded and + stored into the operand field). The "undo_reloc" function takes the + unencoded offset value and the current PC and sets the value to the + appropriate address. The return values are non-zero on error. Note + that these functions do not replace the encode/decode functions; the + operands must be encoded/decoded separately and the encode functions + are responsible for detecting invalid operand values. */ + +extern int +xtensa_operand_do_reloc (xtensa_isa isa, xtensa_opcode opc, int opnd, + uint32 *valp, uint32 pc); + +extern int +xtensa_operand_undo_reloc (xtensa_isa isa, xtensa_opcode opc, int opnd, + uint32 *valp, uint32 pc); + + +/* State Operands. */ + +/* Get the state accessed by a state operand. Returns XTENSA_UNDEFINED + on error. */ + +extern xtensa_state +xtensa_stateOperand_state (xtensa_isa isa, xtensa_opcode opc, int stOp); + + +/* Check if a state operand is an input ('i'), output ('o'), or inout + ('m') operand. Returns 0 on error. */ + +extern char +xtensa_stateOperand_inout (xtensa_isa isa, xtensa_opcode opc, int stOp); + + +/* Interface Operands. */ + +/* Get the external interface accessed by an interface operand. + Returns XTENSA_UNDEFINED on error. */ + +extern xtensa_interface +xtensa_interfaceOperand_interface (xtensa_isa isa, xtensa_opcode opc, + int ifOp); + + +/* Register Files. */ + +/* Regfiles include both "real" regfiles and "views", where a view + allows a group of adjacent registers in a real "parent" regfile to be + viewed as a single register. A regfile view has all the same + properties as its parent except for its (long) name, bit width, number + of entries, and default ctype. You can use the parent function to + distinguish these two classes. */ + +/* Look up a regfile by either its name or its abbreviated "short name". + Returns XTENSA_UNDEFINED on error. The "lookup_shortname" function + ignores "view" regfiles since they always have the same shortname as + their parents. */ + +extern xtensa_regfile +xtensa_regfile_lookup (xtensa_isa isa, const char *name); + +extern xtensa_regfile +xtensa_regfile_lookup_shortname (xtensa_isa isa, const char *shortname); + + +/* Get the name or abbreviated "short name" of a regfile. + Returns null on error. */ + +extern const char * +xtensa_regfile_name (xtensa_isa isa, xtensa_regfile rf); + +extern const char * +xtensa_regfile_shortname (xtensa_isa isa, xtensa_regfile rf); + + +/* Get the parent regfile of a "view" regfile. If the regfile is not a + view, the result is the same as the input parameter. Returns + XTENSA_UNDEFINED on error. */ + +extern xtensa_regfile +xtensa_regfile_view_parent (xtensa_isa isa, xtensa_regfile rf); + + +/* Get the bit width of a regfile or regfile view. + Returns XTENSA_UNDEFINED on error. */ + +extern int +xtensa_regfile_num_bits (xtensa_isa isa, xtensa_regfile rf); + + +/* Get the number of regfile entries. Returns XTENSA_UNDEFINED on + error. */ + +extern int +xtensa_regfile_num_entries (xtensa_isa isa, xtensa_regfile rf); + + +/* Processor States. */ + +/* Look up a state by name. Returns XTENSA_UNDEFINED on error. */ + +extern xtensa_state +xtensa_state_lookup (xtensa_isa isa, const char *name); + + +/* Get the name for a processor state. Returns null on error. */ + +extern const char * +xtensa_state_name (xtensa_isa isa, xtensa_state st); + + +/* Get the bit width for a processor state. + Returns XTENSA_UNDEFINED on error. */ + +extern int +xtensa_state_num_bits (xtensa_isa isa, xtensa_state st); + + +/* Check if a state is exported from the processor core. Returns 0 if + the condition is false, 1 if the condition is true, and + XTENSA_UNDEFINED on error. */ + +extern int +xtensa_state_is_exported (xtensa_isa isa, xtensa_state st); + + +/* Sysregs ("special registers" and "user registers"). */ + +/* Look up a register by its number and whether it is a "user register" + or a "special register". Returns XTENSA_UNDEFINED if the sysreg does + not exist. */ + +extern xtensa_sysreg +xtensa_sysreg_lookup (xtensa_isa isa, int num, int is_user); + + +/* Check if there exists a sysreg with a given name. + If not, this function returns XTENSA_UNDEFINED. */ + +extern xtensa_sysreg +xtensa_sysreg_lookup_name (xtensa_isa isa, const char *name); + + +/* Get the name of a sysreg. Returns null on error. */ + +extern const char * +xtensa_sysreg_name (xtensa_isa isa, xtensa_sysreg sysreg); + + +/* Get the register number. Returns XTENSA_UNDEFINED on error. */ + +extern int +xtensa_sysreg_number (xtensa_isa isa, xtensa_sysreg sysreg); + + +/* Check if a sysreg is a "special register" or a "user register". + Returns 0 for special registers, 1 for user registers and + XTENSA_UNDEFINED on error. */ + +extern int +xtensa_sysreg_is_user (xtensa_isa isa, xtensa_sysreg sysreg); + + +/* Interfaces. */ + +/* Find an interface by name. The return value is XTENSA_UNDEFINED if + the specified interface is not found. */ + +extern xtensa_interface +xtensa_interface_lookup (xtensa_isa isa, const char *ifname); + + +/* Get the name of an interface. Returns null on error. */ + +extern const char * +xtensa_interface_name (xtensa_isa isa, xtensa_interface intf); + + +/* Get the bit width for an interface. + Returns XTENSA_UNDEFINED on error. */ + +extern int +xtensa_interface_num_bits (xtensa_isa isa, xtensa_interface intf); + + +/* Check if an interface is an input ('i') or output ('o') with respect + to the Xtensa processor core. Returns 0 on error. */ + +extern char +xtensa_interface_inout (xtensa_isa isa, xtensa_interface intf); + + +/* Check if accessing an interface has potential side effects. + Currently "data" interfaces have side effects and "control" + interfaces do not. Returns 1 if there are side effects, 0 if not, + and XTENSA_UNDEFINED on error. */ + +extern int +xtensa_interface_has_side_effect (xtensa_isa isa, xtensa_interface intf); + + +/* Functional Units. */ + +/* Find a functional unit by name. The return value is XTENSA_UNDEFINED if + the specified unit is not found. */ + +extern xtensa_funcUnit +xtensa_funcUnit_lookup (xtensa_isa isa, const char *fname); -extern xtensa_encode_result xtensa_operand_encode (xtensa_operand, uint32 *); -extern uint32 xtensa_operand_decode (xtensa_operand, uint32); +/* Get the name of a functional unit. Returns null on error. */ +extern const char * +xtensa_funcUnit_name (xtensa_isa isa, xtensa_funcUnit fun); -/* For PC-relative offset operands, the interpretation of the offset may vary - between opcodes, e.g., is it relative to the current PC or that of the next - instruction? The following functions are defined to perform PC-relative - relocations and to undo them (as in the disassembler). The first function - takes the desired address and the PC of the current instruction and returns - the unencoded value to be stored in the offset field. The second function - takes the unencoded offset value and the current PC and returns the address. - Note that these functions do not replace the encode/decode functions; the - operands must be encoded/decoded separately. */ -extern int xtensa_operand_isPCRelative (xtensa_operand); +/* Functional units may be replicated. See how many instances of a + particular function unit exist. Returns XTENSA_UNDEFINED on error. */ -extern uint32 xtensa_operand_do_reloc (xtensa_operand, uint32, uint32); +extern int +xtensa_funcUnit_num_copies (xtensa_isa isa, xtensa_funcUnit fun); -extern uint32 xtensa_operand_undo_reloc (xtensa_operand, uint32, uint32); #ifdef __cplusplus } diff --git a/ld/ChangeLog b/ld/ChangeLog index 21095bf42b3..2b157268d95 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,24 @@ +2004-10-07 Bob Wilson + + * ld.texinfo (Xtensa): Describe new linker relaxation to optimize + assembler-generated longcall sequences. Describe new --size-opt + option. + * emulparams/elf32xtensa.sh (OTHER_SECTIONS): Add .xt.prop section. + * emultempl/xtensaelf.em (remove_section, + replace_insn_sec_with_prop_sec, replace_instruction_table_sections, + elf_xtensa_after_open): New. + (OPTION_OPT_SIZEOPT, OPTION_LITERAL_MOVEMENT, + OPTION_NO_LITERAL_MOVEMENT): Define. + (elf32xtensa_size_opt, elf32xtensa_no_literal_movement): New globals. + (PARSE_AND_LIST_LONGOPTS): Add size-opt and [no-]literal-movement. + (PARSE_AND_LIST_OPTIONS): Add --size-opt. + (PARSE_AND_LIST_ARGS_CASES): Handle OPTION_OPT_SIZEOPT, + OPTION_LITERAL_MOVEMENT, and OPTION_NO_LITERAL_MOVEMENT. + (LDEMUL_AFTER_OPEN): Set to elf_xtensa_after_open. + * scripttempl/elfxtensa.sc: Update with changes from elf.sc. + * Makefile.am (eelf32xtensa.c): Update dependencies. + * Makefile.in: Regenerate. + 2004-10-07 Jeff Baker * lexsup.c: Handle --warn-shared-textrel option. diff --git a/ld/Makefile.am b/ld/Makefile.am index 07246b9ffc6..5add7ff2ff1 100644 --- a/ld/Makefile.am +++ b/ld/Makefile.am @@ -609,8 +609,9 @@ eelf32vax.c: $(srcdir)/emulparams/elf32vax.sh \ $(srcdir)/emultempl/elf32.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} ${GENSCRIPTS} elf32vax "$(tdir_elf32vax)" eelf32xtensa.c: $(srcdir)/emulparams/elf32xtensa.sh \ - $(srcdir)/emulparams/xtensa-config.sh \ - $(srcdir)/emultempl/elf32.em $(srcdir)/emultempl/xtensaelf.em \ + $(srcdir)/emulparams/xtensa-config.sh $(srcdir)/emultempl/elf32.em \ + $(srcdir)/emultempl/xtensaelf.em $(INCDIR)/xtensa-config.h \ + $(BFDDIR)/elf-bfd.h $(BFDDIR)/libbfd.h $(INCDIR)/elf/xtensa.h \ $(srcdir)/scripttempl/elfxtensa.sc ${GEN_DEPENDS} ${GENSCRIPTS} elf32xtensa "$(tdir_elf32xtensa)" eelf32fr30.c: $(srcdir)/emulparams/elf32fr30.sh \ diff --git a/ld/Makefile.in b/ld/Makefile.in index ce98c5bf591..10a3c9f536c 100644 --- a/ld/Makefile.in +++ b/ld/Makefile.in @@ -1346,8 +1346,9 @@ eelf32vax.c: $(srcdir)/emulparams/elf32vax.sh \ $(srcdir)/emultempl/elf32.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} ${GENSCRIPTS} elf32vax "$(tdir_elf32vax)" eelf32xtensa.c: $(srcdir)/emulparams/elf32xtensa.sh \ - $(srcdir)/emulparams/xtensa-config.sh \ - $(srcdir)/emultempl/elf32.em $(srcdir)/emultempl/xtensaelf.em \ + $(srcdir)/emulparams/xtensa-config.sh $(srcdir)/emultempl/elf32.em \ + $(srcdir)/emultempl/xtensaelf.em $(INCDIR)/xtensa-config.h \ + $(BFDDIR)/elf-bfd.h $(BFDDIR)/libbfd.h $(INCDIR)/elf/xtensa.h \ $(srcdir)/scripttempl/elfxtensa.sc ${GEN_DEPENDS} ${GENSCRIPTS} elf32xtensa "$(tdir_elf32xtensa)" eelf32fr30.c: $(srcdir)/emulparams/elf32fr30.sh \ diff --git a/ld/emulparams/elf32xtensa.sh b/ld/emulparams/elf32xtensa.sh index 76f9da85d5a..cf456c7ab0c 100644 --- a/ld/emulparams/elf32xtensa.sh +++ b/ld/emulparams/elf32xtensa.sh @@ -29,4 +29,5 @@ OTHER_READWRITE_SECTIONS=" OTHER_SECTIONS=" .xt.lit 0 : { *(.xt.lit${RELOCATING+ .xt.lit.* .gnu.linkonce.p.*}) } .xt.insn 0 : { *(.xt.insn${RELOCATING+ .gnu.linkonce.x.*}) } + .xt.prop 0 : { *(.xt.prop${RELOCATING+ .gnu.linkonce.prop.*}) } " diff --git a/ld/emultempl/xtensaelf.em b/ld/emultempl/xtensaelf.em index ffd4add1b71..386bf8a32e4 100644 --- a/ld/emultempl/xtensaelf.em +++ b/ld/emultempl/xtensaelf.em @@ -25,9 +25,17 @@ cat >>e${EMULATION_NAME}.c < +#include "../bfd/elf-bfd.h" +#include "../bfd/libbfd.h" +#include "elf/xtensa.h" +#include "bfd.h" static void xtensa_wild_group_interleave (lang_statement_union_type *); static void xtensa_colocate_output_literals (lang_statement_union_type *); +static void remove_section (bfd *, asection *); +static bfd_boolean replace_insn_sec_with_prop_sec (bfd *, const char *, + const char *, char **); +static void replace_instruction_table_sections (bfd *, asection *); /* Flag for the emulation-specific "--no-relax" option. */ @@ -37,7 +45,7 @@ static bfd_boolean disable_relaxation = FALSE; static bfd_vma xtensa_page_power = 12; /* 4K pages. */ /* To force a page break between literals and text, change - xtensa_use_literal_pages to "true". */ + xtensa_use_literal_pages to "TRUE". */ static bfd_boolean xtensa_use_literal_pages = FALSE; #define EXTRA_VALIDATION 0 @@ -74,6 +82,266 @@ elf_xtensa_before_parse (void) } +void +remove_section (abfd, os) + bfd *abfd; + asection *os; +{ + asection **spp; + for (spp = &abfd->sections; *spp; spp = &(*spp)->next) + if (*spp == os) + { + *spp = os->next; + os->owner->section_count--; + break; + } +} + + +bfd_boolean +replace_insn_sec_with_prop_sec (abfd, insn_sec_name, prop_sec_name, + error_message) + bfd *abfd; + const char *insn_sec_name; + const char *prop_sec_name; + char **error_message; +{ + asection *insn_sec; + asection *prop_sec; + bfd_byte *prop_contents = NULL; + bfd_byte *insn_contents = NULL; + unsigned entry_count; + unsigned entry; + Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Rela *internal_relocs = NULL; + unsigned reloc_count; + + *error_message = ""; + insn_sec = bfd_get_section_by_name (abfd, insn_sec_name); + if (insn_sec == NULL) + return TRUE; + entry_count = insn_sec->size / 8; + + prop_sec = bfd_get_section_by_name (abfd, prop_sec_name); + if (prop_sec != NULL && insn_sec != NULL) + { + *error_message = _("file already has property tables"); + return FALSE; + } + + if (insn_sec->size != 0) + { + insn_contents = (bfd_byte *) bfd_malloc (insn_sec->size); + if (insn_contents == NULL) + { + *error_message = _("out of memory"); + goto cleanup; + } + if (! bfd_get_section_contents (abfd, insn_sec, insn_contents, + (file_ptr) 0, insn_sec->size)) + { + *error_message = _("failed to read section contents"); + goto cleanup; + } + } + + /* Create a Property table section and relocation section for it. */ + prop_sec_name = strdup (prop_sec_name); + prop_sec = bfd_make_section (abfd, prop_sec_name); + if (prop_sec == NULL + || ! bfd_set_section_flags (abfd, prop_sec, + bfd_get_section_flags (abfd, insn_sec)) + || ! bfd_set_section_alignment (abfd, prop_sec, 2)) + { + *error_message = _("could not create new section"); + goto cleanup; + } + + if (! bfd_set_section_flags (abfd, prop_sec, + bfd_get_section_flags (abfd, insn_sec)) + || ! bfd_set_section_alignment (abfd, prop_sec, 2)) + { + *error_message = _("could not set new section properties"); + goto cleanup; + } + prop_sec->size = entry_count * 12; + prop_contents = (bfd_byte *) bfd_zalloc (abfd, prop_sec->size); + elf_section_data (prop_sec)->this_hdr.contents = prop_contents; + + /* The entry size and size must be set to allow the linker to compute + the number of relocations since it does not use reloc_count. */ + elf_section_data (prop_sec)->rel_hdr.sh_entsize = + sizeof (Elf32_External_Rela); + elf_section_data (prop_sec)->rel_hdr.sh_size = + elf_section_data (insn_sec)->rel_hdr.sh_size; + + if (prop_contents == NULL && prop_sec->size != 0) + { + *error_message = _("could not allocate section contents"); + goto cleanup; + } + + /* Read the relocations. */ + reloc_count = insn_sec->reloc_count; + if (reloc_count != 0) + { + /* If there is already an internal_reloc, then save it so that the + read_relocs function freshly allocates a copy. */ + Elf_Internal_Rela *saved_relocs = elf_section_data (insn_sec)->relocs; + + elf_section_data (insn_sec)->relocs = NULL; + internal_relocs = + _bfd_elf_link_read_relocs (abfd, insn_sec, NULL, NULL, FALSE); + elf_section_data (insn_sec)->relocs = saved_relocs; + + if (internal_relocs == NULL) + { + *error_message = _("out of memory"); + goto cleanup; + } + } + + /* Create a relocation section for the property section. */ + if (internal_relocs != NULL) + { + elf_section_data (prop_sec)->relocs = internal_relocs; + prop_sec->reloc_count = reloc_count; + } + + /* Now copy each insn table entry to the prop table entry with + appropriate flags. */ + for (entry = 0; entry < entry_count; ++entry) + { + unsigned value; + unsigned flags = (XTENSA_PROP_INSN | XTENSA_PROP_INSN_NO_TRANSFORM + | XTENSA_PROP_INSN_NO_REORDER); + value = bfd_get_32 (abfd, insn_contents + entry * 8 + 0); + bfd_put_32 (abfd, value, prop_contents + entry * 12 + 0); + value = bfd_get_32 (abfd, insn_contents + entry * 8 + 4); + bfd_put_32 (abfd, value, prop_contents + entry * 12 + 4); + bfd_put_32 (abfd, flags, prop_contents + entry * 12 + 8); + } + + /* Now copy all of the relocations. Change offsets for the + instruction table section to offsets in the property table + section. */ + if (internal_relocs) + { + unsigned i; + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + + for (i = 0; i < reloc_count; i++) + { + Elf_Internal_Rela *rela; + unsigned r_offset; + + rela = &internal_relocs[i]; + + /* If this relocation is to the .xt.insn section, + change the section number and the offset. */ + r_offset = rela->r_offset; + r_offset += 4 * (r_offset / 8); + rela->r_offset = r_offset; + } + } + + remove_section (abfd, insn_sec); + + if (insn_contents) + free (insn_contents); + + return TRUE; + + cleanup: + if (prop_sec && prop_sec->owner) + remove_section (abfd, prop_sec); + if (insn_contents) + free (insn_contents); + if (internal_relocs) + free (internal_relocs); + + return FALSE; +} + + +#define PROP_SEC_BASE_NAME ".xt.prop" +#define INSN_SEC_BASE_NAME ".xt.insn" +#define LINKONCE_SEC_OLD_TEXT_BASE_NAME ".gnu.linkonce.x." + + +void +replace_instruction_table_sections (abfd, sec) + bfd *abfd; + asection *sec; +{ + char *message = ""; + const char *insn_sec_name = NULL; + char *prop_sec_name = NULL; + char *owned_prop_sec_name = NULL; + const char *sec_name; + + sec_name = bfd_get_section_name (abfd, sec); + if (strcmp (sec_name, INSN_SEC_BASE_NAME) == 0) + { + insn_sec_name = INSN_SEC_BASE_NAME; + prop_sec_name = PROP_SEC_BASE_NAME; + } + else if (strncmp (sec_name, LINKONCE_SEC_OLD_TEXT_BASE_NAME, + strlen (LINKONCE_SEC_OLD_TEXT_BASE_NAME)) == 0) + { + insn_sec_name = sec_name; + owned_prop_sec_name = (char *) xmalloc (strlen (sec_name) + 20); + prop_sec_name = owned_prop_sec_name; + strcpy (prop_sec_name, ".gnu.linkonce.prop.t."); + strcat (prop_sec_name, + sec_name + strlen (LINKONCE_SEC_OLD_TEXT_BASE_NAME)); + } + if (insn_sec_name != NULL) + { + if (! replace_insn_sec_with_prop_sec (abfd, insn_sec_name, prop_sec_name, + &message)) + { + einfo (_("%P: warning: failed to convert %s table in %B (%s); subsequent disassembly may be incomplete\n"), + insn_sec_name, abfd, message); + } + } + if (owned_prop_sec_name) + free (owned_prop_sec_name); +} + + +/* This is called after all input sections have been opened to convert + instruction tables (.xt.insn, gnu.linkonce.x.*) tables into property + tables (.xt.prop) before any section placement. */ + +static void +elf_xtensa_after_open (void) +{ + bfd *abfd; + + /* First call the ELF version. */ + gld${EMULATION_NAME}_after_open (); + + /* Now search the input files looking for instruction table sections. */ + for (abfd = link_info.input_bfds; + abfd != NULL; + abfd = abfd->link_next) + { + asection *sec = abfd->sections; + asection *next_sec; + + /* Do not use bfd_map_over_sections here since we are removing + sections as we iterate. */ + while (sec != NULL) + { + next_sec = sec->next; + replace_instruction_table_sections (abfd, sec); + sec = next_sec; + } + } +} + + /* This is called after the sections have been attached to output sections, but before any sizes or addresses have been set. */ @@ -443,7 +711,7 @@ ld_xtensa_move_section_after (xtensa_ld_iter *to, xtensa_ld_iter *current) /* Can only be called with lang_statements that have lists. Returns - false if the list is empty. */ + FALSE if the list is empty. */ static bfd_boolean iter_stack_empty (xtensa_ld_iter_stack **stack_p) @@ -1443,30 +1711,49 @@ ld_xtensa_insert_page_offsets (bfd_vma dot, EOF -# Define some shell vars to insert bits of code into the standard elf +# Define some shell vars to insert bits of code into the standard ELF # parse_args and list_options functions. # PARSE_AND_LIST_PROLOGUE=' -#define OPTION_NO_RELAX 301 +#define OPTION_OPT_SIZEOPT (300) +#define OPTION_NO_RELAX (OPTION_OPT_SIZEOPT + 1) +#define OPTION_LITERAL_MOVEMENT (OPTION_NO_RELAX + 1) +#define OPTION_NO_LITERAL_MOVEMENT (OPTION_LITERAL_MOVEMENT + 1) +extern int elf32xtensa_size_opt; +extern int elf32xtensa_no_literal_movement; ' PARSE_AND_LIST_LONGOPTS=' + { "size-opt", no_argument, NULL, OPTION_OPT_SIZEOPT}, { "no-relax", no_argument, NULL, OPTION_NO_RELAX}, + { "literal-movement", no_argument, NULL, OPTION_LITERAL_MOVEMENT}, + { "no-literal-movement", no_argument, NULL, OPTION_NO_LITERAL_MOVEMENT}, ' PARSE_AND_LIST_OPTIONS=' + fprintf (file, _(" --size-opt\t\tWhen relaxing longcalls, prefer size optimization\n\t\t\t over branch target alignment\n")); fprintf (file, _(" --no-relax\t\tDo not relax branches or coalesce literals\n")); ' PARSE_AND_LIST_ARGS_CASES=' + case OPTION_OPT_SIZEOPT: + elf32xtensa_size_opt = 1; + break; case OPTION_NO_RELAX: disable_relaxation = TRUE; break; + case OPTION_LITERAL_MOVEMENT: + elf32xtensa_no_literal_movement = 0; + break; + case OPTION_NO_LITERAL_MOVEMENT: + elf32xtensa_no_literal_movement = 1; + break; ' # Replace some of the standard ELF functions with our own versions. # LDEMUL_BEFORE_PARSE=elf_xtensa_before_parse +LDEMUL_AFTER_OPEN=elf_xtensa_after_open LDEMUL_CHOOSE_TARGET=elf_xtensa_choose_target LDEMUL_PLACE_ORPHAN=elf_xtensa_place_orphan LDEMUL_BEFORE_ALLOCATION=elf_xtensa_before_allocation diff --git a/ld/ld.texinfo b/ld/ld.texinfo index 420065b6c9f..bfd346478cc 100644 --- a/ld/ld.texinfo +++ b/ld/ld.texinfo @@ -5552,34 +5552,53 @@ interleaving might place the @code{.literal} sections from an initial group of files followed by the @code{.text} sections of that group of files. Then, the @code{.literal} sections from the rest of the files and the @code{.text} sections from the rest of the files would follow. -The non-interleaved order can still be specified as: -@smallexample -SECTIONS -@{ - .text : @{ - *(.literal) *(.text) - @} -@} -@end smallexample - -@cindex @code{--relax} on Xtensa +@cindex @option{--relax} on Xtensa @cindex relaxing on Xtensa +Relaxation is enabled by default for the Xtensa version of @command{ld} and +provides two important link-time optimizations. The first optimization +is to combine identical literal values to reduce code size. A redundant +literal will be removed and all the @code{L32R} instructions that use it +will be changed to reference an identical literal, as long as the +location of the replacement literal is within the offset range of all +the @code{L32R} instructions. The second optimization is to remove +unnecessary overhead from assembler-generated ``longcall'' sequences of +@code{L32R}/@code{CALLX@var{n}} when the target functions are within +range of direct @code{CALL@var{n}} instructions. + +For each of these cases where an indirect call sequence can be optimized +to a direct call, the linker will change the @code{CALLX@var{n}} +instruction to a @code{CALL@var{n}} instruction, remove the @code{L32R} +instruction, and remove the literal referenced by the @code{L32R} +instruction if it is not used for anything else. Removing the +@code{L32R} instruction always reduces code size but can potentially +hurt performance by changing the alignment of subsequent branch targets. +By default, the linker will always preserve alignments, either by +switching some instructions between 24-bit encodings and the equivalent +density instructions or by inserting a no-op in place of the @code{L32R} +instruction that was removed. If code size is more important than +performance, the @option{--size-opt} option can be used to prevent the +linker from widening density instructions or inserting no-ops, except in +a few cases where no-ops are required for correctness. + +The following Xtensa-specific command-line options can be used to +control the linker: + +@cindex Xtensa options +@table @option @kindex --no-relax -The Xtensa version of @command{ld} enables the @option{--relax} option by -default to attempt to reduce space in the output image by combining -literals with identical values. It also provides the -@option{--no-relax} option to disable this optimization. When enabled, -the relaxation algorithm ensures that a literal will only be merged with -another literal when the new merged literal location is within the -offset range of all of its uses. - -The relaxation mechanism will also attempt to optimize -assembler-generated ``longcall'' sequences of -@code{L32R}/@code{CALLX@var{n}} when the target is known to fit into a -@code{CALL@var{n}} instruction encoding. The current optimization -converts the sequence into @code{NOP}/@code{CALL@var{n}} and removes the -literal referenced by the @code{L32R} instruction. +@item --no-relax +Since the Xtensa version of @code{ld} enables the @option{--relax} option +by default, the @option{--no-relax} option is provided to disable +relaxation. + +@item --size-opt +When optimizing indirect calls to direct calls, optimize for code size +more than performance. With this option, the linker will not insert +no-ops or widen density instructions to preserve branch target +alignment. There may still be some cases where no-ops are required to +preserve the correctness of the code. +@end table @ifclear GENERIC @lowersections diff --git a/ld/scripttempl/elfxtensa.sc b/ld/scripttempl/elfxtensa.sc index f99d2ce0c43..632cf6dc485 100644 --- a/ld/scripttempl/elfxtensa.sc +++ b/ld/scripttempl/elfxtensa.sc @@ -10,6 +10,8 @@ # OTHER_TEXT_SECTIONS - these get put in .text when relocating # OTHER_READWRITE_SECTIONS - other than .data .bss .ctors .sdata ... # (e.g., .PARISC.global) +# OTHER_RELRO_SECTIONS - other than .data.rel.ro ... +# (e.g. PPC32 .fixup, .got[12]) # OTHER_BSS_SECTIONS - other than .bss .sbss ... # OTHER_SECTIONS - at the end # EXECUTABLE_SYMBOLS - symbols that must be defined for an @@ -67,17 +69,24 @@ test -z "$ENTRY" && ENTRY=_start test -z "${ELFSIZE}" && ELFSIZE=32 test -z "${ALIGNMENT}" && ALIGNMENT="${ELFSIZE} / 8" test "$LD_FLAG" = "N" && DATA_ADDR=. -test -n "$CREATE_SHLIB" && test -n "$SHLIB_DATA_ADDR" && COMMONPAGESIZE="" -test -z "$CREATE_SHLIB" && test -n "$DATA_ADDR" && COMMONPAGESIZE="" +test -n "$CREATE_SHLIB$CREATE_PIE" && test -n "$SHLIB_DATA_ADDR" && COMMONPAGESIZE="" +test -z "$CREATE_SHLIB$CREATE_PIE" && test -n "$DATA_ADDR" && COMMONPAGESIZE="" DATA_SEGMENT_ALIGN="ALIGN(${SEGMENT_SIZE}) + (. & (${MAXPAGESIZE} - 1))" +DATA_SEGMENT_RELRO_END="" DATA_SEGMENT_END="" if test -n "${COMMONPAGESIZE}"; then DATA_SEGMENT_ALIGN="ALIGN (${SEGMENT_SIZE}) - ((${MAXPAGESIZE} - .) & (${MAXPAGESIZE} - 1)); . = DATA_SEGMENT_ALIGN (${MAXPAGESIZE}, ${COMMONPAGESIZE})" DATA_SEGMENT_END=". = DATA_SEGMENT_END (.);" + DATA_SEGMENT_RELRO_END=". = DATA_SEGMENT_RELRO_END (.);" fi INTERP=".interp ${RELOCATING-0} : { *(.interp) }" +if test -z "$GOT"; then + GOT=".got ${RELOCATING-0} : { *(.got) }" +fi DYNAMIC=".dynamic ${RELOCATING-0} : { *(.dynamic) }" RODATA=".rodata ${RELOCATING-0} : { *(.rodata${RELOCATING+ .rodata.* .gnu.linkonce.r.*}) }" +DATARELRO=".data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro*) }" +STACKNOTE="/DISCARD/ : { *(.note.GNU-stack) }" INIT_LIT=".init.literal 0 : { *(.init.literal) }" INIT=".init 0 : { *(.init) }" FINI_LIT=".fini.literal 0 : { *(.fini.literal) }" @@ -111,6 +120,8 @@ if test -z "${NO_SMALL_DATA}"; then .rela.sdata2 ${RELOCATING-0} : { *(.rela.sdata2${RELOCATING+ .rela.sdata2.* .rela.gnu.linkonce.s2.*}) }" REL_SBSS2=".rel.sbss2 ${RELOCATING-0} : { *(.rel.sbss2${RELOCATING+ .rel.sbss2.* .rel.gnu.linkonce.sb2.*}) } .rela.sbss2 ${RELOCATING-0} : { *(.rela.sbss2${RELOCATING+ .rela.sbss2.* .rela.gnu.linkonce.sb2.*}) }" +else + NO_SMALL_DATA=" " fi CTOR=".ctors ${CONSTRUCTING-0} : { @@ -175,8 +186,9 @@ ${RELOCATING- /* For some reason, the Solaris linker makes bad executables SECTIONS { /* Read-only sections, merged into text segment: */ - ${CREATE_SHLIB-${RELOCATING+. = ${TEXT_BASE_ADDRESS};}} + ${CREATE_SHLIB-${CREATE_PIE-${RELOCATING+PROVIDE (__executable_start = ${TEXT_START_ADDR}); . = ${TEXT_BASE_ADDRESS};}}} ${CREATE_SHLIB+${RELOCATING+. = ${SHLIB_TEXT_START_ADDR:-0} + SIZEOF_HEADERS;}} + ${CREATE_PIE+${RELOCATING+. = ${SHLIB_TEXT_START_ADDR:-0} + SIZEOF_HEADERS;}} ${CREATE_SHLIB-${INTERP}} ${INITIAL_READONLY_SECTIONS} ${TEXT_DYNAMIC+${DYNAMIC}} @@ -203,6 +215,8 @@ eval $COMBRELOCCAT < + + * ld-xtensa/lcall1.s: Use .literal directive. + * ld-xtensa/lcall2.s: Align function entry. + * ld-xtensa/coalesce2.s: Likewise. + 2004-10-04 H.J. Lu * ld-scripts/sort.exp: New file for section sorting tests. diff --git a/ld/testsuite/ld-xtensa/coalesce2.s b/ld/testsuite/ld-xtensa/coalesce2.s index 962915c8a8c..7c9a83d0b9b 100644 --- a/ld/testsuite/ld-xtensa/coalesce2.s +++ b/ld/testsuite/ld-xtensa/coalesce2.s @@ -1,6 +1,7 @@ .text .global foo .global g_name + .align 4 foo: entry a5,16 movi a5,20000 diff --git a/ld/testsuite/ld-xtensa/lcall1.s b/ld/testsuite/ld-xtensa/lcall1.s index 1056c6a0c15..34393195886 100644 --- a/ld/testsuite/ld-xtensa/lcall1.s +++ b/ld/testsuite/ld-xtensa/lcall1.s @@ -2,9 +2,7 @@ .text .align 4 label1: - .begin literal - .word 0xffffffff - .end literal + .literal .Lunused, 0xffffffff entry a5,16 .begin longcalls call4 foo diff --git a/ld/testsuite/ld-xtensa/lcall2.s b/ld/testsuite/ld-xtensa/lcall2.s index f4784f04221..d697096c560 100644 --- a/ld/testsuite/ld-xtensa/lcall2.s +++ b/ld/testsuite/ld-xtensa/lcall2.s @@ -1,4 +1,5 @@ -.global foo + .global foo + .align 4 foo: entry a5,16 nop diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index 4abaa5488ec..41bf72eda0c 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,12 @@ +2004-10-07 Bob Wilson + + * xtensa-dis.c (state_names): Delete. + (fetch_data): Use xtensa_isa_maxlength. + (print_xtensa_operand): Replace operand parameter with opcode/operand + pair. Remove print_sr_name parameter. Use new xtensa-isa.h functions. + (print_insn_xtensa): Use new xtensa-isa.h functions. Handle multislot + instruction bundles. Use xmalloc instead of malloc. + 2004-10-07 David Gibson * ppc-opc.c: Replace literal "0"s with NULLs in pointer diff --git a/opcodes/xtensa-dis.c b/opcodes/xtensa-dis.c index 8c310854a8a..d7554a719c9 100644 --- a/opcodes/xtensa-dis.c +++ b/opcodes/xtensa-dis.c @@ -1,5 +1,5 @@ /* xtensa-dis.c. Disassembly functions for Xtensa. - Copyright 2003 Free Software Foundation, Inc. + Copyright 2003, 2004 Free Software Foundation, Inc. Contributed by Bob Wilson at Tensilica, Inc. (bwilson@tensilica.com) This file is part of GDB, GAS, and the GNU binutils. @@ -25,328 +25,32 @@ #include #include "xtensa-isa.h" #include "ansidecl.h" +#include "libiberty.h" #include "sysdep.h" #include "dis-asm.h" #include +extern xtensa_isa xtensa_default_isa; + #ifndef MAX #define MAX(a,b) (a > b ? a : b) #endif -static char* state_names[256] = -{ - "lbeg", /* 0 */ - "lend", /* 1 */ - "lcount", /* 2 */ - "sar", /* 3 */ - "br", /* 4 */ - - "reserved_5", /* 5 */ - "reserved_6", /* 6 */ - "reserved_7", /* 7 */ - - "av", /* 8 */ - "avh", /* 9 */ - "bv", /* 10 */ - "sav", /* 11 */ - "scompare1", /* 12 */ - - "reserved_13", /* 13 */ - "reserved_14", /* 14 */ - "reserved_15", /* 15 */ - - "acclo", /* 16 */ - "acchi", /* 17 */ - - "reserved_18", /* 18 */ - "reserved_19", /* 19 */ - "reserved_20", /* 20 */ - "reserved_21", /* 21 */ - "reserved_22", /* 22 */ - "reserved_23", /* 23 */ - "reserved_24", /* 24 */ - "reserved_25", /* 25 */ - "reserved_26", /* 26 */ - "reserved_27", /* 27 */ - "reserved_28", /* 28 */ - "reserved_29", /* 29 */ - "reserved_30", /* 30 */ - "reserved_31", /* 31 */ - - "mr0", /* 32 */ - "mr1", /* 33 */ - "mr2", /* 34 */ - "mr3", /* 35 */ - - "reserved_36", /* 36 */ - "reserved_37", /* 37 */ - "reserved_38", /* 38 */ - "reserved_39", /* 39 */ - "reserved_40", /* 40 */ - "reserved_41", /* 41 */ - "reserved_42", /* 42 */ - "reserved_43", /* 43 */ - "reserved_44", /* 44 */ - "reserved_45", /* 45 */ - "reserved_46", /* 46 */ - "reserved_47", /* 47 */ - "reserved_48", /* 48 */ - "reserved_49", /* 49 */ - "reserved_50", /* 50 */ - "reserved_51", /* 51 */ - "reserved_52", /* 52 */ - "reserved_53", /* 53 */ - "reserved_54", /* 54 */ - "reserved_55", /* 55 */ - "reserved_56", /* 56 */ - "reserved_57", /* 57 */ - "reserved_58", /* 58 */ - "reserved_59", /* 59 */ - "reserved_60", /* 60 */ - "reserved_61", /* 61 */ - "reserved_62", /* 62 */ - "reserved_63", /* 63 */ - - "reserved_64", /* 64 */ - "reserved_65", /* 65 */ - "reserved_66", /* 66 */ - "reserved_67", /* 67 */ - "reserved_68", /* 68 */ - "reserved_69", /* 69 */ - "reserved_70", /* 70 */ - "reserved_71", /* 71 */ - - "wb", /* 72 */ - "ws", /* 73 */ - - "reserved_74", /* 74 */ - "reserved_75", /* 75 */ - "reserved_76", /* 76 */ - "reserved_77", /* 77 */ - "reserved_78", /* 78 */ - "reserved_79", /* 79 */ - "reserved_80", /* 80 */ - "reserved_81", /* 81 */ - "reserved_82", /* 82 */ - - "ptevaddr", /* 83 */ - - "reserved_84", /* 84 */ - "reserved_85", /* 85 */ - "reserved_86", /* 86 */ - "reserved_87", /* 87 */ - "reserved_88", /* 88 */ - "reserved_89", /* 89 */ - - "rasid", /* 90 */ - "itlbcfg", /* 91 */ - "dtlbcfg", /* 92 */ - - "reserved_93", /* 93 */ - "reserved_94", /* 94 */ - "reserved_95", /* 95 */ - - "ibreakenable", /* 96 */ - - "reserved_97", /* 97 */ - - "cacheattr", /* 98 */ - - "reserved_99", /* 99 */ - "reserved_100", /* 100 */ - "reserved_101", /* 101 */ - "reserved_102", /* 102 */ - "reserved_103", /* 103 */ - - "ddr", /* 104 */ - - "reserved_105", /* 105 */ - "reserved_106", /* 106 */ - "reserved_107", /* 107 */ - "reserved_108", /* 108 */ - "reserved_109", /* 109 */ - "reserved_110", /* 110 */ - "reserved_111", /* 111 */ - "reserved_112", /* 112 */ - "reserved_113", /* 113 */ - "reserved_114", /* 114 */ - "reserved_115", /* 115 */ - "reserved_116", /* 116 */ - "reserved_117", /* 117 */ - "reserved_118", /* 118 */ - "reserved_119", /* 119 */ - "reserved_120", /* 120 */ - "reserved_121", /* 121 */ - "reserved_122", /* 122 */ - "reserved_123", /* 123 */ - "reserved_124", /* 124 */ - "reserved_125", /* 125 */ - "reserved_126", /* 126 */ - "reserved_127", /* 127 */ - - "ibreaka0", /* 128 */ - "ibreaka1", /* 129 */ - "ibreaka2", /* 130 */ - "ibreaka3", /* 131 */ - "ibreaka4", /* 132 */ - "ibreaka5", /* 133 */ - "ibreaka6", /* 134 */ - "ibreaka7", /* 135 */ - "ibreaka8", /* 136 */ - "ibreaka9", /* 137 */ - "ibreaka10", /* 138 */ - "ibreaka11", /* 139 */ - "ibreaka12", /* 140 */ - "ibreaka13", /* 141 */ - "ibreaka14", /* 142 */ - "ibreaka15", /* 143 */ - - "dbreaka0", /* 144 */ - "dbreaka1", /* 145 */ - "dbreaka2", /* 146 */ - "dbreaka3", /* 147 */ - "dbreaka4", /* 148 */ - "dbreaka5", /* 149 */ - "dbreaka6", /* 150 */ - "dbreaka7", /* 151 */ - "dbreaka8", /* 152 */ - "dbreaka9", /* 153 */ - "dbreaka10", /* 154 */ - "dbreaka11", /* 155 */ - "dbreaka12", /* 156 */ - "dbreaka13", /* 157 */ - "dbreaka14", /* 158 */ - "dbreaka15", /* 159 */ - - "dbreakc0", /* 160 */ - "dbreakc1", /* 161 */ - "dbreakc2", /* 162 */ - "dbreakc3", /* 163 */ - "dbreakc4", /* 164 */ - "dbreakc5", /* 165 */ - "dbreakc6", /* 166 */ - "dbreakc7", /* 167 */ - "dbreakc8", /* 168 */ - "dbreakc9", /* 169 */ - "dbreakc10", /* 170 */ - "dbreakc11", /* 171 */ - "dbreakc12", /* 172 */ - "dbreakc13", /* 173 */ - "dbreakc14", /* 174 */ - "dbreakc15", /* 175 */ - - "reserved_176", /* 176 */ - - "epc1", /* 177 */ - "epc2", /* 178 */ - "epc3", /* 179 */ - "epc4", /* 180 */ - "epc5", /* 181 */ - "epc6", /* 182 */ - "epc7", /* 183 */ - "epc8", /* 184 */ - "epc9", /* 185 */ - "epc10", /* 186 */ - "epc11", /* 187 */ - "epc12", /* 188 */ - "epc13", /* 189 */ - "epc14", /* 190 */ - "epc15", /* 191 */ - "depc", /* 192 */ - - "reserved_193", /* 193 */ - - "eps2", /* 194 */ - "eps3", /* 195 */ - "eps4", /* 196 */ - "eps5", /* 197 */ - "eps6", /* 198 */ - "eps7", /* 199 */ - "eps8", /* 200 */ - "eps9", /* 201 */ - "eps10", /* 202 */ - "eps11", /* 203 */ - "eps12", /* 204 */ - "eps13", /* 205 */ - "eps14", /* 206 */ - "eps15", /* 207 */ - - "reserved_208", /* 208 */ - - "excsave1", /* 209 */ - "excsave2", /* 210 */ - "excsave3", /* 211 */ - "excsave4", /* 212 */ - "excsave5", /* 213 */ - "excsave6", /* 214 */ - "excsave7", /* 215 */ - "excsave8", /* 216 */ - "excsave9", /* 217 */ - "excsave10", /* 218 */ - "excsave11", /* 219 */ - "excsave12", /* 220 */ - "excsave13", /* 221 */ - "excsave14", /* 222 */ - "excsave15", /* 223 */ - "cpenable", /* 224 */ - - "reserved_225", /* 225 */ - - "interrupt", /* 226 */ - "interrupt2", /* 227 */ - "intenable", /* 228 */ - - "reserved_229", /* 229 */ - - "ps", /* 230 */ - - "reserved_231", /* 231 */ - - "exccause", /* 232 */ - "debugcause", /* 233 */ - "ccount", /* 234 */ - "prid", /* 235 */ - "icount", /* 236 */ - "icountlvl", /* 237 */ - "excvaddr", /* 238 */ - - "reserved_239", /* 239 */ - - "ccompare0", /* 240 */ - "ccompare1", /* 241 */ - "ccompare2", /* 242 */ - "ccompare3", /* 243 */ - - "misc0", /* 244 */ - "misc1", /* 245 */ - "misc2", /* 246 */ - "misc3", /* 247 */ - - "reserved_248", /* 248 */ - "reserved_249", /* 249 */ - "reserved_250", /* 250 */ - "reserved_251", /* 251 */ - "reserved_252", /* 252 */ - "reserved_253", /* 253 */ - "reserved_254", /* 254 */ - "reserved_255", /* 255 */ -}; - - int show_raw_fields; static int fetch_data - PARAMS ((struct disassemble_info *info, bfd_vma memaddr)); + PARAMS ((struct disassemble_info *, bfd_vma)); static void print_xtensa_operand - PARAMS ((bfd_vma, struct disassemble_info *, xtensa_operand, - unsigned operand_val, int print_sr_name)); + PARAMS ((bfd_vma, struct disassemble_info *, xtensa_opcode, int, unsigned)); -struct dis_private { +struct dis_private +{ bfd_byte *byte_buf; jmp_buf bailout; }; + static int fetch_data (info, memaddr) struct disassemble_info *info; @@ -354,7 +58,7 @@ fetch_data (info, memaddr) { int length, status = 0; struct dis_private *priv = (struct dis_private *) info->private_data; - int insn_size = xtensa_insn_maxlength (xtensa_default_isa); + int insn_size = xtensa_isa_maxlength (xtensa_default_isa); /* Read the maximum instruction size, padding with zeros if we go past the end of the text section. This code will automatically adjust @@ -375,14 +79,14 @@ fetch_data (info, memaddr) static void -print_xtensa_operand (memaddr, info, opnd, operand_val, print_sr_name) +print_xtensa_operand (memaddr, info, opc, opnd, operand_val) bfd_vma memaddr; struct disassemble_info *info; - xtensa_operand opnd; + xtensa_opcode opc; + int opnd; unsigned operand_val; - int print_sr_name; { - char *kind = xtensa_operand_kind (opnd); + xtensa_isa isa = xtensa_default_isa; int signed_operand_val; if (show_raw_fields) @@ -394,29 +98,42 @@ print_xtensa_operand (memaddr, info, opnd, operand_val, print_sr_name) return; } - operand_val = xtensa_operand_decode (opnd, operand_val); + (void) xtensa_operand_decode (isa, opc, opnd, &operand_val); signed_operand_val = (int) operand_val; - if (xtensa_operand_isPCRelative (opnd)) + if (xtensa_operand_is_register (isa, opc, opnd) == 0) { - operand_val = xtensa_operand_undo_reloc (opnd, operand_val, memaddr); - info->target = operand_val; - (*info->print_address_func) (info->target, info); - } - else if (!strcmp (kind, "i")) - { - if (print_sr_name - && signed_operand_val >= 0 - && signed_operand_val <= 255) - (*info->fprintf_func) (info->stream, "%s", - state_names[signed_operand_val]); - else if ((signed_operand_val > -256) && (signed_operand_val < 256)) - (*info->fprintf_func) (info->stream, "%d", signed_operand_val); + if (xtensa_operand_is_PCrelative (isa, opc, opnd) == 1) + { + (void) xtensa_operand_undo_reloc (isa, opc, opnd, + &operand_val, memaddr); + info->target = operand_val; + (*info->print_address_func) (info->target, info); + } else - (*info->fprintf_func) (info->stream, "0x%x",signed_operand_val); + { + if ((signed_operand_val > -256) && (signed_operand_val < 256)) + (*info->fprintf_func) (info->stream, "%d", signed_operand_val); + else + (*info->fprintf_func) (info->stream, "0x%x", signed_operand_val); + } } else - (*info->fprintf_func) (info->stream, "%s%u", kind, operand_val); + { + int i = 1; + xtensa_regfile opnd_rf = xtensa_operand_regfile (isa, opc, opnd); + (*info->fprintf_func) (info->stream, "%s%u", + xtensa_regfile_shortname (isa, opnd_rf), + operand_val); + while (i < xtensa_operand_num_regs (isa, opc, opnd)) + { + operand_val++; + (*info->fprintf_func) (info->stream, ":%s%u", + xtensa_regfile_shortname (isa, opnd_rf), + operand_val); + i++; + } + } } @@ -429,20 +146,21 @@ print_insn_xtensa (memaddr, info) struct disassemble_info *info; { unsigned operand_val; - int bytes_fetched, size, maxsize, i, noperands; + int bytes_fetched, size, maxsize, i, n, noperands, nslots; xtensa_isa isa; xtensa_opcode opc; - char *op_name; - int print_sr_name; + xtensa_format fmt; struct dis_private priv; static bfd_byte *byte_buf = NULL; static xtensa_insnbuf insn_buffer = NULL; + static xtensa_insnbuf slot_buffer = NULL; + int first, first_slot, valid_insn; if (!xtensa_default_isa) - (void) xtensa_isa_init (); + xtensa_default_isa = xtensa_isa_init (0, 0); info->target = 0; - maxsize = xtensa_insn_maxlength (xtensa_default_isa); + maxsize = xtensa_isa_maxlength (xtensa_default_isa); /* Set bytes_per_line to control the amount of whitespace between the hex values and the opcode. For Xtensa, we always print one "chunk" and we @@ -458,9 +176,11 @@ print_insn_xtensa (memaddr, info) /* Allocate buffers the first time through. */ if (!insn_buffer) - insn_buffer = xtensa_insnbuf_alloc (xtensa_default_isa); - if (!byte_buf) - byte_buf = (bfd_byte *) malloc (MAX (maxsize, 4)); + { + insn_buffer = xtensa_insnbuf_alloc (xtensa_default_isa); + slot_buffer = xtensa_insnbuf_alloc (xtensa_default_isa); + byte_buf = (bfd_byte *) xmalloc (MAX (maxsize, 4)); + } priv.byte_buf = byte_buf; @@ -471,6 +191,8 @@ print_insn_xtensa (memaddr, info) /* Don't set "isa" before the setjmp to keep the compiler from griping. */ isa = xtensa_default_isa; + size = 0; + nslots = 0; /* Fetch the maximum size instruction. */ bytes_fetched = fetch_data (info, memaddr); @@ -478,44 +200,75 @@ print_insn_xtensa (memaddr, info) /* Copy the bytes into the decode buffer. */ memset (insn_buffer, 0, (xtensa_insnbuf_size (isa) * sizeof (xtensa_insnbuf_word))); - xtensa_insnbuf_from_chars (isa, insn_buffer, priv.byte_buf); + xtensa_insnbuf_from_chars (isa, insn_buffer, priv.byte_buf, bytes_fetched); + + fmt = xtensa_format_decode (isa, insn_buffer); + if (fmt == XTENSA_UNDEFINED + || ((size = xtensa_format_length (isa, fmt)) > bytes_fetched)) + valid_insn = 0; + else + { + /* Make sure all the opcodes are valid. */ + valid_insn = 1; + nslots = xtensa_format_num_slots (isa, fmt); + for (n = 0; n < nslots; n++) + { + xtensa_format_get_slot (isa, fmt, n, insn_buffer, slot_buffer); + if (xtensa_opcode_decode (isa, fmt, n, slot_buffer) + == XTENSA_UNDEFINED) + { + valid_insn = 0; + break; + } + } + } - opc = xtensa_decode_insn (isa, insn_buffer); - if (opc == XTENSA_UNDEFINED - || ((size = xtensa_insn_length (isa, opc)) > bytes_fetched)) + if (!valid_insn) { (*info->fprintf_func) (info->stream, ".byte %#02x", priv.byte_buf[0]); return 1; } - op_name = (char *) xtensa_opcode_name (isa, opc); - (*info->fprintf_func) (info->stream, "%s", op_name); - - print_sr_name = (!strcasecmp (op_name, "wsr") - || !strcasecmp (op_name, "xsr") - || !strcasecmp (op_name, "rsr")); + if (nslots > 1) + (*info->fprintf_func) (info->stream, "{ "); - /* Print the operands (if any). */ - noperands = xtensa_num_operands (isa, opc); - if (noperands > 0) + first_slot = 1; + for (n = 0; n < nslots; n++) { - int first = 1; + if (first_slot) + first_slot = 0; + else + (*info->fprintf_func) (info->stream, "; "); + + xtensa_format_get_slot (isa, fmt, n, insn_buffer, slot_buffer); + opc = xtensa_opcode_decode (isa, fmt, n, slot_buffer); + (*info->fprintf_func) (info->stream, "%s", + xtensa_opcode_name (isa, opc)); - (*info->fprintf_func) (info->stream, "\t"); + /* Print the operands (if any). */ + noperands = xtensa_opcode_num_operands (isa, opc); + first = 1; for (i = 0; i < noperands; i++) { - xtensa_operand opnd = xtensa_get_operand (isa, opc, i); - + if (xtensa_operand_is_visible (isa, opc, i) == 0) + continue; if (first) - first = 0; + { + (*info->fprintf_func) (info->stream, "\t"); + first = 0; + } else (*info->fprintf_func) (info->stream, ", "); - operand_val = xtensa_operand_get_field (opnd, insn_buffer); - print_xtensa_operand (memaddr, info, opnd, operand_val, - print_sr_name); - } + (void) xtensa_operand_get_field (isa, opc, i, fmt, n, + slot_buffer, &operand_val); + + print_xtensa_operand (memaddr, info, opc, i, operand_val); + } } + if (nslots > 1) + (*info->fprintf_func) (info->stream, " }"); + info->bytes_per_chunk = size; info->display_endian = info->endian;