summaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
authorMax Filippov <jcmvbkbc@gmail.com>2017-10-20 16:23:28 -0700
committerMax Filippov <jcmvbkbc@gmail.com>2017-11-27 15:10:49 -0800
commit120bc8b8b91cba4a8d4092ea0fb3d76bcbe98712 (patch)
tree738f660438e3ba7a6783d0ff36a4ad2fa762266c /gas
parent10329bb27fa5531bf97da184c4d0ed9c4ed85605 (diff)
gas: extract xg_relax_trampoline from xtensa_relax_frag
To make measurement and changes easier extract trampoline relaxation function. No functional changes. gas/ 2017-11-27 Max Filippov <jcmvbkbc@gmail.com> * config/tc-xtensa.c (xg_relax_trampoline): New function. (xtensa_relax_frag): Replace trampoline relaxation code with a call to xg_relax_trampoline.
Diffstat (limited to 'gas')
-rw-r--r--gas/ChangeLog6
-rw-r--r--gas/config/tc-xtensa.c327
2 files changed, 174 insertions, 159 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 4dd68208a0..683ebbfc80 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,9 @@
+2017-11-27 Max Filippov <jcmvbkbc@gmail.com>
+
+ * config/tc-xtensa.c (xg_relax_trampoline): New function.
+ (xtensa_relax_frag): Replace trampoline relaxation code with a
+ call to xg_relax_trampoline.
+
2017-11-27 Nick Clifton <nickc@redhat.com>
PR 22492
diff --git a/gas/config/tc-xtensa.c b/gas/config/tc-xtensa.c
index a48ce1e543..087caad202 100644
--- a/gas/config/tc-xtensa.c
+++ b/gas/config/tc-xtensa.c
@@ -9164,6 +9164,173 @@ static bfd_boolean xtensa_add_cached_fixup (fixup_cacheS *cache, fixS *fixP)
return TRUE;
}
+static void xg_relax_trampoline (fragS *fragP, long stretch, long *new_stretch)
+{
+ xtensa_isa isa = xtensa_default_isa;
+ 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;
+ int slot;
+ xtensa_format fmt;
+ 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;
+ struct trampoline_frag *best_tf_prev = 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;
+ best_tf_prev = prev;
+ }
+ }
+ tf = best_tf;
+ prev = best_tf_prev;
+ }
+ 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->fx_size = 3;
+ fixP->tc_fix_data.slot = 0;
+ fixP->fx_r_type = BFD_RELOC_XTENSA_SLOT0_OP;
+
+ 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;
+ }
+ }
+ }
+ }
+ }
+}
+
/* Return the number of bytes added to this fragment, given that the
input has been stretched already by "stretch". */
@@ -9307,165 +9474,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->fx_size = 3;
- fixP->tc_fix_data.slot = 0;
- fixP->fx_r_type = BFD_RELOC_XTENSA_SLOT0_OP;
-
- 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: