mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-23 18:14:13 +08:00
xtensa: add --auto-litpools option
Auto-litpools is the automated version of text-section-literals: literal pool candidate frags are planted every N frags and during relaxation they are turned into actual literal pools where literals are moved to become reachable for their first reference by L32R instruction. 2015-08-12 David Weatherford <weath@cadence.com> gas/ * config/tc-xtensa.c (struct litpool_frag, struct litpool_seg): New structures. (xtensa_maybe_create_literal_pool_frag): New function. (litpool_seg_list, auto_litpools, auto_litpool_limit) (litpool_buf, litpool_slotbuf): New static variables. (option_auto_litpools, option_no_auto_litpools) (option_auto_litpool_limit): New enum identifiers. (md_longopts): Add entries for auto-litpools, no-auto-litpools and auto-litpool-limit. (md_parse_option): Handle option_auto_litpools, option_no_auto_litpools and option_auto_litpool_limit. (md_show_usage): Add help for --[no-]auto-litpools and --auto-litpool-limit. (xtensa_mark_literal_pool_location): Record a place for literal pool with a call to xtensa_maybe_create_literal_pool_frag. (get_literal_pool_location): Find highest priority literal pool or convert candidate to literal pool when auto-litpools are used. (xg_assemble_vliw_tokens): Create literal pool after jump instruction. (xtensa_check_frag_count): Create candidate literal pool every auto_litpool_limit frags. (xtensa_relax_frag): Add jump around literals to non-empty literal pool. (xtensa_move_literals): Estimate literal pool addresses and move unreachable literals closer to their users, converting candidate to literal pool if needed. (xtensa_switch_to_non_abs_literal_fragment): Only emit error about missing .literal_position in case auto-litpools are not used. * config/tc-xtensa.h (xtensa_relax_statesE): New relaxation state: RELAX_LITERAL_POOL_CANDIDATE_BEGIN. * doc/as.texinfo (Xtensa options): Document --auto-litpools and --no-auto-litpools options. * doc/c-xtensa.texi (Xtensa options): Likewise. 2015-08-12 Max Filippov <jcmvbkbc@gmail.com> gas/testsuite/ * gas/xtensa/all.exp: Add auto-litpools to the list of xtensa tests. * gas/xtensa/auto-litpools.s: New file: auto-litpools test. * gas/xtensa/auto-litpools.s: New file: auto-litpools test result pattern.
This commit is contained in:
parent
5ba325978c
commit
b46824bd49
@ -1,3 +1,40 @@
|
||||
2015-08-12 David Weatherford <weath@cadence.com>
|
||||
|
||||
* config/tc-xtensa.c (struct litpool_frag, struct litpool_seg):
|
||||
New structures.
|
||||
(xtensa_maybe_create_literal_pool_frag): New function.
|
||||
(litpool_seg_list, auto_litpools, auto_litpool_limit)
|
||||
(litpool_buf, litpool_slotbuf): New static variables.
|
||||
(option_auto_litpools, option_no_auto_litpools)
|
||||
(option_auto_litpool_limit): New enum identifiers.
|
||||
(md_longopts): Add entries for auto-litpools, no-auto-litpools
|
||||
and auto-litpool-limit.
|
||||
(md_parse_option): Handle option_auto_litpools,
|
||||
option_no_auto_litpools and option_auto_litpool_limit.
|
||||
(md_show_usage): Add help for --[no-]auto-litpools and
|
||||
--auto-litpool-limit.
|
||||
(xtensa_mark_literal_pool_location): Record a place for literal
|
||||
pool with a call to xtensa_maybe_create_literal_pool_frag.
|
||||
(get_literal_pool_location): Find highest priority literal pool
|
||||
or convert candidate to literal pool when auto-litpools are used.
|
||||
(xg_assemble_vliw_tokens): Create literal pool after jump
|
||||
instruction.
|
||||
(xtensa_check_frag_count): Create candidate literal pool every
|
||||
auto_litpool_limit frags.
|
||||
(xtensa_relax_frag): Add jump around literals to non-empty
|
||||
literal pool.
|
||||
(xtensa_move_literals): Estimate literal pool addresses and move
|
||||
unreachable literals closer to their users, converting candidate
|
||||
to literal pool if needed.
|
||||
(xtensa_switch_to_non_abs_literal_fragment): Only emit error
|
||||
about missing .literal_position in case auto-litpools are not
|
||||
used.
|
||||
* config/tc-xtensa.h (xtensa_relax_statesE): New relaxation
|
||||
state: RELAX_LITERAL_POOL_CANDIDATE_BEGIN.
|
||||
* doc/as.texinfo (Xtensa options): Document --auto-litpools and
|
||||
--no-auto-litpools options.
|
||||
* doc/c-xtensa.texi (Xtensa options): Likewise.
|
||||
|
||||
2015-08-12 Simon Dardis <simon.dardis@imgtec.com>
|
||||
|
||||
* config/tc-mips.c (move_register): Change to use 'or' only.
|
||||
|
@ -440,6 +440,29 @@ bfd_boolean directive_state[] =
|
||||
#endif
|
||||
};
|
||||
|
||||
/* A circular list of all potential and actual literal pool locations
|
||||
in a segment. */
|
||||
struct litpool_frag
|
||||
{
|
||||
struct litpool_frag *next;
|
||||
struct litpool_frag *prev;
|
||||
fragS *fragP;
|
||||
addressT addr;
|
||||
short priority; /* 1, 2, or 3 -- 1 is highest */
|
||||
short original_priority;
|
||||
};
|
||||
|
||||
/* Map a segment to its litpool_frag list. */
|
||||
struct litpool_seg
|
||||
{
|
||||
struct litpool_seg *next;
|
||||
asection *seg;
|
||||
struct litpool_frag frag_list;
|
||||
int frag_count; /* since last litpool location */
|
||||
};
|
||||
|
||||
static struct litpool_seg litpool_seg_list;
|
||||
|
||||
|
||||
/* Directive functions. */
|
||||
|
||||
@ -474,6 +497,9 @@ 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 void xtensa_maybe_create_literal_pool_frag (bfd_boolean, bfd_boolean);
|
||||
static bfd_boolean auto_litpools = FALSE;
|
||||
static int auto_litpool_limit = 10000;
|
||||
|
||||
/* Alignment Functions. */
|
||||
|
||||
@ -698,6 +724,10 @@ enum
|
||||
|
||||
option_trampolines,
|
||||
option_no_trampolines,
|
||||
|
||||
option_auto_litpools,
|
||||
option_no_auto_litpools,
|
||||
option_auto_litpool_limit,
|
||||
};
|
||||
|
||||
const char *md_shortopts = "";
|
||||
@ -773,6 +803,10 @@ struct option md_longopts[] =
|
||||
{ "trampolines", no_argument, NULL, option_trampolines },
|
||||
{ "no-trampolines", no_argument, NULL, option_no_trampolines },
|
||||
|
||||
{ "auto-litpools", no_argument, NULL, option_auto_litpools },
|
||||
{ "no-auto-litpools", no_argument, NULL, option_no_auto_litpools },
|
||||
{ "auto-litpool-limit", required_argument, NULL, option_auto_litpool_limit },
|
||||
|
||||
{ NULL, no_argument, NULL, 0 }
|
||||
};
|
||||
|
||||
@ -961,6 +995,34 @@ md_parse_option (int c, char *arg)
|
||||
use_trampolines = FALSE;
|
||||
return 1;
|
||||
|
||||
case option_auto_litpools:
|
||||
auto_litpools = TRUE;
|
||||
use_literal_section = FALSE;
|
||||
return 1;
|
||||
|
||||
case option_no_auto_litpools:
|
||||
auto_litpools = FALSE;
|
||||
auto_litpool_limit = -1;
|
||||
return 1;
|
||||
|
||||
case option_auto_litpool_limit:
|
||||
{
|
||||
int value = 0;
|
||||
if (auto_litpool_limit < 0)
|
||||
as_fatal (_("no-auto-litpools is incompatible with auto-litpool-limit"));
|
||||
if (*arg == 0 || *arg == '-')
|
||||
as_fatal (_("invalid auto-litpool-limit argument"));
|
||||
value = strtol (arg, &arg, 10);
|
||||
if (*arg != 0)
|
||||
as_fatal (_("invalid auto-litpool-limit argument"));
|
||||
if (value < 100 || value > 10000)
|
||||
as_fatal (_("invalid auto-litpool-limit argument (range is 100-10000)"));
|
||||
auto_litpool_limit = value;
|
||||
auto_litpools = TRUE;
|
||||
use_literal_section = FALSE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -986,7 +1048,12 @@ Xtensa options:\n\
|
||||
flix bundles\n\
|
||||
--rename-section old=new Rename section 'old' to 'new'\n\
|
||||
--[no-]trampolines [Do not] generate trampolines (jumps to jumps)\n\
|
||||
when jumps do not reach their targets\n", stream);
|
||||
when jumps do not reach their targets\n\
|
||||
--[no-]auto-litpools [Do not] automatically create literal pools\n\
|
||||
--auto-litpool-limit=<value>\n\
|
||||
(range 100-10000) Maximum number of blocks of\n\
|
||||
instructions to emit between literal pool\n\
|
||||
locations; implies --auto-litpools flag\n", stream);
|
||||
}
|
||||
|
||||
|
||||
@ -4728,6 +4795,8 @@ xtensa_mark_literal_pool_location (void)
|
||||
pool_location = frag_now;
|
||||
frag_now->tc_frag_data.lit_frchain = frchain_now;
|
||||
frag_now->tc_frag_data.literal_frag = frag_now;
|
||||
/* Just record this frag. */
|
||||
xtensa_maybe_create_literal_pool_frag (FALSE, FALSE);
|
||||
frag_variant (rs_machine_dependent, 0, 0,
|
||||
RELAX_LITERAL_POOL_BEGIN, NULL, 0, NULL);
|
||||
xtensa_set_frag_assembly_state (frag_now);
|
||||
@ -4832,6 +4901,31 @@ 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@ -7098,6 +7192,11 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
|
||||
frag_now->tc_frag_data.slot_symbols[slot] = tinsn->symbol;
|
||||
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;
|
||||
}
|
||||
if (tinsn->literal_space != 0)
|
||||
xg_assemble_literal_space (tinsn->literal_space, slot);
|
||||
frag_now->tc_frag_data.free_reg[slot] = tinsn->extra_arg;
|
||||
@ -7170,6 +7269,8 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
|
||||
frag_now->fr_symbol, frag_now->fr_offset, NULL);
|
||||
xtensa_set_frag_assembly_state (frag_now);
|
||||
xtensa_maybe_create_trampoline_frag ();
|
||||
/* Always create one here. */
|
||||
xtensa_maybe_create_literal_pool_frag (TRUE, FALSE);
|
||||
}
|
||||
else if (is_branch && do_align_targets ())
|
||||
{
|
||||
@ -7314,11 +7415,18 @@ xtensa_check_frag_count (void)
|
||||
clear_frag_count ();
|
||||
unreachable_count = 0;
|
||||
}
|
||||
|
||||
/* We create an area for a possible literal pool every N (default 5000)
|
||||
frags or so. */
|
||||
xtensa_maybe_create_literal_pool_frag (TRUE, TRUE);
|
||||
}
|
||||
|
||||
static xtensa_insnbuf trampoline_buf = NULL;
|
||||
static xtensa_insnbuf trampoline_slotbuf = NULL;
|
||||
|
||||
static xtensa_insnbuf litpool_buf = NULL;
|
||||
static xtensa_insnbuf litpool_slotbuf = NULL;
|
||||
|
||||
#define TRAMPOLINE_FRAG_SIZE 3000
|
||||
|
||||
static void
|
||||
@ -7410,6 +7518,135 @@ dump_trampolines (void)
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_litpools (void) __attribute__ ((unused));
|
||||
|
||||
static void
|
||||
dump_litpools (void)
|
||||
{
|
||||
struct litpool_seg *lps = litpool_seg_list.next;
|
||||
struct litpool_frag *lpf;
|
||||
|
||||
for ( ; lps ; lps = lps->next )
|
||||
{
|
||||
printf("litpool seg %s\n", lps->seg->name);
|
||||
for ( lpf = lps->frag_list.next; lpf->fragP; lpf = lpf->next )
|
||||
{
|
||||
fragS *litfrag = lpf->fragP->fr_next;
|
||||
int count = 0;
|
||||
while (litfrag && litfrag->fr_subtype != RELAX_LITERAL_POOL_END)
|
||||
{
|
||||
if (litfrag->fr_fix == 4)
|
||||
count++;
|
||||
litfrag = litfrag->fr_next;
|
||||
}
|
||||
printf(" %ld <%d:%d> (%d) [%d]: ",
|
||||
lpf->addr, lpf->priority, lpf->original_priority,
|
||||
lpf->fragP->fr_line, count);
|
||||
//dump_frag(lpf->fragP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xtensa_maybe_create_literal_pool_frag (bfd_boolean create,
|
||||
bfd_boolean only_if_needed)
|
||||
{
|
||||
struct litpool_seg *lps = litpool_seg_list.next;
|
||||
fragS *fragP;
|
||||
struct litpool_frag *lpf;
|
||||
bfd_boolean needed = FALSE;
|
||||
|
||||
if (use_literal_section || !auto_litpools)
|
||||
return;
|
||||
|
||||
for ( ; lps ; lps = lps->next )
|
||||
{
|
||||
if (lps->seg == now_seg)
|
||||
break;
|
||||
}
|
||||
|
||||
if (lps == NULL)
|
||||
{
|
||||
lps = (struct litpool_seg *)xcalloc (sizeof (struct litpool_seg), 1);
|
||||
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;
|
||||
}
|
||||
|
||||
lps->frag_count++;
|
||||
|
||||
if (create)
|
||||
{
|
||||
if (only_if_needed)
|
||||
{
|
||||
if (past_xtensa_end || !use_transform() ||
|
||||
frag_now->tc_frag_data.is_no_transform)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (auto_litpool_limit <= 0)
|
||||
{
|
||||
/* Don't create a litpool based only on frag count. */
|
||||
return;
|
||||
}
|
||||
else if (lps->frag_count > auto_litpool_limit)
|
||||
{
|
||||
needed = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
needed = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (needed)
|
||||
{
|
||||
int size = (only_if_needed) ? 3 : 0; /* Space for a "j" insn. */
|
||||
/* Create a potential site for a literal pool. */
|
||||
frag_wane (frag_now);
|
||||
frag_new (0);
|
||||
xtensa_set_frag_assembly_state (frag_now);
|
||||
fragP = frag_now;
|
||||
fragP->tc_frag_data.lit_frchain = frchain_now;
|
||||
fragP->tc_frag_data.literal_frag = fragP;
|
||||
frag_var (rs_machine_dependent, size, size,
|
||||
(only_if_needed) ?
|
||||
RELAX_LITERAL_POOL_CANDIDATE_BEGIN :
|
||||
RELAX_LITERAL_POOL_BEGIN,
|
||||
NULL, 0, NULL);
|
||||
frag_now->tc_frag_data.lit_seg = now_seg;
|
||||
frag_variant (rs_machine_dependent, 0, 0,
|
||||
RELAX_LITERAL_POOL_END, NULL, 0, NULL);
|
||||
xtensa_set_frag_assembly_state (frag_now);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* RELAX_LITERAL_POOL_BEGIN frag is being created;
|
||||
just record it here. */
|
||||
fragP = frag_now;
|
||||
}
|
||||
|
||||
lpf = (struct litpool_frag *)xmalloc(sizeof (struct litpool_frag));
|
||||
/* Insert at tail of circular list. */
|
||||
lpf->addr = 0;
|
||||
lps->frag_list.prev->next = lpf;
|
||||
lpf->next = &lps->frag_list;
|
||||
lpf->prev = lps->frag_list.prev;
|
||||
lps->frag_list.prev = lpf;
|
||||
lpf->fragP = fragP;
|
||||
lpf->priority = (needed) ? (only_if_needed) ? 3 : 2 : 1;
|
||||
lpf->original_priority = lpf->priority;
|
||||
|
||||
lps->frag_count = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
xtensa_cleanup_align_frags (void)
|
||||
{
|
||||
@ -9029,7 +9266,41 @@ xtensa_relax_frag (fragS *fragP, long stretch, int *stretched_p)
|
||||
break;
|
||||
|
||||
case RELAX_LITERAL_POOL_BEGIN:
|
||||
if (fragP->fr_var != 0)
|
||||
{
|
||||
/* We have a converted "candidate" literal pool;
|
||||
assemble a jump around it. */
|
||||
TInsn insn;
|
||||
if (!litpool_slotbuf)
|
||||
{
|
||||
litpool_buf = xtensa_insnbuf_alloc (isa);
|
||||
litpool_slotbuf = xtensa_insnbuf_alloc (isa);
|
||||
}
|
||||
new_stretch += 3;
|
||||
fragP->tc_frag_data.relax_seen = FALSE; /* Need another pass. */
|
||||
fragP->tc_frag_data.is_insn = TRUE;
|
||||
tinsn_init (&insn);
|
||||
insn.insn_type = ITYPE_INSN;
|
||||
insn.opcode = xtensa_j_opcode;
|
||||
insn.ntok = 1;
|
||||
set_expr_symbol_offset (&insn.tok[0], fragP->fr_symbol,
|
||||
fragP->fr_fix);
|
||||
fmt = xg_get_single_format (xtensa_j_opcode);
|
||||
tinsn_to_slotbuf (fmt, 0, &insn, litpool_slotbuf);
|
||||
xtensa_format_set_slot (isa, fmt, 0, litpool_buf, litpool_slotbuf);
|
||||
xtensa_insnbuf_to_chars (isa, litpool_buf,
|
||||
(unsigned char *)fragP->fr_literal +
|
||||
fragP->fr_fix, 3);
|
||||
fragP->fr_fix += 3;
|
||||
fragP->fr_var -= 3;
|
||||
/* Add a fix-up. */
|
||||
fix_new (fragP, 0, 3, fragP->fr_symbol, 0, TRUE,
|
||||
BFD_RELOC_XTENSA_SLOT0_OP);
|
||||
}
|
||||
break;
|
||||
|
||||
case RELAX_LITERAL_POOL_END:
|
||||
case RELAX_LITERAL_POOL_CANDIDATE_BEGIN:
|
||||
case RELAX_MAYBE_UNREACHABLE:
|
||||
case RELAX_MAYBE_DESIRE_ALIGN:
|
||||
/* No relaxation required. */
|
||||
@ -10789,12 +11060,115 @@ xtensa_move_literals (void)
|
||||
segT dest_seg;
|
||||
fixS *fix, *next_fix, **fix_splice;
|
||||
sym_list *lit;
|
||||
struct litpool_seg *lps;
|
||||
|
||||
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. */
|
||||
|
||||
for (lps = litpool_seg_list.next; lps; lps = lps->next)
|
||||
{
|
||||
frchainS *frchP = seg_info (lps->seg)->frchainP;
|
||||
struct litpool_frag *lpf = lps->frag_list.next;
|
||||
addressT addr = 0;
|
||||
|
||||
for ( ; frchP; frchP = frchP->frch_next)
|
||||
{
|
||||
fragS *fragP;
|
||||
for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
|
||||
{
|
||||
if (lpf && fragP == lpf->fragP)
|
||||
{
|
||||
gas_assert(fragP->fr_type == rs_machine_dependent &&
|
||||
(fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN ||
|
||||
fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN));
|
||||
/* Found a litpool location. */
|
||||
lpf->addr = addr;
|
||||
lpf = lpf->next;
|
||||
}
|
||||
if (fragP->fr_type == rs_machine_dependent &&
|
||||
fragP->fr_subtype == RELAX_SLOTS)
|
||||
{
|
||||
int slot;
|
||||
for (slot = 0; slot < MAX_SLOTS; slot++)
|
||||
{
|
||||
if (fragP->tc_frag_data.literal_frags[slot])
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
addr += fragP->fr_fix;
|
||||
if (fragP->fr_type == rs_fill)
|
||||
addr += fragP->fr_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (segment = literal_head->next; segment; segment = segment->next)
|
||||
{
|
||||
/* Keep the literals for .init and .fini in separate sections. */
|
||||
@ -10839,9 +11213,6 @@ xtensa_move_literals (void)
|
||||
while (search_frag != frag_now)
|
||||
{
|
||||
next_frag = search_frag->fr_next;
|
||||
|
||||
/* 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;
|
||||
@ -10849,8 +11220,56 @@ xtensa_move_literals (void)
|
||||
frchain_to = literal_pool->tc_frag_data.lit_frchain;
|
||||
gas_assert (frchain_to);
|
||||
}
|
||||
|
||||
if (search_frag->fr_type == rs_fill && search_frag->fr_fix == 0)
|
||||
{
|
||||
/* Skip empty fill frags. */
|
||||
*frag_splice = next_frag;
|
||||
search_frag = next_frag;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (search_frag->fr_type == rs_align)
|
||||
{
|
||||
/* Skip alignment frags, because the pool as a whole will be
|
||||
aligned if used, and we don't want to force alignment if the
|
||||
pool is unused. */
|
||||
*frag_splice = next_frag;
|
||||
search_frag = next_frag;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* First, move the frag out of the literal section and
|
||||
to the appropriate place. */
|
||||
|
||||
/* Insert an aligmnent 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)
|
||||
{
|
||||
segT pool_seg = literal_pool->fr_next->tc_frag_data.lit_seg;
|
||||
emit_state prev_state;
|
||||
fragS *prev_frag;
|
||||
fragS *align_frag;
|
||||
xtensa_switch_section_emit_state (&prev_state, pool_seg, 0);
|
||||
prev_frag = frag_now;
|
||||
frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL);
|
||||
align_frag = frag_now;
|
||||
frag_align (2, 0, 0);
|
||||
/* Splice it into the right place. */
|
||||
prev_frag->fr_next = align_frag->fr_next;
|
||||
align_frag->fr_next = literal_pool->fr_next;
|
||||
literal_pool->fr_next = align_frag;
|
||||
/* Insert after this one. */
|
||||
literal_pool->tc_frag_data.literal_frag = align_frag;
|
||||
xtensa_restore_emit_state (&prev_state);
|
||||
}
|
||||
insert_after = literal_pool->tc_frag_data.literal_frag;
|
||||
dest_seg = insert_after->fr_next->tc_frag_data.lit_seg;
|
||||
/* Skip align frag. */
|
||||
if (insert_after->fr_next->fr_type == rs_align)
|
||||
{
|
||||
insert_after = insert_after->fr_next;
|
||||
}
|
||||
|
||||
*frag_splice = next_frag;
|
||||
search_frag->fr_next = insert_after->fr_next;
|
||||
@ -11014,7 +11433,10 @@ xtensa_switch_to_non_abs_literal_fragment (emit_state *result)
|
||||
&& !recursive
|
||||
&& !is_init && ! is_fini)
|
||||
{
|
||||
as_bad (_("literal pool location required for text-section-literals; specify with .literal_position"));
|
||||
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
|
||||
|
@ -124,6 +124,7 @@ enum xtensa_relax_statesE
|
||||
|
||||
RELAX_LITERAL_POOL_BEGIN,
|
||||
RELAX_LITERAL_POOL_END,
|
||||
RELAX_LITERAL_POOL_CANDIDATE_BEGIN,
|
||||
/* 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. */
|
||||
|
@ -555,7 +555,8 @@ gcc(1), ld(1), and the Info entries for @file{binutils} and @file{ld}.
|
||||
@ifset XTENSA
|
||||
|
||||
@emph{Target Xtensa options:}
|
||||
[@b{--[no-]text-section-literals}] [@b{--[no-]absolute-literals}]
|
||||
[@b{--[no-]text-section-literals}] [@b{--[no-]auto-litpools}]
|
||||
[@b{--[no-]absolute-literals}]
|
||||
[@b{--[no-]target-align}] [@b{--[no-]longcalls}]
|
||||
[@b{--[no-]transform}]
|
||||
[@b{--rename-section} @var{oldname}=@var{newname}]
|
||||
|
@ -43,9 +43,30 @@ 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, where the literals would otherwise be out of range of the
|
||||
@code{L32R} instructions in the text section. These options only affect
|
||||
@code{L32R} instructions in the text section. Literals are grouped into
|
||||
pools following @code{.literal_position} directives or preceding
|
||||
@code{ENTRY} instructions. These options only affect literals referenced
|
||||
via PC-relative @code{L32R} instructions; literals for absolute mode
|
||||
@code{L32R} instructions are handled separately.
|
||||
@xref{Literal Directive, ,literal}.
|
||||
|
||||
@item --auto-litpools | --no-auto-litpools
|
||||
@kindex --auto-litpools
|
||||
@kindex --no-auto-litpools
|
||||
Control the treatment of literal pools. The default is
|
||||
@samp{--no-@-auto-@-litpools}, which in the absence of
|
||||
@samp{--text-@-section-@-literals} places literals in separate sections
|
||||
in the output file. This allows the literal pool to be placed in a data
|
||||
RAM/ROM. With @samp{--auto-@-litpools}, the literals are interspersed
|
||||
in the text section in order to keep them as close as possible to their
|
||||
references, explicit @code{.literal_position} directives are not
|
||||
required. This may be necessary for very large functions, where single
|
||||
literal pool at the beginning of the function may not be reachable by
|
||||
@code{L32R} instructions at the end. These options only affect
|
||||
literals referenced via PC-relative @code{L32R} instructions; literals
|
||||
for absolute mode @code{L32R} instructions are handled separately.
|
||||
When used together with @samp{--text-@-section-@-literals},
|
||||
@samp{--auto-@-litpools} takes precedence.
|
||||
@xref{Literal Directive, ,literal}.
|
||||
|
||||
@item --absolute-literals | --no-absolute-literals
|
||||
|
@ -1,3 +1,11 @@
|
||||
2015-08-12 Max Filippov <jcmvbkbc@gmail.com>
|
||||
|
||||
* gas/xtensa/all.exp: Add auto-litpools to the list of xtensa
|
||||
tests.
|
||||
* gas/xtensa/auto-litpools.s: New file: auto-litpools test.
|
||||
* gas/xtensa/auto-litpools.s: New file: auto-litpools test
|
||||
result pattern.
|
||||
|
||||
2015-08-12 Simon Dardis <simon.dardis@imgtec.com>
|
||||
|
||||
* gas/mips/elf-rel23.d: Update test.
|
||||
|
@ -100,6 +100,7 @@ if [istarget xtensa*-*-*] then {
|
||||
run_dump_test "jlong"
|
||||
run_dump_test "trampoline"
|
||||
run_dump_test "first_frag_align"
|
||||
run_dump_test "auto-litpools"
|
||||
}
|
||||
|
||||
if [info exists errorInfo] then {
|
||||
|
12
gas/testsuite/gas/xtensa/auto-litpools.d
Normal file
12
gas/testsuite/gas/xtensa/auto-litpools.d
Normal file
@ -0,0 +1,12 @@
|
||||
#as: --auto-litpools
|
||||
#objdump: -d
|
||||
#name: auto literal pool placement
|
||||
|
||||
.*: +file format .*xtensa.*
|
||||
#...
|
||||
.*4:.*l32r.a2, 0 .*
|
||||
#...
|
||||
.*3e437:.*j.3e440 .*
|
||||
#...
|
||||
.*40750:.*l32r.a2, 3e43c .*
|
||||
#...
|
13
gas/testsuite/gas/xtensa/auto-litpools.s
Normal file
13
gas/testsuite/gas/xtensa/auto-litpools.s
Normal file
@ -0,0 +1,13 @@
|
||||
.text
|
||||
.align 4
|
||||
.literal .L0, 0x12345
|
||||
.literal .L1, 0x12345
|
||||
|
||||
f:
|
||||
l32r a2, .L0
|
||||
.rep 44000
|
||||
_nop
|
||||
_nop
|
||||
.endr
|
||||
l32r a2, .L1
|
||||
ret
|
Loading…
Reference in New Issue
Block a user