* config/tc-xtensa.c (insn_labels, free_insn_labels, saved_insn_labels,

literal_syms): New global variables.
	(xtensa_define_label, add_target_symbol, xtensa_find_label,
	map_over_defined_symbols, is_loop_target_label,
	xtensa_mark_target_fragments, xtensa_move_frag_symbol,
	xtensa_move_frag_symbols, defined_symbols, branch_targets): Delete.
	(xtensa_begin_directive): Call md_flush_pending_output.  Move symbols
	from insn_labels to saved_insn_labels when entering a literal region.
	(xtensa_end_directive): Call md_flush_pending_output.  Restore
	insn_labels list when leaving a literal region.
	(xtensa_literal_position): Call xtensa_clear_insn_labels.
	(xtensa_literal_pseudo): Add check to disallow .literal inside a
	literal region.  Move insn_labels to saved_insn_labels and then restore
	insn_labels on exit.
	(xg_add_branch_and_loop_targets): Replace add_target_symbol calls with
	code to set is_loop_target or is_branch_target flag on the symbol
	(xtensa_create_literal_symbol): Call xtensa_add_literal_sym.
	(xtensa_add_literal_sym, xtensa_add_insn_label,
	xtensa_clear_insn_labels): New functions.
	(xtensa_move_labels): Remove old_frag and old_offset arguments.  Add
	loops_ok argument.  Rewrite to use insn_labels list instead of
	calling xtensa_find_label and to check the is_loop_target flag on
	symbols when loops_ok is false.
	(xtensa_frob_label): Remove call to xtensa_define_label.  Add call
	to either xtensa_add_literal_sym or xtensa_add_insn_label.  Adjust
	call to xtensa_move_labels.  Propagate is_branch_target and
	is_loop_target flags from symbols to frags.
	(xtensa_flush_pending_output): Call xtensa_clear_insn_labels.
	(md_assemble): Use xtensa_move_labels with loops_ok = FALSE when
	aligning a loop instruction.  Adjust call to xtensa_move_labels for
	aligning entry instructions.  Add call to xtensa_clear_insn_labels.
	(xtensa_end): Remove call to xtensa_mark_target_fragments.
	(xtensa_move_literals): Replace xtensa_move_frag_symbols call with
	code to use new literal_syms list.
	* config/tc-xtensa.h (xtensa_symfield_type): Add is_loop_target and
	is_branch_target flags.
This commit is contained in:
Bob Wilson 2003-09-12 00:00:03 +00:00
parent a1632d59e5
commit 82e7541da2
3 changed files with 226 additions and 246 deletions

View File

@ -1,3 +1,42 @@
2003-09-11 Bob Wilson <bob.wilson@acm.org>
* config/tc-xtensa.c (insn_labels, free_insn_labels, saved_insn_labels,
literal_syms): New global variables.
(xtensa_define_label, add_target_symbol, xtensa_find_label,
map_over_defined_symbols, is_loop_target_label,
xtensa_mark_target_fragments, xtensa_move_frag_symbol,
xtensa_move_frag_symbols, defined_symbols, branch_targets): Delete.
(xtensa_begin_directive): Call md_flush_pending_output. Move symbols
from insn_labels to saved_insn_labels when entering a literal region.
(xtensa_end_directive): Call md_flush_pending_output. Restore
insn_labels list when leaving a literal region.
(xtensa_literal_position): Call xtensa_clear_insn_labels.
(xtensa_literal_pseudo): Add check to disallow .literal inside a
literal region. Move insn_labels to saved_insn_labels and then restore
insn_labels on exit.
(xg_add_branch_and_loop_targets): Replace add_target_symbol calls with
code to set is_loop_target or is_branch_target flag on the symbol
(xtensa_create_literal_symbol): Call xtensa_add_literal_sym.
(xtensa_add_literal_sym, xtensa_add_insn_label,
xtensa_clear_insn_labels): New functions.
(xtensa_move_labels): Remove old_frag and old_offset arguments. Add
loops_ok argument. Rewrite to use insn_labels list instead of
calling xtensa_find_label and to check the is_loop_target flag on
symbols when loops_ok is false.
(xtensa_frob_label): Remove call to xtensa_define_label. Add call
to either xtensa_add_literal_sym or xtensa_add_insn_label. Adjust
call to xtensa_move_labels. Propagate is_branch_target and
is_loop_target flags from symbols to frags.
(xtensa_flush_pending_output): Call xtensa_clear_insn_labels.
(md_assemble): Use xtensa_move_labels with loops_ok = FALSE when
aligning a loop instruction. Adjust call to xtensa_move_labels for
aligning entry instructions. Add call to xtensa_clear_insn_labels.
(xtensa_end): Remove call to xtensa_mark_target_fragments.
(xtensa_move_literals): Replace xtensa_move_frag_symbols call with
code to use new literal_syms list.
* config/tc-xtensa.h (xtensa_symfield_type): Add is_loop_target and
is_branch_target flags.
2003-09-09 Bob Wilson <bob.wilson@acm.org>
* config/tc-xtensa.c (xtensa_mark_literal_pool_location): Remove

View File

@ -133,6 +133,25 @@ static seg_list fini_literal_head_h;
static seg_list *fini_literal_head = &fini_literal_head_h;
/* Lists of symbols. We keep a list of symbols that label the current
instruction, so that we can adjust the symbols when inserting alignment
for various instructions. We also keep a list of all the symbols on
literals, so that we can fix up those symbols when the literals are
later moved into the text sections. */
typedef struct sym_list_struct
{
struct sym_list_struct *next;
symbolS *sym;
} sym_list;
static sym_list *insn_labels = NULL;
static sym_list *free_insn_labels = NULL;
static sym_list *saved_insn_labels = NULL;
static sym_list *literal_syms;
/* Global flag to indicate when we are emitting literals. */
int generating_literals = 0;
@ -397,20 +416,6 @@ static void xtensa_insnbuf_set_immediate_field
static bfd_boolean is_negatable_branch
PARAMS ((TInsn *));
/* Functions for Internal Lists of Symbols. */
static void xtensa_define_label
PARAMS ((symbolS *));
static void add_target_symbol
PARAMS ((symbolS *, bfd_boolean));
static symbolS *xtensa_find_label
PARAMS ((fragS *, offsetT, bfd_boolean));
static void map_over_defined_symbols
PARAMS ((void (*fn) (symbolS *)));
static bfd_boolean is_loop_target_label
PARAMS ((symbolS *));
static void xtensa_mark_target_fragments
PARAMS ((void));
/* Various Other Internal Functions. */
static bfd_boolean is_unique_insn_expansion
@ -477,6 +482,12 @@ static void xg_assemble_literal_space
PARAMS ((int));
static symbolS *xtensa_create_literal_symbol
PARAMS ((segT, fragS *));
static void xtensa_add_literal_sym
PARAMS ((symbolS *));
static void xtensa_add_insn_label
PARAMS ((symbolS *));
static void xtensa_clear_insn_labels
PARAMS ((void));
static bfd_boolean get_is_linkonce_section
PARAMS ((bfd *, segT));
static bfd_boolean xg_emit_insn
@ -514,7 +525,7 @@ static bfd_boolean is_next_frag_target
static void xtensa_mark_literal_pool_location
PARAMS ((void));
static void xtensa_move_labels
PARAMS ((fragS *, valueT, fragS *, valueT));
PARAMS ((fragS *, valueT, bfd_boolean));
static void assemble_nop
PARAMS ((size_t, char *));
static addressT get_expanded_loop_offset
@ -626,10 +637,6 @@ static void xtensa_move_seg_list_to_beginning
PARAMS ((seg_list *));
static void xtensa_move_literals
PARAMS ((void));
static void xtensa_move_frag_symbol
PARAMS ((symbolS *));
static void xtensa_move_frag_symbols
PARAMS ((void));
static void xtensa_reorder_seg_list
PARAMS ((seg_list *, segT));
static void xtensa_reorder_segments
@ -1268,6 +1275,8 @@ xtensa_begin_directive (ignore)
int len;
lit_state *ls;
md_flush_pending_output ();
get_directive (&directive, &negated);
if (directive == (directiveE) XTENSA_UNDEFINED)
{
@ -1278,6 +1287,13 @@ xtensa_begin_directive (ignore)
switch (directive)
{
case directive_literal:
if (!inside_directive (directive_literal))
{
/* Previous labels go with whatever follows this directive, not with
the literal, so save them now. */
saved_insn_labels = insn_labels;
insn_labels = NULL;
}
state = (emit_state *) xmalloc (sizeof (emit_state));
xtensa_switch_to_literal_fragment (state);
directive_push (directive_literal, negated, state);
@ -1350,6 +1366,8 @@ xtensa_end_directive (ignore)
emit_state *state;
lit_state *s;
md_flush_pending_output ();
get_directive (&end_directive, &end_negated);
if (end_directive == (directiveE) XTENSA_UNDEFINED)
{
@ -1383,6 +1401,12 @@ xtensa_end_directive (ignore)
frag_var (rs_fill, 0, 0, 0, NULL, 0, NULL);
xtensa_restore_emit_state (state);
free (state);
if (!inside_directive (directive_literal))
{
/* Restore the list of current labels. */
xtensa_clear_insn_labels ();
insn_labels = saved_insn_labels;
}
break;
case directive_freeregs:
@ -1422,6 +1446,7 @@ xtensa_literal_position (ignore)
xtensa_mark_literal_pool_location ();
demand_empty_rest_of_line ();
xtensa_clear_insn_labels ();
}
@ -1437,6 +1462,18 @@ xtensa_literal_pseudo (ignored)
expressionS expP;
segT dest_seg;
if (inside_directive (directive_literal))
{
as_bad (_(".literal not allowed inside .begin literal region"));
ignore_rest_of_line ();
return;
}
/* Previous labels go with whatever follows this directive, not with
the literal, so save them now. */
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;
@ -1487,6 +1524,10 @@ xtensa_literal_pseudo (ignored)
demand_empty_rest_of_line ();
xtensa_restore_emit_state (&state);
/* Restore the list of current labels. */
xtensa_clear_insn_labels ();
insn_labels = saved_insn_labels;
}
@ -2474,167 +2515,6 @@ is_negatable_branch (insn)
return FALSE;
}
/* Lists for recording various properties of symbols. */
typedef struct symbol_consS_struct
{
symbolS *first;
/* These are used for the target taken. */
int is_loop_target:1;
int is_branch_target:1;
int is_literal:1;
int is_moved:1;
struct symbol_consS_struct *rest;
} symbol_consS;
symbol_consS *defined_symbols = 0;
symbol_consS *branch_targets = 0;
static void
xtensa_define_label (sym)
symbolS *sym;
{
symbol_consS *cons = (symbol_consS *) xmalloc (sizeof (symbol_consS));
cons->first = sym;
cons->is_branch_target = 0;
cons->is_loop_target = 0;
cons->is_literal = generating_literals ? 1 : 0;
cons->is_moved = 0;
cons->rest = defined_symbols;
defined_symbols = cons;
}
void
add_target_symbol (sym, is_loop)
symbolS *sym;
bfd_boolean is_loop;
{
symbol_consS *cons, *sym_e;
for (sym_e = branch_targets; sym_e; sym_e = sym_e->rest)
{
if (sym_e->first == sym)
{
if (is_loop)
sym_e->is_loop_target = 1;
else
sym_e->is_branch_target = 1;
return;
}
}
cons = (symbol_consS *) xmalloc (sizeof (symbol_consS));
cons->first = sym;
cons->is_branch_target = (is_loop ? 0 : 1);
cons->is_loop_target = (is_loop ? 1 : 0);
cons->rest = branch_targets;
branch_targets = cons;
}
/* Find the symbol at a given position. (Note: the "loops_ok"
argument is provided to allow ignoring labels that define loop
ends. This fixes a bug where the NOPs to align a loop opcode were
included in a previous zero-cost loop:
loop a0, loopend
<loop1 body>
loopend:
loop a2, loopend2
<loop2 body>
would become:
loop a0, loopend
<loop1 body>
nop.n <===== bad!
loopend:
loop a2, loopend2
<loop2 body>
This argument is used to prevent moving the NOP to before the
loop-end label, which is what you want in this special case.) */
static symbolS *
xtensa_find_label (fragP, offset, loops_ok)
fragS *fragP;
offsetT offset;
bfd_boolean loops_ok;
{
symbol_consS *consP;
for (consP = defined_symbols; consP; consP = consP->rest)
{
symbolS *symP = consP->first;
if (S_GET_SEGMENT (symP) == now_seg
&& symbol_get_frag (symP) == fragP
&& symbol_constant_p (symP)
&& S_GET_VALUE (symP) == fragP->fr_address + (unsigned) offset
&& (loops_ok || !is_loop_target_label (symP)))
return symP;
}
return NULL;
}
static void
map_over_defined_symbols (fn)
void (*fn) PARAMS ((symbolS *));
{
symbol_consS *sym_cons;
for (sym_cons = defined_symbols; sym_cons; sym_cons = sym_cons->rest)
fn (sym_cons->first);
}
static bfd_boolean
is_loop_target_label (sym)
symbolS *sym;
{
symbol_consS *sym_e;
for (sym_e = branch_targets; sym_e; sym_e = sym_e->rest)
{
if (sym_e->first == sym)
return sym_e->is_loop_target;
}
return FALSE;
}
/* Walk over all of the symbols that are branch target labels and
loop target labels. Mark the associated fragments for these with
the appropriate flags. */
static void
xtensa_mark_target_fragments ()
{
symbol_consS *sym_e;
for (sym_e = branch_targets; sym_e; sym_e = sym_e->rest)
{
symbolS *sym = sym_e->first;
if (symbol_get_frag (sym)
&& symbol_constant_p (sym)
&& S_GET_VALUE (sym) == 0)
{
if (sym_e->is_branch_target)
symbol_get_frag (sym)->tc_frag_data.is_branch_target = TRUE;
if (sym_e->is_loop_target)
symbol_get_frag (sym)->tc_frag_data.is_loop_target = TRUE;
}
}
}
/* Various Other Internal Functions. */
@ -3514,7 +3394,7 @@ xg_add_branch_and_loop_targets (insn)
char *kind = xtensa_operand_kind (opnd);
if (strlen (kind) == 1 && *kind == 'l')
if (insn->tok[i].X_op == O_symbol)
add_target_symbol (insn->tok[i].X_add_symbol, TRUE);
symbol_get_tc (insn->tok[i].X_add_symbol)->is_loop_target = TRUE;
return;
}
@ -3532,7 +3412,12 @@ xg_add_branch_and_loop_targets (insn)
char *kind = xtensa_operand_kind (opnd);
if (strlen (kind) == 1 && *kind == 'l'
&& insn->tok[i].X_op == O_symbol)
add_target_symbol (insn->tok[i].X_add_symbol, FALSE);
{
symbolS *sym = insn->tok[i].X_add_symbol;
symbol_get_tc (sym)->is_branch_target = TRUE;
if (S_IS_DEFINED (sym))
symbol_get_frag (sym)->tc_frag_data.is_branch_target = TRUE;
}
}
}
}
@ -3913,12 +3798,59 @@ xtensa_create_literal_symbol (sec, frag)
else
symbolP = symbol_new (name, sec, 0, frag);
xtensa_add_literal_sym (symbolP);
frag->tc_frag_data.is_literal = TRUE;
lit_num++;
return symbolP;
}
static void
xtensa_add_literal_sym (sym)
symbolS *sym;
{
sym_list *l;
l = (sym_list *) xmalloc (sizeof (sym_list));
l->sym = sym;
l->next = literal_syms;
literal_syms = l;
}
static void
xtensa_add_insn_label (sym)
symbolS *sym;
{
sym_list *l;
if (!free_insn_labels)
l = (sym_list *) xmalloc (sizeof (sym_list));
else
{
l = free_insn_labels;
free_insn_labels = l->next;
}
l->sym = sym;
l->next = insn_labels;
insn_labels = l;
}
static void
xtensa_clear_insn_labels (void)
{
sym_list **pl;
for (pl = &free_insn_labels; *pl != NULL; pl = &(*pl)->next)
;
*pl = insn_labels;
insn_labels = NULL;
}
/* Return true if the section flags are marked linkonce
or the name is .gnu.linkonce*. */
@ -4592,22 +4524,46 @@ xtensa_mark_literal_pool_location ()
}
static void
xtensa_move_labels (old_frag, old_offset, new_frag, new_offset)
fragS *old_frag;
valueT old_offset;
fragS *new_frag ATTRIBUTE_UNUSED;
valueT new_offset;
{
symbolS *old_sym;
/* The "loops_ok" argument is provided to allow ignoring labels that
define loop ends. This fixes a bug where the NOPs to align a
loop opcode were included in a previous zero-cost loop:
/* Repeat until there are no more.... */
for (old_sym = xtensa_find_label (old_frag, old_offset, TRUE);
old_sym;
old_sym = xtensa_find_label (old_frag, old_offset, TRUE))
loop a0, loopend
<loop1 body>
loopend:
loop a2, loopend2
<loop2 body>
would become:
loop a0, loopend
<loop1 body>
nop.n <===== bad!
loopend:
loop a2, loopend2
<loop2 body>
This argument is used to prevent moving the NOP to before the
loop-end label, which is what you want in this special case. */
static void
xtensa_move_labels (new_frag, new_offset, loops_ok)
fragS *new_frag;
valueT new_offset;
bfd_boolean loops_ok;
{
sym_list *lit;
for (lit = insn_labels; lit; lit = lit->next)
{
S_SET_VALUE (old_sym, (valueT) new_offset);
symbol_set_frag (old_sym, frag_now);
symbolS *lit_sym = lit->sym;
if (loops_ok || symbol_get_tc (lit_sym)->is_loop_target == 0)
{
S_SET_VALUE (lit_sym, new_offset);
symbol_set_frag (lit_sym, new_frag);
}
}
}
@ -4790,8 +4746,12 @@ void
xtensa_frob_label (sym)
symbolS *sym;
{
xtensa_define_label (sym);
if (is_loop_target_label (sym)
if (generating_literals)
xtensa_add_literal_sym (sym);
else
xtensa_add_insn_label (sym);
if (symbol_get_tc (sym)->is_loop_target
&& (get_last_insn_flags (now_seg, now_subseg)
& FLAG_IS_BAD_LOOPEND) != 0)
as_bad (_("invalid last instruction for a zero-overhead loop"));
@ -4802,15 +4762,21 @@ xtensa_frob_label (sym)
&& !is_unaligned_label (sym)
&& !frag_now->tc_frag_data.is_literal)
{
fragS *old_frag = frag_now;
offsetT old_offset = frag_now_fix ();
/* frag_now->tc_frag_data.is_insn = TRUE; */
frag_var (rs_machine_dependent, 4, 4,
RELAX_DESIRE_ALIGN_IF_TARGET,
frag_now->fr_symbol, frag_now->fr_offset, NULL);
xtensa_move_labels (old_frag, old_offset, frag_now, 0);
/* Once we know whether or not the label is a branch target
We will suppress some of these alignments. */
xtensa_move_labels (frag_now, 0, TRUE);
/* If the label is already known to be a branch target, i.e., a
forward branch, mark the frag accordingly. Backward branches
are handled by xg_add_branch_and_loop_targets. */
if (symbol_get_tc (sym)->is_branch_target)
symbol_get_frag (sym)->tc_frag_data.is_branch_target = TRUE;
/* Loops only go forward, so they can be identified here. */
if (symbol_get_tc (sym)->is_loop_target)
symbol_get_frag (sym)->tc_frag_data.is_loop_target = TRUE;
}
}
@ -4827,6 +4793,8 @@ xtensa_flush_pending_output ()
frag_new (0);
}
frag_now->tc_frag_data.is_insn = FALSE;
xtensa_clear_insn_labels ();
}
@ -4952,9 +4920,6 @@ md_assemble (str)
/* Special cases for instructions that force an alignment... */
if (!orig_insn.is_specific_opcode && is_loop_opcode (orig_insn.opcode))
{
fragS *old_frag = frag_now;
offsetT old_offset = frag_now_fix ();
symbolS *old_sym = NULL;
size_t max_fill;
frag_now->tc_frag_data.is_insn = TRUE;
@ -4966,12 +4931,7 @@ md_assemble (str)
RELAX_ALIGN_NEXT_OPCODE, frag_now->fr_symbol,
frag_now->fr_offset, NULL);
/* Repeat until there are no more. */
while ((old_sym = xtensa_find_label (old_frag, old_offset, FALSE)))
{
S_SET_VALUE (old_sym, (valueT) 0);
symbol_set_frag (old_sym, frag_now);
}
xtensa_move_labels (frag_now, 0, FALSE);
}
/* Special-case for "entry" instruction. */
@ -4995,17 +4955,18 @@ md_assemble (str)
if (!orig_insn.is_specific_opcode)
{
fragS *label_target = frag_now;
offsetT label_offset = frag_now_fix ();
xtensa_mark_literal_pool_location ();
/* Automatically align ENTRY instructions. */
xtensa_move_labels (label_target, label_offset, frag_now, 0);
xtensa_move_labels (frag_now, 0, TRUE);
frag_align (2, 0, 0);
}
}
/* Any extra alignment frags have been inserted now, and we're about to
emit a new instruction so clear the list of labels. */
xtensa_clear_insn_labels ();
if (software_a0_b_retw_interlock)
set_last_insn_flags (now_seg, now_subseg, FLAG_IS_A0_WRITER,
is_register_writer (&orig_insn, "a", 0));
@ -5414,7 +5375,6 @@ xtensa_end ()
xtensa_move_literals ();
xtensa_reorder_segments ();
xtensa_mark_target_fragments ();
xtensa_cleanup_align_frags ();
xtensa_fix_target_frags ();
if (software_a0_b_retw_interlock && has_a0_b_retw)
@ -7520,6 +7480,7 @@ xtensa_move_literals ()
emit_state state;
segT dest_seg;
fixS *fix, *next_fix, **fix_splice;
sym_list *lit;
/* As clunky as this is, we can't rely on frag_var
and frag_variant to get called in all situations. */
@ -7629,35 +7590,13 @@ xtensa_move_literals ()
segment = segment->next;
}
xtensa_move_frag_symbols ();
}
static void
xtensa_move_frag_symbol (sym)
symbolS *sym;
{
fragS *frag = symbol_get_frag (sym);
if (frag->tc_frag_data.lit_seg != (segT) 0)
S_SET_SEGMENT (sym, frag->tc_frag_data.lit_seg);
}
static void
xtensa_move_frag_symbols ()
{
symbolS *symbolP;
/* Although you might think that only one of these lists should be
searched, it turns out that the difference of the two sets
(either way) is not empty. They do overlap quite a bit,
however. */
for (symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next)
xtensa_move_frag_symbol (symbolP);
map_over_defined_symbols (xtensa_move_frag_symbol);
/* Now fix up the SEGMENT value for all the literal symbols. */
for (lit = literal_syms; lit; lit = lit->next)
{
symbolS *lit_sym = lit->sym;
segT dest_seg = symbol_get_frag (lit_sym)->tc_frag_data.lit_seg;
S_SET_SEGMENT (lit_sym, dest_seg);
}
}

View File

@ -100,6 +100,8 @@ typedef struct xtensa_segment_info_struct
typedef struct xtensa_symfield_type_struct
{
unsigned int plt : 1;
unsigned int is_loop_target : 1;
unsigned int is_branch_target : 1;
} xtensa_symfield_type;