X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-xtensa.c;h=4440ed450076810d6ea35ff344c9af423f58bd5a;hb=82e9597c9ec1c14a402d47f2d9b544235998be1e;hp=abefdd2429ad0cd6e04e16ed023a2ef1353edede;hpb=4ec9d7d56427e9fa49fd705599bb2ff0c3c5f3c1;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-xtensa.c b/gas/config/tc-xtensa.c index abefdd2429..4440ed4500 100644 --- a/gas/config/tc-xtensa.c +++ b/gas/config/tc-xtensa.c @@ -1,5 +1,5 @@ /* tc-xtensa.c -- Assemble Xtensa instructions. - Copyright (C) 2003-2016 Free Software Foundation, Inc. + Copyright (C) 2003-2020 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -27,8 +27,8 @@ #include "xtensa-relax.h" #include "dwarf2dbg.h" #include "xtensa-istack.h" -#include "struc-symbol.h" #include "xtensa-config.h" +#include "elf/xtensa.h" /* Provide default values for new configuration settings. */ #ifndef XSHAL_ABI @@ -71,13 +71,13 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP"; /* Flags to indicate whether the hardware supports the density and absolute literals options. */ -bfd_boolean density_supported = XCHAL_HAVE_DENSITY; -bfd_boolean absolute_literals_supported = XSHAL_USE_ABSOLUTE_LITERALS; +bfd_boolean density_supported; +bfd_boolean absolute_literals_supported; static vliw_insn cur_vinsn; unsigned xtensa_num_pipe_stages; -unsigned xtensa_fetch_width = XCHAL_INST_FETCH_WIDTH; +unsigned xtensa_fetch_width; static enum debug_info_type xt_saved_debug_type = DEBUG_NONE; @@ -213,8 +213,6 @@ int generating_literals = 0; /* 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)) @@ -235,8 +233,6 @@ int generating_literals = 0; #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)) @@ -364,7 +360,7 @@ struct suffix_reloc_map const char *suffix; int length; bfd_reloc_code_real_type reloc; - unsigned char operator; + operatorT operator; }; #define SUFFIX_MAP(str, reloc, op) { str, sizeof (str) - 1, reloc, op } @@ -380,7 +376,6 @@ static struct suffix_reloc_map suffix_relocs[] = SUFFIX_MAP ("tlscall", BFD_RELOC_XTENSA_TLS_CALL, O_tlscall), SUFFIX_MAP ("tpoff", BFD_RELOC_XTENSA_TLS_TPOFF, O_tpoff), SUFFIX_MAP ("dtpoff", BFD_RELOC_XTENSA_TLS_DTPOFF, O_dtpoff), - { (char *) 0, 0, BFD_RELOC_UNUSED, 0 } }; @@ -423,21 +418,13 @@ bfd_boolean directive_state[] = { FALSE, /* none */ FALSE, /* literal */ -#if !XCHAL_HAVE_DENSITY FALSE, /* density */ -#else - TRUE, /* density */ -#endif TRUE, /* transform */ FALSE, /* freeregs */ FALSE, /* longcalls */ FALSE, /* literal_prefix */ FALSE, /* schedule */ -#if XSHAL_USE_ABSOLUTE_LITERALS - TRUE /* absolute_literals */ -#else FALSE /* absolute_literals */ -#endif }; /* A circular list of all potential and actual literal pool locations @@ -450,6 +437,7 @@ struct litpool_frag addressT addr; short priority; /* 1, 2, or 3 -- 1 is highest */ short original_priority; + int literal_count; }; /* Map a segment to its litpool_frag list. */ @@ -463,6 +451,14 @@ struct litpool_seg static struct litpool_seg litpool_seg_list; +/* Limit maximal size of auto litpool by half of the j range. */ +#define MAX_AUTO_POOL_LITERALS 16384 + +/* Limit maximal size of explicit literal pool by l32r range. */ +#define MAX_EXPLICIT_POOL_LITERALS 65536 + +#define MAX_POOL_LITERALS \ + (auto_litpools ? MAX_AUTO_POOL_LITERALS : MAX_EXPLICIT_POOL_LITERALS) /* Directive functions. */ @@ -496,10 +492,12 @@ static void xtensa_check_frag_count (void); static void xtensa_create_trampoline_frag (bfd_boolean); static void xtensa_maybe_create_trampoline_frag (void); struct trampoline_frag; -static int init_trampoline_frag (struct trampoline_frag *); +static int init_trampoline_frag (fragS *); +static fixS *xg_append_jump (fragS *fragP, symbolS *sym, offsetT offset); static void xtensa_maybe_create_literal_pool_frag (bfd_boolean, bfd_boolean); static bfd_boolean auto_litpools = FALSE; -static int auto_litpool_limit = 10000; +static int auto_litpool_limit = 0; +static bfd_boolean xtensa_is_init_fini (segT seg); /* Alignment Functions. */ @@ -529,10 +527,6 @@ static void xtensa_switch_section_emit_state (emit_state *, segT, subsegT); static void xtensa_restore_emit_state (emit_state *); static segT cache_literal_section (bfd_boolean); -/* Import from elf32-xtensa.c in BFD library. */ - -extern asection *xtensa_make_property_section (asection *, const char *); - /* op_placement_info functions. */ static void init_op_placement_info_table (void); @@ -634,6 +628,7 @@ static bfd_boolean maybe_has_short_loop = FALSE; static bfd_boolean workaround_close_loop_end = FALSE; static bfd_boolean maybe_has_close_loop_end = FALSE; static bfd_boolean enforce_three_byte_loop_align = FALSE; +static bfd_boolean opt_linkrelax = 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 @@ -643,6 +638,9 @@ static bfd_boolean enforce_three_byte_loop_align = FALSE; static bfd_boolean workaround_all_short_loops = FALSE; +/* Generate individual property section for every section. + This option is defined in BDF library. */ +extern bfd_boolean elf32xtensa_separate_props; static void xtensa_setup_hw_workarounds (int earliest, int latest) @@ -728,6 +726,9 @@ enum option_auto_litpools, option_no_auto_litpools, option_auto_litpool_limit, + + option_separate_props, + option_no_separate_props, }; const char *md_shortopts = ""; @@ -807,6 +808,8 @@ struct option md_longopts[] = { "no-auto-litpools", no_argument, NULL, option_no_auto_litpools }, { "auto-litpool-limit", required_argument, NULL, option_auto_litpool_limit }, + { "separate-prop-tables", no_argument, NULL, option_separate_props }, + { NULL, no_argument, NULL, 0 } }; @@ -825,10 +828,10 @@ md_parse_option (int c, const char *arg) as_warn (_("--no-density option is ignored")); return 1; case option_link_relax: - linkrelax = 1; + opt_linkrelax = TRUE; return 1; case option_no_link_relax: - linkrelax = 0; + opt_linkrelax = FALSE; return 1; case option_flix: produce_flix = FLIX_ALL; @@ -999,6 +1002,8 @@ md_parse_option (int c, const char *arg) case option_auto_litpools: auto_litpools = TRUE; use_literal_section = FALSE; + if (auto_litpool_limit <= 0) + auto_litpool_limit = MAX_AUTO_POOL_LITERALS / 2; return 1; case option_no_auto_litpools: @@ -1025,6 +1030,14 @@ md_parse_option (int c, const char *arg) return 1; } + case option_separate_props: + elf32xtensa_separate_props = TRUE; + return 1; + + case option_no_separate_props: + elf32xtensa_separate_props = FALSE; + return 1; + default: return 0; } @@ -1055,7 +1068,11 @@ Xtensa options:\n\ --auto-litpool-limit=\n\ (range 100-10000) Maximum number of blocks of\n\ instructions to emit between literal pool\n\ - locations; implies --auto-litpools flag\n", stream); + locations; implies --auto-litpools flag\n\ + --[no-]separate-prop-tables\n\ + [Do not] place Xtensa property records into\n\ + individual property sections for each section.\n\ + Default is to generate single property section.\n", stream); } @@ -1067,7 +1084,7 @@ xtensa_add_insn_label (symbolS *sym) sym_list *l; if (!free_insn_labels) - l = (sym_list *) xmalloc (sizeof (sym_list)); + l = XNEW (sym_list); else { l = free_insn_labels; @@ -1167,7 +1184,7 @@ directive_push (directiveE directive, bfd_boolean negated, const void *datum) { const char *file; unsigned int line; - state_stackS *stack = (state_stackS *) xmalloc (sizeof (state_stackS)); + state_stackS *stack = XNEW (state_stackS); file = as_where (&line); @@ -1195,7 +1212,7 @@ directive_pop (directiveE *directive, if (!directive_state_stack) { - as_bad (_("unmatched end directive")); + as_bad (_("unmatched .end directive")); *directive = directive_none; return; } @@ -1323,7 +1340,7 @@ xtensa_begin_directive (int ignore ATTRIBUTE_UNUSED) insn_labels = NULL; } as_warn (_(".begin literal is deprecated; use .literal instead")); - state = (emit_state *) xmalloc (sizeof (emit_state)); + state = XNEW (emit_state); xtensa_switch_to_literal_fragment (state); directive_push (directive_literal, negated, state); break; @@ -1342,7 +1359,7 @@ xtensa_begin_directive (int ignore ATTRIBUTE_UNUSED) /* Allocate the literal state for this section and push onto the directive stack. */ - ls = xmalloc (sizeof (lit_state)); + ls = XNEW (lit_state); gas_assert (ls); *ls = default_lit_sections; @@ -1515,7 +1532,6 @@ xtensa_literal_pseudo (int ignored ATTRIBUTE_UNUSED) emit_state state; char *p, *base_name; char c; - segT dest_seg; if (inside_directive (directive_literal)) { @@ -1531,21 +1547,10 @@ xtensa_literal_pseudo (int ignored ATTRIBUTE_UNUSED) saved_insn_labels = insn_labels; insn_labels = NULL; - /* If we are using text-section literals, then this is the right value... */ - dest_seg = now_seg; - base_name = input_line_pointer; xtensa_switch_to_literal_fragment (&state); - /* ...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 || directive_state[directive_absolute_literals]) - dest_seg = now_seg; - - /* FIXME, despite the previous comments, dest_seg is unused... */ - (void) dest_seg; - /* All literals are aligned to four-byte boundaries. */ frag_align (2, 0, 0); record_alignment (now_seg, 2); @@ -1594,10 +1599,7 @@ xtensa_literal_prefix (void) "abcdefghijklmnopqrstuvwxyz_/0123456789.$"); /* Get a null-terminated copy of the name. */ - name = xmalloc (len + 1); - gas_assert (name); - strncpy (name, input_line_pointer, len); - name[len] = 0; + name = xmemdup0 (input_line_pointer, len); /* Skip the name in the input line. */ input_line_pointer += len; @@ -1679,7 +1681,9 @@ xtensa_elf_cons (int nbytes) 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"), + as_bad (ngettext ("%s relocations do not fit in %d byte", + "%s relocations do not fit in %d bytes", + nbytes), reloc_howto->name, nbytes); else if (reloc == BFD_RELOC_XTENSA_TLS_FUNC || reloc == BFD_RELOC_XTENSA_TLS_ARG @@ -1727,7 +1731,7 @@ xtensa_elf_suffix (char **str_p, expressionS *exp_p) char *str2; int ch; int len; - struct suffix_reloc_map *ptr; + unsigned int i; if (*str++ != '@') return BFD_RELOC_NONE; @@ -1744,10 +1748,10 @@ xtensa_elf_suffix (char **str_p, expressionS *exp_p) len = str2 - ident; ch = ident[0]; - for (ptr = &suffix_relocs[0]; ptr->length > 0; ptr++) - if (ch == ptr->suffix[0] - && len == ptr->length - && memcmp (ident, ptr->suffix, ptr->length) == 0) + for (i = 0; i < ARRAY_SIZE (suffix_relocs); i++) + if (ch == suffix_relocs[i].suffix[0] + && len == suffix_relocs[i].length + && memcmp (ident, suffix_relocs[i].suffix, suffix_relocs[i].length) == 0) { /* Now check for "identifier@suffix+constant". */ if (*str == '-' || *str == '+') @@ -1768,7 +1772,7 @@ xtensa_elf_suffix (char **str_p, expressionS *exp_p) } *str_p = str; - return ptr->reloc; + return suffix_relocs[i].reloc; } return BFD_RELOC_UNUSED; @@ -1776,21 +1780,21 @@ xtensa_elf_suffix (char **str_p, expressionS *exp_p) /* Find the matching operator type. */ -static unsigned char +static operatorT map_suffix_reloc_to_operator (bfd_reloc_code_real_type reloc) { - struct suffix_reloc_map *sfx; - unsigned char operator = (unsigned char) -1; + operatorT operator = O_illegal; + unsigned int i; - for (sfx = &suffix_relocs[0]; sfx->suffix; sfx++) + for (i = 0; i < ARRAY_SIZE (suffix_relocs); i++) { - if (sfx->reloc == reloc) + if (suffix_relocs[i].reloc == reloc) { - operator = sfx->operator; + operator = suffix_relocs[i].operator; break; } } - gas_assert (operator != (unsigned char) -1); + gas_assert (operator != O_illegal); return operator; } @@ -1799,14 +1803,14 @@ map_suffix_reloc_to_operator (bfd_reloc_code_real_type reloc) static bfd_reloc_code_real_type map_operator_to_reloc (unsigned char operator, bfd_boolean is_literal) { - struct suffix_reloc_map *sfx; + unsigned int i; bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED; - for (sfx = &suffix_relocs[0]; sfx->suffix; sfx++) + for (i = 0; i < ARRAY_SIZE (suffix_relocs); i++) { - if (sfx->operator == operator) + if (suffix_relocs[i].operator == operator) { - reloc = sfx->reloc; + reloc = suffix_relocs[i].reloc; break; } } @@ -2026,7 +2030,7 @@ tokenize_arguments (char **args, char *str) arg_end += 1; arg_len = arg_end - input_line_pointer; - arg = (char *) xmalloc ((saw_colon ? 1 : 0) + arg_len + 1); + arg = XNEWVEC (char, (saw_colon ? 1 : 0) + arg_len + 1); args[num_args] = arg; if (saw_colon) @@ -2239,8 +2243,7 @@ xg_reverse_shift_count (char **cnt_argp) cnt_arg = *cnt_argp; /* replace the argument with "31-(argument)" */ - new_arg = (char *) xmalloc (strlen (cnt_arg) + 6); - sprintf (new_arg, "31-(%s)", cnt_arg); + new_arg = concat ("31-(", cnt_arg, ")", (char *) NULL); free (cnt_arg); *cnt_argp = new_arg; @@ -2428,7 +2431,7 @@ xtensa_translate_old_userreg_ops (char **popname) /* Translate the opcode. */ sr_name = xtensa_sysreg_name (isa, sr); - new_opname = (char *) xmalloc (strlen (sr_name) + 6); + new_opname = XNEWVEC (char, strlen (sr_name) + 6); sprintf (new_opname, "%s%cur.%s", (has_underbar ? "_" : ""), opname[0], sr_name); free (*popname); @@ -4034,14 +4037,18 @@ xg_expand_assembly_insn (IStack *istack, TInsn *orig_insn) orig_insn->opcode); if (orig_insn->ntok < noperands) { - as_bad (_("found %d operands for '%s': Expected %d"), + as_bad (ngettext ("found %d operand for '%s': Expected %d", + "found %d operands for '%s': Expected %d", + orig_insn->ntok), orig_insn->ntok, xtensa_opcode_name (xtensa_default_isa, orig_insn->opcode), noperands); return TRUE; } if (orig_insn->ntok > noperands) - as_warn (_("found too many (%d) operands for '%s': Expected %d"), + as_warn (ngettext ("found %d operand for '%s': Expected %d", + "found %d operands for '%s': Expected %d", + orig_insn->ntok), orig_insn->ntok, xtensa_opcode_name (xtensa_default_isa, orig_insn->opcode), noperands); @@ -4108,7 +4115,7 @@ get_is_linkonce_section (bfd *abfd ATTRIBUTE_UNUSED, segT sec) { flagword flags, link_once_flags; - flags = bfd_get_section_flags (abfd, sec); + flags = bfd_section_flags (sec); link_once_flags = (flags & SEC_LINK_ONCE); /* Flags might not be set yet. */ @@ -4125,7 +4132,7 @@ xtensa_add_literal_sym (symbolS *sym) { sym_list *l; - l = (sym_list *) xmalloc (sizeof (sym_list)); + l = XNEW (sym_list); l->sym = sym; l->next = literal_syms; literal_syms = l; @@ -4780,7 +4787,6 @@ xtensa_mark_literal_pool_location (void) { /* Any labels pointing to the current location need to be adjusted to after the literal pool. */ - emit_state s; fragS *pool_location; if (use_literal_section) @@ -4801,19 +4807,7 @@ xtensa_mark_literal_pool_location (void) 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_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); } @@ -4897,29 +4891,32 @@ get_expanded_loop_offset (xtensa_opcode opcode) static fragS * get_literal_pool_location (segT seg) { - struct litpool_seg *lps = litpool_seg_list.next; - struct litpool_frag *lpf; - for ( ; lps && lps->seg->id != seg->id; lps = lps->next) - ; - if (lps) + if (auto_litpools) { - for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev) - { /* Skip "candidates" for now. */ - if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN && - lpf->priority == 1) - return lpf->fragP; - } - /* Must convert a lower-priority pool. */ - for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev) - { - if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN) - return lpf->fragP; - } - /* Still no match -- try for a low priority pool. */ - for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev) + struct litpool_seg *lps = litpool_seg_list.next; + struct litpool_frag *lpf; + for ( ; lps && lps->seg->id != seg->id; lps = lps->next) + ; + if (lps) { - if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN) - return lpf->fragP; + for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev) + { /* Skip "candidates" for now. */ + if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN && + lpf->priority == 1) + return lpf->fragP; + } + /* Must convert a lower-priority pool. */ + for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev) + { + if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN) + return lpf->fragP; + } + /* Still no match -- try for a low priority pool. */ + for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev) + { + if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN) + return lpf->fragP; + } } } return seg_info (seg)->tc_segment_info_data.literal_pool_loc; @@ -4983,7 +4980,7 @@ xtensa_mark_frags_for_org (void) segment_info_type *seginfo; fragS *fragP; flagword flags; - flags = bfd_get_section_flags (stdoutput, sec); + flags = bfd_section_flags (sec); if (flags & SEC_DEBUGGING) continue; if (!(flags & SEC_ALLOC)) @@ -5028,7 +5025,7 @@ xtensa_find_unmarked_state_frags (void) segment_info_type *seginfo; fragS *fragP; flagword flags; - flags = bfd_get_section_flags (stdoutput, sec); + flags = bfd_section_flags (sec); if (flags & SEC_DEBUGGING) continue; if (!(flags & SEC_ALLOC)) @@ -5076,7 +5073,7 @@ xtensa_find_unaligned_branch_targets (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *unused ATTRIBUTE_UNUSED) { - flagword flags = bfd_get_section_flags (abfd, sec); + flagword flags = bfd_section_flags (sec); segment_info_type *seginfo = seg_info (sec); fragS *frag = seginfo->frchainP->frch_root; @@ -5115,7 +5112,7 @@ xtensa_find_unaligned_loops (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *unused ATTRIBUTE_UNUSED) { - flagword flags = bfd_get_section_flags (abfd, sec); + flagword flags = bfd_section_flags (sec); segment_info_type *seginfo = seg_info (sec); fragS *frag = seginfo->frchainP->frch_root; xtensa_isa isa = xtensa_default_isa; @@ -5228,6 +5225,24 @@ md_number_to_chars (char *buf, valueT val, int n) number_to_chars_littleendian (buf, val, n); } +static void +xg_init_global_config (void) +{ + target_big_endian = XCHAL_HAVE_BE; + + density_supported = XCHAL_HAVE_DENSITY; + absolute_literals_supported = XSHAL_USE_ABSOLUTE_LITERALS; + xtensa_fetch_width = XCHAL_INST_FETCH_WIDTH; + + directive_state[directive_density] = XCHAL_HAVE_DENSITY; + directive_state[directive_absolute_literals] = XSHAL_USE_ABSOLUTE_LITERALS; +} + +void +xtensa_init (int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) +{ + xg_init_global_config (); +} /* This function is called once, at assembler startup time. It should set up all the tables, etc. that the MD part of the assembler will @@ -5244,7 +5259,7 @@ md_begin (void) xtensa_default_isa = xtensa_isa_init (0, 0); isa = xtensa_default_isa; - linkrelax = 1; + linkrelax = opt_linkrelax; /* Set up the literal sections. */ memset (&default_lit_sections, 0, sizeof (default_lit_sections)); @@ -5299,6 +5314,9 @@ md_begin (void) /* Set up the assembly state. */ if (!frag_now->tc_frag_data.is_assembly_state_set) xtensa_set_frag_assembly_state (frag_now); + + if (!use_literal_section) + xtensa_mark_literal_pool_location (); } @@ -5519,7 +5537,7 @@ md_assemble (char *str) orig_insn.is_specific_opcode = (has_underbar || !use_transform ()); orig_insn.opcode = xtensa_opcode_lookup (isa, opname); - /* Special case: Check for "CALLXn.TLS" psuedo op. If found, grab its + /* Special case: Check for "CALLXn.TLS" pseudo op. If found, grab its extra argument and set the opcode to "CALLXn". */ if (orig_insn.opcode == XTENSA_UNDEFINED && strncasecmp (opname, "callx", 5) == 0) @@ -5568,7 +5586,7 @@ md_assemble (char *str) } } - /* Special case: Check for "j.l" psuedo op. */ + /* Special case: Check for "j.l" pseudo op. */ if (orig_insn.opcode == XTENSA_UNDEFINED && strncasecmp (opname, "j.l", 3) == 0) { @@ -5898,6 +5916,11 @@ xtensa_elf_section_change_hook (void) /* Set up the assembly state. */ if (!frag_now->tc_frag_data.is_assembly_state_set) xtensa_set_frag_assembly_state (frag_now); + + if (!use_literal_section + && seg_info (now_seg)->tc_segment_info_data.literal_pool_loc == NULL + && !xtensa_is_init_fini (now_seg)) + xtensa_mark_literal_pool_location (); } @@ -5984,6 +6007,12 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg) val = *valP; fixP->fx_done = 1; } + else if (S_GET_SEGMENT (fixP->fx_addsy) == absolute_section) + { + val = S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset; + *valP = val; + fixP->fx_done = 1; + } /* fall through */ case BFD_RELOC_XTENSA_PLT: @@ -6073,7 +6102,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg) } -char * +const char * md_atof (int type, char *litP, int *sizeP) { return ieee_md_atof (type, litP, sizeP, target_big_endian); @@ -6095,8 +6124,8 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) { arelent *reloc; - reloc = (arelent *) xmalloc (sizeof (arelent)); - reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + reloc = XNEW (arelent); + reloc->sym_ptr_ptr = XNEW (asymbol *); *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; @@ -6141,7 +6170,7 @@ new_resource_table (void *data, opcode_funcUnit_use_stage_func ousf) { int i; - resource_table *rt = (resource_table *) xmalloc (sizeof (resource_table)); + resource_table *rt = XNEW (resource_table); rt->data = data; rt->cycles = cycles; rt->allocated_cycles = cycles; @@ -6151,9 +6180,9 @@ new_resource_table (void *data, rt->opcode_unit_use = ouuf; rt->opcode_unit_stage = ousf; - rt->units = (unsigned char **) xcalloc (cycles, sizeof (unsigned char *)); + rt->units = XCNEWVEC (unsigned char *, cycles); for (i = 0; i < cycles; i++) - rt->units[i] = (unsigned char *) xcalloc (nu, sizeof (unsigned char)); + rt->units[i] = XCNEWVEC (unsigned char, nu); return rt; } @@ -6183,13 +6212,11 @@ resize_resource_table (resource_table *rt, int cycles) old_cycles = rt->allocated_cycles; rt->allocated_cycles = cycles; - rt->units = xrealloc (rt->units, - rt->allocated_cycles * sizeof (unsigned char *)); + rt->units = XRESIZEVEC (unsigned char *, rt->units, rt->allocated_cycles); for (i = 0; i < old_cycles; i++) - rt->units[i] = xrealloc (rt->units[i], - rt->num_units * sizeof (unsigned char)); + rt->units[i] = XRESIZEVEC (unsigned char, rt->units[i], rt->num_units); for (i = old_cycles; i < cycles; i++) - rt->units[i] = xcalloc (rt->num_units, sizeof (unsigned char)); + rt->units[i] = XCNEWVEC (unsigned char, rt->num_units); } @@ -6321,6 +6348,7 @@ finish_vinsn (vliw_insn *vinsn) { IStack slotstack; int i; + int slots; if (find_vinsn_conflicts (vinsn)) { @@ -6332,7 +6360,8 @@ finish_vinsn (vliw_insn *vinsn) if (vinsn->format == XTENSA_UNDEFINED) vinsn->format = xg_find_narrowest_format (vinsn); - if (xtensa_format_num_slots (xtensa_default_isa, vinsn->format) > 1 + slots = xtensa_format_num_slots (xtensa_default_isa, vinsn->format); + if (slots > 1 && produce_flix == FLIX_NONE) { as_bad (_("The option \"--no-allow-flix\" prohibits multi-slot flix.")); @@ -6353,13 +6382,11 @@ finish_vinsn (vliw_insn *vinsn) return; } - if (vinsn->num_slots - != xtensa_format_num_slots (xtensa_default_isa, vinsn->format)) + if (vinsn->num_slots != slots) { - as_bad (_("format '%s' allows %d slots, but there are %d opcodes"), + as_bad (_("mismatch for format '%s': #slots = %d, #opcodes = %d"), xtensa_format_name (xtensa_default_isa, vinsn->format), - xtensa_format_num_slots (xtensa_default_isa, vinsn->format), - vinsn->num_slots); + slots, vinsn->num_slots); xg_clear_vinsn (vinsn); return; } @@ -6967,7 +6994,7 @@ emit_single_op (TInsn *orig_insn) case ITYPE_LABEL: { static int relaxed_sym_idx = 0; - char *label = xmalloc (strlen (FAKE_LABEL_NAME) + 12); + char *label = XNEWVEC (char, strlen (FAKE_LABEL_NAME) + 12); sprintf (label, "%s_rl_%x", FAKE_LABEL_NAME, relaxed_sym_idx++); colon (label); gas_assert (label_sym == NULL); @@ -7181,10 +7208,8 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn) frag_now->tc_frag_data.slot_offsets[slot] = tinsn->offset; frag_now->tc_frag_data.literal_frags[slot] = tinsn->literal_frag; if (tinsn->opcode == xtensa_l32r_opcode) - { - frag_now->tc_frag_data.literal_frags[slot] = - tinsn->tok[1].X_add_symbol->sy_frag; - } + frag_now->tc_frag_data.literal_frags[slot] + = symbol_get_frag (tinsn->tok[1].X_add_symbol); if (tinsn->literal_space != 0) xg_assemble_literal_space (tinsn->literal_space, slot); frag_now->tc_frag_data.free_reg[slot] = tinsn->extra_arg; @@ -7345,24 +7370,53 @@ xtensa_end (void) xtensa_check_frag_count (); } +struct trampoline_chain_entry +{ + symbolS *sym; + addressT offset; +}; -struct trampoline_frag +/* Trampoline chain for a given (sym, offset) pair is a sorted array + of locations of trampoline jumps leading there. Jumps are represented + as pairs (sym, offset): trampoline frag symbol and offset of the jump + inside the frag. */ +struct trampoline_chain +{ + struct trampoline_chain_entry target; + struct trampoline_chain_entry *entry; + size_t n_entries; + size_t n_max; + bfd_boolean needs_sorting; +}; + +struct trampoline_chain_index { - struct trampoline_frag *next; - bfd_boolean needs_jump_around; - fragS *fragP; - fixS *fixP; + struct trampoline_chain *entry; + size_t n_entries; + size_t n_max; + bfd_boolean needs_sorting; +}; + +struct trampoline_index +{ + fragS **entry; + size_t n_entries; + size_t n_max; }; struct trampoline_seg { struct trampoline_seg *next; asection *seg; - struct trampoline_frag trampoline_list; + /* Trampolines ordered by their frag fr_address */ + struct trampoline_index index; + /* Known trampoline chains ordered by (sym, offset) pair */ + struct trampoline_chain_index chain_index; }; static struct trampoline_seg trampoline_seg_list; #define J_RANGE (128 * 1024) +#define J_MARGIN 4096 static int unreachable_count = 0; @@ -7417,6 +7471,73 @@ static xtensa_insnbuf litpool_slotbuf = NULL; #define TRAMPOLINE_FRAG_SIZE 3000 +static struct trampoline_seg * +find_trampoline_seg (asection *seg) +{ + struct trampoline_seg *ts = trampoline_seg_list.next; + static struct trampoline_seg *mr; + + if (mr && mr->seg == seg) + return mr; + + for ( ; ts; ts = ts->next) + { + if (ts->seg == seg) + { + mr = ts; + return ts; + } + } + + return NULL; +} + +static size_t xg_find_trampoline (const struct trampoline_index *idx, + addressT addr) +{ + size_t a = 0; + size_t b = idx->n_entries; + + while (b - a > 1) + { + size_t c = (a + b) / 2; + + if (idx->entry[c]->fr_address <= addr) + a = c; + else + b = c; + } + return a; +} + +static void xg_add_trampoline_to_index (struct trampoline_index *idx, + fragS *fragP) +{ + if (idx->n_entries == idx->n_max) + { + idx->n_max = (idx->n_entries + 1) * 2; + idx->entry = xrealloc (idx->entry, + sizeof (*idx->entry) * idx->n_max); + } + idx->entry[idx->n_entries] = fragP; + ++idx->n_entries; +} + +static void xg_remove_trampoline_from_index (struct trampoline_index *idx, + size_t i) +{ + gas_assert (i < idx->n_entries); + memmove (idx->entry + i, idx->entry + i + 1, + (idx->n_entries - i - 1) * sizeof (*idx->entry)); + --idx->n_entries; +} + +static void xg_add_trampoline_to_seg (struct trampoline_seg *ts, + fragS *fragP) +{ + xg_add_trampoline_to_index (&ts->index, fragP); +} + static void xtensa_create_trampoline_frag (bfd_boolean needs_jump_around) { @@ -7426,21 +7547,14 @@ xtensa_create_trampoline_frag (bfd_boolean needs_jump_around) We allocate enough for 1000 trampolines in each frag. If that's not enough, oh well. */ - struct trampoline_seg *ts = trampoline_seg_list.next; - struct trampoline_frag *tf; + struct trampoline_seg *ts = find_trampoline_seg (now_seg); char *varP; fragS *fragP; int size = TRAMPOLINE_FRAG_SIZE; - for ( ; ts; ts = ts->next) - { - if (ts->seg == now_seg) - break; - } - if (ts == NULL) { - ts = (struct trampoline_seg *)xcalloc(sizeof (struct trampoline_seg), 1); + ts = XCNEW(struct trampoline_seg); ts->next = trampoline_seg_list.next; trampoline_seg_list.next = ts; ts->seg = now_seg; @@ -7456,29 +7570,218 @@ xtensa_create_trampoline_frag (bfd_boolean needs_jump_around) trampoline_buf = xtensa_insnbuf_alloc (xtensa_default_isa); trampoline_slotbuf = xtensa_insnbuf_alloc (xtensa_default_isa); } - tf = (struct trampoline_frag *)xmalloc(sizeof (struct trampoline_frag)); - tf->next = ts->trampoline_list.next; - ts->trampoline_list.next = tf; - tf->needs_jump_around = needs_jump_around; - tf->fragP = fragP; - tf->fixP = NULL; + fragP->tc_frag_data.needs_jump_around = needs_jump_around; + xg_add_trampoline_to_seg (ts, fragP); } +static bfd_boolean xg_is_trampoline_frag_full (const fragS *fragP) +{ + return fragP->fr_var < 3; +} -static struct trampoline_seg * -find_trampoline_seg (asection *seg) +static int xg_order_trampoline_chain_entry (const void *a, const void *b) { - struct trampoline_seg *ts = trampoline_seg_list.next; + const struct trampoline_chain_entry *pa = a; + const struct trampoline_chain_entry *pb = b; - for ( ; ts; ts = ts->next) + if (pa->sym != pb->sym) { - if (ts->seg == seg) - return ts; + valueT aval = S_GET_VALUE (pa->sym); + valueT bval = S_GET_VALUE (pb->sym); + + if (aval != bval) + return aval < bval ? -1 : 1; } + if (pa->offset != pb->offset) + return pa->offset < pb->offset ? -1 : 1; + return 0; +} - return NULL; +static void xg_sort_trampoline_chain (struct trampoline_chain *tc) +{ + qsort (tc->entry, tc->n_entries, sizeof (*tc->entry), + xg_order_trampoline_chain_entry); + tc->needs_sorting = FALSE; } +/* Find entry index in the given chain with maximal address <= source. */ +static size_t xg_find_chain_entry (struct trampoline_chain *tc, + addressT source) +{ + size_t a = 0; + size_t b = tc->n_entries; + + if (tc->needs_sorting) + xg_sort_trampoline_chain (tc); + + while (b - a > 1) + { + size_t c = (a + b) / 2; + struct trampoline_chain_entry *e = tc->entry + c; + + if (S_GET_VALUE(e->sym) + e->offset <= source) + a = c; + else + b = c; + } + return a; +} + +/* Find the best jump target for the source in the given trampoline chain. + The best jump target is the one that results in the shortest path to the + final target, it's the location of the jump closest to the final target, + but within the J_RANGE - J_MARGIN from the source. */ +static struct trampoline_chain_entry * +xg_get_best_chain_entry (struct trampoline_chain *tc, addressT source) +{ + addressT target = S_GET_VALUE(tc->target.sym) + tc->target.offset; + size_t i = xg_find_chain_entry (tc, source); + struct trampoline_chain_entry *e = tc->entry + i; + int step = target < source ? -1 : 1; + addressT chained_target; + offsetT off; + + if (target > source && + S_GET_VALUE(e->sym) + e->offset <= source && + i + 1 < tc->n_entries) + ++i; + + while (i + step < tc->n_entries) + { + struct trampoline_chain_entry *next = tc->entry + i + step; + + chained_target = S_GET_VALUE(next->sym) + next->offset; + off = source - chained_target; + + if (labs (off) >= J_RANGE - J_MARGIN) + break; + + i += step; + } + + e = tc->entry + i; + chained_target = S_GET_VALUE(e->sym) + e->offset; + off = source - chained_target; + + if (labs (off) < J_MARGIN || + labs (off) >= J_RANGE - J_MARGIN) + return &tc->target; + return tc->entry + i; +} + +static int xg_order_trampoline_chain (const void *a, const void *b) +{ + const struct trampoline_chain *_pa = a; + const struct trampoline_chain *_pb = b; + const struct trampoline_chain_entry *pa = &_pa->target; + const struct trampoline_chain_entry *pb = &_pb->target; + symbolS *s1 = pa->sym; + symbolS *s2 = pb->sym; + + if (s1 != s2) + { + symbolS *tmp = symbol_symbolS (s1); + if (tmp) + s1 = tmp; + + tmp = symbol_symbolS (s2); + if (tmp) + s2 = tmp; + + if (s1 != s2) + return s1 < s2 ? -1 : 1; + } + + if (pa->offset != pb->offset) + return pa->offset < pb->offset ? -1 : 1; + return 0; +} + +static struct trampoline_chain * +xg_get_trampoline_chain (struct trampoline_seg *ts, + symbolS *sym, + addressT offset) +{ + struct trampoline_chain_index *idx = &ts->chain_index; + struct trampoline_chain c; + + if (idx->needs_sorting) + { + qsort (idx->entry, idx->n_entries, sizeof (*idx->entry), + xg_order_trampoline_chain); + idx->needs_sorting = FALSE; + } + c.target.sym = sym; + c.target.offset = offset; + return bsearch (&c, idx->entry, idx->n_entries, + sizeof (struct trampoline_chain), + xg_order_trampoline_chain); +} + +/* Find trampoline chain in the given trampoline segment that is going + to the *sym + *offset. If found, replace *sym and *offset with the + best jump target in that chain. */ +static struct trampoline_chain * +xg_find_best_eq_target (struct trampoline_seg *ts, + addressT source, symbolS **sym, + addressT *offset) +{ + struct trampoline_chain *tc = xg_get_trampoline_chain (ts, *sym, *offset); + + if (tc) + { + struct trampoline_chain_entry *e = xg_get_best_chain_entry (tc, source); + + *sym = e->sym; + *offset = e->offset; + } + return tc; +} + +static void xg_add_location_to_chain (struct trampoline_chain *tc, + symbolS *sym, addressT offset) +{ + struct trampoline_chain_entry *e; + + if (tc->n_entries == tc->n_max) + { + tc->n_max = (tc->n_max + 1) * 2; + tc->entry = xrealloc (tc->entry, sizeof (*tc->entry) * tc->n_max); + } + e = tc->entry + tc->n_entries; + e->sym = sym; + e->offset = offset; + ++tc->n_entries; + tc->needs_sorting = TRUE; +} + +static struct trampoline_chain * +xg_create_trampoline_chain (struct trampoline_seg *ts, + symbolS *sym, addressT offset) +{ + struct trampoline_chain_index *idx = &ts->chain_index; + struct trampoline_chain *tc; + + if (idx->n_entries == idx->n_max) + { + idx->n_max = (idx->n_max + 1) * 2; + idx->entry = xrealloc (idx->entry, + sizeof (*idx->entry) * idx->n_max); + } + + tc = idx->entry + idx->n_entries; + tc->target.sym = sym; + tc->target.offset = offset; + tc->entry = NULL; + tc->n_entries = 0; + tc->n_max = 0; + xg_add_location_to_chain (tc, sym, offset); + + ++idx->n_entries; + idx->needs_sorting = TRUE; + + return tc; +} void dump_trampolines (void); @@ -7489,19 +7792,20 @@ dump_trampolines (void) for ( ; ts; ts = ts->next) { + size_t i; asection *seg = ts->seg; if (seg == NULL) continue; fprintf(stderr, "SECTION %s\n", seg->name); - struct trampoline_frag *tf = ts->trampoline_list.next; - for ( ; tf; tf = tf->next) + + for (i = 0; i < ts->index.n_entries; ++i) { - if (tf->fragP == NULL) - continue; + fragS *tf = ts->index.entry[i]; + fprintf(stderr, " 0x%08x: fix=%d, jump_around=%s\n", - (int)tf->fragP->fr_address, (int)tf->fragP->fr_fix, - tf->needs_jump_around ? "T" : "F"); + (int)tf->fr_address, (int)tf->fr_fix, + tf->tc_frag_data.needs_jump_around ? "T" : "F"); } } } @@ -7555,12 +7859,16 @@ xtensa_maybe_create_literal_pool_frag (bfd_boolean create, if (lps == NULL) { - lps = (struct litpool_seg *)xcalloc (sizeof (struct litpool_seg), 1); + lps = XCNEW (struct litpool_seg); lps->next = litpool_seg_list.next; litpool_seg_list.next = lps; lps->seg = now_seg; lps->frag_list.next = &lps->frag_list; lps->frag_list.prev = &lps->frag_list; + /* Put candidate literal pool at the beginning of every section, + so that even when section starts with literal load there's a + literal pool available. */ + lps->frag_count = auto_litpool_limit; } lps->frag_count++; @@ -7621,7 +7929,7 @@ xtensa_maybe_create_literal_pool_frag (bfd_boolean create, fragP = frag_now; } - lpf = (struct litpool_frag *)xmalloc(sizeof (struct litpool_frag)); + lpf = XNEW (struct litpool_frag); /* Insert at tail of circular list. */ lpf->addr = 0; lps->frag_list.prev->next = lpf; @@ -7631,6 +7939,7 @@ xtensa_maybe_create_literal_pool_frag (bfd_boolean create, lpf->fragP = fragP; lpf->priority = (needed) ? (only_if_needed) ? 3 : 2 : 1; lpf->original_priority = lpf->priority; + lpf->literal_count = 0; lps->frag_count = 0; } @@ -7991,7 +8300,7 @@ next_instrs_are_b_retw (fragS *fragP) static xtensa_insnbuf insnbuf = NULL; static xtensa_insnbuf slotbuf = NULL; xtensa_isa isa = xtensa_default_isa; - int offset = 0; + unsigned int offset = 0; int slot; bfd_boolean branch_seen = FALSE; @@ -8384,7 +8693,7 @@ unrelaxed_frag_min_insn_count (fragS *fragP) xtensa_isa isa = xtensa_default_isa; static xtensa_insnbuf insnbuf = NULL; int insn_count = 0; - int offset = 0; + unsigned int offset = 0; if (!fragP->tc_frag_data.is_insn) return insn_count; @@ -8437,7 +8746,7 @@ unrelaxed_frag_has_b_j (fragS *fragP) { static xtensa_insnbuf insnbuf = NULL; xtensa_isa isa = xtensa_default_isa; - int offset = 0; + unsigned int offset = 0; if (!fragP->tc_frag_data.is_insn) return FALSE; @@ -8636,9 +8945,9 @@ xtensa_add_config_info (void) int sz; info_sec = subseg_new (".xtensa.info", 0); - bfd_set_section_flags (stdoutput, info_sec, SEC_HAS_CONTENTS | SEC_READONLY); + bfd_set_section_flags (info_sec, SEC_HAS_CONTENTS | SEC_READONLY); - data = xmalloc (100); + data = XNEWVEC (char, 100); sprintf (data, "USE_ABSOLUTE_LITERALS=%d\nABI=%d\n", XSHAL_USE_ABSOLUTE_LITERALS, XSHAL_ABI); sz = strlen (data) + 1; @@ -9010,50 +9319,122 @@ static long relax_frag_for_align (fragS *, long); static long relax_frag_immed (segT, fragS *, long, int, xtensa_format, int, int *, bfd_boolean); -typedef struct cached_fixup cached_fixupS; -struct cached_fixup +/* Get projected address for the first fulcrum on a path from source to + target. */ +static addressT xg_get_fulcrum (addressT source, addressT target) { - int addr; - int target; - int delta; - fixS *fixP; -}; - -typedef struct fixup_cache fixup_cacheS; -struct fixup_cache -{ - cached_fixupS *fixups; - unsigned n_fixups; - unsigned n_max; + offsetT delta = target - source; + int n; - segT seg; - fragS *first_frag; -}; + n = (labs (delta) + J_RANGE - J_MARGIN - 1) / (J_RANGE - J_MARGIN); + return source + delta / n; +} -static int fixup_order (const void *a, const void *b) +/* Given trampoline index, source and target of a jump find the best + candidate trampoline for the first fulcrum. The best trampoline is + the one in the reach of "j' instruction from the source, closest to + the projected fulcrum address, and preferrably w/o a jump around or + with already initialized jump around. */ +static size_t xg_find_best_trampoline (struct trampoline_index *idx, + addressT source, addressT target) { - const cached_fixupS *pa = a; - const cached_fixupS *pb = b; + addressT fulcrum = xg_get_fulcrum (source, target); + size_t dist = 0; + size_t best = -1; + size_t base_tr = xg_find_trampoline (idx, fulcrum); + int checked = 1; - if (pa->addr == pb->addr) + /* Check trampoline frags around the base_tr to find the best. */ + for (dist = 0; checked; ++dist) { - if (pa->target == pb->target) - { - if (pa->fixP->fx_r_type == pb->fixP->fx_r_type) - return 0; - return pa->fixP->fx_r_type < pb->fixP->fx_r_type ? -1 : 1; - } - return pa->target - pb->target; + int i; + size_t tr = base_tr - dist; + + checked = 0; + + /* Trampolines are checked in the following order: + base_tr, base_tr + 1, base_tr - 1, base_tr + 2, base_tr - 2 */ + for (i = 0; i < 2; ++i, tr = base_tr + dist + 1) + if (tr < idx->n_entries) + { + fragS *trampoline_frag = idx->entry[tr]; + offsetT off; + + /* Don't check trampolines outside source - target interval. */ + if ((trampoline_frag->fr_address < source && + trampoline_frag->fr_address < target) || + (trampoline_frag->fr_address > source && + trampoline_frag->fr_address > target)) + continue; + + /* Don't choose trampoline that contains the source. */ + if (source >= trampoline_frag->fr_address + && source <= trampoline_frag->fr_address + + trampoline_frag->fr_fix) + continue; + + off = trampoline_frag->fr_address - fulcrum; + /* Stop if some trampoline is found and the search is more than + J_RANGE / 4 from the projected fulcrum. A trampoline w/o jump + around is nice, but it shouldn't have much overhead. */ + if (best < idx->n_entries && labs (off) > J_RANGE / 4) + return best; + + off = trampoline_frag->fr_address - source; + if (labs (off) < J_RANGE - J_MARGIN) + { + ++checked; + /* Stop if a trampoline w/o jump around is found or initialized + trampoline with jump around is found. */ + if (!trampoline_frag->tc_frag_data.needs_jump_around || + trampoline_frag->fr_fix) + return tr; + else if (best >= idx->n_entries) + best = tr; + } + } } - return pa->addr - pb->addr; + + if (best < idx->n_entries) + return best; + else + as_fatal (_("cannot find suitable trampoline")); } -static bfd_boolean xtensa_make_cached_fixup (cached_fixupS *o, fixS *fixP) +static fixS *xg_relax_fixup (struct trampoline_index *idx, fixS *fixP) +{ + symbolS *s = fixP->fx_addsy; + addressT source = fixP->fx_frag->fr_address; + addressT target = S_GET_VALUE (s) + fixP->fx_offset; + size_t tr = xg_find_best_trampoline (idx, source, target); + fragS *trampoline_frag = idx->entry[tr]; + fixS *newfixP; + + init_trampoline_frag (trampoline_frag); + newfixP = xg_append_jump (trampoline_frag, + fixP->fx_addsy, fixP->fx_offset); + + /* Adjust the fixup for the original "j" instruction to + point to the newly added jump. */ + fixP->fx_addsy = trampoline_frag->fr_symbol; + fixP->fx_offset = trampoline_frag->fr_fix - 3; + fixP->tc_fix_data.X_add_symbol = trampoline_frag->fr_symbol; + fixP->tc_fix_data.X_add_number = trampoline_frag->fr_fix - 3; + + trampoline_frag->tc_frag_data.relax_seen = FALSE; + + if (xg_is_trampoline_frag_full (trampoline_frag)) + xg_remove_trampoline_from_index (idx, tr); + + return newfixP; +} + +static bfd_boolean xg_is_relaxable_fixup (fixS *fixP) { xtensa_isa isa = xtensa_default_isa; - int addr = fixP->fx_frag->fr_address; - int target; - int delta; + addressT addr = fixP->fx_frag->fr_address; + addressT target; + offsetT delta; symbolS *s = fixP->fx_addsy; int slot; xtensa_format fmt; @@ -9062,10 +9443,11 @@ static bfd_boolean xtensa_make_cached_fixup (cached_fixupS *o, fixS *fixP) if (fixP->fx_r_type < BFD_RELOC_XTENSA_SLOT0_OP || fixP->fx_r_type > BFD_RELOC_XTENSA_SLOT14_OP) return FALSE; - target = S_GET_VALUE (s); + + target = S_GET_VALUE (s) + fixP->fx_offset; delta = target - addr; - if (abs(delta) < J_RANGE / 2) + if (labs (delta) < J_RANGE - J_MARGIN) return FALSE; xtensa_insnbuf_from_chars (isa, trampoline_buf, @@ -9076,87 +9458,52 @@ static bfd_boolean xtensa_make_cached_fixup (cached_fixupS *o, fixS *fixP) slot = fixP->tc_fix_data.slot; xtensa_format_get_slot (isa, fmt, slot, trampoline_buf, trampoline_slotbuf); opcode = xtensa_opcode_decode (isa, fmt, slot, trampoline_slotbuf); - if (opcode != xtensa_j_opcode) - return FALSE; - - o->addr = addr; - o->target = target; - o->delta = delta; - o->fixP = fixP; - - return TRUE; + return opcode == xtensa_j_opcode; } -static void xtensa_realloc_fixup_cache (fixup_cacheS *cache, unsigned add) +static void xg_relax_fixups (struct trampoline_seg *ts) { - if (cache->n_fixups + add > cache->n_max) - { - cache->n_max = (cache->n_fixups + add) * 2; - cache->fixups = xrealloc (cache->fixups, - sizeof (*cache->fixups) * cache->n_max); - } -} + struct trampoline_index *idx = &ts->index; + segment_info_type *seginfo = seg_info (now_seg); + fixS *fx; -static void xtensa_cache_relaxable_fixups (fixup_cacheS *cache, - segment_info_type *seginfo) -{ - fixS *fixP; - - cache->n_fixups = 0; - - for (fixP = seginfo->fix_root; fixP ; fixP = fixP->fx_next) + for (fx = seginfo->fix_root; fx; fx = fx->fx_next) { - xtensa_realloc_fixup_cache (cache, 1); - - if (xtensa_make_cached_fixup (cache->fixups + cache->n_fixups, fixP)) - ++cache->n_fixups; - } - qsort (cache->fixups, cache->n_fixups, sizeof (*cache->fixups), fixup_order); -} - -static unsigned xtensa_find_first_cached_fixup (const fixup_cacheS *cache, - int addr) -{ - unsigned a = 0; - unsigned b = cache->n_fixups; + fixS *fixP = fx; + struct trampoline_chain *tc = NULL; - while (b - a > 1) - { - unsigned c = (a + b) / 2; + if (xg_is_relaxable_fixup (fixP)) + { + tc = xg_find_best_eq_target (ts, fixP->fx_frag->fr_address, + &fixP->fx_addsy, &fixP->fx_offset); + if (!tc) + tc = xg_create_trampoline_chain (ts, fixP->fx_addsy, + fixP->fx_offset); + gas_assert (tc); + } - if (cache->fixups[c].addr < addr) - a = c; - else - b = c; + while (xg_is_relaxable_fixup (fixP)) + { + fixP = xg_relax_fixup (idx, fixP); + xg_add_location_to_chain (tc, fixP->fx_frag->fr_symbol, + fixP->fx_where); + } } - return a; -} - -static void xtensa_delete_cached_fixup (fixup_cacheS *cache, unsigned i) -{ - memmove (cache->fixups + i, cache->fixups + i + 1, - (cache->n_fixups - i - 1) * sizeof (*cache->fixups)); - --cache->n_fixups; } -static bfd_boolean xtensa_add_cached_fixup (fixup_cacheS *cache, fixS *fixP) +/* Given a trampoline frag relax all jumps that might want to use this + trampoline. Only do real work once per relaxation cycle, when + xg_relax_trampoline is called for the first trampoline in the now_seg. + Don't use stretch, don't update new_stretch: place fulcrums with a + slack to tolerate code movement. In the worst case if a jump between + two trampolines wouldn't reach the next relaxation pass will fix it. */ +static void xg_relax_trampoline (fragS *fragP, long stretch ATTRIBUTE_UNUSED, + long *new_stretch ATTRIBUTE_UNUSED) { - cached_fixupS o; - unsigned i; + struct trampoline_seg *ts = find_trampoline_seg (now_seg); - if (!xtensa_make_cached_fixup (&o, fixP)) - return FALSE; - xtensa_realloc_fixup_cache (cache, 1); - i = xtensa_find_first_cached_fixup (cache, o.addr); - if (i < cache->n_fixups) - { - ++i; - memmove (cache->fixups + i + 1, cache->fixups + i, - (cache->n_fixups - i) * sizeof (*cache->fixups)); - } - cache->fixups[i] = o; - ++cache->n_fixups; - return TRUE; + if (ts->index.n_entries && ts->index.entry[0] == fragP) + xg_relax_fixups (ts); } /* Return the number of bytes added to this fragment, given that the @@ -9302,163 +9649,7 @@ xtensa_relax_frag (fragS *fragP, long stretch, int *stretched_p) case RELAX_TRAMPOLINE: if (fragP->tc_frag_data.relax_seen) - { - static fixup_cacheS fixup_cache; - segment_info_type *seginfo = seg_info (now_seg); - int trampaddr = fragP->fr_address + fragP->fr_fix; - int searchaddr = trampaddr < J_RANGE ? 0 : trampaddr - J_RANGE; - unsigned i; - - if (now_seg != fixup_cache.seg || - fragP == fixup_cache.first_frag || - fixup_cache.first_frag == NULL) - { - xtensa_cache_relaxable_fixups (&fixup_cache, seginfo); - fixup_cache.seg = now_seg; - fixup_cache.first_frag = fragP; - } - - /* Scan for jumps that will not reach. */ - for (i = xtensa_find_first_cached_fixup (&fixup_cache, searchaddr); - i < fixup_cache.n_fixups; ++i) - - { - fixS *fixP = fixup_cache.fixups[i].fixP; - int target = fixup_cache.fixups[i].target; - int addr = fixup_cache.fixups[i].addr; - int delta = fixup_cache.fixups[i].delta + stretch; - - trampaddr = fragP->fr_address + fragP->fr_fix; - - if (addr + J_RANGE < trampaddr) - continue; - if (addr > trampaddr + J_RANGE) - break; - if (abs (delta) < J_RANGE) - continue; - - slot = fixP->tc_fix_data.slot; - - if (delta > J_RANGE || delta < -1 * J_RANGE) - { /* Found an out-of-range jump; scan the list of trampolines for the best match. */ - struct trampoline_seg *ts = find_trampoline_seg (now_seg); - struct trampoline_frag *tf = ts->trampoline_list.next; - struct trampoline_frag *prev = &ts->trampoline_list; - int lower = (target < addr) ? target : addr; - int upper = (target > addr) ? target : addr; - int midpoint = lower + (upper - lower) / 2; - - if ((upper - lower) > 2 * J_RANGE) - { - /* One trampoline won't suffice; we need multiple jumps. - Jump to the trampoline that's farthest, but still in - range relative to the original "j" instruction. */ - for ( ; tf; prev = tf, tf = tf->next ) - { - int this_addr = tf->fragP->fr_address + tf->fragP->fr_fix; - int next_addr = (tf->next) ? tf->next->fragP->fr_address + tf->next->fragP->fr_fix : 0 ; - - if (addr == lower) - { - /* Forward jump. */ - if (this_addr - addr < J_RANGE) - break; - } - else - { - /* Backward jump. */ - if (next_addr == 0 || addr - next_addr > J_RANGE) - break; - } - } - } - else - { - struct trampoline_frag *best_tf = NULL; - int best_delta = 0; - - for ( ; tf; prev = tf, tf = tf->next ) - { - int this_addr = tf->fragP->fr_address + tf->fragP->fr_fix; - int this_delta = abs (this_addr - midpoint); - - if (!best_tf || this_delta < best_delta) - { - best_tf = tf; - best_delta = this_delta; - } - } - tf = best_tf; - } - if (tf->fragP == fragP) - { - if (abs (addr - trampaddr) < J_RANGE) - { /* The trampoline is in range of original; fix it! */ - fixS *newfixP; - int offset; - TInsn insn; - symbolS *lsym; - fragS *fP; /* The out-of-range jump. */ - - new_stretch += init_trampoline_frag (tf); - offset = fragP->fr_fix; /* Where to assemble the j insn. */ - lsym = fragP->fr_symbol; - fP = fixP->fx_frag; - /* Assemble a jump to the target label here. */ - tinsn_init (&insn); - insn.insn_type = ITYPE_INSN; - insn.opcode = xtensa_j_opcode; - insn.ntok = 1; - set_expr_symbol_offset (&insn.tok[0], lsym, offset); - fmt = xg_get_single_format (xtensa_j_opcode); - tinsn_to_slotbuf (fmt, 0, &insn, trampoline_slotbuf); - xtensa_format_set_slot (isa, fmt, 0, trampoline_buf, trampoline_slotbuf); - xtensa_insnbuf_to_chars (isa, trampoline_buf, (unsigned char *)fragP->fr_literal + offset, 3); - fragP->fr_fix += 3; - fragP->fr_var -= 3; - /* Add a fix-up for the original j insn. */ - newfixP = fix_new (fP, fixP->fx_where, fixP->fx_size, lsym, fragP->fr_fix - 3, TRUE, fixP->fx_r_type); - newfixP->fx_no_overflow = 1; - newfixP->tc_fix_data.X_add_symbol = lsym; - newfixP->tc_fix_data.X_add_number = offset; - newfixP->tc_fix_data.slot = slot; - - xtensa_delete_cached_fixup (&fixup_cache, i); - xtensa_add_cached_fixup (&fixup_cache, newfixP); - - /* Move the fix-up from the original j insn to this one. */ - fixP->fx_frag = fragP; - fixP->fx_where = fragP->fr_fix - 3; - fixP->tc_fix_data.slot = 0; - - xtensa_add_cached_fixup (&fixup_cache, fixP); - - /* re-do current fixup */ - --i; - - /* Adjust the jump around this trampoline (if present). */ - if (tf->fixP != NULL) - { - tf->fixP->fx_offset += 3; - } - new_stretch += 3; - fragP->tc_frag_data.relax_seen = FALSE; /* Need another pass. */ - /* Do we have room for more? */ - if (fragP->fr_var < 3) - { /* No, convert to fill. */ - frag_wane (fragP); - fragP->fr_subtype = 0; - /* Remove from the trampoline_list. */ - prev->next = tf->next; - if (fragP == fixup_cache.first_frag) - fixup_cache.first_frag = NULL; - break; - } - } - } - } - } - } + xg_relax_trampoline (fragP, stretch, &new_stretch); break; default: @@ -9899,197 +10090,134 @@ bytes_to_stretch (fragS *this_frag, } -static struct trampoline_frag * -search_trampolines (TInsn *tinsn, fragS *fragP, bfd_boolean unreachable_only) +static fragS * +xg_find_best_trampoline_for_tinsn (TInsn *tinsn, fragS *fragP) { - struct trampoline_seg *ts = find_trampoline_seg (now_seg); - struct trampoline_frag *tf = (ts) ? ts->trampoline_list.next : NULL; - struct trampoline_frag *best_tf = NULL; - int best_delta = 0; - int best_addr = 0; symbolS *sym = tinsn->tok[0].X_add_symbol; - offsetT target = S_GET_VALUE (sym) + tinsn->tok[0].X_add_number; - offsetT addr = fragP->fr_address; - offsetT lower = (addr < target) ? addr : target; - offsetT upper = (addr > target) ? addr : target; - int delta = upper - lower; - offsetT midpoint = lower + delta / 2; - int this_delta = -1; - int this_addr = -1; - - if (delta > 2 * J_RANGE) - { - /* One trampoline won't do; we need multiple. - Choose the farthest trampoline that's still in range of the original - and let a later pass finish the job. */ - for ( ; tf; tf = tf->next) - { - int next_addr = (tf->next) ? tf->next->fragP->fr_address + tf->next->fragP->fr_fix : 0; - - this_addr = tf->fragP->fr_address + tf->fragP->fr_fix; - if (lower == addr) - { - /* Forward jump. */ - if (this_addr - addr < J_RANGE) - break; - } - else - { - /* Backward jump. */ - if (next_addr == 0 || addr - next_addr > J_RANGE) - break; - } - } - if (abs (addr - this_addr) < J_RANGE) - return tf; + addressT source = fragP->fr_address; + addressT target = S_GET_VALUE (sym) + tinsn->tok[0].X_add_number; + struct trampoline_seg *ts = find_trampoline_seg (now_seg); + size_t i; - return NULL; - } - for ( ; tf; tf = tf->next) - { - this_addr = tf->fragP->fr_address + tf->fragP->fr_fix; - this_delta = abs (this_addr - midpoint); - if (unreachable_only && tf->needs_jump_around) - continue; - if (!best_tf || this_delta < best_delta) - { - best_tf = tf; - best_delta = this_delta; - best_addr = this_addr; - } - } + if (!ts || !ts->index.n_entries) + return NULL; - if (best_tf && - best_delta < J_RANGE && - abs(best_addr - lower) < J_RANGE && - abs(best_addr - upper) < J_RANGE) - return best_tf; + i = xg_find_best_trampoline (&ts->index, source, target); - return NULL; /* No suitable trampoline found. */ + return ts->index.entry[i]; } -static struct trampoline_frag * -get_best_trampoline (TInsn *tinsn, fragS *fragP) +/* Append jump to sym + offset to the end of the trampoline frag fragP. + Adjust fragP's jump around if it's present. Adjust fragP's fr_fix/fr_var + and finish the frag if it's full (but don't remove it from the trampoline + frag index). Return fixup for the newly created jump. */ +static fixS *xg_append_jump (fragS *fragP, symbolS *sym, offsetT offset) { - struct trampoline_frag *tf = NULL; - - tf = search_trampolines (tinsn, fragP, TRUE); /* Try unreachable first. */ - - if (tf == NULL) - tf = search_trampolines (tinsn, fragP, FALSE); /* Try ones needing a jump-around, too. */ + fixS *fixP; + TInsn insn; + xtensa_format fmt; + xtensa_isa isa = xtensa_default_isa; - return tf; -} + gas_assert (fragP->fr_var >= 3); + tinsn_init (&insn); + insn.insn_type = ITYPE_INSN; + insn.opcode = xtensa_j_opcode; + insn.ntok = 1; + set_expr_symbol_offset (&insn.tok[0], sym, offset); + fmt = xg_get_single_format (xtensa_j_opcode); + tinsn_to_slotbuf (fmt, 0, &insn, trampoline_slotbuf); + xtensa_format_set_slot (isa, fmt, 0, trampoline_buf, trampoline_slotbuf); + xtensa_insnbuf_to_chars (isa, trampoline_buf, + (unsigned char *)fragP->fr_literal + fragP->fr_fix, 3); + fixP = fix_new (fragP, fragP->fr_fix, 3, sym, offset, TRUE, + BFD_RELOC_XTENSA_SLOT0_OP); + fixP->tc_fix_data.slot = 0; + fragP->fr_fix += 3; + fragP->fr_var -= 3; -static void -check_and_update_trampolines (void) -{ - struct trampoline_seg *ts = find_trampoline_seg (now_seg); - struct trampoline_frag *tf = ts->trampoline_list.next; - struct trampoline_frag *prev = &ts->trampoline_list; + /* Adjust the jump around this trampoline (if present). */ + if (fragP->tc_frag_data.jump_around_fix) + fragP->tc_frag_data.jump_around_fix->fx_offset += 3; - for ( ; tf; prev = tf, tf = tf->next) + /* Do we have room for more? */ + if (xg_is_trampoline_frag_full (fragP)) { - if (tf->fragP->fr_var < 3) - { - frag_wane (tf->fragP); - prev->next = tf->next; - tf->fragP = NULL; - } + frag_wane (fragP); + fragP->fr_subtype = 0; } + + return fixP; } static int -init_trampoline_frag (struct trampoline_frag *trampP) +init_trampoline_frag (fragS *fp) { - fragS *fp = trampP->fragP; int growth = 0; if (fp->fr_fix == 0) { symbolS *lsym; char label[10 + 2 * sizeof(fp)]; - sprintf (label, ".L0_TR_%p", fp); + sprintf (label, ".L0_TR_%p", fp); lsym = (symbolS *)local_symbol_make (label, now_seg, 0, fp); fp->fr_symbol = lsym; - if (trampP->needs_jump_around) + if (fp->tc_frag_data.needs_jump_around) { - /* Add a jump around this block of jumps, in case - control flows into this block. */ - fixS *fixP; - TInsn insn; - xtensa_format fmt; - xtensa_isa isa = xtensa_default_isa; - - fp->tc_frag_data.is_insn = 1; - /* Assemble a jump insn. */ - tinsn_init (&insn); - insn.insn_type = ITYPE_INSN; - insn.opcode = xtensa_j_opcode; - insn.ntok = 1; - set_expr_symbol_offset (&insn.tok[0], lsym, 3); - fmt = xg_get_single_format (xtensa_j_opcode); - tinsn_to_slotbuf (fmt, 0, &insn, trampoline_slotbuf); - xtensa_format_set_slot (isa, fmt, 0, trampoline_buf, trampoline_slotbuf); - xtensa_insnbuf_to_chars (isa, trampoline_buf, (unsigned char *)fp->fr_literal, 3); - fp->fr_fix += 3; - fp->fr_var -= 3; + fp->tc_frag_data.jump_around_fix = xg_append_jump (fp, lsym, 3); growth = 3; - fixP = fix_new (fp, 0, 3, lsym, 3, TRUE, BFD_RELOC_XTENSA_SLOT0_OP); - trampP->fixP = fixP; } } return growth; } - static int -add_jump_to_trampoline (struct trampoline_frag *trampP, fragS *origfrag) +xg_get_single_symbol_slot (fragS *fragP) +{ + int i; + int slot = -1; + + for (i = 0; i < MAX_SLOTS; ++i) + if (fragP->tc_frag_data.slot_symbols[i]) + { + gas_assert (slot == -1); + slot = i; + } + + gas_assert (slot >= 0 && slot < MAX_SLOTS); + + return slot; +} + +static fixS * +add_jump_to_trampoline (fragS *tramp, fragS *origfrag) { - fragS *tramp = trampP->fragP; + int slot = xg_get_single_symbol_slot (origfrag); fixS *fixP; - int offset = tramp->fr_fix; /* Where to assemble the j insn. */ - TInsn insn; - symbolS *lsym; - symbolS *tsym; - int toffset; - xtensa_format fmt; - xtensa_isa isa = xtensa_default_isa; - int growth = 0; - lsym = tramp->fr_symbol; /* Assemble a jump to the target label in the trampoline frag. */ - tsym = origfrag->tc_frag_data.slot_symbols[0]; - toffset = origfrag-> tc_frag_data.slot_offsets[0]; - tinsn_init (&insn); - insn.insn_type = ITYPE_INSN; - insn.opcode = xtensa_j_opcode; - insn.ntok = 1; - set_expr_symbol_offset (&insn.tok[0], tsym, toffset); - fmt = xg_get_single_format (xtensa_j_opcode); - tinsn_to_slotbuf (fmt, 0, &insn, trampoline_slotbuf); - xtensa_format_set_slot (isa, fmt, 0, trampoline_buf, trampoline_slotbuf); - xtensa_insnbuf_to_chars (isa, trampoline_buf, (unsigned char *)tramp->fr_literal + offset, 3); - tramp->fr_fix += 3; - tramp->fr_var -= 3; - growth = 3; - /* add a fix-up for the trampoline jump. */ - fixP = fix_new (tramp, tramp->fr_fix - 3, 3, tsym, toffset, TRUE, BFD_RELOC_XTENSA_SLOT0_OP); - /* Modify the jump at the start of this trampoline to point past the newly-added jump. */ - fixP = trampP->fixP; - if (fixP) - fixP->fx_offset += 3; + fixP = xg_append_jump (tramp, + origfrag->tc_frag_data.slot_symbols[slot], + origfrag->tc_frag_data.slot_offsets[slot]); + /* Modify the original j to point here. */ - origfrag->tc_frag_data.slot_symbols[0] = lsym; - origfrag->tc_frag_data.slot_offsets[0] = tramp->fr_fix - 3; + origfrag->tc_frag_data.slot_symbols[slot] = tramp->fr_symbol; + origfrag->tc_frag_data.slot_offsets[slot] = tramp->fr_fix - 3; + /* If trampoline is full, remove it from the list. */ - check_and_update_trampolines (); + if (xg_is_trampoline_frag_full (tramp)) + { + struct trampoline_seg *ts = find_trampoline_seg (now_seg); + size_t tr = xg_find_trampoline (&ts->index, tramp->fr_address); - return growth; + gas_assert (ts->index.entry[tr] == tramp); + xg_remove_trampoline_from_index (&ts->index, tr); + } + + return fixP; } @@ -10238,15 +10366,42 @@ relax_frag_immed (segT segP, istack.insn[istack.ninsn - 2].opcode == xtensa_j_opcode) { TInsn *jinsn = &istack.insn[istack.ninsn - 2]; + struct trampoline_seg *ts = find_trampoline_seg (segP); + struct trampoline_chain *tc = NULL; + + if (ts && + !xg_symbolic_immeds_fit (jinsn, segP, fragP, fragP->fr_offset, + total_text_diff)) + { + int s = xg_get_single_symbol_slot (fragP); + addressT offset = fragP->tc_frag_data.slot_offsets[s]; - if (!xg_symbolic_immeds_fit (jinsn, segP, fragP, fragP->fr_offset, total_text_diff)) + tc = xg_find_best_eq_target (ts, fragP->fr_address, + &fragP->tc_frag_data.slot_symbols[s], + &offset); + + if (!tc) + tc = xg_create_trampoline_chain (ts, + fragP->tc_frag_data.slot_symbols[s], + offset); + fragP->tc_frag_data.slot_offsets[s] = offset; + tinsn_immed_from_frag (jinsn, fragP, s); + } + + if (!xg_symbolic_immeds_fit (jinsn, segP, fragP, fragP->fr_offset, + total_text_diff)) { - struct trampoline_frag *tf = get_best_trampoline (jinsn, fragP); + fragS *tf = xg_find_best_trampoline_for_tinsn (jinsn, fragP); if (tf) { - this_text_diff += init_trampoline_frag (tf); - this_text_diff += add_jump_to_trampoline (tf, fragP); + fixS *fixP; + + this_text_diff += init_trampoline_frag (tf) + 3; + fixP = add_jump_to_trampoline (tf, fragP); + xg_add_location_to_chain (tc, fixP->fx_frag->fr_symbol, + fixP->fx_where); + fragP->tc_frag_data.relax_seen = FALSE; } else { @@ -10505,7 +10660,6 @@ convert_frag_fill_nop (fragS *fragP) static fixS *fix_new_exp_in_seg (segT, subsegT, fragS *, int, int, expressionS *, int, bfd_reloc_code_real_type); -static void convert_frag_immed_finish_loop (segT, fragS *, TInsn *); static void convert_frag_immed (segT segP, @@ -10747,9 +10901,6 @@ convert_frag_immed (segT segP, } } - 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_tinsn.opcode)) { /* Add an expansion note on the expanded instruction. */ @@ -10786,122 +10937,6 @@ fix_new_exp_in_seg (segT new_seg, } -/* 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 (segT segP, fragS *fragP, TInsn *tinsn) -{ - TInsn loop_insn; - TInsn addi_insn; - TInsn addmi_insn; - unsigned long target; - static xtensa_insnbuf insnbuf = NULL; - unsigned int loop_length, loop_length_hi, loop_length_lo; - xtensa_isa isa = xtensa_default_isa; - addressT loop_offset; - addressT addi_offset = 9; - addressT addmi_offset = 12; - fragS *next_fragP; - int target_count; - - if (!insnbuf) - insnbuf = xtensa_insnbuf_alloc (isa); - - /* Get the loop offset. */ - loop_offset = get_expanded_loop_offset (tinsn->opcode); - - /* 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); - - gas_assert (xtensa_opcode_is_loop (isa, loop_insn.opcode) == 1); - addi_offset += loop_offset; - addmi_offset += loop_offset; - - gas_assert (tinsn->ntok == 2); - if (tinsn->tok[1].X_op == O_constant) - target = tinsn->tok[1].X_add_number; - else if (tinsn->tok[1].X_op == O_symbol) - { - /* Find the fragment. */ - symbolS *sym = tinsn->tok[1].X_add_symbol; - gas_assert (S_GET_SEGMENT (sym) == segP - || S_GET_SEGMENT (sym) == absolute_section); - target = (S_GET_VALUE (sym) + tinsn->tok[1].X_add_number); - } - else - { - as_bad (_("invalid expression evaluation type %d"), tinsn->tok[1].X_op); - target = 0; - } - - loop_length = target - (fragP->fr_address + fragP->fr_fix); - loop_length_hi = loop_length & ~0x0ff; - loop_length_lo = loop_length & 0x0ff; - if (loop_length_lo >= 128) - { - loop_length_lo -= 256; - loop_length_hi += 256; - } - - /* 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, 0); - gas_assert (addi_insn.opcode == xtensa_addi_opcode); - - tinsn_from_chars (&addmi_insn, fragP->fr_opcode + addmi_offset, 0); - gas_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, (unsigned char *) 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, (unsigned char *) 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) - { - next_fragP->tc_frag_data.is_no_transform = TRUE; - if (next_fragP->tc_frag_data.is_loop_target) - target_count++; - if (target_count == 2) - break; - } -} - /* A map that keeps information on a per-subsegment basis. This is maintained during initial assembly, but is invalid once the @@ -10942,7 +10977,7 @@ get_subseg_info (segT seg, subsegT subseg) static subseg_map * add_subseg_info (segT seg, subsegT subseg) { - subseg_map *subseg_e = (subseg_map *) xmalloc (sizeof (subseg_map)); + subseg_map *subseg_e = XNEW (subseg_map); memset (subseg_e, 0, sizeof (subseg_map)); subseg_e->seg = seg; subseg_e->subseg = subseg; @@ -11038,29 +11073,101 @@ xtensa_move_seg_list_to_beginning (seg_list *head) static void mark_literal_frags (seg_list *); static void -xtensa_move_literals (void) +xg_promote_candidate_litpool (struct litpool_seg *lps, + struct litpool_frag *lp) { - seg_list *segment; - frchainS *frchain_from, *frchain_to; - fragS *search_frag, *next_frag, *literal_pool, *insert_after; - fragS **frag_splice; - emit_state state; - segT dest_seg; - fixS *fix, *next_fix, **fix_splice; - sym_list *lit; - struct litpool_seg *lps; - const char *init_name = INIT_SECTION_NAME; - const char *fini_name = FINI_SECTION_NAME; - int init_name_len = strlen(init_name); - int fini_name_len = strlen(fini_name); + fragS *poolbeg; + fragS *poolend; + symbolS *lsym; + char label[10 + 2 * sizeof (fragS *)]; - mark_literal_frags (literal_head->next); + poolbeg = lp->fragP; + lp->priority = 1; + poolbeg->fr_subtype = RELAX_LITERAL_POOL_BEGIN; + poolend = poolbeg->fr_next; + gas_assert (poolend->fr_type == rs_machine_dependent && + poolend->fr_subtype == RELAX_LITERAL_POOL_END); + /* Create a local symbol pointing to the + end of the pool. */ + sprintf (label, ".L0_LT_%p", poolbeg); + lsym = (symbolS *)local_symbol_make (label, lps->seg, + 0, poolend); + poolbeg->fr_symbol = lsym; + /* Rest is done in xtensa_relax_frag. */ +} - if (use_literal_section) - return; +static struct litpool_frag *xg_find_litpool (struct litpool_seg *lps, + struct litpool_frag *lpf, + addressT addr) +{ + struct litpool_frag *lp = lpf->prev; - /* Assign addresses (rough estimates) to the potential literal pool locations - and create new ones if the gaps are too large. */ + gas_assert (lp->fragP); + + while (lp->fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN) + { + lp = lp->prev; + if (lp->fragP == NULL) + { + /* End of list; have to bite the bullet. + Take the nearest. */ + lp = lpf->prev; + break; + } + /* Does it (conservatively) reach? */ + if (addr - lp->addr <= 128 * 1024) + { + if (lp->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN && + lp->literal_count < MAX_POOL_LITERALS) + { + /* Found a good one. */ + break; + } + else if (lp->prev->fragP && + addr - lp->prev->addr > 128 * 1024 && + lp->prev->literal_count < MAX_POOL_LITERALS) + { + /* This is still a "candidate" but the next one + will be too far away, so revert to the nearest + one, convert it and add the jump around. */ + lp = lpf->prev; + break; + } + } + } + + if (lp->literal_count >= MAX_POOL_LITERALS) + { + lp = lpf->prev; + while (lp && lp->fragP && lp->literal_count >= MAX_POOL_LITERALS) + { + lp = lp->prev; + } + gas_assert (lp); + } + + gas_assert (lp && lp->fragP && lp->literal_count < MAX_POOL_LITERALS); + ++lp->literal_count; + + /* Convert candidate and add the jump around. */ + if (lp->fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN) + xg_promote_candidate_litpool (lps, lp); + + return lp; +} + +static bfd_boolean xtensa_is_init_fini (segT seg) +{ + if (!seg) + return 0; + return strcmp (segment_name (seg), INIT_SECTION_NAME) == 0 + || strcmp (segment_name (seg), FINI_SECTION_NAME) == 0; +} + +static void +xtensa_assign_litpool_addresses (void) +{ + struct litpool_seg *lps; for (lps = litpool_seg_list.next; lps; lps = lps->next) { @@ -11068,6 +11175,9 @@ xtensa_move_literals (void) struct litpool_frag *lpf = lps->frag_list.next; addressT addr = 0; + if (xtensa_is_init_fini (lps->seg)) + continue; + for ( ; frchP; frchP = frchP->frch_next) { fragS *fragP; @@ -11088,69 +11198,23 @@ xtensa_move_literals (void) int slot; for (slot = 0; slot < MAX_SLOTS; slot++) { - if (fragP->tc_frag_data.literal_frags[slot]) + fragS *litfrag = fragP->tc_frag_data.literal_frags[slot]; + + if (litfrag + && litfrag->tc_frag_data.is_literal + && !litfrag->tc_frag_data.literal_frag) { - /* L32R; point its literal to the nearest litpool - preferring non-"candidate" positions to avoid - the jump-around. */ - fragS *litfrag = fragP->tc_frag_data.literal_frags[slot]; - struct litpool_frag *lp = lpf->prev; - if (!lp->fragP) - { - break; - } - while (lp->fragP->fr_subtype == - RELAX_LITERAL_POOL_CANDIDATE_BEGIN) - { - lp = lp->prev; - if (lp->fragP == NULL) - { - /* End of list; have to bite the bullet. - Take the nearest. */ - lp = lpf->prev; - break; - } - /* Does it (conservatively) reach? */ - if (addr - lp->addr <= 128 * 1024) - { - if (lp->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN) - { - /* Found a good one. */ - break; - } - else if (lp->prev->fragP && - addr - lp->prev->addr > 128 * 1024) - { - /* This is still a "candidate" but the next one - will be too far away, so revert to the nearest - one, convert it and add the jump around. */ - fragS *poolbeg; - fragS *poolend; - symbolS *lsym; - char label[10 + 2 * sizeof (fragS *)]; - lp = lpf->prev; - poolbeg = lp->fragP; - lp->priority = 1; - poolbeg->fr_subtype = RELAX_LITERAL_POOL_BEGIN; - poolend = poolbeg->fr_next; - gas_assert (poolend->fr_type == rs_machine_dependent && - poolend->fr_subtype == RELAX_LITERAL_POOL_END); - /* Create a local symbol pointing to the - end of the pool. */ - sprintf (label, ".L0_LT_%p", poolbeg); - lsym = (symbolS *)local_symbol_make (label, lps->seg, - 0, poolend); - poolbeg->fr_symbol = lsym; - /* Rest is done in xtensa_relax_frag. */ - } - } - } - if (! litfrag->tc_frag_data.literal_frag) - { - /* Take earliest use of this literal to avoid - forward refs. */ - litfrag->tc_frag_data.literal_frag = lp->fragP; - } + /* L32R referring .literal or generated as a result + of relaxation. Point its literal to the nearest + litpool preferring non-"candidate" positions to + avoid the jump-around. */ + + struct litpool_frag *lp; + + lp = xg_find_litpool (lps, lpf, addr); + /* Take earliest use of this literal to avoid + forward refs. */ + litfrag->tc_frag_data.literal_frag = lp->fragP; } } } @@ -11160,7 +11224,35 @@ xtensa_move_literals (void) } } } +} +static void +xtensa_move_literals (void) +{ + seg_list *segment; + frchainS *frchain_from, *frchain_to; + fragS *search_frag, *next_frag, *literal_pool, *insert_after; + fragS **frag_splice; + emit_state state; + segT dest_seg; + fixS *fix, *next_fix, **fix_splice; + sym_list *lit; + const char *init_name = INIT_SECTION_NAME; + const char *fini_name = FINI_SECTION_NAME; + int init_name_len = strlen(init_name); + int fini_name_len = strlen(fini_name); + + mark_literal_frags (literal_head->next); + + if (use_literal_section) + return; + + /* Assign addresses (rough estimates) to the potential literal pool locations + and create new ones if the gaps are too large. */ + + xtensa_assign_litpool_addresses (); + + /* Walk through the literal segments. */ for (segment = literal_head->next; segment; segment = segment->next) { const char *seg_name = segment_name (segment->seg); @@ -11186,12 +11278,7 @@ xtensa_move_literals (void) } if (!search_frag) - { - search_frag = frchain_from->frch_root; - as_bad_where (search_frag->fr_file, search_frag->fr_line, - _("literal pool location required for text-section-literals; specify with .literal_position")); - continue; - } + continue; gas_assert (search_frag->tc_frag_data.literal_frag->fr_subtype == RELAX_LITERAL_POOL_BEGIN); @@ -11238,7 +11325,7 @@ xtensa_move_literals (void) /* First, move the frag out of the literal section and to the appropriate place. */ - /* Insert an aligmnent frag at start of pool. */ + /* Insert an alignment frag at start of pool. */ if (literal_pool->fr_next->fr_type == rs_machine_dependent && literal_pool->fr_next->fr_subtype == RELAX_LITERAL_POOL_END) { @@ -11416,40 +11503,27 @@ xtensa_switch_to_literal_fragment (emit_state *result) static void xtensa_switch_to_non_abs_literal_fragment (emit_state *result) { - static bfd_boolean recursive = FALSE; fragS *pool_location = get_literal_pool_location (now_seg); segT lit_seg; - bfd_boolean is_init = - (now_seg && !strcmp (segment_name (now_seg), INIT_SECTION_NAME)); - bfd_boolean is_fini = - (now_seg && !strcmp (segment_name (now_seg), FINI_SECTION_NAME)); + bfd_boolean is_init_fini = xtensa_is_init_fini (now_seg); if (pool_location == NULL && !use_literal_section - && !recursive - && !is_init && ! is_fini) + && !is_init_fini) { if (!auto_litpools) { as_bad (_("literal pool location required for text-section-literals; specify with .literal_position")); } - - /* 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 - switch_to_literal_fragment. But literal sections don't have - literal pools, so their location is always null, so we would - recurse forever. This is kind of hacky, but it works. */ - - recursive = TRUE; - xtensa_mark_literal_pool_location (); - recursive = FALSE; + xtensa_maybe_create_literal_pool_frag (TRUE, TRUE); + pool_location = get_literal_pool_location (now_seg); } lit_seg = cache_literal_section (FALSE); xtensa_switch_section_emit_state (result, lit_seg, 0); if (!use_literal_section - && !is_init && !is_fini + && !is_init_fini && get_literal_pool_location (now_seg) != pool_location) { /* Close whatever frag is there. */ @@ -11571,7 +11645,7 @@ cache_literal_section (bfd_boolean use_abs_literals) || strncmp (text_name, ".text", 5) == 0)) len -= 5; - name = xmalloc (len + strlen (base_name) + 1); + name = XNEWVEC (char, len + strlen (base_name) + 1); if (strncmp (text_name, ".text", 5) == 0) { strcpy (name, base_name); @@ -11600,7 +11674,7 @@ cache_literal_section (bfd_boolean use_abs_literals) if (! use_abs_literals) { /* Add the newly created literal segment to the list. */ - seg_list *n = (seg_list *) xmalloc (sizeof (seg_list)); + seg_list *n = XNEW (seg_list); n->seg = seg; n->next = literal_head->next; literal_head->next = n; @@ -11612,8 +11686,8 @@ cache_literal_section (bfd_boolean use_abs_literals) elf_group_name (seg) = group_name; - bfd_set_section_flags (stdoutput, seg, flags); - bfd_set_section_alignment (stdoutput, seg, 2); + bfd_set_section_flags (seg, flags); + bfd_set_section_alignment (seg, 2); } *pcached = seg; @@ -11744,7 +11818,7 @@ xtensa_create_property_segments (frag_predicate property_function, num_recs++; rec_size = num_recs * 8; - bfd_set_section_size (stdoutput, sec, rec_size); + bfd_set_section_size (sec, rec_size); if (num_recs) { @@ -11841,7 +11915,7 @@ xtensa_create_xproperty_segments (frag_flags_fn flag_fn, num_recs++; rec_size = num_recs * (8 + 4); - bfd_set_section_size (stdoutput, sec, rec_size); + bfd_set_section_size (sec, rec_size); /* elf_section_data (sec)->this_hdr.sh_entsize = 12; */ if (num_recs) @@ -11885,7 +11959,7 @@ xtensa_create_xproperty_segments (frag_flags_fn flag_fn, static bfd_boolean exclude_section_from_property_tables (segT sec) { - flagword flags = bfd_get_section_flags (stdoutput, sec); + flagword flags = bfd_section_flags (sec); /* Sections that don't contribute to the memory footprint are excluded. */ if ((flags & SEC_DEBUGGING) @@ -11977,8 +12051,7 @@ add_xt_block_frags (segT sec, } if (*xt_block == NULL) { - xtensa_block_info *new_block = (xtensa_block_info *) - xmalloc (sizeof (xtensa_block_info)); + xtensa_block_info *new_block = XNEW (xtensa_block_info); new_block->sec = sec; new_block->offset = fragP->fr_address; new_block->size = fragP->fr_fix; @@ -12235,8 +12308,7 @@ add_xt_prop_frags (segT sec, 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 = XNEW (xtensa_block_info); *new_block = tmp_block; *xt_block = new_block; } @@ -12261,8 +12333,7 @@ init_op_placement_info_table (void) int slot; int num_opcodes = xtensa_isa_num_opcodes (isa); - op_placement_table = (op_placement_info_table) - xmalloc (sizeof (op_placement_info) * num_opcodes); + op_placement_table = XNEWVEC (op_placement_info, num_opcodes); gas_assert (xtensa_isa_num_formats (isa) < MAX_FORMATS); for (opcode = 0; opcode < num_opcodes; opcode++) @@ -13104,7 +13175,7 @@ copy_expr (expressionS *dst, const expressionS *src) struct rename_section_struct { - char *old_name; + const char *old_name; char *new_name; struct rename_section_struct *next; }; @@ -13166,8 +13237,7 @@ build_section_rename (const char *arg) } /* Now add it. */ - r = (struct rename_section_struct *) - xmalloc (sizeof (struct rename_section_struct)); + r = XNEW (struct rename_section_struct); r->old_name = xstrdup (old_name); r->new_name = xstrdup (new_name); r->next = section_rename; @@ -13177,7 +13247,7 @@ build_section_rename (const char *arg) char * -xtensa_section_rename (char *name) +xtensa_section_rename (const char *name) { struct rename_section_struct *r = section_rename; @@ -13187,5 +13257,5 @@ xtensa_section_rename (char *name) return r->new_name; } - return name; + return (char *) name; }